Пример #1
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;
 }