= $pfb['skipfeed']) {
$log = " Max daily download failure attempts exceeded. Clear widget 'failed downloads' to reset.\n\n";
pfb_logger("{$log}", 1);
unlink_if_exists("{$pfbfolder}/{$header}.fail");
return;
}
}
// Attempt download, when a previous 'fail' file marker is found.
if (file_exists("{$pfbfolder}/{$header}.fail")) {
$log = "\t\t\tPrevious download failed.\tRe-attempt download\n";
pfb_logger("{$log}", 1);
$pfb['update_cron'] = TRUE;
unlink_if_exists("{$pfbfolder}/{$header}.txt");
return;
}
}
else {
unlink_if_exists("{$pfbfolder}/{$header}.fail");
}
// Check if List file doesn't exist or Format is 'whois'.
if (!file_exists("{$pfbfolder}/{$header}.txt") || $format == 'whois') {
$log = "\t\t\t\t\t\t\tUpdate found\n";
pfb_logger("{$log}", 1);
$pfb['update_cron'] = TRUE;
return;
}
$host = @parse_url($list_url);
$local_file = "{$pfborig}/{$header}.orig";
// Compare previously downloaded file timestamp with remote timestamp
if (file_exists($local_file)) {
if ($format == 'rsync') {
$log = "\t\t\t\t( rsync )\t\tUpdate found\n";
pfb_logger("{$log}", 1);
$pfb['update_cron'] = TRUE;
unlink_if_exists("{$pfbfolder}/{$header}.txt");
return;
}
// Determine if URL is Remote or Local
if (in_array($host['host'], array('127.0.0.1', $pfb['iplocal'], ''))) {
clearstatcache();
$remote_tds = gmdate('D, d M Y H:i:s T', @filemtime($list_url));
}
else {
// Download URL headers and compare previously downloaded file with remote timestamp
if (($ch = curl_init($list_url))) {
curl_setopt_array($ch, $pfb['curl_defaults']); // Load curl default settings
curl_setopt($ch, CURLOPT_NOBODY, true); // Exclude the body from the output
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
// Allow downgrade of cURL settings if user configured
if ($pflex == 'Flex') {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'TLSv1.2, TLSv1, SSLv3');
}
// Try up to 3 times to download the file before giving up
for ($retries = 1; $retries <= 3; $retries++) {
if (curl_exec($ch)) {
$remote_stamp_raw = curl_getinfo($ch, CURLINFO_FILETIME);
break; // Break on success
}
sleep(3);
}
if ($remote_stamp_raw != -1) {
$remote_tds = gmdate('D, d M Y H:i:s T', $remote_stamp_raw);
}
}
else {
$remote_stamp_raw = -1;
}
curl_close($ch);
}
// If remote timestamp not found, Attempt md5 comparison
if ($remote_stamp_raw == -1) {
// Collect md5 checksums
$remote_md5 = @md5_file($list_url);
$local_md5 = @md5_file($local_file);
if ($remote_md5 != $local_md5) {
$log = "\t\t\t\t( md5 changed )\t\tUpdate found\n";
pfb_logger("{$log}", 1);
$pfb['update_cron'] = TRUE;
unlink_if_exists("{$pfbfolder}/{$header}.txt");
return;
}
else {
$log = "\t( No remote timestamp/md5 unchanged )\t\tUpdate not required\n";
pfb_logger("{$log}", 1);
return;
}
}
else {
$log = " Remote timestamp: {$remote_tds}\n";
pfb_logger("{$log}", 1);
clearstatcache();
$local_tds = gmdate('D, d M Y H:i:s T', @filemtime($local_file));
$log = " Local timestamp: {$local_tds}\t";
pfb_logger("{$log}", 1);
if ("{$remote_tds}" != "{$local_tds}") {
$pfb['cron_update'] = TRUE;
}
else {
$log = "Update not required\n";
pfb_logger("{$log}", 1);
$pfb['cron_update'] = FALSE;
}
}
} else {
$pfb['cron_update'] = TRUE;
}
if ($pfb['cron_update']) {
// Trigger CRON process if updates are found.
$pfb['update_cron'] = TRUE;
$log = "Update found\n";
pfb_logger("{$log}", 1);
unlink_if_exists("{$pfbfolder}/{$header}.txt");
}
return;
}
// Download Extras - MaxMind/Alexa feeds via cURL
function pfblockerng_download_extras($timeout=600) {
global $pfb;
$pfberror = FALSE;
pfb_logger("\nDownload Process Starting [ NOW ]\n", 3);
foreach ($pfb['extras'] as $feed) {
$file_dwn = "{$feed['folder']}/{$feed['file_dwn']}";
if (!pfb_download($feed['url'], $file_dwn, FALSE, "{$feed['folder']}/{$feed['file']}", '', 3, '', $timeout)) {
$log = "\nFailed to Download {$feed['file']}\n";
pfb_logger("{$log}", 3);
// On install, if error found when downloading MaxMind Continent lists
// Return error to install process to download archive from pfSense package repo
if ($feed['install']) {
$pfberror = TRUE;
}
}
}
pfb_logger("Download Process Ended [ NOW ]\n\n", 3);
if ($pfberror) {
return FALSE;
} else {
return TRUE;
}
}
// Function to update Lists/Feeds as per Cron
function pfblockerng_sync_cron() {
global $config, $pfb, $pfbarr;
// Call base hour converter
$pfb_sch = pfb_cron_base_hour();
$hour = date('G');
$dow = date('N');
$pfb['update_cron'] = FALSE;
$log = " CRON PROCESS START [ NOW ]\n";
pfb_logger("{$log}", 1);
$list_type = array('pfblockernglistsv4' => '_v4', 'pfblockernglistsv6' => '_v6', 'pfblockerngdnsbl' => '_v4', 'pfblockerngdnsbleasylist' => '_v4');
foreach ($list_type as $ip_type => $vtype) {
if (!empty($config['installedpackages'][$ip_type]['config'])) {
foreach ($config['installedpackages'][$ip_type]['config'] as $list) {
if (isset($list['row']) && $list['action'] != 'Disabled' && $list['cron'] != 'Never') {
foreach ($list['row'] as $row) {
if (!empty($row['url']) && $row['state'] != 'Disabled') {
if ($vtype == '_v4') {
$header = "{$row['header']}";
} else {
$header = "{$row['header']}_v6";
}
// Determine folder location for alias (return array $pfbarr)
pfb_determine_list_detail($list['action'], '', '', '');
$pfbfolder = $pfbarr['folder'];
$pfborig = $pfbarr['orig'];
// Bypass update if state is defined as 'Hold' and list file exists
if ($row['state'] == 'Hold' && file_exists("{$pfbfolder}/{$header}.txt")) {
continue;
}
// Allow cURL SSL downgrade if user configured.
$pflex = FALSE;
if ($row['state'] == 'Flex') {
$pflex = TRUE;
}
switch ($list['cron']) {
case 'EveryDay':
if ($hour == $pfb['24hour']) {
pfb_update_check($header, $row['url'], $pfbfolder, $pfborig, $pflex, $row['format']);
}
break;
case 'Weekly':
if ($hour == $pfb['24hour'] && $dow == $list['dow']) {
pfb_update_check($header, $row['url'], $pfbfolder, $pfborig, $pflex, $row['format']);
}
break;
default:
if ($pfb['interval'] == '1' || in_array($hour, $pfb_sch)) {
pfb_update_check($header, $row['url'], $pfbfolder, $pfborig, $pflex, $row['format']);
}
break;
}
}
}
}
}
}
}
// If no lists require updates, check if Continents are configured and update accordingly.
if (!$pfb['update_cron']) {
foreach ($pfb['continents'] as $continent => $pfb_alias) {
if (isset($config['installedpackages']['pfblockerng' . strtolower(str_replace(' ', '', $continent))]['config'])) {
$continent_config = $config['installedpackages']['pfblockerng' . strtolower(str_replace(' ', '', $continent))]['config'][0];
if ($continent_config['action'] != 'Disabled') {
$pfb['update_cron'] = TRUE;
break;
}
}
}
}
if ($pfb['update_cron']) {
sync_package_pfblockerng('cron');
$pfb['update_cron'] = FALSE;
} else {
sync_package_pfblockerng('noupdates');
$log = "\n No Updates required.\n CRON PROCESS ENDED\n UPDATE PROCESS ENDED\n";
pfb_logger("{$log}", 1);
}
// Call log mgmt function
// If Update GUI 'Manual view' is selected. Last output will be missed. So sleep for 5 secs.
sleep(5);
pfb_log_mgmt();
}
// Function to process the downloaded MaxMind database and format into Continent txt files.
function pfblockerng_uc_countries() {
global $pfb;
$maxmind_cont = "{$pfb['geoipshare']}/country_continent.csv";
$maxmind_cc4 = "{$pfb['geoipshare']}/GeoIPCountryWhois.csv";
$maxmind_cc6 = "{$pfb['geoipshare']}/GeoIPv6.csv";
// Create folders if not exist
$folder_array = array ("{$pfb['dbdir']}", "{$pfb['logdir']}", "{$pfb['ccdir']}");
foreach ($folder_array as $folder) {
safe_mkdir ("{$folder}", 0755);
}
$now = date('m/d/y G:i:s', time());
$log = "Country code update Start [ NOW ]\n";
if (!$g['pfblockerng_install']) {
print "Country code update Start [ $now ]\n";
}
pfb_logger("{$log}", 3);
if (!file_exists($maxmind_cont) || !file_exists($maxmind_cc4) || !file_exists($maxmind_cc6)) {
$log = " [ MAXMIND UPDATE FAIL, CSV missing, using previous Country code database \n";
if (!$g['pfblockerng_install']) {
print $log;
}
pfb_logger("{$log}", 3);
return;
}
// Save Date/Time stamp to MaxMind version file
$local_tds4 = @gmdate('D, d M Y H:i:s T', @filemtime($maxmind_cc4));
$local_tds6 = @gmdate('D, d M Y H:i:s T', @filemtime($maxmind_cc6));
$maxmind_ver = "MaxMind GeoLite Date/Time Stamps\n";
$maxmind_ver .= "Local_v4 \tLast-Modified: {$local_tds4}\n";
$maxmind_ver .= "Local_v6 \tLast-Modified: {$local_tds6}\n";
@file_put_contents("{$pfb['logdir']}/maxmind_ver", $maxmind_ver, LOCK_EX);
// Collect ISO codes for each Continent
$log = " Processing Continent Data\n";
if (!$g['pfblockerng_install']) {
print $log;
}
pfb_logger("{$log}", 3);
$cont_array = array();
if (($handle = fopen("{$maxmind_cont}", 'r')) !== FALSE) {
while (($cc = fgetcsv($handle)) !== FALSE) {
$cc_key = $cc[0];
$cont_key = $cc[1];
switch ($cont_key) {
case 'AF':
$cont_array[0]['continent'] = 'Africa';
$cont_array[0]['iso'] .= "{$cc_key},";
$cont_array[0]['file4'] = "{$pfb['ccdir']}/Africa_v4.txt";
$cont_array[0]['file6'] = "{$pfb['ccdir']}/Africa_v6.txt";
break;
case 'AS':
$cont_array[1]['continent'] = 'Asia';
$cont_array[1]['iso'] .= "{$cc_key},";
$cont_array[1]['file4'] = "{$pfb['ccdir']}/Asia_v4.txt";
$cont_array[1]['file6'] = "{$pfb['ccdir']}/Asia_v6.txt";
break;
case 'EU':
$cont_array[2]['continent'] = 'Europe';
$cont_array[2]['iso'] .= "{$cc_key},";
$cont_array[2]['file4'] = "{$pfb['ccdir']}/Europe_v4.txt";
$cont_array[2]['file6'] = "{$pfb['ccdir']}/Europe_v6.txt";
break;
case 'NA':
$cont_array[3]['continent'] = 'North America';
$cont_array[3]['iso'] .= "{$cc_key},";
$cont_array[3]['file4'] = "{$pfb['ccdir']}/North_America_v4.txt";
$cont_array[3]['file6'] = "{$pfb['ccdir']}/North_America_v6.txt";
break;
case 'OC':
$cont_array[4]['continent'] = 'Oceania';
$cont_array[4]['iso'] .= "{$cc_key},";
$cont_array[4]['file4'] = "{$pfb['ccdir']}/Oceania_v4.txt";
$cont_array[4]['file6'] = "{$pfb['ccdir']}/Oceania_v6.txt";
break;
case 'SA':
$cont_array[5]['continent'] = 'South America';
$cont_array[5]['iso'] .= "{$cc_key},";
$cont_array[5]['file4'] = "{$pfb['ccdir']}/South_America_v4.txt";
$cont_array[5]['file6'] = "{$pfb['ccdir']}/South_America_v6.txt";
break;
}
}
}
unset($cc);
fclose($handle);
// Add Maxmind Anonymous Proxy and Satellite Providers to array
$cont_array[6]['continent'] = 'Proxy and Satellite';
$cont_array[6]['iso'] = 'A1,A2';
$cont_array[6]['file4'] = "{$pfb['ccdir']}/Proxy_Satellite_v4.txt";
$cont_array[6]['file6'] = "{$pfb['ccdir']}/Proxy_Satellite_v6.txt";
sort($cont_array);
// Collect Country ISO data and sort to Continent arrays (IPv4 and IPv6)
foreach (array('4', '6') as $type) {
$log = " Processing ISO IPv{$type} Continent/Country Data\n";
if (!$g['pfblockerng_install']) {
print $log;
}
pfb_logger("{$log}", 3);
if ($type == '4') {
$maxmind_cc = "{$pfb['geoipshare']}/GeoIPCountryWhois.csv";
} else {
$maxmind_cc = "{$pfb['geoipshare']}/GeoIPv6.csv";
}
$iptype = "ip{$type}";
$filetype = "file{$type}";
if (($handle = fopen("{$maxmind_cc}", 'r')) !== FALSE) {
while (($cc = fgetcsv($handle)) !== FALSE) {
$cc_key = $cc[4];
$country_key = $cc[5];
$a_cidr = implode(',', ip_range_to_subnet_array_temp($cc[0], $cc[1]));
foreach ($cont_array as $key => $iso) {
if (strpos($iso['iso'], $cc_key) !== FALSE) {
$cont_array[$key][$cc_key][$iptype] .= "{$a_cidr},";
$cont_array[$key][$cc_key]['country'] = $country_key;
continue;
}
}
}
}
unset($cc);
fclose($handle);
// Build Continent files
foreach ($cont_array as $key => $iso) {
$header = $pfb_file = $iso_key = '';
$header .= '# Generated from MaxMind Inc. on: ' . date('m/d/y G:i:s', time()) . "\n";
$header .= "# Continent IPv{$type}: {$cont_array[$key]['continent']}\n";
$pfb_file = $cont_array[$key][$filetype];
$iso_key = array_keys($iso);
foreach ($iso_key as $ikey) {
if (strlen($ikey) == 2) {
$header .= "# Country: {$iso[$ikey]['country']}\n";
$header .= "# ISO Code: {$ikey}\n";
$header .= '# Total Networks: ' . substr_count($iso[$ikey][$iptype], ',') . "\n";
$header .= str_replace(',', "\n", $iso[$ikey][$iptype]);
$iso[$ikey][$iptype] = '';
}
}
@file_put_contents($pfb_file, $header, LOCK_EX);
}
}
}
// Function to process Continent txt files and create Country ISO files and to Generate GUI XML files.
function pfblockerng_get_countries() {
global $pfb;
$files = array ( 'Africa' => "{$pfb['ccdir']}/Africa_v4.txt",
'Asia' => "{$pfb['ccdir']}/Asia_v4.txt",
'Europe' => "{$pfb['ccdir']}/Europe_v4.txt",
'North America' => "{$pfb['ccdir']}/North_America_v4.txt",
'Oceania' => "{$pfb['ccdir']}/Oceania_v4.txt",
'South America' => "{$pfb['ccdir']}/South_America_v4.txt",
'Proxy and Satellite' => "{$pfb['ccdir']}/Proxy_Satellite_v4.txt"
);
// Collect data to generate new continent XML files.
$log = " Building pfBlockerNG XML Files \n";
if (!$g['pfblockerng_install']) {
print $log;
}
pfb_logger("{$log}", 3);
foreach ($files as $cont => $file) {
// Process the following for IPv4 and IPv6
foreach (array('4', '6') as $type) {
$log = " IPv{$type} {$cont}\n";
if (!$g['pfblockerng_install']) {
print $log;
}
pfb_logger("{$log}", 3);
if ($type == '6') {
$file = str_replace('v4', 'v6', $file);
}
$convert = explode("\n", file_get_contents($file));
$cont_name = str_replace(' ', '', $cont);
$cont_name_lower = strtolower($cont_name);
$active = array("$cont" => '');
$lastkey = count($convert) - 1;
$pfb['complete'] = FALSE;
$keycount = 1;
$total = 0;
$xml_data = '';
foreach ($convert as $line) {
if (substr($line, 0, 1) == '#') {
if ($pfb['complete']) {
${'coptions' . $type}[] = "{$country}-{$isocode} ({$total}){$isocode}";
// Only collect IPv4 for Reputation Tab
if ($type == '4') {
$roptions4[] = "{$country}-{$isocode} ({$total}){$isocode}";
}
// Save ISO data
@file_put_contents("{$pfb['ccdir']}/{$isocode}_v{$type}.txt", $xml_data, LOCK_EX);
// Clear variables and restart Continent collection process
unset($total, $xml_data);
$pfb['complete'] = FALSE;
}
// Don't collect Countries with null data
if (strpos($line, 'Total Networks: 0') !== FALSE) {
continue;
}
if (strpos($line, 'Country: ') !== FALSE) {
$country = str_replace('# Country: ', '', $line);
}
if (strpos($line, 'ISO Code: ') !== FALSE) {
$isocode = str_replace('# ISO Code: ', '', $line);
}
}
elseif (substr($line, 0, 1) != '#') {
$total++;
if (!empty($line)) {
$xml_data .= "{$line}\n";
}
$pfb['complete'] = TRUE;
}
// Save last EOF ISO IP data
if ($keycount == $lastkey) {
// Don't collect Countries with null data
if (strpos($line, 'Total Networks: 0') !== FALSE) {
continue;
}
${'coptions' . $type}[] = "{$country}-{$isocode} ({$total}){$isocode}";
if ($type == '4') {
$roptions4[] = "{$country}-{$isocode} ({$total}){$isocode}";
}
@file_put_contents("{$pfb['ccdir']}/{$isocode}_v{$type}.txt", $xml_data, LOCK_EX);
unset($total, $xml_data);
}
$keycount++;
}
unset ($ips, $convert);
// Sort IP Countries alphabetically and build XML