Home | History | Annotate | Download | only in route
      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