Xray-core/app/dns/hosts.go
世界 cd4631ce99
Merge dns (#722)
* DNS: add clientip for specific nameserver

* Refactoring: DNS App

* DNS: add DNS over QUIC support

* Feat: add disableCache option for DNS

* Feat: add queryStrategy option for DNS

* Feat: add disableFallback & skipFallback option for DNS

* Feat: DNS hosts support multiple addresses

* Feat: DNS transport over TCP

* DNS: fix typo & refine code

* DNS: refine code

* Add disableFallbackIfMatch dns option

* Feat: routing and freedom outbound ignore Fake DNS

Turn off fake DNS for request sent from Routing and Freedom outbound.
Fake DNS now only apply to DNS outbound.
This is important for Android, where VPN service take over all system DNS
traffic and pass it to core.  "UseIp" option can be used in Freedom outbound
to avoid getting fake IP and fail connection.

* Fix test

* Fix dns return

* Fix local dns return empty

* Apply timeout to dns outbound

* Update app/dns/config.go

Co-authored-by: Loyalsoldier <10487845+loyalsoldier@users.noreply.github.com>
Co-authored-by: Ye Zhihao <vigilans@foxmail.com>
Co-authored-by: maskedeken <52683904+maskedeken@users.noreply.github.com>
Co-authored-by: V2Fly Team <51714622+vcptr@users.noreply.github.com>
Co-authored-by: CalmLong <37164399+calmlong@users.noreply.github.com>
Co-authored-by: Shelikhoo <xiaokangwang@outlook.com>
Co-authored-by: 秋のかえで <autmaple@protonmail.com>
Co-authored-by: 朱聖黎 <digglife@gmail.com>
Co-authored-by: rurirei <72071920+rurirei@users.noreply.github.com>
Co-authored-by: yuhan6665 <1588741+yuhan6665@users.noreply.github.com>
Co-authored-by: Arthur Morgan <4637240+badO1a5A90@users.noreply.github.com>
2021-10-16 21:02:51 +08:00

110 lines
3.2 KiB
Go

package dns
import (
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/strmatcher"
"github.com/xtls/xray-core/features"
"github.com/xtls/xray-core/features/dns"
)
// StaticHosts represents static domain-ip mapping in DNS server.
type StaticHosts struct {
ips [][]net.Address
matchers *strmatcher.MatcherGroup
}
// NewStaticHosts creates a new StaticHosts instance.
func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDomain) (*StaticHosts, error) {
g := new(strmatcher.MatcherGroup)
sh := &StaticHosts{
ips: make([][]net.Address, len(hosts)+len(legacy)+16),
matchers: g,
}
if legacy != nil {
features.PrintDeprecatedFeatureWarning("simple host mapping")
for domain, ip := range legacy {
matcher, err := strmatcher.Full.New(domain)
common.Must(err)
id := g.Add(matcher)
address := ip.AsAddress()
if address.Family().IsDomain() {
return nil, newError("invalid domain address in static hosts: ", address.Domain()).AtWarning()
}
sh.ips[id] = []net.Address{address}
}
}
for _, mapping := range hosts {
matcher, err := toStrMatcher(mapping.Type, mapping.Domain)
if err != nil {
return nil, newError("failed to create domain matcher").Base(err)
}
id := g.Add(matcher)
ips := make([]net.Address, 0, len(mapping.Ip)+1)
switch {
case len(mapping.ProxiedDomain) > 0:
ips = append(ips, net.DomainAddress(mapping.ProxiedDomain))
case len(mapping.Ip) > 0:
for _, ip := range mapping.Ip {
addr := net.IPAddress(ip)
if addr == nil {
return nil, newError("invalid IP address in static hosts: ", ip).AtWarning()
}
ips = append(ips, addr)
}
default:
return nil, newError("neither IP address nor proxied domain specified for domain: ", mapping.Domain).AtWarning()
}
sh.ips[id] = ips
}
return sh, nil
}
func filterIP(ips []net.Address, option dns.IPOption) []net.Address {
filtered := make([]net.Address, 0, len(ips))
for _, ip := range ips {
if (ip.Family().IsIPv4() && option.IPv4Enable) || (ip.Family().IsIPv6() && option.IPv6Enable) {
filtered = append(filtered, ip)
}
}
return filtered
}
func (h *StaticHosts) lookupInternal(domain string) []net.Address {
var ips []net.Address
for _, id := range h.matchers.Match(domain) {
ips = append(ips, h.ips[id]...)
}
return ips
}
func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) []net.Address {
switch addrs := h.lookupInternal(domain); {
case len(addrs) == 0: // Not recorded in static hosts, return nil
return nil
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Try to unwrap domain
newError("found replaced domain: ", domain, " -> ", addrs[0].Domain(), ". Try to unwrap it").AtDebug().WriteToLog()
if maxDepth > 0 {
unwrapped := h.lookup(addrs[0].Domain(), option, maxDepth-1)
if unwrapped != nil {
return unwrapped
}
}
return addrs
default: // IP record found, return a non-nil IP array
return filterIP(addrs, option)
}
}
// Lookup returns IP addresses or proxied domain for the given domain, if exists in this StaticHosts.
func (h *StaticHosts) Lookup(domain string, option dns.IPOption) []net.Address {
return h.lookup(domain, option, 5)
}