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 }