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