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 135
|
// 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
// +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
}
}
|