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
#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(&param->sinsr), SAADDR(&param->req), SAADDRLEN(&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)){
#ifdef WITH_UN
if(*SAFAMILY(&param->sinsr) == AF_UNIX) param->sinsl = param->sinsr;
else
#endif
#ifndef NOIPV6
if(*SAFAMILY(&param->sinsr) == AF_INET6) param->sinsl = param->srv->extsa6;
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;
#endif
}
#endif
#ifdef WITH_UN
if(*SAFAMILY(&param->sinsl) != AF_UNIX)
#endif
if(param->srv->so._bind(param->sostate, param->remsock, (struct sockaddr*)&param->sinsl, SASIZE(&param->sinsl))==-1) {
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){
#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){

View File

@ -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;

View File

@ -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;

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_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)

View File

@ -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 *)&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;
res = (*param->srv->authfunc)(param);
if(res) {RETURN(res);}