@@ -74,29 +74,14 @@ public function parseQuestion(Message $message)
7474 return ;
7575 }
7676
77- $ labels = array ();
78-
7977 $ consumed = $ message ->consumed ;
8078
81- $ length = ord (substr ($ message ->data , $ consumed , 1 ));
82- $ consumed += 1 ;
79+ list ($ labels , $ consumed ) = $ this ->readLabels ($ message ->data , $ consumed );
8380
84- if (strlen ( $ message -> data ) - $ consumed < $ length ) {
81+ if (null === $ labels ) {
8582 return ;
8683 }
8784
88- while ($ length !== 0 ) {
89- $ labels [] = substr ($ message ->data , $ consumed , $ length );
90- $ consumed += $ length ;
91-
92- $ length = ord (substr ($ message ->data , $ consumed , 1 ));
93- $ consumed += 1 ;
94-
95- if (strlen ($ message ->data ) - $ consumed < $ length ) {
96- return ;
97- }
98- }
99-
10085 if (strlen ($ message ->data ) - $ consumed < 4 ) {
10186 return ;
10287 }
@@ -127,28 +112,10 @@ public function parseAnswer(Message $message)
127112
128113 $ consumed = $ message ->consumed ;
129114
130- $ mask = 0xc000 ; // 1100000000000000
131- list ($ nameOffset ) = array_merge (unpack ('n ' , substr ($ message ->data , $ consumed , 2 )));
132-
133- if ($ nameOffset & $ mask ) {
134- $ consumed += 2 ;
135- $ labels [] = $ message ->questions [0 ]['name ' ];
136- // TODO: get proper offset
137- } else {
138- $ length = ord (substr ($ message ->data , $ consumed , 1 ));
139- $ consumed += 1 ;
140-
141- while ($ length !== 0 ) {
142- $ labels [] = substr ($ message ->data , $ consumed , $ length );
143- $ consumed += $ length ;
115+ list ($ labels , $ consumed ) = $ this ->readLabels ($ message ->data , $ consumed );
144116
145- $ length = ord (substr ($ message ->data , $ consumed , 1 ));
146- $ consumed += 1 ;
147-
148- if (strlen ($ message ->data ) - $ consumed < $ length ) {
149- return ;
150- }
151- }
117+ if (null === $ labels ) {
118+ return ;
152119 }
153120
154121 if (strlen ($ message ->data ) - $ consumed < 10 ) {
@@ -165,13 +132,20 @@ public function parseAnswer(Message $message)
165132 $ consumed += 2 ;
166133
167134 $ rdata = null ;
135+
168136 if (Message::TYPE_A === $ type ) {
169137 $ ip = substr ($ message ->data , $ consumed , $ rdLength );
170138 $ consumed += $ rdLength ;
171139
172140 $ rdata = inet_ntop ($ ip );
173141 }
174142
143+ if (Message::TYPE_CNAME === $ type ) {
144+ list ($ bodyLabels , $ consumed ) = $ this ->readLabels ($ message ->data , $ consumed );
145+
146+ $ rdata = implode ('. ' , $ bodyLabels );
147+ }
148+
175149 $ message ->consumed = $ consumed ;
176150
177151 $ name = implode ('. ' , $ labels );
@@ -183,6 +157,66 @@ public function parseAnswer(Message $message)
183157 return $ message ;
184158 }
185159
160+ private function readLabels ($ data , $ consumed )
161+ {
162+ $ labels = array ();
163+
164+ while (true ) {
165+ if ($ this ->isEndOfLabels ($ data , $ consumed )) {
166+ $ consumed += 1 ;
167+ break ;
168+ }
169+
170+ if ($ this ->isCompressedLabel ($ data , $ consumed )) {
171+ list ($ newLabels , $ consumed ) = $ this ->getCompressedLabel ($ data , $ consumed );
172+ $ labels = array_merge ($ labels , $ newLabels );
173+ break ;
174+ }
175+
176+ $ length = ord (substr ($ data , $ consumed , 1 ));
177+ $ consumed += 1 ;
178+
179+ if (strlen ($ data ) - $ consumed < $ length ) {
180+ return array (null , null );
181+ }
182+
183+ $ labels [] = substr ($ data , $ consumed , $ length );
184+ $ consumed += $ length ;
185+ }
186+
187+ return array ($ labels , $ consumed );
188+ }
189+
190+ public function isEndOfLabels ($ data , $ consumed )
191+ {
192+ $ length = ord (substr ($ data , $ consumed , 1 ));
193+ return 0 === $ length ;
194+ }
195+
196+ public function getCompressedLabel ($ data , $ consumed )
197+ {
198+ list ($ nameOffset , $ consumed ) = $ this ->getCompressedLabelOffset ($ data , $ consumed );
199+ list ($ labels ) = $ this ->readLabels ($ data , $ nameOffset );
200+
201+ return array ($ labels , $ consumed );
202+ }
203+
204+ public function isCompressedLabel ($ data , $ consumed )
205+ {
206+ $ mask = 0xc000 ; // 1100000000000000
207+ list ($ peek ) = array_merge (unpack ('n ' , substr ($ data , $ consumed , 2 )));
208+
209+ return (bool ) ($ peek & $ mask );
210+ }
211+
212+ public function getCompressedLabelOffset ($ data , $ consumed )
213+ {
214+ $ mask = 0x3fff ; // 0011111111111111
215+ list ($ peek ) = array_merge (unpack ('n ' , substr ($ data , $ consumed , 2 )));
216+
217+ return array ($ peek & $ mask , $ consumed + 2 );
218+ }
219+
186220 public function signedLongToUnsignedLong ($ i )
187221 {
188222 return $ i & 0x80000000 ? $ i - 0xffffffff : $ i ;
0 commit comments