mirror of
https://github.com/3proxy/3proxy.git
synced 2026-10-29 06:15:48 +08:00
Some checks are pending
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Waiting to run
Each service resolves names the way the last of defaultresolve (the name servers in force, configured or the system's with the hosts file), fakeresolve (127.0.0.2) and sysresolve (the C library) read before it says; the last one in the configuration also applies outside services. defaultresolve is the new command, and the default. The name servers and the hosts file no longer depend on the mode: nserver lines, or the system's, are always in force, so dnspr keeps forwarding; with fakeresolve it does not, as before. fakeresolver moves to common.c, which the standalone services link without resolve.c. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
119 lines
4.0 KiB
Python
119 lines
4.0 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; with nserver lines it is not. Each service resolves names the way the
|
|
last of defaultresolve, sysresolve and fakeresolve before it says."""
|
|
|
|
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")
|
|
|
|
# each service resolves the way the command before it says: fake (to
|
|
# 127.0.0.2, where the server is not), the system routines (no
|
|
# nsrecord) or the default (the system's name servers, and nsrecord)
|
|
fake, system, default, srv = t.free_port(), t.free_port(), t.free_port(), t.free_port()
|
|
t.start("sysdns_modes", f"""
|
|
log
|
|
nscache 1024
|
|
nsrecord only3proxy.test 127.0.0.1
|
|
flush
|
|
auth iponly
|
|
allow *
|
|
fakeresolve
|
|
proxy -p{fake}
|
|
sysresolve
|
|
proxy -p{system}
|
|
defaultresolve
|
|
proxy -p{default}
|
|
flush
|
|
auth iponly
|
|
allow *
|
|
http echo * /echo**
|
|
httpsrv -i127.0.0.1 -p{srv}
|
|
""", ports=[fake, system, default, srv])
|
|
t.eq(200, t.http(f"http://localhost:{srv}/echo", proxy=f"127.0.0.1:{default}").status,
|
|
"defaultresolve: a name of the hosts file resolves")
|
|
t.eq(200, t.http(f"http://only3proxy.test:{srv}/echo", proxy=f"127.0.0.1:{default}").status,
|
|
"and an nsrecord name")
|
|
t.eq(200, t.http(f"http://localhost:{srv}/echo", proxy=f"127.0.0.1:{system}").status,
|
|
"sysresolve: names resolve through the system routines")
|
|
t.ne(200, t.http(f"http://only3proxy.test:{srv}/echo", proxy=f"127.0.0.1:{system}").status,
|
|
"which know no nsrecord name")
|
|
t.ne(200, t.http(f"http://localhost:{srv}/echo", proxy=f"127.0.0.1:{fake}").status,
|
|
"fakeresolve: every name is 127.0.0.2, in a service before the others")
|