| // Copyright 2011 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 syscall |
| |
| import ( |
| "runtime" |
| "unsafe" |
| ) |
| |
| var ( |
| freebsdConfArch string // "machine $arch" line in kern.conftxt on freebsd |
| minRoutingSockaddrLen = rsaAlignOf(0) |
| ) |
| |
| // Round the length of a raw sockaddr up to align it properly. |
| func rsaAlignOf(salen int) int { |
| salign := int(sizeofPtr) |
| if darwin64Bit { |
| // Darwin kernels require 32-bit aligned access to |
| // routing facilities. |
| salign = 4 |
| } else if netbsd32Bit { |
| // NetBSD 6 and beyond kernels require 64-bit aligned |
| // access to routing facilities. |
| salign = 8 |
| } else if runtime.GOOS == "freebsd" { |
| // In the case of kern.supported_archs="amd64 i386", |
| // we need to know the underlying kernel's |
| // architecture because the alignment for routing |
| // facilities are set at the build time of the kernel. |
| if freebsdConfArch == "amd64" { |
| salign = 8 |
| } |
| } |
| if salen == 0 { |
| return salign |
| } |
| return (salen + salign - 1) & ^(salign - 1) |
| } |
| |
| // parseSockaddrLink parses b as a datalink socket address. |
| func parseSockaddrLink(b []byte) (*SockaddrDatalink, error) { |
| if len(b) < 8 { |
| return nil, EINVAL |
| } |
| sa, _, err := parseLinkLayerAddr(b[4:]) |
| if err != nil { |
| return nil, err |
| } |
| rsa := (*RawSockaddrDatalink)(unsafe.Pointer(&b[0])) |
| sa.Len = rsa.Len |
| sa.Family = rsa.Family |
| sa.Index = rsa.Index |
| return sa, nil |
| } |
| |
| // parseLinkLayerAddr parses b as a datalink socket address in |
| // conventional BSD kernel form. |
| func parseLinkLayerAddr(b []byte) (*SockaddrDatalink, int, error) { |
| // The encoding looks like the following: |
| // +----------------------------+ |
| // | Type (1 octet) | |
| // +----------------------------+ |
| // | Name length (1 octet) | |
| // +----------------------------+ |
| // | Address length (1 octet) | |
| // +----------------------------+ |
| // | Selector length (1 octet) | |
| // +----------------------------+ |
| // | Data (variable) | |
| // +----------------------------+ |
| type linkLayerAddr struct { |
| Type byte |
| Nlen byte |
| Alen byte |
| Slen byte |
| } |
| lla := (*linkLayerAddr)(unsafe.Pointer(&b[0])) |
| l := 4 + int(lla.Nlen) + int(lla.Alen) + int(lla.Slen) |
| if len(b) < l { |
| return nil, 0, EINVAL |
| } |
| b = b[4:] |
| sa := &SockaddrDatalink{Type: lla.Type, Nlen: lla.Nlen, Alen: lla.Alen, Slen: lla.Slen} |
| for i := 0; len(sa.Data) > i && i < l-4; i++ { |
| sa.Data[i] = int8(b[i]) |
| } |
| return sa, rsaAlignOf(l), nil |
| } |
| |
| // parseSockaddrInet parses b as an internet socket address. |
| func parseSockaddrInet(b []byte, family byte) (Sockaddr, error) { |
| switch family { |
| case AF_INET: |
| if len(b) < SizeofSockaddrInet4 { |
| return nil, EINVAL |
| } |
| rsa := (*RawSockaddrAny)(unsafe.Pointer(&b[0])) |
| return anyToSockaddr(rsa) |
| case AF_INET6: |
| if len(b) < SizeofSockaddrInet6 { |
| return nil, EINVAL |
| } |
| rsa := (*RawSockaddrAny)(unsafe.Pointer(&b[0])) |
| return anyToSockaddr(rsa) |
| default: |
| return nil, EINVAL |
| } |
| } |
| |
| const ( |
| offsetofInet4 = int(unsafe.Offsetof(RawSockaddrInet4{}.Addr)) |
| offsetofInet6 = int(unsafe.Offsetof(RawSockaddrInet6{}.Addr)) |
| ) |
| |
| // parseNetworkLayerAddr parses b as an internet socket address in |
| // conventional BSD kernel form. |
| func parseNetworkLayerAddr(b []byte, family byte) (Sockaddr, error) { |
| // The encoding looks similar to the NLRI encoding. |
| // +----------------------------+ |
| // | Length (1 octet) | |
| // +----------------------------+ |
| // | Address prefix (variable) | |
| // +----------------------------+ |
| // |
| // The differences between the kernel form and the NLRI |
| // encoding are: |
| // |
| // - The length field of the kernel form indicates the prefix |
| // length in bytes, not in bits |
| // |
| // - In the kernel form, zero value of the length field |
| // doesn't mean 0.0.0.0/0 or ::/0 |
| // |
| // - The kernel form appends leading bytes to the prefix field |
| // to make the <length, prefix> tuple to be conformed with |
| // the routing message boundary |
| l := int(rsaAlignOf(int(b[0]))) |
| if len(b) < l { |
| return nil, EINVAL |
| } |
| // Don't reorder case expressions. |
| // The case expressions for IPv6 must come first. |
| switch { |
| case b[0] == SizeofSockaddrInet6: |
| sa := &SockaddrInet6{} |
| copy(sa.Addr[:], b[offsetofInet6:]) |
| return sa, nil |
| case family == AF_INET6: |
| sa := &SockaddrInet6{} |
| if l-1 < offsetofInet6 { |
| copy(sa.Addr[:], b[1:l]) |
| } else { |
| copy(sa.Addr[:], b[l-offsetofInet6:l]) |
| } |
| return sa, nil |
| case b[0] == SizeofSockaddrInet4: |
| sa := &SockaddrInet4{} |
| copy(sa.Addr[:], b[offsetofInet4:]) |
| return sa, nil |
| default: // an old fashion, AF_UNSPEC or unknown means AF_INET |
| sa := &SockaddrInet4{} |
| if l-1 < offsetofInet4 { |
| copy(sa.Addr[:], b[1:l]) |
| } else { |
| copy(sa.Addr[:], b[l-offsetofInet4:l]) |
| } |
| return sa, nil |
| } |
| } |
| |
| // RouteRIB returns routing information base, as known as RIB, |
| // which consists of network facility information, states and |
| // parameters. |
| // |
| // Deprecated: Use golang.org/x/net/route instead. |
| func RouteRIB(facility, param int) ([]byte, error) { |
| mib := []_C_int{CTL_NET, AF_ROUTE, 0, 0, _C_int(facility), _C_int(param)} |
| // Find size. |
| n := uintptr(0) |
| if err := sysctl(mib, nil, &n, nil, 0); err != nil { |
| return nil, err |
| } |
| if n == 0 { |
| return nil, nil |
| } |
| tab := make([]byte, n) |
| if err := sysctl(mib, &tab[0], &n, nil, 0); err != nil { |
| return nil, err |
| } |
| return tab[:n], nil |
| } |
| |
| // RoutingMessage represents a routing message. |
| // |
| // Deprecated: Use golang.org/x/net/route instead. |
| type RoutingMessage interface { |
| sockaddr() ([]Sockaddr, error) |
| } |
| |
| const anyMessageLen = int(unsafe.Sizeof(anyMessage{})) |
| |
| type anyMessage struct { |
| Msglen uint16 |
| Version uint8 |
| Type uint8 |
| } |
| |
| // RouteMessage represents a routing message containing routing |
| // entries. |
| // |
| // Deprecated: Use golang.org/x/net/route instead. |
| type RouteMessage struct { |
| Header RtMsghdr |
| Data []byte |
| } |
| |
| func (m *RouteMessage) sockaddr() ([]Sockaddr, error) { |
| var sas [RTAX_MAX]Sockaddr |
| b := m.Data[:] |
| family := uint8(AF_UNSPEC) |
| for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ { |
| if m.Header.Addrs&(1<<i) == 0 { |
| continue |
| } |
| rsa := (*RawSockaddr)(unsafe.Pointer(&b[0])) |
| switch rsa.Family { |
| case AF_LINK: |
| sa, err := parseSockaddrLink(b) |
| if err != nil { |
| return nil, err |
| } |
| sas[i] = sa |
| b = b[rsaAlignOf(int(rsa.Len)):] |
| case AF_INET, AF_INET6: |
| sa, err := parseSockaddrInet(b, rsa.Family) |
| if err != nil { |
| return nil, err |
| } |
| sas[i] = sa |
| b = b[rsaAlignOf(int(rsa.Len)):] |
| family = rsa.Family |
| default: |
| sa, err := parseNetworkLayerAddr(b, family) |
| if err != nil { |
| return nil, err |
| } |
| sas[i] = sa |
| b = b[rsaAlignOf(int(b[0])):] |
| } |
| } |
| return sas[:], nil |
| } |
| |
| // InterfaceMessage represents a routing message containing |
| // network interface entries. |
| // |
| // Deprecated: Use golang.org/x/net/route instead. |
| type InterfaceMessage struct { |
| Header IfMsghdr |
| Data []byte |
| } |
| |
| func (m *InterfaceMessage) sockaddr() ([]Sockaddr, error) { |
| var sas [RTAX_MAX]Sockaddr |
| if m.Header.Addrs&RTA_IFP == 0 { |
| return nil, nil |
| } |
| sa, err := parseSockaddrLink(m.Data[:]) |
| if err != nil { |
| return nil, err |
| } |
| sas[RTAX_IFP] = sa |
| return sas[:], nil |
| } |
| |
| // InterfaceAddrMessage represents a routing message containing |
| // network interface address entries. |
| // |
| // Deprecated: Use golang.org/x/net/route instead. |
| type InterfaceAddrMessage struct { |
| Header IfaMsghdr |
| Data []byte |
| } |
| |
| func (m *InterfaceAddrMessage) sockaddr() ([]Sockaddr, error) { |
| var sas [RTAX_MAX]Sockaddr |
| b := m.Data[:] |
| family := uint8(AF_UNSPEC) |
| for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ { |
| if m.Header.Addrs&(1<<i) == 0 { |
| continue |
| } |
| rsa := (*RawSockaddr)(unsafe.Pointer(&b[0])) |
| switch rsa.Family { |
| case AF_LINK: |
| sa, err := parseSockaddrLink(b) |
| if err != nil { |
| return nil, err |
| } |
| sas[i] = sa |
| b = b[rsaAlignOf(int(rsa.Len)):] |
| case AF_INET, AF_INET6: |
| sa, err := parseSockaddrInet(b, rsa.Family) |
| if err != nil { |
| return nil, err |
| } |
| sas[i] = sa |
| b = b[rsaAlignOf(int(rsa.Len)):] |
| family = rsa.Family |
| default: |
| sa, err := parseNetworkLayerAddr(b, family) |
| if err != nil { |
| return nil, err |
| } |
| sas[i] = sa |
| b = b[rsaAlignOf(int(b[0])):] |
| } |
| } |
| return sas[:], nil |
| } |
| |
| // ParseRoutingMessage parses b as routing messages and returns the |
| // slice containing the RoutingMessage interfaces. |
| // |
| // Deprecated: Use golang.org/x/net/route instead. |
| func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) { |
| nmsgs, nskips := 0, 0 |
| for len(b) >= anyMessageLen { |
| nmsgs++ |
| any := (*anyMessage)(unsafe.Pointer(&b[0])) |
| if any.Version != RTM_VERSION { |
| b = b[any.Msglen:] |
| continue |
| } |
| if m := any.toRoutingMessage(b); m == nil { |
| nskips++ |
| } else { |
| msgs = append(msgs, m) |
| } |
| b = b[any.Msglen:] |
| } |
| // We failed to parse any of the messages - version mismatch? |
| if nmsgs != len(msgs)+nskips { |
| return nil, EINVAL |
| } |
| return msgs, nil |
| } |
| |
| // ParseRoutingSockaddr parses msg's payload as raw sockaddrs and |
| // returns the slice containing the Sockaddr interfaces. |
| // |
| // Deprecated: Use golang.org/x/net/route instead. |
| func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) { |
| sas, err := msg.sockaddr() |
| if err != nil { |
| return nil, err |
| } |
| return sas, nil |
| } |