2222
2323import enum
2424import struct
25- from typing import Any , Dict , List , Optional , Sequence , Set , TYPE_CHECKING , Tuple , Union , cast
25+ from typing import Any , Callable , Dict , List , Optional , Sequence , Set , TYPE_CHECKING , Tuple , Union , cast
2626
2727
2828from ._dns import DNSAddress , DNSHinfo , DNSNsec , DNSPointer , DNSQuestion , DNSRecord , DNSService , DNSText
@@ -96,23 +96,39 @@ def __init__(self, data: bytes, scope_id: Optional[int] = None, now: Optional[fl
9696 self .name_cache : Dict [int , List [str ]] = {}
9797 self .seen_pointers : Set [int ] = set ()
9898 self .questions : List [DNSQuestion ] = []
99- self .answers : List [DNSRecord ] = []
99+ self ._answers : List [DNSRecord ] = []
100100 self .id = 0
101101 self .num_questions = 0
102102 self .num_answers = 0
103103 self .num_authorities = 0
104104 self .num_additionals = 0
105105 self .valid = False
106+ self ._read_others = False
106107 self .now = now or current_time_millis ()
107108 self .scope_id = scope_id
109+ self ._parse_data (self ._initial_parse )
108110
109- try :
110- self .read_header ()
111- self .read_questions ()
111+ def _initial_parse (self ) -> None :
112+ """Parse the data needed to initalize the packet object."""
113+ self .read_header ()
114+ self .read_questions ()
115+ if not self .num_questions :
112116 self .read_others ()
113- self .valid = True
117+ self .valid = True
118+
119+ def _parse_data (self , parser_call : Callable ) -> None :
120+ """Parse part of the packet and catch exceptions."""
121+ try :
122+ parser_call ()
114123 except DECODE_EXCEPTIONS :
115- self .log_exception_warning ('Choked at offset %d while unpacking %r' , self .offset , data )
124+ self .log_exception_warning ('Choked at offset %d while unpacking %r' , self .offset , self .data )
125+
126+ @property
127+ def answers (self ) -> List [DNSRecord ]:
128+ """Answers in the packet."""
129+ if not self ._read_others :
130+ self ._parse_data (self .read_others )
131+ return self ._answers
116132
117133 def __repr__ (self ) -> str :
118134 return '<DNSIncoming:{%s}>' % ', ' .join (
@@ -170,6 +186,7 @@ def read_unsigned_short(self) -> int:
170186 def read_others (self ) -> None :
171187 """Reads the answers, authorities and additionals section of the
172188 packet"""
189+ self ._read_others = True
173190 n = self .num_answers + self .num_authorities + self .num_additionals
174191 for _ in range (n ):
175192 domain = self .read_name ()
@@ -192,7 +209,7 @@ def read_others(self) -> None:
192209 exc_info = True ,
193210 )
194211 if rec is not None :
195- self .answers .append (rec )
212+ self ._answers .append (rec )
196213
197214 def read_record (self , domain : str , type_ : int , class_ : int , ttl : int , length : int ) -> Optional [DNSRecord ]:
198215 """Read known records types and skip unknown ones."""
0 commit comments