github.com/Uhtred009/v2ray-core-1@v4.31.2+incompatible/infra/conf/dns.go (about) 1 package conf 2 3 import ( 4 "encoding/json" 5 "sort" 6 "strings" 7 8 "v2ray.com/core/app/dns" 9 "v2ray.com/core/app/router" 10 "v2ray.com/core/common/net" 11 ) 12 13 type NameServerConfig struct { 14 Address *Address 15 Port uint16 16 Domains []string 17 ExpectIPs StringList 18 } 19 20 func (c *NameServerConfig) UnmarshalJSON(data []byte) error { 21 var address Address 22 if err := json.Unmarshal(data, &address); err == nil { 23 c.Address = &address 24 return nil 25 } 26 27 var advanced struct { 28 Address *Address `json:"address"` 29 Port uint16 `json:"port"` 30 Domains []string `json:"domains"` 31 ExpectIPs StringList `json:"expectIps"` 32 } 33 if err := json.Unmarshal(data, &advanced); err == nil { 34 c.Address = advanced.Address 35 c.Port = advanced.Port 36 c.Domains = advanced.Domains 37 c.ExpectIPs = advanced.ExpectIPs 38 return nil 39 } 40 41 return newError("failed to parse name server: ", string(data)) 42 } 43 44 func toDomainMatchingType(t router.Domain_Type) dns.DomainMatchingType { 45 switch t { 46 case router.Domain_Domain: 47 return dns.DomainMatchingType_Subdomain 48 case router.Domain_Full: 49 return dns.DomainMatchingType_Full 50 case router.Domain_Plain: 51 return dns.DomainMatchingType_Keyword 52 case router.Domain_Regex: 53 return dns.DomainMatchingType_Regex 54 default: 55 panic("unknown domain type") 56 } 57 } 58 59 func (c *NameServerConfig) Build() (*dns.NameServer, error) { 60 if c.Address == nil { 61 return nil, newError("NameServer address is not specified.") 62 } 63 64 var domains []*dns.NameServer_PriorityDomain 65 var originalRules []*dns.NameServer_OriginalRule 66 67 for _, rule := range c.Domains { 68 parsedDomain, err := parseDomainRule(rule) 69 if err != nil { 70 return nil, newError("invalid domain rule: ", rule).Base(err) 71 } 72 73 for _, pd := range parsedDomain { 74 domains = append(domains, &dns.NameServer_PriorityDomain{ 75 Type: toDomainMatchingType(pd.Type), 76 Domain: pd.Value, 77 }) 78 } 79 originalRules = append(originalRules, &dns.NameServer_OriginalRule{ 80 Rule: rule, 81 Size: uint32(len(parsedDomain)), 82 }) 83 } 84 85 geoipList, err := toCidrList(c.ExpectIPs) 86 if err != nil { 87 return nil, newError("invalid ip rule: ", c.ExpectIPs).Base(err) 88 } 89 90 return &dns.NameServer{ 91 Address: &net.Endpoint{ 92 Network: net.Network_UDP, 93 Address: c.Address.Build(), 94 Port: uint32(c.Port), 95 }, 96 PrioritizedDomain: domains, 97 Geoip: geoipList, 98 OriginalRules: originalRules, 99 }, nil 100 } 101 102 var typeMap = map[router.Domain_Type]dns.DomainMatchingType{ 103 router.Domain_Full: dns.DomainMatchingType_Full, 104 router.Domain_Domain: dns.DomainMatchingType_Subdomain, 105 router.Domain_Plain: dns.DomainMatchingType_Keyword, 106 router.Domain_Regex: dns.DomainMatchingType_Regex, 107 } 108 109 // DnsConfig is a JSON serializable object for dns.Config. 110 type DnsConfig struct { 111 Servers []*NameServerConfig `json:"servers"` 112 Hosts map[string]*Address `json:"hosts"` 113 ClientIP *Address `json:"clientIp"` 114 Tag string `json:"tag"` 115 } 116 117 func getHostMapping(addr *Address) *dns.Config_HostMapping { 118 if addr.Family().IsIP() { 119 return &dns.Config_HostMapping{ 120 Ip: [][]byte{[]byte(addr.IP())}, 121 } 122 } else { 123 return &dns.Config_HostMapping{ 124 ProxiedDomain: addr.Domain(), 125 } 126 } 127 } 128 129 // Build implements Buildable 130 func (c *DnsConfig) Build() (*dns.Config, error) { 131 config := &dns.Config{ 132 Tag: c.Tag, 133 } 134 135 if c.ClientIP != nil { 136 if !c.ClientIP.Family().IsIP() { 137 return nil, newError("not an IP address:", c.ClientIP.String()) 138 } 139 config.ClientIp = []byte(c.ClientIP.IP()) 140 } 141 142 for _, server := range c.Servers { 143 ns, err := server.Build() 144 if err != nil { 145 return nil, newError("failed to build name server").Base(err) 146 } 147 config.NameServer = append(config.NameServer, ns) 148 } 149 150 if c.Hosts != nil && len(c.Hosts) > 0 { 151 domains := make([]string, 0, len(c.Hosts)) 152 for domain := range c.Hosts { 153 domains = append(domains, domain) 154 } 155 sort.Strings(domains) 156 for _, domain := range domains { 157 addr := c.Hosts[domain] 158 var mappings []*dns.Config_HostMapping 159 if strings.HasPrefix(domain, "domain:") { 160 mapping := getHostMapping(addr) 161 mapping.Type = dns.DomainMatchingType_Subdomain 162 mapping.Domain = domain[7:] 163 164 mappings = append(mappings, mapping) 165 } else if strings.HasPrefix(domain, "geosite:") { 166 domains, err := loadGeositeWithAttr("geosite.dat", strings.ToUpper(domain[8:])) 167 if err != nil { 168 return nil, newError("invalid geosite settings: ", domain).Base(err) 169 } 170 for _, d := range domains { 171 mapping := getHostMapping(addr) 172 mapping.Type = typeMap[d.Type] 173 mapping.Domain = d.Value 174 175 mappings = append(mappings, mapping) 176 } 177 } else if strings.HasPrefix(domain, "regexp:") { 178 mapping := getHostMapping(addr) 179 mapping.Type = dns.DomainMatchingType_Regex 180 mapping.Domain = domain[7:] 181 182 mappings = append(mappings, mapping) 183 } else if strings.HasPrefix(domain, "keyword:") { 184 mapping := getHostMapping(addr) 185 mapping.Type = dns.DomainMatchingType_Keyword 186 mapping.Domain = domain[8:] 187 188 mappings = append(mappings, mapping) 189 } else if strings.HasPrefix(domain, "full:") { 190 mapping := getHostMapping(addr) 191 mapping.Type = dns.DomainMatchingType_Full 192 mapping.Domain = domain[5:] 193 194 mappings = append(mappings, mapping) 195 } else if strings.HasPrefix(domain, "dotless:") { 196 mapping := getHostMapping(addr) 197 mapping.Type = dns.DomainMatchingType_Regex 198 switch substr := domain[8:]; { 199 case substr == "": 200 mapping.Domain = "^[^.]*$" 201 case !strings.Contains(substr, "."): 202 mapping.Domain = "^[^.]*" + substr + "[^.]*$" 203 default: 204 return nil, newError("substr in dotless rule should not contain a dot: ", substr) 205 } 206 207 mappings = append(mappings, mapping) 208 } else if strings.HasPrefix(domain, "ext:") { 209 kv := strings.Split(domain[4:], ":") 210 if len(kv) != 2 { 211 return nil, newError("invalid external resource: ", domain) 212 } 213 filename := kv[0] 214 country := kv[1] 215 domains, err := loadGeositeWithAttr(filename, country) 216 if err != nil { 217 return nil, newError("failed to load domains: ", country, " from ", filename).Base(err) 218 } 219 for _, d := range domains { 220 mapping := getHostMapping(addr) 221 mapping.Type = typeMap[d.Type] 222 mapping.Domain = d.Value 223 224 mappings = append(mappings, mapping) 225 } 226 } else { 227 mapping := getHostMapping(addr) 228 mapping.Type = dns.DomainMatchingType_Full 229 mapping.Domain = domain 230 231 mappings = append(mappings, mapping) 232 } 233 234 config.StaticHosts = append(config.StaticHosts, mappings...) 235 } 236 } 237 238 return config, nil 239 }