diff options
author | Mathias Hall-Andersen <mathias@hall-andersen.dk> | 2017-06-04 21:48:15 +0200 |
---|---|---|
committer | Mathias Hall-Andersen <mathias@hall-andersen.dk> | 2017-06-04 21:48:15 +0200 |
commit | 1868d15914d6cd7cd57b90b7644b008ec16361b9 (patch) | |
tree | dbc788f49f433a5837db3c022facb19be38e4ea1 /src/tun_linux.go | |
parent | dbc3ee3e9dc50e01dab9ae789a44f90502542335 (diff) |
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.
Diffstat (limited to 'src/tun_linux.go')
-rw-r--r-- | src/tun_linux.go | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/src/tun_linux.go b/src/tun_linux.go new file mode 100644 index 0000000..d545dfa --- /dev/null +++ b/src/tun_linux.go @@ -0,0 +1,80 @@ +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 +} |