github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/net/interface_plan9.go (about) 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 }