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

View as plain text