github.com/rafaeltorres324/go/src@v0.0.0-20210519164414-9fdf653a9838/net/interface.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 "errors" 9 "sync" 10 "time" 11 ) 12 13 // BUG(mikio): On JS, methods and functions related to 14 // Interface are not implemented. 15 16 // BUG(mikio): On AIX, DragonFly BSD, NetBSD, OpenBSD, Plan 9 and 17 // Solaris, the MulticastAddrs method of Interface is not implemented. 18 19 var ( 20 errInvalidInterface = errors.New("invalid network interface") 21 errInvalidInterfaceIndex = errors.New("invalid network interface index") 22 errInvalidInterfaceName = errors.New("invalid network interface name") 23 errNoSuchInterface = errors.New("no such network interface") 24 errNoSuchMulticastInterface = errors.New("no such multicast network interface") 25 ) 26 27 // Interface represents a mapping between network interface name 28 // and index. It also represents network interface facility 29 // information. 30 type Interface struct { 31 Index int // positive integer that starts at one, zero is never used 32 MTU int // maximum transmission unit 33 Name string // e.g., "en0", "lo0", "eth0.100" 34 HardwareAddr HardwareAddr // IEEE MAC-48, EUI-48 and EUI-64 form 35 Flags Flags // e.g., FlagUp, FlagLoopback, FlagMulticast 36 } 37 38 type Flags uint 39 40 const ( 41 FlagUp Flags = 1 << iota // interface is up 42 FlagBroadcast // interface supports broadcast access capability 43 FlagLoopback // interface is a loopback interface 44 FlagPointToPoint // interface belongs to a point-to-point link 45 FlagMulticast // interface supports multicast access capability 46 ) 47 48 var flagNames = []string{ 49 "up", 50 "broadcast", 51 "loopback", 52 "pointtopoint", 53 "multicast", 54 } 55 56 func (f Flags) String() string { 57 s := "" 58 for i, name := range flagNames { 59 if f&(1<<uint(i)) != 0 { 60 if s != "" { 61 s += "|" 62 } 63 s += name 64 } 65 } 66 if s == "" { 67 s = "0" 68 } 69 return s 70 } 71 72 // Addrs returns a list of unicast interface addresses for a specific 73 // interface. 74 func (ifi *Interface) Addrs() ([]Addr, error) { 75 if ifi == nil { 76 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface} 77 } 78 ifat, err := interfaceAddrTable(ifi) 79 if err != nil { 80 err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} 81 } 82 return ifat, err 83 } 84 85 // MulticastAddrs returns a list of multicast, joined group addresses 86 // for a specific interface. 87 func (ifi *Interface) MulticastAddrs() ([]Addr, error) { 88 if ifi == nil { 89 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface} 90 } 91 ifat, err := interfaceMulticastAddrTable(ifi) 92 if err != nil { 93 err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} 94 } 95 return ifat, err 96 } 97 98 // Interfaces returns a list of the system's network interfaces. 99 func Interfaces() ([]Interface, error) { 100 ift, err := interfaceTable(0) 101 if err != nil { 102 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} 103 } 104 if len(ift) != 0 { 105 zoneCache.update(ift, false) 106 } 107 return ift, nil 108 } 109 110 // InterfaceAddrs returns a list of the system's unicast interface 111 // addresses. 112 // 113 // The returned list does not identify the associated interface; use 114 // Interfaces and Interface.Addrs for more detail. 115 func InterfaceAddrs() ([]Addr, error) { 116 ifat, err := interfaceAddrTable(nil) 117 if err != nil { 118 err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} 119 } 120 return ifat, err 121 } 122 123 // InterfaceByIndex returns the interface specified by index. 124 // 125 // On Solaris, it returns one of the logical network interfaces 126 // sharing the logical data link; for more precision use 127 // InterfaceByName. 128 func InterfaceByIndex(index int) (*Interface, error) { 129 if index <= 0 { 130 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceIndex} 131 } 132 ift, err := interfaceTable(index) 133 if err != nil { 134 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} 135 } 136 ifi, err := interfaceByIndex(ift, index) 137 if err != nil { 138 err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} 139 } 140 return ifi, err 141 } 142 143 func interfaceByIndex(ift []Interface, index int) (*Interface, error) { 144 for _, ifi := range ift { 145 if index == ifi.Index { 146 return &ifi, nil 147 } 148 } 149 return nil, errNoSuchInterface 150 } 151 152 // InterfaceByName returns the interface specified by name. 153 func InterfaceByName(name string) (*Interface, error) { 154 if name == "" { 155 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceName} 156 } 157 ift, err := interfaceTable(0) 158 if err != nil { 159 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} 160 } 161 if len(ift) != 0 { 162 zoneCache.update(ift, false) 163 } 164 for _, ifi := range ift { 165 if name == ifi.Name { 166 return &ifi, nil 167 } 168 } 169 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface} 170 } 171 172 // An ipv6ZoneCache represents a cache holding partial network 173 // interface information. It is used for reducing the cost of IPv6 174 // addressing scope zone resolution. 175 // 176 // Multiple names sharing the index are managed by first-come 177 // first-served basis for consistency. 178 type ipv6ZoneCache struct { 179 sync.RWMutex // guard the following 180 lastFetched time.Time // last time routing information was fetched 181 toIndex map[string]int // interface name to its index 182 toName map[int]string // interface index to its name 183 } 184 185 var zoneCache = ipv6ZoneCache{ 186 toIndex: make(map[string]int), 187 toName: make(map[int]string), 188 } 189 190 // update refreshes the network interface information if the cache was last 191 // updated more than 1 minute ago, or if force is set. It reports whether the 192 // cache was updated. 193 func (zc *ipv6ZoneCache) update(ift []Interface, force bool) (updated bool) { 194 zc.Lock() 195 defer zc.Unlock() 196 now := time.Now() 197 if !force && zc.lastFetched.After(now.Add(-60*time.Second)) { 198 return false 199 } 200 zc.lastFetched = now 201 if len(ift) == 0 { 202 var err error 203 if ift, err = interfaceTable(0); err != nil { 204 return false 205 } 206 } 207 zc.toIndex = make(map[string]int, len(ift)) 208 zc.toName = make(map[int]string, len(ift)) 209 for _, ifi := range ift { 210 zc.toIndex[ifi.Name] = ifi.Index 211 if _, ok := zc.toName[ifi.Index]; !ok { 212 zc.toName[ifi.Index] = ifi.Name 213 } 214 } 215 return true 216 } 217 218 func (zc *ipv6ZoneCache) name(index int) string { 219 if index == 0 { 220 return "" 221 } 222 updated := zoneCache.update(nil, false) 223 zoneCache.RLock() 224 name, ok := zoneCache.toName[index] 225 zoneCache.RUnlock() 226 if !ok && !updated { 227 zoneCache.update(nil, true) 228 zoneCache.RLock() 229 name, ok = zoneCache.toName[index] 230 zoneCache.RUnlock() 231 } 232 if !ok { // last resort 233 name = uitoa(uint(index)) 234 } 235 return name 236 } 237 238 func (zc *ipv6ZoneCache) index(name string) int { 239 if name == "" { 240 return 0 241 } 242 updated := zoneCache.update(nil, false) 243 zoneCache.RLock() 244 index, ok := zoneCache.toIndex[name] 245 zoneCache.RUnlock() 246 if !ok && !updated { 247 zoneCache.update(nil, true) 248 zoneCache.RLock() 249 index, ok = zoneCache.toIndex[name] 250 zoneCache.RUnlock() 251 } 252 if !ok { // last resort 253 index, _, _ = dtoi(name) 254 } 255 return index 256 }