blob: 199f572a98d36040502747d29da4a16851edd5d1 [file] [log] [blame]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001<?php
2error_reporting(0);
3
4function get_spf_allowed_hosts($check_domain)
5{
6 $hosts = array();
7
8 $records = dns_get_record($check_domain, DNS_TXT);
9 foreach ($records as $record)
10 {
11 $txt = explode(' ', $record['entries'][0]);
12 if (array_shift($txt) != 'v=spf1') // only handle SPF records
13 continue;
14
15 foreach ($txt as $mech)
16 {
17 $qual = substr($mech, 0, 1);
18 if ($qual == '-' || $qual == '~') // only handle pass or neutral records
19 continue(2);
20
21 if ($qual == '+' || $qual == '?')
22 $mech = substr($mech, 1); // remove the qualifier
23
24 if (strpos($mech, '=') !== FALSE) // handle a modifier
25 {
26 $mod = explode('=', $mech);
27 if ($mod[0] == 'redirect') // handle a redirect
28 {
29 $hosts = get_spf_allowed_hosts($mod[1]);
30 return $hosts;
31 }
32 }
33 else
34 {
35 unset($cidr);
36 // reset domain to check_domain
37 $domain = $check_domain;
38 if (strpos($mech, ':') !== FALSE) // handle a domain specification
39 {
40 $split = explode(':', $mech);
41 $mech = array_shift($split);
42 $domain = implode(':', $split);
43 if (strpos($domain, '/') !== FALSE) // remove CIDR specification
44 {
45 $split = explode('/', $domain);
46 $domain = $split[0];
47 $cidr = $split[1];
48 }
49 }
50
51 $new_hosts = array();
52 if ($mech == 'include' && $check_domain != $domain) // handle an inclusion
53 {
54 $new_hosts = get_spf_allowed_hosts($domain);
55 }
56 elseif ($mech == 'a') // handle a mechanism
57 {
58 $new_hosts = get_a_hosts($domain);
59 }
60 elseif ($mech == 'mx') // handle mx mechanism
61 {
62 $new_hosts = get_mx_hosts($domain);
63 }
64 elseif ($mech == 'ip4' || $mech == 'ip6') // handle ip mechanism
65 {
66 $new_hosts = array($domain);
67 }
68
69 if (isset($cidr)) // add CIDR specification if present
70 {
71 foreach ($new_hosts as &$host)
72 {
73 $host .= '/' . $cidr;
74 }
75 unset($host);
76 }
77
78 $hosts = array_unique(array_merge($hosts,$new_hosts), SORT_REGULAR);
79 }
80 }
81 }
82 foreach ($hosts as &$host) {
83 if (filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
84 $host = $host;
85 }
86 }
87 return $hosts;
88}
89
90
91function get_mx_hosts($domain)
92{
93 $hosts = array();
94 try {
95 $mx_records = dns_get_record($domain, DNS_MX);
96 if ($mx_records) {
97 foreach ($mx_records as $mx_record) {
98 $new_hosts = get_a_hosts($mx_record['target']);
99 $hosts = array_unique(array_merge($hosts,$new_hosts), SORT_REGULAR);
100 }
101 }
102 }
103 catch (Exception $e) {
104 if ($e->getMessage() !== 'dns_get_record(): A temporary server error occurred.') {
105 throw $e;
106 }
107 $mx_records = false;
108 }
109 return $hosts;
110}
111
112function get_a_hosts($domain)
113{
114 $hosts = array();
115
116 $a_records = dns_get_record($domain, DNS_A);
117 foreach ($a_records as $a_record)
118 {
119 $hosts[] = $a_record['ip'];
120 }
121 $a_records = dns_get_record($domain, DNS_AAAA);
122 foreach ($a_records as $a_record)
123 {
124 $hosts[] = $a_record['ipv6'];
125 }
126
127 return $hosts;
128}
129
130function get_outgoing_hosts_best_guess($domain)
131{
132 // try the SPF record to get hosts that are allowed to send outgoing mails for this domain
133 $hosts = get_spf_allowed_hosts($domain);
134 if ($hosts) return $hosts;
135
136 // try the MX record to get mail servers for this domain
137 $hosts = get_mx_hosts($domain);
138 if ($hosts) return $hosts;
139
140 // fall back to the A record to get the host name for this domain
141 return get_a_hosts($domain);
142}
143?>