github.com/s1s1ty/go@v0.0.0-20180207192209-104445e3140f/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  // 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 (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  
   228  func (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  }