diff options
-rw-r--r-- | src/config.c | 31 | ||||
-rw-r--r-- | src/config.l | 2 | ||||
-rw-r--r-- | src/config.y | 22 | ||||
-rw-r--r-- | src/fastd.h | 6 | ||||
-rw-r--r-- | src/peer.c | 120 |
5 files changed, 179 insertions, 2 deletions
diff --git a/src/config.c b/src/config.c index 0d9a62b..f18d975 100644 --- a/src/config.c +++ b/src/config.c @@ -79,6 +79,13 @@ static void default_config(fastd_config *conf) { conf->on_down = NULL; conf->on_down_dir = NULL; + + conf->on_establish = NULL; + conf->on_establish_dir = NULL; + + conf->on_disestablish = NULL; + conf->on_disestablish_dir = NULL; + } static bool config_match(const char *opt, ...) { @@ -506,6 +513,26 @@ void fastd_configure(fastd_context *ctx, fastd_config *conf, int argc, char *con continue; } + IF_OPTION_ARG("--on-establish") { + free(conf->on_establish); + free(conf->on_establish_dir); + + conf->on_establish = strdup(arg); + conf->on_establish_dir = get_current_dir_name(); + + continue; + } + + IF_OPTION_ARG("--on-disestablish") { + free(conf->on_disestablish); + free(conf->on_disestablish_dir); + + conf->on_disestablish = strdup(arg); + conf->on_disestablish_dir = get_current_dir_name(); + + continue; + } + IF_OPTION("--generate-key") { keygen = true; continue; @@ -640,5 +667,9 @@ void fastd_config_release(fastd_context *ctx, fastd_config *conf) { free(conf->on_up_dir); free(conf->on_down); free(conf->on_down_dir); + free(conf->on_establish); + free(conf->on_establish_dir); + free(conf->on_disestablish); + free(conf->on_disestablish_dir); free(conf->protocol_config); } diff --git a/src/config.l b/src/config.l index c352a1d..c2f771a 100644 --- a/src/config.l +++ b/src/config.l @@ -71,6 +71,8 @@ tun { UPDATE_LOCATION; return TOK_TUN; } on { UPDATE_LOCATION; return TOK_ON; } up { UPDATE_LOCATION; return TOK_UP; } down { UPDATE_LOCATION; return TOK_DOWN; } +establish { UPDATE_LOCATION; return TOK_ESTABLISH; } +disestablish { UPDATE_LOCATION; return TOK_DISESTABLISH; } 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 0af0980..ac5f808 100644 --- a/src/config.y +++ b/src/config.y @@ -73,6 +73,8 @@ %token TOK_ON %token TOK_UP %token TOK_DOWN +%token TOK_ESTABLISH +%token TOK_DISESTABLISH %token TOK_PEERS %token TOK_FROM %token TOK_LOG @@ -131,6 +133,8 @@ statement: TOK_LOG log ';' | TOK_SECRET secret ';' | TOK_ON TOK_UP on_up ';' | TOK_ON TOK_DOWN on_down ';' + | TOK_ON TOK_ESTABLISH on_establish ';' + | TOK_ON TOK_DISESTABLISH on_disestablish ';' | TOK_PEER peer '{' peer_conf '}' | TOK_PEER_TO_PEER peer_to_peer ';' | TOK_INCLUDE include ';' @@ -212,6 +216,24 @@ on_down: TOK_STRING { } ; +on_establish: TOK_STRING { + free(conf->on_establish); + free(conf->on_establish_dir); + + conf->on_establish = strdup($1->str); + conf->on_establish_dir = get_current_dir_name(); + } + ; + +on_disestablish: TOK_STRING { + free(conf->on_disestablish); + free(conf->on_disestablish_dir); + + conf->on_disestablish = strdup($1->str); + conf->on_disestablish_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.h b/src/fastd.h index 1e78dc7..e3d3b02 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -115,6 +115,12 @@ struct _fastd_config { char *on_down; char *on_down_dir; + + char *on_establish; + char *on_establish_dir; + + char *on_disestablish; + char *on_disestablish_dir; }; struct _fastd_context { @@ -29,8 +29,120 @@ #include "peer.h" #include "task.h" +#include <arpa/inet.h> +#include <unistd.h> + + +static void on_establish(fastd_context *ctx, fastd_peer *peer) { + if (!ctx->conf->on_establish) + return; + + char *cwd = get_current_dir_name(); + chdir(ctx->conf->on_establish_dir); + + setenv("INTERFACE", ctx->ifname, 1); + + char buf[INET6_ADDRSTRLEN]; + snprintf(buf, sizeof(buf), "%u", ctx->conf->mtu); + setenv("MTU", buf, 1); + + if (peer->config && peer->config->name) + setenv("PEER_NAME", peer->config->name, 1); + else + unsetenv("PEER_NAME"); + + switch(peer->address.sa.sa_family) { + case AF_INET: + inet_ntop(AF_INET, &peer->address.in.sin_addr, buf, sizeof(buf)); + setenv("PEER_ADDRESS", buf, 1); + + snprintf(buf, sizeof(buf), "%u", ntohs(peer->address.in.sin_port)); + setenv("PEER_PORT", buf, 1); + + break; + + case AF_INET6: + inet_ntop(AF_INET6, &peer->address.in6.sin6_addr, buf, sizeof(buf)); + setenv("PEER_ADDRESS", buf, 1); + + snprintf(buf, sizeof(buf), "%u", ntohs(peer->address.in6.sin6_port)); + setenv("PEER_PORT", buf, 1); + + break; + + default: + unsetenv("PEER_ADDRESS"); + unsetenv("PEER_PORT"); + } + + int ret = system(ctx->conf->on_establish); + + if (WIFSIGNALED(ret)) + pr_error(ctx, "on-establish command exited with signal %i", WTERMSIG(ret)); + else if(ret) + pr_warn(ctx, "on-establish command exited with status %i", WEXITSTATUS(ret)); + + chdir(cwd); + free(cwd); +} + +static void on_disestablish(fastd_context *ctx, fastd_peer *peer) { + if (!ctx->conf->on_disestablish) + return; + + char *cwd = get_current_dir_name(); + chdir(ctx->conf->on_disestablish_dir); + + setenv("INTERFACE", ctx->ifname, 1); + + char buf[INET6_ADDRSTRLEN]; + snprintf(buf, sizeof(buf), "%u", ctx->conf->mtu); + setenv("MTU", buf, 1); + + if (peer->config && peer->config->name) + setenv("PEER_NAME", peer->config->name, 1); + else + unsetenv("PEER_NAME"); + + switch(peer->address.sa.sa_family) { + case AF_INET: + inet_ntop(AF_INET, &peer->address.in.sin_addr, buf, sizeof(buf)); + setenv("PEER_ADDRESS", buf, 1); + + snprintf(buf, sizeof(buf), "%u", ntohs(peer->address.in.sin_port)); + setenv("PEER_PORT", buf, 1); + + break; + + case AF_INET6: + inet_ntop(AF_INET6, &peer->address.in6.sin6_addr, buf, sizeof(buf)); + setenv("PEER_ADDRESS", buf, 1); + + snprintf(buf, sizeof(buf), "%u", ntohs(peer->address.in6.sin6_port)); + setenv("PEER_PORT", buf, 1); + + break; + + default: + unsetenv("PEER_ADDRESS"); + unsetenv("PEER_PORT"); + } + + int ret = system(ctx->conf->on_disestablish); + + if (WIFSIGNALED(ret)) + pr_error(ctx, "on-disestablish command exited with signal %i", WTERMSIG(ret)); + else if(ret) + pr_warn(ctx, "on-disestablish command exited with status %i", WEXITSTATUS(ret)); + + chdir(cwd); + free(cwd); +} static inline void reset_peer(fastd_context *ctx, fastd_peer *peer) { + if (peer->state == STATE_ESTABLISHED) + on_disestablish(ctx, peer); + ctx->conf->protocol->free_peer_state(ctx, peer); peer->protocol_state = NULL; @@ -217,11 +329,13 @@ fastd_peer* fastd_peer_set_established_merge(fastd_context *ctx, fastd_peer *per ctx->conf->protocol->free_peer_state(ctx, perm_peer); + if (perm_peer->state == STATE_ESTABLISHED) + on_disestablish(ctx, perm_peer); + perm_peer->address = temp_peer->address; perm_peer->state = STATE_ESTABLISHED; perm_peer->seen = temp_peer->seen; perm_peer->protocol_state = temp_peer->protocol_state; - temp_peer->protocol_state = NULL; int i; @@ -235,6 +349,7 @@ fastd_peer* fastd_peer_set_established_merge(fastd_context *ctx, fastd_peer *per fastd_peer_reset(ctx, temp_peer); + on_establish(ctx, perm_peer); pr_info(ctx, "Connection with %P established.", perm_peer); return perm_peer; @@ -243,8 +358,9 @@ fastd_peer* fastd_peer_set_established_merge(fastd_context *ctx, fastd_peer *per void fastd_peer_set_established(fastd_context *ctx, fastd_peer *peer) { switch(peer->state) { case STATE_WAIT: - pr_info(ctx, "Connection with %P established.", peer); peer->state = STATE_ESTABLISHED; + on_establish(ctx, peer); + pr_info(ctx, "Connection with %P established.", peer); break; case STATE_TEMP: |