Source file src/net/interface.go

     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  }
   260  

View as plain text