blob: 4036a7f4750dc0e33b16f4eb18349388af5f8401 [file] [log] [blame]
Brad Fitzpatrick51947442016-03-01 22:57:46 +00001// Copyright 2011 The Go Authors. All rights reserved.
Mikio Hara518331d2011-06-03 14:35:42 -04002// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Mikio Hara518331d2011-06-03 14:35:42 -04005package net
6
Mikio Hara1d214f72016-04-13 06:19:53 +09007import (
8 "errors"
9 "sync"
10 "time"
11)
Mikio Hara518331d2011-06-03 14:35:42 -040012
Chris McGee6ca48f72016-09-28 21:29:08 -040013// BUG(mikio): On NaCl, methods and functions related to
Mikio Hara2f184c62016-09-27 19:54:05 +090014// Interface are not implemented.
Mikio Haraa7ed9ff2016-08-22 05:52:15 +090015
Mikio Hara8fc9c502016-10-12 19:41:29 +090016// BUG(mikio): On DragonFly BSD, NetBSD, OpenBSD, Plan 9 and Solaris,
17// the MulticastAddrs method of Interface is not implemented.
Mikio Haraa7ed9ff2016-08-22 05:52:15 +090018
Mikio Haracbdbdc42012-01-11 09:53:32 +090019var (
Mikio Hara3f5288c2014-04-08 06:14:19 +090020 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")
Mikio Haracbdbdc42012-01-11 09:53:32 +090025)
26
Mikio Hara518331d2011-06-03 14:35:42 -040027// Interface represents a mapping between network interface name
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +000028// and index. It also represents network interface facility
Mikio Hara518331d2011-06-03 14:35:42 -040029// 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
Mikio Harac4dfc552011-06-14 13:32:52 -040035 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
Mikio Hara518331d2011-06-03 14:35:42 -040070}
71
Mikio Hara79c03622016-10-18 19:43:04 +090072// Addrs returns a list of unicast interface addresses for a specific
73// interface.
Russ Coxeb692922011-11-01 22:05:34 -040074func (ifi *Interface) Addrs() ([]Addr, error) {
Mikio Hara518331d2011-06-03 14:35:42 -040075 if ifi == nil {
Mikio Haraafd2d2b2015-04-21 22:53:47 +090076 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
Mikio Hara518331d2011-06-03 14:35:42 -040077 }
Mikio Hara456cf0f2015-04-19 22:17:08 +090078 ifat, err := interfaceAddrTable(ifi)
79 if err != nil {
Mikio Haraafd2d2b2015-04-21 22:53:47 +090080 err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
Mikio Hara456cf0f2015-04-19 22:17:08 +090081 }
82 return ifat, err
Mikio Hara518331d2011-06-03 14:35:42 -040083}
84
Mikio Hara79c03622016-10-18 19:43:04 +090085// MulticastAddrs returns a list of multicast, joined group addresses
86// for a specific interface.
Russ Coxeb692922011-11-01 22:05:34 -040087func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
Mikio Hara946cb0e2011-08-04 00:22:52 -040088 if ifi == nil {
Mikio Haraafd2d2b2015-04-21 22:53:47 +090089 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
Mikio Hara946cb0e2011-08-04 00:22:52 -040090 }
Mikio Hara456cf0f2015-04-19 22:17:08 +090091 ifat, err := interfaceMulticastAddrTable(ifi)
92 if err != nil {
Mikio Haraafd2d2b2015-04-21 22:53:47 +090093 err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
Mikio Hara456cf0f2015-04-19 22:17:08 +090094 }
95 return ifat, err
Mikio Hara946cb0e2011-08-04 00:22:52 -040096}
97
Mikio Hara26fa1c82012-03-09 11:50:38 +090098// Interfaces returns a list of the system's network interfaces.
Russ Coxeb692922011-11-01 22:05:34 -040099func Interfaces() ([]Interface, error) {
Mikio Hara456cf0f2015-04-19 22:17:08 +0900100 ift, err := interfaceTable(0)
101 if err != nil {
Mikio Hara1d214f72016-04-13 06:19:53 +0900102 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
Mikio Hara456cf0f2015-04-19 22:17:08 +0900103 }
Mikio Hara1d214f72016-04-13 06:19:53 +0900104 if len(ift) != 0 {
105 zoneCache.update(ift)
106 }
107 return ift, nil
Mikio Hara518331d2011-06-03 14:35:42 -0400108}
109
Mikio Hara79c03622016-10-18 19:43:04 +0900110// InterfaceAddrs returns a list of the system's unicast interface
Mikio Hara518331d2011-06-03 14:35:42 -0400111// addresses.
Mikio Hara79c03622016-10-18 19:43:04 +0900112//
113// The returned list does not identify the associated interface; use
114// Interfaces and Interface.Addrs for more detail.
Russ Coxeb692922011-11-01 22:05:34 -0400115func InterfaceAddrs() ([]Addr, error) {
Mikio Hara456cf0f2015-04-19 22:17:08 +0900116 ifat, err := interfaceAddrTable(nil)
117 if err != nil {
Mikio Haraafd2d2b2015-04-21 22:53:47 +0900118 err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
Mikio Hara456cf0f2015-04-19 22:17:08 +0900119 }
120 return ifat, err
Mikio Hara518331d2011-06-03 14:35:42 -0400121}
122
123// InterfaceByIndex returns the interface specified by index.
Mikio Hara2f184c62016-09-27 19:54:05 +0900124//
125// On Solaris, it returns one of the logical network interfaces
126// sharing the logical data link; for more precision use
127// InterfaceByName.
Russ Coxeb692922011-11-01 22:05:34 -0400128func InterfaceByIndex(index int) (*Interface, error) {
Mikio Hara518331d2011-06-03 14:35:42 -0400129 if index <= 0 {
Mikio Haraafd2d2b2015-04-21 22:53:47 +0900130 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceIndex}
Mikio Hara518331d2011-06-03 14:35:42 -0400131 }
132 ift, err := interfaceTable(index)
133 if err != nil {
Mikio Haraafd2d2b2015-04-21 22:53:47 +0900134 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
Mikio Hara518331d2011-06-03 14:35:42 -0400135 }
Mikio Hara456cf0f2015-04-19 22:17:08 +0900136 ifi, err := interfaceByIndex(ift, index)
137 if err != nil {
Mikio Haraafd2d2b2015-04-21 22:53:47 +0900138 err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
Mikio Hara456cf0f2015-04-19 22:17:08 +0900139 }
140 return ifi, err
Mikio Hara322214c2013-02-28 14:58:41 +0900141}
142
143func interfaceByIndex(ift []Interface, index int) (*Interface, error) {
Mikio Hara518331d2011-06-03 14:35:42 -0400144 for _, ifi := range ift {
Mikio Hara322214c2013-02-28 14:58:41 +0900145 if index == ifi.Index {
146 return &ifi, nil
147 }
Mikio Hara518331d2011-06-03 14:35:42 -0400148 }
Mikio Haracbdbdc42012-01-11 09:53:32 +0900149 return nil, errNoSuchInterface
Mikio Hara518331d2011-06-03 14:35:42 -0400150}
151
152// InterfaceByName returns the interface specified by name.
Russ Coxeb692922011-11-01 22:05:34 -0400153func InterfaceByName(name string) (*Interface, error) {
Mikio Hara518331d2011-06-03 14:35:42 -0400154 if name == "" {
Mikio Haraafd2d2b2015-04-21 22:53:47 +0900155 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceName}
Mikio Hara518331d2011-06-03 14:35:42 -0400156 }
157 ift, err := interfaceTable(0)
158 if err != nil {
Mikio Haraafd2d2b2015-04-21 22:53:47 +0900159 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
Mikio Hara518331d2011-06-03 14:35:42 -0400160 }
Mikio Hara1d214f72016-04-13 06:19:53 +0900161 if len(ift) != 0 {
162 zoneCache.update(ift)
163 }
Mikio Hara518331d2011-06-03 14:35:42 -0400164 for _, ifi := range ift {
165 if name == ifi.Name {
166 return &ifi, nil
167 }
168 }
Mikio Haraafd2d2b2015-04-21 22:53:47 +0900169 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface}
Mikio Hara518331d2011-06-03 14:35:42 -0400170}
Mikio Hara1d214f72016-04-13 06:19:53 +0900171
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.
Mikio Hara86f2c5f2016-12-20 17:39:54 +0900175//
176// Multiple names sharing the index are managed by first-come
177// first-served basis for consistency.
Mikio Hara1d214f72016-04-13 06:19:53 +0900178type 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
Mikio Hara86f2c5f2016-12-20 17:39:54 +0900208 if _, ok := zc.toName[ifi.Index]; !ok {
209 zc.toName[ifi.Index] = ifi.Name
210 }
Mikio Hara1d214f72016-04-13 06:19:53 +0900211 }
212}
213
Mikio Harabf4cd982017-04-27 19:00:09 +0900214func (zc *ipv6ZoneCache) name(index int) string {
215 if index == 0 {
Mikio Hara1d214f72016-04-13 06:19:53 +0900216 return ""
217 }
218 zoneCache.update(nil)
219 zoneCache.RLock()
220 defer zoneCache.RUnlock()
Mikio Harabf4cd982017-04-27 19:00:09 +0900221 name, ok := zoneCache.toName[index]
Mikio Hara1d214f72016-04-13 06:19:53 +0900222 if !ok {
Mikio Harabf4cd982017-04-27 19:00:09 +0900223 name = uitoa(uint(index))
Mikio Hara1d214f72016-04-13 06:19:53 +0900224 }
225 return name
226}
227
Mikio Harabf4cd982017-04-27 19:00:09 +0900228func (zc *ipv6ZoneCache) index(name string) int {
229 if name == "" {
Mikio Hara1d214f72016-04-13 06:19:53 +0900230 return 0
231 }
232 zoneCache.update(nil)
233 zoneCache.RLock()
234 defer zoneCache.RUnlock()
Mikio Harabf4cd982017-04-27 19:00:09 +0900235 index, ok := zoneCache.toIndex[name]
Mikio Hara1d214f72016-04-13 06:19:53 +0900236 if !ok {
Mikio Harabf4cd982017-04-27 19:00:09 +0900237 index, _, _ = dtoi(name)
Mikio Hara1d214f72016-04-13 06:19:53 +0900238 }
239 return index
240}