github.com/Uhtred009/v2ray-core-1@v4.31.2+incompatible/app/dns/hosts.go (about) 1 // +build !confonly 2 3 package dns 4 5 import ( 6 "v2ray.com/core/common" 7 "v2ray.com/core/common/net" 8 "v2ray.com/core/common/strmatcher" 9 "v2ray.com/core/features" 10 ) 11 12 // StaticHosts represents static domain-ip mapping in DNS server. 13 type StaticHosts struct { 14 ips [][]net.Address 15 matchers *strmatcher.MatcherGroup 16 } 17 18 var typeMap = map[DomainMatchingType]strmatcher.Type{ 19 DomainMatchingType_Full: strmatcher.Full, 20 DomainMatchingType_Subdomain: strmatcher.Domain, 21 DomainMatchingType_Keyword: strmatcher.Substr, 22 DomainMatchingType_Regex: strmatcher.Regex, 23 } 24 25 func toStrMatcher(t DomainMatchingType, domain string) (strmatcher.Matcher, error) { 26 strMType, f := typeMap[t] 27 if !f { 28 return nil, newError("unknown mapping type", t).AtWarning() 29 } 30 matcher, err := strMType.New(domain) 31 if err != nil { 32 return nil, newError("failed to create str matcher").Base(err) 33 } 34 return matcher, nil 35 } 36 37 // NewStaticHosts creates a new StaticHosts instance. 38 func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDomain) (*StaticHosts, error) { 39 g := new(strmatcher.MatcherGroup) 40 sh := &StaticHosts{ 41 ips: make([][]net.Address, len(hosts)+len(legacy)+16), 42 matchers: g, 43 } 44 45 if legacy != nil { 46 features.PrintDeprecatedFeatureWarning("simple host mapping") 47 48 for domain, ip := range legacy { 49 matcher, err := strmatcher.Full.New(domain) 50 common.Must(err) 51 id := g.Add(matcher) 52 53 address := ip.AsAddress() 54 if address.Family().IsDomain() { 55 return nil, newError("invalid domain address in static hosts: ", address.Domain()).AtWarning() 56 } 57 58 sh.ips[id] = []net.Address{address} 59 } 60 } 61 62 for _, mapping := range hosts { 63 matcher, err := toStrMatcher(mapping.Type, mapping.Domain) 64 if err != nil { 65 return nil, newError("failed to create domain matcher").Base(err) 66 } 67 id := g.Add(matcher) 68 ips := make([]net.Address, 0, len(mapping.Ip)+1) 69 if len(mapping.Ip) > 0 { 70 for _, ip := range mapping.Ip { 71 addr := net.IPAddress(ip) 72 if addr == nil { 73 return nil, newError("invalid IP address in static hosts: ", ip).AtWarning() 74 } 75 ips = append(ips, addr) 76 } 77 } else if len(mapping.ProxiedDomain) > 0 { 78 ips = append(ips, net.DomainAddress(mapping.ProxiedDomain)) 79 } else { 80 return nil, newError("neither IP address nor proxied domain specified for domain: ", mapping.Domain).AtWarning() 81 } 82 83 // Special handling for localhost IPv6. This is a dirty workaround as JSON config supports only single IP mapping. 84 if len(ips) == 1 && ips[0] == net.LocalHostIP { 85 ips = append(ips, net.LocalHostIPv6) 86 } 87 88 sh.ips[id] = ips 89 } 90 91 return sh, nil 92 } 93 94 func filterIP(ips []net.Address, option IPOption) []net.Address { 95 filtered := make([]net.Address, 0, len(ips)) 96 for _, ip := range ips { 97 if (ip.Family().IsIPv4() && option.IPv4Enable) || (ip.Family().IsIPv6() && option.IPv6Enable) { 98 filtered = append(filtered, ip) 99 } 100 } 101 if len(filtered) == 0 { 102 return nil 103 } 104 return filtered 105 } 106 107 // LookupIP returns IP address for the given domain, if exists in this StaticHosts. 108 func (h *StaticHosts) LookupIP(domain string, option IPOption) []net.Address { 109 indices := h.matchers.Match(domain) 110 if len(indices) == 0 { 111 return nil 112 } 113 ips := []net.Address{} 114 for _, id := range indices { 115 ips = append(ips, h.ips[id]...) 116 } 117 if len(ips) == 1 && ips[0].Family().IsDomain() { 118 return ips 119 } 120 return filterIP(ips, option) 121 }