From: Guus Sliepen Date: Fri, 12 Nov 2010 15:15:29 +0000 (+0100) Subject: Merge branch 'master' into 1.1 X-Git-Tag: release-1.1pre1~69 X-Git-Url: https://www.tinc-vpn.org/git/browse?p=tinc;a=commitdiff_plain;h=a22041922f160667573e9a5ae3f4195e1668906a Merge branch 'master' into 1.1 Conflicts: doc/tincd.8.in lib/pidfile.c src/graph.c src/net.c src/net.h src/net_packet.c src/net_setup.c src/net_socket.c src/netutl.c src/node.c src/node.h src/protocol_auth.c src/protocol_key.c src/tincd.c --- a22041922f160667573e9a5ae3f4195e1668906a diff --cc have.h index 89454feb,923e76ab..21c16efa --- a/have.h +++ b/have.h @@@ -21,6 -21,14 +21,15 @@@ #ifndef __TINC_HAVE_H__ #define __TINC_HAVE_H__ + #ifdef HAVE_MINGW + #ifdef WITH_WINDOWS2000 + #define WINVER Windows2000 + #else + #define WINVER WindowsXP + #endif ++#define WIN32_LEAN_AND_MEAN + #endif + #include #include #include diff --cc src/conf.c index d5bc9165,07279531..faff003b --- a/src/conf.c +++ b/src/conf.c @@@ -22,7 -23,8 +23,8 @@@ #include "system.h" -#include "avl_tree.h" +#include "splay_tree.h" + #include "connection.h" #include "conf.h" #include "logger.h" #include "netutl.h" /* for str2address */ @@@ -50,15 -59,15 +59,15 @@@ static int config_compare(const config_ if(result) return result; else - return strcmp(a->file, b->file); + return a->file ? strcmp(a->file, b->file) : 0; } -void init_configuration(avl_tree_t ** config_tree) { - *config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config); +void init_configuration(splay_tree_t ** config_tree) { + *config_tree = splay_alloc_tree((splay_compare_t) config_compare, (splay_action_t) free_config); } -void exit_configuration(avl_tree_t ** config_tree) { - avl_delete_tree(*config_tree); +void exit_configuration(splay_tree_t ** config_tree) { + splay_delete_tree(*config_tree); *config_tree = NULL; } @@@ -87,10 -96,10 +96,10 @@@ config_t *lookup_config(splay_tree_t *c config_t cfg, *found; cfg.variable = variable; - cfg.file = ""; + cfg.file = NULL; cfg.line = 0; - found = avl_search_closest_greater(config_tree, &cfg); + found = splay_search_closest_greater(config_tree, &cfg); if(!found) return NULL; @@@ -237,7 -285,7 +285,7 @@@ config_t *parse_config_line(char *line Parse a configuration file and put the results in the configuration tree starting at *base. */ - int read_config_file(splay_tree_t *config_tree, const char *fname) { -bool read_config_file(avl_tree_t *config_tree, const char *fname) { ++bool read_config_file(splay_tree_t *config_tree, const char *fname) { FILE *fp; char buffer[MAX_STRING_SIZE]; char *line; @@@ -316,6 -337,26 +337,26 @@@ return result; } -void read_config_options(avl_tree_t *config_tree, const char *prefix) { ++void read_config_options(splay_tree_t *config_tree, const char *prefix) { + list_node_t *node, *next; + size_t prefix_len = prefix ? strlen(prefix) : 0; + + for(node = cmdline_conf->tail; node; node = next) { + config_t *cfg = (config_t *)node->data; + next = node->prev; + + if(!prefix && strchr(cfg->variable, '.')) + continue; + + if(prefix && (strncmp(prefix, cfg->variable, prefix_len) || cfg->variable[prefix_len] != '.')) + continue; + + config_add(config_tree, cfg); + node->data = NULL; + list_unlink_node(cmdline_conf, node); + } + } + bool read_server_config() { char *fname; bool x; @@@ -332,6 -375,79 +375,19 @@@ return x; } + bool read_connection_config(connection_t *c) { + char *fname; + bool x; + + read_config_options(c->config_tree, c->name); + + xasprintf(&fname, "%s/hosts/%s", confbase, c->name); + x = read_config_file(c->config_tree, fname); + free(fname); + + return x; + } + -FILE *ask_and_open(const char *filename, const char *what) { - FILE *r; - char *directory; - char line[PATH_MAX]; - const char *fn; - - /* Check stdin and stdout */ - if(!isatty(0) || !isatty(1)) { - /* Argh, they are running us from a script or something. Write - the files to the current directory and let them burn in hell - for ever. */ - fn = filename; - } else { - /* Ask for a file and/or directory name. */ - fprintf(stdout, "Please enter a file to save %s to [%s]: ", - what, filename); - fflush(stdout); - - fn = readline(stdin, line, sizeof line); - - if(!fn) { - fprintf(stderr, "Error while reading stdin: %s\n", - strerror(errno)); - return NULL; - } - - if(!strlen(fn)) - /* User just pressed enter. */ - fn = filename; - } - -#ifdef HAVE_MINGW - if(fn[0] != '\\' && fn[0] != '/' && !strchr(fn, ':')) { -#else - if(fn[0] != '/') { -#endif - /* The directory is a relative path or a filename. */ - char *p; - - directory = get_current_dir_name(); - xasprintf(&p, "%s/%s", directory, fn); - free(directory); - fn = p; - } - - umask(0077); /* Disallow everything for group and other */ - - /* Open it first to keep the inode busy */ - - r = fopen(fn, "r+") ?: fopen(fn, "w+"); - - if(!r) { - fprintf(stderr, "Error opening file `%s': %s\n", - fn, strerror(errno)); - return NULL; - } - - return r; -} - bool disable_old_keys(FILE *f) { char buf[100]; long pos; diff --cc src/conf.h index be70c24c,3eae4ad7..cc57e82b --- a/src/conf.h +++ b/src/conf.h @@@ -21,7 -21,8 +21,8 @@@ #ifndef __TINC_CONF_H__ #define __TINC_CONF_H__ -#include "avl_tree.h" +#include "splay_tree.h" + #include "list.h" typedef struct config_t { char *variable; @@@ -40,23 -41,27 +41,27 @@@ extern int maxtimeout extern bool bypass_security; extern char *confbase; extern char *netname; + extern list_t *cmdline_conf; -extern void init_configuration(avl_tree_t **); -extern void exit_configuration(avl_tree_t **); +extern void init_configuration(splay_tree_t **); +extern void exit_configuration(splay_tree_t **); extern config_t *new_config(void) __attribute__ ((__malloc__)); extern void free_config(config_t *); -extern void config_add(avl_tree_t *, config_t *); -extern config_t *lookup_config(avl_tree_t *, char *); -extern config_t *lookup_config_next(avl_tree_t *, const config_t *); +extern void config_add(splay_tree_t *, config_t *); +extern config_t *lookup_config(splay_tree_t *, char *); +extern config_t *lookup_config_next(splay_tree_t *, const config_t *); extern bool get_config_bool(const config_t *, bool *); extern bool get_config_int(const config_t *, int *); extern bool get_config_string(const config_t *, char **); extern bool get_config_address(const config_t *, struct addrinfo **); extern bool get_config_subnet(const config_t *, struct subnet_t **); - extern int read_config_file(splay_tree_t *, const char *); + extern config_t *parse_config_line(char *, const char *, int); -extern bool read_config_file(avl_tree_t *, const char *); -extern void read_config_options(avl_tree_t *, const char *); ++extern bool read_config_file(splay_tree_t *, const char *); ++extern void read_config_options(splay_tree_t *, const char *); extern bool read_server_config(void); + extern bool read_connection_config(struct connection_t *); -extern FILE *ask_and_open(const char *, const char *); +extern FILE *ask_and_open(const char *, const char *, const char *); extern bool is_safe_path(const char *); extern bool disable_old_keys(FILE *); diff --cc src/connection.c index 18c03c7e,ac946abe..fecb48d4 --- a/src/connection.c +++ b/src/connection.c @@@ -89,31 -109,21 +89,20 @@@ void connection_add(connection_t *c) } void connection_del(connection_t *c) { - avl_delete(connection_tree, c); + splay_delete(connection_tree, c); } -void dump_connections(void) { - avl_node_t *node; +bool dump_connections(connection_t *cdump) { + splay_node_t *node; connection_t *c; - logger(LOG_DEBUG, "Connections:"); - for(node = connection_tree->head; node; node = node->next) { c = node->data; - logger(LOG_DEBUG, " %s at %s options %x socket %d status %04x outbuf %d/%d/%d", - c->name, c->hostname, c->options, c->socket, bitfield_to_int(&c->status, sizeof c->status), - c->outbufsize, c->outbufstart, c->outbuflen); + send_request(cdump, "%d %d %s at %s options %x socket %d status %04x", + CONTROL, REQ_DUMP_CONNECTIONS, + c->name, c->hostname, c->options, c->socket, + bitfield_to_int(&c->status, sizeof c->status)); } - logger(LOG_DEBUG, "End of connections."); + return send_request(cdump, "%d %d", CONTROL, REQ_DUMP_CONNECTIONS); } - - bool read_connection_config(connection_t *c) { - char *fname; - bool x; - - xasprintf(&fname, "%s/hosts/%s", confbase, c->name); - x = read_config_file(c->config_tree, fname); - free(fname); - - return x; - } diff --cc src/connection.h index 0f2b1d6a,05e8b4ba..0fc49ef3 --- a/src/connection.h +++ b/src/connection.h @@@ -99,7 -110,6 +99,6 @@@ extern connection_t *new_connection(voi extern void free_connection(connection_t *); extern void connection_add(connection_t *); extern void connection_del(connection_t *); -extern void dump_connections(void); +extern bool dump_connections(struct connection_t *); - extern bool read_connection_config(connection_t *); #endif /* __TINC_CONNECTION_H__ */ diff --cc src/logger.c index 35a6a38a,bc20438c..4c0d2312 --- a/src/logger.c +++ b/src/logger.c @@@ -85,8 -85,8 +85,8 @@@ void logger(int priority, const char *f #ifdef HAVE_MINGW { char message[4096]; - char *messages[] = {message}; + const char *messages[] = {message}; - vsnprintf(message, sizeof(message), format, ap); + vsnprintf(message, sizeof message, format, ap); ReportEvent(loghandle, priority, 0, 0, NULL, 1, 0, messages, NULL); } #else diff --cc src/net.c index 0e582364,08e3cad3..7d44d17c --- a/src/net.c +++ b/src/net.c @@@ -36,10 -39,18 +36,13 @@@ #include "subnet.h" #include "xalloc.h" -bool do_purge = false; -volatile bool running = false; - -time_t now = 0; + int contradicting_add_edge = 0; + int contradicting_del_edge = 0; + /* Purge edges and subnets of unreachable nodes. Use carefully. */ -static void purge(void) { - avl_node_t *nnode, *nnext, *enode, *enext, *snode, *snext; +void purge(void) { + splay_node_t *nnode, *nnext, *enode, *enext, *snode, *snext; node_t *n; edge_t *e; subnet_t *s; @@@ -187,30 -257,82 +190,43 @@@ static void timeout_handler(int fd, sho } } } - - if(c->outbuflen > 0 && c->last_flushed_time + pingtimeout < now) { - if(c->status.active) { - ifdebug(CONNECTIONS) logger(LOG_INFO, - "%s (%s) could not flush for %ld seconds (%d bytes remaining)", - c->name, c->hostname, now - c->last_flushed_time, c->outbuflen); - c->status.timeout = true; - terminate_connection(c, true); - } - } - } -} - -/* - check all connections to see if anything - happened on their sockets -*/ -static void check_network_activity(fd_set * readset, fd_set * writeset) { - connection_t *c; - avl_node_t *node; - int result, i; - socklen_t len = sizeof(result); - vpn_packet_t packet; - static int errors = 0; - - /* check input from kernel */ - if(device_fd >= 0 && FD_ISSET(device_fd, readset)) { - if(read_packet(&packet)) { - errors = 0; - packet.priority = 0; - route(myself, &packet); - } else { - usleep(errors * 50000); - errors++; - if(errors > 10) { - logger(LOG_ERR, "Too many errors from %s, exiting!", device); - running = false; - } - } } - /* check meta connections */ - for(node = connection_tree->head; node; node = node->next) { - c = node->data; ++ if(contradicting_del_edge && contradicting_add_edge) { ++ logger(LOG_WARNING, "Possible node with same Name as us!"); + - if(c->status.remove) - continue; - - if(FD_ISSET(c->socket, readset)) { - if(c->status.connecting) { - c->status.connecting = false; - getsockopt(c->socket, SOL_SOCKET, SO_ERROR, (void *)&result, &len); ++ if(rand() % 3 == 0) { ++ logger(LOG_ERR, "Shutting down, check configuration of all nodes for duplicate Names!"); ++ event_loopexit(NULL); ++ return; ++ } + - if(!result) - finish_connecting(c); - else { - ifdebug(CONNECTIONS) logger(LOG_DEBUG, - "Error while connecting to %s (%s): %s", - c->name, c->hostname, sockstrerror(result)); - closesocket(c->socket); - do_outgoing_connection(c); - continue; - } - } ++ contradicting_add_edge = 0; ++ contradicting_del_edge = 0; ++ } + - if(!receive_meta(c)) { - terminate_connection(c, c->status.active); - continue; - } - } + event_add(event, &(struct timeval){pingtimeout, 0}); +} - if(FD_ISSET(c->socket, writeset)) { - if(!flush_meta(c)) { - terminate_connection(c, c->status.active); - continue; - } +void handle_meta_connection_data(int fd, short events, void *data) { + connection_t *c = data; + int result; + socklen_t len = sizeof result; + + if(c->status.connecting) { + c->status.connecting = false; + + getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &result, &len); + + if(!result) + finish_connecting(c); + else { + ifdebug(CONNECTIONS) logger(LOG_DEBUG, + "Error while connecting to %s (%s): %s", + c->name, c->hostname, sockstrerror(result)); + closesocket(c->socket); + do_outgoing_connection(c); + return; } } @@@ -220,145 -345,216 +236,146 @@@ } } -/* - this is where it all happens... -*/ -int main_loop(void) { - fd_set readset, writeset; - struct timeval tv; - int r, maxfd; - time_t last_ping_check, last_config_check, last_graph_dump; - event_t *event; - - last_ping_check = now; - last_config_check = now; - last_graph_dump = now; - - srand(now); - - running = true; +static void sigterm_handler(int signal, short events, void *data) { + logger(LOG_NOTICE, "Got %s signal", strsignal(signal)); + event_loopexit(NULL); +} - while(running) { - now = time(NULL); +static void sighup_handler(int signal, short events, void *data) { + logger(LOG_NOTICE, "Got %s signal", strsignal(signal)); + reload_configuration(); +} - // tv.tv_sec = 1 + (rand() & 7); /* Approx. 5 seconds, randomized to prevent global synchronisation effects */ - tv.tv_sec = 1; - tv.tv_usec = 0; +int reload_configuration(void) { + connection_t *c; + splay_node_t *node, *next; + char *fname; + struct stat s; + static time_t last_config_check = 0; - maxfd = build_fdset(&readset, &writeset); + /* Reread our own configuration file */ -#ifdef HAVE_MINGW - LeaveCriticalSection(&mutex); -#endif - r = select(maxfd + 1, &readset, &writeset, NULL, &tv); -#ifdef HAVE_MINGW - EnterCriticalSection(&mutex); -#endif + exit_configuration(&config_tree); + init_configuration(&config_tree); - if(r < 0) { - if(!sockwouldblock(sockerrno)) { - logger(LOG_ERR, "Error while waiting for input: %s", sockstrerror(sockerrno)); - dump_connections(); - return 1; - } - } - - if(r > 0) - check_network_activity(&readset, &writeset); + if(!read_server_config()) { + logger(LOG_ERR, "Unable to reread configuration file, exitting."); + event_loopexit(NULL); + return EINVAL; + } - if(do_purge) { - purge(); - do_purge = false; + /* Close connections to hosts that have a changed or deleted host config file */ + + for(node = connection_tree->head; node; node = next) { + c = node->data; + next = node->next; + + if(c->outgoing) { + free(c->outgoing->name); + if(c->outgoing->ai) + freeaddrinfo(c->outgoing->ai); + free(c->outgoing); + c->outgoing = NULL; } + + xasprintf(&fname, "%s/hosts/%s", confbase, c->name); + if(stat(fname, &s) || s.st_mtime > last_config_check) + terminate_connection(c, c->status.active); + free(fname); + } - /* Let's check if everybody is still alive */ - - if(last_ping_check + pingtimeout < now) { - check_dead_connections(); - last_ping_check = now; - - if(routing_mode == RMODE_SWITCH) - age_subnets(); - - age_past_requests(); - - /* Should we regenerate our key? */ - - if(keyexpires < now) { - avl_node_t *node; - node_t *n; + last_config_check = time(NULL); - ifdebug(STATUS) logger(LOG_INFO, "Expiring symmetric keys"); + /* If StrictSubnet is set, expire deleted Subnets and read new ones in */ - for(node = node_tree->head; node; node = node->next) { - n = node->data; - if(n->inkey) { - free(n->inkey); - n->inkey = NULL; - } - } + if(strictsubnets) { + subnet_t *subnet; - send_key_changed(broadcast, myself); - keyexpires = now + keylifetime; - } + - if(contradicting_del_edge && contradicting_add_edge) { - logger(LOG_WARNING, "Possible node with same Name as us!"); - - if(rand() % 3 == 0) { - logger(LOG_ERR, "Shutting down, check configuration of all nodes for duplicate Names!"); - running = false; - break; - } - - contradicting_add_edge = 0; - contradicting_del_edge = 0; - } + for(node = subnet_tree->head; node; node = node->next) { + subnet = node->data; + subnet->expires = 1; } - if(sigalrm) { - avl_node_t *node; - logger(LOG_INFO, "Flushing event queue"); - expire_events(); - for(node = connection_tree->head; node; node = node->next) { - connection_t *c = node->data; - send_ping(c); + load_all_subnets(); + + for(node = subnet_tree->head; node; node = next) { + next = node->next; + subnet = node->data; + if(subnet->expires == 1) { + send_del_subnet(broadcast, subnet); + if(subnet->owner->status.reachable) + subnet_update(subnet->owner, subnet, false); + subnet_del(subnet->owner, subnet); + } else if(subnet->expires == -1) { + subnet->expires = 0; + } else { + send_add_subnet(broadcast, subnet); + if(subnet->owner->status.reachable) + subnet_update(subnet->owner, subnet, true); } - sigalrm = false; - } - - while((event = get_expired_event())) { - event->handler(event->data); - free_event(event); } + } - if(sighup) { - connection_t *c; - avl_node_t *node, *next; - char *fname; - struct stat s; - - sighup = false; - - /* Reread our own configuration file */ - - exit_configuration(&config_tree); - init_configuration(&config_tree); - - if(!read_server_config()) { - logger(LOG_ERR, "Unable to reread configuration file, exitting."); - return 1; - } - - /* Cancel non-active outgoing connections */ - - for(node = connection_tree->head; node; node = next) { - next = node->next; - c = node->data; - - c->outgoing = NULL; - - if(c->status.connecting) { - terminate_connection(c, false); - connection_del(c); - } - } - - /* Wipe list of outgoing connections */ - - for(list_node_t *node = outgoing_list->head; node; node = node->next) { - outgoing_t *outgoing = node->data; - - if(outgoing->event) - event_del(outgoing->event); - } - - list_delete_list(outgoing_list); - - /* Close connections to hosts that have a changed or deleted host config file */ - - for(node = connection_tree->head; node; node = node->next) { - c = node->data; - - xasprintf(&fname, "%s/hosts/%s", confbase, c->name); - if(stat(fname, &s) || s.st_mtime > last_config_check) - terminate_connection(c, c->status.active); - free(fname); - } + /* Try to make outgoing connections */ + + try_outgoing_connections(); - last_config_check = now; + return 0; +} - /* If StrictSubnet is set, expire deleted Subnets and read new ones in */ +void retry(void) { + connection_t *c; + splay_node_t *node; - if(strictsubnets) { - subnet_t *subnet; + for(node = connection_tree->head; node; node = node->next) { + c = node->data; + + if(c->outgoing && !c->node) { + if(timeout_initialized(&c->outgoing->ev)) + event_del(&c->outgoing->ev); + if(c->status.connecting) + close(c->socket); + c->outgoing->timeout = 0; + do_outgoing_connection(c); + } + } +} - for(node = subnet_tree->head; node; node = node->next) { - subnet = node->data; - subnet->expires = 1; - } +/* + this is where it all happens... +*/ +int main_loop(void) { + struct event timeout_event; + struct event sighup_event; + struct event sigterm_event; + struct event sigquit_event; - load_all_subnets(); - - for(node = subnet_tree->head; node; node = next) { - next = node->next; - subnet = node->data; - if(subnet->expires == 1) { - send_del_subnet(broadcast, subnet); - if(subnet->owner->status.reachable) - subnet_update(subnet->owner, subnet, false); - subnet_del(subnet->owner, subnet); - } else if(subnet->expires == -1) { - subnet->expires = 0; - } else { - send_add_subnet(broadcast, subnet); - if(subnet->owner->status.reachable) - subnet_update(subnet->owner, subnet, true); - } - } - } + timeout_set(&timeout_event, timeout_handler, &timeout_event); + event_add(&timeout_event, &(struct timeval){pingtimeout, 0}); - /* Try to make outgoing connections */ - - try_outgoing_connections(); - } - - /* Dump graph if wanted every 60 seconds*/ +#ifdef SIGHUP + signal_set(&sighup_event, SIGHUP, sighup_handler, NULL); + signal_add(&sighup_event, NULL); +#endif +#ifdef SIGTERM + signal_set(&sigterm_event, SIGTERM, sigterm_handler, NULL); + signal_add(&sigterm_event, NULL); +#endif +#ifdef SIGQUIT + signal_set(&sigquit_event, SIGQUIT, sigterm_handler, NULL); + signal_add(&sigquit_event, NULL); +#endif - if(last_graph_dump + 60 < now) { - dump_graph(); - last_graph_dump = now; - } + if(event_loop(0) < 0) { + logger(LOG_ERR, "Error while waiting for input: %s", strerror(errno)); + return 1; } + signal_del(&sighup_event); + signal_del(&sigterm_event); + signal_del(&sigquit_event); + event_del(&timeout_event); + return 0; } diff --cc src/net.h index cd97e301,eae979cd..f53c27a4 --- a/src/net.h +++ b/src/net.h @@@ -111,9 -109,14 +111,11 @@@ extern int addressfamily extern listen_socket_t listen_socket[MAXSOCKETS]; extern int listen_sockets; -extern int keyexpires; extern int keylifetime; extern bool do_prune; -extern bool do_purge; extern char *myport; -extern time_t now; + extern int contradicting_add_edge; + extern int contradicting_del_edge; /* Yes, very strange placement indeed, but otherwise the typedefs get all tangled up */ #include "connection.h" diff --cc src/net_packet.c index 46d4e1a0,44ab55d4..b444bc93 --- a/src/net_packet.c +++ b/src/net_packet.c @@@ -355,8 -365,10 +356,10 @@@ static void send_udppacket(node_t *n, v int nextpkt = 0; vpn_packet_t *outpkt; int origlen; - int outlen, outpad; + size_t outlen; + #if defined(SOL_IP) && defined(IP_TOS) static int priority = 0; + #endif int origpriority; int sock; diff --cc src/net_setup.c index 198da3df,f4e56378..9c188957 --- a/src/net_setup.c +++ b/src/net_setup.c @@@ -71,32 -107,59 +71,32 @@@ bool read_rsa_public_key(connection_t * return false; } - /* Else, check if a harnessed public key is in the config file */ - - xasprintf(&fname, "%s/hosts/%s", confbase, c->name); - fp = fopen(fname, "r"); - - if(fp) { - c->rsa_key = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL); - fclose(fp); - } - - free(fname); - - if(c->rsa_key) - return true; - - /* Try again with PEM_read_RSA_PUBKEY. */ - - xasprintf(&fname, "%s/hosts/%s", confbase, c->name); - fp = fopen(fname, "r"); - - if(fp) { - c->rsa_key = PEM_read_RSA_PUBKEY(fp, &c->rsa_key, NULL, NULL); -// RSA_blinding_on(c->rsa_key, NULL); - fclose(fp); - } + result = rsa_read_pem_public_key(&c->rsa, fp); + fclose(fp); + if(!result) + logger(LOG_ERR, "Reading RSA public key file `%s' failed: %s", fname, strerror(errno)); free(fname); - - if(c->rsa_key) - return true; - - logger(LOG_ERR, "No public key for %s specified!", c->name); - - return false; + return result; } -bool read_rsa_private_key(void) { +bool read_rsa_private_key() { FILE *fp; - char *fname, *key, *pubkey; - struct stat s; + char *fname; + char *n, *d; + bool result; - if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key)) { - if(!get_config_string(lookup_config(config_tree, "PublicKey"), &pubkey)) { + /* First, check for simple PrivateKey statement */ + + if(get_config_string(lookup_config(config_tree, "PrivateKey"), &d)) { - if(!get_config_string(lookup_config(myself->connection->config_tree, "PublicKey"), &n)) { ++ if(!get_config_string(lookup_config(config_tree, "PublicKey"), &n)) { logger(LOG_ERR, "PrivateKey used but no PublicKey found!"); + free(d); return false; } - myself->connection->rsa_key = RSA_new(); -// RSA_blinding_on(myself->connection->rsa_key, NULL); - BN_hex2bn(&myself->connection->rsa_key->d, key); - BN_hex2bn(&myself->connection->rsa_key->n, pubkey); - BN_hex2bn(&myself->connection->rsa_key->e, "FFFF"); - free(key); - free(pubkey); + result = rsa_set_hex_private_key(&myself->connection->rsa, n, "FFFF", d); + free(n); + free(d); return true; } @@@ -386,36 -423,65 +376,36 @@@ bool setup_myself(void) /* Generate packet encryption key */ - if(!get_config_string(lookup_config(myself->connection->config_tree, "Cipher"), &cipher)) - if(get_config_string - (lookup_config(config_tree, "Cipher"), &cipher)) { - if(!strcasecmp(cipher, "none")) { - myself->incipher = NULL; - } else { - myself->incipher = EVP_get_cipherbyname(cipher); ++ if(!get_config_string(lookup_config(config_tree, "Cipher"), &cipher)) + cipher = xstrdup("blowfish"); - if(!myself->incipher) { - logger(LOG_ERR, "Unrecognized cipher type!"); - return false; - } - } - } else - myself->incipher = EVP_bf_cbc(); - - if(myself->incipher) - myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len; - else - myself->inkeylength = 1; - - myself->connection->outcipher = EVP_bf_ofb(); + if(!cipher_open_by_name(&myself->incipher, cipher)) { + logger(LOG_ERR, "Unrecognized cipher type!"); + return false; + } if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime)) keylifetime = 3600; - keyexpires = now + keylifetime; - + regenerate_key(); + /* Check if we want to use message authentication codes... */ - if(get_config_string(lookup_config(config_tree, "Digest"), &digest)) { - if(!strcasecmp(digest, "none")) { - myself->indigest = NULL; - } else { - myself->indigest = EVP_get_digestbyname(digest); + if(!get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest)) + digest = xstrdup("sha1"); - if(!myself->indigest) { - logger(LOG_ERR, "Unrecognized digest type!"); - return false; - } - } - } else - myself->indigest = EVP_sha1(); - - myself->connection->outdigest = EVP_sha1(); - - if(get_config_int(lookup_config(config_tree, "MACLength"), &myself->inmaclength)) { - if(myself->indigest) { - if(myself->inmaclength > myself->indigest->md_size) { - logger(LOG_ERR, "MAC length exceeds size of digest!"); - return false; - } else if(myself->inmaclength < 0) { - logger(LOG_ERR, "Bogus MAC length!"); - return false; - } - } - } else - myself->inmaclength = 4; + int maclength = 4; - get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &maclength); ++ get_config_int(lookup_config(config_tree, "MACLength"), &maclength); + + if(maclength < 0) { + logger(LOG_ERR, "Bogus MAC length!"); + return false; + } - myself->connection->outmaclength = 0; + if(!digest_open_by_name(&myself->indigest, digest, maclength)) { + logger(LOG_ERR, "Unrecognized digest type!"); + return false; + } /* Compression */ diff --cc src/net_socket.c index 4fe65161,762c0a22..44d7f771 --- a/src/net_socket.c +++ b/src/net_socket.c @@@ -69,12 -70,12 +69,12 @@@ static void configure_tcp(connection_t #if defined(SOL_TCP) && defined(TCP_NODELAY) option = 1; - setsockopt(c->socket, SOL_TCP, TCP_NODELAY, &option, sizeof option); - setsockopt(c->socket, SOL_TCP, TCP_NODELAY, (void *)&option, sizeof(option)); ++ setsockopt(c->socket, SOL_TCP, TCP_NODELAY, (void *)&option, sizeof option); #endif #if defined(SOL_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY) option = IPTOS_LOWDELAY; - setsockopt(c->socket, SOL_IP, IP_TOS, &option, sizeof option); - setsockopt(c->socket, SOL_IP, IP_TOS, (void *)&option, sizeof(option)); ++ setsockopt(c->socket, SOL_IP, IP_TOS, (void *)&option, sizeof option); #endif } @@@ -180,7 -181,7 +180,7 @@@ int setup_listen_socket(const sockaddr_ /* Optimize TCP settings */ option = 1; - setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof option); - setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option)); ++ setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof option); #if defined(SOL_IPV6) && defined(IPV6_V6ONLY) if(sa->sa.sa_family == AF_INET6) @@@ -192,10 -193,10 +192,10 @@@ #if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); + memset(&ifr, 0, sizeof ifr); strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ); - if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof ifr)) { - if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr))) { ++ if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof ifr)) { closesocket(nfd); logger(LOG_ERR, "Can't bind to interface %s: %s", iface, strerror(sockerrno)); @@@ -258,7 -259,7 +258,7 @@@ int setup_vpn_in_socket(const sockaddr_ #endif option = 1; - setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof option); - setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option)); ++ setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof option); #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) if(sa->sa.sa_family == AF_INET6) diff --cc src/process.c index 09fd63e1,f2fff1dc..77454f75 --- a/src/process.c +++ b/src/process.c @@@ -37,11 -37,18 +37,13 @@@ bool do_detach = true bool sigalrm = false; extern char *identname; -extern char *pidfilename; extern char **g_argv; extern bool use_logfile; -extern volatile bool running; + #ifndef HAVE_MINGW sigset_t emptysigset; + #endif -static int saved_debug_level = -1; - static void memory_full(int size) { logger(LOG_ERR, "Memory exhausted (couldn't allocate %d bytes), exitting.", size); exit(1); diff --cc src/tincd.c index 21623647,3dab9a01..c4750da2 --- a/src/tincd.c +++ b/src/tincd.c @@@ -119,26 -129,33 +122,31 @@@ static void usage(bool status) program_name); else { printf("Usage: %s [option]...\n\n", program_name); - printf(" -c, --config=DIR Read configuration options from DIR.\n" - " -D, --no-detach Don't fork and detach.\n" - " -d, --debug[=LEVEL] Increase debug level or set it to LEVEL.\n" - " -k, --kill[=SIGNAL] Attempt to kill a running tincd and exit.\n" - " -n, --net=NETNAME Connect to net NETNAME.\n" - " -K, --generate-keys[=BITS] Generate public/private RSA keypair.\n" - " -L, --mlock Lock tinc into main memory.\n" - " --logfile[=FILENAME] Write log entries to a logfile.\n" - " --pidfile=FILENAME Write PID to FILENAME.\n" - " -o [HOST.]KEY=VALUE Set global/host configuration value.\n" - " -R, --chroot chroot to NET dir at startup.\n" - " -U, --user=USER setuid to given USER at startup.\n" - " --help Display this help and exit.\n" - " --version Output version information and exit.\n\n"); + printf( " -c, --config=DIR Read configuration options from DIR.\n" + " -D, --no-detach Don't fork and detach.\n" + " -d, --debug[=LEVEL] Increase debug level or set it to LEVEL.\n" + " -n, --net=NETNAME Connect to net NETNAME.\n" + " -L, --mlock Lock tinc into main memory.\n" + " --logfile[=FILENAME] Write log entries to a logfile.\n" + " --controlcookie=FILENAME Write control socket cookie to FILENAME.\n" + " --bypass-security Disables meta protocol security, for debugging.\n" ++ " -o [HOST.]KEY=VALUE Set global/host configuration value.\n" + " -R, --chroot chroot to NET dir at startup.\n" + " -U, --user=USER setuid to given USER at startup.\n" " --help Display this help and exit.\n" + " --version Output version information and exit.\n\n"); printf("Report bugs to tinc@tinc-vpn.org.\n"); } } static bool parse_options(int argc, char **argv) { + config_t *cfg; int r; int option_index = 0; + int lineno = 0; - while((r = getopt_long(argc, argv, "c:DLd::n:RU:", long_options, &option_index)) != EOF) { + cmdline_conf = list_alloc((list_action_t)free_config); + - while((r = getopt_long(argc, argv, "c:DLd::k::n:o:K::RU:", long_options, &option_index)) != EOF) { ++ while((r = getopt_long(argc, argv, "c:DLd::n:o:RU:", long_options, &option_index)) != EOF) { switch (r) { case 0: /* long option */ break; @@@ -167,10 -184,71 +175,19 @@@ debug_level++; break; - case 'k': /* kill old tincds */ -#ifndef HAVE_MINGW - if(optarg) { - if(!strcasecmp(optarg, "HUP")) - kill_tincd = SIGHUP; - else if(!strcasecmp(optarg, "TERM")) - kill_tincd = SIGTERM; - else if(!strcasecmp(optarg, "KILL")) - kill_tincd = SIGKILL; - else if(!strcasecmp(optarg, "USR1")) - kill_tincd = SIGUSR1; - else if(!strcasecmp(optarg, "USR2")) - kill_tincd = SIGUSR2; - else if(!strcasecmp(optarg, "WINCH")) - kill_tincd = SIGWINCH; - else if(!strcasecmp(optarg, "INT")) - kill_tincd = SIGINT; - else if(!strcasecmp(optarg, "ALRM")) - kill_tincd = SIGALRM; - else { - kill_tincd = atoi(optarg); - - if(!kill_tincd) { - fprintf(stderr, "Invalid argument `%s'; SIGNAL must be a number or one of HUP, TERM, KILL, USR1, USR2, WINCH, INT or ALRM.\n", - optarg); - usage(true); - return false; - } - } - } else - kill_tincd = SIGTERM; -#else - kill_tincd = 1; -#endif - break; - case 'n': /* net name given */ - netname = xstrdup(optarg); + /* netname "." is special: a "top-level name" */ + netname = strcmp(optarg, ".") != 0 ? + xstrdup(optarg) : NULL; + break; + + case 'o': /* option */ + cfg = parse_config_line(optarg, NULL, ++lineno); + if (!cfg) + return false; + list_insert_tail(cmdline_conf, cfg); break; - case 'K': /* generate public/private keypair */ - if(optarg) { - generate_keys = atoi(optarg); - - if(generate_keys < 512) { - fprintf(stderr, "Invalid argument `%s'; BITS must be a number equal to or greater than 512.\n", - optarg); - usage(true); - return false; - } - - generate_keys &= ~7; /* Round it to bytes */ - } else - generate_keys = 2048; - break; - case 'R': /* chroot to NETNAME dir */ do_chroot = true; break;