Source file
src/net/interface_linux.go
1
2
3
4
5 package net
6
7 import (
8 "os"
9 "syscall"
10 "unsafe"
11 )
12
13
14
15
16 func interfaceTable(ifindex int) ([]Interface, error) {
17 tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
18 if err != nil {
19 return nil, os.NewSyscallError("netlinkrib", err)
20 }
21 msgs, err := syscall.ParseNetlinkMessage(tab)
22 if err != nil {
23 return nil, os.NewSyscallError("parsenetlinkmessage", err)
24 }
25 var ift []Interface
26 loop:
27 for _, m := range msgs {
28 switch m.Header.Type {
29 case syscall.NLMSG_DONE:
30 break loop
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)
35 if err != nil {
36 return nil, os.NewSyscallError("parsenetlinkrouteattr", err)
37 }
38 ift = append(ift, *newLink(ifim, attrs))
39 if ifindex == int(ifim.Index) {
40 break loop
41 }
42 }
43 }
44 }
45 return ift, nil
46 }
47
48 const (
49
50
51 sysARPHardwareIPv4IPv4 = 768
52 sysARPHardwareIPv6IPv6 = 769
53 sysARPHardwareIPv6IPv4 = 776
54 sysARPHardwareGREIPv4 = 778
55 sysARPHardwareGREIPv6 = 823
56 )
57
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 {
61 switch a.Attr.Type {
62 case syscall.IFLA_ADDRESS:
63
64
65
66 switch len(a.Value) {
67 case IPv4len:
68 switch ifim.Type {
69 case sysARPHardwareIPv4IPv4, sysARPHardwareGREIPv4, sysARPHardwareIPv6IPv4:
70 continue
71 }
72 case IPv6len:
73 switch ifim.Type {
74 case sysARPHardwareIPv6IPv6, sysARPHardwareGREIPv6:
75 continue
76 }
77 }
78 var nonzero bool
79 for _, b := range a.Value {
80 if b != 0 {
81 nonzero = true
82 break
83 }
84 }
85 if nonzero {
86 ifi.HardwareAddr = a.Value[:]
87 }
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])))
92 }
93 }
94 return ifi
95 }
96
97 func linkFlags(rawFlags uint32) Flags {
98 var f Flags
99 if rawFlags&syscall.IFF_UP != 0 {
100 f |= FlagUp
101 }
102 if rawFlags&syscall.IFF_BROADCAST != 0 {
103 f |= FlagBroadcast
104 }
105 if rawFlags&syscall.IFF_LOOPBACK != 0 {
106 f |= FlagLoopback
107 }
108 if rawFlags&syscall.IFF_POINTOPOINT != 0 {
109 f |= FlagPointToPoint
110 }
111 if rawFlags&syscall.IFF_MULTICAST != 0 {
112 f |= FlagMulticast
113 }
114 return f
115 }
116
117
118
119
120 func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
121 tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
122 if err != nil {
123 return nil, os.NewSyscallError("netlinkrib", err)
124 }
125 msgs, err := syscall.ParseNetlinkMessage(tab)
126 if err != nil {
127 return nil, os.NewSyscallError("parsenetlinkmessage", err)
128 }
129 var ift []Interface
130 if ifi == nil {
131 var err error
132 ift, err = interfaceTable(0)
133 if err != nil {
134 return nil, err
135 }
136 }
137 ifat, err := addrTable(ift, ifi, msgs)
138 if err != nil {
139 return nil, err
140 }
141 return ifat, nil
142 }
143
144 func addrTable(ift []Interface, ifi *Interface, msgs []syscall.NetlinkMessage) ([]Addr, error) {
145 var ifat []Addr
146 loop:
147 for _, m := range msgs {
148 switch m.Header.Type {
149 case syscall.NLMSG_DONE:
150 break loop
151 case syscall.RTM_NEWADDR:
152 ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
153 if len(ift) != 0 || ifi.Index == int(ifam.Index) {
154 if len(ift) != 0 {
155 var err error
156 ifi, err = interfaceByIndex(ift, int(ifam.Index))
157 if err != nil {
158 return nil, err
159 }
160 }
161 attrs, err := syscall.ParseNetlinkRouteAttr(&m)
162 if err != nil {
163 return nil, os.NewSyscallError("parsenetlinkrouteattr", err)
164 }
165 ifa := newAddr(ifam, attrs)
166 if ifa != nil {
167 ifat = append(ifat, ifa)
168 }
169 }
170 }
171 }
172 return ifat, nil
173 }
174
175 func newAddr(ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRouteAttr) Addr {
176 var ipPointToPoint bool
177
178
179
180 for _, a := range attrs {
181 if a.Attr.Type == syscall.IFA_LOCAL {
182 ipPointToPoint = true
183 break
184 }
185 }
186 for _, a := range attrs {
187 if ipPointToPoint && a.Attr.Type == syscall.IFA_ADDRESS {
188 continue
189 }
190 switch ifam.Family {
191 case syscall.AF_INET:
192 return &IPNet{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv4len)}
193 case syscall.AF_INET6:
194 ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)}
195 copy(ifa.IP, a.Value[:])
196 return ifa
197 }
198 }
199 return nil
200 }
201
202
203
204 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
205 ifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi)
206 ifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi)
207 return append(ifmat4, ifmat6...), nil
208 }
209
210 func parseProcNetIGMP(path string, ifi *Interface) []Addr {
211 fd, err := open(path)
212 if err != nil {
213 return nil
214 }
215 defer fd.close()
216 var (
217 ifmat []Addr
218 name string
219 )
220 fd.readLine()
221 b := make([]byte, IPv4len)
222 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
223 f := splitAtBytes(l, " :\r\t\n")
224 if len(f) < 4 {
225 continue
226 }
227 switch {
228 case l[0] != ' ' && l[0] != '\t':
229 name = f[1]
230 case len(f[0]) == 8:
231 if ifi == nil || name == ifi.Name {
232
233
234
235 for i := 0; i+1 < len(f[0]); i += 2 {
236 b[i/2], _ = xtoi2(f[0][i:i+2], 0)
237 }
238 i := *(*uint32)(unsafe.Pointer(&b[:4][0]))
239 ifma := &IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))}
240 ifmat = append(ifmat, ifma)
241 }
242 }
243 }
244 return ifmat
245 }
246
247 func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
248 fd, err := open(path)
249 if err != nil {
250 return nil
251 }
252 defer fd.close()
253 var ifmat []Addr
254 b := make([]byte, IPv6len)
255 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
256 f := splitAtBytes(l, " \r\t\n")
257 if len(f) < 6 {
258 continue
259 }
260 if ifi == nil || f[1] == ifi.Name {
261 for i := 0; i+1 < len(f[2]); i += 2 {
262 b[i/2], _ = xtoi2(f[2][i:i+2], 0)
263 }
264 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]}}
265 ifmat = append(ifmat, ifma)
266 }
267 }
268 return ifmat
269 }
270
View as plain text