From 4f20351c3713f42dd540922e88579ec61ca76d94 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20H=C3=A4rdeman?= Date: Sun, 26 Oct 2025 00:49:22 +0200 Subject: [PATCH] odhcpd: remove the "filter_class" option MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The "filter_class" option was first introduced as part of the effort to support the Homenet Control Protocol (HNCP, RFC7368, RFC7788). At first it was hardcoded to filter out the user class "HOMENET", and later it was made configurable, but there appears to be no other use-cases than Homenet. There's also legacy comments in the odhcpd code pointing at filtering out homenet user classes (the comments are misleading since "filter_class" is not set by default). Homenet is effectively dead. The "hnetd" daemon last saw any code changes in 2018, doesn't compile with current versions of GCC, and was removed from OpenWrt altogether in 2025 [1]. The OpenWrt wiki also notes [2] that HNCP is effectively dead, and that the upstream website [3] is gone. Searching for the Homenet Control Protocol mostly returns results pointing either: a) at the standards b) at the OpenWrt/hnetd project c) at various posts stating that it is dead The IETF working group for Homenet is no more, and Éric Vyncke (Area Director for the Internet Area of the IETF) mentioned wanting to avoid Homenet pitfalls [4] (page 11) in the future of IPv6 autoconfig. The current implementation is also contrary to the spirit of the RFCs introducing the option (RFC3004 - DHCPv4; RFC8415, §21.15 - DHCPv6) where it is described (example from RFC8415) as follows: The information contained in the data area of this option is contained in one or more opaque fields that represent the user class or classes of which the client is a member. A server selects configuration information for the client based on the classes identified in this option. For example, the User Class option can be used to configure all clients of people in the accounting department with a different printer than clients of people in the marketing department. I.e., it's meant to be used in a manner similar to "tags" in dnsmasq. Finally, the option has been undocumented for the whole existance of odhcpd. So, remove this option. [1] https://github.com/openwrt/routing/commit/85b868b3413a29da0bd6ecd3518c2d34a6ffb788 [2] https://openwrt.org/docs/guide-user/network/zeroconfig/hncp_configuration [3] https://web.archive.org/web/20180831161552/http://homewrt.org/start [4] https://ripe87.ripe.net/wp-content/uploads/presentations/102-20231130-RIPE-87-IPv6-from-IETF.pdf Signed-off-by: David Härdeman Link: https://github.com/openwrt/odhcpd/pull/294 Signed-off-by: Álvaro Fernández Rojas --- README.md | 1 - src/config.c | 8 -------- src/dhcpv4.c | 10 ---------- src/dhcpv6.c | 7 ------- src/odhcpd.h | 2 -- 5 files changed, 28 deletions(-) diff --git a/README.md b/README.md index 485fc41..c59c039 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,6 @@ and may also receive information from ubus | ntp |list |``| NTP servers to announce accepts IPv4 and IPv6 | | ra_management |string | - | TBD | | upstream |list | - | TBD | -| filter_class |string | - | TBD | | pd_manager |string | - | TBD | | pd_cer |string | - | TBD | | ra_advrouter |bool | - | TBD | diff --git a/src/config.c b/src/config.c index 070aeaa..aaf5652 100644 --- a/src/config.c +++ b/src/config.c @@ -104,7 +104,6 @@ enum { IFACE_ATTR_DNR, IFACE_ATTR_DNS_SERVICE, IFACE_ATTR_DOMAIN, - IFACE_ATTR_FILTER_CLASS, IFACE_ATTR_DHCPV4_FORCERECONF, IFACE_ATTR_DHCPV6_RAW, IFACE_ATTR_DHCPV6_ASSIGNALL, @@ -159,7 +158,6 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = { [IFACE_ATTR_DNR] = { .name = "dnr", .type = BLOBMSG_TYPE_ARRAY }, [IFACE_ATTR_DNS_SERVICE] = { .name = "dns_service", .type = BLOBMSG_TYPE_BOOL }, [IFACE_ATTR_DOMAIN] = { .name = "domain", .type = BLOBMSG_TYPE_ARRAY }, - [IFACE_ATTR_FILTER_CLASS] = { .name = "filter_class", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_DHCPV4_FORCERECONF] = { .name = "dhcpv4_forcereconf", .type = BLOBMSG_TYPE_BOOL }, [IFACE_ATTR_DHCPV6_RAW] = { .name = "dhcpv6_raw", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_DHCPV6_ASSIGNALL] = { .name ="dhcpv6_assignall", .type = BLOBMSG_TYPE_BOOL }, @@ -348,7 +346,6 @@ static void clean_interface(struct interface *iface) free(iface->dhcpv4_router); free(iface->dhcpv4_dns); free(iface->dhcpv6_raw); - free(iface->filter_class); free(iface->dhcpv4_ntp); free(iface->dhcpv6_ntp); free(iface->dhcpv6_sntp); @@ -1386,11 +1383,6 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr } } - if ((c = tb[IFACE_ATTR_FILTER_CLASS])) { - iface->filter_class = realloc(iface->filter_class, blobmsg_data_len(c) + 1); - memcpy(iface->filter_class, blobmsg_get_string(c), blobmsg_data_len(c) + 1); - } - if ((c = tb[IFACE_ATTR_DHCPV4_FORCERECONF])) iface->dhcpv4_forcereconf = blobmsg_get_bool(c); diff --git a/src/dhcpv4.c b/src/dhcpv4.c index d5177c6..b64b1c3 100644 --- a/src/dhcpv4.c +++ b/src/dhcpv4.c @@ -927,16 +927,6 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len, req_opts_len = opt->len; } break; - case DHCPV4_OPT_USER_CLASS: - if (iface->filter_class) { - uint8_t *c = opt->data, *cend = &opt->data[opt->len]; - for (; c < cend && &c[*c] < cend; c = &c[1 + *c]) { - size_t elen = strlen(iface->filter_class); - if (*c == elen && !memcmp(&c[1], iface->filter_class, elen)) - return; // Ignore from homenet - } - } - break; case DHCPV4_OPT_LEASETIME: if (opt->len == 4) { memcpy(&req_leasetime, opt->data, 4); diff --git a/src/dhcpv6.c b/src/dhcpv6.c index ab55ff6..8b6cf6b 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -680,13 +680,6 @@ static void handle_client_request(void *addr, void *data, size_t len, if (olen != ntohs(dest.serverid_length) || memcmp(odata, &dest.serverid_buf, olen)) return; /* Not for us */ - } else if (iface->filter_class && otype == DHCPV6_OPT_USER_CLASS) { - uint8_t *c = odata, *cend = &odata[olen]; - for (; &c[2] <= cend && &c[2 + (c[0] << 8) + c[1]] <= cend; c = &c[2 + (c[0] << 8) + c[1]]) { - size_t elen = strlen(iface->filter_class); - if (((((size_t)c[0]) << 8) | c[1]) == elen && !memcmp(&c[2], iface->filter_class, elen)) - return; /* Ignore from homenet */ - } } else if (otype == DHCPV6_OPT_IA_PD) { #ifdef EXT_CER_ID iov[IOV_CERID].iov_len = sizeof(cerid); diff --git a/src/odhcpd.h b/src/odhcpd.h index 2682e44..01c8d0f 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -450,8 +450,6 @@ struct interface { char *upstream; size_t upstream_len; - char *filter_class; - // NTP struct in_addr *dhcpv4_ntp; size_t dhcpv4_ntp_cnt; -- 2.30.2