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="#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="#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="#CERTIFICATES">How to create CA and certificates for SSL</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>
<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).
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), 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
the -X option makes tlspr speak the plaintext protocol phase with the client (greeting, STARTTLS command) before
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
</pre>
<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>
<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,
@ -681,6 +686,47 @@ parent 1000 tls 0.0.0.0 0
deny * * blocked.example.com
allow *
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>
</p>
<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="#ISFTP">Как настроить FTP прокси?</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="#CERTIFICATES">Как создать CA и сертификаты для SSL</a></li>
<li><a href="#PCRE">Как использовать PCRE-фильтрацию (регулярные выражения)</a></li>
@ -590,6 +591,7 @@
Еще одна задача которую может решать модуль - требование наличия TLS или mTLS (mutual TLS).
Если tlspr используется как отдельный сервис без использования плагина Transparent, то необходимо задать порт назначения через опцию -P (по умолчанию 443),
т.к. TLS хендшейк не содержит информации о порте назначения.
Примечание: tlspr не поддерживает аутентификацию пользователей (в TLS-хендшейке нет учетных данных); используйте ACL по IP или родительский прокси с аутентификацией, если требуется контроль доступа.
</p><p>
<b>Опции:</b>
</p><pre>
@ -600,8 +602,54 @@
2 - требовать TLS, проверять наличие client и server HELLO
3 - требовать TLS, проверять наличие серверного сертификата (не совместим с TLS 1.3+)
4 - требовать взаимный (mutual) TLS, проверять что сервер запрашивает сертификат и клиент его отправляет (не совместим с TLS 1.3+)
-Ximap | -Xpop3 | -Xsmtp - режим explicit TLS (STARTTLS): tlspr говорит с клиентом
на plaintext-протоколе (приветствие, команда STARTTLS), затем поднимает TLS с обеих сторон
</pre>
<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>
<br>tlspr может использоваться как родительский прокси типа "tls" для реализации SNI-фрагментации (аналог NoDPI/GoodByeDPI).
Клиент отправляет первую часть TLS ClientHello, tlspr разбивает его на расширении SNI и отправляет двумя TCP-пакетами,
@ -649,6 +697,48 @@ proxy
</pre>
</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>
<p>
Начиная с версии 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.isudp = 1;
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
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);

View File

@ -25,6 +25,7 @@ void * dnsprchild(struct clientparam* param) {
SASIZETYPE size;
int res, i;
int len;
int semlocked = 1;
unsigned type=0;
uint32_t ttl;
unsigned char addr[16];
@ -38,10 +39,13 @@ void * dnsprchild(struct clientparam* param) {
RETURN (21);
}
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);
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
if((param->clisock=param->srv->so._socket(param->sostate, AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
RETURN(818);
@ -82,7 +86,19 @@ void * dnsprchild(struct clientparam* param) {
*s2 = (len - (int)(s2 - buf)) - 1;
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);
}
@ -191,6 +207,7 @@ void * dnsprchild(struct clientparam* param) {
CLEANRET:
if(semlocked) _3proxy_sem_unlock(udpinit);
if(param->res!=813){
sprintf((char *)buf, "%04x/%s/",
(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 error = 1;
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':
srv.transparent = 1;
break;

View File

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