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 NaCl, methods and functions related to 14 // Interface are not implemented. 15 16 // BUG(mikio): On DragonFly BSD, NetBSD, OpenBSD, Plan 9 and Solaris, 17 // 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) 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) 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 func (zc *ipv6ZoneCache) update(ift []Interface) { 191 zc.Lock() 192 defer zc.Unlock() 193 now := time.Now() 194 if zc.lastFetched.After(now.Add(-60 * time.Second)) { 195 return 196 } 197 zc.lastFetched = now 198 if len(ift) == 0 { 199 var err error 200 if ift, err = interfaceTable(0); err != nil { 201 return 202 } 203 } 204 zc.toIndex = make(map[string]int, len(ift)) 205 zc.toName = make(map[int]string, len(ift)) 206 for _, ifi := range ift { 207 zc.toIndex[ifi.Name] = ifi.Index 208 if _, ok := zc.toName[ifi.Index]; !ok { 209 zc.toName[ifi.Index] = ifi.Name 210 } 211 } 212 } 213 214 func zoneToString(zone int) string { 215 if zone == 0 { 216 return "" 217 } 218 zoneCache.update(nil) 219 zoneCache.RLock() 220 defer zoneCache.RUnlock() 221 name, ok := zoneCache.toName[zone] 222 if !ok { 223 name = uitoa(uint(zone)) 224 } 225 return name 226 } 227 228 func zoneToInt(zone string) int { 229 if zone == "" { 230 return 0 231 } 232 zoneCache.update(nil) 233 zoneCache.RLock() 234 defer zoneCache.RUnlock() 235 index, ok := zoneCache.toIndex[zone] 236 if !ok { 237 index, _, _ = dtoi(zone) 238 } 239 return index 240 } 241