<?php
// Script to find all the common records in a domain and present them
// in a bind friendly format

libxml_use_internal_errors(true);

// Define the array of common records first
$common=array("*._domainkey","_autodiscover._tcp","_caldav._tcp",
        "_caldavs._tcp","_carddav._tcp","_carddavs._tcp","_dmarc",
        "_h323cs._tcp.uc","_h323cs._tcp.vc","_h323ls._udp",
        "_h323ls._udp.uc","_h323ls._udp.vc","_kerberos._udp",
        "_ldap._tcp","_msdcs","_pki-validation","_sip._tcp.uc",
        "_sip._tcp.vc","_sip.tls","_sipfederationtls._tcp","_sips._tcp.uc",
        "_sips._tcp.vc","_sites","_tcp","_udp","access","admin","api","app",
        "as.cwa","autoconfig","autodiscover","backoffice","bbs","blog","caldav","carddav",
        "chat","cloud","cmdb","cms","corp.sts","cpanel","cpcalendars",
        "cpcontacts","crl","cwa","db","demo","dev","dialin","directory",
        "docs","domaindnszones","download","download.cwa","email",
        "enterpriseenrollment","enterpriseregistration","exchange",
        "forestdnszones","forum","ftp","gateway","git","gw","help","imap",
        "imaps","info","lab","ldap","login","lyncdiscover","m","mail",
        "mail-relay","mail1","mail2","mailserver","meet","mobile","msoid",
        "mta01","mx","news","nntp","ns","ns1","ns2","ntp","oscp","outlook","owa","pop",
        "pop3","pop3s","portal","proxy","relay","remote","secure",
        "server","sftp","sharepoint","sip","sip.tls","sipfederationtls",
        "sipfederation._tcp","smtp","spf","socks","sts","support","test",
        "uc","vc","vpn","wap","web","webconf","webdav","webdisk","webmail",
        "whm","wiki","wpad","www","ww2");

sort($common);

// Allow for retrieval of the list
if ( $_SERVER['REQUEST_METHOD'] == 'GET' && !empty($_GET['list']) ) {

	header('Content-Type: text/plain');
	print "*\n";
	print(implode("\n",$common));
	exit;

}

// With this script we can always print he page header

print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
include ("header");
print '<h1 style="text-align:center;">Zone record finder</h1>
	<p>
	This script tries to discover all well known records in a
	given domain and present them in a BIND friendly format.
	Whilst primarily aimed at top level domains it may also 
	return useful results for subdomains<br/>
	If you want a more general DNS discovery tool you might want
	to look at <a href="https://dnsdumpster.com/">DNSdumpster</a>.
	More details about what this tool looks for and the background
	behind it can be found in the ScramWorks <a
	href="https://articles.scramworks.net/2020/08/dns-discovery/">DNS
	discovery</a> article.
	<br/><a
href="https://www.scramworks.net/zone-finder.php?list=yes">Download
record list</a>
	</p>
	<form action="' . $_SERVER['SCRIPT_NAME'] . '" method="POST">
        <p style="text-align:center;">
	<b>N.B.</b> Depending on the domains name servers this script
	may take a while to run.</br>
        Domain : <input name="domain" type="text" maxlength="128" size="32" />
        <br/>
        <input name="submit" type="submit" value="search" />
        </p>
        </form>';

// do the normal sanity checkign of getting input
if ( $_SERVER['REQUEST_METHOD'] == 'POST' && !empty($_POST['domain']) ) {

	$domain=strtolower($_POST['domain']);

} elseif ( $_SERVER['REQUEST_METHOD'] == 'GET' && !empty($_GET['domain']) ) {

	$domain=strtolower($_GET['domain']);

}

if ( empty($domain) ) {

	include('footer');
	exit;
}

$domain=trim($domain);

if ( !filter_var("user@$domain", FILTER_VALIDATE_EMAIL)) {

	print '<p style="text-align:center;">The domain name <b>' . $domain . '</b> appears to be
	invalid, or at least liable to make this script unhappy -
	sorry.</p>';
	include('footer');
	exit;


}

// we need the domain length later
$domlen=strlen($domain);
// Do the SOA seperately for neatness

exec("dig +noall +answer -t soa $domain.",$SOA);
if ( empty($SOA[0])) {

	print '<h3 style="text-align:center;">SOA not found for '.  $domain . ' exiting</h3>';
	include('footer');
	exit;

}


$SOA=$SOA[0];

$DNSrr=dns_get_record($domain,DNS_ALL);

$wild=dns_get_record("*.$domain",DNS_ALL);

// Only do stuff if there's a wild card record
if ( !empty($wild) ) {

	foreach ( $wild as $rwild ) {

		unset($rwild['ttl']);
		$zwild[]=$rwild;

	}

	$DNSrr=array_merge($DNSrr,$zwild);

	$twild=$zwild[0];
	unset($twild['host']);

}

foreach ( $common as $rr ) {

	$rrfound=dns_get_record("$rr.$domain",DNS_ALL);

	if ( empty($rrfound) ) {

		continue;

	} 

	
	// Check for matches with wildcard records

	if ( !empty($twild) ) {

		$wildmatch='';
		foreach ( $rrfound as $check ) {

			unset($check['host']);
			unset($check['ttl']);

			if ( $twild == $check ) {

				$wildmatch=1;
				continue;

			}
		}

		// The record matches the wild card so move on
		if ( !empty($wildmatch) ) {

			continue;

		}

	}

	$DNSrr=array_merge($DNSrr,$rrfound);

}


foreach ( $DNSrr as $rr ) {

	if ( $rr['type'] == "SOA" ) {

		continue;

	} elseif ( strpos($rr['host'],$domain) === FALSE ) {

		continue;

	}

	unset($rr['ttl']);
	unset($rr['entries']);
	if ($rr['type'] == "TXT" ) {

		$rr['txt']='"' . $rr['txt'] . '"';

	}

	// check for additonal records
	if ( !empty($rr['target']) && strpos($rr['target'],$domain)) {

		$additional[]=$rr['target'];

	}

	$trr='';
	$rr['host'] = $rr['host'] . '.';

	if ( !empty($rr['target'] ) ) {

		$rr['target'] = $rr['target'] . '.';
	}

	foreach ( $rr as $data ) {

		$trr .= "$data ";
	}

	$zone[]=$trr;	
}

// Now deal with the additonal records
foreach ( array_unique($additional) as $rr ) {

	$arr=dns_get_record("$rr",DNS_ALL);

	if ( empty($arr) ) {

		continue;
	}

	foreach ( $arr as $arr2 ) {

		unset($arr2['ttl']);
		unset($arr2['entries']);

		$trr='';
		
		if ( substr($arr2['host'],-$domlen) != "$domain") {

			continue;

		}

		$arr2['host'] = $arr2['host'] . '.';

		if ( !empty($arr2['target']) ) {

			$arr2['target'] = $arr2['target'] . '.';

		}

		foreach ( $arr2 as $data ) {

			$trr .="$data ";
		}

		$zone[]=$trr;
	}

}

$rrlist=array_unique($zone);
array_unshift($rrlist,$SOA);


$zonetxt='';

foreach ($rrlist as $rr ) {

	$zonetxt .="$rr\n";

}

print '<h3 style="text-align:center;">' . count($rrlist) . ' records found for ' . $domain . '</h3>
        <hr/>
        <pre>';

print $zonetxt . '</pre>
	<hr/>
	<p><a href="data:text/plain;base64,' . base64_encode($zonetxt)
. '" download="domain.txt">Download</a></p>';
include('footer');
?>
