From a075778f4f1f24f0ebccaad410202eaed91dbbc8 Mon Sep 17 00:00:00 2001 From: Ralph Ronnquist Date: Tue, 8 Nov 2022 16:49:49 +1100 Subject: [PATCH] Add optional source address for UDP. --- rrqnet.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/rrqnet.c b/rrqnet.c index efd7066..ea0a3af 100644 --- a/rrqnet.c +++ b/rrqnet.c @@ -188,6 +188,12 @@ static struct { // Flag to signal the UDP socket as being ipv6 or not (forced ipv4) static int udp6 = 1; +// The given UDP source address, if any +static struct { + int family; + unsigned char address[16]; +} udp_source; + // Flag to indicate tpg transport patch = avoid UDP payload of 1470 // bytes by adding 2 tag-along bytes static int tpg_quirk = 0; @@ -728,6 +734,38 @@ static int parse_mcast(char *arg) { return 0; } +//** IP address parsing utility for UDP source address +// Return 0 if ok and 1 otherwise +// Formats: or +// The ipv4 address should be a multicast address in ranges +// 224.0.0.0/22, 232.0.0.0/7, 234.0.0.0/8 or 239.0.0.0/8 +// though it's not checked here. +static int parse_udp_source(char *arg) { + if ( inet_pton( AF_INET6, arg, udp_source.address ) ) { + // An ipv6 address is given. + if ( udp6 ) { + udp_source.family = AF_INET6; + return 0; + } + return 1; + } + if ( ! inet_pton( AF_INET, arg, udp_source.address ) ) { + return 1; + } + + // An ipv4 address is given. + if ( udp6 ) { + // Translate into ipv6-encoded ipv4 + memmove( udp_source.address + 12, udp_source.address, 4 ); + memset( udp_source.address, 0, 10 ); + memset( udp_source.address + 10, -1, 2 ); + udp_source.family = AF_INET6; + } else { + udp_source.family = AF_INET; + } + return 0; +} + // Utility that sets upt the multicast socket, which is used for // receiving multicast packets. static void setup_mcast() { @@ -1312,9 +1350,16 @@ static void usage(void) { fprintf( stderr, "Packet tunneling over UDP, multiple channels, " ); fprintf( stderr, "version 1.5.3\n" ); fprintf( stderr, "Usage: " ); - fprintf( stderr, - "%s [-v] [-tpg] [-4] [-B n] [-T n] [-m mcast] [-t tap] port [remote]+ \n", - progname ); + fprintf( stderr, "%s [options] port [remote]+ \n", progname ); + fprintf( stderr, "** options must be given or omitted in order!!\n" ); + fprintf( stderr, " -v = verbose log, -vv or -vvv for more logs\n" ); + fprintf( stderr, " -tpg = UDP transport quirk: avoid bad sizes\n" ); + fprintf( stderr, " -4 = use an ipv4 UDP socket\n" ); + fprintf( stderr, " -B n = use n buffers (2*threads) by default\n"); + fprintf( stderr, " -T n = use n delivery threads (5 bu default)\n" ); + fprintf( stderr, " -m mcast = allow remotes on multicast address\n" ); + fprintf( stderr, " -t tap = use the nominated tap (or - for stdio)\n" ); + fprintf( stderr, " -I source = use given source address for UDP\n" ); exit( 1 ); } @@ -1472,6 +1517,15 @@ int main(int argc, char *argv[]) { i += 2; ENSUREARGS( 1 ); } + // Then optional source address for UDP + if ( strncmp( "-I", argv[i], 2 ) == 0 ) { + ENSUREARGS( 2 ); + if ( parse_udp_source( argv[i+1] ) ) { + usage(); + } + i += 2; + ENSUREARGS( 1 ); + } // then: required port if ( sscanf( argv[i++], "%d", &port ) != 1 ) { fprintf( stderr, "Bad local port: %s\n", argv[i-1] ); @@ -1547,8 +1601,12 @@ int main(int argc, char *argv[]) { struct sockaddr_in udp_addr = { .sin_family = AF_INET, .sin_port = htons( port ), - .sin_addr.s_addr = htonl(INADDR_ANY), }; + if ( udp_source.family == 0 ) { + udp_addr.sin_addr.s_addr = htonl( INADDR_ANY ); + } else { + udp_addr.sin_addr.s_addr = *((uint32_t*) udp_source.address); + } if ( bind( udp_fd, (struct sockaddr*) &udp_addr, sizeof(udp_addr))) { fprintf( stderr, "Error binding socket!\n"); exit(1); @@ -1563,8 +1621,8 @@ int main(int argc, char *argv[]) { struct sockaddr_in6 udp6_addr = { .sin6_family = AF_INET6, .sin6_port = htons( port ), - .sin6_addr = IN6ADDR_ANY_INIT, }; + memcpy( udp6_addr.sin6_addr.s6_addr, udp_source.address, 16 ); if ( bind( udp_fd, (struct sockaddr*) &udp6_addr, sizeof(udp6_addr))) { fprintf( stderr, "Error binding socket!\n"); exit(1); -- 2.39.2