Subversion Repositories php-qbpwcf

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 liveuser 1
<?php
2
 
3
namespace React\Dns\Query;
4
 
5
use React\Dns\Config\HostsFile;
6
use React\Dns\Model\Message;
7
use React\Dns\Model\Record;
8
use React\Promise;
9
 
10
/**
11
 * Resolves hosts from the given HostsFile or falls back to another executor
12
 *
13
 * If the host is found in the hosts file, it will not be passed to the actual
14
 * DNS executor. If the host is not found in the hosts file, it will be passed
15
 * to the DNS executor as a fallback.
16
 */
17
final class HostsFileExecutor implements ExecutorInterface
18
{
19
    private $hosts;
20
    private $fallback;
21
 
22
    public function __construct(HostsFile $hosts, ExecutorInterface $fallback)
23
    {
24
        $this->hosts = $hosts;
25
        $this->fallback = $fallback;
26
    }
27
 
28
    public function query(Query $query)
29
    {
30
        if ($query->class === Message::CLASS_IN && ($query->type === Message::TYPE_A || $query->type === Message::TYPE_AAAA)) {
31
            // forward lookup for type A or AAAA
32
            $records = array();
33
            $expectsColon = $query->type === Message::TYPE_AAAA;
34
            foreach ($this->hosts->getIpsForHost($query->name) as $ip) {
35
                // ensure this is an IPv4/IPV6 address according to query type
36
                if ((strpos($ip, ':') !== false) === $expectsColon) {
37
                    $records[] = new Record($query->name, $query->type, $query->class, 0, $ip);
38
                }
39
            }
40
 
41
            if ($records) {
42
                return Promise\resolve(
43
                    Message::createResponseWithAnswersForQuery($query, $records)
44
                );
45
            }
46
        } elseif ($query->class === Message::CLASS_IN && $query->type === Message::TYPE_PTR) {
47
            // reverse lookup: extract IPv4 or IPv6 from special `.arpa` domain
48
            $ip = $this->getIpFromHost($query->name);
49
 
50
            if ($ip !== null) {
51
                $records = array();
52
                foreach ($this->hosts->getHostsForIp($ip) as $host) {
53
                    $records[] = new Record($query->name, $query->type, $query->class, 0, $host);
54
                }
55
 
56
                if ($records) {
57
                    return Promise\resolve(
58
                        Message::createResponseWithAnswersForQuery($query, $records)
59
                    );
60
                }
61
            }
62
        }
63
 
64
        return $this->fallback->query($query);
65
    }
66
 
67
    private function getIpFromHost($host)
68
    {
69
        if (substr($host, -13) === '.in-addr.arpa') {
70
            // IPv4: read as IP and reverse bytes
71
            $ip = @inet_pton(substr($host, 0, -13));
72
            if ($ip === false || isset($ip[4])) {
73
                return null;
74
            }
75
 
76
            return inet_ntop(strrev($ip));
77
        } elseif (substr($host, -9) === '.ip6.arpa') {
78
            // IPv6: replace dots, reverse nibbles and interpret as hexadecimal string
79
            $ip = @inet_ntop(pack('H*', strrev(str_replace('.', '', substr($host, 0, -9)))));
80
            if ($ip === false) {
81
                return null;
82
            }
83
 
84
            return $ip;
85
        } else {
86
            return null;
87
        }
88
    }
89
}