diff --git a/core/src/main/cpp/main.c b/core/src/main/cpp/main.c
index b4b814d2..6c1f2ece 100644
--- a/core/src/main/cpp/main.c
+++ b/core/src/main/cpp/main.c
@@ -98,15 +98,15 @@ Java_com_github_kr328_clash_core_bridge_Bridge_nativeNotifyInstalledAppChanged(J
JNIEXPORT void JNICALL
Java_com_github_kr328_clash_core_bridge_Bridge_nativeStartTun(JNIEnv *env, jobject thiz,
jint fd, jint mtu,
- jstring gateway, jstring dns,
+ jstring dns, jstring blocking,
jobject cb) {
TRACE_METHOD();
- scoped_string _gateway = get_string(gateway);
+ scoped_string _blocking = get_string(blocking);
scoped_string _dns = get_string(dns);
jobject _interface = new_global(cb);
- startTun(fd, mtu, _gateway, _dns, _interface);
+ startTun(fd, mtu, _dns, _blocking, _interface);
}
JNIEXPORT void JNICALL
diff --git a/core/src/main/golang/tun/tcp.go b/core/src/main/golang/tun/tcp.go
index a072c8fb..baa34086 100644
--- a/core/src/main/golang/tun/tcp.go
+++ b/core/src/main/golang/tun/tcp.go
@@ -20,6 +20,7 @@ func (a *adapter) tcp() {
defer log.Infoln("[ATUN] TCP listener exited")
defer a.stack.Close()
+accept:
for {
conn, err := a.stack.TCP().Accept()
if err != nil {
@@ -34,9 +35,11 @@ func (a *adapter) tcp() {
continue
}
- // drop all connections connect to gateway
- if a.gateway.Contains(tAddr.IP) {
- continue
+ // drop all connections connect to blocking list
+ for _, b := range a.blocking {
+ if b.Contains(tAddr.IP) {
+ continue accept
+ }
}
metadata := &C.Metadata{
diff --git a/core/src/main/golang/tun/tun.go b/core/src/main/golang/tun/tun.go
index 6a2c097a..d6c3a751 100644
--- a/core/src/main/golang/tun/tun.go
+++ b/core/src/main/golang/tun/tun.go
@@ -3,6 +3,7 @@ package tun
import (
"net"
"os"
+ "strings"
"sync"
"syscall"
@@ -10,13 +11,13 @@ import (
)
type adapter struct {
- device *os.File
- stack tun2socket.Stack
- gateway *net.IPNet
- dns net.IP
- mtu int
- once sync.Once
- stop func()
+ device *os.File
+ stack tun2socket.Stack
+ blocking []*net.IPNet
+ dns net.IP
+ mtu int
+ once sync.Once
+ stop func()
}
var lock sync.Mutex
@@ -27,7 +28,7 @@ func (a *adapter) close() {
_ = a.device.Close()
}
-func Start(fd, mtu int, gateway, dns string, stop func()) error {
+func Start(fd, mtu int, dns string, blocking string, stop func()) error {
lock.Lock()
defer lock.Unlock()
@@ -46,16 +47,28 @@ func Start(fd, mtu int, gateway, dns string, stop func()) error {
}
dn := net.ParseIP(dns)
- _, gw, _ := net.ParseCIDR(gateway)
+
+ var blk []*net.IPNet
+
+ for _, b := range strings.Split(blocking, ";") {
+ _, n, err := net.ParseCIDR(b)
+ if err != nil {
+ device.Close()
+
+ return err
+ }
+
+ blk = append(blk, n)
+ }
instance = &adapter{
- device: device,
- stack: stack,
- gateway: gw,
- dns: dn,
- mtu: mtu,
- once: sync.Once{},
- stop: stop,
+ device: device,
+ stack: stack,
+ blocking: blk,
+ dns: dn,
+ mtu: mtu,
+ once: sync.Once{},
+ stop: stop,
}
go instance.rx()
diff --git a/core/src/main/golang/tun/udp.go b/core/src/main/golang/tun/udp.go
index a5e26f13..535f9fa5 100644
--- a/core/src/main/golang/tun/udp.go
+++ b/core/src/main/golang/tun/udp.go
@@ -44,6 +44,7 @@ func (a *adapter) udp() {
defer log.Infoln("[ATUN] UDP receiver exited")
defer a.stack.Close()
+read:
for {
buf := pool.Get(a.mtu)
@@ -60,11 +61,11 @@ func (a *adapter) udp() {
continue
}
- // drop all packets send to gateway
- if a.gateway.Contains(tAddr.IP) {
- pool.Put(buf)
-
- continue
+ // drop all packet send to blocking list
+ for _, b := range a.blocking {
+ if b.Contains(tAddr.IP) {
+ continue read
+ }
}
pkt := &packet{
diff --git a/core/src/main/java/com/github/kr328/clash/core/Clash.kt b/core/src/main/java/com/github/kr328/clash/core/Clash.kt
index cd65a2de..eac180e1 100644
--- a/core/src/main/java/com/github/kr328/clash/core/Clash.kt
+++ b/core/src/main/java/com/github/kr328/clash/core/Clash.kt
@@ -61,12 +61,12 @@ object Clash {
fun startTun(
fd: Int,
mtu: Int,
- gateway: String,
dns: String,
+ blocking: String,
markSocket: (Int) -> Boolean,
querySocketUid: (protocol: Int, source: InetSocketAddress, target: InetSocketAddress) -> Int
) {
- Bridge.nativeStartTun(fd, mtu, gateway, dns, object : TunInterface {
+ Bridge.nativeStartTun(fd, mtu, dns, blocking, object : TunInterface {
override fun markSocket(fd: Int) {
markSocket(fd)
}
diff --git a/core/src/main/java/com/github/kr328/clash/core/bridge/Bridge.kt b/core/src/main/java/com/github/kr328/clash/core/bridge/Bridge.kt
index 7794cc36..a775853c 100644
--- a/core/src/main/java/com/github/kr328/clash/core/bridge/Bridge.kt
+++ b/core/src/main/java/com/github/kr328/clash/core/bridge/Bridge.kt
@@ -17,7 +17,7 @@ object Bridge {
external fun nativeQueryTrafficTotal(): Long
external fun nativeNotifyDnsChanged(dnsList: String)
external fun nativeNotifyInstalledAppChanged(uidList: String)
- external fun nativeStartTun(fd: Int, mtu: Int, gateway: String, dns: String, cb: TunInterface)
+ external fun nativeStartTun(fd: Int, mtu: Int, dns: String, blocking: String, cb: TunInterface)
external fun nativeStopTun()
external fun nativeStartHttp(listenAt: String): String?
external fun nativeStopHttp()
diff --git a/design/src/main/java/com/github/kr328/clash/design/NetworkSettingsDesign.kt b/design/src/main/java/com/github/kr328/clash/design/NetworkSettingsDesign.kt
index 5dad3e4d..a2af8015 100644
--- a/design/src/main/java/com/github/kr328/clash/design/NetworkSettingsDesign.kt
+++ b/design/src/main/java/com/github/kr328/clash/design/NetworkSettingsDesign.kt
@@ -70,6 +70,13 @@ class NetworkSettingsDesign(
configure = vpnDependencies::add,
)
+ switch(
+ value = srvStore::blockLoopback,
+ title = R.string.block_loopback,
+ summary = R.string.block_loopback_summary,
+ configure = vpnDependencies::add,
+ )
+
if (Build.VERSION.SDK_INT >= 29) {
switch(
value = srvStore::systemProxy,
diff --git a/design/src/main/res/values-zh-rHK/strings.xml b/design/src/main/res/values-zh-rHK/strings.xml
index 26686598..2c8a7c20 100644
--- a/design/src/main/res/values-zh-rHK/strings.xml
+++ b/design/src/main/res/values-zh-rHK/strings.xml
@@ -211,4 +211,6 @@
源代碼
Clash 核心
Name Server 策略
+ 阻止本地迴環
+ 阻止本地迴環連接
\ No newline at end of file
diff --git a/design/src/main/res/values-zh-rTW/strings.xml b/design/src/main/res/values-zh-rTW/strings.xml
index eb7b62e4..ca70d250 100644
--- a/design/src/main/res/values-zh-rTW/strings.xml
+++ b/design/src/main/res/values-zh-rTW/strings.xml
@@ -211,4 +211,6 @@
源代碼
Clash 核心
Name Server 策略
+ 阻止本地迴環
+ 阻止本地迴環連接
\ No newline at end of file
diff --git a/design/src/main/res/values-zh/strings.xml b/design/src/main/res/values-zh/strings.xml
index 9bddcbae..46c370fb 100644
--- a/design/src/main/res/values-zh/strings.xml
+++ b/design/src/main/res/values-zh/strings.xml
@@ -211,4 +211,6 @@
源代码
Clash 核心
Name Server 策略
+ 阻止本地回环
+ 阻止本地回环连接
\ No newline at end of file
diff --git a/design/src/main/res/values/strings.xml b/design/src/main/res/values/strings.xml
index b2c71329..097edfc0 100644
--- a/design/src/main/res/values/strings.xml
+++ b/design/src/main/res/values/strings.xml
@@ -119,6 +119,8 @@
Bypass private network addresses
DNS Hijacking
Handle all dns packet
+ Block Loopback
+ Block loopback connections
System Proxy
Attach http proxy to VpnService
Access Control Mode
diff --git a/service/src/main/java/com/github/kr328/clash/service/TunService.kt b/service/src/main/java/com/github/kr328/clash/service/TunService.kt
index 93fa1e82..57900e9c 100644
--- a/service/src/main/java/com/github/kr328/clash/service/TunService.kt
+++ b/service/src/main/java/com/github/kr328/clash/service/TunService.kt
@@ -216,11 +216,16 @@ class TunService : VpnService(), CoroutineScope by CoroutineScope(Dispatchers.De
}
}
+ val blocking = mutableListOf("$TUN_GATEWAY/$TUN_SUBNET_PREFIX")
+ if (store.blockLoopback) {
+ blocking.add(NET_SUBNET_LOOPBACK)
+ }
+
TunModule.TunDevice(
fd = establish()?.detachFd()
?: throw NullPointerException("Establish VPN rejected by system"),
mtu = TUN_MTU,
- gateway = "$TUN_GATEWAY/$TUN_SUBNET_PREFIX",
+ blocking = blocking.joinToString(";"),
dns = if (store.dnsHijacking) NET_ANY else TUN_DNS,
)
}
@@ -234,5 +239,6 @@ class TunService : VpnService(), CoroutineScope by CoroutineScope(Dispatchers.De
private const val TUN_GATEWAY = "172.19.0.1"
private const val TUN_DNS = "172.19.0.2"
private const val NET_ANY = "0.0.0.0"
+ private const val NET_SUBNET_LOOPBACK = "127.0.0.0/8"
}
}
\ No newline at end of file
diff --git a/service/src/main/java/com/github/kr328/clash/service/clash/module/TunModule.kt b/service/src/main/java/com/github/kr328/clash/service/clash/module/TunModule.kt
index 2e91316c..54944ee0 100644
--- a/service/src/main/java/com/github/kr328/clash/service/clash/module/TunModule.kt
+++ b/service/src/main/java/com/github/kr328/clash/service/clash/module/TunModule.kt
@@ -16,7 +16,7 @@ class TunModule(private val vpn: VpnService) : Module(vpn) {
data class TunDevice(
val fd: Int,
val mtu: Int,
- val gateway: String,
+ val blocking: String,
val dns: String,
)
@@ -57,8 +57,8 @@ class TunModule(private val vpn: VpnService) : Module(vpn) {
Clash.startTun(
fd = device.fd,
mtu = device.mtu,
- gateway = device.gateway,
dns = device.dns,
+ blocking = device.blocking,
markSocket = vpn::protect,
querySocketUid = this::queryUid
)
diff --git a/service/src/main/java/com/github/kr328/clash/service/store/ServiceStore.kt b/service/src/main/java/com/github/kr328/clash/service/store/ServiceStore.kt
index f1c32190..7a997d24 100644
--- a/service/src/main/java/com/github/kr328/clash/service/store/ServiceStore.kt
+++ b/service/src/main/java/com/github/kr328/clash/service/store/ServiceStore.kt
@@ -46,6 +46,11 @@ class ServiceStore(context: Context) {
defaultValue = false
)
+ var blockLoopback by store.boolean(
+ key = "block_loopback",
+ defaultValue = true
+ )
+
var dynamicNotification by store.boolean(
key = "dynamic_notification",
defaultValue = true