From: Yu Watanabe Date: Wed, 13 Mar 2024 03:31:35 +0000 (+0900) Subject: ndisc-option: add a way to specify invalid or unsupported options X-Git-Tag: v256-rc1~413^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=af0d593b32cc63f00865e6736eb93ed6012522ea;p=thirdparty%2Fsystemd.git ndisc-option: add a way to specify invalid or unsupported options Mostly for testing. --- diff --git a/src/libsystemd-network/ndisc-option.c b/src/libsystemd-network/ndisc-option.c index 380e71e7643..862148a7121 100644 --- a/src/libsystemd-network/ndisc-option.c +++ b/src/libsystemd-network/ndisc-option.c @@ -65,6 +65,13 @@ static sd_ndisc_option* ndisc_option_new(uint8_t type, size_t offset) { return p; } +static void ndisc_raw_done(sd_ndisc_raw *raw) { + if (!raw) + return; + + free(raw->bytes); +} + static void ndisc_rdnss_done(sd_ndisc_rdnss *rdnss) { if (!rdnss) return; @@ -84,6 +91,10 @@ sd_ndisc_option* ndisc_option_free(sd_ndisc_option *option) { return NULL; switch (option->type) { + case 0: + ndisc_raw_done(&option->raw); + break; + case SD_NDISC_OPTION_RDNSS: ndisc_rdnss_done(&option->rdnss); break; @@ -111,6 +122,9 @@ static int ndisc_option_compare_func(const sd_ndisc_option *x, const sd_ndisc_op return r; switch (x->type) { + case 0: + return memcmp_nn(x->raw.bytes, x->raw.length, y->raw.bytes, y->raw.length); + case SD_NDISC_OPTION_SOURCE_LL_ADDRESS: case SD_NDISC_OPTION_TARGET_LL_ADDRESS: case SD_NDISC_OPTION_REDIRECTED_HEADER: @@ -155,6 +169,10 @@ static void ndisc_option_hash_func(const sd_ndisc_option *option, struct siphash siphash24_compress_typesafe(option->type, state); switch (option->type) { + case 0: + siphash24_compress(option->raw.bytes, option->raw.length, state); + break; + case SD_NDISC_OPTION_SOURCE_LL_ADDRESS: case SD_NDISC_OPTION_TARGET_LL_ADDRESS: case SD_NDISC_OPTION_REDIRECTED_HEADER: @@ -199,6 +217,31 @@ static int ndisc_option_consume(Set **options, sd_ndisc_option *p) { return set_ensure_consume(options, &ndisc_option_hash_ops, p); } +int ndisc_option_add_raw(Set **options, size_t offset, size_t length, const uint8_t *bytes) { + _cleanup_free_ uint8_t *copy = NULL; + + assert(options); + assert(bytes); + + if (length == 0) + return -EINVAL; + + copy = newdup(uint8_t, bytes, length); + if (!copy) + return -ENOMEM; + + sd_ndisc_option *p = ndisc_option_new(/* type = */ 0, offset); + if (!p) + return -ENOMEM; + + p->raw = (sd_ndisc_raw) { + .bytes = TAKE_PTR(copy), + .length = length, + }; + + return ndisc_option_consume(options, p); +} + int ndisc_option_add_link_layer_address(Set **options, uint8_t opt, size_t offset, const struct ether_addr *mac) { assert(options); assert(IN_SET(opt, SD_NDISC_OPTION_SOURCE_LL_ADDRESS, SD_NDISC_OPTION_TARGET_LL_ADDRESS)); @@ -788,6 +831,10 @@ int ndisc_parse_options(ICMP6Packet *packet, Set **ret_options) { return log_debug_errno(r, "Failed to parse NDisc option header: %m"); switch (type) { + case 0: + r = -EBADMSG; + break; + case SD_NDISC_OPTION_SOURCE_LL_ADDRESS: case SD_NDISC_OPTION_TARGET_LL_ADDRESS: r = ndisc_option_parse_link_layer_address(&options, offset, length, opt); diff --git a/src/libsystemd-network/ndisc-option.h b/src/libsystemd-network/ndisc-option.h index 45108ee1aa5..fdfea3fc34a 100644 --- a/src/libsystemd-network/ndisc-option.h +++ b/src/libsystemd-network/ndisc-option.h @@ -13,6 +13,11 @@ #include "set.h" #include "time-util.h" +typedef struct sd_ndisc_raw { + uint8_t *bytes; + size_t length; +} sd_ndisc_raw; + /* Mostly equivalent to struct nd_opt_prefix_info, but using usec_t. */ typedef struct sd_ndisc_prefix { uint8_t flags; @@ -51,6 +56,7 @@ typedef struct sd_ndisc_option { size_t offset; union { + sd_ndisc_raw raw; /* for testing or unsupported options */ struct ether_addr mac; /* SD_NDISC_OPTION_SOURCE_LL_ADDRESS or SD_NDISC_OPTION_TARGET_LL_ADDRESS */ sd_ndisc_prefix prefix; /* SD_NDISC_OPTION_PREFIX_INFORMATION */ struct ip6_hdr hdr; /* SD_NDISC_OPTION_REDIRECTED_HEADER */ @@ -107,6 +113,11 @@ static inline sd_ndisc_option* ndisc_option_get(Set *options, uint8_t type) { int ndisc_option_get_mac(Set *options, uint8_t type, struct ether_addr *ret); +int ndisc_option_add_raw( + Set **options, + size_t offset, + size_t length, + const uint8_t *bytes); int ndisc_option_add_link_layer_address( Set **options, uint8_t opt,