From e8cf49f701cf9204f51df2557f75e33d2da4b5d9 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Tue, 27 Nov 2012 00:45:42 +0900 Subject: [PATCH] net, cmd/fix: add IPv6 scoped addressing zone to INET, INET6 address structs 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 --- src/cmd/fix/netipv6zone.go | 71 +++++++++++++++++++++++ src/cmd/fix/netipv6zone_test.go | 51 ++++++++++++++++ src/pkg/net/ip.go | 3 +- src/pkg/net/ip_test.go | 90 ++++++++++++++--------------- src/pkg/net/iprawsock.go | 7 ++- src/pkg/net/iprawsock_plan9.go | 4 +- src/pkg/net/iprawsock_posix.go | 22 ++++--- src/pkg/net/ipsock.go | 23 +++++++- src/pkg/net/ipsock_plan9.go | 6 +- src/pkg/net/ipsock_posix.go | 21 ++++--- src/pkg/net/multicast_posix_test.go | 36 ++++++------ src/pkg/net/tcpsock.go | 3 +- src/pkg/net/tcpsock_posix.go | 6 +- src/pkg/net/udpsock.go | 3 +- src/pkg/net/udpsock_plan9.go | 4 +- src/pkg/net/udpsock_posix.go | 26 ++++----- 16 files changed, 259 insertions(+), 117 deletions(-) create mode 100644 src/cmd/fix/netipv6zone.go create mode 100644 src/cmd/fix/netipv6zone_test.go diff --git a/src/cmd/fix/netipv6zone.go b/src/cmd/fix/netipv6zone.go new file mode 100644 index 0000000000..587b9ffec6 --- /dev/null +++ b/src/cmd/fix/netipv6zone.go @@ -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 index 0000000000..229daa386d --- /dev/null +++ b/src/cmd/fix/netipv6zone_test.go @@ -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 +} +`, + }, +} diff --git a/src/pkg/net/ip.go b/src/pkg/net/ip.go index 979d7acd53..0aac3d187a 100644 --- a/src/pkg/net/ip.go +++ b/src/pkg/net/ip.go @@ -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 } diff --git a/src/pkg/net/ip_test.go b/src/pkg/net/ip_test.go index df647ef73c..dc8a35270b 100644 --- a/src/pkg/net/ip_test.go +++ b/src/pkg/net/ip_test.go @@ -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) } diff --git a/src/pkg/net/iprawsock.go b/src/pkg/net/iprawsock.go index d7bffc69e9..a141e6aee7 100644 --- a/src/pkg/net/iprawsock.go +++ b/src/pkg/net/iprawsock.go @@ -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. diff --git a/src/pkg/net/iprawsock_plan9.go b/src/pkg/net/iprawsock_plan9.go index e77c5476af..9a28256251 100644 --- a/src/pkg/net/iprawsock_plan9.go +++ b/src/pkg/net/iprawsock_plan9.go @@ -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. diff --git a/src/pkg/net/iprawsock_posix.go b/src/pkg/net/iprawsock_posix.go index 00e87cfbf0..7a8cd4470d 100644 --- a/src/pkg/net/iprawsock_posix.go +++ b/src/pkg/net/iprawsock_posix.go @@ -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 } diff --git a/src/pkg/net/ipsock.go b/src/pkg/net/ipsock.go index 9d48e8c103..bd6fe7a0e0 100644 --- a/src/pkg/net/ipsock.go +++ b/src/pkg/net/ipsock.go @@ -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 +} diff --git a/src/pkg/net/ipsock_plan9.go b/src/pkg/net/ipsock_plan9.go index 138c3b4855..eaef768fd0 100644 --- a/src/pkg/net/ipsock_plan9.go +++ b/src/pkg/net/ipsock_plan9.go @@ -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) } diff --git a/src/pkg/net/ipsock_posix.go b/src/pkg/net/ipsock_posix.go index 87a2288973..4c37616ecf 100644 --- a/src/pkg/net/ipsock_posix.go +++ b/src/pkg/net/ipsock_posix.go @@ -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") } diff --git a/src/pkg/net/multicast_posix_test.go b/src/pkg/net/multicast_posix_test.go index d4a8a35627..bcc13ee851 100644 --- a/src/pkg/net/multicast_posix_test.go +++ b/src/pkg/net/multicast_posix_test.go @@ -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 diff --git a/src/pkg/net/tcpsock.go b/src/pkg/net/tcpsock.go index 6aba1f89fc..acded26528 100644 --- a/src/pkg/net/tcpsock.go +++ b/src/pkg/net/tcpsock.go @@ -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 } diff --git a/src/pkg/net/tcpsock_posix.go b/src/pkg/net/tcpsock_posix.go index e5b3a09f75..2d70165647 100644 --- a/src/pkg/net/tcpsock_posix.go +++ b/src/pkg/net/tcpsock_posix.go @@ -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 { diff --git a/src/pkg/net/udpsock.go b/src/pkg/net/udpsock.go index bf2107b03a..66f795185c 100644 --- a/src/pkg/net/udpsock.go +++ b/src/pkg/net/udpsock.go @@ -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 } diff --git a/src/pkg/net/udpsock_plan9.go b/src/pkg/net/udpsock_plan9.go index 6a828e14d2..46d2de2380 100644 --- a/src/pkg/net/udpsock_plan9.go +++ b/src/pkg/net/udpsock_plan9.go @@ -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. diff --git a/src/pkg/net/udpsock_posix.go b/src/pkg/net/udpsock_posix.go index d7329bf32f..b7de678f92 100644 --- a/src/pkg/net/udpsock_posix.go +++ b/src/pkg/net/udpsock_posix.go @@ -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 } -- 2.48.1