From 8028e2d487f181f90758a59edecec47cdf440cf8 Mon Sep 17 00:00:00 2001 From: Daniel Adolfsson Date: Wed, 11 Dec 2019 13:21:29 +0100 Subject: [PATCH] Continue work on handling TTLs --- src/conf.c | 3 +- src/iface.c | 20 ++--- src/iface.h | 2 +- src/ndppd.c | 3 + src/ndppd.h | 2 +- src/proxy.c | 148 +++++++++++++++++++++---------------- src/proxy.h | 4 +- src/{neigh.c => session.c} | 24 +++--- src/{neigh.h => session.h} | 27 ++++--- 9 files changed, 128 insertions(+), 105 deletions(-) rename src/{neigh.c => session.c} (64%) rename src/{neigh.h => session.h} (74%) diff --git a/src/conf.c b/src/conf.c index 2e3546c..252b608 100644 --- a/src/conf.c +++ b/src/conf.c @@ -40,7 +40,8 @@ #include "rule.h" 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_retrans_limit = 3; int nd_conf_retrans_time = 1000; diff --git a/src/iface.c b/src/iface.c index f616c81..8ca798d 100644 --- a/src/iface.c +++ b/src/iface.c @@ -34,8 +34,8 @@ #include "addr.h" #include "iface.h" #include "ndppd.h" -#include "neigh.h" #include "proxy.h" +#include "session.h" #include "sio.h" extern int nd_conf_invalid_ttl; @@ -55,7 +55,7 @@ typedef struct struct icmp6_hdr icmp6_hdr; } 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; @@ -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); - if (ifa->proxy) - nd_proxy_handle_ns(ifa->proxy, &msg->ip6_hdr.ip6_src, &msg->ip6_hdr.ip6_dst, &ns->nd_ns_target, lladdr); + if (iface->proxy) + 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) @@ -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; - nd_neigh_t *neigh; - ND_LL_SEARCH(iface->neighs, neigh, next_in_iface, nd_addr_eq(&neigh->tgt, &na->nd_na_target)); + nd_session_t *session; + ND_LL_SEARCH(iface->sessions, session, next_in_iface, nd_addr_eq(&session->tgt, &na->nd_na_target)); - if (!neigh) + if (!session) return; - neigh->state = ND_STATE_VALID; - neigh->ttl = nd_conf_valid_ttl; - neigh->touched_at = nd_current_time; + session->state = ND_STATE_VALID; + session->mtime = 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) diff --git a/src/iface.h b/src/iface.h index cd2b493..2db36c9 100644 --- a/src/iface.h +++ b/src/iface.h @@ -36,7 +36,7 @@ struct nd_iface int old_promisc; 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; }; diff --git a/src/ndppd.c b/src/ndppd.c index 626e8a9..814cc32 100644 --- a/src/ndppd.c +++ b/src/ndppd.c @@ -225,9 +225,12 @@ int main(int argc, char *argv[]) if (!nd_sio_poll()) { + /* TODO: Error */ break; } + nd_proxy_update_all(); + gettimeofday(&t1, 0); nd_current_time = t1.tv_sec * 1000 + t1.tv_usec / 1000; } diff --git a/src/ndppd.h b/src/ndppd.h index 8385f2a..ea61d0c 100644 --- a/src/ndppd.h +++ b/src/ndppd.h @@ -34,7 +34,7 @@ typedef struct in6_addr nd_addr_t; typedef struct nd_conf_rule nd_conf_rule_t; typedef struct nd_conf_proxy nd_conf_proxy_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 bool nd_daemonized; diff --git a/src/proxy.c b/src/proxy.c index b6aebdb..33bfeb6 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -22,15 +22,16 @@ #include "addr.h" #include "iface.h" #include "ndppd.h" -#include "neigh.h" #include "proxy.h" #include "rtnl.h" #include "rule.h" +#include "session.h" static nd_proxy_t *ndL_proxies; extern int nd_conf_invalid_ttl; extern int nd_conf_valid_ttl; +extern int nd_conf_stale_ttl; extern int nd_conf_renew; extern int nd_conf_retrans_limit; extern int nd_conf_retrans_time; @@ -54,7 +55,7 @@ nd_proxy_t *nd_proxy_create(const char *ifname) proxy->iface = NULL; proxy->rules = NULL; - proxy->neighs = NULL; + proxy->sessions = NULL; proxy->router = false; 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], 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; - 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); return; } @@ -94,11 +94,11 @@ void nd_proxy_handle_ns(nd_proxy_t *proxy, nd_addr_t *src, __attribute__((unused if (!rule) return; - neigh = nd_alloc_neigh(); - neigh->touched_at = nd_current_time; - neigh->tgt = *tgt; + session = nd_alloc_session(); + session->mtime = nd_current_time; + 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) { @@ -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) { /* Could not find a matching route. */ - neigh->state = ND_STATE_INVALID; + session->state = ND_STATE_INVALID; return; } - if (!(neigh->iface = nd_iface_open(NULL, route->oif))) + if (!(session->iface = nd_iface_open(NULL, route->oif))) { /* Could not open interface. */ - neigh->state = ND_STATE_INVALID; + session->state = ND_STATE_INVALID; 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; - nd_iface_write_ns(neigh->iface, tgt); + session->state = ND_STATE_INCOMPLETE; + 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 { - neigh->state = ND_STATE_VALID; + session->state = ND_STATE_VALID; 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: - if ((nd_current_time - neigh->touched_at) < nd_conf_retrans_time) - break; + session->state = ND_STATE_INVALID; + nd_log_debug("session [%s] %s INCOMPLETE -> INVALID", proxy->ifname, nd_addr_to_string(&session->tgt)); + break; + } - neigh->touched_at = nd_current_time; + nd_iface_write_ns(session->iface, &session->tgt); + break; - if (++neigh->attempt > 3) - { - neigh->state = ND_STATE_INVALID; - break; - } - - nd_iface_write_ns(neigh->iface, &neigh->tgt); + case ND_STATE_INVALID: + if (nd_current_time - session->mtime < nd_conf_invalid_ttl) break; - case ND_STATE_INVALID: - if ((nd_current_time - neigh->touched_at) < nd_conf_invalid_ttl) - break; + ND_LL_DELETE(session->iface->sessions, session, next_in_iface); + ND_LL_DELETE(proxy->sessions, session, next_in_proxy); - ND_LL_DELETE(neigh->iface->neighs, neigh, next_in_iface); - ND_LL_DELETE(proxy->neighs, neigh, next_in_proxy); + nd_iface_close(session->iface); + 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); - nd_free_neigh(neigh); + case ND_STATE_VALID: + if (nd_current_time - session->mtime < nd_conf_valid_ttl) break; - case ND_STATE_VALID: - if (nd_current_time - neigh->touched_at < nd_conf_valid_ttl - nd_conf_renew) + session->mtime = nd_current_time; + 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; + session->rcount++; + session->rtime = nd_current_time; + nd_iface_write_ns(session->iface, &session->tgt); + } + break; + } +} - - - - /* TODO: Send solicit. */ - break; - - case ND_STATE_VALID_REFRESH: - 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; +void nd_proxy_update_all() +{ + ND_LL_FOREACH(ndL_proxies, proxy, next) + { + ND_LL_FOREACH_S(proxy->sessions, session, tmp, next_in_proxy) + { + ndL_update_session(proxy, session); } } } @@ -206,6 +226,8 @@ bool nd_proxy_startup() if (!(proxy->iface = nd_iface_open(proxy->ifname, 0))) return false; + proxy->iface->proxy = proxy; + if (proxy->promisc) nd_iface_set_promisc(proxy->iface, true); else diff --git a/src/proxy.h b/src/proxy.h index 4f5649b..09d22ba 100644 --- a/src/proxy.h +++ b/src/proxy.h @@ -30,15 +30,15 @@ struct nd_proxy nd_iface_t *iface; nd_rule_t *rules; - nd_neigh_t *neighs; + nd_session_t *sessions; bool router; bool promisc; }; /* proxy.c */ 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); bool nd_proxy_startup(); +void nd_proxy_update_all(); #endif // NDPPD_PROXY_H diff --git a/src/neigh.c b/src/session.c similarity index 64% rename from src/neigh.c rename to src/session.c index 84957e2..e2dd0fb 100644 --- a/src/neigh.c +++ b/src/session.c @@ -18,28 +18,26 @@ */ #include -#include "neigh.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) - ND_LL_DELETE(ndL_free_neighs, neigh, next_in_proxy); + if (session) + ND_LL_DELETE(ndL_free_sessions, session, next_in_proxy); 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); } - - diff --git a/src/neigh.h b/src/session.h similarity index 74% rename from src/neigh.h rename to src/session.h index c5e5f13..305c22b 100644 --- a/src/neigh.h +++ b/src/session.h @@ -16,8 +16,8 @@ * You should have received a copy of the GNU General Public License * along with ndppd. If not, see . */ -#ifndef NDPPD_NEIGH_H -#define NDPPD_NEIGH_H +#ifndef NDPPD_SESSION_H +#define NDPPD_SESSION_H #include "ndppd.h" @@ -34,9 +34,9 @@ typedef enum 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 @@ -46,20 +46,19 @@ typedef enum } nd_state_t; -struct nd_neigh +struct nd_session { - nd_neigh_t *next_in_proxy; - nd_neigh_t *next_in_iface; + nd_session_t *next_in_proxy; + nd_session_t *next_in_iface; nd_addr_t tgt; - int attempt; - long touched_at; - long used_at; + int rcount; + long rtime; + long mtime; nd_state_t state; nd_iface_t *iface; }; -nd_neigh_t *nd_alloc_neigh(); -void nd_free_neigh(nd_neigh_t *session); -void nd_session_send_ns(nd_neigh_t *session); +nd_session_t *nd_alloc_session(); +void nd_free_session(nd_session_t *session); -#endif /* NDPPD_NEIGH_H */ +#endif /*NDPPD_SESSION_H*/