github.com/huandu/go@v0.0.0-20151114150818-04e615e41150/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  type addrFamily byte
   123  
   124  func (f addrFamily) String() string {
   125  	switch f {
   126  	case syscall.AF_UNSPEC:
   127  		return "unspec"
   128  	case syscall.AF_LINK:
   129  		return "link"
   130  	case syscall.AF_INET:
   131  		return "inet4"
   132  	case syscall.AF_INET6:
   133  		return "inet6"
   134  	default:
   135  		return fmt.Sprintf("unknown %d", f)
   136  	}
   137  }
   138  
   139  type addrFlags uint32
   140  
   141  var addrFlagNames = [...]string{
   142  	"dst",
   143  	"gateway",
   144  	"netmask",
   145  	"genmask",
   146  	"ifp",
   147  	"ifa",
   148  	"author",
   149  	"brd",
   150  	"mpls1,tag,src", // sockaddr_mpls=dragonfly,netbsd, sockaddr_in/in6=openbsd
   151  	"mpls2,srcmask", // sockaddr_mpls=dragonfly, sockaddr_in/in6=openbsd
   152  	"mpls3,label",   // sockaddr_mpls=dragonfly, sockaddr_rtlabel=openbsd
   153  }
   154  
   155  func (f addrFlags) String() string {
   156  	var s string
   157  	for i, name := range addrFlagNames {
   158  		if f&(1<<uint(i)) != 0 {
   159  			if s != "" {
   160  				s += "|"
   161  			}
   162  			s += name
   163  		}
   164  	}
   165  	if s == "" {
   166  		return "<nil>"
   167  	}
   168  	return s
   169  }
   170  
   171  type sockaddrs []syscall.Sockaddr
   172  
   173  func (sas sockaddrs) String() string {
   174  	var s string
   175  	for _, sa := range sas {
   176  		if sa == nil {
   177  			continue
   178  		}
   179  		if len(s) > 0 {
   180  			s += " "
   181  		}
   182  		switch sa := sa.(type) {
   183  		case *syscall.SockaddrDatalink:
   184  			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)
   185  		case *syscall.SockaddrInet4:
   186  			s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To4())
   187  		case *syscall.SockaddrInet6:
   188  			s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To16())
   189  		}
   190  	}
   191  	if s == "" {
   192  		return "<nil>"
   193  	}
   194  	return s
   195  }
   196  
   197  func (sas sockaddrs) match(flags addrFlags) error {
   198  	var f addrFlags
   199  	family := syscall.AF_UNSPEC
   200  	for i := range sas {
   201  		if sas[i] != nil {
   202  			f |= 1 << uint(i)
   203  		}
   204  		switch sas[i].(type) {
   205  		case *syscall.SockaddrInet4:
   206  			if family == syscall.AF_UNSPEC {
   207  				family = syscall.AF_INET
   208  			}
   209  			if family != syscall.AF_INET {
   210  				return fmt.Errorf("got %v; want %v", sockaddrs(sas), family)
   211  			}
   212  		case *syscall.SockaddrInet6:
   213  			if family == syscall.AF_UNSPEC {
   214  				family = syscall.AF_INET6
   215  			}
   216  			if family != syscall.AF_INET6 {
   217  				return fmt.Errorf("got %v; want %v", sockaddrs(sas), family)
   218  			}
   219  		}
   220  	}
   221  	if f != flags {
   222  		return fmt.Errorf("got %v; want %v", f, flags)
   223  	}
   224  	return nil
   225  }