From 1335f1c4c77af3c40d5905ba4134f7c0de332cfd Mon Sep 17 00:00:00 2001 From: Roman Syuzyov Date: Fri, 12 Jun 2026 14:04:53 +0500 Subject: [PATCH] fix: exclude loopback from NFQUEUE interception on Linux Heavy responses from local services on 127.0.0.0/8 stalled while ProxyBridge was active, even with no rules or proxy configured. The lo interface uses an MTU of 65536, so loopback TCP segments (~64 KB) do not survive the NFQUEUE -> userspace -> reinject path; small responses fit in the initial window and were unaffected. Insert `-o lo -j ACCEPT` in mangle/OUTPUT before the NFQUEUE rules so loopback bypasses interception entirely, and remove it symmetrically in both cleanup paths. Loopback is never proxied in the default configuration, matching the Windows default behaviour. Co-Authored-By: Claude Opus 4.8 Signed-off-by: Roman Syuzyov --- Linux/src/ProxyBridge.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Linux/src/ProxyBridge.c b/Linux/src/ProxyBridge.c index 0bed311..820f0a9 100644 --- a/Linux/src/ProxyBridge.c +++ b/Linux/src/ProxyBridge.c @@ -2732,12 +2732,15 @@ bool ProxyBridge_Start(void) // setup iptables rules for packet interception - USE MANGLE table so it runs BEFORE nat log_message("setting up iptables rules"); - // mangle table runs before nat, so we can mark packets there + // mangle table runs before nat, so we can mark packets there. + // Exclude loopback first: local (lo) traffic must never be queued and reinjected, + // otherwise non-trivial 127.0.0.0/8 responses stall. Loopback never needs proxying. + int ret0 = run_iptables_cmd("-t", "mangle", "-A", "OUTPUT", "-o", "lo", "-j", "ACCEPT", NULL, NULL, NULL, NULL, NULL, NULL); int ret1 = run_iptables_cmd("-t", "mangle", "-A", "OUTPUT", "-p", "tcp", "-j", "NFQUEUE", "--queue-num", "0", NULL, NULL, NULL, NULL); int ret2 = run_iptables_cmd("-t", "mangle", "-A", "OUTPUT", "-p", "udp", "-j", "NFQUEUE", "--queue-num", "0", NULL, NULL, NULL, NULL); - if (ret1 != 0 || ret2 != 0) { - log_message("failed to add iptables rules ret1=%d ret2=%d", ret1, ret2); + if (ret0 != 0 || ret1 != 0 || ret2 != 0) { + log_message("failed to add iptables rules ret0=%d ret1=%d ret2=%d", ret0, ret1, ret2); } else { log_message("iptables nfqueue rules added successfully"); } @@ -2779,10 +2782,12 @@ bool ProxyBridge_Stop(void) running = false; // cleanup iptables + int ret0 = run_iptables_cmd("-t", "mangle", "-D", "OUTPUT", "-o", "lo", "-j", "ACCEPT", NULL, NULL, NULL, NULL, NULL, NULL); int ret1 = run_iptables_cmd("-t", "mangle", "-D", "OUTPUT", "-p", "tcp", "-j", "NFQUEUE", "--queue-num", "0", NULL, NULL, NULL, NULL); int ret2 = run_iptables_cmd("-t", "mangle", "-D", "OUTPUT", "-p", "udp", "-j", "NFQUEUE", "--queue-num", "0", NULL, NULL, NULL, NULL); int ret3 = run_iptables_cmd("-t", "nat", "-D", "OUTPUT", "-p", "tcp", "-m", "mark", "--mark", "1", "-j", "REDIRECT", "--to-port", "34010"); int ret4 = run_iptables_cmd("-t", "nat", "-D", "OUTPUT", "-p", "udp", "-m", "mark", "--mark", "2", "-j", "REDIRECT", "--to-port", "34011"); + (void)ret0; (void)ret1; (void)ret2; (void)ret3; @@ -3041,6 +3046,7 @@ static void library_cleanup(void) { // Even if not running, ensure iptables rules are removed // This handles cases where the app crashed before calling Stop + run_iptables_cmd("-t", "mangle", "-D", "OUTPUT", "-o", "lo", "-j", "ACCEPT", NULL, NULL, NULL, NULL, NULL, NULL); run_iptables_cmd("-t", "mangle", "-D", "OUTPUT", "-p", "tcp", "-j", "NFQUEUE", "--queue-num", "0", NULL, NULL, NULL, NULL); run_iptables_cmd("-t", "mangle", "-D", "OUTPUT", "-p", "udp", "-j", "NFQUEUE", "--queue-num", "0", NULL, NULL, NULL, NULL); run_iptables_cmd("-t", "nat", "-D", "OUTPUT", "-p", "tcp", "-m", "mark", "--mark", "1", "-j", "REDIRECT", "--to-port", "34010");