mirror of
https://codeberg.org/scip/udpxd.git
synced 2025-12-16 19:40:58 +01:00
ipv6 works now as well, added fork, added syslog
This commit is contained in:
2
Makefile
2
Makefile
@@ -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
|
||||||
|
|||||||
@@ -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
8
TODO
@@ -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:
|
||||||
|
|||||||
5
client.c
5
client.c
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
client.h
1
client.h
@@ -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
40
host.c
@@ -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
2
host.h
@@ -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
41
log.c
Normal 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
39
log.h
Normal 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
109
net.c
@@ -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,21 +246,10 @@ 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 */
|
||||||
void handle_outside(int inside, int outside, host_t *outside_h) {
|
void handle_outside(int inside, int outside, host_t *outside_h) {
|
||||||
@@ -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
7
net.h
@@ -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)
|
||||||
|
|
||||||
|
|||||||
31
udpxd.c
31
udpxd.c
@@ -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,11 +204,13 @@ 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"
|
||||||
|
"--foreground -f don't fork into background\n"
|
||||||
|
"--pidfile -p <file> pidfile, default: /var/run/udpxd.pid\n"
|
||||||
"--help -h -? print help message\n"
|
"--help -h -? print help message\n"
|
||||||
"--version -v print program version\n"
|
"--version -v print program version\n"
|
||||||
"--verbose -V enable verbose logging\n\n"
|
"--verbose -V enable verbose logging\n\n"
|
||||||
|
|||||||
2
udpxd.h
2
udpxd.h
@@ -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();
|
||||||
|
|||||||
43
udpxd.pod
43
udpxd.pod
@@ -4,12 +4,14 @@ 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
|
||||||
|
--foreground -f don't fork into background
|
||||||
|
--pidfile -p <file> pidfile, default: /var/run/udpxd.pid
|
||||||
--help -h -? print help message
|
--help -h -? print help message
|
||||||
--version -v print program version
|
--version -v print program version
|
||||||
--verbose -V enable verbose logging
|
--verbose -V enable verbose logging
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user