public function __construct($type, $algorithm, $labels, $originalttl, $expiration, $inception, $keytag) { parent::__construct(); date_default_timezone_set('UTC'); $types = new DNSTypes(); $this->setTypecovered($types->GetById($type)); $this->setAlgorithm($algorithm); $this->setLabels($labels); $this->setOriginalTTL($originalttl); $this->setExpirationTimestamp($expiration); $this->setInceptionTimestamp($inception); $this->setExpirationDate(date('YmdHis', $expiration)); $this->setInceptionDate(date('YmdHis', $inception)); $this->setKeytag($keytag); }
public function ReadRecord($buffer, $resulttype = '') { $domain = $this->ReadDomainLabel($buffer); $ans_header_bin = $this->ReadResponse($buffer, 10); // 10 byte header $ans_header = unpack("ntype/nclass/Nttl/nlength", $ans_header_bin); #echo "Record Type ".$ans_header['type']." Class ".$ans_header['class']." TTL ".$ans_header['ttl']." Length ".$ans_header['length']."\n"; #$this->DebugBinary($buffer); $types = new DNSTypes(); $typeid = $types->GetById($ans_header['type']); //$extras = array(); switch ($typeid) { case 'A': $result = new dnsAresult(implode(".", unpack("Ca/Cb/Cc/Cd", $this->ReadResponse($buffer, 4)))); break; case 'NS': $result = new dnsNSresult($this->ReadDomainLabel($buffer)); break; case 'PTR': $result = new dnsPTRresult($this->ReadDomainLabel($buffer)); break; case 'CNAME': $result = new dnsCNAMEresult($this->ReadDomainLabel($buffer)); break; case 'MX': $result = new dnsMXresult(); $prefs = $this->ReadResponse($buffer, 2); $prefs = unpack("nprio", $prefs); $result->setPrio($prefs['prio']); $result->setServer($this->ReadDomainLabel($buffer)); break; case 'SOA': $result = new dnsSOAresult(); $result->setNameserver($this->ReadDomainLabel($buffer)); $result->setResponsible($this->ReadDomainLabel($buffer)); $buffer = $this->ReadResponse($buffer, 20); $extras = unpack("Nserial/Nrefresh/Nretry/Nexpiry/Nminttl", $buffer); $result->setSerial($extras['serial']); $result->setRefresh($extras['refresh']); $result->setRetry($extras['retry']); $result->setExpiry($extras['expiry']); $result->setMinttl($extras['minttl']); break; case 'TXT': $result = new dnsTXTResult($this->ReadResponse($buffer, $ans_header['length'])); break; case 'DS': $stuff = $this->ReadResponse($buffer, $ans_header['length']); $length = ($ans_header['length'] - 4) * 2 - 8; $stuff = unpack("nkeytag/Calgo/Cdigest/H" . $length . "string/H*rest", $stuff); $stuff['string'] = strtoupper($stuff['string']); $stuff['rest'] = strtoupper($stuff['rest']); $result = new dnsDSresult($stuff['keytag'], $stuff['algo'], $stuff['digest'], $stuff['string'], $stuff['rest']); break; case 'DNSKEY': $stuff = $this->ReadResponse($buffer, $ans_header['length']); $this->keytag($stuff, $ans_header['length']); $this->keytag2($stuff, $ans_header['length']); $extras = unpack("nflags/Cprotocol/Calgorithm/a*pubkey", $stuff); $flags = sprintf("%016b\n", $extras['flags']); $result = new dnsDNSKEYresult($extras['flags'], $extras['protocol'], $extras['algorithm'], $extras['pubkey']); $result->setKeytag($this->keytag($stuff, $ans_header['length'])); if ($flags[7] == '1') { $result->setZoneKey(true); } if ($flags[15] == '1') { $result->setSep(true); } break; case 'RRSIG': $stuff = $this->ReadResponse($buffer, 18); //$length = $ans_header['length'] - 18; $test = unpack("ntype/calgorithm/clabels/Noriginalttl/Nexpiration/Ninception/nkeytag", $stuff); $result = new dnsRRSIGresult($test['type'], $test['algorithm'], $test['labels'], $test['originalttl'], $test['expiration'], $test['inception'], $test['keytag']); $name = $this->ReadDomainLabel($buffer); $result->setSignername($name); $sig = $this->ReadResponse($buffer, $ans_header['length'] - (strlen($name) + 2) - 18); $result->setSignature($sig); $result->setSignatureBase64(base64_encode($sig)); break; default: // something we can't deal with $result = new dnsResult(); #echo "Length: ".$ans_header['length']."\n"; $stuff = $this->ReadResponse($buffer, $ans_header['length']); $result->setData($stuff); break; } $result->setDomain($domain); $result->setType($ans_header['type']); $result->setTypeid($typeid); $result->setClass($ans_header['class']); $result->setTtl($ans_header['ttl']); $this->AddResult($result, $resulttype); return; }
/** * @param string $question * @param string $type * @return DNSAnswer|false */ public function query($question, $type = 'A') { $this->clearError(); $typeid = $this->types->getByName($type); if ($typeid === false) { $this->setError('Invalid Query Type ' . $type); return false; } if ($this->udp) { $host = 'udp://' . $this->server; } else { $host = $this->server; } $errno = 0; $errstr = ''; if (!($socket = fsockopen($host, $this->port, $errno, $errstr, $this->timeout))) { $this->setError('Failed to Open Socket'); return false; } // handles timeout on stream read set using timeout as well stream_set_timeout($socket, $this->timeout); // Split Into Labels if (preg_match('/[a-z|A-Z]/', $question) == 0 && $question != '.') { // IP Address // reverse ARPA format $labels = array_reverse(explode('.', $question)); $labels[] = 'IN-ADDR'; $labels[] = 'ARPA'; } else { if ($question == '.') { $labels = array(''); } else { // hostname $labels = explode('.', $question); } } $question_binary = ''; foreach ($labels as $label) { if ($label != '') { $size = strlen($label); $question_binary .= pack('C', $size); // size byte first $question_binary .= $label; // then the label } else { //$size = 0; //$question_binary.=pack('C',$size); //$question_binary.=pack('C',$labels[$a]); } } $question_binary .= pack('C', 0); // end it off $this->debug('Question: ' . $question . ' (type=' . $type . '/' . $typeid . ')'); $id = rand(1, 255) | rand(0, 255) << 8; // generate the ID // Set standard codes and flags $flags = 0x100 & 0x300; // recursion & queryspecmask $opcode = 0x0; // opcode // Build the header $header = ''; $header .= pack('n', $id); $header .= pack('n', $opcode | $flags); $header .= pack('nnnn', 1, 0, 0, 0); $header .= $question_binary; $header .= pack('n', $typeid); $header .= pack('n', 0x1); // internet class $headersize = strlen($header); $headersizebin = pack('n', $headersize); $this->debug('Header Length: ' . $headersize . ' Bytes'); $this->debugBinary($header); if ($this->udp && $headersize >= 512) { $this->setError('Question too big for UDP (' . $headersize . ' bytes)'); fclose($socket); return false; } if ($this->udp) { // UDP method if (!fwrite($socket, $header, $headersize)) { $this->setError('Failed to write question to socket'); fclose($socket); return false; } if (!($this->rawbuffer = fread($socket, 4096))) { // read until the end with UDP $this->setError('Failed to read data buffer'); fclose($socket); return false; } } else { // TCP // write the socket if (!fwrite($socket, $headersizebin)) { $this->setError('Failed to write question length to TCP socket'); fclose($socket); return false; } if (!fwrite($socket, $header, $headersize)) { $this->setError('Failed to write question to TCP socket'); fclose($socket); return false; } if (!($returnsize = fread($socket, 2))) { $this->setError('Failed to read size from TCP socket'); fclose($socket); return false; } $tmplen = unpack('nlength', $returnsize); $datasize = $tmplen['length']; $this->debug('TCP Stream Length Limit ' . $datasize); if (!($this->rawbuffer = fread($socket, $datasize))) { $this->setError('Failed to read data buffer'); fclose($socket); return false; } } fclose($socket); $buffersize = strlen($this->rawbuffer); $this->debug('Read Buffer Size ' . $buffersize); if ($buffersize < 12) { $this->setError('Return Buffer too Small'); return false; } $this->rawheader = substr($this->rawbuffer, 0, 12); // first 12 bytes is the header $this->rawresponse = substr($this->rawbuffer, 12); // after that the response $this->responsecounter = 12; // start parsing response counter from 12 - no longer using response so can do pointers $this->debugBinary($this->rawbuffer); $this->header = unpack('nid/nspec/nqdcount/nancount/nnscount/narcount', $this->rawheader); $id = $this->header['id']; $rcode = $this->header['spec'] & 15; $z = $this->header['spec'] >> 4 & 7; $ra = $this->header['spec'] >> 7 & 1; $rd = $this->header['spec'] >> 8 & 1; $tc = $this->header['spec'] >> 9 & 1; $aa = $this->header['spec'] >> 10 & 1; $opcode = $this->header['spec'] >> 11 & 15; $type = $this->header['spec'] >> 15 & 1; $this->debug("ID={$id}, Type={$type}, OPCODE={$opcode}, AA={$aa}, TC={$tc}, RD={$rd}, RA={$ra}, RCODE={$rcode}"); if ($tc == 1 && $this->udp) { // Truncation detected $this->setError('Response too big for UDP, retry with TCP'); return false; } $answers = $this->header['ancount']; $this->debug('Query Returned ' . $answers . ' Answers'); $dns_answer = new DNSAnswer(); // Deal with the header question data if ($this->header['qdcount'] > 0) { $this->debug('Found ' . $this->header['qdcount'] . ' Questions'); for ($a = 0; $a < $this->header['qdcount']; $a++) { $c = 1; while ($c != 0) { $c = hexdec(bin2hex($this->readResponse(1))); } $this->readResponse(4); } } // New Functional Method for ($a = 0; $a < $this->header['ancount']; $a++) { $record = $this->readRecord(); $dns_answer->addResult(new DNSResult($record['header']['type'], $record['typeid'], $record['header']['class'], $record['header']['ttl'], $record['data'], $record['domain'], $record['string'], $record['extras'])); } $this->lastnameservers = new DNSAnswer(); for ($a = 0; $a < $this->header['nscount']; $a++) { $record = $this->readRecord(); $this->lastnameservers->addResult(new DNSResult($record['header']['type'], $record['typeid'], $record['header']['class'], $record['header']['ttl'], $record['data'], $record['domain'], $record['string'], $record['extras'])); } $this->lastadditional = new DNSAnswer(); for ($a = 0; $a < $this->header['arcount']; $a++) { $record = $this->readRecord(); $this->lastadditional->addResult(new DNSResult($record['header']['type'], $record['typeid'], $record['header']['class'], $record['header']['ttl'], $record['data'], $record['domain'], $record['string'], $record['extras'])); } return $dns_answer; }