SystemResolver::getAnswer()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 8
ccs 5
cts 5
cp 1
crap 2
rs 10
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\Resolver;
13
14
use yswery\DNS\RecordTypeEnum;
15
use yswery\DNS\ResourceRecord;
16
use yswery\DNS\UnsupportedTypeException;
17
18
/**
19
 * Use the host system's configured DNS.
20
 */
21
class SystemResolver extends AbstractResolver
22
{
23
    /**
24
     * SystemResolver constructor.
25
     *
26
     * @param bool $recursionAvailable
27
     * @param bool $authoritative
28
     */
29 2
    public function __construct($recursionAvailable = true, $authoritative = false)
30
    {
31 2
        $this->allowRecursion = (bool) $recursionAvailable;
32 2
        $this->isAuthoritative = (bool) $authoritative;
33 2
    }
34
35
    /**
36
     * @param ResourceRecord[] $queries
37
     *
38
     * @return ResourceRecord[]
39
     *
40
     * @throws UnsupportedTypeException
41
     */
42 2
    public function getAnswer(array $queries, ?string $client = null): array
43
    {
44 2
        $answer = [];
45 2
        foreach ($queries as $query) {
46 1
            $answer = array_merge($answer, $this->getRecordsRecursively($query));
47
        }
48
49 2
        return $answer;
50
    }
51
52
    /**
53
     * Resolve the $query using the system configured local DNS.
54
     *
55
     * @param ResourceRecord $query
56
     *
57
     * @return ResourceRecord[]
58
     *
59
     * @throws UnsupportedTypeException
60
     */
61 1
    private function getRecordsRecursively(ResourceRecord $query): array
62
    {
63 1
        $records = dns_get_record($query->getName(), $this->IANA2PHP($query->getType()));
64 1
        $result = [];
65
66 1
        foreach ($records as $record) {
67 1
            $result[] = (new ResourceRecord())
68 1
                ->setName($query->getName())
69 1
                ->setClass($query->getClass())
70 1
                ->setTtl($record['ttl'])
71 1
                ->setRdata($this->extractPhpRdata($record))
72 1
                ->setType($query->getType());
73
        }
74
75 1
        return $result;
76
    }
77
78
    /**
79
     * @param array $resourceRecord
80
     *
81
     * @return array|string
82
     *
83
     * @throws UnsupportedTypeException
84
     */
85 1
    protected function extractPhpRdata(array $resourceRecord)
86
    {
87 1
        $type = RecordTypeEnum::getTypeFromName($resourceRecord['type']);
88
89 1
        switch ($type) {
90
            case RecordTypeEnum::TYPE_A:
91 1
                return $resourceRecord['ip'];
92
            case RecordTypeEnum::TYPE_AAAA:
93 1
                return $resourceRecord['ipv6'];
94
            case RecordTypeEnum::TYPE_NS:
95
            case RecordTypeEnum::TYPE_CNAME:
96
            case RecordTypeEnum::TYPE_PTR:
97
                return $resourceRecord['target'];
98
            case RecordTypeEnum::TYPE_SOA:
99
                return [
100
                        'mname' => $resourceRecord['mname'],
101
                        'rname' => $resourceRecord['rname'],
102
                        'serial' => $resourceRecord['serial'],
103
                        'refresh' => $resourceRecord['refresh'],
104
                        'retry' => $resourceRecord['retry'],
105
                        'expire' => $resourceRecord['expire'],
106
                        'minimum' => $resourceRecord['minimum-ttl'],
107
                    ];
108
            case RecordTypeEnum::TYPE_MX:
109
                return [
110
                    'preference' => $resourceRecord['pri'],
111
                    'exchange' => $resourceRecord['host'],
112
                ];
113
            case RecordTypeEnum::TYPE_TXT:
114
                return $resourceRecord['txt'];
115
            case RecordTypeEnum::TYPE_SRV:
116
                return [
117
                    'priority' => $resourceRecord['pri'],
118
                    'port' => $resourceRecord['port'],
119
                    'weight' => $resourceRecord['weight'],
120
                    'target' => $resourceRecord['target'],
121
                ];
122
            default:
123
                throw new UnsupportedTypeException(sprintf('Record type "%s" is not a supported type.', RecordTypeEnum::getName($type)));
124
        }
125
    }
126
127
    /**
128
     * Maps an IANA Rdata type to the built-in PHP DNS constant.
129
     *
130
     * @example $this->IANA_to_PHP(5) //Returns DNS_CNAME int(16)
131
     *
132
     * @param int $type the IANA RTYPE
133
     *
134
     * @return int the built-in PHP DNS_<type> constant or `false` if the type is not defined
135
     *
136
     * @throws UnsupportedTypeException|\InvalidArgumentException
137
     */
138 1
    private function IANA2PHP(int $type): int
139
    {
140 1
        $constantName = 'DNS_'.RecordTypeEnum::getName($type);
141 1
        if (!defined($constantName)) {
142
            throw new UnsupportedTypeException(sprintf('Record type "%d" is not a supported type.', $type));
143
        }
144
145 1
        $phpType = constant($constantName);
146
147 1
        if (!is_int($phpType)) {
148
            throw new \InvalidArgumentException(sprintf('Constant "%s" is not an integer.', $constantName));
149
        }
150
151 1
        return $phpType;
152
    }
153
}
154