mirror of
https://github.com/3proxy/3proxy.git
synced 2026-10-28 22:05:48 +08:00
Unix sockets: no addresses on streams, abstract names, tcppm port 0
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
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
On Linux a proxy listening on a Unix socket relayed only the first bytes of an answer: sockmap() read with recvfrom() into the client's address, which for a Unix stream socket Linux fills with an empty AF_UNIX one, and then sent with sendto() to that address, which a connected Unix stream socket refuses. A TCP connection has no use for addresses: sockmap() now sends and receives with NULL ones, and connect-back sends its command with socksend() and reads the answer with sockrecvfrom() without an address, which a NULL sin now allows. An abstract socket name (-iunix:@NAME) was bound with the whole size of struct sockaddr_un, padded with zeros, so a client naming it by its bytes, as most do, reached another name. SASIZE() now gives an abstract address its exact size; getsockname() calls that took SASIZE() of the old contents as the buffer size take the buffer's size instead. tcppm refused port 0 for a unix: target, though the manual gives "tcppm 8080 unix:/var/run/app.sock 0" as the example: the port of a Unix socket target is ignored, so 0 is allowed. On a reload the new service bound the path anew and the old one, closing after it, removed the file, the new service's by then, leaving nothing to connect to. A service now notes the file it bound (device and inode) and removes the path on closing only if it is still that file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
20302a67ff
commit
ae4011604f
@ -7,6 +7,31 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "proxy.h"
|
#include "proxy.h"
|
||||||
|
|
||||||
|
#ifdef WITH_UN
|
||||||
|
/* A service bound to a Unix socket path notes its file, as a service of a
|
||||||
|
newer configuration may bind the same path before this one closes: the
|
||||||
|
file is then the other's, which closing must not remove. */
|
||||||
|
static void unbound(struct srvparam *srv){
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if(*SAFAMILY(&srv->intsa) == AF_UNIX && *SAADDR(&srv->intsa) &&
|
||||||
|
!stat((char *)SAADDR(&srv->intsa), &st)){
|
||||||
|
srv->undev = (uint64_t)st.st_dev;
|
||||||
|
srv->unino = (uint64_t)st.st_ino;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ununlink(struct srvparam *srv){
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if(*SAFAMILY(&srv->intsa) == AF_UNIX && *SAADDR(&srv->intsa) &&
|
||||||
|
!stat((char *)SAADDR(&srv->intsa), &st) &&
|
||||||
|
(uint64_t)st.st_dev == srv->undev && (uint64_t)st.st_ino == srv->unino)
|
||||||
|
unlink((char *)SAADDR(&srv->intsa));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#endif
|
#endif
|
||||||
@ -84,7 +109,7 @@ void * threadfunc (void *p) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if(socksendto(param, param->remsock, (struct sockaddr*)¶m->sinsr, (unsigned char *)"C", 1, CONNBACK_TO*1000) != 1){
|
if(socksend(param, param->remsock, (unsigned char *)"C", 1, CONNBACK_TO) != 1){
|
||||||
dolog(param, (unsigned char *)"Connect back sending command failed");
|
dolog(param, (unsigned char *)"Connect back sending command failed");
|
||||||
param->srv->so._closesocket(param->sostate, param->remsock);
|
param->srv->so._closesocket(param->sostate, param->remsock);
|
||||||
param->remsock = INVALID_SOCKET;
|
param->remsock = INVALID_SOCKET;
|
||||||
@ -687,7 +712,12 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
else {
|
else {
|
||||||
#endif
|
#endif
|
||||||
#ifndef NOPORTMAP
|
#ifndef NOPORTMAP
|
||||||
if (error || argc != i+3 || *argv[i]=='-'|| (*SAPORT(&srv.intsa) = htons((uint16_t)atoi(argv[i])))==0 || (srv.targetport = htons((uint16_t)atoi(argv[i+2])))==0) {
|
/* the port of a Unix socket target is ignored, 0 as the manual has it */
|
||||||
|
if (error || argc != i+3 || *argv[i]=='-'|| (*SAPORT(&srv.intsa) = htons((uint16_t)atoi(argv[i])))==0 || ((srv.targetport = htons((uint16_t)atoi(argv[i+2])))==0
|
||||||
|
#ifdef WITH_UN
|
||||||
|
&& strncmp(argv[i+1], "unix:", 5)
|
||||||
|
#endif
|
||||||
|
)) {
|
||||||
#ifndef STDMAIN
|
#ifndef STDMAIN
|
||||||
haveerror = 1;
|
haveerror = 1;
|
||||||
#endif
|
#endif
|
||||||
@ -870,6 +900,9 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef WITH_UN
|
||||||
|
unbound(&srv);
|
||||||
|
#endif
|
||||||
if(!isudp){
|
if(!isudp){
|
||||||
if(srv.so._listen (srv.so.state, sock, srv.backlog?srv.backlog : 1+(srv.maxchild>>3))==-1) {
|
if(srv.so._listen (srv.so.state, sock, srv.backlog?srv.backlog : 1+(srv.maxchild>>3))==-1) {
|
||||||
sprintf((char *)buf, "listen(): %s", strerror(errno));
|
sprintf((char *)buf, "listen(): %s", strerror(errno));
|
||||||
@ -1020,7 +1053,7 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sockrecvfrom(NULL, new_sock,(struct sockaddr*)&defparam.sincr,buf,1,60*1000) != 1 || *buf!='C') {
|
if(sockrecvfrom(NULL, new_sock, NULL, buf, 1, 60*1000) != 1 || *buf!='C') {
|
||||||
so._closesocket(so.state, new_sock);
|
so._closesocket(so.state, new_sock);
|
||||||
new_sock = INVALID_SOCKET;
|
new_sock = INVALID_SOCKET;
|
||||||
usleep(SLEEPTIME);
|
usleep(SLEEPTIME);
|
||||||
@ -1320,7 +1353,7 @@ void srvfree(struct srvparam * srv){
|
|||||||
if(srv->srvsock != INVALID_SOCKET) {
|
if(srv->srvsock != INVALID_SOCKET) {
|
||||||
so._closesocket(srv->so.state, srv->srvsock);
|
so._closesocket(srv->so.state, srv->srvsock);
|
||||||
#ifdef WITH_UN
|
#ifdef WITH_UN
|
||||||
if(*SAFAMILY(&srv->intsa) == AF_UNIX && *SAADDR(&srv->intsa))unlink((char *)SAADDR(&srv->intsa));
|
ununlink(srv);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
srv->srvsock = INVALID_SOCKET;
|
srv->srvsock = INVALID_SOCKET;
|
||||||
|
|||||||
@ -64,8 +64,9 @@ int sockrecvfrom(struct clientparam *param, SOCKET sock, struct sockaddr * sin,
|
|||||||
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 = sizeof(PROXYSOCKADDRTYPE);
|
sasize = sizeof(PROXYSOCKADDRTYPE);
|
||||||
|
/* sin NULL for a stream socket: nothing to learn the address into */
|
||||||
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, sin? &sasize : NULL):so._recvfrom(so.state, sock, (char *)buf, bufsize, 0, (struct sockaddr *)sin, sin? &sasize : NULL);
|
||||||
} while (res < 0 && (errno == EAGAIN || errno == EINTR));
|
} while (res < 0 && (errno == EAGAIN || errno == EINTR));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -92,7 +92,6 @@ int sockmap(struct clientparam * param, int timeo, int usesplice){
|
|||||||
int sleeptime = 0;
|
int sleeptime = 0;
|
||||||
FILTER_ACTION action;
|
FILTER_ACTION action;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
SASIZETYPE sasize;
|
|
||||||
int needaction = 0;
|
int needaction = 0;
|
||||||
int graceclinum=0, gracesrvnum=0, graceclitraf=0, gracesrvtraf=0;
|
int graceclinum=0, gracesrvnum=0, graceclitraf=0, gracesrvtraf=0;
|
||||||
time_t gracetime = 0;
|
time_t gracetime = 0;
|
||||||
@ -246,8 +245,7 @@ log("send to server from buf");
|
|||||||
param->clioffset = param->cliinbuf = 0;
|
param->clioffset = param->cliinbuf = 0;
|
||||||
if(fromclient) TOCLIENTBUF = 1;
|
if(fromclient) TOCLIENTBUF = 1;
|
||||||
}
|
}
|
||||||
sasize = SASIZE(¶m->sinsr);
|
res = param->srv->so._sendto(param->sostate, param->remsock, (char *)param->clibuf + param->clioffset, (int)MIN(inclientbuf, fromclient), 0, NULL, 0);
|
||||||
res = param->srv->so._sendto(param->sostate, param->remsock, (char *)param->clibuf + param->clioffset, (int)MIN(inclientbuf, fromclient), 0, (struct sockaddr*)¶m->sinsr, sasize);
|
|
||||||
if(res <= 0) {
|
if(res <= 0) {
|
||||||
TOSERVER = 0;
|
TOSERVER = 0;
|
||||||
if(errno && errno != EAGAIN && errno != EINTR){
|
if(errno && errno != EAGAIN && errno != EINTR){
|
||||||
@ -293,8 +291,7 @@ log("send to client from buf");
|
|||||||
if(fromserver) TOSERVERBUF = 1;
|
if(fromserver) TOSERVERBUF = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
sasize = SASIZE(¶m->sincr);
|
res = param->srv->so._sendto(param->sostate, param->clisock, (char *)param->srvbuf + param->srvoffset, (int)MIN(inserverbuf,fromserver), 0, NULL, 0);
|
||||||
res = param->srv->so._sendto(param->sostate, param->clisock, (char *)param->srvbuf + param->srvoffset, (int)MIN(inserverbuf,fromserver), 0, (struct sockaddr*)¶m->sincr, sasize);
|
|
||||||
if(res <= 0) {
|
if(res <= 0) {
|
||||||
TOCLIENT = 0;
|
TOCLIENT = 0;
|
||||||
if(errno && errno != EAGAIN && errno != EINTR){
|
if(errno && errno != EAGAIN && errno != EINTR){
|
||||||
@ -485,8 +482,7 @@ log("done read from server to pipe\n");
|
|||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
log("read from client to buf");
|
log("read from client to buf");
|
||||||
#endif
|
#endif
|
||||||
sasize = sizeof(param->sincr);
|
res = param->srv->so._recvfrom(param->sostate, param->clisock, (char *)param->clibuf + param->cliinbuf, (int)MIN((uint64_t)param->clibufsize - param->cliinbuf, fromclient-inclientbuf), 0, NULL, NULL);
|
||||||
res = param->srv->so._recvfrom(param->sostate, param->clisock, (char *)param->clibuf + param->cliinbuf, (int)MIN((uint64_t)param->clibufsize - param->cliinbuf, fromclient-inclientbuf), 0, (struct sockaddr *)¶m->sincr, &sasize);
|
|
||||||
if(res <= 0) {
|
if(res <= 0) {
|
||||||
FROMCLIENT = 0;
|
FROMCLIENT = 0;
|
||||||
if(res == 0) {
|
if(res == 0) {
|
||||||
@ -518,8 +514,7 @@ log("done read from client to buf");
|
|||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
log("read from server to buf");
|
log("read from server to buf");
|
||||||
#endif
|
#endif
|
||||||
sasize = sizeof(param->sinsr);
|
res = param->srv->so._recvfrom(param->sostate, param->remsock, (char *)param->srvbuf + param->srvinbuf, (int)MIN((uint64_t)param->srvbufsize - param->srvinbuf, fromserver-inserverbuf), 0, NULL, NULL);
|
||||||
res = param->srv->so._recvfrom(param->sostate, param->remsock, (char *)param->srvbuf + param->srvinbuf, (int)MIN((uint64_t)param->srvbufsize - param->srvinbuf, fromserver-inserverbuf), 0, (struct sockaddr *)¶m->sinsr, &sasize);
|
|
||||||
if(res <= 0) {
|
if(res <= 0) {
|
||||||
FROMSERVER = 0;
|
FROMSERVER = 0;
|
||||||
if(res == 0) {
|
if(res == 0) {
|
||||||
|
|||||||
@ -227,7 +227,7 @@ fprintf(stderr, "%hu bound to communicate with server\n", *SAPORT(¶m->sinsl)
|
|||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
sasize = SASIZE(¶m->sinsl);
|
sasize = sizeof(param->sinsl);
|
||||||
param->srv->so._getsockname(param->sostate, param->remsock, (struct sockaddr *)¶m->sinsl, &sasize);
|
param->srv->so._getsockname(param->sostate, param->remsock, (struct sockaddr *)¶m->sinsl, &sasize);
|
||||||
}
|
}
|
||||||
if(command == 3) {
|
if(command == 3) {
|
||||||
@ -246,7 +246,7 @@ fflush(stderr);
|
|||||||
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);}
|
||||||
sasize = SASIZE(&sin);
|
sasize = sizeof(sin);
|
||||||
param->srv->so._getsockname(param->sostate, param->clisock, (struct sockaddr *)&sin, &sasize);
|
param->srv->so._getsockname(param->sostate, param->clisock, (struct sockaddr *)&sin, &sasize);
|
||||||
#if SOCKSTRACE > 0
|
#if SOCKSTRACE > 0
|
||||||
fprintf(stderr, "%hu binded to communicate with client\n",
|
fprintf(stderr, "%hu binded to communicate with client\n",
|
||||||
|
|||||||
@ -105,6 +105,7 @@ int
|
|||||||
|
|
||||||
#ifdef WITH_UN
|
#ifdef WITH_UN
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
#include <stddef.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ALLOW 0
|
#define ALLOW 0
|
||||||
@ -152,7 +153,9 @@ int
|
|||||||
#define UN_SAADDR(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? (unsigned char *)((struct sockaddr_un *)sa)->sun_path :
|
#define UN_SAADDR(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? (unsigned char *)((struct sockaddr_un *)sa)->sun_path :
|
||||||
#define UN_SAADDRLEN(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? (int)sizeof(((struct sockaddr_un *)sa)->sun_path) :
|
#define UN_SAADDRLEN(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? (int)sizeof(((struct sockaddr_un *)sa)->sun_path) :
|
||||||
#define UN_SASOCK(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? PF_UNIX :
|
#define UN_SASOCK(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? PF_UNIX :
|
||||||
#define UN_SASIZE(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? sizeof(struct sockaddr_un) :
|
/* an abstract name (Linux) is its bytes after the leading 0, no more:
|
||||||
|
padded with zeros it would be another name */
|
||||||
|
#define UN_SASIZE(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? (((struct sockaddr_un *)sa)->sun_path[0] || !((struct sockaddr_un *)sa)->sun_path[1]? sizeof(struct sockaddr_un) : offsetof(struct sockaddr_un, sun_path) + 1 + strlen(((struct sockaddr_un *)sa)->sun_path + 1)) :
|
||||||
#define UN_SAISNULL(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? (((struct sockaddr_un *)sa)->sun_path[0] == 0 && ((struct sockaddr_un *)sa)->sun_path[1] == 0) :
|
#define UN_SAISNULL(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? (((struct sockaddr_un *)sa)->sun_path[0] == 0 && ((struct sockaddr_un *)sa)->sun_path[1] == 0) :
|
||||||
#else
|
#else
|
||||||
#define UN_SAPORT(sa)
|
#define UN_SAPORT(sa)
|
||||||
@ -527,6 +530,8 @@ struct srvparam {
|
|||||||
AUTHFUNC authfunc;
|
AUTHFUNC authfunc;
|
||||||
PROXYFUNC pf;
|
PROXYFUNC pf;
|
||||||
SOCKET srvsock, cbsock;
|
SOCKET srvsock, cbsock;
|
||||||
|
/* the file of a Unix socket bound to a path, to remove only it */
|
||||||
|
uint64_t undev, unino;
|
||||||
int childcount;
|
int childcount;
|
||||||
int maxchild;
|
int maxchild;
|
||||||
int backlog;
|
int backlog;
|
||||||
|
|||||||
@ -136,7 +136,7 @@ int udpbind(struct clientparam *param)
|
|||||||
return 12;
|
return 12;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sasize = SASIZE(¶m->sinsl);
|
sasize = sizeof(param->sinsl);
|
||||||
param->srv->so._getsockname(param->sostate, param->remsock,
|
param->srv->so._getsockname(param->sostate, param->remsock,
|
||||||
(struct sockaddr *)¶m->sinsl, &sasize);
|
(struct sockaddr *)¶m->sinsl, &sasize);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user