cli: add tailscale dns query (#13368)

Updates tailscale/tailscale#13326

Adds a CLI subcommand to perform DNS queries using the internal DNS forwarder and observe its internals (namely, which upstream resolvers are being used).

Signed-off-by: Andrea Gottardo <andrea@gottardo.me>
This commit is contained in:
Andrea Gottardo
2024-09-24 13:18:45 -07:00
committed by GitHub
parent a98f75b783
commit 8a6f48b455
13 changed files with 396 additions and 7 deletions
+46
View File
@@ -32,6 +32,7 @@ import (
"time"
"github.com/google/uuid"
"golang.org/x/net/dns/dnsmessage"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/clientupdate"
"tailscale.com/drive"
@@ -49,6 +50,7 @@ import (
"tailscale.com/taildrop"
"tailscale.com/tka"
"tailscale.com/tstime"
"tailscale.com/types/dnstype"
"tailscale.com/types/key"
"tailscale.com/types/logger"
"tailscale.com/types/logid"
@@ -99,6 +101,7 @@ var handler = map[string]localAPIHandler{
"dev-set-state-store": (*Handler).serveDevSetStateStore,
"dial": (*Handler).serveDial,
"dns-osconfig": (*Handler).serveDNSOSConfig,
"dns-query": (*Handler).serveDNSQuery,
"drive/fileserver-address": (*Handler).serveDriveServerAddr,
"drive/shares": (*Handler).serveShares,
"file-targets": (*Handler).serveFileTargets,
@@ -2746,6 +2749,49 @@ func (h *Handler) serveDNSOSConfig(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(response)
}
// serveDNSQuery provides the ability to perform DNS queries using the internal
// DNS forwarder. This is useful for debugging and testing purposes.
// URL parameters:
// - name: the domain name to query
// - type: the DNS record type to query as a number (default if empty: A = '1')
//
// The response if successful is a DNSQueryResponse JSON object.
func (h *Handler) serveDNSQuery(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" {
http.Error(w, "only GET allowed", http.StatusMethodNotAllowed)
return
}
// Require write access for privacy reasons.
if !h.PermitWrite {
http.Error(w, "dns-query access denied", http.StatusForbidden)
return
}
q := r.URL.Query()
name := q.Get("name")
queryType := q.Get("type")
qt := dnsmessage.TypeA
if queryType != "" {
t, err := dnstype.DNSMessageTypeForString(queryType)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
qt = t
}
res, rrs, err := h.b.QueryDNS(name, qt)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(&apitype.DNSQueryResponse{
Bytes: res,
Resolvers: rrs,
})
}
// serveDriveServerAddr handles updates of the Taildrive file server address.
func (h *Handler) serveDriveServerAddr(w http.ResponseWriter, r *http.Request) {
if r.Method != "PUT" {