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