summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--udprelay.c133
1 files changed, 120 insertions, 13 deletions
diff --git a/udprelay.c b/udprelay.c
index 94781b6..033ec19 100644
--- a/udprelay.c
+++ b/udprelay.c
@@ -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;
}