解决了。
我编写了以下 PHP 代码,它查询 Google 的 SPF 记录,然后,只有在需要时,才会用新的 SMTP Auth 块替换现有的 SMTP Auth 块。然后它会创建一个文件,该文件用作 bash 脚本重新启动防火墙的标志。
请注意,/etc/csf/csf.smtpauth 接受 IPV4 和 IPV6 地址以及 CIDR 地址范围。
// Grab current Google SPF IPs...
$dns = dns_get_record('_spf.google.com', DNS_TXT);
if (!$dns)
{
echo "FAILED TO RETRIEVE DNS RECORD<br />\n";
exit;
}
// The variable in which to store the results
$ranges = array();
// Of interest in particular to us is...
$val = $dns[0]['txt'];
preg_match_all("/include:[^\s]+\s/", $val, $matches);
if (sizeof($matches[0]) <= 0)
{
echo "BAD DATA RECEIVED OR FAILED TO DECODE DATA<br />\n";
exit;
}
foreach ($matches[0] as $match)
{
$match = trim($match);
$domain = trim(preg_replace("/include\:/", "", $match));
// Now do it all again for this domain to get the IP range
$dns = dns_get_record($domain, DNS_TXT);
if (!$dns)
{
echo "DNS LOOKUP FAILURE AT PASS 2<br />\n";
exit;
}
$val = $dns[0]['txt'];
preg_match_all("/ip\d:[^\s]+\s/", $val, $ips);
if (sizeof($ips[0])<=0)
{
// At time of writing this is entirely possible as _netblocks3.google.com
// currently holds NO IP ranges
}
else
{
foreach ($ips[0] as $ip)
{
$ip = trim($ip);
if ($ip <> '')
{
$ip = preg_replace("/ip\d\:/", "", $ip);
$ranges[] = $ip;
}
}
}
}
// To be here means we made it without a major problem. Form the new IP range for
// the smtp auth file (/etc/csf/csf.smtpauth) and compare with the existing. Update only if there has
// been a change. Also update only if there are at least N ranges found.
// When I wrote this there were 11 IPV4 ranges and 6 IPV6 ranges so setting
// low limit to 10
$limit = 10;
$filename = '/etc/csf/csf.smtpauth';
if (sizeof($ranges) < $limit)
{
echo "NOT UPDATING RANGES, TOO FEW DISCOVERED, PROBLEM?";
exit;
}
$filerange = "# GOOGLE SPF RESULTS START\n";
$filerange .= join("\n", $ranges);
$filerange .= "\n# GOOGLE SPF RESULTS END";
// Read in existing conf file
$econf = file_get_contents($filename);
if (sizeof($econf)<=0)
{
echo "FAILED TO READ $filename<br />\n";
exit;
}
// Extract the block
if (!preg_match("/\# GOOGLE SPF RESULTS START.+\# GOOGLE SPF RESULTS END/s", $econf, $matches))
{
echo "FAILED TO FIND EXISTING BLOCK. CORRUPT AUTH FILE?<br />\n";
exit;
}
if ($filerange == $matches[0])
{
// IT'S THE SAME DO NOT UPDATE IT!;
exit;
}
// Replace the block entirely
$econf = preg_replace("/\# GOOGLE SPF RESULTS START.+\# GOOGLE SPF RESULTS END/s", $filerange, $econf);
// Write out the new file contents
file_put_contents($filename, $econf);
// Trigger a CSF/LFD restart by creating trigger file.
touch("restartcsflfd");
然后创建一个 CRON 任务以在每次运行上述内容之后不久运行此 shell 脚本:
#!/bin/bash
if [ -f /path-to-file/restartcsflfd ];
then
csf -r
/etc/init.d/lfd restart
rm -f restartcsflfd
echo "RE-STARTED CSF and LFD"
fi