congestvpn/main.cpp

134 lines
4 KiB
C++

#include <cstdio>
#include <unistd.h>
#include <arpa/inet.h>
#include <signal.h>
#include <string.h>
#include "UdpVpn.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();
}
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");
signal(SIGINT, stop_sig_handler);
try {
UdpVpn vpn;
vpn_instance = &vpn;
if(program_options.listen) {
vpn.bind(program_options.bind_addr, program_options.bind_port);
}
if(program_options.has_peer) {
if(program_options.server_port == 0) {
fprintf(stderr,
"Initial peer set without a port -- ignoring.\n");
}
else {
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.set_peer(server_addr);
}
}
printf("Starting to listen...\n");
vpn.run();
vpn_instance = nullptr;
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;
}