From f2ae920db2942bab8fa3a2c49276f07232aefe13 Mon Sep 17 00:00:00 2001 From: Vladimir Dubrovin <3proxy@3proxy.ru> Date: Sat, 29 Aug 2026 23:39:07 +0300 Subject: [PATCH] Build the mail proxies and FTP only when they are asked for pop3p, imapp and smtpp are built with MAILPROXY=true, and ftppr and the ftp:// scheme of the HTTP proxy with FTP=true; with CMake the switches are 3PROXY_USE_MAILPROXY and 3PROXY_USE_FTP. Neither is in a default build, and the standalone binaries follow what was built. A configuration naming one of them is still read either way. The three mail protocols amount to a STARTTLS negotiation now that mail is carried over TLS, so without a proxy of their own those names are tlspr speaking the protocol: the file holds a stand-in which sets the protocol for the connection and returns tlspr for the caller to run, which serves the service name and a parent chain alike and leaves conf.c and the redirect table untouched. FTP has no such fallback, so the service is known, answers nothing and logs the refusal. The Linux workflow builds both, so all of it is still compiled and run. --- .github/workflows/c-cpp-Linux.yml | 2 +- CMakeLists.txt | 30 ++++++++++++++++++++++++++---- Makefile.FreeBSD | 10 ++++++++++ Makefile.Linux | 10 ++++++++++ Makefile.Solaris | 10 ++++++++++ Makefile.unix | 10 ++++++++++ Makefile.win | 10 ++++++++++ man/3proxy.cfg.5 | 26 ++++++++++++++++++++++---- src/Makefile.inc | 2 +- src/ftp.c | 4 ++++ src/ftppr.c | 15 +++++++++++++++ src/imapp.c | 14 ++++++++++++++ src/pop3p.c | 14 ++++++++++++++ src/proxy.c | 4 ++++ src/smtpp.c | 14 ++++++++++++++ src/structures.h | 4 ++++ src/tlspr.c | 3 ++- 17 files changed, 171 insertions(+), 11 deletions(-) diff --git a/.github/workflows/c-cpp-Linux.yml b/.github/workflows/c-cpp-Linux.yml index 1551944..c906317 100644 --- a/.github/workflows/c-cpp-Linux.yml +++ b/.github/workflows/c-cpp-Linux.yml @@ -27,7 +27,7 @@ jobs: if: ${{ startsWith(matrix.target, 'ubuntu') }} run: sudo apt-get update && sudo apt-get install -y libssl-dev libpam-dev libpcre2-dev - name: make - run: make -f Makefile.Linux + run: make -f Makefile.Linux MAILPROXY=true FTP=true - name: regression tests run: python3 tests/run.py - name: mkdir diff --git a/CMakeLists.txt b/CMakeLists.txt index fed8642..f7d969c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,8 @@ option(3PROXY_USE_NETFILTER "Enable Linux netfilter support (Linux only)" ON) option(3PROXY_USE_TRANSPARENT "Build transparent proxying support (Linux and BSD only)" ON) option(3PROXY_USE_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_MAILPROXY "Build the pop3p, imapp and smtpp proxies" OFF) +option(3PROXY_USE_FTP "Build FTP support: the ftppr service and ftp:// in the HTTP proxy" OFF) if(NOT WIN32 AND NOT APPLE) option(3PROXY_STATIC_LINK "Statically link libraries using -Wl,-Bstatic (Linux/Unix only)" OFF) @@ -83,10 +85,13 @@ set(3PROXY_BINARY_PREFIX "3proxy_" CACHE STRING "Prefix for standalone module an option(3PROXY_BUILD_NONE "Do not build standalone binaries" OFF) option(3PROXY_BUILD_PROXY "Build standalone proxy binary" ON) option(3PROXY_BUILD_SOCKS "Build standalone socks binary" ON) -option(3PROXY_BUILD_POP3P "Build standalone pop3p binary" ON) -option(3PROXY_BUILD_IMAPP "Build standalone imapp binary" ON) -option(3PROXY_BUILD_SMTPP "Build standalone smtpp binary" ON) -option(3PROXY_BUILD_FTPPR "Build standalone ftppr binary" ON) +# The mail proxies and FTP are asked for rather than assumed: without them +# pop3p, imapp and smtpp are the STARTTLS proxy under those names, and ftp +# is not spoken at all. A standalone binary needs the support it is made of. +option(3PROXY_BUILD_POP3P "Build standalone pop3p binary" OFF) +option(3PROXY_BUILD_IMAPP "Build standalone imapp binary" OFF) +option(3PROXY_BUILD_SMTPP "Build standalone smtpp binary" OFF) +option(3PROXY_BUILD_FTPPR "Build standalone ftppr binary" OFF) option(3PROXY_BUILD_TCPPM "Build standalone tcppm binary" ON) option(3PROXY_BUILD_UDPPM "Build standalone udppm binary" ON) option(3PROXY_BUILD_TLSPR "Build standalone tlspr binary" ON) @@ -250,6 +255,14 @@ else() ) endif() +if(3PROXY_USE_MAILPROXY) + add_compile_definitions(WITH_POP3P WITH_IMAPP WITH_SMTPP) +endif() + +if(3PROXY_USE_FTP) + add_compile_definitions(WITH_FTP) +endif() + if(3PROXY_USE_HTTPSRV) add_compile_definitions(WITH_HTTPSRV) endif() @@ -684,6 +697,15 @@ foreach(PROXY_NAME proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr) continue() endif() + # A binary of nothing: without the support built, these files hold the + # stand-in the main binary uses and no service of their own. + if(NOT 3PROXY_USE_MAILPROXY AND PROXY_NAME MATCHES "^(pop3p|imapp|smtpp)$") + continue() + endif() + if(NOT 3PROXY_USE_FTP AND PROXY_NAME STREQUAL "ftppr") + continue() + endif() + if(PROXY_NAME STREQUAL "ftppr" OR PROXY_NAME STREQUAL "proxy") # ftppr and proxy use ftp_obj add_executable(${PROXY_NAME} diff --git a/Makefile.FreeBSD b/Makefile.FreeBSD index 7865d04..eddce71 100644 --- a/Makefile.FreeBSD +++ b/Makefile.FreeBSD @@ -24,6 +24,16 @@ LDFLAGS += $(EXTRA_LDFLAGS) # -lpthreads may be reuiured on some platforms instead of -pthreads # -ldl or -lld may be required for some platforms DCFLAGS ?= -fPIC +MAILPROXY ?= false +ifeq ($(MAILPROXY),true) + CFLAGS += -DWITH_POP3P -DWITH_IMAPP -DWITH_SMTPP + MAIL_EXES = $(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS) +endif +FTP ?= false +ifeq ($(FTP),true) + CFLAGS += -DWITH_FTP + FTP_EXES = $(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS) +endif HTTPSRV ?= true ifeq ($(HTTPSRV),true) CFLAGS += -DWITH_HTTPSRV diff --git a/Makefile.Linux b/Makefile.Linux index 48b48d8..94479e5 100644 --- a/Makefile.Linux +++ b/Makefile.Linux @@ -27,6 +27,16 @@ CFLAGS += $(EXTRA_CFLAGS) LDFLAGS += $(EXTRA_LDFLAGS) # The HTTP server serves the endpoints declared by http lines. The admin # interface is built on top of it, so turning it off removes both. +MAILPROXY ?= false +ifeq ($(MAILPROXY),true) + CFLAGS += -DWITH_POP3P -DWITH_IMAPP -DWITH_SMTPP + MAIL_EXES = $(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS) +endif +FTP ?= false +ifeq ($(FTP),true) + CFLAGS += -DWITH_FTP + FTP_EXES = $(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS) +endif HTTPSRV ?= true ifeq ($(HTTPSRV),true) CFLAGS += -DWITH_HTTPSRV diff --git a/Makefile.Solaris b/Makefile.Solaris index f5c2537..8595400 100644 --- a/Makefile.Solaris +++ b/Makefile.Solaris @@ -14,6 +14,16 @@ COUT = -o ./ LN = $(CC) LDFLAGS = -xO3 DCFLAGS = -fPIC +MAILPROXY ?= false +ifeq ($(MAILPROXY),true) + CFLAGS += -DWITH_POP3P -DWITH_IMAPP -DWITH_SMTPP + MAIL_EXES = $(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS) +endif +FTP ?= false +ifeq ($(FTP),true) + CFLAGS += -DWITH_FTP + FTP_EXES = $(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS) +endif HTTPSRV ?= true ifeq ($(HTTPSRV),true) CFLAGS += -DWITH_HTTPSRV diff --git a/Makefile.unix b/Makefile.unix index ec71ad5..96ffe0e 100644 --- a/Makefile.unix +++ b/Makefile.unix @@ -26,6 +26,16 @@ LDFLAGS += $(EXTRA_LDFLAGS) # -lpthreads may be reuqired on some platforms instead of -pthreads # -ldl or -lld may be required for some platforms DCFLAGS ?= -fPIC +MAILPROXY ?= false +ifeq ($(MAILPROXY),true) + CFLAGS += -DWITH_POP3P -DWITH_IMAPP -DWITH_SMTPP + MAIL_EXES = $(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS) +endif +FTP ?= false +ifeq ($(FTP),true) + CFLAGS += -DWITH_FTP + FTP_EXES = $(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS) +endif HTTPSRV ?= true ifeq ($(HTTPSRV),true) CFLAGS += -DWITH_HTTPSRV diff --git a/Makefile.win b/Makefile.win index 9d7a2dd..77304bf 100644 --- a/Makefile.win +++ b/Makefile.win @@ -23,6 +23,16 @@ LDFLAGS += -fno-strict-aliasing -mthreads # makefile, including the += above and the STATIC/LIBSTATIC handling below. CFLAGS += $(EXTRA_CFLAGS) LDFLAGS += $(EXTRA_LDFLAGS) +MAILPROXY ?= false +ifeq ($(MAILPROXY),true) + CFLAGS += -DWITH_POP3P -DWITH_IMAPP -DWITH_SMTPP + MAIL_EXES = $(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS) +endif +FTP ?= false +ifeq ($(FTP),true) + CFLAGS += -DWITH_FTP + FTP_EXES = $(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS) +endif HTTPSRV ?= true ifeq ($(HTTPSRV),true) CFLAGS += -DWITH_HTTPSRV diff --git a/man/3proxy.cfg.5 b/man/3proxy.cfg.5 index 2b22cb7..950ba4c 100644 --- a/man/3proxy.cfg.5 +++ b/man/3proxy.cfg.5 @@ -95,16 +95,19 @@ SNI proxy (destination address is taken from TLS handshake), may be used to redi Proxy with protocol autoselection between proxy / socks / tlspr .br .B pop3p -POP3 proxy (default port 110) +POP3 proxy (default port 110), in a build which has one: otherwise the +service is \fBtlspr\fR speaking POP3 to negotiate STARTTLS, under this name. .br .B imapp -IMAPv4 proxy (default port 143) +IMAPv4 proxy (default port 143), or \fBtlspr\fR speaking IMAP, as above. .br .B smtpp -SMTP proxy (default port 25) +SMTP proxy (default port 25), or \fBtlspr\fR speaking SMTP, as above. .br .B ftppr -FTP proxy (default port 21) +FTP proxy (default port 21), in a build with FTP support. Without it the +service is known but answers nothing, and \fBftp://\fR is not a URL the HTTP +proxy fetches. .br .B admin Web interface (default port 80) @@ -1573,6 +1576,21 @@ matched if the ACL matches the connection data. Warning: Regular expressions don't require authentication and cannot replace authentication and/or allow/deny ACLs. +.SH OPTIONAL SERVICES +The mail proxies and FTP are built when they are asked for, and are not in a +default build. \fBMAILPROXY=true\fR builds \fBpop3p\fR, \fBimapp\fR and +\fBsmtpp\fR, and \fBFTP=true\fR builds \fBftppr\fR and the \fBftp://\fR +scheme of the HTTP proxy; with CMake the switches are +\fB-D3PROXY_USE_MAILPROXY=ON\fR and \fB-D3PROXY_USE_FTP=ON\fR. The standalone +binaries of those services are built with them and not without. +.br + A configuration naming a service which was not built is still read. The three +mail proxies become \fBtlspr\fR negotiating STARTTLS in that protocol, which +is what most of their use amounts to now that the mail protocols are used over +TLS, and a \fBparent\fR chain naming \fBpop3\fR, \fBimap\fR or \fBsmtp\fR +does the same. \fBftppr\fR is answered by nothing: a client reaching it is +turned away and the refusal logged, since there is no protocol to fall back on. + .SH BUILT IN HTTP SERVER The \fBhttpsrv\fR service answers requests itself instead of forwarding them. What it does with a request is decided by \fBhttp\fR rules, which are taken in diff --git a/src/Makefile.inc b/src/Makefile.inc index b2c04ce..1cb5a40 100644 --- a/src/Makefile.inc +++ b/src/Makefile.inc @@ -2,7 +2,7 @@ # 3 proxy common Makefile # -all: $(BUILDDIR)3proxy$(EXESUFFICS) $(BUILDDIR)$(CRYPT_PREFIX)crypt$(EXESUFFICS) $(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS) $(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS) $(BUILDDIR)$(PREFIX)tcppm$(EXESUFFICS) $(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS) $(BUILDDIR)$(PREFIX)tlspr$(EXESUFFICS) $(BUILDDIR)$(PREFIX)socks$(EXESUFFICS) $(BUILDDIR)$(PREFIX)proxy$(EXESUFFICS) allplugins +all: $(BUILDDIR)3proxy$(EXESUFFICS) $(BUILDDIR)$(CRYPT_PREFIX)crypt$(EXESUFFICS) $(MAIL_EXES) $(FTP_EXES) $(BUILDDIR)$(PREFIX)tcppm$(EXESUFFICS) $(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS) $(BUILDDIR)$(PREFIX)tlspr$(EXESUFFICS) $(BUILDDIR)$(PREFIX)socks$(EXESUFFICS) $(BUILDDIR)$(PREFIX)proxy$(EXESUFFICS) allplugins sockmap$(OBJSUFFICS): sockmap.c proxy.h structures.h $(CC) $(CFLAGS) sockmap.c diff --git a/src/ftp.c b/src/ftp.c index a2c71a2..94cda64 100644 --- a/src/ftp.c +++ b/src/ftp.c @@ -7,6 +7,8 @@ #include "proxy.h" +#ifdef WITH_FTP + /* * Read one FTP server response, skipping continuation lines (lines whose * 4th character is '-' per RFC 959). Returns the line length on success, @@ -249,3 +251,5 @@ SOCKET ftpcommand(struct clientparam *param, unsigned char * command, unsigned c } return s; } + +#endif diff --git a/src/ftppr.c b/src/ftppr.c index 049bc93..abe1006 100644 --- a/src/ftppr.c +++ b/src/ftppr.c @@ -8,6 +8,8 @@ #include "proxy.h" +#ifdef WITH_FTP + #define RETURN(xxx) { param->res = xxx; goto CLEANRET; } #define BUFSIZE 2048 @@ -345,3 +347,16 @@ struct proxydef childdef = { }; #include "proxymain.c" #endif + +#else + +/* Built without FTP support. The service and the redirect naming it are + still known, so a configuration carrying them is read rather than + refused, and a client reaching one is turned away. */ +void * ftpprchild(struct clientparam * param){ + param->res = 878; + dolog(param, (unsigned char *)"ftp support is not built in"); + return NULL; +} + +#endif diff --git a/src/imapp.c b/src/imapp.c index 2d1e0db..c3f3b0d 100644 --- a/src/imapp.c +++ b/src/imapp.c @@ -8,6 +8,8 @@ #include "proxy.h" +#ifdef WITH_IMAPP + #define RETURN(xxx) { param->res = xxx; goto CLEANRET; } #define CL_LOGINCMD 0 @@ -250,3 +252,15 @@ struct proxydef childdef = { }; #include "proxymain.c" #endif +#else + +/* Built without this proxy of its own. The command and the redirect + naming it are the STARTTLS proxy speaking that protocol, which + negotiates the same way and passes the session on: what "tlspr -Ximap" + does, under the name a configuration already uses. */ +void * imappchild(struct clientparam * param){ + param->starttls = S_IMAPP; + return (void *)tlsprchild; +} + +#endif diff --git a/src/pop3p.c b/src/pop3p.c index 9bc1333..ccd3a08 100644 --- a/src/pop3p.c +++ b/src/pop3p.c @@ -8,6 +8,8 @@ #include "proxy.h" +#ifdef WITH_POP3P + #define RETURN(xxx) { param->res = xxx; goto CLEANRET; } #ifdef WITHMAIN @@ -88,3 +90,15 @@ struct proxydef childdef = { }; #include "proxymain.c" #endif +#else + +/* Built without this proxy of its own. The command and the redirect + naming it are the STARTTLS proxy speaking that protocol, which + negotiates the same way and passes the session on: what "tlspr -Xpop3" + does, under the name a configuration already uses. */ +void * pop3pchild(struct clientparam * param){ + param->starttls = S_POP3P; + return (void *)tlsprchild; +} + +#endif diff --git a/src/proxy.c b/src/proxy.c index a52d972..811f0af 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -385,10 +385,12 @@ for(;;){ if (!strncasecmp((char *)sb, "http://", 7)) { sb += 7; } +#ifdef WITH_FTP else if (!strncasecmp((char *)sb, "ftp://", 6)) { ftp = 1; sb += 6; } +#endif else if(*sb == '/') { param->transparent = 1; } @@ -712,6 +714,7 @@ for(;;){ #endif +#ifdef WITH_FTP if(ftp && param->redirtype != R_HTTP){ SOCKET s; int mode = 0; @@ -963,6 +966,7 @@ for(;;){ } RETURN(res); } +#endif if(isconnect && param->redirtype != R_HTTP) { if(param->redirectfunc) { diff --git a/src/smtpp.c b/src/smtpp.c index 3905bf0..6bde921 100644 --- a/src/smtpp.c +++ b/src/smtpp.c @@ -8,6 +8,8 @@ #include "proxy.h" +#ifdef WITH_SMTPP + #define RETURN(xxx) { param->res = xxx; goto CLEANRET; } #ifdef WITHMAIN @@ -342,3 +344,15 @@ struct proxydef childdef = { }; #include "proxymain.c" #endif +#else + +/* Built without this proxy of its own. The command and the redirect + naming it are the STARTTLS proxy speaking that protocol, which + negotiates the same way and passes the session on: what "tlspr -Xsmtp" + does, under the name a configuration already uses. */ +void * smtppchild(struct clientparam * param){ + param->starttls = S_SMTPP; + return (void *)tlsprchild; +} + +#endif diff --git a/src/structures.h b/src/structures.h index f7a9d42..459a6a5 100644 --- a/src/structures.h +++ b/src/structures.h @@ -759,6 +759,10 @@ struct clientparam { that a plugin built against an older header still finds the fields it knows where they were. */ int onerequest; + /* A STARTTLS protocol to speak before the session is wrapped, set for + one connection rather than for the service, which is how a redirect + and a service name standing in for a mail proxy reach tlspr. */ + PROXYSERVICE starttls; }; struct filemon { diff --git a/src/tlspr.c b/src/tlspr.c index 44f51c7..c6c343e 100644 --- a/src/tlspr.c +++ b/src/tlspr.c @@ -334,7 +334,8 @@ void * tlsprchild(struct clientparam* param) { int lv=-1; char proto[PROTOLEN]="-"; int snipos = 0; - PROXYSERVICE stlsproto = param->clientstarttls? param->clientstarttls : param->srv->srvstarttls; + PROXYSERVICE stlsproto = param->clientstarttls? param->clientstarttls : + (param->starttls? param->starttls : param->srv->srvstarttls); if(!param->clientstarttls && stlsproto){ res = clistarttls(param, stlsproto);