Fix missing device binding for few cases

This commit is contained in:
Vladimir Dubrovin 2026-10-10 17:38:44 +03:00
parent 3883a51969
commit b4f5ffbf8c
6 changed files with 66 additions and 39 deletions

View File

@ -683,6 +683,49 @@ int connectwithpoll(struct clientparam *param, SOCKET sock, struct sockaddr *sa,
static int bindrange(struct clientparam *param, SOCKET sock, PROXYSOCKADDRTYPE *sa, uint32_t range, int *tries); static int bindrange(struct clientparam *param, SOCKET sock, PROXYSOCKADDRTYPE *sa, uint32_t range, int *tries);
/* -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;
@ -732,25 +775,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

@ -129,6 +129,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(bindwithrange(param, clidatasock, &param->sincl, param->intport)){RETURN(822);} if(bindwithrange(param, clidatasock, &param->sincl, param->intport)){RETURN(822);}
if (pasv) { if (pasv) {

View File

@ -391,6 +391,9 @@ 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 bindwithrange(struct clientparam *param, SOCKET sock, PROXYSOCKADDRTYPE *sa, uint32_t range); int bindwithrange(struct clientparam *param, SOCKET sock, PROXYSOCKADDRTYPE *sa, uint32_t range);
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);
#ifdef WITH_PCRE #ifdef WITH_PCRE
/* One regular expression implementation for the whole program: the pcre /* One regular expression implementation for the whole program: the pcre
commands and every pattern that carries a pcre: prefix. */ commands and every pattern that carries a pcre: prefix. */

View File

@ -862,29 +862,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
@ -1038,6 +1020,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;

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;
@ -244,6 +245,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;
/* the port the client is told to send its datagrams to */ /* the port the client is told to send its datagrams to */

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 (bindwithrange(param, param->remsock, &param->sinsl, param->extport)) { if (bindwithrange(param, param->remsock, &param->sinsl, param->extport)) {
if (param->extport) { if (param->extport) {
param->srv->so._closesocket(param->sostate, param->remsock); param->srv->so._closesocket(param->sostate, param->remsock);