vendor wgctrl
Signed-off-by: leonnicolas <leonloechner@gmx.de>
This commit is contained in:
parent
b1927990c2
commit
bde5c3e7d1
8
vendor/github.com/josharian/native/doc.go
generated
vendored
Normal file
8
vendor/github.com/josharian/native/doc.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
// Package native provides easy access to native byte order.
|
||||
//
|
||||
// Usage: use native.Endian where you need the native binary.ByteOrder.
|
||||
//
|
||||
// Please think twice before using this package.
|
||||
// It can break program portability.
|
||||
// Native byte order is usually not the right answer.
|
||||
package native
|
7
vendor/github.com/josharian/native/endian_big.go
generated
vendored
Normal file
7
vendor/github.com/josharian/native/endian_big.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
// +build mips mips64 ppc64 s390x
|
||||
|
||||
package native
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
var Endian = binary.BigEndian
|
26
vendor/github.com/josharian/native/endian_generic.go
generated
vendored
Normal file
26
vendor/github.com/josharian/native/endian_generic.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
// +build !mips,!mips64,!ppc64,!s390x,!amd64,!386,!arm,!arm64,!mipsle,!mips64le,!ppc64le,!riscv64,!wasm
|
||||
|
||||
// This file is a fallback, so that package native doesn't break
|
||||
// the instant the Go project adds support for a new architecture.
|
||||
//
|
||||
|
||||
package native
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"log"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var Endian binary.ByteOrder
|
||||
|
||||
func init() {
|
||||
b := uint16(0xff) // one byte
|
||||
if *(*byte)(unsafe.Pointer(&b)) == 0 {
|
||||
Endian = binary.BigEndian
|
||||
} else {
|
||||
Endian = binary.LittleEndian
|
||||
}
|
||||
log.Printf("github.com/josharian/native: unrecognized arch %v (%v), please file an issue", runtime.GOARCH, Endian)
|
||||
}
|
7
vendor/github.com/josharian/native/endian_little.go
generated
vendored
Normal file
7
vendor/github.com/josharian/native/endian_little.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
// +build amd64 386 arm arm64 mipsle mips64le ppc64le riscv64 wasm
|
||||
|
||||
package native
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
var Endian = binary.LittleEndian
|
3
vendor/github.com/josharian/native/go.mod
generated
vendored
Normal file
3
vendor/github.com/josharian/native/go.mod
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
module github.com/josharian/native
|
||||
|
||||
go 1.13
|
7
vendor/github.com/josharian/native/license
generated
vendored
Normal file
7
vendor/github.com/josharian/native/license
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
Copyright 2020 Josh Bleecher Snyder
|
||||
|
||||
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.
|
10
vendor/github.com/josharian/native/readme.md
generated
vendored
Normal file
10
vendor/github.com/josharian/native/readme.md
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
Package native provides easy access to native byte order.
|
||||
|
||||
`go get github.com/josharian/native`
|
||||
|
||||
Usage: Use `native.Endian` where you need the native binary.ByteOrder.
|
||||
|
||||
Please think twice before using this package.
|
||||
It can break program portability.
|
||||
Native byte order is usually not the right answer.
|
||||
|
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
|
||||
}
|
10
vendor/github.com/mdlayher/genetlink/go.mod
generated
vendored
Normal file
10
vendor/github.com/mdlayher/genetlink/go.mod
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
module github.com/mdlayher/genetlink
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/google/go-cmp v0.3.1
|
||||
github.com/mdlayher/netlink v1.0.0
|
||||
golang.org/x/net v0.0.0-20191007182048-72f939374954
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be
|
||||
)
|
22
vendor/github.com/mdlayher/genetlink/go.sum
generated
vendored
Normal file
22
vendor/github.com/mdlayher/genetlink/go.sum
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a h1:84IpUNXj4mCR9CuCEvSiCArMbzr/TMbuPIadKDwypkI=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
|
||||
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
|
||||
github.com/mdlayher/netlink v1.0.0 h1:vySPY5Oxnn/8lxAPn2cK6kAzcZzYJl3KriSLO46OT18=
|
||||
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191007182048-72f939374954 h1:JGZucVF/L/TotR719NbujzadOZ2AgnYlqphQGHDCKaU=
|
||||
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
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/
|
95
vendor/github.com/mdlayher/netlink/CHANGELOG.md
generated
vendored
Normal file
95
vendor/github.com/mdlayher/netlink/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 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
|
||||
}
|
569
vendor/github.com/mdlayher/netlink/conn_linux.go
generated
vendored
Normal file
569
vendor/github.com/mdlayher/netlink/conn_linux.go
generated
vendored
Normal file
@ -0,0 +1,569 @@
|
||||
//+build linux
|
||||
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"math"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/net/bpf"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var _ Socket = &conn{}
|
||||
|
||||
// A conn is the Linux implementation of a netlink sockets connection.
|
||||
//
|
||||
// All conn methods must wrap system call errors with os.NewSyscallError to
|
||||
// enable more intelligible error messages in OpError.
|
||||
type conn struct {
|
||||
s *socket
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// Prepare sysSocket's internal loop and create the socket.
|
||||
//
|
||||
// The conditional is inverted because a zero value of false is desired
|
||||
// if no config, but it's easier to interpret within this code when the
|
||||
// value is inverted.
|
||||
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()
|
||||
}
|
||||
|
||||
// Socket will establish the internal state of the socket structure.
|
||||
s, err := newSocket(family)
|
||||
if err != nil {
|
||||
return nil, 0, os.NewSyscallError("socket", err)
|
||||
}
|
||||
|
||||
return newConn(s, config)
|
||||
}
|
||||
|
||||
// newConn binds a connection to netlink using the input socket.
|
||||
func newConn(s *socket, 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, os.NewSyscallError("bind", err)
|
||||
}
|
||||
|
||||
sa, err := s.Getsockname()
|
||||
if err != nil {
|
||||
_ = s.Close()
|
||||
return nil, 0, os.NewSyscallError("getsockname", 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 os.NewSyscallError("sendmsg", 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 os.NewSyscallError("sendmsg", 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, os.NewSyscallError("recvmsg", 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, os.NewSyscallError("recvmsg", 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 os.NewSyscallError("close", c.s.Close())
|
||||
}
|
||||
|
||||
// JoinGroup joins a multicast group by ID.
|
||||
func (c *conn) JoinGroup(group uint32) error {
|
||||
return os.NewSyscallError("setsockopt", 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 os.NewSyscallError("setsockopt", 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 {
|
||||
// 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 os.NewSyscallError("setsockopt", c.s.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 by SO_DETACH_FILTER.
|
||||
return os.NewSyscallError("setsockopt", c.s.SetSockoptInt(
|
||||
unix.SOL_SOCKET,
|
||||
unix.SO_DETACH_FILTER,
|
||||
0,
|
||||
))
|
||||
}
|
||||
|
||||
// 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 os.NewSyscallError("setsockopt", 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 {
|
||||
// First try SO_RCVBUFFORCE. Given necessary permissions this syscall
|
||||
// ignores limits. Fall back to the non-force version.
|
||||
err := os.NewSyscallError("setsockopt", c.s.SetSockoptInt(
|
||||
unix.SOL_SOCKET,
|
||||
unix.SO_RCVBUFFORCE,
|
||||
bytes,
|
||||
))
|
||||
if err != nil {
|
||||
err = os.NewSyscallError("setsockopt", c.s.SetSockoptInt(
|
||||
unix.SOL_SOCKET,
|
||||
unix.SO_RCVBUF,
|
||||
bytes,
|
||||
))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// SetReadBuffer sets the size of the operating system's transmit buffer
|
||||
// associated with the Conn.
|
||||
func (c *conn) SetWriteBuffer(bytes int) error {
|
||||
// First try SO_SNDBUFFORCE. Given necessary permissions this syscall
|
||||
// ignores limits. Fall back to the non-force version.
|
||||
err := os.NewSyscallError("setsockopt", c.s.SetSockoptInt(
|
||||
unix.SOL_SOCKET,
|
||||
unix.SO_SNDBUFFORCE,
|
||||
bytes,
|
||||
))
|
||||
if err != nil {
|
||||
err = os.NewSyscallError("setsockopt", c.s.SetSockoptInt(
|
||||
unix.SOL_SOCKET,
|
||||
unix.SO_SNDBUF,
|
||||
bytes,
|
||||
))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// A socket wraps system call operations.
|
||||
type socket struct {
|
||||
// Atomics must come first.
|
||||
closed uint32
|
||||
|
||||
fd *os.File
|
||||
rc syscall.RawConn
|
||||
}
|
||||
|
||||
// read executes f, a read function, against the associated file descriptor.
|
||||
func (s *socket) read(f func(fd int) bool) error {
|
||||
if atomic.LoadUint32(&s.closed) != 0 {
|
||||
return syscall.EBADF
|
||||
}
|
||||
|
||||
return s.rc.Read(func(sysfd uintptr) bool {
|
||||
return f(int(sysfd))
|
||||
})
|
||||
}
|
||||
|
||||
// write executes f, a write function, against the associated file descriptor.
|
||||
func (s *socket) write(f func(fd int) bool) error {
|
||||
if atomic.LoadUint32(&s.closed) != 0 {
|
||||
return syscall.EBADF
|
||||
}
|
||||
|
||||
return s.rc.Write(func(sysfd uintptr) bool {
|
||||
return f(int(sysfd))
|
||||
})
|
||||
}
|
||||
|
||||
// control executes f, a control function, against the associated file descriptor.
|
||||
func (s *socket) control(f func(fd int)) error {
|
||||
if atomic.LoadUint32(&s.closed) != 0 {
|
||||
return syscall.EBADF
|
||||
}
|
||||
|
||||
return s.rc.Control(func(sysfd uintptr) {
|
||||
f(int(sysfd))
|
||||
})
|
||||
}
|
||||
|
||||
func (s *socket) SyscallConn() (syscall.RawConn, error) {
|
||||
if atomic.LoadUint32(&s.closed) != 0 {
|
||||
return nil, syscall.EBADF
|
||||
}
|
||||
|
||||
return s.rc, nil
|
||||
}
|
||||
|
||||
func newSocket(family int) (*socket, error) {
|
||||
// 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 netlink socket file descriptors unexpectedly.
|
||||
//
|
||||
// On Linux, SOCK_CLOEXEC was introduced in 2.6.27. OTOH,
|
||||
// Go supports Linux 2.6.23 and above. If we get EINVAL on
|
||||
// the first try, it may be that we are running on a kernel
|
||||
// older than 2.6.27. In that case, take syscall.ForkLock
|
||||
// and try again without SOCK_CLOEXEC.
|
||||
//
|
||||
// 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.
|
||||
fd, err := unix.Socket(
|
||||
unix.AF_NETLINK,
|
||||
unix.SOCK_RAW|unix.SOCK_NONBLOCK|unix.SOCK_CLOEXEC,
|
||||
family,
|
||||
)
|
||||
if err == unix.EINVAL {
|
||||
syscall.ForkLock.RLock()
|
||||
fd, err = unix.Socket(
|
||||
unix.AF_NETLINK,
|
||||
unix.SOCK_RAW,
|
||||
family,
|
||||
)
|
||||
if err == nil {
|
||||
unix.CloseOnExec(fd)
|
||||
}
|
||||
syscall.ForkLock.RUnlock()
|
||||
|
||||
if err := unix.SetNonblock(fd, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// os.NewFile registers the 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), "netlink")
|
||||
rc, err := f.SyscallConn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &socket{
|
||||
fd: f,
|
||||
rc: rc,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *socket) Bind(sa unix.Sockaddr) error {
|
||||
var err error
|
||||
doErr := s.control(func(fd int) {
|
||||
err = unix.Bind(fd, sa)
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *socket) 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(&s.closed, 1) != 1 {
|
||||
// Multiple Close calls.
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.fd.Close()
|
||||
}
|
||||
|
||||
func (s *socket) Getsockname() (unix.Sockaddr, error) {
|
||||
var (
|
||||
sa unix.Sockaddr
|
||||
err error
|
||||
)
|
||||
|
||||
doErr := s.control(func(fd int) {
|
||||
sa, err = unix.Getsockname(fd)
|
||||
})
|
||||
if doErr != nil {
|
||||
return nil, doErr
|
||||
}
|
||||
|
||||
return sa, err
|
||||
}
|
||||
|
||||
func (s *socket) Recvmsg(p, oob []byte, flags int) (int, int, int, unix.Sockaddr, error) {
|
||||
var (
|
||||
n, oobn, recvflags int
|
||||
from unix.Sockaddr
|
||||
err error
|
||||
)
|
||||
|
||||
doErr := s.read(func(fd int) bool {
|
||||
n, oobn, recvflags, from, err = unix.Recvmsg(fd, p, oob, flags)
|
||||
|
||||
// Check for readiness.
|
||||
return ready(err)
|
||||
})
|
||||
if doErr != nil {
|
||||
return 0, 0, 0, nil, doErr
|
||||
}
|
||||
|
||||
return n, oobn, recvflags, from, err
|
||||
}
|
||||
|
||||
func (s *socket) Sendmsg(p, oob []byte, to unix.Sockaddr, flags int) error {
|
||||
var err error
|
||||
doErr := s.write(func(fd int) bool {
|
||||
err = unix.Sendmsg(fd, p, oob, to, flags)
|
||||
|
||||
// Check for readiness.
|
||||
return ready(err)
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *socket) SetDeadline(t time.Time) error { return s.fd.SetDeadline(t) }
|
||||
func (s *socket) SetReadDeadline(t time.Time) error { return s.fd.SetReadDeadline(t) }
|
||||
func (s *socket) SetWriteDeadline(t time.Time) error { return s.fd.SetWriteDeadline(t) }
|
||||
|
||||
func (s *socket) SetSockoptInt(level, opt, value int) error {
|
||||
// Value must be in range of a C integer.
|
||||
if value < math.MinInt32 || value > math.MaxInt32 {
|
||||
return unix.EINVAL
|
||||
}
|
||||
|
||||
var err error
|
||||
doErr := s.control(func(fd int) {
|
||||
err = unix.SetsockoptInt(fd, level, opt, value)
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *socket) SetSockoptSockFprog(level, opt int, fprog *unix.SockFprog) error {
|
||||
var err error
|
||||
doErr := s.control(func(fd int) {
|
||||
err = unix.SetsockoptSockFprog(fd, level, opt, fprog)
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// 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. 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.
|
||||
//
|
||||
// If the socket is in blocking mode, EAGAIN should never occur.
|
||||
switch err {
|
||||
case syscall.EAGAIN, syscall.EINTR:
|
||||
// Not ready.
|
||||
return false
|
||||
default:
|
||||
// Ready whether there was error or no error.
|
||||
return true
|
||||
}
|
||||
}
|
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
|
||||
}
|
12
vendor/github.com/mdlayher/netlink/go.mod
generated
vendored
Normal file
12
vendor/github.com/mdlayher/netlink/go.mod
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
module github.com/mdlayher/netlink
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/google/go-cmp v0.5.4
|
||||
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b
|
||||
github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777
|
||||
golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65
|
||||
)
|
66
vendor/github.com/mdlayher/netlink/go.sum
generated
vendored
Normal file
66
vendor/github.com/mdlayher/netlink/go.sum
generated
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA=
|
||||
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b h1:c3NTyLNozICy8B4mlMXemD3z/gXgQzVXZS/HqT+i3do=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U=
|
||||
github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JAQI/ZLUkCZ7VJS3r74hwFIGXJsgZlY=
|
||||
github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo=
|
||||
github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0=
|
||||
github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=
|
||||
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
|
||||
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
|
||||
github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
|
||||
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
|
||||
github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8=
|
||||
github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
|
||||
github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
|
||||
github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65 h1:pTMjDVnP5eVRRlWO76rEWJ8JoC6Lf1CmyjPZXRiy2Sw=
|
||||
golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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"))
|
||||
}
|
3
vendor/golang.org/x/crypto/AUTHORS
generated
vendored
Normal file
3
vendor/golang.org/x/crypto/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# This source code refers to The Go Authors for copyright purposes.
|
||||
# The master list of authors is in the main Go distribution,
|
||||
# visible at https://tip.golang.org/AUTHORS.
|
3
vendor/golang.org/x/crypto/CONTRIBUTORS
generated
vendored
Normal file
3
vendor/golang.org/x/crypto/CONTRIBUTORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at https://tip.golang.org/CONTRIBUTORS.
|
27
vendor/golang.org/x/crypto/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/crypto/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
22
vendor/golang.org/x/crypto/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/crypto/PATENTS
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Go project.
|
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||
patent license to make, have made, use, offer to sell, sell, import,
|
||||
transfer and otherwise run, modify and propagate the contents of this
|
||||
implementation of Go, where such license applies only to those patent
|
||||
claims, both currently owned or controlled by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by this
|
||||
implementation of Go. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute or
|
||||
order or agree to the institution of patent litigation against any
|
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that this implementation of Go or any code incorporated within this
|
||||
implementation of Go constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of Go
|
||||
shall terminate as of the date such litigation is filed.
|
95
vendor/golang.org/x/crypto/curve25519/curve25519.go
generated
vendored
Normal file
95
vendor/golang.org/x/crypto/curve25519/curve25519.go
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
// Package curve25519 provides an implementation of the X25519 function, which
|
||||
// performs scalar multiplication on the elliptic curve known as Curve25519.
|
||||
// See RFC 7748.
|
||||
package curve25519 // import "golang.org/x/crypto/curve25519"
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ScalarMult sets dst to the product scalar * point.
|
||||
//
|
||||
// Deprecated: when provided a low-order point, ScalarMult will set dst to all
|
||||
// zeroes, irrespective of the scalar. Instead, use the X25519 function, which
|
||||
// will return an error.
|
||||
func ScalarMult(dst, scalar, point *[32]byte) {
|
||||
scalarMult(dst, scalar, point)
|
||||
}
|
||||
|
||||
// ScalarBaseMult sets dst to the product scalar * base where base is the
|
||||
// standard generator.
|
||||
//
|
||||
// It is recommended to use the X25519 function with Basepoint instead, as
|
||||
// copying into fixed size arrays can lead to unexpected bugs.
|
||||
func ScalarBaseMult(dst, scalar *[32]byte) {
|
||||
ScalarMult(dst, scalar, &basePoint)
|
||||
}
|
||||
|
||||
const (
|
||||
// ScalarSize is the size of the scalar input to X25519.
|
||||
ScalarSize = 32
|
||||
// PointSize is the size of the point input to X25519.
|
||||
PointSize = 32
|
||||
)
|
||||
|
||||
// Basepoint is the canonical Curve25519 generator.
|
||||
var Basepoint []byte
|
||||
|
||||
var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
|
||||
func init() { Basepoint = basePoint[:] }
|
||||
|
||||
func checkBasepoint() {
|
||||
if subtle.ConstantTimeCompare(Basepoint, []byte{
|
||||
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
}) != 1 {
|
||||
panic("curve25519: global Basepoint value was modified")
|
||||
}
|
||||
}
|
||||
|
||||
// X25519 returns the result of the scalar multiplication (scalar * point),
|
||||
// according to RFC 7748, Section 5. scalar, point and the return value are
|
||||
// slices of 32 bytes.
|
||||
//
|
||||
// scalar can be generated at random, for example with crypto/rand. point should
|
||||
// be either Basepoint or the output of another X25519 call.
|
||||
//
|
||||
// If point is Basepoint (but not if it's a different slice with the same
|
||||
// contents) a precomputed implementation might be used for performance.
|
||||
func X25519(scalar, point []byte) ([]byte, error) {
|
||||
// Outline the body of function, to let the allocation be inlined in the
|
||||
// caller, and possibly avoid escaping to the heap.
|
||||
var dst [32]byte
|
||||
return x25519(&dst, scalar, point)
|
||||
}
|
||||
|
||||
func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
|
||||
var in [32]byte
|
||||
if l := len(scalar); l != 32 {
|
||||
return nil, fmt.Errorf("bad scalar length: %d, expected %d", l, 32)
|
||||
}
|
||||
if l := len(point); l != 32 {
|
||||
return nil, fmt.Errorf("bad point length: %d, expected %d", l, 32)
|
||||
}
|
||||
copy(in[:], scalar)
|
||||
if &point[0] == &Basepoint[0] {
|
||||
checkBasepoint()
|
||||
ScalarBaseMult(dst, &in)
|
||||
} else {
|
||||
var base, zero [32]byte
|
||||
copy(base[:], point)
|
||||
ScalarMult(dst, &in, &base)
|
||||
if subtle.ConstantTimeCompare(dst[:], zero[:]) == 1 {
|
||||
return nil, fmt.Errorf("bad input point: low order point")
|
||||
}
|
||||
}
|
||||
return dst[:], nil
|
||||
}
|
241
vendor/golang.org/x/crypto/curve25519/curve25519_amd64.go
generated
vendored
Normal file
241
vendor/golang.org/x/crypto/curve25519/curve25519_amd64.go
generated
vendored
Normal file
@ -0,0 +1,241 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build amd64 && gc && !purego
|
||||
// +build amd64,gc,!purego
|
||||
|
||||
package curve25519
|
||||
|
||||
// These functions are implemented in the .s files. The names of the functions
|
||||
// in the rest of the file are also taken from the SUPERCOP sources to help
|
||||
// people following along.
|
||||
|
||||
//go:noescape
|
||||
|
||||
func cswap(inout *[5]uint64, v uint64)
|
||||
|
||||
//go:noescape
|
||||
|
||||
func ladderstep(inout *[5][5]uint64)
|
||||
|
||||
//go:noescape
|
||||
|
||||
func freeze(inout *[5]uint64)
|
||||
|
||||
//go:noescape
|
||||
|
||||
func mul(dest, a, b *[5]uint64)
|
||||
|
||||
//go:noescape
|
||||
|
||||
func square(out, in *[5]uint64)
|
||||
|
||||
// mladder uses a Montgomery ladder to calculate (xr/zr) *= s.
|
||||
func mladder(xr, zr *[5]uint64, s *[32]byte) {
|
||||
var work [5][5]uint64
|
||||
|
||||
work[0] = *xr
|
||||
setint(&work[1], 1)
|
||||
setint(&work[2], 0)
|
||||
work[3] = *xr
|
||||
setint(&work[4], 1)
|
||||
|
||||
j := uint(6)
|
||||
var prevbit byte
|
||||
|
||||
for i := 31; i >= 0; i-- {
|
||||
for j < 8 {
|
||||
bit := ((*s)[i] >> j) & 1
|
||||
swap := bit ^ prevbit
|
||||
prevbit = bit
|
||||
cswap(&work[1], uint64(swap))
|
||||
ladderstep(&work)
|
||||
j--
|
||||
}
|
||||
j = 7
|
||||
}
|
||||
|
||||
*xr = work[1]
|
||||
*zr = work[2]
|
||||
}
|
||||
|
||||
func scalarMult(out, in, base *[32]byte) {
|
||||
var e [32]byte
|
||||
copy(e[:], (*in)[:])
|
||||
e[0] &= 248
|
||||
e[31] &= 127
|
||||
e[31] |= 64
|
||||
|
||||
var t, z [5]uint64
|
||||
unpack(&t, base)
|
||||
mladder(&t, &z, &e)
|
||||
invert(&z, &z)
|
||||
mul(&t, &t, &z)
|
||||
pack(out, &t)
|
||||
}
|
||||
|
||||
func setint(r *[5]uint64, v uint64) {
|
||||
r[0] = v
|
||||
r[1] = 0
|
||||
r[2] = 0
|
||||
r[3] = 0
|
||||
r[4] = 0
|
||||
}
|
||||
|
||||
// unpack sets r = x where r consists of 5, 51-bit limbs in little-endian
|
||||
// order.
|
||||
func unpack(r *[5]uint64, x *[32]byte) {
|
||||
r[0] = uint64(x[0]) |
|
||||
uint64(x[1])<<8 |
|
||||
uint64(x[2])<<16 |
|
||||
uint64(x[3])<<24 |
|
||||
uint64(x[4])<<32 |
|
||||
uint64(x[5])<<40 |
|
||||
uint64(x[6]&7)<<48
|
||||
|
||||
r[1] = uint64(x[6])>>3 |
|
||||
uint64(x[7])<<5 |
|
||||
uint64(x[8])<<13 |
|
||||
uint64(x[9])<<21 |
|
||||
uint64(x[10])<<29 |
|
||||
uint64(x[11])<<37 |
|
||||
uint64(x[12]&63)<<45
|
||||
|
||||
r[2] = uint64(x[12])>>6 |
|
||||
uint64(x[13])<<2 |
|
||||
uint64(x[14])<<10 |
|
||||
uint64(x[15])<<18 |
|
||||
uint64(x[16])<<26 |
|
||||
uint64(x[17])<<34 |
|
||||
uint64(x[18])<<42 |
|
||||
uint64(x[19]&1)<<50
|
||||
|
||||
r[3] = uint64(x[19])>>1 |
|
||||
uint64(x[20])<<7 |
|
||||
uint64(x[21])<<15 |
|
||||
uint64(x[22])<<23 |
|
||||
uint64(x[23])<<31 |
|
||||
uint64(x[24])<<39 |
|
||||
uint64(x[25]&15)<<47
|
||||
|
||||
r[4] = uint64(x[25])>>4 |
|
||||
uint64(x[26])<<4 |
|
||||
uint64(x[27])<<12 |
|
||||
uint64(x[28])<<20 |
|
||||
uint64(x[29])<<28 |
|
||||
uint64(x[30])<<36 |
|
||||
uint64(x[31]&127)<<44
|
||||
}
|
||||
|
||||
// pack sets out = x where out is the usual, little-endian form of the 5,
|
||||
// 51-bit limbs in x.
|
||||
func pack(out *[32]byte, x *[5]uint64) {
|
||||
t := *x
|
||||
freeze(&t)
|
||||
|
||||
out[0] = byte(t[0])
|
||||
out[1] = byte(t[0] >> 8)
|
||||
out[2] = byte(t[0] >> 16)
|
||||
out[3] = byte(t[0] >> 24)
|
||||
out[4] = byte(t[0] >> 32)
|
||||
out[5] = byte(t[0] >> 40)
|
||||
out[6] = byte(t[0] >> 48)
|
||||
|
||||
out[6] ^= byte(t[1]<<3) & 0xf8
|
||||
out[7] = byte(t[1] >> 5)
|
||||
out[8] = byte(t[1] >> 13)
|
||||
out[9] = byte(t[1] >> 21)
|
||||
out[10] = byte(t[1] >> 29)
|
||||
out[11] = byte(t[1] >> 37)
|
||||
out[12] = byte(t[1] >> 45)
|
||||
|
||||
out[12] ^= byte(t[2]<<6) & 0xc0
|
||||
out[13] = byte(t[2] >> 2)
|
||||
out[14] = byte(t[2] >> 10)
|
||||
out[15] = byte(t[2] >> 18)
|
||||
out[16] = byte(t[2] >> 26)
|
||||
out[17] = byte(t[2] >> 34)
|
||||
out[18] = byte(t[2] >> 42)
|
||||
out[19] = byte(t[2] >> 50)
|
||||
|
||||
out[19] ^= byte(t[3]<<1) & 0xfe
|
||||
out[20] = byte(t[3] >> 7)
|
||||
out[21] = byte(t[3] >> 15)
|
||||
out[22] = byte(t[3] >> 23)
|
||||
out[23] = byte(t[3] >> 31)
|
||||
out[24] = byte(t[3] >> 39)
|
||||
out[25] = byte(t[3] >> 47)
|
||||
|
||||
out[25] ^= byte(t[4]<<4) & 0xf0
|
||||
out[26] = byte(t[4] >> 4)
|
||||
out[27] = byte(t[4] >> 12)
|
||||
out[28] = byte(t[4] >> 20)
|
||||
out[29] = byte(t[4] >> 28)
|
||||
out[30] = byte(t[4] >> 36)
|
||||
out[31] = byte(t[4] >> 44)
|
||||
}
|
||||
|
||||
// invert calculates r = x^-1 mod p using Fermat's little theorem.
|
||||
func invert(r *[5]uint64, x *[5]uint64) {
|
||||
var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t [5]uint64
|
||||
|
||||
square(&z2, x) /* 2 */
|
||||
square(&t, &z2) /* 4 */
|
||||
square(&t, &t) /* 8 */
|
||||
mul(&z9, &t, x) /* 9 */
|
||||
mul(&z11, &z9, &z2) /* 11 */
|
||||
square(&t, &z11) /* 22 */
|
||||
mul(&z2_5_0, &t, &z9) /* 2^5 - 2^0 = 31 */
|
||||
|
||||
square(&t, &z2_5_0) /* 2^6 - 2^1 */
|
||||
for i := 1; i < 5; i++ { /* 2^20 - 2^10 */
|
||||
square(&t, &t)
|
||||
}
|
||||
mul(&z2_10_0, &t, &z2_5_0) /* 2^10 - 2^0 */
|
||||
|
||||
square(&t, &z2_10_0) /* 2^11 - 2^1 */
|
||||
for i := 1; i < 10; i++ { /* 2^20 - 2^10 */
|
||||
square(&t, &t)
|
||||
}
|
||||
mul(&z2_20_0, &t, &z2_10_0) /* 2^20 - 2^0 */
|
||||
|
||||
square(&t, &z2_20_0) /* 2^21 - 2^1 */
|
||||
for i := 1; i < 20; i++ { /* 2^40 - 2^20 */
|
||||
square(&t, &t)
|
||||
}
|
||||
mul(&t, &t, &z2_20_0) /* 2^40 - 2^0 */
|
||||
|
||||
square(&t, &t) /* 2^41 - 2^1 */
|
||||
for i := 1; i < 10; i++ { /* 2^50 - 2^10 */
|
||||
square(&t, &t)
|
||||
}
|
||||
mul(&z2_50_0, &t, &z2_10_0) /* 2^50 - 2^0 */
|
||||
|
||||
square(&t, &z2_50_0) /* 2^51 - 2^1 */
|
||||
for i := 1; i < 50; i++ { /* 2^100 - 2^50 */
|
||||
square(&t, &t)
|
||||
}
|
||||
mul(&z2_100_0, &t, &z2_50_0) /* 2^100 - 2^0 */
|
||||
|
||||
square(&t, &z2_100_0) /* 2^101 - 2^1 */
|
||||
for i := 1; i < 100; i++ { /* 2^200 - 2^100 */
|
||||
square(&t, &t)
|
||||
}
|
||||
mul(&t, &t, &z2_100_0) /* 2^200 - 2^0 */
|
||||
|
||||
square(&t, &t) /* 2^201 - 2^1 */
|
||||
for i := 1; i < 50; i++ { /* 2^250 - 2^50 */
|
||||
square(&t, &t)
|
||||
}
|
||||
mul(&t, &t, &z2_50_0) /* 2^250 - 2^0 */
|
||||
|
||||
square(&t, &t) /* 2^251 - 2^1 */
|
||||
square(&t, &t) /* 2^252 - 2^2 */
|
||||
square(&t, &t) /* 2^253 - 2^3 */
|
||||
|
||||
square(&t, &t) /* 2^254 - 2^4 */
|
||||
|
||||
square(&t, &t) /* 2^255 - 2^5 */
|
||||
mul(r, &t, &z11) /* 2^255 - 21 */
|
||||
}
|
1793
vendor/golang.org/x/crypto/curve25519/curve25519_amd64.s
generated
vendored
Normal file
1793
vendor/golang.org/x/crypto/curve25519/curve25519_amd64.s
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
828
vendor/golang.org/x/crypto/curve25519/curve25519_generic.go
generated
vendored
Normal file
828
vendor/golang.org/x/crypto/curve25519/curve25519_generic.go
generated
vendored
Normal file
@ -0,0 +1,828 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
package curve25519
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// This code is a port of the public domain, "ref10" implementation of
|
||||
// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
|
||||
|
||||
// fieldElement represents an element of the field GF(2^255 - 19). An element
|
||||
// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
|
||||
// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
|
||||
// context.
|
||||
type fieldElement [10]int32
|
||||
|
||||
func feZero(fe *fieldElement) {
|
||||
for i := range fe {
|
||||
fe[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func feOne(fe *fieldElement) {
|
||||
feZero(fe)
|
||||
fe[0] = 1
|
||||
}
|
||||
|
||||
func feAdd(dst, a, b *fieldElement) {
|
||||
for i := range dst {
|
||||
dst[i] = a[i] + b[i]
|
||||
}
|
||||
}
|
||||
|
||||
func feSub(dst, a, b *fieldElement) {
|
||||
for i := range dst {
|
||||
dst[i] = a[i] - b[i]
|
||||
}
|
||||
}
|
||||
|
||||
func feCopy(dst, src *fieldElement) {
|
||||
for i := range dst {
|
||||
dst[i] = src[i]
|
||||
}
|
||||
}
|
||||
|
||||
// feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0.
|
||||
//
|
||||
// Preconditions: b in {0,1}.
|
||||
func feCSwap(f, g *fieldElement, b int32) {
|
||||
b = -b
|
||||
for i := range f {
|
||||
t := b & (f[i] ^ g[i])
|
||||
f[i] ^= t
|
||||
g[i] ^= t
|
||||
}
|
||||
}
|
||||
|
||||
// load3 reads a 24-bit, little-endian value from in.
|
||||
func load3(in []byte) int64 {
|
||||
var r int64
|
||||
r = int64(in[0])
|
||||
r |= int64(in[1]) << 8
|
||||
r |= int64(in[2]) << 16
|
||||
return r
|
||||
}
|
||||
|
||||
// load4 reads a 32-bit, little-endian value from in.
|
||||
func load4(in []byte) int64 {
|
||||
return int64(binary.LittleEndian.Uint32(in))
|
||||
}
|
||||
|
||||
func feFromBytes(dst *fieldElement, src *[32]byte) {
|
||||
h0 := load4(src[:])
|
||||
h1 := load3(src[4:]) << 6
|
||||
h2 := load3(src[7:]) << 5
|
||||
h3 := load3(src[10:]) << 3
|
||||
h4 := load3(src[13:]) << 2
|
||||
h5 := load4(src[16:])
|
||||
h6 := load3(src[20:]) << 7
|
||||
h7 := load3(src[23:]) << 5
|
||||
h8 := load3(src[26:]) << 4
|
||||
h9 := (load3(src[29:]) & 0x7fffff) << 2
|
||||
|
||||
var carry [10]int64
|
||||
carry[9] = (h9 + 1<<24) >> 25
|
||||
h0 += carry[9] * 19
|
||||
h9 -= carry[9] << 25
|
||||
carry[1] = (h1 + 1<<24) >> 25
|
||||
h2 += carry[1]
|
||||
h1 -= carry[1] << 25
|
||||
carry[3] = (h3 + 1<<24) >> 25
|
||||
h4 += carry[3]
|
||||
h3 -= carry[3] << 25
|
||||
carry[5] = (h5 + 1<<24) >> 25
|
||||
h6 += carry[5]
|
||||
h5 -= carry[5] << 25
|
||||
carry[7] = (h7 + 1<<24) >> 25
|
||||
h8 += carry[7]
|
||||
h7 -= carry[7] << 25
|
||||
|
||||
carry[0] = (h0 + 1<<25) >> 26
|
||||
h1 += carry[0]
|
||||
h0 -= carry[0] << 26
|
||||
carry[2] = (h2 + 1<<25) >> 26
|
||||
h3 += carry[2]
|
||||
h2 -= carry[2] << 26
|
||||
carry[4] = (h4 + 1<<25) >> 26
|
||||
h5 += carry[4]
|
||||
h4 -= carry[4] << 26
|
||||
carry[6] = (h6 + 1<<25) >> 26
|
||||
h7 += carry[6]
|
||||
h6 -= carry[6] << 26
|
||||
carry[8] = (h8 + 1<<25) >> 26
|
||||
h9 += carry[8]
|
||||
h8 -= carry[8] << 26
|
||||
|
||||
dst[0] = int32(h0)
|
||||
dst[1] = int32(h1)
|
||||
dst[2] = int32(h2)
|
||||
dst[3] = int32(h3)
|
||||
dst[4] = int32(h4)
|
||||
dst[5] = int32(h5)
|
||||
dst[6] = int32(h6)
|
||||
dst[7] = int32(h7)
|
||||
dst[8] = int32(h8)
|
||||
dst[9] = int32(h9)
|
||||
}
|
||||
|
||||
// feToBytes marshals h to s.
|
||||
// Preconditions:
|
||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
//
|
||||
// Write p=2^255-19; q=floor(h/p).
|
||||
// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
|
||||
//
|
||||
// Proof:
|
||||
// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
|
||||
// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
|
||||
//
|
||||
// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
|
||||
// Then 0<y<1.
|
||||
//
|
||||
// Write r=h-pq.
|
||||
// Have 0<=r<=p-1=2^255-20.
|
||||
// Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
|
||||
//
|
||||
// Write x=r+19(2^-255)r+y.
|
||||
// Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
|
||||
//
|
||||
// Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
|
||||
// so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
|
||||
func feToBytes(s *[32]byte, h *fieldElement) {
|
||||
var carry [10]int32
|
||||
|
||||
q := (19*h[9] + (1 << 24)) >> 25
|
||||
q = (h[0] + q) >> 26
|
||||
q = (h[1] + q) >> 25
|
||||
q = (h[2] + q) >> 26
|
||||
q = (h[3] + q) >> 25
|
||||
q = (h[4] + q) >> 26
|
||||
q = (h[5] + q) >> 25
|
||||
q = (h[6] + q) >> 26
|
||||
q = (h[7] + q) >> 25
|
||||
q = (h[8] + q) >> 26
|
||||
q = (h[9] + q) >> 25
|
||||
|
||||
// Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20.
|
||||
h[0] += 19 * q
|
||||
// Goal: Output h-2^255 q, which is between 0 and 2^255-20.
|
||||
|
||||
carry[0] = h[0] >> 26
|
||||
h[1] += carry[0]
|
||||
h[0] -= carry[0] << 26
|
||||
carry[1] = h[1] >> 25
|
||||
h[2] += carry[1]
|
||||
h[1] -= carry[1] << 25
|
||||
carry[2] = h[2] >> 26
|
||||
h[3] += carry[2]
|
||||
h[2] -= carry[2] << 26
|
||||
carry[3] = h[3] >> 25
|
||||
h[4] += carry[3]
|
||||
h[3] -= carry[3] << 25
|
||||
carry[4] = h[4] >> 26
|
||||
h[5] += carry[4]
|
||||
h[4] -= carry[4] << 26
|
||||
carry[5] = h[5] >> 25
|
||||
h[6] += carry[5]
|
||||
h[5] -= carry[5] << 25
|
||||
carry[6] = h[6] >> 26
|
||||
h[7] += carry[6]
|
||||
h[6] -= carry[6] << 26
|
||||
carry[7] = h[7] >> 25
|
||||
h[8] += carry[7]
|
||||
h[7] -= carry[7] << 25
|
||||
carry[8] = h[8] >> 26
|
||||
h[9] += carry[8]
|
||||
h[8] -= carry[8] << 26
|
||||
carry[9] = h[9] >> 25
|
||||
h[9] -= carry[9] << 25
|
||||
// h10 = carry9
|
||||
|
||||
// Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
|
||||
// Have h[0]+...+2^230 h[9] between 0 and 2^255-1;
|
||||
// evidently 2^255 h10-2^255 q = 0.
|
||||
// Goal: Output h[0]+...+2^230 h[9].
|
||||
|
||||
s[0] = byte(h[0] >> 0)
|
||||
s[1] = byte(h[0] >> 8)
|
||||
s[2] = byte(h[0] >> 16)
|
||||
s[3] = byte((h[0] >> 24) | (h[1] << 2))
|
||||
s[4] = byte(h[1] >> 6)
|
||||
s[5] = byte(h[1] >> 14)
|
||||
s[6] = byte((h[1] >> 22) | (h[2] << 3))
|
||||
s[7] = byte(h[2] >> 5)
|
||||
s[8] = byte(h[2] >> 13)
|
||||
s[9] = byte((h[2] >> 21) | (h[3] << 5))
|
||||
s[10] = byte(h[3] >> 3)
|
||||
s[11] = byte(h[3] >> 11)
|
||||
s[12] = byte((h[3] >> 19) | (h[4] << 6))
|
||||
s[13] = byte(h[4] >> 2)
|
||||
s[14] = byte(h[4] >> 10)
|
||||
s[15] = byte(h[4] >> 18)
|
||||
s[16] = byte(h[5] >> 0)
|
||||
s[17] = byte(h[5] >> 8)
|
||||
s[18] = byte(h[5] >> 16)
|
||||
s[19] = byte((h[5] >> 24) | (h[6] << 1))
|
||||
s[20] = byte(h[6] >> 7)
|
||||
s[21] = byte(h[6] >> 15)
|
||||
s[22] = byte((h[6] >> 23) | (h[7] << 3))
|
||||
s[23] = byte(h[7] >> 5)
|
||||
s[24] = byte(h[7] >> 13)
|
||||
s[25] = byte((h[7] >> 21) | (h[8] << 4))
|
||||
s[26] = byte(h[8] >> 4)
|
||||
s[27] = byte(h[8] >> 12)
|
||||
s[28] = byte((h[8] >> 20) | (h[9] << 6))
|
||||
s[29] = byte(h[9] >> 2)
|
||||
s[30] = byte(h[9] >> 10)
|
||||
s[31] = byte(h[9] >> 18)
|
||||
}
|
||||
|
||||
// feMul calculates h = f * g
|
||||
// Can overlap h with f or g.
|
||||
//
|
||||
// Preconditions:
|
||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
//
|
||||
// Postconditions:
|
||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
//
|
||||
// Notes on implementation strategy:
|
||||
//
|
||||
// Using schoolbook multiplication.
|
||||
// Karatsuba would save a little in some cost models.
|
||||
//
|
||||
// Most multiplications by 2 and 19 are 32-bit precomputations;
|
||||
// cheaper than 64-bit postcomputations.
|
||||
//
|
||||
// There is one remaining multiplication by 19 in the carry chain;
|
||||
// one *19 precomputation can be merged into this,
|
||||
// but the resulting data flow is considerably less clean.
|
||||
//
|
||||
// There are 12 carries below.
|
||||
// 10 of them are 2-way parallelizable and vectorizable.
|
||||
// Can get away with 11 carries, but then data flow is much deeper.
|
||||
//
|
||||
// With tighter constraints on inputs can squeeze carries into int32.
|
||||
func feMul(h, f, g *fieldElement) {
|
||||
f0 := f[0]
|
||||
f1 := f[1]
|
||||
f2 := f[2]
|
||||
f3 := f[3]
|
||||
f4 := f[4]
|
||||
f5 := f[5]
|
||||
f6 := f[6]
|
||||
f7 := f[7]
|
||||
f8 := f[8]
|
||||
f9 := f[9]
|
||||
g0 := g[0]
|
||||
g1 := g[1]
|
||||
g2 := g[2]
|
||||
g3 := g[3]
|
||||
g4 := g[4]
|
||||
g5 := g[5]
|
||||
g6 := g[6]
|
||||
g7 := g[7]
|
||||
g8 := g[8]
|
||||
g9 := g[9]
|
||||
g1_19 := 19 * g1 // 1.4*2^29
|
||||
g2_19 := 19 * g2 // 1.4*2^30; still ok
|
||||
g3_19 := 19 * g3
|
||||
g4_19 := 19 * g4
|
||||
g5_19 := 19 * g5
|
||||
g6_19 := 19 * g6
|
||||
g7_19 := 19 * g7
|
||||
g8_19 := 19 * g8
|
||||
g9_19 := 19 * g9
|
||||
f1_2 := 2 * f1
|
||||
f3_2 := 2 * f3
|
||||
f5_2 := 2 * f5
|
||||
f7_2 := 2 * f7
|
||||
f9_2 := 2 * f9
|
||||
f0g0 := int64(f0) * int64(g0)
|
||||
f0g1 := int64(f0) * int64(g1)
|
||||
f0g2 := int64(f0) * int64(g2)
|
||||
f0g3 := int64(f0) * int64(g3)
|
||||
f0g4 := int64(f0) * int64(g4)
|
||||
f0g5 := int64(f0) * int64(g5)
|
||||
f0g6 := int64(f0) * int64(g6)
|
||||
f0g7 := int64(f0) * int64(g7)
|
||||
f0g8 := int64(f0) * int64(g8)
|
||||
f0g9 := int64(f0) * int64(g9)
|
||||
f1g0 := int64(f1) * int64(g0)
|
||||
f1g1_2 := int64(f1_2) * int64(g1)
|
||||
f1g2 := int64(f1) * int64(g2)
|
||||
f1g3_2 := int64(f1_2) * int64(g3)
|
||||
f1g4 := int64(f1) * int64(g4)
|
||||
f1g5_2 := int64(f1_2) * int64(g5)
|
||||
f1g6 := int64(f1) * int64(g6)
|
||||
f1g7_2 := int64(f1_2) * int64(g7)
|
||||
f1g8 := int64(f1) * int64(g8)
|
||||
f1g9_38 := int64(f1_2) * int64(g9_19)
|
||||
f2g0 := int64(f2) * int64(g0)
|
||||
f2g1 := int64(f2) * int64(g1)
|
||||
f2g2 := int64(f2) * int64(g2)
|
||||
f2g3 := int64(f2) * int64(g3)
|
||||
f2g4 := int64(f2) * int64(g4)
|
||||
f2g5 := int64(f2) * int64(g5)
|
||||
f2g6 := int64(f2) * int64(g6)
|
||||
f2g7 := int64(f2) * int64(g7)
|
||||
f2g8_19 := int64(f2) * int64(g8_19)
|
||||
f2g9_19 := int64(f2) * int64(g9_19)
|
||||
f3g0 := int64(f3) * int64(g0)
|
||||
f3g1_2 := int64(f3_2) * int64(g1)
|
||||
f3g2 := int64(f3) * int64(g2)
|
||||
f3g3_2 := int64(f3_2) * int64(g3)
|
||||
f3g4 := int64(f3) * int64(g4)
|
||||
f3g5_2 := int64(f3_2) * int64(g5)
|
||||
f3g6 := int64(f3) * int64(g6)
|
||||
f3g7_38 := int64(f3_2) * int64(g7_19)
|
||||
f3g8_19 := int64(f3) * int64(g8_19)
|
||||
f3g9_38 := int64(f3_2) * int64(g9_19)
|
||||
f4g0 := int64(f4) * int64(g0)
|
||||
f4g1 := int64(f4) * int64(g1)
|
||||
f4g2 := int64(f4) * int64(g2)
|
||||
f4g3 := int64(f4) * int64(g3)
|
||||
f4g4 := int64(f4) * int64(g4)
|
||||
f4g5 := int64(f4) * int64(g5)
|
||||
f4g6_19 := int64(f4) * int64(g6_19)
|
||||
f4g7_19 := int64(f4) * int64(g7_19)
|
||||
f4g8_19 := int64(f4) * int64(g8_19)
|
||||
f4g9_19 := int64(f4) * int64(g9_19)
|
||||
f5g0 := int64(f5) * int64(g0)
|
||||
f5g1_2 := int64(f5_2) * int64(g1)
|
||||
f5g2 := int64(f5) * int64(g2)
|
||||
f5g3_2 := int64(f5_2) * int64(g3)
|
||||
f5g4 := int64(f5) * int64(g4)
|
||||
f5g5_38 := int64(f5_2) * int64(g5_19)
|
||||
f5g6_19 := int64(f5) * int64(g6_19)
|
||||
f5g7_38 := int64(f5_2) * int64(g7_19)
|
||||
f5g8_19 := int64(f5) * int64(g8_19)
|
||||
f5g9_38 := int64(f5_2) * int64(g9_19)
|
||||
f6g0 := int64(f6) * int64(g0)
|
||||
f6g1 := int64(f6) * int64(g1)
|
||||
f6g2 := int64(f6) * int64(g2)
|
||||
f6g3 := int64(f6) * int64(g3)
|
||||
f6g4_19 := int64(f6) * int64(g4_19)
|
||||
f6g5_19 := int64(f6) * int64(g5_19)
|
||||
f6g6_19 := int64(f6) * int64(g6_19)
|
||||
f6g7_19 := int64(f6) * int64(g7_19)
|
||||
f6g8_19 := int64(f6) * int64(g8_19)
|
||||
f6g9_19 := int64(f6) * int64(g9_19)
|
||||
f7g0 := int64(f7) * int64(g0)
|
||||
f7g1_2 := int64(f7_2) * int64(g1)
|
||||
f7g2 := int64(f7) * int64(g2)
|
||||
f7g3_38 := int64(f7_2) * int64(g3_19)
|
||||
f7g4_19 := int64(f7) * int64(g4_19)
|
||||
f7g5_38 := int64(f7_2) * int64(g5_19)
|
||||
f7g6_19 := int64(f7) * int64(g6_19)
|
||||
f7g7_38 := int64(f7_2) * int64(g7_19)
|
||||
f7g8_19 := int64(f7) * int64(g8_19)
|
||||
f7g9_38 := int64(f7_2) * int64(g9_19)
|
||||
f8g0 := int64(f8) * int64(g0)
|
||||
f8g1 := int64(f8) * int64(g1)
|
||||
f8g2_19 := int64(f8) * int64(g2_19)
|
||||
f8g3_19 := int64(f8) * int64(g3_19)
|
||||
f8g4_19 := int64(f8) * int64(g4_19)
|
||||
f8g5_19 := int64(f8) * int64(g5_19)
|
||||
f8g6_19 := int64(f8) * int64(g6_19)
|
||||
f8g7_19 := int64(f8) * int64(g7_19)
|
||||
f8g8_19 := int64(f8) * int64(g8_19)
|
||||
f8g9_19 := int64(f8) * int64(g9_19)
|
||||
f9g0 := int64(f9) * int64(g0)
|
||||
f9g1_38 := int64(f9_2) * int64(g1_19)
|
||||
f9g2_19 := int64(f9) * int64(g2_19)
|
||||
f9g3_38 := int64(f9_2) * int64(g3_19)
|
||||
f9g4_19 := int64(f9) * int64(g4_19)
|
||||
f9g5_38 := int64(f9_2) * int64(g5_19)
|
||||
f9g6_19 := int64(f9) * int64(g6_19)
|
||||
f9g7_38 := int64(f9_2) * int64(g7_19)
|
||||
f9g8_19 := int64(f9) * int64(g8_19)
|
||||
f9g9_38 := int64(f9_2) * int64(g9_19)
|
||||
h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38
|
||||
h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19
|
||||
h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38
|
||||
h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19
|
||||
h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38
|
||||
h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19
|
||||
h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38
|
||||
h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19
|
||||
h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38
|
||||
h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0
|
||||
var carry [10]int64
|
||||
|
||||
// |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
|
||||
// i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8
|
||||
// |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
|
||||
// i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9
|
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26
|
||||
h1 += carry[0]
|
||||
h0 -= carry[0] << 26
|
||||
carry[4] = (h4 + (1 << 25)) >> 26
|
||||
h5 += carry[4]
|
||||
h4 -= carry[4] << 26
|
||||
// |h0| <= 2^25
|
||||
// |h4| <= 2^25
|
||||
// |h1| <= 1.51*2^58
|
||||
// |h5| <= 1.51*2^58
|
||||
|
||||
carry[1] = (h1 + (1 << 24)) >> 25
|
||||
h2 += carry[1]
|
||||
h1 -= carry[1] << 25
|
||||
carry[5] = (h5 + (1 << 24)) >> 25
|
||||
h6 += carry[5]
|
||||
h5 -= carry[5] << 25
|
||||
// |h1| <= 2^24; from now on fits into int32
|
||||
// |h5| <= 2^24; from now on fits into int32
|
||||
// |h2| <= 1.21*2^59
|
||||
// |h6| <= 1.21*2^59
|
||||
|
||||
carry[2] = (h2 + (1 << 25)) >> 26
|
||||
h3 += carry[2]
|
||||
h2 -= carry[2] << 26
|
||||
carry[6] = (h6 + (1 << 25)) >> 26
|
||||
h7 += carry[6]
|
||||
h6 -= carry[6] << 26
|
||||
// |h2| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h6| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h3| <= 1.51*2^58
|
||||
// |h7| <= 1.51*2^58
|
||||
|
||||
carry[3] = (h3 + (1 << 24)) >> 25
|
||||
h4 += carry[3]
|
||||
h3 -= carry[3] << 25
|
||||
carry[7] = (h7 + (1 << 24)) >> 25
|
||||
h8 += carry[7]
|
||||
h7 -= carry[7] << 25
|
||||
// |h3| <= 2^24; from now on fits into int32 unchanged
|
||||
// |h7| <= 2^24; from now on fits into int32 unchanged
|
||||
// |h4| <= 1.52*2^33
|
||||
// |h8| <= 1.52*2^33
|
||||
|
||||
carry[4] = (h4 + (1 << 25)) >> 26
|
||||
h5 += carry[4]
|
||||
h4 -= carry[4] << 26
|
||||
carry[8] = (h8 + (1 << 25)) >> 26
|
||||
h9 += carry[8]
|
||||
h8 -= carry[8] << 26
|
||||
// |h4| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h8| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h5| <= 1.01*2^24
|
||||
// |h9| <= 1.51*2^58
|
||||
|
||||
carry[9] = (h9 + (1 << 24)) >> 25
|
||||
h0 += carry[9] * 19
|
||||
h9 -= carry[9] << 25
|
||||
// |h9| <= 2^24; from now on fits into int32 unchanged
|
||||
// |h0| <= 1.8*2^37
|
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26
|
||||
h1 += carry[0]
|
||||
h0 -= carry[0] << 26
|
||||
// |h0| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h1| <= 1.01*2^24
|
||||
|
||||
h[0] = int32(h0)
|
||||
h[1] = int32(h1)
|
||||
h[2] = int32(h2)
|
||||
h[3] = int32(h3)
|
||||
h[4] = int32(h4)
|
||||
h[5] = int32(h5)
|
||||
h[6] = int32(h6)
|
||||
h[7] = int32(h7)
|
||||
h[8] = int32(h8)
|
||||
h[9] = int32(h9)
|
||||
}
|
||||
|
||||
// feSquare calculates h = f*f. Can overlap h with f.
|
||||
//
|
||||
// Preconditions:
|
||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
//
|
||||
// Postconditions:
|
||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
func feSquare(h, f *fieldElement) {
|
||||
f0 := f[0]
|
||||
f1 := f[1]
|
||||
f2 := f[2]
|
||||
f3 := f[3]
|
||||
f4 := f[4]
|
||||
f5 := f[5]
|
||||
f6 := f[6]
|
||||
f7 := f[7]
|
||||
f8 := f[8]
|
||||
f9 := f[9]
|
||||
f0_2 := 2 * f0
|
||||
f1_2 := 2 * f1
|
||||
f2_2 := 2 * f2
|
||||
f3_2 := 2 * f3
|
||||
f4_2 := 2 * f4
|
||||
f5_2 := 2 * f5
|
||||
f6_2 := 2 * f6
|
||||
f7_2 := 2 * f7
|
||||
f5_38 := 38 * f5 // 1.31*2^30
|
||||
f6_19 := 19 * f6 // 1.31*2^30
|
||||
f7_38 := 38 * f7 // 1.31*2^30
|
||||
f8_19 := 19 * f8 // 1.31*2^30
|
||||
f9_38 := 38 * f9 // 1.31*2^30
|
||||
f0f0 := int64(f0) * int64(f0)
|
||||
f0f1_2 := int64(f0_2) * int64(f1)
|
||||
f0f2_2 := int64(f0_2) * int64(f2)
|
||||
f0f3_2 := int64(f0_2) * int64(f3)
|
||||
f0f4_2 := int64(f0_2) * int64(f4)
|
||||
f0f5_2 := int64(f0_2) * int64(f5)
|
||||
f0f6_2 := int64(f0_2) * int64(f6)
|
||||
f0f7_2 := int64(f0_2) * int64(f7)
|
||||
f0f8_2 := int64(f0_2) * int64(f8)
|
||||
f0f9_2 := int64(f0_2) * int64(f9)
|
||||
f1f1_2 := int64(f1_2) * int64(f1)
|
||||
f1f2_2 := int64(f1_2) * int64(f2)
|
||||
f1f3_4 := int64(f1_2) * int64(f3_2)
|
||||
f1f4_2 := int64(f1_2) * int64(f4)
|
||||
f1f5_4 := int64(f1_2) * int64(f5_2)
|
||||
f1f6_2 := int64(f1_2) * int64(f6)
|
||||
f1f7_4 := int64(f1_2) * int64(f7_2)
|
||||
f1f8_2 := int64(f1_2) * int64(f8)
|
||||
f1f9_76 := int64(f1_2) * int64(f9_38)
|
||||
f2f2 := int64(f2) * int64(f2)
|
||||
f2f3_2 := int64(f2_2) * int64(f3)
|
||||
f2f4_2 := int64(f2_2) * int64(f4)
|
||||
f2f5_2 := int64(f2_2) * int64(f5)
|
||||
f2f6_2 := int64(f2_2) * int64(f6)
|
||||
f2f7_2 := int64(f2_2) * int64(f7)
|
||||
f2f8_38 := int64(f2_2) * int64(f8_19)
|
||||
f2f9_38 := int64(f2) * int64(f9_38)
|
||||
f3f3_2 := int64(f3_2) * int64(f3)
|
||||
f3f4_2 := int64(f3_2) * int64(f4)
|
||||
f3f5_4 := int64(f3_2) * int64(f5_2)
|
||||
f3f6_2 := int64(f3_2) * int64(f6)
|
||||
f3f7_76 := int64(f3_2) * int64(f7_38)
|
||||
f3f8_38 := int64(f3_2) * int64(f8_19)
|
||||
f3f9_76 := int64(f3_2) * int64(f9_38)
|
||||
f4f4 := int64(f4) * int64(f4)
|
||||
f4f5_2 := int64(f4_2) * int64(f5)
|
||||
f4f6_38 := int64(f4_2) * int64(f6_19)
|
||||
f4f7_38 := int64(f4) * int64(f7_38)
|
||||
f4f8_38 := int64(f4_2) * int64(f8_19)
|
||||
f4f9_38 := int64(f4) * int64(f9_38)
|
||||
f5f5_38 := int64(f5) * int64(f5_38)
|
||||
f5f6_38 := int64(f5_2) * int64(f6_19)
|
||||
f5f7_76 := int64(f5_2) * int64(f7_38)
|
||||
f5f8_38 := int64(f5_2) * int64(f8_19)
|
||||
f5f9_76 := int64(f5_2) * int64(f9_38)
|
||||
f6f6_19 := int64(f6) * int64(f6_19)
|
||||
f6f7_38 := int64(f6) * int64(f7_38)
|
||||
f6f8_38 := int64(f6_2) * int64(f8_19)
|
||||
f6f9_38 := int64(f6) * int64(f9_38)
|
||||
f7f7_38 := int64(f7) * int64(f7_38)
|
||||
f7f8_38 := int64(f7_2) * int64(f8_19)
|
||||
f7f9_76 := int64(f7_2) * int64(f9_38)
|
||||
f8f8_19 := int64(f8) * int64(f8_19)
|
||||
f8f9_38 := int64(f8) * int64(f9_38)
|
||||
f9f9_38 := int64(f9) * int64(f9_38)
|
||||
h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38
|
||||
h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38
|
||||
h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19
|
||||
h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38
|
||||
h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38
|
||||
h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38
|
||||
h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19
|
||||
h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38
|
||||
h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38
|
||||
h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2
|
||||
var carry [10]int64
|
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26
|
||||
h1 += carry[0]
|
||||
h0 -= carry[0] << 26
|
||||
carry[4] = (h4 + (1 << 25)) >> 26
|
||||
h5 += carry[4]
|
||||
h4 -= carry[4] << 26
|
||||
|
||||
carry[1] = (h1 + (1 << 24)) >> 25
|
||||
h2 += carry[1]
|
||||
h1 -= carry[1] << 25
|
||||
carry[5] = (h5 + (1 << 24)) >> 25
|
||||
h6 += carry[5]
|
||||
h5 -= carry[5] << 25
|
||||
|
||||
carry[2] = (h2 + (1 << 25)) >> 26
|
||||
h3 += carry[2]
|
||||
h2 -= carry[2] << 26
|
||||
carry[6] = (h6 + (1 << 25)) >> 26
|
||||
h7 += carry[6]
|
||||
h6 -= carry[6] << 26
|
||||
|
||||
carry[3] = (h3 + (1 << 24)) >> 25
|
||||
h4 += carry[3]
|
||||
h3 -= carry[3] << 25
|
||||
carry[7] = (h7 + (1 << 24)) >> 25
|
||||
h8 += carry[7]
|
||||
h7 -= carry[7] << 25
|
||||
|
||||
carry[4] = (h4 + (1 << 25)) >> 26
|
||||
h5 += carry[4]
|
||||
h4 -= carry[4] << 26
|
||||
carry[8] = (h8 + (1 << 25)) >> 26
|
||||
h9 += carry[8]
|
||||
h8 -= carry[8] << 26
|
||||
|
||||
carry[9] = (h9 + (1 << 24)) >> 25
|
||||
h0 += carry[9] * 19
|
||||
h9 -= carry[9] << 25
|
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26
|
||||
h1 += carry[0]
|
||||
h0 -= carry[0] << 26
|
||||
|
||||
h[0] = int32(h0)
|
||||
h[1] = int32(h1)
|
||||
h[2] = int32(h2)
|
||||
h[3] = int32(h3)
|
||||
h[4] = int32(h4)
|
||||
h[5] = int32(h5)
|
||||
h[6] = int32(h6)
|
||||
h[7] = int32(h7)
|
||||
h[8] = int32(h8)
|
||||
h[9] = int32(h9)
|
||||
}
|
||||
|
||||
// feMul121666 calculates h = f * 121666. Can overlap h with f.
|
||||
//
|
||||
// Preconditions:
|
||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
//
|
||||
// Postconditions:
|
||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
func feMul121666(h, f *fieldElement) {
|
||||
h0 := int64(f[0]) * 121666
|
||||
h1 := int64(f[1]) * 121666
|
||||
h2 := int64(f[2]) * 121666
|
||||
h3 := int64(f[3]) * 121666
|
||||
h4 := int64(f[4]) * 121666
|
||||
h5 := int64(f[5]) * 121666
|
||||
h6 := int64(f[6]) * 121666
|
||||
h7 := int64(f[7]) * 121666
|
||||
h8 := int64(f[8]) * 121666
|
||||
h9 := int64(f[9]) * 121666
|
||||
var carry [10]int64
|
||||
|
||||
carry[9] = (h9 + (1 << 24)) >> 25
|
||||
h0 += carry[9] * 19
|
||||
h9 -= carry[9] << 25
|
||||
carry[1] = (h1 + (1 << 24)) >> 25
|
||||
h2 += carry[1]
|
||||
h1 -= carry[1] << 25
|
||||
carry[3] = (h3 + (1 << 24)) >> 25
|
||||
h4 += carry[3]
|
||||
h3 -= carry[3] << 25
|
||||
carry[5] = (h5 + (1 << 24)) >> 25
|
||||
h6 += carry[5]
|
||||
h5 -= carry[5] << 25
|
||||
carry[7] = (h7 + (1 << 24)) >> 25
|
||||
h8 += carry[7]
|
||||
h7 -= carry[7] << 25
|
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26
|
||||
h1 += carry[0]
|
||||
h0 -= carry[0] << 26
|
||||
carry[2] = (h2 + (1 << 25)) >> 26
|
||||
h3 += carry[2]
|
||||
h2 -= carry[2] << 26
|
||||
carry[4] = (h4 + (1 << 25)) >> 26
|
||||
h5 += carry[4]
|
||||
h4 -= carry[4] << 26
|
||||
carry[6] = (h6 + (1 << 25)) >> 26
|
||||
h7 += carry[6]
|
||||
h6 -= carry[6] << 26
|
||||
carry[8] = (h8 + (1 << 25)) >> 26
|
||||
h9 += carry[8]
|
||||
h8 -= carry[8] << 26
|
||||
|
||||
h[0] = int32(h0)
|
||||
h[1] = int32(h1)
|
||||
h[2] = int32(h2)
|
||||
h[3] = int32(h3)
|
||||
h[4] = int32(h4)
|
||||
h[5] = int32(h5)
|
||||
h[6] = int32(h6)
|
||||
h[7] = int32(h7)
|
||||
h[8] = int32(h8)
|
||||
h[9] = int32(h9)
|
||||
}
|
||||
|
||||
// feInvert sets out = z^-1.
|
||||
func feInvert(out, z *fieldElement) {
|
||||
var t0, t1, t2, t3 fieldElement
|
||||
var i int
|
||||
|
||||
feSquare(&t0, z)
|
||||
for i = 1; i < 1; i++ {
|
||||
feSquare(&t0, &t0)
|
||||
}
|
||||
feSquare(&t1, &t0)
|
||||
for i = 1; i < 2; i++ {
|
||||
feSquare(&t1, &t1)
|
||||
}
|
||||
feMul(&t1, z, &t1)
|
||||
feMul(&t0, &t0, &t1)
|
||||
feSquare(&t2, &t0)
|
||||
for i = 1; i < 1; i++ {
|
||||
feSquare(&t2, &t2)
|
||||
}
|
||||
feMul(&t1, &t1, &t2)
|
||||
feSquare(&t2, &t1)
|
||||
for i = 1; i < 5; i++ {
|
||||
feSquare(&t2, &t2)
|
||||
}
|
||||
feMul(&t1, &t2, &t1)
|
||||
feSquare(&t2, &t1)
|
||||
for i = 1; i < 10; i++ {
|
||||
feSquare(&t2, &t2)
|
||||
}
|
||||
feMul(&t2, &t2, &t1)
|
||||
feSquare(&t3, &t2)
|
||||
for i = 1; i < 20; i++ {
|
||||
feSquare(&t3, &t3)
|
||||
}
|
||||
feMul(&t2, &t3, &t2)
|
||||
feSquare(&t2, &t2)
|
||||
for i = 1; i < 10; i++ {
|
||||
feSquare(&t2, &t2)
|
||||
}
|
||||
feMul(&t1, &t2, &t1)
|
||||
feSquare(&t2, &t1)
|
||||
for i = 1; i < 50; i++ {
|
||||
feSquare(&t2, &t2)
|
||||
}
|
||||
feMul(&t2, &t2, &t1)
|
||||
feSquare(&t3, &t2)
|
||||
for i = 1; i < 100; i++ {
|
||||
feSquare(&t3, &t3)
|
||||
}
|
||||
feMul(&t2, &t3, &t2)
|
||||
feSquare(&t2, &t2)
|
||||
for i = 1; i < 50; i++ {
|
||||
feSquare(&t2, &t2)
|
||||
}
|
||||
feMul(&t1, &t2, &t1)
|
||||
feSquare(&t1, &t1)
|
||||
for i = 1; i < 5; i++ {
|
||||
feSquare(&t1, &t1)
|
||||
}
|
||||
feMul(out, &t1, &t0)
|
||||
}
|
||||
|
||||
func scalarMultGeneric(out, in, base *[32]byte) {
|
||||
var e [32]byte
|
||||
|
||||
copy(e[:], in[:])
|
||||
e[0] &= 248
|
||||
e[31] &= 127
|
||||
e[31] |= 64
|
||||
|
||||
var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement
|
||||
feFromBytes(&x1, base)
|
||||
feOne(&x2)
|
||||
feCopy(&x3, &x1)
|
||||
feOne(&z3)
|
||||
|
||||
swap := int32(0)
|
||||
for pos := 254; pos >= 0; pos-- {
|
||||
b := e[pos/8] >> uint(pos&7)
|
||||
b &= 1
|
||||
swap ^= int32(b)
|
||||
feCSwap(&x2, &x3, swap)
|
||||
feCSwap(&z2, &z3, swap)
|
||||
swap = int32(b)
|
||||
|
||||
feSub(&tmp0, &x3, &z3)
|
||||
feSub(&tmp1, &x2, &z2)
|
||||
feAdd(&x2, &x2, &z2)
|
||||
feAdd(&z2, &x3, &z3)
|
||||
feMul(&z3, &tmp0, &x2)
|
||||
feMul(&z2, &z2, &tmp1)
|
||||
feSquare(&tmp0, &tmp1)
|
||||
feSquare(&tmp1, &x2)
|
||||
feAdd(&x3, &z3, &z2)
|
||||
feSub(&z2, &z3, &z2)
|
||||
feMul(&x2, &tmp1, &tmp0)
|
||||
feSub(&tmp1, &tmp1, &tmp0)
|
||||
feSquare(&z2, &z2)
|
||||
feMul121666(&z3, &tmp1)
|
||||
feSquare(&x3, &x3)
|
||||
feAdd(&tmp0, &tmp0, &z3)
|
||||
feMul(&z3, &x1, &z2)
|
||||
feMul(&z2, &tmp1, &tmp0)
|
||||
}
|
||||
|
||||
feCSwap(&x2, &x3, swap)
|
||||
feCSwap(&z2, &z3, swap)
|
||||
|
||||
feInvert(&z2, &z2)
|
||||
feMul(&x2, &x2, &z2)
|
||||
feToBytes(out, &x2)
|
||||
}
|
12
vendor/golang.org/x/crypto/curve25519/curve25519_noasm.go
generated
vendored
Normal file
12
vendor/golang.org/x/crypto/curve25519/curve25519_noasm.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !amd64 || !gc || purego
|
||||
// +build !amd64 !gc purego
|
||||
|
||||
package curve25519
|
||||
|
||||
func scalarMult(out, in, base *[32]byte) {
|
||||
scalarMultGeneric(out, in, base)
|
||||
}
|
41
vendor/golang.org/x/net/bpf/asm.go
generated
vendored
Normal file
41
vendor/golang.org/x/net/bpf/asm.go
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bpf
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Assemble converts insts into raw instructions suitable for loading
|
||||
// into a BPF virtual machine.
|
||||
//
|
||||
// Currently, no optimization is attempted, the assembled program flow
|
||||
// is exactly as provided.
|
||||
func Assemble(insts []Instruction) ([]RawInstruction, error) {
|
||||
ret := make([]RawInstruction, len(insts))
|
||||
var err error
|
||||
for i, inst := range insts {
|
||||
ret[i], err = inst.Assemble()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("assembling instruction %d: %s", i+1, err)
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Disassemble attempts to parse raw back into
|
||||
// Instructions. Unrecognized RawInstructions are assumed to be an
|
||||
// extension not implemented by this package, and are passed through
|
||||
// unchanged to the output. The allDecoded value reports whether insts
|
||||
// contains no RawInstructions.
|
||||
func Disassemble(raw []RawInstruction) (insts []Instruction, allDecoded bool) {
|
||||
insts = make([]Instruction, len(raw))
|
||||
allDecoded = true
|
||||
for i, r := range raw {
|
||||
insts[i] = r.Disassemble()
|
||||
if _, ok := insts[i].(RawInstruction); ok {
|
||||
allDecoded = false
|
||||
}
|
||||
}
|
||||
return insts, allDecoded
|
||||
}
|
222
vendor/golang.org/x/net/bpf/constants.go
generated
vendored
Normal file
222
vendor/golang.org/x/net/bpf/constants.go
generated
vendored
Normal file
@ -0,0 +1,222 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bpf
|
||||
|
||||
// A Register is a register of the BPF virtual machine.
|
||||
type Register uint16
|
||||
|
||||
const (
|
||||
// RegA is the accumulator register. RegA is always the
|
||||
// destination register of ALU operations.
|
||||
RegA Register = iota
|
||||
// RegX is the indirection register, used by LoadIndirect
|
||||
// operations.
|
||||
RegX
|
||||
)
|
||||
|
||||
// An ALUOp is an arithmetic or logic operation.
|
||||
type ALUOp uint16
|
||||
|
||||
// ALU binary operation types.
|
||||
const (
|
||||
ALUOpAdd ALUOp = iota << 4
|
||||
ALUOpSub
|
||||
ALUOpMul
|
||||
ALUOpDiv
|
||||
ALUOpOr
|
||||
ALUOpAnd
|
||||
ALUOpShiftLeft
|
||||
ALUOpShiftRight
|
||||
aluOpNeg // Not exported because it's the only unary ALU operation, and gets its own instruction type.
|
||||
ALUOpMod
|
||||
ALUOpXor
|
||||
)
|
||||
|
||||
// A JumpTest is a comparison operator used in conditional jumps.
|
||||
type JumpTest uint16
|
||||
|
||||
// Supported operators for conditional jumps.
|
||||
// K can be RegX for JumpIfX
|
||||
const (
|
||||
// K == A
|
||||
JumpEqual JumpTest = iota
|
||||
// K != A
|
||||
JumpNotEqual
|
||||
// K > A
|
||||
JumpGreaterThan
|
||||
// K < A
|
||||
JumpLessThan
|
||||
// K >= A
|
||||
JumpGreaterOrEqual
|
||||
// K <= A
|
||||
JumpLessOrEqual
|
||||
// K & A != 0
|
||||
JumpBitsSet
|
||||
// K & A == 0
|
||||
JumpBitsNotSet
|
||||
)
|
||||
|
||||
// An Extension is a function call provided by the kernel that
|
||||
// performs advanced operations that are expensive or impossible
|
||||
// within the BPF virtual machine.
|
||||
//
|
||||
// Extensions are only implemented by the Linux kernel.
|
||||
//
|
||||
// TODO: should we prune this list? Some of these extensions seem
|
||||
// either broken or near-impossible to use correctly, whereas other
|
||||
// (len, random, ifindex) are quite useful.
|
||||
type Extension int
|
||||
|
||||
// Extension functions available in the Linux kernel.
|
||||
const (
|
||||
// extOffset is the negative maximum number of instructions used
|
||||
// to load instructions by overloading the K argument.
|
||||
extOffset = -0x1000
|
||||
// ExtLen returns the length of the packet.
|
||||
ExtLen Extension = 1
|
||||
// ExtProto returns the packet's L3 protocol type.
|
||||
ExtProto Extension = 0
|
||||
// ExtType returns the packet's type (skb->pkt_type in the kernel)
|
||||
//
|
||||
// TODO: better documentation. How nice an API do we want to
|
||||
// provide for these esoteric extensions?
|
||||
ExtType Extension = 4
|
||||
// ExtPayloadOffset returns the offset of the packet payload, or
|
||||
// the first protocol header that the kernel does not know how to
|
||||
// parse.
|
||||
ExtPayloadOffset Extension = 52
|
||||
// ExtInterfaceIndex returns the index of the interface on which
|
||||
// the packet was received.
|
||||
ExtInterfaceIndex Extension = 8
|
||||
// ExtNetlinkAttr returns the netlink attribute of type X at
|
||||
// offset A.
|
||||
ExtNetlinkAttr Extension = 12
|
||||
// ExtNetlinkAttrNested returns the nested netlink attribute of
|
||||
// type X at offset A.
|
||||
ExtNetlinkAttrNested Extension = 16
|
||||
// ExtMark returns the packet's mark value.
|
||||
ExtMark Extension = 20
|
||||
// ExtQueue returns the packet's assigned hardware queue.
|
||||
ExtQueue Extension = 24
|
||||
// ExtLinkLayerType returns the packet's hardware address type
|
||||
// (e.g. Ethernet, Infiniband).
|
||||
ExtLinkLayerType Extension = 28
|
||||
// ExtRXHash returns the packets receive hash.
|
||||
//
|
||||
// TODO: figure out what this rxhash actually is.
|
||||
ExtRXHash Extension = 32
|
||||
// ExtCPUID returns the ID of the CPU processing the current
|
||||
// packet.
|
||||
ExtCPUID Extension = 36
|
||||
// ExtVLANTag returns the packet's VLAN tag.
|
||||
ExtVLANTag Extension = 44
|
||||
// ExtVLANTagPresent returns non-zero if the packet has a VLAN
|
||||
// tag.
|
||||
//
|
||||
// TODO: I think this might be a lie: it reads bit 0x1000 of the
|
||||
// VLAN header, which changed meaning in recent revisions of the
|
||||
// spec - this extension may now return meaningless information.
|
||||
ExtVLANTagPresent Extension = 48
|
||||
// ExtVLANProto returns 0x8100 if the frame has a VLAN header,
|
||||
// 0x88a8 if the frame has a "Q-in-Q" double VLAN header, or some
|
||||
// other value if no VLAN information is present.
|
||||
ExtVLANProto Extension = 60
|
||||
// ExtRand returns a uniformly random uint32.
|
||||
ExtRand Extension = 56
|
||||
)
|
||||
|
||||
// The following gives names to various bit patterns used in opcode construction.
|
||||
|
||||
const (
|
||||
opMaskCls uint16 = 0x7
|
||||
// opClsLoad masks
|
||||
opMaskLoadDest = 0x01
|
||||
opMaskLoadWidth = 0x18
|
||||
opMaskLoadMode = 0xe0
|
||||
// opClsALU & opClsJump
|
||||
opMaskOperand = 0x08
|
||||
opMaskOperator = 0xf0
|
||||
)
|
||||
|
||||
const (
|
||||
// +---------------+-----------------+---+---+---+
|
||||
// | AddrMode (3b) | LoadWidth (2b) | 0 | 0 | 0 |
|
||||
// +---------------+-----------------+---+---+---+
|
||||
opClsLoadA uint16 = iota
|
||||
// +---------------+-----------------+---+---+---+
|
||||
// | AddrMode (3b) | LoadWidth (2b) | 0 | 0 | 1 |
|
||||
// +---------------+-----------------+---+---+---+
|
||||
opClsLoadX
|
||||
// +---+---+---+---+---+---+---+---+
|
||||
// | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
|
||||
// +---+---+---+---+---+---+---+---+
|
||||
opClsStoreA
|
||||
// +---+---+---+---+---+---+---+---+
|
||||
// | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
|
||||
// +---+---+---+---+---+---+---+---+
|
||||
opClsStoreX
|
||||
// +---------------+-----------------+---+---+---+
|
||||
// | Operator (4b) | OperandSrc (1b) | 1 | 0 | 0 |
|
||||
// +---------------+-----------------+---+---+---+
|
||||
opClsALU
|
||||
// +-----------------------------+---+---+---+---+
|
||||
// | TestOperator (4b) | 0 | 1 | 0 | 1 |
|
||||
// +-----------------------------+---+---+---+---+
|
||||
opClsJump
|
||||
// +---+-------------------------+---+---+---+---+
|
||||
// | 0 | 0 | 0 | RetSrc (1b) | 0 | 1 | 1 | 0 |
|
||||
// +---+-------------------------+---+---+---+---+
|
||||
opClsReturn
|
||||
// +---+-------------------------+---+---+---+---+
|
||||
// | 0 | 0 | 0 | TXAorTAX (1b) | 0 | 1 | 1 | 1 |
|
||||
// +---+-------------------------+---+---+---+---+
|
||||
opClsMisc
|
||||
)
|
||||
|
||||
const (
|
||||
opAddrModeImmediate uint16 = iota << 5
|
||||
opAddrModeAbsolute
|
||||
opAddrModeIndirect
|
||||
opAddrModeScratch
|
||||
opAddrModePacketLen // actually an extension, not an addressing mode.
|
||||
opAddrModeMemShift
|
||||
)
|
||||
|
||||
const (
|
||||
opLoadWidth4 uint16 = iota << 3
|
||||
opLoadWidth2
|
||||
opLoadWidth1
|
||||
)
|
||||
|
||||
// Operand for ALU and Jump instructions
|
||||
type opOperand uint16
|
||||
|
||||
// Supported operand sources.
|
||||
const (
|
||||
opOperandConstant opOperand = iota << 3
|
||||
opOperandX
|
||||
)
|
||||
|
||||
// An jumpOp is a conditional jump condition.
|
||||
type jumpOp uint16
|
||||
|
||||
// Supported jump conditions.
|
||||
const (
|
||||
opJumpAlways jumpOp = iota << 4
|
||||
opJumpEqual
|
||||
opJumpGT
|
||||
opJumpGE
|
||||
opJumpSet
|
||||
)
|
||||
|
||||
const (
|
||||
opRetSrcConstant uint16 = iota << 4
|
||||
opRetSrcA
|
||||
)
|
||||
|
||||
const (
|
||||
opMiscTAX = 0x00
|
||||
opMiscTXA = 0x80
|
||||
)
|
82
vendor/golang.org/x/net/bpf/doc.go
generated
vendored
Normal file
82
vendor/golang.org/x/net/bpf/doc.go
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
|
||||
Package bpf implements marshaling and unmarshaling of programs for the
|
||||
Berkeley Packet Filter virtual machine, and provides a Go implementation
|
||||
of the virtual machine.
|
||||
|
||||
BPF's main use is to specify a packet filter for network taps, so that
|
||||
the kernel doesn't have to expensively copy every packet it sees to
|
||||
userspace. However, it's been repurposed to other areas where running
|
||||
user code in-kernel is needed. For example, Linux's seccomp uses BPF
|
||||
to apply security policies to system calls. For simplicity, this
|
||||
documentation refers only to packets, but other uses of BPF have their
|
||||
own data payloads.
|
||||
|
||||
BPF programs run in a restricted virtual machine. It has almost no
|
||||
access to kernel functions, and while conditional branches are
|
||||
allowed, they can only jump forwards, to guarantee that there are no
|
||||
infinite loops.
|
||||
|
||||
The virtual machine
|
||||
|
||||
The BPF VM is an accumulator machine. Its main register, called
|
||||
register A, is an implicit source and destination in all arithmetic
|
||||
and logic operations. The machine also has 16 scratch registers for
|
||||
temporary storage, and an indirection register (register X) for
|
||||
indirect memory access. All registers are 32 bits wide.
|
||||
|
||||
Each run of a BPF program is given one packet, which is placed in the
|
||||
VM's read-only "main memory". LoadAbsolute and LoadIndirect
|
||||
instructions can fetch up to 32 bits at a time into register A for
|
||||
examination.
|
||||
|
||||
The goal of a BPF program is to produce and return a verdict (uint32),
|
||||
which tells the kernel what to do with the packet. In the context of
|
||||
packet filtering, the returned value is the number of bytes of the
|
||||
packet to forward to userspace, or 0 to ignore the packet. Other
|
||||
contexts like seccomp define their own return values.
|
||||
|
||||
In order to simplify programs, attempts to read past the end of the
|
||||
packet terminate the program execution with a verdict of 0 (ignore
|
||||
packet). This means that the vast majority of BPF programs don't need
|
||||
to do any explicit bounds checking.
|
||||
|
||||
In addition to the bytes of the packet, some BPF programs have access
|
||||
to extensions, which are essentially calls to kernel utility
|
||||
functions. Currently, the only extensions supported by this package
|
||||
are the Linux packet filter extensions.
|
||||
|
||||
Examples
|
||||
|
||||
This packet filter selects all ARP packets.
|
||||
|
||||
bpf.Assemble([]bpf.Instruction{
|
||||
// Load "EtherType" field from the ethernet header.
|
||||
bpf.LoadAbsolute{Off: 12, Size: 2},
|
||||
// Skip over the next instruction if EtherType is not ARP.
|
||||
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x0806, SkipTrue: 1},
|
||||
// Verdict is "send up to 4k of the packet to userspace."
|
||||
bpf.RetConstant{Val: 4096},
|
||||
// Verdict is "ignore packet."
|
||||
bpf.RetConstant{Val: 0},
|
||||
})
|
||||
|
||||
This packet filter captures a random 1% sample of traffic.
|
||||
|
||||
bpf.Assemble([]bpf.Instruction{
|
||||
// Get a 32-bit random number from the Linux kernel.
|
||||
bpf.LoadExtension{Num: bpf.ExtRand},
|
||||
// 1% dice roll?
|
||||
bpf.JumpIf{Cond: bpf.JumpLessThan, Val: 2^32/100, SkipFalse: 1},
|
||||
// Capture.
|
||||
bpf.RetConstant{Val: 4096},
|
||||
// Ignore.
|
||||
bpf.RetConstant{Val: 0},
|
||||
})
|
||||
|
||||
*/
|
||||
package bpf // import "golang.org/x/net/bpf"
|
726
vendor/golang.org/x/net/bpf/instructions.go
generated
vendored
Normal file
726
vendor/golang.org/x/net/bpf/instructions.go
generated
vendored
Normal file
@ -0,0 +1,726 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bpf
|
||||
|
||||
import "fmt"
|
||||
|
||||
// An Instruction is one instruction executed by the BPF virtual
|
||||
// machine.
|
||||
type Instruction interface {
|
||||
// Assemble assembles the Instruction into a RawInstruction.
|
||||
Assemble() (RawInstruction, error)
|
||||
}
|
||||
|
||||
// A RawInstruction is a raw BPF virtual machine instruction.
|
||||
type RawInstruction struct {
|
||||
// Operation to execute.
|
||||
Op uint16
|
||||
// For conditional jump instructions, the number of instructions
|
||||
// to skip if the condition is true/false.
|
||||
Jt uint8
|
||||
Jf uint8
|
||||
// Constant parameter. The meaning depends on the Op.
|
||||
K uint32
|
||||
}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (ri RawInstruction) Assemble() (RawInstruction, error) { return ri, nil }
|
||||
|
||||
// Disassemble parses ri into an Instruction and returns it. If ri is
|
||||
// not recognized by this package, ri itself is returned.
|
||||
func (ri RawInstruction) Disassemble() Instruction {
|
||||
switch ri.Op & opMaskCls {
|
||||
case opClsLoadA, opClsLoadX:
|
||||
reg := Register(ri.Op & opMaskLoadDest)
|
||||
sz := 0
|
||||
switch ri.Op & opMaskLoadWidth {
|
||||
case opLoadWidth4:
|
||||
sz = 4
|
||||
case opLoadWidth2:
|
||||
sz = 2
|
||||
case opLoadWidth1:
|
||||
sz = 1
|
||||
default:
|
||||
return ri
|
||||
}
|
||||
switch ri.Op & opMaskLoadMode {
|
||||
case opAddrModeImmediate:
|
||||
if sz != 4 {
|
||||
return ri
|
||||
}
|
||||
return LoadConstant{Dst: reg, Val: ri.K}
|
||||
case opAddrModeScratch:
|
||||
if sz != 4 || ri.K > 15 {
|
||||
return ri
|
||||
}
|
||||
return LoadScratch{Dst: reg, N: int(ri.K)}
|
||||
case opAddrModeAbsolute:
|
||||
if ri.K > extOffset+0xffffffff {
|
||||
return LoadExtension{Num: Extension(-extOffset + ri.K)}
|
||||
}
|
||||
return LoadAbsolute{Size: sz, Off: ri.K}
|
||||
case opAddrModeIndirect:
|
||||
return LoadIndirect{Size: sz, Off: ri.K}
|
||||
case opAddrModePacketLen:
|
||||
if sz != 4 {
|
||||
return ri
|
||||
}
|
||||
return LoadExtension{Num: ExtLen}
|
||||
case opAddrModeMemShift:
|
||||
return LoadMemShift{Off: ri.K}
|
||||
default:
|
||||
return ri
|
||||
}
|
||||
|
||||
case opClsStoreA:
|
||||
if ri.Op != opClsStoreA || ri.K > 15 {
|
||||
return ri
|
||||
}
|
||||
return StoreScratch{Src: RegA, N: int(ri.K)}
|
||||
|
||||
case opClsStoreX:
|
||||
if ri.Op != opClsStoreX || ri.K > 15 {
|
||||
return ri
|
||||
}
|
||||
return StoreScratch{Src: RegX, N: int(ri.K)}
|
||||
|
||||
case opClsALU:
|
||||
switch op := ALUOp(ri.Op & opMaskOperator); op {
|
||||
case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor:
|
||||
switch operand := opOperand(ri.Op & opMaskOperand); operand {
|
||||
case opOperandX:
|
||||
return ALUOpX{Op: op}
|
||||
case opOperandConstant:
|
||||
return ALUOpConstant{Op: op, Val: ri.K}
|
||||
default:
|
||||
return ri
|
||||
}
|
||||
case aluOpNeg:
|
||||
return NegateA{}
|
||||
default:
|
||||
return ri
|
||||
}
|
||||
|
||||
case opClsJump:
|
||||
switch op := jumpOp(ri.Op & opMaskOperator); op {
|
||||
case opJumpAlways:
|
||||
return Jump{Skip: ri.K}
|
||||
case opJumpEqual, opJumpGT, opJumpGE, opJumpSet:
|
||||
cond, skipTrue, skipFalse := jumpOpToTest(op, ri.Jt, ri.Jf)
|
||||
switch operand := opOperand(ri.Op & opMaskOperand); operand {
|
||||
case opOperandX:
|
||||
return JumpIfX{Cond: cond, SkipTrue: skipTrue, SkipFalse: skipFalse}
|
||||
case opOperandConstant:
|
||||
return JumpIf{Cond: cond, Val: ri.K, SkipTrue: skipTrue, SkipFalse: skipFalse}
|
||||
default:
|
||||
return ri
|
||||
}
|
||||
default:
|
||||
return ri
|
||||
}
|
||||
|
||||
case opClsReturn:
|
||||
switch ri.Op {
|
||||
case opClsReturn | opRetSrcA:
|
||||
return RetA{}
|
||||
case opClsReturn | opRetSrcConstant:
|
||||
return RetConstant{Val: ri.K}
|
||||
default:
|
||||
return ri
|
||||
}
|
||||
|
||||
case opClsMisc:
|
||||
switch ri.Op {
|
||||
case opClsMisc | opMiscTAX:
|
||||
return TAX{}
|
||||
case opClsMisc | opMiscTXA:
|
||||
return TXA{}
|
||||
default:
|
||||
return ri
|
||||
}
|
||||
|
||||
default:
|
||||
panic("unreachable") // switch is exhaustive on the bit pattern
|
||||
}
|
||||
}
|
||||
|
||||
func jumpOpToTest(op jumpOp, skipTrue uint8, skipFalse uint8) (JumpTest, uint8, uint8) {
|
||||
var test JumpTest
|
||||
|
||||
// Decode "fake" jump conditions that don't appear in machine code
|
||||
// Ensures the Assemble -> Disassemble stage recreates the same instructions
|
||||
// See https://github.com/golang/go/issues/18470
|
||||
if skipTrue == 0 {
|
||||
switch op {
|
||||
case opJumpEqual:
|
||||
test = JumpNotEqual
|
||||
case opJumpGT:
|
||||
test = JumpLessOrEqual
|
||||
case opJumpGE:
|
||||
test = JumpLessThan
|
||||
case opJumpSet:
|
||||
test = JumpBitsNotSet
|
||||
}
|
||||
|
||||
return test, skipFalse, 0
|
||||
}
|
||||
|
||||
switch op {
|
||||
case opJumpEqual:
|
||||
test = JumpEqual
|
||||
case opJumpGT:
|
||||
test = JumpGreaterThan
|
||||
case opJumpGE:
|
||||
test = JumpGreaterOrEqual
|
||||
case opJumpSet:
|
||||
test = JumpBitsSet
|
||||
}
|
||||
|
||||
return test, skipTrue, skipFalse
|
||||
}
|
||||
|
||||
// LoadConstant loads Val into register Dst.
|
||||
type LoadConstant struct {
|
||||
Dst Register
|
||||
Val uint32
|
||||
}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a LoadConstant) Assemble() (RawInstruction, error) {
|
||||
return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a LoadConstant) String() string {
|
||||
switch a.Dst {
|
||||
case RegA:
|
||||
return fmt.Sprintf("ld #%d", a.Val)
|
||||
case RegX:
|
||||
return fmt.Sprintf("ldx #%d", a.Val)
|
||||
default:
|
||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||
}
|
||||
}
|
||||
|
||||
// LoadScratch loads scratch[N] into register Dst.
|
||||
type LoadScratch struct {
|
||||
Dst Register
|
||||
N int // 0-15
|
||||
}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a LoadScratch) Assemble() (RawInstruction, error) {
|
||||
if a.N < 0 || a.N > 15 {
|
||||
return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
|
||||
}
|
||||
return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a LoadScratch) String() string {
|
||||
switch a.Dst {
|
||||
case RegA:
|
||||
return fmt.Sprintf("ld M[%d]", a.N)
|
||||
case RegX:
|
||||
return fmt.Sprintf("ldx M[%d]", a.N)
|
||||
default:
|
||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||
}
|
||||
}
|
||||
|
||||
// LoadAbsolute loads packet[Off:Off+Size] as an integer value into
|
||||
// register A.
|
||||
type LoadAbsolute struct {
|
||||
Off uint32
|
||||
Size int // 1, 2 or 4
|
||||
}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a LoadAbsolute) Assemble() (RawInstruction, error) {
|
||||
return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a LoadAbsolute) String() string {
|
||||
switch a.Size {
|
||||
case 1: // byte
|
||||
return fmt.Sprintf("ldb [%d]", a.Off)
|
||||
case 2: // half word
|
||||
return fmt.Sprintf("ldh [%d]", a.Off)
|
||||
case 4: // word
|
||||
if a.Off > extOffset+0xffffffff {
|
||||
return LoadExtension{Num: Extension(a.Off + 0x1000)}.String()
|
||||
}
|
||||
return fmt.Sprintf("ld [%d]", a.Off)
|
||||
default:
|
||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||
}
|
||||
}
|
||||
|
||||
// LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value
|
||||
// into register A.
|
||||
type LoadIndirect struct {
|
||||
Off uint32
|
||||
Size int // 1, 2 or 4
|
||||
}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a LoadIndirect) Assemble() (RawInstruction, error) {
|
||||
return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a LoadIndirect) String() string {
|
||||
switch a.Size {
|
||||
case 1: // byte
|
||||
return fmt.Sprintf("ldb [x + %d]", a.Off)
|
||||
case 2: // half word
|
||||
return fmt.Sprintf("ldh [x + %d]", a.Off)
|
||||
case 4: // word
|
||||
return fmt.Sprintf("ld [x + %d]", a.Off)
|
||||
default:
|
||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||
}
|
||||
}
|
||||
|
||||
// LoadMemShift multiplies the first 4 bits of the byte at packet[Off]
|
||||
// by 4 and stores the result in register X.
|
||||
//
|
||||
// This instruction is mainly useful to load into X the length of an
|
||||
// IPv4 packet header in a single instruction, rather than have to do
|
||||
// the arithmetic on the header's first byte by hand.
|
||||
type LoadMemShift struct {
|
||||
Off uint32
|
||||
}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a LoadMemShift) Assemble() (RawInstruction, error) {
|
||||
return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a LoadMemShift) String() string {
|
||||
return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off)
|
||||
}
|
||||
|
||||
// LoadExtension invokes a linux-specific extension and stores the
|
||||
// result in register A.
|
||||
type LoadExtension struct {
|
||||
Num Extension
|
||||
}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a LoadExtension) Assemble() (RawInstruction, error) {
|
||||
if a.Num == ExtLen {
|
||||
return assembleLoad(RegA, 4, opAddrModePacketLen, 0)
|
||||
}
|
||||
return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num))
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a LoadExtension) String() string {
|
||||
switch a.Num {
|
||||
case ExtLen:
|
||||
return "ld #len"
|
||||
case ExtProto:
|
||||
return "ld #proto"
|
||||
case ExtType:
|
||||
return "ld #type"
|
||||
case ExtPayloadOffset:
|
||||
return "ld #poff"
|
||||
case ExtInterfaceIndex:
|
||||
return "ld #ifidx"
|
||||
case ExtNetlinkAttr:
|
||||
return "ld #nla"
|
||||
case ExtNetlinkAttrNested:
|
||||
return "ld #nlan"
|
||||
case ExtMark:
|
||||
return "ld #mark"
|
||||
case ExtQueue:
|
||||
return "ld #queue"
|
||||
case ExtLinkLayerType:
|
||||
return "ld #hatype"
|
||||
case ExtRXHash:
|
||||
return "ld #rxhash"
|
||||
case ExtCPUID:
|
||||
return "ld #cpu"
|
||||
case ExtVLANTag:
|
||||
return "ld #vlan_tci"
|
||||
case ExtVLANTagPresent:
|
||||
return "ld #vlan_avail"
|
||||
case ExtVLANProto:
|
||||
return "ld #vlan_tpid"
|
||||
case ExtRand:
|
||||
return "ld #rand"
|
||||
default:
|
||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||
}
|
||||
}
|
||||
|
||||
// StoreScratch stores register Src into scratch[N].
|
||||
type StoreScratch struct {
|
||||
Src Register
|
||||
N int // 0-15
|
||||
}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a StoreScratch) Assemble() (RawInstruction, error) {
|
||||
if a.N < 0 || a.N > 15 {
|
||||
return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
|
||||
}
|
||||
var op uint16
|
||||
switch a.Src {
|
||||
case RegA:
|
||||
op = opClsStoreA
|
||||
case RegX:
|
||||
op = opClsStoreX
|
||||
default:
|
||||
return RawInstruction{}, fmt.Errorf("invalid source register %v", a.Src)
|
||||
}
|
||||
|
||||
return RawInstruction{
|
||||
Op: op,
|
||||
K: uint32(a.N),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a StoreScratch) String() string {
|
||||
switch a.Src {
|
||||
case RegA:
|
||||
return fmt.Sprintf("st M[%d]", a.N)
|
||||
case RegX:
|
||||
return fmt.Sprintf("stx M[%d]", a.N)
|
||||
default:
|
||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||
}
|
||||
}
|
||||
|
||||
// ALUOpConstant executes A = A <Op> Val.
|
||||
type ALUOpConstant struct {
|
||||
Op ALUOp
|
||||
Val uint32
|
||||
}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a ALUOpConstant) Assemble() (RawInstruction, error) {
|
||||
return RawInstruction{
|
||||
Op: opClsALU | uint16(opOperandConstant) | uint16(a.Op),
|
||||
K: a.Val,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a ALUOpConstant) String() string {
|
||||
switch a.Op {
|
||||
case ALUOpAdd:
|
||||
return fmt.Sprintf("add #%d", a.Val)
|
||||
case ALUOpSub:
|
||||
return fmt.Sprintf("sub #%d", a.Val)
|
||||
case ALUOpMul:
|
||||
return fmt.Sprintf("mul #%d", a.Val)
|
||||
case ALUOpDiv:
|
||||
return fmt.Sprintf("div #%d", a.Val)
|
||||
case ALUOpMod:
|
||||
return fmt.Sprintf("mod #%d", a.Val)
|
||||
case ALUOpAnd:
|
||||
return fmt.Sprintf("and #%d", a.Val)
|
||||
case ALUOpOr:
|
||||
return fmt.Sprintf("or #%d", a.Val)
|
||||
case ALUOpXor:
|
||||
return fmt.Sprintf("xor #%d", a.Val)
|
||||
case ALUOpShiftLeft:
|
||||
return fmt.Sprintf("lsh #%d", a.Val)
|
||||
case ALUOpShiftRight:
|
||||
return fmt.Sprintf("rsh #%d", a.Val)
|
||||
default:
|
||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||
}
|
||||
}
|
||||
|
||||
// ALUOpX executes A = A <Op> X
|
||||
type ALUOpX struct {
|
||||
Op ALUOp
|
||||
}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a ALUOpX) Assemble() (RawInstruction, error) {
|
||||
return RawInstruction{
|
||||
Op: opClsALU | uint16(opOperandX) | uint16(a.Op),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a ALUOpX) String() string {
|
||||
switch a.Op {
|
||||
case ALUOpAdd:
|
||||
return "add x"
|
||||
case ALUOpSub:
|
||||
return "sub x"
|
||||
case ALUOpMul:
|
||||
return "mul x"
|
||||
case ALUOpDiv:
|
||||
return "div x"
|
||||
case ALUOpMod:
|
||||
return "mod x"
|
||||
case ALUOpAnd:
|
||||
return "and x"
|
||||
case ALUOpOr:
|
||||
return "or x"
|
||||
case ALUOpXor:
|
||||
return "xor x"
|
||||
case ALUOpShiftLeft:
|
||||
return "lsh x"
|
||||
case ALUOpShiftRight:
|
||||
return "rsh x"
|
||||
default:
|
||||
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||
}
|
||||
}
|
||||
|
||||
// NegateA executes A = -A.
|
||||
type NegateA struct{}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a NegateA) Assemble() (RawInstruction, error) {
|
||||
return RawInstruction{
|
||||
Op: opClsALU | uint16(aluOpNeg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a NegateA) String() string {
|
||||
return fmt.Sprintf("neg")
|
||||
}
|
||||
|
||||
// Jump skips the following Skip instructions in the program.
|
||||
type Jump struct {
|
||||
Skip uint32
|
||||
}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a Jump) Assemble() (RawInstruction, error) {
|
||||
return RawInstruction{
|
||||
Op: opClsJump | uint16(opJumpAlways),
|
||||
K: a.Skip,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a Jump) String() string {
|
||||
return fmt.Sprintf("ja %d", a.Skip)
|
||||
}
|
||||
|
||||
// JumpIf skips the following Skip instructions in the program if A
|
||||
// <Cond> Val is true.
|
||||
type JumpIf struct {
|
||||
Cond JumpTest
|
||||
Val uint32
|
||||
SkipTrue uint8
|
||||
SkipFalse uint8
|
||||
}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a JumpIf) Assemble() (RawInstruction, error) {
|
||||
return jumpToRaw(a.Cond, opOperandConstant, a.Val, a.SkipTrue, a.SkipFalse)
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a JumpIf) String() string {
|
||||
return jumpToString(a.Cond, fmt.Sprintf("#%d", a.Val), a.SkipTrue, a.SkipFalse)
|
||||
}
|
||||
|
||||
// JumpIfX skips the following Skip instructions in the program if A
|
||||
// <Cond> X is true.
|
||||
type JumpIfX struct {
|
||||
Cond JumpTest
|
||||
SkipTrue uint8
|
||||
SkipFalse uint8
|
||||
}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a JumpIfX) Assemble() (RawInstruction, error) {
|
||||
return jumpToRaw(a.Cond, opOperandX, 0, a.SkipTrue, a.SkipFalse)
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a JumpIfX) String() string {
|
||||
return jumpToString(a.Cond, "x", a.SkipTrue, a.SkipFalse)
|
||||
}
|
||||
|
||||
// jumpToRaw assembles a jump instruction into a RawInstruction
|
||||
func jumpToRaw(test JumpTest, operand opOperand, k uint32, skipTrue, skipFalse uint8) (RawInstruction, error) {
|
||||
var (
|
||||
cond jumpOp
|
||||
flip bool
|
||||
)
|
||||
switch test {
|
||||
case JumpEqual:
|
||||
cond = opJumpEqual
|
||||
case JumpNotEqual:
|
||||
cond, flip = opJumpEqual, true
|
||||
case JumpGreaterThan:
|
||||
cond = opJumpGT
|
||||
case JumpLessThan:
|
||||
cond, flip = opJumpGE, true
|
||||
case JumpGreaterOrEqual:
|
||||
cond = opJumpGE
|
||||
case JumpLessOrEqual:
|
||||
cond, flip = opJumpGT, true
|
||||
case JumpBitsSet:
|
||||
cond = opJumpSet
|
||||
case JumpBitsNotSet:
|
||||
cond, flip = opJumpSet, true
|
||||
default:
|
||||
return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", test)
|
||||
}
|
||||
jt, jf := skipTrue, skipFalse
|
||||
if flip {
|
||||
jt, jf = jf, jt
|
||||
}
|
||||
return RawInstruction{
|
||||
Op: opClsJump | uint16(cond) | uint16(operand),
|
||||
Jt: jt,
|
||||
Jf: jf,
|
||||
K: k,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// jumpToString converts a jump instruction to assembler notation
|
||||
func jumpToString(cond JumpTest, operand string, skipTrue, skipFalse uint8) string {
|
||||
switch cond {
|
||||
// K == A
|
||||
case JumpEqual:
|
||||
return conditionalJump(operand, skipTrue, skipFalse, "jeq", "jneq")
|
||||
// K != A
|
||||
case JumpNotEqual:
|
||||
return fmt.Sprintf("jneq %s,%d", operand, skipTrue)
|
||||
// K > A
|
||||
case JumpGreaterThan:
|
||||
return conditionalJump(operand, skipTrue, skipFalse, "jgt", "jle")
|
||||
// K < A
|
||||
case JumpLessThan:
|
||||
return fmt.Sprintf("jlt %s,%d", operand, skipTrue)
|
||||
// K >= A
|
||||
case JumpGreaterOrEqual:
|
||||
return conditionalJump(operand, skipTrue, skipFalse, "jge", "jlt")
|
||||
// K <= A
|
||||
case JumpLessOrEqual:
|
||||
return fmt.Sprintf("jle %s,%d", operand, skipTrue)
|
||||
// K & A != 0
|
||||
case JumpBitsSet:
|
||||
if skipFalse > 0 {
|
||||
return fmt.Sprintf("jset %s,%d,%d", operand, skipTrue, skipFalse)
|
||||
}
|
||||
return fmt.Sprintf("jset %s,%d", operand, skipTrue)
|
||||
// K & A == 0, there is no assembler instruction for JumpBitNotSet, use JumpBitSet and invert skips
|
||||
case JumpBitsNotSet:
|
||||
return jumpToString(JumpBitsSet, operand, skipFalse, skipTrue)
|
||||
default:
|
||||
return fmt.Sprintf("unknown JumpTest %#v", cond)
|
||||
}
|
||||
}
|
||||
|
||||
func conditionalJump(operand string, skipTrue, skipFalse uint8, positiveJump, negativeJump string) string {
|
||||
if skipTrue > 0 {
|
||||
if skipFalse > 0 {
|
||||
return fmt.Sprintf("%s %s,%d,%d", positiveJump, operand, skipTrue, skipFalse)
|
||||
}
|
||||
return fmt.Sprintf("%s %s,%d", positiveJump, operand, skipTrue)
|
||||
}
|
||||
return fmt.Sprintf("%s %s,%d", negativeJump, operand, skipFalse)
|
||||
}
|
||||
|
||||
// RetA exits the BPF program, returning the value of register A.
|
||||
type RetA struct{}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a RetA) Assemble() (RawInstruction, error) {
|
||||
return RawInstruction{
|
||||
Op: opClsReturn | opRetSrcA,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a RetA) String() string {
|
||||
return fmt.Sprintf("ret a")
|
||||
}
|
||||
|
||||
// RetConstant exits the BPF program, returning a constant value.
|
||||
type RetConstant struct {
|
||||
Val uint32
|
||||
}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a RetConstant) Assemble() (RawInstruction, error) {
|
||||
return RawInstruction{
|
||||
Op: opClsReturn | opRetSrcConstant,
|
||||
K: a.Val,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a RetConstant) String() string {
|
||||
return fmt.Sprintf("ret #%d", a.Val)
|
||||
}
|
||||
|
||||
// TXA copies the value of register X to register A.
|
||||
type TXA struct{}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a TXA) Assemble() (RawInstruction, error) {
|
||||
return RawInstruction{
|
||||
Op: opClsMisc | opMiscTXA,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a TXA) String() string {
|
||||
return fmt.Sprintf("txa")
|
||||
}
|
||||
|
||||
// TAX copies the value of register A to register X.
|
||||
type TAX struct{}
|
||||
|
||||
// Assemble implements the Instruction Assemble method.
|
||||
func (a TAX) Assemble() (RawInstruction, error) {
|
||||
return RawInstruction{
|
||||
Op: opClsMisc | opMiscTAX,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
func (a TAX) String() string {
|
||||
return fmt.Sprintf("tax")
|
||||
}
|
||||
|
||||
func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) {
|
||||
var (
|
||||
cls uint16
|
||||
sz uint16
|
||||
)
|
||||
switch dst {
|
||||
case RegA:
|
||||
cls = opClsLoadA
|
||||
case RegX:
|
||||
cls = opClsLoadX
|
||||
default:
|
||||
return RawInstruction{}, fmt.Errorf("invalid target register %v", dst)
|
||||
}
|
||||
switch loadSize {
|
||||
case 1:
|
||||
sz = opLoadWidth1
|
||||
case 2:
|
||||
sz = opLoadWidth2
|
||||
case 4:
|
||||
sz = opLoadWidth4
|
||||
default:
|
||||
return RawInstruction{}, fmt.Errorf("invalid load byte length %d", sz)
|
||||
}
|
||||
return RawInstruction{
|
||||
Op: cls | sz | mode,
|
||||
K: k,
|
||||
}, nil
|
||||
}
|
10
vendor/golang.org/x/net/bpf/setter.go
generated
vendored
Normal file
10
vendor/golang.org/x/net/bpf/setter.go
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
package bpf
|
||||
|
||||
// A Setter is a type which can attach a compiled BPF filter to itself.
|
||||
type Setter interface {
|
||||
SetBPF(filter []RawInstruction) error
|
||||
}
|
150
vendor/golang.org/x/net/bpf/vm.go
generated
vendored
Normal file
150
vendor/golang.org/x/net/bpf/vm.go
generated
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bpf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// A VM is an emulated BPF virtual machine.
|
||||
type VM struct {
|
||||
filter []Instruction
|
||||
}
|
||||
|
||||
// NewVM returns a new VM using the input BPF program.
|
||||
func NewVM(filter []Instruction) (*VM, error) {
|
||||
if len(filter) == 0 {
|
||||
return nil, errors.New("one or more Instructions must be specified")
|
||||
}
|
||||
|
||||
for i, ins := range filter {
|
||||
check := len(filter) - (i + 1)
|
||||
switch ins := ins.(type) {
|
||||
// Check for out-of-bounds jumps in instructions
|
||||
case Jump:
|
||||
if check <= int(ins.Skip) {
|
||||
return nil, fmt.Errorf("cannot jump %d instructions; jumping past program bounds", ins.Skip)
|
||||
}
|
||||
case JumpIf:
|
||||
if check <= int(ins.SkipTrue) {
|
||||
return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue)
|
||||
}
|
||||
if check <= int(ins.SkipFalse) {
|
||||
return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
|
||||
}
|
||||
case JumpIfX:
|
||||
if check <= int(ins.SkipTrue) {
|
||||
return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue)
|
||||
}
|
||||
if check <= int(ins.SkipFalse) {
|
||||
return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
|
||||
}
|
||||
// Check for division or modulus by zero
|
||||
case ALUOpConstant:
|
||||
if ins.Val != 0 {
|
||||
break
|
||||
}
|
||||
|
||||
switch ins.Op {
|
||||
case ALUOpDiv, ALUOpMod:
|
||||
return nil, errors.New("cannot divide by zero using ALUOpConstant")
|
||||
}
|
||||
// Check for unknown extensions
|
||||
case LoadExtension:
|
||||
switch ins.Num {
|
||||
case ExtLen:
|
||||
default:
|
||||
return nil, fmt.Errorf("extension %d not implemented", ins.Num)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure last instruction is a return instruction
|
||||
switch filter[len(filter)-1].(type) {
|
||||
case RetA, RetConstant:
|
||||
default:
|
||||
return nil, errors.New("BPF program must end with RetA or RetConstant")
|
||||
}
|
||||
|
||||
// Though our VM works using disassembled instructions, we
|
||||
// attempt to assemble the input filter anyway to ensure it is compatible
|
||||
// with an operating system VM.
|
||||
_, err := Assemble(filter)
|
||||
|
||||
return &VM{
|
||||
filter: filter,
|
||||
}, err
|
||||
}
|
||||
|
||||
// Run runs the VM's BPF program against the input bytes.
|
||||
// Run returns the number of bytes accepted by the BPF program, and any errors
|
||||
// which occurred while processing the program.
|
||||
func (v *VM) Run(in []byte) (int, error) {
|
||||
var (
|
||||
// Registers of the virtual machine
|
||||
regA uint32
|
||||
regX uint32
|
||||
regScratch [16]uint32
|
||||
|
||||
// OK is true if the program should continue processing the next
|
||||
// instruction, or false if not, causing the loop to break
|
||||
ok = true
|
||||
)
|
||||
|
||||
// TODO(mdlayher): implement:
|
||||
// - NegateA:
|
||||
// - would require a change from uint32 registers to int32
|
||||
// registers
|
||||
|
||||
// TODO(mdlayher): add interop tests that check signedness of ALU
|
||||
// operations against kernel implementation, and make sure Go
|
||||
// implementation matches behavior
|
||||
|
||||
for i := 0; i < len(v.filter) && ok; i++ {
|
||||
ins := v.filter[i]
|
||||
|
||||
switch ins := ins.(type) {
|
||||
case ALUOpConstant:
|
||||
regA = aluOpConstant(ins, regA)
|
||||
case ALUOpX:
|
||||
regA, ok = aluOpX(ins, regA, regX)
|
||||
case Jump:
|
||||
i += int(ins.Skip)
|
||||
case JumpIf:
|
||||
jump := jumpIf(ins, regA)
|
||||
i += jump
|
||||
case JumpIfX:
|
||||
jump := jumpIfX(ins, regA, regX)
|
||||
i += jump
|
||||
case LoadAbsolute:
|
||||
regA, ok = loadAbsolute(ins, in)
|
||||
case LoadConstant:
|
||||
regA, regX = loadConstant(ins, regA, regX)
|
||||
case LoadExtension:
|
||||
regA = loadExtension(ins, in)
|
||||
case LoadIndirect:
|
||||
regA, ok = loadIndirect(ins, in, regX)
|
||||
case LoadMemShift:
|
||||
regX, ok = loadMemShift(ins, in)
|
||||
case LoadScratch:
|
||||
regA, regX = loadScratch(ins, regScratch, regA, regX)
|
||||
case RetA:
|
||||
return int(regA), nil
|
||||
case RetConstant:
|
||||
return int(ins.Val), nil
|
||||
case StoreScratch:
|
||||
regScratch = storeScratch(ins, regScratch, regA, regX)
|
||||
case TAX:
|
||||
regX = regA
|
||||
case TXA:
|
||||
regA = regX
|
||||
default:
|
||||
return 0, fmt.Errorf("unknown Instruction at index %d: %T", i, ins)
|
||||
}
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
182
vendor/golang.org/x/net/bpf/vm_instructions.go
generated
vendored
Normal file
182
vendor/golang.org/x/net/bpf/vm_instructions.go
generated
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bpf
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func aluOpConstant(ins ALUOpConstant, regA uint32) uint32 {
|
||||
return aluOpCommon(ins.Op, regA, ins.Val)
|
||||
}
|
||||
|
||||
func aluOpX(ins ALUOpX, regA uint32, regX uint32) (uint32, bool) {
|
||||
// Guard against division or modulus by zero by terminating
|
||||
// the program, as the OS BPF VM does
|
||||
if regX == 0 {
|
||||
switch ins.Op {
|
||||
case ALUOpDiv, ALUOpMod:
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
|
||||
return aluOpCommon(ins.Op, regA, regX), true
|
||||
}
|
||||
|
||||
func aluOpCommon(op ALUOp, regA uint32, value uint32) uint32 {
|
||||
switch op {
|
||||
case ALUOpAdd:
|
||||
return regA + value
|
||||
case ALUOpSub:
|
||||
return regA - value
|
||||
case ALUOpMul:
|
||||
return regA * value
|
||||
case ALUOpDiv:
|
||||
// Division by zero not permitted by NewVM and aluOpX checks
|
||||
return regA / value
|
||||
case ALUOpOr:
|
||||
return regA | value
|
||||
case ALUOpAnd:
|
||||
return regA & value
|
||||
case ALUOpShiftLeft:
|
||||
return regA << value
|
||||
case ALUOpShiftRight:
|
||||
return regA >> value
|
||||
case ALUOpMod:
|
||||
// Modulus by zero not permitted by NewVM and aluOpX checks
|
||||
return regA % value
|
||||
case ALUOpXor:
|
||||
return regA ^ value
|
||||
default:
|
||||
return regA
|
||||
}
|
||||
}
|
||||
|
||||
func jumpIf(ins JumpIf, regA uint32) int {
|
||||
return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, ins.Val)
|
||||
}
|
||||
|
||||
func jumpIfX(ins JumpIfX, regA uint32, regX uint32) int {
|
||||
return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, regX)
|
||||
}
|
||||
|
||||
func jumpIfCommon(cond JumpTest, skipTrue, skipFalse uint8, regA uint32, value uint32) int {
|
||||
var ok bool
|
||||
|
||||
switch cond {
|
||||
case JumpEqual:
|
||||
ok = regA == value
|
||||
case JumpNotEqual:
|
||||
ok = regA != value
|
||||
case JumpGreaterThan:
|
||||
ok = regA > value
|
||||
case JumpLessThan:
|
||||
ok = regA < value
|
||||
case JumpGreaterOrEqual:
|
||||
ok = regA >= value
|
||||
case JumpLessOrEqual:
|
||||
ok = regA <= value
|
||||
case JumpBitsSet:
|
||||
ok = (regA & value) != 0
|
||||
case JumpBitsNotSet:
|
||||
ok = (regA & value) == 0
|
||||
}
|
||||
|
||||
if ok {
|
||||
return int(skipTrue)
|
||||
}
|
||||
|
||||
return int(skipFalse)
|
||||
}
|
||||
|
||||
func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) {
|
||||
offset := int(ins.Off)
|
||||
size := int(ins.Size)
|
||||
|
||||
return loadCommon(in, offset, size)
|
||||
}
|
||||
|
||||
func loadConstant(ins LoadConstant, regA uint32, regX uint32) (uint32, uint32) {
|
||||
switch ins.Dst {
|
||||
case RegA:
|
||||
regA = ins.Val
|
||||
case RegX:
|
||||
regX = ins.Val
|
||||
}
|
||||
|
||||
return regA, regX
|
||||
}
|
||||
|
||||
func loadExtension(ins LoadExtension, in []byte) uint32 {
|
||||
switch ins.Num {
|
||||
case ExtLen:
|
||||
return uint32(len(in))
|
||||
default:
|
||||
panic(fmt.Sprintf("unimplemented extension: %d", ins.Num))
|
||||
}
|
||||
}
|
||||
|
||||
func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) {
|
||||
offset := int(ins.Off) + int(regX)
|
||||
size := int(ins.Size)
|
||||
|
||||
return loadCommon(in, offset, size)
|
||||
}
|
||||
|
||||
func loadMemShift(ins LoadMemShift, in []byte) (uint32, bool) {
|
||||
offset := int(ins.Off)
|
||||
|
||||
// Size of LoadMemShift is always 1 byte
|
||||
if !inBounds(len(in), offset, 1) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Mask off high 4 bits and multiply low 4 bits by 4
|
||||
return uint32(in[offset]&0x0f) * 4, true
|
||||
}
|
||||
|
||||
func inBounds(inLen int, offset int, size int) bool {
|
||||
return offset+size <= inLen
|
||||
}
|
||||
|
||||
func loadCommon(in []byte, offset int, size int) (uint32, bool) {
|
||||
if !inBounds(len(in), offset, size) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
switch size {
|
||||
case 1:
|
||||
return uint32(in[offset]), true
|
||||
case 2:
|
||||
return uint32(binary.BigEndian.Uint16(in[offset : offset+size])), true
|
||||
case 4:
|
||||
return uint32(binary.BigEndian.Uint32(in[offset : offset+size])), true
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid load size: %d", size))
|
||||
}
|
||||
}
|
||||
|
||||
func loadScratch(ins LoadScratch, regScratch [16]uint32, regA uint32, regX uint32) (uint32, uint32) {
|
||||
switch ins.Dst {
|
||||
case RegA:
|
||||
regA = regScratch[ins.N]
|
||||
case RegX:
|
||||
regX = regScratch[ins.N]
|
||||
}
|
||||
|
||||
return regA, regX
|
||||
}
|
||||
|
||||
func storeScratch(ins StoreScratch, regScratch [16]uint32, regA uint32, regX uint32) [16]uint32 {
|
||||
switch ins.Src {
|
||||
case RegA:
|
||||
regScratch[ins.N] = regA
|
||||
case RegX:
|
||||
regScratch[ins.N] = regX
|
||||
}
|
||||
|
||||
return regScratch
|
||||
}
|
81
vendor/golang.org/x/net/http2/client_conn_pool.go
generated
vendored
81
vendor/golang.org/x/net/http2/client_conn_pool.go
generated
vendored
@ -7,7 +7,9 @@
|
||||
package http2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
@ -78,61 +80,69 @@ func (p *clientConnPool) getClientConn(req *http.Request, addr string, dialOnMis
|
||||
// It gets its own connection.
|
||||
traceGetConn(req, addr)
|
||||
const singleUse = true
|
||||
cc, err := p.t.dialClientConn(addr, singleUse)
|
||||
cc, err := p.t.dialClientConn(req.Context(), addr, singleUse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cc, nil
|
||||
}
|
||||
p.mu.Lock()
|
||||
for _, cc := range p.conns[addr] {
|
||||
if st := cc.idleState(); st.canTakeNewRequest {
|
||||
if p.shouldTraceGetConn(st) {
|
||||
traceGetConn(req, addr)
|
||||
for {
|
||||
p.mu.Lock()
|
||||
for _, cc := range p.conns[addr] {
|
||||
if st := cc.idleState(); st.canTakeNewRequest {
|
||||
if p.shouldTraceGetConn(st) {
|
||||
traceGetConn(req, addr)
|
||||
}
|
||||
p.mu.Unlock()
|
||||
return cc, nil
|
||||
}
|
||||
p.mu.Unlock()
|
||||
return cc, nil
|
||||
}
|
||||
}
|
||||
if !dialOnMiss {
|
||||
if !dialOnMiss {
|
||||
p.mu.Unlock()
|
||||
return nil, ErrNoCachedConn
|
||||
}
|
||||
traceGetConn(req, addr)
|
||||
call := p.getStartDialLocked(req.Context(), addr)
|
||||
p.mu.Unlock()
|
||||
return nil, ErrNoCachedConn
|
||||
<-call.done
|
||||
if shouldRetryDial(call, req) {
|
||||
continue
|
||||
}
|
||||
return call.res, call.err
|
||||
}
|
||||
traceGetConn(req, addr)
|
||||
call := p.getStartDialLocked(addr)
|
||||
p.mu.Unlock()
|
||||
<-call.done
|
||||
return call.res, call.err
|
||||
}
|
||||
|
||||
// dialCall is an in-flight Transport dial call to a host.
|
||||
type dialCall struct {
|
||||
_ incomparable
|
||||
p *clientConnPool
|
||||
_ incomparable
|
||||
p *clientConnPool
|
||||
// the context associated with the request
|
||||
// that created this dialCall
|
||||
ctx context.Context
|
||||
done chan struct{} // closed when done
|
||||
res *ClientConn // valid after done is closed
|
||||
err error // valid after done is closed
|
||||
}
|
||||
|
||||
// requires p.mu is held.
|
||||
func (p *clientConnPool) getStartDialLocked(addr string) *dialCall {
|
||||
func (p *clientConnPool) getStartDialLocked(ctx context.Context, addr string) *dialCall {
|
||||
if call, ok := p.dialing[addr]; ok {
|
||||
// A dial is already in-flight. Don't start another.
|
||||
return call
|
||||
}
|
||||
call := &dialCall{p: p, done: make(chan struct{})}
|
||||
call := &dialCall{p: p, done: make(chan struct{}), ctx: ctx}
|
||||
if p.dialing == nil {
|
||||
p.dialing = make(map[string]*dialCall)
|
||||
}
|
||||
p.dialing[addr] = call
|
||||
go call.dial(addr)
|
||||
go call.dial(call.ctx, addr)
|
||||
return call
|
||||
}
|
||||
|
||||
// run in its own goroutine.
|
||||
func (c *dialCall) dial(addr string) {
|
||||
func (c *dialCall) dial(ctx context.Context, addr string) {
|
||||
const singleUse = false // shared conn
|
||||
c.res, c.err = c.p.t.dialClientConn(addr, singleUse)
|
||||
c.res, c.err = c.p.t.dialClientConn(ctx, addr, singleUse)
|
||||
close(c.done)
|
||||
|
||||
c.p.mu.Lock()
|
||||
@ -276,3 +286,28 @@ type noDialClientConnPool struct{ *clientConnPool }
|
||||
func (p noDialClientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) {
|
||||
return p.getClientConn(req, addr, noDialOnMiss)
|
||||
}
|
||||
|
||||
// shouldRetryDial reports whether the current request should
|
||||
// retry dialing after the call finished unsuccessfully, for example
|
||||
// if the dial was canceled because of a context cancellation or
|
||||
// deadline expiry.
|
||||
func shouldRetryDial(call *dialCall, req *http.Request) bool {
|
||||
if call.err == nil {
|
||||
// No error, no need to retry
|
||||
return false
|
||||
}
|
||||
if call.ctx == req.Context() {
|
||||
// If the call has the same context as the request, the dial
|
||||
// should not be retried, since any cancellation will have come
|
||||
// from this request.
|
||||
return false
|
||||
}
|
||||
if !errors.Is(call.err, context.Canceled) && !errors.Is(call.err, context.DeadlineExceeded) {
|
||||
// If the call error is not because of a context cancellation or a deadline expiry,
|
||||
// the dial should not be retried.
|
||||
return false
|
||||
}
|
||||
// Only retry if the error is a context cancellation error or deadline expiry
|
||||
// and the context associated with the call was canceled or expired.
|
||||
return call.ctx.Err() != nil
|
||||
}
|
||||
|
42
vendor/golang.org/x/net/http2/transport.go
generated
vendored
42
vendor/golang.org/x/net/http2/transport.go
generated
vendored
@ -564,12 +564,12 @@ func canRetryError(err error) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *Transport) dialClientConn(addr string, singleUse bool) (*ClientConn, error) {
|
||||
func (t *Transport) dialClientConn(ctx context.Context, addr string, singleUse bool) (*ClientConn, error) {
|
||||
host, _, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tconn, err := t.dialTLS()("tcp", addr, t.newTLSConfig(host))
|
||||
tconn, err := t.dialTLS(ctx)("tcp", addr, t.newTLSConfig(host))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -590,34 +590,28 @@ func (t *Transport) newTLSConfig(host string) *tls.Config {
|
||||
return cfg
|
||||
}
|
||||
|
||||
func (t *Transport) dialTLS() func(string, string, *tls.Config) (net.Conn, error) {
|
||||
func (t *Transport) dialTLS(ctx context.Context) func(string, string, *tls.Config) (net.Conn, error) {
|
||||
if t.DialTLS != nil {
|
||||
return t.DialTLS
|
||||
}
|
||||
return t.dialTLSDefault
|
||||
}
|
||||
|
||||
func (t *Transport) dialTLSDefault(network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||
cn, err := tls.Dial(network, addr, cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := cn.Handshake(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !cfg.InsecureSkipVerify {
|
||||
if err := cn.VerifyHostname(cfg.ServerName); err != nil {
|
||||
return func(network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||
dialer := &tls.Dialer{
|
||||
Config: cfg,
|
||||
}
|
||||
cn, err := dialer.DialContext(ctx, network, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsCn := cn.(*tls.Conn) // DialContext comment promises this will always succeed
|
||||
state := tlsCn.ConnectionState()
|
||||
if p := state.NegotiatedProtocol; p != NextProtoTLS {
|
||||
return nil, fmt.Errorf("http2: unexpected ALPN protocol %q; want %q", p, NextProtoTLS)
|
||||
}
|
||||
if !state.NegotiatedProtocolIsMutual {
|
||||
return nil, errors.New("http2: could not negotiate protocol mutually")
|
||||
}
|
||||
return cn, nil
|
||||
}
|
||||
state := cn.ConnectionState()
|
||||
if p := state.NegotiatedProtocol; p != NextProtoTLS {
|
||||
return nil, fmt.Errorf("http2: unexpected ALPN protocol %q; want %q", p, NextProtoTLS)
|
||||
}
|
||||
if !state.NegotiatedProtocolIsMutual {
|
||||
return nil, errors.New("http2: could not negotiate protocol mutually")
|
||||
}
|
||||
return cn, nil
|
||||
}
|
||||
|
||||
// disableKeepAlives reports whether connections should be closed as
|
||||
|
113
vendor/golang.org/x/net/idna/idna10.0.0.go
generated
vendored
113
vendor/golang.org/x/net/idna/idna10.0.0.go
generated
vendored
@ -67,15 +67,14 @@ func Transitional(transitional bool) Option {
|
||||
|
||||
// VerifyDNSLength sets whether a Profile should fail if any of the IDN parts
|
||||
// are longer than allowed by the RFC.
|
||||
//
|
||||
// This option corresponds to the VerifyDnsLength flag in UTS #46.
|
||||
func VerifyDNSLength(verify bool) Option {
|
||||
return func(o *options) { o.verifyDNSLength = verify }
|
||||
}
|
||||
|
||||
// RemoveLeadingDots removes leading label separators. Leading runes that map to
|
||||
// dots, such as U+3002 IDEOGRAPHIC FULL STOP, are removed as well.
|
||||
//
|
||||
// This is the behavior suggested by the UTS #46 and is adopted by some
|
||||
// browsers.
|
||||
func RemoveLeadingDots(remove bool) Option {
|
||||
return func(o *options) { o.removeLeadingDots = remove }
|
||||
}
|
||||
@ -83,6 +82,8 @@ func RemoveLeadingDots(remove bool) Option {
|
||||
// ValidateLabels sets whether to check the mandatory label validation criteria
|
||||
// as defined in Section 5.4 of RFC 5891. This includes testing for correct use
|
||||
// of hyphens ('-'), normalization, validity of runes, and the context rules.
|
||||
// In particular, ValidateLabels also sets the CheckHyphens and CheckJoiners flags
|
||||
// in UTS #46.
|
||||
func ValidateLabels(enable bool) Option {
|
||||
return func(o *options) {
|
||||
// Don't override existing mappings, but set one that at least checks
|
||||
@ -91,25 +92,48 @@ func ValidateLabels(enable bool) Option {
|
||||
o.mapping = normalize
|
||||
}
|
||||
o.trie = trie
|
||||
o.validateLabels = enable
|
||||
o.fromPuny = validateFromPunycode
|
||||
o.checkJoiners = enable
|
||||
o.checkHyphens = enable
|
||||
if enable {
|
||||
o.fromPuny = validateFromPunycode
|
||||
} else {
|
||||
o.fromPuny = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CheckHyphens sets whether to check for correct use of hyphens ('-') in
|
||||
// labels. Most web browsers do not have this option set, since labels such as
|
||||
// "r3---sn-apo3qvuoxuxbt-j5pe" are in common use.
|
||||
//
|
||||
// This option corresponds to the CheckHyphens flag in UTS #46.
|
||||
func CheckHyphens(enable bool) Option {
|
||||
return func(o *options) { o.checkHyphens = enable }
|
||||
}
|
||||
|
||||
// CheckJoiners sets whether to check the ContextJ rules as defined in Appendix
|
||||
// A of RFC 5892, concerning the use of joiner runes.
|
||||
//
|
||||
// This option corresponds to the CheckJoiners flag in UTS #46.
|
||||
func CheckJoiners(enable bool) Option {
|
||||
return func(o *options) {
|
||||
o.trie = trie
|
||||
o.checkJoiners = enable
|
||||
}
|
||||
}
|
||||
|
||||
// StrictDomainName limits the set of permissible ASCII characters to those
|
||||
// allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the
|
||||
// hyphen). This is set by default for MapForLookup and ValidateForRegistration.
|
||||
// hyphen). This is set by default for MapForLookup and ValidateForRegistration,
|
||||
// but is only useful if ValidateLabels is set.
|
||||
//
|
||||
// This option is useful, for instance, for browsers that allow characters
|
||||
// outside this range, for example a '_' (U+005F LOW LINE). See
|
||||
// http://www.rfc-editor.org/std/std3.txt for more details This option
|
||||
// corresponds to the UseSTD3ASCIIRules option in UTS #46.
|
||||
// http://www.rfc-editor.org/std/std3.txt for more details.
|
||||
//
|
||||
// This option corresponds to the UseSTD3ASCIIRules flag in UTS #46.
|
||||
func StrictDomainName(use bool) Option {
|
||||
return func(o *options) {
|
||||
o.trie = trie
|
||||
o.useSTD3Rules = use
|
||||
o.fromPuny = validateFromPunycode
|
||||
}
|
||||
return func(o *options) { o.useSTD3Rules = use }
|
||||
}
|
||||
|
||||
// NOTE: the following options pull in tables. The tables should not be linked
|
||||
@ -117,6 +141,8 @@ func StrictDomainName(use bool) Option {
|
||||
|
||||
// BidiRule enables the Bidi rule as defined in RFC 5893. Any application
|
||||
// that relies on proper validation of labels should include this rule.
|
||||
//
|
||||
// This option corresponds to the CheckBidi flag in UTS #46.
|
||||
func BidiRule() Option {
|
||||
return func(o *options) { o.bidirule = bidirule.ValidString }
|
||||
}
|
||||
@ -152,7 +178,8 @@ func MapForLookup() Option {
|
||||
type options struct {
|
||||
transitional bool
|
||||
useSTD3Rules bool
|
||||
validateLabels bool
|
||||
checkHyphens bool
|
||||
checkJoiners bool
|
||||
verifyDNSLength bool
|
||||
removeLeadingDots bool
|
||||
|
||||
@ -225,8 +252,11 @@ func (p *Profile) String() string {
|
||||
if p.useSTD3Rules {
|
||||
s += ":UseSTD3Rules"
|
||||
}
|
||||
if p.validateLabels {
|
||||
s += ":ValidateLabels"
|
||||
if p.checkHyphens {
|
||||
s += ":CheckHyphens"
|
||||
}
|
||||
if p.checkJoiners {
|
||||
s += ":CheckJoiners"
|
||||
}
|
||||
if p.verifyDNSLength {
|
||||
s += ":VerifyDNSLength"
|
||||
@ -254,26 +284,29 @@ var (
|
||||
|
||||
punycode = &Profile{}
|
||||
lookup = &Profile{options{
|
||||
transitional: true,
|
||||
useSTD3Rules: true,
|
||||
validateLabels: true,
|
||||
trie: trie,
|
||||
fromPuny: validateFromPunycode,
|
||||
mapping: validateAndMap,
|
||||
bidirule: bidirule.ValidString,
|
||||
transitional: true,
|
||||
useSTD3Rules: true,
|
||||
checkHyphens: true,
|
||||
checkJoiners: true,
|
||||
trie: trie,
|
||||
fromPuny: validateFromPunycode,
|
||||
mapping: validateAndMap,
|
||||
bidirule: bidirule.ValidString,
|
||||
}}
|
||||
display = &Profile{options{
|
||||
useSTD3Rules: true,
|
||||
validateLabels: true,
|
||||
trie: trie,
|
||||
fromPuny: validateFromPunycode,
|
||||
mapping: validateAndMap,
|
||||
bidirule: bidirule.ValidString,
|
||||
useSTD3Rules: true,
|
||||
checkHyphens: true,
|
||||
checkJoiners: true,
|
||||
trie: trie,
|
||||
fromPuny: validateFromPunycode,
|
||||
mapping: validateAndMap,
|
||||
bidirule: bidirule.ValidString,
|
||||
}}
|
||||
registration = &Profile{options{
|
||||
useSTD3Rules: true,
|
||||
validateLabels: true,
|
||||
verifyDNSLength: true,
|
||||
checkHyphens: true,
|
||||
checkJoiners: true,
|
||||
trie: trie,
|
||||
fromPuny: validateFromPunycode,
|
||||
mapping: validateRegistration,
|
||||
@ -340,7 +373,7 @@ func (p *Profile) process(s string, toASCII bool) (string, error) {
|
||||
}
|
||||
isBidi = isBidi || bidirule.DirectionString(u) != bidi.LeftToRight
|
||||
labels.set(u)
|
||||
if err == nil && p.validateLabels {
|
||||
if err == nil && p.fromPuny != nil {
|
||||
err = p.fromPuny(p, u)
|
||||
}
|
||||
if err == nil {
|
||||
@ -681,16 +714,18 @@ func (p *Profile) validateLabel(s string) (err error) {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if !p.validateLabels {
|
||||
if p.checkHyphens {
|
||||
if len(s) > 4 && s[2] == '-' && s[3] == '-' {
|
||||
return &labelError{s, "V2"}
|
||||
}
|
||||
if s[0] == '-' || s[len(s)-1] == '-' {
|
||||
return &labelError{s, "V3"}
|
||||
}
|
||||
}
|
||||
if !p.checkJoiners {
|
||||
return nil
|
||||
}
|
||||
trie := p.trie // p.validateLabels is only set if trie is set.
|
||||
if len(s) > 4 && s[2] == '-' && s[3] == '-' {
|
||||
return &labelError{s, "V2"}
|
||||
}
|
||||
if s[0] == '-' || s[len(s)-1] == '-' {
|
||||
return &labelError{s, "V3"}
|
||||
}
|
||||
trie := p.trie // p.checkJoiners is only set if trie is set.
|
||||
// TODO: merge the use of this in the trie.
|
||||
v, sz := trie.lookupString(s)
|
||||
x := info(v)
|
||||
|
93
vendor/golang.org/x/net/idna/idna9.0.0.go
generated
vendored
93
vendor/golang.org/x/net/idna/idna9.0.0.go
generated
vendored
@ -66,15 +66,14 @@ func Transitional(transitional bool) Option {
|
||||
|
||||
// VerifyDNSLength sets whether a Profile should fail if any of the IDN parts
|
||||
// are longer than allowed by the RFC.
|
||||
//
|
||||
// This option corresponds to the VerifyDnsLength flag in UTS #46.
|
||||
func VerifyDNSLength(verify bool) Option {
|
||||
return func(o *options) { o.verifyDNSLength = verify }
|
||||
}
|
||||
|
||||
// RemoveLeadingDots removes leading label separators. Leading runes that map to
|
||||
// dots, such as U+3002 IDEOGRAPHIC FULL STOP, are removed as well.
|
||||
//
|
||||
// This is the behavior suggested by the UTS #46 and is adopted by some
|
||||
// browsers.
|
||||
func RemoveLeadingDots(remove bool) Option {
|
||||
return func(o *options) { o.removeLeadingDots = remove }
|
||||
}
|
||||
@ -82,6 +81,8 @@ func RemoveLeadingDots(remove bool) Option {
|
||||
// ValidateLabels sets whether to check the mandatory label validation criteria
|
||||
// as defined in Section 5.4 of RFC 5891. This includes testing for correct use
|
||||
// of hyphens ('-'), normalization, validity of runes, and the context rules.
|
||||
// In particular, ValidateLabels also sets the CheckHyphens and CheckJoiners flags
|
||||
// in UTS #46.
|
||||
func ValidateLabels(enable bool) Option {
|
||||
return func(o *options) {
|
||||
// Don't override existing mappings, but set one that at least checks
|
||||
@ -90,25 +91,48 @@ func ValidateLabels(enable bool) Option {
|
||||
o.mapping = normalize
|
||||
}
|
||||
o.trie = trie
|
||||
o.validateLabels = enable
|
||||
o.fromPuny = validateFromPunycode
|
||||
o.checkJoiners = enable
|
||||
o.checkHyphens = enable
|
||||
if enable {
|
||||
o.fromPuny = validateFromPunycode
|
||||
} else {
|
||||
o.fromPuny = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CheckHyphens sets whether to check for correct use of hyphens ('-') in
|
||||
// labels. Most web browsers do not have this option set, since labels such as
|
||||
// "r3---sn-apo3qvuoxuxbt-j5pe" are in common use.
|
||||
//
|
||||
// This option corresponds to the CheckHyphens flag in UTS #46.
|
||||
func CheckHyphens(enable bool) Option {
|
||||
return func(o *options) { o.checkHyphens = enable }
|
||||
}
|
||||
|
||||
// CheckJoiners sets whether to check the ContextJ rules as defined in Appendix
|
||||
// A of RFC 5892, concerning the use of joiner runes.
|
||||
//
|
||||
// This option corresponds to the CheckJoiners flag in UTS #46.
|
||||
func CheckJoiners(enable bool) Option {
|
||||
return func(o *options) {
|
||||
o.trie = trie
|
||||
o.checkJoiners = enable
|
||||
}
|
||||
}
|
||||
|
||||
// StrictDomainName limits the set of permissable ASCII characters to those
|
||||
// allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the
|
||||
// hyphen). This is set by default for MapForLookup and ValidateForRegistration.
|
||||
// hyphen). This is set by default for MapForLookup and ValidateForRegistration,
|
||||
// but is only useful if ValidateLabels is set.
|
||||
//
|
||||
// This option is useful, for instance, for browsers that allow characters
|
||||
// outside this range, for example a '_' (U+005F LOW LINE). See
|
||||
// http://www.rfc-editor.org/std/std3.txt for more details This option
|
||||
// corresponds to the UseSTD3ASCIIRules option in UTS #46.
|
||||
// http://www.rfc-editor.org/std/std3.txt for more details.
|
||||
//
|
||||
// This option corresponds to the UseSTD3ASCIIRules flag in UTS #46.
|
||||
func StrictDomainName(use bool) Option {
|
||||
return func(o *options) {
|
||||
o.trie = trie
|
||||
o.useSTD3Rules = use
|
||||
o.fromPuny = validateFromPunycode
|
||||
}
|
||||
return func(o *options) { o.useSTD3Rules = use }
|
||||
}
|
||||
|
||||
// NOTE: the following options pull in tables. The tables should not be linked
|
||||
@ -116,6 +140,8 @@ func StrictDomainName(use bool) Option {
|
||||
|
||||
// BidiRule enables the Bidi rule as defined in RFC 5893. Any application
|
||||
// that relies on proper validation of labels should include this rule.
|
||||
//
|
||||
// This option corresponds to the CheckBidi flag in UTS #46.
|
||||
func BidiRule() Option {
|
||||
return func(o *options) { o.bidirule = bidirule.ValidString }
|
||||
}
|
||||
@ -152,7 +178,8 @@ func MapForLookup() Option {
|
||||
type options struct {
|
||||
transitional bool
|
||||
useSTD3Rules bool
|
||||
validateLabels bool
|
||||
checkHyphens bool
|
||||
checkJoiners bool
|
||||
verifyDNSLength bool
|
||||
removeLeadingDots bool
|
||||
|
||||
@ -225,8 +252,11 @@ func (p *Profile) String() string {
|
||||
if p.useSTD3Rules {
|
||||
s += ":UseSTD3Rules"
|
||||
}
|
||||
if p.validateLabels {
|
||||
s += ":ValidateLabels"
|
||||
if p.checkHyphens {
|
||||
s += ":CheckHyphens"
|
||||
}
|
||||
if p.checkJoiners {
|
||||
s += ":CheckJoiners"
|
||||
}
|
||||
if p.verifyDNSLength {
|
||||
s += ":VerifyDNSLength"
|
||||
@ -255,9 +285,10 @@ var (
|
||||
punycode = &Profile{}
|
||||
lookup = &Profile{options{
|
||||
transitional: true,
|
||||
useSTD3Rules: true,
|
||||
validateLabels: true,
|
||||
removeLeadingDots: true,
|
||||
useSTD3Rules: true,
|
||||
checkHyphens: true,
|
||||
checkJoiners: true,
|
||||
trie: trie,
|
||||
fromPuny: validateFromPunycode,
|
||||
mapping: validateAndMap,
|
||||
@ -265,8 +296,9 @@ var (
|
||||
}}
|
||||
display = &Profile{options{
|
||||
useSTD3Rules: true,
|
||||
validateLabels: true,
|
||||
removeLeadingDots: true,
|
||||
checkHyphens: true,
|
||||
checkJoiners: true,
|
||||
trie: trie,
|
||||
fromPuny: validateFromPunycode,
|
||||
mapping: validateAndMap,
|
||||
@ -274,8 +306,9 @@ var (
|
||||
}}
|
||||
registration = &Profile{options{
|
||||
useSTD3Rules: true,
|
||||
validateLabels: true,
|
||||
verifyDNSLength: true,
|
||||
checkHyphens: true,
|
||||
checkJoiners: true,
|
||||
trie: trie,
|
||||
fromPuny: validateFromPunycode,
|
||||
mapping: validateRegistration,
|
||||
@ -339,7 +372,7 @@ func (p *Profile) process(s string, toASCII bool) (string, error) {
|
||||
continue
|
||||
}
|
||||
labels.set(u)
|
||||
if err == nil && p.validateLabels {
|
||||
if err == nil && p.fromPuny != nil {
|
||||
err = p.fromPuny(p, u)
|
||||
}
|
||||
if err == nil {
|
||||
@ -629,16 +662,18 @@ func (p *Profile) validateLabel(s string) error {
|
||||
if p.bidirule != nil && !p.bidirule(s) {
|
||||
return &labelError{s, "B"}
|
||||
}
|
||||
if !p.validateLabels {
|
||||
if p.checkHyphens {
|
||||
if len(s) > 4 && s[2] == '-' && s[3] == '-' {
|
||||
return &labelError{s, "V2"}
|
||||
}
|
||||
if s[0] == '-' || s[len(s)-1] == '-' {
|
||||
return &labelError{s, "V3"}
|
||||
}
|
||||
}
|
||||
if !p.checkJoiners {
|
||||
return nil
|
||||
}
|
||||
trie := p.trie // p.validateLabels is only set if trie is set.
|
||||
if len(s) > 4 && s[2] == '-' && s[3] == '-' {
|
||||
return &labelError{s, "V2"}
|
||||
}
|
||||
if s[0] == '-' || s[len(s)-1] == '-' {
|
||||
return &labelError{s, "V3"}
|
||||
}
|
||||
trie := p.trie // p.checkJoiners is only set if trie is set.
|
||||
// TODO: merge the use of this in the trie.
|
||||
v, sz := trie.lookupString(s)
|
||||
x := info(v)
|
||||
|
17
vendor/golang.zx2c4.com/wireguard/LICENSE
generated
vendored
Normal file
17
vendor/golang.zx2c4.com/wireguard/LICENSE
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
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.
|
286
vendor/golang.zx2c4.com/wireguard/ipc/winpipe/file.go
generated
vendored
Normal file
286
vendor/golang.zx2c4.com/wireguard/ipc/winpipe/file.go
generated
vendored
Normal file
@ -0,0 +1,286 @@
|
||||
// +build windows
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2005 Microsoft
|
||||
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package winpipe
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type timeoutChan chan struct{}
|
||||
|
||||
var ioInitOnce sync.Once
|
||||
var ioCompletionPort windows.Handle
|
||||
|
||||
// ioResult contains the result of an asynchronous IO operation
|
||||
type ioResult struct {
|
||||
bytes uint32
|
||||
err error
|
||||
}
|
||||
|
||||
// ioOperation represents an outstanding asynchronous Win32 IO
|
||||
type ioOperation struct {
|
||||
o windows.Overlapped
|
||||
ch chan ioResult
|
||||
}
|
||||
|
||||
func initIo() {
|
||||
h, err := windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ioCompletionPort = h
|
||||
go ioCompletionProcessor(h)
|
||||
}
|
||||
|
||||
// file implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall.
|
||||
// It takes ownership of this handle and will close it if it is garbage collected.
|
||||
type file struct {
|
||||
handle windows.Handle
|
||||
wg sync.WaitGroup
|
||||
wgLock sync.RWMutex
|
||||
closing uint32 // used as atomic boolean
|
||||
socket bool
|
||||
readDeadline deadlineHandler
|
||||
writeDeadline deadlineHandler
|
||||
}
|
||||
|
||||
type deadlineHandler struct {
|
||||
setLock sync.Mutex
|
||||
channel timeoutChan
|
||||
channelLock sync.RWMutex
|
||||
timer *time.Timer
|
||||
timedout uint32 // used as atomic boolean
|
||||
}
|
||||
|
||||
// makeFile makes a new file from an existing file handle
|
||||
func makeFile(h windows.Handle) (*file, error) {
|
||||
f := &file{handle: h}
|
||||
ioInitOnce.Do(initIo)
|
||||
_, err := windows.CreateIoCompletionPort(h, ioCompletionPort, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = windows.SetFileCompletionNotificationModes(h, windows.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS|windows.FILE_SKIP_SET_EVENT_ON_HANDLE)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.readDeadline.channel = make(timeoutChan)
|
||||
f.writeDeadline.channel = make(timeoutChan)
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// closeHandle closes the resources associated with a Win32 handle
|
||||
func (f *file) closeHandle() {
|
||||
f.wgLock.Lock()
|
||||
// Atomically set that we are closing, releasing the resources only once.
|
||||
if atomic.SwapUint32(&f.closing, 1) == 0 {
|
||||
f.wgLock.Unlock()
|
||||
// cancel all IO and wait for it to complete
|
||||
windows.CancelIoEx(f.handle, nil)
|
||||
f.wg.Wait()
|
||||
// at this point, no new IO can start
|
||||
windows.Close(f.handle)
|
||||
f.handle = 0
|
||||
} else {
|
||||
f.wgLock.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// Close closes a file.
|
||||
func (f *file) Close() error {
|
||||
f.closeHandle()
|
||||
return nil
|
||||
}
|
||||
|
||||
// prepareIo prepares for a new IO operation.
|
||||
// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning.
|
||||
func (f *file) prepareIo() (*ioOperation, error) {
|
||||
f.wgLock.RLock()
|
||||
if atomic.LoadUint32(&f.closing) == 1 {
|
||||
f.wgLock.RUnlock()
|
||||
return nil, os.ErrClosed
|
||||
}
|
||||
f.wg.Add(1)
|
||||
f.wgLock.RUnlock()
|
||||
c := &ioOperation{}
|
||||
c.ch = make(chan ioResult)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// ioCompletionProcessor processes completed async IOs forever
|
||||
func ioCompletionProcessor(h windows.Handle) {
|
||||
for {
|
||||
var bytes uint32
|
||||
var key uintptr
|
||||
var op *ioOperation
|
||||
err := windows.GetQueuedCompletionStatus(h, &bytes, &key, (**windows.Overlapped)(unsafe.Pointer(&op)), windows.INFINITE)
|
||||
if op == nil {
|
||||
panic(err)
|
||||
}
|
||||
op.ch <- ioResult{bytes, err}
|
||||
}
|
||||
}
|
||||
|
||||
// asyncIo processes the return value from ReadFile or WriteFile, blocking until
|
||||
// the operation has actually completed.
|
||||
func (f *file) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) {
|
||||
if err != windows.ERROR_IO_PENDING {
|
||||
return int(bytes), err
|
||||
}
|
||||
|
||||
if atomic.LoadUint32(&f.closing) == 1 {
|
||||
windows.CancelIoEx(f.handle, &c.o)
|
||||
}
|
||||
|
||||
var timeout timeoutChan
|
||||
if d != nil {
|
||||
d.channelLock.Lock()
|
||||
timeout = d.channel
|
||||
d.channelLock.Unlock()
|
||||
}
|
||||
|
||||
var r ioResult
|
||||
select {
|
||||
case r = <-c.ch:
|
||||
err = r.err
|
||||
if err == windows.ERROR_OPERATION_ABORTED {
|
||||
if atomic.LoadUint32(&f.closing) == 1 {
|
||||
err = os.ErrClosed
|
||||
}
|
||||
} else if err != nil && f.socket {
|
||||
// err is from Win32. Query the overlapped structure to get the winsock error.
|
||||
var bytes, flags uint32
|
||||
err = windows.WSAGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags)
|
||||
}
|
||||
case <-timeout:
|
||||
windows.CancelIoEx(f.handle, &c.o)
|
||||
r = <-c.ch
|
||||
err = r.err
|
||||
if err == windows.ERROR_OPERATION_ABORTED {
|
||||
err = os.ErrDeadlineExceeded
|
||||
}
|
||||
}
|
||||
|
||||
// runtime.KeepAlive is needed, as c is passed via native
|
||||
// code to ioCompletionProcessor, c must remain alive
|
||||
// until the channel read is complete.
|
||||
runtime.KeepAlive(c)
|
||||
return int(r.bytes), err
|
||||
}
|
||||
|
||||
// Read reads from a file handle.
|
||||
func (f *file) Read(b []byte) (int, error) {
|
||||
c, err := f.prepareIo()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer f.wg.Done()
|
||||
|
||||
if atomic.LoadUint32(&f.readDeadline.timedout) == 1 {
|
||||
return 0, os.ErrDeadlineExceeded
|
||||
}
|
||||
|
||||
var bytes uint32
|
||||
err = windows.ReadFile(f.handle, b, &bytes, &c.o)
|
||||
n, err := f.asyncIo(c, &f.readDeadline, bytes, err)
|
||||
runtime.KeepAlive(b)
|
||||
|
||||
// Handle EOF conditions.
|
||||
if err == nil && n == 0 && len(b) != 0 {
|
||||
return 0, io.EOF
|
||||
} else if err == windows.ERROR_BROKEN_PIPE {
|
||||
return 0, io.EOF
|
||||
} else {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
|
||||
// Write writes to a file handle.
|
||||
func (f *file) Write(b []byte) (int, error) {
|
||||
c, err := f.prepareIo()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer f.wg.Done()
|
||||
|
||||
if atomic.LoadUint32(&f.writeDeadline.timedout) == 1 {
|
||||
return 0, os.ErrDeadlineExceeded
|
||||
}
|
||||
|
||||
var bytes uint32
|
||||
err = windows.WriteFile(f.handle, b, &bytes, &c.o)
|
||||
n, err := f.asyncIo(c, &f.writeDeadline, bytes, err)
|
||||
runtime.KeepAlive(b)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (f *file) SetReadDeadline(deadline time.Time) error {
|
||||
return f.readDeadline.set(deadline)
|
||||
}
|
||||
|
||||
func (f *file) SetWriteDeadline(deadline time.Time) error {
|
||||
return f.writeDeadline.set(deadline)
|
||||
}
|
||||
|
||||
func (f *file) Flush() error {
|
||||
return windows.FlushFileBuffers(f.handle)
|
||||
}
|
||||
|
||||
func (f *file) Fd() uintptr {
|
||||
return uintptr(f.handle)
|
||||
}
|
||||
|
||||
func (d *deadlineHandler) set(deadline time.Time) error {
|
||||
d.setLock.Lock()
|
||||
defer d.setLock.Unlock()
|
||||
|
||||
if d.timer != nil {
|
||||
if !d.timer.Stop() {
|
||||
<-d.channel
|
||||
}
|
||||
d.timer = nil
|
||||
}
|
||||
atomic.StoreUint32(&d.timedout, 0)
|
||||
|
||||
select {
|
||||
case <-d.channel:
|
||||
d.channelLock.Lock()
|
||||
d.channel = make(chan struct{})
|
||||
d.channelLock.Unlock()
|
||||
default:
|
||||
}
|
||||
|
||||
if deadline.IsZero() {
|
||||
return nil
|
||||
}
|
||||
|
||||
timeoutIO := func() {
|
||||
atomic.StoreUint32(&d.timedout, 1)
|
||||
close(d.channel)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
duration := deadline.Sub(now)
|
||||
if deadline.After(now) {
|
||||
// Deadline is in the future, set a timer to wait
|
||||
d.timer = time.AfterFunc(duration, timeoutIO)
|
||||
} else {
|
||||
// Deadline is in the past. Cancel all pending IO now.
|
||||
timeoutIO()
|
||||
}
|
||||
return nil
|
||||
}
|
474
vendor/golang.zx2c4.com/wireguard/ipc/winpipe/winpipe.go
generated
vendored
Normal file
474
vendor/golang.zx2c4.com/wireguard/ipc/winpipe/winpipe.go
generated
vendored
Normal file
@ -0,0 +1,474 @@
|
||||
// +build windows
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2005 Microsoft
|
||||
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
// Package winpipe implements a net.Conn and net.Listener around Windows named pipes.
|
||||
package winpipe
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type pipe struct {
|
||||
*file
|
||||
path string
|
||||
}
|
||||
|
||||
type messageBytePipe struct {
|
||||
pipe
|
||||
writeClosed bool
|
||||
readEOF bool
|
||||
}
|
||||
|
||||
type pipeAddress string
|
||||
|
||||
func (f *pipe) LocalAddr() net.Addr {
|
||||
return pipeAddress(f.path)
|
||||
}
|
||||
|
||||
func (f *pipe) RemoteAddr() net.Addr {
|
||||
return pipeAddress(f.path)
|
||||
}
|
||||
|
||||
func (f *pipe) SetDeadline(t time.Time) error {
|
||||
f.SetReadDeadline(t)
|
||||
f.SetWriteDeadline(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CloseWrite closes the write side of a message pipe in byte mode.
|
||||
func (f *messageBytePipe) CloseWrite() error {
|
||||
if f.writeClosed {
|
||||
return io.ErrClosedPipe
|
||||
}
|
||||
err := f.file.Flush()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.file.Write(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.writeClosed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write writes bytes to a message pipe in byte mode. Zero-byte writes are ignored, since
|
||||
// they are used to implement CloseWrite.
|
||||
func (f *messageBytePipe) Write(b []byte) (int, error) {
|
||||
if f.writeClosed {
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
if len(b) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
return f.file.Write(b)
|
||||
}
|
||||
|
||||
// Read reads bytes from a message pipe in byte mode. A read of a zero-byte message on a message
|
||||
// mode pipe will return io.EOF, as will all subsequent reads.
|
||||
func (f *messageBytePipe) Read(b []byte) (int, error) {
|
||||
if f.readEOF {
|
||||
return 0, io.EOF
|
||||
}
|
||||
n, err := f.file.Read(b)
|
||||
if err == io.EOF {
|
||||
// If this was the result of a zero-byte read, then
|
||||
// it is possible that the read was due to a zero-size
|
||||
// message. Since we are simulating CloseWrite with a
|
||||
// zero-byte message, ensure that all future Read calls
|
||||
// also return EOF.
|
||||
f.readEOF = true
|
||||
} else if err == windows.ERROR_MORE_DATA {
|
||||
// ERROR_MORE_DATA indicates that the pipe's read mode is message mode
|
||||
// and the message still has more bytes. Treat this as a success, since
|
||||
// this package presents all named pipes as byte streams.
|
||||
err = nil
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (f *pipe) Handle() windows.Handle {
|
||||
return f.handle
|
||||
}
|
||||
|
||||
func (s pipeAddress) Network() string {
|
||||
return "pipe"
|
||||
}
|
||||
|
||||
func (s pipeAddress) String() string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
// tryDialPipe attempts to dial the specified pipe until cancellation or timeout.
|
||||
func tryDialPipe(ctx context.Context, path *string) (windows.Handle, error) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return 0, ctx.Err()
|
||||
default:
|
||||
path16, err := windows.UTF16PtrFromString(*path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
h, err := windows.CreateFile(path16, windows.GENERIC_READ|windows.GENERIC_WRITE, 0, nil, windows.OPEN_EXISTING, windows.FILE_FLAG_OVERLAPPED|windows.SECURITY_SQOS_PRESENT|windows.SECURITY_ANONYMOUS, 0)
|
||||
if err == nil {
|
||||
return h, nil
|
||||
}
|
||||
if err != windows.ERROR_PIPE_BUSY {
|
||||
return h, &os.PathError{Err: err, Op: "open", Path: *path}
|
||||
}
|
||||
// Wait 10 msec and try again. This is a rather simplistic
|
||||
// view, as we always try each 10 milliseconds.
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DialConfig exposes various options for use in Dial and DialContext.
|
||||
type DialConfig struct {
|
||||
ExpectedOwner *windows.SID // If non-nil, the pipe is verified to be owned by this SID.
|
||||
}
|
||||
|
||||
// Dial connects to the specified named pipe by path, timing out if the connection
|
||||
// takes longer than the specified duration. If timeout is nil, then we use
|
||||
// a default timeout of 2 seconds.
|
||||
func Dial(path string, timeout *time.Duration, config *DialConfig) (net.Conn, error) {
|
||||
var absTimeout time.Time
|
||||
if timeout != nil {
|
||||
absTimeout = time.Now().Add(*timeout)
|
||||
} else {
|
||||
absTimeout = time.Now().Add(2 * time.Second)
|
||||
}
|
||||
ctx, _ := context.WithDeadline(context.Background(), absTimeout)
|
||||
conn, err := DialContext(ctx, path, config)
|
||||
if err == context.DeadlineExceeded {
|
||||
return nil, os.ErrDeadlineExceeded
|
||||
}
|
||||
return conn, err
|
||||
}
|
||||
|
||||
// DialContext attempts to connect to the specified named pipe by path
|
||||
// cancellation or timeout.
|
||||
func DialContext(ctx context.Context, path string, config *DialConfig) (net.Conn, error) {
|
||||
if config == nil {
|
||||
config = &DialConfig{}
|
||||
}
|
||||
var err error
|
||||
var h windows.Handle
|
||||
h, err = tryDialPipe(ctx, &path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if config.ExpectedOwner != nil {
|
||||
sd, err := windows.GetSecurityInfo(h, windows.SE_FILE_OBJECT, windows.OWNER_SECURITY_INFORMATION)
|
||||
if err != nil {
|
||||
windows.Close(h)
|
||||
return nil, err
|
||||
}
|
||||
realOwner, _, err := sd.Owner()
|
||||
if err != nil {
|
||||
windows.Close(h)
|
||||
return nil, err
|
||||
}
|
||||
if !realOwner.Equals(config.ExpectedOwner) {
|
||||
windows.Close(h)
|
||||
return nil, windows.ERROR_ACCESS_DENIED
|
||||
}
|
||||
}
|
||||
|
||||
var flags uint32
|
||||
err = windows.GetNamedPipeInfo(h, &flags, nil, nil, nil)
|
||||
if err != nil {
|
||||
windows.Close(h)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
f, err := makeFile(h)
|
||||
if err != nil {
|
||||
windows.Close(h)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the pipe is in message mode, return a message byte pipe, which
|
||||
// supports CloseWrite.
|
||||
if flags&windows.PIPE_TYPE_MESSAGE != 0 {
|
||||
return &messageBytePipe{
|
||||
pipe: pipe{file: f, path: path},
|
||||
}, nil
|
||||
}
|
||||
return &pipe{file: f, path: path}, nil
|
||||
}
|
||||
|
||||
type acceptResponse struct {
|
||||
f *file
|
||||
err error
|
||||
}
|
||||
|
||||
type pipeListener struct {
|
||||
firstHandle windows.Handle
|
||||
path string
|
||||
config ListenConfig
|
||||
acceptCh chan (chan acceptResponse)
|
||||
closeCh chan int
|
||||
doneCh chan int
|
||||
}
|
||||
|
||||
func makeServerPipeHandle(path string, sd *windows.SECURITY_DESCRIPTOR, c *ListenConfig, first bool) (windows.Handle, error) {
|
||||
path16, err := windows.UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
||||
}
|
||||
|
||||
var oa windows.OBJECT_ATTRIBUTES
|
||||
oa.Length = uint32(unsafe.Sizeof(oa))
|
||||
|
||||
var ntPath windows.NTUnicodeString
|
||||
if err := windows.RtlDosPathNameToNtPathName(path16, &ntPath, nil, nil); err != nil {
|
||||
if ntstatus, ok := err.(windows.NTStatus); ok {
|
||||
err = ntstatus.Errno()
|
||||
}
|
||||
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
||||
}
|
||||
defer windows.LocalFree(windows.Handle(unsafe.Pointer(ntPath.Buffer)))
|
||||
oa.ObjectName = &ntPath
|
||||
|
||||
// The security descriptor is only needed for the first pipe.
|
||||
if first {
|
||||
if sd != nil {
|
||||
oa.SecurityDescriptor = sd
|
||||
} else {
|
||||
// Construct the default named pipe security descriptor.
|
||||
var acl *windows.ACL
|
||||
if err := windows.RtlDefaultNpAcl(&acl); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer windows.LocalFree(windows.Handle(unsafe.Pointer(acl)))
|
||||
sd, err := windows.NewSecurityDescriptor()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err = sd.SetDACL(acl, true, false); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
oa.SecurityDescriptor = sd
|
||||
}
|
||||
}
|
||||
|
||||
typ := uint32(windows.FILE_PIPE_REJECT_REMOTE_CLIENTS)
|
||||
if c.MessageMode {
|
||||
typ |= windows.FILE_PIPE_MESSAGE_TYPE
|
||||
}
|
||||
|
||||
disposition := uint32(windows.FILE_OPEN)
|
||||
access := uint32(windows.GENERIC_READ | windows.GENERIC_WRITE | windows.SYNCHRONIZE)
|
||||
if first {
|
||||
disposition = windows.FILE_CREATE
|
||||
// By not asking for read or write access, the named pipe file system
|
||||
// will put this pipe into an initially disconnected state, blocking
|
||||
// client connections until the next call with first == false.
|
||||
access = windows.SYNCHRONIZE
|
||||
}
|
||||
|
||||
timeout := int64(-50 * 10000) // 50ms
|
||||
|
||||
var (
|
||||
h windows.Handle
|
||||
iosb windows.IO_STATUS_BLOCK
|
||||
)
|
||||
err = windows.NtCreateNamedPipeFile(&h, access, &oa, &iosb, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE, disposition, 0, typ, 0, 0, 0xffffffff, uint32(c.InputBufferSize), uint32(c.OutputBufferSize), &timeout)
|
||||
if err != nil {
|
||||
if ntstatus, ok := err.(windows.NTStatus); ok {
|
||||
err = ntstatus.Errno()
|
||||
}
|
||||
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
||||
}
|
||||
|
||||
runtime.KeepAlive(ntPath)
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (l *pipeListener) makeServerPipe() (*file, error) {
|
||||
h, err := makeServerPipeHandle(l.path, nil, &l.config, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := makeFile(h)
|
||||
if err != nil {
|
||||
windows.Close(h)
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (l *pipeListener) makeConnectedServerPipe() (*file, error) {
|
||||
p, err := l.makeServerPipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Wait for the client to connect.
|
||||
ch := make(chan error)
|
||||
go func(p *file) {
|
||||
ch <- connectPipe(p)
|
||||
}(p)
|
||||
|
||||
select {
|
||||
case err = <-ch:
|
||||
if err != nil {
|
||||
p.Close()
|
||||
p = nil
|
||||
}
|
||||
case <-l.closeCh:
|
||||
// Abort the connect request by closing the handle.
|
||||
p.Close()
|
||||
p = nil
|
||||
err = <-ch
|
||||
if err == nil || err == os.ErrClosed {
|
||||
err = net.ErrClosed
|
||||
}
|
||||
}
|
||||
return p, err
|
||||
}
|
||||
|
||||
func (l *pipeListener) listenerRoutine() {
|
||||
closed := false
|
||||
for !closed {
|
||||
select {
|
||||
case <-l.closeCh:
|
||||
closed = true
|
||||
case responseCh := <-l.acceptCh:
|
||||
var (
|
||||
p *file
|
||||
err error
|
||||
)
|
||||
for {
|
||||
p, err = l.makeConnectedServerPipe()
|
||||
// If the connection was immediately closed by the client, try
|
||||
// again.
|
||||
if err != windows.ERROR_NO_DATA {
|
||||
break
|
||||
}
|
||||
}
|
||||
responseCh <- acceptResponse{p, err}
|
||||
closed = err == net.ErrClosed
|
||||
}
|
||||
}
|
||||
windows.Close(l.firstHandle)
|
||||
l.firstHandle = 0
|
||||
// Notify Close and Accept callers that the handle has been closed.
|
||||
close(l.doneCh)
|
||||
}
|
||||
|
||||
// ListenConfig contains configuration for the pipe listener.
|
||||
type ListenConfig struct {
|
||||
// SecurityDescriptor contains a Windows security descriptor. If nil, the default from RtlDefaultNpAcl is used.
|
||||
SecurityDescriptor *windows.SECURITY_DESCRIPTOR
|
||||
|
||||
// MessageMode determines whether the pipe is in byte or message mode. In either
|
||||
// case the pipe is read in byte mode by default. The only practical difference in
|
||||
// this implementation is that CloseWrite is only supported for message mode pipes;
|
||||
// CloseWrite is implemented as a zero-byte write, but zero-byte writes are only
|
||||
// transferred to the reader (and returned as io.EOF in this implementation)
|
||||
// when the pipe is in message mode.
|
||||
MessageMode bool
|
||||
|
||||
// InputBufferSize specifies the initial size of the input buffer, in bytes, which the OS will grow as needed.
|
||||
InputBufferSize int32
|
||||
|
||||
// OutputBufferSize specifies the initial size of the output buffer, in bytes, which the OS will grow as needed.
|
||||
OutputBufferSize int32
|
||||
}
|
||||
|
||||
// Listen creates a listener on a Windows named pipe path,such as \\.\pipe\mypipe.
|
||||
// The pipe must not already exist.
|
||||
func Listen(path string, c *ListenConfig) (net.Listener, error) {
|
||||
if c == nil {
|
||||
c = &ListenConfig{}
|
||||
}
|
||||
h, err := makeServerPipeHandle(path, c.SecurityDescriptor, c, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l := &pipeListener{
|
||||
firstHandle: h,
|
||||
path: path,
|
||||
config: *c,
|
||||
acceptCh: make(chan (chan acceptResponse)),
|
||||
closeCh: make(chan int),
|
||||
doneCh: make(chan int),
|
||||
}
|
||||
// The first connection is swallowed on Windows 7 & 8, so synthesize it.
|
||||
if maj, _, _ := windows.RtlGetNtVersionNumbers(); maj <= 8 {
|
||||
path16, err := windows.UTF16PtrFromString(path)
|
||||
if err == nil {
|
||||
h, err = windows.CreateFile(path16, 0, 0, nil, windows.OPEN_EXISTING, windows.SECURITY_SQOS_PRESENT|windows.SECURITY_ANONYMOUS, 0)
|
||||
if err == nil {
|
||||
windows.CloseHandle(h)
|
||||
}
|
||||
}
|
||||
}
|
||||
go l.listenerRoutine()
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func connectPipe(p *file) error {
|
||||
c, err := p.prepareIo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer p.wg.Done()
|
||||
|
||||
err = windows.ConnectNamedPipe(p.handle, &c.o)
|
||||
_, err = p.asyncIo(c, nil, 0, err)
|
||||
if err != nil && err != windows.ERROR_PIPE_CONNECTED {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *pipeListener) Accept() (net.Conn, error) {
|
||||
ch := make(chan acceptResponse)
|
||||
select {
|
||||
case l.acceptCh <- ch:
|
||||
response := <-ch
|
||||
err := response.err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if l.config.MessageMode {
|
||||
return &messageBytePipe{
|
||||
pipe: pipe{file: response.f, path: l.path},
|
||||
}, nil
|
||||
}
|
||||
return &pipe{file: response.f, path: l.path}, nil
|
||||
case <-l.doneCh:
|
||||
return nil, net.ErrClosed
|
||||
}
|
||||
}
|
||||
|
||||
func (l *pipeListener) Close() error {
|
||||
select {
|
||||
case l.closeCh <- 1:
|
||||
<-l.doneCh
|
||||
case <-l.doneCh:
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *pipeListener) Addr() net.Addr {
|
||||
return pipeAddress(l.path)
|
||||
}
|
35
vendor/golang.zx2c4.com/wireguard/wgctrl/.cibuild.sh
generated
vendored
Normal file
35
vendor/golang.zx2c4.com/wireguard/wgctrl/.cibuild.sh
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
set -x
|
||||
|
||||
# !! This script is meant for use in CI build use only !!
|
||||
|
||||
KERNEL=$(uname -s)
|
||||
|
||||
# Use doas in place of sudo for OpenBSD.
|
||||
SUDO="sudo"
|
||||
if [ "${KERNEL}" == "OpenBSD" ]; then
|
||||
SUDO="doas"
|
||||
fi
|
||||
|
||||
if [ "${KERNEL}" == "Linux" ]; then
|
||||
# Configure a WireGuard interface.
|
||||
sudo ip link add wg0 type wireguard
|
||||
sudo ip link set up wg0
|
||||
fi
|
||||
|
||||
# Set up wireguard-go on all OSes.
|
||||
git clone git://git.zx2c4.com/wireguard-go
|
||||
cd wireguard-go
|
||||
|
||||
if [ "${KERNEL}" == "Linux" ]; then
|
||||
# Bypass Linux compilation restriction.
|
||||
make
|
||||
else
|
||||
# Build directly to avoid Makefile.
|
||||
go build -o wireguard-go
|
||||
fi
|
||||
|
||||
${SUDO} mv ./wireguard-go /usr/local/bin/wireguard-go
|
||||
cd ..
|
||||
${SUDO} rm -rf ./wireguard-go
|
2
vendor/golang.zx2c4.com/wireguard/wgctrl/.gitignore
generated
vendored
Normal file
2
vendor/golang.zx2c4.com/wireguard/wgctrl/.gitignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
cmd/wgctrl/wgctrl
|
||||
*.test
|
23
vendor/golang.zx2c4.com/wireguard/wgctrl/CONTRIBUTING.md
generated
vendored
Normal file
23
vendor/golang.zx2c4.com/wireguard/wgctrl/CONTRIBUTING.md
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
Contributing
|
||||
============
|
||||
|
||||
The `wgctrl` project makes use of the [GitHub Flow](https://guides.github.com/introduction/flow/)
|
||||
for contributions.
|
||||
|
||||
If you'd like to contribute to the project, please
|
||||
[open an issue](https://github.com/WireGuard/wgctrl-go/issues/new) or find an
|
||||
[existing issue](https://github.com/WireGuard/wgctrl-go/issues) that you'd like
|
||||
to take on. This ensures that efforts are not duplicated, and that a new feature
|
||||
aligns with the focus of the rest of the repository.
|
||||
|
||||
Once your suggestion has been submitted and discussed, please be sure that your
|
||||
code meets the following criteria:
|
||||
|
||||
- code is completely `gofmt`'d
|
||||
- new features or codepaths have appropriate test coverage
|
||||
- `go test ./...` passes
|
||||
- `go vet ./...` passes
|
||||
- `staticcheck ./...` passes
|
||||
- `golint ./...` returns no warnings, including documentation comment warnings
|
||||
|
||||
Finally, submit a pull request for review!
|
9
vendor/golang.zx2c4.com/wireguard/wgctrl/LICENSE.md
generated
vendored
Normal file
9
vendor/golang.zx2c4.com/wireguard/wgctrl/LICENSE.md
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
# MIT License
|
||||
|
||||
Copyright (C) 2018-2019 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.
|
33
vendor/golang.zx2c4.com/wireguard/wgctrl/README.md
generated
vendored
Normal file
33
vendor/golang.zx2c4.com/wireguard/wgctrl/README.md
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
# wgctrl [](https://github.com/WireGuard/wgctrl-go/actions) [](https://pkg.go.dev/golang.zx2c4.com/wireguard/wgctrl) [](https://goreportcard.com/report/golang.zx2c4.com/wireguard/wgctrl)
|
||||
|
||||
|
||||
Package `wgctrl` enables control of WireGuard devices on multiple platforms.
|
||||
|
||||
For more information on WireGuard, please see <https://www.wireguard.com/>.
|
||||
|
||||
MIT Licensed.
|
||||
|
||||
```text
|
||||
go get golang.zx2c4.com/wireguard/wgctrl
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
`wgctrl` can control multiple types of WireGuard devices, including:
|
||||
|
||||
- Linux kernel module devices, via generic netlink
|
||||
- userspace devices (e.g. wireguard-go), via the userspace configuration protocol
|
||||
- both UNIX-like and Windows operating systems are supported
|
||||
- **Experimental:** OpenBSD kernel module devices (read-only), via ioctl interface
|
||||
- See <https://git.zx2c4.com/wireguard-openbsd/about/> for details.
|
||||
|
||||
As new operating systems add support for in-kernel WireGuard implementations,
|
||||
this package should also be extended to support those native implementations.
|
||||
|
||||
If you are aware of any efforts on this front, please
|
||||
[file an issue](https://github.com/WireGuard/wgctrl-go/issues/new).
|
||||
|
||||
This package implements WireGuard configuration protocol operations, enabling
|
||||
the configuration of existing WireGuard devices. Operations such as creating
|
||||
WireGuard devices, or applying IP addresses to those devices, are out of scope
|
||||
for this package.
|
101
vendor/golang.zx2c4.com/wireguard/wgctrl/client.go
generated
vendored
Normal file
101
vendor/golang.zx2c4.com/wireguard/wgctrl/client.go
generated
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
package wgctrl
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"golang.zx2c4.com/wireguard/wgctrl/internal/wginternal"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
// Expose an identical interface to the underlying packages.
|
||||
var _ wginternal.Client = &Client{}
|
||||
|
||||
// A Client provides access to WireGuard device information.
|
||||
type Client struct {
|
||||
// Seamlessly use different wginternal.Client implementations to provide an
|
||||
// interface similar to wg(8).
|
||||
cs []wginternal.Client
|
||||
}
|
||||
|
||||
// New creates a new Client.
|
||||
func New() (*Client, error) {
|
||||
cs, err := newClients()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{
|
||||
cs: cs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Close releases resources used by a Client.
|
||||
func (c *Client) Close() error {
|
||||
for _, wgc := range c.cs {
|
||||
if err := wgc.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Devices retrieves all WireGuard devices on this system.
|
||||
func (c *Client) Devices() ([]*wgtypes.Device, error) {
|
||||
var out []*wgtypes.Device
|
||||
for _, wgc := range c.cs {
|
||||
devs, err := wgc.Devices()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out = append(out, devs...)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Device retrieves a WireGuard device by its interface name.
|
||||
//
|
||||
// If the device specified by name does not exist or is not a WireGuard device,
|
||||
// an error is returned which can be checked using `errors.Is(err, os.ErrNotExist)`.
|
||||
func (c *Client) Device(name string) (*wgtypes.Device, error) {
|
||||
for _, wgc := range c.cs {
|
||||
d, err := wgc.Device(name)
|
||||
switch {
|
||||
case err == nil:
|
||||
return d, nil
|
||||
case errors.Is(err, os.ErrNotExist):
|
||||
continue
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
|
||||
// ConfigureDevice configures a WireGuard device by its interface name.
|
||||
//
|
||||
// Because the zero value of some Go types may be significant to WireGuard for
|
||||
// Config fields, only fields which are not nil will be applied when
|
||||
// configuring a device.
|
||||
//
|
||||
// If the device specified by name does not exist or is not a WireGuard device,
|
||||
// an error is returned which can be checked using `errors.Is(err, os.ErrNotExist)`.
|
||||
func (c *Client) ConfigureDevice(name string, cfg wgtypes.Config) error {
|
||||
for _, wgc := range c.cs {
|
||||
err := wgc.ConfigureDevice(name, cfg)
|
||||
switch {
|
||||
case err == nil:
|
||||
return nil
|
||||
case errors.Is(err, os.ErrNotExist):
|
||||
continue
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return os.ErrNotExist
|
||||
}
|
29
vendor/golang.zx2c4.com/wireguard/wgctrl/doc.go
generated
vendored
Normal file
29
vendor/golang.zx2c4.com/wireguard/wgctrl/doc.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
// Package wgctrl enables control of WireGuard devices on multiple platforms.
|
||||
//
|
||||
// For more information on WireGuard, please see https://www.wireguard.com/.
|
||||
//
|
||||
// go get golang.zx2c4.com/wireguard/wgctrl
|
||||
//
|
||||
//
|
||||
// Overview
|
||||
//
|
||||
// wgctrl can control multiple types of WireGuard devices, including:
|
||||
//
|
||||
// - Linux kernel module devices, via generic netlink
|
||||
// - userspace devices (e.g. wireguard-go), via the userspace configuration protocol
|
||||
// - both UNIX-like and Windows operating systems are supported
|
||||
// - **Experimental:** OpenBSD kernel module devices, via ioctl interface
|
||||
// See <https://git.zx2c4.com/wireguard-openbsd/about/> for details. Specify
|
||||
// environment variable WGCTRL_OPENBSD_KERNEL=1 to enable this interface.
|
||||
//
|
||||
// As new operating systems add support for in-kernel WireGuard implementations,
|
||||
// this package should also be extended to support those native implementations.
|
||||
//
|
||||
// If you are aware of any efforts on this front, please file an issue:
|
||||
// https://github.com/WireGuard/wgctrl-go/issues/new.
|
||||
//
|
||||
// This package implements WireGuard configuration protocol operations, enabling
|
||||
// the configuration of existing WireGuard devices. Operations such as creating
|
||||
// WireGuard devices, or applying IP addresses to those devices, are out of scope
|
||||
// for this package.
|
||||
package wgctrl // import "golang.zx2c4.com/wireguard/wgctrl"
|
14
vendor/golang.zx2c4.com/wireguard/wgctrl/go.mod
generated
vendored
Normal file
14
vendor/golang.zx2c4.com/wireguard/wgctrl/go.mod
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
module golang.zx2c4.com/wireguard/wgctrl
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/google/go-cmp v0.5.5
|
||||
github.com/mdlayher/genetlink v1.0.0
|
||||
github.com/mdlayher/netlink v1.4.0
|
||||
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721
|
||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e
|
||||
golang.org/x/net v0.0.0-20210504132125-bbd867fde50d // indirect
|
||||
golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6
|
||||
golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b
|
||||
)
|
84
vendor/golang.zx2c4.com/wireguard/wgctrl/go.sum
generated
vendored
Normal file
84
vendor/golang.zx2c4.com/wireguard/wgctrl/go.sum
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA=
|
||||
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b h1:c3NTyLNozICy8B4mlMXemD3z/gXgQzVXZS/HqT+i3do=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U=
|
||||
github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JAQI/ZLUkCZ7VJS3r74hwFIGXJsgZlY=
|
||||
github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo=
|
||||
github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0=
|
||||
github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=
|
||||
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
|
||||
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
|
||||
github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
|
||||
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
|
||||
github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8=
|
||||
github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
|
||||
github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
|
||||
github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys=
|
||||
github.com/mdlayher/netlink v1.4.0 h1:n3ARR+Fm0dDv37dj5wSWZXDKcy+U0zwcXS3zKMnSiT0=
|
||||
github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8=
|
||||
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws=
|
||||
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI=
|
||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210504132125-bbd867fde50d h1:nTDGCTeAu2LhcsHTRzjyIUbZHCJ4QePArsm27Hka0UM=
|
||||
golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 h1:cdsMqa2nXzqlgs183pHxtvoVwU7CyzaCTAUOg94af4c=
|
||||
golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b h1:XDLXhn7ryprJVo+Lpkiib6CIuXE2031GDwtfEm7vLjI=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg=
|
21
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wginternal/client.go
generated
vendored
Normal file
21
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wginternal/client.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
package wginternal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
// ErrReadOnly indicates that the driver backing a device is read-only. It is
|
||||
// a sentinel value used in integration tests.
|
||||
// TODO(mdlayher): consider exposing in API.
|
||||
var ErrReadOnly = errors.New("driver is read-only")
|
||||
|
||||
// A Client is a type which can control a WireGuard device.
|
||||
type Client interface {
|
||||
io.Closer
|
||||
Devices() ([]*wgtypes.Device, error)
|
||||
Device(name string) (*wgtypes.Device, error)
|
||||
ConfigureDevice(name string, cfg wgtypes.Config) error
|
||||
}
|
5
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wginternal/doc.go
generated
vendored
Normal file
5
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wginternal/doc.go
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
// Package wginternal contains shared internal types for wgctrl.
|
||||
//
|
||||
// This package is internal-only and not meant for end users to consume.
|
||||
// Please use package wgctrl (an abstraction over this package) instead.
|
||||
package wginternal
|
264
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/client_linux.go
generated
vendored
Normal file
264
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/client_linux.go
generated
vendored
Normal file
@ -0,0 +1,264 @@
|
||||
//+build linux
|
||||
|
||||
package wglinux
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/mdlayher/genetlink"
|
||||
"github.com/mdlayher/netlink"
|
||||
"github.com/mdlayher/netlink/nlenc"
|
||||
"golang.org/x/sys/unix"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/internal/wginternal"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
var _ wginternal.Client = &Client{}
|
||||
|
||||
// A Client provides access to Linux WireGuard netlink information.
|
||||
type Client struct {
|
||||
c *genetlink.Conn
|
||||
family genetlink.Family
|
||||
|
||||
interfaces func() ([]string, error)
|
||||
}
|
||||
|
||||
// New creates a new Client and returns whether or not the generic netlink
|
||||
// interface is available.
|
||||
func New() (*Client, bool, error) {
|
||||
c, err := genetlink.Dial(nil)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
return initClient(c)
|
||||
}
|
||||
|
||||
// initClient is the internal Client constructor used in some tests.
|
||||
func initClient(c *genetlink.Conn) (*Client, bool, error) {
|
||||
f, err := c.GetFamily(wgh.GenlName)
|
||||
if err != nil {
|
||||
_ = c.Close()
|
||||
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
// The generic netlink interface is not available.
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
return &Client{
|
||||
c: c,
|
||||
family: f,
|
||||
|
||||
// By default, gather only WireGuard interfaces using rtnetlink.
|
||||
interfaces: rtnlInterfaces,
|
||||
}, true, nil
|
||||
}
|
||||
|
||||
// Close implements wginternal.Client.
|
||||
func (c *Client) Close() error {
|
||||
return c.c.Close()
|
||||
}
|
||||
|
||||
// Devices implements wginternal.Client.
|
||||
func (c *Client) Devices() ([]*wgtypes.Device, error) {
|
||||
// By default, rtnetlink is used to fetch a list of all interfaces and then
|
||||
// filter that list to only find WireGuard interfaces.
|
||||
//
|
||||
// The remainder of this function assumes that any returned device from this
|
||||
// function is a valid WireGuard device.
|
||||
ifis, err := c.interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds := make([]*wgtypes.Device, 0, len(ifis))
|
||||
for _, ifi := range ifis {
|
||||
d, err := c.Device(ifi)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds = append(ds, d)
|
||||
}
|
||||
|
||||
return ds, nil
|
||||
}
|
||||
|
||||
// Device implements wginternal.Client.
|
||||
func (c *Client) Device(name string) (*wgtypes.Device, error) {
|
||||
// Don't bother querying netlink with empty input.
|
||||
if name == "" {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
|
||||
// Fetching a device by interface index is possible as well, but we only
|
||||
// support fetching by name as it seems to be more convenient in general.
|
||||
b, err := netlink.MarshalAttributes([]netlink.Attribute{{
|
||||
Type: wgh.DeviceAIfname,
|
||||
Data: nlenc.Bytes(name),
|
||||
}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgs, err := c.execute(wgh.CmdGetDevice, netlink.Request|netlink.Dump, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return parseDevice(msgs)
|
||||
}
|
||||
|
||||
// ConfigureDevice implements wginternal.Client.
|
||||
func (c *Client) ConfigureDevice(name string, cfg wgtypes.Config) error {
|
||||
// Large configurations are split into batches for use with netlink.
|
||||
for _, b := range buildBatches(cfg) {
|
||||
attrs, err := configAttrs(name, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Request acknowledgement of our request from netlink, even though the
|
||||
// output messages are unused. The netlink package checks and trims the
|
||||
// status code value.
|
||||
if _, err := c.execute(wgh.CmdSetDevice, netlink.Request|netlink.Acknowledge, attrs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// execute executes a single WireGuard netlink request with the specified command,
|
||||
// header flags, and attribute arguments.
|
||||
func (c *Client) execute(command uint8, flags netlink.HeaderFlags, attrb []byte) ([]genetlink.Message, error) {
|
||||
msg := genetlink.Message{
|
||||
Header: genetlink.Header{
|
||||
Command: command,
|
||||
Version: wgh.GenlVersion,
|
||||
},
|
||||
Data: attrb,
|
||||
}
|
||||
|
||||
msgs, err := c.c.Execute(msg, c.family.ID, flags)
|
||||
if err == nil {
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
// We don't want to expose netlink errors directly to callers so unpack to
|
||||
// something more generic.
|
||||
oerr, ok := err.(*netlink.OpError)
|
||||
if !ok {
|
||||
// Expect all errors to conform to netlink.OpError.
|
||||
return nil, fmt.Errorf("wglinux: netlink operation returned non-netlink error (please file a bug: https://golang.zx2c4.com/wireguard/wgctrl): %v", err)
|
||||
}
|
||||
|
||||
switch oerr.Err {
|
||||
// Convert "no such device" and "not a wireguard device" to an error
|
||||
// compatible with os.ErrNotExist for easy checking.
|
||||
case unix.ENODEV, unix.ENOTSUP:
|
||||
return nil, os.ErrNotExist
|
||||
default:
|
||||
// Expose the inner error directly (such as EPERM).
|
||||
return nil, oerr.Err
|
||||
}
|
||||
}
|
||||
|
||||
// rtnlInterfaces uses rtnetlink to fetch a list of WireGuard interfaces.
|
||||
func rtnlInterfaces() ([]string, error) {
|
||||
// Use the stdlib's rtnetlink helpers to get ahold of a table of all
|
||||
// interfaces, so we can begin filtering it down to just WireGuard devices.
|
||||
tab, err := syscall.NetlinkRIB(unix.RTM_GETLINK, unix.AF_UNSPEC)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wglinux: failed to get list of interfaces from rtnetlink: %v", err)
|
||||
}
|
||||
|
||||
msgs, err := syscall.ParseNetlinkMessage(tab)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wglinux: failed to parse rtnetlink messages: %v", err)
|
||||
}
|
||||
|
||||
return parseRTNLInterfaces(msgs)
|
||||
}
|
||||
|
||||
// parseRTNLInterfaces unpacks rtnetlink messages and returns WireGuard
|
||||
// interface names.
|
||||
func parseRTNLInterfaces(msgs []syscall.NetlinkMessage) ([]string, error) {
|
||||
var ifis []string
|
||||
for _, m := range msgs {
|
||||
// Only deal with link messages, and they must have an ifinfomsg
|
||||
// structure appear before the attributes.
|
||||
if m.Header.Type != unix.RTM_NEWLINK {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(m.Data) < unix.SizeofIfInfomsg {
|
||||
return nil, fmt.Errorf("wglinux: rtnetlink message is too short for ifinfomsg: %d", len(m.Data))
|
||||
}
|
||||
|
||||
ad, err := netlink.NewAttributeDecoder(m.Data[syscall.SizeofIfInfomsg:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Determine the interface's name and if it's a WireGuard device.
|
||||
var (
|
||||
ifi string
|
||||
isWG bool
|
||||
)
|
||||
|
||||
for ad.Next() {
|
||||
switch ad.Type() {
|
||||
case unix.IFLA_IFNAME:
|
||||
ifi = ad.String()
|
||||
case unix.IFLA_LINKINFO:
|
||||
ad.Do(isWGKind(&isWG))
|
||||
}
|
||||
}
|
||||
|
||||
if err := ad.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if isWG {
|
||||
// Found one; append it to the list.
|
||||
ifis = append(ifis, ifi)
|
||||
}
|
||||
}
|
||||
|
||||
return ifis, nil
|
||||
}
|
||||
|
||||
// wgKind is the IFLA_INFO_KIND value for WireGuard devices.
|
||||
const wgKind = "wireguard"
|
||||
|
||||
// isWGKind parses netlink attributes to determine if a link is a WireGuard
|
||||
// device, then populates ok with the result.
|
||||
func isWGKind(ok *bool) func(b []byte) error {
|
||||
return func(b []byte) error {
|
||||
ad, err := netlink.NewAttributeDecoder(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for ad.Next() {
|
||||
if ad.Type() != unix.IFLA_INFO_KIND {
|
||||
continue
|
||||
}
|
||||
|
||||
if ad.String() == wgKind {
|
||||
*ok = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return ad.Err()
|
||||
}
|
||||
}
|
293
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/configure_linux.go
generated
vendored
Normal file
293
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/configure_linux.go
generated
vendored
Normal file
@ -0,0 +1,293 @@
|
||||
//+build linux
|
||||
|
||||
package wglinux
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"unsafe"
|
||||
|
||||
"github.com/mdlayher/netlink"
|
||||
"github.com/mdlayher/netlink/nlenc"
|
||||
"golang.org/x/sys/unix"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
// configAttrs creates the required encoded netlink attributes to configure
|
||||
// the device specified by name using the non-nil fields in cfg.
|
||||
func configAttrs(name string, cfg wgtypes.Config) ([]byte, error) {
|
||||
ae := netlink.NewAttributeEncoder()
|
||||
ae.String(wgh.DeviceAIfname, name)
|
||||
|
||||
if cfg.PrivateKey != nil {
|
||||
ae.Bytes(wgh.DeviceAPrivateKey, (*cfg.PrivateKey)[:])
|
||||
}
|
||||
|
||||
if cfg.ListenPort != nil {
|
||||
ae.Uint16(wgh.DeviceAListenPort, uint16(*cfg.ListenPort))
|
||||
}
|
||||
|
||||
if cfg.FirewallMark != nil {
|
||||
ae.Uint32(wgh.DeviceAFwmark, uint32(*cfg.FirewallMark))
|
||||
}
|
||||
|
||||
if cfg.ReplacePeers {
|
||||
ae.Uint32(wgh.DeviceAFlags, wgh.DeviceFReplacePeers)
|
||||
}
|
||||
|
||||
// Only apply peer attributes if necessary.
|
||||
if len(cfg.Peers) > 0 {
|
||||
ae.Nested(wgh.DeviceAPeers, func(nae *netlink.AttributeEncoder) error {
|
||||
// Netlink arrays use type as an array index.
|
||||
for i, p := range cfg.Peers {
|
||||
nae.Nested(uint16(i), encodePeer(p))
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return ae.Encode()
|
||||
}
|
||||
|
||||
// ipBatchChunk is a tunable allowed IP batch limit per peer.
|
||||
//
|
||||
// Because we don't necessarily know how much space a given peer will occupy,
|
||||
// we play it safe and use a reasonably small value. Note that this constant
|
||||
// is used both in this package and tests, so be aware when making changes.
|
||||
const ipBatchChunk = 256
|
||||
|
||||
// peerBatchChunk specifies the number of peers that can appear in a
|
||||
// configuration before we start splitting it into chunks.
|
||||
const peerBatchChunk = 32
|
||||
|
||||
// shouldBatch determines if a configuration is sufficiently complex that it
|
||||
// should be split into batches.
|
||||
func shouldBatch(cfg wgtypes.Config) bool {
|
||||
if len(cfg.Peers) > peerBatchChunk {
|
||||
return true
|
||||
}
|
||||
|
||||
var ips int
|
||||
for _, p := range cfg.Peers {
|
||||
ips += len(p.AllowedIPs)
|
||||
}
|
||||
|
||||
return ips > ipBatchChunk
|
||||
}
|
||||
|
||||
// buildBatches produces a batch of configs from a single config, if needed.
|
||||
func buildBatches(cfg wgtypes.Config) []wgtypes.Config {
|
||||
// Is this a small configuration; no need to batch?
|
||||
if !shouldBatch(cfg) {
|
||||
return []wgtypes.Config{cfg}
|
||||
}
|
||||
|
||||
// Use most fields of cfg for our "base" configuration, and only differ
|
||||
// peers in each batch.
|
||||
base := cfg
|
||||
base.Peers = nil
|
||||
|
||||
// Track the known peers so that peer IPs are not replaced if a single
|
||||
// peer has its allowed IPs split into multiple batches.
|
||||
knownPeers := make(map[wgtypes.Key]struct{})
|
||||
|
||||
batches := make([]wgtypes.Config, 0)
|
||||
for _, p := range cfg.Peers {
|
||||
batch := base
|
||||
|
||||
// Iterate until no more allowed IPs.
|
||||
var done bool
|
||||
for !done {
|
||||
var tmp []net.IPNet
|
||||
if len(p.AllowedIPs) < ipBatchChunk {
|
||||
// IPs all fit within a batch; we are done.
|
||||
tmp = make([]net.IPNet, len(p.AllowedIPs))
|
||||
copy(tmp, p.AllowedIPs)
|
||||
done = true
|
||||
} else {
|
||||
// IPs are larger than a single batch, copy a batch out and
|
||||
// advance the cursor.
|
||||
tmp = make([]net.IPNet, ipBatchChunk)
|
||||
copy(tmp, p.AllowedIPs[:ipBatchChunk])
|
||||
|
||||
p.AllowedIPs = p.AllowedIPs[ipBatchChunk:]
|
||||
|
||||
if len(p.AllowedIPs) == 0 {
|
||||
// IPs ended on a batch boundary; no more IPs left so end
|
||||
// iteration after this loop.
|
||||
done = true
|
||||
}
|
||||
}
|
||||
|
||||
pcfg := wgtypes.PeerConfig{
|
||||
// PublicKey denotes the peer and must be present.
|
||||
PublicKey: p.PublicKey,
|
||||
|
||||
// Apply the update only flag to every chunk to ensure
|
||||
// consistency between batches when the kernel module processes
|
||||
// them.
|
||||
UpdateOnly: p.UpdateOnly,
|
||||
|
||||
// It'd be a bit weird to have a remove peer message with many
|
||||
// IPs, but just in case, add this to every peer's message.
|
||||
Remove: p.Remove,
|
||||
|
||||
// The IPs for this chunk.
|
||||
AllowedIPs: tmp,
|
||||
}
|
||||
|
||||
// Only pass certain fields on the first occurrence of a peer, so
|
||||
// that subsequent IPs won't be wiped out and space isn't wasted.
|
||||
if _, ok := knownPeers[p.PublicKey]; !ok {
|
||||
knownPeers[p.PublicKey] = struct{}{}
|
||||
|
||||
pcfg.PresharedKey = p.PresharedKey
|
||||
pcfg.Endpoint = p.Endpoint
|
||||
pcfg.PersistentKeepaliveInterval = p.PersistentKeepaliveInterval
|
||||
|
||||
// Important: do not move or appending peers won't work.
|
||||
pcfg.ReplaceAllowedIPs = p.ReplaceAllowedIPs
|
||||
}
|
||||
|
||||
// Add a peer configuration to this batch and keep going.
|
||||
batch.Peers = []wgtypes.PeerConfig{pcfg}
|
||||
batches = append(batches, batch)
|
||||
}
|
||||
}
|
||||
|
||||
// Do not allow peer replacement beyond the first message in a batch,
|
||||
// so we don't overwrite our previous batch work.
|
||||
for i := range batches {
|
||||
if i > 0 {
|
||||
batches[i].ReplacePeers = false
|
||||
}
|
||||
}
|
||||
|
||||
return batches
|
||||
}
|
||||
|
||||
// encodePeer returns a function to encode PeerConfig nested attributes.
|
||||
func encodePeer(p wgtypes.PeerConfig) func(ae *netlink.AttributeEncoder) error {
|
||||
return func(ae *netlink.AttributeEncoder) error {
|
||||
ae.Bytes(wgh.PeerAPublicKey, p.PublicKey[:])
|
||||
|
||||
// Flags are stored in a single attribute.
|
||||
var flags uint32
|
||||
if p.Remove {
|
||||
flags |= wgh.PeerFRemoveMe
|
||||
}
|
||||
if p.ReplaceAllowedIPs {
|
||||
flags |= wgh.PeerFReplaceAllowedips
|
||||
}
|
||||
if p.UpdateOnly {
|
||||
flags |= wgh.PeerFUpdateOnly
|
||||
}
|
||||
if flags != 0 {
|
||||
ae.Uint32(wgh.PeerAFlags, flags)
|
||||
}
|
||||
|
||||
if p.PresharedKey != nil {
|
||||
ae.Bytes(wgh.PeerAPresharedKey, (*p.PresharedKey)[:])
|
||||
}
|
||||
|
||||
if p.Endpoint != nil {
|
||||
ae.Do(wgh.PeerAEndpoint, encodeSockaddr(*p.Endpoint))
|
||||
}
|
||||
|
||||
if p.PersistentKeepaliveInterval != nil {
|
||||
ae.Uint16(wgh.PeerAPersistentKeepaliveInterval, uint16(p.PersistentKeepaliveInterval.Seconds()))
|
||||
}
|
||||
|
||||
// Only apply allowed IPs if necessary.
|
||||
if len(p.AllowedIPs) > 0 {
|
||||
ae.Nested(wgh.PeerAAllowedips, encodeAllowedIPs(p.AllowedIPs))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// encodeSockaddr returns a function which encodes a net.UDPAddr as raw
|
||||
// sockaddr_in or sockaddr_in6 bytes.
|
||||
func encodeSockaddr(endpoint net.UDPAddr) func() ([]byte, error) {
|
||||
return func() ([]byte, error) {
|
||||
if !isValidIP(endpoint.IP) {
|
||||
return nil, fmt.Errorf("wglinux: invalid endpoint IP: %s", endpoint.IP.String())
|
||||
}
|
||||
|
||||
// Is this an IPv6 address?
|
||||
if isIPv6(endpoint.IP) {
|
||||
var addr [16]byte
|
||||
copy(addr[:], endpoint.IP.To16())
|
||||
|
||||
sa := unix.RawSockaddrInet6{
|
||||
Family: unix.AF_INET6,
|
||||
Port: sockaddrPort(endpoint.Port),
|
||||
Addr: addr,
|
||||
}
|
||||
|
||||
return (*(*[unix.SizeofSockaddrInet6]byte)(unsafe.Pointer(&sa)))[:], nil
|
||||
}
|
||||
|
||||
// IPv4 address handling.
|
||||
var addr [4]byte
|
||||
copy(addr[:], endpoint.IP.To4())
|
||||
|
||||
sa := unix.RawSockaddrInet4{
|
||||
Family: unix.AF_INET,
|
||||
Port: sockaddrPort(endpoint.Port),
|
||||
Addr: addr,
|
||||
}
|
||||
|
||||
return (*(*[unix.SizeofSockaddrInet4]byte)(unsafe.Pointer(&sa)))[:], nil
|
||||
}
|
||||
}
|
||||
|
||||
// encodeAllowedIPs returns a function to encode allowed IP nested attributes.
|
||||
func encodeAllowedIPs(ipns []net.IPNet) func(ae *netlink.AttributeEncoder) error {
|
||||
return func(ae *netlink.AttributeEncoder) error {
|
||||
for i, ipn := range ipns {
|
||||
if !isValidIP(ipn.IP) {
|
||||
return fmt.Errorf("wglinux: invalid allowed IP: %s", ipn.IP.String())
|
||||
}
|
||||
|
||||
family := uint16(unix.AF_INET6)
|
||||
if !isIPv6(ipn.IP) {
|
||||
// Make sure address is 4 bytes if IPv4.
|
||||
family = unix.AF_INET
|
||||
ipn.IP = ipn.IP.To4()
|
||||
}
|
||||
|
||||
// Netlink arrays use type as an array index.
|
||||
ae.Nested(uint16(i), func(nae *netlink.AttributeEncoder) error {
|
||||
nae.Uint16(wgh.AllowedipAFamily, family)
|
||||
nae.Bytes(wgh.AllowedipAIpaddr, ipn.IP)
|
||||
|
||||
ones, _ := ipn.Mask.Size()
|
||||
nae.Uint8(wgh.AllowedipACidrMask, uint8(ones))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// isValidIP determines if IP is a valid IPv4 or IPv6 address.
|
||||
func isValidIP(ip net.IP) bool {
|
||||
return ip.To16() != nil
|
||||
}
|
||||
|
||||
// isIPv6 determines if IP is a valid IPv6 address.
|
||||
func isIPv6(ip net.IP) bool {
|
||||
return isValidIP(ip) && ip.To4() == nil
|
||||
}
|
||||
|
||||
// sockaddrPort interprets port as a big endian uint16 for use passing sockaddr
|
||||
// structures to the kernel.
|
||||
func sockaddrPort(port int) uint16 {
|
||||
return binary.BigEndian.Uint16(nlenc.Uint16Bytes(uint16(port)))
|
||||
}
|
6
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/doc.go
generated
vendored
Normal file
6
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/doc.go
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
// Package wglinux provides internal access to Linux's WireGuard generic
|
||||
// netlink interface.
|
||||
//
|
||||
// This package is internal-only and not meant for end users to consume.
|
||||
// Please use package wgctrl (an abstraction over this package) instead.
|
||||
package wglinux
|
99
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/const.go
generated
vendored
Normal file
99
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/const.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
// WARNING: This file has automatically been generated on Tue, 04 May 2021 18:36:46 EDT.
|
||||
// Code generated by https://git.io/c-for-go. DO NOT EDIT.
|
||||
|
||||
package wgh
|
||||
|
||||
const (
|
||||
// GenlName as defined in wgh/wireguard.h:134
|
||||
GenlName = "wireguard"
|
||||
// GenlVersion as defined in wgh/wireguard.h:135
|
||||
GenlVersion = 1
|
||||
// KeyLen as defined in wgh/wireguard.h:137
|
||||
KeyLen = 32
|
||||
// CmdMax as defined in wgh/wireguard.h:144
|
||||
CmdMax = (__CmdMax - 1)
|
||||
// DeviceAMax as defined in wgh/wireguard.h:162
|
||||
DeviceAMax = (_DeviceALast - 1)
|
||||
// PeerAMax as defined in wgh/wireguard.h:185
|
||||
PeerAMax = (_PeerALast - 1)
|
||||
// AllowedipAMax as defined in wgh/wireguard.h:194
|
||||
AllowedipAMax = (_AllowedipALast - 1)
|
||||
)
|
||||
|
||||
// wgCmd as declared in wgh/wireguard.h:139
|
||||
type wgCmd int32
|
||||
|
||||
// wgCmd enumeration from wgh/wireguard.h:139
|
||||
const (
|
||||
CmdGetDevice = iota
|
||||
CmdSetDevice = 1
|
||||
__CmdMax = 2
|
||||
)
|
||||
|
||||
// wgdeviceFlag as declared in wgh/wireguard.h:146
|
||||
type wgdeviceFlag int32
|
||||
|
||||
// wgdeviceFlag enumeration from wgh/wireguard.h:146
|
||||
const (
|
||||
DeviceFReplacePeers = uint32(1) << 0
|
||||
_DeviceFAll = DeviceFReplacePeers
|
||||
)
|
||||
|
||||
// wgdeviceAttribute as declared in wgh/wireguard.h:150
|
||||
type wgdeviceAttribute int32
|
||||
|
||||
// wgdeviceAttribute enumeration from wgh/wireguard.h:150
|
||||
const (
|
||||
DeviceAUnspec = iota
|
||||
DeviceAIfindex = 1
|
||||
DeviceAIfname = 2
|
||||
DeviceAPrivateKey = 3
|
||||
DeviceAPublicKey = 4
|
||||
DeviceAFlags = 5
|
||||
DeviceAListenPort = 6
|
||||
DeviceAFwmark = 7
|
||||
DeviceAPeers = 8
|
||||
_DeviceALast = 9
|
||||
)
|
||||
|
||||
// wgpeerFlag as declared in wgh/wireguard.h:164
|
||||
type wgpeerFlag int32
|
||||
|
||||
// wgpeerFlag enumeration from wgh/wireguard.h:164
|
||||
const (
|
||||
PeerFRemoveMe = uint32(1) << 0
|
||||
PeerFReplaceAllowedips = uint32(1) << 1
|
||||
PeerFUpdateOnly = uint32(1) << 2
|
||||
_PeerFAll = PeerFRemoveMe | PeerFReplaceAllowedips | PeerFUpdateOnly
|
||||
)
|
||||
|
||||
// wgpeerAttribute as declared in wgh/wireguard.h:171
|
||||
type wgpeerAttribute int32
|
||||
|
||||
// wgpeerAttribute enumeration from wgh/wireguard.h:171
|
||||
const (
|
||||
PeerAUnspec = iota
|
||||
PeerAPublicKey = 1
|
||||
PeerAPresharedKey = 2
|
||||
PeerAFlags = 3
|
||||
PeerAEndpoint = 4
|
||||
PeerAPersistentKeepaliveInterval = 5
|
||||
PeerALastHandshakeTime = 6
|
||||
PeerARxBytes = 7
|
||||
PeerATxBytes = 8
|
||||
PeerAAllowedips = 9
|
||||
PeerAProtocolVersion = 10
|
||||
_PeerALast = 11
|
||||
)
|
||||
|
||||
// wgallowedipAttribute as declared in wgh/wireguard.h:187
|
||||
type wgallowedipAttribute int32
|
||||
|
||||
// wgallowedipAttribute enumeration from wgh/wireguard.h:187
|
||||
const (
|
||||
AllowedipAUnspec = iota
|
||||
AllowedipAFamily = 1
|
||||
AllowedipAIpaddr = 2
|
||||
AllowedipACidrMask = 3
|
||||
_AllowedipALast = 4
|
||||
)
|
12
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/doc.go
generated
vendored
Normal file
12
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/doc.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
// Package wgh is an auto-generated package which contains constants and
|
||||
// types used to access WireGuard information using generic netlink.
|
||||
package wgh
|
||||
|
||||
// Pull the latest wireguard.h from GitHub for code generation.
|
||||
//go:generate wget https://raw.githubusercontent.com/torvalds/linux/master/include/uapi/linux/wireguard.h
|
||||
|
||||
// Generate Go source from C constants.
|
||||
//go:generate c-for-go -out ../ -nocgo wgh.yml
|
||||
|
||||
// Clean up build artifacts.
|
||||
//go:generate rm -rf wireguard.h _obj/
|
22
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/wgh.yml
generated
vendored
Normal file
22
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/wgh.yml
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
GENERATOR:
|
||||
PackageName: wgh
|
||||
|
||||
PARSER:
|
||||
IncludePaths: [/usr/include]
|
||||
SourcesPaths: [wireguard.h]
|
||||
|
||||
TRANSLATOR:
|
||||
ConstRules:
|
||||
defines: expand
|
||||
enum: expand
|
||||
Rules:
|
||||
const:
|
||||
- {transform: lower}
|
||||
- {action: accept, from: "(?i)wg_"}
|
||||
- {action: replace, from: "(?i)wg_", to: _}
|
||||
- {action: accept, from: "(?i)wg"}
|
||||
- {action: replace, from: "(?i)wg", to: }
|
||||
- {transform: export}
|
||||
post-global:
|
||||
- {load: snakecase}
|
303
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/parse_linux.go
generated
vendored
Normal file
303
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/parse_linux.go
generated
vendored
Normal file
@ -0,0 +1,303 @@
|
||||
//+build linux
|
||||
|
||||
package wglinux
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/mdlayher/genetlink"
|
||||
"github.com/mdlayher/netlink"
|
||||
"golang.org/x/sys/unix"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
// parseDevice parses a Device from a slice of generic netlink messages,
|
||||
// automatically merging peer lists from subsequent messages into the Device
|
||||
// from the first message.
|
||||
func parseDevice(msgs []genetlink.Message) (*wgtypes.Device, error) {
|
||||
var first wgtypes.Device
|
||||
knownPeers := make(map[wgtypes.Key]int)
|
||||
|
||||
for i, m := range msgs {
|
||||
d, err := parseDeviceLoop(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
// First message contains our target device.
|
||||
first = *d
|
||||
|
||||
// Gather the known peers so that we can merge
|
||||
// them later if needed
|
||||
for i := range first.Peers {
|
||||
knownPeers[first.Peers[i].PublicKey] = i
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Any subsequent messages have their peer contents merged into the
|
||||
// first "target" message.
|
||||
mergeDevices(&first, d, knownPeers)
|
||||
}
|
||||
|
||||
return &first, nil
|
||||
}
|
||||
|
||||
// parseDeviceLoop parses a Device from a single generic netlink message.
|
||||
func parseDeviceLoop(m genetlink.Message) (*wgtypes.Device, error) {
|
||||
ad, err := netlink.NewAttributeDecoder(m.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d := wgtypes.Device{Type: wgtypes.LinuxKernel}
|
||||
for ad.Next() {
|
||||
switch ad.Type() {
|
||||
case wgh.DeviceAIfindex:
|
||||
// Ignored; interface index isn't exposed at all in the userspace
|
||||
// configuration protocol, and name is more friendly anyway.
|
||||
case wgh.DeviceAIfname:
|
||||
d.Name = ad.String()
|
||||
case wgh.DeviceAPrivateKey:
|
||||
ad.Do(parseKey(&d.PrivateKey))
|
||||
case wgh.DeviceAPublicKey:
|
||||
ad.Do(parseKey(&d.PublicKey))
|
||||
case wgh.DeviceAListenPort:
|
||||
d.ListenPort = int(ad.Uint16())
|
||||
case wgh.DeviceAFwmark:
|
||||
d.FirewallMark = int(ad.Uint32())
|
||||
case wgh.DeviceAPeers:
|
||||
// Netlink array of peers.
|
||||
//
|
||||
// Errors while parsing are propagated up to top-level ad.Err check.
|
||||
ad.Nested(func(nad *netlink.AttributeDecoder) error {
|
||||
// Initialize to the number of peers in this decoder and begin
|
||||
// handling nested Peer attributes.
|
||||
d.Peers = make([]wgtypes.Peer, 0, nad.Len())
|
||||
for nad.Next() {
|
||||
nad.Nested(func(nnad *netlink.AttributeDecoder) error {
|
||||
d.Peers = append(d.Peers, parsePeer(nnad))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if err := ad.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
// parseAllowedIPs parses a wgtypes.Peer from a netlink attribute payload.
|
||||
func parsePeer(ad *netlink.AttributeDecoder) wgtypes.Peer {
|
||||
var p wgtypes.Peer
|
||||
for ad.Next() {
|
||||
switch ad.Type() {
|
||||
case wgh.PeerAPublicKey:
|
||||
ad.Do(parseKey(&p.PublicKey))
|
||||
case wgh.PeerAPresharedKey:
|
||||
ad.Do(parseKey(&p.PresharedKey))
|
||||
case wgh.PeerAEndpoint:
|
||||
p.Endpoint = &net.UDPAddr{}
|
||||
ad.Do(parseSockaddr(p.Endpoint))
|
||||
case wgh.PeerAPersistentKeepaliveInterval:
|
||||
p.PersistentKeepaliveInterval = time.Duration(ad.Uint16()) * time.Second
|
||||
case wgh.PeerALastHandshakeTime:
|
||||
ad.Do(parseTimespec(&p.LastHandshakeTime))
|
||||
case wgh.PeerARxBytes:
|
||||
p.ReceiveBytes = int64(ad.Uint64())
|
||||
case wgh.PeerATxBytes:
|
||||
p.TransmitBytes = int64(ad.Uint64())
|
||||
case wgh.PeerAAllowedips:
|
||||
ad.Nested(parseAllowedIPs(&p.AllowedIPs))
|
||||
case wgh.PeerAProtocolVersion:
|
||||
p.ProtocolVersion = int(ad.Uint32())
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// parseAllowedIPs parses a slice of net.IPNet from a netlink attribute payload.
|
||||
func parseAllowedIPs(ipns *[]net.IPNet) func(ad *netlink.AttributeDecoder) error {
|
||||
return func(ad *netlink.AttributeDecoder) error {
|
||||
// Initialize to the number of allowed IPs and begin iterating through
|
||||
// the netlink array to decode each one.
|
||||
*ipns = make([]net.IPNet, 0, ad.Len())
|
||||
for ad.Next() {
|
||||
// Allowed IP nested attributes.
|
||||
ad.Nested(func(nad *netlink.AttributeDecoder) error {
|
||||
var (
|
||||
ipn net.IPNet
|
||||
mask int
|
||||
family int
|
||||
)
|
||||
|
||||
for nad.Next() {
|
||||
switch nad.Type() {
|
||||
case wgh.AllowedipAIpaddr:
|
||||
nad.Do(parseAddr(&ipn.IP))
|
||||
case wgh.AllowedipACidrMask:
|
||||
mask = int(nad.Uint8())
|
||||
case wgh.AllowedipAFamily:
|
||||
family = int(nad.Uint16())
|
||||
}
|
||||
}
|
||||
|
||||
if err := nad.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The address family determines the correct number of bits in
|
||||
// the mask.
|
||||
switch family {
|
||||
case unix.AF_INET:
|
||||
ipn.Mask = net.CIDRMask(mask, 32)
|
||||
case unix.AF_INET6:
|
||||
ipn.Mask = net.CIDRMask(mask, 128)
|
||||
}
|
||||
|
||||
*ipns = append(*ipns, ipn)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// parseKey parses a wgtypes.Key from a byte slice.
|
||||
func parseKey(key *wgtypes.Key) func(b []byte) error {
|
||||
return func(b []byte) error {
|
||||
k, err := wgtypes.NewKey(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*key = k
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// parseAddr parses a net.IP from raw in_addr or in6_addr struct bytes.
|
||||
func parseAddr(ip *net.IP) func(b []byte) error {
|
||||
return func(b []byte) error {
|
||||
switch len(b) {
|
||||
case net.IPv4len, net.IPv6len:
|
||||
// Okay to convert directly to net.IP; memory layout is identical.
|
||||
*ip = make(net.IP, len(b))
|
||||
copy(*ip, b)
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("wglinux: unexpected IP address size: %d", len(b))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parseSockaddr parses a *net.UDPAddr from raw sockaddr_in or sockaddr_in6 bytes.
|
||||
func parseSockaddr(endpoint *net.UDPAddr) func(b []byte) error {
|
||||
return func(b []byte) error {
|
||||
switch len(b) {
|
||||
case unix.SizeofSockaddrInet4:
|
||||
// IPv4 address parsing.
|
||||
sa := *(*unix.RawSockaddrInet4)(unsafe.Pointer(&b[0]))
|
||||
|
||||
*endpoint = net.UDPAddr{
|
||||
IP: net.IP(sa.Addr[:]).To4(),
|
||||
Port: int(sockaddrPort(int(sa.Port))),
|
||||
}
|
||||
|
||||
return nil
|
||||
case unix.SizeofSockaddrInet6:
|
||||
// IPv6 address parsing.
|
||||
sa := *(*unix.RawSockaddrInet6)(unsafe.Pointer(&b[0]))
|
||||
|
||||
*endpoint = net.UDPAddr{
|
||||
IP: net.IP(sa.Addr[:]),
|
||||
Port: int(sockaddrPort(int(sa.Port))),
|
||||
}
|
||||
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("wglinux: unexpected sockaddr size: %d", len(b))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// timespec32 is a unix.Timespec with 32-bit integers.
|
||||
type timespec32 struct {
|
||||
Sec int32
|
||||
Nsec int32
|
||||
}
|
||||
|
||||
// timespec64 is a unix.Timespec with 64-bit integers.
|
||||
type timespec64 struct {
|
||||
Sec int64
|
||||
Nsec int64
|
||||
}
|
||||
|
||||
const (
|
||||
sizeofTimespec32 = int(unsafe.Sizeof(timespec32{}))
|
||||
sizeofTimespec64 = int(unsafe.Sizeof(timespec64{}))
|
||||
)
|
||||
|
||||
// parseTimespec parses a time.Time from raw timespec bytes.
|
||||
func parseTimespec(t *time.Time) func(b []byte) error {
|
||||
return func(b []byte) error {
|
||||
// It would appear that WireGuard can return a __kernel_timespec which
|
||||
// uses 64-bit integers, even on 32-bit platforms. Clarification of this
|
||||
// behavior is being sought in:
|
||||
// https://lists.zx2c4.com/pipermail/wireguard/2019-April/004088.html.
|
||||
//
|
||||
// In the mean time, be liberal and accept 32-bit and 64-bit variants.
|
||||
var sec, nsec int64
|
||||
|
||||
switch len(b) {
|
||||
case sizeofTimespec32:
|
||||
ts := *(*timespec32)(unsafe.Pointer(&b[0]))
|
||||
|
||||
sec = int64(ts.Sec)
|
||||
nsec = int64(ts.Nsec)
|
||||
case sizeofTimespec64:
|
||||
ts := *(*timespec64)(unsafe.Pointer(&b[0]))
|
||||
|
||||
sec = ts.Sec
|
||||
nsec = ts.Nsec
|
||||
default:
|
||||
return fmt.Errorf("wglinux: unexpected timespec size: %d bytes, expected 8 or 16 bytes", len(b))
|
||||
}
|
||||
|
||||
// Only set fields if UNIX timestamp value is greater than 0, so the
|
||||
// caller will see a zero-value time.Time otherwise.
|
||||
if sec > 0 || nsec > 0 {
|
||||
*t = time.Unix(sec, nsec)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// mergeDevices merges Peer information from d into target. mergeDevices is
|
||||
// used to deal with multiple incoming netlink messages for the same device.
|
||||
func mergeDevices(target, d *wgtypes.Device, knownPeers map[wgtypes.Key]int) {
|
||||
for i := range d.Peers {
|
||||
// Peer is already known, append to it's allowed IP networks
|
||||
if peerIndex, ok := knownPeers[d.Peers[i].PublicKey]; ok {
|
||||
target.Peers[peerIndex].AllowedIPs = append(target.Peers[peerIndex].AllowedIPs, d.Peers[i].AllowedIPs...)
|
||||
} else { // New peer, add it to the target peers.
|
||||
target.Peers = append(target.Peers, d.Peers[i])
|
||||
knownPeers[d.Peers[i].PublicKey] = len(target.Peers) - 1
|
||||
}
|
||||
}
|
||||
}
|
372
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/client_openbsd.go
generated
vendored
Normal file
372
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/client_openbsd.go
generated
vendored
Normal file
@ -0,0 +1,372 @@
|
||||
//+build openbsd
|
||||
|
||||
package wgopenbsd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/internal/wginternal"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
var (
|
||||
// ifGroupWG is the WireGuard interface group name passed to the kernel.
|
||||
ifGroupWG = [16]byte{0: 'w', 1: 'g'}
|
||||
)
|
||||
|
||||
var _ wginternal.Client = &Client{}
|
||||
|
||||
// A Client provides access to OpenBSD WireGuard ioctl information.
|
||||
type Client struct {
|
||||
// Hooks which use system calls by default, but can also be swapped out
|
||||
// during tests.
|
||||
close func() error
|
||||
ioctlIfgroupreq func(ifg *wgh.Ifgroupreq) error
|
||||
ioctlWGDataIO func(data *wgh.WGDataIO) error
|
||||
}
|
||||
|
||||
// New creates a new Client and returns whether or not the ioctl interface
|
||||
// is available.
|
||||
func New() (*Client, bool, error) {
|
||||
// The OpenBSD ioctl interface operates on a generic AF_INET socket.
|
||||
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
// TODO(mdlayher): find a call to invoke here to probe for availability.
|
||||
// c.Devices won't work because it returns a "not found" error when the
|
||||
// kernel WireGuard implementation is available but the interface group
|
||||
// has no members.
|
||||
|
||||
// By default, use system call implementations for all hook functions.
|
||||
return &Client{
|
||||
close: func() error { return unix.Close(fd) },
|
||||
ioctlIfgroupreq: ioctlIfgroupreq(fd),
|
||||
ioctlWGDataIO: ioctlWGDataIO(fd),
|
||||
}, true, nil
|
||||
}
|
||||
|
||||
// Close implements wginternal.Client.
|
||||
func (c *Client) Close() error {
|
||||
return c.close()
|
||||
}
|
||||
|
||||
// Devices implements wginternal.Client.
|
||||
func (c *Client) Devices() ([]*wgtypes.Device, error) {
|
||||
ifg := wgh.Ifgroupreq{
|
||||
// Query for devices in the "wg" group.
|
||||
Name: ifGroupWG,
|
||||
}
|
||||
|
||||
// Determine how many device names we must allocate memory for.
|
||||
if err := c.ioctlIfgroupreq(&ifg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// ifg.Len is size in bytes; allocate enough memory for the correct number
|
||||
// of wgh.Ifgreq and then store a pointer to the memory where the data
|
||||
// should be written (ifgrs) in ifg.Groups.
|
||||
//
|
||||
// From a thread in golang-nuts, this pattern is valid:
|
||||
// "It would be OK to pass a pointer to a struct to ioctl if the struct
|
||||
// contains a pointer to other Go memory, but the struct field must have
|
||||
// pointer type."
|
||||
// See: https://groups.google.com/forum/#!topic/golang-nuts/FfasFTZvU_o.
|
||||
ifgrs := make([]wgh.Ifgreq, ifg.Len/wgh.SizeofIfgreq)
|
||||
ifg.Groups = &ifgrs[0]
|
||||
|
||||
// Now actually fetch the device names.
|
||||
if err := c.ioctlIfgroupreq(&ifg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Keep this alive until we're done doing the ioctl dance.
|
||||
runtime.KeepAlive(&ifg)
|
||||
|
||||
devices := make([]*wgtypes.Device, 0, len(ifgrs))
|
||||
for _, ifgr := range ifgrs {
|
||||
// Remove any trailing NULL bytes from the interface names.
|
||||
d, err := c.Device(string(bytes.TrimRight(ifgr.Ifgrqu[:], "\x00")))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
devices = append(devices, d)
|
||||
}
|
||||
|
||||
return devices, nil
|
||||
}
|
||||
|
||||
// Device implements wginternal.Client.
|
||||
func (c *Client) Device(name string) (*wgtypes.Device, error) {
|
||||
dname, err := deviceName(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// First, specify the name of the device and determine how much memory
|
||||
// must be allocated in order to store the WGInterfaceIO structure and
|
||||
// any trailing WGPeerIO/WGAIPIOs.
|
||||
data := wgh.WGDataIO{Name: dname}
|
||||
|
||||
// TODO: consider preallocating some memory to avoid a second system call
|
||||
// if it proves to be a concern.
|
||||
var mem []byte
|
||||
for {
|
||||
if err := c.ioctlWGDataIO(&data); err != nil {
|
||||
// ioctl functions always return a wrapped unix.Errno value.
|
||||
// Conform to the wgctrl contract by unwrapping some values:
|
||||
// ENXIO: "no such device": (no such WireGuard device)
|
||||
// ENOTTY: "inappropriate ioctl for device" (device is not a
|
||||
// WireGuard device)
|
||||
switch err.(*os.SyscallError).Err {
|
||||
case unix.ENXIO, unix.ENOTTY:
|
||||
return nil, os.ErrNotExist
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(mem) >= int(data.Size) {
|
||||
// Allocated enough memory!
|
||||
break
|
||||
}
|
||||
|
||||
// Ensure we don't unsafe cast into uninitialized memory. We need at very
|
||||
// least a single WGInterfaceIO with no peers.
|
||||
if data.Size < wgh.SizeofWGInterfaceIO {
|
||||
return nil, fmt.Errorf("wgopenbsd: kernel returned unexpected number of bytes for WGInterfaceIO: %d", data.Size)
|
||||
}
|
||||
|
||||
// Allocate the appropriate amount of memory and point the kernel at
|
||||
// the first byte of our slice's backing array. When the loop continues,
|
||||
// we will check if we've allocated enough memory.
|
||||
mem = make([]byte, data.Size)
|
||||
data.Interface = (*wgh.WGInterfaceIO)(unsafe.Pointer(&mem[0]))
|
||||
}
|
||||
|
||||
return parseDevice(name, data.Interface)
|
||||
}
|
||||
|
||||
// parseDevice unpacks a Device from ifio, along with its associated peers
|
||||
// and their allowed IPs.
|
||||
func parseDevice(name string, ifio *wgh.WGInterfaceIO) (*wgtypes.Device, error) {
|
||||
d := &wgtypes.Device{
|
||||
Name: name,
|
||||
Type: wgtypes.OpenBSDKernel,
|
||||
}
|
||||
|
||||
// The kernel populates ifio.Flags to indicate which fields are present.
|
||||
|
||||
if ifio.Flags&wgh.WG_INTERFACE_HAS_PRIVATE != 0 {
|
||||
d.PrivateKey = wgtypes.Key(ifio.Private)
|
||||
}
|
||||
|
||||
if ifio.Flags&wgh.WG_INTERFACE_HAS_PUBLIC != 0 {
|
||||
d.PublicKey = wgtypes.Key(ifio.Public)
|
||||
}
|
||||
|
||||
if ifio.Flags&wgh.WG_INTERFACE_HAS_PORT != 0 {
|
||||
d.ListenPort = int(ifio.Port)
|
||||
}
|
||||
|
||||
if ifio.Flags&wgh.WG_INTERFACE_HAS_RTABLE != 0 {
|
||||
d.FirewallMark = int(ifio.Rtable)
|
||||
}
|
||||
|
||||
d.Peers = make([]wgtypes.Peer, 0, ifio.Peers_count)
|
||||
|
||||
// If there were no peers, exit early so we do not advance the pointer
|
||||
// beyond the end of the WGInterfaceIO structure.
|
||||
if ifio.Peers_count == 0 {
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// Set our pointer to the beginning of the first peer's location in memory.
|
||||
peer := (*wgh.WGPeerIO)(unsafe.Pointer(
|
||||
uintptr(unsafe.Pointer(ifio)) + wgh.SizeofWGInterfaceIO,
|
||||
))
|
||||
|
||||
for i := 0; i < int(ifio.Peers_count); i++ {
|
||||
p := parsePeer(peer)
|
||||
|
||||
// Same idea, we know how many allowed IPs we need to account for, so
|
||||
// reserve the space and advance the pointer through each WGAIP structure.
|
||||
p.AllowedIPs = make([]net.IPNet, 0, peer.Aips_count)
|
||||
for j := uintptr(0); j < uintptr(peer.Aips_count); j++ {
|
||||
aip := (*wgh.WGAIPIO)(unsafe.Pointer(
|
||||
uintptr(unsafe.Pointer(peer)) + wgh.SizeofWGPeerIO + j*wgh.SizeofWGAIPIO,
|
||||
))
|
||||
|
||||
p.AllowedIPs = append(p.AllowedIPs, parseAllowedIP(aip))
|
||||
}
|
||||
|
||||
// Prepare for the next iteration.
|
||||
d.Peers = append(d.Peers, p)
|
||||
peer = (*wgh.WGPeerIO)(unsafe.Pointer(
|
||||
uintptr(unsafe.Pointer(peer)) + wgh.SizeofWGPeerIO +
|
||||
uintptr(peer.Aips_count)*wgh.SizeofWGAIPIO,
|
||||
))
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// ConfigureDevice implements wginternal.Client.
|
||||
func (c *Client) ConfigureDevice(name string, cfg wgtypes.Config) error {
|
||||
// Currently read-only: we must determine if a device belongs to this driver,
|
||||
// and if it does, return a sentinel so integration tests that configure a
|
||||
// device can be skipped.
|
||||
if _, err := c.Device(name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return wginternal.ErrReadOnly
|
||||
}
|
||||
|
||||
// deviceName converts an interface name string to the format required to pass
|
||||
// with wgh.WGGetServ.
|
||||
func deviceName(name string) ([16]byte, error) {
|
||||
var out [unix.IFNAMSIZ]byte
|
||||
if len(name) > unix.IFNAMSIZ {
|
||||
return out, fmt.Errorf("wgopenbsd: interface name %q too long", name)
|
||||
}
|
||||
|
||||
copy(out[:], name)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// parsePeer unpacks a wgtypes.Peer from a WGPeerIO structure.
|
||||
func parsePeer(pio *wgh.WGPeerIO) wgtypes.Peer {
|
||||
p := wgtypes.Peer{
|
||||
ReceiveBytes: int64(pio.Rxbytes),
|
||||
TransmitBytes: int64(pio.Txbytes),
|
||||
ProtocolVersion: int(pio.Protocol_version),
|
||||
}
|
||||
|
||||
// Only set last handshake if a non-zero timespec was provided, matching
|
||||
// the time.Time.IsZero() behavior of internal/wglinux.
|
||||
if pio.Last_handshake.Sec > 0 && pio.Last_handshake.Nsec > 0 {
|
||||
p.LastHandshakeTime = time.Unix(
|
||||
pio.Last_handshake.Sec,
|
||||
// Conversion required for GOARCH=386.
|
||||
int64(pio.Last_handshake.Nsec),
|
||||
)
|
||||
}
|
||||
|
||||
if pio.Flags&wgh.WG_PEER_HAS_PUBLIC != 0 {
|
||||
p.PublicKey = wgtypes.Key(pio.Public)
|
||||
}
|
||||
|
||||
if pio.Flags&wgh.WG_PEER_HAS_PSK != 0 {
|
||||
p.PresharedKey = wgtypes.Key(pio.Psk)
|
||||
}
|
||||
|
||||
if pio.Flags&wgh.WG_PEER_HAS_PKA != 0 {
|
||||
p.PersistentKeepaliveInterval = time.Duration(pio.Pka) * time.Second
|
||||
}
|
||||
|
||||
if pio.Flags&wgh.WG_PEER_HAS_ENDPOINT != 0 {
|
||||
p.Endpoint = parseEndpoint(pio.Endpoint)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// parseAllowedIP unpacks a net.IPNet from a WGAIP structure.
|
||||
func parseAllowedIP(aip *wgh.WGAIPIO) net.IPNet {
|
||||
switch aip.Af {
|
||||
case unix.AF_INET:
|
||||
return net.IPNet{
|
||||
IP: net.IP(aip.Addr[:net.IPv4len]),
|
||||
Mask: net.CIDRMask(int(aip.Cidr), 32),
|
||||
}
|
||||
case unix.AF_INET6:
|
||||
return net.IPNet{
|
||||
IP: net.IP(aip.Addr[:]),
|
||||
Mask: net.CIDRMask(int(aip.Cidr), 128),
|
||||
}
|
||||
default:
|
||||
panicf("wgopenbsd: invalid address family for allowed IP: %+v", aip)
|
||||
return net.IPNet{}
|
||||
}
|
||||
}
|
||||
|
||||
// parseEndpoint parses a peer endpoint from a wgh.WGIP structure.
|
||||
func parseEndpoint(ep [28]byte) *net.UDPAddr {
|
||||
// sockaddr* structures have family at index 1.
|
||||
switch ep[1] {
|
||||
case unix.AF_INET:
|
||||
sa := *(*unix.RawSockaddrInet4)(unsafe.Pointer(&ep[0]))
|
||||
|
||||
ep := &net.UDPAddr{
|
||||
IP: make(net.IP, net.IPv4len),
|
||||
Port: bePort(sa.Port),
|
||||
}
|
||||
copy(ep.IP, sa.Addr[:])
|
||||
|
||||
return ep
|
||||
case unix.AF_INET6:
|
||||
sa := *(*unix.RawSockaddrInet6)(unsafe.Pointer(&ep[0]))
|
||||
|
||||
// TODO(mdlayher): IPv6 zone?
|
||||
ep := &net.UDPAddr{
|
||||
IP: make(net.IP, net.IPv6len),
|
||||
Port: bePort(sa.Port),
|
||||
}
|
||||
copy(ep.IP, sa.Addr[:])
|
||||
|
||||
return ep
|
||||
default:
|
||||
// No endpoint configured.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// bePort interprets a port integer stored in native endianness as a big
|
||||
// endian value. This is necessary for proper endpoint port handling on
|
||||
// little endian machines.
|
||||
func bePort(port uint16) int {
|
||||
b := *(*[2]byte)(unsafe.Pointer(&port))
|
||||
return int(binary.BigEndian.Uint16(b[:]))
|
||||
}
|
||||
|
||||
// ioctlIfgroupreq returns a function which performs the appropriate ioctl on
|
||||
// fd to retrieve members of an interface group.
|
||||
func ioctlIfgroupreq(fd int) func(*wgh.Ifgroupreq) error {
|
||||
return func(ifg *wgh.Ifgroupreq) error {
|
||||
return ioctl(fd, wgh.SIOCGIFGMEMB, unsafe.Pointer(ifg))
|
||||
}
|
||||
}
|
||||
|
||||
// ioctlWGDataIO returns a function which performs the appropriate ioctl on
|
||||
// fd to issue a WireGuard data I/O.
|
||||
func ioctlWGDataIO(fd int) func(*wgh.WGDataIO) error {
|
||||
return func(data *wgh.WGDataIO) error {
|
||||
return ioctl(fd, wgh.SIOCGWG, unsafe.Pointer(data))
|
||||
}
|
||||
}
|
||||
|
||||
// ioctl is a raw wrapper for the ioctl system call.
|
||||
func ioctl(fd int, req uint, arg unsafe.Pointer) error {
|
||||
_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
|
||||
if errno != 0 {
|
||||
return os.NewSyscallError("ioctl", errno)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func panicf(format string, a ...interface{}) {
|
||||
panic(fmt.Sprintf(format, a...))
|
||||
}
|
6
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/doc.go
generated
vendored
Normal file
6
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/doc.go
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
// Package wgopenbsd provides internal access to OpenBSD's WireGuard
|
||||
// ioctl interface.
|
||||
//
|
||||
// This package is internal-only and not meant for end users to consume.
|
||||
// Please use package wgctrl (an abstraction over this package) instead.
|
||||
package wgopenbsd
|
83
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/defs_openbsd_386.go
generated
vendored
Normal file
83
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/defs_openbsd_386.go
generated
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
//+build openbsd,386
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs defs.go
|
||||
|
||||
package wgh
|
||||
|
||||
const (
|
||||
SIOCGIFGMEMB = 0xc024698a
|
||||
|
||||
SizeofIfgreq = 0x10
|
||||
)
|
||||
|
||||
type Ifgroupreq struct {
|
||||
Name [16]byte
|
||||
Len uint32
|
||||
Pad1 [0]byte
|
||||
Groups *Ifgreq
|
||||
Pad2 [12]byte
|
||||
}
|
||||
|
||||
type Ifgreq struct {
|
||||
Ifgrqu [16]byte
|
||||
}
|
||||
|
||||
type Timespec struct {
|
||||
Sec int64
|
||||
Nsec int32
|
||||
}
|
||||
|
||||
type WGAIPIO struct {
|
||||
Af uint8
|
||||
Cidr int32
|
||||
Addr [16]byte
|
||||
}
|
||||
|
||||
type WGDataIO struct {
|
||||
Name [16]byte
|
||||
Size uint32
|
||||
Interface *WGInterfaceIO
|
||||
}
|
||||
|
||||
type WGInterfaceIO struct {
|
||||
Flags uint8
|
||||
Port uint16
|
||||
Rtable int32
|
||||
Public [32]byte
|
||||
Private [32]byte
|
||||
Peers_count uint32
|
||||
}
|
||||
|
||||
type WGPeerIO struct {
|
||||
Flags int32
|
||||
Protocol_version int32
|
||||
Public [32]byte
|
||||
Psk [32]byte
|
||||
Pka uint16
|
||||
Pad_cgo_0 [2]byte
|
||||
Endpoint [28]byte
|
||||
Txbytes uint64
|
||||
Rxbytes uint64
|
||||
Last_handshake Timespec
|
||||
Aips_count uint32
|
||||
}
|
||||
|
||||
const (
|
||||
SIOCGWG = 0xc01869d3
|
||||
|
||||
WG_INTERFACE_HAS_PUBLIC = 0x1
|
||||
WG_INTERFACE_HAS_PRIVATE = 0x2
|
||||
WG_INTERFACE_HAS_PORT = 0x4
|
||||
WG_INTERFACE_HAS_RTABLE = 0x8
|
||||
WG_INTERFACE_REPLACE_PEERS = 0x10
|
||||
|
||||
WG_PEER_HAS_PUBLIC = 0x1
|
||||
WG_PEER_HAS_PSK = 0x2
|
||||
WG_PEER_HAS_PKA = 0x4
|
||||
WG_PEER_HAS_ENDPOINT = 0x8
|
||||
|
||||
SizeofWGAIPIO = 0x18
|
||||
SizeofWGInterfaceIO = 0x4c
|
||||
SizeofWGPeerIO = 0x88
|
||||
)
|
83
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/defs_openbsd_amd64.go
generated
vendored
Normal file
83
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/defs_openbsd_amd64.go
generated
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
//+build openbsd,amd64
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs defs.go
|
||||
|
||||
package wgh
|
||||
|
||||
const (
|
||||
SIOCGIFGMEMB = 0xc028698a
|
||||
|
||||
SizeofIfgreq = 0x10
|
||||
)
|
||||
|
||||
type Ifgroupreq struct {
|
||||
Name [16]byte
|
||||
Len uint32
|
||||
Pad1 [4]byte
|
||||
Groups *Ifgreq
|
||||
Pad2 [8]byte
|
||||
}
|
||||
|
||||
type Ifgreq struct {
|
||||
Ifgrqu [16]byte
|
||||
}
|
||||
|
||||
type Timespec struct {
|
||||
Sec int64
|
||||
Nsec int64
|
||||
}
|
||||
|
||||
type WGAIPIO struct {
|
||||
Af uint8
|
||||
Cidr int32
|
||||
Addr [16]byte
|
||||
}
|
||||
|
||||
type WGDataIO struct {
|
||||
Name [16]byte
|
||||
Size uint64
|
||||
Interface *WGInterfaceIO
|
||||
}
|
||||
|
||||
type WGInterfaceIO struct {
|
||||
Flags uint8
|
||||
Port uint16
|
||||
Rtable int32
|
||||
Public [32]byte
|
||||
Private [32]byte
|
||||
Peers_count uint64
|
||||
}
|
||||
|
||||
type WGPeerIO struct {
|
||||
Flags int32
|
||||
Protocol_version int32
|
||||
Public [32]byte
|
||||
Psk [32]byte
|
||||
Pka uint16
|
||||
Pad_cgo_0 [2]byte
|
||||
Endpoint [28]byte
|
||||
Txbytes uint64
|
||||
Rxbytes uint64
|
||||
Last_handshake Timespec
|
||||
Aips_count uint64
|
||||
}
|
||||
|
||||
const (
|
||||
SIOCGWG = 0xc02069d3
|
||||
|
||||
WG_INTERFACE_HAS_PUBLIC = 0x1
|
||||
WG_INTERFACE_HAS_PRIVATE = 0x2
|
||||
WG_INTERFACE_HAS_PORT = 0x4
|
||||
WG_INTERFACE_HAS_RTABLE = 0x8
|
||||
WG_INTERFACE_REPLACE_PEERS = 0x10
|
||||
|
||||
WG_PEER_HAS_PUBLIC = 0x1
|
||||
WG_PEER_HAS_PSK = 0x2
|
||||
WG_PEER_HAS_PKA = 0x4
|
||||
WG_PEER_HAS_ENDPOINT = 0x8
|
||||
|
||||
SizeofWGAIPIO = 0x18
|
||||
SizeofWGInterfaceIO = 0x50
|
||||
SizeofWGPeerIO = 0x90
|
||||
)
|
3
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/doc.go
generated
vendored
Normal file
3
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/doc.go
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
// Package wgh is an auto-generated package which contains constants and
|
||||
// types used to access WireGuard information using ioctl calls.
|
||||
package wgh
|
25
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/generate.sh
generated
vendored
Normal file
25
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/generate.sh
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
#/bin/sh
|
||||
|
||||
set -x
|
||||
|
||||
# Fix up generated code.
|
||||
gofix()
|
||||
{
|
||||
IN=$1
|
||||
OUT=$2
|
||||
|
||||
# Change types that are a nuisance to deal with in Go, use byte for
|
||||
# consistency, and produce gofmt'd output.
|
||||
sed 's/]u*int8/]byte/g' $1 | gofmt -s > $2
|
||||
}
|
||||
|
||||
echo -e "//+build openbsd,amd64\n" > /tmp/wgamd64.go
|
||||
GOARCH=amd64 go tool cgo -godefs defs.go >> /tmp/wgamd64.go
|
||||
|
||||
echo -e "//+build openbsd,386\n" > /tmp/wg386.go
|
||||
GOARCH=386 go tool cgo -godefs defs.go >> /tmp/wg386.go
|
||||
|
||||
gofix /tmp/wgamd64.go defs_openbsd_amd64.go
|
||||
gofix /tmp/wg386.go defs_openbsd_386.go
|
||||
|
||||
rm -rf _obj/ /tmp/wg*.go
|
99
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/client.go
generated
vendored
Normal file
99
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/client.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
package wguser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.zx2c4.com/wireguard/wgctrl/internal/wginternal"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
var _ wginternal.Client = &Client{}
|
||||
|
||||
// A Client provides access to userspace WireGuard device information.
|
||||
type Client struct {
|
||||
dial func(device string) (net.Conn, error)
|
||||
find func() ([]string, error)
|
||||
}
|
||||
|
||||
// New creates a new Client.
|
||||
func New() (*Client, error) {
|
||||
return &Client{
|
||||
// Operating system-specific functions which can identify and connect
|
||||
// to userspace WireGuard devices. These functions can also be
|
||||
// overridden for tests.
|
||||
dial: dial,
|
||||
find: find,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Close implements wginternal.Client.
|
||||
func (c *Client) Close() error { return nil }
|
||||
|
||||
// Devices implements wginternal.Client.
|
||||
func (c *Client) Devices() ([]*wgtypes.Device, error) {
|
||||
devices, err := c.find()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var wgds []*wgtypes.Device
|
||||
for _, d := range devices {
|
||||
wgd, err := c.getDevice(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wgds = append(wgds, wgd)
|
||||
}
|
||||
|
||||
return wgds, nil
|
||||
}
|
||||
|
||||
// Device implements wginternal.Client.
|
||||
func (c *Client) Device(name string) (*wgtypes.Device, error) {
|
||||
devices, err := c.find()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, d := range devices {
|
||||
if name != deviceName(d) {
|
||||
continue
|
||||
}
|
||||
|
||||
return c.getDevice(d)
|
||||
}
|
||||
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
|
||||
// ConfigureDevice implements wginternal.Client.
|
||||
func (c *Client) ConfigureDevice(name string, cfg wgtypes.Config) error {
|
||||
devices, err := c.find()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, d := range devices {
|
||||
if name != deviceName(d) {
|
||||
continue
|
||||
}
|
||||
|
||||
return c.configureDevice(d, cfg)
|
||||
}
|
||||
|
||||
return os.ErrNotExist
|
||||
}
|
||||
|
||||
// deviceName infers a device name from an absolute file path with extension.
|
||||
func deviceName(sock string) string {
|
||||
return strings.TrimSuffix(filepath.Base(sock), filepath.Ext(sock))
|
||||
}
|
||||
|
||||
func panicf(format string, a ...interface{}) {
|
||||
panic(fmt.Sprintf(format, a...))
|
||||
}
|
106
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/configure.go
generated
vendored
Normal file
106
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/configure.go
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
package wguser
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
// configureDevice configures a device specified by its path.
|
||||
func (c *Client) configureDevice(device string, cfg wgtypes.Config) error {
|
||||
conn, err := c.dial(device)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// Start with set command.
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString("set=1\n")
|
||||
|
||||
// Add any necessary configuration from cfg, then finish with an empty line.
|
||||
writeConfig(&buf, cfg)
|
||||
buf.WriteString("\n")
|
||||
|
||||
// Apply configuration for the device and then check the error number.
|
||||
if _, err := io.Copy(conn, &buf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res := make([]byte, 32)
|
||||
n, err := conn.Read(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// errno=0 indicates success, anything else returns an error number that
|
||||
// matches definitions from errno.h.
|
||||
str := strings.TrimSpace(string(res[:n]))
|
||||
if str != "errno=0" {
|
||||
// TODO(mdlayher): return actual errno on Linux?
|
||||
return os.NewSyscallError("read", fmt.Errorf("wguser: %s", str))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeConfig writes textual configuration to w as specified by cfg.
|
||||
func writeConfig(w io.Writer, cfg wgtypes.Config) {
|
||||
if cfg.PrivateKey != nil {
|
||||
fmt.Fprintf(w, "private_key=%s\n", hexKey(*cfg.PrivateKey))
|
||||
}
|
||||
|
||||
if cfg.ListenPort != nil {
|
||||
fmt.Fprintf(w, "listen_port=%d\n", *cfg.ListenPort)
|
||||
}
|
||||
|
||||
if cfg.FirewallMark != nil {
|
||||
fmt.Fprintf(w, "fwmark=%d\n", *cfg.FirewallMark)
|
||||
}
|
||||
|
||||
if cfg.ReplacePeers {
|
||||
fmt.Fprintln(w, "replace_peers=true")
|
||||
}
|
||||
|
||||
for _, p := range cfg.Peers {
|
||||
fmt.Fprintf(w, "public_key=%s\n", hexKey(p.PublicKey))
|
||||
|
||||
if p.Remove {
|
||||
fmt.Fprintln(w, "remove=true")
|
||||
}
|
||||
|
||||
if p.UpdateOnly {
|
||||
fmt.Fprintln(w, "update_only=true")
|
||||
}
|
||||
|
||||
if p.PresharedKey != nil {
|
||||
fmt.Fprintf(w, "preshared_key=%s\n", hexKey(*p.PresharedKey))
|
||||
}
|
||||
|
||||
if p.Endpoint != nil {
|
||||
fmt.Fprintf(w, "endpoint=%s\n", p.Endpoint.String())
|
||||
}
|
||||
|
||||
if p.PersistentKeepaliveInterval != nil {
|
||||
fmt.Fprintf(w, "persistent_keepalive_interval=%d\n", int(p.PersistentKeepaliveInterval.Seconds()))
|
||||
}
|
||||
|
||||
if p.ReplaceAllowedIPs {
|
||||
fmt.Fprintln(w, "replace_allowed_ips=true")
|
||||
}
|
||||
|
||||
for _, ip := range p.AllowedIPs {
|
||||
fmt.Fprintf(w, "allowed_ip=%s\n", ip.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// hexKey encodes a wgtypes.Key into a hexadecimal string.
|
||||
func hexKey(k wgtypes.Key) string {
|
||||
return hex.EncodeToString(k[:])
|
||||
}
|
50
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/conn_unix.go
generated
vendored
Normal file
50
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/conn_unix.go
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
//+build !windows
|
||||
|
||||
package wguser
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// dial is the default implementation of Client.dial.
|
||||
func dial(device string) (net.Conn, error) {
|
||||
return net.Dial("unix", device)
|
||||
}
|
||||
|
||||
// find is the default implementation of Client.find.
|
||||
func find() ([]string, error) {
|
||||
return findUNIXSockets([]string{
|
||||
// It seems that /var/run is a common location between Linux and the
|
||||
// BSDs, even though it's a symlink on Linux.
|
||||
"/var/run/wireguard",
|
||||
})
|
||||
}
|
||||
|
||||
// findUNIXSockets looks for UNIX socket files in the specified directories.
|
||||
func findUNIXSockets(dirs []string) ([]string, error) {
|
||||
var socks []string
|
||||
for _, d := range dirs {
|
||||
files, err := ioutil.ReadDir(d)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
continue
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
if f.Mode()&os.ModeSocket == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
socks = append(socks, filepath.Join(d, f.Name()))
|
||||
}
|
||||
}
|
||||
|
||||
return socks, nil
|
||||
}
|
252
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/conn_windows.go
generated
vendored
Normal file
252
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/conn_windows.go
generated
vendored
Normal file
@ -0,0 +1,252 @@
|
||||
//+build windows
|
||||
|
||||
package wguser
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wireguard/ipc/winpipe"
|
||||
)
|
||||
|
||||
// Expected prefixes when dealing with named pipes.
|
||||
const (
|
||||
pipePrefix = `\\.\pipe\`
|
||||
wgPrefix = `ProtectedPrefix\Administrators\WireGuard\`
|
||||
)
|
||||
|
||||
// dial is the default implementation of Client.dial.
|
||||
func dial(device string) (net.Conn, error) {
|
||||
// Thanks to @zx2c4 for the sample code that makes this possible:
|
||||
// https://github.com/WireGuard/wgctrl-go/issues/36#issuecomment-491912143.
|
||||
//
|
||||
// See also:
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/secauthz/impersonation-tokens
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-reverttoself
|
||||
//
|
||||
// All of these operations require a locked OS thread for the duration of
|
||||
// this function. Once the pipe is opened successfully, RevertToSelf
|
||||
// terminates the impersonation of a client application.
|
||||
runtime.LockOSThread()
|
||||
defer func() {
|
||||
// Terminate the token impersonation operation. Per the Microsoft
|
||||
// documentation, the process should shut down if RevertToSelf fails.
|
||||
if err := windows.RevertToSelf(); err != nil {
|
||||
panicf("wguser: failed to terminate token impersonation, panicking per Microsoft recommendation: %v", err)
|
||||
}
|
||||
|
||||
runtime.UnlockOSThread()
|
||||
}()
|
||||
|
||||
privileges := windows.Tokenprivileges{
|
||||
PrivilegeCount: 1,
|
||||
Privileges: [1]windows.LUIDAndAttributes{
|
||||
{
|
||||
Attributes: windows.SE_PRIVILEGE_ENABLED,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := windows.LookupPrivilegeValue(
|
||||
nil,
|
||||
windows.StringToUTF16Ptr("SeDebugPrivilege"),
|
||||
&privileges.Privileges[0].Luid,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
processes, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer windows.CloseHandle(processes)
|
||||
|
||||
e := windows.ProcessEntry32{
|
||||
Size: uint32(unsafe.Sizeof(windows.ProcessEntry32{})),
|
||||
}
|
||||
|
||||
// Iterate the process list looking for any processes named winlogon.exe.
|
||||
//
|
||||
// It is possible for an attacker to attempt a denial of service of this
|
||||
// application by creating bogus processes with that name, so we must
|
||||
// attempt dialing a connection for each matching process until we either
|
||||
// succeed or run out of processes to try.
|
||||
//
|
||||
// It is unlikely that an attacker's process could appear before the true
|
||||
// winlogon.exe in this list, but better safe than sorry.
|
||||
for err := windows.Process32First(processes, &e); ; err = windows.Process32Next(processes, &e) {
|
||||
// Handle any errors from process list iteration.
|
||||
switch err {
|
||||
case nil:
|
||||
// Keep iterating processes.
|
||||
case windows.ERROR_NO_MORE_FILES:
|
||||
// No more files to check.
|
||||
return nil, errors.New("wguser: unable to find suitable winlogon.exe process to communicate with WireGuard")
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if strings.ToLower(windows.UTF16ToString(e.ExeFile[:])) != "winlogon.exe" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Can we communicate with the device by impersonating this process?
|
||||
c, err := tryDial(device, e.ProcessID, privileges)
|
||||
switch {
|
||||
case err == nil:
|
||||
// Success, use this connection.
|
||||
return c, nil
|
||||
case os.IsPermission(err):
|
||||
// We found a process named winlogon.exe that doesn't have permission
|
||||
// to open a handle to the WireGuard device. Skip it and keep trying.
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tryDial attempts to impersonate the security token of pid to dial device.
|
||||
// tryDial _must_ only be invoked by dial.
|
||||
func tryDial(device string, pid uint32, privileges windows.Tokenprivileges) (net.Conn, error) {
|
||||
// Revert to normal thread state before attempting any further manipulation.
|
||||
// See comment in dial about the panic.
|
||||
if err := windows.RevertToSelf(); err != nil {
|
||||
panicf("wguser: failed to terminate token impersonation, panicking per Microsoft recommendation: %v", err)
|
||||
}
|
||||
|
||||
if err := windows.ImpersonateSelf(windows.SecurityImpersonation); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
thread, err := windows.GetCurrentThread()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer windows.CloseHandle(thread)
|
||||
|
||||
var ttok windows.Token
|
||||
err = windows.OpenThreadToken(
|
||||
thread,
|
||||
windows.TOKEN_ADJUST_PRIVILEGES,
|
||||
false,
|
||||
&ttok,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer ttok.Close()
|
||||
|
||||
err = windows.AdjustTokenPrivileges(
|
||||
ttok,
|
||||
false,
|
||||
&privileges,
|
||||
uint32(unsafe.Sizeof(privileges)),
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
proc, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer windows.CloseHandle(proc)
|
||||
|
||||
var ptok windows.Token
|
||||
err = windows.OpenProcessToken(
|
||||
proc,
|
||||
windows.TOKEN_IMPERSONATE|windows.TOKEN_DUPLICATE,
|
||||
&ptok,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer ptok.Close()
|
||||
|
||||
var dup windows.Token
|
||||
err = windows.DuplicateTokenEx(
|
||||
ptok,
|
||||
0,
|
||||
nil,
|
||||
windows.SecurityImpersonation,
|
||||
windows.TokenImpersonation,
|
||||
&dup,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer dup.Close()
|
||||
|
||||
if err := windows.SetThreadToken(nil, dup); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
localSystem, err := windows.CreateWellKnownSid(windows.WinLocalSystemSid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pipeCfg := &winpipe.DialConfig{
|
||||
ExpectedOwner: localSystem,
|
||||
}
|
||||
return winpipe.Dial(device, nil, pipeCfg)
|
||||
}
|
||||
|
||||
// find is the default implementation of Client.find.
|
||||
func find() ([]string, error) {
|
||||
return findNamedPipes(wgPrefix)
|
||||
}
|
||||
|
||||
// findNamedPipes looks for Windows named pipes that match the specified
|
||||
// search string prefix.
|
||||
func findNamedPipes(search string) ([]string, error) {
|
||||
var (
|
||||
pipes []string
|
||||
data windows.Win32finddata
|
||||
)
|
||||
|
||||
// Thanks @zx2c4 for the tips on the appropriate Windows APIs here:
|
||||
// https://א.cc/dHGpnhxX/c.
|
||||
h, err := windows.FindFirstFile(
|
||||
// Append * to find all named pipes.
|
||||
windows.StringToUTF16Ptr(pipePrefix+"*"),
|
||||
&data,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// FindClose is used to close file search handles instead of the typical
|
||||
// CloseHandle used elsewhere, see:
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-findclose.
|
||||
defer windows.FindClose(h)
|
||||
|
||||
// Check the first file's name for a match, but also keep searching for
|
||||
// WireGuard named pipes until no more files can be iterated.
|
||||
for {
|
||||
name := windows.UTF16ToString(data.FileName[:])
|
||||
if strings.HasPrefix(name, search) {
|
||||
// Concatenate strings directly as filepath.Join appears to break the
|
||||
// named pipe prefix convention.
|
||||
pipes = append(pipes, pipePrefix+name)
|
||||
}
|
||||
|
||||
if err := windows.FindNextFile(h, &data); err != nil {
|
||||
if err == windows.ERROR_NO_MORE_FILES {
|
||||
break
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return pipes, nil
|
||||
}
|
6
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/doc.go
generated
vendored
Normal file
6
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/doc.go
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
// Package wguser provides internal access to the userspace WireGuard
|
||||
// configuration protocol interface.
|
||||
//
|
||||
// This package is internal-only and not meant for end users to consume.
|
||||
// Please use package wgctrl (an abstraction over this package) instead.
|
||||
package wguser
|
258
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/parse.go
generated
vendored
Normal file
258
vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/parse.go
generated
vendored
Normal file
@ -0,0 +1,258 @@
|
||||
package wguser
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
// The WireGuard userspace configuration protocol is described here:
|
||||
// https://www.wireguard.com/xplatform/#cross-platform-userspace-implementation.
|
||||
|
||||
// getDevice gathers device information from a device specified by its path
|
||||
// and returns a Device.
|
||||
func (c *Client) getDevice(device string) (*wgtypes.Device, error) {
|
||||
conn, err := c.dial(device)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// Get information about this device.
|
||||
if _, err := io.WriteString(conn, "get=1\n\n"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Parse the device from the incoming data stream.
|
||||
d, err := parseDevice(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO(mdlayher): populate interface index too?
|
||||
d.Name = deviceName(device)
|
||||
d.Type = wgtypes.Userspace
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// parseDevice parses a Device and its Peers from an io.Reader.
|
||||
func parseDevice(r io.Reader) (*wgtypes.Device, error) {
|
||||
var dp deviceParser
|
||||
s := bufio.NewScanner(r)
|
||||
for s.Scan() {
|
||||
b := s.Bytes()
|
||||
if len(b) == 0 {
|
||||
// Empty line, done parsing.
|
||||
break
|
||||
}
|
||||
|
||||
// All data is in key=value format.
|
||||
kvs := bytes.Split(b, []byte("="))
|
||||
if len(kvs) != 2 {
|
||||
return nil, fmt.Errorf("wguser: invalid key=value pair: %q", string(b))
|
||||
}
|
||||
|
||||
dp.Parse(string(kvs[0]), string(kvs[1]))
|
||||
}
|
||||
|
||||
if err := s.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dp.Device()
|
||||
}
|
||||
|
||||
// A deviceParser accumulates information about a Device and its Peers.
|
||||
type deviceParser struct {
|
||||
d wgtypes.Device
|
||||
err error
|
||||
|
||||
parsePeers bool
|
||||
peers int
|
||||
hsSec, hsNano int
|
||||
}
|
||||
|
||||
// Device returns a Device or any errors that were encountered while parsing
|
||||
// a Device.
|
||||
func (dp *deviceParser) Device() (*wgtypes.Device, error) {
|
||||
if dp.err != nil {
|
||||
return nil, dp.err
|
||||
}
|
||||
|
||||
// Compute remaining fields of the Device now that all parsing is done.
|
||||
dp.d.PublicKey = dp.d.PrivateKey.PublicKey()
|
||||
|
||||
return &dp.d, nil
|
||||
}
|
||||
|
||||
// Parse parses a single key/value pair into fields of a Device.
|
||||
func (dp *deviceParser) Parse(key, value string) {
|
||||
switch key {
|
||||
case "errno":
|
||||
// 0 indicates success, anything else returns an error number that matches
|
||||
// definitions from errno.h.
|
||||
if errno := dp.parseInt(value); errno != 0 {
|
||||
// TODO(mdlayher): return actual errno on Linux?
|
||||
dp.err = os.NewSyscallError("read", fmt.Errorf("wguser: errno=%d", errno))
|
||||
return
|
||||
}
|
||||
case "public_key":
|
||||
// We've either found the first peer or the next peer. Stop parsing
|
||||
// Device fields and start parsing Peer fields, including the public
|
||||
// key indicated here.
|
||||
dp.parsePeers = true
|
||||
dp.peers++
|
||||
|
||||
dp.d.Peers = append(dp.d.Peers, wgtypes.Peer{
|
||||
PublicKey: dp.parseKey(value),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Are we parsing peer fields?
|
||||
if dp.parsePeers {
|
||||
dp.peerParse(key, value)
|
||||
return
|
||||
}
|
||||
|
||||
// Device field parsing.
|
||||
switch key {
|
||||
case "private_key":
|
||||
dp.d.PrivateKey = dp.parseKey(value)
|
||||
case "listen_port":
|
||||
dp.d.ListenPort = dp.parseInt(value)
|
||||
case "fwmark":
|
||||
dp.d.FirewallMark = dp.parseInt(value)
|
||||
}
|
||||
}
|
||||
|
||||
// curPeer returns the current Peer being parsed so its fields can be populated.
|
||||
func (dp *deviceParser) curPeer() *wgtypes.Peer {
|
||||
return &dp.d.Peers[dp.peers-1]
|
||||
}
|
||||
|
||||
// peerParse parses a key/value field into the current Peer.
|
||||
func (dp *deviceParser) peerParse(key, value string) {
|
||||
p := dp.curPeer()
|
||||
switch key {
|
||||
case "preshared_key":
|
||||
p.PresharedKey = dp.parseKey(value)
|
||||
case "endpoint":
|
||||
p.Endpoint = dp.parseAddr(value)
|
||||
case "last_handshake_time_sec":
|
||||
dp.hsSec = dp.parseInt(value)
|
||||
case "last_handshake_time_nsec":
|
||||
dp.hsNano = dp.parseInt(value)
|
||||
|
||||
// Assume that we've seen both seconds and nanoseconds and populate this
|
||||
// field now. However, if both fields were set to 0, assume we have never
|
||||
// had a successful handshake with this peer, and return a zero-value
|
||||
// time.Time to our callers.
|
||||
if dp.hsSec > 0 && dp.hsNano > 0 {
|
||||
p.LastHandshakeTime = time.Unix(int64(dp.hsSec), int64(dp.hsNano))
|
||||
}
|
||||
case "tx_bytes":
|
||||
p.TransmitBytes = dp.parseInt64(value)
|
||||
case "rx_bytes":
|
||||
p.ReceiveBytes = dp.parseInt64(value)
|
||||
case "persistent_keepalive_interval":
|
||||
p.PersistentKeepaliveInterval = time.Duration(dp.parseInt(value)) * time.Second
|
||||
case "allowed_ip":
|
||||
cidr := dp.parseCIDR(value)
|
||||
if cidr != nil {
|
||||
p.AllowedIPs = append(p.AllowedIPs, *cidr)
|
||||
}
|
||||
case "protocol_version":
|
||||
p.ProtocolVersion = dp.parseInt(value)
|
||||
}
|
||||
}
|
||||
|
||||
// parseKey parses a Key from a hex string.
|
||||
func (dp *deviceParser) parseKey(s string) wgtypes.Key {
|
||||
if dp.err != nil {
|
||||
return wgtypes.Key{}
|
||||
}
|
||||
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
dp.err = err
|
||||
return wgtypes.Key{}
|
||||
}
|
||||
|
||||
key, err := wgtypes.NewKey(b)
|
||||
if err != nil {
|
||||
dp.err = err
|
||||
return wgtypes.Key{}
|
||||
}
|
||||
|
||||
return key
|
||||
}
|
||||
|
||||
// parseInt parses an integer from a string.
|
||||
func (dp *deviceParser) parseInt(s string) int {
|
||||
if dp.err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
v, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
dp.err = err
|
||||
return 0
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// parseInt64 parses an int64 from a string.
|
||||
func (dp *deviceParser) parseInt64(s string) int64 {
|
||||
if dp.err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
v, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
dp.err = err
|
||||
return 0
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// parseAddr parses a UDP address from a string.
|
||||
func (dp *deviceParser) parseAddr(s string) *net.UDPAddr {
|
||||
if dp.err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
addr, err := net.ResolveUDPAddr("udp", s)
|
||||
if err != nil {
|
||||
dp.err = err
|
||||
return nil
|
||||
}
|
||||
|
||||
return addr
|
||||
}
|
||||
|
||||
// parseInt parses an address CIDR from a string.
|
||||
func (dp *deviceParser) parseCIDR(s string) *net.IPNet {
|
||||
if dp.err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, cidr, err := net.ParseCIDR(s)
|
||||
if err != nil {
|
||||
dp.err = err
|
||||
return nil
|
||||
}
|
||||
|
||||
return cidr
|
||||
}
|
35
vendor/golang.zx2c4.com/wireguard/wgctrl/os_linux.go
generated
vendored
Normal file
35
vendor/golang.zx2c4.com/wireguard/wgctrl/os_linux.go
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
//+build linux
|
||||
|
||||
package wgctrl
|
||||
|
||||
import (
|
||||
"golang.zx2c4.com/wireguard/wgctrl/internal/wginternal"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/internal/wglinux"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/internal/wguser"
|
||||
)
|
||||
|
||||
// newClients configures wginternal.Clients for Linux systems.
|
||||
func newClients() ([]wginternal.Client, error) {
|
||||
var clients []wginternal.Client
|
||||
|
||||
// Linux has an in-kernel WireGuard implementation. Determine if it is
|
||||
// available and make use of it if so.
|
||||
kc, ok, err := wglinux.New()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ok {
|
||||
clients = append(clients, kc)
|
||||
}
|
||||
|
||||
// Although it isn't recommended to use userspace implementations on Linux,
|
||||
// it can be used. We make use of it in integration tests as well.
|
||||
uc, err := wguser.New()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Kernel devices seem to appear first in wg(8).
|
||||
clients = append(clients, uc)
|
||||
return clients, nil
|
||||
}
|
33
vendor/golang.zx2c4.com/wireguard/wgctrl/os_openbsd.go
generated
vendored
Normal file
33
vendor/golang.zx2c4.com/wireguard/wgctrl/os_openbsd.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
//+build openbsd
|
||||
|
||||
package wgctrl
|
||||
|
||||
import (
|
||||
"golang.zx2c4.com/wireguard/wgctrl/internal/wginternal"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/internal/wguser"
|
||||
)
|
||||
|
||||
// newClients configures wginternal.Clients for OpenBSD systems.
|
||||
func newClients() ([]wginternal.Client, error) {
|
||||
var clients []wginternal.Client
|
||||
|
||||
// OpenBSD has an experimental in-kernel WireGuard implementation:
|
||||
// https://git.zx2c4.com/wireguard-openbsd/about/. Determine if it is
|
||||
// available and make use of it if so.
|
||||
kc, ok, err := wgopenbsd.New()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ok {
|
||||
clients = append(clients, kc)
|
||||
}
|
||||
|
||||
uc, err := wguser.New()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clients = append(clients, uc)
|
||||
return clients, nil
|
||||
}
|
19
vendor/golang.zx2c4.com/wireguard/wgctrl/os_userspace.go
generated
vendored
Normal file
19
vendor/golang.zx2c4.com/wireguard/wgctrl/os_userspace.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
//+build !linux,!openbsd
|
||||
|
||||
package wgctrl
|
||||
|
||||
import (
|
||||
"golang.zx2c4.com/wireguard/wgctrl/internal/wginternal"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/internal/wguser"
|
||||
)
|
||||
|
||||
// newClients configures wginternal.Clients for systems which only support
|
||||
// userspace WireGuard implementations.
|
||||
func newClients() ([]wginternal.Client, error) {
|
||||
c, err := wguser.New()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []wginternal.Client{c}, nil
|
||||
}
|
2
vendor/golang.zx2c4.com/wireguard/wgctrl/wgtypes/doc.go
generated
vendored
Normal file
2
vendor/golang.zx2c4.com/wireguard/wgctrl/wgtypes/doc.go
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// Package wgtypes provides shared types for the wgctrl family of packages.
|
||||
package wgtypes // import "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
270
vendor/golang.zx2c4.com/wireguard/wgctrl/wgtypes/types.go
generated
vendored
Normal file
270
vendor/golang.zx2c4.com/wireguard/wgctrl/wgtypes/types.go
generated
vendored
Normal file
@ -0,0 +1,270 @@
|
||||
package wgtypes
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/curve25519"
|
||||
)
|
||||
|
||||
// A DeviceType specifies the underlying implementation of a WireGuard device.
|
||||
type DeviceType int
|
||||
|
||||
// Possible DeviceType values.
|
||||
const (
|
||||
Unknown DeviceType = iota
|
||||
LinuxKernel
|
||||
OpenBSDKernel
|
||||
Userspace
|
||||
)
|
||||
|
||||
// String returns the string representation of a DeviceType.
|
||||
func (dt DeviceType) String() string {
|
||||
switch dt {
|
||||
case LinuxKernel:
|
||||
return "Linux kernel"
|
||||
case OpenBSDKernel:
|
||||
return "OpenBSD kernel"
|
||||
case Userspace:
|
||||
return "userspace"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// A Device is a WireGuard device.
|
||||
type Device struct {
|
||||
// Name is the name of the device.
|
||||
Name string
|
||||
|
||||
// Type specifies the underlying implementation of the device.
|
||||
Type DeviceType
|
||||
|
||||
// PrivateKey is the device's private key.
|
||||
PrivateKey Key
|
||||
|
||||
// PublicKey is the device's public key, computed from its PrivateKey.
|
||||
PublicKey Key
|
||||
|
||||
// ListenPort is the device's network listening port.
|
||||
ListenPort int
|
||||
|
||||
// FirewallMark is the device's current firewall mark.
|
||||
//
|
||||
// The firewall mark can be used in conjunction with firewall software to
|
||||
// take action on outgoing WireGuard packets.
|
||||
FirewallMark int
|
||||
|
||||
// Peers is the list of network peers associated with this device.
|
||||
Peers []Peer
|
||||
}
|
||||
|
||||
// KeyLen is the expected key length for a WireGuard key.
|
||||
const KeyLen = 32 // wgh.KeyLen
|
||||
|
||||
// A Key is a public, private, or pre-shared secret key. The Key constructor
|
||||
// functions in this package can be used to create Keys suitable for each of
|
||||
// these applications.
|
||||
type Key [KeyLen]byte
|
||||
|
||||
// GenerateKey generates a Key suitable for use as a pre-shared secret key from
|
||||
// a cryptographically safe source.
|
||||
//
|
||||
// The output Key should not be used as a private key; use GeneratePrivateKey
|
||||
// instead.
|
||||
func GenerateKey() (Key, error) {
|
||||
b := make([]byte, KeyLen)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return Key{}, fmt.Errorf("wgtypes: failed to read random bytes: %v", err)
|
||||
}
|
||||
|
||||
return NewKey(b)
|
||||
}
|
||||
|
||||
// GeneratePrivateKey generates a Key suitable for use as a private key from a
|
||||
// cryptographically safe source.
|
||||
func GeneratePrivateKey() (Key, error) {
|
||||
key, err := GenerateKey()
|
||||
if err != nil {
|
||||
return Key{}, err
|
||||
}
|
||||
|
||||
// Modify random bytes using algorithm described at:
|
||||
// https://cr.yp.to/ecdh.html.
|
||||
key[0] &= 248
|
||||
key[31] &= 127
|
||||
key[31] |= 64
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// NewKey creates a Key from an existing byte slice. The byte slice must be
|
||||
// exactly 32 bytes in length.
|
||||
func NewKey(b []byte) (Key, error) {
|
||||
if len(b) != KeyLen {
|
||||
return Key{}, fmt.Errorf("wgtypes: incorrect key size: %d", len(b))
|
||||
}
|
||||
|
||||
var k Key
|
||||
copy(k[:], b)
|
||||
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// ParseKey parses a Key from a base64-encoded string, as produced by the
|
||||
// Key.String method.
|
||||
func ParseKey(s string) (Key, error) {
|
||||
b, err := base64.StdEncoding.DecodeString(s)
|
||||
if err != nil {
|
||||
return Key{}, fmt.Errorf("wgtypes: failed to parse base64-encoded key: %v", err)
|
||||
}
|
||||
|
||||
return NewKey(b)
|
||||
}
|
||||
|
||||
// PublicKey computes a public key from the private key k.
|
||||
//
|
||||
// PublicKey should only be called when k is a private key.
|
||||
func (k Key) PublicKey() Key {
|
||||
var (
|
||||
pub [KeyLen]byte
|
||||
priv = [KeyLen]byte(k)
|
||||
)
|
||||
|
||||
// ScalarBaseMult uses the correct base value per https://cr.yp.to/ecdh.html,
|
||||
// so no need to specify it.
|
||||
curve25519.ScalarBaseMult(&pub, &priv)
|
||||
|
||||
return Key(pub)
|
||||
}
|
||||
|
||||
// String returns the base64-encoded string representation of a Key.
|
||||
//
|
||||
// ParseKey can be used to produce a new Key from this string.
|
||||
func (k Key) String() string {
|
||||
return base64.StdEncoding.EncodeToString(k[:])
|
||||
}
|
||||
|
||||
// A Peer is a WireGuard peer to a Device.
|
||||
type Peer struct {
|
||||
// PublicKey is the public key of a peer, computed from its private key.
|
||||
//
|
||||
// PublicKey is always present in a Peer.
|
||||
PublicKey Key
|
||||
|
||||
// PresharedKey is an optional preshared key which may be used as an
|
||||
// additional layer of security for peer communications.
|
||||
//
|
||||
// A zero-value Key means no preshared key is configured.
|
||||
PresharedKey Key
|
||||
|
||||
// Endpoint is the most recent source address used for communication by
|
||||
// this Peer.
|
||||
Endpoint *net.UDPAddr
|
||||
|
||||
// PersistentKeepaliveInterval specifies how often an "empty" packet is sent
|
||||
// to a peer to keep a connection alive.
|
||||
//
|
||||
// A value of 0 indicates that persistent keepalives are disabled.
|
||||
PersistentKeepaliveInterval time.Duration
|
||||
|
||||
// LastHandshakeTime indicates the most recent time a handshake was performed
|
||||
// with this peer.
|
||||
//
|
||||
// A zero-value time.Time indicates that no handshake has taken place with
|
||||
// this peer.
|
||||
LastHandshakeTime time.Time
|
||||
|
||||
// ReceiveBytes indicates the number of bytes received from this peer.
|
||||
ReceiveBytes int64
|
||||
|
||||
// TransmitBytes indicates the number of bytes transmitted to this peer.
|
||||
TransmitBytes int64
|
||||
|
||||
// AllowedIPs specifies which IPv4 and IPv6 addresses this peer is allowed
|
||||
// to communicate on.
|
||||
//
|
||||
// 0.0.0.0/0 indicates that all IPv4 addresses are allowed, and ::/0
|
||||
// indicates that all IPv6 addresses are allowed.
|
||||
AllowedIPs []net.IPNet
|
||||
|
||||
// ProtocolVersion specifies which version of the WireGuard protocol is used
|
||||
// for this Peer.
|
||||
//
|
||||
// A value of 0 indicates that the most recent protocol version will be used.
|
||||
ProtocolVersion int
|
||||
}
|
||||
|
||||
// A Config is a WireGuard device configuration.
|
||||
//
|
||||
// Because the zero value of some Go types may be significant to WireGuard for
|
||||
// Config fields, pointer types are used for some of these fields. Only
|
||||
// pointer fields which are not nil will be applied when configuring a device.
|
||||
type Config struct {
|
||||
// PrivateKey specifies a private key configuration, if not nil.
|
||||
//
|
||||
// A non-nil, zero-value Key will clear the private key.
|
||||
PrivateKey *Key
|
||||
|
||||
// ListenPort specifies a device's listening port, if not nil.
|
||||
ListenPort *int
|
||||
|
||||
// FirewallMark specifies a device's firewall mark, if not nil.
|
||||
//
|
||||
// If non-nil and set to 0, the firewall mark will be cleared.
|
||||
FirewallMark *int
|
||||
|
||||
// ReplacePeers specifies if the Peers in this configuration should replace
|
||||
// the existing peer list, instead of appending them to the existing list.
|
||||
ReplacePeers bool
|
||||
|
||||
// Peers specifies a list of peer configurations to apply to a device.
|
||||
Peers []PeerConfig
|
||||
}
|
||||
|
||||
// TODO(mdlayher): consider adding ProtocolVersion in PeerConfig.
|
||||
|
||||
// A PeerConfig is a WireGuard device peer configuration.
|
||||
//
|
||||
// Because the zero value of some Go types may be significant to WireGuard for
|
||||
// PeerConfig fields, pointer types are used for some of these fields. Only
|
||||
// pointer fields which are not nil will be applied when configuring a peer.
|
||||
type PeerConfig struct {
|
||||
// PublicKey specifies the public key of this peer. PublicKey is a
|
||||
// mandatory field for all PeerConfigs.
|
||||
PublicKey Key
|
||||
|
||||
// Remove specifies if the peer with this public key should be removed
|
||||
// from a device's peer list.
|
||||
Remove bool
|
||||
|
||||
// UpdateOnly specifies that an operation will only occur on this peer
|
||||
// if the peer already exists as part of the interface.
|
||||
UpdateOnly bool
|
||||
|
||||
// PresharedKey specifies a peer's preshared key configuration, if not nil.
|
||||
//
|
||||
// A non-nil, zero-value Key will clear the preshared key.
|
||||
PresharedKey *Key
|
||||
|
||||
// Endpoint specifies the endpoint of this peer entry, if not nil.
|
||||
Endpoint *net.UDPAddr
|
||||
|
||||
// PersistentKeepaliveInterval specifies the persistent keepalive interval
|
||||
// for this peer, if not nil.
|
||||
//
|
||||
// A non-nil value of 0 will clear the persistent keepalive interval.
|
||||
PersistentKeepaliveInterval *time.Duration
|
||||
|
||||
// ReplaceAllowedIPs specifies if the allowed IPs specified in this peer
|
||||
// configuration should replace any existing ones, instead of appending them
|
||||
// to the allowed IPs list.
|
||||
ReplaceAllowedIPs bool
|
||||
|
||||
// AllowedIPs specifies a list of allowed IP addresses in CIDR notation
|
||||
// for this peer.
|
||||
AllowedIPs []net.IPNet
|
||||
}
|
Loading…
Reference in New Issue
Block a user