OSDN Git Service

compiler, runtime: Add explicit checks for zero and overflow division.
[pf3gnuchains/gcc-fork.git] / libgo / go / 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                         if syscall.BigEndian {
68                                 ifi.MTU = int(uint32(a.Value[0])<<24 | uint32(a.Value[1])<<16 | uint32(a.Value[2])<<8 | uint32(a.Value[3]))
69                         } else {
70                                 ifi.MTU = int(uint32(a.Value[3])<<24 | uint32(a.Value[2])<<16 | uint32(a.Value[1])<<8 | uint32(a.Value[0]))
71                         }
72                 }
73         }
74         return ifi
75 }
76
77 func linkFlags(rawFlags uint32) Flags {
78         var f Flags
79         if rawFlags&syscall.IFF_UP != 0 {
80                 f |= FlagUp
81         }
82         if rawFlags&syscall.IFF_BROADCAST != 0 {
83                 f |= FlagBroadcast
84         }
85         if rawFlags&syscall.IFF_LOOPBACK != 0 {
86                 f |= FlagLoopback
87         }
88         if rawFlags&syscall.IFF_POINTOPOINT != 0 {
89                 f |= FlagPointToPoint
90         }
91         if rawFlags&syscall.IFF_MULTICAST != 0 {
92                 f |= FlagMulticast
93         }
94         return f
95 }
96
97 // If the ifindex is zero, interfaceAddrTable returns addresses
98 // for all network interfaces.  Otherwise it returns addresses
99 // for a specific interface.
100 func interfaceAddrTable(ifindex int) ([]Addr, error) {
101         tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
102         if err != nil {
103                 return nil, os.NewSyscallError("netlink rib", err)
104         }
105
106         msgs, err := syscall.ParseNetlinkMessage(tab)
107         if err != nil {
108                 return nil, os.NewSyscallError("netlink message", err)
109         }
110
111         ifat, err := addrTable(msgs, ifindex)
112         if err != nil {
113                 return nil, err
114         }
115         return ifat, nil
116 }
117
118 func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) {
119         var ifat []Addr
120         for _, m := range msgs {
121                 switch m.Header.Type {
122                 case syscall.NLMSG_DONE:
123                         goto done
124                 case syscall.RTM_NEWADDR:
125                         ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
126                         if ifindex == 0 || ifindex == int(ifam.Index) {
127                                 attrs, err := syscall.ParseNetlinkRouteAttr(&m)
128                                 if err != nil {
129                                         return nil, os.NewSyscallError("netlink routeattr", err)
130                                 }
131                                 ifat = append(ifat, newAddr(attrs, int(ifam.Family), int(ifam.Prefixlen)))
132                         }
133                 }
134         }
135 done:
136         return ifat, nil
137 }
138
139 func newAddr(attrs []syscall.NetlinkRouteAttr, family, pfxlen int) Addr {
140         ifa := &IPNet{}
141         for _, a := range attrs {
142                 switch a.Attr.Type {
143                 case syscall.IFA_ADDRESS:
144                         switch family {
145                         case syscall.AF_INET:
146                                 ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])
147                                 ifa.Mask = CIDRMask(pfxlen, 8*IPv4len)
148                         case syscall.AF_INET6:
149                                 ifa.IP = make(IP, IPv6len)
150                                 copy(ifa.IP, a.Value[:])
151                                 ifa.Mask = CIDRMask(pfxlen, 8*IPv6len)
152                         }
153                 }
154         }
155         return ifa
156 }
157
158 // If the ifindex is zero, interfaceMulticastAddrTable returns
159 // addresses for all network interfaces.  Otherwise it returns
160 // addresses for a specific interface.
161 func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
162         var (
163                 err error
164                 ifi *Interface
165         )
166         if ifindex > 0 {
167                 ifi, err = InterfaceByIndex(ifindex)
168                 if err != nil {
169                         return nil, err
170                 }
171         }
172         ifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi)
173         ifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi)
174         return append(ifmat4, ifmat6...), nil
175 }
176
177 func parseProcNetIGMP(path string, ifi *Interface) []Addr {
178         fd, err := open(path)
179         if err != nil {
180                 return nil
181         }
182         defer fd.close()
183
184         var (
185                 ifmat []Addr
186                 name  string
187         )
188         fd.readLine() // skip first line
189         b := make([]byte, IPv4len)
190         for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
191                 f := splitAtBytes(l, " :\r\t\n")
192                 if len(f) < 4 {
193                         continue
194                 }
195                 switch {
196                 case l[0] != ' ' && l[0] != '\t': // new interface line
197                         name = f[1]
198                 case len(f[0]) == 8:
199                         if ifi == nil || name == ifi.Name {
200                                 for i := 0; i+1 < len(f[0]); i += 2 {
201                                         b[i/2], _ = xtoi2(f[0][i:i+2], 0)
202                                 }
203                                 var ifma IPAddr
204                                 if syscall.BigEndian {
205                                         ifma = IPAddr{IP: IPv4(b[0], b[1], b[2], b[3])}
206                                 } else {
207                                         ifma = IPAddr{IP: IPv4(b[3], b[2], b[1], b[0])}
208                                 }
209                                 ifmat = append(ifmat, ifma.toAddr())
210                         }
211                 }
212         }
213         return ifmat
214 }
215
216 func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
217         fd, err := open(path)
218         if err != nil {
219                 return nil
220         }
221         defer fd.close()
222
223         var ifmat []Addr
224         b := make([]byte, IPv6len)
225         for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
226                 f := splitAtBytes(l, " \r\t\n")
227                 if len(f) < 6 {
228                         continue
229                 }
230                 if ifi == nil || f[1] == ifi.Name {
231                         for i := 0; i+1 < len(f[2]); i += 2 {
232                                 b[i/2], _ = xtoi2(f[2][i:i+2], 0)
233                         }
234                         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]}}
235                         ifmat = append(ifmat, ifma.toAddr())
236                 }
237         }
238         return ifmat
239 }