From fc9401f04a3aca5abb22f87ebc210de8afe11d32 Mon Sep 17 00:00:00 2001 From: marvin-borner@live.com Date: Tue, 10 Apr 2018 21:50:16 +0200 Subject: Initial Commit --- .../vendor/react/dns/src/Query/CachedExecutor.php | 55 ++++++++ .../react/dns/src/Query/CancellationException.php | 7 + assets/php/vendor/react/dns/src/Query/Executor.php | 156 +++++++++++++++++++++ .../react/dns/src/Query/ExecutorInterface.php | 8 ++ .../react/dns/src/Query/HostsFileExecutor.php | 89 ++++++++++++ assets/php/vendor/react/dns/src/Query/Query.php | 19 +++ .../php/vendor/react/dns/src/Query/RecordBag.php | 27 ++++ .../php/vendor/react/dns/src/Query/RecordCache.php | 82 +++++++++++ .../vendor/react/dns/src/Query/RetryExecutor.php | 44 ++++++ .../react/dns/src/Query/TimeoutException.php | 7 + .../vendor/react/dns/src/Query/TimeoutExecutor.php | 32 +++++ 11 files changed, 526 insertions(+) create mode 100644 assets/php/vendor/react/dns/src/Query/CachedExecutor.php create mode 100644 assets/php/vendor/react/dns/src/Query/CancellationException.php create mode 100644 assets/php/vendor/react/dns/src/Query/Executor.php create mode 100644 assets/php/vendor/react/dns/src/Query/ExecutorInterface.php create mode 100644 assets/php/vendor/react/dns/src/Query/HostsFileExecutor.php create mode 100644 assets/php/vendor/react/dns/src/Query/Query.php create mode 100644 assets/php/vendor/react/dns/src/Query/RecordBag.php create mode 100644 assets/php/vendor/react/dns/src/Query/RecordCache.php create mode 100644 assets/php/vendor/react/dns/src/Query/RetryExecutor.php create mode 100644 assets/php/vendor/react/dns/src/Query/TimeoutException.php create mode 100644 assets/php/vendor/react/dns/src/Query/TimeoutExecutor.php (limited to 'assets/php/vendor/react/dns/src/Query') diff --git a/assets/php/vendor/react/dns/src/Query/CachedExecutor.php b/assets/php/vendor/react/dns/src/Query/CachedExecutor.php new file mode 100644 index 0000000..285936d --- /dev/null +++ b/assets/php/vendor/react/dns/src/Query/CachedExecutor.php @@ -0,0 +1,55 @@ +executor = $executor; + $this->cache = $cache; + } + + public function query($nameserver, Query $query) + { + $executor = $this->executor; + $cache = $this->cache; + + return $this->cache + ->lookup($query) + ->then( + function ($cachedRecords) use ($query) { + return Message::createResponseWithAnswersForQuery($query, $cachedRecords); + }, + function () use ($executor, $cache, $nameserver, $query) { + return $executor + ->query($nameserver, $query) + ->then(function ($response) use ($cache, $query) { + $cache->storeResponseMessage($query->currentTime, $response); + return $response; + }); + } + ); + } + + /** + * @deprecated unused, exists for BC only + */ + public function buildResponse(Query $query, array $cachedRecords) + { + return Message::createResponseWithAnswersForQuery($query, $cachedRecords); + } + + /** + * @deprecated unused, exists for BC only + */ + protected function generateId() + { + return mt_rand(0, 0xffff); + } +} diff --git a/assets/php/vendor/react/dns/src/Query/CancellationException.php b/assets/php/vendor/react/dns/src/Query/CancellationException.php new file mode 100644 index 0000000..ac30f4c --- /dev/null +++ b/assets/php/vendor/react/dns/src/Query/CancellationException.php @@ -0,0 +1,7 @@ +loop = $loop; + $this->parser = $parser; + $this->dumper = $dumper; + $this->timeout = $timeout; + } + + public function query($nameserver, Query $query) + { + $request = Message::createRequestForQuery($query); + + $queryData = $this->dumper->toBinary($request); + $transport = strlen($queryData) > 512 ? 'tcp' : 'udp'; + + return $this->doQuery($nameserver, $transport, $queryData, $query->name); + } + + /** + * @deprecated unused, exists for BC only + */ + public function prepareRequest(Query $query) + { + return Message::createRequestForQuery($query); + } + + public function doQuery($nameserver, $transport, $queryData, $name) + { + // we only support UDP right now + if ($transport !== 'udp') { + return Promise\reject(new \RuntimeException( + 'DNS query for ' . $name . ' failed: Requested transport "' . $transport . '" not available, only UDP is supported in this version' + )); + } + + $that = $this; + $parser = $this->parser; + $loop = $this->loop; + + // UDP connections are instant, so try this without a timer + try { + $conn = $this->createConnection($nameserver, $transport); + } catch (\Exception $e) { + return Promise\reject(new \RuntimeException('DNS query for ' . $name . ' failed: ' . $e->getMessage(), 0, $e)); + } + + $deferred = new Deferred(function ($resolve, $reject) use (&$timer, $loop, &$conn, $name) { + $reject(new CancellationException(sprintf('DNS query for %s has been cancelled', $name))); + + if ($timer !== null) { + $loop->cancelTimer($timer); + } + $conn->close(); + }); + + $timer = null; + if ($this->timeout !== null) { + $timer = $this->loop->addTimer($this->timeout, function () use (&$conn, $name, $deferred) { + $conn->close(); + $deferred->reject(new TimeoutException(sprintf("DNS query for %s timed out", $name))); + }); + } + + $conn->on('data', function ($data) use ($conn, $parser, $deferred, $timer, $loop, $name) { + $conn->end(); + if ($timer !== null) { + $loop->cancelTimer($timer); + } + + try { + $response = $parser->parseMessage($data); + } catch (\Exception $e) { + $deferred->reject($e); + return; + } + + if ($response->header->isTruncated()) { + $deferred->reject(new \RuntimeException('DNS query for ' . $name . ' failed: The server returned a truncated result for a UDP query, but retrying via TCP is currently not supported')); + return; + } + + $deferred->resolve($response); + }); + $conn->write($queryData); + + return $deferred->promise(); + } + + /** + * @deprecated unused, exists for BC only + */ + protected function generateId() + { + return mt_rand(0, 0xffff); + } + + /** + * @param string $nameserver + * @param string $transport + * @return \React\Stream\DuplexStreamInterface + */ + protected function createConnection($nameserver, $transport) + { + $fd = @stream_socket_client("$transport://$nameserver", $errno, $errstr, 0, STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT); + if ($fd === false) { + throw new \RuntimeException('Unable to connect to DNS server: ' . $errstr, $errno); + } + + // Instantiate stream instance around this stream resource. + // This ought to be replaced with a datagram socket in the future. + // Temporary work around for Windows 10: buffer whole UDP response + // @coverageIgnoreStart + if (!class_exists('React\Stream\Stream')) { + // prefer DuplexResourceStream as of react/stream v0.7.0 + $conn = new DuplexResourceStream($fd, $this->loop, -1); + } else { + // use legacy Stream class for react/stream < v0.7.0 + $conn = new Stream($fd, $this->loop); + $conn->bufferSize = null; + } + // @coverageIgnoreEnd + + return $conn; + } +} diff --git a/assets/php/vendor/react/dns/src/Query/ExecutorInterface.php b/assets/php/vendor/react/dns/src/Query/ExecutorInterface.php new file mode 100644 index 0000000..2f7a635 --- /dev/null +++ b/assets/php/vendor/react/dns/src/Query/ExecutorInterface.php @@ -0,0 +1,8 @@ +hosts = $hosts; + $this->fallback = $fallback; + } + + public function query($nameserver, Query $query) + { + if ($query->class === Message::CLASS_IN && ($query->type === Message::TYPE_A || $query->type === Message::TYPE_AAAA)) { + // forward lookup for type A or AAAA + $records = array(); + $expectsColon = $query->type === Message::TYPE_AAAA; + foreach ($this->hosts->getIpsForHost($query->name) as $ip) { + // ensure this is an IPv4/IPV6 address according to query type + if ((strpos($ip, ':') !== false) === $expectsColon) { + $records[] = new Record($query->name, $query->type, $query->class, 0, $ip); + } + } + + if ($records) { + return Promise\resolve( + Message::createResponseWithAnswersForQuery($query, $records) + ); + } + } elseif ($query->class === Message::CLASS_IN && $query->type === Message::TYPE_PTR) { + // reverse lookup: extract IPv4 or IPv6 from special `.arpa` domain + $ip = $this->getIpFromHost($query->name); + + if ($ip !== null) { + $records = array(); + foreach ($this->hosts->getHostsForIp($ip) as $host) { + $records[] = new Record($query->name, $query->type, $query->class, 0, $host); + } + + if ($records) { + return Promise\resolve( + Message::createResponseWithAnswersForQuery($query, $records) + ); + } + } + } + + return $this->fallback->query($nameserver, $query); + } + + private function getIpFromHost($host) + { + if (substr($host, -13) === '.in-addr.arpa') { + // IPv4: read as IP and reverse bytes + $ip = @inet_pton(substr($host, 0, -13)); + if ($ip === false || isset($ip[4])) { + return null; + } + + return inet_ntop(strrev($ip)); + } elseif (substr($host, -9) === '.ip6.arpa') { + // IPv6: replace dots, reverse nibbles and interpret as hexadecimal string + $ip = @inet_ntop(pack('H*', strrev(str_replace('.', '', substr($host, 0, -9))))); + if ($ip === false) { + return null; + } + + return $ip; + } else { + return null; + } + } +} diff --git a/assets/php/vendor/react/dns/src/Query/Query.php b/assets/php/vendor/react/dns/src/Query/Query.php new file mode 100644 index 0000000..aef6e05 --- /dev/null +++ b/assets/php/vendor/react/dns/src/Query/Query.php @@ -0,0 +1,19 @@ +name = $name; + $this->type = $type; + $this->class = $class; + $this->currentTime = $currentTime; + } +} diff --git a/assets/php/vendor/react/dns/src/Query/RecordBag.php b/assets/php/vendor/react/dns/src/Query/RecordBag.php new file mode 100644 index 0000000..358cf5d --- /dev/null +++ b/assets/php/vendor/react/dns/src/Query/RecordBag.php @@ -0,0 +1,27 @@ +records[$record->data] = array($currentTime + $record->ttl, $record); + } + + public function all() + { + return array_values(array_map( + function ($value) { + list($expiresAt, $record) = $value; + return $record; + }, + $this->records + )); + } +} diff --git a/assets/php/vendor/react/dns/src/Query/RecordCache.php b/assets/php/vendor/react/dns/src/Query/RecordCache.php new file mode 100644 index 0000000..b8142d3 --- /dev/null +++ b/assets/php/vendor/react/dns/src/Query/RecordCache.php @@ -0,0 +1,82 @@ +cache = $cache; + } + + public function lookup(Query $query) + { + $id = $this->serializeQueryToIdentity($query); + + $expiredAt = $this->expiredAt; + + return $this->cache + ->get($id) + ->then(function ($value) use ($query, $expiredAt) { + $recordBag = unserialize($value); + + if (null !== $expiredAt && $expiredAt <= $query->currentTime) { + return Promise\reject(); + } + + return $recordBag->all(); + }); + } + + public function storeResponseMessage($currentTime, Message $message) + { + foreach ($message->answers as $record) { + $this->storeRecord($currentTime, $record); + } + } + + public function storeRecord($currentTime, Record $record) + { + $id = $this->serializeRecordToIdentity($record); + + $cache = $this->cache; + + $this->cache + ->get($id) + ->then( + function ($value) { + return unserialize($value); + }, + function ($e) { + return new RecordBag(); + } + ) + ->then(function ($recordBag) use ($id, $currentTime, $record, $cache) { + $recordBag->set($currentTime, $record); + $cache->set($id, serialize($recordBag)); + }); + } + + public function expire($currentTime) + { + $this->expiredAt = $currentTime; + } + + public function serializeQueryToIdentity(Query $query) + { + return sprintf('%s:%s:%s', $query->name, $query->type, $query->class); + } + + public function serializeRecordToIdentity(Record $record) + { + return sprintf('%s:%s:%s', $record->name, $record->type, $record->class); + } +} diff --git a/assets/php/vendor/react/dns/src/Query/RetryExecutor.php b/assets/php/vendor/react/dns/src/Query/RetryExecutor.php new file mode 100644 index 0000000..90353e5 --- /dev/null +++ b/assets/php/vendor/react/dns/src/Query/RetryExecutor.php @@ -0,0 +1,44 @@ +executor = $executor; + $this->retries = $retries; + } + + public function query($nameserver, Query $query) + { + return $this->tryQuery($nameserver, $query, $this->retries); + } + + public function tryQuery($nameserver, Query $query, $retries) + { + $that = $this; + $errorback = function ($error) use ($nameserver, $query, $retries, $that) { + if (!$error instanceof TimeoutException) { + throw $error; + } + if (0 >= $retries) { + throw new \RuntimeException( + sprintf("DNS query for %s failed: too many retries", $query->name), + 0, + $error + ); + } + return $that->tryQuery($nameserver, $query, $retries-1); + }; + + return $this->executor + ->query($nameserver, $query) + ->then(null, $errorback); + } +} diff --git a/assets/php/vendor/react/dns/src/Query/TimeoutException.php b/assets/php/vendor/react/dns/src/Query/TimeoutException.php new file mode 100644 index 0000000..90bf806 --- /dev/null +++ b/assets/php/vendor/react/dns/src/Query/TimeoutException.php @@ -0,0 +1,7 @@ +executor = $executor; + $this->loop = $loop; + $this->timeout = $timeout; + } + + public function query($nameserver, Query $query) + { + return Timer\timeout($this->executor->query($nameserver, $query), $this->timeout, $this->loop)->then(null, function ($e) use ($query) { + if ($e instanceof Timer\TimeoutException) { + $e = new TimeoutException(sprintf("DNS query for %s timed out", $query->name), 0, $e); + } + throw $e; + }); + } +} -- cgit v1.2.3