diff options
Diffstat (limited to 'assets/php/vendor/react/dns/src/Resolver')
-rw-r--r-- | assets/php/vendor/react/dns/src/Resolver/Factory.php | 103 | ||||
-rw-r--r-- | assets/php/vendor/react/dns/src/Resolver/Resolver.php | 100 |
2 files changed, 203 insertions, 0 deletions
diff --git a/assets/php/vendor/react/dns/src/Resolver/Factory.php b/assets/php/vendor/react/dns/src/Resolver/Factory.php new file mode 100644 index 0000000..12a912f --- /dev/null +++ b/assets/php/vendor/react/dns/src/Resolver/Factory.php @@ -0,0 +1,103 @@ +<?php + +namespace React\Dns\Resolver; + +use React\Cache\ArrayCache; +use React\Cache\CacheInterface; +use React\Dns\Config\HostsFile; +use React\Dns\Protocol\Parser; +use React\Dns\Protocol\BinaryDumper; +use React\Dns\Query\CachedExecutor; +use React\Dns\Query\Executor; +use React\Dns\Query\ExecutorInterface; +use React\Dns\Query\HostsFileExecutor; +use React\Dns\Query\RecordCache; +use React\Dns\Query\RetryExecutor; +use React\Dns\Query\TimeoutExecutor; +use React\EventLoop\LoopInterface; + +class Factory +{ + public function create($nameserver, LoopInterface $loop) + { + $nameserver = $this->addPortToServerIfMissing($nameserver); + $executor = $this->decorateHostsFileExecutor($this->createRetryExecutor($loop)); + + return new Resolver($nameserver, $executor); + } + + public function createCached($nameserver, LoopInterface $loop, CacheInterface $cache = null) + { + if (!($cache instanceof CacheInterface)) { + $cache = new ArrayCache(); + } + + $nameserver = $this->addPortToServerIfMissing($nameserver); + $executor = $this->decorateHostsFileExecutor($this->createCachedExecutor($loop, $cache)); + + return new Resolver($nameserver, $executor); + } + + /** + * Tries to load the hosts file and decorates the given executor on success + * + * @param ExecutorInterface $executor + * @return ExecutorInterface + * @codeCoverageIgnore + */ + private function decorateHostsFileExecutor(ExecutorInterface $executor) + { + try { + $executor = new HostsFileExecutor( + HostsFile::loadFromPathBlocking(), + $executor + ); + } catch (\RuntimeException $e) { + // ignore this file if it can not be loaded + } + + // Windows does not store localhost in hosts file by default but handles this internally + // To compensate for this, we explicitly use hard-coded defaults for localhost + if (DIRECTORY_SEPARATOR === '\\') { + $executor = new HostsFileExecutor( + new HostsFile("127.0.0.1 localhost\n::1 localhost"), + $executor + ); + } + + return $executor; + } + + protected function createExecutor(LoopInterface $loop) + { + return new TimeoutExecutor( + new Executor($loop, new Parser(), new BinaryDumper(), null), + 5.0, + $loop + ); + } + + protected function createRetryExecutor(LoopInterface $loop) + { + return new RetryExecutor($this->createExecutor($loop)); + } + + protected function createCachedExecutor(LoopInterface $loop, CacheInterface $cache) + { + return new CachedExecutor($this->createRetryExecutor($loop), new RecordCache($cache)); + } + + protected function addPortToServerIfMissing($nameserver) + { + if (strpos($nameserver, '[') === false && substr_count($nameserver, ':') >= 2) { + // several colons, but not enclosed in square brackets => enclose IPv6 address in square brackets + $nameserver = '[' . $nameserver . ']'; + } + // assume a dummy scheme when checking for the port, otherwise parse_url() fails + if (parse_url('dummy://' . $nameserver, PHP_URL_PORT) === null) { + $nameserver .= ':53'; + } + + return $nameserver; + } +} diff --git a/assets/php/vendor/react/dns/src/Resolver/Resolver.php b/assets/php/vendor/react/dns/src/Resolver/Resolver.php new file mode 100644 index 0000000..4a4983a --- /dev/null +++ b/assets/php/vendor/react/dns/src/Resolver/Resolver.php @@ -0,0 +1,100 @@ +<?php + +namespace React\Dns\Resolver; + +use React\Dns\Query\ExecutorInterface; +use React\Dns\Query\Query; +use React\Dns\RecordNotFoundException; +use React\Dns\Model\Message; + +class Resolver +{ + private $nameserver; + private $executor; + + public function __construct($nameserver, ExecutorInterface $executor) + { + $this->nameserver = $nameserver; + $this->executor = $executor; + } + + public function resolve($domain) + { + $query = new Query($domain, Message::TYPE_A, Message::CLASS_IN, time()); + $that = $this; + + return $this->executor + ->query($this->nameserver, $query) + ->then(function (Message $response) use ($query, $that) { + return $that->extractAddress($query, $response); + }); + } + + public function extractAddress(Query $query, Message $response) + { + $answers = $response->answers; + + $addresses = $this->resolveAliases($answers, $query->name); + + if (0 === count($addresses)) { + $message = 'DNS Request did not return valid answer.'; + throw new RecordNotFoundException($message); + } + + $address = $addresses[array_rand($addresses)]; + return $address; + } + + public function resolveAliases(array $answers, $name) + { + $named = $this->filterByName($answers, $name); + $aRecords = $this->filterByType($named, Message::TYPE_A); + $cnameRecords = $this->filterByType($named, Message::TYPE_CNAME); + + if ($aRecords) { + return $this->mapRecordData($aRecords); + } + + if ($cnameRecords) { + $aRecords = array(); + + $cnames = $this->mapRecordData($cnameRecords); + foreach ($cnames as $cname) { + $targets = $this->filterByName($answers, $cname); + $aRecords = array_merge( + $aRecords, + $this->resolveAliases($answers, $cname) + ); + } + + return $aRecords; + } + + return array(); + } + + private function filterByName(array $answers, $name) + { + return $this->filterByField($answers, 'name', $name); + } + + private function filterByType(array $answers, $type) + { + return $this->filterByField($answers, 'type', $type); + } + + private function filterByField(array $answers, $field, $value) + { + $value = strtolower($value); + return array_filter($answers, function ($answer) use ($field, $value) { + return $value === strtolower($answer->$field); + }); + } + + private function mapRecordData(array $records) + { + return array_map(function ($record) { + return $record->data; + }, $records); + } +} |