mirror of
https://github.com/3proxy/3proxy.git
synced 2026-11-05 01:15:48 +08:00
Some checks failed
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Has been cancelled
3proxy --help (and the usage message of a bad invocation) now lists what the build was made with: TLS and its backend, RADIUS, PCRE, IPv6, UNIX sockets, the built-in HTTP server, transparency, ODBC and the optional proxy services. The test runner reads the list before the first case and the cases state the features they need with t.skip_unless(), so a build without a feature skips its cases instead of failing them; a binary too old to report anything skips the cases with needs and runs the rest.
99 lines
3.4 KiB
Python
99 lines
3.4 KiB
Python
"""The SOCKS proxy, reaching the built-in server."""
|
|
|
|
|
|
def run(t):
|
|
if not t.skip_unless("httpsrv"):
|
|
return
|
|
srv = t.free_port()
|
|
sks = t.free_port()
|
|
sauth = t.free_port()
|
|
sdeny = t.free_port()
|
|
sallow = t.free_port()
|
|
|
|
t.start("socks", f"""
|
|
log
|
|
auth iponly
|
|
allow *
|
|
http echo * /echo**
|
|
http data * /data
|
|
httpsrv -p{srv}
|
|
|
|
flush
|
|
auth iponly
|
|
allow *
|
|
socks -p{sks}
|
|
|
|
flush
|
|
auth strong
|
|
users alice:CL:secret
|
|
allow alice
|
|
socks -p{sauth}
|
|
|
|
flush
|
|
auth iponly
|
|
deny * * *.example.com
|
|
allow *
|
|
socks -p{sdeny}
|
|
|
|
flush
|
|
auth iponly
|
|
allow * * *.example.com
|
|
socks -p{sallow}
|
|
""", ports=[srv, sks, sauth, sdeny, sallow])
|
|
|
|
origin = f"http://127.0.0.1:{srv}"
|
|
plain = f"127.0.0.1:{sks}"
|
|
guarded = f"127.0.0.1:{sauth}"
|
|
|
|
# --- SOCKS5 ---------------------------------------------------------
|
|
r = t.socks_http(plain, origin + "/echo")
|
|
t.eq(200, r.status, "a SOCKS5 connection")
|
|
t.contains(r, "path=/echo", "the origin sees the request made over SOCKS5")
|
|
t.eq(10000, t.socks_http(plain, origin + "/data?size=10000").length,
|
|
"a body survives SOCKS5")
|
|
|
|
# resolution delegated to the proxy
|
|
t.eq(200, t.socks_http(plain, f"http://localhost:{srv}/echo",
|
|
remote_dns=True).status,
|
|
"SOCKS5 resolves the hostname itself")
|
|
|
|
# --- SOCKS4 -----------------------------------------------------------
|
|
t.eq(200, t.socks_http(plain, origin + "/echo", socks4=True).status,
|
|
"a SOCKS4 connection")
|
|
|
|
# --- the UDP association, and what goes through it ---------------------
|
|
# Binding the association is one thing; carrying a datagram is what it
|
|
# is for.
|
|
echo = t.udp_echo()
|
|
reply, bound = t.socks_udp(plain, "127.0.0.1", echo, b"ping")
|
|
t.eq(b"echo:ping", reply, "a datagram is relayed and answered")
|
|
t.ne(None, bound, "the association reports the port to send to")
|
|
|
|
reply, _ = t.socks_udp(plain, "127.0.0.1", echo, b"x" * 2000)
|
|
t.eq(b"echo:" + b"x" * 2000, reply, "a larger datagram survives the relay")
|
|
|
|
# each association gets its own socket
|
|
_, first = t.socks_udp(plain, "127.0.0.1", echo, b"one")
|
|
_, second = t.socks_udp(plain, "127.0.0.1", echo, b"two")
|
|
t.ne(first, second, "a second association binds its own port")
|
|
|
|
# A datagram names its destination by address. A rule listing host names
|
|
# only has to judge it by that address as text, the way CONNECT is judged,
|
|
# rather than match whatever the address is.
|
|
reply, _ = t.socks_udp(f"127.0.0.1:{sdeny}", "127.0.0.1", echo, b"ip")
|
|
t.eq(b"echo:ip", reply,
|
|
"a deny by host name leaves datagrams to an address alone")
|
|
reply, _ = t.socks_udp(f"127.0.0.1:{sallow}", "127.0.0.1", echo, b"ip")
|
|
t.eq(None, reply,
|
|
"an allow by host name does not let datagrams to an address through")
|
|
|
|
# --- authentication ----------------------------------------------------
|
|
t.eq(200, t.socks_http(guarded, origin + "/echo",
|
|
auth=("alice", "secret")).status,
|
|
"valid SOCKS5 credentials pass")
|
|
t.ne(None, t.socks_connect(guarded, "127.0.0.1", srv,
|
|
auth=("alice", "wrong")),
|
|
"wrong SOCKS5 credentials are refused")
|
|
t.ne(None, t.socks_connect(guarded, "127.0.0.1", srv),
|
|
"SOCKS5 without credentials is refused")
|