dmarc-srg icon indicating copy to clipboard operation
dmarc-srg copied to clipboard

Feature request - resolve IPs to DNS names

Open williamdes opened this issue 2 years ago • 29 comments

There is two things I did find frustrating when reading reports today:

  • When I click on the IP link all the information is useless to me as I would have needed
    • It's reverse DNS name
    • What MX records exist for this reversed DNS name
  • reverse DNS support when displaying an IP, since an IP is not very informative when browsing my clients reports I need to have a visual way to find out what service is behind the IP in the report without having to open a ton of tabs

So what about reverse DNS support ?

williamdes avatar Jun 19 '23 00:06 williamdes

When I click on the IP link all the information is useless to me as I would have needed

FYI: You can set up another service to display this information.

I need to think how and where to accurately display this information. BTW: there is already a suitable pull request: https://github.com/liuch/dmarc-srg/pull/5

liuch avatar Jun 19 '23 21:06 liuch

The current link to whois from an IP address link does not give much usefull information. Mostly it gives the owner information of a complete ip block. What you want to know is if there is a proper mail server behind the ip-address. If it resolves to something funny or does not resolve at all then it is time to start digging (with another tool maybe.)

My suggestion is to create a link that will attempt to resolve a domain name from the ip-address and display it as a popup. Opening up a new page is too distracting for a quick check. Alternative is to resolve all ip-addresses and add as a title attribute when you create the HTML page. This may however incur a lot of dns overhead and delays.

Note that an ip-address to domain lookup may not come up with the actual domain because there may be hundreds of domains associated with the ip-address. However since the ip-reverse check is very common in determining valid mail servers you may expect that proper mail handlers will set this up in a decent way.

KlaasBonnema avatar Aug 25 '23 07:08 KlaasBonnema

I made some changes that will do a hostname lookup on server IP and then validate that a reverse lookup for ip-address using the hostname returns the original ip-address. A failing lookup of ip-address match will mark the ip-address - hostname entry as red while a match will mark the entry as green. This is similar to the ip-rev check that mail receivers will perform to spot improper mail senders. The actual lookup is being performed by a PHP script. It is called in parallel by an asynchronous fetch so that the dns lookups are executed also in parallel and will not adversly impact page load times.

common.js

	static makeIpElement(ip) {
		let url = null;
		let type = ip.includes(":") && 6 || 4;
		switch (type) {
			case 4:
				url = Common.ipv4_url;
				break;
			case 6:
				url = Common.ipv6_url;
				break;
		}
		let tn = document.createTextNode(ip);
		if (url) {
			url = url.replace("{$ip}", ip).replace("{$eip}", encodeURIComponent(ip));
			let el = document.createElement("a");
			el.setAttribute("href", url);
			el.setAttribute("target", "_blank");
			el.setAttribute("title", "IP address - hostname");
			el.appendChild(tn);
			this.resolveIp(ip, type)
				.then((response) => {
					el.innerHTML = el.innerHTML + " - " + response.hostname;
					if (response.status == 'valid')
						el.setAttribute("class", 'report-result-pass');
					else
						el.setAttribute("class", 'report-result-fail');
				})
				.catch(console.log);
			return el;
		}
		else {
			this.resolveIp(ip, type)
				.then((response) => {
					tn.textContent = tn.textContent + " - " + response.hostname;
					if (response.status == 'valid')
						tn.parentNode.setAttribute("class", 'report-result-pass');
					else
						tn.parentNode.setAttribute("class", 'report-result-fail');
				})
				.catch(console.log);
		}
		return tn;
	}

	static resolveIp = async (ip, type) => {
		const response = await fetch("resolve_ip.php?ip=" + ip + "&type=" + type);
		if (response.ok) {
			return response.json();
		}
	};

resolve_ip.php

<?php
/**
 * Resolve ip-address to hostname and perform reverse lookup to match resolved hostname with ip-address.
 * Mail servers should be set up in dns with a dedicated static hostname. 
 * Flag invalid and non-matching ip-address - hostname pairs.  
 * @var string $ip
 */
$response = array();
$ip = $_GET['ip'];
$type = $_GET['type'];

// empty $ip parameter is invalid
if (empty($ip))
{
    $response['status'] = "invalid";
    $response['hostname'] = "hostname lookup invalid";
    echo json_encode($response);
    exit();
}

// get the hostname by ip
$hostname = gethostbyaddr($ip);
if ($hostname === false)
{
    $response['status'] = "invalid";
    $response['hostname'] = "hostname lookup failed";
    echo json_encode($response);
    exit();
}

// lookup dns to get an array of ip_addresses by hostname
switch ($type)
{
    case "6":
        {
            // lookup ipv6 
            $ip_res = dns_get_record($hostname, DNS_AAAA);
            break;
        }
    case "4":
    default:
        {
            // lookup ipv4
            $ip_res = dns_get_record($hostname, DNS_A);
            break;
        }
}

// invalid if result is not an array
if (! is_array($ip_res))
{
    $response['status'] = "invalid";
    $response['hostname'] = $hostname;
    echo json_encode($response);
    exit();
}

// match our input ip with the result ip's. A match returns a valid status
foreach ($ip_res as $entry)
{
    if (($type == "6" && isset($entry['ipv6']) && inet_ntop(inet_pton($entry['ipv6'])) == $ip) || (isset($entry['ip']) && $entry['ip'] == $ip))
    {
        $response['status'] = "valid";
        $response['hostname'] = $hostname;
        echo json_encode($response);
        exit();
    }
}

// no match found, return invalid status
$response['status'] = "invalid";
$response['hostname'] = $hostname;
echo json_encode($response);
exit();

KlaasBonnema avatar Aug 28 '23 14:08 KlaasBonnema

I will try to implement something like this. At the very least, your php code lacks input parameter validation and access level validation. There are questions to the js code as well. But the main thing is your idea. Thank you.

liuch avatar Aug 28 '23 22:08 liuch