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.
13 // If the ifindex is zero, interfaceTable returns mappings of all
14 // network interfaces. Otherwise it returns a mapping of a specific
16 func interfaceTable(ifindex int) ([]Interface, error) {
18 n, err := interfaceCount()
22 ifcs := make([]Interface, n)
24 ifc, err := readInterface(i)
33 ifc, err := readInterface(ifindex - 1)
37 return []Interface{*ifc}, nil
40 func readInterface(i int) (*Interface, error) {
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
46 ifcstat := ifc.Name + "/status"
47 ifcstatf, err := open(ifcstat)
51 defer ifcstatf.close()
53 line, ok := ifcstatf.readLine()
55 return nil, errors.New("invalid interface status file: " + ifcstat)
58 fields := getFields(line)
60 return nil, errors.New("invalid interface status file: " + ifcstat)
66 mtu, _, ok := dtoi(mtustr)
68 return nil, errors.New("invalid status file of interface: " + ifcstat)
72 // Not a loopback device ("/dev/null") or packet interface (e.g. "pkt2")
73 if stringsHasPrefix(device, netdir+"/") {
74 deviceaddrf, err := open(device + "/addr")
78 defer deviceaddrf.close()
80 line, ok = deviceaddrf.readLine()
82 return nil, errors.New("invalid address file for interface: " + device + "/addr")
85 if len(line) > 0 && len(line)%2 == 0 {
86 ifc.HardwareAddr = make([]byte, len(line)/2)
88 for i := range ifc.HardwareAddr {
90 ifc.HardwareAddr[i], ok = xtoi2(line[i*2:j], 0)
92 ifc.HardwareAddr = ifc.HardwareAddr[:i]
98 ifc.Flags = FlagUp | FlagRunning | FlagBroadcast | FlagMulticast
100 ifc.Flags = FlagUp | FlagRunning | FlagMulticast | FlagLoopback
106 func interfaceCount() (int, error) {
107 d, err := os.Open(netdir + "/ipifc")
113 names, err := d.Readdirnames(0)
118 // Assumes that numbered files in ipifc are strictly
119 // the incrementing numbered directories for the
122 for _, name := range names {
123 if _, _, ok := dtoi(name); !ok {
132 // If the ifi is nil, interfaceAddrTable returns addresses for all
133 // network interfaces. Otherwise it returns addresses for a specific
135 func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
139 ifcs, err = interfaceTable(0)
144 ifcs = []Interface{*ifi}
148 for _, ifc := range ifcs {
149 status := ifc.Name + "/status"
150 statusf, err := open(status)
154 defer statusf.close()
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)
162 for line, ok := statusf.readLine(); ok; line, ok = statusf.readLine() {
163 fields := getFields(line)
165 return nil, errors.New("cannot parse IP address for interface: " + status)
170 return nil, errors.New("cannot parse IP address for interface: " + status)
173 // The mask is represented as CIDR relative to the IPv6 address.
174 // Plan 9 internal representation is always IPv6.
176 maskfld = maskfld[1:]
177 pfxlen, _, ok := dtoi(maskfld)
179 return nil, errors.New("cannot parse network mask for interface: " + status)
182 if ip.To4() != nil { // IPv4 or IPv6 IPv4-mapped address
183 mask = CIDRMask(pfxlen-8*len(v4InV6Prefix), 8*IPv4len)
185 if ip.To16() != nil && ip.To4() == nil { // IPv6 address
186 mask = CIDRMask(pfxlen, 8*IPv6len)
189 addrs = append(addrs, &IPNet{IP: ip, Mask: mask})
196 // interfaceMulticastAddrTable returns addresses for a specific
198 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {