git subrepo clone https://github.com/mailcow/mailcow-dockerized.git mailcow/src/mailcow-dockerized
subrepo: subdir: "mailcow/src/mailcow-dockerized"
merged: "a832becb"
upstream: origin: "https://github.com/mailcow/mailcow-dockerized.git"
branch: "master"
commit: "a832becb"
git-subrepo: version: "0.4.3"
origin: "???"
commit: "???"
Change-Id: If5be2d621a211e164c9b6577adaa7884449f16b5
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/spf.inc.php b/mailcow/src/mailcow-dockerized/data/web/inc/spf.inc.php
new file mode 100644
index 0000000..199f572
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/spf.inc.php
@@ -0,0 +1,143 @@
+<?php
+error_reporting(0);
+
+function get_spf_allowed_hosts($check_domain)
+{
+ $hosts = array();
+
+ $records = dns_get_record($check_domain, DNS_TXT);
+ 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
+ {
+ $hosts = get_spf_allowed_hosts($mod[1]);
+ return $hosts;
+ }
+ }
+ else
+ {
+ unset($cidr);
+ // reset domain to check_domain
+ $domain = $check_domain;
+ 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();
+ if ($mech == 'include' && $check_domain != $domain) // handle an inclusion
+ {
+ $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);
+ }
+ }
+ }
+ foreach ($hosts as &$host) {
+ if (filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
+ $host = $host;
+ }
+ }
+ return $hosts;
+}
+
+
+function get_mx_hosts($domain)
+{
+ $hosts = array();
+ try {
+ $mx_records = dns_get_record($domain, DNS_MX);
+ 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);
+ }
+ }
+ }
+ catch (Exception $e) {
+ if ($e->getMessage() !== 'dns_get_record(): A temporary server error occurred.') {
+ throw $e;
+ }
+ $mx_records = false;
+ }
+ 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);
+ foreach ($a_records as $a_record)
+ {
+ $hosts[] = $a_record['ipv6'];
+ }
+
+ 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);
+}
+?>