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  }