diff --git a/configs/conf-available/10-backend-exec-ipset.conf b/configs/conf-available/10-backend-exec-ipset.conf index 2c7fbc0..992353e 100644 --- a/configs/conf-available/10-backend-exec-ipset.conf +++ b/configs/conf-available/10-backend-exec-ipset.conf @@ -8,3 +8,4 @@ ban = /sbin/ipset -! add check = /sbin/ipset -! test unban = /sbin/ipset -! del timeout = 2 +shared = no diff --git a/src/backends/exec.c b/src/backends/exec.c index a8d7892..dbec5dc 100644 --- a/src/backends/exec.c +++ b/src/backends/exec.c @@ -24,10 +24,17 @@ typedef struct cmd_t { size_t pos_id; /**< index+1 in argv[] where to insert IP address (zero means "no placeholder") */ } cmd_t; +typedef struct cfg_id_t { + struct cfg_id_t *next; + char name[ID_MAX + 1]; + size_t count; +} cfg_id_t; + struct _config { char name[ID_MAX + 1]; char error[256]; time_t timeout; + bool shared; cmd_t *start; cmd_t *stop; cmd_t *ban; @@ -35,6 +42,50 @@ struct _config { cmd_t *check; }; +/* this list needed for tracking backend usage with `shared = yes` */ +cfg_id_t *ids_usage = NULL; + +static size_t +usage_inc(const char *id) { + cfg_id_t *e = NULL; + + assert(id != NULL); + + for (e = ids_usage; e != NULL; e = e->next) { + if (strcmp(e->name, id) != 0) + continue; + /* found */ + e->count++; + return e->count; + } + /* not found or list is empty */ + e = calloc(1, sizeof(cfg_id_t)); + snprintf(e->name, sizeof(e->name), "%s", id); + e->count++; + e->next = ids_usage; + ids_usage = e; + return e->count; +} + +static size_t +usage_dec(const char *id) { + cfg_id_t *e = NULL; + + assert(id != NULL); + + for (e = ids_usage; e != NULL; e = e->next) { + if (strcmp(e->name, id) != 0) + continue; + /* found */ + if (e->count > 0) + e->count--; + return e->count; + } + + /* not found or list is empty */ + return 0; +} + static cmd_t * cmd_from_str(const char *str) { cmd_t *cmd = NULL; @@ -182,6 +233,10 @@ config(cfg_t *cfg, const char *key, const char *value) { cfg->timeout = atoi(value); return true; } + if (strcmp(key, "shared") == 0) { + cfg->shared = (strcmp(value, "yes") ? true : false); + return true; + } CREATE_CMD(start) CREATE_CMD(stop) @@ -216,6 +271,9 @@ start(cfg_t *cfg) { if (!cfg->start) return true; + if (cfg->shared && usage_inc(cfg->name) > 1) + return true; + return cmd_list_exec(cfg, cfg->start, NULL); } @@ -226,6 +284,9 @@ stop(cfg_t *cfg) { if (!cfg->stop) return true; + if (cfg->shared && usage_dec(cfg->name) > 0) + return true; + return cmd_list_exec(cfg, cfg->stop, NULL); }