migrate to golang.zx2c4.com/wireguard/wgctrl (#239)
* migrate to golang.zx2c4.com/wireguard/wgctrl This commit introduces the usage of wgctrl. It avoids the usage of exec calls of the wg command and parsing the output of `wg show`. Signed-off-by: leonnicolas <leonloechner@gmx.de> * vendor wgctrl Signed-off-by: leonnicolas <leonloechner@gmx.de> * apply suggestions from code review Remove wireguard.Enpoint struct and use net.UDPAddr for the resolved endpoint and addr string (dnsanme:port) if a DN was supplied. Signed-off-by: leonnicolas <leonloechner@gmx.de> * pkg/*: use wireguard.Enpoint This commit introduces the wireguard.Enpoint struct. It encapsulates a DN name with port and a net.UPDAddr. The fields are private and only accessible over exported Methods to avoid accidental modification. Also iptables.GetProtocol is improved to avoid ipv4 rules being applied by `ip6tables`. Signed-off-by: leonnicolas <leonloechner@gmx.de> * pkg/wireguard/conf_test.go: add tests for Endpoint Signed-off-by: leonnicolas <leonloechner@gmx.de> * cmd/kg/main.go: validate port range Signed-off-by: leonnicolas <leonloechner@gmx.de> * add suggestions from review Signed-off-by: leonnicolas <leonloechner@gmx.de> * pkg/mesh/mesh.go: use Equal func Implement an Equal func for Enpoint and use it instead of comparing strings. Signed-off-by: leonnicolas <leonloechner@gmx.de> * cmd/kgctl/main.go: check port range Signed-off-by: leonnicolas <leonloechner@gmx.de> * vendor Signed-off-by: leonnicolas <leonloechner@gmx.de>
This commit is contained in:
9
vendor/github.com/mdlayher/genetlink/CHANGELOG.md
generated
vendored
Normal file
9
vendor/github.com/mdlayher/genetlink/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# CHANGELOG
|
||||
|
||||
## Unreleased
|
||||
|
||||
n/a
|
||||
|
||||
## v1.0.0
|
||||
|
||||
- Initial stable commit.
|
10
vendor/github.com/mdlayher/genetlink/LICENSE.md
generated
vendored
Normal file
10
vendor/github.com/mdlayher/genetlink/LICENSE.md
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
MIT License
|
||||
===========
|
||||
|
||||
Copyright (C) 2016-2017 Matt Layher
|
||||
|
||||
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.
|
27
vendor/github.com/mdlayher/genetlink/README.md
generated
vendored
Normal file
27
vendor/github.com/mdlayher/genetlink/README.md
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
genetlink [](https://builds.sr.ht/~mdlayher/genetlink?) [](https://godoc.org/github.com/mdlayher/genetlink) [](https://goreportcard.com/report/github.com/mdlayher/genetlink)
|
||||
=========
|
||||
|
||||
Package `genetlink` implements generic netlink interactions and data types.
|
||||
MIT Licensed.
|
||||
|
||||
For more information about how netlink and generic netlink work,
|
||||
check out my blog series on [Linux, Netlink, and Go](https://mdlayher.com/blog/linux-netlink-and-go-part-1-netlink/).
|
||||
|
||||
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!
|
||||
|
||||
## Stability
|
||||
|
||||
See the [CHANGELOG](./CHANGELOG.md) file for a description of changes between
|
||||
releases.
|
||||
|
||||
This package has reached v1.0.0 and any future breaking API changes will prompt
|
||||
the release of a new major version. Features and bug fixes will continue to
|
||||
occur in the v1.x.x series.
|
||||
|
||||
The general policy of this package is to only support the latest, stable version
|
||||
of Go. Compatibility shims may be added for prior versions of Go on an as-needed
|
||||
basis. If you would like to raise a concern, please [file an issue](https://github.com/mdlayher/genetlink/issues/new).
|
||||
|
||||
**If you depend on this package in your applications, please use Go modules.**
|
235
vendor/github.com/mdlayher/genetlink/conn.go
generated
vendored
Normal file
235
vendor/github.com/mdlayher/genetlink/conn.go
generated
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
package genetlink
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/mdlayher/netlink"
|
||||
"golang.org/x/net/bpf"
|
||||
)
|
||||
|
||||
// Protocol is the netlink protocol constant used to specify generic netlink.
|
||||
const Protocol = 0x10 // unix.NETLINK_GENERIC
|
||||
|
||||
// A Conn is a generic netlink connection. A Conn can be used to send and
|
||||
// receive generic netlink messages to and from netlink.
|
||||
//
|
||||
// A Conn is safe for concurrent use, but to avoid contention in
|
||||
// high-throughput applications, the caller should almost certainly create a
|
||||
// pool of Conns and distribute them among workers.
|
||||
type Conn struct {
|
||||
// Operating system-specific netlink connection.
|
||||
c *netlink.Conn
|
||||
}
|
||||
|
||||
// Dial dials a generic 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(Protocol, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewConn(c), nil
|
||||
}
|
||||
|
||||
// NewConn creates a Conn that wraps an existing *netlink.Conn for
|
||||
// generic netlink communications.
|
||||
//
|
||||
// NewConn is primarily useful for tests. Most applications should use
|
||||
// Dial instead.
|
||||
func NewConn(c *netlink.Conn) *Conn {
|
||||
return &Conn{c: c}
|
||||
}
|
||||
|
||||
// Close closes the connection. Close will unblock any concurrent calls to
|
||||
// Receive which are waiting on a response from the kernel.
|
||||
func (c *Conn) Close() error {
|
||||
return c.c.Close()
|
||||
}
|
||||
|
||||
// GetFamily retrieves a generic netlink family with the specified name.
|
||||
//
|
||||
// If the family does not exist, the error value can be checked using
|
||||
// netlink.IsNotExist.
|
||||
func (c *Conn) GetFamily(name string) (Family, error) {
|
||||
return c.getFamily(name)
|
||||
}
|
||||
|
||||
// ListFamilies retrieves all registered generic netlink families.
|
||||
func (c *Conn) ListFamilies() ([]Family, error) {
|
||||
return c.listFamilies()
|
||||
}
|
||||
|
||||
// JoinGroup joins a netlink multicast group by its ID.
|
||||
func (c *Conn) JoinGroup(group uint32) error {
|
||||
return c.c.JoinGroup(group)
|
||||
}
|
||||
|
||||
// LeaveGroup leaves a netlink multicast group by its ID.
|
||||
func (c *Conn) LeaveGroup(group uint32) error {
|
||||
return c.c.LeaveGroup(group)
|
||||
}
|
||||
|
||||
// SetBPF attaches an assembled BPF program to a Conn.
|
||||
func (c *Conn) SetBPF(filter []bpf.RawInstruction) error {
|
||||
return c.c.SetBPF(filter)
|
||||
}
|
||||
|
||||
// RemoveBPF removes a BPF filter from a Conn.
|
||||
func (c *Conn) RemoveBPF() error {
|
||||
return c.c.RemoveBPF()
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// SetReadBuffer sets the size of the operating system's receive buffer
|
||||
// associated with the Conn.
|
||||
func (c *Conn) SetReadBuffer(bytes int) error {
|
||||
return c.c.SetReadBuffer(bytes)
|
||||
}
|
||||
|
||||
// SetWriteBuffer sets the size of the operating system's transmit buffer
|
||||
// associated with the Conn.
|
||||
func (c *Conn) SetWriteBuffer(bytes int) error {
|
||||
return c.c.SetWriteBuffer(bytes)
|
||||
}
|
||||
|
||||
// SyscallConn returns a raw network connection. This implements the
|
||||
// syscall.Conn interface.
|
||||
//
|
||||
// On Go 1.12+, all methods of the returned syscall.RawConn are supported and
|
||||
// the Conn is integrated with the runtime network poller. On versions of Go
|
||||
// prior to Go 1.12, only the Control method of the returned syscall.RawConn
|
||||
// is implemented.
|
||||
//
|
||||
// SyscallConn is intended for advanced use cases, such as getting and setting
|
||||
// arbitrary socket options using the netlink socket's file descriptor.
|
||||
//
|
||||
// Once invoked, it is the caller's responsibility to ensure that operations
|
||||
// performed using Conn and the syscall.RawConn do not conflict with
|
||||
// each other.
|
||||
func (c *Conn) SyscallConn() (syscall.RawConn, error) {
|
||||
return c.c.SyscallConn()
|
||||
}
|
||||
|
||||
// SetDeadline sets the read and write deadlines associated with the connection.
|
||||
//
|
||||
// Deadline functionality is only supported on Go 1.12+. Calling this function
|
||||
// on older versions of Go will result in an error.
|
||||
func (c *Conn) SetDeadline(t time.Time) error {
|
||||
return c.c.SetDeadline(t)
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the read deadline associated with the connection.
|
||||
//
|
||||
// Deadline functionality is only supported on Go 1.12+. Calling this function
|
||||
// on older versions of Go will result in an error.
|
||||
func (c *Conn) SetReadDeadline(t time.Time) error {
|
||||
return c.c.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
// SetWriteDeadline sets the write deadline associated with the connection.
|
||||
//
|
||||
// Deadline functionality is only supported on Go 1.12+. Calling this function
|
||||
// on older versions of Go will result in an error.
|
||||
func (c *Conn) SetWriteDeadline(t time.Time) error {
|
||||
return c.c.SetWriteDeadline(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, err := packMessage(m, family, flags)
|
||||
if err != nil {
|
||||
return netlink.Message{}, err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
gmsgs, err := unpackMessages(msgs)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return gmsgs, 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
|
||||
}
|
||||
|
||||
// Locking behavior handled by netlink.Conn.Execute.
|
||||
msgs, err := c.c.Execute(nm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return unpackMessages(msgs)
|
||||
}
|
||||
|
||||
// packMessage packs a generic netlink Message into a netlink.Message with the
|
||||
// appropriate generic netlink 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 generic netlink Messages from a slice of netlink.Messages.
|
||||
func unpackMessages(msgs []netlink.Message) ([]Message, error) {
|
||||
gmsgs := make([]Message, 0, len(msgs))
|
||||
for _, nm := range msgs {
|
||||
var gm Message
|
||||
if err := (&gm).UnmarshalBinary(nm.Data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gmsgs = append(gmsgs, gm)
|
||||
}
|
||||
|
||||
return gmsgs, nil
|
||||
}
|
6
vendor/github.com/mdlayher/genetlink/doc.go
generated
vendored
Normal file
6
vendor/github.com/mdlayher/genetlink/doc.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
// Package genetlink implements generic netlink interactions and data types.
|
||||
//
|
||||
// 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!
|
||||
package genetlink
|
17
vendor/github.com/mdlayher/genetlink/family.go
generated
vendored
Normal file
17
vendor/github.com/mdlayher/genetlink/family.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package genetlink
|
||||
|
||||
// A Family is a generic netlink family.
|
||||
type Family struct {
|
||||
ID uint16
|
||||
Version uint8
|
||||
Name string
|
||||
Groups []MulticastGroup
|
||||
}
|
||||
|
||||
// A MulticastGroup is a generic netlink multicast group, which can be joined
|
||||
// for notifications from generic netlink families when specific events take
|
||||
// place.
|
||||
type MulticastGroup struct {
|
||||
ID uint32
|
||||
Name string
|
||||
}
|
146
vendor/github.com/mdlayher/genetlink/family_linux.go
generated
vendored
Normal file
146
vendor/github.com/mdlayher/genetlink/family_linux.go
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
//+build linux
|
||||
|
||||
package genetlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/mdlayher/netlink"
|
||||
"github.com/mdlayher/netlink/nlenc"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// errInvalidFamilyVersion is returned when a family's version is greater
|
||||
// than an 8-bit integer.
|
||||
var errInvalidFamilyVersion = errors.New("invalid family version attribute")
|
||||
|
||||
// getFamily retrieves a generic netlink family with the specified name.
|
||||
func (c *Conn) getFamily(name string) (Family, error) {
|
||||
b, err := netlink.MarshalAttributes([]netlink.Attribute{{
|
||||
Type: unix.CTRL_ATTR_FAMILY_NAME,
|
||||
Data: nlenc.Bytes(name),
|
||||
}})
|
||||
if err != nil {
|
||||
return Family{}, err
|
||||
}
|
||||
|
||||
req := Message{
|
||||
Header: Header{
|
||||
Command: unix.CTRL_CMD_GETFAMILY,
|
||||
// TODO(mdlayher): grab nlctrl version?
|
||||
Version: 1,
|
||||
},
|
||||
Data: b,
|
||||
}
|
||||
|
||||
msgs, err := c.Execute(req, unix.GENL_ID_CTRL, netlink.Request)
|
||||
if err != nil {
|
||||
return Family{}, err
|
||||
}
|
||||
|
||||
// TODO(mdlayher): consider interpreting generic netlink header values
|
||||
|
||||
families, err := buildFamilies(msgs)
|
||||
if err != nil {
|
||||
return Family{}, err
|
||||
}
|
||||
if len(families) != 1 {
|
||||
// If this were to ever happen, netlink must be in a state where
|
||||
// its answers cannot be trusted
|
||||
panic(fmt.Sprintf("netlink returned multiple families for name: %q", name))
|
||||
}
|
||||
|
||||
return families[0], nil
|
||||
}
|
||||
|
||||
// listFamilies retrieves all registered generic netlink families.
|
||||
func (c *Conn) listFamilies() ([]Family, error) {
|
||||
req := Message{
|
||||
Header: Header{
|
||||
Command: unix.CTRL_CMD_GETFAMILY,
|
||||
// TODO(mdlayher): grab nlctrl version?
|
||||
Version: 1,
|
||||
},
|
||||
}
|
||||
|
||||
flags := netlink.Request | netlink.Dump
|
||||
msgs, err := c.Execute(req, unix.GENL_ID_CTRL, flags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buildFamilies(msgs)
|
||||
}
|
||||
|
||||
// buildFamilies builds a slice of Families by parsing attributes from the
|
||||
// input Messages.
|
||||
func buildFamilies(msgs []Message) ([]Family, error) {
|
||||
families := make([]Family, 0, len(msgs))
|
||||
for _, m := range msgs {
|
||||
var f Family
|
||||
if err := (&f).parseAttributes(m.Data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
families = append(families, f)
|
||||
}
|
||||
|
||||
return families, nil
|
||||
}
|
||||
|
||||
// parseAttributes decodes netlink attributes into a Family's fields.
|
||||
func (f *Family) parseAttributes(b []byte) error {
|
||||
ad, err := netlink.NewAttributeDecoder(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for ad.Next() {
|
||||
switch ad.Type() {
|
||||
case unix.CTRL_ATTR_FAMILY_ID:
|
||||
f.ID = ad.Uint16()
|
||||
case unix.CTRL_ATTR_FAMILY_NAME:
|
||||
f.Name = ad.String()
|
||||
case unix.CTRL_ATTR_VERSION:
|
||||
v := ad.Uint32()
|
||||
if v > math.MaxUint8 {
|
||||
return errInvalidFamilyVersion
|
||||
}
|
||||
|
||||
f.Version = uint8(v)
|
||||
case unix.CTRL_ATTR_MCAST_GROUPS:
|
||||
ad.Nested(func(nad *netlink.AttributeDecoder) error {
|
||||
f.Groups = parseMulticastGroups(nad)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return ad.Err()
|
||||
}
|
||||
|
||||
// parseMulticastGroups parses an array of multicast group nested attributes
|
||||
// into a slice of MulticastGroups.
|
||||
func parseMulticastGroups(ad *netlink.AttributeDecoder) []MulticastGroup {
|
||||
groups := make([]MulticastGroup, 0, ad.Len())
|
||||
for ad.Next() {
|
||||
ad.Nested(func(nad *netlink.AttributeDecoder) error {
|
||||
var g MulticastGroup
|
||||
for nad.Next() {
|
||||
switch nad.Type() {
|
||||
case unix.CTRL_ATTR_MCAST_GRP_NAME:
|
||||
g.Name = nad.String()
|
||||
case unix.CTRL_ATTR_MCAST_GRP_ID:
|
||||
g.ID = nad.Uint32()
|
||||
}
|
||||
}
|
||||
|
||||
groups = append(groups, g)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return groups
|
||||
}
|
23
vendor/github.com/mdlayher/genetlink/family_others.go
generated
vendored
Normal file
23
vendor/github.com/mdlayher/genetlink/family_others.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
//+build !linux
|
||||
|
||||
package genetlink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// errUnimplemented is returned by all functions on platforms that
|
||||
// cannot make use of generic netlink.
|
||||
var errUnimplemented = fmt.Errorf("generic netlink not implemented on %s/%s",
|
||||
runtime.GOOS, runtime.GOARCH)
|
||||
|
||||
// getFamily always returns an error.
|
||||
func (c *Conn) getFamily(name string) (Family, error) {
|
||||
return Family{}, errUnimplemented
|
||||
}
|
||||
|
||||
// listFamilies always returns an error.
|
||||
func (c *Conn) listFamilies() ([]Family, error) {
|
||||
return nil, errUnimplemented
|
||||
}
|
20
vendor/github.com/mdlayher/genetlink/fuzz.go
generated
vendored
Normal file
20
vendor/github.com/mdlayher/genetlink/fuzz.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
//+build gofuzz
|
||||
|
||||
package genetlink
|
||||
|
||||
func Fuzz(data []byte) int {
|
||||
return fuzzMessage(data)
|
||||
}
|
||||
|
||||
func fuzzMessage(data []byte) int {
|
||||
var m Message
|
||||
if err := (&m).UnmarshalBinary(data); err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
if _, err := m.MarshalBinary(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
61
vendor/github.com/mdlayher/genetlink/message.go
generated
vendored
Normal file
61
vendor/github.com/mdlayher/genetlink/message.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
package genetlink
|
||||
|
||||
import "errors"
|
||||
|
||||
// errInvalidMessage is returned when a Message is malformed.
|
||||
var errInvalidMessage = errors.New("generic netlink message is invalid or too short")
|
||||
|
||||
// A Header is a generic netlink header. A Header is sent and received with
|
||||
// each generic netlink message to indicate metadata regarding a Message.
|
||||
type Header struct {
|
||||
// Command specifies a command to issue to netlink.
|
||||
Command uint8
|
||||
|
||||
// Version specifies the version of a command to use.
|
||||
Version uint8
|
||||
}
|
||||
|
||||
// headerLen is the length of a Header.
|
||||
const headerLen = 4 // unix.GENL_HDRLEN
|
||||
|
||||
// A Message is a generic netlink message. It contains a Header and an
|
||||
// arbitrary byte payload, which may be decoded using information from the
|
||||
// Header.
|
||||
//
|
||||
// Data is encoded using the native endianness of the host system. Use
|
||||
// the netlink.AttributeDecoder and netlink.AttributeEncoder types to decode
|
||||
// and encode data.
|
||||
type Message struct {
|
||||
Header Header
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// MarshalBinary marshals a Message into a byte slice.
|
||||
func (m Message) MarshalBinary() ([]byte, error) {
|
||||
b := make([]byte, headerLen)
|
||||
|
||||
b[0] = m.Header.Command
|
||||
b[1] = m.Header.Version
|
||||
|
||||
// b[2] and b[3] are padding bytes and set to zero
|
||||
|
||||
return append(b, m.Data...), nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary unmarshals the contents of a byte slice into a Message.
|
||||
func (m *Message) UnmarshalBinary(b []byte) error {
|
||||
if len(b) < headerLen {
|
||||
return errInvalidMessage
|
||||
}
|
||||
|
||||
// Don't allow reserved pad bytes to be set
|
||||
if b[2] != 0 || b[3] != 0 {
|
||||
return errInvalidMessage
|
||||
}
|
||||
|
||||
m.Header.Command = b[0]
|
||||
m.Header.Version = b[1]
|
||||
|
||||
m.Data = b[4:]
|
||||
return nil
|
||||
}
|
3
vendor/github.com/mdlayher/netlink/.gitignore
generated
vendored
Normal file
3
vendor/github.com/mdlayher/netlink/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
netlink.test
|
||||
netlink-fuzz.zip
|
||||
testdata/
|
100
vendor/github.com/mdlayher/netlink/CHANGELOG.md
generated
vendored
Normal file
100
vendor/github.com/mdlayher/netlink/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v1.4.1
|
||||
|
||||
- [Improvement]: significant runtime network poller integration cleanup through
|
||||
the use of `github.com/mdlayher/socket`.
|
||||
|
||||
## v1.4.0
|
||||
|
||||
- [New API] [#185](https://github.com/mdlayher/netlink/pull/185): the
|
||||
`netlink.AttributeDecoder` and `netlink.AttributeEncoder` types now have
|
||||
methods for dealing with signed integers: `Int8`, `Int16`, `Int32`, and
|
||||
`Int64`. These are necessary for working with rtnetlink's XDP APIs. Thanks
|
||||
@fbegyn.
|
||||
|
||||
## v1.3.2
|
||||
|
||||
- [Improvement]
|
||||
[commit](https://github.com/mdlayher/netlink/commit/ebc6e2e28bcf1a0671411288423d8116ff924d6d):
|
||||
`github.com/google/go-cmp` is no longer a (non-test) dependency of this module.
|
||||
|
||||
## v1.3.1
|
||||
|
||||
- [Improvement]: many internal cleanups and simplifications. The library is now
|
||||
slimmer and features less internal indirection. There are no user-facing
|
||||
changes in this release.
|
||||
|
||||
## v1.3.0
|
||||
|
||||
- [New API] [#176](https://github.com/mdlayher/netlink/pull/176):
|
||||
`netlink.OpError` now has `Message` and `Offset` fields which are populated
|
||||
when the kernel returns netlink extended acknowledgement data along with an
|
||||
error code. The caller can turn on this option by using
|
||||
`netlink.Conn.SetOption(netlink.ExtendedAcknowledge, true)`.
|
||||
- [New API]
|
||||
[commit](https://github.com/mdlayher/netlink/commit/beba85e0372133b6d57221191d2c557727cd1499):
|
||||
the `netlink.GetStrictCheck` option can be used to tell the kernel to be more
|
||||
strict when parsing requests. This enables more safety checks and can allow
|
||||
the kernel to perform more advanced request filtering in subsystems such as
|
||||
route netlink.
|
||||
|
||||
## v1.2.1
|
||||
|
||||
- [Bug Fix]
|
||||
[commit](https://github.com/mdlayher/netlink/commit/d81418f81b0bfa2465f33790a85624c63d6afe3d):
|
||||
`netlink.SetBPF` will no longer panic if an empty BPF filter is set.
|
||||
- [Improvement]
|
||||
[commit](https://github.com/mdlayher/netlink/commit/8014f9a7dbf4fd7b84a1783dd7b470db9113ff36):
|
||||
the library now uses https://github.com/josharian/native to provide the
|
||||
system's native endianness at compile time, rather than re-computing it many
|
||||
times at runtime.
|
||||
|
||||
## v1.2.0
|
||||
|
||||
**This is the first release of package netlink that only supports Go 1.12+. Users on older versions must use v1.1.1.**
|
||||
|
||||
- [Improvement] [#173](https://github.com/mdlayher/netlink/pull/173): support
|
||||
for Go 1.11 and below has been dropped. All users are highly recommended to
|
||||
use a stable and supported release of Go for their applications.
|
||||
- [Performance] [#171](https://github.com/mdlayher/netlink/pull/171):
|
||||
`netlink.Conn` no longer requires a locked OS thread for the vast majority of
|
||||
operations, which should result in a significant speedup for highly concurrent
|
||||
callers. Thanks @ti-mo.
|
||||
- [Bug Fix] [#169](https://github.com/mdlayher/netlink/pull/169): calls to
|
||||
`netlink.Conn.Close` are now able to unblock concurrent calls to
|
||||
`netlink.Conn.Receive` and other blocking operations.
|
||||
|
||||
## v1.1.1
|
||||
|
||||
**This is the last release of package netlink that supports Go 1.11.**
|
||||
|
||||
- [Improvement] [#165](https://github.com/mdlayher/netlink/pull/165):
|
||||
`netlink.Conn` `SetReadBuffer` and `SetWriteBuffer` methods now attempt the
|
||||
`SO_*BUFFORCE` socket options to possibly ignore system limits given elevated
|
||||
caller permissions. Thanks @MarkusBauer.
|
||||
- [Note]
|
||||
[commit](https://github.com/mdlayher/netlink/commit/c5f8ab79aa345dcfcf7f14d746659ca1b80a0ecc):
|
||||
`netlink.Conn.Close` has had a long-standing bug
|
||||
[#162](https://github.com/mdlayher/netlink/pull/162) related to internal
|
||||
concurrency handling where a call to `Close` is not sufficient to unblock
|
||||
pending reads. To effectively fix this issue, it is necessary to drop support
|
||||
for Go 1.11 and below. This will be fixed in a future release, but a
|
||||
workaround is noted in the method documentation as of now.
|
||||
|
||||
## v1.1.0
|
||||
|
||||
- [New API] [#157](https://github.com/mdlayher/netlink/pull/157): the
|
||||
`netlink.AttributeDecoder.TypeFlags` method enables retrieval of the type bits
|
||||
stored in a netlink attribute's type field, because the existing `Type` method
|
||||
masks away these bits. Thanks @ti-mo!
|
||||
- [Performance] [#157](https://github.com/mdlayher/netlink/pull/157): `netlink.AttributeDecoder`
|
||||
now decodes netlink attributes on demand, enabling callers who only need a
|
||||
limited number of attributes to exit early from decoding loops. Thanks @ti-mo!
|
||||
- [Improvement] [#161](https://github.com/mdlayher/netlink/pull/161): `netlink.Conn`
|
||||
system calls are now ready for Go 1.14+'s changes to goroutine preemption.
|
||||
See the PR for details.
|
||||
|
||||
## v1.0.0
|
||||
|
||||
- Initial stable commit.
|
9
vendor/github.com/mdlayher/netlink/LICENSE.md
generated
vendored
Normal file
9
vendor/github.com/mdlayher/netlink/LICENSE.md
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# MIT License
|
||||
|
||||
Copyright (C) 2016-2021 Matt Layher
|
||||
|
||||
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.
|
51
vendor/github.com/mdlayher/netlink/README.md
generated
vendored
Normal file
51
vendor/github.com/mdlayher/netlink/README.md
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
# netlink [](https://github.com/mdlayher/netlink/actions) [](https://pkg.go.dev/github.com/mdlayher/netlink) [](https://goreportcard.com/report/github.com/mdlayher/netlink)
|
||||
|
||||
Package `netlink` provides low-level access to Linux netlink sockets.
|
||||
MIT Licensed.
|
||||
|
||||
For more information about how netlink works, check out my blog series
|
||||
on [Linux, Netlink, and Go](https://mdlayher.com/blog/linux-netlink-and-go-part-1-netlink/).
|
||||
|
||||
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!
|
||||
|
||||
## Stability
|
||||
|
||||
See the [CHANGELOG](./CHANGELOG.md) file for a description of changes between
|
||||
releases.
|
||||
|
||||
This package has a stable v1 API and any future breaking changes will prompt
|
||||
the release of a new major version. Features and bug fixes will continue to
|
||||
occur in the v1.x.x series.
|
||||
|
||||
In order to reduce the maintenance burden, this package is only supported on
|
||||
Go 1.12+. Older versions of Go lack critical features and APIs which are
|
||||
necessary for this package to function correctly.
|
||||
|
||||
**If you depend on this package in your applications, please use Go modules.**
|
||||
|
||||
## Design
|
||||
|
||||
A [number of netlink packages](https://godoc.org/?q=netlink) are already
|
||||
available for Go, but I wasn't able to find one that aligned with what
|
||||
I wanted in a netlink package:
|
||||
|
||||
- Straightforward, idiomatic API
|
||||
- Well tested
|
||||
- Well documented
|
||||
- Doesn't use package/global variables or state
|
||||
- Doesn't necessarily need root to work
|
||||
|
||||
My goal for this package is to use it as a building block for the creation
|
||||
of other netlink family packages.
|
||||
|
||||
## Ecosystem
|
||||
|
||||
Over time, an ecosystem of Go packages has developed around package `netlink`.
|
||||
Many of these packages provide building blocks for further interactions with
|
||||
various netlink families, such as `NETLINK_GENERIC` or `NETLINK_ROUTE`.
|
||||
|
||||
To have your package included in this diagram, please send a pull request!
|
||||
|
||||

|
37
vendor/github.com/mdlayher/netlink/align.go
generated
vendored
Normal file
37
vendor/github.com/mdlayher/netlink/align.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package netlink
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// Functions and values used to properly align netlink messages, headers,
|
||||
// and attributes. Definitions taken from Linux kernel source.
|
||||
|
||||
// #define NLMSG_ALIGNTO 4U
|
||||
const nlmsgAlignTo = 4
|
||||
|
||||
// #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
|
||||
func nlmsgAlign(len int) int {
|
||||
return ((len) + nlmsgAlignTo - 1) & ^(nlmsgAlignTo - 1)
|
||||
}
|
||||
|
||||
// #define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
|
||||
func nlmsgLength(len int) int {
|
||||
return len + nlmsgHeaderLen
|
||||
}
|
||||
|
||||
// #define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
|
||||
var nlmsgHeaderLen = nlmsgAlign(int(unsafe.Sizeof(Header{})))
|
||||
|
||||
// #define NLA_ALIGNTO 4
|
||||
const nlaAlignTo = 4
|
||||
|
||||
// #define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
|
||||
func nlaAlign(len int) int {
|
||||
return ((len) + nlaAlignTo - 1) & ^(nlaAlignTo - 1)
|
||||
}
|
||||
|
||||
// Because this package's Attribute type contains a byte slice, unsafe.Sizeof
|
||||
// can't be used to determine the correct length.
|
||||
const sizeofAttribute = 4
|
||||
|
||||
// #define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr)))
|
||||
var nlaHeaderLen = nlaAlign(sizeofAttribute)
|
707
vendor/github.com/mdlayher/netlink/attribute.go
generated
vendored
Normal file
707
vendor/github.com/mdlayher/netlink/attribute.go
generated
vendored
Normal file
@@ -0,0 +1,707 @@
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/josharian/native"
|
||||
"github.com/mdlayher/netlink/nlenc"
|
||||
)
|
||||
|
||||
// errInvalidAttribute specifies if an Attribute's length is incorrect.
|
||||
var errInvalidAttribute = errors.New("invalid attribute; length too short or too large")
|
||||
|
||||
// An Attribute is a netlink attribute. Attributes are packed and unpacked
|
||||
// to and from the Data field of Message for some netlink families.
|
||||
type Attribute struct {
|
||||
// Length of an Attribute, including this field and Type.
|
||||
Length uint16
|
||||
|
||||
// The type of this Attribute, typically matched to a constant. Note that
|
||||
// flags such as Nested and NetByteOrder must be handled manually when
|
||||
// working with Attribute structures directly.
|
||||
Type uint16
|
||||
|
||||
// An arbitrary payload which is specified by Type.
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// marshal marshals the contents of a into b and returns the number of bytes
|
||||
// written to b, including attribute alignment padding.
|
||||
func (a *Attribute) marshal(b []byte) (int, error) {
|
||||
if int(a.Length) < nlaHeaderLen {
|
||||
return 0, errInvalidAttribute
|
||||
}
|
||||
|
||||
nlenc.PutUint16(b[0:2], a.Length)
|
||||
nlenc.PutUint16(b[2:4], a.Type)
|
||||
n := copy(b[nlaHeaderLen:], a.Data)
|
||||
|
||||
return nlaHeaderLen + nlaAlign(n), nil
|
||||
}
|
||||
|
||||
// unmarshal unmarshals the contents of a byte slice into an Attribute.
|
||||
func (a *Attribute) unmarshal(b []byte) error {
|
||||
if len(b) < nlaHeaderLen {
|
||||
return errInvalidAttribute
|
||||
}
|
||||
|
||||
a.Length = nlenc.Uint16(b[0:2])
|
||||
a.Type = nlenc.Uint16(b[2:4])
|
||||
|
||||
if int(a.Length) > len(b) {
|
||||
return errInvalidAttribute
|
||||
}
|
||||
|
||||
switch {
|
||||
// No length, no data
|
||||
case a.Length == 0:
|
||||
a.Data = make([]byte, 0)
|
||||
// Not enough length for any data
|
||||
case int(a.Length) < nlaHeaderLen:
|
||||
return errInvalidAttribute
|
||||
// Data present
|
||||
case int(a.Length) >= nlaHeaderLen:
|
||||
a.Data = make([]byte, len(b[nlaHeaderLen:a.Length]))
|
||||
copy(a.Data, b[nlaHeaderLen:a.Length])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalAttributes packs a slice of Attributes into a single byte slice.
|
||||
// In most cases, the Length field of each Attribute should be set to 0, so it
|
||||
// can be calculated and populated automatically for each Attribute.
|
||||
//
|
||||
// It is recommend to use the AttributeEncoder type where possible instead of
|
||||
// calling MarshalAttributes and using package nlenc functions directly.
|
||||
func MarshalAttributes(attrs []Attribute) ([]byte, error) {
|
||||
// Count how many bytes we should allocate to store each attribute's contents.
|
||||
var c int
|
||||
for _, a := range attrs {
|
||||
c += nlaHeaderLen + nlaAlign(len(a.Data))
|
||||
}
|
||||
|
||||
// Advance through b with idx to place attribute data at the correct offset.
|
||||
var idx int
|
||||
b := make([]byte, c)
|
||||
for _, a := range attrs {
|
||||
// Infer the length of attribute if zero.
|
||||
if a.Length == 0 {
|
||||
a.Length = uint16(nlaHeaderLen + len(a.Data))
|
||||
}
|
||||
|
||||
// Marshal a into b and advance idx to show many bytes are occupied.
|
||||
n, err := a.marshal(b[idx:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idx += n
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// UnmarshalAttributes unpacks a slice of Attributes from a single byte slice.
|
||||
//
|
||||
// It is recommend to use the AttributeDecoder type where possible instead of calling
|
||||
// UnmarshalAttributes and using package nlenc functions directly.
|
||||
func UnmarshalAttributes(b []byte) ([]Attribute, error) {
|
||||
ad, err := NewAttributeDecoder(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return a nil slice when there are no attributes to decode.
|
||||
if ad.Len() == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
attrs := make([]Attribute, 0, ad.Len())
|
||||
|
||||
for ad.Next() {
|
||||
if ad.attr().Length != 0 {
|
||||
attrs = append(attrs, ad.attr())
|
||||
}
|
||||
}
|
||||
|
||||
if err := ad.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return attrs, nil
|
||||
}
|
||||
|
||||
// An AttributeDecoder provides a safe, iterator-like, API around attribute
|
||||
// decoding.
|
||||
//
|
||||
// It is recommend to use an AttributeDecoder where possible instead of calling
|
||||
// UnmarshalAttributes and using package nlenc functions directly.
|
||||
//
|
||||
// The Err method must be called after the Next method returns false to determine
|
||||
// if any errors occurred during iteration.
|
||||
type AttributeDecoder struct {
|
||||
// ByteOrder defines a specific byte order to use when processing integer
|
||||
// attributes. ByteOrder should be set immediately after creating the
|
||||
// AttributeDecoder: before any attributes are parsed.
|
||||
//
|
||||
// If not set, the native byte order will be used.
|
||||
ByteOrder binary.ByteOrder
|
||||
|
||||
// The current attribute being worked on.
|
||||
a Attribute
|
||||
|
||||
// The slice of input bytes and its iterator index.
|
||||
b []byte
|
||||
i int
|
||||
|
||||
length int
|
||||
|
||||
// Any error encountered while decoding attributes.
|
||||
err error
|
||||
}
|
||||
|
||||
// NewAttributeDecoder creates an AttributeDecoder that unpacks Attributes
|
||||
// from b and prepares the decoder for iteration.
|
||||
func NewAttributeDecoder(b []byte) (*AttributeDecoder, error) {
|
||||
ad := &AttributeDecoder{
|
||||
// By default, use native byte order.
|
||||
ByteOrder: native.Endian,
|
||||
|
||||
b: b,
|
||||
}
|
||||
|
||||
var err error
|
||||
ad.length, err = ad.available()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ad, nil
|
||||
}
|
||||
|
||||
// Next advances the decoder to the next netlink attribute. It returns false
|
||||
// when no more attributes are present, or an error was encountered.
|
||||
func (ad *AttributeDecoder) Next() bool {
|
||||
if ad.err != nil {
|
||||
// Hit an error, stop iteration.
|
||||
return false
|
||||
}
|
||||
|
||||
// Exit if array pointer is at or beyond the end of the slice.
|
||||
if ad.i >= len(ad.b) {
|
||||
return false
|
||||
}
|
||||
|
||||
if err := ad.a.unmarshal(ad.b[ad.i:]); err != nil {
|
||||
ad.err = err
|
||||
return false
|
||||
}
|
||||
|
||||
// Advance the pointer by at least one header's length.
|
||||
if int(ad.a.Length) < nlaHeaderLen {
|
||||
ad.i += nlaHeaderLen
|
||||
} else {
|
||||
ad.i += nlaAlign(int(ad.a.Length))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Type returns the Attribute.Type field of the current netlink attribute
|
||||
// pointed to by the decoder.
|
||||
//
|
||||
// Type masks off the high bits of the netlink attribute type which may contain
|
||||
// the Nested and NetByteOrder flags. These can be obtained by calling TypeFlags.
|
||||
func (ad *AttributeDecoder) Type() uint16 {
|
||||
// Mask off any flags stored in the high bits.
|
||||
return ad.a.Type & attrTypeMask
|
||||
}
|
||||
|
||||
// TypeFlags returns the two high bits of the Attribute.Type field of the current
|
||||
// netlink attribute pointed to by the decoder.
|
||||
//
|
||||
// These bits of the netlink attribute type are used for the Nested and NetByteOrder
|
||||
// flags, available as the Nested and NetByteOrder constants in this package.
|
||||
func (ad *AttributeDecoder) TypeFlags() uint16 {
|
||||
return ad.a.Type & ^attrTypeMask
|
||||
}
|
||||
|
||||
// Len returns the number of netlink attributes pointed to by the decoder.
|
||||
func (ad *AttributeDecoder) Len() int { return ad.length }
|
||||
|
||||
// count scans the input slice to count the number of netlink attributes
|
||||
// that could be decoded by Next().
|
||||
func (ad *AttributeDecoder) available() (int, error) {
|
||||
var i, count int
|
||||
for {
|
||||
|
||||
// No more data to read.
|
||||
if i >= len(ad.b) {
|
||||
break
|
||||
}
|
||||
|
||||
// Make sure there's at least a header's worth
|
||||
// of data to read on each iteration.
|
||||
if len(ad.b[i:]) < nlaHeaderLen {
|
||||
return 0, errInvalidAttribute
|
||||
}
|
||||
|
||||
// Extract the length of the attribute.
|
||||
l := int(nlenc.Uint16(ad.b[i : i+2]))
|
||||
|
||||
// Ignore zero-length attributes.
|
||||
if l != 0 {
|
||||
count++
|
||||
}
|
||||
|
||||
// Advance by at least a header's worth of bytes.
|
||||
if l < nlaHeaderLen {
|
||||
l = nlaHeaderLen
|
||||
}
|
||||
|
||||
i += nlaAlign(l)
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// attr returns the current Attribute pointed to by the decoder.
|
||||
func (ad *AttributeDecoder) attr() Attribute {
|
||||
return ad.a
|
||||
}
|
||||
|
||||
// data returns the Data field of the current Attribute pointed to by the decoder.
|
||||
func (ad *AttributeDecoder) data() []byte {
|
||||
return ad.a.Data
|
||||
}
|
||||
|
||||
// Err returns the first error encountered by the decoder.
|
||||
func (ad *AttributeDecoder) Err() error {
|
||||
return ad.err
|
||||
}
|
||||
|
||||
// Bytes returns the raw bytes of the current Attribute's data.
|
||||
func (ad *AttributeDecoder) Bytes() []byte {
|
||||
src := ad.data()
|
||||
dest := make([]byte, len(src))
|
||||
copy(dest, src)
|
||||
return dest
|
||||
}
|
||||
|
||||
// String returns the string representation of the current Attribute's data.
|
||||
func (ad *AttributeDecoder) String() string {
|
||||
if ad.err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return nlenc.String(ad.data())
|
||||
}
|
||||
|
||||
// Uint8 returns the uint8 representation of the current Attribute's data.
|
||||
func (ad *AttributeDecoder) Uint8() uint8 {
|
||||
if ad.err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
b := ad.data()
|
||||
if len(b) != 1 {
|
||||
ad.err = fmt.Errorf("netlink: attribute %d is not a uint8; length: %d", ad.Type(), len(b))
|
||||
return 0
|
||||
}
|
||||
|
||||
return uint8(b[0])
|
||||
}
|
||||
|
||||
// Uint16 returns the uint16 representation of the current Attribute's data.
|
||||
func (ad *AttributeDecoder) Uint16() uint16 {
|
||||
if ad.err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
b := ad.data()
|
||||
if len(b) != 2 {
|
||||
ad.err = fmt.Errorf("netlink: attribute %d is not a uint16; length: %d", ad.Type(), len(b))
|
||||
return 0
|
||||
}
|
||||
|
||||
return ad.ByteOrder.Uint16(b)
|
||||
}
|
||||
|
||||
// Uint32 returns the uint32 representation of the current Attribute's data.
|
||||
func (ad *AttributeDecoder) Uint32() uint32 {
|
||||
if ad.err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
b := ad.data()
|
||||
if len(b) != 4 {
|
||||
ad.err = fmt.Errorf("netlink: attribute %d is not a uint32; length: %d", ad.Type(), len(b))
|
||||
return 0
|
||||
}
|
||||
|
||||
return ad.ByteOrder.Uint32(b)
|
||||
}
|
||||
|
||||
// Uint64 returns the uint64 representation of the current Attribute's data.
|
||||
func (ad *AttributeDecoder) Uint64() uint64 {
|
||||
if ad.err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
b := ad.data()
|
||||
if len(b) != 8 {
|
||||
ad.err = fmt.Errorf("netlink: attribute %d is not a uint64; length: %d", ad.Type(), len(b))
|
||||
return 0
|
||||
}
|
||||
|
||||
return ad.ByteOrder.Uint64(b)
|
||||
}
|
||||
|
||||
// Int8 returns the Int8 representation of the current Attribute's data.
|
||||
func (ad *AttributeDecoder) Int8() int8 {
|
||||
if ad.err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
b := ad.data()
|
||||
if len(b) != 1 {
|
||||
ad.err = fmt.Errorf("netlink: attribute %d is not a int8; length: %d", ad.Type(), len(b))
|
||||
return 0
|
||||
}
|
||||
|
||||
return int8(b[0])
|
||||
}
|
||||
|
||||
// Int16 returns the Int16 representation of the current Attribute's data.
|
||||
func (ad *AttributeDecoder) Int16() int16 {
|
||||
if ad.err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
b := ad.data()
|
||||
if len(b) != 2 {
|
||||
ad.err = fmt.Errorf("netlink: attribute %d is not a int16; length: %d", ad.Type(), len(b))
|
||||
return 0
|
||||
}
|
||||
|
||||
return int16(ad.ByteOrder.Uint16(b))
|
||||
}
|
||||
|
||||
// Int32 returns the Int32 representation of the current Attribute's data.
|
||||
func (ad *AttributeDecoder) Int32() int32 {
|
||||
if ad.err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
b := ad.data()
|
||||
if len(b) != 4 {
|
||||
ad.err = fmt.Errorf("netlink: attribute %d is not a int32; length: %d", ad.Type(), len(b))
|
||||
return 0
|
||||
}
|
||||
|
||||
return int32(ad.ByteOrder.Uint32(b))
|
||||
}
|
||||
|
||||
// Int64 returns the Int64 representation of the current Attribute's data.
|
||||
func (ad *AttributeDecoder) Int64() int64 {
|
||||
if ad.err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
b := ad.data()
|
||||
if len(b) != 8 {
|
||||
ad.err = fmt.Errorf("netlink: attribute %d is not a int64; length: %d", ad.Type(), len(b))
|
||||
return 0
|
||||
}
|
||||
|
||||
return int64(ad.ByteOrder.Uint64(b))
|
||||
}
|
||||
|
||||
// Flag returns a boolean representing the Attribute.
|
||||
func (ad *AttributeDecoder) Flag() bool {
|
||||
if ad.err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
b := ad.data()
|
||||
if len(b) != 0 {
|
||||
ad.err = fmt.Errorf("netlink: attribute %d is not a flag; length: %d", ad.Type(), len(b))
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Do is a general purpose function which allows access to the current data
|
||||
// pointed to by the AttributeDecoder.
|
||||
//
|
||||
// Do can be used to allow parsing arbitrary data within the context of the
|
||||
// decoder. Do is most useful when dealing with nested attributes, attribute
|
||||
// arrays, or decoding arbitrary types (such as C structures) which don't fit
|
||||
// cleanly into a typical unsigned integer value.
|
||||
//
|
||||
// The function fn should not retain any reference to the data b outside of the
|
||||
// scope of the function.
|
||||
func (ad *AttributeDecoder) Do(fn func(b []byte) error) {
|
||||
if ad.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b := ad.data()
|
||||
if err := fn(b); err != nil {
|
||||
ad.err = err
|
||||
}
|
||||
}
|
||||
|
||||
// Nested decodes data into a nested AttributeDecoder to handle nested netlink
|
||||
// attributes. When calling Nested, the Err method does not need to be called on
|
||||
// the nested AttributeDecoder.
|
||||
//
|
||||
// The nested AttributeDecoder nad inherits the same ByteOrder setting as the
|
||||
// top-level AttributeDecoder ad.
|
||||
func (ad *AttributeDecoder) Nested(fn func(nad *AttributeDecoder) error) {
|
||||
// Because we are wrapping Do, there is no need to check ad.err immediately.
|
||||
ad.Do(func(b []byte) error {
|
||||
nad, err := NewAttributeDecoder(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nad.ByteOrder = ad.ByteOrder
|
||||
|
||||
if err := fn(nad); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nad.Err()
|
||||
})
|
||||
}
|
||||
|
||||
// An AttributeEncoder provides a safe way to encode attributes.
|
||||
//
|
||||
// It is recommended to use an AttributeEncoder where possible instead of
|
||||
// calling MarshalAttributes or using package nlenc directly.
|
||||
//
|
||||
// Errors from intermediate encoding steps are returned in the call to
|
||||
// Encode.
|
||||
type AttributeEncoder struct {
|
||||
// ByteOrder defines a specific byte order to use when processing integer
|
||||
// attributes. ByteOrder should be set immediately after creating the
|
||||
// AttributeEncoder: before any attributes are encoded.
|
||||
//
|
||||
// If not set, the native byte order will be used.
|
||||
ByteOrder binary.ByteOrder
|
||||
|
||||
attrs []Attribute
|
||||
err error
|
||||
}
|
||||
|
||||
// NewAttributeEncoder creates an AttributeEncoder that encodes Attributes.
|
||||
func NewAttributeEncoder() *AttributeEncoder {
|
||||
return &AttributeEncoder{
|
||||
ByteOrder: native.Endian,
|
||||
}
|
||||
}
|
||||
|
||||
// Uint8 encodes uint8 data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Uint8(typ uint16, v uint8) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: []byte{v},
|
||||
})
|
||||
}
|
||||
|
||||
// Uint16 encodes uint16 data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Uint16(typ uint16, v uint16) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b := make([]byte, 2)
|
||||
ae.ByteOrder.PutUint16(b, v)
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// Uint32 encodes uint32 data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Uint32(typ uint16, v uint32) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b := make([]byte, 4)
|
||||
ae.ByteOrder.PutUint32(b, v)
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// Uint64 encodes uint64 data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Uint64(typ uint16, v uint64) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b := make([]byte, 8)
|
||||
ae.ByteOrder.PutUint64(b, v)
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// Int8 encodes int8 data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Int8(typ uint16, v int8) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: []byte{uint8(v)},
|
||||
})
|
||||
}
|
||||
|
||||
// Int16 encodes int16 data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Int16(typ uint16, v int16) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b := make([]byte, 2)
|
||||
ae.ByteOrder.PutUint16(b, uint16(v))
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// Int32 encodes int32 data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Int32(typ uint16, v int32) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b := make([]byte, 4)
|
||||
ae.ByteOrder.PutUint32(b, uint32(v))
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// Int64 encodes int64 data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Int64(typ uint16, v int64) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b := make([]byte, 8)
|
||||
ae.ByteOrder.PutUint64(b, uint64(v))
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// Flag encodes a flag into an Attribute specidied by typ.
|
||||
func (ae *AttributeEncoder) Flag(typ uint16, v bool) {
|
||||
// Only set flag on no previous error or v == true.
|
||||
if ae.err != nil || !v {
|
||||
return
|
||||
}
|
||||
|
||||
// Flags have no length or data fields.
|
||||
ae.attrs = append(ae.attrs, Attribute{Type: typ})
|
||||
}
|
||||
|
||||
// String encodes string s as a null-terminated string into an Attribute
|
||||
// specified by typ.
|
||||
func (ae *AttributeEncoder) String(typ uint16, s string) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: nlenc.Bytes(s),
|
||||
})
|
||||
}
|
||||
|
||||
// Bytes embeds raw byte data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Bytes(typ uint16, b []byte) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// Do is a general purpose function to encode arbitrary data into an attribute
|
||||
// specified by typ.
|
||||
//
|
||||
// Do is especially helpful in encoding nested attributes, attribute arrays,
|
||||
// or encoding arbitrary types (such as C structures) which don't fit cleanly
|
||||
// into an unsigned integer value.
|
||||
func (ae *AttributeEncoder) Do(typ uint16, fn func() ([]byte, error)) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b, err := fn()
|
||||
if err != nil {
|
||||
ae.err = err
|
||||
return
|
||||
}
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// Nested embeds data produced by a nested AttributeEncoder and flags that data
|
||||
// with the Nested flag. When calling Nested, the Encode method should not be
|
||||
// called on the nested AttributeEncoder.
|
||||
//
|
||||
// The nested AttributeEncoder nae inherits the same ByteOrder setting as the
|
||||
// top-level AttributeEncoder ae.
|
||||
func (ae *AttributeEncoder) Nested(typ uint16, fn func(nae *AttributeEncoder) error) {
|
||||
// Because we are wrapping Do, there is no need to check ae.err immediately.
|
||||
ae.Do(Nested|typ, func() ([]byte, error) {
|
||||
nae := NewAttributeEncoder()
|
||||
nae.ByteOrder = ae.ByteOrder
|
||||
|
||||
if err := fn(nae); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nae.Encode()
|
||||
})
|
||||
}
|
||||
|
||||
// Encode returns the encoded bytes representing the attributes.
|
||||
func (ae *AttributeEncoder) Encode() ([]byte, error) {
|
||||
if ae.err != nil {
|
||||
return nil, ae.err
|
||||
}
|
||||
|
||||
return MarshalAttributes(ae.attrs)
|
||||
}
|
561
vendor/github.com/mdlayher/netlink/conn.go
generated
vendored
Normal file
561
vendor/github.com/mdlayher/netlink/conn.go
generated
vendored
Normal file
@@ -0,0 +1,561 @@
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/bpf"
|
||||
)
|
||||
|
||||
// A Conn is a connection to netlink. A Conn can be used to send and
|
||||
// receives messages to and from netlink.
|
||||
//
|
||||
// A Conn is safe for concurrent use, but to avoid contention in
|
||||
// high-throughput applications, the caller should almost certainly create a
|
||||
// pool of Conns and distribute them among workers.
|
||||
//
|
||||
// A Conn is capable of manipulating netlink subsystems from within a specific
|
||||
// Linux network namespace, but special care must be taken when doing so. See
|
||||
// the documentation of Config for details.
|
||||
type Conn struct {
|
||||
// Atomics must come first.
|
||||
//
|
||||
// seq is an atomically incremented integer used to provide sequence
|
||||
// numbers when Conn.Send is called.
|
||||
seq uint32
|
||||
|
||||
// mu serializes access to the netlink socket for the request/response
|
||||
// transaction within Execute.
|
||||
mu sync.RWMutex
|
||||
|
||||
// sock is the operating system-specific implementation of
|
||||
// a netlink sockets connection.
|
||||
sock Socket
|
||||
|
||||
// pid is the PID assigned by netlink.
|
||||
pid uint32
|
||||
|
||||
// d provides debugging capabilities for a Conn if not nil.
|
||||
d *debugger
|
||||
}
|
||||
|
||||
// A Socket is an operating-system specific implementation of netlink
|
||||
// sockets used by Conn.
|
||||
type Socket interface {
|
||||
Close() error
|
||||
Send(m Message) error
|
||||
SendMessages(m []Message) error
|
||||
Receive() ([]Message, error)
|
||||
}
|
||||
|
||||
// Dial dials a connection to netlink, using the specified netlink family.
|
||||
// Config specifies optional configuration for Conn. If config is nil, a default
|
||||
// configuration will be used.
|
||||
func Dial(family int, config *Config) (*Conn, error) {
|
||||
// Use OS-specific dial() to create Socket
|
||||
c, pid, err := dial(family, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewConn(c, pid), nil
|
||||
}
|
||||
|
||||
// NewConn creates a Conn using the specified Socket and PID for netlink
|
||||
// communications.
|
||||
//
|
||||
// NewConn is primarily useful for tests. Most applications should use
|
||||
// Dial instead.
|
||||
func NewConn(sock Socket, pid uint32) *Conn {
|
||||
// Seed the sequence number using a random number generator.
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
seq := r.Uint32()
|
||||
|
||||
// Configure a debugger if arguments are set.
|
||||
var d *debugger
|
||||
if len(debugArgs) > 0 {
|
||||
d = newDebugger(debugArgs)
|
||||
}
|
||||
|
||||
return &Conn{
|
||||
seq: seq,
|
||||
sock: sock,
|
||||
pid: pid,
|
||||
d: d,
|
||||
}
|
||||
}
|
||||
|
||||
// debug executes fn with the debugger if the debugger is not nil.
|
||||
func (c *Conn) debug(fn func(d *debugger)) {
|
||||
if c.d == nil {
|
||||
return
|
||||
}
|
||||
|
||||
fn(c.d)
|
||||
}
|
||||
|
||||
// Close closes the connection and unblocks any pending read operations.
|
||||
func (c *Conn) Close() error {
|
||||
// Close does not acquire a lock because it must be able to interrupt any
|
||||
// blocked system calls, such as when Receive is waiting on a multicast
|
||||
// group message.
|
||||
//
|
||||
// We rely on the kernel to deal with concurrent operations to the netlink
|
||||
// socket itself.
|
||||
return newOpError("close", c.sock.Close())
|
||||
}
|
||||
|
||||
// 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 Validate.
|
||||
//
|
||||
// Execute acquires a lock for the duration of the function call which blocks
|
||||
// concurrent calls to Send, SendMessages, and Receive, in order to ensure
|
||||
// consistency between netlink request/reply messages.
|
||||
//
|
||||
// See the documentation of Send, Receive, and Validate for details about
|
||||
// each function.
|
||||
func (c *Conn) Execute(m Message) ([]Message, error) {
|
||||
// Acquire the write lock and invoke the internal implementations of Send
|
||||
// and Receive which require the lock already be held.
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
req, err := c.lockedSend(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := c.lockedReceive()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := Validate(req, res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// SendMessages sends multiple Messages to netlink. The handling of
|
||||
// a Header's Length, Sequence and PID fields is the same as when
|
||||
// calling Send.
|
||||
func (c *Conn) SendMessages(msgs []Message) ([]Message, error) {
|
||||
// Wait for any concurrent calls to Execute to finish before proceeding.
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
|
||||
for i := range msgs {
|
||||
c.fixMsg(&msgs[i], nlmsgLength(len(msgs[i].Data)))
|
||||
}
|
||||
|
||||
c.debug(func(d *debugger) {
|
||||
for _, m := range msgs {
|
||||
d.debugf(1, "send msgs: %+v", m)
|
||||
}
|
||||
})
|
||||
|
||||
if err := c.sock.SendMessages(msgs); err != nil {
|
||||
c.debug(func(d *debugger) {
|
||||
d.debugf(1, "send msgs: err: %v", err)
|
||||
})
|
||||
|
||||
return nil, newOpError("send-messages", err)
|
||||
}
|
||||
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
// Send sends a single Message to netlink. In most cases, a Header's Length,
|
||||
// Sequence, and PID fields should be set to 0, so they can be populated
|
||||
// automatically before the Message is sent. On success, Send returns a copy
|
||||
// of the Message with all parameters populated, for later validation.
|
||||
//
|
||||
// If Header.Length is 0, it will be automatically populated using the
|
||||
// correct length for the Message, including its payload.
|
||||
//
|
||||
// If Header.Sequence is 0, it will be automatically populated using the
|
||||
// next sequence number for this connection.
|
||||
//
|
||||
// If Header.PID is 0, it will be automatically populated using a PID
|
||||
// assigned by netlink.
|
||||
func (c *Conn) Send(m Message) (Message, error) {
|
||||
// Wait for any concurrent calls to Execute to finish before proceeding.
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
|
||||
return c.lockedSend(m)
|
||||
}
|
||||
|
||||
// lockedSend implements Send, but must be called with c.mu acquired for reading.
|
||||
// We rely on the kernel to deal with concurrent reads and writes to the netlink
|
||||
// socket itself.
|
||||
func (c *Conn) lockedSend(m Message) (Message, error) {
|
||||
c.fixMsg(&m, nlmsgLength(len(m.Data)))
|
||||
|
||||
c.debug(func(d *debugger) {
|
||||
d.debugf(1, "send: %+v", m)
|
||||
})
|
||||
|
||||
if err := c.sock.Send(m); err != nil {
|
||||
c.debug(func(d *debugger) {
|
||||
d.debugf(1, "send: err: %v", err)
|
||||
})
|
||||
|
||||
return Message{}, newOpError("send", err)
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Receive receives one or more messages from netlink. Multi-part messages are
|
||||
// handled transparently and returned as a single slice of Messages, with the
|
||||
// final empty "multi-part done" message removed.
|
||||
//
|
||||
// If any of the messages indicate a netlink error, that error will be returned.
|
||||
func (c *Conn) Receive() ([]Message, error) {
|
||||
// Wait for any concurrent calls to Execute to finish before proceeding.
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
|
||||
return c.lockedReceive()
|
||||
}
|
||||
|
||||
// lockedReceive implements Receive, but must be called with c.mu acquired for reading.
|
||||
// We rely on the kernel to deal with concurrent reads and writes to the netlink
|
||||
// socket itself.
|
||||
func (c *Conn) lockedReceive() ([]Message, error) {
|
||||
msgs, err := c.receive()
|
||||
if err != nil {
|
||||
c.debug(func(d *debugger) {
|
||||
d.debugf(1, "recv: err: %v", err)
|
||||
})
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.debug(func(d *debugger) {
|
||||
for _, m := range msgs {
|
||||
d.debugf(1, "recv: %+v", m)
|
||||
}
|
||||
})
|
||||
|
||||
// When using nltest, it's possible for zero messages to be returned by receive.
|
||||
if len(msgs) == 0 {
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
// Trim the final message with multi-part done indicator if
|
||||
// present.
|
||||
if m := msgs[len(msgs)-1]; m.Header.Flags&Multi != 0 && m.Header.Type == Done {
|
||||
return msgs[:len(msgs)-1], nil
|
||||
}
|
||||
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
// receive is the internal implementation of Conn.Receive, which can be called
|
||||
// recursively to handle multi-part messages.
|
||||
func (c *Conn) receive() ([]Message, error) {
|
||||
// NB: All non-nil errors returned from this function *must* be of type
|
||||
// OpError in order to maintain the appropriate contract with callers of
|
||||
// this package.
|
||||
//
|
||||
// This contract also applies to functions called within this function,
|
||||
// such as checkMessage.
|
||||
|
||||
var res []Message
|
||||
for {
|
||||
msgs, err := c.sock.Receive()
|
||||
if err != nil {
|
||||
return nil, newOpError("receive", err)
|
||||
}
|
||||
|
||||
// If this message is multi-part, we will need to continue looping to
|
||||
// drain all the messages from the socket.
|
||||
var multi bool
|
||||
|
||||
for _, m := range msgs {
|
||||
if err := checkMessage(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Does this message indicate a multi-part message?
|
||||
if m.Header.Flags&Multi == 0 {
|
||||
// No, check the next messages.
|
||||
continue
|
||||
}
|
||||
|
||||
// Does this message indicate the last message in a series of
|
||||
// multi-part messages from a single read?
|
||||
multi = m.Header.Type != Done
|
||||
}
|
||||
|
||||
res = append(res, msgs...)
|
||||
|
||||
if !multi {
|
||||
// No more messages coming.
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A groupJoinLeaver is a Socket that supports joining and leaving
|
||||
// netlink multicast groups.
|
||||
type groupJoinLeaver interface {
|
||||
Socket
|
||||
JoinGroup(group uint32) error
|
||||
LeaveGroup(group uint32) error
|
||||
}
|
||||
|
||||
// JoinGroup joins a netlink multicast group by its ID.
|
||||
func (c *Conn) JoinGroup(group uint32) error {
|
||||
conn, ok := c.sock.(groupJoinLeaver)
|
||||
if !ok {
|
||||
return notSupported("join-group")
|
||||
}
|
||||
|
||||
return newOpError("join-group", conn.JoinGroup(group))
|
||||
}
|
||||
|
||||
// LeaveGroup leaves a netlink multicast group by its ID.
|
||||
func (c *Conn) LeaveGroup(group uint32) error {
|
||||
conn, ok := c.sock.(groupJoinLeaver)
|
||||
if !ok {
|
||||
return notSupported("leave-group")
|
||||
}
|
||||
|
||||
return newOpError("leave-group", conn.LeaveGroup(group))
|
||||
}
|
||||
|
||||
// A bpfSetter is a Socket that supports setting and removing BPF filters.
|
||||
type bpfSetter interface {
|
||||
Socket
|
||||
bpf.Setter
|
||||
RemoveBPF() error
|
||||
}
|
||||
|
||||
// SetBPF attaches an assembled BPF program to a Conn.
|
||||
func (c *Conn) SetBPF(filter []bpf.RawInstruction) error {
|
||||
conn, ok := c.sock.(bpfSetter)
|
||||
if !ok {
|
||||
return notSupported("set-bpf")
|
||||
}
|
||||
|
||||
return newOpError("set-bpf", conn.SetBPF(filter))
|
||||
}
|
||||
|
||||
// RemoveBPF removes a BPF filter from a Conn.
|
||||
func (c *Conn) RemoveBPF() error {
|
||||
conn, ok := c.sock.(bpfSetter)
|
||||
if !ok {
|
||||
return notSupported("remove-bpf")
|
||||
}
|
||||
|
||||
return newOpError("remove-bpf", conn.RemoveBPF())
|
||||
}
|
||||
|
||||
// A deadlineSetter is a Socket that supports setting deadlines.
|
||||
type deadlineSetter interface {
|
||||
Socket
|
||||
SetDeadline(time.Time) error
|
||||
SetReadDeadline(time.Time) error
|
||||
SetWriteDeadline(time.Time) error
|
||||
}
|
||||
|
||||
// SetDeadline sets the read and write deadlines associated with the connection.
|
||||
func (c *Conn) SetDeadline(t time.Time) error {
|
||||
conn, ok := c.sock.(deadlineSetter)
|
||||
if !ok {
|
||||
return notSupported("set-deadline")
|
||||
}
|
||||
|
||||
return newOpError("set-deadline", conn.SetDeadline(t))
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the read deadline associated with the connection.
|
||||
func (c *Conn) SetReadDeadline(t time.Time) error {
|
||||
conn, ok := c.sock.(deadlineSetter)
|
||||
if !ok {
|
||||
return notSupported("set-read-deadline")
|
||||
}
|
||||
|
||||
return newOpError("set-read-deadline", conn.SetReadDeadline(t))
|
||||
}
|
||||
|
||||
// SetWriteDeadline sets the write deadline associated with the connection.
|
||||
func (c *Conn) SetWriteDeadline(t time.Time) error {
|
||||
conn, ok := c.sock.(deadlineSetter)
|
||||
if !ok {
|
||||
return notSupported("set-write-deadline")
|
||||
}
|
||||
|
||||
return newOpError("set-write-deadline", conn.SetWriteDeadline(t))
|
||||
}
|
||||
|
||||
// A ConnOption is a boolean option that may be set for a Conn.
|
||||
type ConnOption int
|
||||
|
||||
// Possible ConnOption values. These constants are equivalent to the Linux
|
||||
// setsockopt boolean options for netlink sockets.
|
||||
const (
|
||||
PacketInfo ConnOption = iota
|
||||
BroadcastError
|
||||
NoENOBUFS
|
||||
ListenAllNSID
|
||||
CapAcknowledge
|
||||
ExtendedAcknowledge
|
||||
GetStrictCheck
|
||||
)
|
||||
|
||||
// An optionSetter is a Socket that supports setting netlink options.
|
||||
type optionSetter interface {
|
||||
Socket
|
||||
SetOption(option ConnOption, enable bool) error
|
||||
}
|
||||
|
||||
// SetOption enables or disables a netlink socket option for the Conn.
|
||||
func (c *Conn) SetOption(option ConnOption, enable bool) error {
|
||||
conn, ok := c.sock.(optionSetter)
|
||||
if !ok {
|
||||
return notSupported("set-option")
|
||||
}
|
||||
|
||||
return newOpError("set-option", conn.SetOption(option, enable))
|
||||
}
|
||||
|
||||
// A bufferSetter is a Socket that supports setting connection buffer sizes.
|
||||
type bufferSetter interface {
|
||||
Socket
|
||||
SetReadBuffer(bytes int) error
|
||||
SetWriteBuffer(bytes int) error
|
||||
}
|
||||
|
||||
// SetReadBuffer sets the size of the operating system's receive buffer
|
||||
// associated with the Conn.
|
||||
func (c *Conn) SetReadBuffer(bytes int) error {
|
||||
conn, ok := c.sock.(bufferSetter)
|
||||
if !ok {
|
||||
return notSupported("set-read-buffer")
|
||||
}
|
||||
|
||||
return newOpError("set-read-buffer", conn.SetReadBuffer(bytes))
|
||||
}
|
||||
|
||||
// SetWriteBuffer sets the size of the operating system's transmit buffer
|
||||
// associated with the Conn.
|
||||
func (c *Conn) SetWriteBuffer(bytes int) error {
|
||||
conn, ok := c.sock.(bufferSetter)
|
||||
if !ok {
|
||||
return notSupported("set-write-buffer")
|
||||
}
|
||||
|
||||
return newOpError("set-write-buffer", conn.SetWriteBuffer(bytes))
|
||||
}
|
||||
|
||||
// A syscallConner is a Socket that supports syscall.Conn.
|
||||
type syscallConner interface {
|
||||
Socket
|
||||
syscall.Conn
|
||||
}
|
||||
|
||||
var _ syscall.Conn = &Conn{}
|
||||
|
||||
// SyscallConn returns a raw network connection. This implements the
|
||||
// syscall.Conn interface.
|
||||
//
|
||||
// SyscallConn is intended for advanced use cases, such as getting and setting
|
||||
// arbitrary socket options using the netlink socket's file descriptor.
|
||||
//
|
||||
// Once invoked, it is the caller's responsibility to ensure that operations
|
||||
// performed using Conn and the syscall.RawConn do not conflict with
|
||||
// each other.
|
||||
func (c *Conn) SyscallConn() (syscall.RawConn, error) {
|
||||
sc, ok := c.sock.(syscallConner)
|
||||
if !ok {
|
||||
return nil, notSupported("syscall-conn")
|
||||
}
|
||||
|
||||
// TODO(mdlayher): mutex or similar to enforce syscall.RawConn contract of
|
||||
// FD remaining valid for duration of calls?
|
||||
|
||||
return sc.SyscallConn()
|
||||
}
|
||||
|
||||
// fixMsg updates the fields of m using the logic specified in Send.
|
||||
func (c *Conn) fixMsg(m *Message, ml int) {
|
||||
if m.Header.Length == 0 {
|
||||
m.Header.Length = uint32(nlmsgAlign(ml))
|
||||
}
|
||||
|
||||
if m.Header.Sequence == 0 {
|
||||
m.Header.Sequence = c.nextSequence()
|
||||
}
|
||||
|
||||
if m.Header.PID == 0 {
|
||||
m.Header.PID = c.pid
|
||||
}
|
||||
}
|
||||
|
||||
// nextSequence atomically increments Conn's sequence number and returns
|
||||
// the incremented value.
|
||||
func (c *Conn) nextSequence() uint32 {
|
||||
return atomic.AddUint32(&c.seq, 1)
|
||||
}
|
||||
|
||||
// Validate validates one or more reply Messages against a request Message,
|
||||
// ensuring that they contain matching sequence numbers and PIDs.
|
||||
func Validate(request Message, replies []Message) error {
|
||||
for _, m := range replies {
|
||||
// Check for mismatched sequence, unless:
|
||||
// - request had no sequence, meaning we are probably validating
|
||||
// a multicast reply
|
||||
if m.Header.Sequence != request.Header.Sequence && request.Header.Sequence != 0 {
|
||||
return newOpError("validate", errMismatchedSequence)
|
||||
}
|
||||
|
||||
// Check for mismatched PID, unless:
|
||||
// - request had no PID, meaning we are either:
|
||||
// - validating a multicast reply
|
||||
// - netlink has not yet assigned us a PID
|
||||
// - response had no PID, meaning it's from the kernel as a multicast reply
|
||||
if m.Header.PID != request.Header.PID && request.Header.PID != 0 && m.Header.PID != 0 {
|
||||
return newOpError("validate", errMismatchedPID)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Config contains options for a Conn.
|
||||
type Config struct {
|
||||
// Groups is a bitmask which specifies multicast groups. If set to 0,
|
||||
// no multicast group subscriptions will be made.
|
||||
Groups uint32
|
||||
|
||||
// NetNS specifies the network namespace the Conn will operate in.
|
||||
//
|
||||
// If set (non-zero), Conn will enter the specified network namespace and
|
||||
// an error will occur in Dial if the operation fails.
|
||||
//
|
||||
// If not set (zero), a best-effort attempt will be made to enter the
|
||||
// network namespace of the calling thread: this means that any changes made
|
||||
// to the calling thread's network namespace will also be reflected in Conn.
|
||||
// If this operation fails (due to lack of permissions or because network
|
||||
// namespaces are disabled by kernel configuration), Dial will not return
|
||||
// an error, and the Conn will operate in the default network namespace of
|
||||
// the process. This enables non-privileged use of Conn in applications
|
||||
// which do not require elevated privileges.
|
||||
//
|
||||
// Entering a network namespace is a privileged operation (root or
|
||||
// CAP_SYS_ADMIN are required), and most applications should leave this set
|
||||
// to 0.
|
||||
NetNS int
|
||||
|
||||
// DisableNSLockThread is deprecated and has no effect.
|
||||
DisableNSLockThread bool
|
||||
}
|
254
vendor/github.com/mdlayher/netlink/conn_linux.go
generated
vendored
Normal file
254
vendor/github.com/mdlayher/netlink/conn_linux.go
generated
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
//+build linux
|
||||
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/mdlayher/socket"
|
||||
"golang.org/x/net/bpf"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var _ Socket = &conn{}
|
||||
|
||||
// A conn is the Linux implementation of a netlink sockets connection.
|
||||
type conn struct {
|
||||
s *socket.Conn
|
||||
}
|
||||
|
||||
// dial is the entry point for Dial. dial opens a netlink socket using
|
||||
// system calls, and returns its PID.
|
||||
func dial(family int, config *Config) (*conn, uint32, error) {
|
||||
if config == nil {
|
||||
config = &Config{}
|
||||
}
|
||||
|
||||
// The caller has indicated it wants the netlink socket to be created
|
||||
// inside another network namespace.
|
||||
if config.NetNS != 0 {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
// Retrieve and store the calling OS thread's network namespace so
|
||||
// the thread can be reassigned to it after creating a socket in another
|
||||
// network namespace.
|
||||
threadNS, err := threadNetNS()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
// Always close the netns handle created above.
|
||||
defer threadNS.Close()
|
||||
|
||||
// Assign the current OS thread the goroutine is locked to to the given
|
||||
// network namespace.
|
||||
if err := threadNS.Set(config.NetNS); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// Thread's namespace has been successfully set. Return the thread
|
||||
// back to its original namespace after attempting to create the
|
||||
// netlink socket.
|
||||
defer threadNS.Restore()
|
||||
}
|
||||
|
||||
// Prepare the netlink socket.
|
||||
s, err := socket.Socket(unix.AF_NETLINK, unix.SOCK_RAW, family, "netlink")
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return newConn(s, config)
|
||||
}
|
||||
|
||||
// newConn binds a connection to netlink using the input *socket.Conn.
|
||||
func newConn(s *socket.Conn, config *Config) (*conn, uint32, error) {
|
||||
if config == nil {
|
||||
config = &Config{}
|
||||
}
|
||||
|
||||
addr := &unix.SockaddrNetlink{
|
||||
Family: unix.AF_NETLINK,
|
||||
Groups: config.Groups,
|
||||
}
|
||||
|
||||
// Socket must be closed in the event of any system call errors, to avoid
|
||||
// leaking file descriptors.
|
||||
|
||||
if err := s.Bind(addr); err != nil {
|
||||
_ = s.Close()
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
sa, err := s.Getsockname()
|
||||
if err != nil {
|
||||
_ = s.Close()
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return &conn{
|
||||
s: s,
|
||||
}, sa.(*unix.SockaddrNetlink).Pid, nil
|
||||
}
|
||||
|
||||
// SendMessages serializes multiple Messages and sends them to netlink.
|
||||
func (c *conn) SendMessages(messages []Message) error {
|
||||
var buf []byte
|
||||
for _, m := range messages {
|
||||
b, err := m.MarshalBinary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf = append(buf, b...)
|
||||
}
|
||||
|
||||
sa := &unix.SockaddrNetlink{Family: unix.AF_NETLINK}
|
||||
return c.s.Sendmsg(buf, nil, sa, 0)
|
||||
}
|
||||
|
||||
// Send sends a single Message to netlink.
|
||||
func (c *conn) Send(m Message) error {
|
||||
b, err := m.MarshalBinary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sa := &unix.SockaddrNetlink{Family: unix.AF_NETLINK}
|
||||
return c.s.Sendmsg(b, nil, sa, 0)
|
||||
}
|
||||
|
||||
// Receive receives one or more Messages from netlink.
|
||||
func (c *conn) Receive() ([]Message, error) {
|
||||
b := make([]byte, os.Getpagesize())
|
||||
for {
|
||||
// Peek at the buffer to see how many bytes are available.
|
||||
//
|
||||
// TODO(mdlayher): deal with OOB message data if available, such as
|
||||
// when PacketInfo ConnOption is true.
|
||||
n, _, _, _, err := c.s.Recvmsg(b, nil, unix.MSG_PEEK)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Break when we can read all messages
|
||||
if n < len(b) {
|
||||
break
|
||||
}
|
||||
|
||||
// Double in size if not enough bytes
|
||||
b = make([]byte, len(b)*2)
|
||||
}
|
||||
|
||||
// Read out all available messages
|
||||
n, _, _, _, err := c.s.Recvmsg(b, nil, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
raw, err := syscall.ParseNetlinkMessage(b[:nlmsgAlign(n)])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgs := make([]Message, 0, len(raw))
|
||||
for _, r := range raw {
|
||||
m := Message{
|
||||
Header: sysToHeader(r.Header),
|
||||
Data: r.Data,
|
||||
}
|
||||
|
||||
msgs = append(msgs, m)
|
||||
}
|
||||
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
// Close closes the connection.
|
||||
func (c *conn) Close() error { return c.s.Close() }
|
||||
|
||||
// JoinGroup joins a multicast group by ID.
|
||||
func (c *conn) JoinGroup(group uint32) error {
|
||||
return c.s.SetsockoptInt(unix.SOL_NETLINK, unix.NETLINK_ADD_MEMBERSHIP, int(group))
|
||||
}
|
||||
|
||||
// LeaveGroup leaves a multicast group by ID.
|
||||
func (c *conn) LeaveGroup(group uint32) error {
|
||||
return c.s.SetsockoptInt(unix.SOL_NETLINK, unix.NETLINK_DROP_MEMBERSHIP, int(group))
|
||||
}
|
||||
|
||||
// SetBPF attaches an assembled BPF program to a conn.
|
||||
func (c *conn) SetBPF(filter []bpf.RawInstruction) error { return c.s.SetBPF(filter) }
|
||||
|
||||
// RemoveBPF removes a BPF filter from a conn.
|
||||
func (c *conn) RemoveBPF() error { return c.s.RemoveBPF() }
|
||||
|
||||
// SetOption enables or disables a netlink socket option for the Conn.
|
||||
func (c *conn) SetOption(option ConnOption, enable bool) error {
|
||||
o, ok := linuxOption(option)
|
||||
if !ok {
|
||||
// Return the typical Linux error for an unknown ConnOption.
|
||||
return os.NewSyscallError("setsockopt", unix.ENOPROTOOPT)
|
||||
}
|
||||
|
||||
var v int
|
||||
if enable {
|
||||
v = 1
|
||||
}
|
||||
|
||||
return c.s.SetsockoptInt(unix.SOL_NETLINK, o, v)
|
||||
}
|
||||
|
||||
func (c *conn) SetDeadline(t time.Time) error { return c.s.SetDeadline(t) }
|
||||
func (c *conn) SetReadDeadline(t time.Time) error { return c.s.SetReadDeadline(t) }
|
||||
func (c *conn) SetWriteDeadline(t time.Time) error { return c.s.SetWriteDeadline(t) }
|
||||
|
||||
// SetReadBuffer sets the size of the operating system's receive buffer
|
||||
// associated with the Conn.
|
||||
func (c *conn) SetReadBuffer(bytes int) error { return c.s.SetReadBuffer(bytes) }
|
||||
|
||||
// SetReadBuffer sets the size of the operating system's transmit buffer
|
||||
// associated with the Conn.
|
||||
func (c *conn) SetWriteBuffer(bytes int) error { return c.s.SetWriteBuffer(bytes) }
|
||||
|
||||
// SyscallConn returns a raw network connection.
|
||||
func (c *conn) SyscallConn() (syscall.RawConn, error) { return c.s.SyscallConn() }
|
||||
|
||||
// linuxOption converts a ConnOption to its Linux value.
|
||||
func linuxOption(o ConnOption) (int, bool) {
|
||||
switch o {
|
||||
case PacketInfo:
|
||||
return unix.NETLINK_PKTINFO, true
|
||||
case BroadcastError:
|
||||
return unix.NETLINK_BROADCAST_ERROR, true
|
||||
case NoENOBUFS:
|
||||
return unix.NETLINK_NO_ENOBUFS, true
|
||||
case ListenAllNSID:
|
||||
return unix.NETLINK_LISTEN_ALL_NSID, true
|
||||
case CapAcknowledge:
|
||||
return unix.NETLINK_CAP_ACK, true
|
||||
case ExtendedAcknowledge:
|
||||
return unix.NETLINK_EXT_ACK, true
|
||||
case GetStrictCheck:
|
||||
return unix.NETLINK_GET_STRICT_CHK, true
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
|
||||
// sysToHeader converts a syscall.NlMsghdr to a Header.
|
||||
func sysToHeader(r syscall.NlMsghdr) Header {
|
||||
// NB: the memory layout of Header and syscall.NlMsgHdr must be
|
||||
// exactly the same for this unsafe cast to work
|
||||
return *(*Header)(unsafe.Pointer(&r))
|
||||
}
|
||||
|
||||
// newError converts an error number from netlink into the appropriate
|
||||
// system call error for Linux.
|
||||
func newError(errno int) error {
|
||||
return syscall.Errno(errno)
|
||||
}
|
29
vendor/github.com/mdlayher/netlink/conn_others.go
generated
vendored
Normal file
29
vendor/github.com/mdlayher/netlink/conn_others.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
//+build !linux
|
||||
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// errUnimplemented is returned by all functions on platforms that
|
||||
// cannot make use of netlink sockets.
|
||||
var errUnimplemented = fmt.Errorf("netlink: not implemented on %s/%s",
|
||||
runtime.GOOS, runtime.GOARCH)
|
||||
|
||||
var _ Socket = &conn{}
|
||||
|
||||
// A conn is the no-op implementation of a netlink sockets connection.
|
||||
type conn struct{}
|
||||
|
||||
// All cross-platform functions and Socket methods are unimplemented outside
|
||||
// of Linux.
|
||||
|
||||
func dial(_ int, _ *Config) (*conn, uint32, error) { return nil, 0, errUnimplemented }
|
||||
func newError(_ int) error { return errUnimplemented }
|
||||
|
||||
func (c *conn) Send(_ Message) error { return errUnimplemented }
|
||||
func (c *conn) SendMessages(_ []Message) error { return errUnimplemented }
|
||||
func (c *conn) Receive() ([]Message, error) { return nil, errUnimplemented }
|
||||
func (c *conn) Close() error { return errUnimplemented }
|
69
vendor/github.com/mdlayher/netlink/debug.go
generated
vendored
Normal file
69
vendor/github.com/mdlayher/netlink/debug.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Arguments used to create a debugger.
|
||||
var debugArgs []string
|
||||
|
||||
func init() {
|
||||
// Is netlink debugging enabled?
|
||||
s := os.Getenv("NLDEBUG")
|
||||
if s == "" {
|
||||
return
|
||||
}
|
||||
|
||||
debugArgs = strings.Split(s, ",")
|
||||
}
|
||||
|
||||
// A debugger is used to provide debugging information about a netlink connection.
|
||||
type debugger struct {
|
||||
Log *log.Logger
|
||||
Level int
|
||||
}
|
||||
|
||||
// newDebugger creates a debugger by parsing key=value arguments.
|
||||
func newDebugger(args []string) *debugger {
|
||||
d := &debugger{
|
||||
Log: log.New(os.Stderr, "nl: ", 0),
|
||||
Level: 1,
|
||||
}
|
||||
|
||||
for _, a := range args {
|
||||
kv := strings.Split(a, "=")
|
||||
if len(kv) != 2 {
|
||||
// Ignore malformed pairs and assume callers wants defaults.
|
||||
continue
|
||||
}
|
||||
|
||||
switch kv[0] {
|
||||
// Select the log level for the debugger.
|
||||
case "level":
|
||||
level, err := strconv.Atoi(kv[1])
|
||||
if err != nil {
|
||||
panicf("netlink: invalid NLDEBUG level: %q", a)
|
||||
}
|
||||
|
||||
d.Level = level
|
||||
}
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
// debugf prints debugging information at the specified level, if d.Level is
|
||||
// high enough to print the message.
|
||||
func (d *debugger) debugf(level int, format string, v ...interface{}) {
|
||||
if d.Level >= level {
|
||||
d.Log.Printf(format, v...)
|
||||
}
|
||||
}
|
||||
|
||||
func panicf(format string, a ...interface{}) {
|
||||
panic(fmt.Sprintf(format, a...))
|
||||
}
|
36
vendor/github.com/mdlayher/netlink/doc.go
generated
vendored
Normal file
36
vendor/github.com/mdlayher/netlink/doc.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// Package netlink provides low-level access to Linux netlink sockets.
|
||||
//
|
||||
// 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!
|
||||
//
|
||||
//
|
||||
// Network namespaces
|
||||
//
|
||||
// This package is aware of Linux network namespaces, and can enter different
|
||||
// network namespaces either implicitly or explicitly, depending on
|
||||
// configuration. The Config structure passed to Dial to create a Conn controls
|
||||
// these behaviors. See the documentation of Config.NetNS for details.
|
||||
//
|
||||
//
|
||||
// Debugging
|
||||
//
|
||||
// This package supports rudimentary netlink connection debugging support.
|
||||
// To enable this, run your binary with the NLDEBUG environment variable set.
|
||||
// Debugging information will be output to stderr with a prefix of "nl:".
|
||||
//
|
||||
// To use the debugging defaults, use:
|
||||
//
|
||||
// $ NLDEBUG=1 ./nlctl
|
||||
//
|
||||
// To configure individual aspects of the debugger, pass key/value options such
|
||||
// as:
|
||||
//
|
||||
// $ NLDEBUG=level=1 ./nlctl
|
||||
//
|
||||
// Available key/value debugger options include:
|
||||
//
|
||||
// level=N: specify the debugging level (only "1" is currently supported)
|
||||
package netlink
|
||||
|
||||
//go:generate dot netlink.dot -T svg -o netlink.svg
|
143
vendor/github.com/mdlayher/netlink/errors.go
generated
vendored
Normal file
143
vendor/github.com/mdlayher/netlink/errors.go
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Error messages which can be returned by Validate.
|
||||
var (
|
||||
errMismatchedSequence = errors.New("mismatched sequence in netlink reply")
|
||||
errMismatchedPID = errors.New("mismatched PID in netlink reply")
|
||||
errShortErrorMessage = errors.New("not enough data for netlink error code")
|
||||
)
|
||||
|
||||
// Errors which can be returned by a Socket that does not implement
|
||||
// all exposed methods of Conn.
|
||||
|
||||
var errNotSupported = errors.New("operation not supported")
|
||||
|
||||
// notSupported provides a concise constructor for "not supported" errors.
|
||||
func notSupported(op string) error {
|
||||
return newOpError(op, errNotSupported)
|
||||
}
|
||||
|
||||
// IsNotExist determines if an error is produced as the result of querying some
|
||||
// file, object, resource, etc. which does not exist. Users of this package
|
||||
// should always use netlink.IsNotExist, rather than os.IsNotExist, when
|
||||
// checking for specific netlink-related errors.
|
||||
//
|
||||
// Errors types created by this package, such as OpError, can be used with
|
||||
// IsNotExist, but this function also defers to the behavior of os.IsNotExist
|
||||
// for unrecognized error types.
|
||||
//
|
||||
// Deprecated: make use of errors.Unwrap and errors.Is in Go 1.13+.
|
||||
func IsNotExist(err error) bool {
|
||||
switch err := err.(type) {
|
||||
case *OpError:
|
||||
// Unwrap the inner error and use the stdlib's logic.
|
||||
return os.IsNotExist(err.Err)
|
||||
default:
|
||||
return os.IsNotExist(err)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
_ error = &OpError{}
|
||||
_ net.Error = &OpError{}
|
||||
// Ensure compatibility with Go 1.13+ errors package.
|
||||
_ interface{ Unwrap() error } = &OpError{}
|
||||
)
|
||||
|
||||
// An OpError is an error produced as the result of a failed netlink operation.
|
||||
type OpError struct {
|
||||
// Op is the operation which caused this OpError, such as "send"
|
||||
// or "receive".
|
||||
Op string
|
||||
|
||||
// Err is the underlying error which caused this OpError.
|
||||
//
|
||||
// If Err was produced by a system call error, Err will be of type
|
||||
// *os.SyscallError. If Err was produced by an error code in a netlink
|
||||
// message, Err will contain a raw error value type such as a unix.Errno.
|
||||
//
|
||||
// Most callers should inspect Err using errors.Is from the standard
|
||||
// library.
|
||||
Err error
|
||||
|
||||
// Message and Offset contain additional error information provided by the
|
||||
// kernel when the ExtendedAcknowledge option is set on a Conn and the
|
||||
// kernel indicates the AcknowledgeTLVs flag in a response. If this option
|
||||
// is not set, both of these fields will be empty.
|
||||
Message string
|
||||
Offset int
|
||||
}
|
||||
|
||||
// newOpError is a small wrapper for creating an OpError. As a convenience, it
|
||||
// returns nil if the input err is nil: akin to os.NewSyscallError.
|
||||
func newOpError(op string, err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &OpError{
|
||||
Op: op,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *OpError) Error() string {
|
||||
if e == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
|
||||
var sb strings.Builder
|
||||
_, _ = sb.WriteString(fmt.Sprintf("netlink %s: %v", e.Op, e.Err))
|
||||
|
||||
if e.Message != "" || e.Offset != 0 {
|
||||
_, _ = sb.WriteString(fmt.Sprintf(", offset: %d, message: %q",
|
||||
e.Offset, e.Message))
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// Unwrap unwraps the internal Err field for use with errors.Unwrap.
|
||||
func (e *OpError) Unwrap() error { return e.Err }
|
||||
|
||||
// Portions of this code taken from the Go standard library:
|
||||
//
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
type timeout interface {
|
||||
Timeout() bool
|
||||
}
|
||||
|
||||
// Timeout reports whether the error was caused by an I/O timeout.
|
||||
func (e *OpError) Timeout() bool {
|
||||
if ne, ok := e.Err.(*os.SyscallError); ok {
|
||||
t, ok := ne.Err.(timeout)
|
||||
return ok && t.Timeout()
|
||||
}
|
||||
t, ok := e.Err.(timeout)
|
||||
return ok && t.Timeout()
|
||||
}
|
||||
|
||||
type temporary interface {
|
||||
Temporary() bool
|
||||
}
|
||||
|
||||
// Temporary reports whether an operation may succeed if retried.
|
||||
func (e *OpError) Temporary() bool {
|
||||
if ne, ok := e.Err.(*os.SyscallError); ok {
|
||||
t, ok := ne.Err.(temporary)
|
||||
return ok && t.Temporary()
|
||||
}
|
||||
t, ok := e.Err.(temporary)
|
||||
return ok && t.Temporary()
|
||||
}
|
81
vendor/github.com/mdlayher/netlink/fuzz.go
generated
vendored
Normal file
81
vendor/github.com/mdlayher/netlink/fuzz.go
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
//+build gofuzz
|
||||
|
||||
package netlink
|
||||
|
||||
import "github.com/google/go-cmp/cmp"
|
||||
|
||||
func fuzz(b1 []byte) int {
|
||||
// 1. unmarshal, marshal, unmarshal again to check m1 and m2 for equality
|
||||
// after a round trip. checkMessage is also used because there is a fair
|
||||
// amount of tricky logic around testing for presence of error headers and
|
||||
// extended acknowledgement attributes.
|
||||
var m1 Message
|
||||
if err := m1.UnmarshalBinary(b1); err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
if err := checkMessage(m1); err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
b2, err := m1.MarshalBinary()
|
||||
if err != nil {
|
||||
panicf("failed to marshal m1: %v", err)
|
||||
}
|
||||
|
||||
var m2 Message
|
||||
if err := m2.UnmarshalBinary(b2); err != nil {
|
||||
panicf("failed to unmarshal m2: %v", err)
|
||||
}
|
||||
|
||||
if err := checkMessage(m2); err != nil {
|
||||
panicf("failed to check m2: %v", err)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(m1, m2); diff != "" {
|
||||
panicf("unexpected Message (-want +got):\n%s", diff)
|
||||
}
|
||||
|
||||
// 2. marshal again and compare b2 and b3 (b1 may have reserved bytes set
|
||||
// which we ignore and fill with zeros when marshaling) for equality.
|
||||
b3, err := m2.MarshalBinary()
|
||||
if err != nil {
|
||||
panicf("failed to marshal m2: %v", err)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(b2, b3); diff != "" {
|
||||
panicf("unexpected message bytes (-want +got):\n%s", diff)
|
||||
}
|
||||
|
||||
// 3. unmarshal any possible attributes from m1's data and marshal them
|
||||
// again for comparison.
|
||||
a1, err := UnmarshalAttributes(m1.Data)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
ab1, err := MarshalAttributes(a1)
|
||||
if err != nil {
|
||||
panicf("failed to marshal a1: %v", err)
|
||||
}
|
||||
|
||||
a2, err := UnmarshalAttributes(ab1)
|
||||
if err != nil {
|
||||
panicf("failed to unmarshal a2: %v", err)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(a1, a2); diff != "" {
|
||||
panicf("unexpected Attributes (-want +got):\n%s", diff)
|
||||
}
|
||||
|
||||
ab2, err := MarshalAttributes(a2)
|
||||
if err != nil {
|
||||
panicf("failed to marshal a2: %v", err)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(ab1, ab2); diff != "" {
|
||||
panicf("unexpected attribute bytes (-want +got):\n%s", diff)
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
347
vendor/github.com/mdlayher/netlink/message.go
generated
vendored
Normal file
347
vendor/github.com/mdlayher/netlink/message.go
generated
vendored
Normal file
@@ -0,0 +1,347 @@
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/mdlayher/netlink/nlenc"
|
||||
)
|
||||
|
||||
// Flags which may apply to netlink attribute types when communicating with
|
||||
// certain netlink families.
|
||||
const (
|
||||
Nested uint16 = 0x8000
|
||||
NetByteOrder uint16 = 0x4000
|
||||
|
||||
// attrTypeMask masks off Type bits used for the above flags.
|
||||
attrTypeMask uint16 = 0x3fff
|
||||
)
|
||||
|
||||
// Various errors which may occur when attempting to marshal or unmarshal
|
||||
// a Message to and from its binary form.
|
||||
var (
|
||||
errIncorrectMessageLength = errors.New("netlink message header length incorrect")
|
||||
errShortMessage = errors.New("not enough data to create a netlink message")
|
||||
errUnalignedMessage = errors.New("input data is not properly aligned for netlink message")
|
||||
)
|
||||
|
||||
// HeaderFlags specify flags which may be present in a Header.
|
||||
type HeaderFlags uint16
|
||||
|
||||
const (
|
||||
// General netlink communication flags.
|
||||
|
||||
// Request indicates a request to netlink.
|
||||
Request HeaderFlags = 1
|
||||
|
||||
// Multi indicates a multi-part message, terminated by Done on the
|
||||
// last message.
|
||||
Multi HeaderFlags = 2
|
||||
|
||||
// Acknowledge requests that netlink reply with an acknowledgement
|
||||
// using Error and, if needed, an error code.
|
||||
Acknowledge HeaderFlags = 4
|
||||
|
||||
// Echo requests that netlink echo this request back to the sender.
|
||||
Echo HeaderFlags = 8
|
||||
|
||||
// DumpInterrupted indicates that a dump was inconsistent due to a
|
||||
// sequence change.
|
||||
DumpInterrupted HeaderFlags = 16
|
||||
|
||||
// DumpFiltered indicates that a dump was filtered as requested.
|
||||
DumpFiltered HeaderFlags = 32
|
||||
|
||||
// Flags used to retrieve data from netlink.
|
||||
|
||||
// Root requests that netlink return a complete table instead of a
|
||||
// single entry.
|
||||
Root HeaderFlags = 0x100
|
||||
|
||||
// Match requests that netlink return a list of all matching entries.
|
||||
Match HeaderFlags = 0x200
|
||||
|
||||
// Atomic requests that netlink send an atomic snapshot of its entries.
|
||||
// Requires CAP_NET_ADMIN or an effective UID of 0.
|
||||
Atomic HeaderFlags = 0x400
|
||||
|
||||
// Dump requests that netlink return a complete list of all entries.
|
||||
Dump HeaderFlags = Root | Match
|
||||
|
||||
// Flags used to create objects.
|
||||
|
||||
// Replace indicates request replaces an existing matching object.
|
||||
Replace HeaderFlags = 0x100
|
||||
|
||||
// Excl indicates request does not replace the object if it already exists.
|
||||
Excl HeaderFlags = 0x200
|
||||
|
||||
// Create indicates request creates an object if it doesn't already exist.
|
||||
Create HeaderFlags = 0x400
|
||||
|
||||
// Append indicates request adds to the end of the object list.
|
||||
Append HeaderFlags = 0x800
|
||||
|
||||
// Flags for extended acknowledgements.
|
||||
|
||||
// Capped indicates the size of a request was capped in an extended
|
||||
// acknowledgement.
|
||||
Capped HeaderFlags = 0x100
|
||||
|
||||
// AcknowledgeTLVs indicates the presence of netlink extended
|
||||
// acknowledgement TLVs in a response.
|
||||
AcknowledgeTLVs HeaderFlags = 0x200
|
||||
)
|
||||
|
||||
// String returns the string representation of a HeaderFlags.
|
||||
func (f HeaderFlags) String() string {
|
||||
names := []string{
|
||||
"request",
|
||||
"multi",
|
||||
"acknowledge",
|
||||
"echo",
|
||||
"dumpinterrupted",
|
||||
"dumpfiltered",
|
||||
}
|
||||
|
||||
var s string
|
||||
|
||||
left := uint(f)
|
||||
|
||||
for i, name := range names {
|
||||
if f&(1<<uint(i)) != 0 {
|
||||
if s != "" {
|
||||
s += "|"
|
||||
}
|
||||
|
||||
s += name
|
||||
|
||||
left ^= (1 << uint(i))
|
||||
}
|
||||
}
|
||||
|
||||
if s == "" && left == 0 {
|
||||
s = "0"
|
||||
}
|
||||
|
||||
if left > 0 {
|
||||
if s != "" {
|
||||
s += "|"
|
||||
}
|
||||
s += fmt.Sprintf("%#x", left)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// HeaderType specifies the type of a Header.
|
||||
type HeaderType uint16
|
||||
|
||||
const (
|
||||
// Noop indicates that no action was taken.
|
||||
Noop HeaderType = 0x1
|
||||
|
||||
// Error indicates an error code is present, which is also used to indicate
|
||||
// success when the code is 0.
|
||||
Error HeaderType = 0x2
|
||||
|
||||
// Done indicates the end of a multi-part message.
|
||||
Done HeaderType = 0x3
|
||||
|
||||
// Overrun indicates that data was lost from this message.
|
||||
Overrun HeaderType = 0x4
|
||||
)
|
||||
|
||||
// String returns the string representation of a HeaderType.
|
||||
func (t HeaderType) String() string {
|
||||
switch t {
|
||||
case Noop:
|
||||
return "noop"
|
||||
case Error:
|
||||
return "error"
|
||||
case Done:
|
||||
return "done"
|
||||
case Overrun:
|
||||
return "overrun"
|
||||
default:
|
||||
return fmt.Sprintf("unknown(%d)", t)
|
||||
}
|
||||
}
|
||||
|
||||
// NB: the memory layout of Header and Linux's syscall.NlMsgHdr must be
|
||||
// exactly the same. Cannot reorder, change data type, add, or remove fields.
|
||||
// Named types of the same size (e.g. HeaderFlags is a uint16) are okay.
|
||||
|
||||
// A Header is a netlink header. A Header is sent and received with each
|
||||
// Message to indicate metadata regarding a Message.
|
||||
type Header struct {
|
||||
// Length of a Message, including this Header.
|
||||
Length uint32
|
||||
|
||||
// Contents of a Message.
|
||||
Type HeaderType
|
||||
|
||||
// Flags which may be used to modify a request or response.
|
||||
Flags HeaderFlags
|
||||
|
||||
// The sequence number of a Message.
|
||||
Sequence uint32
|
||||
|
||||
// The process ID of the sending process.
|
||||
PID uint32
|
||||
}
|
||||
|
||||
// A Message is a netlink message. It contains a Header and an arbitrary
|
||||
// byte payload, which may be decoded using information from the Header.
|
||||
//
|
||||
// Data is often populated with netlink attributes. For easy encoding and
|
||||
// decoding of attributes, see the AttributeDecoder and AttributeEncoder types.
|
||||
type Message struct {
|
||||
Header Header
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// MarshalBinary marshals a Message into a byte slice.
|
||||
func (m Message) MarshalBinary() ([]byte, error) {
|
||||
ml := nlmsgAlign(int(m.Header.Length))
|
||||
if ml < nlmsgHeaderLen || ml != int(m.Header.Length) {
|
||||
return nil, errIncorrectMessageLength
|
||||
}
|
||||
|
||||
b := make([]byte, ml)
|
||||
|
||||
nlenc.PutUint32(b[0:4], m.Header.Length)
|
||||
nlenc.PutUint16(b[4:6], uint16(m.Header.Type))
|
||||
nlenc.PutUint16(b[6:8], uint16(m.Header.Flags))
|
||||
nlenc.PutUint32(b[8:12], m.Header.Sequence)
|
||||
nlenc.PutUint32(b[12:16], m.Header.PID)
|
||||
copy(b[16:], m.Data)
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary unmarshals the contents of a byte slice into a Message.
|
||||
func (m *Message) UnmarshalBinary(b []byte) error {
|
||||
if len(b) < nlmsgHeaderLen {
|
||||
return errShortMessage
|
||||
}
|
||||
if len(b) != nlmsgAlign(len(b)) {
|
||||
return errUnalignedMessage
|
||||
}
|
||||
|
||||
// Don't allow misleading length
|
||||
m.Header.Length = nlenc.Uint32(b[0:4])
|
||||
if int(m.Header.Length) != len(b) {
|
||||
return errShortMessage
|
||||
}
|
||||
|
||||
m.Header.Type = HeaderType(nlenc.Uint16(b[4:6]))
|
||||
m.Header.Flags = HeaderFlags(nlenc.Uint16(b[6:8]))
|
||||
m.Header.Sequence = nlenc.Uint32(b[8:12])
|
||||
m.Header.PID = nlenc.Uint32(b[12:16])
|
||||
m.Data = b[16:]
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkMessage checks a single Message for netlink errors.
|
||||
func checkMessage(m Message) error {
|
||||
// NB: All non-nil errors returned from this function *must* be of type
|
||||
// OpError in order to maintain the appropriate contract with callers of
|
||||
// this package.
|
||||
|
||||
// The libnl documentation indicates that type error can
|
||||
// contain error codes:
|
||||
// https://www.infradead.org/~tgr/libnl/doc/core.html#core_errmsg.
|
||||
//
|
||||
// However, rtnetlink at least seems to also allow errors to occur at the
|
||||
// end of a multipart message with done/multi and an error number.
|
||||
var hasHeader bool
|
||||
switch {
|
||||
case m.Header.Type == Error:
|
||||
// Error code followed by nlmsghdr/ext ack attributes.
|
||||
hasHeader = true
|
||||
case m.Header.Type == Done && m.Header.Flags&Multi != 0:
|
||||
// If no data, there must be no error number so just exit early. Some
|
||||
// of the unit tests hard-coded this but I don't actually know if this
|
||||
// case occurs in the wild.
|
||||
if len(m.Data) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Done|Multi potentially followed by ext ack attributes.
|
||||
default:
|
||||
// Neither, nothing to do.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Errno occupies 4 bytes.
|
||||
const endErrno = 4
|
||||
if len(m.Data) < endErrno {
|
||||
return newOpError("receive", errShortErrorMessage)
|
||||
}
|
||||
|
||||
c := nlenc.Int32(m.Data[:endErrno])
|
||||
if c == 0 {
|
||||
// 0 indicates no error.
|
||||
return nil
|
||||
}
|
||||
|
||||
oerr := &OpError{
|
||||
Op: "receive",
|
||||
// Error code is a negative integer, convert it into an OS-specific raw
|
||||
// system call error, but do not wrap with os.NewSyscallError to signify
|
||||
// that this error was produced by a netlink message; not a system call.
|
||||
Err: newError(-1 * int(c)),
|
||||
}
|
||||
|
||||
// TODO(mdlayher): investigate the Capped flag.
|
||||
|
||||
if m.Header.Flags&AcknowledgeTLVs == 0 {
|
||||
// No extended acknowledgement.
|
||||
return oerr
|
||||
}
|
||||
|
||||
// Flags indicate an extended acknowledgement. The type/flags combination
|
||||
// checked above determines the offset where the TLVs occur.
|
||||
var off int
|
||||
if hasHeader {
|
||||
// There is an nlmsghdr preceding the TLVs.
|
||||
if len(m.Data) < endErrno+nlmsgHeaderLen {
|
||||
return newOpError("receive", errShortErrorMessage)
|
||||
}
|
||||
|
||||
// The TLVs should be at the offset indicated by the nlmsghdr.length,
|
||||
// plus the offset where the header began. But make sure the calculated
|
||||
// offset is still in-bounds.
|
||||
h := *(*Header)(unsafe.Pointer(&m.Data[endErrno : endErrno+nlmsgHeaderLen][0]))
|
||||
off = endErrno + int(h.Length)
|
||||
|
||||
if len(m.Data) < off {
|
||||
return newOpError("receive", errShortErrorMessage)
|
||||
}
|
||||
} else {
|
||||
// There is no nlmsghdr preceding the TLVs, parse them directly.
|
||||
off = endErrno
|
||||
}
|
||||
|
||||
ad, err := NewAttributeDecoder(m.Data[off:])
|
||||
if err != nil {
|
||||
// Malformed TLVs, just return the OpError with the info we have.
|
||||
return oerr
|
||||
}
|
||||
|
||||
for ad.Next() {
|
||||
switch ad.Type() {
|
||||
case 1: // unix.NLMSGERR_ATTR_MSG
|
||||
oerr.Message = ad.String()
|
||||
case 2: // unix.NLMSGERR_ATTR_OFFS
|
||||
oerr.Offset = int(ad.Uint32())
|
||||
}
|
||||
}
|
||||
|
||||
// Explicitly ignore ad.Err: malformed TLVs, just return the OpError with
|
||||
// the info we have.
|
||||
return oerr
|
||||
}
|
87
vendor/github.com/mdlayher/netlink/netlink.dot
generated
vendored
Normal file
87
vendor/github.com/mdlayher/netlink/netlink.dot
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
digraph {
|
||||
rankdir = LR
|
||||
|
||||
subgraph cluster_netlink {
|
||||
"github.com/mdlayher/netlink" [URL="https://github.com/mdlayher/netlink"]
|
||||
}
|
||||
|
||||
subgraph cluster_connector {
|
||||
label = "NETLINK_CONNECTOR";
|
||||
|
||||
{
|
||||
"github.com/fearful-symmetry/garlic" [URL="https://github.com/fearful-symmetry/garlic"]
|
||||
} -> "github.com/mdlayher/netlink"
|
||||
}
|
||||
|
||||
subgraph cluster_crypto {
|
||||
label = "NETLINK_CRYPTO";
|
||||
|
||||
{
|
||||
"github.com/mdlayher/cryptonl" [URL="https://github.com/mdlayher/cryptonl"]
|
||||
} -> "github.com/mdlayher/netlink"
|
||||
}
|
||||
|
||||
subgraph cluster_generic {
|
||||
label = "NETLINK_GENERIC (genetlink)";
|
||||
"github.com/mdlayher/genetlink" [URL="https://github.com/mdlayher/genetlink"]
|
||||
"github.com/mdlayher/genetlink" -> "github.com/mdlayher/netlink"
|
||||
|
||||
{
|
||||
"github.com/axatrax/l2tp" [URL="https://github.com/axatrax/l2tp"]
|
||||
"github.com/digitalocean/go-openvswitch" [URL="https://github.com/digitalocean/go-openvswitch"]
|
||||
"github.com/mdlayher/devlink" [URL="https://github.com/mdlayher/devlink"]
|
||||
"github.com/mdlayher/ethtool" [URL="https://github.com/mdlayher/ethtool"]
|
||||
"github.com/mdlayher/quota" [URL="https://github.com/mdlayher/quota"]
|
||||
"github.com/mdlayher/taskstats" [URL="https://github.com/mdlayher/taskstats"]
|
||||
"github.com/mdlayher/wifi" [URL="https://github.com/mdlayher/wifi"]
|
||||
"github.com/Merovius/nbd" [URL="https://github.com/Merovius/nbd"]
|
||||
"github.com/rtr7/router7" [URL="https://github.com/rtr7/router7"]
|
||||
"github.com/u-root/u-bmc" [URL="https://github.com/u-root/u-bmc"]
|
||||
"golang.zx2c4.com/wireguard/wgctrl" [URL="https://golang.zx2c4.com/wireguard/wgctrl"]
|
||||
} -> "github.com/mdlayher/genetlink"
|
||||
}
|
||||
|
||||
subgraph cluster_kobject_uevent {
|
||||
label = "NETLINK_KOBJECT_UEVENT";
|
||||
|
||||
{
|
||||
"github.com/mdlayher/kobject" [URL="https://github.com/mdlayher/kobject"]
|
||||
} -> "github.com/mdlayher/netlink"
|
||||
}
|
||||
|
||||
subgraph cluster_netfilter {
|
||||
label = "NETLINK_NETFILTER (nfnetlink)";
|
||||
|
||||
{
|
||||
"github.com/florianl/go-conntrack" [URL="https://github.com/florianl/go-conntrack"]
|
||||
"github.com/florianl/go-nflog" [URL="https://github.com/florianl/go-nflog"]
|
||||
"github.com/florianl/go-nfqueue" [URL="https://github.com/florianl/go-nfqueue"]
|
||||
"github.com/google/nftables" [URL="https://github.com/google/nftables"]
|
||||
"github.com/ti-mo/netfilter" [URL="https://github.com/ti-mo/netfilter"]
|
||||
} -> "github.com/mdlayher/netlink"
|
||||
|
||||
{
|
||||
"github.com/ti-mo/conntrack" [URL="https://github.com/ti-mo/conntrack"]
|
||||
} -> "github.com/ti-mo/netfilter"
|
||||
}
|
||||
|
||||
subgraph cluster_route {
|
||||
label = "NETLINK_ROUTE (rtnetlink)";
|
||||
|
||||
{
|
||||
"github.com/ema/qdisc" [URL="https://github.com/ema/qdisc"]
|
||||
"github.com/florianl/go-tc" [URL="https://github.com/florianl/go-tc"]
|
||||
"github.com/jsimonetti/rtnetlink" [URL="https://github.com/jsimonetti/rtnetlink"]
|
||||
"gitlab.com/mergetb/tech/rtnl" [URL="https://gitlab.com/mergetb/tech/rtnl"]
|
||||
} -> "github.com/mdlayher/netlink"
|
||||
}
|
||||
|
||||
subgraph cluster_w1 {
|
||||
label = "NETLINK_W1";
|
||||
|
||||
{
|
||||
"github.com/SpComb/go-onewire" [URL="https://github.com/SpComb/go-onewire"]
|
||||
} -> "github.com/mdlayher/netlink"
|
||||
}
|
||||
}
|
||||
|
451
vendor/github.com/mdlayher/netlink/netlink.svg
generated
vendored
Normal file
451
vendor/github.com/mdlayher/netlink/netlink.svg
generated
vendored
Normal file
@@ -0,0 +1,451 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.43.0 (0)
|
||||
-->
|
||||
<!-- Title: %3 Pages: 1 -->
|
||||
<svg width="1148pt" height="1515pt"
|
||||
viewBox="0.00 0.00 1148.01 1515.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1511)">
|
||||
<title>%3</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-1511 1144.01,-1511 1144.01,4 -4,4"/>
|
||||
<g id="clust1" class="cluster">
|
||||
<title>cluster_netlink</title>
|
||||
<polygon fill="none" stroke="black" points="826.13,-417 826.13,-469 1132.01,-469 1132.01,-417 826.13,-417"/>
|
||||
</g>
|
||||
<g id="clust2" class="cluster">
|
||||
<title>cluster_connector</title>
|
||||
<polygon fill="none" stroke="black" points="439.16,-1424 439.16,-1499 806.13,-1499 806.13,-1424 439.16,-1424"/>
|
||||
<text text-anchor="middle" x="622.65" y="-1483.8" font-family="Times,serif" font-size="14.00">NETLINK_CONNECTOR</text>
|
||||
</g>
|
||||
<g id="clust4" class="cluster">
|
||||
<title>cluster_crypto</title>
|
||||
<polygon fill="none" stroke="black" points="463.21,-1341 463.21,-1416 782.09,-1416 782.09,-1341 463.21,-1341"/>
|
||||
<text text-anchor="middle" x="622.65" y="-1400.8" font-family="Times,serif" font-size="14.00">NETLINK_CRYPTO</text>
|
||||
</g>
|
||||
<g id="clust6" class="cluster">
|
||||
<title>cluster_generic</title>
|
||||
<polygon fill="none" stroke="black" points="8,-718 8,-1333 786.64,-1333 786.64,-718 8,-718"/>
|
||||
<text text-anchor="middle" x="397.32" y="-1317.8" font-family="Times,serif" font-size="14.00">NETLINK_GENERIC (genetlink)</text>
|
||||
</g>
|
||||
<g id="clust8" class="cluster">
|
||||
<title>cluster_kobject_uevent</title>
|
||||
<polygon fill="none" stroke="black" points="468.41,-635 468.41,-710 776.89,-710 776.89,-635 468.41,-635"/>
|
||||
<text text-anchor="middle" x="622.65" y="-694.8" font-family="Times,serif" font-size="14.00">NETLINK_KOBJECT_UEVENT</text>
|
||||
</g>
|
||||
<g id="clust10" class="cluster">
|
||||
<title>cluster_netfilter</title>
|
||||
<polygon fill="none" stroke="black" points="44.4,-336 44.4,-627 760.64,-627 760.64,-336 44.4,-336"/>
|
||||
<text text-anchor="middle" x="402.52" y="-611.8" font-family="Times,serif" font-size="14.00">NETLINK_NETFILTER (nfnetlink)</text>
|
||||
</g>
|
||||
<g id="clust13" class="cluster">
|
||||
<title>cluster_route</title>
|
||||
<polygon fill="none" stroke="black" points="458.66,-91 458.66,-328 786.64,-328 786.64,-91 458.66,-91"/>
|
||||
<text text-anchor="middle" x="622.65" y="-312.8" font-family="Times,serif" font-size="14.00">NETLINK_ROUTE (rtnetlink)</text>
|
||||
</g>
|
||||
<g id="clust15" class="cluster">
|
||||
<title>cluster_w1</title>
|
||||
<polygon fill="none" stroke="black" points="455.41,-8 455.41,-83 789.89,-83 789.89,-8 455.41,-8"/>
|
||||
<text text-anchor="middle" x="622.65" y="-67.8" font-family="Times,serif" font-size="14.00">NETLINK_W1</text>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/netlink -->
|
||||
<g id="node1" class="node">
|
||||
<title>github.com/mdlayher/netlink</title>
|
||||
<g id="a_node1"><a xlink:href="https://github.com/mdlayher/netlink" xlink:title="github.com/mdlayher/netlink">
|
||||
<ellipse fill="none" stroke="black" cx="979.07" cy="-443" rx="144.87" ry="18"/>
|
||||
<text text-anchor="middle" x="979.07" y="-439.3" font-family="Times,serif" font-size="14.00">github.com/mdlayher/netlink</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/fearful-symmetry/garlic -->
|
||||
<g id="node2" class="node">
|
||||
<title>github.com/fearful-symmetry/garlic</title>
|
||||
<g id="a_node2"><a xlink:href="https://github.com/fearful-symmetry/garlic" xlink:title="github.com/fearful-symmetry/garlic">
|
||||
<ellipse fill="none" stroke="black" cx="622.65" cy="-1450" rx="175.47" ry="18"/>
|
||||
<text text-anchor="middle" x="622.65" y="-1446.3" font-family="Times,serif" font-size="14.00">github.com/fearful-symmetry/garlic</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/fearful-symmetry/garlic->github.com/mdlayher/netlink -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>github.com/fearful-symmetry/garlic->github.com/mdlayher/netlink</title>
|
||||
<path fill="none" stroke="black" d="M775.09,-1441.05C786.54,-1435.8 797.12,-1428.92 806.13,-1420 945.48,-1282.21 972.95,-617.34 977.34,-471.37"/>
|
||||
<polygon fill="black" stroke="black" points="980.84,-471.13 977.63,-461.04 973.85,-470.93 980.84,-471.13"/>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/cryptonl -->
|
||||
<g id="node3" class="node">
|
||||
<title>github.com/mdlayher/cryptonl</title>
|
||||
<g id="a_node3"><a xlink:href="https://github.com/mdlayher/cryptonl" xlink:title="github.com/mdlayher/cryptonl">
|
||||
<ellipse fill="none" stroke="black" cx="622.65" cy="-1367" rx="151.37" ry="18"/>
|
||||
<text text-anchor="middle" x="622.65" y="-1363.3" font-family="Times,serif" font-size="14.00">github.com/mdlayher/cryptonl</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/cryptonl->github.com/mdlayher/netlink -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>github.com/mdlayher/cryptonl->github.com/mdlayher/netlink</title>
|
||||
<path fill="none" stroke="black" d="M766.97,-1361.23C781.49,-1355.68 794.97,-1347.86 806.13,-1337 934.19,-1212.36 970.17,-610.39 976.82,-471.59"/>
|
||||
<polygon fill="black" stroke="black" points="980.33,-471.5 977.3,-461.35 973.34,-471.18 980.33,-471.5"/>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/genetlink -->
|
||||
<g id="node4" class="node">
|
||||
<title>github.com/mdlayher/genetlink</title>
|
||||
<g id="a_node4"><a xlink:href="https://github.com/mdlayher/genetlink" xlink:title="github.com/mdlayher/genetlink">
|
||||
<ellipse fill="none" stroke="black" cx="622.65" cy="-987" rx="155.97" ry="18"/>
|
||||
<text text-anchor="middle" x="622.65" y="-983.3" font-family="Times,serif" font-size="14.00">github.com/mdlayher/genetlink</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/genetlink->github.com/mdlayher/netlink -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>github.com/mdlayher/genetlink->github.com/mdlayher/netlink</title>
|
||||
<path fill="none" stroke="black" d="M635.97,-968.89C665.62,-925.25 743.13,-810.74 806.13,-714 863.98,-625.18 930.8,-518.71 961.32,-469.88"/>
|
||||
<polygon fill="black" stroke="black" points="964.42,-471.51 966.75,-461.17 958.48,-467.8 964.42,-471.51"/>
|
||||
</g>
|
||||
<!-- github.com/axatrax/l2tp -->
|
||||
<g id="node5" class="node">
|
||||
<title>github.com/axatrax/l2tp</title>
|
||||
<g id="a_node5"><a xlink:href="https://github.com/axatrax/l2tp" xlink:title="github.com/axatrax/l2tp">
|
||||
<ellipse fill="none" stroke="black" cx="213.58" cy="-1284" rx="122.38" ry="18"/>
|
||||
<text text-anchor="middle" x="213.58" y="-1280.3" font-family="Times,serif" font-size="14.00">github.com/axatrax/l2tp</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/axatrax/l2tp->github.com/mdlayher/genetlink -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>github.com/axatrax/l2tp->github.com/mdlayher/genetlink</title>
|
||||
<path fill="none" stroke="black" d="M335.31,-1282.19C361.59,-1277.86 388.33,-1270.15 411.16,-1257 512.47,-1198.65 582.36,-1070.58 609.3,-1014.37"/>
|
||||
<polygon fill="black" stroke="black" points="612.6,-1015.59 613.69,-1005.05 606.26,-1012.61 612.6,-1015.59"/>
|
||||
</g>
|
||||
<!-- github.com/digitalocean/go-openvswitch -->
|
||||
<g id="node6" class="node">
|
||||
<title>github.com/digitalocean/go-openvswitch</title>
|
||||
<g id="a_node6"><a xlink:href="https://github.com/digitalocean/go-openvswitch" xlink:title="github.com/digitalocean/go-openvswitch">
|
||||
<ellipse fill="none" stroke="black" cx="213.58" cy="-1230" rx="197.66" ry="18"/>
|
||||
<text text-anchor="middle" x="213.58" y="-1226.3" font-family="Times,serif" font-size="14.00">github.com/digitalocean/go-openvswitch</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/digitalocean/go-openvswitch->github.com/mdlayher/genetlink -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>github.com/digitalocean/go-openvswitch->github.com/mdlayher/genetlink</title>
|
||||
<path fill="none" stroke="black" d="M369.18,-1218.82C383.78,-1214.81 398.02,-1209.64 411.16,-1203 500.09,-1158.12 573.09,-1060.66 604.72,-1013.55"/>
|
||||
<polygon fill="black" stroke="black" points="607.72,-1015.37 610.32,-1005.1 601.88,-1011.51 607.72,-1015.37"/>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/devlink -->
|
||||
<g id="node7" class="node">
|
||||
<title>github.com/mdlayher/devlink</title>
|
||||
<g id="a_node7"><a xlink:href="https://github.com/mdlayher/devlink" xlink:title="github.com/mdlayher/devlink">
|
||||
<ellipse fill="none" stroke="black" cx="213.58" cy="-1176" rx="146.47" ry="18"/>
|
||||
<text text-anchor="middle" x="213.58" y="-1172.3" font-family="Times,serif" font-size="14.00">github.com/mdlayher/devlink</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/devlink->github.com/mdlayher/genetlink -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>github.com/mdlayher/devlink->github.com/mdlayher/genetlink</title>
|
||||
<path fill="none" stroke="black" d="M344.3,-1167.91C367.14,-1163.77 390.27,-1157.74 411.16,-1149 488.01,-1116.85 561.22,-1049.4 597.65,-1012.49"/>
|
||||
<polygon fill="black" stroke="black" points="600.38,-1014.7 604.86,-1005.1 595.37,-1009.81 600.38,-1014.7"/>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/ethtool -->
|
||||
<g id="node8" class="node">
|
||||
<title>github.com/mdlayher/ethtool</title>
|
||||
<g id="a_node8"><a xlink:href="https://github.com/mdlayher/ethtool" xlink:title="github.com/mdlayher/ethtool">
|
||||
<ellipse fill="none" stroke="black" cx="213.58" cy="-1122" rx="145.67" ry="18"/>
|
||||
<text text-anchor="middle" x="213.58" y="-1118.3" font-family="Times,serif" font-size="14.00">github.com/mdlayher/ethtool</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/ethtool->github.com/mdlayher/genetlink -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>github.com/mdlayher/ethtool->github.com/mdlayher/genetlink</title>
|
||||
<path fill="none" stroke="black" d="M335.04,-1112C360.53,-1108.08 387.02,-1102.61 411.16,-1095 475.99,-1074.57 544.96,-1035.42 585.63,-1010.3"/>
|
||||
<polygon fill="black" stroke="black" points="587.73,-1013.11 594.36,-1004.85 584.02,-1007.17 587.73,-1013.11"/>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/quota -->
|
||||
<g id="node9" class="node">
|
||||
<title>github.com/mdlayher/quota</title>
|
||||
<g id="a_node9"><a xlink:href="https://github.com/mdlayher/quota" xlink:title="github.com/mdlayher/quota">
|
||||
<ellipse fill="none" stroke="black" cx="213.58" cy="-1068" rx="139.18" ry="18"/>
|
||||
<text text-anchor="middle" x="213.58" y="-1064.3" font-family="Times,serif" font-size="14.00">github.com/mdlayher/quota</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/quota->github.com/mdlayher/genetlink -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>github.com/mdlayher/quota->github.com/mdlayher/genetlink</title>
|
||||
<path fill="none" stroke="black" d="M318,-1056.06C348.15,-1051.97 381.08,-1046.91 411.16,-1041 459.39,-1031.54 513.03,-1017.72 554.09,-1006.43"/>
|
||||
<polygon fill="black" stroke="black" points="555.28,-1009.74 563.98,-1003.7 553.41,-1002.99 555.28,-1009.74"/>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/taskstats -->
|
||||
<g id="node10" class="node">
|
||||
<title>github.com/mdlayher/taskstats</title>
|
||||
<g id="a_node10"><a xlink:href="https://github.com/mdlayher/taskstats" xlink:title="github.com/mdlayher/taskstats">
|
||||
<ellipse fill="none" stroke="black" cx="213.58" cy="-1014" rx="155.17" ry="18"/>
|
||||
<text text-anchor="middle" x="213.58" y="-1010.3" font-family="Times,serif" font-size="14.00">github.com/mdlayher/taskstats</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/taskstats->github.com/mdlayher/genetlink -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>github.com/mdlayher/taskstats->github.com/mdlayher/genetlink</title>
|
||||
<path fill="none" stroke="black" d="M348.72,-1005.1C389.7,-1002.38 434.95,-999.38 476.62,-996.62"/>
|
||||
<polygon fill="black" stroke="black" points="477.1,-1000.1 486.85,-995.94 476.64,-993.11 477.1,-1000.1"/>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/wifi -->
|
||||
<g id="node11" class="node">
|
||||
<title>github.com/mdlayher/wifi</title>
|
||||
<g id="a_node11"><a xlink:href="https://github.com/mdlayher/wifi" xlink:title="github.com/mdlayher/wifi">
|
||||
<ellipse fill="none" stroke="black" cx="213.58" cy="-960" rx="129.18" ry="18"/>
|
||||
<text text-anchor="middle" x="213.58" y="-956.3" font-family="Times,serif" font-size="14.00">github.com/mdlayher/wifi</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/wifi->github.com/mdlayher/genetlink -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>github.com/mdlayher/wifi->github.com/mdlayher/genetlink</title>
|
||||
<path fill="none" stroke="black" d="M330.69,-967.7C376.21,-970.72 428.94,-974.22 476.9,-977.4"/>
|
||||
<polygon fill="black" stroke="black" points="476.85,-980.9 487.06,-978.07 477.31,-973.92 476.85,-980.9"/>
|
||||
</g>
|
||||
<!-- github.com/Merovius/nbd -->
|
||||
<g id="node12" class="node">
|
||||
<title>github.com/Merovius/nbd</title>
|
||||
<g id="a_node12"><a xlink:href="https://github.com/Merovius/nbd" xlink:title="github.com/Merovius/nbd">
|
||||
<ellipse fill="none" stroke="black" cx="213.58" cy="-906" rx="129.98" ry="18"/>
|
||||
<text text-anchor="middle" x="213.58" y="-902.3" font-family="Times,serif" font-size="14.00">github.com/Merovius/nbd</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/Merovius/nbd->github.com/mdlayher/genetlink -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>github.com/Merovius/nbd->github.com/mdlayher/genetlink</title>
|
||||
<path fill="none" stroke="black" d="M314.2,-917.43C345.37,-921.61 379.81,-926.85 411.16,-933 459.39,-942.46 513.03,-956.28 554.09,-967.57"/>
|
||||
<polygon fill="black" stroke="black" points="553.41,-971.01 563.98,-970.3 555.28,-964.26 553.41,-971.01"/>
|
||||
</g>
|
||||
<!-- github.com/rtr7/router7 -->
|
||||
<g id="node13" class="node">
|
||||
<title>github.com/rtr7/router7</title>
|
||||
<g id="a_node13"><a xlink:href="https://github.com/rtr7/router7" xlink:title="github.com/rtr7/router7">
|
||||
<ellipse fill="none" stroke="black" cx="213.58" cy="-852" rx="122.38" ry="18"/>
|
||||
<text text-anchor="middle" x="213.58" y="-848.3" font-family="Times,serif" font-size="14.00">github.com/rtr7/router7</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/rtr7/router7->github.com/mdlayher/genetlink -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>github.com/rtr7/router7->github.com/mdlayher/genetlink</title>
|
||||
<path fill="none" stroke="black" d="M322.65,-860.2C351.82,-864.2 383.07,-870.15 411.16,-879 475.99,-899.43 544.96,-938.58 585.63,-963.7"/>
|
||||
<polygon fill="black" stroke="black" points="584.02,-966.83 594.36,-969.15 587.73,-960.89 584.02,-966.83"/>
|
||||
</g>
|
||||
<!-- github.com/u-root/u-bmc -->
|
||||
<g id="node14" class="node">
|
||||
<title>github.com/u-root/u-bmc</title>
|
||||
<g id="a_node14"><a xlink:href="https://github.com/u-root/u-bmc" xlink:title="github.com/u-root/u-bmc">
|
||||
<ellipse fill="none" stroke="black" cx="213.58" cy="-798" rx="124.58" ry="18"/>
|
||||
<text text-anchor="middle" x="213.58" y="-794.3" font-family="Times,serif" font-size="14.00">github.com/u-root/u-bmc</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/u-root/u-bmc->github.com/mdlayher/genetlink -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>github.com/u-root/u-bmc->github.com/mdlayher/genetlink</title>
|
||||
<path fill="none" stroke="black" d="M331.58,-803.97C358.44,-808.07 386.38,-814.63 411.16,-825 488.01,-857.15 561.22,-924.6 597.65,-961.51"/>
|
||||
<polygon fill="black" stroke="black" points="595.37,-964.19 604.86,-968.9 600.38,-959.3 595.37,-964.19"/>
|
||||
</g>
|
||||
<!-- golang.zx2c4.com/wireguard/wgctrl -->
|
||||
<g id="node15" class="node">
|
||||
<title>golang.zx2c4.com/wireguard/wgctrl</title>
|
||||
<g id="a_node15"><a xlink:href="https://golang.zx2c4.com/wireguard/wgctrl" xlink:title="golang.zx2c4.com/wireguard/wgctrl">
|
||||
<ellipse fill="none" stroke="black" cx="213.58" cy="-744" rx="176.57" ry="18"/>
|
||||
<text text-anchor="middle" x="213.58" y="-740.3" font-family="Times,serif" font-size="14.00">golang.zx2c4.com/wireguard/wgctrl</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- golang.zx2c4.com/wireguard/wgctrl->github.com/mdlayher/genetlink -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>golang.zx2c4.com/wireguard/wgctrl->github.com/mdlayher/genetlink</title>
|
||||
<path fill="none" stroke="black" d="M363.27,-753.62C379.93,-757.83 396.25,-763.47 411.16,-771 500.09,-815.88 573.09,-913.34 604.72,-960.45"/>
|
||||
<polygon fill="black" stroke="black" points="601.88,-962.49 610.32,-968.9 607.72,-958.63 601.88,-962.49"/>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/kobject -->
|
||||
<g id="node16" class="node">
|
||||
<title>github.com/mdlayher/kobject</title>
|
||||
<g id="a_node16"><a xlink:href="https://github.com/mdlayher/kobject" xlink:title="github.com/mdlayher/kobject">
|
||||
<ellipse fill="none" stroke="black" cx="622.65" cy="-661" rx="146.47" ry="18"/>
|
||||
<text text-anchor="middle" x="622.65" y="-657.3" font-family="Times,serif" font-size="14.00">github.com/mdlayher/kobject</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/mdlayher/kobject->github.com/mdlayher/netlink -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>github.com/mdlayher/kobject->github.com/mdlayher/netlink</title>
|
||||
<path fill="none" stroke="black" d="M749.05,-651.76C768.9,-647.13 788.63,-640.48 806.13,-631 877.87,-592.14 935.5,-511.67 962.1,-469.73"/>
|
||||
<polygon fill="black" stroke="black" points="965.13,-471.49 967.45,-461.15 959.19,-467.79 965.13,-471.49"/>
|
||||
</g>
|
||||
<!-- github.com/florianl/go-conntrack -->
|
||||
<g id="node17" class="node">
|
||||
<title>github.com/florianl/go-conntrack</title>
|
||||
<g id="a_node17"><a xlink:href="https://github.com/florianl/go-conntrack" xlink:title="github.com/florianl/go-conntrack">
|
||||
<ellipse fill="none" stroke="black" cx="213.58" cy="-524" rx="161.37" ry="18"/>
|
||||
<text text-anchor="middle" x="213.58" y="-520.3" font-family="Times,serif" font-size="14.00">github.com/florianl/go-conntrack</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/florianl/go-conntrack->github.com/mdlayher/netlink -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>github.com/florianl/go-conntrack->github.com/mdlayher/netlink</title>
|
||||
<path fill="none" stroke="black" d="M346.97,-513.88C467.01,-504.18 648.72,-488.2 806.13,-469 830.23,-466.06 856.16,-462.4 880.39,-458.77"/>
|
||||
<polygon fill="black" stroke="black" points="880.93,-462.22 890.29,-457.27 879.88,-455.3 880.93,-462.22"/>
|
||||
</g>
|
||||
<!-- github.com/florianl/go-nflog -->
|
||||
<g id="node18" class="node">
|
||||
<title>github.com/florianl/go-nflog</title>
|
||||
<g id="a_node18"><a xlink:href="https://github.com/florianl/go-nflog" xlink:title="github.com/florianl/go-nflog">
|
||||
<ellipse fill="none" stroke="black" cx="213.58" cy="-470" rx="138.38" ry="18"/>
|
||||
<text text-anchor="middle" x="213.58" y="-466.3" font-family="Times,serif" font-size="14.00">github.com/florianl/go-nflog</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/florianl/go-nflog->github.com/mdlayher/netlink -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>github.com/florianl/go-nflog->github.com/mdlayher/netlink</title>
|
||||
<path fill="none" stroke="black" d="M347.57,-465.3C481.99,-460.54 689.29,-453.21 829.15,-448.27"/>
|
||||
<polygon fill="black" stroke="black" points="829.65,-451.75 839.52,-447.9 829.4,-444.76 829.65,-451.75"/>
|
||||
</g>
|
||||
<!-- github.com/florianl/go-nfqueue -->
|
||||
<g id="node19" class="node">
|
||||
<title>github.com/florianl/go-nfqueue</title>
|
||||
<g id="a_node19"><a xlink:href="https://github.com/florianl/go-nfqueue" xlink:title="github.com/florianl/go-nfqueue">
|
||||
<ellipse fill="none" stroke="black" cx="213.58" cy="-416" rx="153.27" ry="18"/>
|
||||
<text text-anchor="middle" x="213.58" y="-412.3" font-family="Times,serif" font-size="14.00">github.com/florianl/go-nfqueue</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/florianl/go-nfqueue->github.com/mdlayher/netlink -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>github.com/florianl/go-nfqueue->github.com/mdlayher/netlink</title>
|
||||
<path fill="none" stroke="black" d="M360.89,-421.17C495.43,-425.93 693.98,-432.95 829.3,-437.74"/>
|
||||
<polygon fill="black" stroke="black" points="829.22,-441.24 839.34,-438.09 829.47,-434.24 829.22,-441.24"/>
|
||||
</g>
|
||||
<!-- github.com/google/nftables -->
|
||||
<g id="node20" class="node">
|
||||
<title>github.com/google/nftables</title>
|
||||
<g id="a_node20"><a xlink:href="https://github.com/google/nftables" xlink:title="github.com/google/nftables">
|
||||
<ellipse fill="none" stroke="black" cx="213.58" cy="-362" rx="137.28" ry="18"/>
|
||||
<text text-anchor="middle" x="213.58" y="-358.3" font-family="Times,serif" font-size="14.00">github.com/google/nftables</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/google/nftables->github.com/mdlayher/netlink -->
|
||||
<g id="edge19" class="edge">
|
||||
<title>github.com/google/nftables->github.com/mdlayher/netlink</title>
|
||||
<path fill="none" stroke="black" d="M329.52,-371.61C448.83,-381.94 640.78,-399.5 806.13,-419 828.43,-421.63 852.3,-424.76 874.95,-427.88"/>
|
||||
<polygon fill="black" stroke="black" points="874.53,-431.35 884.92,-429.26 875.49,-424.42 874.53,-431.35"/>
|
||||
</g>
|
||||
<!-- github.com/ti-mo/netfilter -->
|
||||
<g id="node21" class="node">
|
||||
<title>github.com/ti-mo/netfilter</title>
|
||||
<g id="a_node21"><a xlink:href="https://github.com/ti-mo/netfilter" xlink:title="github.com/ti-mo/netfilter">
|
||||
<ellipse fill="none" stroke="black" cx="622.65" cy="-572" rx="129.98" ry="18"/>
|
||||
<text text-anchor="middle" x="622.65" y="-568.3" font-family="Times,serif" font-size="14.00">github.com/ti-mo/netfilter</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/ti-mo/netfilter->github.com/mdlayher/netlink -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>github.com/ti-mo/netfilter->github.com/mdlayher/netlink</title>
|
||||
<path fill="none" stroke="black" d="M703.9,-557.91C736.18,-551.12 773.43,-541.84 806.13,-530 854.07,-512.65 905.86,-485.13 939.93,-465.69"/>
|
||||
<polygon fill="black" stroke="black" points="941.7,-468.71 948.62,-460.69 938.21,-462.64 941.7,-468.71"/>
|
||||
</g>
|
||||
<!-- github.com/ti-mo/conntrack -->
|
||||
<g id="node22" class="node">
|
||||
<title>github.com/ti-mo/conntrack</title>
|
||||
<g id="a_node22"><a xlink:href="https://github.com/ti-mo/conntrack" xlink:title="github.com/ti-mo/conntrack">
|
||||
<ellipse fill="none" stroke="black" cx="213.58" cy="-578" rx="138.38" ry="18"/>
|
||||
<text text-anchor="middle" x="213.58" y="-574.3" font-family="Times,serif" font-size="14.00">github.com/ti-mo/conntrack</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/ti-mo/conntrack->github.com/ti-mo/netfilter -->
|
||||
<g id="edge21" class="edge">
|
||||
<title>github.com/ti-mo/conntrack->github.com/ti-mo/netfilter</title>
|
||||
<path fill="none" stroke="black" d="M351.26,-575.99C393.71,-575.36 440.52,-574.67 483.09,-574.04"/>
|
||||
<polygon fill="black" stroke="black" points="483.29,-577.54 493.24,-573.89 483.19,-570.54 483.29,-577.54"/>
|
||||
</g>
|
||||
<!-- github.com/ema/qdisc -->
|
||||
<g id="node23" class="node">
|
||||
<title>github.com/ema/qdisc</title>
|
||||
<g id="a_node23"><a xlink:href="https://github.com/ema/qdisc" xlink:title="github.com/ema/qdisc">
|
||||
<ellipse fill="none" stroke="black" cx="622.65" cy="-279" rx="112.38" ry="18"/>
|
||||
<text text-anchor="middle" x="622.65" y="-275.3" font-family="Times,serif" font-size="14.00">github.com/ema/qdisc</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/ema/qdisc->github.com/mdlayher/netlink -->
|
||||
<g id="edge22" class="edge">
|
||||
<title>github.com/ema/qdisc->github.com/mdlayher/netlink</title>
|
||||
<path fill="none" stroke="black" d="M690.34,-293.42C725.65,-302.27 769.22,-315.16 806.13,-332 858.51,-355.89 913.46,-394 946.74,-418.77"/>
|
||||
<polygon fill="black" stroke="black" points="945.03,-421.86 955.13,-425.06 949.24,-416.26 945.03,-421.86"/>
|
||||
</g>
|
||||
<!-- github.com/florianl/go-tc -->
|
||||
<g id="node24" class="node">
|
||||
<title>github.com/florianl/go-tc</title>
|
||||
<g id="a_node24"><a xlink:href="https://github.com/florianl/go-tc" xlink:title="github.com/florianl/go-tc">
|
||||
<ellipse fill="none" stroke="black" cx="622.65" cy="-225" rx="124.28" ry="18"/>
|
||||
<text text-anchor="middle" x="622.65" y="-221.3" font-family="Times,serif" font-size="14.00">github.com/florianl/go-tc</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/florianl/go-tc->github.com/mdlayher/netlink -->
|
||||
<g id="edge23" class="edge">
|
||||
<title>github.com/florianl/go-tc->github.com/mdlayher/netlink</title>
|
||||
<path fill="none" stroke="black" d="M741.38,-230.26C763.78,-234.58 786.38,-241.4 806.13,-252 879.02,-291.1 936.52,-373.74 962.68,-416.35"/>
|
||||
<polygon fill="black" stroke="black" points="959.77,-418.3 967.93,-425.05 965.76,-414.68 959.77,-418.3"/>
|
||||
</g>
|
||||
<!-- github.com/jsimonetti/rtnetlink -->
|
||||
<g id="node25" class="node">
|
||||
<title>github.com/jsimonetti/rtnetlink</title>
|
||||
<g id="a_node25"><a xlink:href="https://github.com/jsimonetti/rtnetlink" xlink:title="github.com/jsimonetti/rtnetlink">
|
||||
<ellipse fill="none" stroke="black" cx="622.65" cy="-171" rx="155.97" ry="18"/>
|
||||
<text text-anchor="middle" x="622.65" y="-167.3" font-family="Times,serif" font-size="14.00">github.com/jsimonetti/rtnetlink</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/jsimonetti/rtnetlink->github.com/mdlayher/netlink -->
|
||||
<g id="edge24" class="edge">
|
||||
<title>github.com/jsimonetti/rtnetlink->github.com/mdlayher/netlink</title>
|
||||
<path fill="none" stroke="black" d="M761.97,-179.11C777.55,-183.56 792.64,-189.67 806.13,-198 891.51,-250.68 945.9,-363.24 967.48,-415.41"/>
|
||||
<polygon fill="black" stroke="black" points="964.25,-416.75 971.25,-424.71 970.74,-414.12 964.25,-416.75"/>
|
||||
</g>
|
||||
<!-- gitlab.com/mergetb/tech/rtnl -->
|
||||
<g id="node26" class="node">
|
||||
<title>gitlab.com/mergetb/tech/rtnl</title>
|
||||
<g id="a_node26"><a xlink:href="https://gitlab.com/mergetb/tech/rtnl" xlink:title="gitlab.com/mergetb/tech/rtnl">
|
||||
<ellipse fill="none" stroke="black" cx="622.65" cy="-117" rx="144.87" ry="18"/>
|
||||
<text text-anchor="middle" x="622.65" y="-113.3" font-family="Times,serif" font-size="14.00">gitlab.com/mergetb/tech/rtnl</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- gitlab.com/mergetb/tech/rtnl->github.com/mdlayher/netlink -->
|
||||
<g id="edge25" class="edge">
|
||||
<title>gitlab.com/mergetb/tech/rtnl->github.com/mdlayher/netlink</title>
|
||||
<path fill="none" stroke="black" d="M759.44,-122.98C776.06,-127.69 792.1,-134.45 806.13,-144 904.62,-211.07 953.88,-354.53 970.94,-415.1"/>
|
||||
<polygon fill="black" stroke="black" points="967.56,-416.02 973.58,-424.75 974.32,-414.18 967.56,-416.02"/>
|
||||
</g>
|
||||
<!-- github.com/SpComb/go-onewire -->
|
||||
<g id="node27" class="node">
|
||||
<title>github.com/SpComb/go-onewire</title>
|
||||
<g id="a_node27"><a xlink:href="https://github.com/SpComb/go-onewire" xlink:title="github.com/SpComb/go-onewire">
|
||||
<ellipse fill="none" stroke="black" cx="622.65" cy="-34" rx="159.47" ry="18"/>
|
||||
<text text-anchor="middle" x="622.65" y="-30.3" font-family="Times,serif" font-size="14.00">github.com/SpComb/go-onewire</text>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- github.com/SpComb/go-onewire->github.com/mdlayher/netlink -->
|
||||
<g id="edge26" class="edge">
|
||||
<title>github.com/SpComb/go-onewire->github.com/mdlayher/netlink</title>
|
||||
<path fill="none" stroke="black" d="M725.73,-47.78C754.17,-55.59 783.46,-67.83 806.13,-87 912.36,-176.8 958.15,-347.52 972.62,-414.77"/>
|
||||
<polygon fill="black" stroke="black" points="969.21,-415.57 974.68,-424.64 976.07,-414.14 969.21,-415.57"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 26 KiB |
93
vendor/github.com/mdlayher/netlink/netns_linux.go
generated
vendored
Normal file
93
vendor/github.com/mdlayher/netlink/netns_linux.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
//+build linux
|
||||
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// errNetNSDisabled is returned when network namespaces are unavailable on
|
||||
// a given system.
|
||||
var errNetNSDisabled = errors.New("netlink: network namespaces are not enabled on this system")
|
||||
|
||||
// A netNS is a handle that can manipulate network namespaces.
|
||||
//
|
||||
// Operations performed on a netNS must use runtime.LockOSThread before
|
||||
// manipulating any network namespaces.
|
||||
type netNS struct {
|
||||
// The handle to a network namespace.
|
||||
f *os.File
|
||||
|
||||
// Indicates if network namespaces are disabled on this system, and thus
|
||||
// operations should become a no-op or return errors.
|
||||
disabled bool
|
||||
}
|
||||
|
||||
// threadNetNS constructs a netNS using the network namespace of the calling
|
||||
// thread. If the namespace is not the default namespace, runtime.LockOSThread
|
||||
// should be invoked first.
|
||||
func threadNetNS() (*netNS, error) {
|
||||
return fileNetNS(fmt.Sprintf("/proc/self/task/%d/ns/net", unix.Gettid()))
|
||||
}
|
||||
|
||||
// fileNetNS opens file and creates a netNS. fileNetNS should only be called
|
||||
// directly in tests.
|
||||
func fileNetNS(file string) (*netNS, error) {
|
||||
f, err := os.Open(file)
|
||||
switch {
|
||||
case err == nil:
|
||||
return &netNS{f: f}, nil
|
||||
case os.IsNotExist(err):
|
||||
// Network namespaces are not enabled on this system. Use this signal
|
||||
// to return errors elsewhere if the caller explicitly asks for a
|
||||
// network namespace to be set.
|
||||
return &netNS{disabled: true}, nil
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Close releases the handle to a network namespace.
|
||||
func (n *netNS) Close() error {
|
||||
return n.do(func() error {
|
||||
return n.f.Close()
|
||||
})
|
||||
}
|
||||
|
||||
// FD returns a file descriptor which represents the network namespace.
|
||||
func (n *netNS) FD() int {
|
||||
if n.disabled {
|
||||
// No reasonable file descriptor value in this case, so specify a
|
||||
// non-existent one.
|
||||
return -1
|
||||
}
|
||||
|
||||
return int(n.f.Fd())
|
||||
}
|
||||
|
||||
// Restore restores the original network namespace for the calling thread.
|
||||
func (n *netNS) Restore() error {
|
||||
return n.do(func() error {
|
||||
return n.Set(n.FD())
|
||||
})
|
||||
}
|
||||
|
||||
// Set sets a new network namespace for the current thread using fd.
|
||||
func (n *netNS) Set(fd int) error {
|
||||
return n.do(func() error {
|
||||
return os.NewSyscallError("setns", unix.Setns(fd, unix.CLONE_NEWNET))
|
||||
})
|
||||
}
|
||||
|
||||
// do runs fn if network namespaces are enabled on this system.
|
||||
func (n *netNS) do(fn func() error) error {
|
||||
if n.disabled {
|
||||
return errNetNSDisabled
|
||||
}
|
||||
|
||||
return fn()
|
||||
}
|
15
vendor/github.com/mdlayher/netlink/nlenc/doc.go
generated
vendored
Normal file
15
vendor/github.com/mdlayher/netlink/nlenc/doc.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// Package nlenc implements encoding and decoding functions for netlink
|
||||
// messages and attributes.
|
||||
package nlenc
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/josharian/native"
|
||||
)
|
||||
|
||||
// NativeEndian returns the native byte order of this system.
|
||||
func NativeEndian() binary.ByteOrder {
|
||||
// TODO(mdlayher): consider deprecating and removing this function for v2.
|
||||
return native.Endian
|
||||
}
|
150
vendor/github.com/mdlayher/netlink/nlenc/int.go
generated
vendored
Normal file
150
vendor/github.com/mdlayher/netlink/nlenc/int.go
generated
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
package nlenc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// PutUint8 encodes a uint8 into b.
|
||||
// If b is not exactly 1 byte in length, PutUint8 will panic.
|
||||
func PutUint8(b []byte, v uint8) {
|
||||
if l := len(b); l != 1 {
|
||||
panic(fmt.Sprintf("PutUint8: unexpected byte slice length: %d", l))
|
||||
}
|
||||
|
||||
b[0] = v
|
||||
}
|
||||
|
||||
// PutUint16 encodes a uint16 into b using the host machine's native endianness.
|
||||
// If b is not exactly 2 bytes in length, PutUint16 will panic.
|
||||
func PutUint16(b []byte, v uint16) {
|
||||
if l := len(b); l != 2 {
|
||||
panic(fmt.Sprintf("PutUint16: unexpected byte slice length: %d", l))
|
||||
}
|
||||
|
||||
*(*uint16)(unsafe.Pointer(&b[0])) = v
|
||||
}
|
||||
|
||||
// PutUint32 encodes a uint32 into b using the host machine's native endianness.
|
||||
// If b is not exactly 4 bytes in length, PutUint32 will panic.
|
||||
func PutUint32(b []byte, v uint32) {
|
||||
if l := len(b); l != 4 {
|
||||
panic(fmt.Sprintf("PutUint32: unexpected byte slice length: %d", l))
|
||||
}
|
||||
|
||||
*(*uint32)(unsafe.Pointer(&b[0])) = v
|
||||
}
|
||||
|
||||
// PutUint64 encodes a uint64 into b using the host machine's native endianness.
|
||||
// If b is not exactly 8 bytes in length, PutUint64 will panic.
|
||||
func PutUint64(b []byte, v uint64) {
|
||||
if l := len(b); l != 8 {
|
||||
panic(fmt.Sprintf("PutUint64: unexpected byte slice length: %d", l))
|
||||
}
|
||||
|
||||
*(*uint64)(unsafe.Pointer(&b[0])) = v
|
||||
}
|
||||
|
||||
// PutInt32 encodes a int32 into b using the host machine's native endianness.
|
||||
// If b is not exactly 4 bytes in length, PutInt32 will panic.
|
||||
func PutInt32(b []byte, v int32) {
|
||||
if l := len(b); l != 4 {
|
||||
panic(fmt.Sprintf("PutInt32: unexpected byte slice length: %d", l))
|
||||
}
|
||||
|
||||
*(*int32)(unsafe.Pointer(&b[0])) = v
|
||||
}
|
||||
|
||||
// Uint8 decodes a uint8 from b.
|
||||
// If b is not exactly 1 byte in length, Uint8 will panic.
|
||||
func Uint8(b []byte) uint8 {
|
||||
if l := len(b); l != 1 {
|
||||
panic(fmt.Sprintf("Uint8: unexpected byte slice length: %d", l))
|
||||
}
|
||||
|
||||
return b[0]
|
||||
}
|
||||
|
||||
// Uint16 decodes a uint16 from b using the host machine's native endianness.
|
||||
// If b is not exactly 2 bytes in length, Uint16 will panic.
|
||||
func Uint16(b []byte) uint16 {
|
||||
if l := len(b); l != 2 {
|
||||
panic(fmt.Sprintf("Uint16: unexpected byte slice length: %d", l))
|
||||
}
|
||||
|
||||
return *(*uint16)(unsafe.Pointer(&b[0]))
|
||||
}
|
||||
|
||||
// Uint32 decodes a uint32 from b using the host machine's native endianness.
|
||||
// If b is not exactly 4 bytes in length, Uint32 will panic.
|
||||
func Uint32(b []byte) uint32 {
|
||||
if l := len(b); l != 4 {
|
||||
panic(fmt.Sprintf("Uint32: unexpected byte slice length: %d", l))
|
||||
}
|
||||
|
||||
return *(*uint32)(unsafe.Pointer(&b[0]))
|
||||
}
|
||||
|
||||
// Uint64 decodes a uint64 from b using the host machine's native endianness.
|
||||
// If b is not exactly 8 bytes in length, Uint64 will panic.
|
||||
func Uint64(b []byte) uint64 {
|
||||
if l := len(b); l != 8 {
|
||||
panic(fmt.Sprintf("Uint64: unexpected byte slice length: %d", l))
|
||||
}
|
||||
|
||||
return *(*uint64)(unsafe.Pointer(&b[0]))
|
||||
}
|
||||
|
||||
// Int32 decodes an int32 from b using the host machine's native endianness.
|
||||
// If b is not exactly 4 bytes in length, Int32 will panic.
|
||||
func Int32(b []byte) int32 {
|
||||
if l := len(b); l != 4 {
|
||||
panic(fmt.Sprintf("Int32: unexpected byte slice length: %d", l))
|
||||
}
|
||||
|
||||
return *(*int32)(unsafe.Pointer(&b[0]))
|
||||
}
|
||||
|
||||
// Uint8Bytes encodes a uint8 into a newly-allocated byte slice. It is a
|
||||
// shortcut for allocating a new byte slice and filling it using PutUint8.
|
||||
func Uint8Bytes(v uint8) []byte {
|
||||
b := make([]byte, 1)
|
||||
PutUint8(b, v)
|
||||
return b
|
||||
}
|
||||
|
||||
// Uint16Bytes encodes a uint16 into a newly-allocated byte slice using the
|
||||
// host machine's native endianness. It is a shortcut for allocating a new
|
||||
// byte slice and filling it using PutUint16.
|
||||
func Uint16Bytes(v uint16) []byte {
|
||||
b := make([]byte, 2)
|
||||
PutUint16(b, v)
|
||||
return b
|
||||
}
|
||||
|
||||
// Uint32Bytes encodes a uint32 into a newly-allocated byte slice using the
|
||||
// host machine's native endianness. It is a shortcut for allocating a new
|
||||
// byte slice and filling it using PutUint32.
|
||||
func Uint32Bytes(v uint32) []byte {
|
||||
b := make([]byte, 4)
|
||||
PutUint32(b, v)
|
||||
return b
|
||||
}
|
||||
|
||||
// Uint64Bytes encodes a uint64 into a newly-allocated byte slice using the
|
||||
// host machine's native endianness. It is a shortcut for allocating a new
|
||||
// byte slice and filling it using PutUint64.
|
||||
func Uint64Bytes(v uint64) []byte {
|
||||
b := make([]byte, 8)
|
||||
PutUint64(b, v)
|
||||
return b
|
||||
}
|
||||
|
||||
// Int32Bytes encodes a int32 into a newly-allocated byte slice using the
|
||||
// host machine's native endianness. It is a shortcut for allocating a new
|
||||
// byte slice and filling it using PutInt32.
|
||||
func Int32Bytes(v int32) []byte {
|
||||
b := make([]byte, 4)
|
||||
PutInt32(b, v)
|
||||
return b
|
||||
}
|
18
vendor/github.com/mdlayher/netlink/nlenc/string.go
generated
vendored
Normal file
18
vendor/github.com/mdlayher/netlink/nlenc/string.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
package nlenc
|
||||
|
||||
import "bytes"
|
||||
|
||||
// Bytes returns a null-terminated byte slice with the contents of s.
|
||||
func Bytes(s string) []byte {
|
||||
return append([]byte(s), 0x00)
|
||||
}
|
||||
|
||||
// String returns a string with the contents of b from a null-terminated
|
||||
// byte slice.
|
||||
func String(b []byte) string {
|
||||
// If the string has more than one NULL terminator byte, we want to remove
|
||||
// all of them before returning the string to the caller; hence the use of
|
||||
// strings.TrimRight instead of strings.TrimSuffix (which previously only
|
||||
// removed a single NULL).
|
||||
return string(bytes.TrimRight(b, "\x00"))
|
||||
}
|
9
vendor/github.com/mdlayher/socket/LICENSE.md
generated
vendored
Normal file
9
vendor/github.com/mdlayher/socket/LICENSE.md
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# MIT License
|
||||
|
||||
Copyright (C) 2021 Matt Layher
|
||||
|
||||
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.
|
14
vendor/github.com/mdlayher/socket/README.md
generated
vendored
Normal file
14
vendor/github.com/mdlayher/socket/README.md
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# socket [](https://github.com/mdlayher/socket/actions) [](https://pkg.go.dev/github.com/mdlayher/socket) [](https://goreportcard.com/report/github.com/mdlayher/socket)
|
||||
|
||||
Package `socket` provides a low-level network connection type which integrates
|
||||
with Go's runtime network poller to provide asynchronous I/O and deadline
|
||||
support. MIT Licensed.
|
||||
|
||||
This package focuses on UNIX-like operating systems which make use of BSD
|
||||
sockets system call APIs. It is meant to be used as a foundation for the
|
||||
creation of operating system-specific socket packages, for socket families such
|
||||
as Linux's `AF_NETLINK`, `AF_PACKET`, or `AF_VSOCK`. This package should not be
|
||||
used directly in end user applications.
|
||||
|
||||
Any use of package socket should be guarded by build tags, as one would also
|
||||
use when importing the `syscall` or `golang.org/x/sys` packages.
|
23
vendor/github.com/mdlayher/socket/accept.go
generated
vendored
Normal file
23
vendor/github.com/mdlayher/socket/accept.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
//go:build !dragonfly && !freebsd && !illumos && !linux
|
||||
// +build !dragonfly,!freebsd,!illumos,!linux
|
||||
|
||||
package socket
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const sysAccept = "accept"
|
||||
|
||||
// accept wraps accept(2).
|
||||
func accept(fd, flags int) (int, unix.Sockaddr, error) {
|
||||
if flags != 0 {
|
||||
// These operating systems have no support for flags to accept(2).
|
||||
return 0, nil, fmt.Errorf("socket: Conn.Accept flags are ineffective on %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
return unix.Accept(fd)
|
||||
}
|
15
vendor/github.com/mdlayher/socket/accept4.go
generated
vendored
Normal file
15
vendor/github.com/mdlayher/socket/accept4.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
//go:build dragonfly || freebsd || illumos || linux
|
||||
// +build dragonfly freebsd illumos linux
|
||||
|
||||
package socket
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const sysAccept = "accept4"
|
||||
|
||||
// accept wraps accept4(2).
|
||||
func accept(fd, flags int) (int, unix.Sockaddr, error) {
|
||||
return unix.Accept4(fd, flags)
|
||||
}
|
496
vendor/github.com/mdlayher/socket/conn.go
generated
vendored
Normal file
496
vendor/github.com/mdlayher/socket/conn.go
generated
vendored
Normal file
@@ -0,0 +1,496 @@
|
||||
package socket
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// A Conn is a low-level network connection which integrates with Go's runtime
|
||||
// network poller to provide asynchronous I/O and deadline support.
|
||||
type Conn struct {
|
||||
// Indicates whether or not Conn.Close has been called. Must be accessed
|
||||
// atomically. Atomics definitions must come first in the Conn struct.
|
||||
closed uint32
|
||||
|
||||
// A unique name for the Conn which is also associated with derived file
|
||||
// descriptors such as those created by accept(2).
|
||||
name string
|
||||
|
||||
// Provides access to the underlying file registered with the runtime
|
||||
// network poller, and arbitrary raw I/O calls.
|
||||
fd *os.File
|
||||
rc syscall.RawConn
|
||||
}
|
||||
|
||||
// High-level methods which provide convenience over raw system calls.
|
||||
|
||||
// Close closes the underlying file descriptor for the Conn, which also causes
|
||||
// all in-flight I/O operations to immediately unblock and return errors. Any
|
||||
// subsequent uses of Conn will result in EBADF.
|
||||
func (c *Conn) Close() error {
|
||||
// The caller has expressed an intent to close the socket, so immediately
|
||||
// increment s.closed to force further calls to result in EBADF before also
|
||||
// closing the file descriptor to unblock any outstanding operations.
|
||||
//
|
||||
// Because other operations simply check for s.closed != 0, we will permit
|
||||
// double Close, which would increment s.closed beyond 1.
|
||||
if atomic.AddUint32(&c.closed, 1) != 1 {
|
||||
// Multiple Close calls.
|
||||
return nil
|
||||
}
|
||||
|
||||
return os.NewSyscallError("close", c.fd.Close())
|
||||
}
|
||||
|
||||
// Read implements io.Reader by reading directly from the underlying file
|
||||
// descriptor.
|
||||
func (c *Conn) Read(b []byte) (int, error) { return c.fd.Read(b) }
|
||||
|
||||
// Write implements io.Writer by writing directly to the underlying file
|
||||
// descriptor.
|
||||
func (c *Conn) Write(b []byte) (int, error) { return c.fd.Write(b) }
|
||||
|
||||
// SetDeadline sets both the read and write deadlines associated with the Conn.
|
||||
func (c *Conn) SetDeadline(t time.Time) error { return c.fd.SetDeadline(t) }
|
||||
|
||||
// SetReadDeadline sets the read deadline associated with the Conn.
|
||||
func (c *Conn) SetReadDeadline(t time.Time) error { return c.fd.SetReadDeadline(t) }
|
||||
|
||||
// SetWriteDeadline sets the write deadline associated with the Conn.
|
||||
func (c *Conn) SetWriteDeadline(t time.Time) error { return c.fd.SetWriteDeadline(t) }
|
||||
|
||||
// ReadBuffer gets the size of the operating system's receive buffer associated
|
||||
// with the Conn.
|
||||
func (c *Conn) ReadBuffer() (int, error) {
|
||||
return c.GetsockoptInt(unix.SOL_SOCKET, unix.SO_RCVBUF)
|
||||
}
|
||||
|
||||
// WriteBuffer gets the size of the operating system's transmit buffer
|
||||
// associated with the Conn.
|
||||
func (c *Conn) WriteBuffer() (int, error) {
|
||||
return c.GetsockoptInt(unix.SOL_SOCKET, unix.SO_SNDBUF)
|
||||
}
|
||||
|
||||
// SetReadBuffer sets the size of the operating system's receive buffer
|
||||
// associated with the Conn.
|
||||
//
|
||||
// When called with elevated privileges on Linux, the SO_RCVBUFFORCE option will
|
||||
// be used to override operating system limits. Otherwise SO_RCVBUF is used
|
||||
// (which obeys operating system limits).
|
||||
func (c *Conn) SetReadBuffer(bytes int) error { return c.setReadBuffer(bytes) }
|
||||
|
||||
// SetWriteBuffer sets the size of the operating system's transmit buffer
|
||||
// associated with the Conn.
|
||||
//
|
||||
// When called with elevated privileges on Linux, the SO_SNDBUFFORCE option will
|
||||
// be used to override operating system limits. Otherwise SO_SNDBUF is used
|
||||
// (which obeys operating system limits).
|
||||
func (c *Conn) SetWriteBuffer(bytes int) error { return c.setWriteBuffer(bytes) }
|
||||
|
||||
// SyscallConn returns a raw network connection. This implements the
|
||||
// syscall.Conn interface.
|
||||
//
|
||||
// SyscallConn is intended for advanced use cases, such as getting and setting
|
||||
// arbitrary socket options using the socket's file descriptor. If possible,
|
||||
// those operations should be performed using methods on Conn instead.
|
||||
//
|
||||
// Once invoked, it is the caller's responsibility to ensure that operations
|
||||
// performed using Conn and the syscall.RawConn do not conflict with each other.
|
||||
func (c *Conn) SyscallConn() (syscall.RawConn, error) {
|
||||
if atomic.LoadUint32(&c.closed) != 0 {
|
||||
return nil, os.NewSyscallError("syscallconn", unix.EBADF)
|
||||
}
|
||||
|
||||
// TODO(mdlayher): mutex or similar to enforce syscall.RawConn contract of
|
||||
// FD remaining valid for duration of calls?
|
||||
return c.rc, nil
|
||||
}
|
||||
|
||||
// Socket wraps the socket(2) system call to produce a Conn. domain, typ, and
|
||||
// proto are passed directly to socket(2), and name should be a unique name for
|
||||
// the socket type such as "netlink" or "vsock".
|
||||
//
|
||||
// If the operating system supports SOCK_CLOEXEC and SOCK_NONBLOCK, they are
|
||||
// automatically applied to typ to mirror the standard library's socket flag
|
||||
// behaviors.
|
||||
func Socket(domain, typ, proto int, name string) (*Conn, error) {
|
||||
var (
|
||||
fd int
|
||||
err error
|
||||
)
|
||||
|
||||
for {
|
||||
fd, err = unix.Socket(domain, typ|socketFlags, proto)
|
||||
switch {
|
||||
case err == nil:
|
||||
// Some OSes already set CLOEXEC with typ.
|
||||
if !flagCLOEXEC {
|
||||
unix.CloseOnExec(fd)
|
||||
}
|
||||
|
||||
// No error, prepare the Conn.
|
||||
return newConn(fd, name)
|
||||
case !ready(err):
|
||||
// System call interrupted or not ready, try again.
|
||||
continue
|
||||
case err == unix.EINVAL, err == unix.EPROTONOSUPPORT:
|
||||
// On Linux, SOCK_NONBLOCK and SOCK_CLOEXEC were introduced in
|
||||
// 2.6.27. On FreeBSD, both flags were introduced in FreeBSD 10.
|
||||
// EINVAL and EPROTONOSUPPORT check for earlier versions of these
|
||||
// OSes respectively.
|
||||
//
|
||||
// Mirror what the standard library does when creating file
|
||||
// descriptors: avoid racing a fork/exec with the creation of new
|
||||
// file descriptors, so that child processes do not inherit socket
|
||||
// file descriptors unexpectedly.
|
||||
//
|
||||
// For a more thorough explanation, see similar work in the Go tree:
|
||||
// func sysSocket in net/sock_cloexec.go, as well as the detailed
|
||||
// comment in syscall/exec_unix.go.
|
||||
syscall.ForkLock.RLock()
|
||||
fd, err = unix.Socket(domain, typ, proto)
|
||||
if err == nil {
|
||||
unix.CloseOnExec(fd)
|
||||
}
|
||||
syscall.ForkLock.RUnlock()
|
||||
|
||||
return newConn(fd, name)
|
||||
default:
|
||||
// Unhandled error.
|
||||
return nil, os.NewSyscallError("socket", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(mdlayher): consider exporting newConn as New?
|
||||
|
||||
// newConn wraps an existing file descriptor to create a Conn. name should be a
|
||||
// unique name for the socket type such as "netlink" or "vsock".
|
||||
func newConn(fd int, name string) (*Conn, error) {
|
||||
// All Conn I/O is nonblocking for integration with Go's runtime network
|
||||
// poller. Depending on the OS this might already be set but it can't hurt
|
||||
// to set it again.
|
||||
if err := unix.SetNonblock(fd, true); err != nil {
|
||||
return nil, os.NewSyscallError("setnonblock", err)
|
||||
}
|
||||
|
||||
// os.NewFile registers the non-blocking file descriptor with the runtime
|
||||
// poller, which is then used for most subsequent operations except those
|
||||
// that require raw I/O via SyscallConn.
|
||||
//
|
||||
// See also: https://golang.org/pkg/os/#NewFile
|
||||
f := os.NewFile(uintptr(fd), name)
|
||||
rc, err := f.SyscallConn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Conn{
|
||||
name: name,
|
||||
fd: f,
|
||||
rc: rc,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Low-level methods which provide raw system call access.
|
||||
|
||||
// Accept wraps accept(2) or accept4(2) depending on the operating system, but
|
||||
// returns a Conn for the accepted connection rather than a raw file descriptor.
|
||||
//
|
||||
// If the operating system supports accept4(2) (which allows flags),
|
||||
// SOCK_CLOEXEC and SOCK_NONBLOCK are automatically applied to flags to mirror
|
||||
// the standard library's socket flag behaviors.
|
||||
//
|
||||
// If the operating system only supports accept(2) (which does not allow flags)
|
||||
// and flags is not zero, an error will be returned.
|
||||
func (c *Conn) Accept(flags int) (*Conn, unix.Sockaddr, error) {
|
||||
var (
|
||||
nfd int
|
||||
sa unix.Sockaddr
|
||||
err error
|
||||
)
|
||||
|
||||
doErr := c.read(sysAccept, func(fd int) error {
|
||||
// Either accept(2) or accept4(2) depending on the OS.
|
||||
nfd, sa, err = accept(fd, flags|socketFlags)
|
||||
return err
|
||||
})
|
||||
if doErr != nil {
|
||||
return nil, nil, doErr
|
||||
}
|
||||
if err != nil {
|
||||
// sysAccept is either "accept" or "accept4" depending on the OS.
|
||||
return nil, nil, os.NewSyscallError(sysAccept, err)
|
||||
}
|
||||
|
||||
// Successfully accepted a connection, wrap it in a Conn for use by the
|
||||
// caller.
|
||||
ac, err := newConn(nfd, c.name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return ac, sa, nil
|
||||
}
|
||||
|
||||
// Bind wraps bind(2).
|
||||
func (c *Conn) Bind(sa unix.Sockaddr) error {
|
||||
const op = "bind"
|
||||
|
||||
var err error
|
||||
doErr := c.control(op, func(fd int) error {
|
||||
err = unix.Bind(fd, sa)
|
||||
return err
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
return os.NewSyscallError(op, err)
|
||||
}
|
||||
|
||||
// Connect wraps connect(2).
|
||||
func (c *Conn) Connect(sa unix.Sockaddr) error {
|
||||
const op = "connect"
|
||||
|
||||
var err error
|
||||
doErr := c.write(op, func(fd int) error {
|
||||
err = unix.Connect(fd, sa)
|
||||
return err
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
if err == unix.EISCONN {
|
||||
// Darwin reports EISCONN if already connected, but the socket is
|
||||
// established and we don't need to report an error.
|
||||
return nil
|
||||
}
|
||||
|
||||
return os.NewSyscallError(op, err)
|
||||
}
|
||||
|
||||
// Getsockname wraps getsockname(2).
|
||||
func (c *Conn) Getsockname() (unix.Sockaddr, error) {
|
||||
const op = "getsockname"
|
||||
|
||||
var (
|
||||
sa unix.Sockaddr
|
||||
err error
|
||||
)
|
||||
|
||||
doErr := c.control(op, func(fd int) error {
|
||||
sa, err = unix.Getsockname(fd)
|
||||
return err
|
||||
})
|
||||
if doErr != nil {
|
||||
return nil, doErr
|
||||
}
|
||||
|
||||
return sa, os.NewSyscallError(op, err)
|
||||
}
|
||||
|
||||
// GetsockoptInt wraps getsockopt(2) for integer values.
|
||||
func (c *Conn) GetsockoptInt(level, opt int) (int, error) {
|
||||
const op = "getsockopt"
|
||||
|
||||
var (
|
||||
value int
|
||||
err error
|
||||
)
|
||||
|
||||
doErr := c.control(op, func(fd int) error {
|
||||
value, err = unix.GetsockoptInt(fd, level, opt)
|
||||
return err
|
||||
})
|
||||
if doErr != nil {
|
||||
return 0, doErr
|
||||
}
|
||||
|
||||
return value, os.NewSyscallError(op, err)
|
||||
}
|
||||
|
||||
// Listen wraps listen(2).
|
||||
func (c *Conn) Listen(n int) error {
|
||||
const op = "listen"
|
||||
|
||||
var err error
|
||||
doErr := c.control(op, func(fd int) error {
|
||||
err = unix.Listen(fd, n)
|
||||
return err
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
return os.NewSyscallError(op, err)
|
||||
}
|
||||
|
||||
// Recvmsg wraps recvmsg(2).
|
||||
func (c *Conn) Recvmsg(p, oob []byte, flags int) (int, int, int, unix.Sockaddr, error) {
|
||||
const op = "recvmsg"
|
||||
|
||||
var (
|
||||
n, oobn, recvflags int
|
||||
from unix.Sockaddr
|
||||
err error
|
||||
)
|
||||
|
||||
doErr := c.read(op, func(fd int) error {
|
||||
n, oobn, recvflags, from, err = unix.Recvmsg(fd, p, oob, flags)
|
||||
return err
|
||||
})
|
||||
if doErr != nil {
|
||||
return 0, 0, 0, nil, doErr
|
||||
}
|
||||
|
||||
return n, oobn, recvflags, from, os.NewSyscallError(op, err)
|
||||
}
|
||||
|
||||
// Recvfrom wraps recvfrom(2)
|
||||
func (c *Conn) Recvfrom(p []byte, flags int) (int, unix.Sockaddr, error) {
|
||||
const op = "recvfrom"
|
||||
|
||||
var (
|
||||
n int
|
||||
addr unix.Sockaddr
|
||||
err error
|
||||
)
|
||||
|
||||
doErr := c.read(op, func(fd int) error {
|
||||
n, addr, err = unix.Recvfrom(fd, p, flags)
|
||||
return err
|
||||
})
|
||||
if doErr != nil {
|
||||
return 0, nil, doErr
|
||||
}
|
||||
|
||||
return n, addr, os.NewSyscallError(op, err)
|
||||
}
|
||||
|
||||
// Sendmsg wraps sendmsg(2).
|
||||
func (c *Conn) Sendmsg(p, oob []byte, to unix.Sockaddr, flags int) error {
|
||||
const op = "sendmsg"
|
||||
|
||||
var err error
|
||||
doErr := c.write(op, func(fd int) error {
|
||||
err = unix.Sendmsg(fd, p, oob, to, flags)
|
||||
return err
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
return os.NewSyscallError(op, err)
|
||||
}
|
||||
|
||||
// Sendto wraps Sendto(2).
|
||||
func (c *Conn) Sendto(b []byte, to unix.Sockaddr, flags int) error {
|
||||
const op = "sendto"
|
||||
|
||||
var err error
|
||||
doErr := c.write(op, func(fd int) error {
|
||||
err = unix.Sendto(fd, b, flags, to)
|
||||
return err
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
return os.NewSyscallError(op, err)
|
||||
}
|
||||
|
||||
// SetsockoptInt wraps setsockopt(2) for integer values.
|
||||
func (c *Conn) SetsockoptInt(level, opt, value int) error {
|
||||
const op = "setsockopt"
|
||||
|
||||
var err error
|
||||
doErr := c.control(op, func(fd int) error {
|
||||
err = unix.SetsockoptInt(fd, level, opt, value)
|
||||
return err
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
return os.NewSyscallError(op, err)
|
||||
}
|
||||
|
||||
// Conn low-level read/write/control functions. These functions mirror the
|
||||
// syscall.RawConn APIs but the input closures return errors rather than
|
||||
// booleans. Any syscalls invoked within f should return their error to allow
|
||||
// the Conn to check for readiness with the runtime network poller, or to retry
|
||||
// operations which may have been interrupted by EINTR or similar.
|
||||
//
|
||||
// Note that errors from the input closure functions are not propagated to the
|
||||
// error return values of read/write/control, and the caller is still
|
||||
// responsible for error handling.
|
||||
|
||||
// read executes f, a read function, against the associated file descriptor.
|
||||
// op is used to create an *os.SyscallError if the file descriptor is closed.
|
||||
func (c *Conn) read(op string, f func(fd int) error) error {
|
||||
if atomic.LoadUint32(&c.closed) != 0 {
|
||||
return os.NewSyscallError(op, unix.EBADF)
|
||||
}
|
||||
|
||||
return c.rc.Read(func(fd uintptr) bool {
|
||||
return ready(f(int(fd)))
|
||||
})
|
||||
}
|
||||
|
||||
// write executes f, a write function, against the associated file descriptor.
|
||||
// op is used to create an *os.SyscallError if the file descriptor is closed.
|
||||
func (c *Conn) write(op string, f func(fd int) error) error {
|
||||
if atomic.LoadUint32(&c.closed) != 0 {
|
||||
return os.NewSyscallError(op, unix.EBADF)
|
||||
}
|
||||
|
||||
return c.rc.Write(func(fd uintptr) bool {
|
||||
return ready(f(int(fd)))
|
||||
})
|
||||
}
|
||||
|
||||
// control executes f, a control function, against the associated file
|
||||
// descriptor. op is used to create an *os.SyscallError if the file descriptor
|
||||
// is closed.
|
||||
func (c *Conn) control(op string, f func(fd int) error) error {
|
||||
if atomic.LoadUint32(&c.closed) != 0 {
|
||||
return os.NewSyscallError(op, unix.EBADF)
|
||||
}
|
||||
|
||||
return c.rc.Control(func(fd uintptr) {
|
||||
// Repeatedly attempt the syscall(s) invoked by f until completion is
|
||||
// indicated by the return value of ready.
|
||||
for {
|
||||
if ready(f(int(fd))) {
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ready indicates readiness based on the value of err.
|
||||
func ready(err error) bool {
|
||||
// When a socket is in non-blocking mode, we might see EAGAIN or
|
||||
// EINPROGRESS. In that case, return false to let the poller wait for
|
||||
// readiness. See the source code for internal/poll.FD.RawRead for more
|
||||
// details.
|
||||
//
|
||||
// Starting in Go 1.14, goroutines are asynchronously preemptible. The 1.14
|
||||
// release notes indicate that applications should expect to see EINTR more
|
||||
// often on slow system calls (like recvmsg while waiting for input), so we
|
||||
// must handle that case as well.
|
||||
switch err {
|
||||
case unix.EAGAIN, unix.EINTR, unix.EINPROGRESS:
|
||||
// Not ready.
|
||||
return false
|
||||
default:
|
||||
// Ready regardless of whether there was an error or no error.
|
||||
return true
|
||||
}
|
||||
}
|
88
vendor/github.com/mdlayher/socket/conn_linux.go
generated
vendored
Normal file
88
vendor/github.com/mdlayher/socket/conn_linux.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package socket
|
||||
|
||||
import (
|
||||
"os"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/net/bpf"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// SetBPF attaches an assembled BPF program to a Conn.
|
||||
func (c *Conn) SetBPF(filter []bpf.RawInstruction) error {
|
||||
// We can't point to the first instruction in the array if no instructions
|
||||
// are present.
|
||||
if len(filter) == 0 {
|
||||
return os.NewSyscallError("setsockopt", unix.EINVAL)
|
||||
}
|
||||
|
||||
prog := unix.SockFprog{
|
||||
Len: uint16(len(filter)),
|
||||
Filter: (*unix.SockFilter)(unsafe.Pointer(&filter[0])),
|
||||
}
|
||||
|
||||
return c.SetsockoptSockFprog(unix.SOL_SOCKET, unix.SO_ATTACH_FILTER, &prog)
|
||||
}
|
||||
|
||||
// RemoveBPF removes a BPF filter from a Conn.
|
||||
func (c *Conn) RemoveBPF() error {
|
||||
// 0 argument is ignored.
|
||||
return c.SetsockoptInt(unix.SOL_SOCKET, unix.SO_DETACH_FILTER, 0)
|
||||
}
|
||||
|
||||
// SetsockoptSockFprog wraps setsockopt(2) for unix.SockFprog values.
|
||||
func (c *Conn) SetsockoptSockFprog(level, opt int, fprog *unix.SockFprog) error {
|
||||
const op = "setsockopt"
|
||||
|
||||
var err error
|
||||
doErr := c.control(op, func(fd int) error {
|
||||
err = unix.SetsockoptSockFprog(fd, level, opt, fprog)
|
||||
return err
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
return os.NewSyscallError(op, err)
|
||||
}
|
||||
|
||||
// GetSockoptTpacketStats wraps getsockopt(2) for getting TpacketStats
|
||||
func (c *Conn) GetSockoptTpacketStats(level, name int) (*unix.TpacketStats, error) {
|
||||
const op = "getsockopt"
|
||||
|
||||
var (
|
||||
stats *unix.TpacketStats
|
||||
err error
|
||||
)
|
||||
|
||||
doErr := c.control(op, func(fd int) error {
|
||||
stats, err = unix.GetsockoptTpacketStats(fd, level, name)
|
||||
return err
|
||||
})
|
||||
if doErr != nil {
|
||||
return stats, doErr
|
||||
}
|
||||
return stats, os.NewSyscallError(op, err)
|
||||
}
|
||||
|
||||
// GetSockoptTpacketStatsV3 wraps getsockopt(2) for getting TpacketStatsV3
|
||||
func (c *Conn) GetSockoptTpacketStatsV3(level, name int) (*unix.TpacketStatsV3, error) {
|
||||
const op = "getsockopt"
|
||||
|
||||
var (
|
||||
stats *unix.TpacketStatsV3
|
||||
err error
|
||||
)
|
||||
|
||||
doErr := c.control(op, func(fd int) error {
|
||||
stats, err = unix.GetsockoptTpacketStatsV3(fd, level, name)
|
||||
return err
|
||||
})
|
||||
if doErr != nil {
|
||||
return stats, doErr
|
||||
}
|
||||
return stats, os.NewSyscallError(op, err)
|
||||
}
|
13
vendor/github.com/mdlayher/socket/doc.go
generated
vendored
Normal file
13
vendor/github.com/mdlayher/socket/doc.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Package socket provides a low-level network connection type which integrates
|
||||
// with Go's runtime network poller to provide asynchronous I/O and deadline
|
||||
// support.
|
||||
//
|
||||
// This package focuses on UNIX-like operating systems which make use of BSD
|
||||
// sockets system call APIs. It is meant to be used as a foundation for the
|
||||
// creation of operating system-specific socket packages, for socket families
|
||||
// such as Linux's AF_NETLINK, AF_PACKET, or AF_VSOCK. This package should not
|
||||
// be used directly in end user applications.
|
||||
//
|
||||
// Any use of package socket should be guarded by build tags, as one would also
|
||||
// use when importing the syscall or golang.org/x/sys packages.
|
||||
package socket
|
24
vendor/github.com/mdlayher/socket/setbuffer_linux.go
generated
vendored
Normal file
24
vendor/github.com/mdlayher/socket/setbuffer_linux.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package socket
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
// setReadBuffer wraps the SO_RCVBUF{,FORCE} setsockopt(2) options.
|
||||
func (c *Conn) setReadBuffer(bytes int) error {
|
||||
err := c.SetsockoptInt(unix.SOL_SOCKET, unix.SO_RCVBUFFORCE, bytes)
|
||||
if err != nil {
|
||||
err = c.SetsockoptInt(unix.SOL_SOCKET, unix.SO_RCVBUF, bytes)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// setWriteBuffer wraps the SO_SNDBUF{,FORCE} setsockopt(2) options.
|
||||
func (c *Conn) setWriteBuffer(bytes int) error {
|
||||
err := c.SetsockoptInt(unix.SOL_SOCKET, unix.SO_SNDBUFFORCE, bytes)
|
||||
if err != nil {
|
||||
err = c.SetsockoptInt(unix.SOL_SOCKET, unix.SO_SNDBUF, bytes)
|
||||
}
|
||||
return err
|
||||
}
|
16
vendor/github.com/mdlayher/socket/setbuffer_others.go
generated
vendored
Normal file
16
vendor/github.com/mdlayher/socket/setbuffer_others.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package socket
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
// setReadBuffer wraps the SO_RCVBUF setsockopt(2) option.
|
||||
func (c *Conn) setReadBuffer(bytes int) error {
|
||||
return c.SetsockoptInt(unix.SOL_SOCKET, unix.SO_RCVBUF, bytes)
|
||||
}
|
||||
|
||||
// setWriteBuffer wraps the SO_SNDBUF setsockopt(2) option.
|
||||
func (c *Conn) setWriteBuffer(bytes int) error {
|
||||
return c.SetsockoptInt(unix.SOL_SOCKET, unix.SO_SNDBUF, bytes)
|
||||
}
|
12
vendor/github.com/mdlayher/socket/typ_cloexec_nonblock.go
generated
vendored
Normal file
12
vendor/github.com/mdlayher/socket/typ_cloexec_nonblock.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
//go:build !darwin
|
||||
// +build !darwin
|
||||
|
||||
package socket
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
const (
|
||||
// These operating systems support CLOEXEC and NONBLOCK socket options.
|
||||
flagCLOEXEC = true
|
||||
socketFlags = unix.SOCK_CLOEXEC | unix.SOCK_NONBLOCK
|
||||
)
|
11
vendor/github.com/mdlayher/socket/typ_none.go
generated
vendored
Normal file
11
vendor/github.com/mdlayher/socket/typ_none.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package socket
|
||||
|
||||
const (
|
||||
// These operating systems do not support CLOEXEC and NONBLOCK socket
|
||||
// options.
|
||||
flagCLOEXEC = false
|
||||
socketFlags = 0
|
||||
)
|
Reference in New Issue
Block a user