-
Notifications
You must be signed in to change notification settings - Fork 4.2k
DNS: Reviewed #4611
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
DNS: Reviewed #4611
Conversation
1 好像确实是个BUG 挪个位置就行了 |
2和3有歧义,没看懂这个改动是否会等待更长时间,如果会变慢: dns和routing使用同一个geoip instance也是我需要的,我用了商业ip库,启动xray就吃掉了2g内存 最后,我不看好 |
priorIPs logic is simple: act same as expectedIPs but if no ip matched, the original-IPs still returned without any change, it is useful for workers/MitM configs. unexpectedIPs and unpriorIPs are just reverse-form of expected/priorIPs, and i explain why we need reverse-form too.
most codes in nameserver files are duplicated, anyway, queryStrategy-code repeated in all nameservers, even localhost and fakedns, so i move it to (nameserver)Client struct (as ipOption) and now it's code is written only once. /// also, you write tag code in QueryIP function, but that is wrong, because tag is a fixed-option and should be set once, not each time QueryIP executed. /// anyway, these are only minor-optimizations and don't matter much, what matters is the bugs that are fixed. also, no logic has changed and everything is the same as before. /// in addition, test explodes is related to xhttp and not to me. |
28245fd
to
fbe2bb9
Compare
This was related to 3 other bugs in xray-core:
|
3 is a critical bug, suppose we receive only AAAA-response and the A-response dropped for a request, So for all subsequent requests and for 600 seconds we only have ipv6!!! /// this problem affect internal usage of built-in-DNS (for example domainStrategy = "UseIP" or domainStrategy = "IPOnDemand" for routing) but not affect client/browser request, because for client/browser IP-request we have two distinct request for IPv4 and IPv6 but for UseIP/IPOnDemand requests we have one merged request, and this bug only affect merged requests. |
#4560 (comment)
After reviewing DNS-codes, I found and fixed some bugs, optimized the code and added some new features.
Fixed bugs:
When the cache is disabled (
disableCache = true
), instead of not using the cache and sending a new IP-query, it both uses the cache and sends new IP-Query!This is because the order of the codes in nameserver_xxx-QueryIP function is wrong and the
ips, ttl, err := s.findIPsForDomain(fqdn, option)
should be afterselect-case
code. linkalso we should not use
for
loop for this part of code.Suppose dialing a dns-server is unsuccessful(for tcp/quic base DNS)[for example receiving rst-ack after sending syn or receiving http-error response for doh], Instead of immediately returning an error and trying the next DNS-server-fallback, it waits until the timeout ends and then tries the next fallback!
When ipOption.IPv4Enable and ipOption.IPv6Enable are both true, two IP-Query(A, AAAA) are sent and it waits for both responses to be received, then it merges the responses and returns, but suppose only AAAA-response is received and in the meantime, another request comes, while the first request is still waiting for A-response, For the second request, since AAAA-record is in the cache, it uses the cache and incorrectly only v6-IPs is returned for the second request! while the second request must wait for A-response like the first request, more details: DNS: Reviewed #4611 (comment)
when IP-record-until-expire-time is less than 1 seconds and the IP-list is not empty, it returns IPs with
TTL = 0
but we shouldn't set record-TTL to 0. The number 0 is not defined in the standard, and it may cause DNS information to be ignored or rejected,so after converting to
uint32
, It should be rounded up, not down. linkthe
IsOwnLink
function in "app > dns > dns.go" not updated after adding tag for each DNS-server.instead of creating new
GeoIPMatcherContainer
in "dns.go" we should useGlobalGeoIPContainer
to reduce memory usage.GeoIPMatcherContainer
is implemented to reduce memory usage, so we should only have one instance ofGeoIPMatcherContainer
in the entire code.when no IPs match
expectedIPs
, we should returnErrEmptyResponse
instead oferrExpectedIPNonMatch
,otherwise, DNS-proxy send no response to client/browser DNS-query.
in
multi_error.go > AllEqual
errors compare with == instead of errors.Is !New features:
disableCache
for each DNS-Server-Object:currently we have only one global disableCache option that affects all DNS-servers, but we may want to disable the cache only for a specific DNS-Server.
///
priorIPs
for each DNS-Server-Object:allowUnexpectedIPs
option is a bit confusing and when it is true expectedIPs act as priorIPs,so it is better that we have
priorIPs
option instead, which is more clear.also, we may have an expectedIPs separate from priorIPs.
for example suppose that we can only handle cloudflare and cloudfront IPs, but we prefer cloudflare IPs, so we should set:
so we may need seperate
priorIPs
option.as a result, I add
priorIPs
option and removeallowUnexpectedIPs
option.///
finalQuery
for DNS-Server-Object:**Suppose you want to use DNS-Server-A for "youtube.com", but use DNS-Server-B for other google sites and use DNS-Server-C for others, so you should set:
But for whatever reason, server-A may be unavailable for a while(for example, the network may be unreachable for a while) so it uses server-B for "youtube.com", but we don't want this to happen.
Currently, there is no mechanism to prevent using server-B for "youtube.com", this is due to strange behavior of
skipFallback
(except creating custom-geosite where "youtube.com" is removed from "google" list, but this is not possible for all users)but now we can set
finalQuery= true
for server-A, so any result from server-A return as a final-result and no other DNS-server will be performed.///
unexpectedIPs
for DNS-Server-Object:**Suppose we want no IP to be in a IP-range-A, and if all IPs in IP-range-A, the next-dns-fallback performed.
for example for Serverless-for-Iran anti-sanction-version, i want to use a anti-sanction DNS, but goverment-run-anti-sanction-DNS only bypass sanctions and not filter.
IRGFW return 10.10.34.0/24, 2001:4188:2:600:10:10:34:0/120 range for blocked domain, so if the return-IPs is in these ranges, the fallback-DNS should be performed.
one way to achieve this goal is creating custom-geosite and then using
!
sign, but this is not possible for all users.another way is to calculate reverse-CIDR-list, for example using online-tools to calculate reverse-CIDR-list, but the reverse-CIDR-list is long and it causes the configuration to be messy.
as a result i add
unexpectedIPs
option, and a IP is matched if and only it does not match any of the IP-ranges in theunexpectedIPs
list, in other words:expectedIPs = [0.0.0.0/0, ::/0] - unexpectedIPs.
also, we may need all IPs to be in range-A, and no IP to be in range B, so we need both
expectedIPS
andunexpectedIPs
:expectedIPS=[range-A], unexpectedIPs=[range-B]
///
unpriorIPs(notPreferredIPs)
for DNS-Server-Object:**reverse form of priorIPs, Similar to unexpectedIPs, we also need
unpriorIPs(notPreferredIPs)
, and these are the IPs we don't prefer to have.(Currently the names
priorIPs
andunpriorIPs
have been chosen, but we can also namepreferredIPs
andnotPreferredIPs
)///
Add to Documentation:
optimization:
Also, some optimizations have been made which are clear in the code and do not need to be explained.