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;
 }
Example #3
0
 /**
  * @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;
 }