github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/src/syscall/route_bsd_test.go (about)

     1  // Copyright 2015 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 syscall_test
     8  
     9  import (
    10  	"fmt"
    11  	"net"
    12  	"os"
    13  	"syscall"
    14  	"testing"
    15  	"time"
    16  )
    17  
    18  func TestRouteRIB(t *testing.T) {
    19  	for _, facility := range []int{syscall.NET_RT_DUMP, syscall.NET_RT_IFLIST} {
    20  		for _, param := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} {
    21  			var err error
    22  			var b []byte
    23  			// The VM allocator wrapper functions can
    24  			// return ENOMEM easily.
    25  			for i := 0; i < 3; i++ {
    26  				b, err = syscall.RouteRIB(facility, param)
    27  				if err != nil {
    28  					time.Sleep(5 * time.Millisecond)
    29  					continue
    30  				}
    31  				break
    32  			}
    33  			if err != nil {
    34  				t.Error(facility, param, err)
    35  				continue
    36  			}
    37  			msgs, err := syscall.ParseRoutingMessage(b)
    38  			if err != nil {
    39  				t.Error(facility, param, err)
    40  				continue
    41  			}
    42  			var ipv4loopback, ipv6loopback bool
    43  			for _, m := range msgs {
    44  				flags, err := parseRoutingMessageHeader(m)
    45  				if err != nil {
    46  					t.Error(err)
    47  					continue
    48  				}
    49  				sas, err := parseRoutingSockaddrs(m)
    50  				if err != nil {
    51  					t.Error(err)
    52  					continue
    53  				}
    54  				if flags&(syscall.RTA_DST|syscall.RTA_IFA) != 0 {
    55  					sa := sas[syscall.RTAX_DST]
    56  					if sa == nil {
    57  						sa = sas[syscall.RTAX_IFA]
    58  					}
    59  					switch sa := sa.(type) {
    60  					case *syscall.SockaddrInet4:
    61  						if net.IP(sa.Addr[:]).IsLoopback() {
    62  							ipv4loopback = true
    63  						}
    64  					case *syscall.SockaddrInet6:
    65  						if net.IP(sa.Addr[:]).IsLoopback() {
    66  							ipv6loopback = true
    67  						}
    68  					}
    69  				}
    70  				t.Log(facility, param, flags, sockaddrs(sas))
    71  			}
    72  			if param == syscall.AF_UNSPEC && len(msgs) > 0 && !ipv4loopback && !ipv6loopback {
    73  				t.Errorf("no loopback facility found: ipv4/ipv6=%v/%v, %v", ipv4loopback, ipv6loopback, len(msgs))
    74  				continue
    75  			}
    76  		}
    77  	}
    78  }
    79  
    80  func TestRouteMonitor(t *testing.T) {
    81  	if testing.Short() || os.Getuid() != 0 {
    82  		t.Skip("must be root")
    83  	}
    84  
    85  	s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
    86  	if err != nil {
    87  		t.Fatal(err)
    88  	}
    89  	defer syscall.Close(s)
    90  
    91  	tmo := time.After(30 * time.Second)
    92  	go func() {
    93  		b := make([]byte, os.Getpagesize())
    94  		for {
    95  			n, err := syscall.Read(s, b)
    96  			if err != nil {
    97  				return
    98  			}
    99  			msgs, err := syscall.ParseRoutingMessage(b[:n])
   100  			if err != nil {
   101  				t.Error(err)
   102  				return
   103  			}
   104  			for _, m := range msgs {
   105  				flags, err := parseRoutingMessageHeader(m)
   106  				if err != nil {
   107  					t.Error(err)
   108  					continue
   109  				}
   110  				sas, err := parseRoutingSockaddrs(m)
   111  				if err != nil {
   112  					t.Error(err)
   113  					continue
   114  				}
   115  				t.Log(flags, sockaddrs(sas))
   116  			}
   117  		}
   118  	}()
   119  	<-tmo
   120  }
   121  
   122  var parseInterfaceMessageTests = []*syscall.InterfaceMessage{
   123  	// with link-layer address
   124  	{
   125  		Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
   126  		Data: []uint8{
   127  			0x11, 0x12, 0x2, 0x0, 0x6, 0x3, 0x6, 0x0,
   128  			0x77, 0x6d, 0x31, 0x01, 0x23, 0x45, 0xab, 0xcd,
   129  			0xef, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
   130  		},
   131  	},
   132  	// without link-layer address
   133  	{
   134  		Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
   135  		Data: []uint8{
   136  			0xe, 0x12, 0x4, 0x0, 0xf5, 0x6, 0x0, 0x0,
   137  			0x70, 0x66, 0x6c, 0x6f, 0x67, 0x30, 0x0, 0x0,
   138  		},
   139  	},
   140  	// no data
   141  	{
   142  		Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
   143  		Data: []uint8{
   144  			0x8, 0xa, 0xb, 0xc, 0xd, 0x0, 0x0, 0x0,
   145  		},
   146  	},
   147  }
   148  
   149  func TestParseInterfaceMessage(t *testing.T) {
   150  	for i, tt := range parseInterfaceMessageTests {
   151  		if _, err := syscall.ParseRoutingSockaddr(tt); err != nil {
   152  			t.Errorf("#%d: %v", i, err)
   153  		}
   154  	}
   155  }
   156  
   157  type addrFamily byte
   158  
   159  func (f addrFamily) String() string {
   160  	switch f {
   161  	case syscall.AF_UNSPEC:
   162  		return "unspec"
   163  	case syscall.AF_LINK:
   164  		return "link"
   165  	case syscall.AF_INET:
   166  		return "inet4"
   167  	case syscall.AF_INET6:
   168  		return "inet6"
   169  	default:
   170  		return fmt.Sprintf("unknown %d", f)
   171  	}
   172  }
   173  
   174  type addrFlags uint32
   175  
   176  var addrFlagNames = [...]string{
   177  	"dst",
   178  	"gateway",
   179  	"netmask",
   180  	"genmask",
   181  	"ifp",
   182  	"ifa",
   183  	"author",
   184  	"brd",
   185  	"mpls1,tag,src", // sockaddr_mpls=dragonfly,netbsd, sockaddr_in/in6=openbsd
   186  	"mpls2,srcmask", // sockaddr_mpls=dragonfly, sockaddr_in/in6=openbsd
   187  	"mpls3,label",   // sockaddr_mpls=dragonfly, sockaddr_rtlabel=openbsd
   188  }
   189  
   190  func (f addrFlags) String() string {
   191  	var s string
   192  	for i, name := range addrFlagNames {
   193  		if f&(1<<uint(i)) != 0 {
   194  			if s != "" {
   195  				s += "|"
   196  			}
   197  			s += name
   198  		}
   199  	}
   200  	if s == "" {
   201  		return "<nil>"
   202  	}
   203  	return s
   204  }
   205  
   206  type sockaddrs []syscall.Sockaddr
   207  
   208  func (sas sockaddrs) String() string {
   209  	var s string
   210  	for _, sa := range sas {
   211  		if sa == nil {
   212  			continue
   213  		}
   214  		if len(s) > 0 {
   215  			s += " "
   216  		}
   217  		switch sa := sa.(type) {
   218  		case *syscall.SockaddrDatalink:
   219  			s += fmt.Sprintf("[%v/%v/%v t/n/a/s=%v/%v/%v/%v]", sa.Len, addrFamily(sa.Family), sa.Index, sa.Type, sa.Nlen, sa.Alen, sa.Slen)
   220  		case *syscall.SockaddrInet4:
   221  			s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To4())
   222  		case *syscall.SockaddrInet6:
   223  			s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To16())
   224  		}
   225  	}
   226  	if s == "" {
   227  		return "<nil>"
   228  	}
   229  	return s
   230  }
   231  
   232  func (sas sockaddrs) match(flags addrFlags) error {
   233  	var f addrFlags
   234  	family := syscall.AF_UNSPEC
   235  	for i := range sas {
   236  		if sas[i] != nil {
   237  			f |= 1 << uint(i)
   238  		}
   239  		switch sas[i].(type) {
   240  		case *syscall.SockaddrInet4:
   241  			if family == syscall.AF_UNSPEC {
   242  				family = syscall.AF_INET
   243  			}
   244  			if family != syscall.AF_INET {
   245  				return fmt.Errorf("got %v; want %v", sockaddrs(sas), family)
   246  			}
   247  		case *syscall.SockaddrInet6:
   248  			if family == syscall.AF_UNSPEC {
   249  				family = syscall.AF_INET6
   250  			}
   251  			if family != syscall.AF_INET6 {
   252  				return fmt.Errorf("got %v; want %v", sockaddrs(sas), family)
   253  			}
   254  		}
   255  	}
   256  	if f != flags {
   257  		return fmt.Errorf("got %v; want %v", f, flags)
   258  	}
   259  	return nil
   260  }