Execute
Save
Share
Share link
share
share
share
Team
Public Teams
Comments
0
Created By:
Guest
Title:
Title
Description
Edit
Copy Link
Login
Email *
Password *
Login
OR
Create Account
Screen Name *
Email *
Password *
Retype Password *
Team Access Code
Register
Public CodeBins
HELP
--Select Theme--
Ambiance
Blackboard
Cobalt
Eclipse
Elegant
Erlang-Dark
Lesser-Dark
Monokai
Neat
Night
Rubyblue
Vibrant-Ink
Xq-Dark
New CodeBin
CodeBins Versions
12/27/2013- V.1
Recent CodeBins
View All CodeBins
<? php /** * * DNSLookup class * This class works only with UDP protocol without ipv6 support. Parse only A and SRV records. Don't support truncated queries. Instructions and recomendations from RFC are considered * Returned data format depends from what you ask i.e. what query type you pass in class (A, AAAA, NS, MX, etc). Function which define data format is DNSLookup::getResult() * * Usage: * $dnsinfo = new DNSLookup('www.google.com') or $dnsinfo = new DNSLookup('_xmpp-client._tcp.google.com', 'SRV') or $dnsinfo = new DNSLookup('_xmpp-client._tcp.google.com', 'SRV', '216.87.84.211'); * if($dnsinfo->error == FALSE) * echo $dnsinfo->getResult(); * For more information set $debug to 1 * * References: * http://tools.ietf.org/html/rfc1035 * http://www.phpclasses.org/browse/file/17457.html * http://www.zytrax.com/books/dns/ch15/ * http://www.dnspython.org/docs/1.11.1/dns.rdtypes.IN.SRV-pysrc.html#SRV * * Capabilities may added in future: * IPv6 support * Working with TCP for responses with length more than 512 bytes and for Zone Transfer * Working with truncated queries * Adding more RRs formats * **/ class DNSLookup { public $dnsserver = '8.8.8.8'; public $qclass; public $qtype; public $recursion = 1; //Set RD because if us SRV queries won't be recursive then we dont get information public $opcode = 0; public $domain_name; public $debug = 0; public $error = FALSE; private $qclasses = array("IN" = > 1, "CS" = > 2, "CH" = > 3, "HS" = > 4, "*" = > 255); private $qtypes = array("A" = > 1, "NS" = > 2, "ND" = > 3, "NF" = > 4, "CNAME" = > 5, "SOA" = > 6, "MB" = > 7, "MG" = > 8, "MR" = > 9, "NULL" = > 10, "WKS" = > 11, "PTR" = > 12, "HINFO" = > 13, "MINFO" = > 14, "MX" = > 15, "TXT" = > 16, "RP" = > 17, "SIG" = > 24, "KEY" = > 25, "LOC" = > 29, "NXT" = > 30, "AAAA" = > 28, "SRV" = > 33, "CERT" = > 37, "A6" = > 38, "AXFR" = > 252, "IXFR" = > 251, "*" = > 255); private $query; private $response; private $response_header; private $response_body; public $RR; public $result; public function DNSLookup($domain_name, $qtype = 'A', $dnsserver = '8.8.8.8') { $this - > error = FALSE; $this - > result = FALSE; $this - > dnsserver = $dnsserver; $this - > domain_name = $domain_name; $this - > qclass = $this - > qclasses['IN']; $this - > qtype = $this - > qtypes[$qtype]; if ($this - > debug == TRUE) { echo "<pre>n"; echo "DNS Server: ".$dnsserver."n"; echo "Query type: ".$qtype."n"; echo "Recursion Desired: "; echo($this - > recursion) ? "Yesn" : "Non"; echo "Domain name: ".$domain_name."n"; echo "n</pre>n"; } if ($this - > getDNSResponse() == FALSE) return FALSE; if ($this - > parseDNSResponse() == FALSE) return FALSE; return $this - > getResult(); } /** * *This function create socket, send data to DNS-server and get answer * **/ private function getDNSResponse() { $this - > constructDNSQuery(); $dnssock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); if (!socket_connect($dnssock, $this - > dnsserver, '53')) { $this - > setError("Socket error. Can't connect to DNS server. ".socket_strerror(socket_last_error($dnssock))); return FALSE; } if (!socket_write($dnssock, $this - > query)) { $this - > setError("Socket error. ".socket_strerror(socket_last_error($dnssock))); return FALSE; } $DNSresponse = socket_read($dnssock, 512); socket_close($dnssock); $this - > response = $DNSresponse; if (empty($this - > response)) { $this - > setError('Something is wrong. Zero length response from server'); return FALSE; } return strlen($this - > response); } /** * *This function returns string with DNS question according RFC1035 which we can send to name server *http://tools.ietf.org/html/rfc1035 * **/ private function constructDNSQuery() { //Message header $DNSmsg = chr(rand(0, 255)).chr(rand(1, 255)); //id - first 2 bytes in header $DNSmsg. = chr($this - > setOptions($this - > recursion, $this - > opcode)).chr(0); //next 2 bytes in header ( |QR| Opcode |AA|TC|RD|RA| Z | RCODE | ) $DNSmsg. = chr(0).chr(1); //QDCOUNT = 1 $DNSmsg. = chr(0).chr(0); //ANCOUNT $DNSmsg. = chr(0).chr(0); //NSCOUNT $DNSmsg. = chr(0).chr(0); //ARCOUNT //Message question section foreach(explode('.', $this - > domain_name) as $fqdn_parts) { $DNSmsg. = chr(strlen($fqdn_parts)); //quantity of symbols in each part of domain name $DNSmsg. = $fqdn_parts; //each part of domain name } $DNSmsg. = chr(0); //NULL-byte - end of domain name $DNSmsg. = chr(0).chr($this - > qtype); //QTYPE. SRV = 33 $DNSmsg. = chr(0).chr($this - > qclass); //QCLASS IN = 1 $this - > query = $DNSmsg; return TRUE; } /** * *This function places parsed data into $RR * **/ private function parseDNSResponse() { $this - > parseResponseHeader(); if ($this - > response_header['RCODE'] == 0) //If No errors { if (!$this - > parseResponseBody()) return FALSE; $this - > parseRDATA(); } else { switch ($this - > response_header['RCODE']) { case '1': $this - > setError("Response with RCODE. Format error"); return FALSE; break; case '2': $this - > setError("Response with RCODE. Server failure"); return FALSE; break; case '3': $this - > setError("Response with RCODE. Name Error"); return FALSE; break; case '4': $this - > setError("Response with RCODE. Not Implemented"); return FALSE; break; case '5': $this - > setError("Response with RCODE. Refused"); return FALSE; break; default: $this - > setError("Response with RCODE. Unknown error code"); return FALSE; break; } } return TRUE; } /** * *Parse DNS response header * **/ private function parseResponseHeader() { for ($i = 0; $i < 4; $i++) $bytes[$i] = $this - > getOctetByte($this - > response { $i }); $response_header = array('ID' = > $bytes[0].$bytes[1], 'QR' = > (bool) $bytes[2] { 0 }, 'OPCODE' = > bindec(substr($bytes[2], 1, 4)), 'AA' = > (bool) $bytes[2] { 5 }, 'TC' = > (bool) $bytes[2] { 6 }, 'RD' = > (bool) $bytes[2] { 7 }, 'RA' = > (bool) $bytes[3] { 0 }, 'RCODE' = > bindec(substr($bytes[3], 4, 4)), 'QDCOUNT' = > ord($this - > response { 5 }), 'ANCOUNT' = > ord($this - > response { 7 }), 'NSCOUNT' = > ord($this - > response { 9 }), 'ARCOUNT' = > ord($this - > response { 11 }), ); $this - > response_header = $response_header; if ($this - > debug == TRUE) { echo "<pre>Response header:n"; var_dump($this - > response_header); echo "nn</pre>"; } return TRUE; } /** * *Parse RDATA, TYPE, CLASS, TTL sections from DNS response answer body * **/ private function parseResponseBody() {#Find response section offset $current_offset = $body_offset = 12; $qcount = $this - > response_header['QDCOUNT']; //Quantity of questions while ($qcount > 0) { $qcount--; if ($this - > isPointer($this - > response, $current_offset)) $current_offset += 6; else $current_offset = ((strpos($this - > response, chr(0), $current_offset)) + 5); } #Parse information from each subsection in response section { $rscount = $this - > response_header['ANCOUNT'] + $this - > response_header['NSCOUNT'] + $this - > response_header['ARCOUNT']; //Quantity of sections with response information if ($rscount == 0) { $this - > setError("No records available for ".$this - > domain_name); return FALSE; } while ($rscount > 0) { $rscount--; #Get name if ($addr = $this - > isPointer($this - > response, $current_offset)) { $name = $this - > getName($this - > response, $addr); $current_offset += 2; } else { $name = $this - > getName($this - > response, $current_offset); $current_offset = ((strpos($this - > response, chr(0), $current_offset)) + 1); } #Get type $type = $this - > getInt($this - > response, $current_offset, 2); #Get class $class = $this - > getInt($this - > response, $current_offset, 2); #Get TTL $ttl = $this - > getInt($this - > response, $current_offset, 4); #Get rdlength $rdlength = $this - > getInt($this - > response, $current_offset, 2); #Get rdata $rdata = substr($this - > response, $current_offset, $rdlength); #dataset $this - > response_body[] = array('SECTION' = > '', 'NAME' = > $name, 'TYPE' = > $type, 'CLASS' = > $class, 'TTL' = > $ttl, 'RDATA' = > $rdata); #Change offset $current_offset += $rdlength; } } #This code correlates from what section each dataset $response_sections = array('answer' = > 'ANCOUNT', 'authority' = > 'NSCOUNT', 'additional' = > 'ARCOUNT'); $i = $j = 0; foreach($response_sections as $sname = > $count_name) { if ($this - > response_header[$count_name] > 0) { for ($j = 0; $j < ($this - > response_header[$count_name]); $i++, $j++) { $this - > response_body[$i]['SECTION'] = $sname; } } } if ($this - > debug == TRUE) { echo "<pre>nResponse body:n"; var_dump($this - > response_body); echo "nn</pre>"; } return TRUE; } /** * *This function represnt information from RDATA in readable view *This function very edged because i need only SRV and A records * **/ private function parseRDATA() {#SRV#http: //www.dnspython.org/docs/1.11.1/dns.rdtypes.IN.SRV-pysrc.html#SRV #__slots__ = ['priority', 'weight', 'port', 'target'] #We work only if at least one answer present(or if $debug flag is set) if (($this - > response_header['ANCOUNT'] == 0) && ($this - > debug == FALSE)) { $this - > setError("Response from DNS server is obtained without errors but no ANSWER data for ".$this - > domain_name); return FALSE; } elseif(($this - > response_header['ANCOUNT'] == 0) && ($this - > debug != FALSE)) { echo "n<pre>nNo ANSWER data for ".$this - > domain_name."n</pre>n"; } #Parse and collect information from RDATA foreach($this - > response_body as $n = > $response_entity) { $current_offset = 0; if ($response_entity['SECTION'] == 'answer') { switch ($response_entity['TYPE']) { case '33': //SRV $this - > RR['SRV'][$n]['name'] = $response_entity['NAME']; $this - > RR['SRV'][$n]['priority'] = $this - > getInt($response_entity['RDATA'], $current_offset, 2); $this - > RR['SRV'][$n]['weight'] = $this - > getInt($response_entity['RDATA'], $current_offset, 2); $this - > RR['SRV'][$n]['port'] = $this - > getInt($response_entity['RDATA'], $current_offset, 2); if ($addr = $this - > isPointer($response_entity['RDATA'], $current_offset)) $this - > RR['SRV'][$n]['target'] = $this - > getName($response_entity['RDATA'], $addr); else $this - > RR['SRV'][$n]['target'] = $this - > getName($response_entity['RDATA'], $current_offset); break; case '1': //A $this - > RR['A'][$n]['name'] = $response_entity['NAME']; $this - > RR['A'][$n]['address'] = $this - > getIpAddress($response_entity['RDATA']); break; case '28': //AAAA $this - > RR['AAAA'][$n]['name'] = $response_entity['NAME']; //$this->RR['AAAA'][$n]['address'] = $this->getIpv6Address($response_entity['RDATA']); true; break; default: //All other $this - > RR['unknown'][$n] = $response_entity['RDATA']; break; } } /* IF(DEBUG IS SET) SHOW AUTHORITATIVE ANSWERS; */ } if ($this - > debug == TRUE) { echo "<pre>Obtained resourse records:n"; var_dump($this - > RR); echo "</pre>n"; } return count($this - > RR); } /* * *This function returns information according client question. Check query type and return string * **/ private function getResult() { $flip = array_flip($this - > qtypes); switch ($flip[$this - > qtype]) { case 'SRV': $serverData = $this - > selectServer(); $this - > result = $serverData['target'].':'.$serverData['port']; break; case 'A': $this - > result = $this - > RR['A'][0]['address']; break; case 'AAAA': $this - > result = FALSE; break; default: break; } unset($this - > query); unset($this - > response); unset($this - > response_header); unset($this - > response_body); unset($this - > RR); return $this - > result; } private function selectServer() { foreach($this - > RR['SRV'] as $n = > $server) { $pn = $server['priority']; if (isset($servers[$pn])) { if ($servers[$pn]['weight'] < $server['weight']) $servers[$pn] = $server; } else $servers[$pn] = $server; } ksort($servers); return reset($servers); } /** * *Just returns decimal integer $count bytes length from $str * **/ private function getInt($str, & $pointer, $count) { $result = ''; for ($i = 0; $i < $count; $i++) $result. = $this - > getOctetByte($str { $pointer++ }); return bindec($result); } /** * *Check symbol at offset. If first two bits is ones then it is pointer and then function return address wich places in next byte ($symbol_offset+1) * **/ private function isPointer($sourceString, $symbol_offset) { return (substr($this - > getOctetByte($sourceString { $symbol_offset }), 0, 2) == '11') ? ord($sourceString { ($symbol_offset + 1) }) : FALSE; } /** * *This function returns normally formatted name from offset. * **/ private function getName($sourceStr, $offset) { $name = ''; $string_offset = 0; $end = strpos($sourceStr, chr(0), $offset); $length = $end - $offset; $string = substr($sourceStr, $offset, $length); while ($string_offset < $length) { $count = ord($string { $string_offset++ }); $name. = substr($string, $string_offset, $count).'.'; $string_offset += $count; } return substr($name, 0, (strlen($name) - 1)); } private function getIpAddress($str) { return ord($str { 0 }).".".ord($str { 1 }).".".ord($str { 2 }).".".ord($str { 3 }); } /** * *Function returns binary representation of byte/symbol * **/ private function getOctetByte($byte) { return sprintf("%08d", decbin(ord($byte))); } private function setError($text) { $this - > error = $text; } private function setOptions($RD = 0, $OPCODE = 0) { $optionset = '00000000'; if ($RD) $optionset = $optionset | '00000001'; switch ($OPCODE) { case 0: true; break; case 1: $optionset = $optionset | '00001000'; break; case 2: $optionset = $optionset | '00001000'; break; case 3: $optionset = $optionset | '00010000'; break; case 4: $optionset = $optionset | '00011000'; break; case 5: $optionset = $optionset | '00100000'; break; case 6: $optionset = $optionset | '00101000'; break; case 7: $optionset = $optionset | '00111000'; break; case 8: $optionset = $optionset | '01000000'; break; case 9: $optionset = $optionset | '01001000'; break; case 10: $optionset = $optionset | '01010000'; break; case 11: $optionset = $optionset | '01011000'; break; case 12: $optionset = $optionset | '01100000'; break; case 13: $optionset = $optionset | '01101000'; break; case 14: $optionset = $optionset | '01110000'; break; case 15: $optionset = $optionset | '01111000'; break; } return decbin($optionset); } } ?>
Bottom of Page
In Head
On Load
On Ready
Setting
Validate
Copy
Format
Setting
Validate
Copy
Format
No Doc Type
HTML5
HTML 4.01 Transitional
HTML 4.01 Strict
HTML 4.01 Frameset
XHTML 1.1
XHTML 1.0 Transitional
XHTML 1.0 Strict
XHTML 1.0 Frameset
Copy
Format
Download
×
Code Description
×
Difference of Versions
HTML
CSS
JS
×
JS Error
×
CSS Error
Errors
Warnings
×
JavaScript Setting
JS Libraries:
Chrome Frame 1.0.3
Dojo 1.8.0
Dojo 1.7.3
Dojo 1.7.2
Ext Core 3.1.0
jQuery 1.8.0
jQuery 1.7.2
jQuery 1.6.0
jQuery 1.5.0
jQuery 1.4.4
jQuery 1.4.0
jQuery-min 1.7.2
jQueryUI-min 1.8.21
MooTools more-1.4.0.1-full
MooTools core-1.4.5-full
MooTools core-1.4.1-full
Prototype 1.7.1.0
script.aculo.us 1.9.0
SWFObject 2.2
Twitter Bootstrap 2.0.4
WebFont Loader 1.0.28
yui 3.5.1
User Libraries:
Upload File
JavaScript URL(s):
×
CSS Setting
CSS Libraries:
jQueryUI 1.8.21
Twitter Bootstrap 2.0.4
User Libraries:
Upload File
CSS URL(s):