Continue work on handling TTLs

This commit is contained in:
Daniel Adolfsson 2019-12-11 13:21:29 +01:00
parent 141f39f20a
commit 8028e2d487
9 changed files with 128 additions and 105 deletions

View File

@ -40,7 +40,8 @@
#include "rule.h" #include "rule.h"
int nd_conf_invalid_ttl = 10000; int nd_conf_invalid_ttl = 10000;
int nd_conf_valid_ttl = 10000; int nd_conf_valid_ttl = 30000;
int nd_conf_stale_ttl = 30000;
int nd_conf_renew = 5000; int nd_conf_renew = 5000;
int nd_conf_retrans_limit = 3; int nd_conf_retrans_limit = 3;
int nd_conf_retrans_time = 1000; int nd_conf_retrans_time = 1000;

View File

@ -34,8 +34,8 @@
#include "addr.h" #include "addr.h"
#include "iface.h" #include "iface.h"
#include "ndppd.h" #include "ndppd.h"
#include "neigh.h"
#include "proxy.h" #include "proxy.h"
#include "session.h"
#include "sio.h" #include "sio.h"
extern int nd_conf_invalid_ttl; extern int nd_conf_invalid_ttl;
@ -55,7 +55,7 @@ typedef struct
struct icmp6_hdr icmp6_hdr; struct icmp6_hdr icmp6_hdr;
} ndL_icmp6_msg_t; } ndL_icmp6_msg_t;
static void ndL_handle_ns(nd_iface_t *ifa, ndL_icmp6_msg_t *msg) 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;
@ -76,8 +76,8 @@ static void ndL_handle_ns(nd_iface_t *ifa, ndL_icmp6_msg_t *msg)
uint8_t *lladdr = (uint8_t *)((void *)opt + 2); uint8_t *lladdr = (uint8_t *)((void *)opt + 2);
if (ifa->proxy) if (iface->proxy)
nd_proxy_handle_ns(ifa->proxy, &msg->ip6_hdr.ip6_src, &msg->ip6_hdr.ip6_dst, &ns->nd_ns_target, lladdr); nd_proxy_handle_ns(iface->proxy, &msg->ip6_hdr.ip6_src, &msg->ip6_hdr.ip6_dst, &ns->nd_ns_target, lladdr);
} }
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)
@ -87,15 +87,15 @@ static void ndL_handle_na(nd_iface_t *iface, ndL_icmp6_msg_t *msg)
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_neigh_t *neigh; nd_session_t *session;
ND_LL_SEARCH(iface->neighs, neigh, next_in_iface, nd_addr_eq(&neigh->tgt, &na->nd_na_target)); ND_LL_SEARCH(iface->sessions, session, next_in_iface, nd_addr_eq(&session->tgt, &na->nd_na_target));
if (!neigh) if (!session)
return; return;
neigh->state = ND_STATE_VALID; session->state = ND_STATE_VALID;
neigh->ttl = nd_conf_valid_ttl; session->mtime = nd_current_time;
neigh->touched_at = nd_current_time; nd_log_debug("session [%s] %s INVALID -> (deleted)", "?", nd_addr_to_string(&session->tgt));
} }
static uint16_t ndL_calculate_checksum(uint32_t sum, const void *data, size_t length) static uint16_t ndL_calculate_checksum(uint32_t sum, const void *data, size_t length)

View File

@ -36,7 +36,7 @@ struct nd_iface
int old_promisc; int old_promisc;
nd_proxy_t *proxy; nd_proxy_t *proxy;
nd_neigh_t *neighs; /* All sessions expecting NA messages to arrive here. */ nd_session_t *sessions; /* All sessions expecting NA messages to arrive here. */
nd_sio_t *sio; nd_sio_t *sio;
}; };

View File

@ -225,9 +225,12 @@ int main(int argc, char *argv[])
if (!nd_sio_poll()) if (!nd_sio_poll())
{ {
/* TODO: Error */
break; break;
} }
nd_proxy_update_all();
gettimeofday(&t1, 0); gettimeofday(&t1, 0);
nd_current_time = t1.tv_sec * 1000 + t1.tv_usec / 1000; nd_current_time = t1.tv_sec * 1000 + t1.tv_usec / 1000;
} }

View File

@ -34,7 +34,7 @@ typedef struct in6_addr nd_addr_t;
typedef struct nd_conf_rule nd_conf_rule_t; typedef struct nd_conf_rule nd_conf_rule_t;
typedef struct nd_conf_proxy nd_conf_proxy_t; typedef struct nd_conf_proxy nd_conf_proxy_t;
typedef struct nd_rule nd_rule_t; typedef struct nd_rule nd_rule_t;
typedef struct nd_neigh nd_neigh_t; typedef struct nd_session nd_session_t;
extern long nd_current_time; extern long nd_current_time;
extern bool nd_daemonized; extern bool nd_daemonized;

View File

@ -22,15 +22,16 @@
#include "addr.h" #include "addr.h"
#include "iface.h" #include "iface.h"
#include "ndppd.h" #include "ndppd.h"
#include "neigh.h"
#include "proxy.h" #include "proxy.h"
#include "rtnl.h" #include "rtnl.h"
#include "rule.h" #include "rule.h"
#include "session.h"
static nd_proxy_t *ndL_proxies; static nd_proxy_t *ndL_proxies;
extern int nd_conf_invalid_ttl; extern int nd_conf_invalid_ttl;
extern int nd_conf_valid_ttl; extern int nd_conf_valid_ttl;
extern int nd_conf_stale_ttl;
extern int nd_conf_renew; extern int nd_conf_renew;
extern int nd_conf_retrans_limit; extern int nd_conf_retrans_limit;
extern int nd_conf_retrans_time; extern int nd_conf_retrans_time;
@ -54,7 +55,7 @@ nd_proxy_t *nd_proxy_create(const char *ifname)
proxy->iface = NULL; proxy->iface = NULL;
proxy->rules = NULL; proxy->rules = NULL;
proxy->neighs = NULL; proxy->sessions = NULL;
proxy->router = false; proxy->router = false;
strcpy(proxy->ifname, ifname); strcpy(proxy->ifname, ifname);
@ -68,16 +69,15 @@ void nd_proxy_handle_ns(nd_proxy_t *proxy, nd_addr_t *src, __attribute__((unused
nd_log_trace("Handle NA src=%s [%x:%x:%x:%x:%x:%x], dst=%s, tgt=%s", nd_addr_to_string(src), src_ll[0], src_ll[1], nd_log_trace("Handle NA src=%s [%x:%x:%x:%x:%x:%x], dst=%s, tgt=%s", nd_addr_to_string(src), src_ll[0], src_ll[1],
src_ll[2], src_ll[3], src_ll[4], src_ll[5], nd_addr_to_string(dst), nd_addr_to_string(tgt)); src_ll[2], src_ll[3], src_ll[4], src_ll[5], nd_addr_to_string(dst), nd_addr_to_string(tgt));
nd_neigh_t *neigh; nd_session_t *session;
ND_LL_FOREACH_NODEF(proxy->neighs, neigh, next_in_proxy) ND_LL_FOREACH_NODEF(proxy->sessions, session, next_in_proxy)
{ {
if (!nd_addr_eq(&neigh->tgt, tgt)) if (!nd_addr_eq(&session->tgt, tgt))
continue; continue;
if (neigh->state == ND_STATE_VALID || neigh->state == ND_STATE_VALID_REFRESH) if (session->state == ND_STATE_VALID || session->state == ND_STATE_STALE)
{ {
neigh->used_at = nd_current_time;
nd_iface_write_na(proxy->iface, src, src_ll, tgt, proxy->router); nd_iface_write_na(proxy->iface, src, src_ll, tgt, proxy->router);
return; return;
} }
@ -94,11 +94,11 @@ void nd_proxy_handle_ns(nd_proxy_t *proxy, nd_addr_t *src, __attribute__((unused
if (!rule) if (!rule)
return; return;
neigh = nd_alloc_neigh(); session = nd_alloc_session();
neigh->touched_at = nd_current_time; session->mtime = nd_current_time;
neigh->tgt = *tgt; session->tgt = *tgt;
ND_LL_PREPEND(proxy->neighs, neigh, next_in_proxy); ND_LL_PREPEND(proxy->sessions, session, next_in_proxy);
if (rule->is_auto) if (rule->is_auto)
{ {
@ -109,92 +109,112 @@ void nd_proxy_handle_ns(nd_proxy_t *proxy, nd_addr_t *src, __attribute__((unused
if (!route || route->oif == proxy->iface->index) if (!route || route->oif == proxy->iface->index)
{ {
/* Could not find a matching route. */ /* Could not find a matching route. */
neigh->state = ND_STATE_INVALID; session->state = ND_STATE_INVALID;
return; return;
} }
if (!(neigh->iface = nd_iface_open(NULL, route->oif))) if (!(session->iface = nd_iface_open(NULL, route->oif)))
{ {
/* Could not open interface. */ /* Could not open interface. */
neigh->state = ND_STATE_INVALID; session->state = ND_STATE_INVALID;
return; return;
} }
} }
else if ((neigh->iface = rule->iface)) else if ((session->iface = rule->iface))
{ {
neigh->iface->refs++; session->iface->refs++;
} }
if (neigh->iface) if (session->iface)
{ {
neigh->state = ND_STATE_INCOMPLETE; session->state = ND_STATE_INCOMPLETE;
nd_iface_write_ns(neigh->iface, tgt); nd_iface_write_ns(session->iface, tgt);
ND_LL_PREPEND(neigh->iface->neighs, neigh, next_in_iface); ND_LL_PREPEND(session->iface->sessions, session, next_in_iface);
} }
else else
{ {
neigh->state = ND_STATE_VALID; session->state = ND_STATE_VALID;
nd_iface_write_na(proxy->iface, src, src_ll, tgt, proxy->router); nd_iface_write_na(proxy->iface, src, src_ll, tgt, proxy->router);
} }
} }
void nd_proxy_update_neighs(nd_proxy_t *proxy) static void ndL_update_session(nd_proxy_t *proxy, nd_session_t *session)
{ {
ND_LL_FOREACH_S(proxy->neighs, neigh, tmp, next_in_proxy) switch (session->state)
{ {
switch (neigh->state) case ND_STATE_INCOMPLETE:
if (nd_current_time - session->mtime < nd_conf_retrans_time)
break;
session->mtime = nd_current_time;
if (++session->rcount > nd_conf_retrans_limit)
{ {
case ND_STATE_INCOMPLETE: session->state = ND_STATE_INVALID;
if ((nd_current_time - neigh->touched_at) < nd_conf_retrans_time) nd_log_debug("session [%s] %s INCOMPLETE -> INVALID", proxy->ifname, nd_addr_to_string(&session->tgt));
break; break;
}
neigh->touched_at = nd_current_time; nd_iface_write_ns(session->iface, &session->tgt);
break;
if (++neigh->attempt > 3) case ND_STATE_INVALID:
{ if (nd_current_time - session->mtime < nd_conf_invalid_ttl)
neigh->state = ND_STATE_INVALID;
break;
}
nd_iface_write_ns(neigh->iface, &neigh->tgt);
break; break;
case ND_STATE_INVALID: ND_LL_DELETE(session->iface->sessions, session, next_in_iface);
if ((nd_current_time - neigh->touched_at) < nd_conf_invalid_ttl) ND_LL_DELETE(proxy->sessions, session, next_in_proxy);
break;
ND_LL_DELETE(neigh->iface->neighs, neigh, next_in_iface); nd_iface_close(session->iface);
ND_LL_DELETE(proxy->neighs, neigh, next_in_proxy); nd_free_session(session);
nd_log_debug("session [%s] %s INVALID -> (deleted)", proxy->ifname, nd_addr_to_string(&session->tgt));
break;
nd_iface_close(neigh->iface); case ND_STATE_VALID:
nd_free_neigh(neigh); if (nd_current_time - session->mtime < nd_conf_valid_ttl)
break; break;
case ND_STATE_VALID: session->mtime = nd_current_time;
if (nd_current_time - neigh->touched_at < nd_conf_valid_ttl - nd_conf_renew) session->rtime = nd_current_time;
session->state = ND_STATE_STALE;
session->rcount = 0;
nd_log_debug("session [%s] %s VALID -> STALE", proxy->ifname, nd_addr_to_string(&session->tgt));
nd_iface_write_ns(session->iface, &session->tgt);
break;
case ND_STATE_STALE:
if (nd_current_time - session->mtime >= nd_conf_stale_ttl)
{
session->mtime = nd_current_time;
session->state = ND_STATE_INVALID;
nd_log_debug("session [%s] %s STALE -> INVALID", proxy->ifname, nd_addr_to_string(&session->tgt));
}
else
{
long t = session->rcount && !(session->rcount % nd_conf_retrans_limit)
? ((1 << session->rcount / 3) * nd_conf_retrans_time)
: nd_conf_retrans_time;
if (nd_current_time - session->rtime < t)
break; break;
session->rcount++;
session->rtime = nd_current_time;
nd_iface_write_ns(session->iface, &session->tgt);
}
break;
}
}
void nd_proxy_update_all()
{
ND_LL_FOREACH(ndL_proxies, proxy, next)
/* TODO: Send solicit. */ {
break; ND_LL_FOREACH_S(proxy->sessions, session, tmp, next_in_proxy)
{
case ND_STATE_VALID_REFRESH: ndL_update_session(proxy, session);
if ((nd_current_time - neigh->touched_at) < nd_conf_retrans_time)
break;
if (++neigh->attempt > 3)
{
neigh->state = ND_STATE_INVALID;
neigh->touched_at = nd_current_time;
break;
}
/* TODO: Send solicit. */
break;
} }
} }
} }
@ -206,6 +226,8 @@ bool nd_proxy_startup()
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;
if (proxy->promisc) if (proxy->promisc)
nd_iface_set_promisc(proxy->iface, true); nd_iface_set_promisc(proxy->iface, true);
else else

View File

@ -30,15 +30,15 @@ struct nd_proxy
nd_iface_t *iface; nd_iface_t *iface;
nd_rule_t *rules; nd_rule_t *rules;
nd_neigh_t *neighs; nd_session_t *sessions;
bool router; bool router;
bool promisc; bool promisc;
}; };
/* proxy.c */ /* proxy.c */
nd_proxy_t *nd_proxy_create(const char *ifname); nd_proxy_t *nd_proxy_create(const char *ifname);
void nd_proxy_handle_na(nd_proxy_t *proxy, nd_addr_t *src, nd_addr_t *tgt);
void nd_proxy_handle_ns(nd_proxy_t *proxy, nd_addr_t *src, nd_addr_t *dst, nd_addr_t *tgt, uint8_t *src_ll); void nd_proxy_handle_ns(nd_proxy_t *proxy, nd_addr_t *src, nd_addr_t *dst, nd_addr_t *tgt, uint8_t *src_ll);
bool nd_proxy_startup(); bool nd_proxy_startup();
void nd_proxy_update_all();
#endif // NDPPD_PROXY_H #endif // NDPPD_PROXY_H

View File

@ -18,28 +18,26 @@
*/ */
#include <string.h> #include <string.h>
#include "neigh.h"
#include "ndppd.h" #include "ndppd.h"
#include "session.h"
static nd_neigh_t *ndL_free_neighs; static nd_session_t *ndL_free_sessions;
nd_neigh_t *nd_alloc_neigh() nd_session_t *nd_alloc_session()
{ {
nd_neigh_t *neigh = ndL_free_neighs; nd_session_t *session = ndL_free_sessions;
if (neigh) if (session)
ND_LL_DELETE(ndL_free_neighs, neigh, next_in_proxy); ND_LL_DELETE(ndL_free_sessions, session, next_in_proxy);
else else
neigh = ND_ALLOC(nd_neigh_t); session = ND_ALLOC(nd_session_t);
memset(neigh, 0, sizeof(nd_neigh_t)); memset(session, 0, sizeof(nd_session_t));
return neigh; return session;
} }
void nd_free_neigh(nd_neigh_t *session) void nd_free_session(nd_session_t *session)
{ {
ND_LL_PREPEND(ndL_free_neighs, session, next_in_proxy); ND_LL_PREPEND(ndL_free_sessions, session, next_in_proxy);
} }

View File

@ -16,8 +16,8 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with ndppd. If not, see <https://www.gnu.org/licenses/>. * along with ndppd. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef NDPPD_NEIGH_H #ifndef NDPPD_SESSION_H
#define NDPPD_NEIGH_H #define NDPPD_SESSION_H
#include "ndppd.h" #include "ndppd.h"
@ -34,9 +34,9 @@ typedef enum
ND_STATE_VALID, ND_STATE_VALID,
/* /*
* Resolution was successful, but this entry is getting old. *
*/ */
ND_STATE_VALID_REFRESH, ND_STATE_STALE,
/* /*
* Resolution failed, and further Neighbor Solicitation messages will be ignored until * Resolution failed, and further Neighbor Solicitation messages will be ignored until
@ -46,20 +46,19 @@ typedef enum
} nd_state_t; } nd_state_t;
struct nd_neigh struct nd_session
{ {
nd_neigh_t *next_in_proxy; nd_session_t *next_in_proxy;
nd_neigh_t *next_in_iface; nd_session_t *next_in_iface;
nd_addr_t tgt; nd_addr_t tgt;
int attempt; int rcount;
long touched_at; long rtime;
long used_at; long mtime;
nd_state_t state; nd_state_t state;
nd_iface_t *iface; nd_iface_t *iface;
}; };
nd_neigh_t *nd_alloc_neigh(); nd_session_t *nd_alloc_session();
void nd_free_neigh(nd_neigh_t *session); void nd_free_session(nd_session_t *session);
void nd_session_send_ns(nd_neigh_t *session);
#endif /* NDPPD_NEIGH_H */ #endif /*NDPPD_SESSION_H*/