Skip to content

Commit b9dbc81

Browse files
committed
proxy: add support for HTTP-only listeners for DoH
It is desirable to use the DoH endpoint even without TLS termination, for example in case of an external proxy (nginx) taking care of termination. This change allows to specify independent --http-port ports which use simple TCP listeners.
1 parent b713cf3 commit b9dbc81

File tree

9 files changed

+77
-6
lines changed

9 files changed

+77
-6
lines changed

internal/cmd/args.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const (
2727
upstreamModeIdx
2828
listenAddrsIdx
2929
listenPortsIdx
30+
httpListenPortsIdx
3031
httpsListenPortsIdx
3132
tlsListenPortsIdx
3233
quicListenPortsIdx
@@ -151,6 +152,12 @@ var commandLineOptions = []*commandLineOption{
151152
short: "p",
152153
valueType: "port",
153154
},
155+
httpListenPortsIdx: {
156+
description: "Listening ports for DNS-over-HTTP.",
157+
long: "http-port",
158+
short: "i",
159+
valueType: "port",
160+
},
154161
httpsListenPortsIdx: {
155162
description: "Listening ports for DNS-over-HTTPS.",
156163
long: "https-port",
@@ -424,6 +431,7 @@ func parseCmdLineOptions(conf *configuration) (err error) {
424431
upstreamModeIdx: &conf.UpstreamMode,
425432
listenAddrsIdx: &conf.ListenAddrs,
426433
listenPortsIdx: &conf.ListenPorts,
434+
httpListenPortsIdx: &conf.HTTPListenPorts,
427435
httpsListenPortsIdx: &conf.HTTPSListenPorts,
428436
tlsListenPortsIdx: &conf.TLSListenPorts,
429437
quicListenPortsIdx: &conf.QUICListenPorts,

internal/cmd/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ type configuration struct {
4949
// ListenPorts are the ports server listens on.
5050
ListenPorts []int `yaml:"listen-ports"`
5151

52+
// HTTP listen ports are the ports server listens on for DNS-over-HTTP.
53+
HTTPListenPorts []int `yaml:"http-port"`
54+
5255
// HTTPSListenPorts are the ports server listens on for DNS-over-HTTPS.
5356
HTTPSListenPorts []int `yaml:"https-port"`
5457

internal/cmd/proxy.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,13 @@ func (conf *configuration) initListenAddrs(config *proxy.Config) (err error) {
382382
}
383383
}
384384

385+
for _, ip := range addrs {
386+
for _, port := range conf.HTTPListenPorts {
387+
a := net.TCPAddrFromAddrPort(netip.AddrPortFrom(ip, uint16(port)))
388+
config.HTTPListenAddr = append(config.HTTPListenAddr, a)
389+
}
390+
}
391+
385392
initTLSListenAddrs(config, conf, addrs)
386393
initDNSCryptListenAddrs(config, conf, addrs)
387394

main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ import (
77
func main() {
88
cmd.Main()
99
}
10+

proxy/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ type Config struct {
143143
// requests.
144144
HTTPSListenAddr []*net.TCPAddr
145145

146+
HTTPListenAddr []*net.TCPAddr // if nil, then it does not listen for HTTP (DoH)
147+
146148
// TLSListenAddr is the set of TCP addresses to listen for DNS-over-TLS
147149
// requests.
148150
TLSListenAddr []*net.TCPAddr
@@ -448,6 +450,7 @@ func (p *Proxy) hasListenAddrs() bool {
448450
return p.UDPListenAddr != nil ||
449451
p.TCPListenAddr != nil ||
450452
p.TLSListenAddr != nil ||
453+
p.HTTPListenAddr != nil ||
451454
p.HTTPSListenAddr != nil ||
452455
p.QUICListenAddr != nil ||
453456
p.DNSCryptUDPListenAddr != nil ||

proxy/proxy.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ type Proxy struct {
146146
// them.
147147
quicTransports []*quic.Transport
148148

149+
httpListen []net.Listener // HTTP listeners
150+
httpServer *http.Server // HTTP server instance
151+
149152
// httpsListen are the listened HTTPS connections.
150153
httpsListen []net.Listener
151154

@@ -444,6 +447,14 @@ func (p *Proxy) closeListeners(errs []error) (res []error) {
444447
p.httpsListen = nil
445448
}
446449

450+
if p.httpServer != nil {
451+
res = closeAll(res, p.httpServer)
452+
p.httpServer = nil
453+
454+
// No need to close these since they're closed by httpsServer.Close().
455+
p.httpListen = nil
456+
}
457+
447458
if p.h3Server != nil {
448459
res = closeAll(res, p.h3Server)
449460
p.h3Server = nil

proxy/proxy_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,4 @@ func TestProxy_Start_closeOnFail(t *testing.T) {
182182
servicetest.RequireRun(t, p, testTimeout)
183183
}))
184184
}
185+
p.HTTPListenAddr = []*net.TCPAddr{{IP: ip, Port: 0}}

proxy/server.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ func (p *Proxy) startListeners(ctx context.Context) (err error) {
3535
return err
3636
}
3737

38+
err = p.initHTTPListeners(ctx)
39+
if err != nil {
40+
return err
41+
}
42+
3843
err = p.initHTTPSListeners(ctx)
3944
if err != nil {
4045
return err
@@ -67,6 +72,10 @@ func (p *Proxy) serveListeners() {
6772
go p.tcpPacketLoop(l, ProtoTLS, p.requestsSema)
6873
}
6974

75+
for _, l := range p.httpListen {
76+
go func(l net.Listener) { _ = p.httpServer.Serve(l) }(l)
77+
}
78+
7079
for _, l := range p.httpsListen {
7180
go func(l net.Listener) { _ = p.httpsServer.Serve(l) }(l)
7281
}

proxy/serverhttps.go

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
func (p *Proxy) listenHTTP(
2929
ctx context.Context,
3030
addr *net.TCPAddr,
31+
withTLS bool,
3132
) (ln net.Listener, tcpAddr *net.TCPAddr, err error) {
3233
var tcpListen *net.TCPListener
3334
err = p.bindWithRetry(ctx, func() (listenErr error) {
@@ -45,14 +46,20 @@ func (p *Proxy) listenHTTP(
4546
return nil, nil, fmt.Errorf("bad listener address type: %T", laddr)
4647
}
4748

48-
p.logger.InfoContext(ctx, "listening to https", "addr", tcpAddr)
49+
if withTLS {
50+
p.logger.InfoContext(ctx, "listening to https", "addr", tcpAddr)
4951

50-
tlsConfig := p.TLSConfig.Clone()
51-
tlsConfig.NextProtos = []string{http2.NextProtoTLS, "http/1.1"}
52+
tlsConfig := p.TLSConfig.Clone()
53+
tlsConfig.NextProtos = []string{http2.NextProtoTLS, "http/1.1"}
54+
55+
tlsListen := tls.NewListener(tcpListen, tlsConfig)
5256

53-
tlsListen := tls.NewListener(tcpListen, tlsConfig)
57+
return tlsListen, tcpAddr, nil
58+
}
5459

55-
return tlsListen, tcpAddr, nil
60+
p.logger.InfoContext(ctx, "listening to http", "addr", tcpAddr)
61+
62+
return tcpListen, tcpAddr, nil
5663
}
5764

5865
// listenH3 creates instances of QUIC listeners that will be used for running
@@ -73,6 +80,27 @@ func (p *Proxy) listenH3(
7380
return quicListen, nil
7481
}
7582

83+
func (p *Proxy) initHTTPListeners(ctx context.Context) (err error) {
84+
p.httpServer = &http.Server{
85+
Handler: p,
86+
ReadHeaderTimeout: defaultTimeout,
87+
WriteTimeout: defaultTimeout,
88+
}
89+
90+
for _, addr := range p.HTTPListenAddr {
91+
p.logger.InfoContext(ctx, "creating an http server")
92+
93+
ln, _, lErr := p.listenHTTP(ctx, addr, false)
94+
if lErr != nil {
95+
return fmt.Errorf("failed to start HTTPS server on %s: %w", addr, lErr)
96+
}
97+
98+
p.httpListen = append(p.httpListen, ln)
99+
}
100+
101+
return nil
102+
}
103+
76104
// initHTTPSListeners creates TCP/UDP listeners and HTTP/H3 servers.
77105
func (p *Proxy) initHTTPSListeners(ctx context.Context) (err error) {
78106
p.httpsServer = &http.Server{
@@ -90,7 +118,7 @@ func (p *Proxy) initHTTPSListeners(ctx context.Context) (err error) {
90118
for _, addr := range p.HTTPSListenAddr {
91119
p.logger.InfoContext(ctx, "creating an https server")
92120

93-
ln, tcpAddr, lErr := p.listenHTTP(ctx, addr)
121+
ln, tcpAddr, lErr := p.listenHTTP(ctx, addr, true)
94122
if lErr != nil {
95123
return fmt.Errorf("failed to start HTTPS server on %s: %w", addr, lErr)
96124
}

0 commit comments

Comments
 (0)