]> Cypherpunks repositories - gostls13.git/commitdiff
net, cmd/fix: add IPv6 scoped addressing zone to INET, INET6 address structs
authorMikio Hara <mikioh.mikioh@gmail.com>
Mon, 26 Nov 2012 15:45:42 +0000 (00:45 +0900)
committerMikio Hara <mikioh.mikioh@gmail.com>
Mon, 26 Nov 2012 15:45:42 +0000 (00:45 +0900)
This CL starts to introduce IPv6 scoped addressing capability
into the net package.

The Public API changes are:
+pkg net, type IPAddr struct, Zone string
+pkg net, type IPNet struct, Zone string
+pkg net, type TCPAddr struct, Zone string
+pkg net, type UDPAddr struct, Zone string

Update #4234.

R=rsc, bradfitz, iant
CC=golang-dev
https://golang.org/cl/6849045

16 files changed:
src/cmd/fix/netipv6zone.go [new file with mode: 0644]
src/cmd/fix/netipv6zone_test.go [new file with mode: 0644]
src/pkg/net/ip.go
src/pkg/net/ip_test.go
src/pkg/net/iprawsock.go
src/pkg/net/iprawsock_plan9.go
src/pkg/net/iprawsock_posix.go
src/pkg/net/ipsock.go
src/pkg/net/ipsock_plan9.go
src/pkg/net/ipsock_posix.go
src/pkg/net/multicast_posix_test.go
src/pkg/net/tcpsock.go
src/pkg/net/tcpsock_posix.go
src/pkg/net/udpsock.go
src/pkg/net/udpsock_plan9.go
src/pkg/net/udpsock_posix.go

diff --git a/src/cmd/fix/netipv6zone.go b/src/cmd/fix/netipv6zone.go
new file mode 100644 (file)
index 0000000..587b9ff
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "go/ast"
+
+func init() {
+       register(netipv6zoneFix)
+}
+
+var netipv6zoneFix = fix{
+       "netipv6zone",
+       "2012-11-26",
+       netipv6zone,
+       `Adapt element key to IPNet, IPAddr, UDPAddr or TCPAddr composite literals.
+
+https://codereview.appspot.com/6849045/
+`,
+}
+
+func netipv6zone(f *ast.File) bool {
+       if !imports(f, "net") {
+               return false
+       }
+
+       fixed := false
+       walk(f, func(n interface{}) {
+               cl, ok := n.(*ast.CompositeLit)
+               if !ok {
+                       return
+               }
+               se, ok := cl.Type.(*ast.SelectorExpr)
+               if !ok {
+                       return
+               }
+               if !isTopName(se.X, "net") || se.Sel == nil {
+                       return
+               }
+               switch ss := se.Sel.String(); ss {
+               case "IPNet", "IPAddr", "UDPAddr", "TCPAddr":
+                       for i, e := range cl.Elts {
+                               if _, ok := e.(*ast.KeyValueExpr); ok {
+                                       break
+                               }
+                               switch i {
+                               case 0:
+                                       cl.Elts[i] = &ast.KeyValueExpr{
+                                               Key:   ast.NewIdent("IP"),
+                                               Value: e,
+                                       }
+                               case 1:
+                                       if ss == "IPNet" {
+                                               cl.Elts[i] = &ast.KeyValueExpr{
+                                                       Key:   ast.NewIdent("Mask"),
+                                                       Value: e,
+                                               }
+                                       } else {
+                                               cl.Elts[i] = &ast.KeyValueExpr{
+                                                       Key:   ast.NewIdent("Port"),
+                                                       Value: e,
+                                               }
+                                       }
+                               }
+                               fixed = true
+                       }
+               }
+       })
+       return fixed
+}
diff --git a/src/cmd/fix/netipv6zone_test.go b/src/cmd/fix/netipv6zone_test.go
new file mode 100644 (file)
index 0000000..229daa3
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+       addTestCases(netipv6zoneTests, netipv6zone)
+}
+
+var netipv6zoneTests = []testCase{
+       {
+               Name: "netipv6zone.0",
+               In: `package main
+
+import "net"
+
+var a = []struct {
+       *net.IPNet
+}{
+       &net.IPNet{net.ParseIP("2001:DB8::"), net.IPMask(net.ParseIP("ffff:ffff:ffff::"))},
+}
+
+func f() net.Addr {
+       b := net.IPNet{net.IPv4(127, 0, 0, 1), net.IPv4Mask(255, 0, 0, 0)}
+       c := &net.IPAddr{ip1}
+       sub(&net.UDPAddr{ip2, 12345})
+       d := &net.TCPAddr{IP: ip3, Port: 54321}
+       return &net.TCPAddr{ip4}, nil
+}
+`,
+               Out: `package main
+
+import "net"
+
+var a = []struct {
+       *net.IPNet
+}{
+       &net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))},
+}
+
+func f() net.Addr {
+       b := net.IPNet{IP: net.IPv4(127, 0, 0, 1), Mask: net.IPv4Mask(255, 0, 0, 0)}
+       c := &net.IPAddr{IP: ip1}
+       sub(&net.UDPAddr{IP: ip2, Port: 12345})
+       d := &net.TCPAddr{IP: ip3, Port: 54321}
+       return &net.TCPAddr{IP: ip4}, nil
+}
+`,
+       },
+}
index 979d7acd53d949e7184c6bcf1cbe23f363bcd7b9..0aac3d187a1921ea7087ee54df4af63c8c4243db 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
@@ -645,5 +646,5 @@ func ParseCIDR(s string) (IP, *IPNet, error) {
                return nil, nil, &ParseError{"CIDR address", s}
        }
        m := CIDRMask(n, 8*iplen)
-       return ip, &IPNet{ip.Mask(m), m}, nil
+       return ip, &IPNet{IP: ip.Mask(m), Mask: m}, nil
 }
index df647ef73c0f8fda053474f95454209a1358c646..dc8a35270bf6c9008a9e4f954026352fece72e79 100644 (file)
@@ -114,23 +114,23 @@ var parsecidrtests = []struct {
        net *IPNet
        err error
 }{
-       {"135.104.0.0/32", IPv4(135, 104, 0, 0), &IPNet{IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 255)}, nil},
-       {"0.0.0.0/24", IPv4(0, 0, 0, 0), &IPNet{IPv4(0, 0, 0, 0), IPv4Mask(255, 255, 255, 0)}, nil},
-       {"135.104.0.0/24", IPv4(135, 104, 0, 0), &IPNet{IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 0)}, nil},
-       {"135.104.0.1/32", IPv4(135, 104, 0, 1), &IPNet{IPv4(135, 104, 0, 1), IPv4Mask(255, 255, 255, 255)}, nil},
-       {"135.104.0.1/24", IPv4(135, 104, 0, 1), &IPNet{IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 0)}, nil},
-       {"::1/128", ParseIP("::1"), &IPNet{ParseIP("::1"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))}, nil},
-       {"abcd:2345::/127", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe"))}, nil},
-       {"abcd:2345::/65", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:8000::"))}, nil},
-       {"abcd:2345::/64", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff::"))}, nil},
-       {"abcd:2345::/63", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:fffe::"))}, nil},
-       {"abcd:2345::/33", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:8000::"))}, nil},
-       {"abcd:2345::/32", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff::"))}, nil},
-       {"abcd:2344::/31", ParseIP("abcd:2344::"), &IPNet{ParseIP("abcd:2344::"), IPMask(ParseIP("ffff:fffe::"))}, nil},
-       {"abcd:2300::/24", ParseIP("abcd:2300::"), &IPNet{ParseIP("abcd:2300::"), IPMask(ParseIP("ffff:ff00::"))}, nil},
-       {"abcd:2345::/24", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2300::"), IPMask(ParseIP("ffff:ff00::"))}, nil},
-       {"2001:DB8::/48", ParseIP("2001:DB8::"), &IPNet{ParseIP("2001:DB8::"), IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
-       {"2001:DB8::1/48", ParseIP("2001:DB8::1"), &IPNet{ParseIP("2001:DB8::"), IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
+       {"135.104.0.0/32", IPv4(135, 104, 0, 0), &IPNet{IP: IPv4(135, 104, 0, 0), Mask: IPv4Mask(255, 255, 255, 255)}, nil},
+       {"0.0.0.0/24", IPv4(0, 0, 0, 0), &IPNet{IP: IPv4(0, 0, 0, 0), Mask: IPv4Mask(255, 255, 255, 0)}, nil},
+       {"135.104.0.0/24", IPv4(135, 104, 0, 0), &IPNet{IP: IPv4(135, 104, 0, 0), Mask: IPv4Mask(255, 255, 255, 0)}, nil},
+       {"135.104.0.1/32", IPv4(135, 104, 0, 1), &IPNet{IP: IPv4(135, 104, 0, 1), Mask: IPv4Mask(255, 255, 255, 255)}, nil},
+       {"135.104.0.1/24", IPv4(135, 104, 0, 1), &IPNet{IP: IPv4(135, 104, 0, 0), Mask: IPv4Mask(255, 255, 255, 0)}, nil},
+       {"::1/128", ParseIP("::1"), &IPNet{IP: ParseIP("::1"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))}, nil},
+       {"abcd:2345::/127", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe"))}, nil},
+       {"abcd:2345::/65", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:8000::"))}, nil},
+       {"abcd:2345::/64", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff::"))}, nil},
+       {"abcd:2345::/63", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:fffe::"))}, nil},
+       {"abcd:2345::/33", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:8000::"))}, nil},
+       {"abcd:2345::/32", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff::"))}, nil},
+       {"abcd:2344::/31", ParseIP("abcd:2344::"), &IPNet{IP: ParseIP("abcd:2344::"), Mask: IPMask(ParseIP("ffff:fffe::"))}, nil},
+       {"abcd:2300::/24", ParseIP("abcd:2300::"), &IPNet{IP: ParseIP("abcd:2300::"), Mask: IPMask(ParseIP("ffff:ff00::"))}, nil},
+       {"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},
        {"192.168.1.1/255.255.255.0", nil, nil, &ParseError{"CIDR address", "192.168.1.1/255.255.255.0"}},
        {"192.168.1.1/35", nil, nil, &ParseError{"CIDR address", "192.168.1.1/35"}},
        {"2001:db8::1/-1", nil, nil, &ParseError{"CIDR address", "2001:db8::1/-1"}},
@@ -154,14 +154,14 @@ var ipnetcontainstests = []struct {
        net *IPNet
        ok  bool
 }{
-       {IPv4(172, 16, 1, 1), &IPNet{IPv4(172, 16, 0, 0), CIDRMask(12, 32)}, true},
-       {IPv4(172, 24, 0, 1), &IPNet{IPv4(172, 16, 0, 0), CIDRMask(13, 32)}, false},
-       {IPv4(192, 168, 0, 3), &IPNet{IPv4(192, 168, 0, 0), IPv4Mask(0, 0, 255, 252)}, true},
-       {IPv4(192, 168, 0, 4), &IPNet{IPv4(192, 168, 0, 0), IPv4Mask(0, 255, 0, 252)}, false},
-       {ParseIP("2001:db8:1:2::1"), &IPNet{ParseIP("2001:db8:1::"), CIDRMask(47, 128)}, true},
-       {ParseIP("2001:db8:1:2::1"), &IPNet{ParseIP("2001:db8:2::"), CIDRMask(47, 128)}, false},
-       {ParseIP("2001:db8:1:2::1"), &IPNet{ParseIP("2001:db8:1::"), IPMask(ParseIP("ffff:0:ffff::"))}, true},
-       {ParseIP("2001:db8:1:2::1"), &IPNet{ParseIP("2001:db8:1::"), IPMask(ParseIP("0:0:0:ffff::"))}, false},
+       {IPv4(172, 16, 1, 1), &IPNet{IP: IPv4(172, 16, 0, 0), Mask: CIDRMask(12, 32)}, true},
+       {IPv4(172, 24, 0, 1), &IPNet{IP: IPv4(172, 16, 0, 0), Mask: CIDRMask(13, 32)}, false},
+       {IPv4(192, 168, 0, 3), &IPNet{IP: IPv4(192, 168, 0, 0), Mask: IPv4Mask(0, 0, 255, 252)}, true},
+       {IPv4(192, 168, 0, 4), &IPNet{IP: IPv4(192, 168, 0, 0), Mask: IPv4Mask(0, 255, 0, 252)}, false},
+       {ParseIP("2001:db8:1:2::1"), &IPNet{IP: ParseIP("2001:db8:1::"), Mask: CIDRMask(47, 128)}, true},
+       {ParseIP("2001:db8:1:2::1"), &IPNet{IP: ParseIP("2001:db8:2::"), Mask: CIDRMask(47, 128)}, false},
+       {ParseIP("2001:db8:1:2::1"), &IPNet{IP: ParseIP("2001:db8:1::"), Mask: IPMask(ParseIP("ffff:0:ffff::"))}, true},
+       {ParseIP("2001:db8:1:2::1"), &IPNet{IP: ParseIP("2001:db8:1::"), Mask: IPMask(ParseIP("0:0:0:ffff::"))}, false},
 }
 
 func TestIPNetContains(t *testing.T) {
@@ -176,10 +176,10 @@ var ipnetstringtests = []struct {
        in  *IPNet
        out string
 }{
-       {&IPNet{IPv4(192, 168, 1, 0), CIDRMask(26, 32)}, "192.168.1.0/26"},
-       {&IPNet{IPv4(192, 168, 1, 0), IPv4Mask(255, 0, 255, 0)}, "192.168.1.0/ff00ff00"},
-       {&IPNet{ParseIP("2001:db8::"), CIDRMask(55, 128)}, "2001:db8::/55"},
-       {&IPNet{ParseIP("2001:db8::"), IPMask(ParseIP("8000:f123:0:cafe::"))}, "2001:db8::/8000f1230000cafe0000000000000000"},
+       {&IPNet{IP: IPv4(192, 168, 1, 0), Mask: CIDRMask(26, 32)}, "192.168.1.0/26"},
+       {&IPNet{IP: IPv4(192, 168, 1, 0), Mask: IPv4Mask(255, 0, 255, 0)}, "192.168.1.0/ff00ff00"},
+       {&IPNet{IP: ParseIP("2001:db8::"), Mask: CIDRMask(55, 128)}, "2001:db8::/55"},
+       {&IPNet{IP: ParseIP("2001:db8::"), Mask: IPMask(ParseIP("8000:f123:0:cafe::"))}, "2001:db8::/8000f1230000cafe0000000000000000"},
 }
 
 func TestIPNetString(t *testing.T) {
@@ -233,27 +233,27 @@ var networknumberandmasktests = []struct {
        in  IPNet
        out IPNet
 }{
-       {IPNet{v4addr, v4mask}, IPNet{v4addr, v4mask}},
-       {IPNet{v4addr, v4mappedv6mask}, IPNet{v4addr, v4mask}},
-       {IPNet{v4mappedv6addr, v4mappedv6mask}, IPNet{v4addr, v4mask}},
-       {IPNet{v4mappedv6addr, v6mask}, IPNet{v4addr, v4maskzero}},
-       {IPNet{v4addr, v6mask}, IPNet{v4addr, v4maskzero}},
-       {IPNet{v6addr, v6mask}, IPNet{v6addr, v6mask}},
-       {IPNet{v6addr, v4mappedv6mask}, IPNet{v6addr, v4mappedv6mask}},
-       {in: IPNet{v6addr, v4mask}},
-       {in: IPNet{v4addr, badmask}},
-       {in: IPNet{v4mappedv6addr, badmask}},
-       {in: IPNet{v6addr, badmask}},
-       {in: IPNet{badaddr, v4mask}},
-       {in: IPNet{badaddr, v4mappedv6mask}},
-       {in: IPNet{badaddr, v6mask}},
-       {in: IPNet{badaddr, badmask}},
+       {IPNet{IP: v4addr, Mask: v4mask}, IPNet{IP: v4addr, Mask: v4mask}},
+       {IPNet{IP: v4addr, Mask: v4mappedv6mask}, IPNet{IP: v4addr, Mask: v4mask}},
+       {IPNet{IP: v4mappedv6addr, Mask: v4mappedv6mask}, IPNet{IP: v4addr, Mask: v4mask}},
+       {IPNet{IP: v4mappedv6addr, Mask: v6mask}, IPNet{IP: v4addr, Mask: v4maskzero}},
+       {IPNet{IP: v4addr, Mask: v6mask}, IPNet{IP: v4addr, Mask: v4maskzero}},
+       {IPNet{IP: v6addr, Mask: v6mask}, IPNet{IP: v6addr, Mask: v6mask}},
+       {IPNet{IP: v6addr, Mask: v4mappedv6mask}, IPNet{IP: v6addr, Mask: v4mappedv6mask}},
+       {in: IPNet{IP: v6addr, Mask: v4mask}},
+       {in: IPNet{IP: v4addr, Mask: badmask}},
+       {in: IPNet{IP: v4mappedv6addr, Mask: badmask}},
+       {in: IPNet{IP: v6addr, Mask: badmask}},
+       {in: IPNet{IP: badaddr, Mask: v4mask}},
+       {in: IPNet{IP: badaddr, Mask: v4mappedv6mask}},
+       {in: IPNet{IP: badaddr, Mask: v6mask}},
+       {in: IPNet{IP: badaddr, Mask: badmask}},
 }
 
 func TestNetworkNumberAndMask(t *testing.T) {
        for _, tt := range networknumberandmasktests {
                ip, m := networkNumberAndMask(&tt.in)
-               out := &IPNet{ip, m}
+               out := &IPNet{IP: ip, Mask: m}
                if !reflect.DeepEqual(&tt.out, out) {
                        t.Errorf("networkNumberAndMask(%v) = %v; want %v", tt.in, out, &tt.out)
                }
index d7bffc69e95d37b3944a45302778fc2b41a5fd9c..a141e6aee7417e79decd06434b56f2fe8a0d8a30 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// (Raw) IP sockets
+// Raw IP sockets
 
 package net
 
@@ -12,7 +12,8 @@ import (
 
 // IPAddr represents the address of an IP end point.
 type IPAddr struct {
-       IP IP
+       IP   IP
+       Zone string // IPv6 scoped addressing zone
 }
 
 // Network returns the address's network name, "ip".
@@ -38,7 +39,7 @@ func resolveIPAddr(net, addr string, deadline time.Time) (*IPAddr, error) {
        if err != nil {
                return nil, err
        }
-       return &IPAddr{ip}, nil
+       return &IPAddr{IP: ip}, nil
 }
 
 // Convert "host" into IP address.
index e77c5476afad6a506c7fb65ed0733a9599f9c096..9a28256251ef241a326a91eb0683fdb64b3b9047 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// (Raw) IP sockets stubs for Plan 9
+// Raw IP sockets for Plan 9
 
 package net
 
@@ -77,8 +77,6 @@ func (c *IPConn) Close() error {
        return syscall.EPLAN9
 }
 
-// IP-specific methods.
-
 // ReadFromIP reads an IP packet from c, copying the payload into b.
 // It returns the number of bytes copied into b and the return address
 // that was on the packet.
index 00e87cfbf0dda38c65d9d314f56f924a0c5eaf58..7a8cd4470d613cfba743a3db534e1bdab095990d 100644 (file)
@@ -4,7 +4,7 @@
 
 // +build darwin freebsd linux netbsd openbsd windows
 
-// (Raw) IP sockets
+// Raw IP sockets for POSIX
 
 package net
 
@@ -16,9 +16,9 @@ import (
 func sockaddrToIP(sa syscall.Sockaddr) Addr {
        switch sa := sa.(type) {
        case *syscall.SockaddrInet4:
-               return &IPAddr{sa.Addr[0:]}
+               return &IPAddr{IP: sa.Addr[0:]}
        case *syscall.SockaddrInet6:
-               return &IPAddr{sa.Addr[0:]}
+               return &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
        }
        return nil
 }
@@ -41,7 +41,7 @@ func (a *IPAddr) isWildcard() bool {
 }
 
 func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
-       return ipToSockaddr(family, a.IP, 0)
+       return ipToSockaddr(family, a.IP, 0, a.Zone)
 }
 
 func (a *IPAddr) toAddr() sockaddr {
@@ -59,8 +59,6 @@ type IPConn struct {
 
 func newIPConn(fd *netFD) *IPConn { return &IPConn{conn{fd}} }
 
-// IP-specific methods.
-
 // ReadFromIP reads an IP packet from c, copying the payload into b.
 // It returns the number of bytes copied into b and the return address
 // that was on the packet.
@@ -78,14 +76,14 @@ func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
        n, sa, err := c.fd.ReadFrom(b)
        switch sa := sa.(type) {
        case *syscall.SockaddrInet4:
-               addr = &IPAddr{sa.Addr[0:]}
+               addr = &IPAddr{IP: sa.Addr[0:]}
                if len(b) >= IPv4len { // discard ipv4 header
                        hsize := (int(b[0]) & 0xf) * 4
                        copy(b, b[hsize:])
                        n -= hsize
                }
        case *syscall.SockaddrInet6:
-               addr = &IPAddr{sa.Addr[0:]}
+               addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
        }
        return n, addr, err
 }
@@ -95,8 +93,8 @@ func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
        if !c.ok() {
                return 0, nil, syscall.EINVAL
        }
-       n, uaddr, err := c.ReadFromIP(b)
-       return n, uaddr.toAddr(), err
+       n, addr, err := c.ReadFromIP(b)
+       return n, addr.toAddr(), err
 }
 
 // ReadMsgIP reads a packet from c, copying the payload into b and the
@@ -111,9 +109,9 @@ func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err
        n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
        switch sa := sa.(type) {
        case *syscall.SockaddrInet4:
-               addr = &IPAddr{sa.Addr[0:]}
+               addr = &IPAddr{IP: sa.Addr[0:]}
        case *syscall.SockaddrInet6:
-               addr = &IPAddr{sa.Addr[0:]}
+               addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
        }
        return
 }
index 9d48e8c1036347d94e7a1d34d796f9d44efbcf47..bd6fe7a0e01e6eb5ad5f419486f97cb6db734fc7 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// IP sockets
+// Internet protocol family sockets
 
 package net
 
@@ -143,3 +143,24 @@ func hostPortToIP(net, hostport string, deadline time.Time) (ip IP, iport int, e
 
        return addr, p, nil
 }
+
+func zoneToString(zone int) string {
+       if zone == 0 {
+               return ""
+       }
+       if ifi, err := InterfaceByIndex(zone); err == nil {
+               return ifi.Name
+       }
+       return itod(uint(zone))
+}
+
+func zoneToInt(zone string) int {
+       if zone == "" {
+               return 0
+       }
+       if ifi, err := InterfaceByName(zone); err == nil {
+               return ifi.Index
+       }
+       n, _, _ := dtoi(zone, 0)
+       return n
+}
index 138c3b4855b7f4a6d864a5f20160302a6ee6b26e..eaef768fd01e30dafd7c207fd2686e23a285ff02 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// IP sockets stubs for Plan 9
+// Internet protocol family sockets for Plan 9
 
 package net
 
@@ -59,9 +59,9 @@ func readPlan9Addr(proto, filename string) (addr Addr, err error) {
        }
        switch proto {
        case "tcp":
-               addr = &TCPAddr{ip, port}
+               addr = &TCPAddr{IP: ip, Port: port}
        case "udp":
-               addr = &UDPAddr{ip, port}
+               addr = &UDPAddr{IP: ip, Port: port}
        default:
                return nil, errors.New("unknown protocol " + proto)
        }
index 87a2288973b9c1a9cefc67d275a5f1c075b33a07..4c37616ecf861d8f0fd11b008a8c4556d11df570 100644 (file)
@@ -4,6 +4,8 @@
 
 // +build darwin freebsd linux netbsd openbsd windows
 
+// Internet protocol family sockets for POSIX
+
 package net
 
 import (
@@ -155,7 +157,7 @@ Error:
        return nil, &OpError{mode, net, addr, err}
 }
 
-func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, error) {
+func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, error) {
        switch family {
        case syscall.AF_INET:
                if len(ip) == 0 {
@@ -164,12 +166,12 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, error) {
                if ip = ip.To4(); ip == nil {
                        return nil, InvalidAddrError("non-IPv4 address")
                }
-               s := new(syscall.SockaddrInet4)
+               sa := new(syscall.SockaddrInet4)
                for i := 0; i < IPv4len; i++ {
-                       s.Addr[i] = ip[i]
+                       sa.Addr[i] = ip[i]
                }
-               s.Port = port
-               return s, nil
+               sa.Port = port
+               return sa, nil
        case syscall.AF_INET6:
                if len(ip) == 0 {
                        ip = IPv6zero
@@ -183,12 +185,13 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, error) {
                if ip = ip.To16(); ip == nil {
                        return nil, InvalidAddrError("non-IPv6 address")
                }
-               s := new(syscall.SockaddrInet6)
+               sa := new(syscall.SockaddrInet6)
                for i := 0; i < IPv6len; i++ {
-                       s.Addr[i] = ip[i]
+                       sa.Addr[i] = ip[i]
                }
-               s.Port = port
-               return s, nil
+               sa.Port = port
+               sa.ZoneId = uint32(zoneToInt(zone))
+               return sa, nil
        }
        return nil, InvalidAddrError("unexpected socket family")
 }
index d4a8a35627dd937977dacd1d8f9f96f55cffa6d8..bcc13ee8511b013ab28d2b7dd341eddc61cd4be4 100644 (file)
@@ -21,26 +21,26 @@ var multicastListenerTests = []struct {
 }{
        // cf. RFC 4727: Experimental Values in IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP Headers
 
-       {"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
-       {"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, 0, false},
-       {"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
-       {"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, 0, true},
+       {"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, FlagUp | FlagLoopback, false},
+       {"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, 0, false},
+       {"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, FlagUp | FlagLoopback, true},
+       {"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, 0, true},
 
-       {"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
-       {"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, 0, false},
+       {"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, FlagUp | FlagLoopback, false},
+       {"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, 0, false},
 
-       {"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, FlagUp | FlagLoopback, true},
-       {"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, 0, true},
-       {"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, FlagUp | FlagLoopback, true},
-       {"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, 0, true},
-       {"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, FlagUp | FlagLoopback, true},
-       {"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, 0, true},
-       {"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, FlagUp | FlagLoopback, true},
-       {"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, 0, true},
-       {"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, FlagUp | FlagLoopback, true},
-       {"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, 0, true},
-       {"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
-       {"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, 0, true},
+       {"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}, FlagUp | FlagLoopback, true},
+       {"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}, 0, true},
+       {"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}, FlagUp | FlagLoopback, true},
+       {"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}, 0, true},
+       {"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}, FlagUp | FlagLoopback, true},
+       {"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}, 0, true},
+       {"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}, FlagUp | FlagLoopback, true},
+       {"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}, 0, true},
+       {"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}, FlagUp | FlagLoopback, true},
+       {"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}, 0, true},
+       {"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, FlagUp | FlagLoopback, true},
+       {"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, 0, true},
 }
 
 // TestMulticastListener tests both single and double listen to a test
index 6aba1f89fc82451e93a5d13abca13afcd23879ae..acded26528db9a184c60cad3f3168425200bfde0 100644 (file)
@@ -12,6 +12,7 @@ import "time"
 type TCPAddr struct {
        IP   IP
        Port int
+       Zone string // IPv6 scoped addressing zone
 }
 
 // Network returns the address's network name, "tcp".
@@ -38,5 +39,5 @@ func resolveTCPAddr(net, addr string, deadline time.Time) (*TCPAddr, error) {
        if err != nil {
                return nil, err
        }
-       return &TCPAddr{ip, port}, nil
+       return &TCPAddr{IP: ip, Port: port}, nil
 }
index e5b3a09f75c257eba7f46f6e7346d3562c375c68..2d70165647317bcfbd608f0c5c48c78b1605484c 100644 (file)
@@ -23,9 +23,9 @@ import (
 func sockaddrToTCP(sa syscall.Sockaddr) Addr {
        switch sa := sa.(type) {
        case *syscall.SockaddrInet4:
-               return &TCPAddr{sa.Addr[0:], sa.Port}
+               return &TCPAddr{IP: sa.Addr[0:], Port: sa.Port}
        case *syscall.SockaddrInet6:
-               return &TCPAddr{sa.Addr[0:], sa.Port}
+               return &TCPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
        default:
                if sa != nil {
                        // Diagnose when we will turn a non-nil sockaddr into a nil.
@@ -53,7 +53,7 @@ func (a *TCPAddr) isWildcard() bool {
 }
 
 func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
-       return ipToSockaddr(family, a.IP, a.Port)
+       return ipToSockaddr(family, a.IP, a.Port, a.Zone)
 }
 
 func (a *TCPAddr) toAddr() sockaddr {
index bf2107b03a22438267ccc8be78ce1127684a2325..66f795185c04bf66167a910dfa8f354adf7e9a9e 100644 (file)
@@ -17,6 +17,7 @@ var ErrWriteToConnected = errors.New("use of WriteTo with pre-connected UDP")
 type UDPAddr struct {
        IP   IP
        Port int
+       Zone string // IPv6 scoped addressing zone
 }
 
 // Network returns the address's network name, "udp".
@@ -43,5 +44,5 @@ func resolveUDPAddr(net, addr string, deadline time.Time) (*UDPAddr, error) {
        if err != nil {
                return nil, err
        }
-       return &UDPAddr{ip, port}, nil
+       return &UDPAddr{IP: ip, Port: port}, nil
 }
index 6a828e14d20378dac788baff9237b4901179d3be..46d2de2380f42d9fd53108a99990406a397ba335 100644 (file)
@@ -19,8 +19,6 @@ type UDPConn struct {
        conn
 }
 
-// UDP-specific methods.
-
 // ReadFromUDP reads a UDP packet from c, copying the payload into b.
 // It returns the number of bytes copied into b and the return address
 // that was on the packet.
@@ -50,7 +48,7 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
 
        h, buf := unmarshalUDPHeader(buf)
        n = copy(b, buf)
-       return n, &UDPAddr{h.raddr, int(h.rport)}, nil
+       return n, &UDPAddr{IP: h.raddr, Port: int(h.rport)}, nil
 }
 
 // ReadFrom implements the PacketConn ReadFrom method.
index d7329bf32fc1809fce396a925b3ef7a3dd681be9..b7de678f928c979b58940edb4e598b8a18d5f7f6 100644 (file)
@@ -4,7 +4,7 @@
 
 // +build darwin freebsd linux netbsd openbsd windows
 
-// UDP sockets
+// UDP sockets for POSIX
 
 package net
 
@@ -16,9 +16,9 @@ import (
 func sockaddrToUDP(sa syscall.Sockaddr) Addr {
        switch sa := sa.(type) {
        case *syscall.SockaddrInet4:
-               return &UDPAddr{sa.Addr[0:], sa.Port}
+               return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
        case *syscall.SockaddrInet6:
-               return &UDPAddr{sa.Addr[0:], sa.Port}
+               return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
        }
        return nil
 }
@@ -41,7 +41,7 @@ func (a *UDPAddr) isWildcard() bool {
 }
 
 func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
-       return ipToSockaddr(family, a.IP, a.Port)
+       return ipToSockaddr(family, a.IP, a.Port, a.Zone)
 }
 
 func (a *UDPAddr) toAddr() sockaddr {
@@ -59,8 +59,6 @@ type UDPConn struct {
 
 func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
 
-// UDP-specific methods.
-
 // ReadFromUDP reads a UDP packet from c, copying the payload into b.
 // It returns the number of bytes copied into b and the return address
 // that was on the packet.
@@ -74,9 +72,9 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
        n, sa, err := c.fd.ReadFrom(b)
        switch sa := sa.(type) {
        case *syscall.SockaddrInet4:
-               addr = &UDPAddr{sa.Addr[0:], sa.Port}
+               addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
        case *syscall.SockaddrInet6:
-               addr = &UDPAddr{sa.Addr[0:], sa.Port}
+               addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
        }
        return
 }
@@ -86,8 +84,8 @@ func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
        if !c.ok() {
                return 0, nil, syscall.EINVAL
        }
-       n, uaddr, err := c.ReadFromUDP(b)
-       return n, uaddr.toAddr(), err
+       n, addr, err := c.ReadFromUDP(b)
+       return n, addr.toAddr(), err
 }
 
 // ReadMsgUDP reads a packet from c, copying the payload into b and
@@ -103,9 +101,9 @@ func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr,
        n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
        switch sa := sa.(type) {
        case *syscall.SockaddrInet4:
-               addr = &UDPAddr{sa.Addr[0:], sa.Port}
+               addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
        case *syscall.SockaddrInet6:
-               addr = &UDPAddr{sa.Addr[0:], sa.Port}
+               addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
        }
        return
 }
@@ -276,7 +274,7 @@ func listenIPv6MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
 func joinIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
        err := joinIPv4Group(c.fd, ifi, ip)
        if err != nil {
-               return &OpError{"joinipv4group", c.fd.net, &IPAddr{ip}, err}
+               return &OpError{"joinipv4group", c.fd.net, &IPAddr{IP: ip}, err}
        }
        return nil
 }
@@ -284,7 +282,7 @@ func joinIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
 func joinIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
        err := joinIPv6Group(c.fd, ifi, ip)
        if err != nil {
-               return &OpError{"joinipv6group", c.fd.net, &IPAddr{ip}, err}
+               return &OpError{"joinipv6group", c.fd.net, &IPAddr{IP: ip}, err}
        }
        return nil
 }