diff options
Diffstat (limited to 'udprelay.c')
-rw-r--r-- | udprelay.c | 133 |
1 files changed, 120 insertions, 13 deletions
@@ -26,6 +26,18 @@ #include <arpa/inet.h> #include <stdio.h> #include <linux/if.h> +#include <stdlib.h> + +int numcharsinstr(char *str, char ch) { + int i, count = 0; + + for (i = 0; str[i] != '\0'; i++) { + if (str[i] == ch) + count++; + } + + return count; +} int main(int argc, char *argv[]) { @@ -37,10 +49,100 @@ int main(int argc, char *argv[]) { int rcvfd; int sndfd; + /* For for loops */ + int i, j; + + /* Destination addresses passed in */ + unsigned long addrcount = 0; + int addressessize = 1024; + int* addresses = malloc(addressessize * sizeof(int)); + + /* argc offset to take into account -b or not */ + int argo = 4; + + /* Do we want to enable sending to a broadcast address? */ + short broadcast = 0; + + if (argc > 1 && !strcmp(argv[1], "-b")) { + broadcast = 1; + argo++; + } + + /* See if we're dealing with a destination address range */ + for (i = 0; i < argc - argo; i++) { + /* Make sure there are zero or one range separators */ + if (numcharsinstr(argv[i + argo], '-') > 1) { + fprintf(stderr, "Too many range separators (-): %s\n", argv[i + argo]); + return 1; + /* We're using a range */ + } else if (numcharsinstr(argv[i + argo], '-') == 1) { + int ip1, ip2, rangelen; + + char *tok = NULL; + char *ptr; + + tok = strtok(argv[i + argo], "-"); + if ((inet_pton(AF_INET, tok, &ip1)) != 1) { + fprintf(stderr, "First IP in range is invalid\n"); + return 1; + } + ip1 = htonl(ip1); + + tok = strtok(NULL, "-"); + if ((inet_pton(AF_INET, tok, &ip2)) != 1) { + fprintf(stderr, "Second IP in range is invalid\n"); + return 1; + } + ip2 = htonl(ip2); + + /* Length of range */ + rangelen = ip2 - ip1 + 1; + + if (rangelen < 1) { + fprintf(stderr, "Range is less than one address long " + "(higher address before lower address?)\n"); + return 1; + } + + // Debugging: + // printf("IP range is %d addresses long\n", rangelen); + if (addrcount + rangelen > addressessize) { + while (addrcount + rangelen > addressessize) { + addressessize *= 2; + } + addresses = realloc(addresses, addressessize * sizeof(int)); + } + + for (j = 0; j < rangelen; j++) { + addresses[addrcount + j] = ip1 + j; + } + addrcount += rangelen; + + /* Limit to around 2^18 addresses because doubling + again leads to struct size problems + */ + if (addrcount > 262144) { + fprintf(stderr, "Range of addresses is too great\n"); + return 1; + } + /* It's a single address */ + } else { + int ip; + + if ((inet_pton(AF_INET, argv[i + argo], &ip)) != 1) { + fprintf(stderr, "IP address is invalid\n"); + return 1; + } + + addresses[addrcount] = htonl(ip); + addrcount++; + } + } + /* Destination addresses */ struct { struct sockaddr_in dstaddr; - } dsts[argc - 4]; /* Anything after 4th arg is a destination address */ + } dsts[addrcount]; /* Number of destination addresses */ int dstcount; @@ -53,8 +155,6 @@ int main(int argc, char *argv[]) { /* Address of source packet */ struct sockaddr_in srcaddr; - /* For for loops */ - int i; /* For setsockopt() values */ int optval; @@ -72,12 +172,20 @@ int main(int argc, char *argv[]) { /* Print some usage instructions */ if (argc < 5) { - fprintf(stderr, "Usage: %s LST-ADDR LST-PORT DST-PORT DST-ADDR [DST-ADDR]...\n" + fprintf(stderr, "Usage: %s [-b] LST-ADDR LST-PORT DST-PORT DST-ADDR [DST-ADDR]...\n" + "\n" + "-b Allow sending to a broadcast address. Beware, this can\n" + " create a broadcast storm if retransmitting to a broadcast\n" + " address on the same port a packet came in on.\n" "\n" "bind()s to address LST-ADDR on port LST-PORT and retransmits UDP\n" "packets received to addresses(s) DST-ADDR(s) on port DST-PORT,\n" "with modified headers to reflect the new target.\n" "\n" + "DST-ADDR can be a range of IP addresses in the form:\n" + "a.b.c.d-w.x.y.z e.g. 10.0.0.1-10.0.1.254\n" + "Note that this may include a broadcast address (see above).\n" + "\n" "To receieve broadcast traffic, use a LST-ADDR of 0.0.0.0. If\n" "a program is already listening on LST-PORT on LST-ADDR, you may\n" "listen on a broadcast address such as 255.255.255.255.\n" @@ -91,7 +199,7 @@ int main(int argc, char *argv[]) { return 1; } - if (((lstport = atoi(argv[2])) == 0) || ((dstport = atoi(argv[3])) == 0)) { + if (((lstport = atoi(argv[argo - 2])) == 0) || ((dstport = atoi(argv[argo - 1])) == 0)) { fprintf(stderr, "lst-port or dst-port is invalid\n"); return 1; } @@ -109,14 +217,13 @@ int main(int argc, char *argv[]) { rcvmsg.msg_controllen = sizeof(pkt_info); /* Enumerate destination addresses */ - for (i = 0; i < argc - 4; i++) { + for (i = 0; i < addrcount; i++) { dsts[i].dstaddr.sin_family = AF_INET; dsts[i].dstaddr.sin_port = htons(dstport); - if ((inet_pton(AF_INET, argv[i + 4], &dsts[i].dstaddr.sin_addr)) != 1) { - fprintf(stderr, "dst-addr%d is invalid\n", i + 1); - return 1; - } + /* Populate sin_addr straight from our numeric addresses */ + dsts[i].dstaddr.sin_addr.s_addr = ntohl(addresses[i]); } + /* Set number of destinations */ dstcount = i; @@ -136,7 +243,7 @@ int main(int argc, char *argv[]) { /* Set properties of source address */ srcaddr.sin_family = AF_INET; srcaddr.sin_port = htons(lstport); - if ((inet_pton(AF_INET, argv[1], &srcaddr.sin_addr.s_addr)) != 1) { + if ((inet_pton(AF_INET, argv[argo - 3], &srcaddr.sin_addr.s_addr)) != 1) { fprintf(stderr, "lst-addr is invalid\n"); return 1; } @@ -153,8 +260,8 @@ int main(int argc, char *argv[]) { return 1; } - /* Allow UDP broadcasts on sending socket */ - if (setsockopt(sndfd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(int)) < 0) { + /* Allow UDP broadcasts on sending socket if requested */ + if (broadcast && setsockopt(sndfd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(int)) < 0) { perror("setsockopt(sndfd, SOL_SOCKET, SO_BROADCAST, ...)"); return 1; } |