From 50bdb453ddfbb034901780e3400727cda200383f Mon Sep 17 00:00:00 2001 From: Gerhard Rieger Date: Sun, 27 Dec 2020 20:43:08 +0100 Subject: [PATCH] UDP-DATAGRAM no longer checks peerport by default --- CHANGES | 6 ++++++ doc/socat.yo | 29 ++++++++++++++++++++++++--- test.sh | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++ xio-udp.c | 11 +++++++---- xio.h | 2 +- xioopts.c | 6 ++++++ 6 files changed, 102 insertions(+), 8 deletions(-) diff --git a/CHANGES b/CHANGES index 989d162..11e2c32 100644 --- a/CHANGES +++ b/CHANGES @@ -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: diff --git a/doc/socat.yo b/doc/socat.yo index e3168f0..e906839 100644 --- a/doc/socat.yo +++ b/doc/socat.yo @@ -1088,7 +1088,7 @@ label(ADDRESS_UDP6_CONNECT)dit(bf(tt(UDP6::))) label(ADDRESS_UDP_DATAGRAM)dit(bf(tt(UDP-DATAGRAM:
:))) 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=))) For outgoing (client) TCP and UDP connections, it sets the source link()(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())) diff --git a/test.sh b/test.sh index 6d4e543..25affe9 100755 --- a/test.sh +++ b/test.sh @@ -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 diff --git a/xio-udp.c b/xio-udp.c index ff5fb6c..7b0bd1b 100644 --- a/xio-udp.c +++ b/xio-udp.c @@ -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) { diff --git a/xio.h b/xio.h index 58487e1..e866053 100644 --- a/xio.h +++ b/xio.h @@ -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 diff --git a/xioopts.c b/xioopts.c index 7a104b6..d3c7748 100644 --- a/xioopts.c +++ b/xioopts.c @@ -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