1
0
mirror of https://github.com/danog/LibDNSNative.git synced 2024-11-29 20:19:08 +01:00

First commit

This commit is contained in:
Daniil Gentili 2019-07-15 14:41:26 +02:00
commit 5a3a88d018
18 changed files with 929 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
.vscode
build
composer.lock
phpunit.xml
vendor
.php_cs.cache
coverage

13
.php_cs.dist Normal file
View File

@ -0,0 +1,13 @@
<?php
$config = new Amp\CodeStyle\Config();
$config->getFinder()
->in(__DIR__ . '/examples')
->in(__DIR__ . '/lib')
->in(__DIR__ . '/test');
$cacheDir = getenv('TRAVIS') ? getenv('HOME') . '/.php-cs-fixer' : __DIR__;
$config->setCacheFile($cacheDir . '/.php_cs.cache');
return $config;

37
.travis.yml Normal file
View File

@ -0,0 +1,37 @@
sudo: false
language: php
php:
- 7.0
- 7.1
- 7.2
- 7.3
- nightly
matrix:
allow_failures:
- php: nightly
fast_finish: true
before_install:
- phpenv config-rm xdebug.ini || echo "No xdebug config."
install:
- composer update -n --prefer-dist
- wget https://github.com/php-coveralls/php-coveralls/releases/download/v1.0.2/coveralls.phar
- chmod +x coveralls.phar
script:
- vendor/bin/phpunit --coverage-text --coverage-clover build/logs/clover.xml
- PHP_CS_FIXER_IGNORE_ENV=1 php vendor/bin/php-cs-fixer --diff --dry-run -v fix
after_script:
- ./coveralls.phar -v
cache:
directories:
- $HOME/.composer/cache
- $HOME/.php-cs-fixer
- $HOME/.local

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015-2017 amphp
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

47
README.md Normal file
View File

@ -0,0 +1,47 @@
# LibDNSNative
[![Build Status](https://img.shields.io/travis/danog/libdnsnative/master.svg?style=flat-square)](https://travis-ci.org/danog/libdnsnative)
![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)
Encoder/decoder for the raw format of [PHP's dns_get_record function](https://www.php.net/manual/en/function.dns-get-record.php) based on [libdns](https://github.com/DaveRandom/LibDNS/): allows usage of the function to fetch **all kinds of DNS records**, not just the ones supported by the `DNS_` constants.
The API consists of a `NativeEncoderFactory` that creates `NativeEncoder` objects, that can encode libdns `Message` objects to a list of parameters that that must be passed to the `dns_get_record` function.
The `NativeDecoderFactory` creates `NativeDecoder` objects, that accept the results of the `dns_get_record` function and decode them back to `Message` objects.
## Installation
```
composer require danog/libdns-native
```
## Usage
```php
<?php
require 'vendor/autoload.php';
use danog\LibDNSNative\NativeEncoderFactory;
use danog\LibDNSNative\NativeDecoderFactory;
use LibDNS\Records\QuestionFactory;
use LibDNS\Records\ResourceQTypes;
use LibDNS\Messages\MessageFactory;
use LibDNS\Messages\MessageTypes;
$question = (new QuestionFactory)->create(ResourceQTypes::DNSKEY);
$question->setName('daniil.it');
$message = (new MessageFactory)->create(MessageTypes::QUERY);
$records = $message->getQuestionRecords();
$records->add($question);
$encoder = (new NativeEncoderFactory)->create();
$question = $encoder->encode($message);
$result = dns_get_record(...$question);
$decoder = (new NativeDecoderFactory)->create();
$result = $decoder->decode($result, ...$question);
```

38
appveyor.yml Normal file
View File

@ -0,0 +1,38 @@
build: false
shallow_clone: false
platform:
- x86
- x64
clone_folder: c:\projects\libdns
cache:
- c:\tools\php73 -> appveyor.yml
init:
- SET PATH=C:\Program Files\OpenSSL;c:\tools\php73;%PATH%
- SET COMPOSER_NO_INTERACTION=1
- SET PHP=1
- SET ANSICON=121x90 (121x90)
install:
- IF EXIST c:\tools\php73 (SET PHP=0)
- IF %PHP%==1 sc config wuauserv start= auto
- IF %PHP%==1 net start wuauserv
- IF %PHP%==1 cinst -y OpenSSL.Light
- IF %PHP%==1 cinst -y php
- cd c:\tools\php73
- IF %PHP%==1 copy php.ini-production php.ini /Y
- IF %PHP%==1 echo date.timezone="UTC" >> php.ini
- IF %PHP%==1 echo extension_dir=ext >> php.ini
- IF %PHP%==1 echo extension=php_openssl.dll >> php.ini
- IF %PHP%==1 echo extension=php_mbstring.dll >> php.ini
- IF %PHP%==1 echo extension=php_fileinfo.dll >> php.ini
- cd c:\projects\libdns
- appveyor DownloadFile https://getcomposer.org/composer.phar
- php composer.phar install --prefer-dist --no-progress
test_script:
- cd c:\projects\libdns
- vendor/bin/phpunit --colors=always

49
composer.json Normal file
View File

@ -0,0 +1,49 @@
{
"name": "danog/libdns-native",
"homepage": "https://github.com/danog/libdns-natie",
"description": "Encoder/decoder for PHP's dns_get_record raw format based on libdns",
"keywords": [
"dns",
"message",
"dns_get_record",
"php",
"native function"
],
"license": "MIT",
"authors": [{
"name": "Daniil Gentili",
"email": "daniil@daniil.it"
},
{
"name": "Chris Wright",
"email": "addr@daverandom.com"
}
],
"require": {
"php": ">=7.0",
"daverandom/libdns": "^2.0.1"
},
"require-dev": {
"amphp/php-cs-fixer-config": "dev-master",
"phpunit/phpunit": "^6"
},
"autoload": {
"psr-4": {
"danog\\LibDNSNative\\": "lib"
}
},
"autoload-dev": {
"psr-4": {
"danog\\LibDNSNative\\Test\\": "test"
}
},
"scripts": {
"check": [
"@cs",
"@test"
],
"cs": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff --dry-run",
"cs-fix": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff",
"test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit --coverage-text"
}
}

0
examples/.gitkeep Normal file
View File

26
examples/simple.php Normal file
View File

@ -0,0 +1,26 @@
<?php
use danog\LibDNSNative\NativeEncoderFactory;
use LibDNS\Records\QuestionFactory;
use danog\LibDNSNative\NativeDecoderFactory;
use LibDNS\Records\ResourceQTypes;
use LibDNS\Messages\MessageFactory;
use LibDNS\Messages\MessageTypes;
require 'vendor/autoload.php';
$question = (new QuestionFactory)->create(ResourceQTypes::DNSKEY);
$question->setName('daniil.it');
$message = (new MessageFactory)->create(MessageTypes::QUERY);
$records = $message->getQuestionRecords();
$records->add($question);
$encoder = (new NativeEncoderFactory)->create();
$question = $encoder->encode($message);
$result = dns_get_record(...$question);
$decoder = (new NativeDecoderFactory)->create();
$result = $decoder->decode($result, ...$question);
var_dump($result);

282
lib/NativeDecoder.php Normal file
View File

@ -0,0 +1,282 @@
<?php
namespace danog\LibDNSNative;
use LibDNS\Decoder\Decoder;
use LibDNS\Decoder\DecoderFactory;
use LibDNS\Encoder\EncodingContext;
use LibDNS\Encoder\EncodingContextFactory;
use LibDNS\Messages\Message;
use LibDNS\Messages\MessageFactory;
use LibDNS\Messages\MessageTypes;
use LibDNS\Packets\PacketFactory;
use LibDNS\Records\Question;
use LibDNS\Records\QuestionFactory;
use LibDNS\Records\Resource;
use LibDNS\Records\Types\DomainName;
use LibDNS\Records\Types\Type;
use LibDNS\Records\Types\TypeBuilder;
use LibDNS\Records\Types\Types;
/**
* Decodes JSON DNS strings to Message objects.
*
* @author Daniil Gentili <https://daniil.it>, Chris Wright <https://github.com/DaveRandom>
*/
class NativeDecoder
{
/**
* @var \LibDNS\Packets\PacketFactory
*/
private $packetFactory;
/**
* @var \LibDNS\Messages\MessageFactory
*/
private $messageFactory;
/**
* @var \LibDNS\Records\QuestionFactory
*/
private $questionFactory;
/**
* @var \LibDNS\Records\Types\TypeBuilder
*/
private $typeBuilder;
/**
* @var \LibDNS\Decoder\DecoderFactory
*/
private $decoderFactory;
/**
* Map class names to IDs
*
* @var array
*/
private $classMap = [];
/**
* Constructor.
*
* @param \LibDNS\Packets\PacketFactory $packetFactory
* @param \LibDNS\Messages\MessageFactory $messageFactory
* @param \LibDNS\Records\QuestionFactory $questionFactory
* @param \LibDNS\Records\Types\TypeBuilder $typeBuilder
* @param \LibDNS\Encoder\EncodingContextFactory $encodingContextFactory
* @param \LibDNS\Decoder\DecoderFactory $decoderFactory
* @param bool $allowTrailingData
*/
public function __construct(
PacketFactory $packetFactory,
MessageFactory $messageFactory,
QuestionFactory $questionFactory,
TypeBuilder $typeBuilder,
EncodingContextFactory $encodingContextFactory,
DecoderFactory $decoderFactory
) {
$this->packetFactory = $packetFactory;
$this->messageFactory = $messageFactory;
$this->questionFactory = $questionFactory;
$this->typeBuilder = $typeBuilder;
$this->encodingContextFactory = $encodingContextFactory;
$this->decoderFactory = $decoderFactory;
$classes = new \ReflectionClass('\\LibDNS\\Records\\ResourceClasses');
foreach ($classes->getConstants() as $name => $value) {
$this->classMap[$name] = $value;
}
}
/**
* Decode a question record.
*
*
* @return \LibDNS\Records\Question
* @throws \UnexpectedValueException When the record is invalid
*/
private function decodeQuestionRecord(string $name, int $type): Question
{
/** @var \LibDNS\Records\Types\DomainName $domainName */
$domainName = $this->typeBuilder->build(Types::DOMAIN_NAME);
$labels = \explode('.', $name);
if (!empty($last = \array_pop($labels))) {
$labels[] = $last;
}
$domainName->setLabels($labels);
$question = $this->questionFactory->create($type);
$question->setName($domainName);
//$question->setClass($meta['class']);
return $question;
}
/**
* Encode a question record
*
* @param \LibDNS\Encoder\EncodingContext $encodingContext
* @param \LibDNS\Records\Question $record
*/
private function encodeQuestionRecord(EncodingContext $encodingContext, string $name, int $type)
{
if (!$encodingContext->isTruncated()) {
$packet = $encodingContext->getPacket();
$record = $this->decodeQuestionRecord($name, $type);
$name = $this->encodeDomainName($record->getName(), $encodingContext);
$meta = \pack('n*', $record->getType(), $record->getClass());
if (12 + $packet->getLength()+\strlen($name) + 4 > 512) {
$encodingContext->isTruncated(true);
} else {
$packet->write($name);
$packet->write($meta);
}
}
}
/**
* Encode a DomainName field
*
* @param \LibDNS\Records\Types\DomainName $domainName
* @param \LibDNS\Encoder\EncodingContext $encodingContext
* @return string
*/
private function encodeDomainName(DomainName $domainName, EncodingContext $encodingContext): string
{
$packetIndex = $encodingContext->getPacket()->getLength() + 12;
$labelRegistry = $encodingContext->getLabelRegistry();
$result = '';
$labels = $domainName->getLabels();
if ($encodingContext->useCompression()) {
do {
$part = \implode('.', $labels);
$index = $labelRegistry->lookupIndex($part);
if ($index === null) {
$labelRegistry->register($part, $packetIndex);
$label = \array_shift($labels);
$length = \strlen($label);
$result .= \chr($length).$label;
$packetIndex += $length + 1;
} else {
$result .= \pack('n', 0b1100000000000000 | $index);
break;
}
} while ($labels);
if (!$labels) {
$result .= "\x00";
}
} else {
foreach ($labels as $label) {
$result .= \chr(\strlen($label)).$label;
}
$result .= "\x00";
}
return $result;
}
/**
* Encode a resource record
*
* @param \LibDNS\Encoder\EncodingContext $encodingContext
* @param array $record
*/
private function encodeResourceRecord(EncodingContext $encodingContext, array $record)
{
if (!$encodingContext->isTruncated()) {
/** @var \LibDNS\Records\Types\DomainName $domainName */
$domainName = $this->typeBuilder->build(Types::DOMAIN_NAME);
$labels = \explode('.', $record['host']);
if (!empty($last = \array_pop($labels))) {
$labels[] = $last;
}
$domainName->setLabels($labels);
$packet = $encodingContext->getPacket();
$name = $this->encodeDomainName($domainName, $encodingContext);
$data = $record['data'];
$meta = \pack('n2Nn', $record['type'], $this->classMap[$record['class']], $record['ttl'], \strlen($data));
if (12 + $packet->getLength()+\strlen($name) + 10+\strlen($data) > 512) {
$encodingContext->isTruncated(true);
} else {
$packet->write($name);
$packet->write($meta);
$packet->write($data);
}
}
}
/**
* Decode a Message from JSON-encoded string.
*
* @param array $result The actual response
* @param string $domain The domain name that was queried
* @param int $type The record type that was queried
* @param array $authoritative Authoritative NS results
* @param array $additional Additional results
* @return \LibDNS\Messages\Message
* @throws \UnexpectedValueException When the packet data is invalid
* @throws \InvalidArgumentException When a type subtype is unknown
*/
public function decode(array $result, string $domain, int $type, array $authoritative = null, array $additional = null): Message
{
$additional = $additional ?? [];
$authoritative = $additional ?? [];
$packet = $this->packetFactory->create();
$encodingContext = $this->encodingContextFactory->create($packet, false);
$message = $this->messageFactory->create();
//$message->isAuthoritative(true);
$message->setType(MessageTypes::RESPONSE);
//$message->setID($requestId);
$message->setResponseCode(0);
$message->isTruncated(false);
$message->isRecursionDesired(false);
$message->isRecursionAvailable(false);
$this->encodeQuestionRecord($encodingContext, $domain, $type);
$expectedAnswers = count($result);
for ($i = 0; $i < $expectedAnswers; $i++) {
$this->encodeResourceRecord($encodingContext, $result[$i]);
}
$expectedAuth = count($authoritative);
for ($i = 0; $i < $expectedAuth; $i++) {
$this->encodeResourceRecord($encodingContext, $authoritative[$i]);
}
$expectedAdditional = count($additional);
for ($i = 0; $i < $expectedAdditional; $i++) {
$this->encodeResourceRecord($encodingContext, $additional[$i]);
}
$header = [
'id' => $message->getID(),
'meta' => 0,
'qd' => 1,
'an' => $expectedAnswers,
'ns' => $expectedAuth,
'ar' => $expectedAdditional,
];
$header['meta'] |= $message->getType() << 15;
$header['meta'] |= $message->getOpCode() << 11;
$header['meta'] |= ((int) $message->isAuthoritative()) << 10;
$header['meta'] |= ((int) $encodingContext->isTruncated()) << 9;
$header['meta'] |= ((int) $message->isRecursionDesired()) << 8;
$header['meta'] |= ((int) $message->isRecursionAvailable()) << 7;
$header['meta'] |= $message->getResponseCode();
$data = \pack('n*', $header['id'], $header['meta'], $header['qd'], $header['an'], $header['ns'], $header['ar']).$packet->read($packet->getLength());
return $this->decoderFactory->create()->decode($data);
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* Creates NativeDecoder objects.
*
* @author Daniil Gentili <https://daniil.it>, Chris Wright <https://github.com/DaveRandom>
* @copyright Copyright (c) Chris Wright <https://github.com/DaveRandom>,
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
namespace danog\LibDNSNative;
use LibDNS\Decoder\DecodingContextFactory;
use \LibDNS\Messages\MessageFactory;
use \LibDNS\Packets\PacketFactory;
use \LibDNS\Records\QuestionFactory;
use \LibDNS\Records\RDataBuilder;
use \LibDNS\Records\RDataFactory;
use \LibDNS\Records\RecordCollectionFactory;
use \LibDNS\Records\ResourceBuilder;
use \LibDNS\Records\ResourceFactory;
use \LibDNS\Records\TypeDefinitions\FieldDefinitionFactory;
use \LibDNS\Records\TypeDefinitions\TypeDefinitionFactory;
use \LibDNS\Records\TypeDefinitions\TypeDefinitionManager;
use \LibDNS\Records\Types\TypeBuilder;
use \LibDNS\Records\Types\TypeFactory;
use LibDNS\Decoder\DecoderFactory;
use LibDNS\Encoder\EncodingContextFactory;
/**
* Creates NativeDecoder objects.
*
* @author Daniil Gentili <https://daniil.it>, Chris Wright <https://github.com/DaveRandom>
*/
class NativeDecoderFactory
{
/**
* Create a new NativeDecoder object.
*
* @param \LibDNS\Records\TypeDefinitions\TypeDefinitionManager $typeDefinitionManager
* @return NativeDecoder
*/
public function create(TypeDefinitionManager $typeDefinitionManager = null): NativeDecoder
{
$typeBuilder = new TypeBuilder(new TypeFactory);
return new NativeDecoder(
new PacketFactory,
new MessageFactory(new RecordCollectionFactory),
new QuestionFactory,
$typeBuilder,
new EncodingContextFactory,
new DecoderFactory
);
}
}

59
lib/NativeEncoder.php Normal file
View File

@ -0,0 +1,59 @@
<?php declare (strict_types = 1);
/**
* Encodes Message objects to query strings.
*
* PHP version 5.4
*
* @category LibDNS
* @package Encoder
* @author Daniil Gentili <https://daniil.it>, Chris Wright <https://github.com/DaveRandom>
* @copyright Copyright (c) Chris Wright <https://github.com/DaveRandom>
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 2.0.0
*/
namespace danog\LibDNSNative;
use LibDNS\Messages\MessageTypes;
use \LibDNS\Messages\Message;
use LibDNS\Records\ResourceQTypes;
/**
* Encodes Message objects to query strings.
*
* @category LibDNS
* @package Encoder
* @author Daniil Gentili <https://daniil.it>, Chris Wright <https://github.com/DaveRandom>
*/
class NativeEncoder
{
/**
* Encode a Message to URL payload.
*
* @param \LibDNS\Messages\Message $message The Message to encode
* @return array Array of parameters to pass to the \dns_get_record function
*/
public function encode(Message $message): array
{
if ($message->getType() !== MessageTypes::QUERY) {
throw new \InvalidArgumentException('Invalid question: is not a question record');
}
$questions = $message->getQuestionRecords();
if ($questions->count() === 0) {
throw new \InvalidArgumentException('Invalid question: 0 question records provided');
}
if ($questions->count() !== 1) {
throw new \InvalidArgumentException('Invalid question: only one question record can be provided at a time');
}
$question = $questions->getRecordByIndex(0);
return [
\implode('.', $question->getName()->getLabels()), // Name
$question->getType(), // Type
null, // Authority records
null, // Additional records
true, // Raw results
];
}
}

View File

@ -0,0 +1,35 @@
<?php declare (strict_types = 1);
/**
* Creates NativeEncoder objects.
*
* PHP version 5.4
*
* @category LibDNS
* @package Encoder
* @author Daniil Gentili <https://daniil.it>, Chris Wright <https://github.com/DaveRandom>
* @copyright Copyright (c) Chris Wright <https://github.com/DaveRandom>
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 2.0.0
*/
namespace danog\LibDNSNative;
/**
* Creates NativeEncoder objects.
*
* @category LibDNS
* @package Encoder
* @author Daniil Gentili <https://daniil.it>, Chris Wright <https://github.com/DaveRandom>
*/
class NativeEncoderFactory
{
/**
* Create a new Encoder object.
*
* @return \LibDNS\Encoder\Encoder
*/
public function create(): NativeEncoder
{
return new NativeEncoder();
}
}

25
phpunit.xml.dist Normal file
View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/6.0/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
>
<testsuites>
<testsuite name="Main">
<directory>test</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">lib</directory>
</whitelist>
</filter>
</phpunit>

View File

@ -0,0 +1,15 @@
<?php
namespace danog\LibDNSNative\Test;
use danog\LibDNSNative\NativeDecoder;
use danog\LibDNSNative\NativeDecoderFactory;
use PHPUnit\Framework\TestCase;
class NativeDecoderFactoryTest extends TestCase
{
public function testNativeDecoderFactoryWorks()
{
$this->assertInstanceOf(NativeDecoder::class, (new NativeDecoderFactory)->create());
}
}

155
test/NativeDecoderTest.php Normal file
View File

@ -0,0 +1,155 @@
<?php
namespace danog\LibDNSNative\Test;
use danog\LibDNSNative\NativeDecoderFactory;
use LibDNS\Messages\Message;
use LibDNS\Messages\MessageTypes;
use LibDNS\Records\ResourceQTypes;
use PHPUnit\Framework\TestCase;
class NativeDecoderTest extends TestCase
{
/**
* Test decoding of valid Native DNS payloads.
*
* @param string $message
* @param int $requestId
* @return void
*
* @dataProvider provideValidNativePayloads
*/
public function testDecodesValidNativePayloads(array $result, string $name, int $type, array $auth = null, array $additional = null)
{
$decoder = (new NativeDecoderFactory)->create();
$response = $decoder->decode($result, $name, $type, $auth, $additional);
$this->assertInstanceOf(Message::class, $response);
$this->assertEquals(MessageTypes::RESPONSE, $response->getType());
}
public function provideValidNativePayloads()
{
return [
[
[
[
'host' => 'daniil.it',
'class' => 'IN',
'ttl' => 3600,
'type' => 48,
'data' => base64_decode('AQADDaCTEREs+ROIGM0v6ulw671NajD2CIwlsyWjmrvFzRGXqgmCg+Wq9CEXfCql1xSZKplX0bzBj5jNcfHxgGtl4Ug='),
],
[
'host' => 'daniil.it',
'class' => 'IN',
'ttl' => 3600,
'type' => 48,
'data' => base64_decode('AQEDDZnbLMFMq9wz1td9pjovFfcRElhPI06NHcQo456KSpfhqicaVV3JBwHhfipMS28SC3wy1E9KwCvYlM8tS+d3ihk='),
],
],
'daniil.it',
ResourceQTypes::DNSKEY,
[
],
null,
],
[
[
[
'host' => 'apple.com',
'class' => 'IN',
'ttl' => 2898,
'type' => 1,
'data' => base64_decode('EazgLw=='),
],
[
'host' => 'apple.com',
'class' => 'IN',
'ttl' => 2898,
'type' => 1,
'data' => base64_decode('EY6gOw=='),
],
[
'host' => 'apple.com',
'class' => 'IN',
'ttl' => 2898,
'type' => 1,
'data' => base64_decode('EbJgOw=='),
],
],
'apple.com',
ResourceQTypes::A,
[
],
null,
],
[
[
[
'host' => 'amphp.org',
'class' => 'IN',
'ttl' => 166,
'type' => 1,
'data' => base64_decode('aBgUIg=='),
],
[
'host' => 'amphp.org',
'class' => 'IN',
'ttl' => 166,
'type' => 1,
'data' => base64_decode('aBgVIg=='),
],
],
'amphp.org',
ResourceQTypes::A,
[
],
null,
],
[
[
[
'host' => 'tssthacks.daniil.it',
'class' => 'IN',
'ttl' => 282,
'type' => 5,
'data' => base64_decode('A2docwxnb29nbGVob3N0ZWQDY29tAA=='),
],
],
'tssthacks.daniil.it',
ResourceQTypes::CNAME,
null,
null,
],
[
[
[
'host' => 'daniil.it',
'class' => 'IN',
'ttl' => 289,
'type' => 15,
'data' => base64_decode('AAoCbXgGeWFuZGV4A25ldAA='),
],
],
'daniil.it',
ResourceQTypes::MX,
[
],
null,
],
];
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace danog\LibDNSNative\Test;
use danog\LibDNSNative\NativeEncoder;
use danog\LibDNSNative\NativeEncoderFactory;
use PHPUnit\Framework\TestCase;
class NativeEncoderFactoryTest extends TestCase
{
public function testNativeEncoderFactoryWorks()
{
$this->assertInstanceOf(NativeEncoder::class, (new NativeEncoderFactory)->create());
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace danog\LibDNSNative\Test;
use danog\LibDNSNative\NativeDecoderFactory;
use danog\LibDNSNative\NativeEncoderFactory;
use LibDNS\Messages\MessageTypes;
use PHPUnit\Framework\TestCase;
use LibDNS\Records\ResourceQTypes;
class NativeEncoderTest extends TestCase
{
/**
* Test encoding of valid DNS message payloads.
*
* @param string $message
* @return void
*
* @dataProvider provideValidNativePayloads
*/
public function testEncodesValidNativePayloads(string $name, int $type)
{
$decoder = (new NativeDecoderFactory)->create();
$response = $decoder->decode([], $name, $type, [], [], [], 0);
$response->setType(MessageTypes::QUERY);
$encoder = (new NativeEncoderFactory)->create();
$request = $encoder->encode($response);
$this->assertInternalType('array', $request, "Got a ".\gettype($request)." instead of an array");
$this->assertCount(5, $request);
$this->assertInternalType('string', $request[0], "Got a ".\gettype($request[0])." instead of a string");
$this->assertInternalType('int', $request[1], "Got a ".\gettype($request[1])." instead of an int");
$this->assertEquals($name, $request[0]);
$this->assertEquals($type, $request[1]);
$this->assertEquals($request[1], $response->getQuestionRecords()->getRecordByIndex(0)->getType());
$this->assertEquals($request[0], \implode('.', $response->getQuestionRecords()->getRecordByIndex(0)->getName()->getLabels()));
}
public function provideValidNativePayloads()
{
return [
['apple.com', ResourceQTypes::A],
['amphp.org', ResourceQTypes::A],
['tssthacks.daniil.it', ResourceQTypes::CNAME],
['daniil.it', ResourceQTypes::MX],
['daniil.it', ResourceQTypes::DNSKEY],
];
}
}