ldns  1.8.3
/build/ldns-rc5ieH/ldns-1.8.3/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 */
23size_t
25{
26 assert(edns != NULL);
27 return edns->_size;
28}
29
32{
33 assert(edns != NULL);
34 return edns->_code;
35}
36
37uint8_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 */
76void
78{
79 assert(edns != NULL);
80 edns->_size = size;
81}
82
83void
85{
86 assert(edns != NULL);
87 edns->_code = code;
88}
89
90void
92{
93 /* only copy the pointer */
94 assert(edns != NULL);
95 edns->_data = data;
96}
97
98/* note: data must be allocated memory */
100ldns_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
115ldns_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
144 ldns_edns_get_size(edns),
145 ldns_edns_get_data(edns));
146
147 return new_option;
148}
149
150void
152{
153 if (edns) {
154 if (edns->_data) {
155 LDNS_FREE(edns->_data);
156 }
157 LDNS_FREE(edns);
158 }
159}
160
161void
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
215void
217{
218 if (option_list) {
219 LDNS_FREE(option_list->_options);
220 LDNS_FREE(option_list);
221 }
222}
223
224void
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
237size_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
258size_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
298bool
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
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_list * ldns_edns_option_list_new()
allocates space for a new list of EDNS options
Definition edns.c:170
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
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_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
uint8_t * ldns_edns_get_data(const ldns_edns_option *edns)
returns the EDNS option data.
Definition edns.c:38
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
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 * 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
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
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
ldns_edns_option * ldns_edns_clone(ldns_edns_option *edns)
clone an EDNS option
Definition edns.c:137
void ldns_edns_option_list_deep_free(ldns_edns_option_list *option_list)
Definition edns.c:225
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
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
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