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 }