You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

124 lines
3.4 KiB

<?php
$dnsMsg = '7ae181a00001000300000001036f6e6503636f6d00000f0001c00c000f000100015180001a000a036d7831037075620d6d61696c706f64332d63706833c00cc00c000f0001000151800008000a036d7832c02bc00c000f0001000151800008000a036d7833c02b00002905ac000000000000';
$dnsMsg = '3ba681a00001000300000001036f6e6503636f6d00000f0001c00c000f000100014a9e001a000a036d7833037075620d6d61696c706f64332d63706833c00cc00c000f000100014a9e0008000a036d7831c02bc00c000f000100014a9e0008000a036d7832c02b00002905ac000000000000';
# Stolen from miekg
# RFC1035 4.1.1. Header section format
define('DNS_FLAGS_QR', 1 << 15); // query/response (response=1)
define('DNS_FLAGS_AA', 1 << 10); // authoritative
define('DNS_FLAGS_TC', 1 << 9); // truncated
define('DNS_FLAGS_RD', 1 << 8); // recursion desired
define('DNS_FLAGS_RA', 1 << 7); // recursion available
define('DNS_FLAGS_Z', 1 << 6); // Z
define('DNS_FLAGS_AD', 1 << 5); // authticated data
define('DNS_FLAGS_CD', 1 << 4); // checking disabled
function unpackTake($msg, $offset, $length){
$s = substr($msg, $offset, $length);
return [$offset+=$length, $s];
}
function unpackUint16($msg, $offset){
list($offset, $r) = unpackTake($msg, $offset, 2);
return [$offset, unpack('n', $r)[1]];
}
class msgHeader {
public $id;
public $flags;
public $querys;
public $answers;
public $auth_rr;
public $add_rr;
public $flagBits;
public function parseFlags() {
$this->flagBits = [
'Id' => $this->id,
'Response' => ($this->flags & DNS_FLAGS_QR) != 0,
'Authoritative' => ($this->flags & DNS_FLAGS_AA) != 0,
'Truncated' => ($this->flags & DNS_FLAGS_TC) != 0,
'RecursionDesired' => ($this->flags & DNS_FLAGS_RD) != 0,
'RecursionAvailable' => ($this->flags & DNS_FLAGS_RA) != 0,
'Zero' => ($this->flags & DNS_FLAGS_Z) != 0,
'AuthenticatedData' => ($this->flags & DNS_FLAGS_AD) != 0,
'CheckingDisabled' => ($this->flags & DNS_FLAGS_CD) != 0,
'Rcode' => floor($this->flags & 0xF),
'Opcode' => floor($this->flags>>11) & 0xF
];
}
}
class msg {
public $msghdr;
public $questions;
public $answers;
public $ns;
public $extra;
}
function unpackMsgHdr($msg, $offset){
$msgh = new msgHeader();
list($offset, $msgh->id) = unpackUint16($msg, $offset);
list($offset, $msgh->flags) = unpackUint16($msg, $offset);
list($offset, $msgh->querys) = unpackUint16($msg, $offset);
list($offset, $msgh->answers) = unpackUint16($msg, $offset);
list($offset, $msgh->auth_rr) = unpackUint16($msg, $offset);
list($offset, $msgh->add_rr) = unpackUint16($msg, $offset);
$msgh->parseFlags();
return [$offset, $msgh];
}
function decompressLabel($msg, $offset){
$s = '';
while(true){
// Implement protection
$c = ord($msg[$offset]);
$offset++;
switch($c & 0xC0){ // 1100 0000 is used for compression, rest is normal type
case 0x00:
if($c == 0x00)
break 2; // End of label, break out of switch, loop
[$offset, $r] = unpackTake($msg, $offset, $c);
$s .= $r . '.';
break;
case 0xC0:
// Compressed part
break;
}
}
return $s;
}
function unpackMsg($msg, $offset, $header){
// Parse querys
for($i = 0; $i < $header->querys; $i++){
$name = decompressLabel($msg, $offset);
list($offset, $type) = unpackUint16($msg, $offset);
list($offset, $qclass) = unpackUint16($msg, $offset);
echo $name;
}
// Parse responses
}
$msg = new msg();
list($offset, $header) = unpackMsgHdr(hex2bin($dnsMsg), 0);
$msg->msghdr = $header;
unpackMsg(hex2bin($dnsMsg), $offset, $header);