151 lines
4.7 KiB
C++
151 lines
4.7 KiB
C++
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <arpa/inet.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
|
|
#include "UdpVpn.hpp"
|
|
#include "UdpVpnServer.hpp"
|
|
#include "UdpVpnClient.hpp"
|
|
#include "util.hpp"
|
|
|
|
struct ProgOptions {
|
|
bool listen;
|
|
in6_addr bind_addr;
|
|
in_port_t bind_port;
|
|
|
|
bool has_peer;
|
|
in6_addr server_addr;
|
|
in_port_t server_port;
|
|
};
|
|
|
|
static UdpVpn* vpn_instance = nullptr;
|
|
|
|
void stop_sig_handler(int signal) {
|
|
printf("Received signal %d. Stopping.\n", signal);
|
|
if(vpn_instance != nullptr)
|
|
vpn_instance->stop();
|
|
}
|
|
|
|
void dump_sig_handler(int /*signal*/) {
|
|
vpn_instance->dump_requested();
|
|
}
|
|
|
|
bool parse_options(int argc, char** argv, ProgOptions& opts) {
|
|
int option;
|
|
memset(&opts, 0, sizeof(opts));
|
|
|
|
while((option = getopt(argc, argv, ":d:l:b:s:p:")) >= 0) {
|
|
switch(option) {
|
|
case 'd': // debug
|
|
debug = atoi(optarg);
|
|
break;
|
|
case 'l': // listen, aka "call bind()"
|
|
opts.listen = true;
|
|
opts.bind_port = atoi(optarg);
|
|
break;
|
|
case 'b': // bind to address
|
|
inet_pton(AF_INET6, optarg, &opts.bind_addr);
|
|
break;
|
|
case 's': // server -- initial peer
|
|
opts.has_peer = true;
|
|
inet_pton(AF_INET6, optarg, &opts.server_addr);
|
|
break;
|
|
case 'p': // port -- initial peer address
|
|
opts.server_port = atoi(optarg);
|
|
break;
|
|
case ':':
|
|
fprintf(stderr, "Option %c requires a value.\n", optopt);
|
|
return false;
|
|
default:
|
|
case '?':
|
|
fprintf(stderr, "Unknown option %c.\n", optopt);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
debug = 0;
|
|
ProgOptions program_options;
|
|
parse_options(argc, argv, program_options);
|
|
|
|
printf("==== Options ====\n");
|
|
printf("Debug level: %d\n", debug);
|
|
printf("Bind socket: %d\n", program_options.listen);
|
|
if(program_options.listen) {
|
|
char bind_addr_str[INET6_ADDRSTRLEN];
|
|
inet_ntop(
|
|
AF_INET6, &(program_options.bind_addr),
|
|
bind_addr_str, INET6_ADDRSTRLEN);
|
|
printf("\taddr: %s\n", bind_addr_str);
|
|
printf("\tport: %d\n", program_options.bind_port);
|
|
}
|
|
printf("Start with peer: %d\n", program_options.has_peer);
|
|
if(program_options.has_peer) {
|
|
char peer_addr_str[INET6_ADDRSTRLEN];
|
|
inet_ntop(
|
|
AF_INET6, &(program_options.server_addr),
|
|
peer_addr_str, INET6_ADDRSTRLEN);
|
|
printf("\taddr: %s\n", peer_addr_str);
|
|
printf("\tport: %d\n", program_options.server_port);
|
|
}
|
|
printf("=== END OPTIONS ==\n\n");
|
|
|
|
srand(time(NULL)); // FIXME something more secure if we ever need crypto
|
|
|
|
signal(SIGINT, stop_sig_handler);
|
|
signal(SIGUSR1, dump_sig_handler);
|
|
|
|
try {
|
|
if(program_options.listen && program_options.has_peer) {
|
|
fprintf(stderr,
|
|
"ERROR: Cannot be a server and a client at the same time "
|
|
"-- provide either -l or -s.\n");
|
|
return 1;
|
|
}
|
|
if(program_options.listen) {
|
|
vpn_instance = new UdpVpnServer(
|
|
program_options.bind_addr, program_options.bind_port);
|
|
} else if(program_options.has_peer) {
|
|
if(program_options.server_port == 0) {
|
|
fprintf(stderr,
|
|
"ERROR: A client instance must be given a server port "
|
|
"-- please provide -p.\n");
|
|
return 1;
|
|
}
|
|
|
|
struct sockaddr_in6 server_addr;
|
|
server_addr.sin6_family = AF_INET6; memcpy(&server_addr.sin6_addr, &program_options.server_addr,
|
|
sizeof(server_addr.sin6_addr));
|
|
server_addr.sin6_port = htons(program_options.server_port);
|
|
|
|
vpn_instance = new UdpVpnClient(server_addr);
|
|
} else {
|
|
fprintf(stderr,
|
|
"ERROR: Must be either a server or a client "
|
|
"-- provide either -l or -s.\n");
|
|
return 1;
|
|
}
|
|
|
|
printf("Starting to listen...\n");
|
|
vpn_instance->run();
|
|
|
|
delete vpn_instance;
|
|
|
|
printf("Shutting down.\n");
|
|
} catch(const TunDevice::InitializationError& exn) {
|
|
fprintf(stderr, "TUN INIT ERROR: %s\n", exn.what());
|
|
} catch(const TunDevice::NetError& exn) {
|
|
fprintf(stderr, "TUN NET ERROR: %s\n", exn.what());
|
|
} catch(const UdpVpn::InitializationError& exn) {
|
|
fprintf(stderr, "VPN INIT ERROR: %s\n", exn.what());
|
|
} catch(const UdpVpn::NetError& exn) {
|
|
fprintf(stderr, "VPN NET ERROR: %s\n", exn.what());
|
|
}
|
|
|
|
return 0;
|
|
}
|