Compare commits

...

6 Commits

Author SHA1 Message Date
github-actions[bot]
371d8396b4 Update version files for 0.9.9.1
Some checks failed
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Has been cancelled
Update version files / version (push) Has been cancelled
2026-10-10 16:57:17 +00:00
Vladimir Dubrovin
0f720bb44d Release as 0.9.9.1 2026-10-10 19:57:06 +03:00
Vladimir Dubrovin
3feb6df00d Fix: invalid hostname ACL handling in UDPASSOC 2026-10-10 19:53:58 +03:00
Vladimir Dubrovin
7e0ee5bace FIx: race condition on service reload 2026-10-10 19:02:09 +03:00
Vladimir Dubrovin
be619898c6 Fix missing device binding for few cases
(cherry picked from commit b4f5ffbf8c)
2026-10-10 17:42:48 +03:00
Derrick Lyndon Pallas
9d0dcaf63f Fix: wrong sasize in sockgetchar/sockrecvfrom
On receive, the struct sockaddr is zeroed and does not have an address
family until recvfrom fills it in.  SASIZE assumes that if there is no
address family, it is INET.  This means that for IPv6 UDP sockets, the
sockaddr is truncated and the reply is forwarded to the wrong address.
Instead, use sizeof(PROXYSOCKADDRTYPE).
2026-10-10 16:47:18 +03:00
15 changed files with 156 additions and 95 deletions

View File

@ -1,18 +1,14 @@
3proxy-0.9.9 Released August, 20 2026 3proxy-0.9.9.1 Released October, 10 2026
! Fix: DNS replies are validated now: a reply from an address other than the nameserver the query was sent to, and a reply with a question section not matching the query, are dropped; both were accepted before ! Fix: crash (segmentation fault) on configuration reload (SIGUSR1) on a busy server: a closing session could still use its service after the reload had freed it; the race existed since 0.9.7, the 5 second linger added in 0.9.9 made it much more likely (#1278)
! Fix: socket leak with SOCKSv5 UDP ASSOCIATE through a parent proxy, sockets were accumulated in CLOSE_WAIT state until descriptors ran out ! Fix: -Di and -De (bind to interface) were not applied to SOCKSv5 UDP ASSOCIATE and BIND sockets, the FTP proxy data connection and connect back (#1277)
! Fix: file descriptor leak in HTTP proxy on the ftp:// request path ! Fix: SOCKSv5 UDP ASSOCIATE over IPv6: the source address of a datagram was truncated and the reply was sent to the wrong address (#1279)
! Fix: crash with illegal instruction on some platforms (e.g. some musl based Linux builds), caused by a memcpy on overlapping buffers ! Fix: SOCKSv5 UDP ASSOCIATE: an access rule with host names matched any datagram sent to a literal address; the address is used as the host name now, as it is for TCP requests
! Fix: extip and ha (HAProxy PROXY protocol) parents are applied to SOCKSv5 UDP ASSOCIATE now ! Fix: buffer could be insufficient for the headers the HTTP proxy adds after a pcre_rewrite had grown the request
! Fix: only socks5 and socks5+ parents are tried for UDP ASSOCIATE, other parent types can not be used for UDP ! Fix: heap buffer overflow in pcre_rewrite: a $N reference to a group which did not match was written out as its digits, which the space allocated for the result did not count
! Fix: udppm through a SOCKSv5 parent did not work ! Fix: pcre_extend did nothing, the rules it appended were never consulted
! Fix: -Ne and -Ni options were never applied, the option letter was not parsed; -Ne is not applied to the UDP ASSOCIATE reply anymore, -Ni is applied to it ! Fix: certificates generated for TLS MitM (openssl) carried no subject and authority key identifiers and were refused by strict verifiers, including macOS clients, OpenSSL with x509_strict and Python 3.13
! Fix: -4 / -6 handling for UDP in socks; a single UDP association can use both IPv4 and IPv6 destinations now ! Fix: null pointer dereference in ftppr on PASS without USER and in smtpp on a user name without a host
! Fix: a datagram with a null destination address is dropped now ! Fix: no service started with wolfSSL on glibc: the default thread stack was too small for wolfSSL thread-local storage, pthread_create() failed and the failure was not reported
! Fix: DNS over TCP: a reply which did not fit a single read was never processed ! Fix: dnspr did not work on Windows, the socket it answers from could not be bound
! Documentation: "How to apply ACLs to UDP traffic" added to HOWTO; authentication cache, ACL and UDP notes added to "Optimizing 3proxy for High Load" and to security recommendations - Windows binaries are no longer signed with a self-signed Authenticode certificate, it gave no trust and triggered antivirus false positives
+ SOCKSv5 UDP: the destination of every datagram is authorized, so ACLs limiting the destination address, host name or port apply to UDP traffic now; the parent proxy and the external address are selected for the destination of the datagram and not for the UDP ASSOCIATE request
+ socks: -U option to control what happens when the destination changes within an UDP association: log it, authorize it, both (default) or neither
+ -C option (for TCP services) to terminate the session as soon as any of the sides closes the connection; by default the session is kept until both sides close it (TCP half-close)
+ timeouts: LINGER value added (11th, default 5), used to deliver buffered data after one of the sides has closed its sending side and as SO_LINGER value on outgoing connections

View File

@ -1,18 +1,14 @@
3proxy-0.9.9 Вышел 20 Августа 2026 3proxy-0.9.9.1 Вышел 10 Октября 2026
! Исправление: ответы DNS теперь проверяются: ответ с адреса, отличного от адреса сервера имён, которому был отправлен запрос, а также ответ с секцией вопроса, не совпадающей с запросом, отбрасываются; ранее оба принимались ! Исправление: падение (segmentation fault) при перезагрузке конфигурации (SIGUSR1) на нагруженном сервере: закрывающаяся сессия могла обращаться к службе после того, как перезагрузка её освободила; гонка существовала с 0.9.7, а добавленная в 0.9.9 задержка закрытия (linger) в 5 секунд сделала её гораздо вероятнее (#1278)
! Исправление: утечка сокетов при SOCKSv5 UDP ASSOCIATE через вышестоящий прокси, сокеты накапливались в состоянии CLOSE_WAIT до исчерпания дескрипторов ! Исправление: -Di и -De (привязка к интерфейсу) не применялись к сокетам SOCKSv5 UDP ASSOCIATE и BIND, к соединению данных FTP прокси и к обратному соединению (connect back) (#1277)
! Исправление: утечка файловых дескрипторов в HTTP-прокси на пути обработки запроса ftp:// ! Исправление: SOCKSv5 UDP ASSOCIATE по IPv6: адрес отправителя датаграммы обрезался, и ответ отправлялся не на тот адрес (#1279)
! Исправление: аварийное завершение с недопустимой инструкцией на некоторых платформах (например, в некоторых сборках Linux на основе musl) из-за memcpy на перекрывающихся буферах ! Исправление: SOCKSv5 UDP ASSOCIATE: правило доступа с именами хостов срабатывало для любой датаграммы, отправленной на адрес, а не на имя; теперь адрес используется как имя хоста, так же как для запросов TCP
! Исправление: родители типа extip и ha (HAProxy PROXY protocol) теперь применяются к SOCKSv5 UDP ASSOCIATE ! Исправление: буфера могло не хватить для заголовков, добавляемых HTTP прокси, после того как pcre_rewrite увеличил запрос
! Исправление: для UDP ASSOCIATE используются только родители socks5 и socks5+, остальные типы для UDP неприменимы ! Исправление: переполнение буфера в куче в pcre_rewrite: ссылка $N на группу, не участвовавшую в совпадении, выводилась своими цифрами, которые не учитывались при выделении памяти под результат
! Исправление: udppm через вышестоящий прокси SOCKSv5 не работал ! Исправление: pcre_extend ничего не делал, добавленные им правила никогда не проверялись
! Исправление: опции -Ne и -Ni никогда не применялись, буква опции не разбиралась; -Ne больше не применяется к ответу на UDP ASSOCIATE, -Ni применяется к нему ! Исправление: сертификаты, создаваемые для TLS MitM (openssl), не содержали идентификаторов ключа субъекта и издателя и отвергались строгой проверкой, в том числе клиентами macOS, OpenSSL с x509_strict и Python 3.13
! Исправление: обработка -4 / -6 для UDP в socks; одна UDP-ассоциация теперь может использовать адреса назначения и IPv4, и IPv6 ! Исправление: обращение по нулевому указателю в ftppr при PASS без USER и в smtpp при имени пользователя без хоста
! Исправление: датаграмма с нулевым адресом назначения теперь отбрасывается ! Исправление: с wolfSSL на glibc не запускалась ни одна служба: стека потока по умолчанию не хватало для thread-local памяти wolfSSL, pthread_create() завершался ошибкой, о которой не сообщалось
! Исправление: DNS поверх TCP: ответ, не помещавшийся в одно чтение, никогда не обрабатывался ! Исправление: dnspr не работал в Windows, сокет, с которого он отвечает, не удавалось привязать
! Документация: в HOWTO добавлен раздел "Как применять ACL к UDP-трафику"; в "Optimizing 3proxy for High Load" и в рекомендации по безопасности добавлены заметки о кэше аутентификации, ACL и UDP - Двоичные файлы для Windows больше не подписываются самоподписанным сертификатом Authenticode: доверия он не давал и вызывал ложные срабатывания антивирусов
+ SOCKSv5 UDP: адрес назначения каждой датаграммы авторизуется, поэтому ACL, ограничивающие адрес назначения, имя хоста или порт, теперь применяются к UDP-трафику; вышестоящий прокси и внешний адрес выбираются для адреса назначения датаграммы, а не для запроса UDP ASSOCIATE
+ socks: опция -U для управления тем, что происходит при смене адреса назначения в рамках UDP-ассоциации: журналировать, авторизовать, и то и другое (по умолчанию) или ничего
+ Опция -C (для TCP-сервисов) завершает сессию, как только любая из сторон закрывает соединение; по умолчанию сессия сохраняется, пока соединение не закроют обе стороны (полузакрытие TCP)
+ timeouts: добавлено значение LINGER (11-е, по умолчанию 5), используется для доставки буферизованных данных после того, как одна из сторон закрыла свою передающую сторону, а также как значение SO_LINGER для исходящих соединений

View File

@ -1 +1 @@
0.9.9.0 0.9.9.1

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
3proxy (0.9.9.1-1) buster; urgency=medium
*3proxy 0.9.9.1 initial build
-- z3APA3A <3apa3a@3proxy.org> Sat, 10 Oct 2026 16:57:17 +0000
3proxy (0.9.9.0-1) buster; urgency=medium 3proxy (0.9.9.0-1) buster; urgency=medium
*3proxy 0.9.9.0 initial build *3proxy 0.9.9.0 initial build

12
doc/changelog/0/9/9/1 Normal file
View File

@ -0,0 +1,12 @@
! Fix: crash (segmentation fault) on configuration reload (SIGUSR1) on a busy server: a closing session could still use its service after the reload had freed it; the race existed since 0.9.7, the 5 second linger added in 0.9.9 made it much more likely (#1278)
! Fix: -Di and -De (bind to interface) were not applied to SOCKSv5 UDP ASSOCIATE and BIND sockets, the FTP proxy data connection and connect back (#1277)
! Fix: SOCKSv5 UDP ASSOCIATE over IPv6: the source address of a datagram was truncated and the reply was sent to the wrong address (#1279)
! Fix: SOCKSv5 UDP ASSOCIATE: an access rule with host names matched any datagram sent to a literal address; the address is used as the host name now, as it is for TCP requests
! Fix: buffer could be insufficient for the headers the HTTP proxy adds after a pcre_rewrite had grown the request
! Fix: heap buffer overflow in pcre_rewrite: a $N reference to a group which did not match was written out as its digits, which the space allocated for the result did not count
! Fix: pcre_extend did nothing, the rules it appended were never consulted
! Fix: certificates generated for TLS MitM (openssl) carried no subject and authority key identifiers and were refused by strict verifiers, including macOS clients, OpenSSL with x509_strict and Python 3.13
! Fix: null pointer dereference in ftppr on PASS without USER and in smtpp on a user name without a host
! Fix: no service started with wolfSSL on glibc: the default thread stack was too small for wolfSSL thread-local storage, pthread_create() failed and the failure was not reported
! Fix: dnspr did not work on Windows, the socket it answers from could not be bound
- Windows binaries are no longer signed with a self-signed Authenticode certificate, it gave no trust and triggered antivirus false positives

View File

@ -1,5 +1,5 @@
Name: 3proxy Name: 3proxy
Version: 0.9.9.0 Version: 0.9.9.1
Release: 1%{?dist} Release: 1%{?dist}
Summary: 3proxy tiny proxy server Summary: 3proxy tiny proxy server
License: GPL/LGPL/Apache/BSD License: GPL/LGPL/Apache/BSD

View File

@ -677,6 +677,49 @@ int connectwithpoll(struct clientparam *param, SOCKET sock, struct sockaddr *sa,
} }
/* -Di / -De: ties a socket to the interface asked for, for TCP and UDP alike.
Where the option is set per protocol, family is the one of the address the
socket will be bound to. */
int bindtodevice(struct sockfuncs *sf, void *state, SOCKET sock, const char *device, int family){
if(!device) return 0;
#if defined SO_BINDTODEVICE
if(sf->_setsockopt(state, sock, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1))
return 1;
#elif defined IP_BOUND_IF
{
int idx;
idx = if_nametoindex(device);
if(!idx || (family == AF_INET && sf->_setsockopt(state, sock, IPPROTO_IP, IP_BOUND_IF, &idx, sizeof(idx))))
return 1;
#ifndef NOIPV6
#ifndef IPV6_BOUND_IF
#define IPV6_BOUND_IF 125
#endif
if(family == AF_INET6 && sf->_setsockopt(state, sock, IPPROTO_IPV6, IPV6_BOUND_IF, &idx, sizeof(idx))) return 1;
#endif
}
#endif
return 0;
}
/* the external side, a socket to be bound to sinsl */
int extbindtodevice(struct clientparam *param, SOCKET sock){
#if defined SO_BINDTODEVICE || defined IP_BOUND_IF
return bindtodevice(&param->srv->so, param->sostate, sock, param->srv->obindtodevice, *SAFAMILY(&param->sinsl));
#else
return 0;
#endif
}
/* the internal side, a socket to be bound to sincl */
int intbindtodevice(struct clientparam *param, SOCKET sock){
#if defined SO_BINDTODEVICE || defined IP_BOUND_IF
return bindtodevice(&param->srv->so, param->sostate, sock, param->srv->ibindtodevice, *SAFAMILY(&param->sincl));
#else
return 0;
#endif
}
int doconnect(struct clientparam * param){ int doconnect(struct clientparam * param){
SASIZETYPE size; SASIZETYPE size;
@ -724,25 +767,7 @@ int doconnect(struct clientparam * param){
setopts(param->remsock, param->srv->srvsockopts); setopts(param->remsock, param->srv->srvsockopts);
param->srv->so._setsockopt(param->sostate, param->remsock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg)); param->srv->so._setsockopt(param->sostate, param->remsock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg));
#if defined SO_BINDTODEVICE if(extbindtodevice(param, param->remsock)) return 12;
if(param->srv->obindtodevice) {
if(param->srv->so._setsockopt(param->sostate, param->remsock, SOL_SOCKET, SO_BINDTODEVICE, param->srv->obindtodevice, strlen(param->srv->obindtodevice) + 1))
return 12;
}
#elif defined IP_BOUND_IF
if(param->srv->obindtodevice) {
int idx;
idx = if_nametoindex(param->srv->obindtodevice);
if(!idx || (*SAFAMILY(&param->sinsl) == AF_INET && param->srv->so._setsockopt(param->sostate, param->remsock, IPPROTO_IP, IP_BOUND_IF, &idx, sizeof(idx))))
return 12;
#ifndef NOIPV6
#ifndef IPV6_BOUND_IF
#define IPV6_BOUND_IF 125
#endif
if(*SAFAMILY(&param->sinsl) == AF_INET6 && param->srv->so._setsockopt(param->sostate, param->remsock, IPPROTO_IPV6, IPV6_BOUND_IF, &idx, sizeof(idx))) return 12;
#endif
}
#endif
#ifdef WITH_UN #ifdef WITH_UN
if(*SAFAMILY(&param->sinsl) != AF_UNIX) if(*SAFAMILY(&param->sinsl) != AF_UNIX)
#endif #endif

View File

@ -127,6 +127,7 @@ void * ftpprchild(struct clientparam* param) {
clidatasock = INVALID_SOCKET; clidatasock = INVALID_SOCKET;
} }
if ((clidatasock=socket(SASOCK(&param->sincl), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN(821);} if ((clidatasock=socket(SASOCK(&param->sincl), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN(821);}
if(intbindtodevice(param, clidatasock)){RETURN(822);}
*SAPORT(&param->sincl) = 0; *SAPORT(&param->sincl) = 0;
if(param->srv->so._bind(param->sostate, clidatasock, (struct sockaddr *)&param->sincl, SASIZE(&param->sincl))){RETURN(822);} if(param->srv->so._bind(param->sostate, clidatasock, (struct sockaddr *)&param->sincl, SASIZE(&param->sincl))){RETURN(822);}
if (pasv) { if (pasv) {

View File

@ -369,6 +369,9 @@ unsigned char * dologname (unsigned char *buf, unsigned char *name, const unsign
int readconfig(FILE * fp); int readconfig(FILE * fp);
void initcommands(void); 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);
int bindtodevice(struct sockfuncs *sf, void *state, SOCKET sock, const char *device, int family);
int extbindtodevice(struct clientparam *param, SOCKET sock);
int intbindtodevice(struct clientparam *param, SOCKET sock);
uint32_t myrand(void); uint32_t myrand(void);

View File

@ -844,29 +844,11 @@ int MODULEMAINFUNC (int argc, char** argv){
srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEPORT, (char *)&opt, sizeof(int)); srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEPORT, (char *)&opt, sizeof(int));
#endif #endif
} }
#if defined SO_BINDTODEVICE #if defined SO_BINDTODEVICE || defined IP_BOUND_IF
if(srv.ibindtodevice && srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_BINDTODEVICE, srv.ibindtodevice, strlen(srv.ibindtodevice) + 1)) { if(bindtodevice(&srv.so, srv.so.state, sock, srv.ibindtodevice, *SAFAMILY(&srv.intsa))) {
dolog(&defparam, (unsigned char *)"failed to bind device"); dolog(&defparam, (unsigned char *)"failed to bind device");
return -12; return -12;
} }
#elif defined IP_BOUND_IF
if(srv.ibindtodevice){
int idx;
idx = if_nametoindex(srv.ibindtodevice);
if(!idx || (*SAFAMILY(&srv.intsa) == AF_INET && setsockopt(sock, IPPROTO_IP, IP_BOUND_IF, &idx, sizeof(idx)))) {
dolog(&defparam, (unsigned char *)"failed to bind device");
return -12;
}
#ifndef NOIPV6
#ifndef IPV6_BOUND_IF
#define IPV6_BOUND_IF 125
#endif
if((*SAFAMILY(&srv.intsa) == AF_INET6 && srv.so._setsockopt(srv.so.state, sock, IPPROTO_IPV6, IPV6_BOUND_IF, &idx, sizeof(idx)))) {
dolog(&defparam, (unsigned char *)"failed to bind device");
return -12;
}
#endif
}
#endif #endif
} }
#ifdef WITH_UN #ifdef WITH_UN
@ -1020,6 +1002,15 @@ int MODULEMAINFUNC (int argc, char** argv){
setopts(new_sock, srv.cbcsockopts); setopts(new_sock, srv.cbcsockopts);
parsehost(srv.family, cbc_string, (struct sockaddr *)&defparam.sincr); parsehost(srv.family, cbc_string, (struct sockaddr *)&defparam.sincr);
#if defined SO_BINDTODEVICE || defined IP_BOUND_IF
/* as for a listening socket, an interface that cannot be
bound to is not worth retrying */
if(bindtodevice(&so, so.state, new_sock, srv.ibindtodevice, *SAFAMILY(&defparam.sincr))) {
dolog(&defparam, (unsigned char *)"failed to bind device");
so._closesocket(so.state, new_sock);
break;
}
#endif
if(connectwithpoll(NULL, new_sock,(struct sockaddr *)&defparam.sincr,SASIZE(&defparam.sincr),CONNBACK_TO)) { if(connectwithpoll(NULL, new_sock,(struct sockaddr *)&defparam.sincr,SASIZE(&defparam.sincr),CONNBACK_TO)) {
so._closesocket(so.state, new_sock); so._closesocket(so.state, new_sock);
new_sock = INVALID_SOCKET; new_sock = INVALID_SOCKET;
@ -1330,7 +1321,16 @@ void srvfree(struct srvparam * srv){
if(srv->cbsock != INVALID_SOCKET) so._closesocket(srv->so.state, srv->cbsock); if(srv->cbsock != INVALID_SOCKET) so._closesocket(srv->so.state, srv->cbsock);
srv->cbsock = INVALID_SOCKET; srv->cbsock = INVALID_SOCKET;
srv->service = S_ZOMBIE; srv->service = S_ZOMBIE;
while(srv->child) usleep(SLEEPTIME * 100); /* under the mutex, so the last child has let go of it before it is destroyed */
for(;;){
struct clientparam *child;
_3proxy_mutex_lock(&srv->counter_mutex);
child = srv->child;
_3proxy_mutex_unlock(&srv->counter_mutex);
if(!child) break;
usleep(SLEEPTIME * 100);
}
#ifndef STDMAIN #ifndef STDMAIN
if(srv->filter){ if(srv->filter){
while(srv->nfilters){ while(srv->nfilters){
@ -1372,22 +1372,13 @@ void srvfree(struct srvparam * srv){
void freeparam(struct clientparam * param) { void freeparam(struct clientparam * param) {
if(param->srv){ if(param->srv){
if(param->srv->so.freefunc) param->srv->so.freefunc(param->sostate); if(param->srv->so.freefunc) param->srv->so.freefunc(param->sostate);
_3proxy_mutex_lock(&param->srv->counter_mutex);
#ifndef STDMAIN #ifndef STDMAIN
if(param->srv->service == S_UDPPM) hashdelete(&udp_table, param); if(param->srv->service == S_UDPPM){
#endif _3proxy_mutex_lock(&param->srv->counter_mutex);
if(param->prev || param->next || param->srv->child == param){ hashdelete(&udp_table, param);
if(param->prev){ _3proxy_mutex_unlock(&param->srv->counter_mutex);
param->prev->next = param->next;
}
else
param->srv->child = param->next;
if(param->next){
param->next->prev = param->prev;
}
(param->srv->childcount)--;
} }
_3proxy_mutex_unlock(&param->srv->counter_mutex); #endif
} }
if(param->clibuf) free(param->clibuf); if(param->clibuf) free(param->clibuf);
if(param->srvbuf) free(param->srvbuf); if(param->srvbuf) free(param->srvbuf);
@ -1427,6 +1418,24 @@ void freeparam(struct clientparam * param) {
} }
if(param->connlim) stopconnlims(param); if(param->connlim) stopconnlims(param);
#endif #endif
/* Leaving the service comes last. Once its last child is gone, srvfree()
frees the service along with its socket functions, filters and mutex,
and a close above may have lingered for seconds before getting here. */
if(param->srv){
_3proxy_mutex_lock(&param->srv->counter_mutex);
if(param->prev || param->next || param->srv->child == param){
if(param->prev){
param->prev->next = param->next;
}
else
param->srv->child = param->next;
if(param->next){
param->next->prev = param->prev;
}
(param->srv->childcount)--;
}
_3proxy_mutex_unlock(&param->srv->counter_mutex);
}
if(param->hostname) free(param->hostname); if(param->hostname) free(param->hostname);
if(param->username) free(param->username); if(param->username) free(param->username);
if(param->password) free(param->password); if(param->password) free(param->password);

View File

@ -63,7 +63,7 @@ int sockrecvfrom(struct clientparam *param, SOCKET sock, struct sockaddr * sin,
if(conf.timetoexit) return EOF; if(conf.timetoexit) return EOF;
res = param?param->srv->so._poll(param->sostate, &fds, 1, to):so._poll(so.state, &fds, 1, to); res = param?param->srv->so._poll(param->sostate, &fds, 1, to):so._poll(so.state, &fds, 1, to);
if (res<1) return 0; if (res<1) return 0;
sasize = SASIZE(sin); sasize = sizeof(PROXYSOCKADDRTYPE);
do { do {
res = param?param->srv->so._recvfrom(param->sostate, sock, (char *)buf, bufsize, 0, (struct sockaddr *)sin, &sasize):so._recvfrom(so.state, sock, (char *)buf, bufsize, 0, (struct sockaddr *)sin, &sasize); res = param?param->srv->so._recvfrom(param->sostate, sock, (char *)buf, bufsize, 0, (struct sockaddr *)sin, &sasize):so._recvfrom(so.state, sock, (char *)buf, bufsize, 0, (struct sockaddr *)sin, &sasize);
} while (res < 0 && (errno == EAGAIN || errno == EINTR)); } while (res < 0 && (errno == EAGAIN || errno == EINTR));

View File

@ -185,6 +185,7 @@ void * sockschild(struct clientparam* param) {
if(command == 2){ if(command == 2){
if ((param->remsock=param->srv->so._socket(param->sostate, SASOCK(&param->req), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN (11);} if ((param->remsock=param->srv->so._socket(param->sostate, SASOCK(&param->req), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN (11);}
setopts(param->remsock, param->srv->lissockopts); setopts(param->remsock, param->srv->lissockopts);
if(extbindtodevice(param, param->remsock)) {RETURN (12);}
} }
break; break;
@ -241,6 +242,7 @@ fflush(stderr);
#else #else
fcntl(param->clisock, F_SETFL, O_NONBLOCK | fcntl(param->clisock, F_GETFL)); fcntl(param->clisock, F_SETFL, O_NONBLOCK | fcntl(param->clisock, F_GETFL));
#endif #endif
if(intbindtodevice(param, param->clisock)) {RETURN (12);}
sin = param->sincl; sin = param->sincl;
*SAPORT(&sin) = 0; *SAPORT(&sin) = 0;
if(param->srv->so._bind(param->sostate, param->clisock,(struct sockaddr *)&sin,SASIZE(&sin))) {RETURN (12);} if(param->srv->so._bind(param->sostate, param->clisock,(struct sockaddr *)&sin,SASIZE(&sin))) {RETURN (12);}

View File

@ -121,6 +121,11 @@ int udpbind(struct clientparam *param)
fcntl(s, F_SETFL, O_NONBLOCK | fcntl(s, F_GETFL)); fcntl(s, F_SETFL, O_NONBLOCK | fcntl(s, F_GETFL));
#endif #endif
param->remsock = s; param->remsock = s;
if (extbindtodevice(param, param->remsock)) {
param->srv->so._closesocket(param->sostate, param->remsock);
param->remsock = INVALID_SOCKET;
return 12;
}
if (param->srv->so._bind(param->sostate, param->remsock, if (param->srv->so._bind(param->sostate, param->remsock,
(struct sockaddr *)&param->sinsl, SASIZE(&param->sinsl))) { (struct sockaddr *)&param->sinsl, SASIZE(&param->sinsl))) {
*SAPORT(&param->sinsl) = 0; *SAPORT(&param->sinsl) = 0;
@ -284,6 +289,12 @@ int udpsockmap(struct clientparam *param, int timeo)
} }
default: return 997; default: return 997;
} }
/* As for TCP requests, a literal address is the host name,
otherwise an ACL with host names only matches any address */
if (!dstname) {
myinet_ntop(*SAFAMILY(&dst), SAADDR(&dst), dstnamebuf, sizeof(dstnamebuf));
dstname = dstnamebuf;
}
memcpy(SAPORT(&dst), base + i, 2); memcpy(SAPORT(&dst), base + i, 2);
i += 2; i += 2;

View File

@ -1,14 +1,14 @@
#ifndef VERSION #ifndef VERSION
#define VERSION "3proxy-0.9.9.0" #define VERSION "3proxy-0.9.9.1"
#endif #endif
#ifndef BUILDDATE #ifndef BUILDDATE
#define BUILDDATE "" #define BUILDDATE "261010165717"
#endif #endif
#define MAJOR3PROXY 0 #define MAJOR3PROXY 0
#define SUBMAJOR3PROXY 9 #define SUBMAJOR3PROXY 9
#define MINOR3PROXY 9 #define MINOR3PROXY 9
#define SUBMINOR3PROXY 0 #define SUBMINOR3PROXY 1
#define RELEASE3PROXY "3proxy-0.9.9.0(" BUILDDATE ")\0" #define RELEASE3PROXY "3proxy-0.9.9.1(" BUILDDATE ")\0"
#ifndef YEAR3PROXY #ifndef YEAR3PROXY
#define YEAR3PROXY "2026" #define YEAR3PROXY "2026"
#endif #endif