Corrected UNIX client NAMED options to work on bind address

This commit is contained in:
Gerhard Rieger 2020-12-27 12:39:48 +01:00
parent 5570bf4d62
commit d9d320cb47
13 changed files with 232 additions and 45 deletions

View file

@ -34,6 +34,11 @@ Corrections:
pselect() system call. pselect() system call.
Thanks to Fulvio Scapin for reporting this issue. Thanks to Fulvio Scapin for reporting this issue.
UNIX domain client addresses applied file system entry options (group
NAMED) to the server socket instead of the client (bind) socket entry.
Tests: UNIX_SENDTO_UNLINK UNIX_CONNECT_UNLINK
Thanks to Nico Williams for reporting this major issue.
Porting: Porting:
In gcc version 10 the default changed from -fcommon to -fno-common. In gcc version 10 the default changed from -fcommon to -fno-common.
Consequently, linking filan and procan failed with error Consequently, linking filan and procan failed with error

View file

@ -157,6 +157,26 @@ PH_LATE FD is ready, before start of data loop
PH_LATE2 FD is ready, dropping privileges PH_LATE2 FD is ready, dropping privileges
Passive UNIX socket addresses; this is a mix of socket phases and file system phases:
PH_INIT retrieving info from original state
PH_EARLY before any other processing
PH_PRESOCKET before socket call
PH_SOCKET for socket call
PH_PASTSOCKET after socket call
PH_FD soon after FD creation or identification
PH_PREOPEN before file creation/opening
PH_PREBIND before socket bind()
PH_BIND during socket bind()
PH_PASTOPEN past file creation/opening
PH_PASTBIND past socket bind(), not used up to 1.7.3.4
PH_PRECONNECT before connect()
PH_CONNECT during connect()
PH_PASTCONNECT after connect()
PH_CONNECTED phase common with listen
PH_LATE FD is ready, before start of data loop
PH_LATE2 FD is ready, dropping privileges
FD addresses: FD addresses:
PH_INIT retrieving info from original state PH_INIT retrieving info from original state

View file

@ -1541,6 +1541,8 @@ startdit()enddit()nl()
label(GROUP_NAMED)em(bf(NAMED option group)) label(GROUP_NAMED)em(bf(NAMED option group))
These options work on file system entries.nl() These options work on file system entries.nl()
Please note that, with UNIX domain client addresses, this means the bind entry,
not the target/peer entry.nl()
See also options link(user)(OPTION_USER), link(group)(OPTION_GROUP), and See also options link(user)(OPTION_USER), link(group)(OPTION_GROUP), and
link(mode)(OPTION_MODE). link(mode)(OPTION_MODE).
@ -1575,12 +1577,11 @@ label(OPTION_UNLINK_LATE)dit(bf(tt(unlink-late)))
label(OPTION_UNLINK_CLOSE)dit(bf(tt(unlink-close))) label(OPTION_UNLINK_CLOSE)dit(bf(tt(unlink-close)))
Removes the addresses file system entry when closing the address. Removes the addresses file system entry when closing the address.
For link(named pipes)(ADDRESS_NAMED_PIPE), For link(named pipes)(ADDRESS_NAMED_PIPE),
link(listening unix domain sockets)(ADDRESS_UNIX_LISTEN), link(UNIX domain sockets)(ADDRESS_UNIX_LISTEN),
and the link(symbolic links)(OPTION_SYMBOLIC_LINK) of link(pty addresses)(ADDRESS_PTY), and the link(symbolic links)(OPTION_SYMBOLIC_LINK) of link(pty addresses)(ADDRESS_PTY),
the default is 1; for link(created files)(ADDRESS_CREAT), the default is 1; for link(created files)(ADDRESS_CREAT),
link(opened files)(ADDRESS_OPEN), link(opened files)(ADDRESS_OPEN), and
link(generic opened files)(ADDRESS_GOPEN), and link(generic opened files)(ADDRESS_GOPEN) the default is 0.
link(client unix domain sockets)(ADDRESS_UNIX_CONNECT) the default is 0.
enddit() enddit()
startdit()enddit()nl() startdit()enddit()nl()

88
test.sh
View file

@ -13573,7 +13573,6 @@ esac
PORT=$((PORT+1)) PORT=$((PORT+1))
N=$((N+1)) N=$((N+1))
# Test if unbalanced quoting in Socat addresses is detected # Test if unbalanced quoting in Socat addresses is detected
NAME=UNBALANCED_QUOTE NAME=UNBALANCED_QUOTE
case "$TESTS" in case "$TESTS" in
@ -13703,6 +13702,93 @@ esac
N=$((N+1)) N=$((N+1))
# test if option unlink-close removes the bind socket file
NAME=UNIX_SENDTO_UNLINK
case "$TESTS" in
*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%unix%*|*%$NAME%*)
TEST="$NAME: Option unlink-close with UNIX sendto socket"
# Have a recv socket with option unlink-close=0
# and a sendto socket with option unlink-close=1
# Expected beavior: the recv socket is kept, the
# sendto/bind socket is removed
if ! eval $NUMCOND; then :; else
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
uns="$td/test$N.server"
unc="$td/test$N.client"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"
CMD0="$TRACE $SOCAT $opts -u UNIX-RECV:$uns,unlink-close=0 GOPEN:$tf"
CMD1="$TRACE $SOCAT $opts - UNIX-SENDTO:$uns,bind=$unc,unlink-close=1"
printf "test $F_n $TEST... " $N
$CMD0 >/dev/null 2>"${te}0" &
pid0=$!
waitunixport $uns 1
echo "$da" |$CMD1 >"${tf}1" 2>"${te}1"
rc1=$?
kill $pid0 2>/dev/null; wait
if test -S $uns && ! test -S $unc; then
$PRINTF "$OK\n"
numOK=$((numOK+1))
else
$PRINTF "$FAILED\n"
echo "$CMD0 &"
echo "$CMD1"
ls -ld $uns $unc
cat "${te}0"
cat "${te}1"
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
fi
fi # NUMCOND
;;
esac
N=$((N+1))
# test if option unlink-close removes the bind socket file
NAME=UNIX_CONNECT_UNLINK
case "$TESTS" in
*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%unix%*|*%$NAME%*)
TEST="$NAME: Option unlink-close with UNIX connect socket"
# Have a listen socket with option unlink-close=0
# and a connect socket with option unlink-close=1
# Expected beavior: the listen socket entry is kept, the
# connect/bind socket is removed
if ! eval $NUMCOND; then :; else
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
uns="$td/test$N.server"
unc="$td/test$N.client"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"
CMD0="$TRACE $SOCAT $opts -u UNIX-LISTEN:$uns,unlink-close=0 GOPEN:$tf"
CMD1="$TRACE $SOCAT $opts - UNIX-CONNECT:$uns,bind=$unc,unlink-close=1"
printf "test $F_n $TEST... " $N
$CMD0 >/dev/null 2>"${te}0" &
pid0=$!
waitunixport $uns 1
echo "$da" |$CMD1 >"${tf}1" 2>"${te}1"
rc1=$?
kill $pid0 2>/dev/null; wait
if test -S $uns && ! test -S $unc; then
$PRINTF "$OK\n"
numOK=$((numOK+1))
else
$PRINTF "$FAILED\n"
echo "$CMD0 &"
echo "$CMD1"
ls -ld $uns $unc
cat "${te}0"
cat "${te}1"
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
fi
fi # NUMCOND
;;
esac
N=$((N+1))
################################################################################## ##################################################################################
#================================================================================= #=================================================================================
# here come tests that might affect your systems integrity. Put normal tests # here come tests that might affect your systems integrity. Put normal tests

View file

@ -79,7 +79,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
result = result =
_xioopen_connect(xfd, _xioopen_connect(xfd,
needbind?(struct sockaddr *)us:NULL, uslen, needbind?us:NULL, uslen,
(struct sockaddr *)them, themlen, (struct sockaddr *)them, themlen,
opts, pf, socktype, ipproto, lowport, level); opts, pf, socktype, ipproto, lowport, level);
switch (result) { switch (result) {

View file

@ -278,7 +278,7 @@ static int
/* this cannot fork because we retrieved fork option above */ /* this cannot fork because we retrieved fork option above */
result = result =
_xioopen_connect(xfd, _xioopen_connect(xfd,
needbind?(struct sockaddr *)us:NULL, uslen, needbind?us:NULL, uslen,
(struct sockaddr *)them, themlen, (struct sockaddr *)them, themlen,
opts, pf, socktype, ipproto, lowport, level); opts, pf, socktype, ipproto, lowport, level);
switch (result) { switch (result) {

View file

@ -149,7 +149,7 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
result = result =
_xioopen_connect(xfd, _xioopen_connect(xfd,
needbind?(struct sockaddr *)us:NULL, sizeof(*us), needbind?us:NULL, sizeof(*us),
(struct sockaddr *)them, themlen, (struct sockaddr *)them, themlen,
opts, pf, socktype, IPPROTO_TCP, lowport, level); opts, pf, socktype, IPPROTO_TCP, lowport, level);
switch (result) { switch (result) {

View file

@ -264,7 +264,7 @@ int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts,
if ((result = if ((result =
xioopen_connect(xfd, xioopen_connect(xfd,
needbind?(struct sockaddr *)&us:NULL, uslen, needbind?&us:NULL, uslen,
(struct sockaddr *)&them, themlen, (struct sockaddr *)&them, themlen,
opts, pf, socktype, proto, false)) != 0) { opts, pf, socktype, proto, false)) != 0) {
return result; return result;
@ -337,7 +337,7 @@ int xioopen_socket_listen(int argc, const char *argv[], struct opt *opts,
if ((result = if ((result =
xioopen_listen(xfd, xioflags, xioopen_listen(xfd, xioflags,
(struct sockaddr *)&us, uslen, &us.soa, uslen,
opts, opts0, 0/*instead of pf*/, socktype, proto)) opts, opts0, 0/*instead of pf*/, socktype, proto))
!= STAT_OK) != STAT_OK)
return result; return result;
@ -702,7 +702,7 @@ int xioopen_socket_datagram(int argc, const char *argv[], struct opt *opts,
OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
returns 0 on success. returns 0 on success.
*/ */
int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, int _xioopen_connect(struct single *xfd, union sockaddr_union *us, size_t uslen,
struct sockaddr *them, size_t themlen, struct sockaddr *them, size_t themlen,
struct opt *opts, int pf, int socktype, int protocol, struct opt *opts, int pf, int socktype, int protocol,
bool alt, int level) { bool alt, int level) {
@ -713,6 +713,10 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
int _errno; int _errno;
int result; int result;
if (pf == PF_UNIX && us != NULL) {
applyopts_named(us->un.sun_path, opts, PH_EARLY);
}
if ((xfd->fd = xiosocket(opts, pf, socktype, protocol, level)) < 0) { if ((xfd->fd = xiosocket(opts, pf, socktype, protocol, level)) < 0) {
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -723,6 +727,9 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
applyopts_cloexec(xfd->fd, opts); applyopts_cloexec(xfd->fd, opts);
if (pf == PF_UNIX && us != NULL) {
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
}
applyopts(xfd->fd, opts, PH_PREBIND); applyopts(xfd->fd, opts, PH_PREBIND);
applyopts(xfd->fd, opts, PH_BIND); applyopts(xfd->fd, opts, PH_BIND);
#if WITH_TCP || WITH_UDP #if WITH_TCP || WITH_UDP
@ -733,7 +740,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
/* prepare sockaddr for bind probing */ /* prepare sockaddr for bind probing */
if (us) { if (us) {
sinp = (union sockaddr_union *)us; sinp = us;
} else { } else {
if (them->sa_family == AF_INET) { if (them->sa_family == AF_INET) {
socket_in_init(&sin.ip4); socket_in_init(&sin.ip4);
@ -779,7 +786,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
i = N = XIO_IPPORT_LOWER + dv.rem; i = N = XIO_IPPORT_LOWER + dv.rem;
do { /* loop over lowport bind() attempts */ do { /* loop over lowport bind() attempts */
*port = htons(i); *port = htons(i);
if (Bind(xfd->fd, (struct sockaddr *)sinp, sizeof(*sinp)) < 0) { if (Bind(xfd->fd, &sinp->soa, sizeof(*sinp)) < 0) {
Msg4(errno==EADDRINUSE?E_INFO:level, Msg4(errno==EADDRINUSE?E_INFO:level,
"bind(%d, {%s}, "F_Zd"): %s", xfd->fd, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd,
sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)), sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
@ -803,14 +810,20 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
#endif /* WITH_TCP || WITH_UDP */ #endif /* WITH_TCP || WITH_UDP */
if (us) { if (us) {
if (Bind(xfd->fd, us, uslen) < 0) { if (pf == PF_UNIX && us != NULL) {
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
}
if (Bind(xfd->fd, &us->soa, uslen) < 0) {
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
xfd->fd, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), xfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
uslen, strerror(errno)); uslen, strerror(errno));
Close(xfd->fd); Close(xfd->fd);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} }
if (pf == PF_UNIX && us != NULL) {
applyopts_named(us->un.sun_path, opts, PH_PASTOPEN);
}
applyopts(xfd->fd, opts, PH_PASTBIND); applyopts(xfd->fd, opts, PH_PASTBIND);
@ -822,7 +835,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
Fcntl_l(xfd->fd, F_SETFL, fcntl_flags|O_NONBLOCK); Fcntl_l(xfd->fd, F_SETFL, fcntl_flags|O_NONBLOCK);
} }
result = Connect(xfd->fd, (struct sockaddr *)them, themlen); result = Connect(xfd->fd, them, themlen);
_errno = errno; _errno = errno;
la.soa.sa_family = them->sa_family; lalen = sizeof(la); la.soa.sa_family = them->sa_family; lalen = sizeof(la);
if (Getsockname(xfd->fd, &la.soa, &lalen) < 0) { if (Getsockname(xfd->fd, &la.soa, &lalen) < 0) {
@ -909,6 +922,9 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
applyopts_fchown(xfd->fd, opts); /* OPT_USER, OPT_GROUP */ applyopts_fchown(xfd->fd, opts); /* OPT_USER, OPT_GROUP */
applyopts(xfd->fd, opts, PH_CONNECTED); applyopts(xfd->fd, opts, PH_CONNECTED);
if (pf == PF_UNIX && us != NULL) {
applyopts_named(us->un.sun_path, opts, PH_LATE);
}
applyopts(xfd->fd, opts, PH_LATE); applyopts(xfd->fd, opts, PH_LATE);
return STAT_OK; return STAT_OK;
@ -925,7 +941,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
returns 0 on success. returns 0 on success.
*/ */
int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, int xioopen_connect(struct single *xfd, union sockaddr_union *us, size_t uslen,
struct sockaddr *them, size_t themlen, struct sockaddr *them, size_t themlen,
struct opt *opts, int pf, int socktype, int protocol, struct opt *opts, int pf, int socktype, int protocol,
bool alt) { bool alt) {
@ -1033,6 +1049,10 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
union sockaddr_union la; socklen_t lalen = sizeof(la); union sockaddr_union la; socklen_t lalen = sizeof(la);
char infobuff[256]; char infobuff[256];
if (pf == PF_UNIX && us != NULL) {
applyopts_named(us->un.sun_path, opts, PH_EARLY);
}
if ((xfd->fd = xiosocket(opts, pf, socktype, ipproto, level)) < 0) { if ((xfd->fd = xiosocket(opts, pf, socktype, ipproto, level)) < 0) {
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
@ -1044,18 +1064,24 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
applyopts_cloexec(xfd->fd, opts); applyopts_cloexec(xfd->fd, opts);
if (pf == PF_UNIX && us != NULL) {
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
}
applyopts(xfd->fd, opts, PH_PREBIND); applyopts(xfd->fd, opts, PH_PREBIND);
applyopts(xfd->fd, opts, PH_BIND); applyopts(xfd->fd, opts, PH_BIND);
if (us) { if (us) {
if (Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) { if (Bind(xfd->fd, &us->soa, uslen) < 0) {
Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", Msg4(level, "bind(%d, {%s}, "F_socklen"): %s",
xfd->fd, sockaddr_info((struct sockaddr *)us, uslen, infobuff, sizeof(infobuff)), xfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
uslen, strerror(errno)); uslen, strerror(errno));
Close(xfd->fd); Close(xfd->fd);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
} }
if (pf == PF_UNIX && us != NULL) {
applyopts_named(us->un.sun_path, opts, PH_PASTOPEN);
}
applyopts(xfd->fd, opts, PH_PASTBIND); applyopts(xfd->fd, opts, PH_PASTBIND);
@ -1068,6 +1094,9 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
applyopts_fchown(xfd->fd, opts); applyopts_fchown(xfd->fd, opts);
applyopts(xfd->fd, opts, PH_CONNECTED); applyopts(xfd->fd, opts, PH_CONNECTED);
if (pf == PF_UNIX && us != NULL) {
applyopts_named(us->un.sun_path, opts, PH_LATE);
}
applyopts(xfd->fd, opts, PH_LATE); applyopts(xfd->fd, opts, PH_LATE);
/* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */ /* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */
@ -1221,7 +1250,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
applyopts(xfd->fd, opts, PH_PREBIND); applyopts(xfd->fd, opts, PH_PREBIND);
applyopts(xfd->fd, opts, PH_BIND); applyopts(xfd->fd, opts, PH_BIND);
if ((us != NULL) && Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) { if ((us != NULL) && Bind(xfd->fd, us, uslen) < 0) {
Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd, Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd,
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
strerror(errno)); strerror(errno));
@ -1362,7 +1391,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
palen = msgh.msg_namelen; palen = msgh.msg_namelen;
Notice1("receiving packet from %s"/*"src"*/, Notice1("receiving packet from %s"/*"src"*/,
sockaddr_info((struct sockaddr *)pa, palen, peername, sizeof(peername))/*, sockaddr_info(&pa->soa, palen, peername, sizeof(peername))/*,
sockaddr_info(&la->soa, sockname, sizeof(sockname))*/); sockaddr_info(&la->soa, sockname, sizeof(sockname))*/);
xiodopacketinfo(&msgh, true, true); xiodopacketinfo(&msgh, true, true);
@ -1374,7 +1403,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
continue; continue;
} }
Info1("permitting packet from %s", Info1("permitting packet from %s",
sockaddr_info((struct sockaddr *)pa, palen, sockaddr_info(&pa->soa, palen,
infobuff, sizeof(infobuff))); infobuff, sizeof(infobuff)));
/* set the env vars describing the local and remote sockets */ /* set the env vars describing the local and remote sockets */
@ -1482,7 +1511,7 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags,
applyopts(xfd->fd, opts, PH_PREBIND); applyopts(xfd->fd, opts, PH_PREBIND);
applyopts(xfd->fd, opts, PH_BIND); applyopts(xfd->fd, opts, PH_BIND);
if ((us != NULL) && Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) { if ((us != NULL) && Bind(xfd->fd, us, uslen) < 0) {
Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd, Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd,
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
strerror(errno)); strerror(errno));
@ -1727,12 +1756,12 @@ int xiocheckpeer(xiosingle_t *xfd,
if (xiocheckrange(pa, &xfd->para.socket.range) < 0) { if (xiocheckrange(pa, &xfd->para.socket.range) < 0) {
char infobuff[256]; char infobuff[256];
Warn1("refusing connection from %s due to range option", Warn1("refusing connection from %s due to range option",
sockaddr_info((struct sockaddr *)pa, 0, sockaddr_info(&pa->soa, 0,
infobuff, sizeof(infobuff))); infobuff, sizeof(infobuff)));
return -1; return -1;
} }
Info1("permitting connection from %s due to range option", Info1("permitting connection from %s due to range option",
sockaddr_info((struct sockaddr *)pa, 0, sockaddr_info(&pa->soa, 0,
infobuff, sizeof(infobuff))); infobuff, sizeof(infobuff)));
} }
#endif /* WITH_IP4 */ #endif /* WITH_IP4 */
@ -1744,7 +1773,7 @@ int xiocheckpeer(xiosingle_t *xfd,
if (pa->soa.sa_family == AF_INET && if (pa->soa.sa_family == AF_INET &&
ntohs(((struct sockaddr_in *)pa)->sin_port) != xfd->para.socket.ip.sourceport) { ntohs(((struct sockaddr_in *)pa)->sin_port) != xfd->para.socket.ip.sourceport) {
Warn1("refusing connection from %s due to wrong sourceport", Warn1("refusing connection from %s due to wrong sourceport",
sockaddr_info((struct sockaddr *)pa, 0, sockaddr_info(&pa->soa, 0,
infobuff, sizeof(infobuff))); infobuff, sizeof(infobuff)));
return -1; return -1;
} }
@ -1753,20 +1782,20 @@ int xiocheckpeer(xiosingle_t *xfd,
if (pa->soa.sa_family == AF_INET6 && if (pa->soa.sa_family == AF_INET6 &&
ntohs(((struct sockaddr_in6 *)pa)->sin6_port) != xfd->para.socket.ip.sourceport) { ntohs(((struct sockaddr_in6 *)pa)->sin6_port) != xfd->para.socket.ip.sourceport) {
Warn1("refusing connection from %s due to wrong sourceport", Warn1("refusing connection from %s due to wrong sourceport",
sockaddr_info((struct sockaddr *)pa, 0, sockaddr_info(&pa->soa, 0,
infobuff, sizeof(infobuff))); infobuff, sizeof(infobuff)));
return -1; return -1;
} }
#endif /* WITH_IP6 */ #endif /* WITH_IP6 */
Info1("permitting connection from %s due to sourceport option", Info1("permitting connection from %s due to sourceport option",
sockaddr_info((struct sockaddr *)pa, 0, sockaddr_info(&pa->soa, 0,
infobuff, sizeof(infobuff))); infobuff, sizeof(infobuff)));
} else if (xfd->para.socket.ip.lowport) { } else if (xfd->para.socket.ip.lowport) {
if (pa == NULL) { return -1; } if (pa == NULL) { return -1; }
if (pa->soa.sa_family == AF_INET && if (pa->soa.sa_family == AF_INET &&
ntohs(((struct sockaddr_in *)pa)->sin_port) >= IPPORT_RESERVED) { ntohs(((struct sockaddr_in *)pa)->sin_port) >= IPPORT_RESERVED) {
Warn1("refusing connection from %s due to lowport option", Warn1("refusing connection from %s due to lowport option",
sockaddr_info((struct sockaddr *)pa, 0, sockaddr_info(&pa->soa, 0,
infobuff, sizeof(infobuff))); infobuff, sizeof(infobuff)));
return -1; return -1;
} }
@ -1775,13 +1804,13 @@ int xiocheckpeer(xiosingle_t *xfd,
ntohs(((struct sockaddr_in6 *)pa)->sin6_port) >= ntohs(((struct sockaddr_in6 *)pa)->sin6_port) >=
IPPORT_RESERVED) { IPPORT_RESERVED) {
Warn1("refusing connection from %s due to lowport option", Warn1("refusing connection from %s due to lowport option",
sockaddr_info((struct sockaddr *)pa, 0, sockaddr_info(&pa->soa, 0,
infobuff, sizeof(infobuff))); infobuff, sizeof(infobuff)));
return -1; return -1;
} }
#endif /* WITH_IP6 */ #endif /* WITH_IP6 */
Info1("permitting connection from %s due to lowport option", Info1("permitting connection from %s due to lowport option",
sockaddr_info((struct sockaddr *)pa, 0, sockaddr_info(&pa->soa, 0,
infobuff, sizeof(infobuff))); infobuff, sizeof(infobuff)));
} }
#endif /* WITH_TCP || WITH_UDP */ #endif /* WITH_TCP || WITH_UDP */
@ -1791,12 +1820,12 @@ int xiocheckpeer(xiosingle_t *xfd,
if (result < 0) { if (result < 0) {
char infobuff[256]; char infobuff[256];
Warn1("refusing connection from %s due to tcpwrapper option", Warn1("refusing connection from %s due to tcpwrapper option",
sockaddr_info((struct sockaddr *)pa, 0, sockaddr_info(&pa->soa, 0,
infobuff, sizeof(infobuff))); infobuff, sizeof(infobuff)));
return -1; return -1;
} else if (result > 0) { } else if (result > 0) {
Info1("permitting connection from %s due to tcpwrapper option", Info1("permitting connection from %s due to tcpwrapper option",
sockaddr_info((struct sockaddr *)pa, 0, sockaddr_info(&pa->soa, 0,
infobuff, sizeof(infobuff))); infobuff, sizeof(infobuff)));
} }
#endif /* (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */ #endif /* (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */

View file

@ -74,13 +74,13 @@ char *xiogetifname(int ind, char *val, int ins);
extern int retropt_socket_pf(struct opt *opts, int *pf); extern int retropt_socket_pf(struct opt *opts, int *pf);
extern int xioopen_connect(struct single *fd, extern int xioopen_connect(struct single *fd,
struct sockaddr *us, size_t uslen, union sockaddr_union *us, size_t uslen,
struct sockaddr *them, size_t themlen, struct sockaddr *them, size_t themlen,
struct opt *opts, struct opt *opts,
int pf, int socktype, int protocol, int pf, int socktype, int protocol,
bool alt); bool alt);
extern int _xioopen_connect(struct single *fd, extern int _xioopen_connect(struct single *fd,
struct sockaddr *us, size_t uslen, union sockaddr_union *us, size_t uslen,
struct sockaddr *them, size_t themlen, struct sockaddr *them, size_t themlen,
struct opt *opts, struct opt *opts,
int pf, int socktype, int protocol, int pf, int socktype, int protocol,

View file

@ -126,7 +126,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
/* this cannot fork because we retrieved fork option above */ /* this cannot fork because we retrieved fork option above */
result = result =
_xioopen_connect (xfd, _xioopen_connect (xfd,
needbind?(struct sockaddr *)us:NULL, sizeof(*us), needbind?us:NULL, sizeof(*us),
(struct sockaddr *)them, themlen, (struct sockaddr *)them, themlen,
opts, pf, socktype, IPPROTO_TCP, lowport, level); opts, pf, socktype, IPPROTO_TCP, lowport, level);
switch (result) { switch (result) {

View file

@ -210,13 +210,14 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
/* we expect the form: filename */ /* we expect the form: filename */
const char *name; const char *name;
struct single *xfd = &xxfd->stream; struct single *xfd = &xxfd->stream;
const struct opt *namedopt;
int pf = PF_UNIX; int pf = PF_UNIX;
int socktype = SOCK_STREAM; int socktype = SOCK_STREAM;
int protocol = 0; int protocol = 0;
struct sockaddr_un them, us; struct sockaddr_un them, us;
socklen_t themlen, uslen = sizeof(us); socklen_t themlen, uslen = sizeof(us);
bool needbind = false; bool needbind = false;
bool opt_unlink_close = false; bool opt_unlink_close = true;
int result; int result;
if (argc != 2) { if (argc != 2) {
@ -235,6 +236,7 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
applyopts(-1, opts, PH_EARLY); applyopts(-1, opts, PH_EARLY);
themlen = xiosetunix(pf, &them, name, abstract, xfd->para.socket.un.tight); themlen = xiosetunix(pf, &them, name, abstract, xfd->para.socket.un.tight);
if (!(ABSTRACT && abstract)) { if (!(ABSTRACT && abstract)) {
/* only for non abstract because abstract do not work in file system */ /* only for non abstract because abstract do not work in file system */
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
@ -244,8 +246,13 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
needbind = true; needbind = true;
} }
if (opt_unlink_close) { if (!needbind &&
if ((xfd->unlink_close = strdup(name)) == NULL) { (namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
Error1("Option \"%s\" only with bind option", namedopt->desc->defname);
}
if (opt_unlink_close && needbind) {
if ((xfd->unlink_close = strdup(us.sun_path)) == NULL) {
Error1("strdup(\"%s\"): out of memory", name); Error1("strdup(\"%s\"): out of memory", name);
} }
xfd->opt_unlink_close = true; xfd->opt_unlink_close = true;
@ -253,7 +260,7 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
if ((result = if ((result =
xioopen_connect(xfd, xioopen_connect(xfd,
needbind?(struct sockaddr *)&us:NULL, uslen, needbind?(union sockaddr_union *)&us:NULL, uslen,
(struct sockaddr *)&them, themlen, (struct sockaddr *)&them, themlen,
opts, pf, socktype, protocol, false)) != 0) { opts, pf, socktype, protocol, false)) != 0) {
return result; return result;
@ -269,13 +276,14 @@ static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, i
/* we expect the form: filename */ /* we expect the form: filename */
const char *name; const char *name;
xiosingle_t *xfd = &xxfd->stream; xiosingle_t *xfd = &xxfd->stream;
const struct opt *namedopt;
int pf = PF_UNIX; int pf = PF_UNIX;
int socktype = SOCK_DGRAM; int socktype = SOCK_DGRAM;
int protocol = 0; int protocol = 0;
union sockaddr_union us; union sockaddr_union us;
socklen_t uslen = sizeof(us); socklen_t uslen = sizeof(us);
bool needbind = false; bool needbind = false;
bool opt_unlink_close = false; bool opt_unlink_close = true;
if (argc != 2) { if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)", Error2("%s: wrong number of parameters (%d instead of 1)",
@ -303,8 +311,13 @@ static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, i
needbind = true; needbind = true;
} }
if (opt_unlink_close) { if (!needbind &&
if ((xfd->unlink_close = strdup(name)) == NULL) { (namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
Error1("Option \"%s\" only with bind option", namedopt->desc->defname);
}
if (opt_unlink_close && needbind) {
if ((xfd->unlink_close = strdup(us.un.sun_path)) == NULL) {
Error1("strdup(\"%s\"): out of memory", name); Error1("strdup(\"%s\"): out of memory", name);
} }
xfd->opt_unlink_close = true; xfd->opt_unlink_close = true;
@ -511,6 +524,7 @@ static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, i
int int
_xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups, _xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups,
int abstract, struct opt *opts, const char *name) { int abstract, struct opt *opts, const char *name) {
const struct opt *namedopt;
int pf = PF_UNIX; int pf = PF_UNIX;
int socktype = 0; /* to be determined by server socket type */ int socktype = 0; /* to be determined by server socket type */
int protocol = 0; int protocol = 0;
@ -540,6 +554,11 @@ _xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups,
needbind = true; needbind = true;
} }
if (!needbind &&
(namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
Error1("Option \"%s\" only with bind option", namedopt->desc->defname);
}
if (opt_unlink_close) { if (opt_unlink_close) {
if ((xfd->unlink_close = strdup(name)) == NULL) { if ((xfd->unlink_close = strdup(name)) == NULL) {
Error1("strdup(\"%s\"): out of memory", name); Error1("strdup(\"%s\"): out of memory", name);
@ -553,8 +572,8 @@ _xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups,
/* xfd->dtype = DATA_STREAM; // is default */ /* xfd->dtype = DATA_STREAM; // is default */
if ((result = if ((result =
xioopen_connect(xfd, xioopen_connect(xfd,
needbind?(struct sockaddr *)&us:NULL, uslen, needbind?&us:NULL, uslen,
(struct sockaddr *)&them, themlen, &them.soa, themlen,
opts, pf, socktype?socktype:SOCK_STREAM, protocol, opts, pf, socktype?socktype:SOCK_STREAM, protocol,
false)) != 0) { false)) != 0) {
if (errno == EPROTOTYPE) { if (errno == EPROTOTYPE) {

View file

@ -2514,6 +2514,31 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
return 0; return 0;
} }
/* look for an option with the given properties
return a pointer to the first matching valid option in the list
Returns NULL when no matching option found */
const struct opt *searchopt(const struct opt *opts, unsigned int groups, enum e_phase from, enum e_phase to,
enum e_func func) {
int i;
if (!opts) return NULL;
/* remember: struct opt are in an array */
i = 0;
while (opts[i].desc != ODESC_END) {
if (opts[i].desc != ODESC_DONE &&
(groups == 0 || (groups && (opts[i].desc->group&groups))) &&
(from == 0 || (from <= opts[i].desc->phase)) &&
(to == 0 || (opts[i].desc->phase <= to)) &&
(func == 0 || (opts[i].desc->func == func))) {
return &opts[i];
}
++i;
}
return NULL;
}
/* copy the already parsed options for repeated application, but only those /* copy the already parsed options for repeated application, but only those
matching groups ANY and <groups> */ matching groups ANY and <groups> */
struct opt *copyopts(const struct opt *opts, unsigned int groups) { struct opt *copyopts(const struct opt *opts, unsigned int groups) {

View file

@ -932,6 +932,8 @@ extern int parseopts(const char **a, unsigned int groups, struct opt **opts);
extern int parseopts_table(const char **a, unsigned int groups, extern int parseopts_table(const char **a, unsigned int groups,
struct opt **opts, struct opt **opts,
const struct optname optionnames[], size_t optionnum); const struct optname optionnames[], size_t optionnum);
extern const struct opt *searchopt(const struct opt *opts, unsigned int groups, enum e_phase from, enum e_phase to,
enum e_func func);
extern struct opt *copyopts(const struct opt *opts, unsigned int groups); extern struct opt *copyopts(const struct opt *opts, unsigned int groups);
extern struct opt *moveopts(struct opt *opts, unsigned int groups); extern struct opt *moveopts(struct opt *opts, unsigned int groups);
extern int leftopts(const struct opt *opts); extern int leftopts(const struct opt *opts);