diff --git a/Makefile b/Makefile index 4cbcebd83..9c0c3992f 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ GOAMD64 = v1 GOPROXY = https://proxy.golang.org|direct GOTELEMETRY = off OUT = dnsproxy -GOTOOLCHAIN = go1.25.5 +GOTOOLCHAIN = go1.25.7 RACE = 0 REVISION = $${REVISION:-$$(git rev-parse --short HEAD)} VERSION = 0 diff --git a/go.mod b/go.mod index cfd587471..a3263b0a8 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/AdguardTeam/dnsproxy -go 1.25.5 +go 1.25.7 require ( github.com/AdguardTeam/golibs v0.35.2 diff --git a/internal/cmd/args.go b/internal/cmd/args.go index c4984503e..ba428c47c 100644 --- a/internal/cmd/args.go +++ b/internal/cmd/args.go @@ -27,6 +27,7 @@ const ( upstreamModeIdx listenAddrsIdx listenPortsIdx + httpListenPortsIdx httpsListenPortsIdx tlsListenPortsIdx quicListenPortsIdx @@ -151,6 +152,12 @@ var commandLineOptions = []*commandLineOption{ short: "p", valueType: "port", }, + httpListenPortsIdx: { + description: "Listening ports for DNS-over-HTTP.", + long: "http-port", + short: "i", + valueType: "port", + }, httpsListenPortsIdx: { description: "Listening ports for DNS-over-HTTPS.", long: "https-port", @@ -424,6 +431,7 @@ func parseCmdLineOptions(conf *configuration) (err error) { upstreamModeIdx: &conf.UpstreamMode, listenAddrsIdx: &conf.ListenAddrs, listenPortsIdx: &conf.ListenPorts, + httpListenPortsIdx: &conf.HTTPListenPorts, httpsListenPortsIdx: &conf.HTTPSListenPorts, tlsListenPortsIdx: &conf.TLSListenPorts, quicListenPortsIdx: &conf.QUICListenPorts, diff --git a/internal/cmd/config.go b/internal/cmd/config.go index 8a246c926..5a9e9f61b 100644 --- a/internal/cmd/config.go +++ b/internal/cmd/config.go @@ -49,6 +49,9 @@ type configuration struct { // ListenPorts are the ports server listens on. ListenPorts []int `yaml:"listen-ports"` + // HTTP listen ports are the ports server listens on for DNS-over-HTTP. + HTTPListenPorts []int `yaml:"http-port"` + // HTTPSListenPorts are the ports server listens on for DNS-over-HTTPS. HTTPSListenPorts []int `yaml:"https-port"` diff --git a/internal/cmd/proxy.go b/internal/cmd/proxy.go index 9e39c8a3d..5bed42352 100644 --- a/internal/cmd/proxy.go +++ b/internal/cmd/proxy.go @@ -382,6 +382,13 @@ func (conf *configuration) initListenAddrs(config *proxy.Config) (err error) { } } + for _, ip := range addrs { + for _, port := range conf.HTTPListenPorts { + a := net.TCPAddrFromAddrPort(netip.AddrPortFrom(ip, uint16(port))) + config.HTTPListenAddr = append(config.HTTPListenAddr, a) + } + } + initTLSListenAddrs(config, conf, addrs) initDNSCryptListenAddrs(config, conf, addrs) diff --git a/main.go b/main.go index 6181dadbf..88ca2b836 100644 --- a/main.go +++ b/main.go @@ -7,3 +7,4 @@ import ( func main() { cmd.Main() } + diff --git a/proxy/config.go b/proxy/config.go index 2a8282eda..3458fc51f 100644 --- a/proxy/config.go +++ b/proxy/config.go @@ -143,6 +143,8 @@ type Config struct { // requests. HTTPSListenAddr []*net.TCPAddr + HTTPListenAddr []*net.TCPAddr // if nil, then it does not listen for HTTP (DoH) + // TLSListenAddr is the set of TCP addresses to listen for DNS-over-TLS // requests. TLSListenAddr []*net.TCPAddr @@ -448,6 +450,7 @@ func (p *Proxy) hasListenAddrs() bool { return p.UDPListenAddr != nil || p.TCPListenAddr != nil || p.TLSListenAddr != nil || + p.HTTPListenAddr != nil || p.HTTPSListenAddr != nil || p.QUICListenAddr != nil || p.DNSCryptUDPListenAddr != nil || diff --git a/proxy/proxy.go b/proxy/proxy.go index 44ca67ca2..2d3b40187 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -146,6 +146,9 @@ type Proxy struct { // them. quicTransports []*quic.Transport + httpListen []net.Listener // HTTP listeners + httpServer *http.Server // HTTP server instance + // httpsListen are the listened HTTPS connections. httpsListen []net.Listener @@ -444,6 +447,14 @@ func (p *Proxy) closeListeners(errs []error) (res []error) { p.httpsListen = nil } + if p.httpServer != nil { + res = closeAll(res, p.httpServer) + p.httpServer = nil + + // No need to close these since they're closed by httpsServer.Close(). + p.httpListen = nil + } + if p.h3Server != nil { res = closeAll(res, p.h3Server) p.h3Server = nil diff --git a/proxy/proxy_test.go b/proxy/proxy_test.go index b38eb0e80..4416ea42d 100644 --- a/proxy/proxy_test.go +++ b/proxy/proxy_test.go @@ -182,3 +182,4 @@ func TestProxy_Start_closeOnFail(t *testing.T) { servicetest.RequireRun(t, p, testTimeout) })) } + p.HTTPListenAddr = []*net.TCPAddr{{IP: ip, Port: 0}} diff --git a/proxy/server.go b/proxy/server.go index f2c51ef24..2cb2582ea 100644 --- a/proxy/server.go +++ b/proxy/server.go @@ -35,6 +35,11 @@ func (p *Proxy) startListeners(ctx context.Context) (err error) { return err } + err = p.initHTTPListeners(ctx) + if err != nil { + return err + } + err = p.initHTTPSListeners(ctx) if err != nil { return err @@ -67,6 +72,10 @@ func (p *Proxy) serveListeners() { go p.tcpPacketLoop(l, ProtoTLS, p.requestsSema) } + for _, l := range p.httpListen { + go func(l net.Listener) { _ = p.httpServer.Serve(l) }(l) + } + for _, l := range p.httpsListen { go func(l net.Listener) { _ = p.httpsServer.Serve(l) }(l) } diff --git a/proxy/serverhttps.go b/proxy/serverhttps.go index 36677cd08..f64106ea0 100644 --- a/proxy/serverhttps.go +++ b/proxy/serverhttps.go @@ -28,6 +28,7 @@ import ( func (p *Proxy) listenHTTP( ctx context.Context, addr *net.TCPAddr, + withTLS bool, ) (ln net.Listener, tcpAddr *net.TCPAddr, err error) { var tcpListen *net.TCPListener err = p.bindWithRetry(ctx, func() (listenErr error) { @@ -45,14 +46,20 @@ func (p *Proxy) listenHTTP( return nil, nil, fmt.Errorf("bad listener address type: %T", laddr) } - p.logger.InfoContext(ctx, "listening to https", "addr", tcpAddr) + if withTLS { + p.logger.InfoContext(ctx, "listening to https", "addr", tcpAddr) - tlsConfig := p.TLSConfig.Clone() - tlsConfig.NextProtos = []string{http2.NextProtoTLS, "http/1.1"} + tlsConfig := p.TLSConfig.Clone() + tlsConfig.NextProtos = []string{http2.NextProtoTLS, "http/1.1"} + + tlsListen := tls.NewListener(tcpListen, tlsConfig) - tlsListen := tls.NewListener(tcpListen, tlsConfig) + return tlsListen, tcpAddr, nil + } - return tlsListen, tcpAddr, nil + p.logger.InfoContext(ctx, "listening to http", "addr", tcpAddr) + + return tcpListen, tcpAddr, nil } // listenH3 creates instances of QUIC listeners that will be used for running @@ -73,6 +80,27 @@ func (p *Proxy) listenH3( return quicListen, nil } +func (p *Proxy) initHTTPListeners(ctx context.Context) (err error) { + p.httpServer = &http.Server{ + Handler: p, + ReadHeaderTimeout: defaultTimeout, + WriteTimeout: defaultTimeout, + } + + for _, addr := range p.HTTPListenAddr { + p.logger.InfoContext(ctx, "creating an http server") + + ln, _, lErr := p.listenHTTP(ctx, addr, false) + if lErr != nil { + return fmt.Errorf("failed to start HTTPS server on %s: %w", addr, lErr) + } + + p.httpListen = append(p.httpListen, ln) + } + + return nil +} + // initHTTPSListeners creates TCP/UDP listeners and HTTP/H3 servers. func (p *Proxy) initHTTPSListeners(ctx context.Context) (err error) { p.httpsServer = &http.Server{ @@ -90,7 +118,7 @@ func (p *Proxy) initHTTPSListeners(ctx context.Context) (err error) { for _, addr := range p.HTTPSListenAddr { p.logger.InfoContext(ctx, "creating an https server") - ln, tcpAddr, lErr := p.listenHTTP(ctx, addr) + ln, tcpAddr, lErr := p.listenHTTP(ctx, addr, true) if lErr != nil { return fmt.Errorf("failed to start HTTPS server on %s: %w", addr, lErr) }