diff --git a/core/src/main/cpp/main.c b/core/src/main/cpp/main.c
index b4b814d218d9a42d5c1bc9c9625445450f38c190..6c1f2ecebe9a7f6adbd39b902c557153a446344a 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 a072c8fbb640728f53b730380ccf6aa4f79ece5f..baa3408649fca1466e2cc9d38334ab4c581729e6 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 6a2c097a2cd05844816d8cad3300db83179c1327..d6c3a7512a5503bbf444032504631b394d8b88e3 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 a5e26f1305dab3b39f88ca3f956ae66e898abd61..535f9fa5f18405f3e526fe647ae8be78032fcc44 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 cd65a2dee0ac4e3e374da781605e174b9fedf425..eac180e169e9787e09c05906e64401061581e24e 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 7794cc36ae8831dbd94dcf8a49837efdf6098a01..a775853c79e2c013d2fdda47a20d9e6824dff53d 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 5dad3e4d3e99f2a57db36872ece0069464885184..a2af80159c15e1c37703dae943110c650c337ecb 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 2668659841dfe2e59d39c3dd91c7f39289cea54c..2c8a7c20975dadb9dfae9948609f9f44dd893640 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 @@
     <string name="sources">源代碼</string>
     <string name="clash_core">Clash 核心</string>
     <string name="name_server_policy">Name Server ç­–ç•¥</string>
+    <string name="block_loopback">阻止本地迴環</string>
+    <string name="block_loopback_summary">阻止本地迴環連接</string>
 </resources>
\ 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 eb7b62e4f54458a5cb74b294dbce5aef9262e1b8..ca70d250563e4da50481e5849960f56dcab4966b 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 @@
     <string name="sources">源代碼</string>
     <string name="clash_core">Clash 核心</string>
     <string name="name_server_policy">Name Server ç­–ç•¥</string>
+    <string name="block_loopback">阻止本地迴環</string>
+    <string name="block_loopback_summary">阻止本地迴環連接</string>
 </resources>
\ 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 9bddcbaebdd640ac701521c28e8913536a9b4a5d..46c370fb92512773f3357474047d32eb47f3b02b 100644
--- a/design/src/main/res/values-zh/strings.xml
+++ b/design/src/main/res/values-zh/strings.xml
@@ -211,4 +211,6 @@
     <string name="sources">源代码</string>
     <string name="clash_core">Clash 核心</string>
     <string name="name_server_policy">Name Server ç­–ç•¥</string>
+    <string name="block_loopback">阻止本地回环</string>
+    <string name="block_loopback_summary">阻止本地回环连接</string>
 </resources>
\ 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 b2c713296888f9cf57be2fdcbbcacb3f5e0c02df..097edfc04d6dec01eb1e47459eeff93647d311cc 100644
--- a/design/src/main/res/values/strings.xml
+++ b/design/src/main/res/values/strings.xml
@@ -119,6 +119,8 @@
     <string name="bypass_private_network_summary">Bypass private network addresses</string>
     <string name="dns_hijacking">DNS Hijacking</string>
     <string name="dns_hijacking_summary">Handle all dns packet</string>
+    <string name="block_loopback">Block Loopback</string>
+    <string name="block_loopback_summary">Block loopback connections</string>
     <string name="system_proxy">System Proxy</string>
     <string name="system_proxy_summary">Attach http proxy to VpnService</string>
     <string name="access_control_mode">Access Control Mode</string>
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 93fa1e82e3e19cfda4fd3fa531101e514292897c..57900e9c64e154113116bc632049864ee8560128 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 2e91316c5d68e012879457dd64fb18f35914df76..54944ee062ed02f67d57331e9cf46c6e7ea55d80 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<Unit>(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<Unit>(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 f1c3219080f6aae815affe1b9dd5cd0780672def..7a997d24cc9d5c373c1944f78038e28ba979f539 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