1 /* 2 * util/data/msgreply.c - store message and reply data. 3 * 4 * Copyright (c) 2007, NLnet Labs. All rights reserved. 5 * 6 * This software is open source. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 19 * Neither the name of the NLNET LABS nor the names of its contributors may 20 * be used to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /** 37 * \file 38 * 39 * This file contains a data structure to store a message and its reply. 40 */ 41 42 #include "config.h" 43 #include "util/data/msgreply.h" 44 #include "util/storage/lookup3.h" 45 #include "util/log.h" 46 #include "util/alloc.h" 47 #include "util/netevent.h" 48 #include "util/net_help.h" 49 #include "util/data/dname.h" 50 #include "util/regional.h" 51 #include "util/data/msgparse.h" 52 #include "util/data/msgencode.h" 53 #include "sldns/sbuffer.h" 54 #include "sldns/wire2str.h" 55 #include "util/module.h" 56 #include "util/fptr_wlist.h" 57 58 /** MAX TTL default for messages and rrsets */ 59 time_t MAX_TTL = 3600 * 24 * 10; /* ten days */ 60 /** MIN TTL default for messages and rrsets */ 61 time_t MIN_TTL = 0; 62 /** MAX Negative TTL, for SOA records in authority section */ 63 time_t MAX_NEG_TTL = 3600; /* one hour */ 64 /** If we serve expired entries and prefetch them */ 65 int SERVE_EXPIRED = 0; 66 /** Time to serve records after expiration */ 67 time_t SERVE_EXPIRED_TTL = 0; 68 /** TTL to use for expired records */ 69 time_t SERVE_EXPIRED_REPLY_TTL = 30; 70 /** If we serve the original TTL or decrementing TTLs */ 71 int SERVE_ORIGINAL_TTL = 0; 72 73 /** allocate qinfo, return 0 on error */ 74 static int 75 parse_create_qinfo(sldns_buffer* pkt, struct msg_parse* msg, 76 struct query_info* qinf, struct regional* region) 77 { 78 if(msg->qname) { 79 if(region) 80 qinf->qname = (uint8_t*)regional_alloc(region, 81 msg->qname_len); 82 else qinf->qname = (uint8_t*)malloc(msg->qname_len); 83 if(!qinf->qname) return 0; 84 dname_pkt_copy(pkt, qinf->qname, msg->qname); 85 } else qinf->qname = 0; 86 qinf->qname_len = msg->qname_len; 87 qinf->qtype = msg->qtype; 88 qinf->qclass = msg->qclass; 89 qinf->local_alias = NULL; 90 return 1; 91 } 92 93 /** constructor for replyinfo */ 94 struct reply_info* 95 construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd, 96 time_t ttl, time_t prettl, time_t expttl, size_t an, size_t ns, 97 size_t ar, size_t total, enum sec_status sec) 98 { 99 struct reply_info* rep; 100 /* rrset_count-1 because the first ref is part of the struct. */ 101 size_t s = sizeof(struct reply_info) - sizeof(struct rrset_ref) + 102 sizeof(struct ub_packed_rrset_key*) * total; 103 if(total >= RR_COUNT_MAX) return NULL; /* sanity check on numRRS*/ 104 if(region) 105 rep = (struct reply_info*)regional_alloc(region, s); 106 else rep = (struct reply_info*)malloc(s + 107 sizeof(struct rrset_ref) * (total)); 108 if(!rep) 109 return NULL; 110 rep->flags = flags; 111 rep->qdcount = qd; 112 rep->ttl = ttl; 113 rep->prefetch_ttl = prettl; 114 rep->serve_expired_ttl = expttl; 115 rep->an_numrrsets = an; 116 rep->ns_numrrsets = ns; 117 rep->ar_numrrsets = ar; 118 rep->rrset_count = total; 119 rep->security = sec; 120 rep->reason_bogus = LDNS_EDE_NONE; 121 rep->authoritative = 0; 122 /* array starts after the refs */ 123 if(region) 124 rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[0]); 125 else rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[total]); 126 /* zero the arrays to assist cleanup in case of malloc failure */ 127 memset( rep->rrsets, 0, sizeof(struct ub_packed_rrset_key*) * total); 128 if(!region) 129 memset( &rep->ref[0], 0, sizeof(struct rrset_ref) * total); 130 return rep; 131 } 132 133 /** allocate replyinfo, return 0 on error */ 134 static int 135 parse_create_repinfo(struct msg_parse* msg, struct reply_info** rep, 136 struct regional* region) 137 { 138 *rep = construct_reply_info_base(region, msg->flags, msg->qdcount, 0, 139 0, 0, msg->an_rrsets, msg->ns_rrsets, msg->ar_rrsets, 140 msg->rrset_count, sec_status_unchecked); 141 if(!*rep) 142 return 0; 143 return 1; 144 } 145 146 int 147 reply_info_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc, 148 struct regional* region) 149 { 150 size_t i; 151 for(i=0; i<rep->rrset_count; i++) { 152 if(region) { 153 rep->rrsets[i] = (struct ub_packed_rrset_key*) 154 regional_alloc(region, 155 sizeof(struct ub_packed_rrset_key)); 156 if(rep->rrsets[i]) { 157 memset(rep->rrsets[i], 0, 158 sizeof(struct ub_packed_rrset_key)); 159 rep->rrsets[i]->entry.key = rep->rrsets[i]; 160 } 161 } 162 else rep->rrsets[i] = alloc_special_obtain(alloc); 163 if(!rep->rrsets[i]) 164 return 0; 165 rep->rrsets[i]->entry.data = NULL; 166 } 167 return 1; 168 } 169 170 struct reply_info * 171 make_new_reply_info(const struct reply_info* rep, struct regional* region, 172 size_t an_numrrsets, size_t copy_rrsets) 173 { 174 struct reply_info* new_rep; 175 size_t i; 176 177 /* create a base struct. we specify 'insecure' security status as 178 * the modified response won't be DNSSEC-valid. In our faked response 179 * the authority and additional sections will be empty (except possible 180 * EDNS0 OPT RR in the additional section appended on sending it out), 181 * so the total number of RRsets is an_numrrsets. */ 182 new_rep = construct_reply_info_base(region, rep->flags, 183 rep->qdcount, rep->ttl, rep->prefetch_ttl, 184 rep->serve_expired_ttl, an_numrrsets, 0, 0, an_numrrsets, 185 sec_status_insecure); 186 if(!new_rep) 187 return NULL; 188 if(!reply_info_alloc_rrset_keys(new_rep, NULL, region)) 189 return NULL; 190 for(i=0; i<copy_rrsets; i++) 191 new_rep->rrsets[i] = rep->rrsets[i]; 192 193 return new_rep; 194 } 195 196 /** find the minimumttl in the rdata of SOA record */ 197 static time_t 198 soa_find_minttl(struct rr_parse* rr) 199 { 200 uint16_t rlen = sldns_read_uint16(rr->ttl_data+4); 201 if(rlen < 20) 202 return 0; /* rdata too small for SOA (dname, dname, 5*32bit) */ 203 /* minimum TTL is the last 32bit value in the rdata of the record */ 204 /* at position ttl_data + 4(ttl) + 2(rdatalen) + rdatalen - 4(timeval)*/ 205 return (time_t)sldns_read_uint32(rr->ttl_data+6+rlen-4); 206 } 207 208 /** do the rdata copy */ 209 static int 210 rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, 211 struct rr_parse* rr, time_t* rr_ttl, uint16_t type, 212 sldns_pkt_section section) 213 { 214 uint16_t pkt_len; 215 const sldns_rr_descriptor* desc; 216 217 *rr_ttl = sldns_read_uint32(rr->ttl_data); 218 /* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */ 219 if(*rr_ttl & 0x80000000U) 220 *rr_ttl = 0; 221 if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) { 222 /* negative response. see if TTL of SOA record larger than the 223 * minimum-ttl in the rdata of the SOA record */ 224 if(*rr_ttl > soa_find_minttl(rr)) 225 *rr_ttl = soa_find_minttl(rr); 226 } 227 if(!SERVE_ORIGINAL_TTL && (*rr_ttl < MIN_TTL)) 228 *rr_ttl = MIN_TTL; 229 if(!SERVE_ORIGINAL_TTL && (*rr_ttl > MAX_TTL)) 230 *rr_ttl = MAX_TTL; 231 if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) { 232 /* max neg ttl overrides the min and max ttl of everything 233 * else, it is for a more specific record */ 234 if(*rr_ttl > MAX_NEG_TTL) 235 *rr_ttl = MAX_NEG_TTL; 236 } 237 if(*rr_ttl < data->ttl) 238 data->ttl = *rr_ttl; 239 240 if(rr->outside_packet) { 241 /* uncompressed already, only needs copy */ 242 memmove(to, rr->ttl_data+sizeof(uint32_t), rr->size); 243 return 1; 244 } 245 246 sldns_buffer_set_position(pkt, (size_t) 247 (rr->ttl_data - sldns_buffer_begin(pkt) + sizeof(uint32_t))); 248 /* insert decompressed size into rdata len stored in memory */ 249 /* -2 because rdatalen bytes are not included. */ 250 pkt_len = htons(rr->size - 2); 251 memmove(to, &pkt_len, sizeof(uint16_t)); 252 to += 2; 253 /* read packet rdata len */ 254 pkt_len = sldns_buffer_read_u16(pkt); 255 if(sldns_buffer_remaining(pkt) < pkt_len) 256 return 0; 257 desc = sldns_rr_descript(type); 258 if(pkt_len > 0 && desc && desc->_dname_count > 0) { 259 int count = (int)desc->_dname_count; 260 int rdf = 0; 261 size_t len; 262 size_t oldpos; 263 /* decompress dnames. */ 264 while(pkt_len > 0 && count) { 265 switch(desc->_wireformat[rdf]) { 266 case LDNS_RDF_TYPE_DNAME: 267 oldpos = sldns_buffer_position(pkt); 268 dname_pkt_copy(pkt, to, 269 sldns_buffer_current(pkt)); 270 to += pkt_dname_len(pkt); 271 pkt_len -= sldns_buffer_position(pkt)-oldpos; 272 count--; 273 len = 0; 274 break; 275 case LDNS_RDF_TYPE_STR: 276 len = sldns_buffer_current(pkt)[0] + 1; 277 break; 278 default: 279 len = get_rdf_size(desc->_wireformat[rdf]); 280 break; 281 } 282 if(len) { 283 log_assert(len <= pkt_len); 284 memmove(to, sldns_buffer_current(pkt), len); 285 to += len; 286 sldns_buffer_skip(pkt, (ssize_t)len); 287 pkt_len -= len; 288 } 289 rdf++; 290 } 291 } 292 /* copy remaining rdata */ 293 if(pkt_len > 0) 294 memmove(to, sldns_buffer_current(pkt), pkt_len); 295 296 return 1; 297 } 298 299 /** copy over the data into packed rrset */ 300 static int 301 parse_rr_copy(sldns_buffer* pkt, struct rrset_parse* pset, 302 struct packed_rrset_data* data) 303 { 304 size_t i; 305 struct rr_parse* rr = pset->rr_first; 306 uint8_t* nextrdata; 307 size_t total = pset->rr_count + pset->rrsig_count; 308 data->ttl = MAX_TTL; 309 data->count = pset->rr_count; 310 data->rrsig_count = pset->rrsig_count; 311 data->trust = rrset_trust_none; 312 data->security = sec_status_unchecked; 313 /* layout: struct - rr_len - rr_data - rr_ttl - rdata - rrsig */ 314 data->rr_len = (size_t*)((uint8_t*)data + 315 sizeof(struct packed_rrset_data)); 316 data->rr_data = (uint8_t**)&(data->rr_len[total]); 317 data->rr_ttl = (time_t*)&(data->rr_data[total]); 318 nextrdata = (uint8_t*)&(data->rr_ttl[total]); 319 for(i=0; i<data->count; i++) { 320 data->rr_len[i] = rr->size; 321 data->rr_data[i] = nextrdata; 322 nextrdata += rr->size; 323 if(!rdata_copy(pkt, data, data->rr_data[i], rr, 324 &data->rr_ttl[i], pset->type, pset->section)) 325 return 0; 326 rr = rr->next; 327 } 328 /* if rrsig, its rdata is at nextrdata */ 329 rr = pset->rrsig_first; 330 for(i=data->count; i<total; i++) { 331 data->rr_len[i] = rr->size; 332 data->rr_data[i] = nextrdata; 333 nextrdata += rr->size; 334 if(!rdata_copy(pkt, data, data->rr_data[i], rr, 335 &data->rr_ttl[i], LDNS_RR_TYPE_RRSIG, pset->section)) 336 return 0; 337 rr = rr->next; 338 } 339 return 1; 340 } 341 342 /** create rrset return 0 on failure */ 343 static int 344 parse_create_rrset(sldns_buffer* pkt, struct rrset_parse* pset, 345 struct packed_rrset_data** data, struct regional* region) 346 { 347 /* allocate */ 348 size_t s; 349 if(pset->rr_count > RR_COUNT_MAX || pset->rrsig_count > RR_COUNT_MAX || 350 pset->size > RR_COUNT_MAX) 351 return 0; /* protect against integer overflow */ 352 s = sizeof(struct packed_rrset_data) + 353 (pset->rr_count + pset->rrsig_count) * 354 (sizeof(size_t)+sizeof(uint8_t*)+sizeof(time_t)) + 355 pset->size; 356 if(region) 357 *data = regional_alloc_zero(region, s); 358 else *data = calloc(1, s); 359 if(!*data) 360 return 0; 361 /* copy & decompress */ 362 if(!parse_rr_copy(pkt, pset, *data)) { 363 if(!region) { 364 free(*data); 365 *data = NULL; 366 } 367 return 0; 368 } 369 return 1; 370 } 371 372 /** get trust value for rrset */ 373 static enum rrset_trust 374 get_rrset_trust(struct msg_parse* msg, struct rrset_parse* rrset) 375 { 376 uint16_t AA = msg->flags & BIT_AA; 377 if(rrset->section == LDNS_SECTION_ANSWER) { 378 if(AA) { 379 /* RFC2181 says remainder of CNAME chain is nonauth*/ 380 if(msg->rrset_first && 381 msg->rrset_first->section==LDNS_SECTION_ANSWER 382 && msg->rrset_first->type==LDNS_RR_TYPE_CNAME){ 383 if(rrset == msg->rrset_first) 384 return rrset_trust_ans_AA; 385 else return rrset_trust_ans_noAA; 386 } 387 if(msg->rrset_first && 388 msg->rrset_first->section==LDNS_SECTION_ANSWER 389 && msg->rrset_first->type==LDNS_RR_TYPE_DNAME){ 390 if(rrset == msg->rrset_first || 391 rrset == msg->rrset_first->rrset_all_next) 392 return rrset_trust_ans_AA; 393 else return rrset_trust_ans_noAA; 394 } 395 return rrset_trust_ans_AA; 396 } 397 else return rrset_trust_ans_noAA; 398 } else if(rrset->section == LDNS_SECTION_AUTHORITY) { 399 if(AA) return rrset_trust_auth_AA; 400 else return rrset_trust_auth_noAA; 401 } else { 402 /* addit section */ 403 if(AA) return rrset_trust_add_AA; 404 else return rrset_trust_add_noAA; 405 } 406 /* NOTREACHED */ 407 return rrset_trust_none; 408 } 409 410 int 411 parse_copy_decompress_rrset(sldns_buffer* pkt, struct msg_parse* msg, 412 struct rrset_parse *pset, struct regional* region, 413 struct ub_packed_rrset_key* pk) 414 { 415 struct packed_rrset_data* data; 416 pk->rk.flags = pset->flags; 417 pk->rk.dname_len = pset->dname_len; 418 if(region) 419 pk->rk.dname = (uint8_t*)regional_alloc( 420 region, pset->dname_len); 421 else pk->rk.dname = 422 (uint8_t*)malloc(pset->dname_len); 423 if(!pk->rk.dname) 424 return 0; 425 /** copy & decompress dname */ 426 dname_pkt_copy(pkt, pk->rk.dname, pset->dname); 427 /** copy over type and class */ 428 pk->rk.type = htons(pset->type); 429 pk->rk.rrset_class = pset->rrset_class; 430 /** read data part. */ 431 if(!parse_create_rrset(pkt, pset, &data, region)) { 432 if(!region) { 433 free(pk->rk.dname); 434 pk->rk.dname = NULL; 435 } 436 return 0; 437 } 438 pk->entry.data = (void*)data; 439 pk->entry.key = (void*)pk; 440 pk->entry.hash = pset->hash; 441 data->trust = get_rrset_trust(msg, pset); 442 return 1; 443 } 444 445 /** 446 * Copy and decompress rrs 447 * @param pkt: the packet for compression pointer resolution. 448 * @param msg: the parsed message 449 * @param rep: reply info to put rrs into. 450 * @param region: if not NULL, used for allocation. 451 * @return 0 on failure. 452 */ 453 static int 454 parse_copy_decompress(sldns_buffer* pkt, struct msg_parse* msg, 455 struct reply_info* rep, struct regional* region) 456 { 457 size_t i; 458 struct rrset_parse *pset = msg->rrset_first; 459 struct packed_rrset_data* data; 460 log_assert(rep); 461 rep->ttl = MAX_TTL; 462 rep->security = sec_status_unchecked; 463 if(rep->rrset_count == 0) 464 rep->ttl = NORR_TTL; 465 466 for(i=0; i<rep->rrset_count; i++) { 467 if(!parse_copy_decompress_rrset(pkt, msg, pset, region, 468 rep->rrsets[i])) 469 return 0; 470 data = (struct packed_rrset_data*)rep->rrsets[i]->entry.data; 471 if(data->ttl < rep->ttl) 472 rep->ttl = data->ttl; 473 474 pset = pset->rrset_all_next; 475 } 476 rep->prefetch_ttl = PREFETCH_TTL_CALC(rep->ttl); 477 rep->serve_expired_ttl = rep->ttl + SERVE_EXPIRED_TTL; 478 return 1; 479 } 480 481 int 482 parse_create_msg(sldns_buffer* pkt, struct msg_parse* msg, 483 struct alloc_cache* alloc, struct query_info* qinf, 484 struct reply_info** rep, struct regional* region) 485 { 486 log_assert(pkt && msg); 487 if(!parse_create_qinfo(pkt, msg, qinf, region)) 488 return 0; 489 if(!parse_create_repinfo(msg, rep, region)) 490 return 0; 491 if(!reply_info_alloc_rrset_keys(*rep, alloc, region)) { 492 if(!region) reply_info_parsedelete(*rep, alloc); 493 return 0; 494 } 495 if(!parse_copy_decompress(pkt, msg, *rep, region)) { 496 if(!region) reply_info_parsedelete(*rep, alloc); 497 return 0; 498 } 499 return 1; 500 } 501 502 int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc, 503 struct query_info* qinf, struct reply_info** rep, 504 struct regional* region, struct edns_data* edns) 505 { 506 /* use scratch pad region-allocator during parsing. */ 507 struct msg_parse* msg; 508 int ret; 509 510 qinf->qname = NULL; 511 qinf->local_alias = NULL; 512 *rep = NULL; 513 if(!(msg = regional_alloc(region, sizeof(*msg)))) { 514 return LDNS_RCODE_SERVFAIL; 515 } 516 memset(msg, 0, sizeof(*msg)); 517 518 sldns_buffer_set_position(pkt, 0); 519 if((ret = parse_packet(pkt, msg, region)) != 0) { 520 return ret; 521 } 522 if((ret = parse_extract_edns_from_response_msg(msg, edns, region)) != 0) 523 return ret; 524 525 /* parse OK, allocate return structures */ 526 /* this also performs dname decompression */ 527 if(!parse_create_msg(pkt, msg, alloc, qinf, rep, NULL)) { 528 query_info_clear(qinf); 529 *rep = NULL; 530 return LDNS_RCODE_SERVFAIL; 531 } 532 return 0; 533 } 534 535 /** helper compare function to sort in lock order */ 536 static int 537 reply_info_sortref_cmp(const void* a, const void* b) 538 { 539 struct rrset_ref* x = (struct rrset_ref*)a; 540 struct rrset_ref* y = (struct rrset_ref*)b; 541 if(x->key < y->key) return -1; 542 if(x->key > y->key) return 1; 543 return 0; 544 } 545 546 void 547 reply_info_sortref(struct reply_info* rep) 548 { 549 qsort(&rep->ref[0], rep->rrset_count, sizeof(struct rrset_ref), 550 reply_info_sortref_cmp); 551 } 552 553 void 554 reply_info_set_ttls(struct reply_info* rep, time_t timenow) 555 { 556 size_t i, j; 557 rep->ttl += timenow; 558 rep->prefetch_ttl += timenow; 559 rep->serve_expired_ttl += timenow; 560 for(i=0; i<rep->rrset_count; i++) { 561 struct packed_rrset_data* data = (struct packed_rrset_data*) 562 rep->ref[i].key->entry.data; 563 if(i>0 && rep->ref[i].key == rep->ref[i-1].key) 564 continue; 565 data->ttl += timenow; 566 for(j=0; j<data->count + data->rrsig_count; j++) { 567 data->rr_ttl[j] += timenow; 568 } 569 data->ttl_add = timenow; 570 } 571 } 572 573 void 574 reply_info_parsedelete(struct reply_info* rep, struct alloc_cache* alloc) 575 { 576 size_t i; 577 if(!rep) 578 return; 579 /* no need to lock, since not shared in hashtables. */ 580 for(i=0; i<rep->rrset_count; i++) { 581 ub_packed_rrset_parsedelete(rep->rrsets[i], alloc); 582 } 583 free(rep); 584 } 585 586 int 587 query_info_parse(struct query_info* m, sldns_buffer* query) 588 { 589 uint8_t* q = sldns_buffer_begin(query); 590 /* minimum size: header + \0 + qtype + qclass */ 591 if(sldns_buffer_limit(query) < LDNS_HEADER_SIZE + 5) 592 return 0; 593 if((LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY && LDNS_OPCODE_WIRE(q) != 594 LDNS_PACKET_NOTIFY) || LDNS_QDCOUNT(q) != 1 || 595 sldns_buffer_position(query) != 0) 596 return 0; 597 sldns_buffer_skip(query, LDNS_HEADER_SIZE); 598 m->qname = sldns_buffer_current(query); 599 if((m->qname_len = query_dname_len(query)) == 0) 600 return 0; /* parse error */ 601 if(sldns_buffer_remaining(query) < 4) 602 return 0; /* need qtype, qclass */ 603 m->qtype = sldns_buffer_read_u16(query); 604 m->qclass = sldns_buffer_read_u16(query); 605 m->local_alias = NULL; 606 return 1; 607 } 608 609 /** tiny subroutine for msgreply_compare */ 610 #define COMPARE_IT(x, y) \ 611 if( (x) < (y) ) return -1; \ 612 else if( (x) > (y) ) return +1; \ 613 log_assert( (x) == (y) ); 614 615 int 616 query_info_compare(void* m1, void* m2) 617 { 618 struct query_info* msg1 = (struct query_info*)m1; 619 struct query_info* msg2 = (struct query_info*)m2; 620 int mc; 621 /* from most different to least different for speed */ 622 COMPARE_IT(msg1->qtype, msg2->qtype); 623 if((mc = query_dname_compare(msg1->qname, msg2->qname)) != 0) 624 return mc; 625 log_assert(msg1->qname_len == msg2->qname_len); 626 COMPARE_IT(msg1->qclass, msg2->qclass); 627 return 0; 628 #undef COMPARE_IT 629 } 630 631 void 632 query_info_clear(struct query_info* m) 633 { 634 free(m->qname); 635 m->qname = NULL; 636 } 637 638 size_t 639 msgreply_sizefunc(void* k, void* d) 640 { 641 struct msgreply_entry* q = (struct msgreply_entry*)k; 642 struct reply_info* r = (struct reply_info*)d; 643 size_t s = sizeof(struct msgreply_entry) + sizeof(struct reply_info) 644 + q->key.qname_len + lock_get_mem(&q->entry.lock) 645 - sizeof(struct rrset_ref); 646 s += r->rrset_count * sizeof(struct rrset_ref); 647 s += r->rrset_count * sizeof(struct ub_packed_rrset_key*); 648 return s; 649 } 650 651 void 652 query_entry_delete(void *k, void* ATTR_UNUSED(arg)) 653 { 654 struct msgreply_entry* q = (struct msgreply_entry*)k; 655 lock_rw_destroy(&q->entry.lock); 656 query_info_clear(&q->key); 657 free(q); 658 } 659 660 void 661 reply_info_delete(void* d, void* ATTR_UNUSED(arg)) 662 { 663 struct reply_info* r = (struct reply_info*)d; 664 free(r); 665 } 666 667 hashvalue_type 668 query_info_hash(struct query_info *q, uint16_t flags) 669 { 670 hashvalue_type h = 0xab; 671 h = hashlittle(&q->qtype, sizeof(q->qtype), h); 672 if(q->qtype == LDNS_RR_TYPE_AAAA && (flags&BIT_CD)) 673 h++; 674 h = hashlittle(&q->qclass, sizeof(q->qclass), h); 675 h = dname_query_hash(q->qname, h); 676 return h; 677 } 678 679 struct msgreply_entry* 680 query_info_entrysetup(struct query_info* q, struct reply_info* r, 681 hashvalue_type h) 682 { 683 struct msgreply_entry* e = (struct msgreply_entry*)malloc( 684 sizeof(struct msgreply_entry)); 685 if(!e) return NULL; 686 memcpy(&e->key, q, sizeof(*q)); 687 e->entry.hash = h; 688 e->entry.key = e; 689 e->entry.data = r; 690 lock_rw_init(&e->entry.lock); 691 lock_protect(&e->entry.lock, &e->key.qname, sizeof(e->key.qname)); 692 lock_protect(&e->entry.lock, &e->key.qname_len, sizeof(e->key.qname_len)); 693 lock_protect(&e->entry.lock, &e->key.qtype, sizeof(e->key.qtype)); 694 lock_protect(&e->entry.lock, &e->key.qclass, sizeof(e->key.qclass)); 695 lock_protect(&e->entry.lock, &e->key.local_alias, sizeof(e->key.local_alias)); 696 lock_protect(&e->entry.lock, &e->entry.hash, sizeof(e->entry.hash)); 697 lock_protect(&e->entry.lock, &e->entry.key, sizeof(e->entry.key)); 698 lock_protect(&e->entry.lock, &e->entry.data, sizeof(e->entry.data)); 699 lock_protect(&e->entry.lock, e->key.qname, e->key.qname_len); 700 q->qname = NULL; 701 return e; 702 } 703 704 /** copy rrsets from replyinfo to dest replyinfo */ 705 static int 706 repinfo_copy_rrsets(struct reply_info* dest, struct reply_info* from, 707 struct regional* region) 708 { 709 size_t i, s; 710 struct packed_rrset_data* fd, *dd; 711 struct ub_packed_rrset_key* fk, *dk; 712 for(i=0; i<dest->rrset_count; i++) { 713 fk = from->rrsets[i]; 714 dk = dest->rrsets[i]; 715 fd = (struct packed_rrset_data*)fk->entry.data; 716 dk->entry.hash = fk->entry.hash; 717 dk->rk = fk->rk; 718 if(region) { 719 dk->id = fk->id; 720 dk->rk.dname = (uint8_t*)regional_alloc_init(region, 721 fk->rk.dname, fk->rk.dname_len); 722 } else 723 dk->rk.dname = (uint8_t*)memdup(fk->rk.dname, 724 fk->rk.dname_len); 725 if(!dk->rk.dname) 726 return 0; 727 s = packed_rrset_sizeof(fd); 728 if(region) 729 dd = (struct packed_rrset_data*)regional_alloc_init( 730 region, fd, s); 731 else dd = (struct packed_rrset_data*)memdup(fd, s); 732 if(!dd) 733 return 0; 734 packed_rrset_ptr_fixup(dd); 735 dk->entry.data = (void*)dd; 736 } 737 return 1; 738 } 739 740 struct reply_info* 741 reply_info_copy(struct reply_info* rep, struct alloc_cache* alloc, 742 struct regional* region) 743 { 744 struct reply_info* cp; 745 cp = construct_reply_info_base(region, rep->flags, rep->qdcount, 746 rep->ttl, rep->prefetch_ttl, rep->serve_expired_ttl, 747 rep->an_numrrsets, rep->ns_numrrsets, rep->ar_numrrsets, 748 rep->rrset_count, rep->security); 749 if(!cp) 750 return NULL; 751 /* allocate ub_key structures special or not */ 752 if(!reply_info_alloc_rrset_keys(cp, alloc, region)) { 753 if(!region) 754 reply_info_parsedelete(cp, alloc); 755 return NULL; 756 } 757 if(!repinfo_copy_rrsets(cp, rep, region)) { 758 if(!region) 759 reply_info_parsedelete(cp, alloc); 760 return NULL; 761 } 762 return cp; 763 } 764 765 uint8_t* 766 reply_find_final_cname_target(struct query_info* qinfo, struct reply_info* rep) 767 { 768 uint8_t* sname = qinfo->qname; 769 size_t snamelen = qinfo->qname_len; 770 size_t i; 771 for(i=0; i<rep->an_numrrsets; i++) { 772 struct ub_packed_rrset_key* s = rep->rrsets[i]; 773 /* follow CNAME chain (if any) */ 774 if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && 775 ntohs(s->rk.rrset_class) == qinfo->qclass && 776 snamelen == s->rk.dname_len && 777 query_dname_compare(sname, s->rk.dname) == 0) { 778 get_cname_target(s, &sname, &snamelen); 779 } 780 } 781 if(sname != qinfo->qname) 782 return sname; 783 return NULL; 784 } 785 786 struct ub_packed_rrset_key* 787 reply_find_answer_rrset(struct query_info* qinfo, struct reply_info* rep) 788 { 789 uint8_t* sname = qinfo->qname; 790 size_t snamelen = qinfo->qname_len; 791 size_t i; 792 for(i=0; i<rep->an_numrrsets; i++) { 793 struct ub_packed_rrset_key* s = rep->rrsets[i]; 794 /* first match type, for query of qtype cname */ 795 if(ntohs(s->rk.type) == qinfo->qtype && 796 ntohs(s->rk.rrset_class) == qinfo->qclass && 797 snamelen == s->rk.dname_len && 798 query_dname_compare(sname, s->rk.dname) == 0) { 799 return s; 800 } 801 /* follow CNAME chain (if any) */ 802 if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && 803 ntohs(s->rk.rrset_class) == qinfo->qclass && 804 snamelen == s->rk.dname_len && 805 query_dname_compare(sname, s->rk.dname) == 0) { 806 get_cname_target(s, &sname, &snamelen); 807 } 808 } 809 return NULL; 810 } 811 812 struct ub_packed_rrset_key* reply_find_rrset_section_an(struct reply_info* rep, 813 uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass) 814 { 815 size_t i; 816 for(i=0; i<rep->an_numrrsets; i++) { 817 struct ub_packed_rrset_key* s = rep->rrsets[i]; 818 if(ntohs(s->rk.type) == type && 819 ntohs(s->rk.rrset_class) == dclass && 820 namelen == s->rk.dname_len && 821 query_dname_compare(name, s->rk.dname) == 0) { 822 return s; 823 } 824 } 825 return NULL; 826 } 827 828 struct ub_packed_rrset_key* reply_find_rrset_section_ns(struct reply_info* rep, 829 uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass) 830 { 831 size_t i; 832 for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) { 833 struct ub_packed_rrset_key* s = rep->rrsets[i]; 834 if(ntohs(s->rk.type) == type && 835 ntohs(s->rk.rrset_class) == dclass && 836 namelen == s->rk.dname_len && 837 query_dname_compare(name, s->rk.dname) == 0) { 838 return s; 839 } 840 } 841 return NULL; 842 } 843 844 struct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep, 845 uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass) 846 { 847 size_t i; 848 for(i=0; i<rep->rrset_count; i++) { 849 struct ub_packed_rrset_key* s = rep->rrsets[i]; 850 if(ntohs(s->rk.type) == type && 851 ntohs(s->rk.rrset_class) == dclass && 852 namelen == s->rk.dname_len && 853 query_dname_compare(name, s->rk.dname) == 0) { 854 return s; 855 } 856 } 857 return NULL; 858 } 859 860 void 861 log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep) 862 { 863 /* not particularly fast but flexible, make wireformat and print */ 864 sldns_buffer* buf = sldns_buffer_new(65535); 865 struct regional* region = regional_create(); 866 if(!(buf && region)) { 867 log_err("%s: log_dns_msg: out of memory", str); 868 sldns_buffer_free(buf); 869 regional_destroy(region); 870 return; 871 } 872 if(!reply_info_encode(qinfo, rep, 0, rep->flags, buf, 0, 873 region, 65535, 1, 0)) { 874 log_err("%s: log_dns_msg: out of memory", str); 875 } else { 876 char* s = sldns_wire2str_pkt(sldns_buffer_begin(buf), 877 sldns_buffer_limit(buf)); 878 if(!s) { 879 log_info("%s: log_dns_msg: ldns tostr failed", str); 880 } else { 881 log_info("%s %s", str, s); 882 } 883 free(s); 884 } 885 sldns_buffer_free(buf); 886 regional_destroy(region); 887 } 888 889 void 890 log_reply_info(enum verbosity_value v, struct query_info *qinf, 891 struct sockaddr_storage *addr, socklen_t addrlen, struct timeval dur, 892 int cached, struct sldns_buffer *rmsg) 893 { 894 char qname_buf[LDNS_MAX_DOMAINLEN+1]; 895 char clientip_buf[128]; 896 char rcode_buf[16]; 897 char type_buf[16]; 898 char class_buf[16]; 899 size_t pktlen; 900 uint16_t rcode = FLAGS_GET_RCODE(sldns_buffer_read_u16_at(rmsg, 2)); 901 902 if(verbosity < v) 903 return; 904 905 sldns_wire2str_rcode_buf((int)rcode, rcode_buf, sizeof(rcode_buf)); 906 addr_to_str(addr, addrlen, clientip_buf, sizeof(clientip_buf)); 907 if(rcode == LDNS_RCODE_FORMERR) 908 { 909 if(LOG_TAG_QUERYREPLY) 910 log_reply("%s - - - %s - - - ", clientip_buf, rcode_buf); 911 else log_info("%s - - - %s - - - ", clientip_buf, rcode_buf); 912 } else { 913 if(qinf->qname) 914 dname_str(qinf->qname, qname_buf); 915 else snprintf(qname_buf, sizeof(qname_buf), "null"); 916 pktlen = sldns_buffer_limit(rmsg); 917 sldns_wire2str_type_buf(qinf->qtype, type_buf, sizeof(type_buf)); 918 sldns_wire2str_class_buf(qinf->qclass, class_buf, sizeof(class_buf)); 919 if(LOG_TAG_QUERYREPLY) 920 log_reply("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d", 921 clientip_buf, qname_buf, type_buf, class_buf, 922 rcode_buf, (long long)dur.tv_sec, (int)dur.tv_usec, cached, (int)pktlen); 923 else log_info("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d", 924 clientip_buf, qname_buf, type_buf, class_buf, 925 rcode_buf, (long long)dur.tv_sec, (int)dur.tv_usec, cached, (int)pktlen); 926 } 927 } 928 929 void 930 log_query_info(enum verbosity_value v, const char* str, 931 struct query_info* qinf) 932 { 933 log_nametypeclass(v, str, qinf->qname, qinf->qtype, qinf->qclass); 934 } 935 936 int 937 reply_check_cname_chain(struct query_info* qinfo, struct reply_info* rep) 938 { 939 /* check only answer section rrs for matching cname chain. 940 * the cache may return changed rdata, but owner names are untouched.*/ 941 size_t i; 942 uint8_t* sname = qinfo->qname; 943 size_t snamelen = qinfo->qname_len; 944 for(i=0; i<rep->an_numrrsets; i++) { 945 uint16_t t = ntohs(rep->rrsets[i]->rk.type); 946 if(t == LDNS_RR_TYPE_DNAME) 947 continue; /* skip dnames; note TTL 0 not cached */ 948 /* verify that owner matches current sname */ 949 if(query_dname_compare(sname, rep->rrsets[i]->rk.dname) != 0){ 950 /* cname chain broken */ 951 return 0; 952 } 953 /* if this is a cname; move on */ 954 if(t == LDNS_RR_TYPE_CNAME) { 955 get_cname_target(rep->rrsets[i], &sname, &snamelen); 956 } 957 } 958 return 1; 959 } 960 961 int 962 reply_all_rrsets_secure(struct reply_info* rep) 963 { 964 size_t i; 965 for(i=0; i<rep->rrset_count; i++) { 966 if( ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) 967 ->security != sec_status_secure ) 968 return 0; 969 } 970 return 1; 971 } 972 973 struct reply_info* 974 parse_reply_in_temp_region(sldns_buffer* pkt, struct regional* region, 975 struct query_info* qi) 976 { 977 struct reply_info* rep; 978 struct msg_parse* msg; 979 if(!(msg = regional_alloc(region, sizeof(*msg)))) { 980 return NULL; 981 } 982 memset(msg, 0, sizeof(*msg)); 983 sldns_buffer_set_position(pkt, 0); 984 if(parse_packet(pkt, msg, region) != 0){ 985 return 0; 986 } 987 if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) { 988 return 0; 989 } 990 return rep; 991 } 992 993 int edns_opt_list_append_ede(struct edns_option** list, struct regional* region, 994 sldns_ede_code code, const char *txt) 995 { 996 struct edns_option** prevp; 997 struct edns_option* opt; 998 size_t txt_len = txt ? strlen(txt) : 0; 999 1000 /* allocate new element */ 1001 opt = (struct edns_option*)regional_alloc(region, sizeof(*opt)); 1002 if(!opt) 1003 return 0; 1004 opt->next = NULL; 1005 opt->opt_code = LDNS_EDNS_EDE; 1006 opt->opt_len = txt_len + sizeof(uint16_t); 1007 opt->opt_data = regional_alloc(region, txt_len + sizeof(uint16_t)); 1008 if(!opt->opt_data) 1009 return 0; 1010 sldns_write_uint16(opt->opt_data, (uint16_t)code); 1011 if (txt_len) 1012 memmove(opt->opt_data + 2, txt, txt_len); 1013 1014 /* append at end of list */ 1015 prevp = list; 1016 while(*prevp != NULL) 1017 prevp = &((*prevp)->next); 1018 verbose(VERB_ALGO, "attached EDE code: %d with message: %s", code, (txt?txt:"\"\"")); 1019 *prevp = opt; 1020 return 1; 1021 } 1022 1023 int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len, 1024 uint8_t* data, struct regional* region) 1025 { 1026 struct edns_option** prevp; 1027 struct edns_option* opt; 1028 1029 /* allocate new element */ 1030 opt = (struct edns_option*)regional_alloc(region, sizeof(*opt)); 1031 if(!opt) 1032 return 0; 1033 opt->next = NULL; 1034 opt->opt_code = code; 1035 opt->opt_len = len; 1036 opt->opt_data = NULL; 1037 if(len > 0) { 1038 opt->opt_data = regional_alloc_init(region, data, len); 1039 if(!opt->opt_data) 1040 return 0; 1041 } 1042 1043 /* append at end of list */ 1044 prevp = list; 1045 while(*prevp != NULL) { 1046 prevp = &((*prevp)->next); 1047 } 1048 *prevp = opt; 1049 return 1; 1050 } 1051 1052 int edns_opt_list_remove(struct edns_option** list, uint16_t code) 1053 { 1054 /* The list should already be allocated in a region. Freeing the 1055 * allocated space in a region is not possible. We just unlink the 1056 * required elements and they will be freed together with the region. */ 1057 1058 struct edns_option* prev; 1059 struct edns_option* curr; 1060 if(!list || !(*list)) return 0; 1061 1062 /* Unlink and repoint if the element(s) are first in list */ 1063 while(list && *list && (*list)->opt_code == code) { 1064 *list = (*list)->next; 1065 } 1066 1067 if(!list || !(*list)) return 1; 1068 /* Unlink elements and reattach the list */ 1069 prev = *list; 1070 curr = (*list)->next; 1071 while(curr != NULL) { 1072 if(curr->opt_code == code) { 1073 prev->next = curr->next; 1074 curr = curr->next; 1075 } else { 1076 prev = curr; 1077 curr = curr->next; 1078 } 1079 } 1080 return 1; 1081 } 1082 1083 static int inplace_cb_reply_call_generic( 1084 struct inplace_cb* callback_list, enum inplace_cb_list_type type, 1085 struct query_info* qinfo, struct module_qstate* qstate, 1086 struct reply_info* rep, int rcode, struct edns_data* edns, 1087 struct comm_reply* repinfo, struct regional* region, 1088 struct timeval* start_time) 1089 { 1090 struct inplace_cb* cb; 1091 struct edns_option* opt_list_out = NULL; 1092 #if defined(EXPORT_ALL_SYMBOLS) 1093 (void)type; /* param not used when fptr_ok disabled */ 1094 #endif 1095 if(qstate) 1096 opt_list_out = qstate->edns_opts_front_out; 1097 for(cb=callback_list; cb; cb=cb->next) { 1098 fptr_ok(fptr_whitelist_inplace_cb_reply_generic( 1099 (inplace_cb_reply_func_type*)cb->cb, type)); 1100 (void)(*(inplace_cb_reply_func_type*)cb->cb)(qinfo, qstate, rep, 1101 rcode, edns, &opt_list_out, repinfo, region, start_time, cb->id, cb->cb_arg); 1102 } 1103 edns->opt_list_inplace_cb_out = opt_list_out; 1104 return 1; 1105 } 1106 1107 int inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo, 1108 struct module_qstate* qstate, struct reply_info* rep, int rcode, 1109 struct edns_data* edns, struct comm_reply* repinfo, struct regional* region, 1110 struct timeval* start_time) 1111 { 1112 return inplace_cb_reply_call_generic( 1113 env->inplace_cb_lists[inplace_cb_reply], inplace_cb_reply, qinfo, 1114 qstate, rep, rcode, edns, repinfo, region, start_time); 1115 } 1116 1117 int inplace_cb_reply_cache_call(struct module_env* env, 1118 struct query_info* qinfo, struct module_qstate* qstate, 1119 struct reply_info* rep, int rcode, struct edns_data* edns, 1120 struct comm_reply* repinfo, struct regional* region, 1121 struct timeval* start_time) 1122 { 1123 return inplace_cb_reply_call_generic( 1124 env->inplace_cb_lists[inplace_cb_reply_cache], inplace_cb_reply_cache, 1125 qinfo, qstate, rep, rcode, edns, repinfo, region, start_time); 1126 } 1127 1128 int inplace_cb_reply_local_call(struct module_env* env, 1129 struct query_info* qinfo, struct module_qstate* qstate, 1130 struct reply_info* rep, int rcode, struct edns_data* edns, 1131 struct comm_reply* repinfo, struct regional* region, 1132 struct timeval* start_time) 1133 { 1134 return inplace_cb_reply_call_generic( 1135 env->inplace_cb_lists[inplace_cb_reply_local], inplace_cb_reply_local, 1136 qinfo, qstate, rep, rcode, edns, repinfo, region, start_time); 1137 } 1138 1139 int inplace_cb_reply_servfail_call(struct module_env* env, 1140 struct query_info* qinfo, struct module_qstate* qstate, 1141 struct reply_info* rep, int rcode, struct edns_data* edns, 1142 struct comm_reply* repinfo, struct regional* region, 1143 struct timeval* start_time) 1144 { 1145 /* We are going to servfail. Remove any potential edns options. */ 1146 if(qstate) 1147 qstate->edns_opts_front_out = NULL; 1148 return inplace_cb_reply_call_generic( 1149 env->inplace_cb_lists[inplace_cb_reply_servfail], 1150 inplace_cb_reply_servfail, qinfo, qstate, rep, rcode, edns, repinfo, 1151 region, start_time); 1152 } 1153 1154 int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo, 1155 uint16_t flags, struct sockaddr_storage* addr, socklen_t addrlen, 1156 uint8_t* zone, size_t zonelen, struct module_qstate* qstate, 1157 struct regional* region) 1158 { 1159 struct inplace_cb* cb = env->inplace_cb_lists[inplace_cb_query]; 1160 for(; cb; cb=cb->next) { 1161 fptr_ok(fptr_whitelist_inplace_cb_query( 1162 (inplace_cb_query_func_type*)cb->cb)); 1163 (void)(*(inplace_cb_query_func_type*)cb->cb)(qinfo, flags, 1164 qstate, addr, addrlen, zone, zonelen, region, 1165 cb->id, cb->cb_arg); 1166 } 1167 return 1; 1168 } 1169 1170 int inplace_cb_edns_back_parsed_call(struct module_env* env, 1171 struct module_qstate* qstate) 1172 { 1173 struct inplace_cb* cb = 1174 env->inplace_cb_lists[inplace_cb_edns_back_parsed]; 1175 for(; cb; cb=cb->next) { 1176 fptr_ok(fptr_whitelist_inplace_cb_edns_back_parsed( 1177 (inplace_cb_edns_back_parsed_func_type*)cb->cb)); 1178 (void)(*(inplace_cb_edns_back_parsed_func_type*)cb->cb)(qstate, 1179 cb->id, cb->cb_arg); 1180 } 1181 return 1; 1182 } 1183 1184 int inplace_cb_query_response_call(struct module_env* env, 1185 struct module_qstate* qstate, struct dns_msg* response) { 1186 struct inplace_cb* cb = 1187 env->inplace_cb_lists[inplace_cb_query_response]; 1188 for(; cb; cb=cb->next) { 1189 fptr_ok(fptr_whitelist_inplace_cb_query_response( 1190 (inplace_cb_query_response_func_type*)cb->cb)); 1191 (void)(*(inplace_cb_query_response_func_type*)cb->cb)(qstate, 1192 response, cb->id, cb->cb_arg); 1193 } 1194 return 1; 1195 } 1196 1197 struct edns_option* edns_opt_copy_region(struct edns_option* list, 1198 struct regional* region) 1199 { 1200 struct edns_option* result = NULL, *cur = NULL, *s; 1201 while(list) { 1202 /* copy edns option structure */ 1203 s = regional_alloc_init(region, list, sizeof(*list)); 1204 if(!s) return NULL; 1205 s->next = NULL; 1206 1207 /* copy option data */ 1208 if(s->opt_data) { 1209 s->opt_data = regional_alloc_init(region, s->opt_data, 1210 s->opt_len); 1211 if(!s->opt_data) 1212 return NULL; 1213 } 1214 1215 /* link into list */ 1216 if(cur) 1217 cur->next = s; 1218 else result = s; 1219 cur = s; 1220 1221 /* examine next element */ 1222 list = list->next; 1223 } 1224 return result; 1225 } 1226 1227 int edns_opt_compare(struct edns_option* p, struct edns_option* q) 1228 { 1229 if(!p && !q) return 0; 1230 if(!p) return -1; 1231 if(!q) return 1; 1232 log_assert(p && q); 1233 if(p->opt_code != q->opt_code) 1234 return (int)q->opt_code - (int)p->opt_code; 1235 if(p->opt_len != q->opt_len) 1236 return (int)q->opt_len - (int)p->opt_len; 1237 if(p->opt_len != 0) 1238 return memcmp(p->opt_data, q->opt_data, p->opt_len); 1239 return 0; 1240 } 1241 1242 int edns_opt_list_compare(struct edns_option* p, struct edns_option* q) 1243 { 1244 int r; 1245 while(p && q) { 1246 r = edns_opt_compare(p, q); 1247 if(r != 0) 1248 return r; 1249 p = p->next; 1250 q = q->next; 1251 } 1252 if(p || q) { 1253 /* uneven length lists */ 1254 if(p) return 1; 1255 if(q) return -1; 1256 } 1257 return 0; 1258 } 1259 1260 void edns_opt_list_free(struct edns_option* list) 1261 { 1262 struct edns_option* n; 1263 while(list) { 1264 free(list->opt_data); 1265 n = list->next; 1266 free(list); 1267 list = n; 1268 } 1269 } 1270 1271 struct edns_option* edns_opt_copy_alloc(struct edns_option* list) 1272 { 1273 struct edns_option* result = NULL, *cur = NULL, *s; 1274 while(list) { 1275 /* copy edns option structure */ 1276 s = memdup(list, sizeof(*list)); 1277 if(!s) { 1278 edns_opt_list_free(result); 1279 return NULL; 1280 } 1281 s->next = NULL; 1282 1283 /* copy option data */ 1284 if(s->opt_data) { 1285 s->opt_data = memdup(s->opt_data, s->opt_len); 1286 if(!s->opt_data) { 1287 free(s); 1288 edns_opt_list_free(result); 1289 return NULL; 1290 } 1291 } 1292 1293 /* link into list */ 1294 if(cur) 1295 cur->next = s; 1296 else result = s; 1297 cur = s; 1298 1299 /* examine next element */ 1300 list = list->next; 1301 } 1302 return result; 1303 } 1304 1305 struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code) 1306 { 1307 struct edns_option* p; 1308 for(p=list; p; p=p->next) { 1309 if(p->opt_code == code) 1310 return p; 1311 } 1312 return NULL; 1313 } 1314