Fix windows route

This commit is contained in:
世界 2022-09-29 18:59:33 +08:00
parent 6bad0c2380
commit a93592a9b5
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
9 changed files with 662 additions and 26 deletions

6
go.mod
View file

@ -7,9 +7,9 @@ require (
github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97
github.com/sagernet/sing v0.0.0-20220925112014-b12b8b7fd220 github.com/sagernet/sing v0.0.0-20220929000216-9a83e35b7186
golang.org/x/net v0.0.0-20220923203811-8be639271d50 golang.org/x/net v0.0.0-20220927171203-f486391704dc
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c
) )

12
go.sum
View file

@ -9,17 +9,17 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
github.com/sagernet/sing v0.0.0-20220925112014-b12b8b7fd220 h1:fQk/BHOeHw5murjeNTdmkXmDy9cMlbubRINRH7GDuu4= github.com/sagernet/sing v0.0.0-20220929000216-9a83e35b7186 h1:ZDlgH6dTozS3ODaYq1GxCj+H8NvYESaex90iX72gadw=
github.com/sagernet/sing v0.0.0-20220925112014-b12b8b7fd220/go.mod h1:5/u6RMDMoGIkSNtrZb41kJvyIFg3Ysn69P3WiAu8m0c= github.com/sagernet/sing v0.0.0-20220929000216-9a83e35b7186/go.mod h1:zvgDYKI+vCAW9RyfyrKTgleI+DOa8lzHMPC7VZo3OL4=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
golang.org/x/net v0.0.0-20220923203811-8be639271d50 h1:vKyz8L3zkd+xrMeIaBsQ/MNVPVFSffdaU3ZyYlBGFnI= golang.org/x/net v0.0.0-20220927171203-f486391704dc h1:FxpXZdoBqT8RjqTy6i1E8nXHhW21wK7ptQ/EPIGxzPQ=
golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc= golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c h1:m5lcgWnL3OElQNVyp3qcncItJ2c0sQlSGjYK2+nJTA4= gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c h1:m5lcgWnL3OElQNVyp3qcncItJ2c0sQlSGjYK2+nJTA4=

View file

@ -0,0 +1,158 @@
//go:build windows
package winsys
import (
"golang.org/x/sys/windows"
)
const (
AF_INET = 2
AF_INET6 = 23
)
const (
MAX_MODULE_NAME32 = 255
MAX_PATH = 260
)
// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot
const (
TH32CS_SNAPHEAPLIST = 0x00000001
TH32CS_SNAPPROCESS = 0x00000002
TH32CS_SNAPTHREAD = 0x00000004
TH32CS_SNAPMODULE = 0x00000008
TH32CS_SNAPMODULE32 = 0x00000010
TH32CS_INHERIT = 0x80000000
TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPMODULE | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD
)
const (
MAX_ADAPTER_NAME = 128
MAX_INTERFACE_NAME_LEN = 256
MAXLEN_PHYSADDR = 8
MAXLEN_IFDESCR = 256
)
const (
ERROR_INSUFFICIENT_BUFFER = 122
)
const (
RPC_C_AUTHN_DEFAULT uint32 = 0xFFFFFFFF
FWPM_SESSION_FLAG_DYNAMIC uint32 = 0x00000001
)
const (
FWP_MATCH_EQUAL uint32 = 0
FWP_MATCH_GREATER = (FWP_MATCH_EQUAL + 1)
FWP_MATCH_LESS = (FWP_MATCH_GREATER + 1)
FWP_MATCH_GREATER_OR_EQUAL = (FWP_MATCH_LESS + 1)
FWP_MATCH_LESS_OR_EQUAL = (FWP_MATCH_GREATER_OR_EQUAL + 1)
FWP_MATCH_RANGE = (FWP_MATCH_LESS_OR_EQUAL + 1)
FWP_MATCH_FLAGS_ALL_SET = (FWP_MATCH_RANGE + 1)
FWP_MATCH_FLAGS_ANY_SET = (FWP_MATCH_FLAGS_ALL_SET + 1)
FWP_MATCH_FLAGS_NONE_SET = (FWP_MATCH_FLAGS_ANY_SET + 1)
FWP_MATCH_EQUAL_CASE_INSENSITIVE = (FWP_MATCH_FLAGS_NONE_SET + 1)
FWP_MATCH_NOT_EQUAL = (FWP_MATCH_EQUAL_CASE_INSENSITIVE + 1)
FWP_MATCH_PREFIX = (FWP_MATCH_NOT_EQUAL + 1)
FWP_MATCH_NOT_PREFIX = (FWP_MATCH_PREFIX + 1)
FWP_MATCH_TYPE_MAX = (FWP_MATCH_NOT_PREFIX + 1)
)
const (
FWP_EMPTY uint32 = 0
FWP_UINT8 = (FWP_EMPTY + 1)
FWP_UINT16 = (FWP_UINT8 + 1)
FWP_UINT32 = (FWP_UINT16 + 1)
FWP_UINT64 = (FWP_UINT32 + 1)
FWP_INT8 = (FWP_UINT64 + 1)
FWP_INT16 = (FWP_INT8 + 1)
FWP_INT32 = (FWP_INT16 + 1)
FWP_INT64 = (FWP_INT32 + 1)
FWP_FLOAT = (FWP_INT64 + 1)
FWP_DOUBLE = (FWP_FLOAT + 1)
FWP_BYTE_ARRAY16_TYPE = (FWP_DOUBLE + 1)
FWP_BYTE_BLOB_TYPE = (FWP_BYTE_ARRAY16_TYPE + 1)
FWP_SID = (FWP_BYTE_BLOB_TYPE + 1)
FWP_SECURITY_DESCRIPTOR_TYPE = (FWP_SID + 1)
FWP_TOKEN_INFORMATION_TYPE = (FWP_SECURITY_DESCRIPTOR_TYPE + 1)
FWP_TOKEN_ACCESS_INFORMATION_TYPE = (FWP_TOKEN_INFORMATION_TYPE + 1)
FWP_UNICODE_STRING_TYPE = (FWP_TOKEN_ACCESS_INFORMATION_TYPE + 1)
FWP_BYTE_ARRAY6_TYPE = (FWP_UNICODE_STRING_TYPE + 1)
FWP_BITMAP_INDEX_TYPE = (FWP_BYTE_ARRAY6_TYPE + 1)
FWP_BITMAP_ARRAY64_TYPE = (FWP_BITMAP_INDEX_TYPE + 1)
FWP_SINGLE_DATA_TYPE_MAX = 0xff
FWP_V4_ADDR_MASK = (FWP_SINGLE_DATA_TYPE_MAX + 1)
FWP_V6_ADDR_MASK = (FWP_V4_ADDR_MASK + 1)
FWP_RANGE_TYPE = (FWP_V6_ADDR_MASK + 1)
FWP_DATA_TYPE_MAX = (FWP_RANGE_TYPE + 1)
)
var FWPM_CONDITION_IP_PROTOCOL = windows.GUID{
Data1: 0x3971ef2b,
Data2: 0x623e,
Data3: 0x4f9a,
Data4: [8]byte{0x8c, 0xb1, 0x6e, 0x79, 0xb8, 0x06, 0xb9, 0xa7},
}
var FWPM_CONDITION_IP_REMOTE_PORT = windows.GUID{
Data1: 0xc35a604d,
Data2: 0xd22b,
Data3: 0x4e1a,
Data4: [8]byte{0x91, 0xb4, 0x68, 0xf6, 0x74, 0xee, 0x67, 0x4b},
}
var FWPM_LAYER_ALE_AUTH_CONNECT_V4 = windows.GUID{
Data1: 0xc38d57d1,
Data2: 0x05a7,
Data3: 0x4c33,
Data4: [8]byte{0x90, 0x4f, 0x7f, 0xbc, 0xee, 0xe6, 0x0e, 0x82},
}
var FWPM_CONDITION_LOCAL_INTERFACE_INDEX = windows.GUID{
Data1: 0x667fd755,
Data2: 0xd695,
Data3: 0x434a,
Data4: [8]byte{0x8a, 0xf5, 0xd3, 0x83, 0x5a, 0x12, 0x59, 0xbc},
}
var FWPM_LAYER_ALE_AUTH_CONNECT_V6 = windows.GUID{
Data1: 0x4a72393b,
Data2: 0x319f,
Data3: 0x44bc,
Data4: [8]byte{0x84, 0xc3, 0xba, 0x54, 0xdc, 0xb3, 0xb6, 0xb4},
}
var FWPM_CONDITION_ALE_APP_ID = windows.GUID{
Data1: 0xd78e1e87,
Data2: 0x8644,
Data3: 0x4ea5,
Data4: [8]byte{0x94, 0x37, 0xd8, 0x09, 0xec, 0xef, 0xc9, 0x71},
}
const (
IPPROTO_UDP uint32 = 17
)
const (
FWP_ACTION_FLAG_TERMINATING uint32 = 0x00001000
FWP_ACTION_BLOCK uint32 = (0x00000001 | FWP_ACTION_FLAG_TERMINATING)
FWP_ACTION_PERMIT uint32 = (0x00000002 | FWP_ACTION_FLAG_TERMINATING)
)
const (
FWPM_FILTER_FLAG_NONE = 0x00000000
FWPM_FILTER_FLAG_PERSISTENT = 0x00000001
FWPM_FILTER_FLAG_BOOTTIME = 0x00000002
FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT = 0x00000004
FWPM_FILTER_FLAG_CLEAR_ACTION_RIGHT = 0x00000008
FWPM_FILTER_FLAG_PERMIT_IF_CALLOUT_UNREGISTERED = 0x00000010
FWPM_FILTER_FLAG_DISABLED = 0x00000020
FWPM_FILTER_FLAG_INDEXED = 0x00000040
FWPM_FILTER_FLAG_HAS_SECURITY_REALM_PROVIDER_CONTEXT = 0x00000080
FWPM_FILTER_FLAG_SYSTEMOS_ONLY = 0x00000100
FWPM_FILTER_FLAG_GAMEOS_ONLY = 0x00000200
FWPM_FILTER_FLAG_SILENT_MODE = 0x00000400
FWPM_FILTER_FLAG_IPSEC_NO_ACQUIRE_INITIATE = 0x00000800
)

46
internal/winsys/helper.go Normal file
View file

@ -0,0 +1,46 @@
//go:build windows
package winsys
import (
"os"
"unsafe"
"github.com/sagernet/sing/common"
"golang.org/x/sys/windows"
)
func CreateDisplayData(name, description string) FWPM_DISPLAY_DATA0 {
namePtr, err := windows.UTF16PtrFromString(name)
common.Must(err)
descriptionPtr, err := windows.UTF16PtrFromString(description)
common.Must(err)
return FWPM_DISPLAY_DATA0{
Name: namePtr,
Description: descriptionPtr,
}
}
func GetCurrentProcessAppID() (*FWP_BYTE_BLOB, error) {
currentFile, err := os.Executable()
if err != nil {
return nil, err
}
curFilePtr, err := windows.UTF16PtrFromString(currentFile)
if err != nil {
return nil, err
}
windows.GetCurrentProcessId()
var appID *FWP_BYTE_BLOB
err = FwpmGetAppIdFromFileName0(curFilePtr, unsafe.Pointer(&appID))
if err != nil {
return nil, err
}
return appID, nil
}

View file

@ -0,0 +1,5 @@
//go:build windows
package winsys
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go syscall_windows.go

View file

@ -0,0 +1,19 @@
package winsys
// https://docs.microsoft.com/en-us/windows/desktop/api/fwpmu/nf-fwpmu-fwpmengineopen0
//sys FwpmEngineOpen0(serverName *uint16, authnService uint32, authIdentity *uintptr, session *FWPM_SESSION0, engineHandle unsafe.Pointer) (err error) [failretval!=0] = fwpuclnt.FwpmEngineOpen0
// https://learn.microsoft.com/en-us/windows/win32/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 *FWPM_SUBLAYER0, sd uintptr) (err error) [failretval!=0] = fwpuclnt.FwpmSubLayerAdd0
// https://docs.microsoft.com/en-us/windows/desktop/api/fwpmu/nf-fwpmu-fwpmfilteradd0
//sys FwpmFilterAdd0(engineHandle uintptr, filter *FWPM_FILTER0, sd uintptr, id *uint64) (err error) [failretval!=0] = fwpuclnt.FwpmFilterAdd0
// 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

View file

@ -0,0 +1,99 @@
package winsys
import (
"golang.org/x/sys/windows"
)
type (
BOOL int32
HANDLE uintptr
DWORD uint32
PDWORD uintptr
ULONG uint32
ULONG_PTR uintptr
HMODULE HANDLE
)
type MIB_IPFORWARDROW struct {
ForwardDest uint32
ForwardMask uint32
ForwardPolicy uint32
ForwardNextHop uint32
ForwardIfIndex uint32
ForwardType uint32
ForwardProto uint32
ForwardAge uint32
ForwardNextHopAS uint32
ForwardMetric1 uint32
ForwardMetric2 uint32
ForwardMetric3 uint32
ForwardMetric4 uint32
ForwardMetric5 uint32
}
type FWPM_DISPLAY_DATA0 struct {
Name *uint16
Description *uint16
}
type FWPM_SESSION0 struct {
SessionKey windows.GUID
DisplayData FWPM_DISPLAY_DATA0
Flags uint32
TxnWaitTimeoutInMSec uint32
ProcessId uint32
Sid *windows.SID
Username *uint16
KernelMode int32
}
type FWP_BYTE_BLOB struct {
size uint32
data *uint8
}
type FWPM_SUBLAYER0 struct {
SubLayerKey windows.GUID // Windows type: GUID
DisplayData FWPM_DISPLAY_DATA0
Flags uint32
ProviderKey *windows.GUID // Windows type: *GUID
ProviderData FWP_BYTE_BLOB
Weight uint16
}
type FWP_VALUE0 struct {
Type uint32
Value uintptr
}
type FWP_CONDITION_VALUE0 FWP_VALUE0
type FWPM_FILTER_CONDITION0 struct {
FieldKey windows.GUID // Windows type: GUID
MatchType uint32
ConditionValue FWP_CONDITION_VALUE0
}
type FWPM_ACTION0 struct {
Type uint32
Value windows.GUID
}
type FWPM_FILTER0 struct {
FilterKey windows.GUID
DisplayData FWPM_DISPLAY_DATA0
Flags uint32
ProviderKey *windows.GUID
ProviderData FWP_BYTE_BLOB
LayerKey windows.GUID
SubLayerKey windows.GUID
Weight FWP_VALUE0
NumFilterConditions uint32
FilterCondition *FWPM_FILTER_CONDITION0
Action FWPM_ACTION0
Offset1 [4]byte
Context windows.GUID
Reserved *windows.GUID
FilterId uint64
EffectiveWeight FWP_VALUE0
}

View file

@ -0,0 +1,94 @@
// Code generated by 'go generate'; DO NOT EDIT.
package winsys
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")
procFwpmSubLayerAdd0 = modfwpuclnt.NewProc("FwpmSubLayerAdd0")
)
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 uint32, authIdentity *uintptr, session *FWPM_SESSION0, 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 *FWPM_FILTER0, 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 FwpmSubLayerAdd0(engineHandle uintptr, subLayer *FWPM_SUBLAYER0, 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
}

View file

@ -4,6 +4,8 @@ import (
"crypto/md5" "crypto/md5"
"errors" "errors"
"fmt" "fmt"
"math"
"net"
"net/netip" "net/netip"
"os" "os"
"sync" "sync"
@ -12,8 +14,10 @@ import (
"unsafe" "unsafe"
"github.com/sagernet/sing-tun/internal/winipcfg" "github.com/sagernet/sing-tun/internal/winipcfg"
"github.com/sagernet/sing-tun/internal/winsys"
"github.com/sagernet/sing-tun/internal/wintun" "github.com/sagernet/sing-tun/internal/wintun"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/windnsapi"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@ -21,14 +25,15 @@ import (
var TunnelType = "sing-tun" var TunnelType = "sing-tun"
type NativeTun struct { type NativeTun struct {
adapter *wintun.Adapter adapter *wintun.Adapter
options Options options Options
session wintun.Session session wintun.Session
readWait windows.Handle readWait windows.Handle
rate rateJuggler rate rateJuggler
running sync.WaitGroup running sync.WaitGroup
closeOnce sync.Once closeOnce sync.Once
close int32 close int32
fwpmSession uintptr
} }
func Open(options Options) (WinTun, error) { func Open(options Options) (WinTun, error) {
@ -78,16 +83,41 @@ func (t *NativeTun) configure() error {
} }
} }
if t.options.AutoRoute { if t.options.AutoRoute {
if len(t.options.Inet4Address) > 0 { if t.options.StrictRoute {
err := luid.AddRoute(netip.PrefixFrom(netip.IPv4Unspecified(), 0), netip.IPv4Unspecified(), 0) if len(t.options.Inet4Address) > 0 {
if err != nil { for _, prefix := range []netip.Prefix{
return E.Cause(err, "set ipv4 route") netip.MustParsePrefix("0.0.0.0/1"),
netip.MustParsePrefix("128.0.0.0/1"),
} {
err := luid.AddRoute(prefix, netip.IPv4Unspecified(), 0)
if err != nil {
return E.Cause(err, "set ipv4 route")
}
}
} }
} if len(t.options.Inet6Address) > 0 {
if len(t.options.Inet6Address) > 0 { for _, prefix := range []netip.Prefix{
err := luid.AddRoute(netip.PrefixFrom(netip.IPv6Unspecified(), 0), netip.IPv6Unspecified(), 0) netip.MustParsePrefix("::/1"),
if err != nil { netip.MustParsePrefix("8000::/1"),
return E.Cause(err, "set ipv6 route") } {
err := luid.AddRoute(prefix, netip.IPv6Unspecified(), 0)
if err != nil {
return E.Cause(err, "set ipv6 route")
}
}
}
} else {
if len(t.options.Inet4Address) > 0 {
err := luid.AddRoute(netip.PrefixFrom(netip.IPv4Unspecified(), 0), netip.IPv4Unspecified(), 0)
if err != nil {
return E.Cause(err, "set ipv4 route")
}
}
if len(t.options.Inet6Address) > 0 {
err := luid.AddRoute(netip.PrefixFrom(netip.IPv6Unspecified(), 0), netip.IPv6Unspecified(), 0)
if err != nil {
return E.Cause(err, "set ipv6 route")
}
} }
} }
} }
@ -131,6 +161,187 @@ func (t *NativeTun) configure() error {
} }
} }
if t.options.AutoRoute {
var engine uintptr
session := &winsys.FWPM_SESSION0{Flags: winsys.FWPM_SESSION_FLAG_DYNAMIC}
err := winsys.FwpmEngineOpen0(nil, winsys.RPC_C_AUTHN_DEFAULT, nil, session, unsafe.Pointer(&engine))
if err != nil {
return os.NewSyscallError("FwpmEngineOpen0", err)
}
t.fwpmSession = engine
subLayerKey, err := windows.GenerateGUID()
if err != nil {
return os.NewSyscallError("CoCreateGuid", err)
}
subLayer := winsys.FWPM_SUBLAYER0{}
subLayer.SubLayerKey = subLayerKey
subLayer.DisplayData = winsys.CreateDisplayData("sing-box", "auto-route rules")
subLayer.Weight = math.MaxUint16
err = winsys.FwpmSubLayerAdd0(engine, &subLayer, 0)
if err != nil {
return os.NewSyscallError("FwpmSubLayerAdd0", err)
}
processAppID, err := winsys.GetCurrentProcessAppID()
if err != nil {
return err
}
defer winsys.FwpmFreeMemory0(unsafe.Pointer(&processAppID))
var filterId uint64
permitCondition := make([]winsys.FWPM_FILTER_CONDITION0, 1)
permitCondition[0].FieldKey = winsys.FWPM_CONDITION_ALE_APP_ID
permitCondition[0].MatchType = winsys.FWP_MATCH_EQUAL
permitCondition[0].ConditionValue.Type = winsys.FWP_BYTE_BLOB_TYPE
permitCondition[0].ConditionValue.Value = uintptr(unsafe.Pointer(processAppID))
permitFilter4 := winsys.FWPM_FILTER0{}
permitFilter4.FilterCondition = &permitCondition[0]
permitFilter4.NumFilterConditions = 1
permitFilter4.DisplayData = winsys.CreateDisplayData("sing-box", "protect ipv4")
permitFilter4.SubLayerKey = subLayerKey
permitFilter4.LayerKey = winsys.FWPM_LAYER_ALE_AUTH_CONNECT_V4
permitFilter4.Action.Type = winsys.FWP_ACTION_PERMIT
permitFilter4.Weight.Type = winsys.FWP_UINT8
permitFilter4.Weight.Value = uintptr(12)
permitFilter4.Flags = winsys.FWPM_FILTER_FLAG_CLEAR_ACTION_RIGHT
err = winsys.FwpmFilterAdd0(engine, &permitFilter4, 0, &filterId)
if err != nil {
return os.NewSyscallError("FwpmFilterAdd0", err)
}
permitFilter6 := winsys.FWPM_FILTER0{}
permitFilter6.FilterCondition = &permitCondition[0]
permitFilter6.NumFilterConditions = 1
permitFilter6.DisplayData = winsys.CreateDisplayData("sing-box", "protect ipv6")
permitFilter6.SubLayerKey = subLayerKey
permitFilter6.LayerKey = winsys.FWPM_LAYER_ALE_AUTH_CONNECT_V6
permitFilter6.Action.Type = winsys.FWP_ACTION_PERMIT
permitFilter6.Weight.Type = winsys.FWP_UINT8
permitFilter6.Weight.Value = uintptr(12)
permitFilter6.Flags = winsys.FWPM_FILTER_FLAG_CLEAR_ACTION_RIGHT
err = winsys.FwpmFilterAdd0(engine, &permitFilter6, 0, &filterId)
if err != nil {
return os.NewSyscallError("FwpmFilterAdd0", err)
}
if len(t.options.Inet4Address) == 0 {
blockFilter := winsys.FWPM_FILTER0{}
blockFilter.DisplayData = winsys.CreateDisplayData("sing-box", "block ipv4")
blockFilter.SubLayerKey = subLayerKey
blockFilter.LayerKey = winsys.FWPM_LAYER_ALE_AUTH_CONNECT_V4
blockFilter.Action.Type = winsys.FWP_ACTION_BLOCK
blockFilter.Weight.Type = winsys.FWP_UINT8
blockFilter.Weight.Value = uintptr(13)
err = winsys.FwpmFilterAdd0(engine, &blockFilter, 0, &filterId)
if err != nil {
return os.NewSyscallError("FwpmFilterAdd0", err)
}
}
if len(t.options.Inet6Address) == 0 {
blockFilter := winsys.FWPM_FILTER0{}
blockFilter.DisplayData = winsys.CreateDisplayData("sing-box", "block ipv6")
blockFilter.SubLayerKey = subLayerKey
blockFilter.LayerKey = winsys.FWPM_LAYER_ALE_AUTH_CONNECT_V6
blockFilter.Action.Type = winsys.FWP_ACTION_BLOCK
blockFilter.Weight.Type = winsys.FWP_UINT8
blockFilter.Weight.Value = uintptr(13)
err = winsys.FwpmFilterAdd0(engine, &blockFilter, 0, &filterId)
if err != nil {
return os.NewSyscallError("FwpmFilterAdd0", err)
}
}
netInterface, err := net.InterfaceByName(t.options.Name)
if err != nil {
return err
}
tunCondition := make([]winsys.FWPM_FILTER_CONDITION0, 1)
tunCondition[0].FieldKey = winsys.FWPM_CONDITION_LOCAL_INTERFACE_INDEX
tunCondition[0].MatchType = winsys.FWP_MATCH_EQUAL
tunCondition[0].ConditionValue.Type = winsys.FWP_UINT32
tunCondition[0].ConditionValue.Value = uintptr(uint32(netInterface.Index))
if len(t.options.Inet4Address) > 0 {
tunFilter4 := winsys.FWPM_FILTER0{}
tunFilter4.FilterCondition = &tunCondition[0]
tunFilter4.NumFilterConditions = 1
tunFilter4.DisplayData = winsys.CreateDisplayData("sing-box", "allow ipv4")
tunFilter4.SubLayerKey = subLayerKey
tunFilter4.LayerKey = winsys.FWPM_LAYER_ALE_AUTH_CONNECT_V4
tunFilter4.Action.Type = winsys.FWP_ACTION_PERMIT
tunFilter4.Weight.Type = winsys.FWP_UINT8
tunFilter4.Weight.Value = uintptr(11)
err = winsys.FwpmFilterAdd0(engine, &tunFilter4, 0, &filterId)
if err != nil {
return os.NewSyscallError("FwpmFilterAdd0", err)
}
}
if len(t.options.Inet6Address) > 0 {
tunFilter6 := winsys.FWPM_FILTER0{}
tunFilter6.FilterCondition = &tunCondition[0]
tunFilter6.NumFilterConditions = 1
tunFilter6.DisplayData = winsys.CreateDisplayData("sing-box", "allow ipv6")
tunFilter6.SubLayerKey = subLayerKey
tunFilter6.LayerKey = winsys.FWPM_LAYER_ALE_AUTH_CONNECT_V6
tunFilter6.Action.Type = winsys.FWP_ACTION_PERMIT
tunFilter6.Weight.Type = winsys.FWP_UINT8
tunFilter6.Weight.Value = uintptr(11)
err = winsys.FwpmFilterAdd0(engine, &tunFilter6, 0, &filterId)
if err != nil {
return os.NewSyscallError("FwpmFilterAdd0", err)
}
}
blockDNSCondition := make([]winsys.FWPM_FILTER_CONDITION0, 2)
blockDNSCondition[0].FieldKey = winsys.FWPM_CONDITION_IP_PROTOCOL
blockDNSCondition[0].MatchType = winsys.FWP_MATCH_EQUAL
blockDNSCondition[0].ConditionValue.Type = winsys.FWP_UINT8
blockDNSCondition[0].ConditionValue.Value = uintptr(uint8(winsys.IPPROTO_UDP))
blockDNSCondition[1].FieldKey = winsys.FWPM_CONDITION_IP_REMOTE_PORT
blockDNSCondition[1].MatchType = winsys.FWP_MATCH_EQUAL
blockDNSCondition[1].ConditionValue.Type = winsys.FWP_UINT16
blockDNSCondition[1].ConditionValue.Value = uintptr(uint16(53))
blockDNSFilter4 := winsys.FWPM_FILTER0{}
blockDNSFilter4.FilterCondition = &blockDNSCondition[0]
blockDNSFilter4.NumFilterConditions = 2
blockDNSFilter4.DisplayData = winsys.CreateDisplayData("sing-box", "block ipv4 dns")
blockDNSFilter4.SubLayerKey = subLayerKey
blockDNSFilter4.LayerKey = winsys.FWPM_LAYER_ALE_AUTH_CONNECT_V4
blockDNSFilter4.Action.Type = winsys.FWP_ACTION_BLOCK
blockDNSFilter4.Weight.Type = winsys.FWP_UINT8
blockDNSFilter4.Weight.Value = uintptr(10)
err = winsys.FwpmFilterAdd0(engine, &blockDNSFilter4, 0, &filterId)
if err != nil {
return os.NewSyscallError("FwpmFilterAdd0", err)
}
blockDNSFilter6 := winsys.FWPM_FILTER0{}
blockDNSFilter6.FilterCondition = &blockDNSCondition[0]
blockDNSFilter6.NumFilterConditions = 2
blockDNSFilter6.DisplayData = winsys.CreateDisplayData("sing-box", "block ipv6 dns")
blockDNSFilter6.SubLayerKey = subLayerKey
blockDNSFilter6.LayerKey = winsys.FWPM_LAYER_ALE_AUTH_CONNECT_V6
blockDNSFilter6.Action.Type = winsys.FWP_ACTION_BLOCK
blockDNSFilter6.Weight.Type = winsys.FWP_UINT8
blockDNSFilter6.Weight.Value = uintptr(10)
err = winsys.FwpmFilterAdd0(engine, &blockDNSFilter6, 0, &filterId)
if err != nil {
return os.NewSyscallError("FwpmFilterAdd0", err)
}
err = windnsapi.FlushResolverCache()
if err != nil {
return err
}
}
return nil return nil
} }
@ -269,6 +480,10 @@ func (t *NativeTun) Close() error {
t.running.Wait() t.running.Wait()
t.session.End() t.session.End()
t.adapter.Close() t.adapter.Close()
if t.fwpmSession != 0 {
winsys.FwpmEngineClose0(t.fwpmSession)
}
windnsapi.FlushResolverCache()
}) })
return err return err
} }