mirror of
https://github.com/qtgolang/SunnyNet.git
synced 2026-08-30 22:11:29 -07:00
2026-05-26
This commit is contained in:
@@ -4,17 +4,19 @@ import "C"
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/qtgolang/SunnyNet/SunnyNet"
|
||||
"github.com/qtgolang/SunnyNet/src/Call"
|
||||
"github.com/qtgolang/SunnyNet/src/SunnyProxy"
|
||||
"github.com/qtgolang/SunnyNet/src/http"
|
||||
"github.com/qtgolang/SunnyNet/src/public"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GetSunnyVersion 获取SunnyNet版本
|
||||
@@ -171,6 +173,9 @@ func GetRequestClientIp(MessageId int) string {
|
||||
}
|
||||
k.Lock.Lock()
|
||||
defer k.Lock.Unlock()
|
||||
if k.Global.Drive().Name() == "tun" && runtime.GOOS == "android" {
|
||||
return k.Conn.LocalAddr().String()
|
||||
}
|
||||
return k.Conn.RemoteAddr().String()
|
||||
}
|
||||
|
||||
|
||||
32
BuildLibrary/BuildAndroid.bat
Normal file
32
BuildLibrary/BuildAndroid.bat
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
|
||||
|
||||
@echo off
|
||||
set NDK=E:\init\windows-ndk-x86_64
|
||||
set CGO_ENABLED=1
|
||||
|
||||
|
||||
set tmpPath=G:\AndroidProject\SunnyNet\app\src\main\jniLibs\
|
||||
|
||||
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%arm64-v8a/libSunnyNet.so"
|
||||
set GOOS=android
|
||||
set GOARCH=arm
|
||||
set CC=%NDK%\bin\armv7a-linux-androideabi21-clang
|
||||
echo [Full]_Build_Android_armeabi-v7a.so
|
||||
go build -trimpath -buildmode=c-shared -ldflags "-s -w" -o "%tmpPath%armeabi-v7a/libSunnyNet.so"
|
||||
|
||||
set GOOS=android
|
||||
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%x86/libSunnyNet.so"
|
||||
|
||||
set GOOS=android
|
||||
set GOARCH=amd64
|
||||
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%x86_64/libSunnyNet.so"
|
||||
15
BuildLibrary/BuildAndroidV8a.bat
Normal file
15
BuildLibrary/BuildAndroidV8a.bat
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
|
||||
|
||||
@echo off
|
||||
set NDK=E:\init\windows-ndk-x86_64
|
||||
set CGO_ENABLED=1
|
||||
|
||||
|
||||
set tmpPath=G:\AndroidProject\SunnyNet\app\src\main\jniLibs\
|
||||
|
||||
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%arm64-v8a/libSunnyNet.so"
|
||||
39
JavaApi.go
39
JavaApi.go
@@ -168,16 +168,18 @@ func Java_com_SunnyNet_api_SunnyNetSetCallback(envObj uintptr, clazz uintptr, Su
|
||||
}
|
||||
defer GlobalVM.DetachCurrentThread()
|
||||
|
||||
_PackageName := _env.NewString(Conn.PackageName())
|
||||
_Method := _env.NewString(Conn.Method())
|
||||
_url := _env.NewString(Conn.URL())
|
||||
_er := _env.NewString(Conn.Error())
|
||||
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()))
|
||||
EventConstructor := _env.GetMethodID(HTTPEventClass, "<init>", fmt.Sprintf("(%s%s%s%s%s%s%s%s%s)%s", sig.Long, sig.Long, sig.Long, sig.Long, sig.String, 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(_PackageName), Jvalue(Conn.PID()))
|
||||
|
||||
_env.CallVoidMethodA(obj, onHTTPCallbackMethodId, Jvalue(EventObj))
|
||||
_env.DeleteLocalRef(EventObj)
|
||||
_env.DeleteLocalRef(_Method)
|
||||
_env.DeleteLocalRef(_PackageName)
|
||||
_env.DeleteLocalRef(_url)
|
||||
_env.DeleteLocalRef(_er)
|
||||
return
|
||||
@@ -193,15 +195,17 @@ func Java_com_SunnyNet_api_SunnyNetSetCallback(envObj uintptr, clazz uintptr, Su
|
||||
defer GlobalVM.DetachCurrentThread()
|
||||
_LocalAddr := _env.NewString(Conn.LocalAddress())
|
||||
_RemoteAddr := _env.NewString(Conn.RemoteAddress())
|
||||
_PackageName := _env.NewString(Conn.PackageName())
|
||||
_data := _env.NewByteArray(Conn.Body())
|
||||
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))
|
||||
EventConstructor := _env.GetMethodID(TCPEventClass, "<init>", fmt.Sprintf("(%s%s%s%s%s%s%s%s%s)%s", sig.Long, sig.String, 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(_PackageName), Jvalue(Conn.Theology()), Jvalue(Conn.MessageId()), Jvalue(Conn.Type()), Jvalue(Conn.PID()), Jvalue(_data))
|
||||
|
||||
_env.CallVoidMethodA(obj, onTCPMethodId, Jvalue(EventObj))
|
||||
_env.DeleteLocalRef(EventObj)
|
||||
_env.DeleteLocalRef(_LocalAddr)
|
||||
_env.DeleteLocalRef(_RemoteAddr)
|
||||
_env.DeleteLocalRef(_PackageName)
|
||||
_env.DeleteLocalRef(_data)
|
||||
}
|
||||
|
||||
@@ -214,15 +218,17 @@ func Java_com_SunnyNet_api_SunnyNetSetCallback(envObj uintptr, clazz uintptr, Su
|
||||
}
|
||||
defer GlobalVM.DetachCurrentThread()
|
||||
|
||||
_PackageName := _env.NewString(Conn.PackageName())
|
||||
_Method := _env.NewString(Conn.Method())
|
||||
_url := _env.NewString(Conn.URL())
|
||||
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()))
|
||||
EventConstructor := _env.GetMethodID(WebSocketEventClass, "<init>", fmt.Sprintf("(%s%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.Long, sig.Void))
|
||||
EventObj := _env.NewObjectA(WebSocketEventClass, EventConstructor, Jvalue(SunnyContext), Jvalue(Conn.Theology()), Jvalue(Conn.MessageId()), Jvalue(Conn.Type()), Jvalue(_Method), Jvalue(_url), Jvalue(_PackageName), Jvalue(Conn.PID()), Jvalue(Conn.MessageType()))
|
||||
|
||||
_env.CallVoidMethodA(obj, onWebSocketMethodId, Jvalue(EventObj))
|
||||
_env.DeleteLocalRef(_Method)
|
||||
_env.DeleteLocalRef(_url)
|
||||
_env.DeleteLocalRef(_PackageName)
|
||||
_env.DeleteLocalRef(EventObj)
|
||||
return
|
||||
}
|
||||
@@ -237,17 +243,17 @@ func Java_com_SunnyNet_api_SunnyNetSetCallback(envObj uintptr, clazz uintptr, Su
|
||||
defer GlobalVM.DetachCurrentThread()
|
||||
MessageId := Conn.MessageId()
|
||||
SunnyNetUDP.ResetMessage(MessageId, Conn.Body())
|
||||
|
||||
_PackageName := _env.NewString(Conn.PackageName())
|
||||
_LocalAddr := _env.NewString(Conn.LocalAddress())
|
||||
_RemoteAddr := _env.NewString(Conn.RemoteAddress())
|
||||
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()))
|
||||
EventConstructor := _env.GetMethodID(UDPEventClass, "<init>", fmt.Sprintf("(%s%s%s%s%s%s%s%s)%s", sig.Long, sig.String, 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(_PackageName), Jvalue(Conn.Theology()), Jvalue(MessageId), Jvalue(Conn.Type()), Jvalue(Conn.PID()))
|
||||
_env.CallVoidMethodA(obj, onUDPMethodId, Jvalue(EventObj))
|
||||
_env.DeleteLocalRef(EventObj)
|
||||
_env.DeleteLocalRef(_LocalAddr)
|
||||
_env.DeleteLocalRef(_RemoteAddr)
|
||||
|
||||
_env.DeleteLocalRef(_PackageName)
|
||||
Conn.SetBody(SunnyNetUDP.GetMessage(MessageId))
|
||||
SunnyNetUDP.DelMessage(MessageId)
|
||||
return
|
||||
@@ -2047,9 +2053,18 @@ func Java_com_SunnyNet_api_HTTPSetOutRouterIP(envObj uintptr, clazz uintptr, Mes
|
||||
return Api.HTTPSetOutRouterIP(int(MessageId), env.GetString(value))
|
||||
}
|
||||
|
||||
/*
|
||||
Java_com_SunnyNet_api_OnTunSetFd 将 VPN TUN fd 交给 Go 侧读取;ConnectivityManager 用于 Android 10+ 查询连接归属包名。
|
||||
对应 Java: public static native boolean OnTunSetFd(long fd, Object ConnectivityManager);
|
||||
*/
|
||||
//export Java_com_SunnyNet_api_OnTunSetFd
|
||||
func Java_com_SunnyNet_api_OnTunSetFd(JavaVM uintptr, reserved uintptr, fd int64) {
|
||||
tun.SetFd(int(fd))
|
||||
func Java_com_SunnyNet_api_OnTunSetFd(envObj uintptr, clazz uintptr, fd int64, connectivityManager uintptr) bool {
|
||||
env := Env(envObj)
|
||||
InitTunConnectivityManager(env, connectivityManager)
|
||||
if fd <= 0 {
|
||||
return false
|
||||
}
|
||||
return tun.SetFd(int(fd))
|
||||
}
|
||||
|
||||
type _GlobalRef struct {
|
||||
|
||||
322
JavaApi/android_tun.go
Normal file
322
JavaApi/android_tun.go
Normal file
@@ -0,0 +1,322 @@
|
||||
//go:build android
|
||||
// +build android
|
||||
|
||||
package JavaJni
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
AndroidSDKQ = 29
|
||||
|
||||
IPProtoTCP = 6
|
||||
IPProtoUDP = 17
|
||||
|
||||
invalidUID = -1
|
||||
)
|
||||
|
||||
// TunPackageResult TUN 五元组查询到的包名及是否在 PackageManager 注册。
|
||||
type TunPackageResult struct {
|
||||
Name string
|
||||
Registered bool
|
||||
}
|
||||
|
||||
var (
|
||||
// AndroidSDKInt 在 InitTunConnectivityManager 时写入当前系统 SDK。
|
||||
AndroidSDKInt int
|
||||
// TunPackageLookupEnabled 为 true 表示已保存 ConnectivityManager 且 SDK>=29。
|
||||
TunPackageLookupEnabled bool
|
||||
|
||||
tunCM Jobject
|
||||
tunCMMu sync.RWMutex
|
||||
)
|
||||
|
||||
// SdkInt 读取 android.os.Build.VERSION.SDK_INT。
|
||||
func SdkInt(env Env) int {
|
||||
verClass := env.FindClass("android/os/Build$VERSION")
|
||||
if verClass == 0 {
|
||||
return 0
|
||||
}
|
||||
defer env.DeleteLocalRef(verClass)
|
||||
field := env.GetStaticFieldID(verClass, "SDK_INT", "I")
|
||||
if field == 0 {
|
||||
return 0
|
||||
}
|
||||
return env.GetStaticIntField(verClass, field)
|
||||
}
|
||||
|
||||
// InitTunConnectivityManager 在 OnTunSetFd 中调用:仅 Android 10+ 保存 CM 全局引用并启用包名查询。
|
||||
func InitTunConnectivityManager(env Env, cm Jobject) bool {
|
||||
sdk := SdkInt(env)
|
||||
AndroidSDKInt = sdk
|
||||
if sdk < AndroidSDKQ || cm == 0 {
|
||||
clearTunConnectivityManager(env)
|
||||
return false
|
||||
}
|
||||
clearTunConnectivityManager(env)
|
||||
tunCMMu.Lock()
|
||||
tunCM = env.NewGlobalRef(cm)
|
||||
tunCMMu.Unlock()
|
||||
TunPackageLookupEnabled = true
|
||||
return true
|
||||
}
|
||||
|
||||
func clearTunConnectivityManager(env Env) {
|
||||
tunCMMu.Lock()
|
||||
old := tunCM
|
||||
tunCM = 0
|
||||
tunCMMu.Unlock()
|
||||
if old != 0 {
|
||||
env.DeleteGlobalRef(old)
|
||||
}
|
||||
TunPackageLookupEnabled = false
|
||||
}
|
||||
|
||||
// CurrentApplication 返回 ActivityThread.currentApplication()。
|
||||
func CurrentApplication(env Env) Jobject {
|
||||
atClass := env.FindClass("android/app/ActivityThread")
|
||||
if atClass == 0 {
|
||||
return 0
|
||||
}
|
||||
defer env.DeleteLocalRef(atClass)
|
||||
|
||||
method := env.GetStaticMethodID(atClass, "currentApplication", "()Landroid/app/Application;")
|
||||
if method == 0 {
|
||||
return 0
|
||||
}
|
||||
app := env.CallStaticObjectMethodA(atClass, method)
|
||||
if app == 0 || env.ExceptionCheck() {
|
||||
env.ExceptionClear()
|
||||
return 0
|
||||
}
|
||||
return app
|
||||
}
|
||||
|
||||
// NewInetSocketAddress 构造 java.net.InetSocketAddress(InetAddress, port)。
|
||||
func NewInetSocketAddress(env Env, host string, port int) Jobject {
|
||||
if host == "" || port <= 0 || port > 65535 {
|
||||
return 0
|
||||
}
|
||||
inetClass := env.FindClass("java/net/InetAddress")
|
||||
if inetClass == 0 {
|
||||
return 0
|
||||
}
|
||||
defer env.DeleteLocalRef(inetClass)
|
||||
|
||||
getByName := env.GetStaticMethodID(inetClass, "getByName", "(Ljava/lang/String;)Ljava/net/InetAddress;")
|
||||
if getByName == 0 {
|
||||
return 0
|
||||
}
|
||||
hostJ := env.NewString(host)
|
||||
if hostJ == 0 {
|
||||
return 0
|
||||
}
|
||||
defer env.DeleteLocalRef(hostJ)
|
||||
|
||||
inetAddr := env.CallStaticObjectMethodA(inetClass, getByName, Jvalue(hostJ))
|
||||
if inetAddr == 0 || env.ExceptionCheck() {
|
||||
env.ExceptionClear()
|
||||
return 0
|
||||
}
|
||||
defer env.DeleteLocalRef(inetAddr)
|
||||
|
||||
isaClass := env.FindClass("java/net/InetSocketAddress")
|
||||
if isaClass == 0 {
|
||||
return 0
|
||||
}
|
||||
defer env.DeleteLocalRef(isaClass)
|
||||
|
||||
init := env.GetMethodID(isaClass, "<init>", "(Ljava/net/InetAddress;I)V")
|
||||
if init == 0 {
|
||||
return 0
|
||||
}
|
||||
sock := env.NewObjectA(isaClass, init, Jvalue(inetAddr), Jvalue(port))
|
||||
if sock == 0 || env.ExceptionCheck() {
|
||||
env.ExceptionClear()
|
||||
return 0
|
||||
}
|
||||
return sock
|
||||
}
|
||||
|
||||
// GetConnectionOwnerUid 调用 ConnectivityManager.getConnectionOwnerUid。
|
||||
func GetConnectionOwnerUid(env Env, cm Jobject, protocol int, local, remote Jobject) int {
|
||||
cmClass := env.FindClass("android/net/ConnectivityManager")
|
||||
if cmClass == 0 {
|
||||
return invalidUID
|
||||
}
|
||||
defer env.DeleteLocalRef(cmClass)
|
||||
|
||||
method := env.GetMethodID(cmClass, "getConnectionOwnerUid",
|
||||
"(ILjava/net/InetSocketAddress;Ljava/net/InetSocketAddress;)I")
|
||||
if method == 0 {
|
||||
return invalidUID
|
||||
}
|
||||
|
||||
uid := env.CallIntMethodA(cm, method, Jvalue(protocol), Jvalue(local), Jvalue(remote))
|
||||
if env.ExceptionCheck() {
|
||||
env.ExceptionClear()
|
||||
return invalidUID
|
||||
}
|
||||
return uid
|
||||
}
|
||||
|
||||
// normalizePackageName 去掉 getNameForUid 返回的 ":appId" 后缀,得到纯包名。
|
||||
func normalizePackageName(name string) string {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" {
|
||||
return ""
|
||||
}
|
||||
if i := strings.LastIndex(name, ":"); i > 0 {
|
||||
suffix := name[i+1:]
|
||||
if suffix != "" && isDecimalString(suffix) {
|
||||
return name[:i]
|
||||
}
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func isDecimalString(s string) bool {
|
||||
for _, c := range s {
|
||||
if c < '0' || c > '9' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return len(s) > 0
|
||||
}
|
||||
|
||||
// isPackageRegistered 判断包名是否已安装(PackageManager.getPackageInfo 能查到)。
|
||||
func isPackageRegistered(env Env, pm Jobject, pmClass Jclass, pkg string) bool {
|
||||
if pkg == "" {
|
||||
return false
|
||||
}
|
||||
getPI := env.GetMethodID(pmClass, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;")
|
||||
if getPI == 0 {
|
||||
return false
|
||||
}
|
||||
pkgJ := env.NewString(pkg)
|
||||
if pkgJ == 0 {
|
||||
return false
|
||||
}
|
||||
defer env.DeleteLocalRef(pkgJ)
|
||||
pi := env.CallObjectMethodA(pm, getPI, Jvalue(pkgJ), Jvalue(0))
|
||||
if pi == 0 || env.ExceptionCheck() {
|
||||
env.ExceptionClear()
|
||||
return false
|
||||
}
|
||||
env.DeleteLocalRef(pi)
|
||||
return true
|
||||
}
|
||||
|
||||
// packageNameFromUid 优先 getPackagesForUid,否则 getNameForUid 并规范化;第二返回值表示是否在 PM 注册。
|
||||
func packageNameFromUid(env Env, pm Jobject, pmClass Jclass, uid int) (string, bool) {
|
||||
getPkgs := env.GetMethodID(pmClass, "getPackagesForUid", "(I)[Ljava/lang/String;")
|
||||
if getPkgs != 0 {
|
||||
arr := env.CallObjectMethodA(pm, getPkgs, Jvalue(uid))
|
||||
if arr != 0 && !env.ExceptionCheck() {
|
||||
defer env.DeleteLocalRef(arr)
|
||||
n := env.GetArrayLength(Jarray(arr))
|
||||
for i := 0; i < n; i++ {
|
||||
item := env.GetObjectArrayElement(JobjectArray(arr), i)
|
||||
if item == 0 {
|
||||
continue
|
||||
}
|
||||
pkg := strings.TrimSpace(env.GetString(Jstring(item)))
|
||||
env.DeleteLocalRef(item)
|
||||
if pkg != "" {
|
||||
return pkg, true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
env.ExceptionClear()
|
||||
}
|
||||
}
|
||||
|
||||
getName := env.GetMethodID(pmClass, "getNameForUid", "(I)Ljava/lang/String;")
|
||||
if getName == 0 {
|
||||
return "", false
|
||||
}
|
||||
nameObj := env.CallObjectMethodA(pm, getName, Jvalue(uid))
|
||||
if nameObj == 0 || env.ExceptionCheck() {
|
||||
env.ExceptionClear()
|
||||
return "", false
|
||||
}
|
||||
defer env.DeleteLocalRef(nameObj)
|
||||
pkg := normalizePackageName(env.GetString(Jstring(nameObj)))
|
||||
if pkg == "" {
|
||||
return "", false
|
||||
}
|
||||
return pkg, isPackageRegistered(env, pm, pmClass, pkg)
|
||||
}
|
||||
|
||||
// PackageNameForUid 解析 UID 对应纯包名及是否已注册。
|
||||
func PackageNameForUid(env Env, uid int) TunPackageResult {
|
||||
ctx := CurrentApplication(env)
|
||||
if ctx == 0 {
|
||||
return TunPackageResult{}
|
||||
}
|
||||
defer env.DeleteLocalRef(ctx)
|
||||
|
||||
getPM := env.GetMethodID(env.GetObjectClass(ctx), "getPackageManager", "()Landroid/content/pm/PackageManager;")
|
||||
if getPM == 0 {
|
||||
return TunPackageResult{}
|
||||
}
|
||||
pm := env.CallObjectMethodA(ctx, getPM)
|
||||
if pm == 0 || env.ExceptionCheck() {
|
||||
env.ExceptionClear()
|
||||
return TunPackageResult{}
|
||||
}
|
||||
defer env.DeleteLocalRef(pm)
|
||||
|
||||
pmClass := env.GetObjectClass(pm)
|
||||
defer env.DeleteLocalRef(pmClass)
|
||||
|
||||
name, reg := packageNameFromUid(env, pm, pmClass, uid)
|
||||
return TunPackageResult{Name: name, Registered: reg}
|
||||
}
|
||||
|
||||
// TunGetRequestPackageName 根据五元组查询来源包名及是否在 PackageManager 注册。
|
||||
func TunGetRequestPackageName(protocol int, srcIp string, srcPort int, dstIp string, dstPort int) TunPackageResult {
|
||||
if !TunPackageLookupEnabled || GlobalVM == 0 {
|
||||
return TunPackageResult{}
|
||||
}
|
||||
if protocol != IPProtoTCP && protocol != IPProtoUDP {
|
||||
return TunPackageResult{}
|
||||
}
|
||||
|
||||
tunCMMu.RLock()
|
||||
cm := tunCM
|
||||
tunCMMu.RUnlock()
|
||||
if cm == 0 {
|
||||
return TunPackageResult{}
|
||||
}
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
env, ret := GlobalVM.AttachCurrentThread()
|
||||
if ret != JNI_OK {
|
||||
return TunPackageResult{}
|
||||
}
|
||||
defer GlobalVM.DetachCurrentThread()
|
||||
|
||||
local := NewInetSocketAddress(env, srcIp, srcPort)
|
||||
if local == 0 {
|
||||
return TunPackageResult{}
|
||||
}
|
||||
defer env.DeleteLocalRef(local)
|
||||
|
||||
remote := NewInetSocketAddress(env, dstIp, dstPort)
|
||||
if remote == 0 {
|
||||
return TunPackageResult{}
|
||||
}
|
||||
defer env.DeleteLocalRef(remote)
|
||||
|
||||
uid := GetConnectionOwnerUid(env, cm, protocol, local, remote)
|
||||
if uid < 0 {
|
||||
return TunPackageResult{}
|
||||
}
|
||||
return PackageNameForUid(env, uid)
|
||||
}
|
||||
43
JavaApi/noAndroid_tun.go
Normal file
43
JavaApi/noAndroid_tun.go
Normal file
@@ -0,0 +1,43 @@
|
||||
//go:build !android
|
||||
// +build !android
|
||||
|
||||
package JavaJni
|
||||
|
||||
const (
|
||||
AndroidSDKQ = 29
|
||||
|
||||
IPProtoTCP = 6
|
||||
IPProtoUDP = 17
|
||||
)
|
||||
|
||||
var (
|
||||
AndroidSDKInt int
|
||||
TunPackageLookupEnabled bool
|
||||
)
|
||||
|
||||
func SdkInt(env Env) int { return 0 }
|
||||
|
||||
func InitTunConnectivityManager(env Env, cm Jobject) bool {
|
||||
AndroidSDKInt = 0
|
||||
TunPackageLookupEnabled = false
|
||||
return false
|
||||
}
|
||||
|
||||
func CurrentApplication(env Env) Jobject { return 0 }
|
||||
|
||||
func NewInetSocketAddress(env Env, host string, port int) Jobject { return 0 }
|
||||
|
||||
func GetConnectionOwnerUid(env Env, cm Jobject, protocol int, local, remote Jobject) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
func PackageNameForUid(env Env, uid int) TunPackageResult { return TunPackageResult{} }
|
||||
|
||||
type TunPackageResult struct {
|
||||
Name string
|
||||
Registered bool
|
||||
}
|
||||
|
||||
func TunGetRequestPackageName(protocol int, srcIp string, srcPort int, dstIp string, dstPort int) TunPackageResult {
|
||||
return TunPackageResult{}
|
||||
}
|
||||
@@ -88,7 +88,8 @@ func (s *proxyRequest) CallbackTCPRequest(callType int, _msg *public.TcpMsg, Rem
|
||||
localAddr: LocalAddr,
|
||||
remoteAddr: hostname,
|
||||
pid: pid,
|
||||
sunnyContext: s.Global.SunnyContext,
|
||||
packageName: s.packageName,
|
||||
sunnyContext: s.Global.SunnyContext,
|
||||
_Display: true,
|
||||
_OutRouterIPFunc: s.SetOutRouterIP,
|
||||
_note: s._note,
|
||||
@@ -196,7 +197,8 @@ func (s *proxyRequest) CallbackBeforeRequest() {
|
||||
_localAddress: s.Conn.LocalAddr().String(),
|
||||
_OutRouterIPFunc: s.SetOutRouterIP,
|
||||
updateRawTarget: s.UpdateRawTarget,
|
||||
_note: s._note,
|
||||
_note: s._note,
|
||||
packageName: s.packageName,
|
||||
}
|
||||
s.Global.scriptHTTPCall(m)
|
||||
s._note = m._note
|
||||
@@ -266,7 +268,8 @@ func (s *proxyRequest) CallbackBeforeResponse() {
|
||||
_localAddress: s.Conn.LocalAddr().String(),
|
||||
_OutRouterIPFunc: s.SetOutRouterIP,
|
||||
updateRawTarget: s.UpdateRawTarget,
|
||||
_note: s._note,
|
||||
_note: s._note,
|
||||
packageName: s.packageName,
|
||||
}
|
||||
s.Global.scriptHTTPCall(m)
|
||||
s._note = m._note
|
||||
@@ -372,7 +375,8 @@ func (s *proxyRequest) CallbackError(err string) {
|
||||
_localAddress: s.Conn.LocalAddr().String(),
|
||||
_OutRouterIPFunc: s.SetOutRouterIP,
|
||||
updateRawTarget: s.UpdateRawTarget,
|
||||
_note: s._note,
|
||||
_note: s._note,
|
||||
packageName: s.packageName,
|
||||
}
|
||||
s.Global.scriptHTTPCall(m)
|
||||
s._note = m._note
|
||||
@@ -414,7 +418,8 @@ 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,
|
||||
_note: s._note,
|
||||
packageName: s.packageName,
|
||||
}
|
||||
s.Global.scriptWebsocketCall(m)
|
||||
messageIdLock.Lock()
|
||||
|
||||
@@ -2,16 +2,17 @@ package SunnyNet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/qtgolang/SunnyNet/src/CrossCompiled"
|
||||
"github.com/qtgolang/SunnyNet/src/Interface"
|
||||
"github.com/qtgolang/SunnyNet/src/SunnyProxy"
|
||||
"github.com/qtgolang/SunnyNet/src/crypto/tls"
|
||||
"github.com/qtgolang/SunnyNet/src/http"
|
||||
"github.com/qtgolang/SunnyNet/src/public"
|
||||
"io"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ConnHTTP Interface.ConnHTTPCall
|
||||
@@ -37,8 +38,15 @@ type httpConn struct {
|
||||
_note string
|
||||
_OutRouterIPFunc func(string) bool
|
||||
updateRawTarget func(int uint32)
|
||||
packageName string //安卓模式下 pid 始终为0,但可以获取对应包名
|
||||
}
|
||||
|
||||
func (h *httpConn) PackageName() string {
|
||||
return h.packageName
|
||||
}
|
||||
func (h *httpConn) SetPackageName(packageName string) {
|
||||
h.packageName = packageName
|
||||
}
|
||||
func (h *httpConn) SetNote(s string) {
|
||||
h._note = s
|
||||
}
|
||||
|
||||
@@ -21,8 +21,15 @@ type tcpConn struct {
|
||||
_Display bool
|
||||
_OutRouterIPFunc func(string) bool
|
||||
_note string
|
||||
packageName string //安卓模式下 pid 始终为0,但可以获取对应包名
|
||||
}
|
||||
|
||||
func (t *tcpConn) PackageName() string {
|
||||
return t.packageName
|
||||
}
|
||||
func (t *tcpConn) SetPackageName(packageName string) {
|
||||
t.packageName = packageName
|
||||
}
|
||||
func (t *tcpConn) SetNote(s string) {
|
||||
t._note = s
|
||||
}
|
||||
|
||||
@@ -19,6 +19,11 @@ type udpConn struct {
|
||||
data []byte
|
||||
_Display bool
|
||||
_note string
|
||||
packageName string //安卓模式下 pid 始终为0,但可以获取对应包名
|
||||
}
|
||||
|
||||
func (u *udpConn) PackageName() string {
|
||||
return u.packageName
|
||||
}
|
||||
|
||||
func (u *udpConn) SetNote(s string) {
|
||||
|
||||
@@ -22,12 +22,19 @@ type wsConn struct {
|
||||
_Display bool
|
||||
_localAddress string
|
||||
_note string
|
||||
packageName string //安卓模式下 pid 始终为0,但可以获取对应包名
|
||||
}
|
||||
|
||||
func (w *wsConn) SetNote(s string) {
|
||||
w._note = s
|
||||
}
|
||||
|
||||
func (w *wsConn) PackageName() string {
|
||||
return w.packageName
|
||||
}
|
||||
func (w *wsConn) SetPackageName(packageName string) {
|
||||
w.packageName = packageName
|
||||
}
|
||||
func (w *wsConn) GetNote() string {
|
||||
return w._note
|
||||
}
|
||||
|
||||
@@ -193,6 +193,7 @@ type proxyRequest struct {
|
||||
Target *TargetInfo //目标连接信息
|
||||
ProxyHost string //请求之上的代理
|
||||
Pid string //s5连接过来的pid
|
||||
packageName string //安卓 TUN 来源包名
|
||||
Global *Sunny //继承全局中间件信息
|
||||
Request *http.Request //要发送的请求体
|
||||
Response response //HTTP响应体
|
||||
@@ -2271,6 +2272,11 @@ func (s *Sunny) OpenDrive(DevMode int) bool {
|
||||
return divert.Run()
|
||||
}
|
||||
|
||||
// Drive 加载的驱动、全局共享
|
||||
func (s *Sunny) Drive() ProcessDrv.Dev {
|
||||
return divert
|
||||
}
|
||||
|
||||
// ProcessALLName 是否允许所有进程通过 所有 SunnyNet 通用,
|
||||
// StopNetwork 是否对所有进程执行一次断网操作
|
||||
// 请注意GoLang调试时候,StopNetwork请不要设置true
|
||||
@@ -2442,6 +2448,7 @@ func (s *proxyRequest) clone() *proxyRequest {
|
||||
defaultScheme: s.defaultScheme,
|
||||
SendTimeout: s.SendTimeout,
|
||||
rawTarget: s.rawTarget,
|
||||
packageName: s.packageName,
|
||||
}
|
||||
if s.outRouterIP != nil {
|
||||
req.outRouterIP = &net.TCPAddr{IP: s.outRouterIP.IP}
|
||||
@@ -2557,6 +2564,7 @@ func (s *Sunny) handleClientConn(conn net.Conn) {
|
||||
req.setSocket5User("驱动程序")
|
||||
//如果是 通过 NFapi 驱动进来的数据 对连接信息进行赋值
|
||||
req.Pid = info.GetPid()
|
||||
req.packageName = info.GetPackageName()
|
||||
req.Target.Parse(info.GetRemoteAddress(), info.GetRemotePort(), info.IsV6())
|
||||
if s.connHijack != nil {
|
||||
if s.connHijack(&_hijack{req}) {
|
||||
|
||||
@@ -3,10 +3,11 @@ package SunnyNet
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/qtgolang/SunnyNet/src/Call"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/SunnyNetUDP"
|
||||
"github.com/qtgolang/SunnyNet/src/public"
|
||||
"sync"
|
||||
|
||||
"net"
|
||||
"sync/atomic"
|
||||
@@ -170,7 +171,7 @@ func (s *Sunny) listenUdpGo() {
|
||||
go s.goUdp(_info, Item.Tid, addr.String(), _info.RemoteAddress, conn, keyHash)
|
||||
}
|
||||
if Item.remote != nil {
|
||||
bs = s.udpSendReceive(public.SunnyNetUDPTypeSend, Item.Tid, 0, addr.String(), _info.RemoteAddress, _info.Data)
|
||||
bs = s.udpSendReceive(public.SunnyNetUDPTypeSend, Item.Tid, 0, addr.String(), _info.RemoteAddress, _info.Data, "")
|
||||
if len(bs) > 0 {
|
||||
_, _ = Item.remote.Write(bs)
|
||||
}
|
||||
@@ -191,7 +192,7 @@ func (s *Sunny) goUdp(info *udpInfo, tid int64, Local, Remote string, conn *net.
|
||||
break
|
||||
}
|
||||
// 调用 udpNFSendReceive 方法发送并接收数据,并将返回的数据添加来源信息
|
||||
bs := s.udpSendReceive(public.SunnyNetUDPTypeReceive, tid, 0, Local, Remote, buff[:nt])
|
||||
bs := s.udpSendReceive(public.SunnyNetUDPTypeReceive, tid, 0, Local, Remote, buff[:nt], "")
|
||||
if len(bs) < 1 {
|
||||
continue
|
||||
}
|
||||
@@ -202,18 +203,24 @@ func (s *Sunny) goUdp(info *udpInfo, tid int64, Local, Remote string, conn *net.
|
||||
_, _ = s.udpSocket.WriteToUDP(data, info.LocalAddress)
|
||||
}
|
||||
|
||||
s.udpSendReceive(public.SunnyNetUDPTypeClosed, tid, 0, Local, Remote, nil)
|
||||
s.udpSendReceive(public.SunnyNetUDPTypeClosed, tid, 0, Local, Remote, nil, "")
|
||||
SunnyNetUDP.DelUDPItem(tid)
|
||||
mu.Lock()
|
||||
delete(list, keyHash)
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
func (s *Sunny) udpSendReceive(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, packageName string) []byte {
|
||||
if s.disableUDP {
|
||||
return nil
|
||||
}
|
||||
n := &udpConn{theology: Theoni, messageId: NewMessageId(), _type: Type, sunnyContext: s.SunnyContext, pid: int(pid), localAddress: LocalAddress, remoteAddress: RemoteAddress, data: data, _Display: true}
|
||||
pkg := packageName
|
||||
if item := SunnyNetUDP.GetUDPItem(Theoni); item != nil {
|
||||
if p, ok := item.(interface{ GetPackageName() string }); ok && pkg == "" {
|
||||
pkg = p.GetPackageName()
|
||||
}
|
||||
}
|
||||
n := &udpConn{theology: Theoni, messageId: NewMessageId(), _type: Type, sunnyContext: s.SunnyContext, pid: int(pid), packageName: pkg, localAddress: LocalAddress, remoteAddress: RemoteAddress, data: data, _Display: true}
|
||||
s.scriptUDPCall(n)
|
||||
if !n._Display {
|
||||
return n.Body()
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package Interface
|
||||
|
||||
import (
|
||||
"github.com/qtgolang/SunnyNet/src/http"
|
||||
"io"
|
||||
|
||||
"github.com/qtgolang/SunnyNet/src/http"
|
||||
)
|
||||
|
||||
/* =============================== 脚本 中 使用的接口 ================================================ */
|
||||
@@ -478,6 +479,15 @@ type general interface {
|
||||
*/
|
||||
PID() int
|
||||
|
||||
/*
|
||||
PackageName
|
||||
|
||||
返回当前会话由发起的安卓进程的包名
|
||||
|
||||
(仅安卓下有效)
|
||||
*/
|
||||
PackageName() string
|
||||
|
||||
/*
|
||||
Theology
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ type DrvInfo interface {
|
||||
GetRemoteAddress() string
|
||||
GetRemotePort() uint16
|
||||
GetPid() string
|
||||
GetPackageName() string
|
||||
IsV6() bool
|
||||
ID() uint64
|
||||
Close() error
|
||||
|
||||
@@ -15,14 +15,15 @@ import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/Info"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/ProcessCheck"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/Info"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/ProcessCheck"
|
||||
)
|
||||
|
||||
var HandleClientConn func(net.Conn)
|
||||
@@ -194,6 +195,9 @@ func (p *proxyProcessInfo) GetRemotePort() uint16 {
|
||||
func (p *proxyProcessInfo) GetPid() string {
|
||||
return p.Pid
|
||||
}
|
||||
func (p *proxyProcessInfo) GetPackageName() string {
|
||||
return ""
|
||||
}
|
||||
func (p *proxyProcessInfo) IsV6() bool {
|
||||
return p.V6
|
||||
}
|
||||
|
||||
@@ -6,18 +6,20 @@ package NFapi
|
||||
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"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
|
||||
. "github.com/qtgolang/SunnyNet/src/ProcessDrv/Info"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/ProcessCheck"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/SunnyNetUDP"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/tun/Tun"
|
||||
net2 "github.com/qtgolang/SunnyNet/src/iphlpapi/net"
|
||||
"github.com/qtgolang/SunnyNet/src/public"
|
||||
"github.com/shirou/gopsutil/process"
|
||||
)
|
||||
|
||||
func getTcpInfoPID(tcpInfo string) string {
|
||||
@@ -231,7 +233,7 @@ func udpClosed(id uint64, pConnInfo *NF_UDP_CONN_INFO) {
|
||||
return
|
||||
}
|
||||
if UdpSendReceiveFunc != nil {
|
||||
UdpSendReceiveFunc(public.SunnyNetUDPTypeClosed, obj.Theoni, pConnInfo.ProcessId.Get(), pConnInfo.LocalAddress.String(), obj.Send.RemoteAddress.String(), nil)
|
||||
UdpSendReceiveFunc(public.SunnyNetUDPTypeClosed, obj.Theoni, pConnInfo.ProcessId.Get(), pConnInfo.LocalAddress.String(), obj.Send.RemoteAddress.String(), nil, "")
|
||||
}
|
||||
mu.Lock()
|
||||
delete(list, id)
|
||||
@@ -262,7 +264,7 @@ func udpReceive(id uint64, RemoteAddress *SockaddrInx, buf []byte, options *NF_U
|
||||
obj.Receive = &NfOPT{Id: id, RemoteAddress: RemoteAddress.Clone(), options: options.Clone()}
|
||||
}
|
||||
mu.Unlock()
|
||||
bs := UdpSendReceiveFunc(public.SunnyNetUDPTypeReceive, obj.Theoni, pid, LocalAddress.String(), RemoteAddress.String(), buf)
|
||||
bs := UdpSendReceiveFunc(public.SunnyNetUDPTypeReceive, obj.Theoni, pid, LocalAddress.String(), RemoteAddress.String(), buf, "")
|
||||
if len(bs) > 0 {
|
||||
_, _ = Api.NfUdpPostReceive(id, RemoteAddress, bs, options)
|
||||
}
|
||||
@@ -294,7 +296,7 @@ func udpSend(id uint64, RemoteAddress *SockaddrInx, buf []byte, options *NF_UDP_
|
||||
}
|
||||
mu.Unlock()
|
||||
//这里因为是接收 所以 RemoteAddress 是本地地址 而 LocalAddress 是远程地址
|
||||
bs := UdpSendReceiveFunc(public.SunnyNetUDPTypeReceive, obj.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)
|
||||
}
|
||||
@@ -311,13 +313,13 @@ func udpSend(id uint64, RemoteAddress *SockaddrInx, buf []byte, options *NF_UDP_
|
||||
mu.Lock()
|
||||
list[id] = obj
|
||||
mu.Unlock()
|
||||
bs := UdpSendReceiveFunc(public.SunnyNetUDPTypeSend, obj.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)
|
||||
}
|
||||
} else {
|
||||
// 如果连接已建立,则发送数据
|
||||
bs := UdpSendReceiveFunc(public.SunnyNetUDPTypeSend, obj.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)
|
||||
}
|
||||
@@ -332,4 +334,4 @@ func udpCanSend(id uint64) {
|
||||
return
|
||||
}
|
||||
|
||||
var UdpSendReceiveFunc func(Type int, Theoni int64, pid uint32, LocalAddress, RemoteAddress string, data []byte) []byte
|
||||
var UdpSendReceiveFunc Tun.UdpFunc
|
||||
|
||||
@@ -6,11 +6,12 @@ package NFapi
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
. "github.com/qtgolang/SunnyNet/src/ProcessDrv/Info"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/nfapi/basetype"
|
||||
"net"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
. "github.com/qtgolang/SunnyNet/src/ProcessDrv/Info"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/nfapi/basetype"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -99,6 +100,9 @@ func (p *ProcessInfo) GetRemotePort() uint16 {
|
||||
func (p *ProcessInfo) GetPid() string {
|
||||
return p.Pid
|
||||
}
|
||||
func (p *ProcessInfo) GetPackageName() string {
|
||||
return ""
|
||||
}
|
||||
func (p *ProcessInfo) IsV6() bool {
|
||||
return p.V6
|
||||
}
|
||||
|
||||
@@ -6,11 +6,12 @@ package NFapi
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
. "github.com/qtgolang/SunnyNet/src/ProcessDrv/Info"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/nfapi/basetype"
|
||||
"net"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
. "github.com/qtgolang/SunnyNet/src/ProcessDrv/Info"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/nfapi/basetype"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -91,6 +92,10 @@ func (p *ProcessInfo) GetRemotePort() uint16 {
|
||||
func (p *ProcessInfo) GetPid() string {
|
||||
return p.Pid
|
||||
}
|
||||
func (p *ProcessInfo) GetPackageName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *ProcessInfo) IsV6() bool {
|
||||
return p.V6
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@ 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
|
||||
|
||||
// UdpFunc PackageName 为安卓模式下的包名,其他系统下无值
|
||||
type UdpFunc func(Type int, Theoni int64, pid uint32, LocalAddress string, RemoteAddress string, data []byte, PackageName string) []byte
|
||||
type TcpFunc func(conn n2.Conn)
|
||||
|
||||
var _myPid = int32(os.Getpid())
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/ProcessCheck"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/tun/getPackageName"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/tun/tunPublic"
|
||||
)
|
||||
|
||||
@@ -24,6 +25,9 @@ type DevConn struct {
|
||||
serverIP net.IP
|
||||
serverPort uint16
|
||||
|
||||
packageName string
|
||||
packageRegistered bool
|
||||
|
||||
// TCP 序列号跟踪
|
||||
clientNext uint32 // 客户端下一个期望的 seq
|
||||
serverISN uint32 // 我们伪造的 server 初始序列号
|
||||
@@ -62,6 +66,10 @@ func (d *DevConn) GetPid() string {
|
||||
return strconv.Itoa(int(d.pid))
|
||||
}
|
||||
|
||||
func (d *DevConn) GetPackageName() string {
|
||||
return d.packageName
|
||||
}
|
||||
|
||||
func (d *DevConn) IsV6() bool {
|
||||
return !d.v4
|
||||
}
|
||||
@@ -70,8 +78,8 @@ 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, clientSynSeq uint32) *DevConn {
|
||||
// 构造函数;protocol 为 IP 协议号(TCP=6,UDP=17),仅 Android 用于查询来源包名。
|
||||
func NewDevConn(h io.ReadWriteCloser, clientIP net.IP, clientPort uint16, serverIP net.IP, serverPort uint16, ipv4 bool, protocol int, clientSynSeq uint32) *DevConn {
|
||||
// 创建 DevConn 基本信息
|
||||
d := &DevConn{
|
||||
clientIP: clientIP, // 客户端 IP
|
||||
@@ -82,6 +90,14 @@ func NewDevConn(h io.ReadWriteCloser, clientIP net.IP, clientPort uint16, server
|
||||
v4: ipv4, // 是否 IPv4
|
||||
tun: h, // TUN 句柄
|
||||
}
|
||||
// 包名查询走 getPackageName 五元组缓存,减少 JNI 调用
|
||||
pkgRes := getPackageName.GetRequestPackageName(
|
||||
protocol,
|
||||
clientIP.String(), int(clientPort),
|
||||
serverIP.String(), int(serverPort),
|
||||
)
|
||||
d.packageName = pkgRes.Name
|
||||
d.packageRegistered = pkgRes.Registered
|
||||
d.ts = time.Now()
|
||||
// 客户端期望 seq:客户端 ISN + 1
|
||||
// 第一个数据包的 tcp.Seq 必须等于这个值才会被接收
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
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)
|
||||
s := NewDevConn(n.tun, srcIP, clientPort, dstIP, serverPort, v4, 6, tcp.Seq)
|
||||
s.pid = uint32(pid)
|
||||
sessionsMu.Lock()
|
||||
sessions[clientPort] = s
|
||||
@@ -35,7 +35,7 @@ func (n *NewTun) handleTCPCommand(tcp *layers.TCP, srcIP, dstIP net.IP, clientPo
|
||||
sessionsMu.Lock()
|
||||
call := n.handleTCPCallback
|
||||
sessionsMu.Unlock()
|
||||
if n.pidFromCheck(pid, name) {
|
||||
if (s.packageName != "" && !s.packageRegistered) || n.pidFromCheck(pid, name) {
|
||||
go func() {
|
||||
var loader *net.TCPAddr
|
||||
if defaultGatewayIP != "" {
|
||||
@@ -79,7 +79,7 @@ func (n *NewTun) handleTCPCommand(tcp *layers.TCP, srcIP, dstIP net.IP, clientPo
|
||||
sess, ok := sessions[clientPort]
|
||||
sessionsMu.Unlock()
|
||||
if !ok {
|
||||
h2 := NewDevConn(n.tun, srcIP, clientPort, dstIP, serverPort, v4, tcp.Seq)
|
||||
h2 := NewDevConn(n.tun, srcIP, clientPort, dstIP, serverPort, v4, 6, tcp.Seq)
|
||||
_ = SendRstToClient(h2)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/SunnyNetUDP"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/tun/getPackageName"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/tun/tunPublic"
|
||||
"github.com/qtgolang/SunnyNet/src/public"
|
||||
)
|
||||
@@ -30,8 +31,13 @@ type connEntry struct {
|
||||
v4 bool
|
||||
pid int32
|
||||
pidFromCheck bool
|
||||
callback func(Type int, Theoni int64, pid uint32, LocalAddress, RemoteAddress string, data []byte) []byte
|
||||
callback func(Type int, Theoni int64, pid uint32, LocalAddress, RemoteAddress string, data []byte, packageName string) []byte
|
||||
mu *sync.Mutex
|
||||
packageName string
|
||||
}
|
||||
|
||||
func (c *connEntry) GetPackageName() string {
|
||||
return c.packageName
|
||||
}
|
||||
|
||||
func (c *connEntry) ToClient(payload []byte) bool {
|
||||
@@ -116,9 +122,16 @@ func (n *NewTun) handleUDP(srcIP, dstIP net.IP, udp *layers.UDP, v4 bool) {
|
||||
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}
|
||||
pkgRes := getPackageName.GetRequestPackageName(
|
||||
getPackageName.ProtocolUDP,
|
||||
clientIP.String(), int(clientPort),
|
||||
serverIP.String(), int(serverPort),
|
||||
)
|
||||
obj.packageName = pkgRes.Name
|
||||
|
||||
pid, name := getPidByPort("udp", clientPort)
|
||||
obj.pid = pid
|
||||
obj.pidFromCheck = n.pidFromCheck(obj.pid, name)
|
||||
obj.pidFromCheck = (pkgRes.Name != "" && !pkgRes.Registered) || n.pidFromCheck(obj.pid, name)
|
||||
connTable[clientPort] = obj
|
||||
connMu.Unlock()
|
||||
mu.Lock()
|
||||
@@ -159,7 +172,7 @@ func (n *NewTun) handleUDP(srcIP, dstIP net.IP, udp *layers.UDP, v4 bool) {
|
||||
if tunPublic.IsLocalIp(obj.ServerIP) {
|
||||
RemoteAddress = net.JoinHostPort("127.0.0.1", strconv.Itoa(int(obj.ServerPort)))
|
||||
}
|
||||
bs := obj.callback(public.SunnyNetUDPTypeSend, obj.Theology, uint32(obj.pid), LocalAddress, RemoteAddress, Payload)
|
||||
bs := obj.callback(public.SunnyNetUDPTypeSend, obj.Theology, uint32(obj.pid), LocalAddress, RemoteAddress, Payload, obj.packageName)
|
||||
if len(bs) < 1 {
|
||||
return
|
||||
}
|
||||
@@ -202,7 +215,7 @@ func (c *connEntry) loop() {
|
||||
return
|
||||
}
|
||||
|
||||
bs := c.callback(public.SunnyNetUDPTypeReceive, c.Theology, uint32(c.pid), LocalAddress, RemoteAddress, buff[:nt])
|
||||
bs := c.callback(public.SunnyNetUDPTypeReceive, c.Theology, uint32(c.pid), LocalAddress, RemoteAddress, buff[:nt], c.packageName)
|
||||
if len(bs) < 1 {
|
||||
continue
|
||||
}
|
||||
@@ -218,7 +231,7 @@ func (c *connEntry) loop() {
|
||||
return
|
||||
}
|
||||
if c.callback != nil {
|
||||
c.callback(public.SunnyNetUDPTypeClosed, c.Theology, uint32(c.pid), LocalAddress, RemoteAddress, nil)
|
||||
c.callback(public.SunnyNetUDPTypeClosed, c.Theology, uint32(c.pid), LocalAddress, RemoteAddress, nil, c.packageName)
|
||||
}
|
||||
delete(connTable, c.ClientPort)
|
||||
}
|
||||
|
||||
@@ -67,6 +67,10 @@ func (d *DevConn) GetPid() string {
|
||||
return strconv.Itoa(int(d.pid))
|
||||
}
|
||||
|
||||
func (d *DevConn) GetPackageName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (d *DevConn) IsV6() bool {
|
||||
return !d.v4
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ func (d *Divert) Run() bool {
|
||||
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) {
|
||||
udpSendReceiveFunc Tun.UdpFunc) {
|
||||
sessionsMu.Lock()
|
||||
defer sessionsMu.Unlock()
|
||||
d.handleTCP = callbackTCP
|
||||
|
||||
@@ -6,14 +6,15 @@ 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"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/qtgolang/SunnyNet/src/ProcessDrv/SunnyNetUDP"
|
||||
"github.com/qtgolang/SunnyNet/src/public"
|
||||
)
|
||||
|
||||
type expiryUDP struct {
|
||||
@@ -153,9 +154,9 @@ func (d *Divert) handleCommandUDP(h *Handle, data []byte, addr *Address, udp *la
|
||||
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)
|
||||
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)
|
||||
bs = call(public.SunnyNetUDPTypeReceive, obj.Theology, uint32(obj.pid), RemoteAddress, LocalAddress, payload, "")
|
||||
}
|
||||
if len(bs) > 0 {
|
||||
if bytes.Equal(bs, payload) {
|
||||
@@ -265,7 +266,7 @@ func (d *Divert) runFlow() bool {
|
||||
call := d.handleUDP
|
||||
sessionsMu.Unlock()
|
||||
if call != nil {
|
||||
call(public.SunnyNetUDPTypeClosed, obj.Theology, uint32(obj.pid), LocalAddress, RemoteAddress, nil)
|
||||
call(public.SunnyNetUDPTypeClosed, obj.Theology, uint32(obj.pid), LocalAddress, RemoteAddress, nil, "")
|
||||
}
|
||||
SunnyNetUDP.DelUDPItem(obj.Theology)
|
||||
}
|
||||
|
||||
23
src/ProcessDrv/tun/getPackageName/android.go
Normal file
23
src/ProcessDrv/tun/getPackageName/android.go
Normal file
@@ -0,0 +1,23 @@
|
||||
//go:build android
|
||||
// +build android
|
||||
|
||||
package getPackageName
|
||||
|
||||
import JavaJni "github.com/qtgolang/SunnyNet/JavaApi"
|
||||
|
||||
const (
|
||||
ProtocolTCP = 6 // IPPROTO_TCP
|
||||
ProtocolUDP = 17 // IPPROTO_UDP
|
||||
)
|
||||
|
||||
// SetConnectivityManager 兼容旧接口;实际 CM 由 JavaJni.InitTunConnectivityManager 在 OnTunSetFd 中注入。
|
||||
// 调用时清空包名缓存,避免 VPN 重建后沿用旧五元组结果。
|
||||
func SetConnectivityManager(uintptr) {
|
||||
ClearPackageNameCache()
|
||||
}
|
||||
|
||||
// queryPackageName 执行一次 JNI 查询(无缓存);由 GetRequestPackageName 统一加缓存。
|
||||
func queryPackageName(protocol int, srcIp string, srcPort int, dstIp string, dstPort int) Result {
|
||||
r := JavaJni.TunGetRequestPackageName(protocol, srcIp, srcPort, dstIp, dstPort)
|
||||
return Result{Name: r.Name, Registered: r.Registered}
|
||||
}
|
||||
116
src/ProcessDrv/tun/getPackageName/cache.go
Normal file
116
src/ProcessDrv/tun/getPackageName/cache.go
Normal file
@@ -0,0 +1,116 @@
|
||||
// Package getPackageName 在 Android TUN 模式下根据五元组查询流量来源包名。
|
||||
// 查询结果带内存缓存,避免 SYN 重传、UDP 多包等场景反复调用 JNI。
|
||||
package getPackageName
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// pkgCacheTTLPositive 命中包名时的缓存时长(连接存活期内五元组通常不变)。
|
||||
pkgCacheTTLPositive = 2 * time.Minute
|
||||
// pkgCacheTTLNegative 未查到包名时的缓存时长(较短,便于 socket 登记后尽快重试)。
|
||||
pkgCacheTTLNegative = 5 * time.Second
|
||||
// maxCacheEntries 缓存条数上限,防止长时间运行内存无限增长。
|
||||
maxCacheEntries = 2048
|
||||
)
|
||||
|
||||
// cacheItem 单条缓存记录。
|
||||
type cacheItem struct {
|
||||
result Result // 查询结果(包名 + 是否已在 PackageManager 注册)
|
||||
expire time.Time // 过期时间
|
||||
}
|
||||
|
||||
var (
|
||||
pkgCacheMu sync.RWMutex
|
||||
pkgCache = make(map[string]cacheItem) // key 见 cacheKey
|
||||
)
|
||||
|
||||
// cacheKey 生成五元组缓存键:protocol|srcIp|srcPort|dstIp|dstPort。
|
||||
// src 为 TUN 上看到的客户端(应用侧),dst 为目标服务器。
|
||||
func cacheKey(protocol int, srcIp string, srcPort int, dstIp string, dstPort int) string {
|
||||
return fmt.Sprintf("%d|%s|%d|%s|%d", protocol, srcIp, srcPort, dstIp, dstPort)
|
||||
}
|
||||
|
||||
// getFromCache 读取缓存;第二个返回值为 true 表示命中且未过期。
|
||||
func getFromCache(protocol int, srcIp string, srcPort int, dstIp string, dstPort int) (Result, bool) {
|
||||
key := cacheKey(protocol, srcIp, srcPort, dstIp, dstPort)
|
||||
now := time.Now()
|
||||
|
||||
pkgCacheMu.RLock()
|
||||
item, ok := pkgCache[key]
|
||||
pkgCacheMu.RUnlock()
|
||||
if !ok {
|
||||
return Result{}, false
|
||||
}
|
||||
if now.After(item.expire) {
|
||||
// 惰性删除过期项,避免后台清扫协程
|
||||
pkgCacheMu.Lock()
|
||||
if cur, still := pkgCache[key]; still && now.After(cur.expire) {
|
||||
delete(pkgCache, key)
|
||||
}
|
||||
pkgCacheMu.Unlock()
|
||||
return Result{}, false
|
||||
}
|
||||
return item.result, true
|
||||
}
|
||||
|
||||
// putCache 写入缓存;有包名与无包名使用不同 TTL。
|
||||
func putCache(protocol int, srcIp string, srcPort int, dstIp string, dstPort int, r Result) {
|
||||
ttl := pkgCacheTTLNegative
|
||||
if r.Name != "" {
|
||||
ttl = pkgCacheTTLPositive
|
||||
}
|
||||
key := cacheKey(protocol, srcIp, srcPort, dstIp, dstPort)
|
||||
item := cacheItem{result: r, expire: time.Now().Add(ttl)}
|
||||
|
||||
pkgCacheMu.Lock()
|
||||
pkgCache[key] = item
|
||||
if len(pkgCache) > maxCacheEntries {
|
||||
evictExpiredLocked(time.Now())
|
||||
// 仍超限则整表重建(极端流量下的兜底)
|
||||
if len(pkgCache) > maxCacheEntries {
|
||||
pkgCache = make(map[string]cacheItem)
|
||||
}
|
||||
}
|
||||
pkgCacheMu.Unlock()
|
||||
}
|
||||
|
||||
// evictExpiredLocked 删除所有已过期项;调用方需已持有 pkgCacheMu 写锁。
|
||||
func evictExpiredLocked(now time.Time) {
|
||||
for k, v := range pkgCache {
|
||||
if now.After(v.expire) {
|
||||
delete(pkgCache, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ClearPackageNameCache 清空五元组包名查询缓存。
|
||||
// 建议在 VPN 重启、OnTunSetFd 或切换用户后调用,避免沿用过期归属信息。
|
||||
func ClearPackageNameCache() {
|
||||
pkgCacheMu.Lock()
|
||||
pkgCache = make(map[string]cacheItem)
|
||||
pkgCacheMu.Unlock()
|
||||
}
|
||||
|
||||
// GetRequestPackageName 按五元组查询来源包名。
|
||||
//
|
||||
// 参数:
|
||||
// - protocol:IP 协议号,TCP=6,UDP=17
|
||||
// - srcIp/srcPort:TUN 包中的源地址(VPN 内应用侧,如 10.0.0.2:port)
|
||||
// - dstIp/dstPort:TUN 包中的目的地址
|
||||
//
|
||||
// 先查缓存,未命中则调用 queryPackageName(Android 下走 ConnectivityManager JNI)。
|
||||
func GetRequestPackageName(protocol int, srcIp string, srcPort int, dstIp string, dstPort int) Result {
|
||||
if r, ok := getFromCache(protocol, srcIp, srcPort, dstIp, dstPort); ok {
|
||||
return r
|
||||
}
|
||||
r := queryPackageName(protocol, srcIp, srcPort, dstIp, dstPort)
|
||||
if r.Name == "" {
|
||||
return r
|
||||
}
|
||||
putCache(protocol, srcIp, srcPort, dstIp, dstPort, r)
|
||||
return r
|
||||
}
|
||||
17
src/ProcessDrv/tun/getPackageName/noAndroid.go
Normal file
17
src/ProcessDrv/tun/getPackageName/noAndroid.go
Normal file
@@ -0,0 +1,17 @@
|
||||
//go:build !android
|
||||
// +build !android
|
||||
|
||||
package getPackageName
|
||||
|
||||
const (
|
||||
ProtocolTCP = 6
|
||||
ProtocolUDP = 17
|
||||
)
|
||||
|
||||
// SetConnectivityManager 非 Android 平台无 TUN 包名查询能力。
|
||||
func SetConnectivityManager(uintptr) {}
|
||||
|
||||
// queryPackageName 非 Android 恒为空结果。
|
||||
func queryPackageName(protocol int, srcIp string, srcPort int, dstIp string, dstPort int) Result {
|
||||
return Result{}
|
||||
}
|
||||
7
src/ProcessDrv/tun/getPackageName/result.go
Normal file
7
src/ProcessDrv/tun/getPackageName/result.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package getPackageName
|
||||
|
||||
// Result 为 TUN 五元组包名查询结果(与 JavaApi.TunPackageResult 对应)。
|
||||
type Result struct {
|
||||
Name string // 来源应用包名(已去掉 getNameForUid 的 ":appId" 后缀)
|
||||
Registered bool // Name 是否为已安装包(pm list packages 可查);false 时可能为共享 UID 合成名
|
||||
}
|
||||
@@ -32,5 +32,5 @@ func UnInstall() bool {
|
||||
return true
|
||||
}
|
||||
func SetFd(fd int) bool {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -6,15 +6,16 @@ package tun
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"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()
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build 386 amd64
|
||||
|
||||
package cpu_test
|
||||
|
||||
import (
|
||||
. "internal/cpu"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestX86ifAVX2hasAVX(t *testing.T) {
|
||||
if X86.HasAVX2 && !X86.HasAVX {
|
||||
t.Fatalf("HasAVX expected true when HasAVX2 is true, got false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisableSSE2(t *testing.T) {
|
||||
runDebugOptionsTest(t, "TestSSE2DebugOption", "cpu.sse2=off")
|
||||
}
|
||||
|
||||
func TestSSE2DebugOption(t *testing.T) {
|
||||
MustHaveDebugOptionsSupport(t)
|
||||
|
||||
if os.Getenv("GODEBUG") != "cpu.sse2=off" {
|
||||
t.Skipf("skipping test: GODEBUG=cpu.sse2=off not set")
|
||||
}
|
||||
|
||||
want := runtime.GOARCH != "386" // SSE2 can only be disabled on 386.
|
||||
if got := X86.HasSSE2; got != want {
|
||||
t.Errorf("X86.HasSSE2 on %s expected %v, got %v", runtime.GOARCH, want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisableSSE3(t *testing.T) {
|
||||
runDebugOptionsTest(t, "TestSSE3DebugOption", "cpu.sse3=off")
|
||||
}
|
||||
|
||||
func TestSSE3DebugOption(t *testing.T) {
|
||||
MustHaveDebugOptionsSupport(t)
|
||||
|
||||
if os.Getenv("GODEBUG") != "cpu.sse3=off" {
|
||||
t.Skipf("skipping test: GODEBUG=cpu.sse3=off not set")
|
||||
}
|
||||
|
||||
want := false
|
||||
if got := X86.HasSSE3; got != want {
|
||||
t.Errorf("X86.HasSSE3 expected %v, got %v", want, got)
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/qtgolang/SunnyNet/src/websocket"
|
||||
)
|
||||
|
||||
const SunnyVersion = "2026-05-22"
|
||||
const SunnyVersion = "2026-05-26"
|
||||
const Information = `
|
||||
------------------------------------------------------
|
||||
欢迎使用 SunnyNet 网络中间件 - V` + SunnyVersion + `
|
||||
|
||||
Reference in New Issue
Block a user