1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
// Copyright 2016 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.
//go:build darwin || dragonfly || freebsd || netbsd || openbsd
// Package route provides basic functions for the manipulation of
// packet routing facilities on BSD variants.
//
// The package supports any version of Darwin, any version of
// DragonFly BSD, FreeBSD 7 and above, NetBSD 6 and above, and OpenBSD
// 5.6 and above.
package route
import (
"errors"
"os"
"syscall"
)
var (
errUnsupportedMessage = errors.New("unsupported message")
errMessageMismatch = errors.New("message mismatch")
errMessageTooShort = errors.New("message too short")
errInvalidMessage = errors.New("invalid message")
errInvalidAddr = errors.New("invalid address")
errShortBuffer = errors.New("short buffer")
)
// A RouteMessage represents a message conveying an address prefix, a
// nexthop address and an output interface.
//
// Unlike other messages, this message can be used to query adjacency
// information for the given address prefix, to add a new route, and
// to delete or modify the existing route from the routing information
// base inside the kernel by writing and reading route messages on a
// routing socket.
//
// For the manipulation of routing information, the route message must
// contain appropriate fields that include:
//
// Version = <must be specified>
// Type = <must be specified>
// Flags = <must be specified>
// Index = <must be specified if necessary>
// ID = <must be specified>
// Seq = <must be specified>
// Addrs = <must be specified>
//
// The Type field specifies a type of manipulation, the Flags field
// specifies a class of target information and the Addrs field
// specifies target information like the following:
//
// route.RouteMessage{
// Version: RTM_VERSION,
// Type: RTM_GET,
// Flags: RTF_UP | RTF_HOST,
// ID: uintptr(os.Getpid()),
// Seq: 1,
// Addrs: []route.Addrs{
// RTAX_DST: &route.Inet4Addr{ ... },
// RTAX_IFP: &route.LinkAddr{ ... },
// RTAX_BRD: &route.Inet4Addr{ ... },
// },
// }
//
// The values for the above fields depend on the implementation of
// each operating system.
//
// The Err field on a response message contains an error value on the
// requested operation. If non-nil, the requested operation is failed.
type RouteMessage struct {
Version int // message version
Type int // message type
Flags int // route flags
Index int // interface index when attached
ID uintptr // sender's identifier; usually process ID
Seq int // sequence number
Err error // error on requested operation
Addrs []Addr // addresses
extOff int // offset of header extension
raw []byte // raw message
}
// Marshal returns the binary encoding of m.
func (m *RouteMessage) Marshal() ([]byte, error) {
return m.marshal()
}
// A RIBType represents a type of routing information base.
type RIBType int
const (
RIBTypeRoute RIBType = syscall.NET_RT_DUMP
RIBTypeInterface RIBType = syscall.NET_RT_IFLIST
)
// FetchRIB fetches a routing information base from the operating
// system.
//
// The provided af must be an address family.
//
// The provided arg must be a RIBType-specific argument.
// When RIBType is related to routes, arg might be a set of route
// flags. When RIBType is related to network interfaces, arg might be
// an interface index or a set of interface flags. In most cases, zero
// means a wildcard.
func FetchRIB(af int, typ RIBType, arg int) ([]byte, error) {
try := 0
for {
try++
mib := [6]int32{syscall.CTL_NET, syscall.AF_ROUTE, 0, int32(af), int32(typ), int32(arg)}
n := uintptr(0)
if err := sysctl(mib[:], nil, &n, nil, 0); err != nil {
return nil, os.NewSyscallError("sysctl", err)
}
if n == 0 {
return nil, nil
}
b := make([]byte, n)
if err := sysctl(mib[:], &b[0], &n, nil, 0); err != nil {
// If the sysctl failed because the data got larger
// between the two sysctl calls, try a few times
// before failing. (golang.org/issue/45736).
const maxTries = 3
if err == syscall.ENOMEM && try < maxTries {
continue
}
return nil, os.NewSyscallError("sysctl", err)
}
return b[:n], nil
}
}
|