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
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
import (

View File

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

93
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
import (
@ -16,6 +21,7 @@ const (
const (
ENV_WG_TUN_FD = "WG_TUN_FD"
ENV_WG_UAPI_FD = "WG_UAPI_FD"
ENV_WG_PROCESS_FOREGROUND = "WG_PROCESS_FOREGROUND"
)
func printUsage() {
@ -23,7 +29,45 @@ func printUsage() {
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() {
warning()
// parse arguments
@ -53,6 +97,10 @@ func main() {
interfaceName = os.Args[1]
}
if !foreground {
foreground = os.Getenv(ENV_WG_PROCESS_FOREGROUND) == "1"
}
// get log level (default: info)
logLevel := func() int {
@ -67,13 +115,6 @@ func main() {
return LogLevelInfo
}()
logger := NewLogger(
logLevel,
fmt.Sprintf("(%s) ", interfaceName),
)
logger.Debug.Println("Debug log enabled")
// open TUN device (or use supplied fd)
tun, err := func() (TUNDevice, error) {
@ -93,6 +134,21 @@ func main() {
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 {
logger.Error.Println("Failed to create TUN device:", err)
os.Exit(ExitSetupFailed)
@ -127,6 +183,7 @@ func main() {
env := os.Environ()
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=1", ENV_WG_PROCESS_FOREGROUND))
attr := &os.ProcAttr{
Files: []*os.File{
nil, // stdin
@ -138,18 +195,26 @@ func main() {
Dir: ".",
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 {
logger.Error.Println("Failed to daemonize:", err)
os.Exit(ExitSetupFailed)
}
process.Release()
return
}
// increase number of go workers (for Go <1.5)
runtime.GOMAXPROCS(runtime.NumCPU())
// create wireguard device
device := NewDevice(tun, logger)
@ -162,6 +227,10 @@ func main() {
term := make(chan os.Signal)
uapi, err := UAPIListen(interfaceName, fileUAPI)
if err != nil {
logger.Error.Println("Failed to listen on uapi socket:", err)
os.Exit(ExitSetupFailed)
}
go func() {
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
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
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
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
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
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
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
/* 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 (
"net"
"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
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
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
/* 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
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
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
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
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
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
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
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
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
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
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
import (

View File

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

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. */
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
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
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
import (
"errors"
"fmt"
"golang.org/x/sys/unix"
"net"
"os"
"path"
"time"
)
const (
@ -22,6 +27,8 @@ type UAPIListener struct {
listener net.Listener // unix socket listener
connNew chan net.Conn
connErr chan error
kqueueFd int
keventFd int
}
func (l *UAPIListener) Accept() (net.Conn, error) {
@ -37,30 +44,27 @@ func (l *UAPIListener) Accept() (net.Conn, 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 {
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)
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)
listener, err := net.FileListener(file)
if err != nil {
return nil, err
}
@ -71,14 +75,43 @@ func NewUAPIListener(name string) (net.Listener, error) {
connErr: make(chan error, 1),
}
socketPath := path.Join(
socketDirectory,
fmt.Sprintf(socketName, name),
)
// 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) {
for ; ; time.Sleep(time.Second) {
if _, err := os.Stat(socketPath); os.IsNotExist(err) {
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,
}
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
return
}
if kerr != nil || n != 1 {
return
}
n, kerr = unix.Kevent(uapi.kqueueFd, []unix.Kevent_t{event}, events, nil)
}
}(uapi)
@ -97,3 +130,56 @@ func NewUAPIListener(name string) (net.Listener, error) {
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
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
/* UAPI on windows uses a bidirectional named pipe

View File

@ -1,6 +1,8 @@
// Copyright (c) 2016 Andreas Auernhammer. All rights reserved.
// Use of this source code is governed by a license that can be
// found in the LICENSE file.
/* 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.
*/
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
import (