From 878a432481ffda00db7073fa3d61545bfd410833 Mon Sep 17 00:00:00 2001 From: Vladimir Dubrovin <3proxy@3proxy.ru> Date: Sun, 12 Apr 2026 19:18:15 +0300 Subject: [PATCH] Support unix socket for parent and tcppm; abstract (fileless) unix sockets for linux support 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. --- src/common.c | 41 +++++++++++++++++++++++++++++++++++------ src/conf.c | 16 +++++++++++----- src/proxy.h | 4 ++++ src/proxymain.c | 28 ++++++++++++++-------------- src/structures.h | 2 +- src/tcppm.c | 13 ++++++++++++- 6 files changed, 77 insertions(+), 27 deletions(-) diff --git a/src/common.c b/src/common.c index 556d658..99fdd5f 100644 --- a/src/common.c +++ b/src/common.c @@ -62,17 +62,34 @@ int mutex_unlock(int *val) } #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){ #ifdef WITH_UN if(af == AF_UNIX){ struct sockaddr_un *sun = (struct sockaddr_un *)src; + int ephemeral = 0; 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++; else basename = path; if(size > 0){ - strncpy(dst, basename, (size > 40) ? 40 : size - 1); - dst[((size > 40) ? 40 : size - 1)] = 0; + strncpy(dst, basename, (size > 40) ? 40 : size - (ephemeral + 1)); + dst[((size > 40) ? 40 : size - (ephemeral + 1))] = 0; } 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)); #endif 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; memset(fds, 0, sizeof(fds)); fds[0].fd = sock; 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))) { - return (13); + return 13; } return 0; } @@ -575,8 +592,17 @@ int doconnect(struct clientparam * param){ memcpy(SAADDR(¶m->sinsr), SAADDR(¶m->req), SAADDRLEN(¶m->req)); } if(!*SAPORT(¶m->sinsr))*SAPORT(¶m->sinsr) = *SAPORT(¶m->req); - if ((param->remsock=param->srv->so._socket(param->sostate, SASOCK(¶m->sinsr), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {return (11);} + if ((param->remsock=param->srv->so._socket(param->sostate, SASOCK(¶m->sinsr), SOCK_STREAM, +#ifdef WITH_UN + *SAFAMILY(¶m->sinsr) == AF_UNIX? 0 : +#endif + IPPROTO_TCP + )) == INVALID_SOCKET) {return (11);} if(SAISNULL(¶m->sinsl)){ +#ifdef WITH_UN + if(*SAFAMILY(¶m->sinsr) == AF_UNIX) param->sinsl = param->sinsr; + else +#endif #ifndef NOIPV6 if(*SAFAMILY(¶m->sinsr) == AF_INET6) param->sinsl = param->srv->extsa6; else @@ -616,6 +642,9 @@ int doconnect(struct clientparam * param){ if(*SAFAMILY(¶m->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 + if(*SAFAMILY(¶m->sinsl) != AF_UNIX) #endif if(param->srv->so._bind(param->sostate, param->remsock, (struct sockaddr*)¶m->sinsl, SASIZE(¶m->sinsl))==-1) { return 12; diff --git a/src/conf.c b/src/conf.c index 23841a0..16dfe51 100644 --- a/src/conf.c +++ b/src/conf.c @@ -287,10 +287,7 @@ static int h_proxy(int argc, unsigned char ** argv){ static int h_internal(int argc, unsigned char ** argv){ #ifdef WITH_UN if(!strncmp((char *)argv[1], "unix:", 5)){ - struct sockaddr_un *sun = (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); + make_un(argv[1] +5, (struct sockaddr_un *)&conf.intsa); } else #endif @@ -776,7 +773,7 @@ struct redirdesc redirs[] = { static int h_parent(int argc, unsigned char **argv){ struct ace *acl = NULL; struct chain *chains; - char * cidr; + char * cidr = NULL; int i; 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]); 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], '/'); if(cidr) *cidr = 0; if(!getip46(46, argv[3], (struct sockaddr *)&chains->addr)) return (5); +#ifdef WITH_UN + } +#endif chains->exthost = (unsigned char *)mystrdup((char *)argv[3]); if(!chains->exthost) return 21; if(cidr){ diff --git a/src/proxy.h b/src/proxy.h index 3d89ece..5ee5386 100644 --- a/src/proxy.h +++ b/src/proxy.h @@ -326,6 +326,10 @@ extern struct commands commandhandlers[]; #define mapsocket(a,b) sockmap(a,b, 0) #endif +#ifdef WITH_UN +void make_un(const unsigned char *path, struct sockaddr_un * sun); +#endif + extern struct radserver { PROXYSOCKADDRTYPE authaddr, logaddr, localaddr; diff --git a/src/proxymain.c b/src/proxymain.c index bc4d654..3074e36 100644 --- a/src/proxymain.c +++ b/src/proxymain.c @@ -407,10 +407,7 @@ int MODULEMAINFUNC (int argc, char** argv){ case 'i': #ifdef WITH_UN if(!strncmp((char *)argv[i]+2, "unix:", 5)){ - struct sockaddr_un *sun = (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); + make_un((unsigned char *)argv[i] + 7, (struct sockaddr_un *)&srv.intsa); } else #endif @@ -658,15 +655,13 @@ int MODULEMAINFUNC (int argc, char** argv){ if (!iscbc) { 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){ - 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 { 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 if(*SAFAMILY(&srv.intsa) == AF_UNIX){ struct sockaddr_un *sun = (struct sockaddr_un *)&srv.intsa; - unlink(sun->sun_path); + if(*sun->sun_path)unlink(sun->sun_path); } #endif size = sizeof(srv.intsa); @@ -1064,7 +1059,12 @@ void srvinit2(struct srvparam * srv, struct clientparam *param){ } 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; if(srv->cbsock != INVALID_SOCKET) so._closesocket(srv->so.state, srv->cbsock); srv->cbsock = INVALID_SOCKET; diff --git a/src/structures.h b/src/structures.h index 5697807..11d12bd 100644 --- a/src/structures.h +++ b/src/structures.h @@ -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_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_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 #define UN_SAPORT(sa) #define UN_SAADDR(sa) diff --git a/src/tcppm.c b/src/tcppm.c index a8c91bd..f05bb63 100644 --- a/src/tcppm.c +++ b/src/tcppm.c @@ -16,7 +16,18 @@ void * tcppmchild(struct clientparam* param) { 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 *)¶m->sinsr); + make_un(param->srv->target + 5, (struct sockaddr_un *)¶m->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; res = (*param->srv->authfunc)(param); if(res) {RETURN(res);}