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) {
20 tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
22 return nil, os.NewSyscallError("netlink rib", err)
25 msgs, err := syscall.ParseNetlinkMessage(tab)
27 return nil, os.NewSyscallError("netlink message", err)
31 for _, m := range msgs {
32 switch m.Header.Type {
33 case syscall.NLMSG_DONE:
35 case syscall.RTM_NEWLINK:
36 ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0]))
37 if ifindex == 0 || ifindex == int(ifim.Index) {
38 attrs, err := syscall.ParseNetlinkRouteAttr(&m)
40 return nil, os.NewSyscallError("netlink routeattr", err)
42 ifi := newLink(ifim, attrs)
43 ift = append(ift, ifi)
51 func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) Interface {
52 ifi := Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
53 for _, a := range attrs {
55 case syscall.IFLA_ADDRESS:
57 for _, b := range a.Value {
63 ifi.HardwareAddr = a.Value[:]
65 case syscall.IFLA_IFNAME:
66 ifi.Name = string(a.Value[:len(a.Value)-1])
67 case syscall.IFLA_MTU:
68 ifi.MTU = int(uint32(a.Value[3])<<24 | uint32(a.Value[2])<<16 | uint32(a.Value[1])<<8 | uint32(a.Value[0]))
74 func linkFlags(rawFlags uint32) Flags {
76 if rawFlags&syscall.IFF_UP != 0 {
79 if rawFlags&syscall.IFF_BROADCAST != 0 {
82 if rawFlags&syscall.IFF_LOOPBACK != 0 {
85 if rawFlags&syscall.IFF_POINTOPOINT != 0 {
88 if rawFlags&syscall.IFF_MULTICAST != 0 {
94 // If the ifindex is zero, interfaceAddrTable returns addresses
95 // for all network interfaces. Otherwise it returns addresses
96 // for a specific interface.
97 func interfaceAddrTable(ifindex int) ([]Addr, error) {
98 tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
100 return nil, os.NewSyscallError("netlink rib", err)
103 msgs, err := syscall.ParseNetlinkMessage(tab)
105 return nil, os.NewSyscallError("netlink message", err)
108 ifat, err := addrTable(msgs, ifindex)
115 func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) {
117 for _, m := range msgs {
118 switch m.Header.Type {
119 case syscall.NLMSG_DONE:
121 case syscall.RTM_NEWADDR:
122 ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
123 if ifindex == 0 || ifindex == int(ifam.Index) {
124 attrs, err := syscall.ParseNetlinkRouteAttr(&m)
126 return nil, os.NewSyscallError("netlink routeattr", err)
128 ifat = append(ifat, newAddr(attrs, int(ifam.Family), int(ifam.Prefixlen)))
136 func newAddr(attrs []syscall.NetlinkRouteAttr, family, pfxlen int) Addr {
138 for _, a := range attrs {
140 case syscall.IFA_ADDRESS:
142 case syscall.AF_INET:
143 ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])
144 ifa.Mask = CIDRMask(pfxlen, 8*IPv4len)
145 case syscall.AF_INET6:
146 ifa.IP = make(IP, IPv6len)
147 copy(ifa.IP, a.Value[:])
148 ifa.Mask = CIDRMask(pfxlen, 8*IPv6len)
155 // If the ifindex is zero, interfaceMulticastAddrTable returns
156 // addresses for all network interfaces. Otherwise it returns
157 // addresses for a specific interface.
158 func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
164 ifi, err = InterfaceByIndex(ifindex)
169 ifmat4 := parseProcNetIGMP(ifi)
170 ifmat6 := parseProcNetIGMP6(ifi)
171 return append(ifmat4, ifmat6...), nil
174 func parseProcNetIGMP(ifi *Interface) []Addr {
175 fd, err := open("/proc/net/igmp")
185 fd.readLine() // skip first line
186 b := make([]byte, IPv4len)
187 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
191 if ifi == nil || name == ifi.Name {
192 fmt.Sscanf(f[0], "%08x", &b)
193 ifma := IPAddr{IP: IPv4(b[3], b[2], b[1], b[0])}
194 ifmat = append(ifmat, ifma.toAddr())
203 func parseProcNetIGMP6(ifi *Interface) []Addr {
204 fd, err := open("/proc/net/igmp6")
211 b := make([]byte, IPv6len)
212 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
214 if ifi == nil || f[1] == ifi.Name {
215 fmt.Sscanf(f[2], "%32x", &b)
216 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]}}
217 ifmat = append(ifmat, ifma.toAddr())