From 8d8a8cd35137ff0fa11b6be455fdd596a8d7d2e9 Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Wed, 6 Jan 2021 13:04:02 +0100 Subject: dhcpv6-ia: apply prefix_filter on dhcpv6 The prefix_filter allows to select which prefix should be assigned to clients if you have multiple prefixes on an interface. Currently, the filter only applies to RAs and does work with a dhcpv6 server. This commit enables the filter also on dhcpv6. Signed-off-by: Nick Hainke Signed-off-by: Hans Dedecker --- src/dhcpv6-ia.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++---------- src/odhcpd.h | 5 +++++ src/router.c | 8 ++------ 3 files changed, 58 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index a59fc20..639e368 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -231,9 +231,19 @@ void dhcpv6_ia_enum_addrs(struct interface *iface, struct dhcp_assignment *c, if (!valid_addr(&addrs[i], now)) continue; + /* Filter Out Prefixes */ + if (ADDR_MATCH_PIO_FILTER(&addrs[i], iface)) { + char addrbuf[INET6_ADDRSTRLEN]; + syslog(LOG_INFO, "Address %s filtered out on %s", + inet_ntop(AF_INET6, &addrs[i].addr.in6, addrbuf, sizeof(addrbuf)), + iface->name); + continue; + } + addr = addrs[i].addr.in6; pref = addrs[i].preferred; valid = addrs[i].valid; + if (c->flags & OAF_DHCPV6_NA) { if (!ADDR_ENTRY_VALID_IA_ADDR(iface, i, m, addrs)) continue; @@ -443,7 +453,12 @@ static void __apply_lease(struct dhcp_assignment *a, return; for (ssize_t i = 0; i < addr_len; ++i) { - struct in6_addr prefix = addrs[i].addr.in6; + struct in6_addr prefix; + + if (ADDR_MATCH_PIO_FILTER(&addrs[i], a->iface)) + continue; + + prefix = addrs[i].addr.in6; prefix.s6_addr32[1] |= htonl(a->assigned); prefix.s6_addr32[2] = prefix.s6_addr32[3] = 0; netlink_setup_route(&prefix, (a->managed_size) ? addrs[i].prefix : a->length, @@ -467,10 +482,15 @@ static void set_border_assignment_size(struct interface *iface, struct dhcp_assi int minprefix = -1; for (size_t i = 0; i < iface->addr6_len; ++i) { - if (iface->addr6[i].preferred > (uint32_t)now && - iface->addr6[i].prefix < 64 && - iface->addr6[i].prefix > minprefix) - minprefix = iface->addr6[i].prefix; + struct odhcpd_ipaddr *addr = &iface->addr6[i]; + + if (ADDR_MATCH_PIO_FILTER(addr, iface)) + continue; + + if (addr->preferred > (uint32_t)now && + addr->prefix < 64 && + addr->prefix > minprefix) + minprefix = addr->prefix; } if (minprefix > 32 && minprefix <= 64) @@ -847,12 +867,23 @@ static size_t build_ia(uint8_t *buf, size_t buflen, uint16_t status, size_t m = get_preferred_addr(addrs, addrlen); for (size_t i = 0; i < addrlen; ++i) { - uint32_t prefix_pref = addrs[i].preferred; - uint32_t prefix_valid = addrs[i].valid; + uint32_t prefix_pref, prefix_valid; if (!valid_addr(&addrs[i], now)) continue; + /* Filter Out Prefixes */ + if (ADDR_MATCH_PIO_FILTER(&addrs[i], iface)) { + char addrbuf[INET6_ADDRSTRLEN]; + syslog(LOG_INFO, "Address %s filtered out on %s", + inet_ntop(AF_INET6, &addrs[i].addr.in6, addrbuf, sizeof(addrbuf)), + iface->name); + continue; + } + + prefix_pref = addrs[i].preferred; + prefix_valid = addrs[i].valid; + if (prefix_pref != UINT32_MAX) prefix_pref -= now; @@ -955,11 +986,18 @@ static size_t build_ia(uint8_t *buf, size_t buflen, uint16_t status, size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->addr6_len; for (size_t i = 0; i < addrlen; ++i) { - if (!valid_addr(&addrs[i], now) || - !valid_prefix_length(a, addrs[i].prefix)) + struct in6_addr addr; + + if (!valid_addr(&addrs[i], now)) + continue; + + if (!valid_prefix_length(a, addrs[i].prefix)) + continue; + + if (ADDR_MATCH_PIO_FILTER(&addrs[i], iface)) continue; - struct in6_addr addr = addrs[i].addr.in6; + addr = addrs[i].addr.in6; if (ia->type == htons(DHCPV6_OPT_IA_PD)) { addr.s6_addr32[1] |= htonl(a->assigned); addr.s6_addr32[2] = addr.s6_addr32[3] = 0; @@ -1118,6 +1156,9 @@ static bool dhcpv6_ia_on_link(const struct dhcpv6_ia_hdr *ia, struct dhcp_assign if (!valid_addr(&addrs[i], now)) continue; + if (ADDR_MATCH_PIO_FILTER(&addrs[i], iface)) + continue; + if (ia->type == htons(DHCPV6_OPT_IA_PD)) { if (p->prefix < addrs[i].prefix || odhcpd_bmemcmp(&p->addr, &addrs[i].addr.in6, addrs[i].prefix)) diff --git a/src/odhcpd.h b/src/odhcpd.h index 45b6784..ee7b008 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -41,6 +41,11 @@ #define IN6_IS_ADDR_ULA(a) (((a)->s6_addr32[0] & htonl(0xfe000000)) == htonl(0xfc000000)) +#define ADDR_MATCH_PIO_FILTER(_addr, iface) (odhcpd_bmemcmp(&(_addr)->addr, \ + &(iface)->pio_filter_addr, \ + (iface)->pio_filter_length) != 0 || \ + (_addr)->prefix < (iface)->pio_filter_length) + struct interface; struct nl_sock; extern struct vlist_tree leases; diff --git a/src/router.c b/src/router.c index d6ab4bb..541c023 100644 --- a/src/router.c +++ b/src/router.c @@ -518,9 +518,7 @@ static int send_router_advert(struct interface *iface, const struct in6_addr *fr continue; } - if (odhcpd_bmemcmp(&addr->addr, &iface->pio_filter_addr, - iface->pio_filter_length) != 0 || - addr->prefix < iface->pio_filter_length) { + if (ADDR_MATCH_PIO_FILTER(addr, iface)) { syslog(LOG_INFO, "Address %s filtered out as RA prefix on %s", inet_ntop(AF_INET6, &addr->addr.in6, buf, sizeof(buf)), iface->name); @@ -682,9 +680,7 @@ static int send_router_advert(struct interface *iface, const struct in6_addr *fr continue; /* Address not suitable */ } - if (odhcpd_bmemcmp(&addr->addr, &iface->pio_filter_addr, - iface->pio_filter_length) != 0 || - addr->prefix < iface->pio_filter_length) { + if (ADDR_MATCH_PIO_FILTER(addr, iface)) { syslog(LOG_INFO, "Address %s filtered out as RA route on %s", inet_ntop(AF_INET6, &addr->addr.in6, buf, sizeof(buf)), iface->name); -- cgit v1.2.3