Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
50 changes: 50 additions & 0 deletions examples/11-query-any.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

use React\Dns\Model\Message;
use React\Dns\Model\Record;
use React\Dns\Query\Query;
use React\Dns\Query\UdpTransportExecutor;
use React\EventLoop\Factory;

require __DIR__ . '/../vendor/autoload.php';

$loop = Factory::create();
$executor = new UdpTransportExecutor($loop);

$name = isset($argv[1]) ? $argv[1] : 'google.com';

$any = new Query($name, Message::TYPE_ANY, Message::CLASS_IN);

$executor->query('8.8.8.8:53', $any)->then(function (Message $message) {
foreach ($message->answers as $answer) {
/* @var $answer Record */

$data = $answer->data;

switch ($answer->type) {
case Message::TYPE_A:
$type = 'A';
break;
case Message::TYPE_AAAA:
$type = 'AAAA';
break;
case Message::TYPE_NS:
$type = 'NS';
break;
case Message::TYPE_PTR:
$type = 'PTR';
break;
case Message::TYPE_CNAME:
$type = 'CNAME';
break;
default:
// unknown type uses HEX format
$type = 'Type ' . $answer->type;
$data = wordwrap(strtoupper(bin2hex($data)), 2, ' ', true);
}

echo $type . ': ' . $data . PHP_EOL;
}
}, 'printf');

$loop->run();
1 change: 1 addition & 0 deletions src/Model/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class Message
const TYPE_MX = 15;
const TYPE_TXT = 16;
const TYPE_AAAA = 28;
const TYPE_ANY = 255;

const CLASS_IN = 1;

Expand Down
39 changes: 39 additions & 0 deletions src/Model/Record.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,49 @@

class Record
{
/**
* @var string hostname without trailing dot, for example "reactphp.org"
*/
public $name;

/**
* @var int see Message::TYPE_* constants (UINT16)
*/
public $type;

/**
* @var int see Message::CLASS_IN constant (UINT16)
*/
public $class;

/**
* @var int maximum TTL in seconds (UINT16)
*/
public $ttl;

/**
* The payload data for this record
*
* The payload data format depends on the record type. As a rule of thumb,
* this library will try to express this in a way that can be consumed
* easily without having to worry about DNS internals and its binary transport:
*
* - A:
* IPv4 address string, for example "192.168.1.1".
* - AAAA:
* IPv6 address string, for example "::1".
* - CNAME / PTR / NS:
* The hostname without trailing dot, for example "reactphp.org".
* - Any other unknown type:
* An opaque binary string containing the RDATA as transported in the DNS
* record. For forwards compatibility, you should not rely on this format
* for unknown types. Future versions may add support for new types and
* this may then parse the payload data appropriately - this will not be
* considered a BC break. See the format definition of known types above
* for more details.
*
* @var string
*/
public $data;

public function __construct($name, $type, $class, $ttl = 0, $data = null)
Expand Down
8 changes: 5 additions & 3 deletions src/Protocol/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,14 @@ public function parseAnswer(Message $message)
$consumed += $rdLength;

$rdata = inet_ntop($ip);
}

if (Message::TYPE_CNAME === $type || Message::TYPE_PTR === $type) {
} elseif (Message::TYPE_CNAME === $type || Message::TYPE_PTR === $type || Message::TYPE_NS === $type) {
list($bodyLabels, $consumed) = $this->readLabels($message->data, $consumed);

$rdata = implode('.', $bodyLabels);
} else {
// unknown types simply parse rdata as an opaque binary string
$rdata = substr($message->data, $consumed, $rdLength);
$consumed += $rdLength;
}

$message->consumed = $consumed;
Expand Down
50 changes: 50 additions & 0 deletions tests/Protocol/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,31 @@ public function testParseAnswerWithInlineData()
$this->assertSame('178.79.169.131', $response->answers[0]->data);
}

public function testParseAnswerWithUnknownType()
{
$data = "";
$data .= "04 69 67 6f 72 02 69 6f 00"; // answer: igor.io
$data .= "23 28 00 01"; // answer: type 9000, class IN
$data .= "00 01 51 80"; // answer: ttl 86400
$data .= "00 05"; // answer: rdlength 5
$data .= "68 65 6c 6c 6f"; // answer: rdata "hello"

$data = $this->convertTcpDumpToBinary($data);

$response = new Message();
$response->header->set('anCount', 1);
$response->data = $data;

$this->parser->parseAnswer($response);

$this->assertCount(1, $response->answers);
$this->assertSame('igor.io', $response->answers[0]->name);
$this->assertSame(9000, $response->answers[0]->type);
$this->assertSame(Message::CLASS_IN, $response->answers[0]->class);
$this->assertSame(86400, $response->answers[0]->ttl);
$this->assertSame('hello', $response->answers[0]->data);
}

public function testParseResponseWithCnameAndOffsetPointers()
{
$data = "";
Expand Down Expand Up @@ -273,6 +298,31 @@ public function testParseResponseWithTwoAnswers()
$this->assertSame('193.223.78.152', $response->answers[1]->data);
}

public function testParseNSResponse()
{
$data = "";
$data .= "04 69 67 6f 72 02 69 6f 00"; // answer: igor.io
$data .= "00 02 00 01"; // answer: type NS, class IN
$data .= "00 01 51 80"; // answer: ttl 86400
$data .= "00 07"; // answer: rdlength 7
$data .= "05 68 65 6c 6c 6f 00"; // answer: rdata hello

$data = $this->convertTcpDumpToBinary($data);

$response = new Message();
$response->header->set('anCount', 1);
$response->data = $data;

$this->parser->parseAnswer($response);

$this->assertCount(1, $response->answers);
$this->assertSame('igor.io', $response->answers[0]->name);
$this->assertSame(Message::TYPE_NS, $response->answers[0]->type);
$this->assertSame(Message::CLASS_IN, $response->answers[0]->class);
$this->assertSame(86400, $response->answers[0]->ttl);
$this->assertSame('hello', $response->answers[0]->data);
}

public function testParsePTRResponse()
{
$data = "";
Expand Down