34 Commits

Author SHA1 Message Date
Jason A. Donenfeld
b41922e5c8 version: bump snapshot 2018-10-01 17:58:31 +02:00
Jason A. Donenfeld
dbb72402f2 Adding missing queueconstants file 2018-10-01 16:11:31 +02:00
Chris Branch
7c971d7ef4 Fix transport message length check
wireguard-go has a bad length check in its transport message handling.
Although it cannot be exploited because of another length check earlier in the
function, this should be fixed regardless.
2018-09-25 05:18:11 +02:00
Jason A. Donenfeld
70bcf9ecb8 Make it easy to restrict queue sizes more 2018-09-25 02:31:02 +02:00
Jason A. Donenfeld
ebc7541953 Fix shutdown races 2018-09-24 01:52:02 +02:00
Jason A. Donenfeld
833597b585 More pooling 2018-09-24 00:37:43 +02:00
Jason A. Donenfeld
cf81a28dd3 Fixup buffer freeing 2018-09-22 05:43:03 +02:00
Jason A. Donenfeld
942abf948a send: more precise padding calculation 2018-09-16 23:42:31 +02:00
Jason A. Donenfeld
47d1140361 device: preallocated buffers scheme
Not useful now but quite possibly later.
2018-09-16 23:10:19 +02:00
Jason A. Donenfeld
39d6e4f2f1 Change queueing drop order and fix memory leaks
If the queues are full, we drop the present packet, which is better for
network traffic flow. Also, we try to fix up the memory leaks with not
putting buffers from our shared pool.
2018-09-16 21:50:58 +02:00
Jason A. Donenfeld
1c02557013 send: use accessor function for buffer pool 2018-09-16 18:49:19 +02:00
Mathias Hall-Andersen
32d2148835 Fixed port overwrite issue on kernels without ipv6
Fixed an issue in CreateBind for Linux:
If ipv6 was not supported the error code would be
correctly identified as EAFNOSUPPORT and ipv4 binding attempted.
However the port would be set to 0,
which results in the subsequent create4 call requesting
a random port rather than the one provided to CreateBind.

This issue was identified by:
Kent Friis <leeloored@gmx.com>
2018-09-16 18:49:19 +02:00
Jason A. Donenfeld
5be541d147 global: fix up copyright headers 2018-09-16 18:49:19 +02:00
Jason A. Donenfeld
063becdc73 uapi: insert peer version placeholder
While we don't want people to ever use old protocols, people will
complain if the API "changes", so explicitly make the unset protocol
mean the latest, and add a dummy mechanism of specifying the protocol on
a per-peer basis, which we hope nobody actually ever uses.
2018-09-02 23:04:47 -06:00
Jason A. Donenfeld
15da869b31 Fix duplicate copyright line 2018-07-30 05:14:17 +02:00
Jason A. Donenfeld
3ad3e83c7a uapi: allow overriding socket directory at compile time 2018-07-24 14:32:35 +02:00
Jason A. Donenfeld
2e13b7b0fb send: better debug message for failed data packet 2018-07-16 16:05:36 +02:00
Jason A. Donenfeld
6b3b1c3b91 version: bump snapshot 2018-06-13 16:22:16 +02:00
Jason A. Donenfeld
6a5d0e2bcd Support IPv6-less kernels 2018-06-12 01:32:46 +02:00
Jason A. Donenfeld
0ba551807f Do not build tun device on ios 2018-06-09 03:31:17 +02:00
Jason A. Donenfeld
99d5aeeb27 Fix duplicated wording 2018-06-02 17:36:35 +02:00
Jason A. Donenfeld
a050431f26 Makefile: export PWD for OpenBSD's ksh(1)
Interestingly, ksh(1) on OpenBSD does not export PWD by default, and it
also has a notion of the "logical cwd" vs the "physical cwd", with the
latter being passed to chdir, but the former being stored in the
non-exported PWD and displayed to the user. This means that if you `cd`
into a directory that's comprised of symlinks, exec'd processes will see
the physical path. Observe:

  # ksh
  # mkdir a
  # ln -s a b
  # cd b
  # pwd
  /root/b
  # ksh -c pwd
  /root/a

The fact of separating physical and logical paths is not too uncommon
for shells (bash does it too), but not exporting PWD is very odd.

Since this is common behavior for many shells, libraries that return the
working directory will do something strange: they `stat(".")` and then
`stat(getenv("PWD"))`, and if these point to the same inode, they roll
with the value of `getenv("PWD")`, or otherwise fallback to asking the
kernel for the cwd.

Since PWD was not exported by ksh(1), Go's dep utility did not understand
it was operating inside of our faked GOPATH and became upset.

This patch works around the whole situation by simply exporting PWD
before executing dep.
2018-06-02 16:36:12 +02:00
Jason A. Donenfeld
0c976003c8 version: bump snapshot 2018-05-31 02:26:07 +02:00
Jason A. Donenfeld
955e89839f Print version number in log 2018-05-30 01:09:18 +02:00
Jason A. Donenfeld
a4cd0216c0 Update deps 2018-05-28 01:39:37 +02:00
Jason A. Donenfeld
1d7845a600 Fix typo in timers 2018-05-27 22:55:15 +02:00
Jason A. Donenfeld
5079298ce2 Disable broadcast mode on *BSD
Keeping it on makes IPv6 problematic and confuses routing daemons.
2018-05-27 22:55:15 +02:00
Jason A. Donenfeld
fc3a7635e5 Disappointing anti-sticky experiment 2018-05-27 22:55:15 +02:00
Jason A. Donenfeld
2496cdd8e6 Fix tests 2018-05-24 19:58:16 +02:00
Jason A. Donenfeld
4365b4583f Trick for being extra sensitive to route changes 2018-05-24 18:21:14 +02:00
Jason A. Donenfeld
bbf320c477 Back to sticky sockets on android 2018-05-24 17:53:00 +02:00
Jason A. Donenfeld
625d59da14 Do not build on Linux 2018-05-24 16:41:42 +02:00
Jason A. Donenfeld
2f2eca8947 Catch EINTR 2018-05-24 15:36:29 +02:00
Jason A. Donenfeld
66f6ca3e4a Remove old makefile artifact 2018-05-24 03:13:46 +02:00
58 changed files with 546 additions and 367 deletions

6
Gopkg.lock generated
View File

@@ -11,7 +11,7 @@
"internal/chacha20",
"poly1305"
]
revision = "1a580b3eff7814fc9b40602fd35256c63b50f491"
revision = "ab813273cd59e1333f7ae7bff5d027d4aadf528c"
[[projects]]
branch = "master"
@@ -23,7 +23,7 @@
"ipv4",
"ipv6"
]
revision = "9ef9f5bb98a1fdc41f8cf6c250a4404b4085e389"
revision = "dfa909b99c79129e1100513e5cd36307665e5723"
[[projects]]
branch = "master"
@@ -32,7 +32,7 @@
"cpu",
"unix"
]
revision = "88eb85aaee56831ad49eaf7aa80d73de9814cde2"
revision = "c11f84a56e43e20a78cee75a7c034031ecf57d1f"
[solve-meta]
analyzer-name = "dep"

View File

@@ -32,11 +32,11 @@ version.go:
vendor/.created: Gopkg.toml Gopkg.lock | .gopath/.created
command -v dep >/dev/null || go get -v github.com/golang/dep/cmd/dep
cd .gopath/src/$(GO_IMPORT_PATH) && dep ensure -vendor-only -v
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 $(GO_BUILD_EXTRA_ARGS) -v $(GO_IMPORT_PATH)
go build -v $(GO_IMPORT_PATH)
install: wireguard-go
@install -v -d "$(DESTDIR)$(BINDIR)" && install -v -m 0755 wireguard-go "$(DESTDIR)$(BINDIR)/wireguard-go"

View File

@@ -76,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/).

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

View File

@@ -2,8 +2,7 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main
@@ -11,7 +10,9 @@ package main
import (
"golang.org/x/sys/unix"
"net"
"os"
"runtime"
"syscall"
)
/* This code is meant to be a temporary solution
@@ -87,6 +88,18 @@ func listenNet(network string, port int) (*net.UDPConn, int, error) {
return conn, uaddr.Port, nil
}
func extractErrno(err error) error {
opErr, ok := err.(*net.OpError)
if !ok {
return nil
}
syscallErr, ok := opErr.Err.(*os.SyscallError)
if !ok {
return nil
}
return syscallErr.Err
}
func CreateBind(uport uint16, device *Device) (Bind, uint16, error) {
var err error
var bind NativeBind
@@ -94,13 +107,15 @@ func CreateBind(uport uint16, device *Device) (Bind, uint16, error) {
port := int(uport)
bind.ipv4, port, err = listenNet("udp4", port)
if err != nil {
if err != nil && extractErrno(err) != syscall.EAFNOSUPPORT {
return nil, 0, err
}
bind.ipv6, port, err = listenNet("udp6", port)
if err != nil {
if err != nil && extractErrno(err) != syscall.EAFNOSUPPORT {
return nil, 0, err
bind.ipv4.Close()
bind.ipv4 = nil
return nil, 0, err
}
@@ -108,8 +123,13 @@ func CreateBind(uport uint16, device *Device) (Bind, uint16, error) {
}
func (bind *NativeBind) Close() error {
err1 := bind.ipv4.Close()
err2 := bind.ipv6.Close()
var err1, err2 error
if bind.ipv4 != nil {
err1 = bind.ipv4.Close()
}
if bind.ipv6 != nil {
err2 = bind.ipv6.Close()
}
if err1 != nil {
return err1
}
@@ -117,6 +137,9 @@ func (bind *NativeBind) Close() error {
}
func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) {
if bind.ipv4 == nil {
return 0, nil, syscall.EAFNOSUPPORT
}
n, endpoint, err := bind.ipv4.ReadFromUDP(buff)
if endpoint != nil {
endpoint.IP = endpoint.IP.To4()
@@ -125,6 +148,9 @@ func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) {
}
func (bind *NativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) {
if bind.ipv6 == nil {
return 0, nil, syscall.EAFNOSUPPORT
}
n, endpoint, err := bind.ipv6.ReadFromUDP(buff)
return n, (*NativeEndpoint)(endpoint), err
}
@@ -133,8 +159,14 @@ 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
@@ -157,31 +189,29 @@ func (bind *NativeBind) SetMark(mark uint32) error {
if fwmarkIoctl == 0 {
return nil
}
fd4, err1 := bind.ipv4.SyscallConn()
fd6, err2 := bind.ipv6.SyscallConn()
if err1 != nil {
return err1
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 err2 != nil {
return err2
}
err3 := fd4.Control(func(fd uintptr) {
err1 = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, fwmarkIoctl, int(mark))
})
err4 := fd6.Control(func(fd uintptr) {
err2 = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, fwmarkIoctl, int(mark))
})
if err1 != nil {
return err1
}
if err2 != nil {
return err2
}
if err3 != nil {
return err3
}
if err4 != nil {
return err4
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
}

View File

@@ -2,8 +2,7 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*
* This implements userspace semantics of "sticky sockets", modeled after
* WireGuard's kernelspace implementation. This is more or less a straight port
@@ -18,15 +17,20 @@
package main
import (
"git.zx2c4.com/wireguard-go/rwcancel"
"errors"
"git.zx2c4.com/wireguard-go/rwcancel"
"golang.org/x/sys/unix"
"net"
"strconv"
"sync"
"syscall"
"unsafe"
)
const (
FD_ERR = -1
)
type IPv4Source struct {
src [4]byte
ifindex int32
@@ -126,6 +130,7 @@ func createNetlinkRouteSocket() (int, error) {
func CreateBind(port uint16, device *Device) (*NativeBind, uint16, error) {
var err error
var bind NativeBind
var newPort uint16
bind.netlinkSock, err = createNetlinkRouteSocket()
if err != nil {
@@ -139,41 +144,63 @@ func CreateBind(port uint16, device *Device) (*NativeBind, uint16, error) {
go bind.routineRouteListener(device)
bind.sock6, port, err = create6(port)
// attempt ipv6 bind, update port if succesful
bind.sock6, newPort, err = create6(port)
if err != nil {
bind.netlinkCancel.Cancel()
return nil, port, err
if err != syscall.EAFNOSUPPORT {
bind.netlinkCancel.Cancel()
return nil, 0, err
}
} else {
port = newPort
}
bind.sock4, port, err = create4(port)
// attempt ipv4 bind, update port if succesful
bind.sock4, newPort, err = create4(port)
if err != nil {
bind.netlinkCancel.Cancel()
unix.Close(bind.sock6)
if err != syscall.EAFNOSUPPORT {
bind.netlinkCancel.Cancel()
unix.Close(bind.sock6)
return nil, 0, err
}
} else {
port = newPort
}
return &bind, port, err
if bind.sock4 == FD_ERR && bind.sock6 == FD_ERR {
return nil, 0, errors.New("ipv4 and ipv6 not supported")
}
return &bind, port, nil
}
func (bind *NativeBind) SetMark(value uint32) error {
err := unix.SetsockoptInt(
bind.sock6,
unix.SOL_SOCKET,
unix.SO_MARK,
int(value),
)
if bind.sock6 != -1 {
err := unix.SetsockoptInt(
bind.sock6,
unix.SOL_SOCKET,
unix.SO_MARK,
int(value),
)
if err != nil {
return err
if err != nil {
return err
}
}
err = unix.SetsockoptInt(
bind.sock4,
unix.SOL_SOCKET,
unix.SO_MARK,
int(value),
)
if bind.sock4 != -1 {
err := unix.SetsockoptInt(
bind.sock4,
unix.SOL_SOCKET,
unix.SO_MARK,
int(value),
)
if err != nil {
return err
if err != nil {
return err
}
}
bind.lastMark = value
@@ -187,9 +214,14 @@ func closeUnblock(fd int) error {
}
func (bind *NativeBind) Close() error {
err1 := closeUnblock(bind.sock6)
err2 := closeUnblock(bind.sock4)
err3 := bind.netlinkCancel.Cancel()
var err1, err2, err3 error
if bind.sock6 != -1 {
err1 = closeUnblock(bind.sock6)
}
if bind.sock4 != -1 {
err2 = closeUnblock(bind.sock4)
}
err3 = bind.netlinkCancel.Cancel()
if err1 != nil {
return err1
@@ -202,6 +234,9 @@ func (bind *NativeBind) Close() error {
func (bind *NativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) {
var end NativeEndpoint
if bind.sock6 == -1 {
return 0, nil, syscall.EAFNOSUPPORT
}
n, err := receive6(
bind.sock6,
buff,
@@ -212,6 +247,9 @@ func (bind *NativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) {
func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) {
var end NativeEndpoint
if bind.sock4 == -1 {
return 0, nil, syscall.EAFNOSUPPORT
}
n, err := receive4(
bind.sock4,
buff,
@@ -223,8 +261,14 @@ func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) {
func (bind *NativeBind) Send(buff []byte, end Endpoint) error {
nend := end.(*NativeEndpoint)
if !nend.isV6 {
if bind.sock4 == -1 {
return syscall.EAFNOSUPPORT
}
return send4(bind.sock4, nend, buff)
} else {
if bind.sock6 == -1 {
return syscall.EAFNOSUPPORT
}
return send6(bind.sock6, nend, buff)
}
}
@@ -312,7 +356,7 @@ func create4(port uint16) (int, uint16, error) {
)
if err != nil {
return -1, 0, err
return FD_ERR, 0, err
}
addr := unix.SockaddrInet4{
@@ -343,7 +387,7 @@ func create4(port uint16) (int, uint16, error) {
return unix.Bind(fd, &addr)
}(); err != nil {
unix.Close(fd)
return -1, 0, err
return FD_ERR, 0, err
}
return fd, uint16(addr.Port), err
@@ -360,7 +404,7 @@ func create6(port uint16) (int, uint16, error) {
)
if err != nil {
return -1, 0, err
return FD_ERR, 0, err
}
// set sockopts and bind
@@ -402,7 +446,7 @@ func create6(port uint16) (int, uint16, error) {
}(); err != nil {
unix.Close(fd)
return -1, 0, err
return FD_ERR, 0, err
}
return fd, uint16(addr.Port), err
@@ -563,7 +607,7 @@ func (bind *NativeBind) routineRouteListener(device *Device) {
var msgn int
for {
msgn, _, _, _, err = unix.Recvmsg(bind.netlinkSock, msg[:], nil, 0)
if err == nil || !rwcancel.ErrorIsEAGAIN(err) {
if err == nil || !rwcancel.RetryAfterError(err) {
break
}
if !bind.netlinkCancel.ReadyRead() {

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main
@@ -27,18 +26,14 @@ const (
PaddingMultiple = 16
)
/* Implementation specific constants */
const (
QueueOutboundSize = 1024
QueueInboundSize = 1024
QueueHandshakeSize = 1024
MaxSegmentSize = (1 << 16) - 1 // largest possible UDP datagram
MinMessageSize = MessageKeepaliveSize // minimum size of transport message (keepalive)
MaxMessageSize = MaxSegmentSize // maximum size of transport message
MaxContentSize = MaxSegmentSize - MessageTransportSize // maximum size of transport message content
MinMessageSize = MessageKeepaliveSize // minimum size of transport message (keepalive)
MaxMessageSize = MaxSegmentSize // maximum size of transport message
MaxContentSize = MaxSegmentSize - MessageTransportSize // maximum size of transport message content
)
/* Implementation constants */
const (
UnderLoadQueueSize = QueueHandshakeSize / 8
UnderLoadAfterTime = time.Second // how long does the device remain under load after detected

View File

@@ -1,15 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main
import (
"git.zx2c4.com/wireguard-go/xchacha20poly1305"
"crypto/hmac"
"crypto/rand"
"git.zx2c4.com/wireguard-go/xchacha20poly1305"
"golang.org/x/crypto/blake2s"
"golang.org/x/crypto/chacha20poly1305"
"sync"

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main
@@ -67,7 +66,12 @@ type Device struct {
}
pool struct {
messageBuffers sync.Pool
messageBufferPool *sync.Pool
messageBufferReuseChan chan *[MaxMessageSize]byte
inboundElementPool *sync.Pool
inboundElementReuseChan chan *QueueInboundElement
outboundElementPool *sync.Pool
outboundElementReuseChan chan *QueueOutboundElement
}
queue struct {
@@ -243,14 +247,6 @@ func (device *Device) SetPrivateKey(sk NoisePrivateKey) error {
return nil
}
func (device *Device) GetMessageBuffer() *[MaxMessageSize]byte {
return device.pool.messageBuffers.Get().(*[MaxMessageSize]byte)
}
func (device *Device) PutMessageBuffer(msg *[MaxMessageSize]byte) {
device.pool.messageBuffers.Put(msg)
}
func NewDevice(tunDevice tun.TUNDevice, logger *Logger) *Device {
device := new(Device)
@@ -275,11 +271,7 @@ func NewDevice(tunDevice tun.TUNDevice, logger *Logger) *Device {
device.indexTable.Init()
device.allowedips.Reset()
device.pool.messageBuffers = sync.Pool{
New: func() interface{} {
return new([MaxMessageSize]byte)
},
}
device.PopulatePools()
// create queues
@@ -385,10 +377,11 @@ func (device *Device) Close() {
close(device.signals.stop)
device.RemoveAllPeers()
device.state.stopping.Wait()
device.FlushPacketQueues()
device.RemoveAllPeers()
device.rate.limiter.Close()
device.state.changing.Set(false)

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

View File

@@ -2,7 +2,7 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main
@@ -9,6 +8,7 @@ package main
import (
"bytes"
"errors"
"git.zx2c4.com/wireguard-go/tun"
"os"
"testing"
)
@@ -20,7 +20,7 @@ type DummyTUN struct {
name string
mtu int
packets chan []byte
events chan TUNEvent
events chan tun.TUNEvent
}
func (tun *DummyTUN) File() *os.File {
@@ -46,7 +46,7 @@ func (tun *DummyTUN) Close() error {
return nil
}
func (tun *DummyTUN) Events() chan TUNEvent {
func (tun *DummyTUN) Events() chan tun.TUNEvent {
return tun.events
}
@@ -59,11 +59,11 @@ func (tun *DummyTUN) Read(d []byte, offset int) (int, error) {
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 TUNEvent, 10)
dummy.events = make(chan tun.TUNEvent, 10)
return &dummy, nil
}

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

3
ip.go
View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

View File

@@ -1,14 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main
import (
"git.zx2c4.com/wireguard-go/replay"
"crypto/cipher"
"git.zx2c4.com/wireguard-go/replay"
"sync"
"time"
)

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

View File

@@ -1,14 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main
import (
"git.zx2c4.com/wireguard-go/tun"
"fmt"
"git.zx2c4.com/wireguard-go/tun"
"os"
"os/signal"
"runtime"
@@ -160,6 +159,8 @@ func main() {
fmt.Sprintf("(%s) ", interfaceName),
)
logger.Info.Println("Starting wireguard-go version", WireGuardGoVersion)
logger.Debug.Println("Debug log enabled")
if err != nil {

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

View File

@@ -1,14 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2015-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main
import (
"git.zx2c4.com/wireguard-go/tai64n"
"errors"
"git.zx2c4.com/wireguard-go/tai64n"
"golang.org/x/crypto/blake2s"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/poly1305"

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

14
peer.go
View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main
@@ -258,3 +257,14 @@ func (peer *Peer) Stop() {
peer.ZeroAndFlushAll()
}
var roamingDisabled bool
func (peer *Peer) SetEndpointFromPacket(endpoint Endpoint) {
if roamingDisabled {
return
}
peer.mutex.Lock()
peer.endpoint = endpoint
peer.mutex.Unlock()
}

89
pools.go Normal file
View File

@@ -0,0 +1,89 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main
import "sync"
func (device *Device) PopulatePools() {
if PreallocatedBuffersPerPool == 0 {
device.pool.messageBufferPool = &sync.Pool{
New: func() interface{} {
return new([MaxMessageSize]byte)
},
}
device.pool.inboundElementPool = &sync.Pool{
New: func() interface{} {
return new(QueueInboundElement)
},
}
device.pool.outboundElementPool = &sync.Pool{
New: func() interface{} {
return new(QueueOutboundElement)
},
}
} else {
device.pool.messageBufferReuseChan = make(chan *[MaxMessageSize]byte, PreallocatedBuffersPerPool)
for i := 0; i < PreallocatedBuffersPerPool; i += 1 {
device.pool.messageBufferReuseChan <- new([MaxMessageSize]byte)
}
device.pool.inboundElementReuseChan = make(chan *QueueInboundElement, PreallocatedBuffersPerPool)
for i := 0; i < PreallocatedBuffersPerPool; i += 1 {
device.pool.inboundElementReuseChan <- new(QueueInboundElement)
}
device.pool.outboundElementReuseChan = make(chan *QueueOutboundElement, PreallocatedBuffersPerPool)
for i := 0; i < PreallocatedBuffersPerPool; i += 1 {
device.pool.outboundElementReuseChan <- new(QueueOutboundElement)
}
}
}
func (device *Device) GetMessageBuffer() *[MaxMessageSize]byte {
if PreallocatedBuffersPerPool == 0 {
return device.pool.messageBufferPool.Get().(*[MaxMessageSize]byte)
} else {
return <-device.pool.messageBufferReuseChan
}
}
func (device *Device) PutMessageBuffer(msg *[MaxMessageSize]byte) {
if PreallocatedBuffersPerPool == 0 {
device.pool.messageBufferPool.Put(msg)
} else {
device.pool.messageBufferReuseChan <- msg
}
}
func (device *Device) GetInboundElement() *QueueInboundElement {
if PreallocatedBuffersPerPool == 0 {
return device.pool.inboundElementPool.Get().(*QueueInboundElement)
} else {
return <-device.pool.inboundElementReuseChan
}
}
func (device *Device) PutInboundElement(msg *QueueInboundElement) {
if PreallocatedBuffersPerPool == 0 {
device.pool.inboundElementPool.Put(msg)
} else {
device.pool.inboundElementReuseChan <- msg
}
}
func (device *Device) GetOutboundElement() *QueueOutboundElement {
if PreallocatedBuffersPerPool == 0 {
return device.pool.outboundElementPool.Get().(*QueueOutboundElement)
} else {
return <-device.pool.outboundElementReuseChan
}
}
func (device *Device) PutOutboundElement(msg *QueueOutboundElement) {
if PreallocatedBuffersPerPool == 0 {
device.pool.outboundElementPool.Put(msg)
} else {
device.pool.outboundElementReuseChan <- msg
}
}

16
queueconstants.go Normal file
View File

@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main
/* Implementation specific constants */
const (
QueueOutboundSize = 1024
QueueInboundSize = 1024
QueueHandshakeSize = 1024
MaxSegmentSize = (1 << 16) - 1 // largest possible UDP datagram
PreallocatedBuffersPerPool = 0 // Disable and allow for infinite memory growth
)

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package ratelimiter

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package ratelimiter

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main
@@ -44,59 +43,29 @@ func (elem *QueueInboundElement) IsDropped() bool {
return atomic.LoadInt32(&elem.dropped) == AtomicTrue
}
func (device *Device) addToInboundQueue(
queue chan *QueueInboundElement,
element *QueueInboundElement,
) {
for {
func (device *Device) addToInboundAndDecryptionQueues(inboundQueue chan *QueueInboundElement, decryptionQueue chan *QueueInboundElement, element *QueueInboundElement) bool {
select {
case inboundQueue <- element:
select {
case queue <- element:
return
case decryptionQueue <- element:
return true
default:
select {
case old := <-queue:
old.Drop()
default:
}
element.Drop()
element.mutex.Unlock()
return false
}
default:
device.PutInboundElement(element)
return false
}
}
func (device *Device) addToDecryptionQueue(
queue chan *QueueInboundElement,
element *QueueInboundElement,
) {
for {
select {
case queue <- element:
return
default:
select {
case old := <-queue:
// drop & release to potential consumer
old.Drop()
old.mutex.Unlock()
default:
}
}
}
}
func (device *Device) addToHandshakeQueue(
queue chan QueueHandshakeElement,
element QueueHandshakeElement,
) {
for {
select {
case queue <- element:
return
default:
select {
case elem := <-queue:
device.PutMessageBuffer(elem.buffer)
default:
}
}
func (device *Device) addToHandshakeQueue(queue chan QueueHandshakeElement, element QueueHandshakeElement) bool {
select {
case queue <- element:
return true
default:
return false
}
}
@@ -155,6 +124,7 @@ func (device *Device) RoutineReceiveIncoming(IP int, bind Bind) {
}
if err != nil {
device.PutMessageBuffer(buffer)
return
}
@@ -177,7 +147,7 @@ func (device *Device) RoutineReceiveIncoming(IP int, bind Bind) {
// check size
if len(packet) < MessageTransportType {
if len(packet) < MessageTransportSize {
continue
}
@@ -199,23 +169,23 @@ func (device *Device) RoutineReceiveIncoming(IP int, bind Bind) {
}
// create work element
peer := value.peer
elem := &QueueInboundElement{
packet: packet,
buffer: buffer,
keypair: keypair,
dropped: AtomicFalse,
endpoint: endpoint,
}
elem := device.GetInboundElement()
elem.packet = packet
elem.buffer = buffer
elem.keypair = keypair
elem.dropped = AtomicFalse
elem.endpoint = endpoint
elem.counter = 0
elem.mutex = sync.Mutex{}
elem.mutex.Lock()
// add to decryption queues
if peer.isRunning.Get() {
device.addToDecryptionQueue(device.queue.decryption, elem)
device.addToInboundQueue(peer.queue.inbound, elem)
buffer = device.GetMessageBuffer()
if device.addToInboundAndDecryptionQueues(peer.queue.inbound, device.queue.decryption, elem) {
buffer = device.GetMessageBuffer()
}
}
continue
@@ -236,7 +206,7 @@ func (device *Device) RoutineReceiveIncoming(IP int, bind Bind) {
}
if okay {
device.addToHandshakeQueue(
if (device.addToHandshakeQueue(
device.queue.handshake,
QueueHandshakeElement{
msgType: msgType,
@@ -244,8 +214,9 @@ func (device *Device) RoutineReceiveIncoming(IP int, bind Bind) {
packet: packet,
endpoint: endpoint,
},
)
buffer = device.GetMessageBuffer()
)) {
buffer = device.GetMessageBuffer()
}
}
}
}
@@ -308,6 +279,7 @@ func (device *Device) RoutineDecryption() {
)
if err != nil {
elem.Drop()
device.PutMessageBuffer(elem.buffer)
}
elem.mutex.Unlock()
}
@@ -322,18 +294,26 @@ func (device *Device) RoutineHandshake() {
logError := device.log.Error
logDebug := device.log.Debug
var elem QueueHandshakeElement
var ok bool
defer func() {
logDebug.Println("Routine: handshake worker - stopped")
device.state.stopping.Done()
if elem.buffer != nil {
device.PutMessageBuffer(elem.buffer)
}
}()
logDebug.Println("Routine: handshake worker - started")
device.state.starting.Done()
var elem QueueHandshakeElement
var ok bool
for {
if elem.buffer != nil {
device.PutMessageBuffer(elem.buffer)
elem.buffer = nil
}
select {
case elem, ok = <-device.queue.handshake:
case <-device.signals.stop:
@@ -440,10 +420,7 @@ func (device *Device) RoutineHandshake() {
peer.timersAnyAuthenticatedPacketReceived()
// update endpoint
peer.mutex.Lock()
peer.endpoint = elem.endpoint
peer.mutex.Unlock()
peer.SetEndpointFromPacket(elem.endpoint)
logDebug.Println(peer, "- Received handshake initiation")
@@ -473,10 +450,7 @@ func (device *Device) RoutineHandshake() {
}
// update endpoint
peer.mutex.Lock()
peer.endpoint = elem.endpoint
peer.mutex.Unlock()
peer.SetEndpointFromPacket(elem.endpoint)
logDebug.Println(peer, "- Received handshake response")
@@ -512,9 +486,18 @@ func (peer *Peer) RoutineSequentialReceiver() {
logError := device.log.Error
logDebug := device.log.Debug
var elem *QueueInboundElement
var ok bool
defer func() {
logDebug.Println(peer, "- Routine: sequential receiver - stopped")
peer.routines.stopping.Done()
if elem != nil {
if !elem.IsDropped() {
device.PutMessageBuffer(elem.buffer)
}
device.PutInboundElement(elem)
}
}()
logDebug.Println(peer, "- Routine: sequential receiver - started")
@@ -522,13 +505,20 @@ func (peer *Peer) RoutineSequentialReceiver() {
peer.routines.starting.Done()
for {
if elem != nil {
if !elem.IsDropped() {
device.PutMessageBuffer(elem.buffer)
}
device.PutInboundElement(elem)
elem = nil
}
select {
case <-peer.routines.stop:
return
case elem, ok := <-peer.queue.inbound:
case elem, ok = <-peer.queue.inbound:
if !ok {
return
@@ -549,10 +539,7 @@ func (peer *Peer) RoutineSequentialReceiver() {
}
// 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) {
@@ -642,10 +629,7 @@ func (peer *Peer) RoutineSequentialReceiver() {
offset := MessageTransportOffsetContent
atomic.AddUint64(&peer.stats.rxBytes, uint64(len(elem.packet)))
_, err := device.tun.device.Write(
elem.buffer[:offset+len(elem.packet)],
offset)
device.PutMessageBuffer(elem.buffer)
_, err := device.tun.device.Write(elem.buffer[:offset+len(elem.packet)], offset)
if err != nil {
logError.Println("Failed to write packet to TUN device:", err)
}

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package replay

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package replay

View File

@@ -2,7 +2,7 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package rwcancel

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package rwcancel

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package rwcancel
@@ -40,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
}
@@ -86,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() {
@@ -98,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() {

View File

@@ -2,7 +2,7 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package rwcancel

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package rwcancel

136
send.go
View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main
@@ -53,10 +52,14 @@ type QueueOutboundElement struct {
}
func (device *Device) NewOutboundElement() *QueueOutboundElement {
return &QueueOutboundElement{
dropped: AtomicFalse,
buffer: device.pool.messageBuffers.Get().(*[MaxMessageSize]byte),
}
elem := device.GetOutboundElement()
elem.dropped = AtomicFalse
elem.buffer = device.GetMessageBuffer()
elem.mutex = sync.Mutex{}
elem.nonce = 0
elem.keypair = nil
elem.peer = nil
return elem
}
func (elem *QueueOutboundElement) Drop() {
@@ -67,10 +70,7 @@ func (elem *QueueOutboundElement) IsDropped() bool {
return atomic.LoadInt32(&elem.dropped) == AtomicTrue
}
func addToOutboundQueue(
queue chan *QueueOutboundElement,
element *QueueOutboundElement,
) {
func addToNonceQueue(queue chan *QueueOutboundElement, element *QueueOutboundElement, device *Device) {
for {
select {
case queue <- element:
@@ -78,30 +78,28 @@ func addToOutboundQueue(
default:
select {
case old := <-queue:
old.Drop()
device.PutMessageBuffer(old.buffer)
device.PutOutboundElement(old)
default:
}
}
}
}
func addToEncryptionQueue(
queue chan *QueueOutboundElement,
element *QueueOutboundElement,
) {
for {
func addToOutboundAndEncryptionQueues(outboundQueue chan *QueueOutboundElement, encryptionQueue chan *QueueOutboundElement, element *QueueOutboundElement) {
select {
case outboundQueue <- element:
select {
case queue <- element:
case encryptionQueue <- element:
return
default:
select {
case old := <-queue:
// drop & release to potential consumer
old.Drop()
old.mutex.Unlock()
default:
}
element.Drop()
element.peer.device.PutMessageBuffer(element.buffer)
element.mutex.Unlock()
}
default:
element.peer.device.PutMessageBuffer(element.buffer)
element.peer.device.PutOutboundElement(element)
}
}
@@ -118,6 +116,8 @@ func (peer *Peer) SendKeepalive() bool {
peer.device.log.Debug.Println(peer, "- Sending keepalive packet")
return true
default:
peer.device.PutMessageBuffer(elem.buffer)
peer.device.PutOutboundElement(elem)
return false
}
}
@@ -243,8 +243,6 @@ func (peer *Peer) keepKeyFreshSending() {
*/
func (device *Device) RoutineReadFromTUN() {
elem := device.NewOutboundElement()
logDebug := device.log.Debug
logError := device.log.Error
@@ -256,7 +254,14 @@ func (device *Device) RoutineReadFromTUN() {
logDebug.Println("Routine: TUN reader - started")
device.state.starting.Done()
var elem *QueueOutboundElement
for {
if elem != nil {
device.PutMessageBuffer(elem.buffer)
device.PutOutboundElement(elem)
}
elem = device.NewOutboundElement()
// read packet
@@ -268,6 +273,8 @@ func (device *Device) RoutineReadFromTUN() {
logError.Println("Failed to read packet from TUN device:", err)
device.Close()
}
device.PutMessageBuffer(elem.buffer)
device.PutOutboundElement(elem)
return
}
@@ -309,8 +316,8 @@ func (device *Device) RoutineReadFromTUN() {
if peer.queue.packetInNonceQueueIsAwaitingKey.Get() {
peer.SendHandshakeInitiation(false)
}
addToOutboundQueue(peer.queue.nonce, elem)
elem = device.NewOutboundElement()
addToNonceQueue(peer.queue.nonce, elem, device)
elem = nil
}
}
}
@@ -334,22 +341,25 @@ func (peer *Peer) RoutineNonce() {
device := peer.device
logDebug := device.log.Debug
defer func() {
logDebug.Println(peer, "- Routine: nonce worker - stopped")
peer.queue.packetInNonceQueueIsAwaitingKey.Set(false)
peer.routines.stopping.Done()
}()
flush := func() {
for {
select {
case <-peer.queue.nonce:
case elem := <-peer.queue.nonce:
device.PutMessageBuffer(elem.buffer)
device.PutOutboundElement(elem)
default:
return
}
}
}
defer func() {
flush()
logDebug.Println(peer, "- Routine: nonce worker - stopped")
peer.queue.packetInNonceQueueIsAwaitingKey.Set(false)
peer.routines.stopping.Done()
}()
peer.routines.starting.Done()
logDebug.Println(peer, "- Routine: nonce worker - started")
@@ -403,10 +413,14 @@ func (peer *Peer) RoutineNonce() {
logDebug.Println(peer, "- Obtained awaited keypair")
case <-peer.signals.flushNonceQueue:
device.PutMessageBuffer(elem.buffer)
device.PutOutboundElement(elem)
flush()
goto NextPacket
case <-peer.routines.stop:
device.PutMessageBuffer(elem.buffer)
device.PutOutboundElement(elem)
return
}
}
@@ -421,6 +435,8 @@ func (peer *Peer) RoutineNonce() {
if elem.nonce >= RejectAfterMessages {
atomic.StoreUint64(&keypair.sendNonce, RejectAfterMessages)
device.PutMessageBuffer(elem.buffer)
device.PutOutboundElement(elem)
goto NextPacket
}
@@ -429,9 +445,7 @@ func (peer *Peer) RoutineNonce() {
elem.mutex.Lock()
// add to parallel and sequential queue
addToEncryptionQueue(device.queue.encryption, elem)
addToOutboundQueue(peer.queue.outbound, elem)
addToOutboundAndEncryptionQueues(peer.queue.outbound, device.queue.encryption, elem)
}
}
}
@@ -448,6 +462,19 @@ func (device *Device) RoutineEncryption() {
logDebug := device.log.Debug
defer func() {
for {
select {
case elem, ok := <-device.queue.encryption:
if ok && !elem.IsDropped() {
elem.Drop()
device.PutMessageBuffer(elem.buffer)
elem.mutex.Unlock()
}
default:
goto out
}
}
out:
logDebug.Println("Routine: encryption worker - stopped")
device.state.stopping.Done()
}()
@@ -490,11 +517,13 @@ func (device *Device) RoutineEncryption() {
// pad content to multiple of 16
mtu := int(atomic.LoadInt32(&device.tun.mtu))
rem := len(elem.packet) % PaddingMultiple
if rem > 0 {
for i := 0; i < PaddingMultiple-rem && len(elem.packet) < mtu; i++ {
elem.packet = append(elem.packet, 0)
}
lastUnit := len(elem.packet) % mtu
paddedSize := (lastUnit + PaddingMultiple - 1) & ^(PaddingMultiple - 1)
if paddedSize > mtu {
paddedSize = mtu
}
for i := len(elem.packet); i < paddedSize; i++ {
elem.packet = append(elem.packet, 0)
}
// encrypt content and release to consumer
@@ -521,8 +550,25 @@ func (peer *Peer) RoutineSequentialSender() {
device := peer.device
logDebug := device.log.Debug
logError := device.log.Error
defer func() {
for {
select {
case elem, ok := <-peer.queue.outbound:
if ok {
if !elem.IsDropped() {
device.PutMessageBuffer(elem.buffer)
elem.Drop()
}
device.PutOutboundElement(elem)
elem.mutex.Unlock()
}
default:
goto out
}
}
out:
logDebug.Println(peer, "- Routine: sequential sender - stopped")
peer.routines.stopping.Done()
}()
@@ -545,6 +591,7 @@ func (peer *Peer) RoutineSequentialSender() {
elem.mutex.Lock()
if elem.IsDropped() {
device.PutOutboundElement(elem)
continue
}
@@ -556,8 +603,9 @@ func (peer *Peer) RoutineSequentialSender() {
length := uint64(len(elem.packet))
err := peer.SendBuffer(elem.packet)
device.PutMessageBuffer(elem.buffer)
device.PutOutboundElement(elem)
if err != nil {
logDebug.Println("Failed to send authenticated packet to peer", peer)
logError.Println(peer, "- Failed to send data packet", err)
continue
}
atomic.AddUint64(&peer.stats.txBytes, length)

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package tai64n

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package tai64n

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2015-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*
* This is based heavily on timers.c from the kernel implementation.
*/
@@ -134,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()
}

3
tun.go
View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package tun

View File

@@ -1,20 +1,22 @@
// +build !ios
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package tun
import (
"git.zx2c4.com/wireguard-go/rwcancel"
"errors"
"fmt"
"git.zx2c4.com/wireguard-go/rwcancel"
"golang.org/x/net/ipv6"
"golang.org/x/sys/unix"
"io/ioutil"
"net"
"os"
"syscall"
"unsafe"
)
@@ -54,8 +56,12 @@ func (tun *nativeTun) routineRouteListener(tunIfindex int) {
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
}
@@ -259,7 +265,7 @@ func (tun *nativeTun) doRead(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() {

View File

@@ -1,19 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package tun
import (
"git.zx2c4.com/wireguard-go/rwcancel"
"bytes"
"errors"
"fmt"
"git.zx2c4.com/wireguard-go/rwcancel"
"golang.org/x/net/ipv6"
"golang.org/x/sys/unix"
"net"
"os"
"syscall"
"unsafe"
)
@@ -67,8 +68,12 @@ func (tun *nativeTun) routineRouteListener(tunIfindex int) {
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
}
@@ -257,19 +262,6 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) {
return nil, fmt.Errorf("error %s", errno.Error())
}
// Set TUN iface to broadcast mode. TUN inferfaces on freebsd come up in point to point by default
ifmodemode := unix.IFF_BROADCAST
_, _, errno = unix.Syscall(
unix.SYS_IOCTL,
uintptr(tunfd),
uintptr(_TUNSIFMODE),
uintptr(unsafe.Pointer(&ifmodemode)),
)
if errno != 0 {
return nil, fmt.Errorf("error %s", errno.Error())
}
// Rename tun interface
// Open control socket
@@ -392,7 +384,7 @@ func (tun *nativeTun) doRead(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() {

View File

@@ -1,21 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
/* Copyright 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
package tun
/* Implementation of the TUN device interface for linux
*/
import (
"git.zx2c4.com/wireguard-go/rwcancel"
"bytes"
"errors"
"fmt"
"git.zx2c4.com/wireguard-go/rwcancel"
"golang.org/x/net/ipv6"
"golang.org/x/sys/unix"
"net"
@@ -102,7 +99,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() {
@@ -334,7 +331,7 @@ func (tun *nativeTun) doRead(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() {

View File

@@ -1,14 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package tun
import (
"git.zx2c4.com/wireguard-go/rwcancel"
"errors"
"fmt"
"git.zx2c4.com/wireguard-go/rwcancel"
"golang.org/x/net/ipv6"
"golang.org/x/sys/unix"
"io/ioutil"
@@ -46,8 +46,12 @@ func (tun *nativeTun) routineRouteListener(tunIfindex int) {
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
}
@@ -90,9 +94,7 @@ func (tun *nativeTun) routineRouteListener(tunIfindex int) {
func errorIsEBUSY(err error) bool {
if pe, ok := err.(*os.PathError); ok {
if errno, ok := pe.Err.(syscall.Errno); ok && errno == syscall.EBUSY {
return true
}
err = pe.Err
}
if errno, ok := err.(syscall.Errno); ok && errno == syscall.EBUSY {
return true
@@ -127,19 +129,6 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) {
return nil, err
}
// Set TUN iface to broadcast mode
ifmodemode := unix.IFF_BROADCAST
_, _, errno := unix.Syscall(
unix.SYS_IOCTL,
uintptr(tunfile.Fd()),
uintptr(_TUNSIFMODE),
uintptr(unsafe.Pointer(&ifmodemode)),
)
if errno != 0 {
return nil, fmt.Errorf("error %s", errno.Error())
}
tun, err := CreateTUNFromFile(tunfile, mtu)
if err == nil && name == "tun" {
@@ -237,7 +226,7 @@ func (tun *nativeTun) doRead(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() {

11
uapi.go
View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main
@@ -75,6 +74,7 @@ func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
send("public_key=" + peer.handshake.remoteStatic.ToHex())
send("preshared_key=" + peer.handshake.presharedKey.ToHex())
send("protocol_version=1")
if peer.endpoint != nil {
send("endpoint=" + peer.endpoint.DstToString())
}
@@ -362,6 +362,13 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
ones, _ := network.Mask.Size()
device.allowedips.Insert(network.IP, uint(ones), peer)
case "protocol_version":
if value != "1" {
logError.Println("Invalid protocol version:", value)
return &IPCError{Code: ipcErrorInvalid}
}
default:
logError.Println("Invalid UAPI peer key:", key)
return &IPCError{Code: ipcErrorInvalid}

View File

@@ -2,8 +2,7 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main
@@ -18,12 +17,13 @@ import (
"unsafe"
)
var socketDirectory = "/var/run/wireguard"
const (
ipcErrorIO = -int64(unix.EIO)
ipcErrorProtocol = -int64(unix.EPROTO)
ipcErrorInvalid = -int64(unix.EINVAL)
ipcErrorPortInUse = -int64(unix.EADDRINUSE)
socketDirectory = "/var/run/wireguard"
socketName = "%s.sock"
)

View File

@@ -1,27 +1,27 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package main
import (
"git.zx2c4.com/wireguard-go/rwcancel"
"errors"
"fmt"
"git.zx2c4.com/wireguard-go/rwcancel"
"golang.org/x/sys/unix"
"net"
"os"
"path"
)
var socketDirectory = "/var/run/wireguard"
const (
ipcErrorIO = -int64(unix.EIO)
ipcErrorProtocol = -int64(unix.EPROTO)
ipcErrorInvalid = -int64(unix.EINVAL)
ipcErrorPortInUse = -int64(unix.EADDRINUSE)
socketDirectory = "/var/run/wireguard"
socketName = "%s.sock"
)

View File

@@ -1,2 +1,2 @@
package main
const WireGuardGoVersion = "0.0.20180524"
const WireGuardGoVersion = "0.0.20181001"

View File

@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (C) 2016 Andreas Auernhammer. All Rights Reserved.
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package xchacha20poly1305

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
*/
package xchacha20poly1305