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 ldns_rr_list
*pr_rrlist
, ldns_rr_list
*up_rrlist
, 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
, 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
;
141 * XXX Ok, this cannot be the best way to find this...?
142 * XXX (I run into weird cache-related stuff here)
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
);
149 return LDNS_STATUS_ERR
;
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
;
158 ldns_pkt_free(query
);
160 return LDNS_STATUS_ERR
;
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
)
168 /* [RFC1035 3.3.13] */
169 soa_mname
= ldns_rdf_clone(ldns_rr_rdf(soa_rr
, 0));
174 return LDNS_STATUS_ERR
;
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
);
180 return LDNS_STATUS_ERR
;
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
;
189 ldns_pkt_free(query
);
191 return LDNS_STATUS_ERR
;
194 if (ldns_pkt_ancount(resp
) == 0) {
196 return LDNS_STATUS_ERR
;
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);
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) {
209 nslist
[0] = nslist
[i
];
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;
221 nslist
[0] = nslist
[i
];
226 /* Make sure to ask the first in the list, i.e SOA mname */
227 ldns_resolver_set_random(r
, false);
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
);
233 return LDNS_STATUS_ERR
;
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
;
242 ldns_pkt_free(query
);
244 return LDNS_STATUS_ERR
;
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
)
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
));
259 return LDNS_STATUS_ERR
;
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
;
269 * ldns_update_{get,set}_{zo,pr,up,ad}count
273 ldns_update_zocount(const ldns_pkt
*p
)
275 return ldns_pkt_qdcount(p
);
279 ldns_update_prcount(const ldns_pkt
*p
)
281 return ldns_pkt_ancount(p
);
285 ldns_update_upcount(const ldns_pkt
*p
)
287 return ldns_pkt_nscount(p
);
291 ldns_update_ad(const ldns_pkt
*p
)
293 return ldns_pkt_arcount(p
);
297 ldns_update_set_zo(ldns_pkt
*p
, uint16_t v
)
299 ldns_pkt_set_qdcount(p
, v
);
303 ldns_update_set_prcount(ldns_pkt
*p
, uint16_t v
)
305 ldns_pkt_set_ancount(p
, v
);
309 ldns_update_set_upcount(ldns_pkt
*p
, uint16_t v
)
311 ldns_pkt_set_nscount(p
, v
);
315 ldns_update_set_adcount(ldns_pkt
*p
, uint16_t v
)
317 ldns_pkt_set_arcount(p
, v
);