Fix: dnspr was broken since udppm rewrite. -F (fake resolve to redirect traffic) option added to dnspr

This commit is contained in:
Vladimir Dubrovin 2026-07-22 17:34:51 +03:00
parent 87fc8ae4ee
commit c94766dff7
6 changed files with 173 additions and 6 deletions

View File

@ -33,6 +33,7 @@
<li><a href="#NAMES">How to resolve names through a parent proxy</a></li> <li><a href="#NAMES">How to resolve names through a parent proxy</a></li>
<li><a href="#ISFTP">How to set up an FTP proxy</a></li> <li><a href="#ISFTP">How to set up an FTP proxy</a></li>
<li><a href="#TLSPR">How to set up an SNI proxy (tlspr)</a></li> <li><a href="#TLSPR">How to set up an SNI proxy (tlspr)</a></li>
<li><a href="#DNSPR">How to set up a DNS proxy (dnspr)</a></li>
<li><a href="#SSLPLUGIN">How to set up TLS/SSL (https proxy, mTLS)</a></li> <li><a href="#SSLPLUGIN">How to set up TLS/SSL (https proxy, mTLS)</a></li>
<li><a href="#CERTIFICATES">How to create CA and certificates for SSL</a></li> <li><a href="#CERTIFICATES">How to create CA and certificates for SSL</a></li>
<li><a href="#PCRE">How to use PCRE filtering (regular expressions)</a></li> <li><a href="#PCRE">How to use PCRE filtering (regular expressions)</a></li>
@ -599,8 +600,8 @@ proxy -p8080 -i192.168.2.1
<p> <p>
<b>Implicit vs explicit TLS:</b> <b>Implicit vs explicit TLS:</b>
</p><p> </p><p>
Implicit TLS means TLS from the first byte of the connection: https (443), imaps (993), submissions (465). Implicit TLS means TLS from the first byte of the connection: https (443), imaps (993), SMTP submission secure (submissions) (465).
Explicit TLS means the connection starts in plaintext and is upgraded with a STARTTLS/STLS command: imap (143), submission (587), pop3 (110). Explicit TLS means the connection starts in plaintext and is upgraded with a STARTTLS/STLS command: imap (143), SMTP 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 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 the -X option makes tlspr speak the plaintext protocol phase with the client (greeting, STARTTLS command) before
upgrading both sides to TLS. Example: upgrading both sides to TLS. Example:
@ -637,6 +638,10 @@ with, for example, iptables:
iptables -t nat -A PREROUTING -p tcp -m multiport --dports 443,993,465 -j REDIRECT --to-port 1443 iptables -t nat -A PREROUTING -p tcp -m multiport --dports 443,993,465 -j REDIRECT --to-port 1443
</pre> </pre>
<p> <p>
Alternatively, if clients use dnspr as their DNS resolver, traffic can be redirected via DNS —
see <a href="#DNSPR">How to set up a DNS proxy (dnspr)</a>.
</p>
<p>
<b>SNI Break (DPI Bypass):</b> <b>SNI Break (DPI Bypass):</b>
<br>tlspr can be used as a parent with the "tls" type to implement SNI splitting for DPI bypass (similar to NoDPI/GoodByeDPI). <br>tlspr can be used as a parent with the "tls" type to implement SNI splitting for DPI bypass (similar to NoDPI/GoodByeDPI).
The client sends the first part of the TLS ClientHello, tlspr splits it at the SNI extension and sends it in two TCP packets, The client sends the first part of the TLS ClientHello, tlspr splits it at the SNI extension and sends it in two TCP packets,
@ -681,6 +686,47 @@ parent 1000 tls 0.0.0.0 0
deny * * blocked.example.com deny * * blocked.example.com
allow * allow *
proxy proxy
</pre>
</p>
<li><a name="DNSPR"><i>How to set up a DNS proxy (dnspr)</i></a></li>
<p>
dnspr is a DNS forwarding service. It answers queries from the 3proxy name cache (including static nsrecord
entries), forwards other queries to the resolvers configured with nserver, and caches the results if
nscache/nscache6 are configured. Options:
</p><pre>
-s - simple DNS forwarding: do not use 3proxy resolver / name cache
-F&lt;ip&gt; - fake: answer all A (or AAAA) queries with the given IP address.
May be given twice - once with an IPv4 and once with an IPv6 address.
</pre>
<p>
dnspr can be used to redirect traffic by hostname, e.g. to point mail clients to a
<a href="#TLSPR">tlspr</a> installation, by adding nsrecord entries for the service hostnames
(nscache/nscache6 keep the answers for all other names intact):
</p><pre>
nscache 65536
nscache6 65536
dnspr -p53
# google
nsrecord smtp.gmail.com 10.0.0.1
nsrecord imap.gmail.com 10.0.0.1
nsrecord pop.gmail.com 10.0.0.1
# mail.ru
nsrecord smtp.mail.ru 10.0.0.1
nsrecord imap.mail.ru 10.0.0.1
nsrecord pop.mail.ru 10.0.0.1
# yandex.ru
nsrecord smtp.yandex.ru 10.0.0.1
nsrecord imap.yandex.ru 10.0.0.1
nsrecord pop.yandex.ru 10.0.0.1
</pre>
<p>
where 10.0.0.1 is the address tlspr listens on. If every hostname must be redirected, a single fake
address can be used instead of individual nsrecords:
</p><pre>
nscache 65536
nscache6 65536
dnspr -p53 -F10.0.0.1
</pre> </pre>
</p> </p>
<li><a name="SSLPLUGIN"><i>How to set up TLS/SSL (https proxy, mTLS)</i></a> <li><a name="SSLPLUGIN"><i>How to set up TLS/SSL (https proxy, mTLS)</i></a>

View File

@ -33,6 +33,7 @@
<li><a href="#NAMES">Как разрешать имена на родительском прокси?</a></li> <li><a href="#NAMES">Как разрешать имена на родительском прокси?</a></li>
<li><a href="#ISFTP">Как настроить FTP прокси?</a></li> <li><a href="#ISFTP">Как настроить FTP прокси?</a></li>
<li><a href="#TLSPR">Как настроить SNI proxy (tlspr)</a></li> <li><a href="#TLSPR">Как настроить SNI proxy (tlspr)</a></li>
<li><a href="#DNSPR">Как настроить DNS proxy (dnspr)</a></li>
<li><a href="#SSLPLUGIN">Как настроить TLS/SSL (https прокси, mTLS)</a></li> <li><a href="#SSLPLUGIN">Как настроить TLS/SSL (https прокси, mTLS)</a></li>
<li><a href="#CERTIFICATES">Как создать CA и сертификаты для SSL</a></li> <li><a href="#CERTIFICATES">Как создать CA и сертификаты для SSL</a></li>
<li><a href="#PCRE">Как использовать PCRE-фильтрацию (регулярные выражения)</a></li> <li><a href="#PCRE">Как использовать PCRE-фильтрацию (регулярные выражения)</a></li>
@ -590,6 +591,7 @@
Еще одна задача которую может решать модуль - требование наличия TLS или mTLS (mutual TLS). Еще одна задача которую может решать модуль - требование наличия TLS или mTLS (mutual TLS).
Если tlspr используется как отдельный сервис без использования плагина Transparent, то необходимо задать порт назначения через опцию -P (по умолчанию 443), Если tlspr используется как отдельный сервис без использования плагина Transparent, то необходимо задать порт назначения через опцию -P (по умолчанию 443),
т.к. TLS хендшейк не содержит информации о порте назначения. т.к. TLS хендшейк не содержит информации о порте назначения.
Примечание: tlspr не поддерживает аутентификацию пользователей (в TLS-хендшейке нет учетных данных); используйте ACL по IP или родительский прокси с аутентификацией, если требуется контроль доступа.
</p><p> </p><p>
<b>Опции:</b> <b>Опции:</b>
</p><pre> </p><pre>
@ -600,8 +602,54 @@
2 - требовать TLS, проверять наличие client и server HELLO 2 - требовать TLS, проверять наличие client и server HELLO
3 - требовать TLS, проверять наличие серверного сертификата (не совместим с TLS 1.3+) 3 - требовать TLS, проверять наличие серверного сертификата (не совместим с TLS 1.3+)
4 - требовать взаимный (mutual) TLS, проверять что сервер запрашивает сертификат и клиент его отправляет (не совместим с TLS 1.3+) 4 - требовать взаимный (mutual) TLS, проверять что сервер запрашивает сертификат и клиент его отправляет (не совместим с TLS 1.3+)
-Ximap | -Xpop3 | -Xsmtp - режим explicit TLS (STARTTLS): tlspr говорит с клиентом
на plaintext-протоколе (приветствие, команда STARTTLS), затем поднимает TLS с обеих сторон
</pre> </pre>
<p> <p>
<b>Implicit и explicit TLS:</b>
</p><p>
Implicit TLS означает TLS с первого байта соединения: https (443), imaps (993), SMTP submission secure (submissions) (465).
Explicit TLS означает, что соединение начинается в plaintext и поднимается до TLS командой STARTTLS/STLS: imap (143), SMTP submission (587), pop3 (110).
tlspr поддерживает оба варианта: для implicit TLS хост назначения берется из SNI, а порт из -P; для explicit TLS
опция -X заставляет tlspr говорить с клиентом на plaintext-фазе протокола (приветствие, команда STARTTLS) перед
поднятием TLS с обеих сторон. Пример:
</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>
Примечание: для explicit TLS вместо tlspr -X можно использовать протокольные сервисы smtpp, imapp и pop3p; они
также поддерживают STARTTLS.
</p><p>
<b>Рекомендуемая конфигурация - перенаправление трафика:</b> наиболее универсальная конфигурация - перенаправлять
TLS-трафик (порты 443, 993, 465, 143, 587, 110) на tlspr правилами внешнего маршрутизатора или локальными
правилами (плагин Transparent). Исходные адрес и порт назначения сохраняются, -P и отдельные сервисы для каждого
порта не требуются, implicit и explicit TLS работают в рамках одной установки.
</p><pre>
auth iponly
allow *
tlspr -p1443 -c1
</pre>
<p>
например, с iptables:
</p><pre>
iptables -t nat -A PREROUTING -p tcp -m multiport --dports 443,993,465 -j REDIRECT --to-port 1443
</pre>
<p>
Также, если клиенты используют dnspr в качестве DNS-резолвера, трафик можно перенаправлять через DNS —
см. <a href="#DNSPR">Как настроить DNS proxy (dnspr)</a>.
</p>
<p>
<b>SNI Break (обход DPI):</b> <b>SNI Break (обход DPI):</b>
<br>tlspr может использоваться как родительский прокси типа "tls" для реализации SNI-фрагментации (аналог NoDPI/GoodByeDPI). <br>tlspr может использоваться как родительский прокси типа "tls" для реализации SNI-фрагментации (аналог NoDPI/GoodByeDPI).
Клиент отправляет первую часть TLS ClientHello, tlspr разбивает его на расширении SNI и отправляет двумя TCP-пакетами, Клиент отправляет первую часть TLS ClientHello, tlspr разбивает его на расширении SNI и отправляет двумя TCP-пакетами,
@ -649,6 +697,48 @@ proxy
</pre> </pre>
</p> </p>
<li><a name="DNSPR"><i>Как настроить DNS proxy (dnspr)</i></a></li>
<p>
dnspr - сервис пересылки DNS-запросов. Он отвечает на запросы из кэша имен 3proxy (включая статические записи
nsrecord), пересылает остальные запросы на резолверы, заданные командой nserver, и кэширует результаты, если
настроены nscache/nscache6. Опции:
</p><pre>
-s - простая пересылка DNS: не использовать резолвер / кэш имен 3proxy
-F&lt;ip&gt; - fake: отвечать на все A (или AAAA) запросы заданным IP-адресом.
Может быть указана дважды - один раз с IPv4 и один раз с IPv6 адресом.
</pre>
<p>
dnspr можно использовать для перенаправления трафика по имени хоста, например, чтобы направить почтовых
клиентов на установку <a href="#TLSPR">tlspr</a>, добавив записи nsrecord для имен почтовых сервисов
(nscache/nscache6 сохраняют ответы для всех остальных имен):
</p><pre>
nscache 65536
nscache6 65536
dnspr -p53
# google
nsrecord smtp.gmail.com 10.0.0.1
nsrecord imap.gmail.com 10.0.0.1
nsrecord pop.gmail.com 10.0.0.1
# mail.ru
nsrecord smtp.mail.ru 10.0.0.1
nsrecord imap.mail.ru 10.0.0.1
nsrecord pop.mail.ru 10.0.0.1
# yandex.ru
nsrecord smtp.yandex.ru 10.0.0.1
nsrecord imap.yandex.ru 10.0.0.1
nsrecord pop.yandex.ru 10.0.0.1
</pre>
<p>
где 10.0.0.1 - адрес, на котором слушает tlspr. Если перенаправлять нужно все имена, вместо отдельных
записей nsrecord можно использовать один fake-адрес:
</p><pre>
nscache 65536
nscache6 65536
dnspr -p53 -F10.0.0.1
</pre>
</p>
<li><a name="SSLPLUGIN"><i>Как настроить TLS/SSL (https прокси, mTLS)</i></a> <li><a name="SSLPLUGIN"><i>Как настроить TLS/SSL (https прокси, mTLS)</i></a>
<p> <p>
Начиная с версии 0.9.7 поддержка TLS/SSL встроена в 3proxy при компиляции с OpenSSL Начиная с версии 0.9.7 поддержка TLS/SSL встроена в 3proxy при компиляции с OpenSSL

View File

@ -264,7 +264,7 @@ static int h_proxy(int argc, unsigned char ** argv){
childdef.port = 53; childdef.port = 53;
childdef.isudp = 1; childdef.isudp = 1;
childdef.service = S_DNSPR; childdef.service = S_DNSPR;
childdef.helpmessage = " -s - simple DNS forwarding - do not use 3proxy resolver / name cache\n"; childdef.helpmessage = " -s - simple DNS forwarding - do not use 3proxy resolver / name cache\n -Fip - fake: answer all A queries with this IP\n";
#ifndef NOIPV6 #ifndef NOIPV6
if(!resolvfunc || (resolvfunc == myresolver && !dns_table.poolsize) || resolvfunc == fakeresolver){ if(!resolvfunc || (resolvfunc == myresolver && !dns_table.poolsize) || resolvfunc == fakeresolver){
fprintf(stderr, "[line %d] Warning: no nserver/nscache configured, dnspr will not work as expected\n", linenum); fprintf(stderr, "[line %d] Warning: no nserver/nscache configured, dnspr will not work as expected\n", linenum);

View File

@ -25,6 +25,7 @@ void * dnsprchild(struct clientparam* param) {
SASIZETYPE size; SASIZETYPE size;
int res, i; int res, i;
int len; int len;
int semlocked = 1;
unsigned type=0; unsigned type=0;
uint32_t ttl; uint32_t ttl;
unsigned char addr[16]; unsigned char addr[16];
@ -38,10 +39,13 @@ void * dnsprchild(struct clientparam* param) {
RETURN (21); RETURN (21);
} }
buf = bbuf+2; buf = bbuf+2;
size = sizeof(param->sincr);
i = param->srv->so._recvfrom(param->sostate, param->srv->srvsock, (char *)buf, BUFSIZE, 0, (struct sockaddr *)&param->sincr, &size);
size = sizeof(param->sinsl); size = sizeof(param->sinsl);
getsockname(param->srv->srvsock, (struct sockaddr *)&param->sincl, &size); getsockname(param->srv->srvsock, (struct sockaddr *)&param->sincl, &size);
i = param->srv->udplen;
if(i > BUFSIZE) i = BUFSIZE;
memcpy(buf, param->srv->udpbuf, i);
_3proxy_sem_unlock(udpinit);
semlocked = 0;
#ifdef _WIN32 #ifdef _WIN32
if((param->clisock=param->srv->so._socket(param->sostate, AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { if((param->clisock=param->srv->so._socket(param->sostate, AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
RETURN(818); RETURN(818);
@ -82,7 +86,19 @@ void * dnsprchild(struct clientparam* param) {
*s2 = (len - (int)(s2 - buf)) - 1; *s2 = (len - (int)(s2 - buf)) - 1;
type = ((unsigned)buf[len+1])*256 + (unsigned)buf[len+2]; type = ((unsigned)buf[len+1])*256 + (unsigned)buf[len+2];
if((type==0x01 || type==0x1c) && !param->srv->s_option){ if(type==0x01 && param->srv->fakeip){
ip = 1;
ttl = 3600;
*(uint32_t *)addr = param->srv->fakeip;
}
#ifndef NOIPV6
else if(type==0x1c && *(uint32_t *)param->srv->fakeip6){
ip = 1;
ttl = 3600;
memcpy(addr, param->srv->fakeip6, 16);
}
#endif
else if((type==0x01 || type==0x1c) && !param->srv->s_option){
ip = udpresolve((type==0x1c)?AF_INET6:AF_INET, (unsigned char *)host, addr, &ttl, param, 0); ip = udpresolve((type==0x1c)?AF_INET6:AF_INET, (unsigned char *)host, addr, &ttl, param, 0);
} }
@ -191,6 +207,7 @@ void * dnsprchild(struct clientparam* param) {
CLEANRET: CLEANRET:
if(semlocked) _3proxy_sem_unlock(udpinit);
if(param->res!=813){ if(param->res!=813){
sprintf((char *)buf, "%04x/%s/", sprintf((char *)buf, "%04x/%s/",
(unsigned)type, (unsigned)type,

View File

@ -537,6 +537,18 @@ int MODULEMAINFUNC (int argc, char** argv){
else if(!strncasecmp(argv[i]+2, "smtp", 4)) srv.srvstarttls = S_SMTPP; else if(!strncasecmp(argv[i]+2, "smtp", 4)) srv.srvstarttls = S_SMTPP;
else error = 1; else error = 1;
break; break;
case 'F':
{
PROXYSOCKADDRTYPE fsa;
memset(&fsa, 0, sizeof(fsa));
if(!getip46(46, (unsigned char *)argv[i]+2, (struct sockaddr *)&fsa)) error = 1;
else if(*SAFAMILY(&fsa) == AF_INET) srv.fakeip = *(uint32_t *)SAADDR(&fsa);
#ifndef NOIPV6
else if(*SAFAMILY(&fsa) == AF_INET6) memcpy(srv.fakeip6, SAADDR(&fsa), 16);
#endif
else error = 1;
}
break;
case 'T': case 'T':
srv.transparent = 1; srv.transparent = 1;
break; break;

View File

@ -539,6 +539,8 @@ struct srvparam {
int haproxy; int haproxy;
int nostarttls; int nostarttls;
PROXYSERVICE srvstarttls; PROXYSERVICE srvstarttls;
uint32_t fakeip;
unsigned char fakeip6[16];
#ifdef WITHSPLICE #ifdef WITHSPLICE
int usesplice; int usesplice;
#endif #endif