Completed
Push — master ( f8e0a8...6d3196 )
by Sam
02:21
created

SystemResolver   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Test Coverage

Coverage 64.81%

Importance

Changes 0
Metric Value
eloc 62
dl 0
loc 138
ccs 35
cts 54
cp 0.6481
rs 10
c 0
b 0
f 0
wmc 18

5 Methods

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