From 946341429051667ec2fd9fa48da83592a641c7d3 Mon Sep 17 00:00:00 2001 From: Andree Klattenhoff Date: Thu, 21 Oct 2021 20:55:37 +0200 Subject: [PATCH] add wireguard backend --- .travis.yml | 8 + Documentation/backends.md | 12 + backend/wireguard/device.go | 272 +++ backend/wireguard/wireguard.go | 115 ++ backend/wireguard/wireguard_network.go | 140 ++ backend/wireguard/wireguard_windows.go | 21 + dist/functional-test-k8s.sh | 9 +- dist/functional-test.sh | 16 +- dist/wireguard | 9 + go.mod | 2 + go.sum | 27 +- main.go | 1 + vendor/github.com/golang/glog/LICENSE | 191 ++ vendor/github.com/golang/glog/README | 44 + vendor/github.com/golang/glog/glog.go | 1180 +++++++++++ vendor/github.com/golang/glog/glog_file.go | 124 ++ .../mdlayher/genetlink/CHANGELOG.md | 9 + .../github.com/mdlayher/genetlink/LICENSE.md | 10 + .../github.com/mdlayher/genetlink/README.md | 27 + vendor/github.com/mdlayher/genetlink/conn.go | 235 +++ vendor/github.com/mdlayher/genetlink/doc.go | 6 + .../github.com/mdlayher/genetlink/family.go | 17 + .../mdlayher/genetlink/family_linux.go | 146 ++ .../mdlayher/genetlink/family_others.go | 23 + vendor/github.com/mdlayher/genetlink/fuzz.go | 20 + vendor/github.com/mdlayher/genetlink/go.mod | 10 + vendor/github.com/mdlayher/genetlink/go.sum | 22 + .../github.com/mdlayher/genetlink/message.go | 61 + vendor/github.com/mdlayher/netlink/.gitignore | 2 + .../github.com/mdlayher/netlink/CHANGELOG.md | 22 + vendor/github.com/mdlayher/netlink/LICENSE.md | 10 + vendor/github.com/mdlayher/netlink/README.md | 51 + vendor/github.com/mdlayher/netlink/align.go | 37 + .../github.com/mdlayher/netlink/attribute.go | 589 ++++++ vendor/github.com/mdlayher/netlink/conn.go | 604 ++++++ .../github.com/mdlayher/netlink/conn_linux.go | 772 +++++++ .../mdlayher/netlink/conn_others.go | 29 + vendor/github.com/mdlayher/netlink/debug.go | 69 + vendor/github.com/mdlayher/netlink/doc.go | 36 + vendor/github.com/mdlayher/netlink/errors.go | 128 ++ .../mdlayher/netlink/fdcall_gteq_1.12.go | 44 + .../mdlayher/netlink/fdcall_lt_1.12.go | 29 + vendor/github.com/mdlayher/netlink/fuzz.go | 34 + vendor/github.com/mdlayher/netlink/go.mod | 10 + vendor/github.com/mdlayher/netlink/go.sum | 29 + vendor/github.com/mdlayher/netlink/message.go | 270 +++ .../github.com/mdlayher/netlink/netlink.dot | 86 + .../github.com/mdlayher/netlink/netlink.svg | 436 ++++ .../mdlayher/netlink/netns_linux.go | 93 + .../github.com/mdlayher/netlink/nlenc/doc.go | 3 + .../mdlayher/netlink/nlenc/endian.go | 14 + .../github.com/mdlayher/netlink/nlenc/int.go | 150 ++ .../mdlayher/netlink/nlenc/string.go | 18 + .../mdlayher/netlink/rawconn_gteq_1.12.go | 12 + .../mdlayher/netlink/rawconn_lt_1.12.go | 32 + .../x/crypto/curve25519/curve25519.go | 95 + .../x/crypto/curve25519/curve25519_amd64.go | 240 +++ .../x/crypto/curve25519/curve25519_amd64.s | 1793 +++++++++++++++++ .../x/crypto/curve25519/curve25519_generic.go | 828 ++++++++ .../x/crypto/curve25519/curve25519_noasm.go | 11 + vendor/golang.org/x/net/bpf/asm.go | 41 + vendor/golang.org/x/net/bpf/constants.go | 222 ++ vendor/golang.org/x/net/bpf/doc.go | 82 + vendor/golang.org/x/net/bpf/instructions.go | 726 +++++++ vendor/golang.org/x/net/bpf/setter.go | 10 + vendor/golang.org/x/net/bpf/vm.go | 150 ++ .../golang.org/x/net/bpf/vm_instructions.go | 182 ++ vendor/golang.zx2c4.com/wireguard/COPYING | 17 + .../wireguard/ipc/winpipe/file.go | 323 +++ .../wireguard/ipc/winpipe/mksyscall.go | 9 + .../wireguard/ipc/winpipe/pipe.go | 509 +++++ .../wireguard/ipc/winpipe/zsyscall_windows.go | 238 +++ .../wireguard/wgctrl/.cibuild.sh | 45 + .../wireguard/wgctrl/.gitignore | 2 + .../wireguard/wgctrl/CONTRIBUTING.md | 23 + .../wireguard/wgctrl/LICENSE.md | 9 + .../wireguard/wgctrl/README.md | 32 + .../wireguard/wgctrl/client.go | 100 + .../golang.zx2c4.com/wireguard/wgctrl/doc.go | 29 + .../golang.zx2c4.com/wireguard/wgctrl/go.mod | 13 + .../golang.zx2c4.com/wireguard/wgctrl/go.sum | 51 + .../wgctrl/internal/wginternal/client.go | 21 + .../wgctrl/internal/wginternal/doc.go | 5 + .../wgctrl/internal/wglinux/client_linux.go | 269 +++ .../internal/wglinux/configure_linux.go | 295 +++ .../wireguard/wgctrl/internal/wglinux/doc.go | 6 + .../internal/wglinux/internal/wgh/const.go | 99 + .../internal/wglinux/internal/wgh/doc.go | 12 + .../internal/wglinux/internal/wgh/wgh.yml | 22 + .../wgctrl/internal/wglinux/parse_linux.go | 303 +++ .../internal/wgopenbsd/client_openbsd.go | 372 ++++ .../wgctrl/internal/wgopenbsd/doc.go | 6 + .../internal/wgh/defs_openbsd_386.go | 83 + .../internal/wgh/defs_openbsd_amd64.go | 83 + .../internal/wgopenbsd/internal/wgh/doc.go | 3 + .../wgopenbsd/internal/wgh/generate.sh | 25 + .../wgctrl/internal/wguser/client.go | 99 + .../wgctrl/internal/wguser/configure.go | 106 + .../wgctrl/internal/wguser/conn_unix.go | 49 + .../wgctrl/internal/wguser/conn_windows.go | 249 +++ .../wireguard/wgctrl/internal/wguser/doc.go | 6 + .../wireguard/wgctrl/internal/wguser/parse.go | 258 +++ .../wireguard/wgctrl/os_linux.go | 35 + .../wireguard/wgctrl/os_openbsd.go | 33 + .../wireguard/wgctrl/os_userspace.go | 19 + .../wireguard/wgctrl/wgtypes/doc.go | 2 + .../wireguard/wgctrl/wgtypes/types.go | 270 +++ vendor/modules.txt | 22 + 108 files changed, 14891 insertions(+), 7 deletions(-) create mode 100644 backend/wireguard/device.go create mode 100644 backend/wireguard/wireguard.go create mode 100644 backend/wireguard/wireguard_network.go create mode 100644 backend/wireguard/wireguard_windows.go create mode 100644 dist/wireguard create mode 100644 vendor/github.com/golang/glog/LICENSE create mode 100644 vendor/github.com/golang/glog/README create mode 100644 vendor/github.com/golang/glog/glog.go create mode 100644 vendor/github.com/golang/glog/glog_file.go create mode 100644 vendor/github.com/mdlayher/genetlink/CHANGELOG.md create mode 100644 vendor/github.com/mdlayher/genetlink/LICENSE.md create mode 100644 vendor/github.com/mdlayher/genetlink/README.md create mode 100644 vendor/github.com/mdlayher/genetlink/conn.go create mode 100644 vendor/github.com/mdlayher/genetlink/doc.go create mode 100644 vendor/github.com/mdlayher/genetlink/family.go create mode 100644 vendor/github.com/mdlayher/genetlink/family_linux.go create mode 100644 vendor/github.com/mdlayher/genetlink/family_others.go create mode 100644 vendor/github.com/mdlayher/genetlink/fuzz.go create mode 100644 vendor/github.com/mdlayher/genetlink/go.mod create mode 100644 vendor/github.com/mdlayher/genetlink/go.sum create mode 100644 vendor/github.com/mdlayher/genetlink/message.go create mode 100644 vendor/github.com/mdlayher/netlink/.gitignore create mode 100644 vendor/github.com/mdlayher/netlink/CHANGELOG.md create mode 100644 vendor/github.com/mdlayher/netlink/LICENSE.md create mode 100644 vendor/github.com/mdlayher/netlink/README.md create mode 100644 vendor/github.com/mdlayher/netlink/align.go create mode 100644 vendor/github.com/mdlayher/netlink/attribute.go create mode 100644 vendor/github.com/mdlayher/netlink/conn.go create mode 100644 vendor/github.com/mdlayher/netlink/conn_linux.go create mode 100644 vendor/github.com/mdlayher/netlink/conn_others.go create mode 100644 vendor/github.com/mdlayher/netlink/debug.go create mode 100644 vendor/github.com/mdlayher/netlink/doc.go create mode 100644 vendor/github.com/mdlayher/netlink/errors.go create mode 100644 vendor/github.com/mdlayher/netlink/fdcall_gteq_1.12.go create mode 100644 vendor/github.com/mdlayher/netlink/fdcall_lt_1.12.go create mode 100644 vendor/github.com/mdlayher/netlink/fuzz.go create mode 100644 vendor/github.com/mdlayher/netlink/go.mod create mode 100644 vendor/github.com/mdlayher/netlink/go.sum create mode 100644 vendor/github.com/mdlayher/netlink/message.go create mode 100644 vendor/github.com/mdlayher/netlink/netlink.dot create mode 100644 vendor/github.com/mdlayher/netlink/netlink.svg create mode 100644 vendor/github.com/mdlayher/netlink/netns_linux.go create mode 100644 vendor/github.com/mdlayher/netlink/nlenc/doc.go create mode 100644 vendor/github.com/mdlayher/netlink/nlenc/endian.go create mode 100644 vendor/github.com/mdlayher/netlink/nlenc/int.go create mode 100644 vendor/github.com/mdlayher/netlink/nlenc/string.go create mode 100644 vendor/github.com/mdlayher/netlink/rawconn_gteq_1.12.go create mode 100644 vendor/github.com/mdlayher/netlink/rawconn_lt_1.12.go create mode 100644 vendor/golang.org/x/crypto/curve25519/curve25519.go create mode 100644 vendor/golang.org/x/crypto/curve25519/curve25519_amd64.go create mode 100644 vendor/golang.org/x/crypto/curve25519/curve25519_amd64.s create mode 100644 vendor/golang.org/x/crypto/curve25519/curve25519_generic.go create mode 100644 vendor/golang.org/x/crypto/curve25519/curve25519_noasm.go create mode 100644 vendor/golang.org/x/net/bpf/asm.go create mode 100644 vendor/golang.org/x/net/bpf/constants.go create mode 100644 vendor/golang.org/x/net/bpf/doc.go create mode 100644 vendor/golang.org/x/net/bpf/instructions.go create mode 100644 vendor/golang.org/x/net/bpf/setter.go create mode 100644 vendor/golang.org/x/net/bpf/vm.go create mode 100644 vendor/golang.org/x/net/bpf/vm_instructions.go create mode 100644 vendor/golang.zx2c4.com/wireguard/COPYING create mode 100644 vendor/golang.zx2c4.com/wireguard/ipc/winpipe/file.go create mode 100644 vendor/golang.zx2c4.com/wireguard/ipc/winpipe/mksyscall.go create mode 100644 vendor/golang.zx2c4.com/wireguard/ipc/winpipe/pipe.go create mode 100644 vendor/golang.zx2c4.com/wireguard/ipc/winpipe/zsyscall_windows.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/.cibuild.sh create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/.gitignore create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/CONTRIBUTING.md create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/LICENSE.md create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/README.md create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/client.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/doc.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/go.mod create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/go.sum create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wginternal/client.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wginternal/doc.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/client_linux.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/configure_linux.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/doc.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/const.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/doc.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/wgh.yml create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/parse_linux.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/client_openbsd.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/doc.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/defs_openbsd_386.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/defs_openbsd_amd64.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/doc.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/generate.sh create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/client.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/configure.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/conn_unix.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/conn_windows.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/doc.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/parse.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/os_linux.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/os_openbsd.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/os_userspace.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/wgtypes/doc.go create mode 100644 vendor/golang.zx2c4.com/wireguard/wgctrl/wgtypes/types.go diff --git a/.travis.yml b/.travis.yml index 0190e1fcaf..aea697820c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,3 +17,11 @@ after_success: fi notifications: email: false + +addons: + apt: + sources: + - sourceline: 'ppa:wireguard/wireguard' + packages: + - wireguard + - linux-headers-$(uname -r) diff --git a/Documentation/backends.md b/Documentation/backends.md index dbad329725..a49d8e874c 100644 --- a/Documentation/backends.md +++ b/Documentation/backends.md @@ -164,3 +164,15 @@ Troubleshooting * `ip xfrm policy` can be used to show the installed policies. Flannel installs three policies for each host it connects to. Flannel will not restore policies that are manually deleted (unless flannel is restarted). It will also not delete stale policies on startup. They can be removed by rebooting your host or by removing all ipsec state with `ip xfrm state flush && ip xfrm policy flush` and restarting flannel. + +### WireGuard + +Use in-kernel [WireGuard](https://www.wireguard.com) to encapsulate and encrypt the packets. + +Type: +* `Type` (string): `wireguard` +* `PSK` (string): Optional. The pre shared key to use. Use `wg genpsk` to generate a key. +* `ListenPort` (int): Optional. The udp port to listen on. Default is `51820`. +* `PersistentKeepaliveInterval` (int): Optional. Default is 0 (disabled). + +The static name of the interface is `flannel-wg`. WireGuard tools like `wg show` can be used to debug interface and peers. diff --git a/backend/wireguard/device.go b/backend/wireguard/device.go new file mode 100644 index 0000000000..f794d9e926 --- /dev/null +++ b/backend/wireguard/device.go @@ -0,0 +1,272 @@ +// Copyright 2019 flannel authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package wireguard + +import ( + "fmt" + "net" + "sync" + "syscall" + "time" + + "github.com/flannel-io/flannel/pkg/ip" + log "github.com/golang/glog" + "github.com/vishvananda/netlink" + "golang.org/x/net/context" + "golang.zx2c4.com/wireguard/wgctrl" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +type wgDeviceAttrs struct { + listenPort int + privateKey *wgtypes.Key + publicKey *wgtypes.Key + psk *wgtypes.Key + keepalive *time.Duration + deviceName string +} + +type wgDevice struct { + link *netlink.GenericLink + client *wgctrl.Client +} + +func setupKeys(devAttrs *wgDeviceAttrs, psk string) error { + privateKey, err := wgtypes.GeneratePrivateKey() + if err != nil { + return fmt.Errorf("could not generate private key: %v", err) + } + devAttrs.privateKey = &privateKey + + publicKey := privateKey.PublicKey() + devAttrs.publicKey = &publicKey + + if psk != "" { + presharedKey, err := wgtypes.ParseKey(psk) + if err != nil { + return fmt.Errorf("could not parse psk: %v", err) + } + devAttrs.psk = &presharedKey + } + + return nil +} + +func newWGDevice(devAttrs *wgDeviceAttrs, ctx context.Context, wg *sync.WaitGroup) (*wgDevice, error) { + la := netlink.LinkAttrs{ + Name: devAttrs.deviceName, + } + link := &netlink.GenericLink{LinkAttrs: la, LinkType: "wireguard"} + + link, err := ensureLink(link) + if err != nil { + return nil, err + } + + dev := wgDevice{ + link: link, + } + + // housekeeping + wg.Add(1) + go func() { + select { + case <-ctx.Done(): + dev.remove() + log.Infof("Stopped wireguard") + wg.Done() + } + }() + + return &dev, nil +} + +func ensureLink(wglan *netlink.GenericLink) (*netlink.GenericLink, error) { + err := netlink.LinkAdd(wglan) + if err == syscall.EEXIST { + existing, err := netlink.LinkByName(wglan.Name) + if err != nil { + return nil, err + } + + log.Warningf("%q already exists; recreating device", wglan.Name) + err = netlink.LinkDel(existing) + if err != nil { + return nil, err + } + + err = netlink.LinkAdd(wglan) + if err != nil { + return nil, fmt.Errorf("could not create wireguard interface: %v", err) + } + } else if err != nil { + return nil, fmt.Errorf("could not create wireguard interface: %v", err) + } + + _, err = netlink.LinkByIndex(wglan.Index) + if err != nil { + return nil, fmt.Errorf("can't locate created wireguard device with index %v", wglan.Index) + } + + return wglan, nil +} + +func (dev *wgDevice) remove() error { + dev.client.Close() + err := netlink.LinkDel(dev.link) + if err != nil { + return fmt.Errorf("could not remove wireguard device: %v", err) + } + return nil +} + +func (dev *wgDevice) Configure(devAttrs *wgDeviceAttrs, devIP ip.IP4, flannelnet ip.IP4Net) error { + cfg := wgtypes.Config{ + PrivateKey: devAttrs.privateKey, + ListenPort: &devAttrs.listenPort, + ReplacePeers: true, + } + + c, err := wgctrl.New() + if err != nil { + return fmt.Errorf("failed to open wgctrl: %v", err) + } + dev.client = c + + err = dev.client.ConfigureDevice(devAttrs.deviceName, cfg) + if err != nil { + return fmt.Errorf("failed to configure device %v", err) + } + + net := ip.IP4Net{IP: devIP, PrefixLen: 32} + err = ip.EnsureV4AddressOnLink(net, flannelnet, dev.link) + if err != nil { + return fmt.Errorf("failed to ensure address of interface %s: %s", dev.link.Attrs().Name, err) + } + + err = netlink.LinkSetUp(dev.link) + if err != nil { + return fmt.Errorf("failed to set interface %s to UP state: %s", dev.link.Attrs().Name, err) + } + + route := netlink.Route{ + LinkIndex: dev.link.Attrs().Index, + Scope: netlink.SCOPE_UNIVERSE, + Dst: flannelnet.ToIPNet(), + } + err = netlink.RouteAdd(&route) + if err != nil { + return fmt.Errorf("failed to add route %s: %s", dev.link.Attrs().Name, err) + } + + return nil +} + +func (dev *wgDevice) addPeer(devAttrs *wgDeviceAttrs, publicIP string, data string, subnet *ip.IP4Net) error { + publicKey, err := wgtypes.ParseKey(data) + if err != nil { + return fmt.Errorf("failed to parse publicKey: %v", err) + } + + publicEndpoint := fmt.Sprintf("%s:%d", publicIP, devAttrs.listenPort) + udpEndpoint, err := net.ResolveUDPAddr("udp", publicEndpoint) + if err != nil { + return fmt.Errorf("failed to resolve UDP address: %v", err) + } + + allowedIP := subnet.ToIPNet() + + wgcfg := wgtypes.Config{ + PrivateKey: devAttrs.privateKey, + ListenPort: &devAttrs.listenPort, + ReplacePeers: false, + Peers: []wgtypes.PeerConfig{ + { + PublicKey: publicKey, + PresharedKey: devAttrs.psk, + PersistentKeepaliveInterval: devAttrs.keepalive, + Endpoint: udpEndpoint, + ReplaceAllowedIPs: true, + AllowedIPs: []net.IPNet{ + *allowedIP, + }, + }, + }} + + err = dev.client.ConfigureDevice(devAttrs.deviceName, wgcfg) + if err != nil { + return fmt.Errorf("failed to add peer %v", err) + } + + // Remove peers with outdated PublicKeys for this endpoint + dev.cleanupPeers(devAttrs, udpEndpoint, data) + + return nil +} + +func (dev *wgDevice) cleanupPeers(devAttrs *wgDeviceAttrs, udpEndpoint *net.UDPAddr, publicKey string) error { + currentDev, err := dev.client.Device(devAttrs.deviceName) + if err != nil { + return fmt.Errorf("failed to open device: %v", err) + } + + peers := []wgtypes.PeerConfig{} + for _, peer := range currentDev.Peers { + if peer.Endpoint.IP.Equal(udpEndpoint.IP) { + if peer.PublicKey.String() != publicKey { + removePeer := wgtypes.PeerConfig{ + PublicKey: peer.PublicKey, + Remove: true, + } + peers = append(peers, removePeer) + } + } + } + + wgcfg := wgtypes.Config{ + PrivateKey: devAttrs.privateKey, + ListenPort: &devAttrs.listenPort, + ReplacePeers: false, + Peers: peers, + } + + err = dev.client.ConfigureDevice(devAttrs.deviceName, wgcfg) + if err != nil { + return fmt.Errorf("failed to cleanup peers %v", err) + } + + return nil +} + +func (dev *wgDevice) removePeer(devAttrs *wgDeviceAttrs, data string) error { + publicKey, err := wgtypes.ParseKey(data) + if err != nil { + return fmt.Errorf("failed to parse publicKey: %v", err) + } + + wgcfg := wgtypes.Config{ + ReplacePeers: false, + Peers: []wgtypes.PeerConfig{ + { + PublicKey: publicKey, + Remove: true, + }, + }} + + err = dev.client.ConfigureDevice(devAttrs.deviceName, wgcfg) + if err != nil { + return fmt.Errorf("failed to remove peer %v", err) + } + return nil +} diff --git a/backend/wireguard/wireguard.go b/backend/wireguard/wireguard.go new file mode 100644 index 0000000000..849fa1fa78 --- /dev/null +++ b/backend/wireguard/wireguard.go @@ -0,0 +1,115 @@ +// Copyright 2019 flannel authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package wireguard + +import ( + "fmt" + "time" + + "encoding/json" + "sync" + + "github.com/flannel-io/flannel/backend" + "github.com/flannel-io/flannel/pkg/ip" + "github.com/flannel-io/flannel/subnet" + "golang.org/x/net/context" +) + +func init() { + backend.Register("wireguard", New) +} + +type WireguardBackend struct { + sm subnet.Manager + extIface *backend.ExternalInterface + networks map[string]*network +} + +func New(sm subnet.Manager, extIface *backend.ExternalInterface) (backend.Backend, error) { + be := &WireguardBackend{ + sm: sm, + extIface: extIface, + networks: make(map[string]*network), + } + + return be, nil +} + +func (be *WireguardBackend) RegisterNetwork(ctx context.Context, wg *sync.WaitGroup, config *subnet.Config) (backend.Network, error) { + n := &network{ + extIface: be.extIface, + sm: be.sm, + devAttrs: &wgDeviceAttrs{}, + } + + // Parse out configuration + if len(config.Backend) > 0 { + cfg := struct { + ListenPort int + PSK string + PersistentKeepaliveInterval time.Duration + }{ + ListenPort: 51820, + PersistentKeepaliveInterval: 0, + } + if err := json.Unmarshal(config.Backend, &cfg); err != nil { + return nil, fmt.Errorf("error decoding backend config: %v", err) + } + keepalive := cfg.PersistentKeepaliveInterval * time.Second + n.devAttrs.listenPort = cfg.ListenPort + n.devAttrs.deviceName = "flannel-wg" + n.devAttrs.keepalive = &keepalive + err := setupKeys(n.devAttrs, cfg.PSK) + if err != nil { + return nil, err + } + } + + publicKey := n.devAttrs.publicKey + data, err := json.Marshal(publicKey.String()) + if err != nil { + return nil, err + } + + dev, err := newWGDevice(n.devAttrs, ctx, wg) + if err != nil { + return nil, err + } + n.dev = dev + + attrs := subnet.LeaseAttrs{ + PublicIP: ip.FromIP(be.extIface.ExtAddr), + BackendType: "wireguard", + BackendData: data, + } + + lease, err := be.sm.AcquireLease(ctx, &attrs) + switch err { + + case nil: + n.lease = lease + case context.Canceled, context.DeadlineExceeded: + return nil, err + default: + return nil, fmt.Errorf("failed to acquire lease: %v", err) + + } + + err = n.dev.Configure(n.devAttrs, lease.Subnet.IP, config.Network) + if err != nil { + return nil, err + } + + return n, nil +} diff --git a/backend/wireguard/wireguard_network.go b/backend/wireguard/wireguard_network.go new file mode 100644 index 0000000000..0240bf58ca --- /dev/null +++ b/backend/wireguard/wireguard_network.go @@ -0,0 +1,140 @@ +// Copyright 2019 flannel authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package wireguard + +import ( + "encoding/json" + "sync" + + log "github.com/golang/glog" + "golang.org/x/net/context" + + "github.com/flannel-io/flannel/backend" + "github.com/flannel-io/flannel/subnet" +) + +const ( + /* + 20-byte IPv4 header or 40 byte IPv6 header + 8-byte UDP header + 4-byte type + 4-byte key index + 8-byte nonce + N-byte encrypted data + 16-byte authentication tag + */ + overhead = 80 +) + +type network struct { + name string + extIface *backend.ExternalInterface + lease *subnet.Lease + sm subnet.Manager + devAttrs *wgDeviceAttrs + dev *wgDevice +} + +func (n *network) Lease() *subnet.Lease { + return n.lease +} + +func (n *network) MTU() int { + return n.extIface.Iface.MTU - overhead +} + +func (n *network) Run(ctx context.Context) { + wg := sync.WaitGroup{} + + log.Info("Watching for new subnet leases") + evts := make(chan []subnet.Event) + wg.Add(1) + go func() { + subnet.WatchLeases(ctx, n.sm, n.lease, evts) + wg.Done() + }() + + defer wg.Wait() + + for { + select { + case evtBatch := <-evts: + n.handleSubnetEvents(evtBatch) + + case <-ctx.Done(): + return + } + } +} + +func (n *network) handleSubnetEvents(batch []subnet.Event) { + for _, evt := range batch { + switch evt.Type { + case subnet.EventAdded: + log.Infof("Subnet added: %v via %v", evt.Lease.Subnet, evt.Lease.Attrs.PublicIP) + + if evt.Lease.Attrs.BackendType != "wireguard" { + log.Warningf("Ignoring non-wireguard subnet: type=%v", evt.Lease.Attrs.BackendType) + continue + } + + backendData := "" + + if len(evt.Lease.Attrs.BackendData) > 0 { + if err := json.Unmarshal(evt.Lease.Attrs.BackendData, &backendData); err != nil { + log.Errorf("failed to unmarshal BackendData: %v", err) + continue + } + } + + if err := n.dev.addPeer( + n.devAttrs, + evt.Lease.Attrs.PublicIP.String(), + backendData, + &evt.Lease.Subnet, + ); err != nil { + log.Errorf("failed to setup peer %v", err) + continue + } + + case subnet.EventRemoved: + log.Info("Subnet removed: ", evt.Lease.Subnet) + + if evt.Lease.Attrs.BackendType != "wireguard" { + log.Warningf("Ignoring non-wireguard subnet: type=%v", evt.Lease.Attrs.BackendType) + continue + } + + backendData := "" + + if len(evt.Lease.Attrs.BackendData) > 0 { + if err := json.Unmarshal(evt.Lease.Attrs.BackendData, &backendData); err != nil { + log.Errorf("failed to unmarshal BackendData: %v", err) + continue + } + } + + if err := n.dev.removePeer( + n.devAttrs, + backendData, + ); err != nil { + log.Errorf("failed to remove peer %v", err) + continue + } + + default: + log.Error("Internal error: unknown event type: ", int(evt.Type)) + } + } +} diff --git a/backend/wireguard/wireguard_windows.go b/backend/wireguard/wireguard_windows.go new file mode 100644 index 0000000000..8b7b443c12 --- /dev/null +++ b/backend/wireguard/wireguard_windows.go @@ -0,0 +1,21 @@ +// Copyright 2019 flannel authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package wireguard + +import log "github.com/golang/glog" + +func init() { + log.Infof("flannel has not implemented wireguard on this platform") +} diff --git a/dist/functional-test-k8s.sh b/dist/functional-test-k8s.sh index 7262c57435..11b8f6b1d7 100755 --- a/dist/functional-test-k8s.sh +++ b/dist/functional-test-k8s.sh @@ -77,7 +77,8 @@ teardown() { start_flannel() { local backend=$1 - flannel_conf="{ \"Network\": \"$FLANNEL_NET\", \"Backend\": { \"Type\": \"${backend}\" } }" + flannel_conf="{ \"Network\": \"$FLANNEL_NET\", \"Backend\": { \"Type\": \"${backend}\" } }" + for host_num in 1 2; do docker rm -f flannel-e2e-test-flannel$host_num >/dev/null 2>/dev/null docker run -e NODE_NAME=flannel$host_num --privileged --name flannel-e2e-test-flannel$host_num -id --entrypoint /bin/sh $FLANNEL_DOCKER_IMAGE >/dev/null @@ -142,6 +143,12 @@ test_public-ip-overwrite(){ flannel.alpha.coreos.com/public-ip-overwrite- >/dev/null 2>&1 } +test_wireguard() { + start_flannel wireguard + create_ping_dest # creates ping_dest1 and ping_dest2 variables + pings +} + pings() { # ping in both directions assert "docker exec --privileged flannel-e2e-test-flannel1 /bin/ping -c 5 $ping_dest2" "Host 1 cannot ping host 2" diff --git a/dist/functional-test.sh b/dist/functional-test.sh index a6bb0d04d8..1ac66621f0 100755 --- a/dist/functional-test.sh +++ b/dist/functional-test.sh @@ -117,6 +117,12 @@ test_ipsec_ping() { pings } +test_wireguard_ping() { + write_config_etcd wireguard + create_ping_dest # creates ping_dest1 and ping_dest2 variables + pings +} + pings() { # ping in both directions assert "docker exec --privileged flannel-e2e-test-flannel1 /bin/ping -I $ping_dest1 -c 3 $ping_dest2" "Host 1 cannot ping host 2" @@ -156,11 +162,11 @@ test_ipsec_perf() { perf } -#test_wireguard_perf() { -# write_config_etcd extension-wireguard -# create_ping_dest -# perf -#} +test_wireguard_perf() { + write_config_etcd wireguard + create_ping_dest + perf +} perf() { # Perf test - run iperf server on flannel1 and client on flannel2 diff --git a/dist/wireguard b/dist/wireguard new file mode 100644 index 0000000000..c01358b009 --- /dev/null +++ b/dist/wireguard @@ -0,0 +1,9 @@ +{ + "Network": "10.10.0.0/16", + "Backend": { + "Type": "wireguard", + "ListenPort": 51820, + "PSK": "H0Ad2yKBMgfGM6/Yt2dRxd8u+juyViCz3KdJfEdteJ8=", + "PersistentKeepaliveInterval": 300 + } +} diff --git a/go.mod b/go.mod index ca5e50b6e1..7b17f9b87d 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf github.com/denverdino/aliyungo v0.0.0-20170629053852-f6cab0c35083 github.com/go-ini/ini v1.28.1 // indirect + github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7 // indirect github.com/joho/godotenv v0.0.0-20161216230537-726cc8b906e3 github.com/jonboulle/clockwork v0.1.0 @@ -26,6 +27,7 @@ require ( github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc golang.org/x/net v0.0.0-20201110031124-69a78807bb2b golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 + golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200609130330-bd2cb7843e1b google.golang.org/api v0.15.0 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect k8s.io/api v0.19.5 diff --git a/go.sum b/go.sum index 488308f397..6ca0124274 100644 --- a/go.sum +++ b/go.sum @@ -73,7 +73,6 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -149,6 +148,9 @@ github.com/joho/godotenv v0.0.0-20161216230537-726cc8b906e3 h1:zShOjUfrFegEHgln4 github.com/joho/godotenv v0.0.0-20161216230537-726cc8b906e3/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= +github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4 h1:nwOc1YaOrYJ37sEBrtWZrdqzK22hiJs3GpDmP3sR2Yw= +github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -165,6 +167,14 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +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 h1:mpdLgm+brq10nI9zM1BpX1kpDbh3NLl3RSnVq6ZSkfg= +github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= +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= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -224,8 +234,10 @@ golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -259,7 +271,11 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191003171128-d98b1b443823/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-20191209160850-c0dbc17a3553/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-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -278,15 +294,20 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY= @@ -324,6 +345,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.zx2c4.com/wireguard v0.0.20200121 h1:vcswa5Q6f+sylDfjqyrVNNrjsFUUbPsgAQTBCAg/Qf8= +golang.zx2c4.com/wireguard v0.0.20200121/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200609130330-bd2cb7843e1b h1:l4mBVCYinjzZuR5DtxHuBD6wyd4348TGiavJ5vLrhEc= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200609130330-bd2cb7843e1b/go.mod h1:UdS9frhv65KTfwxME1xE8+rHYoFpbm36gOud1GhBe9c= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= diff --git a/main.go b/main.go index 4fd8f7f17d..18c92d2f27 100644 --- a/main.go +++ b/main.go @@ -57,6 +57,7 @@ import ( _ "github.com/flannel-io/flannel/backend/tencentvpc" _ "github.com/flannel-io/flannel/backend/udp" _ "github.com/flannel-io/flannel/backend/vxlan" + _ "github.com/flannel-io/flannel/backend/wireguard" ) type flagSlice []string diff --git a/vendor/github.com/golang/glog/LICENSE b/vendor/github.com/golang/glog/LICENSE new file mode 100644 index 0000000000..37ec93a14f --- /dev/null +++ b/vendor/github.com/golang/glog/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor 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, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/golang/glog/README b/vendor/github.com/golang/glog/README new file mode 100644 index 0000000000..387b4eb689 --- /dev/null +++ b/vendor/github.com/golang/glog/README @@ -0,0 +1,44 @@ +glog +==== + +Leveled execution logs for Go. + +This is an efficient pure Go implementation of leveled logs in the +manner of the open source C++ package + https://github.com/google/glog + +By binding methods to booleans it is possible to use the log package +without paying the expense of evaluating the arguments to the log. +Through the -vmodule flag, the package also provides fine-grained +control over logging at the file level. + +The comment from glog.go introduces the ideas: + + Package glog implements logging analogous to the Google-internal + C++ INFO/ERROR/V setup. It provides functions Info, Warning, + Error, Fatal, plus formatting variants such as Infof. It + also provides V-style logging controlled by the -v and + -vmodule=file=2 flags. + + Basic examples: + + glog.Info("Prepare to repel boarders") + + glog.Fatalf("Initialization failed: %s", err) + + See the documentation for the V function for an explanation + of these examples: + + if glog.V(2) { + glog.Info("Starting transaction...") + } + + glog.V(2).Infoln("Processed", nItems, "elements") + + +The repository contains an open source version of the log package +used inside Google. The master copy of the source lives inside +Google, not here. The code in this repo is for export only and is not itself +under development. Feature requests will be ignored. + +Send bug reports to golang-nuts@googlegroups.com. diff --git a/vendor/github.com/golang/glog/glog.go b/vendor/github.com/golang/glog/glog.go new file mode 100644 index 0000000000..54bd7afdca --- /dev/null +++ b/vendor/github.com/golang/glog/glog.go @@ -0,0 +1,1180 @@ +// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/ +// +// Copyright 2013 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package glog implements logging analogous to the Google-internal C++ INFO/ERROR/V setup. +// It provides functions Info, Warning, Error, Fatal, plus formatting variants such as +// Infof. It also provides V-style logging controlled by the -v and -vmodule=file=2 flags. +// +// Basic examples: +// +// glog.Info("Prepare to repel boarders") +// +// glog.Fatalf("Initialization failed: %s", err) +// +// See the documentation for the V function for an explanation of these examples: +// +// if glog.V(2) { +// glog.Info("Starting transaction...") +// } +// +// glog.V(2).Infoln("Processed", nItems, "elements") +// +// Log output is buffered and written periodically using Flush. Programs +// should call Flush before exiting to guarantee all log output is written. +// +// By default, all log statements write to files in a temporary directory. +// This package provides several flags that modify this behavior. +// As a result, flag.Parse must be called before any logging is done. +// +// -logtostderr=false +// Logs are written to standard error instead of to files. +// -alsologtostderr=false +// Logs are written to standard error as well as to files. +// -stderrthreshold=ERROR +// Log events at or above this severity are logged to standard +// error as well as to files. +// -log_dir="" +// Log files will be written to this directory instead of the +// default temporary directory. +// +// Other flags provide aids to debugging. +// +// -log_backtrace_at="" +// When set to a file and line number holding a logging statement, +// such as +// -log_backtrace_at=gopherflakes.go:234 +// a stack trace will be written to the Info log whenever execution +// hits that statement. (Unlike with -vmodule, the ".go" must be +// present.) +// -v=0 +// Enable V-leveled logging at the specified level. +// -vmodule="" +// The syntax of the argument is a comma-separated list of pattern=N, +// where pattern is a literal file name (minus the ".go" suffix) or +// "glob" pattern and N is a V level. For instance, +// -vmodule=gopher*=3 +// sets the V level to 3 in all Go files whose names begin "gopher". +// +package glog + +import ( + "bufio" + "bytes" + "errors" + "flag" + "fmt" + "io" + stdLog "log" + "os" + "path/filepath" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" +) + +// severity identifies the sort of log: info, warning etc. It also implements +// the flag.Value interface. The -stderrthreshold flag is of type severity and +// should be modified only through the flag.Value interface. The values match +// the corresponding constants in C++. +type severity int32 // sync/atomic int32 + +// These constants identify the log levels in order of increasing severity. +// A message written to a high-severity log file is also written to each +// lower-severity log file. +const ( + infoLog severity = iota + warningLog + errorLog + fatalLog + numSeverity = 4 +) + +const severityChar = "IWEF" + +var severityName = []string{ + infoLog: "INFO", + warningLog: "WARNING", + errorLog: "ERROR", + fatalLog: "FATAL", +} + +// get returns the value of the severity. +func (s *severity) get() severity { + return severity(atomic.LoadInt32((*int32)(s))) +} + +// set sets the value of the severity. +func (s *severity) set(val severity) { + atomic.StoreInt32((*int32)(s), int32(val)) +} + +// String is part of the flag.Value interface. +func (s *severity) String() string { + return strconv.FormatInt(int64(*s), 10) +} + +// Get is part of the flag.Value interface. +func (s *severity) Get() interface{} { + return *s +} + +// Set is part of the flag.Value interface. +func (s *severity) Set(value string) error { + var threshold severity + // Is it a known name? + if v, ok := severityByName(value); ok { + threshold = v + } else { + v, err := strconv.Atoi(value) + if err != nil { + return err + } + threshold = severity(v) + } + logging.stderrThreshold.set(threshold) + return nil +} + +func severityByName(s string) (severity, bool) { + s = strings.ToUpper(s) + for i, name := range severityName { + if name == s { + return severity(i), true + } + } + return 0, false +} + +// OutputStats tracks the number of output lines and bytes written. +type OutputStats struct { + lines int64 + bytes int64 +} + +// Lines returns the number of lines written. +func (s *OutputStats) Lines() int64 { + return atomic.LoadInt64(&s.lines) +} + +// Bytes returns the number of bytes written. +func (s *OutputStats) Bytes() int64 { + return atomic.LoadInt64(&s.bytes) +} + +// Stats tracks the number of lines of output and number of bytes +// per severity level. Values must be read with atomic.LoadInt64. +var Stats struct { + Info, Warning, Error OutputStats +} + +var severityStats = [numSeverity]*OutputStats{ + infoLog: &Stats.Info, + warningLog: &Stats.Warning, + errorLog: &Stats.Error, +} + +// Level is exported because it appears in the arguments to V and is +// the type of the v flag, which can be set programmatically. +// It's a distinct type because we want to discriminate it from logType. +// Variables of type level are only changed under logging.mu. +// The -v flag is read only with atomic ops, so the state of the logging +// module is consistent. + +// Level is treated as a sync/atomic int32. + +// Level specifies a level of verbosity for V logs. *Level implements +// flag.Value; the -v flag is of type Level and should be modified +// only through the flag.Value interface. +type Level int32 + +// get returns the value of the Level. +func (l *Level) get() Level { + return Level(atomic.LoadInt32((*int32)(l))) +} + +// set sets the value of the Level. +func (l *Level) set(val Level) { + atomic.StoreInt32((*int32)(l), int32(val)) +} + +// String is part of the flag.Value interface. +func (l *Level) String() string { + return strconv.FormatInt(int64(*l), 10) +} + +// Get is part of the flag.Value interface. +func (l *Level) Get() interface{} { + return *l +} + +// Set is part of the flag.Value interface. +func (l *Level) Set(value string) error { + v, err := strconv.Atoi(value) + if err != nil { + return err + } + logging.mu.Lock() + defer logging.mu.Unlock() + logging.setVState(Level(v), logging.vmodule.filter, false) + return nil +} + +// moduleSpec represents the setting of the -vmodule flag. +type moduleSpec struct { + filter []modulePat +} + +// modulePat contains a filter for the -vmodule flag. +// It holds a verbosity level and a file pattern to match. +type modulePat struct { + pattern string + literal bool // The pattern is a literal string + level Level +} + +// match reports whether the file matches the pattern. It uses a string +// comparison if the pattern contains no metacharacters. +func (m *modulePat) match(file string) bool { + if m.literal { + return file == m.pattern + } + match, _ := filepath.Match(m.pattern, file) + return match +} + +func (m *moduleSpec) String() string { + // Lock because the type is not atomic. TODO: clean this up. + logging.mu.Lock() + defer logging.mu.Unlock() + var b bytes.Buffer + for i, f := range m.filter { + if i > 0 { + b.WriteRune(',') + } + fmt.Fprintf(&b, "%s=%d", f.pattern, f.level) + } + return b.String() +} + +// Get is part of the (Go 1.2) flag.Getter interface. It always returns nil for this flag type since the +// struct is not exported. +func (m *moduleSpec) Get() interface{} { + return nil +} + +var errVmoduleSyntax = errors.New("syntax error: expect comma-separated list of filename=N") + +// Syntax: -vmodule=recordio=2,file=1,gfs*=3 +func (m *moduleSpec) Set(value string) error { + var filter []modulePat + for _, pat := range strings.Split(value, ",") { + if len(pat) == 0 { + // Empty strings such as from a trailing comma can be ignored. + continue + } + patLev := strings.Split(pat, "=") + if len(patLev) != 2 || len(patLev[0]) == 0 || len(patLev[1]) == 0 { + return errVmoduleSyntax + } + pattern := patLev[0] + v, err := strconv.Atoi(patLev[1]) + if err != nil { + return errors.New("syntax error: expect comma-separated list of filename=N") + } + if v < 0 { + return errors.New("negative value for vmodule level") + } + if v == 0 { + continue // Ignore. It's harmless but no point in paying the overhead. + } + // TODO: check syntax of filter? + filter = append(filter, modulePat{pattern, isLiteral(pattern), Level(v)}) + } + logging.mu.Lock() + defer logging.mu.Unlock() + logging.setVState(logging.verbosity, filter, true) + return nil +} + +// isLiteral reports whether the pattern is a literal string, that is, has no metacharacters +// that require filepath.Match to be called to match the pattern. +func isLiteral(pattern string) bool { + return !strings.ContainsAny(pattern, `\*?[]`) +} + +// traceLocation represents the setting of the -log_backtrace_at flag. +type traceLocation struct { + file string + line int +} + +// isSet reports whether the trace location has been specified. +// logging.mu is held. +func (t *traceLocation) isSet() bool { + return t.line > 0 +} + +// match reports whether the specified file and line matches the trace location. +// The argument file name is the full path, not the basename specified in the flag. +// logging.mu is held. +func (t *traceLocation) match(file string, line int) bool { + if t.line != line { + return false + } + if i := strings.LastIndex(file, "/"); i >= 0 { + file = file[i+1:] + } + return t.file == file +} + +func (t *traceLocation) String() string { + // Lock because the type is not atomic. TODO: clean this up. + logging.mu.Lock() + defer logging.mu.Unlock() + return fmt.Sprintf("%s:%d", t.file, t.line) +} + +// Get is part of the (Go 1.2) flag.Getter interface. It always returns nil for this flag type since the +// struct is not exported +func (t *traceLocation) Get() interface{} { + return nil +} + +var errTraceSyntax = errors.New("syntax error: expect file.go:234") + +// Syntax: -log_backtrace_at=gopherflakes.go:234 +// Note that unlike vmodule the file extension is included here. +func (t *traceLocation) Set(value string) error { + if value == "" { + // Unset. + t.line = 0 + t.file = "" + } + fields := strings.Split(value, ":") + if len(fields) != 2 { + return errTraceSyntax + } + file, line := fields[0], fields[1] + if !strings.Contains(file, ".") { + return errTraceSyntax + } + v, err := strconv.Atoi(line) + if err != nil { + return errTraceSyntax + } + if v <= 0 { + return errors.New("negative or zero value for level") + } + logging.mu.Lock() + defer logging.mu.Unlock() + t.line = v + t.file = file + return nil +} + +// flushSyncWriter is the interface satisfied by logging destinations. +type flushSyncWriter interface { + Flush() error + Sync() error + io.Writer +} + +func init() { + flag.BoolVar(&logging.toStderr, "logtostderr", false, "log to standard error instead of files") + flag.BoolVar(&logging.alsoToStderr, "alsologtostderr", false, "log to standard error as well as files") + flag.Var(&logging.verbosity, "v", "log level for V logs") + flag.Var(&logging.stderrThreshold, "stderrthreshold", "logs at or above this threshold go to stderr") + flag.Var(&logging.vmodule, "vmodule", "comma-separated list of pattern=N settings for file-filtered logging") + flag.Var(&logging.traceLocation, "log_backtrace_at", "when logging hits line file:N, emit a stack trace") + + // Default stderrThreshold is ERROR. + logging.stderrThreshold = errorLog + + logging.setVState(0, nil, false) + go logging.flushDaemon() +} + +// Flush flushes all pending log I/O. +func Flush() { + logging.lockAndFlushAll() +} + +// loggingT collects all the global state of the logging setup. +type loggingT struct { + // Boolean flags. Not handled atomically because the flag.Value interface + // does not let us avoid the =true, and that shorthand is necessary for + // compatibility. TODO: does this matter enough to fix? Seems unlikely. + toStderr bool // The -logtostderr flag. + alsoToStderr bool // The -alsologtostderr flag. + + // Level flag. Handled atomically. + stderrThreshold severity // The -stderrthreshold flag. + + // freeList is a list of byte buffers, maintained under freeListMu. + freeList *buffer + // freeListMu maintains the free list. It is separate from the main mutex + // so buffers can be grabbed and printed to without holding the main lock, + // for better parallelization. + freeListMu sync.Mutex + + // mu protects the remaining elements of this structure and is + // used to synchronize logging. + mu sync.Mutex + // file holds writer for each of the log types. + file [numSeverity]flushSyncWriter + // pcs is used in V to avoid an allocation when computing the caller's PC. + pcs [1]uintptr + // vmap is a cache of the V Level for each V() call site, identified by PC. + // It is wiped whenever the vmodule flag changes state. + vmap map[uintptr]Level + // filterLength stores the length of the vmodule filter chain. If greater + // than zero, it means vmodule is enabled. It may be read safely + // using sync.LoadInt32, but is only modified under mu. + filterLength int32 + // traceLocation is the state of the -log_backtrace_at flag. + traceLocation traceLocation + // These flags are modified only under lock, although verbosity may be fetched + // safely using atomic.LoadInt32. + vmodule moduleSpec // The state of the -vmodule flag. + verbosity Level // V logging level, the value of the -v flag/ +} + +// buffer holds a byte Buffer for reuse. The zero value is ready for use. +type buffer struct { + bytes.Buffer + tmp [64]byte // temporary byte array for creating headers. + next *buffer +} + +var logging loggingT + +// setVState sets a consistent state for V logging. +// l.mu is held. +func (l *loggingT) setVState(verbosity Level, filter []modulePat, setFilter bool) { + // Turn verbosity off so V will not fire while we are in transition. + logging.verbosity.set(0) + // Ditto for filter length. + atomic.StoreInt32(&logging.filterLength, 0) + + // Set the new filters and wipe the pc->Level map if the filter has changed. + if setFilter { + logging.vmodule.filter = filter + logging.vmap = make(map[uintptr]Level) + } + + // Things are consistent now, so enable filtering and verbosity. + // They are enabled in order opposite to that in V. + atomic.StoreInt32(&logging.filterLength, int32(len(filter))) + logging.verbosity.set(verbosity) +} + +// getBuffer returns a new, ready-to-use buffer. +func (l *loggingT) getBuffer() *buffer { + l.freeListMu.Lock() + b := l.freeList + if b != nil { + l.freeList = b.next + } + l.freeListMu.Unlock() + if b == nil { + b = new(buffer) + } else { + b.next = nil + b.Reset() + } + return b +} + +// putBuffer returns a buffer to the free list. +func (l *loggingT) putBuffer(b *buffer) { + if b.Len() >= 256 { + // Let big buffers die a natural death. + return + } + l.freeListMu.Lock() + b.next = l.freeList + l.freeList = b + l.freeListMu.Unlock() +} + +var timeNow = time.Now // Stubbed out for testing. + +/* +header formats a log header as defined by the C++ implementation. +It returns a buffer containing the formatted header and the user's file and line number. +The depth specifies how many stack frames above lives the source line to be identified in the log message. + +Log lines have this form: + Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg... +where the fields are defined as follows: + L A single character, representing the log level (eg 'I' for INFO) + mm The month (zero padded; ie May is '05') + dd The day (zero padded) + hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds + threadid The space-padded thread ID as returned by GetTID() + file The file name + line The line number + msg The user-supplied message +*/ +func (l *loggingT) header(s severity, depth int) (*buffer, string, int) { + _, file, line, ok := runtime.Caller(3 + depth) + if !ok { + file = "???" + line = 1 + } else { + slash := strings.LastIndex(file, "/") + if slash >= 0 { + file = file[slash+1:] + } + } + return l.formatHeader(s, file, line), file, line +} + +// formatHeader formats a log header using the provided file name and line number. +func (l *loggingT) formatHeader(s severity, file string, line int) *buffer { + now := timeNow() + if line < 0 { + line = 0 // not a real line number, but acceptable to someDigits + } + if s > fatalLog { + s = infoLog // for safety. + } + buf := l.getBuffer() + + // Avoid Fprintf, for speed. The format is so simple that we can do it quickly by hand. + // It's worth about 3X. Fprintf is hard. + _, month, day := now.Date() + hour, minute, second := now.Clock() + // Lmmdd hh:mm:ss.uuuuuu threadid file:line] + buf.tmp[0] = severityChar[s] + buf.twoDigits(1, int(month)) + buf.twoDigits(3, day) + buf.tmp[5] = ' ' + buf.twoDigits(6, hour) + buf.tmp[8] = ':' + buf.twoDigits(9, minute) + buf.tmp[11] = ':' + buf.twoDigits(12, second) + buf.tmp[14] = '.' + buf.nDigits(6, 15, now.Nanosecond()/1000, '0') + buf.tmp[21] = ' ' + buf.nDigits(7, 22, pid, ' ') // TODO: should be TID + buf.tmp[29] = ' ' + buf.Write(buf.tmp[:30]) + buf.WriteString(file) + buf.tmp[0] = ':' + n := buf.someDigits(1, line) + buf.tmp[n+1] = ']' + buf.tmp[n+2] = ' ' + buf.Write(buf.tmp[:n+3]) + return buf +} + +// Some custom tiny helper functions to print the log header efficiently. + +const digits = "0123456789" + +// twoDigits formats a zero-prefixed two-digit integer at buf.tmp[i]. +func (buf *buffer) twoDigits(i, d int) { + buf.tmp[i+1] = digits[d%10] + d /= 10 + buf.tmp[i] = digits[d%10] +} + +// nDigits formats an n-digit integer at buf.tmp[i], +// padding with pad on the left. +// It assumes d >= 0. +func (buf *buffer) nDigits(n, i, d int, pad byte) { + j := n - 1 + for ; j >= 0 && d > 0; j-- { + buf.tmp[i+j] = digits[d%10] + d /= 10 + } + for ; j >= 0; j-- { + buf.tmp[i+j] = pad + } +} + +// someDigits formats a zero-prefixed variable-width integer at buf.tmp[i]. +func (buf *buffer) someDigits(i, d int) int { + // Print into the top, then copy down. We know there's space for at least + // a 10-digit number. + j := len(buf.tmp) + for { + j-- + buf.tmp[j] = digits[d%10] + d /= 10 + if d == 0 { + break + } + } + return copy(buf.tmp[i:], buf.tmp[j:]) +} + +func (l *loggingT) println(s severity, args ...interface{}) { + buf, file, line := l.header(s, 0) + fmt.Fprintln(buf, args...) + l.output(s, buf, file, line, false) +} + +func (l *loggingT) print(s severity, args ...interface{}) { + l.printDepth(s, 1, args...) +} + +func (l *loggingT) printDepth(s severity, depth int, args ...interface{}) { + buf, file, line := l.header(s, depth) + fmt.Fprint(buf, args...) + if buf.Bytes()[buf.Len()-1] != '\n' { + buf.WriteByte('\n') + } + l.output(s, buf, file, line, false) +} + +func (l *loggingT) printf(s severity, format string, args ...interface{}) { + buf, file, line := l.header(s, 0) + fmt.Fprintf(buf, format, args...) + if buf.Bytes()[buf.Len()-1] != '\n' { + buf.WriteByte('\n') + } + l.output(s, buf, file, line, false) +} + +// printWithFileLine behaves like print but uses the provided file and line number. If +// alsoLogToStderr is true, the log message always appears on standard error; it +// will also appear in the log file unless --logtostderr is set. +func (l *loggingT) printWithFileLine(s severity, file string, line int, alsoToStderr bool, args ...interface{}) { + buf := l.formatHeader(s, file, line) + fmt.Fprint(buf, args...) + if buf.Bytes()[buf.Len()-1] != '\n' { + buf.WriteByte('\n') + } + l.output(s, buf, file, line, alsoToStderr) +} + +// output writes the data to the log files and releases the buffer. +func (l *loggingT) output(s severity, buf *buffer, file string, line int, alsoToStderr bool) { + l.mu.Lock() + if l.traceLocation.isSet() { + if l.traceLocation.match(file, line) { + buf.Write(stacks(false)) + } + } + data := buf.Bytes() + if !flag.Parsed() { + os.Stderr.Write([]byte("ERROR: logging before flag.Parse: ")) + os.Stderr.Write(data) + } else if l.toStderr { + os.Stderr.Write(data) + } else { + if alsoToStderr || l.alsoToStderr || s >= l.stderrThreshold.get() { + os.Stderr.Write(data) + } + if l.file[s] == nil { + if err := l.createFiles(s); err != nil { + os.Stderr.Write(data) // Make sure the message appears somewhere. + l.exit(err) + } + } + switch s { + case fatalLog: + l.file[fatalLog].Write(data) + fallthrough + case errorLog: + l.file[errorLog].Write(data) + fallthrough + case warningLog: + l.file[warningLog].Write(data) + fallthrough + case infoLog: + l.file[infoLog].Write(data) + } + } + if s == fatalLog { + // If we got here via Exit rather than Fatal, print no stacks. + if atomic.LoadUint32(&fatalNoStacks) > 0 { + l.mu.Unlock() + timeoutFlush(10 * time.Second) + os.Exit(1) + } + // Dump all goroutine stacks before exiting. + // First, make sure we see the trace for the current goroutine on standard error. + // If -logtostderr has been specified, the loop below will do that anyway + // as the first stack in the full dump. + if !l.toStderr { + os.Stderr.Write(stacks(false)) + } + // Write the stack trace for all goroutines to the files. + trace := stacks(true) + logExitFunc = func(error) {} // If we get a write error, we'll still exit below. + for log := fatalLog; log >= infoLog; log-- { + if f := l.file[log]; f != nil { // Can be nil if -logtostderr is set. + f.Write(trace) + } + } + l.mu.Unlock() + timeoutFlush(10 * time.Second) + os.Exit(255) // C++ uses -1, which is silly because it's anded with 255 anyway. + } + l.putBuffer(buf) + l.mu.Unlock() + if stats := severityStats[s]; stats != nil { + atomic.AddInt64(&stats.lines, 1) + atomic.AddInt64(&stats.bytes, int64(len(data))) + } +} + +// timeoutFlush calls Flush and returns when it completes or after timeout +// elapses, whichever happens first. This is needed because the hooks invoked +// by Flush may deadlock when glog.Fatal is called from a hook that holds +// a lock. +func timeoutFlush(timeout time.Duration) { + done := make(chan bool, 1) + go func() { + Flush() // calls logging.lockAndFlushAll() + done <- true + }() + select { + case <-done: + case <-time.After(timeout): + fmt.Fprintln(os.Stderr, "glog: Flush took longer than", timeout) + } +} + +// stacks is a wrapper for runtime.Stack that attempts to recover the data for all goroutines. +func stacks(all bool) []byte { + // We don't know how big the traces are, so grow a few times if they don't fit. Start large, though. + n := 10000 + if all { + n = 100000 + } + var trace []byte + for i := 0; i < 5; i++ { + trace = make([]byte, n) + nbytes := runtime.Stack(trace, all) + if nbytes < len(trace) { + return trace[:nbytes] + } + n *= 2 + } + return trace +} + +// logExitFunc provides a simple mechanism to override the default behavior +// of exiting on error. Used in testing and to guarantee we reach a required exit +// for fatal logs. Instead, exit could be a function rather than a method but that +// would make its use clumsier. +var logExitFunc func(error) + +// exit is called if there is trouble creating or writing log files. +// It flushes the logs and exits the program; there's no point in hanging around. +// l.mu is held. +func (l *loggingT) exit(err error) { + fmt.Fprintf(os.Stderr, "log: exiting because of error: %s\n", err) + // If logExitFunc is set, we do that instead of exiting. + if logExitFunc != nil { + logExitFunc(err) + return + } + l.flushAll() + os.Exit(2) +} + +// syncBuffer joins a bufio.Writer to its underlying file, providing access to the +// file's Sync method and providing a wrapper for the Write method that provides log +// file rotation. There are conflicting methods, so the file cannot be embedded. +// l.mu is held for all its methods. +type syncBuffer struct { + logger *loggingT + *bufio.Writer + file *os.File + sev severity + nbytes uint64 // The number of bytes written to this file +} + +func (sb *syncBuffer) Sync() error { + return sb.file.Sync() +} + +func (sb *syncBuffer) Write(p []byte) (n int, err error) { + if sb.nbytes+uint64(len(p)) >= MaxSize { + if err := sb.rotateFile(time.Now()); err != nil { + sb.logger.exit(err) + } + } + n, err = sb.Writer.Write(p) + sb.nbytes += uint64(n) + if err != nil { + sb.logger.exit(err) + } + return +} + +// rotateFile closes the syncBuffer's file and starts a new one. +func (sb *syncBuffer) rotateFile(now time.Time) error { + if sb.file != nil { + sb.Flush() + sb.file.Close() + } + var err error + sb.file, _, err = create(severityName[sb.sev], now) + sb.nbytes = 0 + if err != nil { + return err + } + + sb.Writer = bufio.NewWriterSize(sb.file, bufferSize) + + // Write header. + var buf bytes.Buffer + fmt.Fprintf(&buf, "Log file created at: %s\n", now.Format("2006/01/02 15:04:05")) + fmt.Fprintf(&buf, "Running on machine: %s\n", host) + fmt.Fprintf(&buf, "Binary: Built with %s %s for %s/%s\n", runtime.Compiler, runtime.Version(), runtime.GOOS, runtime.GOARCH) + fmt.Fprintf(&buf, "Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg\n") + n, err := sb.file.Write(buf.Bytes()) + sb.nbytes += uint64(n) + return err +} + +// bufferSize sizes the buffer associated with each log file. It's large +// so that log records can accumulate without the logging thread blocking +// on disk I/O. The flushDaemon will block instead. +const bufferSize = 256 * 1024 + +// createFiles creates all the log files for severity from sev down to infoLog. +// l.mu is held. +func (l *loggingT) createFiles(sev severity) error { + now := time.Now() + // Files are created in decreasing severity order, so as soon as we find one + // has already been created, we can stop. + for s := sev; s >= infoLog && l.file[s] == nil; s-- { + sb := &syncBuffer{ + logger: l, + sev: s, + } + if err := sb.rotateFile(now); err != nil { + return err + } + l.file[s] = sb + } + return nil +} + +const flushInterval = 30 * time.Second + +// flushDaemon periodically flushes the log file buffers. +func (l *loggingT) flushDaemon() { + for _ = range time.NewTicker(flushInterval).C { + l.lockAndFlushAll() + } +} + +// lockAndFlushAll is like flushAll but locks l.mu first. +func (l *loggingT) lockAndFlushAll() { + l.mu.Lock() + l.flushAll() + l.mu.Unlock() +} + +// flushAll flushes all the logs and attempts to "sync" their data to disk. +// l.mu is held. +func (l *loggingT) flushAll() { + // Flush from fatal down, in case there's trouble flushing. + for s := fatalLog; s >= infoLog; s-- { + file := l.file[s] + if file != nil { + file.Flush() // ignore error + file.Sync() // ignore error + } + } +} + +// CopyStandardLogTo arranges for messages written to the Go "log" package's +// default logs to also appear in the Google logs for the named and lower +// severities. Subsequent changes to the standard log's default output location +// or format may break this behavior. +// +// Valid names are "INFO", "WARNING", "ERROR", and "FATAL". If the name is not +// recognized, CopyStandardLogTo panics. +func CopyStandardLogTo(name string) { + sev, ok := severityByName(name) + if !ok { + panic(fmt.Sprintf("log.CopyStandardLogTo(%q): unrecognized severity name", name)) + } + // Set a log format that captures the user's file and line: + // d.go:23: message + stdLog.SetFlags(stdLog.Lshortfile) + stdLog.SetOutput(logBridge(sev)) +} + +// logBridge provides the Write method that enables CopyStandardLogTo to connect +// Go's standard logs to the logs provided by this package. +type logBridge severity + +// Write parses the standard logging line and passes its components to the +// logger for severity(lb). +func (lb logBridge) Write(b []byte) (n int, err error) { + var ( + file = "???" + line = 1 + text string + ) + // Split "d.go:23: message" into "d.go", "23", and "message". + if parts := bytes.SplitN(b, []byte{':'}, 3); len(parts) != 3 || len(parts[0]) < 1 || len(parts[2]) < 1 { + text = fmt.Sprintf("bad log format: %s", b) + } else { + file = string(parts[0]) + text = string(parts[2][1:]) // skip leading space + line, err = strconv.Atoi(string(parts[1])) + if err != nil { + text = fmt.Sprintf("bad line number: %s", b) + line = 1 + } + } + // printWithFileLine with alsoToStderr=true, so standard log messages + // always appear on standard error. + logging.printWithFileLine(severity(lb), file, line, true, text) + return len(b), nil +} + +// setV computes and remembers the V level for a given PC +// when vmodule is enabled. +// File pattern matching takes the basename of the file, stripped +// of its .go suffix, and uses filepath.Match, which is a little more +// general than the *? matching used in C++. +// l.mu is held. +func (l *loggingT) setV(pc uintptr) Level { + fn := runtime.FuncForPC(pc) + file, _ := fn.FileLine(pc) + // The file is something like /a/b/c/d.go. We want just the d. + if strings.HasSuffix(file, ".go") { + file = file[:len(file)-3] + } + if slash := strings.LastIndex(file, "/"); slash >= 0 { + file = file[slash+1:] + } + for _, filter := range l.vmodule.filter { + if filter.match(file) { + l.vmap[pc] = filter.level + return filter.level + } + } + l.vmap[pc] = 0 + return 0 +} + +// Verbose is a boolean type that implements Infof (like Printf) etc. +// See the documentation of V for more information. +type Verbose bool + +// V reports whether verbosity at the call site is at least the requested level. +// The returned value is a boolean of type Verbose, which implements Info, Infoln +// and Infof. These methods will write to the Info log if called. +// Thus, one may write either +// if glog.V(2) { glog.Info("log this") } +// or +// glog.V(2).Info("log this") +// The second form is shorter but the first is cheaper if logging is off because it does +// not evaluate its arguments. +// +// Whether an individual call to V generates a log record depends on the setting of +// the -v and --vmodule flags; both are off by default. If the level in the call to +// V is at least the value of -v, or of -vmodule for the source file containing the +// call, the V call will log. +func V(level Level) Verbose { + // This function tries hard to be cheap unless there's work to do. + // The fast path is two atomic loads and compares. + + // Here is a cheap but safe test to see if V logging is enabled globally. + if logging.verbosity.get() >= level { + return Verbose(true) + } + + // It's off globally but it vmodule may still be set. + // Here is another cheap but safe test to see if vmodule is enabled. + if atomic.LoadInt32(&logging.filterLength) > 0 { + // Now we need a proper lock to use the logging structure. The pcs field + // is shared so we must lock before accessing it. This is fairly expensive, + // but if V logging is enabled we're slow anyway. + logging.mu.Lock() + defer logging.mu.Unlock() + if runtime.Callers(2, logging.pcs[:]) == 0 { + return Verbose(false) + } + v, ok := logging.vmap[logging.pcs[0]] + if !ok { + v = logging.setV(logging.pcs[0]) + } + return Verbose(v >= level) + } + return Verbose(false) +} + +// Info is equivalent to the global Info function, guarded by the value of v. +// See the documentation of V for usage. +func (v Verbose) Info(args ...interface{}) { + if v { + logging.print(infoLog, args...) + } +} + +// Infoln is equivalent to the global Infoln function, guarded by the value of v. +// See the documentation of V for usage. +func (v Verbose) Infoln(args ...interface{}) { + if v { + logging.println(infoLog, args...) + } +} + +// Infof is equivalent to the global Infof function, guarded by the value of v. +// See the documentation of V for usage. +func (v Verbose) Infof(format string, args ...interface{}) { + if v { + logging.printf(infoLog, format, args...) + } +} + +// Info logs to the INFO log. +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Info(args ...interface{}) { + logging.print(infoLog, args...) +} + +// InfoDepth acts as Info but uses depth to determine which call frame to log. +// InfoDepth(0, "msg") is the same as Info("msg"). +func InfoDepth(depth int, args ...interface{}) { + logging.printDepth(infoLog, depth, args...) +} + +// Infoln logs to the INFO log. +// Arguments are handled in the manner of fmt.Println; a newline is appended if missing. +func Infoln(args ...interface{}) { + logging.println(infoLog, args...) +} + +// Infof logs to the INFO log. +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Infof(format string, args ...interface{}) { + logging.printf(infoLog, format, args...) +} + +// Warning logs to the WARNING and INFO logs. +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Warning(args ...interface{}) { + logging.print(warningLog, args...) +} + +// WarningDepth acts as Warning but uses depth to determine which call frame to log. +// WarningDepth(0, "msg") is the same as Warning("msg"). +func WarningDepth(depth int, args ...interface{}) { + logging.printDepth(warningLog, depth, args...) +} + +// Warningln logs to the WARNING and INFO logs. +// Arguments are handled in the manner of fmt.Println; a newline is appended if missing. +func Warningln(args ...interface{}) { + logging.println(warningLog, args...) +} + +// Warningf logs to the WARNING and INFO logs. +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Warningf(format string, args ...interface{}) { + logging.printf(warningLog, format, args...) +} + +// Error logs to the ERROR, WARNING, and INFO logs. +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Error(args ...interface{}) { + logging.print(errorLog, args...) +} + +// ErrorDepth acts as Error but uses depth to determine which call frame to log. +// ErrorDepth(0, "msg") is the same as Error("msg"). +func ErrorDepth(depth int, args ...interface{}) { + logging.printDepth(errorLog, depth, args...) +} + +// Errorln logs to the ERROR, WARNING, and INFO logs. +// Arguments are handled in the manner of fmt.Println; a newline is appended if missing. +func Errorln(args ...interface{}) { + logging.println(errorLog, args...) +} + +// Errorf logs to the ERROR, WARNING, and INFO logs. +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Errorf(format string, args ...interface{}) { + logging.printf(errorLog, format, args...) +} + +// Fatal logs to the FATAL, ERROR, WARNING, and INFO logs, +// including a stack trace of all running goroutines, then calls os.Exit(255). +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Fatal(args ...interface{}) { + logging.print(fatalLog, args...) +} + +// FatalDepth acts as Fatal but uses depth to determine which call frame to log. +// FatalDepth(0, "msg") is the same as Fatal("msg"). +func FatalDepth(depth int, args ...interface{}) { + logging.printDepth(fatalLog, depth, args...) +} + +// Fatalln logs to the FATAL, ERROR, WARNING, and INFO logs, +// including a stack trace of all running goroutines, then calls os.Exit(255). +// Arguments are handled in the manner of fmt.Println; a newline is appended if missing. +func Fatalln(args ...interface{}) { + logging.println(fatalLog, args...) +} + +// Fatalf logs to the FATAL, ERROR, WARNING, and INFO logs, +// including a stack trace of all running goroutines, then calls os.Exit(255). +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Fatalf(format string, args ...interface{}) { + logging.printf(fatalLog, format, args...) +} + +// fatalNoStacks is non-zero if we are to exit without dumping goroutine stacks. +// It allows Exit and relatives to use the Fatal logs. +var fatalNoStacks uint32 + +// Exit logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1). +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Exit(args ...interface{}) { + atomic.StoreUint32(&fatalNoStacks, 1) + logging.print(fatalLog, args...) +} + +// ExitDepth acts as Exit but uses depth to determine which call frame to log. +// ExitDepth(0, "msg") is the same as Exit("msg"). +func ExitDepth(depth int, args ...interface{}) { + atomic.StoreUint32(&fatalNoStacks, 1) + logging.printDepth(fatalLog, depth, args...) +} + +// Exitln logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1). +func Exitln(args ...interface{}) { + atomic.StoreUint32(&fatalNoStacks, 1) + logging.println(fatalLog, args...) +} + +// Exitf logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1). +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Exitf(format string, args ...interface{}) { + atomic.StoreUint32(&fatalNoStacks, 1) + logging.printf(fatalLog, format, args...) +} diff --git a/vendor/github.com/golang/glog/glog_file.go b/vendor/github.com/golang/glog/glog_file.go new file mode 100644 index 0000000000..65075d2811 --- /dev/null +++ b/vendor/github.com/golang/glog/glog_file.go @@ -0,0 +1,124 @@ +// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/ +// +// Copyright 2013 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// File I/O for logs. + +package glog + +import ( + "errors" + "flag" + "fmt" + "os" + "os/user" + "path/filepath" + "strings" + "sync" + "time" +) + +// MaxSize is the maximum size of a log file in bytes. +var MaxSize uint64 = 1024 * 1024 * 1800 + +// logDirs lists the candidate directories for new log files. +var logDirs []string + +// If non-empty, overrides the choice of directory in which to write logs. +// See createLogDirs for the full list of possible destinations. +var logDir = flag.String("log_dir", "", "If non-empty, write log files in this directory") + +func createLogDirs() { + if *logDir != "" { + logDirs = append(logDirs, *logDir) + } + logDirs = append(logDirs, os.TempDir()) +} + +var ( + pid = os.Getpid() + program = filepath.Base(os.Args[0]) + host = "unknownhost" + userName = "unknownuser" +) + +func init() { + h, err := os.Hostname() + if err == nil { + host = shortHostname(h) + } + + current, err := user.Current() + if err == nil { + userName = current.Username + } + + // Sanitize userName since it may contain filepath separators on Windows. + userName = strings.Replace(userName, `\`, "_", -1) +} + +// shortHostname returns its argument, truncating at the first period. +// For instance, given "www.google.com" it returns "www". +func shortHostname(hostname string) string { + if i := strings.Index(hostname, "."); i >= 0 { + return hostname[:i] + } + return hostname +} + +// logName returns a new log file name containing tag, with start time t, and +// the name for the symlink for tag. +func logName(tag string, t time.Time) (name, link string) { + name = fmt.Sprintf("%s.%s.%s.log.%s.%04d%02d%02d-%02d%02d%02d.%d", + program, + host, + userName, + tag, + t.Year(), + t.Month(), + t.Day(), + t.Hour(), + t.Minute(), + t.Second(), + pid) + return name, program + "." + tag +} + +var onceLogDirs sync.Once + +// create creates a new log file and returns the file and its filename, which +// contains tag ("INFO", "FATAL", etc.) and t. If the file is created +// successfully, create also attempts to update the symlink for that tag, ignoring +// errors. +func create(tag string, t time.Time) (f *os.File, filename string, err error) { + onceLogDirs.Do(createLogDirs) + if len(logDirs) == 0 { + return nil, "", errors.New("log: no log dirs") + } + name, link := logName(tag, t) + var lastErr error + for _, dir := range logDirs { + fname := filepath.Join(dir, name) + f, err := os.Create(fname) + if err == nil { + symlink := filepath.Join(dir, link) + os.Remove(symlink) // ignore err + os.Symlink(name, symlink) // ignore err + return f, fname, nil + } + lastErr = err + } + return nil, "", fmt.Errorf("log: cannot create log: %v", lastErr) +} diff --git a/vendor/github.com/mdlayher/genetlink/CHANGELOG.md b/vendor/github.com/mdlayher/genetlink/CHANGELOG.md new file mode 100644 index 0000000000..6860e4bab9 --- /dev/null +++ b/vendor/github.com/mdlayher/genetlink/CHANGELOG.md @@ -0,0 +1,9 @@ +# CHANGELOG + +## Unreleased + +n/a + +## v1.0.0 + +- Initial stable commit. diff --git a/vendor/github.com/mdlayher/genetlink/LICENSE.md b/vendor/github.com/mdlayher/genetlink/LICENSE.md new file mode 100644 index 0000000000..255dbe62fc --- /dev/null +++ b/vendor/github.com/mdlayher/genetlink/LICENSE.md @@ -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. diff --git a/vendor/github.com/mdlayher/genetlink/README.md b/vendor/github.com/mdlayher/genetlink/README.md new file mode 100644 index 0000000000..a619295e41 --- /dev/null +++ b/vendor/github.com/mdlayher/genetlink/README.md @@ -0,0 +1,27 @@ +genetlink [![builds.sr.ht status](https://builds.sr.ht/~mdlayher/genetlink.svg)](https://builds.sr.ht/~mdlayher/genetlink?) [![GoDoc](https://godoc.org/github.com/mdlayher/genetlink?status.svg)](https://godoc.org/github.com/mdlayher/genetlink) [![Go Report Card](https://goreportcard.com/badge/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.** diff --git a/vendor/github.com/mdlayher/genetlink/conn.go b/vendor/github.com/mdlayher/genetlink/conn.go new file mode 100644 index 0000000000..43a667b162 --- /dev/null +++ b/vendor/github.com/mdlayher/genetlink/conn.go @@ -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 +} diff --git a/vendor/github.com/mdlayher/genetlink/doc.go b/vendor/github.com/mdlayher/genetlink/doc.go new file mode 100644 index 0000000000..9bc3530c46 --- /dev/null +++ b/vendor/github.com/mdlayher/genetlink/doc.go @@ -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 diff --git a/vendor/github.com/mdlayher/genetlink/family.go b/vendor/github.com/mdlayher/genetlink/family.go new file mode 100644 index 0000000000..680f74f93f --- /dev/null +++ b/vendor/github.com/mdlayher/genetlink/family.go @@ -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 +} diff --git a/vendor/github.com/mdlayher/genetlink/family_linux.go b/vendor/github.com/mdlayher/genetlink/family_linux.go new file mode 100644 index 0000000000..af5c7eb963 --- /dev/null +++ b/vendor/github.com/mdlayher/genetlink/family_linux.go @@ -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 +} diff --git a/vendor/github.com/mdlayher/genetlink/family_others.go b/vendor/github.com/mdlayher/genetlink/family_others.go new file mode 100644 index 0000000000..19be1b9be9 --- /dev/null +++ b/vendor/github.com/mdlayher/genetlink/family_others.go @@ -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 +} diff --git a/vendor/github.com/mdlayher/genetlink/fuzz.go b/vendor/github.com/mdlayher/genetlink/fuzz.go new file mode 100644 index 0000000000..bcd8cce01b --- /dev/null +++ b/vendor/github.com/mdlayher/genetlink/fuzz.go @@ -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 +} diff --git a/vendor/github.com/mdlayher/genetlink/go.mod b/vendor/github.com/mdlayher/genetlink/go.mod new file mode 100644 index 0000000000..ee52e4615f --- /dev/null +++ b/vendor/github.com/mdlayher/genetlink/go.mod @@ -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 +) diff --git a/vendor/github.com/mdlayher/genetlink/go.sum b/vendor/github.com/mdlayher/genetlink/go.sum new file mode 100644 index 0000000000..a8690be9ef --- /dev/null +++ b/vendor/github.com/mdlayher/genetlink/go.sum @@ -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= diff --git a/vendor/github.com/mdlayher/genetlink/message.go b/vendor/github.com/mdlayher/genetlink/message.go new file mode 100644 index 0000000000..6b34044f76 --- /dev/null +++ b/vendor/github.com/mdlayher/genetlink/message.go @@ -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 +} diff --git a/vendor/github.com/mdlayher/netlink/.gitignore b/vendor/github.com/mdlayher/netlink/.gitignore new file mode 100644 index 0000000000..cc75a0df05 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/.gitignore @@ -0,0 +1,2 @@ +cmd/nlstress/nlstress +netlink.test diff --git a/vendor/github.com/mdlayher/netlink/CHANGELOG.md b/vendor/github.com/mdlayher/netlink/CHANGELOG.md new file mode 100644 index 0000000000..9b5f766684 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/CHANGELOG.md @@ -0,0 +1,22 @@ +# CHANGELOG + +## Unreleased + +- n/a + +## 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. diff --git a/vendor/github.com/mdlayher/netlink/LICENSE.md b/vendor/github.com/mdlayher/netlink/LICENSE.md new file mode 100644 index 0000000000..0018ed3e55 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/LICENSE.md @@ -0,0 +1,10 @@ +MIT License +=========== + +Copyright (C) 2016-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. diff --git a/vendor/github.com/mdlayher/netlink/README.md b/vendor/github.com/mdlayher/netlink/README.md new file mode 100644 index 0000000000..7c214533dc --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/README.md @@ -0,0 +1,51 @@ +# netlink [![builds.sr.ht status](https://builds.sr.ht/~mdlayher/netlink.svg)](https://builds.sr.ht/~mdlayher/netlink?) [![GoDoc](https://godoc.org/github.com/mdlayher/netlink?status.svg)](https://godoc.org/github.com/mdlayher/netlink) [![Go Report Card](https://goreportcard.com/badge/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. + +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/netlink/issues/new). + +**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! + +![netlink ecosystem](./netlink.svg) diff --git a/vendor/github.com/mdlayher/netlink/align.go b/vendor/github.com/mdlayher/netlink/align.go new file mode 100644 index 0000000000..20892c7016 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/align.go @@ -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) diff --git a/vendor/github.com/mdlayher/netlink/attribute.go b/vendor/github.com/mdlayher/netlink/attribute.go new file mode 100644 index 0000000000..cee748d0ff --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/attribute.go @@ -0,0 +1,589 @@ +package netlink + +import ( + "encoding/binary" + "errors" + "fmt" + + "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: nlenc.NativeEndian(), + + 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) +} + +// 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: nlenc.NativeEndian(), + } +} + +// 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, + }) +} + +// 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) +} diff --git a/vendor/github.com/mdlayher/netlink/conn.go b/vendor/github.com/mdlayher/netlink/conn.go new file mode 100644 index 0000000000..5baaf9b614 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/conn.go @@ -0,0 +1,604 @@ +package netlink + +import ( + "errors" + "math/rand" + "os" + "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 { + // sock is the operating system-specific implementation of + // a netlink sockets connection. + sock Socket + + // seq is an atomically incremented integer used to provide sequence + // numbers when Conn.Send is called. + seq *uint32 + + // pid is the PID assigned by netlink. + pid uint32 + + // d provides debugging capabilities for a Conn if not nil. + d *debugger + + // mu serializes access to the netlink socket for the request/response + // transaction within Execute. + mu sync.RWMutex +} + +// 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{ + sock: sock, + seq: &seq, + 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. Close will unblock any concurrent calls to +// Receive which are waiting on a response from the kernel. +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(message 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(message) + if err != nil { + return nil, err + } + + replies, err := c.lockedReceive() + if err != nil { + return nil, err + } + + if err := Validate(req, replies); err != nil { + return nil, err + } + + return replies, 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(messages []Message) ([]Message, error) { + // Wait for any concurrent calls to Execute to finish before proceeding. + c.mu.RLock() + defer c.mu.RUnlock() + + for idx, m := range messages { + ml := nlmsgLength(len(m.Data)) + + // TODO(mdlayher): fine-tune this limit. + if ml > (1024 * 32) { + return nil, errors.New("netlink message data too large") + } + + c.fixMsg(&messages[idx], ml) + } + + c.debug(func(d *debugger) { + for _, m := range messages { + d.debugf(1, "send msgs: %+v", m) + } + }) + + if err := c.sock.SendMessages(messages); err != nil { + c.debug(func(d *debugger) { + d.debugf(1, "send msgs: err: %v", err) + }) + + return nil, newOpError("send-messages", err) + } + + return messages, 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(message Message) (Message, error) { + // Wait for any concurrent calls to Execute to finish before proceeding. + c.mu.RLock() + defer c.mu.RUnlock() + + return c.lockedSend(message) +} + +// 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(message Message) (Message, error) { + ml := nlmsgLength(len(message.Data)) + + // TODO(mdlayher): fine-tune this limit. + if ml > (1024 * 32) { + return Message{}, errors.New("netlink message data too large") + } + + c.fixMsg(&message, ml) + + c.debug(func(d *debugger) { + d.debugf(1, "send: %+v", message) + }) + + if err := c.sock.Send(message); err != nil { + c.debug(func(d *debugger) { + d.debugf(1, "send: err: %v", err) + }) + + return Message{}, newOpError("send", err) + } + + return message, 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 perform an recursive call + // to continue draining 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. +// +// 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 { + 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. +// +// 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 { + 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. +// +// 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 { + 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 +) + +// 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 filer is a Socket that supports retrieving its associated *os.File. +type filer interface { + Socket + File() *os.File +} + +var _ syscall.Conn = &Conn{} + +// TODO(mdlayher): mutex or similar to enforce syscall.RawConn contract of +// FD remaining valid for duration of calls? + +// 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) { + fc, ok := c.sock.(filer) + if !ok { + return nil, notSupported("syscall-conn") + } + + return newRawConn(fc.File()) +} + +// 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 disables package netlink's default goroutine thread + // locking behavior. + // + // By default, the library will lock the processing goroutine to its + // corresponding OS thread in order to enable communication over netlink to + // a different network namespace. + // + // If the caller already knows that the netlink socket is in the same + // namespace as the calling thread, this can introduce a performance + // impact. This option disables the OS thread locking behavior if + // performance considerations are of interest. + // + // If disabled, it is the responsibility of the caller to make sure that all + // threads are running in the correct namespace. + // + // When DisableNSLockThread is set, the caller cannot set the NetNS value. + DisableNSLockThread bool +} diff --git a/vendor/github.com/mdlayher/netlink/conn_linux.go b/vendor/github.com/mdlayher/netlink/conn_linux.go new file mode 100644 index 0000000000..61af3a2407 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/conn_linux.go @@ -0,0 +1,772 @@ +//+build linux + +package netlink + +import ( + "errors" + "math" + "os" + "runtime" + "sync" + "syscall" + "time" + "unsafe" + + "golang.org/x/net/bpf" + "golang.org/x/sys/unix" +) + +var _ Socket = &conn{} + +var _ deadlineSetter = &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 + sa *unix.SockaddrNetlink +} + +// A socket is an interface over socket system calls. +type socket interface { + Bind(sa unix.Sockaddr) error + Close() error + FD() int + File() *os.File + Getsockname() (unix.Sockaddr, error) + Recvmsg(p, oob []byte, flags int) (n int, oobn int, recvflags int, from unix.Sockaddr, err error) + Sendmsg(p, oob []byte, to unix.Sockaddr, flags int) error + SetDeadline(t time.Time) error + SetReadDeadline(t time.Time) error + SetWriteDeadline(t time.Time) error + SetSockoptSockFprog(level, opt int, fprog *unix.SockFprog) error + SetSockoptInt(level, opt, value int) error +} + +// 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{} + } + + sock, err := newSysSocket(config) + if err != nil { + return nil, 0, err + } + + if err := sock.Socket(family); err != nil { + return nil, 0, os.NewSyscallError("socket", err) + } + + return bind(sock, config) +} + +// bind binds a connection to netlink using the input socket, which may be +// a system call implementation or a mocked one for tests. +func bind(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) + } + + pid := sa.(*unix.SockaddrNetlink).Pid + + return &conn{ + s: s, + sa: addr, + }, 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...) + } + + addr := &unix.SockaddrNetlink{ + Family: unix.AF_NETLINK, + } + + return os.NewSyscallError("sendmsg", c.s.Sendmsg(buf, nil, addr, 0)) +} + +// Send sends a single Message to netlink. +func (c *conn) Send(m Message) error { + b, err := m.MarshalBinary() + if err != nil { + return err + } + + addr := &unix.SockaddrNetlink{ + Family: unix.AF_NETLINK, + } + + return os.NewSyscallError("sendmsg", c.s.Sendmsg(b, nil, addr, 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) + } + + n = nlmsgAlign(n) + + raw, err := syscall.ParseNetlinkMessage(b[: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()) +} + +// FD retrieves the file descriptor of the Conn. +func (c *conn) FD() int { + return c.s.FD() +} + +// File retrieves the *os.File associated with the Conn. +func (c *conn) File() *os.File { + return c.s.File() +} + +// 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 { + 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 { + return os.NewSyscallError("setsockopt", c.s.SetSockoptInt( + unix.SOL_SOCKET, + unix.SO_RCVBUF, + bytes, + )) +} + +// SetReadBuffer sets the size of the operating system's transmit buffer +// associated with the Conn. +func (c *conn) SetWriteBuffer(bytes int) error { + return os.NewSyscallError("setsockopt", c.s.SetSockoptInt( + unix.SOL_SOCKET, + unix.SO_SNDBUF, + bytes, + )) +} + +// 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 + 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) +} + +var _ socket = &sysSocket{} + +// A sysSocket is a socket which uses system calls for socket operations. +type sysSocket struct { + mu sync.RWMutex + fd *os.File + closed bool + g *lockedNetNSGoroutine +} + +// newSysSocket creates a sysSocket that optionally locks its internal goroutine +// to a single thread. +func newSysSocket(config *Config) (*sysSocket, error) { + // Determine network namespaces using the threadNetNS function. + g, err := newLockedNetNSGoroutine(config.NetNS, threadNetNS, !config.DisableNSLockThread) + if err != nil { + return nil, err + } + return &sysSocket{ + g: g, + }, nil +} + +// do runs f in a worker goroutine which can be locked to one thread. +func (s *sysSocket) do(f func()) error { + // All operations handled by this function are assumed to only + // read from s.done. + s.mu.RLock() + defer s.mu.RUnlock() + + if s.closed { + return syscall.EBADF + } + + s.g.run(f) + return nil +} + +// read executes f, a read function, against the associated file descriptor. +func (s *sysSocket) read(f func(fd int) bool) error { + s.mu.RLock() + defer s.mu.RUnlock() + + if s.closed { + return syscall.EBADF + } + + var err error + s.g.run(func() { + err = fdread(s.fd, f) + }) + return err +} + +// write executes f, a write function, against the associated file descriptor. +func (s *sysSocket) write(f func(fd int) bool) error { + s.mu.RLock() + defer s.mu.RUnlock() + + if s.closed { + return syscall.EBADF + } + + var err error + s.g.run(func() { + err = fdwrite(s.fd, f) + }) + return err +} + +// control executes f, a control function, against the associated file descriptor. +func (s *sysSocket) control(f func(fd int)) error { + s.mu.RLock() + defer s.mu.RUnlock() + + if s.closed { + return syscall.EBADF + } + + var err error + s.g.run(func() { + err = fdcontrol(s.fd, f) + }) + return err +} + +func (s *sysSocket) Socket(family int) error { + var ( + fd int + err error + ) + + doErr := s.do(func() { + // 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. + // + // SOCK_NONBLOCK was also added in 2.6.27, but we don't + // use SOCK_NONBLOCK here for now, not until we remove support + // for Go 1.11, since we still support the old blocking file + // descriptor behavior. + // + // 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. + // + // TODO(acln): update this to mirror net.sysSocket completely: + // use SOCK_NONBLOCK as well, and remove the separate + // setBlockingMode step once Go 1.11 support is removed and + // we switch to using entirely non-blocking file descriptors. + fd, err = unix.Socket( + unix.AF_NETLINK, + unix.SOCK_RAW|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 doErr != nil { + return doErr + } + if err != nil { + return err + } + + if err := setBlockingMode(fd); err != nil { + return err + } + + // When using Go 1.12+, the setBlockingMode call we just did puts the + // file descriptor into non-blocking mode. In that case, os.NewFile + // registers the file descriptor with the runtime poller, which is + // then used for all subsequent operations. + // + // See also: https://golang.org/pkg/os/#NewFile + s.fd = os.NewFile(uintptr(fd), "netlink") + return nil +} + +func (s *sysSocket) 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 *sysSocket) Close() error { + // Be sure to acquire a write lock because we need to stop any other + // goroutines from sending system call requests after close. + // Any invocation of do() after this write lock unlocks is guaranteed + // to find s.done being true. + s.mu.Lock() + defer s.mu.Unlock() + + // Close the socket from the main thread, this operation has no risk + // of routing data to the wrong socket. + err := s.fd.Close() + s.closed = true + + // Stop the associated goroutine and wait for it to return. + s.g.stop() + + return err +} + +func (s *sysSocket) FD() int { return int(s.fd.Fd()) } + +func (s *sysSocket) File() *os.File { return s.fd } + +func (s *sysSocket) 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 *sysSocket) 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 *sysSocket) 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 *sysSocket) SetDeadline(t time.Time) error { + return s.fd.SetDeadline(t) +} + +func (s *sysSocket) SetReadDeadline(t time.Time) error { + return s.fd.SetReadDeadline(t) +} + +func (s *sysSocket) SetWriteDeadline(t time.Time) error { + return s.fd.SetWriteDeadline(t) +} + +func (s *sysSocket) 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 *sysSocket) 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 + } +} + +// lockedNetNSGoroutine is a worker goroutine locked to an operating system +// thread, optionally configured to run in a non-default network namespace. +type lockedNetNSGoroutine struct { + wg sync.WaitGroup + doneC chan struct{} + funcC chan func() +} + +// newLockedNetNSGoroutine creates a lockedNetNSGoroutine that will enter the +// specified network namespace netNS (by file descriptor), and will use the +// getNS function to produce netNS handles. +func newLockedNetNSGoroutine(netNS int, getNS func() (*netNS, error), lockThread bool) (*lockedNetNSGoroutine, error) { + // Any bare syscall errors (e.g. setns) should be wrapped with + // os.NewSyscallError for the remainder of this function. + + // If the caller has instructed us to not lock OS thread but also attempts + // to set a namespace, return an error. + if !lockThread && netNS != 0 { + return nil, errors.New("netlink Conn attempted to set a namespace with OS thread locking disabled") + } + + callerNS, err := getNS() + if err != nil { + return nil, err + } + defer callerNS.Close() + + g := &lockedNetNSGoroutine{ + doneC: make(chan struct{}), + funcC: make(chan func()), + } + + errC := make(chan error) + g.wg.Add(1) + + go func() { + // It is important to lock this goroutine to its OS thread for the duration + // of the netlink socket being used, or else the kernel may end up routing + // messages to the wrong places. + // See: http://lists.infradead.org/pipermail/libnl/2017-February/002293.html. + // + // + // In addition, the OS thread must also remain locked because we attempt + // to manipulate the network namespace of the thread within this goroutine. + // + // The intent is to never unlock the OS thread, so that the thread + // will terminate when the goroutine exits starting in Go 1.10: + // https://go-review.googlesource.com/c/go/+/46038. + // + // However, due to recent instability and a potential bad interaction + // with the Go runtime for threads which are not unlocked, we have + // elected to temporarily unlock the thread when the goroutine terminates: + // https://github.com/golang/go/issues/25128#issuecomment-410764489. + // + // Locking the thread is not implemented if the caller explicitly asks + // for an unlocked thread. + + // Only lock the tread, if the lockThread is set. + if lockThread { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + } + + defer g.wg.Done() + + // Get the current namespace of the thread the goroutine is locked to. + threadNS, err := getNS() + if err != nil { + errC <- err + return + } + defer threadNS.Close() + + // Attempt to set the network namespace of the current thread to either: + // - the namespace referred to by the provided file descriptor from config + // - the calling thread's namespace + // + // See the rules specified in the Config.NetNS documentation. + explicitNS := true + if netNS == 0 { + explicitNS = false + netNS = int(callerNS.FD()) + } + + // Only return an error if the network namespace was explicitly + // configured; implicit configuration by zero value should be ignored. + err = threadNS.Set(netNS) + switch { + case err != nil && explicitNS: + errC <- err + return + case err == nil: + // If the thread's namespace has been successfully manipulated, + // make sure we change it back when the goroutine returns. + defer threadNS.Restore() + default: + // We couldn't successfully set the namespace, but the caller didn't + // explicitly ask for it to be set either. Continue. + } + + // Signal to caller that initialization was successful. + errC <- nil + + for { + select { + case <-g.doneC: + return + case f := <-g.funcC: + f() + } + } + }() + + // Wait for the goroutine to return err or nil. + if err := <-errC; err != nil { + return nil, err + } + + return g, nil +} + +// stop signals the goroutine to stop and blocks until it does. +// +// It is invalid to call run concurrently with stop. It is also invalid to +// call run after stop has returned. +func (g *lockedNetNSGoroutine) stop() { + close(g.doneC) + g.wg.Wait() +} + +// run runs f on the worker goroutine. +func (g *lockedNetNSGoroutine) run(f func()) { + done := make(chan struct{}) + g.funcC <- func() { + defer close(done) + f() + } + <-done +} diff --git a/vendor/github.com/mdlayher/netlink/conn_others.go b/vendor/github.com/mdlayher/netlink/conn_others.go new file mode 100644 index 0000000000..41ebca970c --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/conn_others.go @@ -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 } diff --git a/vendor/github.com/mdlayher/netlink/debug.go b/vendor/github.com/mdlayher/netlink/debug.go new file mode 100644 index 0000000000..d39d66c58a --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/debug.go @@ -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...)) +} diff --git a/vendor/github.com/mdlayher/netlink/doc.go b/vendor/github.com/mdlayher/netlink/doc.go new file mode 100644 index 0000000000..7948beb078 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/doc.go @@ -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 diff --git a/vendor/github.com/mdlayher/netlink/errors.go b/vendor/github.com/mdlayher/netlink/errors.go new file mode 100644 index 0000000000..648f409fea --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/errors.go @@ -0,0 +1,128 @@ +package netlink + +import ( + "errors" + "fmt" + "net" + "os" +) + +// 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: + // TODO(mdlayher): more error handling logic? + + // 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 a helper such as IsNotExist. + Err error +} + +// 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 "" + } + + return fmt.Sprintf("netlink %s: %v", e.Op, e.Err) +} + +// 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() +} diff --git a/vendor/github.com/mdlayher/netlink/fdcall_gteq_1.12.go b/vendor/github.com/mdlayher/netlink/fdcall_gteq_1.12.go new file mode 100644 index 0000000000..4391092fdb --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/fdcall_gteq_1.12.go @@ -0,0 +1,44 @@ +//+build go1.12,linux + +package netlink + +import ( + "os" + + "golang.org/x/sys/unix" +) + +// setBlockingMode puts the file descriptor into non-blocking mode. +func setBlockingMode(sysfd int) error { + return unix.SetNonblock(sysfd, true) +} + +func fdread(fd *os.File, f func(int) (done bool)) error { + rc, err := fd.SyscallConn() + if err != nil { + return err + } + return rc.Read(func(sysfd uintptr) bool { + return f(int(sysfd)) + }) +} + +func fdwrite(fd *os.File, f func(int) (done bool)) error { + rc, err := fd.SyscallConn() + if err != nil { + return err + } + return rc.Write(func(sysfd uintptr) bool { + return f(int(sysfd)) + }) +} + +func fdcontrol(fd *os.File, f func(int)) error { + rc, err := fd.SyscallConn() + if err != nil { + return err + } + return rc.Control(func(sysfd uintptr) { + f(int(sysfd)) + }) +} diff --git a/vendor/github.com/mdlayher/netlink/fdcall_lt_1.12.go b/vendor/github.com/mdlayher/netlink/fdcall_lt_1.12.go new file mode 100644 index 0000000000..1bee370a85 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/fdcall_lt_1.12.go @@ -0,0 +1,29 @@ +//+build !go1.12,linux + +package netlink + +import "os" + +// setBlockingMode exists for compatibility reasons: prior to Go 1.12, +// package netlink used blocking file descriptors, and did not support +// deadlines. This variant of setBlockingMode, which does nothing (i.e. +// it leaves the file descriptor in blocking mode), maintains compatibility +// for users up to and including Go 1.11. +func setBlockingMode(sysfd int) error { + return nil +} + +func fdread(fd *os.File, f func(int) (done bool)) error { + f(int(fd.Fd())) + return nil +} + +func fdwrite(fd *os.File, f func(int) (done bool)) error { + f(int(fd.Fd())) + return nil +} + +func fdcontrol(fd *os.File, f func(int)) error { + f(int(fd.Fd())) + return nil +} diff --git a/vendor/github.com/mdlayher/netlink/fuzz.go b/vendor/github.com/mdlayher/netlink/fuzz.go new file mode 100644 index 0000000000..2f37e58471 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/fuzz.go @@ -0,0 +1,34 @@ +//+build gofuzz + +package netlink + +func Fuzz(data []byte) int { + return fuzzAttributes(data) + // return fuzzMessage(data) +} + +func fuzzAttributes(data []byte) int { + attrs, err := UnmarshalAttributes(data) + if err != nil { + return 0 + } + + if _, err := MarshalAttributes(attrs); err != nil { + panic(err) + } + + return 1 +} + +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 +} diff --git a/vendor/github.com/mdlayher/netlink/go.mod b/vendor/github.com/mdlayher/netlink/go.mod new file mode 100644 index 0000000000..ddc9d3533c --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/go.mod @@ -0,0 +1,10 @@ +module github.com/mdlayher/netlink + +go 1.12 + +require ( + github.com/google/go-cmp v0.4.0 + github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4 + golang.org/x/net v0.0.0-20200202094626-16171245cfb2 + golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 +) diff --git a/vendor/github.com/mdlayher/netlink/go.sum b/vendor/github.com/mdlayher/netlink/go.sum new file mode 100644 index 0000000000..fa89b49305 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/go.sum @@ -0,0 +1,29 @@ +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/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +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/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4 h1:nwOc1YaOrYJ37sEBrtWZrdqzK22hiJs3GpDmP3sR2Yw= +github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= +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= +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/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/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/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/github.com/mdlayher/netlink/message.go b/vendor/github.com/mdlayher/netlink/message.go new file mode 100644 index 0000000000..0189091c87 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/message.go @@ -0,0 +1,270 @@ +package netlink + +import ( + "errors" + "fmt" + + "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 +) + +// 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< 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. + + const success = 0 + + // Per libnl documentation, only messages that indicate type error can + // contain error codes: + // https://www.infradead.org/~tgr/libnl/doc/core.html#core_errmsg. + // + // However, at one point, this package checked both done and error for + // error codes. Because there was no issue associated with the change, + // it is unknown whether this change was correct or not. If you run into + // a problem with your application because of this change, please file + // an issue. + if m.Header.Type != Error { + return nil + } + + if len(m.Data) < 4 { + return newOpError("receive", errShortErrorMessage) + } + + if c := nlenc.Int32(m.Data[0:4]); c != success { + // 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. + return newOpError("receive", newError(-1*int(c))) + } + + return nil +} diff --git a/vendor/github.com/mdlayher/netlink/netlink.dot b/vendor/github.com/mdlayher/netlink/netlink.dot new file mode 100644 index 0000000000..d324b0b815 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/netlink.dot @@ -0,0 +1,86 @@ +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/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" + } +} + diff --git a/vendor/github.com/mdlayher/netlink/netlink.svg b/vendor/github.com/mdlayher/netlink/netlink.svg new file mode 100644 index 0000000000..639f0c9f02 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/netlink.svg @@ -0,0 +1,436 @@ + + + + + + +%3 + + +cluster_netlink + + + +cluster_connector + +NETLINK_CONNECTOR + + +cluster_crypto + +NETLINK_CRYPTO + + +cluster_generic + +NETLINK_GENERIC (genetlink) + + +cluster_kobject_uevent + +NETLINK_KOBJECT_UEVENT + + +cluster_netfilter + +NETLINK_NETFILTER (nfnetlink) + + +cluster_route + +NETLINK_ROUTE (rtnetlink) + + +cluster_w1 + +NETLINK_W1 + + + +github.com/mdlayher/netlink + + +github.com/mdlayher/netlink + + + + + +github.com/fearful-symmetry/garlic + + +github.com/fearful-symmetry/garlic + + + + + +github.com/fearful-symmetry/garlic->github.com/mdlayher/netlink + + + + + +github.com/mdlayher/cryptonl + + +github.com/mdlayher/cryptonl + + + + + +github.com/mdlayher/cryptonl->github.com/mdlayher/netlink + + + + + +github.com/mdlayher/genetlink + + +github.com/mdlayher/genetlink + + + + + +github.com/mdlayher/genetlink->github.com/mdlayher/netlink + + + + + +github.com/axatrax/l2tp + + +github.com/axatrax/l2tp + + + + + +github.com/axatrax/l2tp->github.com/mdlayher/genetlink + + + + + +github.com/digitalocean/go-openvswitch + + +github.com/digitalocean/go-openvswitch + + + + + +github.com/digitalocean/go-openvswitch->github.com/mdlayher/genetlink + + + + + +github.com/mdlayher/devlink + + +github.com/mdlayher/devlink + + + + + +github.com/mdlayher/devlink->github.com/mdlayher/genetlink + + + + + +github.com/mdlayher/quota + + +github.com/mdlayher/quota + + + + + +github.com/mdlayher/quota->github.com/mdlayher/genetlink + + + + + +github.com/mdlayher/taskstats + + +github.com/mdlayher/taskstats + + + + + +github.com/mdlayher/taskstats->github.com/mdlayher/genetlink + + + + + +github.com/mdlayher/wifi + + +github.com/mdlayher/wifi + + + + + +github.com/mdlayher/wifi->github.com/mdlayher/genetlink + + + + + +github.com/Merovius/nbd + + +github.com/Merovius/nbd + + + + + +github.com/Merovius/nbd->github.com/mdlayher/genetlink + + + + + +github.com/rtr7/router7 + + +github.com/rtr7/router7 + + + + + +github.com/rtr7/router7->github.com/mdlayher/genetlink + + + + + +github.com/u-root/u-bmc + + +github.com/u-root/u-bmc + + + + + +github.com/u-root/u-bmc->github.com/mdlayher/genetlink + + + + + +golang.zx2c4.com/wireguard/wgctrl + + +golang.zx2c4.com/wireguard/wgctrl + + + + + +golang.zx2c4.com/wireguard/wgctrl->github.com/mdlayher/genetlink + + + + + +github.com/mdlayher/kobject + + +github.com/mdlayher/kobject + + + + + +github.com/mdlayher/kobject->github.com/mdlayher/netlink + + + + + +github.com/florianl/go-conntrack + + +github.com/florianl/go-conntrack + + + + + +github.com/florianl/go-conntrack->github.com/mdlayher/netlink + + + + + +github.com/florianl/go-nflog + + +github.com/florianl/go-nflog + + + + + +github.com/florianl/go-nflog->github.com/mdlayher/netlink + + + + + +github.com/florianl/go-nfqueue + + +github.com/florianl/go-nfqueue + + + + + +github.com/florianl/go-nfqueue->github.com/mdlayher/netlink + + + + + +github.com/google/nftables + + +github.com/google/nftables + + + + + +github.com/google/nftables->github.com/mdlayher/netlink + + + + + +github.com/ti-mo/netfilter + + +github.com/ti-mo/netfilter + + + + + +github.com/ti-mo/netfilter->github.com/mdlayher/netlink + + + + + +github.com/ti-mo/conntrack + + +github.com/ti-mo/conntrack + + + + + +github.com/ti-mo/conntrack->github.com/ti-mo/netfilter + + + + + +github.com/ema/qdisc + + +github.com/ema/qdisc + + + + + +github.com/ema/qdisc->github.com/mdlayher/netlink + + + + + +github.com/florianl/go-tc + + +github.com/florianl/go-tc + + + + + +github.com/florianl/go-tc->github.com/mdlayher/netlink + + + + + +github.com/jsimonetti/rtnetlink + + +github.com/jsimonetti/rtnetlink + + + + + +github.com/jsimonetti/rtnetlink->github.com/mdlayher/netlink + + + + + +gitlab.com/mergetb/tech/rtnl + + +gitlab.com/mergetb/tech/rtnl + + + + + +gitlab.com/mergetb/tech/rtnl->github.com/mdlayher/netlink + + + + + +github.com/SpComb/go-onewire + + +github.com/SpComb/go-onewire + + + + + +github.com/SpComb/go-onewire->github.com/mdlayher/netlink + + + + + diff --git a/vendor/github.com/mdlayher/netlink/netns_linux.go b/vendor/github.com/mdlayher/netlink/netns_linux.go new file mode 100644 index 0000000000..8de5440608 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/netns_linux.go @@ -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() +} diff --git a/vendor/github.com/mdlayher/netlink/nlenc/doc.go b/vendor/github.com/mdlayher/netlink/nlenc/doc.go new file mode 100644 index 0000000000..f794fee782 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/nlenc/doc.go @@ -0,0 +1,3 @@ +// Package nlenc implements encoding and decoding functions for netlink +// messages and attributes. +package nlenc diff --git a/vendor/github.com/mdlayher/netlink/nlenc/endian.go b/vendor/github.com/mdlayher/netlink/nlenc/endian.go new file mode 100644 index 0000000000..b1487d29c2 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/nlenc/endian.go @@ -0,0 +1,14 @@ +package nlenc + +import "encoding/binary" + +// NativeEndian returns the native byte order of this system. +func NativeEndian() binary.ByteOrder { + // Determine endianness by storing a uint16 in a byte slice. + b := Uint16Bytes(1) + if b[0] == 1 { + return binary.LittleEndian + } + + return binary.BigEndian +} diff --git a/vendor/github.com/mdlayher/netlink/nlenc/int.go b/vendor/github.com/mdlayher/netlink/nlenc/int.go new file mode 100644 index 0000000000..d56b018dec --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/nlenc/int.go @@ -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 +} diff --git a/vendor/github.com/mdlayher/netlink/nlenc/string.go b/vendor/github.com/mdlayher/netlink/nlenc/string.go new file mode 100644 index 0000000000..c0b166ddfd --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/nlenc/string.go @@ -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")) +} diff --git a/vendor/github.com/mdlayher/netlink/rawconn_gteq_1.12.go b/vendor/github.com/mdlayher/netlink/rawconn_gteq_1.12.go new file mode 100644 index 0000000000..93d822a71c --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/rawconn_gteq_1.12.go @@ -0,0 +1,12 @@ +//+build go1.12 + +package netlink + +import ( + "os" + "syscall" +) + +func newRawConn(fd *os.File) (syscall.RawConn, error) { + return fd.SyscallConn() +} diff --git a/vendor/github.com/mdlayher/netlink/rawconn_lt_1.12.go b/vendor/github.com/mdlayher/netlink/rawconn_lt_1.12.go new file mode 100644 index 0000000000..f494173e66 --- /dev/null +++ b/vendor/github.com/mdlayher/netlink/rawconn_lt_1.12.go @@ -0,0 +1,32 @@ +//+build !go1.12 + +package netlink + +import ( + "os" + "syscall" +) + +func newRawConn(fd *os.File) (syscall.RawConn, error) { + return &rawConn{fd: fd.Fd()}, nil +} + +var _ syscall.RawConn = &rawConn{} + +// A rawConn is a syscall.RawConn. +type rawConn struct { + fd uintptr +} + +func (rc *rawConn) Control(f func(fd uintptr)) error { + f(rc.fd) + return nil +} + +func (rc *rawConn) Read(_ func(fd uintptr) (done bool)) error { + return notSupported("syscall-conn-read") +} + +func (rc *rawConn) Write(_ func(fd uintptr) (done bool)) error { + return notSupported("syscall-conn-write") +} diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519.go b/vendor/golang.org/x/crypto/curve25519/curve25519.go new file mode 100644 index 0000000000..4b9a655d1b --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/curve25519.go @@ -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 +} diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.go b/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.go new file mode 100644 index 0000000000..5120b779b9 --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.go @@ -0,0 +1,240 @@ +// 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. + +// +build amd64,!gccgo,!appengine,!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 */ +} diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.s b/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.s new file mode 100644 index 0000000000..0250c88859 --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.s @@ -0,0 +1,1793 @@ +// 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. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine,!purego + +#define REDMASK51 0x0007FFFFFFFFFFFF + +// These constants cannot be encoded in non-MOVQ immediates. +// We access them directly from memory instead. + +DATA ·_121666_213(SB)/8, $996687872 +GLOBL ·_121666_213(SB), 8, $8 + +DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA +GLOBL ·_2P0(SB), 8, $8 + +DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE +GLOBL ·_2P1234(SB), 8, $8 + +// func freeze(inout *[5]uint64) +TEXT ·freeze(SB),7,$0-8 + MOVQ inout+0(FP), DI + + MOVQ 0(DI),SI + MOVQ 8(DI),DX + MOVQ 16(DI),CX + MOVQ 24(DI),R8 + MOVQ 32(DI),R9 + MOVQ $REDMASK51,AX + MOVQ AX,R10 + SUBQ $18,R10 + MOVQ $3,R11 +REDUCELOOP: + MOVQ SI,R12 + SHRQ $51,R12 + ANDQ AX,SI + ADDQ R12,DX + MOVQ DX,R12 + SHRQ $51,R12 + ANDQ AX,DX + ADDQ R12,CX + MOVQ CX,R12 + SHRQ $51,R12 + ANDQ AX,CX + ADDQ R12,R8 + MOVQ R8,R12 + SHRQ $51,R12 + ANDQ AX,R8 + ADDQ R12,R9 + MOVQ R9,R12 + SHRQ $51,R12 + ANDQ AX,R9 + IMUL3Q $19,R12,R12 + ADDQ R12,SI + SUBQ $1,R11 + JA REDUCELOOP + MOVQ $1,R12 + CMPQ R10,SI + CMOVQLT R11,R12 + CMPQ AX,DX + CMOVQNE R11,R12 + CMPQ AX,CX + CMOVQNE R11,R12 + CMPQ AX,R8 + CMOVQNE R11,R12 + CMPQ AX,R9 + CMOVQNE R11,R12 + NEGQ R12 + ANDQ R12,AX + ANDQ R12,R10 + SUBQ R10,SI + SUBQ AX,DX + SUBQ AX,CX + SUBQ AX,R8 + SUBQ AX,R9 + MOVQ SI,0(DI) + MOVQ DX,8(DI) + MOVQ CX,16(DI) + MOVQ R8,24(DI) + MOVQ R9,32(DI) + RET + +// func ladderstep(inout *[5][5]uint64) +TEXT ·ladderstep(SB),0,$296-8 + MOVQ inout+0(FP),DI + + MOVQ 40(DI),SI + MOVQ 48(DI),DX + MOVQ 56(DI),CX + MOVQ 64(DI),R8 + MOVQ 72(DI),R9 + MOVQ SI,AX + MOVQ DX,R10 + MOVQ CX,R11 + MOVQ R8,R12 + MOVQ R9,R13 + ADDQ ·_2P0(SB),AX + ADDQ ·_2P1234(SB),R10 + ADDQ ·_2P1234(SB),R11 + ADDQ ·_2P1234(SB),R12 + ADDQ ·_2P1234(SB),R13 + ADDQ 80(DI),SI + ADDQ 88(DI),DX + ADDQ 96(DI),CX + ADDQ 104(DI),R8 + ADDQ 112(DI),R9 + SUBQ 80(DI),AX + SUBQ 88(DI),R10 + SUBQ 96(DI),R11 + SUBQ 104(DI),R12 + SUBQ 112(DI),R13 + MOVQ SI,0(SP) + MOVQ DX,8(SP) + MOVQ CX,16(SP) + MOVQ R8,24(SP) + MOVQ R9,32(SP) + MOVQ AX,40(SP) + MOVQ R10,48(SP) + MOVQ R11,56(SP) + MOVQ R12,64(SP) + MOVQ R13,72(SP) + MOVQ 40(SP),AX + MULQ 40(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 40(SP),AX + SHLQ $1,AX + MULQ 48(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 40(SP),AX + SHLQ $1,AX + MULQ 56(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 40(SP),AX + SHLQ $1,AX + MULQ 64(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 40(SP),AX + SHLQ $1,AX + MULQ 72(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 48(SP),AX + MULQ 48(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 48(SP),AX + SHLQ $1,AX + MULQ 56(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 48(SP),AX + SHLQ $1,AX + MULQ 64(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 48(SP),DX + IMUL3Q $38,DX,AX + MULQ 72(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 56(SP),AX + MULQ 56(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 56(SP),DX + IMUL3Q $38,DX,AX + MULQ 64(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 56(SP),DX + IMUL3Q $38,DX,AX + MULQ 72(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 64(SP),DX + IMUL3Q $19,DX,AX + MULQ 64(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 64(SP),DX + IMUL3Q $38,DX,AX + MULQ 72(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 72(SP),DX + IMUL3Q $19,DX,AX + MULQ 72(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,SI,CX + ANDQ DX,SI + SHLQ $13,R8,R9 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R10,R11 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R12,R13 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R14,R15 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + ANDQ DX,SI + MOVQ CX,R8 + SHRQ $51,CX + ADDQ R10,CX + ANDQ DX,R8 + MOVQ CX,R9 + SHRQ $51,CX + ADDQ R12,CX + ANDQ DX,R9 + MOVQ CX,AX + SHRQ $51,CX + ADDQ R14,CX + ANDQ DX,AX + MOVQ CX,R10 + SHRQ $51,CX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,80(SP) + MOVQ R8,88(SP) + MOVQ R9,96(SP) + MOVQ AX,104(SP) + MOVQ R10,112(SP) + MOVQ 0(SP),AX + MULQ 0(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 0(SP),AX + SHLQ $1,AX + MULQ 8(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 0(SP),AX + SHLQ $1,AX + MULQ 16(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 0(SP),AX + SHLQ $1,AX + MULQ 24(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 0(SP),AX + SHLQ $1,AX + MULQ 32(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 8(SP),AX + MULQ 8(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 8(SP),AX + SHLQ $1,AX + MULQ 16(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 8(SP),AX + SHLQ $1,AX + MULQ 24(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 8(SP),DX + IMUL3Q $38,DX,AX + MULQ 32(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 16(SP),AX + MULQ 16(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 16(SP),DX + IMUL3Q $38,DX,AX + MULQ 24(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 16(SP),DX + IMUL3Q $38,DX,AX + MULQ 32(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 24(SP),DX + IMUL3Q $19,DX,AX + MULQ 24(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 24(SP),DX + IMUL3Q $38,DX,AX + MULQ 32(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 32(SP),DX + IMUL3Q $19,DX,AX + MULQ 32(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,SI,CX + ANDQ DX,SI + SHLQ $13,R8,R9 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R10,R11 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R12,R13 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R14,R15 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + ANDQ DX,SI + MOVQ CX,R8 + SHRQ $51,CX + ADDQ R10,CX + ANDQ DX,R8 + MOVQ CX,R9 + SHRQ $51,CX + ADDQ R12,CX + ANDQ DX,R9 + MOVQ CX,AX + SHRQ $51,CX + ADDQ R14,CX + ANDQ DX,AX + MOVQ CX,R10 + SHRQ $51,CX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,120(SP) + MOVQ R8,128(SP) + MOVQ R9,136(SP) + MOVQ AX,144(SP) + MOVQ R10,152(SP) + MOVQ SI,SI + MOVQ R8,DX + MOVQ R9,CX + MOVQ AX,R8 + MOVQ R10,R9 + ADDQ ·_2P0(SB),SI + ADDQ ·_2P1234(SB),DX + ADDQ ·_2P1234(SB),CX + ADDQ ·_2P1234(SB),R8 + ADDQ ·_2P1234(SB),R9 + SUBQ 80(SP),SI + SUBQ 88(SP),DX + SUBQ 96(SP),CX + SUBQ 104(SP),R8 + SUBQ 112(SP),R9 + MOVQ SI,160(SP) + MOVQ DX,168(SP) + MOVQ CX,176(SP) + MOVQ R8,184(SP) + MOVQ R9,192(SP) + MOVQ 120(DI),SI + MOVQ 128(DI),DX + MOVQ 136(DI),CX + MOVQ 144(DI),R8 + MOVQ 152(DI),R9 + MOVQ SI,AX + MOVQ DX,R10 + MOVQ CX,R11 + MOVQ R8,R12 + MOVQ R9,R13 + ADDQ ·_2P0(SB),AX + ADDQ ·_2P1234(SB),R10 + ADDQ ·_2P1234(SB),R11 + ADDQ ·_2P1234(SB),R12 + ADDQ ·_2P1234(SB),R13 + ADDQ 160(DI),SI + ADDQ 168(DI),DX + ADDQ 176(DI),CX + ADDQ 184(DI),R8 + ADDQ 192(DI),R9 + SUBQ 160(DI),AX + SUBQ 168(DI),R10 + SUBQ 176(DI),R11 + SUBQ 184(DI),R12 + SUBQ 192(DI),R13 + MOVQ SI,200(SP) + MOVQ DX,208(SP) + MOVQ CX,216(SP) + MOVQ R8,224(SP) + MOVQ R9,232(SP) + MOVQ AX,240(SP) + MOVQ R10,248(SP) + MOVQ R11,256(SP) + MOVQ R12,264(SP) + MOVQ R13,272(SP) + MOVQ 224(SP),SI + IMUL3Q $19,SI,AX + MOVQ AX,280(SP) + MULQ 56(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 232(SP),DX + IMUL3Q $19,DX,AX + MOVQ AX,288(SP) + MULQ 48(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 200(SP),AX + MULQ 40(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 200(SP),AX + MULQ 48(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 200(SP),AX + MULQ 56(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 200(SP),AX + MULQ 64(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 200(SP),AX + MULQ 72(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 208(SP),AX + MULQ 40(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 208(SP),AX + MULQ 48(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 208(SP),AX + MULQ 56(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 208(SP),AX + MULQ 64(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 208(SP),DX + IMUL3Q $19,DX,AX + MULQ 72(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 216(SP),AX + MULQ 40(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 216(SP),AX + MULQ 48(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 216(SP),AX + MULQ 56(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 216(SP),DX + IMUL3Q $19,DX,AX + MULQ 64(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 216(SP),DX + IMUL3Q $19,DX,AX + MULQ 72(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 224(SP),AX + MULQ 40(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 224(SP),AX + MULQ 48(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 280(SP),AX + MULQ 64(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 280(SP),AX + MULQ 72(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 232(SP),AX + MULQ 40(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 288(SP),AX + MULQ 56(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 288(SP),AX + MULQ 64(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 288(SP),AX + MULQ 72(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,SI,CX + ANDQ DX,SI + SHLQ $13,R8,R9 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R10,R11 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R12,R13 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R14,R15 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,40(SP) + MOVQ R8,48(SP) + MOVQ R9,56(SP) + MOVQ AX,64(SP) + MOVQ R10,72(SP) + MOVQ 264(SP),SI + IMUL3Q $19,SI,AX + MOVQ AX,200(SP) + MULQ 16(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 272(SP),DX + IMUL3Q $19,DX,AX + MOVQ AX,208(SP) + MULQ 8(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 240(SP),AX + MULQ 0(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 240(SP),AX + MULQ 8(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 240(SP),AX + MULQ 16(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 240(SP),AX + MULQ 24(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 240(SP),AX + MULQ 32(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 248(SP),AX + MULQ 0(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 248(SP),AX + MULQ 8(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 248(SP),AX + MULQ 16(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 248(SP),AX + MULQ 24(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 248(SP),DX + IMUL3Q $19,DX,AX + MULQ 32(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 256(SP),AX + MULQ 0(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 256(SP),AX + MULQ 8(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 256(SP),AX + MULQ 16(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 256(SP),DX + IMUL3Q $19,DX,AX + MULQ 24(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 256(SP),DX + IMUL3Q $19,DX,AX + MULQ 32(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 264(SP),AX + MULQ 0(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 264(SP),AX + MULQ 8(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 200(SP),AX + MULQ 24(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 200(SP),AX + MULQ 32(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 272(SP),AX + MULQ 0(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 208(SP),AX + MULQ 16(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 208(SP),AX + MULQ 24(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 208(SP),AX + MULQ 32(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,SI,CX + ANDQ DX,SI + SHLQ $13,R8,R9 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R10,R11 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R12,R13 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R14,R15 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,DX + MOVQ R8,CX + MOVQ R9,R11 + MOVQ AX,R12 + MOVQ R10,R13 + ADDQ ·_2P0(SB),DX + ADDQ ·_2P1234(SB),CX + ADDQ ·_2P1234(SB),R11 + ADDQ ·_2P1234(SB),R12 + ADDQ ·_2P1234(SB),R13 + ADDQ 40(SP),SI + ADDQ 48(SP),R8 + ADDQ 56(SP),R9 + ADDQ 64(SP),AX + ADDQ 72(SP),R10 + SUBQ 40(SP),DX + SUBQ 48(SP),CX + SUBQ 56(SP),R11 + SUBQ 64(SP),R12 + SUBQ 72(SP),R13 + MOVQ SI,120(DI) + MOVQ R8,128(DI) + MOVQ R9,136(DI) + MOVQ AX,144(DI) + MOVQ R10,152(DI) + MOVQ DX,160(DI) + MOVQ CX,168(DI) + MOVQ R11,176(DI) + MOVQ R12,184(DI) + MOVQ R13,192(DI) + MOVQ 120(DI),AX + MULQ 120(DI) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 120(DI),AX + SHLQ $1,AX + MULQ 128(DI) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 120(DI),AX + SHLQ $1,AX + MULQ 136(DI) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 120(DI),AX + SHLQ $1,AX + MULQ 144(DI) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 120(DI),AX + SHLQ $1,AX + MULQ 152(DI) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 128(DI),AX + MULQ 128(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 128(DI),AX + SHLQ $1,AX + MULQ 136(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 128(DI),AX + SHLQ $1,AX + MULQ 144(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 128(DI),DX + IMUL3Q $38,DX,AX + MULQ 152(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 136(DI),AX + MULQ 136(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 136(DI),DX + IMUL3Q $38,DX,AX + MULQ 144(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 136(DI),DX + IMUL3Q $38,DX,AX + MULQ 152(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 144(DI),DX + IMUL3Q $19,DX,AX + MULQ 144(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 144(DI),DX + IMUL3Q $38,DX,AX + MULQ 152(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 152(DI),DX + IMUL3Q $19,DX,AX + MULQ 152(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,SI,CX + ANDQ DX,SI + SHLQ $13,R8,R9 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R10,R11 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R12,R13 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R14,R15 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + ANDQ DX,SI + MOVQ CX,R8 + SHRQ $51,CX + ADDQ R10,CX + ANDQ DX,R8 + MOVQ CX,R9 + SHRQ $51,CX + ADDQ R12,CX + ANDQ DX,R9 + MOVQ CX,AX + SHRQ $51,CX + ADDQ R14,CX + ANDQ DX,AX + MOVQ CX,R10 + SHRQ $51,CX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,120(DI) + MOVQ R8,128(DI) + MOVQ R9,136(DI) + MOVQ AX,144(DI) + MOVQ R10,152(DI) + MOVQ 160(DI),AX + MULQ 160(DI) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 160(DI),AX + SHLQ $1,AX + MULQ 168(DI) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 160(DI),AX + SHLQ $1,AX + MULQ 176(DI) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 160(DI),AX + SHLQ $1,AX + MULQ 184(DI) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 160(DI),AX + SHLQ $1,AX + MULQ 192(DI) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 168(DI),AX + MULQ 168(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 168(DI),AX + SHLQ $1,AX + MULQ 176(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 168(DI),AX + SHLQ $1,AX + MULQ 184(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 168(DI),DX + IMUL3Q $38,DX,AX + MULQ 192(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(DI),AX + MULQ 176(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 176(DI),DX + IMUL3Q $38,DX,AX + MULQ 184(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(DI),DX + IMUL3Q $38,DX,AX + MULQ 192(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 184(DI),DX + IMUL3Q $19,DX,AX + MULQ 184(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 184(DI),DX + IMUL3Q $38,DX,AX + MULQ 192(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 192(DI),DX + IMUL3Q $19,DX,AX + MULQ 192(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,SI,CX + ANDQ DX,SI + SHLQ $13,R8,R9 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R10,R11 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R12,R13 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R14,R15 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + ANDQ DX,SI + MOVQ CX,R8 + SHRQ $51,CX + ADDQ R10,CX + ANDQ DX,R8 + MOVQ CX,R9 + SHRQ $51,CX + ADDQ R12,CX + ANDQ DX,R9 + MOVQ CX,AX + SHRQ $51,CX + ADDQ R14,CX + ANDQ DX,AX + MOVQ CX,R10 + SHRQ $51,CX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,160(DI) + MOVQ R8,168(DI) + MOVQ R9,176(DI) + MOVQ AX,184(DI) + MOVQ R10,192(DI) + MOVQ 184(DI),SI + IMUL3Q $19,SI,AX + MOVQ AX,0(SP) + MULQ 16(DI) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 192(DI),DX + IMUL3Q $19,DX,AX + MOVQ AX,8(SP) + MULQ 8(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 160(DI),AX + MULQ 0(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 160(DI),AX + MULQ 8(DI) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 160(DI),AX + MULQ 16(DI) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 160(DI),AX + MULQ 24(DI) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 160(DI),AX + MULQ 32(DI) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 168(DI),AX + MULQ 0(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 168(DI),AX + MULQ 8(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 168(DI),AX + MULQ 16(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 168(DI),AX + MULQ 24(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 168(DI),DX + IMUL3Q $19,DX,AX + MULQ 32(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(DI),AX + MULQ 0(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 176(DI),AX + MULQ 8(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 176(DI),AX + MULQ 16(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 176(DI),DX + IMUL3Q $19,DX,AX + MULQ 24(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(DI),DX + IMUL3Q $19,DX,AX + MULQ 32(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 184(DI),AX + MULQ 0(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 184(DI),AX + MULQ 8(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 0(SP),AX + MULQ 24(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 0(SP),AX + MULQ 32(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 192(DI),AX + MULQ 0(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 8(SP),AX + MULQ 16(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 8(SP),AX + MULQ 24(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 8(SP),AX + MULQ 32(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,SI,CX + ANDQ DX,SI + SHLQ $13,R8,R9 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R10,R11 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R12,R13 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R14,R15 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,160(DI) + MOVQ R8,168(DI) + MOVQ R9,176(DI) + MOVQ AX,184(DI) + MOVQ R10,192(DI) + MOVQ 144(SP),SI + IMUL3Q $19,SI,AX + MOVQ AX,0(SP) + MULQ 96(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 152(SP),DX + IMUL3Q $19,DX,AX + MOVQ AX,8(SP) + MULQ 88(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 120(SP),AX + MULQ 80(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 120(SP),AX + MULQ 88(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 120(SP),AX + MULQ 96(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 120(SP),AX + MULQ 104(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 120(SP),AX + MULQ 112(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 128(SP),AX + MULQ 80(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 128(SP),AX + MULQ 88(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 128(SP),AX + MULQ 96(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 128(SP),AX + MULQ 104(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 128(SP),DX + IMUL3Q $19,DX,AX + MULQ 112(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 136(SP),AX + MULQ 80(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 136(SP),AX + MULQ 88(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 136(SP),AX + MULQ 96(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 136(SP),DX + IMUL3Q $19,DX,AX + MULQ 104(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 136(SP),DX + IMUL3Q $19,DX,AX + MULQ 112(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 144(SP),AX + MULQ 80(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 144(SP),AX + MULQ 88(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 0(SP),AX + MULQ 104(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 0(SP),AX + MULQ 112(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 152(SP),AX + MULQ 80(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 8(SP),AX + MULQ 96(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 8(SP),AX + MULQ 104(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 8(SP),AX + MULQ 112(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,SI,CX + ANDQ DX,SI + SHLQ $13,R8,R9 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R10,R11 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R12,R13 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R14,R15 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,40(DI) + MOVQ R8,48(DI) + MOVQ R9,56(DI) + MOVQ AX,64(DI) + MOVQ R10,72(DI) + MOVQ 160(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + MOVQ AX,SI + MOVQ DX,CX + MOVQ 168(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + ADDQ AX,CX + MOVQ DX,R8 + MOVQ 176(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + ADDQ AX,R8 + MOVQ DX,R9 + MOVQ 184(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + ADDQ AX,R9 + MOVQ DX,R10 + MOVQ 192(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + ADDQ AX,R10 + IMUL3Q $19,DX,DX + ADDQ DX,SI + ADDQ 80(SP),SI + ADDQ 88(SP),CX + ADDQ 96(SP),R8 + ADDQ 104(SP),R9 + ADDQ 112(SP),R10 + MOVQ SI,80(DI) + MOVQ CX,88(DI) + MOVQ R8,96(DI) + MOVQ R9,104(DI) + MOVQ R10,112(DI) + MOVQ 104(DI),SI + IMUL3Q $19,SI,AX + MOVQ AX,0(SP) + MULQ 176(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 112(DI),DX + IMUL3Q $19,DX,AX + MOVQ AX,8(SP) + MULQ 168(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 80(DI),AX + MULQ 160(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 80(DI),AX + MULQ 168(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 80(DI),AX + MULQ 176(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 80(DI),AX + MULQ 184(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 80(DI),AX + MULQ 192(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 88(DI),AX + MULQ 160(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 88(DI),AX + MULQ 168(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 88(DI),AX + MULQ 176(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 88(DI),AX + MULQ 184(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 88(DI),DX + IMUL3Q $19,DX,AX + MULQ 192(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 96(DI),AX + MULQ 160(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 96(DI),AX + MULQ 168(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 96(DI),AX + MULQ 176(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 96(DI),DX + IMUL3Q $19,DX,AX + MULQ 184(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 96(DI),DX + IMUL3Q $19,DX,AX + MULQ 192(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 104(DI),AX + MULQ 160(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 104(DI),AX + MULQ 168(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 0(SP),AX + MULQ 184(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 0(SP),AX + MULQ 192(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 112(DI),AX + MULQ 160(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 8(SP),AX + MULQ 176(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 8(SP),AX + MULQ 184(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 8(SP),AX + MULQ 192(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,SI,CX + ANDQ DX,SI + SHLQ $13,R8,R9 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R10,R11 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R12,R13 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R14,R15 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,80(DI) + MOVQ R8,88(DI) + MOVQ R9,96(DI) + MOVQ AX,104(DI) + MOVQ R10,112(DI) + RET + +// func cswap(inout *[4][5]uint64, v uint64) +TEXT ·cswap(SB),7,$0 + MOVQ inout+0(FP),DI + MOVQ v+8(FP),SI + + SUBQ $1, SI + NOTQ SI + MOVQ SI, X15 + PSHUFD $0x44, X15, X15 + + MOVOU 0(DI), X0 + MOVOU 16(DI), X2 + MOVOU 32(DI), X4 + MOVOU 48(DI), X6 + MOVOU 64(DI), X8 + MOVOU 80(DI), X1 + MOVOU 96(DI), X3 + MOVOU 112(DI), X5 + MOVOU 128(DI), X7 + MOVOU 144(DI), X9 + + MOVO X1, X10 + MOVO X3, X11 + MOVO X5, X12 + MOVO X7, X13 + MOVO X9, X14 + + PXOR X0, X10 + PXOR X2, X11 + PXOR X4, X12 + PXOR X6, X13 + PXOR X8, X14 + PAND X15, X10 + PAND X15, X11 + PAND X15, X12 + PAND X15, X13 + PAND X15, X14 + PXOR X10, X0 + PXOR X10, X1 + PXOR X11, X2 + PXOR X11, X3 + PXOR X12, X4 + PXOR X12, X5 + PXOR X13, X6 + PXOR X13, X7 + PXOR X14, X8 + PXOR X14, X9 + + MOVOU X0, 0(DI) + MOVOU X2, 16(DI) + MOVOU X4, 32(DI) + MOVOU X6, 48(DI) + MOVOU X8, 64(DI) + MOVOU X1, 80(DI) + MOVOU X3, 96(DI) + MOVOU X5, 112(DI) + MOVOU X7, 128(DI) + MOVOU X9, 144(DI) + RET + +// func mul(dest, a, b *[5]uint64) +TEXT ·mul(SB),0,$16-24 + MOVQ dest+0(FP), DI + MOVQ a+8(FP), SI + MOVQ b+16(FP), DX + + MOVQ DX,CX + MOVQ 24(SI),DX + IMUL3Q $19,DX,AX + MOVQ AX,0(SP) + MULQ 16(CX) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 32(SI),DX + IMUL3Q $19,DX,AX + MOVQ AX,8(SP) + MULQ 8(CX) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 0(SI),AX + MULQ 0(CX) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 0(SI),AX + MULQ 8(CX) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 0(SI),AX + MULQ 16(CX) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 0(SI),AX + MULQ 24(CX) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 0(SI),AX + MULQ 32(CX) + MOVQ AX,BX + MOVQ DX,BP + MOVQ 8(SI),AX + MULQ 0(CX) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 8(SI),AX + MULQ 8(CX) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 8(SI),AX + MULQ 16(CX) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 8(SI),AX + MULQ 24(CX) + ADDQ AX,BX + ADCQ DX,BP + MOVQ 8(SI),DX + IMUL3Q $19,DX,AX + MULQ 32(CX) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 16(SI),AX + MULQ 0(CX) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 16(SI),AX + MULQ 8(CX) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 16(SI),AX + MULQ 16(CX) + ADDQ AX,BX + ADCQ DX,BP + MOVQ 16(SI),DX + IMUL3Q $19,DX,AX + MULQ 24(CX) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 16(SI),DX + IMUL3Q $19,DX,AX + MULQ 32(CX) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 24(SI),AX + MULQ 0(CX) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 24(SI),AX + MULQ 8(CX) + ADDQ AX,BX + ADCQ DX,BP + MOVQ 0(SP),AX + MULQ 24(CX) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 0(SP),AX + MULQ 32(CX) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 32(SI),AX + MULQ 0(CX) + ADDQ AX,BX + ADCQ DX,BP + MOVQ 8(SP),AX + MULQ 16(CX) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 8(SP),AX + MULQ 24(CX) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 8(SP),AX + MULQ 32(CX) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ $REDMASK51,SI + SHLQ $13,R8,R9 + ANDQ SI,R8 + SHLQ $13,R10,R11 + ANDQ SI,R10 + ADDQ R9,R10 + SHLQ $13,R12,R13 + ANDQ SI,R12 + ADDQ R11,R12 + SHLQ $13,R14,R15 + ANDQ SI,R14 + ADDQ R13,R14 + SHLQ $13,BX,BP + ANDQ SI,BX + ADDQ R15,BX + IMUL3Q $19,BP,DX + ADDQ DX,R8 + MOVQ R8,DX + SHRQ $51,DX + ADDQ R10,DX + MOVQ DX,CX + SHRQ $51,DX + ANDQ SI,R8 + ADDQ R12,DX + MOVQ DX,R9 + SHRQ $51,DX + ANDQ SI,CX + ADDQ R14,DX + MOVQ DX,AX + SHRQ $51,DX + ANDQ SI,R9 + ADDQ BX,DX + MOVQ DX,R10 + SHRQ $51,DX + ANDQ SI,AX + IMUL3Q $19,DX,DX + ADDQ DX,R8 + ANDQ SI,R10 + MOVQ R8,0(DI) + MOVQ CX,8(DI) + MOVQ R9,16(DI) + MOVQ AX,24(DI) + MOVQ R10,32(DI) + RET + +// func square(out, in *[5]uint64) +TEXT ·square(SB),7,$0-16 + MOVQ out+0(FP), DI + MOVQ in+8(FP), SI + + MOVQ 0(SI),AX + MULQ 0(SI) + MOVQ AX,CX + MOVQ DX,R8 + MOVQ 0(SI),AX + SHLQ $1,AX + MULQ 8(SI) + MOVQ AX,R9 + MOVQ DX,R10 + MOVQ 0(SI),AX + SHLQ $1,AX + MULQ 16(SI) + MOVQ AX,R11 + MOVQ DX,R12 + MOVQ 0(SI),AX + SHLQ $1,AX + MULQ 24(SI) + MOVQ AX,R13 + MOVQ DX,R14 + MOVQ 0(SI),AX + SHLQ $1,AX + MULQ 32(SI) + MOVQ AX,R15 + MOVQ DX,BX + MOVQ 8(SI),AX + MULQ 8(SI) + ADDQ AX,R11 + ADCQ DX,R12 + MOVQ 8(SI),AX + SHLQ $1,AX + MULQ 16(SI) + ADDQ AX,R13 + ADCQ DX,R14 + MOVQ 8(SI),AX + SHLQ $1,AX + MULQ 24(SI) + ADDQ AX,R15 + ADCQ DX,BX + MOVQ 8(SI),DX + IMUL3Q $38,DX,AX + MULQ 32(SI) + ADDQ AX,CX + ADCQ DX,R8 + MOVQ 16(SI),AX + MULQ 16(SI) + ADDQ AX,R15 + ADCQ DX,BX + MOVQ 16(SI),DX + IMUL3Q $38,DX,AX + MULQ 24(SI) + ADDQ AX,CX + ADCQ DX,R8 + MOVQ 16(SI),DX + IMUL3Q $38,DX,AX + MULQ 32(SI) + ADDQ AX,R9 + ADCQ DX,R10 + MOVQ 24(SI),DX + IMUL3Q $19,DX,AX + MULQ 24(SI) + ADDQ AX,R9 + ADCQ DX,R10 + MOVQ 24(SI),DX + IMUL3Q $38,DX,AX + MULQ 32(SI) + ADDQ AX,R11 + ADCQ DX,R12 + MOVQ 32(SI),DX + IMUL3Q $19,DX,AX + MULQ 32(SI) + ADDQ AX,R13 + ADCQ DX,R14 + MOVQ $REDMASK51,SI + SHLQ $13,CX,R8 + ANDQ SI,CX + SHLQ $13,R9,R10 + ANDQ SI,R9 + ADDQ R8,R9 + SHLQ $13,R11,R12 + ANDQ SI,R11 + ADDQ R10,R11 + SHLQ $13,R13,R14 + ANDQ SI,R13 + ADDQ R12,R13 + SHLQ $13,R15,BX + ANDQ SI,R15 + ADDQ R14,R15 + IMUL3Q $19,BX,DX + ADDQ DX,CX + MOVQ CX,DX + SHRQ $51,DX + ADDQ R9,DX + ANDQ SI,CX + MOVQ DX,R8 + SHRQ $51,DX + ADDQ R11,DX + ANDQ SI,R8 + MOVQ DX,R9 + SHRQ $51,DX + ADDQ R13,DX + ANDQ SI,R9 + MOVQ DX,AX + SHRQ $51,DX + ADDQ R15,DX + ANDQ SI,AX + MOVQ DX,R10 + SHRQ $51,DX + IMUL3Q $19,DX,DX + ADDQ DX,CX + ANDQ SI,R10 + MOVQ CX,0(DI) + MOVQ R8,8(DI) + MOVQ R9,16(DI) + MOVQ AX,24(DI) + MOVQ R10,32(DI) + RET diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519_generic.go b/vendor/golang.org/x/crypto/curve25519/curve25519_generic.go new file mode 100644 index 0000000000..c43b13fc83 --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/curve25519_generic.go @@ -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> 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) +} diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519_noasm.go b/vendor/golang.org/x/crypto/curve25519/curve25519_noasm.go new file mode 100644 index 0000000000..047d49afc2 --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/curve25519_noasm.go @@ -0,0 +1,11 @@ +// 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. + +// +build !amd64 gccgo appengine purego + +package curve25519 + +func scalarMult(out, in, base *[32]byte) { + scalarMultGeneric(out, in, base) +} diff --git a/vendor/golang.org/x/net/bpf/asm.go b/vendor/golang.org/x/net/bpf/asm.go new file mode 100644 index 0000000000..15e21b1812 --- /dev/null +++ b/vendor/golang.org/x/net/bpf/asm.go @@ -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 +} diff --git a/vendor/golang.org/x/net/bpf/constants.go b/vendor/golang.org/x/net/bpf/constants.go new file mode 100644 index 0000000000..12f3ee835a --- /dev/null +++ b/vendor/golang.org/x/net/bpf/constants.go @@ -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 +) diff --git a/vendor/golang.org/x/net/bpf/doc.go b/vendor/golang.org/x/net/bpf/doc.go new file mode 100644 index 0000000000..ae62feb534 --- /dev/null +++ b/vendor/golang.org/x/net/bpf/doc.go @@ -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" diff --git a/vendor/golang.org/x/net/bpf/instructions.go b/vendor/golang.org/x/net/bpf/instructions.go new file mode 100644 index 0000000000..3cffcaa014 --- /dev/null +++ b/vendor/golang.org/x/net/bpf/instructions.go @@ -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 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 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 +// 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 +// 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 +} diff --git a/vendor/golang.org/x/net/bpf/setter.go b/vendor/golang.org/x/net/bpf/setter.go new file mode 100644 index 0000000000..43e35f0ac2 --- /dev/null +++ b/vendor/golang.org/x/net/bpf/setter.go @@ -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 +} diff --git a/vendor/golang.org/x/net/bpf/vm.go b/vendor/golang.org/x/net/bpf/vm.go new file mode 100644 index 0000000000..73f57f1f72 --- /dev/null +++ b/vendor/golang.org/x/net/bpf/vm.go @@ -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 +} diff --git a/vendor/golang.org/x/net/bpf/vm_instructions.go b/vendor/golang.org/x/net/bpf/vm_instructions.go new file mode 100644 index 0000000000..cf8947c332 --- /dev/null +++ b/vendor/golang.org/x/net/bpf/vm_instructions.go @@ -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 +} diff --git a/vendor/golang.zx2c4.com/wireguard/COPYING b/vendor/golang.zx2c4.com/wireguard/COPYING new file mode 100644 index 0000000000..f85e365de0 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/COPYING @@ -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. diff --git a/vendor/golang.zx2c4.com/wireguard/ipc/winpipe/file.go b/vendor/golang.zx2c4.com/wireguard/ipc/winpipe/file.go new file mode 100644 index 0000000000..29d02a75e8 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/ipc/winpipe/file.go @@ -0,0 +1,323 @@ +// +build windows + +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2005 Microsoft + * Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved. + */ +package winpipe + +import ( + "errors" + "io" + "runtime" + "sync" + "sync/atomic" + "time" + + "golang.org/x/sys/windows" +) + +//sys cancelIoEx(file windows.Handle, o *windows.Overlapped) (err error) = CancelIoEx +//sys createIoCompletionPort(file windows.Handle, port windows.Handle, key uintptr, threadCount uint32) (newport windows.Handle, err error) = CreateIoCompletionPort +//sys getQueuedCompletionStatus(port windows.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus +//sys setFileCompletionNotificationModes(h windows.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes +//sys wsaGetOverlappedResult(h windows.Handle, o *windows.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult + +type atomicBool int32 + +func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 } +func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) } +func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) } +func (b *atomicBool) swap(new bool) bool { + var newInt int32 + if new { + newInt = 1 + } + return atomic.SwapInt32((*int32)(b), newInt) == 1 +} + +const ( + cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1 + cFILE_SKIP_SET_EVENT_ON_HANDLE = 2 +) + +var ( + ErrFileClosed = errors.New("file has already been closed") + ErrTimeout = &timeoutError{} +) + +type timeoutError struct{} + +func (e *timeoutError) Error() string { return "i/o timeout" } +func (e *timeoutError) Timeout() bool { return true } +func (e *timeoutError) Temporary() bool { return true } + +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 := createIoCompletionPort(windows.InvalidHandle, 0, 0, 0xffffffff) + if err != nil { + panic(err) + } + ioCompletionPort = h + go ioCompletionProcessor(h) +} + +// win32File 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 win32File struct { + handle windows.Handle + wg sync.WaitGroup + wgLock sync.RWMutex + closing atomicBool + socket bool + readDeadline deadlineHandler + writeDeadline deadlineHandler +} + +type deadlineHandler struct { + setLock sync.Mutex + channel timeoutChan + channelLock sync.RWMutex + timer *time.Timer + timedout atomicBool +} + +// makeWin32File makes a new win32File from an existing file handle +func makeWin32File(h windows.Handle) (*win32File, error) { + f := &win32File{handle: h} + ioInitOnce.Do(initIo) + _, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff) + if err != nil { + return nil, err + } + err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE) + if err != nil { + return nil, err + } + f.readDeadline.channel = make(timeoutChan) + f.writeDeadline.channel = make(timeoutChan) + return f, nil +} + +func MakeOpenFile(h windows.Handle) (io.ReadWriteCloser, error) { + return makeWin32File(h) +} + +// closeHandle closes the resources associated with a Win32 handle +func (f *win32File) closeHandle() { + f.wgLock.Lock() + // Atomically set that we are closing, releasing the resources only once. + if !f.closing.swap(true) { + f.wgLock.Unlock() + // cancel all IO and wait for it to complete + 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 win32File. +func (f *win32File) 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 *win32File) prepareIo() (*ioOperation, error) { + f.wgLock.RLock() + if f.closing.isSet() { + f.wgLock.RUnlock() + return nil, ErrFileClosed + } + 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 := getQueuedCompletionStatus(h, &bytes, &key, &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 *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) { + if err != windows.ERROR_IO_PENDING { + return int(bytes), err + } + + if f.closing.isSet() { + 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 f.closing.isSet() { + err = ErrFileClosed + } + } else if err != nil && f.socket { + // err is from Win32. Query the overlapped structure to get the winsock error. + var bytes, flags uint32 + err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags) + } + case <-timeout: + cancelIoEx(f.handle, &c.o) + r = <-c.ch + err = r.err + if err == windows.ERROR_OPERATION_ABORTED { + err = ErrTimeout + } + } + + // 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 *win32File) Read(b []byte) (int, error) { + c, err := f.prepareIo() + if err != nil { + return 0, err + } + defer f.wg.Done() + + if f.readDeadline.timedout.isSet() { + return 0, ErrTimeout + } + + 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 *win32File) Write(b []byte) (int, error) { + c, err := f.prepareIo() + if err != nil { + return 0, err + } + defer f.wg.Done() + + if f.writeDeadline.timedout.isSet() { + return 0, ErrTimeout + } + + 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 *win32File) SetReadDeadline(deadline time.Time) error { + return f.readDeadline.set(deadline) +} + +func (f *win32File) SetWriteDeadline(deadline time.Time) error { + return f.writeDeadline.set(deadline) +} + +func (f *win32File) Flush() error { + return windows.FlushFileBuffers(f.handle) +} + +func (f *win32File) 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 + } + d.timedout.setFalse() + + select { + case <-d.channel: + d.channelLock.Lock() + d.channel = make(chan struct{}) + d.channelLock.Unlock() + default: + } + + if deadline.IsZero() { + return nil + } + + timeoutIO := func() { + d.timedout.setTrue() + 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 +} diff --git a/vendor/golang.zx2c4.com/wireguard/ipc/winpipe/mksyscall.go b/vendor/golang.zx2c4.com/wireguard/ipc/winpipe/mksyscall.go new file mode 100644 index 0000000000..19ac03a67b --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/ipc/winpipe/mksyscall.go @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2005 Microsoft + * Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved. + */ + +package winpipe + +//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go pipe.go file.go diff --git a/vendor/golang.zx2c4.com/wireguard/ipc/winpipe/pipe.go b/vendor/golang.zx2c4.com/wireguard/ipc/winpipe/pipe.go new file mode 100644 index 0000000000..06b3037849 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/ipc/winpipe/pipe.go @@ -0,0 +1,509 @@ +// +build windows + +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2005 Microsoft + * Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved. + */ + +package winpipe + +import ( + "context" + "errors" + "fmt" + "io" + "net" + "os" + "runtime" + "time" + "unsafe" + + "golang.org/x/sys/windows" +) + +//sys connectNamedPipe(pipe windows.Handle, o *windows.Overlapped) (err error) = ConnectNamedPipe +//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *windows.SecurityAttributes) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateNamedPipeW +//sys createFile(name string, access uint32, mode uint32, sa *windows.SecurityAttributes, createmode uint32, attrs uint32, templatefile windows.Handle) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateFileW +//sys getNamedPipeInfo(pipe windows.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo +//sys getNamedPipeHandleState(pipe windows.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW +//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc +//sys ntCreateNamedPipeFile(pipe *windows.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) = ntdll.NtCreateNamedPipeFile +//sys rtlNtStatusToDosError(status ntstatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb +//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) = ntdll.RtlDosPathNameToNtPathName_U +//sys rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) = ntdll.RtlDefaultNpAcl + +type ioStatusBlock struct { + Status, Information uintptr +} + +type objectAttributes struct { + Length uintptr + RootDirectory uintptr + ObjectName *unicodeString + Attributes uintptr + SecurityDescriptor *windows.SECURITY_DESCRIPTOR + SecurityQoS uintptr +} + +type unicodeString struct { + Length uint16 + MaximumLength uint16 + Buffer uintptr +} + +type ntstatus int32 + +func (status ntstatus) Err() error { + if status >= 0 { + return nil + } + return rtlNtStatusToDosError(status) +} + +const ( + cSECURITY_SQOS_PRESENT = 0x100000 + cSECURITY_ANONYMOUS = 0 + + cPIPE_TYPE_MESSAGE = 4 + + cPIPE_READMODE_MESSAGE = 2 + + cFILE_OPEN = 1 + cFILE_CREATE = 2 + + cFILE_PIPE_MESSAGE_TYPE = 1 + cFILE_PIPE_REJECT_REMOTE_CLIENTS = 2 +) + +var ( + // ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed. + // This error should match net.errClosing since docker takes a dependency on its text. + ErrPipeListenerClosed = errors.New("use of closed network connection") + + errPipeWriteClosed = errors.New("pipe has been closed for write") +) + +type win32Pipe struct { + *win32File + path string +} + +type win32MessageBytePipe struct { + win32Pipe + writeClosed bool + readEOF bool +} + +type pipeAddress string + +func (f *win32Pipe) LocalAddr() net.Addr { + return pipeAddress(f.path) +} + +func (f *win32Pipe) RemoteAddr() net.Addr { + return pipeAddress(f.path) +} + +func (f *win32Pipe) 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 *win32MessageBytePipe) CloseWrite() error { + if f.writeClosed { + return errPipeWriteClosed + } + err := f.win32File.Flush() + if err != nil { + return err + } + _, err = f.win32File.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 *win32MessageBytePipe) Write(b []byte) (int, error) { + if f.writeClosed { + return 0, errPipeWriteClosed + } + if len(b) == 0 { + return 0, nil + } + return f.win32File.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 *win32MessageBytePipe) Read(b []byte) (int, error) { + if f.readEOF { + return 0, io.EOF + } + n, err := f.win32File.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 (s pipeAddress) Network() string { + return "pipe" +} + +func (s pipeAddress) String() string { + return string(s) +} + +// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout. +func tryDialPipe(ctx context.Context, path *string) (windows.Handle, error) { + for { + select { + case <-ctx.Done(): + return windows.Handle(0), ctx.Err() + default: + h, err := createFile(*path, windows.GENERIC_READ|windows.GENERIC_WRITE, 0, nil, windows.OPEN_EXISTING, windows.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_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(time.Millisecond * 10) + } + } +} + +// DialPipe connects to a 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. (We do not use WaitNamedPipe.) +func DialPipe(path string, timeout *time.Duration, expectedOwner *windows.SID) (net.Conn, error) { + var absTimeout time.Time + if timeout != nil { + absTimeout = time.Now().Add(*timeout) + } else { + absTimeout = time.Now().Add(time.Second * 2) + } + ctx, _ := context.WithDeadline(context.Background(), absTimeout) + conn, err := DialPipeContext(ctx, path, expectedOwner) + if err == context.DeadlineExceeded { + return nil, ErrTimeout + } + return conn, err +} + +// DialPipeContext attempts to connect to a named pipe by `path` until `ctx` +// cancellation or timeout. +func DialPipeContext(ctx context.Context, path string, expectedOwner *windows.SID) (net.Conn, error) { + var err error + var h windows.Handle + h, err = tryDialPipe(ctx, &path) + if err != nil { + return nil, err + } + + if 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(expectedOwner) { + windows.Close(h) + return nil, windows.ERROR_ACCESS_DENIED + } + } + + var flags uint32 + err = getNamedPipeInfo(h, &flags, nil, nil, nil) + if err != nil { + windows.Close(h) + return nil, err + } + + f, err := makeWin32File(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&cPIPE_TYPE_MESSAGE != 0 { + return &win32MessageBytePipe{ + win32Pipe: win32Pipe{win32File: f, path: path}, + }, nil + } + return &win32Pipe{win32File: f, path: path}, nil +} + +type acceptResponse struct { + f *win32File + err error +} + +type win32PipeListener struct { + firstHandle windows.Handle + path string + config PipeConfig + acceptCh chan (chan acceptResponse) + closeCh chan int + doneCh chan int +} + +func makeServerPipeHandle(path string, sd *windows.SECURITY_DESCRIPTOR, c *PipeConfig, first bool) (windows.Handle, error) { + path16, err := windows.UTF16FromString(path) + if err != nil { + return 0, &os.PathError{Op: "open", Path: path, Err: err} + } + + var oa objectAttributes + oa.Length = unsafe.Sizeof(oa) + + var ntPath unicodeString + if err := rtlDosPathNameToNtPathName(&path16[0], &ntPath, 0, 0).Err(); err != nil { + return 0, &os.PathError{Op: "open", Path: path, Err: err} + } + defer windows.LocalFree(windows.Handle(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 dacl uintptr + if err := rtlDefaultNpAcl(&dacl).Err(); err != nil { + return 0, fmt.Errorf("getting default named pipe ACL: %s", err) + } + defer windows.LocalFree(windows.Handle(dacl)) + sd, err := windows.NewSecurityDescriptor() + if err != nil { + return 0, fmt.Errorf("creating new security descriptor: %s", err) + } + if err = sd.SetDACL((*windows.ACL)(unsafe.Pointer(dacl)), true, false); err != nil { + return 0, fmt.Errorf("assigning dacl: %s", err) + } + sd, err = sd.ToSelfRelative() + if err != nil { + return 0, fmt.Errorf("converting to self-relative: %s", err) + } + oa.SecurityDescriptor = sd + } + } + + typ := uint32(cFILE_PIPE_REJECT_REMOTE_CLIENTS) + if c.MessageMode { + typ |= cFILE_PIPE_MESSAGE_TYPE + } + + disposition := uint32(cFILE_OPEN) + access := uint32(windows.GENERIC_READ | windows.GENERIC_WRITE | windows.SYNCHRONIZE) + if first { + disposition = cFILE_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 ioStatusBlock + ) + err = 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).Err() + if err != nil { + return 0, &os.PathError{Op: "open", Path: path, Err: err} + } + + runtime.KeepAlive(ntPath) + return h, nil +} + +func (l *win32PipeListener) makeServerPipe() (*win32File, error) { + h, err := makeServerPipeHandle(l.path, nil, &l.config, false) + if err != nil { + return nil, err + } + f, err := makeWin32File(h) + if err != nil { + windows.Close(h) + return nil, err + } + return f, nil +} + +func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, error) { + p, err := l.makeServerPipe() + if err != nil { + return nil, err + } + + // Wait for the client to connect. + ch := make(chan error) + go func(p *win32File) { + 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 == ErrFileClosed { + err = ErrPipeListenerClosed + } + } + return p, err +} + +func (l *win32PipeListener) listenerRoutine() { + closed := false + for !closed { + select { + case <-l.closeCh: + closed = true + case responseCh := <-l.acceptCh: + var ( + p *win32File + 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 == ErrPipeListenerClosed + } + } + windows.Close(l.firstHandle) + l.firstHandle = 0 + // Notify Close() and Accept() callers that the handle has been closed. + close(l.doneCh) +} + +// PipeConfig contain configuration for the pipe listener. +type PipeConfig struct { + // SecurityDescriptor contains a Windows security descriptor. + 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 size the input buffer, in bytes. + InputBufferSize int32 + + // OutputBufferSize specifies the size the input buffer, in bytes. + OutputBufferSize int32 +} + +// ListenPipe creates a listener on a Windows named pipe path, e.g. \\.\pipe\mypipe. +// The pipe must not already exist. +func ListenPipe(path string, c *PipeConfig) (net.Listener, error) { + if c == nil { + c = &PipeConfig{} + } + h, err := makeServerPipeHandle(path, c.SecurityDescriptor, c, true) + if err != nil { + return nil, err + } + l := &win32PipeListener{ + firstHandle: h, + path: path, + config: *c, + acceptCh: make(chan (chan acceptResponse)), + closeCh: make(chan int), + doneCh: make(chan int), + } + go l.listenerRoutine() + return l, nil +} + +func connectPipe(p *win32File) error { + c, err := p.prepareIo() + if err != nil { + return err + } + defer p.wg.Done() + + err = 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 *win32PipeListener) 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 &win32MessageBytePipe{ + win32Pipe: win32Pipe{win32File: response.f, path: l.path}, + }, nil + } + return &win32Pipe{win32File: response.f, path: l.path}, nil + case <-l.doneCh: + return nil, ErrPipeListenerClosed + } +} + +func (l *win32PipeListener) Close() error { + select { + case l.closeCh <- 1: + <-l.doneCh + case <-l.doneCh: + } + return nil +} + +func (l *win32PipeListener) Addr() net.Addr { + return pipeAddress(l.path) +} diff --git a/vendor/golang.zx2c4.com/wireguard/ipc/winpipe/zsyscall_windows.go b/vendor/golang.zx2c4.com/wireguard/ipc/winpipe/zsyscall_windows.go new file mode 100644 index 0000000000..995432975d --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/ipc/winpipe/zsyscall_windows.go @@ -0,0 +1,238 @@ +// Code generated by 'go generate'; DO NOT EDIT. + +package winpipe + +import ( + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +var _ unsafe.Pointer + +// Do the interface allocations only once for common +// Errno values. +const ( + errnoERROR_IO_PENDING = 997 +) + +var ( + errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) +) + +// errnoErr returns common boxed Errno values, to prevent +// allocations at runtime. +func errnoErr(e syscall.Errno) error { + switch e { + case 0: + return nil + case errnoERROR_IO_PENDING: + return errERROR_IO_PENDING + } + // TODO: add more here, after collecting data on the common + // error values see on Windows. (perhaps when running + // all.bat?) + return e +} + +var ( + modkernel32 = windows.NewLazySystemDLL("kernel32.dll") + modntdll = windows.NewLazySystemDLL("ntdll.dll") + modws2_32 = windows.NewLazySystemDLL("ws2_32.dll") + + procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe") + procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW") + procCreateFileW = modkernel32.NewProc("CreateFileW") + procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo") + procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW") + procLocalAlloc = modkernel32.NewProc("LocalAlloc") + procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile") + procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb") + procRtlDosPathNameToNtPathName_U = modntdll.NewProc("RtlDosPathNameToNtPathName_U") + procRtlDefaultNpAcl = modntdll.NewProc("RtlDefaultNpAcl") + procCancelIoEx = modkernel32.NewProc("CancelIoEx") + procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort") + procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus") + procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes") + procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult") +) + +func connectNamedPipe(pipe windows.Handle, o *windows.Overlapped) (err error) { + r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *windows.SecurityAttributes) (handle windows.Handle, err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(name) + if err != nil { + return + } + return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa) +} + +func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *windows.SecurityAttributes) (handle windows.Handle, err error) { + r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0) + handle = windows.Handle(r0) + if handle == windows.InvalidHandle { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func createFile(name string, access uint32, mode uint32, sa *windows.SecurityAttributes, createmode uint32, attrs uint32, templatefile windows.Handle) (handle windows.Handle, err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(name) + if err != nil { + return + } + return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile) +} + +func _createFile(name *uint16, access uint32, mode uint32, sa *windows.SecurityAttributes, createmode uint32, attrs uint32, templatefile windows.Handle) (handle windows.Handle, err error) { + r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0) + handle = windows.Handle(r0) + if handle == windows.InvalidHandle { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func getNamedPipeInfo(pipe windows.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func getNamedPipeHandleState(pipe windows.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func localAlloc(uFlags uint32, length uint32) (ptr uintptr) { + r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(uFlags), uintptr(length), 0) + ptr = uintptr(r0) + return +} + +func ntCreateNamedPipeFile(pipe *windows.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) { + r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0) + status = ntstatus(r0) + return +} + +func rtlNtStatusToDosError(status ntstatus) (winerr error) { + r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0) + if r0 != 0 { + winerr = syscall.Errno(r0) + } + return +} + +func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) { + r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0) + status = ntstatus(r0) + return +} + +func rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) { + r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0) + status = ntstatus(r0) + return +} + +func cancelIoEx(file windows.Handle, o *windows.Overlapped) (err error) { + r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func createIoCompletionPort(file windows.Handle, port windows.Handle, key uintptr, threadCount uint32) (newport windows.Handle, err error) { + r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0) + newport = windows.Handle(r0) + if newport == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func getQueuedCompletionStatus(port windows.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func setFileCompletionNotificationModes(h windows.Handle, flags uint8) (err error) { + r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func wsaGetOverlappedResult(h windows.Handle, o *windows.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) { + var _p0 uint32 + if wait { + _p0 = 1 + } else { + _p0 = 0 + } + r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/.cibuild.sh b/vendor/golang.zx2c4.com/wireguard/wgctrl/.cibuild.sh new file mode 100644 index 0000000000..09c76121f5 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/.cibuild.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -e +set -x + +# !! This script is meant for use in CI build use only !! + +BINDIR=/home/build/go/bin + +KERNEL=$(uname -s) + +# Use doas in place of sudo for OpenBSD. +SUDO="sudo" +if [ "${KERNEL}" == "OpenBSD" ]; then + SUDO="doas" +fi + +if [ "${KERNEL}" == "Linux" ]; then + # Set up the WireGuard kernel module on Linux. + sudo apt --allow-unauthenticated -y update + sudo apt -y install software-properties-common + sudo add-apt-repository -y ppa:wireguard/wireguard + sudo apt --allow-unauthenticated -y update + sudo apt --allow-unauthenticated -y install linux-headers-$(uname -r) wireguard-dkms wireguard-tools + + # 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 + +mkdir -p ${BINDIR} +${SUDO} mv ./wireguard-go ${BINDIR}/wireguard-go +cd .. +${SUDO} rm -rf ./wireguard-go diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/.gitignore b/vendor/golang.zx2c4.com/wireguard/wgctrl/.gitignore new file mode 100644 index 0000000000..81c07a2536 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/.gitignore @@ -0,0 +1,2 @@ +cmd/wgctrl/wgctrl +*.test diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/CONTRIBUTING.md b/vendor/golang.zx2c4.com/wireguard/wgctrl/CONTRIBUTING.md new file mode 100644 index 0000000000..c9f8934cb3 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/CONTRIBUTING.md @@ -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! diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/LICENSE.md b/vendor/golang.zx2c4.com/wireguard/wgctrl/LICENSE.md new file mode 100644 index 0000000000..9807819f8e --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/LICENSE.md @@ -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. diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/README.md b/vendor/golang.zx2c4.com/wireguard/wgctrl/README.md new file mode 100644 index 0000000000..b47a00e637 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/README.md @@ -0,0 +1,32 @@ +# wgctrl [![builds.sr.ht status](https://builds.sr.ht/~mdlayher/wgctrl-go.svg)](https://builds.sr.ht/~mdlayher/wgctrl-go?) [![GoDoc](https://godoc.org/golang.zx2c4.com/wireguard/wgctrl?status.svg)](https://godoc.org/golang.zx2c4.com/wireguard/wgctrl) [![Go Report Card](https://goreportcard.com/badge/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 . + +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 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. diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/client.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/client.go new file mode 100644 index 0000000000..71f78a3136 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/client.go @@ -0,0 +1,100 @@ +package wgctrl + +import ( + "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 os.IsNotExist. +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 os.IsNotExist(err): + 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 os.IsNotExist. +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 os.IsNotExist(err): + continue + default: + return err + } + } + + return os.ErrNotExist +} diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/doc.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/doc.go new file mode 100644 index 0000000000..91cdbad13d --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/doc.go @@ -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 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" diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/go.mod b/vendor/golang.zx2c4.com/wireguard/wgctrl/go.mod new file mode 100644 index 0000000000..e06cc85777 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/go.mod @@ -0,0 +1,13 @@ +module golang.zx2c4.com/wireguard/wgctrl + +go 1.13 + +require ( + github.com/google/go-cmp v0.4.0 + github.com/mdlayher/genetlink v1.0.0 + github.com/mdlayher/netlink v1.1.0 + github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 + golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72 + golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 + golang.zx2c4.com/wireguard v0.0.20200121 +) diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/go.sum b/vendor/golang.zx2c4.com/wireguard/wgctrl/go.sum new file mode 100644 index 0000000000..7d81d12312 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/go.sum @@ -0,0 +1,51 @@ +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/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +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/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4 h1:nwOc1YaOrYJ37sEBrtWZrdqzK22hiJs3GpDmP3sR2Yw= +github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= +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 h1:vySPY5Oxnn/8lxAPn2cK6kAzcZzYJl3KriSLO46OT18= +github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= +github.com/mdlayher/netlink v1.1.0 h1:mpdLgm+brq10nI9zM1BpX1kpDbh3NLl3RSnVq6ZSkfg= +github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= +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-20191002192127-34f69633bfdc h1:c0o/qxkaO2LF5t6fQrT4b5hzyggAkLLlCUjqfRxd8Q4= +golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72 h1:+ELyKg6m8UBf0nPFSqD0mi7zUfwPyXo23HNjMnXPz7w= +golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/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 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-20191003171128-d98b1b443823 h1:Ypyv6BNJh07T1pUSrehkLemqPKXhus2MkfktJ91kRh4= +golang.org/x/net v0.0.0-20191003171128-d98b1b443823/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/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/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-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-20191003212358-c178f38b412c h1:6Zx7DRlKXf79yfxuQ/7GqV3w2y7aDsk6bGg0MzF5RVU= +golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/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/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.zx2c4.com/wireguard v0.0.20200121 h1:vcswa5Q6f+sylDfjqyrVNNrjsFUUbPsgAQTBCAg/Qf8= +golang.zx2c4.com/wireguard v0.0.20200121/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4= diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wginternal/client.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wginternal/client.go new file mode 100644 index 0000000000..4401d72823 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wginternal/client.go @@ -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 +} diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wginternal/doc.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wginternal/doc.go new file mode 100644 index 0000000000..bfdd433512 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wginternal/doc.go @@ -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 diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/client_linux.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/client_linux.go new file mode 100644 index 0000000000..ac03e50b0e --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/client_linux.go @@ -0,0 +1,269 @@ +//+build linux + +package wglinux + +import ( + "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() + + //lint:ignore SA1019 maintain compatibility with old versions of Go + // by using netlink.IsNotExist for now. We can switch to errors.Is at + // a later time. + if netlink.IsNotExist(err) { + // 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 + } + + flags := netlink.Request | netlink.Dump + + // 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, flags, 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. + flags := netlink.Request | netlink.Acknowledge + if _, err := c.execute(wgh.CmdSetDevice, flags, 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 + // the error for use with os.IsNotExist and similar. + 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.IsNotExist 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() + } +} diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/configure_linux.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/configure_linux.go new file mode 100644 index 0000000000..075a0664ed --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/configure_linux.go @@ -0,0 +1,295 @@ +//+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" +) + +// TODO(mdlayher): netlink message chunking with large configurations. + +// 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), func(nnae *netlink.AttributeEncoder) error { + return encodePeer(nnae, 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 converts a PeerConfig into netlink attribute encoder bytes. +func encodePeer(ae *netlink.AttributeEncoder, p wgtypes.PeerConfig) 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, func() ([]byte, error) { + return sockaddrBytes(*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, func(nae *netlink.AttributeEncoder) error { + return encodeAllowedIPs(nae, p.AllowedIPs) + }) + } + + return nil +} + +// sockaddrBytes converts a net.UDPAddr to raw sockaddr_in or sockaddr_in6 bytes. +func sockaddrBytes(endpoint net.UDPAddr) ([]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 converts a slice net.IPNets into netlink attribute encoder +// bytes. +func encodeAllowedIPs(ae *netlink.AttributeEncoder, ipns []net.IPNet) 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))) +} diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/doc.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/doc.go new file mode 100644 index 0000000000..2349ee6e08 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/doc.go @@ -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 diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/const.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/const.go new file mode 100644 index 0000000000..875fa5a6c3 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/const.go @@ -0,0 +1,99 @@ +// WARNING: This file has automatically been generated on Mon, 28 Oct 2019 14:56:12 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 +) diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/doc.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/doc.go new file mode 100644 index 0000000000..3e7c46e01f --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/doc.go @@ -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/WireGuard/WireGuard/master/src/uapi/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/ diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/wgh.yml b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/wgh.yml new file mode 100644 index 0000000000..d87e7eb1cb --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh/wgh.yml @@ -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} diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/parse_linux.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/parse_linux.go new file mode 100644 index 0000000000..804b3538f0 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/parse_linux.go @@ -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(func(nad *netlink.AttributeDecoder) error { + p.AllowedIPs = parseAllowedIPs(nad) + return nil + }) + case wgh.PeerAProtocolVersion: + p.ProtocolVersion = int(ad.Uint32()) + } + } + + return p +} + +// parseAllowedIPs parses a slice of net.IPNet from a netlink attribute payload. +func parseAllowedIPs(ad *netlink.AttributeDecoder) []net.IPNet { + // 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()) + } + } + + // 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 ipns +} + +// 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 + } + } +} diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/client_openbsd.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/client_openbsd.go new file mode 100644 index 0000000000..8edf08fff7 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/client_openbsd.go @@ -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...)) +} diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/doc.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/doc.go new file mode 100644 index 0000000000..c4ab4850ca --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/doc.go @@ -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 diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/defs_openbsd_386.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/defs_openbsd_386.go new file mode 100644 index 0000000000..aeb26a1bb4 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/defs_openbsd_386.go @@ -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 +) diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/defs_openbsd_amd64.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/defs_openbsd_amd64.go new file mode 100644 index 0000000000..611d417d60 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/defs_openbsd_amd64.go @@ -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 +) diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/doc.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/doc.go new file mode 100644 index 0000000000..9832b77017 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/doc.go @@ -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 diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/generate.sh b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/generate.sh new file mode 100644 index 0000000000..f81b5b6e18 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh/generate.sh @@ -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 diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/client.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/client.go new file mode 100644 index 0000000000..2ccb187d42 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/client.go @@ -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...)) +} diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/configure.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/configure.go new file mode 100644 index 0000000000..28770e8d16 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/configure.go @@ -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[:]) +} diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/conn_unix.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/conn_unix.go new file mode 100644 index 0000000000..fd3470b0a9 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/conn_unix.go @@ -0,0 +1,49 @@ +//+build !windows + +package wguser + +import ( + "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 os.IsNotExist(err) { + 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 +} diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/conn_windows.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/conn_windows.go new file mode 100644 index 0000000000..b5a0ae404f --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/conn_windows.go @@ -0,0 +1,249 @@ +//+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 + } + + return winpipe.DialPipe(device, nil, localSystem) +} + +// 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 +} diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/doc.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/doc.go new file mode 100644 index 0000000000..bf50bcd8c5 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/doc.go @@ -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 diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/parse.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/parse.go new file mode 100644 index 0000000000..dc996b2493 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/internal/wguser/parse.go @@ -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 +} diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/os_linux.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/os_linux.go new file mode 100644 index 0000000000..a6ab3d9088 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/os_linux.go @@ -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 +} diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/os_openbsd.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/os_openbsd.go new file mode 100644 index 0000000000..b00ba29356 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/os_openbsd.go @@ -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 +} diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/os_userspace.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/os_userspace.go new file mode 100644 index 0000000000..beb41ae645 --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/os_userspace.go @@ -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 +} diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/wgtypes/doc.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/wgtypes/doc.go new file mode 100644 index 0000000000..97fc48bdfa --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/wgtypes/doc.go @@ -0,0 +1,2 @@ +// Package wgtypes provides shared types for the wgctrl family of packages. +package wgtypes // import "golang.zx2c4.com/wireguard/wgctrl/wgtypes" diff --git a/vendor/golang.zx2c4.com/wireguard/wgctrl/wgtypes/types.go b/vendor/golang.zx2c4.com/wireguard/wgctrl/wgtypes/types.go new file mode 100644 index 0000000000..4b7086cb0e --- /dev/null +++ b/vendor/golang.zx2c4.com/wireguard/wgctrl/wgtypes/types.go @@ -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 +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 536b7fe30d..605cb0a0e3 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -91,6 +91,9 @@ github.com/go-logr/logr # github.com/gogo/protobuf v1.3.1 github.com/gogo/protobuf/proto github.com/gogo/protobuf/sortkeys +# github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b +## explicit +github.com/golang/glog # github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 github.com/golang/groupcache/lru # github.com/golang/protobuf v1.4.2 @@ -129,6 +132,11 @@ github.com/joho/godotenv github.com/jonboulle/clockwork # github.com/json-iterator/go v1.1.10 github.com/json-iterator/go +# github.com/mdlayher/genetlink v1.0.0 +github.com/mdlayher/genetlink +# github.com/mdlayher/netlink v1.1.0 +github.com/mdlayher/netlink +github.com/mdlayher/netlink/nlenc # github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd github.com/modern-go/concurrent # github.com/modern-go/reflect2 v1.0.1 @@ -181,9 +189,11 @@ go.opencensus.io/trace/internal go.opencensus.io/trace/propagation go.opencensus.io/trace/tracestate # golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 +golang.org/x/crypto/curve25519 golang.org/x/crypto/ssh/terminal # golang.org/x/net v0.0.0-20201110031124-69a78807bb2b ## explicit +golang.org/x/net/bpf golang.org/x/net/context golang.org/x/net/context/ctxhttp golang.org/x/net/http/httpguts @@ -211,6 +221,18 @@ golang.org/x/text/unicode/bidi golang.org/x/text/unicode/norm # golang.org/x/time v0.0.0-20191024005414-555d28b269f0 golang.org/x/time/rate +# golang.zx2c4.com/wireguard v0.0.20200121 +golang.zx2c4.com/wireguard/ipc/winpipe +# golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200609130330-bd2cb7843e1b +## explicit +golang.zx2c4.com/wireguard/wgctrl +golang.zx2c4.com/wireguard/wgctrl/internal/wginternal +golang.zx2c4.com/wireguard/wgctrl/internal/wglinux +golang.zx2c4.com/wireguard/wgctrl/internal/wglinux/internal/wgh +golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd +golang.zx2c4.com/wireguard/wgctrl/internal/wgopenbsd/internal/wgh +golang.zx2c4.com/wireguard/wgctrl/internal/wguser +golang.zx2c4.com/wireguard/wgctrl/wgtypes # google.golang.org/api v0.15.0 ## explicit google.golang.org/api/compute/v1