libgo: update to Go 1.11
[official-gcc.git] / libgo / go / net / interface_linux.go
blob441ab2f8805a1f8d4f3c9c10295eee0968f78ddc
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 package net
7 import (
8 "os"
9 "syscall"
10 "unsafe"
13 // If the ifindex is zero, interfaceTable returns mappings of all
14 // network interfaces. Otherwise it returns a mapping of a specific
15 // interface.
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)
21 msgs, err := syscall.ParseNetlinkMessage(tab)
22 if err != nil {
23 return nil, os.NewSyscallError("parsenetlinkmessage", err)
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)
38 ift = append(ift, *newLink(ifim, attrs))
39 if ifindex == int(ifim.Index) {
40 break loop
45 return ift, nil
48 const (
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 {
61 switch a.Attr.Type {
62 case syscall.IFLA_ADDRESS:
63 // We never return any /32 or /128 IP address
64 // prefix on any IP tunnel interface as the
65 // hardware address.
66 switch len(a.Value) {
67 case IPv4len:
68 switch ifim.Type {
69 case sysARPHardwareIPv4IPv4, sysARPHardwareGREIPv4, sysARPHardwareIPv6IPv4:
70 continue
72 case IPv6len:
73 switch ifim.Type {
74 case sysARPHardwareIPv6IPv6, sysARPHardwareGREIPv6:
75 continue
78 var nonzero bool
79 for _, b := range a.Value {
80 if b != 0 {
81 nonzero = true
82 break
85 if nonzero {
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])))
94 return ifi
97 func linkFlags(rawFlags uint32) Flags {
98 var f Flags
99 if rawFlags&syscall.IFF_UP != 0 {
100 f |= FlagUp
102 if rawFlags&syscall.IFF_BROADCAST != 0 {
103 f |= FlagBroadcast
105 if rawFlags&syscall.IFF_LOOPBACK != 0 {
106 f |= FlagLoopback
108 if rawFlags&syscall.IFF_POINTOPOINT != 0 {
109 f |= FlagPointToPoint
111 if rawFlags&syscall.IFF_MULTICAST != 0 {
112 f |= FlagMulticast
114 return f
117 // If the ifi is nil, interfaceAddrTable returns addresses for all
118 // network interfaces. Otherwise it returns addresses for a specific
119 // interface.
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)
125 msgs, err := syscall.ParseNetlinkMessage(tab)
126 if err != nil {
127 return nil, os.NewSyscallError("parsenetlinkmessage", err)
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
137 ifat, err := addrTable(ift, ifi, msgs)
138 if err != nil {
139 return nil, err
141 return ifat, nil
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
161 attrs, err := syscall.ParseNetlinkRouteAttr(&m)
162 if err != nil {
163 return nil, os.NewSyscallError("parsenetlinkrouteattr", err)
165 ifa := newAddr(ifam, attrs)
166 if ifa != nil {
167 ifat = append(ifat, ifa)
172 return ifat, nil
175 func newAddr(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.
180 for _, a := range attrs {
181 if a.Attr.Type == syscall.IFA_LOCAL {
182 ipPointToPoint = true
183 break
186 for _, a := range attrs {
187 if ipPointToPoint && a.Attr.Type == syscall.IFA_ADDRESS {
188 continue
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
199 return nil
202 // interfaceMulticastAddrTable returns addresses for a specific
203 // interface.
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
210 func parseProcNetIGMP(path string, ifi *Interface) []Addr {
211 fd, err := open(path)
212 if err != nil {
213 return nil
215 defer fd.close()
216 var (
217 ifmat []Addr
218 name string
220 fd.readLine() // skip first line
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
227 switch {
228 case l[0] != ' ' && l[0] != '\t': // new interface line
229 name = f[1]
230 case len(f[0]) == 8:
231 if ifi == nil || name == ifi.Name {
232 // The Linux kernel puts the IP
233 // address in /proc/net/igmp in native
234 // endianness.
235 for i := 0; i+1 < len(f[0]); i += 2 {
236 b[i/2], _ = xtoi2(f[0][i:i+2], 0)
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)
244 return ifmat
247 func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
248 fd, err := open(path)
249 if err != nil {
250 return nil
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
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)
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)
268 return ifmat