forked from TrueCloudLab/restic
425 lines
9.5 KiB
Go
425 lines
9.5 KiB
Go
// 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.
|
|
|
|
// +build darwin dragonfly freebsd netbsd openbsd
|
|
|
|
package route
|
|
|
|
import "runtime"
|
|
|
|
// 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 sysAF_LINK }
|
|
|
|
func (a *LinkAddr) lenAndSpace() (int, int) {
|
|
l := 8 + len(a.Name) + len(a.Addr)
|
|
return l, roundup(l)
|
|
}
|
|
|
|
func (a *LinkAddr) marshal(b []byte) (int, error) {
|
|
l, ll := a.lenAndSpace()
|
|
if len(b) < ll {
|
|
return 0, errShortBuffer
|
|
}
|
|
nlen, alen := len(a.Name), len(a.Addr)
|
|
if nlen > 255 || alen > 255 {
|
|
return 0, errInvalidAddr
|
|
}
|
|
b[0] = byte(l)
|
|
b[1] = sysAF_LINK
|
|
if a.Index > 0 {
|
|
nativeEndian.PutUint16(b[2:4], uint16(a.Index))
|
|
}
|
|
data := b[8:]
|
|
if nlen > 0 {
|
|
b[5] = byte(nlen)
|
|
copy(data[:nlen], a.Addr)
|
|
data = data[nlen:]
|
|
}
|
|
if alen > 0 {
|
|
b[6] = byte(alen)
|
|
copy(data[:alen], a.Name)
|
|
data = data[alen:]
|
|
}
|
|
return ll, nil
|
|
}
|
|
|
|
func parseLinkAddr(b []byte) (Addr, error) {
|
|
if len(b) < 8 {
|
|
return nil, errInvalidAddr
|
|
}
|
|
_, a, err := parseKernelLinkAddr(sysAF_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 Inet4Addr represents an internet address for IPv4.
|
|
type Inet4Addr struct {
|
|
IP [4]byte // IP address
|
|
}
|
|
|
|
// Family implements the Family method of Addr interface.
|
|
func (a *Inet4Addr) Family() int { return sysAF_INET }
|
|
|
|
func (a *Inet4Addr) lenAndSpace() (int, int) {
|
|
return sizeofSockaddrInet, roundup(sizeofSockaddrInet)
|
|
}
|
|
|
|
func (a *Inet4Addr) marshal(b []byte) (int, error) {
|
|
l, ll := a.lenAndSpace()
|
|
if len(b) < ll {
|
|
return 0, errShortBuffer
|
|
}
|
|
b[0] = byte(l)
|
|
b[1] = sysAF_INET
|
|
copy(b[4:8], a.IP[:])
|
|
return ll, nil
|
|
}
|
|
|
|
// An Inet6Addr represents an internet address for IPv6.
|
|
type Inet6Addr struct {
|
|
IP [16]byte // IP address
|
|
ZoneID int // zone identifier
|
|
}
|
|
|
|
// Family implements the Family method of Addr interface.
|
|
func (a *Inet6Addr) Family() int { return sysAF_INET6 }
|
|
|
|
func (a *Inet6Addr) lenAndSpace() (int, int) {
|
|
return sizeofSockaddrInet6, roundup(sizeofSockaddrInet6)
|
|
}
|
|
|
|
func (a *Inet6Addr) marshal(b []byte) (int, error) {
|
|
l, ll := a.lenAndSpace()
|
|
if len(b) < ll {
|
|
return 0, errShortBuffer
|
|
}
|
|
b[0] = byte(l)
|
|
b[1] = sysAF_INET6
|
|
copy(b[8:24], a.IP[:])
|
|
if a.ZoneID > 0 {
|
|
nativeEndian.PutUint32(b[24:28], uint32(a.ZoneID))
|
|
}
|
|
return ll, nil
|
|
}
|
|
|
|
// parseInetAddr parses b as an internet address for IPv4 or IPv6.
|
|
func parseInetAddr(af int, b []byte) (Addr, error) {
|
|
switch af {
|
|
case sysAF_INET:
|
|
if len(b) < sizeofSockaddrInet {
|
|
return nil, errInvalidAddr
|
|
}
|
|
a := &Inet4Addr{}
|
|
copy(a.IP[:], b[4:8])
|
|
return a, nil
|
|
case sysAF_INET6:
|
|
if len(b) < sizeofSockaddrInet6 {
|
|
return nil, errInvalidAddr
|
|
}
|
|
a := &Inet6Addr{ZoneID: int(nativeEndian.Uint32(b[24:28]))}
|
|
copy(a.IP[:], b[8:24])
|
|
if a.IP[0] == 0xfe && a.IP[1]&0xc0 == 0x80 || a.IP[0] == 0xff && (a.IP[1]&0x0f == 0x01 || a.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(a.IP[2:4]))
|
|
if id != 0 {
|
|
a.ZoneID = id
|
|
a.IP[2], a.IP[3] = 0, 0
|
|
}
|
|
}
|
|
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 <length, prefix> tuple to be conformed with
|
|
// the routing message boundary
|
|
l := int(b[0])
|
|
if runtime.GOOS == "darwin" {
|
|
// On Darwn, 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] == sizeofSockaddrInet6:
|
|
a := &Inet6Addr{}
|
|
copy(a.IP[:], b[off6:off6+16])
|
|
return int(b[0]), a, nil
|
|
case af == sysAF_INET6:
|
|
a := &Inet6Addr{}
|
|
if l-1 < off6 {
|
|
copy(a.IP[:], b[1:l])
|
|
} else {
|
|
copy(a.IP[:], b[l-off6:l])
|
|
}
|
|
return int(b[0]), a, nil
|
|
case b[0] == sizeofSockaddrInet:
|
|
a := &Inet4Addr{}
|
|
copy(a.IP[:], b[off4:off4+4])
|
|
return int(b[0]), a, nil
|
|
default: // an old fashion, AF_UNSPEC or unknown means AF_INET
|
|
a := &Inet4Addr{}
|
|
if l-1 < off4 {
|
|
copy(a.IP[:], b[1:l])
|
|
} else {
|
|
copy(a.IP[:], b[l-off4:l])
|
|
}
|
|
return int(b[0]), a, nil
|
|
}
|
|
}
|
|
|
|
// A DefaultAddr represents an address of various operating
|
|
// system-specific features.
|
|
type DefaultAddr struct {
|
|
af int
|
|
Raw []byte // raw format of address
|
|
}
|
|
|
|
// Family implements the Family method of Addr interface.
|
|
func (a *DefaultAddr) Family() int { return a.af }
|
|
|
|
func (a *DefaultAddr) lenAndSpace() (int, int) {
|
|
l := len(a.Raw)
|
|
return l, roundup(l)
|
|
}
|
|
|
|
func (a *DefaultAddr) marshal(b []byte) (int, error) {
|
|
l, ll := a.lenAndSpace()
|
|
if len(b) < ll {
|
|
return 0, errShortBuffer
|
|
}
|
|
if l > 255 {
|
|
return 0, errInvalidAddr
|
|
}
|
|
b[1] = byte(l)
|
|
copy(b[:l], a.Raw)
|
|
return ll, nil
|
|
}
|
|
|
|
func parseDefaultAddr(b []byte) (Addr, error) {
|
|
if len(b) < 2 || len(b) < int(b[0]) {
|
|
return nil, errInvalidAddr
|
|
}
|
|
a := &DefaultAddr{af: int(b[1]), Raw: b[:b[0]]}
|
|
return a, nil
|
|
}
|
|
|
|
func addrsSpace(as []Addr) int {
|
|
var l int
|
|
for _, a := range as {
|
|
switch a := a.(type) {
|
|
case *LinkAddr:
|
|
_, ll := a.lenAndSpace()
|
|
l += ll
|
|
case *Inet4Addr:
|
|
_, ll := a.lenAndSpace()
|
|
l += ll
|
|
case *Inet6Addr:
|
|
_, ll := a.lenAndSpace()
|
|
l += ll
|
|
case *DefaultAddr:
|
|
_, ll := a.lenAndSpace()
|
|
l += ll
|
|
}
|
|
}
|
|
return l
|
|
}
|
|
|
|
// marshalAddrs marshals as and returns a bitmap indicating which
|
|
// address is stored in b.
|
|
func marshalAddrs(b []byte, as []Addr) (uint, error) {
|
|
var attrs uint
|
|
for i, a := range as {
|
|
switch a := a.(type) {
|
|
case *LinkAddr:
|
|
l, err := a.marshal(b)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
b = b[l:]
|
|
attrs |= 1 << uint(i)
|
|
case *Inet4Addr:
|
|
l, err := a.marshal(b)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
b = b[l:]
|
|
attrs |= 1 << uint(i)
|
|
case *Inet6Addr:
|
|
l, err := a.marshal(b)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
b = b[l:]
|
|
attrs |= 1 << uint(i)
|
|
case *DefaultAddr:
|
|
l, err := a.marshal(b)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
b = b[l:]
|
|
attrs |= 1 << uint(i)
|
|
}
|
|
}
|
|
return attrs, nil
|
|
}
|
|
|
|
func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) ([]Addr, error) {
|
|
var as [sysRTAX_MAX]Addr
|
|
af := int(sysAF_UNSPEC)
|
|
for i := uint(0); i < sysRTAX_MAX && len(b) >= roundup(0); i++ {
|
|
if attrs&(1<<i) == 0 {
|
|
continue
|
|
}
|
|
if i <= sysRTAX_BRD {
|
|
switch b[1] {
|
|
case sysAF_LINK:
|
|
a, err := parseLinkAddr(b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
as[i] = a
|
|
l := roundup(int(b[0]))
|
|
if len(b) < l {
|
|
return nil, errMessageTooShort
|
|
}
|
|
b = b[l:]
|
|
case sysAF_INET, sysAF_INET6:
|
|
af = int(b[1])
|
|
a, err := parseInetAddr(af, b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
as[i] = a
|
|
l := roundup(int(b[0]))
|
|
if len(b) < l {
|
|
return nil, errMessageTooShort
|
|
}
|
|
b = b[l:]
|
|
default:
|
|
l, a, err := fn(af, b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
as[i] = a
|
|
ll := roundup(l)
|
|
if len(b) < ll {
|
|
b = b[l:]
|
|
} else {
|
|
b = b[ll:]
|
|
}
|
|
}
|
|
} else {
|
|
a, err := parseDefaultAddr(b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
as[i] = a
|
|
l := roundup(int(b[0]))
|
|
if len(b) < l {
|
|
return nil, errMessageTooShort
|
|
}
|
|
b = b[l:]
|
|
}
|
|
}
|
|
return as[:], nil
|
|
}
|