Skip to content

Commit 09d3eb4

Browse files
committed
[Dns] Initial dns resolving code
0 parents  commit 09d3eb4

7 files changed

Lines changed: 238 additions & 0 deletions

File tree

BinaryDumper.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace React\Dns;
4+
5+
class BinaryDumper
6+
{
7+
public function toBinary(Message $message)
8+
{
9+
}
10+
}

Message.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
namespace React\Dns;
4+
5+
class Message
6+
{
7+
const TYPE_A = 1;
8+
const TYPE_NS = 2;
9+
const TYPE_CNAME = 5;
10+
const TYPE_SOA = 6;
11+
const TYPE_PTR = 12;
12+
const TYPE_MX = 15;
13+
const TYPE_TXT = 16;
14+
15+
const CLASS_IN = 1;
16+
17+
const OPCODE_QUERY = 0;
18+
const OPCODE_IQUERY = 1; // inverse query
19+
const OPCODE_STATUS = 2;
20+
21+
public $data = '';
22+
23+
public $header = array();
24+
public $question = array();
25+
public $answer = array();
26+
public $authority = array();
27+
public $additional = array();
28+
29+
public function getId()
30+
{
31+
return $this->header['id'];
32+
}
33+
34+
public function isQuery()
35+
{
36+
return 0 === $this->header['qr'];
37+
}
38+
39+
public function isResponse()
40+
{
41+
return 1 === $this->header['qr'];
42+
}
43+
}

Parser.php

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<?php
2+
3+
namespace React\Dns;
4+
5+
/**
6+
* DNS protocol parser
7+
*
8+
* Obsolete and uncommon types and classes are not implemented.
9+
*/
10+
class Parser
11+
{
12+
public function parseChunk($data, Message $message)
13+
{
14+
$message->data .= $data;
15+
16+
if (!$message->header) {
17+
if (!$this->parseHeader($message)) {
18+
return;
19+
}
20+
}
21+
22+
if ($message->header['qdCount'] != count($message->question)) {
23+
if (!$this->parseQuestion($message)) {
24+
return;
25+
}
26+
}
27+
}
28+
29+
private function parseHeader(Message $message)
30+
{
31+
if (strlen($message->data) < 12) {
32+
return;
33+
}
34+
35+
$header = substr($message->data, 0, 12);
36+
$message->data = substr($message->data, 12);
37+
38+
list($id, $fields, $qdCount, $anCount, $nsCount, $arCount) = array_merge(unpack('n*', $header));
39+
40+
$rcode = $fields & chr(bindec('1111'));
41+
$z = ($fields >> 4) & chr(bindec('111'));
42+
$ra = ($fields >> 7) & 1;
43+
$rd = ($fields >> 8) & 1;
44+
$tc = ($fields >> 9) & 1;
45+
$aa = ($fields >> 10) & 1;
46+
$opcode = ($fields >> 11) & chr(bindec('1111'));
47+
$qr = ($fields >> 15) & 1;
48+
49+
$message->header = compact('id', 'qdCount', 'anCount', 'nsCount', 'arCount',
50+
'qr', 'opcode', 'aa', 'tc', 'rd', 'ra', 'z', 'rcode');
51+
52+
return $message;
53+
}
54+
55+
private function parseQuestion(Message $message)
56+
{
57+
if (strlen($message->data) < 2) {
58+
return;
59+
}
60+
61+
$labels = array();
62+
63+
$consumed = 0;
64+
65+
$length = ord(substr($message->data, $consumed, 1));
66+
$consumed += 1;
67+
68+
if (strlen($message->data) - $consumed < $length) {
69+
return;
70+
}
71+
72+
while ($length !== 0) {
73+
$labels[] = substr($message->data, $consumed, $length);
74+
$consumed += $length;
75+
76+
$length = ord(substr($message->data, $consumed, 1));
77+
$consumed += 1;
78+
79+
if (strlen($message->data) - $consumed < $length) {
80+
return;
81+
}
82+
}
83+
84+
list($type, $class) = array_merge(unpack('n*', substr($message->data, $consumed, 4)));
85+
$consumed += 4;
86+
87+
$message->data = substr($message->data, 0, $consumed);
88+
89+
$message->question[] = array(
90+
'name' => implode('.', $labels),
91+
'type' => $type,
92+
'class' => $class,
93+
);
94+
95+
if ($message->header['qdCount'] != count($message->question)) {
96+
return $this->parseQuestion($message);
97+
}
98+
99+
return $message;
100+
}
101+
102+
public function toBinary(Message $message)
103+
{
104+
}
105+
}

Query.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace React\Dns;
4+
5+
class Query
6+
{
7+
public $name;
8+
public $type;
9+
public $class;
10+
}

Record.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace React\Dns;
4+
5+
class Record
6+
{
7+
public $name;
8+
public $type;
9+
public $class;
10+
public $ttl;
11+
public $data;
12+
}

Resolver.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace React\Dns;
4+
5+
use React\Socket\Connection;
6+
7+
class Resolver
8+
{
9+
public function resolve($domain, $callback)
10+
{
11+
$nameserver = '8.8.8.8';
12+
$query = new Query($domain, 'A', 'IN');
13+
14+
$this->query($nameserver, $query, function (Message $response) use ($callback) {
15+
$answer = $response->answer[array_rand($response->answer)]->data->address;
16+
$callback($address);
17+
});
18+
}
19+
20+
public function query($nameserver, Query $query, $callback)
21+
{
22+
$dumper = new BinaryDumper();
23+
$parser = new Parser();
24+
25+
$message = new Message();
26+
$message->header = array(
27+
$query...
28+
);
29+
$message->question = array(
30+
$query...
31+
);
32+
33+
$response = new Message();
34+
35+
$conn = new Connection(fopen("udp://$nameserver:53"), $this->loop);
36+
$conn->on('data', function ($data) use ($conn, $response, $callback) {
37+
if ($parser->parseChunk($data, $response)) {
38+
$conn->end();
39+
$callback($response);
40+
}
41+
});
42+
$conn->write($dumper->toBinary($message));
43+
}
44+
}

composer.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "react/dns",
3+
"description": "Async DNS resolver.",
4+
"keywords": ["dns", "dns-resolver"],
5+
"license": "MIT",
6+
"require": {
7+
"php": ">=5.3.2",
8+
"react/socket": "dev-master"
9+
},
10+
"autoload": {
11+
"psr-0": { "React\\Dns": "" }
12+
},
13+
"target-dir": "React/Dns"
14+
}

0 commit comments

Comments
 (0)