mirror of
https://github.com/3proxy/3proxy.git
synced 2026-10-28 22:05:48 +08:00
Without nserver (or fakeresolve) names were resolved by the C library. 3proxy's own resolver is now the default, with the system's name servers: up to 3 from /etc/resolv.conf, on Windows from the registry (set for the system, set for an interface with an address, Tcpip6 interfaces, then those DHCP gave). With none found, the C library as before. nserver takes up to 3 as well (MAXNSERVERS), a fourth is warned about. The name servers in force belong to the process, not a configuration: nserver lines are kept aside while a configuration is read and replace them only once it is committed, so a reload resolves with those in force until then. Resolutions and dnspr read a copy of them. The system's are read at start, before the configuration and a chroot in it, and are in force while it is read, so its host names resolve with them; read again at a commit, and checked every 5 seconds from the main loop while the default is in force. What cannot be read then (within a chroot) stays as last read. The hosts file, read with them, is imported into tables of its own while the default is in force: its first address of a family for a name. A name is looked up as one nsrecord made first, then the hosts file, then the name cache, then name servers. A changed file replaces what was imported. No name cache is made for it: without nscache nothing is cached, as before. The name cache's keys are host names of any case now: DNS names are. Tests: sysdns, a name of the hosts file answered by dnspr without nserver, in any case, and not with one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
84 lines
2.4 KiB
Python
84 lines
2.4 KiB
Python
"""The system's name servers and hosts file as the default resolver: with
|
|
no nserver in a configuration, names in the hosts file are answered from
|
|
it, through the name cache; with nserver lines, the file is not used."""
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
import time
|
|
|
|
|
|
def hosts_path():
|
|
if sys.platform == "win32":
|
|
return os.path.join(os.environ.get("SystemRoot", r"C:\Windows"),
|
|
"System32", "drivers", "etc", "hosts")
|
|
return "/etc/hosts"
|
|
|
|
|
|
def hosts_localhost():
|
|
"""Whether the hosts file maps localhost to 127.0.0.1 itself."""
|
|
try:
|
|
with open(hosts_path(), errors="replace") as f:
|
|
for line in f:
|
|
words = line.split("#", 1)[0].split()
|
|
if len(words) > 1 and words[0] == "127.0.0.1" and "localhost" in [w.lower() for w in words[1:]]:
|
|
return True
|
|
except OSError:
|
|
pass
|
|
return False
|
|
|
|
|
|
def system_nameserver():
|
|
"""Whether there is a name server for 3proxy to find: resolv.conf has
|
|
one, or on Windows the registry is taken to."""
|
|
if sys.platform == "win32":
|
|
return True
|
|
try:
|
|
with open("/etc/resolv.conf") as f:
|
|
return any(re.match(r"nameserver\s+[0-9a-fA-F.:]+\s*$", l.split("#")[0]) for l in f)
|
|
except OSError:
|
|
return False
|
|
|
|
|
|
def wait(t, port, name):
|
|
deadline = time.time() + 5
|
|
while time.time() < deadline:
|
|
if t.dns_query(port, name):
|
|
return
|
|
|
|
|
|
def run(t):
|
|
if not hosts_localhost() or not system_nameserver():
|
|
t.skip("no localhost in the hosts file, or no system name server")
|
|
return
|
|
|
|
port = t.free_port()
|
|
t.start("sysdns", f"""
|
|
log
|
|
flush
|
|
auth iponly
|
|
allow *
|
|
dnspr -p{port}
|
|
""")
|
|
wait(t, port, "localhost")
|
|
t.eq(["127.0.0.1"], t.dns_query(port, "localhost"),
|
|
"without nserver, a name of the hosts file is answered from it")
|
|
t.eq(["127.0.0.1"], t.dns_query(port, "LocalHost"),
|
|
"whatever its case")
|
|
|
|
# with a name server configured, one that answers nothing, the hosts
|
|
# file is not used
|
|
other = t.free_port()
|
|
t.start("sysdns_nserver", f"""
|
|
log
|
|
flush
|
|
nserver 127.0.0.1:{t.free_port()}
|
|
nscache 1024
|
|
auth iponly
|
|
allow *
|
|
dnspr -p{other}
|
|
""")
|
|
wait(t, other, "localhost")
|
|
t.ne(["127.0.0.1"], t.dns_query(other, "localhost") or [],
|
|
"with nserver, the hosts file is not used")
|