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; } if (!($socket = fsockopen($host, $this->port, $this->timeout))) { $this->SetError("Failed to Open Socket"); return false; } // Split Into Labels if (preg_match("/[a-z|A-Z]/", $question) == 0) { $labeltmp = explode(".", $question); // reverse ARPA format for ($i = count($labeltmp) - 1; $i >= 0; $i--) { $labels[] = $labeltmp[$i]; } $labels[] = "IN-ADDR"; $labels[] = "ARPA"; } else { // hostname $labels = explode(".", $question); } $question_binary = ""; for ($a = 0; $a < count($labels); $a++) { $size = strlen($labels[$a]); $question_binary .= pack("C", $size); // size byte first $question_binary .= $labels[$a]; // then the label } $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) { if (!fwrite($socket, $header, $headersize)) { $this->SetError("Failed to write question to socket"); fclose($socket); return false; } if (!($this->rawbuffer = fread($socket, 4096))) { $this->SetError("Failed to write read data buffer"); fclose($socket); return false; } } else { 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); $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))); } $extradata = $this->ReadResponse(4); } } // New Functional Method for ($a = 0; $a < $this->header['ancount']; $a++) { $record = $this->ReadRecord(); $dns_answer->AddResult($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($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($record['header']['type'], $record['typeid'], $record['header']['class'], $record['header']['ttl'], $record['data'], $record['domain'], $record['string'], $record['extras']); } return $dns_answer; }
/** * @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; }