Home | History | Annotate | Download | only in net
      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 }
    199