Must specify "auto", "static", or "iface"

This commit is contained in:
Daniel Adolfsson 2019-12-15 04:29:23 +01:00
parent 4db6b7f7a5
commit 17bb6145e5
5 changed files with 114 additions and 47 deletions

@ -24,14 +24,6 @@
#include <string.h>
#include <sys/stat.h>
#ifndef INT_MAX
# define INT_MAX __INT_MAX__
#endif
#ifndef INT_MIN
# define INT_MIN (-INT_MAX - 1)
#endif
#include "ndppd.h"
#include "proxy.h"
#include "rule.h"
@ -53,9 +45,11 @@ typedef struct
int column;
} ndL_state_t;
typedef bool (*ndL_cfcb_t)(ndL_state_t *state, void *ptr);
typedef struct ndL_cfinfo ndL_cfinfo_t;
typedef struct
typedef bool (*ndL_cfcb_t)(ndL_state_t *, const ndL_cfinfo_t *, void *);
struct ndL_cfinfo
{
const char *key;
int scope;
@ -64,7 +58,7 @@ typedef struct
int min;
int max;
ndL_cfcb_t cb;
} ndL_cfinfo_t;
};
//! Scopes.
enum
@ -97,30 +91,36 @@ enum
NDL_IPV6X, // [A-Fa-f0-9:]
};
static bool ndL_parse_rule(ndL_state_t *state, nd_proxy_t *proxy);
static bool ndL_parse_rewrite(ndL_state_t *state, nd_rule_t *rule);
static bool ndL_parse_proxy(ndL_state_t *state, void *unused);
static bool ndL_parse_rule(ndL_state_t *state, ndL_cfinfo_t *info, nd_proxy_t *proxy);
static bool ndL_parse_rewrite(ndL_state_t *state, ndL_cfinfo_t *info, nd_rule_t *rule);
static bool ndL_parse_proxy(ndL_state_t *state, ndL_cfinfo_t *info, void *unused);
static bool ndL_parse_mode(ndL_state_t *state, ndL_cfinfo_t *info, nd_rule_t *rule);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
#pragma GCC diagnostic ignored "-Wint-conversion"
static const ndL_cfinfo_t ndL_cfinfo_table[] = {
{ "proxy", NDL_DEFAULT, NDL_NONE, 0, 0, 0, (ndL_cfcb_t)ndL_parse_proxy },
{ "rule", NDL_PROXY, NDL_NONE, 0, 0, 0, (ndL_cfcb_t)ndL_parse_rule },
{ "rewrite", NDL_RULE, NDL_NONE, 0, 0, 0, (ndL_cfcb_t)ndL_parse_rewrite },
{ "invalid-ttl", NDL_DEFAULT, NDL_INT, (uintptr_t)&nd_conf_invalid_ttl, 1000, 3600000, NULL },
{ "valid-ttl", NDL_DEFAULT, NDL_INT, (uintptr_t)&nd_conf_valid_ttl, 10000, 3600000, NULL },
{ "renew", NDL_DEFAULT, NDL_INT, (uintptr_t)&nd_conf_renew, 0, 0, NULL },
{ "retrans-limit", NDL_DEFAULT, NDL_INT, (uintptr_t)&nd_conf_retrans_limit, 0, 10, NULL },
{ "retrans-time", NDL_DEFAULT, NDL_INT, (uintptr_t)&nd_conf_retrans_time, 0, 60000, NULL },
{ "keepalive", NDL_DEFAULT, NDL_BOOL, (uintptr_t)&nd_conf_keepalive, 0, 0, NULL },
{ "proxy", NDL_DEFAULT, NDL_NONE, 0, 0, 0, ndL_parse_proxy },
{ "rule", NDL_PROXY, NDL_NONE, 0, 0, 0, ndL_parse_rule },
{ "rewrite", NDL_RULE, NDL_NONE, 0, 0, 0, ndL_parse_rewrite },
{ "invalid-ttl", NDL_DEFAULT, NDL_INT, &nd_conf_invalid_ttl, 1000, 3600000, NULL },
{ "valid-ttl", NDL_DEFAULT, NDL_INT, &nd_conf_valid_ttl, 10000, 3600000, NULL },
{ "renew", NDL_DEFAULT, NDL_INT, &nd_conf_renew, 0, 0, NULL },
{ "retrans-limit", NDL_DEFAULT, NDL_INT, &nd_conf_retrans_limit, 0, 10, NULL },
{ "retrans-time", NDL_DEFAULT, NDL_INT, &nd_conf_retrans_time, 0, 60000, NULL },
{ "keepalive", NDL_DEFAULT, NDL_BOOL, &nd_conf_keepalive, 0, 0, NULL },
{ "router", NDL_PROXY, NDL_BOOL, offsetof(nd_proxy_t, router), 0, 0, NULL },
{ "auto", NDL_RULE, NDL_BOOL, offsetof(nd_rule_t, is_auto), 0, 0, NULL },
{ "auto", NDL_RULE, NDL_NONE, 0, 0, 0, ndL_parse_mode },
{ "static", NDL_RULE, NDL_NONE, 0, 0, 0, ndL_parse_mode },
{ "autowire", NDL_RULE, NDL_BOOL, offsetof(nd_rule_t, autowire), 0, 0, NULL },
{ "promisc", NDL_PROXY, NDL_BOOL, offsetof(nd_proxy_t, promisc), 0, 0, NULL },
{ "iface", NDL_RULE, NDL_IDENT, offsetof(nd_rule_t, ifname), 0, IF_NAMESIZE, NULL },
{ "iface", NDL_RULE, NDL_NONE, 0, 0, 0, ndL_parse_mode },
#ifndef __FreeBSD__
{ "table", NDL_RULE, NDL_INT, offsetof(nd_rule_t, table), 0, 255, NULL },
#endif
{ NULL, 0, 0, 0, 0, 0, NULL },
{ 0 },
};
#pragma GCC diagnostic pop
static void ndL_error(const ndL_state_t *state, const char *fmt, ...)
{
@ -131,7 +131,7 @@ static void ndL_error(const ndL_state_t *state, const char *fmt, ...)
vsnprintf(buf, sizeof(buf), fmt, va);
va_end(va);
nd_log_error("%s at line %d column %d", buf, state->line, state->column);
nd_log_error("(at line %d column %d) %s", state->line, state->column, buf);
}
static char ndL_accept_one(ndL_state_t *state, int cl)
@ -368,7 +368,7 @@ static bool ndL_accept_ident(ndL_state_t *state, char *str, size_t size)
static bool ndL_parse_block(ndL_state_t *state, int scope, void *ptr);
static bool ndL_parse_rule(ndL_state_t *state, nd_proxy_t *proxy)
static bool ndL_parse_rule(ndL_state_t *state, ND_UNUSED ndL_cfinfo_t *info, nd_proxy_t *proxy)
{
nd_rule_t *rule = nd_rule_create(proxy);
@ -397,10 +397,25 @@ static bool ndL_parse_rule(ndL_state_t *state, nd_proxy_t *proxy)
rule->table = 0;
#endif
return ndL_parse_block(state, NDL_RULE, rule);
if (!ndL_parse_block(state, NDL_RULE, rule))
return false;
if (rule->mode == ND_MODE_UNKNOWN)
{
ndL_error(state, "\"static\", \"auto\", or \"iface\" need to be specified");
return false;
}
if (rule->autowire && rule->mode != ND_MODE_IFACE)
{
ndL_error(state, "\"autowire\" may only be used in combination with \"iface\"");
return false;
}
return true;
}
static bool ndL_parse_rewrite(ndL_state_t *state, nd_rule_t *rule)
static bool ndL_parse_rewrite(ndL_state_t *state, ND_UNUSED ndL_cfinfo_t *info, nd_rule_t *rule)
{
if (!ndL_accept_addr(state, &rule->rewrite_tgt))
return false;
@ -421,7 +436,7 @@ static bool ndL_parse_rewrite(ndL_state_t *state, nd_rule_t *rule)
return true;
}
static bool ndL_parse_proxy(ndL_state_t *state, __attribute__((unused)) void *unused)
static bool ndL_parse_proxy(ndL_state_t *state, ND_UNUSED ndL_cfinfo_t *u1, ND_UNUSED void *u2)
{
char ifname[IF_NAMESIZE];
@ -439,6 +454,32 @@ static bool ndL_parse_proxy(ndL_state_t *state, __attribute__((unused)) void *un
return ndL_parse_block(state, NDL_PROXY, proxy);
}
static bool ndL_parse_mode(ndL_state_t *state, ndL_cfinfo_t *info, nd_rule_t *rule)
{
if (rule->mode != ND_MODE_UNKNOWN)
{
ndL_error(state, "\"static\", \"auto\" and \"iface\" are mutually exclusive");
return false;
}
if (!strcmp(info->key, "auto"))
rule->mode = ND_MODE_AUTO;
else if (!strcmp(info->key, "static"))
rule->mode = ND_MODE_STATIC;
else
{
if (!ndL_accept_ident(state, rule->ifname, sizeof(rule->ifname)))
{
ndL_error(state, "Expected interface name");
return false;
}
rule->mode = ND_MODE_IFACE;
}
return true;
}
static bool ndL_parse_block(ndL_state_t *state, int scope, void *ptr)
{
ndL_skip(state, false);
@ -449,6 +490,8 @@ static bool ndL_parse_block(ndL_state_t *state, int scope, void *ptr)
return false;
}
uint32_t bits = 0;
for (;;)
{
ndL_skip(state, true);
@ -469,20 +512,36 @@ static bool ndL_parse_block(ndL_state_t *state, int scope, void *ptr)
bool found = false;
char key[32];
const ndL_state_t state_before_key = *state;
if (!ndL_accept_ident(state, key, sizeof(key)))
{
nd_log_error("Expected key");
return false;
}
ndL_skip(state, false);
for (int i = 0; !found && ndL_cfinfo_table[i].key; i++)
{
if (ndL_cfinfo_table[i].scope != scope)
continue;
if (!ndL_accept(state, ndL_cfinfo_table[i].key, NDL_EALNM))
if (strcmp(key, ndL_cfinfo_table[i].key) != 0)
continue;
ndL_skip(state, false);
if (strcmp(key, "rule") != 0 && strcmp(key, "proxy") != 0 && bits & (1 << i))
{
ndL_error(&state_before_key, "\"%s\" has already been configured earlier in this scope", key);
return false;
}
bits |= 1 << i;
found = true;
const ndL_cfinfo_t *t = &ndL_cfinfo_table[i];
const ndL_state_t saved_state = *state;
const ndL_state_t state_before_value = *state;
switch (t->type)
{
@ -492,7 +551,7 @@ static bool ndL_parse_block(ndL_state_t *state, int scope, void *ptr)
case NDL_BOOL:
if (!ndL_accept_bool(state, (bool *)(ptr + t->offset)))
{
ndL_error(&saved_state, "Expected boolean value");
ndL_error(&state_before_value, "Expected boolean value");
return false;
}
break;
@ -500,7 +559,7 @@ static bool ndL_parse_block(ndL_state_t *state, int scope, void *ptr)
case NDL_INT:
if (!ndL_accept_int(state, (int *)(ptr + t->offset), t->min, t->max))
{
ndL_error(&saved_state, "Expected an integer");
ndL_error(&state_before_value, "Expected an integer");
return false;
}
break;
@ -508,7 +567,7 @@ static bool ndL_parse_block(ndL_state_t *state, int scope, void *ptr)
case NDL_ADDR:
if (!ndL_accept_addr(state, (nd_addr_t *)(ptr + t->offset)))
{
ndL_error(&saved_state, "Expected an IPv6 address");
ndL_error(&state_before_value, "Expected an IPv6 address");
return false;
}
break;
@ -516,7 +575,7 @@ static bool ndL_parse_block(ndL_state_t *state, int scope, void *ptr)
case NDL_IDENT:
if (!ndL_accept_ident(state, (char *)(ptr + t->offset), t->max))
{
ndL_error(&saved_state, "Expected identifier");
ndL_error(&state_before_value, "Expected identifier");
return false;
}
break;
@ -526,7 +585,7 @@ static bool ndL_parse_block(ndL_state_t *state, int scope, void *ptr)
{
ndL_skip(state, false);
if (!t->cb(state, ptr))
if (!t->cb(state, &ndL_cfinfo_table[i], ptr))
return false;
}
@ -585,7 +644,7 @@ bool nd_conf_load(const char *path)
{
ndL_state_t state = { .data = buf, .offset = 0, .length = stat.st_size, .column = 0, .line = 1 };
/* TODO: Validate configuration. */
// FIXME: Validate configuration
result = ndL_parse_block(&state, NDL_DEFAULT, NULL);
}

@ -36,6 +36,9 @@ extern bool nd_daemonized;
extern bool nd_opt_syslog;
extern bool nd_opt_daemonize;
#define ND_UNUSED __attribute__((unused))
#define ND_ALIGNED(x) __attribute((aligned(x)))
#define ND_LL_PREPEND(head, el, next) \
do \
{ \

@ -118,9 +118,6 @@ bool nd_proxy_startup()
{
if (rule->ifname[0] && !(rule->iface = nd_iface_open(rule->ifname, 0)))
return false;
nd_log_error("RULE REWRITE %s/%d", nd_aton(&rule->rewrite_tgt), rule->rewrite_pflen);
}
}

@ -21,6 +21,14 @@
#include "ndppd.h"
typedef enum
{
ND_MODE_UNKNOWN,
ND_MODE_STATIC,
ND_MODE_IFACE, // Use a specific interface
ND_MODE_AUTO,
} nd_mode_t;
struct nd_rule
{
nd_rule_t *next;
@ -35,9 +43,9 @@ struct nd_rule
int rewrite_pflen;
nd_iface_t *iface;
bool is_auto;
bool autowire;
int table;
nd_mode_t mode;
};
nd_rule_t *nd_rule_create(nd_proxy_t *proxy);

@ -35,7 +35,7 @@ static nd_session_t *ndL_free_sessions;
static void ndL_up(nd_session_t *session)
{
if (session->iface && !session->autowired && !session->rule->is_auto && session->rule->autowire)
if (session->iface && !session->autowired && session->rule->autowire)
{
nd_rt_add_route(&session->tgt, 128, session->iface->index, session->rule->table);
session->autowired = true;
@ -92,7 +92,7 @@ nd_session_t *nd_session_create(nd_rule_t *rule, nd_addr_t *tgt)
nd_addr_combine(&rule->rewrite_tgt, tgt, rule->rewrite_pflen, &session->real_tgt);
if (rule->is_auto)
if (rule->mode == ND_MODE_AUTO)
{
nd_rt_route_t *route = nd_rt_find_route(tgt, rule->table);
@ -116,7 +116,7 @@ nd_session_t *nd_session_create(nd_rule_t *rule, nd_addr_t *tgt)
session->ons_time = nd_current_time;
nd_iface_write_ns(session->iface, &session->real_tgt);
}
else
else if (rule->mode == ND_MODE_STATIC)
{
session->state = ND_STATE_VALID;
}