3 * Functions for RFC 2136 Dynamic Update
5 * Copyright (c) 2005-2008, NLnet Labs. All rights reserved.
7 * See LICENSE for the license.
10 #include <ldns/config.h>
12 #include <ldns/ldns.h>
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
27 ldns_update_pkt_new(ldns_rdf
*zone_rdf
, ldns_rr_class c
,
28 const ldns_rr_list
*pr_rrlist
, const ldns_rr_list
*up_rrlist
, const ldns_rr_list
*ad_rrlist
)
32 if (!zone_rdf
|| !up_rrlist
) {
40 /* Create packet, fill in Zone Section. */
41 p
= ldns_pkt_query_new(zone_rdf
, LDNS_RR_TYPE_SOA
, c
, LDNS_RD
);
45 zone_rdf
= NULL
; /* No longer safe to use. */
47 ldns_pkt_set_opcode(p
, LDNS_PACKET_UPDATE
);
49 ldns_rr_list_deep_free(p
->_authority
);
51 ldns_pkt_set_authority(p
, ldns_rr_list_clone(up_rrlist
));
53 ldns_update_set_upcount(p
, ldns_rr_list_rr_count(up_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
));
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
));
70 ldns_update_pkt_tsig_add(ldns_pkt
*p
, const ldns_resolver
*r
)
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
);
84 return LDNS_STATUS_OK
;
87 /* Move to higher.c or similar? */
90 ldns_update_soa_mname(ldns_rdf
*zone
, ldns_resolver
*r
,
91 ldns_rr_class c
, ldns_rdf
**mname
)
94 ldns_pkt
*query
, *resp
;
96 /* Nondestructive, so clone 'zone' here */
97 query
= ldns_pkt_query_new(ldns_rdf_clone(zone
), LDNS_RR_TYPE_SOA
,
100 return LDNS_STATUS_ERR
;
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
;
108 ldns_pkt_free(query
);
110 return LDNS_STATUS_ERR
;
113 /* Expect a SOA answer. */
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
)
119 /* [RFC1035 3.3.13] */
120 *mname
= ldns_rdf_clone(ldns_rr_rdf(soa_rr
, 0));
125 return *mname
? LDNS_STATUS_OK
: LDNS_STATUS_ERR
;
128 /* Try to get zone and MNAME from SOA queries. */
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
)
133 ldns_rr
*soa_rr
, *rr
;
134 ldns_rdf
*soa_zone
= NULL
, *soa_mname
= NULL
;
135 ldns_rdf
*ipaddr
, *fqdn_rdf
, *tmp
;
137 ldns_pkt
*query
, *resp
;
138 ldns_resolver
*tmp_r
;
142 * XXX Ok, this cannot be the best way to find this...?
143 * XXX (I run into weird cache-related stuff here)
146 /* Step 1 - first find a nameserver that should know *something* */
147 fqdn_rdf
= ldns_dname_new_frm_str(fqdn
);
148 query
= ldns_pkt_query_new(fqdn_rdf
, LDNS_RR_TYPE_SOA
, c
, LDNS_RD
);
150 return LDNS_STATUS_ERR
;
154 ldns_pkt_set_random_id(query
);
155 if (ldns_resolver_send_pkt(&resp
, r
, query
) != LDNS_STATUS_OK
) {
156 ldns_pkt_free(query
);
157 return LDNS_STATUS_ERR
;
159 ldns_pkt_free(query
);
161 return LDNS_STATUS_ERR
;
164 /* XXX Is it safe to only look in authority section here? */
165 while ((soa_rr
= ldns_rr_list_pop_rr(ldns_pkt_authority(resp
)))) {
166 if (ldns_rr_get_type(soa_rr
) != LDNS_RR_TYPE_SOA
167 || ldns_rr_rdf(soa_rr
, 0) == NULL
)
169 /* [RFC1035 3.3.13] */
170 soa_mname
= ldns_rdf_clone(ldns_rr_rdf(soa_rr
, 0));
175 return LDNS_STATUS_ERR
;
178 /* Step 2 - find SOA MNAME IP address, add to resolver */
179 query
= ldns_pkt_query_new(soa_mname
, LDNS_RR_TYPE_A
, c
, LDNS_RD
);
181 return LDNS_STATUS_ERR
;
185 ldns_pkt_set_random_id(query
);
186 if (ldns_resolver_send_pkt(&resp
, r
, query
) != LDNS_STATUS_OK
) {
187 ldns_pkt_free(query
);
188 return LDNS_STATUS_ERR
;
190 ldns_pkt_free(query
);
192 return LDNS_STATUS_ERR
;
195 if (ldns_pkt_ancount(resp
) == 0) {
197 return LDNS_STATUS_ERR
;
200 /* XXX There may be more than one answer RR here. */
201 rr
= ldns_rr_list_pop_rr(ldns_pkt_answer(resp
));
202 ipaddr
= ldns_rr_rdf(rr
, 0);
204 /* Put the SOA mname IP first in the nameserver list. */
205 if (!(tmp_r
= ldns_resolver_clone(r
))) {
206 return LDNS_STATUS_MEM_ERR
;
208 nslist
= ldns_resolver_nameservers(tmp_r
);
209 for (i
= 0; i
< ldns_resolver_nameserver_count(tmp_r
); i
++) {
210 if (ldns_rdf_compare(ipaddr
, nslist
[i
]) == 0) {
213 nslist
[0] = nslist
[i
];
219 if (i
>= ldns_resolver_nameserver_count(tmp_r
)) {
220 /* SOA mname was not part of the resolver so add it first. */
221 (void) ldns_resolver_push_nameserver(tmp_r
, ipaddr
);
222 nslist
= ldns_resolver_nameservers(tmp_r
);
223 i
= ldns_resolver_nameserver_count(tmp_r
) - 1;
225 nslist
[0] = nslist
[i
];
230 /* Make sure to ask the first in the list, i.e SOA mname */
231 ldns_resolver_set_random(tmp_r
, false);
233 /* Step 3 - Redo SOA query, sending to SOA MNAME directly. */
234 fqdn_rdf
= ldns_dname_new_frm_str(fqdn
);
235 query
= ldns_pkt_query_new(fqdn_rdf
, LDNS_RR_TYPE_SOA
, c
, LDNS_RD
);
237 ldns_resolver_free(tmp_r
);
238 return LDNS_STATUS_ERR
;
242 ldns_pkt_set_random_id(query
);
243 if (ldns_resolver_send_pkt(&resp
, tmp_r
, query
) != LDNS_STATUS_OK
) {
244 ldns_pkt_free(query
);
245 ldns_resolver_free(tmp_r
);
246 return LDNS_STATUS_ERR
;
248 ldns_resolver_free(tmp_r
);
249 ldns_pkt_free(query
);
251 return LDNS_STATUS_ERR
;
254 /* XXX Is it safe to only look in authority section here, too? */
255 while ((soa_rr
= ldns_rr_list_pop_rr(ldns_pkt_authority(resp
)))) {
256 if (ldns_rr_get_type(soa_rr
) != LDNS_RR_TYPE_SOA
257 || ldns_rr_rdf(soa_rr
, 0) == NULL
)
259 /* [RFC1035 3.3.13] */
260 soa_mname
= ldns_rdf_clone(ldns_rr_rdf(soa_rr
, 0));
261 soa_zone
= ldns_rdf_clone(ldns_rr_owner(soa_rr
));
266 return LDNS_STATUS_ERR
;
269 /* That seems to have worked, pass results to caller. */
270 *zone_rdf
= soa_zone
;
271 *mname_rdf
= soa_mname
;
272 return LDNS_STATUS_OK
;
276 * ldns_update_{get,set}_{zo,pr,up,ad}count
280 ldns_update_zocount(const ldns_pkt
*p
)
282 return ldns_pkt_qdcount(p
);
286 ldns_update_prcount(const ldns_pkt
*p
)
288 return ldns_pkt_ancount(p
);
292 ldns_update_upcount(const ldns_pkt
*p
)
294 return ldns_pkt_nscount(p
);
298 ldns_update_ad(const ldns_pkt
*p
)
300 return ldns_pkt_arcount(p
);
304 ldns_update_set_zo(ldns_pkt
*p
, uint16_t v
)
306 ldns_pkt_set_qdcount(p
, v
);
310 ldns_update_set_prcount(ldns_pkt
*p
, uint16_t v
)
312 ldns_pkt_set_ancount(p
, v
);
316 ldns_update_set_upcount(ldns_pkt
*p
, uint16_t v
)
318 ldns_pkt_set_nscount(p
, v
);
322 ldns_update_set_adcount(ldns_pkt
*p
, uint16_t v
)
324 ldns_pkt_set_arcount(p
, v
);