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