From patchwork Wed Mar 29 12:27:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Ond=C5=99ej_Caletka?= X-Patchwork-Id: 1762744 X-Patchwork-Delegate: ansuelsmth@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.openwrt.org (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=hd9tTEgq; dkim=fail reason="signature verification failed" (2048-bit key; secure) header.d=caletka.cz header.i=@caletka.cz header.a=rsa-sha256 header.s=caletka2015 header.b=Erve5Y9p; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PmmLQ4Sfnz1yXv for ; Wed, 29 Mar 2023 23:38:22 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-Id:Date:Subject:Cc :To:From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=pyAXFTGxfbjJzTOf94r4aszk07yljvQvuNEPPmKL6s4=; b=hd9tTEgqcTXew6 2hmLFzS5RX1bGizOPQ0vR/AaIYFvkbYhNGgvENamkXbmNeOs9LBGxvNgevwRaQ0gu/D7WYeHQ+JlZ j2omNiVfkrY2fq7PFsAOXO+z3UVHwjdBmhvIu1NwTqhJzOYFHjjXKiaKr6iwa52F7z6KCdusMVhfW MTHNKcLKoYRmgb8Bpmxfszos6goJWoJgMe6Albg0KHk7izaerjSHR+FFmlFIWthxrxA6ljsdzkVkW +toVwMdNJAUz1X3fd+abMvux/BsuQubxz4LoKqC4J3yIPhHBmxlFWqaXi3ZnFHNwOUpNpw56D5xow dCYF0rytxMe5Vt0VQf0g==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1phV1k-000CVv-25; Wed, 29 Mar 2023 12:35:44 +0000 Received: from flexi.oskarcz.net ([2001:1528:132:70::1]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1phV1h-000CV0-2v for openwrt-devel@lists.openwrt.org; Wed, 29 Mar 2023 12:35:43 +0000 Received: by flexi.oskarcz.net (Postfix, from userid 1000) id 156693E1; Wed, 29 Mar 2023 14:27:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=caletka.cz; s=caletka2015; t=1680092833; bh=bG9/rPjdc2lfz/XB3nYM/9RS2GRMEuX+zSl2D52rPKU=; h=From:To:Cc:Subject:Date:From; b=Erve5Y9pNwVvo0Tu97V6SaM/LGbCiw60A7bJ5klTYOJfAKrHs2YjfJyk0TjNGmHmY KbBO5q0RuBbPqIz3KRNQ9CaLgwzH6IjT9KTwIeQEYWRLL3CcLyRNeQqwW7SIywVPGA Ebj/kmCflqXdryYQzYWhBukDkbyxrnnmhN1/zb6YU+xBvAlbekGJtEAkTWjvqvawj2 L0gdsoDkozEUYjgpicHSgJVlNuuUcsru2Cd2C6BX6waV1H0IHPDPLKl9jYVMfMGMuD 1VqEqJ0xIcyLzhUG4VzzCMAslzcMLfMZX1W8yaW4OSJS4Xfkzhhl5s+iBaq99he59/ mOsvLT/Is38JA== From: =?utf-8?q?Ond=C5=99ej_Caletka?= To: openwrt-devel@lists.openwrt.org Cc: =?utf-8?q?Ond=C5=99ej_Caletka?= Subject: [PATCH][odhcpd] router: Add PREF64 (RFC 8781) RA option support Date: Wed, 29 Mar 2023 14:27:03 +0200 Message-Id: <20230329122703.4142301-1-ondrej@caletka.cz> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230329_053542_243471_92B40C84 X-CRM114-Status: GOOD ( 18.20 ) X-Spam-Score: 0.2 (/) X-Spam-Report: =?unknown-8bit?q?Spam_detection_software=2C_running_on_the_sy?= =?unknown-8bit?q?stem_=22bombadil=2Einfradead=2Eorg=22=2C?= =?unknown-8bit?q?_has_NOT_identified_this_incoming_email_as_spam=2E__The_ori?= =?unknown-8bit?q?ginal?= =?unknown-8bit?q?_message_has_been_attached_to_this_so_you_can_view_it_or_la?= =?unknown-8bit?q?bel?= =?unknown-8bit?q?_similar_future_email=2E__If_you_have_any_questions=2C_see?= =?unknown-8bit?q?_the_administrator_of_that_system_for_details=2E?= =?unknown-8bit?q?_?= =?unknown-8bit?q?_Content_preview=3A__This_adds_support_for_RA_option_that_s?= =?unknown-8bit?q?ignals_NAT64_prefix?= =?unknown-8bit?q?_used_in_the_network=2E_Signed-off-by=3A_Ond=C5=99ej_Caletk?= =?unknown-8bit?q?a_=3Condrej=40caletka=2Ecz=3E_---?= =?unknown-8bit?q?_README_=7C_2_++_src/config=2Ec_=7C_20_+++++++++++++++_src/?= =?unknown-8bit?q?odhcpd=2Eh_=7C_5_++++_src/router=2Ec?= =?unknown-8bit?q?_=7C_70_+++++++++++++++++++++++++++++++++++++++++++++++++++?= =?unknown-8bit?q?-_4_fi_=5B=2E=2E=2E=5D_?= =?unknown-8bit?q?_?= =?unknown-8bit?q?_Content_analysis_details=3A___=280=2E2_points=2C_5=2E0_req?= =?unknown-8bit?q?uired=29?= =?unknown-8bit?q?_?= =?unknown-8bit?q?_pts_rule_name______________description?= =?unknown-8bit?q?_----_----------------------_------------------------------?= =?unknown-8bit?q?--------------------?= =?unknown-8bit?q?_0=2E0_SPF=5FHELO=5FNONE__________SPF=3A_HELO_does_not_publ?= =?unknown-8bit?q?ish_an_SPF_Record?= =?unknown-8bit?q?_0=2E0_SPF=5FNONE_______________SPF=3A_sender_does_not_publ?= =?unknown-8bit?q?ish_an_SPF_Record?= =?unknown-8bit?q?_0=2E2_HEADER=5FFROM=5FDIFFERENT=5FDOMAINS_From_and_Envelop?= =?unknown-8bit?q?eFrom_2nd_level?= =?unknown-8bit?q?_mail_domains_are_different?= =?unknown-8bit?q?_-0=2E1_DKIM=5FVALID=5FAU__________Message_has_a_valid_DKIM?= =?unknown-8bit?q?_or_DK_signature_from?= =?unknown-8bit?q?_author=27s_domain?= =?unknown-8bit?q?_-0=2E1_DKIM=5FVALID_____________Message_has_at_least_one_v?= =?unknown-8bit?q?alid_DKIM_or_DK_signature?= =?unknown-8bit?q?_0=2E1_DKIM=5FSIGNED____________Message_has_a_DKIM_or_DK_si?= =?unknown-8bit?q?gnature=2C_not_necessarily?= =?unknown-8bit?q?_valid?= X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: OpenWrt Development List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org This adds support for RA option that signals NAT64 prefix used in the network. Signed-off-by: Ondřej Caletka --- README | 2 ++ src/config.c | 20 +++++++++++++++ src/odhcpd.h | 5 ++++ src/router.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 96 insertions(+), 1 deletion(-) diff --git a/README b/README index ef8758e..24e57d4 100644 --- a/README +++ b/README @@ -142,6 +142,8 @@ ra_mtu integer - MTU to be advertised in RA messages ra_dns bool 1 Announce DNS configuration in RA messages (RFC8106) +ra_pref64 string Announce PREF64 option + [IPv6 prefix] for NAT64 prefix (RFC8781) ndproxy_routing bool 1 Learn routes from NDP ndproxy_slave bool 0 NDProxy external slave prefix_filter string ::/0 Only advertise on-link prefixes within diff --git a/src/config.c b/src/config.c index 27e7f03..7d54319 100644 --- a/src/config.c +++ b/src/config.c @@ -82,6 +82,7 @@ enum { IFACE_ATTR_RA_HOPLIMIT, IFACE_ATTR_RA_MTU, IFACE_ATTR_RA_DNS, + IFACE_ATTR_RA_PREF64, IFACE_ATTR_PD_MANAGER, IFACE_ATTR_PD_CER, IFACE_ATTR_NDPROXY_ROUTING, @@ -135,6 +136,7 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = { [IFACE_ATTR_RA_HOPLIMIT] = { .name = "ra_hoplimit", .type = BLOBMSG_TYPE_INT32 }, [IFACE_ATTR_RA_MTU] = { .name = "ra_mtu", .type = BLOBMSG_TYPE_INT32 }, [IFACE_ATTR_RA_DNS] = { .name = "ra_dns", .type = BLOBMSG_TYPE_BOOL }, + [IFACE_ATTR_RA_PREF64] = { .name = "ra_pref64", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_NDPROXY_ROUTING] = { .name = "ndproxy_routing", .type = BLOBMSG_TYPE_BOOL }, [IFACE_ATTR_NDPROXY_SLAVE] = { .name = "ndproxy_slave", .type = BLOBMSG_TYPE_BOOL }, [IFACE_ATTR_PREFIX_FILTER] = { .name = "prefix_filter", .type = BLOBMSG_TYPE_STRING }, @@ -953,6 +955,24 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr if ((c = tb[IFACE_ATTR_RA_DNS])) iface->ra_dns = blobmsg_get_bool(c); + if ((c = tb[IFACE_ATTR_RA_PREF64])) { + const char *str = blobmsg_get_string(c); + char *astr = malloc(strlen(str) + 1); + char *delim; + int l; + + if (!astr || !strcpy(astr, str) || + (delim = strchr(astr, '/')) == NULL || (*(delim++) = 0) || + sscanf(delim, "%i", &l) == 0 || l > 128 || + inet_pton(AF_INET6, astr, &iface->pref64_addr) == 0) + iface->pref64_length = 0; + else + iface->pref64_length = l; + + if (astr) + free(astr); + } + if ((c = tb[IFACE_ATTR_RA_PREFERENCE])) { const char *prio = blobmsg_get_string(c); diff --git a/src/odhcpd.h b/src/odhcpd.h index 0550bc2..5dd35f8 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -34,6 +34,9 @@ #define ND_OPT_RECURSIVE_DNS 25 #define ND_OPT_DNS_SEARCH 31 +// RFC 8781 defines PREF64 option +#define ND_OPT_PREF64 38 + #define INFINITE_VALID(x) ((x) == 0) #define _unused __attribute__((unused)) @@ -300,6 +303,8 @@ struct interface { bool ra_advrouter; bool ra_useleasetime; bool ra_dns; + uint8_t pref64_length; + struct in6_addr pref64_addr; bool no_dynamic_dhcp; bool have_link_local; uint8_t pio_filter_length; diff --git a/src/router.c b/src/router.c index eca0bf7..4422eb9 100644 --- a/src/router.c +++ b/src/router.c @@ -390,6 +390,7 @@ enum { IOV_RA_ROUTES, IOV_RA_DNS, IOV_RA_SEARCH, + IOV_RA_PREF64, IOV_RA_ADV_INTERVAL, IOV_RA_TOTAL, }; @@ -427,6 +428,13 @@ struct nd_opt_route_info { uint32_t addr[4]; }; +struct nd_opt_pref64_info { + uint8_t type; + uint8_t len; + uint16_t lifetime_plc; + uint32_t addr[3]; +}; + /* Router Advert server mode */ static int send_router_advert(struct interface *iface, const struct in6_addr *from) { @@ -437,10 +445,12 @@ static int send_router_advert(struct interface *iface, const struct in6_addr *fr struct nd_opt_dns_server *dns = NULL; struct nd_opt_search_list *search = NULL; struct nd_opt_route_info *routes = NULL; + struct nd_opt_pref64_info *pref64 = NULL; struct nd_opt_adv_interval adv_interval; struct iovec iov[IOV_RA_TOTAL]; struct sockaddr_in6 dest; - size_t dns_sz = 0, search_sz = 0, pfxs_cnt = 0, routes_cnt = 0; + size_t dns_sz = 0, search_sz = 0, pref64_sz = 0; + size_t pfxs_cnt = 0, routes_cnt = 0; ssize_t valid_addr_cnt = 0, invalid_addr_cnt = 0; uint32_t minvalid = UINT32_MAX, maxival, lifetime; int msecs, mtu = iface->ra_mtu, hlim = iface->ra_hoplimit; @@ -698,6 +708,64 @@ static int send_router_advert(struct interface *iface, const struct in6_addr *fr iov[IOV_RA_SEARCH].iov_base = (char *)search; iov[IOV_RA_SEARCH].iov_len = search_sz; + if (iface->pref64_length) { + /* RFC 8781 § 4.1 rounding up lifetime to multiply of 8 */ + uint16_t pref64_lifetime = lifetime < (UINT16_MAX - 7) ? lifetime + 7 : UINT16_MAX; + uint8_t prefix_length_code = 0; + uint32_t mask_a1 = 0xffffffff; + uint32_t mask_a2 = 0xffffffff; + + switch (iface->pref64_length) { + case 96: + prefix_length_code = 0; + break; + case 64: + prefix_length_code = 1; + mask_a2 = 0; + break; + case 56: + prefix_length_code = 2; + mask_a1 = htonl(0xffffff00); + mask_a2 = 0; + break; + case 48: + prefix_length_code = 3; + mask_a1 = htonl(0xffff0000); + mask_a2 = 0; + break; + case 40: + prefix_length_code = 4; + mask_a1 = htonl(0xff000000); + mask_a2 = 0; + break; + case 32: + prefix_length_code = 5; + mask_a1 = 0; + mask_a2 = 0; + break; + default: + syslog(LOG_WARNING, "Invalid PREF64 prefix size (%d), " + "ignoring ra_pref64 option!", iface->pref64_length); + goto pref64_out; + break; + } + + pref64_sz = sizeof(*pref64); + pref64 = alloca(pref64_sz); + memset(pref64, 0, pref64_sz); + pref64->type = ND_OPT_PREF64; + pref64->len = 2; + pref64->lifetime_plc = htons((0xfff8 & pref64_lifetime) | + (0x7 & prefix_length_code)); + pref64->addr[0] = iface->pref64_addr.s6_addr32[0]; + pref64->addr[1] = iface->pref64_addr.s6_addr32[1] & mask_a1; + pref64->addr[2] = iface->pref64_addr.s6_addr32[2] & mask_a2; + } + +pref64_out: + iov[IOV_RA_PREF64].iov_base = (char *)pref64; + iov[IOV_RA_PREF64].iov_len = pref64_sz; + /* * RFC7084 § 4.3 : * L-3: An IPv6 CE router MUST advertise itself as a router for the