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 5package net 6 7import ( 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 19var ( 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. 30type 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 38type Flags uint 39 40const ( 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 48var flagNames = []string{ 49 "up", 50 "broadcast", 51 "loopback", 52 "pointtopoint", 53 "multicast", 54} 55 56func (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. 74func (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. 87func (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. 99func 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. 115func 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. 128func 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 143func 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. 153func 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. 178type 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 185var zoneCache = ipv6ZoneCache{ 186 toIndex: make(map[string]int), 187 toName: make(map[int]string), 188} 189 190func (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 214func (zc *ipv6ZoneCache) name(index int) string { 215 if index == 0 { 216 return "" 217 } 218 zoneCache.update(nil) 219 zoneCache.RLock() 220 defer zoneCache.RUnlock() 221 name, ok := zoneCache.toName[index] 222 if !ok { 223 name = uitoa(uint(index)) 224 } 225 return name 226} 227 228func (zc *ipv6ZoneCache) index(name string) int { 229 if name == "" { 230 return 0 231 } 232 zoneCache.update(nil) 233 zoneCache.RLock() 234 defer zoneCache.RUnlock() 235 index, ok := zoneCache.toIndex[name] 236 if !ok { 237 index, _, _ = dtoi(name) 238 } 239 return index 240} 241