Added imapp, starttls support for smtpp, pop3p, tlspr

This commit is contained in:
Vladimir Dubrovin 2026-07-22 16:15:50 +03:00
parent 7798f78137
commit 9ab2e820b5
27 changed files with 893 additions and 122 deletions

3
.gitignore vendored
View File

@ -18,6 +18,7 @@ bin/socks
bin/tcppm bin/tcppm
bin/udppm bin/udppm
bin/pop3p bin/pop3p
bin/imapp
bin/smtpp bin/smtpp
bin/ftppr bin/ftppr
bin/mycrypt bin/mycrypt
@ -45,6 +46,7 @@ src/socks
src/tcppm src/tcppm
src/udppm src/udppm
src/pop3p src/pop3p
src/imapp
src/smtpp src/smtpp
src/ftppr src/ftppr
src/icqpr src/icqpr
@ -261,6 +263,7 @@ CLAUDE.md
bin/3proxy_crypt bin/3proxy_crypt
bin/3proxy_ftppr bin/3proxy_ftppr
bin/3proxy_pop3p bin/3proxy_pop3p
bin/3proxy_imapp
bin/3proxy_proxy bin/3proxy_proxy
bin/3proxy_smtpp bin/3proxy_smtpp
bin/3proxy_socks bin/3proxy_socks

View File

@ -70,6 +70,7 @@ option(3PROXY_BUILD_NONE "Do not build standalone binaries" OFF)
option(3PROXY_BUILD_PROXY "Build standalone proxy binary" ON) option(3PROXY_BUILD_PROXY "Build standalone proxy binary" ON)
option(3PROXY_BUILD_SOCKS "Build standalone socks binary" ON) option(3PROXY_BUILD_SOCKS "Build standalone socks binary" ON)
option(3PROXY_BUILD_POP3P "Build standalone pop3p binary" ON) 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_SMTPP "Build standalone smtpp binary" ON)
option(3PROXY_BUILD_FTPPR "Build standalone ftppr binary" ON) option(3PROXY_BUILD_FTPPR "Build standalone ftppr binary" ON)
option(3PROXY_BUILD_TCPPM "Build standalone tcppm binary" ON) option(3PROXY_BUILD_TCPPM "Build standalone tcppm binary" ON)
@ -77,7 +78,7 @@ option(3PROXY_BUILD_UDPPM "Build standalone udppm binary" ON)
option(3PROXY_BUILD_TLSPR "Build standalone tlspr binary" ON) option(3PROXY_BUILD_TLSPR "Build standalone tlspr binary" ON)
if(3PROXY_BUILD_NONE) if(3PROXY_BUILD_NONE)
foreach(_M PROXY SOCKS POP3P SMTPP FTPPR TCPPM UDPPM TLSPR) foreach(_M PROXY SOCKS POP3P IMAPP SMTPP FTPPR TCPPM UDPPM TLSPR)
set(3PROXY_BUILD_${_M} OFF) set(3PROXY_BUILD_${_M} OFF)
endforeach() endforeach()
endif() endif()
@ -388,6 +389,7 @@ endif()
add_library(srv_modules OBJECT add_library(srv_modules OBJECT
src/proxy.c src/proxy.c
src/pop3p.c src/pop3p.c
src/imapp.c
src/smtpp.c src/smtpp.c
src/ftppr.c src/ftppr.c
src/tcppm.c src/tcppm.c
@ -628,7 +630,7 @@ else()
endif() endif()
# Build standalone proxy executables # Build standalone proxy executables
foreach(PROXY_NAME proxy socks pop3p smtpp ftppr tcppm udppm tlspr) foreach(PROXY_NAME proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr)
string(TOUPPER "${PROXY_NAME}" _MODULE_OPT) string(TOUPPER "${PROXY_NAME}" _MODULE_OPT)
if(NOT 3PROXY_BUILD_${_MODULE_OPT}) if(NOT 3PROXY_BUILD_${_MODULE_OPT})
continue() continue()
@ -723,7 +725,7 @@ install(TARGETS 3proxy 3proxy_crypt
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
) )
foreach(PROXY_NAME proxy socks pop3p smtpp ftppr tcppm udppm tlspr) foreach(PROXY_NAME proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr)
string(TOUPPER "${PROXY_NAME}" _MODULE_OPT) string(TOUPPER "${PROXY_NAME}" _MODULE_OPT)
if(3PROXY_BUILD_${_MODULE_OPT}) if(3PROXY_BUILD_${_MODULE_OPT})
install(TARGETS ${PROXY_NAME} install(TARGETS ${PROXY_NAME}
@ -886,7 +888,7 @@ if(NOT WIN32)
) )
endif() endif()
# Module man pages installed with binary prefix only if module is built # Module man pages installed with binary prefix only if module is built
foreach(_MAN proxy socks pop3p smtpp ftppr tcppm udppm tlspr) foreach(_MAN proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr)
string(TOUPPER "${_MAN}" _MODULE_OPT) string(TOUPPER "${_MAN}" _MODULE_OPT)
if(3PROXY_BUILD_${_MODULE_OPT}) if(3PROXY_BUILD_${_MODULE_OPT})
set(_MAN_SRC "${CMAKE_CURRENT_SOURCE_DIR}/man/${_MAN}.8") set(_MAN_SRC "${CMAKE_CURRENT_SOURCE_DIR}/man/${_MAN}.8")
@ -938,7 +940,7 @@ message(STATUS " Plugins to build: ${ALL_PLUGINS}")
message(STATUS "") message(STATUS "")
message(STATUS " Standalone modules:") message(STATUS " Standalone modules:")
message(STATUS " Binary prefix: \"${3PROXY_BINARY_PREFIX}\"") message(STATUS " Binary prefix: \"${3PROXY_BINARY_PREFIX}\"")
foreach(_M proxy socks pop3p smtpp ftppr tcppm udppm tlspr) foreach(_M proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr)
string(TOUPPER "${_M}" _MO) string(TOUPPER "${_M}" _MO)
message(STATUS " BUILD_${_MO}: ${3PROXY_BUILD_${_MO}}") message(STATUS " BUILD_${_MO}: ${3PROXY_BUILD_${_MO}}")
endforeach() endforeach()

View File

@ -84,7 +84,7 @@ install: all
if [ ! -d "$(DESTDIR)$(BINPREFIX)" ]; then mkdir -p $(DESTDIR)$(BINPREFIX)/; fi if [ ! -d "$(DESTDIR)$(BINPREFIX)" ]; then mkdir -p $(DESTDIR)$(BINPREFIX)/; fi
install bin/3proxy $(DESTDIR)$(BINPREFIX)/3proxy install bin/3proxy $(DESTDIR)$(BINPREFIX)/3proxy
install bin/$(CRYPT_PREFIX)crypt $(DESTDIR)$(BINPREFIX)/$(CRYPT_PREFIX)crypt install bin/$(CRYPT_PREFIX)crypt $(DESTDIR)$(BINPREFIX)/$(CRYPT_PREFIX)crypt
for f in proxy socks pop3p smtpp ftppr tcppm udppm tlspr; do \ for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr; do \
if [ -f bin/$(PREFIX)$$f ]; then install bin/$(PREFIX)$$f $(DESTDIR)$(BINPREFIX)/$(PREFIX)$$f; fi; \ if [ -f bin/$(PREFIX)$$f ]; then install bin/$(PREFIX)$$f $(DESTDIR)$(BINPREFIX)/$(PREFIX)$$f; fi; \
done done
install -d $(DESTDIR)$(prefix)/etc/3proxy/conf install -d $(DESTDIR)$(prefix)/etc/3proxy/conf
@ -101,7 +101,7 @@ install: all
touch $(DESTDIR)$(prefix)/etc/3proxy/conf/bandlimiters touch $(DESTDIR)$(prefix)/etc/3proxy/conf/bandlimiters
install -d $(DESTDIR)$(MANDIR)/man8 install -d $(DESTDIR)$(MANDIR)/man8
install -m 644 man/3proxy.8 $(DESTDIR)$(MANDIR)/man8/3proxy.8 install -m 644 man/3proxy.8 $(DESTDIR)$(MANDIR)/man8/3proxy.8
for f in proxy socks pop3p smtpp ftppr tcppm udppm tlspr; do \ for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr; do \
if [ -f man/$$f.8 ]; then install -m 644 man/$$f.8 $(DESTDIR)$(MANDIR)/man8/$(PREFIX)$$f.8; fi; \ if [ -f man/$$f.8 ]; then install -m 644 man/$$f.8 $(DESTDIR)$(MANDIR)/man8/$(PREFIX)$$f.8; fi; \
done done
install -m 644 man/3proxy_crypt.8 $(DESTDIR)$(MANDIR)/man8/$(CRYPT_PREFIX)crypt.8 install -m 644 man/3proxy_crypt.8 $(DESTDIR)$(MANDIR)/man8/$(CRYPT_PREFIX)crypt.8

View File

@ -94,7 +94,8 @@ INSTALL_DATA = $(INSTALL) -m 644
INSTALL_OBJS = bin/3proxy \ INSTALL_OBJS = bin/3proxy \
bin/$(CRYPT_PREFIX)crypt \ bin/$(CRYPT_PREFIX)crypt \
bin/$(PREFIX)ftppr \ bin/$(PREFIX)ftppr \
bin/$(PREFIX)pop3p \ bin/$(PREFIX)imapp \
bin/$(PREFIX)pop3p \
bin/$(PREFIX)proxy \ bin/$(PREFIX)proxy \
bin/$(PREFIX)smtpp \ bin/$(PREFIX)smtpp \
bin/$(PREFIX)socks \ bin/$(PREFIX)socks \
@ -157,7 +158,7 @@ install-man:
$(INSTALL_BIN) -d $(MANDIR8) $(INSTALL_BIN) -d $(MANDIR8)
$(INSTALL_DATA) man/3proxy.cfg.5 $(MANDIR5) $(INSTALL_DATA) man/3proxy.cfg.5 $(MANDIR5)
$(INSTALL_DATA) man/3proxy.8 $(MANDIR8) $(INSTALL_DATA) man/3proxy.8 $(MANDIR8)
for f in proxy socks pop3p smtpp ftppr tcppm udppm tlspr; do \ for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr; do \
if [ -f man/$$f.8 ]; then $(INSTALL_DATA) man/$$f.8 $(MANDIR8)/$(PREFIX)$$f.8; fi; \ if [ -f man/$$f.8 ]; then $(INSTALL_DATA) man/$$f.8 $(MANDIR8)/$(PREFIX)$$f.8; fi; \
done done
$(INSTALL_DATA) man/3proxy_crypt.8 $(MANDIR8)/$(CRYPT_PREFIX)crypt.8 $(INSTALL_DATA) man/3proxy_crypt.8 $(MANDIR8)/$(CRYPT_PREFIX)crypt.8

View File

@ -86,7 +86,7 @@ install: all
if [ ! -d "$(DESTDIR)$(BINPREFIX)" ]; then mkdir -p $(DESTDIR)$(BINPREFIX)/; fi if [ ! -d "$(DESTDIR)$(BINPREFIX)" ]; then mkdir -p $(DESTDIR)$(BINPREFIX)/; fi
install bin/3proxy $(DESTDIR)$(BINPREFIX)/3proxy install bin/3proxy $(DESTDIR)$(BINPREFIX)/3proxy
install bin/$(CRYPT_PREFIX)crypt $(DESTDIR)$(BINPREFIX)/$(CRYPT_PREFIX)crypt install bin/$(CRYPT_PREFIX)crypt $(DESTDIR)$(BINPREFIX)/$(CRYPT_PREFIX)crypt
for f in proxy socks pop3p smtpp ftppr tcppm udppm tlspr; do \ for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr; do \
if [ -f bin/$(PREFIX)$$f ]; then install bin/$(PREFIX)$$f $(DESTDIR)$(BINPREFIX)/$(PREFIX)$$f; fi; \ if [ -f bin/$(PREFIX)$$f ]; then install bin/$(PREFIX)$$f $(DESTDIR)$(BINPREFIX)/$(PREFIX)$$f; fi; \
done done
install -d $(DESTDIR)$(prefix)/etc/3proxy/conf install -d $(DESTDIR)$(prefix)/etc/3proxy/conf
@ -103,7 +103,7 @@ install: all
touch $(DESTDIR)$(prefix)/etc/3proxy/conf/bandlimiters touch $(DESTDIR)$(prefix)/etc/3proxy/conf/bandlimiters
install -d $(DESTDIR)$(MANDIR)/man8 install -d $(DESTDIR)$(MANDIR)/man8
install -m 644 man/3proxy.8 $(DESTDIR)$(MANDIR)/man8/3proxy.8 install -m 644 man/3proxy.8 $(DESTDIR)$(MANDIR)/man8/3proxy.8
for f in proxy socks pop3p smtpp ftppr tcppm udppm tlspr; do \ for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr; do \
if [ -f man/$$f.8 ]; then install -m 644 man/$$f.8 $(DESTDIR)$(MANDIR)/man8/$(PREFIX)$$f.8; fi; \ if [ -f man/$$f.8 ]; then install -m 644 man/$$f.8 $(DESTDIR)$(MANDIR)/man8/$(PREFIX)$$f.8; fi; \
done done
install -m 644 man/3proxy_crypt.8 $(DESTDIR)$(MANDIR)/man8/$(CRYPT_PREFIX)crypt.8 install -m 644 man/3proxy_crypt.8 $(DESTDIR)$(MANDIR)/man8/$(CRYPT_PREFIX)crypt.8

View File

@ -592,6 +592,48 @@ proxy -p8080 -i192.168.2.1
2 - require TLS, check both client and server HELLO 2 - require TLS, check both client and server HELLO
3 - require TLS, check that the server sends a certificate (not compatible with TLS 1.3) 3 - require TLS, check that the server sends a certificate (not compatible with TLS 1.3)
4 - require mutual TLS, check that the server sends a certificate request and the client sends a certificate (not compatible with TLS 1.3) 4 - require mutual TLS, check that the server sends a certificate request and the client sends a certificate (not compatible with TLS 1.3)
-Ximap | -Xpop3 | -Xsmtp - explicit TLS (STARTTLS) mode: tlspr speaks the plaintext
protocol with the client (greeting, STARTTLS command), then upgrades both sides to TLS
</pre>
<p>
<b>Implicit vs explicit TLS:</b>
</p><p>
Implicit TLS means TLS from the first byte of the connection: https (443), imaps (993), submissions (465).
Explicit TLS means the connection starts in plaintext and is upgraded with a STARTTLS/STLS command: imap (143), submission (587), pop3 (110).
tlspr supports both: for implicit TLS the destination host is taken from SNI and the port from -P; for explicit TLS
the -X option makes tlspr speak the plaintext protocol phase with the client (greeting, STARTTLS command) before
upgrading both sides to TLS. Example:
</p><pre>
# https (implicit)
tlspr -p443 -P443 -c1
# imaps (implicit)
tlspr -p993 -P993 -c1
# submissions (implicit)
tlspr -p465 -P465 -c1
# imap STARTTLS (explicit)
tlspr -p143 -P143 -Ximap
# submission STARTTLS (explicit)
tlspr -p587 -P587 -Xsmtp
# pop3 STLS (explicit)
tlspr -p110 -P110 -Xpop3
</pre>
<p>
Note: for explicit TLS the protocol services smtpp, imapp and pop3p can be used instead of tlspr -X; they also
support STARTTLS.
</p><p>
<b>Recommended setup - traffic redirection:</b> the most universal configuration is to redirect TLS traffic
(ports 443, 993, 465, 143, 587, 110) to tlspr with external router rules or local redirection (Transparent plugin).
The original destination address and port are preserved, no -P or per-port services are required, and both implicit
and explicit TLS work with the same installation.
</p><pre>
auth iponly
allow *
tlspr -p1443 -c1
</pre>
<p>
with, for example, iptables:
</p><pre>
iptables -t nat -A PREROUTING -p tcp -m multiport --dports 443,993,465 -j REDIRECT --to-port 1443
</pre> </pre>
<p> <p>
<b>SNI Break (DPI Bypass):</b> <b>SNI Break (DPI Bypass):</b>

View File

@ -29,6 +29,7 @@ from the configuration file like an independent service
.BR proxy (8) .BR proxy (8)
.BR socks (8) .BR socks (8)
.BR pop3p (8) .BR pop3p (8)
.BR imapp (8)
.BR tcppm (8) .BR tcppm (8)
.BR udppm (8) .BR udppm (8)
.BR ftppr (8) .BR ftppr (8)
@ -140,7 +141,7 @@ configuration file
Report all bugs to Report all bugs to
.BR 3proxy@3proxy.org .BR 3proxy@3proxy.org
.SH SEE ALSO .SH SEE ALSO
3proxy.cfg(5), proxy(8), ftppr(8), socks(8), pop3p(8), tcppm(8), udppm(8), 3proxy.cfg(5), proxy(8), ftppr(8), socks(8), pop3p(8), imapp(8), tcppm(8), udppm(8),
kill(1), syslogd(8), kill(1), syslogd(8),
.br .br
https://3proxy.org/ https://3proxy.org/

View File

@ -55,6 +55,9 @@ Recursion is not allowed.
.B pop3p .B pop3p
[options] [options]
.br .br
.B imapp
[options]
.br
.B smtpp .B smtpp
[options] [options]
.br .br
@ -92,6 +95,9 @@ Proxy with protocol autoselection between proxy / socks / tlspr
.B pop3p .B pop3p
POP3 proxy (default port 110) POP3 proxy (default port 110)
.br .br
.B imapp
IMAPv4 proxy (default port 143)
.br
.B smtpp .B smtpp
SMTP proxy (default port 25) SMTP proxy (default port 25)
.br .br
@ -209,6 +215,7 @@ Never ask for username/password
.BR proxy (8) .BR proxy (8)
.BR socks (8) .BR socks (8)
.BR pop3p (8) .BR pop3p (8)
.BR imapp (8)
.BR tcppm (8) .BR tcppm (8)
.BR udppm (8) .BR udppm (8)
.BR ftppr (8) .BR ftppr (8)
@ -847,6 +854,9 @@ locally redirects to
.B pop3 .B pop3
locally redirects to locally redirects to
.B pop3p .B pop3p
.B imap
locally redirects to
.B imapp
.B http .B http
locally redirects to locally redirects to
.B proxy .B proxy
@ -1384,7 +1394,7 @@ authentication and/or allow/deny ACLs.
Report all bugs to Report all bugs to
.BR 3proxy@3proxy.org .BR 3proxy@3proxy.org
.SH SEE ALSO .SH SEE ALSO
3proxy(8), 3proxy_crypt(8), proxy(8), ftppr(8), socks(8), pop3p(8), smtpp(8), tlspr(8), tcppm(8), udppm(8), syslogd(8), 3proxy(8), 3proxy_crypt(8), proxy(8), ftppr(8), socks(8), pop3p(8), imapp(8), smtpp(8), tlspr(8), tcppm(8), udppm(8), syslogd(8),
.br .br
https://3proxy.org/ https://3proxy.org/
.SH AUTHORS .SH AUTHORS

124
man/imapp.8 Normal file
View File

@ -0,0 +1,124 @@
.TH imapp "8" "July 2026" "3proxy 0.9" "Universal proxy server"
.SH NAME
.B imapp
\- IMAPv4 proxy gateway service
.SH SYNOPSIS
.BR "imapp " [ -d ]
.IB \fR[ -l \fR[ \fR[ @ \fR] logfile \fR]]
.IB \fR[ -p port\fR]
.IB \fR[ -i internal_ip\fR]
.IB \fR[ -e external_ip\fR]
.IB \fR[ -h default_ip[:port]\fR]
.IB \fR[ -x ]
.SH DESCRIPTION
.B imapp
is IMAPv4 (IMAP4rev1) gateway service to allow internal users to access external
IMAP servers.
.SH OPTIONS
.TP
.B -I
Inetd mode. Standalone service only.
.TP
.B -d
Daemonize. Detach service from console and run in the background.
.TP
.B -t
Be silenT. Do not log start/stop/accept error records.
.TP
.B -u
Never look for username authentication.
.TP
.B -e
External address. IP address of the interface the proxy should initiate connections
from.
By default, the system will decide which address to use in accordance
with the routing table.
.TP
.B \-ni\fIPATH\fR
(Linux only) Switch to the network namespace identified by
.I PATH
before opening the listening socket. The current namespace is saved and restored
immediately after binding, so outgoing connections run in the original namespace
unless
.B \-ne
is also given.
.TP
.B \-ne\fIPATH\fR
(Linux only) Switch to the network namespace identified by
.I PATH
after the listening socket has been bound (and after restoring from
.B \-ni
if applicable). Both options accept any namespace file path
(e.g.\& \fI/var/run/netns/myns\fR or \fI/proc/PID/ns/net\fR)
and require \fBCAP_SYS_ADMIN\fR.
.TP
.B -i
Internal address. IP address the proxy accepts connections to.
By default, connections to any interface are accepted. It\'s usually unsafe.
Unix domain sockets can be specified with
.I -iunix:/path/to/socket
syntax (e.g., -iunix:/var/run/imapp.sock). On Linux, abstract sockets use
.I -iunix:@socketname
syntax.
.TP
.B -p
Port. Port proxy listens for incoming connections. Default is 143.
.TP
.B -h
Default destination. It's used if the target address is not specified by the user.
.TP
.B -x
Disable STARTTLS support. STARTTLS is not announced in the CAPABILITY
response and the STARTTLS command is not accepted.
.TP
.B -l
Log. By default logging is to stdout. If
.I logfile
is specified logging is to file. Under Unix, if
.RI \' @ \'
precedes
.IR logfile ,
syslog is used for logging.
.TP
.B -S
Increase or decrease stack size. You may want to try something like -S8192 if you experience 3proxy
crashes.
.SH CLIENTS
You can use any MUA (Mail User Agent) with IMAPv4 support. Set the client to use
.I internal_ip
and
.IR port
as an IMAP server. The address of the real IMAP server must be configured as a part of
the IMAP username. The format for the username is
.IR username @ server ,
where
.I server
is the address of the IMAP server and
.I username
is the user\'s login on this IMAP server. The login itself may contain an \'@\' sign.
Supported client authentication methods are the LOGIN command, AUTHENTICATE PLAIN
and AUTHENTICATE LOGIN. With the server, the proxy authenticates using the method
chosen by the client if the server supports it (as advertised in the CAPABILITY
response); otherwise it falls back to AUTHENTICATE LOGIN, AUTHENTICATE PLAIN or
the LOGIN command, in this order of preference. Challenge-response authentication
(CRAM-MD5, etc.) is not supported, because it requires a challenge from the server
before we know which server to connect to.
When running as a 3proxy service (not as a standalone binary), STARTTLS is
supported and announced in the CAPABILITY response unless disabled with
.BR -x .
After the client issues STARTTLS, the connection is handled by
.BR tlspr (8):
the destination host is taken from the SNI of the client TLS handshake (or from
the -h option), the proxy performs STARTTLS negotiation with the destination
server, and then transparently passes TLS traffic between the client and the
server. If the destination server does not support STARTTLS, the TLS handshake
with the client fails.
.SH BUGS
Report all bugs to
.BR 3proxy@3proxy.org
.SH SEE ALSO
3proxy(8), ftppr(8), pop3p(8), proxy(8), smtpp(8), socks(8), tcppm(8), tlspr(8), udppm(8), syslogd(8),
.br
https://3proxy.org/
.SH AUTHORS
3proxy is designed by Vladimir Dubrovin <vlad@3proxy.org>

View File

@ -9,6 +9,7 @@
.IB \fR[ -i internal_ip\fR] .IB \fR[ -i internal_ip\fR]
.IB \fR[ -e external_ip\fR] .IB \fR[ -e external_ip\fR]
.IB \fR[ -h default_ip[:port]\fR] .IB \fR[ -h default_ip[:port]\fR]
.IB \fR[ -x ]
.SH DESCRIPTION .SH DESCRIPTION
.B pop3p .B pop3p
is POP3 gateway service to allow internal users to access external POP3 is POP3 gateway service to allow internal users to access external POP3
@ -66,6 +67,10 @@ Port. Port proxy listens for incoming connections. Default is 110.
.B -h .B -h
Default destination. It's used if the target address is not specified by the user. Default destination. It's used if the target address is not specified by the user.
.TP .TP
.B -x
Disable STARTTLS (STLS) support. STLS is not announced in the CAPA response
and the STLS command is not accepted.
.TP
.B -l .B -l
Log. By default logging is to stdout. If Log. By default logging is to stdout. If
.I logfile .I logfile
@ -94,6 +99,16 @@ is the user\'s login on this POP3 server. The login itself may contain an \'@\'
Only cleartext authentication is supported, because challenge-response Only cleartext authentication is supported, because challenge-response
authentication (APOP, CRAM-MD5, etc.) requires a challenge from the server before authentication (APOP, CRAM-MD5, etc.) requires a challenge from the server before
we know which server to connect to. we know which server to connect to.
When running as a 3proxy service (not as a standalone binary), STLS is
supported and announced in the CAPA response unless disabled with
.BR -x .
After the client issues STLS, the connection is handled by
.BR tlspr (8):
the destination host is taken from the SNI of the client TLS handshake (or from
the -h option), the proxy performs STLS negotiation with the destination
server, and then transparently passes TLS traffic between the client and the
server. If the destination server does not support STLS, the TLS handshake
with the client fails.
.SH BUGS .SH BUGS
Report all bugs to Report all bugs to
.BR 3proxy@3proxy.org .BR 3proxy@3proxy.org

View File

@ -9,6 +9,7 @@
.IB \fR[ -i internal_ip\fR] .IB \fR[ -i internal_ip\fR]
.IB \fR[ -e external_ip\fR] .IB \fR[ -e external_ip\fR]
.IB \fR[ -h default_ip[:port]\fR] .IB \fR[ -h default_ip[:port]\fR]
.IB \fR[ -x ]
.SH DESCRIPTION .SH DESCRIPTION
.B smtpp .B smtpp
is SMTP gateway service to allow internal users to access external SMTP is SMTP gateway service to allow internal users to access external SMTP
@ -61,11 +62,15 @@ syntax (e.g., -iunix:/var/run/smtpp.sock). On Linux, abstract sockets use
syntax. syntax.
.TP .TP
.B -p .B -p
Port. Port proxy listens for incoming connections. Default is 25. Port. Port proxy listens for incoming connections. Default is 587.
.TP .TP
.B -h .B -h
Default destination. It's used if the target address is not specified by the user. Default destination. It's used if the target address is not specified by the user.
.TP .TP
.B -x
Disable STARTTLS support. STARTTLS is not announced in the EHLO response
and the STARTTLS command is not accepted.
.TP
.B -l .B -l
Log. By default logging is to stdout. If Log. By default logging is to stdout. If
.I logfile .I logfile
@ -95,6 +100,16 @@ is the user\'s login on this SMTP server. The login itself may contain an \'@\'
Only cleartext authentication is supported, because challenge-response Only cleartext authentication is supported, because challenge-response
authentication (CRAM-MD5, SPA, etc.) requires a challenge from the server before authentication (CRAM-MD5, SPA, etc.) requires a challenge from the server before
we know which server to connect to. we know which server to connect to.
When running as a 3proxy service (not as a standalone binary), STARTTLS is
supported and announced in the EHLO response unless disabled with
.BR -x .
After the client issues STARTTLS, the connection is handled by
.BR tlspr (8):
the destination host is taken from the SNI of the client TLS handshake (or from
the -h option), the proxy performs STARTTLS negotiation with the destination
server, and then transparently passes TLS traffic between the client and the
server. If the destination server does not support STARTTLS, the TLS handshake
with the client fails.
.SH BUGS .SH BUGS
Report all bugs to Report all bugs to
.BR 3proxy@3proxy.org .BR 3proxy@3proxy.org

View File

@ -78,6 +78,15 @@ TLS_CHECK_LEVEL. 0 (default) - allow non-TLS traffic to pass, 1 - require TLS, o
.B -s .B -s
Split the TLS Client HELLO packet across multiple TCP segments to make SNI-based DPI detection harder. An optional numeric value can follow (e.g. \fB-s1\fR) to control the splitting behaviour. Split the TLS Client HELLO packet across multiple TCP segments to make SNI-based DPI detection harder. An optional numeric value can follow (e.g. \fB-s1\fR) to control the splitting behaviour.
.TP .TP
.B -Ximap | -Xpop3 | -Xsmtp
STARTTLS mode for the given protocol. The proxy speaks the plaintext protocol
with the client (greeting, capability advertisement with STARTTLS only, STARTTLS
command), then, after the client issues STARTTLS and sends a TLS Client HELLO,
connects to the destination taken from SNI (default port 143/110/587), performs
STARTTLS negotiation with the destination server and transparently passes TLS
traffic. If the destination server does not support STARTTLS, the TLS handshake
with the client fails.
.TP
.B -l .B -l
Log. By default logging is to stdout. If Log. By default logging is to stdout. If
.I logfile .I logfile

View File

@ -537,6 +537,7 @@ int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int
#endif #endif
freeconf(&conf); freeconf(&conf);
initcommands();
res = readconfig(fp); res = readconfig(fp);
conf.version++; conf.version++;

View File

@ -2,7 +2,7 @@
# 3 proxy common Makefile # 3 proxy common Makefile
# #
all: $(BUILDDIR)3proxy$(EXESUFFICS) $(BUILDDIR)$(CRYPT_PREFIX)crypt$(EXESUFFICS) $(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(BUILDDIR)$(PREFIX)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) $(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
sockmap$(OBJSUFFICS): sockmap.c proxy.h structures.h sockmap$(OBJSUFFICS): sockmap.c proxy.h structures.h
$(CC) $(CFLAGS) sockmap.c $(CC) $(CFLAGS) sockmap.c
@ -31,6 +31,9 @@ proxy$(OBJSUFFICS): proxy.c proxy.h structures.h proxymain.c
pop3p$(OBJSUFFICS): pop3p.c proxy.h structures.h proxymain.c pop3p$(OBJSUFFICS): pop3p.c proxy.h structures.h proxymain.c
$(CC) $(CFLAGS) $(DEFINEOPTION)WITHMAIN $(DEFINEOPTION)NOPORTMAP $(DEFINEOPTION)NOUDPMAIN pop3p.c $(CC) $(CFLAGS) $(DEFINEOPTION)WITHMAIN $(DEFINEOPTION)NOPORTMAP $(DEFINEOPTION)NOUDPMAIN pop3p.c
imapp$(OBJSUFFICS): imapp.c proxy.h structures.h proxymain.c
$(CC) $(CFLAGS) $(DEFINEOPTION)WITHMAIN $(DEFINEOPTION)NOPORTMAP $(DEFINEOPTION)NOUDPMAIN imapp.c
smtpp$(OBJSUFFICS): smtpp.c proxy.h structures.h proxymain.c smtpp$(OBJSUFFICS): smtpp.c proxy.h structures.h proxymain.c
$(CC) $(CFLAGS) $(DEFINEOPTION)WITHMAIN $(DEFINEOPTION)NOPORTMAP $(DEFINEOPTION)NOUDPMAIN smtpp.c $(CC) $(CFLAGS) $(DEFINEOPTION)WITHMAIN $(DEFINEOPTION)NOPORTMAP $(DEFINEOPTION)NOUDPMAIN smtpp.c
@ -59,6 +62,9 @@ $(BUILDDIR)$(PREFIX)proxy$(EXESUFFICS): sockmap$(OBJSUFFICS) proxy$(OBJSUFFICS)
$(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS): sockmap$(OBJSUFFICS) pop3p$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) $(COMPATLIBS) $(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS): sockmap$(OBJSUFFICS) pop3p$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) $(COMPATLIBS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) pop3p$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(COMPATLIBS) $(LIBS) $(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) pop3p$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
$(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS): sockmap$(OBJSUFFICS) imapp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) base64$(OBJSUFFICS) $(COMPATLIBS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) imapp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) base64$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
$(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS): sockmap$(OBJSUFFICS) smtpp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) base64$(OBJSUFFICS) $(COMPATLIBS) $(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS): sockmap$(OBJSUFFICS) smtpp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) base64$(OBJSUFFICS) $(COMPATLIBS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) smtpp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) base64$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(COMPATLIBS) $(LIBS) $(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) smtpp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) base64$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
@ -86,6 +92,9 @@ srvproxy$(OBJSUFFICS): proxy.c proxy.h structures.h
srvpop3p$(OBJSUFFICS): pop3p.c proxy.h structures.h srvpop3p$(OBJSUFFICS): pop3p.c proxy.h structures.h
$(CC) $(COUT)srvpop3p$(OBJSUFFICS) $(CFLAGS) pop3p.c $(CC) $(COUT)srvpop3p$(OBJSUFFICS) $(CFLAGS) pop3p.c
srvimapp$(OBJSUFFICS): imapp.c proxy.h structures.h
$(CC) $(COUT)srvimapp$(OBJSUFFICS) $(CFLAGS) imapp.c
srvsmtpp$(OBJSUFFICS): smtpp.c proxy.h structures.h srvsmtpp$(OBJSUFFICS): smtpp.c proxy.h structures.h
$(CC) $(COUT)srvsmtpp$(OBJSUFFICS) $(CFLAGS) smtpp.c $(CC) $(COUT)srvsmtpp$(OBJSUFFICS) $(CFLAGS) smtpp.c
@ -179,6 +188,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) 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) srvwebadmin$(OBJSUFFICS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) mdhash$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_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) srvwebadmin$(OBJSUFFICS) 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) 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) srvwebadmin$(OBJSUFFICS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) mdhash$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_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) srvwebadmin$(OBJSUFFICS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) mdhash$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(COMPATLIBS) $(LIBS) $(PCRE_LIBS)

View File

@ -499,6 +499,14 @@ int parsehostname(char *hostname, struct clientparam *param, uint16_t port){
if(se){ if(se){
*se = 0; *se = 0;
} }
if(!*hostname){
if(sp){
port = atoi(sp+1);
*sp = ':';
}
*SAPORT(&param->req) = htons(port);
return 0;
}
if(hostname != (char *)param->hostname){ if(hostname != (char *)param->hostname){
if(param->hostname) free(param->hostname); if(param->hostname) free(param->hostname);
param->hostname = (unsigned char *)strdup(hostname + (se!=0)); param->hostname = (unsigned char *)strdup(hostname + (se!=0));
@ -553,14 +561,14 @@ int parseconnusername(char *username, struct clientparam *param, int extpasswd,
if(!username || !*username) return 1; if(!username || !*username) return 1;
if ((sb=strchr(username, conf.delimchar)) == NULL){ if ((sb=strchr(username, conf.delimchar)) == NULL){
if(!param->hostname && param->remsock == INVALID_SOCKET) return 2; if(!param->hostname && param->remsock == INVALID_SOCKET) return 2;
if(param->hostname)parsehostname((char *)param->hostname, param, port); if(param->hostname)parsehostname((char *)param->hostname, param, *SAPORT(&param->req)? ntohs(*SAPORT(&param->req)) : port);
return parseusername(username, param, extpasswd); return parseusername(username, param, extpasswd);
} }
while ((se=strchr(sb+1, conf.delimchar)))sb=se; while ((se=strchr(sb+1, conf.delimchar)))sb=se;
*(sb) = 0; *(sb) = 0;
if(parseusername(username, param, extpasswd)) return 3; if(parseusername(username, param, extpasswd)) return 3;
*(sb) = conf.delimchar; *(sb) = conf.delimchar;
if(parsehostname(sb+1, param, port)) return 4; if(parsehostname(sb+1, param, *SAPORT(&param->req)? ntohs(*SAPORT(&param->req)) : port)) return 4;
return 0; return 0;
} }
@ -872,3 +880,21 @@ uint32_t getip46(int family, unsigned char *name, struct sockaddr *sa){
return 0; return 0;
#endif #endif
} }
int hascap(const unsigned char *line, const char *cap){
int len = (int)strlen(cap);
for(; *line; line++) if(!strncasecmp((char *)line, cap, len)) return 1;
return 0;
}
int getmultiline(struct clientparam *param, DIRECTION which, unsigned char *buf, int bufsize, const char *cap, int *found){
int i;
do {
i = sockgetlinebuf(param, which, buf, bufsize, '\n', conf.timeouts[STRING_L]);
if(i > 0 && cap && found && !*found){
buf[i] = 0;
if(hascap(buf, cap)) *found = 1;
}
} while (i > 3 && buf[3] == '-');
return i;
}

View File

@ -191,14 +191,21 @@ static int h_proxy(int argc, unsigned char ** argv){
childdef.port = 110; childdef.port = 110;
childdef.isudp = 0; childdef.isudp = 0;
childdef.service = S_POP3P; childdef.service = S_POP3P;
childdef.helpmessage = " -hdefault_host[:port] - use this host and port as default if no host specified\n"; childdef.helpmessage = " -hdefault_host[:port] - use this host and port as default if no host specified\n -x - disable STARTTLS\n";
}
else if(!strcmp((char *)argv[0], "imapp")) {
childdef.pf = imappchild;
childdef.port = 143;
childdef.isudp = 0;
childdef.service = S_IMAPP;
childdef.helpmessage = " -hdefault_host[:port] - use this host and port as default if no host specified\n -x - disable STARTTLS\n";
} }
else if(!strcmp((char *)argv[0], "smtpp")) { else if(!strcmp((char *)argv[0], "smtpp")) {
childdef.pf = smtppchild; childdef.pf = smtppchild;
childdef.port = 25; childdef.port = 587;
childdef.isudp = 0; childdef.isudp = 0;
childdef.service = S_SMTPP; childdef.service = S_SMTPP;
childdef.helpmessage = " -hdefault_host[:port] - use this host and port as default if no host specified\n"; childdef.helpmessage = " -hdefault_host[:port] - use this host and port as default if no host specified\n -x - disable STARTTLS\n";
} }
else if(!strcmp((char *)argv[0], "ftppr")) { else if(!strcmp((char *)argv[0], "ftppr")) {
childdef.pf = ftpprchild; childdef.pf = ftpprchild;
@ -743,6 +750,7 @@ struct redirdesc redirs[] = {
{R_SOCKS5, "socks5", sockschild}, {R_SOCKS5, "socks5", sockschild},
{R_HTTP, "http", proxychild}, {R_HTTP, "http", proxychild},
{R_POP3, "pop3", pop3pchild}, {R_POP3, "pop3", pop3pchild},
{R_IMAP, "imap", imappchild},
{R_SMTP, "smtp", smtppchild}, {R_SMTP, "smtp", smtppchild},
{R_FTP, "ftp", ftpprchild}, {R_FTP, "ftp", ftpprchild},
{R_CONNECTP, "connect+", proxychild}, {R_CONNECTP, "connect+", proxychild},
@ -1603,88 +1611,94 @@ static int h_chroot(int argc, unsigned char **argv){
#endif #endif
struct commands specificcommands[]={ struct commands commandhandlers[]={
#ifndef _WIN32 {NULL, "", h_noop, 1, 0},
{specificcommands+1, "setuid", h_setuid, 2, 2}, {NULL, "proxy", h_proxy, 1, 0},
{specificcommands+2, "setgid", h_setgid, 2, 2}, {NULL, "pop3p", h_proxy, 1, 0},
{specificcommands+3, "chroot", h_chroot, 2, 4}, {NULL, "imapp", h_proxy, 1, 0},
{NULL, "ftppr", h_proxy, 1, 0},
{NULL, "socks", h_proxy, 1, 0},
{NULL, "tcppm", h_proxy, 4, 0},
{NULL, "udppm", h_proxy, 4, 0},
{NULL, "admin", h_proxy, 1, 0},
{NULL, "dnspr", h_proxy, 1, 0},
{NULL, "internal", h_internal, 2, 2},
{NULL, "external", h_external, 2, 2},
{NULL, "log", h_log, 1, 0},
{NULL, "service", h_service, 1, 1},
{NULL, "daemon", h_daemon, 1, 1},
{NULL, "config", h_config, 2, 2},
{NULL, "include", h_include, 2, 2},
{NULL, "archiver", h_archiver, 3, 0},
{NULL, "counter", h_counter, 2, 4},
{NULL, "rotate", h_rotate, 2, 2},
{NULL, "logformat", h_logformat, 2, 2},
{NULL, "timeouts", h_timeouts, 2, 0},
{NULL, "auth", h_auth, 2, 0},
{NULL, "users", h_users, 1, 0},
{NULL, "maxconn", h_maxconn, 2, 2},
{NULL, "flush", h_flush, 1, 1},
{NULL, "nserver", h_nserver, 2, 2},
{NULL, "fakeresolve", h_fakeresolve, 1, 1},
{NULL, "nscache", h_nscache, 2, 2},
{NULL, "nscache6", h_nscache6, 2, 2},
{NULL, "nsrecord", h_nsrecord, 3, 3},
{NULL, "dialer", h_dialer, 2, 2},
{NULL, "system", h_system, 2, 2},
{NULL, "pidfile", h_pidfile, 2, 2},
{NULL, "monitor", h_monitor, 2, 2},
{NULL, "parent", h_parent, 5, 0},
{NULL, "allow", h_ace, 1, 0},
{NULL, "deny", h_ace, 1, 0},
{NULL, "redirect", h_ace, 3, 0},
{NULL, "bandlimin", h_ace, 2, 0},
{NULL, "bandlimout", h_ace, 2, 0},
{NULL, "nobandlimin", h_ace, 1, 0},
{NULL, "nobandlimout", h_ace, 1, 0},
{NULL, "countin", h_ace, 4, 0},
{NULL, "nocountin", h_ace, 1, 0},
{NULL, "countout", h_ace, 4, 0},
{NULL, "nocountout", h_ace, 1, 0},
{NULL, "countall", h_ace, 4, 0},
{NULL, "nocountall", h_ace, 1, 0},
{NULL, "connlim", h_ace, 4, 0},
{NULL, "noconnlim", h_ace, 1, 0},
{NULL, "plugin", h_plugin, 3, 0},
{NULL, "logdump", h_logdump, 2, 3},
{NULL, "filtermaxsize", h_filtermaxsize, 2, 2},
{NULL, "nolog", h_nolog, 1, 1},
{NULL, "weight", h_nolog, 2, 2},
{NULL, "authcache", h_authcache, 2, 4},
{NULL, "smtpp", h_proxy, 1, 0},
{NULL, "delimchar",h_delimchar, 2, 2},
{NULL, "authnserver", h_authnserver, 2, 2},
{NULL, "stacksize", h_stacksize, 2, 2},
{NULL, "force", h_force, 1, 1},
{NULL, "noforce", h_noforce, 1, 1},
{NULL, "parentretries", h_parentretries, 2, 2},
{NULL, "auto", h_proxy, 1, 0},
{NULL, "backlog", h_backlog, 2, 2},
{NULL, "tlspr", h_proxy, 1, 0},
{NULL, "maxseg", h_maxseg, 2, 2},
#ifndef NORADIUS
{NULL, "radius", h_radius, 3, 0},
#endif #endif
{NULL, "", h_noop, 1, 0} #ifndef _WIN32
{NULL, "setuid", h_setuid, 2, 2},
{NULL, "setgid", h_setgid, 2, 2},
{NULL, "chroot", h_chroot, 2, 4},
#endif
{NULL, "", h_noop, 1, 0}
}; };
struct commands commandhandlers[]={ void initcommands(void){
{commandhandlers+1, "", h_noop, 1, 0}, static int initialized = 0;
{commandhandlers+2, "proxy", h_proxy, 1, 0}, unsigned i;
{commandhandlers+3, "pop3p", h_proxy, 1, 0}, if(initialized) return;
{commandhandlers+4, "ftppr", h_proxy, 1, 0}, initialized = 1;
{commandhandlers+5, "socks", h_proxy, 1, 0}, for(i = 0; i + 1 < sizeof(commandhandlers)/sizeof(commandhandlers[0]); i++)
{commandhandlers+6, "tcppm", h_proxy, 4, 0}, commandhandlers[i].next = commandhandlers + i + 1;
{commandhandlers+7, "udppm", h_proxy, 4, 0}, }
{commandhandlers+8, "admin", h_proxy, 1, 0},
{commandhandlers+9, "dnspr", h_proxy, 1, 0},
{commandhandlers+10, "internal", h_internal, 2, 2},
{commandhandlers+11, "external", h_external, 2, 2},
{commandhandlers+12, "log", h_log, 1, 0},
{commandhandlers+13, "service", h_service, 1, 1},
{commandhandlers+14, "daemon", h_daemon, 1, 1},
{commandhandlers+15, "config", h_config, 2, 2},
{commandhandlers+16, "include", h_include, 2, 2},
{commandhandlers+17, "archiver", h_archiver, 3, 0},
{commandhandlers+18, "counter", h_counter, 2, 4},
{commandhandlers+19, "rotate", h_rotate, 2, 2},
{commandhandlers+20, "logformat", h_logformat, 2, 2},
{commandhandlers+21, "timeouts", h_timeouts, 2, 0},
{commandhandlers+22, "auth", h_auth, 2, 0},
{commandhandlers+23, "users", h_users, 1, 0},
{commandhandlers+24, "maxconn", h_maxconn, 2, 2},
{commandhandlers+25, "flush", h_flush, 1, 1},
{commandhandlers+26, "nserver", h_nserver, 2, 2},
{commandhandlers+27, "fakeresolve", h_fakeresolve, 1, 1},
{commandhandlers+28, "nscache", h_nscache, 2, 2},
{commandhandlers+29, "nscache6", h_nscache6, 2, 2},
{commandhandlers+30, "nsrecord", h_nsrecord, 3, 3},
{commandhandlers+31, "dialer", h_dialer, 2, 2},
{commandhandlers+32, "system", h_system, 2, 2},
{commandhandlers+33, "pidfile", h_pidfile, 2, 2},
{commandhandlers+34, "monitor", h_monitor, 2, 2},
{commandhandlers+35, "parent", h_parent, 5, 0},
{commandhandlers+36, "allow", h_ace, 1, 0},
{commandhandlers+37, "deny", h_ace, 1, 0},
{commandhandlers+38, "redirect", h_ace, 3, 0},
{commandhandlers+39, "bandlimin", h_ace, 2, 0},
{commandhandlers+40, "bandlimout", h_ace, 2, 0},
{commandhandlers+41, "nobandlimin", h_ace, 1, 0},
{commandhandlers+42, "nobandlimout", h_ace, 1, 0},
{commandhandlers+43, "countin", h_ace, 4, 0},
{commandhandlers+44, "nocountin", h_ace, 1, 0},
{commandhandlers+45, "countout", h_ace, 4, 0},
{commandhandlers+46, "nocountout", h_ace, 1, 0},
{commandhandlers+47, "countall", h_ace, 4, 0},
{commandhandlers+48, "nocountall", h_ace, 1, 0},
{commandhandlers+49, "connlim", h_ace, 4, 0},
{commandhandlers+50, "noconnlim", h_ace, 1, 0},
{commandhandlers+51, "plugin", h_plugin, 3, 0},
{commandhandlers+52, "logdump", h_logdump, 2, 3},
{commandhandlers+53, "filtermaxsize", h_filtermaxsize, 2, 2},
{commandhandlers+54, "nolog", h_nolog, 1, 1},
{commandhandlers+55, "weight", h_nolog, 2, 2},
{commandhandlers+56, "authcache", h_authcache, 2, 4},
{commandhandlers+57, "smtpp", h_proxy, 1, 0},
{commandhandlers+58, "delimchar",h_delimchar, 2, 2},
{commandhandlers+59, "authnserver", h_authnserver, 2, 2},
{commandhandlers+60, "stacksize", h_stacksize, 2, 2},
{commandhandlers+61, "force", h_force, 1, 1},
{commandhandlers+62, "noforce", h_noforce, 1, 1},
{commandhandlers+63, "parentretries", h_parentretries, 2, 2},
{commandhandlers+64, "auto", h_proxy, 1, 0},
{commandhandlers+65, "backlog", h_backlog, 2, 2},
{commandhandlers+66, "tlspr", h_proxy, 1, 0},
{commandhandlers+67, "maxseg", h_maxseg, 2, 2},
#ifndef NORADIUS
{commandhandlers+68, "radius", h_radius, 3, 0},
#endif
{specificcommands, "", h_noop, 1, 0}
};
int parsestr (unsigned char *str, unsigned char **argm, int nitems, unsigned char ** buff, int *inbuf, int *bufsize){ int parsestr (unsigned char *str, unsigned char **argm, int nitems, unsigned char ** buff, int *inbuf, int *bufsize){
#define buf (*buff) #define buf (*buff)

View File

@ -523,7 +523,7 @@ static void * ef_server_next(struct node * node){
static void * ef_server_type(struct node * node){ static void * ef_server_type(struct node * node){
int service = ((struct srvparam *)node->value) -> service; int service = ((struct srvparam *)node->value) -> service;
return (service>=0 && service < 15)? (void *)conf.stringtable[SERVICES + service] : (void *)"unknown"; return (service>=0 && service < MAX_SERVICE)? (void *)conf.stringtable[SERVICES + service] : (void *)"unknown";
} }
static void * ef_server_child(struct node * node){ static void * ef_server_child(struct node * node){
@ -682,7 +682,7 @@ static void * ef_client_next(struct node * node){
static void * ef_client_type(struct node * node){ static void * ef_client_type(struct node * node){
int service = ((struct clientparam *)node->value) -> service; int service = ((struct clientparam *)node->value) -> service;
return (service>=0 && service < 15)? (void *)conf.stringtable[SERVICES + service] : (void *)"unknown"; return (service>=0 && service < MAX_SERVICE)? (void *)conf.stringtable[SERVICES + service] : (void *)"unknown";
} }
static void * ef_client_operation(struct node * node){ static void * ef_client_operation(struct node * node){

255
src/imapp.c Normal file
View File

@ -0,0 +1,255 @@
/*
3APA3A simplest proxy server
(c) 2002-2026 by Vladimir Dubrovin <vlad@3proxy.org>
please read License Agreement
*/
#include "proxy.h"
#define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
#define CL_LOGINCMD 0
#define CL_PLAIN 1
#define CL_LOGIN 2
#define CAP_PLAIN 1
#define CAP_LOGIN 2
#ifdef WITHMAIN
#define NOSTARTTLS 1
#else
#define NOSTARTTLS param->srv->nostarttls
#endif
void * imappchild(struct clientparam* param) {
int i=0, res, method=CL_LOGINCMD, caps=0;
unsigned char buf[2048];
unsigned char srvbuf[1024];
unsigned char ibuf[2048];
unsigned char tag[64];
unsigned char ub[320];
unsigned char pb[320];
unsigned char *se, *cmd, *user, *pass, *p1, *p2;
*tag = 0;
i = sprintf((char *)buf, "* OK [CAPABILITY IMAP4rev1%s AUTH=PLAIN AUTH=LOGIN] IMAP4rev1 Proxy Ready\r\n", NOSTARTTLS?"":" STARTTLS");
if(socksend(param, param->clisock, buf, i, conf.timeouts[STRING_S])!=i) {RETURN (691);}
for(;;){
i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
if(i < 4) {RETURN(692);}
buf[i] = 0;
if ((se=(unsigned char *)strchr((char *)buf, '\r'))) *se = 0;
if (!(se=(unsigned char *)strchr((char *)buf, ' ')) || (se - buf) >= (int)(sizeof(tag) - 1)) {RETURN(692);}
memcpy(tag, buf, se - buf);
tag[se - buf] = 0;
cmd = se + 1;
if(!strncasecmp((char *)cmd, "LOGOUT", 6)){
socksend(param, param->clisock, (unsigned char *)"* BYE\r\n", 7, conf.timeouts[STRING_S]);
sprintf((char *)buf, "%.60s OK LOGOUT completed\r\n", (char *)tag);
socksend(param, param->clisock, buf, (int)strlen((char *)buf), conf.timeouts[STRING_S]);
RETURN(0);
}
if(!strncasecmp((char *)cmd, "CAPABILITY", 10)){
i = sprintf((char *)buf, "* CAPABILITY IMAP4rev1%s AUTH=PLAIN AUTH=LOGIN\r\n", NOSTARTTLS?"":" STARTTLS");
socksend(param, param->clisock, buf, i, conf.timeouts[STRING_S]);
sprintf((char *)buf, "%.60s OK CAPABILITY completed\r\n", (char *)tag);
socksend(param, param->clisock, buf, (int)strlen((char *)buf), conf.timeouts[STRING_S]);
continue;
}
#ifndef WITHMAIN
if(!strncasecmp((char *)cmd, "STARTTLS", 8) && !param->srv->nostarttls){
sprintf((char *)buf, "%.60s OK Begin TLS negotiation\r\n", (char *)tag);
if(socksend(param, param->clisock, buf, (int)strlen((char *)buf), conf.timeouts[STRING_S]) <= 0) {RETURN(698);}
param->clientstarttls = S_IMAPP;
if(!param->srv->targetport) param->srv->targetport = htons(143);
return tlsprchild(param);
}
#endif
if(!strncasecmp((char *)cmd, "LOGIN ", 6)){
user = cmd + 6;
if(*user == '"') {
user++;
if (!(se=(unsigned char *)strchr((char *)user, '"'))) {RETURN(693);}
*se = 0;
pass = se + 1;
if(*pass == ' ') pass++;
}
else {
if (!(se=(unsigned char *)strchr((char *)user, ' '))) {RETURN(693);}
*se = 0;
pass = se + 1;
}
if(strlen((char *)user) >= sizeof(ub) || strlen((char *)pass) >= sizeof(pb)) {RETURN(693);}
strcpy((char *)ub, (char *)user);
strcpy((char *)pb, (char *)pass);
break;
}
if(!strncasecmp((char *)cmd, "AUTHENTICATE PLAIN", 18)){
method = CL_PLAIN;
se = cmd + 18;
if(*se == ' ') se++; else se = NULL;
if(!se || !*se){
if(socksend(param, param->clisock, (unsigned char *)"+ \r\n", 4, conf.timeouts[STRING_S])!=4) {RETURN(698);}
i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
if(i < 1) {RETURN(698);}
buf[i] = 0;
if ((se=(unsigned char *)strchr((char *)buf, '\r'))) *se = 0;
se = buf;
}
i = de64(se, ibuf, (int)sizeof(ibuf) - 1);
if(i < 3) {RETURN(693);}
ibuf[i] = 0;
p1 = (unsigned char *)memchr(ibuf, 0, i);
if(!p1 || p1 == ibuf + i - 1) {RETURN(693);}
p2 = (unsigned char *)memchr(p1 + 1, 0, i - (int)(p1 + 1 - ibuf));
if(p2){
user = p1 + 1;
pass = p2 + 1;
}
else {
user = ibuf;
pass = p1 + 1;
}
if(strlen((char *)user) >= sizeof(ub) || strlen((char *)pass) >= sizeof(pb)) {RETURN(693);}
strcpy((char *)ub, (char *)user);
strcpy((char *)pb, (char *)pass);
break;
}
if(!strncasecmp((char *)cmd, "AUTHENTICATE LOGIN", 18)){
method = CL_LOGIN;
se = cmd + 18;
if(*se == ' ') se++; else se = NULL;
if(se && *se){
i = de64(se, ub, (int)sizeof(ub) - 1);
if(i < 0) {RETURN(693);}
ub[i] = 0;
}
else {
if(socksend(param, param->clisock, (unsigned char *)"+ VXNlcm5hbWU6\r\n", 16, conf.timeouts[STRING_S])!=16) {RETURN(698);}
i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
if(i < 1) {RETURN(698);}
buf[i] = 0;
if ((se=(unsigned char *)strchr((char *)buf, '\r'))) *se = 0;
i = de64(buf, ub, (int)sizeof(ub) - 1);
if(i < 0) {RETURN(693);}
ub[i] = 0;
}
if(socksend(param, param->clisock, (unsigned char *)"+ UGFzc3dvcmQ6\r\n", 16, conf.timeouts[STRING_S])!=16) {RETURN(698);}
i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
if(i < 1) {RETURN(698);}
buf[i] = 0;
if ((se=(unsigned char *)strchr((char *)buf, '\r'))) *se = 0;
i = de64(buf, pb, (int)sizeof(pb) - 1);
if(i < 0) {RETURN(693);}
pb[i] = 0;
break;
}
sprintf((char *)buf, "%.60s BAD need LOGIN first\r\n", (char *)tag);
socksend(param, param->clisock, buf, (int)strlen((char *)buf), conf.timeouts[STRING_S]);
}
if(parseconnusername((char *)ub, param, 0, 143)){RETURN(694);}
if(*pb && !param->password) param->password = (unsigned char *)strdup((char *)pb);
param->operation = CONNECT;
res = (*param->srv->authfunc)(param);
if(res) {RETURN(res);}
i = sockgetlinebuf(param, SERVER, srvbuf, sizeof(srvbuf) - 1, '\n', conf.timeouts[STRING_L]);
if( i < 4 ) {RETURN(695);}
srvbuf[i] = 0;
if(strncasecmp((char *)srvbuf, "* OK", 4)||strstr((char *)srvbuf, "IMAP4rev1 Proxy Ready")){RETURN(696);}
if((se = (unsigned char *)strstr((char *)srvbuf, "[CAPABILITY "))){
if(hascap(se, "AUTH=PLAIN")) caps |= CAP_PLAIN;
if(hascap(se, "AUTH=LOGIN")) caps |= CAP_LOGIN;
}
else {
if(socksend(param, param->remsock, (unsigned char *)"zz CAPABILITY\r\n", 15, conf.timeouts[STRING_S])!=15) {RETURN(697);}
for(;;){
i = sockgetlinebuf(param, SERVER, srvbuf, sizeof(srvbuf) - 1, '\n', conf.timeouts[STRING_L]);
if(i < 3) {RETURN(697);}
srvbuf[i] = 0;
if(!strncasecmp((char *)srvbuf, "* CAPABILITY", 12)){
if(hascap(srvbuf, "AUTH=PLAIN")) caps |= CAP_PLAIN;
if(hascap(srvbuf, "AUTH=LOGIN")) caps |= CAP_LOGIN;
continue;
}
if(!strncasecmp((char *)srvbuf, "zz ", 3)) break;
}
}
if(method == CL_PLAIN && !(caps & CAP_PLAIN)) method = (caps & CAP_LOGIN)? CL_LOGIN : CL_LOGINCMD;
else if(method == CL_LOGIN && !(caps & CAP_LOGIN)) method = (caps & CAP_PLAIN)? CL_PLAIN : CL_LOGINCMD;
else if(method == CL_LOGINCMD && caps) method = (caps & CAP_PLAIN)? CL_PLAIN : CL_LOGIN;
if(method == CL_PLAIN){
i = (int)strlen((char *)param->extusername);
res = (int)strlen((char *)pb);
if(((i + res + 4) / 3) * 4 + 1 > (int)sizeof(srvbuf)) {RETURN(693);}
ibuf[0] = 0;
memcpy(ibuf + 1, param->extusername, i);
ibuf[i + 1] = 0;
memcpy(ibuf + i + 2, pb, res);
en64(ibuf, srvbuf, i + res + 2);
if( socksend(param, param->remsock, tag, (int)strlen((char *)tag), conf.timeouts[STRING_S]) <= 0 ||
socksend(param, param->remsock, (unsigned char *)" AUTHENTICATE PLAIN ", 20, conf.timeouts[STRING_S])!= 20 ||
socksend(param, param->remsock, srvbuf, (int)strlen((char *)srvbuf), conf.timeouts[STRING_S]) <= 0 ||
socksend(param, param->remsock, (unsigned char *)"\r\n", 2, conf.timeouts[STRING_S])!=2)
{RETURN(699);}
}
else if(method == CL_LOGIN){
if( socksend(param, param->remsock, tag, (int)strlen((char *)tag), conf.timeouts[STRING_S]) <= 0 ||
socksend(param, param->remsock, (unsigned char *)" AUTHENTICATE LOGIN\r\n", 21, conf.timeouts[STRING_S])!= 21)
{RETURN(699);}
i = sockgetlinebuf(param, SERVER, srvbuf, sizeof(srvbuf) - 1, '\n', conf.timeouts[STRING_L]);
if(i < 1 || *srvbuf != '+') {RETURN(699);}
if(((int)strlen((char *)param->extusername) + 2) / 3 * 4 + 1 > (int)sizeof(ibuf) - 3) {RETURN(693);}
en64(param->extusername, ibuf, (int)strlen((char *)param->extusername));
if( socksend(param, param->remsock, ibuf, (int)strlen((char *)ibuf), conf.timeouts[STRING_S]) <= 0 ||
socksend(param, param->remsock, (unsigned char *)"\r\n", 2, conf.timeouts[STRING_S])!=2)
{RETURN(699);}
i = sockgetlinebuf(param, SERVER, srvbuf, sizeof(srvbuf) - 1, '\n', conf.timeouts[STRING_L]);
if(i < 1 || *srvbuf != '+') {RETURN(699);}
if(((int)strlen((char *)pb) + 2) / 3 * 4 + 1 > (int)sizeof(ibuf) - 3) {RETURN(693);}
en64(pb, ibuf, (int)strlen((char *)pb));
if( socksend(param, param->remsock, ibuf, (int)strlen((char *)ibuf), conf.timeouts[STRING_S]) <= 0 ||
socksend(param, param->remsock, (unsigned char *)"\r\n", 2, conf.timeouts[STRING_S])!=2)
{RETURN(699);}
}
else {
if( socksend(param, param->remsock, tag, (int)strlen((char *)tag), conf.timeouts[STRING_S]) <= 0 ||
socksend(param, param->remsock, (unsigned char *)" LOGIN ", 7, conf.timeouts[STRING_S])!= 7 ||
socksend(param, param->remsock, param->extusername, (int)strlen((char *)param->extusername), conf.timeouts[STRING_S]) <= 0 ||
socksend(param, param->remsock, (unsigned char *)" ", 1, conf.timeouts[STRING_S])!= 1 ||
socksend(param, param->remsock, pb, (int)strlen((char *)pb), conf.timeouts[STRING_S]) <= 0 ||
socksend(param, param->remsock, (unsigned char *)"\r\n", 2, conf.timeouts[STRING_S])!=2)
{RETURN(699);}
}
param->statscli64 += (uint64_t)(strlen((char *)tag) + strlen((char *)param->extusername) + strlen((char *)pb) + 11);
param->nwrites++;
RETURN (mapsocket(param, 180));
CLEANRET:
if(param->hostname&&param->extusername) {
sprintf((char *)buf, "%.128s@%.128s%c%hu", param->extusername, param->hostname, (*SAPORT(&param->sinsr)==143)?0:':', ntohs(*SAPORT(&param->sinsr)));
dolog(param, buf);
}
else dolog(param, NULL);
if(param->clisock != INVALID_SOCKET) {
if ((param->res > 0 && param->res < 100) || (param->res > 691 && param->res <700)) {
sprintf((char *)buf, "%.60s NO proxy error\r\n", *tag? (char *)tag : "*");
socksend(param, param->clisock, buf, (int)strlen((char *)buf),conf.timeouts[STRING_S]);
}
}
freeparam(param);
return (NULL);
}
#ifdef WITHMAIN
struct proxydef childdef = {
imappchild,
143,
0,
S_IMAPP,
" -hdefault_host[:port] - use this host and port as default if no host specified\n -x - disable STARTTLS\n"
};
#include "proxymain.c"
#endif

View File

@ -71,6 +71,7 @@ struct symbol symbols[] = {
{symbols+46, "make_ace", (void *) make_ace}, {symbols+46, "make_ace", (void *) make_ace},
{symbols+47, "freeacl", (void *) freeacl}, {symbols+47, "freeacl", (void *) freeacl},
{symbols+48, "handleredirect", (void *) handleredirect}, {symbols+48, "handleredirect", (void *) handleredirect},
{symbols+49, "imapp", (void *) imappchild},
{NULL, "", NULL} {NULL, "", NULL}
}; };

View File

@ -10,6 +10,12 @@
#define RETURN(xxx) { param->res = xxx; goto CLEANRET; } #define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
#ifdef WITHMAIN
#define NOSTARTTLS 1
#else
#define NOSTARTTLS param->srv->nostarttls
#endif
void * pop3pchild(struct clientparam* param) { void * pop3pchild(struct clientparam* param) {
int i=0, res; int i=0, res;
unsigned char buf[320]; unsigned char buf[320];
@ -19,10 +25,23 @@ void * pop3pchild(struct clientparam* param) {
i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]); i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
while(i > 4 && strncasecmp((char *)buf, "USER", 4)){ while(i > 4 && strncasecmp((char *)buf, "USER", 4)){
if(!strncasecmp((char *)buf, "QUIT", 4)){ if(!strncasecmp((char *)buf, "QUIT", 4)){
socksend(param, param->clisock, (unsigned char *)"+OK\r\n", 5,conf.timeouts[STRING_S]); socksend(param, param->clisock, (unsigned char *)"+OK\r\n", 5,conf.timeouts[STRING_S]);
RETURN(0); RETURN(0);
} }
socksend(param, param->clisock, (unsigned char *)"-ERR need USER first\r\n", 22, conf.timeouts[STRING_S]); if(!strncasecmp((char *)buf, "CAPA", 4) && !NOSTARTTLS){
socksend(param, param->clisock, (unsigned char *)"+OK Capability list follows\r\nSTLS\r\n.\r\n", 38, conf.timeouts[STRING_S]);
i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
continue;
}
#ifndef WITHMAIN
if(!strncasecmp((char *)buf, "STLS", 4) && !param->srv->nostarttls){
if(socksend(param, param->clisock, (unsigned char *)"+OK Begin TLS negotiation\r\n", 27, conf.timeouts[STRING_S])!=27) {RETURN(623);}
param->clientstarttls = S_POP3P;
if(!param->srv->targetport) param->srv->targetport = htons(110);
return tlsprchild(param);
}
#endif
socksend(param, param->clisock, (unsigned char *)"-ERR need USER first\r\n", 22, conf.timeouts[STRING_S]);
i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]); i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
} }
if(i<6) {RETURN(612);} if(i<6) {RETURN(612);}
@ -65,7 +84,7 @@ struct proxydef childdef = {
110, 110,
0, 0,
S_POP3P, S_POP3P,
" -hdefault_host[:port] - use this host and port as default if no host specified\n" " -hdefault_host[:port] - use this host and port as default if no host specified\n -x - disable STARTTLS\n"
}; };
#include "proxymain.c" #include "proxymain.c"

View File

@ -188,6 +188,8 @@ unsigned long sockfillbuffcli(struct clientparam * param, unsigned long size, in
unsigned long sockfillbuffsrv(struct clientparam * param, unsigned long size, int timeosec); unsigned long sockfillbuffsrv(struct clientparam * param, unsigned long size, int timeosec);
int sockgetlinebuf(struct clientparam * param, DIRECTION which, unsigned char * buf, int bufsize, int delim, int to); int sockgetlinebuf(struct clientparam * param, DIRECTION which, unsigned char * buf, int bufsize, int delim, int to);
int getmultiline(struct clientparam * param, DIRECTION which, unsigned char * buf, int bufsize, const char *cap, int *found);
int hascap(const unsigned char *line, const char *cap);
@ -312,6 +314,7 @@ void srvinit2(struct srvparam * srv, struct clientparam *param);
void srvfree(struct srvparam * srv); void srvfree(struct srvparam * srv);
unsigned char * dologname (unsigned char *buf, unsigned char *name, const unsigned char *ext, ROTATION lt, time_t t); unsigned char * dologname (unsigned char *buf, unsigned char *name, const unsigned char *ext, ROTATION lt, time_t t);
int readconfig(FILE * fp); int readconfig(FILE * fp);
void initcommands(void);
int connectwithpoll(struct clientparam *param, SOCKET sock, struct sockaddr *sa, SASIZETYPE size, int to); int connectwithpoll(struct clientparam *param, SOCKET sock, struct sockaddr *sa, SASIZETYPE size, int to);
@ -325,6 +328,7 @@ extern char *copyright;
void * dnsprchild(struct clientparam * param); void * dnsprchild(struct clientparam * param);
void * pop3pchild(struct clientparam * param); void * pop3pchild(struct clientparam * param);
void * imappchild(struct clientparam * param);
void * smtppchild(struct clientparam * param); void * smtppchild(struct clientparam * param);
void * proxychild(struct clientparam * param); void * proxychild(struct clientparam * param);
void * sockschild(struct clientparam * param); void * sockschild(struct clientparam * param);

View File

@ -528,6 +528,15 @@ int MODULEMAINFUNC (int argc, char** argv){
srv.needuser = 0; srv.needuser = 0;
if(*(argv[i] + 2)) srv.needuser = atoi(argv[i] + 2); if(*(argv[i] + 2)) srv.needuser = atoi(argv[i] + 2);
break; break;
case 'x':
srv.nostarttls = 1;
break;
case 'X':
if(!strncasecmp(argv[i]+2, "imap", 4)) srv.srvstarttls = S_IMAPP;
else if(!strncasecmp(argv[i]+2, "pop3", 4)) srv.srvstarttls = S_POP3P;
else if(!strncasecmp(argv[i]+2, "smtp", 4)) srv.srvstarttls = S_SMTPP;
else error = 1;
break;
case 'T': case 'T':
srv.transparent = 1; srv.transparent = 1;
break; break;

View File

@ -47,6 +47,7 @@ int clientnegotiate(struct chain * redir, struct clientparam * param, struct soc
switch(redir->type){ switch(redir->type){
case R_TCP: case R_TCP:
case R_HTTP: case R_HTTP:
case R_IMAP:
return 0; return 0;
case R_CONNECT: case R_CONNECT:
case R_CONNECTP: case R_CONNECTP:

View File

@ -10,11 +10,23 @@
#define RETURN(xxx) { param->res = xxx; goto CLEANRET; } #define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
#ifdef WITHMAIN
#define NOSTARTTLS 1
#else
#define NOSTARTTLS param->srv->nostarttls
#endif
char ehlo[] = "250-Proxy\r\n" char ehlo[] = "250-Proxy\r\n"
"250-AUTH PLAIN LOGIN\r\n" "250-AUTH PLAIN LOGIN\r\n"
"250-8BITMIME\r\n" "250-8BITMIME\r\n"
"250 DSN\r\n"; "250 DSN\r\n";
char ehlotls[] = "250-Proxy\r\n"
"250-AUTH PLAIN LOGIN\r\n"
"250-8BITMIME\r\n"
"250-STARTTLS\r\n"
"250 DSN\r\n";
int readreply (struct clientparam* param) { int readreply (struct clientparam* param) {
unsigned char * buf; unsigned char * buf;
int res, i, bufsize = 640; int res, i, bufsize = 640;
@ -112,9 +124,18 @@ void * smtppchild(struct clientparam* param) {
socksend(param, param->clisock, (unsigned char *)"250 Proxy\r\n", 11,conf.timeouts[STRING_S]); socksend(param, param->clisock, (unsigned char *)"250 Proxy\r\n", 11,conf.timeouts[STRING_S]);
} }
else if(!strncasecmp((char *)buf, "EHLO ", 5)){ else if(!strncasecmp((char *)buf, "EHLO ", 5)){
socksend(param, param->clisock, (unsigned char *)ehlo, sizeof(ehlo) - 1,conf.timeouts[STRING_S]); if(!NOSTARTTLS) socksend(param, param->clisock, (unsigned char *)ehlotls, sizeof(ehlotls) - 1,conf.timeouts[STRING_S]);
else socksend(param, param->clisock, (unsigned char *)ehlo, sizeof(ehlo) - 1,conf.timeouts[STRING_S]);
} }
else if(!param->hostname) socksend(param, param->clisock, (unsigned char *)"571 need AUTH first\r\n", 22, conf.timeouts[STRING_S]); #ifndef WITHMAIN
else if(!strncasecmp((char *)buf, "STARTTLS", 8) && !param->srv->nostarttls){
if(socksend(param, param->clisock, (unsigned char *)"220 2.0.0 Ready to start TLS\r\n", 30, conf.timeouts[STRING_S])!=30) {RETURN(673);}
param->clientstarttls = S_SMTPP;
if(!param->srv->targetport) param->srv->targetport = htons(587);
return tlsprchild(param);
}
#endif
else if(!param->hostname) socksend(param, param->clisock, (unsigned char *)"571 need AUTH first\r\n", 22, conf.timeouts[STRING_S]);
else { else {
login = -1; login = -1;
buf[i] = 0; buf[i] = 0;
@ -132,7 +153,7 @@ void * smtppchild(struct clientparam* param) {
i = de64(buf,username,255); i = de64(buf,username,255);
if(i < 1) {RETURN(664);} if(i < 1) {RETURN(664);}
username[i] = 0; username[i] = 0;
parseconnusername((char *)username, param, 0, 25); parseconnusername((char *)username, param, 0, 587);
socksend(param, param->clisock, (unsigned char *)"334 UGFzc3dvcmQ6\r\n", 18,conf.timeouts[STRING_S]); socksend(param, param->clisock, (unsigned char *)"334 UGFzc3dvcmQ6\r\n", 18,conf.timeouts[STRING_S]);
i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]); i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
if(i < 2) {RETURN(665);} if(i < 2) {RETURN(665);}
@ -157,7 +178,7 @@ void * smtppchild(struct clientparam* param) {
} }
if(i < 3 || *username) {RETURN(668);} if(i < 3 || *username) {RETURN(668);}
username[i] = 0; username[i] = 0;
parseconnusername((char *)username+1, param, 0, 25); parseconnusername((char *)username+1, param, 0, 587);
res = (int)strlen((char *)username+1) + 2; res = (int)strlen((char *)username+1) + 2;
if(res < i){ if(res < i){
if(param->extpassword) free(param->extpassword); if(param->extpassword) free(param->extpassword);
@ -180,9 +201,7 @@ void * smtppchild(struct clientparam* param) {
param->operation = CONNECT; param->operation = CONNECT;
res = (*param->srv->authfunc)(param); res = (*param->srv->authfunc)(param);
if(res) {RETURN(res);} if(res) {RETURN(res);}
do { i = getmultiline(param, SERVER, buf, sizeof(buf) - 1, NULL, NULL);
i = sockgetlinebuf(param, SERVER, buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L]);
} while (i > 3 && buf[3] == '-');
if( i < 3 ) {RETURN(671);} if( i < 3 ) {RETURN(671);}
buf[i] = 0; buf[i] = 0;
if(strncasecmp((char *)buf, "220", 3)||!strncasecmp((char *)buf+4, "PROXY", 5)){RETURN(672);} if(strncasecmp((char *)buf, "220", 3)||!strncasecmp((char *)buf+4, "PROXY", 5)){RETURN(672);}
@ -292,7 +311,7 @@ void * smtppchild(struct clientparam* param) {
CLEANRET: CLEANRET:
if(param->hostname&&param->extusername) { if(param->hostname&&param->extusername) {
sprintf((char *)buf, "%.128s@%.128s%c%hu", param->extusername, param->hostname, *SAPORT(&param->sinsr)==25?0:':',ntohs(*SAPORT(&param->sinsr))); sprintf((char *)buf, "%.128s@%.128s%c%hu", param->extusername, param->hostname, *SAPORT(&param->sinsr)==587?0:':',ntohs(*SAPORT(&param->sinsr)));
dolog(param, buf); dolog(param, buf);
} }
else dolog(param, NULL); else dolog(param, NULL);
@ -307,10 +326,10 @@ CLEANRET:
#ifdef WITHMAIN #ifdef WITHMAIN
struct proxydef childdef = { struct proxydef childdef = {
smtppchild, smtppchild,
25, 587,
0, 0,
S_SMTPP, S_SMTPP,
" -hdefault_host[:port] - use this host and port as default if no host specified\n" " -hdefault_host[:port] - use this host and port as default if no host specified\n -x - disable STARTTLS\n"
}; };
#include "proxymain.c" #include "proxymain.c"

View File

@ -30,8 +30,8 @@ unsigned char * strings[] = {
/* 17 */ (unsigned char *)"SMTPP", /* 17 */ (unsigned char *)"SMTPP",
/* 18 */ (unsigned char *)"AUTO", /* 18 */ (unsigned char *)"AUTO",
/* 19 */ (unsigned char *)"TLSPR", /* 19 */ (unsigned char *)"TLSPR",
/* 20 */ (unsigned char *)"ZOMBIE", /* 20 */ (unsigned char *)"IMAPP",
/* 21 */ NULL, /* 21 */ (unsigned char *)"ZOMBIE",
/* 22 */ NULL, /* 22 */ NULL,
/* 23 */ NULL, /* 23 */ NULL,
/* 24 */ NULL, /* 24 */ NULL,

View File

@ -208,6 +208,7 @@ typedef enum {
S_SMTPP, S_SMTPP,
S_AUTO, S_AUTO,
S_TLSPR, S_TLSPR,
S_IMAPP,
S_ZOMBIE S_ZOMBIE
}PROXYSERVICE; }PROXYSERVICE;
@ -304,7 +305,8 @@ typedef enum {
R_EXTIP, R_EXTIP,
R_TLS, R_TLS,
R_HA, R_HA,
R_DNS R_DNS,
R_IMAP
} REDIRTYPE; } REDIRTYPE;
struct redirdesc { struct redirdesc {
@ -535,6 +537,8 @@ struct srvparam {
int gracetraf, gracenum, gracedelay; int gracetraf, gracenum, gracedelay;
int requirecert; int requirecert;
int haproxy; int haproxy;
int nostarttls;
PROXYSERVICE srvstarttls;
#ifdef WITHSPLICE #ifdef WITHSPLICE
int usesplice; int usesplice;
#endif #endif
@ -594,6 +598,8 @@ struct clientparam {
PROXYSERVICE service; PROXYSERVICE service;
PROXYSERVICE clientstarttls;
SOCKET clisock, SOCKET clisock,
remsock, remsock,
ctrlsock, ctrlsock,

View File

@ -37,6 +37,176 @@ int readtls(struct clientparam *param, int direction, unsigned char *buf, int bu
#define SNILEN (256) #define SNILEN (256)
#define PROTOLEN (32) #define PROTOLEN (32)
int srvstarttls(struct clientparam *param, PROXYSERVICE proto){
unsigned char buf[1024];
int i, found = 0;
switch(proto){
case S_IMAPP:
i = sockgetlinebuf(param, SERVER, buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L]);
if(i < 4) return 1;
buf[i] = 0;
if(strncasecmp((char *)buf, "* OK", 4)) return 1;
found = hascap(buf, "STARTTLS");
if(!found){
if(socksend(param, param->remsock, (unsigned char *)"zz CAPABILITY\r\n", 15, conf.timeouts[STRING_S])!=15) return 2;
for(;;){
i = sockgetlinebuf(param, SERVER, buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L]);
if(i < 3) return 2;
buf[i] = 0;
if(!strncasecmp((char *)buf, "* CAPABILITY", 12) && hascap(buf, "STARTTLS")) found = 1;
if(!strncasecmp((char *)buf, "zz ", 3)) break;
}
if(!found) return 3;
}
if(socksend(param, param->remsock, (unsigned char *)"zz STARTTLS\r\n", 13, conf.timeouts[STRING_S])!=13) return 2;
i = sockgetlinebuf(param, SERVER, buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L]);
if(i < 5) return 2;
buf[i] = 0;
if(strncasecmp((char *)buf, "zz OK", 5)) return 3;
break;
case S_POP3P:
i = sockgetlinebuf(param, SERVER, buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L]);
if(i < 3) return 1;
buf[i] = 0;
if(strncasecmp((char *)buf, "+OK", 3)) return 1;
if(socksend(param, param->remsock, (unsigned char *)"CAPA\r\n", 6, conf.timeouts[STRING_S])!=6) return 2;
for(;;){
i = sockgetlinebuf(param, SERVER, buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L]);
if(i < 1) return 2;
buf[i] = 0;
if(buf[0] == '.') break;
if(!strncasecmp((char *)buf, "-ERR", 4)) return 2;
if(hascap(buf, "STLS")) found = 1;
}
if(!found) return 3;
if(socksend(param, param->remsock, (unsigned char *)"STLS\r\n", 6, conf.timeouts[STRING_S])!=6) return 2;
i = sockgetlinebuf(param, SERVER, buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L]);
if(i < 3) return 2;
buf[i] = 0;
if(strncasecmp((char *)buf, "+OK", 3)) return 3;
break;
case S_SMTPP:
i = getmultiline(param, SERVER, buf, sizeof(buf) - 1, NULL, NULL);
if(i < 3) return 1;
buf[i] = 0;
if(strncasecmp((char *)buf, "220", 3)) return 1;
i = sprintf((char *)buf, "EHLO [");
i += myinet_ntop(*SAFAMILY(&param->sinsl), SAADDR(&param->sinsl), (char *)buf+strlen((char *)buf), 64);
i += sprintf((char *)buf+strlen((char *)buf), "]\r\n");
if(socksend(param, param->remsock, buf, i, conf.timeouts[STRING_S])!= i) return 2;
i = getmultiline(param, SERVER, buf, sizeof(buf) - 1, "STARTTLS", &found);
if(i < 3) return 2;
buf[i] = 0;
if(strncasecmp((char *)buf, "250", 3)) return 2;
if(!found) return 3;
if(socksend(param, param->remsock, (unsigned char *)"STARTTLS\r\n", 10, conf.timeouts[STRING_S])!= 10) return 2;
i = sockgetlinebuf(param, SERVER, buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L]);
if(i < 3) return 2;
buf[i] = 0;
if(strncasecmp((char *)buf, "220", 3)) return 3;
break;
default:
return 1;
}
return 0;
}
uint16_t starttlsport(PROXYSERVICE proto){
switch(proto){
case S_IMAPP: return 143;
case S_POP3P: return 110;
case S_SMTPP: return 587;
default: return 443;
}
}
int clistarttls(struct clientparam *param, PROXYSERVICE proto){
unsigned char buf[1024];
unsigned char tag[64];
unsigned char *se, *cmd;
int i;
switch(proto){
case S_IMAPP:
i = sprintf((char *)buf, "* OK [CAPABILITY IMAP4rev1 STARTTLS LOGINDISABLED] IMAP4rev1 Proxy Ready\r\n");
if(socksend(param, param->clisock, buf, i, conf.timeouts[STRING_S])!=i) return 1;
for(;;){
i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
if(i < 4) return 1;
buf[i] = 0;
if ((se=(unsigned char *)strchr((char *)buf, '\r'))) *se = 0;
if (!(se=(unsigned char *)strchr((char *)buf, ' ')) || (se - buf) >= (int)(sizeof(tag) - 1)) return 1;
memcpy(tag, buf, se - buf);
tag[se - buf] = 0;
cmd = se + 1;
if(!strncasecmp((char *)cmd, "LOGOUT", 6)){
socksend(param, param->clisock, (unsigned char *)"* BYE\r\n", 7, conf.timeouts[STRING_S]);
sprintf((char *)buf, "%.60s OK LOGOUT completed\r\n", (char *)tag);
socksend(param, param->clisock, buf, (int)strlen((char *)buf), conf.timeouts[STRING_S]);
return -1;
}
if(!strncasecmp((char *)cmd, "CAPABILITY", 10)){
i = sprintf((char *)buf, "* CAPABILITY IMAP4rev1 STARTTLS LOGINDISABLED\r\n");
socksend(param, param->clisock, buf, i, conf.timeouts[STRING_S]);
sprintf((char *)buf, "%.60s OK CAPABILITY completed\r\n", (char *)tag);
socksend(param, param->clisock, buf, (int)strlen((char *)buf), conf.timeouts[STRING_S]);
continue;
}
if(!strncasecmp((char *)cmd, "STARTTLS", 8)){
sprintf((char *)buf, "%.60s OK Begin TLS negotiation\r\n", (char *)tag);
if(socksend(param, param->clisock, buf, (int)strlen((char *)buf), conf.timeouts[STRING_S]) <= 0) return 1;
return 0;
}
sprintf((char *)buf, "%.60s BAD need STARTTLS first\r\n", (char *)tag);
socksend(param, param->clisock, buf, (int)strlen((char *)buf), conf.timeouts[STRING_S]);
}
case S_POP3P:
if(socksend(param, param->clisock, (unsigned char *)"+OK Proxy\r\n", 11, conf.timeouts[STRING_S])!=11) return 1;
for(;;){
i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
if(i < 4) return 1;
if(!strncasecmp((char *)buf, "STLS", 4)){
if(socksend(param, param->clisock, (unsigned char *)"+OK Begin TLS negotiation\r\n", 27, conf.timeouts[STRING_S])!=27) return 1;
return 0;
}
if(!strncasecmp((char *)buf, "CAPA", 4)){
socksend(param, param->clisock, (unsigned char *)"+OK Capability list follows\r\nSTLS\r\n.\r\n", 38, conf.timeouts[STRING_S]);
continue;
}
if(!strncasecmp((char *)buf, "QUIT", 4)){
socksend(param, param->clisock, (unsigned char *)"+OK\r\n", 5, conf.timeouts[STRING_S]);
return -1;
}
socksend(param, param->clisock, (unsigned char *)"-ERR need STLS first\r\n", 22, conf.timeouts[STRING_S]);
}
case S_SMTPP:
if(socksend(param, param->clisock, (unsigned char *)"220 Proxy\r\n", 11, conf.timeouts[STRING_S])!=11) return 1;
for(;;){
i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
if(i < 4) return 1;
if(!strncasecmp((char *)buf, "STARTTLS", 8)){
if(socksend(param, param->clisock, (unsigned char *)"220 2.0.0 Ready to start TLS\r\n", 30, conf.timeouts[STRING_S])!=30) return 1;
return 0;
}
if(!strncasecmp((char *)buf, "EHLO ", 5)){
socksend(param, param->clisock, (unsigned char *)"250-Proxy\r\n250 STARTTLS\r\n", 24, conf.timeouts[STRING_S]);
continue;
}
if(!strncasecmp((char *)buf, "HELO ", 5)){
socksend(param, param->clisock, (unsigned char *)"250 Proxy\r\n", 11, conf.timeouts[STRING_S]);
continue;
}
if(!strncasecmp((char *)buf, "QUIT", 4)){
socksend(param, param->clisock, (unsigned char *)"221 Proxy\r\n", 11, conf.timeouts[STRING_S]);
return -1;
}
socksend(param, param->clisock, (unsigned char *)"530 5.7.0 Must issue a STARTTLS command first\r\n", 45, conf.timeouts[STRING_S]);
}
}
return 1;
}
int parsehello(int type, unsigned char *hello, unsigned len, char *sni, int * snipos, int *lv, char * proto){ int parsehello(int type, unsigned char *hello, unsigned len, char *sni, int * snipos, int *lv, char * proto){
unsigned offset; unsigned offset;
@ -176,7 +346,14 @@ void * tlsprchild(struct clientparam* param) {
int lv=-1; int lv=-1;
char proto[PROTOLEN]="-"; char proto[PROTOLEN]="-";
int snipos = 0; int snipos = 0;
PROXYSERVICE stlsproto = param->clientstarttls? param->clientstarttls : param->srv->srvstarttls;
if(!param->clientstarttls && stlsproto){
res = clistarttls(param, stlsproto);
if(res > 0) RETURN(364);
if(res < 0) RETURN(0);
}
res = tlstobufcli(param); res = tlstobufcli(param);
if(res <= 0 || param->clibuf[0] != 22){ if(res <= 0 || param->clibuf[0] != 22){
if(param->srv->requirecert)RETURN(300-res); if(param->srv->requirecert)RETURN(300-res);
@ -189,7 +366,7 @@ void * tlsprchild(struct clientparam* param) {
free(param->hostname); free(param->hostname);
param->hostname = NULL; param->hostname = NULL;
} }
else if (parsehostname(sni, param, param->srv->targetport? ntohs(param->srv->targetport):443)) RETURN (100); else if (parsehostname(sni, param, param->srv->targetport? ntohs(param->srv->targetport):starttlsport(stlsproto))) RETURN (100);
if (!param->hostname)param->hostname = (unsigned char *)strdup(sni); if (!param->hostname)param->hostname = (unsigned char *)strdup(sni);
if(param->srv->s_option && snipos && res > 1){ if(param->srv->s_option && snipos && res > 1){
int len; int len;
@ -219,7 +396,15 @@ void * tlsprchild(struct clientparam* param) {
if(param->redirectfunc && param->redirectfunc != tlsprchild){ if(param->redirectfunc && param->redirectfunc != tlsprchild){
return (*param->redirectfunc)(param); return (*param->redirectfunc)(param);
} }
if(stlsproto){
res = srvstarttls(param, stlsproto);
if(res){
socksend(param, param->clisock, (unsigned char *)"\x15\x03\x01\x00\x02\x02\x28", 7, conf.timeouts[STRING_S]);
RETURN(360+res);
}
}
if(param->srv->requirecert > 1){ if(param->srv->requirecert > 1){
res = tlstobufsrv(param); res = tlstobufsrv(param);
if(res <= 0 || param->srvbuf[0] != 22) RETURN(340-res); if(res <= 0 || param->srvbuf[0] != 22) RETURN(340-res);