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_RUNNING != 0 {
103 f |= FlagRunning
104 }
105 if rawFlags&syscall.IFF_BROADCAST != 0 {
106 f |= FlagBroadcast
107 }
108 if rawFlags&syscall.IFF_LOOPBACK != 0 {
109 f |= FlagLoopback
110 }
111 if rawFlags&syscall.IFF_POINTOPOINT != 0 {
112 f |= FlagPointToPoint
113 }
114 if rawFlags&syscall.IFF_MULTICAST != 0 {
115 f |= FlagMulticast
116 }
117 return f
118 }
119
120
121
122
123 func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
124 tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
125 if err != nil {
126 return nil, os.NewSyscallError("netlinkrib", err)
127 }
128 msgs, err := syscall.ParseNetlinkMessage(tab)
129 if err != nil {
130 return nil, os.NewSyscallError("parsenetlinkmessage", err)
131 }
132 var ift []Interface
133 if ifi == nil {
134 var err error
135 ift, err = interfaceTable(0)
136 if err != nil {
137 return nil, err
138 }
139 }
140 ifat, err := addrTable(ift, ifi, msgs)
141 if err != nil {
142 return nil, err
143 }
144 return ifat, nil
145 }
146
147 func addrTable(ift []Interface, ifi *Interface, msgs []syscall.NetlinkMessage) ([]Addr, error) {
148 var ifat []Addr
149 loop:
150 for _, m := range msgs {
151 switch m.Header.Type {
152 case syscall.NLMSG_DONE:
153 break loop
154 case syscall.RTM_NEWADDR:
155 ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
156 if len(ift) != 0 || ifi.Index == int(ifam.Index) {
157 if len(ift) != 0 {
158 var err error
159 ifi, err = interfaceByIndex(ift, int(ifam.Index))
160 if err != nil {
161 return nil, err
162 }
163 }
164 attrs, err := syscall.ParseNetlinkRouteAttr(&m)
165 if err != nil {
166 return nil, os.NewSyscallError("parsenetlinkrouteattr", err)
167 }
168 ifa := newAddr(ifam, attrs)
169 if ifa != nil {
170 ifat = append(ifat, ifa)
171 }
172 }
173 }
174 }
175 return ifat, nil
176 }
177
178 func newAddr(ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRouteAttr) Addr {
179 var ipPointToPoint bool
180
181
182
183 for _, a := range attrs {
184 if a.Attr.Type == syscall.IFA_LOCAL {
185 ipPointToPoint = true
186 break
187 }
188 }
189 for _, a := range attrs {
190 if ipPointToPoint && a.Attr.Type == syscall.IFA_ADDRESS {
191 continue
192 }
193 switch ifam.Family {
194 case syscall.AF_INET:
195 return &IPNet{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv4len)}
196 case syscall.AF_INET6:
197 ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)}
198 copy(ifa.IP, a.Value[:])
199 return ifa
200 }
201 }
202 return nil
203 }
204
205
206
207 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
208 ifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi)
209 ifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi)
210 return append(ifmat4, ifmat6...), nil
211 }
212
213 func parseProcNetIGMP(path string, ifi *Interface) []Addr {
214 fd, err := open(path)
215 if err != nil {
216 return nil
217 }
218 defer fd.close()
219 var (
220 ifmat []Addr
221 name string
222 )
223 fd.readLine()
224 b := make([]byte, IPv4len)
225 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
226 f := splitAtBytes(l, " :\r\t\n")
227 if len(f) < 4 {
228 continue
229 }
230 switch {
231 case l[0] != ' ' && l[0] != '\t':
232 name = f[1]
233 case len(f[0]) == 8:
234 if ifi == nil || name == ifi.Name {
235
236
237
238 for i := 0; i+1 < len(f[0]); i += 2 {
239 b[i/2], _ = xtoi2(f[0][i:i+2], 0)
240 }
241 i := *(*uint32)(unsafe.Pointer(&b[:4][0]))
242 ifma := &IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))}
243 ifmat = append(ifmat, ifma)
244 }
245 }
246 }
247 return ifmat
248 }
249
250 func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
251 fd, err := open(path)
252 if err != nil {
253 return nil
254 }
255 defer fd.close()
256 var ifmat []Addr
257 b := make([]byte, IPv6len)
258 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
259 f := splitAtBytes(l, " \r\t\n")
260 if len(f) < 6 {
261 continue
262 }
263 if ifi == nil || f[1] == ifi.Name {
264 for i := 0; i+1 < len(f[2]); i += 2 {
265 b[i/2], _ = xtoi2(f[2][i:i+2], 0)
266 }
267 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]}}
268 ifmat = append(ifmat, ifma)
269 }
270 }
271 return ifmat
272 }
273
View as plain text