mirror of
https://github.com/MatsuriDayo/NekoBoxForAndroid.git
synced 2026-01-05 02:19:02 +08:00
Compare commits
20 Commits
ad61b2ee66
...
d44438df8b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d44438df8b | ||
|
|
3b3c6757b9 | ||
|
|
e1b8488f94 | ||
|
|
6a0d998eaf | ||
|
|
4483a85df2 | ||
|
|
89c1dab989 | ||
|
|
6f7b4a125f | ||
|
|
c7ef42d9f1 | ||
|
|
607afa8ce3 | ||
|
|
ea8e4aee60 | ||
|
|
cc9ea9a81a | ||
|
|
febb1e210e | ||
|
|
e241977572 | ||
|
|
e3fe755b25 | ||
|
|
3ee216700c | ||
|
|
8590d9284a | ||
|
|
5a191fdc94 | ||
|
|
71a3cdd8b6 | ||
|
|
d69f607d72 | ||
|
|
fd825c5532 |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -33,7 +33,7 @@ jobs:
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.22.10"
|
||||
go-version: "1.23.6"
|
||||
- name: Native Build
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: ./run lib core
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("kotlin-android")
|
||||
id("kotlin-kapt")
|
||||
id("com.google.devtools.ksp")
|
||||
id("kotlin-parcelize")
|
||||
}
|
||||
|
||||
@ -13,8 +13,8 @@ android {
|
||||
compileOptions {
|
||||
isCoreLibraryDesugaringEnabled = true
|
||||
}
|
||||
kapt.arguments {
|
||||
arg("room.incremental", true)
|
||||
ksp {
|
||||
arg("room.incremental", "true")
|
||||
arg("room.schemaLocation", "$projectDir/schemas")
|
||||
}
|
||||
bundle {
|
||||
@ -23,9 +23,19 @@ android {
|
||||
}
|
||||
}
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
viewBinding = true
|
||||
aidl = true
|
||||
}
|
||||
namespace = "io.nekohasekai.sagernet"
|
||||
packaging {
|
||||
jniLibs {
|
||||
useLegacyPackaging = true
|
||||
}
|
||||
}
|
||||
androidResources {
|
||||
generateLocaleConfig = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@ -68,11 +78,11 @@ dependencies {
|
||||
exclude(group = "androidx.appcompat")
|
||||
}
|
||||
|
||||
implementation("androidx.room:room-runtime:2.5.1")
|
||||
kapt("androidx.room:room-compiler:2.5.1")
|
||||
implementation("androidx.room:room-ktx:2.5.1")
|
||||
implementation("androidx.room:room-runtime:2.6.1")
|
||||
ksp("androidx.room:room-compiler:2.6.1")
|
||||
implementation("androidx.room:room-ktx:2.6.1")
|
||||
implementation("com.github.MatrixDev.Roomigrant:RoomigrantLib:0.3.4")
|
||||
kapt("com.github.MatrixDev.Roomigrant:RoomigrantCompiler:0.3.4")
|
||||
ksp("com.github.MatrixDev.Roomigrant:RoomigrantCompiler:0.3.4")
|
||||
|
||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.3")
|
||||
}
|
||||
|
||||
@ -0,0 +1,360 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 4,
|
||||
"identityHash": "cff00d0142d9e53d2ca24a6a55cd213c",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "proxy_groups",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL, `isSelector` INTEGER NOT NULL, `frontProxy` INTEGER NOT NULL, `landingProxy` INTEGER NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "userOrder",
|
||||
"columnName": "userOrder",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "ungrouped",
|
||||
"columnName": "ungrouped",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "subscription",
|
||||
"columnName": "subscription",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "order",
|
||||
"columnName": "order",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isSelector",
|
||||
"columnName": "isSelector",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "frontProxy",
|
||||
"columnName": "frontProxy",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "landingProxy",
|
||||
"columnName": "landingProxy",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "proxy_entities",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `groupId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `status` INTEGER NOT NULL, `ping` INTEGER NOT NULL, `uuid` TEXT NOT NULL, `error` TEXT, `socksBean` BLOB, `httpBean` BLOB, `ssBean` BLOB, `vmessBean` BLOB, `trojanBean` BLOB, `trojanGoBean` BLOB, `mieruBean` BLOB, `naiveBean` BLOB, `hysteriaBean` BLOB, `tuicBean` BLOB, `sshBean` BLOB, `wgBean` BLOB, `shadowTLSBean` BLOB, `chainBean` BLOB, `nekoBean` BLOB, `configBean` BLOB)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "groupId",
|
||||
"columnName": "groupId",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "userOrder",
|
||||
"columnName": "userOrder",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "tx",
|
||||
"columnName": "tx",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "rx",
|
||||
"columnName": "rx",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "status",
|
||||
"columnName": "status",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "ping",
|
||||
"columnName": "ping",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "uuid",
|
||||
"columnName": "uuid",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "error",
|
||||
"columnName": "error",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "socksBean",
|
||||
"columnName": "socksBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "httpBean",
|
||||
"columnName": "httpBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "ssBean",
|
||||
"columnName": "ssBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "vmessBean",
|
||||
"columnName": "vmessBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "trojanBean",
|
||||
"columnName": "trojanBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "trojanGoBean",
|
||||
"columnName": "trojanGoBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "mieruBean",
|
||||
"columnName": "mieruBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "naiveBean",
|
||||
"columnName": "naiveBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "hysteriaBean",
|
||||
"columnName": "hysteriaBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "tuicBean",
|
||||
"columnName": "tuicBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "sshBean",
|
||||
"columnName": "sshBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "wgBean",
|
||||
"columnName": "wgBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "shadowTLSBean",
|
||||
"columnName": "shadowTLSBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "chainBean",
|
||||
"columnName": "chainBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "nekoBean",
|
||||
"columnName": "nekoBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "configBean",
|
||||
"columnName": "configBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "groupId",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"groupId"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `groupId` ON `${TABLE_NAME}` (`groupId`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "rules",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `userOrder` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `domains` TEXT NOT NULL, `ip` TEXT NOT NULL, `port` TEXT NOT NULL, `sourcePort` TEXT NOT NULL, `network` TEXT NOT NULL, `source` TEXT NOT NULL, `protocol` TEXT NOT NULL, `outbound` INTEGER NOT NULL, `packages` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "userOrder",
|
||||
"columnName": "userOrder",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "enabled",
|
||||
"columnName": "enabled",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "domains",
|
||||
"columnName": "domains",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "ip",
|
||||
"columnName": "ip",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "port",
|
||||
"columnName": "port",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "sourcePort",
|
||||
"columnName": "sourcePort",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "network",
|
||||
"columnName": "network",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "source",
|
||||
"columnName": "source",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "protocol",
|
||||
"columnName": "protocol",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "outbound",
|
||||
"columnName": "outbound",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "packages",
|
||||
"columnName": "packages",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'cff00d0142d9e53d2ca24a6a55cd213c')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,366 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 5,
|
||||
"identityHash": "1dbf667053726c13d139a4d83c41f895",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "proxy_groups",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL, `isSelector` INTEGER NOT NULL, `frontProxy` INTEGER NOT NULL, `landingProxy` INTEGER NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "userOrder",
|
||||
"columnName": "userOrder",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "ungrouped",
|
||||
"columnName": "ungrouped",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "subscription",
|
||||
"columnName": "subscription",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "order",
|
||||
"columnName": "order",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isSelector",
|
||||
"columnName": "isSelector",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "frontProxy",
|
||||
"columnName": "frontProxy",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "landingProxy",
|
||||
"columnName": "landingProxy",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "proxy_entities",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `groupId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `status` INTEGER NOT NULL, `ping` INTEGER NOT NULL, `uuid` TEXT NOT NULL, `error` TEXT, `socksBean` BLOB, `httpBean` BLOB, `ssBean` BLOB, `vmessBean` BLOB, `trojanBean` BLOB, `trojanGoBean` BLOB, `mieruBean` BLOB, `naiveBean` BLOB, `hysteriaBean` BLOB, `tuicBean` BLOB, `sshBean` BLOB, `wgBean` BLOB, `shadowTLSBean` BLOB, `anyTLSBean` BLOB, `chainBean` BLOB, `nekoBean` BLOB, `configBean` BLOB)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "groupId",
|
||||
"columnName": "groupId",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "userOrder",
|
||||
"columnName": "userOrder",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "tx",
|
||||
"columnName": "tx",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "rx",
|
||||
"columnName": "rx",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "status",
|
||||
"columnName": "status",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "ping",
|
||||
"columnName": "ping",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "uuid",
|
||||
"columnName": "uuid",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "error",
|
||||
"columnName": "error",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "socksBean",
|
||||
"columnName": "socksBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "httpBean",
|
||||
"columnName": "httpBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "ssBean",
|
||||
"columnName": "ssBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "vmessBean",
|
||||
"columnName": "vmessBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "trojanBean",
|
||||
"columnName": "trojanBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "trojanGoBean",
|
||||
"columnName": "trojanGoBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "mieruBean",
|
||||
"columnName": "mieruBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "naiveBean",
|
||||
"columnName": "naiveBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "hysteriaBean",
|
||||
"columnName": "hysteriaBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "tuicBean",
|
||||
"columnName": "tuicBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "sshBean",
|
||||
"columnName": "sshBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "wgBean",
|
||||
"columnName": "wgBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "shadowTLSBean",
|
||||
"columnName": "shadowTLSBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "anyTLSBean",
|
||||
"columnName": "anyTLSBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "chainBean",
|
||||
"columnName": "chainBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "nekoBean",
|
||||
"columnName": "nekoBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "configBean",
|
||||
"columnName": "configBean",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "groupId",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"groupId"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `groupId` ON `${TABLE_NAME}` (`groupId`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "rules",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `userOrder` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `domains` TEXT NOT NULL, `ip` TEXT NOT NULL, `port` TEXT NOT NULL, `sourcePort` TEXT NOT NULL, `network` TEXT NOT NULL, `source` TEXT NOT NULL, `protocol` TEXT NOT NULL, `outbound` INTEGER NOT NULL, `packages` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "userOrder",
|
||||
"columnName": "userOrder",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "enabled",
|
||||
"columnName": "enabled",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "domains",
|
||||
"columnName": "domains",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "ip",
|
||||
"columnName": "ip",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "port",
|
||||
"columnName": "port",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "sourcePort",
|
||||
"columnName": "sourcePort",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "network",
|
||||
"columnName": "network",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "source",
|
||||
"columnName": "source",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "protocol",
|
||||
"columnName": "protocol",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "outbound",
|
||||
"columnName": "outbound",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "packages",
|
||||
"columnName": "packages",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1dbf667053726c13d139a4d83c41f895')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -13,6 +13,7 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
@ -50,7 +51,6 @@
|
||||
android:autoRevokePermissions="allowed"
|
||||
android:banner="@mipmap/ic_launcher"
|
||||
android:dataExtractionRules="@xml/backup_rules"
|
||||
android:extractNativeLibs="true"
|
||||
android:fullBackupContent="@xml/backup_descriptor"
|
||||
android:fullBackupOnly="true"
|
||||
android:hardwareAccelerated="true"
|
||||
@ -188,6 +188,9 @@
|
||||
<activity
|
||||
android:name="moe.matsuri.nb4a.proxy.shadowtls.ShadowTLSSettingsActivity"
|
||||
android:configChanges="uiMode" />
|
||||
<activity
|
||||
android:name="moe.matsuri.nb4a.proxy.anytls.AnyTLSSettingsActivity"
|
||||
android:configChanges="uiMode" />
|
||||
<activity
|
||||
android:name="moe.matsuri.nb4a.proxy.neko.NekoSettingActivity"
|
||||
android:configChanges="uiMode" />
|
||||
@ -255,11 +258,17 @@
|
||||
<service
|
||||
android:name="io.nekohasekai.sagernet.bg.ProxyService"
|
||||
android:exported="false"
|
||||
android:process=":bg" />
|
||||
android:foregroundServiceType="specialUse"
|
||||
android:process=":bg">
|
||||
<property
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||
android:value="proxy" />
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name="io.nekohasekai.sagernet.bg.VpnService"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="specialUse"
|
||||
android:label="@string/app_name"
|
||||
android:permission="android.permission.BIND_VPN_SERVICE"
|
||||
android:process=":bg">
|
||||
@ -267,6 +276,9 @@
|
||||
<intent-filter>
|
||||
<action android:name="android.net.VpnService" />
|
||||
</intent-filter>
|
||||
<property
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||
android:value="vpn" />
|
||||
</service>
|
||||
|
||||
<service
|
||||
|
||||
@ -52,9 +52,6 @@ object Key {
|
||||
const val ALWAYS_SHOW_ADDRESS = "alwaysShowAddress"
|
||||
|
||||
// Protocol Settings
|
||||
const val MUX_TYPE = "muxType"
|
||||
const val MUX_PROTOCOLS = "mux"
|
||||
const val MUX_CONCURRENCY = "muxConcurrency"
|
||||
const val GLOBAL_ALLOW_INSECURE = "globalAllowInsecure"
|
||||
|
||||
const val ACQUIRE_WAKE_LOCK = "acquireWakeLock"
|
||||
|
||||
@ -328,7 +328,7 @@ class BaseService {
|
||||
data.proxy = proxy
|
||||
BootReceiver.enabled = DataStore.persistAcrossReboot
|
||||
if (!data.closeReceiverRegistered) {
|
||||
registerReceiver(data.receiver, IntentFilter().apply {
|
||||
val filter = IntentFilter().apply {
|
||||
addAction(Action.RELOAD)
|
||||
addAction(Intent.ACTION_SHUTDOWN)
|
||||
addAction(Action.CLOSE)
|
||||
@ -337,7 +337,23 @@ class BaseService {
|
||||
addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)
|
||||
}
|
||||
addAction(Action.RESET_UPSTREAM_CONNECTIONS)
|
||||
}, "$packageName.SERVICE", null)
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
registerReceiver(
|
||||
data.receiver,
|
||||
filter,
|
||||
"$packageName.SERVICE",
|
||||
null,
|
||||
Context.RECEIVER_EXPORTED
|
||||
)
|
||||
} else {
|
||||
registerReceiver(
|
||||
data.receiver,
|
||||
filter,
|
||||
"$packageName.SERVICE",
|
||||
null
|
||||
)
|
||||
}
|
||||
data.closeReceiverRegistered = true
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
|
||||
import android.os.Build
|
||||
import android.text.format.Formatter
|
||||
import androidx.core.app.NotificationCompat
|
||||
@ -183,7 +184,17 @@ class ServiceNotification(
|
||||
|
||||
|
||||
private suspend fun show() =
|
||||
useBuilder { (service as Service).startForeground(notificationId, it.build()) }
|
||||
useBuilder {
|
||||
if (Build.VERSION.SDK_INT >= 34) {
|
||||
(service as Service).startForeground(
|
||||
notificationId,
|
||||
it.build(),
|
||||
FOREGROUND_SERVICE_TYPE_SPECIAL_USE
|
||||
)
|
||||
} else {
|
||||
(service as Service).startForeground(notificationId, it.build())
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun update() = useBuilder {
|
||||
NotificationManagerCompat.from(service as Service).notify(notificationId, it.build())
|
||||
@ -191,7 +202,11 @@ class ServiceNotification(
|
||||
|
||||
fun destroy() {
|
||||
listenPostSpeed = false
|
||||
(service as Service).stopForeground(true)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
(service as Service).stopForeground(Service.STOP_FOREGROUND_REMOVE)
|
||||
} else {
|
||||
(service as Service).stopForeground(true)
|
||||
}
|
||||
service.unregisterReceiver(this)
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,7 +47,6 @@ class TestInstance(profile: ProxyEntity, val link: String, val timeout: Int) :
|
||||
// don't call destroyAllJsi here
|
||||
if (BuildConfig.DEBUG) Logs.d(config.config)
|
||||
box = Libcore.newSingBoxInstance(config.config)
|
||||
box.forTest = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,13 +2,24 @@ package io.nekohasekai.sagernet.database
|
||||
|
||||
import android.os.Binder
|
||||
import androidx.preference.PreferenceDataStore
|
||||
import io.nekohasekai.sagernet.*
|
||||
import io.nekohasekai.sagernet.CONNECTION_TEST_URL
|
||||
import io.nekohasekai.sagernet.GroupType
|
||||
import io.nekohasekai.sagernet.IPv6Mode
|
||||
import io.nekohasekai.sagernet.Key
|
||||
import io.nekohasekai.sagernet.TunImplementation
|
||||
import io.nekohasekai.sagernet.bg.BaseService
|
||||
import io.nekohasekai.sagernet.bg.VpnService
|
||||
import io.nekohasekai.sagernet.database.preference.OnPreferenceDataStoreChangeListener
|
||||
import io.nekohasekai.sagernet.database.preference.PublicDatabase
|
||||
import io.nekohasekai.sagernet.database.preference.RoomPreferenceDataStore
|
||||
import io.nekohasekai.sagernet.ktx.*
|
||||
import io.nekohasekai.sagernet.ktx.boolean
|
||||
import io.nekohasekai.sagernet.ktx.int
|
||||
import io.nekohasekai.sagernet.ktx.long
|
||||
import io.nekohasekai.sagernet.ktx.parsePort
|
||||
import io.nekohasekai.sagernet.ktx.string
|
||||
import io.nekohasekai.sagernet.ktx.stringSet
|
||||
import io.nekohasekai.sagernet.ktx.stringToInt
|
||||
import io.nekohasekai.sagernet.ktx.stringToIntIfExists
|
||||
import moe.matsuri.nb4a.TempDatabase
|
||||
|
||||
object DataStore : OnPreferenceDataStoreChangeListener {
|
||||
@ -98,7 +109,7 @@ object DataStore : OnPreferenceDataStoreChangeListener {
|
||||
var showGroupInNotification by configurationStore.boolean("showGroupInNotification")
|
||||
|
||||
var remoteDns by configurationStore.string(Key.REMOTE_DNS) { "https://dns.google/dns-query" }
|
||||
var directDns by configurationStore.string(Key.DIRECT_DNS) { "https://120.53.53.53/dns-query" }
|
||||
var directDns by configurationStore.string(Key.DIRECT_DNS) { "https://223.5.5.5/dns-query" }
|
||||
var enableDnsRouting by configurationStore.boolean(Key.ENABLE_DNS_ROUTING) { true }
|
||||
var enableFakeDns by configurationStore.boolean(Key.ENABLE_FAKEDNS)
|
||||
|
||||
@ -158,9 +169,6 @@ object DataStore : OnPreferenceDataStoreChangeListener {
|
||||
|
||||
// protocol
|
||||
|
||||
var muxType by configurationStore.stringToInt(Key.MUX_TYPE)
|
||||
var muxProtocols by configurationStore.stringSet(Key.MUX_PROTOCOLS)
|
||||
var muxConcurrency by configurationStore.stringToInt(Key.MUX_CONCURRENCY) { 8 }
|
||||
var globalAllowInsecure by configurationStore.boolean(Key.GLOBAL_ALLOW_INSECURE) { false }
|
||||
|
||||
// old cache, DO NOT ADD
|
||||
|
||||
@ -32,7 +32,9 @@ import io.nekohasekai.sagernet.fmt.wireguard.WireGuardBean
|
||||
import io.nekohasekai.sagernet.ktx.app
|
||||
import io.nekohasekai.sagernet.ktx.applyDefaultValues
|
||||
import io.nekohasekai.sagernet.ui.profile.*
|
||||
import moe.matsuri.nb4a.Protocols
|
||||
import moe.matsuri.nb4a.SingBoxOptions.MultiplexOptions
|
||||
import moe.matsuri.nb4a.proxy.anytls.AnyTLSBean
|
||||
import moe.matsuri.nb4a.proxy.anytls.AnyTLSSettingsActivity
|
||||
import moe.matsuri.nb4a.proxy.config.ConfigBean
|
||||
import moe.matsuri.nb4a.proxy.config.ConfigSettingActivity
|
||||
import moe.matsuri.nb4a.proxy.neko.*
|
||||
@ -65,6 +67,7 @@ data class ProxyEntity(
|
||||
var sshBean: SSHBean? = null,
|
||||
var wgBean: WireGuardBean? = null,
|
||||
var shadowTLSBean: ShadowTLSBean? = null,
|
||||
var anyTLSBean: AnyTLSBean? = null,
|
||||
var chainBean: ChainBean? = null,
|
||||
var nekoBean: NekoBean? = null,
|
||||
var configBean: ConfigBean? = null,
|
||||
@ -77,16 +80,16 @@ data class ProxyEntity(
|
||||
const val TYPE_VMESS = 4
|
||||
const val TYPE_TROJAN = 6
|
||||
|
||||
const val TYPE_TROJAN_GO = 7
|
||||
const val TYPE_MIERU = 21
|
||||
const val TYPE_NAIVE = 9
|
||||
const val TYPE_HYSTERIA = 15
|
||||
const val TYPE_TUIC = 20
|
||||
|
||||
const val TYPE_SSH = 17
|
||||
const val TYPE_WG = 18
|
||||
|
||||
const val TYPE_TROJAN_GO = 7
|
||||
const val TYPE_NAIVE = 9
|
||||
const val TYPE_HYSTERIA = 15
|
||||
const val TYPE_SHADOWTLS = 19
|
||||
const val TYPE_TUIC = 20
|
||||
const val TYPE_MIERU = 21
|
||||
const val TYPE_ANYTLS = 22
|
||||
|
||||
const val TYPE_CONFIG = 998
|
||||
const val TYPE_NEKO = 999
|
||||
@ -172,6 +175,7 @@ data class ProxyEntity(
|
||||
TYPE_WG -> wgBean = KryoConverters.wireguardDeserialize(byteArray)
|
||||
TYPE_TUIC -> tuicBean = KryoConverters.tuicDeserialize(byteArray)
|
||||
TYPE_SHADOWTLS -> shadowTLSBean = KryoConverters.shadowTLSDeserialize(byteArray)
|
||||
TYPE_ANYTLS -> anyTLSBean = KryoConverters.anyTLSDeserialize(byteArray)
|
||||
TYPE_CHAIN -> chainBean = KryoConverters.chainDeserialize(byteArray)
|
||||
TYPE_NEKO -> nekoBean = KryoConverters.nekoDeserialize(byteArray)
|
||||
TYPE_CONFIG -> configBean = KryoConverters.configDeserialize(byteArray)
|
||||
@ -192,6 +196,7 @@ data class ProxyEntity(
|
||||
TYPE_WG -> "WireGuard"
|
||||
TYPE_TUIC -> "TUIC"
|
||||
TYPE_SHADOWTLS -> "ShadowTLS"
|
||||
TYPE_ANYTLS -> "AnyTLS"
|
||||
TYPE_CHAIN -> chainName
|
||||
TYPE_NEKO -> nekoBean!!.displayType()
|
||||
TYPE_CONFIG -> configBean!!.displayType()
|
||||
@ -216,6 +221,7 @@ data class ProxyEntity(
|
||||
TYPE_WG -> wgBean
|
||||
TYPE_TUIC -> tuicBean
|
||||
TYPE_SHADOWTLS -> shadowTLSBean
|
||||
TYPE_ANYTLS -> anyTLSBean
|
||||
TYPE_CHAIN -> chainBean
|
||||
TYPE_NEKO -> nekoBean
|
||||
TYPE_CONFIG -> configBean
|
||||
@ -235,6 +241,7 @@ data class ProxyEntity(
|
||||
is SSHBean -> false
|
||||
is WireGuardBean -> false
|
||||
is ShadowTLSBean -> false
|
||||
is AnyTLSBean -> false
|
||||
is NekoBean -> nekoBean!!.haveStandardLink()
|
||||
is ConfigBean -> false
|
||||
else -> true
|
||||
@ -309,19 +316,31 @@ data class ProxyEntity(
|
||||
}
|
||||
}
|
||||
|
||||
fun needCoreMux(): Boolean {
|
||||
fun singMux(): MultiplexOptions? {
|
||||
return when (type) {
|
||||
TYPE_VMESS -> if (vmessBean!!.isVLESS) {
|
||||
Protocols.isProfileNeedMux(vmessBean!!) && Protocols.shouldEnableMux("vless")
|
||||
} else {
|
||||
Protocols.isProfileNeedMux(vmessBean!!) && Protocols.shouldEnableMux("vmess")
|
||||
TYPE_VMESS -> MultiplexOptions().apply {
|
||||
enabled = vmessBean!!.enableMux
|
||||
padding = vmessBean!!.muxPadding
|
||||
max_streams = vmessBean!!.muxConcurrency
|
||||
protocol = when (vmessBean!!.muxType) {
|
||||
1 -> "smux"
|
||||
2 -> "yamux"
|
||||
else -> "h2mux"
|
||||
}
|
||||
}
|
||||
|
||||
TYPE_TROJAN -> Protocols.isProfileNeedMux(trojanBean!!)
|
||||
&& Protocols.shouldEnableMux("trojan")
|
||||
TYPE_TROJAN -> MultiplexOptions().apply {
|
||||
enabled = trojanBean!!.enableMux
|
||||
padding = trojanBean!!.muxPadding
|
||||
max_streams = trojanBean!!.muxConcurrency
|
||||
protocol = when (trojanBean!!.muxType) {
|
||||
1 -> "smux"
|
||||
2 -> "yamux"
|
||||
else -> "h2mux"
|
||||
}
|
||||
}
|
||||
|
||||
TYPE_SS -> !ssBean!!.sUoT && Protocols.shouldEnableMux("shadowsocks")
|
||||
else -> false
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@ -339,6 +358,7 @@ data class ProxyEntity(
|
||||
wgBean = null
|
||||
tuicBean = null
|
||||
shadowTLSBean = null
|
||||
anyTLSBean = null
|
||||
chainBean = null
|
||||
configBean = null
|
||||
nekoBean = null
|
||||
@ -409,6 +429,11 @@ data class ProxyEntity(
|
||||
shadowTLSBean = bean
|
||||
}
|
||||
|
||||
is AnyTLSBean -> {
|
||||
type = TYPE_ANYTLS
|
||||
anyTLSBean = bean
|
||||
}
|
||||
|
||||
is ChainBean -> {
|
||||
type = TYPE_CHAIN
|
||||
chainBean = bean
|
||||
@ -445,6 +470,7 @@ data class ProxyEntity(
|
||||
TYPE_WG -> WireGuardSettingsActivity::class.java
|
||||
TYPE_TUIC -> TuicSettingsActivity::class.java
|
||||
TYPE_SHADOWTLS -> ShadowTLSSettingsActivity::class.java
|
||||
TYPE_ANYTLS -> AnyTLSSettingsActivity::class.java
|
||||
TYPE_CHAIN -> ChainSettingsActivity::class.java
|
||||
TYPE_NEKO -> NekoSettingActivity::class.java
|
||||
TYPE_CONFIG -> ConfigSettingActivity::class.java
|
||||
|
||||
@ -8,6 +8,7 @@ import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Entity(tableName = "rules")
|
||||
@Parcelize
|
||||
@TypeConverters(StringCollectionConverter::class)
|
||||
data class RuleEntity(
|
||||
@PrimaryKey(autoGenerate = true) var id: Long = 0L,
|
||||
var name: String = "",
|
||||
@ -21,7 +22,7 @@ data class RuleEntity(
|
||||
var source: String = "",
|
||||
var protocol: String = "",
|
||||
var outbound: Long = 0,
|
||||
var packages: List<String> = listOf(),
|
||||
var packages: Set<String> = emptySet(),
|
||||
) : Parcelable {
|
||||
|
||||
fun displayName(): String {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package io.nekohasekai.sagernet.database
|
||||
|
||||
import androidx.room.AutoMigration
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
@ -15,7 +16,11 @@ import kotlinx.coroutines.launch
|
||||
|
||||
@Database(
|
||||
entities = [ProxyGroup::class, ProxyEntity::class, RuleEntity::class],
|
||||
version = 3
|
||||
version = 5,
|
||||
autoMigrations = [
|
||||
AutoMigration(from = 3, to = 4),
|
||||
AutoMigration(from = 4, to = 5)
|
||||
]
|
||||
)
|
||||
@TypeConverters(value = [KryoConverters::class, GsonConverters::class])
|
||||
@GenerateRoomMigrations
|
||||
@ -27,7 +32,7 @@ abstract class SagerDatabase : RoomDatabase() {
|
||||
val instance by lazy {
|
||||
SagerNet.application.getDatabasePath(Key.DB_PROFILE).parentFile?.mkdirs()
|
||||
Room.databaseBuilder(SagerNet.application, SagerDatabase::class.java, Key.DB_PROFILE)
|
||||
.addMigrations(*SagerDatabase_Migrations.build())
|
||||
// .addMigrations(*SagerDatabase_Migrations.build())
|
||||
.allowMainThreadQueries()
|
||||
.enableMultiInstanceInvalidation()
|
||||
.fallbackToDestructiveMigration()
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
package io.nekohasekai.sagernet.database
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
|
||||
class StringCollectionConverter {
|
||||
companion object {
|
||||
const val SPLIT_FLAG = ","
|
||||
|
||||
/*
|
||||
@TypeConverter
|
||||
@JvmStatic
|
||||
fun fromList(list: List<String>): String = if (list.isEmpty()) {
|
||||
""
|
||||
} else {
|
||||
list.joinToString(SPLIT_FLAG)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
@JvmStatic
|
||||
fun toList(str: String): List<String> = if (str.isBlank()) {
|
||||
emptyList()
|
||||
} else {
|
||||
str.split(SPLIT_FLAG)
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
@TypeConverter
|
||||
@JvmStatic
|
||||
fun fromSet(set: Set<String>): String = if (set.isEmpty()) {
|
||||
""
|
||||
} else {
|
||||
set.joinToString(SPLIT_FLAG)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
@JvmStatic
|
||||
fun toSet(str: String): Set<String> = if (str.isBlank()) {
|
||||
emptySet()
|
||||
} else {
|
||||
str.split(",").toSet()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,7 @@
|
||||
package io.nekohasekai.sagernet.fmt
|
||||
|
||||
import android.widget.Toast
|
||||
import io.nekohasekai.sagernet.IPv6Mode
|
||||
import io.nekohasekai.sagernet.Key
|
||||
import io.nekohasekai.sagernet.R
|
||||
import io.nekohasekai.sagernet.SagerNet
|
||||
import io.nekohasekai.sagernet.TunImplementation
|
||||
import io.nekohasekai.sagernet.*
|
||||
import io.nekohasekai.sagernet.bg.VpnService
|
||||
import io.nekohasekai.sagernet.database.DataStore
|
||||
import io.nekohasekai.sagernet.database.ProxyEntity
|
||||
@ -27,39 +23,21 @@ import io.nekohasekai.sagernet.fmt.v2ray.StandardV2RayBean
|
||||
import io.nekohasekai.sagernet.fmt.v2ray.buildSingBoxOutboundStandardV2RayBean
|
||||
import io.nekohasekai.sagernet.fmt.wireguard.WireGuardBean
|
||||
import io.nekohasekai.sagernet.fmt.wireguard.buildSingBoxOutboundWireguardBean
|
||||
import io.nekohasekai.sagernet.ktx.isIpAddress
|
||||
import io.nekohasekai.sagernet.ktx.mkPort
|
||||
import io.nekohasekai.sagernet.utils.PackageCache
|
||||
import moe.matsuri.nb4a.Protocols
|
||||
import moe.matsuri.nb4a.SingBoxOptions.CacheFile
|
||||
import moe.matsuri.nb4a.SingBoxOptions.ClashAPIOptions
|
||||
import moe.matsuri.nb4a.SingBoxOptions.DNSFakeIPOptions
|
||||
import moe.matsuri.nb4a.SingBoxOptions.DNSOptions
|
||||
import moe.matsuri.nb4a.SingBoxOptions.DNSRule_DefaultOptions
|
||||
import moe.matsuri.nb4a.SingBoxOptions.DNSServerOptions
|
||||
import moe.matsuri.nb4a.SingBoxOptions.ExperimentalOptions
|
||||
import moe.matsuri.nb4a.SingBoxOptions.Inbound_DirectOptions
|
||||
import moe.matsuri.nb4a.SingBoxOptions.Inbound_MixedOptions
|
||||
import moe.matsuri.nb4a.SingBoxOptions.Inbound_TunOptions
|
||||
import moe.matsuri.nb4a.SingBoxOptions.LogOptions
|
||||
import moe.matsuri.nb4a.SingBoxOptions.MultiplexOptions
|
||||
import moe.matsuri.nb4a.SingBoxOptions.MyOptions
|
||||
import moe.matsuri.nb4a.SingBoxOptions.Outbound
|
||||
import moe.matsuri.nb4a.SingBoxOptions.Outbound_SelectorOptions
|
||||
import moe.matsuri.nb4a.SingBoxOptions.Outbound_SocksOptions
|
||||
import moe.matsuri.nb4a.SingBoxOptions.RouteOptions
|
||||
import moe.matsuri.nb4a.SingBoxOptions.RuleSet
|
||||
import moe.matsuri.nb4a.SingBoxOptions.Rule_DefaultOptions
|
||||
import moe.matsuri.nb4a.SingBoxOptionsUtil
|
||||
import moe.matsuri.nb4a.checkEmpty
|
||||
import moe.matsuri.nb4a.generateRuleSet
|
||||
import moe.matsuri.nb4a.makeSingBoxRule
|
||||
import moe.matsuri.nb4a.*
|
||||
import moe.matsuri.nb4a.SingBoxOptions.*
|
||||
import moe.matsuri.nb4a.plugin.Plugins
|
||||
import moe.matsuri.nb4a.proxy.anytls.AnyTLSBean
|
||||
import moe.matsuri.nb4a.proxy.anytls.buildSingBoxOutboundAnyTLSBean
|
||||
import moe.matsuri.nb4a.proxy.config.ConfigBean
|
||||
import moe.matsuri.nb4a.proxy.shadowtls.ShadowTLSBean
|
||||
import moe.matsuri.nb4a.proxy.shadowtls.buildSingBoxOutboundShadowTLSBean
|
||||
import moe.matsuri.nb4a.utils.JavaUtil.gson
|
||||
import moe.matsuri.nb4a.utils.Util
|
||||
import moe.matsuri.nb4a.utils.listByLineOrComma
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
|
||||
const val TAG_MIXED = "mixed-in"
|
||||
|
||||
@ -156,6 +134,7 @@ fun buildConfig(
|
||||
}.toHashSet().toList()).associateBy { it.id }
|
||||
val buildSelector = !forTest && group?.isSelector == true && !forExport
|
||||
val userDNSRuleList = mutableListOf<DNSRule_DefaultOptions>()
|
||||
val domainListDNSDirectForce = mutableListOf<String>()
|
||||
val bypassDNSBeans = hashSetOf<AbstractBean>()
|
||||
val isVPN = DataStore.serviceMode == Key.MODE_VPN
|
||||
val bind = if (!forTest && DataStore.allowAccess) "0.0.0.0" else LOCALHOST
|
||||
@ -398,6 +377,9 @@ fun buildConfig(
|
||||
is SSHBean ->
|
||||
buildSingBoxOutboundSSHBean(bean).asMap()
|
||||
|
||||
is AnyTLSBean ->
|
||||
buildSingBoxOutboundAnyTLSBean(bean).asMap()
|
||||
|
||||
else -> throw IllegalStateException("can't reach")
|
||||
}
|
||||
|
||||
@ -406,18 +388,12 @@ fun buildConfig(
|
||||
// val keepAliveInterval = DataStore.tcpKeepAliveInterval
|
||||
// val needKeepAliveInterval = keepAliveInterval !in intArrayOf(0, 15)
|
||||
|
||||
if (!muxApplied && proxyEntity.needCoreMux()) {
|
||||
muxApplied = true
|
||||
currentOutbound["multiplex"] = MultiplexOptions().apply {
|
||||
enabled = true
|
||||
padding = Protocols.shouldEnableMux("padding")
|
||||
max_streams = DataStore.muxConcurrency
|
||||
protocol = when (DataStore.muxType) {
|
||||
1 -> "smux"
|
||||
2 -> "yamux"
|
||||
else -> "h2mux"
|
||||
}
|
||||
}.asMap()
|
||||
if (!muxApplied) {
|
||||
val muxObj = proxyEntity.singMux()
|
||||
if (muxObj != null && muxObj.enabled) {
|
||||
muxApplied = true
|
||||
currentOutbound["multiplex"] = muxObj.asMap()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -434,7 +410,12 @@ fun buildConfig(
|
||||
}
|
||||
|
||||
// domain_strategy
|
||||
|
||||
pastEntity?.requireBean()?.apply {
|
||||
// don't loopback
|
||||
if (defaultServerDomainStrategy != "" && !serverAddress.isIpAddress()) {
|
||||
domainListDNSDirectForce.add("full:$serverAddress")
|
||||
}
|
||||
}
|
||||
currentOutbound["domain_strategy"] =
|
||||
if (forTest) "" else defaultServerDomainStrategy
|
||||
|
||||
@ -667,6 +648,35 @@ fun buildConfig(
|
||||
}.asMap())
|
||||
}
|
||||
|
||||
// Bypass Lookup for the first profile
|
||||
bypassDNSBeans.forEach {
|
||||
var serverAddr = it.serverAddress
|
||||
|
||||
if (it is ConfigBean) {
|
||||
var config = mutableMapOf<String, Any>()
|
||||
config = gson.fromJson(it.config, config.javaClass)
|
||||
config["server"]?.apply {
|
||||
serverAddr = toString()
|
||||
}
|
||||
}
|
||||
|
||||
if (!serverAddr.isIpAddress()) {
|
||||
domainListDNSDirectForce.add("full:${serverAddr}")
|
||||
}
|
||||
}
|
||||
|
||||
remoteDns.forEach {
|
||||
var address = it
|
||||
if (address.contains("://")) {
|
||||
address = address.substringAfter("://")
|
||||
}
|
||||
"https://$address".toHttpUrlOrNull()?.apply {
|
||||
if (!host.isIpAddress()) {
|
||||
domainListDNSDirectForce.add("full:$host")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remote dns obj
|
||||
remoteDns.firstOrNull().let {
|
||||
dns.servers.add(DNSServerOptions().apply {
|
||||
@ -748,11 +758,18 @@ fun buildConfig(
|
||||
disable_cache = true
|
||||
})
|
||||
}
|
||||
// avoid loopback (always top DNS rule)
|
||||
// avoid loopback
|
||||
dns.rules.add(0, DNSRule_DefaultOptions().apply {
|
||||
outbound = mutableListOf("any")
|
||||
server = "dns-direct"
|
||||
})
|
||||
// force bypass (always top DNS rule)
|
||||
if (domainListDNSDirectForce.isNotEmpty()) {
|
||||
dns.rules.add(0, DNSRule_DefaultOptions().apply {
|
||||
makeSingBoxRule(domainListDNSDirectForce.toHashSet().toList())
|
||||
server = "dns-direct"
|
||||
})
|
||||
}
|
||||
}
|
||||
}.let {
|
||||
ConfigBuildResult(
|
||||
|
||||
@ -16,6 +16,7 @@ import io.nekohasekai.sagernet.fmt.internal.ChainBean;
|
||||
import io.nekohasekai.sagernet.fmt.mieru.MieruBean;
|
||||
import io.nekohasekai.sagernet.fmt.naive.NaiveBean;
|
||||
import io.nekohasekai.sagernet.fmt.shadowsocks.ShadowsocksBean;
|
||||
import moe.matsuri.nb4a.proxy.anytls.AnyTLSBean;
|
||||
import moe.matsuri.nb4a.proxy.shadowtls.ShadowTLSBean;
|
||||
import io.nekohasekai.sagernet.fmt.socks.SOCKSBean;
|
||||
import io.nekohasekai.sagernet.fmt.ssh.SSHBean;
|
||||
@ -142,6 +143,13 @@ public class KryoConverters {
|
||||
return deserialize(new ShadowTLSBean(), bytes);
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
public static AnyTLSBean anyTLSDeserialize(byte[] bytes) {
|
||||
if (JavaUtil.isEmpty(bytes)) return null;
|
||||
return deserialize(new AnyTLSBean(), bytes);
|
||||
}
|
||||
|
||||
|
||||
@TypeConverter
|
||||
public static ChainBean chainDeserialize(byte[] bytes) {
|
||||
if (JavaUtil.isEmpty(bytes)) return null;
|
||||
|
||||
@ -16,6 +16,7 @@ object TypeMap : HashMap<String, Int>() {
|
||||
this["ssh"] = ProxyEntity.TYPE_SSH
|
||||
this["wg"] = ProxyEntity.TYPE_WG
|
||||
this["tuic"] = ProxyEntity.TYPE_TUIC
|
||||
this["anytls"] = ProxyEntity.TYPE_ANYTLS
|
||||
this["neko"] = ProxyEntity.TYPE_NEKO
|
||||
this["config"] = ProxyEntity.TYPE_CONFIG
|
||||
}
|
||||
|
||||
@ -95,9 +95,9 @@ fun parseHysteria2(url: String): HysteriaBean {
|
||||
link.queryParameter("obfs-password")?.also {
|
||||
obfuscation = it
|
||||
}
|
||||
link.queryParameter("pinSHA256")?.also {
|
||||
// TODO your box do not support it
|
||||
}
|
||||
// link.queryParameter("pinSHA256")?.also {
|
||||
// // TODO your box do not support it
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@ -284,9 +284,9 @@ fun buildSingBoxOutboundHysteriaBean(bean: HysteriaBean): MutableMap<String, Any
|
||||
if (port != null) {
|
||||
server_port = port
|
||||
} else {
|
||||
hop_ports = bean.serverPorts
|
||||
server_ports = bean.serverPorts
|
||||
}
|
||||
hop_interval = bean.hopInterval
|
||||
hop_interval = "${bean.hopInterval}s"
|
||||
up_mbps = bean.uploadMbps
|
||||
down_mbps = bean.downloadMbps
|
||||
obfs = bean.obfuscation
|
||||
@ -323,9 +323,9 @@ fun buildSingBoxOutboundHysteriaBean(bean: HysteriaBean): MutableMap<String, Any
|
||||
if (port != null) {
|
||||
server_port = port
|
||||
} else {
|
||||
hop_ports = bean.serverPorts
|
||||
server_ports = bean.serverPorts
|
||||
}
|
||||
hop_interval = bean.hopInterval
|
||||
hop_interval = "${bean.hopInterval}s"
|
||||
up_mbps = bean.uploadMbps
|
||||
down_mbps = bean.downloadMbps
|
||||
if (bean.obfuscation.isNotBlank()) {
|
||||
|
||||
@ -92,10 +92,10 @@ fun TrojanGoBean.buildTrojanGoConfig(port: Int): String {
|
||||
put(password)
|
||||
})
|
||||
put("log_level", if (DataStore.logLevel > 0) 0 else 2)
|
||||
if (Protocols.shouldEnableMux("trojan-go")) put("mux", JSONObject().apply {
|
||||
put("enabled", true)
|
||||
put("concurrency", DataStore.muxConcurrency)
|
||||
})
|
||||
// if (Protocols.shouldEnableMux("trojan-go")) put("mux", JSONObject().apply {
|
||||
// put("enabled", true)
|
||||
// put("concurrency", DataStore.muxConcurrency)
|
||||
// })
|
||||
put("tcp", JSONObject().apply {
|
||||
put("prefer_ipv4", DataStore.ipv6Mode <= IPv6Mode.ENABLE)
|
||||
})
|
||||
|
||||
@ -52,11 +52,20 @@ public abstract class StandardV2RayBean extends AbstractBean {
|
||||
|
||||
public Boolean enableECH;
|
||||
|
||||
public String echConfig;
|
||||
|
||||
// sing-box 不再使用
|
||||
public Boolean enablePqSignature;
|
||||
|
||||
public Boolean disabledDRS;
|
||||
|
||||
public String echConfig;
|
||||
// --------------------------------------- Mux
|
||||
|
||||
public Boolean enableMux;
|
||||
public Boolean muxPadding;
|
||||
public Integer muxType;
|
||||
public Integer muxConcurrency;
|
||||
|
||||
|
||||
// --------------------------------------- //
|
||||
|
||||
@ -101,11 +110,16 @@ public abstract class StandardV2RayBean extends AbstractBean {
|
||||
if (JavaUtil.isNullOrBlank(echConfig)) echConfig = "";
|
||||
if (enablePqSignature == null) enablePqSignature = false;
|
||||
if (disabledDRS == null) disabledDRS = false;
|
||||
|
||||
if (enableMux == null) enableMux = false;
|
||||
if (muxPadding == null) muxPadding = false;
|
||||
if (muxType == null) muxType = 0;
|
||||
if (muxConcurrency == null) muxConcurrency = 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(ByteBufferOutput output) {
|
||||
output.writeInt(1);
|
||||
output.writeInt(2);
|
||||
super.serialize(output);
|
||||
output.writeString(uuid);
|
||||
output.writeString(encryption);
|
||||
@ -160,6 +174,11 @@ public abstract class StandardV2RayBean extends AbstractBean {
|
||||
}
|
||||
|
||||
output.writeInt(packetEncoding);
|
||||
|
||||
output.writeBoolean(enableMux);
|
||||
output.writeBoolean(muxPadding);
|
||||
output.writeInt(muxType);
|
||||
output.writeInt(muxConcurrency);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -239,6 +258,13 @@ public abstract class StandardV2RayBean extends AbstractBean {
|
||||
}
|
||||
|
||||
packetEncoding = input.readInt();
|
||||
|
||||
if (version >= 2) {
|
||||
enableMux = input.readBoolean();
|
||||
muxPadding = input.readBoolean();
|
||||
muxType = input.readInt();
|
||||
muxConcurrency = input.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -251,6 +277,10 @@ public abstract class StandardV2RayBean extends AbstractBean {
|
||||
bean.enableECH = enableECH;
|
||||
bean.disabledDRS = disabledDRS;
|
||||
bean.echConfig = echConfig;
|
||||
bean.enableMux = enableMux;
|
||||
bean.muxPadding = muxPadding;
|
||||
bean.muxType = muxType;
|
||||
bean.muxConcurrency = muxConcurrency;
|
||||
}
|
||||
|
||||
public boolean isVLESS() {
|
||||
|
||||
@ -622,8 +622,6 @@ fun buildSingBoxOutboundTLS(bean: StandardV2RayBean): OutboundTLSOptions? {
|
||||
if (bean.enableECH) {
|
||||
ech = OutboundECHOptions().apply {
|
||||
enabled = true
|
||||
pq_signature_schemes_enabled = bean.enablePqSignature
|
||||
dynamic_record_sizing_disabled = bean.disabledDRS
|
||||
if (bean.echConfig.isNotBlank()) {
|
||||
config = bean.echConfig.lines()
|
||||
}
|
||||
|
||||
@ -22,7 +22,9 @@ import io.nekohasekai.sagernet.fmt.wireguard.WireGuardBean
|
||||
import io.nekohasekai.sagernet.ktx.*
|
||||
import libcore.Libcore
|
||||
import moe.matsuri.nb4a.Protocols
|
||||
import moe.matsuri.nb4a.proxy.anytls.AnyTLSBean
|
||||
import moe.matsuri.nb4a.proxy.config.ConfigBean
|
||||
import moe.matsuri.nb4a.utils.Util
|
||||
import org.ini4j.Ini
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
@ -66,10 +68,11 @@ object RawUpdater : GroupUpdater() {
|
||||
setURL(subscription.link)
|
||||
setUserAgent(subscription.customUserAgent.takeIf { it.isNotBlank() } ?: USER_AGENT)
|
||||
}.execute()
|
||||
proxies = parseRaw(response.contentString)
|
||||
proxies = parseRaw(Util.getStringBox(response.contentString))
|
||||
?: error(app.getString(R.string.no_proxies_found))
|
||||
|
||||
subscription.subscriptionUserinfo = response.getHeader("Subscription-Userinfo")
|
||||
subscription.subscriptionUserinfo =
|
||||
Util.getStringBox(response.getHeader("Subscription-Userinfo"))
|
||||
}
|
||||
|
||||
val proxiesMap = LinkedHashMap<String, AbstractBean>()
|
||||
@ -247,6 +250,7 @@ object RawUpdater : GroupUpdater() {
|
||||
setTLS(proxy["tls"]?.toString() == "true")
|
||||
sni = proxy["sni"]?.toString()
|
||||
name = proxy["name"]?.toString()
|
||||
allowInsecure = proxy["name"]?.toString() == "true"
|
||||
})
|
||||
}
|
||||
|
||||
@ -414,6 +418,20 @@ object RawUpdater : GroupUpdater() {
|
||||
realityOpt.value.toString()
|
||||
}
|
||||
}
|
||||
|
||||
"smux" -> for (smuxOpt in (opt.value as Map<String, Any>)) {
|
||||
when (smuxOpt.key.lowercase()) {
|
||||
"enabled" -> bean.enableMux =
|
||||
smuxOpt.value.toString() == "true"
|
||||
|
||||
"max-streams" -> bean.muxConcurrency =
|
||||
smuxOpt.value.toString().toInt()
|
||||
|
||||
"padding" -> bean.muxPadding =
|
||||
smuxOpt.value.toString() == "true"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (isHttpUpgrade) {
|
||||
@ -473,6 +491,19 @@ object RawUpdater : GroupUpdater() {
|
||||
grpcOpt.value.toString()
|
||||
}
|
||||
}
|
||||
|
||||
"smux" -> for (smuxOpt in (opt.value as Map<String, Any>)) {
|
||||
when (smuxOpt.key.lowercase()) {
|
||||
"enabled" -> bean.enableMux =
|
||||
smuxOpt.value.toString() == "true"
|
||||
|
||||
"max-streams" -> bean.muxConcurrency =
|
||||
smuxOpt.value.toString().toInt()
|
||||
|
||||
"padding" -> bean.muxPadding =
|
||||
smuxOpt.value.toString() == "true"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isHttpUpgrade) {
|
||||
@ -481,6 +512,31 @@ object RawUpdater : GroupUpdater() {
|
||||
proxies.add(bean)
|
||||
}
|
||||
|
||||
"anytls" -> {
|
||||
val bean = AnyTLSBean()
|
||||
for (opt in proxy) {
|
||||
if (opt.value == null) continue
|
||||
when (opt.key.replace("_", "-")) {
|
||||
"name" -> bean.name = opt.value.toString()
|
||||
"server" -> bean.serverAddress = opt.value as String
|
||||
"port" -> bean.serverPort = opt.value.toString().toInt()
|
||||
"password" -> bean.password = opt.value.toString()
|
||||
"client-fingerprint" -> bean.utlsFingerprint =
|
||||
opt.value as String
|
||||
|
||||
"sni" -> bean.sni = opt.value.toString()
|
||||
"skip-cert-verify" -> bean.allowInsecure =
|
||||
opt.value.toString() == "true"
|
||||
|
||||
"alpn" -> {
|
||||
val alpn = (opt.value as? (List<String>))
|
||||
bean.alpn = alpn?.joinToString("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
proxies.add(bean)
|
||||
}
|
||||
|
||||
"hysteria" -> {
|
||||
val bean = HysteriaBean()
|
||||
bean.protocolVersion = 1
|
||||
@ -731,9 +787,25 @@ object RawUpdater : GroupUpdater() {
|
||||
}
|
||||
|
||||
json.has("outbounds") -> {
|
||||
return listOf(ConfigBean().applyDefaultValues().apply {
|
||||
config = json.toStringPretty()
|
||||
})
|
||||
return json.getJSONArray("outbounds")
|
||||
.filterIsInstance<JSONObject>()
|
||||
.mapNotNull {
|
||||
val ty = it.getStr("type")
|
||||
if (ty == null || ty == "" ||
|
||||
ty == "dns" || ty == "block" || ty == "direct" || ty == "selector" || ty == "urltest"
|
||||
) {
|
||||
null
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}.map {
|
||||
ConfigBean().apply {
|
||||
applyDefaultValues()
|
||||
type = 1
|
||||
config = it.toStringPretty()
|
||||
name = it.getStr("tag")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
json.has("server") && json.has("server_port") -> {
|
||||
|
||||
@ -5,8 +5,11 @@ package io.nekohasekai.sagernet.ktx
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.*
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.res.Resources
|
||||
import android.os.Build
|
||||
import android.system.Os
|
||||
@ -33,10 +36,17 @@ import io.nekohasekai.sagernet.database.SagerDatabase
|
||||
import io.nekohasekai.sagernet.database.preference.PublicDatabase
|
||||
import io.nekohasekai.sagernet.ui.MainActivity
|
||||
import io.nekohasekai.sagernet.ui.ThemedActivity
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import moe.matsuri.nb4a.utils.NGUtil
|
||||
import java.io.FileDescriptor
|
||||
import java.net.*
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.InetAddress
|
||||
import java.net.Socket
|
||||
import java.net.URLEncoder
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
@ -48,6 +58,7 @@ import kotlin.reflect.KMutableProperty0
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KProperty0
|
||||
|
||||
fun String?.blankAsNull(): String? = if (isNullOrBlank()) null else this
|
||||
|
||||
inline fun <T> Iterable<T>.forEachTry(action: (T) -> Unit) {
|
||||
var result: Exception? = null
|
||||
@ -113,9 +124,6 @@ fun Context.listenForPackageChanges(onetime: Boolean = true, callback: () -> Uni
|
||||
})
|
||||
}
|
||||
|
||||
val PackageInfo.signaturesCompat
|
||||
get() = if (Build.VERSION.SDK_INT >= 28) signingInfo.apkContentsSigners else @Suppress("DEPRECATION") signatures
|
||||
|
||||
/**
|
||||
* Based on: https://stackoverflow.com/a/26348729/2245107
|
||||
*/
|
||||
|
||||
@ -107,7 +107,7 @@ class AboutFragment : ToolbarFragment(R.layout.layout_about) {
|
||||
PackageCache.awaitLoadSync()
|
||||
for ((_, pkg) in PackageCache.installedPluginPackages) {
|
||||
try {
|
||||
val pluginId = pkg.providers[0].loadString(Plugins.METADATA_KEY_ID)
|
||||
val pluginId = pkg.providers?.get(0)?.loadString(Plugins.METADATA_KEY_ID)
|
||||
if (pluginId.isNullOrBlank() || pluginId.startsWith(Plugins.AUTHORITIES_PREFIX_NEKO_PLUGIN)) continue
|
||||
addItem(MaterialAboutActionItem.Builder()
|
||||
.icon(R.drawable.ic_baseline_nfc_24)
|
||||
|
||||
@ -139,9 +139,9 @@ class AppListActivity : ThemedActivity() {
|
||||
var filteredApps = apps
|
||||
|
||||
suspend fun reload() {
|
||||
apps = getCachedApps().map { (packageName, packageInfo) ->
|
||||
apps = getCachedApps().mapNotNull { (packageName, packageInfo) ->
|
||||
coroutineContext[Job]!!.ensureActive()
|
||||
ProxiedApp(packageManager, packageInfo.applicationInfo, packageName)
|
||||
packageInfo.applicationInfo?.let { ProxiedApp(packageManager, it, packageName) }
|
||||
}.sortedWith(compareBy({ !isProxiedApp(it) }, { it.name.toString() }))
|
||||
}
|
||||
|
||||
@ -200,8 +200,11 @@ class AppListActivity : ThemedActivity() {
|
||||
private fun initProxiedUids(str: String = DataStore.routePackages) {
|
||||
proxiedUids.clear()
|
||||
val apps = getCachedApps()
|
||||
for (line in str.lineSequence()) proxiedUids[(apps[line]
|
||||
?: continue).applicationInfo.uid] = true
|
||||
for (line in str.lineSequence()) {
|
||||
val app = (apps[line] ?: continue)
|
||||
val uid = app.applicationInfo?.uid ?: continue
|
||||
proxiedUids[uid] = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun isProxiedApp(app: ProxiedApp) = proxiedUids[app.uid]
|
||||
@ -306,6 +309,7 @@ class AppListActivity : ThemedActivity() {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.action_clear_selections -> {
|
||||
runOnDefaultDispatcher {
|
||||
proxiedUids.clear()
|
||||
@ -316,6 +320,7 @@ class AppListActivity : ThemedActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
R.id.action_export_clipboard -> {
|
||||
val success = SagerNet.trySetPrimaryClip("false\n${DataStore.routePackages}")
|
||||
Snackbar.make(
|
||||
@ -325,6 +330,7 @@ class AppListActivity : ThemedActivity() {
|
||||
).show()
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.action_import_clipboard -> {
|
||||
val proxiedAppString =
|
||||
SagerNet.clipboard.primaryClip?.getItemAt(0)?.text?.toString()
|
||||
@ -344,6 +350,7 @@ class AppListActivity : ThemedActivity() {
|
||||
}
|
||||
Snackbar.make(binding.list, R.string.action_import_err, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
R.id.uninstall_all -> {
|
||||
runOnDefaultDispatcher {
|
||||
proxiedUids.clear()
|
||||
|
||||
@ -103,9 +103,9 @@ class AppManagerActivity : ThemedActivity() {
|
||||
var filteredApps = apps
|
||||
|
||||
suspend fun reload() {
|
||||
apps = cachedApps.map { (packageName, packageInfo) ->
|
||||
apps = cachedApps.mapNotNull { (packageName, packageInfo) ->
|
||||
coroutineContext[Job]!!.ensureActive()
|
||||
ProxiedApp(packageManager, packageInfo.applicationInfo, packageName)
|
||||
packageInfo.applicationInfo?.let { ProxiedApp(packageManager, it, packageName) }
|
||||
}.sortedWith(compareBy({ !isProxiedApp(it) }, { it.name.toString() }))
|
||||
}
|
||||
|
||||
@ -164,8 +164,11 @@ class AppManagerActivity : ThemedActivity() {
|
||||
private fun initProxiedUids(str: String = DataStore.individual) {
|
||||
proxiedUids.clear()
|
||||
val apps = cachedApps
|
||||
for (line in str.lineSequence()) proxiedUids[(apps[line]
|
||||
?: continue).applicationInfo.uid] = true
|
||||
for (line in str.lineSequence()) {
|
||||
val app = (apps[line] ?: continue)
|
||||
val uid = app.applicationInfo?.uid ?: continue
|
||||
proxiedUids[uid] = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun isProxiedApp(app: ProxiedApp) = proxiedUids[app.uid]
|
||||
@ -325,14 +328,19 @@ class AppManagerActivity : ThemedActivity() {
|
||||
proxiedUids.clear()
|
||||
for (app in cachedApps) {
|
||||
val needProxy =
|
||||
needProxyAppsList.contains(app.key) || app.value.applicationInfo.uid == 1000
|
||||
needProxyAppsList.contains(app.key) || (app.value.applicationInfo?.uid
|
||||
?: 0) == 1000
|
||||
if (needProxy) {
|
||||
if (!bypass) {
|
||||
proxiedUids[app.value.applicationInfo.uid] = true
|
||||
app.value.applicationInfo?.apply {
|
||||
proxiedUids[uid] = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (bypass) {
|
||||
proxiedUids[app.value.applicationInfo.uid] = true
|
||||
app.value.applicationInfo?.apply {
|
||||
proxiedUids[uid] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ import io.nekohasekai.sagernet.databinding.LayoutAssetsBinding
|
||||
import io.nekohasekai.sagernet.ktx.*
|
||||
import io.nekohasekai.sagernet.widget.UndoSnackbarManager
|
||||
import libcore.Libcore
|
||||
import moe.matsuri.nb4a.utils.Util
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
import java.io.FileWriter
|
||||
@ -283,7 +284,7 @@ class AssetsActivity : ThemedActivity() {
|
||||
setURL("https://api.github.com/repos/$repo/releases/latest")
|
||||
}.execute()
|
||||
|
||||
val release = JSONObject(response.contentString)
|
||||
val release = JSONObject(Util.getStringBox(response.contentString))
|
||||
val tagName = release.optString("tag_name")
|
||||
|
||||
if (tagName == localVersion) {
|
||||
|
||||
@ -57,6 +57,7 @@ import kotlinx.coroutines.sync.withLock
|
||||
import moe.matsuri.nb4a.Protocols
|
||||
import moe.matsuri.nb4a.Protocols.getProtocolColor
|
||||
import moe.matsuri.nb4a.plugin.NekoPluginManager
|
||||
import moe.matsuri.nb4a.proxy.anytls.AnyTLSSettingsActivity
|
||||
import moe.matsuri.nb4a.proxy.config.ConfigSettingActivity
|
||||
import moe.matsuri.nb4a.proxy.neko.NekoJSInterface
|
||||
import moe.matsuri.nb4a.proxy.neko.NekoSettingActivity
|
||||
@ -148,7 +149,7 @@ class ConfigurationFragment @JvmOverloads constructor(
|
||||
searchView.setOnQueryTextListener(this)
|
||||
searchView.maxWidth = Int.MAX_VALUE
|
||||
|
||||
searchView.setOnQueryTextFocusChangeListener { _, hasFocus ->
|
||||
searchView.setOnQueryTextFocusChangeListener { _, hasFocus ->
|
||||
if (!hasFocus) {
|
||||
cancelSearch(searchView)
|
||||
}
|
||||
@ -390,6 +391,10 @@ class ConfigurationFragment @JvmOverloads constructor(
|
||||
startActivity(Intent(requireActivity(), ShadowTLSSettingsActivity::class.java))
|
||||
}
|
||||
|
||||
R.id.action_new_anytls -> {
|
||||
startActivity(Intent(requireActivity(), AnyTLSSettingsActivity::class.java))
|
||||
}
|
||||
|
||||
R.id.action_new_config -> {
|
||||
startActivity(Intent(requireActivity(), ConfigSettingActivity::class.java))
|
||||
}
|
||||
@ -1711,9 +1716,9 @@ class ConfigurationFragment @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun cancelSearch(searchView: SearchView) {
|
||||
searchView.onActionViewCollapsed()
|
||||
searchView.clearFocus()
|
||||
}
|
||||
private fun cancelSearch(searchView: SearchView) {
|
||||
searchView.onActionViewCollapsed()
|
||||
searchView.clearFocus()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ class RouteSettingsActivity(
|
||||
fun init(packageName: String?) {
|
||||
RuleEntity().apply {
|
||||
if (!packageName.isNullOrBlank()) {
|
||||
packages = listOf(packageName)
|
||||
packages = setOf(packageName)
|
||||
name = app.getString(R.string.route_for, PackageCache.loadLabel(packageName))
|
||||
}
|
||||
}.init()
|
||||
@ -89,7 +89,7 @@ class RouteSettingsActivity(
|
||||
2 -> -2L
|
||||
else -> DataStore.routeOutboundRule
|
||||
}
|
||||
packages = DataStore.routePackages.split("\n").filter { it.isNotBlank() }
|
||||
packages = DataStore.routePackages.split("\n").filter { it.isNotBlank() }.toSet()
|
||||
|
||||
if (DataStore.editingId == 0L) {
|
||||
enabled = true
|
||||
|
||||
@ -17,7 +17,6 @@ import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers
|
||||
import io.nekohasekai.sagernet.ktx.*
|
||||
import io.nekohasekai.sagernet.utils.Theme
|
||||
import io.nekohasekai.sagernet.widget.AppListPreference
|
||||
import moe.matsuri.nb4a.Protocols
|
||||
import moe.matsuri.nb4a.ui.*
|
||||
|
||||
class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
||||
@ -81,7 +80,6 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
||||
val ipv6Mode = findPreference<Preference>(Key.IPV6_MODE)!!
|
||||
val trafficSniffing = findPreference<Preference>(Key.TRAFFIC_SNIFFING)!!
|
||||
|
||||
val muxConcurrency = findPreference<EditTextPreference>(Key.MUX_CONCURRENCY)!!
|
||||
val tcpKeepAliveInterval = findPreference<EditTextPreference>(Key.TCP_KEEP_ALIVE_INTERVAL)!!
|
||||
tcpKeepAliveInterval.isVisible = false
|
||||
|
||||
@ -123,16 +121,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
||||
true
|
||||
}
|
||||
|
||||
val muxProtocols = findPreference<MultiSelectListPreference>(Key.MUX_PROTOCOLS)!!
|
||||
|
||||
muxProtocols.apply {
|
||||
val e = Protocols.getCanMuxList().toTypedArray()
|
||||
entries = e
|
||||
entryValues = e
|
||||
}
|
||||
|
||||
portLocalDns.setOnBindEditTextListener(EditTextPreferenceModifiers.Port)
|
||||
muxConcurrency.setOnBindEditTextListener(EditTextPreferenceModifiers.Port)
|
||||
mixedPort.setOnBindEditTextListener(EditTextPreferenceModifiers.Port)
|
||||
|
||||
val metedNetwork = findPreference<Preference>(Key.METERED_NETWORK)!!
|
||||
@ -175,7 +164,6 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
||||
appendHttpProxy.onPreferenceChangeListener = reloadListener
|
||||
showDirectSpeed.onPreferenceChangeListener = reloadListener
|
||||
trafficSniffing.onPreferenceChangeListener = reloadListener
|
||||
muxConcurrency.onPreferenceChangeListener = reloadListener
|
||||
tcpKeepAliveInterval.onPreferenceChangeListener = reloadListener
|
||||
bypassLan.onPreferenceChangeListener = reloadListener
|
||||
bypassLanInCore.onPreferenceChangeListener = reloadListener
|
||||
|
||||
@ -7,6 +7,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.net.VpnService
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
@ -26,7 +27,15 @@ class VpnRequestActivity : AppCompatActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
if (getSystemService<KeyguardManager>()!!.isKeyguardLocked) {
|
||||
receiver = broadcastReceiver { _, _ -> connect.launch(null) }
|
||||
registerReceiver(receiver, IntentFilter(Intent.ACTION_USER_PRESENT))
|
||||
if (SDK_INT >= 33) {
|
||||
registerReceiver(
|
||||
receiver,
|
||||
IntentFilter(Intent.ACTION_USER_PRESENT),
|
||||
Context.RECEIVER_EXPORTED
|
||||
)
|
||||
} else {
|
||||
registerReceiver(receiver, IntentFilter(Intent.ACTION_USER_PRESENT))
|
||||
}
|
||||
} else connect.launch(null)
|
||||
}
|
||||
|
||||
|
||||
@ -45,10 +45,13 @@ abstract class StandardV2RaySettingsActivity : ProfileSettingsActivity<StandardV
|
||||
private val realityShortId = pbm.add(PreferenceBinding(Type.Text, "realityShortId"))
|
||||
|
||||
private val enableECH = pbm.add(PreferenceBinding(Type.Bool, "enableECH"))
|
||||
private val enablePqSignature = pbm.add(PreferenceBinding(Type.Bool, "enablePqSignature"))
|
||||
private val disabledDRS = pbm.add(PreferenceBinding(Type.Bool, "disabledDRS"))
|
||||
private val echConfig = pbm.add(PreferenceBinding(Type.Text, "echConfig"))
|
||||
|
||||
private val enableMux = pbm.add(PreferenceBinding(Type.Bool, "enableMux"))
|
||||
private val muxPadding = pbm.add(PreferenceBinding(Type.Bool, "muxPadding"))
|
||||
private val muxType = pbm.add(PreferenceBinding(Type.TextToInt, "muxType"))
|
||||
private val muxConcurrency = pbm.add(PreferenceBinding(Type.TextToInt, "muxConcurrency"))
|
||||
|
||||
override fun StandardV2RayBean.init() {
|
||||
if (this is TrojanBean) {
|
||||
this@StandardV2RaySettingsActivity.uuid.fieldName = "password"
|
||||
@ -160,6 +163,7 @@ abstract class StandardV2RaySettingsActivity : ProfileSettingsActivity<StandardV
|
||||
host.preference.isVisible = true
|
||||
path.preference.isVisible = true
|
||||
}
|
||||
|
||||
"ws" -> {
|
||||
host.preference.setTitle(R.string.ws_host)
|
||||
path.preference.setTitle(R.string.ws_path)
|
||||
|
||||
@ -9,6 +9,7 @@ import io.nekohasekai.sagernet.utils.cf.RegisterRequest
|
||||
import io.nekohasekai.sagernet.utils.cf.UpdateDeviceRequest
|
||||
import libcore.Libcore
|
||||
import moe.matsuri.nb4a.utils.JavaUtil.gson
|
||||
import moe.matsuri.nb4a.utils.Util
|
||||
|
||||
// kang from wgcf
|
||||
object Cloudflare {
|
||||
@ -37,8 +38,9 @@ object Cloudflare {
|
||||
setUserAgent("okhttp/3.12.1")
|
||||
}.execute()
|
||||
|
||||
Logs.d(response.contentString)
|
||||
val device = gson.fromJson(response.contentString, DeviceResponse::class.java)
|
||||
Logs.d(Util.getStringBox(response.contentString))
|
||||
val device =
|
||||
gson.fromJson(Util.getStringBox(response.contentString), DeviceResponse::class.java)
|
||||
val accessToken = device.token
|
||||
|
||||
client.newRequest().apply {
|
||||
|
||||
@ -2,43 +2,14 @@ package moe.matsuri.nb4a
|
||||
|
||||
import android.content.Context
|
||||
import io.nekohasekai.sagernet.R
|
||||
import io.nekohasekai.sagernet.database.DataStore
|
||||
import io.nekohasekai.sagernet.database.ProxyEntity.Companion.TYPE_NEKO
|
||||
import io.nekohasekai.sagernet.fmt.AbstractBean
|
||||
import io.nekohasekai.sagernet.fmt.v2ray.StandardV2RayBean
|
||||
import io.nekohasekai.sagernet.fmt.v2ray.isTLS
|
||||
import io.nekohasekai.sagernet.ktx.app
|
||||
import io.nekohasekai.sagernet.ktx.getColorAttr
|
||||
import moe.matsuri.nb4a.plugin.NekoPluginManager
|
||||
import moe.matsuri.nb4a.proxy.config.ConfigBean
|
||||
|
||||
// Settings for all protocols, built-in or plugin
|
||||
object Protocols {
|
||||
// Mux
|
||||
|
||||
fun isProfileNeedMux(bean: StandardV2RayBean): Boolean {
|
||||
return when (bean.type) {
|
||||
"tcp", "ws" -> true
|
||||
"http" -> !bean.isTLS()
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
fun shouldEnableMux(protocol: String): Boolean {
|
||||
return DataStore.muxProtocols.contains(protocol)
|
||||
}
|
||||
|
||||
fun getCanMuxList(): List<String> {
|
||||
// built-in and support mux
|
||||
val list = mutableListOf("vmess", "trojan", "trojan-go", "shadowsocks", "vless", "padding")
|
||||
|
||||
NekoPluginManager.getProtocols().forEach {
|
||||
if (it.protocolConfig.optBoolean("canMux")) {
|
||||
list.add(it.protocolId)
|
||||
}
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
// Deduplication
|
||||
|
||||
@ -47,6 +18,9 @@ object Protocols {
|
||||
) {
|
||||
|
||||
fun hash(): String {
|
||||
if (bean is ConfigBean) {
|
||||
return bean.config
|
||||
}
|
||||
return bean.serverAddress + bean.serverPort + type
|
||||
}
|
||||
|
||||
|
||||
@ -449,9 +449,9 @@ public class SingBoxOptions {
|
||||
|
||||
public OutboundTLSOptions tls;
|
||||
|
||||
public String hop_ports;
|
||||
public String server_ports;
|
||||
|
||||
public Integer hop_interval;
|
||||
public String hop_interval;
|
||||
|
||||
}
|
||||
|
||||
@ -575,9 +575,9 @@ public class SingBoxOptions {
|
||||
|
||||
public OutboundTLSOptions tls;
|
||||
|
||||
public String hop_ports;
|
||||
public String server_ports;
|
||||
|
||||
public Integer hop_interval;
|
||||
public String hop_interval;
|
||||
|
||||
}
|
||||
|
||||
@ -1879,10 +1879,6 @@ public class SingBoxOptions {
|
||||
|
||||
public Boolean enabled;
|
||||
|
||||
public Boolean pq_signature_schemes_enabled;
|
||||
|
||||
public Boolean dynamic_record_sizing_disabled;
|
||||
|
||||
// Generate note: Listable
|
||||
public List<String> key;
|
||||
|
||||
@ -1894,10 +1890,6 @@ public class SingBoxOptions {
|
||||
|
||||
public Boolean enabled;
|
||||
|
||||
public Boolean pq_signature_schemes_enabled;
|
||||
|
||||
public Boolean dynamic_record_sizing_disabled;
|
||||
|
||||
// Generate note: Listable
|
||||
public List<String> config;
|
||||
|
||||
@ -3910,9 +3902,9 @@ public class SingBoxOptions {
|
||||
|
||||
public OutboundTLSOptions tls;
|
||||
|
||||
public String hop_ports;
|
||||
public String server_ports;
|
||||
|
||||
public Integer hop_interval;
|
||||
public String hop_interval;
|
||||
|
||||
}
|
||||
|
||||
@ -4284,9 +4276,9 @@ public class SingBoxOptions {
|
||||
|
||||
public OutboundTLSOptions tls;
|
||||
|
||||
public String hop_ports;
|
||||
public String server_ports;
|
||||
|
||||
public Integer hop_interval;
|
||||
public String hop_interval;
|
||||
|
||||
}
|
||||
|
||||
@ -4343,7 +4335,6 @@ public class SingBoxOptions {
|
||||
|
||||
public Boolean source_ip_is_private;
|
||||
|
||||
public Boolean rule_set_ipcidr_match_source;
|
||||
public Boolean ip_is_private;
|
||||
|
||||
// Generate note: Listable
|
||||
@ -4517,4 +4508,57 @@ public class SingBoxOptions {
|
||||
|
||||
}
|
||||
|
||||
// sing-box Options 生成器已经坏了,以下是从 husi 抄的
|
||||
|
||||
public static class Outbound_AnyTLSOptions extends Outbound {
|
||||
|
||||
// Generate note: nested type DialerOptions
|
||||
public String detour;
|
||||
|
||||
public String bind_interface;
|
||||
|
||||
public String inet4_bind_address;
|
||||
|
||||
public String inet6_bind_address;
|
||||
|
||||
public String protect_path;
|
||||
|
||||
public Integer routing_mark;
|
||||
|
||||
public Boolean reuse_addr;
|
||||
|
||||
public String connect_timeout;
|
||||
|
||||
public Boolean tcp_fast_open;
|
||||
|
||||
public Boolean tcp_multi_path;
|
||||
|
||||
public Boolean udp_fragment;
|
||||
|
||||
public String domain_strategy;
|
||||
|
||||
public String network_strategy;
|
||||
|
||||
public List<String> network_type;
|
||||
|
||||
public List<String> fallback_network_type;
|
||||
|
||||
public String fallback_delay;
|
||||
|
||||
// Generate note: nested type ServerOptions
|
||||
public String server;
|
||||
|
||||
public Integer server_port;
|
||||
|
||||
// Generate note: nested type OutboundTLSOptionsContainer
|
||||
public OutboundTLSOptions tls;
|
||||
|
||||
public String password;
|
||||
|
||||
public String idle_session_check_interval;
|
||||
|
||||
public String idle_session_timeout;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -113,7 +113,6 @@ fun SingBoxOptions.Rule_DefaultOptions.makeSingBoxRule(list: List<String>, isIP:
|
||||
if (isIP) {
|
||||
if (it.startsWith("geoip:")) {
|
||||
rule_set.plusAssign(it)
|
||||
rule_set_ipcidr_match_source = false
|
||||
} else {
|
||||
ip_cidr.plusAssign(it)
|
||||
}
|
||||
@ -130,8 +129,7 @@ fun SingBoxOptions.Rule_DefaultOptions.makeSingBoxRule(list: List<String>, isIP:
|
||||
} else if (it.startsWith("keyword:")) {
|
||||
domain_keyword.plusAssign(it.removePrefix("keyword:").lowercase())
|
||||
} else {
|
||||
// https://github.com/SagerNet/sing-box/commit/5d41e328d4a9f7549dd27f11b4ccc43710a73664
|
||||
domain.plusAssign(it.lowercase())
|
||||
domain_suffix.plusAssign(it.lowercase())
|
||||
}
|
||||
}
|
||||
ip_cidr?.removeIf { it.isNullOrBlank() }
|
||||
|
||||
@ -22,8 +22,8 @@ object Plugins {
|
||||
const val METADATA_KEY_EXECUTABLE_PATH = "io.nekohasekai.sagernet.plugin.executable_path"
|
||||
|
||||
fun isExeOrPlugin(pkg: PackageInfo): Boolean {
|
||||
if (pkg.providers == null || pkg.providers.isEmpty()) return false
|
||||
val provider = pkg.providers[0] ?: return false
|
||||
if (pkg.providers?.isEmpty() == true) return false
|
||||
val provider = pkg.providers?.get(0) ?: return false
|
||||
val auth = provider.authority ?: return false
|
||||
return auth.startsWith(AUTHORITIES_PREFIX_SEKAI_EXE)
|
||||
|| auth.startsWith(AUTHORITIES_PREFIX_NEKO_EXE)
|
||||
@ -92,8 +92,8 @@ object Plugins {
|
||||
PackageCache.awaitLoadSync()
|
||||
val pkgs = PackageCache.installedPluginPackages
|
||||
.map { it.value }
|
||||
.filter { it.providers[0].loadString(METADATA_KEY_ID) == pluginId }
|
||||
return pkgs.map { it.providers[0] }
|
||||
.filter { it.providers?.get(0)?.loadString(METADATA_KEY_ID) == pluginId }
|
||||
return pkgs.mapNotNull { it.providers?.get(0) }
|
||||
}
|
||||
|
||||
private fun buildUri(id: String, auth: String) = Uri.Builder()
|
||||
|
||||
@ -0,0 +1,82 @@
|
||||
package moe.matsuri.nb4a.proxy.anytls;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.esotericsoftware.kryo.io.ByteBufferInput;
|
||||
import com.esotericsoftware.kryo.io.ByteBufferOutput;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import io.nekohasekai.sagernet.fmt.AbstractBean;
|
||||
import io.nekohasekai.sagernet.fmt.KryoConverters;
|
||||
|
||||
public class AnyTLSBean extends AbstractBean {
|
||||
|
||||
public static final Creator<AnyTLSBean> CREATOR = new CREATOR<AnyTLSBean>() {
|
||||
@NonNull
|
||||
@Override
|
||||
public AnyTLSBean newInstance() {
|
||||
return new AnyTLSBean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnyTLSBean[] newArray(int size) {
|
||||
return new AnyTLSBean[size];
|
||||
}
|
||||
};
|
||||
public String password;
|
||||
public String sni;
|
||||
public String alpn;
|
||||
public String certificates;
|
||||
public String utlsFingerprint;
|
||||
public Boolean allowInsecure;
|
||||
// In sing-box, this seemed can be used with REALITY.
|
||||
// But even mihomo appended many options, it still not provide REALITY.
|
||||
// https://github.com/anytls/anytls-go/blob/4636d90462fa21a510420512d7706a9acf69c7b9/docs/faq.md?plain=1#L25-L37
|
||||
|
||||
public String echConfig;
|
||||
|
||||
@Override
|
||||
public void initializeDefaultValues() {
|
||||
super.initializeDefaultValues();
|
||||
if (password == null) password = "";
|
||||
if (sni == null) sni = "";
|
||||
if (alpn == null) alpn = "";
|
||||
if (certificates == null) certificates = "";
|
||||
if (utlsFingerprint == null) utlsFingerprint = "";
|
||||
if (allowInsecure == null) allowInsecure = false;
|
||||
if (echConfig == null) echConfig = "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(ByteBufferOutput output) {
|
||||
output.writeInt(0);
|
||||
super.serialize(output);
|
||||
output.writeString(password);
|
||||
output.writeString(sni);
|
||||
output.writeString(alpn);
|
||||
output.writeString(certificates);
|
||||
output.writeString(utlsFingerprint);
|
||||
output.writeBoolean(allowInsecure);
|
||||
output.writeString(echConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserialize(ByteBufferInput input) {
|
||||
int version = input.readInt();
|
||||
super.deserialize(input);
|
||||
password = input.readString();
|
||||
sni = input.readString();
|
||||
alpn = input.readString();
|
||||
certificates = input.readString();
|
||||
utlsFingerprint = input.readString();
|
||||
allowInsecure = input.readBoolean();
|
||||
echConfig = input.readString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AnyTLSBean clone() {
|
||||
return KryoConverters.deserialize(new AnyTLSBean(), KryoConverters.serialize(this));
|
||||
}
|
||||
}
|
||||
37
app/src/main/java/moe/matsuri/nb4a/proxy/anytls/AnyTLSFmt.kt
Normal file
37
app/src/main/java/moe/matsuri/nb4a/proxy/anytls/AnyTLSFmt.kt
Normal file
@ -0,0 +1,37 @@
|
||||
package moe.matsuri.nb4a.proxy.anytls
|
||||
|
||||
import io.nekohasekai.sagernet.ktx.blankAsNull
|
||||
import moe.matsuri.nb4a.SingBoxOptions
|
||||
import moe.matsuri.nb4a.utils.listByLineOrComma
|
||||
|
||||
fun buildSingBoxOutboundAnyTLSBean(bean: AnyTLSBean): SingBoxOptions.Outbound_AnyTLSOptions {
|
||||
return SingBoxOptions.Outbound_AnyTLSOptions().apply {
|
||||
type = "anytls"
|
||||
server = bean.serverAddress
|
||||
server_port = bean.serverPort
|
||||
password = bean.password
|
||||
|
||||
tls = SingBoxOptions.OutboundTLSOptions().apply {
|
||||
enabled = true
|
||||
server_name = bean.sni.blankAsNull()
|
||||
if (bean.allowInsecure) insecure = true
|
||||
alpn = bean.alpn.blankAsNull()?.listByLineOrComma()
|
||||
bean.certificates.blankAsNull()?.let {
|
||||
certificate = it
|
||||
}
|
||||
bean.utlsFingerprint.blankAsNull()?.let {
|
||||
utls = SingBoxOptions.OutboundUTLSOptions().apply {
|
||||
enabled = true
|
||||
fingerprint = it
|
||||
}
|
||||
}
|
||||
bean.echConfig.blankAsNull()?.let {
|
||||
// In new version, some complex options will be deprecated, so we just do this.
|
||||
ech = SingBoxOptions.OutboundECHOptions().apply {
|
||||
enabled = true
|
||||
config = listOf(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package moe.matsuri.nb4a.proxy.anytls
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import io.nekohasekai.sagernet.Key
|
||||
import io.nekohasekai.sagernet.R
|
||||
import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers
|
||||
import io.nekohasekai.sagernet.ktx.applyDefaultValues
|
||||
import io.nekohasekai.sagernet.ui.profile.ProfileSettingsActivity
|
||||
import moe.matsuri.nb4a.proxy.PreferenceBinding
|
||||
import moe.matsuri.nb4a.proxy.PreferenceBindingManager
|
||||
import moe.matsuri.nb4a.proxy.Type
|
||||
|
||||
class AnyTLSSettingsActivity : ProfileSettingsActivity<AnyTLSBean>() {
|
||||
override fun createEntity() = AnyTLSBean().applyDefaultValues()
|
||||
|
||||
private val pbm = PreferenceBindingManager()
|
||||
private val name = pbm.add(PreferenceBinding(Type.Text, "name"))
|
||||
private val serverAddress = pbm.add(PreferenceBinding(Type.Text, "serverAddress"))
|
||||
private val serverPort = pbm.add(PreferenceBinding(Type.TextToInt, "serverPort"))
|
||||
private val password = pbm.add(PreferenceBinding(Type.Text, "password"))
|
||||
private val sni = pbm.add(PreferenceBinding(Type.Text, "sni"))
|
||||
private val alpn = pbm.add(PreferenceBinding(Type.Text, "alpn"))
|
||||
private val certificates = pbm.add(PreferenceBinding(Type.Text, "certificates"))
|
||||
private val allowInsecure = pbm.add(PreferenceBinding(Type.Bool, "allowInsecure"))
|
||||
private val utlsFingerprint = pbm.add(PreferenceBinding(Type.Text, "utlsFingerprint"))
|
||||
|
||||
override fun AnyTLSBean.init() {
|
||||
pbm.writeToCacheAll(this)
|
||||
|
||||
}
|
||||
|
||||
override fun AnyTLSBean.serialize() {
|
||||
pbm.fromCacheAll(this)
|
||||
}
|
||||
|
||||
override fun PreferenceFragmentCompat.createPreferences(
|
||||
savedInstanceState: Bundle?,
|
||||
rootKey: String?
|
||||
) {
|
||||
addPreferencesFromResource(R.xml.anytls_preferences)
|
||||
|
||||
findPreference<EditTextPreference>(Key.SERVER_PORT)!!.apply {
|
||||
setOnBindEditTextListener(EditTextPreferenceModifiers.Port)
|
||||
}
|
||||
findPreference<EditTextPreference>("password")!!.apply {
|
||||
summaryProvider = PasswordSummaryProvider
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -65,8 +65,8 @@ suspend fun NekoBean.updateAllConfig(port: Int) = suspendCoroutine<Unit> {
|
||||
val otherArgs = mutableMapOf<String, Any>()
|
||||
otherArgs["finalAddress"] = finalAddress
|
||||
otherArgs["finalPort"] = finalPort
|
||||
otherArgs["muxEnabled"] = Protocols.shouldEnableMux(protocolId)
|
||||
otherArgs["muxConcurrency"] = DataStore.muxConcurrency
|
||||
// otherArgs["muxEnabled"] = Protocols.shouldEnableMux(protocolId)
|
||||
// otherArgs["muxConcurrency"] = DataStore.muxConcurrency
|
||||
|
||||
val ret = jsip.buildAllConfig(port, this@updateAllConfig, otherArgs)
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ package moe.matsuri.nb4a.utils
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.util.Base64
|
||||
import libcore.StringBox
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
@ -181,4 +182,10 @@ object Util {
|
||||
}
|
||||
}
|
||||
|
||||
fun getStringBox(b: StringBox?): String {
|
||||
if (b != null && b.value != null) {
|
||||
return b.value
|
||||
}
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,15 +57,18 @@
|
||||
<item
|
||||
android:id="@+id/action_new_tuic"
|
||||
android:title="@string/action_tuic" />
|
||||
<item
|
||||
android:id="@+id/action_new_shadowtls"
|
||||
android:title="@string/action_shadowtls" />
|
||||
<item
|
||||
android:id="@+id/action_new_anytls"
|
||||
android:title="@string/action_anytls" />
|
||||
<item
|
||||
android:id="@+id/action_new_ssh"
|
||||
android:title="@string/action_ssh" />
|
||||
<item
|
||||
android:id="@+id/action_new_wg"
|
||||
android:title="@string/action_wireguard" />
|
||||
<item
|
||||
android:id="@+id/action_new_shadowtls"
|
||||
android:title="@string/action_shadowtls" />
|
||||
<item
|
||||
android:id="@+id/action_new_config"
|
||||
android:title="@string/custom_config" />
|
||||
|
||||
1
app/src/main/res/resources.properties
Normal file
1
app/src/main/res/resources.properties
Normal file
@ -0,0 +1 @@
|
||||
unqualifiedResLocale=en-US
|
||||
@ -482,9 +482,6 @@
|
||||
<string name="enable_ech">启用 ECH 技术支持</string>
|
||||
<string name="enable_ech_sum">启用 ECH</string>
|
||||
<string name="ech_settings">ECH 设置</string>
|
||||
<string name="pq_signature_schemes_enabled">启用对后量子对等证书签名方案支持</string>
|
||||
<string name="dynamic_record_sizing_disabled">禁用TLS记录的自适应调整大小</string>
|
||||
<string name="dynamic_record_sizing_sum">如果启用,将始终使用最大可能的TLS记录大小。当禁用时,TLS记录的大小可能会进行调整以尝试改善延迟。</string>
|
||||
<string name="ech_config">ECH 配置</string>
|
||||
<string name="http_upgrade_host">HTTPUpgrade 主机</string>
|
||||
<string name="http_upgrade_path">HTTPUpgrade 路径</string>
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
<string name="auto_connect_summary">在開機或本程式更新後將自動重新啓用代理</string>
|
||||
<string name="delete">移除</string>
|
||||
<string name="enable">啟用</string>
|
||||
<string name="donate_info">世界好得意 請比世界錢</string>
|
||||
<string name="donate_info">貓貓好得意 請比貓貓錢</string>
|
||||
<string name="route_bypass">繞過</string>
|
||||
<string name="route_block">封鎖</string>
|
||||
<string name="add_profile_methods_scan_qr_code">掃描二維碼</string>
|
||||
|
||||
@ -284,7 +284,7 @@
|
||||
<string name="connection_test_icmp_ping_unavailable">ICMPing 無法使用</string>
|
||||
<string name="connection_test_domain_not_found">網域不存在</string>
|
||||
<string name="connection_test_refused">連線被拒</string>
|
||||
<string name="donate_info">世界很可愛 請給世界錢</string>
|
||||
<string name="donate_info">貓貓很可愛 請給貓貓錢</string>
|
||||
<string name="connection_test_unreachable">無法連線</string>
|
||||
<string name="connection_test_timeout">逾時</string>
|
||||
<string name="append_http_proxy">為 VPN 附加 HTTP 代理</string>
|
||||
|
||||
@ -216,7 +216,7 @@
|
||||
<string name="action_trojan_go" translatable="false">Trojan Go</string>
|
||||
<string name="action_mieru" translatable="false">Mieru</string>
|
||||
<string name="action_naive" translatable="false">Naïve</string>
|
||||
<string name="action_ping_tunnel" translatable="false">Ping Tunnel</string>
|
||||
<string name="action_anytls" translatable="false">AnyTLS</string>
|
||||
<string name="action_hysteria" translatable="false">Hysteria</string>
|
||||
<string name="action_ssh" translatable="false">SSH</string>
|
||||
<string name="action_wireguard" translatable="false">WireGuard</string>
|
||||
@ -560,13 +560,7 @@
|
||||
<string name="enable_ech">Enable ECH</string>
|
||||
<string name="enable_ech_sum">Enable Encrypted Client Hello</string>
|
||||
<string name="ech_settings">ECH Settings</string>
|
||||
<string name="pq_signature_schemes_enabled">Enable post-quantum peer certificate signature
|
||||
supports</string>
|
||||
<string name="dynamic_record_sizing_disabled">Disables adaptive sizing of TLS records</string>
|
||||
<string name="ech_config">ECH Config</string>
|
||||
<string name="dynamic_record_sizing_sum">If enable, the largest possible TLS record size is
|
||||
always used. When disable, the size of TLS records may be adjusted in an attempt to improve
|
||||
latency.</string>
|
||||
<string name="http_upgrade_host">HTTPUpgrade Host</string>
|
||||
<string name="http_upgrade_path">HTTPUpgrade Path</string>
|
||||
<string name="update_current_subscription">Update current Group\'s subscription</string>
|
||||
@ -574,4 +568,6 @@
|
||||
<string name="allow_insecure_on_request_sum">Disable certificate checking when updating
|
||||
subscriptions</string>
|
||||
<string name="global_allow_insecure">Always allow insecure</string>
|
||||
<string name="mux_preference">Mulitplex</string>
|
||||
<string name="padding">Padding</string>
|
||||
</resources>
|
||||
57
app/src/main/res/xml/anytls_preferences.xml
Normal file
57
app/src/main/res/xml/anytls_preferences.xml
Normal file
@ -0,0 +1,57 @@
|
||||
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<EditTextPreference
|
||||
app:icon="@drawable/ic_social_emoji_symbols"
|
||||
app:key="profileName"
|
||||
app:title="@string/profile_name"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<PreferenceCategory app:title="@string/proxy_cat">
|
||||
|
||||
<EditTextPreference
|
||||
app:icon="@drawable/ic_hardware_router"
|
||||
app:key="serverAddress"
|
||||
app:title="@string/server_address"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<EditTextPreference
|
||||
app:icon="@drawable/ic_maps_directions_boat"
|
||||
app:key="serverPort"
|
||||
app:title="@string/server_port"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<EditTextPreference
|
||||
app:icon="@drawable/ic_settings_password"
|
||||
app:key="password"
|
||||
app:title="@string/password" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory app:title="@string/security_settings">
|
||||
<EditTextPreference
|
||||
app:icon="@drawable/ic_action_copyright"
|
||||
app:key="sni"
|
||||
app:title="@string/sni"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<SwitchPreference
|
||||
app:icon="@drawable/ic_notification_enhanced_encryption"
|
||||
app:key="allowInsecure"
|
||||
app:title="@string/allow_insecure" />
|
||||
<EditTextPreference
|
||||
app:icon="@drawable/ic_baseline_legend_toggle_24"
|
||||
app:key="alpn"
|
||||
app:title="@string/alpn"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<EditTextPreference
|
||||
app:icon="@drawable/ic_baseline_vpn_key_24"
|
||||
app:key="certificates"
|
||||
app:title="@string/certificates"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<moe.matsuri.nb4a.ui.SimpleMenuPreference
|
||||
app:defaultValue=""
|
||||
app:entries="@array/utls_fingerprint_entry"
|
||||
app:entryValues="@array/utls_fingerprint_entry"
|
||||
app:icon="@drawable/ic_baseline_fingerprint_24"
|
||||
app:key="utlsFingerprint"
|
||||
app:title="@string/utls_fingerprint"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
@ -2,10 +2,6 @@
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<PreferenceCategory app:title="@string/general_settings">
|
||||
<io.nekohasekai.sagernet.widget.AppListPreference
|
||||
app:icon="@drawable/ic_baseline_android_24"
|
||||
app:key="nekoPlugins"
|
||||
app:title="@string/neko_plugin" />
|
||||
<SwitchPreference
|
||||
app:defaultValue="false"
|
||||
app:icon="@drawable/ic_communication_phonelink_ring"
|
||||
@ -88,6 +84,10 @@
|
||||
app:key="logLevel"
|
||||
app:title="@string/log_level"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<io.nekohasekai.sagernet.widget.AppListPreference
|
||||
app:icon="@drawable/ic_baseline_android_24"
|
||||
app:key="nekoPlugins"
|
||||
app:title="@string/neko_plugin" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory app:title="@string/cag_route">
|
||||
@ -134,34 +134,6 @@
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory app:title="@string/protocol_settings">
|
||||
<MultiSelectListPreference
|
||||
app:defaultValue="@array/mux_select_init"
|
||||
app:entries="@array/mux_select_init"
|
||||
app:entryValues="@array/mux_select_init"
|
||||
app:icon="@drawable/ic_baseline_compare_arrows_24"
|
||||
app:key="mux"
|
||||
app:summary="@string/mux_sum"
|
||||
app:title="@string/enable_mux" />
|
||||
<moe.matsuri.nb4a.ui.SimpleMenuPreference
|
||||
app:defaultValue="0"
|
||||
app:entries="@array/mux_type"
|
||||
app:entryValues="@array/int_array_3"
|
||||
app:key="muxType"
|
||||
app:title="@string/mux_type"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<EditTextPreference
|
||||
app:defaultValue="8"
|
||||
app:icon="@drawable/ic_baseline_low_priority_24"
|
||||
app:key="muxConcurrency"
|
||||
app:title="@string/mux_concurrency"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<SwitchPreference
|
||||
app:key="globalAllowInsecure"
|
||||
app:icon="@drawable/ic_action_lock_open"
|
||||
app:title="@string/global_allow_insecure" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory app:title="@string/cag_dns">
|
||||
<EditTextPreference
|
||||
app:defaultValue="https://dns.google/dns-query"
|
||||
@ -177,7 +149,7 @@
|
||||
app:title="@string/domain_strategy_for_remote"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<EditTextPreference
|
||||
app:defaultValue="https://120.53.53.53/dns-query"
|
||||
app:defaultValue="https://223.5.5.5/dns-query"
|
||||
app:icon="@drawable/ic_action_dns"
|
||||
app:key="directDns"
|
||||
app:title="@string/direct_dns"
|
||||
@ -262,10 +234,14 @@
|
||||
app:title="@string/app_tls_version"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<SwitchPreference
|
||||
app:key="showBottomBar"
|
||||
app:title="@string/show_bottom_bar" />
|
||||
app:icon="@drawable/ic_action_lock_open"
|
||||
app:key="globalAllowInsecure"
|
||||
app:title="@string/global_allow_insecure" />
|
||||
<SwitchPreference
|
||||
app:key="allowInsecureOnRequest"
|
||||
app:title="@string/allow_insecure_on_request_sum" />
|
||||
<SwitchPreference
|
||||
app:key="showBottomBar"
|
||||
app:title="@string/show_bottom_bar" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
||||
@ -118,11 +118,6 @@
|
||||
app:key="allowInsecure"
|
||||
app:summary="@string/allow_insecure_sum"
|
||||
app:title="@string/allow_insecure" />
|
||||
<SwitchPreference
|
||||
app:icon="@drawable/ic_baseline_security_24"
|
||||
app:key="enableECH"
|
||||
app:summary="@string/enable_ech_sum"
|
||||
app:title="@string/enable_ech" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
@ -149,19 +144,41 @@
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:key="serverECHCategory"
|
||||
app:title="@string/ech_settings">
|
||||
app:key="serverMuxCategory"
|
||||
app:title="@string/mux_preference">
|
||||
<SwitchPreference
|
||||
app:icon="@drawable/ic_baseline_security_24"
|
||||
app:key="enablePqSignature"
|
||||
app:title="@string/pq_signature_schemes_enabled" />
|
||||
<SwitchPreference
|
||||
app:icon="@drawable/ic_baseline_security_24"
|
||||
app:key="disabledDRS"
|
||||
app:summary="@string/dynamic_record_sizing_sum"
|
||||
app:title="@string/dynamic_record_sizing_disabled" />
|
||||
app:icon="@drawable/ic_baseline_compare_arrows_24"
|
||||
app:key="enableMux"
|
||||
app:summary="@string/mux_sum"
|
||||
app:title="@string/enable_mux" />
|
||||
<moe.matsuri.nb4a.ui.SimpleMenuPreference
|
||||
app:defaultValue="0"
|
||||
app:entries="@array/mux_type"
|
||||
app:entryValues="@array/int_array_3"
|
||||
app:key="muxType"
|
||||
app:title="@string/mux_type"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<EditTextPreference
|
||||
app:icon="@drawable/ic_baseline_texture_24"
|
||||
app:defaultValue="1"
|
||||
app:icon="@drawable/ic_baseline_low_priority_24"
|
||||
app:key="muxConcurrency"
|
||||
app:title="@string/mux_concurrency"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<SwitchPreference
|
||||
app:icon="@drawable/baseline_developer_board_24"
|
||||
app:key="muxPadding"
|
||||
app:title="@string/padding" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:key="serverECHCategory"
|
||||
app:title="ECH">
|
||||
<SwitchPreference
|
||||
app:icon="@drawable/ic_baseline_security_24"
|
||||
app:key="enableECH"
|
||||
app:title="@string/enable" />
|
||||
<EditTextPreference
|
||||
app:icon="@drawable/ic_baseline_nfc_24"
|
||||
app:key="echConfig"
|
||||
app:title="@string/ech_config"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
@ -6,3 +6,7 @@ allprojects {
|
||||
tasks.register<Delete>("clean") {
|
||||
delete(rootProject.buildDir)
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("com.google.devtools.ksp") version "2.0.21-1.0.27" apply false
|
||||
}
|
||||
|
||||
@ -6,10 +6,6 @@ ENV_NB4A=1
|
||||
source "buildScript/lib/core/get_source_env.sh"
|
||||
pushd ..
|
||||
|
||||
######
|
||||
## From nekoray/libs/get_source.sh
|
||||
######
|
||||
|
||||
####
|
||||
|
||||
if [ ! -d "sing-box" ]; then
|
||||
@ -17,17 +13,6 @@ if [ ! -d "sing-box" ]; then
|
||||
fi
|
||||
pushd sing-box
|
||||
git checkout "$COMMIT_SING_BOX"
|
||||
|
||||
popd
|
||||
|
||||
####
|
||||
|
||||
if [ ! -d "sing-quic" ]; then
|
||||
git clone --no-checkout https://github.com/MatsuriDayo/sing-quic.git
|
||||
fi
|
||||
pushd sing-quic
|
||||
git checkout "$COMMIT_SING_QUIC"
|
||||
|
||||
popd
|
||||
|
||||
####
|
||||
@ -37,7 +22,6 @@ if [ ! -d "libneko" ]; then
|
||||
fi
|
||||
pushd libneko
|
||||
git checkout "$COMMIT_LIBNEKO"
|
||||
|
||||
popd
|
||||
|
||||
####
|
||||
|
||||
@ -1,3 +1,2 @@
|
||||
export COMMIT_SING_BOX="06557f6cef23160668122a17a818b378b5a216b5"
|
||||
export COMMIT_SING_QUIC="b49ce60d9b3622d5238fee96bfd3c5f6e3915b42"
|
||||
export COMMIT_SING_BOX="76802b787333ad72bc1db2de79ea69993b79d892"
|
||||
export COMMIT_LIBNEKO="1c47a3af71990a7b2192e03292b4d246c308ef0b"
|
||||
|
||||
@ -7,6 +7,6 @@ apply(from = "../repositories.gradle.kts")
|
||||
|
||||
dependencies {
|
||||
// Gradle Plugins
|
||||
implementation("com.android.tools.build:gradle:7.4.2")
|
||||
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10")
|
||||
implementation("com.android.tools.build:gradle:8.8.1")
|
||||
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21")
|
||||
}
|
||||
|
||||
@ -1,25 +1,15 @@
|
||||
import com.android.build.api.dsl.ApplicationExtension
|
||||
import com.android.build.api.dsl.LibraryExtension
|
||||
import com.android.build.api.dsl.Lint
|
||||
import com.android.build.gradle.AbstractAppExtension
|
||||
import com.android.build.gradle.AppExtension
|
||||
import com.android.build.gradle.BaseExtension
|
||||
import com.android.build.gradle.internal.api.BaseVariantOutputImpl
|
||||
import org.gradle.api.JavaVersion
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.ExtensionAware
|
||||
import org.gradle.kotlin.dsl.getByName
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
|
||||
import java.security.MessageDigest
|
||||
import java.util.*
|
||||
import java.util.Base64
|
||||
import java.util.Properties
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
fun sha256Hex(bytes: ByteArray): String {
|
||||
val md = MessageDigest.getInstance("SHA-256")
|
||||
val digest = md.digest(bytes)
|
||||
return digest.fold("") { str, it -> str + "%02x".format(it) }
|
||||
}
|
||||
|
||||
private val Project.android get() = extensions.getByName<ApplicationExtension>("android")
|
||||
|
||||
private lateinit var metadata: Properties
|
||||
@ -76,29 +66,13 @@ fun Project.requireLocalProperties(): Properties {
|
||||
return localProperties
|
||||
}
|
||||
|
||||
fun Project.requireTargetAbi(): String {
|
||||
var targetAbi = ""
|
||||
if (gradle.startParameter.taskNames.isNotEmpty()) {
|
||||
if (gradle.startParameter.taskNames.size == 1) {
|
||||
val targetTask = gradle.startParameter.taskNames[0].toLowerCase(Locale.ROOT).trim()
|
||||
when {
|
||||
targetTask.contains("arm64") -> targetAbi = "arm64-v8a"
|
||||
targetTask.contains("arm") -> targetAbi = "armeabi-v7a"
|
||||
targetTask.contains("x64") -> targetAbi = "x86_64"
|
||||
targetTask.contains("x86") -> targetAbi = "x86"
|
||||
}
|
||||
}
|
||||
}
|
||||
return targetAbi
|
||||
}
|
||||
|
||||
fun Project.setupCommon() {
|
||||
android.apply {
|
||||
buildToolsVersion = "30.0.3"
|
||||
compileSdk = 33
|
||||
buildToolsVersion = "35.0.1"
|
||||
compileSdk = 35
|
||||
defaultConfig {
|
||||
minSdk = 21
|
||||
targetSdk = 33
|
||||
targetSdk = 35
|
||||
}
|
||||
buildTypes {
|
||||
getByName("release") {
|
||||
@ -120,7 +94,7 @@ fun Project.setupCommon() {
|
||||
textOutput = project.file("build/lint.txt")
|
||||
htmlOutput = project.file("build/lint.html")
|
||||
}
|
||||
packagingOptions {
|
||||
packaging {
|
||||
resources.excludes.addAll(
|
||||
listOf(
|
||||
"**/*.kotlin_*",
|
||||
@ -137,9 +111,6 @@ fun Project.setupCommon() {
|
||||
)
|
||||
)
|
||||
}
|
||||
packagingOptions {
|
||||
jniLibs.useLegacyPackaging = true
|
||||
}
|
||||
(this as? AbstractAppExtension)?.apply {
|
||||
buildTypes {
|
||||
getByName("release") {
|
||||
@ -191,9 +162,7 @@ fun Project.setupAppCommon() {
|
||||
buildTypes {
|
||||
val key = signingConfigs.findByName("release")
|
||||
if (key != null) {
|
||||
if (requireTargetAbi().isBlank()) {
|
||||
getByName("release").signingConfig = key
|
||||
}
|
||||
getByName("release").signingConfig = key
|
||||
getByName("debug").signingConfig = key
|
||||
}
|
||||
}
|
||||
@ -213,8 +182,6 @@ fun Project.setupApp() {
|
||||
}
|
||||
setupAppCommon()
|
||||
|
||||
val targetAbi = requireTargetAbi()
|
||||
|
||||
android.apply {
|
||||
this as AbstractAppExtension
|
||||
|
||||
@ -228,12 +195,13 @@ fun Project.setupApp() {
|
||||
}
|
||||
|
||||
splits.abi {
|
||||
reset()
|
||||
isEnable = true
|
||||
isUniversalApk = false
|
||||
if (targetAbi.isNotBlank()) {
|
||||
reset()
|
||||
include(targetAbi)
|
||||
}
|
||||
include("armeabi-v7a")
|
||||
include("arm64-v8a")
|
||||
include("x86")
|
||||
include("x86_64")
|
||||
}
|
||||
|
||||
flavorDimensions += "vendor"
|
||||
|
||||
@ -21,3 +21,5 @@ android.enableJetifier=true
|
||||
kotlin.code.style=official
|
||||
# Gradle parallel build
|
||||
org.gradle.parallel=true
|
||||
android.nonTransitiveRClass=false
|
||||
android.nonFinalResIds=false
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
1
libcore/.gitignore
vendored
1
libcore/.gitignore
vendored
@ -5,3 +5,4 @@ binary*.go
|
||||
/debug.go
|
||||
build
|
||||
.build
|
||||
env_*.sh
|
||||
|
||||
@ -10,21 +10,27 @@ import (
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/matsuridayo/libneko/protect_server"
|
||||
"github.com/matsuridayo/libneko/speedtest"
|
||||
"github.com/sagernet/sing-box/boxapi"
|
||||
"github.com/sagernet/sing-box/experimental/libbox/platform"
|
||||
"github.com/sagernet/sing-box/protocol/group"
|
||||
|
||||
box "github.com/sagernet/sing-box"
|
||||
"github.com/sagernet/sing-box/common/conntrack"
|
||||
"github.com/sagernet/sing-box/common/dialer"
|
||||
"github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-box/outbound"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/service"
|
||||
"github.com/sagernet/sing/service/pause"
|
||||
)
|
||||
|
||||
func init() {
|
||||
dialer.DoNotSelectInterface = true
|
||||
}
|
||||
|
||||
var mainInstance *BoxInstance
|
||||
|
||||
func VersionBox() string {
|
||||
@ -59,36 +65,37 @@ func ResetAllConnections(system bool) {
|
||||
}
|
||||
|
||||
type BoxInstance struct {
|
||||
access sync.Mutex
|
||||
|
||||
*box.Box
|
||||
cancel context.CancelFunc
|
||||
state int
|
||||
|
||||
v2api *boxapi.SbV2rayServer
|
||||
selector *outbound.Selector
|
||||
selector *group.Selector
|
||||
pauseManager pause.Manager
|
||||
|
||||
ForTest bool
|
||||
}
|
||||
|
||||
func NewSingBoxInstance(config string) (b *BoxInstance, err error) {
|
||||
defer device.DeferPanicToError("NewSingBoxInstance", func(err_ error) { err = err_ })
|
||||
|
||||
// create box context
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx = box.Context(ctx, nekoboxAndroidInboundRegistry(), nekoboxAndroidOutboundRegistry(), nekoboxAndroidEndpointRegistry())
|
||||
ctx = service.ContextWithDefaultRegistry(ctx)
|
||||
service.MustRegister[platform.Interface](ctx, boxPlatformInterfaceInstance)
|
||||
|
||||
// parse options
|
||||
var options option.Options
|
||||
err = options.UnmarshalJSON([]byte(config))
|
||||
err = options.UnmarshalJSONContext(ctx, []byte(config))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode config: %v", err)
|
||||
}
|
||||
|
||||
// create box context
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx = service.ContextWithDefaultRegistry(ctx)
|
||||
|
||||
// create box
|
||||
instance, err := box.New(box.Options{
|
||||
Options: options,
|
||||
Context: ctx,
|
||||
PlatformInterface: boxPlatformInterfaceInstance,
|
||||
PlatformLogWriter: boxPlatformLogWriter,
|
||||
})
|
||||
if err != nil {
|
||||
@ -103,8 +110,8 @@ func NewSingBoxInstance(config string) (b *BoxInstance, err error) {
|
||||
}
|
||||
|
||||
// selector
|
||||
if proxy, ok := b.Router().Outbound("proxy"); ok {
|
||||
if selector, ok := proxy.(*outbound.Selector); ok {
|
||||
if proxy, ok := b.Outbound().Outbound("proxy"); ok {
|
||||
if selector, ok := proxy.(*group.Selector); ok {
|
||||
b.selector = selector
|
||||
}
|
||||
}
|
||||
@ -113,6 +120,9 @@ func NewSingBoxInstance(config string) (b *BoxInstance, err error) {
|
||||
}
|
||||
|
||||
func (b *BoxInstance) Start() (err error) {
|
||||
b.access.Lock()
|
||||
defer b.access.Unlock()
|
||||
|
||||
defer device.DeferPanicToError("box.Start", func(err_ error) { err = err_ })
|
||||
|
||||
if b.state == 0 {
|
||||
@ -123,6 +133,9 @@ func (b *BoxInstance) Start() (err error) {
|
||||
}
|
||||
|
||||
func (b *BoxInstance) Close() (err error) {
|
||||
b.access.Lock()
|
||||
defer b.access.Unlock()
|
||||
|
||||
defer device.DeferPanicToError("box.Close", func(err_ error) { err = err_ })
|
||||
|
||||
// no double close
|
||||
@ -138,14 +151,19 @@ func (b *BoxInstance) Close() (err error) {
|
||||
}
|
||||
|
||||
// close box
|
||||
common.Close(b.Box)
|
||||
if b.cancel != nil {
|
||||
b.cancel()
|
||||
}
|
||||
if b.Box != nil {
|
||||
b.Box.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BoxInstance) Sleep() {
|
||||
b.pauseManager.DevicePause()
|
||||
_ = b.Box.Router().ResetNetwork()
|
||||
// _ = b.Box.Router().ResetNetwork()
|
||||
}
|
||||
|
||||
func (b *BoxInstance) Wake() {
|
||||
@ -162,7 +180,7 @@ func (b *BoxInstance) SetV2rayStats(outbounds string) {
|
||||
Enabled: true,
|
||||
Outbounds: strings.Split(outbounds, "\n"),
|
||||
})
|
||||
b.Box.Router().SetV2RayServer(b.v2api)
|
||||
b.Box.Router().SetTracker(b.v2api.StatsService())
|
||||
}
|
||||
|
||||
func (b *BoxInstance) QueryStats(tag, direct string) int64 {
|
||||
|
||||
101
libcore/box_include.go
Normal file
101
libcore/box_include.go
Normal file
@ -0,0 +1,101 @@
|
||||
package libcore
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing-box/adapter/endpoint"
|
||||
"github.com/sagernet/sing-box/adapter/inbound"
|
||||
"github.com/sagernet/sing-box/adapter/outbound"
|
||||
"github.com/sagernet/sing-box/protocol/anytls"
|
||||
"github.com/sagernet/sing-box/protocol/block"
|
||||
"github.com/sagernet/sing-box/protocol/direct"
|
||||
"github.com/sagernet/sing-box/protocol/dns"
|
||||
"github.com/sagernet/sing-box/protocol/group"
|
||||
"github.com/sagernet/sing-box/protocol/http"
|
||||
"github.com/sagernet/sing-box/protocol/hysteria"
|
||||
"github.com/sagernet/sing-box/protocol/hysteria2"
|
||||
"github.com/sagernet/sing-box/protocol/mixed"
|
||||
"github.com/sagernet/sing-box/protocol/redirect"
|
||||
"github.com/sagernet/sing-box/protocol/shadowsocks"
|
||||
"github.com/sagernet/sing-box/protocol/shadowtls"
|
||||
"github.com/sagernet/sing-box/protocol/socks"
|
||||
"github.com/sagernet/sing-box/protocol/ssh"
|
||||
"github.com/sagernet/sing-box/protocol/tor"
|
||||
"github.com/sagernet/sing-box/protocol/trojan"
|
||||
"github.com/sagernet/sing-box/protocol/tuic"
|
||||
"github.com/sagernet/sing-box/protocol/tun"
|
||||
"github.com/sagernet/sing-box/protocol/vless"
|
||||
"github.com/sagernet/sing-box/protocol/vmess"
|
||||
"github.com/sagernet/sing-box/protocol/wireguard"
|
||||
|
||||
_ "github.com/sagernet/sing-box/experimental/clashapi"
|
||||
)
|
||||
|
||||
func nekoboxAndroidInboundRegistry() *inbound.Registry {
|
||||
registry := inbound.NewRegistry()
|
||||
|
||||
tun.RegisterInbound(registry)
|
||||
redirect.RegisterRedirect(registry)
|
||||
redirect.RegisterTProxy(registry)
|
||||
direct.RegisterInbound(registry)
|
||||
|
||||
socks.RegisterInbound(registry)
|
||||
http.RegisterInbound(registry)
|
||||
mixed.RegisterInbound(registry)
|
||||
|
||||
return registry
|
||||
}
|
||||
|
||||
func nekoboxAndroidOutboundRegistry() *outbound.Registry {
|
||||
registry := outbound.NewRegistry()
|
||||
|
||||
direct.RegisterOutbound(registry)
|
||||
|
||||
block.RegisterOutbound(registry)
|
||||
dns.RegisterOutbound(registry)
|
||||
|
||||
group.RegisterSelector(registry)
|
||||
group.RegisterURLTest(registry)
|
||||
|
||||
socks.RegisterOutbound(registry)
|
||||
http.RegisterOutbound(registry)
|
||||
shadowsocks.RegisterOutbound(registry)
|
||||
vmess.RegisterOutbound(registry)
|
||||
trojan.RegisterOutbound(registry)
|
||||
tor.RegisterOutbound(registry)
|
||||
ssh.RegisterOutbound(registry)
|
||||
shadowtls.RegisterOutbound(registry)
|
||||
vless.RegisterOutbound(registry)
|
||||
anytls.RegisterOutbound(registry)
|
||||
|
||||
registerQUICOutbounds(registry)
|
||||
registerWireGuardOutbound(registry)
|
||||
|
||||
return registry
|
||||
}
|
||||
|
||||
func nekoboxAndroidEndpointRegistry() *endpoint.Registry {
|
||||
registry := endpoint.NewRegistry()
|
||||
|
||||
registerWireGuardEndpoint(registry)
|
||||
|
||||
return registry
|
||||
}
|
||||
|
||||
func registerQUICInbounds(registry *inbound.Registry) {
|
||||
hysteria.RegisterInbound(registry)
|
||||
tuic.RegisterInbound(registry)
|
||||
hysteria2.RegisterInbound(registry)
|
||||
}
|
||||
|
||||
func registerQUICOutbounds(registry *outbound.Registry) {
|
||||
hysteria.RegisterOutbound(registry)
|
||||
tuic.RegisterOutbound(registry)
|
||||
hysteria2.RegisterOutbound(registry)
|
||||
}
|
||||
|
||||
func registerWireGuardOutbound(registry *outbound.Registry) {
|
||||
wireguard.RegisterOutbound(registry)
|
||||
}
|
||||
|
||||
func registerWireGuardEndpoint(registry *endpoint.Registry) {
|
||||
wireguard.RegisterEndpoint(registry)
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
source ./env_java.sh || true
|
||||
source ../buildScript/init/env_ndk.sh
|
||||
|
||||
BUILD=".build"
|
||||
@ -9,7 +10,11 @@ rm -rf $BUILD/android \
|
||||
$BUILD/javac-output \
|
||||
$BUILD/src
|
||||
|
||||
gomobile bind -v -androidapi 21 -cache $(realpath $BUILD) -trimpath -ldflags='-s -w' -tags='with_conntrack,with_gvisor,with_quic,with_wireguard,with_utls,with_clash_api,with_ech' . || exit 1
|
||||
if [ -z "$GOPATH" ]; then
|
||||
GOPATH=$(go env GOPATH)
|
||||
fi
|
||||
|
||||
"$GOPATH"/bin/gomobile-matsuri bind -v -androidapi 21 -cache "$(realpath $BUILD)" -trimpath -ldflags='-s -w' -tags='with_conntrack,with_gvisor,with_quic,with_wireguard,with_utls,with_clash_api,with_ech' . || exit 1
|
||||
rm -r libcore-sources.jar
|
||||
|
||||
proj=../app/libs
|
||||
|
||||
12
libcore/fix.go
Normal file
12
libcore/fix.go
Normal file
@ -0,0 +1,12 @@
|
||||
package libcore
|
||||
|
||||
// https://github.com/golang/go/issues/46893
|
||||
// TODO: remove after `bulkBarrierPreWrite: unaligned arguments` fixed
|
||||
|
||||
type StringBox struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
func wrapString(value string) *StringBox {
|
||||
return &StringBox{Value: value}
|
||||
}
|
||||
@ -1,14 +1,15 @@
|
||||
package libcore
|
||||
|
||||
import (
|
||||
"github.com/oschwald/maxminddb-golang"
|
||||
"github.com/sagernet/sing-box/common/srs"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/oschwald/maxminddb-golang"
|
||||
"github.com/sagernet/sing-box/common/srs"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
)
|
||||
|
||||
type Geoip struct {
|
||||
@ -66,7 +67,8 @@ func (g *Geoip) ConvertGeoip(countryCode, outputPath string) {
|
||||
}
|
||||
|
||||
outputFile, err := os.Create(outputPath)
|
||||
err = srs.Write(outputFile, plainRuleSet.Upgrade())
|
||||
rs, _ := plainRuleSet.Upgrade()
|
||||
err = srs.Write(outputFile, rs, plainRuleSet.Version)
|
||||
if err != nil {
|
||||
log.Println("failed to write geosite file:", err)
|
||||
return
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
package libcore
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/sagernet/sing-box/common/geosite"
|
||||
"github.com/sagernet/sing-box/common/srs"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"os"
|
||||
|
||||
"log"
|
||||
)
|
||||
|
||||
type Geosite struct {
|
||||
@ -58,7 +58,8 @@ func (g *Geosite) ConvertGeosite(code string, outputPath string) {
|
||||
}
|
||||
|
||||
outputFile, err := os.Create(outputPath)
|
||||
err = srs.Write(outputFile, plainRuleSet.Upgrade())
|
||||
rs, _ := plainRuleSet.Upgrade()
|
||||
err = srs.Write(outputFile, rs, plainRuleSet.Version)
|
||||
if err != nil {
|
||||
log.Println("failed to write geosite file:", err)
|
||||
return
|
||||
|
||||
@ -1,42 +1,41 @@
|
||||
module libcore
|
||||
|
||||
go 1.20
|
||||
go 1.23.1
|
||||
|
||||
toolchain go1.23.6
|
||||
|
||||
require (
|
||||
github.com/matsuridayo/libneko v1.0.0 // replaced
|
||||
github.com/miekg/dns v1.1.59
|
||||
github.com/sagernet/sing v0.4.3
|
||||
github.com/miekg/dns v1.1.63
|
||||
github.com/oschwald/maxminddb-golang v1.12.0
|
||||
github.com/sagernet/sing v0.6.1
|
||||
github.com/sagernet/sing-box v1.0.0 // replaced
|
||||
github.com/sagernet/sing-dns v0.2.3
|
||||
github.com/sagernet/sing-tun v0.3.3
|
||||
github.com/sagernet/sing-dns v0.4.0
|
||||
github.com/sagernet/sing-tun v0.6.1
|
||||
github.com/ulikunitz/xz v0.5.11
|
||||
golang.org/x/mobile v0.0.0-20231108233038-35478a0c49da
|
||||
)
|
||||
|
||||
require github.com/oschwald/maxminddb-golang v1.12.0
|
||||
|
||||
require (
|
||||
berty.tech/go-libtor v1.0.385 // indirect
|
||||
github.com/ajg/form v1.5.1 // indirect
|
||||
github.com/andybalholm/brotli v1.0.6 // indirect
|
||||
github.com/anytls/sing-anytls v0.0.2 // indirect
|
||||
github.com/caddyserver/certmagic v0.20.0 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/cretz/bine v0.2.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/gaukas/godicttls v0.0.4 // indirect
|
||||
github.com/go-chi/chi/v5 v5.0.12 // indirect
|
||||
github.com/go-chi/cors v1.2.1 // indirect
|
||||
github.com/go-chi/chi/v5 v5.2.1 // indirect
|
||||
github.com/go-chi/render v1.0.3 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gofrs/uuid/v5 v5.2.0 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/gofrs/uuid/v5 v5.3.0 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 // indirect
|
||||
github.com/hashicorp/yamux v0.1.2 // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 // indirect
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
@ -44,47 +43,49 @@ require (
|
||||
github.com/libdns/cloudflare v0.1.1 // indirect
|
||||
github.com/libdns/libdns v0.2.2 // indirect
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
|
||||
github.com/metacubex/tfo-go v0.0.0-20240821025650-e9be0afd5e7d // indirect
|
||||
github.com/mdlayher/netlink v1.7.2 // indirect
|
||||
github.com/mdlayher/socket v0.4.1 // indirect
|
||||
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 // indirect
|
||||
github.com/mholt/acmez v1.2.0 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.9.7 // indirect
|
||||
github.com/ooni/go-libtor v1.1.8 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 // indirect
|
||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba // indirect
|
||||
github.com/sagernet/quic-go v0.47.0-beta.2 // indirect
|
||||
github.com/sagernet/cors v1.2.1 // indirect
|
||||
github.com/sagernet/fswatch v0.1.1 // indirect
|
||||
github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
|
||||
github.com/sagernet/nftables v0.3.0-beta.4 // indirect
|
||||
github.com/sagernet/quic-go v0.49.0-beta.1 // indirect
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
|
||||
github.com/sagernet/sing-mux v0.2.0 // indirect
|
||||
github.com/sagernet/sing-quic v0.2.2 // indirect
|
||||
github.com/sagernet/sing-mux v0.3.1 // indirect
|
||||
github.com/sagernet/sing-quic v0.4.0 // indirect
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7 // indirect
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0 // indirect
|
||||
github.com/sagernet/sing-shadowtls v0.1.4 // indirect
|
||||
github.com/sagernet/sing-vmess v0.1.12 // indirect
|
||||
github.com/sagernet/sing-shadowtls v0.2.0 // indirect
|
||||
github.com/sagernet/sing-vmess v0.2.0 // indirect
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect
|
||||
github.com/sagernet/utls v1.5.4 // indirect
|
||||
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 // indirect
|
||||
github.com/sagernet/utls v1.6.7 // indirect
|
||||
github.com/sagernet/wireguard-go v0.0.1-beta.5 // indirect
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect
|
||||
github.com/spf13/cobra v1.8.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
|
||||
golang.org/x/mod v0.18.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.25.0 // indirect
|
||||
golang.org/x/text v0.18.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 // indirect
|
||||
golang.org/x/crypto v0.32.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/mod v0.20.0 // indirect
|
||||
golang.org/x/net v0.34.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
google.golang.org/grpc v1.63.2 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
@ -95,7 +96,7 @@ replace github.com/matsuridayo/libneko => ../../libneko
|
||||
|
||||
replace github.com/sagernet/sing-box => ../../sing-box
|
||||
|
||||
replace github.com/sagernet/sing-quic => ../../sing-quic
|
||||
// replace github.com/sagernet/sing-quic => ../../sing-quic
|
||||
|
||||
// replace github.com/sagernet/sing => ../../sing
|
||||
|
||||
|
||||
162
libcore/go.sum
162
libcore/go.sum
@ -1,15 +1,13 @@
|
||||
berty.tech/go-libtor v1.0.385 h1:RWK94C3hZj6Z2GdvePpHJLnWYobFr3bY/OdUJ5aoEXw=
|
||||
berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+fJEw=
|
||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/anytls/sing-anytls v0.0.2 h1:25azSh0o/LMcIkhS4ZutgRTIGwh8O3wuOhsThVM9K9o=
|
||||
github.com/anytls/sing-anytls v0.0.2/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8=
|
||||
github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4BpCQ/Fc=
|
||||
github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NYacrNoZYiRM2jTg=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
|
||||
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
||||
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -17,15 +15,12 @@ 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=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk=
|
||||
github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
|
||||
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
||||
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
|
||||
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
||||
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
@ -34,20 +29,20 @@ github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gofrs/uuid/v5 v5.2.0 h1:qw1GMx6/y8vhVsx626ImfKMuS5CvJmhIKKtuyvfajMM=
|
||||
github.com/gofrs/uuid/v5 v5.2.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/gofrs/uuid/v5 v5.3.0 h1:m0mUMr+oVYUdxpMLgSYCZiXe7PuVPnI94+OMeVBNedk=
|
||||
github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk=
|
||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
||||
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 h1:9K06NfxkBh25x56yVhWWlKFE8YpicaSfHwoV8SFbueA=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI=
|
||||
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
|
||||
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 h1:q3OEI9RaN/wwcx+qgGo6ZaoJkCiDYe/gjDLfq7lQQF4=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905/go.mod h1:VvGYjkZoJyKqlmT1yzakUs4mfKMNB0XdODP0+rdml6k=
|
||||
github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
@ -65,17 +60,20 @@ github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
|
||||
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/metacubex/tfo-go v0.0.0-20240821025650-e9be0afd5e7d h1:j9LtzkYstLFoNvXW824QQeN7Y26uPL5249kzWKbzO9U=
|
||||
github.com/metacubex/tfo-go v0.0.0-20240821025650-e9be0afd5e7d/go.mod h1:c7bVFM9f5+VzeZ/6Kg77T/jrg1Xp8QpqlSHvG/aXVts=
|
||||
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY=
|
||||
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
|
||||
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
|
||||
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
|
||||
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
|
||||
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
|
||||
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
|
||||
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
|
||||
github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss=
|
||||
github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0=
|
||||
github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
|
||||
github.com/ooni/go-libtor v1.1.8 h1:Wo3V3DVTxl5vZdxtQakqYP+DAHx7pPtAFSl1bnAa08w=
|
||||
github.com/ooni/go-libtor v1.1.8/go.mod h1:q1YyLwRD9GeMyeerVvwc0vJ2YgwDLTp2bdVcrh/JXyI=
|
||||
github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4=
|
||||
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
|
||||
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
|
||||
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
||||
@ -86,59 +84,62 @@ github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0=
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 h1:YbmpqPQEMdlk9oFSKYWRqVuu9qzNiOayIonKmv1gCXY=
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1/go.mod h1:J2yAxTFPDjrDPhuAi9aWFz2L3ox9it4qAluBBbN0H5k=
|
||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f h1:NkhuupzH5ch7b/Y/6ZHJWrnNLoiNnSJaow6DPb8VW2I=
|
||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f/go.mod h1:KXmw+ouSJNOsuRpg4wgwwCQuunrGz4yoAqQjsLjc6N0=
|
||||
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba h1:EY5AS7CCtfmARNv2zXUOrsEMPFDGYxaw65JzA2p51Vk=
|
||||
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/quic-go v0.47.0-beta.2 h1:1tCGWFOSaXIeuQaHrwOMJIYvlupjTcaVInGQw5ArULU=
|
||||
github.com/sagernet/quic-go v0.47.0-beta.2/go.mod h1:bLVKvElSEMNv7pu7SZHscW02TYigzQ5lQu3Nh4wNh8Q=
|
||||
github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
|
||||
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
|
||||
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
|
||||
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
|
||||
github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff h1:mlohw3360Wg1BNGook/UHnISXhUx4Gd/3tVLs5T0nSs=
|
||||
github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff/go.mod h1:ehZwnT2UpmOWAHFL48XdBhnd4Qu4hN2O3Ji0us3ZHMw=
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
|
||||
github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8=
|
||||
github.com/sagernet/quic-go v0.49.0-beta.1 h1:3LdoCzVVfYRibZns1tYWSIoB65fpTmrwy+yfK8DQ8Jk=
|
||||
github.com/sagernet/quic-go v0.49.0-beta.1/go.mod h1:uesWD1Ihrldq1M3XtjuEvIUqi8WHNsRs71b3Lt1+p/U=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||
github.com/sagernet/sing v0.4.3 h1:Ty/NAiNnVd6844k7ujlL5lkzydhcTH5Psc432jXA4Y8=
|
||||
github.com/sagernet/sing v0.4.3/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls=
|
||||
github.com/sagernet/sing-dns v0.2.3 h1:YzeBUn2tR38F7HtvGEQ0kLRLmZWMEgi/+7wqa4Twb1k=
|
||||
github.com/sagernet/sing-dns v0.2.3/go.mod h1:BJpJv6XLnrUbSyIntOT6DG9FW0f4fETmPAHvNjOprLg=
|
||||
github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo=
|
||||
github.com/sagernet/sing-mux v0.2.0/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ=
|
||||
github.com/sagernet/sing v0.6.1 h1:mJ6e7Ir2wtCoGLbdnnXWBsNJu5YHtbXmv66inoE0zFA=
|
||||
github.com/sagernet/sing v0.6.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-dns v0.4.0 h1:+mNoOuR3nljjouCH+qMg4zHI1+R9T2ReblGFkZPEndc=
|
||||
github.com/sagernet/sing-dns v0.4.0/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8=
|
||||
github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI=
|
||||
github.com/sagernet/sing-mux v0.3.1/go.mod h1:Mkdz8LnDstthz0HWuA/5foncnDIdcNN5KZ6AdJX+x78=
|
||||
github.com/sagernet/sing-quic v0.4.0 h1:E4geazHk/UrJTXMlT+CBCKmn8V86RhtNeczWtfeoEFc=
|
||||
github.com/sagernet/sing-quic v0.4.0/go.mod h1:c+CytOEyeN20KCTFIP8YQUkNDVFLSzjrEPqP7Hlnxys=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
|
||||
github.com/sagernet/sing-tun v0.3.3 h1:LZnQNmfGcNG2KPTPkLgc+Lo7k606QJVkPp2DnjriwUk=
|
||||
github.com/sagernet/sing-tun v0.3.3/go.mod h1:DxLIyhjWU/HwGYoX0vNGg2c5QgTQIakphU1MuERR5tQ=
|
||||
github.com/sagernet/sing-vmess v0.1.12 h1:2gFD8JJb+eTFMoa8FIVMnknEi+vCSfaiTXTfEYAYAPg=
|
||||
github.com/sagernet/sing-vmess v0.1.12/go.mod h1:luTSsfyBGAc9VhtCqwjR+dt1QgqBhuYBCONB/POhF8I=
|
||||
github.com/sagernet/sing-shadowtls v0.2.0 h1:cLKe4OAOFwuhmAIuPLj//CIL7Q9js+pIDardhJ+/osk=
|
||||
github.com/sagernet/sing-shadowtls v0.2.0/go.mod h1:agU+Fw5X+xnWVyRHyFthoZCX3MfWKCFPm4JUf+1oaxo=
|
||||
github.com/sagernet/sing-tun v0.6.1 h1:4l0+gnEKcGjlWfUVTD+W0BRApqIny/lU2ZliurE+VMo=
|
||||
github.com/sagernet/sing-tun v0.6.1/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE=
|
||||
github.com/sagernet/sing-vmess v0.2.0 h1:pCMGUXN2k7RpikQV65/rtXtDHzb190foTfF9IGTMZrI=
|
||||
github.com/sagernet/sing-vmess v0.2.0/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA=
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
|
||||
github.com/sagernet/utls v1.5.4 h1:KmsEGbB2dKUtCNC+44NwAdNAqnqQ6GA4pTO0Yik56co=
|
||||
github.com/sagernet/utls v1.5.4/go.mod h1:CTGxPWExIloRipK3XFpYv0OVyhO8kk3XCGW/ieyTh1s=
|
||||
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 h1:R0OMYAScomNAVpTfbHFpxqJpvwuhxSRi+g6z7gZhABs=
|
||||
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8/go.mod h1:K4J7/npM+VAMUeUmTa2JaA02JmyheP0GpRBOUvn3ecc=
|
||||
github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8=
|
||||
github.com/sagernet/utls v1.6.7/go.mod h1:Uua1TKO/FFuAhLr9rkaVnnrTmmiItzDjv1BUb2+ERwM=
|
||||
github.com/sagernet/wireguard-go v0.0.1-beta.5 h1:aBEsxJUMEONwOZqKPIkuAcv4zJV5p6XlzEN04CF0FXc=
|
||||
github.com/sagernet/wireguard-go v0.0.1-beta.5/go.mod h1:jGXij2Gn2wbrWuYNUmmNhf1dwcZtvyAvQoe8Xd8MbUo=
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
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/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA=
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264=
|
||||
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
|
||||
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
|
||||
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
|
||||
@ -146,30 +147,28 @@ github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvv
|
||||
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
||||
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
|
||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/mobile v0.0.0-20231108233038-35478a0c49da h1:gS9sVMAeHM+gVBmM9bTM6vUi/NHv58O3QzJ3vjjN84M=
|
||||
golang.org/x/mobile v0.0.0-20231108233038-35478a0c49da/go.mod h1:IEceR0jfVklLJXrbUe90rfdAFAYDW0SQwKl4qvO1GBQ=
|
||||
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/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@ -177,21 +176,22 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE=
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80=
|
||||
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
|
||||
google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
|
||||
|
||||
@ -45,9 +45,9 @@ type HTTPRequest interface {
|
||||
}
|
||||
|
||||
type HTTPResponse interface {
|
||||
GetHeader(string) string
|
||||
GetHeader(string) *StringBox
|
||||
GetContent() ([]byte, error)
|
||||
GetContentString() (string, error)
|
||||
GetContentString() (*StringBox, error)
|
||||
WriteTo(path string) error
|
||||
}
|
||||
|
||||
@ -204,7 +204,7 @@ type httpResponse struct {
|
||||
}
|
||||
|
||||
func (h *httpResponse) errorString() string {
|
||||
content, err := h.GetContentString()
|
||||
content, err := h.getContentString()
|
||||
if err != nil {
|
||||
return fmt.Sprint("HTTP ", h.Status)
|
||||
}
|
||||
@ -214,8 +214,8 @@ func (h *httpResponse) errorString() string {
|
||||
return fmt.Sprint("HTTP ", h.Status, ": ", content)
|
||||
}
|
||||
|
||||
func (h *httpResponse) GetHeader(key string) string {
|
||||
return h.Header.Get(key)
|
||||
func (h *httpResponse) GetHeader(key string) *StringBox {
|
||||
return wrapString(h.Header.Get(key))
|
||||
}
|
||||
|
||||
func (h *httpResponse) GetContent() ([]byte, error) {
|
||||
@ -226,7 +226,15 @@ func (h *httpResponse) GetContent() ([]byte, error) {
|
||||
return h.content, h.contentError
|
||||
}
|
||||
|
||||
func (h *httpResponse) GetContentString() (string, error) {
|
||||
func (h *httpResponse) GetContentString() (*StringBox, error) {
|
||||
content, err := h.getContentString()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return wrapString(content), nil
|
||||
}
|
||||
|
||||
func (h *httpResponse) getContentString() (string, error) {
|
||||
content, err := h.GetContent()
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
@ -3,8 +3,12 @@
|
||||
chmod -R 777 .build 2>/dev/null
|
||||
rm -rf .build 2>/dev/null
|
||||
|
||||
if [ -z "$GOPATH" ]; then
|
||||
GOPATH=$(go env GOPATH)
|
||||
fi
|
||||
|
||||
# Install gomobile
|
||||
if [ ! -f "$GOPATH/bin/gomobile" ]; then
|
||||
if [ ! -f "$GOPATH/bin/gomobile-matsuri" ]; then
|
||||
git clone https://github.com/MatsuriDayo/gomobile.git
|
||||
pushd gomobile/cmd
|
||||
pushd gomobile
|
||||
@ -15,6 +19,8 @@ if [ ! -f "$GOPATH/bin/gomobile" ]; then
|
||||
popd
|
||||
popd
|
||||
rm -rf gomobile
|
||||
mv "$GOPATH/bin/gomobile" "$GOPATH/bin/gomobile-matsuri"
|
||||
mv "$GOPATH/bin/gobind" "$GOPATH/bin/gobind-matsuri"
|
||||
fi
|
||||
|
||||
gomobile init
|
||||
gomobile-matsuri init
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"net/netip"
|
||||
|
||||
tun "github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
"github.com/sagernet/sing/common/x/list"
|
||||
)
|
||||
|
||||
@ -28,8 +29,8 @@ func (i *interfaceMonitor) DefaultInterfaceIndex(destination netip.Addr) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (i *interfaceMonitor) DefaultInterface(destination netip.Addr) (string, int) {
|
||||
return "", 0
|
||||
func (i *interfaceMonitor) DefaultInterface() *control.Interface {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *interfaceMonitor) OverrideAndroidVPN() bool {
|
||||
|
||||
@ -12,7 +12,6 @@ import (
|
||||
|
||||
"github.com/matsuridayo/libneko/neko_common"
|
||||
"github.com/matsuridayo/libneko/neko_log"
|
||||
boxmain "github.com/sagernet/sing-box/cmd/sing-box"
|
||||
"github.com/sagernet/sing-box/nekoutils"
|
||||
)
|
||||
|
||||
@ -58,7 +57,6 @@ func InitCore(process, cachePath, internalAssets, externalAssets string,
|
||||
neko_log.LogWriterDisable = !logEnable
|
||||
neko_log.TruncateOnStart = isBgProcess
|
||||
neko_log.SetupLog(int(maxLogSizeKb)*1024, filepath.Join(cachePath, "neko.log"))
|
||||
boxmain.SetDisableColor(true)
|
||||
|
||||
// nekoutils
|
||||
nekoutils.Selector_OnProxySelected = intfNB4A.Selector_OnProxySelected
|
||||
|
||||
@ -18,7 +18,6 @@ import (
|
||||
sblog "github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
tun "github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
@ -36,7 +35,7 @@ func (w *boxPlatformInterfaceWrapper) ReadWIFIState() adapter.WIFIState {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *boxPlatformInterfaceWrapper) Initialize(ctx context.Context, router adapter.Router) error {
|
||||
func (w *boxPlatformInterfaceWrapper) Initialize(n adapter.NetworkManager) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -44,13 +43,9 @@ func (w *boxPlatformInterfaceWrapper) UsePlatformAutoDetectInterfaceControl() bo
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *boxPlatformInterfaceWrapper) AutoDetectInterfaceControl() control.Func {
|
||||
func (w *boxPlatformInterfaceWrapper) AutoDetectInterfaceControl(fd int) error {
|
||||
// "protect"
|
||||
return func(network, address string, conn syscall.RawConn) error {
|
||||
return control.Raw(conn, func(fd uintptr) error {
|
||||
return intfBox.AutoDetectInterfaceControl(int32(fd))
|
||||
})
|
||||
}
|
||||
return intfBox.AutoDetectInterfaceControl(int32(fd))
|
||||
}
|
||||
|
||||
func (w *boxPlatformInterfaceWrapper) OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error) {
|
||||
@ -92,7 +87,7 @@ func (w *boxPlatformInterfaceWrapper) UsePlatformInterfaceGetter() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (w *boxPlatformInterfaceWrapper) Interfaces() ([]control.Interface, error) {
|
||||
func (w *boxPlatformInterfaceWrapper) Interfaces() ([]adapter.NetworkInterface, error) {
|
||||
return nil, errors.New("wtf")
|
||||
}
|
||||
|
||||
@ -100,6 +95,10 @@ func (w *boxPlatformInterfaceWrapper) IncludeAllNetworks() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (w *boxPlatformInterfaceWrapper) SendNotification(notification *platform.Notification) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Android not using
|
||||
|
||||
func (w *boxPlatformInterfaceWrapper) UnderNetworkExtension() bool {
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
PACKAGE_NAME=moe.nb4a
|
||||
VERSION_NAME=1.3.2
|
||||
VERSION_CODE=36
|
||||
VERSION_NAME=1.3.5
|
||||
VERSION_CODE=39
|
||||
|
||||
Loading…
Reference in New Issue
Block a user