github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/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  var (
    14  	errInvalidInterface         = errors.New("invalid network interface")
    15  	errInvalidInterfaceIndex    = errors.New("invalid network interface index")
    16  	errInvalidInterfaceName     = errors.New("invalid network interface name")
    17  	errNoSuchInterface          = errors.New("no such network interface")
    18  	errNoSuchMulticastInterface = errors.New("no such multicast network interface")
    19  )
    20  
    21  // Interface represents a mapping between network interface name
    22  // and index. It also represents network interface facility
    23  // information.
    24  type Interface struct {
    25  	Index        int          // positive integer that starts at one, zero is never used
    26  	MTU          int          // maximum transmission unit
    27  	Name         string       // e.g., "en0", "lo0", "eth0.100"
    28  	HardwareAddr HardwareAddr // IEEE MAC-48, EUI-48 and EUI-64 form
    29  	Flags        Flags        // e.g., FlagUp, FlagLoopback, FlagMulticast
    30  }
    31  
    32  type Flags uint
    33  
    34  const (
    35  	FlagUp           Flags = 1 << iota // interface is up
    36  	FlagBroadcast                      // interface supports broadcast access capability
    37  	FlagLoopback                       // interface is a loopback interface
    38  	FlagPointToPoint                   // interface belongs to a point-to-point link
    39  	FlagMulticast                      // interface supports multicast access capability
    40  )
    41  
    42  var flagNames = []string{
    43  	"up",
    44  	"broadcast",
    45  	"loopback",
    46  	"pointtopoint",
    47  	"multicast",
    48  }
    49  
    50  func (f Flags) String() string {
    51  	s := ""
    52  	for i, name := range flagNames {
    53  		if f&(1<<uint(i)) != 0 {
    54  			if s != "" {
    55  				s += "|"
    56  			}
    57  			s += name
    58  		}
    59  	}
    60  	if s == "" {
    61  		s = "0"
    62  	}
    63  	return s
    64  }
    65  
    66  // Addrs returns interface addresses for a specific interface.
    67  func (ifi *Interface) Addrs() ([]Addr, error) {
    68  	if ifi == nil {
    69  		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
    70  	}
    71  	ifat, err := interfaceAddrTable(ifi)
    72  	if err != nil {
    73  		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
    74  	}
    75  	return ifat, err
    76  }
    77  
    78  // MulticastAddrs returns multicast, joined group addresses for
    79  // a specific interface.
    80  func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
    81  	if ifi == nil {
    82  		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
    83  	}
    84  	ifat, err := interfaceMulticastAddrTable(ifi)
    85  	if err != nil {
    86  		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
    87  	}
    88  	return ifat, err
    89  }
    90  
    91  // Interfaces returns a list of the system's network interfaces.
    92  func Interfaces() ([]Interface, error) {
    93  	ift, err := interfaceTable(0)
    94  	if err != nil {
    95  		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
    96  	}
    97  	if len(ift) != 0 {
    98  		zoneCache.update(ift)
    99  	}
   100  	return ift, nil
   101  }
   102  
   103  // InterfaceAddrs returns a list of the system's network interface
   104  // addresses.
   105  func InterfaceAddrs() ([]Addr, error) {
   106  	ifat, err := interfaceAddrTable(nil)
   107  	if err != nil {
   108  		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
   109  	}
   110  	return ifat, err
   111  }
   112  
   113  // InterfaceByIndex returns the interface specified by index.
   114  func InterfaceByIndex(index int) (*Interface, error) {
   115  	if index <= 0 {
   116  		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceIndex}
   117  	}
   118  	ift, err := interfaceTable(index)
   119  	if err != nil {
   120  		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
   121  	}
   122  	ifi, err := interfaceByIndex(ift, index)
   123  	if err != nil {
   124  		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
   125  	}
   126  	return ifi, err
   127  }
   128  
   129  func interfaceByIndex(ift []Interface, index int) (*Interface, error) {
   130  	for _, ifi := range ift {
   131  		if index == ifi.Index {
   132  			return &ifi, nil
   133  		}
   134  	}
   135  	return nil, errNoSuchInterface
   136  }
   137  
   138  // InterfaceByName returns the interface specified by name.
   139  func InterfaceByName(name string) (*Interface, error) {
   140  	if name == "" {
   141  		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceName}
   142  	}
   143  	ift, err := interfaceTable(0)
   144  	if err != nil {
   145  		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
   146  	}
   147  	if len(ift) != 0 {
   148  		zoneCache.update(ift)
   149  	}
   150  	for _, ifi := range ift {
   151  		if name == ifi.Name {
   152  			return &ifi, nil
   153  		}
   154  	}
   155  	return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface}
   156  }
   157  
   158  // An ipv6ZoneCache represents a cache holding partial network
   159  // interface information. It is used for reducing the cost of IPv6
   160  // addressing scope zone resolution.
   161  type ipv6ZoneCache struct {
   162  	sync.RWMutex                // guard the following
   163  	lastFetched  time.Time      // last time routing information was fetched
   164  	toIndex      map[string]int // interface name to its index
   165  	toName       map[int]string // interface index to its name
   166  }
   167  
   168  var zoneCache = ipv6ZoneCache{
   169  	toIndex: make(map[string]int),
   170  	toName:  make(map[int]string),
   171  }
   172  
   173  func (zc *ipv6ZoneCache) update(ift []Interface) {
   174  	zc.Lock()
   175  	defer zc.Unlock()
   176  	now := time.Now()
   177  	if zc.lastFetched.After(now.Add(-60 * time.Second)) {
   178  		return
   179  	}
   180  	zc.lastFetched = now
   181  	if len(ift) == 0 {
   182  		var err error
   183  		if ift, err = interfaceTable(0); err != nil {
   184  			return
   185  		}
   186  	}
   187  	zc.toIndex = make(map[string]int, len(ift))
   188  	zc.toName = make(map[int]string, len(ift))
   189  	for _, ifi := range ift {
   190  		zc.toIndex[ifi.Name] = ifi.Index
   191  		zc.toName[ifi.Index] = ifi.Name
   192  	}
   193  }
   194  
   195  func zoneToString(zone int) string {
   196  	if zone == 0 {
   197  		return ""
   198  	}
   199  	zoneCache.update(nil)
   200  	zoneCache.RLock()
   201  	defer zoneCache.RUnlock()
   202  	name, ok := zoneCache.toName[zone]
   203  	if !ok {
   204  		name = uitoa(uint(zone))
   205  	}
   206  	return name
   207  }
   208  
   209  func zoneToInt(zone string) int {
   210  	if zone == "" {
   211  		return 0
   212  	}
   213  	zoneCache.update(nil)
   214  	zoneCache.RLock()
   215  	defer zoneCache.RUnlock()
   216  	index, ok := zoneCache.toIndex[zone]
   217  	if !ok {
   218  		index, _, _ = dtoi(zone, 0)
   219  	}
   220  	return index
   221  }