From 5b00a121631c85aa5c754932be00178f5d3c2dfd Mon Sep 17 00:00:00 2001 From: mikitsu Date: Sun, 24 Aug 2025 15:28:11 +0200 Subject: [PATCH 1/2] handler, cmd: add disable-ipv4 option The new disable-ipv4 option operates completely analogously to the existing disable-ipv6 option: A records are discarded from answers. This feature is useful on IPv6-only hosts with misbehaving applications that only attempt one connection using the first DNS answer. --- internal/cmd/args.go | 9 +++++++++ internal/cmd/config.go | 3 +++ internal/cmd/proxy.go | 1 + internal/handler/default.go | 10 ++++++++++ internal/handler/ipv4halt.go | 23 +++++++++++++++++++++++ 5 files changed, 46 insertions(+) create mode 100644 internal/handler/ipv4halt.go diff --git a/internal/cmd/args.go b/internal/cmd/args.go index 40b3761f7..469dfcca5 100644 --- a/internal/cmd/args.go +++ b/internal/cmd/args.go @@ -57,6 +57,7 @@ const ( verboseIdx insecureIdx ipv6DisabledIdx + ipv4DisabledIdx http3Idx cacheOptimisticIdx cacheIdx @@ -340,6 +341,13 @@ var commandLineOptions = []*commandLineOption{ short: "", valueType: "", }, + ipv4DisabledIdx: { + description: "If specified, all A requests will be replied with NoError RCode and " + + "empty answer.", + long: "ipv4-disabled", + short: "", + valueType: "", + }, http3Idx: { description: "Enable HTTP/3 support.", long: "http3", @@ -440,6 +448,7 @@ func parseCmdLineOptions(conf *configuration) (err error) { verboseIdx: &conf.Verbose, insecureIdx: &conf.Insecure, ipv6DisabledIdx: &conf.IPv6Disabled, + ipv4DisabledIdx: &conf.IPv4Disabled, http3Idx: &conf.HTTP3, cacheOptimisticIdx: &conf.CacheOptimistic, cacheIdx: &conf.Cache, diff --git a/internal/cmd/config.go b/internal/cmd/config.go index 847df0ddb..4d92c75f3 100644 --- a/internal/cmd/config.go +++ b/internal/cmd/config.go @@ -162,6 +162,9 @@ type configuration struct { // IPv6Disabled makes the server to respond with NODATA to all AAAA queries. IPv6Disabled bool `yaml:"ipv6-disabled"` + // IPv4Disabled makes the server to respond with NODATA to all A queries. + IPv4Disabled bool `yaml:"ipv4-disabled"` + // HTTP3 controls whether HTTP/3 is enabled for this instance of dnsproxy. // It enables HTTP/3 support for both the DoH upstreams and the DoH server. HTTP3 bool `yaml:"http3"` diff --git a/internal/cmd/proxy.go b/internal/cmd/proxy.go index 65e50c385..6fca324bf 100644 --- a/internal/cmd/proxy.go +++ b/internal/cmd/proxy.go @@ -49,6 +49,7 @@ func createProxyConfig( // TODO(e.burkov): Use the configured message constructor. MessageConstructor: dnsmsg.DefaultMessageConstructor{}, HaltIPv6: conf.IPv6Disabled, + HaltIPv4: conf.IPv4Disabled, HostsFiles: hosts, }) diff --git a/internal/handler/default.go b/internal/handler/default.go index 86b7e23f2..add8258c7 100644 --- a/internal/handler/default.go +++ b/internal/handler/default.go @@ -23,6 +23,10 @@ type DefaultConfig struct { // HaltIPv6 halts the processing of AAAA requests and makes the handler // reply with NODATA to them, if true. HaltIPv6 bool + + // HaltIPv4 halts the processing of A requests and makes the handler + // reply with NODATA to them. + HaltIPv4 bool } // Default implements the default configurable [proxy.RequestHandler]. @@ -31,6 +35,7 @@ type Default struct { hosts hostsfile.Storage logger *slog.Logger isIPv6Halted bool + isIPv4Halted bool } // NewDefault creates a new [Default] handler. @@ -45,6 +50,7 @@ func NewDefault(conf *DefaultConfig) (d *Default) { return &Default{ logger: conf.Logger, isIPv6Halted: conf.HaltIPv6, + isIPv4Halted: conf.HaltIPv4, messages: mc, hosts: conf.HostsFiles, } @@ -64,6 +70,10 @@ func (h *Default) HandleRequest(p *proxy.Proxy, proxyCtx *proxy.DNSContext) (err return nil } + if proxyCtx.Res = h.haltA(ctx, proxyCtx.Req); proxyCtx.Res != nil { + return nil + } + if proxyCtx.Res = h.resolveFromHosts(ctx, proxyCtx.Req); proxyCtx.Res != nil { return nil } diff --git a/internal/handler/ipv4halt.go b/internal/handler/ipv4halt.go new file mode 100644 index 000000000..b1595e027 --- /dev/null +++ b/internal/handler/ipv4halt.go @@ -0,0 +1,23 @@ +package handler + +import ( + "context" + + "github.com/miekg/dns" +) + +// haltA halts the processing of A requests if IPv4 is disabled. req must +// not be nil. +func (h *Default) haltA(ctx context.Context, req *dns.Msg) (resp *dns.Msg) { + if h.isIPv4Halted && req.Question[0].Qtype == dns.TypeA { + h.logger.DebugContext( + ctx, + "ipv4 is disabled; replying with empty response", + "req", req.Question[0].Name, + ) + + return h.messages.NewMsgNODATA(req) + } + + return nil +} From e1bc9b53c98fceca3813c247e82102a4562c5176 Mon Sep 17 00:00:00 2001 From: mikitsu Date: Sun, 24 Aug 2025 15:45:37 +0200 Subject: [PATCH 2/2] update REAMDE to mention --ipv4-disabled --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d216407c2..6e73c3e5d 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,8 @@ Usage of ./dnsproxy: Disable secure TLS certificate validation. --ipv6-disabled If specified, all AAAA requests will be replied with NoError RCode and empty answer. + --ipv4-disabled + If specified, all A requests will be replied with NoError RCode and empty answer. --listen=address/-l address Listening addresses. --max-go-routines=uint