#! /usr/bin/env python
import os
import re
import collections

# constants
PING_HOST_RESPONSE = 0
PING_COMMAND = "ping -c 1 -W 1 {0} > /dev/null 2>&1"
ZONE_REGEX = "(\S+)\s+IN\s+([A-Z]+)\s+(\S+)"
DNS_REGEX = "([a-z0-9._-]+)$"

ZONE_FILENAMES = [
	"master/0.16.10.in-addr.arpa",
	"master/125.5.10.in-addr.arpa",
	"master/126.5.10.in-addr.arpa",
	"master/127.5.10.in-addr.arpa",
	"master/phx2.fedoraproject.org"
]

AddressRecord = collections.namedtuple('AddressRecord', 'host, type, value')

def get_host_dict(fp, prefix):
	hosts = dict()

	# get the hostnames from the file
	pattern = re.compile(ZONE_REGEX)
	for line in fp:
		m = pattern.match(line)
		if m:
			full_host = prefix.format(m.group(1))
			if full_host[0] <> ';':
				hosts[full_host] = AddressRecord._make( [full_host, m.group(2), m.group(3)] )
	return hosts

def check_zones_match(fwd_hosts, rev_hosts):
	results = {}
	results["correct"] = []
	results["mismatch"] = []
	results["missing"] = []

	for record in fwd_hosts.values():
		if record.type is 'A':
			try:
				rev_record = rev_hosts[record.value]
				if record.host == rev_record.value:
					results["correct"].append( (record, rev_record) )
				else:
					results["mismatch"].append( (record, rev_record) )
			except KeyError:
				results["missing"].append( (record, None) )
	return results

# ping each host and record the result
def ping(hosts):
	results = {}
	for record in hosts.values():
		results[record] = os.system(PING_COMMAND.format(record.host) )
	return results

def build_dns_suffix(filename, reverse=False):
	m = re.search(DNS_REGEX, filename)
	if m:
		suffix = m.group(1)
		if reverse:
			parts = suffix.split(".")
			return parts[2]+"."+parts[1]+"."+parts[0]+".{0}"
		else:
			return "{0}."+m.group(1)+"."

def main(filenames, check_dns=True, ping_hosts=True, print_stats=False):
	rev_hosts = {}
	fwd_hosts = {}

	for filename in filenames:
		is_reverse = filename.endswith(".in-addr.arpa")
		suffix = build_dns_suffix(filename, is_reverse)
		host_dict = get_host_dict(open(filename, "r"), suffix)

		type_dict = rev_hosts if is_reverse else fwd_hosts
		type_dict.update(host_dict)

	if check_dns:
		check_results = check_zones_match(fwd_hosts, rev_hosts)

		if print_stats:
			print("reverse dns records")
			print("records correct: {0}".format(len(check_results["correct"])))
			print("records incorrect: {0}".format(len(check_results["mismatch"])))
			print("records missing: {0}".format(len(check_results["missing"])))

		for (fwd, rev) in check_results["mismatch"]:
			print ("mismatched record: {0} -> {1} -> {2}".format(fwd.host, fwd.value, rev.value))

		for (fwd, rev) in check_results["missing"]:
			print ("missing record: {0} -> {1}").format(fwd.host, fwd.value)

	if ping_hosts:
		results = ping(fwd_hosts)

		# print all the non-zero (error) results
		for (host, result) in results.items():
			if result is not 0:
				print ("ping failed: {0} (err {1})").format(host.host[:-1], result)

main(ZONE_FILENAMES)
