wireguard-go/src/tun_linux.go
Mathias Hall-Andersen 1868d15914 Beginning work on TUN interface
And outbound routing

I am not entirely convinced the use of net.IP is a good idea,
since the internal representation of net.IP is a byte slice
and all constructor functions in "net" return 16 byte slices
(padded for IPv4), while the use in this project uses 4 byte slices.
Which may be confusing.
2017-06-04 21:48:15 +02:00

81 lines
1.4 KiB
Go

package main
import (
"encoding/binary"
"errors"
"os"
"strings"
"syscall"
"unsafe"
)
/* Platform dependent functions for interacting with
* TUN devices on linux systems
*
*/
const CloneDevicePath = "/dev/net/tun"
const (
IFF_NO_PI = 0x1000
IFF_TUN = 0x1
IFNAMSIZ = 0x10
TUNSETIFF = 0x400454CA
)
type NativeTun struct {
fd *os.File
name string
mtu uint
}
func (tun *NativeTun) Name() string {
return tun.name
}
func (tun *NativeTun) MTU() uint {
return tun.mtu
}
func (tun *NativeTun) Write(d []byte) (int, error) {
return tun.fd.Write(d)
}
func (tun *NativeTun) Read(d []byte) (int, error) {
return tun.fd.Read(d)
}
func CreateTUN(name string) (TUN, error) {
// Open clone device
fd, err := os.OpenFile(CloneDevicePath, os.O_RDWR, 0)
if err != nil {
return nil, err
}
// Prepare ifreq struct
var ifr [18]byte
var flags uint16 = IFF_TUN | IFF_NO_PI
nameBytes := []byte(name)
if len(nameBytes) >= IFNAMSIZ {
return nil, errors.New("Name size too long")
}
copy(ifr[:], nameBytes)
binary.LittleEndian.PutUint16(ifr[16:], flags)
// Create new device
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL,
uintptr(fd.Fd()), uintptr(TUNSETIFF),
uintptr(unsafe.Pointer(&ifr[0])))
if errno != 0 {
return nil, errors.New("Failed to create tun, ioctl call failed")
}
// Read name of interface
newName := string(ifr[:])
newName = newName[:strings.Index(newName, "\000")]
return &NativeTun{
fd: fd,
name: newName,
}, nil
}