6 * a Net::DNS like library for C
8 * (c) NLnet Labs, 2004-2022
10 * See the file LICENSE for the license
13 #include <ldns/ldns.h>
15 #define LDNS_OPTIONLIST_INIT 8
19 * functions to get and set type checking
24 ldns_edns_get_size(const ldns_edns_option *edns)
31 ldns_edns_get_code(const ldns_edns_option *edns)
38 ldns_edns_get_data(const ldns_edns_option *edns)
45 ldns_edns_get_wireformat_buffer(const ldns_edns_option *edns)
56 option = ldns_edns_get_code(edns);
57 size = ldns_edns_get_size(edns);
58 data = ldns_edns_get_data(edns);
60 buffer = ldns_buffer_new(size + 4);
66 ldns_buffer_write_u16(buffer, option);
67 ldns_buffer_write_u16(buffer, size);
68 ldns_buffer_write(buffer, data, size);
70 ldns_buffer_flip(buffer);
77 ldns_edns_set_size(ldns_edns_option *edns, size_t size)
84 ldns_edns_set_code(ldns_edns_option *edns, ldns_edns_option_code code)
91 ldns_edns_set_data(ldns_edns_option *edns, void *data)
93 /* only copy the pointer */
98 /* note: data must be allocated memory */
100 ldns_edns_new(ldns_edns_option_code code, size_t size, void *data)
102 ldns_edns_option *edns;
103 edns = LDNS_MALLOC(ldns_edns_option);
107 ldns_edns_set_code(edns, code);
108 ldns_edns_set_size(edns, size);
109 ldns_edns_set_data(edns, data);
115 ldns_edns_new_from_data(ldns_edns_option_code code, size_t size, const void *data)
117 ldns_edns_option *edns;
118 edns = LDNS_MALLOC(ldns_edns_option);
122 edns->_data = LDNS_XMALLOC(uint8_t, size);
129 ldns_edns_set_code(edns, code);
130 ldns_edns_set_size(edns, size);
131 memcpy(edns->_data, data, size);
137 ldns_edns_clone(ldns_edns_option *edns)
139 ldns_edns_option *new_option;
141 assert(edns != NULL);
143 new_option = ldns_edns_new_from_data(ldns_edns_get_code(edns),
144 ldns_edns_get_size(edns),
145 ldns_edns_get_data(edns));
151 ldns_edns_deep_free(ldns_edns_option *edns)
155 LDNS_FREE(edns->_data);
162 ldns_edns_free(ldns_edns_option *edns)
169 ldns_edns_option_list*
170 ldns_edns_option_list_new()
172 ldns_edns_option_list *option_list = LDNS_MALLOC(ldns_edns_option_list);
177 option_list->_option_count = 0;
178 option_list->_option_capacity = 0;
179 option_list->_options_size = 0;
180 option_list->_options = NULL;
184 ldns_edns_option_list *
185 ldns_edns_option_list_clone(ldns_edns_option_list *old_list)
188 ldns_edns_option_list *new_list;
194 new_list = ldns_edns_option_list_new();
199 if (old_list->_option_count == 0) {
203 /* adding options also updates the total options size */
204 for (i = 0; i < old_list->_option_count; i++) {
205 ldns_edns_option *option = ldns_edns_clone(ldns_edns_option_list_get_option(old_list, i));
206 if (!ldns_edns_option_list_push(new_list, option)) {
207 ldns_edns_deep_free(option);
208 ldns_edns_option_list_deep_free(new_list);
216 ldns_edns_option_list_free(ldns_edns_option_list *option_list)
219 LDNS_FREE(option_list->_options);
220 LDNS_FREE(option_list);
225 ldns_edns_option_list_deep_free(ldns_edns_option_list *option_list)
230 for (i=0; i < ldns_edns_option_list_get_count(option_list); i++) {
231 ldns_edns_deep_free(ldns_edns_option_list_get_option(option_list, i));
233 ldns_edns_option_list_free(option_list);
238 ldns_edns_option_list_get_count(const ldns_edns_option_list *option_list)
241 return option_list->_option_count;
248 ldns_edns_option_list_get_option(const ldns_edns_option_list *option_list, size_t index)
250 if (option_list && index < ldns_edns_option_list_get_count(option_list)) {
251 assert(option_list->_options[index]);
252 return option_list->_options[index];
259 ldns_edns_option_list_get_options_size(const ldns_edns_option_list *option_list)
262 return option_list->_options_size;
270 ldns_edns_option_list_set_option(ldns_edns_option_list *option_list,
271 ldns_edns_option *option, size_t index)
273 ldns_edns_option* old;
275 assert(option_list != NULL);
277 if (index > ldns_edns_option_list_get_count(option_list)) {
281 if (option == NULL) {
285 old = ldns_edns_option_list_get_option(option_list, index);
287 /* shrink the total EDNS size if the old EDNS option exists */
289 option_list->_options_size -= (ldns_edns_get_size(old) + 4);
292 option_list->_options_size += (ldns_edns_get_size(option) + 4);
294 option_list->_options[index] = option;
299 ldns_edns_option_list_push(ldns_edns_option_list *option_list,
300 ldns_edns_option *option)
305 assert(option_list != NULL);
307 if (option == NULL) {
311 cap = option_list->_option_capacity;
312 option_count = ldns_edns_option_list_get_count(option_list);
314 /* verify we need to grow the array to fit the new option */
315 if (option_count+1 > cap) {
316 ldns_edns_option **new_list;
318 /* initialize the capacity if needed, otherwise grow by doubling */
320 cap = LDNS_OPTIONLIST_INIT; /* initial list size */
325 new_list = LDNS_XREALLOC(option_list->_options,
326 ldns_edns_option *, cap);
332 option_list->_options = new_list;
333 option_list->_option_capacity = cap;
336 /* add the new option */
337 ldns_edns_option_list_set_option(option_list, option,
338 option_list->_option_count);
339 option_list->_option_count += 1;
345 ldns_edns_option_list_pop(ldns_edns_option_list *option_list)
347 ldns_edns_option* pop;
351 assert(option_list != NULL);
353 cap = option_list->_option_capacity;
354 count = ldns_edns_option_list_get_count(option_list);
359 /* get the last option from the list */
360 pop = ldns_edns_option_list_get_option(option_list, count-1);
362 /* shrink the array */
363 if (cap > LDNS_OPTIONLIST_INIT && count-1 <= cap/2) {
364 ldns_edns_option **new_list;
368 new_list = LDNS_XREALLOC(option_list->_options,
369 ldns_edns_option *, cap);
371 option_list->_options = new_list;
373 /* if the realloc fails, the capacity for the list remains unchanged */
376 /* shrink the total EDNS size of the options if the popped EDNS option exists */
378 option_list->_options_size -= (ldns_edns_get_size(pop) + 4);
381 option_list->_option_count = count - 1;
387 ldns_edns_option_list2wireformat_buffer(const ldns_edns_option_list *option_list)
389 size_t i, list_size, options_size, option, size;
391 ldns_edns_option *edns;
392 uint8_t* data = NULL;
398 /* get the number of EDNS options in the list*/
399 list_size = ldns_edns_option_list_get_count(option_list);
401 /* create buffer the size of the total EDNS wireformat options */
402 options_size = ldns_edns_option_list_get_options_size(option_list);
403 buffer = ldns_buffer_new(options_size);
409 /* write individual serialized EDNS options to final buffer*/
410 for (i = 0; i < list_size; i++) {
411 edns = ldns_edns_option_list_get_option(option_list, i);
414 /* this shouldn't be possible */
418 option = ldns_edns_get_code(edns);
419 size = ldns_edns_get_size(edns);
420 data = ldns_edns_get_data(edns);
422 /* make sure the option fits */
423 if (!(ldns_buffer_available(buffer, size + 4))) {
424 ldns_buffer_free(buffer);
428 ldns_buffer_write_u16(buffer, option);
429 ldns_buffer_write_u16(buffer, size);
430 ldns_buffer_write(buffer, data, size);
433 ldns_buffer_flip(buffer);