...

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		"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			// Read but ignore first line as it only contains the table header.
   156			// See https://9p.io/magic/man2html/3/ip
   157			if _, ok := statusf.readLine(); !ok {
   158				return nil, errors.New("cannot read header line for interface: " + status)
   159			}
   160			line, ok := statusf.readLine()
   161			if !ok {
   162				return nil, errors.New("cannot read IP address for interface: " + status)
   163			}
   164	
   165			// This assumes only a single address for the interface.
   166			fields := getFields(line)
   167			if len(fields) < 1 {
   168				return nil, errors.New("cannot parse IP address for interface: " + status)
   169			}
   170			addr := fields[0]
   171			ip := ParseIP(addr)
   172			if ip == nil {
   173				return nil, errors.New("cannot parse IP address for interface: " + status)
   174			}
   175	
   176			// The mask is represented as CIDR relative to the IPv6 address.
   177			// Plan 9 internal representation is always IPv6.
   178			maskfld := fields[1]
   179			maskfld = maskfld[1:]
   180			pfxlen, _, ok := dtoi(maskfld)
   181			if !ok {
   182				return nil, errors.New("cannot parse network mask for interface: " + status)
   183			}
   184			var mask IPMask
   185			if ip.To4() != nil { // IPv4 or IPv6 IPv4-mapped address
   186				mask = CIDRMask(pfxlen-8*len(v4InV6Prefix), 8*IPv4len)
   187			}
   188			if ip.To16() != nil && ip.To4() == nil { // IPv6 address
   189				mask = CIDRMask(pfxlen, 8*IPv6len)
   190			}
   191	
   192			addrs[i] = &IPNet{IP: ip, Mask: mask}
   193		}
   194	
   195		return addrs, nil
   196	}
   197	
   198	// interfaceMulticastAddrTable returns addresses for a specific
   199	// interface.
   200	func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
   201		return nil, nil
   202	}
   203	

View as plain text