mirror of
https://github.com/amnezia-vpn/amneziawg-windows-client.git
synced 2026-05-17 00:05:45 +03:00
Import code from RomikB/amneziawg-client-windows (#2)
AmneziaWG for Windows client
This commit is contained in:
30
Makefile
30
Makefile
@@ -10,12 +10,12 @@ RCFLAGS := -DWIREGUARD_VERSION_ARRAY=$(subst $(space),$(comma),$(wordlist 1,4,$(
|
||||
|
||||
rwildcard=$(foreach d,$(filter-out .deps,$(wildcard $1*)),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
|
||||
SOURCE_FILES := $(call rwildcard,,*.go) .deps/go/prepared go.mod go.sum
|
||||
RESOURCE_FILES := resources.rc version/version.go manifest.xml $(patsubst %.svg,%.ico,$(wildcard ui/icon/*.svg)) .deps/wireguard-nt/prepared
|
||||
RESOURCE_FILES := resources.rc version/version.go manifest.xml $(patsubst %.svg,%.ico,$(wildcard ui/icon/*.svg)) .deps/wintun/prepared
|
||||
|
||||
DEPLOYMENT_HOST ?= winvm
|
||||
DEPLOYMENT_PATH ?= Desktop
|
||||
|
||||
all: amd64/wireguard.exe x86/wireguard.exe arm64/wireguard.exe
|
||||
all: amd64/wireguard.exe x86/wireguard.exe
|
||||
|
||||
define download =
|
||||
.distfiles/$(1):
|
||||
@@ -25,8 +25,8 @@ define download =
|
||||
if ! mv $$@.unverified $$@; then rm -f $$@.unverified; exit 1; fi
|
||||
endef
|
||||
|
||||
$(eval $(call download,go.tar.gz,https://go.dev/dl/go1.18.linux-amd64.tar.gz,e85278e98f57cdb150fe8409e6e5df5343ecb13cebf03a5d5ff12bd55a80264f))
|
||||
$(eval $(call download,wireguard-nt.zip,https://download.wireguard.com/wireguard-nt/wireguard-nt-0.10.1.zip,772c0b1463d8d2212716f43f06f4594d880dea4f735165bd68e388fc41b81605))
|
||||
$(eval $(call download,go.tar.gz,https://go.dev/dl/go1.22.0.linux-amd64.tar.gz,f6c8a87aa03b92c4b0bf3d558e28ea03006eb29db78917daec5cfb6ec1046265))
|
||||
$(eval $(call download,wintun.zip,https://www.wintun.net/builds/wintun-0.14.1.zip,07c256185d6ee3652e09fa55c0b673e2624b565e02c4b9091c79ca7d2f24ef51))
|
||||
|
||||
.deps/go/prepared: .distfiles/go.tar.gz
|
||||
mkdir -p .deps
|
||||
@@ -35,36 +35,42 @@ $(eval $(call download,wireguard-nt.zip,https://download.wireguard.com/wireguard
|
||||
chmod -R +w .deps/go
|
||||
touch $@
|
||||
|
||||
.deps/wireguard-nt/prepared: .distfiles/wireguard-nt.zip
|
||||
.deps/wintun/prepared: .distfiles/wintun.zip
|
||||
mkdir -p .deps
|
||||
rm -rf .deps/wireguard-nt
|
||||
bsdtar -C .deps -xf .distfiles/wireguard-nt.zip
|
||||
rm -rf .deps/wintun
|
||||
bsdtar -C .deps -xf .distfiles/wintun.zip
|
||||
touch $@
|
||||
|
||||
%.ico: %.svg
|
||||
convert -background none $< -define icon:auto-resize="256,192,128,96,64,48,40,32,24,20,16" -compress zip $@
|
||||
|
||||
resources_amd64.syso: $(RESOURCE_FILES)
|
||||
x86_64-w64-mingw32-windres $(RCFLAGS) -I .deps/wireguard-nt/bin/amd64 -i $< -o $@
|
||||
x86_64-w64-mingw32-windres $(RCFLAGS) -i $< -o $@
|
||||
|
||||
resources_386.syso: $(RESOURCE_FILES)
|
||||
i686-w64-mingw32-windres $(RCFLAGS) -I .deps/wireguard-nt/bin/x86 -i $< -o $@
|
||||
i686-w64-mingw32-windres $(RCFLAGS) -i $< -o $@
|
||||
|
||||
resources_arm64.syso: $(RESOURCE_FILES)
|
||||
aarch64-w64-mingw32-windres $(RCFLAGS) -I .deps/wireguard-nt/bin/arm64 -i $< -o $@
|
||||
aarch64-w64-mingw32-windres $(RCFLAGS) -i $< -o $@
|
||||
|
||||
amd64/wireguard.exe: export GOARCH := amd64
|
||||
amd64/wireguard.exe: resources_amd64.syso $(SOURCE_FILES)
|
||||
amd64/wireguard.exe: amd64/wintun.dll resources_amd64.syso $(SOURCE_FILES)
|
||||
go build $(GOFLAGS) -o $@
|
||||
|
||||
x86/wireguard.exe: export GOARCH := 386
|
||||
x86/wireguard.exe: resources_386.syso $(SOURCE_FILES)
|
||||
x86/wireguard.exe: x86/wintun.dll resources_386.syso $(SOURCE_FILES)
|
||||
go build $(GOFLAGS) -o $@
|
||||
|
||||
arm64/wireguard.exe: export GOARCH := arm64
|
||||
arm64/wireguard.exe: resources_arm64.syso $(SOURCE_FILES)
|
||||
go build $(GOFLAGS) -o $@
|
||||
|
||||
amd64/wintun.dll:
|
||||
cp .deps/wintun/bin/amd64/wintun.dll $@
|
||||
|
||||
x86/wintun.dll:
|
||||
cp .deps/wintun/bin/x86/wintun.dll $@
|
||||
|
||||
remaster: export GOARCH := amd64
|
||||
remaster: export GOPROXY := direct
|
||||
remaster: .deps/go/prepared
|
||||
|
||||
14
build.bat
14
build.bat
@@ -4,7 +4,7 @@ rem Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
set BUILDDIR=%~dp0
|
||||
set PATH=%BUILDDIR%.deps\llvm-mingw\bin;%BUILDDIR%.deps\go\bin;%BUILDDIR%.deps;%PATH%
|
||||
set PATH=%BUILDDIR%.deps\llvm-mingw-20231128-ucrt-x86_64\bin;%BUILDDIR%.deps\go\bin;%BUILDDIR%.deps;%PATH%
|
||||
set PATHEXT=.exe
|
||||
cd /d %BUILDDIR% || exit /b 1
|
||||
|
||||
@@ -13,15 +13,14 @@ if exist .deps\prepared goto :render
|
||||
rmdir /s /q .deps 2> NUL
|
||||
mkdir .deps || goto :error
|
||||
cd .deps || goto :error
|
||||
call :download go.zip https://go.dev/dl/go1.18.windows-amd64.zip 65c5c0c709a7ca1b357091b10b795b439d8b50e579d3893edab4c7e9b384f435 || goto :error
|
||||
rem Mirror of https://github.com/mstorsjo/llvm-mingw/releases/download/20201020/llvm-mingw-20201020-msvcrt-x86_64.zip
|
||||
call :download llvm-mingw-msvcrt.zip https://download.wireguard.com/windows-toolchain/distfiles/llvm-mingw-20201020-msvcrt-x86_64.zip 2e46593245090df96d15e360e092f0b62b97e93866e0162dca7f93b16722b844 || goto :error
|
||||
call :download go.zip https://go.dev/dl/go1.22.0.windows-amd64.zip 78b3158fe3aa358e0b6c9f26ecd338f9a11441e88bc434ae2e9f0ca2b0cc4dd3 || goto :error
|
||||
call :download llvm-mingw-20231128-ucrt-x86_64.zip https://github.com/mstorsjo/llvm-mingw/releases/download/20231128/llvm-mingw-20231128-ucrt-x86_64.zip 7a344dafa6942de2c1f4643b3eb5c5ce5317fbab671a887e4d39f326b331798f || goto :error
|
||||
rem Mirror of https://imagemagick.org/download/binaries/ImageMagick-7.0.8-42-portable-Q16-x64.zip
|
||||
call :download imagemagick.zip https://download.wireguard.com/windows-toolchain/distfiles/ImageMagick-7.0.8-42-portable-Q16-x64.zip 584e069f56456ce7dde40220948ff9568ac810688c892c5dfb7f6db902aa05aa "convert.exe colors.xml delegates.xml" || goto :error
|
||||
rem Mirror of https://sourceforge.net/projects/ezwinports/files/make-4.2.1-without-guile-w32-bin.zip
|
||||
call :download make.zip https://download.wireguard.com/windows-toolchain/distfiles/make-4.2.1-without-guile-w32-bin.zip 30641be9602712be76212b99df7209f4f8f518ba764cf564262bc9d6e4047cc7 "--strip-components 1 bin" || goto :error
|
||||
call :download wireguard-tools.zip https://git.zx2c4.com/wireguard-tools/snapshot/wireguard-tools-1ee37b8e4833a25efe6f1fc0d5bdcb476148f4ba.zip ed0739bc3e5a7021a59d4cc4fc63e5fb60a0cb8628d30515a747bfbdcf1fdb0a "--exclude wg-quick --strip-components 1" || goto :error
|
||||
call :download wireguard-nt.zip https://download.wireguard.com/wireguard-nt/wireguard-nt-0.10.1.zip 772c0b1463d8d2212716f43f06f4594d880dea4f735165bd68e388fc41b81605 || goto :error
|
||||
call :download wintun.zip https://www.wintun.net/builds/wintun-0.14.1.zip 07c256185d6ee3652e09fa55c0b673e2624b565e02c4b9091c79ca7d2f24ef51 || goto :error
|
||||
copy /y NUL prepared > NUL || goto :error
|
||||
cd .. || goto :error
|
||||
|
||||
@@ -71,7 +70,7 @@ if exist .deps\prepared goto :render
|
||||
set GOARCH=%~3
|
||||
mkdir %1 >NUL 2>&1
|
||||
echo [+] Assembling resources %1
|
||||
%~2-w64-mingw32-windres -I ".deps\wireguard-nt\bin\%~1" -DWIREGUARD_VERSION_ARRAY=%WIREGUARD_VERSION_ARRAY% -DWIREGUARD_VERSION_STR=%WIREGUARD_VERSION% -i resources.rc -o "resources_%~3.syso" -O coff -c 65001 || exit /b %errorlevel%
|
||||
%~2-w64-mingw32-windres -DWIREGUARD_VERSION_ARRAY=%WIREGUARD_VERSION_ARRAY% -DWIREGUARD_VERSION_STR=%WIREGUARD_VERSION% -i resources.rc -o "resources_%~3.syso" -O coff -c 65001 || exit /b %errorlevel%
|
||||
echo [+] Building program %1
|
||||
go build -tags load_wgnt_from_rsrc -ldflags="-H windowsgui -s -w" -trimpath -buildvcs=false -v -o "%~1\wireguard.exe" || exit /b 1
|
||||
if not exist "%~1\wg.exe" (
|
||||
@@ -81,6 +80,9 @@ if exist .deps\prepared goto :render
|
||||
make --no-print-directory -C .deps\src PLATFORM=windows CC=%~2-w64-mingw32-gcc WINDRES=%~2-w64-mingw32-windres V=1 RUNSTATEDIR= SYSTEMDUNITDIR= -j%NUMBER_OF_PROCESSORS% || exit /b 1
|
||||
move /Y .deps\src\wg.exe "%~1\wg.exe" > NUL || exit /b 1
|
||||
)
|
||||
if not exist "%~1\wintun.dll" (
|
||||
copy /Y ".deps\wintun\bin\%~1\wintun.dll" "%~1\wintun.dll" > NUL || exit /b 1
|
||||
)
|
||||
goto :eof
|
||||
|
||||
:error
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package conf
|
||||
|
||||
import "golang.org/x/sys/windows/registry"
|
||||
|
||||
const adminRegKey = `Software\WireGuard`
|
||||
|
||||
var adminKey registry.Key
|
||||
|
||||
func openAdminKey() (registry.Key, error) {
|
||||
if adminKey != 0 {
|
||||
return adminKey, nil
|
||||
}
|
||||
var err error
|
||||
adminKey, err = registry.OpenKey(registry.LOCAL_MACHINE, adminRegKey, registry.QUERY_VALUE|registry.WOW64_64KEY)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return adminKey, nil
|
||||
}
|
||||
|
||||
func AdminBool(name string) bool {
|
||||
key, err := openAdminKey()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
val, _, err := key.GetIntegerValue(name)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return val != 0
|
||||
}
|
||||
248
conf/config.go
248
conf/config.go
@@ -1,248 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/curve25519"
|
||||
|
||||
"golang.zx2c4.com/wireguard/windows/l18n"
|
||||
)
|
||||
|
||||
const KeyLength = 32
|
||||
|
||||
type Endpoint struct {
|
||||
Host string
|
||||
Port uint16
|
||||
}
|
||||
|
||||
type (
|
||||
Key [KeyLength]byte
|
||||
HandshakeTime time.Duration
|
||||
Bytes uint64
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Name string
|
||||
Interface Interface
|
||||
Peers []Peer
|
||||
}
|
||||
|
||||
type Interface struct {
|
||||
PrivateKey Key
|
||||
Addresses []netip.Prefix
|
||||
ListenPort uint16
|
||||
MTU uint16
|
||||
DNS []netip.Addr
|
||||
DNSSearch []string
|
||||
PreUp string
|
||||
PostUp string
|
||||
PreDown string
|
||||
PostDown string
|
||||
TableOff bool
|
||||
}
|
||||
|
||||
type Peer struct {
|
||||
PublicKey Key
|
||||
PresharedKey Key
|
||||
AllowedIPs []netip.Prefix
|
||||
Endpoint Endpoint
|
||||
PersistentKeepalive uint16
|
||||
|
||||
RxBytes Bytes
|
||||
TxBytes Bytes
|
||||
LastHandshakeTime HandshakeTime
|
||||
}
|
||||
|
||||
func (conf *Config) IntersectsWith(other *Config) bool {
|
||||
allRoutes := make(map[netip.Prefix]bool, len(conf.Interface.Addresses)*2+len(conf.Peers)*3)
|
||||
for _, a := range conf.Interface.Addresses {
|
||||
allRoutes[netip.PrefixFrom(a.Addr(), a.Addr().BitLen())] = true
|
||||
allRoutes[a.Masked()] = true
|
||||
}
|
||||
for i := range conf.Peers {
|
||||
for _, a := range conf.Peers[i].AllowedIPs {
|
||||
allRoutes[a.Masked()] = true
|
||||
}
|
||||
}
|
||||
for _, a := range other.Interface.Addresses {
|
||||
if allRoutes[netip.PrefixFrom(a.Addr(), a.Addr().BitLen())] {
|
||||
return true
|
||||
}
|
||||
if allRoutes[a.Masked()] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for i := range other.Peers {
|
||||
for _, a := range other.Peers[i].AllowedIPs {
|
||||
if allRoutes[a.Masked()] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *Endpoint) String() string {
|
||||
if strings.IndexByte(e.Host, ':') != -1 {
|
||||
return fmt.Sprintf("[%s]:%d", e.Host, e.Port)
|
||||
}
|
||||
return fmt.Sprintf("%s:%d", e.Host, e.Port)
|
||||
}
|
||||
|
||||
func (e *Endpoint) IsEmpty() bool {
|
||||
return len(e.Host) == 0
|
||||
}
|
||||
|
||||
func (k *Key) String() string {
|
||||
return base64.StdEncoding.EncodeToString(k[:])
|
||||
}
|
||||
|
||||
func (k *Key) IsZero() bool {
|
||||
var zeros Key
|
||||
return subtle.ConstantTimeCompare(zeros[:], k[:]) == 1
|
||||
}
|
||||
|
||||
func (k *Key) Public() *Key {
|
||||
var p [KeyLength]byte
|
||||
curve25519.ScalarBaseMult(&p, (*[KeyLength]byte)(k))
|
||||
return (*Key)(&p)
|
||||
}
|
||||
|
||||
func NewPresharedKey() (*Key, error) {
|
||||
var k [KeyLength]byte
|
||||
_, err := rand.Read(k[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*Key)(&k), nil
|
||||
}
|
||||
|
||||
func NewPrivateKey() (*Key, error) {
|
||||
k, err := NewPresharedKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k[0] &= 248
|
||||
k[31] = (k[31] & 127) | 64
|
||||
return k, nil
|
||||
}
|
||||
|
||||
func NewPrivateKeyFromString(b64 string) (*Key, error) {
|
||||
return parseKeyBase64(b64)
|
||||
}
|
||||
|
||||
func (t HandshakeTime) IsEmpty() bool {
|
||||
return t == HandshakeTime(0)
|
||||
}
|
||||
|
||||
func (t HandshakeTime) String() string {
|
||||
u := time.Unix(0, 0).Add(time.Duration(t)).Unix()
|
||||
n := time.Now().Unix()
|
||||
if u == n {
|
||||
return l18n.Sprintf("Now")
|
||||
} else if u > n {
|
||||
return l18n.Sprintf("System clock wound backward!")
|
||||
}
|
||||
left := n - u
|
||||
years := left / (365 * 24 * 60 * 60)
|
||||
left = left % (365 * 24 * 60 * 60)
|
||||
days := left / (24 * 60 * 60)
|
||||
left = left % (24 * 60 * 60)
|
||||
hours := left / (60 * 60)
|
||||
left = left % (60 * 60)
|
||||
minutes := left / 60
|
||||
seconds := left % 60
|
||||
s := make([]string, 0, 5)
|
||||
if years > 0 {
|
||||
s = append(s, l18n.Sprintf("%d year(s)", years))
|
||||
}
|
||||
if days > 0 {
|
||||
s = append(s, l18n.Sprintf("%d day(s)", days))
|
||||
}
|
||||
if hours > 0 {
|
||||
s = append(s, l18n.Sprintf("%d hour(s)", hours))
|
||||
}
|
||||
if minutes > 0 {
|
||||
s = append(s, l18n.Sprintf("%d minute(s)", minutes))
|
||||
}
|
||||
if seconds > 0 {
|
||||
s = append(s, l18n.Sprintf("%d second(s)", seconds))
|
||||
}
|
||||
timestamp := strings.Join(s, l18n.UnitSeparator())
|
||||
return l18n.Sprintf("%s ago", timestamp)
|
||||
}
|
||||
|
||||
func (b Bytes) String() string {
|
||||
if b < 1024 {
|
||||
return l18n.Sprintf("%d\u00a0B", b)
|
||||
} else if b < 1024*1024 {
|
||||
return l18n.Sprintf("%.2f\u00a0KiB", float64(b)/1024)
|
||||
} else if b < 1024*1024*1024 {
|
||||
return l18n.Sprintf("%.2f\u00a0MiB", float64(b)/(1024*1024))
|
||||
} else if b < 1024*1024*1024*1024 {
|
||||
return l18n.Sprintf("%.2f\u00a0GiB", float64(b)/(1024*1024*1024))
|
||||
}
|
||||
return l18n.Sprintf("%.2f\u00a0TiB", float64(b)/(1024*1024*1024)/1024)
|
||||
}
|
||||
|
||||
func (conf *Config) DeduplicateNetworkEntries() {
|
||||
m := make(map[string]bool, len(conf.Interface.Addresses))
|
||||
i := 0
|
||||
for _, addr := range conf.Interface.Addresses {
|
||||
s := addr.String()
|
||||
if m[s] {
|
||||
continue
|
||||
}
|
||||
m[s] = true
|
||||
conf.Interface.Addresses[i] = addr
|
||||
i++
|
||||
}
|
||||
conf.Interface.Addresses = conf.Interface.Addresses[:i]
|
||||
|
||||
m = make(map[string]bool, len(conf.Interface.DNS))
|
||||
i = 0
|
||||
for _, addr := range conf.Interface.DNS {
|
||||
s := addr.String()
|
||||
if m[s] {
|
||||
continue
|
||||
}
|
||||
m[s] = true
|
||||
conf.Interface.DNS[i] = addr
|
||||
i++
|
||||
}
|
||||
conf.Interface.DNS = conf.Interface.DNS[:i]
|
||||
|
||||
for _, peer := range conf.Peers {
|
||||
m = make(map[string]bool, len(peer.AllowedIPs))
|
||||
i = 0
|
||||
for _, addr := range peer.AllowedIPs {
|
||||
s := addr.String()
|
||||
if m[s] {
|
||||
continue
|
||||
}
|
||||
m[s] = true
|
||||
peer.AllowedIPs[i] = addr
|
||||
i++
|
||||
}
|
||||
peer.AllowedIPs = peer.AllowedIPs[:i]
|
||||
}
|
||||
}
|
||||
|
||||
func (conf *Config) Redact() {
|
||||
conf.Interface.PrivateKey = Key{}
|
||||
for i := range conf.Peers {
|
||||
conf.Peers[i].PublicKey = Key{}
|
||||
conf.Peers[i].PresharedKey = Key{}
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/netip"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wireguard/windows/services"
|
||||
)
|
||||
|
||||
func resolveHostname(name string) (resolvedIPString string, err error) {
|
||||
maxTries := 10
|
||||
if services.StartedAtBoot() {
|
||||
maxTries *= 3
|
||||
}
|
||||
for i := 0; i < maxTries; i++ {
|
||||
if i > 0 {
|
||||
time.Sleep(time.Second * 4)
|
||||
}
|
||||
resolvedIPString, err = resolveHostnameOnce(name)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
if err == windows.WSATRY_AGAIN {
|
||||
log.Printf("Temporary DNS error when resolving %s, so sleeping for 4 seconds", name)
|
||||
continue
|
||||
}
|
||||
if err == windows.WSAHOST_NOT_FOUND && services.StartedAtBoot() {
|
||||
log.Printf("Host not found when resolving %s at boot time, so sleeping for 4 seconds", name)
|
||||
continue
|
||||
}
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func resolveHostnameOnce(name string) (resolvedIPString string, err error) {
|
||||
hints := windows.AddrinfoW{
|
||||
Family: windows.AF_UNSPEC,
|
||||
Socktype: windows.SOCK_DGRAM,
|
||||
Protocol: windows.IPPROTO_IP,
|
||||
}
|
||||
var result *windows.AddrinfoW
|
||||
name16, err := windows.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = windows.GetAddrInfoW(name16, nil, &hints, &result)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if result == nil {
|
||||
err = windows.WSAHOST_NOT_FOUND
|
||||
return
|
||||
}
|
||||
defer windows.FreeAddrInfoW(result)
|
||||
var v6 netip.Addr
|
||||
for ; result != nil; result = result.Next {
|
||||
if result.Family != windows.AF_INET && result.Family != windows.AF_INET6 {
|
||||
continue
|
||||
}
|
||||
addr := (*winipcfg.RawSockaddrInet)(unsafe.Pointer(result.Addr)).Addr()
|
||||
if addr.Is4() {
|
||||
return addr.String(), nil
|
||||
} else if !v6.IsValid() && addr.Is6() {
|
||||
v6 = addr
|
||||
}
|
||||
}
|
||||
if v6.IsValid() {
|
||||
return v6.String(), nil
|
||||
}
|
||||
err = windows.WSAHOST_NOT_FOUND
|
||||
return
|
||||
}
|
||||
|
||||
func (config *Config) ResolveEndpoints() error {
|
||||
for i := range config.Peers {
|
||||
if config.Peers[i].Endpoint.IsEmpty() {
|
||||
continue
|
||||
}
|
||||
var err error
|
||||
config.Peers[i].Endpoint.Host, err = resolveHostname(config.Peers[i].Endpoint.Host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package dpapi
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func bytesToBlob(bytes []byte) *windows.DataBlob {
|
||||
blob := &windows.DataBlob{Size: uint32(len(bytes))}
|
||||
if len(bytes) > 0 {
|
||||
blob.Data = &bytes[0]
|
||||
}
|
||||
return blob
|
||||
}
|
||||
|
||||
func Encrypt(data []byte, name string) ([]byte, error) {
|
||||
out := windows.DataBlob{}
|
||||
err := windows.CryptProtectData(bytesToBlob(data), windows.StringToUTF16Ptr(name), nil, 0, nil, windows.CRYPTPROTECT_UI_FORBIDDEN, &out)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to encrypt DPAPI protected data: %w", err)
|
||||
}
|
||||
ret := make([]byte, out.Size)
|
||||
copy(ret, unsafe.Slice(out.Data, out.Size))
|
||||
windows.LocalFree(windows.Handle(unsafe.Pointer(out.Data)))
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func Decrypt(data []byte, name string) ([]byte, error) {
|
||||
out := windows.DataBlob{}
|
||||
var outName *uint16
|
||||
utf16Name, err := windows.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = windows.CryptUnprotectData(bytesToBlob(data), &outName, nil, 0, nil, windows.CRYPTPROTECT_UI_FORBIDDEN, &out)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to decrypt DPAPI protected data: %w", err)
|
||||
}
|
||||
ret := make([]byte, out.Size)
|
||||
copy(ret, unsafe.Slice(out.Data, out.Size))
|
||||
windows.LocalFree(windows.Handle(unsafe.Pointer(out.Data)))
|
||||
|
||||
// Note: this ridiculous open-coded strcmp is not constant time.
|
||||
different := false
|
||||
a := outName
|
||||
b := utf16Name
|
||||
for {
|
||||
if *a != *b {
|
||||
different = true
|
||||
break
|
||||
}
|
||||
if *a == 0 || *b == 0 {
|
||||
break
|
||||
}
|
||||
a = (*uint16)(unsafe.Add(unsafe.Pointer(a), 2))
|
||||
b = (*uint16)(unsafe.Add(unsafe.Pointer(b), 2))
|
||||
}
|
||||
runtime.KeepAlive(utf16Name)
|
||||
windows.LocalFree(windows.Handle(unsafe.Pointer(outName)))
|
||||
|
||||
if different {
|
||||
return nil, errors.New("input name does not match the stored name")
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package dpapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func TestRoundTrip(t *testing.T) {
|
||||
name := "golang test"
|
||||
original := []byte("The quick brown fox jumped over the lazy dog")
|
||||
|
||||
e, err := Encrypt(original, name)
|
||||
if err != nil {
|
||||
t.Errorf("Error encrypting: %s", err.Error())
|
||||
}
|
||||
|
||||
if len(e) < len(original) {
|
||||
t.Error("Encrypted data is smaller than original data.")
|
||||
}
|
||||
|
||||
d, err := Decrypt(e, name)
|
||||
if err != nil {
|
||||
t.Errorf("Error decrypting: %s", err.Error())
|
||||
}
|
||||
|
||||
if !bytes.Equal(d, original) {
|
||||
t.Error("Decrypted content does not match original")
|
||||
}
|
||||
|
||||
_, err = Decrypt(e, "bad name")
|
||||
if err == nil {
|
||||
t.Error("Decryption failed to notice ad mismatch")
|
||||
}
|
||||
|
||||
eCorrupt := make([]byte, len(e))
|
||||
copy(eCorrupt, e)
|
||||
eCorrupt[len(original)-1] = 7
|
||||
_, err = Decrypt(eCorrupt, name)
|
||||
if err == nil {
|
||||
t.Error("Decryption failed to notice ciphertext corruption")
|
||||
}
|
||||
|
||||
copy(eCorrupt, e)
|
||||
nameUtf16, err := windows.UTF16FromString(name)
|
||||
if err != nil {
|
||||
t.Errorf("Unable to get utf16 chars for name: %s", err)
|
||||
}
|
||||
nameUtf16Bytes := unsafe.Slice((*byte)(unsafe.Pointer(&nameUtf16[0])), len(nameUtf16)*2)
|
||||
i := bytes.Index(eCorrupt, nameUtf16Bytes)
|
||||
if i == -1 {
|
||||
t.Error("Unable to find ad in blob")
|
||||
} else {
|
||||
eCorrupt[i] = 7
|
||||
_, err = Decrypt(eCorrupt, name)
|
||||
if err == nil {
|
||||
t.Error("Decryption failed to notice ad corruption")
|
||||
}
|
||||
}
|
||||
|
||||
// BUG: Actually, Windows doesn't report length extension of the buffer, unfortunately.
|
||||
//
|
||||
// eCorrupt = make([]byte, len(e)+1)
|
||||
// copy(eCorrupt, e)
|
||||
// _, err = Decrypt(eCorrupt, name)
|
||||
// if err == nil {
|
||||
// t.Error("Decryption failed to notice length extension")
|
||||
// }
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"path/filepath"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var encryptedFileSd unsafe.Pointer
|
||||
|
||||
func randomFileName() string {
|
||||
var randBytes [32]byte
|
||||
_, err := rand.Read(randBytes[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return hex.EncodeToString(randBytes[:]) + ".tmp"
|
||||
}
|
||||
|
||||
func writeLockedDownFile(destination string, overwrite bool, contents []byte) error {
|
||||
var err error
|
||||
sa := &windows.SecurityAttributes{Length: uint32(unsafe.Sizeof(windows.SecurityAttributes{}))}
|
||||
sa.SecurityDescriptor = (*windows.SECURITY_DESCRIPTOR)(atomic.LoadPointer(&encryptedFileSd))
|
||||
if sa.SecurityDescriptor == nil {
|
||||
sa.SecurityDescriptor, err = windows.SecurityDescriptorFromString("O:SYG:SYD:PAI(A;;FA;;;SY)(A;;SD;;;BA)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
atomic.StorePointer(&encryptedFileSd, unsafe.Pointer(sa.SecurityDescriptor))
|
||||
}
|
||||
destination16, err := windows.UTF16FromString(destination)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tmpDestination := filepath.Join(filepath.Dir(destination), randomFileName())
|
||||
tmpDestination16, err := windows.UTF16PtrFromString(tmpDestination)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
handle, err := windows.CreateFile(tmpDestination16, windows.GENERIC_WRITE|windows.DELETE, windows.FILE_SHARE_READ, sa, windows.CREATE_ALWAYS, windows.FILE_ATTRIBUTE_NORMAL, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer windows.CloseHandle(handle)
|
||||
deleteIt := func() {
|
||||
yes := byte(1)
|
||||
windows.SetFileInformationByHandle(handle, windows.FileDispositionInfo, &yes, 1)
|
||||
}
|
||||
n, err := windows.Write(handle, contents)
|
||||
if err != nil {
|
||||
deleteIt()
|
||||
return err
|
||||
}
|
||||
if n != len(contents) {
|
||||
deleteIt()
|
||||
return windows.ERROR_IO_INCOMPLETE
|
||||
}
|
||||
fileRenameInfo := &struct {
|
||||
replaceIfExists byte
|
||||
rootDirectory windows.Handle
|
||||
fileNameLength uint32
|
||||
fileName [windows.MAX_PATH]uint16
|
||||
}{replaceIfExists: func() byte {
|
||||
if overwrite {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}(), fileNameLength: uint32(len(destination16) - 1)}
|
||||
if len(destination16) > len(fileRenameInfo.fileName) {
|
||||
deleteIt()
|
||||
return windows.ERROR_BUFFER_OVERFLOW
|
||||
}
|
||||
copy(fileRenameInfo.fileName[:], destination16[:])
|
||||
err = windows.SetFileInformationByHandle(handle, windows.FileRenameInfo, (*byte)(unsafe.Pointer(fileRenameInfo)), uint32(unsafe.Sizeof(*fileRenameInfo)))
|
||||
if err != nil {
|
||||
deleteIt()
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
migrating sync.Mutex
|
||||
lastMigrationTimer *time.Timer
|
||||
)
|
||||
|
||||
type MigrationCallback func(name, oldPath, newPath string)
|
||||
|
||||
func MigrateUnencryptedConfigs(migrated MigrationCallback) { migrateUnencryptedConfigs(3, migrated) }
|
||||
|
||||
func migrateUnencryptedConfigs(sharingBase int, migrated MigrationCallback) {
|
||||
if migrated == nil {
|
||||
migrated = func(_, _, _ string) {}
|
||||
}
|
||||
migrating.Lock()
|
||||
defer migrating.Unlock()
|
||||
configFileDir, err := tunnelConfigurationsDirectory()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
files, err := os.ReadDir(configFileDir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ignoreSharingViolations := false
|
||||
for _, file := range files {
|
||||
path := filepath.Join(configFileDir, file.Name())
|
||||
name := filepath.Base(file.Name())
|
||||
if len(name) <= len(configFileUnencryptedSuffix) || !strings.HasSuffix(name, configFileUnencryptedSuffix) {
|
||||
continue
|
||||
}
|
||||
if !file.Type().IsRegular() {
|
||||
continue
|
||||
}
|
||||
info, err := file.Info()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if info.Mode().Perm()&0o444 == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var bytes []byte
|
||||
var config *Config
|
||||
var newPath string
|
||||
// We don't use os.ReadFile, because we actually want RDWR, so that we can take advantage
|
||||
// of Windows file locking for ensuring the file is finished being written.
|
||||
f, err := os.OpenFile(path, os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
if errors.Is(err, windows.ERROR_SHARING_VIOLATION) {
|
||||
if ignoreSharingViolations {
|
||||
continue
|
||||
} else if sharingBase > 0 {
|
||||
if lastMigrationTimer != nil {
|
||||
lastMigrationTimer.Stop()
|
||||
}
|
||||
lastMigrationTimer = time.AfterFunc(time.Second/time.Duration(sharingBase*sharingBase), func() { migrateUnencryptedConfigs(sharingBase-1, migrated) })
|
||||
ignoreSharingViolations = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
goto error
|
||||
}
|
||||
bytes, err = io.ReadAll(f)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
goto error
|
||||
}
|
||||
config, err = FromWgQuickWithUnknownEncoding(string(bytes), strings.TrimSuffix(name, configFileUnencryptedSuffix))
|
||||
if err != nil {
|
||||
goto error
|
||||
}
|
||||
err = config.Save(false)
|
||||
if err != nil {
|
||||
goto error
|
||||
}
|
||||
err = os.Remove(path)
|
||||
if err != nil {
|
||||
goto error
|
||||
}
|
||||
newPath, err = config.Path()
|
||||
if err != nil {
|
||||
goto error
|
||||
}
|
||||
migrated(config.Name, path, newPath)
|
||||
continue
|
||||
error:
|
||||
log.Printf("Unable to ingest and encrypt %#q: %v", path, err)
|
||||
}
|
||||
}
|
||||
127
conf/name.go
127
conf/name.go
@@ -1,127 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var reservedNames = []string{
|
||||
"CON", "PRN", "AUX", "NUL",
|
||||
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
|
||||
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
|
||||
}
|
||||
|
||||
const (
|
||||
serviceNameForbidden = "$"
|
||||
netshellDllForbidden = "\\/:*?\"<>|\t"
|
||||
specialChars = "/\\<>:\"|?*\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x00"
|
||||
)
|
||||
|
||||
var allowedNameFormat = regexp.MustCompile("^[a-zA-Z0-9_=+.-]{1,32}$")
|
||||
|
||||
func isReserved(name string) bool {
|
||||
if len(name) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, reserved := range reservedNames {
|
||||
if strings.EqualFold(name, reserved) {
|
||||
return true
|
||||
}
|
||||
for i := len(name) - 1; i >= 0; i-- {
|
||||
if name[i] == '.' {
|
||||
if strings.EqualFold(name[:i], reserved) {
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasSpecialChars(name string) bool {
|
||||
return strings.ContainsAny(name, specialChars) || strings.ContainsAny(name, netshellDllForbidden) || strings.ContainsAny(name, serviceNameForbidden)
|
||||
}
|
||||
|
||||
func TunnelNameIsValid(name string) bool {
|
||||
// Aside from our own restrictions, let's impose the Windows restrictions first
|
||||
if isReserved(name) || hasSpecialChars(name) {
|
||||
return false
|
||||
}
|
||||
return allowedNameFormat.MatchString(name)
|
||||
}
|
||||
|
||||
type naturalSortToken struct {
|
||||
maybeString string
|
||||
maybeNumber int
|
||||
}
|
||||
|
||||
type naturalSortString struct {
|
||||
originalString string
|
||||
tokens []naturalSortToken
|
||||
}
|
||||
|
||||
var naturalSortDigitFinder = regexp.MustCompile(`\d+|\D+`)
|
||||
|
||||
func newNaturalSortString(s string) (t naturalSortString) {
|
||||
t.originalString = s
|
||||
s = strings.ToLower(strings.Join(strings.Fields(s), " "))
|
||||
x := naturalSortDigitFinder.FindAllString(s, -1)
|
||||
t.tokens = make([]naturalSortToken, len(x))
|
||||
for i, s := range x {
|
||||
if n, err := strconv.Atoi(s); err == nil {
|
||||
t.tokens[i].maybeNumber = n
|
||||
} else {
|
||||
t.tokens[i].maybeString = s
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (f1 naturalSortToken) Cmp(f2 naturalSortToken) int {
|
||||
if len(f1.maybeString) == 0 {
|
||||
if len(f2.maybeString) > 0 || f1.maybeNumber < f2.maybeNumber {
|
||||
return -1
|
||||
} else if f1.maybeNumber > f2.maybeNumber {
|
||||
return 1
|
||||
}
|
||||
} else if len(f2.maybeString) == 0 || f1.maybeString > f2.maybeString {
|
||||
return 1
|
||||
} else if f1.maybeString < f2.maybeString {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func TunnelNameIsLess(a, b string) bool {
|
||||
if a == b {
|
||||
return false
|
||||
}
|
||||
na, nb := newNaturalSortString(a), newNaturalSortString(b)
|
||||
for i, t := range nb.tokens {
|
||||
if i == len(na.tokens) {
|
||||
return true
|
||||
}
|
||||
switch na.tokens[i].Cmp(t) {
|
||||
case -1:
|
||||
return true
|
||||
case 1:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ServiceNameOfTunnel(tunnelName string) (string, error) {
|
||||
if !TunnelNameIsValid(tunnelName) {
|
||||
return "", errors.New("Tunnel name is not valid")
|
||||
}
|
||||
return "WireGuardTunnel$" + tunnelName, nil
|
||||
}
|
||||
400
conf/parser.go
400
conf/parser.go
@@ -1,400 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/text/encoding/unicode"
|
||||
|
||||
"golang.zx2c4.com/wireguard/windows/driver"
|
||||
"golang.zx2c4.com/wireguard/windows/l18n"
|
||||
)
|
||||
|
||||
type ParseError struct {
|
||||
why string
|
||||
offender string
|
||||
}
|
||||
|
||||
func (e *ParseError) Error() string {
|
||||
return l18n.Sprintf("%s: %q", e.why, e.offender)
|
||||
}
|
||||
|
||||
func parseIPCidr(s string) (netip.Prefix, error) {
|
||||
ipcidr, err := netip.ParsePrefix(s)
|
||||
if err == nil {
|
||||
return ipcidr, nil
|
||||
}
|
||||
addr, err := netip.ParseAddr(s)
|
||||
if err != nil {
|
||||
return netip.Prefix{}, &ParseError{l18n.Sprintf("Invalid IP address: "), s}
|
||||
}
|
||||
return netip.PrefixFrom(addr, addr.BitLen()), nil
|
||||
}
|
||||
|
||||
func parseEndpoint(s string) (*Endpoint, error) {
|
||||
i := strings.LastIndexByte(s, ':')
|
||||
if i < 0 {
|
||||
return nil, &ParseError{l18n.Sprintf("Missing port from endpoint"), s}
|
||||
}
|
||||
host, portStr := s[:i], s[i+1:]
|
||||
if len(host) < 1 {
|
||||
return nil, &ParseError{l18n.Sprintf("Invalid endpoint host"), host}
|
||||
}
|
||||
port, err := parsePort(portStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hostColon := strings.IndexByte(host, ':')
|
||||
if host[0] == '[' || host[len(host)-1] == ']' || hostColon > 0 {
|
||||
err := &ParseError{l18n.Sprintf("Brackets must contain an IPv6 address"), host}
|
||||
if len(host) > 3 && host[0] == '[' && host[len(host)-1] == ']' && hostColon > 0 {
|
||||
end := len(host) - 1
|
||||
if i := strings.LastIndexByte(host, '%'); i > 1 {
|
||||
end = i
|
||||
}
|
||||
maybeV6, err2 := netip.ParseAddr(host[1:end])
|
||||
if err2 != nil || !maybeV6.Is6() {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
host = host[1 : len(host)-1]
|
||||
}
|
||||
return &Endpoint{host, port}, nil
|
||||
}
|
||||
|
||||
func parseMTU(s string) (uint16, error) {
|
||||
m, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if m < 576 || m > 65535 {
|
||||
return 0, &ParseError{l18n.Sprintf("Invalid MTU"), s}
|
||||
}
|
||||
return uint16(m), nil
|
||||
}
|
||||
|
||||
func parsePort(s string) (uint16, error) {
|
||||
m, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if m < 0 || m > 65535 {
|
||||
return 0, &ParseError{l18n.Sprintf("Invalid port"), s}
|
||||
}
|
||||
return uint16(m), nil
|
||||
}
|
||||
|
||||
func parsePersistentKeepalive(s string) (uint16, error) {
|
||||
if s == "off" {
|
||||
return 0, nil
|
||||
}
|
||||
m, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if m < 0 || m > 65535 {
|
||||
return 0, &ParseError{l18n.Sprintf("Invalid persistent keepalive"), s}
|
||||
}
|
||||
return uint16(m), nil
|
||||
}
|
||||
|
||||
func parseTableOff(s string) (bool, error) {
|
||||
if s == "off" {
|
||||
return true, nil
|
||||
} else if s == "auto" || s == "main" {
|
||||
return false, nil
|
||||
}
|
||||
_, err := strconv.ParseUint(s, 10, 32)
|
||||
return false, err
|
||||
}
|
||||
|
||||
func parseKeyBase64(s string) (*Key, error) {
|
||||
k, err := base64.StdEncoding.DecodeString(s)
|
||||
if err != nil {
|
||||
return nil, &ParseError{l18n.Sprintf("Invalid key: %v", err), s}
|
||||
}
|
||||
if len(k) != KeyLength {
|
||||
return nil, &ParseError{l18n.Sprintf("Keys must decode to exactly 32 bytes"), s}
|
||||
}
|
||||
var key Key
|
||||
copy(key[:], k)
|
||||
return &key, nil
|
||||
}
|
||||
|
||||
func splitList(s string) ([]string, error) {
|
||||
var out []string
|
||||
for _, split := range strings.Split(s, ",") {
|
||||
trim := strings.TrimSpace(split)
|
||||
if len(trim) == 0 {
|
||||
return nil, &ParseError{l18n.Sprintf("Two commas in a row"), s}
|
||||
}
|
||||
out = append(out, trim)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
type parserState int
|
||||
|
||||
const (
|
||||
inInterfaceSection parserState = iota
|
||||
inPeerSection
|
||||
notInASection
|
||||
)
|
||||
|
||||
func (c *Config) maybeAddPeer(p *Peer) {
|
||||
if p != nil {
|
||||
c.Peers = append(c.Peers, *p)
|
||||
}
|
||||
}
|
||||
|
||||
func FromWgQuick(s, name string) (*Config, error) {
|
||||
if !TunnelNameIsValid(name) {
|
||||
return nil, &ParseError{l18n.Sprintf("Tunnel name is not valid"), name}
|
||||
}
|
||||
lines := strings.Split(s, "\n")
|
||||
parserState := notInASection
|
||||
conf := Config{Name: name}
|
||||
sawPrivateKey := false
|
||||
var peer *Peer
|
||||
for _, line := range lines {
|
||||
line, _, _ = strings.Cut(line, "#")
|
||||
line = strings.TrimSpace(line)
|
||||
lineLower := strings.ToLower(line)
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
if lineLower == "[interface]" {
|
||||
conf.maybeAddPeer(peer)
|
||||
parserState = inInterfaceSection
|
||||
continue
|
||||
}
|
||||
if lineLower == "[peer]" {
|
||||
conf.maybeAddPeer(peer)
|
||||
peer = &Peer{}
|
||||
parserState = inPeerSection
|
||||
continue
|
||||
}
|
||||
if parserState == notInASection {
|
||||
return nil, &ParseError{l18n.Sprintf("Line must occur in a section"), line}
|
||||
}
|
||||
equals := strings.IndexByte(line, '=')
|
||||
if equals < 0 {
|
||||
return nil, &ParseError{l18n.Sprintf("Config key is missing an equals separator"), line}
|
||||
}
|
||||
key, val := strings.TrimSpace(lineLower[:equals]), strings.TrimSpace(line[equals+1:])
|
||||
if len(val) == 0 {
|
||||
return nil, &ParseError{l18n.Sprintf("Key must have a value"), line}
|
||||
}
|
||||
if parserState == inInterfaceSection {
|
||||
switch key {
|
||||
case "privatekey":
|
||||
k, err := parseKeyBase64(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conf.Interface.PrivateKey = *k
|
||||
sawPrivateKey = true
|
||||
case "listenport":
|
||||
p, err := parsePort(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conf.Interface.ListenPort = p
|
||||
case "mtu":
|
||||
m, err := parseMTU(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conf.Interface.MTU = m
|
||||
case "address":
|
||||
addresses, err := splitList(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, address := range addresses {
|
||||
a, err := parseIPCidr(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conf.Interface.Addresses = append(conf.Interface.Addresses, a)
|
||||
}
|
||||
case "dns":
|
||||
addresses, err := splitList(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, address := range addresses {
|
||||
a, err := netip.ParseAddr(address)
|
||||
if err != nil {
|
||||
conf.Interface.DNSSearch = append(conf.Interface.DNSSearch, address)
|
||||
} else {
|
||||
conf.Interface.DNS = append(conf.Interface.DNS, a)
|
||||
}
|
||||
}
|
||||
case "preup":
|
||||
conf.Interface.PreUp = val
|
||||
case "postup":
|
||||
conf.Interface.PostUp = val
|
||||
case "predown":
|
||||
conf.Interface.PreDown = val
|
||||
case "postdown":
|
||||
conf.Interface.PostDown = val
|
||||
case "table":
|
||||
tableOff, err := parseTableOff(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conf.Interface.TableOff = tableOff
|
||||
default:
|
||||
return nil, &ParseError{l18n.Sprintf("Invalid key for [Interface] section"), key}
|
||||
}
|
||||
} else if parserState == inPeerSection {
|
||||
switch key {
|
||||
case "publickey":
|
||||
k, err := parseKeyBase64(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
peer.PublicKey = *k
|
||||
case "presharedkey":
|
||||
k, err := parseKeyBase64(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
peer.PresharedKey = *k
|
||||
case "allowedips":
|
||||
addresses, err := splitList(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, address := range addresses {
|
||||
a, err := parseIPCidr(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
peer.AllowedIPs = append(peer.AllowedIPs, a)
|
||||
}
|
||||
case "persistentkeepalive":
|
||||
p, err := parsePersistentKeepalive(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
peer.PersistentKeepalive = p
|
||||
case "endpoint":
|
||||
e, err := parseEndpoint(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
peer.Endpoint = *e
|
||||
default:
|
||||
return nil, &ParseError{l18n.Sprintf("Invalid key for [Peer] section"), key}
|
||||
}
|
||||
}
|
||||
}
|
||||
conf.maybeAddPeer(peer)
|
||||
|
||||
if !sawPrivateKey {
|
||||
return nil, &ParseError{l18n.Sprintf("An interface must have a private key"), l18n.Sprintf("[none specified]")}
|
||||
}
|
||||
for _, p := range conf.Peers {
|
||||
if p.PublicKey.IsZero() {
|
||||
return nil, &ParseError{l18n.Sprintf("All peers must have public keys"), l18n.Sprintf("[none specified]")}
|
||||
}
|
||||
}
|
||||
|
||||
return &conf, nil
|
||||
}
|
||||
|
||||
func FromWgQuickWithUnknownEncoding(s, name string) (*Config, error) {
|
||||
c, firstErr := FromWgQuick(s, name)
|
||||
if firstErr == nil {
|
||||
return c, nil
|
||||
}
|
||||
for _, encoding := range unicode.All {
|
||||
decoded, err := encoding.NewDecoder().String(s)
|
||||
if err == nil {
|
||||
c, err := FromWgQuick(decoded, name)
|
||||
if err == nil {
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, firstErr
|
||||
}
|
||||
|
||||
func FromDriverConfiguration(interfaze *driver.Interface, existingConfig *Config) *Config {
|
||||
conf := Config{
|
||||
Name: existingConfig.Name,
|
||||
Interface: Interface{
|
||||
Addresses: existingConfig.Interface.Addresses,
|
||||
DNS: existingConfig.Interface.DNS,
|
||||
DNSSearch: existingConfig.Interface.DNSSearch,
|
||||
MTU: existingConfig.Interface.MTU,
|
||||
PreUp: existingConfig.Interface.PreUp,
|
||||
PostUp: existingConfig.Interface.PostUp,
|
||||
PreDown: existingConfig.Interface.PreDown,
|
||||
PostDown: existingConfig.Interface.PostDown,
|
||||
TableOff: existingConfig.Interface.TableOff,
|
||||
},
|
||||
}
|
||||
if interfaze.Flags&driver.InterfaceHasPrivateKey != 0 {
|
||||
conf.Interface.PrivateKey = interfaze.PrivateKey
|
||||
}
|
||||
if interfaze.Flags&driver.InterfaceHasListenPort != 0 {
|
||||
conf.Interface.ListenPort = interfaze.ListenPort
|
||||
}
|
||||
var p *driver.Peer
|
||||
for i := uint32(0); i < interfaze.PeerCount; i++ {
|
||||
if p == nil {
|
||||
p = interfaze.FirstPeer()
|
||||
} else {
|
||||
p = p.NextPeer()
|
||||
}
|
||||
peer := Peer{}
|
||||
if p.Flags&driver.PeerHasPublicKey != 0 {
|
||||
peer.PublicKey = p.PublicKey
|
||||
}
|
||||
if p.Flags&driver.PeerHasPresharedKey != 0 {
|
||||
peer.PresharedKey = p.PresharedKey
|
||||
}
|
||||
if p.Flags&driver.PeerHasEndpoint != 0 {
|
||||
peer.Endpoint.Port = p.Endpoint.Port()
|
||||
peer.Endpoint.Host = p.Endpoint.Addr().String()
|
||||
}
|
||||
if p.Flags&driver.PeerHasPersistentKeepalive != 0 {
|
||||
peer.PersistentKeepalive = p.PersistentKeepalive
|
||||
}
|
||||
peer.TxBytes = Bytes(p.TxBytes)
|
||||
peer.RxBytes = Bytes(p.RxBytes)
|
||||
if p.LastHandshake != 0 {
|
||||
peer.LastHandshakeTime = HandshakeTime((p.LastHandshake - 116444736000000000) * 100)
|
||||
}
|
||||
var a *driver.AllowedIP
|
||||
for j := uint32(0); j < p.AllowedIPsCount; j++ {
|
||||
if a == nil {
|
||||
a = p.FirstAllowedIP()
|
||||
} else {
|
||||
a = a.NextAllowedIP()
|
||||
}
|
||||
var ip netip.Addr
|
||||
if a.AddressFamily == windows.AF_INET {
|
||||
ip = netip.AddrFrom4(*(*[4]byte)(a.Address[:4]))
|
||||
} else if a.AddressFamily == windows.AF_INET6 {
|
||||
ip = netip.AddrFrom16(*(*[16]byte)(a.Address[:16]))
|
||||
}
|
||||
peer.AllowedIPs = append(peer.AllowedIPs, netip.PrefixFrom(ip, int(a.Cidr)))
|
||||
}
|
||||
conf.Peers = append(conf.Peers, peer)
|
||||
}
|
||||
return &conf
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const testInput = `
|
||||
[Interface]
|
||||
Address = 10.192.122.1/24
|
||||
Address = 10.10.0.1/16
|
||||
PrivateKey = yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk=
|
||||
ListenPort = 51820 #comments don't matter
|
||||
|
||||
[Peer]
|
||||
PublicKey = xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=
|
||||
Endpoint = 192.95.5.67:1234
|
||||
AllowedIPs = 10.192.122.3/32, 10.192.124.1/24
|
||||
|
||||
[Peer]
|
||||
PublicKey = TrMvSoP4jYQlY6RIzBgbssQqY3vxI2Pi+y71lOWWXX0=
|
||||
Endpoint = [2607:5300:60:6b0::c05f:543]:2468
|
||||
AllowedIPs = 10.192.122.4/32, 192.168.0.0/16
|
||||
PersistentKeepalive = 100
|
||||
|
||||
[Peer]
|
||||
PublicKey = gN65BkIKy1eCE9pP1wdc8ROUtkHLF2PfAqYdyYBz6EA=
|
||||
PresharedKey = TrMvSoP4jYQlY6RIzBgbssQqY3vxI2Pi+y71lOWWXX0=
|
||||
Endpoint = test.wireguard.com:18981
|
||||
AllowedIPs = 10.10.10.230/32`
|
||||
|
||||
func noError(t *testing.T, err error) bool {
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
_, fn, line, _ := runtime.Caller(1)
|
||||
t.Errorf("Error at %s:%d: %#v", fn, line, err)
|
||||
return false
|
||||
}
|
||||
|
||||
func equal(t *testing.T, expected, actual any) bool {
|
||||
if reflect.DeepEqual(expected, actual) {
|
||||
return true
|
||||
}
|
||||
_, fn, line, _ := runtime.Caller(1)
|
||||
t.Errorf("Failed equals at %s:%d\nactual %#v\nexpected %#v", fn, line, actual, expected)
|
||||
return false
|
||||
}
|
||||
|
||||
func lenTest(t *testing.T, actualO any, expected int) bool {
|
||||
actual := reflect.ValueOf(actualO).Len()
|
||||
if reflect.DeepEqual(expected, actual) {
|
||||
return true
|
||||
}
|
||||
_, fn, line, _ := runtime.Caller(1)
|
||||
t.Errorf("Wrong length at %s:%d\nactual %#v\nexpected %#v", fn, line, actual, expected)
|
||||
return false
|
||||
}
|
||||
|
||||
func contains(t *testing.T, list, element any) bool {
|
||||
listValue := reflect.ValueOf(list)
|
||||
for i := 0; i < listValue.Len(); i++ {
|
||||
if reflect.DeepEqual(listValue.Index(i).Interface(), element) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
_, fn, line, _ := runtime.Caller(1)
|
||||
t.Errorf("Error %s:%d\nelement not found: %#v", fn, line, element)
|
||||
return false
|
||||
}
|
||||
|
||||
func TestFromWgQuick(t *testing.T) {
|
||||
conf, err := FromWgQuick(testInput, "test")
|
||||
if noError(t, err) {
|
||||
lenTest(t, conf.Interface.Addresses, 2)
|
||||
contains(t, conf.Interface.Addresses, netip.PrefixFrom(netip.AddrFrom4([4]byte{0, 10, 0, 1}), 16))
|
||||
contains(t, conf.Interface.Addresses, netip.PrefixFrom(netip.AddrFrom4([4]byte{10, 192, 122, 1}), 24))
|
||||
equal(t, "yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk=", conf.Interface.PrivateKey.String())
|
||||
equal(t, uint16(51820), conf.Interface.ListenPort)
|
||||
|
||||
lenTest(t, conf.Peers, 3)
|
||||
lenTest(t, conf.Peers[0].AllowedIPs, 2)
|
||||
equal(t, Endpoint{Host: "192.95.5.67", Port: 1234}, conf.Peers[0].Endpoint)
|
||||
equal(t, "xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=", conf.Peers[0].PublicKey.String())
|
||||
|
||||
lenTest(t, conf.Peers[1].AllowedIPs, 2)
|
||||
equal(t, Endpoint{Host: "2607:5300:60:6b0::c05f:543", Port: 2468}, conf.Peers[1].Endpoint)
|
||||
equal(t, "TrMvSoP4jYQlY6RIzBgbssQqY3vxI2Pi+y71lOWWXX0=", conf.Peers[1].PublicKey.String())
|
||||
equal(t, uint16(100), conf.Peers[1].PersistentKeepalive)
|
||||
|
||||
lenTest(t, conf.Peers[2].AllowedIPs, 1)
|
||||
equal(t, Endpoint{Host: "test.wireguard.com", Port: 18981}, conf.Peers[2].Endpoint)
|
||||
equal(t, "gN65BkIKy1eCE9pP1wdc8ROUtkHLF2PfAqYdyYBz6EA=", conf.Peers[2].PublicKey.String())
|
||||
equal(t, "TrMvSoP4jYQlY6RIzBgbssQqY3vxI2Pi+y71lOWWXX0=", conf.Peers[2].PresharedKey.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseEndpoint(t *testing.T) {
|
||||
_, err := parseEndpoint("[192.168.42.0:]:51880")
|
||||
if err == nil {
|
||||
t.Error("Error was expected")
|
||||
}
|
||||
e, err := parseEndpoint("192.168.42.0:51880")
|
||||
if noError(t, err) {
|
||||
equal(t, "192.168.42.0", e.Host)
|
||||
equal(t, uint16(51880), e.Port)
|
||||
}
|
||||
e, err = parseEndpoint("test.wireguard.com:18981")
|
||||
if noError(t, err) {
|
||||
equal(t, "test.wireguard.com", e.Host)
|
||||
equal(t, uint16(18981), e.Port)
|
||||
}
|
||||
e, err = parseEndpoint("[2607:5300:60:6b0::c05f:543]:2468")
|
||||
if noError(t, err) {
|
||||
equal(t, "2607:5300:60:6b0::c05f:543", e.Host)
|
||||
equal(t, uint16(2468), e.Port)
|
||||
}
|
||||
_, err = parseEndpoint("[::::::invalid:18981")
|
||||
if err == nil {
|
||||
t.Error("Error was expected")
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
cachedConfigFileDir string
|
||||
cachedRootDir string
|
||||
)
|
||||
|
||||
func tunnelConfigurationsDirectory() (string, error) {
|
||||
if cachedConfigFileDir != "" {
|
||||
return cachedConfigFileDir, nil
|
||||
}
|
||||
root, err := RootDirectory(true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
c := filepath.Join(root, "Configurations")
|
||||
err = os.Mkdir(c, os.ModeDir|0o700)
|
||||
if err != nil && !os.IsExist(err) {
|
||||
return "", err
|
||||
}
|
||||
cachedConfigFileDir = c
|
||||
return cachedConfigFileDir, nil
|
||||
}
|
||||
|
||||
// PresetRootDirectory causes RootDirectory() to not try any automatic deduction, and instead
|
||||
// uses what's passed to it. This isn't used by wireguard-windows, but is useful for external
|
||||
// consumers of our libraries who might want to do strange things.
|
||||
func PresetRootDirectory(root string) {
|
||||
cachedRootDir = root
|
||||
}
|
||||
|
||||
func RootDirectory(create bool) (string, error) {
|
||||
if cachedRootDir != "" {
|
||||
return cachedRootDir, nil
|
||||
}
|
||||
root, err := windows.KnownFolderPath(windows.FOLDERID_ProgramFiles, windows.KF_FLAG_DEFAULT)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
root = filepath.Join(root, "WireGuard")
|
||||
if !create {
|
||||
return filepath.Join(root, "Data"), nil
|
||||
}
|
||||
root16, err := windows.UTF16PtrFromString(root)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// The root directory inherits its ACL from Program Files; we don't want to mess with that
|
||||
err = windows.CreateDirectory(root16, nil)
|
||||
if err != nil && err != windows.ERROR_ALREADY_EXISTS {
|
||||
return "", err
|
||||
}
|
||||
|
||||
dataDirectorySd, err := windows.SecurityDescriptorFromString("O:SYG:SYD:PAI(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
dataDirectorySa := &windows.SecurityAttributes{
|
||||
Length: uint32(unsafe.Sizeof(windows.SecurityAttributes{})),
|
||||
SecurityDescriptor: dataDirectorySd,
|
||||
}
|
||||
|
||||
data := filepath.Join(root, "Data")
|
||||
data16, err := windows.UTF16PtrFromString(data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var dataHandle windows.Handle
|
||||
for {
|
||||
err = windows.CreateDirectory(data16, dataDirectorySa)
|
||||
if err != nil && err != windows.ERROR_ALREADY_EXISTS {
|
||||
return "", err
|
||||
}
|
||||
dataHandle, err = windows.CreateFile(data16, windows.READ_CONTROL|windows.WRITE_OWNER|windows.WRITE_DAC, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, nil, windows.OPEN_EXISTING, windows.FILE_FLAG_BACKUP_SEMANTICS|windows.FILE_FLAG_OPEN_REPARSE_POINT|windows.FILE_ATTRIBUTE_DIRECTORY, 0)
|
||||
if err != nil && err != windows.ERROR_FILE_NOT_FOUND {
|
||||
return "", err
|
||||
}
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
defer windows.CloseHandle(dataHandle)
|
||||
var fileInfo windows.ByHandleFileInformation
|
||||
err = windows.GetFileInformationByHandle(dataHandle, &fileInfo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if fileInfo.FileAttributes&windows.FILE_ATTRIBUTE_DIRECTORY == 0 {
|
||||
return "", errors.New("Data directory is actually a file")
|
||||
}
|
||||
if fileInfo.FileAttributes&windows.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
|
||||
return "", errors.New("Data directory is reparse point")
|
||||
}
|
||||
buf := make([]uint16, windows.MAX_PATH+4)
|
||||
for {
|
||||
bufLen, err := windows.GetFinalPathNameByHandle(dataHandle, &buf[0], uint32(len(buf)), 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if bufLen < uint32(len(buf)) {
|
||||
break
|
||||
}
|
||||
buf = make([]uint16, bufLen)
|
||||
}
|
||||
if !strings.EqualFold(`\\?\`+data, windows.UTF16ToString(buf[:])) {
|
||||
return "", errors.New("Data directory jumped to unexpected location")
|
||||
}
|
||||
err = windows.SetKernelObjectSecurity(dataHandle, windows.DACL_SECURITY_INFORMATION|windows.GROUP_SECURITY_INFORMATION|windows.OWNER_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION, dataDirectorySd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
cachedRootDir = data
|
||||
return cachedRootDir, nil
|
||||
}
|
||||
|
||||
func LogFile(createRoot bool) (string, error) {
|
||||
root, err := RootDirectory(createRoot)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(root, "log.bin"), nil
|
||||
}
|
||||
142
conf/store.go
142
conf/store.go
@@ -1,142 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.zx2c4.com/wireguard/windows/conf/dpapi"
|
||||
)
|
||||
|
||||
const (
|
||||
configFileSuffix = ".conf.dpapi"
|
||||
configFileUnencryptedSuffix = ".conf"
|
||||
)
|
||||
|
||||
func ListConfigNames() ([]string, error) {
|
||||
configFileDir, err := tunnelConfigurationsDirectory()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
files, err := os.ReadDir(configFileDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configs := make([]string, len(files))
|
||||
i := 0
|
||||
for _, file := range files {
|
||||
name, err := NameFromPath(file.Name())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if !file.Type().IsRegular() {
|
||||
continue
|
||||
}
|
||||
info, err := file.Info()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if info.Mode().Perm()&0o444 == 0 {
|
||||
continue
|
||||
}
|
||||
configs[i] = name
|
||||
i++
|
||||
}
|
||||
return configs[:i], nil
|
||||
}
|
||||
|
||||
func LoadFromName(name string) (*Config, error) {
|
||||
configFileDir, err := tunnelConfigurationsDirectory()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return LoadFromPath(filepath.Join(configFileDir, name+configFileSuffix))
|
||||
}
|
||||
|
||||
func LoadFromPath(path string) (*Config, error) {
|
||||
name, err := NameFromPath(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if strings.HasSuffix(path, configFileSuffix) {
|
||||
bytes, err = dpapi.Decrypt(bytes, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return FromWgQuickWithUnknownEncoding(string(bytes), name)
|
||||
}
|
||||
|
||||
func PathIsEncrypted(path string) bool {
|
||||
return strings.HasSuffix(filepath.Base(path), configFileSuffix)
|
||||
}
|
||||
|
||||
func NameFromPath(path string) (string, error) {
|
||||
name := filepath.Base(path)
|
||||
if !((len(name) > len(configFileSuffix) && strings.HasSuffix(name, configFileSuffix)) ||
|
||||
(len(name) > len(configFileUnencryptedSuffix) && strings.HasSuffix(name, configFileUnencryptedSuffix))) {
|
||||
return "", errors.New("Path must end in either " + configFileSuffix + " or " + configFileUnencryptedSuffix)
|
||||
}
|
||||
if strings.HasSuffix(path, configFileSuffix) {
|
||||
name = strings.TrimSuffix(name, configFileSuffix)
|
||||
} else {
|
||||
name = strings.TrimSuffix(name, configFileUnencryptedSuffix)
|
||||
}
|
||||
if !TunnelNameIsValid(name) {
|
||||
return "", errors.New("Tunnel name is not valid")
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func (config *Config) Save(overwrite bool) error {
|
||||
if !TunnelNameIsValid(config.Name) {
|
||||
return errors.New("Tunnel name is not valid")
|
||||
}
|
||||
configFileDir, err := tunnelConfigurationsDirectory()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
filename := filepath.Join(configFileDir, config.Name+configFileSuffix)
|
||||
bytes := []byte(config.ToWgQuick())
|
||||
bytes, err = dpapi.Encrypt(bytes, config.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeLockedDownFile(filename, overwrite, bytes)
|
||||
}
|
||||
|
||||
func (config *Config) Path() (string, error) {
|
||||
if !TunnelNameIsValid(config.Name) {
|
||||
return "", errors.New("Tunnel name is not valid")
|
||||
}
|
||||
configFileDir, err := tunnelConfigurationsDirectory()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(configFileDir, config.Name+configFileSuffix), nil
|
||||
}
|
||||
|
||||
func DeleteName(name string) error {
|
||||
if !TunnelNameIsValid(name) {
|
||||
return errors.New("Tunnel name is not valid")
|
||||
}
|
||||
configFileDir, err := tunnelConfigurationsDirectory()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Remove(filepath.Join(configFileDir, name+configFileSuffix))
|
||||
}
|
||||
|
||||
func (config *Config) Delete() error {
|
||||
return DeleteName(config.Name)
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStorage(t *testing.T) {
|
||||
c, err := FromWgQuick(testInput, "golangTest")
|
||||
if err != nil {
|
||||
t.Errorf("Unable to parse test config: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err = c.Save(true)
|
||||
if err != nil {
|
||||
t.Errorf("Unable to save config: %s", err.Error())
|
||||
}
|
||||
|
||||
configs, err := ListConfigNames()
|
||||
if err != nil {
|
||||
t.Errorf("Unable to list configs: %s", err.Error())
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, name := range configs {
|
||||
if name == "golangTest" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Error("Unable to find saved config in list")
|
||||
}
|
||||
|
||||
loaded, err := LoadFromName("golangTest")
|
||||
if err != nil {
|
||||
t.Errorf("Unable to load config: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(loaded, c) {
|
||||
t.Error("Loaded config is not the same as saved config")
|
||||
}
|
||||
|
||||
k, err := NewPrivateKey()
|
||||
if err != nil {
|
||||
t.Errorf("Unable to generate new private key: %s", err.Error())
|
||||
}
|
||||
c.Interface.PrivateKey = *k
|
||||
|
||||
err = c.Save(false)
|
||||
if err == nil {
|
||||
t.Error("Config disappeared or was unexpectedly overwritten")
|
||||
}
|
||||
err = c.Save(true)
|
||||
if err != nil {
|
||||
t.Errorf("Unable to save config a second time: %s", err.Error())
|
||||
}
|
||||
|
||||
loaded, err = LoadFromName("golangTest")
|
||||
if err != nil {
|
||||
t.Errorf("Unable to load config a second time: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(loaded, c) {
|
||||
t.Error("Second loaded config is not the same as second saved config")
|
||||
}
|
||||
|
||||
err = DeleteName("golangTest")
|
||||
if err != nil {
|
||||
t.Errorf("Unable to delete config: %s", err.Error())
|
||||
}
|
||||
|
||||
configs, err = ListConfigNames()
|
||||
if err != nil {
|
||||
t.Errorf("Unable to list configs: %s", err.Error())
|
||||
}
|
||||
found = false
|
||||
for _, name := range configs {
|
||||
if name == "golangTest" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if found {
|
||||
t.Error("Config wasn't actually deleted")
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package conf
|
||||
|
||||
type StoreCallback struct {
|
||||
cb func()
|
||||
}
|
||||
|
||||
var storeCallbacks = make(map[*StoreCallback]bool)
|
||||
|
||||
func RegisterStoreChangeCallback(cb func()) *StoreCallback {
|
||||
startWatchingConfigDir()
|
||||
cb()
|
||||
s := &StoreCallback{cb}
|
||||
storeCallbacks[s] = true
|
||||
return s
|
||||
}
|
||||
|
||||
func (cb *StoreCallback) Unregister() {
|
||||
delete(storeCallbacks, cb)
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var haveStartedWatchingConfigDir bool
|
||||
|
||||
func startWatchingConfigDir() {
|
||||
if haveStartedWatchingConfigDir {
|
||||
return
|
||||
}
|
||||
haveStartedWatchingConfigDir = true
|
||||
go func() {
|
||||
h := windows.InvalidHandle
|
||||
defer func() {
|
||||
if h != windows.InvalidHandle {
|
||||
windows.FindCloseChangeNotification(h)
|
||||
}
|
||||
haveStartedWatchingConfigDir = false
|
||||
}()
|
||||
startover:
|
||||
configFileDir, err := tunnelConfigurationsDirectory()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
h, err = windows.FindFirstChangeNotification(configFileDir, true, windows.FILE_NOTIFY_CHANGE_FILE_NAME|windows.FILE_NOTIFY_CHANGE_DIR_NAME|windows.FILE_NOTIFY_CHANGE_ATTRIBUTES|windows.FILE_NOTIFY_CHANGE_SIZE|windows.FILE_NOTIFY_CHANGE_LAST_WRITE|windows.FILE_NOTIFY_CHANGE_LAST_ACCESS|windows.FILE_NOTIFY_CHANGE_CREATION|windows.FILE_NOTIFY_CHANGE_SECURITY)
|
||||
if err != nil {
|
||||
log.Printf("Unable to monitor config directory: %v", err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
s, err := windows.WaitForSingleObject(h, windows.INFINITE)
|
||||
if err != nil || s == windows.WAIT_FAILED {
|
||||
log.Printf("Unable to wait on config directory watcher: %v", err)
|
||||
windows.FindCloseChangeNotification(h)
|
||||
h = windows.InvalidHandle
|
||||
goto startover
|
||||
}
|
||||
|
||||
for cb := range storeCallbacks {
|
||||
cb.cb()
|
||||
}
|
||||
|
||||
err = windows.FindNextChangeNotification(h)
|
||||
if err != nil {
|
||||
log.Printf("Unable to monitor config directory again: %v", err)
|
||||
windows.FindCloseChangeNotification(h)
|
||||
h = windows.InvalidHandle
|
||||
goto startover
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
140
conf/writer.go
140
conf/writer.go
@@ -1,140 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wireguard/windows/driver"
|
||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||
)
|
||||
|
||||
func (conf *Config) ToWgQuick() string {
|
||||
var output strings.Builder
|
||||
output.WriteString("[Interface]\n")
|
||||
|
||||
output.WriteString(fmt.Sprintf("PrivateKey = %s\n", conf.Interface.PrivateKey.String()))
|
||||
|
||||
if conf.Interface.ListenPort > 0 {
|
||||
output.WriteString(fmt.Sprintf("ListenPort = %d\n", conf.Interface.ListenPort))
|
||||
}
|
||||
|
||||
if len(conf.Interface.Addresses) > 0 {
|
||||
addrStrings := make([]string, len(conf.Interface.Addresses))
|
||||
for i, address := range conf.Interface.Addresses {
|
||||
addrStrings[i] = address.String()
|
||||
}
|
||||
output.WriteString(fmt.Sprintf("Address = %s\n", strings.Join(addrStrings[:], ", ")))
|
||||
}
|
||||
|
||||
if len(conf.Interface.DNS)+len(conf.Interface.DNSSearch) > 0 {
|
||||
addrStrings := make([]string, 0, len(conf.Interface.DNS)+len(conf.Interface.DNSSearch))
|
||||
for _, address := range conf.Interface.DNS {
|
||||
addrStrings = append(addrStrings, address.String())
|
||||
}
|
||||
addrStrings = append(addrStrings, conf.Interface.DNSSearch...)
|
||||
output.WriteString(fmt.Sprintf("DNS = %s\n", strings.Join(addrStrings[:], ", ")))
|
||||
}
|
||||
|
||||
if conf.Interface.MTU > 0 {
|
||||
output.WriteString(fmt.Sprintf("MTU = %d\n", conf.Interface.MTU))
|
||||
}
|
||||
|
||||
if len(conf.Interface.PreUp) > 0 {
|
||||
output.WriteString(fmt.Sprintf("PreUp = %s\n", conf.Interface.PreUp))
|
||||
}
|
||||
if len(conf.Interface.PostUp) > 0 {
|
||||
output.WriteString(fmt.Sprintf("PostUp = %s\n", conf.Interface.PostUp))
|
||||
}
|
||||
if len(conf.Interface.PreDown) > 0 {
|
||||
output.WriteString(fmt.Sprintf("PreDown = %s\n", conf.Interface.PreDown))
|
||||
}
|
||||
if len(conf.Interface.PostDown) > 0 {
|
||||
output.WriteString(fmt.Sprintf("PostDown = %s\n", conf.Interface.PostDown))
|
||||
}
|
||||
if conf.Interface.TableOff {
|
||||
output.WriteString("Table = off\n")
|
||||
}
|
||||
|
||||
for _, peer := range conf.Peers {
|
||||
output.WriteString("\n[Peer]\n")
|
||||
|
||||
output.WriteString(fmt.Sprintf("PublicKey = %s\n", peer.PublicKey.String()))
|
||||
|
||||
if !peer.PresharedKey.IsZero() {
|
||||
output.WriteString(fmt.Sprintf("PresharedKey = %s\n", peer.PresharedKey.String()))
|
||||
}
|
||||
|
||||
if len(peer.AllowedIPs) > 0 {
|
||||
addrStrings := make([]string, len(peer.AllowedIPs))
|
||||
for i, address := range peer.AllowedIPs {
|
||||
addrStrings[i] = address.String()
|
||||
}
|
||||
output.WriteString(fmt.Sprintf("AllowedIPs = %s\n", strings.Join(addrStrings[:], ", ")))
|
||||
}
|
||||
|
||||
if !peer.Endpoint.IsEmpty() {
|
||||
output.WriteString(fmt.Sprintf("Endpoint = %s\n", peer.Endpoint.String()))
|
||||
}
|
||||
|
||||
if peer.PersistentKeepalive > 0 {
|
||||
output.WriteString(fmt.Sprintf("PersistentKeepalive = %d\n", peer.PersistentKeepalive))
|
||||
}
|
||||
}
|
||||
return output.String()
|
||||
}
|
||||
|
||||
func (config *Config) ToDriverConfiguration() (*driver.Interface, uint32) {
|
||||
preallocation := unsafe.Sizeof(driver.Interface{}) + uintptr(len(config.Peers))*unsafe.Sizeof(driver.Peer{})
|
||||
for i := range config.Peers {
|
||||
preallocation += uintptr(len(config.Peers[i].AllowedIPs)) * unsafe.Sizeof(driver.AllowedIP{})
|
||||
}
|
||||
var c driver.ConfigBuilder
|
||||
c.Preallocate(uint32(preallocation))
|
||||
c.AppendInterface(&driver.Interface{
|
||||
Flags: driver.InterfaceHasPrivateKey | driver.InterfaceHasListenPort,
|
||||
ListenPort: config.Interface.ListenPort,
|
||||
PrivateKey: config.Interface.PrivateKey,
|
||||
PeerCount: uint32(len(config.Peers)),
|
||||
})
|
||||
for i := range config.Peers {
|
||||
flags := driver.PeerHasPublicKey | driver.PeerHasPersistentKeepalive
|
||||
if !config.Peers[i].PresharedKey.IsZero() {
|
||||
flags |= driver.PeerHasPresharedKey
|
||||
}
|
||||
var endpoint winipcfg.RawSockaddrInet
|
||||
if !config.Peers[i].Endpoint.IsEmpty() {
|
||||
addr, err := netip.ParseAddr(config.Peers[i].Endpoint.Host)
|
||||
if err == nil {
|
||||
flags |= driver.PeerHasEndpoint
|
||||
endpoint.SetAddrPort(netip.AddrPortFrom(addr, config.Peers[i].Endpoint.Port))
|
||||
}
|
||||
}
|
||||
c.AppendPeer(&driver.Peer{
|
||||
Flags: flags,
|
||||
PublicKey: config.Peers[i].PublicKey,
|
||||
PresharedKey: config.Peers[i].PresharedKey,
|
||||
PersistentKeepalive: config.Peers[i].PersistentKeepalive,
|
||||
Endpoint: endpoint,
|
||||
AllowedIPsCount: uint32(len(config.Peers[i].AllowedIPs)),
|
||||
})
|
||||
for j := range config.Peers[i].AllowedIPs {
|
||||
a := &driver.AllowedIP{Cidr: uint8(config.Peers[i].AllowedIPs[j].Bits())}
|
||||
copy(a.Address[:], config.Peers[i].AllowedIPs[j].Addr().AsSlice())
|
||||
if config.Peers[i].AllowedIPs[j].Addr().Is4() {
|
||||
a.AddressFamily = windows.AF_INET
|
||||
} else if config.Peers[i].AllowedIPs[j].Addr().Is6() {
|
||||
a.AddressFamily = windows.AF_INET6
|
||||
}
|
||||
c.AppendAllowedIP(a)
|
||||
}
|
||||
}
|
||||
return c.Interface()
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package driver
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||
)
|
||||
|
||||
type AdapterState uint32
|
||||
|
||||
const (
|
||||
AdapterStateDown AdapterState = 0
|
||||
AdapterStateUp AdapterState = 1
|
||||
)
|
||||
|
||||
type AllowedIP struct {
|
||||
Address [16]byte
|
||||
AddressFamily winipcfg.AddressFamily
|
||||
Cidr uint8
|
||||
_ [4]byte
|
||||
}
|
||||
|
||||
type PeerFlag uint32
|
||||
|
||||
const (
|
||||
PeerHasPublicKey PeerFlag = 1 << 0
|
||||
PeerHasPresharedKey PeerFlag = 1 << 1
|
||||
PeerHasPersistentKeepalive PeerFlag = 1 << 2
|
||||
PeerHasEndpoint PeerFlag = 1 << 3
|
||||
PeerReplaceAllowedIPs PeerFlag = 1 << 5
|
||||
PeerRemove PeerFlag = 1 << 6
|
||||
PeerUpdateOnly PeerFlag = 1 << 7
|
||||
)
|
||||
|
||||
type Peer struct {
|
||||
Flags PeerFlag
|
||||
_ uint32
|
||||
PublicKey [32]byte
|
||||
PresharedKey [32]byte
|
||||
PersistentKeepalive uint16
|
||||
_ uint16
|
||||
Endpoint winipcfg.RawSockaddrInet
|
||||
TxBytes uint64
|
||||
RxBytes uint64
|
||||
LastHandshake uint64
|
||||
AllowedIPsCount uint32
|
||||
_ [4]byte
|
||||
}
|
||||
|
||||
type InterfaceFlag uint32
|
||||
|
||||
const (
|
||||
InterfaceHasPublicKey InterfaceFlag = 1 << 0
|
||||
InterfaceHasPrivateKey InterfaceFlag = 1 << 1
|
||||
InterfaceHasListenPort InterfaceFlag = 1 << 2
|
||||
InterfaceReplacePeers InterfaceFlag = 1 << 3
|
||||
)
|
||||
|
||||
type Interface struct {
|
||||
Flags InterfaceFlag
|
||||
ListenPort uint16
|
||||
PrivateKey [32]byte
|
||||
PublicKey [32]byte
|
||||
PeerCount uint32
|
||||
_ [4]byte
|
||||
}
|
||||
|
||||
var (
|
||||
procWireGuardSetAdapterState = modwireguard.NewProc("WireGuardSetAdapterState")
|
||||
procWireGuardGetAdapterState = modwireguard.NewProc("WireGuardGetAdapterState")
|
||||
procWireGuardSetConfiguration = modwireguard.NewProc("WireGuardSetConfiguration")
|
||||
procWireGuardGetConfiguration = modwireguard.NewProc("WireGuardGetConfiguration")
|
||||
)
|
||||
|
||||
// SetAdapterState sets the adapter either Up or Down.
|
||||
func (wireguard *Adapter) SetAdapterState(adapterState AdapterState) (err error) {
|
||||
r0, _, e1 := syscall.SyscallN(procWireGuardSetAdapterState.Addr(), wireguard.handle, uintptr(adapterState))
|
||||
if r0 == 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// AdapterState returns the current state of the adapter.
|
||||
func (wireguard *Adapter) AdapterState() (adapterState AdapterState, err error) {
|
||||
r0, _, e1 := syscall.SyscallN(procWireGuardGetAdapterState.Addr(), wireguard.handle, uintptr(unsafe.Pointer(&adapterState)))
|
||||
if r0 == 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetConfiguration sets the adapter configuration.
|
||||
func (wireguard *Adapter) SetConfiguration(interfaze *Interface, size uint32) (err error) {
|
||||
r0, _, e1 := syscall.SyscallN(procWireGuardSetConfiguration.Addr(), wireguard.handle, uintptr(unsafe.Pointer(interfaze)), uintptr(size))
|
||||
if r0 == 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Configuration gets the adapter configuration.
|
||||
func (wireguard *Adapter) Configuration() (interfaze *Interface, err error) {
|
||||
size := wireguard.lastGetGuessSize
|
||||
if size == 0 {
|
||||
size = 512
|
||||
}
|
||||
for {
|
||||
buf := make([]byte, size)
|
||||
r0, _, e1 := syscall.SyscallN(procWireGuardGetConfiguration.Addr(), wireguard.handle, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&size)))
|
||||
if r0 != 0 {
|
||||
wireguard.lastGetGuessSize = size
|
||||
return (*Interface)(unsafe.Pointer(&buf[0])), nil
|
||||
}
|
||||
if e1 != windows.ERROR_MORE_DATA {
|
||||
return nil, e1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FirstPeer returns the first peer attached to the interface.
|
||||
func (interfaze *Interface) FirstPeer() *Peer {
|
||||
return (*Peer)(unsafe.Add(unsafe.Pointer(interfaze), unsafe.Sizeof(*interfaze)))
|
||||
}
|
||||
|
||||
// NextPeer returns the subsequent peer of the current one.
|
||||
func (peer *Peer) NextPeer() *Peer {
|
||||
return (*Peer)(unsafe.Pointer(uintptr(unsafe.Pointer(peer)) + unsafe.Sizeof(*peer) + uintptr(peer.AllowedIPsCount)*unsafe.Sizeof(AllowedIP{})))
|
||||
}
|
||||
|
||||
// FirstAllowedIP returns the first allowed IP attached to the peer.
|
||||
func (peer *Peer) FirstAllowedIP() *AllowedIP {
|
||||
return (*AllowedIP)(unsafe.Add(unsafe.Pointer(peer), unsafe.Sizeof(*peer)))
|
||||
}
|
||||
|
||||
// NextAllowedIP returns the subsequent allowed IP of the current one.
|
||||
func (allowedIP *AllowedIP) NextAllowedIP() *AllowedIP {
|
||||
return (*AllowedIP)(unsafe.Add(unsafe.Pointer(allowedIP), unsafe.Sizeof(*allowedIP)))
|
||||
}
|
||||
|
||||
type ConfigBuilder struct {
|
||||
buffer []byte
|
||||
}
|
||||
|
||||
// Preallocate reserves memory in the config builder to reduce allocations of append operations.
|
||||
func (builder *ConfigBuilder) Preallocate(size uint32) {
|
||||
if builder.buffer == nil {
|
||||
builder.buffer = make([]byte, 0, size)
|
||||
}
|
||||
}
|
||||
|
||||
// AppendInterface appends an interface to the building configuration. This should be called first.
|
||||
func (builder *ConfigBuilder) AppendInterface(interfaze *Interface) {
|
||||
newBytes := unsafe.Slice((*byte)(unsafe.Pointer(interfaze)), unsafe.Sizeof(*interfaze))
|
||||
builder.buffer = append(builder.buffer, newBytes...)
|
||||
}
|
||||
|
||||
// AppendPeer appends a peer to the building configuration. This should be called after an interface has been added.
|
||||
func (builder *ConfigBuilder) AppendPeer(peer *Peer) {
|
||||
newBytes := unsafe.Slice((*byte)(unsafe.Pointer(peer)), unsafe.Sizeof(*peer))
|
||||
builder.buffer = append(builder.buffer, newBytes...)
|
||||
}
|
||||
|
||||
// AppendAllowedIP appends an allowed IP to the building configuration. This should be called after a peer has been added.
|
||||
func (builder *ConfigBuilder) AppendAllowedIP(allowedIP *AllowedIP) {
|
||||
newBytes := unsafe.Slice((*byte)(unsafe.Pointer(allowedIP)), unsafe.Sizeof(*allowedIP))
|
||||
builder.buffer = append(builder.buffer, newBytes...)
|
||||
}
|
||||
|
||||
// Interface assembles the configuration and returns the interface and length to be passed to SetConfiguration.
|
||||
func (builder *ConfigBuilder) Interface() (*Interface, uint32) {
|
||||
if builder.buffer == nil {
|
||||
return nil, 0
|
||||
}
|
||||
return (*Interface)(unsafe.Pointer(&builder.buffer[0])), uint32(len(builder.buffer))
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
//go:build !load_wgnt_from_rsrc
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package driver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type lazyDLL struct {
|
||||
Name string
|
||||
Base windows.Handle
|
||||
mu sync.Mutex
|
||||
module windows.Handle
|
||||
onLoad func(d *lazyDLL)
|
||||
}
|
||||
|
||||
func (d *lazyDLL) Load() error {
|
||||
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.module))) != nil {
|
||||
return nil
|
||||
}
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if d.module != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200
|
||||
LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
|
||||
)
|
||||
module, err := windows.LoadLibraryEx(d.Name, 0, LOAD_LIBRARY_SEARCH_APPLICATION_DIR|LOAD_LIBRARY_SEARCH_SYSTEM32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to load library: %w", err)
|
||||
}
|
||||
d.Base = module
|
||||
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.module)), unsafe.Pointer(module))
|
||||
if d.onLoad != nil {
|
||||
d.onLoad(d)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *lazyProc) nameToAddr() (uintptr, error) {
|
||||
return windows.GetProcAddress(p.dll.module, p.Name)
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
//go:build load_wgnt_from_rsrc
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package driver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wireguard/windows/driver/memmod"
|
||||
)
|
||||
|
||||
type lazyDLL struct {
|
||||
Name string
|
||||
Base windows.Handle
|
||||
mu sync.Mutex
|
||||
module *memmod.Module
|
||||
onLoad func(d *lazyDLL)
|
||||
}
|
||||
|
||||
func (d *lazyDLL) Load() error {
|
||||
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.module))) != nil {
|
||||
return nil
|
||||
}
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if d.module != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
const ourModule windows.Handle = 0
|
||||
resInfo, err := windows.FindResource(ourModule, d.Name, windows.RT_RCDATA)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to find \"%v\" RCDATA resource: %w", d.Name, err)
|
||||
}
|
||||
data, err := windows.LoadResourceData(ourModule, resInfo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to load resource: %w", err)
|
||||
}
|
||||
module, err := memmod.LoadLibrary(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to load library: %w", err)
|
||||
}
|
||||
d.Base = windows.Handle(module.BaseAddr())
|
||||
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.module)), unsafe.Pointer(module))
|
||||
if d.onLoad != nil {
|
||||
d.onLoad(d)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *lazyProc) nameToAddr() (uintptr, error) {
|
||||
return p.dll.module.ProcAddressByName(p.Name)
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package driver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func newLazyDLL(name string, onLoad func(d *lazyDLL)) *lazyDLL {
|
||||
return &lazyDLL{Name: name, onLoad: onLoad}
|
||||
}
|
||||
|
||||
func (d *lazyDLL) NewProc(name string) *lazyProc {
|
||||
return &lazyProc{dll: d, Name: name}
|
||||
}
|
||||
|
||||
type lazyProc struct {
|
||||
Name string
|
||||
mu sync.Mutex
|
||||
dll *lazyDLL
|
||||
addr uintptr
|
||||
}
|
||||
|
||||
func (p *lazyProc) Find() error {
|
||||
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.addr))) != nil {
|
||||
return nil
|
||||
}
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
if p.addr != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := p.dll.Load()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error loading %v DLL: %w", p.dll.Name, err)
|
||||
}
|
||||
addr, err := p.nameToAddr()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error getting %v address: %w", p.Name, err)
|
||||
}
|
||||
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.addr)), unsafe.Pointer(addr))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *lazyProc) Addr() uintptr {
|
||||
err := p.Find()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return p.addr
|
||||
}
|
||||
|
||||
// Version returns the version of the driver DLL.
|
||||
func Version() string {
|
||||
if modwireguard.Load() != nil {
|
||||
return "unknown"
|
||||
}
|
||||
resInfo, err := windows.FindResource(modwireguard.Base, windows.ResourceID(1), windows.RT_VERSION)
|
||||
if err != nil {
|
||||
return "unknown"
|
||||
}
|
||||
data, err := windows.LoadResourceData(modwireguard.Base, resInfo)
|
||||
if err != nil {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
var fixedInfo *windows.VS_FIXEDFILEINFO
|
||||
fixedInfoLen := uint32(unsafe.Sizeof(*fixedInfo))
|
||||
err = windows.VerQueryValue(unsafe.Pointer(&data[0]), `\`, unsafe.Pointer(&fixedInfo), &fixedInfoLen)
|
||||
if err != nil {
|
||||
return "unknown"
|
||||
}
|
||||
version := fmt.Sprintf("%d.%d", (fixedInfo.FileVersionMS>>16)&0xff, (fixedInfo.FileVersionMS>>0)&0xff)
|
||||
if nextNibble := (fixedInfo.FileVersionLS >> 16) & 0xff; nextNibble != 0 {
|
||||
version += fmt.Sprintf(".%d", nextNibble)
|
||||
}
|
||||
if nextNibble := (fixedInfo.FileVersionLS >> 0) & 0xff; nextNibble != 0 {
|
||||
version += fmt.Sprintf(".%d", nextNibble)
|
||||
}
|
||||
return version
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package driver
|
||||
|
||||
import (
|
||||
"log"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||
)
|
||||
|
||||
type loggerLevel int
|
||||
|
||||
const (
|
||||
logInfo loggerLevel = iota
|
||||
logWarn
|
||||
logErr
|
||||
)
|
||||
|
||||
const AdapterNameMax = 128
|
||||
|
||||
type Adapter struct {
|
||||
handle uintptr
|
||||
lastGetGuessSize uint32
|
||||
}
|
||||
|
||||
var (
|
||||
modwireguard = newLazyDLL("wireguard.dll", setupLogger)
|
||||
procWireGuardCreateAdapter = modwireguard.NewProc("WireGuardCreateAdapter")
|
||||
procWireGuardOpenAdapter = modwireguard.NewProc("WireGuardOpenAdapter")
|
||||
procWireGuardCloseAdapter = modwireguard.NewProc("WireGuardCloseAdapter")
|
||||
procWireGuardDeleteDriver = modwireguard.NewProc("WireGuardDeleteDriver")
|
||||
procWireGuardGetAdapterLUID = modwireguard.NewProc("WireGuardGetAdapterLUID")
|
||||
procWireGuardGetRunningDriverVersion = modwireguard.NewProc("WireGuardGetRunningDriverVersion")
|
||||
procWireGuardSetAdapterLogging = modwireguard.NewProc("WireGuardSetAdapterLogging")
|
||||
)
|
||||
|
||||
type TimestampedWriter interface {
|
||||
WriteWithTimestamp(p []byte, ts int64) (n int, err error)
|
||||
}
|
||||
|
||||
func logMessage(level loggerLevel, timestamp uint64, msg *uint16) int {
|
||||
if tw, ok := log.Default().Writer().(TimestampedWriter); ok {
|
||||
tw.WriteWithTimestamp([]byte(log.Default().Prefix()+windows.UTF16PtrToString(msg)), (int64(timestamp)-116444736000000000)*100)
|
||||
} else {
|
||||
log.Println(windows.UTF16PtrToString(msg))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func setupLogger(dll *lazyDLL) {
|
||||
var callback uintptr
|
||||
if runtime.GOARCH == "386" {
|
||||
callback = windows.NewCallback(func(level loggerLevel, timestampLow, timestampHigh uint32, msg *uint16) int {
|
||||
return logMessage(level, uint64(timestampHigh)<<32|uint64(timestampLow), msg)
|
||||
})
|
||||
} else if runtime.GOARCH == "arm" {
|
||||
callback = windows.NewCallback(func(level loggerLevel, _, timestampLow, timestampHigh uint32, msg *uint16) int {
|
||||
return logMessage(level, uint64(timestampHigh)<<32|uint64(timestampLow), msg)
|
||||
})
|
||||
} else if runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64" {
|
||||
callback = windows.NewCallback(logMessage)
|
||||
}
|
||||
syscall.SyscallN(dll.NewProc("WireGuardSetLogger").Addr(), callback)
|
||||
}
|
||||
|
||||
func closeAdapter(wireguard *Adapter) {
|
||||
syscall.SyscallN(procWireGuardCloseAdapter.Addr(), wireguard.handle)
|
||||
}
|
||||
|
||||
// CreateAdapter creates a WireGuard adapter. name is the cosmetic name of the adapter.
|
||||
// tunnelType represents the type of adapter and should be "WireGuard". requestedGUID is
|
||||
// the GUID of the created network adapter, which then influences NLA generation
|
||||
// deterministically. If it is set to nil, the GUID is chosen by the system at random,
|
||||
// and hence a new NLA entry is created for each new adapter.
|
||||
func CreateAdapter(name, tunnelType string, requestedGUID *windows.GUID) (wireguard *Adapter, err error) {
|
||||
var name16 *uint16
|
||||
name16, err = windows.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var tunnelType16 *uint16
|
||||
tunnelType16, err = windows.UTF16PtrFromString(tunnelType)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := syscall.SyscallN(procWireGuardCreateAdapter.Addr(), uintptr(unsafe.Pointer(name16)), uintptr(unsafe.Pointer(tunnelType16)), uintptr(unsafe.Pointer(requestedGUID)))
|
||||
if r0 == 0 {
|
||||
err = e1
|
||||
return
|
||||
}
|
||||
wireguard = &Adapter{handle: r0}
|
||||
runtime.SetFinalizer(wireguard, closeAdapter)
|
||||
return
|
||||
}
|
||||
|
||||
// OpenAdapter opens an existing WireGuard adapter by name.
|
||||
func OpenAdapter(name string) (wireguard *Adapter, err error) {
|
||||
var name16 *uint16
|
||||
name16, err = windows.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := syscall.SyscallN(procWireGuardOpenAdapter.Addr(), uintptr(unsafe.Pointer(name16)))
|
||||
if r0 == 0 {
|
||||
err = e1
|
||||
return
|
||||
}
|
||||
wireguard = &Adapter{handle: r0}
|
||||
runtime.SetFinalizer(wireguard, closeAdapter)
|
||||
return
|
||||
}
|
||||
|
||||
// Close closes a WireGuard adapter.
|
||||
func (wireguard *Adapter) Close() (err error) {
|
||||
runtime.SetFinalizer(wireguard, nil)
|
||||
r1, _, e1 := syscall.SyscallN(procWireGuardCloseAdapter.Addr(), wireguard.handle)
|
||||
if r1 == 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Uninstall removes the driver from the system if no drivers are currently in use.
|
||||
func Uninstall() (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procWireGuardDeleteDriver.Addr())
|
||||
if r1 == 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type AdapterLogState uint32
|
||||
|
||||
const (
|
||||
AdapterLogOff AdapterLogState = 0
|
||||
AdapterLogOn AdapterLogState = 1
|
||||
AdapterLogOnWithPrefix AdapterLogState = 2
|
||||
)
|
||||
|
||||
// SetLogging enables or disables logging on the WireGuard adapter.
|
||||
func (wireguard *Adapter) SetLogging(logState AdapterLogState) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procWireGuardSetAdapterLogging.Addr(), wireguard.handle, uintptr(logState))
|
||||
if r1 == 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RunningVersion returns the version of the loaded driver.
|
||||
func RunningVersion() (version uint32, err error) {
|
||||
r0, _, e1 := syscall.SyscallN(procWireGuardGetRunningDriverVersion.Addr())
|
||||
version = uint32(r0)
|
||||
if version == 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// LUID returns the LUID of the adapter.
|
||||
func (wireguard *Adapter) LUID() (luid winipcfg.LUID) {
|
||||
syscall.SyscallN(procWireGuardGetAdapterLUID.Addr(), wireguard.handle, uintptr(unsafe.Pointer(&luid)))
|
||||
return
|
||||
}
|
||||
@@ -1,698 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package memmod
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type addressList struct {
|
||||
next *addressList
|
||||
address uintptr
|
||||
}
|
||||
|
||||
func (head *addressList) free() {
|
||||
for node := head; node != nil; node = node.next {
|
||||
windows.VirtualFree(node.address, 0, windows.MEM_RELEASE)
|
||||
}
|
||||
}
|
||||
|
||||
type Module struct {
|
||||
headers *IMAGE_NT_HEADERS
|
||||
codeBase uintptr
|
||||
modules []windows.Handle
|
||||
initialized bool
|
||||
isDLL bool
|
||||
isRelocated bool
|
||||
nameExports map[string]uint16
|
||||
entry uintptr
|
||||
blockedMemory *addressList
|
||||
}
|
||||
|
||||
func (module *Module) BaseAddr() uintptr {
|
||||
return module.codeBase
|
||||
}
|
||||
|
||||
func (module *Module) headerDirectory(idx int) *IMAGE_DATA_DIRECTORY {
|
||||
return &module.headers.OptionalHeader.DataDirectory[idx]
|
||||
}
|
||||
|
||||
func (module *Module) copySections(address, size uintptr, oldHeaders *IMAGE_NT_HEADERS) error {
|
||||
sections := module.headers.Sections()
|
||||
for i := range sections {
|
||||
if sections[i].SizeOfRawData == 0 {
|
||||
// Section doesn't contain data in the dll itself, but may define uninitialized data.
|
||||
sectionSize := oldHeaders.OptionalHeader.SectionAlignment
|
||||
if sectionSize == 0 {
|
||||
continue
|
||||
}
|
||||
dest, err := windows.VirtualAlloc(module.codeBase+uintptr(sections[i].VirtualAddress),
|
||||
uintptr(sectionSize),
|
||||
windows.MEM_COMMIT,
|
||||
windows.PAGE_READWRITE)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error allocating section: %w", err)
|
||||
}
|
||||
|
||||
// Always use position from file to support alignments smaller than page size (allocation above will align to page size).
|
||||
dest = module.codeBase + uintptr(sections[i].VirtualAddress)
|
||||
// NOTE: On 64bit systems we truncate to 32bit here but expand again later when "PhysicalAddress" is used.
|
||||
sections[i].SetPhysicalAddress((uint32)(dest & 0xffffffff))
|
||||
dst := unsafe.Slice((*byte)(a2p(dest)), sectionSize)
|
||||
for j := range dst {
|
||||
dst[j] = 0
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if size < uintptr(sections[i].PointerToRawData+sections[i].SizeOfRawData) {
|
||||
return errors.New("Incomplete section")
|
||||
}
|
||||
|
||||
// Commit memory block and copy data from dll.
|
||||
dest, err := windows.VirtualAlloc(module.codeBase+uintptr(sections[i].VirtualAddress),
|
||||
uintptr(sections[i].SizeOfRawData),
|
||||
windows.MEM_COMMIT,
|
||||
windows.PAGE_READWRITE)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error allocating memory block: %w", err)
|
||||
}
|
||||
|
||||
// Always use position from file to support alignments smaller than page size (allocation above will align to page size).
|
||||
memcpy(
|
||||
module.codeBase+uintptr(sections[i].VirtualAddress),
|
||||
address+uintptr(sections[i].PointerToRawData),
|
||||
uintptr(sections[i].SizeOfRawData))
|
||||
// NOTE: On 64bit systems we truncate to 32bit here but expand again later when "PhysicalAddress" is used.
|
||||
sections[i].SetPhysicalAddress((uint32)(dest & 0xffffffff))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (module *Module) realSectionSize(section *IMAGE_SECTION_HEADER) uintptr {
|
||||
size := section.SizeOfRawData
|
||||
if size != 0 {
|
||||
return uintptr(size)
|
||||
}
|
||||
if (section.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) != 0 {
|
||||
return uintptr(module.headers.OptionalHeader.SizeOfInitializedData)
|
||||
}
|
||||
if (section.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0 {
|
||||
return uintptr(module.headers.OptionalHeader.SizeOfUninitializedData)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type sectionFinalizeData struct {
|
||||
address uintptr
|
||||
alignedAddress uintptr
|
||||
size uintptr
|
||||
characteristics uint32
|
||||
last bool
|
||||
}
|
||||
|
||||
func (module *Module) finalizeSection(sectionData *sectionFinalizeData) error {
|
||||
if sectionData.size == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if (sectionData.characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0 {
|
||||
// Section is not needed any more and can safely be freed.
|
||||
if sectionData.address == sectionData.alignedAddress &&
|
||||
(sectionData.last ||
|
||||
(sectionData.size%uintptr(module.headers.OptionalHeader.SectionAlignment)) == 0) {
|
||||
// Only allowed to decommit whole pages.
|
||||
windows.VirtualFree(sectionData.address, sectionData.size, windows.MEM_DECOMMIT)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// determine protection flags based on characteristics
|
||||
ProtectionFlags := [8]uint32{
|
||||
windows.PAGE_NOACCESS, // not writeable, not readable, not executable
|
||||
windows.PAGE_EXECUTE, // not writeable, not readable, executable
|
||||
windows.PAGE_READONLY, // not writeable, readable, not executable
|
||||
windows.PAGE_EXECUTE_READ, // not writeable, readable, executable
|
||||
windows.PAGE_WRITECOPY, // writeable, not readable, not executable
|
||||
windows.PAGE_EXECUTE_WRITECOPY, // writeable, not readable, executable
|
||||
windows.PAGE_READWRITE, // writeable, readable, not executable
|
||||
windows.PAGE_EXECUTE_READWRITE, // writeable, readable, executable
|
||||
}
|
||||
protect := ProtectionFlags[sectionData.characteristics>>29]
|
||||
if (sectionData.characteristics & IMAGE_SCN_MEM_NOT_CACHED) != 0 {
|
||||
protect |= windows.PAGE_NOCACHE
|
||||
}
|
||||
|
||||
// Change memory access flags.
|
||||
var oldProtect uint32
|
||||
err := windows.VirtualProtect(sectionData.address, sectionData.size, protect, &oldProtect)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error protecting memory page: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (module *Module) registerExceptionHandlers() {
|
||||
directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_EXCEPTION)
|
||||
if directory.Size == 0 || directory.VirtualAddress == 0 {
|
||||
return
|
||||
}
|
||||
runtimeFuncs := (*windows.RUNTIME_FUNCTION)(unsafe.Pointer(module.codeBase + uintptr(directory.VirtualAddress)))
|
||||
windows.RtlAddFunctionTable(runtimeFuncs, uint32(uintptr(directory.Size)/unsafe.Sizeof(*runtimeFuncs)), module.codeBase)
|
||||
}
|
||||
|
||||
func (module *Module) finalizeSections() error {
|
||||
sections := module.headers.Sections()
|
||||
imageOffset := module.headers.OptionalHeader.imageOffset()
|
||||
sectionData := sectionFinalizeData{}
|
||||
sectionData.address = uintptr(sections[0].PhysicalAddress()) | imageOffset
|
||||
sectionData.alignedAddress = alignDown(sectionData.address, uintptr(module.headers.OptionalHeader.SectionAlignment))
|
||||
sectionData.size = module.realSectionSize(§ions[0])
|
||||
sections[0].SetVirtualSize(uint32(sectionData.size))
|
||||
sectionData.characteristics = sections[0].Characteristics
|
||||
|
||||
// Loop through all sections and change access flags.
|
||||
for i := uint16(1); i < module.headers.FileHeader.NumberOfSections; i++ {
|
||||
sectionAddress := uintptr(sections[i].PhysicalAddress()) | imageOffset
|
||||
alignedAddress := alignDown(sectionAddress, uintptr(module.headers.OptionalHeader.SectionAlignment))
|
||||
sectionSize := module.realSectionSize(§ions[i])
|
||||
sections[i].SetVirtualSize(uint32(sectionSize))
|
||||
// Combine access flags of all sections that share a page.
|
||||
// TODO: We currently share flags of a trailing large section with the page of a first small section. This should be optimized.
|
||||
if sectionData.alignedAddress == alignedAddress || sectionData.address+sectionData.size > alignedAddress {
|
||||
// Section shares page with previous.
|
||||
if (sections[i].Characteristics&IMAGE_SCN_MEM_DISCARDABLE) == 0 || (sectionData.characteristics&IMAGE_SCN_MEM_DISCARDABLE) == 0 {
|
||||
sectionData.characteristics = (sectionData.characteristics | sections[i].Characteristics) &^ IMAGE_SCN_MEM_DISCARDABLE
|
||||
} else {
|
||||
sectionData.characteristics |= sections[i].Characteristics
|
||||
}
|
||||
sectionData.size = sectionAddress + sectionSize - sectionData.address
|
||||
continue
|
||||
}
|
||||
|
||||
err := module.finalizeSection(§ionData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error finalizing section: %w", err)
|
||||
}
|
||||
sectionData.address = sectionAddress
|
||||
sectionData.alignedAddress = alignedAddress
|
||||
sectionData.size = sectionSize
|
||||
sectionData.characteristics = sections[i].Characteristics
|
||||
}
|
||||
sectionData.last = true
|
||||
err := module.finalizeSection(§ionData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error finalizing section: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (module *Module) executeTLS() {
|
||||
directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_TLS)
|
||||
if directory.VirtualAddress == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
tls := (*IMAGE_TLS_DIRECTORY)(a2p(module.codeBase + uintptr(directory.VirtualAddress)))
|
||||
callback := tls.AddressOfCallbacks
|
||||
if callback != 0 {
|
||||
for {
|
||||
f := *(*uintptr)(a2p(callback))
|
||||
if f == 0 {
|
||||
break
|
||||
}
|
||||
syscall.SyscallN(f, module.codeBase, DLL_PROCESS_ATTACH, 0)
|
||||
callback += unsafe.Sizeof(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (module *Module) performBaseRelocation(delta uintptr) (relocated bool, err error) {
|
||||
directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_BASERELOC)
|
||||
if directory.Size == 0 {
|
||||
return delta == 0, nil
|
||||
}
|
||||
|
||||
relocationHdr := (*IMAGE_BASE_RELOCATION)(a2p(module.codeBase + uintptr(directory.VirtualAddress)))
|
||||
for relocationHdr.VirtualAddress > 0 {
|
||||
dest := module.codeBase + uintptr(relocationHdr.VirtualAddress)
|
||||
|
||||
relInfos := unsafe.Slice(
|
||||
(*uint16)(a2p(uintptr(unsafe.Pointer(relocationHdr))+unsafe.Sizeof(*relocationHdr))),
|
||||
(uintptr(relocationHdr.SizeOfBlock)-unsafe.Sizeof(*relocationHdr))/unsafe.Sizeof(uint16(0)))
|
||||
for _, relInfo := range relInfos {
|
||||
// The upper 4 bits define the type of relocation.
|
||||
relType := relInfo >> 12
|
||||
// The lower 12 bits define the offset.
|
||||
relOffset := uintptr(relInfo & 0xfff)
|
||||
|
||||
switch relType {
|
||||
case IMAGE_REL_BASED_ABSOLUTE:
|
||||
// Skip relocation.
|
||||
|
||||
case IMAGE_REL_BASED_LOW:
|
||||
*(*uint16)(a2p(dest + relOffset)) += uint16(delta & 0xffff)
|
||||
break
|
||||
|
||||
case IMAGE_REL_BASED_HIGH:
|
||||
*(*uint16)(a2p(dest + relOffset)) += uint16(uint32(delta) >> 16)
|
||||
break
|
||||
|
||||
case IMAGE_REL_BASED_HIGHLOW:
|
||||
*(*uint32)(a2p(dest + relOffset)) += uint32(delta)
|
||||
|
||||
case IMAGE_REL_BASED_DIR64:
|
||||
*(*uint64)(a2p(dest + relOffset)) += uint64(delta)
|
||||
|
||||
case IMAGE_REL_BASED_THUMB_MOV32:
|
||||
inst := *(*uint32)(a2p(dest + relOffset))
|
||||
imm16 := ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) +
|
||||
((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff)
|
||||
if (inst & 0x8000fbf0) != 0x0000f240 {
|
||||
return false, fmt.Errorf("Wrong Thumb2 instruction %08x, expected MOVW", inst)
|
||||
}
|
||||
imm16 += uint32(delta) & 0xffff
|
||||
hiDelta := (uint32(delta&0xffff0000) >> 16) + ((imm16 & 0xffff0000) >> 16)
|
||||
*(*uint32)(a2p(dest + relOffset)) = (inst & 0x8f00fbf0) + ((imm16 >> 1) & 0x0400) +
|
||||
((imm16 >> 12) & 0x000f) +
|
||||
((imm16 << 20) & 0x70000000) +
|
||||
((imm16 << 16) & 0xff0000)
|
||||
if hiDelta != 0 {
|
||||
inst = *(*uint32)(a2p(dest + relOffset + 4))
|
||||
imm16 = ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) +
|
||||
((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff)
|
||||
if (inst & 0x8000fbf0) != 0x0000f2c0 {
|
||||
return false, fmt.Errorf("Wrong Thumb2 instruction %08x, expected MOVT", inst)
|
||||
}
|
||||
imm16 += hiDelta
|
||||
if imm16 > 0xffff {
|
||||
return false, fmt.Errorf("Resulting immediate value won't fit: %08x", imm16)
|
||||
}
|
||||
*(*uint32)(a2p(dest + relOffset + 4)) = (inst & 0x8f00fbf0) +
|
||||
((imm16 >> 1) & 0x0400) +
|
||||
((imm16 >> 12) & 0x000f) +
|
||||
((imm16 << 20) & 0x70000000) +
|
||||
((imm16 << 16) & 0xff0000)
|
||||
}
|
||||
|
||||
default:
|
||||
return false, fmt.Errorf("Unsupported relocation: %v", relType)
|
||||
}
|
||||
}
|
||||
|
||||
// Advance to next relocation block.
|
||||
relocationHdr = (*IMAGE_BASE_RELOCATION)(a2p(uintptr(unsafe.Pointer(relocationHdr)) + uintptr(relocationHdr.SizeOfBlock)))
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (module *Module) buildImportTable() error {
|
||||
directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_IMPORT)
|
||||
if directory.Size == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
module.modules = make([]windows.Handle, 0, 16)
|
||||
importDesc := (*IMAGE_IMPORT_DESCRIPTOR)(a2p(module.codeBase + uintptr(directory.VirtualAddress)))
|
||||
for importDesc.Name != 0 {
|
||||
handle, err := windows.LoadLibraryEx(windows.BytePtrToString((*byte)(a2p(module.codeBase+uintptr(importDesc.Name)))), 0, windows.LOAD_LIBRARY_SEARCH_SYSTEM32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error loading module: %w", err)
|
||||
}
|
||||
var thunkRef, funcRef *uintptr
|
||||
if importDesc.OriginalFirstThunk() != 0 {
|
||||
thunkRef = (*uintptr)(a2p(module.codeBase + uintptr(importDesc.OriginalFirstThunk())))
|
||||
funcRef = (*uintptr)(a2p(module.codeBase + uintptr(importDesc.FirstThunk)))
|
||||
} else {
|
||||
// No hint table.
|
||||
thunkRef = (*uintptr)(a2p(module.codeBase + uintptr(importDesc.FirstThunk)))
|
||||
funcRef = (*uintptr)(a2p(module.codeBase + uintptr(importDesc.FirstThunk)))
|
||||
}
|
||||
for *thunkRef != 0 {
|
||||
if IMAGE_SNAP_BY_ORDINAL(*thunkRef) {
|
||||
*funcRef, err = windows.GetProcAddressByOrdinal(handle, IMAGE_ORDINAL(*thunkRef))
|
||||
} else {
|
||||
thunkData := (*IMAGE_IMPORT_BY_NAME)(a2p(module.codeBase + *thunkRef))
|
||||
*funcRef, err = windows.GetProcAddress(handle, windows.BytePtrToString(&thunkData.Name[0]))
|
||||
}
|
||||
if err != nil {
|
||||
windows.FreeLibrary(handle)
|
||||
return fmt.Errorf("Error getting function address: %w", err)
|
||||
}
|
||||
thunkRef = (*uintptr)(a2p(uintptr(unsafe.Pointer(thunkRef)) + unsafe.Sizeof(*thunkRef)))
|
||||
funcRef = (*uintptr)(a2p(uintptr(unsafe.Pointer(funcRef)) + unsafe.Sizeof(*funcRef)))
|
||||
}
|
||||
module.modules = append(module.modules, handle)
|
||||
importDesc = (*IMAGE_IMPORT_DESCRIPTOR)(a2p(uintptr(unsafe.Pointer(importDesc)) + unsafe.Sizeof(*importDesc)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (module *Module) buildNameExports() error {
|
||||
directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT)
|
||||
if directory.Size == 0 {
|
||||
return errors.New("No export table found")
|
||||
}
|
||||
exports := (*IMAGE_EXPORT_DIRECTORY)(a2p(module.codeBase + uintptr(directory.VirtualAddress)))
|
||||
if exports.NumberOfNames == 0 || exports.NumberOfFunctions == 0 {
|
||||
return errors.New("No functions exported")
|
||||
}
|
||||
if exports.NumberOfNames == 0 {
|
||||
return errors.New("No functions exported by name")
|
||||
}
|
||||
nameRefs := unsafe.Slice((*uint32)(a2p(module.codeBase+uintptr(exports.AddressOfNames))), exports.NumberOfNames)
|
||||
ordinals := unsafe.Slice((*uint16)(a2p(module.codeBase+uintptr(exports.AddressOfNameOrdinals))), exports.NumberOfNames)
|
||||
module.nameExports = make(map[string]uint16)
|
||||
for i := range nameRefs {
|
||||
nameArray := windows.BytePtrToString((*byte)(a2p(module.codeBase + uintptr(nameRefs[i]))))
|
||||
module.nameExports[nameArray] = ordinals[i]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type addressRange struct {
|
||||
start uintptr
|
||||
end uintptr
|
||||
}
|
||||
|
||||
var (
|
||||
loadedAddressRanges []addressRange
|
||||
loadedAddressRangesMu sync.RWMutex
|
||||
haveHookedRtlPcToFileHeader sync.Once
|
||||
hookRtlPcToFileHeaderResult error
|
||||
)
|
||||
|
||||
func hookRtlPcToFileHeader() error {
|
||||
var kernelBase windows.Handle
|
||||
err := windows.GetModuleHandleEx(windows.GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, windows.StringToUTF16Ptr("kernelbase.dll"), &kernelBase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imageBase := unsafe.Pointer(kernelBase)
|
||||
dosHeader := (*IMAGE_DOS_HEADER)(imageBase)
|
||||
ntHeaders := (*IMAGE_NT_HEADERS)(unsafe.Add(imageBase, dosHeader.E_lfanew))
|
||||
importsDirectory := ntHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
|
||||
importDescriptor := (*IMAGE_IMPORT_DESCRIPTOR)(unsafe.Add(imageBase, importsDirectory.VirtualAddress))
|
||||
for ; importDescriptor.Name != 0; importDescriptor = (*IMAGE_IMPORT_DESCRIPTOR)(unsafe.Add(unsafe.Pointer(importDescriptor), unsafe.Sizeof(*importDescriptor))) {
|
||||
libraryName := windows.BytePtrToString((*byte)(unsafe.Add(imageBase, importDescriptor.Name)))
|
||||
if strings.EqualFold(libraryName, "ntdll.dll") {
|
||||
break
|
||||
}
|
||||
}
|
||||
if importDescriptor.Name == 0 {
|
||||
return errors.New("ntdll.dll not found")
|
||||
}
|
||||
originalThunk := (*uintptr)(unsafe.Add(imageBase, importDescriptor.OriginalFirstThunk()))
|
||||
thunk := (*uintptr)(unsafe.Add(imageBase, importDescriptor.FirstThunk))
|
||||
for ; *originalThunk != 0; originalThunk = (*uintptr)(unsafe.Add(unsafe.Pointer(originalThunk), unsafe.Sizeof(*originalThunk))) {
|
||||
if *originalThunk&IMAGE_ORDINAL_FLAG == 0 {
|
||||
function := (*IMAGE_IMPORT_BY_NAME)(unsafe.Add(imageBase, *originalThunk))
|
||||
name := windows.BytePtrToString(&function.Name[0])
|
||||
if name == "RtlPcToFileHeader" {
|
||||
break
|
||||
}
|
||||
}
|
||||
thunk = (*uintptr)(unsafe.Add(unsafe.Pointer(thunk), unsafe.Sizeof(*thunk)))
|
||||
}
|
||||
if *originalThunk == 0 {
|
||||
return errors.New("RtlPcToFileHeader not found")
|
||||
}
|
||||
var oldProtect uint32
|
||||
err = windows.VirtualProtect(uintptr(unsafe.Pointer(thunk)), unsafe.Sizeof(*thunk), windows.PAGE_READWRITE, &oldProtect)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
originalRtlPcToFileHeader := *thunk
|
||||
*thunk = windows.NewCallback(func(pcValue uintptr, baseOfImage *uintptr) uintptr {
|
||||
loadedAddressRangesMu.RLock()
|
||||
for i := range loadedAddressRanges {
|
||||
if pcValue >= loadedAddressRanges[i].start && pcValue < loadedAddressRanges[i].end {
|
||||
pcValue = *thunk
|
||||
break
|
||||
}
|
||||
}
|
||||
loadedAddressRangesMu.RUnlock()
|
||||
ret, _, _ := syscall.SyscallN(originalRtlPcToFileHeader, pcValue, uintptr(unsafe.Pointer(baseOfImage)))
|
||||
return ret
|
||||
})
|
||||
err = windows.VirtualProtect(uintptr(unsafe.Pointer(thunk)), unsafe.Sizeof(*thunk), oldProtect, &oldProtect)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadLibrary loads module image to memory.
|
||||
func LoadLibrary(data []byte) (module *Module, err error) {
|
||||
addr := uintptr(unsafe.Pointer(&data[0]))
|
||||
size := uintptr(len(data))
|
||||
if size < unsafe.Sizeof(IMAGE_DOS_HEADER{}) {
|
||||
return nil, errors.New("Incomplete IMAGE_DOS_HEADER")
|
||||
}
|
||||
dosHeader := (*IMAGE_DOS_HEADER)(a2p(addr))
|
||||
if dosHeader.E_magic != IMAGE_DOS_SIGNATURE {
|
||||
return nil, fmt.Errorf("Not an MS-DOS binary (provided: %x, expected: %x)", dosHeader.E_magic, IMAGE_DOS_SIGNATURE)
|
||||
}
|
||||
if (size < uintptr(dosHeader.E_lfanew)+unsafe.Sizeof(IMAGE_NT_HEADERS{})) {
|
||||
return nil, errors.New("Incomplete IMAGE_NT_HEADERS")
|
||||
}
|
||||
oldHeader := (*IMAGE_NT_HEADERS)(a2p(addr + uintptr(dosHeader.E_lfanew)))
|
||||
if oldHeader.Signature != IMAGE_NT_SIGNATURE {
|
||||
return nil, fmt.Errorf("Not an NT binary (provided: %x, expected: %x)", oldHeader.Signature, IMAGE_NT_SIGNATURE)
|
||||
}
|
||||
if oldHeader.FileHeader.Machine != imageFileProcess {
|
||||
return nil, fmt.Errorf("Foreign platform (provided: %x, expected: %x)", oldHeader.FileHeader.Machine, imageFileProcess)
|
||||
}
|
||||
if (oldHeader.OptionalHeader.SectionAlignment & 1) != 0 {
|
||||
return nil, errors.New("Unaligned section")
|
||||
}
|
||||
lastSectionEnd := uintptr(0)
|
||||
sections := oldHeader.Sections()
|
||||
optionalSectionSize := oldHeader.OptionalHeader.SectionAlignment
|
||||
for i := range sections {
|
||||
var endOfSection uintptr
|
||||
if sections[i].SizeOfRawData == 0 {
|
||||
// Section without data in the DLL
|
||||
endOfSection = uintptr(sections[i].VirtualAddress) + uintptr(optionalSectionSize)
|
||||
} else {
|
||||
endOfSection = uintptr(sections[i].VirtualAddress) + uintptr(sections[i].SizeOfRawData)
|
||||
}
|
||||
if endOfSection > lastSectionEnd {
|
||||
lastSectionEnd = endOfSection
|
||||
}
|
||||
}
|
||||
alignedImageSize := alignUp(uintptr(oldHeader.OptionalHeader.SizeOfImage), uintptr(oldHeader.OptionalHeader.SectionAlignment))
|
||||
if alignedImageSize != alignUp(lastSectionEnd, uintptr(oldHeader.OptionalHeader.SectionAlignment)) {
|
||||
return nil, errors.New("Section is not page-aligned")
|
||||
}
|
||||
|
||||
module = &Module{isDLL: (oldHeader.FileHeader.Characteristics & IMAGE_FILE_DLL) != 0}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
module.Free()
|
||||
module = nil
|
||||
}
|
||||
}()
|
||||
|
||||
// Reserve memory for image of library.
|
||||
// TODO: Is it correct to commit the complete memory region at once? Calling DllEntry raises an exception if we don't.
|
||||
module.codeBase, err = windows.VirtualAlloc(oldHeader.OptionalHeader.ImageBase,
|
||||
alignedImageSize,
|
||||
windows.MEM_RESERVE|windows.MEM_COMMIT,
|
||||
windows.PAGE_READWRITE)
|
||||
if err != nil {
|
||||
// Try to allocate memory at arbitrary position.
|
||||
module.codeBase, err = windows.VirtualAlloc(0,
|
||||
alignedImageSize,
|
||||
windows.MEM_RESERVE|windows.MEM_COMMIT,
|
||||
windows.PAGE_READWRITE)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error allocating code: %w", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
err = module.check4GBBoundaries(alignedImageSize)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error reallocating code: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
if size < uintptr(oldHeader.OptionalHeader.SizeOfHeaders) {
|
||||
err = errors.New("Incomplete headers")
|
||||
return
|
||||
}
|
||||
// Commit memory for headers.
|
||||
headers, err := windows.VirtualAlloc(module.codeBase,
|
||||
uintptr(oldHeader.OptionalHeader.SizeOfHeaders),
|
||||
windows.MEM_COMMIT,
|
||||
windows.PAGE_READWRITE)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error allocating headers: %w", err)
|
||||
return
|
||||
}
|
||||
// Copy PE header to code.
|
||||
memcpy(headers, addr, uintptr(oldHeader.OptionalHeader.SizeOfHeaders))
|
||||
module.headers = (*IMAGE_NT_HEADERS)(a2p(headers + uintptr(dosHeader.E_lfanew)))
|
||||
|
||||
// Update position.
|
||||
module.headers.OptionalHeader.ImageBase = module.codeBase
|
||||
|
||||
// Copy sections from DLL file block to new memory location.
|
||||
err = module.copySections(addr, size, oldHeader)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error copying sections: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Adjust base address of imported data.
|
||||
locationDelta := module.headers.OptionalHeader.ImageBase - oldHeader.OptionalHeader.ImageBase
|
||||
if locationDelta != 0 {
|
||||
module.isRelocated, err = module.performBaseRelocation(locationDelta)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error relocating module: %w", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
module.isRelocated = true
|
||||
}
|
||||
|
||||
// Load required dlls and adjust function table of imports.
|
||||
err = module.buildImportTable()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error building import table: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Mark memory pages depending on section headers and release sections that are marked as "discardable".
|
||||
err = module.finalizeSections()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error finalizing sections: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Register exception tables, if they exist.
|
||||
module.registerExceptionHandlers()
|
||||
|
||||
// Register function PCs.
|
||||
loadedAddressRangesMu.Lock()
|
||||
loadedAddressRanges = append(loadedAddressRanges, addressRange{module.codeBase, module.codeBase + alignedImageSize})
|
||||
loadedAddressRangesMu.Unlock()
|
||||
haveHookedRtlPcToFileHeader.Do(func() {
|
||||
hookRtlPcToFileHeaderResult = hookRtlPcToFileHeader()
|
||||
})
|
||||
err = hookRtlPcToFileHeaderResult
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// TLS callbacks are executed BEFORE the main loading.
|
||||
module.executeTLS()
|
||||
|
||||
// Get entry point of loaded module.
|
||||
if module.headers.OptionalHeader.AddressOfEntryPoint != 0 {
|
||||
module.entry = module.codeBase + uintptr(module.headers.OptionalHeader.AddressOfEntryPoint)
|
||||
if module.isDLL {
|
||||
// Notify library about attaching to process.
|
||||
r0, _, _ := syscall.SyscallN(module.entry, module.codeBase, DLL_PROCESS_ATTACH, 0)
|
||||
successful := r0 != 0
|
||||
if !successful {
|
||||
err = windows.ERROR_DLL_INIT_FAILED
|
||||
return
|
||||
}
|
||||
module.initialized = true
|
||||
}
|
||||
}
|
||||
|
||||
module.buildNameExports()
|
||||
return
|
||||
}
|
||||
|
||||
// Free releases module resources and unloads it.
|
||||
func (module *Module) Free() {
|
||||
if module.initialized {
|
||||
// Notify library about detaching from process.
|
||||
syscall.SyscallN(module.entry, module.codeBase, DLL_PROCESS_DETACH, 0)
|
||||
module.initialized = false
|
||||
}
|
||||
if module.modules != nil {
|
||||
// Free previously opened libraries.
|
||||
for _, handle := range module.modules {
|
||||
windows.FreeLibrary(handle)
|
||||
}
|
||||
module.modules = nil
|
||||
}
|
||||
if module.codeBase != 0 {
|
||||
windows.VirtualFree(module.codeBase, 0, windows.MEM_RELEASE)
|
||||
module.codeBase = 0
|
||||
}
|
||||
if module.blockedMemory != nil {
|
||||
module.blockedMemory.free()
|
||||
module.blockedMemory = nil
|
||||
}
|
||||
}
|
||||
|
||||
// ProcAddressByName returns function address by exported name.
|
||||
func (module *Module) ProcAddressByName(name string) (uintptr, error) {
|
||||
directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT)
|
||||
if directory.Size == 0 {
|
||||
return 0, errors.New("No export table found")
|
||||
}
|
||||
exports := (*IMAGE_EXPORT_DIRECTORY)(a2p(module.codeBase + uintptr(directory.VirtualAddress)))
|
||||
if module.nameExports == nil {
|
||||
return 0, errors.New("No functions exported by name")
|
||||
}
|
||||
if idx, ok := module.nameExports[name]; ok {
|
||||
if uint32(idx) > exports.NumberOfFunctions {
|
||||
return 0, errors.New("Ordinal number too high")
|
||||
}
|
||||
// AddressOfFunctions contains the RVAs to the "real" functions.
|
||||
return module.codeBase + uintptr(*(*uint32)(a2p(module.codeBase + uintptr(exports.AddressOfFunctions) + uintptr(idx)*4))), nil
|
||||
}
|
||||
return 0, errors.New("Function not found by name")
|
||||
}
|
||||
|
||||
// ProcAddressByOrdinal returns function address by exported ordinal.
|
||||
func (module *Module) ProcAddressByOrdinal(ordinal uint16) (uintptr, error) {
|
||||
directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT)
|
||||
if directory.Size == 0 {
|
||||
return 0, errors.New("No export table found")
|
||||
}
|
||||
exports := (*IMAGE_EXPORT_DIRECTORY)(a2p(module.codeBase + uintptr(directory.VirtualAddress)))
|
||||
if uint32(ordinal) < exports.Base {
|
||||
return 0, errors.New("Ordinal number too low")
|
||||
}
|
||||
idx := ordinal - uint16(exports.Base)
|
||||
if uint32(idx) > exports.NumberOfFunctions {
|
||||
return 0, errors.New("Ordinal number too high")
|
||||
}
|
||||
// AddressOfFunctions contains the RVAs to the "real" functions.
|
||||
return module.codeBase + uintptr(*(*uint32)(a2p(module.codeBase + uintptr(exports.AddressOfFunctions) + uintptr(idx)*4))), nil
|
||||
}
|
||||
|
||||
func alignDown(value, alignment uintptr) uintptr {
|
||||
return value & ^(alignment - 1)
|
||||
}
|
||||
|
||||
func alignUp(value, alignment uintptr) uintptr {
|
||||
return (value + alignment - 1) & ^(alignment - 1)
|
||||
}
|
||||
|
||||
func a2p(addr uintptr) unsafe.Pointer {
|
||||
return unsafe.Pointer(addr)
|
||||
}
|
||||
|
||||
func memcpy(dst, src, size uintptr) {
|
||||
copy(unsafe.Slice((*byte)(a2p(dst)), size), unsafe.Slice((*byte)(a2p(src)), size))
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
//go:build (windows && 386) || (windows && arm)
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package memmod
|
||||
|
||||
func (opthdr *IMAGE_OPTIONAL_HEADER) imageOffset() uintptr {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (module *Module) check4GBBoundaries(alignedImageSize uintptr) (err error) {
|
||||
return
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package memmod
|
||||
|
||||
const imageFileProcess = IMAGE_FILE_MACHINE_I386
|
||||
@@ -1,36 +0,0 @@
|
||||
//go:build (windows && amd64) || (windows && arm64)
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package memmod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func (opthdr *IMAGE_OPTIONAL_HEADER) imageOffset() uintptr {
|
||||
return uintptr(opthdr.ImageBase & 0xffffffff00000000)
|
||||
}
|
||||
|
||||
func (module *Module) check4GBBoundaries(alignedImageSize uintptr) (err error) {
|
||||
for (module.codeBase >> 32) < ((module.codeBase + alignedImageSize) >> 32) {
|
||||
node := &addressList{
|
||||
next: module.blockedMemory,
|
||||
address: module.codeBase,
|
||||
}
|
||||
module.blockedMemory = node
|
||||
module.codeBase, err = windows.VirtualAlloc(0,
|
||||
alignedImageSize,
|
||||
windows.MEM_RESERVE|windows.MEM_COMMIT,
|
||||
windows.PAGE_READWRITE)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error allocating memory block: %w", err)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package memmod
|
||||
|
||||
const imageFileProcess = IMAGE_FILE_MACHINE_AMD64
|
||||
@@ -1,8 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package memmod
|
||||
|
||||
const imageFileProcess = IMAGE_FILE_MACHINE_ARMNT
|
||||
@@ -1,8 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package memmod
|
||||
|
||||
const imageFileProcess = IMAGE_FILE_MACHINE_ARM64
|
||||
@@ -1,392 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package memmod
|
||||
|
||||
import "unsafe"
|
||||
|
||||
const (
|
||||
IMAGE_DOS_SIGNATURE = 0x5A4D // MZ
|
||||
IMAGE_OS2_SIGNATURE = 0x454E // NE
|
||||
IMAGE_OS2_SIGNATURE_LE = 0x454C // LE
|
||||
IMAGE_VXD_SIGNATURE = 0x454C // LE
|
||||
IMAGE_NT_SIGNATURE = 0x00004550 // PE00
|
||||
)
|
||||
|
||||
// DOS .EXE header
|
||||
type IMAGE_DOS_HEADER struct {
|
||||
E_magic uint16 // Magic number
|
||||
E_cblp uint16 // Bytes on last page of file
|
||||
E_cp uint16 // Pages in file
|
||||
E_crlc uint16 // Relocations
|
||||
E_cparhdr uint16 // Size of header in paragraphs
|
||||
E_minalloc uint16 // Minimum extra paragraphs needed
|
||||
E_maxalloc uint16 // Maximum extra paragraphs needed
|
||||
E_ss uint16 // Initial (relative) SS value
|
||||
E_sp uint16 // Initial SP value
|
||||
E_csum uint16 // Checksum
|
||||
E_ip uint16 // Initial IP value
|
||||
E_cs uint16 // Initial (relative) CS value
|
||||
E_lfarlc uint16 // File address of relocation table
|
||||
E_ovno uint16 // Overlay number
|
||||
E_res [4]uint16 // Reserved words
|
||||
E_oemid uint16 // OEM identifier (for e_oeminfo)
|
||||
E_oeminfo uint16 // OEM information; e_oemid specific
|
||||
E_res2 [10]uint16 // Reserved words
|
||||
E_lfanew int32 // File address of new exe header
|
||||
}
|
||||
|
||||
// File header format
|
||||
type IMAGE_FILE_HEADER struct {
|
||||
Machine uint16
|
||||
NumberOfSections uint16
|
||||
TimeDateStamp uint32
|
||||
PointerToSymbolTable uint32
|
||||
NumberOfSymbols uint32
|
||||
SizeOfOptionalHeader uint16
|
||||
Characteristics uint16
|
||||
}
|
||||
|
||||
const (
|
||||
IMAGE_SIZEOF_FILE_HEADER = 20
|
||||
|
||||
IMAGE_FILE_RELOCS_STRIPPED = 0x0001 // Relocation info stripped from file.
|
||||
IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002 // File is executable (i.e. no unresolved external references).
|
||||
IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004 // Line nunbers stripped from file.
|
||||
IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008 // Local symbols stripped from file.
|
||||
IMAGE_FILE_AGGRESIVE_WS_TRIM = 0x0010 // Aggressively trim working set
|
||||
IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020 // App can handle >2gb addresses
|
||||
IMAGE_FILE_BYTES_REVERSED_LO = 0x0080 // Bytes of machine word are reversed.
|
||||
IMAGE_FILE_32BIT_MACHINE = 0x0100 // 32 bit word machine.
|
||||
IMAGE_FILE_DEBUG_STRIPPED = 0x0200 // Debugging info stripped from file in .DBG file
|
||||
IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400 // If Image is on removable media, copy and run from the swap file.
|
||||
IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800 // If Image is on Net, copy and run from the swap file.
|
||||
IMAGE_FILE_SYSTEM = 0x1000 // System File.
|
||||
IMAGE_FILE_DLL = 0x2000 // File is a DLL.
|
||||
IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000 // File should only be run on a UP machine
|
||||
IMAGE_FILE_BYTES_REVERSED_HI = 0x8000 // Bytes of machine word are reversed.
|
||||
|
||||
IMAGE_FILE_MACHINE_UNKNOWN = 0
|
||||
IMAGE_FILE_MACHINE_TARGET_HOST = 0x0001 // Useful for indicating we want to interact with the host and not a WoW guest.
|
||||
IMAGE_FILE_MACHINE_I386 = 0x014c // Intel 386.
|
||||
IMAGE_FILE_MACHINE_R3000 = 0x0162 // MIPS little-endian, 0x160 big-endian
|
||||
IMAGE_FILE_MACHINE_R4000 = 0x0166 // MIPS little-endian
|
||||
IMAGE_FILE_MACHINE_R10000 = 0x0168 // MIPS little-endian
|
||||
IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x0169 // MIPS little-endian WCE v2
|
||||
IMAGE_FILE_MACHINE_ALPHA = 0x0184 // Alpha_AXP
|
||||
IMAGE_FILE_MACHINE_SH3 = 0x01a2 // SH3 little-endian
|
||||
IMAGE_FILE_MACHINE_SH3DSP = 0x01a3
|
||||
IMAGE_FILE_MACHINE_SH3E = 0x01a4 // SH3E little-endian
|
||||
IMAGE_FILE_MACHINE_SH4 = 0x01a6 // SH4 little-endian
|
||||
IMAGE_FILE_MACHINE_SH5 = 0x01a8 // SH5
|
||||
IMAGE_FILE_MACHINE_ARM = 0x01c0 // ARM Little-Endian
|
||||
IMAGE_FILE_MACHINE_THUMB = 0x01c2 // ARM Thumb/Thumb-2 Little-Endian
|
||||
IMAGE_FILE_MACHINE_ARMNT = 0x01c4 // ARM Thumb-2 Little-Endian
|
||||
IMAGE_FILE_MACHINE_AM33 = 0x01d3
|
||||
IMAGE_FILE_MACHINE_POWERPC = 0x01F0 // IBM PowerPC Little-Endian
|
||||
IMAGE_FILE_MACHINE_POWERPCFP = 0x01f1
|
||||
IMAGE_FILE_MACHINE_IA64 = 0x0200 // Intel 64
|
||||
IMAGE_FILE_MACHINE_MIPS16 = 0x0266 // MIPS
|
||||
IMAGE_FILE_MACHINE_ALPHA64 = 0x0284 // ALPHA64
|
||||
IMAGE_FILE_MACHINE_MIPSFPU = 0x0366 // MIPS
|
||||
IMAGE_FILE_MACHINE_MIPSFPU16 = 0x0466 // MIPS
|
||||
IMAGE_FILE_MACHINE_AXP64 = IMAGE_FILE_MACHINE_ALPHA64
|
||||
IMAGE_FILE_MACHINE_TRICORE = 0x0520 // Infineon
|
||||
IMAGE_FILE_MACHINE_CEF = 0x0CEF
|
||||
IMAGE_FILE_MACHINE_EBC = 0x0EBC // EFI Byte Code
|
||||
IMAGE_FILE_MACHINE_AMD64 = 0x8664 // AMD64 (K8)
|
||||
IMAGE_FILE_MACHINE_M32R = 0x9041 // M32R little-endian
|
||||
IMAGE_FILE_MACHINE_ARM64 = 0xAA64 // ARM64 Little-Endian
|
||||
IMAGE_FILE_MACHINE_CEE = 0xC0EE
|
||||
)
|
||||
|
||||
// Directory format
|
||||
type IMAGE_DATA_DIRECTORY struct {
|
||||
VirtualAddress uint32
|
||||
Size uint32
|
||||
}
|
||||
|
||||
const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16
|
||||
|
||||
type IMAGE_NT_HEADERS struct {
|
||||
Signature uint32
|
||||
FileHeader IMAGE_FILE_HEADER
|
||||
OptionalHeader IMAGE_OPTIONAL_HEADER
|
||||
}
|
||||
|
||||
func (ntheader *IMAGE_NT_HEADERS) Sections() []IMAGE_SECTION_HEADER {
|
||||
return (*[0xffff]IMAGE_SECTION_HEADER)(unsafe.Pointer(
|
||||
(uintptr)(unsafe.Pointer(ntheader)) +
|
||||
unsafe.Offsetof(ntheader.OptionalHeader) +
|
||||
uintptr(ntheader.FileHeader.SizeOfOptionalHeader)))[:ntheader.FileHeader.NumberOfSections]
|
||||
}
|
||||
|
||||
const (
|
||||
IMAGE_DIRECTORY_ENTRY_EXPORT = 0 // Export Directory
|
||||
IMAGE_DIRECTORY_ENTRY_IMPORT = 1 // Import Directory
|
||||
IMAGE_DIRECTORY_ENTRY_RESOURCE = 2 // Resource Directory
|
||||
IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3 // Exception Directory
|
||||
IMAGE_DIRECTORY_ENTRY_SECURITY = 4 // Security Directory
|
||||
IMAGE_DIRECTORY_ENTRY_BASERELOC = 5 // Base Relocation Table
|
||||
IMAGE_DIRECTORY_ENTRY_DEBUG = 6 // Debug Directory
|
||||
IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7 // (X86 usage)
|
||||
IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7 // Architecture Specific Data
|
||||
IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8 // RVA of GP
|
||||
IMAGE_DIRECTORY_ENTRY_TLS = 9 // TLS Directory
|
||||
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10 // Load Configuration Directory
|
||||
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11 // Bound Import Directory in headers
|
||||
IMAGE_DIRECTORY_ENTRY_IAT = 12 // Import Address Table
|
||||
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13 // Delay Load Import Descriptors
|
||||
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14 // COM Runtime descriptor
|
||||
)
|
||||
|
||||
const IMAGE_SIZEOF_SHORT_NAME = 8
|
||||
|
||||
// Section header format
|
||||
type IMAGE_SECTION_HEADER struct {
|
||||
Name [IMAGE_SIZEOF_SHORT_NAME]byte
|
||||
physicalAddressOrVirtualSize uint32
|
||||
VirtualAddress uint32
|
||||
SizeOfRawData uint32
|
||||
PointerToRawData uint32
|
||||
PointerToRelocations uint32
|
||||
PointerToLinenumbers uint32
|
||||
NumberOfRelocations uint16
|
||||
NumberOfLinenumbers uint16
|
||||
Characteristics uint32
|
||||
}
|
||||
|
||||
func (ishdr *IMAGE_SECTION_HEADER) PhysicalAddress() uint32 {
|
||||
return ishdr.physicalAddressOrVirtualSize
|
||||
}
|
||||
|
||||
func (ishdr *IMAGE_SECTION_HEADER) SetPhysicalAddress(addr uint32) {
|
||||
ishdr.physicalAddressOrVirtualSize = addr
|
||||
}
|
||||
|
||||
func (ishdr *IMAGE_SECTION_HEADER) VirtualSize() uint32 {
|
||||
return ishdr.physicalAddressOrVirtualSize
|
||||
}
|
||||
|
||||
func (ishdr *IMAGE_SECTION_HEADER) SetVirtualSize(addr uint32) {
|
||||
ishdr.physicalAddressOrVirtualSize = addr
|
||||
}
|
||||
|
||||
const (
|
||||
// Dll characteristics.
|
||||
IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020
|
||||
IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040
|
||||
IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY = 0x0080
|
||||
IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100
|
||||
IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION = 0x0200
|
||||
IMAGE_DLL_CHARACTERISTICS_NO_SEH = 0x0400
|
||||
IMAGE_DLL_CHARACTERISTICS_NO_BIND = 0x0800
|
||||
IMAGE_DLL_CHARACTERISTICS_APPCONTAINER = 0x1000
|
||||
IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER = 0x2000
|
||||
IMAGE_DLL_CHARACTERISTICS_GUARD_CF = 0x4000
|
||||
IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000
|
||||
)
|
||||
|
||||
const (
|
||||
// Section characteristics.
|
||||
IMAGE_SCN_TYPE_REG = 0x00000000 // Reserved.
|
||||
IMAGE_SCN_TYPE_DSECT = 0x00000001 // Reserved.
|
||||
IMAGE_SCN_TYPE_NOLOAD = 0x00000002 // Reserved.
|
||||
IMAGE_SCN_TYPE_GROUP = 0x00000004 // Reserved.
|
||||
IMAGE_SCN_TYPE_NO_PAD = 0x00000008 // Reserved.
|
||||
IMAGE_SCN_TYPE_COPY = 0x00000010 // Reserved.
|
||||
|
||||
IMAGE_SCN_CNT_CODE = 0x00000020 // Section contains code.
|
||||
IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040 // Section contains initialized data.
|
||||
IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080 // Section contains uninitialized data.
|
||||
|
||||
IMAGE_SCN_LNK_OTHER = 0x00000100 // Reserved.
|
||||
IMAGE_SCN_LNK_INFO = 0x00000200 // Section contains comments or some other type of information.
|
||||
IMAGE_SCN_TYPE_OVER = 0x00000400 // Reserved.
|
||||
IMAGE_SCN_LNK_REMOVE = 0x00000800 // Section contents will not become part of image.
|
||||
IMAGE_SCN_LNK_COMDAT = 0x00001000 // Section contents comdat.
|
||||
IMAGE_SCN_MEM_PROTECTED = 0x00004000 // Obsolete.
|
||||
IMAGE_SCN_NO_DEFER_SPEC_EXC = 0x00004000 // Reset speculative exceptions handling bits in the TLB entries for this section.
|
||||
IMAGE_SCN_GPREL = 0x00008000 // Section content can be accessed relative to GP
|
||||
IMAGE_SCN_MEM_FARDATA = 0x00008000
|
||||
IMAGE_SCN_MEM_SYSHEAP = 0x00010000 // Obsolete.
|
||||
IMAGE_SCN_MEM_PURGEABLE = 0x00020000
|
||||
IMAGE_SCN_MEM_16BIT = 0x00020000
|
||||
IMAGE_SCN_MEM_LOCKED = 0x00040000
|
||||
IMAGE_SCN_MEM_PRELOAD = 0x00080000
|
||||
|
||||
IMAGE_SCN_ALIGN_1BYTES = 0x00100000 //
|
||||
IMAGE_SCN_ALIGN_2BYTES = 0x00200000 //
|
||||
IMAGE_SCN_ALIGN_4BYTES = 0x00300000 //
|
||||
IMAGE_SCN_ALIGN_8BYTES = 0x00400000 //
|
||||
IMAGE_SCN_ALIGN_16BYTES = 0x00500000 // Default alignment if no others are specified.
|
||||
IMAGE_SCN_ALIGN_32BYTES = 0x00600000 //
|
||||
IMAGE_SCN_ALIGN_64BYTES = 0x00700000 //
|
||||
IMAGE_SCN_ALIGN_128BYTES = 0x00800000 //
|
||||
IMAGE_SCN_ALIGN_256BYTES = 0x00900000 //
|
||||
IMAGE_SCN_ALIGN_512BYTES = 0x00A00000 //
|
||||
IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000 //
|
||||
IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000 //
|
||||
IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000 //
|
||||
IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000 //
|
||||
IMAGE_SCN_ALIGN_MASK = 0x00F00000
|
||||
|
||||
IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000 // Section contains extended relocations.
|
||||
IMAGE_SCN_MEM_DISCARDABLE = 0x02000000 // Section can be discarded.
|
||||
IMAGE_SCN_MEM_NOT_CACHED = 0x04000000 // Section is not cachable.
|
||||
IMAGE_SCN_MEM_NOT_PAGED = 0x08000000 // Section is not pageable.
|
||||
IMAGE_SCN_MEM_SHARED = 0x10000000 // Section is shareable.
|
||||
IMAGE_SCN_MEM_EXECUTE = 0x20000000 // Section is executable.
|
||||
IMAGE_SCN_MEM_READ = 0x40000000 // Section is readable.
|
||||
IMAGE_SCN_MEM_WRITE = 0x80000000 // Section is writeable.
|
||||
|
||||
// TLS Characteristic Flags
|
||||
IMAGE_SCN_SCALE_INDEX = 0x00000001 // Tls index is scaled.
|
||||
)
|
||||
|
||||
// Based relocation format
|
||||
type IMAGE_BASE_RELOCATION struct {
|
||||
VirtualAddress uint32
|
||||
SizeOfBlock uint32
|
||||
}
|
||||
|
||||
const (
|
||||
IMAGE_REL_BASED_ABSOLUTE = 0
|
||||
IMAGE_REL_BASED_HIGH = 1
|
||||
IMAGE_REL_BASED_LOW = 2
|
||||
IMAGE_REL_BASED_HIGHLOW = 3
|
||||
IMAGE_REL_BASED_HIGHADJ = 4
|
||||
IMAGE_REL_BASED_MACHINE_SPECIFIC_5 = 5
|
||||
IMAGE_REL_BASED_RESERVED = 6
|
||||
IMAGE_REL_BASED_MACHINE_SPECIFIC_7 = 7
|
||||
IMAGE_REL_BASED_MACHINE_SPECIFIC_8 = 8
|
||||
IMAGE_REL_BASED_MACHINE_SPECIFIC_9 = 9
|
||||
IMAGE_REL_BASED_DIR64 = 10
|
||||
|
||||
IMAGE_REL_BASED_IA64_IMM64 = 9
|
||||
|
||||
IMAGE_REL_BASED_MIPS_JMPADDR = 5
|
||||
IMAGE_REL_BASED_MIPS_JMPADDR16 = 9
|
||||
|
||||
IMAGE_REL_BASED_ARM_MOV32 = 5
|
||||
IMAGE_REL_BASED_THUMB_MOV32 = 7
|
||||
)
|
||||
|
||||
// Export Format
|
||||
type IMAGE_EXPORT_DIRECTORY struct {
|
||||
Characteristics uint32
|
||||
TimeDateStamp uint32
|
||||
MajorVersion uint16
|
||||
MinorVersion uint16
|
||||
Name uint32
|
||||
Base uint32
|
||||
NumberOfFunctions uint32
|
||||
NumberOfNames uint32
|
||||
AddressOfFunctions uint32 // RVA from base of image
|
||||
AddressOfNames uint32 // RVA from base of image
|
||||
AddressOfNameOrdinals uint32 // RVA from base of image
|
||||
}
|
||||
|
||||
type IMAGE_IMPORT_BY_NAME struct {
|
||||
Hint uint16
|
||||
Name [1]byte
|
||||
}
|
||||
|
||||
func IMAGE_ORDINAL(ordinal uintptr) uintptr {
|
||||
return ordinal & 0xffff
|
||||
}
|
||||
|
||||
func IMAGE_SNAP_BY_ORDINAL(ordinal uintptr) bool {
|
||||
return (ordinal & IMAGE_ORDINAL_FLAG) != 0
|
||||
}
|
||||
|
||||
// Thread Local Storage
|
||||
type IMAGE_TLS_DIRECTORY struct {
|
||||
StartAddressOfRawData uintptr
|
||||
EndAddressOfRawData uintptr
|
||||
AddressOfIndex uintptr // PDWORD
|
||||
AddressOfCallbacks uintptr // PIMAGE_TLS_CALLBACK *;
|
||||
SizeOfZeroFill uint32
|
||||
Characteristics uint32
|
||||
}
|
||||
|
||||
type IMAGE_IMPORT_DESCRIPTOR struct {
|
||||
characteristicsOrOriginalFirstThunk uint32 // 0 for terminating null import descriptor
|
||||
// RVA to original unbound IAT (PIMAGE_THUNK_DATA)
|
||||
TimeDateStamp uint32 // 0 if not bound,
|
||||
// -1 if bound, and real date\time stamp
|
||||
// in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
|
||||
// O.W. date/time stamp of DLL bound to (Old BIND)
|
||||
ForwarderChain uint32 // -1 if no forwarders
|
||||
Name uint32
|
||||
FirstThunk uint32 // RVA to IAT (if bound this IAT has actual addresses)
|
||||
}
|
||||
|
||||
func (imgimpdesc *IMAGE_IMPORT_DESCRIPTOR) Characteristics() uint32 {
|
||||
return imgimpdesc.characteristicsOrOriginalFirstThunk
|
||||
}
|
||||
|
||||
func (imgimpdesc *IMAGE_IMPORT_DESCRIPTOR) OriginalFirstThunk() uint32 {
|
||||
return imgimpdesc.characteristicsOrOriginalFirstThunk
|
||||
}
|
||||
|
||||
type IMAGE_DELAYLOAD_DESCRIPTOR struct {
|
||||
Attributes uint32
|
||||
DllNameRVA uint32
|
||||
ModuleHandleRVA uint32
|
||||
ImportAddressTableRVA uint32
|
||||
ImportNameTableRVA uint32
|
||||
BoundImportAddressTableRVA uint32
|
||||
UnloadInformationTableRVA uint32
|
||||
TimeDateStamp uint32
|
||||
}
|
||||
|
||||
type IMAGE_LOAD_CONFIG_CODE_INTEGRITY struct {
|
||||
Flags uint16
|
||||
Catalog uint16
|
||||
CatalogOffset uint32
|
||||
Reserved uint32
|
||||
}
|
||||
|
||||
const (
|
||||
IMAGE_GUARD_CF_INSTRUMENTED = 0x00000100
|
||||
IMAGE_GUARD_CFW_INSTRUMENTED = 0x00000200
|
||||
IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT = 0x00000400
|
||||
IMAGE_GUARD_SECURITY_COOKIE_UNUSED = 0x00000800
|
||||
IMAGE_GUARD_PROTECT_DELAYLOAD_IAT = 0x00001000
|
||||
IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION = 0x00002000
|
||||
IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT = 0x00004000
|
||||
IMAGE_GUARD_CF_ENABLE_EXPORT_SUPPRESSION = 0x00008000
|
||||
IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT = 0x00010000
|
||||
IMAGE_GUARD_RF_INSTRUMENTED = 0x00020000
|
||||
IMAGE_GUARD_RF_ENABLE = 0x00040000
|
||||
IMAGE_GUARD_RF_STRICT = 0x00080000
|
||||
IMAGE_GUARD_RETPOLINE_PRESENT = 0x00100000
|
||||
IMAGE_GUARD_EH_CONTINUATION_TABLE_PRESENT = 0x00400000
|
||||
IMAGE_GUARD_XFG_ENABLED = 0x00800000
|
||||
IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK = 0xF0000000
|
||||
IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT = 28
|
||||
)
|
||||
|
||||
const (
|
||||
DLL_PROCESS_ATTACH = 1
|
||||
DLL_THREAD_ATTACH = 2
|
||||
DLL_THREAD_DETACH = 3
|
||||
DLL_PROCESS_DETACH = 0
|
||||
)
|
||||
|
||||
type SYSTEM_INFO struct {
|
||||
ProcessorArchitecture uint16
|
||||
Reserved uint16
|
||||
PageSize uint32
|
||||
MinimumApplicationAddress uintptr
|
||||
MaximumApplicationAddress uintptr
|
||||
ActiveProcessorMask uintptr
|
||||
NumberOfProcessors uint32
|
||||
ProcessorType uint32
|
||||
AllocationGranularity uint32
|
||||
ProcessorLevel uint16
|
||||
ProcessorRevision uint16
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
//go:build (windows && 386) || (windows && arm)
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package memmod
|
||||
|
||||
// Optional header format
|
||||
type IMAGE_OPTIONAL_HEADER struct {
|
||||
Magic uint16
|
||||
MajorLinkerVersion uint8
|
||||
MinorLinkerVersion uint8
|
||||
SizeOfCode uint32
|
||||
SizeOfInitializedData uint32
|
||||
SizeOfUninitializedData uint32
|
||||
AddressOfEntryPoint uint32
|
||||
BaseOfCode uint32
|
||||
BaseOfData uint32
|
||||
ImageBase uintptr
|
||||
SectionAlignment uint32
|
||||
FileAlignment uint32
|
||||
MajorOperatingSystemVersion uint16
|
||||
MinorOperatingSystemVersion uint16
|
||||
MajorImageVersion uint16
|
||||
MinorImageVersion uint16
|
||||
MajorSubsystemVersion uint16
|
||||
MinorSubsystemVersion uint16
|
||||
Win32VersionValue uint32
|
||||
SizeOfImage uint32
|
||||
SizeOfHeaders uint32
|
||||
CheckSum uint32
|
||||
Subsystem uint16
|
||||
DllCharacteristics uint16
|
||||
SizeOfStackReserve uintptr
|
||||
SizeOfStackCommit uintptr
|
||||
SizeOfHeapReserve uintptr
|
||||
SizeOfHeapCommit uintptr
|
||||
LoaderFlags uint32
|
||||
NumberOfRvaAndSizes uint32
|
||||
DataDirectory [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]IMAGE_DATA_DIRECTORY
|
||||
}
|
||||
|
||||
const IMAGE_ORDINAL_FLAG uintptr = 0x80000000
|
||||
|
||||
type IMAGE_LOAD_CONFIG_DIRECTORY struct {
|
||||
Size uint32
|
||||
TimeDateStamp uint32
|
||||
MajorVersion uint16
|
||||
MinorVersion uint16
|
||||
GlobalFlagsClear uint32
|
||||
GlobalFlagsSet uint32
|
||||
CriticalSectionDefaultTimeout uint32
|
||||
DeCommitFreeBlockThreshold uint32
|
||||
DeCommitTotalFreeThreshold uint32
|
||||
LockPrefixTable uint32
|
||||
MaximumAllocationSize uint32
|
||||
VirtualMemoryThreshold uint32
|
||||
ProcessHeapFlags uint32
|
||||
ProcessAffinityMask uint32
|
||||
CSDVersion uint16
|
||||
DependentLoadFlags uint16
|
||||
EditList uint32
|
||||
SecurityCookie uint32
|
||||
SEHandlerTable uint32
|
||||
SEHandlerCount uint32
|
||||
GuardCFCheckFunctionPointer uint32
|
||||
GuardCFDispatchFunctionPointer uint32
|
||||
GuardCFFunctionTable uint32
|
||||
GuardCFFunctionCount uint32
|
||||
GuardFlags uint32
|
||||
CodeIntegrity IMAGE_LOAD_CONFIG_CODE_INTEGRITY
|
||||
GuardAddressTakenIatEntryTable uint32
|
||||
GuardAddressTakenIatEntryCount uint32
|
||||
GuardLongJumpTargetTable uint32
|
||||
GuardLongJumpTargetCount uint32
|
||||
DynamicValueRelocTable uint32
|
||||
CHPEMetadataPointer uint32
|
||||
GuardRFFailureRoutine uint32
|
||||
GuardRFFailureRoutineFunctionPointer uint32
|
||||
DynamicValueRelocTableOffset uint32
|
||||
DynamicValueRelocTableSection uint16
|
||||
Reserved2 uint16
|
||||
GuardRFVerifyStackPointerFunctionPointer uint32
|
||||
HotPatchTableOffset uint32
|
||||
Reserved3 uint32
|
||||
EnclaveConfigurationPointer uint32
|
||||
VolatileMetadataPointer uint32
|
||||
GuardEHContinuationTable uint32
|
||||
GuardEHContinuationCount uint32
|
||||
GuardXFGCheckFunctionPointer uint32
|
||||
GuardXFGDispatchFunctionPointer uint32
|
||||
GuardXFGTableDispatchFunctionPointer uint32
|
||||
CastGuardOsDeterminedFailureMode uint32
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
//go:build (windows && amd64) || (windows && arm64)
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package memmod
|
||||
|
||||
// Optional header format
|
||||
type IMAGE_OPTIONAL_HEADER struct {
|
||||
Magic uint16
|
||||
MajorLinkerVersion uint8
|
||||
MinorLinkerVersion uint8
|
||||
SizeOfCode uint32
|
||||
SizeOfInitializedData uint32
|
||||
SizeOfUninitializedData uint32
|
||||
AddressOfEntryPoint uint32
|
||||
BaseOfCode uint32
|
||||
ImageBase uintptr
|
||||
SectionAlignment uint32
|
||||
FileAlignment uint32
|
||||
MajorOperatingSystemVersion uint16
|
||||
MinorOperatingSystemVersion uint16
|
||||
MajorImageVersion uint16
|
||||
MinorImageVersion uint16
|
||||
MajorSubsystemVersion uint16
|
||||
MinorSubsystemVersion uint16
|
||||
Win32VersionValue uint32
|
||||
SizeOfImage uint32
|
||||
SizeOfHeaders uint32
|
||||
CheckSum uint32
|
||||
Subsystem uint16
|
||||
DllCharacteristics uint16
|
||||
SizeOfStackReserve uintptr
|
||||
SizeOfStackCommit uintptr
|
||||
SizeOfHeapReserve uintptr
|
||||
SizeOfHeapCommit uintptr
|
||||
LoaderFlags uint32
|
||||
NumberOfRvaAndSizes uint32
|
||||
DataDirectory [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]IMAGE_DATA_DIRECTORY
|
||||
}
|
||||
|
||||
const IMAGE_ORDINAL_FLAG uintptr = 0x8000000000000000
|
||||
|
||||
type IMAGE_LOAD_CONFIG_DIRECTORY struct {
|
||||
Size uint32
|
||||
TimeDateStamp uint32
|
||||
MajorVersion uint16
|
||||
MinorVersion uint16
|
||||
GlobalFlagsClear uint32
|
||||
GlobalFlagsSet uint32
|
||||
CriticalSectionDefaultTimeout uint32
|
||||
DeCommitFreeBlockThreshold uint64
|
||||
DeCommitTotalFreeThreshold uint64
|
||||
LockPrefixTable uint64
|
||||
MaximumAllocationSize uint64
|
||||
VirtualMemoryThreshold uint64
|
||||
ProcessAffinityMask uint64
|
||||
ProcessHeapFlags uint32
|
||||
CSDVersion uint16
|
||||
DependentLoadFlags uint16
|
||||
EditList uint64
|
||||
SecurityCookie uint64
|
||||
SEHandlerTable uint64
|
||||
SEHandlerCount uint64
|
||||
GuardCFCheckFunctionPointer uint64
|
||||
GuardCFDispatchFunctionPointer uint64
|
||||
GuardCFFunctionTable uint64
|
||||
GuardCFFunctionCount uint64
|
||||
GuardFlags uint32
|
||||
CodeIntegrity IMAGE_LOAD_CONFIG_CODE_INTEGRITY
|
||||
GuardAddressTakenIatEntryTable uint64
|
||||
GuardAddressTakenIatEntryCount uint64
|
||||
GuardLongJumpTargetTable uint64
|
||||
GuardLongJumpTargetCount uint64
|
||||
DynamicValueRelocTable uint64
|
||||
CHPEMetadataPointer uint64
|
||||
GuardRFFailureRoutine uint64
|
||||
GuardRFFailureRoutineFunctionPointer uint64
|
||||
DynamicValueRelocTableOffset uint32
|
||||
DynamicValueRelocTableSection uint16
|
||||
Reserved2 uint16
|
||||
GuardRFVerifyStackPointerFunctionPointer uint64
|
||||
HotPatchTableOffset uint32
|
||||
Reserved3 uint32
|
||||
EnclaveConfigurationPointer uint64
|
||||
VolatileMetadataPointer uint64
|
||||
GuardEHContinuationTable uint64
|
||||
GuardEHContinuationCount uint64
|
||||
GuardXFGCheckFunctionPointer uint64
|
||||
GuardXFGDispatchFunctionPointer uint64
|
||||
GuardXFGTableDispatchFunctionPointer uint64
|
||||
CastGuardOsDeterminedFailureMode uint64
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package driver
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func UninstallLegacyWintun() error {
|
||||
deviceClassNetGUID := &windows.GUID{0x4d36e972, 0xe325, 0x11ce, [8]byte{0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}}
|
||||
devInfo, err := windows.SetupDiCreateDeviceInfoListEx(deviceClassNetGUID, 0, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer devInfo.Close()
|
||||
devInfoData, err := devInfo.CreateDeviceInfo("Wintun", deviceClassNetGUID, "", 0, windows.DICD_GENERATE_ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = devInfo.SetDeviceRegistryProperty(devInfoData, windows.SPDRP_HARDWAREID, []byte("W\x00i\x00n\x00t\x00u\x00n\x00\x00\x00\x00\x00"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = devInfo.BuildDriverInfoList(devInfoData, windows.SPDIT_COMPATDRIVER)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer devInfo.DestroyDriverInfoList(devInfoData, windows.SPDIT_COMPATDRIVER)
|
||||
var lastError error
|
||||
for i := 0; ; i++ {
|
||||
drvInfoData, err := devInfo.EnumDriverInfo(devInfoData, windows.SPDIT_COMPATDRIVER, i)
|
||||
if err != nil {
|
||||
if err == windows.ERROR_NO_MORE_ITEMS {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
drvInfoDetailData, err := devInfo.DriverInfoDetail(devInfoData, drvInfoData)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
lastError = windows.SetupUninstallOEMInf(filepath.Base(drvInfoDetailData.InfFileName()), 0)
|
||||
}
|
||||
return lastError
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/registry"
|
||||
|
||||
"golang.zx2c4.com/wireguard/windows/version"
|
||||
"github.com/amnezia-vpn/amneziawg-windows-client/version"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
4
embeddable-dll-service/.gitignore
vendored
4
embeddable-dll-service/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
# Build Output
|
||||
/x86
|
||||
/amd64
|
||||
/arm64
|
||||
@@ -1,41 +0,0 @@
|
||||
## Embeddable WireGuard Tunnel Library
|
||||
|
||||
This allows embedding WireGuard as a service inside of another application. Build `tunnel.dll` by running `./build.bat` in this folder. The first time you run it, it will invoke `..\build.bat` simply for downloading dependencies. After, you should have `amd64/tunnel.dll`, `x86/tunnel.dll`, and `arm64/tunnel.dll`. In addition, `tunnel.dll` requires `wireguard.dll`, which can be downloaded from [the wireguard-nt download server](https://download.wireguard.com/wireguard-nt/).
|
||||
|
||||
The basic setup to use `tunnel.dll` is:
|
||||
|
||||
##### 1. Install a service with these parameters:
|
||||
|
||||
```text
|
||||
Service Name: "WireGuardTunnel$SomeTunnelName"
|
||||
Display Name: "Some Service Name"
|
||||
Service Type: SERVICE_WIN32_OWN_PROCESS
|
||||
Start Type: StartAutomatic
|
||||
Error Control: ErrorNormal,
|
||||
Dependencies: [ "Nsi", "TcpIp" ]
|
||||
Sid Type: SERVICE_SID_TYPE_UNRESTRICTED
|
||||
Executable: "C:\path\to\example\vpnclient.exe /service configfile.conf"
|
||||
```
|
||||
|
||||
Some of these may have to be changed with `ChangeServiceConfig2` after the
|
||||
initial call to `CreateService` The `SERVICE_SID_TYPE_UNRESTRICTED` parameter
|
||||
is absolutely essential; do not forget it.
|
||||
|
||||
##### 2. Have your program's main function handle the `/service` switch:
|
||||
|
||||
```c
|
||||
if (wargc == 3 && !wcscmp(wargv[1], L"/service")) {
|
||||
HMODULE tunnel_lib = LoadLibrary("tunnel.dll");
|
||||
if (!tunnel_lib)
|
||||
abort();
|
||||
BOOL (_cdecl *tunnel_proc)(_In_ LPCWSTR conf_file);
|
||||
*(FARPROC*)&tunnel_proc = GetProcAddress(tunnel_lib, "WireGuardTunnelService");
|
||||
if (!tunnel_proc)
|
||||
abort();
|
||||
return tunnel_proc(wargv[2]);
|
||||
}
|
||||
```
|
||||
|
||||
##### 3. Scoop up logs by implementing a ringlogger format reader.
|
||||
|
||||
There is a sample implementation of bits and pieces of this inside of the `csharp\` directory.
|
||||
@@ -1,48 +0,0 @@
|
||||
@echo off
|
||||
rem SPDX-License-Identifier: MIT
|
||||
rem Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
|
||||
setlocal
|
||||
set BUILDDIR=%~dp0
|
||||
set PATH=%BUILDDIR%..\.deps\llvm-mingw\bin;%BUILDDIR%..\.deps\go\bin;%PATH%
|
||||
set PATHEXT=.exe
|
||||
cd /d %BUILDDIR% || exit /b 1
|
||||
|
||||
if exist ..\.deps\prepared goto :build
|
||||
:installdeps
|
||||
call ..\build.bat || goto :error
|
||||
|
||||
:build
|
||||
set GOOS=windows
|
||||
set GOARM=7
|
||||
set GOPATH=%BUILDDIR%..\.deps\gopath
|
||||
set GOROOT=%BUILDDIR%..\.deps\go
|
||||
set CGO_ENABLED=1
|
||||
set CGO_CFLAGS=-O3 -Wall -Wno-unused-function -Wno-switch -std=gnu11 -DWINVER=0x0601
|
||||
call :build_plat x86 i686 386 || goto :error
|
||||
call :build_plat amd64 x86_64 amd64 || goto :error
|
||||
call :build_plat arm64 aarch64 arm64 || goto :error
|
||||
|
||||
:sign
|
||||
if exist ..\sign.bat call ..\sign.bat
|
||||
if "%SigningCertificate%"=="" goto :success
|
||||
if "%TimestampServer%"=="" goto :success
|
||||
echo [+] Signing
|
||||
signtool sign /sha1 "%SigningCertificate%" /fd sha256 /tr "%TimestampServer%" /td sha256 /d "WireGuard Tunnel" x86\tunnel.dll amd64\tunnel.dll arm64\tunnel.dll || goto :error
|
||||
|
||||
:success
|
||||
echo [+] Success
|
||||
exit /b 0
|
||||
|
||||
:build_plat
|
||||
set CC=%~2-w64-mingw32-gcc
|
||||
set GOARCH=%~3
|
||||
mkdir %1 >NUL 2>&1
|
||||
echo [+] Building library %1
|
||||
go build -buildmode c-shared -ldflags="-w -s" -trimpath -v -o "%~1/tunnel.dll" || exit /b 1
|
||||
del "%~1\tunnel.h"
|
||||
goto :eof
|
||||
|
||||
:error
|
||||
echo [-] Failed with error #%errorlevel%.
|
||||
cmd /c exit %errorlevel%
|
||||
3
embeddable-dll-service/csharp/.gitignore
vendored
3
embeddable-dll-service/csharp/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
/.vs
|
||||
/bin
|
||||
/obj
|
||||
@@ -1,87 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
namespace DemoUI
|
||||
{
|
||||
partial class MainWindow
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.connectButton = new System.Windows.Forms.Button();
|
||||
this.logBox = new System.Windows.Forms.TextBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// connectButton
|
||||
//
|
||||
this.connectButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.connectButton.Location = new System.Drawing.Point(12, 12);
|
||||
this.connectButton.Name = "connectButton";
|
||||
this.connectButton.Size = new System.Drawing.Size(1137, 46);
|
||||
this.connectButton.TabIndex = 5;
|
||||
this.connectButton.Text = "&Connect";
|
||||
this.connectButton.UseVisualStyleBackColor = true;
|
||||
this.connectButton.Click += new System.EventHandler(this.connectButton_Click);
|
||||
//
|
||||
// logBox
|
||||
//
|
||||
this.logBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.logBox.Location = new System.Drawing.Point(12, 64);
|
||||
this.logBox.Multiline = true;
|
||||
this.logBox.Name = "logBox";
|
||||
this.logBox.ReadOnly = true;
|
||||
this.logBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||
this.logBox.Size = new System.Drawing.Size(1137, 561);
|
||||
this.logBox.TabIndex = 4;
|
||||
this.logBox.TabStop = false;
|
||||
//
|
||||
// MainWindow
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(13F, 32F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(1161, 637);
|
||||
this.Controls.Add(this.logBox);
|
||||
this.Controls.Add(this.connectButton);
|
||||
this.Name = "MainWindow";
|
||||
this.Text = "WireGuard Demo Client";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainWindow_FormClosing);
|
||||
this.Load += new System.EventHandler(this.MainWindow_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
private System.Windows.Forms.Button connectButton;
|
||||
private System.Windows.Forms.TextBox logBox;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,215 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using System.Threading;
|
||||
using System.IO.Pipes;
|
||||
using System.Diagnostics;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.AccessControl;
|
||||
|
||||
namespace DemoUI
|
||||
{
|
||||
public partial class MainWindow : Form
|
||||
{
|
||||
private static readonly string userDirectory = Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "Config"); //TODO: put in Program Files in real code.
|
||||
private static readonly string configFile = Path.Combine(userDirectory, "demobox.conf");
|
||||
private static readonly string logFile = Path.Combine(userDirectory, "log.bin");
|
||||
|
||||
private Tunnel.Ringlogger log;
|
||||
private Thread logPrintingThread, transferUpdateThread;
|
||||
private volatile bool threadsRunning;
|
||||
private bool connected;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
makeConfigDirectory();
|
||||
InitializeComponent();
|
||||
Application.ApplicationExit += Application_ApplicationExit;
|
||||
try { File.Delete(logFile); } catch { }
|
||||
log = new Tunnel.Ringlogger(logFile, "GUI");
|
||||
logPrintingThread = new Thread(new ThreadStart(tailLog));
|
||||
transferUpdateThread = new Thread(new ThreadStart(tailTransfer));
|
||||
}
|
||||
|
||||
private void makeConfigDirectory()
|
||||
{
|
||||
var ds = new DirectorySecurity();
|
||||
ds.SetSecurityDescriptorSddlForm("O:BAG:BAD:PAI(A;OICI;FA;;;BA)(A;OICI;FA;;;SY)");
|
||||
FileSystemAclExtensions.CreateDirectory(ds, userDirectory);
|
||||
}
|
||||
|
||||
private void tailLog()
|
||||
{
|
||||
var cursor = Tunnel.Ringlogger.CursorAll;
|
||||
while (threadsRunning)
|
||||
{
|
||||
var lines = log.FollowFromCursor(ref cursor);
|
||||
foreach (var line in lines)
|
||||
logBox.Invoke(new Action<string>(logBox.AppendText), new object[] { line + "\r\n" });
|
||||
try
|
||||
{
|
||||
Thread.Sleep(300);
|
||||
}
|
||||
catch
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void tailTransfer()
|
||||
{
|
||||
Tunnel.Driver.Adapter adapter = null;
|
||||
while (threadsRunning)
|
||||
{
|
||||
if (adapter == null)
|
||||
{
|
||||
while (threadsRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
adapter = Tunnel.Service.GetAdapter(configFile);
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (adapter == null)
|
||||
continue;
|
||||
try
|
||||
{
|
||||
ulong rx = 0, tx = 0;
|
||||
var config = adapter.GetConfiguration();
|
||||
foreach (var peer in config.Peers)
|
||||
{
|
||||
rx += peer.RxBytes;
|
||||
tx += peer.TxBytes;
|
||||
}
|
||||
Invoke(new Action<ulong, ulong>(updateTransferTitle), new object[] { rx, tx });
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
catch { adapter = null; }
|
||||
}
|
||||
}
|
||||
|
||||
private void Application_ApplicationExit(object sender, EventArgs e)
|
||||
{
|
||||
Tunnel.Service.Remove(configFile, true);
|
||||
try { File.Delete(logFile); } catch { }
|
||||
try { File.Delete(configFile); } catch { }
|
||||
}
|
||||
|
||||
private void MainWindow_Load(object sender, EventArgs e)
|
||||
{
|
||||
threadsRunning = true;
|
||||
logPrintingThread.Start();
|
||||
transferUpdateThread.Start();
|
||||
}
|
||||
|
||||
private void MainWindow_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
threadsRunning = false;
|
||||
logPrintingThread.Interrupt();
|
||||
transferUpdateThread.Interrupt();
|
||||
try { logPrintingThread.Join(); } catch { }
|
||||
try { transferUpdateThread.Join(); } catch { }
|
||||
}
|
||||
|
||||
private static string formatBytes(ulong bytes)
|
||||
{
|
||||
decimal d = bytes;
|
||||
string selectedUnit = null;
|
||||
foreach (string unit in new string[] { "B", "KiB", "MiB", "GiB", "TiB" })
|
||||
{
|
||||
selectedUnit = unit;
|
||||
if (d < 1024)
|
||||
break;
|
||||
d /= 1024;
|
||||
}
|
||||
return string.Format("{0:0.##} {1}", d, selectedUnit);
|
||||
}
|
||||
|
||||
private void updateTransferTitle(ulong rx, ulong tx)
|
||||
{
|
||||
var titleBase = Text;
|
||||
var idx = titleBase.IndexOf(" - ");
|
||||
if (idx != -1)
|
||||
titleBase = titleBase.Substring(0, idx);
|
||||
if (rx == 0 && tx == 0)
|
||||
Text = titleBase;
|
||||
else
|
||||
Text = string.Format("{0} - rx: {1}, tx: {2}", titleBase, formatBytes(rx), formatBytes(tx));
|
||||
}
|
||||
|
||||
private async Task<string> generateNewConfig()
|
||||
{
|
||||
log.Write("Generating keys");
|
||||
var keys = Tunnel.Keypair.Generate();
|
||||
log.Write("Exchanging keys with demo server");
|
||||
var client = new TcpClient();
|
||||
await client.ConnectAsync("demo.wireguard.com", 42912);
|
||||
var stream = client.GetStream();
|
||||
var reader = new StreamReader(stream, Encoding.UTF8);
|
||||
var pubKeyBytes = Encoding.UTF8.GetBytes(keys.Public + "\n");
|
||||
await stream.WriteAsync(pubKeyBytes, 0, pubKeyBytes.Length);
|
||||
await stream.FlushAsync();
|
||||
var ret = (await reader.ReadLineAsync()).Split(':');
|
||||
client.Close();
|
||||
var status = ret.Length >= 1 ? ret[0] : "";
|
||||
var serverPubkey = ret.Length >= 2 ? ret[1] : "";
|
||||
var serverPort = ret.Length >= 3 ? ret[2] : "";
|
||||
var internalIP = ret.Length >= 4 ? ret[3] : "";
|
||||
if (status != "OK")
|
||||
throw new InvalidOperationException(string.Format("Server status is {0}", status));
|
||||
return string.Format("[Interface]\nPrivateKey = {0}\nAddress = {1}/24\nDNS = 8.8.8.8, 8.8.4.4\n\n[Peer]\nPublicKey = {2}\nEndpoint = demo.wireguard.com:{3}\nAllowedIPs = 0.0.0.0/0\n", keys.Private, internalIP, serverPubkey, serverPort);
|
||||
}
|
||||
|
||||
private async void connectButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (connected)
|
||||
{
|
||||
connectButton.Enabled = false;
|
||||
await Task.Run(() =>
|
||||
{
|
||||
Tunnel.Service.Remove(configFile, true);
|
||||
try { File.Delete(configFile); } catch { }
|
||||
});
|
||||
updateTransferTitle(0, 0);
|
||||
connectButton.Text = "&Connect";
|
||||
connectButton.Enabled = true;
|
||||
connected = false;
|
||||
return;
|
||||
}
|
||||
|
||||
connectButton.Enabled = false;
|
||||
try
|
||||
{
|
||||
var config = await generateNewConfig();
|
||||
await File.WriteAllBytesAsync(configFile, Encoding.UTF8.GetBytes(config));
|
||||
await Task.Run(() => Tunnel.Service.Add(configFile, true));
|
||||
connected = true;
|
||||
connectButton.Text = "&Disconnect";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.Write(ex.Message);
|
||||
try { File.Delete(configFile); } catch { }
|
||||
}
|
||||
connectButton.Enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -1,44 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace DemoUI
|
||||
{
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (args.Length == 3 && args[0] == "/service")
|
||||
{
|
||||
var t = new Thread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var currentProcess = Process.GetCurrentProcess();
|
||||
var uiProcess = Process.GetProcessById(int.Parse(args[2]));
|
||||
if (uiProcess.MainModule.FileName != currentProcess.MainModule.FileName)
|
||||
return;
|
||||
uiProcess.WaitForExit();
|
||||
Tunnel.Service.Remove(args[1], false);
|
||||
}
|
||||
catch { }
|
||||
});
|
||||
t.Start();
|
||||
Tunnel.Service.Run(args[1]);
|
||||
t.Interrupt();
|
||||
return;
|
||||
}
|
||||
Application.SetHighDpiMode(HighDpiMode.SystemAware);
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.Run(new MainWindow());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="demo-client"/>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- Windows 7 -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
|
||||
|
||||
<!-- Windows 8 -->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
|
||||
|
||||
<!-- Windows 8.1 -->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*"
|
||||
/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
|
||||
</assembly>
|
||||
@@ -1,7 +0,0 @@
|
||||
# Example WireGuard Demo Client for Windows
|
||||
|
||||
This is a simple client for demo.wireguard.com, which brings up WireGuard tunnels using the [embeddable-dll-service](https://git.zx2c4.com/wireguard-windows/about/embeddable-dll-service/README.md).
|
||||
|
||||
## Building
|
||||
|
||||
The code in this repository can be built in Visual Studio 2019 by opening the .sln and pressing build. However, it requires [`tunnel.dll` and `wireguard.dll`](../README.md).
|
||||
@@ -1,234 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Tunnel
|
||||
{
|
||||
public class Driver
|
||||
{
|
||||
[DllImport("wireguard.dll", EntryPoint = "WireGuardOpenAdapter", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
||||
private static extern IntPtr openAdapter([MarshalAs(UnmanagedType.LPWStr)] string name);
|
||||
[DllImport("wireguard.dll", EntryPoint = "WireGuardCloseAdapter", CallingConvention = CallingConvention.StdCall)]
|
||||
private static extern void freeAdapter(IntPtr adapter);
|
||||
[DllImport("wireguard.dll", EntryPoint = "WireGuardGetConfiguration", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
||||
private static extern bool getConfiguration(IntPtr adapter, byte[] iface, ref UInt32 bytes);
|
||||
|
||||
public class Adapter
|
||||
{
|
||||
private IntPtr _handle;
|
||||
private UInt32 _lastGetGuess;
|
||||
public Adapter(string name)
|
||||
{
|
||||
_lastGetGuess = 1024;
|
||||
_handle = openAdapter(name);
|
||||
if (_handle == IntPtr.Zero)
|
||||
throw new Win32Exception();
|
||||
}
|
||||
~Adapter()
|
||||
{
|
||||
freeAdapter(_handle);
|
||||
}
|
||||
public unsafe Interface GetConfiguration()
|
||||
{
|
||||
var iface = new Interface();
|
||||
byte[] bytes;
|
||||
for (; ; )
|
||||
{
|
||||
bytes = new byte[_lastGetGuess];
|
||||
if (getConfiguration(_handle, bytes, ref _lastGetGuess))
|
||||
break;
|
||||
if (Marshal.GetLastWin32Error() != 234 /* ERROR_MORE_DATA */)
|
||||
throw new Win32Exception();
|
||||
}
|
||||
fixed (void* start = bytes)
|
||||
{
|
||||
var ioctlIface = (IoctlInterface*)start;
|
||||
if ((ioctlIface->Flags & IoctlInterfaceFlags.HasPublicKey) != 0)
|
||||
iface.PublicKey = new Key(ioctlIface->PublicKey);
|
||||
if ((ioctlIface->Flags & IoctlInterfaceFlags.HasPrivateKey) != 0)
|
||||
iface.PrivateKey = new Key(ioctlIface->PrivateKey);
|
||||
if ((ioctlIface->Flags & IoctlInterfaceFlags.HasListenPort) != 0)
|
||||
iface.ListenPort = ioctlIface->ListenPort;
|
||||
var peers = new Peer[ioctlIface->PeersCount];
|
||||
var ioctlPeer = (IoctlPeer*)((byte*)ioctlIface + sizeof(IoctlInterface));
|
||||
for (UInt32 i = 0; i < peers.Length; ++i)
|
||||
{
|
||||
var peer = new Peer();
|
||||
if ((ioctlPeer->Flags & IoctlPeerFlags.HasPublicKey) != 0)
|
||||
peer.PublicKey = new Key(ioctlPeer->PublicKey);
|
||||
if ((ioctlPeer->Flags & IoctlPeerFlags.HasPresharedKey) != 0)
|
||||
peer.PresharedKey = new Key(ioctlPeer->PresharedKey);
|
||||
if ((ioctlPeer->Flags & IoctlPeerFlags.HasPersistentKeepalive) != 0)
|
||||
peer.PersistentKeepalive = ioctlPeer->PersistentKeepalive;
|
||||
if ((ioctlPeer->Flags & IoctlPeerFlags.HasEndpoint) != 0)
|
||||
{
|
||||
if (ioctlPeer->Endpoint.si_family == Win32.ADDRESS_FAMILY.AF_INET)
|
||||
{
|
||||
var ip = new byte[4];
|
||||
Marshal.Copy((IntPtr)ioctlPeer->Endpoint.Ipv4.sin_addr.bytes, ip, 0, 4);
|
||||
peer.Endpoint = new IPEndPoint(new IPAddress(ip), (ushort)IPAddress.NetworkToHostOrder((short)ioctlPeer->Endpoint.Ipv4.sin_port));
|
||||
}
|
||||
else if (ioctlPeer->Endpoint.si_family == Win32.ADDRESS_FAMILY.AF_INET6)
|
||||
{
|
||||
var ip = new byte[16];
|
||||
Marshal.Copy((IntPtr)ioctlPeer->Endpoint.Ipv6.sin6_addr.bytes, ip, 0, 16);
|
||||
peer.Endpoint = new IPEndPoint(new IPAddress(ip), (ushort)IPAddress.NetworkToHostOrder((short)ioctlPeer->Endpoint.Ipv6.sin6_port));
|
||||
}
|
||||
}
|
||||
peer.TxBytes = ioctlPeer->TxBytes;
|
||||
peer.RxBytes = ioctlPeer->RxBytes;
|
||||
if (ioctlPeer->LastHandshake != 0)
|
||||
peer.LastHandshake = DateTime.FromFileTimeUtc((long)ioctlPeer->LastHandshake);
|
||||
var allowedIPs = new AllowedIP[ioctlPeer->AllowedIPsCount];
|
||||
var ioctlAllowedIP = (IoctlAllowedIP*)((byte*)ioctlPeer + sizeof(IoctlPeer));
|
||||
for (UInt32 j = 0; j < allowedIPs.Length; ++j)
|
||||
{
|
||||
var allowedIP = new AllowedIP();
|
||||
if (ioctlAllowedIP->AddressFamily == Win32.ADDRESS_FAMILY.AF_INET)
|
||||
{
|
||||
var ip = new byte[4];
|
||||
Marshal.Copy((IntPtr)ioctlAllowedIP->V4.bytes, ip, 0, 4);
|
||||
allowedIP.Address = new IPAddress(ip);
|
||||
}
|
||||
else if (ioctlAllowedIP->AddressFamily == Win32.ADDRESS_FAMILY.AF_INET6)
|
||||
{
|
||||
var ip = new byte[16];
|
||||
Marshal.Copy((IntPtr)ioctlAllowedIP->V6.bytes, ip, 0, 16);
|
||||
allowedIP.Address = new IPAddress(ip);
|
||||
}
|
||||
allowedIP.Cidr = ioctlAllowedIP->Cidr;
|
||||
allowedIPs[j] = allowedIP;
|
||||
ioctlAllowedIP = (IoctlAllowedIP*)((byte*)ioctlAllowedIP + sizeof(IoctlAllowedIP));
|
||||
}
|
||||
peer.AllowedIPs = allowedIPs;
|
||||
peers[i] = peer;
|
||||
ioctlPeer = (IoctlPeer*)ioctlAllowedIP;
|
||||
}
|
||||
iface.Peers = peers;
|
||||
}
|
||||
return iface;
|
||||
}
|
||||
|
||||
public class Key
|
||||
{
|
||||
private byte[] _bytes;
|
||||
public byte[] Bytes
|
||||
{
|
||||
get
|
||||
{
|
||||
return _bytes;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null || value.Length != 32)
|
||||
throw new ArgumentException("Keys must be 32 bytes");
|
||||
_bytes = value;
|
||||
}
|
||||
}
|
||||
public Key(byte[] bytes)
|
||||
{
|
||||
Bytes = bytes;
|
||||
}
|
||||
public unsafe Key(byte* bytes)
|
||||
{
|
||||
_bytes = new byte[32];
|
||||
Marshal.Copy((IntPtr)bytes, _bytes, 0, 32);
|
||||
}
|
||||
public override String ToString()
|
||||
{
|
||||
return Convert.ToBase64String(_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
public class Interface
|
||||
{
|
||||
public UInt16 ListenPort { get; set; }
|
||||
public Key PrivateKey { get; set; }
|
||||
public Key PublicKey { get; set; }
|
||||
public Peer[] Peers { get; set; }
|
||||
}
|
||||
|
||||
public class Peer
|
||||
{
|
||||
public Key PublicKey { get; set; }
|
||||
public Key PresharedKey { get; set; }
|
||||
public UInt16 PersistentKeepalive { get; set; }
|
||||
public IPEndPoint Endpoint { get; set; }
|
||||
public UInt64 TxBytes { get; set; }
|
||||
public UInt64 RxBytes { get; set; }
|
||||
public DateTime LastHandshake { get; set; }
|
||||
public AllowedIP[] AllowedIPs { get; set; }
|
||||
}
|
||||
|
||||
public class AllowedIP
|
||||
{
|
||||
public IPAddress Address { get; set; }
|
||||
public byte Cidr { get; set; }
|
||||
}
|
||||
|
||||
private enum IoctlInterfaceFlags : UInt32
|
||||
{
|
||||
HasPublicKey = 1 << 0,
|
||||
HasPrivateKey = 1 << 1,
|
||||
HasListenPort = 1 << 2,
|
||||
ReplacePeers = 1 << 3
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 80)]
|
||||
private unsafe struct IoctlInterface
|
||||
{
|
||||
public IoctlInterfaceFlags Flags;
|
||||
public UInt16 ListenPort;
|
||||
public fixed byte PrivateKey[32];
|
||||
public fixed byte PublicKey[32];
|
||||
public UInt32 PeersCount;
|
||||
};
|
||||
|
||||
private enum IoctlPeerFlags : UInt32
|
||||
{
|
||||
HasPublicKey = 1 << 0,
|
||||
HasPresharedKey = 1 << 1,
|
||||
HasPersistentKeepalive = 1 << 2,
|
||||
HasEndpoint = 1 << 3,
|
||||
ReplaceAllowedIPs = 1 << 5,
|
||||
Remove = 1 << 6,
|
||||
UpdateOnly = 1 << 7
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 136)]
|
||||
private unsafe struct IoctlPeer
|
||||
{
|
||||
public IoctlPeerFlags Flags;
|
||||
public UInt32 Reserved;
|
||||
public fixed byte PublicKey[32];
|
||||
public fixed byte PresharedKey[32];
|
||||
public UInt16 PersistentKeepalive;
|
||||
public Win32.SOCKADDR_INET Endpoint;
|
||||
public UInt64 TxBytes, RxBytes;
|
||||
public UInt64 LastHandshake;
|
||||
public UInt32 AllowedIPsCount;
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Pack = 8, Size = 24)]
|
||||
private unsafe struct IoctlAllowedIP
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
[MarshalAs(UnmanagedType.Struct)]
|
||||
public Win32.IN_ADDR V4;
|
||||
[FieldOffset(0)]
|
||||
[MarshalAs(UnmanagedType.Struct)]
|
||||
public Win32.IN6_ADDR V6;
|
||||
[FieldOffset(16)]
|
||||
public Win32.ADDRESS_FAMILY AddressFamily;
|
||||
[FieldOffset(20)]
|
||||
public byte Cidr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Tunnel
|
||||
{
|
||||
public class Keypair
|
||||
{
|
||||
public readonly string Public;
|
||||
public readonly string Private;
|
||||
|
||||
public Keypair(string pub, string priv)
|
||||
{
|
||||
Public = pub;
|
||||
Private = priv;
|
||||
}
|
||||
|
||||
[DllImport("tunnel.dll", EntryPoint = "WireGuardGenerateKeypair", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool WireGuardGenerateKeypair(byte[] publicKey, byte[] privateKey);
|
||||
|
||||
public static Keypair Generate()
|
||||
{
|
||||
var publicKey = new byte[32];
|
||||
var privateKey = new byte[32];
|
||||
WireGuardGenerateKeypair(publicKey, privateKey);
|
||||
return new Keypair(Convert.ToBase64String(publicKey), Convert.ToBase64String(privateKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Tunnel
|
||||
{
|
||||
public class Ringlogger
|
||||
{
|
||||
private struct UnixTimestamp
|
||||
{
|
||||
private Int64 _ns;
|
||||
public UnixTimestamp(Int64 ns) => _ns = ns;
|
||||
public bool IsEmpty => _ns == 0;
|
||||
public static UnixTimestamp Empty => new UnixTimestamp(0);
|
||||
public static UnixTimestamp Now
|
||||
{
|
||||
get
|
||||
{
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var ns = (now.Subtract(DateTimeOffset.FromUnixTimeSeconds(0)).Ticks * 100) % 1000000000;
|
||||
return new UnixTimestamp(now.ToUnixTimeSeconds() * 1000000000 + ns);
|
||||
}
|
||||
}
|
||||
public Int64 Nanoseconds => _ns;
|
||||
public override string ToString()
|
||||
{
|
||||
return DateTimeOffset.FromUnixTimeSeconds(_ns / 1000000000).LocalDateTime.ToString("yyyy'-'MM'-'dd HH':'mm':'ss'.'") + ((_ns % 1000000000).ToString() + "00000").Substring(0, 6);
|
||||
}
|
||||
}
|
||||
private struct Line
|
||||
{
|
||||
private const int maxLineLength = 512;
|
||||
private const int offsetTimeNs = 0;
|
||||
private const int offsetLine = 8;
|
||||
|
||||
private readonly MemoryMappedViewAccessor _view;
|
||||
private readonly int _start;
|
||||
public Line(MemoryMappedViewAccessor view, UInt32 index) => (_view, _start) = (view, (int)(Log.HeaderBytes + index * Bytes));
|
||||
|
||||
public static int Bytes => maxLineLength + offsetLine;
|
||||
|
||||
public UnixTimestamp Timestamp
|
||||
{
|
||||
get => new UnixTimestamp(_view.ReadInt64(_start + offsetTimeNs));
|
||||
set => _view.Write(_start + offsetTimeNs, value.Nanoseconds);
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get
|
||||
{
|
||||
var textBytes = new byte[maxLineLength];
|
||||
_view.ReadArray(_start + offsetLine, textBytes, 0, textBytes.Length);
|
||||
var nullByte = Array.IndexOf<byte>(textBytes, 0);
|
||||
if (nullByte <= 0)
|
||||
return null;
|
||||
return Encoding.UTF8.GetString(textBytes, 0, nullByte);
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
_view.WriteArray(_start + offsetLine, new byte[maxLineLength], 0, maxLineLength);
|
||||
return;
|
||||
}
|
||||
var textBytes = Encoding.UTF8.GetBytes(value);
|
||||
var bytesToWrite = Math.Min(maxLineLength - 1, textBytes.Length);
|
||||
_view.Write(_start + offsetLine + bytesToWrite, (byte)0);
|
||||
_view.WriteArray(_start + offsetLine, textBytes, 0, bytesToWrite);
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var time = Timestamp;
|
||||
if (time.IsEmpty)
|
||||
return null;
|
||||
var text = Text;
|
||||
if (text == null)
|
||||
return null;
|
||||
return string.Format("{0}: {1}", time, text);
|
||||
}
|
||||
}
|
||||
private struct Log
|
||||
{
|
||||
private const UInt32 maxLines = 2048;
|
||||
private const UInt32 magic = 0xbadbabe;
|
||||
private const int offsetMagic = 0;
|
||||
private const int offsetNextIndex = 4;
|
||||
private const int offsetLines = 8;
|
||||
|
||||
private readonly MemoryMappedViewAccessor _view;
|
||||
public Log(MemoryMappedViewAccessor view) => _view = view;
|
||||
|
||||
public static int HeaderBytes => offsetLines;
|
||||
public static int Bytes => (int)(HeaderBytes + Line.Bytes * maxLines);
|
||||
|
||||
public UInt32 ExpectedMagic => magic;
|
||||
public UInt32 Magic
|
||||
{
|
||||
get => _view.ReadUInt32(offsetMagic);
|
||||
set => _view.Write(offsetMagic, value);
|
||||
}
|
||||
|
||||
public UInt32 NextIndex
|
||||
{
|
||||
get => _view.ReadUInt32(offsetNextIndex);
|
||||
set => _view.Write(offsetNextIndex, value);
|
||||
}
|
||||
public unsafe UInt32 InsertNextIndex()
|
||||
{
|
||||
byte* pointer = null;
|
||||
_view.SafeMemoryMappedViewHandle.AcquirePointer(ref pointer);
|
||||
var ret = (UInt32)Interlocked.Increment(ref Unsafe.AsRef<Int32>(pointer + offsetNextIndex));
|
||||
_view.SafeMemoryMappedViewHandle.ReleasePointer();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public UInt32 LineCount => maxLines;
|
||||
public Line this[UInt32 i] => new Line(_view, i % maxLines);
|
||||
|
||||
public void Clear() => _view.WriteArray(0, new byte[Bytes], 0, Bytes);
|
||||
}
|
||||
|
||||
private readonly Log _log;
|
||||
private readonly string _tag;
|
||||
|
||||
public Ringlogger(string filename, string tag)
|
||||
{
|
||||
var file = File.Open(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete);
|
||||
file.SetLength(Log.Bytes);
|
||||
var mmap = MemoryMappedFile.CreateFromFile(file, null, 0, MemoryMappedFileAccess.ReadWrite, HandleInheritability.None, false);
|
||||
var view = mmap.CreateViewAccessor(0, Log.Bytes, MemoryMappedFileAccess.ReadWrite);
|
||||
_log = new Log(view);
|
||||
if (_log.Magic != _log.ExpectedMagic)
|
||||
{
|
||||
_log.Clear();
|
||||
_log.Magic = _log.ExpectedMagic;
|
||||
}
|
||||
_tag = tag;
|
||||
}
|
||||
|
||||
public void Write(string line)
|
||||
{
|
||||
var time = UnixTimestamp.Now;
|
||||
var entry = _log[_log.InsertNextIndex() - 1];
|
||||
entry.Timestamp = UnixTimestamp.Empty;
|
||||
entry.Text = null;
|
||||
entry.Text = string.Format("[{0}] {1}", _tag, line.Trim());
|
||||
entry.Timestamp = time;
|
||||
}
|
||||
|
||||
public void WriteTo(TextWriter writer)
|
||||
{
|
||||
var start = _log.NextIndex;
|
||||
for (UInt32 i = 0; i < _log.LineCount; ++i)
|
||||
{
|
||||
var entry = _log[i + start];
|
||||
if (entry.Timestamp.IsEmpty)
|
||||
continue;
|
||||
var text = entry.ToString();
|
||||
if (text == null)
|
||||
continue;
|
||||
writer.WriteLine(text);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly UInt32 CursorAll = UInt32.MaxValue;
|
||||
public List<string> FollowFromCursor(ref UInt32 cursor)
|
||||
{
|
||||
var lines = new List<string>((int)_log.LineCount);
|
||||
var i = cursor;
|
||||
var all = cursor == CursorAll;
|
||||
if (all)
|
||||
i = _log.NextIndex;
|
||||
for (UInt32 l = 0; l < _log.LineCount; ++l, ++i)
|
||||
{
|
||||
if (!all && i % _log.LineCount == _log.NextIndex % _log.LineCount)
|
||||
break;
|
||||
var entry = _log[i];
|
||||
if (entry.Timestamp.IsEmpty)
|
||||
{
|
||||
if (all)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
cursor = (i + 1) % _log.LineCount;
|
||||
var text = entry.ToString();
|
||||
if (text == null)
|
||||
continue;
|
||||
lines.Add(text);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Pipes;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace Tunnel
|
||||
{
|
||||
public class Service
|
||||
{
|
||||
private const string LongName = "WireGuard Demo Box";
|
||||
private const string Description = "Demonstration tunnel for testing WireGuard";
|
||||
|
||||
[DllImport("tunnel.dll", EntryPoint = "WireGuardTunnelService", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool Run([MarshalAs(UnmanagedType.LPWStr)] string configFile);
|
||||
|
||||
public static Driver.Adapter GetAdapter(string configFile)
|
||||
{
|
||||
return new Driver.Adapter(Path.GetFileNameWithoutExtension(configFile));
|
||||
}
|
||||
|
||||
public static void Add(string configFile, bool ephemeral)
|
||||
{
|
||||
var tunnelName = Path.GetFileNameWithoutExtension(configFile);
|
||||
var shortName = String.Format("WireGuardTunnel${0}", tunnelName);
|
||||
var longName = String.Format("{0}: {1}", LongName, tunnelName);
|
||||
var exeName = Process.GetCurrentProcess().MainModule.FileName;
|
||||
var pathAndArgs = String.Format("\"{0}\" /service \"{1}\" {2}", exeName, configFile, Process.GetCurrentProcess().Id); //TODO: This is not the proper way to escape file args.
|
||||
|
||||
var scm = Win32.OpenSCManager(null, null, Win32.ScmAccessRights.AllAccess);
|
||||
if (scm == IntPtr.Zero)
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
try
|
||||
{
|
||||
var service = Win32.OpenService(scm, shortName, Win32.ServiceAccessRights.AllAccess);
|
||||
if (service != IntPtr.Zero)
|
||||
{
|
||||
Win32.CloseServiceHandle(service);
|
||||
Remove(configFile, true);
|
||||
}
|
||||
service = Win32.CreateService(scm, shortName, longName, Win32.ServiceAccessRights.AllAccess, Win32.ServiceType.Win32OwnProcess, Win32.ServiceStartType.Demand, Win32.ServiceError.Normal, pathAndArgs, null, IntPtr.Zero, "Nsi\0TcpIp\0", null, null);
|
||||
if (service == IntPtr.Zero)
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
try
|
||||
{
|
||||
var sidType = Win32.ServiceSidType.Unrestricted;
|
||||
if (!Win32.ChangeServiceConfig2(service, Win32.ServiceConfigType.SidInfo, ref sidType))
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
|
||||
var description = new Win32.ServiceDescription { lpDescription = Description };
|
||||
if (!Win32.ChangeServiceConfig2(service, Win32.ServiceConfigType.Description, ref description))
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
|
||||
if (!Win32.StartService(service, 0, null))
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
|
||||
if (ephemeral && !Win32.DeleteService(service))
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
finally
|
||||
{
|
||||
Win32.CloseServiceHandle(service);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Win32.CloseServiceHandle(scm);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Remove(string configFile, bool waitForStop)
|
||||
{
|
||||
var tunnelName = Path.GetFileNameWithoutExtension(configFile);
|
||||
var shortName = String.Format("WireGuardTunnel${0}", tunnelName);
|
||||
|
||||
var scm = Win32.OpenSCManager(null, null, Win32.ScmAccessRights.AllAccess);
|
||||
if (scm == IntPtr.Zero)
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
try
|
||||
{
|
||||
var service = Win32.OpenService(scm, shortName, Win32.ServiceAccessRights.AllAccess);
|
||||
if (service == IntPtr.Zero)
|
||||
return;
|
||||
try
|
||||
{
|
||||
var serviceStatus = new Win32.ServiceStatus();
|
||||
Win32.ControlService(service, Win32.ServiceControl.Stop, serviceStatus);
|
||||
|
||||
for (int i = 0; waitForStop && i < 180 && Win32.QueryServiceStatus(service, serviceStatus) && serviceStatus.dwCurrentState != Win32.ServiceState.Stopped; ++i)
|
||||
Thread.Sleep(1000);
|
||||
|
||||
if (!Win32.DeleteService(service) && Marshal.GetLastWin32Error() != 0x00000430)
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
finally
|
||||
{
|
||||
Win32.CloseServiceHandle(service);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Win32.CloseServiceHandle(scm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Tunnel
|
||||
{
|
||||
static class Win32
|
||||
{
|
||||
[Flags]
|
||||
public enum ScmAccessRights
|
||||
{
|
||||
Connect = 0x0001,
|
||||
CreateService = 0x0002,
|
||||
EnumerateService = 0x0004,
|
||||
Lock = 0x0008,
|
||||
QueryLockStatus = 0x0010,
|
||||
ModifyBootConfig = 0x0020,
|
||||
StandardRightsRequired = 0xF0000,
|
||||
AllAccess = (StandardRightsRequired | Connect | CreateService | EnumerateService | Lock | QueryLockStatus | ModifyBootConfig)
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ServiceAccessRights
|
||||
{
|
||||
QueryConfig = 0x1,
|
||||
ChangeConfig = 0x2,
|
||||
QueryStatus = 0x4,
|
||||
EnumerateDependants = 0x8,
|
||||
Start = 0x10,
|
||||
Stop = 0x20,
|
||||
PauseContinue = 0x40,
|
||||
Interrogate = 0x80,
|
||||
UserDefinedControl = 0x100,
|
||||
Delete = 0x00010000,
|
||||
StandardRightsRequired = 0xF0000,
|
||||
AllAccess = (StandardRightsRequired | QueryConfig | ChangeConfig | QueryStatus | EnumerateDependants | Start | Stop | PauseContinue | Interrogate | UserDefinedControl)
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ServiceStartType
|
||||
{
|
||||
Boot = 0x00000000,
|
||||
System = 0x00000001,
|
||||
Auto = 0x00000002,
|
||||
Demand = 0x00000003,
|
||||
Disabled = 0x00000004
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ServiceControl
|
||||
{
|
||||
Stop = 0x00000001,
|
||||
Pause = 0x00000002,
|
||||
Continue = 0x00000003,
|
||||
Interrogate = 0x00000004,
|
||||
Shutdown = 0x00000005,
|
||||
ParamChange = 0x00000006,
|
||||
NetBindAdd = 0x00000007,
|
||||
NetBindRemove = 0x00000008,
|
||||
NetBindEnable = 0x00000009,
|
||||
NetBindDisable = 0x0000000A
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ServiceError
|
||||
{
|
||||
Ignore = 0x00000000,
|
||||
Normal = 0x00000001,
|
||||
Severe = 0x00000002,
|
||||
Critical = 0x00000003
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ServiceSidType
|
||||
{
|
||||
None = 0x00000000,
|
||||
Unrestricted = 0x00000001,
|
||||
Restricted = 0x00000003
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ServiceType
|
||||
{
|
||||
KernelDriver = 0x00000001,
|
||||
FileSystemDriver = 0x00000002,
|
||||
Win32OwnProcess = 0x00000010,
|
||||
Win32ShareProcess = 0x00000020,
|
||||
InteractiveProcess = 0x00000100
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Size = 8192), ComVisible(false)]
|
||||
public struct ServiceSidInfo
|
||||
{
|
||||
public ServiceSidType serviceSidType;
|
||||
};
|
||||
|
||||
public enum ServiceState
|
||||
{
|
||||
Unknown = -1,
|
||||
NotFound = 0,
|
||||
Stopped = 1,
|
||||
StartPending = 2,
|
||||
StopPending = 3,
|
||||
Running = 4,
|
||||
ContinuePending = 5,
|
||||
PausePending = 6,
|
||||
Paused = 7
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class ServiceStatus
|
||||
{
|
||||
public int dwServiceType = 0;
|
||||
public ServiceState dwCurrentState = 0;
|
||||
public int dwControlsAccepted = 0;
|
||||
public int dwWin32ExitCode = 0;
|
||||
public int dwServiceSpecificExitCode = 0;
|
||||
public int dwCheckPoint = 0;
|
||||
public int dwWaitHint = 0;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Size = 8192), ComVisible(false)]
|
||||
public struct ServiceDescription
|
||||
{
|
||||
public String lpDescription;
|
||||
};
|
||||
|
||||
public enum ServiceConfigType
|
||||
{
|
||||
Description = 1,
|
||||
SidInfo = 5
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct IN_ADDR
|
||||
{
|
||||
public fixed byte bytes[4];
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct IN6_ADDR
|
||||
{
|
||||
public fixed byte bytes[16];
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SOCKADDR_IN
|
||||
{
|
||||
public ushort sin_family;
|
||||
public ushort sin_port;
|
||||
public IN_ADDR sin_addr;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SOCKADDR_IN6
|
||||
{
|
||||
public ushort sin6_family;
|
||||
public ushort sin6_port;
|
||||
public uint sin6_flowinfo;
|
||||
public IN6_ADDR sin6_addr;
|
||||
public uint sin6_scope_id;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct SOCKADDR_INET
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
[MarshalAs(UnmanagedType.Struct)]
|
||||
public SOCKADDR_IN Ipv4;
|
||||
|
||||
[FieldOffset(0)]
|
||||
[MarshalAs(UnmanagedType.Struct)]
|
||||
public SOCKADDR_IN6 Ipv6;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public ADDRESS_FAMILY si_family;
|
||||
}
|
||||
|
||||
public enum ADDRESS_FAMILY : UInt16
|
||||
{
|
||||
AF_UNSPEC = 0,
|
||||
AF_INET = 2,
|
||||
AF_INET6 = 23
|
||||
}
|
||||
|
||||
[DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern IntPtr OpenSCManager(string machineName, string databaseName, ScmAccessRights dwDesiredAccess);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, ServiceAccessRights dwDesiredAccess);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool CloseServiceHandle(IntPtr hSCObject);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool StartService(IntPtr hService, int dwNumServiceArgs, string[] lpServiceArgVectors);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr CreateService(IntPtr hSCManager, string lpServiceName, string lpDisplayName, ServiceAccessRights dwDesiredAccess, ServiceType dwServiceType, ServiceStartType dwStartType, ServiceError dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string lpDependencies, string lp, string lpPassword);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool DeleteService(IntPtr hService);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool ControlService(IntPtr hService, ServiceControl dwControl, ServiceStatus lpServiceStatus);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool QueryServiceStatus(IntPtr hService, ServiceStatus lpServiceStatus);
|
||||
|
||||
[DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig2", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool ChangeServiceConfig2(IntPtr hService, ServiceConfigType dwInfoLevel, ref ServiceSidType lpInfo);
|
||||
|
||||
[DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig2", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool ChangeServiceConfig2(IntPtr hService, ServiceConfigType dwInfoLevel, ref ServiceDescription lpInfo);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<RootNamespace>DemoUI</RootNamespace>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<AssemblyName>demo-client</AssemblyName>
|
||||
<Platforms>x64</Platforms>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<ApplicationManifest>DemoUI\app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Compile Update="DemoUI\MainWindow.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30804.86
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "demo-client", "demo-client.csproj", "{AADC81E1-0294-483B-ABAE-63DBE82436E9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{AADC81E1-0294-483B-ABAE-63DBE82436E9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AADC81E1-0294-483B-ABAE-63DBE82436E9}.Debug|x64.Build.0 = Debug|x64
|
||||
{AADC81E1-0294-483B-ABAE-63DBE82436E9}.Release|x64.ActiveCfg = Release|x64
|
||||
{AADC81E1-0294-483B-ABAE-63DBE82436E9}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {E410FD53-4E4A-4299-B6BD-CE91685DF7BE}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,48 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"C"
|
||||
"crypto/rand"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/crypto/curve25519"
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"golang.zx2c4.com/wireguard/windows/conf"
|
||||
"golang.zx2c4.com/wireguard/windows/tunnel"
|
||||
)
|
||||
|
||||
//export WireGuardTunnelService
|
||||
func WireGuardTunnelService(confFile16 *uint16) bool {
|
||||
confFile := windows.UTF16PtrToString(confFile16)
|
||||
conf.PresetRootDirectory(filepath.Dir(confFile))
|
||||
tunnel.UseFixedGUIDInsteadOfDeterministic = true
|
||||
err := tunnel.Run(confFile)
|
||||
if err != nil {
|
||||
log.Printf("Service run error: %v", err)
|
||||
}
|
||||
return err == nil
|
||||
}
|
||||
|
||||
//export WireGuardGenerateKeypair
|
||||
func WireGuardGenerateKeypair(publicKey, privateKey *byte) {
|
||||
publicKeyArray := (*[32]byte)(unsafe.Pointer(publicKey))
|
||||
privateKeyArray := (*[32]byte)(unsafe.Pointer(privateKey))
|
||||
n, err := rand.Read(privateKeyArray[:])
|
||||
if err != nil || n != len(privateKeyArray) {
|
||||
panic("Unable to generate random bytes")
|
||||
}
|
||||
privateKeyArray[0] &= 248
|
||||
privateKeyArray[31] = (privateKeyArray[31] & 127) | 64
|
||||
|
||||
curve25519.ScalarBaseMult(publicKeyArray, privateKeyArray)
|
||||
}
|
||||
|
||||
func main() {}
|
||||
22
go.mod
22
go.mod
@@ -1,20 +1,24 @@
|
||||
module golang.zx2c4.com/wireguard/windows
|
||||
module github.com/amnezia-vpn/amneziawg-windows-client
|
||||
|
||||
go 1.18
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/amnezia-vpn/awg-windows v0.1.4-0.20240424161542-e8e067a05ad4
|
||||
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
|
||||
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86
|
||||
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab
|
||||
golang.org/x/crypto v0.18.0
|
||||
golang.org/x/sys v0.16.0
|
||||
golang.org/x/text v0.14.0
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3
|
||||
)
|
||||
|
||||
require (
|
||||
golang.org/x/mod v0.4.2 // indirect
|
||||
golang.org/x/tools v0.1.7 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
github.com/amnezia-vpn/amnezia-wg v0.1.8 // indirect
|
||||
github.com/tevino/abool/v2 v2.1.0 // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/net v0.20.0 // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
|
||||
50
go.sum
50
go.sum
@@ -1,29 +1,31 @@
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
github.com/amnezia-vpn/amnezia-wg v0.1.8 h1:CuJ33YIuRbmuN6+Rs6n6qe2sVvDu1v1toRly9BHZgKM=
|
||||
github.com/amnezia-vpn/amnezia-wg v0.1.8/go.mod h1:vB51g4MZ8nCj3oEF5qg1YN/2JYEgKvd7+knuCFH4Tf0=
|
||||
github.com/amnezia-vpn/awg-windows v0.1.4-0.20240424161542-e8e067a05ad4 h1:07po/2reK/zDeYiTrkHH3AFV+triJII5s5e/RZ0ryNU=
|
||||
github.com/amnezia-vpn/awg-windows v0.1.4-0.20240424161542-e8e067a05ad4/go.mod h1:FKM2YNOa0fUgViVGuTMP09p5if/KwHMd9C2aMA+ueRo=
|
||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||
github.com/tevino/abool/v2 v2.1.0 h1:7w+Vf9f/5gmKT4m4qkayb33/92M+Um45F2BkHOR+L/c=
|
||||
github.com/tevino/abool/v2 v2.1.0/go.mod h1:+Lmlqk6bHDWHqN1cbxqhwEAwMPXgc8I1SDEamtseuXY=
|
||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc=
|
||||
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab h1:eHo2TTVBaAPw9lDGK2Gb9GyPMXT6g7O63W6sx3ylbzU=
|
||||
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||
golang.zx2c4.com/wireguard/windows v0.0.0-20210121140954-e7fc19d483bd h1:kAUzMAITME2MCtrXBaUa9P4tndiXGWO674k9gn6ZR28=
|
||||
golang.zx2c4.com/wireguard/windows v0.0.0-20210121140954-e7fc19d483bd/go.mod h1:Y+FYqVFaQO6a+1uigm0N0GiuaZrLEaBxEiJ8tfH9sMQ=
|
||||
golang.zx2c4.com/wireguard/windows v0.0.0-20210224134948-620c54ef6199 h1:ogXKLng/Myrt2odYTkleySGzQj/GWg9GV1AQ8P9NnU4=
|
||||
golang.zx2c4.com/wireguard/windows v0.0.0-20210224134948-620c54ef6199/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE=
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
|
||||
gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259 h1:TbRPT0HtzFP3Cno1zZo7yPzEEnfu8EjLfl6IU9VfqkQ=
|
||||
|
||||
@@ -21,7 +21,7 @@ if exist .deps\prepared goto :build
|
||||
rmdir /s /q .deps 2> NUL
|
||||
mkdir .deps || goto :error
|
||||
cd .deps || goto :error
|
||||
call :download wix-binaries.zip https://wixtoolset.org/downloads/v3.14.0.4118/wix314-binaries.zip 34dcbba9952902bfb710161bd45ee2e721ffa878db99f738285a21c9b09c6edb || goto :error
|
||||
call :download wix-binaries.zip https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip 6ac824e1642d6f7277d0ed7ea09411a508f6116ba6fae0aa5f2c7daa2ff43d31 || goto :error
|
||||
echo [+] Extracting wix-binaries.zip
|
||||
mkdir wix\bin || goto :error
|
||||
tar -xf wix-binaries.zip -C wix\bin || goto :error
|
||||
@@ -32,7 +32,7 @@ if exist .deps\prepared goto :build
|
||||
|
||||
:build
|
||||
if exist ..\sign.bat call ..\sign.bat
|
||||
set PATH=%BUILDDIR%..\.deps\llvm-mingw\bin;%PATH%
|
||||
set PATH=%BUILDDIR%..\.deps\llvm-mingw-20231128-ucrt-x86_64\bin;%PATH%
|
||||
set WIX=%BUILDDIR%.deps\wix\
|
||||
set CFLAGS=-O3 -Wall -std=gnu11 -DWINVER=0x0601 -D_WIN32_WINNT=0x0601 -municode -DUNICODE -D_UNICODE -DNDEBUG
|
||||
set LDFLAGS=-shared -s -Wl,--kill-at -Wl,--major-os-version=6 -Wl,--minor-os-version=1 -Wl,--major-subsystem-version=6 -Wl,--minor-subsystem-version=1 -Wl,--tsaware -Wl,--dynamicbase -Wl,--nxcompat -Wl,--export-all-symbols
|
||||
|
||||
@@ -84,6 +84,9 @@
|
||||
<File Source="..\$(var.WIREGUARD_PLATFORM)\wg.exe" KeyPath="yes" />
|
||||
<Environment Id="PATH" Name="PATH" System="yes" Action="set" Part="last" Permanent="no" Value="[WireGuardFolder]" />
|
||||
</Component>
|
||||
<Component Directory="WireGuardFolder" Id="WintunLibrary" Guid="ac88e408-9b78-4eb3-9d2a-99305f2e5a51">
|
||||
<File Source="..\$(var.WIREGUARD_PLATFORM)\wintun.dll" KeyPath="yes" />
|
||||
</Component>
|
||||
</ComponentGroup>
|
||||
|
||||
<!--
|
||||
|
||||
@@ -290,7 +290,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -326,7 +326,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -296,7 +296,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -309,7 +309,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -214,7 +214,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -296,7 +296,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -275,7 +275,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -296,7 +296,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -281,7 +281,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -290,7 +290,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -326,7 +326,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -311,7 +311,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -326,7 +326,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -202,7 +202,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -326,7 +326,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -326,7 +326,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -296,7 +296,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -156,7 +156,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -281,7 +281,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
@@ -281,7 +281,7 @@
|
||||
{
|
||||
"id": "Bytes",
|
||||
"string": "%[1]d",
|
||||
"type": "golang.zx2c4.com/wireguard/windows/conf.Bytes",
|
||||
"type": "github.com/amnezia-vpn/amneziawg-windows-client/conf.Bytes",
|
||||
"underlyingType": "uint64",
|
||||
"argNum": 1,
|
||||
"expr": "b"
|
||||
|
||||
30
main.go
30
main.go
@@ -18,15 +18,14 @@ import (
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"golang.zx2c4.com/wireguard/windows/conf"
|
||||
"golang.zx2c4.com/wireguard/windows/driver"
|
||||
"golang.zx2c4.com/wireguard/windows/elevate"
|
||||
"golang.zx2c4.com/wireguard/windows/l18n"
|
||||
"golang.zx2c4.com/wireguard/windows/manager"
|
||||
"golang.zx2c4.com/wireguard/windows/ringlogger"
|
||||
"golang.zx2c4.com/wireguard/windows/tunnel"
|
||||
"golang.zx2c4.com/wireguard/windows/ui"
|
||||
"golang.zx2c4.com/wireguard/windows/updater"
|
||||
"github.com/amnezia-vpn/awg-windows/tunnel"
|
||||
|
||||
"github.com/amnezia-vpn/amneziawg-windows-client/elevate"
|
||||
"github.com/amnezia-vpn/amneziawg-windows-client/l18n"
|
||||
"github.com/amnezia-vpn/amneziawg-windows-client/manager"
|
||||
"github.com/amnezia-vpn/amneziawg-windows-client/ringlogger"
|
||||
"github.com/amnezia-vpn/amneziawg-windows-client/ui"
|
||||
"github.com/amnezia-vpn/amneziawg-windows-client/updater"
|
||||
)
|
||||
|
||||
func setLogFile() {
|
||||
@@ -74,7 +73,6 @@ func usage() {
|
||||
"/ui CMD_READ_HANDLE CMD_WRITE_HANDLE CMD_EVENT_HANDLE LOG_MAPPING_HANDLE",
|
||||
"/dumplog [/tail]",
|
||||
"/update",
|
||||
"/removedriver",
|
||||
}
|
||||
builder := strings.Builder{}
|
||||
for _, flag := range flags {
|
||||
@@ -281,7 +279,7 @@ func main() {
|
||||
}
|
||||
file := os.NewFile(uintptr(outputHandle), "stdout")
|
||||
defer file.Close()
|
||||
logPath, err := conf.LogFile(false)
|
||||
logPath, err := manager.LogFile(false)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
@@ -314,16 +312,6 @@ func main() {
|
||||
}
|
||||
}
|
||||
return
|
||||
case "/removedriver":
|
||||
if len(os.Args) != 2 {
|
||||
usage()
|
||||
}
|
||||
_ = driver.UninstallLegacyWintun() // Best effort
|
||||
err := driver.Uninstall()
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
usage()
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ import (
|
||||
"golang.org/x/sys/windows/svc"
|
||||
"golang.org/x/sys/windows/svc/mgr"
|
||||
|
||||
"golang.zx2c4.com/wireguard/windows/conf"
|
||||
"github.com/amnezia-vpn/awg-windows/conf"
|
||||
"github.com/amnezia-vpn/awg-windows/services"
|
||||
)
|
||||
|
||||
var cachedServiceManager *mgr.Mgr
|
||||
@@ -129,7 +130,7 @@ func InstallTunnel(configPath string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
serviceName, err := conf.ServiceNameOfTunnel(name)
|
||||
serviceName, err := services.ServiceNameOfTunnel(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -182,7 +183,7 @@ func UninstallTunnel(name string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
serviceName, err := conf.ServiceNameOfTunnel(name)
|
||||
serviceName, err := services.ServiceNameOfTunnel(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -210,7 +211,7 @@ func changeTunnelServiceConfigFilePath(name, oldPath, newPath string) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
serviceName, err := conf.ServiceNameOfTunnel(name)
|
||||
serviceName, err := services.ServiceNameOfTunnel(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"golang.zx2c4.com/wireguard/windows/conf"
|
||||
"golang.zx2c4.com/wireguard/windows/updater"
|
||||
"github.com/amnezia-vpn/amneziawg-windows-client/updater"
|
||||
"github.com/amnezia-vpn/awg-windows/conf"
|
||||
)
|
||||
|
||||
type Tunnel struct {
|
||||
|
||||
@@ -19,8 +19,9 @@ import (
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/svc"
|
||||
|
||||
"golang.zx2c4.com/wireguard/windows/conf"
|
||||
"golang.zx2c4.com/wireguard/windows/updater"
|
||||
"github.com/amnezia-vpn/amneziawg-windows-client/updater"
|
||||
"github.com/amnezia-vpn/awg-windows/conf"
|
||||
"github.com/amnezia-vpn/awg-windows/services"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -48,7 +49,9 @@ func (s *ManagerService) StoredConfig(tunnelName string) (*conf.Config, error) {
|
||||
}
|
||||
|
||||
func (s *ManagerService) RuntimeConfig(tunnelName string) (*conf.Config, error) {
|
||||
storedConfig, err := conf.LoadFromName(tunnelName)
|
||||
log.Printf("[%s] RuntimeConfig", tunnelName)
|
||||
return nil, nil
|
||||
/*storedConfig, err := conf.LoadFromName(tunnelName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -67,7 +70,7 @@ func (s *ManagerService) RuntimeConfig(tunnelName string) (*conf.Config, error)
|
||||
if s.elevatedToken == 0 {
|
||||
conf.Redact()
|
||||
}
|
||||
return conf, nil
|
||||
return conf, nil*/
|
||||
}
|
||||
|
||||
func (s *ManagerService) Start(tunnelName string) error {
|
||||
@@ -81,11 +84,11 @@ func (s *ManagerService) Start(tunnelName string) error {
|
||||
tt := make([]string, 0, len(trackedTunnels))
|
||||
var inTransition string
|
||||
for t, state := range trackedTunnels {
|
||||
c2, err := conf.LoadFromName(t)
|
||||
/*c2, err := conf.LoadFromName(t)
|
||||
if err != nil || !c.IntersectsWith(c2) {
|
||||
// If we can't get the config, assume it doesn't intersect.
|
||||
continue
|
||||
}
|
||||
}*/
|
||||
tt = append(tt, t)
|
||||
if len(t) > 0 && (state == TunnelStarting || state == TunnelUnknown) {
|
||||
inTransition = t
|
||||
@@ -131,7 +134,7 @@ func (s *ManagerService) Stop(tunnelName string) error {
|
||||
}
|
||||
|
||||
func (s *ManagerService) WaitForStop(tunnelName string) error {
|
||||
serviceName, err := conf.ServiceNameOfTunnel(tunnelName)
|
||||
serviceName, err := services.ServiceNameOfTunnel(tunnelName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -162,7 +165,7 @@ func (s *ManagerService) Delete(tunnelName string) error {
|
||||
}
|
||||
|
||||
func (s *ManagerService) State(tunnelName string) (TunnelState, error) {
|
||||
serviceName, err := conf.ServiceNameOfTunnel(tunnelName)
|
||||
serviceName, err := services.ServiceNameOfTunnel(tunnelName)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
@@ -19,10 +20,10 @@ import (
|
||||
"golang.org/x/sys/windows/svc"
|
||||
"golang.zx2c4.com/wireguard/windows/driver"
|
||||
|
||||
"golang.zx2c4.com/wireguard/windows/conf"
|
||||
"golang.zx2c4.com/wireguard/windows/elevate"
|
||||
"golang.zx2c4.com/wireguard/windows/ringlogger"
|
||||
"golang.zx2c4.com/wireguard/windows/services"
|
||||
"github.com/amnezia-vpn/amneziawg-windows-client/elevate"
|
||||
"github.com/amnezia-vpn/amneziawg-windows-client/ringlogger"
|
||||
"github.com/amnezia-vpn/amneziawg-windows-client/services"
|
||||
"github.com/amnezia-vpn/awg-windows/conf"
|
||||
)
|
||||
|
||||
type managerService struct{}
|
||||
@@ -43,7 +44,7 @@ func (service *managerService) Execute(args []string, r <-chan svc.ChangeRequest
|
||||
}()
|
||||
|
||||
var logFile string
|
||||
logFile, err = conf.LogFile(true)
|
||||
logFile, err = LogFile(true)
|
||||
if err != nil {
|
||||
serviceError = services.ErrorRingloggerOpen
|
||||
return
|
||||
@@ -353,3 +354,11 @@ loop:
|
||||
func Run() error {
|
||||
return svc.Run("WireGuardManager", &managerService{})
|
||||
}
|
||||
|
||||
func LogFile(createRoot bool) (string, error) {
|
||||
root, err := conf.RootDirectory(createRoot)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(root, "log.bin"), nil
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ import (
|
||||
"golang.org/x/sys/windows/svc"
|
||||
"golang.org/x/sys/windows/svc/mgr"
|
||||
|
||||
"golang.zx2c4.com/wireguard/windows/conf"
|
||||
"golang.zx2c4.com/wireguard/windows/services"
|
||||
"github.com/amnezia-vpn/awg-windows/conf"
|
||||
"github.com/amnezia-vpn/awg-windows/services"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -280,7 +280,7 @@ func trackExistingTunnels() error {
|
||||
continue
|
||||
}
|
||||
trackedTunnelsLock.Unlock()
|
||||
serviceName, err := conf.ServiceNameOfTunnel(name)
|
||||
serviceName, err := services.ServiceNameOfTunnel(name)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
"time"
|
||||
_ "unsafe"
|
||||
|
||||
"golang.zx2c4.com/wireguard/windows/services"
|
||||
"golang.zx2c4.com/wireguard/windows/updater"
|
||||
"golang.zx2c4.com/wireguard/windows/version"
|
||||
"github.com/amnezia-vpn/amneziawg-windows-client/services"
|
||||
"github.com/amnezia-vpn/amneziawg-windows-client/updater"
|
||||
"github.com/amnezia-vpn/amneziawg-windows-client/version"
|
||||
)
|
||||
|
||||
//go:linkname fastrandn runtime.fastrandn
|
||||
|
||||
@@ -14,7 +14,6 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST manifest.xml
|
||||
7 ICON ui/icon/wireguard.ico
|
||||
8 ICON ui/icon/dot.ico
|
||||
wireguard.dll RCDATA wireguard.dll
|
||||
|
||||
#define VERSIONINFO_TEMPLATE(block_id, lang_id, codepage_id, file_desc, comments) \
|
||||
VS_VERSION_INFO VERSIONINFO \
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wireguard/windows/conf"
|
||||
"golang.zx2c4.com/wireguard/windows/services"
|
||||
"golang.zx2c4.com/wireguard/windows/tunnel/firewall"
|
||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||
)
|
||||
|
||||
func cleanupAddressesOnDisconnectedInterfaces(family winipcfg.AddressFamily, addresses []netip.Prefix) {
|
||||
if len(addresses) == 0 {
|
||||
return
|
||||
}
|
||||
addrHash := make(map[netip.Addr]bool, len(addresses))
|
||||
for i := range addresses {
|
||||
addrHash[addresses[i].Addr()] = true
|
||||
}
|
||||
interfaces, err := winipcfg.GetAdaptersAddresses(family, winipcfg.GAAFlagDefault)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, iface := range interfaces {
|
||||
if iface.OperStatus == winipcfg.IfOperStatusUp {
|
||||
continue
|
||||
}
|
||||
for address := iface.FirstUnicastAddress; address != nil; address = address.Next {
|
||||
if ip, _ := netip.AddrFromSlice(address.Address.IP()); addrHash[ip] {
|
||||
prefix := netip.PrefixFrom(ip, int(address.OnLinkPrefixLength))
|
||||
log.Printf("Cleaning up stale address %s from interface ‘%s’", prefix.String(), iface.FriendlyName())
|
||||
iface.LUID.DeleteIPAddress(prefix)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func configureInterface(family winipcfg.AddressFamily, conf *conf.Config, luid winipcfg.LUID) error {
|
||||
retryOnFailure := services.StartedAtBoot()
|
||||
tryTimes := 0
|
||||
startOver:
|
||||
var err error
|
||||
if tryTimes > 0 {
|
||||
log.Printf("Retrying interface configuration after failure because system just booted (T+%v): %v", windows.DurationSinceBoot(), err)
|
||||
time.Sleep(time.Second)
|
||||
retryOnFailure = retryOnFailure && tryTimes < 15
|
||||
}
|
||||
tryTimes++
|
||||
|
||||
estimatedRouteCount := 0
|
||||
for _, peer := range conf.Peers {
|
||||
estimatedRouteCount += len(peer.AllowedIPs)
|
||||
}
|
||||
routes := make(map[winipcfg.RouteData]bool, estimatedRouteCount)
|
||||
|
||||
foundDefault4 := false
|
||||
foundDefault6 := false
|
||||
for _, peer := range conf.Peers {
|
||||
for _, allowedip := range peer.AllowedIPs {
|
||||
route := winipcfg.RouteData{
|
||||
Destination: allowedip.Masked(),
|
||||
Metric: 0,
|
||||
}
|
||||
if allowedip.Addr().Is4() {
|
||||
if allowedip.Bits() == 0 {
|
||||
foundDefault4 = true
|
||||
}
|
||||
route.NextHop = netip.IPv4Unspecified()
|
||||
} else if allowedip.Addr().Is6() {
|
||||
if allowedip.Bits() == 0 {
|
||||
foundDefault6 = true
|
||||
}
|
||||
route.NextHop = netip.IPv6Unspecified()
|
||||
}
|
||||
routes[route] = true
|
||||
}
|
||||
}
|
||||
|
||||
deduplicatedRoutes := make([]*winipcfg.RouteData, 0, len(routes))
|
||||
for route := range routes {
|
||||
r := route
|
||||
deduplicatedRoutes = append(deduplicatedRoutes, &r)
|
||||
}
|
||||
|
||||
if !conf.Interface.TableOff {
|
||||
err = luid.SetRoutesForFamily(family, deduplicatedRoutes)
|
||||
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
|
||||
goto startOver
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("unable to set routes: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = luid.SetIPAddressesForFamily(family, conf.Interface.Addresses)
|
||||
if err == windows.ERROR_OBJECT_ALREADY_EXISTS {
|
||||
cleanupAddressesOnDisconnectedInterfaces(family, conf.Interface.Addresses)
|
||||
err = luid.SetIPAddressesForFamily(family, conf.Interface.Addresses)
|
||||
}
|
||||
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
|
||||
goto startOver
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("unable to set ips: %w", err)
|
||||
}
|
||||
|
||||
var ipif *winipcfg.MibIPInterfaceRow
|
||||
ipif, err = luid.IPInterface(family)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ipif.RouterDiscoveryBehavior = winipcfg.RouterDiscoveryDisabled
|
||||
ipif.DadTransmits = 0
|
||||
ipif.ManagedAddressConfigurationSupported = false
|
||||
ipif.OtherStatefulConfigurationSupported = false
|
||||
if conf.Interface.MTU > 0 {
|
||||
ipif.NLMTU = uint32(conf.Interface.MTU)
|
||||
}
|
||||
if (family == windows.AF_INET && foundDefault4) || (family == windows.AF_INET6 && foundDefault6) {
|
||||
ipif.UseAutomaticMetric = false
|
||||
ipif.Metric = 0
|
||||
}
|
||||
err = ipif.Set()
|
||||
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
|
||||
goto startOver
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("unable to set metric and MTU: %w", err)
|
||||
}
|
||||
|
||||
err = luid.SetDNS(family, conf.Interface.DNS, conf.Interface.DNSSearch)
|
||||
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
|
||||
goto startOver
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("unable to set DNS: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func enableFirewall(conf *conf.Config, luid winipcfg.LUID) error {
|
||||
doNotRestrict := true
|
||||
if len(conf.Peers) == 1 && !conf.Interface.TableOff {
|
||||
for _, allowedip := range conf.Peers[0].AllowedIPs {
|
||||
if allowedip.Bits() == 0 && allowedip == allowedip.Masked() {
|
||||
doNotRestrict = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Println("Enabling firewall rules")
|
||||
return firewall.EnableFirewall(uint64(luid), doNotRestrict, conf.Interface.DNS)
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"sort"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/crypto/blake2s"
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/text/unicode/norm"
|
||||
|
||||
"golang.zx2c4.com/wireguard/windows/conf"
|
||||
)
|
||||
|
||||
const (
|
||||
deterministicGUIDLabel = "Deterministic WireGuard Windows GUID v1 jason@zx2c4.com"
|
||||
fixedGUIDLabel = "Fixed WireGuard Windows GUID v1 jason@zx2c4.com"
|
||||
)
|
||||
|
||||
// Escape hatch for external consumers, not us.
|
||||
var UseFixedGUIDInsteadOfDeterministic = false
|
||||
|
||||
/* All peer public keys and allowed ips are sorted. Length/number fields are
|
||||
* little endian 32-bit. Hash input is:
|
||||
*
|
||||
* label || len(interface name) || interface name ||
|
||||
* interface public key || number of peers ||
|
||||
* peer public key || number of peer allowed ips ||
|
||||
* len(allowed ip string) || allowed ip/cidr in canonical string notation ||
|
||||
* len(allowed ip string) || allowed ip/cidr in canonical string notation ||
|
||||
* len(allowed ip string) || allowed ip/cidr in canonical string notation ||
|
||||
* ...
|
||||
* peer public key || number of peer allowed ips ||
|
||||
* len(allowed ip string) || allowed ip/cidr in canonical string notation ||
|
||||
* len(allowed ip string) || allowed ip/cidr in canonical string notation ||
|
||||
* len(allowed ip string) || allowed ip/cidr in canonical string notation ||
|
||||
* ...
|
||||
* ...
|
||||
*/
|
||||
|
||||
func deterministicGUID(c *conf.Config) *windows.GUID {
|
||||
b2, _ := blake2s.New256(nil)
|
||||
if !UseFixedGUIDInsteadOfDeterministic {
|
||||
b2.Write([]byte(deterministicGUIDLabel))
|
||||
} else {
|
||||
b2.Write([]byte(fixedGUIDLabel))
|
||||
}
|
||||
b2Number := func(i int) {
|
||||
if uint(i) > uint(^uint32(0)) {
|
||||
panic("length out of bounds")
|
||||
}
|
||||
var bytes [4]byte
|
||||
binary.LittleEndian.PutUint32(bytes[:], uint32(i))
|
||||
b2.Write(bytes[:])
|
||||
}
|
||||
b2String := func(s string) {
|
||||
bytes := []byte(s)
|
||||
bytes = norm.NFC.Bytes(bytes)
|
||||
b2Number(len(bytes))
|
||||
b2.Write(bytes)
|
||||
}
|
||||
b2Key := func(k *conf.Key) {
|
||||
b2.Write(k[:])
|
||||
}
|
||||
|
||||
b2String(c.Name)
|
||||
if !UseFixedGUIDInsteadOfDeterministic {
|
||||
b2Key(c.Interface.PrivateKey.Public())
|
||||
b2Number(len(c.Peers))
|
||||
sortedPeers := c.Peers
|
||||
sort.Slice(sortedPeers, func(i, j int) bool {
|
||||
return bytes.Compare(sortedPeers[i].PublicKey[:], sortedPeers[j].PublicKey[:]) < 0
|
||||
})
|
||||
for _, peer := range sortedPeers {
|
||||
b2Key(&peer.PublicKey)
|
||||
b2Number(len(peer.AllowedIPs))
|
||||
sortedAllowedIPs := peer.AllowedIPs
|
||||
sort.Slice(sortedAllowedIPs, func(i, j int) bool {
|
||||
if bi, bj := sortedAllowedIPs[i].Addr().BitLen(), sortedAllowedIPs[j].Addr().BitLen(); bi != bj {
|
||||
return bi < bj
|
||||
}
|
||||
if sortedAllowedIPs[i].Bits() != sortedAllowedIPs[j].Bits() {
|
||||
return sortedAllowedIPs[i].Bits() < sortedAllowedIPs[j].Bits()
|
||||
}
|
||||
return sortedAllowedIPs[i].Addr().Compare(sortedAllowedIPs[j].Addr()) < 0
|
||||
})
|
||||
for _, allowedip := range sortedAllowedIPs {
|
||||
b2String(allowedip.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
return (*windows.GUID)(unsafe.Pointer(&b2.Sum(nil)[0]))
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package firewall
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/netip"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type wfpObjectInstaller func(uintptr) error
|
||||
|
||||
//
|
||||
// Fundamental WireGuard specific WFP objects.
|
||||
//
|
||||
type baseObjects struct {
|
||||
provider windows.GUID
|
||||
filters windows.GUID
|
||||
}
|
||||
|
||||
var wfpSession uintptr
|
||||
|
||||
func createWfpSession() (uintptr, error) {
|
||||
sessionDisplayData, err := createWtFwpmDisplayData0("WireGuard", "WireGuard dynamic session")
|
||||
if err != nil {
|
||||
return 0, wrapErr(err)
|
||||
}
|
||||
|
||||
session := wtFwpmSession0{
|
||||
displayData: *sessionDisplayData,
|
||||
flags: cFWPM_SESSION_FLAG_DYNAMIC,
|
||||
txnWaitTimeoutInMSec: windows.INFINITE,
|
||||
}
|
||||
|
||||
sessionHandle := uintptr(0)
|
||||
|
||||
err = fwpmEngineOpen0(nil, cRPC_C_AUTHN_WINNT, nil, &session, unsafe.Pointer(&sessionHandle))
|
||||
if err != nil {
|
||||
return 0, wrapErr(err)
|
||||
}
|
||||
|
||||
return sessionHandle, nil
|
||||
}
|
||||
|
||||
func registerBaseObjects(session uintptr) (*baseObjects, error) {
|
||||
bo := &baseObjects{}
|
||||
var err error
|
||||
bo.provider, err = windows.GenerateGUID()
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
bo.filters, err = windows.GenerateGUID()
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
|
||||
//
|
||||
// Register provider.
|
||||
//
|
||||
{
|
||||
displayData, err := createWtFwpmDisplayData0("WireGuard", "WireGuard provider")
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
provider := wtFwpmProvider0{
|
||||
providerKey: bo.provider,
|
||||
displayData: *displayData,
|
||||
}
|
||||
err = fwpmProviderAdd0(session, &provider, 0)
|
||||
if err != nil {
|
||||
// TODO: cleanup entire call chain of these if failure?
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Register filters sublayer.
|
||||
//
|
||||
{
|
||||
displayData, err := createWtFwpmDisplayData0("WireGuard filters", "Permissive and blocking filters")
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
sublayer := wtFwpmSublayer0{
|
||||
subLayerKey: bo.filters,
|
||||
displayData: *displayData,
|
||||
providerKey: &bo.provider,
|
||||
weight: ^uint16(0),
|
||||
}
|
||||
err = fwpmSubLayerAdd0(session, &sublayer, 0)
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
return bo, nil
|
||||
}
|
||||
|
||||
func EnableFirewall(luid uint64, doNotRestrict bool, restrictToDNSServers []netip.Addr) error {
|
||||
if wfpSession != 0 {
|
||||
return errors.New("The firewall has already been enabled")
|
||||
}
|
||||
|
||||
session, err := createWfpSession()
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
objectInstaller := func(session uintptr) error {
|
||||
baseObjects, err := registerBaseObjects(session)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
err = permitWireGuardService(session, baseObjects, 15)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
if !doNotRestrict {
|
||||
if len(restrictToDNSServers) > 0 {
|
||||
err = blockDNS(restrictToDNSServers, session, baseObjects, 15, 14)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
err = permitLoopback(session, baseObjects, 13)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
err = permitTunInterface(session, baseObjects, 12, luid)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
err = permitDHCPIPv4(session, baseObjects, 12)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
err = permitDHCPIPv6(session, baseObjects, 12)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
err = permitNdp(session, baseObjects, 12)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
/* TODO: actually evaluate if this does anything and if we need this. It's layer 2; our other rules are layer 3.
|
||||
* In other words, if somebody complains, try enabling it. For now, keep it off.
|
||||
err = permitHyperV(session, baseObjects, 12)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
*/
|
||||
|
||||
err = blockAll(session, baseObjects, 0)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
err = runTransaction(session, objectInstaller)
|
||||
if err != nil {
|
||||
fwpmEngineClose0(session)
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
wfpSession = session
|
||||
return nil
|
||||
}
|
||||
|
||||
func DisableFirewall() {
|
||||
if wfpSession != 0 {
|
||||
fwpmEngineClose0(wfpSession)
|
||||
wfpSession = 0
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package firewall
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func runTransaction(session uintptr, operation wfpObjectInstaller) error {
|
||||
err := fwpmTransactionBegin0(session, 0)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
err = operation(session)
|
||||
if err != nil {
|
||||
fwpmTransactionAbort0(session)
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
err = fwpmTransactionCommit0(session)
|
||||
if err != nil {
|
||||
fwpmTransactionAbort0(session)
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createWtFwpmDisplayData0(name, description string) (*wtFwpmDisplayData0, error) {
|
||||
namePtr, err := windows.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
|
||||
descriptionPtr, err := windows.UTF16PtrFromString(description)
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
|
||||
return &wtFwpmDisplayData0{
|
||||
name: namePtr,
|
||||
description: descriptionPtr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func filterWeight(weight uint8) wtFwpValue0 {
|
||||
return wtFwpValue0{
|
||||
_type: cFWP_UINT8,
|
||||
value: uintptr(weight),
|
||||
}
|
||||
}
|
||||
|
||||
func wrapErr(err error) error {
|
||||
if _, ok := err.(syscall.Errno); !ok {
|
||||
return err
|
||||
}
|
||||
_, file, line, ok := runtime.Caller(1)
|
||||
if !ok {
|
||||
return fmt.Errorf("Firewall error at unknown location: %w", err)
|
||||
}
|
||||
return fmt.Errorf("Firewall error at %s:%d: %w", file, line, err)
|
||||
}
|
||||
|
||||
func getCurrentProcessSecurityDescriptor() (*windows.SECURITY_DESCRIPTOR, error) {
|
||||
var processToken windows.Token
|
||||
err := windows.OpenProcessToken(windows.CurrentProcess(), windows.TOKEN_QUERY, &processToken)
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
defer processToken.Close()
|
||||
gs, err := processToken.GetTokenGroups()
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
var sid *windows.SID
|
||||
for _, g := range gs.AllGroups() {
|
||||
if g.Attributes != windows.SE_GROUP_ENABLED|windows.SE_GROUP_ENABLED_BY_DEFAULT|windows.SE_GROUP_OWNER {
|
||||
continue
|
||||
}
|
||||
// We could be checking != 6, but hopefully Microsoft will update
|
||||
// RtlCreateServiceSid to use SHA2, which will then likely bump
|
||||
// this up. So instead just roll with a minimum.
|
||||
if !g.Sid.IsValid() || g.Sid.IdentifierAuthority() != windows.SECURITY_NT_AUTHORITY || g.Sid.SubAuthorityCount() < 6 || g.Sid.SubAuthority(0) != 80 {
|
||||
continue
|
||||
}
|
||||
sid = g.Sid
|
||||
break
|
||||
}
|
||||
if sid == nil {
|
||||
return nil, wrapErr(windows.ERROR_NO_SUCH_GROUP)
|
||||
}
|
||||
|
||||
access := []windows.EXPLICIT_ACCESS{{
|
||||
AccessPermissions: cFWP_ACTRL_MATCH_FILTER,
|
||||
AccessMode: windows.GRANT_ACCESS,
|
||||
Trustee: windows.TRUSTEE{
|
||||
TrusteeForm: windows.TRUSTEE_IS_SID,
|
||||
TrusteeType: windows.TRUSTEE_IS_GROUP,
|
||||
TrusteeValue: windows.TrusteeValueFromSID(sid),
|
||||
},
|
||||
}}
|
||||
dacl, err := windows.ACLFromEntries(access, nil)
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
sd, err := windows.NewSecurityDescriptor()
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
err = sd.SetDACL(dacl, true, false)
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
sd, err = sd.ToSelfRelative()
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
return sd, nil
|
||||
}
|
||||
|
||||
func getCurrentProcessAppID() (*wtFwpByteBlob, error) {
|
||||
currentFile, err := os.Executable()
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
|
||||
curFilePtr, err := windows.UTF16PtrFromString(currentFile)
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
|
||||
var appID *wtFwpByteBlob
|
||||
err = fwpmGetAppIdFromFileName0(curFilePtr, unsafe.Pointer(&appID))
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
return appID, nil
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package firewall
|
||||
|
||||
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go syscall_windows.go
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,36 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package firewall
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/fwpmu/nf-fwpmu-fwpmengineopen0
|
||||
//sys fwpmEngineOpen0(serverName *uint16, authnService wtRpcCAuthN, authIdentity *uintptr, session *wtFwpmSession0, engineHandle unsafe.Pointer) (err error) [failretval!=0] = fwpuclnt.FwpmEngineOpen0
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/fwpmu/nf-fwpmu-fwpmengineclose0
|
||||
//sys fwpmEngineClose0(engineHandle uintptr) (err error) [failretval!=0] = fwpuclnt.FwpmEngineClose0
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/fwpmu/nf-fwpmu-fwpmsublayeradd0
|
||||
//sys fwpmSubLayerAdd0(engineHandle uintptr, subLayer *wtFwpmSublayer0, sd uintptr) (err error) [failretval!=0] = fwpuclnt.FwpmSubLayerAdd0
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/fwpmu/nf-fwpmu-fwpmgetappidfromfilename0
|
||||
//sys fwpmGetAppIdFromFileName0(fileName *uint16, appID unsafe.Pointer) (err error) [failretval!=0] = fwpuclnt.FwpmGetAppIdFromFileName0
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/fwpmu/nf-fwpmu-fwpmfreememory0
|
||||
//sys fwpmFreeMemory0(p unsafe.Pointer) = fwpuclnt.FwpmFreeMemory0
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/fwpmu/nf-fwpmu-fwpmfilteradd0
|
||||
//sys fwpmFilterAdd0(engineHandle uintptr, filter *wtFwpmFilter0, sd uintptr, id *uint64) (err error) [failretval!=0] = fwpuclnt.FwpmFilterAdd0
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/Fwpmu/nf-fwpmu-fwpmtransactionbegin0
|
||||
//sys fwpmTransactionBegin0(engineHandle uintptr, flags uint32) (err error) [failretval!=0] = fwpuclnt.FwpmTransactionBegin0
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/fwpmu/nf-fwpmu-fwpmtransactioncommit0
|
||||
//sys fwpmTransactionCommit0(engineHandle uintptr) (err error) [failretval!=0] = fwpuclnt.FwpmTransactionCommit0
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/fwpmu/nf-fwpmu-fwpmtransactionabort0
|
||||
//sys fwpmTransactionAbort0(engineHandle uintptr) (err error) [failretval!=0] = fwpuclnt.FwpmTransactionAbort0
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/fwpmu/nf-fwpmu-fwpmprovideradd0
|
||||
//sys fwpmProviderAdd0(engineHandle uintptr, provider *wtFwpmProvider0, sd uintptr) (err error) [failretval!=0] = fwpuclnt.FwpmProviderAdd0
|
||||
@@ -1,412 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package firewall
|
||||
|
||||
import "golang.org/x/sys/windows"
|
||||
|
||||
const (
|
||||
anysizeArray = 1 // ANYSIZE_ARRAY defined in winnt.h
|
||||
|
||||
wtFwpBitmapArray64_Size = 8
|
||||
|
||||
wtFwpByteArray16_Size = 16
|
||||
|
||||
wtFwpByteArray6_Size = 6
|
||||
|
||||
wtFwpmAction0_Size = 20
|
||||
wtFwpmAction0_filterType_Offset = 4
|
||||
|
||||
wtFwpV4AddrAndMask_Size = 8
|
||||
wtFwpV4AddrAndMask_mask_Offset = 4
|
||||
|
||||
wtFwpV6AddrAndMask_Size = 17
|
||||
wtFwpV6AddrAndMask_prefixLength_Offset = 16
|
||||
)
|
||||
|
||||
type wtFwpActionFlag uint32
|
||||
|
||||
const (
|
||||
cFWP_ACTION_FLAG_TERMINATING wtFwpActionFlag = 0x00001000
|
||||
cFWP_ACTION_FLAG_NON_TERMINATING wtFwpActionFlag = 0x00002000
|
||||
cFWP_ACTION_FLAG_CALLOUT wtFwpActionFlag = 0x00004000
|
||||
)
|
||||
|
||||
// FWP_ACTION_TYPE defined in fwptypes.h
|
||||
type wtFwpActionType uint32
|
||||
|
||||
const (
|
||||
cFWP_ACTION_BLOCK wtFwpActionType = wtFwpActionType(0x00000001 | cFWP_ACTION_FLAG_TERMINATING)
|
||||
cFWP_ACTION_PERMIT wtFwpActionType = wtFwpActionType(0x00000002 | cFWP_ACTION_FLAG_TERMINATING)
|
||||
cFWP_ACTION_CALLOUT_TERMINATING wtFwpActionType = wtFwpActionType(0x00000003 | cFWP_ACTION_FLAG_CALLOUT | cFWP_ACTION_FLAG_TERMINATING)
|
||||
cFWP_ACTION_CALLOUT_INSPECTION wtFwpActionType = wtFwpActionType(0x00000004 | cFWP_ACTION_FLAG_CALLOUT | cFWP_ACTION_FLAG_NON_TERMINATING)
|
||||
cFWP_ACTION_CALLOUT_UNKNOWN wtFwpActionType = wtFwpActionType(0x00000005 | cFWP_ACTION_FLAG_CALLOUT)
|
||||
cFWP_ACTION_CONTINUE wtFwpActionType = wtFwpActionType(0x00000006 | cFWP_ACTION_FLAG_NON_TERMINATING)
|
||||
cFWP_ACTION_NONE wtFwpActionType = 0x00000007
|
||||
cFWP_ACTION_NONE_NO_MATCH wtFwpActionType = 0x00000008
|
||||
cFWP_ACTION_BITMAP_INDEX_SET wtFwpActionType = 0x00000009
|
||||
)
|
||||
|
||||
// FWP_BYTE_BLOB defined in fwptypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwptypes/ns-fwptypes-fwp_byte_blob_)
|
||||
type wtFwpByteBlob struct {
|
||||
size uint32
|
||||
data *uint8
|
||||
}
|
||||
|
||||
// FWP_MATCH_TYPE defined in fwptypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwptypes/ne-fwptypes-fwp_match_type_)
|
||||
type wtFwpMatchType uint32
|
||||
|
||||
const (
|
||||
cFWP_MATCH_EQUAL wtFwpMatchType = 0
|
||||
cFWP_MATCH_GREATER wtFwpMatchType = cFWP_MATCH_EQUAL + 1
|
||||
cFWP_MATCH_LESS wtFwpMatchType = cFWP_MATCH_GREATER + 1
|
||||
cFWP_MATCH_GREATER_OR_EQUAL wtFwpMatchType = cFWP_MATCH_LESS + 1
|
||||
cFWP_MATCH_LESS_OR_EQUAL wtFwpMatchType = cFWP_MATCH_GREATER_OR_EQUAL + 1
|
||||
cFWP_MATCH_RANGE wtFwpMatchType = cFWP_MATCH_LESS_OR_EQUAL + 1
|
||||
cFWP_MATCH_FLAGS_ALL_SET wtFwpMatchType = cFWP_MATCH_RANGE + 1
|
||||
cFWP_MATCH_FLAGS_ANY_SET wtFwpMatchType = cFWP_MATCH_FLAGS_ALL_SET + 1
|
||||
cFWP_MATCH_FLAGS_NONE_SET wtFwpMatchType = cFWP_MATCH_FLAGS_ANY_SET + 1
|
||||
cFWP_MATCH_EQUAL_CASE_INSENSITIVE wtFwpMatchType = cFWP_MATCH_FLAGS_NONE_SET + 1
|
||||
cFWP_MATCH_NOT_EQUAL wtFwpMatchType = cFWP_MATCH_EQUAL_CASE_INSENSITIVE + 1
|
||||
cFWP_MATCH_PREFIX wtFwpMatchType = cFWP_MATCH_NOT_EQUAL + 1
|
||||
cFWP_MATCH_NOT_PREFIX wtFwpMatchType = cFWP_MATCH_PREFIX + 1
|
||||
cFWP_MATCH_TYPE_MAX wtFwpMatchType = cFWP_MATCH_NOT_PREFIX + 1
|
||||
)
|
||||
|
||||
// FWPM_ACTION0 defined in fwpmtypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwpmtypes/ns-fwpmtypes-fwpm_action0_)
|
||||
type wtFwpmAction0 struct {
|
||||
_type wtFwpActionType
|
||||
filterType windows.GUID // Windows type: GUID
|
||||
}
|
||||
|
||||
// Defined in fwpmu.h. 4cd62a49-59c3-4969-b7f3-bda5d32890a4
|
||||
var cFWPM_CONDITION_IP_LOCAL_INTERFACE = windows.GUID{
|
||||
Data1: 0x4cd62a49,
|
||||
Data2: 0x59c3,
|
||||
Data3: 0x4969,
|
||||
Data4: [8]byte{0xb7, 0xf3, 0xbd, 0xa5, 0xd3, 0x28, 0x90, 0xa4},
|
||||
}
|
||||
|
||||
// Defined in fwpmu.h. b235ae9a-1d64-49b8-a44c-5ff3d9095045
|
||||
var cFWPM_CONDITION_IP_REMOTE_ADDRESS = windows.GUID{
|
||||
Data1: 0xb235ae9a,
|
||||
Data2: 0x1d64,
|
||||
Data3: 0x49b8,
|
||||
Data4: [8]byte{0xa4, 0x4c, 0x5f, 0xf3, 0xd9, 0x09, 0x50, 0x45},
|
||||
}
|
||||
|
||||
// Defined in fwpmu.h. 3971ef2b-623e-4f9a-8cb1-6e79b806b9a7
|
||||
var cFWPM_CONDITION_IP_PROTOCOL = windows.GUID{
|
||||
Data1: 0x3971ef2b,
|
||||
Data2: 0x623e,
|
||||
Data3: 0x4f9a,
|
||||
Data4: [8]byte{0x8c, 0xb1, 0x6e, 0x79, 0xb8, 0x06, 0xb9, 0xa7},
|
||||
}
|
||||
|
||||
// Defined in fwpmu.h. 0c1ba1af-5765-453f-af22-a8f791ac775b
|
||||
var cFWPM_CONDITION_IP_LOCAL_PORT = windows.GUID{
|
||||
Data1: 0x0c1ba1af,
|
||||
Data2: 0x5765,
|
||||
Data3: 0x453f,
|
||||
Data4: [8]byte{0xaf, 0x22, 0xa8, 0xf7, 0x91, 0xac, 0x77, 0x5b},
|
||||
}
|
||||
|
||||
// Defined in fwpmu.h. c35a604d-d22b-4e1a-91b4-68f674ee674b
|
||||
var cFWPM_CONDITION_IP_REMOTE_PORT = windows.GUID{
|
||||
Data1: 0xc35a604d,
|
||||
Data2: 0xd22b,
|
||||
Data3: 0x4e1a,
|
||||
Data4: [8]byte{0x91, 0xb4, 0x68, 0xf6, 0x74, 0xee, 0x67, 0x4b},
|
||||
}
|
||||
|
||||
// Defined in fwpmu.h. d78e1e87-8644-4ea5-9437-d809ecefc971
|
||||
var cFWPM_CONDITION_ALE_APP_ID = windows.GUID{
|
||||
Data1: 0xd78e1e87,
|
||||
Data2: 0x8644,
|
||||
Data3: 0x4ea5,
|
||||
Data4: [8]byte{0x94, 0x37, 0xd8, 0x09, 0xec, 0xef, 0xc9, 0x71},
|
||||
}
|
||||
|
||||
// af043a0a-b34d-4f86-979c-c90371af6e66
|
||||
var cFWPM_CONDITION_ALE_USER_ID = windows.GUID{
|
||||
Data1: 0xaf043a0a,
|
||||
Data2: 0xb34d,
|
||||
Data3: 0x4f86,
|
||||
Data4: [8]byte{0x97, 0x9c, 0xc9, 0x03, 0x71, 0xaf, 0x6e, 0x66},
|
||||
}
|
||||
|
||||
// d9ee00de-c1ef-4617-bfe3-ffd8f5a08957
|
||||
var cFWPM_CONDITION_IP_LOCAL_ADDRESS = windows.GUID{
|
||||
Data1: 0xd9ee00de,
|
||||
Data2: 0xc1ef,
|
||||
Data3: 0x4617,
|
||||
Data4: [8]byte{0xbf, 0xe3, 0xff, 0xd8, 0xf5, 0xa0, 0x89, 0x57},
|
||||
}
|
||||
|
||||
var (
|
||||
cFWPM_CONDITION_ICMP_TYPE = cFWPM_CONDITION_IP_LOCAL_PORT
|
||||
cFWPM_CONDITION_ICMP_CODE = cFWPM_CONDITION_IP_REMOTE_PORT
|
||||
)
|
||||
|
||||
// 7bc43cbf-37ba-45f1-b74a-82ff518eeb10
|
||||
var cFWPM_CONDITION_L2_FLAGS = windows.GUID{
|
||||
Data1: 0x7bc43cbf,
|
||||
Data2: 0x37ba,
|
||||
Data3: 0x45f1,
|
||||
Data4: [8]byte{0xb7, 0x4a, 0x82, 0xff, 0x51, 0x8e, 0xeb, 0x10},
|
||||
}
|
||||
|
||||
type wtFwpmL2Flags uint32
|
||||
|
||||
const cFWP_CONDITION_L2_IS_VM2VM wtFwpmL2Flags = 0x00000010
|
||||
|
||||
var cFWPM_CONDITION_FLAGS = windows.GUID{
|
||||
Data1: 0x632ce23b,
|
||||
Data2: 0x5167,
|
||||
Data3: 0x435c,
|
||||
Data4: [8]byte{0x86, 0xd7, 0xe9, 0x03, 0x68, 0x4a, 0xa8, 0x0c},
|
||||
}
|
||||
|
||||
type wtFwpmFlags uint32
|
||||
|
||||
const cFWP_CONDITION_FLAG_IS_LOOPBACK wtFwpmFlags = 0x00000001
|
||||
|
||||
// Defined in fwpmtypes.h
|
||||
type wtFwpmFilterFlags uint32
|
||||
|
||||
const (
|
||||
cFWPM_FILTER_FLAG_NONE wtFwpmFilterFlags = 0x00000000
|
||||
cFWPM_FILTER_FLAG_PERSISTENT wtFwpmFilterFlags = 0x00000001
|
||||
cFWPM_FILTER_FLAG_BOOTTIME wtFwpmFilterFlags = 0x00000002
|
||||
cFWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT wtFwpmFilterFlags = 0x00000004
|
||||
cFWPM_FILTER_FLAG_CLEAR_ACTION_RIGHT wtFwpmFilterFlags = 0x00000008
|
||||
cFWPM_FILTER_FLAG_PERMIT_IF_CALLOUT_UNREGISTERED wtFwpmFilterFlags = 0x00000010
|
||||
cFWPM_FILTER_FLAG_DISABLED wtFwpmFilterFlags = 0x00000020
|
||||
cFWPM_FILTER_FLAG_INDEXED wtFwpmFilterFlags = 0x00000040
|
||||
cFWPM_FILTER_FLAG_HAS_SECURITY_REALM_PROVIDER_CONTEXT wtFwpmFilterFlags = 0x00000080
|
||||
cFWPM_FILTER_FLAG_SYSTEMOS_ONLY wtFwpmFilterFlags = 0x00000100
|
||||
cFWPM_FILTER_FLAG_GAMEOS_ONLY wtFwpmFilterFlags = 0x00000200
|
||||
cFWPM_FILTER_FLAG_SILENT_MODE wtFwpmFilterFlags = 0x00000400
|
||||
cFWPM_FILTER_FLAG_IPSEC_NO_ACQUIRE_INITIATE wtFwpmFilterFlags = 0x00000800
|
||||
)
|
||||
|
||||
// FWPM_LAYER_ALE_AUTH_CONNECT_V4 (c38d57d1-05a7-4c33-904f-7fbceee60e82) defined in fwpmu.h
|
||||
var cFWPM_LAYER_ALE_AUTH_CONNECT_V4 = windows.GUID{
|
||||
Data1: 0xc38d57d1,
|
||||
Data2: 0x05a7,
|
||||
Data3: 0x4c33,
|
||||
Data4: [8]byte{0x90, 0x4f, 0x7f, 0xbc, 0xee, 0xe6, 0x0e, 0x82},
|
||||
}
|
||||
|
||||
// e1cd9fe7-f4b5-4273-96c0-592e487b8650
|
||||
var cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4 = windows.GUID{
|
||||
Data1: 0xe1cd9fe7,
|
||||
Data2: 0xf4b5,
|
||||
Data3: 0x4273,
|
||||
Data4: [8]byte{0x96, 0xc0, 0x59, 0x2e, 0x48, 0x7b, 0x86, 0x50},
|
||||
}
|
||||
|
||||
// FWPM_LAYER_ALE_AUTH_CONNECT_V6 (4a72393b-319f-44bc-84c3-ba54dcb3b6b4) defined in fwpmu.h
|
||||
var cFWPM_LAYER_ALE_AUTH_CONNECT_V6 = windows.GUID{
|
||||
Data1: 0x4a72393b,
|
||||
Data2: 0x319f,
|
||||
Data3: 0x44bc,
|
||||
Data4: [8]byte{0x84, 0xc3, 0xba, 0x54, 0xdc, 0xb3, 0xb6, 0xb4},
|
||||
}
|
||||
|
||||
// a3b42c97-9f04-4672-b87e-cee9c483257f
|
||||
var cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6 = windows.GUID{
|
||||
Data1: 0xa3b42c97,
|
||||
Data2: 0x9f04,
|
||||
Data3: 0x4672,
|
||||
Data4: [8]byte{0xb8, 0x7e, 0xce, 0xe9, 0xc4, 0x83, 0x25, 0x7f},
|
||||
}
|
||||
|
||||
// 94c44912-9d6f-4ebf-b995-05ab8a088d1b
|
||||
var cFWPM_LAYER_OUTBOUND_MAC_FRAME_NATIVE = windows.GUID{
|
||||
Data1: 0x94c44912,
|
||||
Data2: 0x9d6f,
|
||||
Data3: 0x4ebf,
|
||||
Data4: [8]byte{0xb9, 0x95, 0x05, 0xab, 0x8a, 0x08, 0x8d, 0x1b},
|
||||
}
|
||||
|
||||
// d4220bd3-62ce-4f08-ae88-b56e8526df50
|
||||
var cFWPM_LAYER_INBOUND_MAC_FRAME_NATIVE = windows.GUID{
|
||||
Data1: 0xd4220bd3,
|
||||
Data2: 0x62ce,
|
||||
Data3: 0x4f08,
|
||||
Data4: [8]byte{0xae, 0x88, 0xb5, 0x6e, 0x85, 0x26, 0xdf, 0x50},
|
||||
}
|
||||
|
||||
// FWP_BITMAP_ARRAY64 defined in fwtypes.h
|
||||
type wtFwpBitmapArray64 struct {
|
||||
bitmapArray64 [8]uint8 // Windows type: [8]UINT8
|
||||
}
|
||||
|
||||
// FWP_BYTE_ARRAY6 defined in fwtypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwptypes/ns-fwptypes-fwp_byte_array6_)
|
||||
type wtFwpByteArray6 struct {
|
||||
byteArray6 [6]uint8 // Windows type: [6]UINT8
|
||||
}
|
||||
|
||||
// FWP_BYTE_ARRAY16 defined in fwptypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwptypes/ns-fwptypes-fwp_byte_array16_)
|
||||
type wtFwpByteArray16 struct {
|
||||
byteArray16 [16]uint8 // Windows type [16]UINT8
|
||||
}
|
||||
|
||||
// FWP_CONDITION_VALUE0 defined in fwptypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwptypes/ns-fwptypes-fwp_condition_value0).
|
||||
type wtFwpConditionValue0 wtFwpValue0
|
||||
|
||||
// FWP_DATA_TYPE defined in fwptypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwptypes/ne-fwptypes-fwp_data_type_)
|
||||
type wtFwpDataType uint
|
||||
|
||||
const (
|
||||
cFWP_EMPTY wtFwpDataType = 0
|
||||
cFWP_UINT8 wtFwpDataType = cFWP_EMPTY + 1
|
||||
cFWP_UINT16 wtFwpDataType = cFWP_UINT8 + 1
|
||||
cFWP_UINT32 wtFwpDataType = cFWP_UINT16 + 1
|
||||
cFWP_UINT64 wtFwpDataType = cFWP_UINT32 + 1
|
||||
cFWP_INT8 wtFwpDataType = cFWP_UINT64 + 1
|
||||
cFWP_INT16 wtFwpDataType = cFWP_INT8 + 1
|
||||
cFWP_INT32 wtFwpDataType = cFWP_INT16 + 1
|
||||
cFWP_INT64 wtFwpDataType = cFWP_INT32 + 1
|
||||
cFWP_FLOAT wtFwpDataType = cFWP_INT64 + 1
|
||||
cFWP_DOUBLE wtFwpDataType = cFWP_FLOAT + 1
|
||||
cFWP_BYTE_ARRAY16_TYPE wtFwpDataType = cFWP_DOUBLE + 1
|
||||
cFWP_BYTE_BLOB_TYPE wtFwpDataType = cFWP_BYTE_ARRAY16_TYPE + 1
|
||||
cFWP_SID wtFwpDataType = cFWP_BYTE_BLOB_TYPE + 1
|
||||
cFWP_SECURITY_DESCRIPTOR_TYPE wtFwpDataType = cFWP_SID + 1
|
||||
cFWP_TOKEN_INFORMATION_TYPE wtFwpDataType = cFWP_SECURITY_DESCRIPTOR_TYPE + 1
|
||||
cFWP_TOKEN_ACCESS_INFORMATION_TYPE wtFwpDataType = cFWP_TOKEN_INFORMATION_TYPE + 1
|
||||
cFWP_UNICODE_STRING_TYPE wtFwpDataType = cFWP_TOKEN_ACCESS_INFORMATION_TYPE + 1
|
||||
cFWP_BYTE_ARRAY6_TYPE wtFwpDataType = cFWP_UNICODE_STRING_TYPE + 1
|
||||
cFWP_BITMAP_INDEX_TYPE wtFwpDataType = cFWP_BYTE_ARRAY6_TYPE + 1
|
||||
cFWP_BITMAP_ARRAY64_TYPE wtFwpDataType = cFWP_BITMAP_INDEX_TYPE + 1
|
||||
cFWP_SINGLE_DATA_TYPE_MAX wtFwpDataType = 0xff
|
||||
cFWP_V4_ADDR_MASK wtFwpDataType = cFWP_SINGLE_DATA_TYPE_MAX + 1
|
||||
cFWP_V6_ADDR_MASK wtFwpDataType = cFWP_V4_ADDR_MASK + 1
|
||||
cFWP_RANGE_TYPE wtFwpDataType = cFWP_V6_ADDR_MASK + 1
|
||||
cFWP_DATA_TYPE_MAX wtFwpDataType = cFWP_RANGE_TYPE + 1
|
||||
)
|
||||
|
||||
// FWP_V4_ADDR_AND_MASK defined in fwptypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwptypes/ns-fwptypes-fwp_v4_addr_and_mask).
|
||||
type wtFwpV4AddrAndMask struct {
|
||||
addr uint32
|
||||
mask uint32
|
||||
}
|
||||
|
||||
// FWP_V6_ADDR_AND_MASK defined in fwptypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwptypes/ns-fwptypes-fwp_v6_addr_and_mask).
|
||||
type wtFwpV6AddrAndMask struct {
|
||||
addr [16]uint8
|
||||
prefixLength uint8
|
||||
}
|
||||
|
||||
// FWP_VALUE0 defined in fwptypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwptypes/ns-fwptypes-fwp_value0_)
|
||||
type wtFwpValue0 struct {
|
||||
_type wtFwpDataType
|
||||
value uintptr
|
||||
}
|
||||
|
||||
// FWPM_DISPLAY_DATA0 defined in fwptypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwptypes/ns-fwptypes-fwpm_display_data0).
|
||||
type wtFwpmDisplayData0 struct {
|
||||
name *uint16 // Windows type: *wchar_t
|
||||
description *uint16 // Windows type: *wchar_t
|
||||
}
|
||||
|
||||
// FWPM_FILTER_CONDITION0 defined in fwpmtypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwpmtypes/ns-fwpmtypes-fwpm_filter_condition0).
|
||||
type wtFwpmFilterCondition0 struct {
|
||||
fieldKey windows.GUID // Windows type: GUID
|
||||
matchType wtFwpMatchType
|
||||
conditionValue wtFwpConditionValue0
|
||||
}
|
||||
|
||||
// FWPM_PROVIDER0 defined in fwpmtypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwpmtypes/ns-fwpmtypes-fwpm_provider0_)
|
||||
type wtFwpProvider0 struct {
|
||||
providerKey windows.GUID // Windows type: GUID
|
||||
displayData wtFwpmDisplayData0
|
||||
flags uint32
|
||||
providerData wtFwpByteBlob
|
||||
serviceName *uint16 // Windows type: *wchar_t
|
||||
}
|
||||
|
||||
type wtFwpmSessionFlagsValue uint32
|
||||
|
||||
const (
|
||||
cFWPM_SESSION_FLAG_DYNAMIC wtFwpmSessionFlagsValue = 0x00000001 // FWPM_SESSION_FLAG_DYNAMIC defined in fwpmtypes.h
|
||||
)
|
||||
|
||||
// FWPM_SESSION0 defined in fwpmtypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwpmtypes/ns-fwpmtypes-fwpm_session0).
|
||||
type wtFwpmSession0 struct {
|
||||
sessionKey windows.GUID // Windows type: GUID
|
||||
displayData wtFwpmDisplayData0
|
||||
flags wtFwpmSessionFlagsValue // Windows type UINT32
|
||||
txnWaitTimeoutInMSec uint32
|
||||
processId uint32 // Windows type: DWORD
|
||||
sid *windows.SID
|
||||
username *uint16 // Windows type: *wchar_t
|
||||
kernelMode uint8 // Windows type: BOOL
|
||||
}
|
||||
|
||||
type wtFwpmSublayerFlags uint32
|
||||
|
||||
const (
|
||||
cFWPM_SUBLAYER_FLAG_PERSISTENT wtFwpmSublayerFlags = 0x00000001 // FWPM_SUBLAYER_FLAG_PERSISTENT defined in fwpmtypes.h
|
||||
)
|
||||
|
||||
// FWPM_SUBLAYER0 defined in fwpmtypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwpmtypes/ns-fwpmtypes-fwpm_sublayer0_)
|
||||
type wtFwpmSublayer0 struct {
|
||||
subLayerKey windows.GUID // Windows type: GUID
|
||||
displayData wtFwpmDisplayData0
|
||||
flags wtFwpmSublayerFlags
|
||||
providerKey *windows.GUID // Windows type: *GUID
|
||||
providerData wtFwpByteBlob
|
||||
weight uint16
|
||||
}
|
||||
|
||||
// Defined in rpcdce.h
|
||||
type wtRpcCAuthN uint32
|
||||
|
||||
const (
|
||||
cRPC_C_AUTHN_NONE wtRpcCAuthN = 0
|
||||
cRPC_C_AUTHN_WINNT wtRpcCAuthN = 10
|
||||
cRPC_C_AUTHN_DEFAULT wtRpcCAuthN = 0xFFFFFFFF
|
||||
)
|
||||
|
||||
// FWPM_PROVIDER0 defined in fwpmtypes.h
|
||||
// (https://docs.microsoft.com/sv-se/windows/desktop/api/fwpmtypes/ns-fwpmtypes-fwpm_provider0).
|
||||
type wtFwpmProvider0 struct {
|
||||
providerKey windows.GUID
|
||||
displayData wtFwpmDisplayData0
|
||||
flags uint32
|
||||
providerData wtFwpByteBlob
|
||||
serviceName *uint16
|
||||
}
|
||||
|
||||
type wtIPProto uint32
|
||||
|
||||
const (
|
||||
cIPPROTO_ICMP wtIPProto = 1
|
||||
cIPPROTO_ICMPV6 wtIPProto = 58
|
||||
cIPPROTO_TCP wtIPProto = 6
|
||||
cIPPROTO_UDP wtIPProto = 17
|
||||
)
|
||||
|
||||
const (
|
||||
cFWP_ACTRL_MATCH_FILTER = 1
|
||||
)
|
||||
@@ -1,90 +0,0 @@
|
||||
//go:build 386 || arm
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package firewall
|
||||
|
||||
import "golang.org/x/sys/windows"
|
||||
|
||||
const (
|
||||
wtFwpByteBlob_Size = 8
|
||||
wtFwpByteBlob_data_Offset = 4
|
||||
|
||||
wtFwpConditionValue0_Size = 8
|
||||
wtFwpConditionValue0_uint8_Offset = 4
|
||||
|
||||
wtFwpmDisplayData0_Size = 8
|
||||
wtFwpmDisplayData0_description_Offset = 4
|
||||
|
||||
wtFwpmFilter0_Size = 152
|
||||
wtFwpmFilter0_displayData_Offset = 16
|
||||
wtFwpmFilter0_flags_Offset = 24
|
||||
wtFwpmFilter0_providerKey_Offset = 28
|
||||
wtFwpmFilter0_providerData_Offset = 32
|
||||
wtFwpmFilter0_layerKey_Offset = 40
|
||||
wtFwpmFilter0_subLayerKey_Offset = 56
|
||||
wtFwpmFilter0_weight_Offset = 72
|
||||
wtFwpmFilter0_numFilterConditions_Offset = 80
|
||||
wtFwpmFilter0_filterCondition_Offset = 84
|
||||
wtFwpmFilter0_action_Offset = 88
|
||||
wtFwpmFilter0_providerContextKey_Offset = 112
|
||||
wtFwpmFilter0_reserved_Offset = 128
|
||||
wtFwpmFilter0_filterID_Offset = 136
|
||||
wtFwpmFilter0_effectiveWeight_Offset = 144
|
||||
|
||||
wtFwpmFilterCondition0_Size = 28
|
||||
wtFwpmFilterCondition0_matchType_Offset = 16
|
||||
wtFwpmFilterCondition0_conditionValue_Offset = 20
|
||||
|
||||
wtFwpmSession0_Size = 48
|
||||
wtFwpmSession0_displayData_Offset = 16
|
||||
wtFwpmSession0_flags_Offset = 24
|
||||
wtFwpmSession0_txnWaitTimeoutInMSec_Offset = 28
|
||||
wtFwpmSession0_processId_Offset = 32
|
||||
wtFwpmSession0_sid_Offset = 36
|
||||
wtFwpmSession0_username_Offset = 40
|
||||
wtFwpmSession0_kernelMode_Offset = 44
|
||||
|
||||
wtFwpmSublayer0_Size = 44
|
||||
wtFwpmSublayer0_displayData_Offset = 16
|
||||
wtFwpmSublayer0_flags_Offset = 24
|
||||
wtFwpmSublayer0_providerKey_Offset = 28
|
||||
wtFwpmSublayer0_providerData_Offset = 32
|
||||
wtFwpmSublayer0_weight_Offset = 40
|
||||
|
||||
wtFwpProvider0_Size = 40
|
||||
wtFwpProvider0_displayData_Offset = 16
|
||||
wtFwpProvider0_flags_Offset = 24
|
||||
wtFwpProvider0_providerData_Offset = 28
|
||||
wtFwpProvider0_serviceName_Offset = 36
|
||||
|
||||
wtFwpTokenInformation_Size = 16
|
||||
|
||||
wtFwpValue0_Size = 8
|
||||
wtFwpValue0_value_Offset = 4
|
||||
)
|
||||
|
||||
// FWPM_FILTER0 defined in fwpmtypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwpmtypes/ns-fwpmtypes-fwpm_filter0).
|
||||
type wtFwpmFilter0 struct {
|
||||
filterKey windows.GUID // Windows type: GUID
|
||||
displayData wtFwpmDisplayData0
|
||||
flags wtFwpmFilterFlags
|
||||
providerKey *windows.GUID // Windows type: *GUID
|
||||
providerData wtFwpByteBlob
|
||||
layerKey windows.GUID // Windows type: GUID
|
||||
subLayerKey windows.GUID // Windows type: GUID
|
||||
weight wtFwpValue0
|
||||
numFilterConditions uint32
|
||||
filterCondition *wtFwpmFilterCondition0
|
||||
action wtFwpmAction0
|
||||
offset1 [4]byte // Layout correction field
|
||||
providerContextKey windows.GUID // Windows type: GUID
|
||||
reserved *windows.GUID // Windows type: *GUID
|
||||
offset2 [4]byte // Layout correction field
|
||||
filterID uint64
|
||||
effectiveWeight wtFwpValue0
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
//go:build amd64 || arm64
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package firewall
|
||||
|
||||
import "golang.org/x/sys/windows"
|
||||
|
||||
const (
|
||||
wtFwpByteBlob_Size = 16
|
||||
wtFwpByteBlob_data_Offset = 8
|
||||
|
||||
wtFwpConditionValue0_Size = 16
|
||||
wtFwpConditionValue0_uint8_Offset = 8
|
||||
|
||||
wtFwpmDisplayData0_Size = 16
|
||||
wtFwpmDisplayData0_description_Offset = 8
|
||||
|
||||
wtFwpmFilter0_Size = 200
|
||||
wtFwpmFilter0_displayData_Offset = 16
|
||||
wtFwpmFilter0_flags_Offset = 32
|
||||
wtFwpmFilter0_providerKey_Offset = 40
|
||||
wtFwpmFilter0_providerData_Offset = 48
|
||||
wtFwpmFilter0_layerKey_Offset = 64
|
||||
wtFwpmFilter0_subLayerKey_Offset = 80
|
||||
wtFwpmFilter0_weight_Offset = 96
|
||||
wtFwpmFilter0_numFilterConditions_Offset = 112
|
||||
wtFwpmFilter0_filterCondition_Offset = 120
|
||||
wtFwpmFilter0_action_Offset = 128
|
||||
wtFwpmFilter0_providerContextKey_Offset = 152
|
||||
wtFwpmFilter0_reserved_Offset = 168
|
||||
wtFwpmFilter0_filterID_Offset = 176
|
||||
wtFwpmFilter0_effectiveWeight_Offset = 184
|
||||
|
||||
wtFwpmFilterCondition0_Size = 40
|
||||
wtFwpmFilterCondition0_matchType_Offset = 16
|
||||
wtFwpmFilterCondition0_conditionValue_Offset = 24
|
||||
|
||||
wtFwpmSession0_Size = 72
|
||||
wtFwpmSession0_displayData_Offset = 16
|
||||
wtFwpmSession0_flags_Offset = 32
|
||||
wtFwpmSession0_txnWaitTimeoutInMSec_Offset = 36
|
||||
wtFwpmSession0_processId_Offset = 40
|
||||
wtFwpmSession0_sid_Offset = 48
|
||||
wtFwpmSession0_username_Offset = 56
|
||||
wtFwpmSession0_kernelMode_Offset = 64
|
||||
|
||||
wtFwpmSublayer0_Size = 72
|
||||
wtFwpmSublayer0_displayData_Offset = 16
|
||||
wtFwpmSublayer0_flags_Offset = 32
|
||||
wtFwpmSublayer0_providerKey_Offset = 40
|
||||
wtFwpmSublayer0_providerData_Offset = 48
|
||||
wtFwpmSublayer0_weight_Offset = 64
|
||||
|
||||
wtFwpProvider0_Size = 64
|
||||
wtFwpProvider0_displayData_Offset = 16
|
||||
wtFwpProvider0_flags_Offset = 32
|
||||
wtFwpProvider0_providerData_Offset = 40
|
||||
wtFwpProvider0_serviceName_Offset = 56
|
||||
|
||||
wtFwpValue0_Size = 16
|
||||
wtFwpValue0_value_Offset = 8
|
||||
)
|
||||
|
||||
// FWPM_FILTER0 defined in fwpmtypes.h
|
||||
// (https://docs.microsoft.com/en-us/windows/desktop/api/fwpmtypes/ns-fwpmtypes-fwpm_filter0).
|
||||
type wtFwpmFilter0 struct {
|
||||
filterKey windows.GUID // Windows type: GUID
|
||||
displayData wtFwpmDisplayData0
|
||||
flags wtFwpmFilterFlags // Windows type: UINT32
|
||||
providerKey *windows.GUID // Windows type: *GUID
|
||||
providerData wtFwpByteBlob
|
||||
layerKey windows.GUID // Windows type: GUID
|
||||
subLayerKey windows.GUID // Windows type: GUID
|
||||
weight wtFwpValue0
|
||||
numFilterConditions uint32
|
||||
filterCondition *wtFwpmFilterCondition0
|
||||
action wtFwpmAction0
|
||||
offset1 [4]byte // Layout correction field
|
||||
providerContextKey windows.GUID // Windows type: GUID
|
||||
reserved *windows.GUID // Windows type: *GUID
|
||||
filterID uint64
|
||||
effectiveWeight wtFwpValue0
|
||||
}
|
||||
@@ -1,511 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package firewall
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func TestWtFwpByteBlobSize(t *testing.T) {
|
||||
const actualWtFwpByteBlobSize = unsafe.Sizeof(wtFwpByteBlob{})
|
||||
|
||||
if actualWtFwpByteBlobSize != wtFwpByteBlob_Size {
|
||||
t.Errorf("Size of FwpByteBlob is %d, although %d is expected.", actualWtFwpByteBlobSize,
|
||||
wtFwpByteBlob_Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpByteBlobOffsets(t *testing.T) {
|
||||
s := wtFwpByteBlob{}
|
||||
sp := uintptr(unsafe.Pointer(&s))
|
||||
|
||||
offset := uintptr(unsafe.Pointer(&s.data)) - sp
|
||||
|
||||
if offset != wtFwpByteBlob_data_Offset {
|
||||
t.Errorf("FwpByteBlob.data offset is %d although %d is expected", offset, wtFwpByteBlob_data_Offset)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpmAction0Size(t *testing.T) {
|
||||
const actualWtFwpmAction0Size = unsafe.Sizeof(wtFwpmAction0{})
|
||||
|
||||
if actualWtFwpmAction0Size != wtFwpmAction0_Size {
|
||||
t.Errorf("Size of wtFwpmAction0 is %d, although %d is expected.", actualWtFwpmAction0Size,
|
||||
wtFwpmAction0_Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpmAction0Offsets(t *testing.T) {
|
||||
s := wtFwpmAction0{}
|
||||
sp := uintptr(unsafe.Pointer(&s))
|
||||
|
||||
offset := uintptr(unsafe.Pointer(&s.filterType)) - sp
|
||||
|
||||
if offset != wtFwpmAction0_filterType_Offset {
|
||||
t.Errorf("wtFwpmAction0.filterType offset is %d although %d is expected", offset,
|
||||
wtFwpmAction0_filterType_Offset)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpBitmapArray64Size(t *testing.T) {
|
||||
const actualWtFwpBitmapArray64Size = unsafe.Sizeof(wtFwpBitmapArray64{})
|
||||
|
||||
if actualWtFwpBitmapArray64Size != wtFwpBitmapArray64_Size {
|
||||
t.Errorf("Size of wtFwpBitmapArray64 is %d, although %d is expected.", actualWtFwpBitmapArray64Size,
|
||||
wtFwpBitmapArray64_Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpByteArray6Size(t *testing.T) {
|
||||
const actualWtFwpByteArray6Size = unsafe.Sizeof(wtFwpByteArray6{})
|
||||
|
||||
if actualWtFwpByteArray6Size != wtFwpByteArray6_Size {
|
||||
t.Errorf("Size of wtFwpByteArray6 is %d, although %d is expected.", actualWtFwpByteArray6Size,
|
||||
wtFwpByteArray6_Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpByteArray16Size(t *testing.T) {
|
||||
const actualWtFwpByteArray16Size = unsafe.Sizeof(wtFwpByteArray16{})
|
||||
|
||||
if actualWtFwpByteArray16Size != wtFwpByteArray16_Size {
|
||||
t.Errorf("Size of wtFwpByteArray16 is %d, although %d is expected.", actualWtFwpByteArray16Size,
|
||||
wtFwpByteArray16_Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpConditionValue0Size(t *testing.T) {
|
||||
const actualWtFwpConditionValue0Size = unsafe.Sizeof(wtFwpConditionValue0{})
|
||||
|
||||
if actualWtFwpConditionValue0Size != wtFwpConditionValue0_Size {
|
||||
t.Errorf("Size of wtFwpConditionValue0 is %d, although %d is expected.", actualWtFwpConditionValue0Size,
|
||||
wtFwpConditionValue0_Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpConditionValue0Offsets(t *testing.T) {
|
||||
s := wtFwpConditionValue0{}
|
||||
sp := uintptr(unsafe.Pointer(&s))
|
||||
|
||||
offset := uintptr(unsafe.Pointer(&s.value)) - sp
|
||||
|
||||
if offset != wtFwpConditionValue0_uint8_Offset {
|
||||
t.Errorf("wtFwpConditionValue0.value offset is %d although %d is expected", offset, wtFwpConditionValue0_uint8_Offset)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpV4AddrAndMaskSize(t *testing.T) {
|
||||
const actualWtFwpV4AddrAndMaskSize = unsafe.Sizeof(wtFwpV4AddrAndMask{})
|
||||
|
||||
if actualWtFwpV4AddrAndMaskSize != wtFwpV4AddrAndMask_Size {
|
||||
t.Errorf("Size of wtFwpV4AddrAndMask is %d, although %d is expected.", actualWtFwpV4AddrAndMaskSize,
|
||||
wtFwpV4AddrAndMask_Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpV4AddrAndMaskOffsets(t *testing.T) {
|
||||
s := wtFwpV4AddrAndMask{}
|
||||
sp := uintptr(unsafe.Pointer(&s))
|
||||
|
||||
offset := uintptr(unsafe.Pointer(&s.mask)) - sp
|
||||
|
||||
if offset != wtFwpV4AddrAndMask_mask_Offset {
|
||||
t.Errorf("wtFwpV4AddrAndMask.mask offset is %d although %d is expected", offset,
|
||||
wtFwpV4AddrAndMask_mask_Offset)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpV6AddrAndMaskSize(t *testing.T) {
|
||||
const actualWtFwpV6AddrAndMaskSize = unsafe.Sizeof(wtFwpV6AddrAndMask{})
|
||||
|
||||
if actualWtFwpV6AddrAndMaskSize != wtFwpV6AddrAndMask_Size {
|
||||
t.Errorf("Size of wtFwpV6AddrAndMask is %d, although %d is expected.", actualWtFwpV6AddrAndMaskSize,
|
||||
wtFwpV6AddrAndMask_Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpV6AddrAndMaskOffsets(t *testing.T) {
|
||||
s := wtFwpV6AddrAndMask{}
|
||||
sp := uintptr(unsafe.Pointer(&s))
|
||||
|
||||
offset := uintptr(unsafe.Pointer(&s.prefixLength)) - sp
|
||||
|
||||
if offset != wtFwpV6AddrAndMask_prefixLength_Offset {
|
||||
t.Errorf("wtFwpV6AddrAndMask.prefixLength offset is %d although %d is expected", offset,
|
||||
wtFwpV6AddrAndMask_prefixLength_Offset)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpValue0Size(t *testing.T) {
|
||||
const actualWtFwpValue0Size = unsafe.Sizeof(wtFwpValue0{})
|
||||
|
||||
if actualWtFwpValue0Size != wtFwpValue0_Size {
|
||||
t.Errorf("Size of wtFwpValue0 is %d, although %d is expected.", actualWtFwpValue0Size, wtFwpValue0_Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpValue0Offsets(t *testing.T) {
|
||||
s := wtFwpValue0{}
|
||||
sp := uintptr(unsafe.Pointer(&s))
|
||||
|
||||
offset := uintptr(unsafe.Pointer(&s.value)) - sp
|
||||
|
||||
if offset != wtFwpValue0_value_Offset {
|
||||
t.Errorf("wtFwpValue0.value offset is %d although %d is expected", offset, wtFwpValue0_value_Offset)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpmDisplayData0Size(t *testing.T) {
|
||||
const actualWtFwpmDisplayData0Size = unsafe.Sizeof(wtFwpmDisplayData0{})
|
||||
|
||||
if actualWtFwpmDisplayData0Size != wtFwpmDisplayData0_Size {
|
||||
t.Errorf("Size of wtFwpmDisplayData0 is %d, although %d is expected.", actualWtFwpmDisplayData0Size,
|
||||
wtFwpmDisplayData0_Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpmDisplayData0Offsets(t *testing.T) {
|
||||
s := wtFwpmDisplayData0{}
|
||||
sp := uintptr(unsafe.Pointer(&s))
|
||||
|
||||
offset := uintptr(unsafe.Pointer(&s.description)) - sp
|
||||
|
||||
if offset != wtFwpmDisplayData0_description_Offset {
|
||||
t.Errorf("wtFwpmDisplayData0.description offset is %d although %d is expected", offset,
|
||||
wtFwpmDisplayData0_description_Offset)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpmFilterCondition0Size(t *testing.T) {
|
||||
const actualWtFwpmFilterCondition0Size = unsafe.Sizeof(wtFwpmFilterCondition0{})
|
||||
|
||||
if actualWtFwpmFilterCondition0Size != wtFwpmFilterCondition0_Size {
|
||||
t.Errorf("Size of wtFwpmFilterCondition0 is %d, although %d is expected.",
|
||||
actualWtFwpmFilterCondition0Size, wtFwpmFilterCondition0_Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpmFilterCondition0Offsets(t *testing.T) {
|
||||
s := wtFwpmFilterCondition0{}
|
||||
sp := uintptr(unsafe.Pointer(&s))
|
||||
|
||||
offset := uintptr(unsafe.Pointer(&s.matchType)) - sp
|
||||
|
||||
if offset != wtFwpmFilterCondition0_matchType_Offset {
|
||||
t.Errorf("wtFwpmFilterCondition0.matchType offset is %d although %d is expected", offset,
|
||||
wtFwpmFilterCondition0_matchType_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.conditionValue)) - sp
|
||||
|
||||
if offset != wtFwpmFilterCondition0_conditionValue_Offset {
|
||||
t.Errorf("wtFwpmFilterCondition0.conditionValue offset is %d although %d is expected", offset,
|
||||
wtFwpmFilterCondition0_conditionValue_Offset)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpmFilter0Size(t *testing.T) {
|
||||
const actualWtFwpmFilter0Size = unsafe.Sizeof(wtFwpmFilter0{})
|
||||
|
||||
if actualWtFwpmFilter0Size != wtFwpmFilter0_Size {
|
||||
t.Errorf("Size of wtFwpmFilter0 is %d, although %d is expected.", actualWtFwpmFilter0Size,
|
||||
wtFwpmFilter0_Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpmFilter0Offsets(t *testing.T) {
|
||||
s := wtFwpmFilter0{}
|
||||
sp := uintptr(unsafe.Pointer(&s))
|
||||
|
||||
offset := uintptr(unsafe.Pointer(&s.displayData)) - sp
|
||||
|
||||
if offset != wtFwpmFilter0_displayData_Offset {
|
||||
t.Errorf("wtFwpmFilter0.displayData offset is %d although %d is expected", offset,
|
||||
wtFwpmFilter0_displayData_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.flags)) - sp
|
||||
|
||||
if offset != wtFwpmFilter0_flags_Offset {
|
||||
t.Errorf("wtFwpmFilter0.flags offset is %d although %d is expected", offset, wtFwpmFilter0_flags_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.providerKey)) - sp
|
||||
|
||||
if offset != wtFwpmFilter0_providerKey_Offset {
|
||||
t.Errorf("wtFwpmFilter0.providerKey offset is %d although %d is expected", offset,
|
||||
wtFwpmFilter0_providerKey_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.providerData)) - sp
|
||||
|
||||
if offset != wtFwpmFilter0_providerData_Offset {
|
||||
t.Errorf("wtFwpmFilter0.providerData offset is %d although %d is expected", offset,
|
||||
wtFwpmFilter0_providerData_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.layerKey)) - sp
|
||||
|
||||
if offset != wtFwpmFilter0_layerKey_Offset {
|
||||
t.Errorf("wtFwpmFilter0.layerKey offset is %d although %d is expected", offset,
|
||||
wtFwpmFilter0_layerKey_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.subLayerKey)) - sp
|
||||
|
||||
if offset != wtFwpmFilter0_subLayerKey_Offset {
|
||||
t.Errorf("wtFwpmFilter0.subLayerKey offset is %d although %d is expected", offset,
|
||||
wtFwpmFilter0_subLayerKey_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.weight)) - sp
|
||||
|
||||
if offset != wtFwpmFilter0_weight_Offset {
|
||||
t.Errorf("wtFwpmFilter0.weight offset is %d although %d is expected", offset,
|
||||
wtFwpmFilter0_weight_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.numFilterConditions)) - sp
|
||||
|
||||
if offset != wtFwpmFilter0_numFilterConditions_Offset {
|
||||
t.Errorf("wtFwpmFilter0.numFilterConditions offset is %d although %d is expected", offset,
|
||||
wtFwpmFilter0_numFilterConditions_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.filterCondition)) - sp
|
||||
|
||||
if offset != wtFwpmFilter0_filterCondition_Offset {
|
||||
t.Errorf("wtFwpmFilter0.filterCondition offset is %d although %d is expected", offset,
|
||||
wtFwpmFilter0_filterCondition_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.action)) - sp
|
||||
|
||||
if offset != wtFwpmFilter0_action_Offset {
|
||||
t.Errorf("wtFwpmFilter0.action offset is %d although %d is expected", offset,
|
||||
wtFwpmFilter0_action_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.providerContextKey)) - sp
|
||||
|
||||
if offset != wtFwpmFilter0_providerContextKey_Offset {
|
||||
t.Errorf("wtFwpmFilter0.providerContextKey offset is %d although %d is expected", offset,
|
||||
wtFwpmFilter0_providerContextKey_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.reserved)) - sp
|
||||
|
||||
if offset != wtFwpmFilter0_reserved_Offset {
|
||||
t.Errorf("wtFwpmFilter0.reserved offset is %d although %d is expected", offset,
|
||||
wtFwpmFilter0_reserved_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.filterID)) - sp
|
||||
|
||||
if offset != wtFwpmFilter0_filterID_Offset {
|
||||
t.Errorf("wtFwpmFilter0.filterID offset is %d although %d is expected", offset,
|
||||
wtFwpmFilter0_filterID_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.effectiveWeight)) - sp
|
||||
|
||||
if offset != wtFwpmFilter0_effectiveWeight_Offset {
|
||||
t.Errorf("wtFwpmFilter0.effectiveWeight offset is %d although %d is expected", offset,
|
||||
wtFwpmFilter0_effectiveWeight_Offset)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpProvider0Size(t *testing.T) {
|
||||
const actualWtFwpProvider0Size = unsafe.Sizeof(wtFwpProvider0{})
|
||||
|
||||
if actualWtFwpProvider0Size != wtFwpProvider0_Size {
|
||||
t.Errorf("Size of wtFwpProvider0 is %d, although %d is expected.", actualWtFwpProvider0Size,
|
||||
wtFwpProvider0_Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpProvider0Offsets(t *testing.T) {
|
||||
s := wtFwpProvider0{}
|
||||
sp := uintptr(unsafe.Pointer(&s))
|
||||
|
||||
offset := uintptr(unsafe.Pointer(&s.displayData)) - sp
|
||||
|
||||
if offset != wtFwpProvider0_displayData_Offset {
|
||||
t.Errorf("wtFwpProvider0.displayData offset is %d although %d is expected", offset,
|
||||
wtFwpProvider0_displayData_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.flags)) - sp
|
||||
|
||||
if offset != wtFwpProvider0_flags_Offset {
|
||||
t.Errorf("wtFwpProvider0.flags offset is %d although %d is expected", offset,
|
||||
wtFwpProvider0_flags_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.providerData)) - sp
|
||||
|
||||
if offset != wtFwpProvider0_providerData_Offset {
|
||||
t.Errorf("wtFwpProvider0.providerData offset is %d although %d is expected", offset,
|
||||
wtFwpProvider0_providerData_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.serviceName)) - sp
|
||||
|
||||
if offset != wtFwpProvider0_serviceName_Offset {
|
||||
t.Errorf("wtFwpProvider0.serviceName offset is %d although %d is expected", offset,
|
||||
wtFwpProvider0_serviceName_Offset)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpmSession0Size(t *testing.T) {
|
||||
const actualWtFwpmSession0Size = unsafe.Sizeof(wtFwpmSession0{})
|
||||
|
||||
if actualWtFwpmSession0Size != wtFwpmSession0_Size {
|
||||
t.Errorf("Size of wtFwpmSession0 is %d, although %d is expected.", actualWtFwpmSession0Size,
|
||||
wtFwpmSession0_Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpmSession0Offsets(t *testing.T) {
|
||||
s := wtFwpmSession0{}
|
||||
sp := uintptr(unsafe.Pointer(&s))
|
||||
|
||||
offset := uintptr(unsafe.Pointer(&s.displayData)) - sp
|
||||
|
||||
if offset != wtFwpmSession0_displayData_Offset {
|
||||
t.Errorf("wtFwpmSession0.displayData offset is %d although %d is expected", offset,
|
||||
wtFwpmSession0_displayData_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.flags)) - sp
|
||||
|
||||
if offset != wtFwpmSession0_flags_Offset {
|
||||
t.Errorf("wtFwpmSession0.flags offset is %d although %d is expected", offset, wtFwpmSession0_flags_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.txnWaitTimeoutInMSec)) - sp
|
||||
|
||||
if offset != wtFwpmSession0_txnWaitTimeoutInMSec_Offset {
|
||||
t.Errorf("wtFwpmSession0.txnWaitTimeoutInMSec offset is %d although %d is expected", offset,
|
||||
wtFwpmSession0_txnWaitTimeoutInMSec_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.processId)) - sp
|
||||
|
||||
if offset != wtFwpmSession0_processId_Offset {
|
||||
t.Errorf("wtFwpmSession0.processId offset is %d although %d is expected", offset,
|
||||
wtFwpmSession0_processId_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.sid)) - sp
|
||||
|
||||
if offset != wtFwpmSession0_sid_Offset {
|
||||
t.Errorf("wtFwpmSession0.sid offset is %d although %d is expected", offset, wtFwpmSession0_sid_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.username)) - sp
|
||||
|
||||
if offset != wtFwpmSession0_username_Offset {
|
||||
t.Errorf("wtFwpmSession0.username offset is %d although %d is expected", offset,
|
||||
wtFwpmSession0_username_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.kernelMode)) - sp
|
||||
|
||||
if offset != wtFwpmSession0_kernelMode_Offset {
|
||||
t.Errorf("wtFwpmSession0.kernelMode offset is %d although %d is expected", offset,
|
||||
wtFwpmSession0_kernelMode_Offset)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpmSublayer0Size(t *testing.T) {
|
||||
const actualWtFwpmSublayer0Size = unsafe.Sizeof(wtFwpmSublayer0{})
|
||||
|
||||
if actualWtFwpmSublayer0Size != wtFwpmSublayer0_Size {
|
||||
t.Errorf("Size of wtFwpmSublayer0 is %d, although %d is expected.", actualWtFwpmSublayer0Size,
|
||||
wtFwpmSublayer0_Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWtFwpmSublayer0Offsets(t *testing.T) {
|
||||
s := wtFwpmSublayer0{}
|
||||
sp := uintptr(unsafe.Pointer(&s))
|
||||
|
||||
offset := uintptr(unsafe.Pointer(&s.displayData)) - sp
|
||||
|
||||
if offset != wtFwpmSublayer0_displayData_Offset {
|
||||
t.Errorf("wtFwpmSublayer0.displayData offset is %d although %d is expected", offset,
|
||||
wtFwpmSublayer0_displayData_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.flags)) - sp
|
||||
|
||||
if offset != wtFwpmSublayer0_flags_Offset {
|
||||
t.Errorf("wtFwpmSublayer0.flags offset is %d although %d is expected", offset,
|
||||
wtFwpmSublayer0_flags_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.providerKey)) - sp
|
||||
|
||||
if offset != wtFwpmSublayer0_providerKey_Offset {
|
||||
t.Errorf("wtFwpmSublayer0.providerKey offset is %d although %d is expected", offset,
|
||||
wtFwpmSublayer0_providerKey_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.providerData)) - sp
|
||||
|
||||
if offset != wtFwpmSublayer0_providerData_Offset {
|
||||
t.Errorf("wtFwpmSublayer0.providerData offset is %d although %d is expected", offset,
|
||||
wtFwpmSublayer0_providerData_Offset)
|
||||
return
|
||||
}
|
||||
|
||||
offset = uintptr(unsafe.Pointer(&s.weight)) - sp
|
||||
|
||||
if offset != wtFwpmSublayer0_weight_Offset {
|
||||
t.Errorf("wtFwpmSublayer0.weight offset is %d although %d is expected", offset,
|
||||
wtFwpmSublayer0_weight_Offset)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
// Code generated by 'go generate'; DO NOT EDIT.
|
||||
|
||||
package firewall
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
// Do the interface allocations only once for common
|
||||
// Errno values.
|
||||
const (
|
||||
errnoERROR_IO_PENDING = 997
|
||||
)
|
||||
|
||||
var (
|
||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||
errERROR_EINVAL error = syscall.EINVAL
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
// allocations at runtime.
|
||||
func errnoErr(e syscall.Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return errERROR_EINVAL
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
// TODO: add more here, after collecting data on the common
|
||||
// error values see on Windows. (perhaps when running
|
||||
// all.bat?)
|
||||
return e
|
||||
}
|
||||
|
||||
var (
|
||||
modfwpuclnt = windows.NewLazySystemDLL("fwpuclnt.dll")
|
||||
|
||||
procFwpmEngineClose0 = modfwpuclnt.NewProc("FwpmEngineClose0")
|
||||
procFwpmEngineOpen0 = modfwpuclnt.NewProc("FwpmEngineOpen0")
|
||||
procFwpmFilterAdd0 = modfwpuclnt.NewProc("FwpmFilterAdd0")
|
||||
procFwpmFreeMemory0 = modfwpuclnt.NewProc("FwpmFreeMemory0")
|
||||
procFwpmGetAppIdFromFileName0 = modfwpuclnt.NewProc("FwpmGetAppIdFromFileName0")
|
||||
procFwpmProviderAdd0 = modfwpuclnt.NewProc("FwpmProviderAdd0")
|
||||
procFwpmSubLayerAdd0 = modfwpuclnt.NewProc("FwpmSubLayerAdd0")
|
||||
procFwpmTransactionAbort0 = modfwpuclnt.NewProc("FwpmTransactionAbort0")
|
||||
procFwpmTransactionBegin0 = modfwpuclnt.NewProc("FwpmTransactionBegin0")
|
||||
procFwpmTransactionCommit0 = modfwpuclnt.NewProc("FwpmTransactionCommit0")
|
||||
)
|
||||
|
||||
func fwpmEngineClose0(engineHandle uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procFwpmEngineClose0.Addr(), 1, uintptr(engineHandle), 0, 0)
|
||||
if r1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func fwpmEngineOpen0(serverName *uint16, authnService wtRpcCAuthN, authIdentity *uintptr, session *wtFwpmSession0, engineHandle unsafe.Pointer) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procFwpmEngineOpen0.Addr(), 5, uintptr(unsafe.Pointer(serverName)), uintptr(authnService), uintptr(unsafe.Pointer(authIdentity)), uintptr(unsafe.Pointer(session)), uintptr(engineHandle), 0)
|
||||
if r1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func fwpmFilterAdd0(engineHandle uintptr, filter *wtFwpmFilter0, sd uintptr, id *uint64) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procFwpmFilterAdd0.Addr(), 4, uintptr(engineHandle), uintptr(unsafe.Pointer(filter)), uintptr(sd), uintptr(unsafe.Pointer(id)), 0, 0)
|
||||
if r1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func fwpmFreeMemory0(p unsafe.Pointer) {
|
||||
syscall.Syscall(procFwpmFreeMemory0.Addr(), 1, uintptr(p), 0, 0)
|
||||
return
|
||||
}
|
||||
|
||||
func fwpmGetAppIdFromFileName0(fileName *uint16, appID unsafe.Pointer) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procFwpmGetAppIdFromFileName0.Addr(), 2, uintptr(unsafe.Pointer(fileName)), uintptr(appID), 0)
|
||||
if r1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func fwpmProviderAdd0(engineHandle uintptr, provider *wtFwpmProvider0, sd uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procFwpmProviderAdd0.Addr(), 3, uintptr(engineHandle), uintptr(unsafe.Pointer(provider)), uintptr(sd))
|
||||
if r1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func fwpmSubLayerAdd0(engineHandle uintptr, subLayer *wtFwpmSublayer0, sd uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procFwpmSubLayerAdd0.Addr(), 3, uintptr(engineHandle), uintptr(unsafe.Pointer(subLayer)), uintptr(sd))
|
||||
if r1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func fwpmTransactionAbort0(engineHandle uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procFwpmTransactionAbort0.Addr(), 1, uintptr(engineHandle), 0, 0)
|
||||
if r1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func fwpmTransactionBegin0(engineHandle uintptr, flags uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procFwpmTransactionBegin0.Addr(), 2, uintptr(engineHandle), uintptr(flags), 0)
|
||||
if r1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func fwpmTransactionCommit0(engineHandle uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procFwpmTransactionCommit0.Addr(), 1, uintptr(engineHandle), 0, 0)
|
||||
if r1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user