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 //go: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. 13 package route 14 15 import ( 16 "errors" 17 "os" 18 "syscall" 19 ) 20 21 var ( 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. 72 type 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. 87 func (m *RouteMessage) Marshal() ([]byte, error) { 88 return m.marshal() 89 } 90 91 // A RIBType represents a type of routing information base. 92 type RIBType int 93 94 const ( 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. 109 func FetchRIB(af int, typ RIBType, arg int) ([]byte, error) { 110 try := 0 111 for { 112 try++ 113 mib := [6]int32{syscall.CTL_NET, syscall.AF_ROUTE, 0, int32(af), int32(typ), int32(arg)} 114 n := uintptr(0) 115 if err := sysctl(mib[:], nil, &n, nil, 0); err != nil { 116 return nil, os.NewSyscallError("sysctl", err) 117 } 118 if n == 0 { 119 return nil, nil 120 } 121 b := make([]byte, n) 122 if err := sysctl(mib[:], &b[0], &n, nil, 0); err != nil { 123 // If the sysctl failed because the data got larger 124 // between the two sysctl calls, try a few times 125 // before failing. (golang.org/issue/45736). 126 const maxTries = 3 127 if err == syscall.ENOMEM && try < maxTries { 128 continue 129 } 130 return nil, os.NewSyscallError("sysctl", err) 131 } 132 return b[:n], nil 133 } 134 } 135