简体   繁体   中英

How to find range (prefix?) of ipv6 addresses that a machine can use, and how to transform a subnet of ipv6 into a slice of ip addresses?

There are many things I don't understand about ipv6 and.networking in general, which is why I need some further clarification on some the answers already posted to other questions. I'll list my questions, what I grasped from other answers, and what I'm still confused about.

  1. Say I have a VPS with a /56 ipv6 su.net (256 * residential /64 su.nets) allotted to it. How can I programmatically find the range (prefix?) of the ip's I "own". How to get IPv4 and IPv6 address of local machine? . This is the answer I saw for this question: and what I think I understand is that I get the DNS hostname for the machine, then look up that same hostname to find the range. I'm wondering two things: How do I do this in Go, and

  2. How do I transfer this range ^ into a slice (array) of ipv6 addresses. For this specific use case: the ideal solution would be to only get one ipv6 address per \64 su.net, resulting in 256 seperate ips

DNS is not very helpful in determining the local IP addresses, because a DNS entry is not required to make an IP address work, nor is it required to point to (only) the machine that you happen to run your program on.

Instead, inspect the network interfaces and their configuration:

package main

import (
    "fmt"
    "log"
    "net"
    "os"
    "text/tabwriter"
)

func main() {
    tw := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)

    ifaces, err := net.Interfaces()
    if err != nil {
        log.Fatal(err)
    }

    for _, iface := range ifaces {
        addrs, err := iface.Addrs()
        if err != nil {
            log.Fatal(err)
        }
        for _, addr := range addrs {
            addr, ok := addr.(*net.IPNet)
            if !ok {
                // Not an IP interface
                continue
            }
            if addr.IP.To4() != nil {
                // Skip IPv4 addresses
                continue
            }

            fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n", 
                iface.Name, addr.String(), addr.IP, addr.Mask)
        }
    }
    tw.Flush()
}

For my local machine the output is:

lo          ::1/128                      ::1                       ffffffffffffffffffffffffffffffff
enp2s0      fe80::52e5:49ff:fe3b:107a/64 fe80::52e5:49ff:fe3b:107a ffffffffffffffff0000000000000000
docker0     fe80::42:afff:fedb:7389/64   fe80::42:afff:fedb:7389   ffffffffffffffff0000000000000000
tun0        fe80::f22c:2d3b:a5a0:1b61/64 fe80::f22c:2d3b:a5a0:1b61 ffffffffffffffff0000000000000000
vethd176f0c fe80::1cc1:65ff:fe39:feff/64 fe80::1cc1:65ff:fe39:feff ffffffffffffffff0000000000000000

Note that these addresses are not necessarily reachable from the Internet. This all depends on how the routing of the hoster works. In any kind of cloud setup, you are almost always better off querying the providers APIs.


To list all /64 subnets in a particular /56 subnet, you have to leave the 56 upper bits of the subnet address as they are and permute the following 64-56 = 8 bits (which happens to be the eigth byte):

package main

import (
    "fmt"
    "net"
)

func main() {
    _, subnet, _ := net.ParseCIDR("2001:db8::/56")
    fmt.Println(subnet)

    subnet.Mask = net.CIDRMask(64, 128) // change mask to /64

    for i := 0; i <= 0xff; i++ {
        subnet.IP[7] = byte(i) // permute the 8th byte
        fmt.Println("\t", subnet)
    }

    // Output:
    // 2001:db8::/56
    //          2001:db8::/64
    //          2001:db8:0:1::/64
    //          2001:db8:0:2::/64
    //          2001:db8:0:3::/64
    //          2001:db8:0:4::/64
    //          2001:db8:0:5::/64
    //          2001:db8:0:6::/64
    //          2001:db8:0:7::/64
    //          2001:db8:0:8::/64
    // [...]
}

Regarding the second part of your question, "How do I transfer this range ^ into a slice (array) of ipv6 addresses"

The IPAddress Go library can do this with polymorphic code that works with both IPv4 and IPv6 addresses and all prefix lengths. Repository here . Disclaimer: I am the project manager.

addrStr := "2001:db8::/56"
addr := ipaddr.NewIPAddressString(addrStr).GetAddress()
addrAdjusted := addr.SetPrefixLen(64) // adjust prefix
iterator := addrAdjusted.PrefixIterator()
var blocks []*ipaddr.IPAddress
for iterator.HasNext() {
    blocks = append(blocks, iterator.Next())
}

// print the details
fmt.Println("first and last blocks are",
    addrAdjusted.GetLower().ToPrefixBlock(), "and",
    addrAdjusted.GetUpper().ToPrefixBlock())
fmt.Print("list: ")
for i, addr := range blocks {
    if i < 3 || len(blocks)-i <= 3 {
        if i > 0 {
            fmt.Print(", ")
        }
        fmt.Print(addr)
    } else if i == 3 {
        fmt.Print(", ...")
    }
}

Output:

first and last blocks are 2001:db8::/64 and 2001:db8:0:ff::/64
list: 2001:db8::/64, 2001:db8:0:1::/64, 2001:db8:0:2::/64, ..., 2001:db8:0:fd::/64, 2001:db8:0:fe::/64, 2001:db8:0:ff::/64

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM