From 7b2cfb422af6a957aa90e22bd6e9b19f16b30319 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 5 Apr 2012 13:17:02 +0200 Subject: Cleanly shutdown; add on-down command --- src/config.c | 32 +++++++++++++++++++-- src/config.l | 1 + src/config.y | 15 ++++++++-- src/fastd.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- src/fastd.h | 6 +++- src/peer.c | 12 ++++---- src/peer.h | 1 + 7 files changed, 141 insertions(+), 20 deletions(-) diff --git a/src/config.c b/src/config.c index 7725c40..0d9a62b 100644 --- a/src/config.c +++ b/src/config.c @@ -41,10 +41,10 @@ #include -extern fastd_protocol fastd_protocol_null; +extern const fastd_protocol fastd_protocol_null; #ifdef WITH_PROTOCOL_ECFXP -extern fastd_protocol fastd_protocol_ec25519_fhmqvc_xsalsa20_poly1305; +extern const fastd_protocol fastd_protocol_ec25519_fhmqvc_xsalsa20_poly1305; #endif @@ -76,6 +76,9 @@ static void default_config(fastd_config *conf) { conf->on_up = NULL; conf->on_up_dir = NULL; + + conf->on_down = NULL; + conf->on_down_dir = NULL; } static bool config_match(const char *opt, ...) { @@ -493,6 +496,16 @@ void fastd_configure(fastd_context *ctx, fastd_config *conf, int argc, char *con continue; } + IF_OPTION_ARG("--on-down") { + free(conf->on_down); + free(conf->on_down_dir); + + conf->on_down = strdup(arg); + conf->on_down_dir = get_current_dir_name(); + + continue; + } + IF_OPTION("--generate-key") { keygen = true; continue; @@ -614,3 +627,18 @@ void fastd_reconfigure(fastd_context *ctx, fastd_config *conf) { count_peers(ctx, conf); } + +void fastd_config_release(fastd_context *ctx, fastd_config *conf) { + while (conf->peers) + fastd_peer_config_delete(ctx, conf); + + fastd_string_stack_free(conf->peer_dirs); + + free(conf->ifname); + free(conf->secret); + free(conf->on_up); + free(conf->on_up_dir); + free(conf->on_down); + free(conf->on_down_dir); + free(conf->protocol_config); +} diff --git a/src/config.l b/src/config.l index 49c0117..1de0457 100644 --- a/src/config.l +++ b/src/config.l @@ -70,6 +70,7 @@ tap { UPDATE_LOCATION; return TOK_TAP; } tun { UPDATE_LOCATION; return TOK_TUN; } on { UPDATE_LOCATION; return TOK_ON; } up { UPDATE_LOCATION; return TOK_UP; } +down { UPDATE_LOCATION; return TOK_DOWN; } peers { UPDATE_LOCATION; return TOK_PEERS; } from { UPDATE_LOCATION; return TOK_FROM; } log { UPDATE_LOCATION; return TOK_LOG; } diff --git a/src/config.y b/src/config.y index 332ad77..0af0980 100644 --- a/src/config.y +++ b/src/config.y @@ -72,6 +72,7 @@ %token TOK_TUN %token TOK_ON %token TOK_UP +%token TOK_DOWN %token TOK_PEERS %token TOK_FROM %token TOK_LOG @@ -97,10 +98,10 @@ void fastd_config_error(YYLTYPE *loc, fastd_context *ctx, fastd_config *conf, const char *filename, int depth, char *s); - extern fastd_protocol fastd_protocol_null; + extern const fastd_protocol fastd_protocol_null; #ifdef WITH_PROTOCOL_ECFXP - extern fastd_protocol fastd_protocol_ec25519_fhmqvc_xsalsa20_poly1305; + extern const fastd_protocol fastd_protocol_ec25519_fhmqvc_xsalsa20_poly1305; #endif } @@ -129,6 +130,7 @@ statement: TOK_LOG log ';' | TOK_PROTOCOL protocol ';' | TOK_SECRET secret ';' | TOK_ON TOK_UP on_up ';' + | TOK_ON TOK_DOWN on_down ';' | TOK_PEER peer '{' peer_conf '}' | TOK_PEER_TO_PEER peer_to_peer ';' | TOK_INCLUDE include ';' @@ -201,6 +203,15 @@ on_up: TOK_STRING { } ; +on_down: TOK_STRING { + free(conf->on_down); + free(conf->on_down_dir); + + conf->on_down = strdup($1->str); + conf->on_down_dir = get_current_dir_name(); + } + ; + peer: maybe_string { fastd_peer_config_new(ctx, conf); conf->peers->name = strdup($1->str); diff --git a/src/fastd.c b/src/fastd.c index f38bf60..ca4edb8 100644 --- a/src/fastd.c +++ b/src/fastd.c @@ -43,22 +43,35 @@ static bool sighup = false; +static bool terminate = false; static void on_sighup(int signo) { sighup = true; } +static void on_terminate(int signo) { + terminate = true; +} + static void init_signals(fastd_context *ctx) { struct sigaction action; - action.sa_handler = on_sighup; action.sa_flags = 0; sigemptyset(&action.sa_mask); + action.sa_handler = on_sighup; if(sigaction(SIGHUP, &action, NULL)) exit_errno(ctx, "sigaction"); + + action.sa_handler = on_terminate; + if(sigaction(SIGTERM, &action, NULL)) + exit_errno(ctx, "sigaction"); + if(sigaction(SIGQUIT, &action, NULL)) + exit_errno(ctx, "sigaction"); + if(sigaction(SIGINT, &action, NULL)) + exit_errno(ctx, "sigaction"); } static void init_tuntap(fastd_context *ctx) { @@ -93,10 +106,17 @@ static void init_tuntap(fastd_context *ctx) { ctx->ifname = strdup(ifr.ifr_name); - pr_debug(ctx, "Tun/tap device initialized."); + pr_debug(ctx, "tun/tap device initialized."); +} + +static void close_tuntap(fastd_context *ctx) { + if(close(ctx->tunfd)) + warn_errno(ctx, "closing tun/tap: close"); + + free(ctx->ifname); } -static void init_socket(fastd_context *ctx) { +static void init_sockets(fastd_context *ctx) { struct sockaddr_in addr_in = ctx->conf->bind_addr_in; struct sockaddr_in6 addr_in6 = ctx->conf->bind_addr_in6; @@ -133,7 +153,7 @@ static void init_socket(fastd_context *ctx) { pr_debug(ctx, "Initializing IPv6 socket..."); if ((ctx->sock6fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) { - if (ctx->sockfd > 0) + if (ctx->sockfd >= 0) warn_errno(ctx, "socket"); else exit_errno(ctx, "socket"); @@ -154,6 +174,18 @@ static void init_socket(fastd_context *ctx) { } } +static void close_sockets(fastd_context *ctx) { + if (ctx->sockfd >= 0) { + if(close(ctx->sockfd)) + warn_errno(ctx, "closing IPv4 socket: close"); + } + + if (ctx->sock6fd >= 0) { + if(close(ctx->sock6fd)) + warn_errno(ctx, "closing IPv6 socket: close"); + } +} + static void on_up(fastd_context *ctx) { if (!ctx->conf->on_up) return; @@ -178,6 +210,30 @@ static void on_up(fastd_context *ctx) { free(cwd); } +static void on_down(fastd_context *ctx) { + if (!ctx->conf->on_down) + return; + + char *cwd = get_current_dir_name(); + chdir(ctx->conf->on_down_dir); + + setenv("INTERFACE", ctx->ifname, 1); + + char buf[6]; + snprintf(buf, 6, "%u", ctx->conf->mtu); + setenv("MTU", buf, 1); + + int ret = system(ctx->conf->on_down); + + if (WIFSIGNALED(ret)) + pr_error(ctx, "on-down command exited with signal %i", WTERMSIG(ret)); + else if(ret) + pr_warn(ctx, "on-down command exited with status %i", WEXITSTATUS(ret)); + + chdir(cwd); + free(cwd); +} + static void init_peers(fastd_context *ctx) { fastd_peer_config *peer_conf; for (peer_conf = ctx->conf->peers; peer_conf; peer_conf = peer_conf->next) { @@ -188,6 +244,15 @@ static void init_peers(fastd_context *ctx) { } } +static void delete_peers(fastd_context *ctx) { + fastd_peer *peer, *next; + for (peer = ctx->peers; peer; peer = next) { + next = peer->next; + + fastd_peer_delete(ctx, peer); + } +} + static void update_time(fastd_context *ctx) { clock_gettime(CLOCK_MONOTONIC, &ctx->now); } @@ -500,24 +565,24 @@ int main(int argc, char *argv[]) { fastd_random_bytes(&ctx, &ctx.randseed, sizeof(ctx.randseed), false); + init_signals(&ctx); + fastd_config conf; fastd_configure(&ctx, &conf, argc, argv); ctx.conf = &conf; conf.protocol_config = conf.protocol->init(&ctx); - init_signals(&ctx); - update_time(&ctx); - init_peers(&ctx); - init_tuntap(&ctx); - init_socket(&ctx); + init_sockets(&ctx); + + init_peers(&ctx); on_up(&ctx); - while (1) { + while (!terminate) { handle_tasks(&ctx); handle_input(&ctx); @@ -529,5 +594,14 @@ int main(int argc, char *argv[]) { } } + on_down(&ctx); + + delete_peers(&ctx); + + close_sockets(&ctx); + close_tuntap(&ctx); + + fastd_config_release(&ctx, &conf); + return 0; } diff --git a/src/fastd.h b/src/fastd.h index f07f108..1e78dc7 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -96,7 +96,7 @@ struct _fastd_config { bool peer_to_peer; - fastd_protocol *protocol; + const fastd_protocol *protocol; char *secret; unsigned key_valid; unsigned key_refresh; @@ -112,6 +112,9 @@ struct _fastd_config { char *on_up; char *on_up_dir; + + char *on_down; + char *on_down_dir; }; struct _fastd_context { @@ -146,6 +149,7 @@ void fastd_read_peer_dir(fastd_context *ctx, fastd_config *conf, const char *dir bool fastd_read_config(fastd_context *ctx, fastd_config *conf, const char *filename, bool peer_config, int depth); void fastd_configure(fastd_context *ctx, fastd_config *conf, int argc, char *const argv[]); void fastd_reconfigure(fastd_context *ctx, fastd_config *conf); +void fastd_config_release(fastd_context *ctx, fastd_config *conf); void fastd_random_bytes(fastd_context *ctx, void *buffer, size_t len, bool secure); diff --git a/src/peer.c b/src/peer.c index 9bb900b..3566cfc 100644 --- a/src/peer.c +++ b/src/peer.c @@ -113,11 +113,8 @@ void fastd_peer_config_purge(fastd_context *ctx, fastd_peer_config *conf) { for (peer = ctx->peers; peer; peer = next) { next = peer->next; - if (peer->config == conf) { - reset_peer(ctx, peer); - delete_peer(ctx, peer); - continue; - } + if (peer->config == conf) + fastd_peer_delete(ctx, peer); } ctx->conf->protocol->peer_config_purged(ctx, conf); @@ -169,6 +166,11 @@ void fastd_peer_reset(fastd_context *ctx, fastd_peer *peer) { setup_peer(ctx, peer); } +void fastd_peer_delete(fastd_context *ctx, fastd_peer *peer) { + reset_peer(ctx, peer); + delete_peer(ctx, peer); +} + static fastd_peer* add_peer(fastd_context *ctx) { fastd_peer *peer = malloc(sizeof(fastd_peer)); diff --git a/src/peer.h b/src/peer.h index 94b9026..4afa9a1 100644 --- a/src/peer.h +++ b/src/peer.h @@ -79,6 +79,7 @@ void fastd_peer_config_purge(fastd_context *ctx, fastd_peer_config *conf); bool fastd_peer_config_equal(const fastd_peer_config *peer1, const fastd_peer_config *peer2); void fastd_peer_reset(fastd_context *ctx, fastd_peer *peer); +void fastd_peer_delete(fastd_context *ctx, fastd_peer *peer); fastd_peer* fastd_peer_add(fastd_context *ctx, fastd_peer_config *conf); fastd_peer* fastd_peer_add_temp(fastd_context *ctx, const fastd_peer_address *address); fastd_peer* fastd_peer_set_established_merge(fastd_context *ctx, fastd_peer *perm_peer, fastd_peer *temp_peer); -- cgit v1.2.3