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