diff --git a/dnscrypt-proxy/config.go b/dnscrypt-proxy/config.go index bc469e1ece..baf049daa3 100644 --- a/dnscrypt-proxy/config.go +++ b/dnscrypt-proxy/config.go @@ -117,6 +117,7 @@ func newConfig() Config { LogLevel: int(dlog.LogLevel()), LogFileLatest: true, ListenAddresses: []string{"127.0.0.1:53"}, + ControlSocket: DefaultControlSocket, LocalDoH: LocalDoHConfig{Path: "/dns-query"}, MonitoringUI: MonitoringUIConfig{ Enabled: false, diff --git a/dnscrypt-proxy/control.go b/dnscrypt-proxy/control.go index ff6441c59a..0e7b40094a 100644 --- a/dnscrypt-proxy/control.go +++ b/dnscrypt-proxy/control.go @@ -34,6 +34,12 @@ import ( // Replies are "ok " or "error ". There is no // authentication: the channel is only ever a unix socket (control_socket), // readable and writable by its owner only. +// +// control_socket defaults to DefaultControlSocket, so a config needs no key for +// it and stays loadable by builds without the control channel; set it to '' to +// turn the channel off. A missing default directory only disables the channel. + +const DefaultControlSocket = "/run/dnscrypt/control.sock" const ( controlReadTimeout = 2 * time.Second @@ -147,7 +153,7 @@ func readControlLine(r io.Reader) (string, error) { // cache, prints the reply and returns the exit code. func Flush(path string, arg string) int { if path == "" { - fmt.Fprintln(os.Stderr, "control_socket is not set in the configuration file") + fmt.Fprintln(os.Stderr, "the control channel is turned off (control_socket = '')") return 1 } command := "flush " + arg diff --git a/dnscrypt-proxy/control_test.go b/dnscrypt-proxy/control_test.go index da5828414a..7eda4385c5 100644 --- a/dnscrypt-proxy/control_test.go +++ b/dnscrypt-proxy/control_test.go @@ -2,8 +2,10 @@ package main import ( "bufio" + "errors" "fmt" "io" + "io/fs" "net" "net/netip" "os" @@ -13,6 +15,7 @@ import ( "codeberg.org/miekg/dns" "codeberg.org/miekg/dns/rdata" + "github.com/BurntSushi/toml" ) func resetControlState(t *testing.T) { @@ -421,3 +424,22 @@ func TestControlFlushClient(t *testing.T) { t.Fatalf("an unreachable proxy must exit 1, got %d", code) } } + +func TestControlSocketDefault(t *testing.T) { + cfg := newConfig() + if cfg.ControlSocket != DefaultControlSocket { + t.Fatalf("default control_socket %q, want %q", cfg.ControlSocket, DefaultControlSocket) + } + // a config without the key keeps the default, an empty value turns it off + if _, err := toml.Decode("cache = true\n", &cfg); err != nil || cfg.ControlSocket != DefaultControlSocket { + t.Fatalf("without the key: %q, %v", cfg.ControlSocket, err) + } + if _, err := toml.Decode("control_socket = ''\n", &cfg); err != nil || cfg.ControlSocket != "" { + t.Fatalf("control_socket = '': %q, %v", cfg.ControlSocket, err) + } + // a missing directory is reported as such, so the default can be skipped quietly + err := (&Proxy{}).startControl(t.TempDir() + "/missing/c.sock") + if !errors.Is(err, fs.ErrNotExist) { + t.Fatalf("missing directory: got %v", err) + } +} diff --git a/dnscrypt-proxy/example-dnscrypt-proxy.toml b/dnscrypt-proxy/example-dnscrypt-proxy.toml index 44dd0a8030..a0eb11f455 100644 --- a/dnscrypt-proxy/example-dnscrypt-proxy.toml +++ b/dnscrypt-proxy/example-dnscrypt-proxy.toml @@ -517,6 +517,14 @@ cache_neg_min_ttl = 60 cache_neg_max_ttl = 600 +## Unix socket for dropping names from the cache: one command per connection, +## "flush " or "flush_type ". Also available from the +## command line as `dnscrypt-proxy -config -flush [,]`. +## Readable and writable by the proxy's user only. If that directory does not +## exist the channel stays off; set to '' to turn it off explicitly. + +# control_socket = '/run/dnscrypt/control.sock' + ############################################################################### # Captive portal handling # diff --git a/dnscrypt-proxy/proxy.go b/dnscrypt-proxy/proxy.go index 3699ebfe4f..1e113564a8 100644 --- a/dnscrypt-proxy/proxy.go +++ b/dnscrypt-proxy/proxy.go @@ -3,8 +3,11 @@ package main import ( "context" "encoding/binary" + "errors" + "io/fs" "net" "os" + "path/filepath" "runtime" "strings" "sync" @@ -286,7 +289,11 @@ func (proxy *Proxy) StartProxy() { if proxy.controlSocket != "" { if err := proxy.startControl(proxy.controlSocket); err != nil { - dlog.Errorf("Failed to start the control channel on %s: %v", proxy.controlSocket, err) + if proxy.controlSocket == DefaultControlSocket && errors.Is(err, fs.ErrNotExist) { + dlog.Noticef("Control channel off: %s does not exist", filepath.Dir(DefaultControlSocket)) + } else { + dlog.Errorf("Failed to start the control channel on %s: %v", proxy.controlSocket, err) + } } }