]> Cypherpunks repositories - gostls13.git/commitdiff
net, syscall: interface address and mask
authorMikio Hara <mikioh.mikioh@gmail.com>
Wed, 21 Dec 2011 12:39:00 +0000 (21:39 +0900)
committerMikio Hara <mikioh.mikioh@gmail.com>
Wed, 21 Dec 2011 12:39:00 +0000 (21:39 +0900)
This CL makes both InterfaceAddrs and Addrs method on Interface
return IPNet struct for representing interface address and mask
like below:

interface "lo0": flags "up|loopback|multicast", ifindex 1, mtu 16384
        interface address "fe80::1/64"
        interface address "127.0.0.1/8"
        interface address "::1/128"
        joined group address "ff02::fb"
        joined group address "224.0.0.251"
        joined group address "ff02::2:65d0:d71e"
        joined group address "224.0.0.1"
  joined group address "ff01::1"
        joined group address "ff02::1"
        joined group address "ff02::1:ff00:1"

Fixes #2571.

R=rsc
CC=golang-dev
https://golang.org/cl/5489062

src/pkg/net/interface_bsd.go
src/pkg/net/interface_linux.go
src/pkg/net/interface_test.go
src/pkg/net/ip.go
src/pkg/syscall/route_bsd.go

index cdfb3dbd1e2aa1f688c1ea2658da8ad69138c2b4..907f80a80f3118522bf0cc16a0dd1113f31919c1 100644 (file)
@@ -18,21 +18,16 @@ import (
 // network interfaces.  Otheriwse it returns a mapping of a specific
 // interface.
 func interfaceTable(ifindex int) ([]Interface, error) {
-       var (
-               tab  []byte
-               e    error
-               msgs []syscall.RoutingMessage
-               ift  []Interface
-       )
-
-       tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
-       if e != nil {
-               return nil, os.NewSyscallError("route rib", e)
+       var ift []Interface
+
+       tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
+       if err != nil {
+               return nil, os.NewSyscallError("route rib", err)
        }
 
-       msgs, e = syscall.ParseRoutingMessage(tab)
-       if e != nil {
-               return nil, os.NewSyscallError("route message", e)
+       msgs, err := syscall.ParseRoutingMessage(tab)
+       if err != nil {
+               return nil, os.NewSyscallError("route message", err)
        }
 
        for _, m := range msgs {
@@ -54,9 +49,9 @@ func interfaceTable(ifindex int) ([]Interface, error) {
 func newLink(m *syscall.InterfaceMessage) ([]Interface, error) {
        var ift []Interface
 
-       sas, e := syscall.ParseRoutingSockaddr(m)
-       if e != nil {
-               return nil, os.NewSyscallError("route sockaddr", e)
+       sas, err := syscall.ParseRoutingSockaddr(m)
+       if err != nil {
+               return nil, os.NewSyscallError("route sockaddr", err)
        }
 
        for _, s := range sas {
@@ -108,21 +103,16 @@ func linkFlags(rawFlags int32) Flags {
 // for all network interfaces.  Otherwise it returns addresses
 // for a specific interface.
 func interfaceAddrTable(ifindex int) ([]Addr, error) {
-       var (
-               tab  []byte
-               e    error
-               msgs []syscall.RoutingMessage
-               ifat []Addr
-       )
-
-       tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
-       if e != nil {
-               return nil, os.NewSyscallError("route rib", e)
+       var ifat []Addr
+
+       tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
+       if err != nil {
+               return nil, os.NewSyscallError("route rib", err)
        }
 
-       msgs, e = syscall.ParseRoutingMessage(tab)
-       if e != nil {
-               return nil, os.NewSyscallError("route message", e)
+       msgs, err := syscall.ParseRoutingMessage(tab)
+       if err != nil {
+               return nil, os.NewSyscallError("route message", err)
        }
 
        for _, m := range msgs {
@@ -133,7 +123,7 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
                                if err != nil {
                                        return nil, err
                                }
-                               ifat = append(ifat, ifa...)
+                               ifat = append(ifat, ifa)
                        }
                }
        }
@@ -141,32 +131,41 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
        return ifat, nil
 }
 
-func newAddr(m *syscall.InterfaceAddrMessage) ([]Addr, error) {
-       var ifat []Addr
+func newAddr(m *syscall.InterfaceAddrMessage) (Addr, error) {
+       ifa := &IPNet{}
 
-       sas, e := syscall.ParseRoutingSockaddr(m)
-       if e != nil {
-               return nil, os.NewSyscallError("route sockaddr", e)
+       sas, err := syscall.ParseRoutingSockaddr(m)
+       if err != nil {
+               return nil, os.NewSyscallError("route sockaddr", err)
        }
 
-       for _, s := range sas {
+       for i, s := range sas {
                switch v := s.(type) {
                case *syscall.SockaddrInet4:
-                       ifa := &IPAddr{IP: IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])}
-                       ifat = append(ifat, ifa.toAddr())
+                       switch i {
+                       case 0:
+                               ifa.Mask = IPv4Mask(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])
+                       case 1:
+                               ifa.IP = IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])
+                       }
                case *syscall.SockaddrInet6:
-                       ifa := &IPAddr{IP: make(IP, IPv6len)}
-                       copy(ifa.IP, v.Addr[:])
-                       // NOTE: KAME based IPv6 protcol stack usually embeds
-                       // the interface index in the interface-local or link-
-                       // local address as the kernel-internal form.
-                       if ifa.IP.IsLinkLocalUnicast() {
-                               // remove embedded scope zone ID
-                               ifa.IP[2], ifa.IP[3] = 0, 0
+                       switch i {
+                       case 0:
+                               ifa.Mask = make(IPMask, IPv6len)
+                               copy(ifa.Mask, v.Addr[:])
+                       case 1:
+                               ifa.IP = make(IP, IPv6len)
+                               copy(ifa.IP, v.Addr[:])
+                               // NOTE: KAME based IPv6 protcol stack usually embeds
+                               // the interface index in the interface-local or link-
+                               // local address as the kernel-internal form.
+                               if ifa.IP.IsLinkLocalUnicast() {
+                                       // remove embedded scope zone ID
+                                       ifa.IP[2], ifa.IP[3] = 0, 0
+                               }
                        }
-                       ifat = append(ifat, ifa.toAddr())
                }
        }
 
-       return ifat, nil
+       return ifa, nil
 }
index 96db7186af552d6d53cbb8af04a6aa1980383239..c0887c57efeeb2b2e3e123a8eace09132844caf4 100644 (file)
@@ -17,21 +17,16 @@ import (
 // network interfaces.  Otheriwse it returns a mapping of a specific
 // interface.
 func interfaceTable(ifindex int) ([]Interface, error) {
-       var (
-               ift  []Interface
-               tab  []byte
-               msgs []syscall.NetlinkMessage
-               e    error
-       )
+       var ift []Interface
 
-       tab, e = syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
-       if e != nil {
-               return nil, os.NewSyscallError("netlink rib", e)
+       tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
+       if err != nil {
+               return nil, os.NewSyscallError("netlink rib", err)
        }
 
-       msgs, e = syscall.ParseNetlinkMessage(tab)
-       if e != nil {
-               return nil, os.NewSyscallError("netlink message", e)
+       msgs, err := syscall.ParseNetlinkMessage(tab)
+       if err != nil {
+               return nil, os.NewSyscallError("netlink message", err)
        }
 
        for _, m := range msgs {
@@ -41,11 +36,11 @@ func interfaceTable(ifindex int) ([]Interface, error) {
                case syscall.RTM_NEWLINK:
                        ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0]))
                        if ifindex == 0 || ifindex == int(ifim.Index) {
-                               attrs, e := syscall.ParseNetlinkRouteAttr(&m)
-                               if e != nil {
-                                       return nil, os.NewSyscallError("netlink routeattr", e)
+                               attrs, err := syscall.ParseNetlinkRouteAttr(&m)
+                               if err != nil {
+                                       return nil, os.NewSyscallError("netlink routeattr", err)
                                }
-                               ifi := newLink(attrs, ifim)
+                               ifi := newLink(ifim, attrs)
                                ift = append(ift, ifi)
                        }
                }
@@ -55,7 +50,7 @@ done:
        return ift, nil
 }
 
-func newLink(attrs []syscall.NetlinkRouteAttr, ifim *syscall.IfInfomsg) Interface {
+func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) Interface {
        ifi := Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
        for _, a := range attrs {
                switch a.Attr.Type {
@@ -102,19 +97,19 @@ func linkFlags(rawFlags uint32) Flags {
 // for all network interfaces.  Otherwise it returns addresses
 // for a specific interface.
 func interfaceAddrTable(ifindex int) ([]Addr, error) {
-       tab, e := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
-       if e != nil {
-               return nil, os.NewSyscallError("netlink rib", e)
+       tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
+       if err != nil {
+               return nil, os.NewSyscallError("netlink rib", err)
        }
 
-       msgs, e := syscall.ParseNetlinkMessage(tab)
-       if e != nil {
-               return nil, os.NewSyscallError("netlink message", e)
+       msgs, err := syscall.ParseNetlinkMessage(tab)
+       if err != nil {
+               return nil, os.NewSyscallError("netlink message", err)
        }
 
-       ifat, e := addrTable(msgs, ifindex)
-       if e != nil {
-               return nil, e
+       ifat, err := addrTable(msgs, ifindex)
+       if err != nil {
+               return nil, err
        }
 
        return ifat, nil
@@ -130,11 +125,11 @@ func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) {
                case syscall.RTM_NEWADDR:
                        ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
                        if ifindex == 0 || ifindex == int(ifam.Index) {
-                               attrs, e := syscall.ParseNetlinkRouteAttr(&m)
-                               if e != nil {
-                                       return nil, os.NewSyscallError("netlink routeattr", e)
+                               attrs, err := syscall.ParseNetlinkRouteAttr(&m)
+                               if err != nil {
+                                       return nil, os.NewSyscallError("netlink routeattr", err)
                                }
-                               ifat = append(ifat, newAddr(attrs, int(ifam.Family))...)
+                               ifat = append(ifat, newAddr(attrs, int(ifam.Family), int(ifam.Prefixlen)))
                        }
                }
        }
@@ -143,25 +138,23 @@ done:
        return ifat, nil
 }
 
-func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr {
-       var ifat []Addr
-
+func newAddr(attrs []syscall.NetlinkRouteAttr, family, pfxlen int) Addr {
+       ifa := &IPNet{}
        for _, a := range attrs {
                switch a.Attr.Type {
                case syscall.IFA_ADDRESS:
                        switch family {
                        case syscall.AF_INET:
-                               ifa := &IPAddr{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])}
-                               ifat = append(ifat, ifa.toAddr())
+                               ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])
+                               ifa.Mask = CIDRMask(pfxlen, 8*IPv4len)
                        case syscall.AF_INET6:
-                               ifa := &IPAddr{IP: make(IP, IPv6len)}
+                               ifa.IP = make(IP, IPv6len)
                                copy(ifa.IP, a.Value[:])
-                               ifat = append(ifat, ifa.toAddr())
+                               ifa.Mask = CIDRMask(pfxlen, 8*IPv6len)
                        }
                }
        }
-
-       return ifat
+       return ifa
 }
 
 // If the ifindex is zero, interfaceMulticastAddrTable returns
@@ -169,8 +162,8 @@ func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr {
 // addresses for a specific interface.
 func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
        var (
-               ifi *Interface
                err error
+               ifi *Interface
        )
 
        if ifindex > 0 {
index cc614910fac87437c4af166f6c22bd186fbd5440..4ce01dc906189598ac0be0052760d3f707c568bb 100644 (file)
@@ -24,7 +24,7 @@ func sameInterface(i, j *Interface) bool {
 func TestInterfaces(t *testing.T) {
        ift, err := Interfaces()
        if err != nil {
-               t.Fatalf("Interfaces() failed: %v", err)
+               t.Fatalf("Interfaces failed: %v", err)
        }
        t.Logf("table: len/cap = %v/%v\n", len(ift), cap(ift))
 
@@ -43,34 +43,57 @@ func TestInterfaces(t *testing.T) {
                if !sameInterface(ifxn, &ifi) {
                        t.Fatalf("InterfaceByName(%#q) = %v, want %v", ifi.Name, *ifxn, ifi)
                }
-               ifat, err := ifi.Addrs()
-               if err != nil {
-                       t.Fatalf("Interface.Addrs() failed: %v", err)
-               }
-               ifmat, err := ifi.MulticastAddrs()
-               if err != nil {
-                       t.Fatalf("Interface.MulticastAddrs() failed: %v", err)
-               }
                t.Logf("%q: flags %q, ifindex %v, mtu %v\n", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
-               for _, ifa := range ifat {
-                       t.Logf("\tinterface address %q\n", ifa.String())
-               }
-               for _, ifma := range ifmat {
-                       t.Logf("\tjoined group address %q\n", ifma.String())
-               }
                t.Logf("\thardware address %q", ifi.HardwareAddr.String())
+               testInterfaceAddrs(t, &ifi)
+               testInterfaceMulticastAddrs(t, &ifi)
        }
 }
 
 func TestInterfaceAddrs(t *testing.T) {
        ifat, err := InterfaceAddrs()
        if err != nil {
-               t.Fatalf("InterfaceAddrs() failed: %v", err)
+               t.Fatalf("InterfaceAddrs failed: %v", err)
        }
        t.Logf("table: len/cap = %v/%v\n", len(ifat), cap(ifat))
+       testAddrs(t, ifat)
+}
+
+func testInterfaceAddrs(t *testing.T, ifi *Interface) {
+       ifat, err := ifi.Addrs()
+       if err != nil {
+               t.Fatalf("Interface.Addrs failed: %v", err)
+       }
+       testAddrs(t, ifat)
+}
+
+func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) {
+       ifmat, err := ifi.MulticastAddrs()
+       if err != nil {
+               t.Fatalf("Interface.MulticastAddrs failed: %v", err)
+       }
+       testMulticastAddrs(t, ifmat)
+}
 
+func testAddrs(t *testing.T, ifat []Addr) {
        for _, ifa := range ifat {
-               t.Logf("interface address %q\n", ifa.String())
+               switch ifa.(type) {
+               case *IPAddr, *IPNet:
+                       t.Logf("\tinterface address %q\n", ifa.String())
+               default:
+                       t.Errorf("\tunexpected type: %T", ifa)
+               }
+       }
+}
+
+func testMulticastAddrs(t *testing.T, ifmat []Addr) {
+       for _, ifma := range ifmat {
+               switch ifma.(type) {
+               case *IPAddr:
+                       t.Logf("\tjoined group address %q\n", ifma.String())
+               default:
+                       t.Errorf("\tunexpected type: %T", ifma)
+               }
        }
 }
 
index 4a388827875a6e5d0728668719ce3b52201f903f..979d7acd53d949e7184c6bcf1cbe23f363bcd7b9 100644 (file)
@@ -450,6 +450,9 @@ func (n *IPNet) String() string {
        return nn.String() + "/" + itod(uint(l))
 }
 
+// Network returns the address's network name, "ip+net".
+func (n *IPNet) Network() string { return "ip+net" }
+
 // Parse IPv4 address (d.d.d.d).
 func parseIPv4(s string) IP {
        var p [IPv4len]byte
index 85c26c5703e6b84d7db1578af975ecf643eb98dc..e17d976b1548723cd1b19cc42c9662c7ac988173 100644 (file)
@@ -85,8 +85,8 @@ func (m *RouteMessage) sockaddr() []Sockaddr {
                rsa := (*RawSockaddr)(unsafe.Pointer(&buf[0]))
                switch i {
                case RTAX_DST, RTAX_GATEWAY:
-                       sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
-                       if e != nil {
+                       sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+                       if err != nil {
                                return nil
                        }
                        if i == RTAX_DST {
@@ -128,8 +128,8 @@ func (m *InterfaceMessage) sockaddr() (sas []Sockaddr) {
        if m.Header.Addrs&RTA_IFP == 0 {
                return nil
        }
-       sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0])))
-       if e != nil {
+       sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0])))
+       if err != nil {
                return nil
        }
        return append(sas, sa)
@@ -157,12 +157,21 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
                rsa := (*RawSockaddr)(unsafe.Pointer(&buf[0]))
                switch i {
                case RTAX_IFA:
-                       sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
-                       if e != nil {
+                       sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+                       if err != nil {
                                return nil
                        }
                        sas = append(sas, sa)
-               case RTAX_NETMASK, RTAX_BRD:
+               case RTAX_NETMASK:
+                       if rsa.Family == AF_UNSPEC {
+                               rsa.Family = AF_INET // an old fasion, AF_UNSPEC means AF_INET
+                       }
+                       sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+                       if err != nil {
+                               return nil
+                       }
+                       sas = append(sas, sa)
+               case RTAX_BRD:
                        // nothing to do
                }
                buf = buf[rsaAlignOf(int(rsa.Len)):]