edns.c
Go to the documentation of this file.
1 /*
2  * edns.c
3  *
4  * edns implementation
5  *
6  * a Net::DNS like library for C
7  *
8  * (c) NLnet Labs, 2004-2022
9  *
10  * See the file LICENSE for the license
11  */
12 
13 #include <ldns/ldns.h>
14 
15 #define LDNS_OPTIONLIST_INIT 8
16 
17 /*
18  * Access functions
19  * functions to get and set type checking
20  */
21 
22 /* read */
23 size_t
25 {
26  assert(edns != NULL);
27  return edns->_size;
28 }
29 
32 {
33  assert(edns != NULL);
34  return edns->_code;
35 }
36 
37 uint8_t *
39 {
40  assert(edns != NULL);
41  return edns->_data;
42 }
43 
46 {
47  uint16_t option;
48  size_t size;
49  uint8_t* data;
50  ldns_buffer* buffer;
51 
52  if (edns == NULL) {
53  return NULL;
54  }
55 
56  option = ldns_edns_get_code(edns);
57  size = ldns_edns_get_size(edns);
58  data = ldns_edns_get_data(edns);
59 
60  buffer = ldns_buffer_new(size + 4);
61 
62  if (buffer == NULL) {
63  return NULL;
64  }
65 
66  ldns_buffer_write_u16(buffer, option);
67  ldns_buffer_write_u16(buffer, size);
68  ldns_buffer_write(buffer, data, size);
69 
70  ldns_buffer_flip(buffer);
71 
72  return buffer;
73 }
74 
75 /* write */
76 void
78 {
79  assert(edns != NULL);
80  edns->_size = size;
81 }
82 
83 void
85 {
86  assert(edns != NULL);
87  edns->_code = code;
88 }
89 
90 void
92 {
93  /* only copy the pointer */
94  assert(edns != NULL);
95  edns->_data = data;
96 }
97 
98 /* note: data must be allocated memory */
100 ldns_edns_new(ldns_edns_option_code code, size_t size, void *data)
101 {
102  ldns_edns_option *edns;
104  if (!edns) {
105  return NULL;
106  }
107  ldns_edns_set_code(edns, code);
108  ldns_edns_set_size(edns, size);
109  ldns_edns_set_data(edns, data);
110 
111  return edns;
112 }
113 
115 ldns_edns_new_from_data(ldns_edns_option_code code, size_t size, const void *data)
116 {
117  ldns_edns_option *edns;
119  if (!edns) {
120  return NULL;
121  }
122  edns->_data = LDNS_XMALLOC(uint8_t, size);
123  if (!edns->_data) {
124  LDNS_FREE(edns);
125  return NULL;
126  }
127 
128  /* set the values */
129  ldns_edns_set_code(edns, code);
130  ldns_edns_set_size(edns, size);
131  memcpy(edns->_data, data, size);
132 
133  return edns;
134 }
135 
138 {
139  ldns_edns_option *new_option;
140 
141  assert(edns != NULL);
142 
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));
146 
147  return new_option;
148 }
149 
150 void
152 {
153  if (edns) {
154  if (edns->_data) {
155  LDNS_FREE(edns->_data);
156  }
157  LDNS_FREE(edns);
158  }
159 }
160 
161 void
163 {
164  if (edns) {
165  LDNS_FREE(edns);
166  }
167 }
168 
171 {
173  if(!option_list) {
174  return NULL;
175  }
176 
177  option_list->_option_count = 0;
178  option_list->_option_capacity = 0;
179  option_list->_options_size = 0;
180  option_list->_options = NULL;
181  return option_list;
182 }
183 
186 {
187  size_t i;
188  ldns_edns_option_list *new_list;
189 
190  if (!old_list) {
191  return NULL;
192  }
193 
194  new_list = ldns_edns_option_list_new();
195  if (!new_list) {
196  return NULL;
197  }
198 
199  if (old_list->_option_count == 0) {
200  return new_list;
201  }
202 
203  /* adding options also updates the total options size */
204  for (i = 0; i < old_list->_option_count; i++) {
206  if (!ldns_edns_option_list_push(new_list, option)) {
207  ldns_edns_deep_free(option);
209  return NULL;
210  }
211  }
212  return new_list;
213 }
214 
215 void
217 {
218  if (option_list) {
219  LDNS_FREE(option_list->_options);
220  LDNS_FREE(option_list);
221  }
222 }
223 
224 void
226 {
227  size_t i;
228 
229  if (option_list) {
230  for (i=0; i < ldns_edns_option_list_get_count(option_list); i++) {
232  }
233  ldns_edns_option_list_free(option_list);
234  }
235 }
236 
237 size_t
239 {
240  if (option_list) {
241  return option_list->_option_count;
242  } else {
243  return 0;
244  }
245 }
246 
249 {
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];
253  } else {
254  return NULL;
255  }
256 }
257 
258 size_t
260 {
261  if (option_list) {
262  return option_list->_options_size;
263  } else {
264  return 0;
265  }
266 }
267 
268 
271  ldns_edns_option *option, size_t index)
272 {
273  ldns_edns_option* old;
274 
275  assert(option_list != NULL);
276 
277  if (index > ldns_edns_option_list_get_count(option_list)) {
278  return NULL;
279  }
280 
281  if (option == NULL) {
282  return NULL;
283  }
284 
285  old = ldns_edns_option_list_get_option(option_list, index);
286 
287  /* shrink the total EDNS size if the old EDNS option exists */
288  if (old != NULL) {
289  option_list->_options_size -= (ldns_edns_get_size(old) + 4);
290  }
291 
292  option_list->_options_size += (ldns_edns_get_size(option) + 4);
293 
294  option_list->_options[index] = option;
295  return old;
296 }
297 
298 bool
300  ldns_edns_option *option)
301 {
302  size_t cap;
303  size_t option_count;
304 
305  assert(option_list != NULL);
306 
307  if (option == NULL) {
308  return false;
309  }
310 
311  cap = option_list->_option_capacity;
312  option_count = ldns_edns_option_list_get_count(option_list);
313 
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;
317 
318  /* initialize the capacity if needed, otherwise grow by doubling */
319  if (cap == 0) {
320  cap = LDNS_OPTIONLIST_INIT; /* initial list size */
321  } else {
322  cap *= 2;
323  }
324 
325  new_list = LDNS_XREALLOC(option_list->_options,
326  ldns_edns_option *, cap);
327 
328  if (!new_list) {
329  return false;
330  }
331 
332  option_list->_options = new_list;
333  option_list->_option_capacity = cap;
334  }
335 
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;
340 
341  return true;
342 }
343 
346 {
347  ldns_edns_option* pop;
348  size_t count;
349  size_t cap;
350 
351  assert(option_list != NULL);
352 
353  cap = option_list->_option_capacity;
354  count = ldns_edns_option_list_get_count(option_list);
355 
356  if (count == 0) {
357  return NULL;
358  }
359  /* get the last option from the list */
360  pop = ldns_edns_option_list_get_option(option_list, count-1);
361 
362  /* shrink the array */
363  if (cap > LDNS_OPTIONLIST_INIT && count-1 <= cap/2) {
364  ldns_edns_option **new_list;
365 
366  cap /= 2;
367 
368  new_list = LDNS_XREALLOC(option_list->_options,
369  ldns_edns_option *, cap);
370  if (new_list) {
371  option_list->_options = new_list;
372  }
373  /* if the realloc fails, the capacity for the list remains unchanged */
374  }
375 
376  /* shrink the total EDNS size of the options if the popped EDNS option exists */
377  if (pop != NULL) {
378  option_list->_options_size -= (ldns_edns_get_size(pop) + 4);
379  }
380 
381  option_list->_option_count = count - 1;
382 
383  return pop;
384 }
385 
386 ldns_buffer *
388 {
389  size_t i, list_size, options_size, option, size;
390  ldns_buffer* buffer;
391  ldns_edns_option *edns;
392  uint8_t* data = NULL;
393 
394  if (!option_list) {
395  return NULL;
396  }
397 
398  /* get the number of EDNS options in the list*/
399  list_size = ldns_edns_option_list_get_count(option_list);
400 
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);
404 
405  if (!buffer) {
406  return NULL;
407  }
408 
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);
412 
413  if (edns == NULL) {
414  /* this shouldn't be possible */
415  return NULL;
416  }
417 
418  option = ldns_edns_get_code(edns);
419  size = ldns_edns_get_size(edns);
420  data = ldns_edns_get_data(edns);
421 
422  /* make sure the option fits */
423  if (!(ldns_buffer_available(buffer, size + 4))) {
424  ldns_buffer_free(buffer);
425  return NULL;
426  }
427 
428  ldns_buffer_write_u16(buffer, option);
429  ldns_buffer_write_u16(buffer, size);
430  ldns_buffer_write(buffer, data, size);
431  }
432 
433  ldns_buffer_flip(buffer);
434 
435  return buffer;
436 }
void ldns_buffer_free(ldns_buffer *buffer)
frees the buffer.
Definition: buffer.c:137
ldns_buffer * ldns_buffer_new(size_t capacity)
creates a new buffer with the specified capacity.
Definition: buffer.c:16
ldns_edns_option * ldns_edns_clone(ldns_edns_option *edns)
clone an EDNS option
Definition: edns.c:137
bool ldns_edns_option_list_push(ldns_edns_option_list *option_list, ldns_edns_option *option)
adds an EDNS option at the end of the list of options.
Definition: edns.c:299
void ldns_edns_set_code(ldns_edns_option *edns, ldns_edns_option_code code)
Definition: edns.c:84
uint8_t * ldns_edns_get_data(const ldns_edns_option *edns)
returns the EDNS option data.
Definition: edns.c:38
ldns_buffer * ldns_edns_get_wireformat_buffer(const ldns_edns_option *edns)
serialise the EDNS option into wireformat.
Definition: edns.c:45
#define LDNS_OPTIONLIST_INIT
Definition: edns.c:15
ldns_edns_option * ldns_edns_option_list_pop(ldns_edns_option_list *option_list)
removes and returns the EDNS option at the end of the list of options.
Definition: edns.c:345
ldns_edns_option * ldns_edns_new_from_data(ldns_edns_option_code code, size_t size, const void *data)
allocates a new EDNS structure and fills it.
Definition: edns.c:115
ldns_edns_option_code ldns_edns_get_code(const ldns_edns_option *edns)
returns the option code of the EDNS data.
Definition: edns.c:31
ldns_edns_option_list * ldns_edns_option_list_clone(ldns_edns_option_list *old_list)
clone the EDNS options list and it's contents
Definition: edns.c:185
ldns_edns_option * ldns_edns_option_list_set_option(ldns_edns_option_list *option_list, ldns_edns_option *option, size_t index)
adds an EDNS option to the list of options at the specified index.
Definition: edns.c:270
size_t ldns_edns_option_list_get_count(const ldns_edns_option_list *option_list)
returns the number of options in the EDNS options list.
Definition: edns.c:238
size_t ldns_edns_get_size(const ldns_edns_option *edns)
returns the size of the EDNS data.
Definition: edns.c:24
void ldns_edns_deep_free(ldns_edns_option *edns)
free the EDNS option.
Definition: edns.c:151
void ldns_edns_option_list_free(ldns_edns_option_list *option_list)
free the EDNS option list.
Definition: edns.c:216
void ldns_edns_set_size(ldns_edns_option *edns, size_t size)
Definition: edns.c:77
void ldns_edns_option_list_deep_free(ldns_edns_option_list *option_list)
Definition: edns.c:225
ldns_buffer * ldns_edns_option_list2wireformat_buffer(const ldns_edns_option_list *option_list)
serializes all the EDNS options into a single wireformat buffer
Definition: edns.c:387
ldns_edns_option_list * ldns_edns_option_list_new()
allocates space for a new list of EDNS options
Definition: edns.c:170
ldns_edns_option * ldns_edns_new(ldns_edns_option_code code, size_t size, void *data)
allocates a new EDNS structure and fills it.
Definition: edns.c:100
void ldns_edns_free(ldns_edns_option *edns)
Definition: edns.c:162
void ldns_edns_set_data(ldns_edns_option *edns, void *data)
Definition: edns.c:91
size_t ldns_edns_option_list_get_options_size(const ldns_edns_option_list *option_list)
returns the total size of all the individual EDNS options in the EDNS list.
Definition: edns.c:259
ldns_edns_option * ldns_edns_option_list_get_option(const ldns_edns_option_list *option_list, size_t index)
returns the EDNS option as the specified index in the list of EDNS options.
Definition: edns.c:248
enum ldns_enum_edns_option ldns_edns_option_code
Definition: edns.h:46
Including this file will include all ldns files, and define some lookup tables.
implementation of buffers to ease operations
Definition: buffer.h:51
ldns_edns_option ** _options
Definition: edns.h:113
The struct that stores an ordered EDNS option.
Definition: edns.h:97
ldns_edns_option_code _code
Definition: edns.h:98
#define LDNS_FREE(ptr)
Definition: util.h:60
#define LDNS_MALLOC(type)
Memory management macros.
Definition: util.h:49
#define LDNS_XMALLOC(type, count)
Definition: util.h:51
#define LDNS_XREALLOC(ptr, type, count)
Definition: util.h:57