Commit e8cf49f7 authored by Mikio Hara's avatar Mikio Hara

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
parent f02cf199
// 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
}
// 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
}
`,
},
}
...@@ -36,6 +36,7 @@ type IPMask []byte ...@@ -36,6 +36,7 @@ type IPMask []byte
type IPNet struct { type IPNet struct {
IP IP // network number IP IP // network number
Mask IPMask // network mask Mask IPMask // network mask
Zone string // IPv6 scoped addressing zone
} }
// IPv4 returns the IP address (in 16-byte form) of the // IPv4 returns the IP address (in 16-byte form) of the
...@@ -645,5 +646,5 @@ func ParseCIDR(s string) (IP, *IPNet, error) { ...@@ -645,5 +646,5 @@ func ParseCIDR(s string) (IP, *IPNet, error) {
return nil, nil, &ParseError{"CIDR address", s} return nil, nil, &ParseError{"CIDR address", s}
} }
m := CIDRMask(n, 8*iplen) m := CIDRMask(n, 8*iplen)
return ip, &IPNet{ip.Mask(m), m}, nil return ip, &IPNet{IP: ip.Mask(m), Mask: m}, nil
} }
...@@ -114,23 +114,23 @@ var parsecidrtests = []struct { ...@@ -114,23 +114,23 @@ var parsecidrtests = []struct {
net *IPNet net *IPNet
err error err error
}{ }{
{"135.104.0.0/32", IPv4(135, 104, 0, 0), &IPNet{IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 255)}, 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{IPv4(0, 0, 0, 0), IPv4Mask(255, 255, 255, 0)}, 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{IPv4(135, 104, 0, 0), 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{IPv4(135, 104, 0, 1), IPv4Mask(255, 255, 255, 255)}, 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{IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 0)}, 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{ParseIP("::1"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))}, 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{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe"))}, 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{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:8000::"))}, 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{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff::"))}, 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{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:fffe::"))}, 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{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:8000::"))}, 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{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff::"))}, 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{ParseIP("abcd:2344::"), IPMask(ParseIP("ffff:fffe::"))}, 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{ParseIP("abcd:2300::"), IPMask(ParseIP("ffff:ff00::"))}, 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{ParseIP("abcd:2300::"), 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{ParseIP("2001:DB8::"), IPMask(ParseIP("ffff:ffff:ffff::"))}, 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{ParseIP("2001:DB8::"), 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/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"}}, {"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"}}, {"2001:db8::1/-1", nil, nil, &ParseError{"CIDR address", "2001:db8::1/-1"}},
...@@ -154,14 +154,14 @@ var ipnetcontainstests = []struct { ...@@ -154,14 +154,14 @@ var ipnetcontainstests = []struct {
net *IPNet net *IPNet
ok bool ok bool
}{ }{
{IPv4(172, 16, 1, 1), &IPNet{IPv4(172, 16, 0, 0), CIDRMask(12, 32)}, true}, {IPv4(172, 16, 1, 1), &IPNet{IP: IPv4(172, 16, 0, 0), Mask: CIDRMask(12, 32)}, true},
{IPv4(172, 24, 0, 1), &IPNet{IPv4(172, 16, 0, 0), CIDRMask(13, 32)}, false}, {IPv4(172, 24, 0, 1), &IPNet{IP: IPv4(172, 16, 0, 0), Mask: 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, 3), &IPNet{IP: IPv4(192, 168, 0, 0), Mask: IPv4Mask(0, 0, 255, 252)}, true},
{IPv4(192, 168, 0, 4), &IPNet{IPv4(192, 168, 0, 0), IPv4Mask(0, 255, 0, 252)}, false}, {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{ParseIP("2001:db8:1::"), CIDRMask(47, 128)}, true}, {ParseIP("2001:db8:1:2::1"), &IPNet{IP: ParseIP("2001:db8:1::"), Mask: 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{IP: ParseIP("2001:db8:2::"), Mask: 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{IP: ParseIP("2001:db8:1::"), Mask: IPMask(ParseIP("ffff:0:ffff::"))}, true},
{ParseIP("2001:db8:1:2::1"), &IPNet{ParseIP("2001:db8:1::"), IPMask(ParseIP("0:0:0:ffff::"))}, false}, {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) { func TestIPNetContains(t *testing.T) {
...@@ -176,10 +176,10 @@ var ipnetstringtests = []struct { ...@@ -176,10 +176,10 @@ var ipnetstringtests = []struct {
in *IPNet in *IPNet
out string out string
}{ }{
{&IPNet{IPv4(192, 168, 1, 0), CIDRMask(26, 32)}, "192.168.1.0/26"}, {&IPNet{IP: IPv4(192, 168, 1, 0), Mask: 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{IP: IPv4(192, 168, 1, 0), Mask: IPv4Mask(255, 0, 255, 0)}, "192.168.1.0/ff00ff00"},
{&IPNet{ParseIP("2001:db8::"), CIDRMask(55, 128)}, "2001:db8::/55"}, {&IPNet{IP: ParseIP("2001:db8::"), Mask: CIDRMask(55, 128)}, "2001:db8::/55"},
{&IPNet{ParseIP("2001:db8::"), IPMask(ParseIP("8000:f123:0:cafe::"))}, "2001:db8::/8000f1230000cafe0000000000000000"}, {&IPNet{IP: ParseIP("2001:db8::"), Mask: IPMask(ParseIP("8000:f123:0:cafe::"))}, "2001:db8::/8000f1230000cafe0000000000000000"},
} }
func TestIPNetString(t *testing.T) { func TestIPNetString(t *testing.T) {
...@@ -233,27 +233,27 @@ var networknumberandmasktests = []struct { ...@@ -233,27 +233,27 @@ var networknumberandmasktests = []struct {
in IPNet in IPNet
out IPNet out IPNet
}{ }{
{IPNet{v4addr, v4mask}, IPNet{v4addr, v4mask}}, {IPNet{IP: v4addr, Mask: v4mask}, IPNet{IP: v4addr, Mask: v4mask}},
{IPNet{v4addr, v4mappedv6mask}, IPNet{v4addr, v4mask}}, {IPNet{IP: v4addr, Mask: v4mappedv6mask}, IPNet{IP: v4addr, Mask: v4mask}},
{IPNet{v4mappedv6addr, v4mappedv6mask}, IPNet{v4addr, v4mask}}, {IPNet{IP: v4mappedv6addr, Mask: v4mappedv6mask}, IPNet{IP: v4addr, Mask: v4mask}},
{IPNet{v4mappedv6addr, v6mask}, IPNet{v4addr, v4maskzero}}, {IPNet{IP: v4mappedv6addr, Mask: v6mask}, IPNet{IP: v4addr, Mask: v4maskzero}},
{IPNet{v4addr, v6mask}, IPNet{v4addr, v4maskzero}}, {IPNet{IP: v4addr, Mask: v6mask}, IPNet{IP: v4addr, Mask: v4maskzero}},
{IPNet{v6addr, v6mask}, IPNet{v6addr, v6mask}}, {IPNet{IP: v6addr, Mask: v6mask}, IPNet{IP: v6addr, Mask: v6mask}},
{IPNet{v6addr, v4mappedv6mask}, IPNet{v6addr, v4mappedv6mask}}, {IPNet{IP: v6addr, Mask: v4mappedv6mask}, IPNet{IP: v6addr, Mask: v4mappedv6mask}},
{in: IPNet{v6addr, v4mask}}, {in: IPNet{IP: v6addr, Mask: v4mask}},
{in: IPNet{v4addr, badmask}}, {in: IPNet{IP: v4addr, Mask: badmask}},
{in: IPNet{v4mappedv6addr, badmask}}, {in: IPNet{IP: v4mappedv6addr, Mask: badmask}},
{in: IPNet{v6addr, badmask}}, {in: IPNet{IP: v6addr, Mask: badmask}},
{in: IPNet{badaddr, v4mask}}, {in: IPNet{IP: badaddr, Mask: v4mask}},
{in: IPNet{badaddr, v4mappedv6mask}}, {in: IPNet{IP: badaddr, Mask: v4mappedv6mask}},
{in: IPNet{badaddr, v6mask}}, {in: IPNet{IP: badaddr, Mask: v6mask}},
{in: IPNet{badaddr, badmask}}, {in: IPNet{IP: badaddr, Mask: badmask}},
} }
func TestNetworkNumberAndMask(t *testing.T) { func TestNetworkNumberAndMask(t *testing.T) {
for _, tt := range networknumberandmasktests { for _, tt := range networknumberandmasktests {
ip, m := networkNumberAndMask(&tt.in) ip, m := networkNumberAndMask(&tt.in)
out := &IPNet{ip, m} out := &IPNet{IP: ip, Mask: m}
if !reflect.DeepEqual(&tt.out, out) { if !reflect.DeepEqual(&tt.out, out) {
t.Errorf("networkNumberAndMask(%v) = %v; want %v", tt.in, out, &tt.out) t.Errorf("networkNumberAndMask(%v) = %v; want %v", tt.in, out, &tt.out)
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// (Raw) IP sockets // Raw IP sockets
package net package net
...@@ -13,6 +13,7 @@ import ( ...@@ -13,6 +13,7 @@ import (
// IPAddr represents the address of an IP end point. // IPAddr represents the address of an IP end point.
type IPAddr struct { type IPAddr struct {
IP IP IP IP
Zone string // IPv6 scoped addressing zone
} }
// Network returns the address's network name, "ip". // Network returns the address's network name, "ip".
...@@ -38,7 +39,7 @@ func resolveIPAddr(net, addr string, deadline time.Time) (*IPAddr, error) { ...@@ -38,7 +39,7 @@ func resolveIPAddr(net, addr string, deadline time.Time) (*IPAddr, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &IPAddr{ip}, nil return &IPAddr{IP: ip}, nil
} }
// Convert "host" into IP address. // Convert "host" into IP address.
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// (Raw) IP sockets stubs for Plan 9 // Raw IP sockets for Plan 9
package net package net
...@@ -77,8 +77,6 @@ func (c *IPConn) Close() error { ...@@ -77,8 +77,6 @@ func (c *IPConn) Close() error {
return syscall.EPLAN9 return syscall.EPLAN9
} }
// IP-specific methods.
// ReadFromIP reads an IP packet from c, copying the payload into b. // 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 // It returns the number of bytes copied into b and the return address
// that was on the packet. // that was on the packet.
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
// +build darwin freebsd linux netbsd openbsd windows // +build darwin freebsd linux netbsd openbsd windows
// (Raw) IP sockets // Raw IP sockets for POSIX
package net package net
...@@ -16,9 +16,9 @@ import ( ...@@ -16,9 +16,9 @@ import (
func sockaddrToIP(sa syscall.Sockaddr) Addr { func sockaddrToIP(sa syscall.Sockaddr) Addr {
switch sa := sa.(type) { switch sa := sa.(type) {
case *syscall.SockaddrInet4: case *syscall.SockaddrInet4:
return &IPAddr{sa.Addr[0:]} return &IPAddr{IP: sa.Addr[0:]}
case *syscall.SockaddrInet6: case *syscall.SockaddrInet6:
return &IPAddr{sa.Addr[0:]} return &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
} }
return nil return nil
} }
...@@ -41,7 +41,7 @@ func (a *IPAddr) isWildcard() bool { ...@@ -41,7 +41,7 @@ func (a *IPAddr) isWildcard() bool {
} }
func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) { 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 { func (a *IPAddr) toAddr() sockaddr {
...@@ -59,8 +59,6 @@ type IPConn struct { ...@@ -59,8 +59,6 @@ type IPConn struct {
func newIPConn(fd *netFD) *IPConn { return &IPConn{conn{fd}} } func newIPConn(fd *netFD) *IPConn { return &IPConn{conn{fd}} }
// IP-specific methods.
// ReadFromIP reads an IP packet from c, copying the payload into b. // 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 // It returns the number of bytes copied into b and the return address
// that was on the packet. // that was on the packet.
...@@ -78,14 +76,14 @@ func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) { ...@@ -78,14 +76,14 @@ func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
n, sa, err := c.fd.ReadFrom(b) n, sa, err := c.fd.ReadFrom(b)
switch sa := sa.(type) { switch sa := sa.(type) {
case *syscall.SockaddrInet4: case *syscall.SockaddrInet4:
addr = &IPAddr{sa.Addr[0:]} addr = &IPAddr{IP: sa.Addr[0:]}
if len(b) >= IPv4len { // discard ipv4 header if len(b) >= IPv4len { // discard ipv4 header
hsize := (int(b[0]) & 0xf) * 4 hsize := (int(b[0]) & 0xf) * 4
copy(b, b[hsize:]) copy(b, b[hsize:])
n -= hsize n -= hsize
} }
case *syscall.SockaddrInet6: case *syscall.SockaddrInet6:
addr = &IPAddr{sa.Addr[0:]} addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
} }
return n, addr, err return n, addr, err
} }
...@@ -95,8 +93,8 @@ func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) { ...@@ -95,8 +93,8 @@ func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
if !c.ok() { if !c.ok() {
return 0, nil, syscall.EINVAL return 0, nil, syscall.EINVAL
} }
n, uaddr, err := c.ReadFromIP(b) n, addr, err := c.ReadFromIP(b)
return n, uaddr.toAddr(), err return n, addr.toAddr(), err
} }
// ReadMsgIP reads a packet from c, copying the payload into b and the // 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 ...@@ -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) n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
switch sa := sa.(type) { switch sa := sa.(type) {
case *syscall.SockaddrInet4: case *syscall.SockaddrInet4:
addr = &IPAddr{sa.Addr[0:]} addr = &IPAddr{IP: sa.Addr[0:]}
case *syscall.SockaddrInet6: case *syscall.SockaddrInet6:
addr = &IPAddr{sa.Addr[0:]} addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
} }
return return
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// IP sockets // Internet protocol family sockets
package net package net
...@@ -143,3 +143,24 @@ func hostPortToIP(net, hostport string, deadline time.Time) (ip IP, iport int, e ...@@ -143,3 +143,24 @@ func hostPortToIP(net, hostport string, deadline time.Time) (ip IP, iport int, e
return addr, p, nil 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
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// IP sockets stubs for Plan 9 // Internet protocol family sockets for Plan 9
package net package net
...@@ -59,9 +59,9 @@ func readPlan9Addr(proto, filename string) (addr Addr, err error) { ...@@ -59,9 +59,9 @@ func readPlan9Addr(proto, filename string) (addr Addr, err error) {
} }
switch proto { switch proto {
case "tcp": case "tcp":
addr = &TCPAddr{ip, port} addr = &TCPAddr{IP: ip, Port: port}
case "udp": case "udp":
addr = &UDPAddr{ip, port} addr = &UDPAddr{IP: ip, Port: port}
default: default:
return nil, errors.New("unknown protocol " + proto) return nil, errors.New("unknown protocol " + proto)
} }
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
// +build darwin freebsd linux netbsd openbsd windows // +build darwin freebsd linux netbsd openbsd windows
// Internet protocol family sockets for POSIX
package net package net
import ( import (
...@@ -155,7 +157,7 @@ Error: ...@@ -155,7 +157,7 @@ Error:
return nil, &OpError{mode, net, addr, err} 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 { switch family {
case syscall.AF_INET: case syscall.AF_INET:
if len(ip) == 0 { if len(ip) == 0 {
...@@ -164,12 +166,12 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, error) { ...@@ -164,12 +166,12 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, error) {
if ip = ip.To4(); ip == nil { if ip = ip.To4(); ip == nil {
return nil, InvalidAddrError("non-IPv4 address") return nil, InvalidAddrError("non-IPv4 address")
} }
s := new(syscall.SockaddrInet4) sa := new(syscall.SockaddrInet4)
for i := 0; i < IPv4len; i++ { for i := 0; i < IPv4len; i++ {
s.Addr[i] = ip[i] sa.Addr[i] = ip[i]
} }
s.Port = port sa.Port = port
return s, nil return sa, nil
case syscall.AF_INET6: case syscall.AF_INET6:
if len(ip) == 0 { if len(ip) == 0 {
ip = IPv6zero ip = IPv6zero
...@@ -183,12 +185,13 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, error) { ...@@ -183,12 +185,13 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, error) {
if ip = ip.To16(); ip == nil { if ip = ip.To16(); ip == nil {
return nil, InvalidAddrError("non-IPv6 address") return nil, InvalidAddrError("non-IPv6 address")
} }
s := new(syscall.SockaddrInet6) sa := new(syscall.SockaddrInet6)
for i := 0; i < IPv6len; i++ { for i := 0; i < IPv6len; i++ {
s.Addr[i] = ip[i] sa.Addr[i] = ip[i]
} }
s.Port = port sa.Port = port
return s, nil sa.ZoneId = uint32(zoneToInt(zone))
return sa, nil
} }
return nil, InvalidAddrError("unexpected socket family") return nil, InvalidAddrError("unexpected socket family")
} }
...@@ -21,26 +21,26 @@ var multicastListenerTests = []struct { ...@@ -21,26 +21,26 @@ var multicastListenerTests = []struct {
}{ }{
// cf. RFC 4727: Experimental Values in IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP Headers // 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{IP: IPv4(224, 0, 0, 254), Port: 12345}, FlagUp | FlagLoopback, false},
{"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, 0, false}, {"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, 0, false},
{"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true}, {"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, FlagUp | FlagLoopback, true},
{"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, 0, true}, {"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, 0, true},
{"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false}, {"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, FlagUp | FlagLoopback, false},
{"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, 0, false}, {"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, 0, false},
{"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, FlagUp | FlagLoopback, true}, {"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, 0, true}, {"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}, 0, true},
{"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, FlagUp | FlagLoopback, true}, {"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, 0, true}, {"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}, 0, true},
{"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, FlagUp | FlagLoopback, true}, {"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, 0, true}, {"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}, 0, true},
{"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, FlagUp | FlagLoopback, true}, {"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, 0, true}, {"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}, 0, true},
{"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, FlagUp | FlagLoopback, true}, {"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, 0, true}, {"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}, 0, true},
{"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true}, {"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, 0, true}, {"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, 0, true},
} }
// TestMulticastListener tests both single and double listen to a test // TestMulticastListener tests both single and double listen to a test
......
...@@ -12,6 +12,7 @@ import "time" ...@@ -12,6 +12,7 @@ import "time"
type TCPAddr struct { type TCPAddr struct {
IP IP IP IP
Port int Port int
Zone string // IPv6 scoped addressing zone
} }
// Network returns the address's network name, "tcp". // Network returns the address's network name, "tcp".
...@@ -38,5 +39,5 @@ func resolveTCPAddr(net, addr string, deadline time.Time) (*TCPAddr, error) { ...@@ -38,5 +39,5 @@ func resolveTCPAddr(net, addr string, deadline time.Time) (*TCPAddr, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &TCPAddr{ip, port}, nil return &TCPAddr{IP: ip, Port: port}, nil
} }
...@@ -23,9 +23,9 @@ import ( ...@@ -23,9 +23,9 @@ import (
func sockaddrToTCP(sa syscall.Sockaddr) Addr { func sockaddrToTCP(sa syscall.Sockaddr) Addr {
switch sa := sa.(type) { switch sa := sa.(type) {
case *syscall.SockaddrInet4: case *syscall.SockaddrInet4:
return &TCPAddr{sa.Addr[0:], sa.Port} return &TCPAddr{IP: sa.Addr[0:], Port: sa.Port}
case *syscall.SockaddrInet6: 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: default:
if sa != nil { if sa != nil {
// Diagnose when we will turn a non-nil sockaddr into a nil. // Diagnose when we will turn a non-nil sockaddr into a nil.
...@@ -53,7 +53,7 @@ func (a *TCPAddr) isWildcard() bool { ...@@ -53,7 +53,7 @@ func (a *TCPAddr) isWildcard() bool {
} }
func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, error) { 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 { func (a *TCPAddr) toAddr() sockaddr {
......
...@@ -17,6 +17,7 @@ var ErrWriteToConnected = errors.New("use of WriteTo with pre-connected UDP") ...@@ -17,6 +17,7 @@ var ErrWriteToConnected = errors.New("use of WriteTo with pre-connected UDP")
type UDPAddr struct { type UDPAddr struct {
IP IP IP IP
Port int Port int
Zone string // IPv6 scoped addressing zone
} }
// Network returns the address's network name, "udp". // Network returns the address's network name, "udp".
...@@ -43,5 +44,5 @@ func resolveUDPAddr(net, addr string, deadline time.Time) (*UDPAddr, error) { ...@@ -43,5 +44,5 @@ func resolveUDPAddr(net, addr string, deadline time.Time) (*UDPAddr, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &UDPAddr{ip, port}, nil return &UDPAddr{IP: ip, Port: port}, nil
} }
...@@ -19,8 +19,6 @@ type UDPConn struct { ...@@ -19,8 +19,6 @@ type UDPConn struct {
conn conn
} }
// UDP-specific methods.
// ReadFromUDP reads a UDP packet from c, copying the payload into b. // 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 // It returns the number of bytes copied into b and the return address
// that was on the packet. // that was on the packet.
...@@ -50,7 +48,7 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) { ...@@ -50,7 +48,7 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
h, buf := unmarshalUDPHeader(buf) h, buf := unmarshalUDPHeader(buf)
n = copy(b, 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. // ReadFrom implements the PacketConn ReadFrom method.
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
// +build darwin freebsd linux netbsd openbsd windows // +build darwin freebsd linux netbsd openbsd windows
// UDP sockets // UDP sockets for POSIX
package net package net
...@@ -16,9 +16,9 @@ import ( ...@@ -16,9 +16,9 @@ import (
func sockaddrToUDP(sa syscall.Sockaddr) Addr { func sockaddrToUDP(sa syscall.Sockaddr) Addr {
switch sa := sa.(type) { switch sa := sa.(type) {
case *syscall.SockaddrInet4: case *syscall.SockaddrInet4:
return &UDPAddr{sa.Addr[0:], sa.Port} return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
case *syscall.SockaddrInet6: 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 return nil
} }
...@@ -41,7 +41,7 @@ func (a *UDPAddr) isWildcard() bool { ...@@ -41,7 +41,7 @@ func (a *UDPAddr) isWildcard() bool {
} }
func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) { 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 { func (a *UDPAddr) toAddr() sockaddr {
...@@ -59,8 +59,6 @@ type UDPConn struct { ...@@ -59,8 +59,6 @@ type UDPConn struct {
func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} } func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
// UDP-specific methods.
// ReadFromUDP reads a UDP packet from c, copying the payload into b. // 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 // It returns the number of bytes copied into b and the return address
// that was on the packet. // that was on the packet.
...@@ -74,9 +72,9 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) { ...@@ -74,9 +72,9 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
n, sa, err := c.fd.ReadFrom(b) n, sa, err := c.fd.ReadFrom(b)
switch sa := sa.(type) { switch sa := sa.(type) {
case *syscall.SockaddrInet4: case *syscall.SockaddrInet4:
addr = &UDPAddr{sa.Addr[0:], sa.Port} addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
case *syscall.SockaddrInet6: 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 return
} }
...@@ -86,8 +84,8 @@ func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) { ...@@ -86,8 +84,8 @@ func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
if !c.ok() { if !c.ok() {
return 0, nil, syscall.EINVAL return 0, nil, syscall.EINVAL
} }
n, uaddr, err := c.ReadFromUDP(b) n, addr, err := c.ReadFromUDP(b)
return n, uaddr.toAddr(), err return n, addr.toAddr(), err
} }
// ReadMsgUDP reads a packet from c, copying the payload into b and // 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, ...@@ -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) n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
switch sa := sa.(type) { switch sa := sa.(type) {
case *syscall.SockaddrInet4: case *syscall.SockaddrInet4:
addr = &UDPAddr{sa.Addr[0:], sa.Port} addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
case *syscall.SockaddrInet6: 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 return
} }
...@@ -276,7 +274,7 @@ func listenIPv6MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error { ...@@ -276,7 +274,7 @@ func listenIPv6MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
func joinIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error { func joinIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
err := joinIPv4Group(c.fd, ifi, ip) err := joinIPv4Group(c.fd, ifi, ip)
if err != nil { if err != nil {
return &OpError{"joinipv4group", c.fd.net, &IPAddr{ip}, err} return &OpError{"joinipv4group", c.fd.net, &IPAddr{IP: ip}, err}
} }
return nil return nil
} }
...@@ -284,7 +282,7 @@ func joinIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error { ...@@ -284,7 +282,7 @@ func joinIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
func joinIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error { func joinIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
err := joinIPv6Group(c.fd, ifi, ip) err := joinIPv6Group(c.fd, ifi, ip)
if err != nil { if err != nil {
return &OpError{"joinipv6group", c.fd.net, &IPAddr{ip}, err} return &OpError{"joinipv6group", c.fd.net, &IPAddr{IP: ip}, err}
} }
return nil return nil
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment