Skip to content

Commit b6bc43d

Browse files
authored
Merge pull request #63 from HnDK0/fix-local-auth
fix: add auth to local mixed inbound to prevent IP leak
2 parents dd1ef3c + 5f93cd7 commit b6bc43d

17 files changed

Lines changed: 94 additions & 10 deletions

File tree

app/src/main/java/io/nekohasekai/sagernet/Constants.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ object Key {
4141
const val CONCURRENT_DIAL = "concurrentDial"
4242

4343
const val MIXED_PORT = "mixedPort"
44+
const val MIXED_SECRET = "mixedSecret" // storage key for the generated inbound secret
45+
const val MIXED_USERNAME = "neko" // username presented to the authed mixed inbound
4446
const val ALLOW_ACCESS = "allowAccess"
4547
const val SPEED_INTERVAL = "speedInterval"
4648
const val SHOW_DIRECT_SPEED = "showDirectSpeed"

app/src/main/java/io/nekohasekai/sagernet/bg/BaseService.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ class BaseService {
236236
fun stopRunner(restart: Boolean = false, msg: String? = null) {
237237
DataStore.baseService = null
238238
DataStore.vpnService = null
239+
DataStore.mixedInboundAuthed = false
239240

240241
if (data.state == State.Stopping) return
241242
data.notification?.destroy()

app/src/main/java/io/nekohasekai/sagernet/bg/proto/BoxInstance.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ abstract class BoxInstance(
4646

4747
protected open fun buildConfig() {
4848
config = buildConfig(profile)
49+
DataStore.mixedInboundAuthed = DataStore.mixedInboundNeedsAuth
4950
}
5051

5152
protected open suspend fun loadConfig() {
@@ -219,4 +220,4 @@ abstract class BoxInstance(
219220
}
220221
}
221222

222-
}
223+
}

app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.nekohasekai.sagernet.database
22

33
import android.os.Binder
4+
import android.os.Build
45
import androidx.preference.PreferenceDataStore
56
import io.nekohasekai.sagernet.CONNECTION_TEST_URL
67
import io.nekohasekai.sagernet.GroupType
@@ -27,6 +28,9 @@ object DataStore : OnPreferenceDataStoreChangeListener {
2728
@Volatile
2829
var serviceState = BaseService.State.Idle
2930

31+
@Volatile
32+
var mixedInboundAuthed: Boolean = false
33+
3034
val configurationStore = RoomPreferenceDataStore(PublicDatabase.kvPairDao)
3135
val profileCacheStore = RoomPreferenceDataStore(TempDatabase.profileCacheDao)
3236

@@ -134,10 +138,27 @@ object DataStore : OnPreferenceDataStoreChangeListener {
134138

135139
// hopefully hashCode = mHandle doesn't change, currently this is true from KitKat to Nougat
136140
private val userIndex by lazy { Binder.getCallingUserHandle().hashCode() }
141+
val mixedSecret: String
142+
@Synchronized get() {
143+
var s = configurationStore.getString(Key.MIXED_SECRET)
144+
if (s.isNullOrEmpty()) {
145+
s = java.util.UUID.randomUUID().toString().replace("-", "")
146+
configurationStore.putString(Key.MIXED_SECRET, s)
147+
}
148+
return s
149+
}
150+
137151
var mixedPort: Int
138152
get() = getLocalPort(Key.MIXED_PORT, 2080)
139153
set(value) = saveLocalPort(Key.MIXED_PORT, value)
140154

155+
val mixedInboundNeedsAuth: Boolean
156+
get() = serviceMode == Key.MODE_VPN &&
157+
!(appendHttpProxy && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
158+
159+
val mixedInboundUser: String get() = if (mixedInboundAuthed) Key.MIXED_USERNAME else ""
160+
val mixedInboundPass: String get() = if (mixedInboundAuthed) mixedSecret else ""
161+
141162
fun initGlobal() {
142163
if (configurationStore.getString(Key.MIXED_PORT) == null) {
143164
mixedPort = mixedPort

app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,12 @@ fun buildConfig(
254254
domain_strategy = genDomainStrategy(DataStore.resolveDestination)
255255
sniff = needSniff
256256
sniff_override_destination = needSniffOverride
257+
if (DataStore.mixedInboundNeedsAuth) {
258+
users = listOf(User().also { u ->
259+
u.username = Key.MIXED_USERNAME
260+
u.password = DataStore.mixedSecret
261+
})
262+
}
257263
})
258264
}
259265

app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,11 @@ object RawUpdater : GroupUpdater() {
6161
} else {
6262

6363
val response = Libcore.newHttpClient().apply {
64-
trySocks5(DataStore.mixedPort)
64+
trySocks5(
65+
DataStore.mixedPort,
66+
DataStore.mixedInboundUser,
67+
DataStore.mixedInboundPass
68+
)
6569
tryH3Direct()
6670
when (DataStore.appTLSVersion) {
6771
"1.3" -> restrictedTLS()

app/src/main/java/io/nekohasekai/sagernet/ui/AboutFragment.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,11 @@ class AboutFragment : ToolbarFragment(R.layout.layout_about) {
216216
try {
217217
val client = Libcore.newHttpClient().apply {
218218
modernTLS()
219-
trySocks5(DataStore.mixedPort)
219+
trySocks5(
220+
DataStore.mixedPort,
221+
DataStore.mixedInboundUser,
222+
DataStore.mixedInboundPass
223+
)
220224
}
221225
val response = client.newRequest().apply {
222226
if (checkPreview) {
@@ -276,4 +280,4 @@ class AboutFragment : ToolbarFragment(R.layout.layout_about) {
276280

277281
}
278282

279-
}
283+
}

app/src/main/java/io/nekohasekai/sagernet/ui/AssetsActivity.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,11 @@ class AssetsActivity : ThemedActivity() {
282282
val client = Libcore.newHttpClient().apply {
283283
modernTLS()
284284
keepAlive()
285-
trySocks5(DataStore.mixedPort)
285+
trySocks5(
286+
DataStore.mixedPort,
287+
DataStore.mixedInboundUser,
288+
DataStore.mixedInboundPass
289+
)
286290
}
287291

288292
try {
@@ -345,7 +349,11 @@ class AssetsActivity : ThemedActivity() {
345349
val client = Libcore.newHttpClient().apply {
346350
modernTLS()
347351
keepAlive()
348-
trySocks5(DataStore.mixedPort)
352+
trySocks5(
353+
DataStore.mixedPort,
354+
DataStore.mixedInboundUser,
355+
DataStore.mixedInboundPass
356+
)
349357
}
350358
try {
351359
val response = client.newRequest().apply {

app/src/main/java/io/nekohasekai/sagernet/ui/SettingsPreferenceFragment.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,23 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
175175
}
176176

177177
mixedPort.onPreferenceChangeListener = reloadListener
178-
appendHttpProxy.onPreferenceChangeListener = reloadListener
178+
appendHttpProxy.setOnPreferenceChangeListener { _, newValue ->
179+
if (newValue as Boolean) {
180+
MaterialAlertDialogBuilder(requireContext()).apply {
181+
setTitle(R.string.append_http_proxy_security_title)
182+
setMessage(R.string.append_http_proxy_security_message)
183+
setNegativeButton(android.R.string.cancel, null)
184+
setPositiveButton(R.string.enable_anyway) { _, _ ->
185+
appendHttpProxy.isChecked = true
186+
needReload()
187+
}
188+
}.show()
189+
false
190+
} else {
191+
needReload()
192+
true
193+
}
194+
}
179195
strictRoute.onPreferenceChangeListener = reloadListener
180196
showDirectSpeed.onPreferenceChangeListener = reloadListener
181197
trafficSniffing.onPreferenceChangeListener = reloadListener

app/src/main/res/values-fa/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,9 @@
326326
<string name="connection_test_timeout_error">بدون پاسخ</string>
327327
<string name="append_http_proxy">پراکسی HTTP را به VPN اضافه کنید</string>
328328
<string name="append_http_proxy_sum">پروکسی HTTP مستقیماً از (مرورگر/برخی برنامه‌های پشتیبانی‌شده) بدون استفاده از دستگاه NIC مجازی (نسخه اندروید بالاتر از 10) استفاده می‌شود.</string>
329+
<string name="append_http_proxy_security_title">اطلاعیه امنیتی</string>
330+
<string name="append_http_proxy_security_message">پس از فعال‌سازی، برنامه‌های دیگر در این دستگاه می‌توانند مستقیماً از پورت پروکسی محلی استفاده کنند.\n\nتوصیه: تنها در صورتی که به تمام برنامه‌های نصب‌شده اعتماد دارید، این گزینه را فعال کنید.</string>
331+
<string name="enable_anyway">همچنان فعال کن</string>
329332
<string name="protocol_settings">تنظیمات پروتکل‌ها</string>
330333
<string name="trojan_provider">تأمین‌کننده Trojan</string>
331334
<string name="group_basic">ابتدایی</string>

0 commit comments

Comments
 (0)