UDP-DATAGRAM no longer checks peerport by default

This commit is contained in:
Gerhard Rieger 2020-12-27 20:43:08 +01:00
parent 583e14d7fa
commit 50bdb453dd
6 changed files with 102 additions and 8 deletions

View file

@ -158,6 +158,12 @@ New features:
New option ip-add-source-membership
Feature inspired by Brian (b f31415)
INCOMPATIBLE CHANGE: Address UDP-DATAGRAM now does not check peerport
of replies, as it did up to version 1.7.3.4. Use option sourceport when
you need the old behaviour.
Test: UDP_DATAGRAM_SOURCEPORT
Feature inspired by Hans Bueckler for SSDP inquiry (for UPnP)
####################### V 1.7.3.4:
Corrections:

View file

@ -1088,7 +1088,7 @@ label(ADDRESS_UDP6_CONNECT)dit(bf(tt(UDP6:<host>:<port>)))
label(ADDRESS_UDP_DATAGRAM)dit(bf(tt(UDP-DATAGRAM:<address>:<port>)))
Sends outgoing data to the specified address which may in particular be a
broadcast or multicast address. Packets arriving on the local socket are
checked for the correct remote port and if their source addresses match
checked for the correct remote port only when option link(sourceport)(OPTION_SOURCEPORT) is used (this is a change with Socat() version 1.7.4.0) and if their source addresses match
link(RANGE)(OPTION_RANGE) or link(TCPWRAP)(OPTION_TCPWRAPPERS)
options. This address type can for example be used for implementing
symmetric or asymmetric broadcast or multicast communications.nl()
@ -2260,6 +2260,20 @@ enddit()
startdit()enddit()nl()
label(GROUP_UDP)em(bf(UDP option group))
This option may be applied to UDP datagram sockets.
startdit()
label(OPTION_UDP_IGNORE_PEERPORT)dit(bf(tt(udp-ignore-peerport>)))
Address UDP-DATAGRAM expects incoming responses to come from the port
specified in its second parameter. With this option, it accepts packets
coming from any port.
enddit()
startdit()enddit()nl()
label(GROUP_SCTP)em(bf(SCTP option group))
These options may be applied to SCTP stream sockets.
@ -2274,7 +2288,7 @@ enddit()
startdit()enddit()nl()
em(bf(UDP, TCP, and SCTP option groups))
em(bf(UDP, TCP, and SCTP option group))
Here we find options that are related to the network port mechanism and thus
can be used with UDP, TCP, and SCTP client and server addresses.
@ -2283,7 +2297,10 @@ label(OPTION_SOURCEPORT)dit(bf(tt(sourceport=<port>)))
For outgoing (client) TCP and UDP connections, it sets the source
link(<port>)(TYPE_PORT) using an extra code(bind()) call.
With TCP or UDP listen addresses, socat immediately shuts down the
connection if the client does not use this sourceport (link(example)(EXAMPLE_OPTION_SOURCEPORT)).
connection if the client does not use this sourceport. UDP-RECV,
UDP-RECVFROM, UDP-SENDTO, and UDP-DATAGRAM addresses ignore the packet when
it does not match.
(link(example)(EXAMPLE_OPTION_SOURCEPORT)).
label(OPTION_LOWPORT)dit(bf(tt(lowport)))
Outgoing (client) TCP and UDP connections with this option use
an unused random source port between 640 and 1023 incl. On UNIX class operating
@ -3452,6 +3469,12 @@ SOCAT_IP_DSTADDR: it contains the target address of the packet which may be a
unicast, multicast, or broadcast address.
label(EXAMPLE_SSD)
dit(bf(tt(echo -e "M-SEARCH * HTTP/1.1\nHOST: 239.255.255.250:1900\nMAN: \"ssdp:discover\"\nMX: 4\nST: \"ssdp:all\"\n" |./socat - UDP-DATAGRAM:239.255.255.250:1900,crlf)))
sends an SSDP (Simple Service Discovery Protocol) query to the local network
and collects and outputs the answers received.
dit(bf(tt()))

56
test.sh
View file

@ -69,6 +69,15 @@ export SOCAT_OPTS="$opts"
#debug="1"
debug=
TESTS="$@"; export TESTS
if ! $SOCAT -V >/dev/null 2>&1; then
echo "Failed to execute $SOCAT, exiting" >&2
exit 1
fi
SOCAT_VERSION=$($SOCAT -V |head -n 2 |tail -n 1 |sed 's/.* \([0-9][1-9]*\.[0-9][0-9]*\.[0-9][^[:space:]]*\).*/\1/')
if [ -z "$SOCAT_VERSION" ]; then
echo "Warning: failed to retrieve Socat version" >&2
fi
# for some tests we need a network interface
if type ip >/dev/null 2>&1; then
@ -14465,6 +14474,53 @@ esac
N=$((N+1))
# Test the modified UDP-DATAGRAM address: Now it ignores peerport by default
NAME=UDP_DATAGRAM_PEERPORT
case "$TESTS" in
*%$N%*|*%functions%*|*%udp%*|*%socket%*|*%$NAME%*)
TEST="$NAME: test UDP-DATAGRAM ignoring peerport"
# A UDP-DATAGRAM address bound to PORT has defined peer on PORT+1
# From another Socat instance we send a packet to PORT but with source port
# PORT+2. The first instance should accept the packet
if ! eval $NUMCOND; then :
elif [ $(echo $E "$SOCAT_VERSION\n1.7.3.4" |sort -n |tail -n 1) = 1.7.3.4 ]; then
$PRINTF "test $F_n $TEST... ${YELLOW}Only with Socat 1.7.4.0 or higher${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
else
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"
CMD0="$TRACE $SOCAT $opts -u UDP-DATAGRAM:$LOCALHOST:$((PORT+1)),bind=:$((PORT)) -"
CMD1="$TRACE $SOCAT $opts -u - UDP-DATAGRAM:$LOCALHOST:$((PORT)),bind=:$((PORT+2))"
printf "test $F_n $TEST... " $N
$CMD0 >${tf}0 2>"${te}0" &
pid0=$!
waitudp4port $PORT 1
echo "$da" |$CMD1 >"${tf}1" 2>"${te}1"
rc1=$?
kill $pid0 2>/dev/null; wait
if [ -f ${tf}0 ] && echo "$da" |diff - ${tf}0 >$tdiff; then
$PRINTF "$OK\n"
numOK=$((numOK+1))
else
$PRINTF "$FAILED\n"
echo "$CMD0 &" >&2
cat "${te}0" >&2
echo "$CMD1" >&2
cat "${te}1" >&2
cat "${tdiff}" >&2
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
fi
fi # NUMCOND
;;
esac
PORT=$((PORT+1))
N=$((N+1))
##################################################################################
#=================================================================================
# here come tests that might affect your systems integrity. Put normal tests

View file

@ -453,6 +453,13 @@ int xioopen_udp_datagram(int argc, const char *argv[], struct opt *opts,
return STAT_RETRYLATER;
}
/* only accept packets with correct remote ports */
if (retropt_ushort(opts, OPT_SOURCEPORT, &xfd->para.socket.ip.sourceport)
>= 0) {
xfd->para.socket.ip.dosourceport = true;
xfd->para.socket.ip.sourceport = ntohs(xfd->peersa.ip4.sin_port);
}
retropt_socket_pf(opts, &pf);
result =
_xioopen_udp_sendto(hostname, argv[2], opts, xioflags, xxfd, groups,
@ -466,10 +473,6 @@ int xioopen_udp_datagram(int argc, const char *argv[], struct opt *opts,
xfd->para.socket.la.soa.sa_family = xfd->peersa.soa.sa_family;
/* only accept packets with correct remote ports */
xfd->para.socket.ip.sourceport = ntohs(xfd->peersa.ip4.sin_port);
xfd->para.socket.ip.dosourceport = true;
/* which reply packets will be accepted - determine by range option */
if (retropt_string(opts, OPT_RANGE, &rangename)
>= 0) {

2
xio.h
View file

@ -193,7 +193,7 @@ typedef struct single {
struct {
unsigned int res_opts[2]; /* bits to be set in _res.options are
at [0], bits to be cleared are at [1] */
bool dosourceport;
bool dosourceport; /* check the source port of incoming connection or packets */
uint16_t sourceport; /* host byte order */
bool lowport;
#if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP

View file

@ -83,6 +83,12 @@ bool xioopts_ignoregroups;
# define IF_TCP(a,b)
#endif
#if WITH_UDP
# define IF_UDP(a,b) {a,b},
#else
# define IF_UDP(a,b)
#endif
#if WITH_SCTP
# define IF_SCTP(a,b) {a,b},
#else