github.com/tailscale/wireguard-go@v0.0.20201119-0.20210522003738-46b531feb08a/tun/wintun/wintun_windows.go (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  package wintun
     7  
     8  import (
     9  	"errors"
    10  	"log"
    11  	"runtime"
    12  	"syscall"
    13  	"unsafe"
    14  
    15  	"golang.org/x/sys/windows"
    16  )
    17  
    18  type loggerLevel int
    19  
    20  const (
    21  	logInfo loggerLevel = iota
    22  	logWarn
    23  	logErr
    24  )
    25  
    26  const (
    27  	PoolNameMax    = 256
    28  	AdapterNameMax = 128
    29  )
    30  
    31  type Pool [PoolNameMax]uint16
    32  type Adapter struct {
    33  	handle uintptr
    34  }
    35  
    36  var (
    37  	modwintun = newLazyDLL("wintun.dll", setupLogger)
    38  
    39  	procWintunCreateAdapter           = modwintun.NewProc("WintunCreateAdapter")
    40  	procWintunDeleteAdapter           = modwintun.NewProc("WintunDeleteAdapter")
    41  	procWintunDeletePoolDriver        = modwintun.NewProc("WintunDeletePoolDriver")
    42  	procWintunEnumAdapters            = modwintun.NewProc("WintunEnumAdapters")
    43  	procWintunFreeAdapter             = modwintun.NewProc("WintunFreeAdapter")
    44  	procWintunOpenAdapter             = modwintun.NewProc("WintunOpenAdapter")
    45  	procWintunGetAdapterLUID          = modwintun.NewProc("WintunGetAdapterLUID")
    46  	procWintunGetAdapterName          = modwintun.NewProc("WintunGetAdapterName")
    47  	procWintunGetRunningDriverVersion = modwintun.NewProc("WintunGetRunningDriverVersion")
    48  	procWintunSetAdapterName          = modwintun.NewProc("WintunSetAdapterName")
    49  )
    50  
    51  func setupLogger(dll *lazyDLL) {
    52  	syscall.Syscall(dll.NewProc("WintunSetLogger").Addr(), 1, windows.NewCallback(func(level loggerLevel, msg *uint16) int {
    53  		log.Println("[Wintun]", windows.UTF16PtrToString(msg))
    54  		return 0
    55  	}), 0, 0)
    56  }
    57  
    58  func MakePool(poolName string) (pool *Pool, err error) {
    59  	poolName16, err := windows.UTF16FromString(poolName)
    60  	if err != nil {
    61  		return
    62  	}
    63  	if len(poolName16) > PoolNameMax {
    64  		err = errors.New("Pool name too long")
    65  		return
    66  	}
    67  	pool = &Pool{}
    68  	copy(pool[:], poolName16)
    69  	return
    70  }
    71  
    72  func (pool *Pool) String() string {
    73  	return windows.UTF16ToString(pool[:])
    74  }
    75  
    76  func freeAdapter(wintun *Adapter) {
    77  	syscall.Syscall(procWintunFreeAdapter.Addr(), 1, uintptr(wintun.handle), 0, 0)
    78  }
    79  
    80  // OpenAdapter finds a Wintun adapter by its name. This function returns the adapter if found, or
    81  // windows.ERROR_FILE_NOT_FOUND otherwise. If the adapter is found but not a Wintun-class or a
    82  // member of the pool, this function returns windows.ERROR_ALREADY_EXISTS. The adapter must be
    83  // released after use.
    84  func (pool *Pool) OpenAdapter(ifname string) (wintun *Adapter, err error) {
    85  	ifname16, err := windows.UTF16PtrFromString(ifname)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  	r0, _, e1 := syscall.Syscall(procWintunOpenAdapter.Addr(), 2, uintptr(unsafe.Pointer(pool)), uintptr(unsafe.Pointer(ifname16)), 0)
    90  	if r0 == 0 {
    91  		err = e1
    92  		return
    93  	}
    94  	wintun = &Adapter{r0}
    95  	runtime.SetFinalizer(wintun, freeAdapter)
    96  	return
    97  }
    98  
    99  // CreateAdapter creates a Wintun adapter. ifname is the requested name of the adapter, while
   100  // requestedGUID is the GUID of the created network adapter, which then influences NLA generation
   101  // deterministically. If it is set to nil, the GUID is chosen by the system at random, and hence a
   102  // new NLA entry is created for each new adapter. It is called "requested" GUID because the API it
   103  // uses is completely undocumented, and so there could be minor interesting complications with its
   104  // usage. This function returns the network adapter ID and a flag if reboot is required.
   105  func (pool *Pool) CreateAdapter(ifname string, requestedGUID *windows.GUID) (wintun *Adapter, rebootRequired bool, err error) {
   106  	var ifname16 *uint16
   107  	ifname16, err = windows.UTF16PtrFromString(ifname)
   108  	if err != nil {
   109  		return
   110  	}
   111  	var _p0 uint32
   112  	r0, _, e1 := syscall.Syscall6(procWintunCreateAdapter.Addr(), 4, uintptr(unsafe.Pointer(pool)), uintptr(unsafe.Pointer(ifname16)), uintptr(unsafe.Pointer(requestedGUID)), uintptr(unsafe.Pointer(&_p0)), 0, 0)
   113  	rebootRequired = _p0 != 0
   114  	if r0 == 0 {
   115  		err = e1
   116  		return
   117  	}
   118  	wintun = &Adapter{r0}
   119  	runtime.SetFinalizer(wintun, freeAdapter)
   120  	return
   121  }
   122  
   123  // Delete deletes a Wintun adapter. This function succeeds if the adapter was not found. It returns
   124  // a bool indicating whether a reboot is required.
   125  func (wintun *Adapter) Delete(forceCloseSessions bool) (rebootRequired bool, err error) {
   126  	var _p0 uint32
   127  	if forceCloseSessions {
   128  		_p0 = 1
   129  	}
   130  	var _p1 uint32
   131  	r1, _, e1 := syscall.Syscall(procWintunDeleteAdapter.Addr(), 3, uintptr(wintun.handle), uintptr(_p0), uintptr(unsafe.Pointer(&_p1)))
   132  	rebootRequired = _p1 != 0
   133  	if r1 == 0 {
   134  		err = e1
   135  	}
   136  	return
   137  }
   138  
   139  // DeleteMatchingAdapters deletes all Wintun adapters, which match
   140  // given criteria, and returns which ones it deleted, whether a reboot
   141  // is required after, and which errors occurred during the process.
   142  func (pool *Pool) DeleteMatchingAdapters(matches func(adapter *Adapter) bool, forceCloseSessions bool) (rebootRequired bool, errors []error) {
   143  	cb := func(handle uintptr, _ uintptr) int {
   144  		adapter := &Adapter{handle}
   145  		if !matches(adapter) {
   146  			return 1
   147  		}
   148  		rebootRequired2, err := adapter.Delete(forceCloseSessions)
   149  		if err != nil {
   150  			errors = append(errors, err)
   151  			return 1
   152  		}
   153  		rebootRequired = rebootRequired || rebootRequired2
   154  		return 1
   155  	}
   156  	r1, _, e1 := syscall.Syscall(procWintunEnumAdapters.Addr(), 3, uintptr(unsafe.Pointer(pool)), uintptr(windows.NewCallback(cb)), 0)
   157  	if r1 == 0 {
   158  		errors = append(errors, e1)
   159  	}
   160  	return
   161  }
   162  
   163  // Name returns the name of the Wintun adapter.
   164  func (wintun *Adapter) Name() (ifname string, err error) {
   165  	var ifname16 [AdapterNameMax]uint16
   166  	r1, _, e1 := syscall.Syscall(procWintunGetAdapterName.Addr(), 2, uintptr(wintun.handle), uintptr(unsafe.Pointer(&ifname16[0])), 0)
   167  	if r1 == 0 {
   168  		err = e1
   169  		return
   170  	}
   171  	ifname = windows.UTF16ToString(ifname16[:])
   172  	return
   173  }
   174  
   175  // DeleteDriver deletes all Wintun adapters in a pool and if there are no more adapters in any other
   176  // pools, also removes Wintun from the driver store, usually called by uninstallers.
   177  func (pool *Pool) DeleteDriver() (rebootRequired bool, err error) {
   178  	var _p0 uint32
   179  	r1, _, e1 := syscall.Syscall(procWintunDeletePoolDriver.Addr(), 2, uintptr(unsafe.Pointer(pool)), uintptr(unsafe.Pointer(&_p0)), 0)
   180  	rebootRequired = _p0 != 0
   181  	if r1 == 0 {
   182  		err = e1
   183  	}
   184  	return
   185  
   186  }
   187  
   188  // SetName sets name of the Wintun adapter.
   189  func (wintun *Adapter) SetName(ifname string) (err error) {
   190  	ifname16, err := windows.UTF16FromString(ifname)
   191  	if err != nil {
   192  		return err
   193  	}
   194  	r1, _, e1 := syscall.Syscall(procWintunSetAdapterName.Addr(), 2, uintptr(wintun.handle), uintptr(unsafe.Pointer(&ifname16[0])), 0)
   195  	if r1 == 0 {
   196  		err = e1
   197  	}
   198  	return
   199  }
   200  
   201  // RunningVersion returns the version of the running Wintun driver.
   202  func RunningVersion() (version uint32, err error) {
   203  	r0, _, e1 := syscall.Syscall(procWintunGetRunningDriverVersion.Addr(), 0, 0, 0, 0)
   204  	version = uint32(r0)
   205  	if version == 0 {
   206  		err = e1
   207  	}
   208  	return
   209  }
   210  
   211  // LUID returns the LUID of the adapter.
   212  func (wintun *Adapter) LUID() (luid uint64) {
   213  	syscall.Syscall(procWintunGetAdapterLUID.Addr(), 2, uintptr(wintun.handle), uintptr(unsafe.Pointer(&luid)), 0)
   214  	return
   215  }