1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Network interface identification for Linux
16 // If the ifindex is zero, interfaceTable returns mappings of all
17 // network interfaces. Otheriwse it returns a mapping of a specific
19 func interfaceTable(ifindex int) ([]Interface, error) {
22 tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
24 return nil, os.NewSyscallError("netlink rib", err)
27 msgs, err := syscall.ParseNetlinkMessage(tab)
29 return nil, os.NewSyscallError("netlink message", err)
32 for _, m := range msgs {
33 switch m.Header.Type {
34 case syscall.NLMSG_DONE:
36 case syscall.RTM_NEWLINK:
37 ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0]))
38 if ifindex == 0 || ifindex == int(ifim.Index) {
39 attrs, err := syscall.ParseNetlinkRouteAttr(&m)
41 return nil, os.NewSyscallError("netlink routeattr", err)
43 ifi := newLink(ifim, attrs)
44 ift = append(ift, ifi)
53 func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) Interface {
54 ifi := Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
55 for _, a := range attrs {
57 case syscall.IFLA_ADDRESS:
59 for _, b := range a.Value {
65 ifi.HardwareAddr = a.Value[:]
67 case syscall.IFLA_IFNAME:
68 ifi.Name = string(a.Value[:len(a.Value)-1])
69 case syscall.IFLA_MTU:
70 ifi.MTU = int(uint32(a.Value[3])<<24 | uint32(a.Value[2])<<16 | uint32(a.Value[1])<<8 | uint32(a.Value[0]))
76 func linkFlags(rawFlags uint32) Flags {
78 if rawFlags&syscall.IFF_UP != 0 {
81 if rawFlags&syscall.IFF_BROADCAST != 0 {
84 if rawFlags&syscall.IFF_LOOPBACK != 0 {
87 if rawFlags&syscall.IFF_POINTOPOINT != 0 {
90 if rawFlags&syscall.IFF_MULTICAST != 0 {
96 // If the ifindex is zero, interfaceAddrTable returns addresses
97 // for all network interfaces. Otherwise it returns addresses
98 // for a specific interface.
99 func interfaceAddrTable(ifindex int) ([]Addr, error) {
100 tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
102 return nil, os.NewSyscallError("netlink rib", err)
105 msgs, err := syscall.ParseNetlinkMessage(tab)
107 return nil, os.NewSyscallError("netlink message", err)
110 ifat, err := addrTable(msgs, ifindex)
118 func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) {
121 for _, m := range msgs {
122 switch m.Header.Type {
123 case syscall.NLMSG_DONE:
125 case syscall.RTM_NEWADDR:
126 ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
127 if ifindex == 0 || ifindex == int(ifam.Index) {
128 attrs, err := syscall.ParseNetlinkRouteAttr(&m)
130 return nil, os.NewSyscallError("netlink routeattr", err)
132 ifat = append(ifat, newAddr(attrs, int(ifam.Family), int(ifam.Prefixlen)))
141 func newAddr(attrs []syscall.NetlinkRouteAttr, family, pfxlen int) Addr {
143 for _, a := range attrs {
145 case syscall.IFA_ADDRESS:
147 case syscall.AF_INET:
148 ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])
149 ifa.Mask = CIDRMask(pfxlen, 8*IPv4len)
150 case syscall.AF_INET6:
151 ifa.IP = make(IP, IPv6len)
152 copy(ifa.IP, a.Value[:])
153 ifa.Mask = CIDRMask(pfxlen, 8*IPv6len)
160 // If the ifindex is zero, interfaceMulticastAddrTable returns
161 // addresses for all network interfaces. Otherwise it returns
162 // addresses for a specific interface.
163 func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
170 ifi, err = InterfaceByIndex(ifindex)
176 ifmat4 := parseProcNetIGMP(ifi)
177 ifmat6 := parseProcNetIGMP6(ifi)
179 return append(ifmat4, ifmat6...), nil
182 func parseProcNetIGMP(ifi *Interface) []Addr {
188 fd, err := open("/proc/net/igmp")
194 fd.readLine() // skip first line
195 b := make([]byte, IPv4len)
196 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
200 if ifi == nil || name == ifi.Name {
201 fmt.Sscanf(f[0], "%08x", &b)
202 ifma := IPAddr{IP: IPv4(b[3], b[2], b[1], b[0])}
203 ifmat = append(ifmat, ifma.toAddr())
213 func parseProcNetIGMP6(ifi *Interface) []Addr {
216 fd, err := open("/proc/net/igmp6")
222 b := make([]byte, IPv6len)
223 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
225 if ifi == nil || f[1] == ifi.Name {
226 fmt.Sscanf(f[2], "%32x", &b)
227 ifma := IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
228 ifmat = append(ifmat, ifma.toAddr())