Passed
Push — master ( d7fd0c...0cd2cd )
by Sam
04:33
created

EncoderTest::testEncodeType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 42
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 30
nc 1
nop 0
dl 0
loc 42
rs 9.44
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of PHP DNS Server.
5
 *
6
 * (c) Yif Swery <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace yswery\DNS\Tests;
13
14
use yswery\DNS\ClassEnum;
15
use yswery\DNS\Encoder;
16
use yswery\DNS\Header;
17
use yswery\DNS\RecordTypeEnum;
18
use yswery\DNS\ResourceRecord;
19
use PHPUnit\Framework\TestCase;
20
21
class EncoderTest extends TestCase
22
{
23
    public function testEncodeDomainName()
24
    {
25
        $input_1 = 'www.example.com.';
26
        $expectation_1 = chr(3).'www'.chr(7).'example'.chr(3).'com'."\0";
27
28
        $input_2 = '.';
29
        $expectation_2 = "\0";
30
31
        $input_3 = 'tld.';
32
        $expectation_3 = chr(3).'tld'."\0";
33
34
        $this->assertEquals($expectation_1, Encoder::encodeDomainName($input_1));
35
        $this->assertEquals($expectation_2, Encoder::encodeDomainName($input_2));
36
        $this->assertEquals($expectation_3, Encoder::encodeDomainName($input_3));
37
    }
38
39
    /**
40
     * @throws \yswery\DNS\UnsupportedTypeException
41
     */
42
    public function testEncodeQuestionResourceRecord()
43
    {
44
        $input_1 = [];
45
        $input_1[] = (new ResourceRecord())
46
            ->setName('www.example.com.')
47
            ->setType(RecordTypeEnum::TYPE_A)
48
            ->setClass(ClassEnum::INTERNET)
49
            ->setQuestion(true);
50
51
        $expectation_1 =
52
            chr(3).'www'.chr(7).'example'.chr(3).'com'."\0".
53
            pack('nn', 1, 1);
54
55
        $input_2 = [];
56
        $input_2[] = (new ResourceRecord())
57
            ->setName('domain.com.au.')
58
            ->setType(RecordTypeEnum::TYPE_MX)
59
            ->setClass(ClassEnum::INTERNET)
60
            ->setQuestion(2);
0 ignored issues
show
Bug introduced by
2 of type integer is incompatible with the type boolean expected by parameter $question of yswery\DNS\ResourceRecord::setQuestion(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

60
            ->setQuestion(/** @scrutinizer ignore-type */ 2);
Loading history...
61
62
        $expectation_2 =
63
            chr(6).'domain'.chr(3).'com'.chr(2).'au'."\0".
64
            pack('nn', 15, 1);
65
66
        $input_3 = [$input_1[0], $input_2[0]];
67
        $expectation_3 = $expectation_1.$expectation_2;
68
69
        $this->assertEquals($expectation_1, Encoder::encodeResourceRecords($input_1));
70
        $this->assertEquals($expectation_2, Encoder::encodeResourceRecords($input_2));
71
        $this->assertEquals($expectation_3, Encoder::encodeResourceRecords($input_3));
72
    }
73
74
    /**
75
     * @throws \yswery\DNS\UnsupportedTypeException
76
     */
77
    public function testEncodeResourceRecord()
78
    {
79
        $name = 'example.com.';
80
        $nameEncoded = Encoder::encodeDomainName($name);
81
        $exchange = 'mail.example.com.';
82
        $exchangeEncoded = Encoder::encodeDomainName($exchange);
83
        $preference = 10;
84
        $ttl = 1337;
85
        $class = ClassEnum::INTERNET;
86
        $type = RecordTypeEnum::TYPE_MX;
87
        $ipAddress = '192.163.5.2';
88
89
        $rdata = pack('n', $preference).$exchangeEncoded;
90
        $rdata2 = inet_pton($ipAddress);
91
92
        $decoded1 = (new ResourceRecord())
93
            ->setName($name)
94
            ->setTtl($ttl)
95
            ->setType(RecordTypeEnum::TYPE_MX)
96
            ->setRdata([
97
                'preference' => $preference,
98
                'exchange' => $exchange,
99
            ]);
100
101
        $decoded2 = (new ResourceRecord())
102
            ->setName($name)
103
            ->setTtl($ttl)
104
            ->setType(RecordTypeEnum::TYPE_A)
105
            ->setRdata($ipAddress);
106
107
        $encoded1 = $nameEncoded.pack('nnNn', $type, $class, $ttl, strlen($rdata)).$rdata;
108
        $encoded2 = $nameEncoded.pack('nnNn', 1, $class, $ttl, strlen($rdata2)).$rdata2;
109
110
        $this->assertEquals($encoded1, Encoder::encodeResourceRecords([$decoded1]));
111
        $this->assertEquals($encoded2, Encoder::encodeResourceRecords([$decoded2]));
112
    }
113
114
    /**
115
     * @throws \yswery\DNS\UnsupportedTypeException
116
     */
117
    public function testEncodeType()
118
    {
119
        $decoded_1 = '192.168.0.1';
120
        $encoded_1 = inet_pton($decoded_1);
121
122
        $decoded_2 = '2001:acad:1337:b8::19';
123
        $encoded_2 = inet_pton($decoded_2);
124
125
        $decoded_5 = 'dns1.example.com.';
126
        $encoded_5 = chr(4).'dns1'.chr(7).'example'.chr(3).'com'."\0";
127
128
        $decoded_6 = [
129
            'mname' => 'example.com.',
130
            'rname' => 'postmaster.example.com',
131
            'serial' => 1970010188,
132
            'refresh' => 1800,
133
            'retry' => 7200,
134
            'expire' => 10800,
135
            'minimum' => 3600,
136
        ];
137
138
        $encoded_6 =
139
            chr(7).'example'.chr(3).'com'."\0".
140
            chr(10).'postmaster'.chr(7).'example'.chr(3).'com'."\0".
141
            pack('NNNNN', 1970010188, 1800, 7200, 10800, 3600);
142
143
        $decoded_7 = [
144
            'preference' => 15,
145
            'exchange' => 'mail.example.com.',
146
        ];
147
148
        $encoded_7 = pack('n', 15).chr(4).'mail'.chr(7).'example'.chr(3).'com'."\0";
149
150
        $decoded_8 = 'This is a comment.';
151
        $encoded_8 = chr(18).$decoded_8;
152
153
        $this->assertEquals($encoded_1, Encoder::encodeRdata(1, $decoded_1));
154
        $this->assertEquals($encoded_2, Encoder::encodeRdata(28, $decoded_2));
155
        $this->assertEquals($encoded_5, Encoder::encodeRdata(2, $decoded_5));
156
        $this->assertEquals($encoded_6, Encoder::encodeRdata(6, $decoded_6));
157
        $this->assertEquals($encoded_7, Encoder::encodeRdata(15, $decoded_7));
158
        $this->assertEquals($encoded_8, Encoder::encodeRdata(16, $decoded_8));
159
    }
160
161
    /**
162
     * @expectedException \InvalidArgumentException
163
     */
164
    public function testInvalidIpv4()
165
    {
166
        Encoder::encodeRdata(RecordTypeEnum::TYPE_A, '192.168.1');
167
    }
168
169
    /**
170
     * @expectedException \InvalidArgumentException
171
     */
172
    public function testInvalidIpv6()
173
    {
174
        Encoder::encodeRdata(RecordTypeEnum::TYPE_AAAA, '2001:acad:1337:b8:19');
175
    }
176
177
    public function testEncodeHeader()
178
    {
179
        $id = 1337;
180
        $flags = 0b1000010000000000;
181
        $qdcount = 1;
182
        $ancount = 2;
183
        $nscount = 0;
184
        $arcount = 0;
185
186
        $encoded = pack('nnnnnn', $id, $flags, $qdcount, $ancount, $nscount, $arcount);
187
188
        $header = new Header();
189
        $header
190
            ->setId($id)
191
            ->setResponse(true)
192
            ->setOpcode(Header::OPCODE_STANDARD_QUERY)
193
            ->setAuthoritative(true)
194
            ->setTruncated(false)
195
            ->setRecursionDesired(false)
196
            ->setRecursionAvailable(false)
197
            ->setRcode(Header::RCODE_NO_ERROR)
198
            ->setQuestionCount($qdcount)
199
            ->setAnswerCount($ancount)
200
            ->setNameServerCount($nscount)
201
            ->setAdditionalRecordsCount($arcount)
202
        ;
203
204
        $this->assertEquals($encoded, Encoder::encodeHeader($header));
205
    }
206
}
207