From be97afdf83bd15ee8348f260dbbd07b347ad3e39 Mon Sep 17 00:00:00 2001 From: Daniel Adolfsson Date: Wed, 11 Dec 2019 17:19:00 +0100 Subject: [PATCH] Start tracking DELADDR + cleanup --- ChangeLog | 1 - src/addr.c | 18 ++++----------- src/addr.h | 2 +- src/conf.c | 1 - src/iface.c | 37 ++++++++++-------------------- src/iface.h | 2 +- src/proxy.c | 14 ++++++------ src/rtnl.c | 66 +++++++++++++++++++++++++++++++++++++---------------- src/rtnl.h | 2 +- src/sio.c | 5 ++++ 10 files changed, 78 insertions(+), 70 deletions(-) diff --git a/ChangeLog b/ChangeLog index e24aec0..a912975 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/src/addr.c b/src/addr.c index c6e5950..2ffbe3a 100644 --- a/src/addr.c +++ b/src/addr.c @@ -21,15 +21,12 @@ #include "ndppd.h" -/*! Get the string representation of the specified address. +/*! Returns the string representation of addr. * * @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 addr 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 pflen bits are the same in first and second. */ 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 first and second 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] && diff --git a/src/addr.h b/src/addr.h index 1d4e58b..74f41c9 100644 --- a/src/addr.h +++ b/src/addr.h @@ -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); diff --git a/src/conf.c b/src/conf.c index 252b608..7e64b20 100644 --- a/src/conf.c +++ b/src/conf.c @@ -34,7 +34,6 @@ # define INT_MIN (-INT_MAX - 1) #endif -#include "conf.h" #include "ndppd.h" #include "proxy.h" #include "rule.h" diff --git a/src/iface.c b/src/iface.c index 1d1c443..91be2ad 100644 --- a/src/iface.c +++ b/src/iface.c @@ -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); } } diff --git a/src/iface.h b/src/iface.h index 5992bfc..006449e 100644 --- a/src/iface.h +++ b/src/iface.h @@ -25,7 +25,7 @@ struct nd_iface { nd_iface_t *next; - int refs; + int refcount; char name[IF_NAMESIZE]; uint8_t lladdr[6]; diff --git a/src/proxy.c b/src/proxy.c index f691437..df87034 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -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 { diff --git a/src/rtnl.c b/src/rtnl.c index 8682c12..d58f869 100644 --- a/src/rtnl.c +++ b/src/rtnl.c @@ -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)); } } } diff --git a/src/rtnl.h b/src/rtnl.h index 29cf1c6..f2d89d0 100644 --- a/src/rtnl.h +++ b/src/rtnl.h @@ -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; }; diff --git a/src/sio.c b/src/sio.c index d794de1..ce58fbd 100644 --- a/src/sio.c +++ b/src/sio.c @@ -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; }