From e9a21fdb43c9f94762a724db1a043b376f745ae3 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Mon, 17 Feb 2014 21:08:29 +0100 Subject: [PATCH] Add support for (managed) prefixes of length 65-96 --- src/dhcpv6-ia.c | 7 +++---- src/ndp.c | 31 +------------------------------ src/odhcpd.c | 30 ++++++++++++++++++++++++++++++ src/odhcpd.h | 3 +++ src/router.c | 13 +++++++------ 5 files changed, 44 insertions(+), 40 deletions(-) diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index 4d68258..cca6664 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -233,7 +233,7 @@ void dhcpv6_write_statefile(void) struct in6_addr addr; for (size_t i = 0; i < iface->ia_addr_len; ++i) { - if (iface->ia_addr[i].prefix > 64) + if (iface->ia_addr[i].prefix > 96) continue; addr = iface->ia_addr[i].addr; @@ -451,7 +451,6 @@ static void update(struct interface *iface) if (addr[i].prefix > minprefix) minprefix = addr[i].prefix; - addr[i].addr.s6_addr32[2] = 0; addr[i].addr.s6_addr32[3] = 0; if (addr[i].preferred < UINT32_MAX - now) @@ -604,7 +603,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, uint32_t prefix_pref = iface->ia_addr[i].preferred - now; uint32_t prefix_valid = iface->ia_addr[i].valid - now; - if (iface->ia_addr[i].prefix > 64 || + if (iface->ia_addr[i].prefix > 96 || iface->ia_addr[i].preferred <= (uint32_t)now) continue; @@ -712,7 +711,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, bool found = false; if (a) { for (size_t i = 0; i < iface->ia_addr_len; ++i) { - if (iface->ia_addr[i].prefix > 64 || + if (iface->ia_addr[i].prefix > 96 || iface->ia_addr[i].preferred <= (uint32_t)now) continue; diff --git a/src/ndp.c b/src/ndp.c index 02c2dbd..6d18bb5 100644 --- a/src/ndp.c +++ b/src/ndp.c @@ -364,41 +364,12 @@ static void free_neighbor(struct ndp_neighbor *n) --neighbor_count; } - -static bool match_neighbor(struct ndp_neighbor *n, struct in6_addr *addr) -{ - if (n->len <= 32) - return ntohl(n->addr.s6_addr32[0]) >> (32 - n->len) == - ntohl(addr->s6_addr32[0]) >> (32 - n->len); - - if (n->addr.s6_addr32[0] != addr->s6_addr32[0]) - return false; - - if (n->len <= 64) - return ntohl(n->addr.s6_addr32[1]) >> (64 - n->len) == - ntohl(addr->s6_addr32[1]) >> (64 - n->len); - - if (n->addr.s6_addr32[1] != addr->s6_addr32[1]) - return false; - - if (n->len <= 96) - return ntohl(n->addr.s6_addr32[2]) >> (96 - n->len) == - ntohl(addr->s6_addr32[2]) >> (96 - n->len); - - if (n->addr.s6_addr32[2] != addr->s6_addr32[2]) - return false; - - return ntohl(n->addr.s6_addr32[3]) >> (128 - n->len) == - ntohl(addr->s6_addr32[3]) >> (128 - n->len); -} - - static struct ndp_neighbor* find_neighbor(struct in6_addr *addr, bool strict) { time_t now = time(NULL); struct ndp_neighbor *n, *e; list_for_each_entry_safe(n, e, &neighbors, head) { - if ((!strict && match_neighbor(n, addr)) || + if ((!strict && !odhcpd_bmemcmp(&n->addr, addr, n->len)) || (n->len == 128 && IN6_ARE_ADDR_EQUAL(&n->addr, addr))) return n; diff --git a/src/odhcpd.c b/src/odhcpd.c index f40cea0..25a6047 100644 --- a/src/odhcpd.c +++ b/src/odhcpd.c @@ -427,3 +427,33 @@ void odhcpd_hexlify(char *dst, const uint8_t *src, size_t len) } *dst = 0; } + + +int odhcpd_bmemcmp(const void *av, const void *bv, size_t bits) +{ + const uint8_t *a = av, *b = bv; + size_t bytes = bits / 8; + bits %= 8; + + int res = memcmp(a, b, bytes); + if (res == 0 && bits > 0) + res = (a[bytes] >> (8 - bits)) - (b[bytes] >> (8 - bits)); + + return res; +} + + +void odhcpd_bmemcpy(void *av, const void *bv, size_t bits) +{ + uint8_t *a = av; + const uint8_t *b = bv; + + size_t bytes = bits / 8; + bits %= 8; + memcpy(a, b, bytes); + + if (bits > 0) { + uint8_t mask = (1 << (8 - bits)) - 1; + a[bytes] = (a[bytes] & mask) | ((~mask) & b[bytes]); + } +} diff --git a/src/odhcpd.h b/src/odhcpd.h index 789f696..010cd9e 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -188,6 +188,9 @@ time_t odhcpd_time(void); ssize_t odhcpd_unhexlify(uint8_t *dst, size_t len, const char *src); void odhcpd_hexlify(char *dst, const uint8_t *src, size_t len); +int odhcpd_bmemcmp(const void *av, const void *bv, size_t bits); +void odhcpd_bmemcpy(void *av, const void *bv, size_t bits); + int config_parse_interface(void *data, size_t len, const char *iname, bool overwrite); #ifdef WITH_UBUS diff --git a/src/router.c b/src/router.c index 372c400..907011a 100644 --- a/src/router.c +++ b/src/router.c @@ -296,7 +296,7 @@ static void send_router_advert(struct uloop_timeout *event) for (ssize_t i = 0; i < ipcnt; ++i) { struct odhcpd_ipaddr *addr = &addrs[i]; - if (addr->prefix > 64 || addr->has_class) + if (addr->prefix > 96 || addr->has_class) continue; // Address not suitable if (addr->preferred > MaxPreferredTime) @@ -307,8 +307,9 @@ static void send_router_advert(struct uloop_timeout *event) struct nd_opt_prefix_info *p = NULL; for (size_t i = 0; i < cnt; ++i) { - if (!memcmp(&adv.prefix[i].nd_opt_pi_prefix, - &addr->addr, 8)) + if (addr->prefix == adv.prefix[i].nd_opt_pi_prefix_len && + !odhcpd_bmemcmp(&adv.prefix[i].nd_opt_pi_prefix, + &addr->addr, addr->prefix)) p = &adv.prefix[i]; } @@ -326,14 +327,14 @@ static void send_router_advert(struct uloop_timeout *event) maxpreferred = 1000 * addr->preferred; } - memcpy(&p->nd_opt_pi_prefix, &addr->addr, 8); + odhcpd_bmemcpy(&p->nd_opt_pi_prefix, &addr->addr, addr->prefix); p->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; p->nd_opt_pi_len = 4; - p->nd_opt_pi_prefix_len = 64; + p->nd_opt_pi_prefix_len = (addr->prefix < 64) ? 64 : addr->prefix; p->nd_opt_pi_flags_reserved = 0; if (!iface->ra_not_onlink) p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK; - if (iface->managed < RELAYD_MANAGED_NO_AFLAG) + if (iface->managed < RELAYD_MANAGED_NO_AFLAG && addr->prefix <= 64) p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO; p->nd_opt_pi_valid_time = htonl(addr->valid); p->nd_opt_pi_preferred_time = htonl(addr->preferred); -- 2.25.1