summaryrefslogtreecommitdiffhomepage
path: root/src/tun_linux.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/tun_linux.go')
-rw-r--r--src/tun_linux.go80
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
+}