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 // +build darwin dragonfly freebsd netbsd openbsd 6 7 package route 8 9 import ( 10 "fmt" 11 "os/exec" 12 "runtime" 13 "time" 14 ) 15 16 func (m *RouteMessage) String() string { 17 return fmt.Sprintf("%s", addrAttrs(nativeEndian.Uint32(m.raw[12:16]))) 18 } 19 20 func (m *InterfaceMessage) String() string { 21 var attrs addrAttrs 22 if runtime.GOOS == "openbsd" { 23 attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16])) 24 } else { 25 attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8])) 26 } 27 return fmt.Sprintf("%s", attrs) 28 } 29 30 func (m *InterfaceAddrMessage) String() string { 31 var attrs addrAttrs 32 if runtime.GOOS == "openbsd" { 33 attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16])) 34 } else { 35 attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8])) 36 } 37 return fmt.Sprintf("%s", attrs) 38 } 39 40 func (m *InterfaceMulticastAddrMessage) String() string { 41 return fmt.Sprintf("%s", addrAttrs(nativeEndian.Uint32(m.raw[4:8]))) 42 } 43 44 func (m *InterfaceAnnounceMessage) String() string { 45 what := "<nil>" 46 switch m.What { 47 case 0: 48 what = "arrival" 49 case 1: 50 what = "departure" 51 } 52 return fmt.Sprintf("(%d %s %s)", m.Index, m.Name, what) 53 } 54 55 func (m *InterfaceMetrics) String() string { 56 return fmt.Sprintf("(type=%d mtu=%d)", m.Type, m.MTU) 57 } 58 59 func (m *RouteMetrics) String() string { 60 return fmt.Sprintf("(pmtu=%d)", m.PathMTU) 61 } 62 63 type addrAttrs uint 64 65 var addrAttrNames = [...]string{ 66 "dst", 67 "gateway", 68 "netmask", 69 "genmask", 70 "ifp", 71 "ifa", 72 "author", 73 "brd", 74 "df:mpls1-n:tag-o:src", // mpls1 for dragonfly, tag for netbsd, src for openbsd 75 "df:mpls2-o:srcmask", // mpls2 for dragonfly, srcmask for openbsd 76 "df:mpls3-o:label", // mpls3 for dragonfly, label for openbsd 77 } 78 79 func (attrs addrAttrs) String() string { 80 var s string 81 for i, name := range addrAttrNames { 82 if attrs&(1<<uint(i)) != 0 { 83 if s != "" { 84 s += "|" 85 } 86 s += name 87 } 88 } 89 if s == "" { 90 return "<nil>" 91 } 92 return s 93 } 94 95 type msgs []Message 96 97 func (ms msgs) validate() ([]string, error) { 98 var ss []string 99 for _, m := range ms { 100 switch m := m.(type) { 101 case *RouteMessage: 102 if err := addrs(m.Addrs).match(addrAttrs(nativeEndian.Uint32(m.raw[12:16]))); err != nil { 103 return nil, err 104 } 105 sys := m.Sys() 106 if sys == nil { 107 return nil, fmt.Errorf("no sys for %s", m.String()) 108 } 109 ss = append(ss, m.String()+" "+syss(sys).String()+" "+addrs(m.Addrs).String()) 110 case *InterfaceMessage: 111 var attrs addrAttrs 112 if runtime.GOOS == "openbsd" { 113 attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16])) 114 } else { 115 attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8])) 116 } 117 if err := addrs(m.Addrs).match(attrs); err != nil { 118 return nil, err 119 } 120 sys := m.Sys() 121 if sys == nil { 122 return nil, fmt.Errorf("no sys for %s", m.String()) 123 } 124 ss = append(ss, m.String()+" "+syss(sys).String()+" "+addrs(m.Addrs).String()) 125 case *InterfaceAddrMessage: 126 var attrs addrAttrs 127 if runtime.GOOS == "openbsd" { 128 attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16])) 129 } else { 130 attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8])) 131 } 132 if err := addrs(m.Addrs).match(attrs); err != nil { 133 return nil, err 134 } 135 ss = append(ss, m.String()+" "+addrs(m.Addrs).String()) 136 case *InterfaceMulticastAddrMessage: 137 if err := addrs(m.Addrs).match(addrAttrs(nativeEndian.Uint32(m.raw[4:8]))); err != nil { 138 return nil, err 139 } 140 ss = append(ss, m.String()+" "+addrs(m.Addrs).String()) 141 case *InterfaceAnnounceMessage: 142 ss = append(ss, m.String()) 143 default: 144 ss = append(ss, fmt.Sprintf("%+v", m)) 145 } 146 } 147 return ss, nil 148 } 149 150 type syss []Sys 151 152 func (sys syss) String() string { 153 var s string 154 for _, sy := range sys { 155 switch sy := sy.(type) { 156 case *InterfaceMetrics: 157 if len(s) > 0 { 158 s += " " 159 } 160 s += sy.String() 161 case *RouteMetrics: 162 if len(s) > 0 { 163 s += " " 164 } 165 s += sy.String() 166 } 167 } 168 return s 169 } 170 171 type addrFamily int 172 173 func (af addrFamily) String() string { 174 switch af { 175 case sysAF_UNSPEC: 176 return "unspec" 177 case sysAF_LINK: 178 return "link" 179 case sysAF_INET: 180 return "inet4" 181 case sysAF_INET6: 182 return "inet6" 183 default: 184 return fmt.Sprintf("%d", af) 185 } 186 } 187 188 const hexDigit = "0123456789abcdef" 189 190 type llAddr []byte 191 192 func (a llAddr) String() string { 193 if len(a) == 0 { 194 return "" 195 } 196 buf := make([]byte, 0, len(a)*3-1) 197 for i, b := range a { 198 if i > 0 { 199 buf = append(buf, ':') 200 } 201 buf = append(buf, hexDigit[b>>4]) 202 buf = append(buf, hexDigit[b&0xF]) 203 } 204 return string(buf) 205 } 206 207 type ipAddr []byte 208 209 func (a ipAddr) String() string { 210 if len(a) == 0 { 211 return "<nil>" 212 } 213 if len(a) == 4 { 214 return fmt.Sprintf("%d.%d.%d.%d", a[0], a[1], a[2], a[3]) 215 } 216 if len(a) == 16 { 217 return fmt.Sprintf("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]) 218 } 219 s := make([]byte, len(a)*2) 220 for i, tn := range a { 221 s[i*2], s[i*2+1] = hexDigit[tn>>4], hexDigit[tn&0xf] 222 } 223 return string(s) 224 } 225 226 func (a *LinkAddr) String() string { 227 name := a.Name 228 if name == "" { 229 name = "<nil>" 230 } 231 lla := llAddr(a.Addr).String() 232 if lla == "" { 233 lla = "<nil>" 234 } 235 return fmt.Sprintf("(%v %d %s %s)", addrFamily(a.Family()), a.Index, name, lla) 236 } 237 238 func (a *Inet4Addr) String() string { 239 return fmt.Sprintf("(%v %v)", addrFamily(a.Family()), ipAddr(a.IP[:])) 240 } 241 242 func (a *Inet6Addr) String() string { 243 return fmt.Sprintf("(%v %v %d)", addrFamily(a.Family()), ipAddr(a.IP[:]), a.ZoneID) 244 } 245 246 func (a *DefaultAddr) String() string { 247 return fmt.Sprintf("(%v %s)", addrFamily(a.Family()), ipAddr(a.Raw[2:]).String()) 248 } 249 250 type addrs []Addr 251 252 func (as addrs) String() string { 253 var s string 254 for _, a := range as { 255 if a == nil { 256 continue 257 } 258 if len(s) > 0 { 259 s += " " 260 } 261 switch a := a.(type) { 262 case *LinkAddr: 263 s += a.String() 264 case *Inet4Addr: 265 s += a.String() 266 case *Inet6Addr: 267 s += a.String() 268 case *DefaultAddr: 269 s += a.String() 270 } 271 } 272 if s == "" { 273 return "<nil>" 274 } 275 return s 276 } 277 278 func (as addrs) match(attrs addrAttrs) error { 279 var ts addrAttrs 280 af := sysAF_UNSPEC 281 for i := range as { 282 if as[i] != nil { 283 ts |= 1 << uint(i) 284 } 285 switch as[i].(type) { 286 case *Inet4Addr: 287 if af == sysAF_UNSPEC { 288 af = sysAF_INET 289 } 290 if af != sysAF_INET { 291 return fmt.Errorf("got %v; want %v", addrs(as), addrFamily(af)) 292 } 293 case *Inet6Addr: 294 if af == sysAF_UNSPEC { 295 af = sysAF_INET6 296 } 297 if af != sysAF_INET6 { 298 return fmt.Errorf("got %v; want %v", addrs(as), addrFamily(af)) 299 } 300 } 301 } 302 if ts != attrs && ts > attrs { 303 return fmt.Errorf("%v not included in %v", ts, attrs) 304 } 305 return nil 306 } 307 308 func fetchAndParseRIB(af int, typ RIBType) ([]Message, error) { 309 var err error 310 var b []byte 311 for i := 0; i < 3; i++ { 312 if b, err = FetchRIB(af, typ, 0); err != nil { 313 time.Sleep(10 * time.Millisecond) 314 continue 315 } 316 break 317 } 318 if err != nil { 319 return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err) 320 } 321 ms, err := ParseRIB(typ, b) 322 if err != nil { 323 return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err) 324 } 325 return ms, nil 326 } 327 328 // propVirtual is a proprietary virtual network interface. 329 type propVirtual struct { 330 name string 331 addr, mask string 332 setupCmds []*exec.Cmd 333 teardownCmds []*exec.Cmd 334 } 335 336 func (pv *propVirtual) setup() error { 337 for _, cmd := range pv.setupCmds { 338 if err := cmd.Run(); err != nil { 339 pv.teardown() 340 return err 341 } 342 } 343 return nil 344 } 345 346 func (pv *propVirtual) teardown() error { 347 for _, cmd := range pv.teardownCmds { 348 if err := cmd.Run(); err != nil { 349 return err 350 } 351 } 352 return nil 353 } 354 355 func (pv *propVirtual) configure(suffix int) error { 356 if runtime.GOOS == "openbsd" { 357 pv.name = fmt.Sprintf("vether%d", suffix) 358 } else { 359 pv.name = fmt.Sprintf("vlan%d", suffix) 360 } 361 xname, err := exec.LookPath("ifconfig") 362 if err != nil { 363 return err 364 } 365 pv.setupCmds = append(pv.setupCmds, &exec.Cmd{ 366 Path: xname, 367 Args: []string{"ifconfig", pv.name, "create"}, 368 }) 369 if runtime.GOOS == "netbsd" { 370 // NetBSD requires an underlying dot1Q-capable network 371 // interface. 372 pv.setupCmds = append(pv.setupCmds, &exec.Cmd{ 373 Path: xname, 374 Args: []string{"ifconfig", pv.name, "vlan", fmt.Sprintf("%d", suffix&0xfff), "vlanif", "wm0"}, 375 }) 376 } 377 pv.setupCmds = append(pv.setupCmds, &exec.Cmd{ 378 Path: xname, 379 Args: []string{"ifconfig", pv.name, "inet", pv.addr, "netmask", pv.mask}, 380 }) 381 pv.teardownCmds = append(pv.teardownCmds, &exec.Cmd{ 382 Path: xname, 383 Args: []string{"ifconfig", pv.name, "destroy"}, 384 }) 385 return nil 386 } 387