Skip to content

Instantly share code, notes, and snippets.

@stephanhuewe
Forked from horsley/dns.php
Last active May 18, 2023 08:53
Show Gist options
  • Save stephanhuewe/8998156ff5148df86eaed92d415db197 to your computer and use it in GitHub Desktop.
Save stephanhuewe/8998156ff5148df86eaed92d415db197 to your computer and use it in GitHub Desktop.
Simple PHP code act as a dig tool to find dns records (using specific given nameservers)
<?php
$result = array();
$result_html = '';
function getDnsRecords($domain) {
$result = array();
$servers = array("8.8.8.8", "8.8.8.8", "8.8.8.8", "8.8.8.8", "8.8.8.8", "8.8.8.8", "8.8.8.8", "8.8.8.8");
foreach ($servers as $server) {
$dnsResult = dns_get_record_from($server, "A", $domain);
foreach ($dnsResult as $record) {
reset($record);
$host = $domain;
$type = "A";
$value = $record;
$result[] = array(
'server' => $server,
'host' => $host,
'type' => $type,
'value' => $value
);
}
}
return $result;
}
if (isset($_POST['domain']) && !empty($_POST['domain'])) {
$domain = $_POST['domain'];
$domain_regex = '/[a-z\d][a-z\-\d\.]+[a-z\d]/i';
if (preg_match($domain_regex, $domain)) {
if ($url = parse_url($domain)) {
if (isset($url['host'])) {
$result = getDnsRecords($url['host']);
} else if (isset($url['path'])) {
$result = getDnsRecords($domain);
}
}
}
if (empty($result)) {
$result_html = '<hr>Nothing found or Domain Invalid';
} else {
$result_html .= "<hr>\n<table>\n";
foreach ($result as $record) {
$result_html .= sprintf("<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n", $record['server'], $record['host'], $record['type'], $record['value']);
}
$result_html .= "</table>\n";
}
}
function dns_get_record_from(string $server, string $type, string $record): array
{
// Source: https://github.com/metaregistrar/php-dns-client/blob/master/DNS/dnsData/dnsTypes.php
static $types = [
1 => 'A',
2 => 'NS',
5 => 'CNAME',
6 => 'SOA',
12 => 'PTR',
15 => 'MX',
16 => 'TXT',
28 => 'AAAA',
255 => 'ANY',
];
$typeid = array_search($type, $types, true);
if (!$typeid) {
throw new \InvalidArgumentException('Invalid type');
}
$host = 'udp://' . $server;
if (!$socket = @fsockopen($host, 53, $errno, $errstr, 10)) {
throw new \RuntimeException('Failed to open socket to ' . $host);
}
$labels = explode('.', $record);
$question_binary = '';
foreach ($labels as $label) {
$question_binary .= pack("C", strlen($label)); // size byte first
$question_binary .= $label; // then the label
}
$question_binary .= pack("C", 0); // end it off
$id = rand(1,255)|(rand(0,255)<<8); // generate the ID
// Set standard codes and flags
$flags = (0x0100 & 0x0300) | 0x0020; // recursion & queryspecmask | authenticated data
$opcode = 0x0000; // 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", 0x0001); // internet class
$headersize = strlen($header);
$headersizebin = pack("n", $headersize);
$request_size = fwrite($socket, $header, $headersize);
$rawbuffer = fread($socket, 4096);
fclose($socket);
if (strlen($rawbuffer) < 12) {
throw new \RuntimeException("DNS query return buffer too small");
}
$pos = 0;
$read = function ($len) use (&$pos, $rawbuffer) {
$out = substr($rawbuffer, $pos, $len);
$pos += $len;
return $out;
};
$read_name_pos = function ($offset) use ($rawbuffer) {
$out = [];
while (($len = ord(substr($rawbuffer, $offset, 1))) && $len > 0) {
$out[] = substr($rawbuffer, $offset + 1, $len);
$offset += $len + 1;
}
return $out;
};
$read_name = function() use (&$read, $read_name_pos) {
$out = [];
while (($len = ord($read(1))) && $len > 0) {
if ($len >= 64) {
$offset = (($len & 0x3f) << 8) + ord($read(1));
$out = array_merge($out, $read_name_pos($offset));
break;
}
else {
$out[] = $read($len);
}
}
return implode('.', $out);
};
$header = unpack("nid/nflags/nqdcount/nancount/nnscount/narcount", $read(12));
$flags = sprintf("%016b\n", $header['flags']);
// No answers
if (!$header['ancount']) {
return [];
}
$is_authorative = $flags[5] == 1;
// Question section
if ($header['qdcount']) {
// Skip name
$read_name();
// skip question part
$pos += 4; // 4 => QTYPE + QCLASS
}
$responses = [];
for ($a = 0; $a < $header['ancount']; $a++) {
$read_name(); // Skip name
$ans_header = unpack("ntype/nclass/Nttl/nlength", $read(10));
$t = $types[$ans_header['type']] ?? null;
if ($type != 'ANY' && $t != $type) {
// Skip type that was not requested
$t = null;
}
switch ($t) {
case 'A':
$responses[] = implode(".", unpack("Ca/Cb/Cc/Cd", $read(4)));
break;
case 'AAAA':
$responses[] = implode(':', unpack("H4a/H4b/H4c/H4d/H4e/H4f/H4g/H4h", $read(16)));
break;
case 'MX':
$prio = unpack('nprio', $read(2)); // priority
$responses[$prio['prio']] = $read_name();
break;
case 'NS':
case 'CNAME':
case 'PTR':
$responses[] = $read_name();
break;
case 'TXT':
$responses[] = $read($ans_header['length']);
break;
default:
// Skip
$read($ans_header['length']);
break;
}
}
return $responses;
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>DNS Lookup</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
padding: 20px;
}
.form-inline {
margin-bottom: 10px;
}
table {
margin: auto;
width: 100%;
}
</style>
</head>
<body>
<div class="container">
<h1 class="text-center">DNS Lookup</h1>
<form method="post">
<div class="form-inline justify-content-center">
<label for="domain">Domain:</label>
<input id="domain" type="text" name="domain" class="form-control mx-2" value="<?= empty($_POST['domain']) ? '' : $_POST['domain'] ?>">
<button type="submit" class="btn btn-primary">Lookup</button>
</div>
</form>
<div class="mt-4">
<?= $result_html ? $result_html : '' ?>
</div>
<hr>
</div>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment