Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gnrc_ipv6_nib/SLAAC: rfc7217 stable privacy addresses #20370

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
110fa3c
config: Define feature flag
xnumad Feb 8, 2024
60933a5
🍒SLAAC only for /64 prefixes
xnumad Feb 9, 2024
fd01be3
🍒Documentation for constant
xnumad Feb 9, 2024
6774248
🍒Documentation
xnumad Feb 9, 2024
828ac9d
🍒creation: Check IANA IID
xnumad Feb 9, 2024
6b5424a
Wrap IANA IID check in IS_ACTIVE
xnumad Feb 9, 2024
227181a
🍒gnrc_netif_ipv6_addr_pfx_idx
xnumad Feb 9, 2024
3c9e0d0
🍒Supress SLAAC trigger
xnumad Feb 9, 2024
356b3d9
🍒retries: New flag
xnumad Feb 9, 2024
f934340
Wrap retries flag in IS_ACTIVE
xnumad Feb 9, 2024
1836de5
config: RFC params
xnumad Feb 8, 2024
fa015a2
includes
xnumad Feb 8, 2024
6340dcd
IDGEN
xnumad Feb 8, 2024
20375dd
Generate secret_key at compilation
xnumad Feb 8, 2024
0a31c73
Retry condition check
xnumad Feb 8, 2024
ec7caef
Overload method
xnumad Feb 8, 2024
758b838
Use IDGEN
xnumad Feb 8, 2024
30914b7
Handle DAD
xnumad Feb 8, 2024
cb846fd
Fix `unused-function`
xnumad Feb 8, 2024
ff81306
IDGEN error handling and logging
xnumad Feb 8, 2024
e9a5b1c
Allow rfc7217 IDGEN without L2 addr
xnumad Feb 8, 2024
8bc9b10
Perform DAD for RPL PIO
xnumad Feb 8, 2024
f96b610
RFC7217 for NETOPT_IPV6_IID
xnumad Feb 8, 2024
f544165
Rename method
xnumad Feb 9, 2024
4635a2e
Rename method
xnumad Feb 9, 2024
46b1107
No RFC7217 for 6LN link-local addresses
xnumad Feb 9, 2024
63e98ac
IDGEN: require L2 addr
xnumad Feb 9, 2024
0962383
finalize: vera++ style check
xnumad Feb 9, 2024
ca4f23a
Wrap
xnumad Feb 10, 2024
36fb6b3
doccheck
xnumad Feb 20, 2024
af35c11
chore: Use C-style comments
xnumad Feb 22, 2024
a69adaa
refactor: Make called function inline
xnumad Feb 22, 2024
dfb5e1d
refactor: Rename
xnumad Feb 22, 2024
35e2326
fix: Don't generate already assigned addresses
xnumad Feb 24, 2024
6cbd58d
fixup! RFC7217 for NETOPT_IPV6_IID
xnumad Feb 27, 2024
3af0785
fix: Idempotency wrapper for callers
xnumad Mar 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions sys/include/net/gnrc/ipv6/nib/conf.h
Original file line number Diff line number Diff line change
@@ -186,6 +186,13 @@ extern "C" {
#define CONFIG_GNRC_IPV6_NIB_SLAAC 1
#endif

/**
* @brief Use stable privacy addresses (rfc7217)
*/
#ifndef CONFIG_GNRC_IPV6_STABLE_PRIVACY
#define CONFIG_GNRC_IPV6_STABLE_PRIVACY 0
#endif

/**
* @brief handle Redirect Messages
*/
41 changes: 41 additions & 0 deletions sys/include/net/gnrc/netif/internal.h
Original file line number Diff line number Diff line change
@@ -130,6 +130,28 @@ void gnrc_netif_ipv6_addr_remove_internal(gnrc_netif_t *netif,
int gnrc_netif_ipv6_addr_idx(gnrc_netif_t *netif,
const ipv6_addr_t *addr);

/**
* @brief Returns the index of the first pfx
* in gnrc_netif_t::ipv6_addrs of @p netif
* where the first @p pfx_len bits match with @p pfx
*
* @pre `(netif != NULL) && (pfx != NULL)`
*
* Can be used to check if an address is assigned to an interface.
*
* @param[in] netif the network interface
* @param[in] pfx the address to check
* @param[in] pfx_len the amount of bits to compare
*
* @note Only available with @ref net_gnrc_ipv6 "gnrc_ipv6".
*
* @return index of the first matching address
* in gnrc_netif_t::ipv6_addrs of @p netif
* @return -1, if no matching address found for @p netif
*/
int gnrc_netif_ipv6_addr_pfx_idx(gnrc_netif_t *netif,
const ipv6_addr_t *pfx, uint8_t pfx_len);

/**
* @brief Gets state from address flags
*
@@ -160,6 +182,25 @@ static inline uint8_t gnrc_netif_ipv6_addr_dad_trans(const gnrc_netif_t *netif,
return netif->ipv6.addrs_flags[idx] & GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_TENTATIVE;
}

#if IS_ACTIVE(CONFIG_GNRC_IPV6_STABLE_PRIVACY) || defined(DOXYGEN)
/**
* @brief Gets number of address generation retries already performed for an address
*
* @param[in] netif the network interface
* @param[in] idx index of the address (and its flags)
*
* @return the number of address generation retries already
* performed
*/
static inline uint8_t gnrc_netif_ipv6_addr_gen_retries(const gnrc_netif_t *netif,
int idx)
{
return (netif->ipv6.addrs_flags[idx]
& GNRC_NETIF_IPV6_ADDRS_FLAGS_IDGEN_RETRIES)
>> GNRC_NETIF_IPV6_ADDRS_FLAGS_IDGEN_RETRIES_POS;
}
#endif

/**
* @brief Returns the index of an address in gnrc_netif_t::ipv6_addrs of @p
* netif that matches @p addr best
13 changes: 13 additions & 0 deletions sys/include/net/gnrc/netif/ipv6.h
Original file line number Diff line number Diff line change
@@ -68,6 +68,19 @@ extern "C" {
* @brief Address is an anycast address
*/
#define GNRC_NETIF_IPV6_ADDRS_FLAGS_ANYCAST (0x20U)

#if IS_ACTIVE(CONFIG_GNRC_IPV6_STABLE_PRIVACY) || defined(DOXYGEN)
/**
* @brief Number of address generation retries
* For addresses generated as per RFC7217, this stores the DAD_Counter value
* and the upper limit is defined by @ref STABLE_PRIVACY_IDGEN_RETRIES
*/
#define GNRC_NETIF_IPV6_ADDRS_FLAGS_IDGEN_RETRIES (0xC0U)
/**
* @brief Shift position of address generation retries
*/
#define GNRC_NETIF_IPV6_ADDRS_FLAGS_IDGEN_RETRIES_POS (6)
#endif
/** @} */

/**
35 changes: 35 additions & 0 deletions sys/include/net/netopt.h
Original file line number Diff line number Diff line change
@@ -25,8 +25,11 @@
#ifndef NET_NETOPT_H
#define NET_NETOPT_H

#include <kernel_defines.h>
#include <stdint.h>
#include <stdbool.h>
#include <net/ipv6/addr.h>
#include "eui64.h"

#ifdef __cplusplus
extern "C" {
@@ -911,6 +914,38 @@
/* add other states if needed */
} netopt_state_t;

/**
* @brief Option parameter to be used with @ref NETOPT_IPV6_IID
*/
enum {
NETOPT_IPV6_IID_HWADDR = 0,
#if IS_ACTIVE(CONFIG_GNRC_IPV6_STABLE_PRIVACY) || defined(DOXYGEN)
NETOPT_IPV6_IID_RFC7217,
#endif
};

#if IS_ACTIVE(CONFIG_GNRC_IPV6_STABLE_PRIVACY) || defined(DOXYGEN)
/**
* @brief Data for @ref NETOPT_IPV6_IID when using RFC7217,
* passed on to ipv6_get_rfc7217_iid,
* from which the descriptions are also copied
*/
typedef struct {
/**
* @param[out] where to store the generated interface identifier
*/
eui64_t *iid;
/**
* @param[in] pfx The prefix for which the IID is to be generated.
*/
const ipv6_addr_t *pfx;
/**
* @param[in,out] dad_ctr ("DAD_Counter" in rfc7217)
*/
uint8_t *dad_ctr;
} netopt_ipv6_rfc7217_iid_data;
#endif

/**
* @brief Option parameter to be used with @ref NETOPT_RF_TESTMODE
*/
@@ -1030,7 +1065,7 @@
/**
* @brief Basic callback type on network disconnection @ref NETOPT_CONNECT
*/
typedef void (*netopt_on_disconnect_result_t) (void *netif, const struct netopt_disconnect_result *res);

Check warning on line 1068 in sys/include/net/netopt.h

GitHub Actions / static-tests

line is longer than 100 characters

/**
* @brief Basic network connect request
15 changes: 15 additions & 0 deletions sys/net/gnrc/Makefile.dep
Original file line number Diff line number Diff line change
@@ -431,6 +431,21 @@ ifneq (,$(filter gnrc_ipv6_nib,$(USEMODULE)))
USEMODULE += random
endif

#This checks if the option is being set via Kconfig or CFLAGS
ifneq (,$(or $(CONFIG_GNRC_IPV6_STABLE_PRIVACY),$(filter -DCONFIG_GNRC_IPV6_STABLE_PRIVACY=1,$(CFLAGS))))
# Set another macro that is needed for this option.

##prepare value
stable_privacy_secret_key != python3 -c "import secrets; print(','.join([f'0x{byte:02x}' for byte in secrets.token_bytes(16)]))"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll have to think a bit about device individualization in RIOT as a whole (esp. for questions like "is this maybe better created in a HWRNG assisted way at first start?"), but until then, passing it into the build seems fine.

As someone who repeatedly flashes devices and then starts network interactions, it may be convenient to store this in the build directory and recreate only if absent, as that will make addresses stable across rebuilds.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely agree, letting the board generate the secret_key by itself (and permanently store it - as per the RFC) would be more convenient, as a future improvement!


##set macro
CFLAGS += -DSTABLE_PRIVACY_SECRET_KEY=$(stable_privacy_secret_key)

# dependencies
USEMODULE += hashes ##include "hashes/sha256.h"
USEMODULE += ztimer_msec
endif

ifneq (,$(filter gnrc_udp,$(USEMODULE)))
DEFAULT_MODULE += auto_init_gnrc_udp
USEMODULE += gnrc_nettype_udp
82 changes: 78 additions & 4 deletions sys/net/gnrc/netif/gnrc_netif.c
Original file line number Diff line number Diff line change
@@ -49,6 +49,7 @@

#define ENABLE_DEBUG 0
#include "debug.h"
#include "../network_layer/ipv6/nib/_nib-slaac.h"

static void _update_l2addr_from_dev(gnrc_netif_t *netif);
static void _check_netdev_capabilities(netdev_t *dev);
@@ -269,8 +270,23 @@
}
break;
case NETOPT_IPV6_IID:
assert(opt->data_len >= sizeof(eui64_t));
res = gnrc_netif_ipv6_get_iid(netif, opt->data);
switch ((int16_t)opt->context) {
case NETOPT_IPV6_IID_HWADDR:
assert(opt->data_len >= sizeof(eui64_t));
res = gnrc_netif_ipv6_get_iid(netif, opt->data);
break;
#if IS_ACTIVE(CONFIG_GNRC_IPV6_STABLE_PRIVACY)
case NETOPT_IPV6_IID_RFC7217:
assert(opt->data_len == sizeof(netopt_ipv6_rfc7217_iid_data));
netopt_ipv6_rfc7217_iid_data *data =
(netopt_ipv6_rfc7217_iid_data *) opt->data;
res = ipv6_get_rfc7217_iid_idempotent(
data->iid, netif, data->pfx, data->dad_ctr);
break;
#endif
default:
break;
}
break;
case NETOPT_MAX_PDU_SIZE:
if (opt->context == GNRC_NETTYPE_IPV6) {
@@ -502,6 +518,9 @@

#if IS_USED(MODULE_GNRC_NETIF_IPV6)
static int _addr_idx(const gnrc_netif_t *netif, const ipv6_addr_t *addr);
static int _addr_pfx_idx(const gnrc_netif_t *netif,
const ipv6_addr_t *pfx,
uint8_t pfx_len);
static int _group_idx(const gnrc_netif_t *netif, const ipv6_addr_t *addr);

static char addr_str[IPV6_ADDR_MAX_STR_LEN];
@@ -730,6 +749,23 @@
return idx;
}

int gnrc_netif_ipv6_addr_pfx_idx(gnrc_netif_t *netif,
const ipv6_addr_t *pfx, uint8_t pfx_len)
{
int idx;

assert((netif != NULL) && (pfx != NULL));
DEBUG("gnrc_netif: get index of first address matching %s/%u"
" from interface %" PRIkernel_pid "\n",
ipv6_addr_to_str(addr_str, pfx, sizeof(addr_str)),
pfx_len,
netif->pid);
gnrc_netif_acquire(netif);
idx = _addr_pfx_idx(netif, pfx, pfx_len);
gnrc_netif_release(netif);
return idx;
}

int gnrc_netif_ipv6_addr_match(gnrc_netif_t *netif,
const ipv6_addr_t *addr)
{
@@ -947,11 +983,35 @@
return -1;
}

static int _pfx_idx(const gnrc_netif_t *netif, const ipv6_addr_t *pfx, uint8_t pfx_len, bool mcast)
{
/*same as function @ref _idx above, but with generalized condition*/
if (!ipv6_addr_is_unspecified(pfx)) {
const ipv6_addr_t *iplist = (mcast) ? netif->ipv6.groups :
netif->ipv6.addrs;
unsigned ipmax = (mcast) ? GNRC_NETIF_IPV6_GROUPS_NUMOF :
CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF;
for (unsigned i = 0; i < ipmax; i++) {
if (ipv6_addr_match_prefix(&iplist[i], pfx) >= pfx_len) {
return i;
}
}
}
return -1;
}

static inline int _addr_idx(const gnrc_netif_t *netif, const ipv6_addr_t *addr)
{
return _idx(netif, addr, false);
}

static inline int _addr_pfx_idx(const gnrc_netif_t *netif,
const ipv6_addr_t *pfx,
uint8_t pfx_len)
{
return _pfx_idx(netif, pfx, pfx_len, false);
}

static inline int _group_idx(const gnrc_netif_t *netif, const ipv6_addr_t *addr)
{
return _idx(netif, addr, true);
@@ -1284,8 +1344,22 @@
assert(netif != NULL);
DEBUG("gnrc_netif: (re-)configure prefix %s/%d\n",
ipv6_addr_to_str(addr_str, pfx, sizeof(addr_str)), pfx_len);
if (gnrc_netapi_get(netif->pid, NETOPT_IPV6_IID, 0, &iid,
sizeof(eui64_t)) >= 0) {
#if IS_ACTIVE(CONFIG_GNRC_IPV6_STABLE_PRIVACY)
uint8_t dad_ctr = 0;
netopt_ipv6_rfc7217_iid_data data;
data.iid = &iid;
data.pfx = pfx;
data.dad_ctr = &dad_ctr;
/* no need to store dad_ctr with address (via flags)
* as it can't fail DAD, since already valid */
#endif
if (gnrc_netapi_get(netif->pid, NETOPT_IPV6_IID,
#if IS_ACTIVE(CONFIG_GNRC_IPV6_STABLE_PRIVACY)
NETOPT_IPV6_IID_RFC7217, &data, sizeof(data)
#else
NETOPT_IPV6_IID_HWADDR, &iid, sizeof(eui64_t)
#endif
) >= 0) {
ipv6_addr_set_aiid(&addr, iid.uint8);
}
else {
@@ -2149,4 +2223,4 @@
}
}
}
/** @} */

Check warning on line 2226 in sys/net/gnrc/netif/gnrc_netif.c

GitHub Actions / static-tests

source file is too long
8 changes: 8 additions & 0 deletions sys/net/gnrc/network_layer/ipv6/nib/Kconfig
Original file line number Diff line number Diff line change
@@ -38,6 +38,14 @@ config GNRC_IPV6_NIB_SLAAC
default n if USEMODULE_GNRC_IPV6_NIB_6LR || USEMODULE_GNRC_IPV6_NIB_6LN
default y

config GNRC_IPV6_STABLE_PRIVACY
bool "Use stable privacy addresses (rfc7217)"
depends on GNRC_IPV6_NIB_SLAAC
help
Generate semantically opaque interface identifiers
(i.e. L2ADDR is not embedded)
for SLAAC IPv6 addresses

config GNRC_IPV6_NIB_QUEUE_PKT
bool "Use packet queue with address resolution"
default n if USEMODULE_GNRC_IPV6_NIB_6LN || GNRC_IPV6_NIB_6LN
Loading