import (
"./ratelimiter"
+ "./tun"
"runtime"
"sync"
"sync/atomic"
}
tun struct {
- device TUNDevice
+ device tun.TUNDevice
mtu int32
}
}
device.pool.messageBuffers.Put(msg)
}
-func NewDevice(tun TUNDevice, logger *Logger) *Device {
+func NewDevice(tunDevice tun.TUNDevice, logger *Logger) *Device {
device := new(Device)
device.isUp.Set(false)
device.log = logger
- device.tun.device = tun
+ device.tun.device = tunDevice
mtu, err := device.tun.device.MTU()
if err != nil {
logger.Error.Println("Trouble determining MTU, assuming default:", err)
package main
import (
+ "./tun"
"fmt"
"os"
"os/signal"
// open TUN device (or use supplied fd)
- tun, err := func() (TUNDevice, error) {
+ tun, err := func() (tun.TUNDevice, error) {
tunFdStr := os.Getenv(ENV_WG_TUN_FD)
if tunFdStr == "" {
- return CreateTUN(interfaceName)
+ return tun.CreateTUN(interfaceName, DefaultMTU)
}
// construct tun device from supplied fd
}
file := os.NewFile(uintptr(fd), "")
- return CreateTUNFromFile(file)
+ return tun.CreateTUNFromFile(file, DefaultMTU)
}()
if err == nil {
atomic.StoreInt32(&a.flag, flag)
}
-/* Integer manipulation */
-
-func toInt32(n uint32) int32 {
- mask := uint32(1 << 31)
- return int32(-(n & mask) + (n & ^mask))
-}
-
func min(a, b uint) uint {
if a > b {
return b
package main
import (
- "os"
+ "./tun"
"sync/atomic"
)
const DefaultMTU = 1420
-type TUNEvent int
-
-const (
- TUNEventUp = 1 << iota
- TUNEventDown
- TUNEventMTUUpdate
-)
-
-type TUNDevice interface {
- File() *os.File // returns the file descriptor of the device
- Read([]byte, int) (int, error) // read a packet from the device (without any additional headers)
- Write([]byte, int) (int, error) // writes a packet to the device (without any additional headers)
- MTU() (int, error) // returns the MTU of the device
- Name() (string, error) // fetches and returns the current name
- Events() chan TUNEvent // returns a constant channel of events related to the device
- Close() error // stops the device and closes the event channel
-}
-
func (device *Device) RoutineTUNEventReader() {
setUp := false
logDebug := device.log.Debug
device.state.starting.Done()
for event := range device.tun.device.Events() {
- if event&TUNEventMTUUpdate != 0 {
+ if event&tun.TUNEventMTUUpdate != 0 {
mtu, err := device.tun.device.MTU()
old := atomic.LoadInt32(&device.tun.mtu)
if err != nil {
}
}
- if event&TUNEventUp != 0 && !setUp {
+ if event&tun.TUNEventUp != 0 && !setUp {
logInfo.Println("Interface set up")
setUp = true
device.Up()
}
- if event&TUNEventDown != 0 && setUp {
+ if event&tun.TUNEventDown != 0 && setUp {
logInfo.Println("Interface set down")
setUp = false
device.Down()
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ * Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
+ */
+
+package tun
+
+import "os"
+
+type TUNEvent int
+
+const (
+ TUNEventUp = 1 << iota
+ TUNEventDown
+ TUNEventMTUUpdate
+)
+
+type TUNDevice interface {
+ File() *os.File // returns the file descriptor of the device
+ Read([]byte, int) (int, error) // read a packet from the device (without any additional headers)
+ Write([]byte, int) (int, error) // writes a packet to the device (without any additional headers)
+ MTU() (int, error) // returns the MTU of the device
+ Name() (string, error) // fetches and returns the current name
+ Events() chan TUNEvent // returns a constant channel of events related to the device
+ Close() error // stops the device and closes the event channel
+}
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
*/
-package main
+package tun
import (
- "./rwcancel"
- "encoding/binary"
+ "../rwcancel"
"errors"
"fmt"
"golang.org/x/net/ipv6"
scReserved [5]uint32
}
-type NativeTun struct {
+type nativeTun struct {
name string
fd *os.File
rwcancel *rwcancel.RWCancel
var sockaddrCtlSize uintptr = 32
-func (tun *NativeTun) RoutineRouteListener(tunIfindex int) {
+func (tun *nativeTun) routineRouteListener(tunIfindex int) {
var (
statusUp bool
statusMTU int
}
}
-func CreateTUN(name string) (TUNDevice, error) {
+func CreateTUN(name string, mtu int) (TUNDevice, error) {
ifIndex := -1
if name != "utun" {
_, err := fmt.Sscanf(name, "utun%d", &ifIndex)
return nil, fmt.Errorf("SYS_CONNECT: %v", errno)
}
- tun, err := CreateTUNFromFile(os.NewFile(uintptr(fd), ""))
+ tun, err := CreateTUNFromFile(os.NewFile(uintptr(fd), ""), mtu)
if err == nil && name == "utun" {
fname := os.Getenv("WG_TUN_NAME_FILE")
if fname != "" {
- ioutil.WriteFile(fname, []byte(tun.(*NativeTun).name+"\n"), 0400)
+ ioutil.WriteFile(fname, []byte(tun.(*nativeTun).name+"\n"), 0400)
}
}
return tun, err
}
-func CreateTUNFromFile(file *os.File) (TUNDevice, error) {
+func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
- tun := &NativeTun{
+ tun := &nativeTun{
fd: file,
events: make(chan TUNEvent, 10),
errors: make(chan error, 1),
return nil, err
}
- go tun.RoutineRouteListener(tunIfindex)
+ go tun.routineRouteListener(tunIfindex)
- // set default MTU
- err = tun.setMTU(DefaultMTU)
+ err = tun.setMTU(mtu)
if err != nil {
tun.Close()
return nil, err
return tun, nil
}
-func (tun *NativeTun) Name() (string, error) {
+func (tun *nativeTun) Name() (string, error) {
var ifName struct {
name [16]byte
return tun.name, nil
}
-func (tun *NativeTun) File() *os.File {
+func (tun *nativeTun) File() *os.File {
return tun.fd
}
-func (tun *NativeTun) Events() chan TUNEvent {
+func (tun *nativeTun) Events() chan TUNEvent {
return tun.events
}
-func (tun *NativeTun) doRead(buff []byte, offset int) (int, error) {
+func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
select {
case err := <-tun.errors:
return 0, err
}
}
-func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
+func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
for {
n, err := tun.doRead(buff, offset)
if err == nil || !rwcancel.ErrorIsEAGAIN(err) {
}
}
-func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
+func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
// reserve space for header
return tun.fd.Write(buff)
}
-func (tun *NativeTun) Close() error {
+func (tun *nativeTun) Close() error {
var err3 error
err1 := tun.rwcancel.Cancel()
err2 := tun.fd.Close()
return err3
}
-func (tun *NativeTun) setMTU(n int) error {
+func (tun *nativeTun) setMTU(n int) error {
// open datagram socket
var ifr [32]byte
copy(ifr[:], tun.name)
- binary.LittleEndian.PutUint32(ifr[16:20], uint32(n))
+ *(*uint32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = uint32(n)
_, _, errno := unix.Syscall(
unix.SYS_IOCTL,
uintptr(fd),
return nil
}
-func (tun *NativeTun) MTU() (int, error) {
+func (tun *nativeTun) MTU() (int, error) {
// open datagram socket
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
-package main
+package tun
import (
- "./rwcancel"
+ "../rwcancel"
"bytes"
"errors"
"fmt"
Ascii [_IFSTATMAX]byte
}
-type NativeTun struct {
+type nativeTun struct {
name string
fd *os.File
rwcancel *rwcancel.RWCancel
routeSocket int
}
-func (tun *NativeTun) RoutineRouteListener(tunIfindex int) {
+func (tun *nativeTun) routineRouteListener(tunIfindex int) {
var (
statusUp bool
statusMTU int
return nil
}
-func CreateTUN(name string) (TUNDevice, error) {
+func CreateTUN(name string, mtu int) (TUNDevice, error) {
if len(name) > unix.IFNAMSIZ-1 {
return nil, errors.New("interface name too long")
}
return nil, fmt.Errorf("failed to rename %s to %s: %s", assignedName, name, errno.Error())
}
- return CreateTUNFromFile(tunfile)
+ return CreateTUNFromFile(tunfile, mtu)
}
-func CreateTUNFromFile(file *os.File) (TUNDevice, error) {
+func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
- tun := &NativeTun{
+ tun := &nativeTun{
fd: file,
events: make(chan TUNEvent, 10),
errors: make(chan error, 1),
return nil, err
}
- go tun.RoutineRouteListener(tunIfindex)
+ go tun.routineRouteListener(tunIfindex)
- // set default MTU
- err = tun.setMTU(DefaultMTU)
+ err = tun.setMTU(mtu)
if err != nil {
tun.Close()
return nil, err
return tun, nil
}
-func (tun *NativeTun) Name() (string, error) {
+func (tun *nativeTun) Name() (string, error) {
name, err := tunName(tun.fd.Fd())
if err != nil {
return "", err
return name, nil
}
-func (tun *NativeTun) File() *os.File {
+func (tun *nativeTun) File() *os.File {
return tun.fd
}
-func (tun *NativeTun) Events() chan TUNEvent {
+func (tun *nativeTun) Events() chan TUNEvent {
return tun.events
}
-func (tun *NativeTun) doRead(buff []byte, offset int) (int, error) {
+func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
select {
case err := <-tun.errors:
return 0, err
}
}
-func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
+func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
for {
n, err := tun.doRead(buff, offset)
if err == nil || !rwcancel.ErrorIsEAGAIN(err) {
}
}
-func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
+func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
// reserve space for header
return tun.fd.Write(buff)
}
-func (tun *NativeTun) Close() error {
+func (tun *nativeTun) Close() error {
var err4 error
err1 := tun.rwcancel.Cancel()
err2 := tun.fd.Close()
return err4
}
-func (tun *NativeTun) setMTU(n int) error {
+func (tun *nativeTun) setMTU(n int) error {
// open datagram socket
var fd int
return nil
}
-func (tun *NativeTun) MTU() (int, error) {
+func (tun *nativeTun) MTU() (int, error) {
// open datagram socket
fd, err := unix.Socket(
/* Copyright 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
-package main
+package tun
/* Implementation of the TUN device interface for linux
*/
import (
- "./rwcancel"
+ "../rwcancel"
"bytes"
- "encoding/binary"
"errors"
"fmt"
"golang.org/x/net/ipv6"
ifReqSize = unix.IFNAMSIZ + 64
)
-type NativeTun struct {
+type nativeTun struct {
fd *os.File
fdCancel *rwcancel.RWCancel
index int32 // if index
statusListenersShutdown chan struct{}
}
-func (tun *NativeTun) File() *os.File {
+func (tun *nativeTun) File() *os.File {
return tun.fd
}
-func (tun *NativeTun) RoutineHackListener() {
+func (tun *nativeTun) routineHackListener() {
defer tun.hackListenerClosed.Unlock()
/* This is needed for the detection to work across network namespaces
* If you are reading this and know a better method, please get in touch.
return sock, nil
}
-func (tun *NativeTun) RoutineNetlinkListener() {
+func (tun *nativeTun) routineNetlinkListener() {
defer func() {
unix.Close(tun.netlinkSock)
tun.hackListenerClosed.Lock()
}
}
-func (tun *NativeTun) isUp() (bool, error) {
+func (tun *nativeTun) isUp() (bool, error) {
inter, err := net.InterfaceByName(tun.name)
return inter.Flags&net.FlagUp != 0, err
}
return 0, errno
}
- index := binary.LittleEndian.Uint32(ifr[unix.IFNAMSIZ:])
- return toInt32(index), nil
+ return *(*int32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])), nil
}
-func (tun *NativeTun) setMTU(n int) error {
+func (tun *nativeTun) setMTU(n int) error {
// open datagram socket
var ifr [ifReqSize]byte
copy(ifr[:], tun.name)
- binary.LittleEndian.PutUint32(ifr[16:20], uint32(n))
+ *(*uint32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = uint32(n)
_, _, errno := unix.Syscall(
unix.SYS_IOCTL,
uintptr(fd),
return nil
}
-func (tun *NativeTun) MTU() (int, error) {
+func (tun *nativeTun) MTU() (int, error) {
// open datagram socket
return 0, errors.New("failed to get MTU of TUN device: " + strconv.FormatInt(int64(errno), 10))
}
- return int(*(*int32)(unsafe.Pointer(&ifr[16]))), nil
+ return int(*(*int32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ]))), nil
}
-func (tun *NativeTun) Name() (string, error) {
+func (tun *nativeTun) Name() (string, error) {
var ifr [ifReqSize]byte
_, _, errno := unix.Syscall(
return tun.name, nil
}
-func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
+func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
if tun.nopi {
buff = buff[offset:]
return tun.fd.Write(buff)
}
-func (tun *NativeTun) doRead(buff []byte, offset int) (int, error) {
+func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
select {
case err := <-tun.errors:
return 0, err
}
}
-func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
+func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
for {
n, err := tun.doRead(buff, offset)
if err == nil || !rwcancel.ErrorIsEAGAIN(err) {
}
}
-func (tun *NativeTun) Events() chan TUNEvent {
+func (tun *nativeTun) Events() chan TUNEvent {
return tun.events
}
-func (tun *NativeTun) Close() error {
+func (tun *nativeTun) Close() error {
var err1 error
if tun.statusListenersShutdown != nil {
close(tun.statusListenersShutdown)
return err3
}
-func CreateTUN(name string) (TUNDevice, error) {
+func CreateTUN(name string, mtu int) (TUNDevice, error) {
// open clone device
return nil, errors.New("interface name too long")
}
copy(ifr[:], nameBytes)
- binary.LittleEndian.PutUint16(ifr[16:], flags)
+ *(*uint16)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = flags
_, _, errno := unix.Syscall(
unix.SYS_IOCTL,
return nil, errno
}
- return CreateTUNFromFile(fd)
+ return CreateTUNFromFile(fd, mtu)
}
-func CreateTUNFromFile(fd *os.File) (TUNDevice, error) {
- tun := &NativeTun{
- fd: fd,
+func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
+ tun := &nativeTun{
+ fd: file,
events: make(chan TUNEvent, 5),
errors: make(chan error, 5),
statusListenersShutdown: make(chan struct{}),
}
var err error
- tun.fdCancel, err = rwcancel.NewRWCancel(int(fd.Fd()))
+ tun.fdCancel, err = rwcancel.NewRWCancel(int(file.Fd()))
if err != nil {
tun.fd.Close()
return nil, err
}
tun.hackListenerClosed.Lock()
- go tun.RoutineNetlinkListener()
- go tun.RoutineHackListener() // cross namespace
+ go tun.routineNetlinkListener()
+ go tun.routineHackListener() // cross namespace
- // set default MTU
-
- err = tun.setMTU(DefaultMTU)
+ err = tun.setMTU(mtu)
if err != nil {
tun.Close()
return nil, err
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
-package main
+package tun
import (
- "./rwcancel"
+ "../rwcancel"
"errors"
"fmt"
"golang.org/x/net/ipv6"
const _TUNSIFMODE = 0x8004745d
-type NativeTun struct {
+type nativeTun struct {
name string
fd *os.File
rwcancel *rwcancel.RWCancel
routeSocket int
}
-func (tun *NativeTun) RoutineRouteListener(tunIfindex int) {
+func (tun *nativeTun) routineRouteListener(tunIfindex int) {
var (
statusUp bool
statusMTU int
return false
}
-func CreateTUN(name string) (TUNDevice, error) {
+func CreateTUN(name string, mtu int) (TUNDevice, error) {
ifIndex := -1
if name != "tun" {
_, err := fmt.Sscanf(name, "tun%d", &ifIndex)
return nil, fmt.Errorf("error %s", errno.Error())
}
- tun, err := CreateTUNFromFile(tunfile)
+ tun, err := CreateTUNFromFile(tunfile, mtu)
if err == nil && name == "tun" {
fname := os.Getenv("WG_TUN_NAME_FILE")
if fname != "" {
- ioutil.WriteFile(fname, []byte(tun.(*NativeTun).name+"\n"), 0400)
+ ioutil.WriteFile(fname, []byte(tun.(*nativeTun).name+"\n"), 0400)
}
}
return tun, err
}
-func CreateTUNFromFile(file *os.File) (TUNDevice, error) {
+func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
- tun := &NativeTun{
+ tun := &nativeTun{
fd: file,
events: make(chan TUNEvent, 10),
errors: make(chan error, 1),
return nil, err
}
- go tun.RoutineRouteListener(tunIfindex)
+ go tun.routineRouteListener(tunIfindex)
- // set default MTU
- err = tun.setMTU(DefaultMTU)
+ err = tun.setMTU(mtu)
if err != nil {
tun.Close()
return nil, err
return tun, nil
}
-func (tun *NativeTun) Name() (string, error) {
+func (tun *nativeTun) Name() (string, error) {
gostat, err := tun.fd.Stat()
if err != nil {
tun.name = ""
return tun.name, nil
}
-func (tun *NativeTun) File() *os.File {
+func (tun *nativeTun) File() *os.File {
return tun.fd
}
-func (tun *NativeTun) Events() chan TUNEvent {
+func (tun *nativeTun) Events() chan TUNEvent {
return tun.events
}
-func (tun *NativeTun) doRead(buff []byte, offset int) (int, error) {
+func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
select {
case err := <-tun.errors:
return 0, err
}
}
-func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
+func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
for {
n, err := tun.doRead(buff, offset)
if err == nil || !rwcancel.ErrorIsEAGAIN(err) {
}
}
-func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
+func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
// reserve space for header
return tun.fd.Write(buff)
}
-func (tun *NativeTun) Close() error {
+func (tun *nativeTun) Close() error {
var err3 error
err1 := tun.rwcancel.Cancel()
err2 := tun.fd.Close()
return err3
}
-func (tun *NativeTun) setMTU(n int) error {
+func (tun *nativeTun) setMTU(n int) error {
// open datagram socket
var fd int
return nil
}
-func (tun *NativeTun) MTU() (int, error) {
+func (tun *nativeTun) MTU() (int, error) {
// open datagram socket
fd, err := unix.Socket(