]> Cypherpunks repositories - gostls13.git/commitdiff
net: add support for Zone of IPNet
authorMikio Hara <mikioh.mikioh@gmail.com>
Sun, 28 Feb 2016 00:37:36 +0000 (09:37 +0900)
committerMikio Hara <mikioh.mikioh@gmail.com>
Tue, 19 Apr 2016 09:21:57 +0000 (09:21 +0000)
This change adds Zone field to IPNet structure for making it possible to
determine which network interface is associated with IPv6 link-local
address. Also makes ParseCIDR and IPNet.String capable handling literal
IPv6 address prefixes with zone identifier.

Fixes #14518.

Change-Id: I8f8a40d3b4f500ffef25728d4995651379d8408a
Reviewed-on: https://go-review.googlesource.com/19946
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/net/interface_bsd.go
src/net/interface_linux.go
src/net/interface_test.go
src/net/interface_windows.go
src/net/ip.go
src/net/ip_test.go

index 17c6dd3dcd69df12ffbe5bd38d26add416961153..98d19f2d33d42f9789d289b2a95b5fb0e82e5c75 100644 (file)
@@ -166,6 +166,7 @@ func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (*IPNet, error) {
                // link-local address as the kernel-internal form.
                if ifa.IP.IsLinkLocalUnicast() {
                        ifa.IP[2], ifa.IP[3] = 0, 0
+                       ifa.Zone = ifi.Name
                }
        }
        if ifa.IP == nil || ifa.Mask == nil {
index 5e391b28b0f8c4b2f83b4a9353d8249655dbb12f..b8f57fd7db39f0046607c0287f726ee9dcbea5b9 100644 (file)
@@ -193,6 +193,9 @@ func newAddr(ifi *Interface, ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRou
                case syscall.AF_INET6:
                        ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)}
                        copy(ifa.IP, a.Value[:])
+                       if ifa.IP.IsLinkLocalUnicast() {
+                               ifa.Zone = ifi.Name
+                       }
                        return ifa
                }
        }
index e1580134937de0c739fbf1219ea05812fdc6164f..c3e1ee231ffce9642f254c88d0c5b028d103797d 100644 (file)
@@ -221,6 +221,10 @@ func testAddrs(t *testing.T, ifat []Addr) (naf4, naf6 int) {
                                        t.Errorf("unexpected prefix length for IPv6 loopback: %d/%d", prefixLen, maxPrefixLen)
                                        continue
                                }
+                               if ifa.IP.IsLinkLocalUnicast() && ifa.Zone == "" {
+                                       t.Errorf("no IPv6 zone identifier found: %#v", ifa)
+                                       continue
+                               }
                                naf6++
                        }
                        t.Logf("interface address %q", ifa.String())
@@ -239,7 +243,7 @@ func testAddrs(t *testing.T, ifat []Addr) (naf4, naf6 int) {
                        if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
                                naf6++
                        }
-                       t.Logf("interface address %s", ifa.String())
+                       t.Logf("interface address %q", ifa.String())
                default:
                        t.Errorf("unexpected type: %T", ifa)
                }
index 8b976e585f36aab51876c2a1b36681c074532b72..a0b26c3750cc6dd211104ddfcefc25ffea28135a 100644 (file)
@@ -158,6 +158,9 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
                                                l = addrPrefixLen(pfx6, IP(sa.Addr[:]))
                                        }
                                        ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(l, 8*IPv6len)}
+                                       if ifa.IP.IsLinkLocalUnicast() {
+                                               ifa.Zone = syscall.UTF16ToString((*(*[10000]uint16)(unsafe.Pointer(aa.FriendlyName)))[:])
+                                       }
                                        copy(ifa.IP, sa.Addr[:])
                                        ifat = append(ifat, ifa)
                                }
index a2361bbdbfc132cffec03d89ee3ff3b913523141..e8b0fd990bf896f68e4265ce5a33c265603a7371 100644 (file)
@@ -36,6 +36,7 @@ type IPMask []byte
 type IPNet struct {
        IP   IP     // network number
        Mask IPMask // network mask
+       Zone string // IPv6 scoped addressing zone
 }
 
 // IPv4 returns the IP address (in 16-byte form) of the
@@ -494,11 +495,15 @@ func (n *IPNet) String() string {
        if nn == nil || m == nil {
                return "<nil>"
        }
+       ip := nn.String()
+       if n.Zone != "" {
+               ip = ip + "%" + n.Zone
+       }
        l := simpleMaskLength(m)
        if l == -1 {
-               return nn.String() + "/" + m.String()
+               return ip + "/" + m.String()
        }
-       return nn.String() + "/" + uitoa(uint(l))
+       return ip + "/" + uitoa(uint(l))
 }
 
 // Parse IPv4 address (d.d.d.d).
@@ -670,17 +675,18 @@ func ParseCIDR(s string) (IP, *IPNet, error) {
        if i < 0 {
                return nil, nil, &ParseError{Type: "CIDR address", Text: s}
        }
+       var zone string
        addr, mask := s[:i], s[i+1:]
        iplen := IPv4len
        ip := parseIPv4(addr)
        if ip == nil {
                iplen = IPv6len
-               ip, _ = parseIPv6(addr, false)
+               ip, zone = parseIPv6(addr, true)
        }
        n, i, ok := dtoi(mask, 0)
        if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen {
                return nil, nil, &ParseError{Type: "CIDR address", Text: s}
        }
        m := CIDRMask(n, 8*iplen)
-       return ip, &IPNet{IP: ip.Mask(m), Mask: m}, nil
+       return ip, &IPNet{IP: ip.Mask(m), Mask: m, Zone: zone}, nil
 }
index 87c12133c3356753796ec3d1d0f2295042c1921d..1d67057d6afbbc9896c54afe15373b574da96d62 100644 (file)
@@ -327,6 +327,9 @@ var parseCIDRTests = []struct {
        {"abcd:2345::/24", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2300::"), Mask: IPMask(ParseIP("ffff:ff00::"))}, nil},
        {"2001:DB8::/48", ParseIP("2001:DB8::"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
        {"2001:DB8::1/48", ParseIP("2001:DB8::1"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
+       {"fe80::%en0/64", ParseIP("fe80::"), &IPNet{IP: ParseIP("fe80::"), Mask: CIDRMask(64, 128), Zone: "en0"}, nil},
+       {"fe80::1%en0/64", ParseIP("fe80::1"), &IPNet{IP: ParseIP("fe80::"), Mask: CIDRMask(64, 128), Zone: "en0"}, nil},
+
        {"192.168.1.1/255.255.255.0", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/255.255.255.0"}},
        {"192.168.1.1/35", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/35"}},
        {"2001:db8::1/-1", nil, nil, &ParseError{Type: "CIDR address", Text: "2001:db8::1/-1"}},
@@ -373,8 +376,13 @@ var ipNetStringTests = []struct {
        out string
 }{
        {&IPNet{IP: IPv4(192, 168, 1, 0), Mask: CIDRMask(26, 32)}, "192.168.1.0/26"},
+       {&IPNet{IP: IPv4(192, 168, 1, 1), Mask: CIDRMask(26, 32)}, "192.168.1.1/26"},
        {&IPNet{IP: IPv4(192, 168, 1, 0), Mask: IPv4Mask(255, 0, 255, 0)}, "192.168.1.0/ff00ff00"},
+       {&IPNet{IP: ParseIP("fe80::"), Mask: CIDRMask(64, 128), Zone: "en0"}, "fe80::%en0/64"},
+       {&IPNet{IP: ParseIP("fe80::1"), Mask: CIDRMask(64, 128), Zone: "en0"}, "fe80::1%en0/64"},
+       {&IPNet{IP: ParseIP("fe80::"), Mask: IPMask(ParseIP("8000:f123:0:cafe::")), Zone: "en0"}, "fe80::%en0/8000f1230000cafe0000000000000000"},
        {&IPNet{IP: ParseIP("2001:db8::"), Mask: CIDRMask(55, 128)}, "2001:db8::/55"},
+       {&IPNet{IP: ParseIP("2001:db8::1"), Mask: CIDRMask(55, 128)}, "2001:db8::1/55"},
        {&IPNet{IP: ParseIP("2001:db8::"), Mask: IPMask(ParseIP("8000:f123:0:cafe::"))}, "2001:db8::/8000f1230000cafe0000000000000000"},
 }