From 35af4051c3749cd2c2137a7eb57171a1fbb12af7 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Tue, 20 Oct 2009 22:14:47 +0200 Subject: [PATCH] Fix a possible crash when sending the HUP signal. When the HUP signal is sent while some outgoing connections have not been made yet, or are being retried, a NULL pointer could be dereferenced resulting in tinc crashing. We fix this by more careful handling of outgoing_ts, and by deleting all connections that have not been fully activated yet at the HUP signal is received. --- src/event.h | 2 +- src/net.c | 27 ++++++++++++++++++++++++++- src/net.h | 1 + src/net_setup.c | 9 ++++++++- src/net_socket.c | 33 +++++++++++++++------------------ 5 files changed, 51 insertions(+), 21 deletions(-) diff --git a/src/event.h b/src/event.h index 345a5f9..da2e741 100644 --- a/src/event.h +++ b/src/event.h @@ -27,7 +27,7 @@ extern avl_tree_t *event_tree; typedef void (*event_handler_t)(void *); -typedef struct { +typedef struct event { time_t time; int id; event_handler_t handler; diff --git a/src/net.c b/src/net.c index 3197036..59dd39b 100644 --- a/src/net.c +++ b/src/net.c @@ -431,7 +431,7 @@ int main_loop(void) { if(sighup) { connection_t *c; - avl_node_t *node; + avl_node_t *node, *next; char *fname; struct stat s; @@ -447,6 +447,31 @@ int main_loop(void) { 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) { diff --git a/src/net.h b/src/net.h index 31438e5..fe4b54b 100644 --- a/src/net.h +++ b/src/net.h @@ -98,6 +98,7 @@ typedef struct outgoing_t { struct config_t *cfg; struct addrinfo *ai; struct addrinfo *aip; + struct event *event; } outgoing_t; extern list_t *outgoing_list; diff --git a/src/net_setup.c b/src/net_setup.c index a08981f..cbf631f 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -541,10 +541,17 @@ void close_network_connections(void) { for(node = connection_tree->head; node; node = next) { next = node->next; c = node->data; - c->outgoing = false; + c->outgoing = NULL; terminate_connection(c, false); } + 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); if(myself && myself->connection) { diff --git a/src/net_socket.c b/src/net_socket.c index 7189025..baf0227 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -306,18 +306,18 @@ int setup_vpn_in_socket(const sockaddr_t *sa) { } /* int setup_vpn_in_socket */ void retry_outgoing(outgoing_t *outgoing) { - event_t *event; - outgoing->timeout += 5; if(outgoing->timeout > maxtimeout) outgoing->timeout = maxtimeout; - event = new_event(); - event->handler = (event_handler_t) setup_outgoing_connection; - event->time = now + outgoing->timeout; - event->data = outgoing; - event_add(event); + if(outgoing->event) + event_del(outgoing->event); + outgoing->event = new_event(); + outgoing->event->handler = (event_handler_t) setup_outgoing_connection; + outgoing->event->time = now + outgoing->timeout; + outgoing->event->data = outgoing; + event_add(outgoing->event); ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Trying to re-establish outgoing connection in %d seconds", @@ -338,6 +338,11 @@ void do_outgoing_connection(connection_t *c) { char *address, *port; int result; + if(!c->outgoing) { + logger(LOG_ERR, "do_outgoing_connection() for %s called without c->outgoing", c->name); + abort(); + } + begin: if(!c->outgoing->ai) { if(!c->outgoing->cfg) { @@ -345,6 +350,7 @@ begin: c->name); c->status.remove = true; retry_outgoing(c->outgoing); + c->outgoing = NULL; return; } @@ -431,6 +437,8 @@ void setup_outgoing_connection(outgoing_t *outgoing) { connection_t *c; node_t *n; + outgoing->event = NULL; + n = lookup_node(outgoing->name); if(n) @@ -525,18 +533,7 @@ void try_outgoing_connections(void) { static config_t *cfg = NULL; char *name; outgoing_t *outgoing; - connection_t *c; - avl_node_t *node; - if(outgoing_list) { - for(node = connection_tree->head; node; node = node->next) { - c = node->data; - c->outgoing = NULL; - } - - list_delete_list(outgoing_list); - } - outgoing_list = list_alloc((list_action_t)free_outgoing); for(cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg)) { -- 2.25.1