2017-06-04 21:48:15 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/binary"
|
|
|
|
"errors"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
"syscall"
|
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
2017-06-28 23:45:45 +02:00
|
|
|
/* Implementation of the TUN device interface for linux
|
2017-06-04 21:48:15 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
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
|
2017-07-01 23:29:22 +02:00
|
|
|
mtu int
|
2017-06-04 21:48:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (tun *NativeTun) Name() string {
|
|
|
|
return tun.name
|
|
|
|
}
|
|
|
|
|
2017-07-01 23:29:22 +02:00
|
|
|
func (tun *NativeTun) MTU() int {
|
2017-06-04 21:48:15 +02:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2017-06-28 23:45:45 +02:00
|
|
|
func CreateTUN(name string) (TUNDevice, error) {
|
2017-06-04 21:48:15 +02:00
|
|
|
// Open clone device
|
|
|
|
fd, err := os.OpenFile(CloneDevicePath, os.O_RDWR, 0)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prepare ifreq struct
|
2017-06-28 23:45:45 +02:00
|
|
|
var ifr [128]byte
|
2017-06-04 21:48:15 +02:00
|
|
|
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,
|
2017-07-07 13:47:09 +02:00
|
|
|
mtu: 0,
|
2017-06-04 21:48:15 +02:00
|
|
|
}, nil
|
|
|
|
}
|