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 , int | tuple ] = {}
@@ -409,7 +409,7 @@ def _read_name(self) -> str:
409409 labels : list [str ] = []
410410 seen_pointers : set [int ] = set ()
411411 original_offset = self .offset
412- self .offset = self ._decode_labels_at_offset (original_offset , labels , seen_pointers )
412+ self .offset = self ._decode_labels_at_offset (original_offset , labels , seen_pointers , 0 )
413413 self ._name_cache [original_offset ] = labels
414414 name = "." .join (labels ) + "."
415415 if len (name ) > MAX_NAME_LENGTH :
@@ -418,8 +418,14 @@ def _read_name(self) -> str:
418418 )
419419 return name
420420
421- def _decode_labels_at_offset (self , off : _int , labels : list [str ], seen_pointers : set [int ]) -> int :
421+ def _decode_labels_at_offset (
422+ self , off : _int , labels : list [str ], seen_pointers : set [int ], depth : _int
423+ ) -> int :
422424 # This is a tight loop that is called frequently, small optimizations can make a difference.
425+ if depth > MAX_DNS_LABELS :
426+ raise IncomingDecodeError (
427+ f"DNS compression pointer chain exceeds { MAX_DNS_LABELS } at { off } from { self .source } "
428+ )
423429 view = self .view
424430 while off < self ._data_len :
425431 length = view [off ]
@@ -457,7 +463,7 @@ def _decode_labels_at_offset(self, off: _int, labels: list[str], seen_pointers:
457463 if not linked_labels :
458464 linked_labels = []
459465 seen_pointers .add (link_py_int )
460- self ._decode_labels_at_offset (link , linked_labels , seen_pointers )
466+ self ._decode_labels_at_offset (link , linked_labels , seen_pointers , depth + 1 )
461467 self ._name_cache [link_py_int ] = linked_labels
462468 labels .extend (linked_labels )
463469 if len (labels ) > MAX_DNS_LABELS :
0 commit comments