From: Fazlul Shahriar Date: Wed, 16 Oct 2019 02:58:40 +0000 (-0400) Subject: net: fix multicast and IPv6 related issues on Plan 9 X-Git-Tag: go1.14beta1~730 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=e94475eab199463f81f4a55e0f841d15504a0e56;p=gostls13.git net: fix multicast and IPv6 related issues on Plan 9 Fix issues that make these tests pass: - TestDialerLocalAddr: return error if local address is not IPv4 for "tcp4" network. - TestInterfaceAddrs, TestInterfaceUnicastAddrs: don't assume each interface has only one address. It may have more than one or none. - TestConcurrentPreferGoResolversDial: should be skipped on Plan 9. - TestListenMulticastUDP: remove IP from `announce` command and don't mix IPv4 address with IPv6 address in `addmulti` command. Fixes #34931 Change-Id: Ie0fdfe19ea282e5d6d6c938bf3c9139f8f5b0308 Reviewed-on: https://go-review.googlesource.com/c/go/+/201397 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- diff --git a/src/net/interface_plan9.go b/src/net/interface_plan9.go index 8fe9138406..1295017a1b 100644 --- a/src/net/interface_plan9.go +++ b/src/net/interface_plan9.go @@ -143,8 +143,8 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) { ifcs = []Interface{*ifi} } - addrs := make([]Addr, len(ifcs)) - for i, ifc := range ifcs { + var addrs []Addr + for _, ifc := range ifcs { status := ifc.Name + "/status" statusf, err := open(status) if err != nil { @@ -157,39 +157,36 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) { if _, ok := statusf.readLine(); !ok { return nil, errors.New("cannot read header line for interface: " + status) } - line, ok := statusf.readLine() - if !ok { - return nil, errors.New("cannot read IP address for interface: " + status) - } - // This assumes only a single address for the interface. - fields := getFields(line) - if len(fields) < 1 { - return nil, errors.New("cannot parse IP address for interface: " + status) - } - addr := fields[0] - ip := ParseIP(addr) - if ip == nil { - return nil, errors.New("cannot parse IP address for interface: " + status) - } + for line, ok := statusf.readLine(); ok; line, ok = statusf.readLine() { + fields := getFields(line) + if len(fields) < 1 { + return nil, errors.New("cannot parse IP address for interface: " + status) + } + addr := fields[0] + ip := ParseIP(addr) + if ip == nil { + return nil, errors.New("cannot parse IP address for interface: " + status) + } - // The mask is represented as CIDR relative to the IPv6 address. - // Plan 9 internal representation is always IPv6. - maskfld := fields[1] - maskfld = maskfld[1:] - pfxlen, _, ok := dtoi(maskfld) - if !ok { - return nil, errors.New("cannot parse network mask for interface: " + status) - } - var mask IPMask - if ip.To4() != nil { // IPv4 or IPv6 IPv4-mapped address - mask = CIDRMask(pfxlen-8*len(v4InV6Prefix), 8*IPv4len) - } - if ip.To16() != nil && ip.To4() == nil { // IPv6 address - mask = CIDRMask(pfxlen, 8*IPv6len) - } + // The mask is represented as CIDR relative to the IPv6 address. + // Plan 9 internal representation is always IPv6. + maskfld := fields[1] + maskfld = maskfld[1:] + pfxlen, _, ok := dtoi(maskfld) + if !ok { + return nil, errors.New("cannot parse network mask for interface: " + status) + } + var mask IPMask + if ip.To4() != nil { // IPv4 or IPv6 IPv4-mapped address + mask = CIDRMask(pfxlen-8*len(v4InV6Prefix), 8*IPv4len) + } + if ip.To16() != nil && ip.To4() == nil { // IPv6 address + mask = CIDRMask(pfxlen, 8*IPv6len) + } - addrs[i] = &IPNet{IP: ip, Mask: mask} + addrs = append(addrs, &IPNet{IP: ip, Mask: mask}) + } } return addrs, nil diff --git a/src/net/ipsock_plan9.go b/src/net/ipsock_plan9.go index d226585e08..93f0f4eec3 100644 --- a/src/net/ipsock_plan9.go +++ b/src/net/ipsock_plan9.go @@ -227,7 +227,7 @@ func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err er _, err = f.WriteString("announce " + dest) if err != nil { f.Close() - return nil, err + return nil, &OpError{Op: "announce", Net: net, Source: laddr, Addr: nil, Err: err} } laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local") if err != nil { diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go index dc8a0839b9..8a41510daf 100644 --- a/src/net/lookup_test.go +++ b/src/net/lookup_test.go @@ -972,10 +972,11 @@ func (lcr *lookupCustomResolver) dial() func(ctx context.Context, network, addre // TestConcurrentPreferGoResolversDial tests that multiple resolvers with the // PreferGo option used concurrently are all dialed properly. func TestConcurrentPreferGoResolversDial(t *testing.T) { - // The windows implementation of the resolver does not use the Dial - // function. - if runtime.GOOS == "windows" { - t.Skip("skip on windows") + // The windows and plan9 implementation of the resolver does not use + // the Dial function. + switch runtime.GOOS { + case "windows", "plan9": + t.Skipf("skip on %v", runtime.GOOS) } testenv.MustHaveExternalNetwork(t) diff --git a/src/net/tcpsock_plan9.go b/src/net/tcpsock_plan9.go index e2e835957c..768d03b06c 100644 --- a/src/net/tcpsock_plan9.go +++ b/src/net/tcpsock_plan9.go @@ -23,7 +23,12 @@ func (sd *sysDialer) dialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPCo func (sd *sysDialer) doDialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) { switch sd.network { - case "tcp", "tcp4", "tcp6": + case "tcp4": + // Plan 9 doesn't complain about [::]:0->127.0.0.1, so it's up to us. + if laddr != nil && len(laddr.IP) != 0 && laddr.IP.To4() == nil { + return nil, &AddrError{Err: "non-IPv4 local address", Addr: laddr.String()} + } + case "tcp", "tcp6": default: return nil, UnknownNetworkError(sd.network) } diff --git a/src/net/udpsock_plan9.go b/src/net/udpsock_plan9.go index 563d943507..79986ce4da 100644 --- a/src/net/udpsock_plan9.go +++ b/src/net/udpsock_plan9.go @@ -109,7 +109,9 @@ func (sl *sysListener) listenUDP(ctx context.Context, laddr *UDPAddr) (*UDPConn, } func (sl *sysListener) listenMulticastUDP(ctx context.Context, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) { - l, err := listenPlan9(ctx, sl.network, gaddr) + // Plan 9 does not like announce command with a multicast address, + // so do not specify an IP address when listening. + l, err := listenPlan9(ctx, sl.network, &UDPAddr{IP: nil, Port: gaddr.Port, Zone: gaddr.Zone}) if err != nil { return nil, err } @@ -129,11 +131,13 @@ func (sl *sysListener) listenMulticastUDP(ctx context.Context, ifi *Interface, g return nil, err } } + + have4 := gaddr.IP.To4() != nil for _, addr := range addrs { - if ipnet, ok := addr.(*IPNet); ok { + if ipnet, ok := addr.(*IPNet); ok && (ipnet.IP.To4() != nil) == have4 { _, err = l.ctl.WriteString("addmulti " + ipnet.IP.String() + " " + gaddr.IP.String()) if err != nil { - return nil, err + return nil, &OpError{Op: "addmulti", Net: "", Source: nil, Addr: ipnet, Err: err} } } } diff --git a/src/net/udpsock_plan9_test.go b/src/net/udpsock_plan9_test.go index 09f5a5dc65..3febfcc074 100644 --- a/src/net/udpsock_plan9_test.go +++ b/src/net/udpsock_plan9_test.go @@ -36,7 +36,7 @@ func TestListenMulticastUDP(t *testing.T) { c1, err := ListenMulticastUDP("udp4", mifc, &UDPAddr{IP: ParseIP("224.0.0.254")}) if err != nil { - t.Fatalf("multicast not working on %s", runtime.GOOS) + t.Fatalf("multicast not working on %s: %v", runtime.GOOS, err) } c1addr := c1.LocalAddr().(*UDPAddr) if err != nil {