From: TCY16 Date: Tue, 12 Apr 2022 09:10:49 +0000 (+0200) Subject: add serializing functions for single edns options and option lists X-Git-Tag: 1.8.2-rc.1~3^2~23 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fa36106918d11843d0ccb8f9a798bd3d5d40784c;p=thirdparty%2Fldns.git add serializing functions for single edns options and option lists --- diff --git a/edns.c b/edns.c index 1d786b6c..f6a8a797 100644 --- a/edns.c +++ b/edns.c @@ -39,6 +39,37 @@ ldns_edns_get_data(const ldns_edns_option *edns) return edns->_data; } +ldns_buffer * +ldns_edns_get_wireformat_buffer(const ldns_edns_option *edns) +{ + uint16_t option; + size_t size; + uint8_t* data; + ldns_buffer* buffer; + + if (edns == NULL) { + return NULL; + } + + option = ldns_edns_get_code(edns); + size = ldns_edns_get_size(edns); + data = ldns_edns_get_data(edns); + + buffer = ldns_buffer_new(size + 4); + + if (buffer == NULL) { + return NULL; + } + + ldns_buffer_write_u16(buffer, option); + ldns_buffer_write_u16(buffer, size); + ldns_buffer_write(buffer, data, size); + + ldns_buffer_flip(buffer); + + return buffer; +} + /* write */ void ldns_edns_set_size(ldns_edns_option *edns, size_t size) @@ -71,9 +102,32 @@ ldns_edns_new(ldns_edns_option_code code, size_t size, void *data) if (!edns) { return NULL; } - ldns_edns_set_size(edns, size); ldns_edns_set_code(edns, code); + ldns_edns_set_size(edns, size); ldns_edns_set_data(edns, data); + + return edns; +} + +ldns_edns_option * +ldns_edns_new_from_data(ldns_edns_option_code code, size_t size, const void *data) +{ + ldns_edns_option *edns; + edns = LDNS_MALLOC(ldns_edns_option); + if (!edns) { + return NULL; + } + edns->_data = LDNS_XMALLOC(uint8_t, size); + if (!edns->_data) { + LDNS_FREE(edns); + return NULL; + } + + /* set the values */ + ldns_edns_set_code(edns, code); + ldns_edns_set_size(edns, size); + memcpy(edns->_data, data, size); + return edns; } @@ -146,7 +200,7 @@ ldns_edns_option_list_get_count(const ldns_edns_option_list *option_list) void ldns_edns_option_list_set_count(ldns_edns_option_list *option_list, size_t count) { - assert(option_list); // @TODO does this check need to check more? + assert(option_list); option_list->_option_count = count; } @@ -196,7 +250,7 @@ ldns_edns_option_list_set_option(ldns_edns_option_list *option_list, option_list->_options_size += (ldns_edns_get_size(option) + 4); - /* overwrite the pointer of "old" */ + /* overwrite the pointer of the old entry */ option_list->_options[index] = (ldns_edns_option*)option; return old; } @@ -209,8 +263,7 @@ ldns_edns_option_list_push(ldns_edns_option_list *option_list, if (option != NULL) { - // @TODO rethink reallocing per push - + /* grow the array */ option_list->_options = LDNS_XREALLOC(option_list->_options, ldns_edns_option *, option_list->_option_count + 1); if (!option_list) { @@ -242,8 +295,6 @@ ldns_edns_option_list_pop(ldns_edns_option_list *option_list) /* get the last option from the list */ pop = ldns_edns_option_list_get_option(option_list, count-1); - // @TODO rethink reallocing per pop - /* shrink the array */ new_list = LDNS_XREALLOC(option_list->_options, ldns_edns_option *, count -1); if (new_list){ @@ -260,3 +311,46 @@ ldns_edns_option_list_pop(ldns_edns_option_list *option_list) return pop; } +ldns_buffer * +ldns_edns_option_list2wireformat_buffer(const ldns_edns_option_list *option_list) +{ + size_t i, list_size, options_size, option, size; + ldns_buffer* buffer; + ldns_edns_option *edns; + uint8_t* data = NULL; + + /* get the number of EDNS options in the list*/ + list_size = ldns_edns_option_list_get_count(option_list); + + /* create buffer the size of the total EDNS wireformat options */ + options_size = ldns_edns_option_list_get_options_size(option_list); + buffer = ldns_buffer_new(options_size); + + /* write individual serialized EDNS options to final buffer*/ + for (i = 0; i < list_size; i++) { + edns = ldns_edns_option_list_get_option(option_list, i); + + if (edns == NULL) { + /* this shouldn't be possible */ + return NULL; + } + + option = ldns_edns_get_code(edns); + size = ldns_edns_get_size(edns); + data = ldns_edns_get_data(edns); + + /* make sure the option fits */ + if (ldns_buffer_capacity(buffer) > size + 4) { + ldns_buffer_free(buffer); + return NULL; + } + + ldns_buffer_write_u16(buffer, option); + ldns_buffer_write_u16(buffer, size); + ldns_buffer_write(buffer, data, size); + } + + ldns_buffer_flip(buffer); + + return buffer; +} diff --git a/ldns/edns.h b/ldns/edns.h index c6c2ebb1..9d821ee9 100644 --- a/ldns/edns.h +++ b/ldns/edns.h @@ -95,9 +95,9 @@ typedef enum ldns_edns_enum_ede_code ldns_edns_ede_code; +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ struct ldns_struct_edns_option { - ldns_edns_option_code _code; - size_t _size; - void *_data; + ldns_edns_option_code _code; + size_t _size; + void *_data; }; typedef struct ldns_struct_edns_option ldns_edns_option; @@ -108,7 +108,7 @@ typedef struct ldns_struct_edns_option ldns_edns_option; struct ldns_struct_edns_option_list { size_t _option_count; - size_t _options_size; /* the total size of the options in the list*/ + size_t _options_size; /* the total size of the options serialized */ ldns_edns_option **_options; }; typedef struct ldns_struct_edns_option_list ldns_edns_option_list; @@ -134,11 +134,19 @@ ldns_edns_option_code ldns_edns_get_code(const ldns_edns_option *edns); /** * returns the EDNS option data. - * \param[in] *edns the rdf to read from - * \return uint8_t* pointer to the rdf's data + * \param[in] *edns the EDNS option to read from + * \return uint8_t* pointer to the EDNS option's data */ uint8_t *ldns_edns_get_data(const ldns_edns_option *edns); + +/** + * serialise the EDNS option into wireformat. + * \param[in] *edns the EDNS option to read from + * \return ldns_buffer* the buffer containing the data + */ +ldns_buffer *ldns_edns_get_wireformat_buffer(const ldns_edns_option *edns); + /* Constructors and destructors*/ /** @@ -151,6 +159,9 @@ uint8_t *ldns_edns_get_data(const ldns_edns_option *edns); */ ldns_edns_option *ldns_edns_new(ldns_edns_option_code code, size_t size, void *data); +// @TODO write this/determine if we need it +ldns_edns_option *ldns_edns_new_from_data(ldns_edns_option_code code, size_t size, const void *data); + void ldns_edns_deep_free(ldns_edns_option *edns); void ldns_edns_free(ldns_edns_option *edns); @@ -222,6 +233,13 @@ bool ldns_edns_option_list_push(ldns_edns_option_list *options_list, */ ldns_edns_option* ldns_edns_option_list_pop(ldns_edns_option_list *options_list); +/** + * serializes all the EDNS options into a single wireformat buffer + * \param[in] options_list the EDNS options_list to combine into one wireformat + * \return the filled buffer or NULL on failure + */ +ldns_buffer *ldns_edns_option_list2wireformat_buffer(const ldns_edns_option_list *option_list); + #ifdef __cplusplus } #endif