github.com/sagernet/sing-box@v1.9.0-rc.20/experimental/clashapi/dns.go (about) 1 package clashapi 2 3 import ( 4 "context" 5 "net/http" 6 7 "github.com/sagernet/sing-box/adapter" 8 C "github.com/sagernet/sing-box/constant" 9 "github.com/sagernet/sing/common" 10 11 "github.com/go-chi/chi/v5" 12 "github.com/go-chi/render" 13 "github.com/miekg/dns" 14 ) 15 16 func dnsRouter(router adapter.Router) http.Handler { 17 r := chi.NewRouter() 18 r.Get("/query", queryDNS(router)) 19 return r 20 } 21 22 func queryDNS(router adapter.Router) func(w http.ResponseWriter, r *http.Request) { 23 return func(w http.ResponseWriter, r *http.Request) { 24 name := r.URL.Query().Get("name") 25 qTypeStr := r.URL.Query().Get("type") 26 if qTypeStr == "" { 27 qTypeStr = "A" 28 } 29 30 qType, exist := dns.StringToType[qTypeStr] 31 if !exist { 32 render.Status(r, http.StatusBadRequest) 33 render.JSON(w, r, newError("invalid query type")) 34 return 35 } 36 37 ctx, cancel := context.WithTimeout(context.Background(), C.DNSTimeout) 38 defer cancel() 39 40 msg := dns.Msg{} 41 msg.SetQuestion(dns.Fqdn(name), qType) 42 resp, err := router.Exchange(ctx, &msg) 43 if err != nil { 44 render.Status(r, http.StatusInternalServerError) 45 render.JSON(w, r, newError(err.Error())) 46 return 47 } 48 49 responseData := render.M{ 50 "Status": resp.Rcode, 51 "Question": resp.Question, 52 "Server": "internal", 53 "TC": resp.Truncated, 54 "RD": resp.RecursionDesired, 55 "RA": resp.RecursionAvailable, 56 "AD": resp.AuthenticatedData, 57 "CD": resp.CheckingDisabled, 58 } 59 60 rr2Json := func(rr dns.RR) render.M { 61 header := rr.Header() 62 return render.M{ 63 "name": header.Name, 64 "type": header.Rrtype, 65 "TTL": header.Ttl, 66 "data": rr.String()[len(header.String()):], 67 } 68 } 69 70 if len(resp.Answer) > 0 { 71 responseData["Answer"] = common.Map(resp.Answer, rr2Json) 72 } 73 if len(resp.Ns) > 0 { 74 responseData["Authority"] = common.Map(resp.Ns, rr2Json) 75 } 76 if len(resp.Extra) > 0 { 77 responseData["Additional"] = common.Map(resp.Extra, rr2Json) 78 } 79 80 render.JSON(w, r, responseData) 81 } 82 }