2017-04-22 12:33:53 +02:00
|
|
|
<?php
|
2017-05-08 23:09:40 +02:00
|
|
|
error_reporting(0);
|
2021-02-11 09:34:21 +01:00
|
|
|
function get_spf_allowed_hosts($check_domain, $expand_ipv6 = false) {
|
2017-04-22 12:33:53 +02:00
|
|
|
$hosts = array();
|
|
|
|
|
2019-08-16 18:20:58 +02:00
|
|
|
$records = dns_get_record($check_domain, DNS_TXT);
|
2017-04-22 12:33:53 +02:00
|
|
|
foreach ($records as $record)
|
|
|
|
{
|
|
|
|
$txt = explode(' ', $record['entries'][0]);
|
|
|
|
if (array_shift($txt) != 'v=spf1') // only handle SPF records
|
|
|
|
continue;
|
|
|
|
|
|
|
|
foreach ($txt as $mech)
|
|
|
|
{
|
|
|
|
$qual = substr($mech, 0, 1);
|
|
|
|
if ($qual == '-' || $qual == '~') // only handle pass or neutral records
|
|
|
|
continue(2);
|
|
|
|
|
|
|
|
if ($qual == '+' || $qual == '?')
|
|
|
|
$mech = substr($mech, 1); // remove the qualifier
|
|
|
|
|
|
|
|
if (strpos($mech, '=') !== FALSE) // handle a modifier
|
|
|
|
{
|
|
|
|
$mod = explode('=', $mech);
|
|
|
|
if ($mod[0] == 'redirect') // handle a redirect
|
|
|
|
{
|
2021-05-28 23:48:15 +02:00
|
|
|
$hosts = get_spf_allowed_hosts($mod[1],true);
|
2017-04-22 12:33:53 +02:00
|
|
|
return $hosts;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unset($cidr);
|
2020-05-25 16:13:51 +02:00
|
|
|
// reset domain to check_domain
|
|
|
|
$domain = $check_domain;
|
2017-04-22 12:33:53 +02:00
|
|
|
if (strpos($mech, ':') !== FALSE) // handle a domain specification
|
|
|
|
{
|
|
|
|
$split = explode(':', $mech);
|
|
|
|
$mech = array_shift($split);
|
|
|
|
$domain = implode(':', $split);
|
|
|
|
if (strpos($domain, '/') !== FALSE) // remove CIDR specification
|
|
|
|
{
|
|
|
|
$split = explode('/', $domain);
|
|
|
|
$domain = $split[0];
|
|
|
|
$cidr = $split[1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$new_hosts = array();
|
2019-08-16 18:20:58 +02:00
|
|
|
if ($mech == 'include' && $check_domain != $domain) // handle an inclusion
|
2017-04-22 12:33:53 +02:00
|
|
|
{
|
|
|
|
$new_hosts = get_spf_allowed_hosts($domain);
|
|
|
|
}
|
|
|
|
elseif ($mech == 'a') // handle a mechanism
|
|
|
|
{
|
|
|
|
$new_hosts = get_a_hosts($domain);
|
|
|
|
}
|
|
|
|
elseif ($mech == 'mx') // handle mx mechanism
|
|
|
|
{
|
|
|
|
$new_hosts = get_mx_hosts($domain);
|
|
|
|
}
|
|
|
|
elseif ($mech == 'ip4' || $mech == 'ip6') // handle ip mechanism
|
|
|
|
{
|
|
|
|
$new_hosts = array($domain);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($cidr)) // add CIDR specification if present
|
|
|
|
{
|
|
|
|
foreach ($new_hosts as &$host)
|
|
|
|
{
|
|
|
|
$host .= '/' . $cidr;
|
|
|
|
}
|
|
|
|
unset($host);
|
|
|
|
}
|
|
|
|
|
|
|
|
$hosts = array_unique(array_merge($hosts,$new_hosts), SORT_REGULAR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-05-25 16:13:51 +02:00
|
|
|
foreach ($hosts as &$host) {
|
|
|
|
if (filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
2021-05-28 23:48:15 +02:00
|
|
|
if ($expand_ipv6 === true) {
|
|
|
|
$hex = unpack("H*hex", inet_pton($host));
|
|
|
|
$host = substr(preg_replace("/([A-f0-9]{4})/", "$1:", $hex['hex']), 0, -1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$host = $host;
|
|
|
|
}
|
2020-05-25 16:13:51 +02:00
|
|
|
}
|
|
|
|
}
|
2017-04-22 12:33:53 +02:00
|
|
|
return $hosts;
|
|
|
|
}
|
|
|
|
|
2017-05-08 15:41:05 +02:00
|
|
|
|
2017-04-22 12:33:53 +02:00
|
|
|
function get_mx_hosts($domain)
|
|
|
|
{
|
|
|
|
$hosts = array();
|
2017-05-08 15:41:05 +02:00
|
|
|
try {
|
|
|
|
$mx_records = dns_get_record($domain, DNS_MX);
|
2017-05-08 23:09:40 +02:00
|
|
|
if ($mx_records) {
|
|
|
|
foreach ($mx_records as $mx_record) {
|
|
|
|
$new_hosts = get_a_hosts($mx_record['target']);
|
|
|
|
$hosts = array_unique(array_merge($hosts,$new_hosts), SORT_REGULAR);
|
|
|
|
}
|
2017-05-08 15:41:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception $e) {
|
|
|
|
if ($e->getMessage() !== 'dns_get_record(): A temporary server error occurred.') {
|
|
|
|
throw $e;
|
|
|
|
}
|
|
|
|
$mx_records = false;
|
|
|
|
}
|
2017-04-22 12:33:53 +02:00
|
|
|
return $hosts;
|
|
|
|
}
|
|
|
|
|
|
|
|
function get_a_hosts($domain)
|
|
|
|
{
|
|
|
|
$hosts = array();
|
|
|
|
|
|
|
|
$a_records = dns_get_record($domain, DNS_A);
|
|
|
|
foreach ($a_records as $a_record)
|
|
|
|
{
|
|
|
|
$hosts[] = $a_record['ip'];
|
|
|
|
}
|
|
|
|
$a_records = dns_get_record($domain, DNS_AAAA);
|
2021-02-11 09:34:21 +01:00
|
|
|
foreach ($a_records as $a_record) {
|
|
|
|
$hosts[] = $a_record['ipv6'];
|
2017-04-22 12:33:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return $hosts;
|
|
|
|
}
|
|
|
|
|
|
|
|
function get_outgoing_hosts_best_guess($domain)
|
|
|
|
{
|
|
|
|
// try the SPF record to get hosts that are allowed to send outgoing mails for this domain
|
|
|
|
$hosts = get_spf_allowed_hosts($domain);
|
|
|
|
if ($hosts) return $hosts;
|
|
|
|
|
|
|
|
// try the MX record to get mail servers for this domain
|
|
|
|
$hosts = get_mx_hosts($domain);
|
|
|
|
if ($hosts) return $hosts;
|
|
|
|
|
|
|
|
// fall back to the A record to get the host name for this domain
|
|
|
|
return get_a_hosts($domain);
|
|
|
|
}
|
2019-08-16 18:20:58 +02:00
|
|
|
?>
|