mirror of
https://github.com/3proxy/3proxy.git
synced 2026-11-16 06:05:50 +08:00
Compare commits
3 Commits
57b94b209b
...
51559e12c4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51559e12c4 | ||
|
|
79583d7aa7 | ||
|
|
796eff444a |
2
.github/workflows/update-wiki.yml
vendored
2
.github/workflows/update-wiki.yml
vendored
@ -45,6 +45,8 @@ jobs:
|
||||
cp -f doc/html/man8/tlspr.8.html wiki/tlspr.md
|
||||
cp -f doc/html/man8/tcppm.8.html wiki/tcppm.md
|
||||
cp -f doc/html/man8/udppm.8.html wiki/udppm.md
|
||||
cp -f doc/html/man8/tcptoudp.8.html wiki/tcptoudp.md
|
||||
cp -f doc/html/man8/udptotcp.8.html wiki/udptotcp.md
|
||||
cp -f doc/html/man5/3proxy.cfg.5.html wiki/3proxy.cfg.md
|
||||
cp -f doc/html/highload.html wiki/High-Load.md
|
||||
cp -f doc/html/howtoe.html wiki/How-To.md
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -268,8 +268,10 @@ bin/3proxy_proxy
|
||||
bin/3proxy_smtpp
|
||||
bin/3proxy_socks
|
||||
bin/3proxy_tcppm
|
||||
bin/3proxy_tcptoudp
|
||||
bin/3proxy_tlspr
|
||||
bin/3proxy_udppm
|
||||
bin/3proxy_udptotcp
|
||||
build*/*
|
||||
testcerts/
|
||||
/.claude
|
||||
|
||||
@ -92,10 +92,12 @@ 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_TCPTOUDP "Build standalone tcptoudp binary" ON)
|
||||
option(3PROXY_BUILD_UDPTOTCP "Build standalone udptotcp binary" ON)
|
||||
option(3PROXY_BUILD_TLSPR "Build standalone tlspr binary" ON)
|
||||
|
||||
if(3PROXY_BUILD_NONE)
|
||||
foreach(_M PROXY SOCKS POP3P IMAPP SMTPP FTPPR TCPPM UDPPM TLSPR)
|
||||
foreach(_M PROXY SOCKS POP3P IMAPP SMTPP FTPPR TCPPM UDPPM TCPTOUDP UDPTOTCP TLSPR)
|
||||
set(3PROXY_BUILD_${_M} OFF)
|
||||
endforeach()
|
||||
endif()
|
||||
@ -419,6 +421,7 @@ add_library(srv_modules OBJECT
|
||||
src/smtpp.c
|
||||
src/ftppr.c
|
||||
src/tcppm.c
|
||||
src/tcptoudp.c
|
||||
src/tlspr.c
|
||||
src/auto.c
|
||||
src/socks.c
|
||||
@ -436,6 +439,12 @@ target_include_directories(srvudppm_obj PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
)
|
||||
|
||||
# UDP to TCP tunnel server module (without WITHMAIN)
|
||||
add_library(srvudptotcp_obj OBJECT src/udptotcp.c)
|
||||
target_include_directories(srvudptotcp_obj PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
)
|
||||
|
||||
# UDP socket relay (used by 3proxy, socks, udppm)
|
||||
add_library(udpsockmap_obj OBJECT src/udpsockmap.c)
|
||||
target_include_directories(udpsockmap_obj PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
@ -469,6 +478,7 @@ add_executable(3proxy
|
||||
${3PROXY_CORE_SOURCES}
|
||||
$<TARGET_OBJECTS:srv_modules>
|
||||
$<TARGET_OBJECTS:srvudppm_obj>
|
||||
$<TARGET_OBJECTS:srvudptotcp_obj>
|
||||
$<TARGET_OBJECTS:mainfunc>
|
||||
$<TARGET_OBJECTS:common_obj>
|
||||
$<TARGET_OBJECTS:udpsockmap_obj>
|
||||
@ -673,7 +683,7 @@ else()
|
||||
endif()
|
||||
|
||||
# Build standalone proxy executables
|
||||
foreach(PROXY_NAME proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr)
|
||||
foreach(PROXY_NAME proxy socks pop3p imapp smtpp ftppr tcppm udppm tcptoudp udptotcp tlspr)
|
||||
string(TOUPPER "${PROXY_NAME}" _MODULE_OPT)
|
||||
if(NOT 3PROXY_BUILD_${_MODULE_OPT})
|
||||
continue()
|
||||
@ -712,8 +722,8 @@ foreach(PROXY_NAME proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr)
|
||||
|
||||
target_compile_definitions(${PROXY_NAME} PRIVATE WITHMAIN)
|
||||
|
||||
# each takes the main loop of its kind only: udppm UDP, the others TCP
|
||||
if(PROXY_NAME STREQUAL "udppm")
|
||||
# each takes the main loop of its kind only: udppm and udptotcp UDP, the others TCP
|
||||
if(PROXY_NAME STREQUAL "udppm" OR PROXY_NAME STREQUAL "udptotcp")
|
||||
target_compile_definitions(${PROXY_NAME} PRIVATE NOTCPMAIN)
|
||||
else()
|
||||
target_compile_definitions(${PROXY_NAME} PRIVATE NOUDPMAIN)
|
||||
@ -727,7 +737,7 @@ foreach(PROXY_NAME proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr)
|
||||
|
||||
# port mappers take port, host and port as arguments, the others options
|
||||
# only; one of the two is defined, as in src/Makefile.inc
|
||||
if(PROXY_NAME STREQUAL "tcppm" OR PROXY_NAME STREQUAL "udppm" OR PROXY_NAME STREQUAL "tlspr")
|
||||
if(PROXY_NAME STREQUAL "tcppm" OR PROXY_NAME STREQUAL "udppm" OR PROXY_NAME STREQUAL "tcptoudp" OR PROXY_NAME STREQUAL "udptotcp" OR PROXY_NAME STREQUAL "tlspr")
|
||||
target_compile_definitions(${PROXY_NAME} PRIVATE PORTMAP)
|
||||
else()
|
||||
target_compile_definitions(${PROXY_NAME} PRIVATE NOPORTMAP)
|
||||
@ -741,11 +751,11 @@ foreach(PROXY_NAME proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr)
|
||||
target_sources(${PROXY_NAME} PRIVATE $<TARGET_OBJECTS:base64_obj>)
|
||||
endif()
|
||||
|
||||
if(PROXY_NAME STREQUAL "udppm")
|
||||
if(PROXY_NAME STREQUAL "udppm" OR PROXY_NAME STREQUAL "udptotcp")
|
||||
target_sources(${PROXY_NAME} PRIVATE src/hash.c src/loop.c)
|
||||
endif()
|
||||
|
||||
if(PROXY_NAME STREQUAL "socks" OR PROXY_NAME STREQUAL "udppm")
|
||||
if(PROXY_NAME STREQUAL "socks" OR PROXY_NAME STREQUAL "udppm" OR PROXY_NAME STREQUAL "tcptoudp")
|
||||
target_sources(${PROXY_NAME} PRIVATE src/udpsockmap.c)
|
||||
endif()
|
||||
endforeach()
|
||||
@ -781,7 +791,7 @@ install(TARGETS 3proxy 3proxy_crypt
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
foreach(PROXY_NAME proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr)
|
||||
foreach(PROXY_NAME proxy socks pop3p imapp smtpp ftppr tcppm udppm tcptoudp udptotcp tlspr)
|
||||
string(TOUPPER "${PROXY_NAME}" _MODULE_OPT)
|
||||
if(3PROXY_BUILD_${_MODULE_OPT})
|
||||
install(TARGETS ${PROXY_NAME}
|
||||
|
||||
@ -117,7 +117,7 @@ install: all
|
||||
if [ ! -d "$(DESTDIR)$(BINPREFIX)" ]; then mkdir -p $(DESTDIR)$(BINPREFIX)/; fi
|
||||
install bin/3proxy $(DESTDIR)$(BINPREFIX)/3proxy
|
||||
install bin/$(CRYPT_PREFIX)crypt $(DESTDIR)$(BINPREFIX)/$(CRYPT_PREFIX)crypt
|
||||
for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr; do \
|
||||
for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tcptoudp udptotcp tlspr; do \
|
||||
if [ -f bin/$(PREFIX)$$f ]; then install bin/$(PREFIX)$$f $(DESTDIR)$(BINPREFIX)/$(PREFIX)$$f; fi; \
|
||||
done
|
||||
install -d $(DESTDIR)$(prefix)/etc/3proxy/conf
|
||||
@ -134,7 +134,7 @@ install: all
|
||||
touch $(DESTDIR)$(prefix)/etc/3proxy/conf/bandlimiters
|
||||
install -d $(DESTDIR)$(MANDIR)/man8
|
||||
install -m 644 man/3proxy.8 $(DESTDIR)$(MANDIR)/man8/3proxy.8
|
||||
for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr; do \
|
||||
for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tcptoudp udptotcp tlspr; do \
|
||||
if [ -f man/$$f.8 ] && [ -f bin/$(PREFIX)$$f ]; then install -m 644 man/$$f.8 $(DESTDIR)$(MANDIR)/man8/$(PREFIX)$$f.8; fi; \
|
||||
done
|
||||
install -m 644 man/3proxy_crypt.8 $(DESTDIR)$(MANDIR)/man8/$(CRYPT_PREFIX)crypt.8
|
||||
|
||||
@ -126,8 +126,10 @@ INSTALL_OBJS = bin/3proxy \
|
||||
bin/$(PREFIX)proxy \
|
||||
bin/$(PREFIX)socks \
|
||||
bin/$(PREFIX)tcppm \
|
||||
bin/$(PREFIX)tcptoudp \
|
||||
bin/$(PREFIX)tlspr \
|
||||
bin/$(PREFIX)udppm
|
||||
bin/$(PREFIX)udppm \
|
||||
bin/$(PREFIX)udptotcp
|
||||
# the mail proxies and ftppr are only there when they were built
|
||||
ifeq ($(MAILPROXY),true)
|
||||
INSTALL_OBJS += bin/$(PREFIX)imapp bin/$(PREFIX)pop3p bin/$(PREFIX)smtpp
|
||||
@ -191,7 +193,7 @@ install-man:
|
||||
$(INSTALL_BIN) -d $(MANDIR8)
|
||||
$(INSTALL_DATA) man/3proxy.cfg.5 $(MANDIR5)
|
||||
$(INSTALL_DATA) man/3proxy.8 $(MANDIR8)
|
||||
for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr; do \
|
||||
for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tcptoudp udptotcp tlspr; do \
|
||||
if [ -f man/$$f.8 ] && [ -f bin/$(PREFIX)$$f ]; then $(INSTALL_DATA) man/$$f.8 $(MANDIR8)/$(PREFIX)$$f.8; fi; \
|
||||
done
|
||||
$(INSTALL_DATA) man/3proxy_crypt.8 $(MANDIR8)/$(CRYPT_PREFIX)crypt.8
|
||||
|
||||
@ -32,6 +32,8 @@ from the configuration file like an independent service
|
||||
.BR imapp (8)
|
||||
.BR tcppm (8)
|
||||
.BR udppm (8)
|
||||
.BR tcptoudp (8)
|
||||
.BR udptotcp (8)
|
||||
.BR ftppr (8)
|
||||
.BR dnspr
|
||||
but
|
||||
@ -161,7 +163,7 @@ configuration file
|
||||
Report all bugs to
|
||||
.BR 3proxy@3proxy.org
|
||||
.SH SEE ALSO
|
||||
3proxy.cfg(5), proxy(8), ftppr(8), socks(8), pop3p(8), imapp(8), tcppm(8), udppm(8),
|
||||
3proxy.cfg(5), proxy(8), ftppr(8), socks(8), pop3p(8), imapp(8), tcppm(8), udppm(8), tcptoudp(8), udptotcp(8),
|
||||
kill(1), syslogd(8),
|
||||
.br
|
||||
https://3proxy.org/
|
||||
|
||||
@ -79,6 +79,14 @@ Recursion is not allowed.
|
||||
.B udppm
|
||||
[options]
|
||||
\fI<SRCPORT>\fR \fI<DSTADDR>\fR \fI<DSTPORT>\fR
|
||||
.br
|
||||
.B tcptoudp
|
||||
[options]
|
||||
\fI<SRCPORT>\fR \fI<DSTADDR>\fR \fI<DSTPORT>\fR
|
||||
.br
|
||||
.B udptotcp
|
||||
[options]
|
||||
\fI<SRCPORT>\fR \fI<DSTADDR>\fR \fI<DSTPORT>\fR
|
||||
.br
|
||||
Descriptions:
|
||||
.br
|
||||
@ -127,6 +135,25 @@ but must be specified for syntax compatibility.
|
||||
.B udppm
|
||||
UDP portmapper
|
||||
|
||||
.br
|
||||
.B tcptoudp
|
||||
TCP to UDP tunnel: connections on SRCPORT carry datagrams, each with a
|
||||
two byte length in network order in front of it, sent as UDP datagrams
|
||||
to DSTADDR:DSTPORT, the answers framed the same way back. The handshake
|
||||
a client speaks \(em udptunnel's (the rfc1036 one) or ProxyGuard's HTTP
|
||||
Upgrade for UoTLV/1 (eduVPN) \(em is recognised and answered; a
|
||||
connection that begins with a length needs none. Each connection has a
|
||||
UDP socket of its own to the target.
|
||||
|
||||
.br
|
||||
.B udptotcp
|
||||
UDP to TCP tunnel: each client sending datagrams to SRCPORT is a session
|
||||
of the service with a TCP connection of its own to DSTADDR:DSTPORT, its
|
||||
datagrams sent on it with a two byte length in front of each, what comes
|
||||
back answered to the client. \fB-m\fR sends udptunnel's handshake to the
|
||||
target first, \fB-m2\fR ProxyGuard's (an HTTP Upgrade for UoTLV/1), \fB-m0\fR
|
||||
sends none, which is the default.
|
||||
|
||||
.br
|
||||
Options:
|
||||
.br
|
||||
@ -2085,7 +2112,7 @@ the tree is refused outright.
|
||||
Report all bugs to
|
||||
.BR 3proxy@3proxy.org
|
||||
.SH SEE ALSO
|
||||
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),
|
||||
3proxy(8), 3proxy_crypt(8), proxy(8), ftppr(8), socks(8), pop3p(8), imapp(8), smtpp(8), tlspr(8), tcppm(8), udppm(8), tcptoudp(8), udptotcp(8), syslogd(8),
|
||||
.br
|
||||
https://3proxy.org/
|
||||
.SH AUTHORS
|
||||
|
||||
99
man/tcptoudp.8
Normal file
99
man/tcptoudp.8
Normal file
@ -0,0 +1,99 @@
|
||||
.TH tcptoudp "8" "November 2026" "3proxy" "Universal proxy server"
|
||||
.SH NAME
|
||||
.B tcptoudp
|
||||
\- TCP to UDP tunnel
|
||||
.SH SYNOPSIS
|
||||
.BR "tcptoudp " [ -d ]
|
||||
.IB \fR[ -l \fR[ \fR[ @ \fR] logfile \fR]]
|
||||
.IB \fR[ -i internal_ip\fR]
|
||||
.IB \fR[ -e external_ip\fR]
|
||||
.I local_port remote_host remote_port
|
||||
.SH DESCRIPTION
|
||||
.B tcptoudp
|
||||
takes TCP connections on
|
||||
.I local_port
|
||||
and sends what they carry as datagrams to
|
||||
.IR remote_host : remote_port ,
|
||||
framing each datagram with its length on the connection. This is the
|
||||
server side of udptunnel (the rfc1036 one, started with \fB-s\fR) and of
|
||||
ProxyGuard (eduVPN), whose clients it answers: a connection that begins
|
||||
with udptunnel's 32 byte handshake has it taken off, one that asks with
|
||||
an HTTP Upgrade for UoTLV/1 is told the protocols are switched, and one
|
||||
that begins with a length goes to the framing at once. What comes back
|
||||
from the target is sent on the connection framed the same way. Each
|
||||
connection has a UDP socket of its own to the target; a parent the ACL
|
||||
gives is a SOCKS5 UDP relay, as for udppm.
|
||||
.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 -e
|
||||
External address. IP address of the interface the proxy should send datagrams
|
||||
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 datagrams 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.
|
||||
.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 ARGUMENTS
|
||||
.TP
|
||||
.I local_port
|
||||
- port tcptoudp accepts connections on
|
||||
.TP
|
||||
.I remote_host
|
||||
- IP address of the host datagrams are sent to
|
||||
.TP
|
||||
.I remote_port
|
||||
- remote port datagrams are sent to
|
||||
.SH CLIENTS
|
||||
udptunnel's client (without \fB-s\fR), ProxyGuard's client
|
||||
(\fBproxyguard-client\fR), or anything that puts datagrams on a TCP
|
||||
connection with a two byte length in network order in front of each.
|
||||
.SH BUGS
|
||||
Report all bugs to
|
||||
.BR 3proxy@3proxy.org
|
||||
.SH SEE ALSO
|
||||
3proxy(8), 3proxy.cfg(5), udptotcp(8), tcppm(8), udppm(8), syslogd(8),
|
||||
.br
|
||||
https://3proxy.org/
|
||||
.SH AUTHORS
|
||||
3proxy is designed by Vladimir Dubrovin <vlad@3proxy.org>
|
||||
113
man/udptotcp.8
Normal file
113
man/udptotcp.8
Normal file
@ -0,0 +1,113 @@
|
||||
.TH udptotcp "8" "November 2026" "3proxy" "Universal proxy server"
|
||||
.SH NAME
|
||||
.B udptotcp
|
||||
\- UDP to TCP tunnel
|
||||
.SH SYNOPSIS
|
||||
.BR "udptotcp " [ -d ", " \fR[ -m \fR| \fR -m2 \fR| \fR -m0 \fR] ]
|
||||
.IB \fR[ -l \fR[ \fR[ @ \fR] logfile \fR]]
|
||||
.IB \fR[ -i internal_ip\fR]
|
||||
.IB \fR[ -e external_ip\fR]
|
||||
.I local_port remote_host remote_port
|
||||
.SH DESCRIPTION
|
||||
.B udptotcp
|
||||
takes datagrams on
|
||||
.I local_port
|
||||
and sends them on a TCP connection to
|
||||
.IR remote_host : remote_port ,
|
||||
each with its length in front of it. This is the client side of udptunnel
|
||||
(the rfc1036 one) and of ProxyGuard (eduVPN): each client is a session of
|
||||
the service with a TCP connection of its own, and what comes back on the
|
||||
connection is answered to that client as datagrams. A parent the ACL
|
||||
gives is asked for a TCP connection to the target, not a UDP relay as
|
||||
udppm's.
|
||||
.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 -e
|
||||
External address. IP address of the interface the proxy should initiate the
|
||||
TCP connection 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 the TCP connection runs 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 datagrams to.
|
||||
By default, datagrams to any interface are accepted. It\'s usually unsafe.
|
||||
.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 -m
|
||||
udptunnel's handshake: the 32 bytes a client of udptunnel sends are sent
|
||||
to the target before the datagrams.
|
||||
.TP
|
||||
.B -m2
|
||||
ProxyGuard's handshake: an HTTP Upgrade for UoTLV/1 is asked of the
|
||||
target, and the datagrams begin once the target has switched protocols.
|
||||
.TP
|
||||
.B -m0
|
||||
No handshake: the datagrams are sent with none at all, which tcptoudp
|
||||
and ProxyGuard's server also take. This is the default.
|
||||
.TP
|
||||
.B -S
|
||||
Increase or decrease stack size. You may want to try something like -S8192 if you experience 3proxy
|
||||
crashes.
|
||||
.SH ARGUMENTS
|
||||
.TP
|
||||
.I local_port
|
||||
- port udptotcp accepts datagrams on
|
||||
.TP
|
||||
.I remote_host
|
||||
- IP address of the host the TCP connection is made to
|
||||
.TP
|
||||
.I remote_port
|
||||
- remote port the TCP connection is made to
|
||||
.SH CLIENTS
|
||||
Any UDP-based application can be used as a client. Use
|
||||
.I internal_ip
|
||||
and
|
||||
.I local_port
|
||||
as the destination in the client application. The datagrams are carried
|
||||
to
|
||||
.IR remote_host : remote_port
|
||||
and the answers come back.
|
||||
.SH BUGS
|
||||
Report all bugs to
|
||||
.BR 3proxy@3proxy.org
|
||||
.SH SEE ALSO
|
||||
3proxy(8), 3proxy.cfg(5), tcptoudp(8), tcppm(8), udppm(8), syslogd(8),
|
||||
.br
|
||||
https://3proxy.org/
|
||||
.SH AUTHORS
|
||||
3proxy is designed by Vladimir Dubrovin <vlad@3proxy.org>
|
||||
@ -39,8 +39,10 @@ make clean
|
||||
/bin/3proxy_proxy
|
||||
/bin/3proxy_socks
|
||||
/bin/3proxy_tcppm
|
||||
/bin/3proxy_tcptoudp
|
||||
/bin/3proxy_tlspr
|
||||
/bin/3proxy_udppm
|
||||
/bin/3proxy_udptotcp
|
||||
/bin/add3proxyuser
|
||||
%config(noreplace) /etc/3proxy/3proxy.cfg
|
||||
/etc/3proxy/conf
|
||||
|
||||
@ -29,7 +29,7 @@ void httpsrv_init(void);
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULTCONFIG
|
||||
#define DEFAULTCONFIG conf->stringtable[25]
|
||||
#define DEFAULTCONFIG conf->stringtable[27]
|
||||
#endif
|
||||
|
||||
FILE * confopen();
|
||||
|
||||
@ -5,7 +5,7 @@ PROXYMAIN = proxymain.c mainconf.c mainlisten.c mainclient.c maintcp.c mainudp.c
|
||||
# 3 proxy common Makefile
|
||||
#
|
||||
|
||||
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
|
||||
all: $(BUILDDIR)3proxy$(EXESUFFICS) $(BUILDDIR)$(CRYPT_PREFIX)crypt$(EXESUFFICS) $(MAIL_EXES) $(FTP_EXES) $(BUILDDIR)$(PREFIX)tcppm$(EXESUFFICS) $(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS) $(BUILDDIR)$(PREFIX)tcptoudp$(EXESUFFICS) $(BUILDDIR)$(PREFIX)udptotcp$(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
|
||||
@ -58,6 +58,12 @@ tcppm$(OBJSUFFICS): tcppm.c proxy.h structures.h $(PROXYMAIN)
|
||||
udppm$(OBJSUFFICS): udppm.c proxy.h structures.h $(PROXYMAIN)
|
||||
$(CC) $(CFLAGS) $(DEFINEOPTION)WITHMAIN $(DEFINEOPTION)PORTMAP $(DEFINEOPTION)NOTCPMAIN udppm.c
|
||||
|
||||
tcptoudp$(OBJSUFFICS): tcptoudp.c proxy.h structures.h udptunnel.h $(PROXYMAIN)
|
||||
$(CC) $(CFLAGS) $(DEFINEOPTION)WITHMAIN $(DEFINEOPTION)PORTMAP $(DEFINEOPTION)NOUDPMAIN tcptoudp.c
|
||||
|
||||
udptotcp$(OBJSUFFICS): udptotcp.c proxy.h structures.h udptunnel.h $(PROXYMAIN)
|
||||
$(CC) $(CFLAGS) $(DEFINEOPTION)WITHMAIN $(DEFINEOPTION)PORTMAP $(DEFINEOPTION)NOTCPMAIN udptotcp.c
|
||||
|
||||
tlspr$(OBJSUFFICS): tlspr.c proxy.h structures.h $(PROXYMAIN)
|
||||
$(CC) $(CFLAGS) $(DEFINEOPTION)WITHMAIN $(DEFINEOPTION)PORTMAP $(DEFINEOPTION)NOUDPMAIN tlspr.c
|
||||
|
||||
@ -92,6 +98,12 @@ $(BUILDDIR)$(PREFIX)tcppm$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUF
|
||||
$(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS): sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) hash$(OBJSUFFICS) loop$(OBJSUFFICS)
|
||||
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) hash$(OBJSUFFICS) loop$(OBJSUFFICS) $(LIBS)
|
||||
|
||||
$(BUILDDIR)$(PREFIX)tcptoudp$(EXESUFFICS): sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tcptoudp$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS)
|
||||
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)tcptoudp$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tcptoudp$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) $(LIBS)
|
||||
|
||||
$(BUILDDIR)$(PREFIX)udptotcp$(EXESUFFICS): sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udptotcp$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) hash$(OBJSUFFICS) loop$(OBJSUFFICS)
|
||||
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)udptotcp$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udptotcp$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) hash$(OBJSUFFICS) loop$(OBJSUFFICS) $(LIBS)
|
||||
|
||||
$(BUILDDIR)$(PREFIX)tlspr$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tlspr$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS)
|
||||
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)tlspr$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tlspr$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) $(LIBS)
|
||||
|
||||
@ -137,6 +149,12 @@ srvhttpsrv$(OBJSUFFICS): httpsrv.c proxy.h structures.h
|
||||
srvudppm$(OBJSUFFICS): udppm.c proxy.h structures.h
|
||||
$(CC) $(COUT)srvudppm$(OBJSUFFICS) $(CFLAGS) udppm.c
|
||||
|
||||
srvtcptoudp$(OBJSUFFICS): tcptoudp.c proxy.h structures.h udptunnel.h
|
||||
$(CC) $(COUT)srvtcptoudp$(OBJSUFFICS) $(CFLAGS) tcptoudp.c
|
||||
|
||||
srvudptotcp$(OBJSUFFICS): udptotcp.c proxy.h structures.h udptunnel.h
|
||||
$(CC) $(COUT)srvudptotcp$(OBJSUFFICS) $(CFLAGS) udptotcp.c
|
||||
|
||||
srvdnspr$(OBJSUFFICS): dnspr.c proxy.h structures.h
|
||||
$(CC) $(COUT)srvdnspr$(OBJSUFFICS) $(CFLAGS) dnspr.c
|
||||
|
||||
@ -206,6 +224,6 @@ ssl$(OBJSUFFICS): ssl.c structures.h proxy.h ssl.h
|
||||
pcre$(OBJSUFFICS): pcre.c structures.h
|
||||
$(CC) $(COUT)pcre$(OBJSUFFICS) $(CFLAGS) $(DEFINEOPTION)WITH_PCRE pcre.c
|
||||
|
||||
$(BUILDDIR)3proxy$(EXESUFFICS): 3proxy$(OBJSUFFICS) loop$(OBJSUFFICS) fiber$(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) sem$(OBJSUFFICS) auth$(OBJSUFFICS) acl$(OBJSUFFICS) limiter$(OBJSUFFICS) redirect$(OBJSUFFICS) authradius$(OBJSUFFICS) hash$(OBJSUFFICS) hashtables$(OBJSUFFICS) resolve$(OBJSUFFICS) sql$(OBJSUFFICS) conf$(OBJSUFFICS) log$(OBJSUFFICS) datatypes$(OBJSUFFICS) md4$(OBJSUFFICS) md5$(OBJSUFFICS) blake2$(OBJSUFFICS) 3proxy_crypt$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) $(HTTPSRV_OBJS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) mdhash$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(TRANSPARENT_OBJS) $(COMPATLIBS) $(VERSIONDEP)
|
||||
$(LN) $(LNOUT)$(BUILDDIR)3proxy$(EXESUFFICS) $(LDFLAGS) $(VERFILE) 3proxy$(OBJSUFFICS) loop$(OBJSUFFICS) fiber$(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) sem$(OBJSUFFICS) log$(OBJSUFFICS) 3proxy_crypt$(OBJSUFFICS) md4$(OBJSUFFICS) md5$(OBJSUFFICS) blake2$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) $(HTTPSRV_OBJS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) mdhash$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(TRANSPARENT_OBJS) $(COMPATLIBS) $(LIBS) $(PCRE_LIBS)
|
||||
$(BUILDDIR)3proxy$(EXESUFFICS): 3proxy$(OBJSUFFICS) loop$(OBJSUFFICS) fiber$(OBJSUFFICS) mainfunc$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvimapp$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvudppm$(OBJSUFFICS) srvtcptoudp$(OBJSUFFICS) srvudptotcp$(OBJSUFFICS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) auth$(OBJSUFFICS) acl$(OBJSUFFICS) limiter$(OBJSUFFICS) redirect$(OBJSUFFICS) authradius$(OBJSUFFICS) hash$(OBJSUFFICS) hashtables$(OBJSUFFICS) resolve$(OBJSUFFICS) sql$(OBJSUFFICS) conf$(OBJSUFFICS) log$(OBJSUFFICS) datatypes$(OBJSUFFICS) md4$(OBJSUFFICS) md5$(OBJSUFFICS) blake2$(OBJSUFFICS) 3proxy_crypt$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) $(HTTPSRV_OBJS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) mdhash$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(TRANSPARENT_OBJS) $(COMPATLIBS) $(VERSIONDEP)
|
||||
$(LN) $(LNOUT)$(BUILDDIR)3proxy$(EXESUFFICS) $(LDFLAGS) $(VERFILE) 3proxy$(OBJSUFFICS) loop$(OBJSUFFICS) fiber$(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) srvtcptoudp$(OBJSUFFICS) srvudptotcp$(OBJSUFFICS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) 3proxy_crypt$(OBJSUFFICS) md4$(OBJSUFFICS) md5$(OBJSUFFICS) blake2$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) $(HTTPSRV_OBJS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) mdhash$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(TRANSPARENT_OBJS) $(COMPATLIBS) $(LIBS) $(PCRE_LIBS)
|
||||
|
||||
|
||||
19
src/conf.c
19
src/conf.c
@ -31,7 +31,7 @@ void transparent_install(void);
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULTCONFIG
|
||||
#define DEFAULTCONFIG conf->stringtable[25]
|
||||
#define DEFAULTCONFIG conf->stringtable[27]
|
||||
#endif
|
||||
|
||||
_3proxy_mutex_t bandlim_mutex;
|
||||
@ -296,6 +296,21 @@ static int h_proxy(int argc, unsigned char ** argv){
|
||||
childdef.service = S_UDPPM;
|
||||
childdef.helpmessage = " -s single packet UDP service for request/reply (DNS-like) services\n";
|
||||
}
|
||||
else if(!strcmp((char *)argv[0], "tcptoudp")) {
|
||||
childdef.pf = tcptoudpchild;
|
||||
childdef.port = 0;
|
||||
childdef.isudp = 0;
|
||||
childdef.service = S_TCPTOUDP;
|
||||
childdef.helpmessage = " the handshake a client speaks, udptunnel's or ProxyGuard's, is answered\n";
|
||||
}
|
||||
else if(!strcmp((char *)argv[0], "udptotcp")) {
|
||||
childdef.pf = NULL;
|
||||
childdef.udp = &udptotcpservice;
|
||||
childdef.port = 0;
|
||||
childdef.isudp = 1;
|
||||
childdef.service = S_UDPTOTCP;
|
||||
childdef.helpmessage = " -m - udptunnel handshake with the target, -m2 - ProxyGuard's, -m0 - none\n";
|
||||
}
|
||||
#ifdef WITH_HTTPSRV
|
||||
else if(!strcmp((char *)argv[0], "admin")) {
|
||||
/* The same service as httpsrv, with the administration pages
|
||||
@ -2059,6 +2074,8 @@ struct commands commandhandlers[]={
|
||||
{NULL, "socks", h_proxy, 1, 0},
|
||||
{NULL, "tcppm", h_proxy, 4, 0},
|
||||
{NULL, "udppm", h_proxy, 4, 0},
|
||||
{NULL, "tcptoudp", h_proxy, 4, 0},
|
||||
{NULL, "udptotcp", h_proxy, 4, 0},
|
||||
#ifdef WITH_HTTPSRV
|
||||
{NULL, "admin", h_proxy, 1, 0},
|
||||
#endif
|
||||
|
||||
@ -1585,6 +1585,14 @@ void * httpsrvchild(struct clientparam *param)
|
||||
r.lasthost = lasthost;
|
||||
param->res = 0;
|
||||
|
||||
/* What the request brought belongs to it alone. A connection
|
||||
can carry a client's request after another's, as a reverse
|
||||
proxy reuses its upstreams, so the credentials and the host
|
||||
of an earlier request decide nothing for this one. */
|
||||
*param->hostname = 0;
|
||||
*param->username = 0;
|
||||
*param->password = 0;
|
||||
|
||||
answered = httpsrv_request(param, &r);
|
||||
handoff = r.handoff;
|
||||
param->climark = -1;
|
||||
|
||||
@ -561,6 +561,12 @@ static int srvprepare(struct srvstart *s, int argc, char **argv){
|
||||
case 'U':
|
||||
srv->udpauth = *(argv[i]+2)? atoi(argv[i]+2) : 0;
|
||||
break;
|
||||
case 'm':
|
||||
/* udptotcp: which handshake the target is spoken to with */
|
||||
if(srv->service == S_UDPTOTCP)
|
||||
srv->s_option = argv[i][2]? atoi(argv[i]+2) : 1;
|
||||
else error = 1;
|
||||
break;
|
||||
case 'B':
|
||||
/* the TLS ClientHello split at the SNI (tlspr), which -s is
|
||||
where -s is not splice; s_option means something else
|
||||
|
||||
@ -632,6 +632,15 @@ for(;;){
|
||||
hdrfree(&buf, &bufown);
|
||||
hdrsdone = 0;
|
||||
|
||||
/* What the request brought belongs to it alone. A connection can carry
|
||||
a request after another's, so the credentials of an earlier request
|
||||
decide nothing for this one. */
|
||||
*param->username = 0;
|
||||
*param->password = 0;
|
||||
param->pwtype = 0;
|
||||
*param->extusername = 0;
|
||||
*param->extpassword = 0;
|
||||
|
||||
if(keepalive && (param->cliinbuf == param->clioffset) && (param->remsock != INVALID_SOCKET)){
|
||||
memset(fds, 0, sizeof(fds));
|
||||
fds[0].fd = param->clisock;
|
||||
|
||||
@ -310,7 +310,7 @@ struct udploop {
|
||||
uint64_t monotime(void);
|
||||
int udpanswer(struct udploop *u, struct clientparam *param, unsigned char *buf, int len);
|
||||
|
||||
extern const struct udpservice udppmservice, dnsprservice;
|
||||
extern const struct udpservice udppmservice, dnsprservice, udptotcpservice;
|
||||
int socks5_setaddr(int family, int atyp, const unsigned char *addr, PROXYSOCKADDRTYPE *sa);
|
||||
/* which of a service's network namespaces a socket is made in */
|
||||
#define NS_IN 0 /* -ni: what faces the clients */
|
||||
@ -565,6 +565,7 @@ void * smtppchild(struct clientparam * param);
|
||||
void * proxychild(struct clientparam * param);
|
||||
void * sockschild(struct clientparam * param);
|
||||
void * tcppmchild(struct clientparam * param);
|
||||
void * tcptoudpchild(struct clientparam * param);
|
||||
void * autochild(struct clientparam * param);
|
||||
#ifdef WITH_HTTPSRV
|
||||
int op_admin(struct httpreq *r, const unsigned char *params);
|
||||
|
||||
@ -32,20 +32,20 @@ unsigned char * strings[] = {
|
||||
/* 19 */ (unsigned char *)"TLSPR",
|
||||
/* 20 */ (unsigned char *)"IMAPP",
|
||||
/* 21 */ (unsigned char *)"HTTPSRV",
|
||||
/* 22 */ (unsigned char *)"ZOMBIE",
|
||||
/* 23 */ NULL,
|
||||
/* 24 */ NULL,
|
||||
/* 22 */ (unsigned char *)"TCPTOUDP",
|
||||
/* 23 */ (unsigned char *)"UDPTOTCP",
|
||||
/* 24 */ (unsigned char *)"ZOMBIE",
|
||||
/* 25 */ NULL,
|
||||
/* 26 */ NULL,
|
||||
#ifndef TPROXY_CONF
|
||||
#ifndef _WIN32
|
||||
/* 25 */ (unsigned char *)"/usr/local/etc/3proxy/3proxy.cfg",
|
||||
/* 27 */ (unsigned char *)"/usr/local/etc/3proxy/3proxy.cfg",
|
||||
#else
|
||||
/* 25 */ (unsigned char *)"3proxy.cfg",
|
||||
/* 27 */ (unsigned char *)"3proxy.cfg",
|
||||
#endif
|
||||
#else
|
||||
/* 25 */ (unsigned char *)TPROXY_CONF,
|
||||
/* 27 */ (unsigned char *)TPROXY_CONF,
|
||||
#endif
|
||||
/* 26 */ NULL,
|
||||
/* 27 */ NULL,
|
||||
/* 28 */ NULL,
|
||||
/* 29 */ NULL,
|
||||
/* 30 */ NULL,
|
||||
|
||||
@ -197,6 +197,8 @@ typedef enum {
|
||||
S_TLSPR,
|
||||
S_IMAPP,
|
||||
S_HTTPSRV,
|
||||
S_TCPTOUDP,
|
||||
S_UDPTOTCP,
|
||||
S_ZOMBIE
|
||||
}PROXYSERVICE;
|
||||
|
||||
|
||||
230
src/tcptoudp.c
Normal file
230
src/tcptoudp.c
Normal file
@ -0,0 +1,230 @@
|
||||
/*
|
||||
3APA3A simplest proxy server
|
||||
(c) 2002-2026 by Vladimir Dubrovin <vlad@3proxy.org>
|
||||
|
||||
please read License Agreement
|
||||
|
||||
*/
|
||||
|
||||
#include "proxy.h"
|
||||
#include "udptunnel.h"
|
||||
|
||||
#ifndef PORTMAP
|
||||
#define PORTMAP
|
||||
#endif
|
||||
#define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
|
||||
|
||||
/* tcptoudp: a TCP connection in, datagrams out, to the one target the
|
||||
service is given. What the connection carries is datagrams with
|
||||
their length in front of them (udptunnel.h); the handshake a client
|
||||
speaks, udptunnel's or ProxyGuard's, is recognised and answered. A
|
||||
parent the ACL gives is a SOCKS UDP relay, as for udppm. */
|
||||
|
||||
/* what the connection's first bytes have said, or not yet */
|
||||
enum { HS_MAYBE, HS_RAW, HS_TUNNEL, HS_HTTP };
|
||||
|
||||
/* ProxyGuard's server answer, which ends its handshake */
|
||||
static const unsigned char tcptoudp101[] =
|
||||
"HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Upgrade: " UDPTUN_PROTO "\r\n"
|
||||
"\r\n";
|
||||
|
||||
/* A datagram of the client, from buf, on to the target or the first
|
||||
relay of a chain, the headers of the hops after it and of the target
|
||||
in front of it: as udppm sends one. */
|
||||
static void tcptoudpforward(struct clientparam *param, unsigned char *data, int len){
|
||||
int i, off = 0;
|
||||
|
||||
if(param->bandlimfunc && (*param->bandlimfunc)(param, 0, len)) return;
|
||||
if(param->udp_nhops){
|
||||
for(i = 1; i < param->udp_nhops; i++)
|
||||
off += socks5_udp_build_hdr(param->clibuf + off, ¶m->udp_relay[i-1]);
|
||||
off += socks5_udp_build_hdr(param->clibuf + off, ¶m->req);
|
||||
}
|
||||
if(len > param->clibufsize - off) len = param->clibufsize - off;
|
||||
memcpy(param->clibuf + off, data, len);
|
||||
param->srv->so._sendto(param->sostate, param->remsock, (char *)param->clibuf, off + len, 0,
|
||||
(struct sockaddr *)¶m->sinsr, SASIZE(¶m->sinsr));
|
||||
param->statscli64 += len;
|
||||
param->nwrites++;
|
||||
}
|
||||
|
||||
/* The datagrams framed in b[0..*len): each on to the target, what is
|
||||
left of one moved to the front. 0, or the res of a framing no
|
||||
datagram can be (a length the buffers cannot hold). */
|
||||
static int tcptoudpframes(struct clientparam *param, unsigned char *b, int *len){
|
||||
int off = 0, n;
|
||||
|
||||
while(*len - off >= UDPTUN_HDR){
|
||||
n = udptunget(b + off);
|
||||
if(n > param->srvbufsize - UDPTUN_HDR) return 483;
|
||||
if(*len - off < UDPTUN_HDR + n) break;
|
||||
tcptoudpforward(param, b + off + UDPTUN_HDR, n);
|
||||
off += UDPTUN_HDR + n;
|
||||
}
|
||||
if(off){
|
||||
memmove(b, b + off, *len - off);
|
||||
*len -= off;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Where the end of a handshake's header block was looked for up to */
|
||||
static int tcptoudphdrend(unsigned char *b, int from, int len){
|
||||
int i;
|
||||
|
||||
for(i = from; i + 3 < len; i++)
|
||||
if(b[i] == '\r' && b[i+1] == '\n' && b[i+2] == '\r' && b[i+3] == '\n') return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int tcptoudpmap(struct clientparam *param, int timeo){
|
||||
struct pollfd fds[2];
|
||||
PROXYSOCKADDRTYPE from;
|
||||
SASIZETYPE size;
|
||||
unsigned char *b = param->srvbuf;
|
||||
int bufsize = param->srvbufsize;
|
||||
int len = 0, res, n, hs = HS_MAYBE, hscan = 0;
|
||||
|
||||
for(;;){
|
||||
fds[0].fd = param->clisock;
|
||||
fds[0].events = POLLIN;
|
||||
fds[0].revents = 0;
|
||||
fds[1].fd = param->remsock;
|
||||
fds[1].events = POLLIN;
|
||||
fds[1].revents = 0;
|
||||
res = sockpoll(¶m->srv->so, param->sostate, fds, 2, timeo * 1000);
|
||||
if(res < 0) return 481;
|
||||
if(res == 0) return 92;
|
||||
|
||||
/* a reload: the session goes by the newest configuration's
|
||||
rules, as a connection of sockmap() does */
|
||||
if(param->version < runconf->version) {
|
||||
if(param->srv->noforce || !reattachfunc) param->version = runconf->version;
|
||||
else if((n = (*reattachfunc)(param, 1)) && n != 2) return n;
|
||||
}
|
||||
|
||||
if(fds[0].revents){
|
||||
n = (int)param->srv->so._recvfrom(param->sostate, param->clisock,
|
||||
(char *)b + len, bufsize - len, 0, NULL, NULL);
|
||||
if(n == 0) return 0;
|
||||
if(n < 0){
|
||||
if(errno == EAGAIN || errno == EINTR) n = 0;
|
||||
else return 482;
|
||||
}
|
||||
len += n;
|
||||
|
||||
/* the handshake, until the first bytes tell which */
|
||||
if(hs == HS_MAYBE){
|
||||
/* 'G' of "GET " or 'u' of "udptunnel by ", or neither */
|
||||
if(len >= 1 && b[0] != 'G' && b[0] != 'u') hs = HS_RAW;
|
||||
else if(len >= 4){
|
||||
if(!memcmp(b, "GET ", 4)) hs = HS_HTTP;
|
||||
else if(!memcmp(b, "udpt", 4)) hs = HS_TUNNEL;
|
||||
else hs = HS_RAW;
|
||||
}
|
||||
}
|
||||
if(hs == HS_TUNNEL){
|
||||
if(len < UDPTUN_MAGIC_LEN) continue;
|
||||
memmove(b, b + UDPTUN_MAGIC_LEN, len - UDPTUN_MAGIC_LEN);
|
||||
len -= UDPTUN_MAGIC_LEN;
|
||||
hs = HS_RAW;
|
||||
}
|
||||
else if(hs == HS_HTTP){
|
||||
n = tcptoudphdrend(b, hscan > 3? hscan - 3 : 0, len);
|
||||
if(n < 0){
|
||||
hscan = len;
|
||||
if(len >= UDPTUN_MAXHDR || len >= bufsize) return 484;
|
||||
continue;
|
||||
}
|
||||
/* the header block names the protocol or it is not
|
||||
ProxyGuard asking */
|
||||
if(!udptunprotoin(b, n)) return 484;
|
||||
if(socksend(param, param->clisock, (unsigned char *)tcptoudp101,
|
||||
(int)sizeof(tcptoudp101) - 1, timeo) != (int)sizeof(tcptoudp101) - 1)
|
||||
return 487;
|
||||
memmove(b, b + n + 4, len - n - 4);
|
||||
len -= n + 4;
|
||||
hs = HS_RAW;
|
||||
}
|
||||
if((res = tcptoudpframes(param, b, &len))) return res;
|
||||
/* a datagram longer than the buffer is no client's */
|
||||
if(len == bufsize) return 483;
|
||||
}
|
||||
|
||||
if(fds[1].revents){
|
||||
int k, next, off = 0;
|
||||
|
||||
size = sizeof(from);
|
||||
n = (int)param->srv->so._recvfrom(param->sostate, param->remsock,
|
||||
(char *)param->clibuf + UDPTUN_HDR, param->clibufsize - UDPTUN_HDR, 0,
|
||||
(struct sockaddr *)&from, &size);
|
||||
if(n < 0 && (errno == EAGAIN || errno == EINTR)) continue;
|
||||
#ifdef _WIN32
|
||||
/* an earlier datagram was refused (ICMP): not fatal */
|
||||
if(n < 0 && WSAGetLastError() == WSAECONNRESET) continue;
|
||||
#endif
|
||||
if(n <= 0) return 486;
|
||||
if(!param->udp_nhops){
|
||||
/* none but the target itself */
|
||||
if(!SAISNULL(¶m->sinsr) && *SAPORT(¶m->sinsr) &&
|
||||
(SAADDRLEN(&from) != SAADDRLEN(¶m->sinsr) ||
|
||||
memcmp(SAADDR(&from), SAADDR(¶m->sinsr), SAADDRLEN(&from)) ||
|
||||
memcmp(SAPORT(&from), SAPORT(¶m->sinsr), 2)))
|
||||
return 0;
|
||||
}
|
||||
else for(k = 0; k < param->udp_nhops; k++){
|
||||
if((next = socks5_udp_skip_hdr(param->clibuf + UDPTUN_HDR + off, n - off)) < 0) break;
|
||||
off += next;
|
||||
}
|
||||
if(off) n -= off;
|
||||
param->statssrv64 += n;
|
||||
param->nreads++;
|
||||
if(param->bandlimfunc && (*param->bandlimfunc)(param, n, 0)) continue;
|
||||
udptunput(param->clibuf, n);
|
||||
if(socksend(param, param->clisock, param->clibuf, n + UDPTUN_HDR, timeo) != n + UDPTUN_HDR)
|
||||
return 487;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *tcptoudpchild(struct clientparam* param) {
|
||||
int res;
|
||||
|
||||
if(!*param->hostname){
|
||||
if(parsehostname((char *)param->srv->target, param, ntohs(param->srv->targetport))) RETURN(100);
|
||||
}
|
||||
param->sinsl = *SAFAMILY(¶m->req) == AF_INET6? param->srv->extsa6 : param->srv->extsa;
|
||||
*SAPORT(¶m->sinsl) = 0;
|
||||
param->sinsr = param->req;
|
||||
param->operation = UDPASSOC;
|
||||
res = (*param->srv->authfunc)(param);
|
||||
if(res) {RETURN(res);}
|
||||
if (param->npredatfilters){
|
||||
int action;
|
||||
action = handlepredatflt(param);
|
||||
if(action == HANDLED) RETURN(0);
|
||||
if(action != PASS) RETURN(19);
|
||||
}
|
||||
if(param->redirectfunc){
|
||||
return (void *)param->redirectfunc;
|
||||
}
|
||||
if((res = udpbind(param))) RETURN(res);
|
||||
RETURN(tcptoudpmap(param, param->srv->timeouts[CONNECTION_L]));
|
||||
CLEANRET:
|
||||
dolog(param, *param->hostname? param->hostname : NULL);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
#ifdef WITHMAIN
|
||||
struct proxydef childdef = {
|
||||
tcptoudpchild,
|
||||
0,
|
||||
0,
|
||||
S_TCPTOUDP,
|
||||
" the handshake a client speaks, udptunnel's or ProxyGuard's, is answered\n",
|
||||
NULL
|
||||
};
|
||||
#include "proxymain.c"
|
||||
#endif
|
||||
307
src/udptotcp.c
Normal file
307
src/udptotcp.c
Normal file
@ -0,0 +1,307 @@
|
||||
/*
|
||||
3APA3A simplest proxy server
|
||||
(c) 2002-2026 by Vladimir Dubrovin <vlad@3proxy.org>
|
||||
|
||||
please read License Agreement
|
||||
|
||||
*/
|
||||
|
||||
#include "proxy.h"
|
||||
#include "udptunnel.h"
|
||||
|
||||
#ifndef PORTMAP
|
||||
#define PORTMAP
|
||||
#endif
|
||||
#ifndef UDP
|
||||
#define UDP
|
||||
#endif
|
||||
|
||||
/* udptotcp: datagrams in, from any number of clients, each client a
|
||||
session of the service's own (see udploop() in proxymain.c) with a
|
||||
TCP connection of its own to the target. On the connection the
|
||||
datagrams carry their length in front of them (udptunnel.h); -m
|
||||
sends udptunnel's handshake to the target first, -m2 ProxyGuard's
|
||||
HTTP Upgrade, -m0 (the default) none. What comes back on the
|
||||
connection is answered to the client the session is. A parent the
|
||||
ACL gives is asked for a TCP connection, unlike udppm's UDP relay. */
|
||||
|
||||
/* the handshake -m asks for: none, udptunnel's, ProxyGuard's */
|
||||
enum { U2T_NONE, U2T_TUNNEL, U2T_HTTP };
|
||||
|
||||
/* what the session's connection is up to */
|
||||
enum { U2T_CONNECTING, U2T_ASKING, U2T_RUN };
|
||||
|
||||
struct u2t {
|
||||
int state;
|
||||
int mode; /* the handshake of U2T_* */
|
||||
unsigned char *out; /* framed datagrams waiting to be written */
|
||||
int outlen, outoff, outcap;
|
||||
unsigned char in[UDPTUN_HDR + UDPBUFSIZE]; /* a datagram being read */
|
||||
int inlen;
|
||||
};
|
||||
|
||||
/* udptunnel's handshake, "udptunnel by md." of the rfc1036 udptunnel
|
||||
followed by zeroes and a counting sequence */
|
||||
static const unsigned char u2tmagic[UDPTUN_MAGIC_LEN] =
|
||||
"udptunnel by md."
|
||||
"\0\0\0\001\003\006\020\025\041\050\066\105\125\146\170\221";
|
||||
|
||||
/* bytes at the end of the queue, or -1 if the connection is gone */
|
||||
static int u2tflush(struct clientparam *param, struct u2t *d){
|
||||
while(d->outoff < d->outlen){
|
||||
int s = (int)param->srv->so._send(param->sostate, param->remsock,
|
||||
(char *)d->out + d->outoff, d->outlen - d->outoff, 0);
|
||||
|
||||
if(s > 0){ d->outoff += s; continue; }
|
||||
if(s < 0 && (errno == EAGAIN || errno == EINTR)) return 0;
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void u2tcompact(struct u2t *d){
|
||||
if(d->outoff){
|
||||
memmove(d->out, d->out + d->outoff, d->outlen - d->outoff);
|
||||
d->outlen -= d->outoff;
|
||||
d->outoff = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* bytes without a prefix on the queue, a handshake's; -1 without room */
|
||||
static int u2tput(struct u2t *d, const unsigned char *data, int n){
|
||||
unsigned char *o;
|
||||
|
||||
if(d->outlen + n > d->outcap){
|
||||
int want = d->outcap? 2 * d->outcap : UDPBUFSIZE;
|
||||
|
||||
while(want < d->outlen + n){
|
||||
int w = 2 * want;
|
||||
|
||||
if(w <= want) return -1;
|
||||
want = w;
|
||||
}
|
||||
if(!(o = realloc(d->out, want))) return -1;
|
||||
d->out = o;
|
||||
d->outcap = want;
|
||||
}
|
||||
memcpy(d->out + d->outlen, data, n);
|
||||
d->outlen += n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* a datagram, with its length in front of it, on the queue */
|
||||
static int u2tframe(struct u2t *d, const unsigned char *data, int n){
|
||||
unsigned char h[UDPTUN_HDR];
|
||||
|
||||
udptunput(h, n);
|
||||
if(u2tput(d, h, UDPTUN_HDR)) return -1;
|
||||
return u2tput(d, data, n);
|
||||
}
|
||||
|
||||
/* Where the end of a header block was looked for up to */
|
||||
static int u2thdrend(unsigned char *b, int from, int len){
|
||||
int i;
|
||||
|
||||
for(i = from; i + 3 < len; i++)
|
||||
if(b[i] == '\r' && b[i+1] == '\n' && b[i+2] == '\r' && b[i+3] == '\n') return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int udptotcpfirst(struct udploop *u, struct udpsession *ss, unsigned char *buf, int len){
|
||||
struct clientparam *param = ss->param;
|
||||
struct u2t *d;
|
||||
int res;
|
||||
SOCKET s;
|
||||
|
||||
if(parsehostname((char *)param->srv->target, param, ntohs(param->srv->targetport))) return (param->res = 100);
|
||||
param->sinsl = *SAFAMILY(¶m->req) == AF_INET6? param->srv->extsa6 : param->srv->extsa;
|
||||
*SAPORT(¶m->sinsl) = 0;
|
||||
param->sinsr = param->req;
|
||||
/* a parent, if the ACL gives one, is asked for a TCP connection */
|
||||
param->operation = CONNECT;
|
||||
if((res = (*param->srv->authfunc)(param))) return (param->res = res);
|
||||
if(!(d = calloc(1, sizeof(*d)))) return (param->res = 21);
|
||||
ss->data = d;
|
||||
d->mode = param->srv->s_option == U2T_TUNNEL || param->srv->s_option == U2T_HTTP?
|
||||
param->srv->s_option : U2T_NONE;
|
||||
|
||||
/* the chain walk, if a parent gave a connection, has connected it;
|
||||
otherwise the session's own is connected as the loop sees it
|
||||
writable (dnspr asks a name server over TCP the same way) */
|
||||
if(param->remsock == INVALID_SOCKET){
|
||||
if((s = nssocket(param->srv, ¶m->srv->so, param->sostate, NS_OUT, SASOCK(¶m->sinsr), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET){
|
||||
free(d);
|
||||
ss->data = NULL;
|
||||
return (param->res = 11);
|
||||
}
|
||||
param->remsock = s;
|
||||
if((*param->srv->so._connect)(param->sostate, s, (struct sockaddr *)¶m->sinsr, SASIZE(¶m->sinsr))
|
||||
#ifdef _WIN32
|
||||
&& WSAGetLastError() != WSAEWOULDBLOCK
|
||||
#else
|
||||
&& errno != EINPROGRESS
|
||||
#endif
|
||||
){
|
||||
free(d);
|
||||
ss->data = NULL;
|
||||
return (param->res = 12);
|
||||
}
|
||||
}
|
||||
d->state = U2T_CONNECTING;
|
||||
ss->events = POLLOUT;
|
||||
ss->deadline = u->now + (uint64_t)param->srv->timeouts[CONNECT_TO] * 1000;
|
||||
|
||||
/* the handshake the mode asks for, sent once the connection is
|
||||
made, the first datagram after it */
|
||||
if(d->mode == U2T_TUNNEL){
|
||||
if(u2tput(d, u2tmagic, UDPTUN_MAGIC_LEN)) return (param->res = 21);
|
||||
}
|
||||
else if(d->mode == U2T_HTTP){
|
||||
char req[HOSTNAMELEN + 128];
|
||||
|
||||
res = sprintf(req, "GET / HTTP/1.1\r\nHost: %.256s\r\nUser-Agent: 3proxy\r\nConnection: Upgrade\r\nUpgrade: " UDPTUN_PROTO "\r\n\r\n",
|
||||
(char *)param->srv->target);
|
||||
if(u2tput(d, (unsigned char *)req, res)) return (param->res = 21);
|
||||
}
|
||||
if(!param->bandlimfunc || !(*param->bandlimfunc)(param, 0, len)){
|
||||
if(u2tframe(d, buf, len)) return (param->res = 21);
|
||||
param->statscli64 += len;
|
||||
param->nwrites++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int udptotcpclient(struct udploop *u, struct udpsession *ss, unsigned char *buf, int len){
|
||||
struct clientparam *param = ss->param;
|
||||
struct u2t *d = ss->data;
|
||||
|
||||
if(param->bandlimfunc && (*param->bandlimfunc)(param, 0, len)) return 0;
|
||||
/* the connection is not taking what it is given */
|
||||
if(d->outlen - d->outoff > 65536) return (param->res = 487);
|
||||
if(u2tframe(d, buf, len)) return (param->res = 21);
|
||||
param->statscli64 += len;
|
||||
param->nwrites++;
|
||||
if(d->state == U2T_RUN){
|
||||
if(u2tflush(param, d) < 0) return (param->res = 487);
|
||||
u2tcompact(d);
|
||||
ss->events = d->outoff < d->outlen? POLLIN | POLLOUT : POLLIN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int udptotcpserver(struct udploop *u, struct udpsession *ss){
|
||||
struct clientparam *param = ss->param;
|
||||
struct u2t *d = ss->data;
|
||||
int len, n, off, err;
|
||||
SASIZETYPE elen;
|
||||
|
||||
if(d->state == U2T_CONNECTING){
|
||||
err = 0;
|
||||
elen = sizeof(err);
|
||||
if(param->srv->so._getsockopt(param->sostate, param->remsock, SOL_SOCKET, SO_ERROR, (char *)&err, &elen) || err)
|
||||
return (param->res = 60);
|
||||
d->state = d->mode == U2T_HTTP? U2T_ASKING : U2T_RUN;
|
||||
/* the handshake and the datagrams after it */
|
||||
if(u2tflush(param, d) < 0) return (param->res = 487);
|
||||
u2tcompact(d);
|
||||
if(d->state == U2T_RUN){
|
||||
ss->idle = param->srv->timeouts[STRING_L];
|
||||
ss->deadline = u->now + (uint64_t)ss->idle * 1000;
|
||||
ss->events = d->outoff < d->outlen? POLLIN | POLLOUT : POLLIN;
|
||||
}
|
||||
else ss->events = POLLIN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(d->state == U2T_ASKING){
|
||||
/* ProxyGuard's answer: a header block, then the framing */
|
||||
int i;
|
||||
|
||||
len = (int)param->srv->so._recv(param->sostate, param->remsock,
|
||||
(char *)d->in + d->inlen, (int)sizeof(d->in) - d->inlen, 0);
|
||||
if(len < 0 && (errno == EAGAIN || errno == EINTR)) return 0;
|
||||
if(len <= 0) return (param->res = 487);
|
||||
d->inlen += len;
|
||||
i = u2thdrend(d->in, (d->inlen - len > 3)? d->inlen - len - 3 : 0, d->inlen);
|
||||
if(i < 0){
|
||||
if(d->inlen >= UDPTUN_MAXHDR || d->inlen >= (int)sizeof(d->in)) return (param->res = 63);
|
||||
return 0;
|
||||
}
|
||||
/* a 101 answer naming the protocol */
|
||||
n = 0;
|
||||
while(n < i && d->in[n] != ' ') n++;
|
||||
if(n + 4 > i || memcmp(d->in + n + 1, "101", 3) || !udptunprotoin(d->in, i))
|
||||
return (param->res = 63);
|
||||
d->inlen -= i + 4;
|
||||
if(d->inlen > 0) memmove(d->in, d->in + i + 4, d->inlen);
|
||||
d->state = U2T_RUN;
|
||||
ss->idle = param->srv->timeouts[STRING_L];
|
||||
ss->deadline = u->now + (uint64_t)ss->idle * 1000;
|
||||
ss->events = d->outoff < d->outlen? POLLIN | POLLOUT : POLLIN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* U2T_RUN: first what waits, then what has come */
|
||||
if(d->outoff < d->outlen){
|
||||
if(u2tflush(param, d) < 0) return (param->res = 487);
|
||||
u2tcompact(d);
|
||||
ss->events = d->outoff < d->outlen? POLLIN | POLLOUT : POLLIN;
|
||||
}
|
||||
len = (int)param->srv->so._recv(param->sostate, param->remsock,
|
||||
(char *)d->in + d->inlen, (int)sizeof(d->in) - d->inlen, 0);
|
||||
if(len < 0 && (errno == EAGAIN || errno == EINTR)) return 0;
|
||||
if(len == 0) return 1; /* the target closed: over */
|
||||
if(len < 0) return (param->res = 486);
|
||||
d->inlen += len;
|
||||
off = 0;
|
||||
while(d->inlen - off >= UDPTUN_HDR){
|
||||
n = udptunget(d->in + off);
|
||||
if(n > UDPBUFSIZE) return (param->res = 483);
|
||||
if(d->inlen - off < UDPTUN_HDR + n) break;
|
||||
param->statssrv64 += n;
|
||||
param->nreads++;
|
||||
if(!param->bandlimfunc || !(*param->bandlimfunc)(param, n, 0))
|
||||
udpanswer(u, param, d->in + off + UDPTUN_HDR, n);
|
||||
off += UDPTUN_HDR + n;
|
||||
}
|
||||
if(off){
|
||||
memmove(d->in, d->in + off, d->inlen - off);
|
||||
d->inlen -= off;
|
||||
}
|
||||
/* half a datagram, and no room for the rest of it */
|
||||
if(d->inlen == (int)sizeof(d->in)) return (param->res = 483);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void udptotcpend(struct udploop *u, struct udpsession *ss){
|
||||
struct u2t *d = ss->data;
|
||||
|
||||
if(d){
|
||||
free(d->out);
|
||||
free(d);
|
||||
ss->data = NULL;
|
||||
}
|
||||
dolog(ss->param, NULL);
|
||||
}
|
||||
|
||||
const struct udpservice udptotcpservice = {
|
||||
1,
|
||||
udptotcpfirst,
|
||||
udptotcpclient,
|
||||
udptotcpserver,
|
||||
udptotcpend,
|
||||
92,
|
||||
NULL
|
||||
};
|
||||
|
||||
#ifdef WITHMAIN
|
||||
struct proxydef childdef = {
|
||||
NULL,
|
||||
0,
|
||||
1,
|
||||
S_UDPTOTCP,
|
||||
" -m - udptunnel handshake with the target, -m2 - ProxyGuard's, -m0 - none\n",
|
||||
&udptotcpservice
|
||||
};
|
||||
#include "proxymain.c"
|
||||
#endif
|
||||
69
src/udptunnel.h
Normal file
69
src/udptunnel.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
3APA3A simplest proxy server
|
||||
(c) 2002-2026 by Vladimir Dubrovin <vlad@3proxy.org>
|
||||
|
||||
please read License Agreement
|
||||
|
||||
*/
|
||||
|
||||
/* What the tunnels between TCP and UDP speak, tcptoudp and udptotcp:
|
||||
datagrams on a TCP connection, each with its length, in network
|
||||
order, in front of it. udptunnel (the rfc1036 one) and ProxyGuard's
|
||||
UoTLV/1 (eduVPN) put datagrams on a connection the same way; what
|
||||
they differ in is what comes first:
|
||||
|
||||
- nothing: the framing alone;
|
||||
- udptunnel's handshake: 32 bytes beginning "udptunnel by ", which
|
||||
the client sends and no answer follows;
|
||||
- ProxyGuard's: an HTTP Upgrade, the client asking with "GET",
|
||||
"Connection: Upgrade" and "Upgrade: UoTLV/1", the server answering
|
||||
"101 Switching Protocols" before the framing begins.
|
||||
|
||||
Which of these a connection speaks is told by its first bytes, "GET"
|
||||
or "udptunnel by ", so tcptoudp takes any of them from a client;
|
||||
udptotcp sends the one it was configured to (-m: udptunnel's, -m2:
|
||||
ProxyGuard's, -m0: none). */
|
||||
|
||||
#ifndef _UDPTUNNEL_H
|
||||
#define _UDPTUNNEL_H
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
/* the length of the prefix a datagram carries on the connection */
|
||||
#define UDPTUN_HDR 2
|
||||
/* udptunnel's handshake: "udptunnel by md." of the rfc1036 udptunnel,
|
||||
followed by zeroes and a counting sequence; any 32 bytes beginning
|
||||
with the prefix are taken, the original Columbia one included */
|
||||
#define UDPTUN_MAGIC_LEN 32
|
||||
#define UDPTUN_PREFIX "udptunnel by "
|
||||
#define UDPTUN_PREFIX_LEN 13
|
||||
/* ProxyGuard's protocol, as the Upgrade: header names it */
|
||||
#define UDPTUN_PROTO "UoTLV/1"
|
||||
/* a header of a handshake is not longer */
|
||||
#define UDPTUN_MAXHDR 2048
|
||||
|
||||
/* the length a datagram's prefix tells */
|
||||
static int udptunget(const unsigned char *p){
|
||||
return (p[0] << 8) | p[1];
|
||||
}
|
||||
|
||||
/* the prefix of a datagram of this length */
|
||||
static void udptunput(unsigned char *p, int n){
|
||||
p[0] = (unsigned char)(n >> 8);
|
||||
p[1] = (unsigned char)n;
|
||||
}
|
||||
|
||||
/* whether the bytes of a handshake name the protocol, whatever the
|
||||
case of the letters */
|
||||
static int udptunprotoin(const unsigned char *b, int len){
|
||||
int i, j;
|
||||
|
||||
for(i = 0; i + 7 <= len; i++){
|
||||
for(j = 0; j < 7; j++)
|
||||
if(tolower(b[i + j]) != tolower((unsigned char)UDPTUN_PROTO[j])) break;
|
||||
if(j == 7) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,5 +1,7 @@
|
||||
"""Authentication and access rules in front of the HTTP server."""
|
||||
|
||||
import base64
|
||||
|
||||
|
||||
def run(t):
|
||||
if not t.skip_unless("httpsrv"):
|
||||
@ -49,3 +51,19 @@ def run(t):
|
||||
|
||||
t.contains(t.http(url + "/echo", auth=("alice", "secret")), "path=/echo",
|
||||
"an authenticated request is dispatched")
|
||||
|
||||
# --- credentials do not outlive the request that carried them ------
|
||||
# A kept connection answers a second request without credentials as
|
||||
# unauthenticated: a reverse proxy reuses its upstreams between
|
||||
# clients, so one client's login must not open another's way in.
|
||||
creds = base64.b64encode(b"alice:secret").decode()
|
||||
text, closed = t.raw_session(srv,
|
||||
f"GET /echo HTTP/1.1\r\nHost: t\r\n"
|
||||
f"Authorization: Basic {creds}\r\n\r\n"
|
||||
f"GET /echo HTTP/1.1\r\nHost: t\r\nConnection: close\r\n\r\n")
|
||||
parts = text.split("HTTP/1.")
|
||||
t.eq(3, len(parts), "the kept connection answers both requests")
|
||||
t.eq(True, parts[1].startswith("1 200"),
|
||||
"the request with credentials is allowed")
|
||||
t.eq(True, parts[2].startswith("0 401"),
|
||||
"the request after it, without credentials, is refused")
|
||||
|
||||
@ -4,6 +4,8 @@ Access rules accumulate until "flush", so each service section here starts
|
||||
from a clean list.
|
||||
"""
|
||||
|
||||
import base64
|
||||
|
||||
|
||||
def run(t):
|
||||
if not t.skip_unless("httpsrv"):
|
||||
@ -108,3 +110,18 @@ def run(t):
|
||||
t.eq(407, t.http(origin + "/echo", proxy=needs_auth,
|
||||
proxy_auth=("alice", "wrong")).status,
|
||||
"wrong proxy credentials are refused")
|
||||
|
||||
# credentials do not outlive the request which carried them: a second
|
||||
# request on the same connection, without them, is asked again
|
||||
creds = base64.b64encode(b"alice:secret").decode()
|
||||
text, closed = t.raw_session(auth,
|
||||
f"GET {origin}/echo HTTP/1.1\r\nHost: 127.0.0.1:{srv}\r\n"
|
||||
f"Proxy-Authorization: Basic {creds}\r\n\r\n"
|
||||
f"GET {origin}/echo HTTP/1.1\r\nHost: 127.0.0.1:{srv}\r\n"
|
||||
f"Connection: close\r\n\r\n")
|
||||
parts = text.split("HTTP/1.")
|
||||
t.eq(3, len(parts), "the kept connection answers both requests")
|
||||
t.eq(True, parts[1].startswith("1 200"),
|
||||
"the request with credentials is allowed")
|
||||
t.eq(True, parts[2].startswith("0 407"),
|
||||
"the request after it, without credentials, is refused")
|
||||
|
||||
106
tests/cases/tunnels.py
Normal file
106
tests/cases/tunnels.py
Normal file
@ -0,0 +1,106 @@
|
||||
"""The UDP<->TCP tunnels: udptotcp takes datagrams to a TCP connection,
|
||||
tcptoudp takes a TCP connection to datagrams, the datagrams on the
|
||||
connection carrying their length, as udptunnel and ProxyGuard put them."""
|
||||
|
||||
import socket
|
||||
import struct
|
||||
import threading
|
||||
|
||||
UDP_MAGIC = b"udptunnel by md.\0\0\0\x01\x03\x06\x10\x15\x21\x28\x36\x45\x55\x66\x78\x91"
|
||||
PG_GET = (b"GET / HTTP/1.1\r\nHost: 127.0.0.1\r\nUser-Agent: test\r\n"
|
||||
b"Connection: Upgrade\r\nUpgrade: UoTLV/1\r\n\r\n")
|
||||
|
||||
|
||||
def frame(payload):
|
||||
return struct.pack(">H", len(payload)) + payload
|
||||
|
||||
|
||||
def read_frames(sock, state, count, timeout=10.0):
|
||||
"""count length-prefixed datagrams from sock; state[0] is the bytes
|
||||
already read and not yet used."""
|
||||
out = []
|
||||
sock.settimeout(timeout)
|
||||
while len(out) < count:
|
||||
while len(state[0]) >= 2:
|
||||
need = 2 + struct.unpack(">H", state[0][:2])[0]
|
||||
if len(state[0]) < need:
|
||||
break
|
||||
out.append(state[0][2:need])
|
||||
state[0] = state[0][need:]
|
||||
if len(out) >= count:
|
||||
return out
|
||||
data = sock.recv(65536)
|
||||
if not data:
|
||||
raise EOFError("the tunnel closed")
|
||||
state[0] += data
|
||||
return out
|
||||
|
||||
|
||||
def run(t):
|
||||
echo = t.udp_echo()
|
||||
tunnel = t.free_port() # udptotcp listens here
|
||||
tunnel_hs = t.free_port() # the same, udptunnel's handshake
|
||||
server = t.free_port() # tcptoudp listens here
|
||||
plain = t.free_port() # tcptoudp for the handshake clients
|
||||
|
||||
t.start("tunnels", f"""
|
||||
log
|
||||
auth iponly
|
||||
allow *
|
||||
udptotcp {tunnel} 127.0.0.1 {server}
|
||||
udptotcp -m {tunnel_hs} 127.0.0.1 {server}
|
||||
|
||||
flush
|
||||
auth iponly
|
||||
allow *
|
||||
tcptoudp {server} 127.0.0.1 {echo}
|
||||
tcptoudp {plain} 127.0.0.1 {echo}
|
||||
""", ports=[server, plain])
|
||||
# a UDP service answers only once it is asked, so ask until it does
|
||||
if t.wait_udp(tunnel):
|
||||
t.ok("the UDP side of the tunnel is up")
|
||||
else:
|
||||
t.fail("the UDP side of the tunnel is up")
|
||||
|
||||
# --- a datagram each way, through both services ---------------
|
||||
t.eq(b"echo:hello", t.udp_exchange(tunnel, b"hello"),
|
||||
"a datagram reaches the target through the tunnel")
|
||||
t.eq(b"echo:again", t.udp_exchange(tunnel, b"again"),
|
||||
"a second datagram uses the same session")
|
||||
big = b"x" * 4000
|
||||
t.eq(b"echo:" + big, t.udp_exchange(tunnel, big),
|
||||
"a larger datagram survives the round trip")
|
||||
|
||||
# --- udptunnel's handshake, accepted by tcptoudp ---------------
|
||||
if t.wait_udp(tunnel_hs):
|
||||
t.ok("the UDP side of the udptunnel-handshake tunnel is up")
|
||||
t.eq(b"echo:with handshake", t.udp_exchange(tunnel_hs, b"with handshake"),
|
||||
"a datagram with udptunnel's handshake before it is answered")
|
||||
|
||||
# --- a client speaking udptunnel, to tcptoudp ------------------
|
||||
s = socket.create_connection(("127.0.0.1", plain), timeout=10)
|
||||
s.sendall(UDP_MAGIC + frame(b"udptunnel asks"))
|
||||
t.eq([b"echo:udptunnel asks"], read_frames(s, [b""], 1),
|
||||
"a udptunnel client is answered")
|
||||
s.close()
|
||||
|
||||
# --- a client speaking ProxyGuard, to tcptoudp -----------------
|
||||
s = socket.create_connection(("127.0.0.1", plain), timeout=10)
|
||||
s.sendall(PG_GET)
|
||||
head = b""
|
||||
while b"\r\n\r\n" not in head:
|
||||
head += s.recv(4096)
|
||||
t.eq(True, head.startswith(b"HTTP/1.1 101"),
|
||||
"ProxyGuard's client is told the protocols are switched")
|
||||
t.contains(head.decode("latin1"), "UoTLV/1", "the answer names the protocol")
|
||||
s.sendall(frame(b"proxyguard asks"))
|
||||
t.eq([b"echo:proxyguard asks"], read_frames(s, [b""], 1),
|
||||
"ProxyGuard's datagram is answered")
|
||||
s.close()
|
||||
|
||||
# --- a client that frames, two datagrams in one write ----------
|
||||
s = socket.create_connection(("127.0.0.1", plain), timeout=10)
|
||||
s.sendall(frame(b"first") + frame(b"second"))
|
||||
t.eq([b"echo:first", b"echo:second"], read_frames(s, [b""], 2),
|
||||
"two datagrams in one write are both answered")
|
||||
s.close()
|
||||
Loading…
Reference in New Issue
Block a user