Skip to content

Commit 8a20b48

Browse files
committed
[dns] Implement offset pointers and CNAME messages
1 parent 9a9df33 commit 8a20b48

File tree

1 file changed

+72
-38
lines changed

1 file changed

+72
-38
lines changed

Protocol/Parser.php

Lines changed: 72 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)