1
2
3
4
5
6
7 package route
8
9 import (
10 "fmt"
11 "os/exec"
12 "runtime"
13 "syscall"
14 )
15
16 func (m *RouteMessage) String() string {
17 return fmt.Sprintf("%s", addrAttrs(nativeEndian.Uint32(m.raw[12:16])))
18 }
19
20 func (m *InterfaceMessage) String() string {
21 var attrs addrAttrs
22 if runtime.GOOS == "openbsd" {
23 attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16]))
24 } else {
25 attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8]))
26 }
27 return fmt.Sprintf("%s", attrs)
28 }
29
30 func (m *InterfaceAddrMessage) String() string {
31 var attrs addrAttrs
32 if runtime.GOOS == "openbsd" {
33 attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16]))
34 } else {
35 attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8]))
36 }
37 return fmt.Sprintf("%s", attrs)
38 }
39
40 func (m *InterfaceMulticastAddrMessage) String() string {
41 return fmt.Sprintf("%s", addrAttrs(nativeEndian.Uint32(m.raw[4:8])))
42 }
43
44 func (m *InterfaceAnnounceMessage) String() string {
45 what := "<nil>"
46 switch m.What {
47 case 0:
48 what = "arrival"
49 case 1:
50 what = "departure"
51 }
52 return fmt.Sprintf("(%d %s %s)", m.Index, m.Name, what)
53 }
54
55 func (m *InterfaceMetrics) String() string {
56 return fmt.Sprintf("(type=%d mtu=%d)", m.Type, m.MTU)
57 }
58
59 func (m *RouteMetrics) String() string {
60 return fmt.Sprintf("(pmtu=%d)", m.PathMTU)
61 }
62
63 type addrAttrs uint
64
65 var addrAttrNames = [...]string{
66 "dst",
67 "gateway",
68 "netmask",
69 "genmask",
70 "ifp",
71 "ifa",
72 "author",
73 "brd",
74 "df:mpls1-n:tag-o:src",
75 "df:mpls2-o:srcmask",
76 "df:mpls3-o:label",
77 "o:bfd",
78 "o:dns",
79 "o:static",
80 "o:search",
81 }
82
83 func (attrs addrAttrs) String() string {
84 var s string
85 for i, name := range addrAttrNames {
86 if attrs&(1<<uint(i)) != 0 {
87 if s != "" {
88 s += "|"
89 }
90 s += name
91 }
92 }
93 if s == "" {
94 return "<nil>"
95 }
96 return s
97 }
98
99 type msgs []Message
100
101 func (ms msgs) validate() ([]string, error) {
102 var ss []string
103 for _, m := range ms {
104 switch m := m.(type) {
105 case *RouteMessage:
106 if err := addrs(m.Addrs).match(addrAttrs(nativeEndian.Uint32(m.raw[12:16]))); err != nil {
107 return nil, err
108 }
109 sys := m.Sys()
110 if sys == nil {
111 return nil, fmt.Errorf("no sys for %s", m.String())
112 }
113 ss = append(ss, m.String()+" "+syss(sys).String()+" "+addrs(m.Addrs).String())
114 case *InterfaceMessage:
115 var attrs addrAttrs
116 if runtime.GOOS == "openbsd" {
117 attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16]))
118 } else {
119 attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8]))
120 }
121 if err := addrs(m.Addrs).match(attrs); err != nil {
122 return nil, err
123 }
124 sys := m.Sys()
125 if sys == nil {
126 return nil, fmt.Errorf("no sys for %s", m.String())
127 }
128 ss = append(ss, m.String()+" "+syss(sys).String()+" "+addrs(m.Addrs).String())
129 case *InterfaceAddrMessage:
130 var attrs addrAttrs
131 if runtime.GOOS == "openbsd" {
132 attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16]))
133 } else {
134 attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8]))
135 }
136 if err := addrs(m.Addrs).match(attrs); err != nil {
137 return nil, err
138 }
139 ss = append(ss, m.String()+" "+addrs(m.Addrs).String())
140 case *InterfaceMulticastAddrMessage:
141 if err := addrs(m.Addrs).match(addrAttrs(nativeEndian.Uint32(m.raw[4:8]))); err != nil {
142 return nil, err
143 }
144 ss = append(ss, m.String()+" "+addrs(m.Addrs).String())
145 case *InterfaceAnnounceMessage:
146 ss = append(ss, m.String())
147 default:
148 ss = append(ss, fmt.Sprintf("%+v", m))
149 }
150 }
151 return ss, nil
152 }
153
154 type syss []Sys
155
156 func (sys syss) String() string {
157 var s string
158 for _, sy := range sys {
159 switch sy := sy.(type) {
160 case *InterfaceMetrics:
161 if len(s) > 0 {
162 s += " "
163 }
164 s += sy.String()
165 case *RouteMetrics:
166 if len(s) > 0 {
167 s += " "
168 }
169 s += sy.String()
170 }
171 }
172 return s
173 }
174
175 type addrFamily int
176
177 func (af addrFamily) String() string {
178 switch af {
179 case syscall.AF_UNSPEC:
180 return "unspec"
181 case syscall.AF_LINK:
182 return "link"
183 case syscall.AF_INET:
184 return "inet4"
185 case syscall.AF_INET6:
186 return "inet6"
187 default:
188 return fmt.Sprintf("%d", af)
189 }
190 }
191
192 const hexDigit = "0123456789abcdef"
193
194 type llAddr []byte
195
196 func (a llAddr) String() string {
197 if len(a) == 0 {
198 return ""
199 }
200 buf := make([]byte, 0, len(a)*3-1)
201 for i, b := range a {
202 if i > 0 {
203 buf = append(buf, ':')
204 }
205 buf = append(buf, hexDigit[b>>4])
206 buf = append(buf, hexDigit[b&0xF])
207 }
208 return string(buf)
209 }
210
211 type ipAddr []byte
212
213 func (a ipAddr) String() string {
214 if len(a) == 0 {
215 return "<nil>"
216 }
217 if len(a) == 4 {
218 return fmt.Sprintf("%d.%d.%d.%d", a[0], a[1], a[2], a[3])
219 }
220 if len(a) == 16 {
221 return fmt.Sprintf("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15])
222 }
223 s := make([]byte, len(a)*2)
224 for i, tn := range a {
225 s[i*2], s[i*2+1] = hexDigit[tn>>4], hexDigit[tn&0xf]
226 }
227 return string(s)
228 }
229
230 func (a *LinkAddr) String() string {
231 name := a.Name
232 if name == "" {
233 name = "<nil>"
234 }
235 lla := llAddr(a.Addr).String()
236 if lla == "" {
237 lla = "<nil>"
238 }
239 return fmt.Sprintf("(%v %d %s %s)", addrFamily(a.Family()), a.Index, name, lla)
240 }
241
242 func (a *Inet4Addr) String() string {
243 return fmt.Sprintf("(%v %v)", addrFamily(a.Family()), ipAddr(a.IP[:]))
244 }
245
246 func (a *Inet6Addr) String() string {
247 return fmt.Sprintf("(%v %v %d)", addrFamily(a.Family()), ipAddr(a.IP[:]), a.ZoneID)
248 }
249
250 func (a *DefaultAddr) String() string {
251 return fmt.Sprintf("(%v %s)", addrFamily(a.Family()), ipAddr(a.Raw[2:]).String())
252 }
253
254 type addrs []Addr
255
256 func (as addrs) String() string {
257 var s string
258 for _, a := range as {
259 if a == nil {
260 continue
261 }
262 if len(s) > 0 {
263 s += " "
264 }
265 switch a := a.(type) {
266 case *LinkAddr:
267 s += a.String()
268 case *Inet4Addr:
269 s += a.String()
270 case *Inet6Addr:
271 s += a.String()
272 case *DefaultAddr:
273 s += a.String()
274 }
275 }
276 if s == "" {
277 return "<nil>"
278 }
279 return s
280 }
281
282 func (as addrs) match(attrs addrAttrs) error {
283 var ts addrAttrs
284 af := syscall.AF_UNSPEC
285 for i := range as {
286 if as[i] != nil {
287 ts |= 1 << uint(i)
288 }
289 switch as[i].(type) {
290 case *Inet4Addr:
291 if af == syscall.AF_UNSPEC {
292 af = syscall.AF_INET
293 }
294 if af != syscall.AF_INET {
295 return fmt.Errorf("got %v; want %v", addrs(as), addrFamily(af))
296 }
297 case *Inet6Addr:
298 if af == syscall.AF_UNSPEC {
299 af = syscall.AF_INET6
300 }
301 if af != syscall.AF_INET6 {
302 return fmt.Errorf("got %v; want %v", addrs(as), addrFamily(af))
303 }
304 }
305 }
306 if ts != attrs && ts > attrs {
307 return fmt.Errorf("%v not included in %v", ts, attrs)
308 }
309 return nil
310 }
311
312 func fetchAndParseRIB(af int, typ RIBType) ([]Message, error) {
313 b, err := FetchRIB(af, typ, 0)
314 if err != nil {
315 return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err)
316 }
317 ms, err := ParseRIB(typ, b)
318 if err != nil {
319 return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err)
320 }
321 return ms, nil
322 }
323
324
325 type propVirtual struct {
326 name string
327 addr, mask string
328 setupCmds []*exec.Cmd
329 teardownCmds []*exec.Cmd
330 }
331
332 func (pv *propVirtual) setup() error {
333 for _, cmd := range pv.setupCmds {
334 if err := cmd.Run(); err != nil {
335 pv.teardown()
336 return err
337 }
338 }
339 return nil
340 }
341
342 func (pv *propVirtual) teardown() error {
343 for _, cmd := range pv.teardownCmds {
344 if err := cmd.Run(); err != nil {
345 return err
346 }
347 }
348 return nil
349 }
350
351 func (pv *propVirtual) configure(suffix int) error {
352 if runtime.GOOS == "openbsd" {
353 pv.name = fmt.Sprintf("vether%d", suffix)
354 } else {
355 pv.name = fmt.Sprintf("vlan%d", suffix)
356 }
357 xname, err := exec.LookPath("ifconfig")
358 if err != nil {
359 return err
360 }
361 pv.setupCmds = append(pv.setupCmds, &exec.Cmd{
362 Path: xname,
363 Args: []string{"ifconfig", pv.name, "create"},
364 })
365 if runtime.GOOS == "netbsd" {
366
367
368 pv.setupCmds = append(pv.setupCmds, &exec.Cmd{
369 Path: xname,
370 Args: []string{"ifconfig", pv.name, "vlan", fmt.Sprintf("%d", suffix&0xfff), "vlanif", "wm0"},
371 })
372 }
373 pv.setupCmds = append(pv.setupCmds, &exec.Cmd{
374 Path: xname,
375 Args: []string{"ifconfig", pv.name, "inet", pv.addr, "netmask", pv.mask},
376 })
377 pv.teardownCmds = append(pv.teardownCmds, &exec.Cmd{
378 Path: xname,
379 Args: []string{"ifconfig", pv.name, "destroy"},
380 })
381 return nil
382 }
383
View as plain text