6060MAX_DNS_LABELS = 128
6161MAX_NAME_LENGTH = 253
6262
63- DECODE_EXCEPTIONS = (IndexError , struct .error , IncomingDecodeError )
63+ DECODE_EXCEPTIONS = (IndexError , struct .error , IncomingDecodeError , RecursionError )
6464
6565
6666_seen_logs : dict [str , None ] = {}
@@ -403,7 +403,7 @@ def _read_name(self) -> str:
403403 labels : list [str ] = []
404404 seen_pointers : set [int ] = set ()
405405 original_offset = self .offset
406- self .offset = self ._decode_labels_at_offset (original_offset , labels , seen_pointers )
406+ self .offset = self ._decode_labels_at_offset (original_offset , labels , seen_pointers , 0 )
407407 self ._name_cache [original_offset ] = labels
408408 name = "." .join (labels ) + "."
409409 if len (name ) > MAX_NAME_LENGTH :
@@ -412,8 +412,14 @@ def _read_name(self) -> str:
412412 )
413413 return name
414414
415- def _decode_labels_at_offset (self , off : _int , labels : list [str ], seen_pointers : set [int ]) -> int :
415+ def _decode_labels_at_offset (
416+ self , off : _int , labels : list [str ], seen_pointers : set [int ], depth : _int
417+ ) -> int :
416418 # This is a tight loop that is called frequently, small optimizations can make a difference.
419+ if depth > MAX_DNS_LABELS :
420+ raise IncomingDecodeError (
421+ f"DNS compression pointer chain exceeds { MAX_DNS_LABELS } at { off } from { self .source } "
422+ )
417423 view = self .view
418424 while off < self ._data_len :
419425 length = view [off ]
@@ -451,7 +457,7 @@ def _decode_labels_at_offset(self, off: _int, labels: list[str], seen_pointers:
451457 if not linked_labels :
452458 linked_labels = []
453459 seen_pointers .add (link_py_int )
454- self ._decode_labels_at_offset (link , linked_labels , seen_pointers )
460+ self ._decode_labels_at_offset (link , linked_labels , seen_pointers , depth + 1 )
455461 self ._name_cache [link_py_int ] = linked_labels
456462 labels .extend (linked_labels )
457463 if len (labels ) > MAX_DNS_LABELS :
0 commit comments