github.com/spotify/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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 func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) *Interface { 49 ifi := &Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)} 50 for _, a := range attrs { 51 switch a.Attr.Type { 52 case syscall.IFLA_ADDRESS: 53 var nonzero bool 54 for _, b := range a.Value { 55 if b != 0 { 56 nonzero = true 57 } 58 } 59 if nonzero { 60 ifi.HardwareAddr = a.Value[:] 61 } 62 case syscall.IFLA_IFNAME: 63 ifi.Name = string(a.Value[:len(a.Value)-1]) 64 case syscall.IFLA_MTU: 65 ifi.MTU = int(*(*uint32)(unsafe.Pointer(&a.Value[:4][0]))) 66 } 67 } 68 return ifi 69 } 70 71 func linkFlags(rawFlags uint32) Flags { 72 var f Flags 73 if rawFlags&syscall.IFF_UP != 0 { 74 f |= FlagUp 75 } 76 if rawFlags&syscall.IFF_BROADCAST != 0 { 77 f |= FlagBroadcast 78 } 79 if rawFlags&syscall.IFF_LOOPBACK != 0 { 80 f |= FlagLoopback 81 } 82 if rawFlags&syscall.IFF_POINTOPOINT != 0 { 83 f |= FlagPointToPoint 84 } 85 if rawFlags&syscall.IFF_MULTICAST != 0 { 86 f |= FlagMulticast 87 } 88 return f 89 } 90 91 // If the ifi is nil, interfaceAddrTable returns addresses for all 92 // network interfaces. Otherwise it returns addresses for a specific 93 // interface. 94 func interfaceAddrTable(ifi *Interface) ([]Addr, error) { 95 tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC) 96 if err != nil { 97 return nil, os.NewSyscallError("netlink rib", err) 98 } 99 msgs, err := syscall.ParseNetlinkMessage(tab) 100 if err != nil { 101 return nil, os.NewSyscallError("netlink message", err) 102 } 103 var ift []Interface 104 if ifi == nil { 105 var err error 106 ift, err = interfaceTable(0) 107 if err != nil { 108 return nil, err 109 } 110 } 111 ifat, err := addrTable(ift, ifi, msgs) 112 if err != nil { 113 return nil, err 114 } 115 return ifat, nil 116 } 117 118 func addrTable(ift []Interface, ifi *Interface, msgs []syscall.NetlinkMessage) ([]Addr, error) { 119 var ifat []Addr 120 loop: 121 for _, m := range msgs { 122 switch m.Header.Type { 123 case syscall.NLMSG_DONE: 124 break loop 125 case syscall.RTM_NEWADDR: 126 ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0])) 127 if len(ift) != 0 || ifi.Index == int(ifam.Index) { 128 if len(ift) != 0 { 129 var err error 130 ifi, err = interfaceByIndex(ift, int(ifam.Index)) 131 if err != nil { 132 return nil, err 133 } 134 } 135 attrs, err := syscall.ParseNetlinkRouteAttr(&m) 136 if err != nil { 137 return nil, os.NewSyscallError("netlink routeattr", err) 138 } 139 ifa := newAddr(ifi, ifam, attrs) 140 if ifa != nil { 141 ifat = append(ifat, ifa) 142 } 143 } 144 } 145 } 146 return ifat, nil 147 } 148 149 func newAddr(ifi *Interface, ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRouteAttr) Addr { 150 for _, a := range attrs { 151 if ifi.Flags&FlagPointToPoint != 0 && a.Attr.Type == syscall.IFA_LOCAL || 152 ifi.Flags&FlagPointToPoint == 0 && a.Attr.Type == syscall.IFA_ADDRESS { 153 switch ifam.Family { 154 case syscall.AF_INET: 155 return &IPNet{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv4len)} 156 case syscall.AF_INET6: 157 ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)} 158 copy(ifa.IP, a.Value[:]) 159 return ifa 160 } 161 } 162 } 163 return nil 164 } 165 166 // interfaceMulticastAddrTable returns addresses for a specific 167 // interface. 168 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { 169 ifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi) 170 ifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi) 171 return append(ifmat4, ifmat6...), nil 172 } 173 174 func parseProcNetIGMP(path string, ifi *Interface) []Addr { 175 fd, err := open(path) 176 if err != nil { 177 return nil 178 } 179 defer fd.close() 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 // The Linux kernel puts the IP 197 // address in /proc/net/igmp in native 198 // endianness. 199 for i := 0; i+1 < len(f[0]); i += 2 { 200 b[i/2], _ = xtoi2(f[0][i:i+2], 0) 201 } 202 i := *(*uint32)(unsafe.Pointer(&b[:4][0])) 203 ifma := IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))} 204 ifmat = append(ifmat, ifma.toAddr()) 205 } 206 } 207 } 208 return ifmat 209 } 210 211 func parseProcNetIGMP6(path string, ifi *Interface) []Addr { 212 fd, err := open(path) 213 if err != nil { 214 return nil 215 } 216 defer fd.close() 217 var ifmat []Addr 218 b := make([]byte, IPv6len) 219 for l, ok := fd.readLine(); ok; l, ok = fd.readLine() { 220 f := splitAtBytes(l, " \r\t\n") 221 if len(f) < 6 { 222 continue 223 } 224 if ifi == nil || f[1] == ifi.Name { 225 for i := 0; i+1 < len(f[2]); i += 2 { 226 b[i/2], _ = xtoi2(f[2][i:i+2], 0) 227 } 228 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]}} 229 ifmat = append(ifmat, ifma.toAddr()) 230 } 231 } 232 return ifmat 233 }