1
0

hosts.go 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. package dns
  2. import (
  3. "context"
  4. "sort"
  5. "github.com/xtls/xray-core/common/errors"
  6. "github.com/xtls/xray-core/common/net"
  7. "github.com/xtls/xray-core/common/strmatcher"
  8. "github.com/xtls/xray-core/features/dns"
  9. )
  10. // StaticHosts represents static domain-ip mapping in DNS server.
  11. type StaticHosts struct {
  12. ips [][]net.Address
  13. matchers *strmatcher.MatcherGroup
  14. }
  15. // NewStaticHosts creates a new StaticHosts instance.
  16. func NewStaticHosts(hosts []*Config_HostMapping) (*StaticHosts, error) {
  17. g := new(strmatcher.MatcherGroup)
  18. sh := &StaticHosts{
  19. ips: make([][]net.Address, len(hosts)+16),
  20. matchers: g,
  21. }
  22. for _, mapping := range hosts {
  23. matcher, err := toStrMatcher(mapping.Type, mapping.Domain)
  24. if err != nil {
  25. return nil, errors.New("failed to create domain matcher").Base(err)
  26. }
  27. id := g.Add(matcher)
  28. ips := make([]net.Address, 0, len(mapping.Ip)+1)
  29. switch {
  30. case len(mapping.ProxiedDomain) > 0:
  31. ips = append(ips, net.DomainAddress(mapping.ProxiedDomain))
  32. case len(mapping.Ip) > 0:
  33. for _, ip := range mapping.Ip {
  34. addr := net.IPAddress(ip)
  35. if addr == nil {
  36. return nil, errors.New("invalid IP address in static hosts: ", ip).AtWarning()
  37. }
  38. ips = append(ips, addr)
  39. }
  40. }
  41. sh.ips[id] = ips
  42. }
  43. return sh, nil
  44. }
  45. func filterIP(ips []net.Address, option dns.IPOption) []net.Address {
  46. filtered := make([]net.Address, 0, len(ips))
  47. for _, ip := range ips {
  48. if (ip.Family().IsIPv4() && option.IPv4Enable) || (ip.Family().IsIPv6() && option.IPv6Enable) {
  49. filtered = append(filtered, ip)
  50. }
  51. }
  52. return filtered
  53. }
  54. func (h *StaticHosts) lookupInternal(domain string) []net.Address {
  55. MatchSlice := h.matchers.Match(domain)
  56. sort.Slice(MatchSlice, func(i, j int) bool {
  57. return MatchSlice[i] < MatchSlice[j]
  58. })
  59. if len(MatchSlice) == 0 {
  60. return nil
  61. }
  62. return h.ips[MatchSlice[0]]
  63. }
  64. func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) []net.Address {
  65. switch addrs := h.lookupInternal(domain); {
  66. case len(addrs) == 0: // Not recorded in static hosts, return nil
  67. return addrs
  68. case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Try to unwrap domain
  69. errors.LogDebug(context.Background(), "found replaced domain: ", domain, " -> ", addrs[0].Domain(), ". Try to unwrap it")
  70. if maxDepth > 0 {
  71. unwrapped := h.lookup(addrs[0].Domain(), option, maxDepth-1)
  72. if unwrapped != nil {
  73. return unwrapped
  74. }
  75. }
  76. return addrs
  77. default: // IP record found, return a non-nil IP array
  78. return filterIP(addrs, option)
  79. }
  80. }
  81. // Lookup returns IP addresses or proxied domain for the given domain, if exists in this StaticHosts.
  82. func (h *StaticHosts) Lookup(domain string, option dns.IPOption) []net.Address {
  83. return h.lookup(domain, option, 5)
  84. }