hosts.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  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) Start(stage adapter.StartStage) error {
  47. return nil
  48. }
  49. func (t *Transport) Close() error {
  50. return nil
  51. }
  52. func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
  53. question := message.Question[0]
  54. domain := mDNS.CanonicalName(question.Name)
  55. if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA {
  56. if addresses, ok := t.predefined[domain]; ok {
  57. return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil
  58. }
  59. for _, file := range t.files {
  60. addresses := file.Lookup(domain)
  61. if len(addresses) > 0 {
  62. return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil
  63. }
  64. }
  65. }
  66. return &mDNS.Msg{
  67. MsgHdr: mDNS.MsgHdr{
  68. Id: message.Id,
  69. Rcode: mDNS.RcodeNameError,
  70. Response: true,
  71. },
  72. Question: []mDNS.Question{question},
  73. }, nil
  74. }