xref: /dragonfly/contrib/ldns/update.c (revision 92fc8b5c)
1 /* update.c
2  *
3  * Functions for RFC 2136 Dynamic Update
4  *
5  * Copyright (c) 2005-2008, NLnet Labs. All rights reserved.
6  *
7  * See LICENSE for the license.
8  */
9 
10 #include <ldns/config.h>
11 
12 #include <ldns/ldns.h>
13 
14 #include <strings.h>
15 #include <stdlib.h>
16 #include <limits.h>
17 
18 /*
19  * RFC 2136 sections mapped to RFC 1035:
20  *              zone/ZO -- QD/question
21  *     prerequisites/PR -- AN/answers
22  *           updates/UP -- NS/authority records
23  *   additional data/AD -- AR/additional records
24  */
25 
26 ldns_pkt *
27 ldns_update_pkt_new(ldns_rdf *zone_rdf, ldns_rr_class c,
28     ldns_rr_list *pr_rrlist, ldns_rr_list *up_rrlist, ldns_rr_list *ad_rrlist)
29 {
30 	ldns_pkt *p;
31 
32 	if (!zone_rdf || !up_rrlist) {
33 		return NULL;
34 	}
35 
36 	if (c == 0) {
37 		c = LDNS_RR_CLASS_IN;
38 	}
39 
40 	/* Create packet, fill in Zone Section. */
41 	p = ldns_pkt_query_new(zone_rdf, LDNS_RR_TYPE_SOA, c, LDNS_RD);
42 	if (!p) {
43 		return NULL;
44 	}
45 	zone_rdf = NULL; /* No longer safe to use. */
46 
47 	ldns_pkt_set_opcode(p, LDNS_PACKET_UPDATE);
48 
49 	ldns_rr_list_deep_free(p->_authority);
50 
51 	ldns_pkt_set_authority(p, ldns_rr_list_clone(up_rrlist));
52 
53 	ldns_update_set_upcount(p, ldns_rr_list_rr_count(up_rrlist));
54 
55 	if (pr_rrlist) {
56 		ldns_rr_list_deep_free(p->_answer); /*XXX access function */
57 		ldns_pkt_set_answer(p, ldns_rr_list_clone(pr_rrlist));
58 		ldns_update_set_prcount(p, ldns_rr_list_rr_count(pr_rrlist));
59 	}
60 
61 	if (ad_rrlist) {
62 		ldns_rr_list_deep_free(p->_additional);
63 		ldns_pkt_set_additional(p, ldns_rr_list_clone(ad_rrlist));
64 		ldns_update_set_adcount(p, ldns_rr_list_rr_count(ad_rrlist));
65 	}
66 	return p;
67 }
68 
69 ldns_status
70 ldns_update_pkt_tsig_add(ldns_pkt *p, ldns_resolver *r)
71 {
72 #ifdef HAVE_SSL
73 	uint16_t fudge = 300; /* Recommended fudge. [RFC2845 6.4]  */
74 	if (ldns_resolver_tsig_keyname(r) && ldns_resolver_tsig_keydata(r))
75 		return ldns_pkt_tsig_sign(p, ldns_resolver_tsig_keyname(r),
76 		    ldns_resolver_tsig_keydata(r), fudge,
77 		    ldns_resolver_tsig_algorithm(r), NULL);
78 #else
79 	/* do nothing */
80 	(void)p;
81 	(void)r;
82 #endif /* HAVE_SSL */
83 	/* No TSIG to do. */
84 	return LDNS_STATUS_OK;
85 }
86 
87 /* Move to higher.c or similar? */
88 /* XXX doc */
89 ldns_status
90 ldns_update_soa_mname(ldns_rdf *zone, ldns_resolver *r,
91     ldns_rr_class c, ldns_rdf **mname)
92 {
93 	ldns_rr		*soa_rr;
94 	ldns_pkt	*query, *resp;
95 
96 	/* Nondestructive, so clone 'zone' here */
97 	query = ldns_pkt_query_new(ldns_rdf_clone(zone), LDNS_RR_TYPE_SOA,
98 	    c, LDNS_RD);
99 	if (!query) {
100 		return LDNS_STATUS_ERR;
101 	}
102 
103 	ldns_pkt_set_random_id(query);
104 	if (ldns_resolver_send_pkt(&resp, r, query) != LDNS_STATUS_OK) {
105 		ldns_pkt_free(query);
106 		return LDNS_STATUS_ERR;
107 	}
108 	ldns_pkt_free(query);
109 	if (!resp) {
110 		return LDNS_STATUS_ERR;
111 	}
112 
113 	/* Expect a SOA answer. */
114 	*mname = NULL;
115 	while ((soa_rr = ldns_rr_list_pop_rr(ldns_pkt_answer(resp)))) {
116 		if (ldns_rr_get_type(soa_rr) != LDNS_RR_TYPE_SOA)
117 			continue;
118 		/* [RFC1035 3.3.13] */
119 		*mname = ldns_rdf_clone(ldns_rr_rdf(soa_rr, 0));
120 		break;
121 	}
122 	ldns_pkt_free(resp);
123 
124 	return *mname ? LDNS_STATUS_OK : LDNS_STATUS_ERR;
125 }
126 
127 /* Try to get zone and MNAME from SOA queries. */
128 ldns_status
129 ldns_update_soa_zone_mname(const char *fqdn, ldns_resolver *r,
130     ldns_rr_class c, ldns_rdf **zone_rdf, ldns_rdf **mname_rdf)
131 {
132 	ldns_rr		*soa_rr, *rr;
133 	ldns_rdf	*soa_zone = NULL, *soa_mname = NULL;
134 	ldns_rdf	*ipaddr, *fqdn_rdf, *tmp;
135 	ldns_rdf	**nslist;
136 	ldns_pkt	*query, *resp;
137 	size_t		i;
138 
139 	/*
140 	 * XXX Ok, this cannot be the best way to find this...?
141 	 * XXX (I run into weird cache-related stuff here)
142 	 */
143 
144 	/* Step 1 - first find a nameserver that should know *something* */
145 	fqdn_rdf = ldns_dname_new_frm_str(fqdn);
146 	query = ldns_pkt_query_new(fqdn_rdf, LDNS_RR_TYPE_SOA, c, LDNS_RD);
147 	if (!query) {
148 		return LDNS_STATUS_ERR;
149 	}
150 	fqdn_rdf = NULL;
151 
152 	ldns_pkt_set_random_id(query);
153 	if (ldns_resolver_send_pkt(&resp, r, query) != LDNS_STATUS_OK) {
154 		ldns_pkt_free(query);
155 		return LDNS_STATUS_ERR;
156 	}
157 	ldns_pkt_free(query);
158 	if (!resp) {
159 		return LDNS_STATUS_ERR;
160 	}
161 
162 	/* XXX Is it safe to only look in authority section here? */
163 	while ((soa_rr = ldns_rr_list_pop_rr(ldns_pkt_authority(resp)))) {
164 		if (ldns_rr_get_type(soa_rr) != LDNS_RR_TYPE_SOA)
165 			continue;
166 		/* [RFC1035 3.3.13] */
167 		soa_mname = ldns_rdf_clone(ldns_rr_rdf(soa_rr, 0));
168 		break;
169 	}
170 	ldns_pkt_free(resp);
171 	if (!soa_rr) {
172 		return LDNS_STATUS_ERR;
173 	}
174 
175 	/* Step 2 - find SOA MNAME IP address, add to resolver */
176 	query = ldns_pkt_query_new(soa_mname, LDNS_RR_TYPE_A, c, LDNS_RD);
177 	if (!query) {
178 		return LDNS_STATUS_ERR;
179 	}
180 	soa_mname = NULL;
181 
182 	ldns_pkt_set_random_id(query);
183 	if (ldns_resolver_send_pkt(&resp, r, query) != LDNS_STATUS_OK) {
184 		ldns_pkt_free(query);
185 		return LDNS_STATUS_ERR;
186 	}
187 	ldns_pkt_free(query);
188 	if (!resp) {
189 		return LDNS_STATUS_ERR;
190 	}
191 
192 	if (ldns_pkt_ancount(resp) == 0) {
193 		ldns_pkt_free(resp);
194 		return LDNS_STATUS_ERR;
195 	}
196 
197 	/* XXX There may be more than one answer RR here. */
198 	rr = ldns_rr_list_pop_rr(ldns_pkt_answer(resp));
199 	ipaddr = ldns_rr_rdf(rr, 0);
200 
201 	/* Put the SOA mname IP first in the nameserver list. */
202 	nslist = ldns_resolver_nameservers(r);
203 	for (i = 0; i < ldns_resolver_nameserver_count(r); i++) {
204 		if (ldns_rdf_compare(ipaddr, nslist[i]) == 0) {
205 			if (i) {
206 				tmp = nslist[0];
207 				nslist[0] = nslist[i];
208 				nslist[i] = tmp;
209 			}
210 			break;
211 		}
212 	}
213 	if (i >= ldns_resolver_nameserver_count(r)) {
214 		/* SOA mname was not part of the resolver so add it first. */
215 		(void) ldns_resolver_push_nameserver(r, ipaddr);
216 		nslist = ldns_resolver_nameservers(r);
217 		i = ldns_resolver_nameserver_count(r) - 1;
218 		tmp = nslist[0];
219 		nslist[0] = nslist[i];
220 		nslist[i] = tmp;
221 	}
222 	ldns_pkt_free(resp);
223 
224 	/* Make sure to ask the first in the list, i.e SOA mname */
225 	ldns_resolver_set_random(r, false);
226 
227 	/* Step 3 - Redo SOA query, sending to SOA MNAME directly. */
228 	fqdn_rdf = ldns_dname_new_frm_str(fqdn);
229 	query = ldns_pkt_query_new(fqdn_rdf, LDNS_RR_TYPE_SOA, c, LDNS_RD);
230 	if (!query) {
231 		return LDNS_STATUS_ERR;
232 	}
233 	fqdn_rdf = NULL;
234 
235 	ldns_pkt_set_random_id(query);
236 	if (ldns_resolver_send_pkt(&resp, r, query) != LDNS_STATUS_OK) {
237 		ldns_pkt_free(query);
238 		return LDNS_STATUS_ERR;
239 	}
240 	ldns_pkt_free(query);
241 	if (!resp) {
242 		return LDNS_STATUS_ERR;
243 	}
244 
245 	/* XXX Is it safe to only look in authority section here, too? */
246 	while ((soa_rr = ldns_rr_list_pop_rr(ldns_pkt_authority(resp)))) {
247 		if (ldns_rr_get_type(soa_rr) != LDNS_RR_TYPE_SOA)
248 			continue;
249 		/* [RFC1035 3.3.13] */
250 		soa_mname = ldns_rdf_clone(ldns_rr_rdf(soa_rr, 0));
251 		soa_zone = ldns_rdf_clone(ldns_rr_owner(soa_rr));
252 		break;
253 	}
254 	ldns_pkt_free(resp);
255 	if (!soa_rr) {
256 		return LDNS_STATUS_ERR;
257 	}
258 
259 	/* That seems to have worked, pass results to caller. */
260 	*zone_rdf = soa_zone;
261 	*mname_rdf = soa_mname;
262 	return LDNS_STATUS_OK;
263 }
264 
265 /*
266  * ldns_update_{get,set}_{zo,pr,up,ad}count
267  */
268 
269 uint16_t
270 ldns_update_zocount(const ldns_pkt *p)
271 {
272 	return ldns_pkt_qdcount(p);
273 }
274 
275 uint16_t
276 ldns_update_prcount(const ldns_pkt *p)
277 {
278 	return ldns_pkt_ancount(p);
279 }
280 
281 uint16_t
282 ldns_update_upcount(const ldns_pkt *p)
283 {
284 	return ldns_pkt_nscount(p);
285 }
286 
287 uint16_t
288 ldns_update_ad(const ldns_pkt *p)
289 {
290 	return ldns_pkt_arcount(p);
291 }
292 
293 void
294 ldns_update_set_zo(ldns_pkt *p, uint16_t v)
295 {
296 	ldns_pkt_set_qdcount(p, v);
297 }
298 
299 void
300 ldns_update_set_prcount(ldns_pkt *p, uint16_t v)
301 {
302 	ldns_pkt_set_ancount(p, v);
303 }
304 
305 void
306 ldns_update_set_upcount(ldns_pkt *p, uint16_t v)
307 {
308 	ldns_pkt_set_nscount(p, v);
309 }
310 
311 void
312 ldns_update_set_adcount(ldns_pkt *p, uint16_t v)
313 {
314 	ldns_pkt_set_arcount(p, v);
315 }
316