SPFCheck : Allow to test an IP against the SPF DNS entries sets
git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@5940 bf3deb0d-5f1a-0410-827f-c0cc1f45334c
This commit is contained in:
208
Tests/spfcheckTest.php
Normal file
208
Tests/spfcheckTest.php
Normal file
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
*/
|
||||
|
||||
/** Test the spfcheck tools
|
||||
*/
|
||||
class spfcheckTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function test_getRecords_NoSPF ()
|
||||
{
|
||||
$this->expectException ("Exception",
|
||||
"Can not find a valid SPF TXT entry in DNS for domain ".
|
||||
"'notfound.tester.fournier38.fr'", 403);
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("notfound.tester.fournier38.fr");
|
||||
}
|
||||
|
||||
public function test_getRecords_SPFReject ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("reject.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("reject.spf.tester.fournier38.fr" =>
|
||||
array ("-all" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_Loop ()
|
||||
{
|
||||
$this->expectException ("Exception",
|
||||
"SPFCheck : Too much DNS requests (30 >= 30)", 500);
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("loop.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res, array ());
|
||||
}
|
||||
|
||||
public function test_getRecords_Include_emptyInclude ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("includeempty.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("includeempty.spf.tester.fournier38.fr" =>
|
||||
array ("include:" => array (), "-all" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_Redirect_emptyRedirect ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("redirectempty.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("redirectempty.spf.tester.fournier38.fr" =>
|
||||
array ("redirect=" => array (), "-all" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_MX_emptyMX ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("mx.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("mx.spf.tester.fournier38.fr" =>
|
||||
array ("mx" => array (), "-all" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_MX_validMX ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("mxvalid.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("mxvalid.spf.tester.fournier38.fr" => array (
|
||||
"mx:tester.fournier38.fr" => array (
|
||||
"2a01:e0a:234:3930::103",
|
||||
"2a01:e0a:289:3090::206",
|
||||
"82.64.55.197",
|
||||
"82.64.75.195"),
|
||||
"-all" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_A_emptyA ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("a.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("a.spf.tester.fournier38.fr" =>
|
||||
array ("a" => array (), "-all" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_A_validA ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("avalid.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("avalid.spf.tester.fournier38.fr" => array (
|
||||
"a:tester.fournier38.fr" => array (
|
||||
"2a01:e0a:234:3930::100",
|
||||
"82.64.55.197",),
|
||||
"-all" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_IP4_emptyIP4 ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("ip4empty.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("ip4empty.spf.tester.fournier38.fr" => array (
|
||||
"ip4:" => array (),
|
||||
"-all" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_IP4_invalidIP4 ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("ip4invalid.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("ip4invalid.spf.tester.fournier38.fr" => array (
|
||||
"ip4:0::1" => array (),
|
||||
"-all" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_IP4_validIP4 ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("ip4valid.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("ip4valid.spf.tester.fournier38.fr" => array (
|
||||
"ip4:192.168.1.1" => array ("192.168.1.1"),
|
||||
"-all" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_IP6_emptyIP6 ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("ip6empty.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("ip6empty.spf.tester.fournier38.fr" => array (
|
||||
"ip6:" => array (),
|
||||
"-all" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_IP6_invalidIP6 ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("ip6invalid.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("ip6invalid.spf.tester.fournier38.fr" => array (
|
||||
"ip6:192.168.1.1" => array (),
|
||||
"-all" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_IP6_validIP6 ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("ip6valid.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("ip6valid.spf.tester.fournier38.fr" => array (
|
||||
"ip6:0::1" => array ("0::1"),
|
||||
"-all" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_PTR ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("ptrvalid.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("ptrvalid.spf.tester.fournier38.fr" => array (
|
||||
"ptr" => array (),
|
||||
"-all" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_All_Multiple ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("allmultiple.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("allmultiple.spf.tester.fournier38.fr" => array (
|
||||
"+all" => array (),
|
||||
"-all" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_All_NotEnd ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("allnotend.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("allnotend.spf.tester.fournier38.fr" => array (
|
||||
"+all" => array (),
|
||||
"mx" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_All_NotSet ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("allnotset.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("allnotset.spf.tester.fournier38.fr" => array (
|
||||
"mx" => array ())));
|
||||
}
|
||||
|
||||
public function test_getRecords_Unknown ()
|
||||
{
|
||||
$spfcheck = new spfcheck ();
|
||||
$res = $spfcheck->getRecords ("unknown.spf.tester.fournier38.fr");
|
||||
$this->assertSame ($res,
|
||||
array ("unknown.spf.tester.fournier38.fr" => array (
|
||||
"unknown" => array (),
|
||||
"-all" => array ())));
|
||||
}
|
||||
}
|
||||
472
spfcheck.php
Normal file
472
spfcheck.php
Normal file
@@ -0,0 +1,472 @@
|
||||
<?php
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
*/
|
||||
|
||||
require ("domframework/ipaddresses.php");
|
||||
|
||||
/** This class allow to get a SPF record for a domain and check an IP against
|
||||
* the rules set in SPF record.
|
||||
* It also says in which rule the IP match
|
||||
* RFC 7208
|
||||
* SPF Format :
|
||||
* v=spf1 (ip4:[0-9.]+(/\d+)|ip6:[0-9a-f:]+(/\d+)|mx(:\S+)|
|
||||
* a(:\S+)|
|
||||
* redirect=\S+|include:\S+)
|
||||
*/
|
||||
class spfcheck
|
||||
{
|
||||
////////////////////
|
||||
// PROPERTIES //
|
||||
////////////////////
|
||||
/** The stack of errors detected
|
||||
*/
|
||||
private $errors = array ();
|
||||
/** The [+-~]all parameter first get
|
||||
*/
|
||||
private $catchAll = "";
|
||||
/** The domain catchAll
|
||||
*/
|
||||
private $catchAllDomain = "";
|
||||
/** The rule matching the search
|
||||
*/
|
||||
private $matchRule = "";
|
||||
/** The IP records get from SPF record
|
||||
*/
|
||||
private $ipRecords = array ();
|
||||
/** Store all the DNS requests done
|
||||
*/
|
||||
private $dnsRequests = array ();
|
||||
|
||||
/** Set the DNS maximum number of requests
|
||||
*/
|
||||
const dnsRequestsMax = 30;
|
||||
|
||||
////////////////////////
|
||||
// PUBLIC METHODS //
|
||||
////////////////////////
|
||||
/** Get all the IP entries set in all the blocks of the SPF for provided
|
||||
* domain. Manage all the redirections, and get extract all the MX, IP4, IP6
|
||||
* content.
|
||||
* Set also the $this->errors and $this->catchAll properties available with
|
||||
* the associated getters
|
||||
* @param string $domain The domain to check
|
||||
* @return array (The netmasks to match, the last all)
|
||||
*/
|
||||
public function getRecords ($domain)
|
||||
// {{{
|
||||
{
|
||||
$this->errors = array ();
|
||||
$this->dnsRequests = array ();
|
||||
$this->catchAll = "";
|
||||
$this->ipRecords = $this->getRecordsRecurse ($domain);
|
||||
if ($this->catchAll === "")
|
||||
$this->errors[$domain] = dgettext ("domframework",
|
||||
"No catch all defined for the domain");
|
||||
return $this->ipRecords;
|
||||
}
|
||||
// }}}
|
||||
|
||||
/** Try to match the provided IP address against the $domain SPF record to
|
||||
* be get
|
||||
* @param string $domain The domain to check
|
||||
* @param string $ip The IPv4 or IPv6 address to check against the SPF record
|
||||
* @return string PASS/FAIL/SOFTFAIL
|
||||
*/
|
||||
public function ipCheckToSPF ($domain, $ip)
|
||||
// {{{
|
||||
{
|
||||
$ips = $this->getRecords ($domain);
|
||||
if (filter_var ($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false)
|
||||
$ipType = "ipv4";
|
||||
elseif (filter_var ($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false)
|
||||
$ipType = "ipv6";
|
||||
else
|
||||
throw new \Exception (dgettext ("domframework",
|
||||
"SFPCheck : Invalid IP address provided : Not Ipv4 neither IPv6"), 403);
|
||||
$ipaddresses = new ipaddresses ();
|
||||
foreach ($ips as $key => $sub)
|
||||
{
|
||||
foreach ($sub as $part => $spfips)
|
||||
{
|
||||
foreach ($spfips as $ipToTest)
|
||||
{
|
||||
@list ($ipToTest, $mask) = explode ("/", $ipToTest, 2);
|
||||
if ($ipType === "ipv4")
|
||||
{
|
||||
if (! filter_var ($ipToTest, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))
|
||||
continue;
|
||||
if ($mask === null)
|
||||
$mask = "32";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! filter_var ($ipToTest, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6))
|
||||
continue;
|
||||
if ($mask === null)
|
||||
$mask = "128";
|
||||
}
|
||||
if ($ipaddresses->ipInNetwork ($ip, $ipToTest, $mask))
|
||||
{
|
||||
$this->matchRule = "$key/$part";
|
||||
return "PASS";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->catchAll === "-all")
|
||||
{
|
||||
$this->matchRule = "$this->catchAllDomain/$this->catchAll";
|
||||
return "FAIL";
|
||||
}
|
||||
if ($this->catchAll === "~all")
|
||||
{
|
||||
$this->matchRule = "$this->catchAllDomain/$this->catchAll";
|
||||
return "SOFTFAIL";
|
||||
}
|
||||
}
|
||||
// }}}
|
||||
|
||||
/////////////////
|
||||
// GETTERS //
|
||||
/////////////////
|
||||
/** Get the errors detected when reading the SPF record
|
||||
*/
|
||||
public function getErrors ()
|
||||
// {{{
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
// }}}
|
||||
|
||||
/** Get the DNS requests done to get the SPF records
|
||||
*/
|
||||
public function getDNSRequests ()
|
||||
// {{{
|
||||
{
|
||||
return $this->dnsRequests;
|
||||
}
|
||||
// }}}
|
||||
|
||||
/** Get the number of DNS queries
|
||||
*/
|
||||
public function getDNSRequestNumber ()
|
||||
// {{{
|
||||
{
|
||||
return count ($this->dnsRequests);
|
||||
}
|
||||
// }}}
|
||||
|
||||
/** Get default case (if set)
|
||||
*/
|
||||
public function getDefaultCase ()
|
||||
// {{{
|
||||
{
|
||||
return $this->catchAll;
|
||||
}
|
||||
// }}}
|
||||
|
||||
/** Get the matching rule when testing an IP against a SPF domain record
|
||||
*/
|
||||
public function getMatchRule ()
|
||||
// {{{
|
||||
{
|
||||
return $this->matchRule;
|
||||
}
|
||||
// }}}
|
||||
|
||||
/** Get the IPs from the SPF records
|
||||
*/
|
||||
public function getIpRecords ()
|
||||
// {{{
|
||||
{
|
||||
return $this->ipRecords;
|
||||
}
|
||||
// }}}
|
||||
|
||||
/////////////////////////
|
||||
// PRIVATE METHODS //
|
||||
/////////////////////////
|
||||
/** Get all the IP entries set in all the blocks of the SPF for provided
|
||||
* domain. Manage all the redirections, and get extract all the MX, IP4, IP6
|
||||
* content.
|
||||
* Set also the $this->errors and $this->catchAll properties available with
|
||||
* the associated getters
|
||||
* Recursive, can be called by itself
|
||||
* @param string $domain The domain to check
|
||||
* @return array (The netmasks to match, the last all)
|
||||
*/
|
||||
private function getRecordsRecurse ($domain)
|
||||
// {{{
|
||||
{
|
||||
$records = array ();
|
||||
$localAll = "";
|
||||
// TODO : Catch timeouts !
|
||||
foreach ($this->dns_get_record ($domain, DNS_TXT, $domain) as $record)
|
||||
{
|
||||
if (substr ($record, 0, 7) !== "v=spf1 ")
|
||||
continue;
|
||||
// Do not allow more than 1 SPF record by domain
|
||||
if (key_exists ($domain, $records))
|
||||
$this->errors[$domain][] = sprintf (dgettext ("domframework",
|
||||
"More than one SPF record for domain '%s'"), $domain);
|
||||
$records[$domain] = $record;
|
||||
}
|
||||
if (empty ($records))
|
||||
throw new \Exception (sprintf (dgettext ("domframework",
|
||||
"Can not find a valid SPF TXT entry in DNS for domain '%s'"), $domain),
|
||||
403);
|
||||
$ips = array ();
|
||||
foreach ($records as $domain => $record)
|
||||
{
|
||||
$split = preg_split ("#\s+#", $record);
|
||||
foreach ($split as $nb => $part)
|
||||
{
|
||||
if ($part === "v=spf1")
|
||||
continue;
|
||||
// "redirect=" part
|
||||
$ips[$domain][$part] = array ();
|
||||
if (stripos ($part, "redirect=") === 0)
|
||||
// {{{
|
||||
{
|
||||
$ext = substr ($part, 9);
|
||||
if (! is_string ($ext) || trim ($ext) === "")
|
||||
{
|
||||
$this->errors[$domain][$part] = sprintf (dgettext ("domframework",
|
||||
"Invalid redirect set form domain '%s' : empty"), $domain);
|
||||
continue;
|
||||
}
|
||||
$ips = $ips + $this->getRecordsRecurse ($ext);
|
||||
}
|
||||
// }}}
|
||||
// "include:" part
|
||||
elseif (stripos ($part, "include:") === 0)
|
||||
// {{{
|
||||
{
|
||||
$ext = substr ($part, 8);
|
||||
if (! is_string ($ext) || trim ($ext) === "")
|
||||
{
|
||||
$this->errors[$domain][$part] = sprintf (dgettext ("domframework",
|
||||
"Invalid include set form domain '%s' : empty"), $domain);
|
||||
continue;
|
||||
}
|
||||
$ips = $ips + $this->getRecordsRecurse ($ext);
|
||||
}
|
||||
// }}}
|
||||
// "mx:" / "mx" part
|
||||
elseif (stripos ($part, "mx:") === 0 || strtolower ($part) === "mx")
|
||||
// {{{
|
||||
{
|
||||
$partWithDomain = $part;
|
||||
if ($partWithDomain === "mx")
|
||||
$partWithDomain = "mx:$domain";
|
||||
$ext = substr ($partWithDomain, 3);
|
||||
if (! is_string ($ext) || trim ($ext) === "")
|
||||
{
|
||||
$this->errors[$domain][$part] = sprintf (dgettext ("domframework",
|
||||
"Invalid mx set form domain '%s' : empty"), $domain);
|
||||
continue;
|
||||
}
|
||||
foreach ($this->dns_get_record ($ext, DNS_MX, $domain) as $record)
|
||||
{
|
||||
foreach ($this->dns_get_record ($record, DNS_A | DNS_AAAA, $domain)
|
||||
as $ip)
|
||||
{
|
||||
$ips[$domain][$part][] = $ip;
|
||||
}
|
||||
}
|
||||
sort ($ips[$domain][$part]);
|
||||
}
|
||||
// }}}
|
||||
// "ip4:" part
|
||||
elseif (stripos ($part, "ip4:") === 0)
|
||||
// {{{
|
||||
{
|
||||
$ext = substr ($part, 4);
|
||||
if (! is_string ($ext) || trim ($ext) === "")
|
||||
{
|
||||
$this->errors[$domain][$part] = sprintf (dgettext ("domframework",
|
||||
"Invalid ip4 set form domain '%s' : empty"), $domain);
|
||||
continue;
|
||||
}
|
||||
@list ($ip, $mask) = explode ("/", $ext);
|
||||
$mask = ($mask === null) ? $mask = "" : $mask = "/$mask";
|
||||
if (filter_var ($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false)
|
||||
{
|
||||
$this->errors[$domain][$part] = sprintf (dgettext ("domframework",
|
||||
"Invalid ip4 set for domain '%s' : Not a valid IPv4 '%s'"),
|
||||
$domain, $ext);
|
||||
continue;
|
||||
}
|
||||
$ips[$domain][$part][] = $ip.$mask;
|
||||
}
|
||||
// }}}
|
||||
// "ip6:" part
|
||||
elseif (stripos ($part, "ip6:") === 0)
|
||||
// {{{
|
||||
{
|
||||
$ext = substr ($part, 4);
|
||||
if (! is_string ($ext) || trim ($ext) === "")
|
||||
{
|
||||
$this->errors[$domain][$part] = sprintf (dgettext ("domframework",
|
||||
"Invalid ip6 set form domain '%s' : empty"), $domain);
|
||||
continue;
|
||||
}
|
||||
@list ($ip, $mask) = explode ("/", $ext);
|
||||
$mask = ($mask === null) ? $mask = "" : $mask = "/$mask";
|
||||
if (filter_var ($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false)
|
||||
{
|
||||
$this->errors[$domain][$part] = sprintf (dgettext ("domframework",
|
||||
"Invalid ip6 set for domain '%s' : Not a valid IPv6 '%s'"),
|
||||
$domain, $ext);
|
||||
continue;
|
||||
}
|
||||
$ips[$domain][$part][] = $ip.$mask;
|
||||
}
|
||||
// }}}
|
||||
// "ptr:" MUST NOT BE USED
|
||||
elseif (stripos ($part, "ptr:") === 0 || strtolower ($part) === "ptr")
|
||||
// {{{
|
||||
{
|
||||
$this->errors[$domain][$part] = sprintf (dgettext ("domframework",
|
||||
"Invalid ptr set for domain '%s' : PTR must not be used anymore ".
|
||||
"(see RFC7208)"), $domain, $part);
|
||||
continue;
|
||||
}
|
||||
// }}}
|
||||
// "a:" part
|
||||
elseif (stripos ($part, "a:") === 0 || strtolower ($part) === "a")
|
||||
// {{{
|
||||
{
|
||||
$partWithDomain = $part;
|
||||
if ($partWithDomain === "a")
|
||||
$partWithDomain = "a:$domain";
|
||||
$ext = substr ($partWithDomain, 2);
|
||||
if (! is_string ($ext) || trim ($ext) === "")
|
||||
{
|
||||
$this->errors[$domain][$part] = sprintf (dgettext ("domframework",
|
||||
"Invalid A set form domain '%s' : empty"), $domain);
|
||||
continue;
|
||||
}
|
||||
foreach ($this->dns_get_record ($ext, DNS_A | DNS_AAAA, $domain) as
|
||||
$record)
|
||||
{
|
||||
$ips[$domain][$part][] = $record;
|
||||
}
|
||||
sort ($ips[$domain][$part]);
|
||||
}
|
||||
// }}}
|
||||
// "-all" / "~all" / "+all" part
|
||||
elseif (strtolower ($part) === "-all" ||
|
||||
strtolower ($part) === "~all" ||
|
||||
strtolower ($part) === "+all")
|
||||
// {{{
|
||||
{
|
||||
$ips[$domain][$part] = array ();
|
||||
if ($localAll !== "")
|
||||
{
|
||||
$this->errors [$domain][$part] = sprintf (dgettext ("domframework",
|
||||
"Multiple 'all' definitions for domain '%s'"), $domain);
|
||||
continue;
|
||||
}
|
||||
if ($nb < count ($split) -1)
|
||||
{
|
||||
$this->errors [$domain][$part] = sprintf (dgettext ("domframework",
|
||||
"'all' must be the last part of the record for domain '%s'"),
|
||||
$domain);
|
||||
}
|
||||
$localAll = $part;
|
||||
$this->catchAll = $part;
|
||||
$this->catchAllDomain = $domain;
|
||||
}
|
||||
// }}}
|
||||
else
|
||||
{
|
||||
$this->errors [$domain][$part] = sprintf (dgettext ("domframework",
|
||||
"Unknown record part for domain '%s' : '%s'"), $domain, $part);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $ips;
|
||||
}
|
||||
// }}}
|
||||
|
||||
/** Get the requested hostname and get the type
|
||||
* @param string $hostname The hostname to get
|
||||
* @param integer $type The type to get
|
||||
* @param string $domain The domain to impact the errors
|
||||
* @return array (array (ip (for A), target (for TXT));
|
||||
*/
|
||||
private function dns_get_record ($hostname, $type, $domain)
|
||||
// {{{
|
||||
{
|
||||
$typeStr = "";
|
||||
switch ($type)
|
||||
{
|
||||
case DNS_TXT: $typeStr = "TXT"; break;
|
||||
case DNS_MX: $typeStr = "MX"; break;
|
||||
case DNS_A | DNS_AAAA: $typeStr = "A | AAAA"; break;
|
||||
default: throw new \Exception (dgettext ("domframework",
|
||||
"SPFCheck : Invalid type for DNS get record"), 500);
|
||||
}
|
||||
if (count ($this->dnsRequests) >= self::dnsRequestsMax)
|
||||
throw new \Exception (sprintf (dgettext ("domframework",
|
||||
"SPFCheck : Too much DNS requests (%d >= %d)"),
|
||||
count ($this->dnsRequests), self::dnsRequestsMax), 500);
|
||||
$this->dnsRequests[] = "$hostname, $typeStr";
|
||||
$res = array ();
|
||||
if ($type === DNS_TXT)
|
||||
{
|
||||
foreach (dns_get_record ($hostname, DNS_TXT) as $record)
|
||||
{
|
||||
if (! isset ($record["txt"]))
|
||||
{
|
||||
$this->errors[$somain][] = sprintf (dgettext ("domframework",
|
||||
"No TXT record for domain '%s'"), $domain);
|
||||
continue;
|
||||
}
|
||||
$res[] = $record["txt"];
|
||||
}
|
||||
}
|
||||
elseif ($type === DNS_MX)
|
||||
{
|
||||
foreach (dns_get_record ($hostname, DNS_MX) as $record)
|
||||
{
|
||||
if (! isset ($record["target"]))
|
||||
{
|
||||
$this->errors[$domain][] = sprintf (dgettext ("domframework",
|
||||
"No MX record for domain '%s' : '%s' not found"), $domain,
|
||||
$hostname);
|
||||
continue;
|
||||
}
|
||||
$res[] = $record["target"];
|
||||
}
|
||||
}
|
||||
elseif ($type === DNS_A | DNS_AAAA)
|
||||
{
|
||||
$records = dns_get_record ($hostname, DNS_A | DNS_AAAA);
|
||||
if (empty ($records))
|
||||
$this->errors[$domain][] = sprintf (dgettext ("domframework",
|
||||
"No IP record for domain '%s' : '%s' not found"), $domain,
|
||||
$hostname);
|
||||
foreach ($records as $record)
|
||||
{
|
||||
if (! isset ($record["ip"]) && ! isset ($record["ipv6"]))
|
||||
{
|
||||
$this->errors[$domain][] = sprintf (dgettext ("domframework",
|
||||
"No IP record for domain '%s' : '%s' not IPv4 nor IPv6"), $domain,
|
||||
$hostname);
|
||||
continue;
|
||||
}
|
||||
$ip = isset ($record["ip"]) ? $record["ip"] : $record["ipv6"];
|
||||
$res[] = $ip;
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new \Exception ("Can not get unknown type : $type");
|
||||
return $res;
|
||||
}
|
||||
// }}}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user