Update dependencies
This commit is contained in:
1
vendor/github.com/jsimonetti/rtnetlink/.gitignore
generated
vendored
Normal file
1
vendor/github.com/jsimonetti/rtnetlink/.gitignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
rtnetlink-fuzz.zip
|
||||
10
vendor/github.com/jsimonetti/rtnetlink/LICENSE.md
generated
vendored
Normal file
10
vendor/github.com/jsimonetti/rtnetlink/LICENSE.md
generated
vendored
Normal 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
32
vendor/github.com/jsimonetti/rtnetlink/Makefile.fuzz
generated
vendored
Normal 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
43
vendor/github.com/jsimonetti/rtnetlink/README.md
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
rtnetlink  [](https://godoc.org/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
269
vendor/github.com/jsimonetti/rtnetlink/address.go
generated
vendored
Normal 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
197
vendor/github.com/jsimonetti/rtnetlink/conn.go
generated
vendored
Normal 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
27
vendor/github.com/jsimonetti/rtnetlink/doc.go
generated
vendored
Normal 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
13
vendor/github.com/jsimonetti/rtnetlink/endian.go
generated
vendored
Normal 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
15
vendor/github.com/jsimonetti/rtnetlink/fuzz-shell.nix
generated
vendored
Normal 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 ""
|
||||
'';
|
||||
}
|
||||
150
vendor/github.com/jsimonetti/rtnetlink/internal/unix/types_linux.go
generated
vendored
Normal file
150
vendor/github.com/jsimonetti/rtnetlink/internal/unix/types_linux.go
generated
vendored
Normal 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
|
||||
)
|
||||
146
vendor/github.com/jsimonetti/rtnetlink/internal/unix/types_other.go
generated
vendored
Normal file
146
vendor/github.com/jsimonetti/rtnetlink/internal/unix/types_other.go
generated
vendored
Normal 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
622
vendor/github.com/jsimonetti/rtnetlink/link.go
generated
vendored
Normal 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
226
vendor/github.com/jsimonetti/rtnetlink/neigh.go
generated
vendored
Normal 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
626
vendor/github.com/jsimonetti/rtnetlink/route.go
generated
vendored
Normal 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
394
vendor/github.com/jsimonetti/rtnetlink/rule.go
generated
vendored
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user