This commit is contained in:
Daniel Adolfsson 2019-12-15 13:47:16 +01:00
parent 17bb6145e5
commit 724fa74974
21 changed files with 453 additions and 565 deletions

View File

@ -1,7 +1,13 @@
BreakBeforeBraces: Allman BreakBeforeBraces: Linux
IndentWidth: 4 IndentWidth: 4
ColumnLimit: 120 ColumnLimit: 120
AllowShortFunctionsOnASingleLine: None AllowShortFunctionsOnASingleLine: None
Cpp11BracedListStyle: false Cpp11BracedListStyle: false
IndentPPDirectives: AfterHash IndentPPDirectives: AfterHash
MaxEmptyLinesToKeep: 1 MaxEmptyLinesToKeep: 1
ForEachMacros:
- ND_LL_FOREACH
- ND_LL_FOREACH_S
- ND_LL_FOREACH_NODEF
- ND_LL_FOREACH_S_NODEF

View File

@ -29,7 +29,6 @@ Checks: >
-google-*, -google-*,
-hicpp-avoid-c-arrays, -hicpp-avoid-c-arrays,
-hicpp-avoid-goto, -hicpp-avoid-goto,
-hicpp-braces-around-statements,
-hicpp-function-size, -hicpp-function-size,
-hicpp-named-parameter, -hicpp-named-parameter,
-hicpp-no-array-decay, -hicpp-no-array-decay,
@ -52,7 +51,6 @@ Checks: >
-modernize-use-using, -modernize-use-using,
-objc-*, -objc-*,
-openmp-exception-escape, -openmp-exception-escape,
-readability-braces-around-statements,
-readability-else-after-return, -readability-else-after-return,
-readability-function-size, -readability-function-size,
-readability-identifier-naming, -readability-identifier-naming,

View File

@ -33,8 +33,9 @@ const char *nd_aton(nd_addr_t *addr)
static int index; static int index;
static char buf[3][64]; static char buf[3][64];
if (addr == NULL) if (addr == NULL) {
return "(null)"; return "(null)";
}
int n = index++ % 3; int n = index++ % 3;
@ -80,19 +81,20 @@ bool nd_addr_eq(nd_addr_t *first, nd_addr_t *second)
//! Returns true if the first <tt>pflen</tt> bits are the same in <tt>first</tt> and <tt>second</tt>. //! Returns true if the first <tt>pflen</tt> bits are the same in <tt>first</tt> and <tt>second</tt>.
bool nd_addr_match(nd_addr_t *first, nd_addr_t *second, unsigned pflen) bool nd_addr_match(nd_addr_t *first, nd_addr_t *second, unsigned pflen)
{ {
if (pflen > 128) if (pflen > 128) {
return false; return false;
else if (pflen == 0) } else if (pflen == 0) {
return true; return true;
else if (pflen == 128) } else if (pflen == 128) {
return nd_addr_eq(first, second); return nd_addr_eq(first, second);
}
for (unsigned i = 0, top = (pflen - 1) >> 5; i <= top; i++) for (unsigned i = 0, top = (pflen - 1) >> 5; i <= top; i++) {
{
uint32_t mask = i < top ? 0xffffffff : ndL_masks[(pflen - 1) & 31]; uint32_t mask = i < top ? 0xffffffff : ndL_masks[(pflen - 1) & 31];
if ((first->s6_addr32[i] ^ second->s6_addr32[i]) & mask) if ((first->s6_addr32[i] ^ second->s6_addr32[i]) & mask) {
return false; return false;
}
} }
return true; return true;
@ -100,29 +102,25 @@ bool nd_addr_match(nd_addr_t *first, nd_addr_t *second, unsigned pflen)
void nd_addr_combine(const nd_addr_t *first, const nd_addr_t *second, unsigned pflen, nd_addr_t *result) void nd_addr_combine(const nd_addr_t *first, const nd_addr_t *second, unsigned pflen, nd_addr_t *result)
{ {
if (pflen == 0) if (pflen == 0) {
{
*result = *second; *result = *second;
return; return;
} }
if (pflen >= 128) if (pflen >= 128) {
{
*result = *first; *result = *first;
return; return;
} }
for (unsigned i = 0, top = (pflen - 1) >> 5; i < 4; i++) for (unsigned i = 0, top = (pflen - 1) >> 5; i < 4; i++) {
{ if (i == top) {
if (i == top)
{
uint32_t mask = ndL_masks[(pflen - 1) & 31]; uint32_t mask = ndL_masks[(pflen - 1) & 31];
result->s6_addr32[i] = (first->s6_addr32[i] & mask) | (second->s6_addr32[i] & ~mask); result->s6_addr32[i] = (first->s6_addr32[i] & mask) | (second->s6_addr32[i] & ~mask);
} } else if (i < top) {
else if (i < top)
result->s6_addr32[i] = first->s6_addr32[i]; result->s6_addr32[i] = first->s6_addr32[i];
else } else {
result->s6_addr32[i] = second->s6_addr32[i]; result->s6_addr32[i] = second->s6_addr32[i];
}
} }
} }
@ -144,8 +142,7 @@ int nd_mask_to_pflen(nd_addr_t *netmask)
void nd_mask_from_pflen(unsigned pflen, nd_addr_t *netmask) void nd_mask_from_pflen(unsigned pflen, nd_addr_t *netmask)
{ {
if (pflen == 0) if (pflen == 0) {
{
netmask->s6_addr32[0] = 0; netmask->s6_addr32[0] = 0;
netmask->s6_addr32[1] = 0; netmask->s6_addr32[1] = 0;
netmask->s6_addr32[2] = 0; netmask->s6_addr32[2] = 0;
@ -153,8 +150,7 @@ void nd_mask_from_pflen(unsigned pflen, nd_addr_t *netmask)
return; return;
} }
if (pflen >= 128) if (pflen >= 128) {
{
netmask->s6_addr32[0] = 0xffffffff; netmask->s6_addr32[0] = 0xffffffff;
netmask->s6_addr32[1] = 0xffffffff; netmask->s6_addr32[1] = 0xffffffff;
netmask->s6_addr32[2] = 0xffffffff; netmask->s6_addr32[2] = 0xffffffff;
@ -162,13 +158,13 @@ void nd_mask_from_pflen(unsigned pflen, nd_addr_t *netmask)
return; return;
} }
for (unsigned i = 0, top = (pflen - 1) >> 5; i < 4; i++) for (unsigned i = 0, top = (pflen - 1) >> 5; i < 4; i++) {
{ if (i == top) {
if (i == top)
netmask->s6_addr32[i] = ndL_masks[(pflen - 1) & 31]; netmask->s6_addr32[i] = ndL_masks[(pflen - 1) & 31];
else if (i < top) } else if (i < top) {
netmask->s6_addr32[i] = 0xffffffff; netmask->s6_addr32[i] = 0xffffffff;
else } else {
netmask->s6_addr32[i] = 0; netmask->s6_addr32[i] = 0;
}
} }
} }

View File

@ -27,8 +27,7 @@
typedef struct ndL_chunk ndL_chunk_t; typedef struct ndL_chunk ndL_chunk_t;
struct ndL_chunk struct ndL_chunk {
{
ndL_chunk_t *next; ndL_chunk_t *next;
size_t free; size_t free;
size_t size; size_t size;
@ -52,10 +51,8 @@ void *nd_alloc(size_t size)
// To keep everything properly aligned, we'll make sure it's multiple of 8. // To keep everything properly aligned, we'll make sure it's multiple of 8.
size = (size + 7U) & ~7U; size = (size + 7U) & ~7U;
for (ndL_chunk_t *chunk = ndL_chunks; chunk; chunk = chunk->next) for (ndL_chunk_t *chunk = ndL_chunks; chunk; chunk = chunk->next) {
{ if (chunk->free >= size) {
if (chunk->free >= size)
{
void *ptr = (void *)chunk + chunk->size - chunk->free; void *ptr = (void *)chunk + chunk->size - chunk->free;
chunk->free -= size; chunk->free -= size;
return ptr; return ptr;
@ -65,8 +62,9 @@ void *nd_alloc(size_t size)
ndL_chunk_t *chunk = (ndL_chunk_t *)calloc(1, ndL_alloc_size); ndL_chunk_t *chunk = (ndL_chunk_t *)calloc(1, ndL_alloc_size);
// This should never happen. // This should never happen.
if (chunk == NULL) if (chunk == NULL) {
abort(); abort();
}
chunk->next = ndL_chunks; chunk->next = ndL_chunks;
chunk->size = ndL_alloc_size; chunk->size = ndL_alloc_size;
@ -83,8 +81,7 @@ void *nd_alloc(size_t size)
void nd_alloc_cleanup() void nd_alloc_cleanup()
{ {
ND_LL_FOREACH_S(ndL_chunks, chunk, tmp, next) ND_LL_FOREACH_S (ndL_chunks, chunk, tmp, next) {
{
free(chunk); free(chunk);
} }
} }

View File

@ -36,8 +36,7 @@ int nd_conf_retrans_limit = 3;
int nd_conf_retrans_time = 1000; int nd_conf_retrans_time = 1000;
bool nd_conf_keepalive = false; bool nd_conf_keepalive = false;
typedef struct typedef struct {
{
const char *data; const char *data;
size_t offset; size_t offset;
size_t length; size_t length;
@ -49,8 +48,7 @@ typedef struct ndL_cfinfo ndL_cfinfo_t;
typedef bool (*ndL_cfcb_t)(ndL_state_t *, const ndL_cfinfo_t *, void *); typedef bool (*ndL_cfcb_t)(ndL_state_t *, const ndL_cfinfo_t *, void *);
struct ndL_cfinfo struct ndL_cfinfo {
{
const char *key; const char *key;
int scope; int scope;
int type; int type;
@ -61,26 +59,13 @@ struct ndL_cfinfo
}; };
//! Scopes. //! Scopes.
enum enum { NDL_DEFAULT, NDL_PROXY, NDL_RULE };
{
NDL_DEFAULT,
NDL_PROXY,
NDL_RULE
};
//! Configuration types. //! Configuration types.
enum enum { NDL_NONE, NDL_INT, NDL_BOOL, NDL_ADDR, NDL_IDENT };
{
NDL_NONE,
NDL_INT,
NDL_BOOL,
NDL_ADDR,
NDL_IDENT
};
//! Character classes. //! Character classes.
enum enum {
{
NDL_ALPHA = 256, // [a-zA-Z] NDL_ALPHA = 256, // [a-zA-Z]
NDL_ALNUM, // [a-zA-Z0-9] NDL_ALNUM, // [a-zA-Z0-9]
NDL_DIGIT, // [0-9] NDL_DIGIT, // [0-9]
@ -93,7 +78,7 @@ enum
static bool ndL_parse_rule(ndL_state_t *state, ndL_cfinfo_t *info, nd_proxy_t *proxy); 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_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_proxy(ndL_state_t *state, ND_UNUSED ndL_cfinfo_t *u1, ND_UNUSED void *u2);
static bool ndL_parse_mode(ndL_state_t *state, ndL_cfinfo_t *info, nd_rule_t *rule); static bool ndL_parse_mode(ndL_state_t *state, ndL_cfinfo_t *info, nd_rule_t *rule);
#pragma GCC diagnostic push #pragma GCC diagnostic push
@ -136,15 +121,15 @@ static void ndL_error(const ndL_state_t *state, const char *fmt, ...)
static char ndL_accept_one(ndL_state_t *state, int cl) static char ndL_accept_one(ndL_state_t *state, int cl)
{ {
if (state->offset >= state->length) if (state->offset >= state->length) {
return 0; return 0;
}
char ch = state->data[state->offset]; char ch = state->data[state->offset];
bool result; bool result;
switch (cl) switch (cl) {
{
case 0: case 0:
result = true; result = true;
break; break;
@ -186,16 +171,14 @@ static char ndL_accept_one(ndL_state_t *state, int cl)
break; break;
} }
if (!result) if (!result) {
return false; return false;
}
if (ch == '\n') if (ch == '\n') {
{
state->line++; state->line++;
state->column = 1; state->column = 1;
} } else {
else
{
state->column++; state->column++;
} }
@ -208,17 +191,15 @@ static bool ndL_accept_all(ndL_state_t *state, int cl, char *buf, size_t buflen)
{ {
ndL_state_t tmp = *state; ndL_state_t tmp = *state;
for (size_t i = 0; !buf || i < buflen; i++) for (size_t i = 0; !buf || i < buflen; i++) {
{
char ch = ndL_accept_one(&tmp, cl); char ch = ndL_accept_one(&tmp, cl);
if (buf) if (buf) {
buf[i] = ch; buf[i] = ch;
}
if (!ch) if (!ch) {
{ if (i > 0) {
if (i > 0)
{
*state = tmp; *state = tmp;
return true; return true;
} }
@ -234,14 +215,17 @@ static bool ndL_accept(ndL_state_t *state, const char *str, int except_cl)
{ {
ndL_state_t tmp = *state; ndL_state_t tmp = *state;
while (*str && ndL_accept_one(&tmp, *str)) while (*str && ndL_accept_one(&tmp, *str)) {
str++; str++;
}
if (*str) if (*str) {
return false; return false;
}
if (except_cl && ndL_accept_one(&tmp, except_cl)) if (except_cl && ndL_accept_one(&tmp, except_cl)) {
return false; return false;
}
*state = tmp; *state = tmp;
return true; return true;
@ -249,16 +233,16 @@ static bool ndL_accept(ndL_state_t *state, const char *str, int except_cl)
static bool ndL_accept_bool(ndL_state_t *state, bool *value) static bool ndL_accept_bool(ndL_state_t *state, bool *value)
{ {
if (ndL_accept(state, "yes", NDL_EALNM) || ndL_accept(state, "true", NDL_EALNM)) if (ndL_accept(state, "yes", NDL_EALNM) || ndL_accept(state, "true", NDL_EALNM)) {
*value = true; *value = true;
else if (ndL_accept(state, "no", NDL_EALNM) || ndL_accept(state, "false", NDL_EALNM)) } else if (ndL_accept(state, "no", NDL_EALNM) || ndL_accept(state, "false", NDL_EALNM)) {
*value = false; *value = false;
else } else {
{
// For accurate reporting of location. // For accurate reporting of location.
ndL_state_t tmp = *state; ndL_state_t tmp = *state;
if (ndL_accept_one(&tmp, NDL_XNONL) != 0) if (ndL_accept_one(&tmp, NDL_XNONL) != 0) {
return false; return false;
}
*value = true; *value = true;
} }
@ -274,17 +258,18 @@ static bool ndL_accept_int(ndL_state_t *state, int *value, int min, int max)
char buf[32]; char buf[32];
if (!ndL_accept_all(&tmp, NDL_DIGIT, buf, sizeof(buf))) if (!ndL_accept_all(&tmp, NDL_DIGIT, buf, sizeof(buf))) {
return false; return false;
}
// Trailing [A-Za-z0-9_-] are invalid. // Trailing [A-Za-z0-9_-] are invalid.
if (ndL_accept_one(&tmp, NDL_EALNM)) if (ndL_accept_one(&tmp, NDL_EALNM)) {
return false; return false;
}
long longval = strtoll(buf, NULL, 10) * n; long longval = strtoll(buf, NULL, 10) * n;
if (longval < min || longval > max) if (longval < min || longval > max) {
{
ndL_error(state, "Expected a number between %d and %d", min, max); ndL_error(state, "Expected a number between %d and %d", min, max);
return false; return false;
} }
@ -301,32 +286,25 @@ static bool ndL_eof(ndL_state_t *state)
static void ndL_skip(ndL_state_t *state, bool skip_newline) static void ndL_skip(ndL_state_t *state, bool skip_newline)
{ {
for (;;) for (;;) {
{
ndL_accept_all(state, skip_newline ? NDL_SPACE : NDL_SNONL, NULL, 0); ndL_accept_all(state, skip_newline ? NDL_SPACE : NDL_SNONL, NULL, 0);
if (ndL_accept(state, "#", 0)) if (ndL_accept(state, "#", 0)) {
{
ndL_accept_all(state, NDL_XNONL, NULL, 0); ndL_accept_all(state, NDL_XNONL, NULL, 0);
} } else if (ndL_accept(state, "/*", 0)) {
else if (ndL_accept(state, "/*", 0)) for (;;) {
{ if (ndL_eof(state)) {
for (;;)
{
if (ndL_eof(state))
{
ndL_error(state, "Expected end-of-comment before end-of-file"); ndL_error(state, "Expected end-of-comment before end-of-file");
break; break;
} }
if (ndL_accept(state, "*/", 0)) if (ndL_accept(state, "*/", 0)) {
break; break;
}
ndL_accept_one(state, 0); ndL_accept_one(state, 0);
} }
} } else {
else
{
break; break;
} }
} }
@ -338,15 +316,16 @@ static bool ndL_accept_addr(ndL_state_t *state, nd_addr_t *addr)
char buf[64]; char buf[64];
if (!ndL_accept_all(&tmp, NDL_IPV6X, buf, sizeof(buf))) if (!ndL_accept_all(&tmp, NDL_IPV6X, buf, sizeof(buf))) {
return false; return false;
}
// Make sure we don't have a trailing [A-Za-z0-9-_] // Make sure we don't have a trailing [A-Za-z0-9-_]
if (ndL_accept_one(&tmp, NDL_EALNM)) if (ndL_accept_one(&tmp, NDL_EALNM)) {
return false; return false;
}
if (inet_pton(AF_INET6, buf, addr) != 1) if (inet_pton(AF_INET6, buf, addr) != 1) {
{
ndL_error(state, "Invalid IPv6 address \"%s\"", buf); ndL_error(state, "Invalid IPv6 address \"%s\"", buf);
return false; return false;
} }
@ -359,8 +338,9 @@ static bool ndL_accept_ident(ndL_state_t *state, char *str, size_t size)
{ {
ndL_state_t tmp = *state; ndL_state_t tmp = *state;
if (!ndL_accept_all(&tmp, NDL_EALNM, str, size)) if (!ndL_accept_all(&tmp, NDL_EALNM, str, size)) {
return false; return false;
}
*state = tmp; *state = tmp;
return true; return true;
@ -372,22 +352,17 @@ static bool ndL_parse_rule(ndL_state_t *state, ND_UNUSED ndL_cfinfo_t *info, nd_
{ {
nd_rule_t *rule = nd_rule_create(proxy); nd_rule_t *rule = nd_rule_create(proxy);
if (!ndL_accept_addr(state, &rule->addr)) if (!ndL_accept_addr(state, &rule->addr)) {
{
ndL_error(state, "Expected IPv6 address"); ndL_error(state, "Expected IPv6 address");
return false; return false;
} }
if (ndL_accept(state, "/", 0)) if (ndL_accept(state, "/", 0)) {
{ if (!ndL_accept_int(state, &rule->prefix, 0, 128)) {
if (!ndL_accept_int(state, &rule->prefix, 0, 128))
{
ndL_error(state, "Expected prefix"); ndL_error(state, "Expected prefix");
return false; return false;
} }
} } else {
else
{
rule->prefix = 128; rule->prefix = 128;
} }
@ -397,17 +372,16 @@ static bool ndL_parse_rule(ndL_state_t *state, ND_UNUSED ndL_cfinfo_t *info, nd_
rule->table = 0; rule->table = 0;
#endif #endif
if (!ndL_parse_block(state, NDL_RULE, rule)) if (!ndL_parse_block(state, NDL_RULE, rule)) {
return false; return false;
}
if (rule->mode == ND_MODE_UNKNOWN) if (rule->mode == ND_MODE_UNKNOWN) {
{
ndL_error(state, "\"static\", \"auto\", or \"iface\" need to be specified"); ndL_error(state, "\"static\", \"auto\", or \"iface\" need to be specified");
return false; return false;
} }
if (rule->autowire && rule->mode != ND_MODE_IFACE) if (rule->autowire && rule->mode != ND_MODE_IFACE) {
{
ndL_error(state, "\"autowire\" may only be used in combination with \"iface\""); ndL_error(state, "\"autowire\" may only be used in combination with \"iface\"");
return false; return false;
} }
@ -417,19 +391,16 @@ static bool ndL_parse_rule(ndL_state_t *state, ND_UNUSED ndL_cfinfo_t *info, nd_
static bool ndL_parse_rewrite(ndL_state_t *state, ND_UNUSED ndL_cfinfo_t *info, 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)) if (!ndL_accept_addr(state, &rule->rewrite_tgt)) {
return false; return false;
}
if (ndL_accept(state, "/", 0)) if (ndL_accept(state, "/", 0)) {
{ if (!ndL_accept_int(state, &rule->rewrite_pflen, 0, 128)) {
if (!ndL_accept_int(state, &rule->rewrite_pflen, 0, 128))
{
ndL_error(state, "Expected prefix"); ndL_error(state, "Expected prefix");
return false; return false;
} }
} } else {
else
{
rule->rewrite_pflen = 128; rule->rewrite_pflen = 128;
} }
@ -440,36 +411,33 @@ static bool ndL_parse_proxy(ndL_state_t *state, ND_UNUSED ndL_cfinfo_t *u1, ND_U
{ {
char ifname[IF_NAMESIZE]; char ifname[IF_NAMESIZE];
if (!ndL_accept_all(state, NDL_EALNM, ifname, sizeof(ifname))) if (!ndL_accept_all(state, NDL_EALNM, ifname, sizeof(ifname))) {
{
ndL_error(state, "Expected interface name"); ndL_error(state, "Expected interface name");
return false; return false;
} }
nd_proxy_t *proxy = nd_proxy_create(ifname); nd_proxy_t *proxy = nd_proxy_create(ifname);
if (proxy == NULL) if (proxy == NULL) {
return false; return false;
}
return ndL_parse_block(state, NDL_PROXY, proxy); 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) static bool ndL_parse_mode(ndL_state_t *state, ndL_cfinfo_t *info, nd_rule_t *rule)
{ {
if (rule->mode != ND_MODE_UNKNOWN) if (rule->mode != ND_MODE_UNKNOWN) {
{
ndL_error(state, "\"static\", \"auto\" and \"iface\" are mutually exclusive"); ndL_error(state, "\"static\", \"auto\" and \"iface\" are mutually exclusive");
return false; return false;
} }
if (!strcmp(info->key, "auto")) if (!strcmp(info->key, "auto")) {
rule->mode = ND_MODE_AUTO; rule->mode = ND_MODE_AUTO;
else if (!strcmp(info->key, "static")) } else if (!strcmp(info->key, "static")) {
rule->mode = ND_MODE_STATIC; rule->mode = ND_MODE_STATIC;
else } else {
{ if (!ndL_accept_ident(state, rule->ifname, sizeof(rule->ifname))) {
if (!ndL_accept_ident(state, rule->ifname, sizeof(rule->ifname)))
{
ndL_error(state, "Expected interface name"); ndL_error(state, "Expected interface name");
return false; return false;
} }
@ -484,25 +452,22 @@ static bool ndL_parse_block(ndL_state_t *state, int scope, void *ptr)
{ {
ndL_skip(state, false); ndL_skip(state, false);
if (scope != NDL_DEFAULT && !ndL_accept_one(state, '{')) if (scope != NDL_DEFAULT && !ndL_accept_one(state, '{')) {
{
ndL_error(state, "Expected start-of-block '{'"); ndL_error(state, "Expected start-of-block '{'");
return false; return false;
} }
uint32_t bits = 0; uint32_t bits = 0;
for (;;) for (;;) {
{
ndL_skip(state, true); ndL_skip(state, true);
if (scope != NDL_DEFAULT && ndL_accept_one(state, '}')) if (scope != NDL_DEFAULT && ndL_accept_one(state, '}')) {
return true; return true;
}
if (ndL_eof(state)) if (ndL_eof(state)) {
{ if (scope != NDL_DEFAULT) {
if (scope != NDL_DEFAULT)
{
ndL_error(state, "Expected end-of-block '}'"); ndL_error(state, "Expected end-of-block '}'");
return false; return false;
} }
@ -515,24 +480,23 @@ static bool ndL_parse_block(ndL_state_t *state, int scope, void *ptr)
char key[32]; char key[32];
const ndL_state_t state_before_key = *state; const ndL_state_t state_before_key = *state;
if (!ndL_accept_ident(state, key, sizeof(key))) if (!ndL_accept_ident(state, key, sizeof(key))) {
{
nd_log_error("Expected key"); nd_log_error("Expected key");
return false; return false;
} }
ndL_skip(state, false); ndL_skip(state, false);
for (int i = 0; !found && ndL_cfinfo_table[i].key; i++) for (int i = 0; !found && ndL_cfinfo_table[i].key; i++) {
{ if (ndL_cfinfo_table[i].scope != scope) {
if (ndL_cfinfo_table[i].scope != scope)
continue; continue;
}
if (strcmp(key, ndL_cfinfo_table[i].key) != 0) if (strcmp(key, ndL_cfinfo_table[i].key) != 0) {
continue; continue;
}
if (strcmp(key, "rule") != 0 && strcmp(key, "proxy") != 0 && bits & (1 << i)) 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); ndL_error(&state_before_key, "\"%s\" has already been configured earlier in this scope", key);
return false; return false;
} }
@ -543,63 +507,56 @@ static bool ndL_parse_block(ndL_state_t *state, int scope, void *ptr)
const ndL_cfinfo_t *t = &ndL_cfinfo_table[i]; const ndL_cfinfo_t *t = &ndL_cfinfo_table[i];
const ndL_state_t state_before_value = *state; const ndL_state_t state_before_value = *state;
switch (t->type) switch (t->type) {
{
case NDL_NONE: case NDL_NONE:
break; break;
case NDL_BOOL: case NDL_BOOL:
if (!ndL_accept_bool(state, (bool *)(ptr + t->offset))) if (!ndL_accept_bool(state, (bool *)(ptr + t->offset))) {
{
ndL_error(&state_before_value, "Expected boolean value"); ndL_error(&state_before_value, "Expected boolean value");
return false; return false;
} }
break; break;
case NDL_INT: case NDL_INT:
if (!ndL_accept_int(state, (int *)(ptr + t->offset), t->min, t->max)) if (!ndL_accept_int(state, (int *)(ptr + t->offset), t->min, t->max)) {
{
ndL_error(&state_before_value, "Expected an integer"); ndL_error(&state_before_value, "Expected an integer");
return false; return false;
} }
break; break;
case NDL_ADDR: case NDL_ADDR:
if (!ndL_accept_addr(state, (nd_addr_t *)(ptr + t->offset))) if (!ndL_accept_addr(state, (nd_addr_t *)(ptr + t->offset))) {
{
ndL_error(&state_before_value, "Expected an IPv6 address"); ndL_error(&state_before_value, "Expected an IPv6 address");
return false; return false;
} }
break; break;
case NDL_IDENT: case NDL_IDENT:
if (!ndL_accept_ident(state, (char *)(ptr + t->offset), t->max)) if (!ndL_accept_ident(state, (char *)(ptr + t->offset), t->max)) {
{
ndL_error(&state_before_value, "Expected identifier"); ndL_error(&state_before_value, "Expected identifier");
return false; return false;
} }
break; break;
} }
if (t->cb) if (t->cb) {
{
ndL_skip(state, false); ndL_skip(state, false);
if (!t->cb(state, &ndL_cfinfo_table[i], ptr)) if (!t->cb(state, &ndL_cfinfo_table[i], ptr)) {
return false; return false;
}
} }
ndL_skip(state, false); ndL_skip(state, false);
if (!ndL_eof(state) && !ndL_accept_one(state, '\n')) if (!ndL_eof(state) && !ndL_accept_one(state, '\n')) {
{
ndL_error(state, "Expected newline"); ndL_error(state, "Expected newline");
return false; return false;
} }
} }
if (!found) if (!found) {
{
ndL_error(state, "Invalid configuration"); ndL_error(state, "Invalid configuration");
return false; return false;
} }
@ -610,16 +567,14 @@ bool nd_conf_load(const char *path)
{ {
FILE *fp = fopen(path, "r"); FILE *fp = fopen(path, "r");
if (fp == NULL) if (fp == NULL) {
{
nd_log_error("Failed to load configuration: %s", strerror(errno)); nd_log_error("Failed to load configuration: %s", strerror(errno));
return NULL; return NULL;
} }
struct stat stat; struct stat stat;
if (fstat(fileno(fp), &stat) < 0) if (fstat(fileno(fp), &stat) < 0) {
{
nd_log_error("Failed to determine size: %s", strerror(errno)); nd_log_error("Failed to determine size: %s", strerror(errno));
fclose(fp); fclose(fp);
return NULL; return NULL;
@ -627,8 +582,7 @@ bool nd_conf_load(const char *path)
char *buf = (char *)malloc(stat.st_size); char *buf = (char *)malloc(stat.st_size);
if (buf == NULL) if (buf == NULL) {
{
nd_log_error("Failed to allocate buffer: %s", strerror(errno)); nd_log_error("Failed to allocate buffer: %s", strerror(errno));
fclose(fp); fclose(fp);
return NULL; return NULL;
@ -636,12 +590,9 @@ bool nd_conf_load(const char *path)
bool result = false; bool result = false;
if (fread(buf, stat.st_size, 1, fp) != 1) if (fread(buf, stat.st_size, 1, fp) != 1) {
{
nd_log_error("Failed to read config: %s", strerror(errno)); nd_log_error("Failed to read config: %s", strerror(errno));
} } else {
else
{
ndL_state_t state = { .data = buf, .offset = 0, .length = stat.st_size, .column = 0, .line = 1 }; ndL_state_t state = { .data = buf, .offset = 0, .length = stat.st_size, .column = 0, .line = 1 };
// FIXME: Validate configuration // FIXME: Validate configuration

View File

@ -66,8 +66,7 @@ static nd_io_t *ndL_io;
//! Used when daemonizing to make sure the parent process does not restore these flags upon exit. //! Used when daemonizing to make sure the parent process does not restore these flags upon exit.
bool nd_iface_no_restore_flags; bool nd_iface_no_restore_flags;
typedef struct typedef struct {
{
struct ip6_hdr ip6_hdr; struct ip6_hdr ip6_hdr;
struct icmp6_hdr icmp6_hdr; struct icmp6_hdr icmp6_hdr;
} ndL_icmp6_msg_t; } ndL_icmp6_msg_t;
@ -76,37 +75,43 @@ static void ndL_handle_ns(nd_iface_t *iface, ndL_icmp6_msg_t *msg)
{ {
struct nd_neighbor_solicit *ns = (struct nd_neighbor_solicit *)&msg->icmp6_hdr; struct nd_neighbor_solicit *ns = (struct nd_neighbor_solicit *)&msg->icmp6_hdr;
if (msg->ip6_hdr.ip6_plen < sizeof(struct nd_neighbor_solicit)) if (msg->ip6_hdr.ip6_plen < sizeof(struct nd_neighbor_solicit)) {
return; return;
}
// We're not doing "proper" parsing of options here. // We're not doing "proper" parsing of options here.
if (ntohs(msg->ip6_hdr.ip6_plen) - sizeof(struct nd_neighbor_solicit) < 8) if (ntohs(msg->ip6_hdr.ip6_plen) - sizeof(struct nd_neighbor_solicit) < 8) {
return; return;
}
struct nd_opt_hdr *opt = (struct nd_opt_hdr *)((void *)ns + sizeof(struct nd_neighbor_solicit)); struct nd_opt_hdr *opt = (struct nd_opt_hdr *)((void *)ns + sizeof(struct nd_neighbor_solicit));
if (opt->nd_opt_len != 1 || opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR) if (opt->nd_opt_len != 1 || opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR) {
return; return;
}
uint8_t *src_ll = (uint8_t *)((void *)opt + 2); uint8_t *src_ll = (uint8_t *)((void *)opt + 2);
if (iface->proxy) if (iface->proxy) {
nd_proxy_handle_ns(iface->proxy, &msg->ip6_hdr.ip6_src, &msg->ip6_hdr.ip6_dst, &ns->nd_ns_target, src_ll); nd_proxy_handle_ns(iface->proxy, &msg->ip6_hdr.ip6_src, &msg->ip6_hdr.ip6_dst, &ns->nd_ns_target, src_ll);
}
} }
static void ndL_handle_na(nd_iface_t *iface, ndL_icmp6_msg_t *msg) static void ndL_handle_na(nd_iface_t *iface, ndL_icmp6_msg_t *msg)
{ {
if (msg->ip6_hdr.ip6_plen < sizeof(struct nd_neighbor_advert)) if (msg->ip6_hdr.ip6_plen < sizeof(struct nd_neighbor_advert)) {
return; return;
}
struct nd_neighbor_advert *na = (struct nd_neighbor_advert *)&msg->icmp6_hdr; struct nd_neighbor_advert *na = (struct nd_neighbor_advert *)&msg->icmp6_hdr;
nd_session_t *session; nd_session_t *session;
ND_LL_SEARCH(iface->sessions, session, next_in_iface, nd_addr_eq(&session->real_tgt, &na->nd_na_target)); ND_LL_SEARCH(iface->sessions, session, next_in_iface, nd_addr_eq(&session->real_tgt, &na->nd_na_target));
if (!session) if (!session) {
return; return;
}
nd_session_handle_na(session); nd_session_handle_na(session);
} }
@ -115,15 +120,17 @@ static uint16_t ndL_calculate_checksum(uint32_t sum, const void *data, size_t le
{ {
uint8_t *p = (uint8_t *)data; uint8_t *p = (uint8_t *)data;
for (size_t i = 0; i < length; i += 2) for (size_t i = 0; i < length; i += 2) {
{ if (i + 1 < length) {
if (i + 1 < length) sum += ntohs(*(uint16_t *)p);
sum += ntohs(*(uint16_t *)p), p += 2; p += 2;
else } else {
sum += *p++; sum += *p++;
}
if (sum > 0xffff) if (sum > 0xffff) {
sum -= 0xffff; sum -= 0xffff;
}
} }
return sum; return sum;
@ -131,8 +138,7 @@ static uint16_t ndL_calculate_checksum(uint32_t sum, const void *data, size_t le
static uint16_t ndL_calculate_icmp6_checksum(ndL_icmp6_msg_t *msg, size_t size) static uint16_t ndL_calculate_icmp6_checksum(ndL_icmp6_msg_t *msg, size_t size)
{ {
struct __attribute__((packed)) struct __attribute__((packed)) {
{
struct in6_addr src; struct in6_addr src;
struct in6_addr dst; struct in6_addr dst;
uint32_t len; uint32_t len;
@ -162,22 +168,27 @@ static void ndL_handle_packet(nd_iface_t *iface, uint8_t *buf, size_t buflen)
{ {
ndL_icmp6_msg_t *msg = (ndL_icmp6_msg_t *)buf; ndL_icmp6_msg_t *msg = (ndL_icmp6_msg_t *)buf;
if ((size_t)buflen < sizeof(ndL_icmp6_msg_t)) if ((size_t)buflen < sizeof(ndL_icmp6_msg_t)) {
return; return;
}
if ((size_t)buflen != sizeof(struct ip6_hdr) + ntohs(msg->ip6_hdr.ip6_plen)) if ((size_t)buflen != sizeof(struct ip6_hdr) + ntohs(msg->ip6_hdr.ip6_plen)) {
return; return;
}
if (msg->ip6_hdr.ip6_nxt != IPPROTO_ICMPV6) if (msg->ip6_hdr.ip6_nxt != IPPROTO_ICMPV6) {
return; return;
}
if (ndL_calculate_icmp6_checksum(msg, buflen) != msg->icmp6_hdr.icmp6_cksum) if (ndL_calculate_icmp6_checksum(msg, buflen) != msg->icmp6_hdr.icmp6_cksum) {
return; return;
}
if (msg->icmp6_hdr.icmp6_type == ND_NEIGHBOR_SOLICIT) if (msg->icmp6_hdr.icmp6_type == ND_NEIGHBOR_SOLICIT) {
ndL_handle_ns(iface, msg); ndL_handle_ns(iface, msg);
else if (msg->icmp6_hdr.icmp6_type == ND_NEIGHBOR_ADVERT) } else if (msg->icmp6_hdr.icmp6_type == ND_NEIGHBOR_ADVERT) {
ndL_handle_na(iface, msg); ndL_handle_na(iface, msg);
}
} }
#ifdef __linux__ #ifdef __linux__
@ -191,8 +202,7 @@ static void ndL_io_handler(nd_io_t *io, __attribute__((unused)) int events)
uint8_t buf[1024]; uint8_t buf[1024];
for (;;) for (;;) {
{
ssize_t len = nd_io_recv(io, (struct sockaddr *)&lladdr, sizeof(lladdr), buf, sizeof(buf)); ssize_t len = nd_io_recv(io, (struct sockaddr *)&lladdr, sizeof(lladdr), buf, sizeof(buf));
if (len == 0) if (len == 0)
@ -225,30 +235,30 @@ static void ndL_io_handler(nd_io_t *io, __attribute__((unused)) int events)
{ {
__attribute__((aligned(BPF_ALIGNMENT))) uint8_t buf[4096]; /* Depends on BIOCGBLEN */ __attribute__((aligned(BPF_ALIGNMENT))) uint8_t buf[4096]; /* Depends on BIOCGBLEN */
for (;;) for (;;) {
{
ssize_t len = nd_io_read(io, buf, sizeof(buf)); ssize_t len = nd_io_read(io, buf, sizeof(buf));
if (len < 0) if (len < 0) {
{ if (errno == EAGAIN) {
if (errno == EAGAIN)
return; return;
}
nd_log_error("%s", strerror(errno)); nd_log_error("%s", strerror(errno));
} }
for (size_t i = 0; i < (size_t)len;) for (size_t i = 0; i < (size_t)len;) {
{
struct bpf_hdr *bpf_hdr = (struct bpf_hdr *)(buf + i); struct bpf_hdr *bpf_hdr = (struct bpf_hdr *)(buf + i);
i += BPF_WORDALIGN(bpf_hdr->bh_hdrlen + bpf_hdr->bh_caplen); i += BPF_WORDALIGN(bpf_hdr->bh_hdrlen + bpf_hdr->bh_caplen);
if (bpf_hdr->bh_caplen < sizeof(struct ether_header) + sizeof(struct ip6_hdr)) if (bpf_hdr->bh_caplen < sizeof(struct ether_header) + sizeof(struct ip6_hdr)) {
continue; continue;
}
struct ether_header *eh = (struct ether_header *)((void *)bpf_hdr + bpf_hdr->bh_hdrlen); struct ether_header *eh = (struct ether_header *)((void *)bpf_hdr + bpf_hdr->bh_hdrlen);
if (eh->ether_type != ntohs(ETHERTYPE_IPV6)) if (eh->ether_type != ntohs(ETHERTYPE_IPV6)) {
continue; continue;
}
struct ip6_hdr *ip6_hdr = (struct ip6_hdr *)(eh + 1); struct ip6_hdr *ip6_hdr = (struct ip6_hdr *)(eh + 1);
@ -298,8 +308,9 @@ static bool ndL_configure_filter(nd_io_t *io)
# undef sock_filter # undef sock_filter
# undef sock_fprog # undef sock_fprog
if (ioctl(io->fd, BIOCSETF, &fprog) == -1) if (ioctl(io->fd, BIOCSETF, &fprog) == -1) {
return false; return false;
}
#endif #endif
return true; return true;
@ -309,21 +320,17 @@ nd_iface_t *nd_iface_open(const char *name, unsigned index)
{ {
char tmp_name[IF_NAMESIZE]; char tmp_name[IF_NAMESIZE];
if (!name && !index) if (!name && !index) {
return NULL; return NULL;
}
if (name && index && if_nametoindex(name) != index) if (name && index && if_nametoindex(name) != index) {
{
nd_log_error("Expected interface %s to have index %d", name, index); nd_log_error("Expected interface %s to have index %d", name, index);
return NULL; return NULL;
} } else if (name && !(index = if_nametoindex(name))) {
else if (name && !(index = if_nametoindex(name)))
{
nd_log_error("Failed to get index of interface %s: %s", name, strerror(errno)); nd_log_error("Failed to get index of interface %s: %s", name, strerror(errno));
return NULL; return NULL;
} } else if (!(name = if_indextoname(index, tmp_name))) {
else if (!(name = if_indextoname(index, tmp_name)))
{
nd_log_error("Failed to get name of interface index %d: %s", index, strerror(errno)); nd_log_error("Failed to get name of interface index %d: %s", index, strerror(errno));
return NULL; return NULL;
} }
@ -333,8 +340,7 @@ nd_iface_t *nd_iface_open(const char *name, unsigned index)
nd_iface_t *iface; nd_iface_t *iface;
ND_LL_SEARCH(ndL_first_iface, iface, next, iface->index == index); ND_LL_SEARCH(ndL_first_iface, iface, next, iface->index == index);
if (iface) if (iface) {
{
iface->refcount++; iface->refcount++;
return iface; return iface;
} }
@ -346,8 +352,7 @@ nd_iface_t *nd_iface_open(const char *name, unsigned index)
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, name); strcpy(ifr.ifr_name, name);
if (ioctl(ndL_io->fd, SIOCGIFHWADDR, &ifr) < 0) if (ioctl(ndL_io->fd, SIOCGIFHWADDR, &ifr) < 0) {
{
nd_log_error("Failed to determine link-layer address: %s", strerror(errno)); nd_log_error("Failed to determine link-layer address: %s", strerror(errno));
return NULL; return NULL;
} }
@ -357,8 +362,7 @@ nd_iface_t *nd_iface_open(const char *name, unsigned index)
nd_io_t *io = NULL; nd_io_t *io = NULL;
/* This requires a cloning bpf device, but I hope most sane systems got them. */ /* This requires a cloning bpf device, but I hope most sane systems got them. */
if (!(io = nd_io_open("/dev/bpf", O_RDWR))) if (!(io = nd_io_open("/dev/bpf", O_RDWR))) {
{
nd_log_error("Failed to open /dev/bpf"); nd_log_error("Failed to open /dev/bpf");
return NULL; return NULL;
} }
@ -368,8 +372,7 @@ nd_iface_t *nd_iface_open(const char *name, unsigned index)
/* Set buffer length. */ /* Set buffer length. */
unsigned len = 4096; /* TODO: Configure */ unsigned len = 4096; /* TODO: Configure */
if (ioctl(io->fd, BIOCSBLEN, &len) < 0) if (ioctl(io->fd, BIOCSBLEN, &len) < 0) {
{
nd_log_error("BIOCSBLEN: %s", strerror(errno)); nd_log_error("BIOCSBLEN: %s", strerror(errno));
nd_io_close(io); nd_io_close(io);
return NULL; return NULL;
@ -379,8 +382,7 @@ nd_iface_t *nd_iface_open(const char *name, unsigned index)
struct ifreq ifr; struct ifreq ifr;
strcpy(ifr.ifr_name, name); strcpy(ifr.ifr_name, name);
if (ioctl(io->fd, BIOCSETIF, &ifr) < 0) if (ioctl(io->fd, BIOCSETIF, &ifr) < 0) {
{
nd_log_error("Failed to bind to interface: %s", strerror(errno)); nd_log_error("Failed to bind to interface: %s", strerror(errno));
nd_io_close(io); nd_io_close(io);
return NULL; return NULL;
@ -389,8 +391,7 @@ nd_iface_t *nd_iface_open(const char *name, unsigned index)
/* Immediate */ /* Immediate */
uint32_t enable = 1; uint32_t enable = 1;
if (ioctl(io->fd, BIOCIMMEDIATE, &enable) < 0) if (ioctl(io->fd, BIOCIMMEDIATE, &enable) < 0) {
{
nd_log_error("BIOCIMMEDIATE: %s", strerror(errno)); nd_log_error("BIOCIMMEDIATE: %s", strerror(errno));
nd_io_close(io); nd_io_close(io);
return NULL; return NULL;
@ -402,15 +403,13 @@ nd_iface_t *nd_iface_open(const char *name, unsigned index)
uint8_t sysctl_buf[512]; uint8_t sysctl_buf[512];
size_t sysctl_buflen = sizeof(sysctl_buf); size_t sysctl_buflen = sizeof(sysctl_buf);
if (sysctl(mib, 6, sysctl_buf, &sysctl_buflen, NULL, 0) == -1) if (sysctl(mib, 6, sysctl_buf, &sysctl_buflen, NULL, 0) == -1) {
{
nd_log_error("Failed to determine link-layer address: %s", strerror(errno)); nd_log_error("Failed to determine link-layer address: %s", strerror(errno));
nd_io_close(io); nd_io_close(io);
return NULL; return NULL;
} }
if (!ndL_configure_filter(io)) if (!ndL_configure_filter(io)) {
{
nd_log_error("Could not configure filter: %s", strerror(errno)); nd_log_error("Could not configure filter: %s", strerror(errno));
nd_io_close(io); nd_io_close(io);
return NULL; return NULL;
@ -421,10 +420,11 @@ nd_iface_t *nd_iface_open(const char *name, unsigned index)
iface = ndL_first_free_iface; iface = ndL_first_free_iface;
if (iface) if (iface) {
ND_LL_DELETE(ndL_first_free_iface, iface, next); ND_LL_DELETE(ndL_first_free_iface, iface, next);
else } else {
iface = ND_ALLOC(nd_iface_t); iface = ND_ALLOC(nd_iface_t);
}
memset(iface, 0, sizeof(nd_iface_t)); memset(iface, 0, sizeof(nd_iface_t));
@ -450,15 +450,17 @@ nd_iface_t *nd_iface_open(const char *name, unsigned index)
void nd_iface_close(nd_iface_t *iface) void nd_iface_close(nd_iface_t *iface)
{ {
if (--iface->refcount > 0) if (--iface->refcount > 0) {
return; return;
}
if (!nd_iface_no_restore_flags) if (!nd_iface_no_restore_flags) {
{ if (iface->old_promisc >= 0) {
if (iface->old_promisc >= 0)
nd_iface_set_promisc(iface, iface->old_promisc); nd_iface_set_promisc(iface, iface->old_promisc);
if (iface->old_allmulti >= 0) }
if (iface->old_allmulti >= 0) {
nd_iface_set_allmulti(iface, iface->old_allmulti); nd_iface_set_allmulti(iface, iface->old_allmulti);
}
} }
#ifndef __linux__ #ifndef __linux__
@ -518,8 +520,7 @@ static ssize_t ndL_send_icmp6(nd_iface_t *ifa, ndL_icmp6_msg_t *msg, size_t size
ssize_t nd_iface_write_na(nd_iface_t *iface, nd_addr_t *dst, uint8_t *dst_ll, nd_addr_t *tgt, bool router) ssize_t nd_iface_write_na(nd_iface_t *iface, nd_addr_t *dst, uint8_t *dst_ll, nd_addr_t *tgt, bool router)
{ {
struct struct {
{
struct ip6_hdr ip; struct ip6_hdr ip;
struct nd_neighbor_advert na; struct nd_neighbor_advert na;
struct nd_opt_hdr opt; struct nd_opt_hdr opt;
@ -534,11 +535,13 @@ ssize_t nd_iface_write_na(nd_iface_t *iface, nd_addr_t *dst, uint8_t *dst_ll, nd
msg.na.nd_na_type = ND_NEIGHBOR_ADVERT; msg.na.nd_na_type = ND_NEIGHBOR_ADVERT;
msg.na.nd_na_target = *tgt; msg.na.nd_na_target = *tgt;
if (nd_addr_is_multicast(dst)) if (nd_addr_is_multicast(dst)) {
msg.na.nd_na_flags_reserved |= ND_NA_FLAG_SOLICITED; msg.na.nd_na_flags_reserved |= ND_NA_FLAG_SOLICITED;
}
if (router) if (router) {
msg.na.nd_na_flags_reserved |= ND_NA_FLAG_ROUTER; msg.na.nd_na_flags_reserved |= ND_NA_FLAG_ROUTER;
}
msg.opt.nd_opt_type = ND_OPT_TARGET_LINKADDR; msg.opt.nd_opt_type = ND_OPT_TARGET_LINKADDR;
msg.opt.nd_opt_len = 1; msg.opt.nd_opt_len = 1;
@ -555,8 +558,7 @@ ssize_t nd_iface_write_na(nd_iface_t *iface, nd_addr_t *dst, uint8_t *dst_ll, nd
ssize_t nd_iface_write_ns(nd_iface_t *ifa, nd_addr_t *tgt) ssize_t nd_iface_write_ns(nd_iface_t *ifa, nd_addr_t *tgt)
{ {
struct struct {
{
struct ip6_hdr ip; struct ip6_hdr ip;
struct nd_neighbor_solicit ns; struct nd_neighbor_solicit ns;
struct nd_opt_hdr opt; struct nd_opt_hdr opt;
@ -595,8 +597,7 @@ bool nd_iface_startup()
if (!(ndL_io = nd_io_socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IPV6)))) if (!(ndL_io = nd_io_socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IPV6))))
return false; return false;
if (!ndL_configure_filter(ndL_io)) if (!ndL_configure_filter(ndL_io)) {
{
nd_io_close(ndL_io); nd_io_close(ndL_io);
ndL_io = NULL; ndL_io = NULL;
nd_log_error("Failed to configure BPF: %s", strerror(errno)); nd_log_error("Failed to configure BPF: %s", strerror(errno));
@ -616,25 +617,26 @@ bool nd_iface_set_allmulti(nd_iface_t *iface, bool on)
struct ifreq ifr; struct ifreq ifr;
memcpy(ifr.ifr_name, iface->name, IFNAMSIZ); memcpy(ifr.ifr_name, iface->name, IFNAMSIZ);
if (ioctl(ndL_io->fd, SIOCGIFFLAGS, &ifr) < 0) if (ioctl(ndL_io->fd, SIOCGIFFLAGS, &ifr) < 0) {
{
nd_log_error("Failed to get interface flags: %s", strerror(errno)); nd_log_error("Failed to get interface flags: %s", strerror(errno));
return false; return false;
} }
if (iface->old_allmulti < 0) if (iface->old_allmulti < 0) {
iface->old_allmulti = (ifr.ifr_flags & IFF_ALLMULTI) != 0; iface->old_allmulti = (ifr.ifr_flags & IFF_ALLMULTI) != 0;
}
if (on == ((ifr.ifr_flags & IFF_ALLMULTI) != 0)) if (on == ((ifr.ifr_flags & IFF_ALLMULTI) != 0)) {
return true; return true;
}
if (on) if (on) {
ifr.ifr_flags |= IFF_ALLMULTI; ifr.ifr_flags |= IFF_ALLMULTI;
else } else {
ifr.ifr_flags &= ~IFF_ALLMULTI; ifr.ifr_flags &= ~IFF_ALLMULTI;
}
if (ioctl(ndL_io->fd, SIOCSIFFLAGS, &ifr) < 0) if (ioctl(ndL_io->fd, SIOCSIFFLAGS, &ifr) < 0) {
{
nd_log_error("Failed to set interface flags: %s", strerror(errno)); nd_log_error("Failed to set interface flags: %s", strerror(errno));
return false; return false;
} }
@ -649,25 +651,26 @@ bool nd_iface_set_promisc(nd_iface_t *iface, bool on)
struct ifreq ifr; struct ifreq ifr;
memcpy(ifr.ifr_name, iface->name, IFNAMSIZ); memcpy(ifr.ifr_name, iface->name, IFNAMSIZ);
if (ioctl(ndL_io->fd, SIOCGIFFLAGS, &ifr) < 0) if (ioctl(ndL_io->fd, SIOCGIFFLAGS, &ifr) < 0) {
{
nd_log_error("Failed to get interface flags: %s", strerror(errno)); nd_log_error("Failed to get interface flags: %s", strerror(errno));
return false; return false;
} }
if (iface->old_promisc < 0) if (iface->old_promisc < 0) {
iface->old_promisc = (ifr.ifr_flags & IFF_PROMISC) != 0; iface->old_promisc = (ifr.ifr_flags & IFF_PROMISC) != 0;
}
if (on == ((ifr.ifr_flags & IFF_PROMISC) != 0)) if (on == ((ifr.ifr_flags & IFF_PROMISC) != 0)) {
return true; return true;
}
if (on) if (on) {
ifr.ifr_flags |= IFF_PROMISC; ifr.ifr_flags |= IFF_PROMISC;
else } else {
ifr.ifr_flags &= ~IFF_PROMISC; ifr.ifr_flags &= ~IFF_PROMISC;
}
if (ioctl(ndL_io->fd, SIOCSIFFLAGS, &ifr) < 0) if (ioctl(ndL_io->fd, SIOCSIFFLAGS, &ifr) < 0) {
{
nd_log_error("Failed to set interface flags: %s", strerror(errno)); nd_log_error("Failed to set interface flags: %s", strerror(errno));
return false; return false;
} }
@ -677,12 +680,12 @@ bool nd_iface_set_promisc(nd_iface_t *iface, bool on)
void nd_iface_cleanup() void nd_iface_cleanup()
{ {
ND_LL_FOREACH_S(ndL_first_iface, iface, tmp, next) ND_LL_FOREACH_S (ndL_first_iface, iface, tmp, next) {
{
iface->refcount = 1; iface->refcount = 1;
nd_iface_close(iface); nd_iface_close(iface);
} }
if (ndL_io) if (ndL_io) {
nd_io_close(ndL_io); nd_io_close(ndL_io);
}
} }

View File

@ -21,8 +21,7 @@
#include <net/if.h> #include <net/if.h>
struct nd_iface struct nd_iface {
{
nd_iface_t *next; nd_iface_t *next;
int refcount; int refcount;

View File

@ -60,20 +60,18 @@ static void ndL_refresh_pollfds()
ND_LL_COUNT(ndL_first_io, count, next); ND_LL_COUNT(ndL_first_io, count, next);
if (count > ndL_pollfds_size) if (count > ndL_pollfds_size) {
{
int new_pollfds_size = count * 2; int new_pollfds_size = count * 2;
ndL_pollfds = (struct pollfd *)realloc(ndL_pollfds == ndL_static_pollfds ? NULL : ndL_pollfds, ndL_pollfds = (struct pollfd *)realloc(ndL_pollfds == ndL_static_pollfds ? NULL : ndL_pollfds,
new_pollfds_size * sizeof(struct pollfd)); new_pollfds_size * sizeof(struct pollfd));
ndL_pollfds_size = new_pollfds_size; ndL_pollfds_size = new_pollfds_size;
} }
int index = 0; int index = 0;
ND_LL_FOREACH(ndL_first_io, io, next) ND_LL_FOREACH (ndL_first_io, io, next) {
{
ndL_pollfds[index].fd = io->fd; ndL_pollfds[index].fd = io->fd;
ndL_pollfds[index].revents = 0; ndL_pollfds[index].revents = 0;
ndL_pollfds[index].events = POLLIN; ndL_pollfds[index].events = POLLIN;
@ -88,15 +86,13 @@ static nd_io_t *ndL_create(int fd)
{ {
int flags = fcntl(fd, F_GETFL, 0); int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) if (flags == -1) {
{
nd_log_error("Could not read flags: %s", strerror(errno)); nd_log_error("Could not read flags: %s", strerror(errno));
close(fd); close(fd);
return false; return false;
} }
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
{
nd_log_error("Could not set flags: %s", strerror(errno)); nd_log_error("Could not set flags: %s", strerror(errno));
close(fd); close(fd);
return false; return false;
@ -104,10 +100,11 @@ static nd_io_t *ndL_create(int fd)
nd_io_t *io = ndL_first_free_io; nd_io_t *io = ndL_first_free_io;
if (io) if (io) {
ND_LL_DELETE(ndL_first_free_io, io, next); ND_LL_DELETE(ndL_first_free_io, io, next);
else } else {
io = ND_ALLOC(nd_io_t); io = ND_ALLOC(nd_io_t);
}
ND_LL_PREPEND(ndL_first_io, io, next); ND_LL_PREPEND(ndL_first_io, io, next);
@ -116,16 +113,14 @@ static nd_io_t *ndL_create(int fd)
io->handler = NULL; io->handler = NULL;
#ifndef NDPPD_NO_USE_EPOLL #ifndef NDPPD_NO_USE_EPOLL
if (ndL_epoll_fd <= 0 && (ndL_epoll_fd = epoll_create(1)) < 0) if (ndL_epoll_fd <= 0 && (ndL_epoll_fd = epoll_create(1)) < 0) {
{
nd_log_error("epoll_create() failed: %s", strerror(errno)); nd_log_error("epoll_create() failed: %s", strerror(errno));
return NULL; return NULL;
} }
struct epoll_event event = { .events = EPOLLIN, .data.ptr = io }; struct epoll_event event = { .events = EPOLLIN, .data.ptr = io };
if (epoll_ctl(ndL_epoll_fd, EPOLL_CTL_ADD, io->fd, &event) < 0) if (epoll_ctl(ndL_epoll_fd, EPOLL_CTL_ADD, io->fd, &event) < 0) {
{
nd_log_error("epoll_ctl() failed: %s", strerror(errno)); nd_log_error("epoll_ctl() failed: %s", strerror(errno));
return NULL; return NULL;
} }
@ -141,8 +136,7 @@ nd_io_t *nd_io_socket(int domain, int type, int protocol)
{ {
int fd = socket(domain, type, protocol); int fd = socket(domain, type, protocol);
if (fd == -1) if (fd == -1) {
{
nd_log_error("nd_io_socket(): Could not create socket: %s", strerror(errno)); nd_log_error("nd_io_socket(): Could not create socket: %s", strerror(errno));
return NULL; return NULL;
} }
@ -154,8 +148,9 @@ nd_io_t *nd_io_open(const char *file, int oflag)
{ {
int fd = open(file, oflag); int fd = open(file, oflag);
if (fd == -1) if (fd == -1) {
return NULL; return NULL;
}
return ndL_create(fd); return ndL_create(fd);
} }
@ -186,8 +181,7 @@ ssize_t nd_io_send(nd_io_t *io, const struct sockaddr *addr, size_t addrlen, con
ssize_t len; ssize_t len;
if ((len = sendmsg(io->fd, &mhdr, 0)) < 0) if ((len = sendmsg(io->fd, &mhdr, 0)) < 0) {
{
nd_log_error("nd_sio_send() failed: %s", strerror(errno)); nd_log_error("nd_sio_send() failed: %s", strerror(errno));
return -1; return -1;
} }
@ -210,10 +204,10 @@ ssize_t nd_io_recv(nd_io_t *io, struct sockaddr *addr, size_t addrlen, void *msg
int len; int len;
if ((len = recvmsg(io->fd, &mhdr, 0)) < 0) if ((len = recvmsg(io->fd, &mhdr, 0)) < 0) {
{ if (errno != EAGAIN) {
if (errno != EAGAIN)
nd_log_error("nd_sio_recv() failed: %s", strerror(errno)); nd_log_error("nd_sio_recv() failed: %s", strerror(errno));
}
return -1; return -1;
} }
@ -229,8 +223,9 @@ ssize_t nd_io_read(nd_io_t *io, void *buf, size_t count)
ssize_t nd_io_write(nd_io_t *io, void *buf, size_t count) ssize_t nd_io_write(nd_io_t *io, void *buf, size_t count)
{ {
ssize_t len = write(io->fd, buf, count); ssize_t len = write(io->fd, buf, count);
if (len < 0) if (len < 0) {
nd_log_error("err: %s", strerror(errno)); nd_log_error("err: %s", strerror(errno));
}
return len; return len;
} }
@ -246,45 +241,43 @@ bool nd_io_poll()
int count = epoll_wait(ndL_epoll_fd, events, 8, 250); int count = epoll_wait(ndL_epoll_fd, events, 8, 250);
if (count < 0) if (count < 0) {
{
nd_log_error("epoll() failed: %s", strerror(errno)); nd_log_error("epoll() failed: %s", strerror(errno));
return false; return false;
} }
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++) {
{
nd_io_t *io = (nd_io_t *)events[i].data.ptr; nd_io_t *io = (nd_io_t *)events[i].data.ptr;
if (io->handler) if (io->handler)
io->handler(io, events[i].events); io->handler(io, events[i].events);
} }
#else #else
if (ndL_dirty) if (ndL_dirty) {
{
ndL_refresh_pollfds(); ndL_refresh_pollfds();
ndL_dirty = false; ndL_dirty = false;
} }
int len = poll(ndL_pollfds, ndL_pollfds_count, 250); int len = poll(ndL_pollfds, ndL_pollfds_count, 250);
if (len < 0) if (len < 0) {
return false; return false;
}
if (len == 0) if (len == 0) {
return true; return true;
}
for (int i = 0; i < ndL_pollfds_count; i++) for (int i = 0; i < ndL_pollfds_count; i++) {
{ if (ndL_pollfds[i].revents == 0) {
if (ndL_pollfds[i].revents == 0)
continue; continue;
}
ND_LL_FOREACH(ndL_first_io, io, next) ND_LL_FOREACH (ndL_first_io, io, next) {
{ if (io->fd == ndL_pollfds[i].fd) {
if (io->fd == ndL_pollfds[i].fd) if (io->handler != NULL) {
{
if (io->handler != NULL)
io->handler(io, ndL_pollfds[i].revents); io->handler(io, ndL_pollfds[i].revents);
}
break; break;
} }
@ -297,14 +290,12 @@ bool nd_io_poll()
void nd_io_cleanup() void nd_io_cleanup()
{ {
ND_LL_FOREACH_S(ndL_first_io, sio, tmp, next) ND_LL_FOREACH_S (ndL_first_io, sio, tmp, next) {
{
nd_io_close(sio); nd_io_close(sio);
} }
#ifndef NDPPD_NO_USE_EPOLL #ifndef NDPPD_NO_USE_EPOLL
if (ndL_epoll_fd > 0) if (ndL_epoll_fd > 0) {
{
close(ndL_epoll_fd); close(ndL_epoll_fd);
ndL_epoll_fd = 0; ndL_epoll_fd = 0;
} }

View File

@ -21,8 +21,7 @@
typedef void(nd_io_handler_t)(nd_io_t *io, int events); typedef void(nd_io_handler_t)(nd_io_t *io, int events);
struct nd_io struct nd_io {
{
nd_io_t *next; nd_io_t *next;
int fd; int fd;
uintptr_t data; uintptr_t data;

View File

@ -31,8 +31,9 @@ bool nd_opt_syslog;
static void ndL_open_syslog() static void ndL_open_syslog()
{ {
if (ndL_syslog_opened) if (ndL_syslog_opened) {
return; return;
}
setlogmask(LOG_UPTO(LOG_DEBUG)); setlogmask(LOG_UPTO(LOG_DEBUG));
openlog("ndppd", LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_DAEMON); openlog("ndppd", LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_DAEMON);
@ -43,29 +44,29 @@ void nd_log_printf(nd_loglevel_t level, const char *fmt, ...)
{ {
assert(level >= 0 && level <= ND_LOG_TRACE); assert(level >= 0 && level <= ND_LOG_TRACE);
if (level > nd_opt_verbosity) if (level > nd_opt_verbosity) {
return; return;
}
if (nd_daemonized || nd_opt_syslog) if (nd_daemonized || nd_opt_syslog) {
ndL_open_syslog(); ndL_open_syslog();
}
char buf[512]; char buf[512];
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
if (vsnprintf(buf, sizeof(buf), fmt, va) < 0) if (vsnprintf(buf, sizeof(buf), fmt, va) < 0) {
abort(); abort();
}
va_end(va); va_end(va);
if (ndL_syslog_opened) if (ndL_syslog_opened) {
{
const int pris[] = { LOG_ERR, LOG_INFO, LOG_DEBUG, LOG_DEBUG }; const int pris[] = { LOG_ERR, LOG_INFO, LOG_DEBUG, LOG_DEBUG };
syslog(pris[level], "%s", buf); syslog(pris[level], "%s", buf);
} } else {
else
{
const char *names[] = { "error", "info", "debug", "trace" }; const char *names[] = { "error", "info", "debug", "trace" };
time_t time = nd_current_time / 1000; time_t time = nd_current_time / 1000;

View File

@ -19,13 +19,7 @@
#include <stdbool.h> #include <stdbool.h>
typedef enum typedef enum { ND_LOG_ERROR, ND_LOG_INFO, ND_LOG_DEBUG, ND_LOG_TRACE } nd_loglevel_t;
{
ND_LOG_ERROR,
ND_LOG_INFO,
ND_LOG_DEBUG,
ND_LOG_TRACE
} nd_loglevel_t;
extern nd_loglevel_t nd_opt_verbosity; extern nd_loglevel_t nd_opt_verbosity;
extern bool nd_opt_syslog; extern bool nd_opt_syslog;

View File

@ -51,10 +51,10 @@ static bool ndL_check_pidfile()
{ {
int fd = open(nd_opt_pidfile_path, O_RDWR); int fd = open(nd_opt_pidfile_path, O_RDWR);
if (fd == -1) if (fd == -1) {
{ if (errno == ENOENT) {
if (errno == ENOENT)
return true; return true;
}
return false; return false;
} }
@ -68,32 +68,31 @@ static bool ndL_daemonize()
{ {
int fd = open(nd_opt_pidfile_path, O_WRONLY | O_CREAT, 0644); int fd = open(nd_opt_pidfile_path, O_WRONLY | O_CREAT, 0644);
if (fd == -1) if (fd == -1) {
return false; return false;
}
if (flock(fd, LOCK_EX | LOCK_NB) < 0) if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
{
close(fd); close(fd);
return false; return false;
} }
pid_t pid = fork(); pid_t pid = fork();
if (pid < 0) if (pid < 0) {
{
// logger::error() << "Failed to fork during daemonize: " << logger::err(); // logger::error() << "Failed to fork during daemonize: " << logger::err();
return false; return false;
} }
if (pid > 0) if (pid > 0) {
{
char buf[21]; char buf[21];
int len = snprintf(buf, sizeof(buf), "%d", pid); int len = snprintf(buf, sizeof(buf), "%d", pid);
if (ftruncate(fd, 0) == -1) if (ftruncate(fd, 0) == -1) {
nd_log_error("Failed to write PID file: ftruncate(): %s", strerror(errno)); nd_log_error("Failed to write PID file: ftruncate(): %s", strerror(errno));
else if (write(fd, buf, len) != 0) } else if (write(fd, buf, len) != 0) {
nd_log_error("Failed to write PID file: write(): %s", strerror(errno)); nd_log_error("Failed to write PID file: write(): %s", strerror(errno));
}
nd_iface_no_restore_flags = true; nd_iface_no_restore_flags = true;
exit(0); exit(0);
@ -102,14 +101,12 @@ static bool ndL_daemonize()
umask(0); umask(0);
pid_t sid = setsid(); pid_t sid = setsid();
if (sid < 0) if (sid < 0) {
{
// logger::error() << "Failed to setsid during daemonize: " << logger::err(); // logger::error() << "Failed to setsid during daemonize: " << logger::err();
return false; return false;
} }
if (chdir("/") < 0) if (chdir("/") < 0) {
{
// logger::error() << "Failed to change path during daemonize: " << logger::err(); // logger::error() << "Failed to change path during daemonize: " << logger::err();
return false; return false;
} }
@ -144,10 +141,8 @@ int main(int argc, char *argv[])
{ "syslog", 0, 0, 1 }, { "pidfile", 1, 0, 'p' }, { NULL, 0, 0, 0 }, { "syslog", 0, 0, 1 }, { "pidfile", 1, 0, 'p' }, { NULL, 0, 0, 0 },
}; };
for (int ch; (ch = getopt_long(argc, argv, "c:dp:v", long_options, NULL)) != -1;) for (int ch; (ch = getopt_long(argc, argv, "c:dp:v", long_options, NULL)) != -1;) {
{ switch (ch) {
switch (ch)
{
case 'c': case 'c':
nd_opt_config_path = nd_strdup(optarg); nd_opt_config_path = nd_strdup(optarg);
break; break;
@ -157,8 +152,9 @@ int main(int argc, char *argv[])
break; break;
case 'v': case 'v':
if (nd_opt_verbosity < ND_LOG_ERROR) if (nd_opt_verbosity < ND_LOG_ERROR) {
nd_opt_verbosity++; nd_opt_verbosity++;
}
break; break;
case 'p': case 'p':
@ -180,49 +176,52 @@ int main(int argc, char *argv[])
nd_log_info("ndppd " NDPPD_VERSION); nd_log_info("ndppd " NDPPD_VERSION);
if (nd_opt_pidfile_path && !ndL_check_pidfile()) if (nd_opt_pidfile_path && !ndL_check_pidfile()) {
{
nd_log_error("Failed to lock pidfile. Is ndppd already running?"); nd_log_error("Failed to lock pidfile. Is ndppd already running?");
return -1; return -1;
} }
if (nd_opt_config_path == NULL) if (nd_opt_config_path == NULL) {
nd_opt_config_path = NDPPD_CONFIG_PATH; nd_opt_config_path = NDPPD_CONFIG_PATH;
}
nd_log_info("Loading configuration \"%s\"...", nd_opt_config_path); nd_log_info("Loading configuration \"%s\"...", nd_opt_config_path);
if (!nd_conf_load(nd_opt_config_path)) if (!nd_conf_load(nd_opt_config_path)) {
return -1; return -1;
}
if (!nd_iface_startup()) if (!nd_iface_startup()) {
return -1; return -1;
}
if (!nd_proxy_startup()) if (!nd_proxy_startup()) {
return -1; return -1;
}
if (!nd_rt_open()) if (!nd_rt_open()) {
return -1; return -1;
}
if (nd_opt_daemonize && !ndL_daemonize()) if (nd_opt_daemonize && !ndL_daemonize()) {
return -1; return -1;
}
nd_rt_query_routes(); nd_rt_query_routes();
bool querying_routes = true; bool querying_routes = true;
while (1) while (1) {
{ if (nd_current_time >= nd_rt_dump_timeout) {
if (nd_current_time >= nd_rt_dump_timeout)
nd_rt_dump_timeout = 0; nd_rt_dump_timeout = 0;
}
if (querying_routes && !nd_rt_dump_timeout) if (querying_routes && !nd_rt_dump_timeout) {
{
querying_routes = false; querying_routes = false;
nl_rt_remove_owned_routes(); nl_rt_remove_owned_routes();
nd_rt_query_addresses(); nd_rt_query_addresses();
} }
if (!nd_io_poll()) if (!nd_io_poll()) {
{
/* TODO: Error */ /* TODO: Error */
break; break;
} }

View File

@ -40,15 +40,13 @@ extern bool nd_opt_daemonize;
#define ND_ALIGNED(x) __attribute((aligned(x))) #define ND_ALIGNED(x) __attribute((aligned(x)))
#define ND_LL_PREPEND(head, el, next) \ #define ND_LL_PREPEND(head, el, next) \
do \ do { \
{ \
(el)->next = (head); \ (el)->next = (head); \
(head) = (el); \ (head) = (el); \
} while (0) } while (0)
#define ND_LL_DELETE(head, el, next) \ #define ND_LL_DELETE(head, el, next) \
do \ do { \
{ \
__typeof(el) _last = (head); \ __typeof(el) _last = (head); \
while (_last != NULL && _last->next != (el)) \ while (_last != NULL && _last->next != (el)) \
_last = _last->next; \ _last = _last->next; \
@ -59,8 +57,7 @@ extern bool nd_opt_daemonize;
} while (0) } while (0)
#define ND_LL_COUNT(head, count, next) \ #define ND_LL_COUNT(head, count, next) \
do \ do { \
{ \
(count) = 0; \ (count) = 0; \
for (__typeof(head) _el = (head); _el; _el = _el->next) \ for (__typeof(head) _el = (head); _el; _el = _el->next) \
(count)++; \ (count)++; \
@ -78,8 +75,7 @@ extern bool nd_opt_daemonize;
#define ND_LL_FOREACH_NODEF(head, el, next) for ((el) = (head); (el); (el) = (el)->next) #define ND_LL_FOREACH_NODEF(head, el, next) for ((el) = (head); (el); (el) = (el)->next)
#define ND_LL_SEARCH(head, el, next, pred) \ #define ND_LL_SEARCH(head, el, next, pred) \
do \ do { \
{ \
for (el = (head); el && !(pred); el = el->next) \ for (el = (head); el && !(pred); el = el->next) \
; \ ; \
} while (0) } while (0)

View File

@ -39,8 +39,7 @@ nd_proxy_t *nd_proxy_create(const char *ifname)
ND_LL_SEARCH(ndL_proxies, proxy, next, !strcmp(proxy->ifname, ifname)); ND_LL_SEARCH(ndL_proxies, proxy, next, !strcmp(proxy->ifname, ifname));
if (proxy) if (proxy) {
{
nd_log_error("Proxy already exists for interface \"%s\"", ifname); nd_log_error("Proxy already exists for interface \"%s\"", ifname);
return NULL; return NULL;
} }
@ -66,10 +65,8 @@ void nd_proxy_handle_ns(nd_proxy_t *proxy, nd_addr_t *src, nd_addr_t *dst, nd_ad
nd_session_t *session; nd_session_t *session;
ND_LL_FOREACH_NODEF(proxy->sessions, session, next_in_proxy) ND_LL_FOREACH_NODEF (proxy->sessions, session, next_in_proxy) {
{ if (nd_addr_eq(&session->tgt, tgt)) {
if (nd_addr_eq(&session->tgt, tgt))
{
nd_session_handle_ns(session, src, src_ll); nd_session_handle_ns(session, src, src_ll);
return; return;
} }
@ -81,18 +78,17 @@ void nd_proxy_handle_ns(nd_proxy_t *proxy, nd_addr_t *src, nd_addr_t *dst, nd_ad
nd_rule_t *rule; nd_rule_t *rule;
ND_LL_SEARCH(proxy->rules, rule, next, nd_addr_match(&rule->addr, tgt, rule->prefix)); ND_LL_SEARCH(proxy->rules, rule, next, nd_addr_match(&rule->addr, tgt, rule->prefix));
if (!rule) if (!rule) {
return; return;
}
nd_session_handle_ns(nd_session_create(rule, tgt), src, src_ll); nd_session_handle_ns(nd_session_create(rule, tgt), src, src_ll);
} }
void nd_proxy_update_all() void nd_proxy_update_all()
{ {
ND_LL_FOREACH(ndL_proxies, proxy, next) ND_LL_FOREACH (ndL_proxies, proxy, next) {
{ ND_LL_FOREACH_S (proxy->sessions, session, tmp, next_in_proxy) {
ND_LL_FOREACH_S(proxy->sessions, session, tmp, next_in_proxy)
{
nd_session_update(session); nd_session_update(session);
} }
} }
@ -100,10 +96,10 @@ void nd_proxy_update_all()
bool nd_proxy_startup() bool nd_proxy_startup()
{ {
ND_LL_FOREACH(ndL_proxies, proxy, next) ND_LL_FOREACH (ndL_proxies, proxy, next) {
{ if (!(proxy->iface = nd_iface_open(proxy->ifname, 0))) {
if (!(proxy->iface = nd_iface_open(proxy->ifname, 0)))
return false; return false;
}
proxy->iface->proxy = proxy; proxy->iface->proxy = proxy;
@ -114,10 +110,10 @@ bool nd_proxy_startup()
nd_iface_set_allmulti(proxy->iface, true); nd_iface_set_allmulti(proxy->iface, true);
#endif #endif
ND_LL_FOREACH(proxy->rules, rule, next) ND_LL_FOREACH (proxy->rules, rule, next) {
{ if (rule->ifname[0] && !(rule->iface = nd_iface_open(rule->ifname, 0))) {
if (rule->ifname[0] && !(rule->iface = nd_iface_open(rule->ifname, 0)))
return false; return false;
}
} }
} }

View File

@ -21,8 +21,7 @@
#include "ndppd.h" #include "ndppd.h"
struct nd_proxy struct nd_proxy {
{
nd_proxy_t *next; nd_proxy_t *next;
char ifname[IF_NAMESIZE]; char ifname[IF_NAMESIZE];

189
src/rt.c
View File

@ -60,17 +60,18 @@ static void ndL_new_route(nd_rt_route_t *route)
{ {
nd_rt_route_t *new_route; nd_rt_route_t *new_route;
ND_LL_FOREACH_NODEF(ndL_routes, new_route, next) ND_LL_FOREACH_NODEF (ndL_routes, new_route, next) {
{
if ((nd_addr_eq(&new_route->dst, &route->dst) && new_route->pflen == route->pflen && if ((nd_addr_eq(&new_route->dst, &route->dst) && new_route->pflen == route->pflen &&
new_route->table == route->table)) new_route->table == route->table)) {
return; return;
}
} }
if ((new_route = ndL_free_routes)) if ((new_route = ndL_free_routes)) {
ND_LL_DELETE(ndL_free_routes, new_route, next); ND_LL_DELETE(ndL_free_routes, new_route, next);
else } else {
new_route = ND_ALLOC(nd_rt_route_t); new_route = ND_ALLOC(nd_rt_route_t);
}
*new_route = *route; *new_route = *route;
@ -78,21 +79,18 @@ static void ndL_new_route(nd_rt_route_t *route)
nd_rt_route_t *prev = NULL; nd_rt_route_t *prev = NULL;
ND_LL_FOREACH(ndL_routes, cur, next) ND_LL_FOREACH (ndL_routes, cur, next) {
{ if (new_route->pflen >= cur->pflen) {
if (new_route->pflen >= cur->pflen)
break; break;
}
prev = cur; prev = cur;
} }
if (prev) if (prev) {
{
new_route->next = prev->next; new_route->next = prev->next;
prev->next = new_route; prev->next = new_route;
} } else {
else
{
ND_LL_PREPEND(ndL_routes, new_route, next); ND_LL_PREPEND(ndL_routes, new_route, next);
} }
@ -104,22 +102,24 @@ static void ndL_delete_route(nd_rt_route_t *route)
{ {
nd_rt_route_t *prev = NULL, *cur; nd_rt_route_t *prev = NULL, *cur;
ND_LL_FOREACH_NODEF(ndL_routes, cur, next) ND_LL_FOREACH_NODEF (ndL_routes, cur, next) {
{
if ((nd_addr_eq(&cur->dst, &route->dst) && cur->oif == route->oif && cur->pflen == route->pflen && if ((nd_addr_eq(&cur->dst, &route->dst) && cur->oif == route->oif && cur->pflen == route->pflen &&
cur->table == route->table)) cur->table == route->table)) {
break; break;
}
prev = cur; prev = cur;
} }
if (!cur) if (!cur) {
return; return;
}
if (prev) if (prev) {
prev->next = cur->next; prev->next = cur->next;
else } else {
ndL_routes = cur->next; ndL_routes = cur->next;
}
nd_log_debug("rt: (event) delete route %s/%d dev %d table %d", // nd_log_debug("rt: (event) delete route %s/%d dev %d table %d", //
nd_aton(&cur->dst), cur->pflen, cur->oif, cur->table); nd_aton(&cur->dst), cur->pflen, cur->oif, cur->table);
@ -131,16 +131,17 @@ static void ndL_new_addr(unsigned index, nd_addr_t *addr, unsigned pflen)
{ {
nd_rt_addr_t *rt_addr; nd_rt_addr_t *rt_addr;
ND_LL_FOREACH_NODEF(ndL_addrs, rt_addr, next) ND_LL_FOREACH_NODEF (ndL_addrs, rt_addr, next) {
{ if (rt_addr->iif == index && nd_addr_eq(&rt_addr->addr, addr) && rt_addr->pflen == pflen) {
if (rt_addr->iif == index && nd_addr_eq(&rt_addr->addr, addr) && rt_addr->pflen == pflen)
return; return;
}
} }
if ((rt_addr = ndL_free_addrs)) if ((rt_addr = ndL_free_addrs)) {
ND_LL_DELETE(ndL_free_addrs, rt_addr, next); ND_LL_DELETE(ndL_free_addrs, rt_addr, next);
else } else {
rt_addr = ND_ALLOC(nd_rt_addr_t); rt_addr = ND_ALLOC(nd_rt_addr_t);
}
ND_LL_PREPEND(ndL_addrs, rt_addr, next); ND_LL_PREPEND(ndL_addrs, rt_addr, next);
@ -155,16 +156,15 @@ static void ndL_delete_addr(unsigned int index, nd_addr_t *addr, unsigned pflen)
{ {
nd_rt_addr_t *prev = NULL, *rt_addr; nd_rt_addr_t *prev = NULL, *rt_addr;
ND_LL_FOREACH_NODEF(ndL_addrs, rt_addr, next) ND_LL_FOREACH_NODEF (ndL_addrs, rt_addr, next) {
{ if (rt_addr->iif == index && nd_addr_eq(&rt_addr->addr, addr) && rt_addr->pflen == pflen) {
if (rt_addr->iif == index && nd_addr_eq(&rt_addr->addr, addr) && rt_addr->pflen == pflen)
{
nd_log_debug("rt: (event) delete address %s/%d if %d", nd_aton(addr), pflen, index); nd_log_debug("rt: (event) delete address %s/%d if %d", nd_aton(addr), pflen, index);
if (prev) if (prev) {
prev->next = rt_addr->next; prev->next = rt_addr->next;
else } else {
ndL_addrs = rt_addr->next; ndL_addrs = rt_addr->next;
}
ND_LL_PREPEND(ndL_free_addrs, rt_addr, next); ND_LL_PREPEND(ndL_free_addrs, rt_addr, next);
return; return;
@ -179,8 +179,7 @@ static void ndL_handle_newaddr(struct ifaddrmsg *msg, int length)
{ {
nd_addr_t *addr = NULL; nd_addr_t *addr = NULL;
for (struct rtattr *rta = IFA_RTA(msg); RTA_OK(rta, length); rta = RTA_NEXT(rta, length)) for (struct rtattr *rta = IFA_RTA(msg); RTA_OK(rta, length); rta = RTA_NEXT(rta, length)) {
{
if (rta->rta_type == IFA_ADDRESS) if (rta->rta_type == IFA_ADDRESS)
addr = (nd_addr_t *)RTA_DATA(rta); addr = (nd_addr_t *)RTA_DATA(rta);
} }
@ -195,8 +194,7 @@ static void ndL_handle_deladdr(struct ifaddrmsg *msg, int length)
{ {
nd_addr_t *addr = NULL; nd_addr_t *addr = NULL;
for (struct rtattr *rta = IFA_RTA(msg); RTA_OK(rta, length); rta = RTA_NEXT(rta, length)) for (struct rtattr *rta = IFA_RTA(msg); RTA_OK(rta, length); rta = RTA_NEXT(rta, length)) {
{
if (rta->rta_type == IFA_ADDRESS) if (rta->rta_type == IFA_ADDRESS)
addr = (nd_addr_t *)RTA_DATA(rta); addr = (nd_addr_t *)RTA_DATA(rta);
} }
@ -212,8 +210,7 @@ static void ndL_handle_newroute(struct rtmsg *msg, int rtl)
nd_addr_t *dst = NULL; nd_addr_t *dst = NULL;
int oif = 0; int oif = 0;
for (struct rtattr *rta = RTM_RTA(msg); RTA_OK(rta, rtl); rta = RTA_NEXT(rta, rtl)) for (struct rtattr *rta = RTM_RTA(msg); RTA_OK(rta, rtl); rta = RTA_NEXT(rta, rtl)) {
{
if (rta->rta_type == RTA_OIF) if (rta->rta_type == RTA_OIF)
oif = *(int *)RTA_DATA(rta); oif = *(int *)RTA_DATA(rta);
else if (rta->rta_type == RTA_DST) else if (rta->rta_type == RTA_DST)
@ -239,8 +236,7 @@ static void ndL_handle_delroute(struct rtmsg *msg, int rtl)
nd_addr_t *dst = NULL; nd_addr_t *dst = NULL;
int oif = 0; int oif = 0;
for (struct rtattr *rta = RTM_RTA(msg); RTA_OK(rta, rtl); rta = RTA_NEXT(rta, rtl)) for (struct rtattr *rta = RTM_RTA(msg); RTA_OK(rta, rtl); rta = RTA_NEXT(rta, rtl)) {
{
if (rta->rta_type == RTA_OIF) if (rta->rta_type == RTA_OIF)
oif = *(int *)RTA_DATA(rta); oif = *(int *)RTA_DATA(rta);
else if (rta->rta_type == RTA_DST) else if (rta->rta_type == RTA_DST)
@ -264,23 +260,19 @@ static void ndL_io_handler(__attribute__((unused)) nd_io_t *unused1, __attribute
{ {
uint8_t buf[4096]; uint8_t buf[4096];
for (;;) for (;;) {
{
ssize_t len = nd_io_recv(ndL_io, NULL, 0, buf, sizeof(buf)); ssize_t len = nd_io_recv(ndL_io, NULL, 0, buf, sizeof(buf));
if (len < 0) if (len < 0)
return; return;
for (struct nlmsghdr *hdr = (struct nlmsghdr *)buf; NLMSG_OK(hdr, len); hdr = NLMSG_NEXT(hdr, len)) for (struct nlmsghdr *hdr = (struct nlmsghdr *)buf; NLMSG_OK(hdr, len); hdr = NLMSG_NEXT(hdr, len)) {
{ if (hdr->nlmsg_type == NLMSG_DONE) {
if (hdr->nlmsg_type == NLMSG_DONE)
{
nd_rt_dump_timeout = 0; nd_rt_dump_timeout = 0;
break; break;
} }
if (hdr->nlmsg_type == NLMSG_ERROR) if (hdr->nlmsg_type == NLMSG_ERROR) {
{
struct nlmsgerr *e = (struct nlmsgerr *)NLMSG_DATA(hdr); struct nlmsgerr *e = (struct nlmsgerr *)NLMSG_DATA(hdr);
nd_log_error("rt: Netlink: %s (%d)", strerror(-e->error), e->msg.nlmsg_type); nd_log_error("rt: Netlink: %s (%d)", strerror(-e->error), e->msg.nlmsg_type);
continue; continue;
@ -300,15 +292,11 @@ static void ndL_io_handler(__attribute__((unused)) nd_io_t *unused1, __attribute
#else #else
static void ndL_get_rtas(int addrs, struct sockaddr *sa, struct sockaddr **rtas) static void ndL_get_rtas(int addrs, struct sockaddr *sa, struct sockaddr **rtas)
{ {
for (int i = 0; i < RTAX_MAX; i++) for (int i = 0; i < RTAX_MAX; i++) {
{ if (addrs & (1 << i)) {
if (addrs & (1 << i))
{
rtas[i] = sa; rtas[i] = sa;
sa = (void *)sa + ((sa->sa_len + sizeof(u_long) - 1) & ~(sizeof(u_long) - 1)); sa = (void *)sa + ((sa->sa_len + sizeof(u_long) - 1) & ~(sizeof(u_long) - 1));
} } else {
else
{
rtas[i] = NULL; rtas[i] = NULL;
} }
} }
@ -319,8 +307,9 @@ static void ndL_handle_rt(struct rt_msghdr *hdr)
struct sockaddr *rtas[RTAX_MAX]; struct sockaddr *rtas[RTAX_MAX];
ndL_get_rtas(hdr->rtm_addrs, (struct sockaddr *)(hdr + 1), rtas); ndL_get_rtas(hdr->rtm_addrs, (struct sockaddr *)(hdr + 1), rtas);
if (!rtas[RTAX_DST] || rtas[RTAX_DST]->sa_family != AF_INET6) if (!rtas[RTAX_DST] || rtas[RTAX_DST]->sa_family != AF_INET6) {
return; return;
}
int pflen = rtas[RTAX_NETMASK] ? nd_mask_to_pflen(&((struct sockaddr_in6 *)rtas[RTAX_NETMASK])->sin6_addr) : 128; int pflen = rtas[RTAX_NETMASK] ? nd_mask_to_pflen(&((struct sockaddr_in6 *)rtas[RTAX_NETMASK])->sin6_addr) : 128;
@ -338,10 +327,11 @@ static void ndL_handle_rt(struct rt_msghdr *hdr)
.owned = (hdr->rtm_flags & RTF_PROTO3) != 0, .owned = (hdr->rtm_flags & RTF_PROTO3) != 0,
}; };
if (hdr->rtm_type == RTM_GET || hdr->rtm_type == RTM_ADD) if (hdr->rtm_type == RTM_GET || hdr->rtm_type == RTM_ADD) {
ndL_new_route(&route); ndL_new_route(&route);
else if (hdr->rtm_type == RTM_DELETE) } else if (hdr->rtm_type == RTM_DELETE) {
ndL_delete_route(&route); ndL_delete_route(&route);
}
} }
static void ndL_handle_ifa(struct ifa_msghdr *hdr) static void ndL_handle_ifa(struct ifa_msghdr *hdr)
@ -349,21 +339,22 @@ static void ndL_handle_ifa(struct ifa_msghdr *hdr)
struct sockaddr *rtas[RTAX_MAX]; struct sockaddr *rtas[RTAX_MAX];
ndL_get_rtas(hdr->ifam_addrs, (struct sockaddr *)(hdr + 1), rtas); ndL_get_rtas(hdr->ifam_addrs, (struct sockaddr *)(hdr + 1), rtas);
if (!rtas[RTAX_IFA] || rtas[RTAX_IFA]->sa_family != AF_INET6) if (!rtas[RTAX_IFA] || rtas[RTAX_IFA]->sa_family != AF_INET6) {
return; return;
}
int pflen = rtas[RTAX_NETMASK] ? nd_mask_to_pflen(&((struct sockaddr_in6 *)rtas[RTAX_NETMASK])->sin6_addr) : 128; int pflen = rtas[RTAX_NETMASK] ? nd_mask_to_pflen(&((struct sockaddr_in6 *)rtas[RTAX_NETMASK])->sin6_addr) : 128;
nd_addr_t *ifa = &((struct sockaddr_in6 *)rtas[RTAX_IFA])->sin6_addr; nd_addr_t *ifa = &((struct sockaddr_in6 *)rtas[RTAX_IFA])->sin6_addr;
if (hdr->ifam_type == RTM_NEWADDR) if (hdr->ifam_type == RTM_NEWADDR) {
ndL_new_addr(hdr->ifam_index, ifa, pflen); ndL_new_addr(hdr->ifam_index, ifa, pflen);
else if (hdr->ifam_type == RTM_DELADDR) } else if (hdr->ifam_type == RTM_DELADDR) {
ndL_delete_addr(hdr->ifam_index, ifa, pflen); ndL_delete_addr(hdr->ifam_index, ifa, pflen);
}
} }
typedef struct typedef struct {
{
u_short msglen; u_short msglen;
u_char version; u_char version;
u_char type; u_char type;
@ -371,16 +362,15 @@ typedef struct
static void ndL_handle(void *buf, size_t buflen) static void ndL_handle(void *buf, size_t buflen)
{ {
for (size_t i = 0; i < buflen;) for (size_t i = 0; i < buflen;) {
{
ndL_msghdr_t *hdr = (ndL_msghdr_t *)(buf + i); ndL_msghdr_t *hdr = (ndL_msghdr_t *)(buf + i);
i += hdr->msglen; i += hdr->msglen;
if (i > buflen) if (i > buflen) {
break; break;
}
switch (hdr->type) switch (hdr->type) {
{
case RTM_ADD: case RTM_ADD:
case RTM_GET: case RTM_GET:
case RTM_DELETE: case RTM_DELETE:
@ -400,8 +390,7 @@ static bool ndL_dump(int type)
int mib[] = { CTL_NET, PF_ROUTE, 0, 0, type, 0 }; int mib[] = { CTL_NET, PF_ROUTE, 0, 0, type, 0 };
size_t size; size_t size;
if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0) if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0) {
{
nd_log_error("sysctl(): %s", strerror(errno)); nd_log_error("sysctl(): %s", strerror(errno));
return false; return false;
} }
@ -409,8 +398,7 @@ static bool ndL_dump(int type)
void *buf = malloc(size); void *buf = malloc(size);
// FIXME: Potential race condition as the number of routes might have increased since the previous syscall(). // FIXME: Potential race condition as the number of routes might have increased since the previous syscall().
if (sysctl(mib, 6, buf, &size, NULL, 0) < 0) if (sysctl(mib, 6, buf, &size, NULL, 0) < 0) {
{
free(buf); free(buf);
nd_log_error("sysctl(): %s", strerror(errno)); nd_log_error("sysctl(): %s", strerror(errno));
return false; return false;
@ -426,12 +414,12 @@ static void ndL_io_handler(__attribute__((unused)) nd_io_t *unused1, __attribute
{ {
uint8_t buf[4096]; uint8_t buf[4096];
for (;;) for (;;) {
{
ssize_t len = nd_io_recv(ndL_io, NULL, 0, buf, sizeof(buf)); ssize_t len = nd_io_recv(ndL_io, NULL, 0, buf, sizeof(buf));
if (len < 0) if (len < 0) {
return; return;
}
ndL_handle(buf, len); ndL_handle(buf, len);
} }
@ -441,12 +429,12 @@ static void ndL_io_handler(__attribute__((unused)) nd_io_t *unused1, __attribute
bool nd_rt_open() bool nd_rt_open()
{ {
if (ndL_io != NULL) if (ndL_io != NULL) {
return true; return true;
}
#ifdef __linux__ #ifdef __linux__
if (!(ndL_io = nd_io_socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE))) if (!(ndL_io = nd_io_socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE))) {
{
nd_log_error("Failed to open netlink socket: %s", strerror(errno)); nd_log_error("Failed to open netlink socket: %s", strerror(errno));
return false; return false;
} }
@ -456,16 +444,14 @@ bool nd_rt_open()
addr.nl_family = AF_NETLINK; addr.nl_family = AF_NETLINK;
addr.nl_groups = (1 << (RTNLGRP_IPV6_IFADDR - 1)) | (1 << (RTNLGRP_IPV6_ROUTE - 1)); addr.nl_groups = (1 << (RTNLGRP_IPV6_IFADDR - 1)) | (1 << (RTNLGRP_IPV6_ROUTE - 1));
if (!nd_io_bind(ndL_io, (struct sockaddr *)&addr, sizeof(addr))) if (!nd_io_bind(ndL_io, (struct sockaddr *)&addr, sizeof(addr))) {
{
nd_log_error("Failed to bind netlink socket: %s", strerror(errno)); nd_log_error("Failed to bind netlink socket: %s", strerror(errno));
nd_io_close(ndL_io); nd_io_close(ndL_io);
ndL_io = NULL; ndL_io = NULL;
return false; return false;
} }
#else #else
if (!(ndL_io = nd_io_socket(AF_ROUTE, SOCK_RAW, AF_INET6))) if (!(ndL_io = nd_io_socket(AF_ROUTE, SOCK_RAW, AF_INET6))) {
{
nd_log_error("Failed to open routing socket: %s", strerror(errno)); nd_log_error("Failed to open routing socket: %s", strerror(errno));
return false; return false;
} }
@ -478,8 +464,9 @@ bool nd_rt_open()
void nd_rt_cleanup() void nd_rt_cleanup()
{ {
if (ndL_io) if (ndL_io) {
nd_io_close(ndL_io); nd_io_close(ndL_io);
}
} }
bool nd_rt_query_routes() bool nd_rt_query_routes()
@ -488,8 +475,7 @@ bool nd_rt_query_routes()
if (nd_rt_dump_timeout) if (nd_rt_dump_timeout)
return false; return false;
struct struct {
{
struct nlmsghdr hdr; struct nlmsghdr hdr;
struct rtmsg msg; struct rtmsg msg;
} req; } req;
@ -523,8 +509,7 @@ bool nd_rt_query_addresses()
if (nd_rt_dump_timeout) if (nd_rt_dump_timeout)
return false; return false;
struct struct {
{
struct nlmsghdr hdr; struct nlmsghdr hdr;
struct ifaddrmsg msg; struct ifaddrmsg msg;
} req; } req;
@ -553,10 +538,10 @@ bool nd_rt_query_addresses()
nd_rt_route_t *nd_rt_find_route(nd_addr_t *addr, unsigned table) nd_rt_route_t *nd_rt_find_route(nd_addr_t *addr, unsigned table)
{ {
ND_LL_FOREACH(ndL_routes, route, next) ND_LL_FOREACH (ndL_routes, route, next) {
{ if (nd_addr_match(&route->dst, addr, route->pflen) && route->table == table) {
if (nd_addr_match(&route->dst, addr, route->pflen) && route->table == table)
return route; return route;
}
} }
return NULL; return NULL;
@ -565,16 +550,15 @@ nd_rt_route_t *nd_rt_find_route(nd_addr_t *addr, unsigned table)
bool nd_rt_add_route(nd_addr_t *dst, unsigned pflen, unsigned oif, unsigned table) bool nd_rt_add_route(nd_addr_t *dst, unsigned pflen, unsigned oif, unsigned table)
{ {
#ifdef __linux__ #ifdef __linux__
struct __attribute__((packed)) struct __attribute__((packed)) {
{
struct nlmsghdr hdr; struct nlmsghdr hdr;
struct rtmsg msg; struct rtmsg msg;
struct rtattr oif_attr __attribute__((aligned(NLMSG_ALIGNTO))); struct rtattr oif_attr __attribute__((aligned(NLMSG_ALIGNTO)));
uint32_t oif; uint32_t oif;
struct rtattr dst_attr __attribute__((aligned(RTA_ALIGNTO))); struct rtattr dst_attr __attribute__((aligned(RTA_ALIGNTO)));
nd_addr_t dst; nd_addr_t dst;
//struct rtattr exp_attr __attribute__((aligned(RTA_ALIGNTO))); // struct rtattr exp_attr __attribute__((aligned(RTA_ALIGNTO)));
//uint32_t exp; // uint32_t exp;
} req; } req;
memset(&req, 0, sizeof(req)); memset(&req, 0, sizeof(req));
@ -593,9 +577,9 @@ bool nd_rt_add_route(nd_addr_t *dst, unsigned pflen, unsigned oif, unsigned tabl
req.dst_attr.rta_len = RTA_LENGTH(sizeof(req.dst)); req.dst_attr.rta_len = RTA_LENGTH(sizeof(req.dst));
req.dst = *dst; req.dst = *dst;
//req.exp_attr.rta_type = RTA_EXPIRES; // req.exp_attr.rta_type = RTA_EXPIRES;
//req.exp_attr.rta_len = RTA_LENGTH(sizeof(req.exp)); // req.exp_attr.rta_len = RTA_LENGTH(sizeof(req.exp));
//req.exp = 60; // req.exp = 60;
req.hdr.nlmsg_type = RTM_NEWROUTE; req.hdr.nlmsg_type = RTM_NEWROUTE;
req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
@ -607,8 +591,7 @@ bool nd_rt_add_route(nd_addr_t *dst, unsigned pflen, unsigned oif, unsigned tabl
return nd_io_send(ndL_io, (struct sockaddr *)&addr, sizeof(addr), &req, sizeof(req)) >= 0; return nd_io_send(ndL_io, (struct sockaddr *)&addr, sizeof(addr), &req, sizeof(req)) >= 0;
#else #else
struct struct {
{
struct rt_msghdr hdr; struct rt_msghdr hdr;
struct sockaddr_in6 dst; struct sockaddr_in6 dst;
struct sockaddr_dl dl __aligned(sizeof(u_long)); struct sockaddr_dl dl __aligned(sizeof(u_long));
@ -652,8 +635,7 @@ bool nd_rt_add_route(nd_addr_t *dst, unsigned pflen, unsigned oif, unsigned tabl
bool nd_rt_remove_route(nd_addr_t *dst, unsigned pflen, unsigned table) bool nd_rt_remove_route(nd_addr_t *dst, unsigned pflen, unsigned table)
{ {
#ifdef __linux__ #ifdef __linux__
struct __attribute__((packed)) struct __attribute__((packed)) {
{
struct nlmsghdr hdr; struct nlmsghdr hdr;
struct rtmsg msg; struct rtmsg msg;
struct rtattr dst_attr __attribute__((aligned(NLMSG_ALIGNTO))); struct rtattr dst_attr __attribute__((aligned(NLMSG_ALIGNTO)));
@ -682,8 +664,7 @@ bool nd_rt_remove_route(nd_addr_t *dst, unsigned pflen, unsigned table)
return nd_io_send(ndL_io, (struct sockaddr *)&addr, sizeof(addr), &req, sizeof(req)) >= 0; return nd_io_send(ndL_io, (struct sockaddr *)&addr, sizeof(addr), &req, sizeof(req)) >= 0;
#else #else
struct __attribute__((packed)) struct __attribute__((packed)) {
{
struct rt_msghdr hdr; struct rt_msghdr hdr;
struct sockaddr_in6 dst; struct sockaddr_in6 dst;
struct sockaddr_in6 mask __aligned(sizeof(u_long)); struct sockaddr_in6 mask __aligned(sizeof(u_long));
@ -718,9 +699,9 @@ bool nd_rt_remove_route(nd_addr_t *dst, unsigned pflen, unsigned table)
void nl_rt_remove_owned_routes() void nl_rt_remove_owned_routes()
{ {
ND_LL_FOREACH_S(ndL_routes, route, tmp, next) ND_LL_FOREACH_S (ndL_routes, route, tmp, next) {
{ if (route->owned) {
if (route->owned)
nd_rt_remove_route(&route->dst, route->pflen, route->table); nd_rt_remove_route(&route->dst, route->pflen, route->table);
}
} }
} }

View File

@ -22,8 +22,7 @@
typedef struct nd_rt_route nd_rt_route_t; typedef struct nd_rt_route nd_rt_route_t;
typedef struct nd_rt_addr nd_rt_addr_t; typedef struct nd_rt_addr nd_rt_addr_t;
struct nd_rt_route struct nd_rt_route {
{
nd_rt_route_t *next; nd_rt_route_t *next;
nd_addr_t dst; nd_addr_t dst;
unsigned oif; unsigned oif;
@ -32,8 +31,7 @@ struct nd_rt_route
bool owned; // If this route is owned by ndppd. bool owned; // If this route is owned by ndppd.
}; };
struct nd_rt_addr struct nd_rt_addr {
{
nd_rt_addr_t *next; nd_rt_addr_t *next;
unsigned iif; unsigned iif;
nd_addr_t addr; nd_addr_t addr;

View File

@ -16,9 +16,9 @@
// along with ndppd. If not, see <https://www.gnu.org/licenses/>. // along with ndppd. If not, see <https://www.gnu.org/licenses/>.
#include <string.h> #include <string.h>
#include "rule.h"
#include "ndppd.h" #include "ndppd.h"
#include "proxy.h" #include "proxy.h"
#include "rule.h"
nd_rule_t *nd_rule_create(nd_proxy_t *proxy) nd_rule_t *nd_rule_create(nd_proxy_t *proxy)
{ {

View File

@ -21,16 +21,14 @@
#include "ndppd.h" #include "ndppd.h"
typedef enum typedef enum {
{
ND_MODE_UNKNOWN, ND_MODE_UNKNOWN,
ND_MODE_STATIC, ND_MODE_STATIC,
ND_MODE_IFACE, // Use a specific interface ND_MODE_IFACE, // Use a specific interface
ND_MODE_AUTO, ND_MODE_AUTO,
} nd_mode_t; } nd_mode_t;
struct nd_rule struct nd_rule {
{
nd_rule_t *next; nd_rule_t *next;
nd_proxy_t *proxy; nd_proxy_t *proxy;

View File

@ -35,8 +35,7 @@ static nd_session_t *ndL_free_sessions;
static void ndL_up(nd_session_t *session) static void ndL_up(nd_session_t *session)
{ {
if (session->iface && !session->autowired && session->rule->autowire) if (session->iface && !session->autowired && session->rule->autowire) {
{
nd_rt_add_route(&session->tgt, 128, session->iface->index, session->rule->table); nd_rt_add_route(&session->tgt, 128, session->iface->index, session->rule->table);
session->autowired = true; session->autowired = true;
} }
@ -44,8 +43,7 @@ static void ndL_up(nd_session_t *session)
static void ndL_down(nd_session_t *session) static void ndL_down(nd_session_t *session)
{ {
if (session->iface && session->autowired) if (session->iface && session->autowired) {
{
nd_rt_remove_route(&session->tgt, 128, session->rule->table); nd_rt_remove_route(&session->tgt, 128, session->rule->table);
session->autowired = false; session->autowired = false;
} }
@ -55,16 +53,16 @@ void nd_session_handle_ns(nd_session_t *session, nd_addr_t *src, uint8_t *src_ll
{ {
session->ins_time = nd_current_time; session->ins_time = nd_current_time;
if (session->state != ND_STATE_VALID && session->state != ND_STATE_STALE) if (session->state != ND_STATE_VALID && session->state != ND_STATE_STALE) {
return; return;
}
nd_iface_write_na(session->rule->proxy->iface, src, src_ll, &session->tgt, session->rule->proxy->router); nd_iface_write_na(session->rule->proxy->iface, src, src_ll, &session->tgt, session->rule->proxy->router);
} }
void nd_session_handle_na(nd_session_t *session) void nd_session_handle_na(nd_session_t *session)
{ {
if (session->state != ND_STATE_VALID) if (session->state != ND_STATE_VALID) {
{
nd_log_debug("session [%s] %s -> VALID", session->rule->proxy->ifname, nd_aton(&session->tgt)); nd_log_debug("session [%s] %s -> VALID", session->rule->proxy->ifname, nd_aton(&session->tgt));
ndL_up(session); ndL_up(session);
@ -77,10 +75,11 @@ nd_session_t *nd_session_create(nd_rule_t *rule, nd_addr_t *tgt)
{ {
nd_session_t *session = ndL_free_sessions; nd_session_t *session = ndL_free_sessions;
if (session) if (session) {
ND_LL_DELETE(ndL_free_sessions, session, next_in_proxy); ND_LL_DELETE(ndL_free_sessions, session, next_in_proxy);
else } else {
session = ND_ALLOC(nd_session_t); session = ND_ALLOC(nd_session_t);
}
ND_LL_PREPEND(rule->proxy->sessions, session, next_in_proxy); ND_LL_PREPEND(rule->proxy->sessions, session, next_in_proxy);
@ -92,32 +91,25 @@ 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); nd_addr_combine(&rule->rewrite_tgt, tgt, rule->rewrite_pflen, &session->real_tgt);
if (rule->mode == ND_MODE_AUTO) if (rule->mode == ND_MODE_AUTO) {
{
nd_rt_route_t *route = nd_rt_find_route(tgt, rule->table); nd_rt_route_t *route = nd_rt_find_route(tgt, rule->table);
if (!route || route->oif == rule->proxy->iface->index || !(session->iface = nd_iface_open(NULL, route->oif))) if (!route || route->oif == rule->proxy->iface->index || !(session->iface = nd_iface_open(NULL, route->oif))) {
{
session->state = ND_STATE_INVALID; session->state = ND_STATE_INVALID;
return session; return session;
} }
} } else if ((session->iface = rule->iface)) {
else if ((session->iface = rule->iface))
{
session->iface->refcount++; session->iface->refcount++;
} }
if (session->iface) if (session->iface) {
{
ND_LL_PREPEND(session->iface->sessions, session, next_in_iface); ND_LL_PREPEND(session->iface->sessions, session, next_in_iface);
session->state = ND_STATE_INCOMPLETE; session->state = ND_STATE_INCOMPLETE;
session->ons_count = 1; session->ons_count = 1;
session->ons_time = nd_current_time; session->ons_time = nd_current_time;
nd_iface_write_ns(session->iface, &session->real_tgt); nd_iface_write_ns(session->iface, &session->real_tgt);
} } else if (rule->mode == ND_MODE_STATIC) {
else if (rule->mode == ND_MODE_STATIC)
{
session->state = ND_STATE_VALID; session->state = ND_STATE_VALID;
} }
@ -126,14 +118,13 @@ nd_session_t *nd_session_create(nd_rule_t *rule, nd_addr_t *tgt)
void nd_session_update(nd_session_t *session) void nd_session_update(nd_session_t *session)
{ {
switch (session->state) switch (session->state) {
{
case ND_STATE_INCOMPLETE: case ND_STATE_INCOMPLETE:
if (nd_current_time - session->ons_time < nd_conf_retrans_time) if (nd_current_time - session->ons_time < nd_conf_retrans_time) {
break; break;
}
if (++session->ons_count > nd_conf_retrans_limit) if (++session->ons_count > nd_conf_retrans_limit) {
{
session->state = ND_STATE_INVALID; session->state = ND_STATE_INVALID;
session->state_time = nd_current_time; session->state_time = nd_current_time;
nd_log_debug("session [%s] %s INCOMPLETE -> INVALID", // nd_log_debug("session [%s] %s INCOMPLETE -> INVALID", //
@ -145,13 +136,13 @@ void nd_session_update(nd_session_t *session)
break; break;
case ND_STATE_INVALID: case ND_STATE_INVALID:
if (nd_current_time - session->state_time < nd_conf_invalid_ttl) if (nd_current_time - session->state_time < nd_conf_invalid_ttl) {
break; break;
}
ndL_down(session); ndL_down(session);
if (session->iface) if (session->iface) {
{
ND_LL_DELETE(session->iface->sessions, session, next_in_iface); ND_LL_DELETE(session->iface->sessions, session, next_in_iface);
nd_iface_close(session->iface); nd_iface_close(session->iface);
} }
@ -164,8 +155,9 @@ void nd_session_update(nd_session_t *session)
break; break;
case ND_STATE_VALID: case ND_STATE_VALID:
if (nd_current_time - session->state_time < nd_conf_valid_ttl) if (nd_current_time - session->state_time < nd_conf_valid_ttl) {
break; break;
}
session->state = ND_STATE_STALE; session->state = ND_STATE_STALE;
session->state_time = nd_current_time; session->state_time = nd_current_time;
@ -174,41 +166,37 @@ void nd_session_update(nd_session_t *session)
nd_log_debug("session [%s] %s VALID -> STALE", // nd_log_debug("session [%s] %s VALID -> STALE", //
session->rule->proxy->ifname, nd_aton(&session->tgt)); session->rule->proxy->ifname, nd_aton(&session->tgt));
if (nd_conf_keepalive || nd_current_time - session->ins_time < nd_conf_valid_ttl) if (nd_conf_keepalive || nd_current_time - session->ins_time < nd_conf_valid_ttl) {
{
session->ons_count = 1; session->ons_count = 1;
nd_iface_write_ns(session->iface, &session->real_tgt); nd_iface_write_ns(session->iface, &session->real_tgt);
} } else {
else
{
session->ons_count = 0; session->ons_count = 0;
} }
break; break;
case ND_STATE_STALE: case ND_STATE_STALE:
if (nd_current_time - session->state_time >= nd_conf_stale_ttl) if (nd_current_time - session->state_time >= nd_conf_stale_ttl) {
{
session->state = ND_STATE_INVALID; session->state = ND_STATE_INVALID;
session->state_time = nd_current_time; session->state_time = nd_current_time;
nd_log_debug("session [%s] %s STALE -> INVALID", // nd_log_debug("session [%s] %s STALE -> INVALID", //
session->rule->proxy->ifname, nd_aton(&session->tgt)); session->rule->proxy->ifname, nd_aton(&session->tgt));
} } else {
else
{
// We will only retransmit if nd_conf_keepalive is true, or if the last incoming NS // We will only retransmit if nd_conf_keepalive is true, or if the last incoming NS
// request was made less than nd_conf_valid_ttl milliseconds ago. // request was made less than nd_conf_valid_ttl milliseconds ago.
if (!nd_conf_keepalive && nd_current_time - session->ins_time > nd_conf_valid_ttl) if (!nd_conf_keepalive && nd_current_time - session->ins_time > nd_conf_valid_ttl) {
break; break;
}
long time = session->ons_count && !(session->ons_count % nd_conf_retrans_limit) long time = session->ons_count && !(session->ons_count % nd_conf_retrans_limit)
? ((1 << session->ons_count / 3) * nd_conf_retrans_time) ? ((1 << session->ons_count / 3) * nd_conf_retrans_time)
: nd_conf_retrans_time; : nd_conf_retrans_time;
if (nd_current_time - session->ons_time < time) if (nd_current_time - session->ons_time < time) {
break; break;
}
session->ons_count++; session->ons_count++;
session->ons_time = nd_current_time; session->ons_time = nd_current_time;

View File

@ -20,8 +20,7 @@
#include "ndppd.h" #include "ndppd.h"
#include "rt.h" #include "rt.h"
typedef enum typedef enum {
{
//! Address resolution is in progress. //! Address resolution is in progress.
ND_STATE_INCOMPLETE, ND_STATE_INCOMPLETE,
@ -35,8 +34,7 @@ typedef enum
} nd_state_t; } nd_state_t;
struct nd_session struct nd_session {
{
nd_session_t *next_in_proxy; nd_session_t *next_in_proxy;
nd_session_t *next_in_iface; nd_session_t *next_in_iface;
nd_rule_t *rule; nd_rule_t *rule;