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"
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;

View File

@ -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)

View File

@ -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;
};

View File

@ -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;
}

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_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;

View File

@ -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

View File

@ -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

View File

@ -18,28 +18,26 @@
*/
#include <string.h>
#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);
}

View File

@ -16,8 +16,8 @@
* You should have received a copy of the GNU General Public License
* along with ndppd. If not, see <https://www.gnu.org/licenses/>.
*/
#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*/