From 5a765dc7f90c2ebc9a11cd79dcfbd8a8b8d99fcd Mon Sep 17 00:00:00 2001 From: Shulhan Date: Thu, 26 Mar 2026 05:34:30 +0700 Subject: lib/dns: refactoring DoT and DoH to use address instead of port Using port makes the IP address of DoT and DoH listen on the same address with UDP. If we set ListenAddress to 0.0.0.0 and TLS termination is handled by proxy, this cause DoT and DoH will also listen on all addresses. --- lib/dns/dns_test.go | 5 ++--- lib/dns/server.go | 24 +++++++++++++----------- lib/dns/server_example_test.go | 2 +- lib/dns/server_options.go | 30 ++++++++---------------------- 4 files changed, 24 insertions(+), 37 deletions(-) diff --git a/lib/dns/dns_test.go b/lib/dns/dns_test.go index 48212766..7f52af80 100644 --- a/lib/dns/dns_test.go +++ b/lib/dns/dns_test.go @@ -14,7 +14,6 @@ import ( const ( testServerAddress = "127.0.0.1:5300" testDoTServerAddress = "127.0.0.1:18053" - testTLSPort = 18053 // Equal to 2023-08-05 07:53:20 +0000 UTC. testNowEpoch = 1691222000 @@ -47,8 +46,8 @@ func runServer() { var ( serverOptions = &ServerOptions{ ListenAddress: "127.0.0.1:5300", - HTTPPort: 8443, - TLSPort: testTLSPort, + DoHListen: `127.0.0.1:8443`, + DoTListen: testDoTServerAddress, TLSCertFile: "testdata/domain.crt", TLSPrivateKey: "testdata/domain.key", TLSAllowInsecure: true, diff --git a/lib/dns/server.go b/lib/dns/server.go index 3d46d114..4ba59bd2 100644 --- a/lib/dns/server.go +++ b/lib/dns/server.go @@ -194,10 +194,10 @@ func (srv *Server) ListenAndServe() (err error) { srv.startAllForwarders() go srv.processRequest() - if srv.opts.TLSPort > 0 { + if srv.opts.DoTListen != `` { go srv.serveDoT() } - if srv.opts.HTTPPort > 0 { + if srv.opts.DoHListen != `` { go srv.serveDoH() } go srv.serveTCP() @@ -242,17 +242,14 @@ func (srv *Server) Stop() { // serveDoH listen for request over HTTPS using certificate and key // file in parameter. The path to request is static "/dns-query". func (srv *Server) serveDoH() { - var ( - logp = `serveDoH` - addr = srv.opts.getHTTPAddress().String() - ) + logp := `serveDoH` var mux = http.NewServeMux() mux.Handle(`/dns-query`, srv) srv.doh = &http.Server{ - Addr: addr, + Addr: srv.opts.DoHListen, IdleTimeout: srv.opts.HTTPIdleTimeout, ReadHeaderTimeout: 5 * time.Second, Handler: mux, @@ -260,11 +257,11 @@ func (srv *Server) serveDoH() { var err error if srv.tlsConfig != nil && !srv.opts.DoHBehindProxy { - log.Printf(`%s: listening at %s`, logp, addr) + log.Printf(`%s: listening at %s`, logp, srv.doh.Addr) srv.doh.TLSConfig = srv.tlsConfig err = srv.doh.ListenAndServeTLS("", "") } else { - log.Printf(`%s: listening behind proxy at %s`, logp, addr) + log.Printf(`%s: listening behind proxy at %s`, logp, srv.doh.Addr) err = srv.doh.ListenAndServe() } if errors.Is(err, io.EOF) { @@ -278,14 +275,19 @@ func (srv *Server) serveDoH() { func (srv *Server) serveDoT() { var ( - logp = `serveDoT` - dotAddr = srv.opts.getDoTAddress() + logp = `serveDoT` cl *TCPClient conn net.Conn err error ) + dotAddr, err := net.ResolveTCPAddr(`tcp`, srv.opts.DoTListen) + if err != nil { + log.Printf(`%s: %s`, logp, err) + return + } + for { if srv.opts.DoHBehindProxy || srv.tlsConfig == nil { srv.dot, err = net.ListenTCP("tcp", dotAddr) diff --git a/lib/dns/server_example_test.go b/lib/dns/server_example_test.go index c9222885..c14f2888 100644 --- a/lib/dns/server_example_test.go +++ b/lib/dns/server_example_test.go @@ -51,7 +51,7 @@ func ExampleServer() { serverAddress = "127.0.0.1:5300" serverOptions = &ServerOptions{ ListenAddress: "127.0.0.1:5300", - HTTPPort: 8443, + DoHListen: "127.0.0.1:8443", TLSCertFile: "testdata/domain.crt", TLSPrivateKey: "testdata/domain.key", TLSAllowInsecure: true, diff --git a/lib/dns/server_options.go b/lib/dns/server_options.go index d53b1abd..89a6912b 100644 --- a/lib/dns/server_options.go +++ b/lib/dns/server_options.go @@ -41,6 +41,14 @@ type ServerOptions struct { // This field is optional, default to "0.0.0.0:53". ListenAddress string `ini:"dns:server:listen"` + // DoHListen address for listening DNS over HTTP (DoH). + // If its empty, the server will not serve DoH. + DoHListen string `ini:"dns:server:doh.listen"` + + // DoTListen address for listening DNS over TLS (DoT). + // If its empty, the server will not serve DoT. + DoTListen string `ini:"dns:server:dot.listen"` + // TLSCertFile contains path to certificate for serving DNS over TLS // and HTTPS. // This field is optional, if its empty, server will listening on @@ -108,14 +116,6 @@ type ServerOptions struct { // it. Debug int `ini:"dns:server:debug"` - // HTTPPort port for listening DNS over HTTP (DoH), default to 0. - // If its zero, the server will not serve DNS over HTTP. - HTTPPort uint16 `ini:"dns:server:http.port"` - - // TLSPort port for listening DNS over TLS, default to 0. - // If its zero, the server will not serve DNS over TLS. - TLSPort uint16 `ini:"dns:server:tls.port"` - port uint16 // TLSAllowInsecure option to allow to serve DoH with self-signed @@ -180,20 +180,6 @@ func (opts *ServerOptions) getTCPAddress() *net.TCPAddr { } } -func (opts *ServerOptions) getHTTPAddress() *net.TCPAddr { - return &net.TCPAddr{ - IP: opts.ip, - Port: int(opts.HTTPPort), - } -} - -func (opts *ServerOptions) getDoTAddress() *net.TCPAddr { - return &net.TCPAddr{ - IP: opts.ip, - Port: int(opts.TLSPort), - } -} - // parseNameServers parse each name server in NameServers list based on scheme // and store the result either in udpAddrs, tcpAddrs, dohAddrs, or dotAddrs. // -- cgit v1.3