dns.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. package route
  2. import (
  3. "context"
  4. "math"
  5. "net/http"
  6. "github.com/metacubex/mihomo/component/resolver"
  7. "github.com/go-chi/chi/v5"
  8. "github.com/go-chi/render"
  9. "github.com/miekg/dns"
  10. "github.com/samber/lo"
  11. )
  12. func dnsRouter() http.Handler {
  13. r := chi.NewRouter()
  14. r.Get("/query", queryDNS)
  15. return r
  16. }
  17. func queryDNS(w http.ResponseWriter, r *http.Request) {
  18. if resolver.DefaultResolver == nil {
  19. render.Status(r, http.StatusInternalServerError)
  20. render.JSON(w, r, newError("DNS section is disabled"))
  21. return
  22. }
  23. name := r.URL.Query().Get("name")
  24. qTypeStr, _ := lo.Coalesce(r.URL.Query().Get("type"), "A")
  25. qType, exist := dns.StringToType[qTypeStr]
  26. if !exist {
  27. render.Status(r, http.StatusBadRequest)
  28. render.JSON(w, r, newError("invalid query type"))
  29. return
  30. }
  31. ctx, cancel := context.WithTimeout(context.Background(), resolver.DefaultDNSTimeout)
  32. defer cancel()
  33. msg := dns.Msg{}
  34. msg.SetQuestion(dns.Fqdn(name), qType)
  35. resp, err := resolver.DefaultResolver.ExchangeContext(ctx, &msg)
  36. if err != nil {
  37. render.Status(r, http.StatusInternalServerError)
  38. render.JSON(w, r, newError(err.Error()))
  39. return
  40. }
  41. responseData := render.M{
  42. "Status": resp.Rcode,
  43. "Question": resp.Question,
  44. "TC": resp.Truncated,
  45. "RD": resp.RecursionDesired,
  46. "RA": resp.RecursionAvailable,
  47. "AD": resp.AuthenticatedData,
  48. "CD": resp.CheckingDisabled,
  49. }
  50. rr2Json := func(rr dns.RR, _ int) render.M {
  51. header := rr.Header()
  52. return render.M{
  53. "name": header.Name,
  54. "type": header.Rrtype,
  55. "TTL": header.Ttl,
  56. "data": lo.Substring(rr.String(), len(header.String()), math.MaxUint),
  57. }
  58. }
  59. if len(resp.Answer) > 0 {
  60. responseData["Answer"] = lo.Map(resp.Answer, rr2Json)
  61. }
  62. if len(resp.Ns) > 0 {
  63. responseData["Authority"] = lo.Map(resp.Ns, rr2Json)
  64. }
  65. if len(resp.Extra) > 0 {
  66. responseData["Additional"] = lo.Map(resp.Extra, rr2Json)
  67. }
  68. render.JSON(w, r, responseData)
  69. }