mirror of
https://github.com/3proxy/3proxy.git
synced 2026-09-29 16:55:51 +08:00
Compare commits
No commits in common. "7bc34002df3604ac568553cd4acc97e2defa08a6" and "1d240ced933f9977e6d0bc543e832ee775763d0b" have entirely different histories.
7bc34002df
...
1d240ced93
1
.github/workflows/update-docs.yml
vendored
1
.github/workflows/update-docs.yml
vendored
@ -2,7 +2,6 @@ name: Update HTML documentation
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [master]
|
|
||||||
paths:
|
paths:
|
||||||
- 'man/**'
|
- 'man/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|||||||
33
.github/workflows/update-version.yml
vendored
33
.github/workflows/update-version.yml
vendored
@ -4,7 +4,6 @@ on:
|
|||||||
push:
|
push:
|
||||||
paths:
|
paths:
|
||||||
- RELEASE
|
- RELEASE
|
||||||
- DEVEL
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
@ -20,23 +19,12 @@ jobs:
|
|||||||
|
|
||||||
- name: Regenerate version files
|
- name: Regenerate version files
|
||||||
run: |
|
run: |
|
||||||
# A release branch carries RELEASE, a development branch DEVEL, whose
|
RELEASE=$(tr -d ' \t\r\n' < RELEASE)
|
||||||
# version may have a suffix such as 2.0.0-devel.
|
if [ -z "$RELEASE" ]; then echo "RELEASE is empty"; exit 1; fi
|
||||||
if [ -f RELEASE ]; then VERFILE=RELEASE
|
MAJOR=$(echo "$RELEASE" | cut -d . -f 1)
|
||||||
elif [ -f DEVEL ]; then VERFILE=DEVEL
|
SUBMAJOR=$(echo "$RELEASE" | cut -d . -f 2)
|
||||||
else echo "neither RELEASE nor DEVEL is present"; exit 1
|
MINOR=$(echo "$RELEASE" | cut -d . -f 3)
|
||||||
fi
|
SUBMINOR=$(echo "$RELEASE" | cut -d . -f 4)
|
||||||
RELEASE=$(tr -d ' \t\r\n' < "$VERFILE")
|
|
||||||
if [ -z "$RELEASE" ]; then echo "$VERFILE is empty"; exit 1; fi
|
|
||||||
|
|
||||||
# the numbered fields take the numeric part, the strings keep all of it
|
|
||||||
NUMBERS=${RELEASE%%[!0-9.]*}
|
|
||||||
NUMBERS=${NUMBERS%.}
|
|
||||||
if [ -z "$NUMBERS" ]; then echo "no version number in '$RELEASE'"; exit 1; fi
|
|
||||||
MAJOR=$(echo "$NUMBERS" | cut -d . -f 1)
|
|
||||||
SUBMAJOR=$(echo "$NUMBERS" | cut -d . -f 2)
|
|
||||||
MINOR=$(echo "$NUMBERS" | cut -d . -f 3)
|
|
||||||
SUBMINOR=$(echo "$NUMBERS" | cut -d . -f 4)
|
|
||||||
[ -n "$SUBMAJOR" ] || SUBMAJOR=0
|
[ -n "$SUBMAJOR" ] || SUBMAJOR=0
|
||||||
[ -n "$MINOR" ] || MINOR=0
|
[ -n "$MINOR" ] || MINOR=0
|
||||||
[ -n "$SUBMINOR" ] || SUBMINOR=0
|
[ -n "$SUBMINOR" ] || SUBMINOR=0
|
||||||
@ -51,10 +39,7 @@ jobs:
|
|||||||
else
|
else
|
||||||
BUILDDATE=$(date -u +%y%m%d%H%M%S)
|
BUILDDATE=$(date -u +%y%m%d%H%M%S)
|
||||||
fi
|
fi
|
||||||
# rpm refuses a hyphen in Version, so a suffix becomes a tilde, which
|
echo "release $RELEASE -> $MAJOR $SUBMAJOR $MINOR $SUBMINOR, build date $BUILDDATE"
|
||||||
# also sorts before the release of the same number
|
|
||||||
RPMVERSION=$(echo "$RELEASE" | tr '-' '~')
|
|
||||||
echo "$VERFILE $RELEASE -> $MAJOR $SUBMAJOR $MINOR $SUBMINOR, rpm $RPMVERSION, build date $BUILDDATE"
|
|
||||||
SOURCE_DATE_EPOCH=$(date -u -d "20${BUILDDATE:0:2}-${BUILDDATE:2:2}-${BUILDDATE:4:2} ${BUILDDATE:6:2}:${BUILDDATE:8:2}:${BUILDDATE:10:2}" +%s)
|
SOURCE_DATE_EPOCH=$(date -u -d "20${BUILDDATE:0:2}-${BUILDDATE:2:2}-${BUILDDATE:4:2} ${BUILDDATE:6:2}:${BUILDDATE:8:2}:${BUILDDATE:10:2}" +%s)
|
||||||
YEAR=$(date -u -d @$SOURCE_DATE_EPOCH +%Y)
|
YEAR=$(date -u -d @$SOURCE_DATE_EPOCH +%Y)
|
||||||
|
|
||||||
@ -74,7 +59,7 @@ jobs:
|
|||||||
|
|
||||||
mv scripts/rh/3proxy.spec scripts/rh/3proxy.spec.old
|
mv scripts/rh/3proxy.spec scripts/rh/3proxy.spec.old
|
||||||
{ echo "Name: 3proxy"
|
{ echo "Name: 3proxy"
|
||||||
echo "Version: $RPMVERSION"
|
echo "Version: $RELEASE"
|
||||||
echo "Release: 1%{?dist}"
|
echo "Release: 1%{?dist}"
|
||||||
tail --lines=+4 scripts/rh/3proxy.spec.old
|
tail --lines=+4 scripts/rh/3proxy.spec.old
|
||||||
} > scripts/rh/3proxy.spec
|
} > scripts/rh/3proxy.spec
|
||||||
@ -105,5 +90,5 @@ jobs:
|
|||||||
git config user.name "github-actions[bot]"
|
git config user.name "github-actions[bot]"
|
||||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||||
git add debian/changelog scripts/rh/3proxy.spec src/version.h
|
git add debian/changelog scripts/rh/3proxy.spec src/version.h
|
||||||
git commit -m "Update version files for $(tr -d ' \t\r\n' < $(test -f RELEASE && echo RELEASE || echo DEVEL))"
|
git commit -m "Update version files for $(tr -d ' \t\r\n' < RELEASE)"
|
||||||
git push
|
git push
|
||||||
|
|||||||
3
.github/workflows/update-wiki.yml
vendored
3
.github/workflows/update-wiki.yml
vendored
@ -2,7 +2,6 @@ name: Update wiki
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [master]
|
|
||||||
paths:
|
paths:
|
||||||
- 'doc/html/**'
|
- 'doc/html/**'
|
||||||
workflow_run:
|
workflow_run:
|
||||||
@ -19,8 +18,6 @@ concurrency:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
wiki:
|
wiki:
|
||||||
# the wiki mirrors master, so a run started by anything else is not for it
|
|
||||||
if: github.event_name != 'workflow_run' || github.event.workflow_run.head_branch == 'master'
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v7
|
||||||
|
|||||||
@ -4,20 +4,8 @@
|
|||||||
|
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
# Read the version. A release branch carries RELEASE, a development branch
|
# Read version from RELEASE file
|
||||||
# DEVEL, whose version may have a suffix that project() will not take.
|
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/RELEASE" PROJECT_VERSION LIMIT_COUNT 1)
|
||||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/RELEASE")
|
|
||||||
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/RELEASE" PROJECT_VERSION_FULL LIMIT_COUNT 1)
|
|
||||||
elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/DEVEL")
|
|
||||||
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/DEVEL" PROJECT_VERSION_FULL LIMIT_COUNT 1)
|
|
||||||
else()
|
|
||||||
message(FATAL_ERROR "Neither RELEASE nor DEVEL found: cannot tell the version")
|
|
||||||
endif()
|
|
||||||
string(STRIP "${PROJECT_VERSION_FULL}" PROJECT_VERSION_FULL)
|
|
||||||
string(REGEX MATCH "^[0-9]+(\\.[0-9]+)*" PROJECT_VERSION "${PROJECT_VERSION_FULL}")
|
|
||||||
if(NOT PROJECT_VERSION)
|
|
||||||
message(FATAL_ERROR "No version number in '${PROJECT_VERSION_FULL}'")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
project(3proxy
|
project(3proxy
|
||||||
VERSION ${PROJECT_VERSION}
|
VERSION ${PROJECT_VERSION}
|
||||||
@ -67,7 +55,6 @@ option(3PROXY_USE_SPLICE "Build Linux splice() support, slower than read/write f
|
|||||||
option(3PROXY_USE_POLL "Use poll() instead of select() (Unix only)" ON)
|
option(3PROXY_USE_POLL "Use poll() instead of select() (Unix only)" ON)
|
||||||
option(3PROXY_USE_WSAPOLL "Use WSAPoll instead of select() (Windows only)" ON)
|
option(3PROXY_USE_WSAPOLL "Use WSAPoll instead of select() (Windows only)" ON)
|
||||||
option(3PROXY_USE_NETFILTER "Enable Linux netfilter support (Linux only)" ON)
|
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_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)
|
||||||
|
|
||||||
@ -115,9 +102,6 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
|||||||
if(WIN32)
|
if(WIN32)
|
||||||
# Windows-specific configuration
|
# Windows-specific configuration
|
||||||
add_compile_definitions(
|
add_compile_definitions(
|
||||||
# Windows does not take a recv and a send on one socket from two
|
|
||||||
# threads, so a UDP service answers from a socket of its own
|
|
||||||
NO_SHARE_UDP_SOCKET
|
|
||||||
WIN32
|
WIN32
|
||||||
_WIN32
|
_WIN32
|
||||||
_MBCS
|
_MBCS
|
||||||
@ -209,6 +193,7 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
|||||||
set(DEFAULT_PLUGINS
|
set(DEFAULT_PLUGINS
|
||||||
StringsPlugin
|
StringsPlugin
|
||||||
TrafficPlugin
|
TrafficPlugin
|
||||||
|
TransparentPlugin
|
||||||
FilePlugin
|
FilePlugin
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -230,6 +215,7 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD|Darwin|OpenBSD|NetBSD")
|
|||||||
set(DEFAULT_PLUGINS
|
set(DEFAULT_PLUGINS
|
||||||
StringsPlugin
|
StringsPlugin
|
||||||
TrafficPlugin
|
TrafficPlugin
|
||||||
|
TransparentPlugin
|
||||||
FilePlugin
|
FilePlugin
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -246,6 +232,7 @@ else()
|
|||||||
set(DEFAULT_PLUGINS
|
set(DEFAULT_PLUGINS
|
||||||
StringsPlugin
|
StringsPlugin
|
||||||
TrafficPlugin
|
TrafficPlugin
|
||||||
|
TransparentPlugin
|
||||||
FilePlugin
|
FilePlugin
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
@ -254,25 +241,6 @@ if(3PROXY_USE_HTTPSRV)
|
|||||||
add_compile_definitions(WITH_HTTPSRV)
|
add_compile_definitions(WITH_HTTPSRV)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Transparent proxying needs a redirection that leaves the original
|
|
||||||
# destination where 3proxy reads it: the kernel on Linux, the socket on the
|
|
||||||
# BSDs. That means netfilter, OpenBSD divert-to or FreeBSD ipfw fwd. NetBSD
|
|
||||||
# and macOS rewrite the destination instead and are left out.
|
|
||||||
if(3PROXY_USE_TRANSPARENT AND (CMAKE_SYSTEM_NAME STREQUAL "Linux"
|
|
||||||
OR CMAKE_SYSTEM_NAME MATCHES "FreeBSD|OpenBSD|NetBSD"))
|
|
||||||
add_compile_definitions(WITH_TRANSPARENT)
|
|
||||||
set(3PROXY_TRANSPARENT_BUILT ON)
|
|
||||||
# pf keeps the original destination in its state table, which is read
|
|
||||||
# through /dev/pf. macOS has the device but ships no header for it.
|
|
||||||
include(CheckIncludeFiles)
|
|
||||||
check_include_files("sys/types.h;sys/socket.h;net/if.h;net/pfvar.h" HAVE_PFVAR_H)
|
|
||||||
if(HAVE_PFVAR_H)
|
|
||||||
add_compile_definitions(WITH_PF)
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
set(3PROXY_TRANSPARENT_BUILT OFF)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Unix domain sockets off: NO_UN also undefines WITH_UN if it arrives from
|
# Unix domain sockets off: NO_UN also undefines WITH_UN if it arrives from
|
||||||
# elsewhere, e.g. CFLAGS
|
# elsewhere, e.g. CFLAGS
|
||||||
if(NOT 3PROXY_USE_UNIX_SOCKETS)
|
if(NOT 3PROXY_USE_UNIX_SOCKETS)
|
||||||
@ -503,10 +471,6 @@ if(PCRE2_FOUND)
|
|||||||
target_sources(3proxy PRIVATE src/pcre.c)
|
target_sources(3proxy PRIVATE src/pcre.c)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(3PROXY_TRANSPARENT_BUILT)
|
|
||||||
target_sources(3proxy PRIVATE src/transparent.c)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_include_directories(3proxy PRIVATE
|
target_include_directories(3proxy PRIVATE
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/libs
|
${CMAKE_CURRENT_SOURCE_DIR}/src/libs
|
||||||
@ -953,7 +917,7 @@ endif()
|
|||||||
# Summary
|
# Summary
|
||||||
message(STATUS "")
|
message(STATUS "")
|
||||||
message(STATUS "3proxy configuration summary:")
|
message(STATUS "3proxy configuration summary:")
|
||||||
message(STATUS " Version: ${PROJECT_VERSION_FULL}")
|
message(STATUS " Version: ${PROJECT_VERSION}")
|
||||||
message(STATUS " Platform: ${CMAKE_SYSTEM_NAME}")
|
message(STATUS " Platform: ${CMAKE_SYSTEM_NAME}")
|
||||||
message(STATUS " Compiler: ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION}")
|
message(STATUS " Compiler: ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION}")
|
||||||
message(STATUS " Build type: ${CMAKE_BUILD_TYPE}")
|
message(STATUS " Build type: ${CMAKE_BUILD_TYPE}")
|
||||||
@ -963,7 +927,6 @@ message(STATUS " BUILD_SHARED: ${3PROXY_BUILD_SHARED}")
|
|||||||
message(STATUS " USE_WOLFSSL: ${3PROXY_USE_WOLFSSL}")
|
message(STATUS " USE_WOLFSSL: ${3PROXY_USE_WOLFSSL}")
|
||||||
message(STATUS " USE_OPENSSL: ${3PROXY_USE_OPENSSL}")
|
message(STATUS " USE_OPENSSL: ${3PROXY_USE_OPENSSL}")
|
||||||
message(STATUS " USE_PCRE2: ${3PROXY_USE_PCRE2}")
|
message(STATUS " USE_PCRE2: ${3PROXY_USE_PCRE2}")
|
||||||
message(STATUS " TRANSPARENT: ${3PROXY_TRANSPARENT_BUILT}")
|
|
||||||
message(STATUS " USE_PAM: ${3PROXY_USE_PAM}")
|
message(STATUS " USE_PAM: ${3PROXY_USE_PAM}")
|
||||||
message(STATUS " USE_ODBC: ${3PROXY_USE_ODBC}")
|
message(STATUS " USE_ODBC: ${3PROXY_USE_ODBC}")
|
||||||
message(STATUS " USE_POLL: ${3PROXY_USE_POLL}")
|
message(STATUS " USE_POLL: ${3PROXY_USE_POLL}")
|
||||||
|
|||||||
@ -44,20 +44,7 @@ AFTERCLEAN = (find . -type f -name "*.o" -delete && find src/ -type f -name "Mak
|
|||||||
TYPECOMMAND = cat
|
TYPECOMMAND = cat
|
||||||
COMPATLIBS =
|
COMPATLIBS =
|
||||||
MAKEFILE = Makefile.FreeBSD
|
MAKEFILE = Makefile.FreeBSD
|
||||||
PLUGINS ?= StringsPlugin TrafficPlugin FilePlugin
|
PLUGINS ?= StringsPlugin TrafficPlugin TransparentPlugin FilePlugin
|
||||||
|
|
||||||
# Transparent proxying, built in. The destination of a redirected connection
|
|
||||||
# comes from pf where its headers are available, and from the socket where a
|
|
||||||
# redirection leaves it there (OpenBSD divert-to, FreeBSD ipfw fwd). macOS
|
|
||||||
# has /dev/pf but ships no pfvar.h, so only the socket route is built there
|
|
||||||
# and no macOS redirection leaves the address on the socket.
|
|
||||||
CFLAGS += -DWITH_TRANSPARENT
|
|
||||||
TRANSPARENT_OBJS = transparent$(OBJSUFFICS)
|
|
||||||
|
|
||||||
PF_CHECK ?= $(shell printf "\#include <sys/types.h>\\n\#include <sys/socket.h>\\n\#include <net/if.h>\\n\#include <net/pfvar.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpf.o -c - 2>/dev/null && rm testpf.o && echo true||echo false)
|
|
||||||
ifeq ($(PF_CHECK), true)
|
|
||||||
CFLAGS += -DWITH_PF
|
|
||||||
endif
|
|
||||||
ifeq ($(STATIC), true)
|
ifeq ($(STATIC), true)
|
||||||
LDFLAGS += -static
|
LDFLAGS += -static
|
||||||
CFLAGS += -DNOPLUGINS -DNOSTDRESOLVE -DNOCRYPT
|
CFLAGS += -DNOPLUGINS -DNOSTDRESOLVE -DNOCRYPT
|
||||||
|
|||||||
@ -50,12 +50,8 @@ MAKEFILE = Makefile.Linux
|
|||||||
# PamAuth requires libpam, you may require pam-devel package to be installed
|
# PamAuth requires libpam, you may require pam-devel package to be installed
|
||||||
# SSLPlugin requires -lcrypto -lssl
|
# SSLPlugin requires -lcrypto -lssl
|
||||||
#LIBS = -lcrypto -lssl -ldl
|
#LIBS = -lcrypto -lssl -ldl
|
||||||
#PLUGINS = StringsPlugin TrafficPlugin PamAuth LdapPlugin
|
#PLUGINS = SSLPlugin StringsPlugin TrafficPlugin PCREPlugin TransparentPlugin PamAuth
|
||||||
PLUGINS ?= StringsPlugin TrafficPlugin FilePlugin
|
PLUGINS ?= StringsPlugin TrafficPlugin TransparentPlugin FilePlugin
|
||||||
|
|
||||||
# Transparent proxying, built in: it needs the packet filter of the platform
|
|
||||||
CFLAGS += -DWITH_TRANSPARENT
|
|
||||||
TRANSPARENT_OBJS = transparent$(OBJSUFFICS)
|
|
||||||
ifeq ($(STATIC), true)
|
ifeq ($(STATIC), true)
|
||||||
LDFLAGS += -static
|
LDFLAGS += -static
|
||||||
CFLAGS += -DNOPLUGINS -DNOSTDRESOLVE -DNOCRYPT
|
CFLAGS += -DNOPLUGINS -DNOSTDRESOLVE -DNOCRYPT
|
||||||
|
|||||||
@ -34,7 +34,7 @@ AFTERCLEAN = (find . -type f -name "*.o" -delete && find src/ -type f -name "Mak
|
|||||||
TYPECOMMAND = cat
|
TYPECOMMAND = cat
|
||||||
COMPATLIBS =
|
COMPATLIBS =
|
||||||
MAKEFILE = Makefile.Solaris
|
MAKEFILE = Makefile.Solaris
|
||||||
PLUGINS = StringsPlugin TrafficPlugin FilePlugin
|
PLUGINS = StringsPlugin TrafficPlugin TransparentPlugin FilePlugin
|
||||||
|
|
||||||
WOLFSSL_CHECK = $(shell printf "\#include <wolfssl/options.h>\\n\#include <wolfssl/openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testwssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -o testwssl testwssl.o -lwolfssl 2>/dev/null && rm testwssl testwssl.o && echo true||echo false)
|
WOLFSSL_CHECK = $(shell printf "\#include <wolfssl/options.h>\\n\#include <wolfssl/openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testwssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -o testwssl testwssl.o -lwolfssl 2>/dev/null && rm testwssl testwssl.o && echo true||echo false)
|
||||||
ifeq ($(WOLFSSL_CHECK), true)
|
ifeq ($(WOLFSSL_CHECK), true)
|
||||||
|
|||||||
@ -18,7 +18,7 @@ SSL_LIBS = wolfssl.lib
|
|||||||
SSL_DEFS = /D "WITH_SSL"
|
SSL_DEFS = /D "WITH_SSL"
|
||||||
SSL_LIBS = libcrypto.lib libssl.lib
|
SSL_LIBS = libcrypto.lib libssl.lib
|
||||||
!ENDIF
|
!ENDIF
|
||||||
CFLAGS = /D "WITH_HTTPSRV" /nologo /MT /W3 /Ox /GS /EHs- /GA /GF /D "MSVC" /D "WITH_WSAPOLL" /D "NDEBUG" /D "WIN32" $(SSL_DEFS) /D "WITH_PCRE" /D "WITH_ODBC" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "NO_SHARE_UDP_SOCKET" /Fp"proxy.pch" /FD /c $(BUILDDATE) $(VERSION)
|
CFLAGS = /D "WITH_HTTPSRV" /nologo /MT /W3 /Ox /GS /EHs- /GA /GF /D "MSVC" /D "WITH_WSAPOLL" /D "NDEBUG" /D "WIN32" $(SSL_DEFS) /D "WITH_PCRE" /D "WITH_ODBC" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /Fp"proxy.pch" /FD /c $(BUILDDATE) $(VERSION)
|
||||||
COUT = /Fo
|
COUT = /Fo
|
||||||
LN = link
|
LN = link
|
||||||
LDFLAGS = /nologo /subsystem:console /incremental:no
|
LDFLAGS = /nologo /subsystem:console /incremental:no
|
||||||
|
|||||||
@ -46,13 +46,7 @@ AFTERCLEAN = (find . -type f -name "*.o" -delete && find src/ -type f -name "Mak
|
|||||||
TYPECOMMAND = cat
|
TYPECOMMAND = cat
|
||||||
COMPATLIBS =
|
COMPATLIBS =
|
||||||
MAKEFILE = Makefile.unix
|
MAKEFILE = Makefile.unix
|
||||||
PLUGINS ?= StringsPlugin TrafficPlugin FilePlugin
|
PLUGINS ?= StringsPlugin TrafficPlugin TransparentPlugin FilePlugin
|
||||||
|
|
||||||
# Transparent proxying is not built here: this makefile is for the systems
|
|
||||||
# without a redirection 3proxy can read the original destination from. Where
|
|
||||||
# the platform has one - OpenBSD divert-to is the case that fits - uncomment:
|
|
||||||
#CFLAGS += -DWITH_TRANSPARENT
|
|
||||||
#TRANSPARENT_OBJS = transparent$(OBJSUFFICS)
|
|
||||||
ifeq ($(STATIC), true)
|
ifeq ($(STATIC), true)
|
||||||
LDFLAGS += -static
|
LDFLAGS += -static
|
||||||
CFLAGS += -DNOPLUGINS -DNOSTDRESOLVE -DNOCRYPT
|
CFLAGS += -DNOPLUGINS -DNOSTDRESOLVE -DNOCRYPT
|
||||||
|
|||||||
@ -8,7 +8,7 @@ BUILDDIR = ../bin/
|
|||||||
PREFIX = 3proxy_
|
PREFIX = 3proxy_
|
||||||
CRYPT_PREFIX = 3proxy_
|
CRYPT_PREFIX = 3proxy_
|
||||||
CC = cl
|
CC = cl
|
||||||
CFLAGS = /D "WITH_HTTPSRV" /nologo /Ox /MT /D "NOIPV6" /D "NO_UN" /D "NODEBUG" /D "NORADIUS" /D"WATCOM" /D "NO_SHARE_UDP_SOCKET" /D "MSVC" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "PRId64=\"I64d\"" /D "PRIu64=\"I64u\"" /D "SCNu64=\"I64u\"" /D "SCNx64=\"I64x\"" /D "SCNd64=\"I64d\"" /D "PRIx64=\"I64x\"" /c $(VERSION) $(BUILDDATE)
|
CFLAGS = /D "WITH_HTTPSRV" /nologo /Ox /MT /D "NOIPV6" /D "NO_UN" /D "NODEBUG" /D "NORADIUS" /D"WATCOM" /D "MSVC" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "PRId64=\"I64d\"" /D "PRIu64=\"I64u\"" /D "SCNu64=\"I64u\"" /D "SCNx64=\"I64x\"" /D "SCNd64=\"I64d\"" /D "PRIx64=\"I64x\"" /c $(VERSION) $(BUILDDATE)
|
||||||
COUT = /Fo
|
COUT = /Fo
|
||||||
LN = link
|
LN = link
|
||||||
LDFLAGS = /nologo /subsystem:console /incremental:no
|
LDFLAGS = /nologo /subsystem:console /incremental:no
|
||||||
|
|||||||
@ -11,9 +11,6 @@ CRYPT_PREFIX ?= $(PREFIX)
|
|||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
CFLAGS ?= -O3 -flto
|
CFLAGS ?= -O3 -flto
|
||||||
CFLAGS += -fno-strict-aliasing -c -mthreads -DWITH_WSAPOLL -DWITH_ODBC
|
CFLAGS += -fno-strict-aliasing -c -mthreads -DWITH_WSAPOLL -DWITH_ODBC
|
||||||
# Windows does not take a recv and a send on one socket from two threads,
|
|
||||||
# so a UDP service answers from a socket of its own
|
|
||||||
CFLAGS += -DNO_SHARE_UDP_SOCKET
|
|
||||||
COUT = -o
|
COUT = -o
|
||||||
LN ?= $(CC)
|
LN ?= $(CC)
|
||||||
LDFLAGS ?= -O3 -flto
|
LDFLAGS ?= -O3 -flto
|
||||||
|
|||||||
@ -37,7 +37,6 @@
|
|||||||
<li><a href="#SSLPLUGIN">How to set up TLS/SSL (https proxy, mTLS)</a></li>
|
<li><a href="#SSLPLUGIN">How to set up TLS/SSL (https proxy, mTLS)</a></li>
|
||||||
<li><a href="#CERTIFICATES">How to create CA and certificates for SSL</a></li>
|
<li><a href="#CERTIFICATES">How to create CA and certificates for SSL</a></li>
|
||||||
<li><a href="#PCRE">How to use PCRE filtering (regular expressions)</a></li>
|
<li><a href="#PCRE">How to use PCRE filtering (regular expressions)</a></li>
|
||||||
<li><a href="#TRANSPARENT">How to proxy transparently</a></li>
|
|
||||||
<li><A HREF="#AUTH">How to limit service access</a>
|
<li><A HREF="#AUTH">How to limit service access</a>
|
||||||
<li><A HREF="#USERS">How to create a user list</a>
|
<li><A HREF="#USERS">How to create a user list</a>
|
||||||
<li><A HREF="#ACL">How to limit user access to resources</a>
|
<li><A HREF="#ACL">How to limit user access to resources</a>
|
||||||
@ -982,189 +981,6 @@ openssl pkcs12 -export -out client.p12 -passout pass: \
|
|||||||
openssl verify -x509_strict -CAfile ca.crt server.crt
|
openssl verify -x509_strict -CAfile ca.crt server.crt
|
||||||
openssl verify -x509_strict -CAfile ca.crt client.crt
|
openssl verify -x509_strict -CAfile ca.crt client.crt
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<li><a name="TRANSPARENT"><i>How to proxy transparently</i></a>
|
|
||||||
<p>
|
|
||||||
A transparent proxy serves clients that were never configured to use one. A
|
|
||||||
packet filter redirects their connections to 3proxy, and the
|
|
||||||
<b>transparent</b> command tells the service to take the destination from the
|
|
||||||
filter instead of from the request. Every other feature applies as usual:
|
|
||||||
access rules, parent proxies, limits and logging all see the real destination.
|
|
||||||
It works on Linux and on the BSDs. Since 1.0.1 it is part of the binary; before
|
|
||||||
that it was the separate TransparentPlugin, and the <b>plugin</b> line it
|
|
||||||
needed is no longer required.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
The command supplies both the address and the port the client was trying to
|
|
||||||
reach, so a service can serve whatever was redirected to it rather than one
|
|
||||||
port with one target.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Without it a service has to get a destination from somewhere else: an HTTP
|
|
||||||
proxy falls back to the <b>Host</b> header, and a port mapper uses the address
|
|
||||||
it was configured with. Taking the destination from the filter is what makes
|
|
||||||
the other protocols work, and what makes the address authoritative rather than
|
|
||||||
something the client claimed.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<b>tlspr</b> is the clearest case. Nothing reaches it at all unless traffic is
|
|
||||||
redirected to it, or the clients resolve the names to it through DNS. With a
|
|
||||||
redirection it gets the address as well as the name from the handshake, and
|
|
||||||
that is what lets access rules be written with host names: the name from the
|
|
||||||
handshake is matched, and the connection still goes to the address the client
|
|
||||||
was going to. Without the address it would have to resolve the name itself,
|
|
||||||
which is a second lookup and a second answer.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
A configuration for web and TLS traffic:
|
|
||||||
</p><pre>
|
|
||||||
log /var/log/3proxy.log D
|
|
||||||
auth iponly
|
|
||||||
allow *
|
|
||||||
|
|
||||||
# the destination comes from the redirection for the services below
|
|
||||||
transparent
|
|
||||||
|
|
||||||
# ordinary web traffic, redirected here from port 80
|
|
||||||
proxy -p3129 -e192.0.2.10
|
|
||||||
|
|
||||||
# TLS, redirected here from port 443: tlspr would otherwise have only the
|
|
||||||
# name in the handshake, and this gives it the address as well
|
|
||||||
tlspr -p3143 -e192.0.2.10
|
|
||||||
|
|
||||||
notransparent
|
|
||||||
</pre>
|
|
||||||
<p>
|
|
||||||
<b>-e</b> gives those services an address of their own to connect from. That
|
|
||||||
address is what the redirection rules exclude, and excluding it is what stops
|
|
||||||
the proxy's own connections from being redirected back into it. Without an
|
|
||||||
exclusion the connection 3proxy makes to the origin matches the same rule,
|
|
||||||
returns to 3proxy, and the traffic goes round until something gives out.
|
|
||||||
Running 3proxy as its own account and excluding that account works too, and is
|
|
||||||
the better choice when the machine has one address.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><b>Linux, iptables</b>. For traffic the machine forwards for others:
|
|
||||||
</p><pre>
|
|
||||||
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-ports 3129
|
|
||||||
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-ports 3143
|
|
||||||
</pre>
|
|
||||||
<p>
|
|
||||||
Traffic the machine generates itself passes through OUTPUT instead, where the
|
|
||||||
proxy's own connections have to be excluded:
|
|
||||||
</p><pre>
|
|
||||||
# by the address the services connect from
|
|
||||||
iptables -t nat -A OUTPUT -p tcp --dport 80 ! -s 192.0.2.10 -j REDIRECT --to-ports 3129
|
|
||||||
|
|
||||||
# or by the account 3proxy runs as
|
|
||||||
iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner ! --uid-owner proxy3 \
|
|
||||||
-j REDIRECT --to-ports 3129
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Linux, nftables</b> (Debian 11+, Ubuntu 22.04+, RHEL 8+, Fedora, Arch,
|
|
||||||
where nftables is what iptables is a front end for):
|
|
||||||
</p><pre>
|
|
||||||
table ip proxy3 {
|
|
||||||
chain prerouting {
|
|
||||||
type nat hook prerouting priority dstnat; policy accept;
|
|
||||||
iif "eth0" tcp dport 80 redirect to :3129
|
|
||||||
iif "eth0" tcp dport 443 redirect to :3143
|
|
||||||
}
|
|
||||||
|
|
||||||
chain output {
|
|
||||||
type nat hook output priority dstnat; policy accept;
|
|
||||||
meta skuid != "proxy3" tcp dport 80 redirect to :3129
|
|
||||||
meta skuid != "proxy3" tcp dport 443 redirect to :3143
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
<p>
|
|
||||||
Load it with <b>nft -f</b>, and keep it across reboots in
|
|
||||||
<b>/etc/nftables.conf</b> (Debian, Ubuntu) or
|
|
||||||
<b>/etc/sysconfig/nftables.conf</b> (RHEL, Fedora). A table name cannot begin
|
|
||||||
with a digit, which is why the table above is not called 3proxy.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><b>Linux, firewalld</b> (RHEL, CentOS Stream, Fedora, openSUSE). Redirect an
|
|
||||||
incoming port on a zone:
|
|
||||||
</p><pre>
|
|
||||||
firewall-cmd --permanent --zone=internal --add-forward-port=port=80:proto=tcp:toport=3129
|
|
||||||
firewall-cmd --permanent --zone=internal --add-forward-port=port=443:proto=tcp:toport=3143
|
|
||||||
firewall-cmd --reload
|
|
||||||
</pre>
|
|
||||||
<p>
|
|
||||||
firewalld has no exclusion for the proxy's own traffic in that form, so put
|
|
||||||
that part in a direct rule:
|
|
||||||
</p><pre>
|
|
||||||
firewall-cmd --permanent --direct --add-rule ipv4 nat OUTPUT 0 \
|
|
||||||
-p tcp --dport 80 -m owner ! --uid-owner proxy3 -j REDIRECT --to-ports 3129
|
|
||||||
firewall-cmd --reload
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Linux, ufw</b> (Ubuntu, Debian). ufw has no command for redirection;
|
|
||||||
add the rules to <b>/etc/ufw/before.rules</b>, above the <b>*filter</b> block:
|
|
||||||
</p><pre>
|
|
||||||
*nat
|
|
||||||
:PREROUTING ACCEPT [0:0]
|
|
||||||
-A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-ports 3129
|
|
||||||
-A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-ports 3143
|
|
||||||
COMMIT
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
On Linux 3proxy asks the kernel where the connection was going. On the BSDs it
|
|
||||||
asks pf, which keeps the original destination in its state table, through
|
|
||||||
<b>/dev/pf</b> - so <b>rdr</b> rules work, and 3proxy has to be able to read
|
|
||||||
that device. Where a redirection leaves the destination on the socket instead,
|
|
||||||
that is used: OpenBSD <b>divert-to</b> and FreeBSD <b>ipfw fwd</b> both do.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
The mechanism is chosen automatically, and <b>transparent</b> takes an
|
|
||||||
argument for the installations that need to pin it: <b>auto</b> (the default),
|
|
||||||
<b>netfilter</b>, <b>pf</b>, or <b>socket</b> for reading it off the socket. A
|
|
||||||
mode the build has no code for is refused, so a configuration written for
|
|
||||||
another platform fails where it is wrong instead of quietly doing something
|
|
||||||
else.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><b>FreeBSD, NetBSD and OpenBSD, pf</b>. Redirect in <b>/etc/pf.conf</b>,
|
|
||||||
excluding the address the proxy connects from:
|
|
||||||
</p><pre>
|
|
||||||
rdr pass on em0 inet proto tcp from ! 192.0.2.10 to any port 80 -> 127.0.0.1 port 3129
|
|
||||||
rdr pass on em0 inet proto tcp from ! 192.0.2.10 to any port 443 -> 127.0.0.1 port 3143
|
|
||||||
</pre>
|
|
||||||
<p>
|
|
||||||
Load with <b>pfctl -f /etc/pf.conf</b>. 3proxy looks the destination up in pf's
|
|
||||||
state table, so it needs to read <b>/dev/pf</b>: either run it as root, or give
|
|
||||||
its account access to that device.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><b>OpenBSD, divert-to</b> is an alternative which leaves the destination on
|
|
||||||
the socket, and needs no access to <b>/dev/pf</b>:
|
|
||||||
</p><pre>
|
|
||||||
pass in on em0 inet proto tcp to any port 80 divert-to 127.0.0.1 port 3129
|
|
||||||
pass in on em0 inet proto tcp to any port 443 divert-to 127.0.0.1 port 3143
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>FreeBSD, ipfw</b>. <b>fwd</b> delivers the connection locally without
|
|
||||||
rewriting it, which also leaves the destination on the socket:
|
|
||||||
</p><pre>
|
|
||||||
ipfw add fwd 127.0.0.1,3129 tcp from any to any 80 in recv em0
|
|
||||||
ipfw add fwd 127.0.0.1,3143 tcp from any to any 443 in recv em0
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>macOS</b> has <b>/dev/pf</b> but ships no header for it, so a macOS build
|
|
||||||
has no pf lookup, and macOS has neither <b>divert-to</b> nor ipfw to leave the
|
|
||||||
address on the socket. Transparent proxying is not usable there, even though
|
|
||||||
the commands exist in a macOS build.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Check the result by asking for a host through a redirected port and reading
|
|
||||||
the log: the request should appear with the address the client asked for,
|
|
||||||
which is what it would look like through a configured proxy.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<li><a name="PCRE"><i>How to use PCRE filtering (regular expressions)</i></a>
|
<li><a name="PCRE"><i>How to use PCRE filtering (regular expressions)</i></a>
|
||||||
<p>
|
<p>
|
||||||
Since version 0.9.7, PCRE (Perl Compatible Regular Expressions) filtering is built into
|
Since version 0.9.7, PCRE (Perl Compatible Regular Expressions) filtering is built into
|
||||||
|
|||||||
@ -37,7 +37,6 @@
|
|||||||
<li><a href="#SSLPLUGIN">Как настроить TLS/SSL (https прокси, mTLS)</a></li>
|
<li><a href="#SSLPLUGIN">Как настроить TLS/SSL (https прокси, mTLS)</a></li>
|
||||||
<li><a href="#CERTIFICATES">Как создать CA и сертификаты для SSL</a></li>
|
<li><a href="#CERTIFICATES">Как создать CA и сертификаты для SSL</a></li>
|
||||||
<li><a href="#PCRE">Как использовать PCRE-фильтрацию (регулярные выражения)</a></li>
|
<li><a href="#PCRE">Как использовать PCRE-фильтрацию (регулярные выражения)</a></li>
|
||||||
<li><a href="#TRANSPARENT">Как сделать транспарентный прокси</a></li>
|
|
||||||
<li><a href="#AUTH">Как ограничить доступ к службе</a>
|
<li><a href="#AUTH">Как ограничить доступ к службе</a>
|
||||||
<li><a href="#USERS">Как создать список пользователей</a>
|
<li><a href="#USERS">Как создать список пользователей</a>
|
||||||
<li><a href="#ACL">Как ограничить доступ пользователей к ресурсам</a>
|
<li><a href="#ACL">Как ограничить доступ пользователей к ресурсам</a>
|
||||||
@ -993,176 +992,6 @@ openssl verify -x509_strict -CAfile ca.crt server.crt
|
|||||||
openssl verify -x509_strict -CAfile ca.crt client.crt
|
openssl verify -x509_strict -CAfile ca.crt client.crt
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
<li><a name="TRANSPARENT"><i>Как сделать транспарентный прокси</i></a>
|
|
||||||
<p>
|
|
||||||
Транспарентный прокси обслуживает клиентов, которые не настроены на работу
|
|
||||||
через прокси. Пакетный фильтр перенаправляет их соединения на 3proxy, а команда
|
|
||||||
<b>transparent</b> указывает сервису брать адрес назначения у фильтра, а не из
|
|
||||||
запроса. Всё остальное работает как обычно: правила доступа, родительские
|
|
||||||
прокси, ограничения и логирование видят настоящий адрес назначения. Работает в
|
|
||||||
Linux и BSD. С версии 1.0.1 встроено в бинарник, раньше это был отдельный
|
|
||||||
TransparentPlugin, и строка <b>plugin</b> больше не нужна.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Команда даёт и адрес, и порт назначения, поэтому сервис обслуживает всё, что
|
|
||||||
на него перенаправлено, а не один порт с одним адресом назначения.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Без неё сервис берёт адрес откуда-то ещё: HTTP-прокси - из заголовка
|
|
||||||
<b>Host</b>, порт-маппер - из своей конфигурации. Именно получение адреса от
|
|
||||||
фильтра позволяет работать с остальными протоколами и делает адрес
|
|
||||||
достоверным, а не заявленным клиентом.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Нагляднее всего это с <b>tlspr</b>. Без перенаправления трафика (или без
|
|
||||||
резолва имён на него через DNS) на него вообще ничего не попадёт. С
|
|
||||||
перенаправлением он получает и имя из TLS handshake, и адрес назначения -
|
|
||||||
именно это позволяет писать правила доступа по именам хостов: имя из handshake
|
|
||||||
проверяется в ACL, а соединение идёт на тот адрес, куда шёл клиент. Без адреса
|
|
||||||
пришлось бы резолвить имя самостоятельно, то есть делать ещё один запрос и
|
|
||||||
получать ещё один ответ.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Конфигурация для веб- и TLS-трафика:
|
|
||||||
</p><pre>
|
|
||||||
log /var/log/3proxy.log D
|
|
||||||
auth iponly
|
|
||||||
allow *
|
|
||||||
|
|
||||||
# для сервисов ниже адрес назначения берётся из перенаправления
|
|
||||||
transparent
|
|
||||||
|
|
||||||
# обычный веб-трафик, перенаправленный сюда с порта 80
|
|
||||||
proxy -p3129 -e192.0.2.10
|
|
||||||
|
|
||||||
# TLS, перенаправленный сюда с порта 443: без этого у tlspr было бы только
|
|
||||||
# имя из handshake, а так есть и адрес
|
|
||||||
tlspr -p3143 -e192.0.2.10
|
|
||||||
|
|
||||||
notransparent
|
|
||||||
</pre>
|
|
||||||
<p>
|
|
||||||
<b>-e</b> задаёт сервисам собственный адрес для исходящих соединений. Именно
|
|
||||||
этот адрес исключается в правилах перенаправления, и это исключение не даёт
|
|
||||||
соединениям самого прокси попасть обратно в него. Без исключения соединение,
|
|
||||||
которое 3proxy устанавливает к серверу назначения, попадает под то же правило,
|
|
||||||
возвращается в 3proxy, и трафик зацикливается. Можно вместо этого запускать
|
|
||||||
3proxy под отдельной учётной записью и исключать её - так лучше, если у машины
|
|
||||||
один адрес.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><b>Linux, iptables</b>. Для транзитного трафика:
|
|
||||||
</p><pre>
|
|
||||||
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-ports 3129
|
|
||||||
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-ports 3143
|
|
||||||
</pre>
|
|
||||||
<p>
|
|
||||||
Трафик самой машины проходит через цепочку OUTPUT, где соединения прокси нужно
|
|
||||||
исключить:
|
|
||||||
</p><pre>
|
|
||||||
# по адресу, с которого сервисы устанавливают соединения
|
|
||||||
iptables -t nat -A OUTPUT -p tcp --dport 80 ! -s 192.0.2.10 -j REDIRECT --to-ports 3129
|
|
||||||
|
|
||||||
# либо по учётной записи, под которой работает 3proxy
|
|
||||||
iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner ! --uid-owner proxy3 \
|
|
||||||
-j REDIRECT --to-ports 3129
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Linux, nftables</b> (Debian 11+, Ubuntu 22.04+, RHEL 8+, Fedora, Arch):
|
|
||||||
</p><pre>
|
|
||||||
table ip proxy3 {
|
|
||||||
chain prerouting {
|
|
||||||
type nat hook prerouting priority dstnat; policy accept;
|
|
||||||
iif "eth0" tcp dport 80 redirect to :3129
|
|
||||||
iif "eth0" tcp dport 443 redirect to :3143
|
|
||||||
}
|
|
||||||
|
|
||||||
chain output {
|
|
||||||
type nat hook output priority dstnat; policy accept;
|
|
||||||
meta skuid != "proxy3" tcp dport 80 redirect to :3129
|
|
||||||
meta skuid != "proxy3" tcp dport 443 redirect to :3143
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
<p>
|
|
||||||
Загружается через <b>nft -f</b>, сохраняется в <b>/etc/nftables.conf</b>
|
|
||||||
(Debian, Ubuntu) или <b>/etc/sysconfig/nftables.conf</b> (RHEL, Fedora). Имя
|
|
||||||
таблицы не может начинаться с цифры, поэтому таблица называется не 3proxy.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><b>Linux, firewalld</b> (RHEL, CentOS Stream, Fedora, openSUSE):
|
|
||||||
</p><pre>
|
|
||||||
firewall-cmd --permanent --zone=internal --add-forward-port=port=80:proto=tcp:toport=3129
|
|
||||||
firewall-cmd --permanent --zone=internal --add-forward-port=port=443:proto=tcp:toport=3143
|
|
||||||
firewall-cmd --reload
|
|
||||||
</pre>
|
|
||||||
<p>
|
|
||||||
Исключение для трафика самого прокси в таком виде не задаётся, для него нужно
|
|
||||||
прямое правило:
|
|
||||||
</p><pre>
|
|
||||||
firewall-cmd --permanent --direct --add-rule ipv4 nat OUTPUT 0 \
|
|
||||||
-p tcp --dport 80 -m owner ! --uid-owner proxy3 -j REDIRECT --to-ports 3129
|
|
||||||
firewall-cmd --reload
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>Linux, ufw</b> (Ubuntu, Debian). В ufw нет команды для перенаправления,
|
|
||||||
правила добавляются в <b>/etc/ufw/before.rules</b> перед блоком <b>*filter</b>:
|
|
||||||
</p><pre>
|
|
||||||
*nat
|
|
||||||
:PREROUTING ACCEPT [0:0]
|
|
||||||
-A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-ports 3129
|
|
||||||
-A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-ports 3143
|
|
||||||
COMMIT
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
В Linux 3proxy спрашивает у ядра, куда шло соединение. В BSD он спрашивает у pf,
|
|
||||||
который хранит исходный адрес назначения в таблице состояний, через
|
|
||||||
<b>/dev/pf</b> - поэтому работают правила <b>rdr</b>, и 3proxy должен иметь
|
|
||||||
доступ к этому устройству. Если перенаправление оставляет адрес на самом сокете,
|
|
||||||
используется он: так делают OpenBSD <b>divert-to</b> и FreeBSD <b>ipfw fwd</b>.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Механизм выбирается автоматически, а команда <b>transparent</b> принимает
|
|
||||||
аргумент для случаев, когда его надо зафиксировать: <b>auto</b> (по умолчанию),
|
|
||||||
<b>netfilter</b>, <b>pf</b> или <b>socket</b> для чтения адреса с сокета. Режим,
|
|
||||||
которого нет в сборке, отвергается, поэтому конфигурация, написанная для другой
|
|
||||||
платформы, не запустится вместо того, чтобы молча делать что-то другое.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><b>FreeBSD, NetBSD, OpenBSD, pf</b>. Перенаправление в <b>/etc/pf.conf</b> с
|
|
||||||
исключением адреса, с которого соединяется прокси:
|
|
||||||
</p><pre>
|
|
||||||
rdr pass on em0 inet proto tcp from ! 192.0.2.10 to any port 80 -> 127.0.0.1 port 3129
|
|
||||||
rdr pass on em0 inet proto tcp from ! 192.0.2.10 to any port 443 -> 127.0.0.1 port 3143
|
|
||||||
</pre>
|
|
||||||
<p>
|
|
||||||
Загружается через <b>pfctl -f /etc/pf.conf</b>. 3proxy ищет адрес назначения в
|
|
||||||
таблице состояний pf, поэтому ему нужен доступ на чтение к <b>/dev/pf</b>: либо
|
|
||||||
запуск от root, либо права на устройство для его учётной записи.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><b>OpenBSD, divert-to</b> - альтернатива, оставляющая адрес на сокете, доступ
|
|
||||||
к <b>/dev/pf</b> при этом не нужен:
|
|
||||||
</p><pre>
|
|
||||||
pass in on em0 inet proto tcp to any port 80 divert-to 127.0.0.1 port 3129
|
|
||||||
pass in on em0 inet proto tcp to any port 443 divert-to 127.0.0.1 port 3143
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>FreeBSD, ipfw</b>. <b>fwd</b> доставляет соединение локально, не переписывая
|
|
||||||
его, и адрес тоже остаётся на сокете:
|
|
||||||
</p><pre>
|
|
||||||
ipfw add fwd 127.0.0.1,3129 tcp from any to any 80 in recv em0
|
|
||||||
ipfw add fwd 127.0.0.1,3143 tcp from any to any 443 in recv em0
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><b>macOS</b>: <b>/dev/pf</b> есть, но заголовочных файлов для него нет,
|
|
||||||
поэтому в сборке под macOS нет обращения к pf, а ни <b>divert-to</b>, ни ipfw в
|
|
||||||
macOS нет. Транспарентное проксирование там неприменимо, хотя команды в сборке
|
|
||||||
присутствуют.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<li><a name="PCRE"><i>Как использовать PCRE-фильтрацию (регулярные выражения)</i></a>
|
<li><a name="PCRE"><i>Как использовать PCRE-фильтрацию (регулярные выражения)</i></a>
|
||||||
<p>
|
<p>
|
||||||
Начиная с версии 0.9.7 фильтрация PCRE встроена в 3proxy при компиляции с поддержкой
|
Начиная с версии 0.9.7 фильтрация PCRE встроена в 3proxy при компиляции с поддержкой
|
||||||
|
|||||||
@ -1115,57 +1115,6 @@ users "test4:CR:$3$salt$G47yV9w...." <br>
|
|||||||
Note: double quotes are required because the password
|
Note: double quotes are required because the password
|
||||||
contains a $ sign.</p>
|
contains a $ sign.</p>
|
||||||
|
|
||||||
|
|
||||||
<p style="margin-left:9%; margin-top: 1em"><b>transparent</b>
|
|
||||||
<i>[auto|netfilter|pf|socket]</i> <br>
|
|
||||||
Take the destination of a connection, both address and port,
|
|
||||||
from the packet filter that redirected it, instead of from
|
|
||||||
the request. It applies to services declared after it, and
|
|
||||||
<b>notransparent</b> turns it off again for the services
|
|
||||||
after that. Built into the binary since 1.0.1, and
|
|
||||||
previously the separate TransparentPlugin. <br>
|
|
||||||
On Linux the kernel is asked, so <b>iptables</b> or
|
|
||||||
<b>nftables</b> redirection is enough. On the BSDs pf is
|
|
||||||
asked through <b>/dev/pf</b>, which 3proxy must be able to
|
|
||||||
read, so <b>rdr</b> rules work; a redirection that leaves
|
|
||||||
the destination on the socket is used where there is one, as
|
|
||||||
<b>divert-to</b> on OpenBSD and <b>ipfw fwd</b> on FreeBSD
|
|
||||||
do. macOS ships no header for pf and has neither of those,
|
|
||||||
so the commands exist in a macOS build but cannot be used.
|
|
||||||
<br>
|
|
||||||
The mechanism is chosen automatically. The optional argument
|
|
||||||
pins it for an installation that has more than one:
|
|
||||||
<b>auto</b> is the default, <b>netfilter</b> asks the Linux
|
|
||||||
kernel, <b>pf</b> looks the connection up in the packet
|
|
||||||
filter, and <b>socket</b> reads the address off the socket.
|
|
||||||
A mode the build has no code for is refused rather than
|
|
||||||
ignored. <br>
|
|
||||||
A connection that reaches a <b>socket</b> mode service
|
|
||||||
without having been redirected is refused: its destination
|
|
||||||
is the address the service listens on, and using that would
|
|
||||||
send the service to itself. <br>
|
|
||||||
A redirected connection carries no destination of its own,
|
|
||||||
so without this the service uses whatever it would use
|
|
||||||
otherwise: the <b>Host</b> header for an HTTP request, or
|
|
||||||
the address a port mapper was configured with. <b>tlspr</b>
|
|
||||||
receives nothing at all unless traffic is redirected to it
|
|
||||||
or the clients resolve names to it, and with a redirection
|
|
||||||
it has the address as well as the name from the handshake,
|
|
||||||
which is what allows access rules to be written with host
|
|
||||||
names. With it, every service reaches the address the client
|
|
||||||
was trying to reach, and access rules, parents, limits and
|
|
||||||
logging apply to it as usual. <br>
|
|
||||||
The redirection rules must not match the connections the
|
|
||||||
proxy itself makes to those destinations, or the traffic
|
|
||||||
returns to the proxy and loops. Give the service an outgoing
|
|
||||||
address with <b>-e</b> and exclude that address in the
|
|
||||||
rules, or run 3proxy as its own user and exclude that user.
|
|
||||||
See the <b>TRANSPARENT PROXYING</b> section of the
|
|
||||||
documentation for rules per platform. <b><br>
|
|
||||||
notransparent</b> <br>
|
|
||||||
Stop taking the destination from the packet filter for the
|
|
||||||
services declared after it.</p>
|
|
||||||
|
|
||||||
<p style="margin-left:9%; margin-top: 1em"><b>flush</b>
|
<p style="margin-left:9%; margin-top: 1em"><b>flush</b>
|
||||||
<br>
|
<br>
|
||||||
empty the active access list. The access list must be
|
empty the active access list. The access list must be
|
||||||
|
|||||||
@ -1,56 +1,31 @@
|
|||||||
<h3>3proxy transparent proxying (Linux/BSD only)</h3>
|
<h3>3proxy TransparentPlugin (Linux/BSD only)</h3>
|
||||||
|
|
||||||
Transparent proxying is part of 3proxy itself since 1.0.1. It was the separate
|
This plugin can turn 3proxy into a transparent proxy for virtually any TCP-based protocol
|
||||||
TransparentPlugin before that, and the <b>plugin</b> line that used to load it
|
and use all 3proxy features - redirections, parent proxies, ACLs, traffic limitations,
|
||||||
is no longer needed: the <b>transparent</b> and <b>notransparent</b> commands
|
etc. The TransparentPlugin takes the destination IP:port from Linux and uses this
|
||||||
are always available on the platforms that can redirect a connection.
|
information as the target IP in the proxy. An example usage:
|
||||||
|
|
||||||
<p>
|
|
||||||
It turns 3proxy into a transparent proxy for virtually any TCP-based protocol,
|
|
||||||
with the rest of 3proxy applying as usual - redirections, parent proxies, ACLs,
|
|
||||||
traffic limitations and logging. The destination IP and port come from the
|
|
||||||
packet filter that redirected the connection, and are used as the target of the
|
|
||||||
proxied connection.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
|
plugin /path/to/TransparentPlugin.ld.so transparent_plugin
|
||||||
log /path/to/log
|
log /path/to/log
|
||||||
auth iponly
|
auth iponly
|
||||||
allow * * * 80
|
allow * * * 80
|
||||||
parent 1000 http 0.0.0.0 0
|
parent 1000 http 0.0.0.0 0
|
||||||
allow *
|
allow *
|
||||||
parent 1000 socks5 SOCKS5_IP SOCKS5_PORT USER PASSWORD
|
parent 1000 socks5 SOCKS5_IP SOCKS5_PORT USER PASSWORD
|
||||||
|
|
||||||
transparent
|
transparent
|
||||||
tcppm -eLOCAL_IP 12345 127.0.0.1 11111
|
tcppm -iLOCAL_IP 12345 127.0.0.1 11111
|
||||||
notransparent
|
notransparent
|
||||||
proxy
|
proxy
|
||||||
</pre>
|
</pre>
|
||||||
|
Now, any TCP traffic transparently redirected to port 12345 will be routed via
|
||||||
|
the parent SOCKSv5 proxy and logged; all URLs for web requests are visible in logs.
|
||||||
|
The parameters '127.0.0.1 11111' in this case are not used and are overwritten by
|
||||||
|
the destination IP:port for each transparent connection.
|
||||||
|
|
||||||
<p>
|
<h4>Download:</h4>
|
||||||
Any TCP traffic redirected to port 12345 is routed through the parent SOCKSv5
|
<ul>
|
||||||
proxy and logged, with the URLs of web requests visible in the log. The
|
<li>Plugin is included in 3proxy 0.8
|
||||||
'127.0.0.1 11111' arguments are not used in that case: they are replaced by the
|
</li></ul>
|
||||||
destination the client was trying to reach.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The destination is looked up in pf on the BSDs, through <b>/dev/pf</b>, and
|
|
||||||
asked of the kernel on Linux; a redirection that leaves the address on the
|
|
||||||
socket is used where there is one. <b>transparent</b> takes an optional
|
|
||||||
<b>auto</b>, <b>netfilter</b>, <b>pf</b> or <b>socket</b> to pin that choice.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
The redirection rules must not match the connections 3proxy itself makes, or
|
|
||||||
the traffic returns to the proxy and loops. Give the service an address to
|
|
||||||
connect from with <b>-e</b> and exclude it in the rules, or run 3proxy as its
|
|
||||||
own account and exclude that account.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Redirection rules for iptables, nftables, firewalld, ufw and pf are in
|
|
||||||
<a href="../howtoe.html#TRANSPARENT">How to proxy transparently</a>, and the
|
|
||||||
commands are described in 3proxy.cfg(5).
|
|
||||||
</p>
|
|
||||||
|
|
||||||
© Vladimir Dubrovin, License: BSD style
|
© Vladimir Dubrovin, License: BSD style
|
||||||
|
|||||||
@ -1,56 +1,33 @@
|
|||||||
<h3>Транспарентное проксирование 3proxy (только для Linux/BSD)</h3>
|
<h3>Плагин TransparentPlugin 3proxy (только для Linux/BSD)</h3>
|
||||||
|
|
||||||
Начиная с 1.0.1 транспарентное проксирование встроено в 3proxy. Раньше это был
|
Плагин превращает 3proxy в транспарентный прокси для практически любых TCP-соединений
|
||||||
отдельный TransparentPlugin, и строка <b>plugin</b>, которой он загружался,
|
и позволяет прозрачно для клиентов использовать весь фунционал прокси - редиректоры,
|
||||||
больше не нужна: команды <b>transparent</b> и <b>notransparent</b> доступны
|
родительские прокси, ACLи, ограничения трафика. TransparentPlugin получает IP:port
|
||||||
всегда на тех платформах, где соединение можно перенаправить.
|
назначения от Linux и использует эту информацию в качестве конечного адреса назначения.
|
||||||
|
<br>
|
||||||
<p>
|
Пример использования:
|
||||||
3proxy становится транспарентным прокси практически для любых TCP-соединений,
|
|
||||||
причём весь остальной функционал работает как обычно - редиректоры,
|
|
||||||
родительские прокси, ACLи, ограничения трафика и логирование. IP и порт
|
|
||||||
назначения берутся у пакетного фильтра, перенаправившего соединение, и
|
|
||||||
используются как адрес назначения проксируемого соединения.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
|
plugin /path/to/TransparentPlugin.ld.so transparent_plugin
|
||||||
log /path/to/log
|
log /path/to/log
|
||||||
auth iponly
|
auth iponly
|
||||||
allow * * * 80
|
allow * * * 80
|
||||||
parent 1000 http 0.0.0.0 0
|
parent 1000 http 0.0.0.0 0
|
||||||
allow *
|
allow *
|
||||||
parent 1000 socks5 SOCKS5_IP SOCKS5_PORT USER PASSWORD
|
parent 1000 socks5 SOCKS5_IP SOCKS5_PORT USER PASSWORD
|
||||||
|
|
||||||
transparent
|
transparent
|
||||||
tcppm -eLOCAL_IP 12345 127.0.0.1 11111
|
tcppm -iLOCAL_IP 12345 127.0.0.1 11111
|
||||||
notransparent
|
notransparent
|
||||||
proxy
|
proxy
|
||||||
</pre>
|
</pre>
|
||||||
|
Теперь любые TCP-соединения транспарентно перенаправленные в локальный порт 12345
|
||||||
<p>
|
будут прологгированы и перенаправлены в родительский SOCKSv5 proxy, при этом для
|
||||||
Любой TCP-трафик, перенаправленный на порт 12345, пойдёт через родительский
|
HTTP-запросов по порту TCP/80 будут видны параметры HTTP-запроса.
|
||||||
SOCKSv5 прокси и будет залогирован, URL веб-запросов видны в логе. Аргументы
|
Параметры '127.0.0.1 11111' в данном случае не оказывают влияния, т.к.
|
||||||
'127.0.0.1 11111' в этом случае не используются: они заменяются адресом, к
|
будут перезаписываться IP и портом назначения для каждого TCP-соединения соответственно.
|
||||||
которому обращался клиент.
|
<h4>Загрузить:</h4>
|
||||||
</p>
|
<ul>
|
||||||
|
<li>Плагин включен в дистрибутив 3proxy 0.8
|
||||||
<p>
|
</li></ul>
|
||||||
В BSD адрес назначения ищется в pf через <b>/dev/pf</b>, в Linux запрашивается у
|
|
||||||
ядра; если перенаправление оставляет адрес на сокете, используется он. Команда
|
|
||||||
<b>transparent</b> принимает необязательный аргумент <b>auto</b>,
|
|
||||||
<b>netfilter</b>, <b>pf</b> или <b>socket</b>, чтобы зафиксировать выбор.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Правила перенаправления не должны попадать на соединения, которые устанавливает
|
|
||||||
сам 3proxy, иначе трафик возвращается в прокси и зацикливается. Задайте сервису
|
|
||||||
адрес для исходящих соединений через <b>-e</b> и исключите его в правилах, либо
|
|
||||||
запускайте 3proxy под отдельной учётной записью и исключайте её.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Правила перенаправления для iptables, nftables, firewalld, ufw и pf приведены в
|
|
||||||
<a href="../howtor.html#TRANSPARENT">описании транспарентного проксирования</a>,
|
|
||||||
команды описаны в 3proxy.cfg(5).
|
|
||||||
</p>
|
|
||||||
|
|
||||||
© Vladimir Dubrovin, License: BSD style
|
© Vladimir Dubrovin, License: BSD style
|
||||||
|
|||||||
@ -1192,54 +1192,6 @@ the format:
|
|||||||
Note: double quotes are required because the password contains a $ sign.
|
Note: double quotes are required because the password contains a $ sign.
|
||||||
|
|
||||||
.br
|
.br
|
||||||
.BR transparent
|
|
||||||
\fI[auto|netfilter|pf|socket]\fR
|
|
||||||
.br
|
|
||||||
Take the destination of a connection, both address and port, from the packet
|
|
||||||
filter that redirected it, instead of from the request. It applies to services declared after it, and
|
|
||||||
\fBnotransparent\fR turns it off again for the services after that. Built into the
|
|
||||||
binary since 1.0.1, and previously the separate TransparentPlugin.
|
|
||||||
.br
|
|
||||||
On Linux the kernel is asked, so \fBiptables\fR or \fBnftables\fR
|
|
||||||
redirection is enough. On the BSDs pf is asked through \fB/dev/pf\fR, which
|
|
||||||
3proxy must be able to read, so \fBrdr\fR rules work; a redirection that
|
|
||||||
leaves the destination on the socket is used where there is one, as
|
|
||||||
\fBdivert-to\fR on OpenBSD and \fBipfw fwd\fR on FreeBSD do. macOS ships no
|
|
||||||
header for pf and has neither of those, so the commands exist in a macOS build
|
|
||||||
but cannot be used.
|
|
||||||
.br
|
|
||||||
The mechanism is chosen automatically. The optional argument pins it for an
|
|
||||||
installation that has more than one: \fBauto\fR is the default,
|
|
||||||
\fBnetfilter\fR asks the Linux kernel, \fBpf\fR looks the connection up in
|
|
||||||
the packet filter, and \fBsocket\fR reads the address off the socket. A mode
|
|
||||||
the build has no code for is refused rather than ignored.
|
|
||||||
.br
|
|
||||||
A connection that reaches a \fBsocket\fR mode service without having been
|
|
||||||
redirected is refused: its destination is the address the service listens on,
|
|
||||||
and using that would send the service to itself.
|
|
||||||
.br
|
|
||||||
A redirected connection carries no destination of its own, so without this the
|
|
||||||
service uses whatever it would use otherwise: the \fBHost\fR header for an
|
|
||||||
HTTP request, or the address a port mapper was configured with. \fBtlspr\fR
|
|
||||||
receives nothing at all unless traffic is redirected to it or the clients
|
|
||||||
resolve names to it, and with a redirection it has the address as well as the
|
|
||||||
name from the handshake, which is what allows access rules to be written with
|
|
||||||
host names. With it, every service reaches the address the
|
|
||||||
client was trying to reach, and access rules, parents, limits and logging apply
|
|
||||||
to it as usual.
|
|
||||||
.br
|
|
||||||
The redirection rules must not match the connections the proxy itself makes to
|
|
||||||
those destinations, or the traffic returns to the proxy and loops. Give the
|
|
||||||
service an outgoing address with \fB-e\fR and exclude that address in the rules,
|
|
||||||
or run 3proxy as its own user and exclude that user. See the
|
|
||||||
.B TRANSPARENT PROXYING
|
|
||||||
section of the documentation for rules per platform.
|
|
||||||
.br
|
|
||||||
.BR notransparent
|
|
||||||
.br
|
|
||||||
Stop taking the destination from the packet filter for the services declared
|
|
||||||
after it.
|
|
||||||
|
|
||||||
.B flush
|
.B flush
|
||||||
.br
|
.br
|
||||||
empty the active access list. The access list must be flushed every time you create a
|
empty the active access list. The access list must be flushed every time you create a
|
||||||
|
|||||||
@ -13,9 +13,6 @@ void ssl_install(void);
|
|||||||
#ifdef WITH_PCRE
|
#ifdef WITH_PCRE
|
||||||
void pcre_install(void);
|
void pcre_install(void);
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITH_TRANSPARENT
|
|
||||||
void transparent_install(void);
|
|
||||||
#endif
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#ifndef NOPLUGINS
|
#ifndef NOPLUGINS
|
||||||
@ -532,9 +529,6 @@ int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int
|
|||||||
#ifdef WITH_PCRE
|
#ifdef WITH_PCRE
|
||||||
pcre_install();
|
pcre_install();
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITH_TRANSPARENT
|
|
||||||
transparent_install();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
freeconf(&conf);
|
freeconf(&conf);
|
||||||
initcommands();
|
initcommands();
|
||||||
|
|||||||
@ -116,9 +116,6 @@ srvsocks$(OBJSUFFICS): socks.c proxy.h structures.h
|
|||||||
srvwebadmin$(OBJSUFFICS): webadmin.c proxy.h structures.h
|
srvwebadmin$(OBJSUFFICS): webadmin.c proxy.h structures.h
|
||||||
$(CC) $(COUT)srvwebadmin$(OBJSUFFICS) $(CFLAGS) webadmin.c
|
$(CC) $(COUT)srvwebadmin$(OBJSUFFICS) $(CFLAGS) webadmin.c
|
||||||
|
|
||||||
transparent$(OBJSUFFICS): transparent.c proxy.h structures.h
|
|
||||||
$(CC) $(COUT)transparent$(OBJSUFFICS) $(CFLAGS) transparent.c
|
|
||||||
|
|
||||||
srvhttpsrv$(OBJSUFFICS): httpsrv.c proxy.h structures.h
|
srvhttpsrv$(OBJSUFFICS): httpsrv.c proxy.h structures.h
|
||||||
$(CC) $(COUT)srvhttpsrv$(OBJSUFFICS) $(CFLAGS) httpsrv.c
|
$(CC) $(COUT)srvhttpsrv$(OBJSUFFICS) $(CFLAGS) httpsrv.c
|
||||||
|
|
||||||
@ -194,6 +191,6 @@ ssl$(OBJSUFFICS): ssl.c structures.h proxy.h ssl.h
|
|||||||
pcre$(OBJSUFFICS): pcre.c structures.h
|
pcre$(OBJSUFFICS): pcre.c structures.h
|
||||||
$(CC) $(COUT)pcre$(OBJSUFFICS) $(CFLAGS) $(DEFINEOPTION)WITH_PCRE pcre.c
|
$(CC) $(COUT)pcre$(OBJSUFFICS) $(CFLAGS) $(DEFINEOPTION)WITH_PCRE pcre.c
|
||||||
|
|
||||||
$(BUILDDIR)3proxy$(EXESUFFICS): 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvimapp$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) auth$(OBJSUFFICS) acl$(OBJSUFFICS) limiter$(OBJSUFFICS) redirect$(OBJSUFFICS) authradius$(OBJSUFFICS) hash$(OBJSUFFICS) hashtables$(OBJSUFFICS) resolve$(OBJSUFFICS) sql$(OBJSUFFICS) conf$(OBJSUFFICS) log$(OBJSUFFICS) datatypes$(OBJSUFFICS) md4$(OBJSUFFICS) md5$(OBJSUFFICS) blake2$(OBJSUFFICS) 3proxy_crypt$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) $(HTTPSRV_OBJS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) mdhash$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(TRANSPARENT_OBJS) $(COMPATLIBS) $(VERSIONDEP)
|
$(BUILDDIR)3proxy$(EXESUFFICS): 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvimapp$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) auth$(OBJSUFFICS) acl$(OBJSUFFICS) limiter$(OBJSUFFICS) redirect$(OBJSUFFICS) authradius$(OBJSUFFICS) hash$(OBJSUFFICS) hashtables$(OBJSUFFICS) resolve$(OBJSUFFICS) sql$(OBJSUFFICS) conf$(OBJSUFFICS) log$(OBJSUFFICS) datatypes$(OBJSUFFICS) md4$(OBJSUFFICS) md5$(OBJSUFFICS) blake2$(OBJSUFFICS) 3proxy_crypt$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) $(HTTPSRV_OBJS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) mdhash$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(COMPATLIBS) $(VERSIONDEP)
|
||||||
$(LN) $(LNOUT)$(BUILDDIR)3proxy$(EXESUFFICS) $(LDFLAGS) $(VERFILE) 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) auth$(OBJSUFFICS) acl$(OBJSUFFICS) limiter$(OBJSUFFICS) redirect$(OBJSUFFICS) authradius$(OBJSUFFICS) hash$(OBJSUFFICS) hashtables$(OBJSUFFICS) resolve$(OBJSUFFICS) sql$(OBJSUFFICS) conf$(OBJSUFFICS) datatypes$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvimapp$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) 3proxy_crypt$(OBJSUFFICS) md4$(OBJSUFFICS) md5$(OBJSUFFICS) blake2$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) $(HTTPSRV_OBJS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) mdhash$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(TRANSPARENT_OBJS) $(COMPATLIBS) $(LIBS) $(PCRE_LIBS)
|
$(LN) $(LNOUT)$(BUILDDIR)3proxy$(EXESUFFICS) $(LDFLAGS) $(VERFILE) 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) auth$(OBJSUFFICS) acl$(OBJSUFFICS) limiter$(OBJSUFFICS) redirect$(OBJSUFFICS) authradius$(OBJSUFFICS) hash$(OBJSUFFICS) hashtables$(OBJSUFFICS) resolve$(OBJSUFFICS) sql$(OBJSUFFICS) conf$(OBJSUFFICS) datatypes$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvimapp$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) 3proxy_crypt$(OBJSUFFICS) md4$(OBJSUFFICS) md5$(OBJSUFFICS) blake2$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) $(HTTPSRV_OBJS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) mdhash$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(COMPATLIBS) $(LIBS) $(PCRE_LIBS)
|
||||||
|
|
||||||
|
|||||||
19
src/conf.c
19
src/conf.c
@ -18,9 +18,6 @@ void ssl_install(void);
|
|||||||
#ifdef WITH_PCRE
|
#ifdef WITH_PCRE
|
||||||
void pcre_install(void);
|
void pcre_install(void);
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITH_TRANSPARENT
|
|
||||||
void transparent_install(void);
|
|
||||||
#endif
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
@ -1624,11 +1621,6 @@ static int h_plugin(int argc, unsigned char **argv){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITH_TRANSPARENT
|
|
||||||
if(argc >= 3 && !strcmp((char *)argv[2], "transparent_plugin")){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef NOPLUGINS
|
#ifdef NOPLUGINS
|
||||||
return 999;
|
return 999;
|
||||||
#else
|
#else
|
||||||
@ -1801,10 +1793,6 @@ int h_server_verify(int argc, unsigned char **argv);
|
|||||||
int h_no_server_verify(int argc, unsigned char **argv);
|
int h_no_server_verify(int argc, unsigned char **argv);
|
||||||
int h_client_mode(int argc, unsigned char **argv);
|
int h_client_mode(int argc, unsigned char **argv);
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITH_TRANSPARENT
|
|
||||||
int h_transparent(int argc, unsigned char **argv);
|
|
||||||
int h_notransparent(int argc, unsigned char **argv);
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_PCRE
|
#ifdef WITH_PCRE
|
||||||
int h_pcre(int argc, unsigned char **argv);
|
int h_pcre(int argc, unsigned char **argv);
|
||||||
int h_pcre_rewrite(int argc, unsigned char **argv);
|
int h_pcre_rewrite(int argc, unsigned char **argv);
|
||||||
@ -1934,10 +1922,6 @@ struct commands commandhandlers[]={
|
|||||||
{NULL, "ssl_client_mode", h_client_mode, 1, 2},
|
{NULL, "ssl_client_mode", h_client_mode, 1, 2},
|
||||||
{NULL, "ssl_certcache", h_certcache, 2, 2},
|
{NULL, "ssl_certcache", h_certcache, 2, 2},
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITH_TRANSPARENT
|
|
||||||
{NULL, "transparent", h_transparent, 1, 2},
|
|
||||||
{NULL, "notransparent", h_notransparent, 1, 1},
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_PCRE
|
#ifdef WITH_PCRE
|
||||||
{NULL, "pcre", h_pcre, 4, 0},
|
{NULL, "pcre", h_pcre, 4, 0},
|
||||||
{NULL, "pcre_rewrite", h_pcre_rewrite, 5, 0},
|
{NULL, "pcre_rewrite", h_pcre_rewrite, 5, 0},
|
||||||
@ -2228,9 +2212,6 @@ int reload (void){
|
|||||||
#endif
|
#endif
|
||||||
#ifdef WITH_PCRE
|
#ifdef WITH_PCRE
|
||||||
pcre_install();
|
pcre_install();
|
||||||
#endif
|
|
||||||
#ifdef WITH_TRANSPARENT
|
|
||||||
transparent_install();
|
|
||||||
#endif
|
#endif
|
||||||
conf.paused++;
|
conf.paused++;
|
||||||
freeconf(&conf);
|
freeconf(&conf);
|
||||||
|
|||||||
@ -45,7 +45,7 @@ void * dnsprchild(struct clientparam* param) {
|
|||||||
memcpy(buf, param->srv->udpbuf, i);
|
memcpy(buf, param->srv->udpbuf, i);
|
||||||
_3proxy_sem_unlock(udpinit);
|
_3proxy_sem_unlock(udpinit);
|
||||||
semlocked = 0;
|
semlocked = 0;
|
||||||
#if defined(_WIN32) && !defined(SHARE_UDP_SOCKET)
|
#ifdef _WIN32
|
||||||
if((param->clisock=param->srv->so._socket(param->sostate, AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
|
if((param->clisock=param->srv->so._socket(param->sostate, AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
|
||||||
RETURN(818);
|
RETURN(818);
|
||||||
}
|
}
|
||||||
@ -56,8 +56,6 @@ void * dnsprchild(struct clientparam* param) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* The reply has to come from the address the query was sent to, which
|
|
||||||
is the listening socket. */
|
|
||||||
param->clisock = param->srv->srvsock;
|
param->clisock = param->srv->srvsock;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -219,8 +217,7 @@ CLEANRET:
|
|||||||
}
|
}
|
||||||
if(bbuf)free(bbuf);
|
if(bbuf)free(bbuf);
|
||||||
if(host)free(host);
|
if(host)free(host);
|
||||||
#if !defined(_WIN32) || defined(SHARE_UDP_SOCKET)
|
#ifndef _WIN32
|
||||||
/* The socket belongs to the service, so the caller must not close it. */
|
|
||||||
param->clisock = INVALID_SOCKET;
|
param->clisock = INVALID_SOCKET;
|
||||||
#endif
|
#endif
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|||||||
6
src/plugins/TransparentPlugin/CMakeLists.txt
Normal file
6
src/plugins/TransparentPlugin/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# TransparentPlugin
|
||||||
|
# Works on Linux (with netfilter), BSD and macOS (without netfilter support)
|
||||||
|
|
||||||
|
add_3proxy_plugin(TransparentPlugin
|
||||||
|
SOURCES transparent_plugin.c
|
||||||
|
)
|
||||||
1
src/plugins/TransparentPlugin/Makefile
Normal file
1
src/plugins/TransparentPlugin/Makefile
Normal file
@ -0,0 +1 @@
|
|||||||
|
include Makefile.var
|
||||||
10
src/plugins/TransparentPlugin/Makefile.inc
Normal file
10
src/plugins/TransparentPlugin/Makefile.inc
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
all: $(BUILDDIR)TransparentPlugin$(DLSUFFICS)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
transparent_plugin$(OBJSUFFICS): transparent_plugin.c
|
||||||
|
$(CC) $(CFLAGS) $(DCFLAGS) transparent_plugin.c
|
||||||
|
|
||||||
|
|
||||||
|
$(BUILDDIR)TransparentPlugin$(DLSUFFICS): transparent_plugin$(OBJSUFFICS)
|
||||||
|
$(LN) $(LNOUT)../../$(BUILDDIR)TransparentPlugin$(DLSUFFICS) $(LDFLAGS) $(DLFLAGS) transparent_plugin$(OBJSUFFICS)
|
||||||
128
src/plugins/TransparentPlugin/transparent_plugin.c
Normal file
128
src/plugins/TransparentPlugin/transparent_plugin.c
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
3APA3A simplest proxy server
|
||||||
|
(c) 2002-2026 by Vladimir Dubrovin <vlad@3proxy.org>
|
||||||
|
|
||||||
|
please read License Agreement
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WITH_NETFILTER
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#endif
|
||||||
|
#include "../../structures.h"
|
||||||
|
#include "../../proxy.h"
|
||||||
|
#ifdef WITH_NETFILTER
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <linux/netfilter_ipv4.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static struct pluginlink * pl;
|
||||||
|
|
||||||
|
static int transparent_loaded = 0;
|
||||||
|
|
||||||
|
static void* transparent_filter_open(void * idata, struct srvparam * param){
|
||||||
|
return idata;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FILTER_ACTION transparent_filter_client(void *fo, struct clientparam * param, void** fc){
|
||||||
|
|
||||||
|
char addrbuf[64];
|
||||||
|
|
||||||
|
#ifdef WITH_NETFILTER
|
||||||
|
socklen_t len;
|
||||||
|
|
||||||
|
len = sizeof(param->req);
|
||||||
|
#ifdef SO_ORIGINAL_DST
|
||||||
|
|
||||||
|
if(getsockopt(param->clisock,
|
||||||
|
#ifndef NOIPV6
|
||||||
|
#ifdef SOL_IPV6
|
||||||
|
*SAFAMILY(¶m->sincr) == AF_INET6?SOL_IPV6:
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
SOL_IP, SO_ORIGINAL_DST,(struct sockaddr *) ¶m->req, &len) || !memcmp((char *)SAADDR(¶m->req), "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", SAADDRLEN(¶m->req))){
|
||||||
|
return PASS;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error No SO_ORIGINAL_DST defined
|
||||||
|
param->srv->logfunc(param, (unsigned char *)"transparent_plugin: No SO_ORIGINAL_DST defined");
|
||||||
|
return REJECT;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
if(*SAFAMILY(¶m->sincl) == AF_INET || *SAFAMILY(¶m->sincl) == AF_INET6){
|
||||||
|
param->req = param->sincl;
|
||||||
|
param->sincl = param->srv->intsa;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
pl->myinet_ntop(*SAFAMILY(¶m->req), SAADDR(¶m->req), (char *)addrbuf, sizeof(addrbuf));
|
||||||
|
if(param->hostname) pl->freefunc(param->hostname);
|
||||||
|
param->hostname = (unsigned char *)pl->strdupfunc(addrbuf);
|
||||||
|
param->sinsr = param->req;
|
||||||
|
return PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void transparent_filter_clear(void *fo){
|
||||||
|
}
|
||||||
|
|
||||||
|
static void transparent_filter_close(void *fo){
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct filter transparent_filter = {
|
||||||
|
NULL,
|
||||||
|
"Transparent filter",
|
||||||
|
"Transparent filter",
|
||||||
|
transparent_filter_open,
|
||||||
|
transparent_filter_client,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
transparent_filter_clear,
|
||||||
|
transparent_filter_close
|
||||||
|
};
|
||||||
|
|
||||||
|
static int h_transparent(int argc, unsigned char **argv){
|
||||||
|
transparent_filter.filter_open = transparent_filter_open;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int h_notransparent(int argc, unsigned char **argv){
|
||||||
|
transparent_filter.filter_open = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct commands transparent_commandhandlers[] = {
|
||||||
|
{transparent_commandhandlers+1, "transparent", h_transparent, 1, 1},
|
||||||
|
{NULL, "notransparent", h_notransparent, 1, 1}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WATCOM
|
||||||
|
#pragma aux transparent_plugin "*" parm caller [ ] value struct float struct routine [eax] modify [eax ecx edx]
|
||||||
|
#undef PLUGINCALL
|
||||||
|
#define PLUGINCALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
PLUGINAPI int PLUGINCALL transparent_plugin (struct pluginlink * pluginlink,
|
||||||
|
int argc, char** argv){
|
||||||
|
pl = pluginlink;
|
||||||
|
if(!transparent_loaded){
|
||||||
|
transparent_loaded = 1;
|
||||||
|
transparent_filter.next = pl->conf->filters;
|
||||||
|
pl->conf->filters = &transparent_filter;
|
||||||
|
transparent_commandhandlers[1].next = pl->commandhandlers->next;
|
||||||
|
pl->commandhandlers->next = transparent_commandhandlers;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
15
src/proxy.h
15
src/proxy.h
@ -152,21 +152,6 @@ void daemonize(void);
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* A UDP service answers from the address the client sent to, so the reply has
|
|
||||||
to leave the listening socket. Sharing that socket with the request handler
|
|
||||||
is the simple way, and what every Unix build does.
|
|
||||||
|
|
||||||
Older Windows cannot have two operations in flight on one socket, so a
|
|
||||||
build for it binds a second socket to the same address instead, which needs
|
|
||||||
SO_REUSEADDR on the listening socket as well. A build for those versions
|
|
||||||
asks for that with NO_SHARE_UDP_SOCKET, as Makefile.watcom does.
|
|
||||||
*/
|
|
||||||
#ifndef SHARE_UDP_SOCKET
|
|
||||||
#ifndef NO_SHARE_UDP_SOCKET
|
|
||||||
#define SHARE_UDP_SOCKET
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
size_t threadstacksize(int extra);
|
size_t threadstacksize(int extra);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -835,21 +835,10 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
port there, and it only allows another local process to bind the same
|
port there, and it only allows another local process to bind the same
|
||||||
address and port, with undefined behaviour as to which socket receives the
|
address and port, with undefined behaviour as to which socket receives the
|
||||||
connections. Use -olSO_EXCLUSIVEADDRUSE to prevent that instead.
|
connections. Use -olSO_EXCLUSIVEADDRUSE to prevent that instead.
|
||||||
|
|
||||||
A Windows build which does not share the listening socket is the exception:
|
|
||||||
its UDP services bind a second socket to the same address to answer from,
|
|
||||||
and Windows only allows that when both sockets ask for it.
|
|
||||||
*/
|
*/
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
opt = 1;
|
opt = 1;
|
||||||
if(srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int)))perror("setsockopt()");
|
if(srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int)))perror("setsockopt()");
|
||||||
#else
|
|
||||||
#ifndef SHARE_UDP_SOCKET
|
|
||||||
if(isudp){
|
|
||||||
opt = 1;
|
|
||||||
if(srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int)))perror("setsockopt()");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef SO_REUSEPORT
|
#ifdef SO_REUSEPORT
|
||||||
opt = 1;
|
opt = 1;
|
||||||
|
|||||||
@ -1,240 +0,0 @@
|
|||||||
/*
|
|
||||||
3APA3A simplest proxy server
|
|
||||||
(c) 2002-2026 by Vladimir Dubrovin <vlad@3proxy.org>
|
|
||||||
|
|
||||||
please read License Agreement
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "structures.h"
|
|
||||||
#include "proxy.h"
|
|
||||||
|
|
||||||
#ifdef WITH_TRANSPARENT
|
|
||||||
|
|
||||||
#ifdef WITH_NETFILTER
|
|
||||||
#include <sys/utsname.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <linux/netfilter_ipv4.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WITH_PF
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <net/if.h>
|
|
||||||
#include <net/pfvar.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Where the address the client was trying to reach is read from.
|
|
||||||
|
|
||||||
AUTO uses what the platform offers, which is the only thing an
|
|
||||||
installation usually needs. The rest name one mechanism, for a machine
|
|
||||||
that has more than one and redirects with a particular one.
|
|
||||||
*/
|
|
||||||
#define TRANSPARENT_AUTO 0
|
|
||||||
#define TRANSPARENT_NETFILTER 1
|
|
||||||
#define TRANSPARENT_PF 2
|
|
||||||
#define TRANSPARENT_SOCKET 3
|
|
||||||
|
|
||||||
static struct pluginlink * pl;
|
|
||||||
|
|
||||||
static int transparent_loaded = 0;
|
|
||||||
static int transparent_mode = TRANSPARENT_AUTO;
|
|
||||||
|
|
||||||
#ifdef WITH_PF
|
|
||||||
static int pf_device = -1;
|
|
||||||
|
|
||||||
/* Ask the packet filter what the connection was addressed to before it was
|
|
||||||
redirected. pf keeps that in its state table rather than on the socket,
|
|
||||||
so it has to be looked up with the addresses of both ends.
|
|
||||||
*/
|
|
||||||
static int transparent_pf(struct clientparam *param)
|
|
||||||
{
|
|
||||||
struct pfioc_natlook nl;
|
|
||||||
|
|
||||||
if(pf_device < 0){
|
|
||||||
pf_device = open("/dev/pf", O_RDONLY);
|
|
||||||
if(pf_device < 0) return 1;
|
|
||||||
}
|
|
||||||
memset(&nl, 0, sizeof(nl));
|
|
||||||
nl.proto = IPPROTO_TCP;
|
|
||||||
nl.direction = PF_OUT;
|
|
||||||
#ifndef NOIPV6
|
|
||||||
if(*SAFAMILY(¶m->sincr) == AF_INET6){
|
|
||||||
nl.af = AF_INET6;
|
|
||||||
memcpy(&nl.saddr.v6, SAADDR(¶m->sincr), 16);
|
|
||||||
memcpy(&nl.daddr.v6, SAADDR(¶m->sincl), 16);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
nl.af = AF_INET;
|
|
||||||
memcpy(&nl.saddr.v4, SAADDR(¶m->sincr), 4);
|
|
||||||
memcpy(&nl.daddr.v4, SAADDR(¶m->sincl), 4);
|
|
||||||
}
|
|
||||||
nl.sport = *SAPORT(¶m->sincr);
|
|
||||||
nl.dport = *SAPORT(¶m->sincl);
|
|
||||||
|
|
||||||
if(ioctl(pf_device, DIOCNATLOOK, &nl)) return 1;
|
|
||||||
|
|
||||||
memset(¶m->req, 0, sizeof(param->req));
|
|
||||||
*SAFAMILY(¶m->req) = nl.af;
|
|
||||||
#ifndef NOIPV6
|
|
||||||
if(nl.af == AF_INET6) memcpy(SAADDR(¶m->req), &nl.rdaddr.v6, 16);
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
memcpy(SAADDR(¶m->req), &nl.rdaddr.v4, 4);
|
|
||||||
*SAPORT(¶m->req) = nl.rdport;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WITH_NETFILTER
|
|
||||||
/* Linux keeps the original address for the connection it redirected. */
|
|
||||||
static int transparent_netfilter(struct clientparam *param)
|
|
||||||
{
|
|
||||||
socklen_t len = sizeof(param->req);
|
|
||||||
|
|
||||||
#ifdef SO_ORIGINAL_DST
|
|
||||||
if(getsockopt(param->clisock,
|
|
||||||
#ifndef NOIPV6
|
|
||||||
#ifdef SOL_IPV6
|
|
||||||
*SAFAMILY(¶m->sincr) == AF_INET6?SOL_IPV6:
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
SOL_IP, SO_ORIGINAL_DST, (struct sockaddr *) ¶m->req, &len)
|
|
||||||
|| !memcmp((char *)SAADDR(¶m->req), "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", SAADDRLEN(¶m->req))){
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
#error No SO_ORIGINAL_DST defined
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Some redirections leave the original address on the socket itself, so the
|
|
||||||
local address of the accepted connection is what the client asked for.
|
|
||||||
|
|
||||||
A connection which was not redirected at all arrives at the address the
|
|
||||||
service listens on, and taking that as the destination would send the
|
|
||||||
service to itself. Refuse instead of making the connection.
|
|
||||||
*/
|
|
||||||
static int transparent_socket(struct clientparam *param)
|
|
||||||
{
|
|
||||||
if(*SAFAMILY(¶m->sincl) != AF_INET && *SAFAMILY(¶m->sincl) != AF_INET6)
|
|
||||||
return 1;
|
|
||||||
if(*SAPORT(¶m->sincl) == *SAPORT(¶m->srv->intsa)
|
|
||||||
&& (SAISNULL(¶m->srv->intsa)
|
|
||||||
|| !memcmp(SAADDR(¶m->sincl), SAADDR(¶m->srv->intsa), SAADDRLEN(¶m->sincl))))
|
|
||||||
return 2;
|
|
||||||
param->req = param->sincl;
|
|
||||||
param->sincl = param->srv->intsa;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void* transparent_filter_open(void * idata, struct srvparam * param){
|
|
||||||
return idata;
|
|
||||||
}
|
|
||||||
|
|
||||||
static FILTER_ACTION transparent_filter_client(void *fo, struct clientparam * param, void** fc){
|
|
||||||
|
|
||||||
char addrbuf[64];
|
|
||||||
int res = 1;
|
|
||||||
|
|
||||||
#ifdef WITH_NETFILTER
|
|
||||||
if(transparent_mode == TRANSPARENT_AUTO || transparent_mode == TRANSPARENT_NETFILTER)
|
|
||||||
res = transparent_netfilter(param);
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_PF
|
|
||||||
if(res && (transparent_mode == TRANSPARENT_AUTO || transparent_mode == TRANSPARENT_PF))
|
|
||||||
res = transparent_pf(param);
|
|
||||||
#endif
|
|
||||||
if(res && (transparent_mode == TRANSPARENT_AUTO || transparent_mode == TRANSPARENT_SOCKET)){
|
|
||||||
res = transparent_socket(param);
|
|
||||||
if(res == 2){
|
|
||||||
param->srv->logfunc(param, (unsigned char *)"transparent: connection was not redirected");
|
|
||||||
return REJECT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Nothing knows where this was going: leave the request alone, so the
|
|
||||||
service decides as it would without the command. */
|
|
||||||
if(res) return PASS;
|
|
||||||
|
|
||||||
pl->myinet_ntop(*SAFAMILY(¶m->req), SAADDR(¶m->req), (char *)addrbuf, sizeof(addrbuf));
|
|
||||||
if(param->hostname) pl->freefunc(param->hostname);
|
|
||||||
param->hostname = (unsigned char *)pl->strdupfunc(addrbuf);
|
|
||||||
param->sinsr = param->req;
|
|
||||||
return PASS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void transparent_filter_clear(void *fo){
|
|
||||||
}
|
|
||||||
|
|
||||||
static void transparent_filter_close(void *fo){
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct filter transparent_filter = {
|
|
||||||
NULL,
|
|
||||||
"Transparent filter",
|
|
||||||
"Transparent filter",
|
|
||||||
transparent_filter_open,
|
|
||||||
transparent_filter_client,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
transparent_filter_clear,
|
|
||||||
transparent_filter_close
|
|
||||||
};
|
|
||||||
|
|
||||||
int h_transparent(int argc, unsigned char **argv){
|
|
||||||
transparent_mode = TRANSPARENT_AUTO;
|
|
||||||
if(argc > 1){
|
|
||||||
if(!strcmp((char *)argv[1], "auto")) transparent_mode = TRANSPARENT_AUTO;
|
|
||||||
else if(!strcmp((char *)argv[1], "netfilter")){
|
|
||||||
#ifndef WITH_NETFILTER
|
|
||||||
fprintf(stderr, "transparent: netfilter is not available in this build\n");
|
|
||||||
return 1;
|
|
||||||
#else
|
|
||||||
transparent_mode = TRANSPARENT_NETFILTER;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else if(!strcmp((char *)argv[1], "pf")){
|
|
||||||
#ifndef WITH_PF
|
|
||||||
fprintf(stderr, "transparent: pf is not available in this build\n");
|
|
||||||
return 1;
|
|
||||||
#else
|
|
||||||
transparent_mode = TRANSPARENT_PF;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else if(!strcmp((char *)argv[1], "socket")) transparent_mode = TRANSPARENT_SOCKET;
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "transparent: unknown mode %s, expected auto, netfilter, pf or socket\n", argv[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
transparent_filter.filter_open = transparent_filter_open;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int h_notransparent(int argc, unsigned char **argv){
|
|
||||||
transparent_filter.filter_open = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void transparent_install(void){
|
|
||||||
pl = &pluginlink;
|
|
||||||
/* A reload runs this again: the filter is a single static entry, so it
|
|
||||||
is only linked in once, and the commands decide whether it acts. */
|
|
||||||
if(!transparent_loaded){
|
|
||||||
transparent_loaded = 1;
|
|
||||||
transparent_filter.next = pl->conf->filters;
|
|
||||||
pl->conf->filters = &transparent_filter;
|
|
||||||
}
|
|
||||||
transparent_filter.filter_open = NULL;
|
|
||||||
transparent_mode = TRANSPARENT_AUTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,7 +1,5 @@
|
|||||||
"""dnspr: a caching DNS proxy, answering from what it has been told."""
|
"""dnspr: a caching DNS proxy, answering from what it has been told."""
|
||||||
|
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
def run(t):
|
def run(t):
|
||||||
port = t.free_port()
|
port = t.free_port()
|
||||||
@ -17,11 +15,8 @@ def run(t):
|
|||||||
allow *
|
allow *
|
||||||
dnspr -p{port}
|
dnspr -p{port}
|
||||||
""")
|
""")
|
||||||
# Wait for the service: a datagram sent too early is simply lost. Bound
|
# wait for the service: a datagram sent too early is simply lost
|
||||||
# by the clock, not by a number of attempts, so a server that answers
|
for _ in range(100):
|
||||||
# nothing costs seconds rather than minutes.
|
|
||||||
deadline = time.time() + 5
|
|
||||||
while time.time() < deadline:
|
|
||||||
if t.dns_query(port, "host.test"):
|
if t.dns_query(port, "host.test"):
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@ -190,23 +190,15 @@ def run(t):
|
|||||||
|
|
||||||
t.ne(200, t.http(v4url, proxy=f"127.0.0.1:{partial}").status,
|
t.ne(200, t.http(v4url, proxy=f"127.0.0.1:{partial}").status,
|
||||||
"denying 127.0.0.1 denies the address as written")
|
"denying 127.0.0.1 denies the address as written")
|
||||||
|
t.eq(200, t.http(mapped, proxy=f"127.0.0.1:{partial}").status,
|
||||||
# Whether the mapped form reaches the same host is up to the stack: it
|
"but the same host asked for as ::ffff:127.0.0.1 is still reached")
|
||||||
# does where a mapped address is routed to IPv4, and that is the hazard
|
|
||||||
# the security notes describe. Where it does not, there is nothing to
|
|
||||||
# assert, but the rule that names every spelling still has to hold.
|
|
||||||
if t.http(mapped, proxy=f"127.0.0.1:{partial}").status == 200:
|
|
||||||
t.ok("the same host asked for as ::ffff:127.0.0.1 is still reached")
|
|
||||||
else:
|
|
||||||
t.skip("the mapped form (this stack does not route it to IPv4)")
|
|
||||||
|
|
||||||
t.eq(200, t.http(url, proxy=f"127.0.0.1:{partial}").status,
|
t.eq(200, t.http(url, proxy=f"127.0.0.1:{partial}").status,
|
||||||
"and ::1 is reached, which the rule never mentioned")
|
"and so is ::1, which the rule never mentioned")
|
||||||
|
|
||||||
t.ne(200, t.http(v4url, proxy=f"127.0.0.1:{complete}").status,
|
t.ne(200, t.http(v4url, proxy=f"127.0.0.1:{complete}").status,
|
||||||
"naming every spelling denies the plain address")
|
"naming every spelling denies the plain address")
|
||||||
t.ne(200, t.http(mapped, proxy=f"127.0.0.1:{complete}").status,
|
t.ne(200, t.http(mapped, proxy=f"127.0.0.1:{complete}").status,
|
||||||
"and the mapped one, whether or not it would have been reachable")
|
"and the mapped one")
|
||||||
t.ne(200, t.http(url, proxy=f"127.0.0.1:{complete}").status,
|
t.ne(200, t.http(url, proxy=f"127.0.0.1:{complete}").status,
|
||||||
"and the IPv6 loopback")
|
"and the IPv6 loopback")
|
||||||
|
|
||||||
|
|||||||
@ -1,164 +0,0 @@
|
|||||||
"""Transparent proxying: the destination comes from the redirection.
|
|
||||||
|
|
||||||
A redirected connection no longer says where it was going, so the proxy has
|
|
||||||
to ask the packet filter. That means a real redirection rule, which needs
|
|
||||||
privilege, so the case skips unless it can install one and remove it again.
|
|
||||||
|
|
||||||
The rule must not catch the proxy's own connection to the origin, or the
|
|
||||||
traffic goes round for ever. Here the proxy is given an outgoing address of
|
|
||||||
its own and the rule excludes it, which is the arrangement the documentation
|
|
||||||
recommends.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
ORIGIN_ADDR = "127.0.0.9" # where the client believes it is going
|
|
||||||
PROXY_ADDR = "127.0.0.8" # the source the proxy connects from
|
|
||||||
DECOY_ADDR = "127.0.0.7" # a second server, to show where traffic went
|
|
||||||
|
|
||||||
|
|
||||||
def _run(command):
|
|
||||||
done = subprocess.run(command, stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.STDOUT, timeout=30)
|
|
||||||
return done.returncode, done.stdout.decode("utf-8", "replace").strip()
|
|
||||||
|
|
||||||
|
|
||||||
def _iptables_rule(action, origin_port, proxy_port):
|
|
||||||
return ["iptables", "-t", "nat", action, "OUTPUT",
|
|
||||||
"-p", "tcp", "-d", ORIGIN_ADDR, "--dport", str(origin_port),
|
|
||||||
"!", "-s", PROXY_ADDR,
|
|
||||||
"-j", "REDIRECT", "--to-ports", str(proxy_port)]
|
|
||||||
|
|
||||||
|
|
||||||
def _config(t, name, body):
|
|
||||||
"""Run a configuration that has no service, and return what it said."""
|
|
||||||
return t.run_config(name, body + "\nnot_a_command\n")
|
|
||||||
|
|
||||||
|
|
||||||
def run(t):
|
|
||||||
# --- the command and its modes ------------------------------------
|
|
||||||
# These need no redirection, so they run wherever the feature is built.
|
|
||||||
out = _config(t, "transparent_probe", "log\ntransparent")
|
|
||||||
if "'transparent'" in out:
|
|
||||||
t.skip("transparent proxying (not built in this configuration)")
|
|
||||||
return
|
|
||||||
|
|
||||||
for mode in ("auto", "socket"):
|
|
||||||
t.not_contains(_config(t, "mode_" + mode, f"log\ntransparent {mode}"),
|
|
||||||
"transparent:", f"the {mode} mode is accepted")
|
|
||||||
|
|
||||||
t.contains(_config(t, "mode_bogus", "log\ntransparent bogus"),
|
|
||||||
"unknown mode", "an unknown mode is refused")
|
|
||||||
|
|
||||||
# A mode the build has no code for is refused rather than ignored, so a
|
|
||||||
# configuration written for another platform fails where it is wrong
|
|
||||||
# instead of quietly doing something else.
|
|
||||||
for mode, built in (("netfilter", platform.system() == "Linux"), ("pf", False)):
|
|
||||||
out = _config(t, "mode_" + mode, f"log\ntransparent {mode}")
|
|
||||||
if built:
|
|
||||||
t.not_contains(out, "not available", f"the {mode} mode is accepted where it exists")
|
|
||||||
elif "not available" in out:
|
|
||||||
t.ok(f"the {mode} mode is refused where it does not exist")
|
|
||||||
else:
|
|
||||||
t.skip(f"the {mode} mode (built here, nothing to check)")
|
|
||||||
|
|
||||||
t.not_contains(_config(t, "notransparent", "log\ntransparent\nnotransparent"),
|
|
||||||
"'notransparent'", "notransparent is accepted")
|
|
||||||
|
|
||||||
# A configuration written for the plugin still loads: the line that used
|
|
||||||
# to load it is accepted and does nothing, the way the ssl and pcre ones
|
|
||||||
# are, so an existing configuration does not have to be edited first.
|
|
||||||
out = _config(t, "plugin_line",
|
|
||||||
"log\nplugin /usr/local/lib/TransparentPlugin.ld.so transparent_plugin")
|
|
||||||
t.not_contains(out, "failed", "loading the old plugin is accepted and ignored")
|
|
||||||
t.contains(_config(t, "plugin_missing", "log\nplugin /nope/NoSuch.so nosuch_plugin"),
|
|
||||||
"failed", "an unknown plugin still fails to load")
|
|
||||||
|
|
||||||
# --- and the redirection itself ------------------------------------
|
|
||||||
if platform.system() != "Linux":
|
|
||||||
# The BSDs need a redirection that leaves the original destination on
|
|
||||||
# the socket - divert-to on OpenBSD, ipfw fwd on FreeBSD - and macOS
|
|
||||||
# has neither, so there is nothing to set up here.
|
|
||||||
t.skip(f"transparent proxying (no redirection to set up on {platform.system()})")
|
|
||||||
return
|
|
||||||
if os.geteuid() != 0 or not shutil.which("iptables"):
|
|
||||||
t.skip("transparent proxying (needs root and iptables to redirect)")
|
|
||||||
return
|
|
||||||
|
|
||||||
origin_port = t.free_port()
|
|
||||||
decoy_port = t.free_port()
|
|
||||||
mapper_port = t.free_port()
|
|
||||||
plain_port = t.free_port()
|
|
||||||
|
|
||||||
t.start("transparent", f"""
|
|
||||||
log
|
|
||||||
auth iponly
|
|
||||||
allow *
|
|
||||||
http * /echo* echo
|
|
||||||
httpsrv -p{origin_port} -i{ORIGIN_ADDR}
|
|
||||||
|
|
||||||
# a second server, to tell apart where a connection actually went
|
|
||||||
flush
|
|
||||||
auth iponly
|
|
||||||
allow *
|
|
||||||
http * * data size=13
|
|
||||||
httpsrv -p{decoy_port} -i{DECOY_ADDR}
|
|
||||||
|
|
||||||
# a port mapper aimed at the decoy: with the destination taken from
|
|
||||||
# the redirection instead, it goes to the origin
|
|
||||||
flush
|
|
||||||
auth iponly
|
|
||||||
allow *
|
|
||||||
transparent
|
|
||||||
tcppm -e{PROXY_ADDR} {mapper_port} {DECOY_ADDR} {decoy_port}
|
|
||||||
notransparent
|
|
||||||
|
|
||||||
# the same mapper without it, which keeps going to the decoy
|
|
||||||
flush
|
|
||||||
auth iponly
|
|
||||||
allow *
|
|
||||||
tcppm -e{PROXY_ADDR} {plain_port} {DECOY_ADDR} {decoy_port}
|
|
||||||
""", ports=[(ORIGIN_ADDR, origin_port), (DECOY_ADDR, decoy_port),
|
|
||||||
mapper_port, plain_port])
|
|
||||||
|
|
||||||
code, out = _run(_iptables_rule("-A", origin_port, mapper_port))
|
|
||||||
if code:
|
|
||||||
t.skip(f"transparent proxying (could not add a redirect rule: {out})")
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
# The client asks for the address it wants; the rule sends the
|
|
||||||
# connection to the mapper instead, and the mapper has to work out
|
|
||||||
# where it was headed.
|
|
||||||
r = t.http(f"http://{ORIGIN_ADDR}:{origin_port}/echo")
|
|
||||||
t.eq(200, r.status, "a redirected connection reaches its destination")
|
|
||||||
t.contains(r, "path=/echo", "the request arrives unchanged")
|
|
||||||
t.contains(r, f"host={ORIGIN_ADDR}:{origin_port}",
|
|
||||||
"the client still believes it is talking to the origin")
|
|
||||||
t.contains(r, f"peer.addr={PROXY_ADDR}",
|
|
||||||
"the origin is reached from the proxy's own address")
|
|
||||||
|
|
||||||
# That address is what the rule excludes, which is what stops the
|
|
||||||
# proxy's own connection from being redirected back into itself.
|
|
||||||
t.not_contains(r, "size=13", "the connection did not go to the decoy")
|
|
||||||
|
|
||||||
# Without the command the mapper has no reason to look, and goes
|
|
||||||
# where it was configured to go.
|
|
||||||
_run(_iptables_rule("-D", origin_port, mapper_port))
|
|
||||||
code, out = _run(_iptables_rule("-A", origin_port, plain_port))
|
|
||||||
if code:
|
|
||||||
t.skip("the mapper without the command (could not move the rule)")
|
|
||||||
else:
|
|
||||||
r = t.http(f"http://{ORIGIN_ADDR}:{origin_port}/echo")
|
|
||||||
t.eq(13, r.length,
|
|
||||||
"without the command the connection goes to the configured target")
|
|
||||||
t.not_contains(r, "path=/echo",
|
|
||||||
"and never reaches the address the client asked for")
|
|
||||||
_run(_iptables_rule("-D", origin_port, plain_port))
|
|
||||||
finally:
|
|
||||||
# leave the machine as it was found, whatever happened above
|
|
||||||
_run(_iptables_rule("-D", origin_port, mapper_port))
|
|
||||||
_run(_iptables_rule("-D", origin_port, plain_port))
|
|
||||||
@ -424,20 +424,15 @@ class Tester:
|
|||||||
|
|
||||||
# ---- DNS ---------------------------------------------------------
|
# ---- DNS ---------------------------------------------------------
|
||||||
|
|
||||||
def dns_query(self, port, name, host="127.0.0.1", timeout=2.0):
|
def dns_query(self, port, name, host="127.0.0.1"):
|
||||||
"""Ask for an A record and return the addresses in the answer.
|
"""Ask for an A record and return the addresses in the answer."""
|
||||||
|
|
||||||
The default timeout is short: a name server on the loopback answers
|
|
||||||
at once or not at all, and waiting the full request timeout on every
|
|
||||||
attempt turns a server that answers nothing into a very slow run.
|
|
||||||
"""
|
|
||||||
query = struct.pack("!HHHHHH", 0x2A2A, 0x0100, 1, 0, 0, 0)
|
query = struct.pack("!HHHHHH", 0x2A2A, 0x0100, 1, 0, 0, 0)
|
||||||
for label in name.split("."):
|
for label in name.split("."):
|
||||||
query += bytes([len(label)]) + label.encode()
|
query += bytes([len(label)]) + label.encode()
|
||||||
query += b"\x00" + struct.pack("!HH", 1, 1)
|
query += b"\x00" + struct.pack("!HH", 1, 1)
|
||||||
|
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
sock.settimeout(timeout)
|
sock.settimeout(self.timeout)
|
||||||
try:
|
try:
|
||||||
sock.sendto(query, (host, port))
|
sock.sendto(query, (host, port))
|
||||||
data = sock.recvfrom(65536)[0]
|
data = sock.recvfrom(65536)[0]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user