congestvpn/main.cpp

152 lines
4.7 KiB
C++

#include <cstdio>
#include <cstdlib>
#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;
}