Commit 83610567 authored by Mikio Hara's avatar Mikio Hara

net, syscall: interface address and mask

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