Support unix socket for parent and tcppm; abstract (fileless) unix sockets for linux support
Some checks are pending
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Waiting to run

Use unix:/path/to/socket, e.g.

tcppm 1234 unix:/path/to/socket 1234

Under linux abstract sockets are supported with '@' prefix, e.g.

parent 1000 http unix:@virtual.3proxy.socket 1111

Destination port numbers are not used in tcppm/parent, but you must specify any positive value to match the syntaxis.
This commit is contained in:
Vladimir Dubrovin 2026-04-12 19:18:15 +03:00
parent 3f92dc7355
commit 878a432481
6 changed files with 77 additions and 27 deletions

View File

@ -62,17 +62,34 @@ int mutex_unlock(int *val)
} }
#endif #endif
#ifdef WITH_UN
void make_un(const unsigned char *path, struct sockaddr_un * sun){
memset(sun, 0, sizeof(*sun));
sun->sun_family = AF_UNIX;
strncpy(sun->sun_path, (char *)path, sizeof(sun->sun_path) - 1);
if(*path == '@')*sun->sun_path = 0;
}
#endif
int myinet_ntop(int af, void *src, char *dst, socklen_t size){ int myinet_ntop(int af, void *src, char *dst, socklen_t size){
#ifdef WITH_UN #ifdef WITH_UN
if(af == AF_UNIX){ if(af == AF_UNIX){
struct sockaddr_un *sun = (struct sockaddr_un *)src; struct sockaddr_un *sun = (struct sockaddr_un *)src;
int ephemeral = 0;
char *path = sun->sun_path; char *path = sun->sun_path;
char *basename = strrchr(path, '/'); char *basename;
if(!path[0] && path[1]){
ephemeral = 1;
*dst++ = '@';
path++;
}
basename = strrchr(path, '/');
if(basename) basename++; if(basename) basename++;
else basename = path; else basename = path;
if(size > 0){ if(size > 0){
strncpy(dst, basename, (size > 40) ? 40 : size - 1); strncpy(dst, basename, (size > 40) ? 40 : size - (ephemeral + 1));
dst[((size > 40) ? 40 : size - 1)] = 0; dst[((size > 40) ? 40 : size - (ephemeral + 1))] = 0;
} }
return (int)strlen(dst); return (int)strlen(dst);
} }
@ -538,14 +555,14 @@ int connectwithpoll(struct clientparam *param, SOCKET sock, struct sockaddr *sa,
fcntl(sock,F_SETFL, O_NONBLOCK | fcntl(sock,F_GETFL)); fcntl(sock,F_SETFL, O_NONBLOCK | fcntl(sock,F_GETFL));
#endif #endif
if(param?param->srv->so._connect(param->sostate, sock,sa,size) : so._connect(so.state, sock,sa,size)) { if(param?param->srv->so._connect(param->sostate, sock,sa,size) : so._connect(so.state, sock,sa,size)) {
if(errno != EAGAIN && errno != EINPROGRESS) return (13); if(errno != EAGAIN && errno != EINPROGRESS) return 13;
} }
if(!errno) return 0; if(!errno) return 0;
memset(fds, 0, sizeof(fds)); memset(fds, 0, sizeof(fds));
fds[0].fd = sock; fds[0].fd = sock;
fds[0].events = POLLOUT; fds[0].events = POLLOUT;
if((param?param->srv->so._poll(param->sostate, fds, 1, to*1000):so._poll(so.state, fds, 1, to*1000)) <= 0 || !(fds[0].revents & POLLOUT) || (fds[0].revents & (POLLERR|POLLHUP))) { if((param?param->srv->so._poll(param->sostate, fds, 1, to*1000):so._poll(so.state, fds, 1, to*1000)) <= 0 || !(fds[0].revents & POLLOUT) || (fds[0].revents & (POLLERR|POLLHUP))) {
return (13); return 13;
} }
return 0; return 0;
} }
@ -575,8 +592,17 @@ int doconnect(struct clientparam * param){
memcpy(SAADDR(&param->sinsr), SAADDR(&param->req), SAADDRLEN(&param->req)); memcpy(SAADDR(&param->sinsr), SAADDR(&param->req), SAADDRLEN(&param->req));
} }
if(!*SAPORT(&param->sinsr))*SAPORT(&param->sinsr) = *SAPORT(&param->req); if(!*SAPORT(&param->sinsr))*SAPORT(&param->sinsr) = *SAPORT(&param->req);
if ((param->remsock=param->srv->so._socket(param->sostate, SASOCK(&param->sinsr), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {return (11);} if ((param->remsock=param->srv->so._socket(param->sostate, SASOCK(&param->sinsr), SOCK_STREAM,
#ifdef WITH_UN
*SAFAMILY(&param->sinsr) == AF_UNIX? 0 :
#endif
IPPROTO_TCP
)) == INVALID_SOCKET) {return (11);}
if(SAISNULL(&param->sinsl)){ if(SAISNULL(&param->sinsl)){
#ifdef WITH_UN
if(*SAFAMILY(&param->sinsr) == AF_UNIX) param->sinsl = param->sinsr;
else
#endif
#ifndef NOIPV6 #ifndef NOIPV6
if(*SAFAMILY(&param->sinsr) == AF_INET6) param->sinsl = param->srv->extsa6; if(*SAFAMILY(&param->sinsr) == AF_INET6) param->sinsl = param->srv->extsa6;
else else
@ -616,6 +642,9 @@ int doconnect(struct clientparam * param){
if(*SAFAMILY(&param->sinsl) == AF_INET6 && param->srv->so._setsockopt(param->sostate, param->remsock, IPPROTO_IPV6, IPV6_BOUND_IF, &idx, sizeof(idx))) return 12; 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
} }
#endif
#ifdef WITH_UN
if(*SAFAMILY(&param->sinsl) != AF_UNIX)
#endif #endif
if(param->srv->so._bind(param->sostate, param->remsock, (struct sockaddr*)&param->sinsl, SASIZE(&param->sinsl))==-1) { if(param->srv->so._bind(param->sostate, param->remsock, (struct sockaddr*)&param->sinsl, SASIZE(&param->sinsl))==-1) {
return 12; return 12;

View File

@ -287,10 +287,7 @@ static int h_proxy(int argc, unsigned char ** argv){
static int h_internal(int argc, unsigned char ** argv){ static int h_internal(int argc, unsigned char ** argv){
#ifdef WITH_UN #ifdef WITH_UN
if(!strncmp((char *)argv[1], "unix:", 5)){ if(!strncmp((char *)argv[1], "unix:", 5)){
struct sockaddr_un *sun = (struct sockaddr_un *)&conf.intsa; make_un(argv[1] +5, (struct sockaddr_un *)&conf.intsa);
memset(sun, 0, sizeof(*sun));
sun->sun_family = AF_UNIX;
strncpy(sun->sun_path, (char *)argv[1] + 5, sizeof(sun->sun_path) - 1);
} }
else else
#endif #endif
@ -776,7 +773,7 @@ struct redirdesc redirs[] = {
static int h_parent(int argc, unsigned char **argv){ static int h_parent(int argc, unsigned char **argv){
struct ace *acl = NULL; struct ace *acl = NULL;
struct chain *chains; struct chain *chains;
char * cidr; char * cidr = NULL;
int i; int i;
acl = conf.acl; acl = conf.acl;
@ -807,9 +804,18 @@ static int h_parent(int argc, unsigned char **argv){
fprintf(stderr, "Chaining error: bad chain type (%s)\n", argv[2]); fprintf(stderr, "Chaining error: bad chain type (%s)\n", argv[2]);
return(4); return(4);
} }
#ifdef WITH_UN
if(!strncmp((char *)argv[3], "unix:", 5)){
make_un(argv[3] + 5, (struct sockaddr_un*)&chains->addr);
}
else {
#endif
cidr = strchr((char *)argv[3], '/'); cidr = strchr((char *)argv[3], '/');
if(cidr) *cidr = 0; if(cidr) *cidr = 0;
if(!getip46(46, argv[3], (struct sockaddr *)&chains->addr)) return (5); if(!getip46(46, argv[3], (struct sockaddr *)&chains->addr)) return (5);
#ifdef WITH_UN
}
#endif
chains->exthost = (unsigned char *)mystrdup((char *)argv[3]); chains->exthost = (unsigned char *)mystrdup((char *)argv[3]);
if(!chains->exthost) return 21; if(!chains->exthost) return 21;
if(cidr){ if(cidr){

View File

@ -326,6 +326,10 @@ extern struct commands commandhandlers[];
#define mapsocket(a,b) sockmap(a,b, 0) #define mapsocket(a,b) sockmap(a,b, 0)
#endif #endif
#ifdef WITH_UN
void make_un(const unsigned char *path, struct sockaddr_un * sun);
#endif
extern struct radserver { extern struct radserver {
PROXYSOCKADDRTYPE authaddr, logaddr, localaddr; PROXYSOCKADDRTYPE authaddr, logaddr, localaddr;

View File

@ -407,10 +407,7 @@ int MODULEMAINFUNC (int argc, char** argv){
case 'i': case 'i':
#ifdef WITH_UN #ifdef WITH_UN
if(!strncmp((char *)argv[i]+2, "unix:", 5)){ if(!strncmp((char *)argv[i]+2, "unix:", 5)){
struct sockaddr_un *sun = (struct sockaddr_un *)&srv.intsa; make_un((unsigned char *)argv[i] + 7, (struct sockaddr_un *)&srv.intsa);
memset(sun, 0, sizeof(*sun));
sun->sun_family = AF_UNIX;
strncpy(sun->sun_path, (char *)argv[i] + 7, sizeof(sun->sun_path) - 1);
} }
else else
#endif #endif
@ -658,15 +655,13 @@ int MODULEMAINFUNC (int argc, char** argv){
if (!iscbc) { if (!iscbc) {
if(srv.srvsock == INVALID_SOCKET){ if(srv.srvsock == INVALID_SOCKET){
#ifdef WITH_UN
if(*SAFAMILY(&srv.intsa) == AF_UNIX){
sock=srv.so._socket(srv.so.state, PF_UNIX, SOCK_STREAM, 0);
}
else
#endif
if(!isudp){ if(!isudp){
sock=srv.so._socket(srv.so.state, SASOCK(&srv.intsa), SOCK_STREAM, IPPROTO_TCP); sock=srv.so._socket(srv.so.state, SASOCK(&srv.intsa), SOCK_STREAM,
#ifdef WITH_UN
*SAFAMILY(&srv.intsa) == AF_UNIX? 0 :
#endif
IPPROTO_TCP
);
} }
else { else {
sock=srv.so._socket(srv.so.state, SASOCK(&srv.intsa), SOCK_DGRAM, IPPROTO_UDP); sock=srv.so._socket(srv.so.state, SASOCK(&srv.intsa), SOCK_DGRAM, IPPROTO_UDP);
@ -718,7 +713,7 @@ int MODULEMAINFUNC (int argc, char** argv){
#ifdef WITH_UN #ifdef WITH_UN
if(*SAFAMILY(&srv.intsa) == AF_UNIX){ if(*SAFAMILY(&srv.intsa) == AF_UNIX){
struct sockaddr_un *sun = (struct sockaddr_un *)&srv.intsa; struct sockaddr_un *sun = (struct sockaddr_un *)&srv.intsa;
unlink(sun->sun_path); if(*sun->sun_path)unlink(sun->sun_path);
} }
#endif #endif
size = sizeof(srv.intsa); size = sizeof(srv.intsa);
@ -1064,7 +1059,12 @@ void srvinit2(struct srvparam * srv, struct clientparam *param){
} }
void srvfree(struct srvparam * srv){ void srvfree(struct srvparam * srv){
if(srv->srvsock != INVALID_SOCKET) so._closesocket(srv->so.state, srv->srvsock); if(srv->srvsock != INVALID_SOCKET) {
so._closesocket(srv->so.state, srv->srvsock);
#ifdef WITH_UN
if(*SAFAMILY(&srv->intsa) == AF_UNIX && *SAADDR(&srv->intsa))unlink((char *)SAADDR(&srv->intsa));
#endif
}
srv->srvsock = INVALID_SOCKET; srv->srvsock = INVALID_SOCKET;
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;

View File

@ -156,7 +156,7 @@ int
#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) : #define UN_SASIZE(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? sizeof(struct sockaddr_un) :
#define UN_SAISNULL(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? (*((struct sockaddr_un *)sa)->sun_path == 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)
#define UN_SAADDR(sa) #define UN_SAADDR(sa)

View File

@ -16,7 +16,18 @@
void * tcppmchild(struct clientparam* param) { void * tcppmchild(struct clientparam* param) {
int res; int res;
if(!param->hostname && parsehostname((char *)param->srv->target, param, ntohs(param->srv->targetport))) RETURN(100); if(!param->hostname){
#ifdef WITH_UN
if(!strncmp((char *)param->srv->target, "unix:", 5)){
make_un(param->srv->target + 5, (struct sockaddr_un *)&param->sinsr);
make_un(param->srv->target + 5, (struct sockaddr_un *)&param->req);
param->hostname = (unsigned char *)mystrdup((char *)param->srv->target);
} else
#endif
if(
parsehostname((char *)param->srv->target, param, ntohs(param->srv->targetport))
) RETURN(100);
}
param->operation = CONNECT; param->operation = CONNECT;
res = (*param->srv->authfunc)(param); res = (*param->srv->authfunc)(param);
if(res) {RETURN(res);} if(res) {RETURN(res);}