github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/pkg/net/interface_linux.go (about) 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 package net 6 7 import ( 8 "os" 9 "syscall" 10 "unsafe" 11 ) 12 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("netlink rib", err) 20 } 21 msgs, err := syscall.ParseNetlinkMessage(tab) 22 if err != nil { 23 return nil, os.NewSyscallError("netlink message", 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("netlink routeattr", 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 // 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 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 // 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 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 // 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("netlink rib", err) 124 } 125 msgs, err := syscall.ParseNetlinkMessage(tab) 126 if err != nil { 127 return nil, os.NewSyscallError("netlink message", 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("netlink routeattr", err) 164 } 165 ifa := newAddr(ifi, ifam, attrs) 166 if ifa != nil { 167 ifat = append(ifat, ifa) 168 } 169 } 170 } 171 } 172 return ifat, nil 173 } 174 175 func newAddr(ifi *Interface, 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 over point-to-point link encapsulation. 180 if ifi.Flags&FlagPointToPoint != 0 { 181 for _, a := range attrs { 182 if a.Attr.Type == syscall.IFA_LOCAL { 183 ipPointToPoint = true 184 break 185 } 186 } 187 } 188 for _, a := range attrs { 189 if ipPointToPoint && a.Attr.Type == syscall.IFA_ADDRESS || !ipPointToPoint && a.Attr.Type == syscall.IFA_LOCAL { 190 continue 191 } 192 switch ifam.Family { 193 case syscall.AF_INET: 194 return &IPNet{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv4len)} 195 case syscall.AF_INET6: 196 ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)} 197 copy(ifa.IP, a.Value[:]) 198 return ifa 199 } 200 } 201 return nil 202 } 203 204 // interfaceMulticastAddrTable returns addresses for a specific 205 // interface. 206 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { 207 ifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi) 208 ifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi) 209 return append(ifmat4, ifmat6...), nil 210 } 211 212 func parseProcNetIGMP(path string, ifi *Interface) []Addr { 213 fd, err := open(path) 214 if err != nil { 215 return nil 216 } 217 defer fd.close() 218 var ( 219 ifmat []Addr 220 name string 221 ) 222 fd.readLine() // skip first line 223 b := make([]byte, IPv4len) 224 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() { 225 f := splitAtBytes(l, " :\r\t\n") 226 if len(f) < 4 { 227 continue 228 } 229 switch { 230 case l[0] != ' ' && l[0] != '\t': // new interface line 231 name = f[1] 232 case len(f[0]) == 8: 233 if ifi == nil || name == ifi.Name { 234 // The Linux kernel puts the IP 235 // address in /proc/net/igmp in native 236 // endianness. 237 for i := 0; i+1 < len(f[0]); i += 2 { 238 b[i/2], _ = xtoi2(f[0][i:i+2], 0) 239 } 240 i := *(*uint32)(unsafe.Pointer(&b[:4][0])) 241 ifma := IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))} 242 ifmat = append(ifmat, ifma.toAddr()) 243 } 244 } 245 } 246 return ifmat 247 } 248 249 func parseProcNetIGMP6(path string, ifi *Interface) []Addr { 250 fd, err := open(path) 251 if err != nil { 252 return nil 253 } 254 defer fd.close() 255 var ifmat []Addr 256 b := make([]byte, IPv6len) 257 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() { 258 f := splitAtBytes(l, " \r\t\n") 259 if len(f) < 6 { 260 continue 261 } 262 if ifi == nil || f[1] == ifi.Name { 263 for i := 0; i+1 < len(f[2]); i += 2 { 264 b[i/2], _ = xtoi2(f[2][i:i+2], 0) 265 } 266 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]}} 267 ifmat = append(ifmat, ifma.toAddr()) 268 } 269 } 270 return ifmat 271 }