plugin/forward: Add http(2) host/authority header and TO server resolution (#8233)

This commit is contained in:
llucas
2026-07-22 19:07:09 -07:00
committed by GitHub
parent 56f7c09311
commit 73d1eacf87
9 changed files with 83 additions and 32 deletions

View File

@@ -25,11 +25,11 @@ const Path = "/dns-query"
// The URL should not have a path, so please exclude /dns-query. The URL will
// be prefixed with https:// by default, unless it's already prefixed with
// either http:// or https://.
func NewRequest(method, url string, m *dns.Msg) (*http.Request, error) {
return NewRequestWithContext(context.Background(), method, url, m)
func NewRequest(method, url, host string, m *dns.Msg) (*http.Request, error) {
return NewRequestWithContext(context.Background(), method, url, host, m)
}
func NewRequestWithContext(ctx context.Context, method, url string, m *dns.Msg) (*http.Request, error) {
func NewRequestWithContext(ctx context.Context, method, url, host string, m *dns.Msg) (*http.Request, error) {
buf, err := m.Pack()
if err != nil {
return nil, err
@@ -55,6 +55,7 @@ func NewRequestWithContext(ctx context.Context, method, url string, m *dns.Msg)
req.Header.Set("Content-Type", MimeType)
req.Header.Set("Accept", MimeType)
req.Host = host
return req, nil
case http.MethodPost:
@@ -70,6 +71,7 @@ func NewRequestWithContext(ctx context.Context, method, url string, m *dns.Msg)
req.Header.Set("Content-Type", MimeType)
req.Header.Set("Accept", MimeType)
req.Host = host
return req, nil
default:

View File

@@ -25,7 +25,7 @@ func TestDoH(t *testing.T) {
m := new(dns.Msg)
m.SetQuestion("example.org.", dns.TypeDNSKEY)
req, err := NewRequest(test.method, test.url, m)
req, err := NewRequest(test.method, test.url, "example.org", m)
if err != nil {
t.Errorf("Failure to make request: %s", err)
}

View File

@@ -228,6 +228,13 @@ func (p *Proxy) lookupDoH(ctx context.Context, state request.Request, _ Options)
// DoH always runs over TCP (HTTPS), regardless of the downstream
// client's protocol.
const proto = "tcp"
// records the origin Id before upstream.
originId := state.Req.Id
// RFC8484 has DNS ID of 0 as a SHOULD
state.Req.Id = 0
defer func() {
state.Req.Id = originId
}()
var localAddr net.Addr
trace := &httptrace.ClientTrace{
@@ -237,7 +244,7 @@ func (p *Proxy) lookupDoH(ctx context.Context, state request.Request, _ Options)
}
ctx = httptrace.WithClientTrace(ctx, trace)
req, err := doh.NewRequestWithContext(ctx, p.dohMethod, p.addr, state.Req)
req, err := doh.NewRequestWithContext(ctx, p.dohMethod, p.addr, p.dohHost, state.Req)
if err != nil {
return nil, nil, proto, err
}
@@ -253,6 +260,10 @@ func (p *Proxy) lookupDoH(ctx context.Context, state request.Request, _ Options)
return nil, localAddr, proto, err
}
// recovery the origin Id after upstream.
if ret != nil {
ret.Id = originId
}
return ret, localAddr, proto, nil
}

View File

@@ -205,7 +205,7 @@ type dohHc struct {
}
func (h *dohHc) Check(p *Proxy) error {
err := h.send(p.addr)
err := h.send(p.addr, p.dohHost)
if err != nil {
healthcheckFailureCount.WithLabelValues(p.proxyName, p.addr).Add(1)
p.incrementFails()
@@ -216,7 +216,7 @@ func (h *dohHc) Check(p *Proxy) error {
return nil
}
func (h *dohHc) send(addr string) error {
func (h *dohHc) send(addr, host string) error {
ping := new(dns.Msg)
ping.SetQuestion(h.domain, dns.TypeNS)
ping.RecursionDesired = h.recursionDesired
@@ -224,7 +224,7 @@ func (h *dohHc) send(addr string) error {
ctx, cancel := context.WithTimeout(context.Background(), h.client.Timeout)
defer cancel()
req, err := doh.NewRequestWithContext(ctx, http.MethodPost, addr, ping)
req, err := doh.NewRequestWithContext(ctx, http.MethodPost, addr, host, ping)
if err != nil {
return err
}

View File

@@ -22,6 +22,7 @@ type Proxy struct {
protocol string
dohMethod string
dohHost string
readTimeout time.Duration
@@ -40,6 +41,7 @@ func NewProxy(proxyName, addr, protocol string) *Proxy {
transport: newTransport(proxyName, addr),
protocol: protocol,
dohMethod: http.MethodPost,
dohHost: "",
health: NewHealthChecker(proxyName, protocol, true, "."),
proxyName: proxyName,
}
@@ -68,7 +70,13 @@ func (p *Proxy) SetMaxAge(maxAge time.Duration) { p.transport.SetMaxAge(maxAge)
// SetMaxIdleConns sets the maximum idle connections per transport type.
// A value of 0 means unlimited (default).
func (p *Proxy) SetMaxIdleConns(n int) { p.transport.SetMaxIdleConns(n) }
func (p *Proxy) SetMaxIdleConns(n int) {
p.transport.SetMaxIdleConns(n)
if p.transport.httpClient != nil {
p.transport.httpClient.Transport.(*http.Transport).MaxIdleConns = n
p.transport.httpClient.Transport.(*http.Transport).MaxIdleConnsPerHost = n
}
}
func (p *Proxy) SetHTTPClient(client *http.Client) {
p.transport.httpClient = client
@@ -78,6 +86,12 @@ func (p *Proxy) SetDOHRequestOptions(method string) {
p.dohMethod = method
}
func (p *Proxy) SetDOHHost(host string) {
p.dohHost = host
}
func (p *Proxy) DoHHost() string { return p.dohHost }
func (p *Proxy) GetHealthchecker() HealthChecker {
return p.health
}