github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/src/net/interface_plan9.go (about)

     1  // Copyright 2016 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  	"os"
    10  )
    11  
    12  // If the ifindex is zero, interfaceTable returns mappings of all
    13  // network interfaces. Otherwise it returns a mapping of a specific
    14  // interface.
    15  func interfaceTable(ifindex int) ([]Interface, error) {
    16  	if ifindex == 0 {
    17  		n, err := interfaceCount()
    18  		if err != nil {
    19  			return nil, err
    20  		}
    21  		ifcs := make([]Interface, n)
    22  		for i := range ifcs {
    23  			ifc, err := readInterface(i)
    24  			if err != nil {
    25  				return nil, err
    26  			}
    27  			ifcs[i] = *ifc
    28  		}
    29  		return ifcs, nil
    30  	}
    31  
    32  	ifc, err := readInterface(ifindex - 1)
    33  	if err != nil {
    34  		return nil, err
    35  	}
    36  	return []Interface{*ifc}, nil
    37  }
    38  
    39  func readInterface(i int) (*Interface, error) {
    40  	ifc := &Interface{
    41  		Index: i + 1,                        // Offset the index by one to suit the contract
    42  		Name:  netdir + "/ipifc/" + itoa(i), // Name is the full path to the interface path in plan9
    43  	}
    44  
    45  	ifcstat := ifc.Name + "/status"
    46  	ifcstatf, err := open(ifcstat)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  	defer ifcstatf.close()
    51  
    52  	line, ok := ifcstatf.readLine()
    53  	if !ok {
    54  		return nil, errors.New("invalid interface status file: " + ifcstat)
    55  	}
    56  
    57  	fields := getFields(line)
    58  	if len(fields) < 4 {
    59  		return nil, errors.New("invalid interface status file: " + ifcstat)
    60  	}
    61  
    62  	device := fields[1]
    63  	mtustr := fields[3]
    64  
    65  	mtu, _, ok := dtoi(mtustr)
    66  	if !ok {
    67  		return nil, errors.New("invalid status file of interface: " + ifcstat)
    68  	}
    69  	ifc.MTU = mtu
    70  
    71  	// Not a loopback device
    72  	if device != "/dev/null" {
    73  		deviceaddrf, err := open(device + "/addr")
    74  		if err != nil {
    75  			return nil, err
    76  		}
    77  		defer deviceaddrf.close()
    78  
    79  		line, ok = deviceaddrf.readLine()
    80  		if !ok {
    81  			return nil, errors.New("invalid address file for interface: " + device + "/addr")
    82  		}
    83  
    84  		if len(line) > 0 && len(line)%2 == 0 {
    85  			ifc.HardwareAddr = make([]byte, len(line)/2)
    86  			var ok bool
    87  			for i := range ifc.HardwareAddr {
    88  				j := (i + 1) * 2
    89  				ifc.HardwareAddr[i], ok = xtoi2(line[i*2:j], 0)
    90  				if !ok {
    91  					ifc.HardwareAddr = ifc.HardwareAddr[:i]
    92  					break
    93  				}
    94  			}
    95  		}
    96  
    97  		ifc.Flags = FlagUp | FlagBroadcast | FlagMulticast
    98  	} else {
    99  		ifc.Flags = FlagUp | FlagMulticast | FlagLoopback
   100  	}
   101  
   102  	return ifc, nil
   103  }
   104  
   105  func interfaceCount() (int, error) {
   106  	d, err := os.Open(netdir + "/ipifc")
   107  	if err != nil {
   108  		return -1, err
   109  	}
   110  	defer d.Close()
   111  
   112  	names, err := d.Readdirnames(0)
   113  	if err != nil {
   114  		return -1, err
   115  	}
   116  
   117  	// Assumes that numbered files in ipifc are strictly
   118  	// the incrementing numbered directories for the
   119  	// interfaces
   120  	c := 0
   121  	for _, name := range names {
   122  		if _, _, ok := dtoi(name); !ok {
   123  			continue
   124  		}
   125  		c++
   126  	}
   127  
   128  	return c, nil
   129  }
   130  
   131  // If the ifi is nil, interfaceAddrTable returns addresses for all
   132  // network interfaces. Otherwise it returns addresses for a specific
   133  // interface.
   134  func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
   135  	var ifcs []Interface
   136  	if ifi == nil {
   137  		var err error
   138  		ifcs, err = interfaceTable(0)
   139  		if err != nil {
   140  			return nil, err
   141  		}
   142  	} else {
   143  		ifcs = []Interface{*ifi}
   144  	}
   145  
   146  	addrs := make([]Addr, len(ifcs))
   147  	for i, ifc := range ifcs {
   148  		status := ifc.Name + "/status"
   149  		statusf, err := open(status)
   150  		if err != nil {
   151  			return nil, err
   152  		}
   153  		defer statusf.close()
   154  
   155  		line, ok := statusf.readLine()
   156  		line, ok = statusf.readLine()
   157  		if !ok {
   158  			return nil, errors.New("cannot parse IP address for interface: " + status)
   159  		}
   160  
   161  		// This assumes only a single address for the interface.
   162  		fields := getFields(line)
   163  		if len(fields) < 1 {
   164  			return nil, errors.New("cannot parse IP address for interface: " + status)
   165  		}
   166  		addr := fields[0]
   167  		ip := ParseIP(addr)
   168  		if ip == nil {
   169  			return nil, errors.New("cannot parse IP address for interface: " + status)
   170  		}
   171  
   172  		// The mask is represented as CIDR relative to the IPv6 address.
   173  		// Plan 9 internal representation is always IPv6.
   174  		maskfld := fields[1]
   175  		maskfld = maskfld[1:]
   176  		pfxlen, _, ok := dtoi(maskfld)
   177  		if !ok {
   178  			return nil, errors.New("cannot parse network mask for interface: " + status)
   179  		}
   180  		var mask IPMask
   181  		if ip.To4() != nil { // IPv4 or IPv6 IPv4-mapped address
   182  			mask = CIDRMask(pfxlen-8*len(v4InV6Prefix), 8*IPv4len)
   183  		}
   184  		if ip.To16() != nil && ip.To4() == nil { // IPv6 address
   185  			mask = CIDRMask(pfxlen, 8*IPv6len)
   186  		}
   187  
   188  		addrs[i] = &IPNet{IP: ip, Mask: mask}
   189  	}
   190  
   191  	return addrs, nil
   192  }
   193  
   194  // interfaceMulticastAddrTable returns addresses for a specific
   195  // interface.
   196  func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
   197  	return nil, nil
   198  }