Subir todo el proyecto incluyendo vendor y dependencias
This commit is contained in:
199
vendor/react/dns/src/Protocol/BinaryDumper.php
vendored
Executable file
199
vendor/react/dns/src/Protocol/BinaryDumper.php
vendored
Executable file
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
namespace React\Dns\Protocol;
|
||||
|
||||
use React\Dns\Model\Message;
|
||||
use React\Dns\Model\Record;
|
||||
use React\Dns\Query\Query;
|
||||
|
||||
final class BinaryDumper
|
||||
{
|
||||
/**
|
||||
* @param Message $message
|
||||
* @return string
|
||||
*/
|
||||
public function toBinary(Message $message)
|
||||
{
|
||||
$data = '';
|
||||
|
||||
$data .= $this->headerToBinary($message);
|
||||
$data .= $this->questionToBinary($message->questions);
|
||||
$data .= $this->recordsToBinary($message->answers);
|
||||
$data .= $this->recordsToBinary($message->authority);
|
||||
$data .= $this->recordsToBinary($message->additional);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Message $message
|
||||
* @return string
|
||||
*/
|
||||
private function headerToBinary(Message $message)
|
||||
{
|
||||
$data = '';
|
||||
|
||||
$data .= pack('n', $message->id);
|
||||
|
||||
$flags = 0x00;
|
||||
$flags = ($flags << 1) | ($message->qr ? 1 : 0);
|
||||
$flags = ($flags << 4) | $message->opcode;
|
||||
$flags = ($flags << 1) | ($message->aa ? 1 : 0);
|
||||
$flags = ($flags << 1) | ($message->tc ? 1 : 0);
|
||||
$flags = ($flags << 1) | ($message->rd ? 1 : 0);
|
||||
$flags = ($flags << 1) | ($message->ra ? 1 : 0);
|
||||
$flags = ($flags << 3) | 0; // skip unused zero bit
|
||||
$flags = ($flags << 4) | $message->rcode;
|
||||
|
||||
$data .= pack('n', $flags);
|
||||
|
||||
$data .= pack('n', count($message->questions));
|
||||
$data .= pack('n', count($message->answers));
|
||||
$data .= pack('n', count($message->authority));
|
||||
$data .= pack('n', count($message->additional));
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Query[] $questions
|
||||
* @return string
|
||||
*/
|
||||
private function questionToBinary(array $questions)
|
||||
{
|
||||
$data = '';
|
||||
|
||||
foreach ($questions as $question) {
|
||||
$data .= $this->domainNameToBinary($question->name);
|
||||
$data .= pack('n*', $question->type, $question->class);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Record[] $records
|
||||
* @return string
|
||||
*/
|
||||
private function recordsToBinary(array $records)
|
||||
{
|
||||
$data = '';
|
||||
|
||||
foreach ($records as $record) {
|
||||
/* @var $record Record */
|
||||
switch ($record->type) {
|
||||
case Message::TYPE_A:
|
||||
case Message::TYPE_AAAA:
|
||||
$binary = \inet_pton($record->data);
|
||||
break;
|
||||
case Message::TYPE_CNAME:
|
||||
case Message::TYPE_NS:
|
||||
case Message::TYPE_PTR:
|
||||
$binary = $this->domainNameToBinary($record->data);
|
||||
break;
|
||||
case Message::TYPE_TXT:
|
||||
case Message::TYPE_SPF:
|
||||
$binary = $this->textsToBinary($record->data);
|
||||
break;
|
||||
case Message::TYPE_MX:
|
||||
$binary = \pack(
|
||||
'n',
|
||||
$record->data['priority']
|
||||
);
|
||||
$binary .= $this->domainNameToBinary($record->data['target']);
|
||||
break;
|
||||
case Message::TYPE_SRV:
|
||||
$binary = \pack(
|
||||
'n*',
|
||||
$record->data['priority'],
|
||||
$record->data['weight'],
|
||||
$record->data['port']
|
||||
);
|
||||
$binary .= $this->domainNameToBinary($record->data['target']);
|
||||
break;
|
||||
case Message::TYPE_SOA:
|
||||
$binary = $this->domainNameToBinary($record->data['mname']);
|
||||
$binary .= $this->domainNameToBinary($record->data['rname']);
|
||||
$binary .= \pack(
|
||||
'N*',
|
||||
$record->data['serial'],
|
||||
$record->data['refresh'],
|
||||
$record->data['retry'],
|
||||
$record->data['expire'],
|
||||
$record->data['minimum']
|
||||
);
|
||||
break;
|
||||
case Message::TYPE_CAA:
|
||||
$binary = \pack(
|
||||
'C*',
|
||||
$record->data['flag'],
|
||||
\strlen($record->data['tag'])
|
||||
);
|
||||
$binary .= $record->data['tag'];
|
||||
$binary .= $record->data['value'];
|
||||
break;
|
||||
case Message::TYPE_SSHFP:
|
||||
$binary = \pack(
|
||||
'CCH*',
|
||||
$record->data['algorithm'],
|
||||
$record->data['type'],
|
||||
$record->data['fingerprint']
|
||||
);
|
||||
break;
|
||||
case Message::TYPE_OPT:
|
||||
$binary = '';
|
||||
foreach ($record->data as $opt => $value) {
|
||||
if ($opt === Message::OPT_TCP_KEEPALIVE && $value !== null) {
|
||||
$value = \pack('n', round($value * 10));
|
||||
}
|
||||
$binary .= \pack('n*', $opt, \strlen((string) $value)) . $value;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// RDATA is already stored as binary value for unknown record types
|
||||
$binary = $record->data;
|
||||
}
|
||||
|
||||
$data .= $this->domainNameToBinary($record->name);
|
||||
$data .= \pack('nnNn', $record->type, $record->class, $record->ttl, \strlen($binary));
|
||||
$data .= $binary;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $texts
|
||||
* @return string
|
||||
*/
|
||||
private function textsToBinary(array $texts)
|
||||
{
|
||||
$data = '';
|
||||
foreach ($texts as $text) {
|
||||
$data .= \chr(\strlen($text)) . $text;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $host
|
||||
* @return string
|
||||
*/
|
||||
private function domainNameToBinary($host)
|
||||
{
|
||||
if ($host === '') {
|
||||
return "\0";
|
||||
}
|
||||
|
||||
// break up domain name at each dot that is not preceeded by a backslash (escaped notation)
|
||||
return $this->textsToBinary(
|
||||
\array_map(
|
||||
'stripcslashes',
|
||||
\preg_split(
|
||||
'/(?<!\\\\)\./',
|
||||
$host . '.'
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
356
vendor/react/dns/src/Protocol/Parser.php
vendored
Executable file
356
vendor/react/dns/src/Protocol/Parser.php
vendored
Executable file
@@ -0,0 +1,356 @@
|
||||
<?php
|
||||
|
||||
namespace React\Dns\Protocol;
|
||||
|
||||
use React\Dns\Model\Message;
|
||||
use React\Dns\Model\Record;
|
||||
use React\Dns\Query\Query;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* DNS protocol parser
|
||||
*
|
||||
* Obsolete and uncommon types and classes are not implemented.
|
||||
*/
|
||||
final class Parser
|
||||
{
|
||||
/**
|
||||
* Parses the given raw binary message into a Message object
|
||||
*
|
||||
* @param string $data
|
||||
* @throws InvalidArgumentException
|
||||
* @return Message
|
||||
*/
|
||||
public function parseMessage($data)
|
||||
{
|
||||
$message = $this->parse($data, 0);
|
||||
if ($message === null) {
|
||||
throw new InvalidArgumentException('Unable to parse binary message');
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @param int $consumed
|
||||
* @return ?Message
|
||||
*/
|
||||
private function parse($data, $consumed)
|
||||
{
|
||||
if (!isset($data[12 - 1])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
list($id, $fields, $qdCount, $anCount, $nsCount, $arCount) = array_values(unpack('n*', substr($data, 0, 12)));
|
||||
|
||||
$message = new Message();
|
||||
$message->id = $id;
|
||||
$message->rcode = $fields & 0xf;
|
||||
$message->ra = (($fields >> 7) & 1) === 1;
|
||||
$message->rd = (($fields >> 8) & 1) === 1;
|
||||
$message->tc = (($fields >> 9) & 1) === 1;
|
||||
$message->aa = (($fields >> 10) & 1) === 1;
|
||||
$message->opcode = ($fields >> 11) & 0xf;
|
||||
$message->qr = (($fields >> 15) & 1) === 1;
|
||||
$consumed += 12;
|
||||
|
||||
// parse all questions
|
||||
for ($i = $qdCount; $i > 0; --$i) {
|
||||
list($question, $consumed) = $this->parseQuestion($data, $consumed);
|
||||
if ($question === null) {
|
||||
return null;
|
||||
} else {
|
||||
$message->questions[] = $question;
|
||||
}
|
||||
}
|
||||
|
||||
// parse all answer records
|
||||
for ($i = $anCount; $i > 0; --$i) {
|
||||
list($record, $consumed) = $this->parseRecord($data, $consumed);
|
||||
if ($record === null) {
|
||||
return null;
|
||||
} else {
|
||||
$message->answers[] = $record;
|
||||
}
|
||||
}
|
||||
|
||||
// parse all authority records
|
||||
for ($i = $nsCount; $i > 0; --$i) {
|
||||
list($record, $consumed) = $this->parseRecord($data, $consumed);
|
||||
if ($record === null) {
|
||||
return null;
|
||||
} else {
|
||||
$message->authority[] = $record;
|
||||
}
|
||||
}
|
||||
|
||||
// parse all additional records
|
||||
for ($i = $arCount; $i > 0; --$i) {
|
||||
list($record, $consumed) = $this->parseRecord($data, $consumed);
|
||||
if ($record === null) {
|
||||
return null;
|
||||
} else {
|
||||
$message->additional[] = $record;
|
||||
}
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @param int $consumed
|
||||
* @return array
|
||||
*/
|
||||
private function parseQuestion($data, $consumed)
|
||||
{
|
||||
list($labels, $consumed) = $this->readLabels($data, $consumed);
|
||||
|
||||
if ($labels === null || !isset($data[$consumed + 4 - 1])) {
|
||||
return array(null, null);
|
||||
}
|
||||
|
||||
list($type, $class) = array_values(unpack('n*', substr($data, $consumed, 4)));
|
||||
$consumed += 4;
|
||||
|
||||
return array(
|
||||
new Query(
|
||||
implode('.', $labels),
|
||||
$type,
|
||||
$class
|
||||
),
|
||||
$consumed
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @param int $consumed
|
||||
* @return array An array with a parsed Record on success or array with null if data is invalid/incomplete
|
||||
*/
|
||||
private function parseRecord($data, $consumed)
|
||||
{
|
||||
list($name, $consumed) = $this->readDomain($data, $consumed);
|
||||
|
||||
if ($name === null || !isset($data[$consumed + 10 - 1])) {
|
||||
return array(null, null);
|
||||
}
|
||||
|
||||
list($type, $class) = array_values(unpack('n*', substr($data, $consumed, 4)));
|
||||
$consumed += 4;
|
||||
|
||||
list($ttl) = array_values(unpack('N', substr($data, $consumed, 4)));
|
||||
$consumed += 4;
|
||||
|
||||
// TTL is a UINT32 that must not have most significant bit set for BC reasons
|
||||
if ($ttl < 0 || $ttl >= 1 << 31) {
|
||||
$ttl = 0;
|
||||
}
|
||||
|
||||
list($rdLength) = array_values(unpack('n', substr($data, $consumed, 2)));
|
||||
$consumed += 2;
|
||||
|
||||
if (!isset($data[$consumed + $rdLength - 1])) {
|
||||
return array(null, null);
|
||||
}
|
||||
|
||||
$rdata = null;
|
||||
$expected = $consumed + $rdLength;
|
||||
|
||||
if (Message::TYPE_A === $type) {
|
||||
if ($rdLength === 4) {
|
||||
$rdata = inet_ntop(substr($data, $consumed, $rdLength));
|
||||
$consumed += $rdLength;
|
||||
}
|
||||
} elseif (Message::TYPE_AAAA === $type) {
|
||||
if ($rdLength === 16) {
|
||||
$rdata = inet_ntop(substr($data, $consumed, $rdLength));
|
||||
$consumed += $rdLength;
|
||||
}
|
||||
} elseif (Message::TYPE_CNAME === $type || Message::TYPE_PTR === $type || Message::TYPE_NS === $type) {
|
||||
list($rdata, $consumed) = $this->readDomain($data, $consumed);
|
||||
} elseif (Message::TYPE_TXT === $type || Message::TYPE_SPF === $type) {
|
||||
$rdata = array();
|
||||
while ($consumed < $expected) {
|
||||
$len = ord($data[$consumed]);
|
||||
$rdata[] = (string)substr($data, $consumed + 1, $len);
|
||||
$consumed += $len + 1;
|
||||
}
|
||||
} elseif (Message::TYPE_MX === $type) {
|
||||
if ($rdLength > 2) {
|
||||
list($priority) = array_values(unpack('n', substr($data, $consumed, 2)));
|
||||
list($target, $consumed) = $this->readDomain($data, $consumed + 2);
|
||||
|
||||
$rdata = array(
|
||||
'priority' => $priority,
|
||||
'target' => $target
|
||||
);
|
||||
}
|
||||
} elseif (Message::TYPE_SRV === $type) {
|
||||
if ($rdLength > 6) {
|
||||
list($priority, $weight, $port) = array_values(unpack('n*', substr($data, $consumed, 6)));
|
||||
list($target, $consumed) = $this->readDomain($data, $consumed + 6);
|
||||
|
||||
$rdata = array(
|
||||
'priority' => $priority,
|
||||
'weight' => $weight,
|
||||
'port' => $port,
|
||||
'target' => $target
|
||||
);
|
||||
}
|
||||
} elseif (Message::TYPE_SSHFP === $type) {
|
||||
if ($rdLength > 2) {
|
||||
list($algorithm, $hash) = \array_values(\unpack('C*', \substr($data, $consumed, 2)));
|
||||
$fingerprint = \bin2hex(\substr($data, $consumed + 2, $rdLength - 2));
|
||||
$consumed += $rdLength;
|
||||
|
||||
$rdata = array(
|
||||
'algorithm' => $algorithm,
|
||||
'type' => $hash,
|
||||
'fingerprint' => $fingerprint
|
||||
);
|
||||
}
|
||||
} elseif (Message::TYPE_SOA === $type) {
|
||||
list($mname, $consumed) = $this->readDomain($data, $consumed);
|
||||
list($rname, $consumed) = $this->readDomain($data, $consumed);
|
||||
|
||||
if ($mname !== null && $rname !== null && isset($data[$consumed + 20 - 1])) {
|
||||
list($serial, $refresh, $retry, $expire, $minimum) = array_values(unpack('N*', substr($data, $consumed, 20)));
|
||||
$consumed += 20;
|
||||
|
||||
$rdata = array(
|
||||
'mname' => $mname,
|
||||
'rname' => $rname,
|
||||
'serial' => $serial,
|
||||
'refresh' => $refresh,
|
||||
'retry' => $retry,
|
||||
'expire' => $expire,
|
||||
'minimum' => $minimum
|
||||
);
|
||||
}
|
||||
} elseif (Message::TYPE_OPT === $type) {
|
||||
$rdata = array();
|
||||
while (isset($data[$consumed + 4 - 1])) {
|
||||
list($code, $length) = array_values(unpack('n*', substr($data, $consumed, 4)));
|
||||
$value = (string) substr($data, $consumed + 4, $length);
|
||||
if ($code === Message::OPT_TCP_KEEPALIVE && $value === '') {
|
||||
$value = null;
|
||||
} elseif ($code === Message::OPT_TCP_KEEPALIVE && $length === 2) {
|
||||
list($value) = array_values(unpack('n', $value));
|
||||
$value = round($value * 0.1, 1);
|
||||
} elseif ($code === Message::OPT_TCP_KEEPALIVE) {
|
||||
break;
|
||||
}
|
||||
$rdata[$code] = $value;
|
||||
$consumed += 4 + $length;
|
||||
}
|
||||
} elseif (Message::TYPE_CAA === $type) {
|
||||
if ($rdLength > 3) {
|
||||
list($flag, $tagLength) = array_values(unpack('C*', substr($data, $consumed, 2)));
|
||||
|
||||
if ($tagLength > 0 && $rdLength - 2 - $tagLength > 0) {
|
||||
$tag = substr($data, $consumed + 2, $tagLength);
|
||||
$value = substr($data, $consumed + 2 + $tagLength, $rdLength - 2 - $tagLength);
|
||||
$consumed += $rdLength;
|
||||
|
||||
$rdata = array(
|
||||
'flag' => $flag,
|
||||
'tag' => $tag,
|
||||
'value' => $value
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// unknown types simply parse rdata as an opaque binary string
|
||||
$rdata = substr($data, $consumed, $rdLength);
|
||||
$consumed += $rdLength;
|
||||
}
|
||||
|
||||
// ensure parsing record data consumes expact number of bytes indicated in record length
|
||||
if ($consumed !== $expected || $rdata === null) {
|
||||
return array(null, null);
|
||||
}
|
||||
|
||||
return array(
|
||||
new Record($name, $type, $class, $ttl, $rdata),
|
||||
$consumed
|
||||
);
|
||||
}
|
||||
|
||||
private function readDomain($data, $consumed)
|
||||
{
|
||||
list ($labels, $consumed) = $this->readLabels($data, $consumed);
|
||||
|
||||
if ($labels === null) {
|
||||
return array(null, null);
|
||||
}
|
||||
|
||||
// use escaped notation for each label part, then join using dots
|
||||
return array(
|
||||
\implode(
|
||||
'.',
|
||||
\array_map(
|
||||
function ($label) {
|
||||
return \addcslashes($label, "\0..\40.\177");
|
||||
},
|
||||
$labels
|
||||
)
|
||||
),
|
||||
$consumed
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @param int $consumed
|
||||
* @param int $compressionDepth maximum depth for compressed labels to avoid unreasonable recursion
|
||||
* @return array
|
||||
*/
|
||||
private function readLabels($data, $consumed, $compressionDepth = 127)
|
||||
{
|
||||
$labels = array();
|
||||
|
||||
while (true) {
|
||||
if (!isset($data[$consumed])) {
|
||||
return array(null, null);
|
||||
}
|
||||
|
||||
$length = \ord($data[$consumed]);
|
||||
|
||||
// end of labels reached
|
||||
if ($length === 0) {
|
||||
$consumed += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// first two bits set? this is a compressed label (14 bit pointer offset)
|
||||
if (($length & 0xc0) === 0xc0 && isset($data[$consumed + 1]) && $compressionDepth) {
|
||||
$offset = ($length & ~0xc0) << 8 | \ord($data[$consumed + 1]);
|
||||
if ($offset >= $consumed) {
|
||||
return array(null, null);
|
||||
}
|
||||
|
||||
$consumed += 2;
|
||||
list($newLabels) = $this->readLabels($data, $offset, $compressionDepth - 1);
|
||||
|
||||
if ($newLabels === null) {
|
||||
return array(null, null);
|
||||
}
|
||||
|
||||
$labels = array_merge($labels, $newLabels);
|
||||
break;
|
||||
}
|
||||
|
||||
// length MUST be 0-63 (6 bits only) and data has to be large enough
|
||||
if ($length & 0xc0 || !isset($data[$consumed + $length - 1])) {
|
||||
return array(null, null);
|
||||
}
|
||||
|
||||
$labels[] = substr($data, $consumed + 1, $length);
|
||||
$consumed += $length + 1;
|
||||
}
|
||||
|
||||
return array($labels, $consumed);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user