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