From 735590d24499f182a9a58aaa521ed82b418d82e0 Mon Sep 17 00:00:00 2001 From: Codescribe Date: Thu, 4 Jun 2026 19:35:52 -0400 Subject: [PATCH] fix: allow intercept fallback for default listener --- cmd/cli/cli.go | 12 ++++++++++- cmd/cli/cli_intercept_listener_test.go | 28 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 cmd/cli/cli_intercept_listener_test.go diff --git a/cmd/cli/cli.go b/cmd/cli/cli.go index bf6ea0e..b75856f 100644 --- a/cmd/cli/cli.go +++ b/cmd/cli/cli.go @@ -1258,7 +1258,7 @@ func tryUpdateListenerConfigIntercept(cfg *ctrld.Config, notifyFunc func(), fata return false, true } - hasExplicitConfig := lc.IP != "" && lc.IP != "0.0.0.0" && lc.Port != 0 + hasExplicitConfig := isExplicitInterceptListener(lc.IP, lc.Port) if !hasExplicitConfig { // Set defaults for intercept mode if lc.IP == "" || lc.IP == "0.0.0.0" { @@ -1316,6 +1316,16 @@ func tryUpdateListenerConfigIntercept(cfg *ctrld.Config, notifyFunc func(), fata return updated, false } +func isExplicitInterceptListener(ip string, port int) bool { + if ip == "" || ip == "0.0.0.0" || port == 0 { + return false + } + // 127.0.0.1:53 is the default macOS DNS-intercept listener. It can appear + // in generated/custom Control D configs, but it should still be allowed to + // fall back to 127.0.0.1:5354 when mDNSResponder already owns port 53. + return !(ip == "127.0.0.1" && port == 53) +} + // tryUpdateListenerConfig tries updating listener config with a working one. // If fatal is true, and there's listen address conflicted, the function do // fatal error. diff --git a/cmd/cli/cli_intercept_listener_test.go b/cmd/cli/cli_intercept_listener_test.go new file mode 100644 index 0000000..489b7ac --- /dev/null +++ b/cmd/cli/cli_intercept_listener_test.go @@ -0,0 +1,28 @@ +package cli + +import "testing" + +func TestIsExplicitInterceptListener(t *testing.T) { + tests := []struct { + name string + ip string + port int + want bool + }{ + {name: "empty", ip: "", port: 0, want: false}, + {name: "wildcard", ip: "0.0.0.0", port: 53, want: false}, + {name: "zero port", ip: "127.0.0.1", port: 0, want: false}, + {name: "default intercept listener", ip: "127.0.0.1", port: 53, want: false}, + {name: "fallback port explicit", ip: "127.0.0.1", port: 5354, want: true}, + {name: "custom loopback explicit", ip: "127.0.0.2", port: 53, want: true}, + {name: "custom address explicit", ip: "192.0.2.10", port: 53, want: true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := isExplicitInterceptListener(tt.ip, tt.port); got != tt.want { + t.Fatalf("isExplicitInterceptListener(%q, %d) = %v, want %v", tt.ip, tt.port, got, tt.want) + } + }) + } +}