// 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 package routebsd import ( "net/netip" "runtime" "syscall" ) // An Addr represents an address associated with packet routing. type Addr interface { // Family returns an address family. Family() int } // A LinkAddr represents a link-layer address. type LinkAddr struct { Index int // interface index when attached Name string // interface name when attached Addr []byte // link-layer address when attached } // Family implements the Family method of Addr interface. func (a *LinkAddr) Family() int { return syscall.AF_LINK } func parseLinkAddr(b []byte) (Addr, error) { if len(b) < 8 { return nil, errInvalidAddr } _, a, err := parseKernelLinkAddr(syscall.AF_LINK, b[4:]) if err != nil { return nil, err } a.(*LinkAddr).Index = int(nativeEndian.Uint16(b[2:4])) return a, nil } // parseKernelLinkAddr parses b as a link-layer address in // conventional BSD kernel form. func parseKernelLinkAddr(_ int, b []byte) (int, Addr, error) { // The encoding looks like the following: // +----------------------------+ // | Type (1 octet) | // +----------------------------+ // | Name length (1 octet) | // +----------------------------+ // | Address length (1 octet) | // +----------------------------+ // | Selector length (1 octet) | // +----------------------------+ // | Data (variable) | // +----------------------------+ // // On some platforms, all-bit-one of length field means "don't // care". nlen, alen, slen := int(b[1]), int(b[2]), int(b[3]) if nlen == 0xff { nlen = 0 } if alen == 0xff { alen = 0 } if slen == 0xff { slen = 0 } l := 4 + nlen + alen + slen if len(b) < l { return 0, nil, errInvalidAddr } data := b[4:] var name string var addr []byte if nlen > 0 { name = string(data[:nlen]) data = data[nlen:] } if alen > 0 { addr = data[:alen] data = data[alen:] } return l, &LinkAddr{Name: name, Addr: addr}, nil } // An InetAddr represent an internet address using IPv4 or IPv6. type InetAddr struct { IP netip.Addr } func (a *InetAddr) Family() int { if a.IP.Is4() { return syscall.AF_INET } else { return syscall.AF_INET6 } } // parseInetAddr parses b as an internet address for IPv4 or IPv6. func parseInetAddr(af int, b []byte) (Addr, error) { const ( off4 = 4 // offset of in_addr off6 = 8 // offset of in6_addr ipv4Len = 4 // length of IPv4 address in bytes ipv6Len = 16 // length of IPv6 address in bytes ) switch af { case syscall.AF_INET: if len(b) < (off4+1) || len(b) < int(b[0]) { return nil, errInvalidAddr } sockAddrLen := int(b[0]) var ip [ipv4Len]byte if sockAddrLen != 0 { // Calculate how many bytes of the address to copy: // either full IPv4 length or the available length. n := off4 + ipv4Len if sockAddrLen < n { n = sockAddrLen } copy(ip[:], b[off4:n]) } a := &InetAddr{ IP: netip.AddrFrom4(ip), } return a, nil case syscall.AF_INET6: if len(b) < (off6+1) || len(b) < int(b[0]) { return nil, errInvalidAddr } var ip [ipv6Len]byte sockAddrLen := int(b[0]) if sockAddrLen != 0 { n := off6 + ipv6Len if sockAddrLen < n { n = sockAddrLen } copy(ip[:], b[off6:n]) if ip[0] == 0xfe && ip[1]&0xc0 == 0x80 || ip[0] == 0xff && (ip[1]&0x0f == 0x01 || ip[1]&0x0f == 0x02) { // KAME based IPv6 protocol stack usually // embeds the interface index in the // interface-local or link-local address as // the kernel-internal form. id := int(bigEndian.Uint16(ip[2:4])) if id != 0 { ip[2], ip[3] = 0, 0 } } } // The kernel can provide an integer zone ID. // We ignore it. a := &InetAddr{ IP: netip.AddrFrom16(ip), } return a, nil default: return nil, errInvalidAddr } } // parseKernelInetAddr parses b as an internet address in conventional // BSD kernel form. func parseKernelInetAddr(af int, b []byte) (int, Addr, 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 tuple to be conformed with // the routing message boundary l := int(b[0]) if runtime.GOOS == "darwin" || runtime.GOOS == "ios" { // On Darwin, an address in the kernel form is also // used as a message filler. if l == 0 || len(b) > roundup(l) { l = roundup(l) } } else { l = roundup(l) } if len(b) < l { return 0, nil, errInvalidAddr } // Don't reorder case expressions. // The case expressions for IPv6 must come first. const ( off4 = 4 // offset of in_addr off6 = 8 // offset of in6_addr ) switch { case b[0] == syscall.SizeofSockaddrInet6: a := &InetAddr{ IP: netip.AddrFrom16([16]byte(b[off6 : off6+16])), } return int(b[0]), a, nil case af == syscall.AF_INET6: var ab [16]byte if l-1 < off6 { copy(ab[:], b[1:l]) } else { copy(ab[:], b[l-off6:l]) } a := &InetAddr{ IP: netip.AddrFrom16(ab), } return int(b[0]), a, nil case b[0] == syscall.SizeofSockaddrInet4: a := &InetAddr{ IP: netip.AddrFrom4([4]byte(b[off4 : off4+4])), } return int(b[0]), a, nil default: // an old fashion, AF_UNSPEC or unknown means AF_INET var ab [4]byte if l-1 < off4 { copy(ab[:], b[1:l]) } else { copy(ab[:], b[l-off4:l]) } a := &InetAddr{ IP: netip.AddrFrom4(ab), } return int(b[0]), a, nil } } func parseAddrs(attrs uint, b []byte) ([]Addr, error) { var as [syscall.RTAX_MAX]Addr af := int(syscall.AF_UNSPEC) for i := uint(0); i < syscall.RTAX_MAX && len(b) >= roundup(0); i++ { if attrs&(1<