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