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 } 226