mirror of
https://github.com/autc04/Retro68.git
synced 2024-09-08 20:55:01 +00:00
261 lines
5.7 KiB
Go
261 lines
5.7 KiB
Go
// Copyright 2015 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// +build darwin dragonfly freebsd netbsd openbsd
|
|
|
|
package syscall_test
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"syscall"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestRouteRIB(t *testing.T) {
|
|
for _, facility := range []int{syscall.NET_RT_DUMP, syscall.NET_RT_IFLIST} {
|
|
for _, param := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} {
|
|
var err error
|
|
var b []byte
|
|
// The VM allocator wrapper functions can
|
|
// return ENOMEM easily.
|
|
for i := 0; i < 3; i++ {
|
|
b, err = syscall.RouteRIB(facility, param)
|
|
if err != nil {
|
|
time.Sleep(5 * time.Millisecond)
|
|
continue
|
|
}
|
|
break
|
|
}
|
|
if err != nil {
|
|
t.Error(facility, param, err)
|
|
continue
|
|
}
|
|
msgs, err := syscall.ParseRoutingMessage(b)
|
|
if err != nil {
|
|
t.Error(facility, param, err)
|
|
continue
|
|
}
|
|
var ipv4loopback, ipv6loopback bool
|
|
for _, m := range msgs {
|
|
flags, err := parseRoutingMessageHeader(m)
|
|
if err != nil {
|
|
t.Error(err)
|
|
continue
|
|
}
|
|
sas, err := parseRoutingSockaddrs(m)
|
|
if err != nil {
|
|
t.Error(err)
|
|
continue
|
|
}
|
|
if flags&(syscall.RTA_DST|syscall.RTA_IFA) != 0 {
|
|
sa := sas[syscall.RTAX_DST]
|
|
if sa == nil {
|
|
sa = sas[syscall.RTAX_IFA]
|
|
}
|
|
switch sa := sa.(type) {
|
|
case *syscall.SockaddrInet4:
|
|
if net.IP(sa.Addr[:]).IsLoopback() {
|
|
ipv4loopback = true
|
|
}
|
|
case *syscall.SockaddrInet6:
|
|
if net.IP(sa.Addr[:]).IsLoopback() {
|
|
ipv6loopback = true
|
|
}
|
|
}
|
|
}
|
|
t.Log(facility, param, flags, sockaddrs(sas))
|
|
}
|
|
if param == syscall.AF_UNSPEC && len(msgs) > 0 && !ipv4loopback && !ipv6loopback {
|
|
t.Errorf("no loopback facility found: ipv4/ipv6=%v/%v, %v", ipv4loopback, ipv6loopback, len(msgs))
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRouteMonitor(t *testing.T) {
|
|
if testing.Short() || os.Getuid() != 0 {
|
|
t.Skip("must be root")
|
|
}
|
|
|
|
s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer syscall.Close(s)
|
|
|
|
tmo := time.After(30 * time.Second)
|
|
go func() {
|
|
b := make([]byte, os.Getpagesize())
|
|
for {
|
|
n, err := syscall.Read(s, b)
|
|
if err != nil {
|
|
return
|
|
}
|
|
msgs, err := syscall.ParseRoutingMessage(b[:n])
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
for _, m := range msgs {
|
|
flags, err := parseRoutingMessageHeader(m)
|
|
if err != nil {
|
|
t.Error(err)
|
|
continue
|
|
}
|
|
sas, err := parseRoutingSockaddrs(m)
|
|
if err != nil {
|
|
t.Error(err)
|
|
continue
|
|
}
|
|
t.Log(flags, sockaddrs(sas))
|
|
}
|
|
}
|
|
}()
|
|
<-tmo
|
|
}
|
|
|
|
var parseInterfaceMessageTests = []*syscall.InterfaceMessage{
|
|
// with link-layer address
|
|
{
|
|
Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
|
|
Data: []uint8{
|
|
0x11, 0x12, 0x2, 0x0, 0x6, 0x3, 0x6, 0x0,
|
|
0x77, 0x6d, 0x31, 0x01, 0x23, 0x45, 0xab, 0xcd,
|
|
0xef, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
},
|
|
},
|
|
// without link-layer address
|
|
{
|
|
Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
|
|
Data: []uint8{
|
|
0xe, 0x12, 0x4, 0x0, 0xf5, 0x6, 0x0, 0x0,
|
|
0x70, 0x66, 0x6c, 0x6f, 0x67, 0x30, 0x0, 0x0,
|
|
},
|
|
},
|
|
// no data
|
|
{
|
|
Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
|
|
Data: []uint8{
|
|
0x8, 0xa, 0xb, 0xc, 0xd, 0x0, 0x0, 0x0,
|
|
},
|
|
},
|
|
}
|
|
|
|
func TestParseInterfaceMessage(t *testing.T) {
|
|
for i, tt := range parseInterfaceMessageTests {
|
|
if _, err := syscall.ParseRoutingSockaddr(tt); err != nil {
|
|
t.Errorf("#%d: %v", i, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
type addrFamily byte
|
|
|
|
func (f addrFamily) String() string {
|
|
switch f {
|
|
case syscall.AF_UNSPEC:
|
|
return "unspec"
|
|
case syscall.AF_LINK:
|
|
return "link"
|
|
case syscall.AF_INET:
|
|
return "inet4"
|
|
case syscall.AF_INET6:
|
|
return "inet6"
|
|
default:
|
|
return fmt.Sprintf("unknown %d", f)
|
|
}
|
|
}
|
|
|
|
type addrFlags uint32
|
|
|
|
var addrFlagNames = [...]string{
|
|
"dst",
|
|
"gateway",
|
|
"netmask",
|
|
"genmask",
|
|
"ifp",
|
|
"ifa",
|
|
"author",
|
|
"brd",
|
|
"mpls1,tag,src", // sockaddr_mpls=dragonfly,netbsd, sockaddr_in/in6=openbsd
|
|
"mpls2,srcmask", // sockaddr_mpls=dragonfly, sockaddr_in/in6=openbsd
|
|
"mpls3,label", // sockaddr_mpls=dragonfly, sockaddr_rtlabel=openbsd
|
|
}
|
|
|
|
func (f addrFlags) String() string {
|
|
var s string
|
|
for i, name := range addrFlagNames {
|
|
if f&(1<<uint(i)) != 0 {
|
|
if s != "" {
|
|
s += "|"
|
|
}
|
|
s += name
|
|
}
|
|
}
|
|
if s == "" {
|
|
return "<nil>"
|
|
}
|
|
return s
|
|
}
|
|
|
|
type sockaddrs []syscall.Sockaddr
|
|
|
|
func (sas sockaddrs) String() string {
|
|
var s string
|
|
for _, sa := range sas {
|
|
if sa == nil {
|
|
continue
|
|
}
|
|
if len(s) > 0 {
|
|
s += " "
|
|
}
|
|
switch sa := sa.(type) {
|
|
case *syscall.SockaddrDatalink:
|
|
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)
|
|
case *syscall.SockaddrInet4:
|
|
s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To4())
|
|
case *syscall.SockaddrInet6:
|
|
s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To16())
|
|
}
|
|
}
|
|
if s == "" {
|
|
return "<nil>"
|
|
}
|
|
return s
|
|
}
|
|
|
|
func (sas sockaddrs) match(flags addrFlags) error {
|
|
var f addrFlags
|
|
family := syscall.AF_UNSPEC
|
|
for i := range sas {
|
|
if sas[i] != nil {
|
|
f |= 1 << uint(i)
|
|
}
|
|
switch sas[i].(type) {
|
|
case *syscall.SockaddrInet4:
|
|
if family == syscall.AF_UNSPEC {
|
|
family = syscall.AF_INET
|
|
}
|
|
if family != syscall.AF_INET {
|
|
return fmt.Errorf("got %v; want %v", sockaddrs(sas), family)
|
|
}
|
|
case *syscall.SockaddrInet6:
|
|
if family == syscall.AF_UNSPEC {
|
|
family = syscall.AF_INET6
|
|
}
|
|
if family != syscall.AF_INET6 {
|
|
return fmt.Errorf("got %v; want %v", sockaddrs(sas), family)
|
|
}
|
|
}
|
|
}
|
|
if f != flags {
|
|
return fmt.Errorf("got %v; want %v", f, flags)
|
|
}
|
|
return nil
|
|
}
|