@@ -66,7 +66,7 @@ private function parse($data, Message $message)
6666
6767 public function parseHeader (Message $ message )
6868 {
69- if (strlen ($ message ->data ) < 12 ) {
69+ if (! isset ($ message ->data [ 12 - 1 ]) ) {
7070 return ;
7171 }
7272
@@ -97,19 +97,11 @@ public function parseHeader(Message $message)
9797
9898 public function parseQuestion (Message $ message )
9999 {
100- if (strlen ($ message ->data ) < 2 ) {
101- return ;
102- }
103-
104100 $ consumed = $ message ->consumed ;
105101
106102 list ($ labels , $ consumed ) = $ this ->readLabels ($ message ->data , $ consumed );
107103
108- if (null === $ labels ) {
109- return ;
110- }
111-
112- if (strlen ($ message ->data ) - $ consumed < 4 ) {
104+ if ($ labels === null || !isset ($ message ->data [$ consumed + 4 - 1 ])) {
113105 return ;
114106 }
115107
@@ -133,19 +125,11 @@ public function parseQuestion(Message $message)
133125
134126 public function parseAnswer (Message $ message )
135127 {
136- if (strlen ($ message ->data ) < 2 ) {
137- return ;
138- }
139-
140128 $ consumed = $ message ->consumed ;
141129
142- list ($ labels , $ consumed ) = $ this ->readLabels ($ message ->data , $ consumed );
130+ list ($ name , $ consumed ) = $ this ->readDomain ($ message ->data , $ consumed );
143131
144- if (null === $ labels ) {
145- return ;
146- }
147-
148- if (strlen ($ message ->data ) - $ consumed < 10 ) {
132+ if ($ name === null || !isset ($ message ->data [$ consumed + 10 - 1 ])) {
149133 return ;
150134 }
151135
@@ -163,68 +147,85 @@ public function parseAnswer(Message $message)
163147 list ($ rdLength ) = array_values (unpack ('n ' , substr ($ message ->data , $ consumed , 2 )));
164148 $ consumed += 2 ;
165149
166- $ rdata = null ;
150+ if (!isset ($ message ->data [$ consumed + $ rdLength - 1 ])) {
151+ return ;
152+ }
167153
168- if (Message::TYPE_A === $ type || Message::TYPE_AAAA === $ type ) {
169- $ ip = substr ($ message ->data , $ consumed , $ rdLength );
170- $ consumed += $ rdLength ;
154+ $ rdata = null ;
155+ $ expected = $ consumed + $ rdLength ;
171156
172- $ rdata = inet_ntop ($ ip );
157+ if (Message::TYPE_A === $ type ) {
158+ if ($ rdLength === 4 ) {
159+ $ rdata = inet_ntop (substr ($ message ->data , $ consumed , $ rdLength ));
160+ $ consumed += $ rdLength ;
161+ }
162+ } elseif (Message::TYPE_AAAA === $ type ) {
163+ if ($ rdLength === 16 ) {
164+ $ rdata = inet_ntop (substr ($ message ->data , $ consumed , $ rdLength ));
165+ $ consumed += $ rdLength ;
166+ }
173167 } elseif (Message::TYPE_CNAME === $ type || Message::TYPE_PTR === $ type || Message::TYPE_NS === $ type ) {
174- list ($ bodyLabels , $ consumed ) = $ this ->readLabels ($ message ->data , $ consumed );
175-
176- $ rdata = implode ('. ' , $ bodyLabels );
168+ list ($ rdata , $ consumed ) = $ this ->readDomain ($ message ->data , $ consumed );
177169 } elseif (Message::TYPE_TXT === $ type ) {
178170 $ rdata = array ();
179- $ remaining = $ rdLength ;
180- while ($ remaining ) {
171+ while ($ consumed < $ expected ) {
181172 $ len = ord ($ message ->data [$ consumed ]);
182- $ rdata [] = substr ($ message ->data , $ consumed + 1 , $ len );
173+ $ rdata [] = ( string ) substr ($ message ->data , $ consumed + 1 , $ len );
183174 $ consumed += $ len + 1 ;
184- $ remaining -= $ len + 1 ;
185175 }
186176 } elseif (Message::TYPE_MX === $ type ) {
187- list ($ priority ) = array_values (unpack ('n ' , substr ($ message ->data , $ consumed , 2 )));
188- list ($ bodyLabels , $ consumed ) = $ this ->readLabels ($ message ->data , $ consumed + 2 );
189-
190- $ rdata = array (
191- 'priority ' => $ priority ,
192- 'target ' => implode ('. ' , $ bodyLabels )
193- );
177+ if ($ rdLength > 2 ) {
178+ list ($ priority ) = array_values (unpack ('n ' , substr ($ message ->data , $ consumed , 2 )));
179+ list ($ target , $ consumed ) = $ this ->readDomain ($ message ->data , $ consumed + 2 );
180+
181+ $ rdata = array (
182+ 'priority ' => $ priority ,
183+ 'target ' => $ target
184+ );
185+ }
194186 } elseif (Message::TYPE_SRV === $ type ) {
195- list ($ priority , $ weight , $ port ) = array_values (unpack ('n* ' , substr ($ message ->data , $ consumed , 6 )));
196- list ($ bodyLabels , $ consumed ) = $ this ->readLabels ($ message ->data , $ consumed + 6 );
197-
198- $ rdata = array (
199- 'priority ' => $ priority ,
200- 'weight ' => $ weight ,
201- 'port ' => $ port ,
202- 'target ' => implode ('. ' , $ bodyLabels )
203- );
187+ if ($ rdLength > 6 ) {
188+ list ($ priority , $ weight , $ port ) = array_values (unpack ('n* ' , substr ($ message ->data , $ consumed , 6 )));
189+ list ($ target , $ consumed ) = $ this ->readDomain ($ message ->data , $ consumed + 6 );
190+
191+ $ rdata = array (
192+ 'priority ' => $ priority ,
193+ 'weight ' => $ weight ,
194+ 'port ' => $ port ,
195+ 'target ' => $ target
196+ );
197+ }
204198 } elseif (Message::TYPE_SOA === $ type ) {
205- list ($ primaryLabels , $ consumed ) = $ this ->readLabels ($ message ->data , $ consumed );
206- list ($ mailLabels , $ consumed ) = $ this ->readLabels ($ message ->data , $ consumed );
207- list ($ serial , $ refresh , $ retry , $ expire , $ minimum ) = array_values (unpack ('N* ' , substr ($ message ->data , $ consumed , 20 )));
208- $ consumed += 20 ;
209-
210- $ rdata = array (
211- 'mname ' => implode ('. ' , $ primaryLabels ),
212- 'rname ' => implode ('. ' , $ mailLabels ),
213- 'serial ' => $ serial ,
214- 'refresh ' => $ refresh ,
215- 'retry ' => $ retry ,
216- 'expire ' => $ expire ,
217- 'minimum ' => $ minimum
218- );
199+ list ($ mname , $ consumed ) = $ this ->readDomain ($ message ->data , $ consumed );
200+ list ($ rname , $ consumed ) = $ this ->readDomain ($ message ->data , $ consumed );
201+
202+ if ($ mname !== null && $ rname !== null && isset ($ message ->data [$ consumed + 20 - 1 ])) {
203+ list ($ serial , $ refresh , $ retry , $ expire , $ minimum ) = array_values (unpack ('N* ' , substr ($ message ->data , $ consumed , 20 )));
204+ $ consumed += 20 ;
205+
206+ $ rdata = array (
207+ 'mname ' => $ mname ,
208+ 'rname ' => $ rname ,
209+ 'serial ' => $ serial ,
210+ 'refresh ' => $ refresh ,
211+ 'retry ' => $ retry ,
212+ 'expire ' => $ expire ,
213+ 'minimum ' => $ minimum
214+ );
215+ }
219216 } else {
220217 // unknown types simply parse rdata as an opaque binary string
221218 $ rdata = substr ($ message ->data , $ consumed , $ rdLength );
222219 $ consumed += $ rdLength ;
223220 }
224221
222+ // ensure parsing record data consumes expact number of bytes indicated in record length
223+ if ($ consumed !== $ expected || $ rdata === null ) {
224+ return ;
225+ }
226+
225227 $ message ->consumed = $ consumed ;
226228
227- $ name = implode ('. ' , $ labels );
228229 $ record = new Record ($ name , $ type , $ class , $ ttl , $ rdata );
229230
230231 $ message ->answers [] = $ record ;
@@ -236,6 +237,17 @@ public function parseAnswer(Message $message)
236237 return $ message ;
237238 }
238239
240+ private function readDomain ($ data , $ consumed )
241+ {
242+ list ($ labels , $ consumed ) = $ this ->readLabels ($ data , $ consumed );
243+
244+ if ($ labels === null ) {
245+ return array (null , null );
246+ }
247+
248+ return array (implode ('. ' , $ labels ), $ consumed );
249+ }
250+
239251 private function readLabels ($ data , $ consumed )
240252 {
241253 $ labels = array ();
@@ -262,6 +274,7 @@ private function readLabels($data, $consumed)
262274
263275 $ consumed += 2 ;
264276 list ($ newLabels ) = $ this ->readLabels ($ data , $ offset );
277+
265278 if ($ newLabels === null ) {
266279 return array (null , null );
267280 }
0 commit comments