github.com/ccccaoqing/test@v0.0.0-20220510085219-3985d23445c0/src/syscall/route_bsd.go (about) 1 // Copyright 2011 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 // Routing sockets and messages 8 9 package syscall 10 11 import "unsafe" 12 13 // Round the length of a raw sockaddr up to align it properly. 14 func rsaAlignOf(salen int) int { 15 salign := sizeofPtr 16 // NOTE: It seems like 64-bit Darwin kernel still requires 17 // 32-bit aligned access to BSD subsystem. Also NetBSD 6 18 // kernel and beyond require 64-bit aligned access to routing 19 // facilities. 20 if darwin64Bit { 21 salign = 4 22 } else if netbsd32Bit { 23 salign = 8 24 } 25 if salen == 0 { 26 return salign 27 } 28 return (salen + salign - 1) & ^(salign - 1) 29 } 30 31 // RouteRIB returns routing information base, as known as RIB, 32 // which consists of network facility information, states and 33 // parameters. 34 func RouteRIB(facility, param int) ([]byte, error) { 35 mib := []_C_int{CTL_NET, AF_ROUTE, 0, 0, _C_int(facility), _C_int(param)} 36 // Find size. 37 n := uintptr(0) 38 if err := sysctl(mib, nil, &n, nil, 0); err != nil { 39 return nil, err 40 } 41 if n == 0 { 42 return nil, nil 43 } 44 tab := make([]byte, n) 45 if err := sysctl(mib, &tab[0], &n, nil, 0); err != nil { 46 return nil, err 47 } 48 return tab[:n], nil 49 } 50 51 // RoutingMessage represents a routing message. 52 type RoutingMessage interface { 53 sockaddr() []Sockaddr 54 } 55 56 const anyMessageLen = int(unsafe.Sizeof(anyMessage{})) 57 58 type anyMessage struct { 59 Msglen uint16 60 Version uint8 61 Type uint8 62 } 63 64 // RouteMessage represents a routing message containing routing 65 // entries. 66 type RouteMessage struct { 67 Header RtMsghdr 68 Data []byte 69 } 70 71 const rtaRtMask = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK 72 73 func (m *RouteMessage) sockaddr() []Sockaddr { 74 var ( 75 af int 76 sas [4]Sockaddr 77 ) 78 b := m.Data[:] 79 for i := uint(0); i < RTAX_MAX; i++ { 80 if m.Header.Addrs&rtaRtMask&(1<<i) == 0 { 81 continue 82 } 83 rsa := (*RawSockaddr)(unsafe.Pointer(&b[0])) 84 switch i { 85 case RTAX_DST, RTAX_GATEWAY: 86 sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa))) 87 if err != nil { 88 return nil 89 } 90 if i == RTAX_DST { 91 af = int(rsa.Family) 92 } 93 sas[i] = sa 94 case RTAX_NETMASK, RTAX_GENMASK: 95 switch af { 96 case AF_INET: 97 rsa4 := (*RawSockaddrInet4)(unsafe.Pointer(&b[0])) 98 sa := new(SockaddrInet4) 99 for j := 0; rsa4.Len > 0 && j < int(rsa4.Len)-int(unsafe.Offsetof(rsa4.Addr)); j++ { 100 sa.Addr[j] = rsa4.Addr[j] 101 } 102 sas[i] = sa 103 case AF_INET6: 104 rsa6 := (*RawSockaddrInet6)(unsafe.Pointer(&b[0])) 105 sa := new(SockaddrInet6) 106 for j := 0; rsa6.Len > 0 && j < int(rsa6.Len)-int(unsafe.Offsetof(rsa6.Addr)); j++ { 107 sa.Addr[j] = rsa6.Addr[j] 108 } 109 sas[i] = sa 110 } 111 } 112 b = b[rsaAlignOf(int(rsa.Len)):] 113 } 114 return sas[:] 115 } 116 117 // InterfaceMessage represents a routing message containing 118 // network interface entries. 119 type InterfaceMessage struct { 120 Header IfMsghdr 121 Data []byte 122 } 123 124 func (m *InterfaceMessage) sockaddr() (sas []Sockaddr) { 125 if m.Header.Addrs&RTA_IFP == 0 { 126 return nil 127 } 128 sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0]))) 129 if err != nil { 130 return nil 131 } 132 return append(sas, sa) 133 } 134 135 // InterfaceAddrMessage represents a routing message containing 136 // network interface address entries. 137 type InterfaceAddrMessage struct { 138 Header IfaMsghdr 139 Data []byte 140 } 141 142 const rtaIfaMask = RTA_IFA | RTA_NETMASK | RTA_BRD 143 144 func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) { 145 if m.Header.Addrs&rtaIfaMask == 0 { 146 return nil 147 } 148 b := m.Data[:] 149 // We still see AF_UNSPEC in socket addresses on some 150 // platforms. To identify each address family correctly, we 151 // will use the address family of RTAX_NETMASK as a preferred 152 // one on the 32-bit NetBSD kernel, also use the length of 153 // RTAX_NETMASK socket address on the FreeBSD kernel. 154 preferredFamily := uint8(AF_UNSPEC) 155 for i := uint(0); i < RTAX_MAX; i++ { 156 if m.Header.Addrs&(1<<i) == 0 { 157 continue 158 } 159 rsa := (*RawSockaddr)(unsafe.Pointer(&b[0])) 160 switch i { 161 case RTAX_IFA: 162 if rsa.Family == AF_UNSPEC { 163 rsa.Family = preferredFamily 164 } 165 sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa))) 166 if err != nil { 167 return nil 168 } 169 sas = append(sas, sa) 170 case RTAX_NETMASK: 171 switch rsa.Family { 172 case AF_UNSPEC: 173 switch rsa.Len { 174 case SizeofSockaddrInet4: 175 rsa.Family = AF_INET 176 case SizeofSockaddrInet6: 177 rsa.Family = AF_INET6 178 default: 179 rsa.Family = AF_INET // an old fashion, AF_UNSPEC means AF_INET 180 } 181 case AF_INET, AF_INET6: 182 preferredFamily = rsa.Family 183 default: 184 return nil 185 } 186 sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa))) 187 if err != nil { 188 return nil 189 } 190 sas = append(sas, sa) 191 case RTAX_BRD: 192 // nothing to do 193 } 194 b = b[rsaAlignOf(int(rsa.Len)):] 195 } 196 return sas 197 } 198 199 // ParseRoutingMessage parses b as routing messages and returns the 200 // slice containing the RoutingMessage interfaces. 201 func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) { 202 msgCount := 0 203 for len(b) >= anyMessageLen { 204 msgCount++ 205 any := (*anyMessage)(unsafe.Pointer(&b[0])) 206 if any.Version != RTM_VERSION { 207 b = b[any.Msglen:] 208 continue 209 } 210 msgs = append(msgs, any.toRoutingMessage(b)) 211 b = b[any.Msglen:] 212 } 213 // We failed to parse any of the messages - version mismatch? 214 if msgCount > 0 && len(msgs) == 0 { 215 return nil, EINVAL 216 } 217 return msgs, nil 218 } 219 220 // ParseRoutingMessage parses msg's payload as raw sockaddrs and 221 // returns the slice containing the Sockaddr interfaces. 222 func ParseRoutingSockaddr(msg RoutingMessage) (sas []Sockaddr, err error) { 223 return append(sas, msg.sockaddr()...), nil 224 }