clrghouz/app/Classes/Protocol/DNS/Query.php

88 lines
2.0 KiB
PHP

<?php
namespace App\Classes\Protocol\DNS;
use Illuminate\Support\Collection;
final class Query
{
private string $buf;
private int $class;
private string $domain;
private int $id;
private int $type;
private Collection $labels;
// https://github.com/guyinatuxedo/dns-fuzzer/blob/master/dns.md
private const header = [ // Struct of a DNS query
'id' => [0x00,'n',1], // ID
'header' => [0x01,'n',1], // Header
'qdcount' => [0x02,'n',1], // Entries in the question
'ancount' => [0x03,'n',1], // Resource Records in the answer
'nscount' => [0x04,'n',1], // Server Resource Records in the answer
'arcount' => [0x05,'n',1], // Resource Records in the addition records section
];
public function __construct(string $buf) {
$this->buf = $buf;
$rx_ptr = 0;
// DNS Query header
$header = unpack(self::unpackheader(self::header),$buf);
$rx_ptr += $this->header_len();
$this->id = $header['id'];
$this->qdcount = $header['qdcount'];
// Get the domain elements
$this->labels = collect();
while (($len=ord(substr($this->buf,$rx_ptr++,1))) !== 0x00) {
$this->labels->push(substr($this->buf,$rx_ptr,$len));
$rx_ptr += $len;
}
// Get the query type/class
$result = unpack('ntype/nclass',substr($this->buf,$rx_ptr,4));
$rx_ptr += 4;
$this->type = $result['type'];
$this->class = $result['class'];
$this->domain = substr($this->buf,$x=$this->header_len(),$rx_ptr-$x);
}
public function __get($key)
{
switch ($key) {
case 'class':
case 'domain':
case 'id':
case 'labels':
case 'qdcount':
case 'type':
return $this->{$key};
}
}
public static function header_len() {
return collect(self::header)->sum(function($item) { return $item[2]*2; });
}
/**
* Unpack our configured DNS header
*
* @param array $pack
* @return string
*/
protected static function unpackheader(array $pack): string
{
return join('/',
collect($pack)
->sortBy(function($k,$v) {return $k[0];})
->transform(function($k,$v) {return $k[1].$v;})
->values()
->toArray()
);
}
}