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