8617663d43a4fdce03fead5d14d06907013ae8ae
[platform/upstream/gcc.git] / libgo / go / syscall / route_bsd_test.go
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 }