Merge branch 'master' of ssh://git.zx2c4.com/wireguard-go

This commit is contained in:
Mathias Hall-Andersen 2018-05-05 02:23:03 +02:00
commit edbce6b400
50 changed files with 499 additions and 228 deletions

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import "errors" import "errors"

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,5 +1,10 @@
// +build !linux // +build !linux
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,4 +1,6 @@
/* Copyright 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. /* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* *
* This implements userspace semantics of "sticky sockets", modeled after * This implements userspace semantics of "sticky sockets", modeled after
* WireGuard's kernelspace implementation. This is more or less a straight port * WireGuard's kernelspace implementation. This is more or less a straight port

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,9 +0,0 @@
package main
import (
"errors"
)
func Daemonize() error {
return errors.New("Not implemented on OSX")
}

View file

@ -1,32 +0,0 @@
package main
import (
"os"
"os/exec"
)
/* Daemonizes the process on linux
*
* This is done by spawning and releasing a copy with the --foreground flag
*/
func Daemonize(attr *os.ProcAttr) error {
// I would like to use os.Executable,
// however this means dropping support for Go <1.8
path, err := exec.LookPath(os.Args[0])
if err != nil {
return err
}
argv := []string{os.Args[0], "--foreground"}
argv = append(argv, os.Args[1:]...)
process, err := os.StartProcess(
path,
argv,
attr,
)
if err != nil {
return err
}
process.Release()
return nil
}

View file

@ -1,34 +0,0 @@
package main
import (
"os"
)
/* Daemonizes the process on windows
*
* This is done by spawning and releasing a copy with the --foreground flag
*/
func Daemonize() error {
argv := []string{os.Args[0], "--foreground"}
argv = append(argv, os.Args[1:]...)
attr := &os.ProcAttr{
Dir: ".",
Env: os.Environ(),
Files: []*os.File{
os.Stdin,
nil,
nil,
},
}
process, err := os.StartProcess(
argv[0],
argv,
attr,
)
if err != nil {
return err
}
process.Release()
return nil
}

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
/* Create two device instances and simulate full WireGuard interaction /* Create two device instances and simulate full WireGuard interaction

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

5
ip.go
View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

97
main.go
View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (
@ -14,8 +19,9 @@ const (
) )
const ( const (
ENV_WG_TUN_FD = "WG_TUN_FD" ENV_WG_TUN_FD = "WG_TUN_FD"
ENV_WG_UAPI_FD = "WG_UAPI_FD" ENV_WG_UAPI_FD = "WG_UAPI_FD"
ENV_WG_PROCESS_FOREGROUND = "WG_PROCESS_FOREGROUND"
) )
func printUsage() { func printUsage() {
@ -23,7 +29,45 @@ func printUsage() {
fmt.Printf("%s [-f/--foreground] INTERFACE-NAME\n", os.Args[0]) fmt.Printf("%s [-f/--foreground] INTERFACE-NAME\n", os.Args[0])
} }
func warning() {
shouldQuit := false
fmt.Fprintln(os.Stderr, "WARNING WARNING WARNING WARNING WARNING WARNING WARNING")
fmt.Fprintln(os.Stderr, "W G")
fmt.Fprintln(os.Stderr, "W This is alpha software. It will very likely not G")
fmt.Fprintln(os.Stderr, "W do what it is supposed to do, and things may go G")
fmt.Fprintln(os.Stderr, "W horribly wrong. You have been warned. Proceed G")
fmt.Fprintln(os.Stderr, "W at your own risk. G")
if runtime.GOOS == "linux" {
shouldQuit = os.Getenv("WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD") != "1"
fmt.Fprintln(os.Stderr, "W G")
fmt.Fprintln(os.Stderr, "W Furthermore, you are running this software on a G")
fmt.Fprintln(os.Stderr, "W Linux kernel, which is probably unnecessary and G")
fmt.Fprintln(os.Stderr, "W foolish. This is because the Linux kernel has G")
fmt.Fprintln(os.Stderr, "W built-in first class support for WireGuard, and G")
fmt.Fprintln(os.Stderr, "W this support is much more refined than this G")
fmt.Fprintln(os.Stderr, "W program. For more information on installing the G")
fmt.Fprintln(os.Stderr, "W kernel module, please visit: G")
fmt.Fprintln(os.Stderr, "W https://www.wireguard.com/install G")
if shouldQuit {
fmt.Fprintln(os.Stderr, "W G")
fmt.Fprintln(os.Stderr, "W If you still want to use this program, against G")
fmt.Fprintln(os.Stderr, "W the sage advice here, please first export this G")
fmt.Fprintln(os.Stderr, "W environment variable: G")
fmt.Fprintln(os.Stderr, "W WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD=1 G")
}
}
fmt.Fprintln(os.Stderr, "W G")
fmt.Fprintln(os.Stderr, "WARNING WARNING WARNING WARNING WARNING WARNING WARNING")
if shouldQuit {
os.Exit(1)
}
}
func main() { func main() {
warning()
// parse arguments // parse arguments
@ -53,6 +97,10 @@ func main() {
interfaceName = os.Args[1] interfaceName = os.Args[1]
} }
if !foreground {
foreground = os.Getenv(ENV_WG_PROCESS_FOREGROUND) == "1"
}
// get log level (default: info) // get log level (default: info)
logLevel := func() int { logLevel := func() int {
@ -67,13 +115,6 @@ func main() {
return LogLevelInfo return LogLevelInfo
}() }()
logger := NewLogger(
logLevel,
fmt.Sprintf("(%s) ", interfaceName),
)
logger.Debug.Println("Debug log enabled")
// open TUN device (or use supplied fd) // open TUN device (or use supplied fd)
tun, err := func() (TUNDevice, error) { tun, err := func() (TUNDevice, error) {
@ -93,6 +134,21 @@ func main() {
return CreateTUNFromFile(file) return CreateTUNFromFile(file)
}() }()
if err == nil {
realInterfaceName, err2 := tun.Name()
if err2 == nil {
interfaceName = realInterfaceName
}
}
logger := NewLogger(
logLevel,
fmt.Sprintf("(%s) ", interfaceName),
)
logger.Debug.Println("Debug log enabled")
if err != nil { if err != nil {
logger.Error.Println("Failed to create TUN device:", err) logger.Error.Println("Failed to create TUN device:", err)
os.Exit(ExitSetupFailed) os.Exit(ExitSetupFailed)
@ -127,6 +183,7 @@ func main() {
env := os.Environ() env := os.Environ()
env = append(env, fmt.Sprintf("%s=3", ENV_WG_TUN_FD)) env = append(env, fmt.Sprintf("%s=3", ENV_WG_TUN_FD))
env = append(env, fmt.Sprintf("%s=4", ENV_WG_UAPI_FD)) env = append(env, fmt.Sprintf("%s=4", ENV_WG_UAPI_FD))
env = append(env, fmt.Sprintf("%s=1", ENV_WG_PROCESS_FOREGROUND))
attr := &os.ProcAttr{ attr := &os.ProcAttr{
Files: []*os.File{ Files: []*os.File{
nil, // stdin nil, // stdin
@ -138,18 +195,26 @@ func main() {
Dir: ".", Dir: ".",
Env: env, Env: env,
} }
err = Daemonize(attr)
path, err := os.Executable()
if err != nil {
logger.Error.Println("Failed to determine executable:", err)
os.Exit(ExitSetupFailed)
}
process, err := os.StartProcess(
path,
os.Args,
attr,
)
if err != nil { if err != nil {
logger.Error.Println("Failed to daemonize:", err) logger.Error.Println("Failed to daemonize:", err)
os.Exit(ExitSetupFailed) os.Exit(ExitSetupFailed)
} }
process.Release()
return return
} }
// increase number of go workers (for Go <1.5)
runtime.GOMAXPROCS(runtime.NumCPU())
// create wireguard device // create wireguard device
device := NewDevice(tun, logger) device := NewDevice(tun, logger)
@ -162,6 +227,10 @@ func main() {
term := make(chan os.Signal) term := make(chan os.Signal)
uapi, err := UAPIListen(interfaceName, fileUAPI) uapi, err := UAPIListen(interfaceName, fileUAPI)
if err != nil {
logger.Error.Println("Failed to listen on uapi socket:", err)
os.Exit(ExitSetupFailed)
}
go func() { go func() {
for { for {

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,9 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package ratelimiter package ratelimiter
/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
/* This file contains a port of the rate-limiter from the linux kernel version */
import ( import (
"net" "net"
"sync" "sync"

View file

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

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */ /* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
func signalSend(s chan<- struct{}) { func signalSend(s chan<- struct{}) {

View file

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

View file

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

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

5
tun.go
View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,22 +1,17 @@
/* Copyright (c) 2016, Song Gao <song@gao.io> /* SPDX-License-Identifier: GPL-2.0
* All rights reserved.
* *
* Code from https://github.com/songgao/water * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/ */
package main package main
import ( import (
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6" "golang.org/x/net/ipv6"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"io"
"net" "net"
"os" "os"
"sync"
"time" "time"
"unsafe" "unsafe"
) )
@ -36,36 +31,32 @@ type sockaddrCtl struct {
scReserved [5]uint32 scReserved [5]uint32
} }
// NativeTUN is a hack to work around the first 4 bytes "packet // 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. // information" because there doesn't seem to be an IFF_NO_PI for darwin.
type NativeTUN struct { type NativeTun struct {
name string name string
f io.ReadWriteCloser fd *os.File
mtu int mtu int
rMu sync.Mutex
rBuf []byte
wMu sync.Mutex
wBuf []byte
events chan TUNEvent events chan TUNEvent
errors chan error errors chan error
} }
var sockaddrCtlSize uintptr = 32 var sockaddrCtlSize uintptr = 32
func CreateTUN(name string) (ifce TUNDevice, err error) { func CreateTUN(name string) (TUNDevice, error) {
ifIndex := -1 ifIndex := -1
fmt.Sscanf(name, "utun%d", &ifIndex) if (name != "utun") {
if ifIndex < 0 { fmt.Sscanf(name, "utun%d", &ifIndex)
return nil, fmt.Errorf("error parsing interface name %s, must be utun[0-9]+", name) if ifIndex < 0 {
return nil, fmt.Errorf("Interface name must be utun[0-9]*")
}
} }
fd, err := unix.Socket(unix.AF_SYSTEM, unix.SOCK_DGRAM, 2) fd, err := unix.Socket(unix.AF_SYSTEM, unix.SOCK_DGRAM, 2)
if err != nil { if err != nil {
return nil, fmt.Errorf("error in unix.Socket: %v", err) return nil, err
} }
var ctlInfo = &struct { var ctlInfo = &struct {
@ -83,8 +74,7 @@ func CreateTUN(name string) (ifce TUNDevice, err error) {
) )
if errno != 0 { if errno != 0 {
err = errno return nil, fmt.Errorf("_CTLIOCGINFO: %v", errno)
return nil, fmt.Errorf("error in unix.Syscall(unix.SYS_IOTL, ...): %v", err)
} }
sc := sockaddrCtl{ sc := sockaddrCtl{
@ -105,148 +95,139 @@ func CreateTUN(name string) (ifce TUNDevice, err error) {
) )
if errno != 0 { if errno != 0 {
err = errno return nil, fmt.Errorf("SYS_CONNECT: %v", errno)
return nil, fmt.Errorf("error in unix.RawSyscall(unix.SYS_CONNECT, ...): %v", err)
} }
// read (new) name of interface tun, err := CreateTUNFromFile(os.NewFile(uintptr(fd), ""))
var ifName struct { if err == nil && name == "utun" {
name [16]byte fmt.Printf("OS assigned interface: %s\n", tun.(*NativeTun).name)
}
ifNameSize := uintptr(16)
_, _, errno = unix.Syscall6(
unix.SYS_GETSOCKOPT,
uintptr(fd),
2, /* #define SYSPROTO_CONTROL 2 */
2, /* #define UTUN_OPT_IFNAME 2 */
uintptr(unsafe.Pointer(&ifName)),
uintptr(unsafe.Pointer(&ifNameSize)), 0)
if errno != 0 {
err = errno
return nil, fmt.Errorf("error in unix.Syscall6(unix.SYS_GETSOCKOPT, ...): %v", err)
} }
device := &NativeTUN{ return tun, err
name: string(ifName.name[:ifNameSize-1 /* -1 is for \0 */]), }
f: os.NewFile(uintptr(fd), string(ifName.name[:])),
func CreateTUNFromFile(file *os.File) (TUNDevice, error) {
tun := &NativeTun{
fd: file,
mtu: 1500, mtu: 1500,
events: make(chan TUNEvent, 10), events: make(chan TUNEvent, 10),
errors: make(chan error, 1), errors: make(chan error, 1),
} }
// start listener _, err := tun.Name()
if err != nil {
return nil, err
}
go func(native *NativeTUN) { // TODO: Fix this very naive implementation
// TODO: Fix this very niave implementation go func(tun *NativeTun) {
var ( var (
statusUp bool statusUp bool
statusMTU int statusMTU int
) )
for ; ; time.Sleep(time.Second) { for ; ; time.Sleep(time.Second) {
intr, err := net.InterfaceByName(device.name) intr, err := net.InterfaceByName(tun.name)
if err != nil { if err != nil {
native.errors <- err tun.errors <- err
return return
} }
// Up / Down event // Up / Down event
up := (intr.Flags & net.FlagUp) != 0 up := (intr.Flags & net.FlagUp) != 0
if up != statusUp && up { if up != statusUp && up {
native.events <- TUNEventUp tun.events <- TUNEventUp
} }
if up != statusUp && !up { if up != statusUp && !up {
native.events <- TUNEventDown tun.events <- TUNEventDown
} }
statusUp = up statusUp = up
// MTU changes // MTU changes
if intr.MTU != statusMTU { if intr.MTU != statusMTU {
native.events <- TUNEventMTUUpdate tun.events <- TUNEventMTUUpdate
} }
statusMTU = intr.MTU statusMTU = intr.MTU
} }
}(device) }(tun)
// set default MTU // set default MTU
err = tun.setMTU(DefaultMTU)
err = device.setMTU(DefaultMTU) return tun, err
return device, err
} }
var _ io.ReadWriteCloser = (*NativeTUN)(nil) func (tun *NativeTun) Name() (string, error) {
func (t *NativeTUN) Events() chan TUNEvent { var ifName struct {
return t.events name [16]byte
}
func (t *NativeTUN) Read(to []byte) (int, error) {
t.rMu.Lock()
defer t.rMu.Unlock()
if cap(t.rBuf) < len(to)+4 {
t.rBuf = make([]byte, len(to)+4)
} }
t.rBuf = t.rBuf[:len(to)+4] ifNameSize := uintptr(16)
n, err := t.f.Read(t.rBuf) _, _, errno := unix.Syscall6(
copy(to, t.rBuf[4:]) unix.SYS_GETSOCKOPT,
uintptr(tun.fd.Fd()),
2, /* #define SYSPROTO_CONTROL 2 */
2, /* #define UTUN_OPT_IFNAME 2 */
uintptr(unsafe.Pointer(&ifName)),
uintptr(unsafe.Pointer(&ifNameSize)), 0)
if errno != 0 {
return "", fmt.Errorf("SYS_GETSOCKOPT: %v", errno)
}
tun.name = string(ifName.name[:ifNameSize-1])
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) Read(buff []byte, offset int) (int, error) {
buff = buff[offset-4:]
n, err := tun.fd.Read(buff[:])
if n < 4 {
return 0, err
}
return n - 4, err return n - 4, err
} }
func (t *NativeTUN) Write(from []byte) (int, error) { func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
if len(from) == 0 { // reserve space for header
return 0, unix.EIO
}
t.wMu.Lock() buff = buff[offset-4:]
defer t.wMu.Unlock()
if cap(t.wBuf) < len(from)+4 { // add packet information header
t.wBuf = make([]byte, len(from)+4)
}
t.wBuf = t.wBuf[:len(from)+4]
// determine the IP Family for the NULL L2 Header buff[0] = 0x00
buff[1] = 0x00
buff[2] = 0x00
ipVer := from[0] >> 4 if buff[4]>>4 == ipv6.Version {
if ipVer == ipv4.Version { buff[3] = unix.AF_INET6
t.wBuf[3] = unix.AF_INET
} else if ipVer == ipv6.Version {
t.wBuf[3] = unix.AF_INET6
} else { } else {
return 0, errors.New("Unable to determine IP version from packet.") buff[3] = unix.AF_INET
} }
copy(t.wBuf[4:], from) // write
n, err := t.f.Write(t.wBuf) return tun.fd.Write(buff)
return n - 4, err
} }
func (t *NativeTUN) Close() error { func (tun *NativeTun) Close() error {
return tun.fd.Close()
// lock to make sure no read/write is in process.
t.rMu.Lock()
defer t.rMu.Unlock()
t.wMu.Lock()
defer t.wMu.Unlock()
return t.f.Close()
} }
func (t *NativeTUN) Name() string { func (tun *NativeTun) setMTU(n int) error {
return t.name
}
func (t *NativeTUN) setMTU(n int) error {
// open datagram socket // open datagram socket
@ -267,7 +248,7 @@ func (t *NativeTUN) setMTU(n int) error {
// do ioctl call // do ioctl call
var ifr [32]byte var ifr [32]byte
copy(ifr[:], t.name) copy(ifr[:], tun.name)
binary.LittleEndian.PutUint32(ifr[16:20], uint32(n)) binary.LittleEndian.PutUint32(ifr[16:20], uint32(n))
_, _, errno := unix.Syscall( _, _, errno := unix.Syscall(
unix.SYS_IOCTL, unix.SYS_IOCTL,
@ -277,13 +258,13 @@ func (t *NativeTUN) setMTU(n int) error {
) )
if errno != 0 { if errno != 0 {
return fmt.Errorf("Failed to set MTU on %s", t.name) return fmt.Errorf("Failed to set MTU on %s", tun.name)
} }
return nil return nil
} }
func (t *NativeTUN) MTU() (int, error) { func (tun *NativeTun) MTU() (int, error) {
// open datagram socket // open datagram socket
@ -302,7 +283,7 @@ func (t *NativeTUN) MTU() (int, error) {
// do ioctl call // do ioctl call
var ifr [64]byte var ifr [64]byte
copy(ifr[:], t.name) copy(ifr[:], tun.name)
_, _, errno := unix.Syscall( _, _, errno := unix.Syscall(
unix.SYS_IOCTL, unix.SYS_IOCTL,
uintptr(fd), uintptr(fd),
@ -310,7 +291,7 @@ func (t *NativeTUN) MTU() (int, error) {
uintptr(unsafe.Pointer(&ifr[0])), uintptr(unsafe.Pointer(&ifr[0])),
) )
if errno != 0 { if errno != 0 {
return 0, fmt.Errorf("Failed to get MTU on %s", t.name) return 0, fmt.Errorf("Failed to get MTU on %s", tun.name)
} }
// convert result to signed 32-bit int // convert result to signed 32-bit int

View file

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

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,12 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (
"errors"
"fmt" "fmt"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"net" "net"
"os" "os"
"path" "path"
"time"
) )
const ( const (
@ -22,6 +27,8 @@ type UAPIListener struct {
listener net.Listener // unix socket listener listener net.Listener // unix socket listener
connNew chan net.Conn connNew chan net.Conn
connErr chan error connErr chan error
kqueueFd int
keventFd int
} }
func (l *UAPIListener) Accept() (net.Conn, error) { func (l *UAPIListener) Accept() (net.Conn, error) {
@ -37,30 +44,27 @@ func (l *UAPIListener) Accept() (net.Conn, error) {
} }
func (l *UAPIListener) Close() error { func (l *UAPIListener) Close() error {
return l.listener.Close() err1 := unix.Close(l.kqueueFd)
err2 := unix.Close(l.keventFd)
err3 := l.listener.Close()
if err1 != nil {
return err1
}
if err2 != nil {
return err2
}
return err3
} }
func (l *UAPIListener) Addr() net.Addr { func (l *UAPIListener) Addr() net.Addr {
return nil return nil
} }
func NewUAPIListener(name string) (net.Listener, error) { func UAPIListen(name string, file *os.File) (net.Listener, error) {
// check if path exist // wrap file in listener
err := os.MkdirAll(socketDirectory, 077) listener, err := net.FileListener(file)
if err != nil && !os.IsExist(err) {
return nil, err
}
// open UNIX socket
socketPath := path.Join(
socketDirectory,
fmt.Sprintf(socketName, name),
)
listener, err := net.Listen("unix", socketPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -71,14 +75,43 @@ func NewUAPIListener(name string) (net.Listener, error) {
connErr: make(chan error, 1), connErr: make(chan error, 1),
} }
socketPath := path.Join(
socketDirectory,
fmt.Sprintf(socketName, name),
)
// watch for deletion of socket // watch for deletion of socket
uapi.kqueueFd, err = unix.Kqueue()
if err != nil {
return nil, err
}
uapi.keventFd, err = unix.Open(socketDirectory, unix.O_EVTONLY, 0)
if err != nil {
unix.Close(uapi.kqueueFd)
return nil, err
}
go func(l *UAPIListener) { go func(l *UAPIListener) {
for ; ; time.Sleep(time.Second) { event := unix.Kevent_t{
if _, err := os.Stat(socketPath); os.IsNotExist(err) { Ident: uint64(uapi.keventFd),
Filter: unix.EVFILT_VNODE,
Flags: unix.EV_ADD | unix.EV_ENABLE | unix.EV_ONESHOT,
Fflags: unix.NOTE_WRITE,
}
events := make([]unix.Kevent_t, 1)
n := 1
var kerr error
for {
// start with lstat to avoid race condition
if _, err := os.Lstat(socketPath); os.IsNotExist(err) {
l.connErr <- err l.connErr <- err
return return
} }
if kerr != nil || n != 1 {
return
}
n, kerr = unix.Kevent(uapi.kqueueFd, []unix.Kevent_t{event}, events, nil)
} }
}(uapi) }(uapi)
@ -97,3 +130,56 @@ func NewUAPIListener(name string) (net.Listener, error) {
return uapi, nil return uapi, nil
} }
func UAPIOpen(name string) (*os.File, error) {
// check if path exist
err := os.MkdirAll(socketDirectory, 0600)
if err != nil && !os.IsExist(err) {
return nil, err
}
// open UNIX socket
socketPath := path.Join(
socketDirectory,
fmt.Sprintf(socketName, name),
)
addr, err := net.ResolveUnixAddr("unix", socketPath)
if err != nil {
return nil, err
}
listener, err := func() (*net.UnixListener, error) {
// initial connection attempt
listener, err := net.ListenUnix("unix", addr)
if err == nil {
return listener, nil
}
// check if socket already active
_, err = net.Dial("unix", socketPath)
if err == nil {
return nil, errors.New("unix socket in use")
}
// cleanup & attempt again
err = os.Remove(socketPath)
if err != nil {
return nil, err
}
return net.ListenUnix("unix", addr)
}()
if err != nil {
return nil, err
}
return listener.File()
}

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
import ( import (

View file

@ -1,3 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main package main
/* UAPI on windows uses a bidirectional named pipe /* UAPI on windows uses a bidirectional named pipe

View file

@ -1,6 +1,8 @@
// Copyright (c) 2016 Andreas Auernhammer. All rights reserved. /* SPDX-License-Identifier: MIT
// Use of this source code is governed by a license that can be *
// found in the LICENSE file. * Copyright (C) 2016 Andreas Auernhammer. All Rights Reserved.
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package xchacha20poly1305 package xchacha20poly1305

View file

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