6262#define RETVAL_TRUNC -4
6363/** return code that means all is peachy keen. Equal to DNS rcode NOERROR */
6464#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
6569
6670/**
6771 * Data structure to help domain name compression in outgoing messages.
@@ -284,15 +288,17 @@ write_compressed_dname(sldns_buffer* pkt, uint8_t* dname, int labs,
284288
285289/** compress owner name of RR, return RETVAL_OUTMEM RETVAL_TRUNC */
286290static int
287- compress_owner (struct ub_packed_rrset_key * key , sldns_buffer * pkt ,
288- struct regional * region , struct compress_tree_node * * tree ,
289- size_t owner_pos , uint16_t * owner_ptr , int owner_labs )
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 )
290295{
291296 struct compress_tree_node * p ;
292297 struct compress_tree_node * * insertpt = NULL ;
293298 if (!* owner_ptr ) {
294299 /* compress first time dname */
295- if ((p = compress_tree_lookup (tree , key -> rk .dname ,
300+ if (* compress_count < MAX_COMPRESSION_PER_MESSAGE &&
301+ (p = compress_tree_lookup (tree , key -> rk .dname ,
296302 owner_labs , & insertpt ))) {
297303 if (p -> labs == owner_labs )
298304 /* avoid ptr chains, since some software is
@@ -301,6 +307,7 @@ compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
301307 if (!write_compressed_dname (pkt , key -> rk .dname ,
302308 owner_labs , p ))
303309 return RETVAL_TRUNC ;
310+ (* compress_count )++ ;
304311 /* check if typeclass+4 ttl + rdatalen is available */
305312 if (sldns_buffer_remaining (pkt ) < 4 + 4 + 2 )
306313 return RETVAL_TRUNC ;
@@ -313,7 +320,8 @@ compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
313320 if (owner_pos <= PTR_MAX_OFFSET )
314321 * owner_ptr = htons (PTR_CREATE (owner_pos ));
315322 }
316- if (!compress_tree_store (key -> rk .dname , owner_labs ,
323+ if (* compress_count < MAX_COMPRESSION_PER_MESSAGE &&
324+ !compress_tree_store (key -> rk .dname , owner_labs ,
317325 owner_pos , region , p , insertpt ))
318326 return RETVAL_OUTMEM ;
319327 } else {
@@ -333,20 +341,24 @@ compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
333341
334342/** compress any domain name to the packet, return RETVAL_* */
335343static int
336- compress_any_dname (uint8_t * dname , sldns_buffer * pkt , int labs ,
337- struct regional * region , struct compress_tree_node * * tree )
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 )
338347{
339348 struct compress_tree_node * p ;
340349 struct compress_tree_node * * insertpt = NULL ;
341350 size_t pos = sldns_buffer_position (pkt );
342- if ((p = compress_tree_lookup (tree , dname , labs , & insertpt ))) {
351+ if (* compress_count < MAX_COMPRESSION_PER_MESSAGE &&
352+ (p = compress_tree_lookup (tree , dname , labs , & insertpt ))) {
343353 if (!write_compressed_dname (pkt , dname , labs , p ))
344354 return RETVAL_TRUNC ;
355+ (* compress_count )++ ;
345356 } else {
346357 if (!dname_buffer_write (pkt , dname ))
347358 return RETVAL_TRUNC ;
348359 }
349- if (!compress_tree_store (dname , labs , pos , region , p , insertpt ))
360+ if (* compress_count < MAX_COMPRESSION_PER_MESSAGE &&
361+ !compress_tree_store (dname , labs , pos , region , p , insertpt ))
350362 return RETVAL_OUTMEM ;
351363 return RETVAL_OK ;
352364}
@@ -364,9 +376,9 @@ type_rdata_compressable(struct ub_packed_rrset_key* key)
364376
365377/** compress domain names in rdata, return RETVAL_* */
366378static int
367- compress_rdata (sldns_buffer * pkt , uint8_t * rdata , size_t todolen ,
368- struct regional * region , struct compress_tree_node * * tree ,
369- const sldns_rr_descriptor * desc )
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 )
370382{
371383 int labs , r , rdf = 0 ;
372384 size_t dname_len , len , pos = sldns_buffer_position (pkt );
@@ -380,8 +392,8 @@ compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen,
380392 switch (desc -> _wireformat [rdf ]) {
381393 case LDNS_RDF_TYPE_DNAME :
382394 labs = dname_count_size_labels (rdata , & dname_len );
383- if ((r = compress_any_dname (rdata , pkt , labs , region ,
384- tree )) != RETVAL_OK )
395+ if ((r = compress_any_dname (rdata , pkt , labs , region ,
396+ tree , compress_count )) != RETVAL_OK )
385397 return r ;
386398 rdata += dname_len ;
387399 todolen -= dname_len ;
@@ -449,7 +461,8 @@ static int
449461packed_rrset_encode (struct ub_packed_rrset_key * key , sldns_buffer * pkt ,
450462 uint16_t * num_rrs , time_t timenow , struct regional * region ,
451463 int do_data , int do_sig , struct compress_tree_node * * tree ,
452- sldns_pkt_section s , uint16_t qtype , int dnssec , size_t rr_offset )
464+ sldns_pkt_section s , uint16_t qtype , int dnssec , size_t rr_offset ,
465+ size_t * compress_count )
453466{
454467 size_t i , j , owner_pos ;
455468 int r , owner_labs ;
@@ -477,9 +490,9 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
477490 for (i = 0 ; i < data -> count ; i ++ ) {
478491 /* rrset roundrobin */
479492 j = (i + rr_offset ) % data -> count ;
480- if ((r = compress_owner (key , pkt , region , tree ,
481- owner_pos , & owner_ptr , owner_labs ))
482- != RETVAL_OK )
493+ if ((r = compress_owner (key , pkt , region , tree ,
494+ owner_pos , & owner_ptr , owner_labs ,
495+ compress_count )) != RETVAL_OK )
483496 return r ;
484497 sldns_buffer_write (pkt , & key -> rk .type , 2 );
485498 sldns_buffer_write (pkt , & key -> rk .rrset_class , 2 );
@@ -489,8 +502,8 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
489502 else sldns_buffer_write_u32 (pkt , data -> rr_ttl [j ]- adjust );
490503 if (c ) {
491504 if ((r = compress_rdata (pkt , data -> rr_data [j ],
492- data -> rr_len [j ], region , tree , c ))
493- != RETVAL_OK )
505+ data -> rr_len [j ], region , tree , c ,
506+ compress_count )) != RETVAL_OK )
494507 return r ;
495508 } else {
496509 if (sldns_buffer_remaining (pkt ) < data -> rr_len [j ])
@@ -510,9 +523,9 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
510523 return RETVAL_TRUNC ;
511524 sldns_buffer_write (pkt , & owner_ptr , 2 );
512525 } else {
513- if ((r = compress_any_dname (key -> rk .dname ,
514- pkt , owner_labs , region , tree ))
515- != RETVAL_OK )
526+ if ((r = compress_any_dname (key -> rk .dname ,
527+ pkt , owner_labs , region , tree ,
528+ compress_count )) != RETVAL_OK )
516529 return r ;
517530 if (sldns_buffer_remaining (pkt ) <
518531 4 + 4 + data -> rr_len [i ])
@@ -544,7 +557,8 @@ static int
544557insert_section (struct reply_info * rep , size_t num_rrsets , uint16_t * num_rrs ,
545558 sldns_buffer * pkt , size_t rrsets_before , time_t timenow ,
546559 struct regional * region , struct compress_tree_node * * tree ,
547- sldns_pkt_section s , uint16_t qtype , int dnssec , size_t rr_offset )
560+ sldns_pkt_section s , uint16_t qtype , int dnssec , size_t rr_offset ,
561+ size_t * compress_count )
548562{
549563 int r ;
550564 size_t i , setstart ;
@@ -560,7 +574,7 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
560574 setstart = sldns_buffer_position (pkt );
561575 if ((r = packed_rrset_encode (rep -> rrsets [rrsets_before + i ],
562576 pkt , num_rrs , timenow , region , 1 , 1 , tree ,
563- s , qtype , dnssec , rr_offset ))
577+ s , qtype , dnssec , rr_offset , compress_count ))
564578 != RETVAL_OK ) {
565579 /* Bad, but if due to size must set TC bit */
566580 /* trim off the rrset neatly. */
@@ -573,7 +587,7 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
573587 setstart = sldns_buffer_position (pkt );
574588 if ((r = packed_rrset_encode (rep -> rrsets [rrsets_before + i ],
575589 pkt , num_rrs , timenow , region , 1 , 0 , tree ,
576- s , qtype , dnssec , rr_offset ))
590+ s , qtype , dnssec , rr_offset , compress_count ))
577591 != RETVAL_OK ) {
578592 sldns_buffer_set_position (pkt , setstart );
579593 return r ;
@@ -584,7 +598,7 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
584598 setstart = sldns_buffer_position (pkt );
585599 if ((r = packed_rrset_encode (rep -> rrsets [rrsets_before + i ],
586600 pkt , num_rrs , timenow , region , 0 , 1 , tree ,
587- s , qtype , dnssec , rr_offset ))
601+ s , qtype , dnssec , rr_offset , compress_count ))
588602 != RETVAL_OK ) {
589603 sldns_buffer_set_position (pkt , setstart );
590604 return r ;
@@ -677,6 +691,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
677691 struct compress_tree_node * tree = 0 ;
678692 int r ;
679693 size_t rr_offset ;
694+ size_t compress_count = 0 ;
680695
681696 sldns_buffer_clear (buffer );
682697 if (udpsize < sldns_buffer_limit (buffer ))
@@ -723,7 +738,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
723738 arep .rrsets = & qinfo -> local_alias -> rrset ;
724739 if ((r = insert_section (& arep , 1 , & ancount , buffer , 0 ,
725740 timezero , region , & tree , LDNS_SECTION_ANSWER ,
726- qinfo -> qtype , dnssec , rr_offset )) != RETVAL_OK ) {
741+ qinfo -> qtype , dnssec , rr_offset , & compress_count )) != RETVAL_OK ) {
727742 if (r == RETVAL_TRUNC ) {
728743 /* create truncated message */
729744 sldns_buffer_write_u16_at (buffer , 6 , ancount );
@@ -738,7 +753,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
738753 /* insert answer section */
739754 if ((r = insert_section (rep , rep -> an_numrrsets , & ancount , buffer ,
740755 0 , timenow , region , & tree , LDNS_SECTION_ANSWER , qinfo -> qtype ,
741- dnssec , rr_offset )) != RETVAL_OK ) {
756+ dnssec , rr_offset , & compress_count )) != RETVAL_OK ) {
742757 if (r == RETVAL_TRUNC ) {
743758 /* create truncated message */
744759 sldns_buffer_write_u16_at (buffer , 6 , ancount );
@@ -756,7 +771,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
756771 if ((r = insert_section (rep , rep -> ns_numrrsets , & nscount , buffer ,
757772 rep -> an_numrrsets , timenow , region , & tree ,
758773 LDNS_SECTION_AUTHORITY , qinfo -> qtype ,
759- dnssec , rr_offset )) != RETVAL_OK ) {
774+ dnssec , rr_offset , & compress_count )) != RETVAL_OK ) {
760775 if (r == RETVAL_TRUNC ) {
761776 /* create truncated message */
762777 sldns_buffer_write_u16_at (buffer , 8 , nscount );
@@ -773,7 +788,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
773788 if ((r = insert_section (rep , rep -> ar_numrrsets , & arcount , buffer ,
774789 rep -> an_numrrsets + rep -> ns_numrrsets , timenow , region ,
775790 & tree , LDNS_SECTION_ADDITIONAL , qinfo -> qtype ,
776- dnssec , rr_offset )) != RETVAL_OK ) {
791+ dnssec , rr_offset , & compress_count )) != RETVAL_OK ) {
777792 if (r == RETVAL_TRUNC ) {
778793 /* no need to set TC bit, this is the additional */
779794 sldns_buffer_write_u16_at (buffer , 10 , arcount );
0 commit comments