summaryrefslogtreecommitdiffhomepage
path: root/src/tun_windows.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/tun_windows.go')
-rw-r--r--src/tun_windows.go475
1 files changed, 0 insertions, 475 deletions
diff --git a/src/tun_windows.go b/src/tun_windows.go
deleted file mode 100644
index 0711032..0000000
--- a/src/tun_windows.go
+++ /dev/null
@@ -1,475 +0,0 @@
-package main
-
-import (
- "encoding/binary"
- "errors"
- "fmt"
- "golang.org/x/sys/windows"
- "golang.org/x/sys/windows/registry"
- "net"
- "sync"
- "syscall"
- "time"
- "unsafe"
-)
-
-/* Relies on the OpenVPN TAP-Windows driver (NDIS 6 version)
- *
- * https://github.com/OpenVPN/tap-windows
- */
-
-type NativeTUN struct {
- fd windows.Handle
- rl sync.Mutex
- wl sync.Mutex
- ro *windows.Overlapped
- wo *windows.Overlapped
- events chan TUNEvent
- name string
-}
-
-const (
- METHOD_BUFFERED = 0
- ComponentID = "tap0901" // tap0801
-)
-
-func ctl_code(device_type, function, method, access uint32) uint32 {
- return (device_type << 16) | (access << 14) | (function << 2) | method
-}
-
-func TAP_CONTROL_CODE(request, method uint32) uint32 {
- return ctl_code(file_device_unknown, request, method, 0)
-}
-
-var (
- errIfceNameNotFound = errors.New("Failed to find the name of interface")
-
- TAP_IOCTL_GET_MAC = TAP_CONTROL_CODE(1, METHOD_BUFFERED)
- TAP_IOCTL_GET_VERSION = TAP_CONTROL_CODE(2, METHOD_BUFFERED)
- TAP_IOCTL_GET_MTU = TAP_CONTROL_CODE(3, METHOD_BUFFERED)
- TAP_IOCTL_GET_INFO = TAP_CONTROL_CODE(4, METHOD_BUFFERED)
- TAP_IOCTL_CONFIG_POINT_TO_POINT = TAP_CONTROL_CODE(5, METHOD_BUFFERED)
- TAP_IOCTL_SET_MEDIA_STATUS = TAP_CONTROL_CODE(6, METHOD_BUFFERED)
- TAP_IOCTL_CONFIG_DHCP_MASQ = TAP_CONTROL_CODE(7, METHOD_BUFFERED)
- TAP_IOCTL_GET_LOG_LINE = TAP_CONTROL_CODE(8, METHOD_BUFFERED)
- TAP_IOCTL_CONFIG_DHCP_SET_OPT = TAP_CONTROL_CODE(9, METHOD_BUFFERED)
- TAP_IOCTL_CONFIG_TUN = TAP_CONTROL_CODE(10, METHOD_BUFFERED)
-
- file_device_unknown = uint32(0x00000022)
- nCreateEvent,
- nResetEvent,
- nGetOverlappedResult uintptr
-)
-
-func init() {
- k32, err := windows.LoadLibrary("kernel32.dll")
- if err != nil {
- panic("LoadLibrary " + err.Error())
- }
- defer windows.FreeLibrary(k32)
- nCreateEvent = getProcAddr(k32, "CreateEventW")
- nResetEvent = getProcAddr(k32, "ResetEvent")
- nGetOverlappedResult = getProcAddr(k32, "GetOverlappedResult")
-}
-
-/* implementation of the read/write/closer interface */
-
-func getProcAddr(lib windows.Handle, name string) uintptr {
- addr, err := windows.GetProcAddress(lib, name)
- if err != nil {
- panic(name + " " + err.Error())
- }
- return addr
-}
-
-func resetEvent(h windows.Handle) error {
- r, _, err := syscall.Syscall(nResetEvent, 1, uintptr(h), 0, 0)
- if r == 0 {
- return err
- }
- return nil
-}
-
-func getOverlappedResult(h windows.Handle, overlapped *windows.Overlapped) (int, error) {
- var n int
- r, _, err := syscall.Syscall6(
- nGetOverlappedResult,
- 4,
- uintptr(h),
- uintptr(unsafe.Pointer(overlapped)),
- uintptr(unsafe.Pointer(&n)), 1, 0, 0)
-
- if r == 0 {
- return n, err
- }
- return n, nil
-}
-
-func newOverlapped() (*windows.Overlapped, error) {
- var overlapped windows.Overlapped
- r, _, err := syscall.Syscall6(nCreateEvent, 4, 0, 1, 0, 0, 0, 0)
- if r == 0 {
- return nil, err
- }
- overlapped.HEvent = windows.Handle(r)
- return &overlapped, nil
-}
-
-func (f *NativeTUN) Events() chan TUNEvent {
- return f.events
-}
-
-func (f *NativeTUN) Close() error {
- return windows.Close(f.fd)
-}
-
-func (f *NativeTUN) Write(b []byte) (int, error) {
- f.wl.Lock()
- defer f.wl.Unlock()
-
- if err := resetEvent(f.wo.HEvent); err != nil {
- return 0, err
- }
- var n uint32
- err := windows.WriteFile(f.fd, b, &n, f.wo)
- if err != nil && err != windows.ERROR_IO_PENDING {
- return int(n), err
- }
- return getOverlappedResult(f.fd, f.wo)
-}
-
-func (f *NativeTUN) Read(b []byte) (int, error) {
- f.rl.Lock()
- defer f.rl.Unlock()
-
- if err := resetEvent(f.ro.HEvent); err != nil {
- return 0, err
- }
- var done uint32
- err := windows.ReadFile(f.fd, b, &done, f.ro)
- if err != nil && err != windows.ERROR_IO_PENDING {
- return int(done), err
- }
- return getOverlappedResult(f.fd, f.ro)
-}
-
-func getdeviceid(
- targetComponentId string,
- targetDeviceName string,
-) (deviceid string, err error) {
-
- getName := func(instanceId string) (string, error) {
- path := fmt.Sprintf(
- `SYSTEM\CurrentControlSet\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}\%s\Connection`,
- instanceId,
- )
-
- key, err := registry.OpenKey(
- registry.LOCAL_MACHINE,
- path,
- registry.READ,
- )
-
- if err != nil {
- return "", err
- }
- defer key.Close()
-
- val, _, err := key.GetStringValue("Name")
- key.Close()
- return val, err
- }
-
- getInstanceId := func(keyName string) (string, string, error) {
- path := fmt.Sprintf(
- `SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\%s`,
- keyName,
- )
-
- key, err := registry.OpenKey(
- registry.LOCAL_MACHINE,
- path,
- registry.READ,
- )
-
- if err != nil {
- return "", "", err
- }
- defer key.Close()
-
- componentId, _, err := key.GetStringValue("ComponentId")
- if err != nil {
- return "", "", err
- }
-
- instanceId, _, err := key.GetStringValue("NetCfgInstanceId")
-
- return componentId, instanceId, err
- }
-
- // find list of all network devices
-
- k, err := registry.OpenKey(
- registry.LOCAL_MACHINE,
- `SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}`,
- registry.READ,
- )
-
- if err != nil {
- return "", fmt.Errorf("Failed to open the adapter registry, TAP driver may be not installed, %v", err)
- }
-
- defer k.Close()
-
- keys, err := k.ReadSubKeyNames(-1)
-
- if err != nil {
- return "", err
- }
-
- // look for matching component id and name
-
- var componentFound bool
-
- for _, v := range keys {
-
- componentId, instanceId, err := getInstanceId(v)
- if err != nil || componentId != targetComponentId {
- continue
- }
-
- componentFound = true
-
- deviceName, err := getName(instanceId)
- if err != nil || deviceName != targetDeviceName {
- continue
- }
-
- return instanceId, nil
- }
-
- // provide a descriptive error message
-
- if componentFound {
- return "", fmt.Errorf("Unable to find tun/tap device with name = %s", targetDeviceName)
- }
-
- return "", fmt.Errorf(
- "Unable to find device in registry with ComponentId = %s, is tap-windows installed?",
- targetComponentId,
- )
-}
-
-// setStatus is used to bring up or bring down the interface
-func setStatus(fd windows.Handle, status bool) error {
- var code [4]byte
- if status {
- binary.LittleEndian.PutUint32(code[:], 1)
- }
-
- var bytesReturned uint32
- rdbbuf := make([]byte, windows.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
- return windows.DeviceIoControl(
- fd,
- TAP_IOCTL_SET_MEDIA_STATUS,
- &code[0],
- uint32(4),
- &rdbbuf[0],
- uint32(len(rdbbuf)),
- &bytesReturned,
- nil,
- )
-}
-
-/* When operating in TUN mode we must assign an ip address & subnet to the device.
- *
- */
-func setTUN(fd windows.Handle, network string) error {
- var bytesReturned uint32
- rdbbuf := make([]byte, windows.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
- localIP, remoteNet, err := net.ParseCIDR(network)
-
- if err != nil {
- return fmt.Errorf("Failed to parse network CIDR in config, %v", err)
- }
-
- if localIP.To4() == nil {
- return fmt.Errorf("Provided network(%s) is not a valid IPv4 address", network)
- }
-
- var param [12]byte
-
- copy(param[0:4], localIP.To4())
- copy(param[4:8], remoteNet.IP.To4())
- copy(param[8:12], remoteNet.Mask)
-
- return windows.DeviceIoControl(
- fd,
- TAP_IOCTL_CONFIG_TUN,
- &param[0],
- uint32(12),
- &rdbbuf[0],
- uint32(len(rdbbuf)),
- &bytesReturned,
- nil,
- )
-}
-
-func (tun *NativeTUN) MTU() (int, error) {
- var mtu [4]byte
- var bytesReturned uint32
- err := windows.DeviceIoControl(
- tun.fd,
- TAP_IOCTL_GET_MTU,
- &mtu[0],
- uint32(len(mtu)),
- &mtu[0],
- uint32(len(mtu)),
- &bytesReturned,
- nil,
- )
- val := binary.LittleEndian.Uint32(mtu[:])
- return int(val), err
-}
-
-func (tun *NativeTUN) Name() string {
- return tun.name
-}
-
-func CreateTUN(name string) (TUNDevice, error) {
-
- // find the device in registry.
-
- deviceid, err := getdeviceid(ComponentID, name)
- if err != nil {
- return nil, err
- }
- path := "\\\\.\\Global\\" + deviceid + ".tap"
- pathp, err := windows.UTF16PtrFromString(path)
- if err != nil {
- return nil, err
- }
-
- // create TUN device
-
- handle, err := windows.CreateFile(
- pathp,
- windows.GENERIC_READ|windows.GENERIC_WRITE,
- 0,
- nil,
- windows.OPEN_EXISTING,
- windows.FILE_ATTRIBUTE_SYSTEM|windows.FILE_FLAG_OVERLAPPED,
- 0,
- )
-
- if err != nil {
- return nil, err
- }
-
- ro, err := newOverlapped()
- if err != nil {
- windows.Close(handle)
- return nil, err
- }
-
- wo, err := newOverlapped()
- if err != nil {
- windows.Close(handle)
- return nil, err
- }
-
- tun := &NativeTUN{
- fd: handle,
- name: name,
- ro: ro,
- wo: wo,
- events: make(chan TUNEvent, 5),
- }
-
- // find addresses of interface
- // TODO: fix this hack, the question is how
-
- inter, err := net.InterfaceByName(name)
- if err != nil {
- windows.Close(handle)
- return nil, err
- }
-
- addrs, err := inter.Addrs()
- if err != nil {
- windows.Close(handle)
- return nil, err
- }
-
- var ip net.IP
- for _, addr := range addrs {
- ip = func() net.IP {
- switch v := addr.(type) {
- case *net.IPNet:
- return v.IP.To4()
- case *net.IPAddr:
- return v.IP.To4()
- }
- return nil
- }()
- if ip != nil {
- break
- }
- }
-
- if ip == nil {
- windows.Close(handle)
- return nil, errors.New("No IPv4 address found for interface")
- }
-
- // bring up device.
-
- if err := setStatus(handle, true); err != nil {
- windows.Close(handle)
- return nil, err
- }
-
- // set tun mode
-
- mask := ip.String() + "/0"
- if err := setTUN(handle, mask); err != nil {
- windows.Close(handle)
- return nil, err
- }
-
- // start listener
-
- go func(native *NativeTUN, ifname string) {
- // TODO: Fix this very niave implementation
- var (
- statusUp bool
- statusMTU int
- )
-
- for ; ; time.Sleep(time.Second) {
- intr, err := net.InterfaceByName(name)
- if err != nil {
- // TODO: handle
- return
- }
-
- // Up / Down event
- up := (intr.Flags & net.FlagUp) != 0
- if up != statusUp && up {
- native.events <- TUNEventUp
- }
- if up != statusUp && !up {
- native.events <- TUNEventDown
- }
- statusUp = up
-
- // MTU changes
- if intr.MTU != statusMTU {
- native.events <- TUNEventMTUUpdate
- }
- statusMTU = intr.MTU
- }
- }(tun, name)
-
- return tun, nil
-}