pkg: address managed DNS mode review feedback

This commit is contained in:
Dev Scribe
2026-08-24 15:18:01 +07:00
committed by Cuong Manh Le
parent 47dd64b901
commit f0b60f3efa
10 changed files with 86 additions and 24 deletions
+1 -1
View File
@@ -391,7 +391,7 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
// would silently re-enable interception from config. // would silently re-enable interception from config.
if updateConfigInterceptMode(&cfg, interceptMode) { if updateConfigInterceptMode(&cfg, interceptMode) {
updated = true updated = true
p.Info().Msgf("writing intercept_mode = %q to config", cfg.Service.InterceptMode) p.Info().Msgf("writing intercept_mode = %q to config (requested %q)", cfg.Service.InterceptMode, interceptMode)
} }
// Persist firewall_mode to config only when provided via CLI flag. // Persist firewall_mode to config only when provided via CLI flag.
+1 -1
View File
@@ -51,7 +51,7 @@ func InitRunCmd(rootCmd *cobra.Command) *cobra.Command {
_ = runCmd.Flags().MarkHidden("iface") _ = runCmd.Flags().MarkHidden("iface")
runCmd.Flags().StringVarP(&cdUpstreamProto, "proto", "", ctrld.ResolverTypeDOH, `Control D upstream type, either "doh" or "doh3"`) runCmd.Flags().StringVarP(&cdUpstreamProto, "proto", "", ctrld.ResolverTypeDOH, `Control D upstream type, either "doh" or "doh3"`)
runCmd.Flags().BoolVarP(&rfc1918, "rfc1918", "", false, "Listen on RFC1918 addresses when 127.0.0.1 is the only listener") runCmd.Flags().BoolVarP(&rfc1918, "rfc1918", "", false, "Listen on RFC1918 addresses when 127.0.0.1 is the only listener")
runCmd.Flags().StringVarP(&interceptMode, "intercept-mode", "", "", "OS-level DNS interception mode: 'dns' (with VPN split routing) or 'hard' (all DNS through ctrld, no VPN split routing)") runCmd.Flags().StringVarP(&interceptMode, "intercept-mode", "", "", "OS-level DNS interception mode: 'off' (disable interception and clear a persisted intercept_mode), 'dns' (with VPN split routing), or 'hard' (all DNS through ctrld, no VPN split routing)")
runCmd.Flags().StringVarP(&firewallMode, "firewall-mode", "", "off", "DNS-resolved IP allowlist: 'on' blocks connections to IPs not resolved by ctrld, 'off' allows all") runCmd.Flags().StringVarP(&firewallMode, "firewall-mode", "", "off", "DNS-resolved IP allowlist: 'on' blocks connections to IPs not resolved by ctrld, 'off' allows all")
runCmd.FParseErrWhitelist = cobra.FParseErrWhitelist{UnknownFlags: true} runCmd.FParseErrWhitelist = cobra.FParseErrWhitelist{UnknownFlags: true}
+2 -3
View File
@@ -118,8 +118,7 @@ func (sc *ServiceCommand) Start(cmd *cobra.Command, args []string) error {
svcExists := serviceConfigFileExists() svcExists := serviceConfigFileExists()
logger.Debug().Msgf("intercept upgrade check: args=%v interceptOnly=%v svcConfigExists=%v interceptMode=%q", osArgsEarly, interceptOnly, svcExists, interceptMode) logger.Debug().Msgf("intercept upgrade check: args=%v interceptOnly=%v svcConfigExists=%v interceptMode=%q", osArgsEarly, interceptOnly, svcExists, interceptMode)
if interceptOnly && svcExists { if interceptOnly && svcExists {
// Replace any existing split or --intercept-mode=<value> form. Keep an // An explicit "off" argument must override a previously persisted config
// explicit "off" argument so it overrides a previously persisted config
// value while the service clears that value on startup. // value while the service clears that value on startup.
if err := removeServiceFlag("--intercept-mode"); err != nil { if err := removeServiceFlag("--intercept-mode"); err != nil {
logger.Fatal().Err(err).Msg("failed to remove existing intercept mode from service arguments") logger.Fatal().Err(err).Msg("failed to remove existing intercept mode from service arguments")
@@ -511,7 +510,7 @@ NOTE: running "ctrld start" without any arguments will start already installed c
startCmd.Flags().BoolVarP(&startOnly, "start_only", "", false, "Do not install new service") startCmd.Flags().BoolVarP(&startOnly, "start_only", "", false, "Do not install new service")
_ = startCmd.Flags().MarkHidden("start_only") _ = startCmd.Flags().MarkHidden("start_only")
startCmd.Flags().BoolVarP(&rfc1918, "rfc1918", "", false, "Listen on RFC1918 addresses when 127.0.0.1 is the only listener") startCmd.Flags().BoolVarP(&rfc1918, "rfc1918", "", false, "Listen on RFC1918 addresses when 127.0.0.1 is the only listener")
startCmd.Flags().StringVarP(&interceptMode, "intercept-mode", "", "", "OS-level DNS interception mode: 'dns' (with VPN split routing) or 'hard' (all DNS through ctrld, no VPN split routing)") startCmd.Flags().StringVarP(&interceptMode, "intercept-mode", "", "", "OS-level DNS interception mode: 'off' (disable interception and clear a persisted intercept_mode), 'dns' (with VPN split routing), or 'hard' (all DNS through ctrld, no VPN split routing)")
startCmd.Flags().StringVarP(&firewallMode, "firewall-mode", "", "off", "DNS-resolved IP allowlist: 'on' blocks connections to IPs not resolved by ctrld, 'off' allows all") startCmd.Flags().StringVarP(&firewallMode, "firewall-mode", "", "off", "DNS-resolved IP allowlist: 'on' blocks connections to IPs not resolved by ctrld, 'off' allows all")
// Start command alias // Start command alias
+27
View File
@@ -36,3 +36,30 @@ func TestUpdateConfigInterceptMode(t *testing.T) {
}) })
} }
} }
func TestConfiguredInterceptMode(t *testing.T) {
oldInterceptMode := interceptMode
t.Cleanup(func() { interceptMode = oldInterceptMode })
p := &prog{cfg: &ctrld.Config{}}
p.cfg.Service.InterceptMode = "dns"
tests := []struct {
name string
flag string
want string
}{
{name: "empty flag falls back to config", flag: "", want: "dns"},
{name: "explicit off is final", flag: "off", want: "off"},
{name: "explicit hard wins over config", flag: "hard", want: "hard"},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
interceptMode = tc.flag
if got := p.configuredInterceptMode(); got != tc.want {
t.Fatalf("configuredInterceptMode() = %q, want %q", got, tc.want)
}
})
}
}
+1 -1
View File
@@ -45,7 +45,7 @@ var (
cleanup bool cleanup bool
startOnly bool startOnly bool
rfc1918 bool rfc1918 bool
interceptMode string // "", "dns", or "hard" — set via --intercept-mode flag or config interceptMode string // "", "off", "dns", or "hard" — set via --intercept-mode flag or config
dnsIntercept bool // derived: interceptMode == "dns" || interceptMode == "hard" dnsIntercept bool // derived: interceptMode == "dns" || interceptMode == "hard"
hardIntercept bool // derived: interceptMode == "hard" hardIntercept bool // derived: interceptMode == "hard"
firewallMode string // "off" or "on" — set via --firewall-mode flag or config firewallMode string // "off" or "on" — set via --firewall-mode flag or config
+3 -3
View File
@@ -1070,11 +1070,11 @@ func (p *prog) setDNS() {
} }
// configuredInterceptMode resolves the service's effective intercept mode without // configuredInterceptMode resolves the service's effective intercept mode without
// mutating package state. Platform startup preflights use the same precedence as // mutating package state. An explicit flag value, including "off", takes priority
// setDNS so they do not make adapter-DNS decisions from a different mode value. // over the persisted config value.
func (p *prog) configuredInterceptMode() string { func (p *prog) configuredInterceptMode() string {
im := interceptMode im := interceptMode
if im == "" || im == "off" { if im == "" {
im = p.cfg.Service.InterceptMode im = p.cfg.Service.InterceptMode
} }
return im return im
+2 -5
View File
@@ -124,11 +124,8 @@ func (s *systemd) Start() error {
// This is necessary for running self-upgrade flow. // This is necessary for running self-upgrade flow.
func ensureSystemdKillMode(r io.Reader) (opts []*unit.UnitOption, change bool) { func ensureSystemdKillMode(r io.Reader) (opts []*unit.UnitOption, change bool) {
opts, err := unit.DeserializeOptions(r) opts, err := unit.DeserializeOptions(r)
// staticcheck sees only the explicit non-nil sends on the lexer's error // On success the lexer sends nothing and closes the channel, so the receive
// channel, so it reports this comparison as always true. On success the // yields a nil error and this branch is not taken.
// lexer sends nothing and closes the channel, so the receive yields a nil
// error and this branch is not taken.
//lint:ignore SA4023 upstream delivers a nil error by closing the channel
if err != nil { if err != nil {
mainLog.Load().Error().Err(err).Msg("Failed to deserialize options") mainLog.Load().Error().Err(err).Msg("Failed to deserialize options")
return return
+5
View File
@@ -15,6 +15,11 @@ func TestServiceArgumentPresent(t *testing.T) {
if serviceArgumentPresent(out, "off") { if serviceArgumentPresent(out, "off") {
t.Fatal("substring in an unrelated path was mistaken for the off argument") t.Fatal("substring in an unrelated path was mistaken for the off argument")
} }
splitOut := []byte("Array {\n /usr/local/bin/ctrld\n run\n --intercept-mode\n dns\n}\n")
if !serviceArgumentPresent(splitOut, "--intercept-mode") {
t.Fatal("standalone flag argument was not found")
}
} }
func TestServiceFlagPosition(t *testing.T) { func TestServiceFlagPosition(t *testing.T) {
+1 -1
View File
@@ -89,7 +89,7 @@ func verifyServiceRegistration() error {
mainLog.Load().Debug().Msgf("Service registry: BinaryPathName = %q", config.BinaryPathName) mainLog.Load().Debug().Msgf("Service registry: BinaryPathName = %q", config.BinaryPathName)
// If intercept mode is set, verify the flag is present in BinPath. // If intercept mode is set, verify the flag is present in BinPath.
if interceptMode == "dns" || interceptMode == "hard" { if interceptMode == "off" || interceptMode == "dns" || interceptMode == "hard" {
if !strings.Contains(config.BinaryPathName, "--intercept-mode") { if !strings.Contains(config.BinaryPathName, "--intercept-mode") {
return fmt.Errorf("service registry: --intercept-mode flag missing from BinaryPathName (expected mode %q)", interceptMode) return fmt.Errorf("service registry: --intercept-mode flag missing from BinaryPathName (expected mode %q)", interceptMode)
} }
+43 -9
View File
@@ -2,7 +2,7 @@
set -eu set -eu
repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd) repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)
postinstall="$repo_root/scripts/pkg/postinstall" postinstall_source="$repo_root/scripts/pkg/postinstall"
fixture=$(mktemp -d "${TMPDIR:-/tmp}/ctrld-pkg-intercept.XXXXXX") fixture=$(mktemp -d "${TMPDIR:-/tmp}/ctrld-pkg-intercept.XXXXXX")
trap 'rm -rf "$fixture"' EXIT HUP INT TERM trap 'rm -rf "$fixture"' EXIT HUP INT TERM
@@ -39,10 +39,12 @@ EOF
cat >"$bin/ctrld" <<'EOF' cat >"$bin/ctrld" <<'EOF'
#!/bin/sh #!/bin/sh
printf 'ctrld %s\n' "$*" >>"$CALLS" printf 'ctrld %s\n' "$*" >>"$CALLS"
case " $* " in if [ "${FAKE_CTRLD_EXIT:-0}" = "0" ]; then
*" --cd-org="*) : >"$CTRLD_POSTINSTALL_PLIST" ;; case " $* " in
esac *" --cd-org="*) : >"$FAKE_PLIST" ;;
exit 0 esac
fi
exit "${FAKE_CTRLD_EXIT:-0}"
EOF EOF
chmod +x "$bin/defaults" "$bin/launchctl" "$bin/ctrld" chmod +x "$bin/defaults" "$bin/launchctl" "$bin/ctrld"
@@ -72,31 +74,49 @@ run_case() {
existing=$2 existing=$2
mode_present=$3 mode_present=$3
mode=$4 mode=$4
ctrld_exit=${5:-0}
expected_status=${6:-0}
case_dir="$fixture/$name" case_dir="$fixture/$name"
mkdir -p "$case_dir" mkdir -p "$case_dir"
plist="$case_dir/ctrld.plist" plist="$case_dir/ctrld.plist"
prefs="$case_dir/preferences" prefs="$case_dir/preferences"
calls="$case_dir/calls" calls="$case_dir/calls"
output="$case_dir/output" output="$case_dir/output"
postinstall="$case_dir/postinstall"
: >"$calls" : >"$calls"
if [ "$existing" = "1" ]; then if [ "$existing" = "1" ]; then
: >"$plist" : >"$plist"
fi fi
sed \
-e "s|^PLIST=\"/Library/LaunchDaemons/ctrld.plist\"$|PLIST=\"$plist\"|" \
-e "s|^CTRLD=\"/usr/local/bin/ctrld\"$|CTRLD=\"$bin/ctrld\"|" \
-e "s|^PREFS=\"/Library/Managed Preferences/com.controld.ctrld\"$|PREFS=\"$prefs\"|" \
"$postinstall_source" >"$postinstall"
chmod +x "$postinstall"
status=0
PATH="$bin:$PATH" \ PATH="$bin:$PATH" \
CALLS="$calls" \ CALLS="$calls" \
FAKE_TOKEN_PRESENT=1 \ FAKE_TOKEN_PRESENT=1 \
FAKE_TOKEN=test-token \ FAKE_TOKEN=test-token \
FAKE_MODE_PRESENT="$mode_present" \ FAKE_MODE_PRESENT="$mode_present" \
FAKE_MODE="$mode" \ FAKE_MODE="$mode" \
CTRLD_POSTINSTALL_PLIST="$plist" \ FAKE_CTRLD_EXIT="$ctrld_exit" \
CTRLD_POSTINSTALL_CTRLD="$bin/ctrld" \ FAKE_PLIST="$plist" \
CTRLD_POSTINSTALL_PREFS="$prefs" \ "$postinstall" >"$output" 2>&1 || status=$?
"$postinstall" >"$output" 2>&1
if [ "$status" -ne "$expected_status" ]; then
printf 'FAIL: %s exited %s, want %s\n' "$name" "$status" "$expected_status" >&2
sed -n '1,120p' "$output" >&2
exit 1
fi
printf '%s\n' "$case_dir" printf '%s\n' "$case_dir"
} }
assert_not_contains 'CTRLD_POSTINSTALL_' "$postinstall_source"
case_dir=$(run_case fresh-legacy 0 0 '') case_dir=$(run_case fresh-legacy 0 0 '')
assert_contains 'ctrld start --cd-org=test-token' "$case_dir/calls" assert_contains 'ctrld start --cd-org=test-token' "$case_dir/calls"
assert_not_contains '--intercept-mode' "$case_dir/calls" assert_not_contains '--intercept-mode' "$case_dir/calls"
@@ -120,4 +140,18 @@ case_dir=$(run_case upgrade-intercept 1 1 intercept-dns)
assert_contains 'ctrld start --intercept-mode dns' "$case_dir/calls" assert_contains 'ctrld start --intercept-mode dns' "$case_dir/calls"
assert_not_contains 'launchctl load' "$case_dir/calls" assert_not_contains 'launchctl load' "$case_dir/calls"
case_dir=$(run_case fresh-invalid 0 1 invalid)
assert_contains 'WARNING: unsupported InterceptMode in managed preferences; using standard mode' "$case_dir/output"
assert_not_contains '--intercept-mode' "$case_dir/calls"
case_dir=$(run_case upgrade-invalid 1 1 invalid)
assert_contains 'WARNING: unsupported InterceptMode in managed preferences; preserving existing service mode' "$case_dir/output"
assert_contains 'launchctl load' "$case_dir/calls"
assert_not_contains 'ctrld start' "$case_dir/calls"
case_dir=$(run_case upgrade-standard-failure 1 1 standard 1 1)
assert_contains 'ctrld start --intercept-mode off' "$case_dir/calls"
assert_contains 'ERROR: upgrade installed but managed InterceptMode could not be applied' "$case_dir/output"
assert_not_contains 'launchctl load' "$case_dir/calls"
printf 'PASS: pkg postinstall preserves legacy mode and applies standard/intercept-dns policy\n' printf 'PASS: pkg postinstall preserves legacy mode and applies standard/intercept-dns policy\n'