2025-10-23

This commit is contained in:
Qin tian
2025-10-23 14:42:38 +08:00
parent 288a54b3fa
commit 9dbd266e02
146 changed files with 24049 additions and 1105 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
/BuildLibrary/Library
/.idea
/SunnyNetWebview

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -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
View 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

Binary file not shown.

1989
BuildLibrary/SunnyNet.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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

Binary file not shown.

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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()
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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
View File

@@ -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
View File

@@ -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
View File

@@ -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=

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -29,6 +29,8 @@ import (
"reflect"
"SunnyNet/src/Call"
"SunnyNet/src/mmCompress"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
"SunnyNet/src/SunnyProtobuf"
)

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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) {

View File

@@ -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 ""
}

View File

@@ -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")) {
//如果微信连接到本机的这个请求被拦截,小程序无法打开,目前不清楚原因

View File

@@ -0,0 +1,9 @@
//go:build windows
// +build windows
package ProcessCheck
var ClosePidTCP = func(PID int) {
}
var CloseNameTCP = func(processName string) {
}

View 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
}

View File

@@ -0,0 +1,9 @@
//go:build !windows
// +build !windows
package ProcessCheck
var ClosePidTCP = func(PID int) {
}
var CloseNameTCP = func(processName string) {
}

View File

@@ -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
}

View File

@@ -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
}

View 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
View 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
}

View File

@@ -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

View File

@@ -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()

View File

@@ -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 连接的 mapkey 为 Local + Remotevalue 为 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)

View File

@@ -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
}
/**

View 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())

View 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, ""
}

View 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()
}

View 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, ""
}

View 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 "🎉 所有物理网卡重启完成"
`

View 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, ""
}

View 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 200TUN默认走 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
// 清理 table200TUN与 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
}

View 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 结束
}

View 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
}

View 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
}

View 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)
}

View 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/ACKserver -> client并在成功后把 serverSeqNext 增 1FIN 消耗 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 201500 - 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 字节总数
}

View 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()
}

View 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)
}

View 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))
}

View 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()
}

View 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 ""
}
}

View 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)
)

View 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
}

View 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
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
//go:build windows
package divert

View 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];
}

View 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 */

View 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 */

View 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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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
}

View 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)
}

View 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()
}
}

View 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
}

View File

@@ -0,0 +1,3 @@
// 2022-02-04
// https://github.com/WireGuard/wireguard-windows/tree/master/driver/memmod
package memmod

View 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(&sections[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(&sections[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(&sectionData)
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(&sectionData)
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))
}

View 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
}

View File

@@ -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

View 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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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
}

View 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
}

View 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
}

View 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
// 处理 SYNclient 发起连接)
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
}

View 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/ACKserver -> client并在成功后把 serverSeqNext 增 1FIN 消耗 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)
}

View 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
}

View 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
}

View 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
}

View 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
View 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
}

View File

@@ -0,0 +1,8 @@
//go:build !darwin && !linux
// +build !darwin,!linux
package tunPublic
func GetGatewayByDefault() (string, string) {
panic("implement me:!darwin,!linux")
}

View 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
}

View 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 ""
}

View 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