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("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 // 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("netlinkrib", err) 124 } 125 msgs, err := syscall.ParseNetlinkMessage(tab) 126 if err != nil { 127 return nil, os.NewSyscallError("parsenetlinkmessage", 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("parsenetlinkrouteattr", 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. 180 for _, a := range attrs { 181 if a.Attr.Type == syscall.IFA_LOCAL { 182 ipPointToPoint = true 183 break 184 } 185 } 186 for _, a := range attrs { 187 if ipPointToPoint && a.Attr.Type == syscall.IFA_ADDRESS { 188 continue 189 } 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 197 } 198 } 199 return nil 200 } 201 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 208 } 209 210 func parseProcNetIGMP(path string, ifi *Interface) []Addr { 211 fd, err := open(path) 212 if err != nil { 213 return nil 214 } 215 defer fd.close() 216 var ( 217 ifmat []Addr 218 name string 219 ) 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 226 } 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) 237 } 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) 241 } 242 } 243 } 244 return ifmat 245 } 246 247 func parseProcNetIGMP6(path string, ifi *Interface) []Addr { 248 fd, err := open(path) 249 if err != nil { 250 return nil 251 } 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 259 } 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) 263 } 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) 266 } 267 } 268 return ifmat 269 } 270