dhcpv6-ia: apply prefix_filter on dhcpv6
authorNick Hainke <vincent@systemli.org>
Wed, 6 Jan 2021 12:04:02 +0000 (13:04 +0100)
committerHans Dedecker <dedeckeh@gmail.com>
Sat, 30 Jan 2021 20:14:08 +0000 (21:14 +0100)
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 <vincent@systemli.org>
Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
src/dhcpv6-ia.c
src/odhcpd.h
src/router.c

index a59fc20f9054723d35d347968d1a5231582fc6e9..639e36878534244e43ba72bc32a1b47748a26209 100644 (file)
@@ -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))
index 45b6784ce0986acd5167d49d10ee58122c77cd22..ee7b0086782700be141266d71a824110a1d447cd 100644 (file)
 
 #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;
index d6ab4bb517ff67ca68491504a94f97a192b7720e..541c0237dd7d21e75e3eefc796393ece33739c77 100644 (file)
@@ -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);