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.
13 // If the ifindex is zero, interfaceTable returns mappings of all
14 // network interfaces. Otherwise it returns a mapping of a specific
16 func interfaceTable(ifindex
int) ([]Interface
, error
) {
17 tab
, err
:= syscall
.NetlinkRIB(syscall
.RTM_GETLINK
, syscall
.AF_UNSPEC
)
19 return nil, os
.NewSyscallError("netlink rib", err
)
21 msgs
, err
:= syscall
.ParseNetlinkMessage(tab
)
23 return nil, os
.NewSyscallError("netlink message", err
)
27 for _
, m
:= range msgs
{
28 switch m
.Header
.Type
{
29 case syscall
.NLMSG_DONE
:
31 case syscall
.RTM_NEWLINK
:
32 ifim
:= (*syscall
.IfInfomsg
)(unsafe
.Pointer(&m
.Data
[0]))
33 if ifindex
== 0 || ifindex
== int(ifim
.Index
) {
34 attrs
, err
:= syscall
.ParseNetlinkRouteAttr(&m
)
36 return nil, os
.NewSyscallError("netlink routeattr", err
)
38 ift
= append(ift
, *newLink(ifim
, attrs
))
39 if ifindex
== int(ifim
.Index
) {
49 // See linux/if_arp.h.
50 // Note that Linux doesn't support IPv4 over IPv6 tunneling.
51 sysARPHardwareIPv4IPv4
= 768 // IPv4 over IPv4 tunneling
52 sysARPHardwareIPv6IPv6
= 769 // IPv6 over IPv6 tunneling
53 sysARPHardwareIPv6IPv4
= 776 // IPv6 over IPv4 tunneling
54 sysARPHardwareGREIPv4
= 778 // any over GRE over IPv4 tunneling
55 sysARPHardwareGREIPv6
= 823 // any over GRE over IPv6 tunneling
58 func newLink(ifim
*syscall
.IfInfomsg
, attrs
[]syscall
.NetlinkRouteAttr
) *Interface
{
59 ifi
:= &Interface
{Index
: int(ifim
.Index
), Flags
: linkFlags(ifim
.Flags
)}
60 for _
, a
:= range attrs
{
62 case syscall
.IFLA_ADDRESS
:
63 // We never return any /32 or /128 IP address
64 // prefix on any IP tunnel interface as the
69 case sysARPHardwareIPv4IPv4
, sysARPHardwareGREIPv4
, sysARPHardwareIPv6IPv4
:
74 case sysARPHardwareIPv6IPv6
, sysARPHardwareGREIPv6
:
79 for _
, b
:= range a
.Value
{
86 ifi
.HardwareAddr
= a
.Value
[:]
88 case syscall
.IFLA_IFNAME
:
89 ifi
.Name
= string(a
.Value
[:len(a
.Value
)-1])
90 case syscall
.IFLA_MTU
:
91 ifi
.MTU
= int(*(*uint32)(unsafe
.Pointer(&a
.Value
[:4][0])))
97 func linkFlags(rawFlags
uint32) Flags
{
99 if rawFlags
&syscall
.IFF_UP
!= 0 {
102 if rawFlags
&syscall
.IFF_BROADCAST
!= 0 {
105 if rawFlags
&syscall
.IFF_LOOPBACK
!= 0 {
108 if rawFlags
&syscall
.IFF_POINTOPOINT
!= 0 {
109 f |
= FlagPointToPoint
111 if rawFlags
&syscall
.IFF_MULTICAST
!= 0 {
117 // If the ifi is nil, interfaceAddrTable returns addresses for all
118 // network interfaces. Otherwise it returns addresses for a specific
120 func interfaceAddrTable(ifi
*Interface
) ([]Addr
, error
) {
121 tab
, err
:= syscall
.NetlinkRIB(syscall
.RTM_GETADDR
, syscall
.AF_UNSPEC
)
123 return nil, os
.NewSyscallError("netlink rib", err
)
125 msgs
, err
:= syscall
.ParseNetlinkMessage(tab
)
127 return nil, os
.NewSyscallError("netlink message", err
)
132 ift
, err
= interfaceTable(0)
137 ifat
, err
:= addrTable(ift
, ifi
, msgs
)
144 func addrTable(ift
[]Interface
, ifi
*Interface
, msgs
[]syscall
.NetlinkMessage
) ([]Addr
, error
) {
147 for _
, m
:= range msgs
{
148 switch m
.Header
.Type
{
149 case syscall
.NLMSG_DONE
:
151 case syscall
.RTM_NEWADDR
:
152 ifam
:= (*syscall
.IfAddrmsg
)(unsafe
.Pointer(&m
.Data
[0]))
153 if len(ift
) != 0 || ifi
.Index
== int(ifam
.Index
) {
156 ifi
, err
= interfaceByIndex(ift
, int(ifam
.Index
))
161 attrs
, err
:= syscall
.ParseNetlinkRouteAttr(&m
)
163 return nil, os
.NewSyscallError("netlink routeattr", err
)
165 ifa
:= newAddr(ifi
, ifam
, attrs
)
167 ifat
= append(ifat
, ifa
)
175 func newAddr(ifi
*Interface
, ifam
*syscall
.IfAddrmsg
, attrs
[]syscall
.NetlinkRouteAttr
) Addr
{
176 var ipPointToPoint
bool
177 // Seems like we need to make sure whether the IP interface
178 // stack consists of IP point-to-point numbered or unnumbered
179 // addressing over point-to-point link encapsulation.
180 if ifi
.Flags
&FlagPointToPoint
!= 0 {
181 for _
, a
:= range attrs
{
182 if a
.Attr
.Type
== syscall
.IFA_LOCAL
{
183 ipPointToPoint
= true
188 for _
, a
:= range attrs
{
189 if ipPointToPoint
&& a
.Attr
.Type
== syscall
.IFA_ADDRESS ||
!ipPointToPoint
&& a
.Attr
.Type
== syscall
.IFA_LOCAL
{
193 case syscall
.AF_INET
:
194 return &IPNet
{IP
: IPv4(a
.Value
[0], a
.Value
[1], a
.Value
[2], a
.Value
[3]), Mask
: CIDRMask(int(ifam
.Prefixlen
), 8*IPv4len
)}
195 case syscall
.AF_INET6
:
196 ifa
:= &IPNet
{IP
: make(IP
, IPv6len
), Mask
: CIDRMask(int(ifam
.Prefixlen
), 8*IPv6len
)}
197 copy(ifa
.IP
, a
.Value
[:])
204 // interfaceMulticastAddrTable returns addresses for a specific
206 func interfaceMulticastAddrTable(ifi
*Interface
) ([]Addr
, error
) {
207 ifmat4
:= parseProcNetIGMP("/proc/net/igmp", ifi
)
208 ifmat6
:= parseProcNetIGMP6("/proc/net/igmp6", ifi
)
209 return append(ifmat4
, ifmat6
...), nil
212 func parseProcNetIGMP(path
string, ifi
*Interface
) []Addr
{
213 fd
, err
:= open(path
)
222 fd
.readLine() // skip first line
223 b
:= make([]byte, IPv4len
)
224 for l
, ok
:= fd
.readLine(); ok
; l
, ok
= fd
.readLine() {
225 f
:= splitAtBytes(l
, " :\r\t\n")
230 case l
[0] != ' ' && l
[0] != '\t': // new interface line
233 if ifi
== nil || name
== ifi
.Name
{
234 // The Linux kernel puts the IP
235 // address in /proc/net/igmp in native
237 for i
:= 0; i
+1 < len(f
[0]); i
+= 2 {
238 b
[i
/2], _
= xtoi2(f
[0][i
:i
+2], 0)
240 i
:= *(*uint32)(unsafe
.Pointer(&b
[:4][0]))
241 ifma
:= IPAddr
{IP
: IPv4(byte(i
>>24), byte(i
>>16), byte(i
>>8), byte(i
))}
242 ifmat
= append(ifmat
, ifma
.toAddr())
249 func parseProcNetIGMP6(path
string, ifi
*Interface
) []Addr
{
250 fd
, err
:= open(path
)
256 b
:= make([]byte, IPv6len
)
257 for l
, ok
:= fd
.readLine(); ok
; l
, ok
= fd
.readLine() {
258 f
:= splitAtBytes(l
, " \r\t\n")
262 if ifi
== nil || f
[1] == ifi
.Name
{
263 for i
:= 0; i
+1 < len(f
[2]); i
+= 2 {
264 b
[i
/2], _
= xtoi2(f
[2][i
:i
+2], 0)
266 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]}}
267 ifmat
= append(ifmat
, ifma
.toAddr())