root/tools/iphone-sdk/trunk/ldns_sources/update.c
@
81
| Revision 32, 7.2 kB (checked in by kjaleel, 5 years ago) |
|---|
| Line | |
|---|---|
| 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.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 class, |
| 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 (class == 0) { |
| 37 | class = 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, class, 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 class, 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 | class, 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 class, 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, class, 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, class, 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, class, 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 | } |
Note: See TracBrowser
for help on using the browser.








