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