From b750cefb00a59bcccebf2f6ab6e48d609f8b20d7 Mon Sep 17 00:00:00 2001 From: ValdikSS Date: Thu, 13 Apr 2017 00:59:14 +0300 Subject: [PATCH] Implement promiscuous (dumb) mode by binding port on outgoing socket This mode is useful for services which cannot handle multiple clients. Also useful for NAT traversal. All outgoing packets would be transmitted from a single "client" (UDP port). Moreover, only one (latest) proxy client receives the reply. --- net.c | 6 ++++-- net.h | 2 +- udpxd.c | 25 ++++++++++++++++--------- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/net.c b/net.c index 4c61ffe..bd39283 100644 --- a/net.c +++ b/net.c @@ -185,7 +185,7 @@ int drop_privileges(char *user, char *chrootdir) { return 0; } -int start_listener (char *inip, char *inpt, char *srcip, char *dstip, +int start_listener (char *inip, char *inpt, char *srcip, char *srcpt, char *dstip, char *dstpt, char *pidfile, char *chrootdir, char *user) { host_t *listen_h, *dst_h, *bind_h; @@ -208,7 +208,7 @@ int start_listener (char *inip, char *inpt, char *srcip, char *dstip, bind_h = NULL; if(srcip != NULL) { - bind_h = get_host(srcip, 0, NULL, NULL); + bind_h = get_host(srcip, atoi(srcpt), NULL, NULL); } else { if(dst_h->is_v6) @@ -298,6 +298,8 @@ void handle_inside(int inside, host_t *listen_h, host_t *bind_h, host_t *dst_h) src_h->ip, src_h->port, len, dst_h->ip, dst_h->port); verb_prbind(bind_h); + if (bind_h->port) + client_clean(1); output = bindsocket(bind_h); if (output >= 0) { /* send req out */ diff --git a/net.h b/net.h index 25156f7..6a7d615 100644 --- a/net.h +++ b/net.h @@ -56,7 +56,7 @@ void handle_inside(int inside, host_t *listen_h, host_t *bind_h, host_t *dst_h); void handle_outside(int inside, int outside, host_t *outside_h); int main_loop(int listensocket, host_t *listen_h, host_t *bind_h, host_t *dst_h); -int start_listener (char *inip, char *inpt, char *srcip, char *dstip, +int start_listener (char *inip, char *inpt, char *srcip, char *srcpt, char *dstip, char *dstpt, char *pidfile, char *chrootdir, char *user); int daemonize(char *pidfile); int drop_privileges(char *user, char *chrootdir); diff --git a/udpxd.c b/udpxd.c index 5f36f35..00ad44b 100644 --- a/udpxd.c +++ b/udpxd.c @@ -92,7 +92,8 @@ void usage() { "Usage: udpxd [-lbdfpvhV]\n\n" "Options:\n" "--listen -l listen for incoming requests\n" - "--bind -b bind ip used for outgoing requests\n" + "--bind -b bind ip used for outgoing requests\n" + " specify port for promiscuous mode\n" "--to -t destination to forward requests to\n" "--daemon -d daemon mode, fork into background\n" "--pidfile -p pidfile, default: /var/run/udpxd.pid\n" @@ -110,7 +111,7 @@ void usage() { int main ( int argc, char* argv[] ) { int opt, err; - char *inip, *inpt, *srcip, *dstip, *dstpt; + char *inip, *inpt, *srcip, *srcpt, *dstip, *dstpt; char pidfile[MAX_BUFFER_SIZE]; char user[128]; char chroot[MAX_BUFFER_SIZE]; @@ -135,7 +136,7 @@ int main ( int argc, char* argv[] ) { return 1; } - srcip = dstip = inip = dstpt = inpt = NULL; + srcip = srcpt = dstip = inip = dstpt = inpt = NULL; /* set defaults */ strncpy(pidfile, "/var/run/udpxd.pid", 19); @@ -171,19 +172,23 @@ int main ( int argc, char* argv[] ) { dstip = malloc(INET6_ADDRSTRLEN+1); dstpt = malloc(6); if (parse_ip(optarg, dstip, dstpt) != 0) { - fprintf(stderr, "Parameter -d has the format !\n"); + fprintf(stderr, "Parameter -t has the format !\n"); err = 1; } break; case 'b': - srcip = malloc(INET6_ADDRSTRLEN+1); - if(strlen(optarg) > INET6_ADDRSTRLEN) { + srcip = malloc(INET6_ADDRSTRLEN+1+5); // +5 is for port + srcpt = malloc(6); + if(strlen(optarg) > INET6_ADDRSTRLEN+5) { fprintf(stderr, "Bind ip address is too long!\n"); err = 1; } else { - strncpy(srcip, optarg, INET6_ADDRSTRLEN); - srcip[INET6_ADDRSTRLEN-1] = '\0'; + if (strchr(optarg, ':') == NULL || parse_ip(optarg, srcip, srcpt) != 0) { + strncpy(srcip, optarg, INET6_ADDRSTRLEN+5); + srcip[INET6_ADDRSTRLEN+5-1] = '\0'; + strncpy(srcpt, "0", 2); + } } break; case 'p': @@ -225,11 +230,13 @@ int main ( int argc, char* argv[] ) { } if(! err) { - err = start_listener (inip, inpt, srcip, dstip, dstpt, pidfile, chroot, user); + err = start_listener (inip, inpt, srcip, srcpt, dstip, dstpt, pidfile, chroot, user); } if(srcip != NULL) free(srcip); + if(srcpt != NULL) + free(srcpt); if(dstip != NULL) free(dstip); if(inip != NULL)