Compare commits
86 Commits
0.0.201805
...
0.0.201810
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
738d027f0b | ||
|
|
60848b9c72 | ||
|
|
2e772194cf | ||
|
|
85b2378a07 | ||
|
|
fddb949002 | ||
|
|
5d6083df7e | ||
|
|
b41922e5c8 | ||
|
|
dbb72402f2 | ||
|
|
7c971d7ef4 | ||
|
|
70bcf9ecb8 | ||
|
|
ebc7541953 | ||
|
|
833597b585 | ||
|
|
cf81a28dd3 | ||
|
|
942abf948a | ||
|
|
47d1140361 | ||
|
|
39d6e4f2f1 | ||
|
|
1c02557013 | ||
|
|
32d2148835 | ||
|
|
5be541d147 | ||
|
|
063becdc73 | ||
|
|
15da869b31 | ||
|
|
3ad3e83c7a | ||
|
|
2e13b7b0fb | ||
|
|
6b3b1c3b91 | ||
|
|
6a5d0e2bcd | ||
|
|
0ba551807f | ||
|
|
99d5aeeb27 | ||
|
|
a050431f26 | ||
|
|
0c976003c8 | ||
|
|
955e89839f | ||
|
|
a4cd0216c0 | ||
|
|
1d7845a600 | ||
|
|
5079298ce2 | ||
|
|
fc3a7635e5 | ||
|
|
2496cdd8e6 | ||
|
|
4365b4583f | ||
|
|
bbf320c477 | ||
|
|
625d59da14 | ||
|
|
2f2eca8947 | ||
|
|
66f6ca3e4a | ||
|
|
e6657638fc | ||
|
|
4a9de3218e | ||
|
|
28a167e828 | ||
|
|
99c6513d60 | ||
|
|
8a92a9109a | ||
|
|
0b647d1ca7 | ||
|
|
588b9f01ae | ||
|
|
f70bd1fab3 | ||
|
|
40d5ff0c70 | ||
|
|
5a2228a5c9 | ||
|
|
0a63188afa | ||
|
|
65a74f3175 | ||
|
|
b4cef2524f | ||
|
|
7038de95e1 | ||
|
|
82d12e85bb | ||
|
|
d6b694e161 | ||
|
|
794e494802 | ||
|
|
dd663a7ba4 | ||
|
|
8462c08cf2 | ||
|
|
b8c9e13c6e | ||
|
|
bc05eb1c3c | ||
|
|
7a527f7c89 | ||
|
|
84f52ce0d6 | ||
|
|
7bdc5eb54e | ||
|
|
1c666576d5 | ||
|
|
2ae22ac65d | ||
|
|
ff3f2455e5 | ||
|
|
b962d7d791 | ||
|
|
837a12c841 | ||
|
|
7472930d4e | ||
|
|
6307bfcdf4 | ||
|
|
e28d70f5b2 | ||
|
|
84c5357cf3 | ||
|
|
acb5481246 | ||
|
|
18f43705ec | ||
|
|
058cedcf66 | ||
|
|
c5fa3de24c | ||
|
|
1068d6b92b | ||
|
|
5e924e5407 | ||
|
|
b290cf05e3 | ||
|
|
b95a4c61a5 | ||
|
|
a5b3340e5b | ||
|
|
7c21a3de0a | ||
|
|
0a68c1ab17 | ||
|
|
e04f9543c0 | ||
|
|
fa003b6933 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
wireguard-go
|
||||
vendor
|
||||
.gopath
|
||||
ireallywantobuildon_linux.go
|
||||
|
||||
16
Gopkg.lock
generated
16
Gopkg.lock
generated
@@ -1,16 +0,0 @@
|
||||
# This was generated by ./generate-vendor.sh
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
revision = "1a580b3eff7814fc9b40602fd35256c63b50f491"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/net"
|
||||
revision = "2491c5de3490fced2f6cff376127c667efeed857"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
revision = "7c87d13f8e835d2fb3a70a2912c811ed0c1d241b"
|
||||
|
||||
13
Gopkg.toml
13
Gopkg.toml
@@ -1,13 +0,0 @@
|
||||
# This was generated by ./generate-vendor.sh
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/net"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
|
||||
34
Makefile
34
Makefile
@@ -1,16 +1,42 @@
|
||||
PREFIX ?= /usr
|
||||
DESTDIR ?=
|
||||
BINDIR ?= $(PREFIX)/bin
|
||||
export GOPATH ?= $(CURDIR)/.gopath
|
||||
export GO111MODULE := on
|
||||
|
||||
all: wireguard-go
|
||||
all: generate-version-and-build
|
||||
|
||||
ifeq ($(shell go env GOOS)|$(wildcard .git),linux|)
|
||||
$(error Do not build this for Linux. Instead use the Linux kernel module. See wireguard.com/install/ for more info.)
|
||||
else
|
||||
ireallywantobuildon_linux.go:
|
||||
@printf "WARNING: This software is meant for use on non-Linux\nsystems. For Linux, please use the kernel module\ninstead. See wireguard.com/install/ for more info.\n\n" >&2
|
||||
@printf 'package main\nconst UseTheKernelModuleInstead = 0xdeadbabe\n' > "$@"
|
||||
clean-ireallywantobuildon_linux.go:
|
||||
@rm -f ireallywantobuildon_linux.go
|
||||
.PHONY: clean-ireallywantobuildon_linux.go
|
||||
clean: clean-ireallywantobuildon_linux.go
|
||||
wireguard-go: ireallywantobuildon_linux.go
|
||||
endif
|
||||
|
||||
MAKEFLAGS += --no-print-directory
|
||||
|
||||
generate-version-and-build:
|
||||
@export GIT_CEILING_DIRECTORIES="$(realpath $(CURDIR)/..)" && \
|
||||
tag="$$(git describe --dirty 2>/dev/null)" && \
|
||||
ver="$$(printf 'package main\nconst WireGuardGoVersion = "%s"\n' "$$tag")" && \
|
||||
[ "$$(cat version.go 2>/dev/null)" != "$$ver" ] && \
|
||||
echo "$$ver" > version.go && \
|
||||
git update-index --assume-unchanged version.go || true
|
||||
@$(MAKE) wireguard-go
|
||||
|
||||
wireguard-go: $(wildcard *.go) $(wildcard */*.go)
|
||||
go build -v -o $@
|
||||
go build -v -o "$@"
|
||||
|
||||
install: wireguard-go
|
||||
@install -v -d "$(DESTDIR)$(BINDIR)" && install -m 0755 -v wireguard-go "$(DESTDIR)$(BINDIR)/wireguard-go"
|
||||
@install -v -d "$(DESTDIR)$(BINDIR)" && install -v -m 0755 "$<" "$(DESTDIR)$(BINDIR)/wireguard-go"
|
||||
|
||||
clean:
|
||||
rm -f wireguard-go
|
||||
|
||||
.PHONY: clean install
|
||||
.PHONY: all clean install generate-version-and-build
|
||||
|
||||
20
README.md
20
README.md
@@ -32,7 +32,7 @@ This will run on Linux; however **YOU SHOULD NOT RUN THIS ON LINUX**. Instead us
|
||||
|
||||
### macOS
|
||||
|
||||
This runs on macOS using the utun driver. It does not yet support sticky sockets, and won't support fwmarks because of Darwin limitations. Since the utun driver cannot have arbitrary interface names, you must either use `utun[0-9]+` for an explicit interface name or `utun` to have the kernel select one for you. If you choose `utun` as the interface name, and the environment variable `WG_DARWIN_UTUN_NAME_FILE` is defined, then the actual name of the interface chosen by the kernel is written to the file specified by that variable.
|
||||
This runs on macOS using the utun driver. It does not yet support sticky sockets, and won't support fwmarks because of Darwin limitations. Since the utun driver cannot have arbitrary interface names, you must either use `utun[0-9]+` for an explicit interface name or `utun` to have the kernel select one for you. If you choose `utun` as the interface name, and the environment variable `WG_TUN_NAME_FILE` is defined, then the actual name of the interface chosen by the kernel is written to the file specified by that variable.
|
||||
|
||||
### Windows
|
||||
|
||||
@@ -40,17 +40,19 @@ It is currently a work in progress to strip out the beginnings of an experiment
|
||||
|
||||
### FreeBSD
|
||||
|
||||
Work in progress, but nothing yet to share.
|
||||
This will run on FreeBSD. It does not yet support sticky sockets. Fwmark is mapped to `SO_USER_COOKIE`.
|
||||
|
||||
### OpenBSD
|
||||
|
||||
This will run on OpenBSD. It does not yet support sticky sockets. Fwmark is mapped to `SO_RTABLE`. Since the tun driver cannot have arbitrary interface names, you must either use `tun[0-9]+` for an explicit interface name or `tun` to have the program select one for you. If you choose `tun` as the interface name, and the environment variable `WG_TUN_NAME_FILE` is defined, then the actual name of the interface chosen by the kernel is written to the file specified by that variable.
|
||||
|
||||
## Building
|
||||
|
||||
You can satisfy dependencies with either `go get -d -v` or `dep ensure -vendor-only`. Then run `make`. As this is a Go project, a `GOPATH` is required. For example, wireguard-go can be built with:
|
||||
This requires an installation of [go](https://golang.org) ≥ 1.11.
|
||||
|
||||
```
|
||||
$ git clone https://git.zx2c4.com/wireguard-go
|
||||
$ cd wireguard-go
|
||||
$ export GOPATH="$PWD/gopath"
|
||||
$ go get -d -v
|
||||
$ make
|
||||
```
|
||||
|
||||
@@ -74,9 +76,9 @@ $ make
|
||||
are otherwise in compliance with the GPLv2 for each covered work you convey
|
||||
(including without limitation making the Corresponding Source available in
|
||||
compliance with Section 3 of the GPLv2), you are granted the additional
|
||||
the additional permission to convey through the Apple App Store
|
||||
non-source executable versions of the Program as incorporated into each
|
||||
applicable covered work as Executable Versions only under the Mozilla
|
||||
Public License version 2.0 (https://www.mozilla.org/en-US/MPL/2.0/).
|
||||
permission to convey through the Apple App Store non-source executable
|
||||
versions of the Program as incorporated into each applicable covered work
|
||||
as Executable Versions only under the Mozilla Public License version 2.0
|
||||
(https://www.mozilla.org/en-US/MPL/2.0/).
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
@echo off
|
||||
|
||||
REM builds wireguard for windows
|
||||
|
||||
go get
|
||||
go build -o wireguard-go.exe
|
||||
11
conn.go
11
conn.go
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
@@ -66,8 +65,6 @@ func parseEndpoint(s string) (*net.UDPAddr, error) {
|
||||
return addr, err
|
||||
}
|
||||
|
||||
/* Must hold device and net lock
|
||||
*/
|
||||
func unsafeCloseBind(device *Device) error {
|
||||
var err error
|
||||
netc := &device.net
|
||||
@@ -75,6 +72,7 @@ func unsafeCloseBind(device *Device) error {
|
||||
err = netc.bind.Close()
|
||||
netc.bind = nil
|
||||
}
|
||||
netc.stopping.Wait()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -162,10 +160,11 @@ func (device *Device) BindUpdate() error {
|
||||
|
||||
// start receiving routines
|
||||
|
||||
device.state.starting.Add(ConnRoutineNumber)
|
||||
device.state.stopping.Add(ConnRoutineNumber)
|
||||
device.net.starting.Add(ConnRoutineNumber)
|
||||
device.net.stopping.Add(ConnRoutineNumber)
|
||||
go device.RoutineReceiveIncoming(ipv4.Version, netc.bind)
|
||||
go device.RoutineReceiveIncoming(ipv6.Version, netc.bind)
|
||||
device.net.starting.Wait()
|
||||
|
||||
device.log.Debug.Println("UDP bind has been updated")
|
||||
}
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
// +build !linux
|
||||
// +build !linux android
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
/* This code is meant to be a temporary solution
|
||||
@@ -85,6 +88,18 @@ func listenNet(network string, port int) (*net.UDPConn, int, error) {
|
||||
return conn, uaddr.Port, nil
|
||||
}
|
||||
|
||||
func extractErrno(err error) error {
|
||||
opErr, ok := err.(*net.OpError)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
syscallErr, ok := opErr.Err.(*os.SyscallError)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return syscallErr.Err
|
||||
}
|
||||
|
||||
func CreateBind(uport uint16, device *Device) (Bind, uint16, error) {
|
||||
var err error
|
||||
var bind NativeBind
|
||||
@@ -92,13 +107,15 @@ func CreateBind(uport uint16, device *Device) (Bind, uint16, error) {
|
||||
port := int(uport)
|
||||
|
||||
bind.ipv4, port, err = listenNet("udp4", port)
|
||||
if err != nil {
|
||||
if err != nil && extractErrno(err) != syscall.EAFNOSUPPORT {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
bind.ipv6, port, err = listenNet("udp6", port)
|
||||
if err != nil {
|
||||
if err != nil && extractErrno(err) != syscall.EAFNOSUPPORT {
|
||||
return nil, 0, err
|
||||
bind.ipv4.Close()
|
||||
bind.ipv4 = nil
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
@@ -106,8 +123,13 @@ func CreateBind(uport uint16, device *Device) (Bind, uint16, error) {
|
||||
}
|
||||
|
||||
func (bind *NativeBind) Close() error {
|
||||
err1 := bind.ipv4.Close()
|
||||
err2 := bind.ipv6.Close()
|
||||
var err1, err2 error
|
||||
if bind.ipv4 != nil {
|
||||
err1 = bind.ipv4.Close()
|
||||
}
|
||||
if bind.ipv6 != nil {
|
||||
err2 = bind.ipv6.Close()
|
||||
}
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
@@ -115,6 +137,9 @@ func (bind *NativeBind) Close() error {
|
||||
}
|
||||
|
||||
func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) {
|
||||
if bind.ipv4 == nil {
|
||||
return 0, nil, syscall.EAFNOSUPPORT
|
||||
}
|
||||
n, endpoint, err := bind.ipv4.ReadFromUDP(buff)
|
||||
if endpoint != nil {
|
||||
endpoint.IP = endpoint.IP.To4()
|
||||
@@ -123,6 +148,9 @@ func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) {
|
||||
}
|
||||
|
||||
func (bind *NativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) {
|
||||
if bind.ipv6 == nil {
|
||||
return 0, nil, syscall.EAFNOSUPPORT
|
||||
}
|
||||
n, endpoint, err := bind.ipv6.ReadFromUDP(buff)
|
||||
return n, (*NativeEndpoint)(endpoint), err
|
||||
}
|
||||
@@ -131,13 +159,59 @@ func (bind *NativeBind) Send(buff []byte, endpoint Endpoint) error {
|
||||
var err error
|
||||
nend := endpoint.(*NativeEndpoint)
|
||||
if nend.IP.To4() != nil {
|
||||
if bind.ipv4 == nil {
|
||||
return syscall.EAFNOSUPPORT
|
||||
}
|
||||
_, err = bind.ipv4.WriteToUDP(buff, (*net.UDPAddr)(nend))
|
||||
} else {
|
||||
if bind.ipv6 == nil {
|
||||
return syscall.EAFNOSUPPORT
|
||||
}
|
||||
_, err = bind.ipv6.WriteToUDP(buff, (*net.UDPAddr)(nend))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (bind *NativeBind) SetMark(_ uint32) error {
|
||||
var fwmarkIoctl int
|
||||
|
||||
func init() {
|
||||
switch runtime.GOOS {
|
||||
case "linux", "android":
|
||||
fwmarkIoctl = 36 /* unix.SO_MARK */
|
||||
case "freebsd":
|
||||
fwmarkIoctl = 0x1015 /* unix.SO_USER_COOKIE */
|
||||
case "openbsd":
|
||||
fwmarkIoctl = 0x1021 /* unix.SO_RTABLE */
|
||||
}
|
||||
}
|
||||
|
||||
func (bind *NativeBind) SetMark(mark uint32) error {
|
||||
if fwmarkIoctl == 0 {
|
||||
return nil
|
||||
}
|
||||
if bind.ipv4 != nil {
|
||||
fd, err := bind.ipv4.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = fd.Control(func(fd uintptr) {
|
||||
err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, fwmarkIoctl, int(mark))
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if bind.ipv6 != nil {
|
||||
fd, err := bind.ipv6.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = fd.Control(func(fd uintptr) {
|
||||
err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, fwmarkIoctl, int(mark))
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
125
conn_linux.go
125
conn_linux.go
@@ -1,7 +1,8 @@
|
||||
// +build !android
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*
|
||||
* This implements userspace semantics of "sticky sockets", modeled after
|
||||
* WireGuard's kernelspace implementation. This is more or less a straight port
|
||||
@@ -16,14 +17,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"./rwcancel"
|
||||
"errors"
|
||||
"git.zx2c4.com/wireguard-go/rwcancel"
|
||||
"golang.org/x/sys/unix"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
FD_ERR = -1
|
||||
)
|
||||
|
||||
type IPv4Source struct {
|
||||
src [4]byte
|
||||
ifindex int32
|
||||
@@ -123,6 +130,7 @@ func createNetlinkRouteSocket() (int, error) {
|
||||
func CreateBind(port uint16, device *Device) (*NativeBind, uint16, error) {
|
||||
var err error
|
||||
var bind NativeBind
|
||||
var newPort uint16
|
||||
|
||||
bind.netlinkSock, err = createNetlinkRouteSocket()
|
||||
if err != nil {
|
||||
@@ -136,41 +144,63 @@ func CreateBind(port uint16, device *Device) (*NativeBind, uint16, error) {
|
||||
|
||||
go bind.routineRouteListener(device)
|
||||
|
||||
bind.sock6, port, err = create6(port)
|
||||
// attempt ipv6 bind, update port if succesful
|
||||
|
||||
bind.sock6, newPort, err = create6(port)
|
||||
if err != nil {
|
||||
bind.netlinkCancel.Cancel()
|
||||
return nil, port, err
|
||||
if err != syscall.EAFNOSUPPORT {
|
||||
bind.netlinkCancel.Cancel()
|
||||
return nil, 0, err
|
||||
}
|
||||
} else {
|
||||
port = newPort
|
||||
}
|
||||
|
||||
bind.sock4, port, err = create4(port)
|
||||
// attempt ipv4 bind, update port if succesful
|
||||
|
||||
bind.sock4, newPort, err = create4(port)
|
||||
if err != nil {
|
||||
bind.netlinkCancel.Cancel()
|
||||
unix.Close(bind.sock6)
|
||||
if err != syscall.EAFNOSUPPORT {
|
||||
bind.netlinkCancel.Cancel()
|
||||
unix.Close(bind.sock6)
|
||||
return nil, 0, err
|
||||
}
|
||||
} else {
|
||||
port = newPort
|
||||
}
|
||||
return &bind, port, err
|
||||
|
||||
if bind.sock4 == FD_ERR && bind.sock6 == FD_ERR {
|
||||
return nil, 0, errors.New("ipv4 and ipv6 not supported")
|
||||
}
|
||||
|
||||
return &bind, port, nil
|
||||
}
|
||||
|
||||
func (bind *NativeBind) SetMark(value uint32) error {
|
||||
err := unix.SetsockoptInt(
|
||||
bind.sock6,
|
||||
unix.SOL_SOCKET,
|
||||
unix.SO_MARK,
|
||||
int(value),
|
||||
)
|
||||
if bind.sock6 != -1 {
|
||||
err := unix.SetsockoptInt(
|
||||
bind.sock6,
|
||||
unix.SOL_SOCKET,
|
||||
unix.SO_MARK,
|
||||
int(value),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = unix.SetsockoptInt(
|
||||
bind.sock4,
|
||||
unix.SOL_SOCKET,
|
||||
unix.SO_MARK,
|
||||
int(value),
|
||||
)
|
||||
if bind.sock4 != -1 {
|
||||
err := unix.SetsockoptInt(
|
||||
bind.sock4,
|
||||
unix.SOL_SOCKET,
|
||||
unix.SO_MARK,
|
||||
int(value),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
bind.lastMark = value
|
||||
@@ -184,9 +214,14 @@ func closeUnblock(fd int) error {
|
||||
}
|
||||
|
||||
func (bind *NativeBind) Close() error {
|
||||
err1 := closeUnblock(bind.sock6)
|
||||
err2 := closeUnblock(bind.sock4)
|
||||
err3 := bind.netlinkCancel.Cancel()
|
||||
var err1, err2, err3 error
|
||||
if bind.sock6 != -1 {
|
||||
err1 = closeUnblock(bind.sock6)
|
||||
}
|
||||
if bind.sock4 != -1 {
|
||||
err2 = closeUnblock(bind.sock4)
|
||||
}
|
||||
err3 = bind.netlinkCancel.Cancel()
|
||||
|
||||
if err1 != nil {
|
||||
return err1
|
||||
@@ -199,6 +234,9 @@ func (bind *NativeBind) Close() error {
|
||||
|
||||
func (bind *NativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) {
|
||||
var end NativeEndpoint
|
||||
if bind.sock6 == -1 {
|
||||
return 0, nil, syscall.EAFNOSUPPORT
|
||||
}
|
||||
n, err := receive6(
|
||||
bind.sock6,
|
||||
buff,
|
||||
@@ -209,6 +247,9 @@ func (bind *NativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) {
|
||||
|
||||
func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) {
|
||||
var end NativeEndpoint
|
||||
if bind.sock4 == -1 {
|
||||
return 0, nil, syscall.EAFNOSUPPORT
|
||||
}
|
||||
n, err := receive4(
|
||||
bind.sock4,
|
||||
buff,
|
||||
@@ -220,8 +261,14 @@ func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) {
|
||||
func (bind *NativeBind) Send(buff []byte, end Endpoint) error {
|
||||
nend := end.(*NativeEndpoint)
|
||||
if !nend.isV6 {
|
||||
if bind.sock4 == -1 {
|
||||
return syscall.EAFNOSUPPORT
|
||||
}
|
||||
return send4(bind.sock4, nend, buff)
|
||||
} else {
|
||||
if bind.sock6 == -1 {
|
||||
return syscall.EAFNOSUPPORT
|
||||
}
|
||||
return send6(bind.sock6, nend, buff)
|
||||
}
|
||||
}
|
||||
@@ -309,7 +356,7 @@ func create4(port uint16) (int, uint16, error) {
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return -1, 0, err
|
||||
return FD_ERR, 0, err
|
||||
}
|
||||
|
||||
addr := unix.SockaddrInet4{
|
||||
@@ -340,7 +387,7 @@ func create4(port uint16) (int, uint16, error) {
|
||||
return unix.Bind(fd, &addr)
|
||||
}(); err != nil {
|
||||
unix.Close(fd)
|
||||
return -1, 0, err
|
||||
return FD_ERR, 0, err
|
||||
}
|
||||
|
||||
return fd, uint16(addr.Port), err
|
||||
@@ -357,7 +404,7 @@ func create6(port uint16) (int, uint16, error) {
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return -1, 0, err
|
||||
return FD_ERR, 0, err
|
||||
}
|
||||
|
||||
// set sockopts and bind
|
||||
@@ -399,7 +446,7 @@ func create6(port uint16) (int, uint16, error) {
|
||||
|
||||
}(); err != nil {
|
||||
unix.Close(fd)
|
||||
return -1, 0, err
|
||||
return FD_ERR, 0, err
|
||||
}
|
||||
|
||||
return fd, uint16(addr.Port), err
|
||||
@@ -551,6 +598,7 @@ func (bind *NativeBind) routineRouteListener(device *Device) {
|
||||
endpoint *Endpoint
|
||||
}
|
||||
var reqPeer map[uint32]peerEndpointPtr
|
||||
var reqPeerLock sync.Mutex
|
||||
|
||||
defer unix.Close(bind.netlinkSock)
|
||||
|
||||
@@ -559,7 +607,7 @@ func (bind *NativeBind) routineRouteListener(device *Device) {
|
||||
var msgn int
|
||||
for {
|
||||
msgn, _, _, _, err = unix.Recvmsg(bind.netlinkSock, msg[:], nil, 0)
|
||||
if err == nil || !rwcancel.ErrorIsEAGAIN(err) {
|
||||
if err == nil || !rwcancel.RetryAfterError(err) {
|
||||
break
|
||||
}
|
||||
if !bind.netlinkCancel.ReadyRead() {
|
||||
@@ -580,7 +628,7 @@ func (bind *NativeBind) routineRouteListener(device *Device) {
|
||||
|
||||
switch hdr.Type {
|
||||
case unix.RTM_NEWROUTE, unix.RTM_DELROUTE:
|
||||
if hdr.Seq <= MaxPeers {
|
||||
if hdr.Seq <= MaxPeers && hdr.Seq > 0 {
|
||||
if uint(len(remain)) < uint(hdr.Len) {
|
||||
break
|
||||
}
|
||||
@@ -596,10 +644,13 @@ func (bind *NativeBind) routineRouteListener(device *Device) {
|
||||
}
|
||||
if attrhdr.Type == unix.RTA_OIF && attrhdr.Len == unix.SizeofRtAttr+4 {
|
||||
ifidx := *(*uint32)(unsafe.Pointer(&attr[unix.SizeofRtAttr]))
|
||||
reqPeerLock.Lock()
|
||||
if reqPeer == nil {
|
||||
reqPeerLock.Unlock()
|
||||
break
|
||||
}
|
||||
pePtr, ok := reqPeer[hdr.Seq]
|
||||
reqPeerLock.Unlock()
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
@@ -620,7 +671,9 @@ func (bind *NativeBind) routineRouteListener(device *Device) {
|
||||
}
|
||||
break
|
||||
}
|
||||
reqPeerLock.Lock()
|
||||
reqPeer = make(map[uint32]peerEndpointPtr)
|
||||
reqPeerLock.Unlock()
|
||||
go func() {
|
||||
device.peers.mutex.RLock()
|
||||
i := uint32(1)
|
||||
@@ -671,10 +724,12 @@ func (bind *NativeBind) routineRouteListener(device *Device) {
|
||||
uint32(bind.lastMark),
|
||||
}
|
||||
nlmsg.hdr.Len = uint32(unsafe.Sizeof(nlmsg))
|
||||
reqPeerLock.Lock()
|
||||
reqPeer[i] = peerEndpointPtr{
|
||||
peer: peer,
|
||||
endpoint: &peer.endpoint,
|
||||
}
|
||||
reqPeerLock.Unlock()
|
||||
peer.mutex.RUnlock()
|
||||
i++
|
||||
_, err := bind.netlinkCancel.Write((*[unsafe.Sizeof(nlmsg)]byte)(unsafe.Pointer(&nlmsg))[:])
|
||||
|
||||
17
constants.go
17
constants.go
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
@@ -27,18 +26,14 @@ const (
|
||||
PaddingMultiple = 16
|
||||
)
|
||||
|
||||
/* Implementation specific constants */
|
||||
|
||||
const (
|
||||
QueueOutboundSize = 1024
|
||||
QueueInboundSize = 1024
|
||||
QueueHandshakeSize = 1024
|
||||
MaxSegmentSize = (1 << 16) - 1 // largest possible UDP datagram
|
||||
MinMessageSize = MessageKeepaliveSize // minimum size of transport message (keepalive)
|
||||
MaxMessageSize = MaxSegmentSize // maximum size of transport message
|
||||
MaxContentSize = MaxSegmentSize - MessageTransportSize // maximum size of transport message content
|
||||
MinMessageSize = MessageKeepaliveSize // minimum size of transport message (keepalive)
|
||||
MaxMessageSize = MaxSegmentSize // maximum size of transport message
|
||||
MaxContentSize = MaxSegmentSize - MessageTransportSize // maximum size of transport message content
|
||||
)
|
||||
|
||||
/* Implementation constants */
|
||||
|
||||
const (
|
||||
UnderLoadQueueSize = QueueHandshakeSize / 8
|
||||
UnderLoadAfterTime = time.Second // how long does the device remain under load after detected
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"./xchacha20poly1305"
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"git.zx2c4.com/wireguard-go/xchacha20poly1305"
|
||||
"golang.org/x/crypto/blake2s"
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
"sync"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
50
device.go
50
device.go
@@ -1,13 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"./ratelimiter"
|
||||
"git.zx2c4.com/wireguard-go/ratelimiter"
|
||||
"git.zx2c4.com/wireguard-go/tun"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -35,10 +35,12 @@ type Device struct {
|
||||
}
|
||||
|
||||
net struct {
|
||||
mutex sync.RWMutex
|
||||
bind Bind // bind interface
|
||||
port uint16 // listening port
|
||||
fwmark uint32 // mark value (0 = disabled)
|
||||
starting sync.WaitGroup
|
||||
stopping sync.WaitGroup
|
||||
mutex sync.RWMutex
|
||||
bind Bind // bind interface
|
||||
port uint16 // listening port
|
||||
fwmark uint32 // mark value (0 = disabled)
|
||||
}
|
||||
|
||||
staticIdentity struct {
|
||||
@@ -64,7 +66,12 @@ type Device struct {
|
||||
}
|
||||
|
||||
pool struct {
|
||||
messageBuffers sync.Pool
|
||||
messageBufferPool *sync.Pool
|
||||
messageBufferReuseChan chan *[MaxMessageSize]byte
|
||||
inboundElementPool *sync.Pool
|
||||
inboundElementReuseChan chan *QueueInboundElement
|
||||
outboundElementPool *sync.Pool
|
||||
outboundElementReuseChan chan *QueueOutboundElement
|
||||
}
|
||||
|
||||
queue struct {
|
||||
@@ -78,7 +85,7 @@ type Device struct {
|
||||
}
|
||||
|
||||
tun struct {
|
||||
device TUNDevice
|
||||
device tun.TUNDevice
|
||||
mtu int32
|
||||
}
|
||||
}
|
||||
@@ -162,16 +169,12 @@ func (device *Device) Up() {
|
||||
return
|
||||
}
|
||||
|
||||
device.state.mutex.Lock()
|
||||
device.isUp.Set(true)
|
||||
device.state.mutex.Unlock()
|
||||
deviceUpdateState(device)
|
||||
}
|
||||
|
||||
func (device *Device) Down() {
|
||||
device.state.mutex.Lock()
|
||||
device.isUp.Set(false)
|
||||
device.state.mutex.Unlock()
|
||||
deviceUpdateState(device)
|
||||
}
|
||||
|
||||
@@ -244,15 +247,7 @@ func (device *Device) SetPrivateKey(sk NoisePrivateKey) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (device *Device) GetMessageBuffer() *[MaxMessageSize]byte {
|
||||
return device.pool.messageBuffers.Get().(*[MaxMessageSize]byte)
|
||||
}
|
||||
|
||||
func (device *Device) PutMessageBuffer(msg *[MaxMessageSize]byte) {
|
||||
device.pool.messageBuffers.Put(msg)
|
||||
}
|
||||
|
||||
func NewDevice(tun TUNDevice, logger *Logger) *Device {
|
||||
func NewDevice(tunDevice tun.TUNDevice, logger *Logger) *Device {
|
||||
device := new(Device)
|
||||
|
||||
device.isUp.Set(false)
|
||||
@@ -260,7 +255,7 @@ func NewDevice(tun TUNDevice, logger *Logger) *Device {
|
||||
|
||||
device.log = logger
|
||||
|
||||
device.tun.device = tun
|
||||
device.tun.device = tunDevice
|
||||
mtu, err := device.tun.device.MTU()
|
||||
if err != nil {
|
||||
logger.Error.Println("Trouble determining MTU, assuming default:", err)
|
||||
@@ -276,11 +271,7 @@ func NewDevice(tun TUNDevice, logger *Logger) *Device {
|
||||
device.indexTable.Init()
|
||||
device.allowedips.Reset()
|
||||
|
||||
device.pool.messageBuffers = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new([MaxMessageSize]byte)
|
||||
},
|
||||
}
|
||||
device.PopulatePools()
|
||||
|
||||
// create queues
|
||||
|
||||
@@ -386,10 +377,11 @@ func (device *Device) Close() {
|
||||
|
||||
close(device.signals.stop)
|
||||
|
||||
device.RemoveAllPeers()
|
||||
|
||||
device.state.stopping.Wait()
|
||||
device.FlushPacketQueues()
|
||||
|
||||
device.RemoveAllPeers()
|
||||
device.rate.limiter.Close()
|
||||
|
||||
device.state.changing.Set(false)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
@@ -26,8 +25,8 @@ func TestDevice(t *testing.T) {
|
||||
t.Error("failed to create tun:", err.Error())
|
||||
}
|
||||
|
||||
println(tun1)
|
||||
println(tun2)
|
||||
_ = tun1
|
||||
_ = tun2
|
||||
|
||||
// prepare endpoints
|
||||
|
||||
@@ -41,8 +40,8 @@ func TestDevice(t *testing.T) {
|
||||
t.Error("failed to create endpoint:", err.Error())
|
||||
}
|
||||
|
||||
println(end1)
|
||||
println(end2)
|
||||
_ = end1
|
||||
_ = end2
|
||||
|
||||
// create binds
|
||||
|
||||
|
||||
15
donotuseon_linux.go
Normal file
15
donotuseon_linux.go
Normal file
@@ -0,0 +1,15 @@
|
||||
// +build !android
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
const DoNotUseThisProgramOnLinux = UseTheKernelModuleInstead
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Do not use this on Linux. Instead use the kernel module.
|
||||
// See wireguard.com/install for more information.
|
||||
// --------------------------------------------------------
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "# This was generated by ./generate-vendor.sh" > Gopkg.lock
|
||||
echo "# This was generated by ./generate-vendor.sh" > Gopkg.toml
|
||||
|
||||
while read -r package; do
|
||||
cat >> Gopkg.lock <<-_EOF
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "$package"
|
||||
revision = "$(< "$GOPATH/src/$package/.git/refs/heads/master")"
|
||||
|
||||
_EOF
|
||||
cat >> Gopkg.toml <<-_EOF
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "$package"
|
||||
|
||||
_EOF
|
||||
done < <(sed -n 's/.*"\(golang.org\/x\/[^/]\+\)\/\?.*".*/\1/p' *.go */*.go | sort | uniq)
|
||||
7
go.mod
Normal file
7
go.mod
Normal file
@@ -0,0 +1,7 @@
|
||||
module git.zx2c4.com/wireguard-go
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4
|
||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58
|
||||
golang.org/x/sys v0.0.0-20181005133103-4497e2df6f9e
|
||||
)
|
||||
6
go.sum
Normal file
6
go.sum
Normal file
@@ -0,0 +1,6 @@
|
||||
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4 h1:Vk3wNqEZwyGyei9yq5ekj7frek2u7HUfffJ1/opblzc=
|
||||
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58 h1:otZG8yDCO4LVps5+9bxOeNiCvgmOyt96J3roHTYs7oE=
|
||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/sys v0.0.0-20181005133103-4497e2df6f9e h1:EfdBzeKbFSvOjoIqSZcfS8wp0FBLokGBEs9lz1OtSg0=
|
||||
golang.org/x/sys v0.0.0-20181005133103-4497e2df6f9e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1,13 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"git.zx2c4.com/wireguard-go/tun"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
@@ -19,7 +20,7 @@ type DummyTUN struct {
|
||||
name string
|
||||
mtu int
|
||||
packets chan []byte
|
||||
events chan TUNEvent
|
||||
events chan tun.TUNEvent
|
||||
}
|
||||
|
||||
func (tun *DummyTUN) File() *os.File {
|
||||
@@ -40,23 +41,29 @@ func (tun *DummyTUN) Write(d []byte, offset int) (int, error) {
|
||||
}
|
||||
|
||||
func (tun *DummyTUN) Close() error {
|
||||
close(tun.events)
|
||||
close(tun.packets)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *DummyTUN) Events() chan TUNEvent {
|
||||
func (tun *DummyTUN) Events() chan tun.TUNEvent {
|
||||
return tun.events
|
||||
}
|
||||
|
||||
func (tun *DummyTUN) Read(d []byte, offset int) (int, error) {
|
||||
t := <-tun.packets
|
||||
t, ok := <-tun.packets
|
||||
if !ok {
|
||||
return 0, errors.New("device closed")
|
||||
}
|
||||
copy(d[offset:], t)
|
||||
return len(t), nil
|
||||
}
|
||||
|
||||
func CreateDummyTUN(name string) (TUNDevice, error) {
|
||||
func CreateDummyTUN(name string) (tun.TUNDevice, error) {
|
||||
var dummy DummyTUN
|
||||
dummy.mtu = 0
|
||||
dummy.packets = make(chan []byte, 100)
|
||||
dummy.events = make(chan tun.TUNEvent, 10)
|
||||
return &dummy, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
3
ip.go
3
ip.go
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"git.zx2c4.com/wireguard-go/replay"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@@ -23,7 +23,7 @@ type Keypair struct {
|
||||
sendNonce uint64
|
||||
send cipher.AEAD
|
||||
receive cipher.AEAD
|
||||
replayFilter ReplayFilter
|
||||
replayFilter replay.ReplayFilter
|
||||
isInitiator bool
|
||||
created time.Time
|
||||
localIndex uint32
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
22
main.go
22
main.go
@@ -1,17 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.zx2c4.com/wireguard-go/tun"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -72,6 +73,11 @@ func warning() {
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) == 2 && os.Args[1] == "--version" {
|
||||
fmt.Printf("wireguard-go v%s\n\nUserspace WireGuard daemon for %s-%s.\nInformation available at https://www.wireguard.com.\nCopyright (C) Jason A. Donenfeld <Jason@zx2c4.com>.\n", WireGuardGoVersion, runtime.GOOS, runtime.GOARCH)
|
||||
return
|
||||
}
|
||||
|
||||
warning()
|
||||
|
||||
// parse arguments
|
||||
@@ -124,10 +130,10 @@ func main() {
|
||||
|
||||
// open TUN device (or use supplied fd)
|
||||
|
||||
tun, err := func() (TUNDevice, error) {
|
||||
tun, err := func() (tun.TUNDevice, error) {
|
||||
tunFdStr := os.Getenv(ENV_WG_TUN_FD)
|
||||
if tunFdStr == "" {
|
||||
return CreateTUN(interfaceName)
|
||||
return tun.CreateTUN(interfaceName, DefaultMTU)
|
||||
}
|
||||
|
||||
// construct tun device from supplied fd
|
||||
@@ -138,7 +144,7 @@ func main() {
|
||||
}
|
||||
|
||||
file := os.NewFile(uintptr(fd), "")
|
||||
return CreateTUNFromFile(file)
|
||||
return tun.CreateTUNFromFile(file, DefaultMTU)
|
||||
}()
|
||||
|
||||
if err == nil {
|
||||
@@ -153,6 +159,8 @@ func main() {
|
||||
fmt.Sprintf("(%s) ", interfaceName),
|
||||
)
|
||||
|
||||
logger.Info.Println("Starting wireguard-go version", WireGuardGoVersion)
|
||||
|
||||
logger.Debug.Println("Debug log enabled")
|
||||
|
||||
if err != nil {
|
||||
@@ -236,7 +244,7 @@ func main() {
|
||||
logger.Info.Println("Device started")
|
||||
|
||||
errs := make(chan error)
|
||||
term := make(chan os.Signal)
|
||||
term := make(chan os.Signal, 1)
|
||||
|
||||
uapi, err := UAPIListen(interfaceName, fileUAPI)
|
||||
if err != nil {
|
||||
@@ -259,7 +267,7 @@ func main() {
|
||||
|
||||
// wait for program to terminate
|
||||
|
||||
signal.Notify(term, os.Kill)
|
||||
signal.Notify(term, syscall.SIGTERM)
|
||||
signal.Notify(term, os.Interrupt)
|
||||
|
||||
select {
|
||||
|
||||
17
misc.go
17
misc.go
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
@@ -41,23 +40,9 @@ func (a *AtomicBool) Set(val bool) {
|
||||
atomic.StoreInt32(&a.flag, flag)
|
||||
}
|
||||
|
||||
/* Integer manipulation */
|
||||
|
||||
func toInt32(n uint32) int32 {
|
||||
mask := uint32(1 << 31)
|
||||
return int32(-(n & mask) + (n & ^mask))
|
||||
}
|
||||
|
||||
func min(a, b uint) uint {
|
||||
if a > b {
|
||||
return b
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func minUint64(a uint64, b uint64) uint64 {
|
||||
if a > b {
|
||||
return b
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2015-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"./tai64n"
|
||||
"errors"
|
||||
"git.zx2c4.com/wireguard-go/tai64n"
|
||||
"golang.org/x/crypto/blake2s"
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
"golang.org/x/crypto/poly1305"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
@@ -58,6 +57,7 @@ func TestNoiseHandshake(t *testing.T) {
|
||||
packet := make([]byte, 0, 256)
|
||||
writer := bytes.NewBuffer(packet)
|
||||
err = binary.Write(writer, binary.LittleEndian, msg1)
|
||||
assertNil(t, err)
|
||||
peer := dev2.ConsumeMessageInitiation(msg1)
|
||||
if peer == nil {
|
||||
t.Fatal("handshake failed at initiation message")
|
||||
|
||||
26
peer.go
26
peer.go
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
@@ -40,9 +39,9 @@ type Peer struct {
|
||||
newHandshake *Timer
|
||||
zeroKeyMaterial *Timer
|
||||
persistentKeepalive *Timer
|
||||
handshakeAttempts uint
|
||||
needAnotherKeepalive bool
|
||||
sentLastMinuteHandshake bool
|
||||
handshakeAttempts uint32
|
||||
needAnotherKeepalive AtomicBool
|
||||
sentLastMinuteHandshake AtomicBool
|
||||
}
|
||||
|
||||
signals struct {
|
||||
@@ -54,7 +53,7 @@ type Peer struct {
|
||||
nonce chan *QueueOutboundElement // nonce / pre-handshake queue
|
||||
outbound chan *QueueOutboundElement // sequential ordering of work
|
||||
inbound chan *QueueInboundElement // sequential ordering of work
|
||||
packetInNonceQueueIsAwaitingKey bool
|
||||
packetInNonceQueueIsAwaitingKey AtomicBool
|
||||
}
|
||||
|
||||
routines struct {
|
||||
@@ -171,7 +170,7 @@ func (peer *Peer) Start() {
|
||||
}
|
||||
|
||||
device := peer.device
|
||||
device.log.Debug.Println(peer, ": Starting...")
|
||||
device.log.Debug.Println(peer, "- Starting...")
|
||||
|
||||
// reset routine state
|
||||
|
||||
@@ -241,7 +240,7 @@ func (peer *Peer) Stop() {
|
||||
peer.routines.mutex.Lock()
|
||||
defer peer.routines.mutex.Unlock()
|
||||
|
||||
peer.device.log.Debug.Println(peer, ": Stopping...")
|
||||
peer.device.log.Debug.Println(peer, "- Stopping...")
|
||||
|
||||
peer.timersStop()
|
||||
|
||||
@@ -258,3 +257,14 @@ func (peer *Peer) Stop() {
|
||||
|
||||
peer.ZeroAndFlushAll()
|
||||
}
|
||||
|
||||
var roamingDisabled bool
|
||||
|
||||
func (peer *Peer) SetEndpointFromPacket(endpoint Endpoint) {
|
||||
if roamingDisabled {
|
||||
return
|
||||
}
|
||||
peer.mutex.Lock()
|
||||
peer.endpoint = endpoint
|
||||
peer.mutex.Unlock()
|
||||
}
|
||||
|
||||
89
pools.go
Normal file
89
pools.go
Normal file
@@ -0,0 +1,89 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import "sync"
|
||||
|
||||
func (device *Device) PopulatePools() {
|
||||
if PreallocatedBuffersPerPool == 0 {
|
||||
device.pool.messageBufferPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new([MaxMessageSize]byte)
|
||||
},
|
||||
}
|
||||
device.pool.inboundElementPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(QueueInboundElement)
|
||||
},
|
||||
}
|
||||
device.pool.outboundElementPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(QueueOutboundElement)
|
||||
},
|
||||
}
|
||||
} else {
|
||||
device.pool.messageBufferReuseChan = make(chan *[MaxMessageSize]byte, PreallocatedBuffersPerPool)
|
||||
for i := 0; i < PreallocatedBuffersPerPool; i += 1 {
|
||||
device.pool.messageBufferReuseChan <- new([MaxMessageSize]byte)
|
||||
}
|
||||
device.pool.inboundElementReuseChan = make(chan *QueueInboundElement, PreallocatedBuffersPerPool)
|
||||
for i := 0; i < PreallocatedBuffersPerPool; i += 1 {
|
||||
device.pool.inboundElementReuseChan <- new(QueueInboundElement)
|
||||
}
|
||||
device.pool.outboundElementReuseChan = make(chan *QueueOutboundElement, PreallocatedBuffersPerPool)
|
||||
for i := 0; i < PreallocatedBuffersPerPool; i += 1 {
|
||||
device.pool.outboundElementReuseChan <- new(QueueOutboundElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (device *Device) GetMessageBuffer() *[MaxMessageSize]byte {
|
||||
if PreallocatedBuffersPerPool == 0 {
|
||||
return device.pool.messageBufferPool.Get().(*[MaxMessageSize]byte)
|
||||
} else {
|
||||
return <-device.pool.messageBufferReuseChan
|
||||
}
|
||||
}
|
||||
|
||||
func (device *Device) PutMessageBuffer(msg *[MaxMessageSize]byte) {
|
||||
if PreallocatedBuffersPerPool == 0 {
|
||||
device.pool.messageBufferPool.Put(msg)
|
||||
} else {
|
||||
device.pool.messageBufferReuseChan <- msg
|
||||
}
|
||||
}
|
||||
|
||||
func (device *Device) GetInboundElement() *QueueInboundElement {
|
||||
if PreallocatedBuffersPerPool == 0 {
|
||||
return device.pool.inboundElementPool.Get().(*QueueInboundElement)
|
||||
} else {
|
||||
return <-device.pool.inboundElementReuseChan
|
||||
}
|
||||
}
|
||||
|
||||
func (device *Device) PutInboundElement(msg *QueueInboundElement) {
|
||||
if PreallocatedBuffersPerPool == 0 {
|
||||
device.pool.inboundElementPool.Put(msg)
|
||||
} else {
|
||||
device.pool.inboundElementReuseChan <- msg
|
||||
}
|
||||
}
|
||||
|
||||
func (device *Device) GetOutboundElement() *QueueOutboundElement {
|
||||
if PreallocatedBuffersPerPool == 0 {
|
||||
return device.pool.outboundElementPool.Get().(*QueueOutboundElement)
|
||||
} else {
|
||||
return <-device.pool.outboundElementReuseChan
|
||||
}
|
||||
}
|
||||
|
||||
func (device *Device) PutOutboundElement(msg *QueueOutboundElement) {
|
||||
if PreallocatedBuffersPerPool == 0 {
|
||||
device.pool.outboundElementPool.Put(msg)
|
||||
} else {
|
||||
device.pool.outboundElementReuseChan <- msg
|
||||
}
|
||||
}
|
||||
16
queueconstants.go
Normal file
16
queueconstants.go
Normal file
@@ -0,0 +1,16 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
/* Implementation specific constants */
|
||||
|
||||
const (
|
||||
QueueOutboundSize = 1024
|
||||
QueueInboundSize = 1024
|
||||
QueueHandshakeSize = 1024
|
||||
MaxSegmentSize = (1 << 16) - 1 // largest possible UDP datagram
|
||||
PreallocatedBuffersPerPool = 0 // Disable and allow for infinite memory growth
|
||||
)
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package ratelimiter
|
||||
@@ -27,7 +27,7 @@ type RatelimiterEntry struct {
|
||||
|
||||
type Ratelimiter struct {
|
||||
mutex sync.RWMutex
|
||||
stop chan struct{}
|
||||
stopReset chan struct{}
|
||||
tableIPv4 map[[net.IPv4len]byte]*RatelimiterEntry
|
||||
tableIPv6 map[[net.IPv6len]byte]*RatelimiterEntry
|
||||
}
|
||||
@@ -36,8 +36,8 @@ func (rate *Ratelimiter) Close() {
|
||||
rate.mutex.Lock()
|
||||
defer rate.mutex.Unlock()
|
||||
|
||||
if rate.stop != nil {
|
||||
close(rate.stop)
|
||||
if rate.stopReset != nil {
|
||||
close(rate.stopReset)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,11 +47,11 @@ func (rate *Ratelimiter) Init() {
|
||||
|
||||
// stop any ongoing garbage collection routine
|
||||
|
||||
if rate.stop != nil {
|
||||
close(rate.stop)
|
||||
if rate.stopReset != nil {
|
||||
close(rate.stopReset)
|
||||
}
|
||||
|
||||
rate.stop = make(chan struct{})
|
||||
rate.stopReset = make(chan struct{})
|
||||
rate.tableIPv4 = make(map[[net.IPv4len]byte]*RatelimiterEntry)
|
||||
rate.tableIPv6 = make(map[[net.IPv6len]byte]*RatelimiterEntry)
|
||||
|
||||
@@ -59,11 +59,16 @@ func (rate *Ratelimiter) Init() {
|
||||
|
||||
go func() {
|
||||
ticker := time.NewTicker(time.Second)
|
||||
ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-rate.stop:
|
||||
case _, ok := <-rate.stopReset:
|
||||
ticker.Stop()
|
||||
return
|
||||
if ok {
|
||||
ticker = time.NewTicker(time.Second)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
case <-ticker.C:
|
||||
func() {
|
||||
rate.mutex.Lock()
|
||||
@@ -84,6 +89,10 @@ func (rate *Ratelimiter) Init() {
|
||||
}
|
||||
entry.mutex.Unlock()
|
||||
}
|
||||
|
||||
if len(rate.tableIPv4) == 0 && len(rate.tableIPv6) == 0 {
|
||||
ticker.Stop()
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
@@ -121,8 +130,14 @@ func (rate *Ratelimiter) Allow(ip net.IP) bool {
|
||||
rate.mutex.Lock()
|
||||
if IPv4 != nil {
|
||||
rate.tableIPv4[keyIPv4] = entry
|
||||
if len(rate.tableIPv4) == 1 && len(rate.tableIPv6) == 0 {
|
||||
rate.stopReset <- struct{}{}
|
||||
}
|
||||
} else {
|
||||
rate.tableIPv6[keyIPv6] = entry
|
||||
if len(rate.tableIPv6) == 1 && len(rate.tableIPv4) == 0 {
|
||||
rate.stopReset <- struct{}{}
|
||||
}
|
||||
}
|
||||
rate.mutex.Unlock()
|
||||
return true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package ratelimiter
|
||||
|
||||
176
receive.go
176
receive.go
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
@@ -44,59 +43,29 @@ func (elem *QueueInboundElement) IsDropped() bool {
|
||||
return atomic.LoadInt32(&elem.dropped) == AtomicTrue
|
||||
}
|
||||
|
||||
func (device *Device) addToInboundQueue(
|
||||
queue chan *QueueInboundElement,
|
||||
element *QueueInboundElement,
|
||||
) {
|
||||
for {
|
||||
func (device *Device) addToInboundAndDecryptionQueues(inboundQueue chan *QueueInboundElement, decryptionQueue chan *QueueInboundElement, element *QueueInboundElement) bool {
|
||||
select {
|
||||
case inboundQueue <- element:
|
||||
select {
|
||||
case queue <- element:
|
||||
return
|
||||
case decryptionQueue <- element:
|
||||
return true
|
||||
default:
|
||||
select {
|
||||
case old := <-queue:
|
||||
old.Drop()
|
||||
default:
|
||||
}
|
||||
element.Drop()
|
||||
element.mutex.Unlock()
|
||||
return false
|
||||
}
|
||||
default:
|
||||
device.PutInboundElement(element)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (device *Device) addToDecryptionQueue(
|
||||
queue chan *QueueInboundElement,
|
||||
element *QueueInboundElement,
|
||||
) {
|
||||
for {
|
||||
select {
|
||||
case queue <- element:
|
||||
return
|
||||
default:
|
||||
select {
|
||||
case old := <-queue:
|
||||
// drop & release to potential consumer
|
||||
old.Drop()
|
||||
old.mutex.Unlock()
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (device *Device) addToHandshakeQueue(
|
||||
queue chan QueueHandshakeElement,
|
||||
element QueueHandshakeElement,
|
||||
) {
|
||||
for {
|
||||
select {
|
||||
case queue <- element:
|
||||
return
|
||||
default:
|
||||
select {
|
||||
case elem := <-queue:
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
default:
|
||||
}
|
||||
}
|
||||
func (device *Device) addToHandshakeQueue(queue chan QueueHandshakeElement, element QueueHandshakeElement) bool {
|
||||
select {
|
||||
case queue <- element:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,12 +74,12 @@ func (device *Device) addToHandshakeQueue(
|
||||
* NOTE: Not thread safe, but called by sequential receiver!
|
||||
*/
|
||||
func (peer *Peer) keepKeyFreshReceiving() {
|
||||
if peer.timers.sentLastMinuteHandshake {
|
||||
if peer.timers.sentLastMinuteHandshake.Get() {
|
||||
return
|
||||
}
|
||||
keypair := peer.keypairs.Current()
|
||||
if keypair != nil && keypair.isInitiator && time.Now().Sub(keypair.created) > (RejectAfterTime-KeepaliveTimeout-RekeyTimeout) {
|
||||
peer.timers.sentLastMinuteHandshake = true
|
||||
peer.timers.sentLastMinuteHandshake.Set(true)
|
||||
peer.SendHandshakeInitiation(false)
|
||||
}
|
||||
}
|
||||
@@ -125,11 +94,11 @@ func (device *Device) RoutineReceiveIncoming(IP int, bind Bind) {
|
||||
logDebug := device.log.Debug
|
||||
defer func() {
|
||||
logDebug.Println("Routine: receive incoming IPv" + strconv.Itoa(IP) + " - stopped")
|
||||
device.state.stopping.Done()
|
||||
device.net.stopping.Done()
|
||||
}()
|
||||
|
||||
logDebug.Println("Routine: receive incoming IPv" + strconv.Itoa(IP) + " - starting")
|
||||
device.state.starting.Done()
|
||||
device.net.starting.Done()
|
||||
|
||||
// receive datagrams until conn is closed
|
||||
|
||||
@@ -155,6 +124,7 @@ func (device *Device) RoutineReceiveIncoming(IP int, bind Bind) {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
device.PutMessageBuffer(buffer)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -177,7 +147,7 @@ func (device *Device) RoutineReceiveIncoming(IP int, bind Bind) {
|
||||
|
||||
// check size
|
||||
|
||||
if len(packet) < MessageTransportType {
|
||||
if len(packet) < MessageTransportSize {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -199,23 +169,23 @@ func (device *Device) RoutineReceiveIncoming(IP int, bind Bind) {
|
||||
}
|
||||
|
||||
// create work element
|
||||
|
||||
peer := value.peer
|
||||
elem := &QueueInboundElement{
|
||||
packet: packet,
|
||||
buffer: buffer,
|
||||
keypair: keypair,
|
||||
dropped: AtomicFalse,
|
||||
endpoint: endpoint,
|
||||
}
|
||||
elem := device.GetInboundElement()
|
||||
elem.packet = packet
|
||||
elem.buffer = buffer
|
||||
elem.keypair = keypair
|
||||
elem.dropped = AtomicFalse
|
||||
elem.endpoint = endpoint
|
||||
elem.counter = 0
|
||||
elem.mutex = sync.Mutex{}
|
||||
elem.mutex.Lock()
|
||||
|
||||
// add to decryption queues
|
||||
|
||||
if peer.isRunning.Get() {
|
||||
device.addToDecryptionQueue(device.queue.decryption, elem)
|
||||
device.addToInboundQueue(peer.queue.inbound, elem)
|
||||
buffer = device.GetMessageBuffer()
|
||||
if device.addToInboundAndDecryptionQueues(peer.queue.inbound, device.queue.decryption, elem) {
|
||||
buffer = device.GetMessageBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
continue
|
||||
@@ -236,7 +206,7 @@ func (device *Device) RoutineReceiveIncoming(IP int, bind Bind) {
|
||||
}
|
||||
|
||||
if okay {
|
||||
device.addToHandshakeQueue(
|
||||
if (device.addToHandshakeQueue(
|
||||
device.queue.handshake,
|
||||
QueueHandshakeElement{
|
||||
msgType: msgType,
|
||||
@@ -244,8 +214,9 @@ func (device *Device) RoutineReceiveIncoming(IP int, bind Bind) {
|
||||
packet: packet,
|
||||
endpoint: endpoint,
|
||||
},
|
||||
)
|
||||
buffer = device.GetMessageBuffer()
|
||||
)) {
|
||||
buffer = device.GetMessageBuffer()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -308,6 +279,7 @@ func (device *Device) RoutineDecryption() {
|
||||
)
|
||||
if err != nil {
|
||||
elem.Drop()
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
}
|
||||
elem.mutex.Unlock()
|
||||
}
|
||||
@@ -322,18 +294,26 @@ func (device *Device) RoutineHandshake() {
|
||||
logError := device.log.Error
|
||||
logDebug := device.log.Debug
|
||||
|
||||
var elem QueueHandshakeElement
|
||||
var ok bool
|
||||
|
||||
defer func() {
|
||||
logDebug.Println("Routine: handshake worker - stopped")
|
||||
device.state.stopping.Done()
|
||||
if elem.buffer != nil {
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
}
|
||||
}()
|
||||
|
||||
logDebug.Println("Routine: handshake worker - started")
|
||||
device.state.starting.Done()
|
||||
|
||||
var elem QueueHandshakeElement
|
||||
var ok bool
|
||||
|
||||
for {
|
||||
if elem.buffer != nil {
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
elem.buffer = nil
|
||||
}
|
||||
|
||||
select {
|
||||
case elem, ok = <-device.queue.handshake:
|
||||
case <-device.signals.stop:
|
||||
@@ -440,12 +420,9 @@ func (device *Device) RoutineHandshake() {
|
||||
peer.timersAnyAuthenticatedPacketReceived()
|
||||
|
||||
// update endpoint
|
||||
peer.SetEndpointFromPacket(elem.endpoint)
|
||||
|
||||
peer.mutex.Lock()
|
||||
peer.endpoint = elem.endpoint
|
||||
peer.mutex.Unlock()
|
||||
|
||||
logDebug.Println(peer, ": Received handshake initiation")
|
||||
logDebug.Println(peer, "- Received handshake initiation")
|
||||
|
||||
peer.SendHandshakeResponse()
|
||||
|
||||
@@ -466,19 +443,16 @@ func (device *Device) RoutineHandshake() {
|
||||
peer := device.ConsumeMessageResponse(&msg)
|
||||
if peer == nil {
|
||||
logInfo.Println(
|
||||
"Recieved invalid response message from",
|
||||
"Received invalid response message from",
|
||||
elem.endpoint.DstToString(),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
// update endpoint
|
||||
peer.SetEndpointFromPacket(elem.endpoint)
|
||||
|
||||
peer.mutex.Lock()
|
||||
peer.endpoint = elem.endpoint
|
||||
peer.mutex.Unlock()
|
||||
|
||||
logDebug.Println(peer, ": Received handshake response")
|
||||
logDebug.Println(peer, "- Received handshake response")
|
||||
|
||||
// update timers
|
||||
|
||||
@@ -490,7 +464,7 @@ func (device *Device) RoutineHandshake() {
|
||||
err = peer.BeginSymmetricSession()
|
||||
|
||||
if err != nil {
|
||||
logError.Println(peer, ": Failed to derive keypair:", err)
|
||||
logError.Println(peer, "- Failed to derive keypair:", err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -512,23 +486,39 @@ func (peer *Peer) RoutineSequentialReceiver() {
|
||||
logError := device.log.Error
|
||||
logDebug := device.log.Debug
|
||||
|
||||
var elem *QueueInboundElement
|
||||
var ok bool
|
||||
|
||||
defer func() {
|
||||
logDebug.Println(peer, ": Routine: sequential receiver - stopped")
|
||||
logDebug.Println(peer, "- Routine: sequential receiver - stopped")
|
||||
peer.routines.stopping.Done()
|
||||
if elem != nil {
|
||||
if !elem.IsDropped() {
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
}
|
||||
device.PutInboundElement(elem)
|
||||
}
|
||||
}()
|
||||
|
||||
logDebug.Println(peer, ": Routine: sequential receiver - started")
|
||||
logDebug.Println(peer, "- Routine: sequential receiver - started")
|
||||
|
||||
peer.routines.starting.Done()
|
||||
|
||||
for {
|
||||
if elem != nil {
|
||||
if !elem.IsDropped() {
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
}
|
||||
device.PutInboundElement(elem)
|
||||
elem = nil
|
||||
}
|
||||
|
||||
select {
|
||||
|
||||
case <-peer.routines.stop:
|
||||
return
|
||||
|
||||
case elem, ok := <-peer.queue.inbound:
|
||||
case elem, ok = <-peer.queue.inbound:
|
||||
|
||||
if !ok {
|
||||
return
|
||||
@@ -544,15 +534,12 @@ func (peer *Peer) RoutineSequentialReceiver() {
|
||||
|
||||
// check for replay
|
||||
|
||||
if !elem.keypair.replayFilter.ValidateCounter(elem.counter) {
|
||||
if !elem.keypair.replayFilter.ValidateCounter(elem.counter, RejectAfterMessages) {
|
||||
continue
|
||||
}
|
||||
|
||||
// update endpoint
|
||||
|
||||
peer.mutex.Lock()
|
||||
peer.endpoint = elem.endpoint
|
||||
peer.mutex.Unlock()
|
||||
peer.SetEndpointFromPacket(elem.endpoint)
|
||||
|
||||
// check if using new keypair
|
||||
if peer.ReceivedWithKeypair(elem.keypair) {
|
||||
@@ -570,7 +557,7 @@ func (peer *Peer) RoutineSequentialReceiver() {
|
||||
// check for keepalive
|
||||
|
||||
if len(elem.packet) == 0 {
|
||||
logDebug.Println(peer, ": Receiving keepalive packet")
|
||||
logDebug.Println(peer, "- Receiving keepalive packet")
|
||||
continue
|
||||
}
|
||||
peer.timersDataReceived()
|
||||
@@ -642,10 +629,7 @@ func (peer *Peer) RoutineSequentialReceiver() {
|
||||
|
||||
offset := MessageTransportOffsetContent
|
||||
atomic.AddUint64(&peer.stats.rxBytes, uint64(len(elem.packet)))
|
||||
_, err := device.tun.device.Write(
|
||||
elem.buffer[:offset+len(elem.packet)],
|
||||
offset)
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
_, err := device.tun.device.Write(elem.buffer[:offset+len(elem.packet)], offset)
|
||||
if err != nil {
|
||||
logError.Println("Failed to write packet to TUN device:", err)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
||||
package replay
|
||||
|
||||
/* Implementation of RFC6479
|
||||
* https://tools.ietf.org/html/rfc6479
|
||||
@@ -32,6 +29,13 @@ const (
|
||||
BacktrackWords = CounterBitsTotal / _WordSize
|
||||
)
|
||||
|
||||
func minUint64(a uint64, b uint64) uint64 {
|
||||
if a > b {
|
||||
return b
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
type ReplayFilter struct {
|
||||
counter uint64
|
||||
backtrack [BacktrackWords]uintptr
|
||||
@@ -42,8 +46,8 @@ func (filter *ReplayFilter) Init() {
|
||||
filter.backtrack[0] = 0
|
||||
}
|
||||
|
||||
func (filter *ReplayFilter) ValidateCounter(counter uint64) bool {
|
||||
if counter >= RejectAfterMessages {
|
||||
func (filter *ReplayFilter) ValidateCounter(counter uint64, limit uint64) bool {
|
||||
if counter >= limit {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package replay
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -15,6 +14,8 @@ import (
|
||||
*
|
||||
*/
|
||||
|
||||
const RejectAfterMessages = (1 << 64) - (1 << 4) - 1
|
||||
|
||||
func TestReplay(t *testing.T) {
|
||||
var filter ReplayFilter
|
||||
|
||||
@@ -23,7 +24,7 @@ func TestReplay(t *testing.T) {
|
||||
testNumber := 0
|
||||
T := func(n uint64, v bool) {
|
||||
testNumber++
|
||||
if filter.ValidateCounter(n) != v {
|
||||
if filter.ValidateCounter(n, RejectAfterMessages) != v {
|
||||
t.Fatal("Test", testNumber, "failed", n, v)
|
||||
}
|
||||
}
|
||||
24
rwcancel/fdset_default.go
Normal file
24
rwcancel/fdset_default.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// +build !freebsd
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package rwcancel
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
type fdSet struct {
|
||||
fdset unix.FdSet
|
||||
}
|
||||
|
||||
func (fdset *fdSet) set(i int) {
|
||||
bits := 32 << (^uint(0) >> 63)
|
||||
fdset.fdset.Bits[i/bits] |= 1 << uint(i%bits)
|
||||
}
|
||||
|
||||
func (fdset *fdSet) check(i int) bool {
|
||||
bits := 32 << (^uint(0) >> 63)
|
||||
return (fdset.fdset.Bits[i/bits] & (1 << uint(i%bits))) != 0
|
||||
}
|
||||
22
rwcancel/fdset_freebsd.go
Normal file
22
rwcancel/fdset_freebsd.go
Normal file
@@ -0,0 +1,22 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package rwcancel
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
type fdSet struct {
|
||||
fdset unix.FdSet
|
||||
}
|
||||
|
||||
func (fdset *fdSet) set(i int) {
|
||||
bits := 32 << (^uint(0) >> 63)
|
||||
fdset.fdset.X__fds_bits[i/bits] |= 1 << uint(i%bits)
|
||||
}
|
||||
|
||||
func (fdset *fdSet) check(i int) bool {
|
||||
bits := 32 << (^uint(0) >> 63)
|
||||
return (fdset.fdset.X__fds_bits[i/bits] & (1 << uint(i%bits))) != 0
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package rwcancel
|
||||
@@ -12,26 +12,6 @@ import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type RWCancel struct {
|
||||
fd int
|
||||
closingReader *os.File
|
||||
closingWriter *os.File
|
||||
}
|
||||
|
||||
type fdSet struct {
|
||||
fdset unix.FdSet
|
||||
}
|
||||
|
||||
func (fdset *fdSet) set(i int) {
|
||||
bits := 32 << (^uint(0) >> 63)
|
||||
fdset.fdset.Bits[i/bits] |= 1 << uint(i%bits)
|
||||
}
|
||||
|
||||
func (fdset *fdSet) check(i int) bool {
|
||||
bits := 32 << (^uint(0) >> 63)
|
||||
return (fdset.fdset.Bits[i/bits] & (1 << uint(i%bits))) != 0
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
@@ -39,6 +19,12 @@ func max(a, b int) int {
|
||||
return b
|
||||
}
|
||||
|
||||
type RWCancel struct {
|
||||
fd int
|
||||
closingReader *os.File
|
||||
closingWriter *os.File
|
||||
}
|
||||
|
||||
func NewRWCancel(fd int) (*RWCancel, error) {
|
||||
err := unix.SetNonblock(fd, true)
|
||||
if err != nil {
|
||||
@@ -54,15 +40,16 @@ func NewRWCancel(fd int) (*RWCancel, error) {
|
||||
return &rwcancel, nil
|
||||
}
|
||||
|
||||
/* https://golang.org/src/crypto/rand/eagain.go */
|
||||
func ErrorIsEAGAIN(err error) bool {
|
||||
func RetryAfterError(err error) bool {
|
||||
if pe, ok := err.(*os.PathError); ok {
|
||||
if errno, ok := pe.Err.(syscall.Errno); ok && errno == syscall.EAGAIN {
|
||||
err = pe.Err
|
||||
}
|
||||
if errno, ok := err.(syscall.Errno); ok {
|
||||
switch errno {
|
||||
case syscall.EAGAIN, syscall.EINTR:
|
||||
return true
|
||||
}
|
||||
}
|
||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.EAGAIN {
|
||||
return true
|
||||
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -100,7 +87,7 @@ func (rw *RWCancel) ReadyWrite() bool {
|
||||
func (rw *RWCancel) Read(p []byte) (n int, err error) {
|
||||
for {
|
||||
n, err := unix.Read(rw.fd, p)
|
||||
if err == nil || !ErrorIsEAGAIN(err) {
|
||||
if err == nil || !RetryAfterError(err) {
|
||||
return n, err
|
||||
}
|
||||
if !rw.ReadyRead() {
|
||||
@@ -112,7 +99,7 @@ func (rw *RWCancel) Read(p []byte) (n int, err error) {
|
||||
func (rw *RWCancel) Write(p []byte) (n int, err error) {
|
||||
for {
|
||||
n, err := unix.Write(rw.fd, p)
|
||||
if err == nil || !ErrorIsEAGAIN(err) {
|
||||
if err == nil || !RetryAfterError(err) {
|
||||
return n, err
|
||||
}
|
||||
if !rw.ReadyWrite() {
|
||||
@@ -1,6 +1,8 @@
|
||||
// +build !linux
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package rwcancel
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package rwcancel
|
||||
|
||||
180
send.go
180
send.go
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
@@ -53,10 +52,14 @@ type QueueOutboundElement struct {
|
||||
}
|
||||
|
||||
func (device *Device) NewOutboundElement() *QueueOutboundElement {
|
||||
return &QueueOutboundElement{
|
||||
dropped: AtomicFalse,
|
||||
buffer: device.pool.messageBuffers.Get().(*[MaxMessageSize]byte),
|
||||
}
|
||||
elem := device.GetOutboundElement()
|
||||
elem.dropped = AtomicFalse
|
||||
elem.buffer = device.GetMessageBuffer()
|
||||
elem.mutex = sync.Mutex{}
|
||||
elem.nonce = 0
|
||||
elem.keypair = nil
|
||||
elem.peer = nil
|
||||
return elem
|
||||
}
|
||||
|
||||
func (elem *QueueOutboundElement) Drop() {
|
||||
@@ -67,10 +70,7 @@ func (elem *QueueOutboundElement) IsDropped() bool {
|
||||
return atomic.LoadInt32(&elem.dropped) == AtomicTrue
|
||||
}
|
||||
|
||||
func addToOutboundQueue(
|
||||
queue chan *QueueOutboundElement,
|
||||
element *QueueOutboundElement,
|
||||
) {
|
||||
func addToNonceQueue(queue chan *QueueOutboundElement, element *QueueOutboundElement, device *Device) {
|
||||
for {
|
||||
select {
|
||||
case queue <- element:
|
||||
@@ -78,53 +78,53 @@ func addToOutboundQueue(
|
||||
default:
|
||||
select {
|
||||
case old := <-queue:
|
||||
old.Drop()
|
||||
device.PutMessageBuffer(old.buffer)
|
||||
device.PutOutboundElement(old)
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addToEncryptionQueue(
|
||||
queue chan *QueueOutboundElement,
|
||||
element *QueueOutboundElement,
|
||||
) {
|
||||
for {
|
||||
func addToOutboundAndEncryptionQueues(outboundQueue chan *QueueOutboundElement, encryptionQueue chan *QueueOutboundElement, element *QueueOutboundElement) {
|
||||
select {
|
||||
case outboundQueue <- element:
|
||||
select {
|
||||
case queue <- element:
|
||||
case encryptionQueue <- element:
|
||||
return
|
||||
default:
|
||||
select {
|
||||
case old := <-queue:
|
||||
// drop & release to potential consumer
|
||||
old.Drop()
|
||||
old.mutex.Unlock()
|
||||
default:
|
||||
}
|
||||
element.Drop()
|
||||
element.peer.device.PutMessageBuffer(element.buffer)
|
||||
element.mutex.Unlock()
|
||||
}
|
||||
default:
|
||||
element.peer.device.PutMessageBuffer(element.buffer)
|
||||
element.peer.device.PutOutboundElement(element)
|
||||
}
|
||||
}
|
||||
|
||||
/* Queues a keepalive if no packets are queued for peer
|
||||
*/
|
||||
func (peer *Peer) SendKeepalive() bool {
|
||||
if len(peer.queue.nonce) != 0 || peer.queue.packetInNonceQueueIsAwaitingKey || !peer.isRunning.Get() {
|
||||
if len(peer.queue.nonce) != 0 || peer.queue.packetInNonceQueueIsAwaitingKey.Get() || !peer.isRunning.Get() {
|
||||
return false
|
||||
}
|
||||
elem := peer.device.NewOutboundElement()
|
||||
elem.packet = nil
|
||||
select {
|
||||
case peer.queue.nonce <- elem:
|
||||
peer.device.log.Debug.Println(peer, ": Sending keepalive packet")
|
||||
peer.device.log.Debug.Println(peer, "- Sending keepalive packet")
|
||||
return true
|
||||
default:
|
||||
peer.device.PutMessageBuffer(elem.buffer)
|
||||
peer.device.PutOutboundElement(elem)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (peer *Peer) SendHandshakeInitiation(isRetry bool) error {
|
||||
if !isRetry {
|
||||
peer.timers.handshakeAttempts = 0
|
||||
atomic.StoreUint32(&peer.timers.handshakeAttempts, 0)
|
||||
}
|
||||
|
||||
peer.handshake.mutex.RLock()
|
||||
@@ -142,11 +142,11 @@ func (peer *Peer) SendHandshakeInitiation(isRetry bool) error {
|
||||
peer.handshake.lastSentHandshake = time.Now()
|
||||
peer.handshake.mutex.Unlock()
|
||||
|
||||
peer.device.log.Debug.Println(peer, ": Sending handshake initiation")
|
||||
peer.device.log.Debug.Println(peer, "- Sending handshake initiation")
|
||||
|
||||
msg, err := peer.device.CreateMessageInitiation(peer)
|
||||
if err != nil {
|
||||
peer.device.log.Error.Println(peer, ": Failed to create initiation message:", err)
|
||||
peer.device.log.Error.Println(peer, "- Failed to create initiation message:", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ func (peer *Peer) SendHandshakeInitiation(isRetry bool) error {
|
||||
|
||||
err = peer.SendBuffer(packet)
|
||||
if err != nil {
|
||||
peer.device.log.Error.Println(peer, ": Failed to send handshake initiation", err)
|
||||
peer.device.log.Error.Println(peer, "- Failed to send handshake initiation", err)
|
||||
}
|
||||
peer.timersHandshakeInitiated()
|
||||
|
||||
@@ -173,11 +173,11 @@ func (peer *Peer) SendHandshakeResponse() error {
|
||||
peer.handshake.lastSentHandshake = time.Now()
|
||||
peer.handshake.mutex.Unlock()
|
||||
|
||||
peer.device.log.Debug.Println(peer, ": Sending handshake response")
|
||||
peer.device.log.Debug.Println(peer, "- Sending handshake response")
|
||||
|
||||
response, err := peer.device.CreateMessageResponse(peer)
|
||||
if err != nil {
|
||||
peer.device.log.Error.Println(peer, ": Failed to create response message:", err)
|
||||
peer.device.log.Error.Println(peer, "- Failed to create response message:", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ func (peer *Peer) SendHandshakeResponse() error {
|
||||
|
||||
err = peer.BeginSymmetricSession()
|
||||
if err != nil {
|
||||
peer.device.log.Error.Println(peer, ": Failed to derive keypair:", err)
|
||||
peer.device.log.Error.Println(peer, "- Failed to derive keypair:", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ func (peer *Peer) SendHandshakeResponse() error {
|
||||
|
||||
err = peer.SendBuffer(packet)
|
||||
if err != nil {
|
||||
peer.device.log.Error.Println(peer, ": Failed to send handshake response", err)
|
||||
peer.device.log.Error.Println(peer, "- Failed to send handshake response", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -243,8 +243,6 @@ func (peer *Peer) keepKeyFreshSending() {
|
||||
*/
|
||||
func (device *Device) RoutineReadFromTUN() {
|
||||
|
||||
elem := device.NewOutboundElement()
|
||||
|
||||
logDebug := device.log.Debug
|
||||
logError := device.log.Error
|
||||
|
||||
@@ -256,7 +254,14 @@ func (device *Device) RoutineReadFromTUN() {
|
||||
logDebug.Println("Routine: TUN reader - started")
|
||||
device.state.starting.Done()
|
||||
|
||||
var elem *QueueOutboundElement
|
||||
|
||||
for {
|
||||
if elem != nil {
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
device.PutOutboundElement(elem)
|
||||
}
|
||||
elem = device.NewOutboundElement()
|
||||
|
||||
// read packet
|
||||
|
||||
@@ -264,8 +269,12 @@ func (device *Device) RoutineReadFromTUN() {
|
||||
size, err := device.tun.device.Read(elem.buffer[:], offset)
|
||||
|
||||
if err != nil {
|
||||
logError.Println("Failed to read packet from TUN device:", err)
|
||||
device.Close()
|
||||
if !device.isClosed.Get() {
|
||||
logError.Println("Failed to read packet from TUN device:", err)
|
||||
device.Close()
|
||||
}
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
device.PutOutboundElement(elem)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -304,11 +313,11 @@ func (device *Device) RoutineReadFromTUN() {
|
||||
// insert into nonce/pre-handshake queue
|
||||
|
||||
if peer.isRunning.Get() {
|
||||
if peer.queue.packetInNonceQueueIsAwaitingKey {
|
||||
if peer.queue.packetInNonceQueueIsAwaitingKey.Get() {
|
||||
peer.SendHandshakeInitiation(false)
|
||||
}
|
||||
addToOutboundQueue(peer.queue.nonce, elem)
|
||||
elem = device.NewOutboundElement()
|
||||
addToNonceQueue(peer.queue.nonce, elem, device)
|
||||
elem = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -332,28 +341,31 @@ func (peer *Peer) RoutineNonce() {
|
||||
device := peer.device
|
||||
logDebug := device.log.Debug
|
||||
|
||||
defer func() {
|
||||
logDebug.Println(peer, ": Routine: nonce worker - stopped")
|
||||
peer.queue.packetInNonceQueueIsAwaitingKey = false
|
||||
peer.routines.stopping.Done()
|
||||
}()
|
||||
|
||||
flush := func() {
|
||||
for {
|
||||
select {
|
||||
case <-peer.queue.nonce:
|
||||
case elem := <-peer.queue.nonce:
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
device.PutOutboundElement(elem)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
flush()
|
||||
logDebug.Println(peer, "- Routine: nonce worker - stopped")
|
||||
peer.queue.packetInNonceQueueIsAwaitingKey.Set(false)
|
||||
peer.routines.stopping.Done()
|
||||
}()
|
||||
|
||||
peer.routines.starting.Done()
|
||||
logDebug.Println(peer, ": Routine: nonce worker - started")
|
||||
logDebug.Println(peer, "- Routine: nonce worker - started")
|
||||
|
||||
for {
|
||||
NextPacket:
|
||||
peer.queue.packetInNonceQueueIsAwaitingKey = false
|
||||
peer.queue.packetInNonceQueueIsAwaitingKey.Set(false)
|
||||
|
||||
select {
|
||||
case <-peer.routines.stop:
|
||||
@@ -381,7 +393,7 @@ func (peer *Peer) RoutineNonce() {
|
||||
break
|
||||
}
|
||||
}
|
||||
peer.queue.packetInNonceQueueIsAwaitingKey = true
|
||||
peer.queue.packetInNonceQueueIsAwaitingKey.Set(true)
|
||||
|
||||
// no suitable key pair, request for new handshake
|
||||
|
||||
@@ -394,21 +406,25 @@ func (peer *Peer) RoutineNonce() {
|
||||
|
||||
// wait for key to be established
|
||||
|
||||
logDebug.Println(peer, ": Awaiting keypair")
|
||||
logDebug.Println(peer, "- Awaiting keypair")
|
||||
|
||||
select {
|
||||
case <-peer.signals.newKeypairArrived:
|
||||
logDebug.Println(peer, ": Obtained awaited keypair")
|
||||
logDebug.Println(peer, "- Obtained awaited keypair")
|
||||
|
||||
case <-peer.signals.flushNonceQueue:
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
device.PutOutboundElement(elem)
|
||||
flush()
|
||||
goto NextPacket
|
||||
|
||||
case <-peer.routines.stop:
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
device.PutOutboundElement(elem)
|
||||
return
|
||||
}
|
||||
}
|
||||
peer.queue.packetInNonceQueueIsAwaitingKey = false
|
||||
peer.queue.packetInNonceQueueIsAwaitingKey.Set(false)
|
||||
|
||||
// populate work element
|
||||
|
||||
@@ -419,6 +435,8 @@ func (peer *Peer) RoutineNonce() {
|
||||
|
||||
if elem.nonce >= RejectAfterMessages {
|
||||
atomic.StoreUint64(&keypair.sendNonce, RejectAfterMessages)
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
device.PutOutboundElement(elem)
|
||||
goto NextPacket
|
||||
}
|
||||
|
||||
@@ -427,9 +445,7 @@ func (peer *Peer) RoutineNonce() {
|
||||
elem.mutex.Lock()
|
||||
|
||||
// add to parallel and sequential queue
|
||||
|
||||
addToEncryptionQueue(device.queue.encryption, elem)
|
||||
addToOutboundQueue(peer.queue.outbound, elem)
|
||||
addToOutboundAndEncryptionQueues(peer.queue.outbound, device.queue.encryption, elem)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -446,6 +462,19 @@ func (device *Device) RoutineEncryption() {
|
||||
logDebug := device.log.Debug
|
||||
|
||||
defer func() {
|
||||
for {
|
||||
select {
|
||||
case elem, ok := <-device.queue.encryption:
|
||||
if ok && !elem.IsDropped() {
|
||||
elem.Drop()
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
elem.mutex.Unlock()
|
||||
}
|
||||
default:
|
||||
goto out
|
||||
}
|
||||
}
|
||||
out:
|
||||
logDebug.Println("Routine: encryption worker - stopped")
|
||||
device.state.stopping.Done()
|
||||
}()
|
||||
@@ -488,11 +517,13 @@ func (device *Device) RoutineEncryption() {
|
||||
// pad content to multiple of 16
|
||||
|
||||
mtu := int(atomic.LoadInt32(&device.tun.mtu))
|
||||
rem := len(elem.packet) % PaddingMultiple
|
||||
if rem > 0 {
|
||||
for i := 0; i < PaddingMultiple-rem && len(elem.packet) < mtu; i++ {
|
||||
elem.packet = append(elem.packet, 0)
|
||||
}
|
||||
lastUnit := len(elem.packet) % mtu
|
||||
paddedSize := (lastUnit + PaddingMultiple - 1) & ^(PaddingMultiple - 1)
|
||||
if paddedSize > mtu {
|
||||
paddedSize = mtu
|
||||
}
|
||||
for i := len(elem.packet); i < paddedSize; i++ {
|
||||
elem.packet = append(elem.packet, 0)
|
||||
}
|
||||
|
||||
// encrypt content and release to consumer
|
||||
@@ -519,13 +550,30 @@ func (peer *Peer) RoutineSequentialSender() {
|
||||
device := peer.device
|
||||
|
||||
logDebug := device.log.Debug
|
||||
logError := device.log.Error
|
||||
|
||||
defer func() {
|
||||
logDebug.Println(peer, ": Routine: sequential sender - stopped")
|
||||
for {
|
||||
select {
|
||||
case elem, ok := <-peer.queue.outbound:
|
||||
if ok {
|
||||
if !elem.IsDropped() {
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
elem.Drop()
|
||||
}
|
||||
device.PutOutboundElement(elem)
|
||||
elem.mutex.Unlock()
|
||||
}
|
||||
default:
|
||||
goto out
|
||||
}
|
||||
}
|
||||
out:
|
||||
logDebug.Println(peer, "- Routine: sequential sender - stopped")
|
||||
peer.routines.stopping.Done()
|
||||
}()
|
||||
|
||||
logDebug.Println(peer, ": Routine: sequential sender - started")
|
||||
logDebug.Println(peer, "- Routine: sequential sender - started")
|
||||
|
||||
peer.routines.starting.Done()
|
||||
|
||||
@@ -543,6 +591,7 @@ func (peer *Peer) RoutineSequentialSender() {
|
||||
|
||||
elem.mutex.Lock()
|
||||
if elem.IsDropped() {
|
||||
device.PutOutboundElement(elem)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -554,8 +603,9 @@ func (peer *Peer) RoutineSequentialSender() {
|
||||
length := uint64(len(elem.packet))
|
||||
err := peer.SendBuffer(elem.packet)
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
device.PutOutboundElement(elem)
|
||||
if err != nil {
|
||||
logDebug.Println("Failed to send authenticated packet to peer", peer)
|
||||
logError.Println(peer, "- Failed to send data packet", err)
|
||||
continue
|
||||
}
|
||||
atomic.AddUint64(&peer.stats.txBytes, length)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package tai64n
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package tai64n
|
||||
|
||||
40
timers.go
40
timers.go
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2015-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*
|
||||
* This is based heavily on timers.c from the kernel implementation.
|
||||
*/
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
|
||||
type Timer struct {
|
||||
timer *time.Timer
|
||||
modifyingLock sync.Mutex
|
||||
modifyingLock sync.RWMutex
|
||||
runningLock sync.Mutex
|
||||
isPending bool
|
||||
}
|
||||
@@ -67,12 +67,18 @@ func (timer *Timer) DelSync() {
|
||||
timer.runningLock.Unlock()
|
||||
}
|
||||
|
||||
func (timer *Timer) IsPending() bool {
|
||||
timer.modifyingLock.RLock()
|
||||
defer timer.modifyingLock.RUnlock()
|
||||
return timer.isPending
|
||||
}
|
||||
|
||||
func (peer *Peer) timersActive() bool {
|
||||
return peer.isRunning.Get() && peer.device != nil && peer.device.isUp.Get() && len(peer.device.peers.keyMap) > 0
|
||||
}
|
||||
|
||||
func expiredRetransmitHandshake(peer *Peer) {
|
||||
if peer.timers.handshakeAttempts > MaxTimerHandshakes {
|
||||
if atomic.LoadUint32(&peer.timers.handshakeAttempts) > MaxTimerHandshakes {
|
||||
peer.device.log.Debug.Printf("%s: Handshake did not complete after %d attempts, giving up\n", peer, MaxTimerHandshakes+2)
|
||||
|
||||
if peer.timersActive() {
|
||||
@@ -87,12 +93,12 @@ func expiredRetransmitHandshake(peer *Peer) {
|
||||
/* We set a timer for destroying any residue that might be left
|
||||
* of a partial exchange.
|
||||
*/
|
||||
if peer.timersActive() && !peer.timers.zeroKeyMaterial.isPending {
|
||||
if peer.timersActive() && !peer.timers.zeroKeyMaterial.IsPending() {
|
||||
peer.timers.zeroKeyMaterial.Mod(RejectAfterTime * 3)
|
||||
}
|
||||
} else {
|
||||
peer.timers.handshakeAttempts++
|
||||
peer.device.log.Debug.Printf("%s: Handshake did not complete after %d seconds, retrying (try %d)\n", peer, int(RekeyTimeout.Seconds()), peer.timers.handshakeAttempts+1)
|
||||
atomic.AddUint32(&peer.timers.handshakeAttempts, 1)
|
||||
peer.device.log.Debug.Printf("%s: Handshake did not complete after %d seconds, retrying (try %d)\n", peer, int(RekeyTimeout.Seconds()), atomic.LoadUint32(&peer.timers.handshakeAttempts)+1)
|
||||
|
||||
/* We clear the endpoint address src address, in case this is the cause of trouble. */
|
||||
peer.mutex.Lock()
|
||||
@@ -107,8 +113,8 @@ func expiredRetransmitHandshake(peer *Peer) {
|
||||
|
||||
func expiredSendKeepalive(peer *Peer) {
|
||||
peer.SendKeepalive()
|
||||
if peer.timers.needAnotherKeepalive {
|
||||
peer.timers.needAnotherKeepalive = false
|
||||
if peer.timers.needAnotherKeepalive.Get() {
|
||||
peer.timers.needAnotherKeepalive.Set(false)
|
||||
if peer.timersActive() {
|
||||
peer.timers.sendKeepalive.Mod(KeepaliveTimeout)
|
||||
}
|
||||
@@ -128,7 +134,7 @@ func expiredNewHandshake(peer *Peer) {
|
||||
}
|
||||
|
||||
func expiredZeroKeyMaterial(peer *Peer) {
|
||||
peer.device.log.Debug.Printf(":%s Removing all keys, since we haven't received a new one in %d seconds\n", peer, int((RejectAfterTime * 3).Seconds()))
|
||||
peer.device.log.Debug.Printf("%s: Removing all keys, since we haven't received a new one in %d seconds\n", peer, int((RejectAfterTime * 3).Seconds()))
|
||||
peer.ZeroAndFlushAll()
|
||||
}
|
||||
|
||||
@@ -140,7 +146,7 @@ func expiredPersistentKeepalive(peer *Peer) {
|
||||
|
||||
/* Should be called after an authenticated data packet is sent. */
|
||||
func (peer *Peer) timersDataSent() {
|
||||
if peer.timersActive() && !peer.timers.newHandshake.isPending {
|
||||
if peer.timersActive() && !peer.timers.newHandshake.IsPending() {
|
||||
peer.timers.newHandshake.Mod(KeepaliveTimeout + RekeyTimeout)
|
||||
}
|
||||
}
|
||||
@@ -148,10 +154,10 @@ func (peer *Peer) timersDataSent() {
|
||||
/* Should be called after an authenticated data packet is received. */
|
||||
func (peer *Peer) timersDataReceived() {
|
||||
if peer.timersActive() {
|
||||
if !peer.timers.sendKeepalive.isPending {
|
||||
if !peer.timers.sendKeepalive.IsPending() {
|
||||
peer.timers.sendKeepalive.Mod(KeepaliveTimeout)
|
||||
} else {
|
||||
peer.timers.needAnotherKeepalive = true
|
||||
peer.timers.needAnotherKeepalive.Set(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,8 +188,8 @@ func (peer *Peer) timersHandshakeComplete() {
|
||||
if peer.timersActive() {
|
||||
peer.timers.retransmitHandshake.Del()
|
||||
}
|
||||
peer.timers.handshakeAttempts = 0
|
||||
peer.timers.sentLastMinuteHandshake = false
|
||||
atomic.StoreUint32(&peer.timers.handshakeAttempts, 0)
|
||||
peer.timers.sentLastMinuteHandshake.Set(false)
|
||||
atomic.StoreInt64(&peer.stats.lastHandshakeNano, time.Now().UnixNano())
|
||||
}
|
||||
|
||||
@@ -207,9 +213,9 @@ func (peer *Peer) timersInit() {
|
||||
peer.timers.newHandshake = peer.NewTimer(expiredNewHandshake)
|
||||
peer.timers.zeroKeyMaterial = peer.NewTimer(expiredZeroKeyMaterial)
|
||||
peer.timers.persistentKeepalive = peer.NewTimer(expiredPersistentKeepalive)
|
||||
peer.timers.handshakeAttempts = 0
|
||||
peer.timers.sentLastMinuteHandshake = false
|
||||
peer.timers.needAnotherKeepalive = false
|
||||
atomic.StoreUint32(&peer.timers.handshakeAttempts, 0)
|
||||
peer.timers.sentLastMinuteHandshake.Set(false)
|
||||
peer.timers.needAnotherKeepalive.Set(false)
|
||||
}
|
||||
|
||||
func (peer *Peer) timersStop() {
|
||||
|
||||
32
tun.go
32
tun.go
@@ -1,45 +1,28 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"git.zx2c4.com/wireguard-go/tun"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
const DefaultMTU = 1420
|
||||
|
||||
type TUNEvent int
|
||||
|
||||
const (
|
||||
TUNEventUp = 1 << iota
|
||||
TUNEventDown
|
||||
TUNEventMTUUpdate
|
||||
)
|
||||
|
||||
type TUNDevice interface {
|
||||
File() *os.File // returns the file descriptor of the device
|
||||
Read([]byte, int) (int, error) // read a packet from the device (without any additional headers)
|
||||
Write([]byte, int) (int, error) // writes a packet to the device (without any additional headers)
|
||||
MTU() (int, error) // returns the MTU of the device
|
||||
Name() (string, error) // fetches and returns the current name
|
||||
Events() chan TUNEvent // returns a constant channel of events related to the device
|
||||
Close() error // stops the device and closes the event channel
|
||||
}
|
||||
|
||||
func (device *Device) RoutineTUNEventReader() {
|
||||
setUp := false
|
||||
logDebug := device.log.Debug
|
||||
logInfo := device.log.Info
|
||||
logError := device.log.Error
|
||||
|
||||
logDebug.Println("Routine: event worker - started")
|
||||
device.state.starting.Done()
|
||||
|
||||
for event := range device.tun.device.Events() {
|
||||
if event&TUNEventMTUUpdate != 0 {
|
||||
if event&tun.TUNEventMTUUpdate != 0 {
|
||||
mtu, err := device.tun.device.MTU()
|
||||
old := atomic.LoadInt32(&device.tun.mtu)
|
||||
if err != nil {
|
||||
@@ -54,18 +37,19 @@ func (device *Device) RoutineTUNEventReader() {
|
||||
}
|
||||
}
|
||||
|
||||
if event&TUNEventUp != 0 && !setUp {
|
||||
if event&tun.TUNEventUp != 0 && !setUp {
|
||||
logInfo.Println("Interface set up")
|
||||
setUp = true
|
||||
device.Up()
|
||||
}
|
||||
|
||||
if event&TUNEventDown != 0 && setUp {
|
||||
if event&tun.TUNEventDown != 0 && setUp {
|
||||
logInfo.Println("Interface set down")
|
||||
setUp = false
|
||||
device.Down()
|
||||
}
|
||||
}
|
||||
|
||||
logDebug.Println("Routine: event worker - stopped")
|
||||
device.state.stopping.Done()
|
||||
}
|
||||
|
||||
26
tun/tun.go
Normal file
26
tun/tun.go
Normal file
@@ -0,0 +1,26 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package tun
|
||||
|
||||
import "os"
|
||||
|
||||
type TUNEvent int
|
||||
|
||||
const (
|
||||
TUNEventUp = 1 << iota
|
||||
TUNEventDown
|
||||
TUNEventMTUUpdate
|
||||
)
|
||||
|
||||
type TUNDevice interface {
|
||||
File() *os.File // returns the file descriptor of the device
|
||||
Read([]byte, int) (int, error) // read a packet from the device (without any additional headers)
|
||||
Write([]byte, int) (int, error) // writes a packet to the device (without any additional headers)
|
||||
MTU() (int, error) // returns the MTU of the device
|
||||
Name() (string, error) // fetches and returns the current name
|
||||
Events() chan TUNEvent // returns a constant channel of events related to the device
|
||||
Close() error // stops the device and closes the event channel
|
||||
}
|
||||
@@ -1,22 +1,22 @@
|
||||
// +build !ios
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package tun
|
||||
|
||||
import (
|
||||
"./rwcancel"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.zx2c4.com/wireguard-go/rwcancel"
|
||||
"golang.org/x/net/ipv6"
|
||||
"golang.org/x/sys/unix"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@@ -35,25 +35,79 @@ type sockaddrCtl struct {
|
||||
scReserved [5]uint32
|
||||
}
|
||||
|
||||
// NativeTun is a hack to work around the first 4 bytes "packet
|
||||
// information" because there doesn't seem to be an IFF_NO_PI for darwin.
|
||||
type NativeTun struct {
|
||||
name string
|
||||
fd *os.File
|
||||
rwcancel *rwcancel.RWCancel
|
||||
mtu int
|
||||
events chan TUNEvent
|
||||
errors chan error
|
||||
statusListenersShutdown chan struct{}
|
||||
type nativeTun struct {
|
||||
name string
|
||||
tunFile *os.File
|
||||
fd uintptr
|
||||
rwcancel *rwcancel.RWCancel
|
||||
events chan TUNEvent
|
||||
errors chan error
|
||||
routeSocket int
|
||||
}
|
||||
|
||||
var sockaddrCtlSize uintptr = 32
|
||||
|
||||
func CreateTUN(name string) (TUNDevice, error) {
|
||||
func (tun *nativeTun) routineRouteListener(tunIfindex int) {
|
||||
var (
|
||||
statusUp bool
|
||||
statusMTU int
|
||||
)
|
||||
|
||||
defer close(tun.events)
|
||||
|
||||
data := make([]byte, os.Getpagesize())
|
||||
for {
|
||||
retry:
|
||||
n, err := unix.Read(tun.routeSocket, data)
|
||||
if err != nil {
|
||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINTR {
|
||||
goto retry
|
||||
}
|
||||
tun.errors <- err
|
||||
return
|
||||
}
|
||||
|
||||
if n < 14 {
|
||||
continue
|
||||
}
|
||||
|
||||
if data[3 /* type */] != unix.RTM_IFINFO {
|
||||
continue
|
||||
}
|
||||
ifindex := int(*(*uint16)(unsafe.Pointer(&data[12 /* ifindex */])))
|
||||
if ifindex != tunIfindex {
|
||||
continue
|
||||
}
|
||||
|
||||
iface, err := net.InterfaceByIndex(ifindex)
|
||||
if err != nil {
|
||||
tun.errors <- err
|
||||
return
|
||||
}
|
||||
|
||||
// Up / Down event
|
||||
up := (iface.Flags & net.FlagUp) != 0
|
||||
if up != statusUp && up {
|
||||
tun.events <- TUNEventUp
|
||||
}
|
||||
if up != statusUp && !up {
|
||||
tun.events <- TUNEventDown
|
||||
}
|
||||
statusUp = up
|
||||
|
||||
// MTU changes
|
||||
if iface.MTU != statusMTU {
|
||||
tun.events <- TUNEventMTUUpdate
|
||||
}
|
||||
statusMTU = iface.MTU
|
||||
}
|
||||
}
|
||||
|
||||
func CreateTUN(name string, mtu int) (TUNDevice, error) {
|
||||
ifIndex := -1
|
||||
if name != "utun" {
|
||||
fmt.Sscanf(name, "utun%d", &ifIndex)
|
||||
if ifIndex < 0 {
|
||||
_, err := fmt.Sscanf(name, "utun%d", &ifIndex)
|
||||
if err != nil || ifIndex < 0 {
|
||||
return nil, fmt.Errorf("Interface name must be utun[0-9]*")
|
||||
}
|
||||
}
|
||||
@@ -103,80 +157,60 @@ func CreateTUN(name string) (TUNDevice, error) {
|
||||
return nil, fmt.Errorf("SYS_CONNECT: %v", errno)
|
||||
}
|
||||
|
||||
tun, err := CreateTUNFromFile(os.NewFile(uintptr(fd), ""))
|
||||
tun, err := CreateTUNFromFile(os.NewFile(uintptr(fd), ""), mtu)
|
||||
|
||||
if err == nil && name == "utun" {
|
||||
fname := os.Getenv("WG_DARWIN_UTUN_NAME_FILE")
|
||||
fname := os.Getenv("WG_TUN_NAME_FILE")
|
||||
if fname != "" {
|
||||
ioutil.WriteFile(fname, []byte(tun.(*NativeTun).name+"\n"), 0400)
|
||||
ioutil.WriteFile(fname, []byte(tun.(*nativeTun).name+"\n"), 0400)
|
||||
}
|
||||
}
|
||||
|
||||
return tun, err
|
||||
}
|
||||
|
||||
func CreateTUNFromFile(file *os.File) (TUNDevice, error) {
|
||||
func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
|
||||
tun := &NativeTun{
|
||||
fd: file,
|
||||
mtu: 1500,
|
||||
events: make(chan TUNEvent, 10),
|
||||
errors: make(chan error, 1),
|
||||
statusListenersShutdown: make(chan struct{}),
|
||||
tun := &nativeTun{
|
||||
tunFile: file,
|
||||
fd: file.Fd(),
|
||||
events: make(chan TUNEvent, 10),
|
||||
errors: make(chan error, 1),
|
||||
}
|
||||
|
||||
_, err := tun.Name()
|
||||
name, err := tun.Name()
|
||||
if err != nil {
|
||||
tun.fd.Close()
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun.rwcancel, err = rwcancel.NewRWCancel(int(file.Fd()))
|
||||
if err != nil {
|
||||
tun.fd.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: Fix this very naive implementation
|
||||
go func(tun *NativeTun) {
|
||||
var (
|
||||
statusUp bool
|
||||
statusMTU int
|
||||
)
|
||||
|
||||
for {
|
||||
intr, err := net.InterfaceByName(tun.name)
|
||||
if err != nil {
|
||||
tun.errors <- err
|
||||
return
|
||||
}
|
||||
|
||||
// Up / Down event
|
||||
up := (intr.Flags & net.FlagUp) != 0
|
||||
if up != statusUp && up {
|
||||
tun.events <- TUNEventUp
|
||||
}
|
||||
if up != statusUp && !up {
|
||||
tun.events <- TUNEventDown
|
||||
}
|
||||
statusUp = up
|
||||
|
||||
// MTU changes
|
||||
if intr.MTU != statusMTU {
|
||||
tun.events <- TUNEventMTUUpdate
|
||||
}
|
||||
statusMTU = intr.MTU
|
||||
|
||||
select {
|
||||
case <-time.After(time.Second / 10):
|
||||
case <-tun.statusListenersShutdown:
|
||||
return
|
||||
}
|
||||
tunIfindex, err := func() (int, error) {
|
||||
iface, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
}(tun)
|
||||
return iface.Index, nil
|
||||
}()
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// set default MTU
|
||||
err = tun.setMTU(DefaultMTU)
|
||||
tun.rwcancel, err = rwcancel.NewRWCancel(int(tun.fd))
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go tun.routineRouteListener(tunIfindex)
|
||||
|
||||
err = tun.setMTU(mtu)
|
||||
if err != nil {
|
||||
tun.Close()
|
||||
return nil, err
|
||||
@@ -185,7 +219,7 @@ func CreateTUNFromFile(file *os.File) (TUNDevice, error) {
|
||||
return tun, nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Name() (string, error) {
|
||||
func (tun *nativeTun) Name() (string, error) {
|
||||
|
||||
var ifName struct {
|
||||
name [16]byte
|
||||
@@ -194,7 +228,7 @@ func (tun *NativeTun) Name() (string, error) {
|
||||
|
||||
_, _, errno := unix.Syscall6(
|
||||
unix.SYS_GETSOCKOPT,
|
||||
uintptr(tun.fd.Fd()),
|
||||
uintptr(tun.fd),
|
||||
2, /* #define SYSPROTO_CONTROL 2 */
|
||||
2, /* #define UTUN_OPT_IFNAME 2 */
|
||||
uintptr(unsafe.Pointer(&ifName)),
|
||||
@@ -208,21 +242,21 @@ func (tun *NativeTun) Name() (string, error) {
|
||||
return tun.name, nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) File() *os.File {
|
||||
return tun.fd
|
||||
func (tun *nativeTun) File() *os.File {
|
||||
return tun.tunFile
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Events() chan TUNEvent {
|
||||
func (tun *nativeTun) Events() chan TUNEvent {
|
||||
return tun.events
|
||||
}
|
||||
|
||||
func (tun *NativeTun) doRead(buff []byte, offset int) (int, error) {
|
||||
func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
|
||||
select {
|
||||
case err := <-tun.errors:
|
||||
return 0, err
|
||||
default:
|
||||
buff := buff[offset-4:]
|
||||
n, err := tun.fd.Read(buff[:])
|
||||
n, err := tun.tunFile.Read(buff[:])
|
||||
if n < 4 {
|
||||
return 0, err
|
||||
}
|
||||
@@ -230,10 +264,10 @@ func (tun *NativeTun) doRead(buff []byte, offset int) (int, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
for {
|
||||
n, err := tun.doRead(buff, offset)
|
||||
if err == nil || !rwcancel.ErrorIsEAGAIN(err) {
|
||||
if err == nil || !rwcancel.RetryAfterError(err) {
|
||||
return n, err
|
||||
}
|
||||
if !tun.rwcancel.ReadyRead() {
|
||||
@@ -242,7 +276,7 @@ func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
|
||||
// reserve space for header
|
||||
|
||||
@@ -262,21 +296,30 @@ func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
|
||||
// write
|
||||
|
||||
return tun.fd.Write(buff)
|
||||
return tun.tunFile.Write(buff)
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Close() error {
|
||||
close(tun.statusListenersShutdown)
|
||||
func (tun *nativeTun) Close() error {
|
||||
var err3 error
|
||||
err1 := tun.rwcancel.Cancel()
|
||||
err2 := tun.fd.Close()
|
||||
close(tun.events)
|
||||
err2 := tun.tunFile.Close()
|
||||
if tun.routeSocket != -1 {
|
||||
unix.Shutdown(tun.routeSocket, unix.SHUT_RDWR)
|
||||
err3 = unix.Close(tun.routeSocket)
|
||||
tun.routeSocket = -1
|
||||
} else if tun.events != nil {
|
||||
close(tun.events)
|
||||
}
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
return err2
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
return err3
|
||||
}
|
||||
|
||||
func (tun *NativeTun) setMTU(n int) error {
|
||||
func (tun *nativeTun) setMTU(n int) error {
|
||||
|
||||
// open datagram socket
|
||||
|
||||
@@ -298,7 +341,7 @@ func (tun *NativeTun) setMTU(n int) error {
|
||||
|
||||
var ifr [32]byte
|
||||
copy(ifr[:], tun.name)
|
||||
binary.LittleEndian.PutUint32(ifr[16:20], uint32(n))
|
||||
*(*uint32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = uint32(n)
|
||||
_, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
uintptr(fd),
|
||||
@@ -307,13 +350,13 @@ func (tun *NativeTun) setMTU(n int) error {
|
||||
)
|
||||
|
||||
if errno != 0 {
|
||||
return fmt.Errorf("Failed to set MTU on %s", tun.name)
|
||||
return fmt.Errorf("failed to set MTU on %s", tun.name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) MTU() (int, error) {
|
||||
func (tun *nativeTun) MTU() (int, error) {
|
||||
|
||||
// open datagram socket
|
||||
|
||||
@@ -340,14 +383,8 @@ func (tun *NativeTun) MTU() (int, error) {
|
||||
uintptr(unsafe.Pointer(&ifr[0])),
|
||||
)
|
||||
if errno != 0 {
|
||||
return 0, fmt.Errorf("Failed to get MTU on %s", tun.name)
|
||||
return 0, fmt.Errorf("failed to get MTU on %s", tun.name)
|
||||
}
|
||||
|
||||
// convert result to signed 32-bit int
|
||||
|
||||
val := binary.LittleEndian.Uint32(ifr[16:20])
|
||||
if val >= (1 << 31) {
|
||||
return int(val-(1<<31)) - (1 << 31), nil
|
||||
}
|
||||
return int(val), nil
|
||||
return int(*(*int32)(unsafe.Pointer(&ifr[16]))), nil
|
||||
}
|
||||
512
tun/tun_freebsd.go
Normal file
512
tun/tun_freebsd.go
Normal file
@@ -0,0 +1,512 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.zx2c4.com/wireguard-go/rwcancel"
|
||||
"golang.org/x/net/ipv6"
|
||||
"golang.org/x/sys/unix"
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// _TUNSIFHEAD, value derived from sys/net/{if_tun,ioccom}.h
|
||||
// const _TUNSIFHEAD = ((0x80000000) | (((4) & ((1 << 13) - 1) ) << 16) | (uint32(byte('t')) << 8) | (96))
|
||||
const _TUNSIFHEAD = 0x80047460
|
||||
const _TUNSIFMODE = 0x8004745e
|
||||
const _TUNSIFPID = 0x2000745f
|
||||
|
||||
// Iface status string max len
|
||||
const _IFSTATMAX = 800
|
||||
|
||||
const SIZEOF_UINTPTR = 4 << (^uintptr(0) >> 32 & 1)
|
||||
|
||||
// structure for iface requests with a pointer
|
||||
type ifreq_ptr struct {
|
||||
Name [unix.IFNAMSIZ]byte
|
||||
Data uintptr
|
||||
Pad0 [24 - SIZEOF_UINTPTR]byte
|
||||
}
|
||||
|
||||
// Structure for iface mtu get/set ioctls
|
||||
type ifreq_mtu struct {
|
||||
Name [unix.IFNAMSIZ]byte
|
||||
MTU uint32
|
||||
Pad0 [12]byte
|
||||
}
|
||||
|
||||
// Structure for interface status request ioctl
|
||||
type ifstat struct {
|
||||
IfsName [unix.IFNAMSIZ]byte
|
||||
Ascii [_IFSTATMAX]byte
|
||||
}
|
||||
|
||||
type nativeTun struct {
|
||||
name string
|
||||
tunFile *os.File
|
||||
fd uintptr
|
||||
rwcancel *rwcancel.RWCancel
|
||||
events chan TUNEvent
|
||||
errors chan error
|
||||
routeSocket int
|
||||
}
|
||||
|
||||
func (tun *nativeTun) routineRouteListener(tunIfindex int) {
|
||||
var (
|
||||
statusUp bool
|
||||
statusMTU int
|
||||
)
|
||||
|
||||
defer close(tun.events)
|
||||
|
||||
data := make([]byte, os.Getpagesize())
|
||||
for {
|
||||
retry:
|
||||
n, err := unix.Read(tun.routeSocket, data)
|
||||
if err != nil {
|
||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINTR {
|
||||
goto retry
|
||||
}
|
||||
tun.errors <- err
|
||||
return
|
||||
}
|
||||
|
||||
if n < 14 {
|
||||
continue
|
||||
}
|
||||
|
||||
if data[3 /* type */] != unix.RTM_IFINFO {
|
||||
continue
|
||||
}
|
||||
ifindex := int(*(*uint16)(unsafe.Pointer(&data[12 /* ifindex */])))
|
||||
if ifindex != tunIfindex {
|
||||
continue
|
||||
}
|
||||
|
||||
iface, err := net.InterfaceByIndex(ifindex)
|
||||
if err != nil {
|
||||
tun.errors <- err
|
||||
return
|
||||
}
|
||||
|
||||
// Up / Down event
|
||||
up := (iface.Flags & net.FlagUp) != 0
|
||||
if up != statusUp && up {
|
||||
tun.events <- TUNEventUp
|
||||
}
|
||||
if up != statusUp && !up {
|
||||
tun.events <- TUNEventDown
|
||||
}
|
||||
statusUp = up
|
||||
|
||||
// MTU changes
|
||||
if iface.MTU != statusMTU {
|
||||
tun.events <- TUNEventMTUUpdate
|
||||
}
|
||||
statusMTU = iface.MTU
|
||||
}
|
||||
}
|
||||
|
||||
func tunName(fd uintptr) (string, error) {
|
||||
//Terrible hack to make up for freebsd not having a TUNGIFNAME
|
||||
|
||||
//First, make sure the tun pid matches this proc's pid
|
||||
_, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
uintptr(fd),
|
||||
uintptr(_TUNSIFPID),
|
||||
uintptr(0),
|
||||
)
|
||||
|
||||
if errno != 0 {
|
||||
return "", fmt.Errorf("failed to set tun device PID: %s", errno.Error())
|
||||
}
|
||||
|
||||
// Open iface control socket
|
||||
|
||||
confd, err := unix.Socket(
|
||||
unix.AF_INET,
|
||||
unix.SOCK_DGRAM,
|
||||
0,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
defer unix.Close(confd)
|
||||
|
||||
procPid := os.Getpid()
|
||||
|
||||
//Try to find interface with matching PID
|
||||
for i := 1; ; i++ {
|
||||
iface, _ := net.InterfaceByIndex(i)
|
||||
if err != nil || iface == nil {
|
||||
break
|
||||
}
|
||||
|
||||
// Structs for getting data in and out of SIOCGIFSTATUS ioctl
|
||||
var ifstatus ifstat
|
||||
copy(ifstatus.IfsName[:], iface.Name)
|
||||
|
||||
// Make the syscall to get the status string
|
||||
_, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
uintptr(confd),
|
||||
uintptr(unix.SIOCGIFSTATUS),
|
||||
uintptr(unsafe.Pointer(&ifstatus)),
|
||||
)
|
||||
|
||||
if errno != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
nullStr := ifstatus.Ascii[:]
|
||||
i := bytes.IndexByte(nullStr, 0)
|
||||
if i < 1 {
|
||||
continue
|
||||
}
|
||||
statStr := string(nullStr[:i])
|
||||
var pidNum int = 0
|
||||
|
||||
// Finally get the owning PID
|
||||
// Format string taken from sys/net/if_tun.c
|
||||
_, err := fmt.Sscanf(statStr, "\tOpened by PID %d\n", &pidNum)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if pidNum == procPid {
|
||||
return iface.Name, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Destroy a named system interface
|
||||
func tunDestroy(name string) error {
|
||||
// open control socket
|
||||
var fd int
|
||||
|
||||
fd, err := unix.Socket(
|
||||
unix.AF_INET,
|
||||
unix.SOCK_DGRAM,
|
||||
0,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer unix.Close(fd)
|
||||
|
||||
// do ioctl call
|
||||
|
||||
var ifr [32]byte
|
||||
copy(ifr[:], name)
|
||||
_, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
uintptr(fd),
|
||||
uintptr(unix.SIOCIFDESTROY),
|
||||
uintptr(unsafe.Pointer(&ifr[0])),
|
||||
)
|
||||
|
||||
if errno != 0 {
|
||||
return fmt.Errorf("failed to destroy interface %s: %s", name, errno.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateTUN(name string, mtu int) (TUNDevice, error) {
|
||||
if len(name) > unix.IFNAMSIZ-1 {
|
||||
return nil, errors.New("interface name too long")
|
||||
}
|
||||
|
||||
// See if interface already exists
|
||||
iface, _ := net.InterfaceByName(name)
|
||||
if iface != nil {
|
||||
return nil, fmt.Errorf("interface %s already exists", name)
|
||||
}
|
||||
|
||||
tunFile, err := os.OpenFile("/dev/tun", unix.O_RDWR, 0)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tunfd := tunFile.Fd()
|
||||
assignedName, err := tunName(tunfd)
|
||||
if err != nil {
|
||||
tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Enable ifhead mode, otherwise tun will complain if it gets a non-AF_INET packet
|
||||
ifheadmode := 1
|
||||
_, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
uintptr(tunfd),
|
||||
uintptr(_TUNSIFHEAD),
|
||||
uintptr(unsafe.Pointer(&ifheadmode)),
|
||||
)
|
||||
|
||||
if errno != 0 {
|
||||
return nil, fmt.Errorf("error %s", errno.Error())
|
||||
}
|
||||
|
||||
// Rename tun interface
|
||||
|
||||
// Open control socket
|
||||
confd, err := unix.Socket(
|
||||
unix.AF_INET,
|
||||
unix.SOCK_DGRAM,
|
||||
0,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer unix.Close(confd)
|
||||
|
||||
// set up struct for iface rename
|
||||
var newnp [unix.IFNAMSIZ]byte
|
||||
copy(newnp[:], name)
|
||||
|
||||
var ifr ifreq_ptr
|
||||
copy(ifr.Name[:], assignedName)
|
||||
ifr.Data = uintptr(unsafe.Pointer(&newnp[0]))
|
||||
|
||||
//do actual ioctl to rename iface
|
||||
_, _, errno = unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
uintptr(confd),
|
||||
uintptr(unix.SIOCSIFNAME),
|
||||
uintptr(unsafe.Pointer(&ifr)),
|
||||
)
|
||||
if errno != 0 {
|
||||
tunFile.Close()
|
||||
tunDestroy(name)
|
||||
return nil, fmt.Errorf("failed to rename %s to %s: %s", assignedName, name, errno.Error())
|
||||
}
|
||||
|
||||
return CreateTUNFromFile(tunFile, mtu)
|
||||
}
|
||||
|
||||
func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
|
||||
tun := &nativeTun{
|
||||
tunFile: file,
|
||||
fd: file.Fd(),
|
||||
events: make(chan TUNEvent, 10),
|
||||
errors: make(chan error, 1),
|
||||
}
|
||||
|
||||
name, err := tun.Name()
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tunIfindex, err := func() (int, error) {
|
||||
iface, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return iface.Index, nil
|
||||
}()
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun.rwcancel, err = rwcancel.NewRWCancel(int(tun.fd))
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go tun.routineRouteListener(tunIfindex)
|
||||
|
||||
err = tun.setMTU(mtu)
|
||||
if err != nil {
|
||||
tun.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tun, nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Name() (string, error) {
|
||||
name, err := tunName(tun.fd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
tun.name = name
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) File() *os.File {
|
||||
return tun.tunFile
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Events() chan TUNEvent {
|
||||
return tun.events
|
||||
}
|
||||
|
||||
func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
|
||||
select {
|
||||
case err := <-tun.errors:
|
||||
return 0, err
|
||||
default:
|
||||
buff := buff[offset-4:]
|
||||
n, err := tun.tunFile.Read(buff[:])
|
||||
if n < 4 {
|
||||
return 0, err
|
||||
}
|
||||
return n - 4, err
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
for {
|
||||
n, err := tun.doRead(buff, offset)
|
||||
if err == nil || !rwcancel.RetryAfterError(err) {
|
||||
return n, err
|
||||
}
|
||||
if !tun.rwcancel.ReadyRead() {
|
||||
return 0, errors.New("tun device closed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
|
||||
// reserve space for header
|
||||
|
||||
buff = buff[offset-4:]
|
||||
|
||||
// add packet information header
|
||||
|
||||
buff[0] = 0x00
|
||||
buff[1] = 0x00
|
||||
buff[2] = 0x00
|
||||
|
||||
if buff[4]>>4 == ipv6.Version {
|
||||
buff[3] = unix.AF_INET6
|
||||
} else {
|
||||
buff[3] = unix.AF_INET
|
||||
}
|
||||
|
||||
// write
|
||||
|
||||
return tun.tunFile.Write(buff)
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Close() error {
|
||||
var err4 error
|
||||
err1 := tun.rwcancel.Cancel()
|
||||
err2 := tun.tunFile.Close()
|
||||
err3 := tunDestroy(tun.name)
|
||||
if tun.routeSocket != -1 {
|
||||
unix.Shutdown(tun.routeSocket, unix.SHUT_RDWR)
|
||||
err4 = unix.Close(tun.routeSocket)
|
||||
tun.routeSocket = -1
|
||||
} else if tun.events != nil {
|
||||
close(tun.events)
|
||||
}
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
if err3 != nil {
|
||||
return err3
|
||||
}
|
||||
return err4
|
||||
}
|
||||
|
||||
func (tun *nativeTun) setMTU(n int) error {
|
||||
// open datagram socket
|
||||
|
||||
var fd int
|
||||
|
||||
fd, err := unix.Socket(
|
||||
unix.AF_INET,
|
||||
unix.SOCK_DGRAM,
|
||||
0,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer unix.Close(fd)
|
||||
|
||||
// do ioctl call
|
||||
|
||||
var ifr ifreq_mtu
|
||||
copy(ifr.Name[:], tun.name)
|
||||
ifr.MTU = uint32(n)
|
||||
|
||||
_, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
uintptr(fd),
|
||||
uintptr(unix.SIOCSIFMTU),
|
||||
uintptr(unsafe.Pointer(&ifr)),
|
||||
)
|
||||
|
||||
if errno != 0 {
|
||||
return fmt.Errorf("failed to set MTU on %s", tun.name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) MTU() (int, error) {
|
||||
// open datagram socket
|
||||
|
||||
fd, err := unix.Socket(
|
||||
unix.AF_INET,
|
||||
unix.SOCK_DGRAM,
|
||||
0,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
defer unix.Close(fd)
|
||||
|
||||
// do ioctl call
|
||||
var ifr ifreq_mtu
|
||||
copy(ifr.Name[:], tun.name)
|
||||
|
||||
_, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
uintptr(fd),
|
||||
uintptr(unix.SIOCGIFMTU),
|
||||
uintptr(unsafe.Pointer(&ifr)),
|
||||
)
|
||||
if errno != 0 {
|
||||
return 0, fmt.Errorf("failed to get MTU on %s", tun.name)
|
||||
}
|
||||
|
||||
return int(*(*int32)(unsafe.Pointer(&ifr.MTU))), nil
|
||||
}
|
||||
@@ -1,27 +1,24 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/* Copyright 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
|
||||
|
||||
package main
|
||||
package tun
|
||||
|
||||
/* Implementation of the TUN device interface for linux
|
||||
*/
|
||||
|
||||
import (
|
||||
"./rwcancel"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.zx2c4.com/wireguard-go/rwcancel"
|
||||
"golang.org/x/net/ipv6"
|
||||
"golang.org/x/sys/unix"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
@@ -31,29 +28,31 @@ const (
|
||||
ifReqSize = unix.IFNAMSIZ + 64
|
||||
)
|
||||
|
||||
type NativeTun struct {
|
||||
fd *os.File
|
||||
fdCancel *rwcancel.RWCancel
|
||||
index int32 // if index
|
||||
name string // name of interface
|
||||
errors chan error // async error handling
|
||||
events chan TUNEvent // device related events
|
||||
nopi bool // the device was pased IFF_NO_PI
|
||||
netlinkSock int
|
||||
netlinkCancel *rwcancel.RWCancel
|
||||
|
||||
type nativeTun struct {
|
||||
tunFile *os.File
|
||||
fd uintptr
|
||||
fdCancel *rwcancel.RWCancel
|
||||
index int32 // if index
|
||||
name string // name of interface
|
||||
errors chan error // async error handling
|
||||
events chan TUNEvent // device related events
|
||||
nopi bool // the device was pased IFF_NO_PI
|
||||
netlinkSock int
|
||||
netlinkCancel *rwcancel.RWCancel
|
||||
hackListenerClosed sync.Mutex
|
||||
statusListenersShutdown chan struct{}
|
||||
}
|
||||
|
||||
func (tun *NativeTun) File() *os.File {
|
||||
return tun.fd
|
||||
func (tun *nativeTun) File() *os.File {
|
||||
return tun.tunFile
|
||||
}
|
||||
|
||||
func (tun *NativeTun) RoutineHackListener() {
|
||||
func (tun *nativeTun) routineHackListener() {
|
||||
defer tun.hackListenerClosed.Unlock()
|
||||
/* This is needed for the detection to work across network namespaces
|
||||
* If you are reading this and know a better method, please get in touch.
|
||||
*/
|
||||
fd := int(tun.fd.Fd())
|
||||
fd := int(tun.fd)
|
||||
for {
|
||||
_, err := unix.Write(fd, nil)
|
||||
switch err {
|
||||
@@ -65,7 +64,7 @@ func (tun *NativeTun) RoutineHackListener() {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case <-time.After(time.Second / 10):
|
||||
case <-time.After(time.Second):
|
||||
case <-tun.statusListenersShutdown:
|
||||
return
|
||||
}
|
||||
@@ -88,8 +87,12 @@ func createNetlinkSocket() (int, error) {
|
||||
return sock, nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) RoutineNetlinkListener() {
|
||||
defer unix.Close(tun.netlinkSock)
|
||||
func (tun *nativeTun) routineNetlinkListener() {
|
||||
defer func() {
|
||||
unix.Close(tun.netlinkSock)
|
||||
tun.hackListenerClosed.Lock()
|
||||
close(tun.events)
|
||||
}()
|
||||
|
||||
for msg := make([]byte, 1<<16); ; {
|
||||
|
||||
@@ -97,7 +100,7 @@ func (tun *NativeTun) RoutineNetlinkListener() {
|
||||
var msgn int
|
||||
for {
|
||||
msgn, _, _, _, err = unix.Recvmsg(tun.netlinkSock, msg[:], nil, 0)
|
||||
if err == nil || !rwcancel.ErrorIsEAGAIN(err) {
|
||||
if err == nil || !rwcancel.RetryAfterError(err) {
|
||||
break
|
||||
}
|
||||
if !tun.netlinkCancel.ReadyRead() {
|
||||
@@ -154,7 +157,7 @@ func (tun *NativeTun) RoutineNetlinkListener() {
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *NativeTun) isUp() (bool, error) {
|
||||
func (tun *nativeTun) isUp() (bool, error) {
|
||||
inter, err := net.InterfaceByName(tun.name)
|
||||
return inter.Flags&net.FlagUp != 0, err
|
||||
}
|
||||
@@ -188,11 +191,10 @@ func getIFIndex(name string) (int32, error) {
|
||||
return 0, errno
|
||||
}
|
||||
|
||||
index := binary.LittleEndian.Uint32(ifr[unix.IFNAMSIZ:])
|
||||
return toInt32(index), nil
|
||||
return *(*int32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])), nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) setMTU(n int) error {
|
||||
func (tun *nativeTun) setMTU(n int) error {
|
||||
|
||||
// open datagram socket
|
||||
|
||||
@@ -212,7 +214,7 @@ func (tun *NativeTun) setMTU(n int) error {
|
||||
|
||||
var ifr [ifReqSize]byte
|
||||
copy(ifr[:], tun.name)
|
||||
binary.LittleEndian.PutUint32(ifr[16:20], uint32(n))
|
||||
*(*uint32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = uint32(n)
|
||||
_, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
uintptr(fd),
|
||||
@@ -221,13 +223,13 @@ func (tun *NativeTun) setMTU(n int) error {
|
||||
)
|
||||
|
||||
if errno != 0 {
|
||||
return errors.New("Failed to set MTU of TUN device")
|
||||
return errors.New("failed to set MTU of TUN device")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) MTU() (int, error) {
|
||||
func (tun *nativeTun) MTU() (int, error) {
|
||||
|
||||
// open datagram socket
|
||||
|
||||
@@ -254,29 +256,23 @@ func (tun *NativeTun) MTU() (int, error) {
|
||||
uintptr(unsafe.Pointer(&ifr[0])),
|
||||
)
|
||||
if errno != 0 {
|
||||
return 0, errors.New("Failed to get MTU of TUN device: " + strconv.FormatInt(int64(errno), 10))
|
||||
return 0, errors.New("failed to get MTU of TUN device: " + strconv.FormatInt(int64(errno), 10))
|
||||
}
|
||||
|
||||
// convert result to signed 32-bit int
|
||||
|
||||
val := binary.LittleEndian.Uint32(ifr[16:20])
|
||||
if val >= (1 << 31) {
|
||||
return int(toInt32(val)), nil
|
||||
}
|
||||
return int(val), nil
|
||||
return int(*(*int32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ]))), nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Name() (string, error) {
|
||||
func (tun *nativeTun) Name() (string, error) {
|
||||
|
||||
var ifr [ifReqSize]byte
|
||||
_, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
tun.fd.Fd(),
|
||||
tun.fd,
|
||||
uintptr(unix.TUNGETIFF),
|
||||
uintptr(unsafe.Pointer(&ifr[0])),
|
||||
)
|
||||
if errno != 0 {
|
||||
return "", errors.New("Failed to get name of TUN device: " + strconv.FormatInt(int64(errno), 10))
|
||||
return "", errors.New("failed to get name of TUN device: " + strconv.FormatInt(int64(errno), 10))
|
||||
}
|
||||
nullStr := ifr[:]
|
||||
i := bytes.IndexByte(nullStr, 0)
|
||||
@@ -287,7 +283,7 @@ func (tun *NativeTun) Name() (string, error) {
|
||||
return tun.name, nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
|
||||
if tun.nopi {
|
||||
buff = buff[offset:]
|
||||
@@ -312,19 +308,19 @@ func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
|
||||
// write
|
||||
|
||||
return tun.fd.Write(buff)
|
||||
return tun.tunFile.Write(buff)
|
||||
}
|
||||
|
||||
func (tun *NativeTun) doRead(buff []byte, offset int) (int, error) {
|
||||
func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
|
||||
select {
|
||||
case err := <-tun.errors:
|
||||
return 0, err
|
||||
default:
|
||||
if tun.nopi {
|
||||
return tun.fd.Read(buff[offset:])
|
||||
return tun.tunFile.Read(buff[offset:])
|
||||
} else {
|
||||
buff := buff[offset-4:]
|
||||
n, err := tun.fd.Read(buff[:])
|
||||
n, err := tun.tunFile.Read(buff[:])
|
||||
if n < 4 {
|
||||
return 0, err
|
||||
}
|
||||
@@ -333,10 +329,10 @@ func (tun *NativeTun) doRead(buff []byte, offset int) (int, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
for {
|
||||
n, err := tun.doRead(buff, offset)
|
||||
if err == nil || !rwcancel.ErrorIsEAGAIN(err) {
|
||||
if err == nil || !rwcancel.RetryAfterError(err) {
|
||||
return n, err
|
||||
}
|
||||
if !tun.fdCancel.ReadyRead() {
|
||||
@@ -345,19 +341,22 @@ func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Events() chan TUNEvent {
|
||||
func (tun *nativeTun) Events() chan TUNEvent {
|
||||
return tun.events
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Close() error {
|
||||
func (tun *nativeTun) Close() error {
|
||||
var err1 error
|
||||
close(tun.statusListenersShutdown)
|
||||
if tun.netlinkCancel != nil {
|
||||
err1 = tun.netlinkCancel.Cancel()
|
||||
if tun.statusListenersShutdown != nil {
|
||||
close(tun.statusListenersShutdown)
|
||||
if tun.netlinkCancel != nil {
|
||||
err1 = tun.netlinkCancel.Cancel()
|
||||
}
|
||||
} else if tun.events != nil {
|
||||
close(tun.events)
|
||||
}
|
||||
err2 := tun.fd.Close()
|
||||
err2 := tun.tunFile.Close()
|
||||
err3 := tun.fdCancel.Cancel()
|
||||
close(tun.events)
|
||||
|
||||
if err1 != nil {
|
||||
return err1
|
||||
@@ -368,7 +367,7 @@ func (tun *NativeTun) Close() error {
|
||||
return err3
|
||||
}
|
||||
|
||||
func CreateTUN(name string) (TUNDevice, error) {
|
||||
func CreateTUN(name string, mtu int) (TUNDevice, error) {
|
||||
|
||||
// open clone device
|
||||
|
||||
@@ -398,7 +397,7 @@ func CreateTUN(name string) (TUNDevice, error) {
|
||||
return nil, errors.New("interface name too long")
|
||||
}
|
||||
copy(ifr[:], nameBytes)
|
||||
binary.LittleEndian.PutUint16(ifr[16:], flags)
|
||||
*(*uint16)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = flags
|
||||
|
||||
_, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
@@ -410,28 +409,29 @@ func CreateTUN(name string) (TUNDevice, error) {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
return CreateTUNFromFile(fd)
|
||||
return CreateTUNFromFile(fd, mtu)
|
||||
}
|
||||
|
||||
func CreateTUNFromFile(fd *os.File) (TUNDevice, error) {
|
||||
tun := &NativeTun{
|
||||
fd: fd,
|
||||
func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
tun := &nativeTun{
|
||||
tunFile: file,
|
||||
fd: file.Fd(),
|
||||
events: make(chan TUNEvent, 5),
|
||||
errors: make(chan error, 5),
|
||||
statusListenersShutdown: make(chan struct{}),
|
||||
nopi: false,
|
||||
nopi: false,
|
||||
}
|
||||
var err error
|
||||
|
||||
tun.fdCancel, err = rwcancel.NewRWCancel(int(fd.Fd()))
|
||||
tun.fdCancel, err = rwcancel.NewRWCancel(int(tun.fd))
|
||||
if err != nil {
|
||||
tun.fd.Close()
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = tun.Name()
|
||||
if err != nil {
|
||||
tun.fd.Close()
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -444,21 +444,20 @@ func CreateTUNFromFile(fd *os.File) (TUNDevice, error) {
|
||||
|
||||
tun.netlinkSock, err = createNetlinkSocket()
|
||||
if err != nil {
|
||||
tun.fd.Close()
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
tun.netlinkCancel, err = rwcancel.NewRWCancel(tun.netlinkSock)
|
||||
if err != nil {
|
||||
tun.fd.Close()
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go tun.RoutineNetlinkListener()
|
||||
go tun.RoutineHackListener() // cross namespace
|
||||
tun.hackListenerClosed.Lock()
|
||||
go tun.routineNetlinkListener()
|
||||
go tun.routineHackListener() // cross namespace
|
||||
|
||||
// set default MTU
|
||||
|
||||
err = tun.setMTU(DefaultMTU)
|
||||
err = tun.setMTU(mtu)
|
||||
if err != nil {
|
||||
tun.Close()
|
||||
return nil, err
|
||||
348
tun/tun_openbsd.go
Normal file
348
tun/tun_openbsd.go
Normal file
@@ -0,0 +1,348 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.zx2c4.com/wireguard-go/rwcancel"
|
||||
"golang.org/x/net/ipv6"
|
||||
"golang.org/x/sys/unix"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Structure for iface mtu get/set ioctls
|
||||
type ifreq_mtu struct {
|
||||
Name [unix.IFNAMSIZ]byte
|
||||
MTU uint32
|
||||
Pad0 [12]byte
|
||||
}
|
||||
|
||||
const _TUNSIFMODE = 0x8004745d
|
||||
|
||||
type nativeTun struct {
|
||||
name string
|
||||
tunFile *os.File
|
||||
rwcancel *rwcancel.RWCancel
|
||||
events chan TUNEvent
|
||||
errors chan error
|
||||
routeSocket int
|
||||
}
|
||||
|
||||
func (tun *nativeTun) routineRouteListener(tunIfindex int) {
|
||||
var (
|
||||
statusUp bool
|
||||
statusMTU int
|
||||
)
|
||||
|
||||
defer close(tun.events)
|
||||
|
||||
data := make([]byte, os.Getpagesize())
|
||||
for {
|
||||
retry:
|
||||
n, err := unix.Read(tun.routeSocket, data)
|
||||
if err != nil {
|
||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINTR {
|
||||
goto retry
|
||||
}
|
||||
tun.errors <- err
|
||||
return
|
||||
}
|
||||
|
||||
if n < 8 {
|
||||
continue
|
||||
}
|
||||
|
||||
if data[3 /* type */] != unix.RTM_IFINFO {
|
||||
continue
|
||||
}
|
||||
ifindex := int(*(*uint16)(unsafe.Pointer(&data[6 /* ifindex */])))
|
||||
if ifindex != tunIfindex {
|
||||
continue
|
||||
}
|
||||
|
||||
iface, err := net.InterfaceByIndex(ifindex)
|
||||
if err != nil {
|
||||
tun.errors <- err
|
||||
return
|
||||
}
|
||||
|
||||
// Up / Down event
|
||||
up := (iface.Flags & net.FlagUp) != 0
|
||||
if up != statusUp && up {
|
||||
tun.events <- TUNEventUp
|
||||
}
|
||||
if up != statusUp && !up {
|
||||
tun.events <- TUNEventDown
|
||||
}
|
||||
statusUp = up
|
||||
|
||||
// MTU changes
|
||||
if iface.MTU != statusMTU {
|
||||
tun.events <- TUNEventMTUUpdate
|
||||
}
|
||||
statusMTU = iface.MTU
|
||||
}
|
||||
}
|
||||
|
||||
func errorIsEBUSY(err error) bool {
|
||||
if pe, ok := err.(*os.PathError); ok {
|
||||
err = pe.Err
|
||||
}
|
||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.EBUSY {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func CreateTUN(name string, mtu int) (TUNDevice, error) {
|
||||
ifIndex := -1
|
||||
if name != "tun" {
|
||||
_, err := fmt.Sscanf(name, "tun%d", &ifIndex)
|
||||
if err != nil || ifIndex < 0 {
|
||||
return nil, fmt.Errorf("Interface name must be tun[0-9]*")
|
||||
}
|
||||
}
|
||||
|
||||
var tunfile *os.File
|
||||
var err error
|
||||
|
||||
if ifIndex != -1 {
|
||||
tunfile, err = os.OpenFile(fmt.Sprintf("/dev/tun%d", ifIndex), unix.O_RDWR, 0)
|
||||
} else {
|
||||
for ifIndex = 0; ifIndex < 256; ifIndex += 1 {
|
||||
tunfile, err = os.OpenFile(fmt.Sprintf("/dev/tun%d", ifIndex), unix.O_RDWR, 0)
|
||||
if err == nil || !errorIsEBUSY(err) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun, err := CreateTUNFromFile(tunfile, mtu)
|
||||
|
||||
if err == nil && name == "tun" {
|
||||
fname := os.Getenv("WG_TUN_NAME_FILE")
|
||||
if fname != "" {
|
||||
ioutil.WriteFile(fname, []byte(tun.(*nativeTun).name+"\n"), 0400)
|
||||
}
|
||||
}
|
||||
|
||||
return tun, err
|
||||
}
|
||||
|
||||
func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
|
||||
tun := &nativeTun{
|
||||
tunFile: file,
|
||||
events: make(chan TUNEvent, 10),
|
||||
errors: make(chan error, 1),
|
||||
}
|
||||
|
||||
name, err := tun.Name()
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tunIfindex, err := func() (int, error) {
|
||||
iface, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return iface.Index, nil
|
||||
}()
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun.rwcancel, err = rwcancel.NewRWCancel(int(file.Fd()))
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go tun.routineRouteListener(tunIfindex)
|
||||
|
||||
err = tun.setMTU(mtu)
|
||||
if err != nil {
|
||||
tun.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tun, nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Name() (string, error) {
|
||||
gostat, err := tun.tunFile.Stat()
|
||||
if err != nil {
|
||||
tun.name = ""
|
||||
return "", err
|
||||
}
|
||||
stat := gostat.Sys().(*syscall.Stat_t)
|
||||
tun.name = fmt.Sprintf("tun%d", stat.Rdev%256)
|
||||
return tun.name, nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) File() *os.File {
|
||||
return tun.tunFile
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Events() chan TUNEvent {
|
||||
return tun.events
|
||||
}
|
||||
|
||||
func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
|
||||
select {
|
||||
case err := <-tun.errors:
|
||||
return 0, err
|
||||
default:
|
||||
buff := buff[offset-4:]
|
||||
n, err := tun.tunFile.Read(buff[:])
|
||||
if n < 4 {
|
||||
return 0, err
|
||||
}
|
||||
return n - 4, err
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
for {
|
||||
n, err := tun.doRead(buff, offset)
|
||||
if err == nil || !rwcancel.RetryAfterError(err) {
|
||||
return n, err
|
||||
}
|
||||
if !tun.rwcancel.ReadyRead() {
|
||||
return 0, errors.New("tun device closed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
|
||||
// reserve space for header
|
||||
|
||||
buff = buff[offset-4:]
|
||||
|
||||
// add packet information header
|
||||
|
||||
buff[0] = 0x00
|
||||
buff[1] = 0x00
|
||||
buff[2] = 0x00
|
||||
|
||||
if buff[4]>>4 == ipv6.Version {
|
||||
buff[3] = unix.AF_INET6
|
||||
} else {
|
||||
buff[3] = unix.AF_INET
|
||||
}
|
||||
|
||||
// write
|
||||
|
||||
return tun.tunFile.Write(buff)
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Close() error {
|
||||
var err3 error
|
||||
err1 := tun.rwcancel.Cancel()
|
||||
err2 := tun.tunFile.Close()
|
||||
if tun.routeSocket != -1 {
|
||||
unix.Shutdown(tun.routeSocket, unix.SHUT_RDWR)
|
||||
err3 = unix.Close(tun.routeSocket)
|
||||
tun.routeSocket = -1
|
||||
} else if tun.events != nil {
|
||||
close(tun.events)
|
||||
}
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
return err3
|
||||
}
|
||||
|
||||
func (tun *nativeTun) setMTU(n int) error {
|
||||
// open datagram socket
|
||||
|
||||
var fd int
|
||||
|
||||
fd, err := unix.Socket(
|
||||
unix.AF_INET,
|
||||
unix.SOCK_DGRAM,
|
||||
0,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer unix.Close(fd)
|
||||
|
||||
// do ioctl call
|
||||
|
||||
var ifr ifreq_mtu
|
||||
copy(ifr.Name[:], tun.name)
|
||||
ifr.MTU = uint32(n)
|
||||
|
||||
_, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
uintptr(fd),
|
||||
uintptr(unix.SIOCSIFMTU),
|
||||
uintptr(unsafe.Pointer(&ifr)),
|
||||
)
|
||||
|
||||
if errno != 0 {
|
||||
return fmt.Errorf("failed to set MTU on %s", tun.name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) MTU() (int, error) {
|
||||
// open datagram socket
|
||||
|
||||
fd, err := unix.Socket(
|
||||
unix.AF_INET,
|
||||
unix.SOCK_DGRAM,
|
||||
0,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
defer unix.Close(fd)
|
||||
|
||||
// do ioctl call
|
||||
var ifr ifreq_mtu
|
||||
copy(ifr.Name[:], tun.name)
|
||||
|
||||
_, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
uintptr(fd),
|
||||
uintptr(unix.SIOCGIFMTU),
|
||||
uintptr(unsafe.Pointer(&ifr)),
|
||||
)
|
||||
if errno != 0 {
|
||||
return 0, fmt.Errorf("failed to get MTU on %s", tun.name)
|
||||
}
|
||||
|
||||
return int(*(*int32)(unsafe.Pointer(&ifr.MTU))), nil
|
||||
}
|
||||
483
tun_windows.go
483
tun_windows.go
@@ -1,483 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/registry"
|
||||
"net"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
/* Relies on the OpenVPN TAP-Windows driver (NDIS 6 version)
|
||||
*
|
||||
* https://github.com/OpenVPN/tap-windows
|
||||
*/
|
||||
|
||||
type NativeTUN struct {
|
||||
fd windows.Handle
|
||||
rl sync.Mutex
|
||||
wl sync.Mutex
|
||||
ro *windows.Overlapped
|
||||
wo *windows.Overlapped
|
||||
events chan TUNEvent
|
||||
name string
|
||||
}
|
||||
|
||||
const (
|
||||
METHOD_BUFFERED = 0
|
||||
ComponentID = "tap0901" // tap0801
|
||||
)
|
||||
|
||||
func ctl_code(device_type, function, method, access uint32) uint32 {
|
||||
return (device_type << 16) | (access << 14) | (function << 2) | method
|
||||
}
|
||||
|
||||
func TAP_CONTROL_CODE(request, method uint32) uint32 {
|
||||
return ctl_code(file_device_unknown, request, method, 0)
|
||||
}
|
||||
|
||||
var (
|
||||
errIfceNameNotFound = errors.New("Failed to find the name of interface")
|
||||
|
||||
TAP_IOCTL_GET_MAC = TAP_CONTROL_CODE(1, METHOD_BUFFERED)
|
||||
TAP_IOCTL_GET_VERSION = TAP_CONTROL_CODE(2, METHOD_BUFFERED)
|
||||
TAP_IOCTL_GET_MTU = TAP_CONTROL_CODE(3, METHOD_BUFFERED)
|
||||
TAP_IOCTL_GET_INFO = TAP_CONTROL_CODE(4, METHOD_BUFFERED)
|
||||
TAP_IOCTL_CONFIG_POINT_TO_POINT = TAP_CONTROL_CODE(5, METHOD_BUFFERED)
|
||||
TAP_IOCTL_SET_MEDIA_STATUS = TAP_CONTROL_CODE(6, METHOD_BUFFERED)
|
||||
TAP_IOCTL_CONFIG_DHCP_MASQ = TAP_CONTROL_CODE(7, METHOD_BUFFERED)
|
||||
TAP_IOCTL_GET_LOG_LINE = TAP_CONTROL_CODE(8, METHOD_BUFFERED)
|
||||
TAP_IOCTL_CONFIG_DHCP_SET_OPT = TAP_CONTROL_CODE(9, METHOD_BUFFERED)
|
||||
TAP_IOCTL_CONFIG_TUN = TAP_CONTROL_CODE(10, METHOD_BUFFERED)
|
||||
|
||||
file_device_unknown = uint32(0x00000022)
|
||||
nCreateEvent,
|
||||
nResetEvent,
|
||||
nGetOverlappedResult uintptr
|
||||
)
|
||||
|
||||
func init() {
|
||||
k32, err := windows.LoadLibrary("kernel32.dll")
|
||||
if err != nil {
|
||||
panic("LoadLibrary " + err.Error())
|
||||
}
|
||||
defer windows.FreeLibrary(k32)
|
||||
nCreateEvent = getProcAddr(k32, "CreateEventW")
|
||||
nResetEvent = getProcAddr(k32, "ResetEvent")
|
||||
nGetOverlappedResult = getProcAddr(k32, "GetOverlappedResult")
|
||||
}
|
||||
|
||||
/* implementation of the read/write/closer interface */
|
||||
|
||||
func getProcAddr(lib windows.Handle, name string) uintptr {
|
||||
addr, err := windows.GetProcAddress(lib, name)
|
||||
if err != nil {
|
||||
panic(name + " " + err.Error())
|
||||
}
|
||||
return addr
|
||||
}
|
||||
|
||||
func resetEvent(h windows.Handle) error {
|
||||
r, _, err := syscall.Syscall(nResetEvent, 1, uintptr(h), 0, 0)
|
||||
if r == 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getOverlappedResult(h windows.Handle, overlapped *windows.Overlapped) (int, error) {
|
||||
var n int
|
||||
r, _, err := syscall.Syscall6(
|
||||
nGetOverlappedResult,
|
||||
4,
|
||||
uintptr(h),
|
||||
uintptr(unsafe.Pointer(overlapped)),
|
||||
uintptr(unsafe.Pointer(&n)), 1, 0, 0)
|
||||
|
||||
if r == 0 {
|
||||
return n, err
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func newOverlapped() (*windows.Overlapped, error) {
|
||||
var overlapped windows.Overlapped
|
||||
r, _, err := syscall.Syscall6(nCreateEvent, 4, 0, 1, 0, 0, 0, 0)
|
||||
if r == 0 {
|
||||
return nil, err
|
||||
}
|
||||
overlapped.HEvent = windows.Handle(r)
|
||||
return &overlapped, nil
|
||||
}
|
||||
|
||||
func (f *NativeTUN) Events() chan TUNEvent {
|
||||
return f.events
|
||||
}
|
||||
|
||||
func (f *NativeTUN) Close() error {
|
||||
close(f.events)
|
||||
err := windows.Close(f.fd)
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *NativeTUN) Write(b []byte) (int, error) {
|
||||
f.wl.Lock()
|
||||
defer f.wl.Unlock()
|
||||
|
||||
if err := resetEvent(f.wo.HEvent); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var n uint32
|
||||
err := windows.WriteFile(f.fd, b, &n, f.wo)
|
||||
if err != nil && err != windows.ERROR_IO_PENDING {
|
||||
return int(n), err
|
||||
}
|
||||
return getOverlappedResult(f.fd, f.wo)
|
||||
}
|
||||
|
||||
func (f *NativeTUN) Read(b []byte) (int, error) {
|
||||
f.rl.Lock()
|
||||
defer f.rl.Unlock()
|
||||
|
||||
if err := resetEvent(f.ro.HEvent); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var done uint32
|
||||
err := windows.ReadFile(f.fd, b, &done, f.ro)
|
||||
if err != nil && err != windows.ERROR_IO_PENDING {
|
||||
return int(done), err
|
||||
}
|
||||
return getOverlappedResult(f.fd, f.ro)
|
||||
}
|
||||
|
||||
func getdeviceid(
|
||||
targetComponentId string,
|
||||
targetDeviceName string,
|
||||
) (deviceid string, err error) {
|
||||
|
||||
getName := func(instanceId string) (string, error) {
|
||||
path := fmt.Sprintf(
|
||||
`SYSTEM\CurrentControlSet\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}\%s\Connection`,
|
||||
instanceId,
|
||||
)
|
||||
|
||||
key, err := registry.OpenKey(
|
||||
registry.LOCAL_MACHINE,
|
||||
path,
|
||||
registry.READ,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer key.Close()
|
||||
|
||||
val, _, err := key.GetStringValue("Name")
|
||||
key.Close()
|
||||
return val, err
|
||||
}
|
||||
|
||||
getInstanceId := func(keyName string) (string, string, error) {
|
||||
path := fmt.Sprintf(
|
||||
`SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\%s`,
|
||||
keyName,
|
||||
)
|
||||
|
||||
key, err := registry.OpenKey(
|
||||
registry.LOCAL_MACHINE,
|
||||
path,
|
||||
registry.READ,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
defer key.Close()
|
||||
|
||||
componentId, _, err := key.GetStringValue("ComponentId")
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
instanceId, _, err := key.GetStringValue("NetCfgInstanceId")
|
||||
|
||||
return componentId, instanceId, err
|
||||
}
|
||||
|
||||
// find list of all network devices
|
||||
|
||||
k, err := registry.OpenKey(
|
||||
registry.LOCAL_MACHINE,
|
||||
`SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}`,
|
||||
registry.READ,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Failed to open the adapter registry, TAP driver may be not installed, %v", err)
|
||||
}
|
||||
|
||||
defer k.Close()
|
||||
|
||||
keys, err := k.ReadSubKeyNames(-1)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// look for matching component id and name
|
||||
|
||||
var componentFound bool
|
||||
|
||||
for _, v := range keys {
|
||||
|
||||
componentId, instanceId, err := getInstanceId(v)
|
||||
if err != nil || componentId != targetComponentId {
|
||||
continue
|
||||
}
|
||||
|
||||
componentFound = true
|
||||
|
||||
deviceName, err := getName(instanceId)
|
||||
if err != nil || deviceName != targetDeviceName {
|
||||
continue
|
||||
}
|
||||
|
||||
return instanceId, nil
|
||||
}
|
||||
|
||||
// provide a descriptive error message
|
||||
|
||||
if componentFound {
|
||||
return "", fmt.Errorf("Unable to find tun/tap device with name = %s", targetDeviceName)
|
||||
}
|
||||
|
||||
return "", fmt.Errorf(
|
||||
"Unable to find device in registry with ComponentId = %s, is tap-windows installed?",
|
||||
targetComponentId,
|
||||
)
|
||||
}
|
||||
|
||||
// setStatus is used to bring up or bring down the interface
|
||||
func setStatus(fd windows.Handle, status bool) error {
|
||||
var code [4]byte
|
||||
if status {
|
||||
binary.LittleEndian.PutUint32(code[:], 1)
|
||||
}
|
||||
|
||||
var bytesReturned uint32
|
||||
rdbbuf := make([]byte, windows.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
|
||||
return windows.DeviceIoControl(
|
||||
fd,
|
||||
TAP_IOCTL_SET_MEDIA_STATUS,
|
||||
&code[0],
|
||||
uint32(4),
|
||||
&rdbbuf[0],
|
||||
uint32(len(rdbbuf)),
|
||||
&bytesReturned,
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
/* When operating in TUN mode we must assign an ip address & subnet to the device.
|
||||
*
|
||||
*/
|
||||
func setTUN(fd windows.Handle, network string) error {
|
||||
var bytesReturned uint32
|
||||
rdbbuf := make([]byte, windows.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
|
||||
localIP, remoteNet, err := net.ParseCIDR(network)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to parse network CIDR in config, %v", err)
|
||||
}
|
||||
|
||||
if localIP.To4() == nil {
|
||||
return fmt.Errorf("Provided network(%s) is not a valid IPv4 address", network)
|
||||
}
|
||||
|
||||
var param [12]byte
|
||||
|
||||
copy(param[0:4], localIP.To4())
|
||||
copy(param[4:8], remoteNet.IP.To4())
|
||||
copy(param[8:12], remoteNet.Mask)
|
||||
|
||||
return windows.DeviceIoControl(
|
||||
fd,
|
||||
TAP_IOCTL_CONFIG_TUN,
|
||||
¶m[0],
|
||||
uint32(12),
|
||||
&rdbbuf[0],
|
||||
uint32(len(rdbbuf)),
|
||||
&bytesReturned,
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
func (tun *NativeTUN) MTU() (int, error) {
|
||||
var mtu [4]byte
|
||||
var bytesReturned uint32
|
||||
err := windows.DeviceIoControl(
|
||||
tun.fd,
|
||||
TAP_IOCTL_GET_MTU,
|
||||
&mtu[0],
|
||||
uint32(len(mtu)),
|
||||
&mtu[0],
|
||||
uint32(len(mtu)),
|
||||
&bytesReturned,
|
||||
nil,
|
||||
)
|
||||
val := binary.LittleEndian.Uint32(mtu[:])
|
||||
return int(val), err
|
||||
}
|
||||
|
||||
func (tun *NativeTUN) Name() string {
|
||||
return tun.name
|
||||
}
|
||||
|
||||
func CreateTUN(name string) (TUNDevice, error) {
|
||||
|
||||
// find the device in registry.
|
||||
|
||||
deviceid, err := getdeviceid(ComponentID, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path := "\\\\.\\Global\\" + deviceid + ".tap"
|
||||
pathp, err := windows.UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create TUN device
|
||||
|
||||
handle, err := windows.CreateFile(
|
||||
pathp,
|
||||
windows.GENERIC_READ|windows.GENERIC_WRITE,
|
||||
0,
|
||||
nil,
|
||||
windows.OPEN_EXISTING,
|
||||
windows.FILE_ATTRIBUTE_SYSTEM|windows.FILE_FLAG_OVERLAPPED,
|
||||
0,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ro, err := newOverlapped()
|
||||
if err != nil {
|
||||
windows.Close(handle)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wo, err := newOverlapped()
|
||||
if err != nil {
|
||||
windows.Close(handle)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun := &NativeTUN{
|
||||
fd: handle,
|
||||
name: name,
|
||||
ro: ro,
|
||||
wo: wo,
|
||||
events: make(chan TUNEvent, 5),
|
||||
}
|
||||
|
||||
// find addresses of interface
|
||||
// TODO: fix this hack, the question is how
|
||||
|
||||
inter, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
windows.Close(handle)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
addrs, err := inter.Addrs()
|
||||
if err != nil {
|
||||
windows.Close(handle)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ip net.IP
|
||||
for _, addr := range addrs {
|
||||
ip = func() net.IP {
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
return v.IP.To4()
|
||||
case *net.IPAddr:
|
||||
return v.IP.To4()
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
if ip != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ip == nil {
|
||||
windows.Close(handle)
|
||||
return nil, errors.New("No IPv4 address found for interface")
|
||||
}
|
||||
|
||||
// bring up device.
|
||||
|
||||
if err := setStatus(handle, true); err != nil {
|
||||
windows.Close(handle)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// set tun mode
|
||||
|
||||
mask := ip.String() + "/0"
|
||||
if err := setTUN(handle, mask); err != nil {
|
||||
windows.Close(handle)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// start listener
|
||||
|
||||
go func(native *NativeTUN, ifname string) {
|
||||
// TODO: Fix this very niave implementation
|
||||
var (
|
||||
statusUp bool
|
||||
statusMTU int
|
||||
)
|
||||
|
||||
for ; ; time.Sleep(time.Second) {
|
||||
intr, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
// TODO: handle
|
||||
return
|
||||
}
|
||||
|
||||
// Up / Down event
|
||||
up := (intr.Flags & net.FlagUp) != 0
|
||||
if up != statusUp && up {
|
||||
native.events <- TUNEventUp
|
||||
}
|
||||
if up != statusUp && !up {
|
||||
native.events <- TUNEventDown
|
||||
}
|
||||
statusUp = up
|
||||
|
||||
// MTU changes
|
||||
if intr.MTU != statusMTU {
|
||||
native.events <- TUNEventMTUUpdate
|
||||
}
|
||||
statusMTU = intr.MTU
|
||||
}
|
||||
}(tun, name)
|
||||
|
||||
return tun, nil
|
||||
}
|
||||
49
uapi.go
49
uapi.go
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
@@ -75,6 +74,7 @@ func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
|
||||
send("public_key=" + peer.handshake.remoteStatic.ToHex())
|
||||
send("preshared_key=" + peer.handshake.presharedKey.ToHex())
|
||||
send("protocol_version=1")
|
||||
if peer.endpoint != nil {
|
||||
send("endpoint=" + peer.endpoint.DstToString())
|
||||
}
|
||||
@@ -85,8 +85,8 @@ func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
|
||||
send(fmt.Sprintf("last_handshake_time_sec=%d", secs))
|
||||
send(fmt.Sprintf("last_handshake_time_nsec=%d", nano))
|
||||
send(fmt.Sprintf("tx_bytes=%d", peer.stats.txBytes))
|
||||
send(fmt.Sprintf("rx_bytes=%d", peer.stats.rxBytes))
|
||||
send(fmt.Sprintf("tx_bytes=%d", atomic.LoadUint64(&peer.stats.txBytes)))
|
||||
send(fmt.Sprintf("rx_bytes=%d", atomic.LoadUint64(&peer.stats.rxBytes)))
|
||||
send(fmt.Sprintf("persistent_keepalive_interval=%d", peer.persistentKeepaliveInterval))
|
||||
|
||||
for _, ip := range device.allowedips.EntriesForPeer(peer) {
|
||||
@@ -147,7 +147,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
logError.Println("Failed to set private_key:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
logDebug.Println("UAPI: Updating device private key")
|
||||
logDebug.Println("UAPI: Updating private key")
|
||||
device.SetPrivateKey(sk)
|
||||
|
||||
case "listen_port":
|
||||
@@ -211,7 +211,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
device.RemoveAllPeers()
|
||||
|
||||
default:
|
||||
logError.Println("Invalid UAPI key (device configuration):", key)
|
||||
logError.Println("Invalid UAPI device key:", key)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
}
|
||||
@@ -226,7 +226,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
var publicKey NoisePublicKey
|
||||
err := publicKey.FromHex(value)
|
||||
if err != nil {
|
||||
logError.Println("Failed to get peer by public_key:", err)
|
||||
logError.Println("Failed to get peer by public key:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
logError.Println("Failed to create new peer:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
logDebug.Println("UAPI: Created new peer:", peer)
|
||||
logDebug.Println(peer, "- UAPI: Created")
|
||||
}
|
||||
|
||||
case "remove":
|
||||
@@ -260,7 +260,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
if !dummy {
|
||||
logDebug.Println("UAPI: Removing peer:", peer)
|
||||
logDebug.Println(peer, "- UAPI: Removing")
|
||||
device.RemovePeer(peer.handshake.remoteStatic)
|
||||
}
|
||||
peer = &Peer{}
|
||||
@@ -270,14 +270,14 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
|
||||
// update PSK
|
||||
|
||||
logDebug.Println("UAPI: Updating pre-shared key for peer:", peer)
|
||||
logDebug.Println(peer, "- UAPI: Updating preshared key")
|
||||
|
||||
peer.handshake.mutex.Lock()
|
||||
err := peer.handshake.presharedKey.FromHex(value)
|
||||
peer.handshake.mutex.Unlock()
|
||||
|
||||
if err != nil {
|
||||
logError.Println("Failed to set preshared_key:", err)
|
||||
logError.Println("Failed to set preshared key:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
|
||||
// set endpoint destination
|
||||
|
||||
logDebug.Println("UAPI: Updating endpoint for peer:", peer)
|
||||
logDebug.Println(peer, "- UAPI: Updating endpoint")
|
||||
|
||||
err := func() error {
|
||||
peer.mutex.Lock()
|
||||
@@ -307,11 +307,11 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
|
||||
// update persistent keepalive interval
|
||||
|
||||
logDebug.Println("UAPI: Updating persistent_keepalive_interval for peer:", peer)
|
||||
logDebug.Println(peer, "- UAPI: Updating persistent keepalive interva")
|
||||
|
||||
secs, err := strconv.ParseUint(value, 10, 16)
|
||||
if err != nil {
|
||||
logError.Println("Failed to set persistent_keepalive_interval:", err)
|
||||
logError.Println("Failed to set persistent keepalive interval:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
|
||||
@@ -332,10 +332,10 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
|
||||
case "replace_allowed_ips":
|
||||
|
||||
logDebug.Println("UAPI: Removing all allowedips for peer:", peer)
|
||||
logDebug.Println(peer, "- UAPI: Removing all allowedips")
|
||||
|
||||
if value != "true" {
|
||||
logError.Println("Failed to set replace_allowed_ips, invalid value:", value)
|
||||
logError.Println("Failed to replace allowedips, invalid value:", value)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
|
||||
@@ -347,11 +347,11 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
|
||||
case "allowed_ip":
|
||||
|
||||
logDebug.Println("UAPI: Adding allowed_ip to peer:", peer)
|
||||
logDebug.Println(peer, "- UAPI: Adding allowedip")
|
||||
|
||||
_, network, err := net.ParseCIDR(value)
|
||||
if err != nil {
|
||||
logError.Println("Failed to set allowed_ip:", err)
|
||||
logError.Println("Failed to set allowed ip:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
|
||||
@@ -362,8 +362,15 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
ones, _ := network.Mask.Size()
|
||||
device.allowedips.Insert(network.IP, uint(ones), peer)
|
||||
|
||||
case "protocol_version":
|
||||
|
||||
if value != "1" {
|
||||
logError.Println("Invalid protocol version:", value)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
|
||||
default:
|
||||
logError.Println("Invalid UAPI key (peer configuration):", key)
|
||||
logError.Println("Invalid UAPI peer key:", key)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
}
|
||||
@@ -397,11 +404,11 @@ func ipcHandle(device *Device, socket net.Conn) {
|
||||
|
||||
switch op {
|
||||
case "set=1\n":
|
||||
device.log.Debug.Println("Config, set operation")
|
||||
device.log.Debug.Println("UAPI: Set operation")
|
||||
status = ipcSetOperation(device, buffered)
|
||||
|
||||
case "get=1\n":
|
||||
device.log.Debug.Println("Config, get operation")
|
||||
device.log.Debug.Println("UAPI: Get operation")
|
||||
status = ipcGetOperation(device, buffered)
|
||||
|
||||
default:
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// +build darwin freebsd openbsd
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
@@ -13,14 +14,16 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var socketDirectory = "/var/run/wireguard"
|
||||
|
||||
const (
|
||||
ipcErrorIO = -int64(unix.EIO)
|
||||
ipcErrorProtocol = -int64(unix.EPROTO)
|
||||
ipcErrorInvalid = -int64(unix.EINVAL)
|
||||
ipcErrorPortInUse = -int64(unix.EADDRINUSE)
|
||||
socketDirectory = "/var/run/wireguard"
|
||||
socketName = "%s.sock"
|
||||
)
|
||||
|
||||
@@ -91,7 +94,7 @@ func UAPIListen(name string, file *os.File) (net.Listener, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uapi.keventFd, err = unix.Open(socketDirectory, unix.O_EVTONLY, 0)
|
||||
uapi.keventFd, err = unix.Open(socketDirectory, unix.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
unix.Close(uapi.kqueueFd)
|
||||
return nil, err
|
||||
@@ -99,11 +102,13 @@ func UAPIListen(name string, file *os.File) (net.Listener, error) {
|
||||
|
||||
go func(l *UAPIListener) {
|
||||
event := unix.Kevent_t{
|
||||
Ident: uint64(uapi.keventFd),
|
||||
Filter: unix.EVFILT_VNODE,
|
||||
Flags: unix.EV_ADD | unix.EV_ENABLE | unix.EV_ONESHOT,
|
||||
Fflags: unix.NOTE_WRITE,
|
||||
}
|
||||
// Allow this assignment to work with both the 32-bit and 64-bit version
|
||||
// of the above struct. If you know another way, please submit a patch.
|
||||
*(*uintptr)(unsafe.Pointer(&event.Ident)) = uintptr(uapi.keventFd)
|
||||
events := make([]unix.Kevent_t, 1)
|
||||
n := 1
|
||||
var kerr error
|
||||
@@ -145,7 +150,7 @@ func UAPIOpen(name string) (*os.File, error) {
|
||||
|
||||
// check if path exist
|
||||
|
||||
err := os.MkdirAll(socketDirectory, 0700)
|
||||
err := os.MkdirAll(socketDirectory, 0755)
|
||||
if err != nil && !os.IsExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
@@ -162,6 +167,7 @@ func UAPIOpen(name string) (*os.File, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oldUmask := unix.Umask(0077)
|
||||
listener, err := func() (*net.UnixListener, error) {
|
||||
|
||||
// initial connection attempt
|
||||
@@ -186,6 +192,7 @@ func UAPIOpen(name string) (*os.File, error) {
|
||||
}
|
||||
return net.ListenUnix("unix", addr)
|
||||
}()
|
||||
unix.Umask(oldUmask)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1,27 +1,27 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"./rwcancel"
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.zx2c4.com/wireguard-go/rwcancel"
|
||||
"golang.org/x/sys/unix"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
var socketDirectory = "/var/run/wireguard"
|
||||
|
||||
const (
|
||||
ipcErrorIO = -int64(unix.EIO)
|
||||
ipcErrorProtocol = -int64(unix.EPROTO)
|
||||
ipcErrorInvalid = -int64(unix.EINVAL)
|
||||
ipcErrorPortInUse = -int64(unix.EADDRINUSE)
|
||||
socketDirectory = "/var/run/wireguard"
|
||||
socketName = "%s.sock"
|
||||
)
|
||||
|
||||
@@ -147,7 +147,7 @@ func UAPIOpen(name string) (*os.File, error) {
|
||||
|
||||
// check if path exist
|
||||
|
||||
err := os.MkdirAll(socketDirectory, 0700)
|
||||
err := os.MkdirAll(socketDirectory, 0755)
|
||||
if err != nil && !os.IsExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
@@ -164,6 +164,7 @@ func UAPIOpen(name string) (*os.File, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oldUmask := unix.Umask(0077)
|
||||
listener, err := func() (*net.UnixListener, error) {
|
||||
|
||||
// initial connection attempt
|
||||
@@ -188,6 +189,7 @@ func UAPIOpen(name string) (*os.File, error) {
|
||||
}
|
||||
return net.ListenUnix("unix", addr)
|
||||
}()
|
||||
unix.Umask(oldUmask)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
/* UAPI on windows uses a bidirectional named pipe
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Microsoft/go-winio"
|
||||
"golang.org/x/sys/windows"
|
||||
"net"
|
||||
)
|
||||
|
||||
const (
|
||||
ipcErrorIO = -int64(windows.ERROR_BROKEN_PIPE)
|
||||
ipcErrorProtocol = -int64(windows.ERROR_INVALID_NAME)
|
||||
ipcErrorInvalid = -int64(windows.ERROR_INVALID_PARAMETER)
|
||||
ipcErrorPortInUse = -int64(windows.ERROR_ALREADY_EXISTS)
|
||||
)
|
||||
|
||||
const PipeNameFmt = "\\\\.\\pipe\\wireguard-ipc-%s"
|
||||
|
||||
type UAPIListener struct {
|
||||
listener net.Listener
|
||||
}
|
||||
|
||||
func (uapi *UAPIListener) Accept() (net.Conn, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (uapi *UAPIListener) Close() error {
|
||||
return uapi.listener.Close()
|
||||
}
|
||||
|
||||
func (uapi *UAPIListener) Addr() net.Addr {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewUAPIListener(name string) (net.Listener, error) {
|
||||
path := fmt.Sprintf(PipeNameFmt, name)
|
||||
return winio.ListenPipe(path, &winio.PipeConfig{
|
||||
InputBufferSize: 2048,
|
||||
OutputBufferSize: 2048,
|
||||
})
|
||||
}
|
||||
2
version.go
Normal file
2
version.go
Normal file
@@ -0,0 +1,2 @@
|
||||
package main
|
||||
const WireGuardGoVersion = "0.0.20181018"
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2016 Andreas Auernhammer. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package xchacha20poly1305
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package xchacha20poly1305
|
||||
|
||||
Reference in New Issue
Block a user