fixups: will squash before merge

This commit is contained in:
Michael Ben-Ami committed 2026-10-15 11:47:16 -04:00
1 parent ab7caf5fd5
commit 663838c63c
5 files changed
+54 -65

No files matched your search

+6 -6
View File
@@ -31,7 +31,7 @@ import (
"tailscale.com/ipn/ipnext"
"tailscale.com/ipn/ipnlocal"
"tailscale.com/ipn/localapi"
tsresolver "tailscale.com/net/dns/resolver"
"tailscale.com/net/dns/resolver"
"tailscale.com/net/packet"
"tailscale.com/net/traffic"
"tailscale.com/net/tsaddr"
@@ -163,12 +163,12 @@ func (e *extension) installHooks(dph *datapathHandler) error {
if !ok {
return errors.New("could not access system tun")
}
resolver := dnsManager.Resolver()
if resolver == nil {
r := dnsManager.Resolver()
if r == nil {
return errors.New("dns manager resolver not ready")
}
if err := resolver.RegisterCustomScheme(appc.DNSAddrScheme, func(addr string) (string, error) {
if err := r.RegisterCustomScheme(appc.DNSAddrScheme, func(addr string) (string, error) {
scheme, appName, ok := strings.Cut(addr, ":")
if !ok || scheme != appc.DNSAddrScheme {
return "", fmt.Errorf("unexpected conn25 scheme %q", scheme)
@@ -196,7 +196,7 @@ func (e *extension) installHooks(dph *datapathHandler) error {
// Set up the DNS manager to rewrite responses for app domains
// to answer with Magic IPs.
dnsManager.SetQueryResponseMapper(func(res *tsresolver.Response) []byte {
dnsManager.SetQueryResponseMapper(func(res *resolver.Response) []byte {
if !e.conn25.isConfigured() {
return res.Bs
}
@@ -1032,7 +1032,7 @@ var passThroughQuestionTypes = set.Of(
// mapDNSResponse parses and inspects the DNS response. If the domain
// is determined to belong to app this node is client for, it assigns addresses
// for connecting and rewrites the response to contain Magic IPs.
func (c *Conn25) mapDNSResponse(res *tsresolver.Response) []byte {
func (c *Conn25) mapDNSResponse(res *resolver.Response) []byte {
var p dnsmessage.Parser
buf := res.Bs
hdr, err := p.Start(buf)
+3 -3
View File
@@ -65,14 +65,14 @@ func TestDoH(t *testing.T) {
if !ok {
t.Fatal("expected DoH")
}
res, err := f.sendDoH(context.Background(), urlBase, c, someDNSQuestion(t), false)
res, err := f.sendDoH(context.Background(), urlBase, c, someDNSQuestion(t))
if err != nil {
t.Fatal(err)
}
c.Transport.(*http.Transport).CloseIdleConnections()
if res.PeerAPIMeta != nil {
t.Errorf("unexpected PeerAPIMeta %+v for non-PeerAPI DoH", res.PeerAPIMeta)
if res.DoHMeta == nil {
t.Errorf("expected DoHMeta")
}
var p dnsmessage.Parser
+25 -26
View File
@@ -640,9 +640,7 @@ func (f *forwarder) newDoHClientLocked(cacheKey, urlBase string, allIPs []netip.
const dohType = "application/dns-message"
// sendDoH sends packet as a DoH query to urlBase using client c.
// If isPeerAPI is true, urlBase references a PeerAPI's DoH server
// and the returned Response has PeerAPIMeta populated.
func (f *forwarder) sendDoH(ctx context.Context, urlBase string, c *http.Client, packet []byte, isPeerAPI bool) (*Response, error) {
func (f *forwarder) sendDoH(ctx context.Context, urlBase string, c *http.Client, packet []byte) (*Response, error) {
ctx = sockstats.WithSockStats(ctx, sockstats.LabelDNSForwarderDoH, f.logf)
metricDNSFwdDoH.Add(1)
req, err := http.NewRequestWithContext(ctx, "POST", urlBase, bytes.NewReader(packet))
@@ -680,15 +678,13 @@ func (f *forwarder) sendDoH(ctx context.Context, urlBase string, c *http.Client,
metricDNSFwdDoHErrorBody.Add(1)
return nil, err
}
ret := &Response{Bs: res}
if isPeerAPI {
ret.PeerAPIMeta = &PeerAPIMetadata{
RequestURL: hres.Request.URL.Clone(),
ResponseHeader: hres.Header.Clone(),
}
}
return ret, nil
return &Response{
Bs: res,
DoHMeta: &DoHMetadata{
RequestURL: hres.Request.URL,
ResponseHeader: hres.Header,
},
}, nil
}
var (
@@ -717,11 +713,10 @@ func (f *forwarder) send(ctx context.Context, fq *forwardQuery, rr resolverAndDe
}()
}
if strings.HasPrefix(rr.name.Addr, "http://") {
const isPeerAPI = true
if !buildfeatures.HasPeerAPIClient {
return nil, feature.ErrUnavailable
}
res, err := f.sendDoH(ctx, rr.name.Addr, f.dialer.PeerAPIHTTPClient(), fq.packet, isPeerAPI)
res, err := f.sendDoH(ctx, rr.name.Addr, f.dialer.PeerAPIHTTPClient(), fq.packet)
if err != nil {
return nil, err
}
@@ -736,9 +731,8 @@ func (f *forwarder) send(ctx context.Context, fq *forwardQuery, rr resolverAndDe
// usable when the resolver carries a bootstrap resolution, or when the
// URL's host is an IP literal, since we cannot resolve the DoH
// server's own name through DNS without recursing through ourselves.
const isPeerAPI = false
if hc, ok := f.getDoHClientForResolver(rr.name); ok {
res, err := f.sendDoH(ctx, rr.name.Addr, hc, fq.packet, isPeerAPI)
res, err := f.sendDoH(ctx, rr.name.Addr, hc, fq.packet)
if err != nil {
return nil, err
}
@@ -1697,9 +1691,9 @@ func (p *closePool) Close() error {
return nil
}
// PeerAPIMetadata captures data about the HTTP
// DoHMetadata captures data about the HTTP
// request and response when a DNS request is
// forwarded to a PeerAPI DoH server, e.g. for
// forwarded to a DoH server, e.g. PeerAPI DoH for
// exit nodes or app connectors.
//
// As of 2026-09-24, the only known consumer is
@@ -1708,21 +1702,26 @@ func (p *closePool) Close() error {
// a client, and to extract authorization tokens
// from the response headers, which it then uses
// in further communication with the connector.
type PeerAPIMetadata struct {
// RequestURL is a clone of the URL of the PeerAPI request
type DoHMetadata struct {
// RequestURL is the URL of the DoH request
// that produced the response.
// It is passed as a pointer to avoid allocations.
// It should not be modified.
RequestURL *url.URL
// ResponseHeader is a clone of the PeerAPI HTTP response headers.
// ResponseHeader is the DoH HTTP response headers.
// It references the actual headers which may or may
// not have been sent to the HTTP client.
// It should not be modified.
ResponseHeader http.Header
}
// Response is a DNS response in bytes, along with metadata
// from the PeerAPI DoH server that served it, if it was served
// by a PeerAPI DoH server.
// from the DoH server that served it, if it was served
// by a DoH server.
type Response struct {
// Bs is the wire-encoded DNS response.
Bs []byte
// PeerAPIMeta is non-nil if the response came
// from a PeerAPI DoH server, and nil otherwise.
PeerAPIMeta *PeerAPIMetadata
// DoHMeta is non-nil if the response came
// from a DoH server, and nil otherwise.
DoHMeta *DoHMetadata
}
+18 -28
View File
@@ -299,7 +299,7 @@ func TestControlDPremiumDoHLive(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
res, err := fwd.sendDoH(ctx, urlBase, c, query, false)
res, err := fwd.sendDoH(ctx, urlBase, c, query)
if err != nil {
t.Fatalf("sendDoH: %v", err)
}
@@ -2479,11 +2479,11 @@ func TestResolversCustomScheme(t *testing.T) {
}
}
func TestPeerAPIDoH(t *testing.T) {
func TestDoHMeta(t *testing.T) {
const domain = "example.com."
query := makeTestRequest(t, domain, dns.TypeA, 0)
response := makeTestResponse(t, domain, dns.RCodeSuccess, netip.MustParseAddr("1.2.3.4"))
testHdrVal := "hello from PeerAPI"
testHdrVal := "hello from DoH"
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", dohType)
@@ -2495,30 +2495,20 @@ func TestPeerAPIDoH(t *testing.T) {
f := &forwarder{logf: t.Logf}
urlBase := srv.URL + "/dns-query"
for _, isPeerAPI := range []bool{true, false} {
t.Run(fmt.Sprintf("isPeerAPI=%v", isPeerAPI), func(t *testing.T) {
res, err := f.sendDoH(t.Context(), urlBase, srv.Client(), query, isPeerAPI)
if err != nil {
t.Fatalf("sendDoH: %+v", err)
}
if !bytes.Equal(res.Bs, response) {
t.Errorf("response = %x, want %x", res.Bs, response)
}
if !isPeerAPI {
if res.PeerAPIMeta != nil {
t.Errorf("PeerAPIMeta = %+v, want nil", res.PeerAPIMeta)
}
return
}
if res.PeerAPIMeta == nil {
t.Fatal("PeerAPIMeta = nil, want non-nil")
}
if want, got := testHdrVal, res.PeerAPIMeta.ResponseHeader.Get("Tailscale-Test"); want != got {
t.Errorf("PeerAPIMeta.Header[Tailscale-Test] = %q, want %q", got, want)
}
if want, got := urlBase, res.PeerAPIMeta.RequestURL.String(); want != got {
t.Errorf("PeerAPIMeta.RequestURL = %q, want %q", got, want)
}
})
res, err := f.sendDoH(t.Context(), urlBase, srv.Client(), query)
if err != nil {
t.Fatalf("sendDoH: %+v", err)
}
if !bytes.Equal(res.Bs, response) {
t.Errorf("response = %x, want %x", res.Bs, response)
}
if res.DoHMeta == nil {
t.Fatal("DoHMeta = nil, want non-nil")
}
if want, got := testHdrVal, res.DoHMeta.ResponseHeader.Get("Tailscale-Test"); want != got {
t.Errorf("DoHMeta.Header[Tailscale-Test] = %q, want %q", got, want)
}
if want, got := urlBase, res.DoHMeta.RequestURL.String(); want != got {
t.Errorf("DoHMeta.RequestURL = %q, want %q", got, want)
}
}
+2 -2
View File
@@ -550,9 +550,9 @@ func (r *Resolver) HandlePeerDNSQuery(ctx context.Context, q []byte, from netip.
}
}
select {
case fwdRes, ok := <-ch:
case p, ok := <-ch:
if ok {
return fwdRes.Bs, nil
return p.Bs, nil
}
panic("unexpected close chan")
default: