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
15 // If the ifindex is zero, interfaceTable returns mappings of all
16 // network interfaces. Otherwise it returns a mapping of a specific
18 func interfaceTable(ifindex int) ([]Interface, error) {
19 tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
21 return nil, os.NewSyscallError("netlink rib", err)
24 msgs, err := syscall.ParseNetlinkMessage(tab)
26 return nil, os.NewSyscallError("netlink message", err)
30 for _, m := range msgs {
31 switch m.Header.Type {
32 case syscall.NLMSG_DONE:
34 case syscall.RTM_NEWLINK:
35 ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0]))
36 if ifindex == 0 || ifindex == int(ifim.Index) {
37 attrs, err := syscall.ParseNetlinkRouteAttr(&m)
39 return nil, os.NewSyscallError("netlink routeattr", err)
41 ifi := newLink(ifim, attrs)
42 ift = append(ift, ifi)
50 func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) Interface {
51 ifi := Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
52 for _, a := range attrs {
54 case syscall.IFLA_ADDRESS:
56 for _, b := range a.Value {
62 ifi.HardwareAddr = a.Value[:]
64 case syscall.IFLA_IFNAME:
65 ifi.Name = string(a.Value[:len(a.Value)-1])
66 case syscall.IFLA_MTU:
67 ifi.MTU = int(*(*uint32)(unsafe.Pointer(&a.Value[:4][0])))
73 func linkFlags(rawFlags uint32) Flags {
75 if rawFlags&syscall.IFF_UP != 0 {
78 if rawFlags&syscall.IFF_BROADCAST != 0 {
81 if rawFlags&syscall.IFF_LOOPBACK != 0 {
84 if rawFlags&syscall.IFF_POINTOPOINT != 0 {
87 if rawFlags&syscall.IFF_MULTICAST != 0 {
93 // If the ifindex is zero, interfaceAddrTable returns addresses
94 // for all network interfaces. Otherwise it returns addresses
95 // for a specific interface.
96 func interfaceAddrTable(ifindex int) ([]Addr, error) {
97 tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
99 return nil, os.NewSyscallError("netlink rib", err)
102 msgs, err := syscall.ParseNetlinkMessage(tab)
104 return nil, os.NewSyscallError("netlink message", err)
107 ifat, err := addrTable(msgs, ifindex)
114 func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) {
116 for _, m := range msgs {
117 switch m.Header.Type {
118 case syscall.NLMSG_DONE:
120 case syscall.RTM_NEWADDR:
121 ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
122 if ifindex == 0 || ifindex == int(ifam.Index) {
123 attrs, err := syscall.ParseNetlinkRouteAttr(&m)
125 return nil, os.NewSyscallError("netlink routeattr", err)
127 ifat = append(ifat, newAddr(attrs, int(ifam.Family), int(ifam.Prefixlen)))
135 func newAddr(attrs []syscall.NetlinkRouteAttr, family, pfxlen int) Addr {
137 for _, a := range attrs {
139 case syscall.IFA_ADDRESS:
141 case syscall.AF_INET:
142 ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])
143 ifa.Mask = CIDRMask(pfxlen, 8*IPv4len)
144 case syscall.AF_INET6:
145 ifa.IP = make(IP, IPv6len)
146 copy(ifa.IP, a.Value[:])
147 ifa.Mask = CIDRMask(pfxlen, 8*IPv6len)
154 // If the ifindex is zero, interfaceMulticastAddrTable returns
155 // addresses for all network interfaces. Otherwise it returns
156 // addresses for a specific interface.
157 func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
163 ifi, err = InterfaceByIndex(ifindex)
168 ifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi)
169 ifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi)
170 return append(ifmat4, ifmat6...), nil
173 func parseProcNetIGMP(path string, ifi *Interface) []Addr {
174 fd, err := open(path)
184 fd.readLine() // skip first line
185 b := make([]byte, IPv4len)
186 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
187 f := splitAtBytes(l, " :\r\t\n")
192 case l[0] != ' ' && l[0] != '\t': // new interface line
195 if ifi == nil || name == ifi.Name {
196 // The Linux kernel puts the IP
197 // address in /proc/net/igmp in native
199 for i := 0; i+1 < len(f[0]); i += 2 {
200 b[i/2], _ = xtoi2(f[0][i:i+2], 0)
202 i := *(*uint32)(unsafe.Pointer(&b[:4][0]))
203 ifma := IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))}
204 ifmat = append(ifmat, ifma.toAddr())
211 func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
212 fd, err := open(path)
219 b := make([]byte, IPv6len)
220 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
221 f := splitAtBytes(l, " \r\t\n")
225 if ifi == nil || f[1] == ifi.Name {
226 for i := 0; i+1 < len(f[2]); i += 2 {
227 b[i/2], _ = xtoi2(f[2][i:i+2], 0)
229 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]}}
230 ifmat = append(ifmat, ifma.toAddr())