Source file src/net/interface_plan9.go

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

View as plain text