mirror of
https://github.com/qtgolang/SunnyNet.git
synced 2026-08-30 22:11:29 -07:00
2025-10-23
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
/BuildLibrary/Library
|
||||
/.idea
|
||||
/SunnyNetWebview
|
||||
|
||||
@@ -1003,6 +1003,22 @@ func CloseWebsocket(Theology int) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
GetMessageNote 获取请求中的注释,由脚本代码中设置
|
||||
*/
|
||||
func GetMessageNote(MessageId int) string {
|
||||
k, ok := SunnyNet.GetSceneProxyRequest(MessageId)
|
||||
if ok == false {
|
||||
return ""
|
||||
}
|
||||
if k == nil {
|
||||
return ""
|
||||
}
|
||||
k.Lock.Lock()
|
||||
defer k.Lock.Unlock()
|
||||
return k.GetNote()
|
||||
}
|
||||
|
||||
// GetWebsocketBodyLen 获取 WebSocket消息长度
|
||||
func GetWebsocketBodyLen(MessageId int) int {
|
||||
k, ok := SunnyNet.GetSceneWebSocketMsg(MessageId)
|
||||
@@ -1359,13 +1375,13 @@ func CancelIEProxy(SunnyContext int) bool {
|
||||
}
|
||||
|
||||
// OpenDrive 开始进程代理/打开驱动 只允许一个 SunnyNet 使用 [会自动安装所需驱动文件]
|
||||
// IsNfapi 如果为true表示使用NFAPI驱动 如果为false 表示使用Proxifier
|
||||
func OpenDrive(SunnyContext int, IsNf bool) bool {
|
||||
// DevMode 0=Proxifier,1=NFAPI 2=Tun
|
||||
func OpenDrive(SunnyContext int, DevMode int) bool {
|
||||
SunnyNet.SunnyStorageLock.Lock()
|
||||
w := SunnyNet.SunnyStorage[SunnyContext]
|
||||
SunnyNet.SunnyStorageLock.Unlock()
|
||||
if w != nil {
|
||||
return w.OpenDrive(IsNf)
|
||||
return w.OpenDrive(DevMode)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
34
Api/UDP.go
34
Api/UDP.go
@@ -1,35 +1,27 @@
|
||||
package Api
|
||||
|
||||
import (
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/nfapi"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/SunnyNetUDP"
|
||||
)
|
||||
|
||||
func SetUdpData(MessageId int, data []byte) bool {
|
||||
NFapi.UdpSync.Lock()
|
||||
buff := NFapi.UdpMap[MessageId]
|
||||
if buff != nil {
|
||||
buff.Reset()
|
||||
buff.Write(data)
|
||||
NFapi.UdpSync.Unlock()
|
||||
return true
|
||||
}
|
||||
NFapi.UdpSync.Unlock()
|
||||
return false
|
||||
return SunnyNetUDP.SetMessage(MessageId, data)
|
||||
}
|
||||
func GetUdpData(MessageId int) []byte {
|
||||
NFapi.UdpSync.Lock()
|
||||
buff := NFapi.UdpMap[MessageId]
|
||||
if buff != nil {
|
||||
NFapi.UdpSync.Unlock()
|
||||
return buff.Bytes()
|
||||
}
|
||||
NFapi.UdpSync.Unlock()
|
||||
return nil
|
||||
return SunnyNetUDP.GetMessage(MessageId)
|
||||
}
|
||||
|
||||
func UdpSendToServer(tid int, data []byte) bool {
|
||||
return NFapi.UdpSendToServer(int64(tid), data)
|
||||
obj := SunnyNetUDP.GetUDPItem(int64(tid))
|
||||
if obj != nil {
|
||||
return obj.ToServer(data)
|
||||
}
|
||||
return false
|
||||
}
|
||||
func UdpSendToClient(tid int, data []byte) bool {
|
||||
return NFapi.UdpSendToClient(int64(tid), data)
|
||||
obj := SunnyNetUDP.GetUDPItem(int64(tid))
|
||||
if obj != nil {
|
||||
return obj.ToClient(data)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -215,8 +215,10 @@ func HTTPSendBin(Context int, data []byte) {
|
||||
}
|
||||
if k.req.ContentLength > 0 {
|
||||
k.req.Header["Content-Length"] = []string{fmt.Sprintf("%d", len(data))}
|
||||
k.req.ContentLength = int64(len(data))
|
||||
} else {
|
||||
k.req.Header.Del("Content-Length")
|
||||
k.req.ContentLength = 0
|
||||
}
|
||||
var random func() []uint16
|
||||
if k.randomTLS {
|
||||
|
||||
@@ -12,8 +12,5 @@ set GOOS=android
|
||||
set GOARCH=arm64
|
||||
set CC=%NDK%\bin\aarch64-linux-android21-clang
|
||||
echo [Full]_Build_Android_arm64-v8a.so
|
||||
go build -ldflags "-s -w" -o "%tmpPath%Library/Full/Android/arm64-v8a/SunnyNet"
|
||||
echo [Mini]_Build_Android_arm64-v8a.so
|
||||
go build -tags mini -ldflags "-s -w" -o "%tmpPath%Library/Mini/Android/arm64-v8a/SunnyNet"
|
||||
|
||||
go build -trimpath -buildmode=c-shared -ldflags "-s -w" -o "G:\AndroidProject\TunTest\app\src\main\jniLibs\arm64-v8a\libSunnyNet.so"
|
||||
@echo on
|
||||
|
||||
@@ -26,6 +26,14 @@ echo [Mini]_Build_x64_DLL
|
||||
go build -trimpath -tags mini -buildmode=c-shared -ldflags "-s -w" -o "%tmpPath%Library\Mini\windows\SunnyNet64.dll"
|
||||
|
||||
|
||||
set GOOS=android
|
||||
set GOARCH=arm64
|
||||
set CC=%NDK%\bin\aarch64-linux-android21-clang
|
||||
echo [Full]_Build_Android_arm64-v8a.so
|
||||
go build -trimpath -buildmode=c-shared -ldflags "-s -w" -o "%tmpPath%Library/Full/Android/arm64-v8a/libSunnyNet.so"
|
||||
echo [Mini]_Build_Android_arm64-v8a.so
|
||||
go build -trimpath -tags mini -buildmode=c-shared -ldflags "-s -w" -o "%tmpPath%Library/Mini/Android/arm64-v8a/libSunnyNet.so"
|
||||
|
||||
set GOOS=android
|
||||
set GOARCH=arm
|
||||
set CC=%NDK%\bin\armv7a-linux-androideabi21-clang
|
||||
@@ -35,12 +43,21 @@ echo [Mini]_Build_Android_armeabi-v7a.so
|
||||
go build -trimpath -tags mini -buildmode=c-shared -ldflags "-s -w" -o "%tmpPath%Library/Mini/Android/armeabi-v7a/libSunnyNet.so"
|
||||
|
||||
set GOOS=android
|
||||
set GOARCH=arm64
|
||||
set CC=%NDK%\bin\aarch64-linux-android21-clang
|
||||
echo [Full]_Build_Android_arm64-v8a.so
|
||||
go build -trimpath -buildmode=c-shared -ldflags "-s -w" -o "%tmpPath%Library/Full/Android/arm64-v8a/libSunnyNet.so"
|
||||
echo [Mini]_Build_Android_arm64-v8a.so
|
||||
go build -trimpath -tags mini -buildmode=c-shared -ldflags "-s -w" -o "%tmpPath%Library/Mini/Android/arm64-v8a/libSunnyNet.so"
|
||||
set GOARCH=386
|
||||
set CC=%NDK%\bin\x86_64-linux-android21-clang
|
||||
echo [Full]_Build_Android_x86.so
|
||||
go build -trimpath -buildmode=c-shared -ldflags "-s -w" -o "%tmpPath%Library/Full/Android/x86/libSunnyNet.so"
|
||||
echo [Mini]_Build_Android_x86.so
|
||||
go build -trimpath -tags mini -buildmode=c-shared -ldflags "-s -w" -o "%tmpPath%Library/Mini/Android/x86/libSunnyNet.so"
|
||||
|
||||
set GOOS=android
|
||||
set GOARCH=386
|
||||
set CC=%NDK%\bin\x86_64-linux-android21-clang
|
||||
echo [Full]_Build_Android_x86_64.so
|
||||
go build -trimpath -buildmode=c-shared -ldflags "-s -w" -o "%tmpPath%Library/Full/Android/x86_64/libSunnyNet.so"
|
||||
echo [Mini]_Build_Android_x86_64.so
|
||||
go build -trimpath -tags mini -buildmode=c-shared -ldflags "-s -w" -o "%tmpPath%Library/Mini/Android/x86_64/libSunnyNet.so"
|
||||
|
||||
|
||||
set GOOS=android
|
||||
set GOARCH=386
|
||||
|
||||
10
BuildLibrary/BuildT.bat
Normal file
10
BuildLibrary/BuildT.bat
Normal file
@@ -0,0 +1,10 @@
|
||||
@echo off
|
||||
set CGO_ENABLED=1
|
||||
set GOOS=windows
|
||||
set GOARCH=386
|
||||
set tmpPath=%~dp0
|
||||
cd %tmpPath:~0,1%:
|
||||
for %%I in ("%tmpPath%..\") do set "parentPath=%%~fI"
|
||||
cd %parentPath%
|
||||
go build -trimpath -buildmode=c-shared -tags mini -ldflags "-s -w" -o "G:\Sunny\SunnyNet\BuildLibrary\SunnyNet.dll"
|
||||
@echo on
|
||||
BIN
BuildLibrary/SunnyNet.dll
Normal file
BIN
BuildLibrary/SunnyNet.dll
Normal file
Binary file not shown.
1989
BuildLibrary/SunnyNet.h
Normal file
1989
BuildLibrary/SunnyNet.h
Normal file
File diff suppressed because it is too large
Load Diff
172
JavaApi.go
172
JavaApi.go
@@ -11,8 +11,11 @@ import (
|
||||
"github.com/qtgolang/SunnyNet/JavaApi/sig"
|
||||
"github.com/qtgolang/SunnyNet/SunnyNet"
|
||||
"github.com/qtgolang/SunnyNet/src/Compress"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/SunnyNetUDP"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/tun"
|
||||
"github.com/qtgolang/SunnyNet/src/dns"
|
||||
"github.com/qtgolang/SunnyNet/src/public"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
@@ -154,103 +157,98 @@ func Java_com_SunnyNet_api_SunnyNetSetCallback(envObj uintptr, clazz uintptr, Su
|
||||
env.ThrowNew(env.FindClass("java/lang/RuntimeException"), "Find Class [onUDPCallback"+FuncSig+"] failed")
|
||||
panic("Find Class [onUDPCallback" + FuncSig + "] failed")
|
||||
}
|
||||
|
||||
httpCallback := func(Conn SunnyNet.ConnHTTP) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
_env, ret := ___Java_GlobalVM.AttachCurrentThread()
|
||||
if ret != JNI_OK {
|
||||
return
|
||||
}
|
||||
defer ___Java_GlobalVM.DetachCurrentThread()
|
||||
|
||||
EventClass := _env.FindClass("com/SunnyNet/Internal/HTTPEvent")
|
||||
if EventClass == 0 {
|
||||
_env.ThrowNew(_env.FindClass("java/lang/RuntimeException"), "Find Class [com/SunnyNet/Internal/HTTPEvent] failed")
|
||||
panic("Find Class [com/SunnyNet/Internal/HTTPEvent] failed")
|
||||
}
|
||||
_Method := _env.NewString(Conn.Method())
|
||||
_url := _env.NewString(Conn.URL())
|
||||
_er := _env.NewString(Conn.Error())
|
||||
|
||||
EventConstructor := _env.GetMethodID(EventClass, "<init>", fmt.Sprintf("(%s%s%s%s%s%s%s%s)%s", sig.Long, sig.Long, sig.Long, sig.Long, sig.String, sig.String, sig.String, sig.Long, sig.Void))
|
||||
EventObj := _env.NewObjectA(EventClass, EventConstructor, Jvalue(SunnyContext), Jvalue(Conn.Theology()), Jvalue(Conn.MessageId()), Jvalue(Conn.Type()), Jvalue(_Method), Jvalue(_url), Jvalue(_er), Jvalue(Conn.PID()))
|
||||
HTTPEventClass := aliasToClass("HTTPEvent")
|
||||
EventConstructor := _env.GetMethodID(HTTPEventClass, "<init>", fmt.Sprintf("(%s%s%s%s%s%s%s%s)%s", sig.Long, sig.Long, sig.Long, sig.Long, sig.String, sig.String, sig.String, sig.Long, sig.Void))
|
||||
EventObj := _env.NewObjectA(HTTPEventClass, EventConstructor, Jvalue(SunnyContext), Jvalue(Conn.Theology()), Jvalue(Conn.MessageId()), Jvalue(Conn.Type()), Jvalue(_Method), Jvalue(_url), Jvalue(_er), Jvalue(Conn.PID()))
|
||||
|
||||
_env.CallVoidMethodA(obj, onHTTPCallbackMethodId, Jvalue(EventObj))
|
||||
_env.DeleteLocalRef(EventClass)
|
||||
_env.DeleteLocalRef(EventObj)
|
||||
_env.DeleteLocalRef(_Method)
|
||||
_env.DeleteLocalRef(_url)
|
||||
_env.DeleteLocalRef(_er)
|
||||
return
|
||||
}
|
||||
|
||||
tcpCallback := func(Conn SunnyNet.ConnTCP) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
_env, ret := ___Java_GlobalVM.AttachCurrentThread()
|
||||
if ret != JNI_OK {
|
||||
return
|
||||
}
|
||||
defer ___Java_GlobalVM.DetachCurrentThread()
|
||||
EventClass := _env.FindClass("com/SunnyNet/Internal/TCPEvent")
|
||||
if EventClass == 0 {
|
||||
_env.ThrowNew(_env.FindClass("java/lang/RuntimeException"), "Find Class [com/SunnyNet/Internal/TCPEvent] failed")
|
||||
panic("Find Class [com/SunnyNet/Internal/TCPEvent] failed")
|
||||
}
|
||||
|
||||
_LocalAddr := _env.NewString(Conn.LocalAddress())
|
||||
_RemoteAddr := _env.NewString(Conn.RemoteAddress())
|
||||
_data := _env.NewByteArray(Conn.Body())
|
||||
EventConstructor := _env.GetMethodID(EventClass, "<init>", fmt.Sprintf("(%s%s%s%s%s%s%s%s)%s", sig.Long, sig.String, sig.String, sig.Long, sig.Long, sig.Long, sig.Long, sig.ByteArray, sig.Void))
|
||||
EventObj := _env.NewObjectA(EventClass, EventConstructor, Jvalue(SunnyContext), Jvalue(_LocalAddr), Jvalue(_RemoteAddr), Jvalue(Conn.Theology()), Jvalue(Conn.MessageId()), Jvalue(Conn.Type()), Jvalue(Conn.PID()), Jvalue(_data))
|
||||
TCPEventClass := aliasToClass("TCPEvent")
|
||||
EventConstructor := _env.GetMethodID(TCPEventClass, "<init>", fmt.Sprintf("(%s%s%s%s%s%s%s%s)%s", sig.Long, sig.String, sig.String, sig.Long, sig.Long, sig.Long, sig.Long, sig.ByteArray, sig.Void))
|
||||
EventObj := _env.NewObjectA(TCPEventClass, EventConstructor, Jvalue(SunnyContext), Jvalue(_LocalAddr), Jvalue(_RemoteAddr), Jvalue(Conn.Theology()), Jvalue(Conn.MessageId()), Jvalue(Conn.Type()), Jvalue(Conn.PID()), Jvalue(_data))
|
||||
|
||||
_env.CallVoidMethodA(obj, onTCPMethodId, Jvalue(EventObj))
|
||||
_env.DeleteLocalRef(EventClass)
|
||||
_env.DeleteLocalRef(EventObj)
|
||||
_env.DeleteLocalRef(_LocalAddr)
|
||||
_env.DeleteLocalRef(_RemoteAddr)
|
||||
_env.DeleteLocalRef(_data)
|
||||
}
|
||||
|
||||
wsCallback := func(Conn SunnyNet.ConnWebSocket) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
_env, ret := ___Java_GlobalVM.AttachCurrentThread()
|
||||
if ret != JNI_OK {
|
||||
return
|
||||
}
|
||||
defer ___Java_GlobalVM.DetachCurrentThread()
|
||||
|
||||
EventClass := _env.FindClass("com/SunnyNet/Internal/WebSocketEvent")
|
||||
if EventClass == 0 {
|
||||
_env.ThrowNew(_env.FindClass("java/lang/RuntimeException"), "Find Class [com/SunnyNet/Internal/WebSocketEvent] failed")
|
||||
panic("Find Class [com/SunnyNet/Internal/WebSocketEvent] failed")
|
||||
}
|
||||
_Method := _env.NewString(Conn.Method())
|
||||
_url := _env.NewString(Conn.URL())
|
||||
EventConstructor := _env.GetMethodID(EventClass, "<init>", fmt.Sprintf("(%s%s%s%s%s%s%s%s)%s", sig.Long, sig.Long, sig.Long, sig.Long, sig.String, sig.String, sig.Long, sig.Long, sig.Void))
|
||||
EventObj := _env.NewObjectA(EventClass, EventConstructor, Jvalue(SunnyContext), Jvalue(Conn.Theology()), Jvalue(Conn.MessageId()), Jvalue(Conn.Type()), Jvalue(_Method), Jvalue(_url), Jvalue(Conn.PID()), Jvalue(Conn.MessageType()))
|
||||
WebSocketEventClass := aliasToClass("WebSocketEvent")
|
||||
EventConstructor := _env.GetMethodID(WebSocketEventClass, "<init>", fmt.Sprintf("(%s%s%s%s%s%s%s%s)%s", sig.Long, sig.Long, sig.Long, sig.Long, sig.String, sig.String, sig.Long, sig.Long, sig.Void))
|
||||
EventObj := _env.NewObjectA(WebSocketEventClass, EventConstructor, Jvalue(SunnyContext), Jvalue(Conn.Theology()), Jvalue(Conn.MessageId()), Jvalue(Conn.Type()), Jvalue(_Method), Jvalue(_url), Jvalue(Conn.PID()), Jvalue(Conn.MessageType()))
|
||||
|
||||
_env.CallVoidMethodA(obj, onWebSocketMethodId, Jvalue(EventObj))
|
||||
_env.DeleteLocalRef(_Method)
|
||||
_env.DeleteLocalRef(_url)
|
||||
_env.DeleteLocalRef(EventClass)
|
||||
_env.DeleteLocalRef(EventObj)
|
||||
return
|
||||
}
|
||||
|
||||
udpCallback := func(Conn SunnyNet.ConnUDP) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
_env, ret := ___Java_GlobalVM.AttachCurrentThread()
|
||||
if ret != JNI_OK {
|
||||
return
|
||||
}
|
||||
defer ___Java_GlobalVM.DetachCurrentThread()
|
||||
EventClass := _env.FindClass("com/SunnyNet/Internal/UDPEvent")
|
||||
if EventClass == 0 {
|
||||
_env.ThrowNew(_env.FindClass("java/lang/RuntimeException"), "Find Class [com/SunnyNet/Internal/UDPEvent] failed")
|
||||
panic("Find Class [com/SunnyNet/Internal/UDPEvent] failed")
|
||||
}
|
||||
MessageId := Conn.MessageId()
|
||||
SunnyNetUDP.ResetMessage(MessageId, Conn.Body())
|
||||
|
||||
_LocalAddr := _env.NewString(Conn.LocalAddress())
|
||||
_RemoteAddr := _env.NewString(Conn.RemoteAddress())
|
||||
EventConstructor := _env.GetMethodID(EventClass, "<init>", fmt.Sprintf("(%s%s%s%s%s%s%s)%s", sig.Long, sig.String, sig.String, sig.Long, sig.Long, sig.Long, sig.Long, sig.Void))
|
||||
EventObj := _env.NewObjectA(EventClass, EventConstructor, Jvalue(SunnyContext), Jvalue(_LocalAddr), Jvalue(_RemoteAddr), Jvalue(Conn.Theology()), Jvalue(Conn.MessageId()), Jvalue(Conn.Type()), Jvalue(Conn.PID()))
|
||||
UDPEventClass := aliasToClass("UDPEvent")
|
||||
EventConstructor := _env.GetMethodID(UDPEventClass, "<init>", fmt.Sprintf("(%s%s%s%s%s%s%s)%s", sig.Long, sig.String, sig.String, sig.Long, sig.Long, sig.Long, sig.Long, sig.Void))
|
||||
EventObj := _env.NewObjectA(UDPEventClass, EventConstructor, Jvalue(SunnyContext), Jvalue(_LocalAddr), Jvalue(_RemoteAddr), Jvalue(Conn.Theology()), Jvalue(MessageId), Jvalue(Conn.Type()), Jvalue(Conn.PID()))
|
||||
_env.CallVoidMethodA(obj, onUDPMethodId, Jvalue(EventObj))
|
||||
_env.DeleteLocalRef(EventClass)
|
||||
_env.DeleteLocalRef(EventObj)
|
||||
_env.DeleteLocalRef(_LocalAddr)
|
||||
_env.DeleteLocalRef(_RemoteAddr)
|
||||
|
||||
Conn.SetBody(SunnyNetUDP.GetMessage(MessageId))
|
||||
SunnyNetUDP.DelMessage(MessageId)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -266,6 +264,8 @@ func Java_com_SunnyNet_api_SunnyNetSetCallback(envObj uintptr, clazz uintptr, Su
|
||||
panic("Find Class [onScriptCodeSaveCallback" + FuncSig + "] failed")
|
||||
}
|
||||
log := func(Context int, info ...any) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
_env, ret := ___Java_GlobalVM.AttachCurrentThread()
|
||||
if ret != JNI_OK {
|
||||
return
|
||||
@@ -276,6 +276,8 @@ func Java_com_SunnyNet_api_SunnyNetSetCallback(envObj uintptr, clazz uintptr, Su
|
||||
_env.DeleteLocalRef(_logInfo)
|
||||
}
|
||||
code := func(Context int, code []byte) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
_env, ret := ___Java_GlobalVM.AttachCurrentThread()
|
||||
if ret != JNI_OK {
|
||||
return
|
||||
@@ -628,6 +630,15 @@ func Java_com_SunnyNet_api_GetRequestAllHeader(envObj uintptr, clazz uintptr, Me
|
||||
return env.NewString(r)
|
||||
}
|
||||
|
||||
/*
|
||||
ava_com_SunnyNet_api_GetMessageNote 获取请求中的注释,由脚本代码中设置
|
||||
*/
|
||||
//export ava_com_SunnyNet_api_GetMessageNote
|
||||
func ava_com_SunnyNet_api_GetMessageNote(envObj uintptr, clazz uintptr, MessageId int64) uintptr {
|
||||
env := Env(envObj)
|
||||
return env.NewString(Api.GetMessageNote(int(MessageId)))
|
||||
}
|
||||
|
||||
/*
|
||||
Java_com_SunnyNet_api_SetRequestProxy 设置HTTP/S请求代理,仅支持Socket5和http 例如 socket5://admin:123456@127.0.0.1:8888 或 http://admin:123456@127.0.0.1:8888
|
||||
*/
|
||||
@@ -962,8 +973,8 @@ func Java_com_SunnyNet_api_WebpToPng(envObj uintptr, clazz uintptr, webpPath, sa
|
||||
Java_com_SunnyNet_api_OpenDrive 开启进程代理/打开驱动
|
||||
*/
|
||||
//export Java_com_SunnyNet_api_OpenDrive
|
||||
func Java_com_SunnyNet_api_OpenDrive(envObj uintptr, clazz uintptr, SunnyContext int64, isNf bool) bool {
|
||||
return Api.OpenDrive(int(SunnyContext), isNf)
|
||||
func Java_com_SunnyNet_api_OpenDrive(envObj uintptr, clazz uintptr, SunnyContext int64, devMode int64) bool {
|
||||
return Api.OpenDrive(int(SunnyContext), int(devMode))
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1480,6 +1491,8 @@ func Java_com_SunnyNet_api_SocketClientDial(envObj uintptr, clazz uintptr, Conte
|
||||
panic("Find Class [onCallback(JJ[B)V] failed")
|
||||
}
|
||||
f := func(Context, types int, bs []byte) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
_env, ret := ___Java_GlobalVM.AttachCurrentThread()
|
||||
if ret != JNI_OK {
|
||||
return
|
||||
@@ -1593,6 +1606,8 @@ func Java_com_SunnyNet_api_WebsocketHeartbeat(envObj uintptr, clazz uintptr, Con
|
||||
methodId := env.GetMethodID(cls, "onHeartbeatCallback", "(J)V")
|
||||
if methodId != 0 {
|
||||
Api.WebsocketHeartbeat(int(Context), int(HeartbeatTime), 0, func(_Context int) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
_env, ret := ___Java_GlobalVM.AttachCurrentThread()
|
||||
if ret != JNI_OK {
|
||||
return
|
||||
@@ -1625,6 +1640,8 @@ func Java_com_SunnyNet_api_WebsocketDial(envObj uintptr, clazz uintptr, Context
|
||||
panic("Find Class [onCallback(JJ[BJ)V] failed")
|
||||
}
|
||||
f := func(Context, types int, bs []byte, messageType int) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
_env, ret := ___Java_GlobalVM.AttachCurrentThread()
|
||||
if ret != JNI_OK {
|
||||
return
|
||||
@@ -1704,6 +1721,8 @@ func Java_com_SunnyNet_api_RedisSubscribe(envObj uintptr, clazz uintptr, Context
|
||||
panic("Find Class [onCallback(Ljava/lang/String;)V] failed")
|
||||
}
|
||||
f := func(message string) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
_env, ret := ___Java_GlobalVM.AttachCurrentThread()
|
||||
if ret != JNI_OK {
|
||||
return
|
||||
@@ -2027,6 +2046,11 @@ func Java_com_SunnyNet_api_HTTPSetOutRouterIP(envObj uintptr, clazz uintptr, Mes
|
||||
return Api.HTTPSetOutRouterIP(int(MessageId), env.GetString(value))
|
||||
}
|
||||
|
||||
//export Java_com_SunnyNet_api_OnTunSetFd
|
||||
func Java_com_SunnyNet_api_OnTunSetFd(JavaVM uintptr, reserved uintptr, fd int64) {
|
||||
tun.SetFd(int(fd))
|
||||
}
|
||||
|
||||
type _GlobalRef struct {
|
||||
obj uintptr
|
||||
Type string
|
||||
@@ -2044,39 +2068,42 @@ func Java_GlobalRef_Add(Type string, obj uintptr, Context int) {
|
||||
___Java_GlobalRef_index++
|
||||
___Java_GlobalRef_map[___Java_GlobalRef_index] = _GlobalRef{obj: obj, Type: Type, Context: Context}
|
||||
}
|
||||
|
||||
func goJavaInit() {
|
||||
// 固定在一个线程上
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
if ___Java_GlobalVM == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
env, ok := ___Java_GlobalVM.AttachCurrentThread()
|
||||
if ok != JNI_OK {
|
||||
return
|
||||
}
|
||||
defer ___Java_GlobalVM.DetachCurrentThread() // 退出时再 detach
|
||||
|
||||
for {
|
||||
time.Sleep(10 * time.Second)
|
||||
if ___Java_GlobalVM == 0 {
|
||||
return
|
||||
}
|
||||
env, ok := ___Java_GlobalVM.AttachCurrentThread()
|
||||
if ok != JNI_OK {
|
||||
continue
|
||||
}
|
||||
|
||||
for key, v := range ___Java_GlobalRef_map {
|
||||
switch v.Type {
|
||||
case "SocketClient":
|
||||
w := Api.LoadSocketContext(v.Context)
|
||||
if w == nil {
|
||||
if Api.LoadSocketContext(v.Context) == nil {
|
||||
env.DeleteGlobalRef(v.obj)
|
||||
delete(___Java_GlobalRef_map, key)
|
||||
}
|
||||
break
|
||||
case "Redis":
|
||||
w := Api.LoadRedisContext(v.Context)
|
||||
if w == nil {
|
||||
if Api.LoadRedisContext(v.Context) == nil {
|
||||
env.DeleteGlobalRef(v.obj)
|
||||
delete(___Java_GlobalRef_map, key)
|
||||
}
|
||||
break
|
||||
case "websocket":
|
||||
w := Api.LoadWebSocketContext(v.Context)
|
||||
if w == nil {
|
||||
if Api.LoadWebSocketContext(v.Context) == nil {
|
||||
env.DeleteGlobalRef(v.obj)
|
||||
delete(___Java_GlobalRef_map, key)
|
||||
}
|
||||
break
|
||||
case "SunnyNet":
|
||||
SunnyNet.SunnyStorageLock.Lock()
|
||||
w := SunnyNet.SunnyStorage[v.Context]
|
||||
@@ -2085,18 +2112,53 @@ func goJavaInit() {
|
||||
env.DeleteGlobalRef(v.obj)
|
||||
delete(___Java_GlobalRef_map, key)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
___Java_GlobalVM.DetachCurrentThread()
|
||||
}
|
||||
}
|
||||
|
||||
var ___Java_GlobalVM VM
|
||||
|
||||
var _classList = make(map[string]Jclass)
|
||||
var _classLock sync.Mutex
|
||||
|
||||
func aliasToClass(ClassAlias string) Jclass {
|
||||
_classLock.Lock()
|
||||
defer _classLock.Unlock()
|
||||
return _classList[ClassAlias]
|
||||
}
|
||||
|
||||
// classInit 因为 FindClass 在新线程里会失败,因为新线程没有应用类加载器。 所以全局缓存
|
||||
func classInit(env Env) {
|
||||
_classLock.Lock()
|
||||
defer _classLock.Unlock()
|
||||
|
||||
names := []struct {
|
||||
alias, path string
|
||||
}{
|
||||
{"HTTPEvent", "com/SunnyNet/Internal/HTTPEvent"},
|
||||
{"TCPEvent", "com/SunnyNet/Internal/TCPEvent"},
|
||||
{"WebSocketEvent", "com/SunnyNet/Internal/WebSocketEvent"},
|
||||
{"UDPEvent", "com/SunnyNet/Internal/UDPEvent"},
|
||||
}
|
||||
|
||||
for _, n := range names {
|
||||
local := env.FindClass(n.path)
|
||||
if local == 0 {
|
||||
panic("FindClass [" + n.path + "] failed")
|
||||
}
|
||||
_classList[n.alias] = env.NewGlobalRef(local)
|
||||
}
|
||||
}
|
||||
|
||||
//export JNI_OnLoad
|
||||
func JNI_OnLoad(JavaVM uintptr, reserved uintptr) int {
|
||||
___Java_GlobalVM = VM(JavaVM)
|
||||
env, ret := ___Java_GlobalVM.GetEnv(JNI_VERSION_1_6)
|
||||
if ret != JNI_OK {
|
||||
return 0
|
||||
}
|
||||
go goJavaInit()
|
||||
classInit(env)
|
||||
return JNI_VERSION_1_6
|
||||
}
|
||||
|
||||
BIN
SunnyNet.7z
Normal file
BIN
SunnyNet.7z
Normal file
Binary file not shown.
@@ -79,7 +79,7 @@ func (s *proxyRequest) CallbackTCPRequest(callType int, _msg *public.TcpMsg, Rem
|
||||
delete(httpStorage, MessageId)
|
||||
messageIdLock.Unlock()
|
||||
}()
|
||||
Ams := &tcpConn{
|
||||
m := &tcpConn{
|
||||
c: _msg,
|
||||
messageId: MessageId,
|
||||
_type: callType,
|
||||
@@ -90,12 +90,16 @@ func (s *proxyRequest) CallbackTCPRequest(callType int, _msg *public.TcpMsg, Rem
|
||||
sunnyContext: s.Global.SunnyContext,
|
||||
_Display: true,
|
||||
_OutRouterIPFunc: s.SetOutRouterIP,
|
||||
_note: s._note,
|
||||
}
|
||||
s.Global.scriptTCPCall(Ams)
|
||||
if !Ams._Display {
|
||||
s.Global.scriptTCPCall(m)
|
||||
messageIdLock.Lock()
|
||||
s._note = m._note
|
||||
messageIdLock.Unlock()
|
||||
if !m._Display {
|
||||
return
|
||||
}
|
||||
msg := Ams.c
|
||||
msg := m.c
|
||||
if callType == public.SunnyNetMsgTypeTCPAboutToConnect {
|
||||
if msg.Proxy != nil {
|
||||
_msg.Proxy = msg.Proxy
|
||||
@@ -103,7 +107,7 @@ func (s *proxyRequest) CallbackTCPRequest(callType int, _msg *public.TcpMsg, Rem
|
||||
}
|
||||
if s.TcpCall < 10 {
|
||||
if s.TcpGoCall != nil {
|
||||
s.TcpGoCall(Ams)
|
||||
s.TcpGoCall(m)
|
||||
if callType == public.SunnyNetMsgTypeTCPAboutToConnect {
|
||||
if msg.Proxy != nil {
|
||||
_msg.Proxy = msg.Proxy
|
||||
@@ -185,8 +189,10 @@ func (s *proxyRequest) CallbackBeforeRequest() {
|
||||
_localAddress: s.Conn.LocalAddr().String(),
|
||||
_OutRouterIPFunc: s.SetOutRouterIP,
|
||||
updateRawTarget: s.UpdateRawTarget,
|
||||
_note: s._note,
|
||||
}
|
||||
s.Global.scriptHTTPCall(m)
|
||||
s._note = m._note
|
||||
s.TlsConfig = m._tls
|
||||
s.Response.Response = m._response
|
||||
s._Display = m._Display
|
||||
@@ -254,8 +260,10 @@ func (s *proxyRequest) CallbackBeforeResponse() {
|
||||
_localAddress: s.Conn.LocalAddr().String(),
|
||||
_OutRouterIPFunc: s.SetOutRouterIP,
|
||||
updateRawTarget: s.UpdateRawTarget,
|
||||
_note: s._note,
|
||||
}
|
||||
s.Global.scriptHTTPCall(m)
|
||||
s._note = m._note
|
||||
s.Response.Response = m._response
|
||||
if s._Display == false {
|
||||
return
|
||||
@@ -357,8 +365,10 @@ func (s *proxyRequest) CallbackError(err string) {
|
||||
_localAddress: s.Conn.LocalAddr().String(),
|
||||
_OutRouterIPFunc: s.SetOutRouterIP,
|
||||
updateRawTarget: s.UpdateRawTarget,
|
||||
_note: s._note,
|
||||
}
|
||||
s.Global.scriptHTTPCall(m)
|
||||
s._note = m._note
|
||||
if s._Display == false {
|
||||
return
|
||||
}
|
||||
@@ -397,8 +407,12 @@ func (s *proxyRequest) CallbackWssRequest(State int, Method, Url string, msg *pu
|
||||
_ClientIP: s.Conn.RemoteAddr().String(),
|
||||
_localAddress: s.Conn.LocalAddr().String(),
|
||||
_Display: true,
|
||||
_note: s._note,
|
||||
}
|
||||
s.Global.scriptWebsocketCall(m)
|
||||
messageIdLock.Lock()
|
||||
s._note = m._note
|
||||
messageIdLock.Unlock()
|
||||
if !s._Display {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -34,13 +34,22 @@ type httpConn struct {
|
||||
_serverIP string
|
||||
_isRandomCipherSuites bool
|
||||
_localAddress string
|
||||
_note string
|
||||
_OutRouterIPFunc func(string) bool
|
||||
updateRawTarget func(int uint32)
|
||||
}
|
||||
|
||||
func (k *httpConn) SetOutRouterIP(way string) bool {
|
||||
if k._OutRouterIPFunc != nil {
|
||||
return k._OutRouterIPFunc(way)
|
||||
func (h *httpConn) SetNote(s string) {
|
||||
h._note = s
|
||||
}
|
||||
|
||||
func (h *httpConn) GetNote() string {
|
||||
return h._note
|
||||
}
|
||||
|
||||
func (h *httpConn) SetOutRouterIP(way string) bool {
|
||||
if h._OutRouterIPFunc != nil {
|
||||
return h._OutRouterIPFunc(way)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -20,96 +20,105 @@ type tcpConn struct {
|
||||
pid int //Pid
|
||||
_Display bool
|
||||
_OutRouterIPFunc func(string) bool
|
||||
_note string
|
||||
}
|
||||
|
||||
func (k *tcpConn) SetOutRouterIP(way string) bool {
|
||||
if k._type != public.SunnyNetMsgTypeTCPAboutToConnect {
|
||||
func (t *tcpConn) SetNote(s string) {
|
||||
t._note = s
|
||||
}
|
||||
|
||||
func (t *tcpConn) GetNote() string {
|
||||
return t._note
|
||||
}
|
||||
|
||||
func (t *tcpConn) SetOutRouterIP(way string) bool {
|
||||
if t._type != public.SunnyNetMsgTypeTCPAboutToConnect {
|
||||
return false
|
||||
}
|
||||
if k._OutRouterIPFunc != nil {
|
||||
return k._OutRouterIPFunc(way)
|
||||
if t._OutRouterIPFunc != nil {
|
||||
return t._OutRouterIPFunc(way)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (k *tcpConn) SetDisplay(Display bool) {
|
||||
k._Display = Display
|
||||
func (t *tcpConn) SetDisplay(Display bool) {
|
||||
t._Display = Display
|
||||
}
|
||||
|
||||
func (k *tcpConn) GetSocket5User() string {
|
||||
return GetSocket5User(k.theology)
|
||||
func (t *tcpConn) GetSocket5User() string {
|
||||
return GetSocket5User(t.theology)
|
||||
}
|
||||
|
||||
func (k *tcpConn) GetProcessName() string {
|
||||
if k.pid == 0 {
|
||||
func (t *tcpConn) GetProcessName() string {
|
||||
if t.pid == 0 {
|
||||
return "代理连接"
|
||||
}
|
||||
return CrossCompiled.GetPidName(int32(k.pid))
|
||||
return CrossCompiled.GetPidName(int32(t.pid))
|
||||
}
|
||||
func (k *tcpConn) Context() int {
|
||||
return k.sunnyContext
|
||||
func (t *tcpConn) Context() int {
|
||||
return t.sunnyContext
|
||||
}
|
||||
|
||||
func (k *tcpConn) Theology() int {
|
||||
return k.theology
|
||||
func (t *tcpConn) Theology() int {
|
||||
return t.theology
|
||||
}
|
||||
|
||||
func (k *tcpConn) MessageId() int {
|
||||
return k.messageId
|
||||
func (t *tcpConn) MessageId() int {
|
||||
return t.messageId
|
||||
}
|
||||
|
||||
func (k *tcpConn) Type() int {
|
||||
return k._type
|
||||
func (t *tcpConn) Type() int {
|
||||
return t._type
|
||||
}
|
||||
|
||||
func (k *tcpConn) PID() int {
|
||||
return k.pid
|
||||
func (t *tcpConn) PID() int {
|
||||
return t.pid
|
||||
}
|
||||
|
||||
func (k *tcpConn) LocalAddress() string {
|
||||
return k.localAddr
|
||||
func (t *tcpConn) LocalAddress() string {
|
||||
return t.localAddr
|
||||
}
|
||||
|
||||
func (k *tcpConn) RemoteAddress() string {
|
||||
return k.remoteAddr
|
||||
func (t *tcpConn) RemoteAddress() string {
|
||||
return t.remoteAddr
|
||||
}
|
||||
|
||||
// SetAgent Set仅支持S5代理 例如 socket5://admin:123456@127.0.0.1:8888
|
||||
func (k *tcpConn) SetAgent(ProxyUrl string, outTime ...int) bool {
|
||||
if k._type != public.SunnyNetMsgTypeTCPAboutToConnect {
|
||||
func (t *tcpConn) SetAgent(ProxyUrl string, outTime ...int) bool {
|
||||
if t._type != public.SunnyNetMsgTypeTCPAboutToConnect {
|
||||
return false
|
||||
}
|
||||
if k.c == nil {
|
||||
if t.c == nil {
|
||||
return false
|
||||
}
|
||||
var er error
|
||||
k.c.Proxy, er = SunnyProxy.ParseProxy(ProxyUrl, outTime...)
|
||||
t.c.Proxy, er = SunnyProxy.ParseProxy(ProxyUrl, outTime...)
|
||||
if er != nil {
|
||||
return false
|
||||
}
|
||||
return k.c.Proxy != nil
|
||||
return t.c.Proxy != nil
|
||||
}
|
||||
|
||||
// SetBody 修改 TCP/发送接收数据
|
||||
func (k *tcpConn) SetBody(data []byte) bool {
|
||||
if k._type != public.SunnyNetMsgTypeTCPClientReceive && k._type != public.SunnyNetMsgTypeTCPClientSend {
|
||||
func (t *tcpConn) SetBody(data []byte) bool {
|
||||
if t._type != public.SunnyNetMsgTypeTCPClientReceive && t._type != public.SunnyNetMsgTypeTCPClientSend {
|
||||
return false
|
||||
}
|
||||
if k.c == nil {
|
||||
if t.c == nil {
|
||||
return false
|
||||
}
|
||||
k.c.Data.Reset()
|
||||
k.c.Data.Write(data)
|
||||
t.c.Data.Reset()
|
||||
t.c.Data.Write(data)
|
||||
return true
|
||||
}
|
||||
|
||||
// Close 关闭TCP连接
|
||||
func (k *tcpConn) Close() bool {
|
||||
if k._type == public.SunnyNetMsgTypeTCPAboutToConnect {
|
||||
func (t *tcpConn) Close() bool {
|
||||
if t._type == public.SunnyNetMsgTypeTCPAboutToConnect {
|
||||
return false
|
||||
}
|
||||
TcpSceneLock.Lock()
|
||||
w := TcpStorage[k.theology]
|
||||
w := TcpStorage[t.theology]
|
||||
TcpSceneLock.Unlock()
|
||||
if w == nil {
|
||||
return false
|
||||
@@ -126,22 +135,22 @@ func (k *tcpConn) Close() bool {
|
||||
}
|
||||
|
||||
// SetNewAddress 修改目标连接地址 目标地址必须带端口号 例如 baidu.com:443 [仅限即将连接时使用]
|
||||
func (k *tcpConn) SetNewAddress(ip string) bool {
|
||||
if k.c == nil {
|
||||
func (t *tcpConn) SetNewAddress(ip string) bool {
|
||||
if t.c == nil {
|
||||
return false
|
||||
}
|
||||
if k._type == public.SunnyNetMsgTypeTCPAboutToConnect {
|
||||
k.c.Data.Reset()
|
||||
k.c.Data.WriteString(ip)
|
||||
if t._type == public.SunnyNetMsgTypeTCPAboutToConnect {
|
||||
t.c.Data.Reset()
|
||||
t.c.Data.WriteString(ip)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SendToServer 模拟客户端向服务器端主动发送数据
|
||||
func (k *tcpConn) SendToServer(data []byte) bool {
|
||||
func (t *tcpConn) SendToServer(data []byte) bool {
|
||||
TcpSceneLock.Lock()
|
||||
w := TcpStorage[k.theology]
|
||||
w := TcpStorage[t.theology]
|
||||
TcpSceneLock.Unlock()
|
||||
if w == nil {
|
||||
return false
|
||||
@@ -162,9 +171,9 @@ func (k *tcpConn) SendToServer(data []byte) bool {
|
||||
}
|
||||
|
||||
// SendToClient 模拟服务器端向客户端主动发送数据
|
||||
func (k *tcpConn) SendToClient(data []byte) bool {
|
||||
func (t *tcpConn) SendToClient(data []byte) bool {
|
||||
TcpSceneLock.Lock()
|
||||
w := TcpStorage[k.theology]
|
||||
w := TcpStorage[t.theology]
|
||||
TcpSceneLock.Unlock()
|
||||
if w == nil {
|
||||
return false
|
||||
@@ -185,23 +194,23 @@ func (k *tcpConn) SendToClient(data []byte) bool {
|
||||
}
|
||||
|
||||
// Body 获取发送、接收的数据
|
||||
func (k *tcpConn) Body() []byte {
|
||||
if k == nil {
|
||||
func (t *tcpConn) Body() []byte {
|
||||
if t == nil {
|
||||
return []byte{}
|
||||
}
|
||||
if k.c == nil {
|
||||
if t.c == nil {
|
||||
return []byte{}
|
||||
}
|
||||
return public.CopyBytes(k.c.Data.Bytes())
|
||||
return public.CopyBytes(t.c.Data.Bytes())
|
||||
}
|
||||
|
||||
// BodyLen 获取发送、接收的数据长度
|
||||
func (k *tcpConn) BodyLen() int {
|
||||
if k == nil {
|
||||
func (t *tcpConn) BodyLen() int {
|
||||
if t == nil {
|
||||
return 0
|
||||
}
|
||||
if k.c == nil {
|
||||
if t.c == nil {
|
||||
return 0
|
||||
}
|
||||
return k.c.Data.Len()
|
||||
return t.c.Data.Len()
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package SunnyNet
|
||||
import (
|
||||
"github.com/qtgolang/SunnyNet/src/CrossCompiled"
|
||||
"github.com/qtgolang/SunnyNet/src/Interface"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/nfapi"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/SunnyNetUDP"
|
||||
)
|
||||
|
||||
type ConnUDP Interface.ConnUDPCall
|
||||
@@ -18,67 +18,83 @@ type udpConn struct {
|
||||
remoteAddress string
|
||||
data []byte
|
||||
_Display bool
|
||||
_note string
|
||||
}
|
||||
|
||||
func (U udpConn) SetDisplay(Display bool) {
|
||||
U._Display = Display
|
||||
func (u *udpConn) SetNote(s string) {
|
||||
u._note = s
|
||||
}
|
||||
|
||||
func (U udpConn) GetSocket5User() string {
|
||||
func (u *udpConn) GetNote() string {
|
||||
return u._note
|
||||
}
|
||||
|
||||
func (u *udpConn) SetDisplay(Display bool) {
|
||||
u._Display = Display
|
||||
}
|
||||
func (u *udpConn) GetSocket5User() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (U udpConn) GetProcessName() string {
|
||||
if U.pid == 0 {
|
||||
func (u *udpConn) GetProcessName() string {
|
||||
if u.pid == 0 {
|
||||
return "代理连接"
|
||||
}
|
||||
return CrossCompiled.GetPidName(int32(U.pid))
|
||||
return CrossCompiled.GetPidName(int32(u.pid))
|
||||
}
|
||||
|
||||
// SetBody 修改消息
|
||||
func (U udpConn) SetBody(i []byte) bool {
|
||||
U.data = i
|
||||
func (u *udpConn) SetBody(i []byte) bool {
|
||||
u.data = i
|
||||
return true
|
||||
}
|
||||
func (U udpConn) BodyLen() int {
|
||||
return len(U.data)
|
||||
func (u *udpConn) BodyLen() int {
|
||||
return len(u.data)
|
||||
}
|
||||
|
||||
func (U udpConn) Context() int {
|
||||
return U.sunnyContext
|
||||
func (u *udpConn) Context() int {
|
||||
return u.sunnyContext
|
||||
}
|
||||
func (U udpConn) Type() int {
|
||||
return U._type
|
||||
func (u *udpConn) Type() int {
|
||||
return u._type
|
||||
}
|
||||
func (U udpConn) MessageId() int {
|
||||
return U.messageId
|
||||
func (u *udpConn) MessageId() int {
|
||||
return u.messageId
|
||||
}
|
||||
func (U udpConn) Theology() int {
|
||||
return int(U.theology)
|
||||
func (u *udpConn) Theology() int {
|
||||
return int(u.theology)
|
||||
}
|
||||
|
||||
func (U udpConn) PID() int {
|
||||
return U.pid
|
||||
func (u *udpConn) PID() int {
|
||||
return u.pid
|
||||
}
|
||||
|
||||
func (U udpConn) LocalAddress() string {
|
||||
return U.localAddress
|
||||
func (u *udpConn) LocalAddress() string {
|
||||
return u.localAddress
|
||||
}
|
||||
|
||||
func (U udpConn) RemoteAddress() string {
|
||||
return U.remoteAddress
|
||||
func (u *udpConn) RemoteAddress() string {
|
||||
return u.remoteAddress
|
||||
}
|
||||
|
||||
func (U udpConn) Body() []byte {
|
||||
return U.data
|
||||
func (u *udpConn) Body() []byte {
|
||||
return u.data
|
||||
}
|
||||
|
||||
// SendToServer 主动向服务器发送消息
|
||||
func (U udpConn) SendToServer(data []byte) bool {
|
||||
return NFapi.UdpSendToServer(U.theology, data)
|
||||
func (u *udpConn) SendToServer(data []byte) bool {
|
||||
obj := SunnyNetUDP.GetUDPItem(u.theology)
|
||||
if obj != nil {
|
||||
return obj.ToServer(data)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SendToClient 主动向客户端发送消息
|
||||
func (U udpConn) SendToClient(data []byte) bool {
|
||||
return NFapi.UdpSendToClient(U.theology, data)
|
||||
func (u *udpConn) SendToClient(data []byte) bool {
|
||||
obj := SunnyNetUDP.GetUDPItem(u.theology)
|
||||
if obj != nil {
|
||||
return obj.ToClient(data)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -21,89 +21,98 @@ type wsConn struct {
|
||||
Request *http.Request //请求体
|
||||
_Display bool
|
||||
_localAddress string
|
||||
_note string
|
||||
}
|
||||
|
||||
func (k *wsConn) LocalAddress() string {
|
||||
return k._localAddress
|
||||
func (w *wsConn) SetNote(s string) {
|
||||
w._note = s
|
||||
}
|
||||
|
||||
func (k *wsConn) SetDisplay(Display bool) {
|
||||
k._Display = Display
|
||||
func (w *wsConn) GetNote() string {
|
||||
return w._note
|
||||
}
|
||||
|
||||
func (k *wsConn) Method() string {
|
||||
return k._Method
|
||||
func (w *wsConn) LocalAddress() string {
|
||||
return w._localAddress
|
||||
}
|
||||
|
||||
func (k *wsConn) GetSocket5User() string {
|
||||
return GetSocket5User(k._Theology)
|
||||
func (w *wsConn) SetDisplay(Display bool) {
|
||||
w._Display = Display
|
||||
}
|
||||
|
||||
func (k *wsConn) GetProcessName() string {
|
||||
if k.Pid == 0 {
|
||||
func (w *wsConn) Method() string {
|
||||
return w._Method
|
||||
}
|
||||
|
||||
func (w *wsConn) GetSocket5User() string {
|
||||
return GetSocket5User(w._Theology)
|
||||
}
|
||||
|
||||
func (w *wsConn) GetProcessName() string {
|
||||
if w.Pid == 0 {
|
||||
return "代理连接"
|
||||
}
|
||||
return CrossCompiled.GetPidName(int32(k.Pid))
|
||||
return CrossCompiled.GetPidName(int32(w.Pid))
|
||||
}
|
||||
func (k *wsConn) Context() int {
|
||||
return k.SunnyContext
|
||||
func (w *wsConn) Context() int {
|
||||
return w.SunnyContext
|
||||
}
|
||||
func (k *wsConn) MessageId() int {
|
||||
return k._MessageId
|
||||
func (w *wsConn) MessageId() int {
|
||||
return w._MessageId
|
||||
}
|
||||
func (k *wsConn) Theology() int {
|
||||
return k._Theology
|
||||
func (w *wsConn) Theology() int {
|
||||
return w._Theology
|
||||
}
|
||||
func (k *wsConn) PID() int {
|
||||
return k.Pid
|
||||
func (w *wsConn) PID() int {
|
||||
return w.Pid
|
||||
}
|
||||
func (k *wsConn) URL() string {
|
||||
return k.Url
|
||||
func (w *wsConn) URL() string {
|
||||
return w.Url
|
||||
}
|
||||
|
||||
func (k *wsConn) Type() int {
|
||||
return k._Type
|
||||
func (w *wsConn) Type() int {
|
||||
return w._Type
|
||||
}
|
||||
|
||||
func (k *wsConn) ClientIP() string {
|
||||
return k._ClientIP
|
||||
func (w *wsConn) ClientIP() string {
|
||||
return w._ClientIP
|
||||
}
|
||||
func (k *wsConn) Body() []byte {
|
||||
k.c.Sync.Lock()
|
||||
defer k.c.Sync.Unlock()
|
||||
return public.CopyBytes(k.c.Data.Bytes())
|
||||
func (w *wsConn) Body() []byte {
|
||||
w.c.Sync.Lock()
|
||||
defer w.c.Sync.Unlock()
|
||||
return public.CopyBytes(w.c.Data.Bytes())
|
||||
}
|
||||
|
||||
// MessageType 获取 消息类型
|
||||
// Text=1 Binary=2 Close=8 Ping=9 Pong=10 Invalid=-1/255
|
||||
func (k *wsConn) MessageType() int {
|
||||
k.c.Sync.Lock()
|
||||
defer k.c.Sync.Unlock()
|
||||
return k.c.Mt
|
||||
func (w *wsConn) MessageType() int {
|
||||
w.c.Sync.Lock()
|
||||
defer w.c.Sync.Unlock()
|
||||
return w.c.Mt
|
||||
}
|
||||
|
||||
// BodyLen 获取 消息长度
|
||||
func (k *wsConn) BodyLen() int {
|
||||
k.c.Sync.Lock()
|
||||
defer k.c.Sync.Unlock()
|
||||
return k.c.Data.Len()
|
||||
func (w *wsConn) BodyLen() int {
|
||||
w.c.Sync.Lock()
|
||||
defer w.c.Sync.Unlock()
|
||||
return w.c.Data.Len()
|
||||
}
|
||||
|
||||
// SetBody 修改 消息
|
||||
func (k *wsConn) SetBody(data []byte) bool {
|
||||
k.c.Sync.Lock()
|
||||
defer k.c.Sync.Unlock()
|
||||
k.c.Data.Reset()
|
||||
k.c.Data.Write(data)
|
||||
func (w *wsConn) SetBody(data []byte) bool {
|
||||
w.c.Sync.Lock()
|
||||
defer w.c.Sync.Unlock()
|
||||
w.c.Data.Reset()
|
||||
w.c.Data.Write(data)
|
||||
return true
|
||||
}
|
||||
|
||||
// SendToServer 主动向Websocket服务器发送消息
|
||||
func (k *wsConn) SendToServer(MessageType int, data []byte) bool {
|
||||
k.c.Sync.Lock()
|
||||
defer k.c.Sync.Unlock()
|
||||
if k.c.Server != nil {
|
||||
e := k.c.Server.WriteMessage(MessageType, data)
|
||||
func (w *wsConn) SendToServer(MessageType int, data []byte) bool {
|
||||
w.c.Sync.Lock()
|
||||
defer w.c.Sync.Unlock()
|
||||
if w.c.Server != nil {
|
||||
e := w.c.Server.WriteMessage(MessageType, data)
|
||||
if e != nil {
|
||||
return false
|
||||
}
|
||||
@@ -112,11 +121,11 @@ func (k *wsConn) SendToServer(MessageType int, data []byte) bool {
|
||||
}
|
||||
|
||||
// SendToClient 主动向Websocket客户端发送消息
|
||||
func (k *wsConn) SendToClient(MessageType int, data []byte) bool {
|
||||
k.c.Sync.Lock()
|
||||
defer k.c.Sync.Unlock()
|
||||
if k.c.Client != nil {
|
||||
e := k.c.Client.WriteMessage(MessageType, data)
|
||||
func (w *wsConn) SendToClient(MessageType int, data []byte) bool {
|
||||
w.c.Sync.Lock()
|
||||
defer w.c.Sync.Unlock()
|
||||
if w.c.Client != nil {
|
||||
e := w.c.Client.WriteMessage(MessageType, data)
|
||||
if e != nil {
|
||||
return false
|
||||
}
|
||||
@@ -125,14 +134,14 @@ func (k *wsConn) SendToClient(MessageType int, data []byte) bool {
|
||||
}
|
||||
|
||||
// Close 关闭Websocket连接
|
||||
func (k *wsConn) Close() bool {
|
||||
k.c.Sync.Lock()
|
||||
defer k.c.Sync.Unlock()
|
||||
if k.c.Server != nil {
|
||||
_ = k.c.Server.Close()
|
||||
func (w *wsConn) Close() bool {
|
||||
w.c.Sync.Lock()
|
||||
defer w.c.Sync.Unlock()
|
||||
if w.c.Server != nil {
|
||||
_ = w.c.Server.Close()
|
||||
}
|
||||
if k.c.Client != nil {
|
||||
_ = k.c.Client.Close()
|
||||
if w.c.Client != nil {
|
||||
_ = w.c.Client.Close()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ import (
|
||||
"github.com/qtgolang/SunnyNet/src/GoScriptCode"
|
||||
"github.com/qtgolang/SunnyNet/src/HttpCertificate"
|
||||
"github.com/qtgolang/SunnyNet/src/Interface"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/Info"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/ProcessCheck"
|
||||
"github.com/qtgolang/SunnyNet/src/ReadWriteObject"
|
||||
"github.com/qtgolang/SunnyNet/src/Resource"
|
||||
"github.com/qtgolang/SunnyNet/src/SunnyProxy"
|
||||
@@ -34,7 +35,6 @@ import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -211,6 +211,7 @@ type proxyRequest struct {
|
||||
_SocksUser string
|
||||
outRouterIP *net.TCPAddr
|
||||
rawTarget uint32
|
||||
_note string //注释上下文
|
||||
}
|
||||
|
||||
var sUser = make(map[int]string)
|
||||
@@ -222,6 +223,9 @@ func (s *proxyRequest) setSocket5User(user string) {
|
||||
sUser[s.Theology] = user
|
||||
sL.Unlock()
|
||||
}
|
||||
func (s *proxyRequest) GetNote() string {
|
||||
return s._note
|
||||
}
|
||||
|
||||
// 更新唯一ID以及s5连接账号
|
||||
func (s *proxyRequest) updateSocket5User() {
|
||||
@@ -686,7 +690,7 @@ func (s *proxyRequest) MustTcpProcessing(Tag string) {
|
||||
as.Data.Write([]byte(RemoteTCP.LocalAddr().String()))
|
||||
s.CallbackTCPRequest(public.SunnyNetMsgTypeTCPConnectOK, as, RemoteAddr)
|
||||
as.Data.Reset()
|
||||
isClose = s.TcpCallback(&RemoteTCP, Tag, tw, RemoteAddr)
|
||||
isClose = s.TcpCallback(RemoteTCP, Tag, tw, RemoteAddr)
|
||||
} else {
|
||||
_ = s.Conn.Close()
|
||||
}
|
||||
@@ -719,23 +723,20 @@ func (s *proxyRequest) releaseTcp() {
|
||||
}
|
||||
|
||||
// TcpCallback TCP消息处理 返回 是否已经调用 通知 回调函数 TCP已经关闭
|
||||
func (s *proxyRequest) TcpCallback(RemoteTCP *net.Conn, Tag string, tw *ReadWriteObject.ReadWriteObject, RemoteAddr string) bool {
|
||||
func (s *proxyRequest) TcpCallback(RemoteTCP net.Conn, Tag string, tw *ReadWriteObject.ReadWriteObject, RemoteAddr string) bool {
|
||||
if RemoteTCP == nil {
|
||||
return false
|
||||
}
|
||||
if *RemoteTCP == nil {
|
||||
return false
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
isHttpReq := false //是否纠正HTTP请求,可能由于某些原因 客户端发送数据不及时判断为了TCP请求,后续TCP处理时纠正为HTTP请求
|
||||
//读取客户端消息转发给服务端
|
||||
go func() {
|
||||
s.SocketForward(*tw.Writer, s.RwObj, public.SunnyNetMsgTypeTCPClientSend, s.Conn, *RemoteTCP, &s.TCP, &isHttpReq, RemoteAddr)
|
||||
s.SocketForward(*tw.Writer, s.RwObj, public.SunnyNetMsgTypeTCPClientSend, s.Conn, RemoteTCP, &s.TCP, &isHttpReq, RemoteAddr)
|
||||
wg.Done()
|
||||
}()
|
||||
//读取服务器消息转发给客户端
|
||||
s.SocketForward(*s.RwObj.Writer, tw, public.SunnyNetMsgTypeTCPClientReceive, *RemoteTCP, s.Conn, &s.TCP, &isHttpReq, RemoteAddr)
|
||||
s.SocketForward(*s.RwObj.Writer, tw, public.SunnyNetMsgTypeTCPClientReceive, RemoteTCP, s.Conn, &s.TCP, &isHttpReq, RemoteAddr)
|
||||
wg.Wait()
|
||||
s.releaseTcp()
|
||||
if isHttpReq {
|
||||
@@ -1788,7 +1789,7 @@ func (s *proxyRequest) CompleteRequest(req *http.Request) {
|
||||
s.Request.Body = RequestBody
|
||||
RawRequestBodyLength, isRawRequestBodyLength := s.Request.Context().Value(public.SunnyNetRawRequestBodyLength).(int64)
|
||||
if isRawRequestBodyLength {
|
||||
s.Request.SetHeaderLength(RawRequestBodyLength)
|
||||
s.Request.Header.Set("Content-Length", strconv.Itoa(int(RawRequestBodyLength)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2170,6 +2171,7 @@ func resize(slice []byte, newLength int) []byte {
|
||||
return newSlice
|
||||
}
|
||||
|
||||
var divert ProcessDrv.Dev //使用的驱动
|
||||
// Sunny 请使用 NewSunny 方法 请不要直接构造
|
||||
type Sunny struct {
|
||||
disableTCP bool //禁止TCP连接
|
||||
@@ -2205,7 +2207,7 @@ type Sunny struct {
|
||||
SunnyContext int
|
||||
isRandomTLS bool //是否随机使用TLS指纹
|
||||
userScriptCode []byte //用户脚本代码
|
||||
_http_max_body_len int64 //最大的用户提交数据长度
|
||||
httpMaxBodyLen int64 //最大的用户提交数据长度
|
||||
connHijack func(Hijack) bool
|
||||
script struct {
|
||||
http GoScriptCode.GoScriptTypeHTTP //脚本代码 HTTP 事件入口函数
|
||||
@@ -2298,7 +2300,7 @@ var defaultManager = func() int {
|
||||
func NewSunny() *Sunny {
|
||||
SunnyContext := NewMessageId()
|
||||
a, _ := regexp.Compile("ALL")
|
||||
s := &Sunny{SunnyContext: SunnyContext, connList: make(map[int64]net.Conn), socket5VerifyUserList: make(map[string]string), proxyRegexp: a, _http_max_body_len: public.MaxUploadLength, mustTcpRegexp: a, mustTcpRulesAllow: true}
|
||||
s := &Sunny{SunnyContext: SunnyContext, connList: make(map[int64]net.Conn), socket5VerifyUserList: make(map[string]string), proxyRegexp: a, httpMaxBodyLen: public.MaxUploadLength, mustTcpRegexp: a, mustTcpRulesAllow: true}
|
||||
s.userScriptCode = GoScriptCode.DefaultCode
|
||||
s.script.AdminPage = "SunnyNetScriptEdit"
|
||||
_, s.script.http, s.script.websocket, s.script.tcp, s.script.udp = GoScriptCode.RunCode(SunnyContext, s.userScriptCode, nil)
|
||||
@@ -2400,7 +2402,6 @@ func (s *Sunny) Socket5VerifyUser(n bool) *Sunny {
|
||||
|
||||
// Socket5AddUser S5代理添加需要验证的账号密码
|
||||
func (s *Sunny) Socket5AddUser(u, p string) *Sunny {
|
||||
|
||||
s.socket5VerifyUserLock.Lock()
|
||||
s.socket5VerifyUserList[u] = p
|
||||
s.socket5VerifyUserLock.Unlock()
|
||||
@@ -2508,7 +2509,7 @@ func (s *Sunny) IsScriptCodeSupported() bool {
|
||||
func (s *Sunny) SetHTTPRequestMaxUpdateLength(max int64) *Sunny {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
s._http_max_body_len = max
|
||||
s.httpMaxBodyLen = max
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -2555,51 +2556,38 @@ func (s *Sunny) SetGoCallback(httpCall func(ConnHTTP), tcpCall func(ConnTCP), ws
|
||||
|
||||
// UnDrive 卸载驱动,仅Windows 有效【需要管理权限】执行成功后会立即重启系统,若函数执行后没有重启系统表示没有管理员权限
|
||||
func (s *Sunny) UnDrive() {
|
||||
CrossCompiled.Drive_UnInstall()
|
||||
CrossCompiled.NFAPI{}.UnInstall()
|
||||
CrossCompiled.Tun{}.UnInstall()
|
||||
//一定要将Pr放到最后,因为写了自动重启
|
||||
CrossCompiled.Pr{}.UnInstall()
|
||||
}
|
||||
|
||||
// OpenDrive 开始进程代理 会自动安装所需驱动文件
|
||||
// IsNfapi 如果为true表示使用NFAPI驱动 如果为false 表示使用Proxifier
|
||||
func (s *Sunny) OpenDrive(IsNfapi bool) bool {
|
||||
if (CrossCompiled.DrvInitState == CrossCompiled.DrvUndefined && IsNfapi) || (CrossCompiled.DrvInitState == CrossCompiled.DrvNF && IsNfapi) {
|
||||
if CrossCompiled.NFapi_IsInit() {
|
||||
if CrossCompiled.NFapi_ProcessPortInt() != 0 && CrossCompiled.NFapi_SunnyPointer() != uintptr(unsafe.Pointer(s)) {
|
||||
CrossCompiled.NFapi_MessageBox("启动失败:", "已在其他 SunnyNet 对象启动\r\n\r\n同一进程不能多次加载驱动", 0x00000010)
|
||||
CrossCompiled.DrvInitState = CrossCompiled.DrvNF
|
||||
return false
|
||||
}
|
||||
CrossCompiled.NFapi_SunnyPointer(uintptr(unsafe.Pointer(s)))
|
||||
CrossCompiled.DrvInitState = CrossCompiled.DrvNF
|
||||
return true
|
||||
}
|
||||
CrossCompiled.NFapi_SunnyPointer(uintptr(unsafe.Pointer(s)))
|
||||
CrossCompiled.NFapi_ProcessPortInt(uint16(s.Port()))
|
||||
CrossCompiled.NFapi_IsInit(CrossCompiled.NFapi_ApiInit())
|
||||
CrossCompiled.NFapi_UdpSendReceiveFunc(s.udpNFSendReceive)
|
||||
ok := CrossCompiled.NFapi_IsInit()
|
||||
if ok {
|
||||
CrossCompiled.DrvInitState = CrossCompiled.DrvNF
|
||||
} else {
|
||||
CrossCompiled.DrvInitState = CrossCompiled.DrvUndefined
|
||||
}
|
||||
return ok
|
||||
}
|
||||
if (CrossCompiled.DrvInitState == CrossCompiled.DrvUndefined && !IsNfapi) || (CrossCompiled.DrvInitState == CrossCompiled.DrvPr && !IsNfapi) {
|
||||
if !CrossCompiled.Pr_Install() {
|
||||
return false
|
||||
}
|
||||
ok := CrossCompiled.Pr_IsInit()
|
||||
if !ok {
|
||||
if CrossCompiled.Pr_SetHandle(s.handleClientConn) {
|
||||
CrossCompiled.DrvInitState = CrossCompiled.DrvPr
|
||||
return true
|
||||
}
|
||||
}
|
||||
//已经启动或已经在其他SunnyNet启动
|
||||
// DevMode 0=Proxifier,1=NFAPI,2=Tun
|
||||
func (s *Sunny) OpenDrive(DevMode int) bool {
|
||||
if divert != nil {
|
||||
fmt.Println("你已选择另一个模式,不可切换")
|
||||
return false
|
||||
}
|
||||
fmt.Println("你已选择另一个模式,不可切换")
|
||||
return false
|
||||
if DevMode == CrossCompiled.DrvNF {
|
||||
divert = &CrossCompiled.NFAPI{TCP: s.handleClientConn, UDP: s.udpSendReceive, Sunny: s}
|
||||
} else if DevMode == CrossCompiled.DrvTun {
|
||||
divert = &CrossCompiled.Tun{TCP: s.handleClientConn, UDP: s.udpSendReceive, Sunny: s}
|
||||
} else if DevMode == CrossCompiled.DrvPr {
|
||||
//不支持UDP
|
||||
divert = &CrossCompiled.Pr{TCP: s.handleClientConn, UDP: s.udpSendReceive, Sunny: s}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
if !divert.Install() {
|
||||
divert = nil
|
||||
return false
|
||||
}
|
||||
divert.SetHandle()
|
||||
if divert.IsRun() {
|
||||
return true
|
||||
}
|
||||
return divert.Run()
|
||||
}
|
||||
|
||||
// ProcessALLName 是否允许所有进程通过 所有 SunnyNet 通用,
|
||||
@@ -2608,41 +2596,41 @@ func (s *Sunny) OpenDrive(IsNfapi bool) bool {
|
||||
// 因为如果不断开的一次的话,已经建立的TCP链接无法抓包。
|
||||
// Go程序调试,是通过TCP连接的,若使用此命令将无法调试。
|
||||
func (s *Sunny) ProcessALLName(open, StopNetwork bool) *Sunny {
|
||||
CrossCompiled.NFapi_HookAllProcess(open, StopNetwork)
|
||||
ProcessCheck.HookAllProcess(open, StopNetwork)
|
||||
return s
|
||||
}
|
||||
|
||||
// ProcessDelName 删除进程名 所有 SunnyNet 通用
|
||||
func (s *Sunny) ProcessDelName(name string) *Sunny {
|
||||
CrossCompiled.NFapi_DelName(name)
|
||||
ProcessCheck.DelName(name)
|
||||
//CrossCompiled.NFapi_CloseNameTCP(name)
|
||||
return s
|
||||
}
|
||||
|
||||
// ProcessAddName 进程代理 添加进程名 所有 SunnyNet 通用
|
||||
func (s *Sunny) ProcessAddName(Name string) *Sunny {
|
||||
CrossCompiled.NFapi_AddName(Name)
|
||||
ProcessCheck.AddName(Name)
|
||||
//CrossCompiled.NFapi_CloseNameTCP(Name)
|
||||
return s
|
||||
}
|
||||
|
||||
// ProcessDelPid 删除PID 所有 SunnyNet 通用
|
||||
func (s *Sunny) ProcessDelPid(Pid int) *Sunny {
|
||||
CrossCompiled.NFapi_DelPid(uint32(Pid))
|
||||
ProcessCheck.DelPid(uint32(Pid))
|
||||
//CrossCompiled.NFapi_ClosePidTCP(Pid)
|
||||
return s
|
||||
}
|
||||
|
||||
// ProcessAddPid 进程代理 添加PID 所有 SunnyNet 通用
|
||||
func (s *Sunny) ProcessAddPid(Pid int) *Sunny {
|
||||
CrossCompiled.NFapi_AddPid(uint32(Pid))
|
||||
ProcessCheck.AddPid(uint32(Pid))
|
||||
//CrossCompiled.NFapi_ClosePidTCP(Pid)
|
||||
return s
|
||||
}
|
||||
|
||||
// ProcessCancelAll 进程代理 取消全部已设置的进程名
|
||||
func (s *Sunny) ProcessCancelAll() *Sunny {
|
||||
CrossCompiled.NFapi_CancelAll()
|
||||
ProcessCheck.CancelAll()
|
||||
//CrossCompiled.NFapi_ClosePidTCP(-1)
|
||||
return s
|
||||
}
|
||||
@@ -2690,11 +2678,14 @@ func (s *Sunny) Start() *Sunny {
|
||||
s.tcpSocket = &tcpListen
|
||||
s.Error = err
|
||||
s.isRun = true
|
||||
if CrossCompiled.NFapi_SunnyPointer() == uintptr(unsafe.Pointer(s)) {
|
||||
CrossCompiled.NFapi_ProcessPortInt(uint16(s.port))
|
||||
CrossCompiled.NFapi_UdpSendReceiveFunc(s.udpNFSendReceive)
|
||||
if divert != nil {
|
||||
if divert.Install() {
|
||||
divert.SetHandle()
|
||||
if !divert.IsRun() {
|
||||
divert.Run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
go s.listenTcpGo()
|
||||
go s.listenUdpGo()
|
||||
return s
|
||||
@@ -2713,13 +2704,8 @@ func (s *Sunny) Close() *Sunny {
|
||||
_ = conn.Close()
|
||||
delete(s.connList, k)
|
||||
}
|
||||
if CrossCompiled.DrvInitState == CrossCompiled.DrvNF {
|
||||
if CrossCompiled.NFapi_SunnyPointer() == uintptr(unsafe.Pointer(s)) {
|
||||
CrossCompiled.NFapi_ProcessPortInt(0)
|
||||
}
|
||||
}
|
||||
if CrossCompiled.DrvInitState == CrossCompiled.DrvPr {
|
||||
CrossCompiled.Pr_SetHandle(nil)
|
||||
if divert != nil {
|
||||
divert.Close()
|
||||
}
|
||||
s.lock.Unlock()
|
||||
return s
|
||||
@@ -2810,14 +2796,26 @@ func (s *proxyRequest) free() {
|
||||
s.Request = nil
|
||||
s.Target = nil
|
||||
}
|
||||
func (s *proxyRequest) isDriveConn() (Info.DrvInfo, uint16) {
|
||||
func (s *proxyRequest) isDriveConn() (ProcessCheck.DrvInfo, uint16) {
|
||||
if s == nil {
|
||||
return nil, 0
|
||||
}
|
||||
if divert == nil {
|
||||
return nil, 0
|
||||
}
|
||||
addr, ok := s.Conn.RemoteAddr().(*net.TCPAddr)
|
||||
if ok {
|
||||
u := uint16(addr.Port)
|
||||
info := CrossCompiled.NFapi_GetTcpConnectInfo(u)
|
||||
info := ProcessCheck.GetTcpConnectInfo(u)
|
||||
if info == nil {
|
||||
addr, ok = s.Conn.LocalAddr().(*net.TCPAddr)
|
||||
if ok {
|
||||
u = uint16(addr.Port)
|
||||
info = ProcessCheck.GetTcpConnectInfo(u)
|
||||
return info, u
|
||||
}
|
||||
return nil, 0
|
||||
}
|
||||
return info, u
|
||||
}
|
||||
return nil, 0
|
||||
@@ -2878,8 +2876,8 @@ func (s *Sunny) handleClientConn(conn net.Conn) {
|
||||
}
|
||||
//然后进行数据处理,按照HTTPS数据进行处理
|
||||
req.https()
|
||||
info.Close()
|
||||
CrossCompiled.NFapi_DelTcpConnectInfo(DrivePort)
|
||||
_ = info.Close()
|
||||
ProcessCheck.DelTcpConnectInfo(DrivePort)
|
||||
return
|
||||
}
|
||||
req.Pid = CrossCompiled.GetTcpInfoPID(conn.RemoteAddr().String(), s.port)
|
||||
|
||||
@@ -72,7 +72,7 @@ func (s *proxyRequest) httpCall(rw http.ResponseWriter, req *http.Request) {
|
||||
} else {
|
||||
res.Body = &httpBody{Body: req.Body, c: s.Conn, req: res}
|
||||
}
|
||||
IsRequestRawBody := res.GetBodyLength() >= s.Global._http_max_body_len
|
||||
IsRequestRawBody := res.GetBodyLength() >= s.Global.httpMaxBodyLen
|
||||
Length := res.GetBodyLength()
|
||||
res.SetContext(public.SunnyNetRawRequestBodyLength, Length)
|
||||
res.IsRawBody = IsRequestRawBody
|
||||
|
||||
111
SunnyNet/udp.go
111
SunnyNet/udp.go
@@ -4,8 +4,9 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/qtgolang/SunnyNet/src/Call"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/nfapi"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/SunnyNetUDP"
|
||||
"github.com/qtgolang/SunnyNet/src/public"
|
||||
"sync"
|
||||
|
||||
"net"
|
||||
"sync/atomic"
|
||||
@@ -134,9 +135,15 @@ func (s *Sunny) listenUdpGo() {
|
||||
continue
|
||||
}
|
||||
k := addr.String() + _info.RemoteAddress
|
||||
// 如果连接池中不存在该连接,则新建连接并添加到连接池中
|
||||
if c, Tid := NFapi.UdpSenders.Get(addr.String() + _info.RemoteAddress); c == nil {
|
||||
Tid = atomic.AddInt64(&public.Theology, 1)
|
||||
mu.Lock()
|
||||
keyHash := public.FNV32(k)
|
||||
Item, ok := list[keyHash]
|
||||
mu.Unlock()
|
||||
if !ok || Item == nil {
|
||||
Item = &udpItem{
|
||||
LocalAddress: _info.LocalAddress,
|
||||
Tid: atomic.AddInt64(&public.Theology, 1),
|
||||
}
|
||||
serverAddr, er := net.ResolveUDPAddr("udp", _info.RemoteAddress)
|
||||
if er != nil {
|
||||
continue
|
||||
@@ -145,23 +152,34 @@ func (s *Sunny) listenUdpGo() {
|
||||
if er != nil {
|
||||
continue
|
||||
}
|
||||
NFapi.UdpSenders.Add(k, conn, Tid, nil, nil, s.udpSocket, _info.LocalAddress, _info.From)
|
||||
NFapi.NfAddTid(0, Tid, k)
|
||||
go s.goUdp(_info, Tid, addr.String(), _info.RemoteAddress, conn)
|
||||
Item.remote = conn
|
||||
list[keyHash] = Item
|
||||
Item.From = _info.From
|
||||
Item._toToClient = func(i []byte) bool {
|
||||
var b []byte
|
||||
b = append(b, Item.From...)
|
||||
b = append(b, i...)
|
||||
_, e := s.udpSocket.WriteToUDP(b, Item.LocalAddress)
|
||||
return e == nil
|
||||
}
|
||||
Item._toToServer = func(i []byte) bool {
|
||||
_, e := Item.remote.Write(bs)
|
||||
return e == nil
|
||||
}
|
||||
SunnyNetUDP.AddUDPItem(Item.Tid, Item)
|
||||
go s.goUdp(_info, Item.Tid, addr.String(), _info.RemoteAddress, conn, keyHash)
|
||||
}
|
||||
// 获取连接并发送数据
|
||||
conn, Tid := NFapi.UdpSenders.Get(k)
|
||||
if conn != nil {
|
||||
bs = s.udpNFSendReceive(public.SunnyNetUDPTypeSend, Tid, 0, addr.String(), _info.RemoteAddress, _info.Data)
|
||||
if Item.remote != nil {
|
||||
bs = s.udpSendReceive(public.SunnyNetUDPTypeSend, Item.Tid, 0, addr.String(), _info.RemoteAddress, _info.Data)
|
||||
if len(bs) > 0 {
|
||||
_, _ = conn.Write(bs)
|
||||
_, _ = Item.remote.Write(bs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 实现 Sunny 结构体的 goUdp 方法,用于处理 UDP 连接
|
||||
func (s *Sunny) goUdp(info *udpInfo, tid int64, Local, Remote string, conn *net.UDPConn) {
|
||||
func (s *Sunny) goUdp(info *udpInfo, tid int64, Local, Remote string, conn *net.UDPConn, keyHash uint32) {
|
||||
// 创建指定大小的缓冲区
|
||||
buff := make([]byte, 65536)
|
||||
// 循环读取 UDP 数据
|
||||
@@ -173,7 +191,7 @@ func (s *Sunny) goUdp(info *udpInfo, tid int64, Local, Remote string, conn *net.
|
||||
break
|
||||
}
|
||||
// 调用 udpNFSendReceive 方法发送并接收数据,并将返回的数据添加来源信息
|
||||
bs := s.udpNFSendReceive(public.SunnyNetUDPTypeReceive, tid, 0, Local, Remote, buff[:nt])
|
||||
bs := s.udpSendReceive(public.SunnyNetUDPTypeReceive, tid, 0, Local, Remote, buff[:nt])
|
||||
if len(bs) < 1 {
|
||||
continue
|
||||
}
|
||||
@@ -183,14 +201,15 @@ func (s *Sunny) goUdp(info *udpInfo, tid int64, Local, Remote string, conn *net.
|
||||
// 将处理后的数据写入 Socket 中
|
||||
_, _ = s.udpSocket.WriteToUDP(data, info.LocalAddress)
|
||||
}
|
||||
// 从连接池中移除 UDP 连接并发送关闭连接的消息
|
||||
NFapi.UdpSenders.Del(info.LocalAddress.String() + info.RemoteAddress)
|
||||
s.udpNFSendReceive(public.SunnyNetUDPTypeClosed, tid, 0, Local, Remote, nil)
|
||||
// 删除 唯一ID
|
||||
NFapi.NfDelTid(tid)
|
||||
|
||||
s.udpSendReceive(public.SunnyNetUDPTypeClosed, tid, 0, Local, Remote, nil)
|
||||
SunnyNetUDP.DelUDPItem(tid)
|
||||
mu.Lock()
|
||||
delete(list, keyHash)
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
func (s *Sunny) udpNFSendReceive(Type int, Theoni int64, pid uint32, LocalAddress, RemoteAddress string, data []byte) []byte {
|
||||
func (s *Sunny) udpSendReceive(Type int, Theoni int64, pid uint32, LocalAddress, RemoteAddress string, data []byte) []byte {
|
||||
if s.disableUDP {
|
||||
return nil
|
||||
}
|
||||
@@ -212,22 +231,44 @@ func (s *Sunny) udpNFSendReceive(Type int, Theoni int64, pid uint32, LocalAddres
|
||||
MessageId := NewMessageId()
|
||||
var buff bytes.Buffer
|
||||
buff.Write(n.Body())
|
||||
|
||||
// 获取锁并将 buffer 存储到 UdpMap 中
|
||||
NFapi.UdpSync.Lock()
|
||||
NFapi.UdpMap[MessageId] = &buff
|
||||
NFapi.UdpSync.Unlock()
|
||||
SunnyNetUDP.ResetMessage(MessageId, buff.Bytes())
|
||||
// 调用回调函数,并传入相关参数
|
||||
Call.Call(s.udpCallback, s.SunnyContext, LocalAddress, RemoteAddress, int(Type), MessageId, int(Theoni), int(pid))
|
||||
// 获取锁并从 UdpMap 中获取返回值
|
||||
NFapi.UdpSync.Lock()
|
||||
rBody := NFapi.UdpMap[MessageId]
|
||||
delete(NFapi.UdpMap, MessageId)
|
||||
NFapi.UdpSync.Unlock()
|
||||
// 如果返回值为空,则返回原始数据
|
||||
if rBody == nil {
|
||||
return data
|
||||
}
|
||||
buff.Reset()
|
||||
buff.Write(SunnyNetUDP.GetMessage(MessageId))
|
||||
SunnyNetUDP.DelMessage(MessageId)
|
||||
// 否则返回返回值的字节切片
|
||||
return rBody.Bytes()
|
||||
return buff.Bytes()
|
||||
}
|
||||
|
||||
var mu sync.Mutex
|
||||
var list = make(map[uint32]*udpItem)
|
||||
|
||||
type udpItem struct {
|
||||
LocalAddress *net.UDPAddr
|
||||
remote *net.UDPConn
|
||||
From []byte
|
||||
Tid int64
|
||||
_toToClient func(i []byte) bool
|
||||
_toToServer func(i []byte) bool
|
||||
}
|
||||
|
||||
func (it udpItem) ToClient(i []byte) bool {
|
||||
if len(i) < 1 {
|
||||
return false
|
||||
}
|
||||
if it._toToClient != nil {
|
||||
return it._toToClient(i)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (it udpItem) ToServer(i []byte) bool {
|
||||
if len(i) < 1 {
|
||||
return false
|
||||
}
|
||||
if it._toToServer != nil {
|
||||
return it._toToServer(i)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
14
api.go
14
api.go
@@ -530,6 +530,14 @@ func CloseWebsocket(Theology int) bool {
|
||||
return Api.CloseWebsocket(Theology)
|
||||
}
|
||||
|
||||
/*
|
||||
GetMessageNote 获取请求中的注释,由脚本代码中设置
|
||||
*/
|
||||
//export GetMessageNote
|
||||
func GetMessageNote(MessageId int) uintptr {
|
||||
return public.PointerPtr(Api.GetMessageNote(MessageId))
|
||||
}
|
||||
|
||||
/*
|
||||
GetWebsocketBody 获取 WebSocket消息 返回数据指针
|
||||
*/
|
||||
@@ -762,11 +770,11 @@ func WebpToPng(webpPath, savePath *C.char) bool {
|
||||
|
||||
/*
|
||||
OpenDrive 开始进程代理/打开驱动 只允许一个 SunnyNet 使用 [会自动安装所需驱动文件]
|
||||
IsNfapi 如果为true表示使用NFAPI驱动 如果为false 表示使用Proxifier
|
||||
// DevMode 0=Proxifier,1=NFAPI,2=Tun
|
||||
*/
|
||||
//export OpenDrive
|
||||
func OpenDrive(SunnyContext int, isNf bool) bool {
|
||||
return Api.OpenDrive(SunnyContext, isNf)
|
||||
func OpenDrive(SunnyContext int, devMode int) bool {
|
||||
return Api.OpenDrive(SunnyContext, devMode)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
18
go.mod
18
go.mod
@@ -5,12 +5,19 @@ go 1.20
|
||||
require (
|
||||
github.com/Trisia/gosysproxy v1.1.0
|
||||
github.com/andybalholm/brotli v1.1.1
|
||||
github.com/bogdanfinn/tls-client v1.11.2
|
||||
github.com/bwesterb/go-ristretto v1.2.3
|
||||
github.com/go-redis/redis v6.15.9+incompatible
|
||||
github.com/go-resty/resty/v2 v2.16.5
|
||||
github.com/google/gopacket v1.1.19
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/klauspost/compress v1.17.11
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5
|
||||
github.com/tidwall/gjson v1.18.0
|
||||
github.com/tidwall/sjson v1.2.5
|
||||
github.com/yusufpapurcu/wmi v1.2.4
|
||||
golang.org/x/crypto v0.36.0
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
||||
@@ -23,12 +30,23 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bogdanfinn/fhttp v0.6.2 // indirect
|
||||
github.com/bogdanfinn/quic-go-utls v1.0.4-utls // indirect
|
||||
github.com/bogdanfinn/utls v1.7.4-barnius // indirect
|
||||
github.com/cloudflare/circl v1.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||
github.com/onsi/gomega v1.10.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
||||
github.com/tklauser/numcpus v0.8.0 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
golang.org/x/mod v0.18.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
golang.org/x/tools v0.22.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
41
go.sum
41
go.sum
@@ -2,8 +2,18 @@ github.com/Trisia/gosysproxy v1.1.0 h1:rBU1mazMXLsZiiaAHXtRoDPt2gzWdA6uxjaLskzao
|
||||
github.com/Trisia/gosysproxy v1.1.0/go.mod h1:PTPPgpRpyTJEL/FMxEE2OcQcGNbUm961xZcgihwraZM=
|
||||
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||
github.com/bogdanfinn/fhttp v0.6.2 h1:qmFu9fxKmSRR+tcKfgxthmiu365tYspz3Mi404ytZPE=
|
||||
github.com/bogdanfinn/fhttp v0.6.2/go.mod h1:0irhEtS+wJ4m8SGhWO0wmbXMjCbH3WZpU6UcymRYKuk=
|
||||
github.com/bogdanfinn/quic-go-utls v1.0.4-utls h1:zPjusVVNeJFA2ORMAP0rjnrZrBkV4Dnia4e6ToOfUDA=
|
||||
github.com/bogdanfinn/quic-go-utls v1.0.4-utls/go.mod h1:UONJOaHGWho08kZtkkgH7GjktEPjMemGxjTcNpVPZVA=
|
||||
github.com/bogdanfinn/tls-client v1.11.2 h1:o6qX0L1cEi+4MaBqujxqOeK254VZM20t3QR+A34/V6I=
|
||||
github.com/bogdanfinn/tls-client v1.11.2/go.mod h1:qQIsVGe35NdxYEozNh9JuDZ+aOaOEq2tKAsu2iYEGZg=
|
||||
github.com/bogdanfinn/utls v1.7.4-barnius h1:1ldNJEpKdkrx7b8hEc6MRkjnZIF8f2lDcTtRVxqY9zw=
|
||||
github.com/bogdanfinn/utls v1.7.4-barnius/go.mod h1:SUn0CoHGVp/akGNuaqh99yvovu64PCP2LbWd3Z/Laic=
|
||||
github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
|
||||
github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -14,6 +24,8 @@ github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
||||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
|
||||
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
@@ -25,6 +37,10 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
@@ -40,14 +56,27 @@ github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8=
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 h1:YqAladjX7xpA6BM04leXMWAEjS0mTZ5kUU9KRBriQJc=
|
||||
github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5/go.mod h1:2JjD2zLQYH5HO74y5+aE3remJQvl6q4Sn6aWA2wD1Ng=
|
||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
|
||||
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
|
||||
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
|
||||
@@ -57,6 +86,8 @@ github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3i
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
@@ -66,7 +97,11 @@ golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJ
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||
golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68=
|
||||
golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
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=
|
||||
@@ -77,6 +112,8 @@ golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
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=
|
||||
@@ -95,9 +132,13 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
|
||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -3,66 +3,9 @@
|
||||
|
||||
package CrossCompiled
|
||||
|
||||
import "github.com/qtgolang/SunnyNet/src/ProcessDrv/Info"
|
||||
|
||||
func SetIeProxy(Off bool, Port int) bool {
|
||||
return false
|
||||
}
|
||||
func NFapi_SunnyPointer(a ...uintptr) uintptr {
|
||||
return 0
|
||||
}
|
||||
func NFapi_IsInit(a ...bool) bool {
|
||||
return false
|
||||
}
|
||||
func NFapi_ProcessPortInt(a ...uint16) uint16 {
|
||||
return 0
|
||||
}
|
||||
func NFapi_ApiInit() bool {
|
||||
return false
|
||||
}
|
||||
func NFapi_MessageBox(caption, text string, style uintptr) (result int) {
|
||||
return 0
|
||||
}
|
||||
func NFapi_HookAllProcess(open, StopNetwork bool) {
|
||||
}
|
||||
func NFapi_ClosePidTCP(pid int) {
|
||||
}
|
||||
func NFapi_DelName(u string) {
|
||||
}
|
||||
func NFapi_AddName(u string) {
|
||||
}
|
||||
func NFapi_DelPid(pid uint32) {
|
||||
}
|
||||
func NFapi_AddPid(pid uint32) {
|
||||
}
|
||||
func NFapi_CloseNameTCP(u string) {
|
||||
}
|
||||
func NFapi_CancelAll() {
|
||||
}
|
||||
func NFapi_DelTcpConnectInfo(U uint16) {
|
||||
}
|
||||
func NFapi_GetTcpConnectInfo(U uint16) Info.DrvInfo {
|
||||
return nil
|
||||
}
|
||||
func Pr_Install() bool {
|
||||
return false
|
||||
}
|
||||
func Pr_SetHandle(Handle any) bool {
|
||||
return false
|
||||
}
|
||||
func Drive_UnInstall() {
|
||||
}
|
||||
func Pr_IsInit() bool {
|
||||
return false
|
||||
}
|
||||
func NFapi_UdpSendReceiveFunc(udp func(Type int, Theoni int64, pid uint32, LocalAddress, RemoteAddress string, data []byte) []byte) func(Type int, Theoni int64, pid uint32, LocalAddress, RemoteAddress string, data []byte) []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NFapi_Api_NfUdpPostSend(id uint64, remoteAddress any, buf []byte, option any) (int32, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func SetNetworkConnectNumber() {
|
||||
}
|
||||
|
||||
@@ -79,3 +22,59 @@ func InstallCert(certificates []byte) string {
|
||||
func AddFirewallRule() {
|
||||
|
||||
}
|
||||
|
||||
func (N NFAPI) UnInstall() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (N NFAPI) Install() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (N NFAPI) IsRun() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (N NFAPI) SetHandle() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (N NFAPI) Run() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (N NFAPI) Close() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (N NFAPI) Name() string {
|
||||
return "NFAPI"
|
||||
}
|
||||
|
||||
func (p Pr) Install() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p Pr) IsRun() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p Pr) SetHandle() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p Pr) Run() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p Pr) Close() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p Pr) Name() string {
|
||||
return "Proxifier"
|
||||
}
|
||||
|
||||
func (p Pr) UnInstall() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ package CrossCompiled
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/Info"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
@@ -108,59 +107,6 @@ func SetIeProxy(Off bool, Port int) bool {
|
||||
}
|
||||
return Inter.SetProxy("127.0.0.1", Port)
|
||||
}
|
||||
func Drive_UnInstall() {
|
||||
}
|
||||
func NFapi_SunnyPointer(a ...uintptr) uintptr {
|
||||
return 0
|
||||
}
|
||||
func NFapi_IsInit(a ...bool) bool {
|
||||
return false
|
||||
}
|
||||
func NFapi_ProcessPortInt(a ...uint16) uint16 {
|
||||
return 0
|
||||
}
|
||||
func NFapi_ApiInit() bool {
|
||||
return false
|
||||
}
|
||||
func NFapi_MessageBox(caption, text string, style uintptr) (result int) {
|
||||
return 0
|
||||
}
|
||||
func NFapi_HookAllProcess(open, StopNetwork bool) {
|
||||
}
|
||||
func NFapi_ClosePidTCP(pid int) {
|
||||
}
|
||||
func NFapi_DelName(u string) {
|
||||
}
|
||||
func NFapi_AddName(u string) {
|
||||
}
|
||||
func NFapi_DelPid(pid uint32) {
|
||||
}
|
||||
func NFapi_AddPid(pid uint32) {
|
||||
}
|
||||
func NFapi_CloseNameTCP(u string) {
|
||||
}
|
||||
func NFapi_CancelAll() {
|
||||
}
|
||||
func NFapi_DelTcpConnectInfo(U uint16) {
|
||||
}
|
||||
func NFapi_GetTcpConnectInfo(U uint16) Info.DrvInfo {
|
||||
return nil
|
||||
}
|
||||
func NFapi_UdpSendReceiveFunc(udp func(Type int, Theoni int64, pid uint32, LocalAddress, RemoteAddress string, data []byte) []byte) func(Type int, Theoni int64, pid uint32, LocalAddress, RemoteAddress string, data []byte) []byte {
|
||||
return nil
|
||||
}
|
||||
func Pr_Install() bool {
|
||||
return false
|
||||
}
|
||||
func Pr_SetHandle(Handle any) bool {
|
||||
return false
|
||||
}
|
||||
func Pr_IsInit() bool {
|
||||
return false
|
||||
}
|
||||
func NFapi_Api_NfUdpPostSend(id uint64, remoteAddress any, buf []byte, option any) (int32, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func SetNetworkConnectNumber() {
|
||||
}
|
||||
@@ -178,3 +124,59 @@ func InstallCert(certificates []byte) string {
|
||||
func AddFirewallRule() {
|
||||
|
||||
}
|
||||
|
||||
func (N NFAPI) UnInstall() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (N NFAPI) Install() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (N NFAPI) IsRun() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (N NFAPI) SetHandle() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (N NFAPI) Run() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (N NFAPI) Close() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (N NFAPI) Name() string {
|
||||
return "NFAPI"
|
||||
}
|
||||
|
||||
func (p Pr) Install() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p Pr) IsRun() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p Pr) SetHandle() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p Pr) Run() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p Pr) Close() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p Pr) Name() string {
|
||||
return "Proxifier"
|
||||
}
|
||||
|
||||
func (p Pr) UnInstall() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,17 +1,62 @@
|
||||
package CrossCompiled
|
||||
|
||||
import (
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/tun"
|
||||
Tun2 "github.com/qtgolang/SunnyNet/src/ProcessDrv/tun/Tun"
|
||||
"github.com/qtgolang/SunnyNet/src/iphlpapi/net"
|
||||
"github.com/shirou/gopsutil/process"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const DrvUndefined = 0
|
||||
const DrvNF = 1
|
||||
const DrvPr = 2
|
||||
type NFAPI struct {
|
||||
TCP Tun2.TcpFunc
|
||||
UDP Tun2.UdpFunc
|
||||
Sunny Tun2.Interface
|
||||
}
|
||||
type Pr struct {
|
||||
TCP Tun2.TcpFunc
|
||||
UDP Tun2.UdpFunc
|
||||
Sunny Tun2.Interface
|
||||
}
|
||||
type Tun struct {
|
||||
TCP Tun2.TcpFunc
|
||||
UDP Tun2.UdpFunc
|
||||
Sunny Tun2.Interface
|
||||
}
|
||||
|
||||
var DrvInitState = 0
|
||||
func (t Tun) Install() bool {
|
||||
return tun.Install()
|
||||
}
|
||||
|
||||
func (t Tun) IsRun() bool {
|
||||
return tun.IsRun()
|
||||
}
|
||||
|
||||
func (t Tun) SetHandle() bool {
|
||||
tun.SetHandle(t.TCP, t.UDP, t.Sunny)
|
||||
return true
|
||||
}
|
||||
|
||||
func (t Tun) Run() bool {
|
||||
return tun.Run()
|
||||
}
|
||||
|
||||
func (t Tun) Close() bool {
|
||||
return tun.Close()
|
||||
}
|
||||
|
||||
func (t Tun) Name() string {
|
||||
return tun.Name()
|
||||
}
|
||||
|
||||
func (t Tun) UnInstall() bool {
|
||||
return tun.UnInstall()
|
||||
}
|
||||
|
||||
const DrvPr = 0
|
||||
const DrvNF = 1
|
||||
const DrvTun = 2
|
||||
|
||||
// GetTcpInfoPID 用于获取指定 TCP 连接信息的 PID
|
||||
func GetTcpInfoPID(tcpInfo string, SunnyPort int) string {
|
||||
|
||||
@@ -18,112 +18,75 @@ import (
|
||||
"github.com/qtgolang/SunnyNet/src/public"
|
||||
"golang.org/x/sys/windows"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func NFapi_SunnyPointer(a ...uintptr) uintptr {
|
||||
if len(a) > 0 {
|
||||
NFapi2.SunnyPointer = a[0]
|
||||
}
|
||||
return NFapi2.SunnyPointer
|
||||
func (N NFAPI) UnInstall() bool {
|
||||
NFapi2.UnInstall()
|
||||
return true
|
||||
}
|
||||
func NFapi_IsInit(a ...bool) bool {
|
||||
if len(a) > 0 {
|
||||
NFapi2.IsInit = a[0]
|
||||
}
|
||||
|
||||
func (N NFAPI) Install() bool {
|
||||
return NFapi2.ApiInit()
|
||||
}
|
||||
|
||||
func (N NFAPI) IsRun() bool {
|
||||
return NFapi2.IsInit
|
||||
}
|
||||
func Pr_Install() bool {
|
||||
|
||||
func (N NFAPI) SetHandle() bool {
|
||||
NFapi2.ProcessPortInt = uint16(N.Sunny.Port())
|
||||
return true
|
||||
}
|
||||
|
||||
func (N NFAPI) Run() bool {
|
||||
NFapi2.UdpSendReceiveFunc = N.UDP
|
||||
NFapi2.IsInit = NFapi2.ApiInit()
|
||||
return NFapi2.IsInit
|
||||
}
|
||||
|
||||
func (N NFAPI) Close() bool {
|
||||
NFapi2.ProcessPortInt = 0
|
||||
NFapi2.IsInit = false
|
||||
return true
|
||||
}
|
||||
|
||||
func (N NFAPI) Name() string {
|
||||
return "NFAPI"
|
||||
}
|
||||
|
||||
func (p Pr) Install() bool {
|
||||
return Proxifier.Install()
|
||||
}
|
||||
func Pr_IsInit() bool {
|
||||
|
||||
func (p Pr) IsRun() bool {
|
||||
return Proxifier.IsInit()
|
||||
}
|
||||
|
||||
func Pr_SetHandle(Handle func(conn net.Conn)) bool {
|
||||
return Proxifier.SetHandle(Handle)
|
||||
func (p Pr) SetHandle() bool {
|
||||
return Proxifier.SetHandle(p.TCP)
|
||||
}
|
||||
func NFapi_ProcessPortInt(a ...uint16) uint16 {
|
||||
if len(a) > 0 {
|
||||
NFapi2.ProcessPortInt = a[0]
|
||||
}
|
||||
return NFapi2.ProcessPortInt
|
||||
func (p Pr) Run() bool {
|
||||
//安装后自动就启动了
|
||||
return true
|
||||
}
|
||||
func NFapi_ApiInit() bool {
|
||||
return NFapi2.ApiInit()
|
||||
|
||||
func (p Pr) Close() bool {
|
||||
return Proxifier.SetHandle(nil)
|
||||
}
|
||||
func NFapi_MessageBox(caption, text string, style uintptr) (result int) {
|
||||
return NFapi2.MessageBox(caption, text, style)
|
||||
|
||||
func (p Pr) Name() string {
|
||||
return "Proxifier"
|
||||
}
|
||||
func Drive_UnInstall() {
|
||||
tmp := NFapi2.System32Dir + "\\tmp.tmp"
|
||||
if err := os.WriteFile(tmp, []byte("check"), 0777); err != nil {
|
||||
return
|
||||
}
|
||||
_ = os.Remove(tmp)
|
||||
NFapi2.UnInstall()
|
||||
|
||||
func (p Pr) UnInstall() bool {
|
||||
Proxifier.UnInstall()
|
||||
Proxifier.Run("shutdown", "/r", "/f", "/t", "0")
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
func NFapi_HookAllProcess(open, StopNetwork bool) {
|
||||
Info.HookAllProcess(open, StopNetwork)
|
||||
}
|
||||
func NFapi_ClosePidTCP(pid int) {
|
||||
Info.ClosePidTCP(pid)
|
||||
}
|
||||
func NFapi_DelName(u string) {
|
||||
a, e := public.GbkToUtf8(u)
|
||||
if e != nil {
|
||||
Info.AddName(a)
|
||||
}
|
||||
a, e = public.Utf8ToGbk(u)
|
||||
if e != nil {
|
||||
Info.AddName(a)
|
||||
}
|
||||
Info.DelName(u)
|
||||
}
|
||||
func NFapi_AddName(u string) {
|
||||
a, e := public.GbkToUtf8(u)
|
||||
if e != nil {
|
||||
Info.AddName(a)
|
||||
}
|
||||
a, e = public.Utf8ToGbk(u)
|
||||
if e != nil {
|
||||
Info.AddName(a)
|
||||
}
|
||||
Info.AddName(u)
|
||||
}
|
||||
func NFapi_DelPid(pid uint32) {
|
||||
Info.DelPid(pid)
|
||||
}
|
||||
func NFapi_AddPid(pid uint32) {
|
||||
Info.AddPid(pid)
|
||||
}
|
||||
|
||||
func NFapi_CancelAll() {
|
||||
Info.CancelAll()
|
||||
}
|
||||
func NFapi_DelTcpConnectInfo(U uint16) {
|
||||
Info.DelTcpConnectInfo(U)
|
||||
}
|
||||
func NFapi_GetTcpConnectInfo(U uint16) Info.DrvInfo {
|
||||
return Info.GetTcpConnectInfo(U)
|
||||
}
|
||||
|
||||
func NFapi_UdpSendReceiveFunc(udp func(Type int, Theoni int64, pid uint32, LocalAddress, RemoteAddress string, data []byte) []byte) func(Type int, Theoni int64, pid uint32, LocalAddress, RemoteAddress string, data []byte) []byte {
|
||||
NFapi2.UdpSendReceiveFunc = udp
|
||||
return NFapi2.UdpSendReceiveFunc
|
||||
}
|
||||
func NFapi_Api_NfUdpPostSend(id uint64, remoteAddress *NFapi2.SockaddrInx, buf []byte, option *NFapi2.NF_UDP_OPTIONS) (NFapi2.NF_STATUS, error) {
|
||||
return NFapi2.Api.NfUdpPostSend(id, remoteAddress, buf, option)
|
||||
return true
|
||||
}
|
||||
|
||||
func SetIeProxy(Off bool, Port int) bool {
|
||||
|
||||
@@ -29,6 +29,8 @@ import (
|
||||
"reflect"
|
||||
"SunnyNet/src/Call"
|
||||
"SunnyNet/src/mmCompress"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
"SunnyNet/src/SunnyProtobuf"
|
||||
)
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ import (
|
||||
_ "github.com/qtgolang/SunnyNet/src/http/pprof"
|
||||
"github.com/qtgolang/SunnyNet/src/protobuf"
|
||||
"github.com/qtgolang/SunnyNet/src/public"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -171,6 +173,28 @@ func init() {
|
||||
Symbols["github.com/qtgolang/SunnyNet/src/RSA/RSA"] = map[string]reflect.Value{
|
||||
"PubKeyIO": reflect.ValueOf(RSA.PubKeyIO),
|
||||
}
|
||||
Symbols["github.com/tidwall/sjson/sjson"] = map[string]reflect.Value{
|
||||
"Set": reflect.ValueOf(sjson.Set),
|
||||
"SetRaw": reflect.ValueOf(sjson.SetRaw),
|
||||
"SetBytes": reflect.ValueOf(sjson.SetBytes),
|
||||
"SetOptions": reflect.ValueOf(sjson.SetOptions),
|
||||
"SetRawBytes": reflect.ValueOf(sjson.SetRawBytes),
|
||||
"SetRawOptions": reflect.ValueOf(sjson.SetRawOptions),
|
||||
"SetRawBytesOptions": reflect.ValueOf(sjson.SetRawBytesOptions),
|
||||
"Options": reflect.ValueOf((*sjson.Options)(nil)),
|
||||
}
|
||||
Symbols["github.com/tidwall/gjson/gjson"] = map[string]reflect.Value{
|
||||
"Parse": reflect.ValueOf(gjson.Parse),
|
||||
"Valid": reflect.ValueOf(gjson.Valid),
|
||||
"ParseBytes": reflect.ValueOf(gjson.ParseBytes),
|
||||
"ValidBytes": reflect.ValueOf(gjson.ValidBytes),
|
||||
"Get": reflect.ValueOf(gjson.Get),
|
||||
"GetMany": reflect.ValueOf(gjson.GetMany),
|
||||
"GetManyBytes": reflect.ValueOf(gjson.GetManyBytes),
|
||||
"GetBytes": reflect.ValueOf(gjson.GetBytes),
|
||||
"AppendJSONString": reflect.ValueOf(gjson.AppendJSONString),
|
||||
"Result": reflect.ValueOf((*gjson.Result)(nil)),
|
||||
}
|
||||
Symbols["reflect/reflect"] = map[string]reflect.Value{
|
||||
"TypeOf": reflect.ValueOf(reflect.TypeOf),
|
||||
"Func": reflect.ValueOf(reflect.Func),
|
||||
@@ -197,7 +221,7 @@ func RunCode(SunnyNetContext int, UserScriptCode []byte, log LogFuncInterface) (
|
||||
}
|
||||
}()
|
||||
var iEval = interp.New(interp.Options{})
|
||||
iEval.Use(Symbols)
|
||||
_ = iEval.Use(Symbols)
|
||||
ca := ""
|
||||
if len(UserScriptCode) < 100 {
|
||||
ca = string(DefaultCode) + string(GoFunc)
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
/* =============================== 脚本 中 使用的接口 ================================================ */
|
||||
type ConnHTTPScriptCall interface {
|
||||
connHTTP
|
||||
noteScript
|
||||
/*
|
||||
SetDisplay
|
||||
设置是否通知回调显示当前请求(默认为true)
|
||||
@@ -24,6 +25,7 @@ type ConnHTTPScriptCall interface {
|
||||
}
|
||||
type ConnWebSocketScriptCall interface {
|
||||
ConnWebSocketCall
|
||||
noteScript
|
||||
/*
|
||||
SetDisplay
|
||||
设置是否通知回调显示当前请求(默认为true)
|
||||
@@ -33,6 +35,7 @@ type ConnWebSocketScriptCall interface {
|
||||
}
|
||||
type ConnTCPScriptCall interface {
|
||||
ConnTCPCall
|
||||
noteScript
|
||||
/*
|
||||
SetDisplay
|
||||
设置是否通知回调显示当前请求(默认为true)
|
||||
@@ -42,6 +45,7 @@ type ConnTCPScriptCall interface {
|
||||
}
|
||||
type ConnUDPScriptCall interface {
|
||||
ConnUDPCall
|
||||
noteScript
|
||||
/*
|
||||
SetDisplay
|
||||
设置是否通知回调显示当前请求(默认为true)
|
||||
@@ -54,6 +58,7 @@ type ConnUDPScriptCall interface {
|
||||
type ConnUDPCall interface {
|
||||
general
|
||||
address
|
||||
note
|
||||
/*
|
||||
Body
|
||||
获取消息内容
|
||||
@@ -90,6 +95,7 @@ type ConnTCPCall interface {
|
||||
proxy
|
||||
router
|
||||
address
|
||||
note
|
||||
/*
|
||||
Body
|
||||
|
||||
@@ -152,6 +158,7 @@ type ConnTCPCall interface {
|
||||
}
|
||||
type ConnWebSocketCall interface {
|
||||
general
|
||||
note
|
||||
/*
|
||||
Body
|
||||
|
||||
@@ -235,6 +242,7 @@ type ConnWebSocketCall interface {
|
||||
}
|
||||
type ConnHTTPCall interface {
|
||||
connHTTP
|
||||
note
|
||||
/*
|
||||
SetHTTP2Config
|
||||
|
||||
@@ -447,7 +455,7 @@ type address interface {
|
||||
SendToClient(data []byte) bool
|
||||
}
|
||||
type general interface {
|
||||
|
||||
note
|
||||
/*
|
||||
Context
|
||||
|
||||
@@ -510,3 +518,25 @@ type router interface {
|
||||
*/
|
||||
SetOutRouterIP(way string) bool
|
||||
}
|
||||
|
||||
/* =============================================================================== */
|
||||
//非脚本不允许调用设置
|
||||
type noteScript interface {
|
||||
note
|
||||
/*
|
||||
SetNote
|
||||
|
||||
设置当前请求注释
|
||||
|
||||
note=要设置的注释
|
||||
*/
|
||||
SetNote(note string)
|
||||
}
|
||||
type note interface {
|
||||
/*
|
||||
GetNote
|
||||
|
||||
获取当前请求注释
|
||||
*/
|
||||
GetNote() string
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package Info
|
||||
|
||||
import (
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/ProcessCheck"
|
||||
"github.com/qtgolang/SunnyNet/src/iphlpapi"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"os/exec"
|
||||
@@ -22,6 +23,10 @@ func ClosePidTCP(PID int) {
|
||||
iphlpapi.CloseCurrentSocket(PID, AF_INET)
|
||||
iphlpapi.CloseCurrentSocket(PID, AF_INET6)
|
||||
}
|
||||
func init() {
|
||||
ProcessCheck.ClosePidTCP = ClosePidTCP
|
||||
ProcessCheck.CloseNameTCP = CloseNameTCP
|
||||
}
|
||||
|
||||
// CloseNameTCP 关闭指定进程的所有TCP连接
|
||||
func CloseNameTCP(processName string) {
|
||||
|
||||
@@ -16,6 +16,7 @@ func MoveFileToTempDir(srcFile, destFileName string) string {
|
||||
destPath := filepath.Join(tempDir, destFileName)
|
||||
// 移动文件
|
||||
err := os.Rename(srcFile, destPath)
|
||||
_ = os.Remove(destPath)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ import (
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
@@ -177,94 +176,6 @@ func ExecCommand(commandName string, params []string) string {
|
||||
}
|
||||
return string(s)
|
||||
}
|
||||
|
||||
type DrvInfo interface {
|
||||
GetRemoteAddress() string
|
||||
GetRemotePort() uint16
|
||||
GetPid() string
|
||||
IsV6() bool
|
||||
ID() uint64
|
||||
Close()
|
||||
}
|
||||
|
||||
var Name = make(map[string]bool)
|
||||
var Pid = make(map[uint32]bool)
|
||||
var Proxy = make(map[uint16]DrvInfo)
|
||||
var Lock sync.Mutex
|
||||
|
||||
var HookProcess bool
|
||||
|
||||
func HookAllProcess(open, StopNetwork bool) {
|
||||
Lock.Lock()
|
||||
for u := range Name {
|
||||
delete(Name, u)
|
||||
}
|
||||
for u := range Pid {
|
||||
delete(Pid, u)
|
||||
}
|
||||
HookProcess = open
|
||||
Lock.Unlock()
|
||||
if StopNetwork {
|
||||
ClosePidTCP(-1)
|
||||
}
|
||||
}
|
||||
|
||||
func GetTcpConnectInfo(u uint16) DrvInfo {
|
||||
Lock.Lock()
|
||||
k := Proxy[u]
|
||||
Lock.Unlock()
|
||||
if k == nil {
|
||||
return nil
|
||||
}
|
||||
return k
|
||||
}
|
||||
func DelTcpConnectInfo(u uint16) {
|
||||
Lock.Lock()
|
||||
delete(Proxy, u)
|
||||
Lock.Unlock()
|
||||
}
|
||||
func AddName(u string) bool {
|
||||
Lock.Lock()
|
||||
Name[strings.ToLower(u)] = true
|
||||
Lock.Unlock()
|
||||
CloseNameTCP(u)
|
||||
return true
|
||||
}
|
||||
func DelName(u string) bool {
|
||||
Lock.Lock()
|
||||
delete(Name, strings.ToLower(u))
|
||||
Lock.Unlock()
|
||||
CloseNameTCP(u)
|
||||
return true
|
||||
}
|
||||
func AddPid(u uint32) bool {
|
||||
Lock.Lock()
|
||||
Pid[u] = true
|
||||
Lock.Unlock()
|
||||
ClosePidTCP(int(u))
|
||||
return true
|
||||
}
|
||||
func DelPid(u uint32) bool {
|
||||
Lock.Lock()
|
||||
delete(Pid, u)
|
||||
Lock.Unlock()
|
||||
ClosePidTCP(int(u))
|
||||
return true
|
||||
}
|
||||
|
||||
func CancelAll() bool {
|
||||
Lock.Lock()
|
||||
for u := range Name {
|
||||
CloseNameTCP(u)
|
||||
delete(Name, u)
|
||||
}
|
||||
for u := range Pid {
|
||||
ClosePidTCP(int(u))
|
||||
delete(Pid, u)
|
||||
}
|
||||
Lock.Unlock()
|
||||
return true
|
||||
}
|
||||
func IsFilterRequests(fileName, addr string) bool {
|
||||
if strings.Index(strings.ToLower(fileName), "wechat.exe") != -1 && (strings.Contains(addr, "::1") || strings.Contains(addr, "127.0.0.1")) {
|
||||
//如果微信连接到本机的这个请求被拦截,小程序无法打开,目前不清楚原因
|
||||
|
||||
9
src/ProcessDrv/ProcessCheck/Win.go
Normal file
9
src/ProcessDrv/ProcessCheck/Win.go
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package ProcessCheck
|
||||
|
||||
var ClosePidTCP = func(PID int) {
|
||||
}
|
||||
var CloseNameTCP = func(processName string) {
|
||||
}
|
||||
118
src/ProcessDrv/ProcessCheck/main.go
Normal file
118
src/ProcessDrv/ProcessCheck/main.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package ProcessCheck
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type DrvInfo interface {
|
||||
GetRemoteAddress() string
|
||||
GetRemotePort() uint16
|
||||
GetPid() string
|
||||
IsV6() bool
|
||||
ID() uint64
|
||||
Close() error
|
||||
}
|
||||
|
||||
var Name = make(map[string]bool)
|
||||
var Pid = make(map[uint32]bool)
|
||||
var Proxy = make(map[uint16]DrvInfo)
|
||||
var Lock sync.Mutex
|
||||
|
||||
var HookProcess bool
|
||||
|
||||
func HookAllProcess(open, StopNetwork bool) {
|
||||
Lock.Lock()
|
||||
for u := range Name {
|
||||
delete(Name, u)
|
||||
}
|
||||
for u := range Pid {
|
||||
delete(Pid, u)
|
||||
}
|
||||
HookProcess = open
|
||||
Lock.Unlock()
|
||||
if StopNetwork {
|
||||
ClosePidTCP(-1)
|
||||
}
|
||||
}
|
||||
func GetTcpConnectInfo(u uint16) DrvInfo {
|
||||
Lock.Lock()
|
||||
k := Proxy[u]
|
||||
Lock.Unlock()
|
||||
if k == nil {
|
||||
return nil
|
||||
}
|
||||
return k
|
||||
}
|
||||
func DelTcpConnectInfo(u uint16) {
|
||||
Lock.Lock()
|
||||
delete(Proxy, u)
|
||||
Lock.Unlock()
|
||||
}
|
||||
func AddName(u string) bool {
|
||||
Lock.Lock()
|
||||
Name[strings.ToLower(u)] = true
|
||||
Lock.Unlock()
|
||||
CloseNameTCP(u)
|
||||
return true
|
||||
}
|
||||
func DelName(u string) bool {
|
||||
Lock.Lock()
|
||||
delete(Name, strings.ToLower(u))
|
||||
Lock.Unlock()
|
||||
CloseNameTCP(u)
|
||||
return true
|
||||
}
|
||||
func AddPid(u uint32) bool {
|
||||
Lock.Lock()
|
||||
Pid[u] = true
|
||||
Lock.Unlock()
|
||||
ClosePidTCP(int(u))
|
||||
return true
|
||||
}
|
||||
func DelPid(u uint32) bool {
|
||||
Lock.Lock()
|
||||
delete(Pid, u)
|
||||
Lock.Unlock()
|
||||
ClosePidTCP(int(u))
|
||||
return true
|
||||
}
|
||||
func CancelAll() bool {
|
||||
Lock.Lock()
|
||||
for u := range Name {
|
||||
CloseNameTCP(u)
|
||||
delete(Name, u)
|
||||
}
|
||||
for u := range Pid {
|
||||
ClosePidTCP(int(u))
|
||||
delete(Pid, u)
|
||||
}
|
||||
Lock.Unlock()
|
||||
return true
|
||||
}
|
||||
|
||||
func AddDevObj(connPort uint16, info DrvInfo) {
|
||||
Lock.Lock()
|
||||
Proxy[connPort] = info
|
||||
Lock.Unlock()
|
||||
}
|
||||
func DelDevObj(connPort uint16) {
|
||||
Lock.Lock()
|
||||
delete(Proxy, connPort)
|
||||
Lock.Unlock()
|
||||
}
|
||||
|
||||
// CheckPidByName 返回 true 表示不要继续,不在规则中
|
||||
func CheckPidByName(pid int32, name string) bool {
|
||||
Lock.Lock()
|
||||
defer Lock.Unlock()
|
||||
if HookProcess {
|
||||
return false
|
||||
}
|
||||
if Name[strings.ToLower(name)] == false {
|
||||
if Pid[uint32(pid)] == false {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
9
src/ProcessDrv/ProcessCheck/noWin.go
Normal file
9
src/ProcessDrv/ProcessCheck/noWin.go
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package ProcessCheck
|
||||
|
||||
var ClosePidTCP = func(PID int) {
|
||||
}
|
||||
var CloseNameTCP = func(processName string) {
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package Proxifier
|
||||
|
||||
import (
|
||||
@@ -29,6 +32,7 @@ func UnInstall() {
|
||||
Info.Wow64RevertWow64FsRedirection(oldValue)
|
||||
}
|
||||
}
|
||||
Run("shutdown", "/r", "/f", "/t", "0")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package Proxifier
|
||||
|
||||
/*
|
||||
@@ -13,10 +16,11 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/Info"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/ProcessCheck"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
@@ -34,31 +38,28 @@ func Write(hPipe C.HANDLE, bs []byte) {
|
||||
C.free(unsafe.Pointer(b))
|
||||
}
|
||||
|
||||
var mu sync.Mutex
|
||||
|
||||
//export Call
|
||||
func Call(hPipe C.HANDLE, raw uintptr) {
|
||||
__pid := int(binary.LittleEndian.Uint16(CStringToBytes(raw+0x4EC, 2)))
|
||||
path := wcharPtrToString(raw + 8)
|
||||
|
||||
Info.Lock.Lock()
|
||||
mu.Lock()
|
||||
Handle := HandleClientConn
|
||||
if __pid == myPid {
|
||||
Info.Lock.Unlock()
|
||||
mu.Unlock()
|
||||
return
|
||||
}
|
||||
if Handle == nil {
|
||||
Info.Lock.Unlock()
|
||||
mu.Unlock()
|
||||
return
|
||||
}
|
||||
fileName := filepath.Base(path)
|
||||
if Info.HookProcess == false {
|
||||
if Info.Name[strings.ToLower(fileName)] == false {
|
||||
if Info.Pid[uint32(__pid)] == false {
|
||||
Info.Lock.Unlock()
|
||||
return
|
||||
}
|
||||
}
|
||||
if ProcessCheck.CheckPidByName(int32(__pid), fileName) {
|
||||
return
|
||||
}
|
||||
Info.Lock.Unlock()
|
||||
mu.Unlock()
|
||||
family := int16(binary.LittleEndian.Uint16(CStringToBytes(raw+0x419, 2)))
|
||||
if family == 0 {
|
||||
WriteData := make([]byte, 1020)
|
||||
@@ -139,15 +140,13 @@ func Call(hPipe C.HANDLE, raw uintptr) {
|
||||
_ISV6 = true
|
||||
}
|
||||
var obj = &proxyProcessInfo{listener: listener, RemoteAddress: domain, RemotePort: uint16(port), V6: _ISV6, Pid: fmt.Sprintf("%d", __pid)}
|
||||
|
||||
connLocalAddr := conn.RemoteAddr().(*net.TCPAddr)
|
||||
connPort := uint16(connLocalAddr.Port)
|
||||
Info.Lock.Lock()
|
||||
Info.Proxy[connPort] = obj
|
||||
Info.Lock.Unlock()
|
||||
ProcessCheck.AddDevObj(connPort, obj)
|
||||
_ = conn.SetDeadline(time.Time{})
|
||||
Handle(conn)
|
||||
_ = conn.Close()
|
||||
ProcessCheck.DelDevObj(connPort)
|
||||
}
|
||||
_ = listener.Close()
|
||||
return
|
||||
@@ -201,13 +200,14 @@ func (p *proxyProcessInfo) IsV6() bool {
|
||||
func (p *proxyProcessInfo) ID() uint64 {
|
||||
return p.Id
|
||||
}
|
||||
func (p *proxyProcessInfo) Close() {
|
||||
Info.Lock.Lock()
|
||||
func (p *proxyProcessInfo) Close() error {
|
||||
mu.Lock()
|
||||
if p.listener != nil {
|
||||
_ = p.listener.Close()
|
||||
}
|
||||
p.listener = nil
|
||||
Info.Lock.Unlock()
|
||||
mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
func wcharPtrToString(ptr uintptr) string {
|
||||
var length int
|
||||
@@ -245,14 +245,14 @@ func IsInit() bool {
|
||||
}
|
||||
func SetHandle(Handle func(conn net.Conn)) bool {
|
||||
res := 0
|
||||
Info.Lock.Lock()
|
||||
mu.Lock()
|
||||
if Handle == nil {
|
||||
res = int(C.StopProxifier())
|
||||
} else {
|
||||
res = int(C.StartProxifier())
|
||||
}
|
||||
HandleClientConn = Handle
|
||||
Info.Lock.Unlock()
|
||||
mu.Unlock()
|
||||
return res == 1
|
||||
}
|
||||
|
||||
|
||||
65
src/ProcessDrv/SunnyNetUDP/udp.go
Normal file
65
src/ProcessDrv/SunnyNetUDP/udp.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package SunnyNetUDP
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type SunnyNetUDP interface {
|
||||
ToClient([]byte) bool
|
||||
ToServer([]byte) bool
|
||||
}
|
||||
|
||||
var mu sync.Mutex
|
||||
var list = make(map[int64]SunnyNetUDP)
|
||||
|
||||
func AddUDPItem(id int64, Item SunnyNetUDP) {
|
||||
mu.Lock()
|
||||
list[id] = Item
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
func DelUDPItem(id int64) {
|
||||
mu.Lock()
|
||||
delete(list, id)
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
func GetUDPItem(id int64) SunnyNetUDP {
|
||||
mu.Lock()
|
||||
obj := list[id]
|
||||
mu.Unlock()
|
||||
return obj
|
||||
}
|
||||
|
||||
var messageMu sync.Mutex
|
||||
|
||||
var message = make(map[int][]byte)
|
||||
|
||||
func SetMessage(MessageId int, buff []byte) bool {
|
||||
messageMu.Lock()
|
||||
defer messageMu.Unlock()
|
||||
if _, ok := message[MessageId]; ok {
|
||||
message[MessageId] = buff
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func ResetMessage(MessageId int, buff []byte) bool {
|
||||
messageMu.Lock()
|
||||
defer messageMu.Unlock()
|
||||
message[MessageId] = buff
|
||||
return true
|
||||
}
|
||||
func GetMessage(MessageId int) []byte {
|
||||
messageMu.Lock()
|
||||
defer messageMu.Unlock()
|
||||
if _, ok := message[MessageId]; ok {
|
||||
return message[MessageId]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func DelMessage(MessageId int) {
|
||||
messageMu.Lock()
|
||||
defer messageMu.Unlock()
|
||||
delete(message, MessageId)
|
||||
}
|
||||
18
src/ProcessDrv/dev.go
Normal file
18
src/ProcessDrv/dev.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package ProcessDrv
|
||||
|
||||
type Dev interface {
|
||||
//Install 安装依赖驱动
|
||||
Install() bool
|
||||
//IsRun 是否已运行
|
||||
IsRun() bool
|
||||
//SetHandle 设置回调
|
||||
SetHandle() bool
|
||||
//Run 开始运行
|
||||
Run() bool
|
||||
//Close 关闭
|
||||
Close() bool
|
||||
//Name 驱动名称
|
||||
Name() string
|
||||
//UnInstall 卸载驱动
|
||||
UnInstall() bool
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import "C"
|
||||
import (
|
||||
"fmt"
|
||||
. "github.com/qtgolang/SunnyNet/src/ProcessDrv/Info"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/ProcessCheck"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/SunnyNetUDP"
|
||||
net2 "github.com/qtgolang/SunnyNet/src/iphlpapi/net"
|
||||
"github.com/qtgolang/SunnyNet/src/public"
|
||||
"github.com/shirou/gopsutil/process"
|
||||
@@ -33,7 +35,6 @@ var Api = new(NFApi)
|
||||
var ProcessPortInt uint16
|
||||
var SunnyPointer = uintptr(0)
|
||||
var IsInit = false
|
||||
var UdpSendReceiveFunc func(Type int, Theoni int64, pid uint32, LocalAddress, RemoteAddress string, data []byte) []byte
|
||||
|
||||
func threadStart() {
|
||||
|
||||
@@ -111,17 +112,10 @@ func tcpConnectRequest(id uint64, pConnInfo *NF_TCP_CONN_INFO) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Lock.Lock()
|
||||
if HookProcess == false {
|
||||
if Name[strings.ToLower(ProcessName)] == false {
|
||||
if Pid[pConnInfo.ProcessId.Get()] == false {
|
||||
Lock.Unlock()
|
||||
_, _ = Api.NfTcpDisableFiltering(id)
|
||||
return
|
||||
}
|
||||
}
|
||||
if ProcessCheck.CheckPidByName(int32(pConnInfo.ProcessId.Get()), ProcessName) {
|
||||
_, _ = Api.NfTcpDisableFiltering(id)
|
||||
return
|
||||
}
|
||||
Lock.Unlock()
|
||||
if IsFilterRequests(ProcessName, pConnInfo.RemoteAddress.String()) {
|
||||
return
|
||||
}
|
||||
@@ -136,9 +130,7 @@ func tcpConnectRequest(id uint64, pConnInfo *NF_TCP_CONN_INFO) {
|
||||
|
||||
//这里是IPV6
|
||||
Process := &ProcessInfo{Pid: strconv.Itoa(int(pConnInfo.ProcessId.Get())), RemoteAddress: IP.String(), RemotePort: pConnInfo.RemoteAddress.GetPort(), Id: id, V6: true}
|
||||
Lock.Lock()
|
||||
Proxy[pConnInfo.LocalAddress.GetPort()] = Process
|
||||
Lock.Unlock()
|
||||
ProcessCheck.AddDevObj(pConnInfo.LocalAddress.GetPort(), Process)
|
||||
pConnInfo.RemoteAddress.SetIP(false, net.ParseIP(getIPV6Lan()))
|
||||
pConnInfo.RemoteAddress.SetPort(ProcessPortInt)
|
||||
return
|
||||
@@ -153,17 +145,13 @@ func tcpConnectRequest(id uint64, pConnInfo *NF_TCP_CONN_INFO) {
|
||||
var Port UINT16
|
||||
Port.BigEndianSet(ProcessPortInt)
|
||||
pConnInfo.RemoteAddress.Port = Port
|
||||
Lock.Lock()
|
||||
Proxy[pConnInfo.LocalAddress.GetPort()] = Process
|
||||
Lock.Unlock()
|
||||
ProcessCheck.AddDevObj(pConnInfo.LocalAddress.GetPort(), Process)
|
||||
return
|
||||
}
|
||||
// 如果连接是 IPv4 的,则将连接的远程地址改为本地 IPv4 地址,并保存到代理列表中
|
||||
_, i := pConnInfo.RemoteAddress.GetIP()
|
||||
Process := &ProcessInfo{Pid: strconv.Itoa(int(pConnInfo.ProcessId.Get())), RemoteAddress: i.String(), RemotePort: pConnInfo.RemoteAddress.GetPort(), Id: id}
|
||||
Lock.Lock()
|
||||
Proxy[pConnInfo.LocalAddress.GetPort()] = Process
|
||||
Lock.Unlock()
|
||||
ProcessCheck.AddDevObj(pConnInfo.LocalAddress.GetPort(), Process)
|
||||
pConnInfo.RemoteAddress.SetIP(true, net.ParseIP("127.0.0.1"))
|
||||
pConnInfo.RemoteAddress.SetPort(ProcessPortInt)
|
||||
return
|
||||
@@ -177,9 +165,7 @@ func tcpClosed(id uint64, pConnInfo *NF_TCP_CONN_INFO) {
|
||||
if pConnInfo == nil {
|
||||
return
|
||||
}
|
||||
Lock.Lock()
|
||||
delete(Proxy, pConnInfo.LocalAddress.GetPort())
|
||||
Lock.Unlock()
|
||||
ProcessCheck.DelDevObj(pConnInfo.LocalAddress.GetPort())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -220,18 +206,11 @@ func isEmpower(id uint64) (bool, SockaddrInx, uint32, NF_UDP_CONN_INFO) {
|
||||
|
||||
// 获取进程名,并检查是否在代理名单中
|
||||
_, _, ProcessName := Api.NfgetProcessNameA(pConnInfo.ProcessId.Get())
|
||||
Lock.Lock()
|
||||
if HookProcess == false {
|
||||
if Name[strings.ToLower(ProcessName)] == false {
|
||||
if Pid[pConnInfo.ProcessId.Get()] == false {
|
||||
Lock.Unlock()
|
||||
Api.NfTcpDisableFiltering(id)
|
||||
return false, pConnInfo.LocalAddress, pConnInfo.ProcessId.Get(), pConnInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
Lock.Unlock()
|
||||
|
||||
if ProcessCheck.CheckPidByName(int32(pConnInfo.ProcessId.Get()), ProcessName) {
|
||||
Api.NfTcpDisableFiltering(id)
|
||||
return false, pConnInfo.LocalAddress, pConnInfo.ProcessId.Get(), pConnInfo
|
||||
}
|
||||
// 如果有权限,则返回 true,并将本地地址和进程 ID 返回
|
||||
return true, pConnInfo.LocalAddress, pConnInfo.ProcessId.Get(), pConnInfo
|
||||
}
|
||||
@@ -245,21 +224,24 @@ func udpClosed(id uint64, pConnInfo *NF_UDP_CONN_INFO) {
|
||||
if pConnInfo == nil {
|
||||
return
|
||||
}
|
||||
tid := NfIdGetTid(id)
|
||||
if tid < 1 {
|
||||
mu.Lock()
|
||||
obj := list[id]
|
||||
mu.Unlock()
|
||||
if obj == nil {
|
||||
return
|
||||
}
|
||||
if UdpSendReceiveFunc != nil {
|
||||
o := NfTidGetObj(tid)
|
||||
if o != nil {
|
||||
UdpSendReceiveFunc(public.SunnyNetUDPTypeClosed, o.Theoni, pConnInfo.ProcessId.Get(), pConnInfo.LocalAddress.String(), o.Send.RemoteAddress.String(), nil)
|
||||
}
|
||||
UdpSendReceiveFunc(public.SunnyNetUDPTypeClosed, obj.Theoni, pConnInfo.ProcessId.Get(), pConnInfo.LocalAddress.String(), obj.Send.RemoteAddress.String(), nil)
|
||||
}
|
||||
NfDelTid(tid)
|
||||
mu.Lock()
|
||||
delete(list, id)
|
||||
mu.Unlock()
|
||||
SunnyNetUDP.DelUDPItem(obj.Theoni)
|
||||
return
|
||||
}
|
||||
|
||||
func udpReceive(id uint64, RemoteAddress *SockaddrInx, buf []byte, options *NF_UDP_OPTIONS) {
|
||||
|
||||
if RemoteAddress == nil {
|
||||
return
|
||||
}
|
||||
@@ -267,19 +249,20 @@ func udpReceive(id uint64, RemoteAddress *SockaddrInx, buf []byte, options *NF_U
|
||||
_, _ = Api.NfUdpPostReceive(id, RemoteAddress, buf, options)
|
||||
return
|
||||
}
|
||||
_, LocalAddress, Pid, pConnInfo := isEmpower(id)
|
||||
k := pConnInfo.LocalAddress.String() + RemoteAddress.String()
|
||||
o := UdpSenders.GetObj(k)
|
||||
if o == nil {
|
||||
_, LocalAddress, pid, _ := isEmpower(id)
|
||||
mu.Lock()
|
||||
obj := list[id]
|
||||
mu.Unlock()
|
||||
if obj == nil {
|
||||
_, _ = Api.NfUdpPostReceive(id, RemoteAddress, buf, options)
|
||||
return
|
||||
}
|
||||
UdpLock.Lock()
|
||||
if o.Receive == nil {
|
||||
o.Receive = &NfSend{Id: id, RemoteAddress: RemoteAddress.Clone(), options: options.Clone()}
|
||||
mu.Lock()
|
||||
if obj.Receive == nil {
|
||||
obj.Receive = &NfOPT{Id: id, RemoteAddress: RemoteAddress.Clone(), options: options.Clone()}
|
||||
}
|
||||
UdpLock.Unlock()
|
||||
bs := UdpSendReceiveFunc(public.SunnyNetUDPTypeReceive, o.Theoni, Pid, LocalAddress.String(), RemoteAddress.String(), buf)
|
||||
mu.Unlock()
|
||||
bs := UdpSendReceiveFunc(public.SunnyNetUDPTypeReceive, obj.Theoni, pid, LocalAddress.String(), RemoteAddress.String(), buf)
|
||||
if len(bs) > 0 {
|
||||
_, _ = Api.NfUdpPostReceive(id, RemoteAddress, bs, options)
|
||||
}
|
||||
@@ -292,46 +275,49 @@ func udpSend(id uint64, RemoteAddress *SockaddrInx, buf []byte, options *NF_UDP_
|
||||
return
|
||||
}
|
||||
if UdpSendReceiveFunc == nil || ProcessPortInt == 0 {
|
||||
Api.NfUdpPostSend(id, RemoteAddress, buf, options)
|
||||
_, _ = Api.NfUdpPostSend(id, RemoteAddress, buf, options)
|
||||
return
|
||||
}
|
||||
// 检查授权,并调用相应的 PID
|
||||
ok, LocalAddress, Pid, pConnInfo := isEmpower(id)
|
||||
ok, LocalAddress, pid, _ := isEmpower(id)
|
||||
if !ok {
|
||||
k := RemoteAddress.String() + pConnInfo.LocalAddress.String()
|
||||
o := UdpSenders.GetObj(k)
|
||||
if o == nil {
|
||||
Api.NfUdpPostSend(id, RemoteAddress, buf, options)
|
||||
mu.Lock()
|
||||
obj := list[id]
|
||||
mu.Unlock()
|
||||
if obj == nil {
|
||||
_, _ = Api.NfUdpPostSend(id, RemoteAddress, buf, options)
|
||||
return
|
||||
}
|
||||
UdpLock.Lock()
|
||||
if o.Receive == nil {
|
||||
o.Receive = &NfSend{Id: id, RemoteAddress: RemoteAddress.Clone(), options: options.Clone()}
|
||||
mu.Lock()
|
||||
if obj.Receive == nil {
|
||||
obj.Receive = &NfOPT{Id: id, RemoteAddress: RemoteAddress.Clone(), options: options.Clone()}
|
||||
}
|
||||
UdpLock.Unlock()
|
||||
mu.Unlock()
|
||||
//这里因为是接收 所以 RemoteAddress 是本地地址 而 LocalAddress 是远程地址
|
||||
bs := UdpSendReceiveFunc(public.SunnyNetUDPTypeReceive, o.Theoni, Pid, RemoteAddress.String(), LocalAddress.String(), buf)
|
||||
bs := UdpSendReceiveFunc(public.SunnyNetUDPTypeReceive, obj.Theoni, pid, RemoteAddress.String(), LocalAddress.String(), buf)
|
||||
if len(bs) > 0 {
|
||||
_, _ = Api.NfUdpPostSend(id, RemoteAddress, bs, options)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 生成唯一键值并获取连接
|
||||
k := LocalAddress.String() + RemoteAddress.String()
|
||||
o := UdpSenders.GetObj(k)
|
||||
mu.Lock()
|
||||
obj := list[id]
|
||||
mu.Unlock()
|
||||
// 如果连接不存在,则新建连接并添加到连接池中
|
||||
if o == nil {
|
||||
Tid := atomic.AddInt64(&public.Theology, 1)
|
||||
UdpSenders.Add(k, nil, Tid, &NfSend{Id: id, RemoteAddress: RemoteAddress.Clone(), options: options.Clone()}, nil, nil, nil, nil)
|
||||
NfAddTid(id, Tid, k)
|
||||
bs := UdpSendReceiveFunc(public.SunnyNetUDPTypeSend, Tid, Pid, LocalAddress.String(), RemoteAddress.String(), buf)
|
||||
if obj == nil {
|
||||
obj = &udpItem{Theoni: atomic.AddInt64(&public.Theology, 1)}
|
||||
obj.Send = &NfOPT{Id: id, RemoteAddress: RemoteAddress.Clone(), options: options.Clone()}
|
||||
SunnyNetUDP.AddUDPItem(obj.Theoni, obj)
|
||||
mu.Lock()
|
||||
list[id] = obj
|
||||
mu.Unlock()
|
||||
bs := UdpSendReceiveFunc(public.SunnyNetUDPTypeSend, obj.Theoni, pid, LocalAddress.String(), RemoteAddress.String(), buf)
|
||||
if len(bs) > 0 {
|
||||
_, _ = Api.NfUdpPostSend(id, RemoteAddress, bs, options)
|
||||
}
|
||||
} else {
|
||||
// 如果连接已建立,则发送数据
|
||||
bs := UdpSendReceiveFunc(public.SunnyNetUDPTypeSend, o.Theoni, Pid, LocalAddress.String(), RemoteAddress.String(), buf)
|
||||
bs := UdpSendReceiveFunc(public.SunnyNetUDPTypeSend, obj.Theoni, pid, LocalAddress.String(), RemoteAddress.String(), buf)
|
||||
if len(bs) > 0 {
|
||||
_, _ = Api.NfUdpPostSend(id, RemoteAddress, bs, options)
|
||||
}
|
||||
@@ -345,3 +331,5 @@ func udpCanReceive(id uint64) {
|
||||
func udpCanSend(id uint64) {
|
||||
return
|
||||
}
|
||||
|
||||
var UdpSendReceiveFunc func(Type int, Theoni int64, pid uint32, LocalAddress, RemoteAddress string, data []byte) []byte
|
||||
|
||||
@@ -16,22 +16,24 @@ import (
|
||||
|
||||
// 删除旧的驱动文件
|
||||
func deleteOldFiles() {
|
||||
OldFileName := System32Dir + "\\drivers\\SunnyFilter.sys"
|
||||
//复制到临时目录去系统重启后才可删除
|
||||
_ = MoveFileToTempDir(OldFileName, "Sunny_"+RandomLetters(32)+extensionsTemp)
|
||||
//删除临时目录下的所有sys 文件
|
||||
tempDir := os.TempDir()
|
||||
// 搜索所有 .sys 文件
|
||||
_ = filepath.Walk(tempDir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 检查文件是否是 .sys 文件
|
||||
if !info.IsDir() && filepath.Ext(path) == extensionsTemp {
|
||||
_ = os.Remove(path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
go func() {
|
||||
OldFileName := System32Dir + "\\drivers\\SunnyFilter.sys"
|
||||
//复制到临时目录去系统重启后才可删除
|
||||
_ = MoveFileToTempDir(OldFileName, "Sunny_"+RandomLetters(32)+extensionsTemp)
|
||||
//删除临时目录下的所有sys 文件
|
||||
tempDir := os.TempDir()
|
||||
// 搜索所有 .sys 文件
|
||||
_ = filepath.Walk(tempDir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 检查文件是否是 .sys 文件
|
||||
if !info.IsDir() && filepath.Ext(path) == extensionsTemp {
|
||||
_ = os.Remove(path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}()
|
||||
}
|
||||
func init() {
|
||||
deleteOldFiles()
|
||||
|
||||
@@ -1,271 +1,35 @@
|
||||
package NFapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// 定义 UdpConnectionManagement 结构体,用于管理 UDP 连接
|
||||
var UdpSenders UdpConnectionManagement
|
||||
var UdpLock sync.Mutex
|
||||
|
||||
type NfSend struct {
|
||||
type NfOPT struct {
|
||||
Id uint64
|
||||
RemoteAddress *SockaddrInx
|
||||
options *NF_UDP_OPTIONS
|
||||
}
|
||||
|
||||
// 实现 UdpConnectionManagement 结构体的 Add 方法,用于将 UDP 连接添加到连接池中,并返回添加的 UDP 选项
|
||||
func (p *UdpConnectionManagement) Add(key string, conn *net.UDPConn,
|
||||
Tid int64, Send *NfSend, receive *NfSend,
|
||||
ClientConn *net.UDPConn, ClientAddress *net.UDPAddr, ClientFrom []byte) {
|
||||
// 获取锁
|
||||
p.l.Lock()
|
||||
|
||||
// 如果连接池为空,则创建一个新的连接池
|
||||
if p.m == nil {
|
||||
p.m = make(map[string]*UdpConnection)
|
||||
}
|
||||
|
||||
// 将 UDP 连接添加到连接池中
|
||||
p.m[key] = &UdpConnection{Send: Send, Receive: receive, Theoni: Tid, Conn: conn, ClientConn: ClientConn, ClientAddress: ClientAddress, ClientFrom: ClientFrom}
|
||||
|
||||
// 释放锁并返回 UDP 选项
|
||||
p.l.Unlock()
|
||||
type udpItem struct {
|
||||
Receive *NfOPT
|
||||
Send *NfOPT
|
||||
Theoni int64
|
||||
}
|
||||
|
||||
// 实现 UdpConnectionManagement 结构体的 Del 方法,用于从连接池中移除指定的 UDP 连接
|
||||
func (p *UdpConnectionManagement) Del(key string) {
|
||||
// 获取锁
|
||||
p.l.Lock()
|
||||
// 如果连接池为空,则创建一个新的连接池
|
||||
if p.m == nil {
|
||||
p.m = make(map[string]*UdpConnection)
|
||||
}
|
||||
|
||||
// 从连接池中移除指定的 UDP 连接
|
||||
delete(p.m, key)
|
||||
|
||||
// 释放锁
|
||||
p.l.Unlock()
|
||||
}
|
||||
|
||||
// 实现 UdpConnectionManagement 结构体的 Get 方法,用于获取指定 UDP 连接的相关信息
|
||||
func (p *UdpConnectionManagement) Get(key string) (*net.UDPConn, int64) {
|
||||
// 获取锁
|
||||
p.l.Lock()
|
||||
// 如果连接池为空,则创建一个新的连接池
|
||||
if p.m == nil {
|
||||
p.m = make(map[string]*UdpConnection)
|
||||
}
|
||||
|
||||
// 获取指定的 UDP 连接
|
||||
u := p.m[key]
|
||||
|
||||
// 释放锁并返回 UDP 连接的相关信息
|
||||
p.l.Unlock()
|
||||
if u == nil {
|
||||
return nil, -1
|
||||
}
|
||||
return u.Conn, u.Theoni
|
||||
}
|
||||
|
||||
// 实现 UdpConnectionManagement 结构体的 GetObj 方法,用于获取指定 UDP 连接的 UdpConnection 结构体指针
|
||||
func (p *UdpConnectionManagement) GetObj(key string) *UdpConnection {
|
||||
// 获取锁
|
||||
p.l.Lock()
|
||||
// 如果连接池为空,则创建一个新的连接池
|
||||
if p.m == nil {
|
||||
p.m = make(map[string]*UdpConnection)
|
||||
}
|
||||
|
||||
// 获取指定的 UDP 连接的 UdpConnection 结构体指针
|
||||
u := p.m[key]
|
||||
|
||||
// 释放锁并返回 UdpConnection 结构体指针
|
||||
p.l.Unlock()
|
||||
return u
|
||||
}
|
||||
|
||||
// 定义 UdpConnectionManagement 结构体,用于管理 UDP 连接
|
||||
type UdpConnectionManagement struct {
|
||||
l sync.Mutex // 互斥锁,用于保护数据访问
|
||||
m map[string]*UdpConnection // 用于存储 UDP 连接的 map,key 为 Local + Remote,value 为 udpConnection 结构体指针
|
||||
}
|
||||
|
||||
// 定义 udpConnection 结构体,用于表示 UDP 连接
|
||||
type UdpConnection struct {
|
||||
Theoni int64 // 用于存储 唯一ID
|
||||
Conn *net.UDPConn // 用于存储服务器端的 UDP 连接
|
||||
Send *NfSend // 用于存储 UDP 发送选项 【NF驱动使用】
|
||||
Receive *NfSend // 用于存储 UDP 接收选项 【NF驱动使用】
|
||||
ClientConn *net.UDPConn // 用于存储客户端的 UDP 连接 【非驱动使用】
|
||||
ClientAddress *net.UDPAddr // 用于存储客户端地址 【非驱动使用】
|
||||
ClientFrom []byte // 用于存储客户端的来源信息 【非驱动使用】
|
||||
}
|
||||
|
||||
// 实现 udpConnection 结构体的 SendServer 方法,用于向服务器发送数据并返回发送结果
|
||||
func (p *UdpConnection) SendServer(data []byte) bool {
|
||||
if len(data) == 0 {
|
||||
return true
|
||||
}
|
||||
if p == nil {
|
||||
return false
|
||||
}
|
||||
if p.Send != nil {
|
||||
r, _ := NFapi_Api_NfUdpPostSend(p.Send.Id, p.Send.RemoteAddress, data, p.Send.options)
|
||||
func (u udpItem) ToClient(data []byte) bool {
|
||||
if u.Receive != nil {
|
||||
r, _ := Api.NfUdpPostReceive(u.Receive.Id, u.Receive.RemoteAddress, data, u.Receive.options)
|
||||
return r == 0
|
||||
}
|
||||
if p.Conn == nil {
|
||||
return false
|
||||
}
|
||||
_, er := p.Conn.Write(data)
|
||||
return er == nil
|
||||
return false
|
||||
}
|
||||
|
||||
// 实现 udpConnection 结构体的 SendClient 方法,用于向客户端发送数据并返回发送结果
|
||||
func (p *UdpConnection) SendClient(data []byte) bool {
|
||||
if len(data) == 0 {
|
||||
return true
|
||||
}
|
||||
if p == nil {
|
||||
return false
|
||||
}
|
||||
if p.Receive != nil {
|
||||
r, _ := NFapi_Api_NfUdpPostSend(p.Receive.Id, p.Receive.RemoteAddress, data, p.Receive.options)
|
||||
func (u udpItem) ToServer(data []byte) bool {
|
||||
if u.Send != nil {
|
||||
r, _ := Api.NfUdpPostSend(u.Send.Id, u.Send.RemoteAddress, data, u.Send.options)
|
||||
return r == 0
|
||||
}
|
||||
if p.ClientAddress != nil && p.ClientConn != nil {
|
||||
var bs []byte
|
||||
bs = append(bs, p.ClientFrom...)
|
||||
bs = append(bs, data...)
|
||||
_, er := p.ClientConn.WriteToUDP(data, p.ClientAddress)
|
||||
return er == nil
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 创建一个 int 类型到 *bytes.Buffer 映射的 map
|
||||
var UdpMap = make(map[int]*bytes.Buffer)
|
||||
|
||||
// 创建一个互斥锁
|
||||
var UdpSync sync.Mutex
|
||||
|
||||
// 创建一个 int64 类型到 string 映射的 map
|
||||
var UdpTidMap = make(map[int64]string)
|
||||
|
||||
// ID 映射 唯一ID
|
||||
var UdpIdTid = make(map[uint64]int64)
|
||||
|
||||
// 向服务器发送数据,返回是否发送成功
|
||||
func UdpSendToServer(tid int64, data []byte) bool {
|
||||
if len(data) < 1 {
|
||||
return false
|
||||
}
|
||||
// 获取锁
|
||||
UdpSync.Lock()
|
||||
// 获取指定 tid 对应的 key
|
||||
key := UdpTidMap[tid]
|
||||
|
||||
// 如果 key 不为空,则获取对应的 sender 并发送数据,最后释放锁并返回发送结果
|
||||
if key != "" {
|
||||
o := UdpSenders.GetObj(key)
|
||||
if o != nil {
|
||||
UdpSync.Unlock()
|
||||
return o.SendServer(data)
|
||||
}
|
||||
}
|
||||
// 如果发送失败,则释放锁并返回 false
|
||||
UdpSync.Unlock()
|
||||
return false
|
||||
}
|
||||
|
||||
// 向客户端发送数据,返回是否发送成功
|
||||
func UdpSendToClient(tid int64, data []byte) bool {
|
||||
if len(data) < 1 {
|
||||
return false
|
||||
}
|
||||
// 获取锁
|
||||
UdpSync.Lock()
|
||||
// 获取指定 tid 对应的 key
|
||||
key := UdpTidMap[tid]
|
||||
|
||||
// 如果 key 不为空,则获取对应的 sender 并发送数据,最后释放锁并返回发送结果
|
||||
if key != "" {
|
||||
o := UdpSenders.GetObj(key)
|
||||
if o != nil {
|
||||
UdpSync.Unlock()
|
||||
return o.SendClient(data)
|
||||
}
|
||||
}
|
||||
|
||||
// 如果发送失败,则释放锁并返回 false
|
||||
UdpSync.Unlock()
|
||||
return false
|
||||
}
|
||||
|
||||
// 删除指定 tid 对应的 key,并从 UdpTidMap 中删除该 tid
|
||||
func NfDelTid(tid int64) {
|
||||
// 获取锁
|
||||
UdpSync.Lock()
|
||||
// 获取指定 tid 对应的 key
|
||||
key := UdpTidMap[tid]
|
||||
// 如果 key 不为空,则删除 key 对应的 sender,并从 UdpTidMap 中删除该 tid
|
||||
if key != "" {
|
||||
o := UdpSenders.GetObj(key)
|
||||
if o != nil {
|
||||
if o.Send != nil {
|
||||
delete(UdpIdTid, o.Send.Id)
|
||||
}
|
||||
if o.Receive != nil {
|
||||
delete(UdpIdTid, o.Receive.Id)
|
||||
}
|
||||
}
|
||||
UdpSenders.Del(key)
|
||||
delete(UdpTidMap, tid)
|
||||
}
|
||||
// 释放锁
|
||||
UdpSync.Unlock()
|
||||
}
|
||||
|
||||
// 将指定 tid 和 key 存储到 UdpTidMap 中
|
||||
func NfAddTid(id uint64, tid int64, key string) {
|
||||
// 获取锁
|
||||
UdpSync.Lock()
|
||||
// 将指定 tid 和 key 存储到 UdpTidMap 中
|
||||
UdpTidMap[tid] = key
|
||||
if id > 0 {
|
||||
UdpIdTid[id] = tid
|
||||
}
|
||||
// 释放锁
|
||||
UdpSync.Unlock()
|
||||
}
|
||||
|
||||
// 将指定 NFid 取唯一ID
|
||||
func NfIdGetTid(id uint64) int64 {
|
||||
// 获取锁
|
||||
UdpSync.Lock()
|
||||
//获取Tid(唯一ID)
|
||||
tid := UdpIdTid[id]
|
||||
// 释放锁
|
||||
UdpSync.Unlock()
|
||||
return tid
|
||||
}
|
||||
|
||||
// 将指定 唯一ID 获取 UDP对象
|
||||
func NfTidGetObj(tid int64) *UdpConnection {
|
||||
// 获取锁
|
||||
UdpSync.Lock()
|
||||
key := UdpTidMap[tid]
|
||||
if key != "" {
|
||||
o := UdpSenders.GetObj(key)
|
||||
if o != nil {
|
||||
UdpSync.Unlock()
|
||||
return o
|
||||
}
|
||||
}
|
||||
// 释放锁
|
||||
UdpSync.Unlock()
|
||||
return nil
|
||||
}
|
||||
var mu sync.Mutex
|
||||
var list = make(map[uint64]*udpItem)
|
||||
|
||||
@@ -97,8 +97,9 @@ func (p *ProcessInfo) IsV6() bool {
|
||||
func (p *ProcessInfo) ID() uint64 {
|
||||
return p.Id
|
||||
}
|
||||
func (p *ProcessInfo) Close() {
|
||||
func (p *ProcessInfo) Close() error {
|
||||
_, _ = Api.NfTcpClose(p.Id)
|
||||
return nil
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
15
src/ProcessDrv/tun/Tun/all.go
Normal file
15
src/ProcessDrv/tun/Tun/all.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package Tun
|
||||
|
||||
import (
|
||||
n2 "net"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
SetOutRouterIP(RouterIP string) bool
|
||||
Port() int
|
||||
}
|
||||
type UdpFunc func(Type int, Theoni int64, pid uint32, LocalAddress string, RemoteAddress string, data []byte) []byte
|
||||
type TcpFunc func(conn n2.Conn)
|
||||
|
||||
var _myPid = int32(os.Getpid())
|
||||
35
src/ProcessDrv/tun/Tun/android.go
Normal file
35
src/ProcessDrv/tun/Tun/android.go
Normal file
@@ -0,0 +1,35 @@
|
||||
//go:build android
|
||||
// +build android
|
||||
|
||||
package Tun
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
var defaultGatewayIP, defaultGatewayIf = "", ""
|
||||
|
||||
func (n *NewTun) OnTunCreated(fd int) {
|
||||
tun := os.NewFile(uintptr(fd), "tun0")
|
||||
defer func() {
|
||||
_ = tun.Close()
|
||||
}()
|
||||
n.tun = tun
|
||||
buf := make([]byte, 65535)
|
||||
for {
|
||||
nBytes, err := tun.Read(buf)
|
||||
if err != nil || !n.IsRunning {
|
||||
_ = tun.Close()
|
||||
break
|
||||
}
|
||||
var packet []byte
|
||||
packet = append(packet, buf[:nBytes]...)
|
||||
go func() {
|
||||
// 解析包(判断方向、类型)
|
||||
n.parsePacket(packet)
|
||||
}()
|
||||
}
|
||||
}
|
||||
func getPidByPort(kind string, port uint16) (int32, string) {
|
||||
return 0, ""
|
||||
}
|
||||
231
src/ProcessDrv/tun/Tun/conn.go
Normal file
231
src/ProcessDrv/tun/Tun/conn.go
Normal file
@@ -0,0 +1,231 @@
|
||||
//go:build android || darwin || linux
|
||||
// +build android darwin linux
|
||||
|
||||
package Tun
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DevConn struct {
|
||||
// 标识:客户端和伪服务端的四元组
|
||||
clientIP net.IP
|
||||
clientPort uint16
|
||||
serverIP net.IP
|
||||
serverPort uint16
|
||||
|
||||
// TCP 序列号跟踪
|
||||
clientNext uint32 // 客户端下一个期望的 seq
|
||||
serverISN uint32 // 我们伪造的 server 初始序列号
|
||||
serverSeqNext uint32 // 我们发送给客户端时的 seq
|
||||
|
||||
// 缓存和同步
|
||||
buff bytes.Buffer
|
||||
mu sync.Mutex
|
||||
closed bool
|
||||
// 通知 channel:避免每次等待都 spawn goroutine
|
||||
dataCh chan struct{}
|
||||
// deadline
|
||||
_outRead time.Time
|
||||
_outWrite time.Time
|
||||
// 记录已发 ack
|
||||
highestClientAckSent uint32
|
||||
tun io.ReadWriteCloser
|
||||
v4 bool
|
||||
pid uint32
|
||||
}
|
||||
|
||||
func (d *DevConn) GetRemoteAddress() string {
|
||||
return net.JoinHostPort(d.serverIP.String(), strconv.Itoa(int(d.serverPort)))
|
||||
}
|
||||
|
||||
func (d *DevConn) GetRemotePort() uint16 {
|
||||
return d.serverPort
|
||||
}
|
||||
|
||||
func (d *DevConn) GetPid() string {
|
||||
return strconv.Itoa(int(d.pid))
|
||||
}
|
||||
|
||||
func (d *DevConn) IsV6() bool {
|
||||
return !d.v4
|
||||
}
|
||||
|
||||
func (d *DevConn) ID() uint64 {
|
||||
return uint64(d.clientPort)
|
||||
}
|
||||
|
||||
// 构造函数
|
||||
func NewDevConn(h io.ReadWriteCloser, clientIP net.IP, clientPort uint16, serverIP net.IP, serverPort uint16, ipv4 bool, seq, ack uint32) *DevConn {
|
||||
d := &DevConn{
|
||||
clientIP: clientIP,
|
||||
clientPort: clientPort,
|
||||
serverIP: serverIP,
|
||||
serverPort: serverPort,
|
||||
dataCh: make(chan struct{}, 1),
|
||||
v4: ipv4,
|
||||
serverSeqNext: seq,
|
||||
clientNext: ack,
|
||||
tun: h,
|
||||
}
|
||||
d.serverISN = rand.Uint32()
|
||||
d.serverSeqNext = d.serverISN + 1
|
||||
return d
|
||||
}
|
||||
|
||||
// --- net.Conn 接口实现 ---
|
||||
|
||||
// Read 从缓冲区读取客户端发来的数据
|
||||
func (d *DevConn) Read(b []byte) (int, error) {
|
||||
a1, a2 := d.read(b)
|
||||
return a1, a2
|
||||
}
|
||||
|
||||
// Read 从缓冲区读取客户端发来的数据(使用 dataCh 通知,避免额外 goroutine)
|
||||
func (d *DevConn) read(b []byte) (int, error) {
|
||||
for {
|
||||
d.mu.Lock()
|
||||
if d.buff.Len() > 0 {
|
||||
n, _ := d.buff.Read(b)
|
||||
d.mu.Unlock()
|
||||
return n, nil
|
||||
}
|
||||
if d.closed {
|
||||
d.mu.Unlock()
|
||||
return 0, io.EOF
|
||||
}
|
||||
// 拿出 deadline 本地变量,避免在 select 中访问共享状态
|
||||
deadline := d._outRead
|
||||
d.mu.Unlock()
|
||||
|
||||
if deadline.IsZero() {
|
||||
// 阻塞等待通知
|
||||
<-d.dataCh
|
||||
// loop to check buffer
|
||||
continue
|
||||
}
|
||||
|
||||
// 有 deadline,则等待 dataCh 或超时
|
||||
now := time.Now()
|
||||
if !deadline.After(now) {
|
||||
return 0, os.ErrDeadlineExceeded
|
||||
}
|
||||
timer := time.NewTimer(time.Until(deadline))
|
||||
select {
|
||||
case <-d.dataCh:
|
||||
if !timer.Stop() {
|
||||
<-timer.C
|
||||
}
|
||||
// loop to read
|
||||
case <-timer.C:
|
||||
return 0, os.ErrDeadlineExceeded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write 将数据发回客户端(通过 WinDivert 注入包)
|
||||
func (d *DevConn) Write(b []byte) (int, error) {
|
||||
// 写超时检查
|
||||
if !d._outWrite.IsZero() && time.Now().After(d._outWrite) {
|
||||
return 0, os.ErrDeadlineExceeded
|
||||
}
|
||||
return SendDataToClient(d, b)
|
||||
}
|
||||
|
||||
// Close 关闭连接:注入 FIN 并清理
|
||||
func (d *DevConn) Close() error {
|
||||
d.mu.Lock()
|
||||
already := d.closed
|
||||
d.closed = true
|
||||
// signal readers (non-blocking send to channel)
|
||||
select {
|
||||
case d.dataCh <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
d.mu.Unlock()
|
||||
if already {
|
||||
return nil
|
||||
}
|
||||
_, _ = d.tun.Write(SendFinToClient(d))
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoteAddr 返回真实的 server 地址
|
||||
func (d *DevConn) RemoteAddr() net.Addr {
|
||||
return &net.TCPAddr{
|
||||
IP: d.serverIP,
|
||||
Port: int(d.serverPort),
|
||||
}
|
||||
}
|
||||
|
||||
// LocalAddr 返回伪造的 client 地址
|
||||
func (d *DevConn) LocalAddr() net.Addr {
|
||||
return &net.TCPAddr{
|
||||
IP: d.clientIP,
|
||||
Port: int(d.clientPort),
|
||||
}
|
||||
}
|
||||
|
||||
// SetDeadline 同时设置读写超时
|
||||
func (d *DevConn) SetDeadline(t time.Time) error {
|
||||
_ = d.SetReadDeadline(t)
|
||||
_ = d.SetWriteDeadline(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetReadDeadline 设置读超时
|
||||
func (d *DevConn) SetReadDeadline(t time.Time) error {
|
||||
d.mu.Lock()
|
||||
d._outRead = t
|
||||
d.mu.Unlock()
|
||||
select {
|
||||
case d.dataCh <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetWriteDeadline 设置写超时
|
||||
func (d *DevConn) SetWriteDeadline(t time.Time) error {
|
||||
d.mu.Lock()
|
||||
d._outWrite = t
|
||||
d.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DevConn) PushClientPayload(payload []byte, seq uint32) {
|
||||
if seq != d.clientNext {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
d.mu.Lock()
|
||||
clientNext := d.clientNext
|
||||
d.mu.Unlock()
|
||||
if clientNext != 0 {
|
||||
_, _ = d.tun.Write(SendAckToKernel(d, clientNext))
|
||||
}
|
||||
}()
|
||||
if len(payload) == 0 {
|
||||
// 仍更新 seq
|
||||
d.mu.Lock()
|
||||
d.clientNext = seq + uint32(len(payload))
|
||||
d.mu.Unlock()
|
||||
return
|
||||
}
|
||||
d.mu.Lock()
|
||||
d.buff.Write(payload)
|
||||
d.clientNext = seq + uint32(len(payload))
|
||||
// 非阻塞通知
|
||||
select {
|
||||
case d.dataCh <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
d.mu.Unlock()
|
||||
}
|
||||
243
src/ProcessDrv/tun/Tun/darwin.go
Normal file
243
src/ProcessDrv/tun/Tun/darwin.go
Normal file
@@ -0,0 +1,243 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package Tun
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/tun/tunPublic"
|
||||
CrossCompiled "github.com/qtgolang/SunnyNet/src/iphlpapi/net"
|
||||
"github.com/shirou/gopsutil/process"
|
||||
"github.com/songgao/water" // TUN 设备
|
||||
)
|
||||
|
||||
// 判断是否是 IPv4
|
||||
func isIPv4(ip net.IP) bool {
|
||||
return ip.To4() != nil
|
||||
}
|
||||
|
||||
// 判断是否是 IPv6
|
||||
func isIPv6(ip net.IP) bool {
|
||||
return ip.To16() != nil && ip.To4() == nil
|
||||
}
|
||||
|
||||
// OpenTunDevice 创建并配置 TUN 设备
|
||||
func OpenTunDevice(name, addr, gw, mask string) (io.ReadWriteCloser, error) {
|
||||
tunDev, err := water.New(water.Config{DeviceType: water.TUN})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
name = tunDev.Name()
|
||||
ip := net.ParseIP(addr)
|
||||
if ip == nil {
|
||||
return nil, errors.New("无效的 IP 地址")
|
||||
}
|
||||
var params string
|
||||
if isIPv4(ip) {
|
||||
params = fmt.Sprintf("%s inet %s netmask %s %s", name, addr, mask, gw)
|
||||
} else if isIPv6(ip) {
|
||||
prefixlen, err := strconv.Atoi(mask)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解析 IPv6 前缀长度失败: %v", err)
|
||||
}
|
||||
params = fmt.Sprintf("%s inet6 %s/%d", name, addr, prefixlen)
|
||||
} else {
|
||||
return nil, errors.New("未知 IP 类型")
|
||||
}
|
||||
out, err := exec.Command("ifconfig", strings.Split(params, " ")...).CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("配置 IP 失败: %v, 输出: %s", err, string(out))
|
||||
}
|
||||
if gw != "" && isIPv4(ip) {
|
||||
routeOut, routeErr := exec.Command("route", "add", "default", gw).CombinedOutput()
|
||||
if routeErr != nil {
|
||||
return nil, fmt.Errorf("添加路由失败: %v, 输出: %s", routeErr, string(routeOut))
|
||||
}
|
||||
}
|
||||
return tunDev, nil
|
||||
}
|
||||
|
||||
var (
|
||||
defaultGatewayIP, defaultGatewayIf, ifaceName = tunPublic.GetGatewayByDefault() // 获取默认网关IP与网卡
|
||||
watchdogStarted bool // Watchdog 是否已经启动
|
||||
watchdogPid int // Watchdog 脚本进程 PID
|
||||
)
|
||||
|
||||
// startWatchdog 启动路由恢复监控脚本,防止主进程异常退出,导致系统无网络
|
||||
func startWatchdog() {
|
||||
// 如果 Watchdog 已经启动,则不重复启动
|
||||
if watchdogStarted {
|
||||
return
|
||||
}
|
||||
// 标记 Watchdog 已启动
|
||||
watchdogStarted = true
|
||||
// 将 shell 脚本内容写入 /usr/local/bin/SunnyTunCancel.sh 并赋予执行权限
|
||||
_ = os.Remove("/usr/local/bin/SunnyTunCancel.sh")
|
||||
_ = os.WriteFile("/usr/local/bin/SunnyTunCancel.sh", []byte(sh1), 0777)
|
||||
// 启动一个后台 goroutine 持续监控
|
||||
go func() {
|
||||
// 获取当前主进程 PID(用于传给监控脚本)
|
||||
mainPid := os.Getpid()
|
||||
for {
|
||||
if watchdogPid > 0 {
|
||||
if syscall.Kill(watchdogPid, 0) == nil {
|
||||
// 如果进程存在,则等待 1 秒后继续检查
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
// 启动监控脚本,脚本内部会监听主进程退出事件,并恢复默认路由
|
||||
cmd := exec.Command("/bin/sh", "/usr/local/bin/SunnyTunCancel.sh", fmt.Sprintf("%d", mainPid), defaultGatewayIf, ifaceName)
|
||||
// 将脚本输出重定向到黑洞(不输出到控制台)
|
||||
var buffer bytes.Buffer
|
||||
cmd.Stdout = &buffer
|
||||
cmd.Stderr = io.Discard
|
||||
// 启动脚本进程
|
||||
if err := cmd.Start(); err != nil {
|
||||
// 如果启动失败,将 PID 设为 0,下次循环会重试
|
||||
watchdogPid = 0
|
||||
} else {
|
||||
_ = cmd.Wait()
|
||||
watchdogPid, _ = strconv.Atoi(strings.TrimSpace(buffer.String()))
|
||||
}
|
||||
// 每 1 秒检查一次脚本状态
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
var _gw = 10
|
||||
|
||||
// OnTunCreated 当 TUN 设备创建时执行
|
||||
func (n *NewTun) OnTunCreated(_ int) bool {
|
||||
// 如果 TUN 已经在运行,则直接返回 true,避免重复启动
|
||||
if n.IsRunning {
|
||||
return true
|
||||
}
|
||||
// 先标记为未运行状态
|
||||
n.IsRunning = false
|
||||
// 如果默认网关、网关 IP 或 Sunny 对象为空,说明环境异常,直接返回
|
||||
if defaultGatewayIf == "" || defaultGatewayIP == "" || n.Sunny == nil {
|
||||
return n.IsRunning
|
||||
}
|
||||
_gw++
|
||||
if _gw > 200 {
|
||||
_gw = 10
|
||||
}
|
||||
// TUN 虚拟网关 IP 地址(模拟出口)
|
||||
gw := fmt.Sprintf("1.2.3.%d", _gw)
|
||||
// 创建 TUN 设备,指定本地 IP、网关 IP 和掩码
|
||||
tun, err := OpenTunDevice("", "1.2.3.1", gw, "255.255.255.0")
|
||||
if err != nil {
|
||||
// 创建失败,返回 false
|
||||
return n.IsRunning
|
||||
}
|
||||
// 保存 TUN 设备对象
|
||||
n.tun = tun
|
||||
// 分配一个 64KB 缓冲区用于读取 TUN 数据
|
||||
buf := make([]byte, 65535)
|
||||
// 再次赋值 TUN 对象(重复赋值,这里保留原逻辑)
|
||||
n.tun = tun
|
||||
// 设置 Sunny 的出口 IP 地址为原默认网关 IP
|
||||
if !n.Sunny.SetOutRouterIP(defaultGatewayIP) {
|
||||
// 如果设置失败,关闭 TUN 设备
|
||||
_ = tun.Close()
|
||||
return n.IsRunning
|
||||
}
|
||||
// 标记 TUN 已经成功运行
|
||||
n.IsRunning = true
|
||||
// 修改系统默认路由为 TUN 网关
|
||||
_, _ = exec.Command("sudo", "route", "delete", "default").CombinedOutput()
|
||||
_, _ = exec.Command("sudo", "route", "add", "default", gw).CombinedOutput()
|
||||
_, _ = exec.Command("sudo", "route", "-n", "add", "-inet", "default", "-ifscope", ifaceName, defaultGatewayIf).CombinedOutput()
|
||||
// 启动 watchdog,用于在进程退出时恢复默认路由
|
||||
startWatchdog()
|
||||
// 启动后台 goroutine,持续读取 TUN 数据包
|
||||
go func() {
|
||||
// 退出时恢复系统默认路由
|
||||
defer func() {
|
||||
if defaultGatewayIf != "" {
|
||||
_, _ = exec.Command("sudo", "route", "delete", "default").CombinedOutput()
|
||||
_, _ = exec.Command("sudo", "route", "-n", "delete", "-inet", "default", "-ifscope", ifaceName).CombinedOutput()
|
||||
_, _ = exec.Command("sudo", "route", "add", "default", defaultGatewayIf).CombinedOutput()
|
||||
}
|
||||
_ = tun.Close()
|
||||
}()
|
||||
for {
|
||||
// 从 TUN 设备读取数据
|
||||
nBytes, er := tun.Read(buf)
|
||||
// 如果 TUN 已经标记为未运行,退出循环
|
||||
if !n.IsRunning {
|
||||
return
|
||||
}
|
||||
// 如果读取出错或长度为 0,则稍等后重试
|
||||
if er != nil || nBytes <= 0 {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
// 将读取到的数据拷贝到新切片中
|
||||
var packet []byte
|
||||
packet = append(packet, buf[:nBytes]...)
|
||||
// 异步调用解析函数处理数据包
|
||||
go func() {
|
||||
n.parsePacket(packet)
|
||||
}()
|
||||
}
|
||||
}()
|
||||
// 返回当前运行状态
|
||||
return n.IsRunning
|
||||
}
|
||||
|
||||
type expiry struct {
|
||||
pid int32
|
||||
name string
|
||||
expiry time.Time
|
||||
}
|
||||
|
||||
var (
|
||||
pidCache = make(map[uint16]expiry)
|
||||
pidCacheMu sync.RWMutex
|
||||
pidTTL = 3 * time.Second
|
||||
pidExpiry = make(map[uint16]time.Time)
|
||||
)
|
||||
|
||||
func getPidByPort(kind string, port uint16) (int32, string) {
|
||||
pidCacheMu.Lock()
|
||||
defer pidCacheMu.Unlock()
|
||||
for k, _ := range pidCache {
|
||||
if !time.Now().Before(pidExpiry[k]) {
|
||||
delete(pidExpiry, k)
|
||||
delete(pidCache, k)
|
||||
}
|
||||
}
|
||||
if obj, ok := pidCache[port]; ok && time.Now().Before(pidExpiry[port]) {
|
||||
return obj.pid, obj.name
|
||||
}
|
||||
all, _ := CrossCompiled.Connections(kind)
|
||||
for _, conn := range all {
|
||||
if conn.Laddr.Port == uint32(port) {
|
||||
pid := conn.Pid
|
||||
p, _ := process.NewProcess(pid)
|
||||
ch := expiry{pid: pid}
|
||||
if p != nil {
|
||||
ch.name, _ = p.Name()
|
||||
}
|
||||
pidCache[port] = ch
|
||||
pidExpiry[port] = time.Now().Add(pidTTL)
|
||||
return ch.pid, ch.name
|
||||
}
|
||||
}
|
||||
return 0, ""
|
||||
}
|
||||
132
src/ProcessDrv/tun/Tun/darwin_sh.go
Normal file
132
src/ProcessDrv/tun/Tun/darwin_sh.go
Normal file
@@ -0,0 +1,132 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package Tun
|
||||
|
||||
// sh1 是恢复默认网关的方式,较快,稳定性未知
|
||||
const sh1 = `
|
||||
#!/bin/bash
|
||||
|
||||
# ==============================
|
||||
# 🛠 SunnyTunCancel.sh
|
||||
# 功能:后台监控目标进程,当进程退出时自动恢复默认网关
|
||||
# ==============================
|
||||
|
||||
# ----------------------------------
|
||||
# 🌀 如果当前脚本未被后台化,则重新后台运行自己,避免被主进程信号杀掉
|
||||
# ----------------------------------
|
||||
if [ -z "$DISOWNED" ]; then
|
||||
export DISOWNED=1 # 标记为已后台化,防止递归
|
||||
nohup "$0" "$@" >/dev/null 2>&1 & # 重新启动自己并脱离主进程
|
||||
echo $! # 重点:输出后台进程 PID
|
||||
exit 0 # 退出当前这份脚本
|
||||
fi
|
||||
|
||||
# ----------------------------------
|
||||
# 📌 获取目标 PID
|
||||
# ----------------------------------
|
||||
TARGET_PID=$1
|
||||
ORIGINAL_GW=$2
|
||||
ORIGINAL_Name=$3
|
||||
if [ -z "$TARGET_PID" ]; then
|
||||
echo "❌ 请传入一个 PID"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ----------------------------------
|
||||
# 🔐 检查是否拥有 ROOT 权限
|
||||
# ----------------------------------
|
||||
if [ "$EUID" -eq 0 ]; then
|
||||
echo "✅ 当前脚本以 ROOT 权限运行 (EUID=0)"
|
||||
else
|
||||
echo "❌ 当前脚本没有 ROOT 权限 (EUID=$EUID)"
|
||||
fi
|
||||
|
||||
# ----------------------------------
|
||||
# 👀 循环检测目标进程是否仍然存在
|
||||
# kill -0 不发送实际信号,只用于判断进程是否存在
|
||||
# ----------------------------------
|
||||
echo "🕓 正在监控进程 PID: $TARGET_PID"
|
||||
while kill -0 "$TARGET_PID" 2>/dev/null; do
|
||||
sleep 1
|
||||
done
|
||||
sudo route delete default
|
||||
sudo route -n delete -inet default -ifscope $ORIGINAL_Name
|
||||
sudo route add default $ORIGINAL_GW
|
||||
`
|
||||
|
||||
// sh2 是重启网卡的方式,较慢,稳定性应该姣好,先用sh1,这个也先保留
|
||||
const sh2 = `
|
||||
#!/bin/bash
|
||||
|
||||
# ==============================
|
||||
# 🛠 SunnyTunCancel.sh
|
||||
# 功能:后台监控目标进程,当进程退出时自动重启所有物理网卡
|
||||
# ==============================
|
||||
|
||||
# ----------------------------------
|
||||
# 🌀 如果当前脚本未被后台化,则重新后台运行自己,避免被主进程信号杀掉
|
||||
# ----------------------------------
|
||||
if [ -z "$DISOWNED" ]; then
|
||||
export DISOWNED=1 # 标记为已后台化,防止递归
|
||||
nohup "$0" "$@" >/dev/null 2>&1 & # 重新启动自己并脱离主进程
|
||||
echo $! # 重点:输出后台进程 PID
|
||||
exit 0 # 退出当前这份脚本
|
||||
fi
|
||||
|
||||
# ----------------------------------
|
||||
# 📌 获取目标 PID
|
||||
# ----------------------------------
|
||||
TARGET_PID=$1
|
||||
if [ -z "$TARGET_PID" ]; then
|
||||
echo "❌ 请传入一个 PID"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ----------------------------------
|
||||
# 🔐 检查是否拥有 ROOT 权限
|
||||
# ----------------------------------
|
||||
if [ "$EUID" -eq 0 ]; then
|
||||
echo "✅ 当前脚本以 ROOT 权限运行 (EUID=0)"
|
||||
else
|
||||
echo "❌ 当前脚本没有 ROOT 权限 (EUID=$EUID)"
|
||||
fi
|
||||
|
||||
# ----------------------------------
|
||||
# 👀 循环检测目标进程是否仍然存在
|
||||
# kill -0 不发送实际信号,只用于判断进程是否存在
|
||||
# ----------------------------------
|
||||
echo "🕓 正在监控进程 PID: $TARGET_PID"
|
||||
while kill -0 "$TARGET_PID" 2>/dev/null; do
|
||||
sleep 1
|
||||
done
|
||||
echo "⚠️ 进程 $TARGET_PID 已退出,开始重启所有网卡..."
|
||||
|
||||
# ----------------------------------
|
||||
# 🌐 获取所有网卡,排除 lo0 和 utun 接口
|
||||
# ----------------------------------
|
||||
interfaces=$(ifconfig -l | tr ' ' '\n' | grep -vE '^lo0$' | grep -vE '^utun')
|
||||
|
||||
if [ -z "$interfaces" ]; then
|
||||
echo "❌ 未检测到可重启的物理网卡"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "🔍 检测到网卡: $interfaces"
|
||||
|
||||
# ----------------------------------
|
||||
# 🔁 依次重启所有网卡
|
||||
# ----------------------------------
|
||||
for iface in $interfaces; do
|
||||
echo "🚧 正在重启网卡: $iface"
|
||||
ifconfig "$iface" down >/dev/null 2>&1
|
||||
sleep 1
|
||||
ifconfig "$iface" up >/dev/null 2>&1
|
||||
echo "✅ $iface 已重启"
|
||||
done
|
||||
|
||||
# ----------------------------------
|
||||
# 🏁 结束
|
||||
# ----------------------------------
|
||||
echo "🎉 所有物理网卡重启完成"
|
||||
`
|
||||
146
src/ProcessDrv/tun/Tun/linux.go
Normal file
146
src/ProcessDrv/tun/Tun/linux.go
Normal file
@@ -0,0 +1,146 @@
|
||||
//go:build linux && !android
|
||||
// +build linux,!android
|
||||
|
||||
package Tun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/tun/tunPublic"
|
||||
CrossCompiled "github.com/qtgolang/SunnyNet/src/iphlpapi/net"
|
||||
"github.com/shirou/gopsutil/process"
|
||||
"github.com/songgao/water" // TUN 设备
|
||||
)
|
||||
|
||||
var defaultGatewayIP, defaultGatewayIf, ifaceName = tunPublic.GetGatewayByDefault()
|
||||
|
||||
// OpenTunDevice 创建并配置 TUN 设备
|
||||
func OpenTunDevice(addr string) (io.ReadWriteCloser, string, error) {
|
||||
// 创建 TUN 设备
|
||||
tunDev, err := water.New(water.Config{DeviceType: water.TUN})
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
name := tunDev.Name()
|
||||
// 配置 TUN 本地 IP 地址
|
||||
cmd := exec.Command("ip", "addr", "add", addr+"/24", "dev", name)
|
||||
if out, er := cmd.CombinedOutput(); er != nil {
|
||||
fmt.Println("❌ 配置 IP 失败:", string(out), er)
|
||||
_ = tunDev.Close()
|
||||
return nil, name, er
|
||||
}
|
||||
|
||||
// 启用 TUN 设备
|
||||
cmd = exec.Command("ip", "link", "set", "dev", name, "up")
|
||||
if out, er := cmd.CombinedOutput(); er != nil {
|
||||
fmt.Println("❌ 启用接口失败:", string(out), er)
|
||||
_ = tunDev.Close()
|
||||
return nil, name, er
|
||||
}
|
||||
|
||||
return tunDev, name, nil
|
||||
}
|
||||
|
||||
// OnTunCreated 当 TUN 设备创建时执行
|
||||
func (n *NewTun) OnTunCreated(_ int) bool {
|
||||
if n.IsRunning {
|
||||
return true
|
||||
}
|
||||
if defaultGatewayIP == "" || defaultGatewayIf == "" || ifaceName == "" || rou.localCIDR == "" {
|
||||
return false
|
||||
}
|
||||
n.IsRunning = false
|
||||
tun, devName, err := OpenTunDevice(rou.tunIP)
|
||||
if err != nil {
|
||||
return n.IsRunning
|
||||
}
|
||||
// 设置 Sunny 的出口 IP 地址为原默认网关 IP
|
||||
if !n.Sunny.SetOutRouterIP(defaultGatewayIP) {
|
||||
_ = tun.Close()
|
||||
return n.IsRunning
|
||||
}
|
||||
n.tun = tun
|
||||
buf := make([]byte, 65535)
|
||||
n.tun = tun
|
||||
n.IsRunning = true
|
||||
rou.tunName = devName
|
||||
if rou.applyRouting() != nil {
|
||||
_ = tun.Close()
|
||||
rou.cleanup()
|
||||
return false
|
||||
}
|
||||
startWatchdog()
|
||||
go func() {
|
||||
defer func() {
|
||||
_ = tun.Close()
|
||||
rou.cleanup()
|
||||
}()
|
||||
for {
|
||||
// 从 TUN 设备读取数据
|
||||
nBytes, er := tun.Read(buf)
|
||||
// 如果 TUN 已经标记为未运行,退出循环
|
||||
if !n.IsRunning {
|
||||
return
|
||||
}
|
||||
// 如果读取出错或长度为 0,则稍等后重试
|
||||
if er != nil || nBytes <= 0 {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
// 将读取到的数据拷贝到新切片中
|
||||
var packet []byte
|
||||
packet = append(packet, buf[:nBytes]...)
|
||||
//我在这里输出,当局域网设备连接时,一点输出都没有
|
||||
go func() {
|
||||
n.parsePacket(packet)
|
||||
}()
|
||||
}
|
||||
}()
|
||||
return n.IsRunning
|
||||
}
|
||||
|
||||
type expiry struct {
|
||||
pid int32
|
||||
name string
|
||||
expiry time.Time
|
||||
}
|
||||
|
||||
var (
|
||||
pidCache = make(map[uint16]expiry)
|
||||
pidCacheMu sync.RWMutex
|
||||
pidTTL = 3 * time.Second
|
||||
pidExpiry = make(map[uint16]time.Time)
|
||||
)
|
||||
|
||||
func getPidByPort(kind string, port uint16) (int32, string) {
|
||||
pidCacheMu.Lock()
|
||||
defer pidCacheMu.Unlock()
|
||||
for k, _ := range pidCache {
|
||||
if !time.Now().Before(pidExpiry[k]) {
|
||||
delete(pidExpiry, k)
|
||||
delete(pidCache, k)
|
||||
}
|
||||
}
|
||||
if obj, ok := pidCache[port]; ok && time.Now().Before(pidExpiry[port]) {
|
||||
return obj.pid, obj.name
|
||||
}
|
||||
all, _ := CrossCompiled.Connections(kind)
|
||||
for _, conn := range all {
|
||||
if conn.Laddr.Port == uint32(port) {
|
||||
pid := conn.Pid
|
||||
p, _ := process.NewProcess(pid)
|
||||
ch := expiry{pid: pid}
|
||||
if p != nil {
|
||||
ch.name, _ = p.Name()
|
||||
}
|
||||
pidCache[port] = ch
|
||||
pidExpiry[port] = time.Now().Add(pidTTL)
|
||||
return ch.pid, ch.name
|
||||
}
|
||||
}
|
||||
return 0, ""
|
||||
}
|
||||
174
src/ProcessDrv/tun/Tun/linux_Router.go
Normal file
174
src/ProcessDrv/tun/Tun/linux_Router.go
Normal file
@@ -0,0 +1,174 @@
|
||||
//go:build linux && !android
|
||||
// +build linux,!android
|
||||
|
||||
package Tun
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func RunCmd(c ...string) string {
|
||||
var arr []string
|
||||
var name string
|
||||
for _, vv := range c {
|
||||
a := strings.Split(strings.TrimSpace(vv), " ")
|
||||
for _, v := range a {
|
||||
if v != "" {
|
||||
if name == "" {
|
||||
name = v
|
||||
continue
|
||||
}
|
||||
arr = append(arr, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(arr) == 0 {
|
||||
return ""
|
||||
}
|
||||
r, _ := exec.Command(name, arr...).CombinedOutput()
|
||||
return string(r)
|
||||
}
|
||||
|
||||
// Router 封装路由/iptables/TUN 的上下文
|
||||
type TunRouter struct {
|
||||
tunName string // TUN 设备名,例如 tun0
|
||||
tunIP string // TUN 本地地址,例如 1.2.3.1
|
||||
tunGW string // TUN 虚拟对端网关,例如 1.2.3.2
|
||||
defGWIP string // 原默认网关 IP,例如 192.168.96.2
|
||||
ifaceName string // 原默认网卡名称,例如 ens33
|
||||
hostIP string // 本机在该网卡上的 IPv4,例如 192.168.96.134
|
||||
localCIDR string // 本地子网CIDR,例如 192.168.96.0/24
|
||||
iptablesRule []string // 记录待删除的 iptables 规则参数
|
||||
}
|
||||
|
||||
// getDefaultRoute 解析默认网关与网卡、以及本机该网卡的 IPv4
|
||||
func getDefaultRoute() (hostIP, defGWIP, localCIDR string, err error) {
|
||||
out := RunCmd("ip", "route", "show", "default")
|
||||
re := regexp.MustCompile(`default\s+via\s+(\S+)\s+dev\s+(\S+)`)
|
||||
m := re.FindStringSubmatch(out)
|
||||
if len(m) < 3 {
|
||||
err = fmt.Errorf("无法解析默认路由: %s", out)
|
||||
return
|
||||
}
|
||||
out2 := RunCmd("ip", "-4", "addr", "show", "dev", ifaceName)
|
||||
defGWIP, ifaceName = m[1], m[2]
|
||||
sc := bufio.NewScanner(strings.NewReader(out2))
|
||||
for sc.Scan() {
|
||||
line := strings.TrimSpace(sc.Text())
|
||||
if strings.HasPrefix(line, "inet ") {
|
||||
// 形如:inet 192.168.96.134/24 brd ...
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) >= 2 {
|
||||
ipCidr := fields[1]
|
||||
localCIDR = ipCidr
|
||||
if i := strings.Index(ipCidr, "/"); i > 0 {
|
||||
hostIP = ipCidr[:i]
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if hostIP == "" || localCIDR == "" {
|
||||
err = fmt.Errorf("无法解析网卡 %s 的 IPv4 地址: %s", ifaceName, out2)
|
||||
return
|
||||
}
|
||||
localCIDR, err = hostCIDRToNetworkCIDR(localCIDR) // 计算 network/prefix
|
||||
if err != nil { // 如果失败
|
||||
return // 返回错误
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// (r *Router) applyRouting 应用策略路由与 iptables 规则
|
||||
func (r *TunRouter) applyRouting() error {
|
||||
// 放宽 rp_filter,避免策略路由下被 RPF 误杀
|
||||
RunCmd("sysctl", "-w", "net.ipv4.conf.all.rp_filter=2") // all=2
|
||||
RunCmd("sysctl", "-w", "net.ipv4.conf.default.rp_filter=2") // default=2
|
||||
RunCmd("sysctl", "-w", fmt.Sprintf("net.ipv4.conf.%s.rp_filter=2", r.ifaceName)) // 原网卡=2
|
||||
RunCmd("sysctl", "-w", fmt.Sprintf("net.ipv4.conf.%s.rp_filter=0", r.tunName)) // TUN=0
|
||||
|
||||
// table 100:旁路(走原网关/原网卡)
|
||||
RunCmd("ip", "route", "replace", "default", "via", r.defGWIP, "dev", r.ifaceName, "table", "100") // 默认走原网关
|
||||
RunCmd("ip", "route", "replace", r.defGWIP+"/32", "dev", r.ifaceName, "table", "100") // 网关/32 直连
|
||||
RunCmd("ip", "route", "replace", r.localCIDR, "dev", r.ifaceName, "table", "100") // 本地网段直连(网络前缀)
|
||||
|
||||
// table 200:TUN(默认走 TUN)
|
||||
RunCmd("ip", "route", "replace", "default", "via", r.tunGW, "dev", r.tunName, "table", "200") // 默认走 TUN
|
||||
|
||||
// ip rule(优先级从小到大)
|
||||
RunCmd("ip", "rule", "add", "priority", "90", "from", r.hostIP+"/32", "lookup", "100") // 本机源IP回包走原网卡
|
||||
RunCmd("ip", "rule", "add", "priority", "100", "fwmark", "1", "lookup", "100") // 本进程(按UID标记)旁路
|
||||
RunCmd("ip", "rule", "add", "priority", "120", "to", r.localCIDR, "lookup", "main") // 目的为本地网段走main
|
||||
RunCmd("ip", "rule", "add", "priority", "220", "lookup", "200") // 兜底全部走TUN
|
||||
|
||||
// 刷新路由缓存
|
||||
RunCmd("ip", "-4", "route", "flush", "cache") // 清空IPv4路由缓存
|
||||
|
||||
// 仅标记“本进程用户”的输出报文(无需 SO_MARK;使用 owner --uid-owner)
|
||||
uidStr := strconv.Itoa(int(_myPid)) // 转字符串
|
||||
r.iptablesRule = []string{"iptables", "-t", "mangle", "-A", "OUTPUT", "-m", "owner", "--uid-owner", uidStr, "-j", "MARK", "--set-mark", "1"} // 记录规则
|
||||
RunCmd(r.iptablesRule...) // 应用规则
|
||||
return nil // 返回成功
|
||||
}
|
||||
|
||||
// (r *Router) cleanup 还原策略路由与 iptables,删除 TUN
|
||||
func (r *TunRouter) cleanup() {
|
||||
// 删除 iptables 规则
|
||||
if len(r.iptablesRule) > 0 { // 若存在记录
|
||||
del := append([]string{}, r.iptablesRule...) // 复制一份
|
||||
del[3] = "-D" // 将 -A 改为 -D
|
||||
RunCmd(del...) // 删除规则
|
||||
}
|
||||
|
||||
// 删除策略路由(按优先级逐条删除)
|
||||
RunCmd("ip", "rule", "del", "priority", "220") // 删兜底
|
||||
RunCmd("ip", "rule", "del", "priority", "120") // 删本地网段
|
||||
RunCmd("ip", "rule", "del", "priority", "100") // 删 fwmark
|
||||
RunCmd("ip", "rule", "del", "priority", "90") // 删 from hostIP
|
||||
|
||||
// 清理 table200(TUN)与 table100(仅删我们加的三条)
|
||||
RunCmd("ip", "route", "flush", "table", "200") // 清空200
|
||||
RunCmd("ip", "route", "del", "default", "via", r.defGWIP, "dev", r.ifaceName, "table", "100") // 删默认
|
||||
RunCmd("ip", "route", "del", r.defGWIP+"/32", "dev", r.ifaceName, "table", "100") // 删/32
|
||||
RunCmd("ip", "route", "del", r.localCIDR, "dev", r.ifaceName, "table", "100") // 删本地网段
|
||||
|
||||
// 还原 rp_filter(可按需保持放宽,这里演示复原)
|
||||
RunCmd("sysctl", "-w", "net.ipv4.conf.all.rp_filter=1") // all=1
|
||||
RunCmd("sysctl", "-w", "net.ipv4.conf.default.rp_filter=1") // default=1
|
||||
RunCmd("sysctl", "-w", fmt.Sprintf("net.ipv4.conf.%s.rp_filter=1", r.ifaceName)) // 原网卡=1
|
||||
RunCmd("sysctl", "-w", fmt.Sprintf("net.ipv4.conf.%s.rp_filter=1", r.tunName)) // TUN=1
|
||||
|
||||
// 删除 TUN(双保险)
|
||||
RunCmd("ip", "link", "del", r.tunName) // 删除 TUN 接口
|
||||
}
|
||||
|
||||
var rou *TunRouter
|
||||
|
||||
func init() {
|
||||
hostIP, defGWIP, localCIDR, _ := getDefaultRoute()
|
||||
rou = &TunRouter{
|
||||
tunIP: "1.2.3.1", // 你可按需修改
|
||||
tunGW: "1.2.3.2", // 你可按需修改
|
||||
defGWIP: defGWIP,
|
||||
ifaceName: ifaceName,
|
||||
hostIP: hostIP,
|
||||
localCIDR: localCIDR,
|
||||
}
|
||||
}
|
||||
|
||||
// hostCIDRToNetworkCIDR 将诸如 "192.168.96.134/24" 规范化为 "192.168.96.0/24"
|
||||
func hostCIDRToNetworkCIDR(hostCIDR string) (string, error) { // 返回网络前缀CIDR与错误
|
||||
ip, ipnet, err := net.ParseCIDR(hostCIDR) // 解析 CIDR
|
||||
if err != nil { // 如果解析失败
|
||||
return "", err // 返回错误
|
||||
}
|
||||
network := ip.Mask(ipnet.Mask) // 计算网络地址
|
||||
prefixLen, _ := ipnet.Mask.Size() // 取掩码长度
|
||||
return fmt.Sprintf("%s/%d", network.String(), prefixLen), nil // 组装 network/prefix
|
||||
}
|
||||
164
src/ProcessDrv/tun/Tun/linux_sh.go
Normal file
164
src/ProcessDrv/tun/Tun/linux_sh.go
Normal file
@@ -0,0 +1,164 @@
|
||||
//go:build linux && !android
|
||||
// +build linux,!android
|
||||
|
||||
package Tun // 定义包名为 Tun
|
||||
|
||||
import ( // 导入所需包
|
||||
"bytes" // 用于接收子进程输出
|
||||
"fmt" // 字符串格式化
|
||||
"io" // IO 接口
|
||||
"os" // 文件与进程操作
|
||||
"os/exec" // 执行外部命令
|
||||
"path/filepath" // 构造临时文件路径
|
||||
"regexp" // 正则解析后台 PID
|
||||
"strconv" // 字符串转数字
|
||||
"strings" // 构建脚本文本
|
||||
"syscall" // 进程存活检测
|
||||
"time" // 定时控制
|
||||
)
|
||||
|
||||
// 全局脚本文本(由 CreateSh 生成)
|
||||
var sh = "" // 存放生成后的 Shell 脚本文本
|
||||
|
||||
// 监控器状态(保持你原有语义)
|
||||
var watchdogStarted bool // 标记监控脚本是否已启动
|
||||
var watchdogPid int // 记录后台化脚本 PID
|
||||
|
||||
// 脚本落盘路径(保持与原代码一致)
|
||||
const scriptPath = "/usr/local/bin/SunnyTunCancel.sh" // 清理脚本的绝对路径
|
||||
|
||||
// writeFileAtomic 原子写文件(避免部分写入导致执行失败)
|
||||
func writeFileAtomic(path string, data []byte, perm os.FileMode) error { // 定义原子写文件函数
|
||||
dir := filepath.Dir(path) // 获取目录
|
||||
tmp := filepath.Join(dir, "."+filepath.Base(path)+".tmp") // 生成临时文件路径
|
||||
if err := os.WriteFile(tmp, data, perm); err != nil { // 先写入临时文件
|
||||
return err // 返回错误
|
||||
}
|
||||
return os.Rename(tmp, path) // 重命名替换,达到原子写入效果
|
||||
}
|
||||
|
||||
// CreateSh 生成守护/清理脚本(根据 r 的状态把命令具体化到脚本内)
|
||||
func (r *TunRouter) CreateSh() { // 定义 CreateSh 方法
|
||||
var b strings.Builder // 使用高效的字符串构建器
|
||||
// 写入脚本头与后台化逻辑
|
||||
b.WriteString(`#!/bin/bash
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
# ==============================
|
||||
# 🛠 SunnyTunCancel.sh
|
||||
# 功能:后台监控目标进程,当进程退出时自动恢复默认网络配置
|
||||
# ==============================
|
||||
|
||||
# 若未后台化,则后台化自己并仅输出后台 PID 一行
|
||||
if [ -z "${DISOWNED-}" ]; then
|
||||
export DISOWNED=1
|
||||
nohup "$0" "$@" >/dev/null 2>&1 &
|
||||
printf "%s\n" "$!"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 目标 PID(第一个参数)
|
||||
TARGET_PID="${1:-}"
|
||||
if [ -z "${TARGET_PID}" ]; then
|
||||
echo "missing TARGET_PID" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🕓 监控进程 PID: ${TARGET_PID}"
|
||||
|
||||
# 轮询检测目标进程是否仍在
|
||||
while kill -0 "${TARGET_PID}" 2>/dev/null; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# === 以下为恢复/清理动作 ===
|
||||
`)
|
||||
// 删除 iptables 规则(如果你进程曾添加过)
|
||||
if len(r.iptablesRule) > 0 { // 如果记录了 iptables 规则
|
||||
del := append([]string{}, r.iptablesRule...) // 拷贝一份
|
||||
if len(del) > 3 && del[3] == "-A" { // 如果第四个参数为 -A
|
||||
del[3] = "-D" // 替换为 -D,实现删除
|
||||
}
|
||||
b.WriteString(strings.Join(del, " ")) // 拼接命令
|
||||
b.WriteByte('\n') // 换行
|
||||
}
|
||||
// 删除策略路由(按优先级顺序)
|
||||
b.WriteString("ip rule del priority 220 || true\n") // 删兜底
|
||||
b.WriteString("ip rule del priority 120 || true\n") // 删本地子网
|
||||
b.WriteString("ip rule del priority 100 || true\n") // 删 fwmark
|
||||
b.WriteString("ip rule del priority 90 || true\n") // 删 from hostIP
|
||||
|
||||
// 清理路由表 200 与 100(仅删我们加的几条,避免误删用户其它配置)
|
||||
b.WriteString("ip route flush table 200 || true\n") // 清空 200
|
||||
b.WriteString(fmt.Sprintf("ip route del default via %s dev %s table 100 || true\n", r.defGWIP, r.ifaceName)) // 删默认
|
||||
b.WriteString(fmt.Sprintf("ip route del %s/32 dev %s table 100 || true\n", r.defGWIP, r.ifaceName)) // 删/32
|
||||
b.WriteString(fmt.Sprintf("ip route del %s dev %s table 100 || true\n", r.localCIDR, r.ifaceName)) // 删本地网段
|
||||
|
||||
// 还原 rp_filter
|
||||
b.WriteString("sysctl -w net.ipv4.conf.all.rp_filter=1 || true\n") // all=1
|
||||
b.WriteString("sysctl -w net.ipv4.conf.default.rp_filter=1 || true\n") // default=1
|
||||
b.WriteString(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.rp_filter=1 || true\n", r.ifaceName)) // iface=1
|
||||
b.WriteString(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.rp_filter=1 || true\n", r.tunName)) // tun=1
|
||||
// 删除 TUN 接口(双保险)
|
||||
b.WriteString(fmt.Sprintf("ip link del %s || true\n", r.tunName)) // 删除 TUN
|
||||
// 收尾注释
|
||||
b.WriteString("echo '✅ SunnyTun 清理完成'\n") // 提示完成
|
||||
// 回填到全局 sh
|
||||
sh = b.String() // 将生成好的脚本文本保存到全局变量
|
||||
}
|
||||
|
||||
// startWatchdog 启动路由恢复监控脚本(防止主进程异常退出导致网络不恢复)
|
||||
func startWatchdog() { // 定义 startWatchdog 函数
|
||||
if watchdogStarted { // 如果已启动
|
||||
return // 直接返回
|
||||
}
|
||||
watchdogStarted = true // 标记已启动
|
||||
rou.CreateSh()
|
||||
_ = os.Remove(scriptPath) // 先尝试删除旧脚本(忽略错误)
|
||||
_ = writeFileAtomic(scriptPath, []byte(sh), 0o777) // 原子写入新脚本并赋可执行权限
|
||||
|
||||
go func() { // 启动后台 goroutine 持续监控
|
||||
mainPid := os.Getpid() // 获取当前主进程 PID(被监控对象)
|
||||
for { // 循环监控
|
||||
// 若已有后台脚本在运行,则无需拉起
|
||||
if watchdogPid > 0 && syscall.Kill(watchdogPid, 0) == nil { // 若 PID 存在
|
||||
time.Sleep(time.Second) // 休眠 1 秒后继续检测
|
||||
continue // 进入下次循环
|
||||
}
|
||||
|
||||
// 运行脚本:使用 /bin/bash,保障 $EUID 等 Bash 变量可用
|
||||
// 兼容你原来的三参形式:传 (PID, defaultGatewayIf, ifaceName)
|
||||
// 即使脚本未使用这两个参数也不影响(保持你的外部调用兼容)
|
||||
cmd := exec.Command("/bin/bash", scriptPath, strconv.Itoa(mainPid), defaultGatewayIf, ifaceName) // 构造命令
|
||||
var buffer bytes.Buffer // 创建输出缓冲区
|
||||
cmd.Stdout = &buffer // 捕获标准输出(脚本首次运行仅输出后台 PID)
|
||||
cmd.Stderr = io.Discard // 丢弃标准错误(避免污染 PID 解析)
|
||||
if err := cmd.Start(); err != nil { // 启动脚本失败
|
||||
watchdogPid = 0 // PID 置 0,稍后重试
|
||||
time.Sleep(time.Second) // 等待 1 秒
|
||||
continue // 下一轮重试
|
||||
}
|
||||
_ = cmd.Wait() // 等待脚本前台进程退出(它会很快退出,只打印后台 PID)
|
||||
// 解析输出中的第一个十进制数字作为 PID(更鲁棒,避免杂讯)
|
||||
out := strings.TrimSpace(buffer.String()) // 去掉首尾空白
|
||||
re := regexp.MustCompile(`\b\d+\b`) // 匹配第一个整数
|
||||
pidStr := re.FindString(out) // 提取 PID 字符串
|
||||
if pidStr == "" { // 若未匹配到
|
||||
watchdogPid = 0 // 置 0 以便重试
|
||||
time.Sleep(time.Second) // 等待 1 秒
|
||||
continue // 重试
|
||||
}
|
||||
pid, err := strconv.Atoi(pidStr) // 转换为整数
|
||||
if err != nil || pid <= 0 { // 若解析失败或不合理
|
||||
watchdogPid = 0 // 置 0
|
||||
time.Sleep(time.Second) // 等待 1 秒
|
||||
continue // 重试
|
||||
}
|
||||
watchdogPid = pid // 记录后台脚本 PID
|
||||
|
||||
// 正常情况下,此处后台脚本常驻;定期确认其存活
|
||||
time.Sleep(time.Second) // 休眠 1 秒再继续下一轮检查
|
||||
}
|
||||
}() // 启动 goroutine 结束
|
||||
}
|
||||
96
src/ProcessDrv/tun/Tun/main.go
Normal file
96
src/ProcessDrv/tun/Tun/main.go
Normal file
@@ -0,0 +1,96 @@
|
||||
//go:build android || darwin || linux
|
||||
// +build android darwin linux
|
||||
|
||||
package Tun
|
||||
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
)
|
||||
|
||||
var sessionsMu sync.Mutex
|
||||
|
||||
var sessions = make(map[uint16]*DevConn)
|
||||
|
||||
func (n *NewTun) pidFromCheck(pid int32, name string) (ok bool) {
|
||||
sessionsMu.Lock()
|
||||
defer sessionsMu.Unlock()
|
||||
if n.CheckProcess == nil {
|
||||
return false
|
||||
}
|
||||
if _myPid == pid {
|
||||
return true
|
||||
}
|
||||
if n.CheckProcess == nil {
|
||||
return false
|
||||
}
|
||||
return n.CheckProcess(pid, name)
|
||||
}
|
||||
|
||||
type NewTun struct {
|
||||
IsRunning bool
|
||||
ProxyPort uint16
|
||||
tun io.ReadWriteCloser
|
||||
handleTCPCallback TcpFunc
|
||||
handleUDPCallback UdpFunc
|
||||
Sunny Interface
|
||||
CheckProcess func(int32, string) bool
|
||||
}
|
||||
|
||||
func (n *NewTun) SetHandle(callbackTCP TcpFunc, udpSendReceiveFunc UdpFunc) {
|
||||
sessionsMu.Lock()
|
||||
defer sessionsMu.Unlock()
|
||||
n.handleTCPCallback = callbackTCP
|
||||
n.handleUDPCallback = udpSendReceiveFunc
|
||||
}
|
||||
|
||||
func (n *NewTun) Send(packetData []byte) {
|
||||
_, _ = n.tun.Write(packetData)
|
||||
}
|
||||
func (n *NewTun) parsePacket(packetData []byte) {
|
||||
first := packetData[0] >> 4
|
||||
var packet gopacket.Packet
|
||||
if first == 4 {
|
||||
packet = gopacket.NewPacket(packetData, layers.LayerTypeIPv4, gopacket.Default)
|
||||
} else if first == 6 {
|
||||
packet = gopacket.NewPacket(packetData, layers.LayerTypeIPv6, gopacket.Default)
|
||||
} else {
|
||||
// n.Send(packetData)
|
||||
return
|
||||
}
|
||||
if ipv4 := packet.Layer(layers.LayerTypeIPv4); ipv4 != nil {
|
||||
ip := ipv4.(*layers.IPv4)
|
||||
switch ip.Protocol {
|
||||
case layers.IPProtocolTCP:
|
||||
if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
|
||||
tcp := tcpLayer.(*layers.TCP)
|
||||
n.handleTCP4(ip, tcp)
|
||||
}
|
||||
case layers.IPProtocolUDP:
|
||||
if udpLayer := packet.Layer(layers.LayerTypeUDP); udpLayer != nil {
|
||||
udp := udpLayer.(*layers.UDP)
|
||||
n.handleUDP(ip.SrcIP, ip.DstIP, udp, true)
|
||||
}
|
||||
|
||||
}
|
||||
} else if ipv6 := packet.Layer(layers.LayerTypeIPv6); ipv6 != nil {
|
||||
ip := ipv6.(*layers.IPv6)
|
||||
switch ip.NextHeader {
|
||||
case layers.IPProtocolTCP:
|
||||
if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
|
||||
tcp := tcpLayer.(*layers.TCP)
|
||||
n.handleTCP6(ip, tcp)
|
||||
}
|
||||
case layers.IPProtocolUDP:
|
||||
if udpLayer := packet.Layer(layers.LayerTypeUDP); udpLayer != nil {
|
||||
udp := udpLayer.(*layers.UDP)
|
||||
n.handleUDP(ip.SrcIP, ip.DstIP, udp, false)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
20
src/ProcessDrv/tun/Tun/oth.go
Normal file
20
src/ProcessDrv/tun/Tun/oth.go
Normal file
@@ -0,0 +1,20 @@
|
||||
//go:build !android && !darwin && !linux
|
||||
// +build !android,!darwin,!linux
|
||||
|
||||
package Tun
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
var defaultGatewayIP, defaultGatewayIf = "", ""
|
||||
|
||||
type NewTun struct {
|
||||
IsRunning bool
|
||||
ProxyPort uint16
|
||||
tun io.ReadWriteCloser
|
||||
handleTCPCallback TcpFunc
|
||||
handleUDPCallback UdpFunc
|
||||
Sunny Interface
|
||||
CheckProcess func(int32, string) bool
|
||||
}
|
||||
128
src/ProcessDrv/tun/Tun/tcp.go
Normal file
128
src/ProcessDrv/tun/Tun/tcp.go
Normal file
@@ -0,0 +1,128 @@
|
||||
//go:build android || darwin || linux
|
||||
// +build android darwin linux
|
||||
|
||||
package Tun
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/ProcessCheck"
|
||||
)
|
||||
|
||||
// ------------------------------------------------
|
||||
// IPv4 TCP 处理函数
|
||||
// ------------------------------------------------
|
||||
func (n *NewTun) handleTCPCommand(tcp *layers.TCP, srcIP, dstIP net.IP, clientPort, serverPort uint16, v4 bool) {
|
||||
if tcp.SYN && !tcp.ACK {
|
||||
pid, name := getPidByPort("tcp", uint16(tcp.SrcPort))
|
||||
s := NewDevConn(n.tun, srcIP, clientPort, dstIP, serverPort, v4, tcp.Seq, tcp.Ack)
|
||||
s.pid = uint32(pid)
|
||||
sessionsMu.Lock()
|
||||
sessions[clientPort] = s
|
||||
sessionsMu.Unlock()
|
||||
// send SYN/ACK to client
|
||||
if _, err := SendSynAckToClient(n.tun, s, tcp.Seq); err != nil {
|
||||
// 如果发送失败,删除会话
|
||||
sessionsMu.Lock()
|
||||
delete(sessions, clientPort)
|
||||
sessionsMu.Unlock()
|
||||
return
|
||||
}
|
||||
sessionsMu.Lock()
|
||||
call := n.handleTCPCallback
|
||||
sessionsMu.Unlock()
|
||||
if n.pidFromCheck(pid, name) {
|
||||
go func() {
|
||||
var loader *net.TCPAddr
|
||||
if defaultGatewayIP != "" {
|
||||
loader = &net.TCPAddr{
|
||||
IP: net.ParseIP(defaultGatewayIP),
|
||||
Port: 0,
|
||||
}
|
||||
}
|
||||
dialer := &net.Dialer{LocalAddr: loader}
|
||||
|
||||
c, e := dialer.Dial("tcp", net.JoinHostPort(dstIP.String(), strconv.Itoa(int(serverPort))))
|
||||
if e != nil {
|
||||
_ = SendRstToClient(s)
|
||||
_ = s.Close()
|
||||
return
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
_, _ = io.Copy(s, c)
|
||||
_ = s.Close()
|
||||
_ = c.Close()
|
||||
wg.Done()
|
||||
}()
|
||||
go func() {
|
||||
_, _ = io.Copy(c, s)
|
||||
_ = s.Close()
|
||||
_ = c.Close()
|
||||
wg.Done()
|
||||
}()
|
||||
wg.Wait()
|
||||
sessionsMu.Lock()
|
||||
delete(sessions, clientPort)
|
||||
sessionsMu.Unlock()
|
||||
}()
|
||||
return
|
||||
}
|
||||
if call != nil {
|
||||
ProcessCheck.AddDevObj(clientPort, s)
|
||||
go call(s)
|
||||
}
|
||||
return
|
||||
}
|
||||
sessionsMu.Lock()
|
||||
sess, ok := sessions[clientPort]
|
||||
sessionsMu.Unlock()
|
||||
if !ok {
|
||||
h2 := NewDevConn(n.tun, srcIP, clientPort, dstIP, serverPort, true, tcp.Seq, tcp.Ack)
|
||||
_ = SendRstToClient(h2)
|
||||
return
|
||||
}
|
||||
if tcp.FIN || tcp.RST {
|
||||
sessionsMu.Lock()
|
||||
delete(sessions, clientPort)
|
||||
sessionsMu.Unlock()
|
||||
ProcessCheck.DelDevObj(clientPort)
|
||||
if tcp.FIN {
|
||||
_, _ = buildTCPReply(sess, tcp, true, true, false)
|
||||
} else if tcp.RST {
|
||||
_, _ = buildTCPReply(sess, tcp, true, false, false)
|
||||
}
|
||||
return
|
||||
}
|
||||
if len(tcp.Payload) > 0 {
|
||||
sess.PushClientPayload(tcp.Payload, tcp.Seq)
|
||||
return
|
||||
}
|
||||
sess.mu.Lock()
|
||||
sess.clientNext = tcp.Seq
|
||||
sess.mu.Unlock()
|
||||
return
|
||||
}
|
||||
func (n *NewTun) handleTCP4(ip *layers.IPv4, tcp *layers.TCP) {
|
||||
clientIP := ip.SrcIP
|
||||
clientPort := uint16(tcp.SrcPort)
|
||||
serverIP := ip.DstIP
|
||||
serverPort := uint16(tcp.DstPort)
|
||||
n.handleTCPCommand(tcp, clientIP, serverIP, clientPort, serverPort, true)
|
||||
}
|
||||
|
||||
// ------------------------------------------------
|
||||
// IPv6 TCP 处理函数
|
||||
// ------------------------------------------------
|
||||
func (n *NewTun) handleTCP6(ip *layers.IPv6, tcp *layers.TCP) {
|
||||
clientIP := ip.SrcIP
|
||||
clientPort := uint16(tcp.SrcPort)
|
||||
serverIP := ip.DstIP
|
||||
serverPort := uint16(tcp.DstPort)
|
||||
n.handleTCPCommand(tcp, clientIP, serverIP, clientPort, serverPort, false)
|
||||
}
|
||||
426
src/ProcessDrv/tun/Tun/toKernel.go
Normal file
426
src/ProcessDrv/tun/Tun/toKernel.go
Normal file
@@ -0,0 +1,426 @@
|
||||
//go:build android || darwin || linux
|
||||
// +build android darwin linux
|
||||
|
||||
package Tun
|
||||
|
||||
import (
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
)
|
||||
|
||||
var serializeOpts = gopacket.SerializeOptions{
|
||||
FixLengths: true,
|
||||
ComputeChecksums: true,
|
||||
}
|
||||
|
||||
func sendIPv4(ip *layers.IPv4, tcp *layers.TCP, payload []byte) []byte {
|
||||
_ = tcp.SetNetworkLayerForChecksum(ip)
|
||||
buf := gopacket.NewSerializeBuffer()
|
||||
if payload != nil && len(payload) > 0 {
|
||||
if err := gopacket.SerializeLayers(buf, serializeOpts, ip, tcp, gopacket.Payload(payload)); err != nil {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
if err := gopacket.SerializeLayers(buf, serializeOpts, ip, tcp); err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func sendIPv6(ip *layers.IPv6, tcp *layers.TCP, payload []byte) []byte {
|
||||
_ = tcp.SetNetworkLayerForChecksum(ip)
|
||||
buf := gopacket.NewSerializeBuffer()
|
||||
if payload != nil && len(payload) > 0 {
|
||||
if err := gopacket.SerializeLayers(buf, serializeOpts, ip, tcp, gopacket.Payload(payload)); err != nil {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
if err := gopacket.SerializeLayers(buf, serializeOpts, ip, tcp); err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// SendSynAckToClient :收到 client SYN 时注入 SYN/ACK(伪造 server 的 SYN/ACK)
|
||||
func SendSynAckToClient(h io.ReadWriteCloser, d *DevConn, clientISN uint32) (int, error) {
|
||||
|
||||
if d.v4 {
|
||||
ip := &layers.IPv4{
|
||||
Version: 4,
|
||||
IHL: 5,
|
||||
SrcIP: d.serverIP,
|
||||
DstIP: d.clientIP,
|
||||
Protocol: layers.IPProtocolTCP,
|
||||
TTL: 64,
|
||||
}
|
||||
tcp := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(d.serverPort),
|
||||
DstPort: layers.TCPPort(d.clientPort),
|
||||
Seq: d.serverISN,
|
||||
Ack: clientISN + 1,
|
||||
SYN: true,
|
||||
ACK: true,
|
||||
Window: 65535,
|
||||
}
|
||||
return h.Write(sendIPv4(ip, tcp, nil))
|
||||
}
|
||||
|
||||
ip6 := &layers.IPv6{
|
||||
Version: 6,
|
||||
SrcIP: d.serverIP,
|
||||
DstIP: d.clientIP,
|
||||
NextHeader: layers.IPProtocolTCP,
|
||||
HopLimit: 64,
|
||||
}
|
||||
tcp6 := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(d.serverPort),
|
||||
DstPort: layers.TCPPort(d.clientPort),
|
||||
Seq: d.serverISN,
|
||||
Ack: clientISN + 1,
|
||||
SYN: true,
|
||||
ACK: true,
|
||||
Window: 65535,
|
||||
}
|
||||
return h.Write(sendIPv6(ip6, tcp6, nil))
|
||||
}
|
||||
|
||||
func SendAckToKernel(d *DevConn, clientNext uint32) []byte {
|
||||
// 只在短时间内持锁读取 seq
|
||||
d.mu.Lock()
|
||||
seq := d.serverSeqNext
|
||||
// copy v4 flag and endpoints
|
||||
v4 := d.v4
|
||||
serverIP := d.serverIP
|
||||
clientIP := d.clientIP
|
||||
serverPort := d.serverPort
|
||||
clientPort := d.clientPort
|
||||
d.mu.Unlock()
|
||||
|
||||
if v4 {
|
||||
ip := &layers.IPv4{
|
||||
Version: 4,
|
||||
IHL: 5,
|
||||
SrcIP: serverIP,
|
||||
DstIP: clientIP,
|
||||
Protocol: layers.IPProtocolTCP,
|
||||
TTL: 64,
|
||||
}
|
||||
tcp := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(serverPort),
|
||||
DstPort: layers.TCPPort(clientPort),
|
||||
Seq: seq,
|
||||
Ack: clientNext,
|
||||
ACK: true,
|
||||
Window: 65535,
|
||||
}
|
||||
bs := sendIPv4(ip, tcp, nil)
|
||||
d.mu.Lock()
|
||||
if clientNext > d.highestClientAckSent {
|
||||
d.highestClientAckSent = clientNext
|
||||
}
|
||||
d.mu.Unlock()
|
||||
return bs
|
||||
}
|
||||
|
||||
ip6 := &layers.IPv6{
|
||||
Version: 6,
|
||||
SrcIP: serverIP,
|
||||
DstIP: clientIP,
|
||||
NextHeader: layers.IPProtocolTCP,
|
||||
HopLimit: 64,
|
||||
}
|
||||
tcp6 := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(serverPort),
|
||||
DstPort: layers.TCPPort(clientPort),
|
||||
Seq: d.serverSeqNext,
|
||||
Ack: clientNext,
|
||||
ACK: true,
|
||||
Window: 65535,
|
||||
}
|
||||
bs := sendIPv6(ip6, tcp6, nil)
|
||||
d.mu.Lock()
|
||||
if clientNext > d.highestClientAckSent {
|
||||
d.highestClientAckSent = clientNext
|
||||
}
|
||||
d.mu.Unlock()
|
||||
return bs
|
||||
}
|
||||
|
||||
// SendFinToClient :注入一个 FIN/ACK(server -> client),并在成功后把 serverSeqNext 增 1(FIN 消耗 1 序号)。
|
||||
func SendFinToClient(d *DevConn) []byte {
|
||||
// 复制需要的字段,避免在持锁时调用 h.Send 导致死锁或长时间阻塞
|
||||
d.mu.Lock()
|
||||
seq := d.serverSeqNext
|
||||
ack := d.clientNext
|
||||
serverIP := d.serverIP
|
||||
clientIP := d.clientIP
|
||||
serverPort := d.serverPort
|
||||
clientPort := d.clientPort
|
||||
v4 := d.v4
|
||||
d.mu.Unlock()
|
||||
|
||||
if v4 {
|
||||
ip := &layers.IPv4{
|
||||
Version: 4,
|
||||
IHL: 5,
|
||||
SrcIP: serverIP,
|
||||
DstIP: clientIP,
|
||||
Protocol: layers.IPProtocolTCP,
|
||||
TTL: 64,
|
||||
}
|
||||
tcp := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(serverPort),
|
||||
DstPort: layers.TCPPort(clientPort),
|
||||
Seq: seq,
|
||||
Ack: ack,
|
||||
FIN: true,
|
||||
ACK: true,
|
||||
Window: 65535,
|
||||
}
|
||||
bs := sendIPv4(ip, tcp, nil)
|
||||
d.mu.Lock()
|
||||
if seq == d.serverSeqNext {
|
||||
d.serverSeqNext = seq + 1
|
||||
}
|
||||
d.mu.Unlock()
|
||||
return bs
|
||||
}
|
||||
|
||||
ip6 := &layers.IPv6{
|
||||
Version: 6,
|
||||
SrcIP: serverIP,
|
||||
DstIP: clientIP,
|
||||
NextHeader: layers.IPProtocolTCP,
|
||||
HopLimit: 64,
|
||||
}
|
||||
tcp6 := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(serverPort),
|
||||
DstPort: layers.TCPPort(clientPort),
|
||||
Seq: seq,
|
||||
Ack: ack,
|
||||
FIN: true,
|
||||
ACK: true,
|
||||
Window: 65535,
|
||||
}
|
||||
bs := sendIPv6(ip6, tcp6, nil)
|
||||
d.mu.Lock()
|
||||
if seq == d.serverSeqNext {
|
||||
d.serverSeqNext = seq + 1
|
||||
}
|
||||
d.mu.Unlock()
|
||||
return bs
|
||||
}
|
||||
|
||||
// SendRstToClient :立刻强制断开(client 会收到 RST),通常客户端会马上重连
|
||||
func SendRstToClient(d *DevConn) []byte {
|
||||
d.mu.Lock()
|
||||
seq := d.serverSeqNext
|
||||
ack := d.clientNext
|
||||
serverIP := d.serverIP
|
||||
clientIP := d.clientIP
|
||||
serverPort := d.serverPort
|
||||
clientPort := d.clientPort
|
||||
v4 := d.v4
|
||||
d.mu.Unlock()
|
||||
if v4 {
|
||||
ip := &layers.IPv4{
|
||||
Version: 4, IHL: 5,
|
||||
SrcIP: serverIP, DstIP: clientIP,
|
||||
Protocol: layers.IPProtocolTCP, TTL: 64,
|
||||
}
|
||||
tcp := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(serverPort),
|
||||
DstPort: layers.TCPPort(clientPort),
|
||||
Seq: seq,
|
||||
Ack: ack,
|
||||
RST: true,
|
||||
Window: 0,
|
||||
}
|
||||
return sendIPv4(ip, tcp, nil)
|
||||
}
|
||||
|
||||
ip6 := &layers.IPv6{
|
||||
Version: 6,
|
||||
SrcIP: serverIP,
|
||||
DstIP: clientIP,
|
||||
NextHeader: layers.IPProtocolTCP,
|
||||
HopLimit: 64,
|
||||
}
|
||||
tcp6 := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(serverPort),
|
||||
DstPort: layers.TCPPort(clientPort),
|
||||
Seq: seq,
|
||||
Ack: ack,
|
||||
RST: true,
|
||||
Window: 0,
|
||||
}
|
||||
return sendIPv6(ip6, tcp6, nil)
|
||||
}
|
||||
func buildTCPReply(d *DevConn, tcp *layers.TCP, sendAck bool, sendFin bool, sendRst bool) (int, error) {
|
||||
var replyIP gopacket.NetworkLayer
|
||||
var replyIPop gopacket.SerializableLayer
|
||||
if d.v4 {
|
||||
ip := &layers.IPv4{
|
||||
Version: 4, IHL: 5,
|
||||
SrcIP: d.serverIP, DstIP: d.clientIP,
|
||||
Protocol: layers.IPProtocolTCP, TTL: 64,
|
||||
}
|
||||
replyIP = ip
|
||||
replyIPop = ip
|
||||
} else {
|
||||
ip6 := &layers.IPv6{
|
||||
Version: 6,
|
||||
SrcIP: d.serverIP,
|
||||
DstIP: d.clientIP,
|
||||
NextHeader: layers.IPProtocolTCP,
|
||||
HopLimit: 64,
|
||||
}
|
||||
replyIP = ip6
|
||||
replyIPop = ip6
|
||||
}
|
||||
|
||||
replyTCP := *tcp
|
||||
|
||||
replyTCP.SrcPort, replyTCP.DstPort = tcp.DstPort, tcp.SrcPort
|
||||
|
||||
// 清空 payload
|
||||
replyTCP.Payload = nil
|
||||
|
||||
// 重置标志
|
||||
replyTCP.SYN = false
|
||||
replyTCP.ACK = sendAck
|
||||
replyTCP.FIN = sendFin
|
||||
replyTCP.RST = sendRst
|
||||
replyTCP.PSH = false
|
||||
replyTCP.URG = false
|
||||
replyTCP.ECE = false
|
||||
replyTCP.CWR = false
|
||||
// 序号与确认号
|
||||
replyTCP.Seq = tcp.Ack
|
||||
replyTCP.Ack = tcp.Seq + uint32(len(tcp.Payload))
|
||||
if tcp.SYN || tcp.FIN {
|
||||
replyTCP.Ack++
|
||||
}
|
||||
_ = replyTCP.SetNetworkLayerForChecksum(replyIP)
|
||||
buf := gopacket.NewSerializeBuffer()
|
||||
opts := gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true}
|
||||
_ = gopacket.SerializeLayers(buf, opts, replyIPop, &replyTCP)
|
||||
return d.tun.Write(buf.Bytes())
|
||||
}
|
||||
|
||||
// minInt 返回较小的整数
|
||||
func minInt(a, b int) int {
|
||||
if a < b { // 如果 a 小于 b
|
||||
return a // 返回 a
|
||||
}
|
||||
return b // 否则返回 b
|
||||
}
|
||||
func calcMSS(v4 bool) int {
|
||||
if v4 { // 如果是 IPv4
|
||||
return 1460 // 典型以太网 MTU 1500 - IPv4 20 - TCP 20 = 1460
|
||||
}
|
||||
return 1440 // IPv6 40 + TCP 20,1500 - 40 - 20 = 1440
|
||||
}
|
||||
|
||||
// SendDataToClient :按 MSS 分段发送;写 TUN 时不持锁;仅最后一段置 PSH
|
||||
func SendDataToClient(d *DevConn, payload []byte) (int, error) { // 对外发送函数
|
||||
if len(payload) == 0 { // 没有数据
|
||||
return 0, nil // 直接返回
|
||||
}
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
mss := calcMSS(d.v4) // 计算单段最大负载
|
||||
// 发送循环变量
|
||||
total := len(payload) // 总长度
|
||||
offset := 0 // 当前偏移
|
||||
sent := 0 // 成功写入的 payload 字节数
|
||||
// 为了减轻内核队列压力,批量发送若干段后让出调度
|
||||
const burstSeg = 8 // 每发送 8 段让出一次
|
||||
|
||||
// 主循环:直到全部发送完成
|
||||
for segIdx := 0; offset < total; segIdx++ {
|
||||
// 按段发送
|
||||
// 计算本段范围
|
||||
remain := total - offset // 剩余字节
|
||||
chunk := minInt(mss, remain) // 本段大小不超过 MSS
|
||||
end := offset + chunk // 本段结束位置
|
||||
psh := end == total // 仅最后一段置 PSH
|
||||
// ---- 锁内:读取快照、构造首部并拿到本段 Seq/Ack ----
|
||||
seq := d.serverSeqNext // 当前段 Seq 起点
|
||||
ack := d.clientNext // 当前 Ack 值
|
||||
serverIP := d.serverIP // 源 IP
|
||||
clientIP := d.clientIP // 目的 IP
|
||||
serverPort := d.serverPort // 源端口
|
||||
clientPort := d.clientPort // 目的端口
|
||||
v4 := d.v4 // 是否 IPv4
|
||||
seg := payload[offset:end] // 当前段载荷切片
|
||||
|
||||
var pkt []byte // 序列化后的 IP 包
|
||||
if v4 { // IPv4 分支
|
||||
ip := &layers.IPv4{ // 构造 IPv4 首部
|
||||
Version: 4, // 版本
|
||||
IHL: 5, // 无选项 IHL=5
|
||||
SrcIP: serverIP, // 源 IP
|
||||
DstIP: clientIP, // 目的 IP
|
||||
Protocol: layers.IPProtocolTCP, // 上层协议 TCP
|
||||
TTL: 64, // TTL
|
||||
}
|
||||
tcp := &layers.TCP{ // 构造 TCP 首部
|
||||
SrcPort: layers.TCPPort(serverPort), // 源端口
|
||||
DstPort: layers.TCPPort(clientPort), // 目的端口
|
||||
Seq: seq, // 本段 Seq
|
||||
Ack: ack, // 本段 Ack
|
||||
ACK: true, // ACK 位
|
||||
PSH: psh, // 仅最后一段置 PSH
|
||||
Window: 65535, // 窗口(与接收窗口无关)
|
||||
}
|
||||
pkt = sendIPv4(ip, tcp, seg) // 序列化完整 IPv4 包
|
||||
} else { // IPv6 分支
|
||||
ip6 := &layers.IPv6{ // 构造 IPv6 首部
|
||||
Version: 6, // 版本
|
||||
SrcIP: serverIP, // 源 IP
|
||||
DstIP: clientIP, // 目的 IP
|
||||
NextHeader: layers.IPProtocolTCP, // 下一头部 TCP
|
||||
HopLimit: 64, // 跳限
|
||||
}
|
||||
tcp6 := &layers.TCP{ // 构造 TCP 首部
|
||||
SrcPort: layers.TCPPort(serverPort), // 源端口
|
||||
DstPort: layers.TCPPort(clientPort), // 目的端口
|
||||
Seq: seq, // 本段 Seq
|
||||
Ack: ack, // 本段 Ack
|
||||
ACK: true, // ACK 位
|
||||
PSH: psh, // 仅最后一段置 PSH
|
||||
Window: 65535, // 窗口
|
||||
}
|
||||
pkt = sendIPv6(ip6, tcp6, seg) // 序列化完整 IPv6 包
|
||||
}
|
||||
// 先在“状态上推进”下一发送序列(成功后生效;失败再回滚)
|
||||
nextSeq := seq + uint32(chunk) // 预计算下一 seq
|
||||
// 锁内不写 TUN,先解锁让收包线程有机会推进窗口
|
||||
|
||||
// ---- 锁外:执行实际写入(避免长时间持锁阻塞收包)----
|
||||
if _, err := d.tun.Write(pkt); err != nil { // 写 TUN 失败
|
||||
// 写失败需要回到锁内回滚 serverSeqNext
|
||||
d.serverSeqNext = seq // 回滚到当前段起始 Seq
|
||||
return sent, err // 返回已发送字节及错误
|
||||
}
|
||||
|
||||
// ---- 锁内:确认写成功后,更新状态并推进 offset/sent ----
|
||||
d.serverSeqNext = nextSeq // 提交推进后的 Seq
|
||||
// 推进偏移与累计成功字节
|
||||
offset = end // 偏移前移到下一段起点
|
||||
sent += chunk // 累计成功写入的 payload 字节数
|
||||
|
||||
// 每写若干段,让出一下调度,减少内核队列压力
|
||||
if segIdx%burstSeg == burstSeg-1 { // 达到一批次
|
||||
runtime.Gosched() // 让出调度给收包 goroutine
|
||||
}
|
||||
}
|
||||
// 全部成功
|
||||
return sent, nil // 返回成功写入的 payload 字节总数
|
||||
}
|
||||
211
src/ProcessDrv/tun/Tun/udp.go
Normal file
211
src/ProcessDrv/tun/Tun/udp.go
Normal file
@@ -0,0 +1,211 @@
|
||||
//go:build android || darwin || linux
|
||||
// +build android darwin linux
|
||||
|
||||
package Tun
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/SunnyNetUDP"
|
||||
"github.com/qtgolang/SunnyNet/src/public"
|
||||
)
|
||||
|
||||
type connEntry struct {
|
||||
LastSeen time.Time
|
||||
ClientIP net.IP
|
||||
ClientPort uint16
|
||||
ServerIP net.IP
|
||||
ServerPort uint16
|
||||
conn *net.UDPConn
|
||||
Theology int64
|
||||
fd io.ReadWriteCloser
|
||||
v4 bool
|
||||
pid int32
|
||||
pidFromCheck bool
|
||||
callback func(Type int, Theoni int64, pid uint32, LocalAddress, RemoteAddress string, data []byte) []byte
|
||||
mu *sync.Mutex
|
||||
}
|
||||
|
||||
func (c *connEntry) ToClient(payload []byte) bool {
|
||||
if c.fd == nil {
|
||||
return false
|
||||
}
|
||||
buf := gopacket.NewSerializeBuffer()
|
||||
opts := gopacket.SerializeOptions{
|
||||
FixLengths: true,
|
||||
ComputeChecksums: true,
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
if c.v4 {
|
||||
ip := &layers.IPv4{
|
||||
Version: 4,
|
||||
IHL: 5,
|
||||
TTL: 64,
|
||||
SrcIP: c.ServerIP,
|
||||
DstIP: c.ClientIP,
|
||||
Protocol: layers.IPProtocolUDP,
|
||||
}
|
||||
udp := &layers.UDP{
|
||||
SrcPort: layers.UDPPort(c.ServerPort),
|
||||
DstPort: layers.UDPPort(c.ClientPort),
|
||||
}
|
||||
_ = udp.SetNetworkLayerForChecksum(ip)
|
||||
|
||||
err = gopacket.SerializeLayers(buf, opts, ip, udp, gopacket.Payload(payload))
|
||||
} else {
|
||||
ip6 := &layers.IPv6{
|
||||
Version: 6,
|
||||
HopLimit: 64,
|
||||
SrcIP: c.ServerIP,
|
||||
DstIP: c.ClientIP,
|
||||
NextHeader: layers.IPProtocolUDP,
|
||||
}
|
||||
udp := &layers.UDP{
|
||||
SrcPort: layers.UDPPort(c.ServerPort),
|
||||
DstPort: layers.UDPPort(c.ClientPort),
|
||||
}
|
||||
_ = udp.SetNetworkLayerForChecksum(ip6)
|
||||
|
||||
err = gopacket.SerializeLayers(buf, opts, ip6, udp, gopacket.Payload(payload))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
packetData := buf.Bytes()
|
||||
_, err = c.fd.Write(packetData)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (c *connEntry) ToServer(bytes []byte) bool {
|
||||
if c.conn == nil {
|
||||
return false
|
||||
}
|
||||
_, e := c.conn.Write(bytes)
|
||||
return e == nil
|
||||
}
|
||||
|
||||
// 全局表
|
||||
var (
|
||||
connTable = make(map[uint16]*connEntry)
|
||||
connMu sync.Mutex
|
||||
)
|
||||
|
||||
func (n *NewTun) handleUDP(srcIP, dstIP net.IP, udp *layers.UDP, v4 bool) {
|
||||
Payload := udp.Payload
|
||||
if len(Payload) == 0 {
|
||||
return
|
||||
}
|
||||
clientIP := srcIP
|
||||
clientPort := uint16(udp.SrcPort)
|
||||
serverIP := dstIP
|
||||
serverPort := uint16(udp.DstPort)
|
||||
connMu.Lock()
|
||||
obj := connTable[clientPort]
|
||||
if obj == nil {
|
||||
var mu sync.Mutex
|
||||
obj = &connEntry{ClientIP: clientIP, ClientPort: clientPort, ServerIP: serverIP, ServerPort: serverPort, Theology: atomic.AddInt64(&public.Theology, 1), v4: v4, callback: n.handleUDPCallback, mu: &mu, fd: n.tun}
|
||||
pid, name := getPidByPort("udp", clientPort)
|
||||
obj.pid = pid
|
||||
obj.pidFromCheck = n.pidFromCheck(obj.pid, name)
|
||||
connTable[clientPort] = obj
|
||||
connMu.Unlock()
|
||||
mu.Lock()
|
||||
target := &net.UDPAddr{IP: serverIP, Port: int(serverPort)}
|
||||
var localAddr *net.UDPAddr
|
||||
if defaultGatewayIP != "" {
|
||||
localAddr = &net.UDPAddr{IP: net.ParseIP(defaultGatewayIP), Port: 0}
|
||||
}
|
||||
conn, er := net.DialUDP("udp", localAddr, target)
|
||||
if er != nil {
|
||||
mu.Unlock()
|
||||
connMu.Lock()
|
||||
delete(connTable, clientPort)
|
||||
connMu.Unlock()
|
||||
return
|
||||
}
|
||||
mu.Unlock()
|
||||
connMu.Lock()
|
||||
obj.conn = conn
|
||||
SunnyNetUDP.AddUDPItem(obj.Theology, obj)
|
||||
go obj.loop()
|
||||
}
|
||||
obj.mu.Lock()
|
||||
defer obj.mu.Unlock()
|
||||
obj.LastSeen = time.Now()
|
||||
connMu.Unlock()
|
||||
if obj.conn != nil {
|
||||
if obj.callback != nil {
|
||||
if obj.pidFromCheck {
|
||||
obj.ToServer(Payload)
|
||||
return
|
||||
}
|
||||
LocalAddress := net.JoinHostPort(obj.ClientIP.String(), strconv.Itoa(int(obj.ClientPort)))
|
||||
RemoteAddress := net.JoinHostPort(obj.ServerIP.String(), strconv.Itoa(int(obj.ServerPort)))
|
||||
bs := obj.callback(public.SunnyNetUDPTypeSend, obj.Theology, uint32(obj.pid), LocalAddress, RemoteAddress, Payload)
|
||||
if len(bs) < 1 {
|
||||
return
|
||||
}
|
||||
obj.ToServer(bs)
|
||||
return
|
||||
}
|
||||
obj.ToServer(Payload)
|
||||
}
|
||||
return
|
||||
}
|
||||
func (c *connEntry) loop() {
|
||||
LocalAddress := net.JoinHostPort(c.ClientIP.String(), strconv.Itoa(int(c.ClientPort)))
|
||||
RemoteAddress := net.JoinHostPort(c.ServerIP.String(), strconv.Itoa(int(c.ServerPort)))
|
||||
buff := make([]byte, 0xffff)
|
||||
for {
|
||||
_ = c.conn.SetReadDeadline(time.Now().Add(time.Duration(10) * time.Second))
|
||||
nt, _, _ := c.conn.ReadFromUDP(buff)
|
||||
if nt == 0 {
|
||||
connMu.Lock()
|
||||
if time.Now().After(c.LastSeen.Add(time.Duration(30) * time.Second)) {
|
||||
connMu.Unlock()
|
||||
break
|
||||
}
|
||||
connMu.Unlock()
|
||||
continue
|
||||
}
|
||||
connMu.Lock()
|
||||
c.LastSeen = time.Now()
|
||||
connMu.Unlock()
|
||||
if c.callback != nil {
|
||||
if c.pidFromCheck {
|
||||
c.ToClient(buff[:nt])
|
||||
return
|
||||
}
|
||||
bs := c.callback(public.SunnyNetUDPTypeReceive, c.Theology, uint32(c.pid), LocalAddress, RemoteAddress, buff[:nt])
|
||||
if len(bs) < 1 {
|
||||
continue
|
||||
}
|
||||
c.ToClient(bs)
|
||||
} else {
|
||||
c.ToClient(buff[:nt])
|
||||
}
|
||||
}
|
||||
connMu.Lock()
|
||||
if connTable[c.ClientPort] != nil {
|
||||
SunnyNetUDP.DelUDPItem(c.Theology)
|
||||
if c.pidFromCheck {
|
||||
return
|
||||
}
|
||||
if c.callback != nil {
|
||||
c.callback(public.SunnyNetUDPTypeClosed, c.Theology, uint32(c.pid), LocalAddress, RemoteAddress, nil)
|
||||
}
|
||||
delete(connTable, c.ClientPort)
|
||||
}
|
||||
connMu.Unlock()
|
||||
}
|
||||
16
src/ProcessDrv/tun/WinDivert/ProcessCheck.go
Normal file
16
src/ProcessDrv/tun/WinDivert/ProcessCheck.go
Normal file
@@ -0,0 +1,16 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package WinDivert
|
||||
|
||||
func (d *Divert) pidFromCheck(pid int32, name string) (ok bool) {
|
||||
if _myPid == pid {
|
||||
return true
|
||||
}
|
||||
sessionsMu.Lock()
|
||||
defer sessionsMu.Unlock()
|
||||
if d.checkProcess == nil {
|
||||
return false
|
||||
}
|
||||
return d.checkProcess(pid, name)
|
||||
}
|
||||
248
src/ProcessDrv/tun/WinDivert/addr.go
Normal file
248
src/ProcessDrv/tun/WinDivert/addr.go
Normal file
@@ -0,0 +1,248 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package WinDivert
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Ethernet is ...
|
||||
type Ethernet struct {
|
||||
InterfaceIndex uint32
|
||||
SubInterfaceIndex uint32
|
||||
_ [7]uint64
|
||||
}
|
||||
|
||||
// Network is ...
|
||||
// The WINDIVERT_LAYER_NETWORK and WINDIVERT_LAYER_NETWORK_FORWARD layers allow the user
|
||||
// application to capture/block/inject network packets passing to/from (and through) the
|
||||
// local machine. Due to technical limitations, process ID information is not available
|
||||
// at these layers.
|
||||
type Network struct {
|
||||
InterfaceIndex uint32
|
||||
SubInterfaceIndex uint32
|
||||
_ [7]uint64
|
||||
}
|
||||
|
||||
// Socket is ...
|
||||
// The WINDIVERT_LAYER_SOCKET layer can capture or block events corresponding to socket
|
||||
// operations, such as bind(), connect(), listen(), etc., or the termination of socket
|
||||
// operations, such as a TCP socket disconnection. Unlike the flow layer, most socket-related
|
||||
// events can be blocked. However, it is not possible to inject new or modified socket events.
|
||||
// Process ID information (of the process responsible for the socket operation) is available
|
||||
// at this layer. Due to technical limitations, this layer cannot capture events that occurred
|
||||
// before the handle was opened.
|
||||
type Socket struct {
|
||||
EndpointID uint64
|
||||
ParentEndpointID uint64
|
||||
ProcessID uint32
|
||||
LocalAddress [16]uint8
|
||||
RemoteAddress [16]uint8
|
||||
LocalPort uint16
|
||||
RemotePort uint16
|
||||
Protocol uint8
|
||||
_ [3]uint8
|
||||
_ uint32
|
||||
}
|
||||
|
||||
// Flow is ...
|
||||
// The WINDIVERT_LAYER_FLOW layer captures information about network flow establishment/deletion
|
||||
// events. Here, a flow represents either (1) a TCP connection, or (2) an implicit "flow" created
|
||||
// by the first sent/received packet for non-TCP traffic, e.g., UDP. Old flows are deleted when
|
||||
// the corresponding connection is closed (for TCP), or based on an activity timeout (non-TCP).
|
||||
// Flow-related events can be captured, but not blocked nor injected. Process ID information is
|
||||
// also available at this layer. Due to technical limitations, the WINDIVERT_LAYER_FLOW layer
|
||||
// cannot capture flow events that occurred before the handle was opened.
|
||||
type Flow struct {
|
||||
EndpointID uint64
|
||||
ParentEndpointID uint64
|
||||
ProcessID uint32
|
||||
LocalAddress [16]uint8
|
||||
RemoteAddress [16]uint8
|
||||
LocalPort uint16
|
||||
RemotePort uint16
|
||||
Protocol uint8
|
||||
_ [3]uint8
|
||||
_ uint32
|
||||
}
|
||||
|
||||
// Reflect is ...
|
||||
// Finally, the WINDIVERT_LAYER_REFLECT layer can capture events relating to WinDivert itself,
|
||||
// such as when another process opens a new WinDivert handle, or closes an old WinDivert handle.
|
||||
// WinDivert events can be captured but not injected nor blocked. Process ID information
|
||||
// (of the process responsible for opening the WinDivert handle) is available at this layer.
|
||||
// This layer also returns data in the form of an "object" representation of the filter string
|
||||
// used to open the handle. The object representation can be converted back into a human-readable
|
||||
// filter string using the WinDivertHelperFormatFilter() function. This layer can also capture
|
||||
// events that occurred before the handle was opened. This layer cannot capture events related
|
||||
// to other WINDIVERT_LAYER_REFLECT-layer handles.
|
||||
type Reflect struct {
|
||||
TimeStamp int64
|
||||
ProcessID uint32
|
||||
layer uint32
|
||||
Flags uint64
|
||||
Priority int16
|
||||
_ int16
|
||||
_ int32
|
||||
_ [4]uint64
|
||||
}
|
||||
|
||||
// Layer is ...
|
||||
func (r *Reflect) Layer() Layer {
|
||||
return Layer(r.layer)
|
||||
}
|
||||
|
||||
// Address is ...
|
||||
type Address struct {
|
||||
Timestamp int64
|
||||
Bitfield uint32 // Layer/Event/Sniffed/Outbound/Loopback/Impostor/IPv6/Checksums/Reserved1
|
||||
Reserved2 uint32 // 4 字节
|
||||
union [64]uint8
|
||||
}
|
||||
|
||||
func (a *Address) Clone() *Address {
|
||||
b := new(Address)
|
||||
b.Timestamp = a.Timestamp
|
||||
b.Bitfield = a.Bitfield
|
||||
b.Reserved2 = a.Reserved2
|
||||
b.union = a.union
|
||||
return b
|
||||
}
|
||||
|
||||
func (a *Address) Layer() uint8 {
|
||||
return uint8(a.Bitfield & 0xFF)
|
||||
}
|
||||
|
||||
func (a *Address) Event() uint8 {
|
||||
return uint8((a.Bitfield >> 8) & 0xFF)
|
||||
}
|
||||
|
||||
func (a *Address) Sniffed() bool {
|
||||
return (a.Bitfield>>16)&1 == 1
|
||||
}
|
||||
|
||||
func (a *Address) Outbound() bool {
|
||||
return (a.Bitfield>>17)&1 == 1
|
||||
}
|
||||
|
||||
func (a *Address) Loopback() bool {
|
||||
return (a.Bitfield>>18)&1 == 1
|
||||
}
|
||||
|
||||
func (a *Address) Impostor() bool {
|
||||
return (a.Bitfield>>19)&1 == 1
|
||||
}
|
||||
|
||||
func (a *Address) IPv6() bool {
|
||||
return (a.Bitfield>>20)&1 == 1
|
||||
}
|
||||
|
||||
func (a *Address) IPChecksum() bool {
|
||||
return (a.Bitfield>>21)&1 == 1
|
||||
}
|
||||
|
||||
func (a *Address) TCPChecksum() bool {
|
||||
return (a.Bitfield>>22)&1 == 1
|
||||
}
|
||||
|
||||
func (a *Address) UDPChecksum() bool {
|
||||
return (a.Bitfield>>23)&1 == 1
|
||||
}
|
||||
|
||||
func (a *Address) SetLayer(v uint8) {
|
||||
a.Bitfield = (a.Bitfield &^ 0xFF) | uint32(v)
|
||||
}
|
||||
|
||||
func (a *Address) SetEvent(v uint8) {
|
||||
a.Bitfield = (a.Bitfield &^ (0xFF << 8)) | (uint32(v) << 8)
|
||||
}
|
||||
|
||||
func (a *Address) SetSniffed(v bool) {
|
||||
if v {
|
||||
a.Bitfield |= 1 << 16
|
||||
} else {
|
||||
a.Bitfield &^= 1 << 16
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Address) SetOutbound(v bool) {
|
||||
if v {
|
||||
a.Bitfield |= 1 << 17
|
||||
} else {
|
||||
a.Bitfield &^= 1 << 17
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Address) SetLoopback(v bool) {
|
||||
if v {
|
||||
a.Bitfield |= 1 << 18
|
||||
} else {
|
||||
a.Bitfield &^= 1 << 18
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Address) SetImpostor(v bool) {
|
||||
if v {
|
||||
a.Bitfield |= 1 << 19
|
||||
} else {
|
||||
a.Bitfield &^= 1 << 19
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Address) SetIPv6(v bool) {
|
||||
if v {
|
||||
a.Bitfield |= 1 << 20
|
||||
} else {
|
||||
a.Bitfield &^= 1 << 20
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Address) SetIPChecksum(v bool) {
|
||||
if v {
|
||||
a.Bitfield |= 1 << 21
|
||||
} else {
|
||||
a.Bitfield &^= 1 << 21
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Address) SetTCPChecksum(v bool) {
|
||||
if v {
|
||||
a.Bitfield |= 1 << 22
|
||||
} else {
|
||||
a.Bitfield &^= 1 << 22
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Address) SetUDPChecksum(v bool) {
|
||||
if v {
|
||||
a.Bitfield |= 1 << 23
|
||||
} else {
|
||||
a.Bitfield &^= 1 << 23
|
||||
}
|
||||
}
|
||||
|
||||
// Ethernet is ...
|
||||
func (a *Address) Ethernet() *Ethernet {
|
||||
return (*Ethernet)(unsafe.Pointer(&a.union))
|
||||
}
|
||||
|
||||
// Network is ...
|
||||
func (a *Address) Network() *Network {
|
||||
return (*Network)(unsafe.Pointer(&a.union))
|
||||
}
|
||||
|
||||
// Socket is ...
|
||||
func (a *Address) Socket() *Socket {
|
||||
return (*Socket)(unsafe.Pointer(&a.union))
|
||||
}
|
||||
|
||||
// Flow is ...
|
||||
func (a *Address) Flow() *Flow {
|
||||
return (*Flow)(unsafe.Pointer(&a.union))
|
||||
}
|
||||
|
||||
// Reflect is ...
|
||||
func (a *Address) Reflect() *Reflect {
|
||||
return (*Reflect)(unsafe.Pointer(&a.union))
|
||||
}
|
||||
249
src/ProcessDrv/tun/WinDivert/conn.go
Normal file
249
src/ProcessDrv/tun/WinDivert/conn.go
Normal file
@@ -0,0 +1,249 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package WinDivert
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DevConn struct {
|
||||
// 标识:客户端和伪服务端的四元组
|
||||
clientIP net.IP
|
||||
clientPort uint16
|
||||
serverIP net.IP
|
||||
serverPort uint16
|
||||
|
||||
// TCP 序列号跟踪
|
||||
clientNext uint32 // 客户端下一个期望的 seq
|
||||
serverISN uint32 // 我们伪造的 server 初始序列号
|
||||
serverSeqNext uint32 // 我们发送给客户端时的 seq
|
||||
|
||||
// 缓存和同步
|
||||
buff bytes.Buffer
|
||||
mu sync.Mutex
|
||||
closed bool
|
||||
// 通知 channel:避免每次等待都 spawn goroutine
|
||||
dataCh chan struct{}
|
||||
// deadline
|
||||
_outRead time.Time
|
||||
_outWrite time.Time
|
||||
|
||||
// 记录已发 ack
|
||||
highestClientAckSent uint32
|
||||
|
||||
// 底层 WinDivert handle 和最后捕获的地址
|
||||
h *Handle
|
||||
lastAddr *Address
|
||||
v4 bool
|
||||
pid uint32
|
||||
}
|
||||
|
||||
func (d *DevConn) GetRemoteAddress() string {
|
||||
/*
|
||||
a := getDnsValue(d.serverIP.String())
|
||||
if a != "" {
|
||||
return net.JoinHostPort(a, strconv.Itoa(int(d.serverPort)))
|
||||
}
|
||||
*/
|
||||
return net.JoinHostPort(d.serverIP.String(), strconv.Itoa(int(d.serverPort)))
|
||||
}
|
||||
|
||||
func (d *DevConn) GetRemotePort() uint16 {
|
||||
return d.serverPort
|
||||
}
|
||||
|
||||
func (d *DevConn) GetPid() string {
|
||||
return strconv.Itoa(int(d.pid))
|
||||
}
|
||||
|
||||
func (d *DevConn) IsV6() bool {
|
||||
return !d.v4
|
||||
}
|
||||
|
||||
func (d *DevConn) ID() uint64 {
|
||||
return uint64(d.clientPort)
|
||||
}
|
||||
|
||||
// 构造函数
|
||||
func NewDevConn(h *Handle, clientIP net.IP, clientPort uint16, serverIP net.IP, serverPort uint16, ipv4 bool, addr *Address, seq, ack uint32) *DevConn {
|
||||
d := &DevConn{
|
||||
clientIP: clientIP,
|
||||
clientPort: clientPort,
|
||||
serverIP: serverIP,
|
||||
serverPort: serverPort,
|
||||
dataCh: make(chan struct{}, 1),
|
||||
h: h,
|
||||
v4: ipv4,
|
||||
lastAddr: addr,
|
||||
serverSeqNext: seq,
|
||||
clientNext: ack,
|
||||
}
|
||||
d.serverISN = rand.Uint32()
|
||||
d.serverSeqNext = d.serverISN + 1
|
||||
return d
|
||||
}
|
||||
|
||||
// --- net.Conn 接口实现 ---
|
||||
|
||||
// Read 从缓冲区读取客户端发来的数据
|
||||
func (d *DevConn) Read(b []byte) (int, error) {
|
||||
a1, a2 := d.read(b)
|
||||
return a1, a2
|
||||
}
|
||||
|
||||
// Read 从缓冲区读取客户端发来的数据(使用 dataCh 通知,避免额外 goroutine)
|
||||
func (d *DevConn) read(b []byte) (int, error) {
|
||||
for {
|
||||
d.mu.Lock()
|
||||
if d.buff.Len() > 0 {
|
||||
n, _ := d.buff.Read(b)
|
||||
d.mu.Unlock()
|
||||
return n, nil
|
||||
}
|
||||
if d.closed {
|
||||
d.mu.Unlock()
|
||||
return 0, io.EOF
|
||||
}
|
||||
// 拿出 deadline 本地变量,避免在 select 中访问共享状态
|
||||
deadline := d._outRead
|
||||
d.mu.Unlock()
|
||||
|
||||
if deadline.IsZero() {
|
||||
// 阻塞等待通知
|
||||
<-d.dataCh
|
||||
// loop to check buffer
|
||||
continue
|
||||
}
|
||||
|
||||
// 有 deadline,则等待 dataCh 或超时
|
||||
now := time.Now()
|
||||
if !deadline.After(now) {
|
||||
return 0, os.ErrDeadlineExceeded
|
||||
}
|
||||
timer := time.NewTimer(time.Until(deadline))
|
||||
select {
|
||||
case <-d.dataCh:
|
||||
if !timer.Stop() {
|
||||
<-timer.C
|
||||
}
|
||||
// loop to read
|
||||
case <-timer.C:
|
||||
return 0, os.ErrDeadlineExceeded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write 将数据发回客户端(通过 WinDivert 注入包)
|
||||
func (d *DevConn) Write(b []byte) (int, error) {
|
||||
// 写超时检查
|
||||
if !d._outWrite.IsZero() && time.Now().After(d._outWrite) {
|
||||
return 0, os.ErrDeadlineExceeded
|
||||
}
|
||||
n, err := SendDataToClient(d.h, d, b, d.lastAddr)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Close 关闭连接:注入 FIN 并清理
|
||||
func (d *DevConn) Close() error {
|
||||
d.mu.Lock()
|
||||
already := d.closed
|
||||
lastAddr := d.lastAddr
|
||||
d.closed = true
|
||||
// signal readers (non-blocking send to channel)
|
||||
select {
|
||||
case d.dataCh <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
d.mu.Unlock()
|
||||
if already {
|
||||
return nil
|
||||
}
|
||||
if lastAddr != nil {
|
||||
_ = SendFinToClient(d.h, d)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoteAddr 返回真实的 server 地址
|
||||
func (d *DevConn) RemoteAddr() net.Addr {
|
||||
return &net.TCPAddr{
|
||||
IP: d.clientIP,
|
||||
Port: int(d.clientPort),
|
||||
}
|
||||
/*
|
||||
return &net.TCPAddr{
|
||||
IP: d.serverIP,
|
||||
Port: int(d.serverPort),
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// LocalAddr 返回伪造的 client 地址
|
||||
func (d *DevConn) LocalAddr() net.Addr {
|
||||
return &net.TCPAddr{
|
||||
IP: d.clientIP,
|
||||
Port: int(d.clientPort),
|
||||
}
|
||||
}
|
||||
|
||||
// SetDeadline 同时设置读写超时
|
||||
func (d *DevConn) SetDeadline(t time.Time) error {
|
||||
_ = d.SetReadDeadline(t)
|
||||
_ = d.SetWriteDeadline(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetReadDeadline 设置读超时
|
||||
func (d *DevConn) SetReadDeadline(t time.Time) error {
|
||||
d.mu.Lock()
|
||||
d._outRead = t
|
||||
d.mu.Unlock()
|
||||
select {
|
||||
case d.dataCh <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetWriteDeadline 设置写超时
|
||||
func (d *DevConn) SetWriteDeadline(t time.Time) error {
|
||||
d.mu.Lock()
|
||||
d._outWrite = t
|
||||
d.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DevConn) PushClientPayload(payload []byte, seq uint32) {
|
||||
defer func() {
|
||||
d.mu.Lock()
|
||||
clientNext := d.clientNext
|
||||
d.mu.Unlock()
|
||||
if clientNext != 0 {
|
||||
_ = SendAckToKernel(d.h, d, clientNext, d.lastAddr)
|
||||
}
|
||||
}()
|
||||
if len(payload) == 0 {
|
||||
// 仍更新 seq
|
||||
d.mu.Lock()
|
||||
d.clientNext = seq + uint32(len(payload))
|
||||
d.mu.Unlock()
|
||||
return
|
||||
}
|
||||
d.mu.Lock()
|
||||
d.buff.Write(payload)
|
||||
d.clientNext = seq + uint32(len(payload))
|
||||
// 非阻塞通知
|
||||
select {
|
||||
case d.dataCh <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
d.mu.Unlock()
|
||||
}
|
||||
90
src/ProcessDrv/tun/WinDivert/const.go
Normal file
90
src/ProcessDrv/tun/WinDivert/const.go
Normal file
@@ -0,0 +1,90 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package WinDivert
|
||||
|
||||
type Layer int
|
||||
|
||||
func (l Layer) String() string {
|
||||
switch l {
|
||||
case LayerNetwork:
|
||||
return "WINDIVERT_LAYER_NETWORK"
|
||||
case LayerNetworkForward:
|
||||
return "WINDIVERT_LAYER_NETWORK_FORWARD"
|
||||
case LayerFlow:
|
||||
return "WINDIVERT_LAYER_FLOW"
|
||||
case LayerSocket:
|
||||
return "WINDIVERT_LAYER_SOCKET"
|
||||
case LayerReflect:
|
||||
return "WINDIVERT_LAYER_REFLECT"
|
||||
//case LayerEthernet:
|
||||
// return "WINDIVERT_LAYER_ETHERNET"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
type Event int
|
||||
|
||||
func (e Event) String() string {
|
||||
switch e {
|
||||
case EventNetworkPacket:
|
||||
return "WINDIVERT_EVENT_NETWORK_PACKET"
|
||||
case EventFlowEstablished:
|
||||
return "WINDIVERT_EVENT_FLOW_ESTABLISHED"
|
||||
case EventFlowDeleted:
|
||||
return "WINDIVERT_EVENT_FLOW_DELETED"
|
||||
case EventSocketBind:
|
||||
return "WINDIVERT_EVENT_SOCKET_BIND"
|
||||
case EventSocketConnect:
|
||||
return "WINDIVERT_EVENT_SOCKET_CONNECT"
|
||||
case EventSocketListen:
|
||||
return "WINDIVERT_EVENT_SOCKET_LISTEN"
|
||||
case EventSocketAccept:
|
||||
return "WINDIVERT_EVENT_SOCKET_ACCEPT"
|
||||
case EventSocketClose:
|
||||
return "WINDIVERT_EVENT_SOCKET_CLOSE"
|
||||
case EventReflectOpen:
|
||||
return "WINDIVERT_EVENT_REFLECT_OPEN"
|
||||
case EventReflectClose:
|
||||
return "WINDIVERT_EVENT_REFLECT_CLOSE"
|
||||
//case EventEthernetFrame:
|
||||
// return "WINDIVERT_EVENT_ETHERNET_FRAME"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
type Shutdown int
|
||||
|
||||
func (s Shutdown) String() string {
|
||||
switch s {
|
||||
case ShutdownRecv:
|
||||
return "WINDIVERT_SHUTDOWN_RECV"
|
||||
case ShutdownSend:
|
||||
return "WINDIVERT_SHUTDOWN_SEND"
|
||||
case ShutdownBoth:
|
||||
return "WINDIVERT_SHUTDOWN_BOTH"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
type Param int
|
||||
|
||||
func (p Param) String() string {
|
||||
switch p {
|
||||
case QueueLength:
|
||||
return "WINDIVERT_PARAM_QUEUE_LENGTH"
|
||||
case QueueTime:
|
||||
return "WINDIVERT_PARAM_QUEUE_TIME"
|
||||
case QueueSize:
|
||||
return "WINDIVERT_PARAM_QUEUE_SIZE"
|
||||
case VersionMajor:
|
||||
return "WINDIVERT_PARAM_VERSION_MAJOR"
|
||||
case VersionMinor:
|
||||
return "WINDIVERT_PARAM_VERSION_MINOR"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
84
src/ProcessDrv/tun/WinDivert/const_cgo.go
Normal file
84
src/ProcessDrv/tun/WinDivert/const_cgo.go
Normal file
@@ -0,0 +1,84 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package WinDivert
|
||||
|
||||
// #cgo CFLAGS: -I${SRCDIR}/divert -Wno-incompatible-pointer-types
|
||||
// #include "windivert.h"
|
||||
import "C"
|
||||
|
||||
const (
|
||||
LayerNetwork = Layer(C.WINDIVERT_LAYER_NETWORK)
|
||||
LayerNetworkForward = Layer(C.WINDIVERT_LAYER_NETWORK_FORWARD)
|
||||
LayerFlow = Layer(C.WINDIVERT_LAYER_FLOW)
|
||||
LayerSocket = Layer(C.WINDIVERT_LAYER_SOCKET)
|
||||
LayerReflect = Layer(C.WINDIVERT_LAYER_REFLECT)
|
||||
//LayerEthernet = Layer(C.WINDIVERT_LAYER_ETHERNET)
|
||||
)
|
||||
|
||||
const (
|
||||
EventNetworkPacket = Event(C.WINDIVERT_EVENT_NETWORK_PACKET)
|
||||
EventFlowEstablished = Event(C.WINDIVERT_EVENT_FLOW_ESTABLISHED)
|
||||
EventFlowDeleted = Event(C.WINDIVERT_EVENT_FLOW_DELETED)
|
||||
EventSocketBind = Event(C.WINDIVERT_EVENT_SOCKET_BIND)
|
||||
EventSocketConnect = Event(C.WINDIVERT_EVENT_SOCKET_CONNECT)
|
||||
EventSocketListen = Event(C.WINDIVERT_EVENT_SOCKET_LISTEN)
|
||||
EventSocketAccept = Event(C.WINDIVERT_EVENT_SOCKET_ACCEPT)
|
||||
EventSocketClose = Event(C.WINDIVERT_EVENT_SOCKET_CLOSE)
|
||||
EventReflectOpen = Event(C.WINDIVERT_EVENT_REFLECT_OPEN)
|
||||
EventReflectClose = Event(C.WINDIVERT_EVENT_REFLECT_CLOSE)
|
||||
//EventEthernetFrame = Event(C.WINDIVERT_EVENT_ETHERNET_FRAME)
|
||||
)
|
||||
|
||||
const (
|
||||
ShutdownRecv = Shutdown(C.WINDIVERT_SHUTDOWN_RECV)
|
||||
ShutdownSend = Shutdown(C.WINDIVERT_SHUTDOWN_SEND)
|
||||
ShutdownBoth = Shutdown(C.WINDIVERT_SHUTDOWN_BOTH)
|
||||
)
|
||||
|
||||
const (
|
||||
QueueLength = Param(C.WINDIVERT_PARAM_QUEUE_LENGTH)
|
||||
QueueTime = Param(C.WINDIVERT_PARAM_QUEUE_TIME)
|
||||
QueueSize = Param(C.WINDIVERT_PARAM_QUEUE_SIZE)
|
||||
VersionMajor = Param(C.WINDIVERT_PARAM_VERSION_MAJOR)
|
||||
VersionMinor = Param(C.WINDIVERT_PARAM_VERSION_MINOR)
|
||||
)
|
||||
|
||||
const (
|
||||
FlagDefault = uint64(0)
|
||||
FlagSniff = uint64(C.WINDIVERT_FLAG_SNIFF)
|
||||
FlagDrop = uint64(C.WINDIVERT_FLAG_DROP)
|
||||
FlagRecvOnly = uint64(C.WINDIVERT_FLAG_RECV_ONLY)
|
||||
FlagSendOnly = uint64(C.WINDIVERT_FLAG_SEND_ONLY)
|
||||
FlagNoInstall = uint64(C.WINDIVERT_FLAG_NO_INSTALL)
|
||||
FlagFragments = uint64(C.WINDIVERT_FLAG_FRAGMENTS)
|
||||
)
|
||||
|
||||
const (
|
||||
PriorityDefault = int16(0)
|
||||
PriorityHighest = int16(C.WINDIVERT_PRIORITY_HIGHEST)
|
||||
PriorityLowest = int16(C.WINDIVERT_PRIORITY_LOWEST)
|
||||
QueueLengthDefault = uint64(C.WINDIVERT_PARAM_QUEUE_LENGTH_DEFAULT)
|
||||
QueueLengthMin = uint64(C.WINDIVERT_PARAM_QUEUE_LENGTH_MIN)
|
||||
QueueLengthMax = uint64(C.WINDIVERT_PARAM_QUEUE_LENGTH_MAX)
|
||||
QueueTimeDefault = uint64(C.WINDIVERT_PARAM_QUEUE_TIME_DEFAULT)
|
||||
QueueTimeMin = uint64(C.WINDIVERT_PARAM_QUEUE_TIME_MIN)
|
||||
QueueTimeMax = uint64(C.WINDIVERT_PARAM_QUEUE_TIME_MAX)
|
||||
QueueSizeDefault = uint64(C.WINDIVERT_PARAM_QUEUE_SIZE_DEFAULT)
|
||||
QueueSizeMin = uint64(C.WINDIVERT_PARAM_QUEUE_SIZE_MIN)
|
||||
QueueSizeMax = uint64(C.WINDIVERT_PARAM_QUEUE_SIZE_MAX)
|
||||
)
|
||||
|
||||
const (
|
||||
ChecksumDefault = uint64(0)
|
||||
NoIPChecksum = uint64(C.WINDIVERT_HELPER_NO_IP_CHECKSUM)
|
||||
NoICMPChecksum = uint64(C.WINDIVERT_HELPER_NO_ICMP_CHECKSUM)
|
||||
NoICMPV6Checksum = uint64(C.WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM)
|
||||
NoTCPChecksum = uint64(C.WINDIVERT_HELPER_NO_TCP_CHECKSUM)
|
||||
NoUDPChecksum = uint64(C.WINDIVERT_HELPER_NO_UDP_CHECKSUM)
|
||||
)
|
||||
|
||||
const (
|
||||
BatchMax = int(C.WINDIVERT_BATCH_MAX)
|
||||
MTUMax = int(C.WINDIVERT_MTU_MAX)
|
||||
)
|
||||
92
src/ProcessDrv/tun/WinDivert/device.go
Normal file
92
src/ProcessDrv/tun/WinDivert/device.go
Normal file
@@ -0,0 +1,92 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package WinDivert
|
||||
|
||||
type CtlCode uint32
|
||||
|
||||
const (
|
||||
METHOD_IN_DIRECT = 1
|
||||
METHOD_OUT_DIRECT = 2
|
||||
)
|
||||
|
||||
const (
|
||||
FILE_READ_DATA = 1
|
||||
FILE_WRITE_DATA = 2
|
||||
)
|
||||
|
||||
const FILE_DEVICE_NETWORK = 0x00000012
|
||||
|
||||
const (
|
||||
ioCtlInitialize = CtlCode(((FILE_DEVICE_NETWORK) << 16) | ((FILE_READ_DATA | FILE_WRITE_DATA) << 14) | ((0x921) << 2) | (METHOD_OUT_DIRECT))
|
||||
ioCtlStartup = CtlCode(((FILE_DEVICE_NETWORK) << 16) | ((FILE_READ_DATA | FILE_WRITE_DATA) << 14) | ((0x922) << 2) | (METHOD_IN_DIRECT))
|
||||
ioCtlRecv = CtlCode(((FILE_DEVICE_NETWORK) << 16) | ((FILE_READ_DATA) << 14) | ((0x923) << 2) | (METHOD_OUT_DIRECT))
|
||||
ioCtlSend = CtlCode(((FILE_DEVICE_NETWORK) << 16) | ((FILE_READ_DATA | FILE_WRITE_DATA) << 14) | ((0x924) << 2) | (METHOD_IN_DIRECT))
|
||||
ioCtlSetParam = CtlCode(((FILE_DEVICE_NETWORK) << 16) | ((FILE_READ_DATA | FILE_WRITE_DATA) << 14) | ((0x925) << 2) | (METHOD_IN_DIRECT))
|
||||
ioCtlGetParam = CtlCode(((FILE_DEVICE_NETWORK) << 16) | ((FILE_READ_DATA) << 14) | ((0x926) << 2) | (METHOD_OUT_DIRECT))
|
||||
ioCtlShutdown = CtlCode(((FILE_DEVICE_NETWORK) << 16) | ((FILE_READ_DATA | FILE_WRITE_DATA) << 14) | ((0x927) << 2) | (METHOD_IN_DIRECT))
|
||||
)
|
||||
|
||||
func (c CtlCode) String() string {
|
||||
switch c {
|
||||
case ioCtlInitialize:
|
||||
return "IOCTL_WINDIVERT_INITIALIZE"
|
||||
case ioCtlStartup:
|
||||
return "IOCTL_WINDIVERT_STARTUP"
|
||||
case ioCtlRecv:
|
||||
return "IOCTL_WINDIVERT_RECV"
|
||||
case ioCtlSend:
|
||||
return "IOCTL_WINDIVERT_SEND"
|
||||
case ioCtlSetParam:
|
||||
return "IOCTL_WINDIVERT_SET_PARAM"
|
||||
case ioCtlGetParam:
|
||||
return "IOCTL_WINDIVERT_GET_PARAM"
|
||||
case ioCtlShutdown:
|
||||
return "IOCTL_WINDIVERT_SHUTDOWN"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
type ioCtl struct {
|
||||
b1, b2, b3, b4 uint32
|
||||
}
|
||||
|
||||
type recv struct {
|
||||
Addr uint64
|
||||
AddrLenPtr uint64
|
||||
}
|
||||
|
||||
type send struct {
|
||||
Addr uint64
|
||||
AddrLen uint64
|
||||
}
|
||||
|
||||
type initialize struct {
|
||||
Layer uint32
|
||||
Priority uint32
|
||||
Flags uint64
|
||||
}
|
||||
|
||||
type startup struct {
|
||||
Flags uint64
|
||||
_ uint64
|
||||
}
|
||||
|
||||
type shutdown struct {
|
||||
How uint32
|
||||
_ uint32
|
||||
_ uint64
|
||||
}
|
||||
|
||||
type getParam struct {
|
||||
Param uint32
|
||||
_ uint32
|
||||
Value uint64
|
||||
}
|
||||
|
||||
type setParam struct {
|
||||
Value uint64
|
||||
Param uint32
|
||||
_ uint32
|
||||
}
|
||||
207
src/ProcessDrv/tun/WinDivert/divert.go
Normal file
207
src/ProcessDrv/tun/WinDivert/divert.go
Normal file
@@ -0,0 +1,207 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package WinDivert
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var once = sync.Once{}
|
||||
|
||||
// GerVersionInfo is ...
|
||||
func GetVersionInfo() (ver string, err error) {
|
||||
h, err := Open("false", LayerNetwork, PriorityDefault, FlagDefault)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
err = h.Close()
|
||||
}()
|
||||
|
||||
major, err := h.GetParam(VersionMajor)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
minor, err := h.GetParam(VersionMinor)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ver = strings.Join([]string{strconv.Itoa(int(major)), strconv.Itoa(int(minor))}, ".")
|
||||
return
|
||||
}
|
||||
|
||||
func ioControlEx(h windows.Handle, code CtlCode, ioctl unsafe.Pointer, buf *byte, bufLen uint32, overlapped *windows.Overlapped) (iolen uint32, err error) {
|
||||
err = windows.DeviceIoControl(h, uint32(code), (*byte)(ioctl), uint32(unsafe.Sizeof(ioCtl{})), buf, bufLen, &iolen, overlapped)
|
||||
if err != windows.ERROR_IO_PENDING {
|
||||
return
|
||||
}
|
||||
|
||||
err = windows.GetOverlappedResult(h, overlapped, &iolen, true)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ioControl(h windows.Handle, code CtlCode, ioctl unsafe.Pointer, buf *byte, bufLen uint32) (iolen uint32, err error) {
|
||||
event, _ := windows.CreateEvent(nil, 0, 0, nil)
|
||||
|
||||
overlapped := windows.Overlapped{
|
||||
HEvent: event,
|
||||
}
|
||||
|
||||
iolen, err = ioControlEx(h, code, ioctl, buf, bufLen, &overlapped)
|
||||
|
||||
windows.CloseHandle(event)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle is ...
|
||||
type Handle struct {
|
||||
sync.Mutex
|
||||
windows.Handle
|
||||
rOverlapped windows.Overlapped
|
||||
wOverlapped windows.Overlapped
|
||||
}
|
||||
|
||||
// Recv is ...
|
||||
func (h *Handle) Recv(buffer []byte, address *Address) (uint, error) {
|
||||
addrLen := uint(unsafe.Sizeof(Address{}))
|
||||
recv := recv{
|
||||
Addr: uint64(uintptr(unsafe.Pointer(address))),
|
||||
AddrLenPtr: uint64(uintptr(unsafe.Pointer(&addrLen))),
|
||||
}
|
||||
|
||||
iolen, err := ioControlEx(h.Handle, ioCtlRecv, unsafe.Pointer(&recv), &buffer[0], uint32(len(buffer)), &h.rOverlapped)
|
||||
if err != nil {
|
||||
return uint(iolen), Error(err.(windows.Errno))
|
||||
}
|
||||
|
||||
return uint(iolen), nil
|
||||
}
|
||||
|
||||
// RecvEx is ...
|
||||
func (h *Handle) RecvEx(buffer []byte, address []Address) (uint, uint, error) {
|
||||
addrLen := uint(len(address)) * uint(unsafe.Sizeof(Address{}))
|
||||
recv := recv{
|
||||
Addr: uint64(uintptr(unsafe.Pointer(&address[0]))),
|
||||
AddrLenPtr: uint64(uintptr(unsafe.Pointer(&addrLen))),
|
||||
}
|
||||
|
||||
iolen, err := ioControlEx(h.Handle, ioCtlRecv, unsafe.Pointer(&recv), &buffer[0], uint32(len(buffer)), &h.rOverlapped)
|
||||
if err != nil {
|
||||
return uint(iolen), addrLen / uint(unsafe.Sizeof(Address{})), Error(err.(windows.Errno))
|
||||
}
|
||||
|
||||
return uint(iolen), addrLen / uint(unsafe.Sizeof(Address{})), nil
|
||||
}
|
||||
|
||||
// Send is ...
|
||||
func (h *Handle) Send(buffer []byte, address *Address) (uint, error) {
|
||||
send := send{
|
||||
Addr: uint64(uintptr(unsafe.Pointer(address))),
|
||||
AddrLen: uint64(unsafe.Sizeof(Address{})),
|
||||
}
|
||||
|
||||
iolen, err := ioControlEx(h.Handle, ioCtlSend, unsafe.Pointer(&send), &buffer[0], uint32(len(buffer)), &h.wOverlapped)
|
||||
if err != nil {
|
||||
return uint(iolen), Error(err.(windows.Errno))
|
||||
}
|
||||
|
||||
return uint(iolen), nil
|
||||
}
|
||||
|
||||
// SendEx is ...
|
||||
func (h *Handle) SendEx(buffer []byte, address []Address) (uint, error) {
|
||||
send := send{
|
||||
Addr: uint64(uintptr(unsafe.Pointer(&address[0]))),
|
||||
AddrLen: uint64(unsafe.Sizeof(Address{})) * uint64(len(address)),
|
||||
}
|
||||
|
||||
iolen, err := ioControlEx(h.Handle, ioCtlSend, unsafe.Pointer(&send), &buffer[0], uint32(len(buffer)), &h.wOverlapped)
|
||||
if err != nil {
|
||||
return uint(iolen), Error(err.(windows.Errno))
|
||||
}
|
||||
|
||||
return uint(iolen), nil
|
||||
}
|
||||
|
||||
// Shutdown is ...
|
||||
func (h *Handle) Shutdown(how Shutdown) error {
|
||||
shutdown := shutdown{
|
||||
How: uint32(how),
|
||||
}
|
||||
|
||||
_, err := ioControl(h.Handle, ioCtlShutdown, unsafe.Pointer(&shutdown), nil, 0)
|
||||
if err != nil {
|
||||
return Error(err.(windows.Errno))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close is ...
|
||||
func (h *Handle) Close() error {
|
||||
windows.CloseHandle(h.rOverlapped.HEvent)
|
||||
windows.CloseHandle(h.wOverlapped.HEvent)
|
||||
|
||||
err := windows.CloseHandle(h.Handle)
|
||||
if err != nil {
|
||||
return Error(err.(windows.Errno))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetParam is ...
|
||||
func (h *Handle) GetParam(p Param) (uint64, error) {
|
||||
getParam := getParam{
|
||||
Param: uint32(p),
|
||||
Value: 0,
|
||||
}
|
||||
|
||||
_, err := ioControl(h.Handle, ioCtlGetParam, unsafe.Pointer(&getParam), (*byte)(unsafe.Pointer(&getParam.Value)), uint32(unsafe.Sizeof(getParam.Value)))
|
||||
if err != nil {
|
||||
return getParam.Value, Error(err.(windows.Errno))
|
||||
}
|
||||
|
||||
return getParam.Value, nil
|
||||
}
|
||||
|
||||
// SetParam is ...
|
||||
func (h *Handle) SetParam(p Param, v uint64) error {
|
||||
switch p {
|
||||
case QueueLength:
|
||||
if v < QueueLengthMin || v > QueueLengthMax {
|
||||
return errQueueLength
|
||||
}
|
||||
case QueueTime:
|
||||
if v < QueueTimeMin || v > QueueTimeMax {
|
||||
return errQueueTime
|
||||
}
|
||||
case QueueSize:
|
||||
if v < QueueSizeMin || v > QueueSizeMax {
|
||||
return errQueueSize
|
||||
}
|
||||
default:
|
||||
return errQueueParam
|
||||
}
|
||||
|
||||
setParam := setParam{
|
||||
Value: v,
|
||||
Param: uint32(p),
|
||||
}
|
||||
|
||||
_, err := ioControl(h.Handle, ioCtlSetParam, unsafe.Pointer(&setParam), nil, 0)
|
||||
if err != nil {
|
||||
return Error(err.(windows.Errno))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
1191
src/ProcessDrv/tun/WinDivert/divert/LICENSE
Normal file
1191
src/ProcessDrv/tun/WinDivert/divert/LICENSE
Normal file
File diff suppressed because it is too large
Load Diff
3
src/ProcessDrv/tun/WinDivert/divert/divert.go
Normal file
3
src/ProcessDrv/tun/WinDivert/divert/divert.go
Normal file
@@ -0,0 +1,3 @@
|
||||
//go:build windows
|
||||
|
||||
package divert
|
||||
988
src/ProcessDrv/tun/WinDivert/divert/windivert.c
Normal file
988
src/ProcessDrv/tun/WinDivert/divert/windivert.c
Normal file
@@ -0,0 +1,988 @@
|
||||
/*
|
||||
* windivert.c
|
||||
* (C) 2019, all rights reserved,
|
||||
*
|
||||
* This file is part of WinDivert.
|
||||
*
|
||||
* WinDivert is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* WinDivert is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef WINDIVERTEXPORT
|
||||
#define WINDIVERTEXPORT extern
|
||||
#endif
|
||||
#include "windivert.h"
|
||||
#include "windivert_device.h"
|
||||
|
||||
#define WINDIVERT_DRIVER_NAME L"WinDivert"
|
||||
#define WINDIVERT_DRIVER32_SYS L"\\" WINDIVERT_DRIVER_NAME L"32.sys"
|
||||
#define WINDIVERT_DRIVER64_SYS L"\\" WINDIVERT_DRIVER_NAME L"64.sys"
|
||||
#define WINDIVERT_VERSION_MAJOR_MIN 2
|
||||
|
||||
#ifndef ERROR_DRIVER_FAILED_PRIOR_UNLOAD
|
||||
#define ERROR_DRIVER_FAILED_PRIOR_UNLOAD ((DWORD)654)
|
||||
#endif
|
||||
|
||||
static BOOLEAN WinDivertIsDigit(char c);
|
||||
static BOOLEAN WinDivertIsXDigit(char c);
|
||||
static BOOLEAN WinDivertIsSpace(char c);
|
||||
static BOOLEAN WinDivertIsAlNum(char c);
|
||||
static char WinDivertToLower(char c);
|
||||
static BOOLEAN WinDivertStrLen(const wchar_t *s, size_t maxlen,
|
||||
size_t *lenptr);
|
||||
static BOOLEAN WinDivertStrCpy(wchar_t *dst, size_t dstlen,
|
||||
const wchar_t *src);
|
||||
static int WinDivertStrCmp(const char *s, const char *t);
|
||||
static BOOLEAN WinDivertAToI(const char *str, char **endptr, UINT32 *intptr,
|
||||
UINT size);
|
||||
static BOOLEAN WinDivertAToX(const char *str, char **endptr, UINT32 *intptr,
|
||||
UINT size, BOOL prefix);
|
||||
static UINT32 WinDivertDivTen128(UINT32 *a);
|
||||
|
||||
/*
|
||||
* Misc.
|
||||
*/
|
||||
#ifndef UINT8_MAX
|
||||
#define UINT8_MAX 0xFF
|
||||
#endif
|
||||
#ifndef UINT16_MAX
|
||||
#define UINT16_MAX 0xFFFF
|
||||
#endif
|
||||
#ifndef UINT32_MAX
|
||||
#define UINT32_MAX 0xFFFFFFFF
|
||||
#endif
|
||||
|
||||
#define IPPROTO_MH 135
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#pragma intrinsic(memcpy)
|
||||
#pragma function(memcpy)
|
||||
void *memcpy(void *dst, const void *src, size_t n)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++)
|
||||
((UINT8 *)dst)[i] = ((const UINT8 *)src)[i];
|
||||
return dst;
|
||||
}
|
||||
|
||||
#pragma intrinsic(memset)
|
||||
#pragma function(memset)
|
||||
void *memset(void *dst, int c, size_t n)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++)
|
||||
((UINT8 *)dst)[i] = (UINT8)c;
|
||||
return dst;
|
||||
}
|
||||
|
||||
#define WINDIVERT_INLINE __forceinline
|
||||
|
||||
#else /* _MSC_VER */
|
||||
|
||||
#define WINDIVERT_INLINE __attribute__((__always_inline__)) inline
|
||||
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
/*
|
||||
* Filter interpreter config.
|
||||
*/
|
||||
static BOOL WinDivertGetData(const VOID *packet, UINT packet_len, INT min,
|
||||
INT max, INT idx, PVOID data, UINT size);
|
||||
#define WINDIVERT_GET_DATA(packet, packet_len, min, max, index, data, size) \
|
||||
WinDivertGetData((packet), (packet_len), (min), (max), (index), (data), \
|
||||
(size))
|
||||
|
||||
/*
|
||||
* Prototypes.
|
||||
*/
|
||||
static BOOLEAN WinDivertUse32Bit(void);
|
||||
static BOOLEAN WinDivertGetDriverFileName(LPWSTR sys_str);
|
||||
static BOOLEAN WinDivertDriverInstall(VOID);
|
||||
|
||||
/*
|
||||
* Include the helper API implementation.
|
||||
*/
|
||||
#include "windivert_shared.c"
|
||||
#include "windivert_helper.c"
|
||||
|
||||
/*
|
||||
* Thread local.
|
||||
*/
|
||||
static DWORD windivert_tls_idx;
|
||||
|
||||
/*
|
||||
* Current DLL hmodule.
|
||||
*/
|
||||
static HMODULE module = NULL;
|
||||
|
||||
/*
|
||||
* Dll Entry
|
||||
*/
|
||||
BOOL APIENTRY WinDivertDllEntry(HANDLE module0, DWORD reason, LPVOID reserved)
|
||||
{
|
||||
HANDLE event;
|
||||
switch (reason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
module = module0;
|
||||
if ((windivert_tls_idx = TlsAlloc()) == TLS_OUT_OF_INDEXES)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
// Fallthrough
|
||||
case DLL_THREAD_ATTACH:
|
||||
event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if (event == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
TlsSetValue(windivert_tls_idx, (LPVOID)event);
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
event = (HANDLE)TlsGetValue(windivert_tls_idx);
|
||||
if (event != (HANDLE)NULL)
|
||||
{
|
||||
CloseHandle(event);
|
||||
}
|
||||
TlsFree(windivert_tls_idx);
|
||||
break;
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
event = (HANDLE)TlsGetValue(windivert_tls_idx);
|
||||
if (event != (HANDLE)NULL)
|
||||
{
|
||||
CloseHandle(event);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test if we should use the 32-bit or 64-bit driver.
|
||||
*/
|
||||
static BOOLEAN WinDivertUse32Bit(void)
|
||||
{
|
||||
BOOL is_wow64;
|
||||
|
||||
if (sizeof(void *) == sizeof(UINT64))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (!IsWow64Process(GetCurrentProcess(), &is_wow64))
|
||||
{
|
||||
// Just guess:
|
||||
return FALSE;
|
||||
}
|
||||
return (is_wow64? FALSE: TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Locate the WinDivert driver files.
|
||||
*/
|
||||
static BOOLEAN WinDivertGetDriverFileName(LPWSTR sys_str)
|
||||
{
|
||||
size_t dir_len, sys_len;
|
||||
BOOLEAN is_32bit;
|
||||
|
||||
is_32bit = WinDivertUse32Bit();
|
||||
|
||||
if (is_32bit)
|
||||
{
|
||||
if (!WinDivertStrLen(WINDIVERT_DRIVER32_SYS, MAX_PATH, &sys_len))
|
||||
{
|
||||
SetLastError(ERROR_BAD_PATHNAME);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!WinDivertStrLen(WINDIVERT_DRIVER64_SYS, MAX_PATH, &sys_len))
|
||||
{
|
||||
SetLastError(ERROR_BAD_PATHNAME);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
dir_len = (size_t)GetModuleFileName(module, sys_str, MAX_PATH);
|
||||
if (dir_len == 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
for (; dir_len > 0 && sys_str[dir_len] != L'\\'; dir_len--)
|
||||
;
|
||||
if (sys_str[dir_len] != L'\\' || dir_len + sys_len + 1 >= MAX_PATH)
|
||||
{
|
||||
SetLastError(ERROR_BAD_PATHNAME);
|
||||
return FALSE;
|
||||
}
|
||||
if (!WinDivertStrCpy(sys_str + dir_len, MAX_PATH-dir_len-1,
|
||||
(is_32bit? WINDIVERT_DRIVER32_SYS: WINDIVERT_DRIVER64_SYS)))
|
||||
{
|
||||
SetLastError(ERROR_BAD_PATHNAME);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register event log. It is not an error if this function fails.
|
||||
*/
|
||||
static void WinDivertRegisterEventSource(const wchar_t *windivert_sys)
|
||||
{
|
||||
HKEY key;
|
||||
size_t len;
|
||||
DWORD types = 7;
|
||||
|
||||
if (!WinDivertStrLen(windivert_sys, MAX_PATH, &len))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (RegCreateKeyExA(HKEY_LOCAL_MACHINE,
|
||||
"System\\CurrentControlSet\\Services\\EventLog\\System\\WinDivert",
|
||||
0, NULL, REG_OPTION_VOLATILE, KEY_SET_VALUE, NULL, &key, NULL)
|
||||
!= ERROR_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
RegSetValueExW(key, L"EventMessageFile", 0, REG_SZ, (LPBYTE)windivert_sys,
|
||||
(len + 1) * sizeof(wchar_t));
|
||||
RegSetValueExA(key, "TypesSupported", 0, REG_DWORD, (LPBYTE)&types,
|
||||
sizeof(types));
|
||||
RegCloseKey(key);
|
||||
}
|
||||
|
||||
/*
|
||||
* Install the WinDivert driver.
|
||||
*/
|
||||
static BOOLEAN WinDivertDriverInstall(VOID)
|
||||
{
|
||||
DWORD err;
|
||||
SC_HANDLE manager = NULL, service = NULL;
|
||||
wchar_t windivert_sys[MAX_PATH+1];
|
||||
HANDLE mutex = NULL;
|
||||
BOOL success = TRUE;
|
||||
|
||||
// Create & lock a named mutex. This is to stop two processes trying
|
||||
// to start the driver at the same time.
|
||||
mutex = CreateMutex(NULL, FALSE, L"WinDivertDriverInstallMutex");
|
||||
if (mutex == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
switch (WaitForSingleObject(mutex, INFINITE))
|
||||
{
|
||||
case WAIT_OBJECT_0: case WAIT_ABANDONED:
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Open the service manager:
|
||||
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
||||
if (manager == NULL)
|
||||
{
|
||||
goto WinDivertDriverInstallExit;
|
||||
}
|
||||
|
||||
// Check if the WinDivert service already exists; if so, start it.
|
||||
service = OpenService(manager, WINDIVERT_DEVICE_NAME, SERVICE_ALL_ACCESS);
|
||||
if (service != NULL)
|
||||
{
|
||||
goto WinDivertDriverInstallExit;
|
||||
}
|
||||
|
||||
// Get driver file:
|
||||
if (!WinDivertGetDriverFileName(windivert_sys))
|
||||
{
|
||||
goto WinDivertDriverInstallExit;
|
||||
}
|
||||
|
||||
// Create the service:
|
||||
service = CreateService(manager, WINDIVERT_DEVICE_NAME,
|
||||
WINDIVERT_DEVICE_NAME, SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER,
|
||||
SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, windivert_sys, NULL, NULL,
|
||||
NULL, NULL, NULL);
|
||||
if (service == NULL)
|
||||
{
|
||||
if (GetLastError() == ERROR_SERVICE_EXISTS)
|
||||
{
|
||||
service = OpenService(manager, WINDIVERT_DEVICE_NAME,
|
||||
SERVICE_ALL_ACCESS);
|
||||
}
|
||||
goto WinDivertDriverInstallExit;
|
||||
}
|
||||
|
||||
// Register event logging:
|
||||
WinDivertRegisterEventSource(windivert_sys);
|
||||
|
||||
WinDivertDriverInstallExit:
|
||||
|
||||
success = (service != NULL);
|
||||
if (service != NULL)
|
||||
{
|
||||
// Start the service:
|
||||
success = StartService(service, 0, NULL);
|
||||
if (!success)
|
||||
{
|
||||
success = (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mark the service for deletion. This will cause the driver to
|
||||
// unload if (1) there are no more open handles, and (2) the
|
||||
// service is STOPPED or on system reboot.
|
||||
(VOID)DeleteService(service);
|
||||
}
|
||||
}
|
||||
|
||||
err = GetLastError();
|
||||
if (manager != NULL)
|
||||
{
|
||||
CloseServiceHandle(manager);
|
||||
}
|
||||
if (service != NULL)
|
||||
{
|
||||
CloseServiceHandle(service);
|
||||
}
|
||||
ReleaseMutex(mutex);
|
||||
CloseHandle(mutex);
|
||||
SetLastError(err);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform an (overlapped) DeviceIoControl.
|
||||
*/
|
||||
static BOOL WinDivertIoControlEx(HANDLE handle, DWORD code,
|
||||
PWINDIVERT_IOCTL ioctl, PVOID buf, UINT len, UINT *iolen,
|
||||
LPOVERLAPPED overlapped)
|
||||
{
|
||||
BOOL result;
|
||||
DWORD iolen0;
|
||||
|
||||
result = DeviceIoControl(handle, code, ioctl, sizeof(WINDIVERT_IOCTL), buf,
|
||||
(DWORD)len, &iolen0, overlapped);
|
||||
if (result && iolen != NULL)
|
||||
{
|
||||
*iolen = (UINT)iolen0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a DeviceIoControl.
|
||||
*/
|
||||
static BOOL WinDivertIoControl(HANDLE handle, DWORD code,
|
||||
PWINDIVERT_IOCTL ioctl, PVOID buf, UINT len, UINT *iolen)
|
||||
{
|
||||
OVERLAPPED overlapped;
|
||||
DWORD iolen0;
|
||||
HANDLE event;
|
||||
|
||||
event = (HANDLE)TlsGetValue(windivert_tls_idx);
|
||||
if (event == (HANDLE)NULL)
|
||||
{
|
||||
event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if (event == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
TlsSetValue(windivert_tls_idx, (LPVOID)event);
|
||||
}
|
||||
|
||||
memset(&overlapped, 0, sizeof(overlapped));
|
||||
overlapped.hEvent = event;
|
||||
if (!WinDivertIoControlEx(handle, code, ioctl, buf, len, iolen,
|
||||
&overlapped))
|
||||
{
|
||||
if (GetLastError() != ERROR_IO_PENDING ||
|
||||
!GetOverlappedResult(handle, &overlapped, &iolen0, TRUE))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (iolen != NULL)
|
||||
{
|
||||
*iolen = (UINT)iolen0;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a WinDivert handle.
|
||||
*/
|
||||
HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer, INT16 priority,
|
||||
UINT64 flags)
|
||||
{
|
||||
WINDIVERT_FILTER *object;
|
||||
UINT obj_len;
|
||||
ERROR comp_err;
|
||||
DWORD err;
|
||||
HANDLE handle, pool;
|
||||
UINT64 filter_flags;
|
||||
WINDIVERT_IOCTL ioctl;
|
||||
WINDIVERT_VERSION version;
|
||||
|
||||
// Static checks (should be compiled away if TRUE):
|
||||
if (sizeof(WINDIVERT_ADDRESS) != 80 ||
|
||||
sizeof(WINDIVERT_DATA_NETWORK) != 8 ||
|
||||
offsetof(WINDIVERT_DATA_FLOW, Protocol) != 56 ||
|
||||
offsetof(WINDIVERT_DATA_SOCKET, Protocol) != 56 ||
|
||||
offsetof(WINDIVERT_DATA_REFLECT, Priority) != 24 ||
|
||||
sizeof(WINDIVERT_FILTER) != 24 ||
|
||||
offsetof(WINDIVERT_ADDRESS, Reserved3) != 16)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
// Parameter checking:
|
||||
switch (layer)
|
||||
{
|
||||
case WINDIVERT_LAYER_NETWORK:
|
||||
case WINDIVERT_LAYER_NETWORK_FORWARD:
|
||||
case WINDIVERT_LAYER_FLOW:
|
||||
case WINDIVERT_LAYER_SOCKET:
|
||||
case WINDIVERT_LAYER_REFLECT:
|
||||
break;
|
||||
default:
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (!WINDIVERT_FLAGS_VALID(flags))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (priority < WINDIVERT_PRIORITY_MIN ||
|
||||
priority > WINDIVERT_PRIORITY_MAX)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
// Compile & analyze the filter:
|
||||
pool = HeapCreate(HEAP_NO_SERIALIZE, WINDIVERT_MIN_POOL_SIZE,
|
||||
WINDIVERT_MAX_POOL_SIZE);
|
||||
if (pool == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
object = HeapAlloc(pool, 0,
|
||||
WINDIVERT_FILTER_MAXLEN * sizeof(WINDIVERT_FILTER));
|
||||
if (object == NULL)
|
||||
{
|
||||
err = GetLastError();
|
||||
HeapDestroy(pool);
|
||||
SetLastError(err);
|
||||
return FALSE;
|
||||
}
|
||||
comp_err = WinDivertCompileFilter(filter, pool, layer, object, &obj_len);
|
||||
if (IS_ERROR(comp_err))
|
||||
{
|
||||
HeapDestroy(pool);
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
filter_flags = WinDivertAnalyzeFilter(layer, object, obj_len);
|
||||
|
||||
// Attempt to open the WinDivert device:
|
||||
handle = CreateFile(L"\\\\.\\" WINDIVERT_DEVICE_NAME,
|
||||
GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, INVALID_HANDLE_VALUE);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
err = GetLastError();
|
||||
if (err != ERROR_FILE_NOT_FOUND && err != ERROR_PATH_NOT_FOUND)
|
||||
{
|
||||
HeapDestroy(pool);
|
||||
SetLastError(err);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
// Open failed because the device isn't installed; install it now.
|
||||
if ((flags & WINDIVERT_FLAG_NO_INSTALL) != 0)
|
||||
{
|
||||
HeapDestroy(pool);
|
||||
SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
SetLastError(0);
|
||||
if (!WinDivertDriverInstall())
|
||||
{
|
||||
err = GetLastError();
|
||||
err = (err == 0? ERROR_OPEN_FAILED: err);
|
||||
HeapDestroy(pool);
|
||||
SetLastError(err);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
handle = CreateFile(L"\\\\.\\" WINDIVERT_DEVICE_NAME,
|
||||
GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
||||
INVALID_HANDLE_VALUE);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
err = GetLastError();
|
||||
HeapDestroy(pool);
|
||||
SetLastError(err);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the handle:
|
||||
memset(&ioctl, 0, sizeof(ioctl));
|
||||
ioctl.initialize.layer = layer;
|
||||
ioctl.initialize.priority = (INT32)priority + WINDIVERT_PRIORITY_MAX;
|
||||
ioctl.initialize.flags = flags;
|
||||
memset(&version, 0, sizeof(version));
|
||||
version.magic = WINDIVERT_MAGIC_DLL;
|
||||
version.major = WINDIVERT_VERSION_MAJOR;
|
||||
version.minor = WINDIVERT_VERSION_MINOR;
|
||||
version.bits = 8 * sizeof(void *);
|
||||
if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_INITIALIZE, &ioctl,
|
||||
&version, sizeof(version), NULL))
|
||||
{
|
||||
err = GetLastError();
|
||||
CloseHandle(handle);
|
||||
HeapDestroy(pool);
|
||||
SetLastError(err);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (version.magic != WINDIVERT_MAGIC_SYS ||
|
||||
version.major < WINDIVERT_VERSION_MAJOR_MIN)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
HeapDestroy(pool);
|
||||
SetLastError(ERROR_DRIVER_FAILED_PRIOR_UNLOAD);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
// Start the filter:
|
||||
memset(&ioctl, 0, sizeof(ioctl));
|
||||
ioctl.startup.flags = filter_flags;
|
||||
if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_STARTUP, &ioctl,
|
||||
object, obj_len * sizeof(WINDIVERT_FILTER), NULL))
|
||||
{
|
||||
err = GetLastError();
|
||||
CloseHandle(handle);
|
||||
HeapDestroy(pool);
|
||||
SetLastError(err);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
HeapDestroy(pool);
|
||||
|
||||
// Success!
|
||||
return handle;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive a WinDivert packet.
|
||||
*/
|
||||
BOOL WinDivertRecv(HANDLE handle, PVOID pPacket, UINT packetLen, UINT *readLen,
|
||||
PWINDIVERT_ADDRESS addr)
|
||||
{
|
||||
WINDIVERT_IOCTL ioctl;
|
||||
memset(&ioctl, 0, sizeof(ioctl));
|
||||
ioctl.recv.addr = (UINT64)(ULONG_PTR)addr;
|
||||
ioctl.recv.addr_len_ptr = (UINT64)(ULONG_PTR)NULL;
|
||||
return WinDivertIoControl(handle, IOCTL_WINDIVERT_RECV, &ioctl,
|
||||
pPacket, packetLen, readLen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive a WinDivert packet.
|
||||
*/
|
||||
BOOL WinDivertRecvEx(HANDLE handle, PVOID pPacket, UINT packetLen,
|
||||
UINT *readLen, UINT64 flags, PWINDIVERT_ADDRESS addr, UINT *pAddrLen,
|
||||
LPOVERLAPPED overlapped)
|
||||
{
|
||||
WINDIVERT_IOCTL ioctl;
|
||||
memset(&ioctl, 0, sizeof(ioctl));
|
||||
ioctl.recv.addr = (UINT64)(ULONG_PTR)addr;
|
||||
ioctl.recv.addr_len_ptr = (UINT64)(ULONG_PTR)pAddrLen;
|
||||
if (flags != 0)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
if (overlapped == NULL)
|
||||
{
|
||||
return WinDivertIoControl(handle, IOCTL_WINDIVERT_RECV, &ioctl,
|
||||
pPacket, packetLen, readLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
return WinDivertIoControlEx(handle, IOCTL_WINDIVERT_RECV, &ioctl,
|
||||
pPacket, packetLen, readLen, overlapped);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a WinDivert packet.
|
||||
*/
|
||||
BOOL WinDivertSend(HANDLE handle, const VOID *pPacket, UINT packetLen,
|
||||
UINT *writeLen, const WINDIVERT_ADDRESS *addr)
|
||||
{
|
||||
WINDIVERT_IOCTL ioctl;
|
||||
memset(&ioctl, 0, sizeof(ioctl));
|
||||
ioctl.send.addr = (UINT64)(ULONG_PTR)addr;
|
||||
ioctl.send.addr_len = sizeof(WINDIVERT_ADDRESS);
|
||||
return WinDivertIoControl(handle, IOCTL_WINDIVERT_SEND, &ioctl,
|
||||
(PVOID)pPacket, packetLen, writeLen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a WinDivert packet.
|
||||
*/
|
||||
BOOL WinDivertSendEx(HANDLE handle, const VOID *pPacket, UINT packetLen,
|
||||
UINT *writeLen, UINT64 flags, const WINDIVERT_ADDRESS *addr, UINT addrLen,
|
||||
LPOVERLAPPED overlapped)
|
||||
{
|
||||
WINDIVERT_IOCTL ioctl;
|
||||
memset(&ioctl, 0, sizeof(ioctl));
|
||||
ioctl.send.addr = (UINT64)(ULONG_PTR)addr;
|
||||
ioctl.send.addr_len = addrLen;
|
||||
if (flags != 0)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
if (overlapped == NULL)
|
||||
{
|
||||
return WinDivertIoControl(handle, IOCTL_WINDIVERT_SEND, &ioctl,
|
||||
(PVOID)pPacket, packetLen, writeLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
return WinDivertIoControlEx(handle, IOCTL_WINDIVERT_SEND, &ioctl,
|
||||
(PVOID)pPacket, packetLen, writeLen, overlapped);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Shutdown a WinDivert handle.
|
||||
*/
|
||||
BOOL WinDivertShutdown(HANDLE handle, WINDIVERT_SHUTDOWN how)
|
||||
{
|
||||
WINDIVERT_IOCTL ioctl;
|
||||
memset(&ioctl, 0, sizeof(ioctl));
|
||||
ioctl.shutdown.how = (UINT32)how;
|
||||
return WinDivertIoControl(handle, IOCTL_WINDIVERT_SHUTDOWN, &ioctl, NULL,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Close a WinDivert handle.
|
||||
*/
|
||||
BOOL WinDivertClose(HANDLE handle)
|
||||
{
|
||||
return CloseHandle(handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a WinDivert parameter.
|
||||
*/
|
||||
BOOL WinDivertSetParam(HANDLE handle, WINDIVERT_PARAM param, UINT64 value)
|
||||
{
|
||||
WINDIVERT_IOCTL ioctl;
|
||||
memset(&ioctl, 0, sizeof(ioctl));
|
||||
ioctl.set_param.param = (UINT32)param;
|
||||
ioctl.set_param.val = value;
|
||||
return WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_PARAM, &ioctl, NULL,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a WinDivert parameter.
|
||||
*/
|
||||
BOOL WinDivertGetParam(HANDLE handle, WINDIVERT_PARAM param, UINT64 *pValue)
|
||||
{
|
||||
WINDIVERT_IOCTL ioctl;
|
||||
memset(&ioctl, 0, sizeof(ioctl));
|
||||
ioctl.get_param.param = (UINT32)param;
|
||||
return WinDivertIoControl(handle, IOCTL_WINDIVERT_GET_PARAM, &ioctl,
|
||||
pValue, sizeof(UINT64), NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* REPLACEMENTS */
|
||||
/*****************************************************************************/
|
||||
|
||||
static BOOLEAN WinDivertIsDigit(char c)
|
||||
{
|
||||
return (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
static BOOLEAN WinDivertIsXDigit(char c)
|
||||
{
|
||||
return (c >= '0' && c <= '9') ||
|
||||
(c >= 'a' && c <= 'f') ||
|
||||
(c >= 'A' && c <= 'F');
|
||||
}
|
||||
|
||||
static BOOLEAN WinDivertIsSpace(char c)
|
||||
{
|
||||
return (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' ||
|
||||
c == '\v');
|
||||
}
|
||||
|
||||
static BOOLEAN WinDivertIsAlNum(char c)
|
||||
{
|
||||
return (c >= 'a' && c <= 'z') ||
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
(c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
static char WinDivertToLower(char c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
return 'a' + (c - 'A');
|
||||
return c;
|
||||
}
|
||||
|
||||
static BOOLEAN WinDivertStrLen(const wchar_t *s, size_t maxlen,
|
||||
size_t *lenptr)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; s[i]; i++)
|
||||
{
|
||||
if (i > maxlen)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
*lenptr = i;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOLEAN WinDivertStrCpy(wchar_t *dst, size_t dstlen, const wchar_t *src)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; src[i]; i++)
|
||||
{
|
||||
if (i > dstlen)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
dst[i] = src[i];
|
||||
}
|
||||
if (i > dstlen)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
dst[i] = src[i];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int WinDivertStrCmp(const char *s, const char *t)
|
||||
{
|
||||
int cmp;
|
||||
size_t i;
|
||||
for (i = 0; ; i++)
|
||||
{
|
||||
cmp = s[i] - t[i];
|
||||
if (cmp != 0)
|
||||
{
|
||||
return cmp;
|
||||
}
|
||||
if (s[i] == '\0')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BOOLEAN WinDivertMul128(UINT32 *n, UINT32 m)
|
||||
{
|
||||
UINT64 n64 = (UINT64)n[0] * (UINT64)m;
|
||||
n[0] = (UINT32)n64;
|
||||
n64 = (UINT64)n[1] * (UINT64)m + (n64 >> 32);
|
||||
n[1] = (UINT32)n64;
|
||||
n64 = (UINT64)n[2] * (UINT64)m + (n64 >> 32);
|
||||
n[2] = (UINT32)n64;
|
||||
n64 = (UINT64)n[3] * (UINT64)m + (n64 >> 32);
|
||||
n[3] = (UINT32)n64;
|
||||
return ((n64 >> 32) == 0);
|
||||
}
|
||||
|
||||
static BOOLEAN WinDivertAdd128(UINT32 *n, UINT32 a)
|
||||
{
|
||||
UINT64 n64 = (UINT64)n[0] + (UINT64)a;
|
||||
n[0] = (UINT32)n64;
|
||||
n64 = (UINT64)n[1] + (n64 >> 32);
|
||||
n[1] = (UINT32)n64;
|
||||
n64 = (UINT64)n[2] + (n64 >> 32);
|
||||
n[2] = (UINT32)n64;
|
||||
n64 = (UINT64)n[3] + (n64 >> 32);
|
||||
n[3] = (UINT32)n64;
|
||||
return ((n64 >> 32) == 0);
|
||||
}
|
||||
|
||||
static BOOLEAN WinDivertAToI(const char *str, char **endptr, UINT32 *intptr,
|
||||
UINT size)
|
||||
{
|
||||
size_t i = 0;
|
||||
UINT32 n[4] = {0};
|
||||
BOOLEAN result = TRUE;
|
||||
for (; str[i] && WinDivertIsDigit(str[i]); i++)
|
||||
{
|
||||
if (!WinDivertMul128(n, 10) || !WinDivertAdd128(n, str[i] - '0'))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (i == 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (endptr != NULL)
|
||||
{
|
||||
*endptr = (char *)str + i;
|
||||
}
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
intptr[i] = n[i];
|
||||
}
|
||||
for (; result && i < size && i < 4; i++)
|
||||
{
|
||||
result = result && (n[i] == 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOLEAN WinDivertAToX(const char *str, char **endptr, UINT32 *intptr,
|
||||
UINT size, BOOL prefix)
|
||||
{
|
||||
size_t i = 0;
|
||||
UINT32 n[4] = {0}, dig;
|
||||
BOOLEAN result = TRUE;
|
||||
if (prefix)
|
||||
{
|
||||
if (str[i] == '0' && str[i+1] == 'x')
|
||||
{
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
for (; str[i] && WinDivertIsXDigit(str[i]); i++)
|
||||
{
|
||||
if (WinDivertIsDigit(str[i]))
|
||||
{
|
||||
dig = (UINT32)(str[i] - '0');
|
||||
}
|
||||
else
|
||||
{
|
||||
dig = (UINT32)(WinDivertToLower(str[i]) - 'a') + 0x0A;
|
||||
}
|
||||
if (!WinDivertMul128(n, 16) || !WinDivertAdd128(n, dig))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (i == 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (endptr != NULL)
|
||||
{
|
||||
*endptr = (char *)str + i;
|
||||
}
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
intptr[i] = n[i];
|
||||
}
|
||||
for (; result && i < size && i < 4; i++)
|
||||
{
|
||||
result = result && (n[i] == 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Divide by 10 and return the remainder.
|
||||
*/
|
||||
#define WINDIVERT_BIG_MUL_ROUND(a, c, r, i) \
|
||||
do { \
|
||||
UINT64 t = WINDIVERT_MUL64((UINT64)(a), (UINT64)(c)); \
|
||||
UINT k; \
|
||||
for (k = (i); k < 9 && t != 0; k++) \
|
||||
{ \
|
||||
UINT64 s = (UINT64)(r)[k] + (t & 0xFFFFFFFF); \
|
||||
(r)[k] = (UINT32)s; \
|
||||
t = (t >> 32) + (s >> 32); \
|
||||
} \
|
||||
} while (FALSE)
|
||||
static UINT32 WinDivertDivTen128(UINT32 *a)
|
||||
{
|
||||
const UINT32 c[5] =
|
||||
{
|
||||
0x9999999A, 0x99999999, 0x99999999, 0x99999999, 0x19999999
|
||||
};
|
||||
UINT32 r[9] = {0}, m[6] = {0};
|
||||
UINT i, j;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
WINDIVERT_BIG_MUL_ROUND(a[i], c[j], r, i+j);
|
||||
}
|
||||
}
|
||||
|
||||
a[0] = r[5];
|
||||
a[1] = r[6];
|
||||
a[2] = r[7];
|
||||
a[3] = r[8];
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
WINDIVERT_BIG_MUL_ROUND(r[i], 10, m, i);
|
||||
}
|
||||
|
||||
return m[5];
|
||||
}
|
||||
|
||||
630
src/ProcessDrv/tun/WinDivert/divert/windivert.h
Normal file
630
src/ProcessDrv/tun/WinDivert/divert/windivert.h
Normal file
@@ -0,0 +1,630 @@
|
||||
/*
|
||||
* windivert.h
|
||||
* (C) 2019, all rights reserved,
|
||||
*
|
||||
* This file is part of WinDivert.
|
||||
*
|
||||
* WinDivert is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* WinDivert is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __WINDIVERT_H
|
||||
#define __WINDIVERT_H
|
||||
|
||||
#ifndef WINDIVERT_KERNEL
|
||||
#include <windows.h>
|
||||
#endif /* WINDIVERT_KERNEL */
|
||||
|
||||
#ifndef WINDIVERTEXPORT
|
||||
#define WINDIVERTEXPORT extern __declspec(dllimport)
|
||||
#endif /* WINDIVERTEXPORT */
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#define __in
|
||||
#define __in_opt
|
||||
#define __out
|
||||
#define __out_opt
|
||||
#define __inout
|
||||
#define __inout_opt
|
||||
#include <stdint.h>
|
||||
#define INT8 int8_t
|
||||
#define UINT8 uint8_t
|
||||
#define INT16 int16_t
|
||||
#define UINT16 uint16_t
|
||||
#define INT32 int32_t
|
||||
#define UINT32 uint32_t
|
||||
#define INT64 int64_t
|
||||
#define UINT64 uint64_t
|
||||
#endif /* __MINGW32__ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/****************************************************************************/
|
||||
/* WINDIVERT API */
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* WinDivert layers.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
WINDIVERT_LAYER_NETWORK = 0, /* Network layer. */
|
||||
WINDIVERT_LAYER_NETWORK_FORWARD = 1,/* Network layer (forwarded packets) */
|
||||
WINDIVERT_LAYER_FLOW = 2, /* Flow layer. */
|
||||
WINDIVERT_LAYER_SOCKET = 3, /* Socket layer. */
|
||||
WINDIVERT_LAYER_REFLECT = 4, /* Reflect layer. */
|
||||
} WINDIVERT_LAYER, *PWINDIVERT_LAYER;
|
||||
|
||||
/*
|
||||
* WinDivert NETWORK and NETWORK_FORWARD layer data.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
UINT32 IfIdx; /* Packet's interface index. */
|
||||
UINT32 SubIfIdx; /* Packet's sub-interface index. */
|
||||
} WINDIVERT_DATA_NETWORK, *PWINDIVERT_DATA_NETWORK;
|
||||
|
||||
/*
|
||||
* WinDivert FLOW layer data.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
UINT64 EndpointId; /* Endpoint ID. */
|
||||
UINT64 ParentEndpointId; /* Parent endpoint ID. */
|
||||
UINT32 ProcessId; /* Process ID. */
|
||||
UINT32 LocalAddr[4]; /* Local address. */
|
||||
UINT32 RemoteAddr[4]; /* Remote address. */
|
||||
UINT16 LocalPort; /* Local port. */
|
||||
UINT16 RemotePort; /* Remote port. */
|
||||
UINT8 Protocol; /* Protocol. */
|
||||
} WINDIVERT_DATA_FLOW, *PWINDIVERT_DATA_FLOW;
|
||||
|
||||
/*
|
||||
* WinDivert SOCKET layer data.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
UINT64 EndpointId; /* Endpoint ID. */
|
||||
UINT64 ParentEndpointId; /* Parent Endpoint ID. */
|
||||
UINT32 ProcessId; /* Process ID. */
|
||||
UINT32 LocalAddr[4]; /* Local address. */
|
||||
UINT32 RemoteAddr[4]; /* Remote address. */
|
||||
UINT16 LocalPort; /* Local port. */
|
||||
UINT16 RemotePort; /* Remote port. */
|
||||
UINT8 Protocol; /* Protocol. */
|
||||
} WINDIVERT_DATA_SOCKET, *PWINDIVERT_DATA_SOCKET;
|
||||
|
||||
/*
|
||||
* WinDivert REFLECTION layer data.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
INT64 Timestamp; /* Handle open time. */
|
||||
UINT32 ProcessId; /* Handle process ID. */
|
||||
WINDIVERT_LAYER Layer; /* Handle layer. */
|
||||
UINT64 Flags; /* Handle flags. */
|
||||
INT16 Priority; /* Handle priority. */
|
||||
} WINDIVERT_DATA_REFLECT, *PWINDIVERT_DATA_REFLECT;
|
||||
|
||||
/*
|
||||
* WinDivert address.
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4201)
|
||||
#endif
|
||||
typedef struct
|
||||
{
|
||||
INT64 Timestamp; /* Packet's timestamp. */
|
||||
UINT32 Layer:8; /* Packet's layer. */
|
||||
UINT32 Event:8; /* Packet event. */
|
||||
UINT32 Sniffed:1; /* Packet was sniffed? */
|
||||
UINT32 Outbound:1; /* Packet is outound? */
|
||||
UINT32 Loopback:1; /* Packet is loopback? */
|
||||
UINT32 Impostor:1; /* Packet is impostor? */
|
||||
UINT32 IPv6:1; /* Packet is IPv6? */
|
||||
UINT32 IPChecksum:1; /* Packet has valid IPv4 checksum? */
|
||||
UINT32 TCPChecksum:1; /* Packet has valid TCP checksum? */
|
||||
UINT32 UDPChecksum:1; /* Packet has valid UDP checksum? */
|
||||
UINT32 Reserved1:8;
|
||||
UINT32 Reserved2;
|
||||
union
|
||||
{
|
||||
WINDIVERT_DATA_NETWORK Network; /* Network layer data. */
|
||||
WINDIVERT_DATA_FLOW Flow; /* Flow layer data. */
|
||||
WINDIVERT_DATA_SOCKET Socket; /* Socket layer data. */
|
||||
WINDIVERT_DATA_REFLECT Reflect; /* Reflect layer data. */
|
||||
UINT8 Reserved3[64];
|
||||
};
|
||||
} WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS;
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* WinDivert events.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
WINDIVERT_EVENT_NETWORK_PACKET = 0, /* Network packet. */
|
||||
WINDIVERT_EVENT_FLOW_ESTABLISHED = 1,
|
||||
/* Flow established. */
|
||||
WINDIVERT_EVENT_FLOW_DELETED = 2, /* Flow deleted. */
|
||||
WINDIVERT_EVENT_SOCKET_BIND = 3, /* Socket bind. */
|
||||
WINDIVERT_EVENT_SOCKET_CONNECT = 4, /* Socket connect. */
|
||||
WINDIVERT_EVENT_SOCKET_LISTEN = 5, /* Socket listen. */
|
||||
WINDIVERT_EVENT_SOCKET_ACCEPT = 6, /* Socket accept. */
|
||||
WINDIVERT_EVENT_SOCKET_CLOSE = 7, /* Socket close. */
|
||||
WINDIVERT_EVENT_REFLECT_OPEN = 8, /* WinDivert handle opened. */
|
||||
WINDIVERT_EVENT_REFLECT_CLOSE = 9, /* WinDivert handle closed. */
|
||||
} WINDIVERT_EVENT, *PWINDIVERT_EVENT;
|
||||
|
||||
/*
|
||||
* WinDivert flags.
|
||||
*/
|
||||
#define WINDIVERT_FLAG_SNIFF 0x0001
|
||||
#define WINDIVERT_FLAG_DROP 0x0002
|
||||
#define WINDIVERT_FLAG_RECV_ONLY 0x0004
|
||||
#define WINDIVERT_FLAG_READ_ONLY WINDIVERT_FLAG_RECV_ONLY
|
||||
#define WINDIVERT_FLAG_SEND_ONLY 0x0008
|
||||
#define WINDIVERT_FLAG_WRITE_ONLY WINDIVERT_FLAG_SEND_ONLY
|
||||
#define WINDIVERT_FLAG_NO_INSTALL 0x0010
|
||||
#define WINDIVERT_FLAG_FRAGMENTS 0x0020
|
||||
|
||||
/*
|
||||
* WinDivert parameters.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
WINDIVERT_PARAM_QUEUE_LENGTH = 0, /* Packet queue length. */
|
||||
WINDIVERT_PARAM_QUEUE_TIME = 1, /* Packet queue time. */
|
||||
WINDIVERT_PARAM_QUEUE_SIZE = 2, /* Packet queue size. */
|
||||
WINDIVERT_PARAM_VERSION_MAJOR = 3, /* Driver version (major). */
|
||||
WINDIVERT_PARAM_VERSION_MINOR = 4, /* Driver version (minor). */
|
||||
} WINDIVERT_PARAM, *PWINDIVERT_PARAM;
|
||||
#define WINDIVERT_PARAM_MAX WINDIVERT_PARAM_VERSION_MINOR
|
||||
|
||||
/*
|
||||
* WinDivert shutdown parameter.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
WINDIVERT_SHUTDOWN_RECV = 0x1, /* Shutdown recv. */
|
||||
WINDIVERT_SHUTDOWN_SEND = 0x2, /* Shutdown send. */
|
||||
WINDIVERT_SHUTDOWN_BOTH = 0x3, /* Shutdown recv and send. */
|
||||
} WINDIVERT_SHUTDOWN, *PWINDIVERT_SHUTDOWN;
|
||||
#define WINDIVERT_SHUTDOWN_MAX WINDIVERT_SHUTDOWN_BOTH
|
||||
|
||||
#ifndef WINDIVERT_KERNEL
|
||||
|
||||
/*
|
||||
* Open a WinDivert handle.
|
||||
*/
|
||||
WINDIVERTEXPORT HANDLE WinDivertOpen(
|
||||
__in const char *filter,
|
||||
__in WINDIVERT_LAYER layer,
|
||||
__in INT16 priority,
|
||||
__in UINT64 flags);
|
||||
|
||||
/*
|
||||
* Receive (read) a packet from a WinDivert handle.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertRecv(
|
||||
__in HANDLE handle,
|
||||
__out_opt VOID *pPacket,
|
||||
__in UINT packetLen,
|
||||
__out_opt UINT *pRecvLen,
|
||||
__out_opt WINDIVERT_ADDRESS *pAddr);
|
||||
|
||||
/*
|
||||
* Receive (read) a packet from a WinDivert handle.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertRecvEx(
|
||||
__in HANDLE handle,
|
||||
__out_opt VOID *pPacket,
|
||||
__in UINT packetLen,
|
||||
__out_opt UINT *pRecvLen,
|
||||
__in UINT64 flags,
|
||||
__out WINDIVERT_ADDRESS *pAddr,
|
||||
__inout_opt UINT *pAddrLen,
|
||||
__inout_opt LPOVERLAPPED lpOverlapped);
|
||||
|
||||
/*
|
||||
* Send (write/inject) a packet to a WinDivert handle.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertSend(
|
||||
__in HANDLE handle,
|
||||
__in const VOID *pPacket,
|
||||
__in UINT packetLen,
|
||||
__out_opt UINT *pSendLen,
|
||||
__in const WINDIVERT_ADDRESS *pAddr);
|
||||
|
||||
/*
|
||||
* Send (write/inject) a packet to a WinDivert handle.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertSendEx(
|
||||
__in HANDLE handle,
|
||||
__in const VOID *pPacket,
|
||||
__in UINT packetLen,
|
||||
__out_opt UINT *pSendLen,
|
||||
__in UINT64 flags,
|
||||
__in const WINDIVERT_ADDRESS *pAddr,
|
||||
__in UINT addrLen,
|
||||
__inout_opt LPOVERLAPPED lpOverlapped);
|
||||
|
||||
/*
|
||||
* Shutdown a WinDivert handle.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertShutdown(
|
||||
__in HANDLE handle,
|
||||
__in WINDIVERT_SHUTDOWN how);
|
||||
|
||||
/*
|
||||
* Close a WinDivert handle.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertClose(
|
||||
__in HANDLE handle);
|
||||
|
||||
/*
|
||||
* Set a WinDivert handle parameter.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertSetParam(
|
||||
__in HANDLE handle,
|
||||
__in WINDIVERT_PARAM param,
|
||||
__in UINT64 value);
|
||||
|
||||
/*
|
||||
* Get a WinDivert handle parameter.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertGetParam(
|
||||
__in HANDLE handle,
|
||||
__in WINDIVERT_PARAM param,
|
||||
__out UINT64 *pValue);
|
||||
|
||||
#endif /* WINDIVERT_KERNEL */
|
||||
|
||||
/*
|
||||
* WinDivert constants.
|
||||
*/
|
||||
#define WINDIVERT_PRIORITY_HIGHEST 30000
|
||||
#define WINDIVERT_PRIORITY_LOWEST (-WINDIVERT_PRIORITY_HIGHEST)
|
||||
#define WINDIVERT_PARAM_QUEUE_LENGTH_DEFAULT 4096
|
||||
#define WINDIVERT_PARAM_QUEUE_LENGTH_MIN 32
|
||||
#define WINDIVERT_PARAM_QUEUE_LENGTH_MAX 16384
|
||||
#define WINDIVERT_PARAM_QUEUE_TIME_DEFAULT 2000 /* 2s */
|
||||
#define WINDIVERT_PARAM_QUEUE_TIME_MIN 100 /* 100ms */
|
||||
#define WINDIVERT_PARAM_QUEUE_TIME_MAX 16000 /* 16s */
|
||||
#define WINDIVERT_PARAM_QUEUE_SIZE_DEFAULT 4194304 /* 4MB */
|
||||
#define WINDIVERT_PARAM_QUEUE_SIZE_MIN 65535 /* 64KB */
|
||||
#define WINDIVERT_PARAM_QUEUE_SIZE_MAX 33554432 /* 32MB */
|
||||
#define WINDIVERT_BATCH_MAX 0xFF /* 255 */
|
||||
#define WINDIVERT_MTU_MAX (40 + 0xFFFF)
|
||||
|
||||
/****************************************************************************/
|
||||
/* WINDIVERT HELPER API */
|
||||
/****************************************************************************/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4214)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* IPv4/IPv6/ICMP/ICMPv6/TCP/UDP header definitions.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
UINT8 HdrLength:4;
|
||||
UINT8 Version:4;
|
||||
UINT8 TOS;
|
||||
UINT16 Length;
|
||||
UINT16 Id;
|
||||
UINT16 FragOff0;
|
||||
UINT8 TTL;
|
||||
UINT8 Protocol;
|
||||
UINT16 Checksum;
|
||||
UINT32 SrcAddr;
|
||||
UINT32 DstAddr;
|
||||
} WINDIVERT_IPHDR, *PWINDIVERT_IPHDR;
|
||||
|
||||
#define WINDIVERT_IPHDR_GET_FRAGOFF(hdr) \
|
||||
(((hdr)->FragOff0) & 0xFF1F)
|
||||
#define WINDIVERT_IPHDR_GET_MF(hdr) \
|
||||
((((hdr)->FragOff0) & 0x0020) != 0)
|
||||
#define WINDIVERT_IPHDR_GET_DF(hdr) \
|
||||
((((hdr)->FragOff0) & 0x0040) != 0)
|
||||
#define WINDIVERT_IPHDR_GET_RESERVED(hdr) \
|
||||
((((hdr)->FragOff0) & 0x0080) != 0)
|
||||
|
||||
#define WINDIVERT_IPHDR_SET_FRAGOFF(hdr, val) \
|
||||
do \
|
||||
{ \
|
||||
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0x00E0) | \
|
||||
((val) & 0xFF1F); \
|
||||
} \
|
||||
while (FALSE)
|
||||
#define WINDIVERT_IPHDR_SET_MF(hdr, val) \
|
||||
do \
|
||||
{ \
|
||||
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFDF) | \
|
||||
(((val) & 0x0001) << 5); \
|
||||
} \
|
||||
while (FALSE)
|
||||
#define WINDIVERT_IPHDR_SET_DF(hdr, val) \
|
||||
do \
|
||||
{ \
|
||||
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFBF) | \
|
||||
(((val) & 0x0001) << 6); \
|
||||
} \
|
||||
while (FALSE)
|
||||
#define WINDIVERT_IPHDR_SET_RESERVED(hdr, val) \
|
||||
do \
|
||||
{ \
|
||||
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFF7F) | \
|
||||
(((val) & 0x0001) << 7); \
|
||||
} \
|
||||
while (FALSE)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 TrafficClass0:4;
|
||||
UINT8 Version:4;
|
||||
UINT8 FlowLabel0:4;
|
||||
UINT8 TrafficClass1:4;
|
||||
UINT16 FlowLabel1;
|
||||
UINT16 Length;
|
||||
UINT8 NextHdr;
|
||||
UINT8 HopLimit;
|
||||
UINT32 SrcAddr[4];
|
||||
UINT32 DstAddr[4];
|
||||
} WINDIVERT_IPV6HDR, *PWINDIVERT_IPV6HDR;
|
||||
|
||||
#define WINDIVERT_IPV6HDR_GET_TRAFFICCLASS(hdr) \
|
||||
((((hdr)->TrafficClass0) << 4) | ((hdr)->TrafficClass1))
|
||||
#define WINDIVERT_IPV6HDR_GET_FLOWLABEL(hdr) \
|
||||
((((UINT32)(hdr)->FlowLabel0) << 16) | ((UINT32)(hdr)->FlowLabel1))
|
||||
|
||||
#define WINDIVERT_IPV6HDR_SET_TRAFFICCLASS(hdr, val) \
|
||||
do \
|
||||
{ \
|
||||
(hdr)->TrafficClass0 = ((UINT8)(val) >> 4); \
|
||||
(hdr)->TrafficClass1 = (UINT8)(val); \
|
||||
} \
|
||||
while (FALSE)
|
||||
#define WINDIVERT_IPV6HDR_SET_FLOWLABEL(hdr, val) \
|
||||
do \
|
||||
{ \
|
||||
(hdr)->FlowLabel0 = (UINT8)((val) >> 16); \
|
||||
(hdr)->FlowLabel1 = (UINT16)(val); \
|
||||
} \
|
||||
while (FALSE)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 Type;
|
||||
UINT8 Code;
|
||||
UINT16 Checksum;
|
||||
UINT32 Body;
|
||||
} WINDIVERT_ICMPHDR, *PWINDIVERT_ICMPHDR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 Type;
|
||||
UINT8 Code;
|
||||
UINT16 Checksum;
|
||||
UINT32 Body;
|
||||
} WINDIVERT_ICMPV6HDR, *PWINDIVERT_ICMPV6HDR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT16 SrcPort;
|
||||
UINT16 DstPort;
|
||||
UINT32 SeqNum;
|
||||
UINT32 AckNum;
|
||||
UINT16 Reserved1:4;
|
||||
UINT16 HdrLength:4;
|
||||
UINT16 Fin:1;
|
||||
UINT16 Syn:1;
|
||||
UINT16 Rst:1;
|
||||
UINT16 Psh:1;
|
||||
UINT16 Ack:1;
|
||||
UINT16 Urg:1;
|
||||
UINT16 Reserved2:2;
|
||||
UINT16 Window;
|
||||
UINT16 Checksum;
|
||||
UINT16 UrgPtr;
|
||||
} WINDIVERT_TCPHDR, *PWINDIVERT_TCPHDR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT16 SrcPort;
|
||||
UINT16 DstPort;
|
||||
UINT16 Length;
|
||||
UINT16 Checksum;
|
||||
} WINDIVERT_UDPHDR, *PWINDIVERT_UDPHDR;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Flags for WinDivertHelperCalcChecksums()
|
||||
*/
|
||||
#define WINDIVERT_HELPER_NO_IP_CHECKSUM 1
|
||||
#define WINDIVERT_HELPER_NO_ICMP_CHECKSUM 2
|
||||
#define WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM 4
|
||||
#define WINDIVERT_HELPER_NO_TCP_CHECKSUM 8
|
||||
#define WINDIVERT_HELPER_NO_UDP_CHECKSUM 16
|
||||
|
||||
#ifndef WINDIVERT_KERNEL
|
||||
|
||||
/*
|
||||
* Hash a packet.
|
||||
*/
|
||||
WINDIVERTEXPORT UINT64 WinDivertHelperHashPacket(
|
||||
__in const VOID *pPacket,
|
||||
__in UINT packetLen,
|
||||
__in UINT64 seed
|
||||
#ifdef __cplusplus
|
||||
= 0
|
||||
#endif
|
||||
);
|
||||
|
||||
/*
|
||||
* Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertHelperParsePacket(
|
||||
__in const VOID *pPacket,
|
||||
__in UINT packetLen,
|
||||
__out_opt PWINDIVERT_IPHDR *ppIpHdr,
|
||||
__out_opt PWINDIVERT_IPV6HDR *ppIpv6Hdr,
|
||||
__out_opt UINT8 *pProtocol,
|
||||
__out_opt PWINDIVERT_ICMPHDR *ppIcmpHdr,
|
||||
__out_opt PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr,
|
||||
__out_opt PWINDIVERT_TCPHDR *ppTcpHdr,
|
||||
__out_opt PWINDIVERT_UDPHDR *ppUdpHdr,
|
||||
__out_opt PVOID *ppData,
|
||||
__out_opt UINT *pDataLen,
|
||||
__out_opt PVOID *ppNext,
|
||||
__out_opt UINT *pNextLen);
|
||||
|
||||
/*
|
||||
* Parse an IPv4 address.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertHelperParseIPv4Address(
|
||||
__in const char *addrStr,
|
||||
__out_opt UINT32 *pAddr);
|
||||
|
||||
/*
|
||||
* Parse an IPv6 address.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertHelperParseIPv6Address(
|
||||
__in const char *addrStr,
|
||||
__out_opt UINT32 *pAddr);
|
||||
|
||||
/*
|
||||
* Format an IPv4 address.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv4Address(
|
||||
__in UINT32 addr,
|
||||
__out char *buffer,
|
||||
__in UINT bufLen);
|
||||
|
||||
/*
|
||||
* Format an IPv6 address.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv6Address(
|
||||
__in const UINT32 *pAddr,
|
||||
__out char *buffer,
|
||||
__in UINT bufLen);
|
||||
|
||||
/*
|
||||
* Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertHelperCalcChecksums(
|
||||
__inout VOID *pPacket,
|
||||
__in UINT packetLen,
|
||||
__out_opt WINDIVERT_ADDRESS *pAddr,
|
||||
__in UINT64 flags);
|
||||
|
||||
/*
|
||||
* Decrement the TTL/HopLimit.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertHelperDecrementTTL(
|
||||
__inout VOID *pPacket,
|
||||
__in UINT packetLen);
|
||||
|
||||
/*
|
||||
* Compile the given filter string.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertHelperCompileFilter(
|
||||
__in const char *filter,
|
||||
__in WINDIVERT_LAYER layer,
|
||||
__out_opt char *object,
|
||||
__in UINT objLen,
|
||||
__out_opt const char **errorStr,
|
||||
__out_opt UINT *errorPos);
|
||||
|
||||
/*
|
||||
* Evaluate the given filter string.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertHelperEvalFilter(
|
||||
__in const char *filter,
|
||||
__in const VOID *pPacket,
|
||||
__in UINT packetLen,
|
||||
__in const WINDIVERT_ADDRESS *pAddr);
|
||||
|
||||
/*
|
||||
* Format the given filter string.
|
||||
*/
|
||||
WINDIVERTEXPORT BOOL WinDivertHelperFormatFilter(
|
||||
__in const char *filter,
|
||||
__in WINDIVERT_LAYER layer,
|
||||
__out char *buffer,
|
||||
__in UINT bufLen);
|
||||
|
||||
/*
|
||||
* Byte ordering.
|
||||
*/
|
||||
WINDIVERTEXPORT UINT16 WinDivertHelperNtohs(
|
||||
__in UINT16 x);
|
||||
WINDIVERTEXPORT UINT16 WinDivertHelperHtons(
|
||||
__in UINT16 x);
|
||||
WINDIVERTEXPORT UINT32 WinDivertHelperNtohl(
|
||||
__in UINT32 x);
|
||||
WINDIVERTEXPORT UINT32 WinDivertHelperHtonl(
|
||||
__in UINT32 x);
|
||||
WINDIVERTEXPORT UINT64 WinDivertHelperNtohll(
|
||||
__in UINT64 x);
|
||||
WINDIVERTEXPORT UINT64 WinDivertHelperHtonll(
|
||||
__in UINT64 x);
|
||||
WINDIVERTEXPORT void WinDivertHelperNtohIPv6Address(
|
||||
__in const UINT *inAddr,
|
||||
__out UINT *outAddr);
|
||||
WINDIVERTEXPORT void WinDivertHelperHtonIPv6Address(
|
||||
__in const UINT *inAddr,
|
||||
__out UINT *outAddr);
|
||||
|
||||
/*
|
||||
* Old names to be removed in the next version.
|
||||
*/
|
||||
WINDIVERTEXPORT void WinDivertHelperNtohIpv6Address(
|
||||
__in const UINT *inAddr,
|
||||
__out UINT *outAddr);
|
||||
WINDIVERTEXPORT void WinDivertHelperHtonIpv6Address(
|
||||
__in const UINT *inAddr,
|
||||
__out UINT *outAddr);
|
||||
|
||||
#endif /* WINDIVERT_KERNEL */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __WINDIVERT_H */
|
||||
325
src/ProcessDrv/tun/WinDivert/divert/windivert_device.h
Normal file
325
src/ProcessDrv/tun/WinDivert/divert/windivert_device.h
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* windivert_device.h
|
||||
* (C) 2019, all rights reserved,
|
||||
*
|
||||
* This file is part of WinDivert.
|
||||
*
|
||||
* WinDivert is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* WinDivert is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __WINDIVERT_DEVICE_H
|
||||
#define __WINDIVERT_DEVICE_H
|
||||
|
||||
/*
|
||||
* NOTE: This is the low-level interface to the WinDivert device driver.
|
||||
* This interface should not be used directly, instead use the high-level
|
||||
* interface provided by the WinDivert API.
|
||||
*/
|
||||
|
||||
#define WINDIVERT_KERNEL
|
||||
#include "windivert.h"
|
||||
|
||||
#define WINDIVERT_VERSION_MAJOR 2
|
||||
#define WINDIVERT_VERSION_MINOR 2
|
||||
|
||||
#define WINDIVERT_MAGIC_DLL 0x4C4C447669645724ull
|
||||
#define WINDIVERT_MAGIC_SYS 0x5359537669645723ull
|
||||
|
||||
#define WINDIVERT_STR2(s) #s
|
||||
#define WINDIVERT_STR(s) WINDIVERT_STR2(s)
|
||||
#define WINDIVERT_LSTR2(s) L ## #s
|
||||
#define WINDIVERT_LSTR(s) WINDIVERT_LSTR2(s)
|
||||
|
||||
#define WINDIVERT_VERSION_LSTR \
|
||||
WINDIVERT_LSTR(WINDIVERT_VERSION_MAJOR) L"." \
|
||||
WINDIVERT_LSTR(WINDIVERT_VERSION_MINOR)
|
||||
|
||||
#define WINDIVERT_DEVICE_NAME \
|
||||
L"WinDivert"
|
||||
#define WINDIVERT_LAYER_NAME \
|
||||
WINDIVERT_DEVICE_NAME WINDIVERT_VERSION_LSTR
|
||||
|
||||
#define WINDIVERT_FILTER_FIELD_ZERO 0
|
||||
#define WINDIVERT_FILTER_FIELD_INBOUND 1
|
||||
#define WINDIVERT_FILTER_FIELD_OUTBOUND 2
|
||||
#define WINDIVERT_FILTER_FIELD_IFIDX 3
|
||||
#define WINDIVERT_FILTER_FIELD_SUBIFIDX 4
|
||||
#define WINDIVERT_FILTER_FIELD_IP 5
|
||||
#define WINDIVERT_FILTER_FIELD_IPV6 6
|
||||
#define WINDIVERT_FILTER_FIELD_ICMP 7
|
||||
#define WINDIVERT_FILTER_FIELD_TCP 8
|
||||
#define WINDIVERT_FILTER_FIELD_UDP 9
|
||||
#define WINDIVERT_FILTER_FIELD_ICMPV6 10
|
||||
#define WINDIVERT_FILTER_FIELD_IP_HDRLENGTH 11
|
||||
#define WINDIVERT_FILTER_FIELD_IP_TOS 12
|
||||
#define WINDIVERT_FILTER_FIELD_IP_LENGTH 13
|
||||
#define WINDIVERT_FILTER_FIELD_IP_ID 14
|
||||
#define WINDIVERT_FILTER_FIELD_IP_DF 15
|
||||
#define WINDIVERT_FILTER_FIELD_IP_MF 16
|
||||
#define WINDIVERT_FILTER_FIELD_IP_FRAGOFF 17
|
||||
#define WINDIVERT_FILTER_FIELD_IP_TTL 18
|
||||
#define WINDIVERT_FILTER_FIELD_IP_PROTOCOL 19
|
||||
#define WINDIVERT_FILTER_FIELD_IP_CHECKSUM 20
|
||||
#define WINDIVERT_FILTER_FIELD_IP_SRCADDR 21
|
||||
#define WINDIVERT_FILTER_FIELD_IP_DSTADDR 22
|
||||
#define WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS 23
|
||||
#define WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL 24
|
||||
#define WINDIVERT_FILTER_FIELD_IPV6_LENGTH 25
|
||||
#define WINDIVERT_FILTER_FIELD_IPV6_NEXTHDR 26
|
||||
#define WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT 27
|
||||
#define WINDIVERT_FILTER_FIELD_IPV6_SRCADDR 28
|
||||
#define WINDIVERT_FILTER_FIELD_IPV6_DSTADDR 29
|
||||
#define WINDIVERT_FILTER_FIELD_ICMP_TYPE 30
|
||||
#define WINDIVERT_FILTER_FIELD_ICMP_CODE 31
|
||||
#define WINDIVERT_FILTER_FIELD_ICMP_CHECKSUM 32
|
||||
#define WINDIVERT_FILTER_FIELD_ICMP_BODY 33
|
||||
#define WINDIVERT_FILTER_FIELD_ICMPV6_TYPE 34
|
||||
#define WINDIVERT_FILTER_FIELD_ICMPV6_CODE 35
|
||||
#define WINDIVERT_FILTER_FIELD_ICMPV6_CHECKSUM 36
|
||||
#define WINDIVERT_FILTER_FIELD_ICMPV6_BODY 37
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_SRCPORT 38
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_DSTPORT 39
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_SEQNUM 40
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_ACKNUM 41
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH 42
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_URG 43
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_ACK 44
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_PSH 45
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_RST 46
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_SYN 47
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_FIN 48
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_WINDOW 49
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_CHECKSUM 50
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_URGPTR 51
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH 52
|
||||
#define WINDIVERT_FILTER_FIELD_UDP_SRCPORT 53
|
||||
#define WINDIVERT_FILTER_FIELD_UDP_DSTPORT 54
|
||||
#define WINDIVERT_FILTER_FIELD_UDP_LENGTH 55
|
||||
#define WINDIVERT_FILTER_FIELD_UDP_CHECKSUM 56
|
||||
#define WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH 57
|
||||
#define WINDIVERT_FILTER_FIELD_LOOPBACK 58
|
||||
#define WINDIVERT_FILTER_FIELD_IMPOSTOR 59
|
||||
#define WINDIVERT_FILTER_FIELD_PROCESSID 60
|
||||
#define WINDIVERT_FILTER_FIELD_LOCALADDR 61
|
||||
#define WINDIVERT_FILTER_FIELD_REMOTEADDR 62
|
||||
#define WINDIVERT_FILTER_FIELD_LOCALPORT 63
|
||||
#define WINDIVERT_FILTER_FIELD_REMOTEPORT 64
|
||||
#define WINDIVERT_FILTER_FIELD_PROTOCOL 65
|
||||
#define WINDIVERT_FILTER_FIELD_ENDPOINTID 66
|
||||
#define WINDIVERT_FILTER_FIELD_PARENTENDPOINTID 67
|
||||
#define WINDIVERT_FILTER_FIELD_LAYER 68
|
||||
#define WINDIVERT_FILTER_FIELD_PRIORITY 69
|
||||
#define WINDIVERT_FILTER_FIELD_EVENT 70
|
||||
#define WINDIVERT_FILTER_FIELD_PACKET 71
|
||||
#define WINDIVERT_FILTER_FIELD_PACKET16 72
|
||||
#define WINDIVERT_FILTER_FIELD_PACKET32 73
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_PAYLOAD 74
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16 75
|
||||
#define WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32 76
|
||||
#define WINDIVERT_FILTER_FIELD_UDP_PAYLOAD 77
|
||||
#define WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16 78
|
||||
#define WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32 79
|
||||
#define WINDIVERT_FILTER_FIELD_LENGTH 80
|
||||
#define WINDIVERT_FILTER_FIELD_TIMESTAMP 81
|
||||
#define WINDIVERT_FILTER_FIELD_RANDOM8 82
|
||||
#define WINDIVERT_FILTER_FIELD_RANDOM16 83
|
||||
#define WINDIVERT_FILTER_FIELD_RANDOM32 84
|
||||
#define WINDIVERT_FILTER_FIELD_FRAGMENT 85
|
||||
#define WINDIVERT_FILTER_FIELD_MAX \
|
||||
WINDIVERT_FILTER_FIELD_FRAGMENT
|
||||
|
||||
#define WINDIVERT_FILTER_TEST_EQ 0
|
||||
#define WINDIVERT_FILTER_TEST_NEQ 1
|
||||
#define WINDIVERT_FILTER_TEST_LT 2
|
||||
#define WINDIVERT_FILTER_TEST_LEQ 3
|
||||
#define WINDIVERT_FILTER_TEST_GT 4
|
||||
#define WINDIVERT_FILTER_TEST_GEQ 5
|
||||
#define WINDIVERT_FILTER_TEST_MAX WINDIVERT_FILTER_TEST_GEQ
|
||||
|
||||
#define WINDIVERT_FILTER_MAXLEN 256
|
||||
|
||||
#define WINDIVERT_FILTER_RESULT_ACCEPT 0x7FFE
|
||||
#define WINDIVERT_FILTER_RESULT_REJECT 0x7FFF
|
||||
|
||||
/*
|
||||
* WinDivert layers.
|
||||
*/
|
||||
#define WINDIVERT_LAYER_MAX WINDIVERT_LAYER_REFLECT
|
||||
|
||||
/*
|
||||
* WinDivert events.
|
||||
*/
|
||||
#define WINDIVERT_EVENT_MAX \
|
||||
WINDIVERT_EVENT_REFLECT_CLOSE
|
||||
|
||||
/*
|
||||
* WinDivert flags.
|
||||
*/
|
||||
#define WINDIVERT_FLAGS_ALL \
|
||||
(WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_DROP | WINDIVERT_FLAG_RECV_ONLY |\
|
||||
WINDIVERT_FLAG_SEND_ONLY | WINDIVERT_FLAG_NO_INSTALL | \
|
||||
WINDIVERT_FLAG_FRAGMENTS)
|
||||
#define WINDIVERT_FLAGS_EXCLUDE(flags, flag1, flag2) \
|
||||
(((flags) & ((flag1) | (flag2))) != ((flag1) | (flag2)))
|
||||
#define WINDIVERT_FLAGS_VALID(flags) \
|
||||
((((flags) & ~WINDIVERT_FLAGS_ALL) == 0) && \
|
||||
WINDIVERT_FLAGS_EXCLUDE(flags, WINDIVERT_FLAG_SNIFF, \
|
||||
WINDIVERT_FLAG_DROP) && \
|
||||
WINDIVERT_FLAGS_EXCLUDE(flags, WINDIVERT_FLAG_RECV_ONLY, \
|
||||
WINDIVERT_FLAG_SEND_ONLY))
|
||||
|
||||
/*
|
||||
* WinDivert filter flags.
|
||||
*/
|
||||
#define WINDIVERT_FILTER_FLAG_INBOUND 0x0000000000000010ull
|
||||
#define WINDIVERT_FILTER_FLAG_OUTBOUND 0x0000000000000020ull
|
||||
#define WINDIVERT_FILTER_FLAG_IP 0x0000000000000040ull
|
||||
#define WINDIVERT_FILTER_FLAG_IPV6 0x0000000000000080ull
|
||||
#define WINDIVERT_FILTER_FLAG_EVENT_FLOW_DELETED 0x0000000000000100ull
|
||||
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_BIND 0x0000000000000200ull
|
||||
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CONNECT 0x0000000000000400ull
|
||||
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN 0x0000000000000800ull
|
||||
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_ACCEPT 0x0000000000001000ull
|
||||
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CLOSE 0x0000000000002000ull
|
||||
|
||||
#define WINDIVERT_FILTER_FLAGS_ALL \
|
||||
(WINDIVERT_FILTER_FLAG_INBOUND | \
|
||||
WINDIVERT_FILTER_FLAG_OUTBOUND | \
|
||||
WINDIVERT_FILTER_FLAG_IP | \
|
||||
WINDIVERT_FILTER_FLAG_IPV6 | \
|
||||
WINDIVERT_FILTER_FLAG_EVENT_FLOW_DELETED | \
|
||||
WINDIVERT_FILTER_FLAG_EVENT_SOCKET_BIND | \
|
||||
WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CONNECT | \
|
||||
WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN | \
|
||||
WINDIVERT_FILTER_FLAG_EVENT_SOCKET_ACCEPT | \
|
||||
WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CLOSE)
|
||||
|
||||
/*
|
||||
* WinDivert priorities.
|
||||
*/
|
||||
#define WINDIVERT_PRIORITY_MAX WINDIVERT_PRIORITY_HIGHEST
|
||||
#define WINDIVERT_PRIORITY_MIN WINDIVERT_PRIORITY_LOWEST
|
||||
|
||||
/*
|
||||
* WinDivert timestamps.
|
||||
*/
|
||||
#define WINDIVERT_TIMESTAMP_MAX 0x7FFFFFFFFFFFFFFFull
|
||||
|
||||
/*
|
||||
* WinDivert message definitions.
|
||||
*/
|
||||
#pragma pack(push, 1)
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
UINT64 addr; // WINDIVERT_ADDRESS pointer.
|
||||
UINT64 addr_len_ptr; // sizeof(addr) pointer.
|
||||
} recv;
|
||||
struct
|
||||
{
|
||||
UINT64 addr; // WINDIVERT_ADDRESS pointer.
|
||||
UINT64 addr_len; // sizeof(addr).
|
||||
} send;
|
||||
struct
|
||||
{
|
||||
UINT32 layer; // Handle layer.
|
||||
UINT32 priority; // Handle priority.
|
||||
UINT64 flags; // Handle flags.
|
||||
} initialize;
|
||||
struct
|
||||
{
|
||||
UINT64 flags; // Filter flags.
|
||||
} startup;
|
||||
struct
|
||||
{
|
||||
UINT32 how; // WINDIVERT_SHUTDOWN_*
|
||||
} shutdown;
|
||||
struct
|
||||
{
|
||||
UINT32 param; // WINDIVERT_PARAM_*
|
||||
} get_param;
|
||||
struct
|
||||
{
|
||||
UINT64 val; // Value pointer.
|
||||
UINT32 param; // WINDIVERT_PARAM_*
|
||||
} set_param;
|
||||
} WINDIVERT_IOCTL, *PWINDIVERT_IOCTL;
|
||||
|
||||
/*
|
||||
* WinDivert initialization structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
UINT64 magic; // Magic number (in/out).
|
||||
UINT32 major; // Driver major version (in/out).
|
||||
UINT32 minor; // Driver minor version (in/out).
|
||||
UINT32 bits; // 32 or 64 (in/out).
|
||||
UINT32 reserved32[3];
|
||||
UINT64 reserved64[4];
|
||||
} WINDIVERT_VERSION, *PWINDIVERT_VERSION;
|
||||
|
||||
/*
|
||||
* WinDivert filter structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
UINT32 field:11; // WINDIVERT_FILTER_FIELD_*
|
||||
UINT32 test:5; // WINDIVERT_FILTER_TEST_*
|
||||
UINT32 success:16; // Success continuation.
|
||||
UINT32 failure:16; // Fail continuation.
|
||||
UINT32 neg:1; // Argument negative?
|
||||
UINT32 reserved:15;
|
||||
UINT32 arg[4]; // Argument.
|
||||
} WINDIVERT_FILTER, *PWINDIVERT_FILTER;
|
||||
#pragma pack(pop)
|
||||
|
||||
/*
|
||||
* IOCTL codes.
|
||||
*/
|
||||
#define IOCTL_WINDIVERT_INITIALIZE \
|
||||
CTL_CODE(FILE_DEVICE_NETWORK, 0x921, METHOD_OUT_DIRECT, FILE_READ_DATA |\
|
||||
FILE_WRITE_DATA)
|
||||
#define IOCTL_WINDIVERT_STARTUP \
|
||||
CTL_CODE(FILE_DEVICE_NETWORK, 0x922, METHOD_IN_DIRECT, FILE_READ_DATA | \
|
||||
FILE_WRITE_DATA)
|
||||
#define IOCTL_WINDIVERT_RECV \
|
||||
CTL_CODE(FILE_DEVICE_NETWORK, 0x923, METHOD_OUT_DIRECT, FILE_READ_DATA)
|
||||
#define IOCTL_WINDIVERT_SEND \
|
||||
CTL_CODE(FILE_DEVICE_NETWORK, 0x924, METHOD_IN_DIRECT, FILE_READ_DATA | \
|
||||
FILE_WRITE_DATA)
|
||||
#define IOCTL_WINDIVERT_SET_PARAM \
|
||||
CTL_CODE(FILE_DEVICE_NETWORK, 0x925, METHOD_IN_DIRECT, FILE_READ_DATA | \
|
||||
FILE_WRITE_DATA)
|
||||
#define IOCTL_WINDIVERT_GET_PARAM \
|
||||
CTL_CODE(FILE_DEVICE_NETWORK, 0x926, METHOD_OUT_DIRECT, FILE_READ_DATA)
|
||||
#define IOCTL_WINDIVERT_SHUTDOWN \
|
||||
CTL_CODE(FILE_DEVICE_NETWORK, 0x927, METHOD_IN_DIRECT, FILE_READ_DATA | \
|
||||
FILE_WRITE_DATA)
|
||||
|
||||
#endif /* __WINDIVERT_DEVICE_H */
|
||||
203
src/ProcessDrv/tun/WinDivert/divert/windivert_hash.c
Normal file
203
src/ProcessDrv/tun/WinDivert/divert/windivert_hash.c
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* windivert_hash.c
|
||||
* (C) 2019, all rights reserved,
|
||||
*
|
||||
* This file is part of WinDivert.
|
||||
*
|
||||
* WinDivert is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* WinDivert is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* xxHash - Fast Hash algorithm
|
||||
* Copyright (C) 2012-2016, Yann Collet
|
||||
*
|
||||
* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a modified version of the 64bit xxHash algorithm:
|
||||
* - The algorithm is seeded with packet data rather than the single 64bit
|
||||
* "seed" value.
|
||||
* - The input sized is fixed to 32bytes (excluding the seed), so there is
|
||||
* only ever a single round. As such, the algorithm has been specialized.
|
||||
*/
|
||||
|
||||
#define WINDIVERT_ROTL64(x, r) (((x) << (r)) | ((x) >> (64 - (r))))
|
||||
|
||||
static const UINT64 WINDIVERT_PRIME64_1 = 11400714785074694791ull;
|
||||
static const UINT64 WINDIVERT_PRIME64_2 = 14029467366897019727ull;
|
||||
static const UINT64 WINDIVERT_PRIME64_3 = 1609587929392839161ull;
|
||||
static const UINT64 WINDIVERT_PRIME64_4 = 9650029242287828579ull;
|
||||
|
||||
static UINT64 WinDivertXXH64Round(UINT64 acc, UINT64 input)
|
||||
{
|
||||
acc += WINDIVERT_MUL64(input, WINDIVERT_PRIME64_2);
|
||||
acc = WINDIVERT_ROTL64(acc, 31);
|
||||
acc = WINDIVERT_MUL64(acc, WINDIVERT_PRIME64_1);
|
||||
return acc;
|
||||
}
|
||||
|
||||
static UINT64 WinDivertXXH64MergeRound(UINT64 acc, UINT64 val)
|
||||
{
|
||||
val = WinDivertXXH64Round(0, val);
|
||||
acc ^= val;
|
||||
acc = WINDIVERT_MUL64(acc, WINDIVERT_PRIME64_1) + WINDIVERT_PRIME64_4;
|
||||
return acc;
|
||||
}
|
||||
|
||||
static UINT64 WinDivertXXH64Avalanche(UINT64 h64)
|
||||
{
|
||||
h64 ^= h64 >> 33;
|
||||
h64 = WINDIVERT_MUL64(h64, WINDIVERT_PRIME64_2);
|
||||
h64 ^= h64 >> 29;
|
||||
h64 = WINDIVERT_MUL64(h64, WINDIVERT_PRIME64_3);
|
||||
h64 ^= h64 >> 32;
|
||||
return h64;
|
||||
}
|
||||
|
||||
/*
|
||||
* WinDivert packet hash function.
|
||||
*/
|
||||
static UINT64 WinDivertHashPacket(UINT64 seed,
|
||||
const WINDIVERT_IPHDR *ip_header, const WINDIVERT_IPV6HDR *ipv6_header,
|
||||
const WINDIVERT_ICMPHDR *icmp_header,
|
||||
const WINDIVERT_ICMPV6HDR *icmpv6_header,
|
||||
const WINDIVERT_TCPHDR *tcp_header, const WINDIVERT_UDPHDR *udp_header)
|
||||
{
|
||||
UINT64 h64, v1, v2, v3, v4, v[4];
|
||||
const UINT64 *data64;
|
||||
const UINT32 *data32;
|
||||
UINT i;
|
||||
static const UINT64 padding64[] = // SHA2 IV
|
||||
{
|
||||
0x428A2F9871374491ull, 0xB5C0FBCFE9B5DBA5ull, 0x3956C25B59F111F1ull,
|
||||
0x923F82A4AB1C5ED5ull, 0xD807AA9812835B01ull, 0x243185BE550C7DC3ull,
|
||||
0x72BE5D7480DEB1FEull, 0x9BDC06A7C19BF174ull, 0xE49B69C1EFBE4786ull,
|
||||
};
|
||||
|
||||
// Set-up seed & data
|
||||
v1 = seed ^ padding64[0];
|
||||
if (ip_header != NULL)
|
||||
{
|
||||
data64 = (const UINT64 *)ip_header;
|
||||
v2 = data64[0] ^ padding64[1];
|
||||
v3 = data64[1] ^ padding64[2];
|
||||
data32 = (const UINT32 *)ip_header;
|
||||
v4 = (UINT64)data32[4] ^ padding64[3];
|
||||
i = 0;
|
||||
}
|
||||
else if (ipv6_header != NULL)
|
||||
{
|
||||
data64 = (const UINT64 *)ipv6_header;
|
||||
v2 = data64[0] ^ padding64[1];
|
||||
v3 = data64[1] ^ padding64[2];
|
||||
v4 = data64[2] ^ padding64[3];
|
||||
v[0] = data64[3] ^ padding64[4];
|
||||
v[1] = data64[4] ^ padding64[5];
|
||||
i = 2;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (tcp_header != NULL)
|
||||
{
|
||||
data64 = (const UINT64 *)tcp_header;
|
||||
v[i] = data64[0] ^ padding64[i+4]; i++;
|
||||
v[i] = data64[1] ^ padding64[i+4]; i++;
|
||||
data32 = (const UINT32 *)tcp_header;
|
||||
if (i <= 3)
|
||||
{
|
||||
v[i] = (UINT64)data32[4] ^ padding64[i+4]; i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
v2 ^= ((UINT64)data32[4] << 32);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (udp_header != NULL)
|
||||
{
|
||||
data64 = (const UINT64 *)udp_header;
|
||||
v[i] = data64[0] ^ padding64[i+4]; i++;
|
||||
}
|
||||
else if (icmp_header != NULL)
|
||||
{
|
||||
data64 = (const UINT64 *)icmp_header;
|
||||
v[i] = data64[0] ^ padding64[i+4]; i++;
|
||||
}
|
||||
else if (icmpv6_header != NULL)
|
||||
{
|
||||
data64 = (const UINT64 *)icmpv6_header;
|
||||
v[i] = data64[0] ^ padding64[i+4]; i++;
|
||||
}
|
||||
}
|
||||
|
||||
while (i <= 3)
|
||||
{
|
||||
v[i] = seed ^ padding64[i+4]; i++;
|
||||
}
|
||||
|
||||
// Hash
|
||||
v1 = WinDivertXXH64Round(v[0], v1);
|
||||
v2 = WinDivertXXH64Round(v[1], v2);
|
||||
v3 = WinDivertXXH64Round(v[2], v3);
|
||||
v4 = WinDivertXXH64Round(v[3], v4);
|
||||
h64 = WINDIVERT_ROTL64(v1, 1) + WINDIVERT_ROTL64(v2, 7) +
|
||||
WINDIVERT_ROTL64(v3, 12) + WINDIVERT_ROTL64(v4, 18);
|
||||
h64 = WinDivertXXH64MergeRound(h64, v1);
|
||||
h64 = WinDivertXXH64MergeRound(h64, v2);
|
||||
h64 = WinDivertXXH64MergeRound(h64, v3);
|
||||
h64 = WinDivertXXH64MergeRound(h64, v4);
|
||||
h64 += 32; // "length"
|
||||
h64 = WinDivertXXH64Avalanche(h64);
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
4330
src/ProcessDrv/tun/WinDivert/divert/windivert_helper.c
Normal file
4330
src/ProcessDrv/tun/WinDivert/divert/windivert_helper.c
Normal file
File diff suppressed because it is too large
Load Diff
1738
src/ProcessDrv/tun/WinDivert/divert/windivert_shared.c
Normal file
1738
src/ProcessDrv/tun/WinDivert/divert/windivert_shared.c
Normal file
File diff suppressed because it is too large
Load Diff
209
src/ProcessDrv/tun/WinDivert/divert_cgo.go
Normal file
209
src/ProcessDrv/tun/WinDivert/divert_cgo.go
Normal file
@@ -0,0 +1,209 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package WinDivert
|
||||
|
||||
// #cgo CFLAGS: -I${SRCDIR}/divert -Wno-incompatible-pointer-types
|
||||
// #define WINDIVERTEXPORT static
|
||||
// #include "windivert.c"
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// Open is ...
|
||||
func Open(filter string, layer Layer, priority int16, flags uint64) (h *Handle, err error) {
|
||||
once.Do(func() {
|
||||
vers := map[string]struct{}{
|
||||
"2.0": {},
|
||||
"2.1": {},
|
||||
"2.2": {},
|
||||
}
|
||||
ver, er := func() (ver string, err error) {
|
||||
h, err := open("false", LayerNetwork, PriorityDefault, FlagDefault)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
err = h.Close()
|
||||
}()
|
||||
|
||||
major, err := h.GetParam(VersionMajor)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
minor, err := h.GetParam(VersionMinor)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ver = strings.Join([]string{strconv.Itoa(int(major)), strconv.Itoa(int(minor))}, ".")
|
||||
return
|
||||
}()
|
||||
if er != nil {
|
||||
err = er
|
||||
return
|
||||
}
|
||||
if _, ok := vers[ver]; !ok {
|
||||
err = fmt.Errorf("unsupported windivert version: %v", ver)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return open(filter, layer, priority, flags)
|
||||
}
|
||||
|
||||
func open(filter string, layer Layer, priority int16, flags uint64) (h *Handle, err error) {
|
||||
if priority < PriorityLowest || priority > PriorityHighest {
|
||||
return nil, errPriority
|
||||
}
|
||||
|
||||
runtime.LockOSThread()
|
||||
hd := C.WinDivertOpen(C.CString(filter), C.WINDIVERT_LAYER(layer), C.int16_t(priority), C.uint64_t(flags))
|
||||
runtime.UnlockOSThread()
|
||||
|
||||
if hd == C.HANDLE(C.INVALID_HANDLE_VALUE) {
|
||||
return nil, Error(C.GetLastError())
|
||||
}
|
||||
|
||||
rEvent, _ := windows.CreateEvent(nil, 0, 0, nil)
|
||||
wEvent, _ := windows.CreateEvent(nil, 0, 0, nil)
|
||||
|
||||
return &Handle{
|
||||
Mutex: sync.Mutex{},
|
||||
Handle: windows.Handle(uintptr(unsafe.Pointer(hd))),
|
||||
rOverlapped: windows.Overlapped{
|
||||
HEvent: rEvent,
|
||||
},
|
||||
wOverlapped: windows.Overlapped{
|
||||
HEvent: wEvent,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CalcChecksums is ...
|
||||
func CalcChecksums(buffer []byte, address *Address, flags uint64) bool {
|
||||
re := C.WinDivertHelperCalcChecksums(unsafe.Pointer(&buffer[0]), C.UINT(len(buffer)), (*C.WINDIVERT_ADDRESS)(unsafe.Pointer(address)), C.uint64_t(flags))
|
||||
return re == C.TRUE
|
||||
}
|
||||
|
||||
// IPv4 header
|
||||
type IPv4Header struct {
|
||||
VersionIHL uint8
|
||||
TOS uint8
|
||||
TotalLength uint16
|
||||
ID uint16
|
||||
FlagsFragOffset uint16
|
||||
TTL uint8
|
||||
Protocol uint8
|
||||
Checksum uint16
|
||||
SrcAddr [4]byte
|
||||
DstAddr [4]byte
|
||||
SrcPort uint16
|
||||
DstPort uint16
|
||||
Name string
|
||||
V4 bool
|
||||
}
|
||||
|
||||
// IPv6 header
|
||||
type IPv6Header struct {
|
||||
VersionTCFlow uint32
|
||||
PayloadLength uint16
|
||||
NextHeader uint8
|
||||
HopLimit uint8
|
||||
SrcAddr [16]byte
|
||||
DstAddr [16]byte
|
||||
SrcPort uint16
|
||||
DstPort uint16
|
||||
Name string
|
||||
V4 bool
|
||||
}
|
||||
type DataPacket interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
func (v6 IPv6Header) String() string {
|
||||
srcIP := net.IP(v6.SrcAddr[:])
|
||||
dstIP := net.IP(v6.DstAddr[:])
|
||||
return fmt.Sprintf("[%s]%s:%d->%s:%d", v6.Name, srcIP.String(), v6.SrcPort, dstIP.String(), v6.DstPort)
|
||||
}
|
||||
func (v4 IPv4Header) String() string {
|
||||
srcIP := net.IP(v4.SrcAddr[:])
|
||||
dstIP := net.IP(v4.DstAddr[:])
|
||||
return fmt.Sprintf("[%s]%s:%d->%s:%d", v4.Name, srcIP.String(), v4.SrcPort, dstIP.String(), v4.DstPort)
|
||||
}
|
||||
func ParsePacket(data []byte) DataPacket {
|
||||
if len(data) < 1 {
|
||||
return nil
|
||||
}
|
||||
version := data[0] >> 4
|
||||
if version == 4 {
|
||||
if len(data) < 20 {
|
||||
return nil
|
||||
}
|
||||
ip := IPv4Header{
|
||||
VersionIHL: data[0],
|
||||
TOS: data[1],
|
||||
TotalLength: binary.BigEndian.Uint16(data[2:4]),
|
||||
ID: binary.BigEndian.Uint16(data[4:6]),
|
||||
FlagsFragOffset: binary.BigEndian.Uint16(data[6:8]),
|
||||
TTL: data[8],
|
||||
Protocol: data[9],
|
||||
Checksum: binary.BigEndian.Uint16(data[10:12]),
|
||||
}
|
||||
copy(ip.SrcAddr[:], data[12:16])
|
||||
copy(ip.DstAddr[:], data[16:20])
|
||||
ip.V4 = true
|
||||
offset := int((ip.VersionIHL & 0x0F) * 4)
|
||||
if ip.Protocol == 6 && len(data) >= offset+20 {
|
||||
ip.Name = "TCP"
|
||||
ip.SrcPort = binary.BigEndian.Uint16(data[offset : offset+2])
|
||||
ip.DstPort = binary.BigEndian.Uint16(data[offset+2 : offset+4])
|
||||
} else if ip.Protocol == 17 && len(data) >= offset+8 {
|
||||
ip.Name = "UDP"
|
||||
ip.SrcPort = binary.BigEndian.Uint16(data[offset : offset+2])
|
||||
ip.DstPort = binary.BigEndian.Uint16(data[offset+2 : offset+4])
|
||||
}
|
||||
return &ip
|
||||
} else if version == 6 {
|
||||
// IPv6
|
||||
if len(data) < 40 {
|
||||
return nil
|
||||
}
|
||||
ip := IPv6Header{
|
||||
VersionTCFlow: binary.BigEndian.Uint32(data[0:4]),
|
||||
PayloadLength: binary.BigEndian.Uint16(data[4:6]),
|
||||
NextHeader: data[6],
|
||||
HopLimit: data[7],
|
||||
}
|
||||
copy(ip.SrcAddr[:], data[8:24])
|
||||
copy(ip.DstAddr[:], data[24:40])
|
||||
ip.V4 = false
|
||||
offset := 40
|
||||
if ip.NextHeader == 6 && len(data) >= offset+20 {
|
||||
ip.Name = "TCP"
|
||||
// TCP
|
||||
ip.SrcPort = binary.BigEndian.Uint16(data[offset : offset+2])
|
||||
ip.DstPort = binary.BigEndian.Uint16(data[offset+2 : offset+4])
|
||||
} else if ip.NextHeader == 17 && len(data) >= offset+8 {
|
||||
ip.Name = "UDP"
|
||||
ip.SrcPort = binary.BigEndian.Uint16(data[offset : offset+2])
|
||||
ip.DstPort = binary.BigEndian.Uint16(data[offset+2 : offset+4])
|
||||
}
|
||||
return &ip
|
||||
}
|
||||
return nil
|
||||
}
|
||||
145
src/ProcessDrv/tun/WinDivert/dns.gbak
Normal file
145
src/ProcessDrv/tun/WinDivert/dns.gbak
Normal file
@@ -0,0 +1,145 @@
|
||||
package divert
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func (d *Divert) handleDNS53(h *Handle, data []byte, addr *Address, SrcIP, DstIP net.IP, v4 bool, pkt gopacket.Packet) bool {
|
||||
udpLayer := pkt.Layer(layers.LayerTypeUDP)
|
||||
dnsLayer := pkt.Layer(layers.LayerTypeDNS)
|
||||
if udpLayer == nil || dnsLayer == nil {
|
||||
return false
|
||||
}
|
||||
udp := udpLayer.(*layers.UDP)
|
||||
dns := dnsLayer.(*layers.DNS)
|
||||
if udp.DstPort != 53 && udp.SrcPort != 53 {
|
||||
return false
|
||||
}
|
||||
if dns.QR { // 不是请求则跳过(我们只伪造请求的响应)
|
||||
return false
|
||||
}
|
||||
if len(dns.Questions) == 0 {
|
||||
return false
|
||||
}
|
||||
q := dns.Questions[0]
|
||||
if q.Type != layers.DNSTypeA {
|
||||
return false
|
||||
}
|
||||
respDNS := &layers.DNS{
|
||||
ID: dns.ID,
|
||||
QR: true,
|
||||
OpCode: dns.OpCode,
|
||||
AA: true,
|
||||
RD: dns.RD,
|
||||
RA: true,
|
||||
ResponseCode: layers.DNSResponseCodeNoErr,
|
||||
QDCount: dns.QDCount,
|
||||
ANCount: 1,
|
||||
Questions: dns.Questions,
|
||||
}
|
||||
name := string(q.Name)
|
||||
dnsMutex.Lock()
|
||||
a := getDnsName(name)
|
||||
if a == "" {
|
||||
a = createLocalHost()
|
||||
addDns(name, a)
|
||||
}
|
||||
dnsMutex.Unlock()
|
||||
i := net.ParseIP(a)
|
||||
rr := layers.DNSResourceRecord{
|
||||
Name: q.Name,
|
||||
Type: layers.DNSTypeA,
|
||||
Class: layers.DNSClassIN,
|
||||
TTL: 3,
|
||||
IP: i,
|
||||
}
|
||||
respDNS.Answers = []layers.DNSResourceRecord{rr}
|
||||
var respIP gopacket.NetworkLayer
|
||||
var respIP2 gopacket.SerializableLayer
|
||||
if v4 {
|
||||
ip := &layers.IPv4{
|
||||
Version: 4,
|
||||
IHL: 5,
|
||||
TTL: 3,
|
||||
Protocol: layers.IPProtocolUDP,
|
||||
SrcIP: DstIP,
|
||||
DstIP: SrcIP,
|
||||
}
|
||||
respIP = ip
|
||||
respIP2 = ip
|
||||
} else {
|
||||
ip := &layers.IPv6{
|
||||
Version: 6,
|
||||
TrafficClass: 0,
|
||||
FlowLabel: 0,
|
||||
HopLimit: 3,
|
||||
NextHeader: layers.IPProtocolUDP,
|
||||
SrcIP: DstIP,
|
||||
DstIP: SrcIP,
|
||||
}
|
||||
respIP = ip
|
||||
respIP2 = ip
|
||||
}
|
||||
respUDP := &layers.UDP{
|
||||
SrcPort: layers.UDPPort(53),
|
||||
DstPort: udp.SrcPort,
|
||||
}
|
||||
_ = respUDP.SetNetworkLayerForChecksum(respIP)
|
||||
buf := gopacket.NewSerializeBuffer()
|
||||
opts := gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true}
|
||||
_ = gopacket.SerializeLayers(buf, opts, respIP2, respUDP, respDNS)
|
||||
addr2 := addr.Clone()
|
||||
addr2.SetOutbound(false)
|
||||
if _, err := h.Send(buf.Bytes(), addr2); err != nil {
|
||||
return false
|
||||
}
|
||||
fmt.Println(name, "->", a)
|
||||
return true
|
||||
}
|
||||
|
||||
var dnsMutex sync.Mutex
|
||||
var udpList1 = make(map[string]string)
|
||||
var udpList2 = make(map[string]string)
|
||||
|
||||
func addDns(name string, val string) {
|
||||
udpList1[name] = val
|
||||
udpList2[val] = name
|
||||
}
|
||||
func getDnsName(name string) string {
|
||||
return udpList1[name]
|
||||
}
|
||||
func getDnsValue(val string) string {
|
||||
dnsMutex.Lock()
|
||||
defer dnsMutex.Unlock()
|
||||
return udpList2[val]
|
||||
}
|
||||
|
||||
var local [3]int = [3]int{1, 2, 2}
|
||||
|
||||
func createLocalHost() string {
|
||||
a1 := local[0]
|
||||
a2 := local[1]
|
||||
a3 := local[2]
|
||||
a3++
|
||||
if a3 > 254 {
|
||||
a3 = 2
|
||||
a2++
|
||||
}
|
||||
if a2 > 254 {
|
||||
a2 = 2
|
||||
a1++
|
||||
}
|
||||
if a1 > 254 {
|
||||
a1 = 1
|
||||
a2 = 2
|
||||
a3 = 2
|
||||
}
|
||||
local[0] = a1
|
||||
local[1] = a2
|
||||
local[2] = a3
|
||||
return fmt.Sprintf("10.%d.%d.%d", a1, a2, a3)
|
||||
}
|
||||
102
src/ProcessDrv/tun/WinDivert/error.go
Normal file
102
src/ProcessDrv/tun/WinDivert/error.go
Normal file
@@ -0,0 +1,102 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package WinDivert
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
errQueueLength = fmt.Errorf("Queue length is not correct, Max: %v, Min: %v", QueueLengthMax, QueueLengthMin)
|
||||
errQueueTime = fmt.Errorf("Queue time is not correct, Max: %v, Min: %v", QueueTimeMax, QueueTimeMin)
|
||||
errQueueSize = fmt.Errorf("Queue size is not correct, Max: %v, Min: %v", QueueSizeMax, QueueSizeMin)
|
||||
errQueueParam = errors.New("VersionMajor and VersionMinor only can be used in function GetParam")
|
||||
errPriority = fmt.Errorf("Priority is not Correct, Max: %v, Min: %v", PriorityHighest, PriorityLowest)
|
||||
)
|
||||
|
||||
const (
|
||||
// The driver files WinDivert32.sys or WinDivert64.sys were not found
|
||||
ErrFileNotFound = Error(windows.ERROR_FILE_NOT_FOUND)
|
||||
|
||||
// The calling application does not have Administrator privileges
|
||||
ErrAccessDenied = Error(windows.ERROR_ACCESS_DENIED)
|
||||
|
||||
// This indicates an invalid packet filter string, layer, priority, or flags
|
||||
ErrInvalidParameter = Error(windows.ERROR_INVALID_PARAMETER)
|
||||
|
||||
// The WinDivert32.sys or WinDivert64.sys driver does not have a valid digital signature (see the driver signing requirements above)
|
||||
ErrInvalidImageHash = Error(windows.ERROR_INVALID_IMAGE_HASH)
|
||||
|
||||
// An incompatible version of the WinDivert driver is currently loaded
|
||||
ErrDriverFailedPriorUnload = Error(windows.ERROR_DRIVER_FAILED_PRIOR_UNLOAD)
|
||||
|
||||
// The handle was opened with the WINDIVERT_FLAG_NO_INSTALL flag and the WinDivert driver is not already installed
|
||||
ErrServiceDoseNotExist = Error(windows.ERROR_SERVICE_DOES_NOT_EXIST)
|
||||
|
||||
// This error occurs for various reasons, including: the WinDivert driver is blocked by security software; or you are using a virtualization environment that does not support drivers
|
||||
ErrDriverBlocked = Error(windows.ERROR_DRIVER_BLOCKED)
|
||||
|
||||
// The captured packet is larger than the pPacket buffer
|
||||
ErrInsufficientBuffer = Error(windows.ERROR_INSUFFICIENT_BUFFER)
|
||||
|
||||
// The handle has been shutdown using WinDivertShutdown() and the packet queue is empty
|
||||
ErrNoData = Error(windows.ERROR_NO_DATA)
|
||||
|
||||
// The error code ERROR_IO_PENDING indicates that the overlapped operation has been successfully initiated and that completion will be indicated at a later time
|
||||
ErrIOPending = Error(windows.ERROR_IO_PENDING)
|
||||
|
||||
// This error occurs when an impostor packet (with pAddr->Impostor set to 1) is injected and the ip.TTL or ipv6.HopLimit field goes to zero. This is a defense of "last resort" against infinite loops caused by impostor packets
|
||||
ErrHostUnreachable = Error(windows.ERROR_HOST_UNREACHABLE)
|
||||
|
||||
// This error occurs when the Base Filtering Engine service has been disabled
|
||||
ErrNotRegistered = Error(windows.EPT_S_NOT_REGISTERED)
|
||||
|
||||
// The I/O operation has been aborted because of either a thread exit or an application request
|
||||
ErrOperationAborted = Error(windows.ERROR_OPERATION_ABORTED)
|
||||
|
||||
// The handle is invalid
|
||||
ErrInvalidHandle = Error(windows.ERROR_INVALID_HANDLE)
|
||||
)
|
||||
|
||||
// Error is ...
|
||||
type Error windows.Errno
|
||||
|
||||
// Error is ...
|
||||
func (e Error) Error() string {
|
||||
switch windows.Errno(e) {
|
||||
case windows.ERROR_FILE_NOT_FOUND:
|
||||
return "The driver files WinDivert32.sys or WinDivert64.sys were not found"
|
||||
case windows.ERROR_ACCESS_DENIED:
|
||||
return "The calling application does not have Administrator privileges"
|
||||
case windows.ERROR_INVALID_PARAMETER:
|
||||
return "This indicates an invalid packet filter string, layer, priority, or flags"
|
||||
case windows.ERROR_INVALID_IMAGE_HASH:
|
||||
return "The WinDivert32.sys or WinDivert64.sys driver does not have a valid digital signature (see the driver signing requirements above)"
|
||||
case windows.ERROR_DRIVER_FAILED_PRIOR_UNLOAD:
|
||||
return "An incompatible version of the WinDivert driver is currently loaded"
|
||||
case windows.ERROR_SERVICE_DOES_NOT_EXIST:
|
||||
return "The handle was opened with the WINDIVERT_FLAG_NO_INSTALL flag and the WinDivert driver is not already installed"
|
||||
case windows.ERROR_DRIVER_BLOCKED:
|
||||
return "This error occurs for various reasons, including: the WinDivert driver is blocked by security software; or you are using a virtualization environment that does not support drivers"
|
||||
case windows.ERROR_INSUFFICIENT_BUFFER:
|
||||
return "The captured packet is larger than the pPacket buffer"
|
||||
case windows.ERROR_NO_DATA:
|
||||
return "The handle has been shutdown using WinDivertShutdown() and the packet queue is empty"
|
||||
case windows.ERROR_IO_PENDING:
|
||||
return "The error code ERROR_IO_PENDING indicates that the overlapped operation has been successfully initiated and that completion will be indicated at a later time"
|
||||
case windows.ERROR_HOST_UNREACHABLE:
|
||||
return "This error occurs when an impostor packet (with pAddr->Impostor set to 1) is injected and the ip.TTL or ipv6.HopLimit field goes to zero. This is a defense of \"last resort\" against infinite loops caused by impostor packets"
|
||||
case windows.EPT_S_NOT_REGISTERED:
|
||||
return "This error occurs when the Base Filtering Engine service has been disabled"
|
||||
case windows.ERROR_OPERATION_ABORTED:
|
||||
return "The I/O operation has been aborted because of either a thread exit or an application request"
|
||||
case windows.ERROR_INVALID_HANDLE:
|
||||
return "The handle is invalid"
|
||||
default:
|
||||
return windows.Errno(e).Error()
|
||||
}
|
||||
}
|
||||
133
src/ProcessDrv/tun/WinDivert/main.go
Normal file
133
src/ProcessDrv/tun/WinDivert/main.go
Normal file
@@ -0,0 +1,133 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package WinDivert
|
||||
|
||||
import (
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/tun/Tun"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var _myPid = int32(os.Getpid())
|
||||
|
||||
type Divert struct {
|
||||
handle, handle2 *Handle
|
||||
stopCh, stopCh2 chan struct{}
|
||||
handleMutex sync.Mutex
|
||||
wg sync.WaitGroup
|
||||
handleTCP Tun.TcpFunc
|
||||
handleUDP Tun.UdpFunc
|
||||
checkProcess func(int32, string) bool
|
||||
}
|
||||
|
||||
func NewWinDivert() *Divert {
|
||||
return &Divert{}
|
||||
}
|
||||
func (d *Divert) IsRunning() bool {
|
||||
return d.handle != nil
|
||||
}
|
||||
func (d *Divert) Close() {
|
||||
d.handleMutex.Lock()
|
||||
if d.handle != nil {
|
||||
_ = d.handle2.Close()
|
||||
}
|
||||
if d.handle2 != nil {
|
||||
_ = d.handle2.Close()
|
||||
}
|
||||
d.handle = nil
|
||||
d.handle2 = nil
|
||||
close(d.stopCh)
|
||||
close(d.stopCh2)
|
||||
d.handleMutex.Unlock()
|
||||
d.wg.Wait()
|
||||
}
|
||||
|
||||
const flowTcp = 6
|
||||
const flowudp = 17
|
||||
|
||||
func (d *Divert) Run() bool {
|
||||
d.handleMutex.Lock()
|
||||
if d.handle != nil {
|
||||
d.handleMutex.Unlock()
|
||||
return true
|
||||
}
|
||||
if !d.runFlow() {
|
||||
return false
|
||||
}
|
||||
h, err := Open("true", LayerNetwork, 0, 0)
|
||||
if err != nil {
|
||||
d.handleMutex.Unlock()
|
||||
return false
|
||||
}
|
||||
d.wg.Add(1)
|
||||
d.handle, d.stopCh = h, make(chan struct{})
|
||||
d.handleMutex.Unlock()
|
||||
|
||||
go func() {
|
||||
defer d.wg.Done()
|
||||
packetBuf := make([]byte, 0xffff)
|
||||
for {
|
||||
select {
|
||||
case <-d.stopCh:
|
||||
return
|
||||
default:
|
||||
}
|
||||
addr := &Address{}
|
||||
n, e := h.Recv(packetBuf, addr)
|
||||
if e != nil || n == 0 {
|
||||
continue
|
||||
}
|
||||
data := append([]byte(nil), packetBuf[:n]...)
|
||||
go func(bs []byte, a *Address) {
|
||||
if pkt := gopacket.NewPacket(bs, layers.LayerTypeIPv4, gopacket.Default); pkt.Layer(layers.LayerTypeIPv4) != nil {
|
||||
ip4 := pkt.Layer(layers.LayerTypeIPv4).(*layers.IPv4)
|
||||
// TCP v4
|
||||
if tcp := pkt.Layer(layers.LayerTypeTCP); tcp != nil {
|
||||
if d.handleIPv4(h, bs, a, ip4, pkt) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// UDP v4
|
||||
if udp := pkt.Layer(layers.LayerTypeUDP); udp != nil {
|
||||
if d.handleUDPv4(h, bs, a, ip4, pkt) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if pkt := gopacket.NewPacket(bs, layers.LayerTypeIPv6, gopacket.Default); pkt.Layer(layers.LayerTypeIPv6) != nil {
|
||||
ip6 := pkt.Layer(layers.LayerTypeIPv6).(*layers.IPv6)
|
||||
// TCP v6
|
||||
if tcp := pkt.Layer(layers.LayerTypeTCP); tcp != nil {
|
||||
if d.handleIPv6(h, bs, a, ip6, pkt) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// UDP v6
|
||||
if udp := pkt.Layer(layers.LayerTypeUDP); udp != nil {
|
||||
if d.handleUDPv6(h, bs, a, ip6, pkt) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
_, _ = h.Send(bs, a)
|
||||
}(data, addr)
|
||||
}
|
||||
}()
|
||||
return true
|
||||
}
|
||||
func (d *Divert) SetHandle(
|
||||
callbackTCP func(conn net.Conn),
|
||||
checkProcess func(int32, string) bool,
|
||||
udpSendReceiveFunc func(Type int, Theoni int64, pid uint32, LocalAddress, RemoteAddress string, data []byte) []byte) {
|
||||
sessionsMu.Lock()
|
||||
defer sessionsMu.Unlock()
|
||||
d.handleTCP = callbackTCP
|
||||
d.handleUDP = udpSendReceiveFunc
|
||||
d.checkProcess = checkProcess
|
||||
}
|
||||
3
src/ProcessDrv/tun/WinDivert/memmod/memmod_doc.go
Normal file
3
src/ProcessDrv/tun/WinDivert/memmod/memmod_doc.go
Normal file
@@ -0,0 +1,3 @@
|
||||
// 2022-02-04
|
||||
// https://github.com/WireGuard/wireguard-windows/tree/master/driver/memmod
|
||||
package memmod
|
||||
698
src/ProcessDrv/tun/WinDivert/memmod/memmod_windows.go
Normal file
698
src/ProcessDrv/tun/WinDivert/memmod/memmod_windows.go
Normal file
@@ -0,0 +1,698 @@
|
||||
/* 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))
|
||||
}
|
||||
16
src/ProcessDrv/tun/WinDivert/memmod/memmod_windows_32.go
Normal file
16
src/ProcessDrv/tun/WinDivert/memmod/memmod_windows_32.go
Normal file
@@ -0,0 +1,16 @@
|
||||
//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
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package memmod
|
||||
|
||||
const imageFileProcess = IMAGE_FILE_MACHINE_I386
|
||||
36
src/ProcessDrv/tun/WinDivert/memmod/memmod_windows_64.go
Normal file
36
src/ProcessDrv/tun/WinDivert/memmod/memmod_windows_64.go
Normal file
@@ -0,0 +1,36 @@
|
||||
//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
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package memmod
|
||||
|
||||
const imageFileProcess = IMAGE_FILE_MACHINE_AMD64
|
||||
@@ -0,0 +1,8 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package memmod
|
||||
|
||||
const imageFileProcess = IMAGE_FILE_MACHINE_ARMNT
|
||||
@@ -0,0 +1,8 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2022 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package memmod
|
||||
|
||||
const imageFileProcess = IMAGE_FILE_MACHINE_ARM64
|
||||
392
src/ProcessDrv/tun/WinDivert/memmod/syscall_windows.go
Normal file
392
src/ProcessDrv/tun/WinDivert/memmod/syscall_windows.go
Normal file
@@ -0,0 +1,392 @@
|
||||
/* 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
|
||||
}
|
||||
96
src/ProcessDrv/tun/WinDivert/memmod/syscall_windows_32.go
Normal file
96
src/ProcessDrv/tun/WinDivert/memmod/syscall_windows_32.go
Normal file
@@ -0,0 +1,96 @@
|
||||
//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
|
||||
}
|
||||
95
src/ProcessDrv/tun/WinDivert/memmod/syscall_windows_64.go
Normal file
95
src/ProcessDrv/tun/WinDivert/memmod/syscall_windows_64.go
Normal file
@@ -0,0 +1,95 @@
|
||||
//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
|
||||
}
|
||||
173
src/ProcessDrv/tun/WinDivert/tcp.go
Normal file
173
src/ProcessDrv/tun/WinDivert/tcp.go
Normal file
@@ -0,0 +1,173 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package WinDivert
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/ProcessCheck"
|
||||
CrossCompiled "github.com/qtgolang/SunnyNet/src/iphlpapi/net"
|
||||
"github.com/shirou/gopsutil/process"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
sessionsMu sync.Mutex
|
||||
sessions = make(map[uint16]*DevConn)
|
||||
)
|
||||
|
||||
func sessKey(ip net.IP, port uint16) string {
|
||||
return ip.String() + ":" + fmt.Sprint(port)
|
||||
}
|
||||
|
||||
type expiry struct {
|
||||
pid int32
|
||||
name string
|
||||
expiry time.Time
|
||||
}
|
||||
|
||||
var (
|
||||
pidCache = make(map[uint16]expiry)
|
||||
pidCacheMu sync.RWMutex
|
||||
pidTTL = 3 * time.Second
|
||||
pidExpiry = make(map[uint16]time.Time)
|
||||
)
|
||||
|
||||
func getPidByPort(kind string, port uint16) (int32, string) {
|
||||
pidCacheMu.Lock()
|
||||
defer pidCacheMu.Unlock()
|
||||
for k, _ := range pidCache {
|
||||
if !time.Now().Before(pidExpiry[k]) {
|
||||
delete(pidExpiry, k)
|
||||
delete(pidCache, k)
|
||||
}
|
||||
}
|
||||
if obj, ok := pidCache[port]; ok && time.Now().Before(pidExpiry[port]) {
|
||||
return obj.pid, obj.name
|
||||
}
|
||||
all, _ := CrossCompiled.Connections(kind)
|
||||
for _, conn := range all {
|
||||
if conn.Laddr.Port == uint32(port) {
|
||||
pid := conn.Pid
|
||||
p, _ := process.NewProcess(pid)
|
||||
ch := expiry{pid: pid}
|
||||
if p != nil {
|
||||
ch.name, _ = p.Name()
|
||||
}
|
||||
pidCache[port] = ch
|
||||
pidExpiry[port] = time.Now().Add(pidTTL)
|
||||
return ch.pid, ch.name
|
||||
}
|
||||
}
|
||||
return 0, ""
|
||||
}
|
||||
|
||||
var loopbackV4 = net.IPv4(127, 0, 0, 1)
|
||||
var loopbackV6 = net.IPv6loopback
|
||||
|
||||
func (d *Divert) handleCommand(h *Handle, data []byte, addr *Address, tcp *layers.TCP, clientIP, serverIP net.IP, clientPort, serverPort uint16, v4 bool) {
|
||||
if !addr.Outbound() || (clientIP.Equal(serverIP) && (serverIP.Equal(loopbackV4) || serverIP.Equal(loopbackV6))) {
|
||||
_, _ = h.Send(data, addr)
|
||||
return
|
||||
}
|
||||
|
||||
// 只处理 SYN 或 TCP payload
|
||||
// 处理 SYN(client 发起连接)
|
||||
if tcp.SYN && !tcp.ACK {
|
||||
pid, name := getPidByPort("tcp", uint16(tcp.SrcPort))
|
||||
if d.pidFromCheck(pid, name) {
|
||||
_, _ = h.Send(data, addr)
|
||||
return
|
||||
}
|
||||
// 创建会话并伪造 SYN/ACK 返回客户端
|
||||
s := NewDevConn(h, clientIP, clientPort, serverIP, serverPort, v4, addr.Clone(), 0, 0)
|
||||
s.pid = uint32(pid)
|
||||
sessionsMu.Lock()
|
||||
sessions[clientPort] = s
|
||||
sessionsMu.Unlock()
|
||||
// send SYN/ACK to client
|
||||
if err := SendSynAckToClient(h, s, addr, tcp.Seq); err != nil {
|
||||
// 如果发送失败,删除会话
|
||||
sessionsMu.Lock()
|
||||
delete(sessions, clientPort)
|
||||
sessionsMu.Unlock()
|
||||
return
|
||||
}
|
||||
sessionsMu.Lock()
|
||||
call := d.handleTCP
|
||||
sessionsMu.Unlock()
|
||||
if call != nil {
|
||||
ProcessCheck.AddDevObj(clientPort, s)
|
||||
go call(s)
|
||||
}
|
||||
return
|
||||
}
|
||||
sessionsMu.Lock()
|
||||
sess, ok := sessions[clientPort]
|
||||
sessionsMu.Unlock()
|
||||
if !ok {
|
||||
pid, name := getPidByPort("tcp", uint16(tcp.SrcPort))
|
||||
if d.pidFromCheck(pid, name) {
|
||||
_, _ = h.Send(data, addr)
|
||||
return
|
||||
}
|
||||
h2 := NewDevConn(h, clientIP, clientPort, serverIP, serverPort, v4, addr.Clone(), tcp.Seq, tcp.Ack)
|
||||
_ = SendRstToClient(h, h2)
|
||||
return
|
||||
}
|
||||
// 如果收到 FIN 或 RST,则清理 session 并放行
|
||||
if tcp.FIN || tcp.RST {
|
||||
_, _ = h.Send(data, addr) // 放行原始包(可选)
|
||||
sessionsMu.Lock()
|
||||
delete(sessions, clientPort)
|
||||
sessionsMu.Unlock()
|
||||
ProcessCheck.DelDevObj(clientPort)
|
||||
_ = sess.Close()
|
||||
return
|
||||
}
|
||||
|
||||
if tcp.ACK && !tcp.SYN && len(tcp.Payload) == 0 {
|
||||
return
|
||||
}
|
||||
// 处理 payload:写入 devConn 并向内核注入 ACK(告知 we've consumed bytes)
|
||||
if len(tcp.Payload) > 0 {
|
||||
fmt.Println(string(tcp.Payload))
|
||||
// 写入 session buffer 并更新 clientNext
|
||||
sess.PushClientPayload(tcp.Payload, tcp.Seq)
|
||||
return
|
||||
}
|
||||
|
||||
// 其他情况原样放行
|
||||
_, _ = h.Send(data, addr)
|
||||
return
|
||||
}
|
||||
func (d *Divert) handleIPv4(h *Handle, data []byte, addr *Address, ip4 *layers.IPv4, pkt gopacket.Packet) bool {
|
||||
tcpLayer := pkt.Layer(layers.LayerTypeTCP)
|
||||
if tcpLayer == nil {
|
||||
return false
|
||||
}
|
||||
tcp := tcpLayer.(*layers.TCP)
|
||||
clientIP := ip4.SrcIP
|
||||
clientPort := uint16(tcp.SrcPort)
|
||||
serverIP := ip4.DstIP
|
||||
serverPort := uint16(tcp.DstPort)
|
||||
d.handleCommand(h, data, addr, tcp, clientIP, serverIP, clientPort, serverPort, true)
|
||||
return true
|
||||
}
|
||||
func (d *Divert) handleIPv6(h *Handle, data []byte, addr *Address, ip6 *layers.IPv6, pkt gopacket.Packet) bool {
|
||||
tcpLayer := pkt.Layer(layers.LayerTypeTCP)
|
||||
if tcpLayer == nil {
|
||||
return false
|
||||
}
|
||||
tcp := tcpLayer.(*layers.TCP)
|
||||
clientIP := ip6.SrcIP
|
||||
clientPort := uint16(tcp.SrcPort)
|
||||
serverIP := ip6.DstIP
|
||||
serverPort := uint16(tcp.DstPort)
|
||||
d.handleCommand(h, data, addr, tcp, clientIP, serverIP, clientPort, serverPort, false)
|
||||
return true
|
||||
}
|
||||
365
src/ProcessDrv/tun/WinDivert/toKernel.go
Normal file
365
src/ProcessDrv/tun/WinDivert/toKernel.go
Normal file
@@ -0,0 +1,365 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package WinDivert
|
||||
|
||||
import (
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
)
|
||||
|
||||
// 公共序列化选项(复用,避免每次重复构造)
|
||||
var serializeOpts = gopacket.SerializeOptions{
|
||||
FixLengths: true,
|
||||
ComputeChecksums: true,
|
||||
}
|
||||
|
||||
// helper: 序列化并发送 IPv4 包(tcp + 可选 payload)
|
||||
// outbound 控制是否把 addr 标记为 outbound (true) 或 inbound (false)
|
||||
func sendIPv4(h *Handle, ip *layers.IPv4, tcp *layers.TCP, payload []byte, addr *Address, outbound bool) error {
|
||||
_ = tcp.SetNetworkLayerForChecksum(ip)
|
||||
buf := gopacket.NewSerializeBuffer()
|
||||
if payload != nil && len(payload) > 0 {
|
||||
if err := gopacket.SerializeLayers(buf, serializeOpts, ip, tcp, gopacket.Payload(payload)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := gopacket.SerializeLayers(buf, serializeOpts, ip, tcp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
out := addr.Clone()
|
||||
out.SetOutbound(outbound)
|
||||
_, err := h.Send(buf.Bytes(), out)
|
||||
return err
|
||||
}
|
||||
|
||||
// helper: 序列化并发送 IPv6 包(tcp + 可选 payload)
|
||||
func sendIPv6(h *Handle, ip *layers.IPv6, tcp *layers.TCP, payload []byte, addr *Address, outbound bool) error {
|
||||
_ = tcp.SetNetworkLayerForChecksum(ip)
|
||||
buf := gopacket.NewSerializeBuffer()
|
||||
if payload != nil && len(payload) > 0 {
|
||||
if err := gopacket.SerializeLayers(buf, serializeOpts, ip, tcp, gopacket.Payload(payload)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := gopacket.SerializeLayers(buf, serializeOpts, ip, tcp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
out := addr.Clone()
|
||||
out.SetOutbound(outbound)
|
||||
_, err := h.Send(buf.Bytes(), out)
|
||||
return err
|
||||
}
|
||||
|
||||
// SendSynAckToClient :收到 client SYN 时注入 SYN/ACK(伪造 server 的 SYN/ACK)
|
||||
func SendSynAckToClient(h *Handle, d *DevConn, addr *Address, clientISN uint32) error {
|
||||
// 复制关键字段(无需长时间持锁)
|
||||
d.mu.Lock()
|
||||
serverIP := d.serverIP
|
||||
clientIP := d.clientIP
|
||||
serverPort := d.serverPort
|
||||
clientPort := d.clientPort
|
||||
serverISN := d.serverISN
|
||||
v4 := d.v4
|
||||
d.mu.Unlock()
|
||||
if v4 {
|
||||
ip := &layers.IPv4{
|
||||
Version: 4,
|
||||
IHL: 5,
|
||||
SrcIP: serverIP,
|
||||
DstIP: clientIP,
|
||||
Protocol: layers.IPProtocolTCP,
|
||||
TTL: 64,
|
||||
}
|
||||
tcp := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(serverPort),
|
||||
DstPort: layers.TCPPort(clientPort),
|
||||
Seq: serverISN,
|
||||
Ack: clientISN + 1,
|
||||
SYN: true,
|
||||
ACK: true,
|
||||
Window: 65535,
|
||||
}
|
||||
return sendIPv4(h, ip, tcp, nil, addr, false) // inbound from server -> client => outbound=false
|
||||
}
|
||||
|
||||
ip6 := &layers.IPv6{
|
||||
Version: 6,
|
||||
SrcIP: serverIP,
|
||||
DstIP: clientIP,
|
||||
NextHeader: layers.IPProtocolTCP,
|
||||
HopLimit: 64,
|
||||
}
|
||||
tcp6 := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(serverPort),
|
||||
DstPort: layers.TCPPort(clientPort),
|
||||
Seq: serverISN,
|
||||
Ack: clientISN + 1,
|
||||
SYN: true,
|
||||
ACK: true,
|
||||
Window: 65535,
|
||||
}
|
||||
return sendIPv6(h, ip6, tcp6, nil, addr, false)
|
||||
}
|
||||
|
||||
// SendAckToKernel :向内核注入 ACK,通知内核我们已接收 client 的数据,避免内核重传
|
||||
func SendAckToKernel(h *Handle, d *DevConn, clientNext uint32, addr *Address) error {
|
||||
// 只在短时间内持锁读取 seq
|
||||
d.mu.Lock()
|
||||
seq := d.serverSeqNext
|
||||
// copy v4 flag and endpoints
|
||||
v4 := d.v4
|
||||
serverIP := d.serverIP
|
||||
clientIP := d.clientIP
|
||||
serverPort := d.serverPort
|
||||
clientPort := d.clientPort
|
||||
d.mu.Unlock()
|
||||
if v4 {
|
||||
ip := &layers.IPv4{
|
||||
Version: 4,
|
||||
IHL: 5,
|
||||
SrcIP: serverIP,
|
||||
DstIP: clientIP,
|
||||
Protocol: layers.IPProtocolTCP,
|
||||
TTL: 64,
|
||||
}
|
||||
tcp := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(serverPort),
|
||||
DstPort: layers.TCPPort(clientPort),
|
||||
Seq: seq,
|
||||
Ack: clientNext,
|
||||
ACK: true,
|
||||
Window: 65535,
|
||||
}
|
||||
if err := sendIPv4(h, ip, tcp, nil, addr, true); err == nil {
|
||||
d.mu.Lock()
|
||||
if clientNext > d.highestClientAckSent {
|
||||
d.highestClientAckSent = clientNext
|
||||
}
|
||||
d.mu.Unlock()
|
||||
return nil
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ip6 := &layers.IPv6{
|
||||
Version: 6,
|
||||
SrcIP: serverIP,
|
||||
DstIP: clientIP,
|
||||
NextHeader: layers.IPProtocolTCP,
|
||||
HopLimit: 64,
|
||||
}
|
||||
tcp6 := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(serverPort),
|
||||
DstPort: layers.TCPPort(clientPort),
|
||||
Seq: d.serverSeqNext,
|
||||
Ack: clientNext,
|
||||
ACK: true,
|
||||
Window: 65535,
|
||||
}
|
||||
if err := sendIPv6(h, ip6, tcp6, nil, addr, true); err == nil {
|
||||
d.mu.Lock()
|
||||
if clientNext > d.highestClientAckSent {
|
||||
d.highestClientAckSent = clientNext
|
||||
}
|
||||
d.mu.Unlock()
|
||||
return nil
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// SendDataToClient :把伪 server 要发送的数据注入给 client,正确设置 Seq/Ack 并更新 serverSeqNext
|
||||
func SendDataToClient(h *Handle, d *DevConn, payload []byte, addr *Address) (int, error) {
|
||||
// 读取必要字段(缩短锁持有时间)
|
||||
d.mu.Lock()
|
||||
seq := d.serverSeqNext
|
||||
ack := d.clientNext
|
||||
serverIP := d.serverIP
|
||||
clientIP := d.clientIP
|
||||
serverPort := d.serverPort
|
||||
clientPort := d.clientPort
|
||||
v4 := d.v4
|
||||
d.mu.Unlock()
|
||||
|
||||
if v4 {
|
||||
ip := &layers.IPv4{
|
||||
Version: 4,
|
||||
IHL: 5,
|
||||
SrcIP: serverIP,
|
||||
DstIP: clientIP,
|
||||
Protocol: layers.IPProtocolTCP,
|
||||
TTL: 64,
|
||||
}
|
||||
tcp := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(serverPort),
|
||||
DstPort: layers.TCPPort(clientPort),
|
||||
Seq: seq,
|
||||
Ack: ack,
|
||||
ACK: true,
|
||||
PSH: true,
|
||||
Window: 65535,
|
||||
}
|
||||
if err := sendIPv4(h, ip, tcp, payload, addr, false); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// 更新 serverSeqNext
|
||||
d.mu.Lock()
|
||||
d.serverSeqNext += uint32(len(payload))
|
||||
d.mu.Unlock()
|
||||
return len(payload), nil
|
||||
}
|
||||
|
||||
ip6 := &layers.IPv6{
|
||||
Version: 6,
|
||||
SrcIP: serverIP,
|
||||
DstIP: clientIP,
|
||||
NextHeader: layers.IPProtocolTCP,
|
||||
HopLimit: 64,
|
||||
}
|
||||
tcp6 := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(serverPort),
|
||||
DstPort: layers.TCPPort(clientPort),
|
||||
Seq: seq,
|
||||
Ack: ack,
|
||||
ACK: true,
|
||||
PSH: true,
|
||||
Window: 65535,
|
||||
}
|
||||
if err := sendIPv6(h, ip6, tcp6, payload, addr, false); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
d.mu.Lock()
|
||||
d.serverSeqNext += uint32(len(payload))
|
||||
d.mu.Unlock()
|
||||
return len(payload), nil
|
||||
}
|
||||
|
||||
// SendFinToClient :注入一个 FIN/ACK(server -> client),并在成功后把 serverSeqNext 增 1(FIN 消耗 1 序号)。
|
||||
func SendFinToClient(h *Handle, d *DevConn) error {
|
||||
// 复制需要的字段,避免在持锁时调用 h.Send 导致死锁或长时间阻塞
|
||||
d.mu.Lock()
|
||||
seq := d.serverSeqNext
|
||||
ack := d.clientNext
|
||||
serverIP := d.serverIP
|
||||
clientIP := d.clientIP
|
||||
serverPort := d.serverPort
|
||||
clientPort := d.clientPort
|
||||
lastAddr := d.lastAddr
|
||||
v4 := d.v4
|
||||
d.mu.Unlock()
|
||||
|
||||
if lastAddr == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if v4 {
|
||||
ip := &layers.IPv4{
|
||||
Version: 4,
|
||||
IHL: 5,
|
||||
SrcIP: serverIP,
|
||||
DstIP: clientIP,
|
||||
Protocol: layers.IPProtocolTCP,
|
||||
TTL: 64,
|
||||
}
|
||||
tcp := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(serverPort),
|
||||
DstPort: layers.TCPPort(clientPort),
|
||||
Seq: seq,
|
||||
Ack: ack,
|
||||
FIN: true,
|
||||
ACK: true,
|
||||
Window: 65535,
|
||||
}
|
||||
if err := sendIPv4(h, ip, tcp, nil, lastAddr, false); err != nil {
|
||||
return err
|
||||
}
|
||||
d.mu.Lock()
|
||||
if seq == d.serverSeqNext {
|
||||
d.serverSeqNext = seq + 1
|
||||
}
|
||||
d.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
ip6 := &layers.IPv6{
|
||||
Version: 6,
|
||||
SrcIP: serverIP,
|
||||
DstIP: clientIP,
|
||||
NextHeader: layers.IPProtocolTCP,
|
||||
HopLimit: 64,
|
||||
}
|
||||
tcp6 := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(serverPort),
|
||||
DstPort: layers.TCPPort(clientPort),
|
||||
Seq: seq,
|
||||
Ack: ack,
|
||||
FIN: true,
|
||||
ACK: true,
|
||||
Window: 65535,
|
||||
}
|
||||
if err := sendIPv6(h, ip6, tcp6, nil, lastAddr, false); err != nil {
|
||||
return err
|
||||
}
|
||||
d.mu.Lock()
|
||||
if seq == d.serverSeqNext {
|
||||
d.serverSeqNext = seq + 1
|
||||
}
|
||||
d.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendRstToClient :立刻强制断开(client 会收到 RST),通常客户端会马上重连
|
||||
func SendRstToClient(h *Handle, d *DevConn) error {
|
||||
d.mu.Lock()
|
||||
seq := d.serverSeqNext
|
||||
ack := d.clientNext
|
||||
serverIP := d.serverIP
|
||||
clientIP := d.clientIP
|
||||
serverPort := d.serverPort
|
||||
clientPort := d.clientPort
|
||||
lastAddr := d.lastAddr
|
||||
v4 := d.v4
|
||||
d.mu.Unlock()
|
||||
|
||||
if lastAddr == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if v4 {
|
||||
ip := &layers.IPv4{
|
||||
Version: 4, IHL: 5,
|
||||
SrcIP: serverIP, DstIP: clientIP,
|
||||
Protocol: layers.IPProtocolTCP, TTL: 64,
|
||||
}
|
||||
tcp := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(serverPort),
|
||||
DstPort: layers.TCPPort(clientPort),
|
||||
Seq: seq,
|
||||
Ack: ack,
|
||||
RST: true,
|
||||
Window: 0,
|
||||
}
|
||||
return sendIPv4(h, ip, tcp, nil, lastAddr, false)
|
||||
}
|
||||
|
||||
ip6 := &layers.IPv6{
|
||||
Version: 6,
|
||||
SrcIP: serverIP,
|
||||
DstIP: clientIP,
|
||||
NextHeader: layers.IPProtocolTCP,
|
||||
HopLimit: 64,
|
||||
}
|
||||
tcp6 := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(serverPort),
|
||||
DstPort: layers.TCPPort(clientPort),
|
||||
Seq: seq,
|
||||
Ack: ack,
|
||||
RST: true,
|
||||
Window: 0,
|
||||
}
|
||||
return sendIPv6(h, ip6, tcp6, nil, lastAddr, false)
|
||||
}
|
||||
288
src/ProcessDrv/tun/WinDivert/udp.go
Normal file
288
src/ProcessDrv/tun/WinDivert/udp.go
Normal file
@@ -0,0 +1,288 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package WinDivert
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/SunnyNetUDP"
|
||||
"github.com/qtgolang/SunnyNet/src/public"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type expiryUDP struct {
|
||||
pid int32
|
||||
name string
|
||||
Theology int64
|
||||
v4 bool
|
||||
h *Handle
|
||||
addr *Address
|
||||
SrcPort, DstPort layers.UDPPort
|
||||
clientIP, serverIP net.IP
|
||||
}
|
||||
|
||||
func (e expiryUDP) ToClient(i []byte) bool {
|
||||
return e.send(i, false)
|
||||
}
|
||||
|
||||
func (e expiryUDP) ToServer(i []byte) bool {
|
||||
return e.send(i, true)
|
||||
}
|
||||
|
||||
// toServer = true 表示发往 server (client -> server)
|
||||
// toServer = false 表示发往 client (server -> client)
|
||||
func (e expiryUDP) send(payload []byte, toServer bool) bool {
|
||||
var srcPort, dstPort layers.UDPPort
|
||||
var srcIP, dstIP net.IP
|
||||
if toServer {
|
||||
srcPort = e.SrcPort
|
||||
dstPort = e.DstPort
|
||||
srcIP = e.clientIP
|
||||
dstIP = e.serverIP
|
||||
} else {
|
||||
srcPort = e.DstPort
|
||||
dstPort = e.SrcPort
|
||||
srcIP = e.serverIP
|
||||
dstIP = e.clientIP
|
||||
}
|
||||
|
||||
buf := gopacket.NewSerializeBuffer()
|
||||
opts := gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true}
|
||||
newUDP := &layers.UDP{SrcPort: srcPort, DstPort: dstPort}
|
||||
if e.v4 {
|
||||
ip := &layers.IPv4{
|
||||
Version: 4,
|
||||
IHL: 5,
|
||||
TTL: 64,
|
||||
Protocol: layers.IPProtocolUDP,
|
||||
SrcIP: srcIP,
|
||||
DstIP: dstIP,
|
||||
}
|
||||
_ = newUDP.SetNetworkLayerForChecksum(ip)
|
||||
if err := gopacket.SerializeLayers(buf, opts, ip, newUDP, gopacket.Payload(payload)); err != nil {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
ip6 := &layers.IPv6{
|
||||
Version: 6,
|
||||
HopLimit: 64,
|
||||
NextHeader: layers.IPProtocolUDP,
|
||||
SrcIP: srcIP,
|
||||
DstIP: dstIP,
|
||||
}
|
||||
_ = newUDP.SetNetworkLayerForChecksum(ip6)
|
||||
if err := gopacket.SerializeLayers(buf, opts, ip6, newUDP, gopacket.Payload(payload)); err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
a := e.addr.Clone()
|
||||
a.SetOutbound(toServer)
|
||||
_, err := e.h.Send(buf.Bytes(), a)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var (
|
||||
udpCache = make(map[uint16]*expiryUDP)
|
||||
udpCacheMu sync.RWMutex
|
||||
)
|
||||
|
||||
func (d *Divert) handleCommandUDP(h *Handle, data []byte, addr *Address, udp *layers.UDP, clientIP, serverIP net.IP, clientPort, serverPort uint16, v4 bool, pkt gopacket.Packet) {
|
||||
payload := udp.LayerPayload()
|
||||
if len(payload) == 0 {
|
||||
// 没有数据直接转发
|
||||
_, _ = h.Send(data, addr)
|
||||
return
|
||||
}
|
||||
var obj *expiryUDP
|
||||
{
|
||||
var ok bool
|
||||
var port uint16
|
||||
udpCacheMu.Lock()
|
||||
if addr.Outbound() {
|
||||
port = clientPort
|
||||
} else {
|
||||
port = serverPort
|
||||
}
|
||||
obj, ok = udpCache[port]
|
||||
if !ok {
|
||||
pid, name := getPidByPort("udp", port)
|
||||
if d.pidFromCheck(pid, name) {
|
||||
udpCacheMu.Unlock()
|
||||
_, _ = h.Send(data, addr)
|
||||
return
|
||||
}
|
||||
obj = &expiryUDP{pid: pid, name: name, v4: v4, h: h, addr: addr, Theology: atomic.AddInt64(&public.Theology, 1)}
|
||||
if addr.Outbound() {
|
||||
obj.clientIP, obj.serverIP = clientIP, serverIP
|
||||
obj.SrcPort, obj.DstPort = udp.SrcPort, udp.DstPort
|
||||
} else {
|
||||
obj.clientIP, obj.serverIP = serverIP, clientIP
|
||||
obj.SrcPort, obj.DstPort = udp.DstPort, udp.SrcPort
|
||||
}
|
||||
udpCache[port] = obj
|
||||
} else {
|
||||
/*
|
||||
if clientPort == 53 || serverPort == 53 {
|
||||
if d.handleDNS53(h, data, addr, clientIP, serverIP, false, pkt) {
|
||||
return
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
udpCacheMu.Unlock()
|
||||
if obj == nil {
|
||||
_, _ = h.Send(data, addr)
|
||||
return
|
||||
}
|
||||
SunnyNetUDP.AddUDPItem(obj.Theology, obj)
|
||||
}
|
||||
sessionsMu.Lock()
|
||||
call := d.handleUDP
|
||||
sessionsMu.Unlock()
|
||||
if call != nil {
|
||||
LocalAddress := net.JoinHostPort(clientIP.String(), strconv.Itoa(int(clientPort)))
|
||||
RemoteAddress := net.JoinHostPort(serverIP.String(), strconv.Itoa(int(serverPort)))
|
||||
var bs []byte
|
||||
if addr.Outbound() {
|
||||
bs = call(public.SunnyNetUDPTypeSend, obj.Theology, uint32(obj.pid), LocalAddress, RemoteAddress, payload)
|
||||
} else {
|
||||
bs = call(public.SunnyNetUDPTypeReceive, obj.Theology, uint32(obj.pid), RemoteAddress, LocalAddress, payload)
|
||||
}
|
||||
if len(bs) > 0 {
|
||||
if bytes.Equal(bs, payload) {
|
||||
//未作修改
|
||||
_, _ = h.Send(data, addr)
|
||||
return
|
||||
}
|
||||
buf := gopacket.NewSerializeBuffer()
|
||||
opts := gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true}
|
||||
newUDP := &layers.UDP{SrcPort: udp.SrcPort, DstPort: udp.DstPort}
|
||||
var layerIP gopacket.SerializableLayer
|
||||
if v4 {
|
||||
ip := &layers.IPv4{Version: 4, IHL: 5, TTL: 64, Protocol: layers.IPProtocolUDP}
|
||||
ip.SrcIP, ip.DstIP = clientIP, serverIP
|
||||
layerIP = ip
|
||||
_ = newUDP.SetNetworkLayerForChecksum(ip)
|
||||
} else {
|
||||
ip6 := &layers.IPv6{Version: 6, HopLimit: 64, NextHeader: layers.IPProtocolUDP}
|
||||
ip6.SrcIP, ip6.DstIP = clientIP, serverIP
|
||||
layerIP = ip6
|
||||
_ = newUDP.SetNetworkLayerForChecksum(ip6)
|
||||
}
|
||||
_ = gopacket.SerializeLayers(buf, opts, layerIP, newUDP, gopacket.Payload(bs))
|
||||
_, _ = h.Send(buf.Bytes(), addr.Clone())
|
||||
}
|
||||
return
|
||||
}
|
||||
_, _ = h.Send(data, addr)
|
||||
return
|
||||
}
|
||||
func (d *Divert) handleUDPv4(h *Handle, data []byte, addr *Address, ip4 *layers.IPv4, pkt gopacket.Packet) bool {
|
||||
udpLayer := pkt.Layer(layers.LayerTypeUDP)
|
||||
if udpLayer == nil {
|
||||
return false
|
||||
}
|
||||
udp := udpLayer.(*layers.UDP)
|
||||
clientIP := ip4.SrcIP
|
||||
clientPort := uint16(udp.SrcPort)
|
||||
serverIP := ip4.DstIP
|
||||
serverPort := uint16(udp.DstPort)
|
||||
d.handleCommandUDP(h, data, addr, udp, clientIP, serverIP, clientPort, serverPort, true, pkt)
|
||||
return true
|
||||
}
|
||||
func (d *Divert) handleUDPv6(h *Handle, data []byte, addr *Address, ip6 *layers.IPv6, pkt gopacket.Packet) bool {
|
||||
udpLayer := pkt.Layer(layers.LayerTypeUDP)
|
||||
if udpLayer == nil {
|
||||
return false
|
||||
}
|
||||
udp := udpLayer.(*layers.UDP)
|
||||
clientIP := ip6.SrcIP
|
||||
clientPort := uint16(udp.SrcPort)
|
||||
serverIP := ip6.DstIP
|
||||
serverPort := uint16(udp.DstPort)
|
||||
d.handleCommandUDP(h, data, addr, udp, clientIP, serverIP, clientPort, serverPort, false, pkt)
|
||||
return true
|
||||
}
|
||||
|
||||
func (d *Divert) runFlow() bool {
|
||||
h, e := Open("true", LayerFlow, 0, FlagSniff|FlagRecvOnly)
|
||||
if e != nil {
|
||||
d.handleMutex.Unlock()
|
||||
return false
|
||||
}
|
||||
d.wg.Add(1)
|
||||
d.handle2, d.stopCh2 = h, make(chan struct{})
|
||||
go func() {
|
||||
defer d.wg.Done()
|
||||
packetBuf := make([]byte, 0xffff)
|
||||
for {
|
||||
select {
|
||||
case <-d.stopCh2:
|
||||
return
|
||||
default:
|
||||
}
|
||||
addr := &Address{}
|
||||
_, err := h.Recv(packetBuf, addr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
Protocol := addr.Flow().Protocol
|
||||
if Protocol == flowTcp {
|
||||
continue
|
||||
}
|
||||
if Protocol == flowudp {
|
||||
if addr.Event() == 1 {
|
||||
//fmt.Println("udp建立连接", addr.Flow().ProcessID, addr.IPv6(), LocalAddress, LocalAddressPort, RemoteAddress, RemoteAddressPort)
|
||||
} else {
|
||||
var LocalAddress, RemoteAddress string
|
||||
LocalAddressPort := addr.Flow().LocalPort
|
||||
RemoteAddressPort := addr.Flow().RemotePort
|
||||
if addr.IPv6() {
|
||||
LocalAddress = fmt.Sprintf("[%s]:%d", flowAddrToIP(addr.Flow().LocalAddress), LocalAddressPort)
|
||||
RemoteAddress = fmt.Sprintf("[%s]:%d", flowAddrToIP(addr.Flow().RemoteAddress), RemoteAddressPort)
|
||||
} else {
|
||||
LocalAddress = fmt.Sprintf("%s:%d", flowAddrToIP(addr.Flow().LocalAddress), LocalAddressPort)
|
||||
RemoteAddress = fmt.Sprintf("%s:%d", flowAddrToIP(addr.Flow().RemoteAddress), RemoteAddressPort)
|
||||
}
|
||||
udpCacheMu.Lock()
|
||||
obj, ok := udpCache[LocalAddressPort]
|
||||
if !ok {
|
||||
udpCacheMu.Unlock()
|
||||
continue
|
||||
}
|
||||
delete(udpCache, LocalAddressPort)
|
||||
udpCacheMu.Unlock()
|
||||
sessionsMu.Lock()
|
||||
call := d.handleUDP
|
||||
sessionsMu.Unlock()
|
||||
if call != nil {
|
||||
call(public.SunnyNetUDPTypeClosed, obj.Theology, uint32(obj.pid), LocalAddress, RemoteAddress, nil)
|
||||
}
|
||||
SunnyNetUDP.DelUDPItem(obj.Theology)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
return true
|
||||
}
|
||||
func flowAddrToIP(addr [16]uint8) net.IP {
|
||||
out := make([]byte, 16)
|
||||
for i := 0; i < 16; i += 1 {
|
||||
out[i] = addr[15-i]
|
||||
}
|
||||
if addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] == 0 &&
|
||||
addr[4] == 0 && addr[5] == 0 && addr[6] == 0 && addr[7] == 0 &&
|
||||
addr[8] == 0 && addr[9] == 0 {
|
||||
return net.IPv4(addr[12], addr[13], addr[14], addr[15])
|
||||
}
|
||||
return out
|
||||
}
|
||||
43
src/ProcessDrv/tun/android.go
Normal file
43
src/ProcessDrv/tun/android.go
Normal file
@@ -0,0 +1,43 @@
|
||||
//go:build android
|
||||
// +build android
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/tun/Tun"
|
||||
)
|
||||
|
||||
var dev = Tun.NewTun{}
|
||||
|
||||
func IsRun() bool {
|
||||
return dev.IsRunning
|
||||
}
|
||||
|
||||
func Install() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func SetHandle(Handle Tun.TcpFunc, udpSendReceiveFunc Tun.UdpFunc, sunny Tun.Interface) bool {
|
||||
dev.ProxyPort = uint16(sunny.Port())
|
||||
dev.SetHandle(Handle, udpSendReceiveFunc)
|
||||
return true
|
||||
}
|
||||
func Run() bool {
|
||||
dev.IsRunning = true
|
||||
return true
|
||||
}
|
||||
func Close() bool {
|
||||
dev.IsRunning = false
|
||||
return true
|
||||
}
|
||||
func Name() string {
|
||||
return "tun"
|
||||
}
|
||||
|
||||
func UnInstall() bool {
|
||||
return true
|
||||
}
|
||||
func SetFd(fd int) bool {
|
||||
go dev.OnTunCreated(fd)
|
||||
return true
|
||||
}
|
||||
47
src/ProcessDrv/tun/darwin.go
Normal file
47
src/ProcessDrv/tun/darwin.go
Normal file
@@ -0,0 +1,47 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/ProcessCheck"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/tun/Tun"
|
||||
)
|
||||
|
||||
var dev = Tun.NewTun{}
|
||||
|
||||
func IsRun() bool {
|
||||
return dev.IsRunning
|
||||
}
|
||||
|
||||
func Install() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func SetHandle(Handle Tun.TcpFunc, udpSendReceiveFunc Tun.UdpFunc, sunny Tun.Interface) bool {
|
||||
dev.ProxyPort = uint16(sunny.Port())
|
||||
dev.Sunny = sunny
|
||||
dev.CheckProcess = ProcessCheck.CheckPidByName
|
||||
dev.SetHandle(Handle, udpSendReceiveFunc)
|
||||
return true
|
||||
}
|
||||
func Run() bool {
|
||||
if dev.IsRunning {
|
||||
return true
|
||||
}
|
||||
return dev.OnTunCreated(0)
|
||||
}
|
||||
func Close() bool {
|
||||
dev.IsRunning = false
|
||||
return true
|
||||
}
|
||||
func Name() string {
|
||||
return "utun"
|
||||
}
|
||||
|
||||
func UnInstall() bool {
|
||||
return true
|
||||
}
|
||||
func SetFd(fd int) bool {
|
||||
return true
|
||||
}
|
||||
42
src/ProcessDrv/tun/linux.go
Normal file
42
src/ProcessDrv/tun/linux.go
Normal file
@@ -0,0 +1,42 @@
|
||||
//go:build linux && !android
|
||||
// +build linux,!android
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/tun/Tun"
|
||||
)
|
||||
|
||||
var dev = Tun.NewTun{}
|
||||
|
||||
func IsRun() bool {
|
||||
return dev.IsRunning
|
||||
}
|
||||
|
||||
func Install() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func SetHandle(Handle Tun.TcpFunc, udpSendReceiveFunc Tun.UdpFunc, sunny Tun.Interface) bool {
|
||||
dev.ProxyPort = uint16(sunny.Port())
|
||||
dev.Sunny = sunny
|
||||
dev.SetHandle(Handle, udpSendReceiveFunc)
|
||||
return true
|
||||
}
|
||||
func Run() bool {
|
||||
return dev.OnTunCreated(0)
|
||||
}
|
||||
func Close() bool {
|
||||
dev.IsRunning = false
|
||||
return true
|
||||
}
|
||||
func Name() string {
|
||||
return "tun"
|
||||
}
|
||||
|
||||
func UnInstall() bool {
|
||||
return true
|
||||
}
|
||||
func SetFd(fd int) bool {
|
||||
return true
|
||||
}
|
||||
36
src/ProcessDrv/tun/oth.go
Normal file
36
src/ProcessDrv/tun/oth.go
Normal file
@@ -0,0 +1,36 @@
|
||||
//go:build !android && !darwin && !linux && !windows
|
||||
// +build !android,!darwin,!linux,!windows
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/tun/Tun"
|
||||
)
|
||||
|
||||
func IsRun() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func Install() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func SetHandle(Handle Tun.TcpFunc, udpSendReceiveFunc Tun.UdpFunc, sunny Tun.Interface) bool {
|
||||
return true
|
||||
}
|
||||
func Run() bool {
|
||||
return false
|
||||
}
|
||||
func Close() bool {
|
||||
return true
|
||||
}
|
||||
func Name() string {
|
||||
return "null"
|
||||
}
|
||||
|
||||
func UnInstall() bool {
|
||||
return true
|
||||
}
|
||||
func SetFd(fd int) bool {
|
||||
return false
|
||||
}
|
||||
8
src/ProcessDrv/tun/tunPublic/all.go
Normal file
8
src/ProcessDrv/tun/tunPublic/all.go
Normal file
@@ -0,0 +1,8 @@
|
||||
//go:build !darwin && !linux
|
||||
// +build !darwin,!linux
|
||||
|
||||
package tunPublic
|
||||
|
||||
func GetGatewayByDefault() (string, string) {
|
||||
panic("implement me:!darwin,!linux")
|
||||
}
|
||||
122
src/ProcessDrv/tun/tunPublic/darwin.go
Normal file
122
src/ProcessDrv/tun/tunPublic/darwin.go
Normal file
@@ -0,0 +1,122 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package tunPublic
|
||||
|
||||
import (
|
||||
"bufio" // 用于按行读取命令输出
|
||||
"fmt" // 格式化输出
|
||||
"net" // 获取本机网卡地址
|
||||
"os/exec" // 执行系统命令
|
||||
"strings" // 处理字符串
|
||||
)
|
||||
|
||||
// findInterfaceByIP 根据给定的 IPv4 字符串查找包含该地址的接口名
|
||||
func findInterfaceByIP(ipStr string) (string, error) {
|
||||
ip := net.ParseIP(ipStr)
|
||||
if ip == nil || ip.To4() == nil {
|
||||
return "", fmt.Errorf("无效的 IPv4 地址: %s", ipStr)
|
||||
}
|
||||
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, ifi := range ifaces {
|
||||
addrs, err := ifi.Addrs()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, a := range addrs {
|
||||
var curIP net.IP
|
||||
switch v := a.(type) {
|
||||
case *net.IPNet:
|
||||
curIP = v.IP
|
||||
case *net.IPAddr:
|
||||
curIP = v.IP
|
||||
}
|
||||
if curIP != nil && curIP.Equal(ip) {
|
||||
return ifi.Name, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("未找到 IP %s 对应的网卡", ipStr)
|
||||
}
|
||||
|
||||
// parseNetstatDefault 解析 netstat -rn -f inet 输出,找到 default 路由网关
|
||||
func parseNetstatDefault(output, ifaceName string) (string, error) {
|
||||
scanner := bufio.NewScanner(strings.NewReader(output))
|
||||
for scanner.Scan() {
|
||||
fields := strings.Fields(strings.TrimSpace(scanner.Text()))
|
||||
if len(fields) < 6 {
|
||||
continue
|
||||
}
|
||||
if fields[0] == "default" && fields[len(fields)-1] == ifaceName {
|
||||
return fields[1], nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("在路由表中未找到接口 %s 的 default 路由", ifaceName)
|
||||
}
|
||||
|
||||
// getGatewayByInterface 通过接口名查找 default 网关
|
||||
func getGatewayByInterface(ifaceName string) (string, error) {
|
||||
// 优先使用 netstat
|
||||
cmd := exec.Command("netstat", "-rn", "-f", "inet")
|
||||
out, err := cmd.Output()
|
||||
if err == nil {
|
||||
if gw, e := parseNetstatDefault(string(out), ifaceName); e == nil {
|
||||
return gw, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 备用使用 route get
|
||||
cmd2 := exec.Command("route", "-n", "get", "default")
|
||||
out2, err2 := cmd2.Output()
|
||||
if err2 != nil {
|
||||
return "", fmt.Errorf("无法获取网关")
|
||||
}
|
||||
|
||||
var gw, ifn string
|
||||
for _, line := range strings.Split(string(out2), "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
switch {
|
||||
case strings.HasPrefix(line, "gateway:"):
|
||||
gw = strings.TrimSpace(strings.TrimPrefix(line, "gateway:"))
|
||||
case strings.HasPrefix(line, "interface:"):
|
||||
ifn = strings.TrimSpace(strings.TrimPrefix(line, "interface:"))
|
||||
}
|
||||
}
|
||||
if ifn == ifaceName && gw != "" {
|
||||
return gw, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("未找到接口 %s 对应的网关", ifaceName)
|
||||
}
|
||||
|
||||
// GetGatewayByDefault 返回当前默认出口 IPv4 及其网关地址
|
||||
func GetGatewayByDefault() (string, string, string) {
|
||||
// 建立 UDP 连接获取默认出口 IP
|
||||
conn, err := net.Dial("udp", "1.2.3.4:5")
|
||||
if err != nil {
|
||||
return "", "", ""
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
localIP := conn.LocalAddr().(*net.UDPAddr).IP.To4()
|
||||
if localIP == nil {
|
||||
return "", "", ""
|
||||
}
|
||||
|
||||
ifaceName, err := findInterfaceByIP(localIP.String())
|
||||
if err != nil {
|
||||
return localIP.String(), "", ifaceName
|
||||
}
|
||||
|
||||
gw, err := getGatewayByInterface(ifaceName)
|
||||
if err != nil {
|
||||
return localIP.String(), "", ifaceName
|
||||
}
|
||||
|
||||
return localIP.String(), gw, ifaceName
|
||||
}
|
||||
45
src/ProcessDrv/tun/tunPublic/linux.go
Normal file
45
src/ProcessDrv/tun/tunPublic/linux.go
Normal file
@@ -0,0 +1,45 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package tunPublic
|
||||
|
||||
import ( // 导入包
|
||||
|
||||
"net" // 获取本机网卡地址
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetGatewayByDefault() (string, string, string) {
|
||||
out, err := exec.Command("ip", "route", "show", "default").Output()
|
||||
if err != nil {
|
||||
return "", "", ""
|
||||
}
|
||||
|
||||
// 示例输出: "default via 192.168.31.1 dev eth0 proto dhcp metric 100"
|
||||
fields := strings.Fields(string(out))
|
||||
if len(fields) < 5 {
|
||||
return "", "", ""
|
||||
}
|
||||
|
||||
gateway := fields[2]
|
||||
iface := fields[4]
|
||||
|
||||
// 获取本地 IP
|
||||
ip := getInterfaceIPv4(iface)
|
||||
return ip, gateway, iface
|
||||
}
|
||||
|
||||
func getInterfaceIPv4(ifaceName string) string {
|
||||
ifi, err := net.InterfaceByName(ifaceName)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
addrs, _ := ifi.Addrs()
|
||||
for _, a := range addrs {
|
||||
if ipnet, ok := a.(*net.IPNet); ok && ipnet.IP.To4() != nil {
|
||||
return ipnet.IP.String()
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
117
src/ProcessDrv/tun/windows.go
Normal file
117
src/ProcessDrv/tun/windows.go
Normal file
@@ -0,0 +1,117 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/Info"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/ProcessCheck"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/tun/Tun"
|
||||
divert "github.com/qtgolang/SunnyNet/src/ProcessDrv/tun/WinDivert"
|
||||
"github.com/qtgolang/SunnyNet/src/Resource"
|
||||
"io"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var Divert = divert.NewWinDivert()
|
||||
|
||||
func IsRun() bool {
|
||||
return Divert.IsRunning()
|
||||
}
|
||||
|
||||
func Install() bool {
|
||||
if checkWinDivert() {
|
||||
return true
|
||||
}
|
||||
var oldValue uintptr
|
||||
if Info.Is64Windows {
|
||||
//如果是32位进程 禁止文件重定向 驱动只能写到 system32 目录
|
||||
if !Info.WindowsX64 {
|
||||
oldValue = Info.Wow64DisableWow64FsRedirection()
|
||||
}
|
||||
}
|
||||
if Info.Is64Windows {
|
||||
Info.WriteFile(driver64File, Resource.WinDivert64)
|
||||
registerWinDivert(driver64File)
|
||||
} else {
|
||||
Info.WriteFile(driver32File, Resource.WinDivert32)
|
||||
registerWinDivert(driver32File)
|
||||
}
|
||||
if Info.Is64Windows {
|
||||
//如果是32位进程 恢复文件重定向
|
||||
if !Info.WindowsX64 {
|
||||
Info.Wow64RevertWow64FsRedirection(oldValue)
|
||||
}
|
||||
}
|
||||
return checkWinDivert()
|
||||
}
|
||||
|
||||
func SetHandle(Handle Tun.TcpFunc, udpSendReceiveFunc Tun.UdpFunc, sunny Tun.Interface) bool {
|
||||
Divert.SetHandle(Handle, ProcessCheck.CheckPidByName, udpSendReceiveFunc)
|
||||
return true
|
||||
}
|
||||
func Run() bool {
|
||||
return Divert.Run()
|
||||
}
|
||||
func Close() bool {
|
||||
Divert.Close()
|
||||
return true
|
||||
}
|
||||
func Name() string {
|
||||
return "winDivert"
|
||||
}
|
||||
|
||||
func UnInstall() bool {
|
||||
runCmd("sc", "stop", "WinDivert")
|
||||
runCmd("sc", "delete", "WinDivert")
|
||||
s := "Sunny_" + Info.RandomLetters(32) + extensionsTemp
|
||||
_ = Info.MoveFileToTempDir(driver32File, s)
|
||||
s = "Sunny_" + Info.RandomLetters(32) + extensionsTemp
|
||||
_ = Info.MoveFileToTempDir(driver64File, s)
|
||||
return true
|
||||
}
|
||||
|
||||
// 安卓接口
|
||||
func AndroidTunCreated(fd int) {}
|
||||
|
||||
var base = Info.GetSystemDirectory() + "\\drivers\\"
|
||||
var driver64File = base + "WinDivert64.sys"
|
||||
var driver32File = base + "WinDivert32.sys"
|
||||
var extensionsTemp = ".tmpSys"
|
||||
|
||||
func registerWinDivert(path string) {
|
||||
runCmd("sc", "create", "WinDivert", "type=kernel", "start=demand", `binPath=`+path)
|
||||
}
|
||||
|
||||
// checkServer 安装证书 将证书安装到Windows系统内
|
||||
func checkWinDivert() bool {
|
||||
return strings.Contains(strings.ReplaceAll(runCmd("sc", "query", "WinDivert"), " ", ""), "SERVICE_NAME:WinDivert")
|
||||
}
|
||||
|
||||
func runCmd(Command string, args ...string) (res string) {
|
||||
cmd := exec.Command(Command, args...)
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
||||
_ = cmd.Start()
|
||||
var Buff bytes.Buffer
|
||||
reader := bufio.NewReader(stdout)
|
||||
for {
|
||||
line, err2 := reader.ReadBytes('\n')
|
||||
if err2 != nil || io.EOF == err2 {
|
||||
break
|
||||
}
|
||||
Buff.Write(line)
|
||||
}
|
||||
return Buff.String()
|
||||
}
|
||||
|
||||
func SetFd(fd int) bool {
|
||||
return true
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user