Start tracking DELADDR + cleanup

This commit is contained in:
Daniel Adolfsson 2019-12-11 17:19:00 +01:00
parent ef90c04257
commit be97afdf83
10 changed files with 78 additions and 70 deletions

View File

@ -12,7 +12,6 @@
* Managing routes and keeping track of local addresses are now done
through the use of Netlink. As such, /proc/* support is now gone.
*
2017-01-07 Johnathan Sharratt <johnathan.sharratt@gmail.com>

View File

@ -21,15 +21,12 @@
#include "ndppd.h"
/*! Get the string representation of the specified address.
/*! Returns the string representation of <tt>addr</tt>.
*
* @note This function returns a pointer to static data. It uses three different static arrays
* to allow the function to be chained.
*
* @param addr
* @return
*/
const char *nd_addr_to_string(nd_addr_t *addr)
const char *nd_aton(nd_addr_t *addr)
{
static int index;
static char buf[3][64];
@ -42,7 +39,7 @@ const char *nd_addr_to_string(nd_addr_t *addr)
return inet_ntop(AF_INET6, addr, buf[n], sizeof(buf[n]));
}
/*! Returns true if the specified address is a multicast address. */
/*! Returns true if <tt>addr</tt> is a multicast address. */
bool nd_addr_is_multicast(nd_addr_t *addr)
{
return addr->s6_addr[0] == 0xff;
@ -53,13 +50,7 @@ bool nd_addr_is_unicast(nd_addr_t *addr)
return !(addr->s6_addr32[2] == 0 && addr->s6_addr32[3] == 0) && addr->s6_addr[0] != 0xff;
}
/*! Compares two addresses using the specified prefix length.
*
* @param first
* @param second
* @param pflen
* @return true if there is a match
*/
/*! 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, int pflen)
{
if (pflen < 0 || pflen > 128)
@ -101,6 +92,7 @@ bool nd_addr_match(nd_addr_t *first, nd_addr_t *second, int pflen)
return true;
}
/*! Returns true if <tt>first</tt> and <tt>second</tt> are the same. */
bool nd_addr_eq(nd_addr_t *first, nd_addr_t *second)
{
return first->s6_addr32[0] == second->s6_addr32[0] && first->s6_addr32[1] == second->s6_addr32[1] &&

View File

@ -24,7 +24,7 @@
bool nd_addr_is_multicast(nd_addr_t *addr);
bool nd_addr_is_unicast(nd_addr_t *addr);
const char *nd_addr_to_string(nd_addr_t *addr);
const char *nd_aton(nd_addr_t *addr);
bool nd_addr_match(nd_addr_t *first, nd_addr_t *second, int pflen);
bool nd_addr_eq(nd_addr_t *first, nd_addr_t *second);

View File

@ -34,7 +34,6 @@
# define INT_MIN (-INT_MAX - 1)
#endif
#include "conf.h"
#include "ndppd.h"
#include "proxy.h"
#include "rule.h"

View File

@ -47,6 +47,7 @@ extern bool nd_conf_keepalive;
static nd_iface_t *ndL_first_iface, *ndL_first_free_iface;
/* Used when daemonizing to make sure the parent process does not restore these flags upon exit. */
bool nd_iface_no_restore_flags;
typedef struct
@ -62,11 +63,9 @@ static void ndL_handle_ns(nd_iface_t *iface, ndL_icmp6_msg_t *msg)
if (msg->ip6_hdr.ip6_plen < sizeof(struct nd_neighbor_solicit))
return;
/* TODO: We need to properly parse options here. */
/* We're not doing "proper" parsing of options here. */
size_t optlen = ntohs(msg->ip6_hdr.ip6_plen) - sizeof(struct nd_neighbor_solicit);
if (optlen < 8)
if (ntohs(msg->ip6_hdr.ip6_plen) - sizeof(struct nd_neighbor_solicit) < 8)
return;
struct nd_opt_hdr *opt = (struct nd_opt_hdr *)((void *)ns + sizeof(struct nd_neighbor_solicit));
@ -74,10 +73,10 @@ static void ndL_handle_ns(nd_iface_t *iface, ndL_icmp6_msg_t *msg)
if (opt->nd_opt_len != 1 || opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR)
return;
uint8_t *lladdr = (uint8_t *)((void *)opt + 2);
uint8_t *src_ll = (uint8_t *)((void *)opt + 2);
if (iface->proxy)
nd_proxy_handle_ns(iface->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, src_ll);
}
static void ndL_handle_na(nd_iface_t *iface, ndL_icmp6_msg_t *msg)
@ -97,7 +96,7 @@ static void ndL_handle_na(nd_iface_t *iface, ndL_icmp6_msg_t *msg)
{
session->state = ND_STATE_VALID;
session->mtime = nd_current_time;
nd_log_debug("session [%s] %s ? -> VALID", "?", nd_addr_to_string(&session->tgt));
nd_log_debug("session [%s] %s ? -> VALID", "?", nd_aton(&session->tgt));
}
session->atime = nd_current_time;
@ -156,23 +155,17 @@ 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;
if ((size_t)buflen < sizeof(ndL_icmp6_msg_t))
/* TODO: log. Invalid length. */
return;
if ((size_t)buflen != sizeof(struct ip6_hdr) + ntohs(msg->ip6_hdr.ip6_plen))
/* TODO: log. Invalid length. */
return;
if (msg->ip6_hdr.ip6_nxt != IPPROTO_ICMPV6)
/* TODO: log. Invalid next header. */
return;
if (ndL_calculate_icmp6_checksum(msg, buflen) != msg->icmp6_hdr.icmp6_cksum)
/* TODO: log. Invalid checksum. */
return;
/* TODO: Validate checksum, lengths, etc. */
if (msg->icmp6_hdr.icmp6_type == ND_NEIGHBOR_SOLICIT)
ndL_handle_ns(iface, msg);
else if (msg->icmp6_hdr.icmp6_type == ND_NEIGHBOR_ADVERT)
@ -199,13 +192,7 @@ static void ndL_sio_handler(nd_sio_t *sio, __attribute__((unused)) int events)
return;
if (len < 0)
{
if (errno == EAGAIN)
return;
/* TODO */
return;
}
ndL_handle_packet(ifa, buf, len);
}
@ -241,7 +228,7 @@ nd_iface_t *nd_iface_open(const char *name, unsigned int index)
if (iface)
{
iface->refs++;
iface->refcount++;
return iface;
}
@ -311,7 +298,7 @@ nd_iface_t *nd_iface_open(const char *name, unsigned int index)
iface->sio = sio;
iface->index = index;
iface->refs = 1;
iface->refcount = 1;
iface->old_allmulti = -1;
iface->old_promisc = -1;
strcpy(iface->name, name);
@ -327,7 +314,7 @@ nd_iface_t *nd_iface_open(const char *name, unsigned int index)
void nd_iface_close(nd_iface_t *iface)
{
if (--iface->refs > 0)
if (--iface->refcount > 0)
return;
if (!nd_iface_no_restore_flags)
@ -408,7 +395,7 @@ ssize_t nd_iface_write_na(nd_iface_t *iface, nd_addr_t *dst, uint8_t *dst_ll, nd
memcpy(msg.lladdr, iface->lladdr, sizeof(msg.lladdr));
nd_log_info("Write NA tgt=%s, dst=%s [%x:%x:%x:%x:%x:%x dev %s]", nd_addr_to_string(tgt), nd_addr_to_string(dst),
nd_log_info("Write NA tgt=%s, dst=%s [%x:%x:%x:%x:%x:%x dev %s]", nd_aton(tgt), nd_aton(dst),
dst_ll[0], dst_ll[1], dst_ll[2], dst_ll[3], dst_ll[4], dst_ll[5], iface->name);
return ndL_send_icmp6(iface, (ndL_icmp6_msg_t *)&msg, sizeof(msg), dst_ll);
@ -445,7 +432,7 @@ ssize_t nd_iface_write_ns(nd_iface_t *ifa, nd_addr_t *tgt)
uint8_t ll_mcast[6] = { 0x33, 0x33 };
*(uint32_t *)&ll_mcast[2] = tgt->s6_addr32[3];
nd_log_trace("Write NS iface=%s, tgt=%s", ifa->name, nd_addr_to_string(tgt));
nd_log_trace("Write NS iface=%s, tgt=%s", ifa->name, nd_aton(tgt));
return ndL_send_icmp6(ifa, (ndL_icmp6_msg_t *)&msg, sizeof(msg), ll_mcast);
}
@ -521,7 +508,7 @@ void nd_iface_cleanup()
ND_LL_FOREACH_S(ndL_first_iface, iface, tmp, next)
{
/* We're gonna be bad and just ignore refs here as all memory will soon be invalid anyway. */
iface->refs = 1;
iface->refcount = 1;
nd_iface_close(iface);
}
}

View File

@ -25,7 +25,7 @@
struct nd_iface
{
nd_iface_t *next;
int refs;
int refcount;
char name[IF_NAMESIZE];
uint8_t lladdr[6];

View File

@ -66,8 +66,8 @@ nd_proxy_t *nd_proxy_create(const char *ifname)
void nd_proxy_handle_ns(nd_proxy_t *proxy, nd_addr_t *src, __attribute__((unused)) nd_addr_t *dst, nd_addr_t *tgt,
uint8_t *src_ll)
{
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_log_trace("Handle NA src=%s [%x:%x:%x:%x:%x:%x], dst=%s, tgt=%s", nd_aton(src), src_ll[0], src_ll[1],
src_ll[2], src_ll[3], src_ll[4], src_ll[5], nd_aton(dst), nd_aton(tgt));
nd_session_t *session;
@ -125,7 +125,7 @@ void nd_proxy_handle_ns(nd_proxy_t *proxy, nd_addr_t *src, __attribute__((unused
}
else if ((session->iface = rule->iface))
{
session->iface->refs++;
session->iface->refcount++;
}
if (session->iface)
@ -156,7 +156,7 @@ static void ndL_update_session(nd_proxy_t *proxy, nd_session_t *session)
if (++session->rcount > nd_conf_retrans_limit)
{
session->state = ND_STATE_INVALID;
nd_log_debug("session [%s] %s INCOMPLETE -> INVALID", proxy->ifname, nd_addr_to_string(&session->tgt));
nd_log_debug("session [%s] %s INCOMPLETE -> INVALID", proxy->ifname, nd_aton(&session->tgt));
break;
}
@ -172,7 +172,7 @@ static void ndL_update_session(nd_proxy_t *proxy, nd_session_t *session)
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));
nd_log_debug("session [%s] %s INVALID -> (deleted)", proxy->ifname, nd_aton(&session->tgt));
break;
case ND_STATE_VALID:
@ -184,7 +184,7 @@ static void ndL_update_session(nd_proxy_t *proxy, nd_session_t *session)
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_log_debug("session [%s] %s VALID -> STALE", proxy->ifname, nd_aton(&session->tgt));
nd_iface_write_ns(session->iface, &session->tgt);
break;
@ -193,7 +193,7 @@ static void ndL_update_session(nd_proxy_t *proxy, nd_session_t *session)
{
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));
nd_log_debug("session [%s] %s STALE -> INVALID", proxy->ifname, nd_aton(&session->tgt));
}
else
{

View File

@ -58,7 +58,7 @@ static void ndL_insert_route(nd_rtnl_route_t *route)
}
}
static void ndL_handle_newaddress(struct ifaddrmsg *msg, int length)
static void ndL_handle_newaddr(struct ifaddrmsg *msg, int length)
{
nd_addr_t *addr = NULL;
@ -75,7 +75,7 @@ static void ndL_handle_newaddress(struct ifaddrmsg *msg, int length)
ND_LL_FOREACH_NODEF(ndL_addrs, rt_addr, next)
{
if (nd_addr_eq(&rt_addr->addr, addr) && rt_addr->pflen == msg->ifa_prefixlen)
if (rt_addr->iif == msg->ifa_index && nd_addr_eq(&rt_addr->addr, addr) && rt_addr->pflen == msg->ifa_prefixlen)
return;
}
@ -90,33 +90,29 @@ static void ndL_handle_newaddress(struct ifaddrmsg *msg, int length)
rt_addr->iif = msg->ifa_index;
rt_addr->addr = *addr;
nd_log_debug("rtnl: NEWADDR %s/%d if %d", nd_addr_to_string(addr), msg->ifa_prefixlen, msg->ifa_index);
nd_log_debug("rtnl: NEWADDR %s/%d if %d", nd_aton(addr), msg->ifa_prefixlen, msg->ifa_index);
}
static void ndL_handle_delroute(struct rtmsg *msg, int rtl)
static void ndL_handle_deladdr(struct ifaddrmsg *msg, int length)
{
nd_addr_t *dst = NULL;
int oif = 0;
nd_addr_t *addr = NULL;
for (struct rtattr *rta = RTM_RTA(msg); RTA_OK(rta, rtl); rta = RTA_NEXT(rta, rtl))
for (struct rtattr *rta = IFA_RTA(msg); RTA_OK(rta, length); rta = RTA_NEXT(rta, length))
{
if (rta->rta_type == RTA_OIF)
oif = *(int *)RTA_DATA(rta);
else if (rta->rta_type == RTA_DST)
dst = (nd_addr_t *)RTA_DATA(rta);
if (rta->rta_type == IFA_ADDRESS)
addr = (nd_addr_t *)RTA_DATA(rta);
}
if (!dst || !oif)
if (!addr)
return;
ND_LL_FOREACH(ndL_routes, route, next)
ND_LL_FOREACH(ndL_addrs, rt_addr, next)
{
if (nd_addr_eq(&route->addr, dst) && route->pflen == msg->rtm_dst_len && route->table == msg->rtm_table)
if (rt_addr->iif == msg->ifa_index && nd_addr_eq(&rt_addr->addr, addr) && rt_addr->pflen == msg->ifa_prefixlen)
{
nd_log_debug("rtnl: DELROUTE %s/%d dev %d table %d", nd_addr_to_string(dst), msg->rtm_dst_len, oif,
msg->rtm_table);
ND_LL_DELETE(ndL_routes, route, next);
ND_LL_PREPEND(ndL_free_routes, route, next);
ND_LL_DELETE(ndL_addrs, rt_addr, next);
ND_LL_PREPEND(ndL_free_addrs, rt_addr, next);
nd_log_debug("rtnl: DELADDR %s/%d if %d", nd_aton(addr), msg->ifa_prefixlen, msg->ifa_index);
return;
}
}
@ -162,7 +158,35 @@ static void ndL_handle_newroute(struct rtmsg *msg, int rtl)
ndL_insert_route(route);
nd_log_debug("rtnl: NEWROUTE %s/%d dev %d table %d", nd_addr_to_string(dst), msg->rtm_dst_len, oif, msg->rtm_table);
nd_log_debug("rtnl: NEWROUTE %s/%d dev %d table %d", nd_aton(dst), msg->rtm_dst_len, oif, msg->rtm_table);
}
static void ndL_handle_delroute(struct rtmsg *msg, int rtl)
{
nd_addr_t *dst = NULL;
int oif = 0;
for (struct rtattr *rta = RTM_RTA(msg); RTA_OK(rta, rtl); rta = RTA_NEXT(rta, rtl))
{
if (rta->rta_type == RTA_OIF)
oif = *(int *)RTA_DATA(rta);
else if (rta->rta_type == RTA_DST)
dst = (nd_addr_t *)RTA_DATA(rta);
}
if (!dst || !oif)
return;
ND_LL_FOREACH(ndL_routes, route, next)
{
if (nd_addr_eq(&route->addr, dst) && route->pflen == msg->rtm_dst_len && route->table == msg->rtm_table)
{
nd_log_debug("rtnl: DELROUTE %s/%d dev %d table %d", nd_aton(dst), msg->rtm_dst_len, oif, msg->rtm_table);
ND_LL_DELETE(ndL_routes, route, next);
ND_LL_PREPEND(ndL_free_routes, route, next);
return;
}
}
}
static void ndL_sio_handler(__attribute__((unused)) nd_sio_t *unused1, __attribute__((unused)) int unused2)
@ -197,7 +221,9 @@ static void ndL_sio_handler(__attribute__((unused)) nd_sio_t *unused1, __attribu
else if (hdr->nlmsg_type == RTM_DELROUTE)
ndL_handle_delroute((struct rtmsg *)NLMSG_DATA(hdr), RTM_PAYLOAD(hdr));
else if (hdr->nlmsg_type == RTM_NEWADDR)
ndL_handle_newaddress((struct ifaddrmsg *)NLMSG_DATA(hdr), IFA_PAYLOAD(hdr));
ndL_handle_newaddr((struct ifaddrmsg *)NLMSG_DATA(hdr), IFA_PAYLOAD(hdr));
else if (hdr->nlmsg_type == RTM_DELADDR)
ndL_handle_deladdr((struct ifaddrmsg *)NLMSG_DATA(hdr), IFA_PAYLOAD(hdr));
}
}
}

View File

@ -37,7 +37,7 @@ struct nd_rtnl_route
struct nd_rtnl_addr
{
nd_rtnl_addr_t *next;
int iif;
unsigned int iif;
nd_addr_t addr;
int pflen;
};

View File

@ -189,7 +189,12 @@ ssize_t nd_sio_recv(nd_sio_t *sio, struct sockaddr *addr, size_t addrlen, void *
int len;
if ((len = recvmsg(sio->fd, &mhdr, 0)) < 0)
{
if (errno != EAGAIN)
nd_log_error("nd_sio_recv() failed: %s", strerror(errno));
return -1;
}
return len;
}