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