ipv6 works now as well, added fork, added syslog

This commit is contained in:
git@daemon.de
2015-04-26 13:26:37 +02:00
parent 649db08857
commit aa4e941e53
14 changed files with 280 additions and 84 deletions

View File

@@ -21,7 +21,7 @@
# warning: do not set -O to 2, see TODO # warning: do not set -O to 2, see TODO
CFLAGS = -Wall -Wextra -Werror -O1 -g CFLAGS = -Wall -Wextra -Werror -O1 -g
LDFLAGS= LDFLAGS=
OBJS = host.o client.o net.o udpxd.o OBJS = host.o client.o net.o udpxd.o log.o
DST = udpxd DST = udpxd
PREFIX = /usr/local PREFIX = /usr/local
UID = root UID = root

View File

@@ -7,7 +7,7 @@ This is the README file for the network program udpxd.
udpxd can be used to forward or proxy UDP client traffic udpxd can be used to forward or proxy UDP client traffic
to another port on another system. It also supports binding to another port on another system. It also supports binding
to a specific ip address which will be used as the source to a specific ip address which will be used as the source
for outgoing packets. for outgoing packets. It supports ip version 4 and 6.
## Documentation ## Documentation

8
TODO
View File

@@ -1,12 +1,4 @@
MUST: MUST:
- support ipv6
+ half done: not tested yet, just compiles.
+ check for bind_h: must be same proto as dst_h (both v4 or both v6!)
+ v6ize verbose outputs
+ check for scopeid for dst_h (no route to host?), also the id
must match for bind_h
- daemonize
- syslog
- if compiled with -O2, gcc mangles the dst sockaddr_in pointers in some weird ways - if compiled with -O2, gcc mangles the dst sockaddr_in pointers in some weird ways
MAYBE: MAYBE:

View File

@@ -20,6 +20,7 @@
*/ */
#include "client.h" #include "client.h"
#include "log.h"
void client_del(client_t *client) { void client_del(client_t *client) {
HASH_DEL(clients, client); HASH_DEL(clients, client);
@@ -72,10 +73,8 @@ void client_clean(int asap) {
client_iter(clients, current) { client_iter(clients, current) {
diff = now - current->lastseen; diff = now - current->lastseen;
if(diff >= MAXAGE || asap) { if(diff >= MAXAGE || asap) {
if(VERBOSE) { verbose("closing socket %s:%d for client %s:%d (aged out after %d seconds)\n",
fprintf(stderr, "closing socket %s:%d for client %s:%d (aged out after %d seconds)\n", current->src->ip, current->src->port, current->dst->ip, current->dst->port, MAXAGE);
current->src->ip, current->src->port, current->dst->ip, current->dst->port, MAXAGE);
}
client_close(current); client_close(current);
} }
} }

View File

@@ -54,6 +54,7 @@ typedef struct _client_t client_t;
extern client_t *clients; extern client_t *clients;
extern int VERBOSE; extern int VERBOSE;
extern int FORKED;
/* wrapper for HASH_ITER */ /* wrapper for HASH_ITER */
/** Iterate over the list of clients. /** Iterate over the list of clients.

40
host.c
View File

@@ -41,16 +41,23 @@ host_t *get_host(char *ip, int port, struct sockaddr_in *v4, struct sockaddr_in6
tmp->sin6_family = AF_INET6; tmp->sin6_family = AF_INET6;
tmp->sin6_port = htons( port ); tmp->sin6_port = htons( port );
unsigned int scope = get_v6_scope(ip);
if (is_linklocal((struct in6_addr*)&tmp->sin6_addr)) if (is_linklocal((struct in6_addr*)&tmp->sin6_addr))
tmp->sin6_scope_id = get_v6_scope(ip); tmp->sin6_scope_id = scope;
else else
tmp->sin6_scope_id = 0; tmp->sin6_scope_id = 0;
host->is_v6 = 1; host->is_v6 = 1;
host->sock = (struct sockaddr*)tmp; host->sock = (struct sockaddr*)tmp;
host->size = sizeof(struct sockaddr_in6); host->size = sizeof(struct sockaddr_in6);
host->ip = malloc(INET6_ADDRSTRLEN+1); if(tmp->sin6_scope_id != 0) {
memcpy(host->ip, ip, INET6_ADDRSTRLEN); host->ip = malloc(INET6_ADDRSTRLEN + 9); /* plus [ % ] \0 , scope*/
sprintf(host->ip, "[%s%%%d]", ip, scope);
}
else {
host->ip = malloc(INET6_ADDRSTRLEN + 3); /* plus [ ] \0 */
sprintf(host->ip, "[%s]", ip);
}
} }
else { else {
struct sockaddr_in *tmp = malloc(sizeof(struct sockaddr_in)); struct sockaddr_in *tmp = malloc(sizeof(struct sockaddr_in));
@@ -58,6 +65,7 @@ host_t *get_host(char *ip, int port, struct sockaddr_in *v4, struct sockaddr_in6
tmp->sin_family = AF_INET; tmp->sin_family = AF_INET;
tmp->sin_addr.s_addr = inet_addr( ip ); tmp->sin_addr.s_addr = inet_addr( ip );
tmp->sin_port = htons( port ); tmp->sin_port = htons( port );
host->sock = (struct sockaddr*)tmp; host->sock = (struct sockaddr*)tmp;
host->size = sizeof(struct sockaddr_in); host->size = sizeof(struct sockaddr_in);
host->ip = malloc(INET_ADDRSTRLEN+1); host->ip = malloc(INET_ADDRSTRLEN+1);
@@ -69,20 +77,31 @@ host_t *get_host(char *ip, int port, struct sockaddr_in *v4, struct sockaddr_in6
memcpy(tmp, v4, sizeof(struct sockaddr_in)); memcpy(tmp, v4, sizeof(struct sockaddr_in));
host->ip = malloc(INET_ADDRSTRLEN); host->ip = malloc(INET_ADDRSTRLEN);
inet_ntop(AF_INET, (struct in_addr *)&tmp->sin_addr, host->ip, INET_ADDRSTRLEN); inet_ntop(AF_INET, (struct in_addr *)&tmp->sin_addr, host->ip, INET_ADDRSTRLEN);
host->port = ntohs(tmp->sin_port); host->port = ntohs(tmp->sin_port);
host->sock = (struct sockaddr*)tmp; host->sock = (struct sockaddr*)tmp;
host->size = sizeof(struct sockaddr_in); host->size = sizeof(struct sockaddr_in);
//fprintf(stderr, "%s sock: %p\n", host->ip, tmp);
} }
else if(v6 != NULL) { else if(v6 != NULL) {
struct sockaddr_in6 *tmp = malloc(sizeof(struct sockaddr_in6)); struct sockaddr_in6 *tmp = malloc(sizeof(struct sockaddr_in6));
memcpy(tmp, v6, sizeof(struct sockaddr_in6)); memcpy(tmp, v6, sizeof(struct sockaddr_in6));
host->ip = malloc(INET6_ADDRSTRLEN); char *myip = malloc(INET6_ADDRSTRLEN);
inet_ntop(AF_INET, (struct in6_addr *)&tmp->sin6_addr, host->ip, INET6_ADDRSTRLEN); inet_ntop(AF_INET6, (struct in6_addr *)&tmp->sin6_addr, myip, INET6_ADDRSTRLEN);
host->port = ntohs(tmp->sin6_port); host->port = ntohs(tmp->sin6_port);
host->sock = (struct sockaddr*)tmp; host->sock = (struct sockaddr*)tmp;
host->is_v6 = 1; host->is_v6 = 1;
host->size = sizeof(struct sockaddr_in6); host->size = sizeof(struct sockaddr_in6);
if(tmp->sin6_scope_id != 0) {
host->ip = malloc(INET6_ADDRSTRLEN + 9); /* plus [ % ] \0 , scope*/
sprintf(host->ip, "[%s%%%d]", ip, tmp->sin6_scope_id);
}
else {
host->ip = malloc(INET6_ADDRSTRLEN + 3); /* plus [ ] \0 */
sprintf(host->ip, "[%s]", myip);
}
free(myip);
} }
else { else {
fprintf(stderr, "call invalid!\n"); fprintf(stderr, "call invalid!\n");
@@ -92,8 +111,12 @@ host_t *get_host(char *ip, int port, struct sockaddr_in *v4, struct sockaddr_in6
return host; return host;
} }
char *is_v6(char *ip) { int is_v6(char *ip) {
return strchr(ip, ':'); char *IS = strchr(ip, ':');
if(IS == NULL)
return 0;
else
return 1;
} }
/* via http://stackoverflow.com/questions/13504934/binding-sockets-to-ipv6-addresses /* via http://stackoverflow.com/questions/13504934/binding-sockets-to-ipv6-addresses
@@ -126,7 +149,6 @@ unsigned get_v6_scope(const char *ip){
} }
} }
freeifaddrs(addrs); freeifaddrs(addrs);
fprintf(stderr, "scope: %d\n", scope);
return scope; return scope;
} }

2
host.h
View File

@@ -49,7 +49,7 @@ typedef struct _host_t host_t;
unsigned get_v6_scope(const char *ip); unsigned get_v6_scope(const char *ip);
int is_linklocal(struct in6_addr *a); int is_linklocal(struct in6_addr *a);
host_t *get_host(char *ip, int port, struct sockaddr_in *v4, struct sockaddr_in6 *v6); host_t *get_host(char *ip, int port, struct sockaddr_in *v4, struct sockaddr_in6 *v6);
char *is_v6(char *ip); int is_v6(char *ip);
void host_dump(host_t *host); void host_dump(host_t *host);
void host_clean(host_t *host); void host_clean(host_t *host);

41
log.c Normal file
View File

@@ -0,0 +1,41 @@
/*
This file is part of udpxd.
Copyright (C) 2015 T.v.Dein.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me by mail: <tom AT vondein DOT org>.
*/
#include "log.h"
void verbose(const char * fmt, ...) {
if(VERBOSE) {
char *msg = NULL;
va_list ap;
va_start(ap, fmt);
vasprintf(&msg, fmt, ap);
va_end(ap);
if(FORKED) {
syslog(LOG_INFO, msg);
}
else {
fprintf(stderr, msg);
}
}
}

39
log.h Normal file
View File

@@ -0,0 +1,39 @@
/*
This file is part of udpxd.
Copyright (C) 2015 T.v.Dein.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me by mail: <tom AT vondein DOT org>.
*/
#ifndef _HAVE_LOG_H
#define _HAVE_LOG_H
#define _WITH_DPRINTF
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
#include <syslog.h>
extern int VERBOSE;
extern int FORKED;
void verbose(const char * fmt, ...);
#endif

109
net.c
View File

@@ -22,6 +22,7 @@
#include "net.h" #include "net.h"
#include "client.h" #include "client.h"
#include "host.h" #include "host.h"
#include "log.h"
@@ -87,10 +88,57 @@ int bindsocket( host_t *sock_h) {
return fd; return fd;
} }
int start_listener (char *inip, char *inpt, char *srcip, char *dstip, char *dstpt) { int start_listener (char *inip, char *inpt, char *srcip, char *dstip, char *dstpt, char *pidfile) {
host_t *listen_h = get_host(inip, atoi(inpt), NULL, NULL); host_t *listen_h, *dst_h, *bind_h;
host_t *dst_h = get_host(dstip, atoi(dstpt), NULL, NULL);
host_t *bind_h = NULL; if(FORKED) {
// fork
pid_t pid, sid;
FILE *fd;
pid = fork();
if (pid < 0) {
perror("fork error");
return 1;
}
if (pid > 0) {
/* leave parent */
if((fd = fopen(pidfile, "w")) == NULL) {
perror("failed to write pidfile");
return 1;
}
else {
fprintf(fd, "%d\n", pid);
fclose(fd);
}
return 0;
}
sid = setsid();
if (sid < 0) {
perror("set sid error");
return 1;
}
if ((chdir("/")) < 0) {
perror("failed to chdir to /");
return 1;
}
umask(0);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
openlog("udpxd", LOG_NOWAIT|LOG_PID, LOG_USER);
}
listen_h = get_host(inip, atoi(inpt), NULL, NULL);
dst_h = get_host(dstip, atoi(dstpt), NULL, NULL);
bind_h = NULL;
if(srcip != NULL) { if(srcip != NULL) {
bind_h = get_host(srcip, 0, NULL, NULL); bind_h = get_host(srcip, 0, NULL, NULL);
@@ -102,19 +150,18 @@ int start_listener (char *inip, char *inpt, char *srcip, char *dstip, char *dstp
bind_h = get_host("0.0.0.0", 0, NULL, NULL); bind_h = get_host("0.0.0.0", 0, NULL, NULL);
} }
int listen = bindsocket(listen_h); int listen = bindsocket(listen_h);
if(listen == -1) if(listen == -1)
return 1; return 1;
if(VERBOSE) { if(VERBOSE) {
fprintf(stderr, "Listening on %s:%s, forwarding to %s:%s", verbose("Listening on %s:%s, forwarding to %s:%s",
inip, inpt, dstip, dstpt); listen_h->ip, inpt, dst_h->ip, dstpt);
if(srcip != NULL) if(srcip != NULL)
fprintf(stderr, ", binding to %s\n", srcip); verbose(", binding to %s\n", bind_h->ip);
else else
fprintf(stderr, "\n"); verbose("\n");
} }
main_loop(listen, listen_h, bind_h, dst_h); main_loop(listen, listen_h, bind_h, dst_h);
@@ -123,6 +170,8 @@ int start_listener (char *inip, char *inpt, char *srcip, char *dstip, char *dstp
host_clean(listen_h); host_clean(listen_h);
host_clean(dst_h); host_clean(dst_h);
closelog();
return 0; return 0;
} }
@@ -148,21 +197,15 @@ void handle_inside(int inside, host_t *listen_h, host_t *bind_h, host_t *dst_h)
free(src); free(src);
if(VERBOSE) {
fprintf(stderr, "New incomming request from %s:%d with %d bytes\n",
src_h->ip, src_h->port, len);
}
if(len > 0) { if(len > 0) {
/* do we know it ? */ /* do we know it ? */
client = client_find_src(src_h); client = client_find_src(src_h);
if(client != NULL) { if(client != NULL) {
/* yes, we know it, send req out via existing bind socket */ /* yes, we know it, send req out via existing bind socket */
if(VERBOSE) { verbose("Client %s:%d is known, forwarding %d bytes to %s:%d ",
fprintf(stderr, "Client %s:%d is known, forwarding data to %s:%d ", src_h->ip, src_h->port, len, dst_h->ip, dst_h->port);
src_h->ip, src_h->port, dst_h->ip, dst_h->port); verb_prbind(bind_h);
}
if(sendto(client->socket, buffer, len, 0, (struct sockaddr*)dst_h->sock, dst_h->size) < 0) { if(sendto(client->socket, buffer, len, 0, (struct sockaddr*)dst_h->sock, dst_h->size) < 0) {
fprintf(stderr, "unable to forward to %s:%d\n", dst_h->ip, dst_h->port); fprintf(stderr, "unable to forward to %s:%d\n", dst_h->ip, dst_h->port);
perror(NULL); perror(NULL);
@@ -173,11 +216,9 @@ void handle_inside(int inside, host_t *listen_h, host_t *bind_h, host_t *dst_h)
} }
else { else {
/* unknown client, open new out socket */ /* unknown client, open new out socket */
if(VERBOSE) { verbose("Client %s:%d is unknown, forwarding %d bytes to %s:%d ",
fprintf(stderr, "Client %s:%d is unknown, forwarding data to %s:%d ", src_h->ip, src_h->port, len, dst_h->ip, dst_h->port);
src_h->ip, src_h->port, dst_h->ip, dst_h->port); verb_prbind(bind_h);
}
output = bindsocket(bind_h); output = bindsocket(bind_h);
@@ -205,20 +246,9 @@ void handle_inside(int inside, host_t *listen_h, host_t *bind_h, host_t *dst_h)
} }
client_add(client); client_add(client);
if(VERBOSE) {
if(strcmp(bind_h->ip, "0.0.0.0") != 0 || strcmp(bind_h->ip, "::0") != 0) {
fprintf(stderr, "from %s:%d\n", ret_h->ip, ret_h->port);
}
else {
fprintf(stderr, "\n");
}
}
} }
} }
} }
/* FIXME: free? */
} }
/* handle answer from the outside */ /* handle answer from the outside */
@@ -310,3 +340,14 @@ void int_handler(int sig) {
signal(sig, SIG_IGN); signal(sig, SIG_IGN);
longjmp(JumpBuffer, 1); longjmp(JumpBuffer, 1);
} }
void verb_prbind (host_t *bind_h) {
if(VERBOSE) {
if(strcmp(bind_h->ip, "0.0.0.0") != 0 || strcmp(bind_h->ip, "[::0]") != 0) {
verbose("from %s:%d\n", bind_h->ip, bind_h->port);
}
else {
verbose("\n");
}
}
}

7
net.h
View File

@@ -30,7 +30,9 @@
#include <time.h> #include <time.h>
#include <signal.h> #include <signal.h>
#include <setjmp.h> #include <setjmp.h>
#include <syslog.h>
#include <sys/stat.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/types.h> #include <sys/types.h>
@@ -44,6 +46,7 @@
extern client_t *clients; extern client_t *clients;
extern int VERBOSE; extern int VERBOSE;
extern int FORKED;
@@ -51,13 +54,13 @@ 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); 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 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, char *dstpt); int start_listener (char *inip, char *inpt, char *srcip, char *dstip, char *dstpt, char *pidfile);
int fill_set(fd_set *fds); int fill_set(fd_set *fds);
int get_sender(fd_set *fds); int get_sender(fd_set *fds);
int bindsocket( host_t *sock_h); int bindsocket( host_t *sock_h);
void int_handler(int sig); void int_handler(int sig);
void verb_prbind (host_t *bind_h);
#define _IS_LINK_LOCAL(a) do { IN6_IS_ADDR_LINKLOCAL(a); } while(0) #define _IS_LINK_LOCAL(a) do { IN6_IS_ADDR_LINKLOCAL(a); } while(0)

43
udpxd.c
View File

@@ -26,6 +26,7 @@
/* global client list */ /* global client list */
client_t *clients = NULL; client_t *clients = NULL;
int VERBOSE = 0; int VERBOSE = 0;
int FORKED = 1;
/* parse ip:port */ /* parse ip:port */
int parse_ip(char *src, char *ip, char *pt) { int parse_ip(char *src, char *ip, char *pt) {
@@ -90,6 +91,8 @@ int parse_ip(char *src, char *ip, char *pt) {
int main ( int argc, char* argv[] ) { int main ( int argc, char* argv[] ) {
int opt, err; int opt, err;
char *inip, *inpt, *srcip, *dstip, *dstpt; char *inip, *inpt, *srcip, *dstip, *dstpt;
char pidfile[MAX_BUFFER_SIZE];
err = 0; err = 0;
static struct option longopts[] = { static struct option longopts[] = {
@@ -98,7 +101,9 @@ int main ( int argc, char* argv[] ) {
{ "dest", required_argument, NULL, 'd' }, { "dest", required_argument, NULL, 'd' },
{ "version", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "verbose", no_argument, NULL, 'V' } { "verbose", no_argument, NULL, 'V' },
{ "foreground",no_argument, NULL, 'f' },
{ "pidfile", required_argument, NULL, 'p' },
}; };
if( argc < 2 ) { if( argc < 2 ) {
@@ -107,13 +112,17 @@ int main ( int argc, char* argv[] ) {
} }
srcip = dstip = inip = dstpt = inpt = NULL; srcip = dstip = inip = dstpt = inpt = NULL;
strncpy(pidfile, "/var/run/udpxd.pid", 19);
while ((opt = getopt_long(argc, argv, "l:b:d:vVh?", longopts, NULL)) != -1) { while ((opt = getopt_long(argc, argv, "l:b:d:vfVh?", longopts, NULL)) != -1) {
switch (opt) { switch (opt) {
case 'v': case 'v':
fprintf(stderr, "This is %s version %s\n", argv[0], UDPXD_VERSION); fprintf(stderr, "This is %s version %s\n", argv[0], UDPXD_VERSION);
return 1; return 1;
break; break;
case 'f':
FORKED = 0;
break;
case 'h': case 'h':
case '?': case '?':
usage(); usage();
@@ -146,6 +155,9 @@ int main ( int argc, char* argv[] ) {
srcip = malloc(INET6_ADDRSTRLEN+1); srcip = malloc(INET6_ADDRSTRLEN+1);
strncpy(srcip, optarg, strlen(optarg)); strncpy(srcip, optarg, strlen(optarg));
break; break;
case 'p':
strncpy(pidfile, optarg, strlen(optarg));
break;
default: default:
usage(); usage();
return 1; return 1;
@@ -165,11 +177,16 @@ int main ( int argc, char* argv[] ) {
err = 1; err = 1;
} }
if(! err) { if(srcip != NULL) {
err = start_listener (inip, inpt, srcip, dstip, dstpt); if(is_v6(srcip) != is_v6(dstip)) {
fprintf(stderr, "Bind ip and destination ip must be both v4 or v6 and can't be mixed!\n");
err = 1;
}
} }
/* FIXME: add sighandler */ if(! err) {
err = start_listener (inip, inpt, srcip, dstip, dstpt, pidfile);
}
if(srcip != NULL) if(srcip != NULL)
free(srcip); free(srcip);
@@ -187,14 +204,16 @@ int main ( int argc, char* argv[] ) {
void usage() { void usage() {
fprintf(stderr, fprintf(stderr,
"Usage: udpxd [-lbdvhV]\n\n" "Usage: udpxd [-lbdfpvhV]\n\n"
"Options:\n" "Options:\n"
"--listen -l <ip:port> listen for incoming requests\n" "--listen -l <ip:port> listen for incoming requests\n"
"--bind -b <ip> bind ip used for outgoing requests\n" "--bind -b <ip> bind ip used for outgoing requests\n"
"--dest -d <ip:port> destination to forward requests to\n" "--dest -d <ip:port> destination to forward requests to\n"
"--help -h -? print help message\n" "--foreground -f don't fork into background\n"
"--version -v print program version\n" "--pidfile -p <file> pidfile, default: /var/run/udpxd.pid\n"
"--verbose -V enable verbose logging\n\n" "--help -h -? print help message\n"
"--version -v print program version\n"
"--verbose -V enable verbose logging\n\n"
"Options -l and -d are mandatory.\n\n" "Options -l and -d are mandatory.\n\n"
"This is udpxd version %s.\n", UDPXD_VERSION "This is udpxd version %s.\n", UDPXD_VERSION
); );

View File

@@ -36,7 +36,7 @@
#include <sys/fcntl.h> #include <sys/fcntl.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#define UDPXD_VERSION "0.0.1" #define UDPXD_VERSION "0.0.2"
void usage(); void usage();

View File

@@ -4,15 +4,17 @@ udpxd - A general purpose UDP relay/port forwarder/proxy
=head1 SYNOPSIS =head1 SYNOPSIS
Usage: udpxd [-lbdvhV] Usage: udpxd [-lbdfpvhV]
Options: Options:
--listen -l <ip:port> listen for incoming requests --listen -l <ip:port> listen for incoming requests
--bind -b <ip> bind ip used for outgoing requests --bind -b <ip> bind ip used for outgoing requests
--dest -d <ip:port> destination to forward requests to --dest -d <ip:port> destination to forward requests to
--help -h -? print help message --foreground -f don't fork into background
--version -v print program version --pidfile -p <file> pidfile, default: /var/run/udpxd.pid
--verbose -V enable verbose logging --help -h -? print help message
--version -v print program version
--verbose -V enable verbose logging
=head1 DESCRIPTION =head1 DESCRIPTION
@@ -39,6 +41,32 @@ with B<-b>.
The options B<-l> and B<-d> are mandatory. The options B<-l> and B<-d> are mandatory.
If the option B<-f> has not been specified, udpxd forks into
the background and becomes a daemon. It writes it pidfile to
C</var/run/udpxd.pid>, which can be changed with the B<-p>
option.
B<Caution: udpxd does not drop its privileges. If started as
root, it will continue to run as root. This may change in the
future.>
Udpxd supports ip version 4 and 6, it doesn't support hostnames,
-l, -d and -b must be ip addresses. In order to specify an ipv6
address and a port, use:
-l [::1]:53
that is, surround the ipv6 address with brackets.
Port forwardings can be mixed:
listen | forward to
-------+-----------
ipv4 | ipv4
ipv6 | ipv4
ipv4 | ipv6
ipv6 | ipv6
=head1 EXAMPLES =head1 EXAMPLES
Let's say you operate a multihomed unix system named 'foo' Let's say you operate a multihomed unix system named 'foo'
@@ -82,9 +110,20 @@ In this case for the client everything looks as before, but the
ntp server on the other end will see ntp requests coming from ntp server on the other end will see ntp requests coming from
192.168.1.45 instead. 192.168.1.45 instead.
Here we listen on the ip v6 loopback address and forward traffic
to another ip v6 destination address:
udpxd -l [::1]:53 -d [2001:4860:4860::8888]:53
Or, we could listen on an ip v4 address and forward to an ip v6
address:
udpxd -l 192.168.1.1:53 -d [2001:4860:4860::8888]:53
=head1 FILES =head1 FILES
udpxd currently does not write or open any files. B</var/run/udpxd.pid>: created if running in daemon mode (-f not
specified).
=head1 BUGS =head1 BUGS