github.com/bugfan/wireguard-go@v0.0.0-20230720020150-a7b2fa340c66/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  	"log"
    10  	"runtime"
    11  	"syscall"
    12  	"unsafe"
    13  
    14  	"golang.org/x/sys/windows"
    15  )
    16  
    17  type loggerLevel int
    18  
    19  const (
    20  	logInfo loggerLevel = iota
    21  	logWarn
    22  	logErr
    23  )
    24  
    25  const AdapterNameMax = 128
    26  
    27  type Adapter struct {
    28  	handle uintptr
    29  }
    30  
    31  var (
    32  	modwintun                         = newLazyDLL("wintun.dll", setupLogger)
    33  	procWintunCreateAdapter           = modwintun.NewProc("WintunCreateAdapter")
    34  	procWintunOpenAdapter             = modwintun.NewProc("WintunOpenAdapter")
    35  	procWintunCloseAdapter            = modwintun.NewProc("WintunCloseAdapter")
    36  	procWintunDeleteDriver            = modwintun.NewProc("WintunDeleteDriver")
    37  	procWintunGetAdapterLUID          = modwintun.NewProc("WintunGetAdapterLUID")
    38  	procWintunGetRunningDriverVersion = modwintun.NewProc("WintunGetRunningDriverVersion")
    39  )
    40  
    41  type TimestampedWriter interface {
    42  	WriteWithTimestamp(p []byte, ts int64) (n int, err error)
    43  }
    44  
    45  func logMessage(level loggerLevel, timestamp uint64, msg *uint16) int {
    46  	if tw, ok := log.Default().Writer().(TimestampedWriter); ok {
    47  		tw.WriteWithTimestamp([]byte(log.Default().Prefix()+windows.UTF16PtrToString(msg)), (int64(timestamp)-116444736000000000)*100)
    48  	} else {
    49  		log.Println(windows.UTF16PtrToString(msg))
    50  	}
    51  	return 0
    52  }
    53  
    54  func setupLogger(dll *lazyDLL) {
    55  	var callback uintptr
    56  	if runtime.GOARCH == "386" || runtime.GOARCH == "arm" {
    57  		callback = windows.NewCallback(func(level loggerLevel, timestampLow, timestampHigh uint32, msg *uint16) int {
    58  			return logMessage(level, uint64(timestampHigh)<<32|uint64(timestampLow), msg)
    59  		})
    60  	} else if runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64" {
    61  		callback = windows.NewCallback(logMessage)
    62  	}
    63  	syscall.Syscall(dll.NewProc("WintunSetLogger").Addr(), 1, callback, 0, 0)
    64  }
    65  
    66  func closeAdapter(wintun *Adapter) {
    67  	syscall.Syscall(procWintunCloseAdapter.Addr(), 1, wintun.handle, 0, 0)
    68  }
    69  
    70  // CreateAdapter creates a Wintun adapter. name is the cosmetic name of the adapter.
    71  // tunnelType represents the type of adapter and should be "Wintun". requestedGUID is
    72  // the GUID of the created network adapter, which then influences NLA generation
    73  // deterministically. If it is set to nil, the GUID is chosen by the system at random,
    74  // and hence a new NLA entry is created for each new adapter.
    75  func CreateAdapter(name string, tunnelType string, requestedGUID *windows.GUID) (wintun *Adapter, err error) {
    76  	var name16 *uint16
    77  	name16, err = windows.UTF16PtrFromString(name)
    78  	if err != nil {
    79  		return
    80  	}
    81  	var tunnelType16 *uint16
    82  	tunnelType16, err = windows.UTF16PtrFromString(tunnelType)
    83  	if err != nil {
    84  		return
    85  	}
    86  	r0, _, e1 := syscall.Syscall(procWintunCreateAdapter.Addr(), 3, uintptr(unsafe.Pointer(name16)), uintptr(unsafe.Pointer(tunnelType16)), uintptr(unsafe.Pointer(requestedGUID)))
    87  	if r0 == 0 {
    88  		err = e1
    89  		return
    90  	}
    91  	wintun = &Adapter{handle: r0}
    92  	runtime.SetFinalizer(wintun, closeAdapter)
    93  	return
    94  }
    95  
    96  // OpenAdapter opens an existing Wintun adapter by name.
    97  func OpenAdapter(name string) (wintun *Adapter, err error) {
    98  	var name16 *uint16
    99  	name16, err = windows.UTF16PtrFromString(name)
   100  	if err != nil {
   101  		return
   102  	}
   103  	r0, _, e1 := syscall.Syscall(procWintunOpenAdapter.Addr(), 1, uintptr(unsafe.Pointer(name16)), 0, 0)
   104  	if r0 == 0 {
   105  		err = e1
   106  		return
   107  	}
   108  	wintun = &Adapter{handle: r0}
   109  	runtime.SetFinalizer(wintun, closeAdapter)
   110  	return
   111  }
   112  
   113  // Close closes a Wintun adapter.
   114  func (wintun *Adapter) Close() (err error) {
   115  	runtime.SetFinalizer(wintun, nil)
   116  	r1, _, e1 := syscall.Syscall(procWintunCloseAdapter.Addr(), 1, wintun.handle, 0, 0)
   117  	if r1 == 0 {
   118  		err = e1
   119  	}
   120  	return
   121  }
   122  
   123  // Uninstall removes the driver from the system if no drivers are currently in use.
   124  func Uninstall() (err error) {
   125  	r1, _, e1 := syscall.Syscall(procWintunDeleteDriver.Addr(), 0, 0, 0, 0)
   126  	if r1 == 0 {
   127  		err = e1
   128  	}
   129  	return
   130  }
   131  
   132  // RunningVersion returns the version of the running Wintun driver.
   133  func RunningVersion() (version uint32, err error) {
   134  	r0, _, e1 := syscall.Syscall(procWintunGetRunningDriverVersion.Addr(), 0, 0, 0, 0)
   135  	version = uint32(r0)
   136  	if version == 0 {
   137  		err = e1
   138  	}
   139  	return
   140  }
   141  
   142  // LUID returns the LUID of the adapter.
   143  func (wintun *Adapter) LUID() (luid uint64) {
   144  	syscall.Syscall(procWintunGetAdapterLUID.Addr(), 2, uintptr(wintun.handle), uintptr(unsafe.Pointer(&luid)), 0)
   145  	return
   146  }