2015-04-21 20:09:12 +02:00
|
|
|
/*
|
|
|
|
|
This file is part of udpxd.
|
|
|
|
|
|
2016-09-22 21:37:30 +02:00
|
|
|
Copyright (C) 2015-2016 T.v.Dein.
|
2015-04-21 20:09:12 +02:00
|
|
|
|
|
|
|
|
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 "udpxd.h"
|
|
|
|
|
#include "net.h"
|
|
|
|
|
#include "client.h"
|
|
|
|
|
|
|
|
|
|
/* global client list */
|
|
|
|
|
client_t *clients = NULL;
|
|
|
|
|
int VERBOSE = 0;
|
2015-04-27 14:04:57 +02:00
|
|
|
int FORKED = 0;
|
2015-04-21 20:09:12 +02:00
|
|
|
|
2015-04-24 22:03:50 +02:00
|
|
|
/* parse ip:port */
|
|
|
|
|
int parse_ip(char *src, char *ip, char *pt) {
|
|
|
|
|
char *ptr = NULL;
|
2015-04-21 20:09:12 +02:00
|
|
|
|
2015-04-24 22:03:50 +02:00
|
|
|
if (strchr(optarg, '[')) {
|
|
|
|
|
/* v6 */
|
|
|
|
|
ptr = strtok(&src[1], "]");
|
2015-04-21 20:09:12 +02:00
|
|
|
|
2015-04-24 22:03:50 +02:00
|
|
|
if(strlen(ptr) > INET6_ADDRSTRLEN) {
|
|
|
|
|
fprintf(stderr, "ip v6 address is too long!\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
strncpy(ip, ptr, strlen(ptr)+1);
|
|
|
|
|
ptr = strtok(NULL, "]");
|
|
|
|
|
if(ptr)
|
|
|
|
|
ptr = &ptr[1]; /* remove : */
|
|
|
|
|
}
|
|
|
|
|
else if(strchr(optarg, ':')) {
|
|
|
|
|
/* v4 */
|
|
|
|
|
ptr = strtok(src, ":");
|
|
|
|
|
|
|
|
|
|
if(strlen(ptr) > INET_ADDRSTRLEN) {
|
|
|
|
|
fprintf(stderr, "ip v4 address is too long!\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
strncpy(ip, ptr, strlen(ptr)+1);
|
|
|
|
|
ptr = strtok(NULL, ":");
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
fprintf(stderr, "Invalid ip/port specification!\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2015-04-21 20:09:12 +02:00
|
|
|
|
2015-04-24 22:03:50 +02:00
|
|
|
if(ptr != NULL) {
|
|
|
|
|
/* got a port */
|
|
|
|
|
if(strlen(ptr) > 5) {
|
|
|
|
|
fprintf(stderr, "port is too long!\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if(atoi(ptr) > 65535) {
|
2016-09-22 21:37:30 +02:00
|
|
|
fprintf(stderr, "maximum port number possible: 65535!\n");
|
|
|
|
|
return 1;
|
2015-04-21 20:09:12 +02:00
|
|
|
}
|
2015-04-24 22:03:50 +02:00
|
|
|
strncpy(pt, ptr, strlen(ptr)+1);
|
2015-04-21 20:09:12 +02:00
|
|
|
}
|
2015-04-24 22:03:50 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
fprintf(stderr, "Port is missing!\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
2015-04-21 20:09:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-04-24 22:03:50 +02:00
|
|
|
|
2015-04-27 14:04:57 +02:00
|
|
|
void usage() {
|
|
|
|
|
fprintf(stderr,
|
2016-09-22 21:37:30 +02:00
|
|
|
"Usage: udpxd [-lbdfpvhV]\n\n"
|
|
|
|
|
"Options:\n"
|
|
|
|
|
"--listen -l <ip:port> listen for incoming requests\n"
|
|
|
|
|
"--bind -b <ip> bind ip used for outgoing requests\n"
|
|
|
|
|
"--to -t <ip:port> destination to forward requests to\n"
|
|
|
|
|
"--daemon -d daemon mode, fork into background\n"
|
|
|
|
|
"--pidfile -p <file> pidfile, default: /var/run/udpxd.pid\n"
|
|
|
|
|
"--user -u <user> run as user (only in daemon mode)\n"
|
|
|
|
|
"--chroot -c <path> chroot to <path> (only in daemon mode)\n"
|
|
|
|
|
"--help -h -? print help message\n"
|
|
|
|
|
"--version -V print program version\n"
|
|
|
|
|
"--verbose -v enable verbose logging\n\n"
|
|
|
|
|
"Options -l and -t are mandatory.\n\n"
|
|
|
|
|
"This is udpxd version %s.\n", UDPXD_VERSION
|
|
|
|
|
);
|
2015-04-27 14:04:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-04-24 22:03:50 +02:00
|
|
|
|
2015-04-21 20:09:12 +02:00
|
|
|
int main ( int argc, char* argv[] ) {
|
2015-04-24 22:03:50 +02:00
|
|
|
int opt, err;
|
2015-04-21 20:09:12 +02:00
|
|
|
char *inip, *inpt, *srcip, *dstip, *dstpt;
|
2015-04-26 13:26:37 +02:00
|
|
|
char pidfile[MAX_BUFFER_SIZE];
|
2015-04-27 14:04:57 +02:00
|
|
|
char user[128];
|
|
|
|
|
char chroot[MAX_BUFFER_SIZE];
|
2015-04-26 13:26:37 +02:00
|
|
|
|
2015-04-24 22:03:50 +02:00
|
|
|
err = 0;
|
2015-04-21 20:09:12 +02:00
|
|
|
|
|
|
|
|
static struct option longopts[] = {
|
|
|
|
|
{ "listen", required_argument, NULL, 'l' },
|
|
|
|
|
{ "bind", required_argument, NULL, 'b' },
|
2015-04-27 14:04:57 +02:00
|
|
|
{ "to", required_argument, NULL, 't' },
|
|
|
|
|
{ "version", no_argument, NULL, 'V' },
|
2015-04-21 20:09:12 +02:00
|
|
|
{ "help", no_argument, NULL, 'h' },
|
2015-04-27 14:04:57 +02:00
|
|
|
{ "verbose", no_argument, NULL, 'v' },
|
|
|
|
|
{ "daemon", no_argument, NULL, 'd' },
|
2015-04-26 13:26:37 +02:00
|
|
|
{ "pidfile", required_argument, NULL, 'p' },
|
2015-04-27 14:04:57 +02:00
|
|
|
{ "user", required_argument, NULL, 'u' },
|
|
|
|
|
{ "chroot", required_argument, NULL, 'c' },
|
2015-04-21 20:09:12 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if( argc < 2 ) {
|
|
|
|
|
usage();
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
srcip = dstip = inip = dstpt = inpt = NULL;
|
2015-04-27 14:04:57 +02:00
|
|
|
|
|
|
|
|
/* set defaults */
|
2015-04-26 13:26:37 +02:00
|
|
|
strncpy(pidfile, "/var/run/udpxd.pid", 19);
|
2015-04-27 14:04:57 +02:00
|
|
|
strncpy(user, "nobody", 7);
|
|
|
|
|
strncpy(chroot, "/var/empty", 11);
|
2015-04-24 22:03:50 +02:00
|
|
|
|
2015-04-27 14:04:57 +02:00
|
|
|
while ((opt = getopt_long(argc, argv, "l:b:t:u:c:vdVh?", longopts, NULL)) != -1) {
|
2015-04-21 20:09:12 +02:00
|
|
|
switch (opt) {
|
2015-04-27 14:04:57 +02:00
|
|
|
case 'V':
|
2015-04-21 20:09:12 +02:00
|
|
|
fprintf(stderr, "This is %s version %s\n", argv[0], UDPXD_VERSION);
|
|
|
|
|
return 1;
|
|
|
|
|
break;
|
2015-04-27 14:04:57 +02:00
|
|
|
case 'd':
|
|
|
|
|
FORKED = 1;
|
2015-04-26 13:26:37 +02:00
|
|
|
break;
|
2015-04-21 20:09:12 +02:00
|
|
|
case 'h':
|
|
|
|
|
case '?':
|
|
|
|
|
usage();
|
|
|
|
|
return 1;
|
|
|
|
|
break;
|
2015-04-27 14:04:57 +02:00
|
|
|
case 'v':
|
2015-04-21 20:09:12 +02:00
|
|
|
VERBOSE = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'l':
|
2015-04-24 22:03:50 +02:00
|
|
|
inip = malloc(INET6_ADDRSTRLEN+1);
|
|
|
|
|
inpt = malloc(6);
|
|
|
|
|
if (parse_ip(optarg, inip, inpt) != 0) {
|
2016-09-22 21:37:30 +02:00
|
|
|
fprintf(stderr, "Parameter -l has the format <ip-address:port>!\n");
|
|
|
|
|
err = 1;
|
2015-04-21 20:09:12 +02:00
|
|
|
}
|
|
|
|
|
break;
|
2015-04-27 14:04:57 +02:00
|
|
|
case 't':
|
2015-04-24 22:03:50 +02:00
|
|
|
dstip = malloc(INET6_ADDRSTRLEN+1);
|
|
|
|
|
dstpt = malloc(6);
|
|
|
|
|
if (parse_ip(optarg, dstip, dstpt) != 0) {
|
2016-09-22 21:37:30 +02:00
|
|
|
fprintf(stderr, "Parameter -d has the format <ip-address:port>!\n");
|
|
|
|
|
err = 1;
|
2015-04-21 20:09:12 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'b':
|
2015-04-24 22:03:50 +02:00
|
|
|
if(strlen(optarg) > INET6_ADDRSTRLEN) {
|
2016-09-22 21:37:30 +02:00
|
|
|
fprintf(stderr, "Bind ip address is too long!\n");
|
|
|
|
|
err = 1;
|
2015-04-24 22:03:50 +02:00
|
|
|
}
|
|
|
|
|
srcip = malloc(INET6_ADDRSTRLEN+1);
|
2015-04-21 20:09:12 +02:00
|
|
|
strncpy(srcip, optarg, strlen(optarg));
|
|
|
|
|
break;
|
2015-04-26 13:26:37 +02:00
|
|
|
case 'p':
|
|
|
|
|
strncpy(pidfile, optarg, strlen(optarg));
|
|
|
|
|
break;
|
2015-04-27 14:04:57 +02:00
|
|
|
case 'u':
|
|
|
|
|
strncpy(user, optarg, strlen(optarg));
|
|
|
|
|
break;
|
|
|
|
|
case 'c':
|
|
|
|
|
strncpy(chroot, optarg, strlen(optarg));
|
|
|
|
|
break;
|
2015-04-21 20:09:12 +02:00
|
|
|
default:
|
|
|
|
|
usage();
|
|
|
|
|
return 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(inip == NULL) {
|
|
|
|
|
fprintf(stderr, "-l parameter is required!\n");
|
|
|
|
|
usage();
|
2015-04-24 22:03:50 +02:00
|
|
|
err = 1;
|
2015-04-21 20:09:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(dstip == NULL) {
|
2015-04-27 14:04:57 +02:00
|
|
|
fprintf(stderr, "-t parameter is required!\n");
|
2015-04-21 20:09:12 +02:00
|
|
|
usage();
|
2015-04-24 22:03:50 +02:00
|
|
|
err = 1;
|
2015-04-21 20:09:12 +02:00
|
|
|
}
|
|
|
|
|
|
2017-04-12 19:31:15 +03:00
|
|
|
if(srcip != NULL && dstip != NULL) {
|
2015-04-26 13:26:37 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-24 22:03:50 +02:00
|
|
|
if(! err) {
|
2015-04-27 14:04:57 +02:00
|
|
|
err = start_listener (inip, inpt, srcip, dstip, dstpt, pidfile, chroot, user);
|
2015-04-21 20:09:12 +02:00
|
|
|
}
|
|
|
|
|
|
2015-04-24 22:03:50 +02:00
|
|
|
if(srcip != NULL)
|
|
|
|
|
free(srcip);
|
|
|
|
|
if(dstip != NULL)
|
|
|
|
|
free(dstip);
|
|
|
|
|
if(inip != NULL)
|
|
|
|
|
free(inip);
|
|
|
|
|
if(inpt != NULL)
|
|
|
|
|
free(inpt);
|
|
|
|
|
if(dstpt != NULL)
|
|
|
|
|
free(dstpt);
|
|
|
|
|
|
|
|
|
|
return err;
|
2015-04-21 20:09:12 +02:00
|
|
|
}
|