Completed
Branch master (f0bd78)
by Sam
04:24 queued 01:02
created

Message::getRcode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Badcow DNS Library.
7
 *
8
 * (c) Samuel Williams <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Badcow\DNS;
15
16
use Badcow\DNS\Rdata\UnsupportedTypeException;
17
18
class Message
19
{
20
    /**
21
     * ID.
22
     *
23
     * @var int
24
     */
25
    private $id;
26
27
    /**
28
     * QR.
29
     *
30
     * @var bool
31
     */
32
    private $isResponse;
33
34
    /**
35
     * OPCODE.
36
     *
37
     * @var int
38
     */
39
    private $opcode;
40
41
    /**
42
     * AA.
43
     *
44
     * @var bool
45
     */
46
    private $isAuthoritative;
47
48
    /**
49
     * TC.
50
     *
51
     * @var bool
52
     */
53
    private $isTruncated;
54
55
    /**
56
     * RD.
57
     *
58
     * @var bool
59
     */
60
    private $isRecursionDesired;
61
62
    /**
63
     * RA.
64
     *
65
     * @var bool
66
     */
67
    private $isRecursionAvailable;
68
69
    /**
70
     * Bit 9 of the header flags.
71
     *
72
     * @var int
73
     */
74
    private $bit9 = 0;
75
76
    /**
77
     * AD.
78
     *
79
     * {@link https://tools.ietf.org/html/rfc4035#section-3.2.3}
80
     *
81
     * @var bool
82
     */
83
    private $isAuthenticData;
84
85
    /**
86
     * CD.
87
     *
88
     * {@link https://tools.ietf.org/html/rfc4035#section-3.2.2}
89
     *
90
     * @var bool
91
     */
92
    private $isCheckingDisabled;
93
94
    /**
95
     * RCODE.
96
     *
97
     * @var int
98
     */
99
    private $rcode;
100
101
    /**
102
     * @var Question[]
103
     */
104
    private $questions = [];
105
106
    /**
107
     * @var ResourceRecord[]
108
     */
109
    private $answers = [];
110
111
    /**
112
     * @var ResourceRecord[]
113
     */
114
    private $authoritatives = [];
115
116
    /**
117
     * @var ResourceRecord[]
118
     */
119
    private $additionals = [];
120
121
    /**
122
     * @return int
123
     */
124 2
    public function getId(): int
125
    {
126 2
        return $this->id;
127
    }
128
129
    /**
130
     * @param int $id
131
     */
132 8
    public function setId(int $id): void
133
    {
134 8
        $this->id = $id;
135 8
    }
136
137
    /**
138
     * @return bool
139
     */
140 2
    public function isResponse(): bool
141
    {
142 2
        return $this->isResponse;
143
    }
144
145
    /**
146
     * @param bool $isResponse
147
     */
148 8
    public function setResponse(bool $isResponse): void
149
    {
150 8
        $this->isResponse = $isResponse;
151 8
    }
152
153
    /**
154
     * @return bool
155
     */
156 1
    public function isQuery(): bool
157
    {
158 1
        return !$this->isResponse;
159
    }
160
161
    /**
162
     * @param bool $query
163
     */
164 1
    public function setQuery(bool $query): void
165
    {
166 1
        $this->setResponse(!$query);
167 1
    }
168
169
    /**
170
     * @return int
171
     */
172 2
    public function getOpcode(): int
173
    {
174 2
        return $this->opcode;
175
    }
176
177
    /**
178
     * @param int $opcode
179
     */
180 7
    public function setOpcode(int $opcode): void
181
    {
182 7
        $this->opcode = $opcode;
183 7
    }
184
185
    /**
186
     * @return bool
187
     */
188 2
    public function isAuthoritative(): bool
189
    {
190 2
        return $this->isAuthoritative;
191
    }
192
193
    /**
194
     * @param bool $isAuthoritative
195
     */
196 7
    public function setAuthoritative(bool $isAuthoritative): void
197
    {
198 7
        $this->isAuthoritative = $isAuthoritative;
199 7
    }
200
201
    /**
202
     * @return bool
203
     */
204 2
    public function isTruncated(): bool
205
    {
206 2
        return $this->isTruncated;
207
    }
208
209
    /**
210
     * @param bool $isTruncated
211
     */
212 7
    public function setTruncated(bool $isTruncated): void
213
    {
214 7
        $this->isTruncated = $isTruncated;
215 7
    }
216
217
    /**
218
     * @return bool
219
     */
220 2
    public function isRecursionDesired(): bool
221
    {
222 2
        return $this->isRecursionDesired;
223
    }
224
225
    /**
226
     * @param bool $isRecursionDesired
227
     */
228 7
    public function setRecursionDesired(bool $isRecursionDesired): void
229
    {
230 7
        $this->isRecursionDesired = $isRecursionDesired;
231 7
    }
232
233
    /**
234
     * @return bool
235
     */
236 2
    public function isRecursionAvailable(): bool
237
    {
238 2
        return $this->isRecursionAvailable;
239
    }
240
241
    /**
242
     * @param bool $isRecursionAvailable
243
     */
244 7
    public function setRecursionAvailable(bool $isRecursionAvailable): void
245
    {
246 7
        $this->isRecursionAvailable = $isRecursionAvailable;
247 7
    }
248
249
    /**
250
     * @return int
251
     */
252 2
    public function getBit9(): int
253
    {
254 2
        return $this->bit9;
255
    }
256
257
    /**
258
     * @param int $bit9
259
     */
260 7
    public function setBit9(int $bit9): void
261
    {
262 7
        $this->bit9 = $bit9;
263 7
    }
264
265
    /**
266
     * @return bool
267
     */
268 2
    public function isAuthenticData(): bool
269
    {
270 2
        return $this->isAuthenticData;
271
    }
272
273
    /**
274
     * @param bool $isAuthenticData
275
     */
276 7
    public function setAuthenticData(bool $isAuthenticData): void
277
    {
278 7
        $this->isAuthenticData = $isAuthenticData;
279 7
    }
280
281
    /**
282
     * @return bool
283
     */
284 2
    public function isCheckingDisabled(): bool
285
    {
286 2
        return $this->isCheckingDisabled;
287
    }
288
289
    /**
290
     * @param bool $isCheckingDisabled
291
     */
292 7
    public function setCheckingDisabled(bool $isCheckingDisabled): void
293
    {
294 7
        $this->isCheckingDisabled = $isCheckingDisabled;
295 7
    }
296
297
    /**
298
     * @return int
299
     */
300 2
    public function getRcode(): int
301
    {
302 2
        return $this->rcode;
303
    }
304
305
    /**
306
     * @param int $rcode
307
     */
308 7
    public function setRcode(int $rcode): void
309
    {
310 7
        $this->rcode = $rcode;
311 7
    }
312
313
    /**
314
     * @return Question[]
315
     */
316 3
    public function getQuestions(): array
317
    {
318 3
        return $this->questions;
319
    }
320
321
    /**
322
     * @param Question $question
323
     */
324 8
    public function addQuestion(Question $question): void
325
    {
326 8
        $this->questions[] = $question;
327 8
    }
328
329
    /**
330
     * @param Question[] $questions
331
     */
332 1
    public function setQuestions(array $questions): void
333
    {
334 1
        $this->questions = [];
335 1
        foreach ($questions as $question) {
336 1
            $this->addQuestion($question);
337
        }
338 1
    }
339
340
    /**
341
     * @return ResourceRecord[]
342
     */
343 3
    public function getAnswers(): array
344
    {
345 3
        return $this->answers;
346
    }
347
348
    /**
349
     * @param ResourceRecord $answer
350
     */
351 7
    public function addAnswer(ResourceRecord $answer): void
352
    {
353 7
        $this->answers[] = $answer;
354 7
    }
355
356
    /**
357
     * @param ResourceRecord[] $answers
358
     */
359 7
    public function setAnswers(array $answers): void
360
    {
361 7
        $this->answers = [];
362 7
        foreach ($answers as $answer) {
363 7
            $this->addAnswer($answer);
364
        }
365 7
    }
366
367
    /**
368
     * @return ResourceRecord[]
369
     */
370 2
    public function getAuthoritatives(): array
371
    {
372 2
        return $this->authoritatives;
373
    }
374
375
    /**
376
     * @param ResourceRecord $authoritative
377
     */
378 5
    public function addAuthoritative(ResourceRecord $authoritative): void
379
    {
380 5
        $this->authoritatives[] = $authoritative;
381 5
    }
382
383
    /**
384
     * @param ResourceRecord[] $authoritatives
385
     */
386 7
    public function setAuthoritatives(array $authoritatives): void
387
    {
388 7
        $this->authoritatives = [];
389 7
        foreach ($authoritatives as $authoritative) {
390 5
            $this->addAuthoritative($authoritative);
391
        }
392 7
    }
393
394
    /**
395
     * @return ResourceRecord[]
396
     */
397 3
    public function getAdditionals(): array
398
    {
399 3
        return $this->additionals;
400
    }
401
402
    /**
403
     * @param ResourceRecord $additional
404
     */
405 7
    public function addAdditional(ResourceRecord $additional): void
406
    {
407 7
        $this->additionals[] = $additional;
408 7
    }
409
410
    /**
411
     * @param ResourceRecord[] $additionals
412
     */
413 7
    public function setAdditionals(array $additionals): void
414
    {
415 7
        $this->additionals = [];
416 7
        foreach ($additionals as $additional) {
417 7
            $this->addAdditional($additional);
418
        }
419 7
    }
420
421 6
    public function countQuestions(): int
422
    {
423 6
        return count($this->questions);
424
    }
425
426 6
    public function countAnswers(): int
427
    {
428 6
        return count($this->answers);
429
    }
430
431 6
    public function countAuthoritatives(): int
432
    {
433 6
        return count($this->authoritatives);
434
    }
435
436 6
    public function countAdditionals(): int
437
    {
438 6
        return count($this->additionals);
439
    }
440
441
    /**
442
     * @return string
443
     *
444
     * @throws UnsetValueException
445
     */
446 3
    public function toWire(): string
447
    {
448
        $flags = 0x0 |
449 3
        ($this->isResponse & 0x1) << 15 |
450 3
        ($this->opcode & 0xf) << 11 |
451 3
        ($this->isAuthoritative & 0x1) << 10 |
452 3
        ($this->isTruncated & 0x1) << 9 |
453 3
        ($this->isRecursionDesired & 0x1) << 8 |
454 3
        ($this->isRecursionAvailable & 0x1) << 7 |
455 3
        ($this->bit9 & 0x1) << 6 |
456 3
        ($this->isAuthenticData & 0x1) << 5 |
457 3
        ($this->isCheckingDisabled & 0x1) << 4 |
458 3
        ($this->rcode & 0xf);
459
460 3
        $encoded = pack(
461 3
            'nnnnnn',
462 3
            $this->id,
463 3
            $flags,
464 3
            $this->countQuestions(),
465 3
            $this->countAnswers(),
466 3
            $this->countAuthoritatives(),
467 3
            $this->countAdditionals()
468
        );
469
470 3
        foreach (array_merge($this->questions, $this->answers, $this->authoritatives, $this->additionals) as $resource) {
471
            /* @var ResourceRecord|Question $resource */
472 3
            $encoded .= $resource->toWire();
473
        }
474
475 3
        return $encoded;
476
    }
477
478
    /**
479
     * @param string $encoded
480
     *
481
     * @return Message
482
     *
483
     * @throws UnsupportedTypeException
484
     */
485 7
    public static function fromWire(string $encoded): Message
486
    {
487 7
        $message = new self();
488 7
        $offset = 0;
489 7
        $header = unpack('nid/nflags/nqdcount/nancount/nnscount/narcount', $encoded, $offset);
490 7
        $offset += 12;
491 7
        $flags = $header['flags'];
492
493 7
        $message->setId($header['id']);
494 7
        $message->setResponse((bool) ($flags >> 15 & 0x1));
495 7
        $message->setOpcode($flags >> 11 & 0xf);
496 7
        $message->setAuthoritative((bool) ($flags >> 10 & 0x1));
497 7
        $message->setTruncated((bool) ($flags >> 9 & 0x1));
498 7
        $message->setRecursionDesired((bool) ($flags >> 8 & 0x1));
499 7
        $message->setRecursionAvailable((bool) ($flags >> 7 & 0x1));
500 7
        $message->setBit9($flags >> 6 & 0x1);
501 7
        $message->setAuthenticData((bool) ($flags >> 5 & 0x1));
502 7
        $message->setCheckingDisabled((bool) ($flags >> 4 & 0x1));
503 7
        $message->setRcode($flags & 0xf);
504
505 7
        for ($i = 0; $i < $header['qdcount']; ++$i) {
506 7
            $message->addQuestion(Question::fromWire($encoded, $offset));
507
        }
508
509 7
        $rrs = [];
510 7
        while ($offset < strlen($encoded)) {
511 7
            $rrs[] = ResourceRecord::fromWire($encoded, $offset);
512
        }
513
514 7
        $message->setAnswers(array_splice($rrs, 0, $header['ancount']));
515 7
        $message->setAuthoritatives(array_splice($rrs, 0, $header['nscount']));
516 7
        $message->setAdditionals(array_splice($rrs, 0, $header['arcount']));
517
518 7
        return $message;
519
    }
520
}
521