xref: /freebsd/contrib/ldns/update.c (revision 640235e2c2ba32947f7c59d168437ffa1280f1e6)
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 				|| ldns_rr_rdf(soa_rr, 0) == NULL)
118 			continue;
119 		/* [RFC1035 3.3.13] */
120 		*mname = ldns_rdf_clone(ldns_rr_rdf(soa_rr, 0));
121 		break;
122 	}
123 	ldns_pkt_free(resp);
124 
125 	return *mname ? LDNS_STATUS_OK : LDNS_STATUS_ERR;
126 }
127 
128 /* Try to get zone and MNAME from SOA queries. */
129 ldns_status
130 ldns_update_soa_zone_mname(const char *fqdn, ldns_resolver *r,
131     ldns_rr_class c, ldns_rdf **zone_rdf, ldns_rdf **mname_rdf)
132 {
133 	ldns_rr		*soa_rr, *rr;
134 	ldns_rdf	*soa_zone = NULL, *soa_mname = NULL;
135 	ldns_rdf	*ipaddr, *fqdn_rdf, *tmp;
136 	ldns_rdf	**nslist;
137 	ldns_pkt	*query, *resp;
138 	size_t		i;
139 
140 	/*
141 	 * XXX Ok, this cannot be the best way to find this...?
142 	 * XXX (I run into weird cache-related stuff here)
143 	 */
144 
145 	/* Step 1 - first find a nameserver that should know *something* */
146 	fqdn_rdf = ldns_dname_new_frm_str(fqdn);
147 	query = ldns_pkt_query_new(fqdn_rdf, LDNS_RR_TYPE_SOA, c, LDNS_RD);
148 	if (!query) {
149 		return LDNS_STATUS_ERR;
150 	}
151 	fqdn_rdf = NULL;
152 
153 	ldns_pkt_set_random_id(query);
154 	if (ldns_resolver_send_pkt(&resp, r, query) != LDNS_STATUS_OK) {
155 		ldns_pkt_free(query);
156 		return LDNS_STATUS_ERR;
157 	}
158 	ldns_pkt_free(query);
159 	if (!resp) {
160 		return LDNS_STATUS_ERR;
161 	}
162 
163 	/* XXX Is it safe to only look in authority section here? */
164 	while ((soa_rr = ldns_rr_list_pop_rr(ldns_pkt_authority(resp)))) {
165 		if (ldns_rr_get_type(soa_rr) != LDNS_RR_TYPE_SOA
166 				|| ldns_rr_rdf(soa_rr, 0) == NULL)
167 			continue;
168 		/* [RFC1035 3.3.13] */
169 		soa_mname = ldns_rdf_clone(ldns_rr_rdf(soa_rr, 0));
170 		break;
171 	}
172 	ldns_pkt_free(resp);
173 	if (!soa_rr) {
174 		return LDNS_STATUS_ERR;
175 	}
176 
177 	/* Step 2 - find SOA MNAME IP address, add to resolver */
178 	query = ldns_pkt_query_new(soa_mname, LDNS_RR_TYPE_A, c, LDNS_RD);
179 	if (!query) {
180 		return LDNS_STATUS_ERR;
181 	}
182 	soa_mname = NULL;
183 
184 	ldns_pkt_set_random_id(query);
185 	if (ldns_resolver_send_pkt(&resp, r, query) != LDNS_STATUS_OK) {
186 		ldns_pkt_free(query);
187 		return LDNS_STATUS_ERR;
188 	}
189 	ldns_pkt_free(query);
190 	if (!resp) {
191 		return LDNS_STATUS_ERR;
192 	}
193 
194 	if (ldns_pkt_ancount(resp) == 0) {
195 		ldns_pkt_free(resp);
196 		return LDNS_STATUS_ERR;
197 	}
198 
199 	/* XXX There may be more than one answer RR here. */
200 	rr = ldns_rr_list_pop_rr(ldns_pkt_answer(resp));
201 	ipaddr = ldns_rr_rdf(rr, 0);
202 
203 	/* Put the SOA mname IP first in the nameserver list. */
204 	nslist = ldns_resolver_nameservers(r);
205 	for (i = 0; i < ldns_resolver_nameserver_count(r); i++) {
206 		if (ldns_rdf_compare(ipaddr, nslist[i]) == 0) {
207 			if (i) {
208 				tmp = nslist[0];
209 				nslist[0] = nslist[i];
210 				nslist[i] = tmp;
211 			}
212 			break;
213 		}
214 	}
215 	if (i >= ldns_resolver_nameserver_count(r)) {
216 		/* SOA mname was not part of the resolver so add it first. */
217 		(void) ldns_resolver_push_nameserver(r, ipaddr);
218 		nslist = ldns_resolver_nameservers(r);
219 		i = ldns_resolver_nameserver_count(r) - 1;
220 		tmp = nslist[0];
221 		nslist[0] = nslist[i];
222 		nslist[i] = tmp;
223 	}
224 	ldns_pkt_free(resp);
225 
226 	/* Make sure to ask the first in the list, i.e SOA mname */
227 	ldns_resolver_set_random(r, false);
228 
229 	/* Step 3 - Redo SOA query, sending to SOA MNAME directly. */
230 	fqdn_rdf = ldns_dname_new_frm_str(fqdn);
231 	query = ldns_pkt_query_new(fqdn_rdf, LDNS_RR_TYPE_SOA, c, LDNS_RD);
232 	if (!query) {
233 		return LDNS_STATUS_ERR;
234 	}
235 	fqdn_rdf = NULL;
236 
237 	ldns_pkt_set_random_id(query);
238 	if (ldns_resolver_send_pkt(&resp, r, query) != LDNS_STATUS_OK) {
239 		ldns_pkt_free(query);
240 		return LDNS_STATUS_ERR;
241 	}
242 	ldns_pkt_free(query);
243 	if (!resp) {
244 		return LDNS_STATUS_ERR;
245 	}
246 
247 	/* XXX Is it safe to only look in authority section here, too? */
248 	while ((soa_rr = ldns_rr_list_pop_rr(ldns_pkt_authority(resp)))) {
249 		if (ldns_rr_get_type(soa_rr) != LDNS_RR_TYPE_SOA
250 				|| ldns_rr_rdf(soa_rr, 0) == NULL)
251 			continue;
252 		/* [RFC1035 3.3.13] */
253 		soa_mname = ldns_rdf_clone(ldns_rr_rdf(soa_rr, 0));
254 		soa_zone = ldns_rdf_clone(ldns_rr_owner(soa_rr));
255 		break;
256 	}
257 	ldns_pkt_free(resp);
258 	if (!soa_rr) {
259 		return LDNS_STATUS_ERR;
260 	}
261 
262 	/* That seems to have worked, pass results to caller. */
263 	*zone_rdf = soa_zone;
264 	*mname_rdf = soa_mname;
265 	return LDNS_STATUS_OK;
266 }
267 
268 /*
269  * ldns_update_{get,set}_{zo,pr,up,ad}count
270  */
271 
272 uint16_t
273 ldns_update_zocount(const ldns_pkt *p)
274 {
275 	return ldns_pkt_qdcount(p);
276 }
277 
278 uint16_t
279 ldns_update_prcount(const ldns_pkt *p)
280 {
281 	return ldns_pkt_ancount(p);
282 }
283 
284 uint16_t
285 ldns_update_upcount(const ldns_pkt *p)
286 {
287 	return ldns_pkt_nscount(p);
288 }
289 
290 uint16_t
291 ldns_update_ad(const ldns_pkt *p)
292 {
293 	return ldns_pkt_arcount(p);
294 }
295 
296 void
297 ldns_update_set_zo(ldns_pkt *p, uint16_t v)
298 {
299 	ldns_pkt_set_qdcount(p, v);
300 }
301 
302 void
303 ldns_update_set_prcount(ldns_pkt *p, uint16_t v)
304 {
305 	ldns_pkt_set_ancount(p, v);
306 }
307 
308 void
309 ldns_update_set_upcount(ldns_pkt *p, uint16_t v)
310 {
311 	ldns_pkt_set_nscount(p, v);
312 }
313 
314 void
315 ldns_update_set_adcount(ldns_pkt *p, uint16_t v)
316 {
317 	ldns_pkt_set_arcount(p, v);
318 }
319