// 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;
return 0;
}
+//** IP address parsing utility for UDP source address
+// Return 0 if ok and 1 otherwise
+// Formats: <ipv4-address> or <ipv6-address>
+// 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() {
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 );
}
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] );
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);
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);