Compare commits
63 Commits
0.0.201805
...
0.0.201806
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
|
||||
|
||||
34
Gopkg.lock
generated
34
Gopkg.lock
generated
@@ -1,16 +1,42 @@
|
||||
# This was generated by ./generate-vendor.sh
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
revision = "1a580b3eff7814fc9b40602fd35256c63b50f491"
|
||||
packages = [
|
||||
"blake2s",
|
||||
"chacha20poly1305",
|
||||
"curve25519",
|
||||
"internal/chacha20",
|
||||
"poly1305"
|
||||
]
|
||||
revision = "ab813273cd59e1333f7ae7bff5d027d4aadf528c"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/net"
|
||||
revision = "2491c5de3490fced2f6cff376127c667efeed857"
|
||||
packages = [
|
||||
"bpf",
|
||||
"internal/iana",
|
||||
"internal/socket",
|
||||
"ipv4",
|
||||
"ipv6"
|
||||
]
|
||||
revision = "dfa909b99c79129e1100513e5cd36307665e5723"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
revision = "7c87d13f8e835d2fb3a70a2912c811ed0c1d241b"
|
||||
packages = [
|
||||
"cpu",
|
||||
"unix"
|
||||
]
|
||||
revision = "c11f84a56e43e20a78cee75a7c034031ecf57d1f"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "d85ae9d2b4afafc3d7535505c46368cbbbec350cf876616302c1bcf44f6ec103"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# This was generated by ./generate-vendor.sh
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
@@ -11,3 +10,6 @@
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
|
||||
43
Makefile
43
Makefile
@@ -2,15 +2,50 @@ PREFIX ?= /usr
|
||||
DESTDIR ?=
|
||||
BINDIR ?= $(PREFIX)/bin
|
||||
|
||||
ifeq ($(shell go env GOOS),linux)
|
||||
ifeq ($(wildcard .git),)
|
||||
$(error Do not build this for Linux. Instead use the Linux kernel module. See wireguard.com/install/ for more info.)
|
||||
else
|
||||
$(shell printf 'package main\nconst UseTheKernelModuleInstead = 0xdeadbabe\n' > ireallywantobuildon_linux.go)
|
||||
endif
|
||||
endif
|
||||
|
||||
all: wireguard-go
|
||||
|
||||
wireguard-go: $(wildcard *.go) $(wildcard */*.go)
|
||||
go build -v -o $@
|
||||
export GOPATH := $(CURDIR)/.gopath
|
||||
export PATH := $(PATH):$(CURDIR)/.gopath/bin
|
||||
GO_IMPORT_PATH := git.zx2c4.com/wireguard-go
|
||||
|
||||
version.go:
|
||||
@export GIT_CEILING_DIRECTORIES="$(realpath $(CURDIR)/..)" && \
|
||||
tag="$$(git describe --dirty 2>/dev/null)" && \
|
||||
ver="$$(printf 'package main\nconst WireGuardGoVersion = "%s"\n' "$$tag")" && \
|
||||
[ "$$(cat $@ 2>/dev/null)" != "$$ver" ] && \
|
||||
echo "$$ver" > $@ && \
|
||||
git update-index --assume-unchanged $@ || true
|
||||
|
||||
.gopath/.created:
|
||||
rm -rf .gopath
|
||||
mkdir -p $(dir .gopath/src/$(GO_IMPORT_PATH))
|
||||
ln -s ../../.. .gopath/src/$(GO_IMPORT_PATH)
|
||||
touch $@
|
||||
|
||||
vendor/.created: Gopkg.toml Gopkg.lock | .gopath/.created
|
||||
command -v dep >/dev/null || go get -v github.com/golang/dep/cmd/dep
|
||||
export PWD; cd .gopath/src/$(GO_IMPORT_PATH) && dep ensure -vendor-only -v
|
||||
touch $@
|
||||
|
||||
wireguard-go: $(wildcard *.go) $(wildcard */*.go) .gopath/.created vendor/.created version.go
|
||||
go build -v $(GO_IMPORT_PATH)
|
||||
|
||||
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 wireguard-go "$(DESTDIR)$(BINDIR)/wireguard-go"
|
||||
|
||||
clean:
|
||||
rm -f wireguard-go
|
||||
|
||||
.PHONY: clean install
|
||||
update-dep: | .gopath/.created
|
||||
command -v dep >/dev/null || go get -v github.com/golang/dep/cmd/dep
|
||||
cd .gopath/src/$(GO_IMPORT_PATH) && dep ensure -update -v
|
||||
|
||||
.PHONY: clean install update-dep version.go
|
||||
|
||||
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) and of [dep](https://github.com/golang/dep). If dep is not installed, it will be downloaded and built as part of the build process.
|
||||
|
||||
```
|
||||
$ 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,6 +0,0 @@
|
||||
@echo off
|
||||
|
||||
REM builds wireguard for windows
|
||||
|
||||
go get
|
||||
go build -o wireguard-go.exe
|
||||
8
conn.go
8
conn.go
@@ -66,8 +66,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 +73,7 @@ func unsafeCloseBind(device *Device) error {
|
||||
err = netc.bind.Close()
|
||||
netc.bind = nil
|
||||
}
|
||||
netc.stopping.Wait()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -162,10 +161,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,4 +1,4 @@
|
||||
// +build !linux
|
||||
// +build !linux android
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
@@ -9,7 +9,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
/* This code is meant to be a temporary solution
|
||||
@@ -85,6 +89,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 +108,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 +124,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 +138,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 +149,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 +160,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
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// +build !android
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
@@ -16,11 +18,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"./rwcancel"
|
||||
"errors"
|
||||
"git.zx2c4.com/wireguard-go/rwcancel"
|
||||
"golang.org/x/sys/unix"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@@ -137,20 +141,22 @@ func CreateBind(port uint16, device *Device) (*NativeBind, uint16, error) {
|
||||
go bind.routineRouteListener(device)
|
||||
|
||||
bind.sock6, port, err = create6(port)
|
||||
if err != nil {
|
||||
if err != nil && err != syscall.EAFNOSUPPORT {
|
||||
bind.netlinkCancel.Cancel()
|
||||
return nil, port, err
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
bind.sock4, port, err = create4(port)
|
||||
if err != nil {
|
||||
if err != nil && err != syscall.EAFNOSUPPORT {
|
||||
bind.netlinkCancel.Cancel()
|
||||
unix.Close(bind.sock6)
|
||||
return nil, 0, err
|
||||
}
|
||||
return &bind, port, err
|
||||
return &bind, port, nil
|
||||
}
|
||||
|
||||
func (bind *NativeBind) SetMark(value uint32) error {
|
||||
if bind.sock6 != -1 {
|
||||
err := unix.SetsockoptInt(
|
||||
bind.sock6,
|
||||
unix.SOL_SOCKET,
|
||||
@@ -161,8 +167,10 @@ func (bind *NativeBind) SetMark(value uint32) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = unix.SetsockoptInt(
|
||||
if bind.sock4 != -1 {
|
||||
err := unix.SetsockoptInt(
|
||||
bind.sock4,
|
||||
unix.SOL_SOCKET,
|
||||
unix.SO_MARK,
|
||||
@@ -172,6 +180,7 @@ func (bind *NativeBind) SetMark(value uint32) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
bind.lastMark = value
|
||||
return nil
|
||||
@@ -184,9 +193,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 +213,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 +226,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 +240,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)
|
||||
}
|
||||
}
|
||||
@@ -551,6 +577,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 +586,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 +607,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 +623,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 +650,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 +703,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))[:])
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
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"
|
||||
|
||||
15
device.go
15
device.go
@@ -7,7 +7,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"./ratelimiter"
|
||||
"git.zx2c4.com/wireguard-go/ratelimiter"
|
||||
"git.zx2c4.com/wireguard-go/tun"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -35,6 +36,8 @@ type Device struct {
|
||||
}
|
||||
|
||||
net struct {
|
||||
starting sync.WaitGroup
|
||||
stopping sync.WaitGroup
|
||||
mutex sync.RWMutex
|
||||
bind Bind // bind interface
|
||||
port uint16 // listening port
|
||||
@@ -78,7 +81,7 @@ type Device struct {
|
||||
}
|
||||
|
||||
tun struct {
|
||||
device TUNDevice
|
||||
device tun.TUNDevice
|
||||
mtu int32
|
||||
}
|
||||
}
|
||||
@@ -162,16 +165,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)
|
||||
}
|
||||
|
||||
@@ -252,7 +251,7 @@ 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 +259,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)
|
||||
|
||||
@@ -26,8 +26,8 @@ func TestDevice(t *testing.T) {
|
||||
t.Error("failed to create tun:", err.Error())
|
||||
}
|
||||
|
||||
println(tun1)
|
||||
println(tun2)
|
||||
_ = tun1
|
||||
_ = tun2
|
||||
|
||||
// prepare endpoints
|
||||
|
||||
@@ -41,8 +41,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 Jason A. Donenfeld <Jason@zx2c4.com>. 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,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)
|
||||
@@ -8,6 +8,8 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"git.zx2c4.com/wireguard-go/tun"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
@@ -19,7 +21,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 +42,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
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ package main
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"git.zx2c4.com/wireguard-go/replay"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@@ -23,7 +24,7 @@ type Keypair struct {
|
||||
sendNonce uint64
|
||||
send cipher.AEAD
|
||||
receive cipher.AEAD
|
||||
replayFilter ReplayFilter
|
||||
replayFilter replay.ReplayFilter
|
||||
isInitiator bool
|
||||
created time.Time
|
||||
localIndex uint32
|
||||
|
||||
19
main.go
19
main.go
@@ -8,10 +8,12 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.zx2c4.com/wireguard-go/tun"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -72,6 +74,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 +131,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 +145,7 @@ func main() {
|
||||
}
|
||||
|
||||
file := os.NewFile(uintptr(fd), "")
|
||||
return CreateTUNFromFile(file)
|
||||
return tun.CreateTUNFromFile(file, DefaultMTU)
|
||||
}()
|
||||
|
||||
if err == nil {
|
||||
@@ -153,6 +160,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 +245,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 +268,7 @@ func main() {
|
||||
|
||||
// wait for program to terminate
|
||||
|
||||
signal.Notify(term, os.Kill)
|
||||
signal.Notify(term, syscall.SIGTERM)
|
||||
signal.Notify(term, os.Interrupt)
|
||||
|
||||
select {
|
||||
|
||||
14
misc.go
14
misc.go
@@ -41,23 +41,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
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
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"
|
||||
|
||||
@@ -58,6 +58,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")
|
||||
|
||||
23
peer.go
23
peer.go
@@ -40,9 +40,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 +54,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 +171,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 +241,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 +258,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()
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
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
|
||||
|
||||
39
receive.go
39
receive.go
@@ -105,12 +105,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 +125,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
|
||||
|
||||
@@ -440,12 +440,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 +463,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 +484,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
|
||||
}
|
||||
|
||||
@@ -513,11 +507,11 @@ func (peer *Peer) RoutineSequentialReceiver() {
|
||||
logDebug := device.log.Debug
|
||||
|
||||
defer func() {
|
||||
logDebug.Println(peer, ": Routine: sequential receiver - stopped")
|
||||
logDebug.Println(peer, "- Routine: sequential receiver - stopped")
|
||||
peer.routines.stopping.Done()
|
||||
}()
|
||||
|
||||
logDebug.Println(peer, ": Routine: sequential receiver - started")
|
||||
logDebug.Println(peer, "- Routine: sequential receiver - started")
|
||||
|
||||
peer.routines.starting.Done()
|
||||
|
||||
@@ -544,15 +538,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 +561,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()
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
*/
|
||||
|
||||
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 +30,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 +47,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
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
|
||||
*/
|
||||
|
||||
package main
|
||||
package replay
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -15,6 +15,8 @@ import (
|
||||
*
|
||||
*/
|
||||
|
||||
const RejectAfterMessages = (1 << 64) - (1 << 4) - 1
|
||||
|
||||
func TestReplay(t *testing.T) {
|
||||
var filter ReplayFilter
|
||||
|
||||
@@ -23,7 +25,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 Jason A. Donenfeld <Jason@zx2c4.com>. 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 Jason A. Donenfeld <Jason@zx2c4.com>. 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
|
||||
}
|
||||
@@ -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,3 +1,5 @@
|
||||
// +build !linux
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
44
send.go
44
send.go
@@ -108,14 +108,14 @@ func addToEncryptionQueue(
|
||||
/* 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:
|
||||
return false
|
||||
@@ -124,7 +124,7 @@ func (peer *Peer) SendKeepalive() bool {
|
||||
|
||||
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
|
||||
}
|
||||
@@ -264,8 +264,10 @@ func (device *Device) RoutineReadFromTUN() {
|
||||
size, err := device.tun.device.Read(elem.buffer[:], offset)
|
||||
|
||||
if err != nil {
|
||||
if !device.isClosed.Get() {
|
||||
logError.Println("Failed to read packet from TUN device:", err)
|
||||
device.Close()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -304,7 +306,7 @@ 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)
|
||||
@@ -333,8 +335,8 @@ func (peer *Peer) RoutineNonce() {
|
||||
logDebug := device.log.Debug
|
||||
|
||||
defer func() {
|
||||
logDebug.Println(peer, ": Routine: nonce worker - stopped")
|
||||
peer.queue.packetInNonceQueueIsAwaitingKey = false
|
||||
logDebug.Println(peer, "- Routine: nonce worker - stopped")
|
||||
peer.queue.packetInNonceQueueIsAwaitingKey.Set(false)
|
||||
peer.routines.stopping.Done()
|
||||
}()
|
||||
|
||||
@@ -349,11 +351,11 @@ func (peer *Peer) RoutineNonce() {
|
||||
}
|
||||
|
||||
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 +383,7 @@ func (peer *Peer) RoutineNonce() {
|
||||
break
|
||||
}
|
||||
}
|
||||
peer.queue.packetInNonceQueueIsAwaitingKey = true
|
||||
peer.queue.packetInNonceQueueIsAwaitingKey.Set(true)
|
||||
|
||||
// no suitable key pair, request for new handshake
|
||||
|
||||
@@ -394,11 +396,11 @@ 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:
|
||||
flush()
|
||||
@@ -408,7 +410,7 @@ func (peer *Peer) RoutineNonce() {
|
||||
return
|
||||
}
|
||||
}
|
||||
peer.queue.packetInNonceQueueIsAwaitingKey = false
|
||||
peer.queue.packetInNonceQueueIsAwaitingKey.Set(false)
|
||||
|
||||
// populate work element
|
||||
|
||||
@@ -521,11 +523,11 @@ func (peer *Peer) RoutineSequentialSender() {
|
||||
logDebug := device.log.Debug
|
||||
|
||||
defer func() {
|
||||
logDebug.Println(peer, ": Routine: sequential sender - stopped")
|
||||
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()
|
||||
|
||||
|
||||
38
timers.go
38
timers.go
@@ -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() {
|
||||
|
||||
29
tun.go
29
tun.go
@@ -7,39 +7,23 @@
|
||||
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 +38,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()
|
||||
}
|
||||
|
||||
27
tun/tun.go
Normal file
27
tun/tun.go
Normal file
@@ -0,0 +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>.
|
||||
*/
|
||||
|
||||
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,23 @@
|
||||
// +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>.
|
||||
*/
|
||||
|
||||
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 +36,78 @@ 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 {
|
||||
type nativeTun struct {
|
||||
name string
|
||||
fd *os.File
|
||||
rwcancel *rwcancel.RWCancel
|
||||
mtu int
|
||||
events chan TUNEvent
|
||||
errors chan error
|
||||
statusListenersShutdown chan struct{}
|
||||
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,29 +157,39 @@ 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{
|
||||
tun := &nativeTun{
|
||||
fd: file,
|
||||
mtu: 1500,
|
||||
events: make(chan TUNEvent, 10),
|
||||
errors: make(chan error, 1),
|
||||
statusListenersShutdown: make(chan struct{}),
|
||||
}
|
||||
|
||||
_, err := tun.Name()
|
||||
name, err := tun.Name()
|
||||
if err != nil {
|
||||
tun.fd.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.fd.Close()
|
||||
return nil, err
|
||||
@@ -137,46 +201,15 @@ func CreateTUNFromFile(file *os.File) (TUNDevice, error) {
|
||||
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)
|
||||
tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
|
||||
if err != nil {
|
||||
tun.errors <- err
|
||||
return
|
||||
tun.fd.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 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
|
||||
go tun.routineRouteListener(tunIfindex)
|
||||
|
||||
// MTU changes
|
||||
if intr.MTU != statusMTU {
|
||||
tun.events <- TUNEventMTUUpdate
|
||||
}
|
||||
statusMTU = intr.MTU
|
||||
|
||||
select {
|
||||
case <-time.After(time.Second / 10):
|
||||
case <-tun.statusListenersShutdown:
|
||||
return
|
||||
}
|
||||
}
|
||||
}(tun)
|
||||
|
||||
// set default MTU
|
||||
err = tun.setMTU(DefaultMTU)
|
||||
err = tun.setMTU(mtu)
|
||||
if err != nil {
|
||||
tun.Close()
|
||||
return nil, err
|
||||
@@ -185,7 +218,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
|
||||
@@ -208,15 +241,15 @@ func (tun *NativeTun) Name() (string, error) {
|
||||
return tun.name, nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) File() *os.File {
|
||||
func (tun *nativeTun) File() *os.File {
|
||||
return tun.fd
|
||||
}
|
||||
|
||||
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
|
||||
@@ -230,10 +263,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 +275,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
|
||||
|
||||
@@ -265,18 +298,27 @@ func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
return tun.fd.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()
|
||||
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 {
|
||||
func (tun *nativeTun) setMTU(n int) error {
|
||||
|
||||
// open datagram socket
|
||||
|
||||
@@ -298,7 +340,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 +349,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 +382,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
|
||||
}
|
||||
510
tun/tun_freebsd.go
Normal file
510
tun/tun_freebsd.go
Normal file
@@ -0,0 +1,510 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. 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
|
||||
fd *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 < 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{
|
||||
fd: file,
|
||||
events: make(chan TUNEvent, 10),
|
||||
errors: make(chan error, 1),
|
||||
}
|
||||
|
||||
name, err := tun.Name()
|
||||
if err != nil {
|
||||
tun.fd.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.fd.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun.rwcancel, err = rwcancel.NewRWCancel(int(file.Fd()))
|
||||
if err != nil {
|
||||
tun.fd.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
|
||||
if err != nil {
|
||||
tun.fd.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.Fd())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
tun.name = name
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) File() *os.File {
|
||||
return tun.fd
|
||||
}
|
||||
|
||||
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.fd.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.fd.Write(buff)
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Close() error {
|
||||
var err4 error
|
||||
err1 := tun.rwcancel.Cancel()
|
||||
err2 := tun.fd.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
|
||||
}
|
||||
@@ -6,22 +6,22 @@
|
||||
|
||||
/* 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,7 +31,7 @@ const (
|
||||
ifReqSize = unix.IFNAMSIZ + 64
|
||||
)
|
||||
|
||||
type NativeTun struct {
|
||||
type nativeTun struct {
|
||||
fd *os.File
|
||||
fdCancel *rwcancel.RWCancel
|
||||
index int32 // if index
|
||||
@@ -41,15 +41,16 @@ type NativeTun struct {
|
||||
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 {
|
||||
func (tun *nativeTun) File() *os.File {
|
||||
return tun.fd
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
@@ -65,7 +66,7 @@ func (tun *NativeTun) RoutineHackListener() {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case <-time.After(time.Second / 10):
|
||||
case <-time.After(time.Second):
|
||||
case <-tun.statusListenersShutdown:
|
||||
return
|
||||
}
|
||||
@@ -88,8 +89,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 +102,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 +159,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 +193,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 +216,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 +225,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,19 +258,13 @@ 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(
|
||||
@@ -276,7 +274,7 @@ func (tun *NativeTun) Name() (string, error) {
|
||||
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 +285,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:]
|
||||
@@ -315,7 +313,7 @@ func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
return tun.fd.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
|
||||
@@ -333,10 +331,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 +343,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
|
||||
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()
|
||||
err3 := tun.fdCancel.Cancel()
|
||||
close(tun.events)
|
||||
|
||||
if err1 != nil {
|
||||
return err1
|
||||
@@ -368,7 +369,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 +399,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,12 +411,12 @@ 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{
|
||||
fd: file,
|
||||
events: make(chan TUNEvent, 5),
|
||||
errors: make(chan error, 5),
|
||||
statusListenersShutdown: make(chan struct{}),
|
||||
@@ -423,7 +424,7 @@ func CreateTUNFromFile(fd *os.File) (TUNDevice, error) {
|
||||
}
|
||||
var err error
|
||||
|
||||
tun.fdCancel, err = rwcancel.NewRWCancel(int(fd.Fd()))
|
||||
tun.fdCancel, err = rwcancel.NewRWCancel(int(file.Fd()))
|
||||
if err != nil {
|
||||
tun.fd.Close()
|
||||
return nil, err
|
||||
@@ -453,12 +454,11 @@ func CreateTUNFromFile(fd *os.File) (TUNDevice, error) {
|
||||
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 Jason A. Donenfeld <Jason@zx2c4.com>. 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
|
||||
fd *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{
|
||||
fd: file,
|
||||
events: make(chan TUNEvent, 10),
|
||||
errors: make(chan error, 1),
|
||||
}
|
||||
|
||||
name, err := tun.Name()
|
||||
if err != nil {
|
||||
tun.fd.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.fd.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun.rwcancel, err = rwcancel.NewRWCancel(int(file.Fd()))
|
||||
if err != nil {
|
||||
tun.fd.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
|
||||
if err != nil {
|
||||
tun.fd.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.fd.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.fd
|
||||
}
|
||||
|
||||
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.fd.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.fd.Write(buff)
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Close() error {
|
||||
var err3 error
|
||||
err1 := tun.rwcancel.Cancel()
|
||||
err2 := tun.fd.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
|
||||
}
|
||||
38
uapi.go
38
uapi.go
@@ -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}
|
||||
}
|
||||
|
||||
@@ -363,7 +363,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
device.allowedips.Insert(network.IP, uint(ones), peer)
|
||||
|
||||
default:
|
||||
logError.Println("Invalid UAPI key (peer configuration):", key)
|
||||
logError.Println("Invalid UAPI peer key:", key)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
}
|
||||
@@ -397,11 +397,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,3 +1,5 @@
|
||||
// +build darwin freebsd openbsd
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
@@ -13,6 +15,7 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -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
|
||||
@@ -7,9 +7,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"./rwcancel"
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.zx2c4.com/wireguard-go/rwcancel"
|
||||
"golang.org/x/sys/unix"
|
||||
"net"
|
||||
"os"
|
||||
@@ -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.20180613"
|
||||
Reference in New Issue
Block a user