hosts.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. package hosts
  2. import (
  3. "context"
  4. "net/netip"
  5. "os"
  6. "github.com/sagernet/sing-box/adapter"
  7. C "github.com/sagernet/sing-box/constant"
  8. "github.com/sagernet/sing-box/dns"
  9. "github.com/sagernet/sing-box/log"
  10. "github.com/sagernet/sing-box/option"
  11. "github.com/sagernet/sing/service/filemanager"
  12. mDNS "github.com/miekg/dns"
  13. )
  14. func RegisterTransport(registry *dns.TransportRegistry) {
  15. dns.RegisterTransport[option.HostsDNSServerOptions](registry, C.DNSTypeHosts, NewTransport)
  16. }
  17. var _ adapter.DNSTransport = (*Transport)(nil)
  18. type Transport struct {
  19. dns.TransportAdapter
  20. files []*File
  21. predefined map[string][]netip.Addr
  22. }
  23. func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.HostsDNSServerOptions) (adapter.DNSTransport, error) {
  24. var (
  25. files []*File
  26. predefined = make(map[string][]netip.Addr)
  27. )
  28. if len(options.Path) == 0 {
  29. files = append(files, NewFile(DefaultPath))
  30. } else {
  31. for _, path := range options.Path {
  32. files = append(files, NewFile(filemanager.BasePath(ctx, os.ExpandEnv(path))))
  33. }
  34. }
  35. if options.Predefined != nil {
  36. for _, entry := range options.Predefined.Entries() {
  37. predefined[mDNS.CanonicalName(entry.Key)] = entry.Value
  38. }
  39. }
  40. return &Transport{
  41. TransportAdapter: dns.NewTransportAdapter(C.DNSTypeHosts, tag, nil),
  42. files: files,
  43. predefined: predefined,
  44. }, nil
  45. }
  46. func (t *Transport) Reset() {
  47. }
  48. func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
  49. question := message.Question[0]
  50. domain := mDNS.CanonicalName(question.Name)
  51. if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA {
  52. if addresses, ok := t.predefined[domain]; ok {
  53. return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil
  54. }
  55. for _, file := range t.files {
  56. addresses := file.Lookup(domain)
  57. if len(addresses) > 0 {
  58. return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil
  59. }
  60. }
  61. }
  62. return &mDNS.Msg{
  63. MsgHdr: mDNS.MsgHdr{
  64. Id: message.Id,
  65. Rcode: mDNS.RcodeNameError,
  66. Response: true,
  67. },
  68. Question: []mDNS.Question{question},
  69. }, nil
  70. }