Skip to content

Commit 178c66e

Browse files
committed
fix(transparentproxy): also drop self-dial to the listener's own address
Extend the self-loop guard (review follow-up from mrsabath + CodeRabbit): in addition to a loopback original destination, drop when the recovered dst equals the connection's own LocalAddr (host:port). This covers a podIP:<port> self-dial that could slip past the iptables CLUSTER_CIDRS RETURN if CLUSTER_CIDRS is misconfigured — belt-and-suspenders behind the iptables layer, which remains the primary control. Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> Signed-off-by: Hai Huang <huang195@gmail.com>
1 parent bbffe8f commit 178c66e

1 file changed

Lines changed: 17 additions & 10 deletions

File tree

  • authbridge/authlib/listener/transparentproxy

authbridge/authlib/listener/transparentproxy/server.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,18 +77,25 @@ func (s *Server) dispatch(conn *net.TCPConn) {
7777
return
7878
}
7979
// Defense-in-depth against a self-redirect loop: a genuinely REDIRECTed
80-
// connection never has a loopback original destination (the enforce-redirect
81-
// iptables rules RETURN loopback before the REDIRECT). So a loopback dst here
82-
// means a direct dial to the listener port, where SO_ORIGINAL_DST reports the
83-
// listener's own address — tunnelling to it would spiral into ever more
84-
// connections/goroutines. Drop it.
85-
if host, _, splitErr := net.SplitHostPort(dst); splitErr == nil {
80+
// connection's original destination is always some external host — never
81+
// this listener itself. Two ways a connection could point back at us:
82+
// - a loopback dst (a direct dial to 127.0.0.1:<port>); the enforce-redirect
83+
// rules RETURN loopback before the REDIRECT, so a real capture never has one;
84+
// - the listener's own address (e.g. a podIP:<port> self-dial that slipped
85+
// past the iptables CLUSTER_CIDRS RETURN under a misconfigured CIDR set).
86+
// Tunnelling either would spiral into ever more connections/goroutines. The
87+
// iptables layer is the primary control; this is belt-and-suspenders. Drop it.
88+
selfLoop := dst == conn.LocalAddr().String()
89+
if host, _, splitErr := net.SplitHostPort(dst); !selfLoop && splitErr == nil {
8690
if ip := net.ParseIP(host); ip != nil && ip.IsLoopback() {
87-
slog.Warn("transparent-proxy: dropping connection whose original destination is loopback (not a redirect; would self-loop)",
88-
"remote", conn.RemoteAddr().String(), "dst", dst)
89-
_ = conn.Close()
90-
return
91+
selfLoop = true
9192
}
9293
}
94+
if selfLoop {
95+
slog.Warn("transparent-proxy: dropping self-referential connection (would self-loop)",
96+
"remote", conn.RemoteAddr().String(), "dst", dst, "local", conn.LocalAddr().String())
97+
_ = conn.Close()
98+
return
99+
}
93100
s.handle(conn, dst)
94101
}

0 commit comments

Comments
 (0)