1 /* 2 * util/data/msgencode.c - Encode DNS messages, queries and replies. 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 routines to encode DNS messages. 40 */ 41 42 #include "config.h" 43 #include "util/data/msgencode.h" 44 #include "util/data/msgreply.h" 45 #include "util/data/msgparse.h" 46 #include "util/data/dname.h" 47 #include "util/log.h" 48 #include "util/regional.h" 49 #include "util/net_help.h" 50 #include "sldns/sbuffer.h" 51 #include "services/localzone.h" 52 53 #ifdef HAVE_TIME_H 54 #include <time.h> 55 #endif 56 #include <sys/time.h> 57 58 /** return code that means the function ran out of memory. negative so it does 59 * not conflict with DNS rcodes. */ 60 #define RETVAL_OUTMEM -2 61 /** return code that means the data did not fit (completely) in the packet */ 62 #define RETVAL_TRUNC -4 63 /** return code that means all is peachy keen. Equal to DNS rcode NOERROR */ 64 #define RETVAL_OK 0 65 /** Max compressions we are willing to perform; more than that will result 66 * in semi-compressed messages, or truncated even on TCP for huge messages, to 67 * avoid locking the CPU for long */ 68 #define MAX_COMPRESSION_PER_MESSAGE 120 69 70 /** 71 * Data structure to help domain name compression in outgoing messages. 72 * A tree of dnames and their offsets in the packet is kept. 73 * It is kept sorted, not canonical, but by label at least, so that after 74 * a lookup of a name you know its closest match, and the parent from that 75 * closest match. These are possible compression targets. 76 * 77 * It is a binary tree, not a rbtree or balanced tree, as the effort 78 * of keeping it balanced probably outweighs usefulness (given typical 79 * DNS packet size). 80 */ 81 struct compress_tree_node { 82 /** left node in tree, all smaller to this */ 83 struct compress_tree_node* left; 84 /** right node in tree, all larger than this */ 85 struct compress_tree_node* right; 86 87 /** the parent node - not for tree, but zone parent. One less label */ 88 struct compress_tree_node* parent; 89 /** the domain name for this node. Pointer to uncompressed memory. */ 90 uint8_t* dname; 91 /** number of labels in domain name, kept to help compare func. */ 92 int labs; 93 /** offset in packet that points to this dname */ 94 size_t offset; 95 }; 96 97 /** 98 * Find domain name in tree, returns exact and closest match. 99 * @param tree: root of tree. 100 * @param dname: pointer to uncompressed dname. 101 * @param labs: number of labels in domain name. 102 * @param match: closest or exact match. 103 * guaranteed to be smaller or equal to the sought dname. 104 * can be null if the tree is empty. 105 * @param matchlabels: number of labels that match with closest match. 106 * can be zero is there is no match. 107 * @param insertpt: insert location for dname, if not found. 108 * @return: 0 if no exact match. 109 */ 110 static int 111 compress_tree_search(struct compress_tree_node** tree, uint8_t* dname, 112 int labs, struct compress_tree_node** match, int* matchlabels, 113 struct compress_tree_node*** insertpt) 114 { 115 int c, n, closen=0; 116 struct compress_tree_node* p = *tree; 117 struct compress_tree_node* close = 0; 118 struct compress_tree_node** prev = tree; 119 while(p) { 120 if((c = dname_lab_cmp(dname, labs, p->dname, p->labs, &n)) 121 == 0) { 122 *matchlabels = n; 123 *match = p; 124 return 1; 125 } 126 if(c<0) { 127 prev = &p->left; 128 p = p->left; 129 } else { 130 closen = n; 131 close = p; /* p->dname is smaller than dname */ 132 prev = &p->right; 133 p = p->right; 134 } 135 } 136 *insertpt = prev; 137 *matchlabels = closen; 138 *match = close; 139 return 0; 140 } 141 142 /** 143 * Lookup a domain name in compression tree. 144 * @param tree: root of tree (not the node with '.'). 145 * @param dname: pointer to uncompressed dname. 146 * @param labs: number of labels in domain name. 147 * @param insertpt: insert location for dname, if not found. 148 * @return: 0 if not found or compress treenode with best compression. 149 */ 150 static struct compress_tree_node* 151 compress_tree_lookup(struct compress_tree_node** tree, uint8_t* dname, 152 int labs, struct compress_tree_node*** insertpt) 153 { 154 struct compress_tree_node* p; 155 int m; 156 if(labs <= 1) 157 return 0; /* do not compress root node */ 158 if(compress_tree_search(tree, dname, labs, &p, &m, insertpt)) { 159 /* exact match */ 160 return p; 161 } 162 /* return some ancestor of p that compresses well. */ 163 if(m>1) { 164 /* www.example.com. (labs=4) matched foo.example.com.(labs=4) 165 * then matchcount = 3. need to go up. */ 166 while(p && p->labs > m) 167 p = p->parent; 168 return p; 169 } 170 return 0; 171 } 172 173 /** 174 * Create node for domain name compression tree. 175 * @param dname: pointer to uncompressed dname (stored in tree). 176 * @param labs: number of labels in dname. 177 * @param offset: offset into packet for dname. 178 * @param region: how to allocate memory for new node. 179 * @return new node or 0 on malloc failure. 180 */ 181 static struct compress_tree_node* 182 compress_tree_newnode(uint8_t* dname, int labs, size_t offset, 183 struct regional* region) 184 { 185 struct compress_tree_node* n = (struct compress_tree_node*) 186 regional_alloc(region, sizeof(struct compress_tree_node)); 187 if(!n) return 0; 188 n->left = 0; 189 n->right = 0; 190 n->parent = 0; 191 n->dname = dname; 192 n->labs = labs; 193 n->offset = offset; 194 return n; 195 } 196 197 /** 198 * Store domain name and ancestors into compression tree. 199 * @param dname: pointer to uncompressed dname (stored in tree). 200 * @param labs: number of labels in dname. 201 * @param offset: offset into packet for dname. 202 * @param region: how to allocate memory for new node. 203 * @param closest: match from previous lookup, used to compress dname. 204 * may be NULL if no previous match. 205 * if the tree has an ancestor of dname already, this must be it. 206 * @param insertpt: where to insert the dname in tree. 207 * @return: 0 on memory error. 208 */ 209 static int 210 compress_tree_store(uint8_t* dname, int labs, size_t offset, 211 struct regional* region, struct compress_tree_node* closest, 212 struct compress_tree_node** insertpt) 213 { 214 uint8_t lablen; 215 struct compress_tree_node* newnode; 216 struct compress_tree_node* prevnode = NULL; 217 int uplabs = labs-1; /* does not store root in tree */ 218 if(closest) uplabs = labs - closest->labs; 219 log_assert(uplabs >= 0); 220 /* algorithms builds up a vine of dname-labels to hang into tree */ 221 while(uplabs--) { 222 if(offset > PTR_MAX_OFFSET) { 223 /* insertion failed, drop vine */ 224 return 1; /* compression pointer no longer useful */ 225 } 226 if(!(newnode = compress_tree_newnode(dname, labs, offset, 227 region))) { 228 /* insertion failed, drop vine */ 229 return 0; 230 } 231 232 if(prevnode) { 233 /* chain nodes together, last one has one label more, 234 * so is larger than newnode, thus goes right. */ 235 newnode->right = prevnode; 236 prevnode->parent = newnode; 237 } 238 239 /* next label */ 240 lablen = *dname++; 241 dname += lablen; 242 offset += lablen+1; 243 prevnode = newnode; 244 labs--; 245 } 246 /* if we have a vine, hang the vine into the tree */ 247 if(prevnode) { 248 *insertpt = prevnode; 249 prevnode->parent = closest; 250 } 251 return 1; 252 } 253 254 /** compress a domain name */ 255 static int 256 write_compressed_dname(sldns_buffer* pkt, uint8_t* dname, int labs, 257 struct compress_tree_node* p) 258 { 259 /* compress it */ 260 int labcopy = labs - p->labs; 261 uint8_t lablen; 262 uint16_t ptr; 263 264 if(labs == 1) { 265 /* write root label */ 266 if(sldns_buffer_remaining(pkt) < 1) 267 return 0; 268 sldns_buffer_write_u8(pkt, 0); 269 return 1; 270 } 271 272 /* copy the first couple of labels */ 273 while(labcopy--) { 274 lablen = *dname++; 275 if(sldns_buffer_remaining(pkt) < (size_t)lablen+1) 276 return 0; 277 sldns_buffer_write_u8(pkt, lablen); 278 sldns_buffer_write(pkt, dname, lablen); 279 dname += lablen; 280 } 281 /* insert compression ptr */ 282 if(sldns_buffer_remaining(pkt) < 2) 283 return 0; 284 ptr = PTR_CREATE(p->offset); 285 sldns_buffer_write_u16(pkt, ptr); 286 return 1; 287 } 288 289 /** compress owner name of RR, return RETVAL_OUTMEM RETVAL_TRUNC */ 290 static int 291 compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt, 292 struct regional* region, struct compress_tree_node** tree, 293 size_t owner_pos, uint16_t* owner_ptr, int owner_labs, 294 size_t* compress_count) 295 { 296 struct compress_tree_node* p; 297 struct compress_tree_node** insertpt = NULL; 298 if(!*owner_ptr) { 299 /* compress first time dname */ 300 if(*compress_count < MAX_COMPRESSION_PER_MESSAGE && 301 (p = compress_tree_lookup(tree, key->rk.dname, 302 owner_labs, &insertpt))) { 303 if(p->labs == owner_labs) 304 /* avoid ptr chains, since some software is 305 * not capable of decoding ptr after a ptr. */ 306 *owner_ptr = htons(PTR_CREATE(p->offset)); 307 if(!write_compressed_dname(pkt, key->rk.dname, 308 owner_labs, p)) 309 return RETVAL_TRUNC; 310 (*compress_count)++; 311 /* check if typeclass+4 ttl + rdatalen is available */ 312 if(sldns_buffer_remaining(pkt) < 4+4+2) 313 return RETVAL_TRUNC; 314 } else { 315 /* no compress */ 316 if(sldns_buffer_remaining(pkt) < key->rk.dname_len+4+4+2) 317 return RETVAL_TRUNC; 318 sldns_buffer_write(pkt, key->rk.dname, 319 key->rk.dname_len); 320 if(owner_pos <= PTR_MAX_OFFSET) 321 *owner_ptr = htons(PTR_CREATE(owner_pos)); 322 } 323 if(*compress_count < MAX_COMPRESSION_PER_MESSAGE && 324 !compress_tree_store(key->rk.dname, owner_labs, 325 owner_pos, region, p, insertpt)) 326 return RETVAL_OUTMEM; 327 } else { 328 /* always compress 2nd-further RRs in RRset */ 329 if(owner_labs == 1) { 330 if(sldns_buffer_remaining(pkt) < 1+4+4+2) 331 return RETVAL_TRUNC; 332 sldns_buffer_write_u8(pkt, 0); 333 } else { 334 if(sldns_buffer_remaining(pkt) < 2+4+4+2) 335 return RETVAL_TRUNC; 336 sldns_buffer_write(pkt, owner_ptr, 2); 337 } 338 } 339 return RETVAL_OK; 340 } 341 342 /** compress any domain name to the packet, return RETVAL_* */ 343 static int 344 compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs, 345 struct regional* region, struct compress_tree_node** tree, 346 size_t* compress_count) 347 { 348 struct compress_tree_node* p; 349 struct compress_tree_node** insertpt = NULL; 350 size_t pos = sldns_buffer_position(pkt); 351 if(*compress_count < MAX_COMPRESSION_PER_MESSAGE && 352 (p = compress_tree_lookup(tree, dname, labs, &insertpt))) { 353 if(!write_compressed_dname(pkt, dname, labs, p)) 354 return RETVAL_TRUNC; 355 } else { 356 if(!dname_buffer_write(pkt, dname)) 357 return RETVAL_TRUNC; 358 } 359 if(*compress_count < MAX_COMPRESSION_PER_MESSAGE && 360 !compress_tree_store(dname, labs, pos, region, p, insertpt)) 361 return RETVAL_OUTMEM; 362 (*compress_count)++; 363 return RETVAL_OK; 364 } 365 366 /** return true if type needs domain name compression in rdata */ 367 static const sldns_rr_descriptor* 368 type_rdata_compressible(struct ub_packed_rrset_key* key) 369 { 370 uint16_t t = ntohs(key->rk.type); 371 if(sldns_rr_descript(t) && 372 sldns_rr_descript(t)->_compress == LDNS_RR_COMPRESS) 373 return sldns_rr_descript(t); 374 return 0; 375 } 376 377 /** compress domain names in rdata, return RETVAL_* */ 378 static int 379 compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen, 380 struct regional* region, struct compress_tree_node** tree, 381 const sldns_rr_descriptor* desc, size_t* compress_count) 382 { 383 int labs, r, rdf = 0; 384 size_t dname_len, len, pos = sldns_buffer_position(pkt); 385 uint8_t count = desc->_dname_count; 386 387 sldns_buffer_skip(pkt, 2); /* rdata len fill in later */ 388 /* space for rdatalen checked for already */ 389 rdata += 2; 390 todolen -= 2; 391 while(todolen > 0 && count) { 392 switch(desc->_wireformat[rdf]) { 393 case LDNS_RDF_TYPE_DNAME: 394 labs = dname_count_size_labels(rdata, &dname_len); 395 if((r=compress_any_dname(rdata, pkt, labs, region, 396 tree, compress_count)) != RETVAL_OK) 397 return r; 398 rdata += dname_len; 399 todolen -= dname_len; 400 count--; 401 len = 0; 402 break; 403 case LDNS_RDF_TYPE_STR: 404 len = *rdata + 1; 405 break; 406 default: 407 len = get_rdf_size(desc->_wireformat[rdf]); 408 } 409 if(len) { 410 /* copy over */ 411 if(sldns_buffer_remaining(pkt) < len) 412 return RETVAL_TRUNC; 413 sldns_buffer_write(pkt, rdata, len); 414 todolen -= len; 415 rdata += len; 416 } 417 rdf++; 418 } 419 /* copy remainder */ 420 if(todolen > 0) { 421 if(sldns_buffer_remaining(pkt) < todolen) 422 return RETVAL_TRUNC; 423 sldns_buffer_write(pkt, rdata, todolen); 424 } 425 426 /* set rdata len */ 427 sldns_buffer_write_u16_at(pkt, pos, sldns_buffer_position(pkt)-pos-2); 428 return RETVAL_OK; 429 } 430 431 /** Returns true if RR type should be included */ 432 static int 433 rrset_belongs_in_reply(sldns_pkt_section s, uint16_t rrtype, uint16_t qtype, 434 int dnssec) 435 { 436 if(dnssec) 437 return 1; 438 /* skip non DNSSEC types, except if directly queried for */ 439 if(s == LDNS_SECTION_ANSWER) { 440 if(qtype == LDNS_RR_TYPE_ANY || qtype == rrtype) 441 return 1; 442 } 443 /* check DNSSEC-ness */ 444 switch(rrtype) { 445 case LDNS_RR_TYPE_SIG: 446 case LDNS_RR_TYPE_KEY: 447 case LDNS_RR_TYPE_NXT: 448 case LDNS_RR_TYPE_DS: 449 case LDNS_RR_TYPE_RRSIG: 450 case LDNS_RR_TYPE_NSEC: 451 case LDNS_RR_TYPE_DNSKEY: 452 case LDNS_RR_TYPE_NSEC3: 453 case LDNS_RR_TYPE_NSEC3PARAMS: 454 return 0; 455 } 456 return 1; 457 } 458 459 /** store rrset in buffer in wireformat, return RETVAL_* */ 460 static int 461 packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt, 462 uint16_t* num_rrs, time_t timenow, struct regional* region, 463 int do_data, int do_sig, struct compress_tree_node** tree, 464 sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset, 465 size_t* compress_count) 466 { 467 size_t i, j, owner_pos; 468 int r, owner_labs; 469 uint16_t owner_ptr = 0; 470 time_t adjust = 0; 471 struct packed_rrset_data* data = (struct packed_rrset_data*) 472 key->entry.data; 473 474 /* does this RR type belong in the answer? */ 475 if(!rrset_belongs_in_reply(s, ntohs(key->rk.type), qtype, dnssec)) 476 return RETVAL_OK; 477 478 owner_labs = dname_count_labels(key->rk.dname); 479 owner_pos = sldns_buffer_position(pkt); 480 481 /** Determine relative time adjustment for TTL values. 482 * For an rrset with a fixed TTL, use the rrset's TTL as given. */ 483 if((key->rk.flags & PACKED_RRSET_FIXEDTTL) != 0) 484 adjust = 0; 485 else 486 adjust = SERVE_ORIGINAL_TTL ? data->ttl_add : timenow; 487 488 if(do_data) { 489 const sldns_rr_descriptor* c = type_rdata_compressible(key); 490 for(i=0; i<data->count; i++) { 491 /* rrset roundrobin */ 492 j = (i + rr_offset) % data->count; 493 if((r=compress_owner(key, pkt, region, tree, 494 owner_pos, &owner_ptr, owner_labs, 495 compress_count)) != RETVAL_OK) 496 return r; 497 sldns_buffer_write(pkt, &key->rk.type, 2); 498 sldns_buffer_write(pkt, &key->rk.rrset_class, 2); 499 if(key->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) { 500 sldns_buffer_write_u32(pkt, 0); 501 } else if(adjust == 0) { 502 sldns_buffer_write_u32(pkt, data->rr_ttl[j]); 503 } else if(TTL_IS_EXPIRED(data->rr_ttl[j], adjust)) { 504 sldns_buffer_write_u32(pkt, 505 EXPIRED_REPLY_TTL_CALC( 506 data->rr_ttl[j], data->ttl_add)); 507 } else { 508 sldns_buffer_write_u32(pkt, 509 data->rr_ttl[j] - adjust); 510 } 511 if(c) { 512 if((r=compress_rdata(pkt, data->rr_data[j], 513 data->rr_len[j], region, tree, c, 514 compress_count)) != RETVAL_OK) 515 return r; 516 } else { 517 if(sldns_buffer_remaining(pkt) < data->rr_len[j]) 518 return RETVAL_TRUNC; 519 sldns_buffer_write(pkt, data->rr_data[j], 520 data->rr_len[j]); 521 } 522 } 523 } 524 /* insert rrsigs */ 525 if(do_sig && dnssec) { 526 size_t total = data->count+data->rrsig_count; 527 for(i=data->count; i<total; i++) { 528 if(owner_ptr && owner_labs != 1) { 529 if(sldns_buffer_remaining(pkt) < 530 2+4+4+data->rr_len[i]) 531 return RETVAL_TRUNC; 532 sldns_buffer_write(pkt, &owner_ptr, 2); 533 } else { 534 if((r=compress_any_dname(key->rk.dname, 535 pkt, owner_labs, region, tree, 536 compress_count)) != RETVAL_OK) 537 return r; 538 if(sldns_buffer_remaining(pkt) < 539 4+4+data->rr_len[i]) 540 return RETVAL_TRUNC; 541 } 542 sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG); 543 sldns_buffer_write(pkt, &key->rk.rrset_class, 2); 544 if(key->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) { 545 sldns_buffer_write_u32(pkt, 0); 546 } else if(adjust == 0) { 547 sldns_buffer_write_u32(pkt, data->rr_ttl[i]); 548 } else if(TTL_IS_EXPIRED(data->rr_ttl[i], adjust)) { 549 sldns_buffer_write_u32(pkt, 550 EXPIRED_REPLY_TTL_CALC( 551 data->rr_ttl[i], data->ttl_add)); 552 } else { 553 sldns_buffer_write_u32(pkt, 554 data->rr_ttl[i] - adjust); 555 } 556 /* rrsig rdata cannot be compressed, perform 100+ byte 557 * memcopy. */ 558 sldns_buffer_write(pkt, data->rr_data[i], 559 data->rr_len[i]); 560 } 561 } 562 /* change rrnum only after we are sure it fits */ 563 if(do_data) 564 *num_rrs += data->count; 565 if(do_sig && dnssec) 566 *num_rrs += data->rrsig_count; 567 568 return RETVAL_OK; 569 } 570 571 /** store msg section in wireformat buffer, return RETVAL_* */ 572 static int 573 insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, 574 sldns_buffer* pkt, size_t rrsets_before, time_t timenow, 575 struct regional* region, struct compress_tree_node** tree, 576 sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset, 577 size_t* compress_count) 578 { 579 int r; 580 size_t i, setstart; 581 /* we now allow this function to be called multiple times for the 582 * same section, incrementally updating num_rrs. The caller is 583 * responsible for initializing it (which is the case in the current 584 * implementation). */ 585 586 if(s != LDNS_SECTION_ADDITIONAL) { 587 if(s == LDNS_SECTION_ANSWER && qtype == LDNS_RR_TYPE_ANY) 588 dnssec = 1; /* include all types in ANY answer */ 589 for(i=0; i<num_rrsets; i++) { 590 setstart = sldns_buffer_position(pkt); 591 if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], 592 pkt, num_rrs, timenow, region, 1, 1, tree, 593 s, qtype, dnssec, rr_offset, compress_count)) 594 != RETVAL_OK) { 595 /* Bad, but if due to size must set TC bit */ 596 /* trim off the rrset neatly. */ 597 sldns_buffer_set_position(pkt, setstart); 598 return r; 599 } 600 } 601 } else { 602 for(i=0; i<num_rrsets; i++) { 603 setstart = sldns_buffer_position(pkt); 604 if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], 605 pkt, num_rrs, timenow, region, 1, 0, tree, 606 s, qtype, dnssec, rr_offset, compress_count)) 607 != RETVAL_OK) { 608 sldns_buffer_set_position(pkt, setstart); 609 return r; 610 } 611 } 612 if(dnssec) 613 for(i=0; i<num_rrsets; i++) { 614 setstart = sldns_buffer_position(pkt); 615 if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], 616 pkt, num_rrs, timenow, region, 0, 1, tree, 617 s, qtype, dnssec, rr_offset, compress_count)) 618 != RETVAL_OK) { 619 sldns_buffer_set_position(pkt, setstart); 620 return r; 621 } 622 } 623 } 624 return RETVAL_OK; 625 } 626 627 /** store query section in wireformat buffer, return RETVAL */ 628 static int 629 insert_query(struct query_info* qinfo, struct compress_tree_node** tree, 630 sldns_buffer* buffer, struct regional* region) 631 { 632 uint8_t* qname = qinfo->local_alias ? 633 qinfo->local_alias->rrset->rk.dname : qinfo->qname; 634 size_t qname_len = qinfo->local_alias ? 635 qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len; 636 if(sldns_buffer_remaining(buffer) < 637 qinfo->qname_len+sizeof(uint16_t)*2) 638 return RETVAL_TRUNC; /* buffer too small */ 639 /* the query is the first name inserted into the tree */ 640 if(!compress_tree_store(qname, dname_count_labels(qname), 641 sldns_buffer_position(buffer), region, NULL, tree)) 642 return RETVAL_OUTMEM; 643 if(sldns_buffer_current(buffer) == qname) 644 sldns_buffer_skip(buffer, (ssize_t)qname_len); 645 else sldns_buffer_write(buffer, qname, qname_len); 646 sldns_buffer_write_u16(buffer, qinfo->qtype); 647 sldns_buffer_write_u16(buffer, qinfo->qclass); 648 return RETVAL_OK; 649 } 650 651 static int 652 positive_answer(struct reply_info* rep, uint16_t qtype) { 653 size_t i; 654 if (FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR) 655 return 0; 656 657 for(i=0;i<rep->an_numrrsets; i++) { 658 if(ntohs(rep->rrsets[i]->rk.type) == qtype) { 659 /* for priming queries, type NS, include addresses */ 660 if(qtype == LDNS_RR_TYPE_NS) 661 return 0; 662 /* in case it is a wildcard with DNSSEC, there will 663 * be NSEC/NSEC3 records in the authority section 664 * that we cannot remove */ 665 for(i=rep->an_numrrsets; i<rep->an_numrrsets+ 666 rep->ns_numrrsets; i++) { 667 if(ntohs(rep->rrsets[i]->rk.type) == 668 LDNS_RR_TYPE_NSEC || 669 ntohs(rep->rrsets[i]->rk.type) == 670 LDNS_RR_TYPE_NSEC3) 671 return 0; 672 } 673 return 1; 674 } 675 } 676 return 0; 677 } 678 679 static int 680 negative_answer(struct reply_info* rep) { 681 size_t i; 682 int ns_seen = 0; 683 if(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN) 684 return 1; 685 if(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR && 686 rep->an_numrrsets != 0) 687 return 0; /* positive */ 688 if(FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR && 689 FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NXDOMAIN) 690 return 0; 691 for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++){ 692 if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_SOA) 693 return 1; 694 if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS) 695 ns_seen = 1; 696 } 697 if(ns_seen) return 0; /* could be referral, NS, but no SOA */ 698 return 1; 699 } 700 701 int 702 reply_info_encode(struct query_info* qinfo, struct reply_info* rep, 703 uint16_t id, uint16_t flags, sldns_buffer* buffer, time_t timenow, 704 struct regional* region, uint16_t udpsize, int dnssec, int minimise) 705 { 706 uint16_t ancount=0, nscount=0, arcount=0; 707 struct compress_tree_node* tree = 0; 708 int r; 709 size_t rr_offset; 710 size_t compress_count=0; 711 712 sldns_buffer_clear(buffer); 713 if(udpsize < sldns_buffer_limit(buffer)) 714 sldns_buffer_set_limit(buffer, udpsize); 715 if(sldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE) 716 return 0; 717 718 sldns_buffer_write(buffer, &id, sizeof(uint16_t)); 719 sldns_buffer_write_u16(buffer, flags); 720 sldns_buffer_write_u16(buffer, rep->qdcount); 721 /* set an, ns, ar counts to zero in case of small packets */ 722 sldns_buffer_write(buffer, "\000\000\000\000\000\000", 6); 723 724 /* insert query section */ 725 if(rep->qdcount) { 726 if((r=insert_query(qinfo, &tree, buffer, region)) != 727 RETVAL_OK) { 728 if(r == RETVAL_TRUNC) { 729 /* create truncated message */ 730 sldns_buffer_write_u16_at(buffer, 4, 0); 731 LDNS_TC_SET(sldns_buffer_begin(buffer)); 732 sldns_buffer_flip(buffer); 733 return 1; 734 } 735 return 0; 736 } 737 } 738 /* roundrobin offset. using query id for random number. With ntohs 739 * for different roundrobins for sequential id client senders. */ 740 rr_offset = RRSET_ROUNDROBIN?ntohs(id)+(timenow?timenow:time(NULL)):0; 741 742 /* "prepend" any local alias records in the answer section if this 743 * response is supposed to be authoritative. Currently it should 744 * be a single CNAME record (sanity-checked in worker_handle_request()) 745 * but it can be extended if and when we support more variations of 746 * aliases. */ 747 if(qinfo->local_alias && (flags & BIT_AA)) { 748 struct reply_info arep; 749 time_t timezero = 0; /* to use the 'authoritative' TTL */ 750 memset(&arep, 0, sizeof(arep)); 751 arep.flags = rep->flags; 752 arep.an_numrrsets = 1; 753 arep.rrset_count = 1; 754 arep.rrsets = &qinfo->local_alias->rrset; 755 if((r=insert_section(&arep, 1, &ancount, buffer, 0, 756 timezero, region, &tree, LDNS_SECTION_ANSWER, 757 qinfo->qtype, dnssec, rr_offset, &compress_count)) != RETVAL_OK) { 758 if(r == RETVAL_TRUNC) { 759 /* create truncated message */ 760 sldns_buffer_write_u16_at(buffer, 6, ancount); 761 LDNS_TC_SET(sldns_buffer_begin(buffer)); 762 sldns_buffer_flip(buffer); 763 return 1; 764 } 765 return 0; 766 } 767 } 768 769 /* insert answer section */ 770 if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, 771 0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype, 772 dnssec, rr_offset, &compress_count)) != RETVAL_OK) { 773 if(r == RETVAL_TRUNC) { 774 /* create truncated message */ 775 sldns_buffer_write_u16_at(buffer, 6, ancount); 776 LDNS_TC_SET(sldns_buffer_begin(buffer)); 777 sldns_buffer_flip(buffer); 778 return 1; 779 } 780 return 0; 781 } 782 sldns_buffer_write_u16_at(buffer, 6, ancount); 783 784 /* if response is positive answer, auth/add sections are not required */ 785 if( ! (minimise && positive_answer(rep, qinfo->qtype)) ) { 786 /* insert auth section */ 787 if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer, 788 rep->an_numrrsets, timenow, region, &tree, 789 LDNS_SECTION_AUTHORITY, qinfo->qtype, 790 dnssec, rr_offset, &compress_count)) != RETVAL_OK) { 791 if(r == RETVAL_TRUNC) { 792 /* create truncated message */ 793 sldns_buffer_write_u16_at(buffer, 8, nscount); 794 LDNS_TC_SET(sldns_buffer_begin(buffer)); 795 sldns_buffer_flip(buffer); 796 return 1; 797 } 798 return 0; 799 } 800 sldns_buffer_write_u16_at(buffer, 8, nscount); 801 802 if(! (minimise && negative_answer(rep))) { 803 /* insert add section */ 804 if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer, 805 rep->an_numrrsets + rep->ns_numrrsets, timenow, region, 806 &tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype, 807 dnssec, rr_offset, &compress_count)) != RETVAL_OK) { 808 if(r == RETVAL_TRUNC) { 809 /* no need to set TC bit, this is the additional */ 810 sldns_buffer_write_u16_at(buffer, 10, arcount); 811 sldns_buffer_flip(buffer); 812 return 1; 813 } 814 return 0; 815 } 816 sldns_buffer_write_u16_at(buffer, 10, arcount); 817 } 818 } 819 sldns_buffer_flip(buffer); 820 return 1; 821 } 822 823 size_t 824 calc_edns_field_size(struct edns_data* edns) 825 { 826 size_t rdatalen = 0; 827 struct edns_option* opt; 828 if(!edns || !edns->edns_present) 829 return 0; 830 for(opt = edns->opt_list_inplace_cb_out; opt; opt = opt->next) { 831 rdatalen += 4 + opt->opt_len; 832 } 833 for(opt = edns->opt_list_out; opt; opt = opt->next) { 834 rdatalen += 4 + opt->opt_len; 835 } 836 /* domain root '.' + type + class + ttl + rdatalen */ 837 return 1 + 2 + 2 + 4 + 2 + rdatalen; 838 } 839 840 uint16_t 841 calc_edns_option_size(struct edns_data* edns, uint16_t code) 842 { 843 size_t rdatalen = 0; 844 struct edns_option* opt; 845 if(!edns || !edns->edns_present) 846 return 0; 847 for(opt = edns->opt_list_inplace_cb_out; opt; opt = opt->next) { 848 if(opt->opt_code == code) 849 rdatalen += 4 + opt->opt_len; 850 } 851 for(opt = edns->opt_list_out; opt; opt = opt->next) { 852 if(opt->opt_code == code) 853 rdatalen += 4 + opt->opt_len; 854 } 855 return rdatalen; 856 } 857 858 uint16_t 859 calc_ede_option_size(struct edns_data* edns, size_t* txt_size) 860 { 861 size_t rdatalen = 0; 862 struct edns_option* opt; 863 *txt_size = 0; 864 if(!edns || !edns->edns_present) 865 return 0; 866 for(opt = edns->opt_list_inplace_cb_out; opt; opt = opt->next) { 867 if(opt->opt_code == LDNS_EDNS_EDE) { 868 rdatalen += 4 + opt->opt_len; 869 if(opt->opt_len > 2) *txt_size += opt->opt_len - 2; 870 if(opt->opt_len >= 2 && sldns_read_uint16( 871 opt->opt_data) == LDNS_EDE_OTHER) { 872 *txt_size += 4 + 2; 873 } 874 } 875 } 876 for(opt = edns->opt_list_out; opt; opt = opt->next) { 877 if(opt->opt_code == LDNS_EDNS_EDE) { 878 rdatalen += 4 + opt->opt_len; 879 if(opt->opt_len > 2) *txt_size += opt->opt_len - 2; 880 if(opt->opt_len >= 2 && sldns_read_uint16( 881 opt->opt_data) == LDNS_EDE_OTHER) { 882 *txt_size += 4 + 2; 883 } 884 } 885 } 886 return rdatalen; 887 } 888 889 /* Trims the EDE OPTION-DATA to not include any EXTRA-TEXT data. 890 * Also removes any LDNS_EDE_OTHER options from the list since they are useless 891 * without the extra text. */ 892 static void 893 ede_trim_text(struct edns_option** list) 894 { 895 struct edns_option* curr, *prev = NULL; 896 if(!list || !(*list)) return; 897 /* Unlink and repoint if LDNS_EDE_OTHER are first in list */ 898 while(list && *list && (*list)->opt_code == LDNS_EDNS_EDE 899 && (*list)->opt_len >= 2 900 && sldns_read_uint16((*list)->opt_data) == LDNS_EDE_OTHER ) { 901 *list = (*list)->next; 902 } 903 if(!list || !(*list)) return; 904 curr = *list; 905 while(curr) { 906 if(curr->opt_code == LDNS_EDNS_EDE) { 907 if(curr->opt_len >= 2 && sldns_read_uint16( 908 curr->opt_data) == LDNS_EDE_OTHER) { 909 /* LDNS_EDE_OTHER cannot be the first option in 910 * this while, so prev is always initialized at 911 * this point from the other branches; 912 * cut this option off */ 913 prev->next = curr->next; 914 curr = curr->next; 915 } else if(curr->opt_len > 2) { 916 /* trim this option's EXTRA-TEXT */ 917 curr->opt_len = 2; 918 prev = curr; 919 curr = curr->next; 920 } else { 921 prev = curr; 922 curr = curr->next; 923 } 924 } else { 925 /* continue */ 926 prev = curr; 927 curr = curr->next; 928 } 929 } 930 } 931 932 static void 933 attach_edns_record_max_msg_sz(sldns_buffer* pkt, struct edns_data* edns, 934 uint16_t max_msg_sz) 935 { 936 size_t len; 937 size_t rdatapos; 938 struct edns_option* opt; 939 struct edns_option* padding_option = NULL; 940 /* inc additional count */ 941 sldns_buffer_write_u16_at(pkt, 10, 942 sldns_buffer_read_u16_at(pkt, 10) + 1); 943 len = sldns_buffer_limit(pkt); 944 sldns_buffer_clear(pkt); 945 sldns_buffer_set_position(pkt, len); 946 /* write EDNS record */ 947 sldns_buffer_write_u8(pkt, 0); /* '.' label */ 948 sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */ 949 sldns_buffer_write_u16(pkt, edns->udp_size); /* class */ 950 sldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */ 951 sldns_buffer_write_u8(pkt, edns->edns_version); 952 sldns_buffer_write_u16(pkt, edns->bits); 953 rdatapos = sldns_buffer_position(pkt); 954 sldns_buffer_write_u16(pkt, 0); /* rdatalen */ 955 /* write rdata */ 956 for(opt=edns->opt_list_inplace_cb_out; opt; opt=opt->next) { 957 if (opt->opt_code == LDNS_EDNS_PADDING) { 958 padding_option = opt; 959 continue; 960 } 961 if(sldns_buffer_position(pkt) + opt->opt_len + 4 > max_msg_sz) 962 break; /* no space for it */ 963 if(!sldns_buffer_available(pkt, 4 + opt->opt_len)) 964 break; 965 sldns_buffer_write_u16(pkt, opt->opt_code); 966 sldns_buffer_write_u16(pkt, opt->opt_len); 967 if(opt->opt_len != 0) 968 sldns_buffer_write(pkt, opt->opt_data, opt->opt_len); 969 } 970 for(opt=edns->opt_list_out; opt; opt=opt->next) { 971 if (opt->opt_code == LDNS_EDNS_PADDING) { 972 padding_option = opt; 973 continue; 974 } 975 if(sldns_buffer_position(pkt) + opt->opt_len + 4 > max_msg_sz) 976 break; /* no space for it */ 977 if(!sldns_buffer_available(pkt, 4 + opt->opt_len)) 978 break; 979 sldns_buffer_write_u16(pkt, opt->opt_code); 980 sldns_buffer_write_u16(pkt, opt->opt_len); 981 if(opt->opt_len != 0) 982 sldns_buffer_write(pkt, opt->opt_data, opt->opt_len); 983 } 984 if (padding_option && edns->padding_block_size && 985 sldns_buffer_position(pkt)+4 <= max_msg_sz && 986 sldns_buffer_available(pkt, 4) /* if there is space for it */) { 987 size_t pad_pos = sldns_buffer_position(pkt); 988 size_t msg_sz = ((pad_pos + 3) / edns->padding_block_size + 1) 989 * edns->padding_block_size; 990 size_t pad_sz; 991 992 if (msg_sz > max_msg_sz) 993 msg_sz = max_msg_sz; 994 995 /* By use of calc_edns_field_size, calling functions should 996 * have made sure that there is enough space for at least a 997 * zero sized padding option. 998 */ 999 log_assert(pad_pos + 4 <= msg_sz); 1000 1001 pad_sz = msg_sz - pad_pos - 4; 1002 sldns_buffer_write_u16(pkt, LDNS_EDNS_PADDING); 1003 sldns_buffer_write_u16(pkt, pad_sz); 1004 if (pad_sz) { 1005 memset(sldns_buffer_current(pkt), 0, pad_sz); 1006 sldns_buffer_skip(pkt, pad_sz); 1007 } 1008 } 1009 sldns_buffer_write_u16_at(pkt, rdatapos, 1010 sldns_buffer_position(pkt)-rdatapos-2); 1011 sldns_buffer_flip(pkt); 1012 } 1013 1014 void 1015 attach_edns_record(sldns_buffer* pkt, struct edns_data* edns) 1016 { 1017 if(!edns || !edns->edns_present) 1018 return; 1019 attach_edns_record_max_msg_sz(pkt, edns, edns->udp_size); 1020 } 1021 1022 int 1023 reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, 1024 uint16_t id, uint16_t qflags, sldns_buffer* pkt, time_t timenow, 1025 int cached, struct regional* region, uint16_t udpsize, 1026 struct edns_data* edns, int dnssec, int secure) 1027 { 1028 uint16_t flags; 1029 unsigned int attach_edns = 0; 1030 size_t edns_field_size, ede_size, ede_txt_size; 1031 1032 if(!cached || rep->authoritative) { 1033 /* original flags, copy RD and CD bits from query. */ 1034 flags = rep->flags | (qflags & (BIT_RD|BIT_CD)); 1035 } else { 1036 /* remove AA bit, copy RD and CD bits from query. */ 1037 flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD)); 1038 } 1039 if(secure && (dnssec || (qflags&BIT_AD))) 1040 flags |= BIT_AD; 1041 /* restore AA bit if we have a local alias and the response can be 1042 * authoritative. Also clear AD bit if set as the local data is the 1043 * primary answer. */ 1044 if(qinf->local_alias && 1045 (FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR || 1046 FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN)) { 1047 flags |= BIT_AA; 1048 flags &= ~BIT_AD; 1049 } 1050 log_assert((flags & BIT_QR)); /* QR bit must be on in our replies */ 1051 if(udpsize < LDNS_HEADER_SIZE) 1052 return 0; 1053 /* currently edns does not change during calculations; 1054 * calculate sizes once here */ 1055 edns_field_size = calc_edns_field_size(edns); 1056 ede_size = calc_ede_option_size(edns, &ede_txt_size); 1057 if(sldns_buffer_capacity(pkt) < (size_t)udpsize) 1058 udpsize = sldns_buffer_capacity(pkt); 1059 if(!edns || !edns->edns_present) { 1060 attach_edns = 0; 1061 /* EDEs are optional, try to fit anything else before them */ 1062 } else if((size_t)udpsize < (size_t)LDNS_HEADER_SIZE + edns_field_size - ede_size) { 1063 /* packet too small to contain edns, omit it. */ 1064 attach_edns = 0; 1065 } else { 1066 /* reserve space for edns record */ 1067 attach_edns = (unsigned int)edns_field_size - ede_size; 1068 } 1069 1070 if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region, 1071 udpsize - attach_edns, dnssec, MINIMAL_RESPONSES)) { 1072 log_err("reply encode: out of memory"); 1073 return 0; 1074 } 1075 if(attach_edns) { 1076 if((size_t)udpsize >= sldns_buffer_limit(pkt) + edns_field_size) 1077 attach_edns_record_max_msg_sz(pkt, edns, udpsize); 1078 else if((size_t)udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_txt_size) { 1079 ede_trim_text(&edns->opt_list_inplace_cb_out); 1080 ede_trim_text(&edns->opt_list_out); 1081 attach_edns_record_max_msg_sz(pkt, edns, udpsize); 1082 } else if((size_t)udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_size) { 1083 edns_opt_list_remove(&edns->opt_list_inplace_cb_out, LDNS_EDNS_EDE); 1084 edns_opt_list_remove(&edns->opt_list_out, LDNS_EDNS_EDE); 1085 attach_edns_record_max_msg_sz(pkt, edns, udpsize); 1086 } 1087 } 1088 return 1; 1089 } 1090 1091 void 1092 qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo) 1093 { 1094 uint16_t flags = 0; /* QUERY, NOERROR */ 1095 const uint8_t* qname = qinfo->local_alias ? 1096 qinfo->local_alias->rrset->rk.dname : qinfo->qname; 1097 size_t qname_len = qinfo->local_alias ? 1098 qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len; 1099 sldns_buffer_clear(pkt); 1100 log_assert(sldns_buffer_remaining(pkt) >= 12+255+4/*max query*/); 1101 sldns_buffer_skip(pkt, 2); /* id done later */ 1102 sldns_buffer_write_u16(pkt, flags); 1103 sldns_buffer_write_u16(pkt, 1); /* query count */ 1104 sldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */ 1105 sldns_buffer_write(pkt, qname, qname_len); 1106 sldns_buffer_write_u16(pkt, qinfo->qtype); 1107 sldns_buffer_write_u16(pkt, qinfo->qclass); 1108 sldns_buffer_flip(pkt); 1109 } 1110 1111 void 1112 extended_error_encode(sldns_buffer* buf, uint16_t rcode, 1113 struct query_info* qinfo, uint16_t qid, uint16_t qflags, 1114 uint16_t xflags, struct edns_data* edns) 1115 { 1116 uint16_t flags; 1117 1118 sldns_buffer_clear(buf); 1119 sldns_buffer_write(buf, &qid, sizeof(uint16_t)); 1120 flags = (uint16_t)(BIT_QR | BIT_RA | (rcode & 0xF)); /* QR and retcode*/ 1121 flags |= xflags; 1122 flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */ 1123 sldns_buffer_write_u16(buf, flags); 1124 if(qinfo) flags = 1; 1125 else flags = 0; 1126 sldns_buffer_write_u16(buf, flags); 1127 flags = 0; 1128 sldns_buffer_write(buf, &flags, sizeof(uint16_t)); 1129 sldns_buffer_write(buf, &flags, sizeof(uint16_t)); 1130 sldns_buffer_write(buf, &flags, sizeof(uint16_t)); 1131 if(qinfo) { 1132 const uint8_t* qname = qinfo->local_alias ? 1133 qinfo->local_alias->rrset->rk.dname : qinfo->qname; 1134 size_t qname_len = qinfo->local_alias ? 1135 qinfo->local_alias->rrset->rk.dname_len : 1136 qinfo->qname_len; 1137 if(sldns_buffer_current(buf) == qname) 1138 sldns_buffer_skip(buf, (ssize_t)qname_len); 1139 else sldns_buffer_write(buf, qname, qname_len); 1140 sldns_buffer_write_u16(buf, qinfo->qtype); 1141 sldns_buffer_write_u16(buf, qinfo->qclass); 1142 } 1143 sldns_buffer_flip(buf); 1144 if(edns && edns->edns_present) { 1145 size_t edns_field_size, ede_size, ede_txt_size; 1146 struct edns_data es = *edns; 1147 es.edns_version = EDNS_ADVERTISED_VERSION; 1148 es.udp_size = EDNS_ADVERTISED_SIZE; 1149 es.ext_rcode = (uint8_t)(rcode >> 4); 1150 es.bits &= EDNS_DO; 1151 /* EDEs are optional. If space is a concern try in order: 1152 * - removing any EXTRA-TEXT fields from explicit EDEs, or 1153 * - removing all EDEs, 1154 * to see if EDNS can fit. */ 1155 edns_field_size = calc_edns_field_size(&es); 1156 ede_size = calc_ede_option_size(&es, &ede_txt_size); 1157 if((size_t)edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size) 1158 attach_edns_record_max_msg_sz(buf, &es, edns->udp_size); 1159 else if((size_t)edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size - ede_txt_size) { 1160 ede_trim_text(&es.opt_list_inplace_cb_out); 1161 ede_trim_text(&es.opt_list_out); 1162 attach_edns_record_max_msg_sz(buf, &es, edns->udp_size); 1163 } else if((size_t)edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size - ede_size) { 1164 edns_opt_list_remove(&es.opt_list_inplace_cb_out, LDNS_EDNS_EDE); 1165 edns_opt_list_remove(&es.opt_list_out, LDNS_EDNS_EDE); 1166 attach_edns_record_max_msg_sz(buf, &es, edns->udp_size); 1167 } 1168 } 1169 } 1170 1171 void 1172 error_encode(sldns_buffer* buf, int r, struct query_info* qinfo, 1173 uint16_t qid, uint16_t qflags, struct edns_data* edns) 1174 { 1175 extended_error_encode(buf, (r & 0x000F), qinfo, qid, qflags, 1176 (r & 0xFFF0), edns); 1177 } 1178