Source file src/pkg/net/interface_linux.go
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.
4
5 // Network interface identification for Linux
6
7 package net
8
9 import (
10 "os"
11 "syscall"
12 "unsafe"
13 )
14
15 // If the ifindex is zero, interfaceTable returns mappings of all
16 // network interfaces. Otherwise it returns a mapping of a specific
17 // interface.
18 func interfaceTable(ifindex int) ([]Interface, error) {
19 tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
20 if err != nil {
21 return nil, os.NewSyscallError("netlink rib", err)
22 }
23
24 msgs, err := syscall.ParseNetlinkMessage(tab)
25 if err != nil {
26 return nil, os.NewSyscallError("netlink message", err)
27 }
28
29 var ift []Interface
30 for _, m := range msgs {
31 switch m.Header.Type {
32 case syscall.NLMSG_DONE:
33 goto 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)
38 if err != nil {
39 return nil, os.NewSyscallError("netlink routeattr", err)
40 }
41 ifi := newLink(ifim, attrs)
42 ift = append(ift, ifi)
43 }
44 }
45 }
46 done:
47 return ift, nil
48 }
49
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 {
53 switch a.Attr.Type {
54 case syscall.IFLA_ADDRESS:
55 var nonzero bool
56 for _, b := range a.Value {
57 if b != 0 {
58 nonzero = true
59 }
60 }
61 if nonzero {
62 ifi.HardwareAddr = a.Value[:]
63 }
64 case syscall.IFLA_IFNAME:
65 ifi.Name = string(a.Value[:len(a.Value)-1])
66 case syscall.IFLA_MTU:
67 ifi.MTU = int(uint32(a.Value[3])<<24 | uint32(a.Value[2])<<16 | uint32(a.Value[1])<<8 | uint32(a.Value[0]))
68 }
69 }
70 return ifi
71 }
72
73 func linkFlags(rawFlags uint32) Flags {
74 var f Flags
75 if rawFlags&syscall.IFF_UP != 0 {
76 f |= FlagUp
77 }
78 if rawFlags&syscall.IFF_BROADCAST != 0 {
79 f |= FlagBroadcast
80 }
81 if rawFlags&syscall.IFF_LOOPBACK != 0 {
82 f |= FlagLoopback
83 }
84 if rawFlags&syscall.IFF_POINTOPOINT != 0 {
85 f |= FlagPointToPoint
86 }
87 if rawFlags&syscall.IFF_MULTICAST != 0 {
88 f |= FlagMulticast
89 }
90 return f
91 }
92
93 // If the ifindex is zero, interfaceAddrTable returns addresses
94 // for all network interfaces. Otherwise it returns addresses
95 // for a specific interface.
96 func interfaceAddrTable(ifindex int) ([]Addr, error) {
97 tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
98 if err != nil {
99 return nil, os.NewSyscallError("netlink rib", err)
100 }
101
102 msgs, err := syscall.ParseNetlinkMessage(tab)
103 if err != nil {
104 return nil, os.NewSyscallError("netlink message", err)
105 }
106
107 ifat, err := addrTable(msgs, ifindex)
108 if err != nil {
109 return nil, err
110 }
111 return ifat, nil
112 }
113
114 func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) {
115 var ifat []Addr
116 for _, m := range msgs {
117 switch m.Header.Type {
118 case syscall.NLMSG_DONE:
119 goto done
120 case syscall.RTM_NEWADDR:
121 ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
122 if ifindex == 0 || ifindex == int(ifam.Index) {
123 attrs, err := syscall.ParseNetlinkRouteAttr(&m)
124 if err != nil {
125 return nil, os.NewSyscallError("netlink routeattr", err)
126 }
127 ifat = append(ifat, newAddr(attrs, int(ifam.Family), int(ifam.Prefixlen)))
128 }
129 }
130 }
131 done:
132 return ifat, nil
133 }
134
135 func newAddr(attrs []syscall.NetlinkRouteAttr, family, pfxlen int) Addr {
136 ifa := &IPNet{}
137 for _, a := range attrs {
138 switch a.Attr.Type {
139 case syscall.IFA_ADDRESS:
140 switch family {
141 case syscall.AF_INET:
142 ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])
143 ifa.Mask = CIDRMask(pfxlen, 8*IPv4len)
144 case syscall.AF_INET6:
145 ifa.IP = make(IP, IPv6len)
146 copy(ifa.IP, a.Value[:])
147 ifa.Mask = CIDRMask(pfxlen, 8*IPv6len)
148 }
149 }
150 }
151 return ifa
152 }
153
154 // If the ifindex is zero, interfaceMulticastAddrTable returns
155 // addresses for all network interfaces. Otherwise it returns
156 // addresses for a specific interface.
157 func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
158 var (
159 err error
160 ifi *Interface
161 )
162 if ifindex > 0 {
163 ifi, err = InterfaceByIndex(ifindex)
164 if err != nil {
165 return nil, err
166 }
167 }
168 ifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi)
169 ifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi)
170 return append(ifmat4, ifmat6...), nil
171 }
172
173 func parseProcNetIGMP(path string, ifi *Interface) []Addr {
174 fd, err := open(path)
175 if err != nil {
176 return nil
177 }
178 defer fd.close()
179
180 var (
181 ifmat []Addr
182 name string
183 )
184 fd.readLine() // skip first line
185 b := make([]byte, IPv4len)
186 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
187 f := splitAtBytes(l, " :\r\t\n")
188 if len(f) < 4 {
189 continue
190 }
191 switch {
192 case l[0] != ' ' && l[0] != '\t': // new interface line
193 name = f[1]
194 case len(f[0]) == 8:
195 if ifi == nil || name == ifi.Name {
196 for i := 0; i+1 < len(f[0]); i += 2 {
197 b[i/2], _ = xtoi2(f[0][i:i+2], 0)
198 }
199 ifma := IPAddr{IP: IPv4(b[3], b[2], b[1], b[0])}
200 ifmat = append(ifmat, ifma.toAddr())
201 }
202 }
203 }
204 return ifmat
205 }
206
207 func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
208 fd, err := open(path)
209 if err != nil {
210 return nil
211 }
212 defer fd.close()
213
214 var ifmat []Addr
215 b := make([]byte, IPv6len)
216 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
217 f := splitAtBytes(l, " \r\t\n")
218 if len(f) < 6 {
219 continue
220 }
221 if ifi == nil || f[1] == ifi.Name {
222 for i := 0; i+1 < len(f[2]); i += 2 {
223 b[i/2], _ = xtoi2(f[2][i:i+2], 0)
224 }
225 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]}}
226 ifmat = append(ifmat, ifma.toAddr())
227 }
228 }
229 return ifmat
230 }