Merge pull request #15508 from namib-project/dhcp-mud-support
Add MUD URL option to DHCPv6 client
This commit is contained in:
commit
c44d77e528
@ -26,6 +26,7 @@ PSEUDOMODULES += evtimer_mbox
|
|||||||
PSEUDOMODULES += evtimer_on_ztimer
|
PSEUDOMODULES += evtimer_on_ztimer
|
||||||
PSEUDOMODULES += fmt_%
|
PSEUDOMODULES += fmt_%
|
||||||
PSEUDOMODULES += gnrc_dhcpv6_%
|
PSEUDOMODULES += gnrc_dhcpv6_%
|
||||||
|
PSEUDOMODULES += gnrc_dhcpv6_client_mud_url
|
||||||
PSEUDOMODULES += gnrc_ipv6_default
|
PSEUDOMODULES += gnrc_ipv6_default
|
||||||
PSEUDOMODULES += gnrc_ipv6_ext_frag_stats
|
PSEUDOMODULES += gnrc_ipv6_ext_frag_stats
|
||||||
PSEUDOMODULES += gnrc_ipv6_router
|
PSEUDOMODULES += gnrc_ipv6_router
|
||||||
|
|||||||
@ -69,6 +69,7 @@ extern "C" {
|
|||||||
* delegation (IA_PD) option */
|
* delegation (IA_PD) option */
|
||||||
#define DHCPV6_OPT_IAPFX (26U) /**< IA prefix option */
|
#define DHCPV6_OPT_IAPFX (26U) /**< IA prefix option */
|
||||||
#define DHCPV6_OPT_SMR (82U) /**< SOL_MAX_RT option */
|
#define DHCPV6_OPT_SMR (82U) /**< SOL_MAX_RT option */
|
||||||
|
#define DHCPV6_OPT_MUD_URL (112U) /**< MUD URL option (see RFC 8520) */
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -45,7 +45,7 @@ extern "C" {
|
|||||||
* @brief Static length of the DUID
|
* @brief Static length of the DUID
|
||||||
*/
|
*/
|
||||||
#define DHCPV6_CLIENT_DUID_LEN (sizeof(dhcpv6_duid_l2_t) + 8U)
|
#define DHCPV6_CLIENT_DUID_LEN (sizeof(dhcpv6_duid_l2_t) + 8U)
|
||||||
#define DHCPV6_CLIENT_BUFLEN (256) /**< length for send and receive buffer */
|
#define DHCPV6_CLIENT_BUFLEN (256) /**< default length for send and receive buffer */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup net_dhcpv6_conf DHCPv6 client compile configurations
|
* @defgroup net_dhcpv6_conf DHCPv6 client compile configurations
|
||||||
@ -58,6 +58,15 @@ extern "C" {
|
|||||||
#ifndef CONFIG_DHCPV6_CLIENT_PFX_LEASE_MAX
|
#ifndef CONFIG_DHCPV6_CLIENT_PFX_LEASE_MAX
|
||||||
#define CONFIG_DHCPV6_CLIENT_PFX_LEASE_MAX (1U)
|
#define CONFIG_DHCPV6_CLIENT_PFX_LEASE_MAX (1U)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MUD URL (must use the https:// scheme)
|
||||||
|
* For more info, see the [definitions](@ref net_dhcpv6_mud_url_option) below
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_DHCPV6_CLIENT_MUD_URL
|
||||||
|
#define CONFIG_DHCPV6_CLIENT_MUD_URL "https://example.org"
|
||||||
|
#endif
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,6 +176,31 @@ uint32_t dhcpv6_client_prefix_valid_until(unsigned netif,
|
|||||||
unsigned pfx_len);
|
unsigned pfx_len);
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DHCPv6 Manufacturer Usage Description (MUD) URL option definitions
|
||||||
|
* @see [RFC 8520, section 10](https://tools.ietf.org/html/rfc8520#section-10)
|
||||||
|
* @anchor net_dhcpv6_mud_url_option
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Length for the send buffer if a MUD URL is included in the DHCP client's packets
|
||||||
|
*
|
||||||
|
* @note Only (re)defined by the `gnrc_dhcpv6_client_mud_url` pseudo-module.
|
||||||
|
*/
|
||||||
|
#if defined(MODULE_GNRC_DHCPV6_CLIENT_MUD_URL) || defined(DOXYGEN)
|
||||||
|
#define DHCPV6_CLIENT_SEND_BUFLEN (DHCPV6_CLIENT_BUFLEN + 256)
|
||||||
|
#else
|
||||||
|
#define DHCPV6_CLIENT_SEND_BUFLEN (DHCPV6_CLIENT_BUFLEN)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Maximal length of a MUD URL
|
||||||
|
*/
|
||||||
|
#define MAX_MUD_URL_LENGTH (0xFF - sizeof(dhcpv6_opt_mud_url_t))
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -16,4 +16,19 @@ config DHCPV6_CLIENT_PFX_LEASE_MAX
|
|||||||
int "Maximum number of prefix leases to be stored"
|
int "Maximum number of prefix leases to be stored"
|
||||||
default 1
|
default 1
|
||||||
|
|
||||||
|
menuconfig KCONFIG_USEMODULE_GNRC_DHCPV6_CLIENT_MUD_URL
|
||||||
|
bool "Enable DHCPv6 Client MUD URL"
|
||||||
|
help
|
||||||
|
Enable the inclusion of a MUD URL in DHCPv6 packets
|
||||||
|
as specified in RFC 8520, section 10. This URL
|
||||||
|
has to point to a MUD file containing YANG-based JSON
|
||||||
|
with a description of the device and its suggested
|
||||||
|
network behavior. The URL must use the "https" scheme.
|
||||||
|
|
||||||
|
if KCONFIG_USEMODULE_GNRC_DHCPV6_CLIENT_MUD_URL
|
||||||
|
|
||||||
|
config CONFIG_DHCPV6_CLIENT_MUD_URL
|
||||||
|
string "URL pointing to a Manufacturer Usage Description file"
|
||||||
|
|
||||||
|
endif # KCONFIG_USEMODULE_GNRC_DHCPV6_CLIENT_MUD_URL
|
||||||
endif # KCONFIG_USEMODULE_DHCPv6
|
endif # KCONFIG_USEMODULE_DHCPv6
|
||||||
|
|||||||
@ -28,7 +28,6 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name DHCPv6 multicast addresses
|
* @name DHCPv6 multicast addresses
|
||||||
* @see [RFC 8415, section 7.1]
|
* @see [RFC 8415, section 7.1]
|
||||||
@ -214,6 +213,17 @@ typedef struct __attribute__((packed)) {
|
|||||||
network_uint32_t value; /**< overriding value for SOL_MAX_RT (in sec) */
|
network_uint32_t value; /**< overriding value for SOL_MAX_RT (in sec) */
|
||||||
} dhcpv6_opt_smr_t;
|
} dhcpv6_opt_smr_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MUD URL DHCPv6 option format
|
||||||
|
* @see [RFC 8520, section 10]
|
||||||
|
* (https://tools.ietf.org/html/rfc8520#section-10)
|
||||||
|
*/
|
||||||
|
typedef struct __attribute__((packed)) {
|
||||||
|
network_uint16_t type; /**< @ref DHCPV6_OPT_MUD_URL */
|
||||||
|
network_uint16_t len; /**< length of the MUDstring in octets. */
|
||||||
|
char mudString[]; /**< MUD URL using the "https" scheme */
|
||||||
|
} dhcpv6_opt_mud_url_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -65,7 +65,7 @@ typedef struct {
|
|||||||
uint8_t duid_len;
|
uint8_t duid_len;
|
||||||
} server_t;
|
} server_t;
|
||||||
|
|
||||||
static uint8_t send_buf[DHCPV6_CLIENT_BUFLEN];
|
static uint8_t send_buf[DHCPV6_CLIENT_SEND_BUFLEN];
|
||||||
static uint8_t recv_buf[DHCPV6_CLIENT_BUFLEN];
|
static uint8_t recv_buf[DHCPV6_CLIENT_BUFLEN];
|
||||||
static uint8_t best_adv[DHCPV6_CLIENT_BUFLEN];
|
static uint8_t best_adv[DHCPV6_CLIENT_BUFLEN];
|
||||||
static uint8_t duid[DHCPV6_CLIENT_DUID_LEN];
|
static uint8_t duid[DHCPV6_CLIENT_DUID_LEN];
|
||||||
@ -247,6 +247,22 @@ static inline size_t _compose_elapsed_time_opt(dhcpv6_opt_elapsed_time_t *time)
|
|||||||
return len + sizeof(dhcpv6_opt_t);
|
return len + sizeof(dhcpv6_opt_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline size_t _compose_mud_url_opt(dhcpv6_opt_mud_url_t *mud_url_opt,
|
||||||
|
const char *mud_url, size_t len_max)
|
||||||
|
{
|
||||||
|
uint16_t len = strlen(mud_url);
|
||||||
|
|
||||||
|
if (len > len_max) {
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mud_url_opt->type = byteorder_htons(DHCPV6_OPT_MUD_URL);
|
||||||
|
mud_url_opt->len = byteorder_htons(len);
|
||||||
|
strncpy(mud_url_opt->mudString, mud_url, len_max);
|
||||||
|
return len + sizeof(dhcpv6_opt_mud_url_t);
|
||||||
|
}
|
||||||
|
|
||||||
static inline size_t _compose_oro_opt(dhcpv6_opt_oro_t *oro, uint16_t *opts,
|
static inline size_t _compose_oro_opt(dhcpv6_opt_oro_t *oro, uint16_t *opts,
|
||||||
unsigned opts_num)
|
unsigned opts_num)
|
||||||
{
|
{
|
||||||
@ -273,7 +289,7 @@ static inline size_t _compose_ia_pd_opt(dhcpv6_opt_ia_pd_t *ia_pd,
|
|||||||
return len + sizeof(dhcpv6_opt_t);
|
return len + sizeof(dhcpv6_opt_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t _add_ia_pd_from_config(uint8_t *buf)
|
static inline size_t _add_ia_pd_from_config(uint8_t *buf, size_t len_max)
|
||||||
{
|
{
|
||||||
size_t msg_len = 0;
|
size_t msg_len = 0;
|
||||||
|
|
||||||
@ -285,6 +301,12 @@ static inline size_t _add_ia_pd_from_config(uint8_t *buf)
|
|||||||
msg_len += _compose_ia_pd_opt(ia_pd, ia_id, 0U);
|
msg_len += _compose_ia_pd_opt(ia_pd, ia_id, 0U);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (msg_len > len_max) {
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return msg_len;
|
return msg_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -707,7 +729,16 @@ static void _solicit_servers(event_t *event)
|
|||||||
msg_len += _compose_elapsed_time_opt(time);
|
msg_len += _compose_elapsed_time_opt(time);
|
||||||
msg_len += _compose_oro_opt((dhcpv6_opt_oro_t *)&send_buf[msg_len], oro_opts,
|
msg_len += _compose_oro_opt((dhcpv6_opt_oro_t *)&send_buf[msg_len], oro_opts,
|
||||||
ARRAY_SIZE(oro_opts));
|
ARRAY_SIZE(oro_opts));
|
||||||
msg_len += _add_ia_pd_from_config(&send_buf[msg_len]);
|
|
||||||
|
if (IS_USED(MODULE_GNRC_DHCPV6_CLIENT_MUD_URL)) {
|
||||||
|
const char mud_url[] = CONFIG_DHCPV6_CLIENT_MUD_URL;
|
||||||
|
assert(strlen(mud_url) <= MAX_MUD_URL_LENGTH);
|
||||||
|
assert(strncmp(mud_url, "https://", 8) == 0);
|
||||||
|
msg_len += _compose_mud_url_opt((dhcpv6_opt_mud_url_t *)&send_buf[msg_len],
|
||||||
|
mud_url, sizeof(send_buf) - msg_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_len += _add_ia_pd_from_config(&send_buf[msg_len], sizeof(send_buf) - msg_len);
|
||||||
DEBUG("DHCPv6 client: send SOLICIT\n");
|
DEBUG("DHCPv6 client: send SOLICIT\n");
|
||||||
_flush_stale_replies(&sock);
|
_flush_stale_replies(&sock);
|
||||||
res = sock_udp_send(&sock, send_buf, msg_len, &remote);
|
res = sock_udp_send(&sock, send_buf, msg_len, &remote);
|
||||||
@ -815,7 +846,7 @@ static void _request_renew_rebind(uint8_t type)
|
|||||||
msg_len += _compose_elapsed_time_opt(time);
|
msg_len += _compose_elapsed_time_opt(time);
|
||||||
msg_len += _compose_oro_opt((dhcpv6_opt_oro_t *)&send_buf[msg_len], oro_opts,
|
msg_len += _compose_oro_opt((dhcpv6_opt_oro_t *)&send_buf[msg_len], oro_opts,
|
||||||
ARRAY_SIZE(oro_opts));
|
ARRAY_SIZE(oro_opts));
|
||||||
msg_len += _add_ia_pd_from_config(&send_buf[msg_len]);
|
msg_len += _add_ia_pd_from_config(&send_buf[msg_len], sizeof(send_buf) - msg_len);
|
||||||
_flush_stale_replies(&sock);
|
_flush_stale_replies(&sock);
|
||||||
while (sock_udp_send(&sock, send_buf, msg_len, &remote) <= 0) {}
|
while (sock_udp_send(&sock, send_buf, msg_len, &remote) <= 0) {}
|
||||||
while (((res = sock_udp_recv(&sock, recv_buf, sizeof(recv_buf),
|
while (((res = sock_udp_recv(&sock, recv_buf, sizeof(recv_buf),
|
||||||
|
|||||||
@ -5,6 +5,7 @@ export TAP ?= tap0
|
|||||||
|
|
||||||
USEMODULE += auto_init_gnrc_netif
|
USEMODULE += auto_init_gnrc_netif
|
||||||
USEMODULE += gnrc_dhcpv6_client_6lbr
|
USEMODULE += gnrc_dhcpv6_client_6lbr
|
||||||
|
USEMODULE += gnrc_dhcpv6_client_mud_url
|
||||||
USEMODULE += gnrc_netdev_default
|
USEMODULE += gnrc_netdev_default
|
||||||
USEMODULE += gnrc_pktdump
|
USEMODULE += gnrc_pktdump
|
||||||
USEMODULE += gnrc_sixlowpan_border_router_default
|
USEMODULE += gnrc_sixlowpan_border_router_default
|
||||||
|
|||||||
@ -14,13 +14,19 @@ import time
|
|||||||
|
|
||||||
from scapy.all import AsyncSniffer, sendp, Ether, IPv6, UDP
|
from scapy.all import AsyncSniffer, sendp, Ether, IPv6, UDP
|
||||||
from scapy.all import DHCP6_Solicit, DHCP6_Advertise, DHCP6_Request, DHCP6_Reply
|
from scapy.all import DHCP6_Solicit, DHCP6_Advertise, DHCP6_Request, DHCP6_Reply
|
||||||
from scapy.all import DHCP6OptClientId, DHCP6OptServerId, DHCP6OptIA_PD
|
from scapy.all import DHCP6OptClientId, DHCP6OptServerId, DHCP6OptIA_PD, DHCP6OptUnknown
|
||||||
from scapy.all import DUID_LL, DHCP6OptIAPrefix
|
from scapy.all import DUID_LL, DHCP6OptIAPrefix
|
||||||
from testrunner import run
|
from testrunner import run
|
||||||
|
|
||||||
|
|
||||||
TIMEOUT = 1
|
TIMEOUT = 1
|
||||||
|
|
||||||
|
MUD_OPTION_CODE = 112
|
||||||
|
MUD_TEST_URL = b'https://example.org'
|
||||||
|
|
||||||
|
# MUD URL option in DHCPv6 is not yet supported by scapy
|
||||||
|
DHCP6OptMUD = DHCP6OptUnknown
|
||||||
|
|
||||||
|
|
||||||
def get_upstream_netif(child):
|
def get_upstream_netif(child):
|
||||||
child.sendline("ifconfig")
|
child.sendline("ifconfig")
|
||||||
@ -123,6 +129,12 @@ def testfunc(child):
|
|||||||
# and it is asking for a prefix delegation
|
# and it is asking for a prefix delegation
|
||||||
assert DHCP6OptIA_PD in pkt
|
assert DHCP6OptIA_PD in pkt
|
||||||
|
|
||||||
|
assert DHCP6OptMUD in pkt
|
||||||
|
mud_packet = pkt[DHCP6OptMUD]
|
||||||
|
assert mud_packet.optcode == 112
|
||||||
|
assert mud_packet.optlen == len(MUD_TEST_URL)
|
||||||
|
assert mud_packet.data == MUD_TEST_URL
|
||||||
|
|
||||||
# reply to solicit with advertise and a prefix provided
|
# reply to solicit with advertise and a prefix provided
|
||||||
trid = pkt[DHCP6_Solicit].trid
|
trid = pkt[DHCP6_Solicit].trid
|
||||||
srv_duid = "aa:bb:cc:dd:ee:ff"
|
srv_duid = "aa:bb:cc:dd:ee:ff"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user