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 if syscall.BigEndian {
68 ifi.MTU = int(uint32(a.Value[0])<<24 | uint32(a.Value[1])<<16 | uint32(a.Value[2])<<8 | uint32(a.Value[3]))
70 ifi.MTU = int(uint32(a.Value[3])<<24 | uint32(a.Value[2])<<16 | uint32(a.Value[1])<<8 | uint32(a.Value[0]))
77 func linkFlags(rawFlags uint32) Flags {
79 if rawFlags&syscall.IFF_UP != 0 {
82 if rawFlags&syscall.IFF_BROADCAST != 0 {
85 if rawFlags&syscall.IFF_LOOPBACK != 0 {
88 if rawFlags&syscall.IFF_POINTOPOINT != 0 {
91 if rawFlags&syscall.IFF_MULTICAST != 0 {
97 // If the ifindex is zero, interfaceAddrTable returns addresses
98 // for all network interfaces. Otherwise it returns addresses
99 // for a specific interface.
100 func interfaceAddrTable(ifindex int) ([]Addr, error) {
101 tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
103 return nil, os.NewSyscallError("netlink rib", err)
106 msgs, err := syscall.ParseNetlinkMessage(tab)
108 return nil, os.NewSyscallError("netlink message", err)
111 ifat, err := addrTable(msgs, ifindex)
118 func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) {
120 for _, m := range msgs {
121 switch m.Header.Type {
122 case syscall.NLMSG_DONE:
124 case syscall.RTM_NEWADDR:
125 ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
126 if ifindex == 0 || ifindex == int(ifam.Index) {
127 attrs, err := syscall.ParseNetlinkRouteAttr(&m)
129 return nil, os.NewSyscallError("netlink routeattr", err)
131 ifat = append(ifat, newAddr(attrs, int(ifam.Family), int(ifam.Prefixlen)))
139 func newAddr(attrs []syscall.NetlinkRouteAttr, family, pfxlen int) Addr {
141 for _, a := range attrs {
143 case syscall.IFA_ADDRESS:
145 case syscall.AF_INET:
146 ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])
147 ifa.Mask = CIDRMask(pfxlen, 8*IPv4len)
148 case syscall.AF_INET6:
149 ifa.IP = make(IP, IPv6len)
150 copy(ifa.IP, a.Value[:])
151 ifa.Mask = CIDRMask(pfxlen, 8*IPv6len)
158 // If the ifindex is zero, interfaceMulticastAddrTable returns
159 // addresses for all network interfaces. Otherwise it returns
160 // addresses for a specific interface.
161 func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
167 ifi, err = InterfaceByIndex(ifindex)
172 ifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi)
173 ifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi)
174 return append(ifmat4, ifmat6...), nil
177 func parseProcNetIGMP(path string, ifi *Interface) []Addr {
178 fd, err := open(path)
188 fd.readLine() // skip first line
189 b := make([]byte, IPv4len)
190 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
191 f := splitAtBytes(l, " :\r\t\n")
196 case l[0] != ' ' && l[0] != '\t': // new interface line
199 if ifi == nil || name == ifi.Name {
200 for i := 0; i+1 < len(f[0]); i += 2 {
201 b[i/2], _ = xtoi2(f[0][i:i+2], 0)
204 if syscall.BigEndian {
205 ifma = IPAddr{IP: IPv4(b[0], b[1], b[2], b[3])}
207 ifma = IPAddr{IP: IPv4(b[3], b[2], b[1], b[0])}
209 ifmat = append(ifmat, ifma.toAddr())
216 func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
217 fd, err := open(path)
224 b := make([]byte, IPv6len)
225 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
226 f := splitAtBytes(l, " \r\t\n")
230 if ifi == nil || f[1] == ifi.Name {
231 for i := 0; i+1 < len(f[2]); i += 2 {
232 b[i/2], _ = xtoi2(f[2][i:i+2], 0)
234 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]}}
235 ifmat = append(ifmat, ifma.toAddr())