mirror of
https://github.com/3proxy/3proxy.git
synced 2026-09-29 16:55:51 +08:00
Compare commits
8 Commits
16ac797008
...
ca4667c035
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca4667c035 | ||
|
|
41a08c11be | ||
|
|
6c4663a045 | ||
|
|
83139bc2e8 | ||
|
|
2dc4a422c5 | ||
|
|
d0ec7687db | ||
|
|
b8e5853b6b | ||
|
|
ad6e151b7c |
2
.github/workflows/c-cpp-Linux.yml
vendored
2
.github/workflows/c-cpp-Linux.yml
vendored
@ -27,7 +27,7 @@ jobs:
|
|||||||
if: ${{ startsWith(matrix.target, 'ubuntu') }}
|
if: ${{ startsWith(matrix.target, 'ubuntu') }}
|
||||||
run: sudo apt-get update && sudo apt-get install -y libssl-dev libpam-dev libpcre2-dev
|
run: sudo apt-get update && sudo apt-get install -y libssl-dev libpam-dev libpcre2-dev
|
||||||
- name: make
|
- name: make
|
||||||
run: make -f Makefile.Linux
|
run: make -f Makefile.Linux MAILPROXY=true FTP=true
|
||||||
- name: regression tests
|
- name: regression tests
|
||||||
run: python3 tests/run.py
|
run: python3 tests/run.py
|
||||||
- name: mkdir
|
- name: mkdir
|
||||||
|
|||||||
85
.github/workflows/release-tarball.yml
vendored
Normal file
85
.github/workflows/release-tarball.yml
vendored
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
name: Release source tarball
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tarball:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
id-token: write
|
||||||
|
attestations: write
|
||||||
|
name: "source tarball"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
|
- name: env
|
||||||
|
run: |
|
||||||
|
if [ -f RELEASE ]; then
|
||||||
|
RELEASE=$(tr -d ' \t\r\n' < RELEASE)
|
||||||
|
else
|
||||||
|
RELEASE=$(tr -d ' \t\r\n' < DEVEL)
|
||||||
|
fi
|
||||||
|
echo "RELEASE=$RELEASE" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Create tarball
|
||||||
|
run: |
|
||||||
|
# git archive is reproducible from the tag: anyone can regenerate the
|
||||||
|
# tarball and compare it against the published checksum.
|
||||||
|
git archive --format=tar.gz -9 \
|
||||||
|
--prefix="3proxy-${{ env.RELEASE }}/" \
|
||||||
|
-o "3proxy-${{ env.RELEASE }}.tar.gz" HEAD
|
||||||
|
tar tzf "3proxy-${{ env.RELEASE }}.tar.gz" >/dev/null
|
||||||
|
ls -l *.tar.gz
|
||||||
|
|
||||||
|
- name: Get artifact
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: "3proxy-${{ env.RELEASE }}-src"
|
||||||
|
path: "*.tar.gz"
|
||||||
|
|
||||||
|
- name: Import signing key
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
env:
|
||||||
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
|
run: |
|
||||||
|
if [ -z "$GPG_PRIVATE_KEY" ]; then echo "GPG_PRIVATE_KEY is not set"; exit 1; fi
|
||||||
|
mkdir -p ~/.gnupg && chmod 700 ~/.gnupg
|
||||||
|
printf 'allow-loopback-pinentry\n' > ~/.gnupg/gpg-agent.conf
|
||||||
|
gpgconf --kill gpg-agent || true
|
||||||
|
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
|
||||||
|
KEYID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/{print $5; exit}')
|
||||||
|
echo "GPG_KEYID=$KEYID" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Checksums and detached signatures
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
env:
|
||||||
|
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||||
|
run: |
|
||||||
|
sha256sum *.tar.gz > SHA256SUMS-src
|
||||||
|
for f in *.tar.gz SHA256SUMS-src; do
|
||||||
|
gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \
|
||||||
|
-u "$GPG_KEYID" --armor --detach-sign "$f"
|
||||||
|
done
|
||||||
|
sha256sum -c SHA256SUMS-src
|
||||||
|
gpg --verify SHA256SUMS-src.asc SHA256SUMS-src
|
||||||
|
|
||||||
|
- name: Attest build provenance
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
uses: actions/attest-build-provenance@v4
|
||||||
|
with:
|
||||||
|
subject-path: |
|
||||||
|
*.tar.gz
|
||||||
|
|
||||||
|
- name: Upload to release
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
TAG: ${{ github.event.release.tag_name }}
|
||||||
|
run: gh release upload "$TAG" *.tar.gz *.tar.gz.asc SHA256SUMS-src SHA256SUMS-src.asc
|
||||||
@ -70,6 +70,8 @@ option(3PROXY_USE_NETFILTER "Enable Linux netfilter support (Linux only)" ON)
|
|||||||
option(3PROXY_USE_TRANSPARENT "Build transparent proxying support (Linux and BSD only)" ON)
|
option(3PROXY_USE_TRANSPARENT "Build transparent proxying support (Linux and BSD only)" ON)
|
||||||
option(3PROXY_USE_UNIX_SOCKETS "Enable Unix domain socket support (Unix only)" ON)
|
option(3PROXY_USE_UNIX_SOCKETS "Enable Unix domain socket support (Unix only)" ON)
|
||||||
option(3PROXY_USE_HTTPSRV "Build the HTTP server and the admin interface on top of it" ON)
|
option(3PROXY_USE_HTTPSRV "Build the HTTP server and the admin interface on top of it" ON)
|
||||||
|
option(3PROXY_USE_MAILPROXY "Build the pop3p, imapp and smtpp proxies" OFF)
|
||||||
|
option(3PROXY_USE_FTP "Build FTP support: the ftppr service and ftp:// in the HTTP proxy" OFF)
|
||||||
|
|
||||||
if(NOT WIN32 AND NOT APPLE)
|
if(NOT WIN32 AND NOT APPLE)
|
||||||
option(3PROXY_STATIC_LINK "Statically link libraries using -Wl,-Bstatic (Linux/Unix only)" OFF)
|
option(3PROXY_STATIC_LINK "Statically link libraries using -Wl,-Bstatic (Linux/Unix only)" OFF)
|
||||||
@ -83,10 +85,13 @@ set(3PROXY_BINARY_PREFIX "3proxy_" CACHE STRING "Prefix for standalone module an
|
|||||||
option(3PROXY_BUILD_NONE "Do not build standalone binaries" OFF)
|
option(3PROXY_BUILD_NONE "Do not build standalone binaries" OFF)
|
||||||
option(3PROXY_BUILD_PROXY "Build standalone proxy binary" ON)
|
option(3PROXY_BUILD_PROXY "Build standalone proxy binary" ON)
|
||||||
option(3PROXY_BUILD_SOCKS "Build standalone socks binary" ON)
|
option(3PROXY_BUILD_SOCKS "Build standalone socks binary" ON)
|
||||||
option(3PROXY_BUILD_POP3P "Build standalone pop3p binary" ON)
|
# The mail proxies and FTP are asked for rather than assumed: without them
|
||||||
option(3PROXY_BUILD_IMAPP "Build standalone imapp binary" ON)
|
# pop3p, imapp and smtpp are the STARTTLS proxy under those names, and ftp
|
||||||
option(3PROXY_BUILD_SMTPP "Build standalone smtpp binary" ON)
|
# is not spoken at all. A standalone binary needs the support it is made of.
|
||||||
option(3PROXY_BUILD_FTPPR "Build standalone ftppr binary" ON)
|
option(3PROXY_BUILD_POP3P "Build standalone pop3p binary" OFF)
|
||||||
|
option(3PROXY_BUILD_IMAPP "Build standalone imapp binary" OFF)
|
||||||
|
option(3PROXY_BUILD_SMTPP "Build standalone smtpp binary" OFF)
|
||||||
|
option(3PROXY_BUILD_FTPPR "Build standalone ftppr binary" OFF)
|
||||||
option(3PROXY_BUILD_TCPPM "Build standalone tcppm binary" ON)
|
option(3PROXY_BUILD_TCPPM "Build standalone tcppm binary" ON)
|
||||||
option(3PROXY_BUILD_UDPPM "Build standalone udppm binary" ON)
|
option(3PROXY_BUILD_UDPPM "Build standalone udppm binary" ON)
|
||||||
option(3PROXY_BUILD_TLSPR "Build standalone tlspr binary" ON)
|
option(3PROXY_BUILD_TLSPR "Build standalone tlspr binary" ON)
|
||||||
@ -250,6 +255,14 @@ else()
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(3PROXY_USE_MAILPROXY)
|
||||||
|
add_compile_definitions(WITH_POP3P WITH_IMAPP WITH_SMTPP)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(3PROXY_USE_FTP)
|
||||||
|
add_compile_definitions(WITH_FTP)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(3PROXY_USE_HTTPSRV)
|
if(3PROXY_USE_HTTPSRV)
|
||||||
add_compile_definitions(WITH_HTTPSRV)
|
add_compile_definitions(WITH_HTTPSRV)
|
||||||
endif()
|
endif()
|
||||||
@ -684,6 +697,15 @@ foreach(PROXY_NAME proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr)
|
|||||||
continue()
|
continue()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# A binary of nothing: without the support built, these files hold the
|
||||||
|
# stand-in the main binary uses and no service of their own.
|
||||||
|
if(NOT 3PROXY_USE_MAILPROXY AND PROXY_NAME MATCHES "^(pop3p|imapp|smtpp)$")
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
if(NOT 3PROXY_USE_FTP AND PROXY_NAME STREQUAL "ftppr")
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
|
||||||
if(PROXY_NAME STREQUAL "ftppr" OR PROXY_NAME STREQUAL "proxy")
|
if(PROXY_NAME STREQUAL "ftppr" OR PROXY_NAME STREQUAL "proxy")
|
||||||
# ftppr and proxy use ftp_obj
|
# ftppr and proxy use ftp_obj
|
||||||
add_executable(${PROXY_NAME}
|
add_executable(${PROXY_NAME}
|
||||||
|
|||||||
@ -24,6 +24,16 @@ LDFLAGS += $(EXTRA_LDFLAGS)
|
|||||||
# -lpthreads may be reuiured on some platforms instead of -pthreads
|
# -lpthreads may be reuiured on some platforms instead of -pthreads
|
||||||
# -ldl or -lld may be required for some platforms
|
# -ldl or -lld may be required for some platforms
|
||||||
DCFLAGS ?= -fPIC
|
DCFLAGS ?= -fPIC
|
||||||
|
MAILPROXY ?= false
|
||||||
|
ifeq ($(MAILPROXY),true)
|
||||||
|
CFLAGS += -DWITH_POP3P -DWITH_IMAPP -DWITH_SMTPP
|
||||||
|
MAIL_EXES = $(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS)
|
||||||
|
endif
|
||||||
|
FTP ?= false
|
||||||
|
ifeq ($(FTP),true)
|
||||||
|
CFLAGS += -DWITH_FTP
|
||||||
|
FTP_EXES = $(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS)
|
||||||
|
endif
|
||||||
HTTPSRV ?= true
|
HTTPSRV ?= true
|
||||||
ifeq ($(HTTPSRV),true)
|
ifeq ($(HTTPSRV),true)
|
||||||
CFLAGS += -DWITH_HTTPSRV
|
CFLAGS += -DWITH_HTTPSRV
|
||||||
|
|||||||
@ -27,6 +27,16 @@ CFLAGS += $(EXTRA_CFLAGS)
|
|||||||
LDFLAGS += $(EXTRA_LDFLAGS)
|
LDFLAGS += $(EXTRA_LDFLAGS)
|
||||||
# The HTTP server serves the endpoints declared by http lines. The admin
|
# The HTTP server serves the endpoints declared by http lines. The admin
|
||||||
# interface is built on top of it, so turning it off removes both.
|
# interface is built on top of it, so turning it off removes both.
|
||||||
|
MAILPROXY ?= false
|
||||||
|
ifeq ($(MAILPROXY),true)
|
||||||
|
CFLAGS += -DWITH_POP3P -DWITH_IMAPP -DWITH_SMTPP
|
||||||
|
MAIL_EXES = $(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS)
|
||||||
|
endif
|
||||||
|
FTP ?= false
|
||||||
|
ifeq ($(FTP),true)
|
||||||
|
CFLAGS += -DWITH_FTP
|
||||||
|
FTP_EXES = $(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS)
|
||||||
|
endif
|
||||||
HTTPSRV ?= true
|
HTTPSRV ?= true
|
||||||
ifeq ($(HTTPSRV),true)
|
ifeq ($(HTTPSRV),true)
|
||||||
CFLAGS += -DWITH_HTTPSRV
|
CFLAGS += -DWITH_HTTPSRV
|
||||||
|
|||||||
@ -14,6 +14,16 @@ COUT = -o ./
|
|||||||
LN = $(CC)
|
LN = $(CC)
|
||||||
LDFLAGS = -xO3
|
LDFLAGS = -xO3
|
||||||
DCFLAGS = -fPIC
|
DCFLAGS = -fPIC
|
||||||
|
MAILPROXY ?= false
|
||||||
|
ifeq ($(MAILPROXY),true)
|
||||||
|
CFLAGS += -DWITH_POP3P -DWITH_IMAPP -DWITH_SMTPP
|
||||||
|
MAIL_EXES = $(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS)
|
||||||
|
endif
|
||||||
|
FTP ?= false
|
||||||
|
ifeq ($(FTP),true)
|
||||||
|
CFLAGS += -DWITH_FTP
|
||||||
|
FTP_EXES = $(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS)
|
||||||
|
endif
|
||||||
HTTPSRV ?= true
|
HTTPSRV ?= true
|
||||||
ifeq ($(HTTPSRV),true)
|
ifeq ($(HTTPSRV),true)
|
||||||
CFLAGS += -DWITH_HTTPSRV
|
CFLAGS += -DWITH_HTTPSRV
|
||||||
|
|||||||
@ -26,6 +26,16 @@ LDFLAGS += $(EXTRA_LDFLAGS)
|
|||||||
# -lpthreads may be reuqired on some platforms instead of -pthreads
|
# -lpthreads may be reuqired on some platforms instead of -pthreads
|
||||||
# -ldl or -lld may be required for some platforms
|
# -ldl or -lld may be required for some platforms
|
||||||
DCFLAGS ?= -fPIC
|
DCFLAGS ?= -fPIC
|
||||||
|
MAILPROXY ?= false
|
||||||
|
ifeq ($(MAILPROXY),true)
|
||||||
|
CFLAGS += -DWITH_POP3P -DWITH_IMAPP -DWITH_SMTPP
|
||||||
|
MAIL_EXES = $(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS)
|
||||||
|
endif
|
||||||
|
FTP ?= false
|
||||||
|
ifeq ($(FTP),true)
|
||||||
|
CFLAGS += -DWITH_FTP
|
||||||
|
FTP_EXES = $(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS)
|
||||||
|
endif
|
||||||
HTTPSRV ?= true
|
HTTPSRV ?= true
|
||||||
ifeq ($(HTTPSRV),true)
|
ifeq ($(HTTPSRV),true)
|
||||||
CFLAGS += -DWITH_HTTPSRV
|
CFLAGS += -DWITH_HTTPSRV
|
||||||
|
|||||||
10
Makefile.win
10
Makefile.win
@ -23,6 +23,16 @@ LDFLAGS += -fno-strict-aliasing -mthreads
|
|||||||
# makefile, including the += above and the STATIC/LIBSTATIC handling below.
|
# makefile, including the += above and the STATIC/LIBSTATIC handling below.
|
||||||
CFLAGS += $(EXTRA_CFLAGS)
|
CFLAGS += $(EXTRA_CFLAGS)
|
||||||
LDFLAGS += $(EXTRA_LDFLAGS)
|
LDFLAGS += $(EXTRA_LDFLAGS)
|
||||||
|
MAILPROXY ?= false
|
||||||
|
ifeq ($(MAILPROXY),true)
|
||||||
|
CFLAGS += -DWITH_POP3P -DWITH_IMAPP -DWITH_SMTPP
|
||||||
|
MAIL_EXES = $(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS)
|
||||||
|
endif
|
||||||
|
FTP ?= false
|
||||||
|
ifeq ($(FTP),true)
|
||||||
|
CFLAGS += -DWITH_FTP
|
||||||
|
FTP_EXES = $(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS)
|
||||||
|
endif
|
||||||
HTTPSRV ?= true
|
HTTPSRV ?= true
|
||||||
ifeq ($(HTTPSRV),true)
|
ifeq ($(HTTPSRV),true)
|
||||||
CFLAGS += -DWITH_HTTPSRV
|
CFLAGS += -DWITH_HTTPSRV
|
||||||
|
|||||||
18
SECURITY.md
18
SECURITY.md
@ -34,8 +34,8 @@ For High/Critical patched version is released within 2 weeks
|
|||||||
|
|
||||||
## Verifying downloads
|
## Verifying downloads
|
||||||
|
|
||||||
Release binaries are published with SHA256 checksums, an OpenPGP signature and
|
Release binaries and the source tarball are published with SHA256 checksums, an
|
||||||
a GitHub build provenance attestation.
|
OpenPGP signature and a GitHub build provenance attestation.
|
||||||
|
|
||||||
The release signing key is `3proxy-release-key.asc` in the root of this
|
The release signing key is `3proxy-release-key.asc` in the root of this
|
||||||
repository, an RSA-4096 key:
|
repository, an RSA-4096 key:
|
||||||
@ -59,6 +59,18 @@ gpg --verify SHA256SUMS-x86_64.asc SHA256SUMS-x86_64
|
|||||||
sha256sum -c SHA256SUMS-x86_64
|
sha256sum -c SHA256SUMS-x86_64
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The source tarball published with each release is signed as well:
|
||||||
|
|
||||||
|
```
|
||||||
|
gpg --verify SHA256SUMS-src.asc SHA256SUMS-src
|
||||||
|
sha256sum -c SHA256SUMS-src
|
||||||
|
gpg --verify 3proxy-0.9.9.tar.gz.asc 3proxy-0.9.9.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
Prefer it over the `Source code (tar.gz)` link GitHub generates automatically:
|
||||||
|
only the published tarball is signed. It is produced with `git archive` from
|
||||||
|
the release tag, so it can be regenerated and compared byte for byte.
|
||||||
|
|
||||||
RPM packages are signed, the signature is checked by rpm itself:
|
RPM packages are signed, the signature is checked by rpm itself:
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -79,5 +91,3 @@ verified with the GitHub CLI:
|
|||||||
gh attestation verify 3proxy-0.9.9.x86_64.rpm --owner 3proxy
|
gh attestation verify 3proxy-0.9.9.x86_64.rpm --owner 3proxy
|
||||||
gh attestation verify oci://docker.io/3proxy/3proxy:latest --owner 3proxy
|
gh attestation verify oci://docker.io/3proxy/3proxy:latest --owner 3proxy
|
||||||
```
|
```
|
||||||
|
|
||||||
Windows binaries are Authenticode signed in addition to the above.
|
|
||||||
|
|||||||
@ -1942,10 +1942,12 @@ allowed traffic in megabytes (MB). nocountin allows you to set exclusions.
|
|||||||
For name resolution and caching, use the commands nserver, nscache / nscache6, and nsrecord.
|
For name resolution and caching, use the commands nserver, nscache / nscache6, and nsrecord.
|
||||||
<pre>
|
<pre>
|
||||||
nserver 192.168.1.2
|
nserver 192.168.1.2
|
||||||
nserver 192.168.1.3:5353/tcp</pre>
|
nserver 192.168.1.3:5353/tcp
|
||||||
|
nserver [2001:4860:4860::8844]</pre>
|
||||||
sets DNS resolvers. 192.168.1.3 will be used via TCP/5353 (instead of default UDP/53)
|
sets DNS resolvers. 192.168.1.3 will be used via TCP/5353 (instead of default UDP/53)
|
||||||
only if 192.168.1.2 fails. Up to 5 nservers may be specified.
|
only if 192.168.1.2 fails. Up to 5 nservers may be specified.
|
||||||
If no nserver is configured, default system name resolution functions are used.
|
If no nserver is configured, default system name resolution functions are used.
|
||||||
|
An IPv6 address has to be written in square brackets.
|
||||||
<pre>
|
<pre>
|
||||||
nscache 65535
|
nscache 65535
|
||||||
nscache6 65535</pre>
|
nscache6 65535</pre>
|
||||||
|
|||||||
@ -1993,11 +1993,13 @@ socks -p1080
|
|||||||
nscache и nsrecord.
|
nscache и nsrecord.
|
||||||
<pre>
|
<pre>
|
||||||
nserver 192.168.1.2
|
nserver 192.168.1.2
|
||||||
nserver 192.168.1.3:5353/tcp</pre>
|
nserver 192.168.1.3:5353/tcp
|
||||||
|
nserver [2001:4860:4860::8844]</pre>
|
||||||
указывает 3proxy какие машины следует использвоать в качестве серверов
|
указывает 3proxy какие машины следует использвоать в качестве серверов
|
||||||
DNS. Сервер 192.168.1.3 будет использоваться по порту TCP/5353 (вместо дефолтного UDP/53) только при недостижимости
|
DNS. Сервер 192.168.1.3 будет использоваться по порту TCP/5353 (вместо дефолтного UDP/53) только при недостижимости
|
||||||
192.168.1.2. Можно указать до 5 серверов. Если nserver не указан, будут
|
192.168.1.2. Можно указать до 5 серверов. Если nserver не указан, будут
|
||||||
использованы системные функции разрешения имен.
|
использованы системные функции разрешения имен.
|
||||||
|
Адрес IPv6 необходимо записывать в квадратных скобках.
|
||||||
<pre>
|
<pre>
|
||||||
nscache 65535
|
nscache 65535
|
||||||
nscache6 65535</pre>
|
nscache6 65535</pre>
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
<a href="#PCRE FILTERING">PCRE FILTERING</a><br>
|
<a href="#PCRE FILTERING">PCRE FILTERING</a><br>
|
||||||
<a href="#PCRE Commands">PCRE Commands</a><br>
|
<a href="#PCRE Commands">PCRE Commands</a><br>
|
||||||
<a href="#PCRE Parameters">PCRE Parameters</a><br>
|
<a href="#PCRE Parameters">PCRE Parameters</a><br>
|
||||||
|
<a href="#OPTIONAL SERVICES">OPTIONAL SERVICES</a><br>
|
||||||
<a href="#BUILT IN HTTP SERVER">BUILT IN HTTP SERVER</a><br>
|
<a href="#BUILT IN HTTP SERVER">BUILT IN HTTP SERVER</a><br>
|
||||||
<a href="#Operations">Operations</a><br>
|
<a href="#Operations">Operations</a><br>
|
||||||
<a href="#What a rule adds to the answer">What a rule adds to the answer</a><br>
|
<a href="#What a rule adds to the answer">What a rule adds to the answer</a><br>
|
||||||
@ -114,10 +115,17 @@ handshake), may be used to redirect any TLS-based traffic
|
|||||||
<b><br>
|
<b><br>
|
||||||
auto</b> Proxy with protocol autoselection between proxy /
|
auto</b> Proxy with protocol autoselection between proxy /
|
||||||
socks / tlspr <b><br>
|
socks / tlspr <b><br>
|
||||||
pop3p</b> POP3 proxy (default port 110) <b><br>
|
pop3p</b> POP3 proxy (default port 110), in a build which
|
||||||
imapp</b> IMAPv4 proxy (default port 143) <b><br>
|
has one: otherwise the service is <b>tlspr</b> speaking POP3
|
||||||
smtpp</b> SMTP proxy (default port 25) <b><br>
|
to negotiate STARTTLS, under this name. <b><br>
|
||||||
ftppr</b> FTP proxy (default port 21) <b><br>
|
imapp</b> IMAPv4 proxy (default port 143), or <b>tlspr</b>
|
||||||
|
speaking IMAP, as above. <b><br>
|
||||||
|
smtpp</b> SMTP proxy (default port 25), or <b>tlspr</b>
|
||||||
|
speaking SMTP, as above. <b><br>
|
||||||
|
ftppr</b> FTP proxy (default port 21), in a build with FTP
|
||||||
|
support. Without it the service is known but answers
|
||||||
|
nothing, and <b>ftp://</b> is not a URL the HTTP proxy
|
||||||
|
fetches. <b><br>
|
||||||
admin</b> Web interface (default port 80) <b><br>
|
admin</b> Web interface (default port 80) <b><br>
|
||||||
dnspr</b> caching DNS proxy (default port 53) <b><br>
|
dnspr</b> caching DNS proxy (default port 53) <b><br>
|
||||||
tcppm</b> TCP portmapper. Destination address (DSTADDR) can
|
tcppm</b> TCP portmapper. Destination address (DSTADDR) can
|
||||||
@ -492,7 +500,11 @@ experimental.</p>
|
|||||||
Nameserver to use for name resolutions. If none specified
|
Nameserver to use for name resolutions. If none specified
|
||||||
system routines for name resolution is used. Optional port
|
system routines for name resolution is used. Optional port
|
||||||
number may be specified. If optional /tcp is added to IP
|
number may be specified. If optional /tcp is added to IP
|
||||||
address, name resolution is performed over TCP.</p>
|
address, name resolution is performed over TCP. An IPv6
|
||||||
|
address has to be enclosed in square brackets: <b><br>
|
||||||
|
nserver 1.1.1.1 <br>
|
||||||
|
nserver [2001:4860:4860::8844] <br>
|
||||||
|
nserver [2001:4860:4860::8844]:5353/tcp</b></p>
|
||||||
|
|
||||||
|
|
||||||
<p style="margin-left:9%; margin-top: 1em"><b>authnserver</b>
|
<p style="margin-left:9%; margin-top: 1em"><b>authnserver</b>
|
||||||
@ -824,15 +836,40 @@ grouped. Proxy inside the group is selected randomly. If few
|
|||||||
groups are specified one proxy is randomly picked from each
|
groups are specified one proxy is randomly picked from each
|
||||||
group and chain of proxies is created (that is second proxy
|
group and chain of proxies is created (that is second proxy
|
||||||
connected through first one and so on). Weight is used to
|
connected through first one and so on). Weight is used to
|
||||||
group proxies. Weight is a number between 1 and 1000.
|
group proxies. A weight is a share of the whole, written
|
||||||
|
either as a fraction of one, anything beginning with 0 or
|
||||||
|
with a point, or the old way, in thousandths: <b><br>
|
||||||
|
.5</b> and <b>0.5</b> and <b>500</b> are all a half <b><br>
|
||||||
|
.333</b> and <b>333</b> are both 333 thousandths <b><br>
|
||||||
|
1000</b> and <b>1.0</b> and <b>100%</b> are all the whole
|
||||||
|
share <b><br>
|
||||||
|
50.5%</b> and <b>.505</b> and <b>505</b> are all the same
|
||||||
|
share <b><br>
|
||||||
|
0</b> is a fallback, described below <br>
|
||||||
|
A fraction takes up to nine digits after the point,
|
||||||
|
<b>.333333333</b> being the finest share there is, and the
|
||||||
|
old notation may now carry further digits after a point of
|
||||||
|
its own, so <b>123.456</b> means the same as <b>.123456</b>.
|
||||||
|
Weights are scanned as integers, nothing is read as a
|
||||||
|
floating point number. <b>1.0</b>, with as many zeroes after
|
||||||
|
the point as you care to write, is the one weight read as it
|
||||||
|
looks rather than in thousandths, so that the whole share
|
||||||
|
can be written as a fraction too: a bare <b>1</b> is still a
|
||||||
|
thousandth of it, and <b>1.5</b> still one and a half of
|
||||||
|
them. A weight ending in <b>%</b> is a percentage, and takes
|
||||||
|
up to seven digits after the point. <br>
|
||||||
Weights are summed and proxies are grouped together until
|
Weights are summed and proxies are grouped together until
|
||||||
the weight of the group is 1000. That is: <br>
|
the weight of the group is the whole share. A group which
|
||||||
|
falls short of it by no more than a thousandth, which three
|
||||||
|
weights of <b>333</b> do, is taken for a whole one rather
|
||||||
|
than for a group with a remainder, so a share which cannot
|
||||||
|
be divided evenly needs no adjusting by hand. That is: <br>
|
||||||
allow * <br>
|
allow * <br>
|
||||||
parent 500 socks5 192.168.10.1 1080 <br>
|
parent 500 socks5 192.168.10.1 1080 <br>
|
||||||
parent 500 connect 192.168.10.1 3128 <br>
|
parent 500 connect 192.168.10.1 3128 <br>
|
||||||
makes 3proxy to randomly choose between 2 proxies for all
|
makes 3proxy to randomly choose between 2 proxies for all
|
||||||
outgoing connections. These 2 proxies form 1 group
|
outgoing connections. These 2 proxies form 1 group (their
|
||||||
(summarized weight is 1000). <br>
|
weights are the whole share between them). <br>
|
||||||
allow * * * 80 <br>
|
allow * * * 80 <br>
|
||||||
parent 1000 socks5 192.168.10.1 1080 <br>
|
parent 1000 socks5 192.168.10.1 1080 <br>
|
||||||
parent 1000 connect 192.168.20.1 3128 <br>
|
parent 1000 connect 192.168.20.1 3128 <br>
|
||||||
@ -972,13 +1009,36 @@ Changes the external address for a given connection to
|
|||||||
1.2.3.4 (equivalent to <b>-e1.2.3.4</b>) <br>
|
1.2.3.4 (equivalent to <b>-e1.2.3.4</b>) <br>
|
||||||
Optional username and password are used to authenticate on
|
Optional username and password are used to authenticate on
|
||||||
parent proxy. Username of ´*´ means username
|
parent proxy. Username of ´*´ means username
|
||||||
must be supplied by user.</p>
|
must be supplied by user. <br>
|
||||||
|
A parent which fails is taken out of the choice for the rest
|
||||||
|
of that connection, so the next attempt, see
|
||||||
|
<b>parentretries</b>, goes to another member of the group
|
||||||
|
instead of the same parent again. Its share is spread over
|
||||||
|
the parents of the group which are left, in proportion to
|
||||||
|
their weights. <br>
|
||||||
|
Weight 0 marks a fallback parent. Such a parent takes no
|
||||||
|
share of the random choice, and none of the share left over
|
||||||
|
by a parent which failed, and is only used once every
|
||||||
|
weighted parent of its group has failed, which is how a
|
||||||
|
parent used only when another one is down is configured:
|
||||||
|
<br>
|
||||||
|
allow * <br>
|
||||||
|
parent 1000 socks5 192.168.10.1 1080 <br>
|
||||||
|
parent 0 socks5 192.168.20.1 1080 <br>
|
||||||
|
Several fallbacks are tried in the order they are written.
|
||||||
|
Reaching a fallback costs an attempt, so
|
||||||
|
<b>parentretries</b> has to be at least as large as the
|
||||||
|
number of parents to try. <br>
|
||||||
|
When every parent of a group has failed the request fails as
|
||||||
|
well, rather than being sent without a parent.</p>
|
||||||
|
|
||||||
|
|
||||||
<p style="margin-left:9%; margin-top: 1em"><b>parentretries</b>
|
<p style="margin-left:9%; margin-top: 1em"><b>parentretries</b>
|
||||||
<i><number></i> <br>
|
<i><number></i> <br>
|
||||||
Number of retries to connect to parent proxy. Default is
|
Number of attempts to reach a parent proxy. Default is 2.
|
||||||
1.</p>
|
Each attempt picks a parent again, leaving out the ones
|
||||||
|
which already failed, so this is also the number of
|
||||||
|
different parents a request may be tried through.</p>
|
||||||
|
|
||||||
<p style="margin-left:9%; margin-top: 1em"><b>nolog</b>
|
<p style="margin-left:9%; margin-top: 1em"><b>nolog</b>
|
||||||
<i><n></i> <br>
|
<i><n></i> <br>
|
||||||
@ -1516,6 +1576,29 @@ the connection data. Warning: Regular expressions
|
|||||||
don’t require authentication and cannot replace
|
don’t require authentication and cannot replace
|
||||||
authentication and/or allow/deny ACLs.</p>
|
authentication and/or allow/deny ACLs.</p>
|
||||||
|
|
||||||
|
<h2>OPTIONAL SERVICES
|
||||||
|
<a name="OPTIONAL SERVICES"></a>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
|
||||||
|
<p style="margin-left:9%; margin-top: 1em">The mail proxies
|
||||||
|
and FTP are built when they are asked for, and are not in a
|
||||||
|
default build. <b>MAILPROXY=true</b> builds <b>pop3p</b>,
|
||||||
|
<b>imapp</b> and <b>smtpp</b>, and <b>FTP=true</b> builds
|
||||||
|
<b>ftppr</b> and the <b>ftp://</b> scheme of the HTTP proxy;
|
||||||
|
with CMake the switches are <b>-D3PROXY_USE_MAILPROXY=ON</b>
|
||||||
|
and <b>-D3PROXY_USE_FTP=ON</b>. The standalone binaries of
|
||||||
|
those services are built with them and not without. <br>
|
||||||
|
A configuration naming a service which was not built is
|
||||||
|
still read. The three mail proxies become <b>tlspr</b>
|
||||||
|
negotiating STARTTLS in that protocol, which is what most of
|
||||||
|
their use amounts to now that the mail protocols are used
|
||||||
|
over TLS, and a <b>parent</b> chain naming <b>pop3</b>,
|
||||||
|
<b>imap</b> or <b>smtp</b> does the same. <b>ftppr</b> is
|
||||||
|
answered by nothing: a client reaching it is turned away and
|
||||||
|
the refusal logged, since there is no protocol to fall back
|
||||||
|
on.</p>
|
||||||
|
|
||||||
<h2>BUILT IN HTTP SERVER
|
<h2>BUILT IN HTTP SERVER
|
||||||
<a name="BUILT IN HTTP SERVER"></a>
|
<a name="BUILT IN HTTP SERVER"></a>
|
||||||
</h2>
|
</h2>
|
||||||
|
|||||||
@ -95,16 +95,19 @@ SNI proxy (destination address is taken from TLS handshake), may be used to redi
|
|||||||
Proxy with protocol autoselection between proxy / socks / tlspr
|
Proxy with protocol autoselection between proxy / socks / tlspr
|
||||||
.br
|
.br
|
||||||
.B pop3p
|
.B pop3p
|
||||||
POP3 proxy (default port 110)
|
POP3 proxy (default port 110), in a build which has one: otherwise the
|
||||||
|
service is \fBtlspr\fR speaking POP3 to negotiate STARTTLS, under this name.
|
||||||
.br
|
.br
|
||||||
.B imapp
|
.B imapp
|
||||||
IMAPv4 proxy (default port 143)
|
IMAPv4 proxy (default port 143), or \fBtlspr\fR speaking IMAP, as above.
|
||||||
.br
|
.br
|
||||||
.B smtpp
|
.B smtpp
|
||||||
SMTP proxy (default port 25)
|
SMTP proxy (default port 25), or \fBtlspr\fR speaking SMTP, as above.
|
||||||
.br
|
.br
|
||||||
.B ftppr
|
.B ftppr
|
||||||
FTP proxy (default port 21)
|
FTP proxy (default port 21), in a build with FTP support. Without it the
|
||||||
|
service is known but answers nothing, and \fBftp://\fR is not a URL the HTTP
|
||||||
|
proxy fetches.
|
||||||
.br
|
.br
|
||||||
.B admin
|
.B admin
|
||||||
Web interface (default port 80)
|
Web interface (default port 80)
|
||||||
@ -508,6 +511,13 @@ system routines for name resolution is
|
|||||||
used. Optional port number may be specified.
|
used. Optional port number may be specified.
|
||||||
If optional /tcp is added to IP address, name resolution is
|
If optional /tcp is added to IP address, name resolution is
|
||||||
performed over TCP.
|
performed over TCP.
|
||||||
|
An IPv6 address has to be enclosed in square brackets:
|
||||||
|
.br
|
||||||
|
\fBnserver 1.1.1.1\fR
|
||||||
|
.br
|
||||||
|
\fBnserver [2001:4860:4860::8844]\fR
|
||||||
|
.br
|
||||||
|
\fBnserver [2001:4860:4860::8844]:5353/tcp\fR
|
||||||
|
|
||||||
.br
|
.br
|
||||||
.BR authnserver
|
.BR authnserver
|
||||||
@ -860,9 +870,35 @@ build proxy chain. Proxies may be grouped. Proxy inside the
|
|||||||
group is selected randomly. If few groups are specified one proxy
|
group is selected randomly. If few groups are specified one proxy
|
||||||
is randomly picked from each group and chain of proxies is created
|
is randomly picked from each group and chain of proxies is created
|
||||||
(that is second proxy connected through first one and so on).
|
(that is second proxy connected through first one and so on).
|
||||||
Weight is used to group proxies. Weight is a number between 1 and 1000.
|
Weight is used to group proxies. A weight is a share of the whole, written
|
||||||
Weights are summed and proxies are grouped together until the weight of
|
either as a fraction of one, anything beginning with 0 or with a point, or the
|
||||||
the group is 1000. That is:
|
old way, in thousandths:
|
||||||
|
.br
|
||||||
|
\fB.5\fR and \fB0.5\fR and \fB500\fR are all a half
|
||||||
|
.br
|
||||||
|
\fB.333\fR and \fB333\fR are both 333 thousandths
|
||||||
|
.br
|
||||||
|
\fB1000\fR and \fB1.0\fR and \fB100%\fR are all the whole share
|
||||||
|
.br
|
||||||
|
\fB50.5%\fR and \fB.505\fR and \fB505\fR are all the same share
|
||||||
|
.br
|
||||||
|
\fB0\fR is a fallback, described below
|
||||||
|
.br
|
||||||
|
A fraction takes up to nine digits after the point, \fB.333333333\fR being
|
||||||
|
the finest share there is, and the old notation may now carry further digits
|
||||||
|
after a point of its own, so \fB123.456\fR means the same as \fB.123456\fR.
|
||||||
|
Weights are scanned as integers, nothing is read as a floating point number.
|
||||||
|
\fB1.0\fR, with as many zeroes after the point as you care to write, is the
|
||||||
|
one weight read as it looks rather than in thousandths, so that the whole
|
||||||
|
share can be written as a fraction too: a bare \fB1\fR is still a thousandth
|
||||||
|
of it, and \fB1.5\fR still one and a half of them. A weight ending in
|
||||||
|
\fB%\fR is a percentage, and takes up to seven digits after the point.
|
||||||
|
.br
|
||||||
|
Weights are summed and proxies are grouped together until the weight of
|
||||||
|
the group is the whole share. A group which falls short of it by no more than
|
||||||
|
a thousandth, which three weights of \fB333\fR do, is taken for a whole one
|
||||||
|
rather than for a group with a remainder, so a share which cannot be divided
|
||||||
|
evenly needs no adjusting by hand. That is:
|
||||||
.br
|
.br
|
||||||
allow *
|
allow *
|
||||||
.br
|
.br
|
||||||
@ -871,7 +907,8 @@ the group is 1000. That is:
|
|||||||
parent 500 connect 192.168.10.1 3128
|
parent 500 connect 192.168.10.1 3128
|
||||||
.br
|
.br
|
||||||
makes 3proxy to randomly choose between 2 proxies for all outgoing
|
makes 3proxy to randomly choose between 2 proxies for all outgoing
|
||||||
connections. These 2 proxies form 1 group (summarized weight is 1000).
|
connections. These 2 proxies form 1 group (their weights are the whole share
|
||||||
|
between them).
|
||||||
.br
|
.br
|
||||||
allow * * * 80
|
allow * * * 80
|
||||||
.br
|
.br
|
||||||
@ -1004,12 +1041,37 @@ local HTTP proxy parses requests and allows only GET and POST requests.
|
|||||||
.br
|
.br
|
||||||
Optional username and password are used to authenticate on parent
|
Optional username and password are used to authenticate on parent
|
||||||
proxy. Username of \'*\' means username must be supplied by user.
|
proxy. Username of \'*\' means username must be supplied by user.
|
||||||
|
.br
|
||||||
|
A parent which fails is taken out of the choice for the rest of that
|
||||||
|
connection, so the next attempt, see \fBparentretries\fR, goes to another
|
||||||
|
member of the group instead of the same parent again. Its share is spread over
|
||||||
|
the parents of the group which are left, in proportion to their weights.
|
||||||
|
.br
|
||||||
|
Weight 0 marks a fallback parent. Such a parent takes no share of the random
|
||||||
|
choice, and none of the share left over by a parent which failed, and is only
|
||||||
|
used once every weighted parent of its group has failed,
|
||||||
|
which is how a parent used only when another one is down is configured:
|
||||||
|
.br
|
||||||
|
allow *
|
||||||
|
.br
|
||||||
|
parent 1000 socks5 192.168.10.1 1080
|
||||||
|
.br
|
||||||
|
parent 0 socks5 192.168.20.1 1080
|
||||||
|
.br
|
||||||
|
Several fallbacks are tried in the order they are written. Reaching a fallback
|
||||||
|
costs an attempt, so \fBparentretries\fR has to be at least as large as the
|
||||||
|
number of parents to try.
|
||||||
|
.br
|
||||||
|
When every parent of a group has failed the request fails as well, rather
|
||||||
|
than being sent without a parent.
|
||||||
|
|
||||||
.br
|
.br
|
||||||
.BR parentretries
|
.BR parentretries
|
||||||
\fI<number>\fR
|
\fI<number>\fR
|
||||||
.br
|
.br
|
||||||
Number of retries to connect to parent proxy. Default is 1.
|
Number of attempts to reach a parent proxy. Default is 2. Each attempt
|
||||||
|
picks a parent again, leaving out the ones which already failed, so this is
|
||||||
|
also the number of different parents a request may be tried through.
|
||||||
|
|
||||||
|
|
||||||
.br
|
.br
|
||||||
@ -1573,6 +1635,21 @@ matched if the ACL matches the connection data.
|
|||||||
Warning: Regular expressions don't require authentication and cannot replace
|
Warning: Regular expressions don't require authentication and cannot replace
|
||||||
authentication and/or allow/deny ACLs.
|
authentication and/or allow/deny ACLs.
|
||||||
|
|
||||||
|
.SH OPTIONAL SERVICES
|
||||||
|
The mail proxies and FTP are built when they are asked for, and are not in a
|
||||||
|
default build. \fBMAILPROXY=true\fR builds \fBpop3p\fR, \fBimapp\fR and
|
||||||
|
\fBsmtpp\fR, and \fBFTP=true\fR builds \fBftppr\fR and the \fBftp://\fR
|
||||||
|
scheme of the HTTP proxy; with CMake the switches are
|
||||||
|
\fB-D3PROXY_USE_MAILPROXY=ON\fR and \fB-D3PROXY_USE_FTP=ON\fR. The standalone
|
||||||
|
binaries of those services are built with them and not without.
|
||||||
|
.br
|
||||||
|
A configuration naming a service which was not built is still read. The three
|
||||||
|
mail proxies become \fBtlspr\fR negotiating STARTTLS in that protocol, which
|
||||||
|
is what most of their use amounts to now that the mail protocols are used over
|
||||||
|
TLS, and a \fBparent\fR chain naming \fBpop3\fR, \fBimap\fR or \fBsmtp\fR
|
||||||
|
does the same. \fBftppr\fR is answered by nothing: a client reaching it is
|
||||||
|
turned away and the refusal logged, since there is no protocol to fall back on.
|
||||||
|
|
||||||
.SH BUILT IN HTTP SERVER
|
.SH BUILT IN HTTP SERVER
|
||||||
The \fBhttpsrv\fR service answers requests itself instead of forwarding them.
|
The \fBhttpsrv\fR service answers requests itself instead of forwarding them.
|
||||||
What it does with a request is decided by \fBhttp\fR rules, which are taken in
|
What it does with a request is decided by \fBhttp\fR rules, which are taken in
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
# 3 proxy common Makefile
|
# 3 proxy common Makefile
|
||||||
#
|
#
|
||||||
|
|
||||||
all: $(BUILDDIR)3proxy$(EXESUFFICS) $(BUILDDIR)$(CRYPT_PREFIX)crypt$(EXESUFFICS) $(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS) $(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS) $(BUILDDIR)$(PREFIX)tcppm$(EXESUFFICS) $(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS) $(BUILDDIR)$(PREFIX)tlspr$(EXESUFFICS) $(BUILDDIR)$(PREFIX)socks$(EXESUFFICS) $(BUILDDIR)$(PREFIX)proxy$(EXESUFFICS) allplugins
|
all: $(BUILDDIR)3proxy$(EXESUFFICS) $(BUILDDIR)$(CRYPT_PREFIX)crypt$(EXESUFFICS) $(MAIL_EXES) $(FTP_EXES) $(BUILDDIR)$(PREFIX)tcppm$(EXESUFFICS) $(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS) $(BUILDDIR)$(PREFIX)tlspr$(EXESUFFICS) $(BUILDDIR)$(PREFIX)socks$(EXESUFFICS) $(BUILDDIR)$(PREFIX)proxy$(EXESUFFICS) allplugins
|
||||||
|
|
||||||
sockmap$(OBJSUFFICS): sockmap.c proxy.h structures.h
|
sockmap$(OBJSUFFICS): sockmap.c proxy.h structures.h
|
||||||
$(CC) $(CFLAGS) sockmap.c
|
$(CC) $(CFLAGS) sockmap.c
|
||||||
|
|||||||
85
src/conf.c
85
src/conf.c
@ -903,6 +903,82 @@ static int parserange(unsigned char *arg, uint32_t *range)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Scan a parent weight into its share of WEIGHTSCALE, as an integer: there is
|
||||||
|
* no floating point anywhere near a configuration file.
|
||||||
|
*
|
||||||
|
* A weight starting with 0 or . is a fraction of one, so .333 and 0.333 are
|
||||||
|
* both a third. Anything else is the old notation, thousandths, where 1000 is
|
||||||
|
* the whole share, and it may now carry more digits after a dot: 123.456 means
|
||||||
|
* the same as .123456. Either way at most 9 digits are kept, which is the
|
||||||
|
* resolution weights are held at.
|
||||||
|
*
|
||||||
|
* 1 followed by a point and nothing but zeroes is the one weight read as it
|
||||||
|
* looks rather than as thousandths: 1.0 is the whole share, where a bare 1 is
|
||||||
|
* a thousandth of it.
|
||||||
|
*
|
||||||
|
* A weight may also be written as a percentage, which is what a trailing %
|
||||||
|
* makes it: 50.5% is .505 is 505.
|
||||||
|
*/
|
||||||
|
static int parseweight(unsigned char * s, unsigned * weight){
|
||||||
|
static const unsigned pow10[10] = {1, 10, 100, 1000, 10000, 100000,
|
||||||
|
1000000, 10000000, 100000000, 1000000000};
|
||||||
|
unsigned char *p, *end;
|
||||||
|
uint64_t val = 0, res;
|
||||||
|
int ndigits = 0, atpoint = -1, after, percent = 0, fraction;
|
||||||
|
|
||||||
|
if(!s || !*s) return 1;
|
||||||
|
end = s + strlen((char *)s);
|
||||||
|
if(end[-1] == '%'){
|
||||||
|
percent = 1;
|
||||||
|
if(--end == s) return 1;
|
||||||
|
}
|
||||||
|
/* 1.0, with as many zeroes after it as anyone cares to write, is the one
|
||||||
|
weight read as it looks rather than as thousandths: the whole share,
|
||||||
|
where a bare 1 is a thousandth of it */
|
||||||
|
if(!percent && s[0] == '1' && s[1] == '.' && s[2]){
|
||||||
|
for(p = s + 2; *p == '0'; p++);
|
||||||
|
if(!*p){
|
||||||
|
*weight = WEIGHTSCALE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fraction = (*s == '.' || *s == '0');
|
||||||
|
for(p = s; p < end; p++){
|
||||||
|
if(*p == '.'){
|
||||||
|
if(atpoint >= 0) return 1;
|
||||||
|
atpoint = ndigits;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(*p < '0' || *p > '9') return 1;
|
||||||
|
if(ndigits == 18) return 1;
|
||||||
|
val = (val * 10) + (unsigned)(*p - '0');
|
||||||
|
ndigits++;
|
||||||
|
}
|
||||||
|
if(!ndigits || val > WEIGHTSCALE) return 1;
|
||||||
|
after = (atpoint < 0)? 0 : ndigits - atpoint;
|
||||||
|
if(percent){
|
||||||
|
/* a hundredth of the whole share for every 1% */
|
||||||
|
if(after > 7) return 1;
|
||||||
|
res = val * pow10[7 - after];
|
||||||
|
}
|
||||||
|
else if(fraction){
|
||||||
|
/* the digits before the point are the leading zero and add
|
||||||
|
nothing, so only the ones after it say what the share is */
|
||||||
|
if(atpoint < 0) return val? 1 : (*weight = 0, 0);
|
||||||
|
if(after > 9) return 1;
|
||||||
|
res = val * pow10[9 - after];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* thousandths, with the digits after the point carrying on
|
||||||
|
from them: three digits of a whole share, six more after */
|
||||||
|
if(after > 6) return 1;
|
||||||
|
res = val * pow10[6 - after];
|
||||||
|
}
|
||||||
|
if(res > WEIGHTSCALE) return 1;
|
||||||
|
*weight = (unsigned)res;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int h_parent(int argc, unsigned char **argv){
|
static int h_parent(int argc, unsigned char **argv){
|
||||||
struct ace *acl = NULL;
|
struct ace *acl = NULL;
|
||||||
struct chain *chains;
|
struct chain *chains;
|
||||||
@ -922,9 +998,10 @@ static int h_parent(int argc, unsigned char **argv){
|
|||||||
return(21);
|
return(21);
|
||||||
}
|
}
|
||||||
memset(chains, 0, sizeof(struct chain));
|
memset(chains, 0, sizeof(struct chain));
|
||||||
chains->weight = (unsigned)atoi((char *)argv[1]);
|
/* 0 is the fallback weight: such a parent is only used once every
|
||||||
if(chains->weight == 0 || chains->weight >1000) {
|
weighted parent of its group has failed */
|
||||||
fprintf(stderr, "Chaining error: bad chain weight %u line %d\n", chains->weight, linenum);
|
if(parseweight(argv[1], &chains->weight)) {
|
||||||
|
fprintf(stderr, "Chaining error: bad chain weight %s line %d\n", argv[1], linenum);
|
||||||
free(chains);
|
free(chains);
|
||||||
return(3);
|
return(3);
|
||||||
}
|
}
|
||||||
@ -1497,7 +1574,7 @@ static int h_ace(int argc, unsigned char **argv){
|
|||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
*SAPORT(&acl->chains->addr) = htons((uint16_t)atoi((char *)argv[2]));
|
*SAPORT(&acl->chains->addr) = htons((uint16_t)atoi((char *)argv[2]));
|
||||||
acl->chains->weight = 1000;
|
acl->chains->weight = WEIGHTSCALE;
|
||||||
case ALLOW:
|
case ALLOW:
|
||||||
case DENY:
|
case DENY:
|
||||||
if(!conf.acl){
|
if(!conf.acl){
|
||||||
|
|||||||
@ -802,7 +802,7 @@ static struct property prop_pwlist[] = {
|
|||||||
static struct property prop_chain[] = {
|
static struct property prop_chain[] = {
|
||||||
{"addr", ef_chain_addr, TYPE_SA, "parent address"},
|
{"addr", ef_chain_addr, TYPE_SA, "parent address"},
|
||||||
{"type", ef_chain_type, TYPE_STRING, "parent type"},
|
{"type", ef_chain_type, TYPE_STRING, "parent type"},
|
||||||
{"weight", ef_chain_weight, TYPE_SHORT, "parent weight 0-1000"},
|
{"weight", ef_chain_weight, TYPE_INTEGER, "parent weight, 1000000000 is the whole share, 0 is a fallback"},
|
||||||
{"user", ef_chain_user, TYPE_STRING, "parent login"},
|
{"user", ef_chain_user, TYPE_STRING, "parent login"},
|
||||||
{"password", ef_chain_password, TYPE_PASSWORD, "parent password"},
|
{"password", ef_chain_password, TYPE_PASSWORD, "parent password"},
|
||||||
{"secure", ef_chain_secure, TYPE_INTEGER, "secure mode"},
|
{"secure", ef_chain_secure, TYPE_INTEGER, "secure mode"},
|
||||||
|
|||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include "proxy.h"
|
#include "proxy.h"
|
||||||
|
|
||||||
|
#ifdef WITH_FTP
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read one FTP server response, skipping continuation lines (lines whose
|
* Read one FTP server response, skipping continuation lines (lines whose
|
||||||
* 4th character is '-' per RFC 959). Returns the line length on success,
|
* 4th character is '-' per RFC 959). Returns the line length on success,
|
||||||
@ -249,3 +251,5 @@ SOCKET ftpcommand(struct clientparam *param, unsigned char * command, unsigned c
|
|||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
15
src/ftppr.c
15
src/ftppr.c
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include "proxy.h"
|
#include "proxy.h"
|
||||||
|
|
||||||
|
#ifdef WITH_FTP
|
||||||
|
|
||||||
#define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
|
#define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
|
||||||
#define BUFSIZE 2048
|
#define BUFSIZE 2048
|
||||||
|
|
||||||
@ -345,3 +347,16 @@ struct proxydef childdef = {
|
|||||||
};
|
};
|
||||||
#include "proxymain.c"
|
#include "proxymain.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Built without FTP support. The service and the redirect naming it are
|
||||||
|
still known, so a configuration carrying them is read rather than
|
||||||
|
refused, and a client reaching one is turned away. */
|
||||||
|
void * ftpprchild(struct clientparam * param){
|
||||||
|
param->res = 878;
|
||||||
|
dolog(param, (unsigned char *)"ftp support is not built in");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
14
src/imapp.c
14
src/imapp.c
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include "proxy.h"
|
#include "proxy.h"
|
||||||
|
|
||||||
|
#ifdef WITH_IMAPP
|
||||||
|
|
||||||
#define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
|
#define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
|
||||||
|
|
||||||
#define CL_LOGINCMD 0
|
#define CL_LOGINCMD 0
|
||||||
@ -250,3 +252,15 @@ struct proxydef childdef = {
|
|||||||
};
|
};
|
||||||
#include "proxymain.c"
|
#include "proxymain.c"
|
||||||
#endif
|
#endif
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Built without this proxy of its own. The command and the redirect
|
||||||
|
naming it are the STARTTLS proxy speaking that protocol, which
|
||||||
|
negotiates the same way and passes the session on: what "tlspr -Ximap"
|
||||||
|
does, under the name a configuration already uses. */
|
||||||
|
void * imappchild(struct clientparam * param){
|
||||||
|
param->starttls = S_IMAPP;
|
||||||
|
return (void *)tlsprchild;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
14
src/pop3p.c
14
src/pop3p.c
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include "proxy.h"
|
#include "proxy.h"
|
||||||
|
|
||||||
|
#ifdef WITH_POP3P
|
||||||
|
|
||||||
#define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
|
#define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
|
||||||
|
|
||||||
#ifdef WITHMAIN
|
#ifdef WITHMAIN
|
||||||
@ -88,3 +90,15 @@ struct proxydef childdef = {
|
|||||||
};
|
};
|
||||||
#include "proxymain.c"
|
#include "proxymain.c"
|
||||||
#endif
|
#endif
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Built without this proxy of its own. The command and the redirect
|
||||||
|
naming it are the STARTTLS proxy speaking that protocol, which
|
||||||
|
negotiates the same way and passes the session on: what "tlspr -Xpop3"
|
||||||
|
does, under the name a configuration already uses. */
|
||||||
|
void * pop3pchild(struct clientparam * param){
|
||||||
|
param->starttls = S_POP3P;
|
||||||
|
return (void *)tlsprchild;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -385,10 +385,12 @@ for(;;){
|
|||||||
if (!strncasecmp((char *)sb, "http://", 7)) {
|
if (!strncasecmp((char *)sb, "http://", 7)) {
|
||||||
sb += 7;
|
sb += 7;
|
||||||
}
|
}
|
||||||
|
#ifdef WITH_FTP
|
||||||
else if (!strncasecmp((char *)sb, "ftp://", 6)) {
|
else if (!strncasecmp((char *)sb, "ftp://", 6)) {
|
||||||
ftp = 1;
|
ftp = 1;
|
||||||
sb += 6;
|
sb += 6;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
else if(*sb == '/') {
|
else if(*sb == '/') {
|
||||||
param->transparent = 1;
|
param->transparent = 1;
|
||||||
}
|
}
|
||||||
@ -712,6 +714,7 @@ for(;;){
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WITH_FTP
|
||||||
if(ftp && param->redirtype != R_HTTP){
|
if(ftp && param->redirtype != R_HTTP){
|
||||||
SOCKET s;
|
SOCKET s;
|
||||||
int mode = 0;
|
int mode = 0;
|
||||||
@ -963,6 +966,7 @@ for(;;){
|
|||||||
}
|
}
|
||||||
RETURN(res);
|
RETURN(res);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if(isconnect && param->redirtype != R_HTTP) {
|
if(isconnect && param->redirtype != R_HTTP) {
|
||||||
if(param->redirectfunc) {
|
if(param->redirectfunc) {
|
||||||
|
|||||||
136
src/redirect.c
136
src/redirect.c
@ -273,45 +273,121 @@ void applyportranges(struct clientparam * param, struct ace * acentry){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void chainaddr(struct chain * cur, PROXYSOCKADDRTYPE * sa){
|
||||||
|
PROXYSOCKADDRTYPE fresh;
|
||||||
|
|
||||||
|
*sa = cur->addr;
|
||||||
|
if(resolvfunc != myresolver) return;
|
||||||
|
if(!cur->exthost || SAISNULL(&cur->addr)) return;
|
||||||
|
#ifdef WITH_UN
|
||||||
|
if(*SAFAMILY(&cur->addr) == AF_UNIX) return;
|
||||||
|
#endif
|
||||||
|
if(afdetect(cur->exthost) != -1) return;
|
||||||
|
memset(&fresh, 0, sizeof(fresh));
|
||||||
|
if(!getip46(46, cur->exthost, (struct sockaddr *)&fresh)) return;
|
||||||
|
*SAPORT(&fresh) = *SAPORT(&cur->addr);
|
||||||
|
*sa = fresh;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parentfailed(struct clientparam * param, struct chain * ch){
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < param->nfailedparents; i++)
|
||||||
|
if(param->failedparents[i] == ch) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remember a parent which could not be used for this connection, so that a
|
||||||
|
* retry picks another member of its group. The list is per connection: a
|
||||||
|
* parent which is down for one client is not taken away from the others.
|
||||||
|
*/
|
||||||
|
static void parentfail(struct clientparam * param, struct chain * ch){
|
||||||
|
if(!ch || param->nfailedparents >= MAXFAILEDPARENTS) return;
|
||||||
|
if(parentfailed(param, ch)) return;
|
||||||
|
param->failedparents[param->nfailedparents++] = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pick the parent to use for one group.
|
||||||
|
*
|
||||||
|
* A group is the members whose weights add up to WEIGHTSCALE, together with
|
||||||
|
* the zero weight members among them. *after is left pointing at the group
|
||||||
|
* after this one, or at NULL. A group which lands within WEIGHTFUZZ of the
|
||||||
|
* whole share counts as a whole one, so that 333 three times over is a group
|
||||||
|
* rather than a group and a remainder of a thousandth.
|
||||||
|
*
|
||||||
|
* A member which already failed for this connection is not offered again and
|
||||||
|
* its weight is given to the others, so a retry goes somewhere else. Zero
|
||||||
|
* weight members are the fallback: they are only offered once every weighted
|
||||||
|
* member of the group has failed, and they never take part in the share.
|
||||||
|
* Where the weights add up to plainly less than the whole share the remainder
|
||||||
|
* keeps its meaning of "no parent at all" and is still counted, so such a
|
||||||
|
* group can still leave the connection direct.
|
||||||
|
*
|
||||||
|
* Returns NULL when the group adds no parent. *exhausted tells the two cases
|
||||||
|
* apart: it is set when the group had parents and all of them are gone, which
|
||||||
|
* is a failure rather than a reason to connect directly.
|
||||||
|
*/
|
||||||
|
static struct chain * pickchain(struct clientparam * param, struct chain * group,
|
||||||
|
struct chain ** after, int * exhausted){
|
||||||
|
struct chain *cur;
|
||||||
|
uint64_t total = 0, avail = 0, slack;
|
||||||
|
uint64_t r;
|
||||||
|
|
||||||
|
*exhausted = 0;
|
||||||
|
for(cur = group; cur; cur = cur->next){
|
||||||
|
if(total + WEIGHTFUZZ >= WEIGHTSCALE && cur->weight) break;
|
||||||
|
total += cur->weight;
|
||||||
|
if(cur->weight && !parentfailed(param, cur)) avail += cur->weight;
|
||||||
|
}
|
||||||
|
*after = cur;
|
||||||
|
|
||||||
|
if(avail){
|
||||||
|
slack = (total + WEIGHTFUZZ < WEIGHTSCALE)? WEIGHTSCALE - total : 0;
|
||||||
|
r = ((uint64_t)myrand() << 32 | myrand()) % (avail + slack);
|
||||||
|
for(cur = group; cur != *after; cur = cur->next){
|
||||||
|
if(!cur->weight || parentfailed(param, cur)) continue;
|
||||||
|
if(r < cur->weight) return cur;
|
||||||
|
r -= cur->weight;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for(cur = group; cur != *after; cur = cur->next){
|
||||||
|
if(!cur->weight && !parentfailed(param, cur)) return cur;
|
||||||
|
}
|
||||||
|
if(total) *exhausted = 1;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int handleredirect(struct clientparam * param, struct ace * acentry){
|
int handleredirect(struct clientparam * param, struct ace * acentry){
|
||||||
int connected = 0;
|
int connected = 0;
|
||||||
int weight = 1000;
|
|
||||||
int res;
|
int res;
|
||||||
int done = 0;
|
|
||||||
int ha = 0;
|
int ha = 0;
|
||||||
struct chain * cur;
|
struct chain * cur;
|
||||||
|
struct chain * after;
|
||||||
struct chain * redir = NULL;
|
struct chain * redir = NULL;
|
||||||
int r2;
|
|
||||||
int saved = 0;
|
int saved = 0;
|
||||||
|
|
||||||
if((SAISNULL(¶m->req) || !*SAPORT(¶m->req)) && param->operation != UDPASSOC) {
|
if((SAISNULL(¶m->req) || !*SAPORT(¶m->req)) && param->operation != UDPASSOC) {
|
||||||
return 100;
|
return 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
r2 = (myrand()%1000);
|
for(cur = acentry->chains; cur; cur = after){
|
||||||
|
struct chain * sel;
|
||||||
|
int exhausted;
|
||||||
|
|
||||||
for(cur = acentry->chains; cur; cur=cur->next){
|
sel = pickchain(param, cur, &after, &exhausted);
|
||||||
if(((weight = weight - cur->weight) > r2)|| done) {
|
/* every parent of the group is gone: connecting direct instead
|
||||||
if(weight <= 0) {
|
would be a way around the rule, so the request fails */
|
||||||
weight += 1000;
|
if(exhausted) return 13;
|
||||||
done = 0;
|
if(!sel) continue;
|
||||||
r2 = (myrand()%1000);
|
cur = sel;
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(cur->type != R_EXTIP && cur->type != R_HA &&
|
if(cur->type != R_EXTIP && cur->type != R_HA &&
|
||||||
cur->type != R_EXTPORT && cur->type != R_INTPORT) param->redirected++;
|
cur->type != R_EXTPORT && cur->type != R_INTPORT) param->redirected++;
|
||||||
done = 1;
|
|
||||||
if(weight <= 0) {
|
|
||||||
weight += 1000;
|
|
||||||
done = 0;
|
|
||||||
r2 = (myrand()%1000);
|
|
||||||
}
|
|
||||||
if(!connected){
|
if(!connected){
|
||||||
if(cur->type == R_EXTPORT || cur->type == R_INTPORT){
|
if(cur->type == R_EXTPORT || cur->type == R_INTPORT){
|
||||||
if(cur->type == R_EXTPORT) param->extport = cur->range;
|
if(cur->type == R_EXTPORT) param->extport = cur->range;
|
||||||
else param->intport = cur->range;
|
else param->intport = cur->range;
|
||||||
if(cur->next)continue;
|
if(after)continue;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if(cur->type == R_EXTIP){
|
if(cur->type == R_EXTIP){
|
||||||
@ -333,7 +409,7 @@ int handleredirect(struct clientparam * param, struct ace * acentry){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if(cur->next)continue;
|
if(after)continue;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if(SAISNULL(&cur->addr) && !*SAPORT(&cur->addr)){
|
else if(SAISNULL(&cur->addr) && !*SAPORT(&cur->addr)){
|
||||||
@ -359,18 +435,18 @@ int handleredirect(struct clientparam * param, struct ace * acentry){
|
|||||||
if(cur->type == R_HA){
|
if(cur->type == R_HA){
|
||||||
ha = 1;
|
ha = 1;
|
||||||
}
|
}
|
||||||
if(cur->next)continue;
|
if(after)continue;
|
||||||
if(!ha) return 0;
|
if(!ha) return 0;
|
||||||
if(param->operation == UDPASSOC) return 0;
|
if(param->operation == UDPASSOC) return 0;
|
||||||
}
|
}
|
||||||
else if(!*SAPORT(&cur->addr) && !SAISNULL(&cur->addr)) {
|
else if(!*SAPORT(&cur->addr) && !SAISNULL(&cur->addr)) {
|
||||||
uint16_t port = *SAPORT(¶m->sinsr);
|
uint16_t port = *SAPORT(¶m->sinsr);
|
||||||
param->sinsr = cur->addr;
|
chainaddr(cur, ¶m->sinsr);
|
||||||
*SAPORT(¶m->sinsr) = port;
|
*SAPORT(¶m->sinsr) = port;
|
||||||
}
|
}
|
||||||
else if(SAISNULL(&cur->addr) && *SAPORT(&cur->addr)) *SAPORT(¶m->sinsr) = *SAPORT(&cur->addr);
|
else if(SAISNULL(&cur->addr) && *SAPORT(&cur->addr)) *SAPORT(¶m->sinsr) = *SAPORT(&cur->addr);
|
||||||
else {
|
else {
|
||||||
param->sinsr = cur->addr;
|
chainaddr(cur, ¶m->sinsr);
|
||||||
}
|
}
|
||||||
if(param->operation == UDPASSOC){
|
if(param->operation == UDPASSOC){
|
||||||
SOCKET s;
|
SOCKET s;
|
||||||
@ -381,6 +457,7 @@ int handleredirect(struct clientparam * param, struct ace * acentry){
|
|||||||
saved = 1;
|
saved = 1;
|
||||||
}
|
}
|
||||||
if((res = alwaysauth(param))){
|
if((res = alwaysauth(param))){
|
||||||
|
parentfail(param, cur);
|
||||||
return (res >= 10)? res : 60+res;
|
return (res >= 10)? res : 60+res;
|
||||||
}
|
}
|
||||||
if(ha) {
|
if(ha) {
|
||||||
@ -400,8 +477,14 @@ int handleredirect(struct clientparam * param, struct ace * acentry){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res = (redir)?clientnegotiate(redir, param, (struct sockaddr *)&cur->addr, cur->exthost):0;
|
PROXYSOCKADDRTYPE next;
|
||||||
if(res) return res;
|
|
||||||
|
chainaddr(cur, &next);
|
||||||
|
res = (redir)?clientnegotiate(redir, param, (struct sockaddr *)&next, cur->exthost):0;
|
||||||
|
if(res) {
|
||||||
|
parentfail(param, cur);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
redir = cur;
|
redir = cur;
|
||||||
param->redirtype = redir->type;
|
param->redirtype = redir->type;
|
||||||
@ -425,6 +508,7 @@ int handleredirect(struct clientparam * param, struct ace * acentry){
|
|||||||
|
|
||||||
if(!connected || !redir) return 0;
|
if(!connected || !redir) return 0;
|
||||||
res = clientnegotiate(redir, param, (struct sockaddr *)¶m->req, param->hostname);
|
res = clientnegotiate(redir, param, (struct sockaddr *)¶m->req, param->hostname);
|
||||||
|
if(res) parentfail(param, redir);
|
||||||
if(saved){
|
if(saved){
|
||||||
SOCKET s;
|
SOCKET s;
|
||||||
|
|
||||||
|
|||||||
14
src/smtpp.c
14
src/smtpp.c
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include "proxy.h"
|
#include "proxy.h"
|
||||||
|
|
||||||
|
#ifdef WITH_SMTPP
|
||||||
|
|
||||||
#define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
|
#define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
|
||||||
|
|
||||||
#ifdef WITHMAIN
|
#ifdef WITHMAIN
|
||||||
@ -342,3 +344,15 @@ struct proxydef childdef = {
|
|||||||
};
|
};
|
||||||
#include "proxymain.c"
|
#include "proxymain.c"
|
||||||
#endif
|
#endif
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Built without this proxy of its own. The command and the redirect
|
||||||
|
naming it are the STARTTLS proxy speaking that protocol, which
|
||||||
|
negotiates the same way and passes the session on: what "tlspr -Xsmtp"
|
||||||
|
does, under the name a configuration already uses. */
|
||||||
|
void * smtppchild(struct clientparam * param){
|
||||||
|
param->starttls = S_SMTPP;
|
||||||
|
return (void *)tlsprchild;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -62,6 +62,13 @@ typedef struct _3proxy_sem_s {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#define MAXBANDLIMS 10
|
#define MAXBANDLIMS 10
|
||||||
|
#define MAXFAILEDPARENTS 16
|
||||||
|
/* Parent weights are kept as a share of WEIGHTSCALE, which is what the
|
||||||
|
weights of a group add up to. WEIGHTFUZZ is how far short of it a group may
|
||||||
|
fall and still be taken for a whole one, a thousandth of the share: three
|
||||||
|
weights of 333, or of .333333333, otherwise leave a remainder. */
|
||||||
|
#define WEIGHTSCALE 1000000000u
|
||||||
|
#define WEIGHTFUZZ 1000000u
|
||||||
|
|
||||||
#ifdef WITH_POLL
|
#ifdef WITH_POLL
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
@ -336,7 +343,7 @@ struct chain {
|
|||||||
unsigned char * exthost;
|
unsigned char * exthost;
|
||||||
unsigned char * extuser;
|
unsigned char * extuser;
|
||||||
unsigned char * extpass;
|
unsigned char * extpass;
|
||||||
unsigned short weight;
|
unsigned weight;
|
||||||
unsigned short cidr;
|
unsigned short cidr;
|
||||||
/* local port range for extport/intport, first in the low half */
|
/* local port range for extport/intport, first in the low half */
|
||||||
uint32_t range;
|
uint32_t range;
|
||||||
@ -759,6 +766,15 @@ struct clientparam {
|
|||||||
that a plugin built against an older header still finds the fields it
|
that a plugin built against an older header still finds the fields it
|
||||||
knows where they were. */
|
knows where they were. */
|
||||||
int onerequest;
|
int onerequest;
|
||||||
|
/* A STARTTLS protocol to speak before the session is wrapped, set for
|
||||||
|
one connection rather than for the service, which is how a redirect
|
||||||
|
and a service name standing in for a mail proxy reach tlspr. */
|
||||||
|
PROXYSERVICE starttls;
|
||||||
|
/* Parents which failed for this connection. A retry picks another
|
||||||
|
member of the group instead of the same one again, and a zero weight
|
||||||
|
member is only reached once every weighted one is in here. */
|
||||||
|
struct chain *failedparents[MAXFAILEDPARENTS];
|
||||||
|
int nfailedparents;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct filemon {
|
struct filemon {
|
||||||
|
|||||||
@ -334,7 +334,8 @@ void * tlsprchild(struct clientparam* param) {
|
|||||||
int lv=-1;
|
int lv=-1;
|
||||||
char proto[PROTOLEN]="-";
|
char proto[PROTOLEN]="-";
|
||||||
int snipos = 0;
|
int snipos = 0;
|
||||||
PROXYSERVICE stlsproto = param->clientstarttls? param->clientstarttls : param->srv->srvstarttls;
|
PROXYSERVICE stlsproto = param->clientstarttls? param->clientstarttls :
|
||||||
|
(param->starttls? param->starttls : param->srv->srvstarttls);
|
||||||
|
|
||||||
if(!param->clientstarttls && stlsproto){
|
if(!param->clientstarttls && stlsproto){
|
||||||
res = clistarttls(param, stlsproto);
|
res = clistarttls(param, stlsproto);
|
||||||
|
|||||||
160
tests/cases/parent_failover.py
Normal file
160
tests/cases/parent_failover.py
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
"""parent: what happens to a group when one of its members is down.
|
||||||
|
|
||||||
|
A parent which fails is taken out of the random choice for the rest of the
|
||||||
|
connection, so a retry reaches another member of the group instead of the same
|
||||||
|
dead one again. A parent of weight 0 is the fallback of its group: it is only
|
||||||
|
used once every weighted member has failed.
|
||||||
|
|
||||||
|
The number of attempts is bounded by parentretries, two by default, so each
|
||||||
|
case here needs at most one parent to fail before a working one is reached.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
def served(server, needle, since=0):
|
||||||
|
"""How many log lines carrying needle a proxy wrote past offset since."""
|
||||||
|
return sum(1 for line in server.output()[since:].splitlines() if needle in line)
|
||||||
|
|
||||||
|
|
||||||
|
def wait_served(server, needle, count, since=0, timeout=5.0):
|
||||||
|
"""Wait for count such lines: a session is logged once it is over, which
|
||||||
|
is a moment after the client has its answer."""
|
||||||
|
deadline = time.time() + timeout
|
||||||
|
while time.time() < deadline:
|
||||||
|
seen = served(server, needle, since)
|
||||||
|
if seen >= count:
|
||||||
|
return seen
|
||||||
|
time.sleep(0.05)
|
||||||
|
return served(server, needle, since)
|
||||||
|
|
||||||
|
|
||||||
|
def run(t):
|
||||||
|
srv = t.free_port()
|
||||||
|
good = t.free_port()
|
||||||
|
spare = t.free_port()
|
||||||
|
# nothing is ever started here, so connecting to it is refused at once
|
||||||
|
dead = t.free_port()
|
||||||
|
|
||||||
|
origin = t.start("failover_origin", f"""
|
||||||
|
log
|
||||||
|
auth iponly
|
||||||
|
allow *
|
||||||
|
http echo * /echo**
|
||||||
|
httpsrv -p{srv}
|
||||||
|
""", ports=[srv])
|
||||||
|
|
||||||
|
goodp = t.start("failover_good", f"""
|
||||||
|
log
|
||||||
|
auth iponly
|
||||||
|
allow *
|
||||||
|
proxy -p{good}
|
||||||
|
""", ports=[good])
|
||||||
|
|
||||||
|
sparep = t.start("failover_spare", f"""
|
||||||
|
log
|
||||||
|
auth iponly
|
||||||
|
allow *
|
||||||
|
proxy -p{spare}
|
||||||
|
""", ports=[spare])
|
||||||
|
|
||||||
|
fallback = t.free_port()
|
||||||
|
idle = t.free_port()
|
||||||
|
group = t.free_port()
|
||||||
|
allgone = t.free_port()
|
||||||
|
lone = t.free_port()
|
||||||
|
|
||||||
|
t.start("failover_client", f"""
|
||||||
|
log
|
||||||
|
auth iponly
|
||||||
|
|
||||||
|
# the only weighted parent is dead, the fallback has to take over
|
||||||
|
flush
|
||||||
|
allow *
|
||||||
|
parent 1000 connect 127.0.0.1 {dead}
|
||||||
|
parent 0 connect 127.0.0.1 {spare}
|
||||||
|
proxy -p{fallback}
|
||||||
|
|
||||||
|
# the weighted parent works, so the fallback stays untouched
|
||||||
|
flush
|
||||||
|
allow *
|
||||||
|
parent 1000 connect 127.0.0.1 {good}
|
||||||
|
parent 0 connect 127.0.0.1 {spare}
|
||||||
|
proxy -p{idle}
|
||||||
|
|
||||||
|
# one member of a group of two is dead: a retry must not pick it again
|
||||||
|
flush
|
||||||
|
allow *
|
||||||
|
parent 500 connect 127.0.0.1 {dead}
|
||||||
|
parent 500 connect 127.0.0.1 {good}
|
||||||
|
proxy -p{group}
|
||||||
|
|
||||||
|
# nothing left to fall back to
|
||||||
|
flush
|
||||||
|
allow *
|
||||||
|
parent 1000 connect 127.0.0.1 {dead}
|
||||||
|
proxy -p{allgone}
|
||||||
|
|
||||||
|
# a parent of weight 0 on its own is simply the parent to use
|
||||||
|
flush
|
||||||
|
allow *
|
||||||
|
parent 0 connect 127.0.0.1 {good}
|
||||||
|
proxy -p{lone}
|
||||||
|
""", ports=[fallback, idle, group, allgone, lone])
|
||||||
|
|
||||||
|
url = f"http://127.0.0.1:{srv}/echo"
|
||||||
|
needle = f"CONNECT 127.0.0.1:{srv}"
|
||||||
|
|
||||||
|
# --- the fallback takes over --------------------------------------------
|
||||||
|
mark = len(sparep.output())
|
||||||
|
r = t.http(url, proxy=f"127.0.0.1:{fallback}")
|
||||||
|
t.eq(200, r.status, "a dead weighted parent falls back to the parent of weight 0")
|
||||||
|
t.eq(1, wait_served(sparep, needle, 1, mark),
|
||||||
|
"the fallback parent carried the request")
|
||||||
|
|
||||||
|
# --- and only then ------------------------------------------------------
|
||||||
|
mark = len(sparep.output())
|
||||||
|
gmark = len(goodp.output())
|
||||||
|
for _ in range(4):
|
||||||
|
t.eq(200, t.http(url, proxy=f"127.0.0.1:{idle}").status,
|
||||||
|
"a working weighted parent serves the request")
|
||||||
|
t.eq(4, wait_served(goodp, needle, 4, gmark),
|
||||||
|
"every request went through the weighted parent")
|
||||||
|
t.eq(0, served(sparep, needle, mark),
|
||||||
|
"the fallback is left alone while the weighted parent works")
|
||||||
|
|
||||||
|
# --- a dead member of a weighted group ----------------------------------
|
||||||
|
# Whichever of the two the first attempt picks, the request has to end up
|
||||||
|
# at the one that is up: the dead one is not offered to the retry again.
|
||||||
|
gmark = len(goodp.output())
|
||||||
|
statuses = [t.http(url, proxy=f"127.0.0.1:{group}").status for _ in range(8)]
|
||||||
|
t.eq([200] * 8, statuses,
|
||||||
|
"a dead member of a group never fails a request twice over")
|
||||||
|
t.eq(8, wait_served(goodp, needle, 8, gmark),
|
||||||
|
"all of them were carried by the member which is up")
|
||||||
|
|
||||||
|
# --- nothing left -------------------------------------------------------
|
||||||
|
# With every parent of the group gone the request has to fail. Connecting
|
||||||
|
# direct instead would be a way around the rule that asked for a parent.
|
||||||
|
omark = len(origin.output())
|
||||||
|
r = t.http(url, proxy=f"127.0.0.1:{allgone}")
|
||||||
|
t.ne(200, r.status, "a request fails when every parent of the group is down")
|
||||||
|
time.sleep(0.5)
|
||||||
|
t.eq(0, served(origin, "/echo", omark),
|
||||||
|
"and it is not sent direct to the origin instead")
|
||||||
|
|
||||||
|
# --- weight 0 on its own ------------------------------------------------
|
||||||
|
gmark = len(goodp.output())
|
||||||
|
t.eq(200, t.http(url, proxy=f"127.0.0.1:{lone}").status,
|
||||||
|
"a parent of weight 0 alone is used like any other")
|
||||||
|
t.eq(1, wait_served(goodp, needle, 1, gmark),
|
||||||
|
"through the parent it names")
|
||||||
|
|
||||||
|
# --- what the parser still rejects --------------------------------------
|
||||||
|
out = t.run_config("failover_badweight", f"""
|
||||||
|
auth iponly
|
||||||
|
allow *
|
||||||
|
parent 1001 connect 127.0.0.1 {good}
|
||||||
|
proxy -p{t.free_port()}
|
||||||
|
""")
|
||||||
|
t.contains(out, "bad chain weight", "a weight above 1000 is still refused")
|
||||||
210
tests/cases/parent_weights.py
Normal file
210
tests/cases/parent_weights.py
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
"""parent weights: the fraction notation, and what a group adds up to.
|
||||||
|
|
||||||
|
A weight is scanned as an integer into a share of 1000000000. A weight which
|
||||||
|
starts with 0 or . is a fraction of one, .333 being a third; anything else is
|
||||||
|
the old notation, thousandths, which may now carry further digits after a dot,
|
||||||
|
so 123.456 means the same as .123456. 1.0 is the exception, read as it looks,
|
||||||
|
and a trailing % makes a weight a percentage: 50.5% is .505 is 505.
|
||||||
|
|
||||||
|
The values are read back from the admin interface, which dumps the parsed
|
||||||
|
configuration, so what is checked is the number 3proxy holds rather than the
|
||||||
|
behaviour it happens to produce.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
|
CHAIN_WEIGHT = re.compile(
|
||||||
|
r"parent weight[^<]*</description><value><!\[CDATA\[([0-9]+)")
|
||||||
|
|
||||||
|
|
||||||
|
def weights(t, adm):
|
||||||
|
return [int(v) for v in CHAIN_WEIGHT.findall(t.http(f"http://127.0.0.1:{adm}/S").text)]
|
||||||
|
|
||||||
|
|
||||||
|
def served(server, needle, since=0):
|
||||||
|
return sum(1 for line in server.output()[since:].splitlines() if needle in line)
|
||||||
|
|
||||||
|
|
||||||
|
def wait_served(server, needle, count, since=0, timeout=5.0):
|
||||||
|
deadline = time.time() + timeout
|
||||||
|
while time.time() < deadline:
|
||||||
|
seen = served(server, needle, since)
|
||||||
|
if seen >= count:
|
||||||
|
return seen
|
||||||
|
time.sleep(0.05)
|
||||||
|
return served(server, needle, since)
|
||||||
|
|
||||||
|
|
||||||
|
def run(t):
|
||||||
|
adm = t.free_port()
|
||||||
|
prx = t.free_port()
|
||||||
|
dummy = t.free_port()
|
||||||
|
|
||||||
|
t.start("weights_parse", f"""
|
||||||
|
auth iponly
|
||||||
|
allow *
|
||||||
|
admin -p{adm}
|
||||||
|
|
||||||
|
flush
|
||||||
|
auth iponly
|
||||||
|
allow *
|
||||||
|
parent 1000 connect 127.0.0.1 {dummy}
|
||||||
|
parent 1.0 connect 127.0.0.1 {dummy}
|
||||||
|
parent 1.00000000000000 connect 127.0.0.1 {dummy}
|
||||||
|
parent 500 connect 127.0.0.1 {dummy}
|
||||||
|
parent 1 connect 127.0.0.1 {dummy}
|
||||||
|
parent 1.5 connect 127.0.0.1 {dummy}
|
||||||
|
parent 123.456 connect 127.0.0.1 {dummy}
|
||||||
|
parent 12.34 connect 127.0.0.1 {dummy}
|
||||||
|
parent 1.000001 connect 127.0.0.1 {dummy}
|
||||||
|
parent .333 connect 127.0.0.1 {dummy}
|
||||||
|
parent 0.333 connect 127.0.0.1 {dummy}
|
||||||
|
parent .5 connect 127.0.0.1 {dummy}
|
||||||
|
parent .333333333 connect 127.0.0.1 {dummy}
|
||||||
|
parent 0.000000001 connect 127.0.0.1 {dummy}
|
||||||
|
parent 100% connect 127.0.0.1 {dummy}
|
||||||
|
parent 50.5% connect 127.0.0.1 {dummy}
|
||||||
|
parent 50% connect 127.0.0.1 {dummy}
|
||||||
|
parent 33.3333333% connect 127.0.0.1 {dummy}
|
||||||
|
parent 1.0% connect 127.0.0.1 {dummy}
|
||||||
|
parent 0.0000001% connect 127.0.0.1 {dummy}
|
||||||
|
parent 0 connect 127.0.0.1 {dummy}
|
||||||
|
proxy -p{prx}
|
||||||
|
""", ports=[adm, prx])
|
||||||
|
|
||||||
|
t.eq([
|
||||||
|
1000000000, # 1000, the old notation for the whole share
|
||||||
|
1000000000, # 1.0, the same share written as a fraction
|
||||||
|
1000000000, # 1.00000000000000, zeroes past the point change nothing
|
||||||
|
500000000, # 500
|
||||||
|
1000000, # 1, a thousandth
|
||||||
|
1500000, # 1.5, one thousandth and a half of one
|
||||||
|
123456000, # 123.456, the old notation carried further
|
||||||
|
12340000, # 12.34
|
||||||
|
1000001, # 1.000001, six digits past the thousandths
|
||||||
|
333000000, # .333
|
||||||
|
333000000, # 0.333, the same thing written out
|
||||||
|
500000000, # .5
|
||||||
|
333333333, # .333333333, the finest the resolution goes
|
||||||
|
1, # 0.000000001, one part of the whole
|
||||||
|
1000000000, # 100%
|
||||||
|
505000000, # 50.5%, the same as .505 and as 505
|
||||||
|
500000000, # 50%
|
||||||
|
333333333, # 33.3333333%, seven digits past the point
|
||||||
|
10000000, # 1.0%, a percent rather than the whole share
|
||||||
|
1, # 0.0000001%, one part again
|
||||||
|
0, # the fallback weight
|
||||||
|
], weights(t, adm), "every notation is scanned into its share")
|
||||||
|
|
||||||
|
# --- what the parser refuses ------------------------------------------
|
||||||
|
for bad in ("1001", "1000.1", "1.0000001", ".1234567890", "01", "abc",
|
||||||
|
"1.2.3", "-1", "1e9", "101%", "50.55555555%", "%", "5%%",
|
||||||
|
"%5"):
|
||||||
|
out = t.run_config("weights_bad", f"""
|
||||||
|
auth iponly
|
||||||
|
allow *
|
||||||
|
parent {bad} connect 127.0.0.1 {dummy}
|
||||||
|
proxy -p{t.free_port()}
|
||||||
|
""")
|
||||||
|
t.contains(out, "bad chain weight", f"{bad} is refused as a weight")
|
||||||
|
|
||||||
|
# --- a group that all but adds up ---------------------------------------
|
||||||
|
# .999999999 is one part short of the whole share. It still closes its
|
||||||
|
# group, so the parent after it is the next hop of a chain rather than
|
||||||
|
# another member of the same group.
|
||||||
|
srv = t.free_port()
|
||||||
|
first = t.free_port()
|
||||||
|
second = t.free_port()
|
||||||
|
chained = t.free_port()
|
||||||
|
grouped = t.free_port()
|
||||||
|
thirds = t.free_port()
|
||||||
|
|
||||||
|
t.start("weights_origin", f"""
|
||||||
|
log
|
||||||
|
auth iponly
|
||||||
|
allow *
|
||||||
|
http echo * /echo**
|
||||||
|
httpsrv -p{srv}
|
||||||
|
""", ports=[srv])
|
||||||
|
|
||||||
|
firstp = t.start("weights_first", f"""
|
||||||
|
log
|
||||||
|
auth iponly
|
||||||
|
allow *
|
||||||
|
proxy -p{first}
|
||||||
|
""", ports=[first])
|
||||||
|
|
||||||
|
secondp = t.start("weights_second", f"""
|
||||||
|
log
|
||||||
|
auth iponly
|
||||||
|
allow *
|
||||||
|
proxy -p{second}
|
||||||
|
""", ports=[second])
|
||||||
|
|
||||||
|
t.start("weights_client", f"""
|
||||||
|
log
|
||||||
|
auth iponly
|
||||||
|
|
||||||
|
# one part short of the whole share still ends the group
|
||||||
|
flush
|
||||||
|
allow *
|
||||||
|
parent .999999999 connect 127.0.0.1 {first}
|
||||||
|
parent 1000 connect 127.0.0.1 {second}
|
||||||
|
proxy -p{chained}
|
||||||
|
|
||||||
|
# two halves, one written each way, are one group and one hop
|
||||||
|
flush
|
||||||
|
allow *
|
||||||
|
parent 500 connect 127.0.0.1 {first}
|
||||||
|
parent .5 connect 127.0.0.1 {second}
|
||||||
|
proxy -p{grouped}
|
||||||
|
|
||||||
|
# three thirds are a thousandth short of the whole share and still
|
||||||
|
# make a group, so the parent after them is the next hop
|
||||||
|
flush
|
||||||
|
allow *
|
||||||
|
parent 333 connect 127.0.0.1 {first}
|
||||||
|
parent 333 connect 127.0.0.1 {first}
|
||||||
|
parent 333 connect 127.0.0.1 {first}
|
||||||
|
parent 1000 connect 127.0.0.1 {second}
|
||||||
|
proxy -p{thirds}
|
||||||
|
""", ports=[chained, grouped, thirds])
|
||||||
|
|
||||||
|
url = f"http://127.0.0.1:{srv}/echo"
|
||||||
|
toorigin = f"CONNECT 127.0.0.1:{srv}"
|
||||||
|
tosecond = f"CONNECT 127.0.0.1:{second}"
|
||||||
|
|
||||||
|
fmark, smark = len(firstp.output()), len(secondp.output())
|
||||||
|
t.eq(200, t.http(url, proxy=f"127.0.0.1:{chained}").status,
|
||||||
|
"a chain of two groups carries the request")
|
||||||
|
t.eq(1, wait_served(firstp, tosecond, 1, fmark),
|
||||||
|
"the first group's parent was asked for the second one")
|
||||||
|
t.eq(1, wait_served(secondp, toorigin, 1, smark),
|
||||||
|
"and the second group's parent reached the origin")
|
||||||
|
t.eq(0, served(firstp, toorigin, fmark),
|
||||||
|
"the first parent never went to the origin itself")
|
||||||
|
|
||||||
|
# both members of one group talk to the origin, never to each other
|
||||||
|
fmark, smark = len(firstp.output()), len(secondp.output())
|
||||||
|
for _ in range(8):
|
||||||
|
t.eq(200, t.http(url, proxy=f"127.0.0.1:{grouped}").status,
|
||||||
|
"a group of two halves carries the request")
|
||||||
|
t.eq(8, wait_served(firstp, toorigin, 8, fmark, timeout=0.5) +
|
||||||
|
wait_served(secondp, toorigin, 8, smark, timeout=0.5),
|
||||||
|
"each request took one hop, through either half")
|
||||||
|
t.eq(0, served(firstp, tosecond, fmark),
|
||||||
|
"the halves are one group, not a chain")
|
||||||
|
|
||||||
|
# --- three thirds -------------------------------------------------------
|
||||||
|
# 999000000 is within a thousandth of the whole share, so the group closes
|
||||||
|
# there. Were it left open the parent of weight 1000 would join it and
|
||||||
|
# carry about half the requests on its own, without the first hop.
|
||||||
|
fmark, smark = len(firstp.output()), len(secondp.output())
|
||||||
|
for _ in range(8):
|
||||||
|
t.eq(200, t.http(url, proxy=f"127.0.0.1:{thirds}").status,
|
||||||
|
"a group of three thirds carries the request")
|
||||||
|
t.eq(8, wait_served(firstp, tosecond, 8, fmark),
|
||||||
|
"every request took a third as its first hop")
|
||||||
|
t.eq(8, wait_served(secondp, toorigin, 8, smark),
|
||||||
|
"and the parent after them as its second")
|
||||||
Loading…
Reference in New Issue
Block a user