Update dependencies

This commit is contained in:
bluepython508
2024-11-01 17:33:34 +00:00
parent 033ac0b400
commit 5cdfab398d
3596 changed files with 1033483 additions and 259 deletions

1
vendor/github.com/jsimonetti/rtnetlink/.gitignore generated vendored Normal file
View File

@@ -0,0 +1 @@
rtnetlink-fuzz.zip

10
vendor/github.com/jsimonetti/rtnetlink/LICENSE.md generated vendored Normal file
View File

@@ -0,0 +1,10 @@
MIT License
===========
Copyright (C) 2016 Jeroen Simonetti
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

32
vendor/github.com/jsimonetti/rtnetlink/Makefile.fuzz generated vendored Normal file
View File

@@ -0,0 +1,32 @@
# Makefile for fuzzing
#
# Currently fuzzing only works inside $GOPATH
#
# Installing go-fuzz
#$ go get github.com/dvyukov/go-fuzz/go-fuzz
#$ go get github.com/dvyukov/go-fuzz/go-fuzz-build
# (or)
#$ make -f Makefile.fuzz install
#
# Start fuzzing:
#$ make -f Makefile.fuzz fuzz
#
# Cleanup using:
#$ make -f Makefile.fuzz clean
.PHONY: install
install:
go get github.com/dvyukov/go-fuzz/go-fuzz
go get github.com/dvyukov/go-fuzz/go-fuzz-build
.PHONY: fuzz
fuzz:
go-fuzz-build -tags gofuzz
echo go-fuzz -bin=./rtnetlink-fuzz.zip -workdir=testdata -func FuzzLinkMessage
echo go-fuzz -bin=./rtnetlink-fuzz.zip -workdir=testdata -func FuzzAddressMessage
echo go-fuzz -bin=./rtnetlink-fuzz.zip -workdir=testdata -func FuzzRouteMessage
echo go-fuzz -bin=./rtnetlink-fuzz.zip -workdir=testdata -func FuzzNeighMessage
.PHONY: clean
clean:
rm rtnetlink-fuzz.zip

43
vendor/github.com/jsimonetti/rtnetlink/README.md generated vendored Normal file
View File

@@ -0,0 +1,43 @@
rtnetlink ![Linux Integration](https://github.com/jsimonetti/rtnetlink/workflows/Go/badge.svg) [![GoDoc](https://godoc.org/github.com/jsimonetti/rtnetlink?status.svg)](https://godoc.org/github.com/jsimonetti/rtnetlink) [![Go Report Card](https://goreportcard.com/badge/github.com/jsimonetti/rtnetlink)](https://goreportcard.com/report/github.com/jsimonetti/rtnetlink)
=======
Package `rtnetlink` allows the kernel's routing tables to be read and
altered. Network routes, IP addresses, Link parameters, Neighbor setups,
Queueing disciplines, Traffic classes and Packet classifiers may all be
controlled. It is based on netlink messages.
A convenient, high-level API wrapper is available using package
[`rtnl`](https://godoc.org/github.com/jsimonetti/rtnetlink/rtnl).
The base `rtnetlink` library explicitly only exposes a limited low-level API to
rtnetlink. It is not the intention (nor wish) to create an iproute2
replacement.
### Debugging and netlink errors
Unfortunately the errors generated by the kernels netlink interface are
not very great.
When in doubt about your message structure it can always be useful to
look at the message send by iproute2 using `strace -f -esendmsg /bin/ip`
or similar.
Another (and possibly even more flexible) way would be using `nlmon` and
`wireshark`. nlmod is a special kernel module which allows you to
capture all netlink (not just rtnetlink) traffic inside the kernel. Be
aware that this might be overwhelming on a system with a lot of netlink
traffic.
```
# modprobe nlmon
# ip link add type nlmon
# ip link set nlmon0 up
```
At this point use wireshark or tcpdump on the nlmon0 interface to view
all netlink traffic.
Have a look at the examples for common uses of rtnetlink.
If you have any questions or you'd like some guidance, please join us on
[Gophers Slack](https://invite.slack.golangbridge.org) in the `#networking`
channel!

269
vendor/github.com/jsimonetti/rtnetlink/address.go generated vendored Normal file
View File

@@ -0,0 +1,269 @@
package rtnetlink
import (
"errors"
"fmt"
"net"
"github.com/jsimonetti/rtnetlink/internal/unix"
"github.com/mdlayher/netlink"
)
var (
// errInvalidaddressMessage is returned when a AddressMessage is malformed.
errInvalidAddressMessage = errors.New("rtnetlink AddressMessage is invalid or too short")
)
var _ Message = &AddressMessage{}
// A AddressMessage is a route netlink address message.
type AddressMessage struct {
// Address family (current unix.AF_INET or unix.AF_INET6)
Family uint8
// Prefix length
PrefixLength uint8
// Contains address flags
Flags uint8
// Address Scope
Scope uint8
// Interface index
Index uint32
// Optional attributes which are appended when not nil.
Attributes *AddressAttributes
}
// MarshalBinary marshals a AddressMessage into a byte slice.
func (m *AddressMessage) MarshalBinary() ([]byte, error) {
b := make([]byte, unix.SizeofIfAddrmsg)
b[0] = m.Family
b[1] = m.PrefixLength
b[2] = m.Flags
b[3] = m.Scope
nativeEndian.PutUint32(b[4:8], m.Index)
if m.Attributes == nil {
// No attributes to encode.
return b, nil
}
ae := netlink.NewAttributeEncoder()
err := m.Attributes.encode(ae)
if err != nil {
return nil, err
}
a, err := ae.Encode()
if err != nil {
return nil, err
}
return append(b, a...), nil
}
// UnmarshalBinary unmarshals the contents of a byte slice into a AddressMessage.
func (m *AddressMessage) UnmarshalBinary(b []byte) error {
l := len(b)
if l < unix.SizeofIfAddrmsg {
return errInvalidAddressMessage
}
m.Family = uint8(b[0])
m.PrefixLength = uint8(b[1])
m.Flags = uint8(b[2])
m.Scope = uint8(b[3])
m.Index = nativeEndian.Uint32(b[4:8])
if l > unix.SizeofIfAddrmsg {
ad, err := netlink.NewAttributeDecoder(b[unix.SizeofIfAddrmsg:])
if err != nil {
return err
}
var aa AddressAttributes
if err := aa.decode(ad); err != nil {
return err
}
// Must consume errors from decoder before returning.
if err := ad.Err(); err != nil {
return fmt.Errorf("invalid address message attributes: %v", err)
}
m.Attributes = &aa
}
return nil
}
// rtMessage is an empty method to sattisfy the Message interface.
func (*AddressMessage) rtMessage() {}
// AddressService is used to retrieve rtnetlink family information.
type AddressService struct {
c *Conn
}
// New creates a new address using the AddressMessage information.
func (a *AddressService) New(req *AddressMessage) error {
flags := netlink.Request | netlink.Create | netlink.Acknowledge | netlink.Excl
_, err := a.c.Execute(req, unix.RTM_NEWADDR, flags)
if err != nil {
return err
}
return nil
}
// Delete removes an address using the AddressMessage information.
func (a *AddressService) Delete(req *AddressMessage) error {
flags := netlink.Request | netlink.Acknowledge
_, err := a.c.Execute(req, unix.RTM_DELADDR, flags)
if err != nil {
return err
}
return nil
}
// List retrieves all addresses.
func (a *AddressService) List() ([]AddressMessage, error) {
req := AddressMessage{}
flags := netlink.Request | netlink.Dump
msgs, err := a.c.Execute(&req, unix.RTM_GETADDR, flags)
if err != nil {
return nil, err
}
addresses := make([]AddressMessage, len(msgs))
for i := range msgs {
addresses[i] = *msgs[i].(*AddressMessage)
}
return addresses, nil
}
// AddressAttributes contains all attributes for an interface.
type AddressAttributes struct {
Address net.IP // Interface Ip address
Local net.IP // Local Ip address
Label string
Broadcast net.IP // Broadcast Ip address
Anycast net.IP // Anycast Ip address
CacheInfo CacheInfo // Address information
Multicast net.IP // Multicast Ip address
Flags uint32 // Address flags
}
func (a *AddressAttributes) decode(ad *netlink.AttributeDecoder) error {
for ad.Next() {
switch ad.Type() {
case unix.IFA_UNSPEC:
// unused attribute
case unix.IFA_ADDRESS:
ad.Do(decodeIP(&a.Address))
case unix.IFA_LOCAL:
ad.Do(decodeIP(&a.Local))
case unix.IFA_LABEL:
a.Label = ad.String()
case unix.IFA_BROADCAST:
ad.Do(decodeIP(&a.Broadcast))
case unix.IFA_ANYCAST:
ad.Do(decodeIP(&a.Anycast))
case unix.IFA_CACHEINFO:
ad.Do(a.CacheInfo.decode)
case unix.IFA_MULTICAST:
ad.Do(decodeIP(&a.Multicast))
case unix.IFA_FLAGS:
a.Flags = ad.Uint32()
}
}
return nil
}
func (a *AddressAttributes) encode(ae *netlink.AttributeEncoder) error {
ae.Uint16(unix.IFA_UNSPEC, 0)
ae.Do(unix.IFA_ADDRESS, encodeIP(a.Address))
if a.Local != nil {
ae.Do(unix.IFA_LOCAL, encodeIP(a.Local))
}
if a.Broadcast != nil {
ae.Do(unix.IFA_BROADCAST, encodeIP(a.Broadcast))
}
if a.Anycast != nil {
ae.Do(unix.IFA_ANYCAST, encodeIP(a.Anycast))
}
if a.Multicast != nil {
ae.Do(unix.IFA_MULTICAST, encodeIP(a.Multicast))
}
if a.Label != "" {
ae.String(unix.IFA_LABEL, a.Label)
}
ae.Uint32(unix.IFA_FLAGS, a.Flags)
return nil
}
// CacheInfo contains address information
type CacheInfo struct {
Prefered uint32
Valid uint32
Created uint32
Updated uint32
}
// decode decodes raw bytes into a CacheInfo's fields.
func (c *CacheInfo) decode(b []byte) error {
if len(b) != 16 {
return fmt.Errorf("rtnetlink: incorrect CacheInfo size, want: 16, got: %d", len(b))
}
c.Prefered = nativeEndian.Uint32(b[0:4])
c.Valid = nativeEndian.Uint32(b[4:8])
c.Created = nativeEndian.Uint32(b[8:12])
c.Updated = nativeEndian.Uint32(b[12:16])
return nil
}
// encodeIP is a helper for validating and encoding IPv4 and IPv6 addresses as
// appropriate for the specified netlink attribute type. It should be used
// with (*netlink.AttributeEncoder).Do.
func encodeIP(ip net.IP) func() ([]byte, error) {
return func() ([]byte, error) {
// Don't allow nil or non 4/16-byte addresses.
if ip == nil || ip.To16() == nil {
return nil, fmt.Errorf("rtnetlink: cannot encode invalid IP address: %s", ip)
}
if ip4 := ip.To4(); ip4 != nil {
// IPv4 address.
return ip4, nil
}
// IPv6 address.
return ip, nil
}
}
// decodeIP is a helper for validating and decoding IPv4 and IPv6 addresses as
// appropriate for the specified netlink attribute type. It should be used with
// (*netlink.AttributeDecoder).Do.
func decodeIP(ip *net.IP) func(b []byte) error {
return func(b []byte) error {
if l := len(b); l != 4 && l != 16 {
return fmt.Errorf("rtnetlink: invalid IP address length: %d", l)
}
// We cannot retain b outside the closure, so make a copy into ip.
*ip = make(net.IP, len(b))
copy(*ip, b)
return nil
}
}

197
vendor/github.com/jsimonetti/rtnetlink/conn.go generated vendored Normal file
View File

@@ -0,0 +1,197 @@
package rtnetlink
import (
"encoding"
"time"
"github.com/jsimonetti/rtnetlink/internal/unix"
"github.com/mdlayher/netlink"
)
// A Conn is a route netlink connection. A Conn can be used to send and
// receive route netlink messages to and from netlink.
type Conn struct {
c conn
Link *LinkService
Address *AddressService
Route *RouteService
Neigh *NeighService
Rule *RuleService
}
var _ conn = &netlink.Conn{}
// A conn is a netlink connection, which can be swapped for tests.
type conn interface {
Close() error
Send(m netlink.Message) (netlink.Message, error)
Receive() ([]netlink.Message, error)
Execute(m netlink.Message) ([]netlink.Message, error)
SetOption(option netlink.ConnOption, enable bool) error
SetReadDeadline(t time.Time) error
}
// Dial dials a route netlink connection. Config specifies optional
// configuration for the underlying netlink connection. If config is
// nil, a default configuration will be used.
func Dial(config *netlink.Config) (*Conn, error) {
c, err := netlink.Dial(unix.NETLINK_ROUTE, config)
if err != nil {
return nil, err
}
return newConn(c), nil
}
// newConn creates a Conn that wraps an existing *netlink.Conn for
// rtnetlink communications. It is used for testing.
func newConn(c conn) *Conn {
rtc := &Conn{
c: c,
}
rtc.Link = &LinkService{c: rtc}
rtc.Address = &AddressService{c: rtc}
rtc.Route = &RouteService{c: rtc}
rtc.Neigh = &NeighService{c: rtc}
rtc.Rule = &RuleService{c: rtc}
return rtc
}
// Close closes the connection.
func (c *Conn) Close() error {
return c.c.Close()
}
// SetOption enables or disables a netlink socket option for the Conn.
func (c *Conn) SetOption(option netlink.ConnOption, enable bool) error {
return c.c.SetOption(option, enable)
}
// SetReadDeadline sets the read deadline associated with the connection.
func (c *Conn) SetReadDeadline(t time.Time) error {
return c.c.SetReadDeadline(t)
}
// Send sends a single Message to netlink, wrapping it in a netlink.Message
// using the specified generic netlink family and flags. On success, Send
// returns a copy of the netlink.Message with all parameters populated, for
// later validation.
func (c *Conn) Send(m Message, family uint16, flags netlink.HeaderFlags) (netlink.Message, error) {
nm := netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType(family),
Flags: flags,
},
}
mb, err := m.MarshalBinary()
if err != nil {
return netlink.Message{}, err
}
nm.Data = mb
reqnm, err := c.c.Send(nm)
if err != nil {
return netlink.Message{}, err
}
return reqnm, nil
}
// Receive receives one or more Messages from netlink. The netlink.Messages
// used to wrap each Message are available for later validation.
func (c *Conn) Receive() ([]Message, []netlink.Message, error) {
msgs, err := c.c.Receive()
if err != nil {
return nil, nil, err
}
rtmsgs, err := unpackMessages(msgs)
if err != nil {
return nil, nil, err
}
return rtmsgs, msgs, nil
}
// Execute sends a single Message to netlink using Send, receives one or more
// replies using Receive, and then checks the validity of the replies against
// the request using netlink.Validate.
//
// Execute acquires a lock for the duration of the function call which blocks
// concurrent calls to Send and Receive, in order to ensure consistency between
// generic netlink request/reply messages.
//
// See the documentation of Send, Receive, and netlink.Validate for details
// about each function.
func (c *Conn) Execute(m Message, family uint16, flags netlink.HeaderFlags) ([]Message, error) {
nm, err := packMessage(m, family, flags)
if err != nil {
return nil, err
}
msgs, err := c.c.Execute(nm)
if err != nil {
return nil, err
}
return unpackMessages(msgs)
}
// Message is the interface used for passing around different kinds of rtnetlink messages
type Message interface {
encoding.BinaryMarshaler
encoding.BinaryUnmarshaler
rtMessage()
}
// packMessage packs a rtnetlink Message into a netlink.Message with the
// appropriate rtnetlink family and netlink flags.
func packMessage(m Message, family uint16, flags netlink.HeaderFlags) (netlink.Message, error) {
nm := netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType(family),
Flags: flags,
},
}
mb, err := m.MarshalBinary()
if err != nil {
return netlink.Message{}, err
}
nm.Data = mb
return nm, nil
}
// unpackMessages unpacks rtnetlink Messages from a slice of netlink.Messages.
func unpackMessages(msgs []netlink.Message) ([]Message, error) {
lmsgs := make([]Message, 0, len(msgs))
for _, nm := range msgs {
var m Message
switch nm.Header.Type {
case unix.RTM_GETLINK, unix.RTM_NEWLINK, unix.RTM_DELLINK:
m = &LinkMessage{}
case unix.RTM_GETADDR, unix.RTM_NEWADDR, unix.RTM_DELADDR:
m = &AddressMessage{}
case unix.RTM_GETROUTE, unix.RTM_NEWROUTE, unix.RTM_DELROUTE:
m = &RouteMessage{}
case unix.RTM_GETNEIGH, unix.RTM_NEWNEIGH, unix.RTM_DELNEIGH:
m = &NeighMessage{}
case unix.RTM_GETRULE, unix.RTM_NEWRULE, unix.RTM_DELRULE:
m = &RuleMessage{}
default:
continue
}
if err := (m).UnmarshalBinary(nm.Data); err != nil {
return nil, err
}
lmsgs = append(lmsgs, m)
}
return lmsgs, nil
}

27
vendor/github.com/jsimonetti/rtnetlink/doc.go generated vendored Normal file
View File

@@ -0,0 +1,27 @@
// Package rtnetlink allows the kernel's routing tables to be read and altered.
// Network routes, IP addresses, Link parameters, Neighbor setups, Queueing disciplines,
// Traffic classes and Packet classifiers may all be controlled.
// It is based on netlink messages.
//
// A convenient, high-level API wrapper is available using package rtnl:
// https://godoc.org/github.com/jsimonetti/rtnetlink/rtnl.
//
// The base rtnetlink library xplicitly only exposes a limited low-level API to rtnetlink.
// It is not the intention (nor wish) to create an iproute2 replacement.
//
// When in doubt about your message structure it can always be useful to look at the
// message send by iproute2 using 'strace -f -esendmsg' or similar.
//
// Another (and possibly even more flexible) way would be using 'nlmon' and wireshark.
// nlmod is a special kernel module which allows you to capture all (not just rtnetlink)
// netlink traffic inside the kernel. Be aware that this might be overwhelming on a system
// with a lot of netlink traffic.
//
// # modprobe nlmon
// # ip link add type nlmon
// # ip link set nlmon0 up
//
// At this point use wireshark or tcpdump on the nlmon0 interface to view all netlink traffic.
//
// Have a look at the examples for common uses of rtnetlink.
package rtnetlink

13
vendor/github.com/jsimonetti/rtnetlink/endian.go generated vendored Normal file
View File

@@ -0,0 +1,13 @@
package rtnetlink
import (
"encoding/binary"
"github.com/mdlayher/netlink/nlenc"
)
var nativeEndian binary.ByteOrder
func init() {
nativeEndian = nlenc.NativeEndian()
}

15
vendor/github.com/jsimonetti/rtnetlink/fuzz-shell.nix generated vendored Normal file
View File

@@ -0,0 +1,15 @@
with import <nixpkgs> { };
pkgs.mkShell {
name = "go-fuzz";
buildInputs = [ go ];
shellHook = ''
echo "Fuzz with commands:"
echo ""
echo "go test -fuzz=AddressMessage - will start fuzzing Address Messages"
echo "go test -fuzz=LinkMessage - will start fuzzing Link Messages"
echo "go test -fuzz=NeighMessage - will start fuzzing Neigh Messages"
echo "go test -fuzz=RouteMessage - will start fuzzing Route Messages"
echo "go test -fuzz=RuleMessage - will start fuzzing Rule Messages"
echo ""
'';
}

View File

@@ -0,0 +1,150 @@
//go:build linux
// +build linux
package unix
import (
linux "golang.org/x/sys/unix"
)
const (
AF_INET = linux.AF_INET
AF_INET6 = linux.AF_INET6
AF_UNSPEC = linux.AF_UNSPEC
NETLINK_ROUTE = linux.NETLINK_ROUTE
SizeofIfAddrmsg = linux.SizeofIfAddrmsg
SizeofIfInfomsg = linux.SizeofIfInfomsg
SizeofNdMsg = linux.SizeofNdMsg
SizeofRtMsg = linux.SizeofRtMsg
SizeofRtNexthop = linux.SizeofRtNexthop
RTM_NEWADDR = linux.RTM_NEWADDR
RTM_DELADDR = linux.RTM_DELADDR
RTM_GETADDR = linux.RTM_GETADDR
RTM_NEWLINK = linux.RTM_NEWLINK
RTM_DELLINK = linux.RTM_DELLINK
RTM_GETLINK = linux.RTM_GETLINK
RTM_SETLINK = linux.RTM_SETLINK
RTM_NEWROUTE = linux.RTM_NEWROUTE
RTM_DELROUTE = linux.RTM_DELROUTE
RTM_GETROUTE = linux.RTM_GETROUTE
RTM_NEWNEIGH = linux.RTM_NEWNEIGH
RTM_DELNEIGH = linux.RTM_DELNEIGH
RTM_GETNEIGH = linux.RTM_GETNEIGH
IFA_UNSPEC = linux.IFA_UNSPEC
IFA_ADDRESS = linux.IFA_ADDRESS
IFA_LOCAL = linux.IFA_LOCAL
IFA_LABEL = linux.IFA_LABEL
IFA_BROADCAST = linux.IFA_BROADCAST
IFA_ANYCAST = linux.IFA_ANYCAST
IFA_CACHEINFO = linux.IFA_CACHEINFO
IFA_MULTICAST = linux.IFA_MULTICAST
IFA_FLAGS = linux.IFA_FLAGS
IFF_UP = linux.IFF_UP
IFF_BROADCAST = linux.IFF_BROADCAST
IFF_LOOPBACK = linux.IFF_LOOPBACK
IFF_POINTOPOINT = linux.IFF_POINTOPOINT
IFF_MULTICAST = linux.IFF_MULTICAST
IFLA_UNSPEC = linux.IFLA_UNSPEC
IFLA_ADDRESS = linux.IFLA_ADDRESS
IFLA_BROADCAST = linux.IFLA_BROADCAST
IFLA_IFNAME = linux.IFLA_IFNAME
IFLA_MTU = linux.IFLA_MTU
IFLA_LINK = linux.IFLA_LINK
IFLA_QDISC = linux.IFLA_QDISC
IFLA_OPERSTATE = linux.IFLA_OPERSTATE
IFLA_STATS = linux.IFLA_STATS
IFLA_STATS64 = linux.IFLA_STATS64
IFLA_TXQLEN = linux.IFLA_TXQLEN
IFLA_GROUP = linux.IFLA_GROUP
IFLA_LINKINFO = linux.IFLA_LINKINFO
IFLA_LINKMODE = linux.IFLA_LINKMODE
IFLA_IFALIAS = linux.IFLA_IFALIAS
IFLA_MASTER = linux.IFLA_MASTER
IFLA_CARRIER = linux.IFLA_CARRIER
IFLA_CARRIER_CHANGES = linux.IFLA_CARRIER_CHANGES
IFLA_CARRIER_UP_COUNT = linux.IFLA_CARRIER_UP_COUNT
IFLA_CARRIER_DOWN_COUNT = linux.IFLA_CARRIER_DOWN_COUNT
IFLA_PHYS_PORT_ID = linux.IFLA_PHYS_PORT_ID
IFLA_PHYS_SWITCH_ID = linux.IFLA_PHYS_SWITCH_ID
IFLA_PHYS_PORT_NAME = linux.IFLA_PHYS_PORT_NAME
IFLA_INFO_KIND = linux.IFLA_INFO_KIND
IFLA_INFO_SLAVE_KIND = linux.IFLA_INFO_SLAVE_KIND
IFLA_INFO_DATA = linux.IFLA_INFO_DATA
IFLA_INFO_SLAVE_DATA = linux.IFLA_INFO_SLAVE_DATA
IFLA_XDP = linux.IFLA_XDP
IFLA_XDP_FD = linux.IFLA_XDP_FD
IFLA_XDP_ATTACHED = linux.IFLA_XDP_ATTACHED
IFLA_XDP_FLAGS = linux.IFLA_XDP_FLAGS
IFLA_XDP_PROG_ID = linux.IFLA_XDP_PROG_ID
IFLA_XDP_EXPECTED_FD = linux.IFLA_XDP_EXPECTED_FD
XDP_FLAGS_DRV_MODE = linux.XDP_FLAGS_DRV_MODE
XDP_FLAGS_SKB_MODE = linux.XDP_FLAGS_SKB_MODE
XDP_FLAGS_HW_MODE = linux.XDP_FLAGS_HW_MODE
XDP_FLAGS_MODES = linux.XDP_FLAGS_MODES
XDP_FLAGS_MASK = linux.XDP_FLAGS_MASK
XDP_FLAGS_REPLACE = linux.XDP_FLAGS_REPLACE
XDP_FLAGS_UPDATE_IF_NOEXIST = linux.XDP_FLAGS_UPDATE_IF_NOEXIST
LWTUNNEL_ENCAP_MPLS = linux.LWTUNNEL_ENCAP_MPLS
MPLS_IPTUNNEL_DST = linux.MPLS_IPTUNNEL_DST
MPLS_IPTUNNEL_TTL = linux.MPLS_IPTUNNEL_TTL
NDA_UNSPEC = linux.NDA_UNSPEC
NDA_DST = linux.NDA_DST
NDA_LLADDR = linux.NDA_LLADDR
NDA_CACHEINFO = linux.NDA_CACHEINFO
NDA_IFINDEX = linux.NDA_IFINDEX
RTA_UNSPEC = linux.RTA_UNSPEC
RTA_DST = linux.RTA_DST
RTA_ENCAP = linux.RTA_ENCAP
RTA_ENCAP_TYPE = linux.RTA_ENCAP_TYPE
RTA_PREFSRC = linux.RTA_PREFSRC
RTA_GATEWAY = linux.RTA_GATEWAY
RTA_OIF = linux.RTA_OIF
RTA_PRIORITY = linux.RTA_PRIORITY
RTA_TABLE = linux.RTA_TABLE
RTA_MARK = linux.RTA_MARK
RTA_EXPIRES = linux.RTA_EXPIRES
RTA_METRICS = linux.RTA_METRICS
RTA_MULTIPATH = linux.RTA_MULTIPATH
RTA_PREF = linux.RTA_PREF
RTAX_ADVMSS = linux.RTAX_ADVMSS
RTAX_FEATURES = linux.RTAX_FEATURES
RTAX_INITCWND = linux.RTAX_INITCWND
RTAX_INITRWND = linux.RTAX_INITRWND
RTAX_MTU = linux.RTAX_MTU
NTF_PROXY = linux.NTF_PROXY
RTN_UNICAST = linux.RTN_UNICAST
RT_TABLE_MAIN = linux.RT_TABLE_MAIN
RTPROT_BOOT = linux.RTPROT_BOOT
RTPROT_STATIC = linux.RTPROT_STATIC
RT_SCOPE_UNIVERSE = linux.RT_SCOPE_UNIVERSE
RT_SCOPE_HOST = linux.RT_SCOPE_HOST
RT_SCOPE_LINK = linux.RT_SCOPE_LINK
RTM_NEWRULE = linux.RTM_NEWRULE
RTM_GETRULE = linux.RTM_GETRULE
RTM_DELRULE = linux.RTM_DELRULE
FRA_UNSPEC = linux.FRA_UNSPEC
FRA_DST = linux.FRA_DST
FRA_SRC = linux.FRA_SRC
FRA_IIFNAME = linux.FRA_IIFNAME
FRA_GOTO = linux.FRA_GOTO
FRA_UNUSED2 = linux.FRA_UNUSED2
FRA_PRIORITY = linux.FRA_PRIORITY
FRA_UNUSED3 = linux.FRA_UNUSED3
FRA_UNUSED4 = linux.FRA_UNUSED4
FRA_UNUSED5 = linux.FRA_UNUSED5
FRA_FWMARK = linux.FRA_FWMARK
FRA_FLOW = linux.FRA_FLOW
FRA_TUN_ID = linux.FRA_TUN_ID
FRA_SUPPRESS_IFGROUP = linux.FRA_SUPPRESS_IFGROUP
FRA_SUPPRESS_PREFIXLEN = linux.FRA_SUPPRESS_PREFIXLEN
FRA_TABLE = linux.FRA_TABLE
FRA_FWMASK = linux.FRA_FWMASK
FRA_OIFNAME = linux.FRA_OIFNAME
FRA_PAD = linux.FRA_PAD
FRA_L3MDEV = linux.FRA_L3MDEV
FRA_UID_RANGE = linux.FRA_UID_RANGE
FRA_PROTOCOL = linux.FRA_PROTOCOL
FRA_IP_PROTO = linux.FRA_IP_PROTO
FRA_SPORT_RANGE = linux.FRA_SPORT_RANGE
FRA_DPORT_RANGE = linux.FRA_DPORT_RANGE
)

View File

@@ -0,0 +1,146 @@
//go:build !linux
// +build !linux
package unix
const (
AF_INET = 0x2
AF_INET6 = 0xa
AF_UNSPEC = 0x0
NETLINK_ROUTE = 0x0
SizeofIfAddrmsg = 0x8
SizeofIfInfomsg = 0x10
SizeofNdMsg = 0xc
SizeofRtMsg = 0xc
SizeofRtNexthop = 0x8
RTM_NEWADDR = 0x14
RTM_DELADDR = 0x15
RTM_GETADDR = 0x16
RTM_NEWLINK = 0x10
RTM_DELLINK = 0x11
RTM_GETLINK = 0x12
RTM_SETLINK = 0x13
RTM_NEWROUTE = 0x18
RTM_DELROUTE = 0x19
RTM_GETROUTE = 0x1a
RTM_NEWNEIGH = 0x1c
RTM_DELNEIGH = 0x1d
RTM_GETNEIGH = 0x1e
IFA_UNSPEC = 0x0
IFA_ADDRESS = 0x1
IFA_LOCAL = 0x2
IFA_LABEL = 0x3
IFA_BROADCAST = 0x4
IFA_ANYCAST = 0x5
IFA_CACHEINFO = 0x6
IFA_MULTICAST = 0x7
IFA_FLAGS = 0x8
IFF_UP = 0x1
IFF_BROADCAST = 0x2
IFF_LOOPBACK = 0x8
IFF_POINTOPOINT = 0x10
IFF_MULTICAST = 0x1000
IFLA_UNSPEC = 0x0
IFLA_ADDRESS = 0x1
IFLA_BROADCAST = 0x2
IFLA_IFNAME = 0x3
IFLA_MTU = 0x4
IFLA_LINK = 0x5
IFLA_QDISC = 0x6
IFLA_OPERSTATE = 0x10
IFLA_STATS = 0x7
IFLA_STATS64 = 0x17
IFLA_TXQLEN = 0xd
IFLA_GROUP = 0x1b
IFLA_LINKINFO = 0x12
IFLA_LINKMODE = 0x11
IFLA_IFALIAS = 0x14
IFLA_MASTER = 0xa
IFLA_CARRIER = 0x21
IFLA_CARRIER_CHANGES = 0x23
IFLA_CARRIER_UP_COUNT = 0x2f
IFLA_CARRIER_DOWN_COUNT = 0x30
IFLA_PHYS_PORT_ID = 0x22
IFLA_PHYS_SWITCH_ID = 0x24
IFLA_PHYS_PORT_NAME = 0x26
IFLA_INFO_KIND = 0x1
IFLA_INFO_SLAVE_KIND = 0x4
IFLA_INFO_DATA = 0x2
IFLA_INFO_SLAVE_DATA = 0x5
IFLA_XDP = 0x2b
IFLA_XDP_FD = 0x1
IFLA_XDP_ATTACHED = 0x2
IFLA_XDP_FLAGS = 0x3
IFLA_XDP_PROG_ID = 0x4
IFLA_XDP_EXPECTED_FD = 0x8
XDP_FLAGS_DRV_MODE = 0x4
XDP_FLAGS_SKB_MODE = 0x2
XDP_FLAGS_HW_MODE = 0x8
XDP_FLAGS_MODES = 0xe
XDP_FLAGS_MASK = 0x1f
XDP_FLAGS_REPLACE = 0x10
XDP_FLAGS_UPDATE_IF_NOEXIST = 0x1
LWTUNNEL_ENCAP_MPLS = 0x1
MPLS_IPTUNNEL_DST = 0x1
MPLS_IPTUNNEL_TTL = 0x2
NDA_UNSPEC = 0x0
NDA_DST = 0x1
NDA_LLADDR = 0x2
NDA_CACHEINFO = 0x3
NDA_IFINDEX = 0x8
RTA_UNSPEC = 0x0
RTA_DST = 0x1
RTA_ENCAP = 0x16
RTA_ENCAP_TYPE = 0x15
RTA_PREFSRC = 0x7
RTA_GATEWAY = 0x5
RTA_OIF = 0x4
RTA_PRIORITY = 0x6
RTA_TABLE = 0xf
RTA_MARK = 0x10
RTA_EXPIRES = 0x17
RTA_METRICS = 0x8
RTA_MULTIPATH = 0x9
RTA_PREF = 0x14
RTAX_ADVMSS = 0x8
RTAX_FEATURES = 0xc
RTAX_INITCWND = 0xb
RTAX_INITRWND = 0xe
RTAX_MTU = 0x2
NTF_PROXY = 0x8
RTN_UNICAST = 0x1
RT_TABLE_MAIN = 0xfe
RTPROT_BOOT = 0x3
RTPROT_STATIC = 0x4
RT_SCOPE_UNIVERSE = 0x0
RT_SCOPE_HOST = 0xfe
RT_SCOPE_LINK = 0xfd
RTM_NEWRULE = 0x20
RTM_GETRULE = 0x22
RTM_DELRULE = 0x21
FRA_UNSPEC = 0x0
FRA_DST = 0x1
FRA_SRC = 0x2
FRA_IIFNAME = 0x3
FRA_GOTO = 0x4
FRA_UNUSED2 = 0x5
FRA_PRIORITY = 0x6
FRA_UNUSED3 = 0x7
FRA_UNUSED4 = 0x8
FRA_UNUSED5 = 0x9
FRA_FWMARK = 0xa
FRA_FLOW = 0xb
FRA_TUN_ID = 0xc
FRA_SUPPRESS_IFGROUP = 0xd
FRA_SUPPRESS_PREFIXLEN = 0xe
FRA_TABLE = 0xf
FRA_FWMASK = 0x10
FRA_OIFNAME = 0x11
FRA_PAD = 0x12
FRA_L3MDEV = 0x13
FRA_UID_RANGE = 0x14
FRA_PROTOCOL = 0x15
FRA_IP_PROTO = 0x16
FRA_SPORT_RANGE = 0x17
FRA_DPORT_RANGE = 0x18
)

622
vendor/github.com/jsimonetti/rtnetlink/link.go generated vendored Normal file
View File

@@ -0,0 +1,622 @@
package rtnetlink
import (
"errors"
"fmt"
"net"
"github.com/jsimonetti/rtnetlink/internal/unix"
"github.com/mdlayher/netlink"
)
var (
// errInvalidLinkMessage is returned when a LinkMessage is malformed.
errInvalidLinkMessage = errors.New("rtnetlink LinkMessage is invalid or too short")
// errInvalidLinkMessageAttr is returned when link attributes are malformed.
errInvalidLinkMessageAttr = errors.New("rtnetlink LinkMessage has a wrong attribute data length")
)
var _ Message = &LinkMessage{}
// A LinkMessage is a route netlink link message.
type LinkMessage struct {
// Always set to AF_UNSPEC (0)
Family uint16
// Device Type
Type uint16
// Unique interface index, using a nonzero value with
// NewLink will instruct the kernel to create a
// device with the given index (kernel 3.7+ required)
Index uint32
// Contains device flags, see netdevice(7)
Flags uint32
// Change Flags, specifies which flags will be affected by the Flags field
Change uint32
// Attributes List
Attributes *LinkAttributes
}
// MarshalBinary marshals a LinkMessage into a byte slice.
func (m *LinkMessage) MarshalBinary() ([]byte, error) {
b := make([]byte, unix.SizeofIfInfomsg)
b[0] = 0 // Family
b[1] = 0 // reserved
nativeEndian.PutUint16(b[2:4], m.Type)
nativeEndian.PutUint32(b[4:8], m.Index)
nativeEndian.PutUint32(b[8:12], m.Flags)
nativeEndian.PutUint32(b[12:16], m.Change)
if m.Attributes != nil {
ae := netlink.NewAttributeEncoder()
ae.ByteOrder = nativeEndian
err := m.Attributes.encode(ae)
if err != nil {
return nil, err
}
a, err := ae.Encode()
if err != nil {
return nil, err
}
return append(b, a...), nil
}
return b, nil
}
// UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (m *LinkMessage) UnmarshalBinary(b []byte) error {
l := len(b)
if l < unix.SizeofIfInfomsg {
return errInvalidLinkMessage
}
m.Family = nativeEndian.Uint16(b[0:2])
m.Type = nativeEndian.Uint16(b[2:4])
m.Index = nativeEndian.Uint32(b[4:8])
m.Flags = nativeEndian.Uint32(b[8:12])
m.Change = nativeEndian.Uint32(b[12:16])
if l > unix.SizeofIfInfomsg {
m.Attributes = &LinkAttributes{}
ad, err := netlink.NewAttributeDecoder(b[16:])
if err != nil {
return err
}
ad.ByteOrder = nativeEndian
err = m.Attributes.decode(ad)
if err != nil {
return err
}
}
return nil
}
// rtMessage is an empty method to sattisfy the Message interface.
func (*LinkMessage) rtMessage() {}
// LinkService is used to retrieve rtnetlink family information.
type LinkService struct {
c *Conn
}
// execute executes the request and returns the messages as a LinkMessage slice
func (l *LinkService) execute(m Message, family uint16, flags netlink.HeaderFlags) ([]LinkMessage, error) {
msgs, err := l.c.Execute(m, family, flags)
links := make([]LinkMessage, len(msgs))
for i := range msgs {
links[i] = *msgs[i].(*LinkMessage)
}
return links, err
}
// New creates a new interface using the LinkMessage information.
func (l *LinkService) New(req *LinkMessage) error {
flags := netlink.Request | netlink.Create | netlink.Acknowledge | netlink.Excl
_, err := l.execute(req, unix.RTM_NEWLINK, flags)
return err
}
// Delete removes an interface by index.
func (l *LinkService) Delete(index uint32) error {
req := &LinkMessage{
Index: index,
}
flags := netlink.Request | netlink.Acknowledge
_, err := l.c.Execute(req, unix.RTM_DELLINK, flags)
return err
}
// Get retrieves interface information by index.
func (l *LinkService) Get(index uint32) (LinkMessage, error) {
req := &LinkMessage{
Index: index,
}
flags := netlink.Request | netlink.DumpFiltered
links, err := l.execute(req, unix.RTM_GETLINK, flags)
if len(links) != 1 {
return LinkMessage{}, fmt.Errorf("too many/little matches, expected 1, actual %d", len(links))
}
return links[0], err
}
// Set sets interface attributes according to the LinkMessage information.
//
// ref: https://lwn.net/Articles/236919/
// We explicitly use RTM_NEWLINK to set link attributes instead of
// RTM_SETLINK because:
// - using RTM_SETLINK is actually an old rtnetlink API, not supporting most
// attributes common today
// - using RTM_NEWLINK is the prefered way to create AND update links
// - RTM_NEWLINK is backward compatible to RTM_SETLINK
func (l *LinkService) Set(req *LinkMessage) error {
flags := netlink.Request | netlink.Acknowledge
_, err := l.c.Execute(req, unix.RTM_NEWLINK, flags)
return err
}
func (l *LinkService) list(kind string) ([]LinkMessage, error) {
req := &LinkMessage{}
if kind != "" {
req.Attributes = &LinkAttributes{
Info: &LinkInfo{Kind: kind},
}
}
flags := netlink.Request | netlink.Dump
return l.execute(req, unix.RTM_GETLINK, flags)
}
// ListByKind retrieves all interfaces of a specific kind.
func (l *LinkService) ListByKind(kind string) ([]LinkMessage, error) {
return l.list(kind)
}
// List retrieves all interfaces.
func (l *LinkService) List() ([]LinkMessage, error) {
return l.list("")
}
// LinkAttributes contains all attributes for an interface.
type LinkAttributes struct {
Address net.HardwareAddr // Interface L2 address
Alias *string // Interface alias name
Broadcast net.HardwareAddr // L2 broadcast address
Carrier *uint8 // Current physical link state of the interface.
CarrierChanges *uint32 // Number of times the link has seen a change from UP to DOWN and vice versa
CarrierUpCount *uint32 // Number of times the link has been up
CarrierDownCount *uint32 // Number of times the link has been down
Index *uint32 // System-wide interface unique index identifier
Info *LinkInfo // Detailed Interface Information
LinkMode *uint8 // Interface link mode
MTU uint32 // MTU of the device
Name string // Device name
NetDevGroup *uint32 // Interface network device group
OperationalState OperationalState // Interface operation state
PhysPortID *string // Interface unique physical port identifier within the NIC
PhysPortName *string // Interface physical port name within the NIC
PhysSwitchID *string // Unique physical switch identifier of a switch this port belongs to
QueueDisc string // Queueing discipline
Master *uint32 // Master device index (0 value un-enslaves)
Stats *LinkStats // Interface Statistics
Stats64 *LinkStats64 // Interface Statistics (64 bits version)
TxQueueLen *uint32 // Interface transmit queue len in number of packets
Type uint32 // Link type
XDP *LinkXDP // Express Data Patch Information
}
// OperationalState represents an interface's operational state.
type OperationalState uint8
// Constants that represent operational state of an interface
//
// Adapted from https://elixir.bootlin.com/linux/v4.19.2/source/include/uapi/linux/if.h#L166
const (
OperStateUnknown OperationalState = iota // status could not be determined
OperStateNotPresent // down, due to some missing component (typically hardware)
OperStateDown // down, either administratively or due to a fault
OperStateLowerLayerDown // down, due to lower-layer interfaces
OperStateTesting // operationally down, in some test mode
OperStateDormant // down, waiting for some external event
OperStateUp // interface is in a state to send and receive packets
)
// unmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (a *LinkAttributes) decode(ad *netlink.AttributeDecoder) error {
for ad.Next() {
switch ad.Type() {
case unix.IFLA_UNSPEC:
// unused attribute
case unix.IFLA_ADDRESS:
l := len(ad.Bytes())
if l < 4 || l > 32 {
return errInvalidLinkMessageAttr
}
a.Address = ad.Bytes()
case unix.IFLA_IFALIAS:
v := ad.String()
a.Alias = &v
case unix.IFLA_BROADCAST:
l := len(ad.Bytes())
if l < 4 || l > 32 {
return errInvalidLinkMessageAttr
}
a.Broadcast = ad.Bytes()
case unix.IFLA_CARRIER:
v := ad.Uint8()
a.Carrier = &v
case unix.IFLA_CARRIER_CHANGES:
v := ad.Uint32()
a.CarrierChanges = &v
case unix.IFLA_CARRIER_UP_COUNT:
v := ad.Uint32()
a.CarrierUpCount = &v
case unix.IFLA_CARRIER_DOWN_COUNT:
v := ad.Uint32()
a.CarrierDownCount = &v
case unix.IFLA_GROUP:
v := ad.Uint32()
a.NetDevGroup = &v
case unix.IFLA_MTU:
a.MTU = ad.Uint32()
case unix.IFLA_IFNAME:
a.Name = ad.String()
case unix.IFLA_LINK:
a.Type = ad.Uint32()
case unix.IFLA_LINKINFO:
a.Info = &LinkInfo{}
ad.Nested(a.Info.decode)
case unix.IFLA_LINKMODE:
v := ad.Uint8()
a.LinkMode = &v
case unix.IFLA_MASTER:
v := ad.Uint32()
a.Master = &v
case unix.IFLA_OPERSTATE:
a.OperationalState = OperationalState(ad.Uint8())
case unix.IFLA_PHYS_PORT_ID:
v := ad.String()
a.PhysPortID = &v
case unix.IFLA_PHYS_SWITCH_ID:
v := ad.String()
a.PhysSwitchID = &v
case unix.IFLA_PHYS_PORT_NAME:
v := ad.String()
a.PhysPortName = &v
case unix.IFLA_QDISC:
a.QueueDisc = ad.String()
case unix.IFLA_STATS:
a.Stats = &LinkStats{}
err := a.Stats.unmarshalBinary(ad.Bytes())
if err != nil {
return err
}
case unix.IFLA_STATS64:
a.Stats64 = &LinkStats64{}
err := a.Stats64.unmarshalBinary(ad.Bytes())
if err != nil {
return err
}
case unix.IFLA_TXQLEN:
v := ad.Uint32()
a.TxQueueLen = &v
case unix.IFLA_XDP:
a.XDP = &LinkXDP{}
ad.Nested(a.XDP.decode)
}
}
return nil
}
// MarshalBinary marshals a LinkAttributes into a byte slice.
func (a *LinkAttributes) encode(ae *netlink.AttributeEncoder) error {
ae.Uint16(unix.IFLA_UNSPEC, 0)
ae.String(unix.IFLA_IFNAME, a.Name)
ae.Uint32(unix.IFLA_LINK, a.Type)
ae.String(unix.IFLA_QDISC, a.QueueDisc)
if a.MTU != 0 {
ae.Uint32(unix.IFLA_MTU, a.MTU)
}
if len(a.Address) != 0 {
ae.Bytes(unix.IFLA_ADDRESS, a.Address)
}
if len(a.Broadcast) != 0 {
ae.Bytes(unix.IFLA_BROADCAST, a.Broadcast)
}
if a.OperationalState != OperStateUnknown {
ae.Uint8(unix.IFLA_OPERSTATE, uint8(a.OperationalState))
}
if a.Info != nil {
nae := netlink.NewAttributeEncoder()
nae.ByteOrder = ae.ByteOrder
err := a.Info.encode(nae)
if err != nil {
return err
}
b, err := nae.Encode()
if err != nil {
return err
}
ae.Bytes(unix.IFLA_LINKINFO, b)
}
if a.XDP != nil {
nae := netlink.NewAttributeEncoder()
nae.ByteOrder = ae.ByteOrder
err := a.XDP.encode(nae)
if err != nil {
return err
}
b, err := nae.Encode()
if err != nil {
return err
}
ae.Bytes(unix.IFLA_XDP, b)
}
if a.Master != nil {
ae.Uint32(unix.IFLA_MASTER, *a.Master)
}
return nil
}
// LinkStats contains packet statistics
type LinkStats struct {
RXPackets uint32 // total packets received
TXPackets uint32 // total packets transmitted
RXBytes uint32 // total bytes received
TXBytes uint32 // total bytes transmitted
RXErrors uint32 // bad packets received
TXErrors uint32 // packet transmit problems
RXDropped uint32 // no space in linux buffers
TXDropped uint32 // no space available in linux
Multicast uint32 // multicast packets received
Collisions uint32
// detailed rx_errors:
RXLengthErrors uint32
RXOverErrors uint32 // receiver ring buff overflow
RXCRCErrors uint32 // recved pkt with crc error
RXFrameErrors uint32 // recv'd frame alignment error
RXFIFOErrors uint32 // recv'r fifo overrun
RXMissedErrors uint32 // receiver missed packet
// detailed tx_errors
TXAbortedErrors uint32
TXCarrierErrors uint32
TXFIFOErrors uint32
TXHeartbeatErrors uint32
TXWindowErrors uint32
// for cslip etc
RXCompressed uint32
TXCompressed uint32
RXNoHandler uint32 // dropped, no handler found
}
// unmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (a *LinkStats) unmarshalBinary(b []byte) error {
l := len(b)
if l != 92 && l != 96 {
return fmt.Errorf("incorrect LinkMessage size, want: 92 or 96, got: %d", len(b))
}
a.RXPackets = nativeEndian.Uint32(b[0:4])
a.TXPackets = nativeEndian.Uint32(b[4:8])
a.RXBytes = nativeEndian.Uint32(b[8:12])
a.TXBytes = nativeEndian.Uint32(b[12:16])
a.RXErrors = nativeEndian.Uint32(b[16:20])
a.TXErrors = nativeEndian.Uint32(b[20:24])
a.RXDropped = nativeEndian.Uint32(b[24:28])
a.TXDropped = nativeEndian.Uint32(b[28:32])
a.Multicast = nativeEndian.Uint32(b[32:36])
a.Collisions = nativeEndian.Uint32(b[36:40])
a.RXLengthErrors = nativeEndian.Uint32(b[40:44])
a.RXOverErrors = nativeEndian.Uint32(b[44:48])
a.RXCRCErrors = nativeEndian.Uint32(b[48:52])
a.RXFrameErrors = nativeEndian.Uint32(b[52:56])
a.RXFIFOErrors = nativeEndian.Uint32(b[56:60])
a.RXMissedErrors = nativeEndian.Uint32(b[60:64])
a.TXAbortedErrors = nativeEndian.Uint32(b[64:68])
a.TXCarrierErrors = nativeEndian.Uint32(b[68:72])
a.TXFIFOErrors = nativeEndian.Uint32(b[72:76])
a.TXHeartbeatErrors = nativeEndian.Uint32(b[76:80])
a.TXWindowErrors = nativeEndian.Uint32(b[80:84])
a.RXCompressed = nativeEndian.Uint32(b[84:88])
a.TXCompressed = nativeEndian.Uint32(b[88:92])
if l == 96 { // kernel 4.6+
a.RXNoHandler = nativeEndian.Uint32(b[92:96])
}
return nil
}
// LinkStats64 contains packet statistics
type LinkStats64 struct {
RXPackets uint64 // total packets received
TXPackets uint64 // total packets transmitted
RXBytes uint64 // total bytes received
TXBytes uint64 // total bytes transmitted
RXErrors uint64 // bad packets received
TXErrors uint64 // packet transmit problems
RXDropped uint64 // no space in linux buffers
TXDropped uint64 // no space available in linux
Multicast uint64 // multicast packets received
Collisions uint64
// detailed rx_errors:
RXLengthErrors uint64
RXOverErrors uint64 // receiver ring buff overflow
RXCRCErrors uint64 // recved pkt with crc error
RXFrameErrors uint64 // recv'd frame alignment error
RXFIFOErrors uint64 // recv'r fifo overrun
RXMissedErrors uint64 // receiver missed packet
// detailed tx_errors
TXAbortedErrors uint64
TXCarrierErrors uint64
TXFIFOErrors uint64
TXHeartbeatErrors uint64
TXWindowErrors uint64
// for cslip etc
RXCompressed uint64
TXCompressed uint64
RXNoHandler uint64 // dropped, no handler found
RXOtherhostDropped uint64 // Number of packets dropped due to mismatch in destination MAC address.
}
// unmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (a *LinkStats64) unmarshalBinary(b []byte) error {
l := len(b)
if l != 184 && l != 192 && l != 200 {
return fmt.Errorf("incorrect size, want: 184 or 192 or 200")
}
a.RXPackets = nativeEndian.Uint64(b[0:8])
a.TXPackets = nativeEndian.Uint64(b[8:16])
a.RXBytes = nativeEndian.Uint64(b[16:24])
a.TXBytes = nativeEndian.Uint64(b[24:32])
a.RXErrors = nativeEndian.Uint64(b[32:40])
a.TXErrors = nativeEndian.Uint64(b[40:48])
a.RXDropped = nativeEndian.Uint64(b[48:56])
a.TXDropped = nativeEndian.Uint64(b[56:64])
a.Multicast = nativeEndian.Uint64(b[64:72])
a.Collisions = nativeEndian.Uint64(b[72:80])
a.RXLengthErrors = nativeEndian.Uint64(b[80:88])
a.RXOverErrors = nativeEndian.Uint64(b[88:96])
a.RXCRCErrors = nativeEndian.Uint64(b[96:104])
a.RXFrameErrors = nativeEndian.Uint64(b[104:112])
a.RXFIFOErrors = nativeEndian.Uint64(b[112:120])
a.RXMissedErrors = nativeEndian.Uint64(b[120:128])
a.TXAbortedErrors = nativeEndian.Uint64(b[128:136])
a.TXCarrierErrors = nativeEndian.Uint64(b[136:144])
a.TXFIFOErrors = nativeEndian.Uint64(b[144:152])
a.TXHeartbeatErrors = nativeEndian.Uint64(b[152:160])
a.TXWindowErrors = nativeEndian.Uint64(b[160:168])
a.RXCompressed = nativeEndian.Uint64(b[168:176])
a.TXCompressed = nativeEndian.Uint64(b[176:184])
if l > 191 { // kernel 4.6+
a.RXNoHandler = nativeEndian.Uint64(b[184:192])
}
if l > 199 { // kernel 5.19+
a.RXOtherhostDropped = nativeEndian.Uint64(b[192:200])
}
return nil
}
// LinkInfo contains data for specific network types
type LinkInfo struct {
Kind string // Driver name
Data []byte // Driver specific configuration stored as nested Netlink messages
SlaveKind string // Slave driver name
SlaveData []byte // Slave driver specific configuration
}
func (i *LinkInfo) decode(ad *netlink.AttributeDecoder) error {
for ad.Next() {
switch ad.Type() {
case unix.IFLA_INFO_KIND:
i.Kind = ad.String()
case unix.IFLA_INFO_SLAVE_KIND:
i.SlaveKind = ad.String()
case unix.IFLA_INFO_DATA:
i.Data = ad.Bytes()
case unix.IFLA_INFO_SLAVE_DATA:
i.SlaveData = ad.Bytes()
}
}
return nil
}
func (i *LinkInfo) encode(ae *netlink.AttributeEncoder) error {
ae.String(unix.IFLA_INFO_KIND, i.Kind)
ae.Bytes(unix.IFLA_INFO_DATA, i.Data)
if len(i.SlaveData) > 0 {
ae.String(unix.IFLA_INFO_SLAVE_KIND, i.SlaveKind)
ae.Bytes(unix.IFLA_INFO_SLAVE_DATA, i.SlaveData)
}
return nil
}
// LinkXDP holds Express Data Path specific information
type LinkXDP struct {
FD int32
ExpectedFD int32
Attached uint8
Flags uint32
ProgID uint32
}
func (xdp *LinkXDP) decode(ad *netlink.AttributeDecoder) error {
for ad.Next() {
switch ad.Type() {
case unix.IFLA_XDP_FD:
xdp.FD = ad.Int32()
case unix.IFLA_XDP_EXPECTED_FD:
xdp.ExpectedFD = ad.Int32()
case unix.IFLA_XDP_ATTACHED:
xdp.Attached = ad.Uint8()
case unix.IFLA_XDP_FLAGS:
xdp.Flags = ad.Uint32()
case unix.IFLA_XDP_PROG_ID:
xdp.ProgID = ad.Uint32()
}
}
return nil
}
func (xdp *LinkXDP) encode(ae *netlink.AttributeEncoder) error {
ae.Int32(unix.IFLA_XDP_FD, xdp.FD)
ae.Int32(unix.IFLA_XDP_EXPECTED_FD, xdp.ExpectedFD)
ae.Uint32(unix.IFLA_XDP_FLAGS, xdp.Flags)
// XDP_ATtACHED and XDP_PROG_ID are things that only can return from the kernel,
// not be send, so we don't encode them.
// source: https://elixir.bootlin.com/linux/v5.10.15/source/net/core/rtnetlink.c#L2894
return nil
}

226
vendor/github.com/jsimonetti/rtnetlink/neigh.go generated vendored Normal file
View File

@@ -0,0 +1,226 @@
package rtnetlink
import (
"errors"
"fmt"
"net"
"github.com/jsimonetti/rtnetlink/internal/unix"
"github.com/mdlayher/netlink"
)
var (
// errInvalidNeighMessage is returned when a LinkMessage is malformed.
errInvalidNeighMessage = errors.New("rtnetlink NeighMessage is invalid or too short")
// errInvalidNeighMessageAttr is returned when neigh attributes are malformed.
errInvalidNeighMessageAttr = errors.New("rtnetlink NeighMessage has a wrong attribute data length")
)
var _ Message = &NeighMessage{}
// A NeighMessage is a route netlink neighbor message.
type NeighMessage struct {
// Always set to AF_UNSPEC (0)
Family uint16
// Unique interface index
Index uint32
// Neighbor State is a bitmask of neighbor states (see rtnetlink(7))
State uint16
// Neighbor flags
Flags uint8
// Neighbor type
Type uint8
// Attributes List
Attributes *NeighAttributes
}
// MarshalBinary marshals a NeighMessage into a byte slice.
func (m *NeighMessage) MarshalBinary() ([]byte, error) {
b := make([]byte, unix.SizeofNdMsg)
b[0] = uint8(m.Family)
// bytes 2-4 are padding
nativeEndian.PutUint32(b[4:8], m.Index)
nativeEndian.PutUint16(b[8:10], m.State)
b[10] = m.Flags
b[11] = m.Type
if m.Attributes != nil {
ae := netlink.NewAttributeEncoder()
ae.ByteOrder = nativeEndian
err := m.Attributes.encode(ae)
if err != nil {
return nil, err
}
a, err := ae.Encode()
if err != nil {
return nil, err
}
return append(b, a...), nil
}
return b, nil
}
// UnmarshalBinary unmarshals the contents of a byte slice into a NeighMessage.
func (m *NeighMessage) UnmarshalBinary(b []byte) error {
l := len(b)
if l < unix.SizeofNdMsg {
return errInvalidNeighMessage
}
m.Family = uint16(b[0])
m.Index = nativeEndian.Uint32(b[4:8])
m.State = nativeEndian.Uint16(b[8:10])
m.Flags = b[10]
m.Type = b[11]
if l > unix.SizeofNdMsg {
m.Attributes = &NeighAttributes{}
ad, err := netlink.NewAttributeDecoder(b[unix.SizeofNdMsg:])
if err != nil {
return err
}
ad.ByteOrder = nativeEndian
err = m.Attributes.decode(ad)
if err != nil {
return err
}
}
return nil
}
// rtMessage is an empty method to sattisfy the Message interface.
func (*NeighMessage) rtMessage() {}
// NeighService is used to retrieve rtnetlink family information.
type NeighService struct {
c *Conn
}
// New creates a new interface using the LinkMessage information.
func (l *NeighService) New(req *NeighMessage) error {
flags := netlink.Request | netlink.Create | netlink.Acknowledge | netlink.Excl
_, err := l.c.Execute(req, unix.RTM_NEWNEIGH, flags)
if err != nil {
return err
}
return nil
}
// Delete removes an neighbor entry by index.
func (l *NeighService) Delete(index uint32) error {
req := &NeighMessage{}
flags := netlink.Request | netlink.Acknowledge
_, err := l.c.Execute(req, unix.RTM_DELNEIGH, flags)
if err != nil {
return err
}
return nil
}
// List retrieves all neighbors.
func (l *NeighService) List() ([]NeighMessage, error) {
req := NeighMessage{}
flags := netlink.Request | netlink.Dump
msgs, err := l.c.Execute(&req, unix.RTM_GETNEIGH, flags)
if err != nil {
return nil, err
}
neighs := make([]NeighMessage, len(msgs))
for i := range msgs {
neighs[i] = *msgs[i].(*NeighMessage)
}
return neighs, nil
}
// NeighCacheInfo contains neigh information
type NeighCacheInfo struct {
Confirmed uint32
Used uint32
Updated uint32
RefCount uint32
}
// UnmarshalBinary unmarshals the contents of a byte slice into a NeighMessage.
func (n *NeighCacheInfo) unmarshalBinary(b []byte) error {
if len(b) != 16 {
return fmt.Errorf("incorrect size, want: 16, got: %d", len(b))
}
n.Confirmed = nativeEndian.Uint32(b[0:4])
n.Used = nativeEndian.Uint32(b[4:8])
n.Updated = nativeEndian.Uint32(b[8:12])
n.RefCount = nativeEndian.Uint32(b[12:16])
return nil
}
// NeighAttributes contains all attributes for a neighbor.
type NeighAttributes struct {
Address net.IP // a neighbor cache n/w layer destination address
LLAddress net.HardwareAddr // a neighbor cache link layer address
CacheInfo *NeighCacheInfo // cache statistics
IfIndex uint32
}
func (a *NeighAttributes) decode(ad *netlink.AttributeDecoder) error {
for ad.Next() {
switch ad.Type() {
case unix.NDA_UNSPEC:
// unused attribute
case unix.NDA_DST:
l := len(ad.Bytes())
if l != 4 && l != 16 {
return errInvalidNeighMessageAttr
}
a.Address = ad.Bytes()
case unix.NDA_LLADDR:
// Allow IEEE 802 MAC-48, EUI-48, EUI-64, or 20-octet
// IP over InfiniBand link-layer addresses
l := len(ad.Bytes())
if l == 0 {
// Ignore empty addresses.
continue
}
if l != 6 && l != 8 && l != 20 {
return errInvalidNeighMessageAttr
}
a.LLAddress = ad.Bytes()
case unix.NDA_CACHEINFO:
a.CacheInfo = &NeighCacheInfo{}
err := a.CacheInfo.unmarshalBinary(ad.Bytes())
if err != nil {
return err
}
case unix.NDA_IFINDEX:
a.IfIndex = ad.Uint32()
}
}
return nil
}
func (a *NeighAttributes) encode(ae *netlink.AttributeEncoder) error {
ae.Uint16(unix.NDA_UNSPEC, 0)
ae.Bytes(unix.NDA_DST, a.Address)
ae.Bytes(unix.NDA_LLADDR, a.LLAddress)
ae.Uint32(unix.NDA_IFINDEX, a.IfIndex)
return nil
}

626
vendor/github.com/jsimonetti/rtnetlink/route.go generated vendored Normal file
View File

@@ -0,0 +1,626 @@
package rtnetlink
import (
"encoding/binary"
"errors"
"fmt"
"net"
"unsafe"
"github.com/jsimonetti/rtnetlink/internal/unix"
"github.com/mdlayher/netlink"
)
var (
// errInvalidRouteMessage is returned when a RouteMessage is malformed.
errInvalidRouteMessage = errors.New("rtnetlink RouteMessage is invalid or too short")
// errInvalidRouteMessageAttr is returned when link attributes are malformed.
errInvalidRouteMessageAttr = errors.New("rtnetlink RouteMessage has a wrong attribute data length")
)
var _ Message = &RouteMessage{}
type RouteMessage struct {
Family uint8 // Address family (current unix.AF_INET or unix.AF_INET6)
DstLength uint8 // Length of destination prefix
SrcLength uint8 // Length of source prefix
Tos uint8 // TOS filter
Table uint8 // Routing table ID
Protocol uint8 // Routing protocol
Scope uint8 // Distance to the destination
Type uint8 // Route type
Flags uint32
Attributes RouteAttributes
}
func (m *RouteMessage) MarshalBinary() ([]byte, error) {
b := make([]byte, unix.SizeofRtMsg)
b[0] = m.Family
b[1] = m.DstLength
b[2] = m.SrcLength
b[3] = m.Tos
b[4] = m.Table
b[5] = m.Protocol
b[6] = m.Scope
b[7] = m.Type
nativeEndian.PutUint32(b[8:12], m.Flags)
ae := netlink.NewAttributeEncoder()
err := m.Attributes.encode(ae)
if err != nil {
return nil, err
}
a, err := ae.Encode()
if err != nil {
return nil, err
}
return append(b, a...), nil
}
func (m *RouteMessage) UnmarshalBinary(b []byte) error {
l := len(b)
if l < unix.SizeofRtMsg {
return errInvalidRouteMessage
}
m.Family = uint8(b[0])
m.DstLength = uint8(b[1])
m.SrcLength = uint8(b[2])
m.Tos = uint8(b[3])
m.Table = uint8(b[4])
m.Protocol = uint8(b[5])
m.Scope = uint8(b[6])
m.Type = uint8(b[7])
m.Flags = nativeEndian.Uint32(b[8:12])
if l > unix.SizeofRtMsg {
ad, err := netlink.NewAttributeDecoder(b[unix.SizeofRtMsg:])
if err != nil {
return err
}
var ra RouteAttributes
if err := ra.decode(ad); err != nil {
return err
}
// Must consume errors from decoder before returning.
if err := ad.Err(); err != nil {
return fmt.Errorf("invalid route message attributes: %v", err)
}
m.Attributes = ra
}
return nil
}
// rtMessage is an empty method to sattisfy the Message interface.
func (*RouteMessage) rtMessage() {}
type RouteService struct {
c *Conn
}
func (r *RouteService) execute(m Message, family uint16, flags netlink.HeaderFlags) ([]RouteMessage, error) {
msgs, err := r.c.Execute(m, family, flags)
routes := make([]RouteMessage, len(msgs))
for i := range msgs {
routes[i] = *msgs[i].(*RouteMessage)
}
return routes, err
}
// Add new route
func (r *RouteService) Add(req *RouteMessage) error {
flags := netlink.Request | netlink.Create | netlink.Acknowledge | netlink.Excl
_, err := r.c.Execute(req, unix.RTM_NEWROUTE, flags)
return err
}
// Replace or add new route
func (r *RouteService) Replace(req *RouteMessage) error {
flags := netlink.Request | netlink.Create | netlink.Replace | netlink.Acknowledge
_, err := r.c.Execute(req, unix.RTM_NEWROUTE, flags)
return err
}
// Delete existing route
func (r *RouteService) Delete(req *RouteMessage) error {
flags := netlink.Request | netlink.Acknowledge
_, err := r.c.Execute(req, unix.RTM_DELROUTE, flags)
return err
}
// Get Route(s)
func (r *RouteService) Get(req *RouteMessage) ([]RouteMessage, error) {
flags := netlink.Request | netlink.DumpFiltered
return r.execute(req, unix.RTM_GETROUTE, flags)
}
// List all routes
func (r *RouteService) List() ([]RouteMessage, error) {
flags := netlink.Request | netlink.Dump
return r.execute(&RouteMessage{}, unix.RTM_GETROUTE, flags)
}
type RouteAttributes struct {
Dst net.IP
Src net.IP
Gateway net.IP
OutIface uint32
Priority uint32
Table uint32
Mark uint32
Pref *uint8
Expires *uint32
Metrics *RouteMetrics
Multipath []NextHop
}
func (a *RouteAttributes) decode(ad *netlink.AttributeDecoder) error {
for ad.Next() {
switch ad.Type() {
case unix.RTA_UNSPEC:
// unused attribute
case unix.RTA_DST:
ad.Do(decodeIP(&a.Dst))
case unix.RTA_PREFSRC:
ad.Do(decodeIP(&a.Src))
case unix.RTA_GATEWAY:
ad.Do(decodeIP(&a.Gateway))
case unix.RTA_OIF:
a.OutIface = ad.Uint32()
case unix.RTA_PRIORITY:
a.Priority = ad.Uint32()
case unix.RTA_TABLE:
a.Table = ad.Uint32()
case unix.RTA_MARK:
a.Mark = ad.Uint32()
case unix.RTA_EXPIRES:
timeout := ad.Uint32()
a.Expires = &timeout
case unix.RTA_METRICS:
a.Metrics = &RouteMetrics{}
ad.Nested(a.Metrics.decode)
case unix.RTA_MULTIPATH:
ad.Do(a.parseMultipath)
case unix.RTA_PREF:
pref := ad.Uint8()
a.Pref = &pref
}
}
return nil
}
func (a *RouteAttributes) encode(ae *netlink.AttributeEncoder) error {
if a.Dst != nil {
ae.Do(unix.RTA_DST, encodeIP(a.Dst))
}
if a.Src != nil {
ae.Do(unix.RTA_PREFSRC, encodeIP(a.Src))
}
if a.Gateway != nil {
ae.Do(unix.RTA_GATEWAY, encodeIP(a.Gateway))
}
if a.OutIface != 0 {
ae.Uint32(unix.RTA_OIF, a.OutIface)
}
if a.Priority != 0 {
ae.Uint32(unix.RTA_PRIORITY, a.Priority)
}
if a.Table != 0 {
ae.Uint32(unix.RTA_TABLE, a.Table)
}
if a.Mark != 0 {
ae.Uint32(unix.RTA_MARK, a.Mark)
}
if a.Pref != nil {
ae.Uint8(unix.RTA_PREF, *a.Pref)
}
if a.Expires != nil {
ae.Uint32(unix.RTA_EXPIRES, *a.Expires)
}
if a.Metrics != nil {
ae.Nested(unix.RTA_METRICS, a.Metrics.encode)
}
if len(a.Multipath) > 0 {
ae.Do(unix.RTA_MULTIPATH, a.encodeMultipath)
}
return nil
}
// RouteMetrics holds some advanced metrics for a route
type RouteMetrics struct {
AdvMSS uint32
Features uint32
InitCwnd uint32
InitRwnd uint32
MTU uint32
}
func (rm *RouteMetrics) decode(ad *netlink.AttributeDecoder) error {
for ad.Next() {
switch ad.Type() {
case unix.RTAX_ADVMSS:
rm.AdvMSS = ad.Uint32()
case unix.RTAX_FEATURES:
rm.Features = ad.Uint32()
case unix.RTAX_INITCWND:
rm.InitCwnd = ad.Uint32()
case unix.RTAX_INITRWND:
rm.InitRwnd = ad.Uint32()
case unix.RTAX_MTU:
rm.MTU = ad.Uint32()
}
}
// ad.Err call handled by Nested method in calling attribute decoder.
return nil
}
func (rm *RouteMetrics) encode(ae *netlink.AttributeEncoder) error {
if rm.AdvMSS != 0 {
ae.Uint32(unix.RTAX_ADVMSS, rm.AdvMSS)
}
if rm.Features != 0 {
ae.Uint32(unix.RTAX_FEATURES, rm.Features)
}
if rm.InitCwnd != 0 {
ae.Uint32(unix.RTAX_INITCWND, rm.InitCwnd)
}
if rm.InitRwnd != 0 {
ae.Uint32(unix.RTAX_INITRWND, rm.InitRwnd)
}
if rm.MTU != 0 {
ae.Uint32(unix.RTAX_MTU, rm.MTU)
}
return nil
}
// TODO(mdlayher): probably eliminate Length field from the API to avoid the
// caller possibly tampering with it since we can compute it.
// RTNextHop represents the netlink rtnexthop struct (not an attribute)
type RTNextHop struct {
Length uint16 // length of this hop including nested values
Flags uint8 // flags defined in rtnetlink.h line 311
Hops uint8
IfIndex uint32 // the interface index number
}
// NextHop wraps struct rtnexthop to provide access to nested attributes
type NextHop struct {
Hop RTNextHop // a rtnexthop struct
Gateway net.IP // that struct's nested Gateway attribute
MPLS []MPLSNextHop // Any MPLS next hops for a route.
}
func (a *RouteAttributes) encodeMultipath() ([]byte, error) {
var b []byte
for _, nh := range a.Multipath {
// Encode the attributes first so their total length can be used to
// compute the length of each (rtnexthop, attributes) pair.
ae := netlink.NewAttributeEncoder()
if nh.Gateway != nil {
ae.Do(unix.RTA_GATEWAY, encodeIP(nh.Gateway))
}
if len(nh.MPLS) > 0 {
// TODO(mdlayher): validation over different encapsulation types,
// and ensure that only one can be set.
ae.Uint16(unix.RTA_ENCAP_TYPE, unix.LWTUNNEL_ENCAP_MPLS)
ae.Nested(unix.RTA_ENCAP, nh.encodeEncap)
}
ab, err := ae.Encode()
if err != nil {
return nil, err
}
// Assume the caller wants the length updated so they don't have to
// keep track of it themselves when encoding attributes.
nh.Hop.Length = unix.SizeofRtNexthop + uint16(len(ab))
var nhb [unix.SizeofRtNexthop]byte
copy(
nhb[:],
(*(*[unix.SizeofRtNexthop]byte)(unsafe.Pointer(&nh.Hop)))[:],
)
// rtnexthop first, then attributes.
b = append(b, nhb[:]...)
b = append(b, ab...)
}
return b, nil
}
// parseMultipath consumes RTA_MULTIPATH data into RouteAttributes.
func (a *RouteAttributes) parseMultipath(b []byte) error {
// We cannot retain b after the function returns, so make a copy of the
// bytes up front for the multipathParser.
buf := make([]byte, len(b))
copy(buf, b)
// Iterate until no more bytes remain in the buffer or an error occurs.
mpp := &multipathParser{b: buf}
for mpp.Next() {
// Each iteration reads a fixed length RTNextHop structure immediately
// followed by its associated netlink attributes with optional data.
nh := NextHop{Hop: mpp.RTNextHop()}
if err := nh.decode(mpp.AttributeDecoder()); err != nil {
return err
}
// Stop iteration early if the data was malformed, or otherwise append
// this NextHop to the Multipath field.
if err := mpp.Err(); err != nil {
return err
}
a.Multipath = append(a.Multipath, nh)
}
// Check the error when Next returns false.
return mpp.Err()
}
// decode decodes netlink attribute values into a NextHop.
func (nh *NextHop) decode(ad *netlink.AttributeDecoder) error {
if ad == nil {
// Invalid decoder, do nothing.
return nil
}
// If encapsulation is present, we won't know how to deal with it until we
// identify the right type and then later parse the nested attribute bytes.
var (
encapType uint16
encapBuf []byte
)
for ad.Next() {
switch ad.Type() {
case unix.RTA_ENCAP:
encapBuf = ad.Bytes()
case unix.RTA_ENCAP_TYPE:
encapType = ad.Uint16()
case unix.RTA_GATEWAY:
ad.Do(decodeIP(&nh.Gateway))
}
}
if err := ad.Err(); err != nil {
return err
}
if encapType != 0 && encapBuf != nil {
// Found encapsulation, start decoding it from the buffer.
return nh.decodeEncap(encapType, encapBuf)
}
return nil
}
// An MPLSNextHop is a route next hop using MPLS encapsulation.
type MPLSNextHop struct {
Label int
TrafficClass int
BottomOfStack bool
TTL uint8
}
// TODO(mdlayher): MPLSNextHop TTL vs MPLS_IPTUNNEL_TTL. What's the difference?
// encodeEncap encodes netlink attribute values related to encapsulation from
// a NextHop.
func (nh *NextHop) encodeEncap(ae *netlink.AttributeEncoder) error {
// TODO: this only handles MPLS encapsulation as that is all we support.
// Allocate enough space for an MPLS label stack.
var (
i int
b = make([]byte, 4*len(nh.MPLS))
)
for _, mnh := range nh.MPLS {
// Pack the following:
// - label: 20 bits
// - traffic class: 3 bits
// - bottom-of-stack: 1 bit
// - TTL: 8 bits
binary.BigEndian.PutUint32(b[i:i+4], uint32(mnh.Label)<<12)
b[i+2] |= byte(mnh.TrafficClass) << 1
if mnh.BottomOfStack {
b[i+2] |= 1
}
b[i+3] = mnh.TTL
// Advance in the buffer to begin storing the next label.
i += 4
}
// Finally store the output bytes.
ae.Bytes(unix.MPLS_IPTUNNEL_DST, b)
return nil
}
// decodeEncap decodes netlink attribute values related to encapsulation into a
// NextHop.
func (nh *NextHop) decodeEncap(typ uint16, b []byte) error {
if typ != unix.LWTUNNEL_ENCAP_MPLS {
// TODO: handle other encapsulation types as needed.
return nil
}
// MPLS labels are stored as big endian bytes.
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return err
}
for ad.Next() {
switch ad.Type() {
case unix.MPLS_IPTUNNEL_DST:
// Every 4 bytes stores another MPLS label, so make sure the stored
// bytes are divisible by exactly 4.
b := ad.Bytes()
if len(b)%4 != 0 {
return errInvalidRouteMessageAttr
}
for i := 0; i < len(b); i += 4 {
n := binary.BigEndian.Uint32(b[i : i+4])
// For reference, see:
// https://en.wikipedia.org/wiki/Multiprotocol_Label_Switching#Operation
nh.MPLS = append(nh.MPLS, MPLSNextHop{
Label: int(n) >> 12,
TrafficClass: int(n & 0xe00 >> 9),
BottomOfStack: n&0x100 != 0,
TTL: uint8(n & 0xff),
})
}
}
}
return ad.Err()
}
// A multipathParser parses packed RTNextHop and netlink attributes into
// multipath attributes for an rtnetlink route.
type multipathParser struct {
// Any errors which occurred during parsing.
err error
// The underlying buffer and a pointer to the reading position.
b []byte
i int
// The length of the next set of netlink attributes.
alen int
}
// Next continues iteration until an error occurs or no bytes remain.
func (mpp *multipathParser) Next() bool {
if mpp.err != nil {
return false
}
// Are there enough bytes left for another RTNextHop, or 0 for EOF?
n := len(mpp.b[mpp.i:])
switch {
case n == 0:
// EOF.
return false
case n >= unix.SizeofRtNexthop:
return true
default:
mpp.err = errInvalidRouteMessageAttr
return false
}
}
// Err returns any errors encountered while parsing.
func (mpp *multipathParser) Err() error { return mpp.err }
// RTNextHop parses the next RTNextHop structure from the buffer.
func (mpp *multipathParser) RTNextHop() RTNextHop {
if mpp.err != nil {
return RTNextHop{}
}
if len(mpp.b)-mpp.i < unix.SizeofRtNexthop {
// Out of bounds access, not enough data for a valid RTNextHop.
mpp.err = errInvalidRouteMessageAttr
return RTNextHop{}
}
// Consume an RTNextHop from the buffer by copying its bytes into an output
// structure while also verifying that the size of each structure is equal
// to avoid any out-of-bounds unsafe memory access.
var rtnh RTNextHop
next := mpp.b[mpp.i : mpp.i+unix.SizeofRtNexthop]
if unix.SizeofRtNexthop != len(next) {
panic("rtnetlink: invalid RTNextHop structure size, panicking to avoid out-of-bounds unsafe access")
}
copy(
(*(*[unix.SizeofRtNexthop]byte)(unsafe.Pointer(&rtnh)))[:],
(*(*[unix.SizeofRtNexthop]byte)(unsafe.Pointer(&next[0])))[:],
)
if rtnh.Length < unix.SizeofRtNexthop {
// Length value is invalid.
mpp.err = errInvalidRouteMessageAttr
return RTNextHop{}
}
// Compute the length of the next set of attributes using the Length value
// in the RTNextHop, minus the size of that fixed length structure itself.
// Then, advance the pointer to be ready to read those attributes.
mpp.alen = int(rtnh.Length) - unix.SizeofRtNexthop
mpp.i += unix.SizeofRtNexthop
return rtnh
}
// AttributeDecoder returns a netlink.AttributeDecoder pointed at the next set
// of netlink attributes from the buffer.
func (mpp *multipathParser) AttributeDecoder() *netlink.AttributeDecoder {
if mpp.err != nil {
return nil
}
// Ensure the attributes length value computed while parsing the rtnexthop
// fits within the actual slice.
if len(mpp.b[mpp.i:]) < mpp.alen {
mpp.err = errInvalidRouteMessageAttr
return nil
}
// Consume the next set of netlink attributes from the buffer and advance
// the pointer to the next RTNextHop or EOF once that is complete.
ad, err := netlink.NewAttributeDecoder(mpp.b[mpp.i : mpp.i+mpp.alen])
if err != nil {
mpp.err = err
return nil
}
mpp.i += mpp.alen
return ad
}

394
vendor/github.com/jsimonetti/rtnetlink/rule.go generated vendored Normal file
View File

@@ -0,0 +1,394 @@
package rtnetlink
import (
"bytes"
"encoding/binary"
"errors"
"net"
"github.com/jsimonetti/rtnetlink/internal/unix"
"github.com/mdlayher/netlink"
)
var (
// errInvalidRuleMessage is returned when a RuleMessage is malformed.
errInvalidRuleMessage = errors.New("rtnetlink RuleMessage is invalid or too short")
// errInvalidRuleAttribute is returned when a RuleMessage contains an unknown attribute.
errInvalidRuleAttribute = errors.New("rtnetlink RuleMessage contains an unknown Attribute")
)
var _ Message = &RuleMessage{}
// A RuleMessage is a route netlink link message.
type RuleMessage struct {
// Address family
Family uint8
// Length of destination prefix
DstLength uint8
// Length of source prefix
SrcLength uint8
// Rule TOS
TOS uint8
// Routing table identifier
Table uint8
// Rule action
Action uint8
// Rule flags
Flags uint32
// Attributes List
Attributes *RuleAttributes
}
// MarshalBinary marshals a LinkMessage into a byte slice.
func (m *RuleMessage) MarshalBinary() ([]byte, error) {
b := make([]byte, 12)
// fib_rule_hdr
b[0] = m.Family
b[1] = m.DstLength
b[2] = m.SrcLength
b[3] = m.TOS
b[4] = m.Table
b[7] = m.Action
nativeEndian.PutUint32(b[8:12], m.Flags)
if m.Attributes != nil {
ae := netlink.NewAttributeEncoder()
ae.ByteOrder = nativeEndian
err := m.Attributes.encode(ae)
if err != nil {
return nil, err
}
a, err := ae.Encode()
if err != nil {
return nil, err
}
return append(b, a...), nil
}
return b, nil
}
// UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (m *RuleMessage) UnmarshalBinary(b []byte) error {
l := len(b)
if l < 12 {
return errInvalidRuleMessage
}
m.Family = b[0]
m.DstLength = b[1]
m.SrcLength = b[2]
m.TOS = b[3]
m.Table = b[4]
// b[5] and b[6] are reserved fields
m.Action = b[7]
m.Flags = nativeEndian.Uint32(b[8:12])
if l > 12 {
m.Attributes = &RuleAttributes{}
ad, err := netlink.NewAttributeDecoder(b[12:])
if err != nil {
return err
}
ad.ByteOrder = nativeEndian
return m.Attributes.decode(ad)
}
return nil
}
// rtMessage is an empty method to sattisfy the Message interface.
func (*RuleMessage) rtMessage() {}
// RuleService is used to retrieve rtnetlink family information.
type RuleService struct {
c *Conn
}
func (r *RuleService) execute(m Message, family uint16, flags netlink.HeaderFlags) ([]RuleMessage, error) {
msgs, err := r.c.Execute(m, family, flags)
rules := make([]RuleMessage, len(msgs))
for i := range msgs {
rules[i] = *msgs[i].(*RuleMessage)
}
return rules, err
}
// Add new rule
func (r *RuleService) Add(req *RuleMessage) error {
flags := netlink.Request | netlink.Create | netlink.Acknowledge | netlink.Excl
_, err := r.c.Execute(req, unix.RTM_NEWRULE, flags)
return err
}
// Replace or add new rule
func (r *RuleService) Replace(req *RuleMessage) error {
flags := netlink.Request | netlink.Create | netlink.Replace | netlink.Acknowledge
_, err := r.c.Execute(req, unix.RTM_NEWRULE, flags)
return err
}
// Delete existing rule
func (r *RuleService) Delete(req *RuleMessage) error {
flags := netlink.Request | netlink.Acknowledge
_, err := r.c.Execute(req, unix.RTM_DELRULE, flags)
return err
}
// Get Rule(s)
func (r *RuleService) Get(req *RuleMessage) ([]RuleMessage, error) {
flags := netlink.Request | netlink.DumpFiltered
return r.execute(req, unix.RTM_GETRULE, flags)
}
// List all rules
func (r *RuleService) List() ([]RuleMessage, error) {
flags := netlink.Request | netlink.Dump
return r.execute(&RuleMessage{}, unix.RTM_GETRULE, flags)
}
// RuleAttributes contains all attributes for a rule.
type RuleAttributes struct {
Src, Dst *net.IP
IIFName, OIFName *string
Goto *uint32
Priority *uint32
FwMark, FwMask *uint32
SrcRealm *uint16
DstRealm *uint16
TunID *uint64
Table *uint32
L3MDev *uint8
Protocol *uint8
IPProto *uint8
SuppressPrefixLen *uint32
SuppressIFGroup *uint32
UIDRange *RuleUIDRange
SPortRange *RulePortRange
DPortRange *RulePortRange
}
// unmarshalBinary unmarshals the contents of a byte slice into a RuleMessage.
func (r *RuleAttributes) decode(ad *netlink.AttributeDecoder) error {
for ad.Next() {
switch ad.Type() {
case unix.FRA_UNSPEC:
// unused
continue
case unix.FRA_DST:
r.Dst = &net.IP{}
ad.Do(decodeIP(r.Dst))
case unix.FRA_SRC:
r.Src = &net.IP{}
ad.Do(decodeIP(r.Src))
case unix.FRA_IIFNAME:
v := ad.String()
r.IIFName = &v
case unix.FRA_GOTO:
v := ad.Uint32()
r.Goto = &v
case unix.FRA_UNUSED2:
// unused
continue
case unix.FRA_PRIORITY:
v := ad.Uint32()
r.Priority = &v
case unix.FRA_UNUSED3:
// unused
continue
case unix.FRA_UNUSED4:
// unused
continue
case unix.FRA_UNUSED5:
// unused
continue
case unix.FRA_FWMARK:
v := ad.Uint32()
r.FwMark = &v
case unix.FRA_FLOW:
dst32 := ad.Uint32()
src32 := uint32(dst32 >> 16)
src32 &= 0xFFFF
dst32 &= 0xFFFF
src16 := uint16(src32)
dst16 := uint16(dst32)
r.SrcRealm = &src16
r.DstRealm = &dst16
case unix.FRA_TUN_ID:
v := ad.Uint64()
r.TunID = &v
case unix.FRA_SUPPRESS_IFGROUP:
v := ad.Uint32()
r.SuppressIFGroup = &v
case unix.FRA_SUPPRESS_PREFIXLEN:
v := ad.Uint32()
r.SuppressPrefixLen = &v
case unix.FRA_TABLE:
v := ad.Uint32()
r.Table = &v
case unix.FRA_FWMASK:
v := ad.Uint32()
r.FwMask = &v
case unix.FRA_OIFNAME:
v := ad.String()
r.OIFName = &v
case unix.FRA_PAD:
// unused
continue
case unix.FRA_L3MDEV:
v := ad.Uint8()
r.L3MDev = &v
case unix.FRA_UID_RANGE:
r.UIDRange = &RuleUIDRange{}
err := r.UIDRange.unmarshalBinary(ad.Bytes())
if err != nil {
return err
}
case unix.FRA_PROTOCOL:
v := ad.Uint8()
r.Protocol = &v
case unix.FRA_IP_PROTO:
v := ad.Uint8()
r.IPProto = &v
case unix.FRA_SPORT_RANGE:
r.SPortRange = &RulePortRange{}
err := r.SPortRange.unmarshalBinary(ad.Bytes())
if err != nil {
return err
}
case unix.FRA_DPORT_RANGE:
r.DPortRange = &RulePortRange{}
err := r.DPortRange.unmarshalBinary(ad.Bytes())
if err != nil {
return err
}
default:
return errInvalidRuleAttribute
}
}
return ad.Err()
}
// MarshalBinary marshals a RuleAttributes into a byte slice.
func (r *RuleAttributes) encode(ae *netlink.AttributeEncoder) error {
if r.Table != nil {
ae.Uint32(unix.FRA_TABLE, *r.Table)
}
if r.Protocol != nil {
ae.Uint8(unix.FRA_PROTOCOL, *r.Protocol)
}
if r.Src != nil {
ae.Do(unix.FRA_SRC, encodeIP(*r.Src))
}
if r.Dst != nil {
ae.Do(unix.FRA_DST, encodeIP(*r.Dst))
}
if r.IIFName != nil {
ae.String(unix.FRA_IIFNAME, *r.IIFName)
}
if r.OIFName != nil {
ae.String(unix.FRA_OIFNAME, *r.OIFName)
}
if r.Goto != nil {
ae.Uint32(unix.FRA_GOTO, *r.Goto)
}
if r.Priority != nil {
ae.Uint32(unix.FRA_PRIORITY, *r.Priority)
}
if r.FwMark != nil {
ae.Uint32(unix.FRA_FWMARK, *r.FwMark)
}
if r.FwMask != nil {
ae.Uint32(unix.FRA_FWMASK, *r.FwMask)
}
if r.DstRealm != nil {
value := uint32(*r.DstRealm)
if r.SrcRealm != nil {
value |= (uint32(*r.SrcRealm&0xFFFF) << 16)
}
ae.Uint32(unix.FRA_FLOW, value)
}
if r.TunID != nil {
ae.Uint64(unix.FRA_TUN_ID, *r.TunID)
}
if r.L3MDev != nil {
ae.Uint8(unix.FRA_L3MDEV, *r.L3MDev)
}
if r.IPProto != nil {
ae.Uint8(unix.FRA_IP_PROTO, *r.IPProto)
}
if r.SuppressIFGroup != nil {
ae.Uint32(unix.FRA_SUPPRESS_IFGROUP, *r.SuppressIFGroup)
}
if r.SuppressPrefixLen != nil {
ae.Uint32(unix.FRA_SUPPRESS_PREFIXLEN, *r.SuppressPrefixLen)
}
if r.UIDRange != nil {
data, err := marshalRuleUIDRange(*r.UIDRange)
if err != nil {
return err
}
ae.Bytes(unix.FRA_UID_RANGE, data)
}
if r.SPortRange != nil {
data, err := marshalRulePortRange(*r.SPortRange)
if err != nil {
return err
}
ae.Bytes(unix.FRA_SPORT_RANGE, data)
}
if r.DPortRange != nil {
data, err := marshalRulePortRange(*r.DPortRange)
if err != nil {
return err
}
ae.Bytes(unix.FRA_DPORT_RANGE, data)
}
return nil
}
// RulePortRange defines start and end ports for a rule
type RulePortRange struct {
Start, End uint16
}
func (r *RulePortRange) unmarshalBinary(data []byte) error {
b := bytes.NewReader(data)
return binary.Read(b, nativeEndian, r)
}
func marshalRulePortRange(s RulePortRange) ([]byte, error) {
var buf bytes.Buffer
err := binary.Write(&buf, nativeEndian, s)
return buf.Bytes(), err
}
// RuleUIDRange defines the start and end for UID matches
type RuleUIDRange struct {
Start, End uint16
}
func (r *RuleUIDRange) unmarshalBinary(data []byte) error {
b := bytes.NewReader(data)
return binary.Read(b, nativeEndian, r)
}
func marshalRuleUIDRange(s RuleUIDRange) ([]byte, error) {
var buf bytes.Buffer
err := binary.Write(&buf, nativeEndian, s)
return buf.Bytes(), err
}