diff options
author | BBcan177 <bbcan177@gmail.com> | 2015-11-15 22:35:26 -0500 |
---|---|---|
committer | BBcan177 <bbcan177@gmail.com> | 2015-11-15 22:35:26 -0500 |
commit | b1ef3af0c8c141b75dc61ba9c68f80b961e9f03d (patch) | |
tree | 310fd5704ed2bc8994d5c7ffef47ea55e75f5d79 | |
parent | 89572c6d988823d5869feec700295c930d14fdbe (diff) | |
download | pfsense-packages-b1ef3af0c8c141b75dc61ba9c68f80b961e9f03d.tar.gz pfsense-packages-b1ef3af0c8c141b75dc61ba9c68f80b961e9f03d.tar.bz2 pfsense-packages-b1ef3af0c8c141b75dc61ba9c68f80b961e9f03d.zip |
pfBlockerNG v2.0
23 files changed, 8429 insertions, 5105 deletions
diff --git a/config/pfblockerng/geoipupdate.sh b/config/pfblockerng/geoipupdate.sh deleted file mode 100644 index 39c08f70..00000000 --- a/config/pfblockerng/geoipupdate.sh +++ /dev/null @@ -1,171 +0,0 @@ -#!/bin/sh -# -# pfBlockerNG MaxMind GeoLite GeoIP Updater Script - By BBcan177@gmail.com -# Copyright (C) 2015 BBcan177@gmail.com -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License Version 2 as -# published by the Free Software Foundation. You may not use, modify or -# distribute this program under any other version of the GNU General -# Public License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# The GeoLite databases by MaxMind Inc., are distributed under the Creative Commons -# Attribution-ShareAlike 3.0 Unported License. The attribution requirement -# may be met by including the following in all advertising and documentation -# mentioning features of or use of this database. - -pfs_version=$(cat /etc/version | cut -c 1-3) - -# Application Locations -pathfetch=/usr/bin/fetch -pathtar=/usr/bin/tar -pathgunzip=/usr/bin/gunzip - -# Folder Locations -pathdb=/var/db/pfblockerng -pathlog=/var/log/pfblockerng -if [ "${pfs_version}" = "2.2" ]; then - mtype=$(/usr/bin/uname -m) - pathshare=/usr/pbi/pfblockerng-$mtype/share/GeoIP -else - pathshare=/usr/local/share/GeoIP -fi - -# File Locations -errorlog=$pathlog/geoip.log -geoipdat=/GeoIP.dat -geoipdatv6=/GeoIPv6.dat - -pathgeoipcc=$pathdb/country_continent.csv -pathgeoipcsv4=$pathdb/GeoIPCountryCSV.zip -pathgeoipcsvfinal4=$pathdb/GeoIPCountryWhois.csv -pathgeoipcsv6=$pathdb/GeoIPv6.csv.gz -pathgeoipcsvfinal6=$pathdb/GeoIPv6.csv - -if [ ! -d $pathdb ]; then mkdir $pathdb; fi -if [ ! -d $pathlog ]; then mkdir $pathlog; fi - -now=$(date) -echo; echo "$now - Updating pfBlockerNG - Country Database Files" -echo "pfBlockerNG uses GeoLite data created by MaxMind, available from http://www.maxmind.com"; echo - -#Function to update MaxMind GeoIP Binary (For Reputation Process) -binaryupdate() { - -# Download Part 1 - GeoLite IPv4 Binary Database - -echo " ** Downloading MaxMind GeoLite IPv4 Binary Database (For Reputation/Alerts Processes) **"; echo -URL="http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz" -$pathfetch -v -o $pathshare$geoipdat.gz -T 20 $URL -if [ "$?" -eq "0" ]; then - $pathgunzip -f $pathshare$geoipdat.gz - echo; echo " ( MaxMind IPv4 GeoIP.dat has been updated )"; echo - echo "Current Date/Timestamp:" - /bin/ls -alh $pathshare$geoipdat - echo -else - echo; echo " => MaxMind IPv4 GeoIP.dat Update [ FAILED ]"; echo - echo "MaxMind IPV4 Binary Update FAIL [ $now ]" >> $errorlog -fi - -# Download Part 2 - GeoLite IPv6 Binary Database - -echo; echo " ** Downloading MaxMind GeoLite IPv6 Binary Database (For Reputation/Alerts Processes) **"; echo -URL="http://geolite.maxmind.com/download/geoip/database/GeoIPv6.dat.gz" -$pathfetch -v -o $pathshare$geoipdatv6.gz -T 20 $URL -if [ "$?" -eq "0" ]; then - $pathgunzip -f $pathshare$geoipdatv6.gz - echo; echo " ( MaxMind IPv6 GeoIPv6.dat has been updated )"; echo - echo "Current Date/Timestamp:" - /bin/ls -alh $pathshare$geoipdatv6 - echo -else - echo; echo " => MaxMind IPv6 GeoIPv6.dat Update [ FAILED ]"; echo - echo "MaxMind IPv6 Binary Update FAIL [ $now ]" >> $errorlog -fi -} - - -#Function to update MaxMind Country Code Files -csvupdate() { - -# Download Part 1 - CSV IPv4 Database - -echo; echo " ** Downloading MaxMind GeoLite IPv4 CSV Database **"; echo -URL="http://geolite.maxmind.com/download/geoip/database/GeoIPCountryCSV.zip" -$pathfetch -v -o $pathgeoipcsv4 -T 20 $URL -if [ "$?" -eq "0" ]; then - $pathtar -zxvf $pathgeoipcsv4 -C $pathdb - if [ "$?" -eq "0" ]; then - echo; echo " ( MaxMind GeoIPCountryWhois has been updated )"; echo - echo "Current Date/Timestamp:" - /bin/ls -alh $pathgeoipcsvfinal4 - echo - else - echo; echo " => MaxMind IPv4 GeoIPCountryWhois [ FAILED ]"; echo - echo "MaxMind CSV Database Update FAIL - Tar extract [ $now ]" >> $errorlog - fi -else - echo; echo " => MaxMind IPv4 CSV Download [ FAILED ]"; echo - echo "MaxMind CSV Database Update FAIL [ $now ]" >> $errorlog -fi - -# Download Part 2 - Country Definitions - -echo; echo " ** Downloading MaxMind GeoLite Database Country Definition File **"; echo -URL="http://dev.maxmind.com/static/csv/codes/country_continent.csv" -$pathfetch -v -o $pathgeoipcc -T 20 $URL -if [ "$?" -eq "0" ]; then - echo; echo " ( MaxMind ISO 3166 Country Codes has been updated. )"; echo - echo "Current Date/Timestamp:" - /bin/ls -alh $pathgeoipcc - echo -else - echo; echo " => MaxMind ISO 3166 Country Codes Update [ FAILED ]"; echo - echo "MaxMind ISO 3166 Country Code Update FAIL [ $now ]" >> $errorlog -fi - -# Download Part 3 - Country Definitions IPV6 - -echo " ** Downloading MaxMind GeoLite IPv6 CSV Database **"; echo -URL="http://geolite.maxmind.com/download/geoip/database/GeoIPv6.csv.gz" -$pathfetch -v -o $pathgeoipcsv6 -T 20 $URL -if [ "$?" -eq "0" ]; then - $pathgunzip -f $pathgeoipcsv6 - echo; echo " ( MaxMind GeoIPv6.csv has been updated )"; echo - echo "Current Date/Timestamp:" - /bin/ls -alh $pathgeoipcsvfinal6 - echo -else - echo; echo " => MaxMind GeoLite IPv6 Update [ FAILED ]"; echo - echo "MaxMind GeoLite IPv6 Update FAIL [ $now ]" >> $errorlog -fi -} - - -# CALL APPROPRIATE PROCESSES using Script Argument $1 -case $1 in - bu) - binaryupdate - ;; - cu) - csvupdate - ;; - all) - binaryupdate - csvupdate - ;; - *) - exit - ;; -esac -exit diff --git a/config/pfblockerng/index.php b/config/pfblockerng/index.php new file mode 100644 index 00000000..804932d2 --- /dev/null +++ b/config/pfblockerng/index.php @@ -0,0 +1,50 @@ +<?php +/* + index.php + + pfBlockerNG (DNSBL) + Copyright (c) 2015 BBcan177@gmail.com + All rights reserved. +*/ +header("Cache-Control: private, no-store, no-cache, must-revalidate, max-age=0"); +header("Cache-Control: post-check=0, pre-check=0", false); +header("Pragma: no-cache"); +header("Expires: Sat, 26 Jul 2014 05:00:00 GMT"); +header("Content-Type: image/gif"); +echo base64_decode('R0lGODlhAQABAJAAAP8AAAAAACH5BAUQAAAALAAAAAABAAEAAAICBAEAOw=='); + +// Record DNSBL HTTP Alert to logfile +$datereq = date('M d H:i:s', $_SERVER['REQUEST_TIME']); +$req_agent = str_replace(',', '', "{$_SERVER['HTTP_REFERER']} | {$_SERVER['REQUEST_URI']} | {$_SERVER['HTTP_USER_AGENT']}"); +$log = htmlspecialchars("DNSBL Reject,{$datereq},{$_SERVER['HTTP_HOST']},{$_SERVER['REMOTE_ADDR']},{$req_agent}\n"); +if (!empty($log)) { + @file_put_contents('/var/log/pfblockerng/dnsbl.log', "{$log}", FILE_APPEND | LOCK_EX); +} + +// Query DNSBL Alias for Domain List. +$query = str_replace('.', '\.', htmlspecialchars($_SERVER['HTTP_HOST'])); +exec("/usr/bin/grep -l ' \"{$query} 60 IN A' /var/db/pfblockerng/dnsblalias/*", $match); +$pfb_query = strstr($match[0], 'DNSBL', FALSE); + +if (!empty($pfb_query)) { + // Increment DNSBL Alias Counter + $dnsbl_info = '/var/db/pfblockerng/dnsbl_info'; + if (($handle = fopen("{$dnsbl_info}", 'r')) !== FALSE) { + flock($handle, LOCK_EX); + $pfb_output = fopen("{$dnsbl_info}.bk", 'w'); + flock($pfb_output, LOCK_EX); + + // Find line with corresponding DNSBL Aliasname + while (($line = fgetcsv($handle)) !== FALSE) { + if ($line[0] == $pfb_query) { + $line[3] += 1; + } + fputcsv($pfb_output, $line); + } + + fclose($pfb_output); + fclose($handle); + @rename("{$dnsbl_info}.bk", "{$dnsbl_info}"); + } +} +?>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng.inc b/config/pfblockerng/pfblockerng.inc index 646e54ca..f1242ca3 100644 --- a/config/pfblockerng/pfblockerng.inc +++ b/config/pfblockerng/pfblockerng.inc @@ -3,13 +3,11 @@ pfBlockerNG.inc pfBlockerNG - Copyright (C) 2015 BBcan177@gmail.com + Copyright (c) 2015 BBcan177@gmail.com All rights reserved. - part of the Postfix package for pfSense - Copyright (C) 2010 Erik Fonnesbeck Based upon pfBlocker by - Copyright (C) 2011-2012 Marcello Coutinho + Copyright (c) 2011-2012 Marcello Coutinho All rights reserved. Redistribution and use in source and binary forms, with or without @@ -37,209 +35,343 @@ */ -//error_reporting(E_ALL); +require_once('util.inc'); +require_once('functions.inc'); +require_once('pkg-utils.inc'); +require_once('pfsense-utils.inc'); +require_once('globals.inc'); +require_once('services.inc'); +require_once('service-utils.inc'); +require_once('/usr/local/pkg/pfblockerng/pfblockerng_extra.inc'); // 'include functions' not yet merged into pfSense + +global $g, $config, $pfb; + +$pfs_version = substr(trim(file_get_contents('/etc/version')), 0, 3); +if ($pfs_version == '2.2') { + $pfb['prefix'] = '/usr/pbi/pfblockerng-' . php_uname('m'); +} else { + $pfb['prefix'] = '/usr/local'; +} + +// Folders +$pfb['dbdir'] = "{$g['vardb_path']}/pfblockerng"; +$pfb['aliasdir'] = "{$g['vardb_path']}/aliastables"; +$pfb['logdir'] = "{$g['varlog_path']}/pfblockerng"; +$pfb['etdir'] = "{$pfb['dbdir']}/ET"; +$pfb['nativedir'] = "{$pfb['dbdir']}/native"; +$pfb['denydir'] = "{$pfb['dbdir']}/deny"; +$pfb['matchdir'] = "{$pfb['dbdir']}/match"; +$pfb['permitdir'] = "{$pfb['dbdir']}/permit"; +$pfb['origdir'] = "{$pfb['dbdir']}/original"; +$pfb['dnsdir'] = "{$pfb['dbdir']}/dnsbl"; +$pfb['dnsorigdir'] = "{$pfb['dbdir']}/dnsblorig"; +$pfb['dnsalias'] = "{$pfb['dbdir']}/dnsblalias"; +$pfb['geoipshare'] = "{$pfb['prefix']}/share/GeoIP"; +$pfb['ccdir'] = "{$pfb['prefix']}/share/GeoIP/cc"; + +// Application Paths +$pfb['grep'] = '/usr/bin/grep'; +$pfb['awk'] = '/usr/bin/awk'; +$pfb['cut'] = '/usr/bin/cut'; +$pfb['sed'] = '/usr/bin/sed'; +$pfb['cat'] = '/bin/cat'; +$pfb['ls'] = '/bin/ls'; +$pfb['pfctl'] = '/sbin/pfctl'; + +// Folder Array +$pfb['folder_array'] = array( "{$pfb['dbdir']}", "{$pfb['logdir']}", "{$pfb['ccdir']}", "{$pfb['origdir']}", "{$pfb['nativedir']}", + "{$pfb['denydir']}", "{$pfb['matchdir']}","{$pfb['permitdir']}", "{$pfb['aliasdir']}", + "{$pfb['dnsdir']}", "{$pfb['dnsorigdir']}", "{$pfb['dnsalias']}"); +// Files +$pfb['errlog'] = "{$pfb['logdir']}/error.log"; +$pfb['extraslog'] = "{$pfb['logdir']}/extras.log"; +$pfb['log'] = "{$pfb['logdir']}/pfblockerng.log"; +$pfb['dnslog'] = "{$pfb['logdir']}/dnsbl.log"; +$pfb['dnserrlog'] = "{$pfb['logdir']}/dnsbl_error.log"; +$pfb['master'] = "{$pfb['dbdir']}/masterfile"; +$pfb['supptxt'] = "{$pfb['dbdir']}/pfbsuppression.txt"; +$pfb['dnsbl_info'] = "{$pfb['dbdir']}/dnsbl_info"; +$pfb['dnsbl_conf'] = '/var/unbound/pfb_dnsbl_lighty.conf'; +$pfb['dnsbl_cert'] = '/var/unbound/dnsbl_cert.pem'; +$pfb['script'] = '/usr/local/pkg/pfblockerng/pfblockerng.sh'; +$pfb['aliasarchive'] = "{$pfb['prefix']}/etc/aliastables.tar.bz2"; + +// Unbound files and folders +$pfb['dnsbl_file'] = '/var/unbound/pfb_dnsbl'; // Filename Extension not referenced +$pfb['dnsbldir'] = '/var/unbound'; + +// Array definitions +$pfb['continents'] = array ( 'Africa' => 'pfB_Africa', + 'Antartica' => 'pfB_Antartica', + 'Asia' => 'pfB_Asia', + 'Europe' => 'pfB_Europe', + 'North America' => 'pfB_NAmerica', + 'Oceania' => 'pfB_Oceania', + 'South America' => 'pfB_SAmerica', + 'Top Spammers' => 'pfB_Top', + 'Proxy and Satellite' => 'pfB_PS' + ); -require_once("util.inc"); -require_once("functions.inc"); -require_once("pkg-utils.inc"); -require_once("pfsense-utils.inc"); -require_once("globals.inc"); -require_once("services.inc"); +// Base rule array +$pfb['base_rule_reg'] = array('ipprotocol' => 'inet'); -// [ $pfb ] pfBlockerNG Global Array for Paths and Variables. This needs to be called to get the Updated Settings. +// Floating rules, base rule array +$pfb['base_rule_float'] = array('quick' => 'yes', 'floating' => 'yes', 'ipprotocol' => 'inet'); + +// Define Arrays for managing the mastefile +foreach (array('existing', 'actual') as $pftype) { + $pfb[$pftype]['match'] = array('type' => 'match', 'folder' => "{$pfb['matchdir']}"); + $pfb[$pftype]['permit'] = array('type' => 'permit', 'folder' => "{$pfb['permitdir']}"); + $pfb[$pftype]['deny'] = array('type' => 'deny', 'folder' => "{$pfb['denydir']}"); + $pfb[$pftype]['native'] = array('type' => 'native', 'folder' => "{$pfb['nativedir']}"); + $pfb[$pftype]['dnsbl'] = array('type' => 'dnsbl', 'folder' => "{$pfb['dnsdir']}"); +} + +// Default cURL options +$pfb['curl_defaults'] = array( CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 Chrome/43.0.2357.65 Safari/537.36', + CURLOPT_SSL_CIPHER_LIST => 'TLSv1.2, TLSv1', + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_SSL_VERIFYPEER => true, + CURLOPT_SSL_VERIFYHOST => true, + CURLOPT_FRESH_CONNECT => true, + CURLOPT_FILETIME => true, + CURLOPT_CONNECTTIMEOUT => 15, + ); + +$pfb['rfc7231'] = array(100 => '100 Continue', 101 => '101 Switching Protocols', 102 => '102 Processing', + + 200 => '200 OK', 201 => '201 Created', 202 => '202 Accepted', + 203 => '203 Non-Authoritative Info', 204 => '204 No Content', 205 => '205 Reset Content', + 206 => '206 Partial Content', 207 => '207 Multi-Status', 208 => '208 Already Reported', + 226 => '226 IM Used', + + 300 => '300 Multiple Choices', 301 => '301 Moved Permanently', 302 => '302 Found', + 303 => '303 See Other', 304 => '304 Not Modified', 305 => '305 Use Proxy', + 306 => '306 Switch Proxy', 307 => '307 Temporary Redirect', 308 => '308 Permanent Redirect', + + 400 => '400 Bad Request', 401 => '401 Unauthorized', 402 => '402 Payment Required', + 403 => '403 Forbidden', 404 => '404 Not Found', 405 => '405 Method Not Allowed', + 406 => '406 Not Acceptable', 407 => '407 Proxy Authentication Required', 408 => '408 Request Timeout', + 409 => '409 Conflict', 410 => '410 Gone', 411 => '411 Length Required', + 412 => '412 Precondition Failed', 413 => '413 Request Entity Too Large', 414 => '414 Request-URI Too Long', + 415 => '415 Unsupported Media Type', 416 => '416 Requested Range Not Satisfiable', 417 => '417 Expectation Failed', + 418 => '418 Im a teapot', 419 => '419 Authentication Timeout', 420 => '420 Method Failure', + 421 => '421 Misdirected Request', 422 => '422 Unprocessable Entity', 423 => '423 Locked', + 424 => '424 Failed Dependency', 426 => '426 Upgrade Required', 428 => '428 Precondition Required', + 429 => '429 Too Many Requests', 431 => '431 Request Header Fields Large', 440 => '440 Login Timeout', + 444 => '444 No Response', 449 => '449 Retry With', 450 => '450 Blocked Windows Parental Controls', + 451 => '451 Unavailable Legal Reasons', 494 => '494 Request Header too Large', 495 => '495 Cert Error', + 496 => '496 No Cert', 497 => '497 HTTP to HTTPS', 498 => '498 Token expired/invalid', + 499 => '499 Client Closed Request', + + 500 => '500 Internal Server Error', 501 => '501 Not Implemented', 502 => '502 Bad Gateway', + 503 => '503 Service Unavailable', 504 => '504 Gateway Timeout', 505 => '505 HTTP Version Not Supported', + 506 => '506 Variant Also Negotiates', 507 => '507 Insufficient Storage', 508 => '508 Loop Detected', + 509 => '509 Bandwidth Limit Exceeded', 510 => '510 Not Extended', 511 => '511 Network Authentication Required', + 598 => '598 Network read timeout error',599 => '599 Network connect timeout error' + ); + + +// [ $pfb ] pfBlockerNG global array. This needs to be called to get the updated settings. function pfb_global() { - global $g,$config,$pfb; + global $g, $config, $pfb; - $pfs_version = substr(trim(file_get_contents("/etc/version")),0,3); + // Create folders if not exist. + foreach ($pfb['folder_array'] as $folder) { + safe_mkdir("{$folder}", 0755); + } - if ($pfs_version == "2.2") { - $prefix = "/usr/pbi/pfblockerng-" . php_uname("m"); - } else { - $prefix = "/usr/local"; - } - - // Folders - $pfb['dbdir'] = "{$g['vardb_path']}/pfblockerng"; - $pfb['aliasdir'] = "{$g['vardb_path']}/aliastables"; - $pfb['logdir'] = "{$g['varlog_path']}/pfblockerng"; - $pfb['etdir'] = "{$pfb['dbdir']}/ET"; - $pfb['nativedir'] = "{$pfb['dbdir']}/native"; - $pfb['denydir'] = "{$pfb['dbdir']}/deny"; - $pfb['matchdir'] = "{$pfb['dbdir']}/match"; - $pfb['permitdir'] = "{$pfb['dbdir']}/permit"; - $pfb['origdir'] = "{$pfb['dbdir']}/original"; - $pfb['ccdir'] = "{$prefix}/share/GeoIP"; - - // Create Folders if not Exist. - $folder_array = array ("{$pfb['dbdir']}","{$pfb['logdir']}","{$pfb['ccdir']}","{$pfb['origdir']}","{$pfb['nativedir']}","{$pfb['denydir']}","{$pfb['matchdir']}","{$pfb['permitdir']}","{$pfb['aliasdir']}"); - foreach ($folder_array as $folder) { - safe_mkdir ("{$folder}",0755); - } - - // Files - $pfb['master'] = "{$pfb['dbdir']}/masterfile"; - $pfb['errlog'] = "{$pfb['logdir']}/error.log"; - $pfb['geolog'] = "{$pfb['logdir']}/geoip.log"; - $pfb['log'] = "{$pfb['logdir']}/pfblockerng.log"; - $pfb['supptxt'] = "{$pfb['dbdir']}/pfbsuppression.txt"; - $pfb['script'] = 'sh /usr/local/pkg/pfblockerng/pfblockerng.sh'; - $pfb['aliasarchive'] = "{$prefix}/etc/aliastables.tar.bz2"; - - // General Variables + // General variables $pfb['config'] = $config['installedpackages']['pfblockerng']['config'][0]; + $pfb['dnsblconfig'] = $config['installedpackages']['pfblockerngdnsblsettings']['config'][0]; + + $pfb['enable'] = $pfb['config']['enable_cb']; // Enable/Disable of pfBlockerNG + $pfb['keep'] = $pfb['config']['pfb_keep']; // Keep blocklists on pfBlockerNG Disable + $pfb['supp'] = $pfb['config']['suppression']; // Enable Suppression + $pfb['logmax'] = $pfb['config']['log_maxlines']; // Max lines in pfblockerng.log file + $pfb['cc'] = $pfb['config']['database_cc']; // Disable Country database CRON updates + $pfb['min'] = $pfb['config']['pfb_min']; // User defined CRON start minute + $pfb['hour'] = $pfb['config']['pfb_hour']; // Start hour of the scheduler + $pfb['interval'] = $pfb['config']['pfb_interval']; // Hour cycle for scheduler + $pfb['24hour'] = $pfb['config']['pfb_dailystart']; // Start hour of the 'Once a day' schedule + $pfb['iplocal'] = $config['interfaces']['lan']['ipaddr']; // Lan IP address + $pfb['dnsbl'] = $pfb['dnsblconfig']['pfb_dnsbl']; // Enabled state of DNSBL + $pfb['dnsbl_port'] = $pfb['dnsblconfig']['pfb_dnsport'] ?: ''; // Lighttpd web server http port setting + $pfb['dnsbl_port_ssl'] = $pfb['dnsblconfig']['pfb_dnsport_ssl']?: ''; // Lighttpd web server https port setting + + // Restore previous download on failure (default to 'on') + $pfb['restore'] = $pfb['config']['restore_feed'] != '' ? $pfb['config']['restore_feed'] : 'on'; + // Max daily download failure threshold (default to '0') + $pfb['skipfeed'] = $pfb['config']['skipfeed'] != '' ? $pfb['config']['skipfeed'] : 0; + + if (isset($config['unbound']['enable'])) { + $pfb['unbound_state'] = 'on'; + } else { + $pfb['unbound_state'] = ''; + } - // Enable/Disable of pfBlockerNG - $pfb['enable'] = $pfb['config']['enable_cb']; - // Keep Blocklists on pfBlockerNG Disable - $pfb['keep'] = $pfb['config']['pfb_keep']; - // Enable Suppression - $pfb['supp'] = $pfb['config']['suppression']; - // Max Lines in pfblockerng.log file - $pfb['logmax'] = $pfb['config']['log_maxlines']; - // Lan IP Address - $pfb['iplocal'] = $config['interfaces']['lan']['ipaddr']; - // Disable Country Database CRON Updates - $pfb['cc'] = $pfb['config']['database_cc']; - - // User Defined CRON Start Minute - $pfb['min'] = $pfb['config']['pfb_min']; - // Start hour of the Scheduler - $pfb['hour'] = $pfb['config']['pfb_hour']; - // Hour cycle for Scheduler - $pfb['interval'] = $pfb['config']['pfb_interval']; - // Start hour of the 'Once a day' Schedule - $pfb['24hour'] = $pfb['config']['pfb_dailystart']; - - // Set pfBlockerNG to Disabled on 'Re-Install' + // cURL - system proxy server setttings, if configured + if (!empty($config['system'][proxyurl])) { + $pfb['curl_defaults'][CURLOPT_PROXY] = $config['system']['proxyurl']; + if (!empty($config['system'][proxyport])) { + $pfb['curl_defaults'][CURLOPT_PROXYPORT] = $config['system']['proxyport']; + } + if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) { + $pfb['curl_defaults'][CURLOPT_PROXYAUTH] = 'CURLAUTH_ANY | CURLAUTH_ANYSAFE'; + $pfb['curl_defaults'][CURLOPT_PROXYUSERPWD] = "{$config['system']['proxyuser']}:{$config['system']['proxypass']}"; + } + } + + // Set pfBlockerNG to disabled on 're-install' if (isset($pfb['install']) && $pfb['install']) { - $pfb['enable'] = ""; - $pfb['install'] = FALSE; + $pfb['enable'] = $pfb['dnsbl'] = ''; + $pfb['install'] = FALSE; } } pfb_global(); -// Set Max PHP Memory Setting +// DNSBL Lighttpd HTTPS Daemon (Scans Lighttpd dnsbl_error.log for requested https domain names) +if ($argv[1] == 'dnsbl') { + pfb_livetail($pfb['dnserrlog'], 'dnsbl'); + exit; +} + +// Set max PHP memory setting $uname = posix_uname(); if ($uname['machine'] == 'amd64') { ini_set('memory_limit', '256M'); } -// Function to decode to Alias Custom entry box. +// Function to decode alias custom entry box. function pfbng_text_area_decode($text) { $customlist = explode("\r\n", base64_decode($text)); - foreach ($customlist as $line) { - if (substr(trim($line), 0, 1) != '#' && !empty($line)) { - if (strpos($line, '#')) { - $custom .= trim(strstr($line, '#', TRUE)) . "\n"; - } else { - $custom .= $line . "\n"; + if (!empty($customlist)) { + foreach ($customlist as $line) { + if (substr(trim($line), 0, 1) != '#' && !empty($line)) { + if (strpos($line, '#') !== FALSE) { + $custom .= trim(strstr($line, '#', TRUE)) . "\n"; + } else { + $custom .= $line . "\n"; + } } } + return $custom; } - return $custom; } -// Manage Log File Line Limit +// Manage log files line limit function pfb_log_mgmt() { global $pfb; pfb_global(); - if ($pfb['logmax'] == "nolimit") { - // Skip Log Mgmt + if ($pfb['logmax'] == 'nolimit') { + // Skip Log mgmt } else { - if (file_exists($pfb['log'])) { - exec("/usr/bin/tail -n {$pfb['logmax']} {$pfb['log']} > /tmp/pfblog; /bin/mv -f /tmp/pfblog {$pfb['log']}"); + foreach (array('log', 'errlog', 'dnslog', 'extraslog') as $logtype) { + if (file_exists($pfb[$logtype])) { + exec("/usr/bin/tail -n {$pfb['logmax']} {$pfb[$logtype]} > /tmp/pfblog; /bin/mv -f /tmp/pfblog $pfb[$logtype]"); + } } } } -// Record Log Messsages to pfBlockerNG Log File and/or Error Log File. -function pfb_logger($log, $type) { - global $g,$pfb,$pfbarr; +// Record log messsages to pfBlockerNG log file and/or error log file. +function pfb_logger($log, $logtype) { + global $g, $pfb; - $now = date("m/d/y G:i:s", time()); + $now = date('m/d/y G:i:s', time()); // Only log timestamp if new - if (preg_match("/NOW/", $log)) { + if (strpos($log, 'NOW') !== FALSE) { if ($now == $pfb['pnow']) { - $log = str_replace("[ NOW ]", "", "{$log}"); + $log = str_replace('[ NOW ]', '', "{$log}"); } else { - $log = str_replace("NOW", $now, "{$log}"); + $log = str_replace('NOW', $now, "{$log}"); } $pfb['pnow'] = "{$now}"; } - if ($type == 2) { + if ($logtype == 2) { @file_put_contents("{$pfb['log']}", "{$log}", FILE_APPEND); @file_put_contents("{$pfb['errlog']}", "{$log}", FILE_APPEND); - } elseif ($type == 3) { - @file_put_contents("{$pfb['geolog']}", "{$log}", FILE_APPEND); + } elseif ($logtype == 3) { + @file_put_contents("{$pfb['extraslog']}", "{$log}", FILE_APPEND); } else { @file_put_contents("{$pfb['log']}", "{$log}", FILE_APPEND); } } -// Determine 'List' Details -function pfb_determine_list_detail($list="", $header_url="", $confconfig="", $key="") { - global $pfb,$pfbarr,$config; +// Determine 'list' details +function pfb_determine_list_detail($list='', $header='', $confconfig='', $key='') { + global $config, $pfb, $pfbarr; $pfbarr = array(); - if (in_array($list,array('Match_Both','Match_Inbound','Match_Outbound','Alias_Match'))) { - $pfbarr['skip'] = FALSE; - $pfbarr['folder'] = "{$pfb['matchdir']}"; - } elseif (in_array($list,array('Permit_Both','Permit_Inbound','Permit_Outbound','Alias_Permit'))) { - $pfbarr['skip'] = FALSE; - $pfbarr['folder'] = "{$pfb['permitdir']}"; - } elseif ($list == "Alias_Native") { - $pfbarr['skip'] = FALSE; - $pfbarr['folder'] = "{$pfb['nativedir']}"; - } else { - // Deny - $pfbarr['skip'] = TRUE; - $pfbarr['folder'] = "{$pfb['denydir']}"; + switch($list) { + case 'Deny_Both': + case 'Deny_Inbound': + case 'Deny_Outbound': + case 'Alias_Deny': + $pfbarr = array('adv' => TRUE, 'folder' => "{$pfb['denydir']}", 'orig' => "{$pfb['origdir']}", 'reuse' => "{$pfb['reuse']}"); + break; + case 'unbound': + $pfbarr = array('adv' => FALSE, 'folder' => "{$pfb['dnsdir']}", 'orig' => "{$pfb['dnsorigdir']}", 'reuse' => "{$pfb['reuse_dnsbl']}"); + break; + case 'Permit_Both': + case 'Permit_Inbound': + case 'Permit_Outbound': + case 'Alias_Permit': + $pfbarr = array('adv' => FALSE, 'folder' => "{$pfb['permitdir']}", 'orig' => "{$pfb['origdir']}", 'reuse' => "{$pfb['reuse']}"); + break; + case 'Match_Both': + case 'Match_Inbound': + case 'Match_Outbound': + case 'Alias_Match': + $pfbarr = array('adv' => FALSE, 'folder' => "{$pfb['matchdir']}", 'orig' => "{$pfb['origdir']}", 'reuse' => "{$pfb['reuse']}"); + break; + case 'Alias_Native': + $pfbarr = array('adv' => FALSE, 'folder' => "{$pfb['nativedir']}", 'orig' => "{$pfb['origdir']}", 'reuse' => "{$pfb['reuse']}"); + break; } - // Collect proper Alias Table Description (Alias Only vs AutoRules) - if (preg_match("/Alias/", $list)) { - $pfbarr['descr'] = ""; + // Collect proper alias table description (alias only vs autorules) + if (strpos($list, 'Alias') !== FALSE) { + $pfbarr['descr'] = ''; } else { - $pfbarr['descr'] = " Auto "; + $pfbarr['descr'] = ' Auto '; } - // Determine length of Header to format log Output - if (strlen($header_url) > 19) { - $pfbarr['logtab'] = ""; - } - elseif (strlen($header_url) > 11) { + // Determine length of header to format log output + $tabtype = strlen($header); + if ($tabtype > 19) { + $pfbarr['logtab'] = ''; + } elseif ($tabtype > 11) { $pfbarr['logtab'] = "\t"; - } - elseif (strlen($header_url) < 4) { + } elseif ($tabtype < 4) { $pfbarr['logtab'] = "\t\t\t"; - } - else { + } else { $pfbarr['logtab'] = "\t\t"; } - if ($confconfig != "") { - // Configure Autoports/Protocol and Auto Destination if required. + if (!empty($confconfig)) { + // Configure autoports/protocol and auto destination if required. $autotype = array( 'autoports' => 'aliasports', 'autodest' => 'aliasdest'); - $aports = ""; $adest = ""; + $aports = ''; $adest = ''; $pfbarr['aproto'] = $config['installedpackages'][$confconfig]['config'][$key]['autoproto']; foreach ($autotype as $akey => $atype) { - if ($config['installedpackages'][$confconfig]['config'][$key][$akey] == "on" && is_array($config['aliases']['alias'])) { + if ($config['installedpackages'][$confconfig]['config'][$key][$akey] == 'on' && isset($config['aliases']['alias'])) { foreach ($config['aliases']['alias'] as $palias) { if ($palias['name'] == $config['installedpackages'][$confconfig]['config'][$key][$atype]) { if (!empty($palias['address'])) { switch($akey) { - case "autoports": + case 'autoports': $pfbarr['aports'] = $config['installedpackages'][$confconfig]['config'][$key][$atype]; break; - case "autodest": + case 'autodest': $pfbarr['adest'] = $config['installedpackages'][$confconfig]['config'][$key][$atype]; break; } @@ -253,11 +385,11 @@ function pfb_determine_list_detail($list="", $header_url="", $confconfig="", $ke } -// Determine if Cron Task requires updating +// Determine if cron task requires updating function pfblockerng_cron_exists($crontask, $pfb_min, $pfb_hour) { global $config; - if (is_array($config['cron']['item'])) { + if (isset($config['cron']['item'])) { foreach ($config['cron']['item'] as $item) { if (strpos($item['command'], $crontask) !== FALSE) { if ($item['minute'] != $pfb_min) { @@ -282,278 +414,1174 @@ function pfblockerng_cron_exists($crontask, $pfb_min, $pfb_hour) { function pfb_cron_base_hour() { global $pfb; - if ($pfb['interval'] == 1) { - return; + switch($pfb['interval']) { + case 1: + return; + break; + case 2: + $j = 11; $k = 2; + break; + case 3: + $j = 7; $k = 3; + break; + case 4: + $j = 5; $k = 4; + break; + case 6: + $j = 3; $k = 6; + break; + case 8: + $j = 2; $k = 8; + break; + case 12: + $j = 1; $k = 12; + break; + case 24: + return array($pfb['24hour']); + break; + default: + $pfb['interval'] = 1; + return; } - if ($pfb['interval'] == 2) { - // 2 Hour Schedule Converter - $shour = intval(substr($pfb['hour'], 0, 2)); - $sch2 = strval($shour); - for ($i=0; $i<11; $i++) { - $shour += 2; - if ($shour >= 24) - $shour -= 24; - $sch2 .= "," . strval($shour); - } - $sch2 = explode(",", $sch2); - sort($sch2); - return $sch2; - } - - if ($pfb['interval'] == 3) { - // 3 Hour Schedule Converter - $shour = intval(substr($pfb['hour'], 0, 2)); - $sch3 = strval($shour); - for ($i=0; $i<7; $i++) { - $shour += 3; - if ($shour >= 24) - $shour -= 24; - $sch3 .= "," . strval($shour); - } - $sch3 = explode(",", $sch3); - sort($sch3); - return $sch3; - } - - if ($pfb['interval'] == 4) { - // 4 Hour Schedule Converter - $shour = intval(substr($pfb['hour'], 0, 2)); - $sch4 = strval($shour); - for ($i=0; $i<5; $i++) { - $shour += 4; - if ($shour >= 24) - $shour -= 24; - $sch4 .= "," . strval($shour); - } - $sch4 = explode(",", $sch4); - sort($sch4); - return $sch4; - } - - if ($pfb['interval'] == 6) { - // 6 Hour Schedule Converter - $shour = intval(substr($pfb['hour'], 0, 2)); - $sch6 = strval($shour); - for ($i=0; $i<3; $i++) { - $shour += 6; - if ($shour >= 24) - $shour -= 24; - $sch6 .= "," . strval($shour); - } - $sch6 = explode(",", $sch6); - sort($sch6); - return $sch6; - } - - if ($pfb['interval'] == 8) { - // 8 Hour Schedule Converter - $shour = intval(substr($pfb['hour'], 0, 2)); - $sch8 = strval($shour); - for ($i=0; $i<2; $i++) { - $shour += 8; - if ($shour >= 24) - $shour -= 24; - $sch8 .= "," . strval($shour); - } - $sch8 = explode(",", $sch8); - sort($sch8); - return $sch8; - } - - if ($pfb['interval'] == 12) { - // 12 Hour Schedule Converter - $shour = intval(substr($pfb['hour'], 0, 2)); - $sch12 = strval($shour) . ","; - $shour += 12; - if ($shour >= 24) + $shour = intval(substr($pfb['hour'], 0, 2)); + $sch = strval($shour); + + for ($i=0; $i < $j; $i++) { + $shour += $k; + if ($shour >= 24) { $shour -= 24; - $sch12 .= strval($shour); - $sch12 = explode(",", $sch12); - sort($sch12); - return $sch12; + } + $sch .= ',' . strval($shour); } - if ($pfb['interval'] == 24) { - return array($pfb['24hour']); - } - - // Default to hourly schedule - $pfb['interval'] = 1; - return; + $sch = explode(',', $sch); + sort($sch); + return $sch; } -// Create Suppression Alias +// Create suppression alias function pfb_create_suppression_alias() { global $config; - // Collect existing pfsense alias(s) - if (is_array($config['aliases']['alias'])) { - foreach($config['aliases']['alias'] as $exalias) { - $new_aliases[] = $exalias; - } + // Reload config.xml to get any recent changes + $config = parse_config(true); + + // Collect existing pfSense alias(es) + if (isset($config['aliases']['alias'])) { + $new_aliases = &$config['aliases']['alias']; } - // Create New pfBlockerNGSuppress Alias - $new_aliases[] = array( "name" => "pfBlockerNGSuppress", - "address" => "", - "descr" => "pfBlockerNG Suppression List (24|32 CIDR only)", - "type" => "network", - "detail" => "" + + // Create new pfBlockerNGSuppress alias + $new_aliases[] = array( 'name' => 'pfBlockerNGSuppress', + 'address' => '', + 'descr' => 'pfBlockerNG Suppression List (24|32 CIDR only)', + 'type' => 'network', + 'detail' => '' ); - $config['aliases']['alias'] = $new_aliases; - $pfb['cron_mod'] = TRUE; + write_config('pfBlockerNG: saving suppression alias'); } -// Create Suppression file from Alias +// Create suppression file from alias function pfb_create_suppression_file() { - global $config,$pfb; - - // Find pfBlockerNGSuppress Array ID Number - $pfb['found'] = FALSE; - if (is_array($config['aliases']['alias'])) { - $pfb_id = 0; - foreach ($config['aliases']['alias'] as $alias) { - if ($alias['name'] == "pfBlockerNGSuppress") { - $pfb['found'] = TRUE; + global $config, $pfb; + + // Find pfBlockerNGSuppress array ID number + $pfbfound = FALSE; + if (isset($config['aliases']['alias'])) { + foreach ($config['aliases']['alias'] as $key => $alias) { + if ($alias['name'] == 'pfBlockerNGSuppress') { + $pfbfound = TRUE; break; } - $pfb_id++; } - if ($pfb['found']) { - $pfb_suppress = str_replace(" ", "\n", $config['aliases']['alias'][$pfb_id]['address']); + if ($pfbfound) { + $pfb_suppress = str_replace(' ', "\n", $config['aliases']['alias'][$key]['address']); if (!empty($pfb_suppress)) { @file_put_contents("{$pfb['supptxt']}", $pfb_suppress, LOCK_EX); } else { unlink_if_exists("{$pfb['supptxt']}"); } } else { - // Delete Suppression File if Alias is Empty. + // Delete suppression file if alias is empty. unlink_if_exists("{$pfb['supptxt']}"); } } - // Call Function to Create Suppression Alias. - if (!$pfb['found']) { + // Call function to create suppression alias. + if (!$pfbfound) { pfb_create_suppression_alias(); } } -// IPv6 Range to CIDR function used courtesey from: -// https://github.com/stilez/pfsense-leases/blob/50cc0fa81dba5fe91bcddaea016c245d1b8479cc/etc/inc/util.inc -function ip_range_to_subnet_array_temp2($ip1, $ip2) { - - if (is_ipaddrv4($ip1) && is_ipaddrv4($ip2)) { - $proto = 'ipv4'; // for clarity - $bits = 32; - $ip1bin = decbin(ip2long32($ip1)); - $ip2bin = decbin(ip2long32($ip2)); - } elseif (is_ipaddrv6($ip1) && is_ipaddrv6($ip2)) { - $proto = 'ipv6'; - $bits = 128; - $ip1bin = Net_IPv6::_ip2Bin($ip1); - $ip2bin = Net_IPv6::_ip2Bin($ip2); - } else - return array(); - - // it's *crucial* that binary strings are guaranteed the expected length; do this for certainty even though for IPv6 it's redundant - $ip1bin = str_pad($ip1bin, $bits, '0', STR_PAD_LEFT); - $ip2bin = str_pad($ip2bin, $bits, '0', STR_PAD_LEFT); - - if ($ip1bin === $ip2bin) - return array($ip1 . '/' . $bits); +// Create DNSBL VIP and NAT rules, lighttpd conf and services +function pfb_create_dnsbl($mode) { + global $config, $pfb; + + // Reload config.xml to get any recent changes + $config = parse_config(true); + + $new_nat = $new_vip = $pfb_ex_nat = $pfb_ex_vip = $dnsbl_ex_nat = $dnsbl_ex_vip = array(); + $pfb['dnsbl_vip_changed'] = $pfbupdate = FALSE; + + if ((!empty($pfb['dnsbl_port']) && !empty($pfb['dnsbl_port_ssl']) && !empty($pfb['dnsbl_vip']) && $mode == 'enable') || $mode == 'disable') { + + // DNSBL NAT rules generation + $pfbfound = FALSE; + // Collect existing pfSense NAT rules + if (isset($config['nat']['rule'])) { + foreach ($config['nat']['rule'] as $ex_nat) { + if (strpos($ex_nat['descr'], 'pfB DNSBL') !== FALSE) { + // Collect DNSBL NAT rules + $dnsbl_ex_nat[] = $ex_nat; + $pfbfound = TRUE; + } else { + // Collect all 'other' NAT rules + $pfb_ex_nat[] = $ex_nat; + } + } + } + + if ($mode == 'enable') { + // Generate new DNSBL NAT per DNSBL listening ports + $selected_ports = array("{$pfb['dnsbl_port']}" => '80', "{$pfb['dnsbl_port_ssl']}" => '443'); + foreach ($selected_ports as $port => $lport) { + $dnsbl_new_nat[] = array ( 'source' => array('any' => ''), + 'destination' => array('address' => "{$pfb['dnsbl_vip']}", 'port' => "{$lport}"), + 'protocol' => 'tcp', + 'target' => '127.0.0.1', + 'local-port' => "{$port}", + 'interface' => "{$pfb['dnsbl_iface']}", + 'descr' => 'pfB DNSBL - DO NOT EDIT', + 'associated-rule-id' => '', + 'natreflection' => 'purenat' + ); + } + + // Compare existing to new and if they are not identical update + if ($dnsbl_ex_nat !== $dnsbl_new_nat) { + $pfbupdate = TRUE; + $new_nat = array_merge($pfb_ex_nat, $dnsbl_new_nat); + } else { + $new_nat = array_merge($pfb_ex_nat, $dnsbl_ex_nat); + } + } else { + $new_nat = array_merge($pfb_ex_nat, $new_nat); + // Update when DNSBL NAT found but is now disabled. + if ($pfbfound) { + $pfbupdate = TRUE; + } + } + + // DNSBL VIP generation + $dnsbl_new_vip[] = array ( 'mode' => 'ipalias', + 'interface' => "{$pfb['dnsbl_iface']}", + 'descr' => 'pfB DNSBL - DO NOT EDIT', + 'type' => 'single', + 'subnet_bits' => '32', + 'subnet' => "{$pfb['dnsbl_vip']}" + ); + + $pfbfound = FALSE; + // Collect existing pfSense VIPs + if (isset($config['virtualip']['vip'])) { + foreach ($config['virtualip']['vip'] as $ex_vip) { + if (strpos($ex_vip['descr'], 'pfB DNSBL') !== FALSE) { + // Collect DNSBL VIP + $dnsbl_ex_vip[] = $ex_vip; + $pfbfound = TRUE; + } else { + // Collect all 'other' VIPs + $pfb_ex_vip[] = $ex_vip; + } + } + } + + if ($mode == 'enable') { + // Compare existing to new and if they are not identical update + if ($dnsbl_ex_vip !== $dnsbl_new_vip) { + $pfb['dnsbl_vip_changed'] = TRUE; + $pfbupdate = TRUE; + $new_vip = array_merge($pfb_ex_vip, $dnsbl_new_vip); + } else { + $new_vip = array_merge($pfb_ex_vip, $dnsbl_ex_vip); + } + } else { + $new_vip = array_merge($pfb_ex_vip, $new_vip); + // Update when DNSBL NAT found but is now disabled. + if ($pfbfound) { + $pfbupdate = TRUE; + } + } + + // Only create DNSBL lighttpd conf file if not exists, or listening port changed + if (!file_exists($pfb['dnsbl_conf']) && $mode == 'enable' || $pfbupdate && $mode == 'enable') { + +// Create Lighttpd conf file for DNSBL +$pfb_conf = <<<EOF +# +#pfBlockerNG Lighttpd DNSBL configuration file +# +server.bind = "0.0.0.0" +server.port = "{$pfb['dnsbl_port']}" +server.event-handler = "freebsd-kqueue" +server.network-backend = "freebsd-sendfile" +server.dir-listing = "disable" +server.document-root = "/usr/local/www/pfblockerng/www/" +server.errorlog = "/var/log/pfblockerng/dnsbl_error.log" +server.pid-file = "/var/run/dnsbl.pid" +server.modules = ( "mod_access", "mod_fastcgi", "mod_rewrite" ) + +server.indexfiles = ( "index.php" ) +mimetype.assign = ( ".html" => "text/html", ".gif" => "image/gif" ) +url.access-deny = ( "~", ".inc" ) +fastcgi.server = ( ".php" => ( "localhost" => ( "socket" => "/var/run/php-fpm.socket", "broken-scriptfilename" => "enable" ) ) ) + +debug.log-condition-handling = "enable" + +\$HTTP["host"] =~ ".*" { + url.rewrite-once = ( ".*" => "index.php" ) +} + +\$SERVER["socket"] == "0.0.0.0:{$pfb['dnsbl_port_ssl']}" { + ssl.engine = "enable" + ssl.pemfile = "{$pfb['dnsbl_cert']}" + ssl.use-sslv2 = "disable" + ssl.use-sslv3 = "disable" + ssl.honor-cipher-order = "enable" + ssl.cipher-list = "AES128+EECDH:AES256+EECDH:AES128+EDH:AES256+EDH:AES128-SHA:AES256-SHA:!aNULL:!eNULL:!DSS" + + \$HTTP["host"] =~ ".*" { + url.rewrite-once = ( ".*" => "index.php" ) + } +} + +EOF; + $log = "\nSaving new DNSBL web server configuration to port [ {$pfb['dnsbl_port']} & {$pfb['dnsbl_port_ssl']} ]\n"; + pfb_logger("{$log}", 1); + + $pfbupdate = TRUE; + @file_put_contents($pfb['dnsbl_conf'], $pfb_conf, LOCK_EX); + unset($pfb_conf); + } + + // Update config.xml, if changes required + if ($pfbupdate) { + $log = "Saving pfSense config...\n"; + pfb_logger("{$log}", 1); + $config['nat']['rule'] = $new_nat; + $config['virtualip']['vip'] = $new_vip; + write_config('pfBlockerNG: saving DNSBL changes'); + + // Execute ifconfig to enable VIP address + $iface = get_real_interface("{$pfb['dnsbl_iface']}"); + if (!empty($iface) && !empty($pfb['dnsbl_vip'])) { + mwexec('/sbin/ifconfig ' . escapeshellarg($iface) . ' inet '. escapeshellarg("{$pfb['dnsbl_vip']}") . '/32 alias'); + $log = "VIP address configured. Widget Packet statistics reset.\n"; + pfb_logger("{$log}", 1); + filter_configure(); + } else { + $log = "DNSBL ifconfig error : Interface:{$iface}, VIP:{$pfb['dnsbl_iface']}\n"; + pfb_logger("{$log}", 1); + } + } + } + + // Save settings, restart services as required + if ($mode == 'enable') { + // Remove any existing and create link for DNSBL lighttpd executable + unlink_if_exists('/usr/local/sbin/lighttpd_pfb'); + link('/usr/local/sbin/lighttpd', '/usr/local/sbin/lighttpd_pfb'); + + // Create DNSBL SSL certificate + if (!file_exists ("{$pfb['dnsbl_cert']}")) { + $log = "New DNSBL Cert Created.\n"; + pfb_logger("{$log}", 1); + exec("/usr/bin/openssl req -new -x509 -keyout {$pfb['dnsbl_cert']} -out {$pfb['dnsbl_cert']} -days 3650 -nodes"); + } + + if ($pfbupdate || !is_service_running ('dnsbl')) { + $log = "Restarting Service DNSBL...\n"; + pfb_logger("{$log}", 1); + restart_service('dnsbl'); + } + } else { + // Determine if VIP exists + if (isset($config['virtualip']['vip'])) { + foreach ($config['virtualip']['vip'] as $ex_vip) { + if (strpos($ex_vip['descr'], 'pfB DNSBL') !== FALSE) { + // Execute ifconfig to remove VIP address + $iface = get_real_interface("{$pfb['dnsbl_iface']}"); + if (!empty($iface) && !empty($pfb['dnsbl_vip'])) { + mwexec('/sbin/ifconfig ' . escapeshellarg($iface) . ' delete ' . escapeshellarg("{$pfb['dnsbl_vip']}")); + filter_configure(); + } + } + } + } + + if (is_service_running('dnsbl')) { + pfb_logger("Stop Service DNSBL\n", 1); + stop_service('dnsbl'); + } + } +} + + +// Define DNSBL Unbound include settings +function pfb_unbound_dnsbl($mode) { + global $config, $pfb; + + // Reload config.xml to get any recent changes + $config = parse_config(true); + + $pfbupdate = FALSE; + $unbound_include = "server:include: {$pfb['dnsbl_file']}.conf"; + + // Collect Unbound custom option pfSense conf line + $pfb['unboundconfig'] = &$config['unbound']['custom_options']; + if (!empty($pfb['unboundconfig'])) { + $unbound_custom = base64_decode($pfb['unboundconfig']); + } else { + $unbound_custom = ''; + } + + // Determine if DNSBL include line exists + if (!empty($unbound_custom)) { + // Append DNSBL Unbound pfSense conf integration + if (!strstr($unbound_custom, 'pfb_dnsbl.conf')) { + if ($mode == 'enabled') { + $pfbupdate = TRUE; + $unbound_custom .= "\n{$unbound_include}"; + $log = "\nDNSBL - Adding to existing Unbound custom options\n"; + } + } + else { + // Remove DNSBL Unbound pfSense conf integration when disabled + if ($mode == 'disabled') { + $custom = explode ("\n", $unbound_custom); + foreach ($custom as $key => $line) { + if (strpos($line, 'pfb_dnsbl.conf') !== FALSE) { + $pfbupdate = TRUE; + $log = "\nDNSBL - Removing DNSBL Unbound custom options\n"; + unset($custom[$key]); + } + } + $unbound_custom = implode("\n", $custom); + } + } + } + else { + // Add DNSBL Unbound pfSense conf integration + if ($mode == 'enabled') { + $pfbupdate = TRUE; + $unbound_custom = "{$unbound_include}"; + $log = "\nDNSBL - Adding Unbound custom 'include' option\n"; + } + } + + // Update config.xml, if changes required + if ($pfbupdate) { + pfb_logger("{$log}", 1); + $unbound_custom = base64_encode(str_replace("\r\n", "\n", $unbound_custom)); + $pfb['unboundconfig'] = "{$unbound_custom}"; + write_config('pfBlockerNG: saving Unbound config'); + } +} + + +// Validate Unbound conf +function pfb_validate_unbound($mode) { + global $g, $pfb; + + if ($mode == 'enabled') { + $ext = '.bk'; + } else { + $ext = '.*'; // Remove all DNSBL Unbound files + } + + pfb_logger(" completed\nValidating database...", 1); + exec("/usr/local/sbin/unbound-checkconf {$pfb['dnsbldir']}/unbound.tmp 2>&1", $result); + pfb_logger(" completed [ NOW ]\n", 1); + + if (preg_grep("/unbound-checkconf: no errors/", $result)) { + @rename("{$pfb['dnsbldir']}/unbound.tmp", "{$pfb['dnsbldir']}/unbound.conf"); + + // Reload Unbound Service + if (is_service_running('unbound')) { + pfb_logger('Restarting Unbound ...', 1); + + $cache_dumpfile = '/var/tmp/unbound_cache'; + unlink_if_exists("{$cache_dumpfile}"); + $chroot_cmd = "chroot -u unbound -g unbound / /usr/local/sbin/unbound-control -c {$g['unbound_chroot_path']}/unbound.conf"; + + exec("{$chroot_cmd} dump_cache > $cache_dumpfile"); + exec("{$chroot_cmd} reload"); + + if (file_exists($cache_dumpfile) && filesize($cache_dumpfile) > 0) { + exec("{$chroot_cmd} load_cache < $cache_dumpfile"); + } + } + else { + pfb_logger('Starting Unbound Service...', 1); + // Code from services_unbound.php 'apply' + $retval = services_unbound_configure(); + if ($retval == 0) { + clear_subsystem_dirty('unbound'); + } + system_resolvconf_generate(); // Update resolv.conf + system_dhcpleases_configure(); // Start or restart dhcpleases + } + + exec("/usr/local/sbin/unbound-control -c {$pfb['dnsbldir']}/unbound.conf status", $result); + if (preg_grep("/is running.../", $result)) { + pfb_logger(" completed\n", 1); + } else { + pfb_logger(" Not completed.\n", 1); + } + + $final_cnt = exec("{$pfb['grep']} -c ^ {$pfb['dnsbldir']}/pfb_dnsbl.conf"); + $log = "DNSBL update [ {$final_cnt} ]... completed [ NOW ]\n------------------------------------------"; + pfb_logger("{$log}", 1); + + // When pfBlockerNG is disabled and 'keep blocklists' is disabled. + if ($pfb['enable'] == '' && $pfb['keep'] == '' && !$pfb['install']) { + unlink_if_exists("{$pfb['dnsbl_file']}{$ext}"); + } + + // Persist/remove Unbound adv. custom options from pfSense conf file + pfb_unbound_dnsbl($mode); + } + else { + // Revert to previous DNSBL database + if ($mode == 'enabled') { + $log = "\nDNSBL {$mode} FAIL - restoring Unbound conf\n"; + pfb_logger("{$log}", 2); + $log = htmlspecialchars(implode("\n", $result)); + pfb_logger("{$log}", 1); + + if (file_exists("{$pfb['dnsbl_file']}.bk")) { + @rename("{$pfb['dnsbl_file']}.bk", "{$pfb['dnsbl_file']}.conf"); + } + } + else { + $log = "\nDNSBL {$mode} - Unbound conf update FAIL\n"; + pfb_logger("{$log}", 1); + } + } +} + + +// Process Alexa database +function pfblockerng_alexa() { + global $pfb; + + if (empty($pfb['dnsbl_alexa_inc'])) { + pfb_logger("\n Alexa: No TLD Inclusions found.\n", 1); + return; + } + + // Array of TLDs to include in Whitelist + $pfb_include = array_flip(explode(',', $pfb['dnsbl_alexa_inc'])); + + if (($handle = fopen("{$pfb['dbdir']}/top-1m.csv", 'r')) !== FALSE) { + $pfb_output = fopen("{$pfb['dbdir']}/pfbalexawhitelist.txt", 'w'); + + for ($x=1; $x <= $pfb['dnsbl_alexa_cnt']; ++$x) { + $aline = fgetcsv($handle); + + // Collect Domain TLD + $tld = array_pop(explode('.', $aline[1])); + + if (isset($pfb_include[$tld])) { + // Whitelist both 'www.example.com' and 'example.com' + if (substr($aline[1], 0, 4) == 'www.') { + $aline[1] = substr($aline[1], 4); + } + fwrite($pfb_output, "local-data: \"www." . $aline[1] . " 60 IN A {$pfb['dnsbl_vip']}\"\n"); + fwrite($pfb_output, "local-data: \"" . $aline[1] . " 60 IN A {$pfb['dnsbl_vip']}\"\n"); + } + else { + // Re-Increment $i count + $x = @max(0, --$x); + } + } + } + else { + $log = "\nAlexa conversion Failed. File: top-1m.csv, not found.\n"; + pfb_logger("{$log}", 2); + } + fclose($handle); + fclose($pfb_output); +} + + +// Function to remove any leading zeros in octets and to exclude private/reserved addresses. +function sanitize_ipaddr($ipaddr, $custom) { + global $pfb; + + list ($subnet, $mask) = explode('/', $ipaddr); + $iparr = explode('.', $subnet); + + foreach ($iparr as $key => $octet) { + // Remove any leading zeros in octets + if ($octet == 0) { + $ip[$key] = 0; + } else { + $ip[$key] = ltrim($octet, '0'); + } + + // Remove 'loopback', '0.0.0.0', and IPs ending with '255' + if ($ip[0] == 127 || $ip[0] == 0 || empty($ip[0]) || $ip[3] == 255) { + return; + } + + if ($key == 3) { + // If mask is not defined and 4th octet is '0', set mask to '24' + if ($octet == 0 && empty($mask)) { + $mask = 24; + } + + // If mask is '24', force 4th octet to '0' + if ($mask == 24 && $octet != 0) { + $ip[$key] = 0; + } + } + } + + $mask = str_replace('32', '', $mask); // Strip '/32' mask + $ip_final = implode('.', $ip); + + // Exclude private/reserved IPs when suppression is enabled (bypass exclusion for custom lists) + if ($pfb['supp'] == 'on' && !$custom) { + if (!filter_var($ip_final, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== FALSE) { + return; + } + } + + if (!empty($mask)) { + return "{$ip_final}/{$mask}"; + } + return "{$ip_final}"; +} + + +// Validate IPv4 IP addresses +function validate_ipv4($ipaddr) { + if (strpos($ipaddr, '/') !== FALSE) { + return is_subnetv4($ipaddr); + } + return is_ipaddrv4($ipaddr); +} + + +// Function to check for loopback addresses (IPv4 range: 127.0.0.0/8, excluding IPv6) +function FILTER_FLAG_NO_LOOPBACK_RANGE($value) { + // http://www.php.net/manual/en/filter.filters.flags.php + return filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? $value : (((ip2long($value) & 0xff000000) == 0x7f000000) ? FALSE : $value); +} + + +// Explode IP for evaluations +function ip_explode($ip) { + + $ix = explode('.', $ip); + foreach ($ix as $key => $octet) { + if ($key != 3) { + $ix1 .= "{$octet}."; + } + } + array_unshift($ix, $ip); + $ix[] = "{$ix1}0/24"; + $ix[] = "{$ix1}"; + + return $ix; +} + + +// Determine the header which Alerted an IP address and return the header name +function find_reported_header($ip, $pfbfolder, $exclude=FALSE) { + + if (substr_count($ip, ':') > 1) { + $query = strstr($ip, ':', true); // IPv6 Prefix + $type = 6; + } else { + $query = strstr($ip, '.', true); // IPv4 Octet #1 + $type = 4; + } + $arr = $cidrs = array(); + + // Exclude MaxMind files for Alerts tab query; however include for Download failure queries. + $exclusion = "--exclude='pfB_*'"; + if ($exclude) { + $exclusion = ''; + } + + exec("/usr/bin/grep '^{$query}\.' {$exclusion} {$pfbfolder}", $result); + if (!empty($result)) { + foreach ($result as $line) { + + $rx = explode('.txt:', $line); + $arr[$rx[1]][0] = substr(strrchr($rx[0], '/'), 1); // Capture IP and header + + if ($rx[1] == $ip) { + return array('', $arr[$rx[1]][0], TRUE); // Return header on exact IP Match + } + + // Collect all CIDRs for analysis if Alert is from a CIDR + if (strpos($rx[1], '/') !== FALSE) { + $cidrs[] = array($rx[1], $arr[$rx[1]][0]); + } + } + + // Determine which CIDR alerted the IP address + if (!empty($cidrs)) { + foreach ($cidrs as $line) { + + // Determine which CIDR alerted the IP address + $validate = FALSE; + if ($type == 4) { + list($addr, $mask) = explode('/', $line[0]); + $mask = (0xffffffff << (32 - $mask)) & 0xffffffff; + $validate = ((ip2long($ip) & $mask) == (ip2long($addr) & $mask)); + } + else { + $validate = (Net_IPv6::isInNetmask($ip, $line[0])); + } + + if ($validate) { + // Mark all CIDRs except /24 as 'FALSE' + $line[2] = FALSE; + if (strpos($line[0], '/24') !== FALSE) { + $line[2] = TRUE; + } + return $line; // Return header on CIDR match + } + } + } + } + + if ($exclude) { + return; // Return null to Download failure function + } + + // Query for any active pfBlockerNG CRON jobs + exec('/bin/ps -wax', $result_cron); + if (preg_grep("/pfblockerng[.]php\s+?(cron|update)/", $result_cron)) { + return array('updating..', 'CRON Task'); + } + return array('', 'no match', FALSE); +} + + +// Function to download feeds +function pfb_download($list_url, $file_dwn, $pflex=FALSE, $header, $format, $logtype, $vtype, $timeout=300) { + global $pfb; + $http_status = ''; + + // Download RSYNC format + if ($format == 'rsync') { + $result = exec("/usr/local/bin/rsync --timeout=5 {$list_url} {$file_dwn}.raw"); + if ($result == 0) { + $http_status = '200 OK'; + } else { + $log = "\n RSYNC Failed...\n"; + pfb_logger("{$log}", "{$logtype}"); + return FALSE; + } + } + elseif ($format == 'whois') { + // Convert a Domain name/AS into its respective IP addresses + exec("{$pfb['script']} whoisconvert {$header} {$vtype} {$list_url} {$elog}"); + return TRUE; + } + else { + // Determine if URL is a localfile + $host = @parse_url("{$list_url}"); + if (in_array($host['host'], array('127.0.0.1', $pfb['iplocal'], ''))) { + $lof = 'local'; + } else { + $lof = ''; + } + + // Download localfile format + if ($lof == 'local') { + if (!$file_data = @file_get_contents($list_url)) { + $error = error_get_last(); + $log = "\n[ {$header} ] {$error['message']}\n"; + pfb_logger("{$log}", "{$logtype}"); + return FALSE; + } else { + // Save original downloaded file + @file_put_contents("{$file_dwn}.raw", $file_data, LOCK_EX); + $http_status = '200 OK'; + } + } - if (strcmp($ip1bin, $ip2bin) > 0) - list ($ip1bin, $ip2bin) = array($ip2bin, $ip1bin); // swap contents of ip1 <= ip2 + // Download using cURL + else { + if (($fhandle = fopen("{$file_dwn}.raw", 'w')) !== FALSE) { + if (!($ch = curl_init($list_url))) { + $log = "\nFailed to create cURL resource... Exiting...\n"; + pfb_logger("{$log}", "{$logtype}"); + return FALSE; + } - $rangesubnets = array(); - $netsize = 0; + curl_setopt_array($ch, $pfb['curl_defaults']); // Load curl default settings + curl_setopt($ch, CURLOPT_FILE, $fhandle); // Add $fhandle setting to cURL + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); // Set cURL download timeout + curl_setopt($ch, CURLOPT_ENCODING, 'gzip'); // Request 'gzip' encoding from server if available + + // Attempt 3 Downloads before failing. + for ($retries = 1; $retries <= 3; $retries++) { + if (curl_exec($ch)) { + // Collect remote timestamp. + $remote_stamp = curl_getinfo($ch, CURLINFO_FILETIME); + break; // Break on success + } - do { - // at loop start, $ip1 is guaranteed strictly less than $ip2 (important for edge case trapping and preventing accidental binary wrapround) - // which means the assignments $ip1 += 1 and $ip2 -= 1 will always be "binary-wrapround-safe" + $curl_error = curl_errno($ch); + if ($logtype != 3) { + pfb_logger(" cURL Error: {$curl_error}\n", 1); + } else { + pfb_logger(" {$header}\t\tcURL Error: {$curl_error}\n\n", 3); + } - // step #1 if start ip (as shifted) ends in any '1's, then it must have a single cidr to itself (any cidr would include the '0' below it) - - if (substr($ip1bin, -1, 1) == '1') { - // the start ip must be in a separate one-IP cidr range - $new_subnet_ip = substr($ip1bin, $netsize, $bits - $netsize) . str_repeat('0', $netsize); - $rangesubnets[$new_subnet_ip] = $bits - $netsize; - $n = strrpos($ip1bin, '0'); //can't be all 1's - $ip1bin = ($n == 0 ? '' : substr($ip1bin, 0, $n)) . '1' . str_repeat('0', $bits - $n - 1); // BINARY VERSION OF $ip1 += 1 - } - - // step #2, if end ip (as shifted) ends in any zeros then that must have a cidr to itself (as cidr cant span the 1->0 gap) - - if (substr($ip2bin, -1, 1) == '0') { - // the end ip must be in a separate one-IP cidr range - $new_subnet_ip = substr($ip2bin, $netsize, $bits - $netsize) . str_repeat('0', $netsize); - $rangesubnets[$new_subnet_ip] = $bits - $netsize; - $n = strrpos($ip2bin, '1'); //can't be all 0's - $ip2bin = ($n == 0 ? '' : substr($ip2bin, 0, $n)) . '0' . str_repeat('1', $bits - $n - 1); // BINARY VERSION OF $ip2 -= 1 - // already checked for the edge case where end = start+1 and start ends in 0x1, above, so it's safe + /* 'Flex' Downgrade cURL errors - [ 35 - GET_SERVER_HELLO:sslv3 ] + [ 51 - NO alternative certificate ] + [ 60 - Local Issuer Certificate Subject ] */ + + // Allow downgrade of cURL settings 'Flex' after 1st failure, if user configured. + if ($retries == 1 && $pflex && in_array($curl_error, array( '35', '51', '60'))) { + 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'); + $log = "\n[ ! ] Downgrading SSL settings (Flex) "; + pfb_logger("{$log}", 1); + } + else { + $log = curl_error($ch) . " Retry in 5 seconds...\n"; + pfb_logger("{$log}", "{$logtype}"); + sleep(5); + pfb_logger('.', "{$logtype}"); + } + } + + // Collect RFC7231 http status code + $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + if (isset($pfb['rfc7231'][$http_status])) { + if ($logtype != 3) { + pfb_logger(". {$pfb['rfc7231'][$http_status]}", 1); + } else { + pfb_logger(" {$header}\t\t{$pfb['rfc7231'][$http_status]}\n", 3); + } + } else { + if ($logtype != 3) { + pfb_logger(". unknown http status code ", 2); + } else { + pfb_logger(". unknown http status code ", 3); + } + } + curl_close($ch); + } + fclose($fhandle); } + } - // this is the only edge case arising from increment/decrement. - // it happens if the range at start of loop is exactly 2 adjacent ips, that spanned the 1->0 gap. (we will have enumerated both by now) - - if (strcmp($ip2bin, $ip1bin) < 0) - continue; - - // step #3 the start and end ip MUST now end in '0's and '1's respectively - // so we have a non-trivial range AND the last N bits are no longer important for CIDR purposes. - - $shift = $bits - max(strrpos($ip1bin, '0'), strrpos($ip2bin, '1')); // num of low bits which are '0' in ip1 and '1' in ip2 - $ip1bin = str_repeat('0', $shift) . substr($ip1bin, 0, $bits - $shift); - $ip2bin = str_repeat('0', $shift) . substr($ip2bin, 0, $bits - $shift); - $netsize += $shift; - if ($ip1bin === $ip2bin) { - // we're done. - $new_subnet_ip = substr($ip1bin, $netsize, $bits - $netsize) . str_repeat('0', $netsize); - $rangesubnets[$new_subnet_ip] = $bits - $netsize; - continue; + if ($http_status == '200 OK') { + // Collect file mime-type + $file_type = exec("/usr/bin/file -b --mime-type {$file_dwn}.raw"); + unset($retval); + + // Decompress file if required + if ($file_type == 'application/x-gzip') { + if ($logtype == 3) { + // Extras - MaxMind downloads + @rename("{$file_dwn}.raw", strstr("{$file_dwn}.raw", '.raw', TRUE)); + exec("/usr/bin/gunzip -dfq {$file_dwn} {$pfb['geoipshare']}"); + return TRUE; + } + else { + pfb_logger('.', 1); + $pfb_output = fopen("{$file_dwn}.orig", 'w'); + if (($fhandle = gzopen("{$file_dwn}.raw", 'r')) !== FALSE) { + if (($fhandle = gzopen("{$file_dwn}.raw", 'r')) !== FALSE) { + while (($line = gzgets($fhandle, 1024)) !== FALSE) { + fwrite($pfb_output, $line); + } + } + $retval = 0; + } + gzclose($fhandle); + fclose($pfb_output); + } } - - // at this point there's still a remaining range, and either startip ends with '1', or endip ends with '0'. So repeat cycle. - } while (strcmp($ip1bin, $ip2bin) < 0); + elseif ($file_type == 'application/x-bzip2') { + pfb_logger('.', 1); + exec("/usr/bin/bzip2 -dkc {$file_dwn}.raw > {$file_dwn}.orig", $output, $retval); + } + elseif ($file_type == 'application/zip') { + if ($logtype == 3) { + // Extras - MaxMind/Alexa downloads + exec("/usr/bin/tar -xOf {$file_dwn}.raw > {$header}"); + unlink_if_exists("{$file_dwn}.raw"); + return TRUE; + } - // subnets are ordered by bit size. Re sort by IP ("naturally") and convert back to IPv4/IPv6 + pfb_logger('.', 1); + + // Check if ZIP archive contains xlsx files + $xlsxtest = exec("/usr/bin/tar -tf {$file_dwn}.raw"); + if (strpos($xlsxtest, '.xlsx') !== FALSE) { + unlink_if_exists("{$file_dwn}.orig"); + exec("{$pfb['script']} xlsx {$header} {$elog}"); + if (file_exists("{$file_dwn}.orig")) { + $retval = 0; + } + } else { + // Process ZIP file + exec("/usr/bin/tar -xOf {$file_dwn}.raw | tr ',' '\n' > {$file_dwn}.orig", $output, $retval); + } + } + else { + // Uncompressed file format. + if ($logtype == 3) { + // Extras - MaxMind/Alexa downloads + @rename("{$file_dwn}.raw", "{$header}"); + return TRUE; + } else { + // Rename file to 'orig' format + @rename("{$file_dwn}.raw", "{$file_dwn}.orig"); + $retval = 0; + } + } + + if ($retval == 0) { + // Set downloaded file timestamp to remote timestamp + if (isset($remote_stamp)) { + if ($remote_stamp != -1 && file_exists("{$file_dwn}.orig")) { + @touch("{$file_dwn}.orig", $remote_stamp); + } + else { + $log = "\n Remote timestamp missing "; + pfb_logger("{$log}", 1); + } + } + + // Process Emerging Threats IQRisk if required + if (strpos($list_url, 'iprepdata.txt') !== FALSE) { + exec("{$pfb['script']} et {$header} x x x x x {$pfb['etblock']} {$pfb['etmatch']} {$elog}"); + } + return TRUE; + } + else { + $log = " Decompression Failed\n"; + pfb_logger("{$log}", 2); + return FALSE; + } + } + else { + // Download failed + unlink_if_exists("{$file_dwn}.raw"); + } + return FALSE; +} + + +// Determine reason for download failure +function pfb_download_failure($alias, $header, $pfbfolder, $vtype, $list_url) { + global $pfb; + $pfbfound = FALSE; + + // Determine if URL is a localfile + $host = @parse_url("{$list_url}"); + if (in_array($host['host'], array('127.0.0.1', $pfb['iplocal'], ''))) { + $lof = 'local'; + } else { + $lof = ''; + } + + // Log FAILED downloads and check if firewall or Snort/Suricata is blocking host + $log = "\n\n [ {$alias} - {$header} ] Download FAIL [ NOW ]\n"; + pfb_logger("{$log}", 2); + + // Only perform these checks if they are not 'localfiles' + if ($lof == 'local') { + $log = " Local File Failure\n"; + pfb_logger("{$log}", 2); + } else { + // Determine if Firewall/IDS is blocking download. + $ip = @gethostbyname($host); + + if (!empty($ip)) { + // Query Firewall aliastables + $result = find_reported_header($ip, "{$pfbfolder}/*", TRUE); + if (!empty($result)) { + $log = " [ {$ip} ] Firewall IP block found in: [ {$result} ]\n"; + pfb_logger("{$log}", 2); + $pfbfound = TRUE; + } + + // Query Snort/Suricata snort2c IP block table + $result = exec("{$pfb['pfctl']} -t snort2c -T show | {$pfb['grep']} {$ip} 2>&1"); + if (!empty($result)) { + $log = " [ {$ip} ] IDS IP block found!\n"; + pfb_logger("{$log}", 2); + $pfbfound = TRUE; + } + } + else { + $log = " Could not determine IP address of host.\n"; + pfb_logger("{$log}", 2); + } + + if (!$pfbfound) { + $log = " Firewall and/or IDS are not blocking download.\n"; + pfb_logger("{$log}", 2); + } + } + + // On download failure, create file marker for subsequent download attempts + if ($pfb['restore'] == 'on' && $pfb['skipfeed'] != 0) { + // Call function to get all previous download fails + pfb_failures(); + + if ($pfb['failed'][$header] <= $pfb['skipfeed']) { + touch("{$pfbfolder}/{$header}.fail"); + return; + } + } + + unlink_if_exists("{$pfbfolder}/{$header}.fail"); + return; +} - ksort($rangesubnets, SORT_STRING); - $out = array(); - foreach ($rangesubnets as $ip => $netmask) { - if ($proto == 'ipv4') { - $i = str_split($ip, 8); - $out[] = implode('.', array( bindec($i[0]),bindec($i[1]),bindec($i[2]),bindec($i[3]))) . '/' . $netmask; - } else - $out[] = Net_IPv6::compress(Net_IPv6::_bin2Ip($ip)) . '/' . $netmask; +// Collect all previously failed daily download notices +function pfb_failures() { + global $pfb; + $pfb['failed'] = array(); + + if (file_exists("{$pfb['errlog']}")) { + exec("{$pfb['grep']} 'FAIL' {$pfb['errlog']} | {$pfb['grep']} $(date +%m/%d/%y)", $results); + if (!empty($results)) { + foreach ($results as $result) { + $header = explode(' ', $result); + $pfb['failed'][$header[4]] += 1; + } + } } + return; +} - return $out; + +// Convert alias name (via ascii table number) and return a 10 digit tracker id +function pfb_tracker($alias) { + for ($i = 0; $i < strlen($alias); $i++) { + $pfbtracker += @ord($alias[$i]); + } + return '177' . str_pad($pfbtracker, 7, '0', STR_PAD_LEFT); } -// Archive Aliastables for NanoBSD and RAMDisk Installations +// Define firewall rule settings +function pfb_firewall_rule($action, $pfb_alias, $vtype='', $pfb_log, $adest='', $aports='', $aproto='', $anot='') { + global $pfb; + $rule = array(); + + switch ($action) { + case 'Deny_Both': + case 'Deny_Outbound': + $rule = $pfb['base_rule']; + $rule['tracker'] = pfb_tracker("{$pfb_alias}{$vtype}deny_out"); + $rule['type'] = "{$pfb['deny_action_outbound']}"; + if ($vtype == '_v6') { + $rule['ipprotocol'] = 'inet6'; + } + if ($pfb['float'] == 'on') { + $rule['direction'] = 'any'; + } + $rule['descr'] = "{$pfb_alias}{$vtype}{$pfb['suffix']}"; + $rule['source'] = array('any' => ''); + $rule['destination'] = array('address' => "{$pfb_alias}{$vtype}"); + if ($pfb['config']['enable_log'] == 'on' || $pfb_log == 'enabled') { + $rule['log'] = ''; + } + $rule['created'] = array('time' => (int)microtime(true), 'username' => 'Auto'); + $pfb['deny_outbound'][] = $rule; + if ($action != 'Deny_Both') { + break; + } + case 'Deny_Inbound': + $rule = $pfb['base_rule']; + $rule['tracker'] = pfb_tracker("{$pfb_alias}{$vtype}deny_in"); + $rule['type'] = "{$pfb['deny_action_inbound']}"; + if ($vtype == '_v6') { + $rule['ipprotocol'] = 'inet6'; + } + if ($pfb['float'] == 'on') { + $rule['direction'] = 'any'; + } + $rule['descr'] = "{$pfb_alias}{$vtype}{$pfb['suffix']}"; + $rule['source'] = array('address' => "{$pfb_alias}{$vtype}"); + if (!empty($adest) && !empty($aports)) { + $rule['destination'] = array('address' => "{$adest}", 'port' => "{$aports}"); + } elseif (!empty($adest) && empty($aports)) { + $rule['destination'] = array('address' => "{$adest}"); + } elseif (empty($adest) && !empty($aports)) { + $rule['destination'] = array('any' => '', 'port' => "{$aports}"); + } else { + $rule['destination'] = array('any' => ''); + } + if (!empty($adest) && $anot == 'on') { + $rule['destination']['not'] = ''; + } + if (!empty($aproto)) { + $rule['protocol'] = "{$aproto}"; + } + if ($pfb['config']['enable_log'] == 'on' || $pfb_log == 'enabled') { + $rule['log'] = ''; + } + $rule['created'] = array('time' => (int)microtime(true), 'username' => 'Auto'); + $pfb['deny_inbound'][] = $rule; + break; + case 'Permit_Both': + case 'Permit_Outbound': + $rule = $pfb['base_rule']; + $rule['type'] = 'pass'; + $rule['tracker'] = pfb_tracker("{$pfb_alias}{$vtype}permit_out"); + if ($vtype == '_v6') { + $rule['ipprotocol'] = 'inet6'; + } + if ($pfb['float'] == 'on') { + $rule['direction'] = 'any'; + } + $rule['descr'] = "{$pfb_alias}{$vtype}{$pfb['suffix']}"; + $rule['source'] = array('any' => ''); + $rule['destination'] = array('address' => "{$pfb_alias}{$vtype}"); + if ($pfb['config']['enable_log'] == 'on' || $pfb_log == 'enabled') { + $rule['log'] = ''; + } + $rule['created'] = array('time' => (int)microtime(true), 'username' => 'Auto'); + $pfb['permit_outbound'][] = $rule; + if ($action != 'Permit_Both') { + break; + } + case 'Permit_Inbound': + $rule = $pfb['base_rule']; + $rule['tracker'] = pfb_tracker("{$pfb_alias}{$vtype}permit_in"); + $rule['type'] = 'pass'; + if ($vtype == '_v6') { + $rule['ipprotocol'] = 'inet6'; + } + if ($pfb['float'] == 'on') { + $rule['direction'] = 'any'; + } + $rule['descr'] = "{$pfb_alias}{$vtype}{$pfb['suffix']}"; + $rule['source'] = array('address' => "{$pfb_alias}{$vtype}"); + if (!empty($adest) && !empty($aports)) { + $rule['destination'] = array('address' => "{$adest}", 'port' => "{$aports}"); + } elseif (!empty($adest) && empty($aports)) { + $rule['destination'] = array('address' => "{$adest}"); + } elseif (empty($adest) && !empty($aports)) { + $rule['destination'] = array('any' => '', 'port' => "{$aports}"); + } else { + $rule['destination'] = array('any' => ''); + } + if (!empty($adest) && $anot == 'on') { + $rule['destination']['not'] = ''; + } + if (!empty($aproto)) { + $rule['protocol'] = "{$aproto}"; + } + if ($pfb['config']['enable_log'] == 'on' || $pfb_log == 'enabled') { + $rule['log'] = ''; + } + $rule['created'] = array('time' => (int)microtime(true), 'username' => 'Auto'); + $pfb['permit_inbound'][] = $rule; + break; + case 'Match_Both': + case 'Match_Outbound': + $rule = $pfb['base_rule_float']; + $rule['tracker'] = pfb_tracker("{$pfb_alias}{$vtype}match_out"); + $rule['type'] = 'match'; + if ($vtype == '_v6') { + $rule['ipprotocol'] = 'inet6'; + } + $rule['direction'] = 'any'; + $rule['descr'] = "{$pfb_alias}{$vtype}{$pfb['suffix']}"; + $rule['source'] = array('any' => ''); + $rule['destination'] = array('address' => "{$pfb_alias}{$vtype}"); + if ($pfb['config']['enable_log'] == 'on' || $pfb_log == 'enabled') { + $rule['log'] = ''; + } + $rule['created'] = array('time' => (int)microtime(true), 'username' => 'Auto'); + $rule['match_outbound'][] = $rule; + if ($action != 'Match_Both') { + break; + } + case 'Match_Inbound': + $rule = $pfb['base_rule_float']; + $rule['tracker'] = pfb_tracker("{$pfb_alias}{$vtype}match_in"); + $rule['type'] = 'match'; + if ($vtype == '_v6') { + $rule['ipprotocol'] = 'inet6'; + } + $rule['direction'] = 'any'; + $rule['descr'] = "{$pfb_alias}{$vtype}{$pfb['suffix']}"; + $rule['source'] = array('address' => "{$pfb_alias}{$vtype}"); + if (!empty($adest) && !empty($aports)) { + $rule['destination'] = array('address' => "{$adest}", 'port' => "{$aports}"); + } elseif (!empty($adest) && empty($aports)) { + $rule['destination'] = array('address' => "{$adest}"); + } elseif (empty($adest) && !empty($aports)) { + $rule['destination'] = array('any' => '', 'port' => "{$aports}"); + } else { + $rule['destination'] = array('any' => ''); + } + if (!empty($adest) && $anot == 'on') { + $rule['destination']['not'] = ''; + } + if (!empty($aproto)) { + $rule['protocol'] = "{$aproto}"; + } + if ($pfb['config']['enable_log'] == 'on' || $pfb_log == 'enabled') { + $rule['log'] = ''; + } + $rule['created'] = array('time' => (int)microtime(true), 'username' => 'Auto'); + $pfb['match_inbound'][] = $rule; + break; + } + return; +} + + +// Archive aliastables for NanoBSD and RAMDisk installations function pfb_aliastables($mode) { - global $g,$config,$pfb; - $earlyshellcmd = "/usr/local/pkg/pfblockerng/pfblockerng.sh aliastables"; - $msg = ""; + global $g, $config, $pfb; + $earlyshellcmd = '/usr/local/pkg/pfblockerng/pfblockerng.sh aliastables'; + $msg = ''; - // Only Execute function if Platform is NanoBSD or Ramdisks are used. - if (($g['platform'] != "pfSense") || isset($config['system']['use_mfs_tmpvar'])) { + // Only execute function if platform is NanoBSD or Ramdisks are used. + if (($g['platform'] != 'pfSense') || isset($config['system']['use_mfs_tmpvar'])) { conf_mount_rw(); - if ($mode == "update") { - // Archive Aliastable Folder - exec ("cd {$pfb['aliasdir']}; ls -A pfB_*.txt && /usr/bin/tar -jcvf {$pfb['aliasarchive']} pfB_*.txt >/dev/null 2>&1"); - $msg = "\n\nArchiving Aliastable Folder\n"; + if ($mode == 'update') { + // Archive aliastable folder + exec("cd {$pfb['aliasdir']}; ls -A pfB_*.txt && /usr/bin/tar -jcvf {$pfb['aliasarchive']} pfB_*.txt >/dev/null 2>&1"); + pfb_logger("\n\nArchiving Aliastable folder\n", 1); } - elseif ($mode == "conf") { + elseif ($mode == 'conf') { + + // Reload config.xml to get any recent changes + $config = parse_config(true); + // Check conf file for earlyshellcmd - if (is_array($config['system']['earlyshellcmd'])) { + if (isset($config['system']['earlyshellcmd'])) { $a_earlyshellcmd = &$config['system']['earlyshellcmd']; if (!preg_grep("/pfblockerng.sh aliastables/", $a_earlyshellcmd)) { $a_earlyshellcmd[] = "{$earlyshellcmd}"; @@ -569,13 +1597,13 @@ function pfb_aliastables($mode) { } else { if (file_exists("{$pfb['aliasarchive']}")) { - // Remove Aliastables archive if found. + // Remove aliastables archive if found. conf_mount_rw(); @unlink_if_exists("{$pfb['aliasarchive']}"); conf_mount_ro(); } // Remove earlyshellcmd if found. - if (is_array($config['system']['earlyshellcmd'])) { + if (isset($config['system']['earlyshellcmd'])) { $a_earlyshellcmd = &$config['system']['earlyshellcmd']; if (preg_grep("/pfblockerng.sh aliastables/", $a_earlyshellcmd)) { $a_earlyshellcmd = preg_grep("/pfblockerng.sh aliastables/", $a_earlyshellcmd, PREG_GREP_INVERT); @@ -584,250 +1612,352 @@ function pfb_aliastables($mode) { } } - if ($msg != "") { - pfb_logger("{$msg}","1"); - $pfb['cron_mod'] = TRUE; + if (!empty($msg)) { + pfb_logger("{$msg}", 1); + write_config('pfBlockerNG: saving earlyshellcmd'); } } -// Main pfBlockerNG Function -function sync_package_pfblockerng($cron = "") { +// Read logfile in realtime (livetail) +// Reference: http://stackoverflow.com/questions/3218895/php-how-to-read-a-file-live-that-is-constantly-being-written-to +function pfb_livetail($logfile, $mode) { + global $pfb; - global $g,$config,$pfb,$pfbarr; - pfb_global(); - $pfb['cron_mod'] = FALSE; // Flag to check for mods to the config.xml file. + if (!file_exists("{$logfile}")) { + touch("{$logfile}"); + } - // Detect Boot Process or Update via CRON - if (isset($_POST) && $cron == "") { - if (!preg_match("/\w+/",$_POST['__csrf_magic'])) { - log_error("[pfBlockerNG] Sync terminated during boot process."); - return; + // Start at EOF + $lastpos_old = ''; + $len = filesize("{$logfile}"); + + if ($mode == 'view') { + // Start at EOF ( - 15000) + if ($len > 15000) { + $lastpos = ($len - 15000); + } else { + $lastpos = 0; } } - log_error("[pfBlockerNG] Starting sync process."); + else { + $lastpos = $len; + } - // Force Update - Set 'Save' variable when 'No Updates' found. - if ($cron == "noupdates") { - $pfb['save'] = TRUE; + while (true) { + usleep(300000); //0.3s + clearstatcache(false, "{$logfile}"); + $len = filesize("{$logfile}"); + if ($len < $lastpos) { + //file deleted or reset + $lastpos = $len; + } else { + $f = fopen("{$logfile}", 'rb+'); + if ($f === false) { + break; + } + fseek($f, $lastpos); + + // 'Force Update/Cron/Reload' + if ($mode == 'force' || $mode == 'view') { + while (!feof($f)) { + $pfb_buffer = fread($f, 2048); + $pfb_output .= str_replace( array ("\r", "\")"), '', $pfb_buffer); + // Refresh on new lines only. This allows Scrolling. + if ($lastpos != $lastpos_old) { + pfbupdate_output($pfb_output); + } + $lastpos_old = $lastpos; + ob_flush(); + flush(); + + } + $lastpos = ftell($f); + fclose($f); + + // Capture remaining output + if ($mode != 'view' && strpos($pfb_output, 'UPDATE PROCESS ENDED') !== FALSE) { + $f = fopen($pfb['log'], 'rb'); + fseek($f, $lastpos); + $pfb_buffer = fread($f, 2048); + $pfb_output .= str_replace( "\r", '', $pfb_buffer); + pfbupdate_output($pfb_output); + clearstatcache(false, $pfb['log']); + ob_flush(); + flush(); + fclose($f); + + // Call log mgmt function + pfb_log_mgmt(); + break; + } + } + else { + // DNSBL Lighttpd 'dnsbl_error.log' conditional log parser + while (($pfb_buffer = fgets($f, 1024)) !== FALSE) { + if (strpos($pfb_buffer, 'HTTPhost') !== FALSE) { + $checkpos = 0; + } + + if ($checkpos == 3 && strpos($pfb_buffer, 'HTTP["host"]') !== FALSE) { + $line = strstr($pfb_buffer, ' ) compare', TRUE); + $line = ltrim(strstr($line, '] ( ', FALSE), '] ( '); + if (!empty($line)) { + $log = "DNSBL Reject HTTPS," . date('M d G:i:s', time()) . ",{$line}\n"; + @file_put_contents($pfb['dnslog'], $log, FILE_APPEND | LOCK_EX); + + // Query DNSBL Alias for Domain list. + $query = str_replace('.', '\.', $line); + exec("/usr/bin/grep -l ' \"{$query} 60 IN A' {$pfb['dnsalias']}/*", $match); + $pfb_query = strstr($match[0], 'DNSBL', FALSE); + + if (!empty($pfb_query)) { + // Increment DNSBL Alias counter + if (($handle = fopen("{$pfb['dnsbl_info']}", 'r')) !== FALSE) { + flock($handle, LOCK_EX); + $pfb_output = fopen("{$pfb['dnsbl_info']}.bk", 'w'); + flock($pfb_output, LOCK_EX); + + // Find line with corresponding DNSBL Aliasname + while (($line = fgetcsv($handle)) !== FALSE) { + if ($line[0] == $pfb_query) { + $line[3] += 1; + } + fputcsv($pfb_output, $line); + } + + fclose($pfb_output); + fclose($handle); + @rename ("{$pfb['dnsbl_info']}.bk", "{$pfb['dnsbl_info']}"); + } + } + } + } + $checkpos++; + ob_flush(); + flush(); + } + + // Delete parsed logfile contents + clearstatcache(false, "{$logfile}"); + $tlen = filesize("{$logfile}"); + if ($tlen > $lastpos) { + $tlen = $tlen - $lastpos; + ftruncate($f, $tlen); + fclose($f); + $lastpos = $tlen; + } + } + } } +} + + +// Main pfBlockerNG function +function sync_package_pfblockerng($cron='') { + global $g, $config, $pfb, $pfbarr; + pfb_global(); + $pfb['conf_mod'] = FALSE; // Flag to check for mods to the config.xml file. ('$pfb_config' array to hold changes) - // Start of pfBlockerNG Logging to 'pfblockerng.log' - if ($pfb['enable'] == "on" && !$pfb['save']) { + // Detect boot process or package installation + if (platform_booting() || $g['pfblockerng_install']) { + // Create DNSBL NAT, VIP, Lighttpd service and certs if required on reboot. + if ($pfb['dnsbl'] == 'on') { + pfb_create_dnsbl('enable'); + } + log_error('[pfBlockerNG] Sync terminated during boot process.'); + return; + } + syslog(LOG_NOTICE, '[pfBlockerNG] Starting sync process.'); + + // Reloads existing lists without downloading new lists when defined 'on' + $pfb['reuse'] = $pfb['config']['pfb_reuse']; + $pfb['reuse_dnsbl'] = ''; + + // Define update process (update or reload) + switch ($cron) { + case 'noupdates': + // Force update - Set 'save' variable when 'No updates' found. + $pfb['save'] = TRUE; + break; + case 'cron': + if ($pfb['reuse'] == 'on') { + $pfb['reuse_dnsbl'] = 'on'; + unlink_if_exists("{$pfb['dbdir']}/masterfile"); + unlink_if_exists("{$pfb['dbdir']}/mastercat"); + } + break; + case 'updatednsbl': + $pfb['reuse'] = ''; + $pfb['reuse_dnsbl'] = 'on'; + break; + case 'updateip': + $pfb['reuse'] = 'on'; + $pfb['reuse_dnsbl'] = ''; + unlink_if_exists("{$pfb['dbdir']}/masterfile"); + unlink_if_exists("{$pfb['dbdir']}/mastercat"); + break; + } + + // Start of pfBlockerNG logging to 'pfblockerng.log' + if ($pfb['enable'] == 'on' && !$pfb['save']) { $log = " UPDATE PROCESS START [ NOW ]\n"; - pfb_logger("{$log}","1"); + pfb_logger("{$log}", 1); } else { - if ($cron != "noupdates") { - $log = "\n**Saving Configuration [ NOW ] ...\n"; - pfb_logger("{$log}","1"); + if ($cron != 'noupdates') { + $log = "\n**Saving configuration [ NOW ] ...\n"; + pfb_logger("{$log}", 1); } } // Call function for NanoBSD/Ramdisk processes. - pfb_aliastables("conf"); + pfb_aliastables('conf'); - // Collect pfSense Max Table Size Entry + // If table limit not defined, set default to 2M if (empty($config['system']['maximumtableentries'])) { - // If Table limit not defined, set Default to 2M - $config['system']['maximumtableentries'] = "2000000"; - $pfb['cron_mod'] = TRUE; + $config['system']['maximumtableentries'] = '2000000'; + write_config('pfBlockerNG: save max Firewall table entries limit'); } $pfb['table_limit'] = $config['system']['maximumtableentries']; // Collect local web gui configuration - $pfb['weblocal'] = ($config['system']['webgui']['protocol'] != "" ? $config['system']['webgui']['protocol'] : "http"); + $pfb['weblocal'] = $config['system']['webgui']['protocol'] ?: 'http'; $pfb['port'] = $config['system']['webgui']['port']; - if ($pfb['port'] == "") { - if ($config['system']['webgui']['protocol'] == "http") { - $pfb['port'] = "80"; + if (empty($pfb['port'])) { + if ($config['system']['webgui']['protocol'] == 'http') { + $pfb['port'] = '80'; } else { - $pfb['port'] = "443"; + $pfb['port'] = '443'; } } $pfb['weblocal'] .= "://127.0.0.1:{$pfb['port']}/pfblockerng/pfblockerng.php"; - // Define Inbound/Outbound Action is not user selected. - $pfb['deny_action_inbound'] = ($pfb['config']['inbound_deny_action'] != "" ? $pfb['config']['inbound_deny_action'] : "block"); - $pfb['deny_action_outbound'] = ($pfb['config']['outbound_deny_action'] != "" ? $pfb['config']['outbound_deny_action'] : "reject"); - - // Reloads Existing Blocklists without Downloading New Lists - $pfb['reuse'] = $pfb['config']['pfb_reuse']; - // Enable OpenVPN AutoRules - $pfb['openvpn'] = $pfb['config']['openvpn_action']; - // Enable/Disable Floating Auto-Rules - $pfb['float'] = $pfb['config']['enable_float']; - // Enable Remove of Duplicate IPs utilizing Grepcidr - $pfb['dup'] = $pfb['config']['enable_dup']; - // Order of the Auto-Rules - $pfb['order'] = $pfb['config']['pass_order']; - // Suffix used for Auto-Rules - $pfb['suffix'] = $pfb['config']['autorule_suffix']; - - // Reputation Variables + // Define Inbound/Outbound action is not user selected. + $pfb['deny_action_inbound'] = $pfb['config']['inbound_deny_action'] ?: 'block'; + $pfb['deny_action_outbound'] = $pfb['config']['outbound_deny_action'] ?: 'reject'; + + $pfb['openvpn'] = $pfb['config']['openvpn_action']; // Enable OpenVPN autorules + $pfb['float'] = $pfb['config']['enable_float']; // Enable/Disable floating autorules + $pfb['dup'] = $pfb['config']['enable_dup']; // Enable remove of duplicate IPs utilizing grepcidr + $pfb['agg'] = $pfb['config']['enable_agg']; // Enable aggregation of CIDRs + $pfb['order'] = $pfb['config']['pass_order']; // Order of the autorules + $pfb['suffix'] = $pfb['config']['autorule_suffix']; // Suffix used for autorules + $pfb['kstates'] = $pfb['config']['killstates']; // Firewall states removal + + // DNSBL settings + $pfb['dnsbl_vip'] = $pfb['dnsblconfig']['pfb_dnsvip'] ?: ''; // Virtual IP local address + $pfb['dnsbl_iface'] = $pfb['dnsblconfig']['dnsbl_interface']?: 'lan'; // VIP Local Interface setting + $pfb['dnsbl_ip'] = $pfb['dnsblconfig']['action'] ?: 'Disabled'; // Enable/Disable IP blocking from DNSBL lists + $pfb['dnsbl_rule'] = $pfb['dnsblconfig']['pfb_dnsbl_rule'] ?: 'Disabled'; // Auto create a Floating Pass Rule for other Lan subnets + $pfb['dnsbl_alexa'] = $pfb['dnsblconfig']['alexa_enable'] ?: 'Disabled'; // Enable Alexa whitelist + $pfb['dnsbl_alexa_cnt'] = $pfb['dnsblconfig']['alexa_count'] ?: '1000'; // Alexa whitelist domain setting + $pfb['dnsbl_alexa_inc'] = $pfb['dnsblconfig']['alexa_inclusion'] ?: ''; // Alexa TLDs inclusions for whitelisting + + // Reputation variables $pfb['config_rep'] = $config['installedpackages']['pfblockerngreputation']['config'][0]; - // Enable/Disable Reputation - $pfb['rep'] = $pfb['config_rep']['enable_rep']; - // Enable/Disable 'pDup' - $pfb['pdup'] = $pfb['config_rep']['enable_pdup']; - // Enable/Disable 'dDup' - $pfb['dedup'] = ($pfb['config_rep']['enable_dedup'] != "" ? $pfb['config_rep']['enable_dedup'] : "x"); - // 'Max' variable setting for Reputation - $pfb['max'] = ($pfb['config_rep']['p24_max_var'] != "" ? $pfb['config_rep']['p24_max_var'] : "x"); - // 'dMax' variable setting for Reputation - $pfb['dmax'] = ($pfb['config_rep']['p24_dmax_var'] != "" ? $pfb['config_rep']['p24_dmax_var'] : "x"); - // 'pMax' variable setting for Reputation - $pfb['pmax'] = ($pfb['config_rep']['p24_pmax_var'] != "" ? $pfb['config_rep']['p24_pmax_var'] : "x"); - // Action for Whitelist Country Category - $pfb['ccwhite'] = $pfb['config_rep']['ccwhite']; - // Action for Blacklist Country Category - $pfb['ccblack'] = $pfb['config_rep']['ccblack']; - // List of Countries in the Whitelist Category - $pfb['ccexclude']= ($pfb['config_rep']['ccexclude'] != "" ? $pfb['config_rep']['ccexclude'] : "x"); - // Emerging Threats IQRisk Block Categories - $pfb['etblock'] = ($pfb['config_rep']['etblock'] != "" ? $pfb['config_rep']['etblock'] : "x"); - // Emerging Threats IQRisk Match Categories - $pfb['etmatch'] = ($pfb['config_rep']['etmatch'] != "" ? $pfb['config_rep']['etmatch'] : "x"); - // Perform a Force Update on ET Categories - $pfb['etupdate']= $pfb['config_rep']['et_update']; - - // Variables - - // Starting Variable to Skip rep, pdup and dedeup functions if no changes are required - $pfb['dupcheck'] = FALSE; - // $pfb['save'] is used to determine if User pressed "Save" Button to avoid Collision with CRON. - // This is defined in each pfBlockerNG XML Files + $pfb['rep'] = $pfb['config_rep']['enable_rep']; // Enable/Disable 'Max' Reputation + $pfb['prep'] = $pfb['config_rep']['enable_pdup']; // Enable/Disable 'pRep' Reputation + $pfb['drep'] = $pfb['config_rep']['enable_dedup'] ?: 'x'; // Enable/Disable 'dRep' Reputation + $pfb['etupdate']= $pfb['config_rep']['et_update']; // Perform a Force Update on ET categories + $pfb['ccwhite'] = $pfb['config_rep']['ccwhite']; // Action for whitelist Country category + $pfb['ccblack'] = $pfb['config_rep']['ccblack']; // Action for blacklist Country category + + $pfb['etblock'] = $pfb['config_rep']['etblock'] ?: 'x'; // Emerging Threats IQRisk block categories + $pfb['etmatch'] = $pfb['config_rep']['etmatch'] ?: 'x'; // Emerging Threats IQRisk match categories + $pfb['max'] = $pfb['config_rep']['p24_max_var'] ?: 'x'; // 'Max' variable setting for Reputation + $pfb['dmax'] = $pfb['config_rep']['p24_dmax_var'] ?: 'x'; // 'dMax' variable setting for Reputation + $pfb['pmax'] = $pfb['config_rep']['p24_pmax_var'] ?: 'x'; // 'pMax' variable setting for Reputation + $pfb['ccexclude']= $pfb['config_rep']['ccexclude'] ?: 'x'; // List of Countries to whitelist + + // Starting variable to skip Reputation functions, if no changes are required + $pfb['repcheck'] = FALSE; + // $pfb['save'] is used to determine if user pressed "save" button to avoid collision with CRON, defined in each pfBlockerNG XML file. + + // For 'script' calls using exec() (used to shorten length of line) + $elog = ">> {$pfb['log']} 2>&1"; ################################# # Configure ARRAYS # ################################# - $continents = array ( "Africa" => "pfB_Africa", - "Antartica" => "pfB_Antartica", - "Asia" => "pfB_Asia", - "Europe" => "pfB_Europe", - "North America" => "pfB_NAmerica", - "Oceania" => "pfB_Oceania", - "South America" => "pfB_SAmerica", - "Top Spammers" => "pfB_Top", - "Proxy and Satellite" => "pfB_PS" - ); - - // create rules vars and arrays - // Array used to Collect Changes to Aliases to be saved to Config - $new_aliases = array(); - $new_aliases_list = array(); - $continent_existing = array(); - $continent_new = array(); - $permit_inbound = array(); - $permit_outbound = array(); - $deny_inbound = array(); - $deny_outbound = array(); - // An Array of all Aliases (Active and non-Active) - $aliases_list = array(); - // This is an Array of Aliases that Have Updated Lists via CRON/Force Update when 'Reputation' disabled. - $pfb_alias_lists = array(); - // This is an Array of All Active Aliases used when 'Reputation' enabled - $pfb_alias_lists_all = array(); - - // Base Rule Array - $base_rule_reg = array( "id" => "", - "tag" => "", - "tagged" => "", - "max" => "", - "max-src-nodes" => "", - "max-src-conn" => "", - "max-src-states"=> "", - "statetimeout" => "", - "statetype" => "keep state", - "os" => "" - ); - - // Floating Rules, Base Rule Array - $base_rule_float = array("id" => "", - "tag" => "", - "tagged" => "", - "quick" => "yes", - "floating" => "yes", - "max" => "", - "max-src-nodes" => "", - "max-src-conn" => "", - "max-src-states"=> "", - "statetimeout" => "", - "statetype" => "keep state", - "os" => "" - ); + $new_aliases = array(); // An array of aliases (full details) + $new_aliases_list = array(); // An array of alias names + $pfb_alias_lists = array(); // An array of aliases that have updated lists via CRON/force update. ('Reputation' disabled) + $pfb_alias_lists_all = array(); // An array of all active aliases. ('Reputation' enabled) ######################################### # Configure Rule Suffix # ######################################### - // Discover if any Rules are AutoRules (If no AutoRules found, $pfb['autorules'] is FALSE, Skip Rules Re-Order ) - // To configure Auto Rule Suffix. pfBlockerNG must be disabled to change Suffix and to avoid Duplicate Rules + // Discover if any rules are autorules (If no autorules found, $pfb['autorules'] is FALSE, skip rules re-order ) + // To configure auto rule suffix. pfBlockerNG must be disabled to change suffix and to avoid duplicate rules $pfb['autorules'] = FALSE; - $pfb['found'] = FALSE; - foreach ($continents as $continent => $pfb_alias) { - if (is_array($config['installedpackages']['pfblockerng' . strtolower(preg_replace('/ /','',$continent))]['config'])) { - $continent_config = $config['installedpackages']['pfblockerng' . strtolower(preg_replace('/ /','',$continent))]['config'][0]; - if ($continent_config['action'] != "Disabled" && in_array($continent_config['action'],array('Deny_Both','Deny_Inbound','Deny_Outbound','Match_Both','Match_Inbound','Match_Outbound','Permit_Both','Permit_Inbound','Permit_Outbound'))) { + $action = array('Deny_Both', 'Deny_Inbound', 'Deny_Outbound', 'Match_Both', 'Match_Inbound', + 'Match_Outbound', 'Permit_Both', 'Permit_Inbound', 'Permit_Outbound'); + + 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' && in_array($continent_config['action'], $action)) { $pfb['autorules'] = TRUE; - $pfb['found'] = TRUE; break; } } } - $list_type = array ("pfblockernglistsv4", "pfblockernglistsv6"); - foreach ($list_type as $ip_type) { - if ($config['installedpackages'][$ip_type]['config'] != "" && !$pfb['found']) { - foreach($config['installedpackages'][$ip_type]['config'] as $list) { - if ($list['action'] != "Disabled" && in_array($list['action'],array('Deny_Both','Deny_Inbound','Deny_Outbound','Match_Both','Match_Inbound','Match_Outbound','Permit_Both','Permit_Inbound','Permit_Outbound'))) { - $pfb['autorules'] = TRUE; - break; + if (!$pfb['autorules']) { + $list_type = array('pfblockernglistsv4', 'pfblockernglistsv6'); + foreach ($list_type as $ip_type) { + if (isset($config['installedpackages'][$ip_type]['config'])) { + foreach($config['installedpackages'][$ip_type]['config'] as $list) { + if ($list['action'] != 'Disabled' && in_array($list['action'], $action)) { + $pfb['autorules'] = TRUE; + break; + } } } } } - // Configure Auto Rule Suffix. pfBlockerNG must be disabled to change Suffix and to avoid Duplicate Rules - // Count Number of Rules with 'pfB_' - $count = 0; - if (is_array($config['filter']['rule'])) { + // Configure auto rule suffix. pfBlockerNG must be disabled to change suffix and to avoid duplicate rules + $pfbfound = FALSE; + if (isset($config['filter']['rule'])) { foreach ($config['filter']['rule'] as $rule) { - // Collect any pre-existing Suffix - if (preg_match("/pfB_\w+(\s.*)/",$rule['descr'], $pfb_suffix_real) && $count == 0) { + // Collect any pre-existing suffix + if (preg_match('/pfB_\w+(\s.*)/', $rule['descr'], $pfb_suffix_real) && $count == 0) { $pfb_suffix_match = $pfb_suffix_real[1]; } - // Query for Existing pfB Rules - if (preg_match("/pfB_/",$rule['descr'])) { - $count++; + // Query for existing pfB rules + if (strpos($rule['descr'], 'pfB_') !== FALSE && $rule['descr'] != 'pfB_DNSBL_Allow_access_to_VIP') { + $pfbfound = TRUE; break; } } } - // Change Suffix only if No pfB Rules Found and Auto Rules are Enabled. - if ($pfb['autorules'] && $count == 0) { + // Change suffix only if no pfB rules found and autorules are enabled. + if ($pfb['autorules'] && !$pfbfound) { switch ($pfb['suffix']) { - case "autorule": - $pfb['suffix'] = " auto rule"; + case 'autorule': + $pfb['suffix'] = ' auto rule'; break; - case "standard": - $pfb['suffix'] = ""; + case 'standard': + $pfb['suffix'] = ''; break; - case "ar": - $pfb['suffix'] = " AR"; + case 'ar': + $pfb['suffix'] = ' AR'; break; } } else { if ($pfb['autorules']) { - // Use existing Suffix Match + // Use existing suffix match $pfb['suffix'] = $pfb_suffix_match; } else { - // Leave Rule Suffix 'Blank' - $pfb['suffix'] = ""; + // Leave rule suffix 'blank' + $pfb['suffix'] = ''; } } @@ -836,69 +1966,57 @@ function sync_package_pfblockerng($cron = "") { # Configure INBOUND/OUTBOUND INTERFACES # ######################################################### - // Collect pfSense Interface Order + // Collect pfSense interface order $ifaces = get_configured_interface_list(); - if (!empty($pfb['config']['inbound_interface'])) { - // Sort Interface Array to match pfSense Interface order to allow Floating Rules to populate. - $selected_interfaces = explode(",",$pfb['config']['inbound_interface']); - // Sort pfBlockerNG Interface order to pfSense Interface Order - $sort_interfaces = array_intersect($ifaces, $selected_interfaces); - $implode_interfaces = ltrim(implode(",",$sort_interfaces), ","); - // CSV String for Inbound Interfaces for 'pfB_' Match Rules - $pfb['inbound_floating'] = $implode_interfaces; - $pfb['inbound_interfaces_float'] = explode(" ",$implode_interfaces); - - // Assign Inbound Base Rule/Interfaces - if ($pfb['float'] == "on") { - // Define Base Firewall Floating Rules Settings - $base_rule = $base_rule_float; - $pfb['inbound_interfaces'] = $pfb['inbound_interfaces_float']; - } else { - // Define Base Firewall Rules Settings - $base_rule = $base_rule_reg; - $pfb['inbound_interfaces'] = explode(",",$pfb['config']['inbound_interface']); - } - } else { - // Define Empty Variable/Array - $pfb['inbound_interfaces_float'] = ""; - $pfb['inbound_interfaces'] = array(); - } - - if (!empty($pfb['config']['outbound_interface'])) { - // Sort Interface Array to match pfSense Interface order to allow Floating Rules to populate. - $selected_interfaces = explode(",",$pfb['config']['outbound_interface']); - // Sort pfBlockerNG Interface order to pfSense Interface Order - $sort_interfaces = array_intersect($ifaces, $selected_interfaces); - // If OpenVPN Interfaces are not in dropdown menu - if ($pfb['openvpn'] == "on" && $config['openvpn']['openvpn-server'] || $pfb['openvpn'] == "on" && $config['openvpn']['openvpn-client']) { - if (!in_array("openvpn",$sort_interfaces)) { - array_push($sort_interfaces, "openvpn"); - } - } - $implode_interfaces = ltrim(implode(",",$sort_interfaces), ","); - // CSV String for Outbound Interfaces for 'pfB_' Match Rules - $pfb['outbound_floating'] = $implode_interfaces; - $pfb['outbound_interfaces_float'] = explode(" ",$implode_interfaces); - - // Assign Outbound Base Rule/Interfaces - if ($pfb['float'] == "on") { - $base_rule = $base_rule_float; - $pfb['outbound_interfaces'] = $pfb['outbound_interfaces_float']; - } else { - $base_rule = $base_rule_reg; - $pfb['outbound_interfaces'] = explode(",",$pfb['config']['outbound_interface']); - // If OpenVPN Interfaces are not in dropdown menu - if ($pfb['openvpn'] == "on" && $config['openvpn']['openvpn-server'] || $pfb['openvpn'] == "on" && $config['openvpn']['openvpn-client']) { - if (!in_array("openvpn",$sort_interfaces)) { - array_push($pfb['outbound_interfaces'], "openvpn"); + $interface_types = array('inbound' => 'inbound_interface', 'outbound' => 'outbound_interface'); + foreach ($interface_types as $pftype => $int_type) { + $int_type_s = "{$int_type}s"; // Add trailing 's' to variable name. + + // Define empty variable/array + $pfb["{$pftype}_interfaces_float"] = ''; + $pfb[$int_type_s] = array(); + + if (!empty($pfb['config'][$int_type])) { + // Sort interface array to match pfSense interface order to allow floating rules to populate. + $selected_interfaces = explode(',', $pfb['config'][$int_type]); + // Sort pfBlockerNG interface order to pfSense interface order + $sort_interfaces = array_intersect($ifaces, $selected_interfaces); + + // If OpenVPN interfaces are not in pfB interface dropdown menu + if ($pfb['openvpn'] == 'on' && $pftype == 'outbound') { + if ($config['openvpn']['openvpn-server'] || $config['openvpn']['openvpn-client']) { + if (!in_array('openvpn', $sort_interfaces)) { + array_push($sort_interfaces, 'openvpn'); + } + } + } + $implode_interfaces = ltrim(implode(',', $sort_interfaces), ','); + $pfb["{$pftype}_interfaces_float"] = explode(' ', $implode_interfaces); + + // CSV string for inbound interfaces for 'pfB_' match rules + $pfb["{$pftype}_floating"] = $implode_interfaces; + + // Assign base rule/interfaces + if ($pfb['float'] == 'on') { + // Define base firewall floating rules settings + $pfb['base_rule'] = $pfb['base_rule_float']; + $pfb[$int_type_s] = $pfb["{$pftype}_interfaces_float"]; + } else { + // Define base firewall rules settings + $pfb['base_rule'] = $pfb['base_rule_reg']; + $pfb[$int_type_s] = explode(',', $pfb['config'][$int_type]); + + // If OpenVPN interfaces are not in pfB interface dropdown menu + if ($pfb['openvpn'] == 'on' && $pftype == 'outbound') { + if ($config['openvpn']['openvpn-server'] || $pfb['openvpn'] == 'on' && $config['openvpn']['openvpn-client']) { + if (!in_array('openvpn', $sort_interfaces)) { + array_push($pfb["{$pftype}_interfaces"], 'openvpn'); + } + } } } } - } else { - // Define Empty Variable/Array - $pfb['outbound_interfaces_float'] = ""; - $pfb['outbound_interfaces'] = array(); } @@ -906,46 +2024,32 @@ function sync_package_pfblockerng($cron = "") { # Clear Removed Lists from Masterfiles # ################################################# - // Process to keep Masterfiles in Sync with Valid Lists from config.conf file. + // Process to keep Masterfiles in sync with valid Lists from config.conf file. $pfb['sync_master'] = TRUE; - // Don't execute this function when pfBlockerNG is Disabled and 'Keep Blocklists' is enabled. - if ($pfb['enable'] == "" && $pfb['keep'] == "on") { + // Don't execute this function when pfBlockerNG is disabled and 'keep blocklists' is enabled. + if ($pfb['enable'] == '' && $pfb['keep'] == 'on') { $pfb['sync_master'] = FALSE; } if ($pfb['sync_master']) { - $pfb['existing']['match']['type'] = "match"; - $pfb['existing']['permit']['type'] = "permit"; - $pfb['existing']['deny']['type'] = "deny"; - $pfb['existing']['native']['type'] = "native"; - $pfb['existing']['match']['folder'] = "{$pfb['matchdir']}"; - $pfb['existing']['permit']['folder'] = "{$pfb['permitdir']}"; - $pfb['existing']['deny']['folder'] = "{$pfb['denydir']}"; - $pfb['existing']['native']['folder'] = "{$pfb['nativedir']}"; - $pfb['actual']['match']['type'] = "match"; - $pfb['actual']['permit']['type'] = "permit"; - $pfb['actual']['deny']['type'] = "deny"; - $pfb['actual']['native']['type'] = "native"; - $pfb['actual']['match']['folder'] = "{$pfb['matchdir']}"; - $pfb['actual']['permit']['folder'] = "{$pfb['permitdir']}"; - $pfb['actual']['deny']['folder'] = "{$pfb['denydir']}"; - $pfb['actual']['native']['folder'] = "{$pfb['nativedir']}"; - - // Find all Enabled Continents Lists - foreach ($continents as $continent => $pfb_alias) { - if (is_array($config['installedpackages']['pfblockerng' . strtolower(preg_replace('/ /','',$continent))]['config']) && $pfb['enable'] == "on") { - $continent_config = $config['installedpackages']['pfblockerng' . strtolower(preg_replace('/ /','',$continent))]['config'][0]; - if ($continent_config['action'] != "Disabled") { - $cont_type = array ("countries4" => "_v4", "countries6" => "_v6"); + $m_action = array('Match_Both', 'Match_Inbound', 'Match_Outbound', 'Alias_Match'); + $p_action = array('Permit_Both', 'Permit_Inbound', 'Permit_Outbound', 'Alias_Permit'); + + // Find all enabled Continents lists + foreach ($pfb['continents'] as $continent => $pfb_alias) { + if (isset($config['installedpackages']['pfblockerng' . strtolower(str_replace(' ', '', $continent))]['config']) && $pfb['enable'] == 'on') { + $continent_config = $config['installedpackages']['pfblockerng' . strtolower(str_replace(' ', '', $continent))]['config'][0]; + if ($continent_config['action'] != 'Disabled') { + $cont_type = array('countries4' => '_v4', 'countries6' => '_v6'); foreach ($cont_type as $c_type => $vtype) { - if ($continent_config[$c_type] != "") { - // Set Parameters for 'Match', 'Permit', 'Native' and 'Deny' - if (in_array($continent_config['action'],array('Match_Both','Match_Inbound','Match_Outbound','Alias_Match'))) { + if (!empty($continent_config[$c_type])) { + // Set parameters for 'Match', 'Permit', 'Native' and 'Deny' actions. + if (in_array($continent_config['action'], $m_action)) { $pfb['existing']['match'][] = "{$pfb_alias}{$vtype}"; - } elseif (in_array($continent_config['action'],array('Permit_Both','Permit_Inbound','Permit_Outbound','Alias_Permit'))){ + } elseif (in_array($continent_config['action'], $p_action)){ $pfb['existing']['permit'][] = "{$pfb_alias}{$vtype}"; - } elseif ($continent_config['action'] == "Alias_Native") { + } elseif ($continent_config['action'] == 'Alias_Native') { $pfb['existing']['native'][] = "{$pfb_alias}{$vtype}"; } else { $pfb['existing']['deny'][] = "{$pfb_alias}{$vtype},"; // Add Trailing ',' @@ -956,112 +2060,102 @@ function sync_package_pfblockerng($cron = "") { } } - // Find all Enabled IPv4/IPv6 Lists - $list_type = array ("pfblockernglistsv4" => "_v4", "pfblockernglistsv6" => "_v6"); + // Find all enabled IPv4/IPv6 lists and DNSBL lists + // Find all enabled IPv4 'Custom List' header names and check if 'Emerging Threats Update' and 'Custom List Update' needs force updating + $list_type = array('pfblockernglistsv4' => '_v4', 'pfblockernglistsv6' => '_v6', 'pfblockerngdnsbl' => '_v4', 'pfblockerngdnsbleasylist' => '_v4'); foreach ($list_type as $ip_type => $vtype) { - if ($config['installedpackages'][$ip_type]['config'] != "" && $pfb['enable'] == "on") { - foreach ($config['installedpackages'][$ip_type]['config'] as $list) { - if (is_array($list['row']) && $list['action'] != "Disabled") { + if (!empty($config['installedpackages'][$ip_type]['config']) && $pfb['enable'] == 'on') { + foreach ($config['installedpackages'][$ip_type]['config'] as $key => $list) { + if (isset($list['row']) && $list['action'] != 'Disabled') { foreach ($list['row'] as $row) { - if ($vtype == "_v4") { - $pfb_alias = "{$row['header']}"; + if ($vtype == '_v4') { + $header = "{$row['header']}"; } else { - $pfb_alias = "{$row['header']}_v6"; + $header = "{$row['header']}_v6"; } - // Collect Enabled Lists - if ($row['url'] != "" && $row['state'] != "Disabled") { - // Set Parameters for 'Match', 'Permit', 'Native' and 'Deny' - if (in_array($list['action'],array('Match_Both','Match_Inbound','Match_Outbound','Alias_Match'))) { - $pfb['existing']['match'][] = "{$pfb_alias}"; - } elseif (in_array($list['action'],array('Permit_Both','Permit_Inbound','Permit_Outbound','Alias_Permit'))) { - $pfb['existing']['permit'][] = "{$pfb_alias}"; - } elseif ($list['action'] == "Alias_Native") { - $pfb['existing']['native'][] = "{$pfb_alias}"; + + // Collect enabled lists + if (!empty($row['url']) && $row['state'] != 'Disabled') { + if (in_array($list['action'], $m_action)) { + $pfb['existing']['match'][] = "{$header}"; + } elseif (in_array($list['action'], $p_action)) { + $pfb['existing']['permit'][] = "{$header}"; + } elseif ($list['action'] == 'Alias_Native') { + $pfb['existing']['native'][] = "{$header}"; + } elseif ($list['action'] == 'unbound') { + $pfb['existing']['dnsbl'][] = "{$header}"; } else { - $pfb['existing']['deny'][] = "{$pfb_alias},"; // Add Trailing ',' + $pfb['existing']['deny'][] = "{$header},"; // Add Trailing ',' } - } - } - } - } - } - } - // Find all Enabled IPv4 'Custom List' Header Names and Check if 'Emerging Threats Update' and 'Custom List Update' Needs Force Updating - $list_type = array ("pfblockernglistsv4" => "_v4", "pfblockernglistsv6" => "_v6"); - foreach ($list_type as $ip_type => $vtype) { - if ($config['installedpackages'][$ip_type]['config'] != "" && $pfb['enable'] == "on") { - $count = -1; - foreach ($config['installedpackages'][$ip_type]['config'] as $list) { - if (is_array($list['row']) && $list['action'] != "Disabled") { - $count++; - // Check if 'Emerging Threats Update' Needs Updating before next CRON Event. - if (is_array($list['row']) && $row['state'] != "Disabled" && $pfb['etupdate'] == "enabled" && $vtype == "_v4") { - foreach ($list['row'] as $row) { - $aliasname = $row['header']; - if ($row['format'] == "et") { - unlink_if_exists("{$pfb['denydir']}/{$aliasname}.txt"); - $config['installedpackages']['pfblockerngreputation']['config'][0]['et_update'] = "disabled"; - $pfb['cron_mod'] = TRUE; - break; + // Check if 'Emerging Threats' needs updating. + if ($pfb['etupdate'] == 'enabled' && strpos($row['url'], 'iprepdata.txt') !== FALSE) { + unlink_if_exists("{$pfb['denydir']}/{$header}.txt"); + $pfb_config['installedpackages']['pfblockerngreputation']['config'][0]['et_update'] = 'disabled'; + $pfb['conf_mod'] = TRUE; } } } } - // Collect Enabled Custom List Box Aliases - if (pfbng_text_area_decode($list['custom']) != "") { - if ($vtype == "_v4") { - $pfb_alias = "{$list['aliasname']}_custom"; + // Collect custom list box aliases + if (!empty($list['custom'])) { + if ($vtype == '_v4') { + $pfb_custom = "{$list['aliasname']}_custom"; } else { - $pfb_alias = "{$list['aliasname']}_custom_v6"; + $pfb_custom = "{$list['aliasname']}_custom_v6"; } - // Determine Folder Location for 'List' - if (in_array($list['action'],array('Match_Both','Match_Inbound','Match_Outbound','Alias_Match'))) { - $pfb['existing']['match'][] = "{$pfb_alias}"; + + // Determine folder location for 'list' + if (in_array($list['action'], $m_action)) { + $pfb['existing']['match'][] = "{$pfb_custom}"; $pfbfolder = "{$pfb['matchdir']}"; - } elseif (in_array($list['action'],array('Permit_Both','Permit_Inbound','Permit_Outbound','Alias_Permit'))) { - $pfb['existing']['permit'][] = "{$pfb_alias}"; + } elseif (in_array($list['action'], $p_action)) { + $pfb['existing']['permit'][] = "{$pfb_custom}"; $pfbfolder = "{$pfb['permitdir']}"; - } elseif ($list['action'] == "Alias_Native") { - $pfb['existing']['native'][] = "{$pfb_alias}"; + } elseif ($list['action'] == 'Alias_Native') { + $pfb['existing']['native'][] = "{$pfb_custom}"; $pfbfolder = "{$pfb['nativedir']}"; + } elseif ($list['action'] == 'unbound') { + $pfb['existing']['dnsbl'][] = "{$pfb_custom}"; + $pfbfolder = "{$pfb['dnsdir']}"; } else { - $pfb['existing']['deny'][] = "{$pfb_alias},"; // Add Trailing ',' + $pfb['existing']['deny'][] = "{$pfb_custom},"; // Add Trailing ',' $pfbfolder = "{$pfb['denydir']}"; } - // Determine if 'Custom List' Needs Force Updating before next CRON Event. - if ($list['custom_update'] == "enabled") { - unlink_if_exists("{$pfbfolder}/{$pfb_alias}.txt"); - // Uncheck 'Enabled' in List 'Custom_update' Setting - $config['installedpackages'][$ip_type]['config'][$count]['custom_update'] = "disabled"; - $pfb['cron_mod'] = TRUE; + + // Determine if 'Custom List' needs force updating before next CRON event. + if ($list['custom_update'] == 'enabled') { + unlink_if_exists("{$pfbfolder}/{$pfb_custom}.txt"); + // Uncheck 'enabled' in list 'custom_update' setting + $pfb_config['installedpackages'][$ip_type]['config'][$key]['custom_update'] = 'disabled'; + $pfb['conf_mod'] = TRUE; } } } } } - // Collect all .txt file Names for each List Type - $list_types = array('match' => $pfb['matchdir'], 'permit' => $pfb['permitdir'], 'deny' => $pfb['denydir'], 'native' => $pfb['nativedir']); - foreach ($list_types as $type => $pfbfolder) { + // Collect all .txt file names for each list type + $list_types = array( 'match' => $pfb['matchdir'], 'permit' => $pfb['permitdir'], 'deny' => $pfb['denydir'], + 'native' => $pfb['nativedir'], 'dnsbl' => $pfb['dnsdir']); + + foreach ($list_types as $pftype => $pfbfolder) { $pfb_files = glob("$pfbfolder/*.txt"); foreach ($pfb_files as $pfb_list) { - $pfb_file = basename($pfb_list,".txt"); - if ($type == "deny") { - $pfb['actual'][$type][] = "{$pfb_file},"; // Add Trailing ',' + $pfb_file = basename($pfb_list, '.txt'); + if ($pftype == 'deny') { + $pfb['actual'][$pftype][] = "{$pfb_file},"; // Add Trailing ',' } else { - $pfb['actual'][$type][] = "{$pfb_file}"; + $pfb['actual'][$pftype][] = "{$pfb_file}"; } } } - // Flag to execute pfctl and Rules Ordering - $pfb['remove'] = FALSE; - // Execute Final Summary as a List was Removed - $pfb['summary'] = FALSE; + $pfb['remove'] = FALSE; // Flag to execute pfctl and rules ordering or reload of DNSBL domains + $pfb['summary'] = FALSE; // Execute final summary as a list was removed - // Process to Remove Lists from Masterfile/DB Folder if they do not Exist + // Process to remove lists from Masterfile/DB folder if they do not exist if (isset($pfb['existing'])) { foreach ($pfb['existing'] as $pfb_exist) { $existing_type = $pfb_exist['type']; @@ -1070,51 +2164,74 @@ function sync_package_pfblockerng($cron = "") { $actual_type = $pfb_act['type']; if ($existing_type == $actual_type) { switch ($existing_type) { - case "deny": + case 'deny': $results = array_diff($pfb_act, $pfb_exist); $f_result = implode($results); - if ($f_result != "") { + if (!empty($f_result)) { $log = "[ Removing List(s) : {$f_result} ]\n"; - pfb_logger("{$log}","1"); + pfb_logger("{$log}", 1); // Script to Remove un-associated Lists - exec ("{$pfb['script']} remove x x x {$f_result} >> {$pfb['log']} 2>&1"); - $pfb['summary'] = TRUE; - $pfb['remove'] = TRUE; + exec("{$pfb['script']} remove x x x {$f_result} {$elog}"); + $pfb['summary'] = $pfb['remove'] = TRUE; } break; - case "match": - case "permit": - case "native": + case 'match': + case 'permit': + case 'native': $results = array_diff($pfb_act, $pfb_exist); // This variable ($f_result) used in next section below. $f_result = implode($results); if (!empty($results)) { foreach ($results as $pfb_result) { - $log = "[ Removing List : {$pfb_result} ]\n"; - pfb_logger("{$log}","1"); + $log = "[ Removing List(s) : {$pfb_result} ]\n"; + pfb_logger("{$log}", 1); unlink_if_exists("{$pfbfolder}/{$pfb_result}.txt"); } - $pfb['summary'] = TRUE; - $pfb['remove'] = TRUE; + $pfb['summary'] = $pfb['remove'] = TRUE; } break; + case 'dnsbl': + $dresults = array_diff($pfb_act, $pfb_exist); + if (!empty($dresults)) { + foreach ($dresults as $pfb_result) { + $log = "[ Removing List(s) : {$pfb_result} ]\n"; + pfb_logger("{$log}", 1); + rmdir_recursive("{$pfb['dnsdir']}"); + safe_mkdir("{$pfb['dnsdir']}"); + } + + // Query for any active pfBlockerNG CRON jobs + $result_cron = array(); + exec('/bin/ps -wax', $result_cron); + if (preg_grep("/pfblockerng[.]php\s+?(cron|update)/", $result_cron)) { + $log = "\n ** DNSBL Reload Terminated due to active pfBlockerNG cron process\n"; + pfb_logger("{$log}", 1); + } else { + if ($pfb['enable'] == 'on' && $pfb['dnsbl'] == 'on') { + pfb_logger("\n ** Running Background Reload Task\n", 1); + // Clear any existing pfBlockerNG Cron Jobs to avoid collision + install_cron_job('pfblockerng.php cron', false); + $cmd = "/usr/local/bin/php /usr/local/www/pfblockerng/pfblockerng.php"; + mwexec_bg("${cmd} updatednsbl >> {$pfb['log']} 2>&1"); + } + } + } } // Allow rebuilding of changed Alias to purge 'SKIP' Lists (when pfBlockerNG is enabled) - $list_type = array ("pfblockernglistsv4" => "_v4", "pfblockernglistsv6" => "_v6"); - foreach ($list_type as $ip_type => $vtype) { - if ($f_result != "" && $pfb['enable'] == "on") { + if (!empty($results) && $pfb['enable'] == 'on') { + $list_type = array('pfblockernglistsv4' => '_v4', 'pfblockernglistsv6' => '_v6'); + foreach ($list_type as $ip_type => $vtype) { foreach ($results as $removed_header) { - if ($config['installedpackages'][$ip_type]['config'] != "") { + if (isset($config['installedpackages'][$ip_type]['config'])) { foreach ($config['installedpackages'][$ip_type]['config'] as $list) { - $alias = "pfB_" . preg_replace("/\W/","",$list['aliasname']); - if (is_array($list['row'])) { + $alias = 'pfB_' . preg_replace("/\W/", '', $list['aliasname']); + if (!empty($list['row'])) { foreach ($list['row'] as $row) { $removed = rtrim($removed_header, ','); if ($row['header'] == $removed) { - $pfb['summary'] = TRUE; - $pfb['remove'] = TRUE; - // Add Alias to Update Array + $pfb['summary'] = $pfb['remove'] = TRUE; + // Add Alias to update array $pfb_alias_lists[] = "{$alias}"; $pfb_alias_lists_all[] = "{$alias}"; } @@ -1136,19 +2253,23 @@ function sync_package_pfblockerng($cron = "") { ######################################################### // When pfBlockerNG is Disabled and 'Keep Blocklists' is Disabled. - if ($pfb['enable'] == "" && $pfb['keep'] == "" && !$pfb['install']) { + if ($pfb['enable'] == '' && $pfb['keep'] == '' && !$pfb['install']) { $log = "\n Removing DB Files/Folders \n"; - pfb_logger("{$log}","1"); + pfb_logger("{$log}", 1); unlink_if_exists("{$pfb['dbdir']}/masterfile"); unlink_if_exists("{$pfb['dbdir']}/mastercat"); unlink_if_exists("{$pfb['supptxt']}"); + unlink_if_exists("{$pfb['dnsbl_info']}"); rmdir_recursive("{$pfb['origdir']}"); rmdir_recursive("{$pfb['matchdir']}"); rmdir_recursive("{$pfb['permitdir']}"); rmdir_recursive("{$pfb['denydir']}"); rmdir_recursive("{$pfb['nativedir']}"); rmdir_recursive("{$pfb['etdir']}"); + rmdir_recursive("{$pfb['dnsdir']}"); + rmdir_recursive("{$pfb['dnsorigdir']}"); + rmdir_recursive("{$pfb['dnsalias']}"); } @@ -1156,271 +2277,939 @@ function sync_package_pfblockerng($cron = "") { # Create IP Suppression Txt File # ################################################# - if ($pfb['enable'] == "on" && $pfb['supp'] == "on") { + if ($pfb['enable'] == 'on' && $pfb['supp'] == 'on') { pfb_create_suppression_file(); } + ######################################### + # DNSBL - Processes # + ######################################### + + if ($pfb['dnsbl'] == 'on' && !$pfb['save']) { + // Terminate if DNSBL VIP is empty + $dnsbl_error = FALSE; + if (empty($pfb['dnsbl_vip']) || empty($pfb['dnsbl_port']) || empty($pfb['dnsbl_port_ssl'])) { + $log = "\n\n===[ DNSBL Virtual IP and/or Ports are not defined. Exiting ]======\n"; + pfb_logger("{$log}", 1); + $dnsbl_error = TRUE; + } + } + + if ($pfb['dnsbl'] == 'on' && !$pfb['save'] && !$dnsbl_error) { + $log = "\n===[ DNSBL Process ]================================================\n"; + pfb_logger("{$log}", 1); + + if (isset($config['installedpackages']['pfblockerngdnsbl']['config']) || isset($config['installedpackages']['pfblockerngdnsbleasylist']['config'])) { + + // Collect existing DNSBL alias statistics + // CSV file format [ alias name , updated timestamp , total domain count, total blocked count ] + if (file_exists("{$pfb['dnsbl_info']}")) { + $dnsbl_info = array_map('str_getcsv', @file("{$pfb['dnsbl_info']}")); + } else { + $dnsbl_info = array(); + } + + // Rebuild DNSBL database or DNSBL statistics if files are not found + if (!file_exists("{$pfb['dnsbl_file']}.conf") || !file_exists($pfb['dnsbl_info'])) { + $log = "Missing DNSBL stats and/or Unbound DNSBL conf file - Rebuilding\n"; + pfb_logger("{$log}", 1); + $pfb['reuse_dnsbl'] = 'on'; + } + + // Collect suppression list + $pfb_dnssupp = array(); + if (!empty($pfb['dnsblconfig']['suppression'])) { + $pfb_dnssupp = explode("\n", pfbng_text_area_decode($pfb['dnsblconfig']['suppression'])); + } + + // Call Alexa whitelist process + if ($pfb['dnsbl_alexa'] == 'on') { + // Check if Alexa database exists + if (!file_exists("{$pfb['dbdir']}/top-1m.csv")) { + // Check if Alexa download already in progress + exec('/bin/ps -wax', $result_cron); + if (!preg_grep("/pfblockerng[.]php\s+al/", $result_cron)) { + $log = "\nAlexa Database downloading ( approx 21M ) ... Please wait ...\n"; + pfb_logger("{$log}", 1); + exec("/usr/local/bin/php /usr/local/www/pfblockerng/pfblockerng.php al"); + } + else { + $log = "\nAlexa download already in process...\n"; + pfb_logger("{$log}", 1); + } + } + + // Process Alexa database + pfblockerng_alexa(); + } + + // Collect feeds and custom list configuration and format into one array ($lists). + $lists = array(); + if (isset($config['installedpackages']['pfblockerngdnsbl']['config'])) { + foreach ($config['installedpackages']['pfblockerngdnsbl']['config'] as $list) { + // If only the 'customlist' is defined. Remove the 'List row' data. + if (empty($list['row'][0]['url'])) { + unset($list['row']); + } + + if (!empty($list['custom'])) { + $list['row'][] = array( 'header' => "{$list['aliasname']}_custom", + 'custom' => $list['custom'], + 'state' => 'Enabled', + 'update' => $list['custom_update'], + 'url' => 'custom' + ); + } + $lists[] = $list; + } + } + + // Add DNSBL EasyList to '$lists array' + if (!empty($config['installedpackages']['pfblockerngdnsbleasylist']['config'])) { + foreach($config['installedpackages']['pfblockerngdnsbleasylist']['config'] as $list) { + $lists[] = $list; + } + } + + // Define DNSBL arrays and variables + $alias_dnsbl_all = array(); // Array of all DNSBL aliases + $pfb['domain_update'] = FALSE; // Flag to signal update Unbound + + foreach ($lists as $list) { + + // Reset variables once per alias + $lists_dnsbl_current = array(); // Array of all active Lists in current alias + $pfb['aliasupdate'] = FALSE; // Flag to signal changes to alias + $pfb['updateip'] = FALSE; // Flag to signal updates to DNSBL IP lists + $alias_cnt = 0; + + if ($list['action'] != 'Disabled' && isset($list['row'])) { + $alias = 'DNSBL_' . preg_replace("/\W/", '', $list['aliasname']); + $alias_dnsbl_all[] = "{$alias}"; + foreach ($list['row'] as $key => $row) { + if (!empty($row['url']) && $row['state'] != 'Disabled') { + + $header = "{$row['header']}"; + $liteparser = FALSE; // Minimal DNSBL Parser + $domain_data_ip = array(); // Array of IPs found in feed + $domain_data = ''; // List of Domains found in feed + + // If row is a custom_list, set flag. + if (isset($row['custom'])) { + $custom = TRUE; + } else { + $custom = FALSE; + } + + // EasyList - collect enabled EasyList categories + if (isset($list['easycat']) && !isset($easylist)) { + $easylist = explode(',', $list['easycat']); + } + + // Determine 'list' details (return array $pfbarr) + pfb_determine_list_detail($list['action'], $header, 'pfblockerngdnsblsettings', '0'); + $pfbadv = $pfbarr['adv']; + $pfbfolder = $pfbarr['folder']; + $pfborig = $pfbarr['orig']; + $pfbreuse = $pfbarr['reuse']; + $logtab = $pfbarr['logtab']; + $aports = $pfbarr['aports']; + $adest = $pfbarr['adest']; + $aproto = $pfbarr['aproto']; + + // Empty header field validation check + if (empty($header)) { + $log = "\n[ {$row['url']} ]{$logtab} Header Field cannot be empty. *Skipping* \n"; + pfb_logger("{$log}", 2); + continue; + } + + if (file_exists("{$pfbfolder}/{$header}.txt") && $pfbreuse == '') { + if ($row['state'] == 'Hold') { + $log = "\n[ {$header} ]{$logtab} Static Hold [ NOW ]"; + } else { + $log = "\n[ {$header} ]{$logtab} exists, Reloading [ NOW ]"; + } + pfb_logger("{$log}", 1); + + // Collect existing list stats + $lists_dnsbl_all[] = "{$row['header']}"; + $lists_dnsbl_current[] = "{$row['header']}"; + $list_cnt = exec("{$pfb['grep']} -c ^ {$pfbfolder}/{$header}.txt"); + $alias_cnt = $alias_cnt + $list_cnt; + + } else { + if ($pfbreuse == 'on' && file_exists("{$pfborig}/{$header}.orig")) { + $log = "\n[ {$header} ]{$logtab} Reload [ NOW ]"; + } else { + $log = "\n[ {$header} ]{$logtab} Downloading update [ NOW ]"; + } + pfb_logger("{$log}", 1); + $file_dwn = "{$pfborig}/{$header}"; + + if (!$custom) { + pfb_logger(' .', 1); + + // Allow cURL SSL downgrade 'Flex' if user configured. + $pflex = FALSE; + if ($row['state'] == 'Flex') { + $pflex = TRUE; + } + + // Determine if list needs to be downloaded or reuse previously downloaded file. + if ($pfbreuse == 'on' && file_exists("{$file_dwn}.orig")) { + // File exists/reuse + pfb_logger(' completed .', 1); + } else { + // Download file + if (!pfb_download($row['url'], $file_dwn, $pflex, $header, + $row['format'], 1, '')) { + + // Determine reason for download failure + pfb_download_failure($alias, $header, $pfbfolder, + $list['vtype'], $row['url']); + + // Utilize previously download file (If 'fail' marker exists) + if (file_exists("{$pfbfolder}/{$header}.fail") && + file_exists("{$file_dwn}.orig")) { + pfb_logger("\n Restoring previously downloaded file\n ", 2); + } else { + continue; + } + } + else { + // Clear any previous download fail marker + unlink_if_exists("{$pfbfolder}/{$header}.fail"); + } + } + } + else { + // Collect custom list data. + $custom_list = pfbng_text_area_decode($row['custom']); + @file_put_contents("{$file_dwn}.orig", $custom_list, LOCK_EX); + unset($custom_list); + $liteparser = TRUE; + } + + // Parse downloaded file for Domain names + + $e_skip = $e_found = FALSE; // Variables for Easylists + $fail_list = ''; $csvfail = $ipcount = $ip_cnt = 0; + if (($fhandle = fopen("{$file_dwn}.orig", 'r')) !== FALSE) { + while (($line = fgets($fhandle, 3072)) !== FALSE) { + + // On 'category match', parse EasyList feed + if (isset($easylist)) { + if (substr($line, 24, 19) == 'easylist_adservers.' || + substr($line, 27, 28) == 'easyprivacy_trackingservers.') { + $e_found = TRUE; + } + } + else { + if (strpos($line, '[Adblock Plus ') !== FALSE) { + pfb_logger("\n\n Terminated - Easylists can not be used.\n", 1); + break; + } + } + + // Skip unuseable EasyList lines + if (isset($easylist) && !$e_found) { + continue; + } + + // Remove any '^M' characters + if (strpos($line, "\r") !== FALSE) { + $line = preg_replace(array("/\^M\s+/", "/\^M/"), '', $line); + } + + // If 'tab' character found, replace with whitespace + if (strpos($line, "\x09") !== FALSE) { + $line = str_replace("\x09", ' ', $line); + } + + // If '%20' found, remove. + if (strpos($line, '%20') !== FALSE) { + $line = str_replace('%20', '', $line); + } + + // If 'http(s)://' found, remove. + if (strpos($line, 'http://') !== FALSE || strpos($line, 'https://') !== FALSE) { + $line = preg_replace("(^https?://)", '', $line); + } + + // Remove any leading/trailing whitespaces + $line = trim($line); + + // Remove blank lines + if (empty($line)) { + continue; + } + + // Remove comment lines and special format considerations + if (substr($line, 0, 1) == '#') { + // Exit (hpHosts) when end of domain names found. + if (strpos($line, 'Append critical updates below') !== FALSE) { + break; + } + + // Spamhaus format validation + if (strpos($line, 'The Spamhaus Project Ltd') !== FALSE) { + $liteparser = TRUE; + } + continue; + } + + // Convert CSV line into array + if (!isset($easylist) && substr_count($line, ',') >= 2) { + $csvline = str_getcsv($line, ',', '', '"'); + } else { + $csvline = ''; + } + + // CSV parser + if (!isset($easylist) && count($csvline) >= 2) { + // Parse Phishtank CSV + if (strpos($csvline[2], 'www.phishtank.com/phish_detail.php') !== FALSE) { + $liteparser = TRUE; + if (count($csvline) == 8) { + $host = parse_url($csvline[1]); + $line = $host['host']; + } else { + //Record Failed attemps + $csvfail++; + $fail_list .= $line . '|'; + continue; + } + } + + // Parse Bambenek Consulting domain list + elseif (strpos($csvline[3], 'osint.bambenekconsulting.com') !== FALSE) { + $liteparser = TRUE; + if (count($csvline) == 4) { + $line = $csvline[0]; + } else { + //Record Failed attemps + $csvfail++; + $fail_list .= $line . '|'; + continue; + } + } + + // Parse ET IQRisk IPRep domain list + elseif (!strpos($csvline[2], 'www.phishtank.com/phish_detail.php')){ + if (strpos($csvline[1], '.') !== FALSE && + (int)$csvline[1] != 0 && count($csvline) == 3) { + $liteparser = TRUE; + $line = $csvline[0]; + } + } + } + $line = trim($line); + + // Parser for EasyList, enable collect of selected EasyList categories + if (isset($easylist) && strpos($line, '! *** easylist:') !== FALSE) { + // Skip all previous Easylist entries + + // Collect EasyList feed + if (substr($line, 24, 19) == 'easylist_adservers.') { + if (in_array('ea', $easylist) ? $e_skip = FALSE : $e_skip = TRUE); + } + elseif (substr($line, 24, 25) == 'easylist_adservers_popup.') { + if (in_array('eap', $easylist) ? $e_skip = FALSE : $e_skip = TRUE); + } + elseif (substr($line, 30, 16) == 'adult_adservers.') { + if (in_array('aa', $easylist) ? $e_skip = FALSE : $e_skip = TRUE); + } + elseif (substr($line, 30, 22) == 'adult_adservers_popup.') { + if (in_array('aap', $easylist) ? $e_skip = FALSE : $e_skip = TRUE); + } + + // Collect EasyPrivacy feed + elseif (substr($line, 27, 28) == 'easyprivacy_trackingservers.') { + if (in_array('epts', $easylist) ? $e_skip = FALSE : $e_skip = TRUE); + } + elseif (substr($line, 27, 42) == 'easyprivacy_trackingservers_international.') { + if (in_array('epti', $easylist) ? $e_skip = FALSE : $e_skip = TRUE); + } + + // End of useable EasyList feed + elseif (substr($line, 24, 20) == 'easylist_thirdparty.') { + break; + } + // End of useable EasyPrivacy feed + elseif (substr($line, 27, 23) == 'easyprivacy_thirdparty.') { + break; + } + } + + // Parse EasyList line + if (isset($easylist)) { + if (!$e_skip) { + if (substr($line, 0, 2) != '||') { + continue; + } + if (strpos($line, '^$') !== FALSE) { + $line = trim(str_replace('|', '', strstr($line, '^$', TRUE))); + } + elseif (strpos($line, '^*') !== FALSE) { + $line = trim(str_replace('|', '', strstr($line, '^*', TRUE))); + } + else { + continue; + } + if (strpos($line, '/') !== FALSE) { + $line = strstr($line, '/', TRUE); + } + if (strpos($line, '*.') !== FALSE) { + $line = substr(strrchr($line, '*.'), 2); + } + $liteparser = TRUE; + } + else { + continue; + } + } + + // Parser for all other domain feeds (Initial line preparation) + if (!$liteparser) { + // If 'space' character found, remove characters before space + if (strpos($line, ' ') !== FALSE) { + $line = strstr($line, ' ', FALSE); + } + + // If '#' character found, remove characters after '#' + if (strpos($line, '#') !== FALSE) { + $line = strstr($line, '#', TRUE); + } + + // Remove any leading/trailing whitespaces + $line = trim($line); + + // If 'space' character found, remove characters after space + if (strpos($line, ' ') !== FALSE) { + $line = strstr($line, ' ', TRUE); + } + + // If '/' character found, remove characters after '/' + if (strpos($line, '/') !== FALSE) { + $line = strstr($line, '/', TRUE); + } + } else { + // If 'space' character found, remove characters after space + if (strpos($line, ' ') !== FALSE) { + $line = strstr($line, ' ', TRUE); + } + + // Remove any leading/trailing whitespaces + $line = trim($line); + } + + // If special characters found, parse line for host + if ((strpos($line, ';') !== FALSE || strpos($line, '&') !== FALSE || + strpos($line, '?') !== FALSE || strpos($line, ":") !== FALSE)) { + $host = parse_url($line); + $line = $host['host']; + } + + // Collect any IPs found in domain feed + if (is_ipaddrv4($line)) { + if ($pfb['dnsbl_ip'] != 'Disabled') { + $parsed = sanitize_ipaddr($line, $custom); + if (validate_ipv4($parsed)) { + $domain_data_ip[] = $parsed; + $pfb['updateip'] = TRUE; + $ipcount++; + } + } + continue; + } + + // Remove invalid domains + if (strpos($line, '.') === FALSE || substr($line, -1) == '.' || + substr($line, 0, 1) == '.' || strpos($line, '..') !== FALSE) { + continue; + } + + // Remove suppressed domain names + if (!in_array($line, $pfb_dnssupp)) { + $domain_data .= "local-data: \"" . $line . " 60 IN A {$pfb['dnsbl_vip']}\"\n"; + } + } + } + fclose($fhandle); + unset($csvline, $easylist); // Unset variables + + // Remove duplicates and save any IPs found in domain feed + if (!empty($domain_data_ip)) { + $domain_data_ip = implode("\n", array_unique($domain_data_ip)) . "\n"; + @file_put_contents("{$pfbfolder}/{$header}.ip", $domain_data_ip, LOCK_EX); + $ip_cnt = exec("{$pfb['grep']} -c ^ {$pfbfolder}/{$header}.ip"); + } + + // Validate feed with Unbound-checkconf + if (!empty($domain_data)) { + $dnsbl_file = "{$pfbfolder}/{$header}"; + + $conf = "server:\n"; + $conf .= "chroot: {$pfb['dnsbldir']}\n"; + $conf .= "username: \"unbound\"\n"; + $conf .= "directory: \"{$pfb['dnsbldir']}\"\n"; + $conf .= "pidfile: \"/var/run/unbound.pid\"\n"; + $conf .= "server:include: {$dnsbl_file}.bk"; + @file_put_contents("{$pfb['dnsbldir']}/check.conf", $conf, LOCK_EX); + + @file_put_contents("{$dnsbl_file}.bk", $domain_data, LOCK_EX); + pfb_logger('.', 1); + + // Bypass Alexa whitelist if user configured + if ($list['filter_alexa'] == 'on' && file_exists("{$pfb['dbdir']}/pfbalexawhitelist.txt")) { + $pfb_alexa = 'on'; + } else { + $pfb_alexa = 'Disabled'; + } + + // Call script to process domain de-duplication/Alexa whitelisting + exec("{$pfb['script']} domainduplicate {$header} {$pfb_alexa} {$elog}"); + + if ($ip_cnt > 0) { + $log = "IP count={$ip_cnt}\n"; + pfb_logger("{$log}", 1); + } + + $result = array(); + exec("/usr/local/sbin/unbound-checkconf {$pfb['dnsbldir']}/check.conf 2>&1", $result); + @unlink_if_exists("{$pfb['dnsbldir']}/check.conf"); + } + else { + $log = "\n No Domains Found\n"; + pfb_logger("{$log}", 1); + continue; + } + + // Exit further processing of feed if parse error found. + if (!preg_grep("/unbound-checkconf: no errors/", $result)) { + @unlink_if_exists("{$dnsbl_file}.bk"); + $log = "\n[ DNSBL FAIL ] [ Skipping : {$row['header']} ]\n\n"; + pfb_logger("{$log}", 2); + $log = htmlspecialchars(implode("\n", $result)); + pfb_logger("{$log}", 1); + continue; + } + else { + // Save DNSBL feed + $pfb['domain_update'] = $pfb['aliasupdate'] = $pfb['summary'] = TRUE; + $lists_dnsbl_all[] = "{$row['header']}"; + $lists_dnsbl_current[] = "{$row['header']}"; + @rename("{$dnsbl_file}.bk", "{$dnsbl_file}.txt"); + $list_cnt = exec("{$pfb['grep']} -c ^ {$dnsbl_file}.txt"); + $alias_cnt = $alias_cnt + $list_cnt; + + // Print failed domain parsing info + if ($csvfail > 0) { + $log = " * Failed Lines: {$csvfail}\n |{$fail_list}\n\n"; + pfb_logger("{$log}", 1); + } + } + } + } + } + + // If changes found update DNSBL alias + if ($pfb['aliasupdate']) { + + // Create master alias file + $pfb_output = fopen("{$pfb['dnsalias']}/{$alias}", 'w'); + foreach ($lists_dnsbl_current as $clist) { + if (($handle = fopen("{$pfbfolder}/{$clist}.txt", 'r')) !== FALSE) { + while (($line = fgets($handle, 3072)) !== FALSE) { + fwrite($pfb_output, $line); + } + } + fclose($handle); + } + fclose($pfb_output); + + // Update domain alias statistics + $dns_now = date('M d G:i', time()); + $pfbfound = FALSE; + foreach ($dnsbl_info as $key => $line) { + // Update existing alias stats + if ($line[0] == "{$alias}") { + $pfbfound = TRUE; + $dnsbl_info[$key][1] = "{$dns_now}"; + $dnsbl_info[$key][2] = "{$alias_cnt}"; + break; + } + } + + if (!$pfbfound) { + $dnsbl_info[] = explode(',', "{$alias},{$dns_now},{$alias_cnt},0"); + } + } + } + else { + // Record disabled alias statistics + $pfbfound = FALSE; + if (!empty($dnsbl_info)) { + foreach ($dnsbl_info as $line) { + if ($line[0] == "{$alias}") { + $pfbfound = TRUE; + break; + } + } + } + if (!$pfbfound) { + $dns_now = date('M d G:i', time()); + $dnsbl_info[] = explode(',', "{$alias},{$dns_now},disabled,0"); + } + } + } + + } + + // Remove any unused DNSBL aliases + $daliases = glob("{$pfb['dnsalias']}/*"); + if (!empty($daliases)) { + foreach ($daliases as $dlist) { + if (!in_array(basename($dlist), $alias_dnsbl_all)) { + unlink_if_exists ("{$dlist}"); + } + } + } + + // Save alias statistics to file (Remove any feeds that are not referenced) + $handle = fopen("{$pfb['dnsbl_info']}", 'w'); + fwrite($handle, "# Keeping this file open in a file editor will interrupt DNSBL!\n"); + foreach ($dnsbl_info as $alias) { + if (in_array($alias[0], $alias_dnsbl_all)) { + fputcsv($handle, $alias); + } + } + fclose($handle); + } + + // Create DNSBL firewall rules/alias if action permits + if ($pfb['enable'] == 'on' && $pfb['dnsbl'] == 'on' && $pfb['dnsbl_ip'] != 'Disabled') { + $new_aliases[] = array( 'name' => 'pfB_DNSBLIP', + 'url' => "{$pfb['weblocal']}?pfb=pfB_DNSBLIP", + 'updatefreq' => '32', + 'address' => '', + 'descr' => 'pfBlockerNG auto DNSBL IP Alias', + 'type' => 'urltable', + 'detail' => 'DO NOT EDIT THIS ALIAS' + ); + + // Determine 'list' details (return array $pfbarr) + pfb_determine_list_detail($list['action'], $header, 'pfblockerngdnsblsettings', '0'); + + // Define DNSBL_IP firewall rule settings + if ($pfb['dnsbl_ip'] != 'Alias_Deny') { + pfb_firewall_rule($pfb['dnsbl_ip'], 'pfB_DNSBLIP', '', $pfb['dnsblconfig']['aliaslog'], + $pfbarr['adest'], $pfbarr['aports'], $pfbarr['aproto'], $pfb['dnsblconfig']['autonot']); + } + + // Collect DNSBL IP addresses into 'pfB_DNSBLIP' aliastable + $dnsbl_ip = glob("{$pfb['dnsdir']}/*.ip"); + if (!empty($dnsbl_ip)) { + if ($pfb['updateip'] || !file_exists("{$pfb['aliasdir']}/pfB_DNSBLIP.txt")) { + $pfb_ips = fopen("{$pfb['aliasdir']}/pfB_DNSBLIP.txt", 'w'); + foreach ($dnsbl_ip as $d_ip) { + if (($handle = fopen("{$d_ip}", 'r')) !== FALSE) { + while (($line = fgets($handle, 1024)) !== FALSE) { + fwrite($pfb_ips, $line); + } + } + fclose($handle); + } + fclose($pfb_ips); + } + + // Update DNSBL_IPs aliastable + if ($pfb['updateip'] && file_exists("{$pfb['aliasdir']}/pfB_DNSBLIP.txt")) { + $result = ''; + $list_cnt = exec("{$pfb['grep']} -c ^ {$pfb['aliasdir']}/pfB_DNSBLIP.txt"); + exec("{$pfb['pfctl']} -t pfB_DNSBLIP -T replace -f {$pfb['aliasdir']}/pfB_DNSBLIP.txt 2>&1", $result); + + $log = "\n[ DNSBL_IP ]\t\t Updating aliastable [ NOW ]\n------------------------------------------\n"; + $log .= implode($result); + + $log .= "\nTotal IP count = {$list_cnt}\n------------------------------------------"; + pfb_logger("{$log}", 1); + } + } + else { + // Flush DNSBL IPs aliastable when empty + exec("{$pfb['pfctl']} -t pfB_DNSBLIP -T flush 2>&1", $result); + // Add empty placeholder '1.1.1.1' to aliastable + exec("{$pfb['pfctl']} -t pfB_DNSBLIP -T add 1.1.1.1"); + @file_put_contents("{$pfb['aliasdir']}/pfB_DNSBLIP.txt", "1.1.1.1\n", LOCK_EX); + } + } + else { + // Remove 'DNSBLIP' aliastable and files + exec("{$pfb['pfctl']} -t pfB_DNSBLIP -T kill 2>&1", $result); + unlink_if_exists("{$pfb['aliasdir']}/pfB_DNSBLIP.txt"); + } + + ######################################### + # UPDATE Unbound DNS Database # + ######################################### + + if ($pfb['domain_update']) { + if (!empty($lists_dnsbl_all)) { + pfb_logger("\n\n------------------------------------------\nAssembling database...", 1); + $pfb_output = fopen("{$pfb['dnsbl_file']}.raw", 'w'); + foreach ($lists_dnsbl_all as $current_list) { + if (($handle = fopen("{$pfb['dnsdir']}/{$current_list}.txt", 'r')) !== FALSE) { + while (($line = fgets($handle, 3072)) !== FALSE) { + fwrite($pfb_output, $line); + } + } + fclose($handle); + } + fclose($pfb_output); + + // Perform sort and uniq on DNSBL database File. Validation of file required before use. + exec("{$pfb['cat']} {$pfb['dnsbl_file']}.raw | /usr/bin/sort | /usr/bin/uniq > {$pfb['dnsbl_file']}.tmp && /bin/rm -f {$pfb['dnsbl_file']}.raw"); + } + else { + $log = "\nDNSBL not Updated!\n"; + pfb_logger("{$log}", 1); + } + } + + + ################################# + # UNBOUND INTEGRATION # + ################################# + + $pfbupdate = FALSE; + if (file_exists("{$pfb['dnsbldir']}/unbound.conf")) { + $conf = file("{$pfb['dnsbldir']}/unbound.conf"); + } + + if ($pfb['enable'] == 'on' && $pfb['dnsbl'] == 'on' && $pfb['unbound_state'] == 'on') { + // If new domain updates found, backup existing DNSBL domain feed + if ($pfb['domain_update']) { + if (file_exists ("{$pfb['dnsbl_file']}.conf")) { + @copy("{$pfb['dnsbl_file']}.conf", "{$pfb['dnsbl_file']}.bk"); + } + @rename("{$pfb['dnsbl_file']}.tmp", "{$pfb['dnsbl_file']}.conf"); + @file_put_contents("{$pfb['dnsbldir']}/unbound.tmp", $conf, LOCK_EX); + } + + // Add 'include:' line in Unbound conf file if not found + if (isset($conf) && !strstr(implode($conf), 'pfb_dnsbl.conf')) { + if (file_exists("{$pfb['dnsbl_file']}.conf")) { + $log = " Adding Unbound Server:Include line..."; + pfb_logger("{$log}", 1); + + $pfbupdate = TRUE; + $conf[] = "# Unbound custom options\n\nserver:include: {$pfb['dnsbl_file']}.conf\n"; + @file_put_contents("{$pfb['dnsbldir']}/unbound.tmp", $conf, LOCK_EX); + } + } + + // Validate new Unbound conf file before use. + if ($pfb['domain_update'] || $pfbupdate) { + pfb_validate_unbound('enabled'); + } + + // Create DNSBL NAT and VIP and lighttpd web server conf if required. + pfb_create_dnsbl('enable'); + } + else { + // When DNSBL is disabled and not during an installation. + if ($pfb['dnsbl'] == '' && !$pfb['install']) { + // Remove 'Unbound' conf integration + if (isset($conf) && stripos(implode($conf), 'pfb_dnsbl.conf') !== FALSE) { + $pfbupdate = FALSE; + foreach ($conf as $key => $line) { + if (strpos($line, 'pfb_dnsbl.conf') !== FALSE) { + $pfbupdate = TRUE; + unset ($conf[$key]); + } + } + if ($pfbupdate) { + @file_put_contents("{$pfb['dnsbldir']}/unbound.tmp", $conf, LOCK_EX); + // Validate new Unbound conf file before use. + pfb_validate_unbound('disabled'); + } + } + + // Remove DNSBL NAT, VIP and lighttpd service + pfb_create_dnsbl('disable'); + + // Remove 'DNSBL_IPs' aliastable + exec("{$pfb['pfctl']} -t pfB_DNSBLIP -T kill 2>&1", $result); + unlink_if_exists("{$pfb['aliasdir']}/pfB_DNSBLIP.txt"); + } + + + // Use applicable log message + if (!$pfbupdate) { + if (!$pfb['save']) { + $log = "\n** DNSBL Disabled **\n"; + pfb_logger("{$log}", 1); + } + } else { + $log = "\n\n===[ DNSBL Disabled ]==========================================\n"; + pfb_logger("{$log}", 1); + } + } + unset($conf); + unlink_if_exists("{$pfb['dnsbl_file']}.bk"); + ################################# # Assign Countries # ################################# - foreach ($continents as $continent => $pfb_alias) { - if (is_array($config['installedpackages']['pfblockerng' . strtolower(preg_replace('/ /','',$continent))]['config'])) { - $continent_config = $config['installedpackages']['pfblockerng' . strtolower(preg_replace('/ /','',$continent))]['config'][0]; - $cc_name = 'pfblockerng' . strtolower(preg_replace('/ /','',$continent)); - if ($continent_config['action'] != "Disabled" && $pfb['enable'] == "on") { + if (!$pfb['save']) { + $log = "\n\n===[ Continent Process ]============================================\n"; + pfb_logger("{$log}", 1); + } - // Determine if Continent Lists require Action (IPv4 and IPv6) - $cont_type = array ("countries4" => "_v4", "countries6" => "_v6"); + 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]; + $cc_name = 'pfblockerng' . strtolower(str_replace(' ', '', $continent)); + if ($continent_config['action'] != 'Disabled' && $pfb['enable'] == 'on') { + + // Determine if Continent lists require action (IPv4 and IPv6) + $cont_type = array('countries4' => '_v4', 'countries6' => '_v6'); foreach ($cont_type as $c_type => $vtype) { - // Determine 'List' details (return array $pfbarr) - pfb_determine_list_detail($continent_config['action'], "{$pfb_alias}{$vtype}", $cc_name, "0"); - $pfb['skip'] = $pfbarr['skip']; - $pfb_descr = $pfbarr['descr']; + // Determine 'list' details (return array $pfbarr) + pfb_determine_list_detail($continent_config['action'], "{$pfb_alias}{$vtype}", $cc_name, '0'); + $pfbadv = $pfbarr['adv']; + $pfbdescr = $pfbarr['descr']; $pfbfolder = $pfbarr['folder']; - $log_tab = $pfbarr['logtab']; + $pfborig = $pfbarr['orig']; + $logtab = $pfbarr['logtab']; $aports = $pfbarr['aports']; $adest = $pfbarr['adest']; $aproto = $pfbarr['aproto']; - $continent = ""; - if ($continent_config[$c_type] != "") { + $continent_ex = array(); // An array of existing Continent IPs + $continent = array(); // An array of updated Continent IPs + + if (!empty($continent_config[$c_type])) { + $ccfile = "{$pfb_alias}{$vtype}"; - // Collect Selected ISO Country Files - foreach (explode(",", $continent_config[$c_type]) as $iso) { - if ($iso != "" && file_exists($pfb['ccdir'] .'/' . $iso . $vtype . '.txt')) { - $continent .= file_get_contents ($pfb['ccdir'] . '/' . $iso . $vtype . '.txt'); + // Collect selected ISO Country ISOs + foreach (explode(',', $continent_config[$c_type]) as $iso) { + $isofile = "{$pfb['ccdir']}/{$iso}{$vtype}.txt"; + + if (!empty($iso) && file_exists("{$isofile}")) { + $cc_iso = file("{$isofile}", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $continent = array_merge($continent, $cc_iso); } } - if (file_exists($pfb['origdir'] . '/' . $pfb_alias . $vtype . '.orig')) { - $continent_existing = preg_replace('/\s/', '', file ($pfb['origdir'] . '/' . $pfb_alias . $vtype . '.orig')); + // Collect existing Continent data + if (file_exists("{$pfborig}/{$ccfile}.orig")) { + $continent_ex = file("{$pfborig}/{$ccfile}.orig", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); } - // Collect New Continent Data for comparison. Cleanup Array for Comparison - $continent_new = preg_split ('/$\R?^/m', $continent); - $line = count ( $continent_new ) - 1; - $match = $continent_new[$line]; - $continent_new[$line] = rtrim($match, "\n"); - - // Check if pfBlockerNG pfctl Continent Tables are Empty (pfBlockerNG was Disabled w/ "keep", then Re-enabled) - $pfctlck = exec ("/sbin/pfctl -vvsTables | grep -A1 {$pfb_alias}{$vtype} | awk '/Addresses/ {s+=$2}; END {print s}'"); - if (empty($pfctlck) && file_exists($pfbfolder . '/' . $pfb_alias . $vtype . '.txt')) { - $file_cont = file_get_contents($pfbfolder . '/' . $pfb_alias . $vtype . '.txt'); - @file_put_contents($pfb['aliasdir'] . '/' . $pfb_alias . $vtype . '.txt',$file_cont, LOCK_EX); - // PFCTL - Update Only Aliases that have been updated. ('Reputation' Disabled) + + // Check if pfBlockerNG pfctl Continent tables are empty (pfBlockerNG was disabled w/ "keep", then re-enabled) + $pfctlck = exec("{$pfb['pfctl']} -vvsTables | {$pfb['grep']} -A1 {$pfb_alias}{$vtype} | {$pfb['awk']} '/Addresses/ {s+=$2}; END {print s}'"); + + if (empty($pfctlck) && file_exists("{$pfbfolder}/{$ccfile}.txt")) { + @copy("{$pfbfolder}/{$ccfile}.txt", "{$pfb['aliasdir']}/{$ccfile}.txt"); + // Collect updated alias lists ('Reputation' disabled) $pfb_alias_lists[] = "{$pfb_alias}{$vtype}"; } - // Collect Active Alias Lists (Used for pfctl Update when 'Reputation' is enabled). + // Collect active alias lists (Used for pfctl update when 'Reputation' is enabled). $pfb_alias_lists_all[] = "{$pfb_alias}{$vtype}"; - // Compare Existing (Original File) and New Continent Data - if ($continent_new === $continent_existing && !empty($pfctlck) && file_exists($pfbfolder . '/' . $pfb_alias . $vtype . '.txt') && $pfb['reuse'] == "") { + // Compare existing (original file) and new Continent data + if ($continent === $continent_ex && !empty($pfctlck) && + file_exists("{$pfbfolder}/{$ccfile}.txt") && $pfb['reuse'] == '') { if (!$pfb['save']) { - $log = "\n[ {$pfb_alias}{$vtype} ]{$log_tab} exists, Reloading File [ NOW ]"; - pfb_logger("{$log}","1"); + $log = "\n[ {$pfb_alias}{$vtype} ]{$logtab} exists, Reloading [ NOW ]"; + pfb_logger("{$log}", 1); } } else { - // Do not proceed with Changes on User 'Save' + // Do not proceed with changes on user 'save' if (!$pfb['save']) { - $log = "\n[ {$pfb_alias}{$vtype} ]{$log_tab} Changes Found... Updating \n"; - pfb_logger("{$log}","1"); + $log = "\n[ {$pfb_alias}{$vtype} ]{$logtab} Changes found... Updating\n"; + pfb_logger("{$log}", 1); - // Test to Skip d-dup and p-dup functions when changes are found. - $pfb['dupcheck'] = TRUE; + // Execute Reputation functions, when changes are found. + $pfb['repcheck'] = TRUE; + // Collect updated alias lists ('Reputation' disabled) $pfb_alias_lists[] = "{$pfb_alias}{$vtype}"; - // Script to call Duplication Check Process only on IPv4 - if ($pfb['dup'] == "on" && $pfb['skip'] && $vtype == "_v4") { - // Copy Continent Data to 'lists' folder for duplication processing - @file_put_contents($pfb['origdir'] . '/' . $pfb_alias . $vtype . '.orig',$continent, LOCK_EX); - @file_put_contents($pfb['denydir'] . '/' . $pfb_alias . $vtype . '.txt',$continent, LOCK_EX); - exec ("{$pfb['script']} continent {$pfb_alias}{$vtype} >> {$pfb['log']} 2>&1"); - $continent = file_get_contents($pfbfolder . '/' . $pfb_alias . $vtype . '.txt'); - @file_put_contents($pfb['aliasdir'] . '/' . $pfb_alias . $vtype . '.txt',$continent, LOCK_EX); - } else { - @file_put_contents($pfbfolder . '/' . $pfb_alias . $vtype . '.txt',$continent, LOCK_EX); - @file_put_contents($pfb['origdir'] . '/' . $pfb_alias . $vtype . '.orig',$continent, LOCK_EX); - @file_put_contents($pfb['aliasdir'] . '/' . $pfb_alias . $vtype . '.txt',$continent, LOCK_EX); + if (!empty($continent)) { + $cont_string = ''; + foreach ($continent as $ccline) { + $cont_string .= "{$ccline}\n"; + } + + // Save Continent data + @file_put_contents("{$pfborig}/{$ccfile}.orig", rtrim($cont_string, "\n"), LOCK_EX); + @copy("{$pfborig}/{$ccfile}.orig", "{$pfbfolder}/{$ccfile}.txt"); + + // Call Aggregate process + if ($pfb['agg'] == 'on' && $vtype == '_v4') { + exec("{$pfb['script']} cidr_aggregate {$ccfile} {$pfbfolder} {$elog}"); + } + + // Call Duplication process + if ($pfb['dup'] == 'on' && $vtype == '_v4' && $pfbadv) { + exec("{$pfb['script']} continent {$ccfile} {$elog}"); + } + + // Save Continent data to aliastable folder + @copy("{$pfbfolder}/{$ccfile}.txt", "{$pfb['aliasdir']}/{$ccfile}.txt"); } - // Check if File Exists and is > 0 in Size and Save alias file - $file_chk = "0"; - $cont_chk = "{$pfbfolder}/{$pfb_alias}{$vtype}.txt"; + // Check if file exists and is > 0 in size and save alias file + $file_chk = 0; + $cont_chk = "{$pfbfolder}/{$ccfile}.txt"; if (file_exists($cont_chk) && @filesize($cont_chk) > 0) { - $file_chk = exec ("/usr/bin/grep -cv '^#\|^$' {$cont_chk}"); + $file_chk = exec("{$pfb['grep']} -cv '^#\|^$' {$cont_chk}"); } - if ($file_chk == "0" || $file_chk == "1") { - $new_file = "1.1.1.1\n"; - @file_put_contents($pfbfolder . '/' . $pfb_alias . $vtype . '.txt', $new_file, LOCK_EX); - @file_put_contents($pfb['aliasdir'] . "/" . $pfb_alias . $vtype . ".txt", $new_file, LOCK_EX); - $log = "[ {$pfb_alias}{$vtype} ] Found no Unique IPs, Adding '1.1.1.1' to avoid Empty File\n"; - pfb_logger("{$log}","1"); + if ($file_chk <= 1) { + @file_put_contents("{$pfbfolder}/{$ccfile}.txt", "1.1.1.1\n", LOCK_EX); + @copy("{$pfbfolder}/{$ccfile}.txt", "{$pfb['aliasdir']}/{$ccfile}.txt"); + $log = "[ {$pfb_alias}{$vtype} ] Found no unique IPs, adding '1.1.1.1' to avoid empty file\n"; + pfb_logger("{$log}", 1); } } } - if (file_exists($pfbfolder . '/' . $pfb_alias . $vtype . '.txt')) { + if (file_exists("{$pfbfolder}/{$ccfile}.txt")) { // Create alias config $new_aliases_list[] = "{$pfb_alias}{$vtype}"; - - $pfb_contlog = $continent_config['aliaslog']; - - $new_aliases[] = array( "name" => "{$pfb_alias}{$vtype}", - "url" => "{$pfb['weblocal']}?pfb={$pfb_alias}{$vtype}", - "updatefreq" => "32", - "address" => "", - "descr" => "pfBlockerNG {$vtype} {$pfb_descr} Country Alias", - "type" => "urltable", - "detail" => "DO NOT EDIT THIS ALIAS" + $new_aliases[] = array( 'name' => "{$pfb_alias}{$vtype}", + 'url' => "{$pfb['weblocal']}?pfb={$pfb_alias}{$vtype}", + 'updatefreq' => '32', + 'address' => '', + 'descr' => "pfBlockerNG {$vtype} {$pfbdescr} Country Alias", + 'type' => 'urltable', + 'detail' => 'DO NOT EDIT THIS ALIAS' ); - // Create rule if action permits - switch ($continent_config['action']) { - case "Deny_Both": - case "Deny_Outbound": - $rule = $base_rule; - $rule['type'] = "{$pfb['deny_action_outbound']}"; - if ($vtype == "_v6") - $rule['ipprotocol'] = "inet6"; - if ($pfb['float'] == "on") - $rule['direction'] = "any"; - $rule['descr']= "{$pfb_alias}{$vtype}{$pfb['suffix']}"; - $rule['source'] = array("any" => ""); - $rule['destination'] = array("address" => "{$pfb_alias}{$vtype}"); - if ($pfb['config']['enable_log'] == "on" || $pfb_contlog == "enabled") - $rule['log'] = ""; - $deny_outbound[] = $rule; - if ($continent_config['action'] != "Deny_Both") - break; - case "Deny_Inbound": - $rule = $base_rule; - $rule['type'] = "{$pfb['deny_action_inbound']}"; - if ($vtype == "_v6") - $rule['ipprotocol'] = "inet6"; - if ($pfb['float'] == "on") - $rule['direction'] = "any"; - $rule['descr'] = "{$pfb_alias}{$vtype}{$pfb['suffix']}"; - $rule['source'] = array("address" => "{$pfb_alias}{$vtype}"); - if (!empty($adest) && !empty($aports)) { - $rule['destination'] = array("address" => "{$adest}", "port" => "{$aports}"); - } elseif (!empty($adest) && empty($aports)) { - $rule['destination'] = array("address" => "{$adest}"); - } elseif (empty($adest) && !empty($aports)) { - $rule['destination'] = array("any" => "", "port" => "{$aports}"); - } else { - $rule['destination'] = array("any" => ""); - } - if (!empty($adest) && $continent_config['autonot'] == "on") - $rule['destination']['not'] = ""; - if (!empty($aproto)) - $rule['protocol'] = "{$aproto}"; - if ($pfb['config']['enable_log'] == "on" || $pfb_contlog == "enabled") - $rule['log'] = ""; - $deny_inbound[] = $rule; - break; - case "Permit_Both": - case "Permit_Outbound": - $rule = $base_rule; - $rule['type'] = "pass"; - if ($vtype == "_v6") - $rule['ipprotocol'] = "inet6"; - if ($pfb['float'] == "on") - $rule['direction'] = "any"; - $rule['descr'] = "{$pfb_alias}{$vtype}{$pfb['suffix']}"; - $rule['source'] = array ("any" => ""); - $rule['destination'] = array("address" => "{$pfb_alias}{$vtype}"); - if ($pfb['config']['enable_log'] == "on" || $pfb_contlog == "enabled") - $rule['log'] = ""; - $permit_outbound[] = $rule; - if ($continent_config['action'] != "Permit_Both") - break; - case "Permit_Inbound": - $rule = $base_rule; - $rule['type'] = "pass"; - if ($vtype == "_v6") - $rule['ipprotocol'] = "inet6"; - if ($pfb['float'] == "on") - $rule['direction'] = "any"; - $rule['descr'] = "{$pfb_alias}{$vtype}{$pfb['suffix']}"; - $rule['source'] = array("address"=> "{$pfb_alias}{$vtype}"); - if (!empty($adest) && !empty($aports)) { - $rule['destination'] = array("address" => "{$adest}", "port" => "{$aports}"); - } elseif (!empty($adest) && empty($aports)) { - $rule['destination'] = array("address" => "{$adest}"); - } elseif (empty($adest) && !empty($aports)) { - $rule['destination'] = array("any" => "", "port" => "{$aports}"); - } else { - $rule['destination'] = array("any" => ""); - } - if (!empty($adest) && $continent_config['autonot'] == "on") - $rule['destination']['not'] = ""; - if (!empty($aproto)) - $rule['protocol'] = "{$aproto}"; - if ($pfb['config']['enable_log'] == "on" || $pfb_contlog == "enabled") - $rule['log'] = ""; - $permit_inbound[] = $rule; - break; - case "Match_Both": - case "Match_Outbound": - $rule = $base_rule_float; - $rule['type'] = "match"; - if ($vtype == "_v6") - $rule['ipprotocol'] = "inet6"; - $rule['direction'] = "any"; - $rule['descr'] = "{$pfb_alias}{$vtype}{$pfb['suffix']}"; - $rule['source'] = array("any" => ""); - $rule['destination'] = array("address" => "{$pfb_alias}{$vtype}"); - if ($pfb['config']['enable_log'] == "on" || $pfb_contlog == "enabled") - $rule['log'] = ""; - $match_outbound[] = $rule; - if ($list['action'] != "Match_Both") - break; - case "Match_Inbound": - $rule = $base_rule_float; - $rule['type'] = "match"; - if ($vtype == "_v6") - $rule['ipprotocol'] = "inet6"; - $rule['direction'] = "any"; - $rule['descr'] = "{$pfb_alias}{$vtype}{$pfb['suffix']}"; - $rule['source'] = array ("address" => "{$pfb_alias}{$vtype}"); - if (!empty($adest) && !empty($aports)) { - $rule['destination'] = array("address" => "{$adest}", "port" => "{$aports}"); - } elseif (!empty($adest) && empty($aports)) { - $rule['destination'] = array("address" => "{$adest}"); - } elseif (empty($adest) && !empty($aports)) { - $rule['destination'] = array("any" => "", "port" => "{$aports}"); - } else { - $rule['destination'] = array("any" => ""); - } - if (!empty($adest) && $continent_config['autonot'] == "on") - $rule['destination']['not'] = ""; - if (!empty($aproto)) - $rule['protocol'] = "{$aproto}"; - if ($pfb['config']['enable_log'] == "on" || $pfb_contlog == "enabled") - $rule['log'] = ""; - $match_inbound[] = $rule; - break; - } - } else { - // unlink continent list if any - unlink_if_exists($pfb['aliasdir'] . '/' . $pfb_alias . $vtype . '.txt'); + // Define firewall rule settings + pfb_firewall_rule($continent_config['action'], $pfb_alias, $vtype, $continent_config['aliaslog'], + $adest, $aports, $aproto, $continent_config['autonot']); + } + else { + // unlink Continent list + unlink_if_exists("{$pfb['aliasdir']}/{$ccfile}.txt"); } } } } - // mark pfctl aliastable for cleanup - if (!in_array($pfb_alias, $aliases_list)) { - $aliases_list[] = "{$pfb_alias}{$vtype}"; - } } } - // UNSET variables - unset ($continent, $continent_existing, $continent_new); + // Unset variables + unset ($continent, $continent_ex); ################################################# # Download and Collect IPv4/IPv6 lists # @@ -1428,511 +3217,406 @@ function sync_package_pfblockerng($cron = "") { // IPv4 REGEX Definitions $pfb['range'] = '/((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))-((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))/'; - $pfb['block'] = '/(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[ 0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.([0]{1})\s+/'; - $pfb['cidr'] = '/(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)?\/([0-9]{2}|[0-9]{1})/'; - $pfb['single'] = '/(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\s+/'; - $pfb['s_html'] = '/(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/'; - - // IPv4 preg_replace Regex Filter array - $pfb_ipreg = array(); - $pfb_ipreg[0] = '/\b0+(?=\d)/'; // Remove any Leading Zeros in each Octet - $pfb_ipreg[1] = '/\s/'; // Remove any Whitespaces - $pfb_ipreg[2] = '/\/32/'; // Remove any /32 CIDR - $pfb_ipreg[3] = '/127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/'; // Remove any Loopback Addresses 127/8 - $pfb_ipreg[4] = '/0\.0\.0\.0/'; // Remove 0.0.0.0 - - // IPv6 REGEX Definitions -- ** Still Needs some Adjustment on Regex Definition for IPv6 ** - // https://mebsd.com/coding-snipits/php-regex-ipv6-with-preg_match.html - $pattern1 = '([A-Fa-f0-9]{1,4}:){7}[A-Fa-f0-9]{1,4}'; - $pattern2 = '[A-Fa-f0-9]{1,4}::([A-Fa-f0-9]{1,4}:){0,5}[A-Fa-f0-9]{1,4}'; - $pattern3 = '([A-Fa-f0-9]{1,4}:){2}:([A-Fa-f0-9]{1,4}:){0,4}[A-Fa-f0-9]{1,4}'; - $pattern4 = '([A-Fa-f0-9]{1,4}:){3}:([A-Fa-f0-9]{1,4}:){0,3}[A-Fa-f0-9]{1,4}'; - $pattern5 = '([A-Fa-f0-9]{1,4}:){4}:([A-Fa-f0-9]{1,4}:){0,2}[A-Fa-f0-9]{1,4}'; - $pattern6 = '([A-Fa-f0-9]{1,4}:){5}:([A-Fa-f0-9]{1,4}:){0,1}[A-Fa-f0-9]{1,4}'; - $pattern7 = '([A-Fa-f0-9]{1,4}:){6}:[A-Fa-f0-9]{1,4}'; - $pattern8 = '[A-Fa-f0-9]{1,4}:[A-Fa-f0-9]{1,4}:[A-Fa-f0-9]{1,4}::\/[0-9]{2}'; - $pattern9 = '[A-Fa-f0-9]{1,4}:([A-Fa-f0-9]{1,4}::)\/[0-9]{2}'; - $pattern10 = '[A-Fa-f0-9]{1,4}::\/[0-9]{2}'; - $pfb['ipv6'] = "/($pattern1)|($pattern2)|($pattern3)|($pattern4)|($pattern5)|($pattern6)|($pattern7)|($pattern8)|($pattern9)|($pattern10)/"; - - $pfb['supp_update'] = FALSE; - $list_type = array ("pfblockernglistsv4" => "_v4", "pfblockernglistsv6" => "_v6"); - foreach ($list_type as $ip_type => $vtype) { - if ($config['installedpackages'][$ip_type]['config'] != "") { - foreach ($config['installedpackages'][$ip_type]['config'] as $list) { - if ($list['action'] != "Disabled" && $pfb['enable'] == "on" && !$pfb['save'] && is_array($list['row'])) { - // capture Alias Name - $alias = "pfB_" . preg_replace("/\W/","",$list['aliasname']); - foreach ($list['row'] as $row) { - if ($row['url'] != "" && $row['state'] != "Disabled") { - - if ($vtype == "_v4") { - $header_url = "{$row['header']}"; - } else { - $header_url = "{$row['header']}_v6"; - } + $pfb['ipv4'] = '/(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\/(3[012]|[12]?[0-9]))?/'; - // Determine 'List' details (return array $pfbarr) - pfb_determine_list_detail($list['action'], $header_url, "", ""); - $pfb['skip'] = $pfbarr['skip']; - $pfbfolder = $pfbarr['folder']; - $log_tab = $pfbarr['logtab']; + // IPv6 REGEX Definitions - Reference: http://labs.spritelink.net/regex + $pfb['ipv6'] = '/((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?(\/[0-9][0-9]?|1([01][0-9]|2[0-8]))?/'; - // Empty Header Field Validation Check - if (empty($header_url) || preg_match("/\W/",$header_url)) { - $log = "\n [ {$row['url']} ]\n ** TERMINATED - Header contains Blank/International/Special or Spaces\n"; - pfb_logger("{$log}","2"); - continue; - } + if ($pfb['enable'] == 'on' && !$pfb['save']) { - // Collect Active Alias List (Used for pfctl Update when 'Reputation' is enabled. - $pfb_alias_lists_all[] = "{$alias}"; + $pfb['supp_update'] = FALSE; + $runonce_v4 = $runonce_v6 = TRUE; + $list_type = array('pfblockernglistsv4' => '_v4', 'pfblockernglistsv6' => '_v6'); + $lists = array(); - if (file_exists($pfbfolder . '/' . $header_url . '.txt') && $pfb['reuse'] == "") { - if ($row['state'] == "Hold") { - $log = "\n[ {$header_url} ]{$log_tab} Static Hold [ NOW ]"; - } else { - $log = "\n[ {$header_url} ]{$log_tab} exists, Reloading File [ NOW ]"; - } - pfb_logger("{$log}","1"); + // Collect lists and custom list configuration and format into one array ($lists). + foreach ($list_type as $ip_type => $vtype) { + if (!empty($config['installedpackages'][$ip_type]['config'])) { + foreach ($config['installedpackages'][$ip_type]['config'] as $list) { + if ($vtype == '_v4') { + $list['vtype'] = '_v4'; + } else { + $list['vtype'] = '_v6'; + } + + // If only the 'customlist' is defined. Remove the 'List row' data. + if (empty($list['row'][0]['url'])) { + unset($list['row']); + } + + if (!empty($list['custom'])) { + $list['row'][] = array( 'header' => "{$list['aliasname']}_custom", + 'custom' => $list['custom'], + 'state' => 'Enabled', + 'update' => $list['custom_update'], + 'url' => 'custom' + ); + } + $lists[] = $list; + } + } + } + + foreach ($lists as $list) { + if ($runonce_v4 && $list['vtype'] == '_v4') { + $runonce_v4 = FALSE; + $log = "\n\n===[ IPv4 Process ]=================================================\n"; + pfb_logger("{$log}", 1); + } elseif ($runonce_v6 && $list['vtype'] == '_v6') { + $runonce_v6 = FALSE; + $log = "\n\n===[ IPv6 Process ]=================================================\n"; + pfb_logger("{$log}", 1); + } + + if ($list['action'] != 'Disabled' && isset($list['row'])) { + // Capture alias name + $alias = 'pfB_' . preg_replace("/\W/", '', $list['aliasname']); + foreach ($list['row'] as $row) { + if (!empty($row['url']) && $row['state'] != 'Disabled') { + + if ($list['vtype'] == '_v4') { + $header = "{$row['header']}"; + } else { + $header = "{$row['header']}_v6"; + } + + // If row is a custom_list, set flag. + if (isset($row['custom'])) { + $custom = TRUE; + } else { + $custom = FALSE; + } + + // Determine 'list' details (return array $pfbarr) + pfb_determine_list_detail($list['action'], $header, '', ''); + $pfbadv = $pfbarr['adv']; + $pfbfolder = $pfbarr['folder']; + $pfborig = $pfbarr['orig']; + $pfbreuse = $pfbarr['reuse']; + $logtab = $pfbarr['logtab']; + + // Collect active alias list (Used for pfctl update when 'Reputation' is enabled. + $pfb_alias_lists_all[] = "{$alias}"; + + if (file_exists("{$pfbfolder}/{$header}.txt") && $pfbreuse == '') { + if ($row['state'] == 'Hold') { + $log = "\n[ {$header} ]{$logtab} Static Hold [ NOW ]"; } else { - if ($pfb['reuse'] == "on" && file_exists($pfb['origdir'] . '/' . $header_url . '.orig')) { - $log = "\n[ {$header_url} ]{$log_tab} Using Previously Downloaded File [ NOW ]"; - } else { - $log = "\n[ {$header_url} ]{$log_tab} Downloading New File [ NOW ]"; - } - pfb_logger("{$log}","1"); - - $list_url = "{$row['url']}"; - if (!$pfb['reuse'] == "on") { - // Perform Remote URL Date/Time Stamp checks - $host = @parse_url($row['url']); - if ($row['format'] != "rsync" || $row['format'] != "html") { - if ($host['host'] == "127.0.0.1" || $host['host'] == $pfb['iplocal'] || empty($host['host'])) { - $remote_tds = "local"; - } else { - $remote_tds = @implode(preg_grep("/Last-Modified/", get_headers($list_url))); - $remote_tds = preg_replace("/^Last-Modified: /","", $remote_tds); - } - } - } + $log = "\n[ {$header} ]{$logtab} exists, Reloading [ NOW ]"; + } + pfb_logger("{$log}", 1); + } else { + if ($pfbreuse == 'on' && file_exists("{$pfborig}/{$header}.orig")) { + $log = "\n[ {$header} ]{$logtab} Reload [ NOW ]"; + } else { + $log = "\n[ {$header} ]{$logtab} Downloading update [ NOW ]"; + } + pfb_logger("{$log}", 1); + $file_dwn = "{$pfborig}/{$header}"; - $url_list = array(); - if ($row['format'] == "gz" || $row['format'] == "gz_2") { - $file_dwn = "{$pfb['origdir']}/{$header_url}.gz"; - if ($pfb['reuse'] == "on" && file_exists($file_dwn)) { - // File Exists/Reuse - } else { - $url_gz = "{$row['url']}"; - $file_gz = @file_get_contents($url_gz); - @file_put_contents($file_dwn, $file_gz, LOCK_EX); - if ($remote_tds == "local") - $remote_tds = gmdate ("D, d M Y H:i:s T", filemtime($file_dwn)); - $remote_stamp = strtotime($remote_tds); - if (!empty($remote_stamp) && file_exists($file_dwn)) - touch ($file_dwn, $remote_stamp); - } - $url_list = @gzfile($file_dwn); + if (!$custom) { + pfb_logger(' .', 1); + + // Allow cURL SSL downgrade 'Flex' if user configured. + $pflex = FALSE; + if ($row['state'] == 'Flex') { + $pflex = TRUE; } - // IBlock Large Files mixed with IPs and Domains. PHP mem of 256M can't handle very large Files. - if ($row['format'] == "gz_lg") { - $file_dwn = "{$pfb['origdir']}/{$header_url}.gz"; - if ($pfb['reuse'] == "on" && file_exists($file_dwn)) { - // File Exists/Reuse - } else { - $url_gz = "{$row['url']}"; - $file_gz = @file_get_contents($url_gz); - @file_put_contents($file_dwn, $file_gz, LOCK_EX); - exec ("/usr/bin/gunzip -c {$file_dwn} | /usr/bin/sed 's/^.*://' | /usr/bin/grep -v '[a-zA-Z]\|^$\|^#' > {$pfb['origdir']}/{$header_url}.orig"); - if ($remote_tds == "local") - $remote_tds = gmdate ("D, d M Y H:i:s T", filemtime($file_dwn)); - $remote_stamp = strtotime($remote_tds); - if (!empty($remote_stamp) && file_exists($file_dwn)) - touch ($file_dwn, $remote_stamp); + // Determine if list needs to be downloaded or reuse previously downloaded file. + if ($pfbreuse == 'on' && file_exists("{$file_dwn}.orig")) { + // File exists/reuse + + // Process Emerging Threats IQRisk if required + if (strpos($row['url'], 'iprepdata.txt') !== FALSE) { + exec("{$pfb['script']} et {$header} x x x x x {$pfb['etblock']} {$pfb['etmatch']} {$elog}"); } - $url_list = @file($pfb['origdir'] . '/' . $header_url . '.orig'); - } + } else { + // Download list + if (!pfb_download($row['url'], $file_dwn, $pflex, $header, $row['format'], + 1, $list['vtype'])) { - elseif ($row['format'] == "zip") { - $file_dwn = "{$pfb['origdir']}/{$header_url}.zip"; - if ($pfb['reuse'] == "on" && file_exists($file_dwn)) { - // File Exists/Reuse - } else { - $url_zip = "{$row['url']}"; - if (!$file_zip = @file_get_contents($url_zip)) { - $error = error_get_last(); - $log = "\n [ {$header_url} ] {$error['message']}\n"; - pfb_logger("{$log}","2"); + // Determine reason for download failure + pfb_download_failure($alias, $header, $pfbfolder, $list['vtype'], $row['url']); + + // Utilize previously download file (If 'fail' marker exists) + if (file_exists("{$pfbfolder}/{$header}.fail") && + file_exists("{$file_dwn}.orig")) { + pfb_logger("\n Restoring previously downloaded file contents ", 2); } else { - @file_put_contents($file_dwn, $file_zip, LOCK_EX); - if ($remote_tds == "local") - $remote_tds = gmdate ("D, d M Y H:i:s T", filemtime($file_dwn)); - $remote_stamp = strtotime($remote_tds); - if (!empty($remote_stamp) && file_exists($file_dwn)) - touch ($file_dwn, $remote_stamp); + if ($pfbadv) { + // Script to Remove failed lists from masterfile + exec("{$pfb['script']} remove x x x {$header} {$elog}"); + } + continue; } - } - $zip_out = "{$pfb['origdir']}/{$header_url}.orig"; - exec ("/usr/bin/tar -xOf {$file_dwn} | tr ',' '\n' > {$zip_out}"); - $url_list = @file($zip_out); - } - - elseif ($row['format'] == "et") { - $file_dwn = "{$pfb['origdir']}/{$header_url}.gz"; - // Script to Call ET IQRISK Process - if ($pfb['reuse'] == "on" && file_exists($file_dwn)) { - // File Exists/Reuse } else { - $url_et = "{$row['url']}"; - $file_et = @file_get_contents($url_et); - @file_put_contents($file_dwn, $file_et, LOCK_EX); - if ($remote_tds == "local") - $remote_tds = gmdate ("D, d M Y H:i:s T", filemtime($file_dwn)); - $remote_stamp = strtotime($remote_tds); - if (!empty($remote_stamp) && file_exists($file_dwn)) - touch ($file_dwn, $remote_stamp); + // Clear any previous download fail marker + unlink_if_exists("{$pfbfolder}/{$header}.fail"); + pfb_logger('.', 1); } - exec ("{$pfb['script']} et {$header_url} x x x x x {$pfb['etblock']} {$pfb['etmatch']} >> {$pfb['log']} 2>&1"); - $url_list = @file($pfb['origdir'] . '/' . $header_url . '.orig'); } + pfb_logger(' completed .', 1); + } + else { + if ($list['whois_convert'] == 'on') { + // Process Domain/AS based custom list + $custom_list = str_replace("\n", ',', pfbng_text_area_decode($list['custom'])); + exec("{$pfb['script']} whoisconvert {$header} {$list['vtype']} {$custom_list} {$elog}"); + } else { + // Process IP based custom list + $custom_list = pfbng_text_area_decode($list['custom']); + @file_put_contents("{$file_dwn}.orig", $custom_list, LOCK_EX); + } + pfb_logger(' . completed .', 1); + } - elseif ($row['format'] == "xlsx") { - $file_dwn = "{$pfb['origdir']}/{$header_url}.zip"; - // Script to Call XLSX Process - if ($pfb['reuse'] == "on" && file_exists($file_dwn)) { - // File Exists/Reuse - } else { - $url_xlsx = "{$row['url']}"; - $file_xlsx = @file_get_contents($url_xlsx); - @file_put_contents($file_dwn, $file_xlsx, LOCK_EX); - if ($remote_tds == "local") - $remote_tds = gmdate ("D, d M Y H:i:s T", filemtime($file_dwn)); - $remote_stamp = strtotime($remote_tds); - if (!empty($remote_stamp) && file_exists($file_dwn)) - touch ($file_dwn, $remote_stamp); - } - exec ("{$pfb['script']} xlsx {$header_url} >> {$pfb['log']} 2>&1"); - $url_list = @file($pfb['origdir'] . '/' . $header_url . '.orig'); + $ip_data = ''; // IPs collected from feed + $parse_fail = 0; // Failed parsed lines from feed + pfb_logger('.', 1); + + // Set 'auto' format for all lists, except for lists that require 'regex' parsing. + if ($row['format'] == 'regex') { + $pftype = 'regex'; + } + else { + $url = pathinfo($row['url']); + + // Strip any text after '?' + if (strpos($url['extension'], '?') !== FALSE) { + $url['extension'] = strstr($url['extension'], '?', TRUE); } - elseif ($row['format'] == "txt") { - $file_dwn = "{$pfb['origdir']}/{$header_url}.orig"; - if ($pfb['reuse'] == "on" && file_exists($file_dwn)) { - $url_list = @file($file_dwn); - } else { - $url_other = @file($row['url']); - $url_list = $url_other; - @file_put_contents($file_dwn, $url_other, LOCK_EX); - if ($remote_tds == "local") - $remote_tds = gmdate ("D, d M Y H:i:s T", filemtime($file_dwn)); - $remote_stamp = strtotime($remote_tds); - if (!empty($remote_stamp) && file_exists($file_dwn)) - touch ($file_dwn, $remote_stamp); - } + // Determine if list is an IBlock list + if (strpos($url['dirname'], 'iblocklist') !== FALSE) { + $url['extension'] = 'iblock'; } - elseif ($row['format'] == "html" || $row['format'] == "block") { - $file_dwn = "{$pfb['origdir']}/{$header_url}.raw"; - if ($pfb['reuse'] == "on" && file_exists($file_dwn)) { - // File Exists/Reuse - $return = 0; - } else { - $url_html = "{$row['url']}"; - exec ("/usr/bin/fetch -v -o {$file_dwn} -T 20 '{$url_html}'",$output,$return); - } - if ($return == 0) - $url_list = @file($file_dwn); + // Use 'regex' IP parser for non-standard IP lists. + if (in_array($url['extension'], array('html', 'htm', 'php', 'aspx', 'cgi', 'csv', 'rules', ''))) { + $pftype = 'regex'; + } else { + $pftype = 'auto'; } + } - elseif ($row['format'] == "rsync") { - $file_dwn = "{$pfb['origdir']}/{$header_url}.orig"; - if ($pfb['reuse'] == "on" && file_exists($file_dwn)) { - // File Exists/Reuse - } else { - $url_rsync = "{$row['url']}"; - exec ("/usr/local/bin/rsync --timeout=5 {$url_rsync} {$file_dwn}"); + if (($fhandle = fopen("{$file_dwn}.orig", 'r')) !== FALSE) { + while (($line = fgets($fhandle, 1024)) !== FALSE) { + + // Record original line for regex matching, if required. + $oline = $line; + + // Remove any leading/trailing whitespaces + $line = trim($line); + + // Remove commentlines and blank lines + if (substr($line, 0, 1) == '#' || empty($line)) { + continue; } - $url_list = @file($file_dwn); - } - // extract range lists - $new_file = ""; - if (!empty($url_list)) { - if ($row['format'] == "gz" && $vtype == "_v4") { - foreach ($url_list as $line) { - if (!preg_match("/^#/", $line)) { - // Network range 192.168.0.0-192.168.0.254 - if (preg_match($pfb['range'],$line,$matches)) { - $a_cidr = ip_range_to_subnet_array_temp2($matches[1],$matches[2]); - if (!empty($a_cidr)) { - foreach ($a_cidr as $cidr) { - $new_file .= preg_replace($pfb_ipreg,'',$cidr) . "\n"; + $parse_error = FALSE; + if ($list['vtype'] == '_v4' && $pftype == 'auto') { + + // IBlock - parser sample ( JKS Media, LLC:4.53.2.12-4.53.2.15 ) + // Remove leading domain name details + if (strpos($line, '-') !== FALSE && strpos($line, ':') !== FALSE) { + $line = str_replace(':', '', strstr($line, ':', FALSE)); + } + + // If 'space' character found, remove characters after space + if (strpos($line, ' ') !== FALSE) { + $line = strstr($line, ' ', TRUE); + } + + // If '#' character found, remove characters after '#' + if (strpos($line, '#') !== FALSE) { + $line = str_replace('#', '', strstr($line, '#', TRUE)); + } + + // Remove any leading/trailing whitespaces + $line = trim($line); + + // Range parser + if (strpos($line, '-') !== FALSE) { + $matches = explode('-', $line); + if (count($matches) == 2) { + $a_cidr = ip_range_to_subnet_array_temp($matches[0],$matches[1]); + if (!empty($a_cidr)) { + foreach ($a_cidr as $cidr) { + $cidr = sanitize_ipaddr($cidr, $custom); + if (!empty($cidr)) { + if (validate_ipv4($cidr)) { + $ip_data .= $cidr . "\n"; + } + else { + $parse_error = TRUE; + } } } + if (!$parse_error) { + continue; + } } } + else { + $parse_error = TRUE; + } } - } - elseif ($row['format'] == "block" && $vtype == "_v4") { - foreach ($url_list as $line) { - if (!preg_match("/^#/", $line)) { - // Block Type '218.77.79.0 218.77.79.255 24' - if (preg_match($pfb['block'],$line,$matches)) { - $new_file .= preg_replace($pfb_ipreg, '',$matches[0]) . "/24\n"; - } + if (!$parse_error) { + // Single address parser + $parsed = sanitize_ipaddr($line, $custom); + if (validate_ipv4($parsed)) { + $ip_data .= $parsed . "\n"; + continue; + } + else { + $parse_error = TRUE; } } } - elseif ($row['format'] == "html" && $vtype == "_v4") { - foreach ($url_list as $line) { - if (!preg_match("/^#/", $line)) { - // CIDR format 192.168.0.0/16 - if (preg_match($pfb['cidr'],$line,$matches)) { - $new_file .= preg_replace($pfb_ipreg, '',$matches[0]) . "\n"; - } - // Single ip addresses - elseif (preg_match($pfb['s_html'],$line,$matches)) { - $new_file .= preg_replace($pfb_ipreg, '',$matches[0]) . "\n"; + if ($list['vtype'] == '_v4' && ($pftype == 'regex' || $parse_error)) { + + // Use regex as last alternative. + + if (strpos($oline, '-') !== FALSE) { + // Network range 192.168.0.0-192.168.0.254 + if (preg_match($pfb['range'], $oline, $matches)) { + $a_cidr = ip_range_to_subnet_array_temp($matches[1], $matches[2]); + if (!empty($a_cidr)) { + foreach ($a_cidr as $cidr) { + $cidr = sanitize_ipaddr($cidr, $custom); + if (validate_ipv4($cidr)) { + $ip_data .= $cidr . "\n"; + } + else { + $parse_fail++; + } + } } + continue; } } - } - - elseif ($vtype == "_v6") { - foreach ($url_list as $line) { - if (!preg_match("/^#/", $line)) { - // IPv6 Regex Match - if (preg_match($pfb['ipv6'],$line,$matches)) { - $new_file .= preg_replace($pfb_ipreg, '',$matches[0]) . "\n"; + + // IPv4/CIDR format 192.168.0.0 | 192.168.0.0/16 + if (preg_match_all($pfb['ipv4'], $oline, $matches)) { + $matches = array_unique($matches[0]); + foreach ($matches as $match) { + $parsed = sanitize_ipaddr($match, $custom); + if (validate_ipv4($parsed)) { + $ip_data .= $parsed . "\n"; } } + continue; } } - else { - foreach ($url_list as $line) { - if (!preg_match("/^#/", $line)) { - // Network range 192.168.0.0-192.168.0.254 - if (preg_match($pfb['range'],$line,$matches)) { - $a_cidr = ip_range_to_subnet_array_temp2($matches[1],$matches[2]); - if (!empty($a_cidr)) { - foreach ($a_cidr as $cidr) { - $new_file .= preg_replace($pfb_ipreg,'',$cidr) . "\n"; - } - } + if ($list['vtype'] == '_v6') { + // Auto IPv6 parser + if ($pftype == 'auto') { + if (strpos($line, ':') !== FALSE) { + if (is_ipaddrv6($line) || is_subnet($line)) { + $ip_data .= $line . "\n"; + continue; } - // CIDR format 192.168.0.0/16 - elseif (preg_match($pfb['cidr'],$line,$matches)) { - $new_file .= preg_replace($pfb_ipreg, '',$matches[0]) . "\n"; - } - // Single ip addresses - elseif (preg_match($pfb['single'],$line,$matches)) { - $new_file .= preg_replace($pfb_ipreg, '',$matches[0]) . "\n"; + } + } + + // IPv6 Regex parser + if (preg_match_all($pfb['ipv6'], $oline, $matches)) { + $matches = array_unique($matches[0]); + foreach ($matches as $match) { + if (is_ipaddrv6($match) || is_subnet($match)) { + $ip_data .= $match . "\n"; } } } } } - // Check to see if Blocklist actually Failed Download or has no IPs listed. - if ($row['format'] == "html" || $row['format'] == "block") { - $url_chk = $file_dwn; - } else { - $url_chk = "{$pfb['origdir']}/{$header_url}.orig"; + // Check for parse failures + if (!empty($line) && !preg_match('/[a-zA-Z,;|\"\'?]/', $line)) { + $parse_fail++; + $log = "[!] Parse Errors [ {$parse_fail} ]\n"; + pfb_logger("{$log}", 2); } - - // Check if File Exists and is > 0 in Size - $file_chk = ""; - if (file_exists($url_chk) && @filesize($url_chk) > 0) { - $file_chk = exec ("/usr/bin/grep -cv '^#\|^$' {$url_chk}"); + } + fclose($fhandle); + pfb_logger("\n", 1); + + if (!$custom) { + // Check to see if list actually failed download or has no IPs listed. + $file_chk = ''; + if (file_exists("{$file_dwn}.orig") && @filesize("{$file_dwn}.orig") > 0) { + $file_chk = exec("{$pfb['grep']} -cv '^#\|^$' {$file_dwn}.orig"); } - if ($file_chk == "0") { - $new_file = "1.1.1.1\n"; - $url_other = $new_file; - $log = "[ {$header_url} ] Found no IPs, Adding '1.1.1.1' to avoid Download FAIL\n"; - pfb_logger("{$log}","1"); + if ($file_chk == 0) { + $ip_data = "1.1.1.1\n"; + $log = " Empty file, Adding '1.1.1.1' to avoid download failure.\n"; + pfb_logger("{$log}", 1); } + } - if ($new_file != "") { - if ($row['format'] == "gz" || $row['format'] == "gz_2" || $row['format'] == "html" || $row['format'] == "block") { - // Re-Save these formats as original file - $url_other = $new_file; - @file_put_contents($pfb['origdir'] . '/' . $header_url . '.orig',$url_other, LOCK_EX); - } - - // Save List to '.txt' format in appropriate Folder - @file_put_contents($pfbfolder . '/' .$header_url . '.txt',$new_file, LOCK_EX); + if (!empty($ip_data)) { + // Save List to '.txt' format in appropriate folder + @file_put_contents("{$pfbfolder}/{$header}.txt", "{$ip_data}", LOCK_EX); - if ($pfb['rep'] == "on" && $pfb['skip'] && $vtype == "_v4") { - // Script to Call p24 Process - exec ("{$pfb['script']} p24 {$header_url} {$pfb['max']} {$pfb['dedup']} {$pfb['ccexclude']} {$pfb['ccwhite']} {$pfb['ccblack']} >> {$pfb['log']} 2>&1"); + // Call 'shell script' functions (Deny Actions only) + if ($pfbadv && $list['vtype'] == '_v4') { + $args = ''; + // Call Process255 + if ($pfb['dup'] == 'on' || $pfb['agg'] == 'on') { + $args = '_255'; } - - if ($pfb['dup'] == "on" && $pfb['skip'] && $vtype == "_v4") { - // Script to call Duplication Check Process - exec ("{$pfb['script']} duplicate {$header_url} >> {$pfb['log']} 2>&1"); + // Call Aggregate process + if ($pfb['agg'] == 'on') { + $args .= '_agg'; } - - // PFCTL - Update Only Aliases that have been updated only. - $pfb_alias_lists[] = "{$alias}"; - // Launch d-dup and p-dup functions when changes are found. - if ($pfb['skip'] && $vtype == "_v4") { - $pfb['dupcheck'] = TRUE; + // Call Reputation Max process + if ($pfb['rep'] == 'on') { + $args .= '_rep'; } - // Enable Suppression Process due to Updates - if ($pfb['supp'] == "on" && $vtype == "_v4") { - $pfb['supp_update'] = TRUE; + // Call Duplication process + if ($pfb['dup'] == 'on') { + $args .= '_dup'; } - } else { - // Log FAILED Downloads and Check if Firewall or Snort/Suricata is Blocking Host - $log = "\n [ {$alias} {$header_url} ] Download FAIL [ NOW ]\n"; - pfb_logger("{$log}","2"); - - // Rebuild Previous List File from contents of Masterfile - if ($pfb['skip'] && $vtype == "_v4") { - // Search with trailing Whitespace to match exact Header in Masterfile - $header_url2 = $header_url . "[[:space:]]"; - $file_chk = exec ("/usr/bin/grep {$header_url2} {$pfb['master']} | grep -c ^"); - - if (!file_exists($pfbfolder . '/' . $header_url . '.txt') && @$file_chk > 0 && file_exists($pfb['master'])) { - $log = " [ {$alias} {$header_url} ] Found: {$file_chk} Line(s), Restoring previous List from Master \n"; - pfb_logger("{$log}","2"); - exec ("/usr/bin/grep {$header_url2} {$pfb['master']} | cut -d' ' -f2 > {$pfbfolder}/{$header_url}.txt"); - } - } - // A "Space" string Variable - $sp = " "; - $ip = @gethostbyname($host['host']); - $ip2 = preg_replace("/(\d{1,3})\.(\d{1,3}).(\d{1,3}).(\d{1,3})/", "\"^$1\.$2\.$3\.\"", $ip); - - // Only Perform these Checks if they are not "localfiles" - if ($host['host'] == "127.0.0.1" || $host['host'] == $pfb['iplocal'] || empty($host['host'])) { - $log = " [ {$alias} {$header_url} ] Local File Failure \n"; - pfb_logger("{$log}","2"); - } else { - // only perform these steps if an 'IP' is found. - if (!empty($ip)) { - // Query for Exact IP Match - $result_b1 = array(); - $pfb_b1 = exec ("/usr/bin/grep ^{$ip} {$pfbfolder}/*", $result_b1); - // Query for First Three IP Octet Matches - $result_b2 = array(); - $pfb_b2 = exec ("/usr/bin/grep {$ip2} {$pfbfolder}/*", $result_b2); - // Query Snort/Suricata snort2c IP Block Table - $snort_pfb = exec("/sbin/pfctl -t snort2c -T show | grep {$ip}"); - - // If an exact IP Match is not found report any First Three IP Octets. - if (!empty($result_b1)) { - $final_b1 = implode("\n ", $result_b1); - $log = " [ {$alias} {$header_url}, {$ip} ] Firewall IP Block Found in : \n{$sp}{$final_b1}\n"; - pfb_logger("{$log}","2"); - } else { - if (!empty($result_b2)) { - $final_b2 = implode("\n ", $result_b2); - $log = " [ {$alias} {$header_url}, {$ip} ] *Potential* Firewall IP Block Found in : \n{$sp}{$final_b2}\n"; - pfb_logger("{$log}","2"); - } - } - if (!empty($snort_pfb)) { - $log = " [ {$alias} {$header_url}, {$ip} ] snort2c IP Block Found in : [ {$snort_pfb} ]\n"; - pfb_logger("{$log}","2"); - } - } else { - $log = " [ {$alias} {$header_url} ] No host IP found \n"; - pfb_logger("{$log}","2"); - } + if (!empty($args)) { + exec("{$pfb['script']} {$args} {$header} {$pfb['max']} {$pfb['drep']} {$pfb['ccexclude']} {$pfb['ccwhite']} {$pfb['ccblack']} {$elog}"); } } - // UNSET variables - unset ($file_gz,$file_zip,$file_et,$file_xlsx,$url_other,$url_list); - } - } - } - // check custom network list - if (pfbng_text_area_decode($list['custom']) != "") { - if ($vtype == "_v4") { - $aliascustom = "{$list['aliasname']}_custom"; - } else { - $aliascustom = "{$list['aliasname']}_custom_v6"; - } - - // Collect Active Alias List (Used for pfctl Update when 'Reputation' is enabled. - $pfb_alias_lists_all[] = "{$alias}"; - - // Determine 'List' details (return array $pfbarr) - pfb_determine_list_detail($list['action'], $aliascustom, "", ""); - $pfb['skip'] = $pfbarr['skip']; - $pfbfolder = $pfbarr['folder']; - $log_tab = $pfbarr['logtab']; - - if (file_exists($pfbfolder . '/' . $aliascustom . '.txt') && $pfb['reuse'] == "") { - $log = "\n[ {$aliascustom} ]{$log_tab} exists, Reloading File [ NOW ]"; - pfb_logger("{$log}","1"); - } else { - $url_list = array(); - $log = "\n[ {$aliascustom} ]{$log_tab} Loading Custom File [ NOW ]\n"; - pfb_logger("{$log}","1"); - - $custom_list = pfbng_text_area_decode($list['custom']) . "\n"; - @file_put_contents($pfb['origdir'] . '/' . $aliascustom . '.orig', $custom_list, LOCK_EX); - $url_list = @file($pfb['origdir'] . '/' . $aliascustom . '.orig'); - - $new_file = ""; - if (!empty($url_list)) { - foreach ($url_list as $line) { - if ($vtype == "_v4") { - // Network range 192.168.0.0-192.168.0.254 - if (preg_match($pfb['range'],$line,$matches)) { - $a_cidr = ip_range_to_subnet_array_temp2($matches[1],$matches[2]); - if (!empty($a_cidr)) { - foreach ($a_cidr as $cidr) { - $new_file .= preg_replace($pfb_ipreg, '',$cidr) . "\n"; - } - } - } - // CIDR format 192.168.0.0/16 - elseif (preg_match($pfb['cidr'],$line,$matches)) { - $new_file .= preg_replace($pfb_ipreg, '',$matches[0]) . "\n"; - } - // Single ip addresses - elseif (preg_match($pfb['s_html'],$line,$matches)) { - $new_file .= preg_replace($pfb_ipreg, '',$matches[0]) . "\n"; - } - } else { - // IPv6 Regex - if (preg_match($pfb['ipv6'],$line,$matches)) { - $new_file .= preg_replace($pfb_ipreg, '',$matches[0]) . "\n"; - } + if (!$pfbadv && $list['vtype'] == '_v4') { + // Call Aggregate process + if ($pfb['agg'] == 'on') { + exec("{$pfb['script']} cidr_aggregate {$header} {$pfbfolder} {$elog}"); } } - } - if ($new_file != "") { - // PFCTL - Collect Only Aliases that have been updated only. + // Collect updated alias lists ('Reputation' disabled) $pfb_alias_lists[] = "{$alias}"; - // Collect Updated lists for Suppression Process - @file_put_contents($pfbfolder . '/'. $aliascustom . '.txt',$new_file, LOCK_EX); - // Enable Suppression Process due to Updates - if ($pfb['supp'] == "on" && $vtype == "_v4") { - $pfb['supp_update'] = TRUE; + + if ($pfbadv && $list['vtype'] == '_v4') { + // Execute Reputation functions, when changes are found. + $pfb['repcheck'] = TRUE; + + // Enable suppression process due to updates + if ($pfb['supp'] == 'on') { + $pfb['supp_update'] = TRUE; + } } - if ($pfb['rep'] == "on" && $pfb['skip'] && $vtype == "_v4") { - // Script to Call p24 Process - exec ("{$pfb['script']} p24 {$aliascustom} {$pfb['max']} {$pfb['dedup']} {$pfb['ccexclude']} {$pfb['ccwhite']} {$pfb['ccblack']} >> {$pfb['log']} 2>&1"); + } else { + if (!$custom) { + $log = "[ {$alias} {$header} ] List Error ]\n"; } - if ($pfb['dup'] == "on" && $pfb['skip'] && $vtype == "_v4") { - // Script to call Duplication Check Process - exec ("{$pfb['script']} duplicate {$aliascustom} >> {$pfb['log']} 2>&1"); + else { + $log = "[ {$alias} {$header} ] Custom List Error ]\n"; } - } else { - $log = "[ {$aliascustom} ] Custom List Error ]\n"; - pfb_logger("{$log}","1"); + pfb_logger("{$log}", 1); } + // Unset variables + unset($ip_data); } } } @@ -1945,40 +3629,47 @@ function sync_package_pfblockerng($cron = "") { # REPUTATION PROCESSES # ################################# - // IP Reputation processes (pdup and ddup) - if ($pfb['pdup'] == "on" && $pfb['dupcheck'] && !$pfb['save'] && $pfb['enable'] == "on") { - // Script to run pdup process - exec ("{$pfb['script']} pdup x {$pfb['pmax']} >> {$pfb['log']} 2>&1"); + // IP Reputation processes (pMax and dMax) + if ($pfb['prep'] == 'on' && $pfb['repcheck'] && !$pfb['save'] && $pfb['enable'] == 'on') { + // Script to run prep process + exec("{$pfb['script']} pmax x {$pfb['pmax']} {$elog}"); } - if ($pfb['dedup'] == "on" && $pfb['dupcheck'] && !$pfb['save'] && $pfb['enable'] == "on") { - // Script to run dedup process - exec ("{$pfb['script']} dedup x {$pfb['dmax']} {$pfb['dedup']} {$pfb['ccexclude']} {$pfb['ccwhite']} {$pfb['ccblack']} >> {$pfb['log']} 2>&1"); + if ($pfb['drep'] == 'on' && $pfb['repcheck'] && !$pfb['save'] && $pfb['enable'] == 'on') { + // Script to run drep process + exec("{$pfb['script']} dmax x {$pfb['dmax']} {$pfb['drep']} {$pfb['ccexclude']} {$pfb['ccwhite']} {$pfb['ccblack']} {$elog}"); } - ################################# - # CONFIGURE ALIASES # - ################################# + ################################################# + # CONFIGURE ALIASES AND FIREWALL RULES # + ################################################# - $list_type = array ("pfblockernglistsv4" => "_v4", "pfblockernglistsv6" => "_v6"); + $list_type = array('pfblockernglistsv4' => '_v4', 'pfblockernglistsv6' => '_v6'); foreach ($list_type as $ip_type => $vtype) { - if ($config['installedpackages'][$ip_type]['config'] != "" && $pfb['enable'] == "on") { - $runonce = 0; + if (!empty($config['installedpackages'][$ip_type]['config']) && $pfb['enable'] == 'on') { + $pfbrunonce = TRUE; foreach ($config['installedpackages'][$ip_type]['config'] as $key => $list) { - $alias = "pfB_" . preg_replace("/\W/","",$list['aliasname']); + $alias = 'pfB_' . preg_replace("/\W/", '', $list['aliasname']); - // Determine 'List' details (return array $pfbarr) - pfb_determine_list_detail($list['action'], "", $ip_type, $key); - $pfb['skip'] = $pfbarr['skip']; - $pfb_descr = $pfbarr['descr']; + // Skip any Alias that are 'enabled' but Lists/customlists are not defined. + if (empty($list['row'][0]['url']) && empty($list['custom'])) { + exec("{$pfb['pfctl']} -t {$alias} -T kill 2>&1", $result); + continue; + } + + // Determine 'list' details (return array $pfbarr) + pfb_determine_list_detail($list['action'], '', $ip_type, $key); + $pfbadv = $pfbarr['adv']; + $pfbdescr = $pfbarr['descr']; $pfbfolder = $pfbarr['folder']; $aports = $pfbarr['aports']; $adest = $pfbarr['adest']; $aproto = $pfbarr['aproto']; - // Re-Save Only Aliases that have been updated only. - // When 'Reputation' is used, all Aliases need to be Updated. + + // Only Save aliases that have been updated. + // When 'Reputation' is used, all aliases need to be updated. $final_alias = array(); - if ($pfb['dedup'] == "on" || $pfb['pdup'] == "on") { + if ($pfb['drep'] == 'on' || $pfb['prep'] == 'on') { if (!empty($pfb_alias_lists_all)) { $final_alias = array_unique($pfb_alias_lists_all); } @@ -1988,331 +3679,212 @@ function sync_package_pfblockerng($cron = "") { } } - if ($list['action'] != "Disabled") { - // remove empty lists files if any - if (is_array($list['row'])) { - $update = 0; - ${$alias} = ""; + if ($list['action'] != 'Disabled') { + $pfbupdate = FALSE; + $alias_ips = ''; // IP Collection of all Lists in the Alias + + if (isset($list['row'])) { foreach ($list['row'] as $row) { - if ($row['url'] != "" && $row['state'] != "Disabled") { - if ($vtype == "_v4") { - $header_url = "{$row['header']}"; + if (!empty($row['url']) && $row['state'] != 'Disabled') { + if ($vtype == '_v4') { + $header = "{$row['header']}"; } else { - $header_url = "{$row['header']}_v6"; + $header = "{$row['header']}_v6"; } - $pfctlck = exec ("/sbin/pfctl -vvsTables | grep -A1 {$alias} | awk '/Addresses/ {s+=$2}; END {print s}'"); - - // Update Alias if List File Exists and its been updated or if the Alias URL Table is Empty. - if (file_exists($pfbfolder . "/" . $header_url . ".txt") && in_array($alias, $final_alias) || file_exists($pfbfolder . "/" . $header_url . ".txt") && empty($pfctlck)) { - // Script to run Suppression process (Print Header Only) - if ($pfb['supp'] == "on" && $vtype == "_v4" && $runonce == 0 && $pfb['supp_update']) { - exec ("{$pfb['script']} suppress x x x suppressheader >> {$pfb['log']} 2>&1"); - $runonce++; + $pfctlck = exec("{$pfb['pfctl']} -vvsTables | {$pfb['grep']} -A1 {$alias} | {$pfb['awk']} '/Addresses/ {s+=$2}; END {print s}'"); + + // Update alias if list file exists and its been updated or if the alias URL table is empty. + if (file_exists("{$pfbfolder}/{$header}.txt") && (in_array($alias, $final_alias) || empty($pfctlck))) { + // Script to run suppression process (print header only) + if ($pfbrunonce && $pfb['supp'] == 'on' && $vtype == '_v4' && $pfb['supp_update']) { + exec("{$pfb['script']} suppress x x x suppressheader {$elog}"); + + // Process suppression for DNSBL IP table + if ($pfb['dnsbl'] == 'on' && $pfb['dnsbl_ip'] != 'Disabled') { + exec("{$pfb['script']} suppress x x x pfB_DNSBLIP\|{$pfb['aliasdir']}/ {$elog}"); + } + $pfbrunonce = FALSE; } - // Script to run Suppression Process (Body) - if ($pfb['supp'] == "on" && $vtype == "_v4" && $pfb['supp_update']) { - if ($pfb['dup'] == "on" || !$pfb['skip']) { - // Execute if Duplication Process is Enabled or List is Permit or Match - exec ("{$pfb['script']} suppress x x x {$header_url}\|{$pfbfolder}/ >> {$pfb['log']} 2>&1"); + // Script to run suppression process (body) + if ($pfb['supp'] == 'on' && $vtype == '_v4' && $pfb['supp_update'] && $pfbadv) { + if ($pfb['dup'] == 'on') { + exec("{$pfb['script']} suppress x x x {$header}\|{$pfbfolder}/ {$elog}"); } else { - // Execute if Duplication Process is Disabled - exec ("{$pfb['script']} suppress x x off {$header_url}\|{$pfbfolder}/ >> {$pfb['log']} 2>&1"); + exec("{$pfb['script']} suppress x x off {$header}\|{$pfbfolder}/ {$elog}"); } } - ${$alias} .= file_get_contents($pfbfolder . '/' . $header_url . '.txt'); - $update++; + $alias_ips .= file_get_contents("{$pfbfolder}/{$header}.txt"); + $pfbupdate = TRUE; } } } } // check custom network list - if ($vtype == "_v4") { + if ($vtype == '_v4') { $aliasname = "{$list['aliasname']}_custom"; } else { $aliasname = "{$list['aliasname']}_custom_v6"; } - // Update Alias if List File Exists and its been updated or if the Alias URL Table is Empty. - $pfctlck = exec ("/sbin/pfctl -vvsTables | grep -A1 {$alias} | awk '/Addresses/ {s+=$2}; END {print s}'"); + // Update alias if list file exists and its been updated or if the alias URL table is empty. + $pfctlck = exec("{$pfb['pfctl']} -vvsTables | {$pfb['grep']} -A1 {$alias} | {$pfb['awk']} '/Addresses/ {s+=$2}; END {print s}'"); - if (pfbng_text_area_decode($list['custom']) != "") { - if (file_exists($pfbfolder . "/" . $aliasname . ".txt") && in_array($alias, $final_alias) || file_exists($pfbfolder . "/" . $aliasname . ".txt") && empty($pfctlck)) { - ${$alias} .= file_get_contents($pfbfolder . '/' . $aliasname . '.txt'); - $update++; + if (!empty($list['custom'])) { + if (file_exists("{$pfbfolder}/{$aliasname}.txt") && in_array($alias, $final_alias) || + file_exists("{$pfbfolder}/{$aliasname}.txt") && empty($pfctlck)) { + $alias_ips .= file_get_contents("{$pfbfolder}/{$aliasname}.txt"); + $pfbupdate = TRUE; } } - // Determine Validity of Alias URL Tables/Rules. ie: Don't create Empty URL Tables or Aliases - if (${$alias} == "" && empty($pfctlck)) { - unlink_if_exists($pfb['aliasdir'] . '/' . $alias. '.txt'); + // Determine validity of alias URL tables/rules. ie: Don't create empty URL tables or aliases + if (empty($alias_ips) && empty($pfctlck)) { + unlink_if_exists("{$pfb['aliasdir']}/{$alias}.txt"); } else { - // Save Only Aliases that have been updated. - if ($update > 0) { - @file_put_contents($pfb['aliasdir'] . '/' . $alias. '.txt',${$alias}, LOCK_EX); + // Save only aliases that have been updated. + if ($pfbupdate) { + @file_put_contents("{$pfb['aliasdir']}/{$alias}.txt", $alias_ips, LOCK_EX); } - $alias_log = $list['aliaslog']; - // create alias - $new_aliases_list[] = "{$alias}"; + // Add '[s]' to Alias descriptions (Bypass States removal feature) + $adescr = "pfBlockerNG {$pfbdescr} List Alias"; + if ($list['stateremoval'] == 'disabled') { + $adescr = "pfBlockerNG {$pfbdescr} List Alias [s]"; + } - $new_aliases[] = array( "name" => "{$alias}", - "url" => "{$pfb['weblocal']}?pfb={$alias}", - "updatefreq" => "32", - "address" => "", - "descr" => "pfBlockerNG {$pfb_descr} List Alias", - "type" => "urltable", - "detail" => "DO NOT EDIT THIS ALIAS" + // Create alias + $new_aliases_list[] = "{$alias}"; + $new_aliases[] = array( 'name' => "{$alias}", + 'url' => "{$pfb['weblocal']}?pfb={$alias}", + 'updatefreq' => '32', + 'address' => '', + 'descr' => "{$adescr}", + 'type' => 'urltable', + 'detail' => 'DO NOT EDIT THIS ALIAS' ); - // Create rule if action permits - switch ($list['action']) { - case "Deny_Both": - case "Deny_Outbound": - $rule = $base_rule; - $rule['type'] = "{$pfb['deny_action_outbound']}"; - if ($vtype == "_v6") - $rule['ipprotocol'] = "inet6"; - if ($pfb['float'] == "on") - $rule['direction'] = "any"; - $rule['descr'] = "{$alias}{$pfb['suffix']}"; - $rule['source'] = array ("any" => ""); - $rule['destination'] = array ("address" => "{$alias}"); - if ($pfb['config']['enable_log'] == "on" || $alias_log == "enabled") - $rule['log'] = ""; - $deny_outbound[] = $rule; - if ($list['action'] != "Deny_Both") - break; - case "Deny_Inbound": - $rule = $base_rule; - $rule['type'] = "{$pfb['deny_action_inbound']}"; - if ($vtype == "_v6") - $rule['ipprotocol'] = "inet6"; - if ($pfb['float'] == "on") - $rule['direction'] = "any"; - $rule['descr'] = "{$alias}{$pfb['suffix']}"; - $rule['source'] = array("address" => "{$alias}"); - if (!empty($adest) && !empty($aports)) { - $rule['destination'] = array ("address" => "{$adest}", "port" => "{$aports}"); - } elseif (!empty($adest) && empty($aports)) { - $rule['destination'] = array ("address" => "{$adest}"); - } elseif (empty($adest) && !empty($aports)) { - $rule['destination'] = array ("any" => "", "port" => "{$aports}"); - } else { - $rule['destination'] = array ("any" => ""); - } - if (!empty($adest) && $list['autonot'] == "on") - $rule['destination']['not'] = ""; - if (!empty($aproto)) - $rule['protocol'] = "{$aproto}"; - if ($pfb['config']['enable_log'] == "on" || $alias_log == "enabled") - $rule['log'] = ""; - $deny_inbound[] = $rule; - break; - case "Permit_Both": - case "Permit_Outbound": - $rule = $base_rule; - $rule['type'] = "pass"; - if ($vtype == "_v6") - $rule['ipprotocol'] = "inet6"; - if ($pfb['float'] == "on") - $rule['direction'] = "any"; - $rule['descr'] = "{$alias}{$pfb['suffix']}"; - $rule['source'] = array ("any" => ""); - $rule['destination'] = array ("address" => "{$alias}"); - if ($pfb['config']['enable_log'] == "on" || $alias_log == "enabled") - $rule['log'] = ""; - $permit_outbound[] = $rule; - if ($list['action'] != "Permit_Both") - break; - case "Permit_Inbound": - $rule = $base_rule; - $rule['type'] = "pass"; - if ($vtype == "_v6") - $rule['ipprotocol'] = "inet6"; - if ($pfb['float'] == "on") - $rule['direction'] = "any"; - $rule['descr'] = "{$alias}{$pfb['suffix']}"; - $rule['source'] = array ("address" => "{$alias}"); - if (!empty($adest) && !empty($aports)) { - $rule['destination'] = array ("address" => "{$adest}", "port" => "{$aports}"); - } elseif (!empty($adest) && empty($aports)) { - $rule['destination'] = array ("address" => "{$adest}"); - } elseif (empty($adest) && !empty($aports)) { - $rule['destination'] = array ("any" => "", "port" => "{$aports}"); - } else { - $rule['destination'] = array ("any" => ""); - } - if (!empty($adest) && $list['autonot'] == "on") - $rule['destination']['not'] = ""; - if (!empty($aproto)) - $rule['protocol'] = "{$aproto}"; - if ($pfb['config']['enable_log'] == "on" || $alias_log == "enabled") - $rule['log'] = ""; - $permit_inbound[] = $rule; - break; - case "Match_Both": - case "Match_Outbound": - $rule = $base_rule_float; - $rule['type'] = "match"; - if ($vtype == "_v6") - $rule['ipprotocol'] = "inet6"; - $rule['direction'] = "any"; - $rule['descr'] = "{$alias}{$pfb['suffix']}"; - $rule['source'] = array ("any" => ""); - $rule['destination'] = array ("address" => "{$alias}"); - if ($pfb['config']['enable_log'] == "on" || $alias_log == "enabled") - $rule['log'] = ""; - $match_outbound[] = $rule; - if ($list['action'] != "Match_Both") - break; - case "Match_Inbound": - $rule = $base_rule_float; - $rule['type'] = "match"; - if ($vtype == "_v6") - $rule['ipprotocol'] = "inet6"; - $rule['direction'] = "any"; - $rule['descr'] = "{$alias}{$pfb['suffix']}"; - $rule['source'] = array ("address" => "{$alias}"); - if (!empty($adest) && !empty($aports)) { - $rule['destination'] = array ("address" => "{$adest}", "port" => "{$aports}"); - } elseif (!empty($adest) && empty($aports)) { - $rule['destination'] = array ("address" => "{$adest}"); - } elseif (empty($adest) && !empty($aports)) { - $rule['destination'] = array ("any" => "", "port" => "{$aports}"); - } else { - $rule['destination'] = array ("any" => ""); - } - if (!empty($adest) && $list['autonot'] == "on") - $rule['destination']['not'] = ""; - if (!empty($aproto)) - $rule['protocol'] = "{$aproto}"; - if ($pfb['config']['enable_log'] == "on" || $alias_log == "enabled") - $rule['log'] = ""; - $match_inbound[] = $rule; - break; - } - } - // mark pfctl aliastable for cleanup - if (!in_array($alias, $aliases_list)) { - $aliases_list[] = "{$alias}"; + // Define firewall rule settings + pfb_firewall_rule($list['action'], $alias, '', $list['aliaslog'], $adest, $aports, $aproto, $list['autonot']); } } else { - // unlink previous pfblockerNG alias list if any - unlink_if_exists($pfb['aliasdir'] . '/' . $alias . '.txt'); + // unlink previous pfblockerNG alias list + unlink_if_exists("{$pfb['aliasdir']}/{$alias}.txt"); } } } } - // Clear Variables - ${$alias} = ""; + // Clear variables + $alias_ips = ''; ######################################### # UPDATE pfSense ALIAS TABLES # ######################################### - // update pfsense alias table - if (is_array($config['aliases']['alias'])) { + // Reload config.xml to get any recent changes + $config = parse_config(true); + + $exist_aliases = $config['aliases']['alias']; + if (isset($config['aliases']['alias'])) { foreach ($config['aliases']['alias'] as $cbalias) { + + // Skip DNSBL IP aliastable as its updated independently + if ($cbalias['name'] == 'pfB_DNSBLIP') { + continue; + } + if (substr($cbalias['name'], 0, 4) == 'pfB_') { - // mark pfctl aliastable for cleaning - if (!in_array($cbalias['name'], $aliases_list)) { - $aliases_list[] = $cbalias['name']; // mark aliastable for cleaning - } - // remove previous aliastable file if alias is not defined any more + // Remove unreferenced pfB aliastable files if (!in_array($cbalias['name'], $new_aliases_list)) { - unlink_if_exists($pfb['aliasdir'] . '/' . $cbalias['name'] . ".txt"); + unlink_if_exists("{$pfb['aliasdir']}/{$cbalias['name']}.*"); } } else { $new_aliases[] = $cbalias; - - // Check Table Size - if (file_exists($pfb['aliasdir'] . '/' . $alias . '.txt') && $message == "") { - preg_match("/(\d+)/",exec("/usr/bin/grep -c ^ " . $pfb['aliasdir'] . '/' . $alias . '.txt'),$matches); - } - if (($matches[1] * 2.1) >= $pfb['table_limit']) { - // alias table too large - $message = "{$alias} alias table is too large. Reduce networks in list or increase 'Firewall Maximum Table Entries' value to at least " . (int)($matches[1] * 2.1) . ' in "system - advanced - Firewall/NAT" . '; - } } } } - // apply new alias table to xml - if ($message == "") { + // Update config.xml, if changes required + if ($exist_aliases != $new_aliases) { $config['aliases']['alias'] = $new_aliases; - $pfb['cron_mod'] = TRUE; + write_config('pfBlockerNG: saving Aliases'); } - // UNSET Variables - unset($new_aliases, $cbalias); + // Unset variables + unset($new_aliases, $exist_aliases); ######################### # Assign Rules # ######################### - // Only Execute if AutoRules are defined or if an Alias has been removed. - if ($pfb['autorules'] || $pfb['enable'] == "" || $pfb['remove']) { - if (count($deny_inbound) > 0 || count($permit_inbound) > 0 || count($match_inbound) > 0) { - if ($pfb['inbound_interfaces'] == "") { - $message = "Unable to apply rules. Inbound Interface option not configured."; + // Only execute if autorules are defined or if an alias has been removed. + if ($pfb['autorules'] || $pfb['enable'] == '' || $pfb['remove']) { + $message = ''; + if (count($pfb['deny_inbound']) > 0 || count($pfb['permit_inbound']) > 0 || count($pfb['match_inbound']) > 0) { + if (empty($pfb['inbound_interfaces'])) { + $message = " Unable to apply rules. Inbound interface option not configured."; } } - if (count($deny_outbound) > 0 || count($permit_outbound) > 0 || count($match_outbound) > 0) { - if ($pfb['outbound_interfaces'] == "") { - $message = "Unable to apply rules. Outbound Interface option not configured."; + if (count($pfb['deny_outbound']) > 0 || count($pfb['permit_outbound']) > 0 || count($pfb['match_outbound']) > 0) { + if (empty($pfb['outbound_interfaces'])) { + $message .= "\n Unable to apply rules. Outbound interface option not configured."; } } - if ($message == "") { - $new_rules = array(); - $permit_rules = array(); - $match_rules = array(); - $other_rules = array(); - $fpermit_rules = array(); - $fmatch_rules = array(); - $fother_rules = array(); + if (empty($message)) { + $new_rules = $permit_rules = $match_rules = $other_rules = $fpermit_rules = $fmatch_rules = $fother_rules = array(); + + // Reload config.xml to get any recent changes + $config = parse_config(true); - // Collect All Existing Rules + // New vs old rules array comparison + $orig_rules_nocreated = $new_rules_nocreated = array(); + + // Collect all existing rules $rules = $config['filter']['rule']; - // Collect Existing pfSense Rules 'Pass', 'Match' and 'Other' pfSense rules into new Arrays. + + // Collect existing pfSense rules 'pass', 'match' and 'other' pfSense rules into new arrays. if (!empty($rules)) { - foreach ($rules as $rule) { - if (!preg_match("/pfB_.*" . $pfb['suffix'] . "/",$rule['descr'])) { - // Floating rules collection 'Floating Pass/Match'. Balance to 'other' - if ($pfb['float'] == "on") { - if ($rule['type'] == "pass" && $rule['floating'] == "yes") { + foreach ($rules as $key => $rule) { + // Remove DNSBL floating rule + if ($rule['descr'] == 'pfB_DNSBL_Allow_access_to_VIP') { + // Remove 'created' tag + $orig_rules_nocreated[] = $rule; + unset($orig_rules_nocreated[$key]['created']); + continue; + } + + // Remove all exisiting rules that start with 'pfB_' in the Rule Description + if (substr($rule['descr'], 0, 4) != 'pfB_') { + // Floating rules collection 'Floating Pass/Match', balance to 'other' + if ($pfb['float'] == 'on') { + if ($rule['type'] == 'pass' && $rule['floating'] == 'yes') { $fpermit_rules[] = $rule; - } elseif ($rule['type'] == "match" && $rule['floating'] == "yes") { + } elseif ($rule['type'] == 'match' && $rule['floating'] == 'yes') { $fmatch_rules[] = $rule; - } elseif ($rule['floating'] == "yes") { + } elseif ($rule['floating'] == 'yes') { $fother_rules[] = $rule; } else { $other_rules[] = $rule; } } else { - // Collect only 'Selected Inbound and Outbound Interfaces'. Balance to 'Other' - if (in_array($rule['interface'],$pfb['inbound_interfaces']) || in_array($rule['interface'],$pfb['outbound_interfaces'])) { - // Floating Rules 'off'. Collect 'Floating Other', Balance to 'Other' - if ($rule['floating'] == "yes") { + // Collect only 'selected inbound and outbound interfaces'. balance to 'other' + if (in_array($rule['interface'], $pfb['inbound_interfaces']) || + in_array($rule['interface'], $pfb['outbound_interfaces'])) { + // Floating rules 'off'. Collect 'floating other', pass, balance to 'other' + if ($rule['floating'] == 'yes') { $fother_rules[] = $rule; - } elseif ($rule['type'] == "pass") { - if ($pfb['order'] == "order_0") { + } elseif ($rule['type'] == 'pass') { + if ($pfb['order'] == 'order_0') { $other_rules[] = $rule; } else { $permit_rules[] = $rule; } - } elseif ($rule['type'] == "match") { - if ($pfb['order'] == "order_0") { - $other_rules[] = $rule; - } else { - $match_rules[] = $rule; - } } else { $other_rules[] = $rule; } } else { - if ($rule['floating'] == "yes") { + if ($rule['floating'] == 'yes') { $fother_rules[] = $rule; } else { $other_rules[] = $rule; @@ -2320,6 +3892,10 @@ function sync_package_pfblockerng($cron = "") { } } } + + // Remove 'created' tag + $orig_rules_nocreated[] = $rule; + unset($orig_rules_nocreated[$key]['created']); } } @@ -2331,78 +3907,90 @@ function sync_package_pfblockerng($cron = "") { # ORDER 3 - pfBlockerNG (p/m) / pfBlockerNG Block/Reject / pfSense (p/m) # ################################################################################# - if ($pfb['float'] == "") { + if ($pfb['float'] == '') { if (!empty($fother_rules)) { foreach ($fother_rules as $cb_rules) { $new_rules[] = $cb_rules; } } } - if (!empty($fpermit_rules) && $pfb['order'] == "order_1") { - foreach ($fpermit_rules as $cb_rules) { - $new_rules[] = $cb_rules; + else { + if ($pfb['order'] == 'order_1') { + foreach (array($fpermit_rules, $fmatch_rules, $fother_rules) as $rtype) { + if (!empty($rtype)) { + foreach ($rtype as $cb_rules) { + $new_rules[] = $cb_rules; + } + } + } } } - if (!empty($fmatch_rules) && $pfb['order'] == "order_1") { - foreach ($fmatch_rules as $cb_rules) { - $new_rules[] = $cb_rules; + + // Define DNSBL 'Floating' pass rule for selected 'OPT' segments to be able to access the LAN DNSBL VIP + if ($pfb['enable'] == 'on' && $pfb['dnsbl'] == 'on' && $pfb['dnsbl_rule'] != 'Disabled' && !empty($pfb['dnsblconfig']['dnsbl_allow_int'])) { + if (isset($implode_interfaces) && isset($pfb['dnsbl_vip'])) { + $rule = $pfb['base_rule_float']; + $rule['tracker'] = pfb_tracker('pfB_DNSBL_Allow_access_to_VIP'); + $rule['type'] = 'pass'; + $rule['direction'] = 'any'; + $rule['interface'] = $implode_interfaces; + $rule['descr'] = 'pfB_DNSBL_Allow_access_to_VIP'; + $rule['source'] = array('any' => ''); + $rule['destination'] = array('address' => "{$pfb['dnsbl_vip']}"); + $rule['created'] = array('time' => (int)microtime(true), 'username' => 'Auto'); + $new_rules[] = $rule; } } - // Define Inbound Interface Rules + // Define inbound interface rules if (!empty($pfb['inbound_interfaces'])) { - $counter = 0; + $pfbrunonce = TRUE; foreach ($pfb['inbound_interfaces'] as $inbound_interface) { - if (!empty($permit_rules) && $pfb['order'] == "order_1") { + if ($pfb['order'] == 'order_1' && !empty($permit_rules)) { foreach ($permit_rules as $cb_rules) { - if ($cb_rules['interface'] == $inbound_interface) - $new_rules[] = $cb_rules; - } - } - if (!empty($match_rules) && $pfb['order'] == "order_1") { - foreach ($match_rules as $cb_rules) { - if ($cb_rules['interface'] == $inbound_interface) + if ($cb_rules['interface'] == $inbound_interface) { $new_rules[] = $cb_rules; + } } } - // Match Inbound Rules defined as Floating Only. - if (!empty($match_inbound) && $counter == 0) { - foreach ($match_inbound as $cb_rules) { + // Match inbound rules defined as floating only. + if ($pfbrunonce && !empty($pfb['match_inbound'])) { + foreach ($pfb['match_inbound'] as $cb_rules) { $cb_rules['interface'] = $pfb['inbound_floating']; $new_rules[] = $cb_rules; - $counter ++; + $pfbrunonce = FALSE; } } - if (!empty($permit_inbound)) { - foreach ($permit_inbound as $cb_rules) { + if ($pfb['order'] != 'order_0' && !empty($pfb['permit_inbound'])) { + foreach ($pfb['permit_inbound'] as $cb_rules) { $cb_rules['interface'] = $inbound_interface; $new_rules[] = $cb_rules; } } - if (!empty($fpermit_rules) && $pfb['order'] == "order_2") { - foreach ($fpermit_rules as $cb_rules) { - $new_rules[] = $cb_rules; - } - } - if (!empty($fmatch_rules) && $pfb['order'] == "order_2") { - foreach ($fmatch_rules as $cb_rules) { - $new_rules[] = $cb_rules; + if ($pfb['order'] == 'order_2') { + foreach (array($fpermit_rules, $fmatch_rules) as $rtype) { + if (!empty($rtype)) { + foreach ($rtype as $cb_rules) { + $new_rules[] = $cb_rules; + } + } } - } - if (!empty($permit_rules) && $pfb['order'] == "order_2") { - foreach ($permit_rules as $cb_rules) { - if ($cb_rules['interface'] == $inbound_interface) - $new_rules[] = $cb_rules; + if (!empty($permit_rules)) { + foreach ($permit_rules as $cb_rules) { + if ($cb_rules['interface'] == $inbound_interface) { + $new_rules[] = $cb_rules; + } + } } } - if (!empty($match_rules) && $pfb['order'] == "order_2") { - foreach ($match_rules as $cb_rules) { - if ($cb_rules['interface'] == $inbound_interface) - $new_rules[] = $cb_rules; + if (!empty($pfb['deny_inbound'])) { + foreach ($pfb['deny_inbound'] as $cb_rules) { + $cb_rules['interface'] = $inbound_interface; + $new_rules[] = $cb_rules; } } - if (!empty($deny_inbound)) { - foreach ($deny_inbound as $cb_rules) { + if ($pfb['order'] == 'order_0' && !empty($pfb['permit_inbound'])) { + foreach ($pfb['permit_inbound'] as $cb_rules) { $cb_rules['interface'] = $inbound_interface; $new_rules[] = $cb_rules; } @@ -2410,50 +3998,46 @@ function sync_package_pfblockerng($cron = "") { } } - // Define Outbound Interface Rules + // Define outbound interface rules if (!empty($pfb['outbound_interfaces'])) { - $counter = 0; + $pfbrunonce = TRUE; foreach ($pfb['outbound_interfaces'] as $outbound_interface) { - if (!empty($permit_rules) && $pfb['order'] == "order_1") { + if ($pfb['order'] == 'order_1' && !empty($permit_rules)) { foreach ($permit_rules as $cb_rules) { - if ($cb_rules['interface'] == $outbound_interface) - $new_rules[] = $cb_rules; - } - } - if (!empty($match_rules) && $pfb['order'] == "order_1") { - foreach ($match_rules as $cb_rules) { - if ($cb_rules['interface'] == $outbound_interface) + if ($cb_rules['interface'] == $outbound_interface) { $new_rules[] = $cb_rules; + } } } - // Match Outbound Rules defined as Floating Only. - if (!empty($match_outbound) && $counter == 0) { - foreach ($match_outbound as $cb_rules) { + // Match outbound rules defined as floating only. + if ($pfbrunonce && !empty($pfb['match_outbound'])) { + foreach ($pfb['match_outbound'] as $cb_rules) { $cb_rules['interface'] = $pfb['outbound_floating']; $new_rules[] = $cb_rules; - $counter++; + $pfbrunonce = FALSE; } } - if (!empty($permit_outbound)) { - foreach ($permit_outbound as $cb_rules) { + if ($pfb['order'] != 'order_0' && !empty($pfb['permit_outbound'])) { + foreach ($pfb['permit_outbound'] as $cb_rules) { $cb_rules['interface'] = $outbound_interface; $new_rules[] = $cb_rules; } } - if (!empty($permit_rules) && $pfb['order'] == "order_2") { + if ($pfb['order'] == 'order_2' && !empty($permit_rules)) { foreach ($permit_rules as $cb_rules) { - if ($cb_rules['interface'] == $outbound_interface) + if ($cb_rules['interface'] == $outbound_interface) { $new_rules[] = $cb_rules; + } } } - if (!empty($match_rules) && $pfb['order'] == "order_2") { - foreach ($match_rules as $cb_rules) { - if ($cb_rules['interface'] == $outbound_interface) - $new_rules[] = $cb_rules; + if (!empty($pfb['deny_outbound'])) { + foreach ($pfb['deny_outbound'] as $cb_rules) { + $cb_rules['interface'] = $outbound_interface; + $new_rules[] = $cb_rules; } } - if (!empty($deny_outbound)) { - foreach ($deny_outbound as $cb_rules) { + if ($pfb['order'] == 'order_0' && !empty($pfb['permit_outbound'])) { + foreach ($pfb['permit_outbound'] as $cb_rules) { $cb_rules['interface'] = $outbound_interface; $new_rules[] = $cb_rules; } @@ -2461,65 +4045,56 @@ function sync_package_pfblockerng($cron = "") { } } - if (!empty($fpermit_rules) && $pfb['order'] == "order_0") { - foreach ($fpermit_rules as $cb_rules) { - $new_rules[] = $cb_rules; - } - } - if (!empty($fmatch_rules) && $pfb['order'] == "order_0") { - foreach ($fmatch_rules as $cb_rules) { - $new_rules[] = $cb_rules; + if ($pfb['float'] == 'on' && in_array($pfb['order'], array('order_0', 'order_3'))) { + if ($pfb['order'] == 'order_0') { + $rule_order = array($fother_rules, $fpermit_rules, $fmatch_rules); + } else { + $rule_order = array($fpermit_rules, $fmatch_rules, $fother_rules); } - } - if (!empty($fpermit_rules) && $pfb['order'] == "order_3") { - foreach ($fpermit_rules as $cb_rules) { - $new_rules[] = $cb_rules; + foreach ($rule_order as $rtype) { + if (!empty($rtype)) { + foreach ($rtype as $cb_rules) { + $new_rules[] = $cb_rules; + } + } } } - if (!empty($fmatch_rules) && $pfb['order'] == "order_3") { - foreach ($fmatch_rules as $cb_rules) { + if ($pfb['float'] == 'on' && $pfb['order'] == 'order_2' && !empty($fother_rules)) { + foreach ($fother_rules as $cb_rules) { $new_rules[] = $cb_rules; } } - if (!empty($permit_rules) && $pfb['order'] == "order_3") { + if ($pfb['order'] == 'order_3' && !empty($permit_rules)) { foreach ($permit_rules as $cb_rules) { $new_rules[] = $cb_rules; } } - if (!empty($match_rules) && $pfb['order'] == "order_3") { - foreach ($match_rules as $cb_rules) { - $new_rules[] = $cb_rules; - } - } - if ($pfb['float'] == "on") { - if (!empty($fother_rules)) { - foreach ($fother_rules as $cb_rules) { - $new_rules[] = $cb_rules; - } - } - } if (!empty($other_rules)) { foreach ($other_rules as $cb_rules) { $new_rules[] = $cb_rules; } } - - // Save New Rule Order to Config - $config['filter']['rule'] = $new_rules; } - if (!empty($message)) { - $log = "\n {$message}\n"; - pfb_logger("{$log}","1"); + + // Unset arrays + unset($pfb['permit_inbound'], $pfb['permit_outbound'], $pfb['deny_inbound'], $pfb['deny_outbound'], $pfb['match_inbound'], $pfb['match_outbound']); + unset($cb_rules, $other_rules, $fother_rules, $permit_rules, $fpermit_rules, $match_rules, $fmatch_rules); + + // Remove 'created' tag (New vs old rules array comparison) + foreach ($new_rules as $key => $rule) { + $new_rules_nocreated[] = $rule; + unset($new_rules_nocreated[$key]['created']); } - // UNSET arrays - unset ($cb_rules,$permit_inbound,$permit_outbound,$deny_inbound,$deny_outbound,$match_inbound,$match_outbound); - unset ($other_rules,$fother_rules,$permit_rules,$fpermit_rules,$match_rules,$fmatch_rules); + // Update config.xml, if changes required + if ($pfb['autorules'] && $orig_rules_nocreated != $new_rules_nocreated) { + $config['filter']['rule'] = $new_rules; + write_config('pfBlockerNG: saving Firewall rules'); + } } - - // Set flag to Update config file. - if ($pfb['autorules'] && $rules != $new_rules) { - $pfb['cron_mod'] = TRUE; + else { + $log = "\n\n{$message}\n"; + pfb_logger("{$log}", 1); } ################################# @@ -2527,43 +4102,43 @@ function sync_package_pfblockerng($cron = "") { ################################# // If 'Rule Changes' are found, utilize the 'filter_configure()' function, if not, utilize 'pfctl replace' command - if ($pfb['autorules'] && $rules != $new_rules || $pfb['enable'] == "" || $pfb['remove']) { - require_once("filter.inc"); + if ($pfb['autorules'] && $orig_rules_nocreated != $new_rules_nocreated || $pfb['enable'] == '' || $pfb['remove']) { + require_once('filter.inc'); if (!$pfb['save']) { $log = "\n===[ Aliastables / Rules ]================================\n\n"; - pfb_logger("{$log}","1"); + pfb_logger("{$log}", 1); - $log = "Firewall Rule Changes Found, Applying Filter Reload\n"; - pfb_logger("{$log}","1"); + $log = "Firewall Rule Changes found, Applying Filter Reload\n"; + pfb_logger("{$log}", 1); } - // Remove all pfBlockerNG Alias tables - if (!empty($aliases_list)) { - foreach ($aliases_list as $table) { - exec ("/sbin/pfctl -t " . escapeshellarg($table) . " -T kill 2>&1", $pfb_null); + // Remove all pfB aliastables + exec("{$pfb['pfctl']} -s Tables | grep '^pfB_'", $pfb_tables); + if (isset($pfb_tables)) { + foreach ($pfb_tables as $pfb_table) { + exec("{$pfb['pfctl']} -t {$pfb_table} -T kill 2>&1", $result); } } - // load filter file which will create the pfctl tables - filter_configure(); + filter_configure(); // Load filter_configure which will create the pfctl tables + $pfb_filter_configure = TRUE; // Flag to skip State removal function due to pf reloading // Call function for NanoBSD/Ramdisk processes. - pfb_aliastables("update"); + pfb_aliastables('update'); } else { - // Don't Execute on User 'Save' + // Don't execute on user 'save' if (!$pfb['save']) { - - $log = "\n\n===[ Aliastables / Rules ]================================\n\n"; - pfb_logger("{$log}","1"); + $log = "\n\n===[ Aliastables / Rules ]==========================================\n\n"; + pfb_logger("{$log}", 1); $log = "No Changes to Firewall Rules, Skipping Filter Reload\n"; - pfb_logger("{$log}","1"); + pfb_logger("{$log}", 1); - // Re-Save Only Aliases that have been updated only. - // When 'Reputation' is used, all Aliases Need to be Updated. + // Only Save Aliases that have been updated. + // When 'Reputation' is used, all aliases need to be updated when any alias has been updated. $final_alias = array(); - if ($pfb['dedup'] == "on" || $pfb['pdup'] == "on") { + if ($pfb['repcheck'] && ($pfb['drep'] == 'on' || $pfb['prep'] == 'on')) { if (!empty($pfb_alias_lists_all)) { $final_alias = array_unique($pfb_alias_lists_all); } @@ -2576,120 +4151,301 @@ function sync_package_pfblockerng($cron = "") { if (!empty($final_alias)) { foreach ($final_alias as $final) { $log = "\n Updating: {$final}\n"; - pfb_logger("{$log}","1"); - $result_pfctl = ""; + pfb_logger("{$log}", 1); + $result = ''; if (file_exists("{$pfb['aliasdir']}/{$final}.txt")) { - exec ("/sbin/pfctl -t " . escapeshellarg($final) . " -T replace -f " . $pfb['aliasdir'] . "/" . escapeshellarg($final) . ".txt 2>&1", $result_pfctl); - $log = implode($result_pfctl); + exec("{$pfb['pfctl']} -t {$final} -T replace -f {$pfb['aliasdir']}/{$final}.txt 2>&1", $result); + $log = implode($result); } else { $log = "Aliastable file not found\n"; } - pfb_logger("{$log}","1"); + pfb_logger("{$log}", 1); } - pfb_logger("\n","1"); + pfb_logger("\n", 1); // Call function for NanoBSD/Ramdisk processes. - pfb_aliastables("update"); + pfb_aliastables('update'); } else { $log = "No Changes to Aliases, Skipping pfctl Update\n"; - pfb_logger("{$log}","1"); + pfb_logger("{$log}", 1); } } } - // UNSET Variables - unset($rules, $new_rules); - - // sync config - pfblockerng_sync_on_changes(); + // Unset arrays + unset($rules, $new_rules, $orig_rules_nocreated, $new_rules_nocreated); ################################# - # FINAL REPORTING # + # SAVE CONFIGURATION # ################################# - // Only run with CRON or Force Invoked Process - if ((!$pfb['save'] && $pfb['dupcheck'] && $pfb['enable'] == "on") || $pfb['summary']) { - // Script to run Final Script Processes. - exec ("{$pfb['script']} closing {$pfb['dup']} >> {$pfb['log']} 2>&1"); + // Uncheck reusing existing downloads check box + if (!$pfb['save'] && $pfb['enable'] == 'on' && $pfb['config']['pfb_reuse'] == 'on') { + $pfb_config['installedpackages']['pfblockerng']['config'][0]['pfb_reuse'] = ''; + $pfb['conf_mod'] = TRUE; } - if ($pfb['enable'] == "on" && !$pfb['save'] || $pfb['summary']) { - $log = "\n UPDATE PROCESS ENDED [ NOW ]\n"; - pfb_logger("{$log}","1"); + // Only save config.xml, if changes are found. + if ($pfb['conf_mod'] && isset($pfb_config)) { + // Reload config.xml to get any recent changes and merge/save changes. + $config = parse_config(true); + $config = array_replace_recursive($config, $pfb_config); + write_config('pfBlockerNG: save settings'); + } + + + ################################# + # KILL STATES # + ################################# + + if ($pfb['kstates'] && !$pfb_filter_configure) { + + $log = "\n===[ Kill States ]==================================================\n\n"; + pfb_logger("{$log}", 1); + + $tablesin = $tablesout = array(); + if (!empty($config['filter']['rule'])) { + foreach ($config['filter']['rule'] as $rule) { + + // Collect all 'pfB_' Rules that are 'Block/Reject' and do not have bypass states enabled + if (strpos($rule['descr'], '[s]') === FALSE && ($rule['type'] == 'block' || $rule['type'] == 'reject') && + (strpos($rule['source']['address'], 'pfB_') !== FALSE || strpos($rule['destination']['address'], 'pfB_') !== FALSE)) { + + if (isset($rule['source']['address'])) { + $tablesin[] = $rule['source']['address']; + } else { + $tablesout[] = $rule['destination']['address']; + } + } + } + } + + $pfb_supp = array(); // List of IPs to suppress + + // Collect pfBlockerNGSuppress alias IPs + $pfb_suppalias = array(); + if (isset($config['aliases']['alias'])) { + foreach ($config['aliases']['alias'] as $key => $alias) { + if ($alias['name'] == 'pfBlockerNGSuppress') { + // Strip any '/32' CIDR values + $pfb_suppalias = str_replace('/32', '', explode(' ', $config['aliases']['alias'][$key]['address'])); + } + } + + // Convert '/24' CIDRs + if (!empty($pfb_suppalias)) { + $pfb_suppaliascidr = array(); + foreach ($pfb_suppalias as $key => $subnet) { + if (strpos($subnet, '/24') !== FALSE) { + $pfb_suppaliascidr = subnetv4_expand($subnet); + unset($pfb_suppalias[$key]); + } + } + $pfb_supp = array_merge($pfb_supp, $pfb_suppaliascidr); + } + $pfb_supp = array_merge($pfb_supp, $pfb_suppalias); + } + + $pfb_supp[] = '0.0.0.0'; // Add 0.0.0.0 to suppression array + + // Collect Gateway IP addresses to suppress + $int_gateway = get_interfaces_with_gateway(); + if (isset($int_gateway)) { + foreach ($int_gateway as $gateway) { + $convert = get_interface_ip($gateway); + $pfb_supp[] = $convert; + } + } + + // Collect DNS servers to suppress + $pfb_dnsservers = get_dns_servers(); + if (!empty($pfb_dnsservers)) { + $pfb_supp = array_merge($pfb_supp, $pfb_dnsservers); + } + + // Remove any duplicate IPs + $pfb_supp = array_unique($pfb_supp); + + $statesin = $statesout = array(); + exec("{$pfb['pfctl']} -s state", $s_matches); + if (!empty($s_matches)) { + foreach ($s_matches as $key => $sline) { + + // SAMPLE : em0 udp 93.15.36.22:6881 -> 192.168.0.3:681 MULTIPLE:MULTIPLE + // SAMPLE : pppoe0 udp 35.170.3.40:57197 (192.168.0.45:681) -> 22.41.123.206:1001 MULTIPLE:MULTIPLE + // SAMPLE : em0 tcp 2001:65c:1398:101:124[443] <- 2001:170:2f:3e:a4c4:7b23:fe5f:b36e[52725] FIN_WAIT_2:FIN_WAIT_2 + + // Remove '( text )' from state line + if (strpos($sline, '(') !== FALSE) { + $s_pos1 = strpos($sline, '('); + $s_pos2 = strpos($sline, ')'); + $s_len = $s_pos2 - $s_pos1 + 2; + $sline = substr_replace($sline, '', $s_pos1, $s_len); + } + + if (!empty($sline)) { + list($int, $proto, $dir1, $sdirection, $dir2) = explode(' ', $sline); + + if ($sdirection == '<-') { + // Inbound State + $s_ip = $dir1; + } else { + // Outbound State + $s_ip = $dir2; + } + + // Strip port + if (strpos($s_ip, '[') !== FALSE) { + // Strip IPv6 port + $s_ip = strstr($s_ip, '[', TRUE); + } else { + if (strpos($s_ip, ':') !== FALSE) { + // Strip IPv4 port + $s_ip = strstr($s_ip, ':', TRUE); + } + } + + // Exclude private, reserved and loopback IPs + if (filter_var($s_ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) && + filter_var($s_ip, FILTER_CALLBACK, array('options' => 'FILTER_FLAG_NO_LOOPBACK_RANGE'))) { + if ($sdirection == '<-') { + $statesin[] = $s_ip; + } else { + $statesout[] = $s_ip; + } + } + } + } + } + + $statesin = array_unique($statesin); + natsort($statesin); + $statesout = array_unique($statesout); + natsort($statesout); + + $pfbfound = FALSE; + foreach (array('<-' => $statesin, '->' => $statesout) as $s_type => $s_state_ips) { + foreach ($s_state_ips as $s_ip) { + if (!in_array($s_ip, $pfb_supp)) { + if ($s_type == '<-') { + $type = '-Inbound'; + $s_tables = $tablesin; + } else { + $type = '-Outbound'; + $s_tables = $tablesout; + } + + foreach ($s_tables as $s_table) { + $result = substr(exec("{$pfb['pfctl']} -t {$s_table} -T test {$s_ip} 2>&1"), 0, 1); + if ($result > 0) { + $pfbfound = TRUE; + $log = " [ {$s_table}{$type} ] Removed state(s) for [ {$s_ip} ]\n"; + pfb_logger("{$log}", 1); + foreach ($s_matches as $s_line) { + if (strpos($s_line, $s_type) !== FALSE && strpos($s_line, $s_ip) !== FALSE) { + pfb_logger(" {$s_line}\n", 1); + } + } + + // Remove states + if ($s_type == '<-') { + // Kill all state entries originating from $s_ip + exec("{$pfb['pfctl']} -k {$s_ip}"); + } else { + // Kill all state entries to the target $s_ip + exec("{$pfb['pfctl']} -k 0.0.0.0/0 -k {$s_ip}"); + } + } + } + } + } + } + if ($pfbfound) { + pfb_logger("\n======================================================================\n", 1); + } else { + pfb_logger(" No matching states found\n======================================================================\n", 1); + } } ######################################### + # XMLRPC - sync process # + ######################################### + + if (!platform_booting() && !$g['pfblockerng_install']) { + pfblockerng_sync_on_changes(); + } + + ######################################### # Define/Apply CRON Jobs # ######################################### - // Replace Cron job with any User Changes to $pfb_min - if ($pfb['enable'] == "on") { - // Define pfBlockerNG CRON Job - $pfb_cmd = "/usr/local/bin/php /usr/local/www/pfblockerng/pfblockerng.php cron >> {$pfb['log']} 2>&1"; - // $pfb['min'] ( User Defined Variable. Variable defined at start of Script ) + // Replace CRON job with any user changes to $pfb_min + if ($pfb['enable'] == 'on') { + // Define pfBlockerNG CRON job + $pfb_cmd = "/usr/local/bin/php /usr/local/www/pfblockerng/pfblockerng.php cron >> {$pfb['log']} 2>&1"; + // $pfb['min'] ( User defined variable. Variable defined at start of script ) - // Define Cron hour (Cron Interval & Start Hour) + // Define CRON hour (CRON interval & start hour) if ($pfb['interval'] == 1) { - $pfb_hour = "*"; + $pfb_hour = '*'; } elseif ($pfb['interval'] == 24) { $pfb_hour = $pfb['24hour']; } else { - $pfb_hour = implode(",", pfb_cron_base_hour()); + $pfb_hour = implode(',', pfb_cron_base_hour()); } - $pfb_mday = "*"; - $pfb_month = "*"; - $pfb_wday = "*"; - $pfb_who = "root"; + $pfb_mday = '*'; + $pfb_month = '*'; + $pfb_wday = '*'; + $pfb_who = 'root'; - // Determine if Cron Task requires updating + // Determine if CRON job requires updating if (!pfblockerng_cron_exists($pfb_cmd, $pfb['min'], $pfb_hour)) { install_cron_job($pfb_cmd, true, $pfb['min'], $pfb_hour, $pfb_mday, $pfb_month, $pfb_wday, $pfb_who); } } else { - // Clear any existing pfBlockerNG Cron Jobs - install_cron_job("pfblockerng.php cron", false); + // Clear any existing pfBlockerNG CRON jobs + install_cron_job('pfblockerng.php cron', false); } - if ($pfb['enable'] == "on") { - // Define pfBlockerNG MaxMind CRON Job - $pfb_gcmd = "/usr/local/bin/php /usr/local/www/pfblockerng/pfblockerng.php dc >> {$pfb['geolog']} 2>&1"; - // MaxMind GeoIP Cron Hour is randomized between 0-23 Hour to minimize effect on MaxMind Website - $pfb_gmin = "0"; + if ($pfb['enable'] == 'on') { + // Define pfBlockerNG MaxMind CRON job + $pfb_gcmd = "/usr/local/bin/php /usr/local/www/pfblockerng/pfblockerng.php dc >> {$pfb['extraslog']} 2>&1"; + // MaxMind GeoIP CRON hour is randomized between 0-23 Hour to minimize effect on MaxMind website + $pfb_gmin = '0'; $pfb_ghour = rand(0,23); - $pfb_gmday = "1,2,3,4,5,6,7"; - $pfb_gmonth = "*"; - $pfb_gwday = "2"; - $pfb_gwho = "root"; + $pfb_gmday = '1,2,3,4,5,6,7'; + $pfb_gmonth = '*'; + $pfb_gwday = '2'; + $pfb_gwho = 'root'; - // Determine if Cron Task requires updating + // Determine if CRON job requires updating if (!pfblockerng_cron_exists($pfb_gcmd, $pfb_gmin, 'maxmind')) { install_cron_job($pfb_gcmd, true, $pfb_gmin, $pfb_ghour, $pfb_gmday, $pfb_gmonth, $pfb_gwday, $pfb_gwho); } } else { - // Clear any existing pfBlockerNG Cron Jobs - install_cron_job("pfblockerng.php dc", false); + // Clear any existing pfBlockerNG CRON jobs + install_cron_job('pfblockerng.php dc', false); } ################################# - # Closing Processes # + # FINAL REPORTING # ################################# - // uncheck Reusing Existing Downloads Check box - if (!$pfb['save'] && $pfb['enable'] == "on" && $pfb['reuse'] == "on") { - $config['installedpackages']['pfblockerng']['config'][0]['pfb_reuse'] = ""; - $pfb['cron_mod'] = TRUE; + // Only run with CRON or Force invoked process + if ((!$pfb['save'] && $pfb['repcheck'] && $pfb['enable'] == 'on') || $pfb['summary']) { + // Script to run final script processes. + exec("{$pfb['script']} closing {$pfb['dup']} {$elog}"); } - // Only save config.xml changes if changes are found. - // Temporay to ensure all conditions are defined before fully enabling this feature - if ($pfb['cron_mod'] || !$pfb['cron_mod']) { - write_config("pfBlockerNG: Save settings"); + if ($pfb['enable'] == 'on' && !$pfb['save'] || $pfb['summary']) { + $log = "\n UPDATE PROCESS ENDED [ NOW ]\n"; + pfb_logger("{$log}", 1); } } @@ -2699,151 +4455,191 @@ function pfblockerng_validate_input($post, &$input_errors) { foreach ($post as $key => $value) { - if (substr($key, 0, 3) == "url" && is_numeric( substr($key, 3, (strlen($key) - 3))) ) { + if (substr($key, 0, 3) == 'url' && is_numeric( substr($key, 3, (strlen($key) - 3))) ) { if (empty($value)) { $input_url_empty = TRUE; continue; } if (substr($value, 0, 1) == ' ') { - $input_errors[] = "Leading whitespace not allowed in URL field"; + $input_errors[] = 'Leading whitespace not allowed in URL field'; } } - if (substr($key, 0, 6) == "header" && is_numeric( substr($key, 6, (strlen($key) - 6))) ) { + if (substr($key, 0, 6) == 'header' && is_numeric( substr($key, 6, (strlen($key) - 6))) ) { if ($input_url_empty && empty($value)) { $input_url_empty = FALSE; continue; } if ($input_url_empty && !empty($value)) { - $input_errors[] = "No URL Defined."; + $input_errors[] = 'No URL Defined.'; } if (substr($value, 0, 1) == ' ' || empty($value)) { - $input_errors[] = "Header field must be defined."; + $input_errors[] = 'Header field must be defined.'; + } + } + + if ($key == 'pfb_dnsbl' && $value == 'on') { + $pfb_dnsbl_state = TRUE; + } + + if ($pfb_dnsbl_state) { + if ($key == 'pfb_dnsvip' && empty($value)) { + $input_errors[] = 'DNSBL VIP address must be defined.'; + } + if ($key == 'pfb_dnsport' && empty($value) || $key == 'pfb_dnsport_ssl' && empty($value)) { + $input_errors[] = 'DNSBL Port must be defined.'; + } + if ($key == 'pfb_dnsport' && !is_port($value) || $key == 'pfb_dnsport_ssl' && !is_port($value)) { + $input_errors[] = 'DNSBL Port must be a valid port in the range of 1 - 65535'; } } } } + +// Function to De-Install pfBlockerNG function pfblockerng_php_deinstall_command() { - require_once("config.inc"); - global $config,$pfb; + require_once('config.inc'); + global $config, $pfb, $static_output; - // Set these two variables to Disable pfBlockerNG on De-Install + // Set these two variables to disable pfBlockerNG on de-install $pfb['save'] = TRUE; $pfb['install'] = TRUE; + sync_package_pfblockerng(); - rmdir_recursive("/usr/local/pkg/pfblockerng"); - rmdir_recursive("/usr/local/www/pfblockerng"); + rmdir_recursive('/usr/local/pkg/pfblockerng'); + rmdir_recursive('/usr/local/www/pfblockerng'); - // Maintain pfBlockerNG Settings and Database Files if $pfb['keep'] is ON. - if ($pfb['keep'] != "on") { - // Remove pfBlockerNG Log and DB Folder + // Maintain pfBlockerNG settings and database files if $pfb['keep'] is ON. + if ($pfb['keep'] != 'on') { + // Remove pfBlockerNG log and DB folder rmdir_recursive("{$pfb['dbdir']}"); rmdir_recursive("{$pfb['logdir']}"); - // Remove Aliastables archive and earlyshellcmd if found. + // Remove aliastables archive and earlyshellcmd if found. @unlink_if_exists("{$pfb['aliasarchive']}"); - if (is_array($config['system']['earlyshellcmd'])) { + if (isset($config['system']['earlyshellcmd'])) { $a_earlyshellcmd = &$config['system']['earlyshellcmd']; if (preg_grep("/pfblockerng.sh aliastables/", $a_earlyshellcmd)) { $a_earlyshellcmd = preg_grep("/pfblockerng.sh aliastables/", $a_earlyshellcmd, PREG_GREP_INVERT); } } - // Remove Settings from Config - if (is_array($config['installedpackages']['pfblockerng'])) + // Remove settings from config + if (isset($config['installedpackages']['pfblockerng'])) unset($config['installedpackages']['pfblockerng']); - if (is_array($config['installedpackages']['pfblockerngglobal'])) + if (isset($config['installedpackages']['pfblockerngglobal'])) unset($config['installedpackages']['pfblockerngglobal']); - if (is_array($config['installedpackages']['pfblockerngsync'])) + if (isset($config['installedpackages']['pfblockerngsync'])) unset($config['installedpackages']['pfblockerngsync']); - if (is_array($config['installedpackages']['pfblockerngreputation'])) + if (isset($config['installedpackages']['pfblockerngreputation'])) unset($config['installedpackages']['pfblockerngreputation']); - if (is_array($config['installedpackages']['pfblockernglistsv4'])) + if (isset($config['installedpackages']['pfblockernglistsv4'])) unset($config['installedpackages']['pfblockernglistsv4']); - if (is_array($config['installedpackages']['pfblockernglistsv6'])) + if (isset($config['installedpackages']['pfblockernglistsv6'])) unset($config['installedpackages']['pfblockernglistsv6']); - if (is_array($config['installedpackages']['pfblockerngafrica'])) + if (isset($config['installedpackages']['pfblockerngdnsbl'])) + unset($config['installedpackages']['pfblockerngdnsbl']); + if (isset($config['installedpackages']['pfblockerngdnsblsettings'])) + unset($config['installedpackages']['pfblockerngdnsblsettings']); + if (isset($config['installedpackages']['pfblockerngdnsbleasylist'])) + unset($config['installedpackages']['pfblockerngdnsbleasylist']); + if (isset($config['installedpackages']['pfblockerngafrica'])) unset($config['installedpackages']['pfblockerngafrica']); - if (is_array($config['installedpackages']['pfblockerngantartica'])) + if (isset($config['installedpackages']['pfblockerngantartica'])) unset($config['installedpackages']['pfblockerngantartica']); - if (is_array($config['installedpackages']['pfblockerngasia'])) + if (isset($config['installedpackages']['pfblockerngasia'])) unset($config['installedpackages']['pfblockerngasia']); - if (is_array($config['installedpackages']['pfblockerngeurope'])) + if (isset($config['installedpackages']['pfblockerngeurope'])) unset($config['installedpackages']['pfblockerngeurope']); - if (is_array($config['installedpackages']['pfblockerngnorthamerica'])) + if (isset($config['installedpackages']['pfblockerngnorthamerica'])) unset($config['installedpackages']['pfblockerngnorthamerica']); - if (is_array($config['installedpackages']['pfblockerngoceania'])) + if (isset($config['installedpackages']['pfblockerngoceania'])) unset($config['installedpackages']['pfblockerngoceania']); - if (is_array($config['installedpackages']['pfblockerngsouthamerica'])) + if (isset($config['installedpackages']['pfblockerngsouthamerica'])) unset($config['installedpackages']['pfblockerngsouthamerica']); - if (is_array($config['installedpackages']['pfblockerngtopspammers'])) + if (isset($config['installedpackages']['pfblockerngtopspammers'])) unset($config['installedpackages']['pfblockerngtopspammers']); - if (is_array($config['installedpackages']['pfblockerngproxyandsatellite'])) + if (isset($config['installedpackages']['pfblockerngproxyandsatellite'])) unset($config['installedpackages']['pfblockerngproxyandsatellite']); + + unlink_if_exists('/usr/local/sbin/lighttpd_pfb'); + unlink_if_exists("{$pfb['dnsbl_conf']}"); + unlink_if_exists("{$pfb['dnsbl_cert']}"); + unlink_if_exists("{$pfb['dnsbl_info']}"); + unlink_if_exists("{$pfb['aliasarchive']}"); } - // Remove Widget (code from Snort deinstall) + // Remove widget (code from Snort deinstall) $pfb['widgets'] = $config['widgets']['sequence']; if (!empty($pfb['widgets'])) { - $widgetlist = explode(",", $pfb['widgets']); + $widgetlist = explode(',', $pfb['widgets']); foreach ($widgetlist as $key => $widget) { - if (strstr($widget, "pfblockerng-container")) { + if (strpos($widget, 'pfblockerng-container') !== FALSE) { unset($widgetlist[$key]); } } - $config['widgets']['sequence'] = implode(",", $widgetlist); + $config['widgets']['sequence'] = implode(',', $widgetlist); + write_config('pfBlockerNG: Remove widget'); } - update_output_window(gettext("pfBlockerNG has been Uninstalled")); + + $static_output .= 'pfBlockerNG has been uninstalled.'; + update_output_window($static_output); } + /* Uses XMLRPC to synchronize the changes to a remote node */ function pfblockerng_sync_on_changes() { - global $config, $g, $pfb_sync; + global $config; - // Create Array of Sync Settings and exit if Sync is Disabled. - if (is_array($config['installedpackages']['pfblockerngsync']['config'][0])) { + // Create array of sync settings and exit if sync is disabled. + if (isset($config['installedpackages']['pfblockerngsync']['config'][0])) { $pfb_sync = $config['installedpackages']['pfblockerngsync']['config'][0]; - if ($pfb_sync['varsynconchanges'] == "disabled" || $pfb_sync['varsynconchanges'] == "") { + if ($pfb_sync['varsynconchanges'] == 'disabled' || empty($pfb_sync['varsynconchanges'])) { return; } - $synctimeout = $pfb_sync['varsynctimeout']; + $synctimeout = $pfb_sync['varsynctimeout'] ?: '150'; } else { return; } - log_error("[pfBlockerNG] XMLRPC sync is starting."); + syslog(LOG_NOTICE, '[pfBlockerNG] XMLRPC sync is starting.'); - if (is_array($config['installedpackages']['pfblockerngsync']['config'])) { + if (isset($config['installedpackages']['pfblockerngsync']['config'])) { switch ($pfb_sync['varsynconchanges']) { - case "manual": - if (is_array($pfb_sync['row'])) { + case 'manual': + if (isset($pfb_sync['row'])) { $rs = $pfb_sync['row']; } else { - log_error("[pfBlockerNG] Manual XMLRPC sync is enabled but there are no replication targets configured."); + log_error('[pfBlockerNG] Manual XMLRPC sync is enabled but there are no replication targets configured.'); return; } break; - case "auto": - if (is_array($config['installedpackages']['carpsettings']) && is_array($config['installedpackages']['carpsettings']['config'])) { - $system_carp = $config['installedpackages']['carpsettings']['config'][0]; - $rs[0]['varsyncipaddress'] = $system_carp['synchronizetoip']; - $rs[0]['varsyncusername'] = $system_carp['username']; - $rs[0]['varsyncpassword'] = $system_carp['password']; + case 'auto': + if (isset($config['hasync'])) { + $system_carp = $config['hasync']; + $rs[0]['varsyncipaddress'] = $system_carp['synchronizetoip']; + $rs[0]['varsyncusername'] = $system_carp['username']; + $rs[0]['varsyncpassword'] = $system_carp['password']; + $rs[0]['varsyncdestinenable'] = FALSE; // XMLRPC sync is currently only supported over connections using the same protocol and port as this system - if ($config['system']['webgui']['protocol'] == "http") { - $rs[0]['varsyncprotocol'] = "http"; + if ($config['system']['webgui']['protocol'] == 'http') { + $rs[0]['varsyncprotocol'] = 'http'; + $rs[0]['varsyncport'] = $config['system']['webgui']['port'] ?: '80'; } else { - $rs[0]['varsyncprotocol'] = "https"; + $rs[0]['varsyncprotocol'] = 'https'; + $rs[0]['varsyncport'] = $config['system']['webgui']['port'] ?: '443'; } - if ($system_carp['synchronizetoip'] == "") { - log_error("[pfBlockerNG] XMLRPC sync is enabled but there is no sync IP address configured."); + if (empty($system_carp['synchronizetoip'])) { + log_error('[pfBlockerNG] Auto XMLRPC sync is enabled but there is no sync IP address configured.'); return; + } else { + $rs[0]['varsyncdestinenable'] = TRUE; } } else { - log_error("[pfBlockerNG] Auto XMLRPC sync is enabled but there are no replication targets configured."); + log_error('[pfBlockerNG] Auto XMLRPC sync is enabled but there are no replication targets configured.'); return; } break; @@ -2851,27 +4647,42 @@ function pfblockerng_sync_on_changes() { return; break; } - if (is_array($rs)) { + if (isset($rs)) { foreach ($rs as $sh) { - // Only Sync Enabled Replication Targets - if ($sh['varsyncdestinenable'] == "ON") { - $sync_to_ip = $sh['varsyncipaddress']; - $port = $sh['varsyncport']; - $password = htmlspecialchars($sh['varsyncpassword']); - $protocol = $sh['varsyncprotocol']; - - if (!empty($sh['varsyncusername'])) { - $username = $sh['varsyncusername']; - } else { - $username = "admin"; + // Only sync enabled replication targets + if ($sh['varsyncdestinenable']) { + $sync_to_ip = $sh['varsyncipaddress']; + $port = $sh['varsyncport']; + $password = $sh['varsyncpassword']; + $protocol = $sh['varsyncprotocol']; + $username = $sh['varsyncusername'] ?: 'admin'; + + $validate = TRUE; + $error = '| '; + + if (empty($password)) { + $error .= 'Password parameter missing. | '; + $validate = FALSE; + } + if (!is_ipaddr($sync_to_ip) && !is_hostname($sync_to_ip) && !is_domain($sync_to_ip)) { + $error .= 'Mis-configured Target IP/Host address. | '; + $validate = FALSE; + } + if (!is_port($port)) { + $error .= 'Mis-configured Target Port setting. |'; + $validate = FALSE; } - pfblockerng_do_xmlrpc_sync($sync_to_ip, $port, $protocol, $username, $password, $synctimeout); + if ($validate) { + pfblockerng_do_xmlrpc_sync($sync_to_ip, $port, $protocol, $username, $password, $synctimeout); + if ($success) { + syslog(LOG_NOTICE, "[pfBlockerNG] XMLRPC sync to [ {$sync_to_ip}:{port} ] completed successfully."); + } + } else { + log_error("[pfBlockerNG] XMLRPC sync to [ {$sync_to_ip}:{port} ] terminated due to the following error(s): {$error}"); + } } } - if ($success) { - log_error("[pfBlockerNG] XMLRPC sync completed successfully."); - } } } } @@ -2879,82 +4690,59 @@ function pfblockerng_sync_on_changes() { /* Do the actual XMLRPC sync */ function pfblockerng_do_xmlrpc_sync($sync_to_ip, $port, $protocol, $username, $password, $synctimeout) { - global $config, $g, $pfb_sync; + global $config, $g; $success = TRUE; - /* Exit on missing parameters */ - if (empty($sync_to_ip) || empty($password)) { - log_error("[pfBlockerNG] XMLRPC sync parameter missing (host IP or password) ... aborting xmlrpc sync"); - $success = FALSE; - return $success; - } + // Take care of IPv6 literal address + if (is_ipaddrv6($sync_to_ip)) { + $sync_to_ip = "[{$sync_to_ip}]"; + } - /* Do not attempt a package sync while booting up or installing package */ - if ($g['booting'] || $g['pfblockerng_postinstall']) { - log_error("[pfBlockerNG] XMLRPC sync to Replication targets terminated during boot up or during package reinstallation."); - $success = FALSE; - return $success; - } - - // Validate Replication Target IP Address and Port Settings - if (!is_ipaddr($sync_to_ip) || !is_port($port)) { - log_error("[pfBlockerNG] XMLRPC sync terminated due to mis-configured Replication Target IP Address or Port settings."); - $success = FALSE; - return $success; - } - - /* Test key variables and set defaults if empty */ - if (empty($synctimeout)) { - $synctimeout = 150; - } $url = "{$protocol}://{$sync_to_ip}"; - if ($port == "") { $port = $config['system']['webgui']['port']; }; - /* If port is empty lets rely on the protocol selection */ - if ($port == "") { - if ($config['system']['webgui']['protocol'] == "http") { - $port = "80"; - } else { - $port = "443"; - } - } /* xml will hold the sections to sync */ $xml = array(); // If User Disabled, remove 'General Tab Customizations' from Sync - if ($config['installedpackages']['pfblockerngsync']['config'][0]['syncinterfaces'] == "") { - if (is_array($config['installedpackages']['pfblockerng'])) + if (isset($config['installedpackages']['pfblockerngsync']['config'][0]['syncinterfaces'])) { + if (isset($config['installedpackages']['pfblockerng'])) $xml['pfblockerng'] = $config['installedpackages']['pfblockerng']; + if (isset($config['installedpackages']['pfblockerngdnsblsettings'])) + $xml['pfblockerngdnsblsettings']= $config['installedpackages']['pfblockerngdnsblsettings']; } - if (is_array($config['installedpackages']['pfblockerngreputation'])) + + if (isset($config['installedpackages']['pfblockerngreputation'])) $xml['pfblockerngreputation'] = $config['installedpackages']['pfblockerngreputation']; - if (is_array($config['installedpackages']['pfblockernglistsv4'])) + if (isset($config['installedpackages']['pfblockernglistsv4'])) $xml['pfblockernglistsv4'] = $config['installedpackages']['pfblockernglistsv4']; - if (is_array($config['installedpackages']['pfblockernglistsv6'])) + if (isset($config['installedpackages']['pfblockernglistsv6'])) $xml['pfblockernglistsv6'] = $config['installedpackages']['pfblockernglistsv6']; - if (is_array($config['installedpackages']['pfblockerngtopspammers'])) + if (isset($config['installedpackages']['pfblockerngtopspammers'])) $xml['pfblockerngtopspammers'] = $config['installedpackages']['pfblockerngtopspammers']; - if (is_array($config['installedpackages']['pfblockerngafrica'])) + if (isset($config['installedpackages']['pfblockerngafrica'])) $xml['pfblockerngafrica'] = $config['installedpackages']['pfblockerngafrica']; - if (is_array($config['installedpackages']['pfblockerngantartica'])) + if (isset($config['installedpackages']['pfblockerngantartica'])) $xml['pfblockerngantartica'] = $config['installedpackages']['pfblockerngantartica']; - if (is_array($config['installedpackages']['pfblockerngasia'])) + if (isset($config['installedpackages']['pfblockerngasia'])) $xml['pfblockerngasia'] = $config['installedpackages']['pfblockerngasia']; - if (is_array($config['installedpackages']['pfblockerngeurope'])) + if (isset($config['installedpackages']['pfblockerngeurope'])) $xml['pfblockerngeurope'] = $config['installedpackages']['pfblockerngeurope']; - if (is_array($config['installedpackages']['pfblockerngnorthamerica'])) + if (isset($config['installedpackages']['pfblockerngnorthamerica'])) $xml['pfblockerngnorthamerica'] = $config['installedpackages']['pfblockerngnorthamerica']; - if (is_array($config['installedpackages']['pfblockerngoceania'])) + if (isset($config['installedpackages']['pfblockerngoceania'])) $xml['pfblockerngoceania'] = $config['installedpackages']['pfblockerngoceania']; - if (is_array($config['installedpackages']['pfblockerngsouthamerica'])) + if (isset($config['installedpackages']['pfblockerngsouthamerica'])) $xml['pfblockerngsouthamerica'] = $config['installedpackages']['pfblockerngsouthamerica']; - if (is_array($config['installedpackages']['pfblockerngproxyandsatellite'])) + if (isset($config['installedpackages']['pfblockerngproxyandsatellite'])) $xml['pfblockerngproxyandsatellite'] = $config['installedpackages']['pfblockerngproxyandsatellite']; + if (isset($config['installedpackages']['pfblockerngdnsbleasylist'])) + $xml['pfblockerngdnsbleasylist'] = $config['installedpackages']['pfblockerngdnsbleasylist']; + if (isset($config['installedpackages']['pfblockerngdnsbl'])) + $xml['pfblockerngdnsbl'] = $config['installedpackages']['pfblockerngdnsbl']; /* assemble xmlrpc payload */ $params = array(XML_RPC_encode($password), XML_RPC_encode($xml)); /* set a few variables needed for sync code borrowed from filter.inc */ - log_error("[pfBlockerNG] XMLRPC syncing to {$url}:{$port}."); $method = 'pfsense.merge_installedpackages_section_xmlrpc'; $msg = new XML_RPC_Message($method, $params); $cli = new XML_RPC_Client('/xmlrpc.php', $url, $port); @@ -2965,22 +4753,18 @@ function pfblockerng_do_xmlrpc_sync($sync_to_ip, $port, $protocol, $username, $p /* send our XMLRPC message and timeout after defined sync timeout value */ $resp = $cli->send($msg, $synctimeout); - $error = ""; + if (!$resp) { log_error("[pfBlockerNG] XMLRPC communications error occurred while attempting sync with {$url}:{$port}."); - file_notice("sync_settings", $error, "pfBlockerNG Settings Sync", ""); + file_notice('sync_settings', $error, 'pfBlockerNG Settings Sync', ''); $success = FALSE; - return $success; } elseif ($resp->faultCode()) { $cli->setDebug(1); $resp = $cli->send($msg, $synctimeout); log_error("[pfBlockerNG] XMLRPC Error received while attempting sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString()); - file_notice("sync_settings", $error, "pfBlockerNG Settings Sync", ""); + file_notice('sync_settings', $error, 'pfBlockerNG Settings Sync', ''); $success = FALSE; - return $success; - } else { - log_error("[pfBlockerNG] XMLRPC sync successfully completed with {$url}:{$port}."); } return $success; } -?> +?>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng.php b/config/pfblockerng/pfblockerng.php index 83b0ed8d..93578f24 100644 --- a/config/pfblockerng/pfblockerng.php +++ b/config/pfblockerng/pfblockerng.php @@ -3,11 +3,11 @@ pfBlockerNG.php pfBlockerNG - Copyright (C) 2015 BBcan177@gmail.com + Copyright (c) 2015 BBcan177@gmail.com All rights reserved. Based upon pfBlocker by - Copyright (C) 2011-2012 Marcello Coutinho + Copyright (c) 2011-2012 Marcello Coutinho All rights reserved. Hour Schedule Convertor code by @@ -39,278 +39,332 @@ */ -require_once("util.inc"); -require_once("functions.inc"); -require_once("pkg-utils.inc"); -require_once("globals.inc"); -require_once("services.inc"); - -// Call Include File and Collect updated Global Settings -if (in_array($argv[1], array( 'update','dc','uc','gc','cron' ))) { - require_once("/usr/local/pkg/pfblockerng/pfblockerng.inc"); +require_once('util.inc'); +require_once('functions.inc'); +require_once('pkg-utils.inc'); +require_once('globals.inc'); +require_once('services.inc'); +require_once('/usr/local/pkg/pfblockerng/pfblockerng.inc'); +require_once('/usr/local/pkg/pfblockerng/pfblockerng_extra.inc'); // 'include functions' not yet merged into pfSense + +global $config, $pfb; + +// Extras - MaxMind/Alexa Download URLs/filenames/settings +$pfb['extras'][0]['url'] = 'http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz'; +$pfb['extras'][0]['file_dwn'] = 'GeoIP.dat.gz'; +$pfb['extras'][0]['file'] = 'GeoIP.dat'; +$pfb['extras'][0]['folder'] = "{$pfb['geoipshare']}"; + +$pfb['extras'][1]['url'] = "http://geolite.maxmind.com/download/geoip/database/GeoIPv6.dat.gz"; +$pfb['extras'][1]['file_dwn'] = 'GeoIPv6.dat.gz'; +$pfb['extras'][1]['file'] = 'GeoIPv6.dat'; +$pfb['extras'][1]['folder'] = "{$pfb['geoipshare']}"; + +$pfb['extras'][2]['url'] = "http://geolite.maxmind.com/download/geoip/database/GeoIPCountryCSV.zip"; +$pfb['extras'][2]['file_dwn'] = 'GeoIPCountryCSV.zip'; +$pfb['extras'][2]['file'] = 'GeoIPCountryWhois.csv'; +$pfb['extras'][2]['folder'] = "{$pfb['geoipshare']}"; +$pfb['extras'][2]['install'] = TRUE; // Flag for package installation + +$pfb['extras'][3]['url'] = "http://dev.maxmind.com/static/csv/codes/country_continent.csv"; +$pfb['extras'][3]['file_dwn'] = 'country_continent.csv'; +$pfb['extras'][3]['file'] = 'country_continent.csv'; +$pfb['extras'][3]['folder'] = "{$pfb['geoipshare']}"; +$pfb['extras'][3]['install'] = TRUE; // Flag for package installation + +$pfb['extras'][4]['url'] = "http://geolite.maxmind.com/download/geoip/database/GeoIPv6.csv.gz"; +$pfb['extras'][4]['file_dwn'] = 'GeoIPv6.csv.gz'; +$pfb['extras'][4]['file'] = 'GeoIPv6.csv'; +$pfb['extras'][4]['folder'] = "{$pfb['geoipshare']}"; +$pfb['extras'][4]['install'] = TRUE; // Flag for package installation + +$pfb['extras'][5]['url'] = "https://s3.amazonaws.com/alexa-static/top-1m.csv.zip"; +$pfb['extras'][5]['file_dwn'] = 'top-1m.csv.zip'; +$pfb['extras'][5]['file'] = 'top-1m.csv'; +$pfb['extras'][5]['folder'] = "{$pfb['dbdir']}"; + + +// Call include file and collect updated Global settings +if (in_array($argv[1], array('update', 'updateip', 'updatednsbl', 'dc', 'bu', 'uc', 'gc', 'al', 'cron'))) { pfb_global(); -} - -// IPv6 Range to CIDR function used courtesey from: -// https://github.com/stilez/pfsense-leases/blob/50cc0fa81dba5fe91bcddaea016c245d1b8479cc/etc/inc/util.inc -function ip_range_to_subnet_array_temp($ip1, $ip2) { - - if (is_ipaddrv4($ip1) && is_ipaddrv4($ip2)) { - $proto = 'ipv4'; // for clarity - $bits = 32; - $ip1bin = decbin(ip2long32($ip1)); - $ip2bin = decbin(ip2long32($ip2)); - } elseif (is_ipaddrv6($ip1) && is_ipaddrv6($ip2)) { - $proto = 'ipv6'; - $bits = 128; - $ip1bin = Net_IPv6::_ip2Bin($ip1); - $ip2bin = Net_IPv6::_ip2Bin($ip2); - } else - return array(); - - // it's *crucial* that binary strings are guaranteed the expected length; do this for certainty even though for IPv6 it's redundant - $ip1bin = str_pad($ip1bin, $bits, '0', STR_PAD_LEFT); - $ip2bin = str_pad($ip2bin, $bits, '0', STR_PAD_LEFT); - - if ($ip1bin === $ip2bin) - return array($ip1 . '/' . $bits); - - if (strcmp($ip1bin, $ip2bin) > 0) - list ($ip1bin, $ip2bin) = array($ip2bin, $ip1bin); // swap contents of ip1 <= ip2 - - $rangesubnets = array(); - $netsize = 0; - - do { - // at loop start, $ip1 is guaranteed strictly less than $ip2 (important for edge case trapping and preventing accidental binary wrapround) - // which means the assignments $ip1 += 1 and $ip2 -= 1 will always be "binary-wrapround-safe" - - // step #1 if start ip (as shifted) ends in any '1's, then it must have a single cidr to itself (any cidr would include the '0' below it) - - if (substr($ip1bin, -1, 1) == '1') { - // the start ip must be in a separate one-IP cidr range - $new_subnet_ip = substr($ip1bin, $netsize, $bits - $netsize) . str_repeat('0', $netsize); - $rangesubnets[$new_subnet_ip] = $bits - $netsize; - $n = strrpos($ip1bin, '0'); //can't be all 1's - $ip1bin = ($n == 0 ? '' : substr($ip1bin, 0, $n)) . '1' . str_repeat('0', $bits - $n - 1); // BINARY VERSION OF $ip1 += 1 - } - - // step #2, if end ip (as shifted) ends in any zeros then that must have a cidr to itself (as cidr cant span the 1->0 gap) - - if (substr($ip2bin, -1, 1) == '0') { - // the end ip must be in a separate one-IP cidr range - $new_subnet_ip = substr($ip2bin, $netsize, $bits - $netsize) . str_repeat('0', $netsize); - $rangesubnets[$new_subnet_ip] = $bits - $netsize; - $n = strrpos($ip2bin, '1'); //can't be all 0's - $ip2bin = ($n == 0 ? '' : substr($ip2bin, 0, $n)) . '0' . str_repeat('1', $bits - $n - 1); // BINARY VERSION OF $ip2 -= 1 - // already checked for the edge case where end = start+1 and start ends in 0x1, above, so it's safe - } - - // this is the only edge case arising from increment/decrement. - // it happens if the range at start of loop is exactly 2 adjacent ips, that spanned the 1->0 gap. (we will have enumerated both by now) - - if (strcmp($ip2bin, $ip1bin) < 0) - continue; - - // step #3 the start and end ip MUST now end in '0's and '1's respectively - // so we have a non-trivial range AND the last N bits are no longer important for CIDR purposes. - - $shift = $bits - max(strrpos($ip1bin, '0'), strrpos($ip2bin, '1')); // num of low bits which are '0' in ip1 and '1' in ip2 - $ip1bin = str_repeat('0', $shift) . substr($ip1bin, 0, $bits - $shift); - $ip2bin = str_repeat('0', $shift) . substr($ip2bin, 0, $bits - $shift); - $netsize += $shift; - if ($ip1bin === $ip2bin) { - // we're done. - $new_subnet_ip = substr($ip1bin, $netsize, $bits - $netsize) . str_repeat('0', $netsize); - $rangesubnets[$new_subnet_ip] = $bits - $netsize; - continue; - } - - // at this point there's still a remaining range, and either startip ends with '1', or endip ends with '0'. So repeat cycle. - } while (strcmp($ip1bin, $ip2bin) < 0); + // Script Arguments + switch($argv[1]) { + case 'cron': // Sync 'cron' + pfblockerng_sync_cron(); + break; + case 'updateip': // Sync 'Force Reload IP only' + case 'updatednsbl': // Sync 'Force Reload DNSBL only' + sync_package_pfblockerng($argv[1]); + break; + case 'update': // Sync 'Force update' + sync_package_pfblockerng('cron'); + break; + case 'dc': // Update Extras - MaxMind/Alexa database files - // subnets are ordered by bit size. Re sort by IP ("naturally") and convert back to IPv4/IPv6 + // If 'General Tab' skip MaxMind download setting if checked, only download binary updates for Reputation/Alerts page. + if (!empty($pfb['cc'])) { + unset($pfb['extras'][2], $pfb['extras'][3], $pfb['extras'][4]); + } - ksort($rangesubnets, SORT_STRING); - $out = array(); + // Skip Alexa update, if disabled + if ($pfb['dnsbl_alexa'] == 'Disabled') { + unset($pfb['extras'][5]); + } - foreach ($rangesubnets as $ip => $netmask) { - if ($proto == 'ipv4') { - $i = str_split($ip, 8); - $out[] = implode('.', array( bindec($i[0]),bindec($i[1]),bindec($i[2]),bindec($i[3]))) . '/' . $netmask; - } else - $out[] = Net_IPv6::compress(Net_IPv6::_bin2Ip($ip)) . '/' . $netmask; + pfblockerng_download_extras(); + pfblockerng_uc_countries(); + pfblockerng_get_countries(); + break; + case 'bu': // Update MaxMind binary database files only. + unset($pfb['extras'][2], $pfb['extras'][3], $pfb['extras'][4], $pfb['extras'][5]); + pfblockerng_download_extras(); + break; + case 'al': // Update Alexa database only. + unset($pfb['extras'][0], $pfb['extras'][1], $pfb['extras'][2], $pfb['extras'][3], $pfb['extras'][4]); + pfblockerng_download_extras(); + break; + case 'uc': // Update MaxMind ISO files from local database files. + pfblockerng_uc_countries(); + break; + case 'gc': // Update Continent XML files. + pfblockerng_get_countries(); + break; } - - return $out; } -// Set php Memory Limit -$uname = posix_uname(); -if ($uname['machine'] == "amd64") { - ini_set('memory_limit', '256M'); -} -function pfb_update_check($header_url, $list_url, $url_format, $pfbfolder) { - global $pfb; +// Determine if source list file has an updated timestamp +function pfb_update_check($header, $list_url, $pfbfolder, $pfborig, $pflex, $format) { + global $config, $pfb; + + $log = "[ {$header} ]\n"; + pfb_logger("{$log}", 1); $pfb['cron_update'] = FALSE; - if ($url_format == "rsync" || $url_format == "html") { - $log = "[ {$header_url} ]\n Skipping timestamp query\n"; - pfb_logger("{$log}","1"); - $pfb['cron_update'] = TRUE; + // Determine if previous download fails have exceeded threshold. + if ($pfb['restore'] == 'on') { + if ($pfb['skipfeed'] != 0) { + // Call function to get all previous download fails + pfb_failures(); + + if ($pfb['failed'][$header] >= $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"); } - switch ($url_format) { - case "gz": - case "gz_2": - case "gz_lg": - case "et": - $type = '.gz'; - break; - case "zip": - case "xlsx": - $type = '.zip'; - break; - case "txt": - $type = '.orig'; - break; - case "html": - case "block": - $type = '.raw'; - break; + // 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; } - $log = "[ {$header_url} ]\n"; - pfb_logger("{$log}","1"); $host = @parse_url($list_url); - $local_file = "{$pfb['origdir']}/{$header_url}{$type}"; + $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 ($host['host'] == "127.0.0.1" || $host['host'] == $pfb['iplocal'] || empty($host['host'])) { - $remote_tds = gmdate ("D, d M Y H:i:s T", filemtime($list_url)); - } else { - $remote_tds = @implode(preg_grep("/Last-Modified/", get_headers($list_url))); - $remote_tds = preg_replace("/^Last-Modified: /","", $remote_tds); + 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'); + } - $log = " Remote timestamp: {$remote_tds}\n"; - pfb_logger("{$log}","1"); - $local_tds = gmdate ("D, d M Y H:i:s T", filemtime($local_file)); - $log = " Local timestamp: {$local_tds}\n"; - pfb_logger("{$log}","1"); - if ("{$remote_tds}" != "{$local_tds}") { - $pfb['cron_update'] = TRUE; - } else { - $log = " Remote file unchanged. Download Terminated\n"; - pfb_logger("{$log}","1"); - $pfb['cron_update'] = FALSE; + // 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. + // Trigger CRON process if updates are found. $pfb['update_cron'] = TRUE; - $log = " Updates Found\n"; - pfb_logger("{$log}","1"); - unlink_if_exists($pfbfolder . '/' . $header_url . '.txt'); + $log = "Update Found\n"; + pfb_logger("{$log}", 1); + unlink_if_exists("{$pfbfolder}/{$header}.txt"); } + return; } -if ($argv[1] == 'update') { - sync_package_pfblockerng("cron"); -} -if ($argv[1] == 'dc') { - // (Options - 'bu' Binary Update for Reputation/Alerts Page, 'all' for Country update and 'bu' options. - if ($pfb['cc'] == "") { - exec("/bin/sh /usr/local/pkg/pfblockerng/geoipupdate.sh all >> {$pfb['geolog']} 2>&1"); - } else { - exec("/bin/sh /usr/local/pkg/pfblockerng/geoipupdate.sh bu >> {$pfb['geolog']} 2>&1"); +// 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; + } + } } - pfblockerng_uc_countries(); - pfblockerng_get_countries(); - - // Remove Original Maxmind Database Files - @unlink_if_exists("{$pfb['dbdir']}/GeoIPCountryCSV.zip"); - @unlink_if_exists("{$pfb['dbdir']}/GeoIPCountryWhois.csv"); - @unlink_if_exists("{$pfb['dbdir']}/GeoIPv6.csv"); - @unlink_if_exists("{$pfb['dbdir']}/country_continent.csv"); -} + pfb_logger("Download Process Ended [ NOW ]\n\n", 3); -if ($argv[1] == 'uc') { - pfblockerng_uc_countries(); + if ($pfberror) { + return FALSE; + } else { + return TRUE; + } } -if ($argv[1] == 'gc') { - pfblockerng_get_countries(); -} -if ($argv[1] == 'cron') { +// Function to update Lists/Feeds as per Cron +function pfblockerng_sync_cron() { + global $config, $pfb, $pfbarr; - // Call Base Hour converter + // 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"); + pfb_logger("{$log}", 1); - $list_type = array ("pfblockernglistsv4" => "_v4", "pfblockernglistsv6" => "_v6"); + $list_type = array('pfblockernglistsv4' => '_v4', 'pfblockernglistsv6' => '_v6', 'pfblockerngdnsbl' => '_v4', 'pfblockerngdnsbleasylist' => '_v4'); foreach ($list_type as $ip_type => $vtype) { - if ($config['installedpackages'][$ip_type]['config'] != "") { + if (!empty($config['installedpackages'][$ip_type]['config'])) { foreach ($config['installedpackages'][$ip_type]['config'] as $list) { - if (is_array($list['row']) && $list['action'] != "Disabled") { + if (isset($list['row']) && $list['action'] != 'Disabled' && $list['cron'] != 'Never') { foreach ($list['row'] as $row) { - if ($row['url'] != "" && $row['state'] != "Disabled") { + if (!empty($row['url']) && $row['state'] != 'Disabled') { - if ($vtype == "_v4") { - $header_url = "{$row['header']}"; + if ($vtype == '_v4') { + $header = "{$row['header']}"; } else { - $header_url = "{$row['header']}_v6"; + $header = "{$row['header']}_v6"; } - // Determine Folder Location for Alias (return array $pfbarr) - pfb_determine_list_detail($list['action'], "", "", ""); - $pfbfolder = $pfbarr['folder']; - - $list_cron = $list['cron']; - $list_url = $row['url']; - $header_dow = $list['dow']; - $url_format = $row['format']; + // 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 (file_exists($pfbfolder . '/' . $header_url . '.txt') && $row['state'] == "Hold") { + // Bypass update if state is defined as 'Hold' and list file exists + if ($row['state'] == 'Hold' && file_exists("{$pfbfolder}/{$header}.txt")) { continue; } - // Check if List file exists, if not found run Update - if (!file_exists($pfbfolder . '/' . $header_url . '.txt')) { - $log = " Updates Found\n"; - pfb_logger("{$log}","1"); - $pfb['update_cron'] = TRUE; - continue; + // Allow cURL SSL downgrade if user configured. + $pflex = FALSE; + if ($row['state'] == 'Flex') { + $pflex = TRUE; } - switch ($list_cron) { - case "EveryDay": + switch ($list['cron']) { + case 'EveryDay': if ($hour == $pfb['24hour']) { - pfb_update_check($header_url, $list_url, $url_format, $pfbfolder); + pfb_update_check($header, $row['url'], $pfbfolder, $pfborig, $pflex, $row['format']); } break; - case "Weekly": - if ($hour == $pfb['24hour'] && $dow == $header_dow) { - pfb_update_check($header_url, $list_url, $url_format, $pfbfolder); + 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_url, $list_url, $url_format, $pfbfolder); + if ($pfb['interval'] == '1' || in_array($hour, $pfb_sch)) { + pfb_update_check($header, $row['url'], $pfbfolder, $pfborig, $pflex, $row['format']); } break; } @@ -321,23 +375,12 @@ if ($argv[1] == 'cron') { } } - // If Continents are Defined, continue with Update Process to determine if further changes are required. - $continents = array ( "Africa" => "pfB_Africa", - "Antartica" => "pfB_Antartica", - "Asia" => "pfB_Asia", - "Europe" => "pfB_Europe", - "North America" => "pfB_NAmerica", - "Oceania" => "pfB_Oceania", - "South America" => "pfB_SAmerica", - "Top Spammers" => "pfB_Top", - "Proxy and Satellite" => "pfB_PS" - ); - + // If no lists require updates, check if Continents are configured and update accordingly. if (!$pfb['update_cron']) { - foreach ($continents as $continent => $pfb_alias) { - if (is_array($config['installedpackages']['pfblockerng' . strtolower(preg_replace('/ /','',$continent))]['config'])) { - $continent_config = $config['installedpackages']['pfblockerng' . strtolower(preg_replace('/ /','',$continent))]['config'][0]; - if ($continent_config['action'] != "Disabled" && $pfb['enable'] == "on") { + 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; } @@ -346,104 +389,106 @@ if ($argv[1] == 'cron') { } if ($pfb['update_cron']) { - sync_package_pfblockerng("cron"); + sync_package_pfblockerng('cron'); + $pfb['update_cron'] = FALSE; } else { - sync_package_pfblockerng("noupdates"); + sync_package_pfblockerng('noupdates'); $log = "\n No Updates required.\n CRON PROCESS ENDED\n UPDATE PROCESS ENDED\n"; - pfb_logger("{$log}","1"); + pfb_logger("{$log}", 1); } - // Call Log Mgmt Function + // 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 to process the downloaded MaxMind database and format into Continent txt files. function pfblockerng_uc_countries() { - global $g,$pfb; + global $pfb; - $maxmind_cont = "{$pfb['dbdir']}/country_continent.csv"; - $maxmind_cc4 = "{$pfb['dbdir']}/GeoIPCountryWhois.csv"; - $maxmind_cc6 = "{$pfb['dbdir']}/GeoIPv6.csv"; + $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']}"); + // Create folders if not exist + $folder_array = array ("{$pfb['dbdir']}", "{$pfb['logdir']}", "{$pfb['ccdir']}"); foreach ($folder_array as $folder) { - safe_mkdir ("{$folder}",0755); + safe_mkdir ("{$folder}", 0755); } - $now = date("m/d/y G:i:s", time()); - $log = "Country Code Update Start - [ NOW ]\n\n"; - print "Country Code Update Start - [ $now ]\n\n"; - pfb_logger("{$log}","3"); + $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"; - print $log; - pfb_logger("{$log}","3"); + $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 - $maxmind_ver = "MaxMind GeoLite Date/Time Stamps \n\n"; - $remote_tds = @implode(preg_grep("/Last-Modified/", get_headers("http://geolite.maxmind.com/download/geoip/database/GeoIPCountryCSV.zip"))); - $maxmind_ver .= "MaxMind_v4 \t" . $remote_tds . "\n"; - $local_tds = @gmdate ("D, d M Y H:i:s T", filemtime($maxmind_cc4)); - $maxmind_ver .= "Local_v4 \tLast-Modified: " . $local_tds . "\n\n"; - $remote_tds = @implode(preg_grep("/Last-Modified/", get_headers("http://geolite.maxmind.com/download/geoip/database/GeoIPv6.csv.gz"))); - $maxmind_ver .= "MaxMind_v6 \t" . $remote_tds . "\n"; - $local_tds = @gmdate ("D, d M Y H:i:s T", filemtime($maxmind_cc6)); - $maxmind_ver .= "Local_v6 \tLast-Modified: " . $local_tds . "\n"; - $maxmind_ver .= "\nThese Timestamps should *match* \n"; - @file_put_contents("{$pfb['logdir']}/maxmind_ver", $maxmind_ver); - - // Collect ISO Codes for Each Continent - $log = "Processing Continent Data\n"; - print $log; - pfb_logger("{$log}","3"); - - $cont_array = array ( array($AF),array($AS),array($EU),array($NA),array($OC),array($SA),array($AX)); - if (($handle = fopen("{$maxmind_cont}",'r')) !== FALSE) { - while (($cc = fgetcsv($handle)) !== FALSE) { + // 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},"; + 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},"; + 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},"; + 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},"; + 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},"; + 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},"; + 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; @@ -454,64 +499,63 @@ function pfblockerng_uc_countries() { 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]['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"; - print $log; - pfb_logger("{$log}","3"); + 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['dbdir']}/GeoIPCountryWhois.csv"; + if ($type == '4') { + $maxmind_cc = "{$pfb['geoipshare']}/GeoIPCountryWhois.csv"; } else { - $maxmind_cc = "{$pfb['dbdir']}/GeoIPv6.csv"; + $maxmind_cc = "{$pfb['geoipshare']}/GeoIPv6.csv"; } $iptype = "ip{$type}"; $filetype = "file{$type}"; - if (($handle = fopen("{$maxmind_cc}",'r')) !== FALSE) { + 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])); - $counter = 0; - foreach ($cont_array as $iso) { - if (preg_match("/\b$cc_key\b/", $iso['iso'])) { - $cont_array[$counter][$cc_key][$iptype] .= $a_cidr . ","; - $cont_array[$counter][$cc_key]['country'] = $country_key; + $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; } - $counter++; } } } unset($cc); fclose($handle); - // Build Continent Files - $counter = 0; - foreach ($cont_array as $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[$counter]['continent'] . "\n"; - $pfb_file = $cont_array[$counter][$filetype]; + // 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 $key) { - if (preg_match("/[A-Z]{2}|A1|A2/", $key)) { - $header .= "# Country: " . $iso[$key]['country'] . "\n"; - $header .= "# ISO Code: " . $key . "\n"; - $header .= "# Total Networks: " . substr_count($iso[$key][$iptype], ",") . "\n"; - $header .= str_replace(",", "\n", $iso[$key][$iptype]); - $iso[$key][$iptype] = ""; + + 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] = ''; } } - $counter++; @file_put_contents($pfb_file, $header, LOCK_EX); } } @@ -520,73 +564,92 @@ function pfblockerng_uc_countries() { // Function to process Continent txt files and create Country ISO files and to Generate GUI XML files. function pfblockerng_get_countries() { - global $g,$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" + 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"; - print $log; - pfb_logger("{$log}","3"); + // 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"; - print $log; - pfb_logger("{$log}","3"); + 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 = preg_replace("/v4/", "v6", $file); + if ($type == '6') { + $file = str_replace('v4', 'v6', $file); + } $convert = explode("\n", file_get_contents($file)); - $cont_name = preg_replace("/ /", "", $cont); + $cont_name = str_replace(' ', '', $cont); $cont_name_lower = strtolower($cont_name); $active = array("$cont" => '<active/>'); - $lastkey = count ($convert) - 1; + $lastkey = count($convert) - 1; $pfb['complete'] = FALSE; $keycount = 1; $total = 0; + $xml_data = ''; foreach ($convert as $line) { - if (preg_match("/#/",$line)) { + if (substr($line, 0, 1) == '#') { if ($pfb['complete']) { - ${'coptions' . $type}[] = $country . '-' . $isocode . ' ('. $total .') ' . ' </name><value>' . $isocode . '</value></option>'; - // Only collect IPv4 for Reputation Tab - if ($type == "4") - $roptions4[] = $country . '-' . $isocode . ' ('. $total .') ' . ' </name><value>' . $isocode . '</value></option>'; - + ${'coptions' . $type}[] = "{$country}-{$isocode} ({$total})</name><value>{$isocode}</value></option>"; + // Only collect IPv4 for Reputation Tab + if ($type == '4') { + $roptions4[] = "{$country}-{$isocode} ({$total})</name><value>{$isocode}</value></option>"; + } // Save ISO data - @file_put_contents($pfb['ccdir'] . '/' . $isocode . '_v' . $type . '.txt', $xml_data, LOCK_EX); + @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; } - if (preg_match("/Total Networks: 0/", $line)) { continue;} // Don't Display Countries with Null Data - if (preg_match("/Country:\s(.*)/",$line, $matches)) { $country = $matches[1];} - if (preg_match("/ISO Code:\s(.*)/",$line, $matches)) { $isocode = $matches[1];} + // 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 (!preg_match("/#/",$line)) { + elseif (substr($line, 0, 1) != '#') { $total++; - if (!empty($line)) - $xml_data .= $line . "\n"; + if (!empty($line)) { + $xml_data .= "{$line}\n"; + } $pfb['complete'] = TRUE; } // Save last EOF ISO IP data if ($keycount == $lastkey) { - if (preg_match("/Total Networks: 0/", $line)) { continue;} // Dont Display Countries with Null Data - ${'coptions' . $type}[] = $country . '-' . $isocode . ' ('. $total .') ' . ' </name><value>' . $isocode . '</value></option>'; - if ($type == "4") - $roptions4[] = $country . '-' . $isocode . ' ('. $total .') ' . ' </name><value>' . $isocode . '</value></option>'; - @file_put_contents($pfb['ccdir'] . '/' . $isocode . '_v' . $type . '.txt', $xml_data, LOCK_EX); + // Don't collect Countries with null data + if (strpos($line, 'Total Networks: 0') !== FALSE) { + continue; + } + ${'coptions' . $type}[] = "{$country}-{$isocode} ({$total})</name><value>{$isocode}</value></option>"; + if ($type == '4') { + $roptions4[] = "{$country}-{$isocode} ({$total})</name><value>{$isocode}</value></option>"; + } + @file_put_contents("{$pfb['ccdir']}/{$isocode}_v{$type}.txt", $xml_data, LOCK_EX); unset($total, $xml_data); } $keycount++; @@ -594,33 +657,36 @@ function pfblockerng_get_countries() { unset ($ips, $convert); // Sort IP Countries alphabetically and build XML <option> data for Continents tab - if (!empty (${'coptions' . $type})) { + if (!empty(${'coptions' . $type})) { sort(${'coptions' . $type}, SORT_STRING); ${'ftotal' . $type} = count(${'coptions' . $type}); $count = 1; - ${'options' . $type} = ""; + ${'options' . $type} = ''; foreach (${'coptions' . $type} as $option) { - if ($count == 1) { ${'options' . $type} .= "\t" . '<option><name>' . $option . "\n"; $count++; continue;} + if ($count == 1) { + ${'options' . $type} .= "\t<option><name>{$option}\n"; + $count++; + continue; + } if (${'ftotal' . $type} == $count) { - ${'options' . $type} .= "\t\t\t\t" . '<option><name>' . $option; + ${'options' . $type} .= "\t\t\t\t<option><name>{$option}"; } else { - ${'options' . $type} .= "\t\t\t\t" . '<option><name>' . $option . "\n"; + ${'options' . $type} .= "\t\t\t\t<option><name>{$option}\n"; } $count++; } } - unset (${'coptions' . $type}); + unset(${'coptions' . $type}); } $xml = <<<EOF <?xml version="1.0" encoding="utf-8" ?> -<!DOCTYPE packagegui SYSTEM "./schema/packages.dtd"> -<?xml-stylesheet type="text/xsl" href="./xsl/package.xsl"?> +<!DOCTYPE packagegui SYSTEM "../schema/packages.dtd"> +<?xml-stylesheet type="text/xsl" href="../xsl/package.xsl"?> <packagegui> <copyright> <![CDATA[ -/* \$Id\$ */ /* ========================================================================== */ /* pfblockerng_{$cont_name}.xml @@ -673,12 +739,12 @@ $xml = <<<EOF <name>pfBlockerNG: {$cont_name}</name> <tooltiptext>Configure pfBlockerNG</tooltiptext> <section>Firewall</section> - <url>pkg_edit.php?xml=pfblockerng_{$cont_name_lower}.xml&id=0</url> + <url>pkg_edit.php?xml=pfblockerng_{$cont_name_lower}.xml</url> </menu> <tabs> <tab> <text>General</text> - <url>/pkg_edit.php?xml=pfblockerng.xml&id=0</url> + <url>/pkg_edit.php?xml=pfblockerng.xml</url> </tab> <tab> <text>Update</text> @@ -690,53 +756,70 @@ $xml = <<<EOF </tab> <tab> <text>Reputation</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml</url> </tab> <tab> <text>IPv4</text> - <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml&id=0</url> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml</url> </tab> <tab> <text>IPv6</text> - <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml&id=0</url> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml</url> + </tab> + <tab> + <text>DNSBL</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl.xml</url> + </tab> + <tab> + <text>Country</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml</url> </tab> <tab> <text>Top 20</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml</url> + <tab_level>2</tab_level> + {$active['top']} </tab> <tab> <text>Africa</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Africa.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Africa.xml</url> + <tab_level>2</tab_level> {$active['Africa']} </tab> <tab> <text>Asia</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Asia.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Asia.xml</url> + <tab_level>2</tab_level> {$active['Asia']} </tab> <tab> <text>Europe</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Europe.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Europe.xml</url> + <tab_level>2</tab_level> {$active['Europe']} </tab> <tab> - <text>N.A.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_NorthAmerica.xml&id=0</url> + <text>North America</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_NorthAmerica.xml</url> + <tab_level>2</tab_level> {$active['North America']} </tab> <tab> <text>Oceania</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Oceania.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Oceania.xml</url> + <tab_level>2</tab_level> {$active['Oceania']} </tab> <tab> - <text>S.A.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_SouthAmerica.xml&id=0</url> + <text>South America</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_SouthAmerica.xml</url> + <tab_level>2</tab_level> {$active['South America']} </tab> <tab> - <text>P.S.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_ProxyandSatellite.xml&id=0</url> + <text>Proxy and Satellite</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_ProxyandSatellite.xml</url> + <tab_level>2</tab_level> {$active['Proxy and Satellite']} </tab> <tab> @@ -745,25 +828,25 @@ $xml = <<<EOF </tab> <tab> <text>Sync</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml</url> </tab> </tabs> <fields> <field> - <name><![CDATA[Continent {$cont} (Geolite Data by MaxMind Inc. - ISO 3166)]]></name> + <name><![CDATA[Continent {$cont}  (Geolite Data by MaxMind Inc. - ISO 3166)]]></name> <type>listtopic</type> </field> <field> <fielddescr>LINKS</fielddescr> - <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a> - <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> + <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a>  + <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> </description> <type>info</type> </field> <field> <fieldname>countries4</fieldname> <fielddescr><![CDATA[<strong><center>Countries</center></strong><br /> - <center>Use CTRL + CLICK to unselect countries</center>]]> + <center>Use CTRL + CLICK to select/unselect countries</center>]]> </fielddescr> <type>select</type> <options> @@ -840,15 +923,13 @@ $xml .= <<<EOF <strong><u>'Alias' Rules:</u></strong><br /> <strong>'Alias'</strong> rules create an <a href="/firewall_aliases.php">alias</a> for the list (and do nothing else). This enables a pfBlockerNG list to be used by name, in any firewall rule or pfSense function, as desired. - <ul><li><strong>Options - Alias Deny, Alias Permit, Alias Match, Alias Native</strong></li><br /> + <ul><li><strong>Options  - Alias Deny, Alias Permit, Alias Match, Alias Native</strong></li><br /> <li>'Alias Deny' can use De-Duplication and Reputation Processes if configured.</li><br /> <li>'Alias Permit' and 'Alias Match' will be saved in the Same folder as the other Permit/Match Auto-Rules</li><br /> <li>'Alias Native' lists are kept in their Native format without any modifications.</li></ul> - <strong>When using 'Alias' rules, change (pfB_) to ( pfb_ ) in the beginning of rule description and use the 'Exact' spelling of - the Alias (no trailing Whitespace)</strong> Custom 'Alias' rules with 'pfB_ xxx' description will be removed by package if - using Auto Rule Creation.<br /><br /><strong>Tip</strong>: You can create the Auto Rules and remove "<u>auto rule</u>" from the Rule - Descriptions, then disable Auto Rules. This method will 'KEEP' these rules from being 'Deleted' which will allow editing for a Custom - Alias Configuration<br />]]> + <font color='red'>Note: </font><ul>When manually creating 'Alias' type firewall rules; <strong>Do not add</strong> (pfB_) to the + start of the rule description, use (pfb_) (Lowercase prefix). Manually created 'Alias' rules with 'pfB_' in the + description will be auto-removed by package when 'Auto' rules are defined.</ul>]]> </description> <fieldname>action</fieldname> <type>select</type> @@ -888,8 +969,8 @@ $xml .= <<<EOF </field> <field> <type>info</type> - <description><![CDATA[<font color='red'>Note: </font>In general Auto-Rules are created as follows:<br /> - <ul>Inbound - 'any' port, 'any' protocol and 'any' destination<br /> + <description><![CDATA[<font color='red'>Note: </font>In general, Auto-Rules are created as follows:<br /> + <ul>Inbound  - 'any' port, 'any' protocol and 'any' destination<br /> Outbound - 'any' port, 'any' protocol and 'any' destination address in the lists</ul> Configuring the Adv. Inbound Rule settings, will allow for more customization of the Inbound Auto-Rules.<br /> <strong>Select the pfSense 'Port' and/or 'Destination' Alias below:</strong>]]> @@ -950,7 +1031,8 @@ $xml .= <<<EOF <field> <fielddescr>Custom Protocol</fielddescr> <fieldname>autoproto</fieldname> - <description><![CDATA[<strong>Default: any</strong><br />Select the Protocol used for Inbound Firewall Rule(s).]]></description> + <description><![CDATA[<strong>Default: any</strong><br />Select the Protocol used for Inbound Firewall Rule(s).<br /> + Do not use 'any' with Adv. Inbound Rules as it will bypass these settings!]]></description> <type>select</type> <options> <option><name>any</name><value></value></option> @@ -962,17 +1044,11 @@ $xml .= <<<EOF <default_value></default_value> </field> <field> - <name><![CDATA[<center>Click to SAVE Settings and/or Rule Edits. Changes are Applied via CRON or + <name><![CDATA[<center>Click to SAVE Settings and/or Rule Edits.   Changes are Applied via CRON or 'Force Update'</center>]]></name> <type>listtopic</type> </field> </fields> - <custom_php_install_command> - pfblockerng_php_install_command(); - </custom_php_install_command> - <custom_php_deinstall_command> - pfblockerng_php_deinstall_command(); - </custom_php_deinstall_command> <custom_php_validation_command> pfblockerng_validate_input(\$_POST, \$input_errors); </custom_php_validation_command> @@ -984,41 +1060,42 @@ $xml .= <<<EOF </packagegui> EOF; - // Update Each Continent XML file. - @file_put_contents('/usr/local/pkg/pfblockerng/pfblockerng_'.$cont_name.'.xml',$xml,LOCK_EX); + // Update each Continent XML file. + @file_put_contents('/usr/local/pkg/pfblockerng/pfblockerng_'.$cont_name.'.xml', $xml,LOCK_EX); // Unset Arrays unset (${'options4'}, ${'options6'}, $xml); - } // End foreach 'Six Continents and Proxy/Satellite' Update XML Process + } // End foreach 'Six Continents and Proxy/Satellite' update XML process - // Sort Countries IPv4 Alphabetically and Build XML <option> Data for Reputation Tab (IPv6 not used by ET IQRisk) + // Sort Countries IPv4 alphabetically and build XML <option> data for Reputation tab (IPv6 not used by ET IQRisk) sort($roptions4, SORT_STRING); $eoa = count($roptions4); + $etoptions = ''; $count = 1; - $etoptions = ""; foreach ($roptions4 as $option4) { - if ($count == 1) { $et_options .= "\t" . '<option><name>' . $option4 . "\n"; $count++; continue; } + if ($count == 1) { + $et_options .= "\t<option><name>{$option4}\n"; $count++; continue; + } if ($eoa == $count) { - $et_options .= "\t\t\t\t" . '<option><name>' . $option4; + $et_options .= "\t\t\t\t<option><name>{$option4}"; } else { - $et_options .= "\t\t\t\t" . '<option><name>' . $option4 . "\n"; + $et_options .= "\t\t\t\t<option><name>{$option4}\n"; } $count++; } -// Update pfBlockerNG_Reputation.xml file with Country Code Changes +// Update pfBlockerNG_Reputation.xml file with Country Code changes $xmlrep = <<<EOF <?xml version="1.0" encoding="utf-8" ?> -<!DOCTYPE packagegui SYSTEM "./schema/packages.dtd"> -<?xml-stylesheet type="text/xsl" href="./xsl/package.xsl"?> +<!DOCTYPE packagegui SYSTEM "../schema/packages.dtd"> +<?xml-stylesheet type="text/xsl" href="../xsl/package.xsl"?> <packagegui> <copyright> <![CDATA[ -/* \$Id\$ */ /* ========================================================================== */ /* pfBlockerNG_Reputation.xml @@ -1070,12 +1147,12 @@ $xmlrep = <<<EOF <name>pfBlockerNG</name> <tooltiptext>Configure pfblockerNG</tooltiptext> <section>Firewall</section> - <url>pkg_edit.php?xml=pfblockerng.xml&id=0</url> + <url>pkg_edit.php?xml=pfblockerng.xml</url> </menu> <tabs> <tab> <text>General</text> - <url>/pkg_edit.php?xml=pfblockerng.xml&id=0</url> + <url>/pkg_edit.php?xml=pfblockerng.xml</url> </tab> <tab> <text>Update</text> @@ -1087,48 +1164,24 @@ $xmlrep = <<<EOF </tab> <tab> <text>Reputation</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml</url> <active/> </tab> <tab> <text>IPv4</text> - <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml&id=0</url> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml</url> </tab> <tab> <text>IPv6</text> - <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml&id=0</url> - </tab> - <tab> - <text>Top 20</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml&id=0</url> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml</url> </tab> <tab> - <text>Africa</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Africa.xml&id=0</url> + <text>DNSBL</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl.xml</url> </tab> <tab> - <text>Asia</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Asia.xml&id=0</url> - </tab> - <tab> - <text>Europe</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Europe.xml&id=0</url> - </tab> - <tab> - <text>N.A.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_NorthAmerica.xml&id=0</url> - </tab> - <tab> - <text>Oceania</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Oceania.xml&id=0</url> - </tab> - <tab> - <text>S.A.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_SouthAmerica.xml&id=0</url> - </tab> - <tab> - <text>P.S.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_ProxyandSatellite.xml&id=0</url> + <text>Country</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml</url> </tab> <tab> <text>Logs</text> @@ -1136,7 +1189,7 @@ $xmlrep = <<<EOF </tab> <tab> <text>Sync</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml</url> </tab> </tabs> <fields> @@ -1146,8 +1199,8 @@ $xmlrep = <<<EOF </field> <field> <fielddescr>LINKS</fielddescr> - <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a> - <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> + <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a>  + <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> </description> <type>info</type> </field> @@ -1155,7 +1208,7 @@ $xmlrep = <<<EOF <fielddescr><![CDATA[<strong>Why Reputation Matters:</strong>]]></fielddescr> <type>info</type> <description><![CDATA[By Enabling '<strong>Reputation</strong>', each Blocklist will be analyzed for Repeat Offenders in each IP Range. - <ul>Example: x.x.x.1, x.x.x.2, x.x.x.3, x.x.x.4, x.x.x.5<br /> + <ul>Example:  x.x.x.1, x.x.x.2, x.x.x.3, x.x.x.4, x.x.x.5<br /> No. of <strong> Repeat Offending IPs </strong> [ <strong>5</strong> ], in a Blocklist within the same IP Range.</ul> With '<strong>Reputation</strong> enabled, these 5 IPs will be removed and a single <strong>x.x.x.0/24</strong> Block is used.<br /> @@ -1184,7 +1237,7 @@ $xmlrep = <<<EOF <description><![CDATA[Enables Search for Repeat Offenders in a /24 Range on <strong>Each Individual Blocklist</strong>]]></description> </field> <field> - <fielddescr><![CDATA[ [ <strong>Max</strong> ] Setting]]></fielddescr> + <fielddescr><![CDATA[ [ <strong>Max</strong> ] Setting]]></fielddescr> <fieldname>p24_max_var</fieldname> <description><![CDATA[Default: <strong>5</strong><br /> Maximum number of Repeat Offenders allowed in a Single IP Range]]></description> @@ -1224,7 +1277,7 @@ $xmlrep = <<<EOF </description> </field> <field> - <fielddescr><![CDATA[ [ <strong>pMax</strong> ] Setting]]></fielddescr> + <fielddescr><![CDATA[ [ <strong>pMax</strong> ] Setting]]></fielddescr> <fieldname>p24_pmax_var</fieldname> <description><![CDATA[Default: <strong>50</strong><br />Maximum number of Repeat Offenders]]></description> <type>select</type> @@ -1245,7 +1298,7 @@ $xmlrep = <<<EOF </description> </field> <field> - <fielddescr><![CDATA[ [ <strong>dMax</strong> ] Setting]]></fielddescr> + <fielddescr><![CDATA[ [ <strong>dMax</strong> ] Setting]]></fielddescr> <fieldname>p24_dmax_var</fieldname> <description><![CDATA[Default: <strong>5</strong><br /> Maximum number of Repeat Offenders]]></description> @@ -1260,7 +1313,7 @@ $xmlrep = <<<EOF </options> </field> <field> - <name>Country Code Settings</name> + <name>Country Code Settings (max/dMax)</name> <type>listtopic</type> </field> <field> @@ -1305,11 +1358,11 @@ $xmlrep = <<<EOF </field> <field> <fielddescr><![CDATA[<br /><strong>IPv4</strong><br />Country Exclusion<br /> - <br />Geolite Data by: <br />MaxMind Inc. (ISO 3166)]]></fielddescr> + <br />Geolite Data by: <br />MaxMind Inc. (ISO 3166)]]></fielddescr> <fieldname>ccexclude</fieldname> <description> <![CDATA[Select Countries you want to <strong>Exclude</strong> from the Reputation Process.<br /> - <strong>Use CTRL + CLICK to unselect countries</strong>]]> + <strong>Use CTRL + CLICK to select/unselect countries</strong>]]> </description> <type>select</type> <options> @@ -1319,18 +1372,19 @@ $xmlrep = <<<EOF <multiple/> </field> <field> - <name>Emerging Threats IQRISK IPv4 Reputation</name> + <name>Proofpoint ET IQRISK IPv4 Reputation</name> <type>listtopic</type> </field> <field> <fielddescr>Subscription Pro. Blocklist</fielddescr> <type>info</type> - <description><![CDATA[<strong>Emerging Threats IQRisk</strong> is a Subscription Professional Reputation List.<br /><br /> + <description><![CDATA[<strong>Proofpoint ET IQRisk</strong> is a Subscription Professional Reputation List.<br /><br /> + <strong>The URL must include the name 'iprepdata.txt' for the filename.</strong><br /> ET IQRisk Blocklist must be entered in the Lists Tab using the following example: <ul>https://rules.emergingthreatspro.com/XXXXXXXXXXXXXXXX/reputation/iprepdata.txt.gz</ul> Select the <strong>ET IQRisk'</strong> format. The URL should use the .gz File Type.<br /> Enter your "ETPRO" code in URL. Further information can be found @ - <a target=_new href='http://emergingthreats.net/solutions/iqrisk-suite/'>ET IQRisk IP Reputation</a><br /><br /> + <a target="_blank" href="http://emergingthreats.net/solutions/iqrisk-suite/">ET IQRisk IP Reputation</a><br /><br /> To use <strong>'Match'</strong> Lists, Create a new 'Alias' and select one of the <strong> Action 'Match'</strong> Formats and <br /> enter the 'Localfile' as: <ul>/var/db/pfblockerng/match/ETMatch.txt</ul> @@ -1351,7 +1405,7 @@ $xmlrep = <<<EOF <fieldname>etblock</fieldname> <description> <![CDATA[Select Lists you want to BLOCK.<br /> - <strong>Use CTRL + CLICK to unselect Categories</strong> + <strong>Use CTRL + CLICK to select/unselect Categories</strong> <br /><br />Any Changes will take effect at the Next Scheduled CRON Task]]> </description> <type>select</type> @@ -1400,7 +1454,7 @@ $xmlrep = <<<EOF <fieldname>etmatch</fieldname> <description> <![CDATA[Select Lists you want to MATCH.<br /> - <strong>Use CTRL + CLICK to unselect Categories</strong> + <strong>Use CTRL + CLICK to select/unselect Categories</strong> <br /><br />Any Changes will take effect at the Next Scheduled CRON Task]]> </description> <type>select</type> @@ -1459,17 +1513,11 @@ $xmlrep = <<<EOF </options> </field> <field> - <name><![CDATA[<center>Click to SAVE Settings and/or Rule Edits. Changes are Applied via CRON or + <name><![CDATA[<center>Click to SAVE Settings and/or Rule Edits.   Changes are Applied via CRON or 'Force Update'</center>]]></name> <type>listtopic</type> </field> </fields> - <custom_php_install_command> - pfblockerng_php_install_command(); - </custom_php_install_command> - <custom_php_deinstall_command> - pfblockerng_php_deinstall_command(); - </custom_php_deinstall_command> <custom_php_validation_command> pfblockerng_validate_input(\$_POST, \$input_errors); </custom_php_validation_command> @@ -1480,22 +1528,23 @@ $xmlrep = <<<EOF </custom_php_resync_config_command> </packagegui> EOF; - $log = "Saving pfBlockerNG Reputation TAB \n"; - print $log; - pfb_logger("{$log}","3"); + $log = " Saving pfBlockerNG Reputation TAB\n"; + if (!$g['pfblockerng_install']) { + print $log; + } + pfb_logger("{$log}", 3); // Save pfBlockerng_reputation.xml file @file_put_contents('/usr/local/pkg/pfblockerng/pfblockerng_reputation.xml', $xmlrep, LOCK_EX); - $log = "\n Country Code - XML File Update completed.\n"; - print $log; - pfb_logger("{$log}","3"); - $now = date("m/d/y G.i:s", time()); - $log = "Country Code Update Ended - [ NOW ]\n"; - print "Country Code Update Ended - [ $now ]\n"; - pfb_logger("{$log}","3"); + $now = date('m/d/y G.i:s', time()); + $log = "Country Code Update Ended - [ NOW ]\n\n"; + if (!$g['pfblockerng_install']) { + print "Country Code Update Ended - [ $now ]\n\n"; + } + pfb_logger("{$log}", 3); - // Unset Arrays + // Unset arrays unset ($roptions4, $et_options, $xmlrep); } ?>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng.priv.inc b/config/pfblockerng/pfblockerng.priv.inc index 97cf6288..0b50ef84 100644 --- a/config/pfblockerng/pfblockerng.priv.inc +++ b/config/pfblockerng/pfblockerng.priv.inc @@ -17,16 +17,23 @@ $priv_list['page-firewall-pfblockerng']['match'][] = "pkg_edit.php?xml=pfblocker $priv_list['page-firewall-pfblockerng']['match'][] = "pkg_edit.php?xml=pfblockerng/pfblockerng_SouthAmerica.xml*"; $priv_list['page-firewall-pfblockerng']['match'][] = "pkg_edit.php?xml=pfblockerng/pfblockerng_ProxyandSatellite.xml*"; $priv_list['page-firewall-pfblockerng']['match'][] = "pkg_edit.php?xml=pfblockerng/pfblockerng_sync.xml*"; +$priv_list['page-firewall-pfblockerng']['match'][] = "pkg_edit.php?xml=pfblockerng/pfblockerng_dnsbl.xml*"; +$priv_list['page-firewall-pfblockerng']['match'][] = "pkg_edit.php?xml=pfblockerng/pfblockerng_dnsbl_easylist.xml*"; $priv_list['page-firewall-pfblockerng']['match'][] = "pkg.php?xml=pfblockerng/pfblockerng_v4lists.xml*"; $priv_list['page-firewall-pfblockerng']['match'][] = "pkg.php?xml=pfblockerng/pfblockerng_v6lists.xml*"; +$priv_list['page-firewall-pfblockerng']['match'][] = "pkg.php?xml=pfblockerng/pfblockerng_dnsbl_lists.xml*"; $priv_list['page-firewall-pfblockerng']['match'][] = "pfblockerng/pfblockerng_update.php*"; $priv_list['page-firewall-pfblockerng']['match'][] = "pfblockerng/pfblockerng_alerts.php*"; +$priv_list['page-firewall-pfblockerng']['match'][] = "pfblockerng/pfblockerng_alerts_ar.php*"; $priv_list['page-firewall-pfblockerng']['match'][] = "pfblockerng/pfblockerng_log.php*"; -$priv_list['page-firewall-pfblockerng']['match'][] = "pfblockerng/pfblockerng_diag_dns.php*"; +$priv_list['page-firewall-pfblockerng']['match'][] = "pfblockerng/pfblockerng_threats.php*"; $priv_list['page-firewall-pfblockerng']['match'][] = "widgets/javascript/pfblockerng.js*"; $priv_list['page-firewall-pfblockerng']['match'][] = "widgets/include/widget-pfblockerng.inc*"; $priv_list['page-firewall-pfblockerng']['match'][] = "widgets/widgets/pfblockerng.widget.php*"; $priv_list['page-firewall-pfblockerng']['match'][] = "pfblockerng/pfblockerng.inc*"; +$priv_list['page-firewall-pfblockerng']['match'][] = "pfblockerng/pfblockerng_extra.inc*"; +$priv_list['page-firewall-pfblockerng']['match'][] = "pfblockerng/pfblockerng_install.inc*"; +$priv_list['page-firewall-pfblockerng']['match'][] = "pfblockerng/pfblockerng.inc*"; ?>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng.sh b/config/pfblockerng/pfblockerng.sh index 5858b08b..45c1a5f1 100644 --- a/config/pfblockerng/pfblockerng.sh +++ b/config/pfblockerng/pfblockerng.sh @@ -1,6 +1,6 @@ #!/bin/sh # pfBlockerNG IP Reputation Script - By BBcan177@gmail.com - 04-12-14 -# Copyright (C) 2015 BBcan177@gmail.com +# Copyright (c) 2015 BBcan177@gmail.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License Version 2 as @@ -13,951 +13,956 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pfs_version=$(cat /etc/version | cut -c 1-3) - -if [ "${pfs_version}" = "2.2" ]; then +pfs_version=$(/bin/cat /etc/version | /usr/bin/cut -c 1-3) +if [ "${pfs_version}" = '2.2' ]; then mtype=$(/usr/bin/uname -m) prefix="/usr/pbi/pfblockerng-${mtype}" else - prefix="/usr/local" + prefix='/usr/local' fi now=$(/bin/date +%m/%d/%y' '%T) # Application Locations pathgrepcidr="${prefix}/bin/grepcidr" -pathgeoip="${prefix}/bin/geoiplookup" -pathtar=/usr/bin/tar + +# MUST EDIT !!!!! +pathaggregate=/usr/local/bin/aggregate +pathmwhois=/usr/local/bin/mwhois + + +pathgeoip="${prefix}/bin/geoiplookup" pathgunzip=/usr/bin/gunzip +pathhost=/usr/bin/host +pathtar=/usr/bin/tar pathpfctl=/sbin/pfctl # Script Arguments -alias=$2 -max=$3 -dedup=$4 -cc=$(echo $5 | sed 's/,/, /g') -ccwhite=$(echo $6 | tr '[A-Z]' '[a-z]') -ccblack=$(echo $7 | tr '[A-Z]' '[a-z]') -etblock=$(echo $8 | sed 's/,/, /g') -etmatch=$(echo $9 | sed 's/,/, /g') +alias="${2}" +max="${3}" +dedup="${4}" +cc="$(echo ${5} | sed 's/,/, /g')" +ccwhite="$(echo ${6} | tr '[A-Z]' '[a-z]')" +ccblack="$(echo ${7} | tr '[A-Z]' '[a-z]')" +etblock="$(echo ${8} | sed 's/,/, /g')" +etmatch="$(echo ${9} | sed 's/,/, /g')" # File Locations aliasarchive="${prefix}/etc/aliastables.tar.bz2" pathgeoipdat="${prefix}/share/GeoIP/GeoIP.dat" pfbsuppression=/var/db/pfblockerng/pfbsuppression.txt +pfbalexa=/var/db/pfblockerng/pfbalexawhitelist.txt masterfile=/var/db/pfblockerng/masterfile mastercat=/var/db/pfblockerng/mastercat geoiplog=/var/log/pfblockerng/geoip.log errorlog=/var/log/pfblockerng/error.log +domainmaster=/tmp/domainmaster # Folder Locations etdir=/var/db/pfblockerng/ET tmpxlsx=/tmp/xlsx/ -pfbdbdir=/var/db/pfblockerng/ +pfbdb=/var/db/pfblockerng/ pfbdeny=/var/db/pfblockerng/deny/ pfborig=/var/db/pfblockerng/original/ pfbmatch=/var/db/pfblockerng/match/ pfbpermit=/var/db/pfblockerng/permit/ pfbnative=/var/db/pfblockerng/native/ -pfsense_alias_dir=/var/db/aliastables/ +pfsensealias=/var/db/aliastables/ +pfbdomain=/var/db/pfblockerng/dnsbl/ -# Store "Match" d-dedups in matchdedup.txt file +# Store 'Match' d-dedups in matchdedup.txt file matchdedup=matchdedup.txt -tempfile=/tmp/pfbtempfile -tempfile2=/tmp/pfbtempfile2 -dupfile=/tmp//pfbduptemp -dedupfile=/tmp/pfbdeduptemp -addfile=/tmp/pfBaddfile -syncfile=/tmp/pfbsyncfile -matchfile=/tmp/pfbmatchfile -tempmatchfile=/tmp/pfbtempmatchfile - -PLATFORM=`cat /etc/platform` -USE_MFS_TMPVAR=`/usr/bin/grep -c use_mfs_tmpvar /cf/conf/config.xml` -DISK_NAME=`/bin/df /var/db/rrd | /usr/bin/tail -1 | /usr/bin/awk '{print $1;}'` -DISK_TYPE=`/usr/bin/basename ${DISK_NAME} | /usr/bin/cut -c1-2` - -if [ "${PLATFORM}" != "pfSense" ] || [ ${USE_MFS_TMPVAR} -gt 0 ] || [ "${DISK_TYPE}" = "md" ]; then - /etc/rc.conf_mount_rw >/dev/null 2>&1 - if [ ! -d $pfbdbdir ]; then mkdir $pfbdbdir; fi - if [ ! -d $pfsense_alias_dir ]; then mkdir $pfsense_alias_dir; fi +# Randomize temporary variables +rvar="$(/usr/bin/jot -r 1 1000 100000)" + +tempfile=/tmp/pfbtemp1_$rvar +tempfile2=/tmp/pfbtemp2_$rvar +dupfile=/tmp/pfbtemp3_$rvar +dedupfile=/tmp/pfbtemp4_$rvar +addfile=/tmp/pfbtemp5_$rvar +syncfile=/tmp/pfbtemp6_$rvar +matchfile=/tmp/pfbtemp7_$rvar +tempmatchfile=/tmp/pfbtemp8_$rvar + +PLATFORM="$(cat /etc/platform)" +USE_MFS_TMPVAR="$(/usr/bin/grep -c use_mfs_tmpvar /cf/conf/config.xml)" +DISK_NAME="$(/bin/df /var/db/rrd | /usr/bin/tail -1 | /usr/bin/awk '{print $1;}')" +DISK_TYPE="$(/usr/bin/basename ${DISK_NAME} | /usr/bin/cut -c1-2)" + +if [ "${PLATFORM}" != 'pfSense' ] || [ ${USE_MFS_TMPVAR} -gt 0 ] || [ "${DISK_TYPE}" = 'md' ]; then + /etc/rc.conf_mount_rw > /dev/null 2>&1 fi -if [ ! -f $masterfile ]; then touch $masterfile; fi -if [ ! -f $mastercat ]; then touch $mastercat; fi -if [ ! -f $tempfile ]; then touch $tempfile; fi -if [ ! -f $tempfile2 ]; then touch $tempfile2; fi -if [ ! -f $dupfile ]; then touch $dupfile; fi -if [ ! -f $dedupfile ]; then touch $dedupfile; fi -if [ ! -f $addfile ]; then touch $addfile; fi -if [ ! -f $syncfile ]; then touch $syncfile; fi -if [ ! -f $matchfile ]; then touch $matchfile; fi -if [ ! -f $tempmatchfile ]; then touch $tempmatchfile; fi -if [ ! -d $pfbmatch ]; then mkdir $pfbmatch; fi -if [ ! -d $etdir ]; then mkdir $etdir; fi -if [ ! -d $tmpxlsx ]; then mkdir $tmpxlsx; fi - - -# Exit Function to set mount RO if required before Exiting +if [ ! -d "${pfbdb}" ]; then mkdir "${pfbdb}"; fi +if [ ! -d "${pfsensealias}" ]; then mkdir "${pfsensealias}"; fi +if [ ! -d "${pfbmatch}" ]; then mkdir "${pfbmatch}"; fi +if [ ! -d "${etdir}" ]; then mkdir "${etdir}"; fi +if [ ! -d "${tmpxlsx}" ]; then mkdir "${tmpxlsx}"; fi + +if [ ! -f "${masterfile}" ]; then touch "${masterfile}"; fi +if [ ! -f "${mastercat}" ]; then touch "${mastercat}"; fi + + +# Exit function to set mount RO if required before exiting. exitnow() { - if [ "${PLATFORM}" != "pfSense" ] || [ ${USE_MFS_TMPVAR} -gt 0 ] || [ "${DISK_TYPE}" = "md" ]; then - /etc/rc.conf_mount_ro >/dev/null 2>&1 + if [ "${PLATFORM}" != 'pfSense' ] || [ ${USE_MFS_TMPVAR} -gt 0 ] || [ "${DISK_TYPE}" = 'md' ]; then + /etc/rc.conf_mount_ro > /dev/null 2>&1 fi + + # Remove temp files + rm -f /tmp/pfbtemp?_"${rvar}" exit } -########## -# Process to condense an IP range if a "Max" amount of IP addresses are found in a /24 range per Alias Group. -process24() { - -if [ ! -x $pathgeoip ]; then - echo "Process24 - Application [ GeoIP ] Not found. Can't proceed." - echo "Process24 - Application [ GeoIP ] Not found. Can't proceed. [ $now ]" >> $errorlog - exitnow -fi +# Function to restore aliasables from archive on reboot. ( NanoBSD and Ramdisk installations only ) +aliastables() { + if [ "${PLATFORM}" != 'pfSense' ] || [ ${USE_MFS_TMPVAR} -gt 0 ] || [ "${DISK_TYPE}" = 'md' ]; then + [ -f "${aliasarchive}" ] && cd "${pfsensealias}" && /usr/bin/tar -jxvf "${aliasarchive}" + fi +} -# Download MaxMind GeoIP.dat Binary on first Install. -if [ ! -f $pathgeoipdat ]; then - echo "Downloading [ MaxMind GeoIP.dat ] [ $now ]" >> $geoiplog - /usr/local/pkg/pfblockerng/geoipupdate.sh bu -fi -# Exit if GeoIP.dat is not found. -if [ ! -f $pathgeoipdat ]; then - echo "Process24 - Database GeoIP [ GeoIP.Dat ] not found. Can't proceed." - echo "Process24 - Database GeoIP [ GeoIP.Dat ] not found. Can't proceed. [ $now ]" >> $errorlog - exitnow -fi -count=$(grep -c ^ $pfbdeny$alias".txt") -echo; echo "Original File Count [ $count ]" - -grep -Ev "^(#|$)" $pfbdeny$alias".txt" | sort | uniq > $tempfile -> $dupfile; > $tempfile2; > $matchfile; > $tempmatchfile -data="$(cut -d '.' -f 1-3 $tempfile | awk -v max="$max" '{a[$0]++}END{for(i in a){if(a[i] > max){print i}}}')" -count=$(echo "$data" | grep -c ^); mcount=0; dcount=0; safe=0 -if [ "$data" == "" ]; then count=0; fi -matchoutfile="match"$header".txt" -# Classify Repeat Offenders by Country Code -if [ -f $pathgeoipdat ]; then - for ip in $data; do - ccheck=$($pathgeoip -f $pathgeoipdat "$ip.1" | cut -c 24-25) - case "$cc" in - *$ccheck*) - safe=$(($safe + 1)) - if [ "$ccwhite" == "match" -o "$ccblack" == "match" ]; then - echo "$ip." >> $matchfile - fi - ;; - *) - echo "$ip." >> $dupfile - ;; - esac +# Function to write '1.1.1.1' to 'empty' final blocklist files. +emptyfiles() { + emptyfiles="$(find ${pfbdeny}*.txt -size 0 2>/dev/null)" + for i in ${emptyfiles}; do + echo '1.1.1.1' > "${i}"; done -else - echo; echo "MaxMind Binary Database Missing [ $pathgeoipdat ], skipping p24 Process"; echo - echo "MaxMind Binary Database Missing [ $pathgeoipdat ], skipping p24 Process [ $now ]" >> $errorlog -fi -# Collect Match File Details -if [ -s "$matchfile" -a ! "$dedup" == "on" -a "$ccwhite" == "match" ]; then - mon=$(sed -e 's/^/^/' -e 's/\./\\\./g' $matchfile) - for ip in $mon; do - grep $ip $tempfile >> $tempfile2 - done - mcount=$(grep -c ^ $tempfile2) - if [ "$ccwhite" == "match" ]; then - sed 's/$/0\/24/' $matchfile >> $tempmatchfile - sed 's/^/\!/' $tempfile2 >> $tempmatchfile - fi -fi +} + -# If no Matches found remove previous Matchoutfile if exists. -if [ ! -s "$tempmatchfile" -a -f $matchoutfile ]; then rm -r $matchoutfile; fi -# Move Match File to the Match Folder by Individual Blocklist Name -if [ -s "$tempmatchfile" ]; then mv -f $tempmatchfile $pfbmatch$matchoutfile; fi - -# Find Repeat Offenders in each individual Blocklist Outfile -if [ -s "$dupfile" ]; then - > $tempfile2 - dup=$(sed -e 's/^/^/' -e 's/\./\\\./g' $dupfile) - for ip in $dup; do - grep $ip $tempfile >> $tempfile2 +# Function to remove lists from masterfiles and delete associated files. +remove() { + echo + for i in ${cc}; do + header="$(echo ${i%*,})" + if [ ! -z "${header}" ]; then + # Make sure that alias exists in masterfile before removal. + masterchk="$(grep -m1 '${header}[[:space:]]' ${masterfile})" + + if [ ! -z "${masterchk}" ]; then + # Grep header with a trailing space character + grep "${header}[[:space:]]" "${masterfile}" > "${tempfile}" + awk 'FNR==NR{a[$0];next}!($0 in a)' "${tempfile}" "${masterfile}" > "${tempfile2}"; mv -f "${tempfile2}" "${masterfile}" + fi + + rm -f "${pfborig}${header}"*; rm -f "${pfbdeny}${header}"*; rm -f "${pfbmatch}${header}"*; + rm -f "${pfbpermit}${header}"*; rm -f "${pfbnative}${header}"* + echo "The Following list has been REMOVED [ ${header} ]" + fi done - dcount=$(grep -c ^ $tempfile2) - if [ "$ccblack" == "block" ]; then - awk 'FNR==NR{a[$0];next}!($0 in a)' $tempfile2 $tempfile > $pfbdeny$alias".txt" - sed 's/$/0\/24/' $dupfile >> $pfbdeny$alias".txt" - elif [ "$ccblack" == "match" ]; then - sed 's/$/0\/24/' $dupfile >> $tempmatchfile - sed 's/^/\!/' $tempfile2 >> $tempmatchfile - else - : + cut -d ' ' -f2 "${masterfile}" > "${mastercat}" + + # Delete masterfiles if they are empty + if [ ! -s "${masterfile}" ]; then + rm -f "${masterfile}"; rm -f "${mastercat}" fi -fi -if [ "$count" == "0" -a "$safe" == "0" ]; then echo; echo " Process /24 Stats [ $alias ] [ $now ] "; echo "------------------------------------------------"; fi -if [ "$count" == "0" ]; then echo "Found [ 0 ] IP range(s) over the threshold of [ $max ] p24 - CC Blacklist"; fi -if [ "$safe" == "0" ]; then echo "Found [ 0 ] IP range(s) over the threshold of [ $max ] p24 - CC Whitelist"; fi - -if [ -s "$dupfile" -o -s "$matchfile" ]; then -echo -echo " Process /24 Stats [ $alias ] [ $now ]" -echo "--------------------------------------------------------" -echo "Found [ $count ] IP range(s) over the threshold of [ $max ] on the CC Blacklist" -echo "Found [ $safe ] IP range(s) over the threshold of [ $max ] on the CC Whitelist" -echo -echo "Found [ $dcount ] CC Blacklisted IP Address(es) are being set to [ $ccblack ]" -# Skip Match Process if dedup=yes as it will create duplicates -if [ "$dedup" == "on" ]; then mcount=Skipped; fi -echo "Found [ $mcount ] CC Whitelisted IP Address(es) are being set to [ $ccwhite ]" -if [ "$ccblack" == "block" ]; then - echo; echo "Removed the following IP Ranges" - cat $dupfile | tr '\n' '|'; echo -else - echo "Skipped, CCBlack set to [ $ccblack ]" -fi -sort $pfbdeny$alias".txt" | uniq > $tempfile; mv -f $tempfile $pfbdeny$alias".txt" -echo "-------------------------------------------------------" -cocount=$(grep -cv "^1\.1\.1\.1" $pfbdeny$alias".txt") -echo "Post /24 Count [ $cocount ]"; echo -fi -exitnow } -########## +# Function to remove IPs if exists over 253 IPs in a range and replace with a single /24 block. (excl. '0' & '255') process255() { -# Remove IPs if exists over 255 IPs in a Range and replace with a single /24 Block -cp $pfbdeny$alias".txt" $tempfile; > $dedupfile - -data255="$(cut -d '.' -f 1-3 $tempfile | awk '{a[$0]++}END{for(i in a){if(a[i] > 255){print i}}}')" -if [ ! -z "$data255" ]; then - for ip in $data255; do - ii=$(echo "^$ip." | sed 's/\./\\\./g') - grep $ii $tempfile >> $dedupfile - done - awk 'FNR==NR{a[$0];next}!($0 in a)' $dedupfile $tempfile > $pfbdeny$alias".txt" - for ip in $data255; do echo $ip".0/24" >> $pfbdeny$alias".txt"; done -fi -} + > "${dedupfile}" + data255="$(cut -d '.' -f 1-3 ${pfbdeny}${alias}.txt | awk '{a[$0]++}END{for(i in a){if(a[i] > 253){print i}}}')" + if [ ! -z "${data255}" ]; then + cp "${pfbdeny}${alias}.txt" "${tempfile}" -########## -continent() { + for ip in ${data255}; do + ii="$(echo ^${ip}. | sed 's/\./\\\./g')" + grep "${ii}" "${tempfile}" >> "${dedupfile}" + done -dupcheck=yes -# Check if Masterfile is Empty -hcheck=$(grep -c ^ $masterfile); if [ "$hcheck" -eq "0" ]; then dupcheck=no; fi -# Check if Alias exists in Masterfile -lcheck=$(grep -m 1 "$alias " $masterfile ); if [ "$lcheck" == "" ]; then dupcheck=no; fi -# Check for single alias in masterfile -aliaslist=$(cut -d' ' -f1 $masterfile | sort | uniq); if [ "$alias" == "$aliaslist" ]; then hcheck="0"; fi + awk 'FNR==NR{a[$0];next}!($0 in a)' "${dedupfile}" "${tempfile}" > "${pfbdeny}${alias}.txt" + for ip in ${data255}; do echo "${ip}.0/24" >> "${pfbdeny}${alias}.txt"; done + fi +} -if [ "$dupcheck" == "yes" ]; then - # Grep Alias with a trailing Space character - grep "$alias[[:space:]]" $masterfile > $tempfile - awk 'FNR==NR{a[$0];next}!($0 in a)' $tempfile $masterfile > $tempfile2; mv -f $tempfile2 $masterfile - cut -d' ' -f2 $masterfile > $mastercat -fi +# Process to remove suppressed entries. +suppress() { + if [ ! -x "${pathgrepcidr}" ]; then + log="Application [ grepcidr ] Not found. Cannot proceed." + echo "${log}" | tee -a "${errorlog}" + exitnow + fi -grep -Ev "^(#|$)" $pfbdeny$alias".txt" | sort | uniq > $tempfile + if [ -e "${pfbsuppression}" ] && [ -s "${pfbsuppression}" ]; then + data="$(cat ${pfbsuppression} | sort | uniq)" -if [ ! "$hcheck" -eq "0" ]; then - $pathgrepcidr -vf $mastercat $pfbdeny$alias".txt" > $tempfile; mv -f $tempfile $pfbdeny$alias".txt" -fi + if [ ! -z "${data}" ] && [ ! -z "${cc}" ]; then + if [ "${cc}" == 'suppressheader' ]; then + echo; echo '===[ Suppression Stats ]==================================='; echo + printf "%-20s %-10s %-10s %-10s\n" 'List' 'Pre' 'Suppress' 'Master' + echo '-----------------------------------------------------------' + exitnow + fi -sed -e 's/^/'$alias' /' $pfbdeny$alias".txt" >> $masterfile -cut -d' ' -f2 $masterfile > $mastercat - -countg=$(grep -c ^ $pfborig$alias".orig") -countm=$(grep -c "$alias " $masterfile); counto=$(grep -c ^ $pfbdeny$alias".txt") -if [ "$countm" == "$counto" ]; then sanity="Passed"; else sanity=" ==> FAILED <== "; fi -echo "----------------------------------------------------------" -echo; echo " Post Duplication count [ $now ]" -echo "----------------------------------------------------------" -printf "%-10s %-10s %-10s %-30s\n" "Original" "Masterfile" "Outfile" "Sanity Check" -echo "----------------------------------------------------------" -printf "%-10s %-10s %-10s %-30s\n" "$countg" "$countm" "$counto" " [ $sanity ]" -echo "----------------------------------------------------------" -exitnow -} + alias="$(echo ${cc%|*})" + pfbfolder="$(echo ${cc#*|})" + counter=0; > "${dupfile}" + if [ ! -z "${alias}" ]; then + countg="$(grep -c ^ ${pfbfolder}${alias}.txt)" + cp "${pfbfolder}${alias}.txt" "${tempfile}" -########## -# Process to remove Suppressed Entries and RFC 1918 and Misc IPs on each downloaded Blocklist -suppress() { + for ip in ${data}; do + found=''; dcheck=''; + mask="$(echo ${ip##*/})" + iptrim="$(echo "${ip%.*}")" + ip="$(echo ${ip%%/*})" + found="$(grep -m1 ${iptrim}.0/24 ${tempfile})" -if [ ! -x $pathgrepcidr ]; then - echo "Application [ Grepcidr ] Not found. Can't proceed. [ $now ]" - echo "Application [ Grepcidr ] Not found. Can't proceed. [ $now ]" >> errorlog - exitnow -fi + # If a suppression is '/32' and a blocklist has a full '/24' block, execute the following. + if [ ! -z "${found}" ] && [ "${mask}" -eq 32 ]; then + echo " Suppression ${alias}: ${iptrim}.0/24" + octet4="$(echo ${ip##*.})" + dcheck="$(grep ${iptrim}.0/24 ${dupfile})" -if [ -e "$pfbsuppression" ] && [ -s "$pfbsuppression" ]; then - # Find '/24' Blocked IPs that are single addresses in the Suppressed IP Address List. - # These '/24' Are converted to single Addresses excluding the Suppressed IPs. - data="$(cat $pfbsuppression)" - if [ ! -z "$data" -a ! -z "$cc" ]; then - # Loop thru each Updated List to remove Suppression and RFC1918 Addresses - if [ "$cc" == "suppressheader" ]; then - echo; echo "===[ Suppression Stats ]========================================"; echo - printf "%-20s %-10s %-10s %-10s %-10s\n" "List" "Pre" "RFC1918" "Suppress" "Masterfile" - echo "----------------------------------------------------------------" - exitnow - fi + if [ -z "${dcheck}" ]; then + echo "${iptrim}.0/24" >> "${dupfile}" + counter="$((counter + 1))" - for i in $cc; do - counter=0 - > $dupfile - alias=$(echo "${i%|*}") - pfbfolder=$(echo "${i#*|}") - - if [ ! "$alias" == "" ]; then - # Count (PRE) - countg=$(grep -c ^ $pfbfolder$alias".txt") - - grep -Ev "^(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.|#|$)" $pfbfolder$alias".txt" | - sort | uniq > $tempfile - # Count (Post RFC1918) - countm=$(grep -c ^ $tempfile) - - for ip in $data; do - found=""; ddcheck=""; - iptrim=$(echo $ip | cut -d '.' -f 1-3) - mask=$(echo $ip | cut -d"/" -f2) - found=$(grep -m1 $iptrim".0/24" $tempfile) - # If a Suppression is '/32' and a Blocklist has a full '/24' Block execute the following. - if [ ! "$found" == "" -a "$mask" == "32" ]; then - echo " Suppression $alias: $iptrim.0/24" - octet4=$(echo $ip | cut -d '.' -f 4 | sed 's/\/.*//') - dcheck=$(grep $iptrim".0/24" $dupfile) - if [ "$dcheck" == "" ]; then - echo $iptrim".0/24" >> $dupfile - counter=$(($counter + 1)) - # Add Individual IP addresses from Range excluding Suppressed IP + # Add individual IP addresses from range excluding suppressed IP for i in $(/usr/bin/jot 255); do - if [ "$i" != "$octet4" ]; then - echo $iptrim"."$i >> $tempfile - counter=$(($counter + 1)) + if [ "${i}" != "${octet4}" ]; then + echo "${iptrim}.${i}" >> "${tempfile}" + counter="$((counter + 1))" fi done fi fi done - if [ -s $dupfile ]; then - # Remove '/24' Suppressed Ranges - awk 'FNR==NR{a[$0];next}!($0 in a)' $dupfile $tempfile > $tempfile2; mv -f $tempfile2 $tempfile + + if [ -s "${dupfile}" ]; then + # Remove '/24' suppressed ranges + awk 'FNR==NR{a[$0];next}!($0 in a)' "${dupfile}" "${tempfile}" > "${tempfile2}"; mv -f "${tempfile2}" "${tempfile}" fi - # Remove All other Suppressions from Lists - $pathgrepcidr -vf $pfbsuppression $tempfile > $pfbfolder$alias".txt" - # Update Masterfiles. Don't execute if Duplication Process is Disabled - if [ "$dedup" == "x" ]; then - # Dont execute if Alias doesnt exist in Masterfile - lcheck=$(grep -m1 "$alias " $masterfile) - if [ ! "$lcheck" == "" ]; then - # Replace Masterfile with changes to List. - grep "$alias[[:space:]]" $masterfile > $tempfile - awk 'FNR==NR{a[$0];next}!($0 in a)' $tempfile $masterfile > $tempfile2; mv -f $tempfile2 $masterfile - sed -e 's/^/'$alias' /' $pfbfolder$alias".txt" >> $masterfile - cut -d' ' -f2 $masterfile > $mastercat + + # Remove all other suppressions from list + "${pathgrepcidr}" -vf "${pfbsuppression}" "${tempfile}" > "${pfbfolder}${alias}.txt" + + # Update masterfiles. Don't execute if duplication process is disabled + if [ "${dedup}" == 'x' ]; then + # Don't execute if alias doesn't exist in masterfile + lcheck="$(grep -m1 ${alias} ${masterfile})" + + if [ ! -z "${lcheck}" ]; then + # Replace masterfile with changes to list. + grep "${alias}[[:space:]]" "${masterfile}" > "${tempfile}" + awk 'FNR==NR{a[$0];next}!($0 in a)' "${tempfile}" "${masterfile}" > "${tempfile2}" + mv -f "${tempfile2}" "${masterfile}" + sed -e 's/^/'$alias' /' "${pfbfolder}${alias}.txt" >> "${masterfile}" + cut -d ' ' -f2 "${masterfile}" > "${mastercat}" fi fi - countk=$(grep -c ^ $masterfile) - countx=$(grep -c ^ $pfbfolder$alias".txt") - counto=$(($countx - $counter)) - printf "%-20s %-10s %-10s %-10s %-10s\n" "$alias" "$countg" "$countm" "$counto" "$countk" + + countk="$(grep -c ^ ${masterfile})" + countx="$(grep -c ^ ${pfbfolder}${alias}.txt)" + counto="$((countx - counter))" + printf "%-20s %-10s %-10s %-10s\n" "${alias}" "${countg}" "${counto}" "${countk}" fi - done + fi fi -else - if [ "$cc" == "suppressheader" ]; then - echo; echo "===[ Suppression Stats ]========================================"; echo - printf "%-20s %-10s %-10s %-10s %-10s\n" "List" "Pre" "RFC1918" "Suppress" "Masterfile" - echo "----------------------------------------------------------------" - exitnow +} + + +# Function to optimise CIDRs +cidr_aggregate() { + if [ ! -x "${pathaggregate}" ]; then + log="Application [ aggregate ] Not found. Cannot proceed." + echo "${log}" | tee -a "${errorlog}" + return + fi + + if [ "${agg_folder}" = true ]; then + # Use $3 folder path + pfbfolder="${max}/" + else + pfbfolder="${pfbdeny}" + fi + + counto="$(grep -c ^ ${pfbfolder}${alias}.txt)" + retval="$(cat "${pfbfolder}${alias}.txt" | "${pathaggregate}" -t -p 32 -m 32 -o 32 2>&1 > ${tempfile})" + sed 's/\/32//' "${tempfile}" > "${pfbfolder}${alias}.txt" + countf="$(grep -c ^ ${pfbfolder}${alias}.txt)" + + # Report errors (First two lines are informational only) + aggstring='aggregate: maximum prefix length permitted will be 32aggregate: prefix length of 32 bits will be used where none specified' + retval2=$(echo "${retval}" | tr -d '\n\r' | sed "s/${aggstring}//g") + if [ ! -z "${retval2}" ]; then + echo "${retval2}" + fi + + if [ "${counto}" != "${countf}" ]; then + echo; echo ' Aggregation Stats:' + echo ' ------------------' + printf "%-10s %-10s \n" ' Original' 'Final' + echo ' ------------------' + printf "%-10s %-10s \n" " ${counto}" "${countf}" + echo ' ------------------' fi - for i in $cc; do - alias=$(echo "${i%|*}") - pfbfolder=$(echo "${i#*|}") - - if [ ! "$alias" == "" ]; then - countg=$(grep -c ^ $pfbfolder$alias".txt") - grep -Ev "^(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.|#|$)" $pfbfolder$alias".txt" | - sort | uniq > $tempfile; mv -f $tempfile $pfbfolder$alias".txt" - countx=$(grep -c ^ $pfbfolder$alias".txt") - # Update Masterfiles. Don't execute if Duplication Process is Disabled or if No Suppression Changes Found - if [ "$dedup" == "x" -a "$countg" != "$countx" ]; then - # Dont execute if Alias doesnt exist in Masterfile - lcheck=$(grep -m1 "$alias " $masterfile) - if [ ! "$lcheck" == "" ]; then - # Replace Masterfile with changes to List. - grep "$alias[[:space:]]" $masterfile > $tempfile - awk 'FNR==NR{a[$0];next}!($0 in a)' $tempfile $masterfile > $tempfile2; mv -f $tempfile2 $masterfile - sed -e 's/^/'$alias' /' $pfbfolder$alias".txt" >> $masterfile - cut -d' ' -f2 $masterfile > $mastercat - fi - fi - countm=$(grep -c ^ $pfbfolder$alias".txt") - counto=" - " - countk=$(grep -c ^ $masterfile) - printf "%-20s %-10s %-10s %-10s %-10s\n" "$alias" "$countg" "$countm" "$counto" "$countk" - fi - done -fi -exitnow } -########## -# Process to remove Duplicate Entries on each downloaded Blocklist Individually +# Function to remove duplicate entries in each list individually. duplicate() { + if [ ! -x "${pathgrepcidr}" ]; then + log="Application [ grepcidr ] Not found. Cannot proceed." + echo "${log}" | tee -a "${errorlog}" + exitnow + fi -if [ ! -x $pathgrepcidr ]; then - echo "Application [ Grepcidr ] Not found. Can't proceed. [ $now ]" - echo "Application [ Grepcidr ] Not found. Can't proceed. [ $now ]" >> errorlog - exitnow -fi + dupcheck=1 + # Check if masterfile is empty + hcheck="$(grep -cv ^$ ${masterfile})"; if [ "${hcheck}" -eq 0 ]; then dupcheck=0; fi + # Check if alias exists in masterfile + lcheck="$(grep -m1 ${alias} ${masterfile})"; if [ -z "${lcheck}" ]; then dupcheck=0; fi + # Check for single alias in masterfile + aliaslist="$(cut -d ' ' -f1 ${masterfile} | sort | uniq)"; if [ "${alias}" == "${aliaslist}" ]; then hcheck=0; fi + + # Only execute if 'Alias' exists in masterfile + if [ "${dupcheck}" -eq 1 ]; then + # Grep alias with a trailing space character + grep "${alias}[[:space:]]" "${masterfile}" > "${tempfile}" + awk 'FNR==NR{a[$0];next}!($0 in a)' "${tempfile}" "${masterfile}" > "${tempfile2}"; mv -f "${tempfile2}" "${masterfile}" + cut -d ' ' -f2 "${masterfile}" > "${mastercat}" + fi -dupcheck=yes -# Check if Masterfile is Empty -hcheck=$(grep -cv "^$" $masterfile); if [ "$hcheck" -eq "0" ]; then dupcheck=no; fi -# Check if Alias exists in Masterfile -lcheck=$(grep -m1 "$alias " $masterfile); if [ "$lcheck" == "" ]; then dupcheck=no; fi -# Check for single alias in masterfile -aliaslist=$(cut -d' ' -f1 $masterfile | sort | uniq); if [ "$alias" == "$aliaslist" ]; then hcheck="0"; fi - -if [ "$dupcheck" == "yes" ]; then - # Grep Alias with a trailing Space character - grep "$alias[[:space:]]" $masterfile > $tempfile - awk 'FNR==NR{a[$0];next}!($0 in a)' $tempfile $masterfile > $tempfile2; mv -f $tempfile2 $masterfile - cut -d' ' -f2 $masterfile > $mastercat -fi + # Don't execute when only a single 'Alias' exists in masterfile + if [ ! "${hcheck}" -eq 0 ]; then + sort "${pfbdeny}${alias}.txt" | uniq > "${tempfile}"; mv -f "${tempfile}" "${pfbdeny}${alias}.txt" + "${pathgrepcidr}" -vf "${mastercat}" "${pfbdeny}${alias}.txt" > "${tempfile}"; mv -f "${tempfile}" "${pfbdeny}${alias}.txt" + fi -grep -Ev "^(#|$)" $pfbdeny$alias".txt" | sort | uniq > $tempfile; mv -f $tempfile $pfbdeny$alias".txt" + sed -e 's/^/'$alias' /' "${pfbdeny}${alias}.txt" >> "${masterfile}" + cut -d ' ' -f2 "${masterfile}" > "${mastercat}" -if [ ! "$hcheck" -eq "0" ]; then - $pathgrepcidr -vf $mastercat $pfbdeny$alias".txt" > $tempfile; mv -f $tempfile $pfbdeny$alias".txt" -fi + counto="$(grep -cv '^#\|^$' ${pfborig}${alias}.orig)" + countm="$(grep -c ${alias} ${masterfile})" + countf="$(grep -c ^ ${pfbdeny}${alias}.txt)" -sed -e 's/^/'$alias' /' $pfbdeny$alias".txt" >> $masterfile -cut -d' ' -f2 $masterfile > $mastercat - -countg=$(grep -c ^ $pfborig$alias".orig") -countm=$(grep -c "$alias " $masterfile); counto=$(grep -c ^ $pfbdeny$alias".txt") -if [ "$countm" == "$counto" ]; then sanity="Passed"; else sanity=" ==> FAILED <== "; fi -echo "----------------------------------------------------------" -printf "%-10s %-10s %-10s %-30s\n" "Original" "Masterfile" "Outfile" " [ Post Duplication count ]" -echo "----------------------------------------------------------" -printf "%-10s %-10s %-10s %-30s\n" "$countg" "$countm" "$counto" " [ $sanity ]" -echo "----------------------------------------------------------" -exitnow -} + if [ "${countm}" -eq "${countf}" ]; then + sanity='Pass' + else + sanity=' ==> FAILED <== ' + fi + echo ' ------------------------------' + printf "%-10s %-10s %-10s\n" ' Original' 'Master' 'Final' + echo ' ------------------------------' + printf "%-10s %-10s %-10s %-10s\n" " ${counto}" "${countm}" "${countf}" " [ ${sanity} ]" + echo ' -----------------------------------------------------------------' +} -########## -# De-Duplication utilizing MaxMind GeoIP Country Code Whitelisting ("dmax" variable) -deduplication() { -if [ ! -x $pathgeoip ]; then - echo "d-duplication - Application [ GeoIP ] Not found. Can't proceed." - echo "d-duplication - Application [ GeoIP ] Not found. Can't proceed. [ $now ]" >> $errorlog - exitnow -fi +# Function to remove duplicate DNSBL domain names from feeds. +domainduplicate() { + # Alexa Whitelist variables + alexa_enable="${max}" -# Download MaxMind GeoIP.dat on first Install. -if [ ! -f $pathgeoipdat ]; then - echo "Downloading [ MaxMind GeoIP.dat ] [ $now ]" >> $geoiplog - /usr/local/pkg/pfblockerng/geoipupdate.sh bu -fi + counto="$(grep -c ^ ${pfbdomain}${alias}.bk)" + if [ -d "${pfbdomain}" ] && [ "$(ls -A ${pfbdomain}*.txt 2>/dev/null)" ]; then + sort "${pfbdomain}${alias}.bk" | uniq > "${pfbdomain}${alias}.bk2" + countu="$(grep -c ^ ${pfbdomain}${alias}.bk2)" + find "${pfbdomain}"*.txt ! -name "${alias}.txt" | xargs cat > "${domainmaster}" -# Exit if GeoIP.dat is not found -if [ ! -f $pathgeoipdat ]; then - echo "d-duplication - Database GeoIP [ GeoIP.Dat ] not found. Can't proceed." - echo "d-duplication - Database GeoIP [ GeoIP.Dat ] not found. Can't proceed. [ $now ]" >> $errorlog - exitnow -fi + # Only execute awk command, if master domain file contains data. + counta="$(grep -c ^ ${domainmaster})" + if [ "${counta}" -gt 0 ]; then + awk 'FNR==NR{a[$0];next}!($0 in a)' "${domainmaster}" "${pfbdomain}${alias}.bk2" > "${pfbdomain}${alias}.bk" + fi -> $tempfile; > $tempfile2; > $dupfile; > $addfile; > $dedupfile; > $matchfile; > $tempmatchfile; count=0; dcount=0; mcount=0; mmcount=0 -echo; echo "Querying for Repeat Offenders" -data="$(find $pfbdeny ! -name "pfB*.txt" ! -name "*_v6.txt" -type f | xargs cut -d '.' -f 1-3 | - awk -v max="$max" '{a[$0]++}END{for(i in a){if(a[i] > max){print i}}}' | grep -v "^1\.1\.1")" -count=$(echo "$data" | grep -c ^) -if [ "$data" == "" ]; then count=0; fi -safe=0 -# Classify Repeat Offenders by Country Code -if [ -f $pathgeoipdat ]; then - echo "Classifying Repeat Offenders by GeoIP" - for ip in $data; do - ccheck=$($pathgeoip -f $pathgeoipdat "$ip.1" | cut -c 24-25) - case "$cc" in - *$ccheck*) - safe=$(($safe + 1)) - if [ "$ccwhite" == "match" -o "$ccblack" == "match" ]; then - echo "$ip." >> $matchfile - fi - ;; - *) - echo "$ip." >> $dupfile - ;; - esac - done -else - echo; echo "MaxMind Binary Database Missing [ $pathgeoipdat ], skipping d-dedup Process"; echo - echo "MaxMind Binary Database Missing [ $pathgeoipdat ], skipping d-dedup Process [ $now ]" >> $errorlog -fi -if [ -s "$matchfile" -a "$ccwhite" == "match" ]; then - echo "Processing [ Match ] IPs" - match=$(sed -e 's/^/^/' -e 's/\./\\\./g' $matchfile) - for mfile in $match; do - grep $mfile $pfbdeny*.txt >> $tempfile - done - sed 's/$/0\/24/' $matchfile >> $tempmatchfile - sed -e 's/.*://' -e 's/^/\!/' $tempfile >> $tempmatchfile - mv -f $tempmatchfile $pfbmatch$matchdedup - mcount=$(grep -c ^ $tempfile) - mmcount=$(($mcount + $mmcount)) -fi -# Find Repeat Offenders in each individual Blocklist Outfile -if [ -s "$dupfile" ]; then - echo "Processing [ Block ] IPs" - dup=$(cat $dupfile) - for ip in $dup; do - pcount=1; ii=$(echo "^$ip" | sed 's/\./\\\./g') - list=$(find $pfbdeny ! -name "pfB*.txt" ! -name "*_v6.txt" -type f | xargs grep -al $ii) - for blfile in $list; do - header=$(echo "${blfile##*/}" | cut -d '.' -f1) - grep $ii $blfile > $tempfile - if [ "$ccblack" == "block" ]; then - awk 'FNR==NR{a[$0];next}!($0 in a)' $tempfile $blfile > $tempfile2; mv -f $tempfile2 $blfile - if [ "$pcount" -eq "1" ]; then - echo $ip"0/24" >> $blfile - echo $header" "$ip >> $dedupfile - echo $header" "$ip"0/24" >> $addfile - pcount=2 - else - echo $header" "$ip >> $dedupfile - fi - else - if [ "$pcount" -eq "1" ]; then - matchoutfile="match"$header".txt" - echo $ip"0/24" >> $pfbmatch$matchoutfile - sed 's/^/\!/' $tempfile >> $pfbmatch$matchoutfile - mcount=$(grep -c ^ $pfbmatch$matchoutfile) - mmcount=$(($mcount + $mmcount)) - pcount=2 - fi - fi - done - done - # Remove Repeat Offenders in Masterfiles - if [ -s "$dedupfile" ]; then - echo "Removing [ Block ] IPs" - > $tempfile; > $tempfile2 - sed 's/\./\\\./g' $dedupfile > $tempfile2 - while IFS=' ' read -r ips; do grep "$ips" $masterfile >> $tempfile; done < $tempfile2 - dcount=$(grep -c ^ $tempfile) - awk 'FNR==NR{a[$0];next}!($0 in a)' $tempfile $masterfile > $tempfile2; mv -f $tempfile2 $masterfile - cat $addfile >> $masterfile - cut -d' ' -f2 $masterfile > $mastercat + rm -f "${domainmaster}"; rm -f "${pfbdomain}${alias}.bk2" + countf="$(grep -c ^ ${pfbdomain}${alias}.bk)" + countd="$((countu - countf))" + else + sort "${pfbdomain}${alias}.bk" | uniq > "${pfbdomain}${alias}.bk2" && mv -f "${pfbdomain}${alias}.bk2" "${pfbdomain}${alias}.bk" + countf="$(grep -c ^ ${pfbdomain}${alias}.bk)" + countd=0; countu="${counto}" fi -fi -echo; echo "d-Duplication Process [ $now ]"; echo "------------------------------------------------" -echo; echo "Found [ $count ] IP range(s) over the threshold of dmax= [ $max ]" -echo "Found [ $safe ] IP range(s) classified as Whitelisted" -echo; echo "Found [ $dcount ] CC Blacklisted IP Address(es) are being set to [ $ccblack ]" -echo "Found [ $mmcount ] CC Whitelisted IP Address(es) are being set to [ $ccwhite ]"; echo -if [ -s "$addfile" ]; then - echo; echo "Removed the following IP Ranges" - sed -e 's/^.* //' -e 's/0\/24//' $addfile | tr '\n' '|'; echo -fi -count=$(grep -c ^ $masterfile) -echo " [ Post d-Deduplication count ] [ $count ]"; echo + if [ "${alexa_enable}" == 'on' ]; then + awk 'FNR==NR{a[$0];next}!($0 in a)' "${pfbalexa}" "${pfbdomain}${alias}.bk" > "${pfbdomain}${alias}.bk2" + countw="$(grep -c ^ ${pfbdomain}${alias}.bk2)" + counta="$((countf - countw))" + + if [ "${counta}" -gt 0 ]; then + data="$(awk 'FNR==NR{a[$0];next}!($0 in a)' ${pfbdomain}${alias}.bk2 ${pfbdomain}${alias}.bk | \ + cut -d '"' -f2 | cut -d ' ' -f1 | sort | uniq | tr '\n' '|')" + echo; echo; echo " Alexa Whitelist: ${data}" + mv -f "${pfbdomain}${alias}.bk2" "${pfbdomain}${alias}.bk" + countf="$((countw))" + else + rm -f "${pfbdomain}${alias}.bk2" + fi + else + counta='-' + fi -# Write "1.1.1.1" to empty Final Blocklist Files -emptyfiles=$(find $pfbdeny -size 0) -for i in $emptyfiles; do echo "1.1.1.1" > $i; done -exitnow + echo; echo ' ------------------------------------------------' + printf "%-10s %-10s %-10s %-10s %-10s\n" ' Original' 'Unique' '# Dups' 'Alexa' 'Final' + echo ' ------------------------------------------------' + printf "%-10s %-10s %-10s %-10s %-10s\n" " ${counto}" "${countu}" "${countd}" "${counta}" "${countf}" + echo ' ------------------------------------------------' } -########## -# Process to perform a final De-Duplication on all of the BlockLists (Excluding Country Whitelist) ("pmax" variable). -pdeduplication(){ +# Function to convert Domains/ASs to its respective IP addresses +whoisconvert() { + if [ ! -x "${pathmwhois}" ]; then + log="Application [ mwhois ] Not found. Cannot proceed." + echo "${log}" | tee -a "${errorlog}" + exitnow + fi -if [ ! -x $pathgeoip ]; then - echo "p-duplication - Application [ GeoIP ] Not found. Can't proceed." - echo "p-duplication - Application [ GeoIP ] Not found. Can't proceed. [ $now ]" >> $errorlog - exitnow -fi + vtype="${max}" + custom_list="$(echo ${dedup} | tr ',' ' ')" + rm -f "${pfborig}${alias}.orig" -# Download MaxMind GeoIP.dat on first Install. -if [ ! -f $pathgeoipdat ]; then - echo "Downloading [ MaxMind GeoIP.dat ] [ $now ]" >> $geoiplog - /usr/local/pkg/pfblockerng/geoipupdate.sh bu -fi -# Exit if GeoIP.dat is not found. -if [ ! -f $pathgeoipdat ]; then - echo "p-duplication - Database GeoIP [ GeoIP.Dat ] not found. Can't proceed." - echo "p-duplication - Database GeoIP [ GeoIP.Dat ] not found. Can't proceed. [ $now ]" >> $errorlog - exitnow -fi + if [ "${vtype}" == '_v4' ]; then + _type=A + _route=route + _opt=gAS + else + _type=AAAA + _route=route6 + _opt=6AS + fi -> $tempfile; > $tempfile2; > $dupfile; > $addfile; > $dedupfile; count=0; dcount=0 -echo; echo "=====================================================================" -echo; echo "Querying for Repeat Offenders" -data="$(find $pfbdeny ! -name "pfB*.txt" ! -name "*_v6.txt" -type f | xargs cut -d '.' -f 1-3 | - awk -v max="$max" '{a[$0]++}END{for(i in a){if(a[i] > max){print i}}}' | grep -v "^1\.1\.1")" -count=$(echo "$data" | grep -c ^) -if [ "$data" == "" ]; then count=0; fi -# Find Repeat Offenders in each individual Blocklist Outfile -echo "Processing [ Block ] IPs" -for ip in $data; do - pcount=1; ii=$(echo "^$ip." | sed 's/\./\\\./g') - list=$(find $pfbdeny ! -name "pfB*.txt" ! -name "*_v6.txt" -type f | xargs grep -al $ii) - for blfile in $list; do - header=$(echo "${blfile##*/}" | cut -d '.' -f1) - grep $ii $blfile > $tempfile - awk 'FNR==NR{a[$0];next}!($0 in a)' $tempfile $blfile > $tempfile2; mv -f $tempfile2 $blfile - if [ "$pcount" -eq "1" ]; then - echo $ip".0/24" >> $blfile - echo $header" $ip." >> $dedupfile - echo $header" "$ip".0/24" >> $addfile - pcount=2 + for host in ${custom_list}; do + # Determine if host is a Domain or an AS + host_check="$(echo ${host} | grep '\.')" + if [ ! -z "${host_check}" ]; then + echo "### Domain: ${host} ###" >> "${pfborig}${alias}.orig" + ${pathhost} -t ${_type} ${host} | sed 's/^.* //' >> "${pfborig}${alias}.orig" else - echo $header" $ip." >> $dedupfile + asn="$(echo ${host} | tr -d 'AaSs')" + echo "### AS${asn}: ${host} ###" >> "${pfborig}${alias}.orig" + "${pathmwhois}" -h whois.radb.net \!"${_opt}${asn}" | tail -n +2 | tr -d '\nC' | tr ' ' '\n' >> "${pfborig}${alias}.orig" fi - done -done -# Remove Repeat Offenders in Masterfile -if [ -s "$dedupfile" ]; then - echo "Removing [ Block ] IPs" - > $tempfile; > $tempfile2 - sed 's/\./\\\./g' $dedupfile > $tempfile2 - while IFS=' ' read -r ips; do grep "$ips" $masterfile >> $tempfile; done < $tempfile2 - dcount=$(grep -c ^ $tempfile) - awk 'FNR==NR{a[$0];next}!($0 in a)' $tempfile $masterfile > $tempfile2; mv -f $tempfile2 $masterfile - cat $addfile >> $masterfile - cut -d' ' -f2 $masterfile > $mastercat -fi - -echo; echo "p-Duplication Process [ $now ]"; echo "------------------------------------------------" -echo "Found [ $dcount ] IP Address(es) are being set to [ block ]" -if [ -s "$addfile" ]; then - echo; echo "Removed the following IP Ranges" - sed -e 's/^.* //' -e 's/0\/24//' $addfile | tr '\n' '|'; echo -fi -count=$(grep -c ^ $masterfile) -echo; echo " [ Post p-Deduplication count ] [ $count ]" -# Write "1.1.1.1" to empty Final Blocklist Files -emptyfiles=$(find $pfbdeny -size 0) -for i in $emptyfiles; do echo "1.1.1.1" > $i; done -exitnow + echo >> "${pfborig}${alias}.orig" + done } -########## -# Process to Split ET Pro IPREP into Category Files and Compile selected Blocked categories into Outfile -processet() { +# Function to check for Reputation application dependencies. +reputation_depends() { + if [ ! -x "${pathgeoip}" ]; then + log="Application [ GeoIP ] Not found, cannot proceed. [ ${now} ]" + echo "${log}" | tee -a "${errorlog}" + return + fi -if [ ! -x $pathgunzip ]; then - echo "Application [ Gunzip ] Not found, Can't proceed." - echo "Application [ Gunzip ] Not found, Can't proceed. [ $now ]" >> $errorlog - exitnow -fi + # Download MaxMind GeoIP.dat on first install. + if [ ! -f "${pathgeoipdat}" ]; then + echo "Downloading [ MaxMind GeoIP.dat ] [ ${now} ]" >> "${geoiplog}" + /usr/local/bin/php /usr/local/www/pfblockerng/pfblockerng.php bu + fi -if [ -s $pfborig$alias".gz" ]; then - evar="ET_*" - # Remove Previous ET IPRep Files - [ -d $etdir ] && [ "$(ls -A $etdir)" ] && rm -r $etdir/$evar - > $tempfile; > $tempfile2 - - $pathgunzip -c $pfborig$alias".gz" > $pfborig$alias".raw" - - # ET CSV Format (IP, Category, Score) - while IFS="," read a b c; do - # Some ET Categories are not in use (For Future Use) - case "$b" in - 1) echo $a >> $etdir/ET_Cnc;; - 2) echo $a >> $etdir/ET_Bot;; - 3) echo $a >> $etdir/ET_Spam;; - 4) echo $a >> $etdir/ET_Drop;; - 5) echo $a >> $etdir/ET_Spywarecnc;; - 6) echo $a >> $etdir/ET_Onlinegaming;; - 7) echo $a >> $etdir/ET_Drivebysrc;; - 8) echo $a >> $etdir/ET_Cat8;; - 9) echo $a >> $etdir/ET_Chatserver;; - 10) echo $a >> $etdir/ET_Tornode;; - 11) echo $a >> $etdir/ET_Cat11;; - 12) echo $a >> $etdir/ET_Cat12;; - 13) echo $a >> $etdir/ET_Compromised;; - 14) echo $a >> $etdir/ET_Cat14;; - 15) echo $a >> $etdir/ET_P2P;; - 16) echo $a >> $etdir/ET_Proxy;; - 17) echo $a >> $etdir/ET_Ipcheck;; - 18) echo $a >> $etdir/ET_Cat18;; - 19) echo $a >> $etdir/ET_Utility;; - 20) echo $a >> $etdir/ET_DDos;; - 21) echo $a >> $etdir/ET_Scanner;; - 22) echo $a >> $etdir/ET_Cat22;; - 23) echo $a >> $etdir/ET_Brute;; - 24) echo $a >> $etdir/ET_Fakeav;; - 25) echo $a >> $etdir/ET_Dyndns;; - 26) echo $a >> $etdir/ET_Undesireable;; - 27) echo $a >> $etdir/ET_Abusedtld;; - 28) echo $a >> $etdir/ET_Selfsignedssl;; - 29) echo $a >> $etdir/ET_Blackhole;; - 30) echo $a >> $etdir/ET_RAS;; - 31) echo $a >> $etdir/ET_P2Pcnc;; - 32) echo $a >> $etdir/ET_Sharedhosting;; - 33) echo $a >> $etdir/ET_Parking;; - 34) echo $a >> $etdir/ET_VPN;; - 35) echo $a >> $etdir/ET_Exesource;; - 36) echo $a >> $etdir/ET_Cat36;; - 37) echo $a >> $etdir/ET_Mobilecnc;; - 38) echo $a >> $etdir/ET_Mobilespyware;; - 39) echo $a >> $etdir/ET_Skypenode;; - 40) echo $a >> $etdir/ET_Bitcoin;; - 41) echo $a >> $etdir/ET_DDosattack;; - *) echo $a >> $etdir/ET_Unknown;; - esac - done <"$pfborig$alias.raw" - data=$(ls $etdir) - echo; echo "Compiling ET IP IQRisk REP Lists based upon User Selected Categories" - printf "%-10s %-25s\n" " Action" "Category" - echo "-------------------------------------------" - - for list in $data; do - case "$etblock" in - *$list*) - printf "%-10s %-25s\n" " Block: " "$list" - cat $etdir/$list >> $tempfile - ;; - esac - case "$etmatch" in - *$list*) - printf "%-10s %-25s\n" " Match: " "$list" - cat $etdir/$list >> $tempfile2 - ;; - esac - done - echo "-------------------------------------------" + # Exit if GeoIP.dat is not found + if [ ! -f "${pathgeoipdat}" ]; then + log="Database GeoIP [ GeoIP.Dat ] not found. Reputation function terminated." + echo "${log}" | tee -a "${errorlog}" + return + fi - if [ -f $tempfile ]; then mv -f $tempfile $pfborig$alias".orig"; fi - if [ "$etmatch" != "x" ]; then mv -f $tempfile2 $pfbmatch/ETMatch.txt; fi - cicount=$(cat $etdir/$evar | grep -cv '^#\|^$'); cocount=$(grep -cv "^1\.1\.1\.1" $pfborig$alias".orig") - echo; echo "ET Folder count [ $cicount ] Outfile count [ $cocount ]" -else - echo; echo "No ET .GZ File Found!" -fi -exitnow + # Clear variables and tempfiles + rm -f /tmp/pfbtemp?_"${rvar}" + count=0; countb=0; countm=0; counts=0; countr=0 } -# Process to extract IP addresses from XLSX Files -processxlsx() { -if [ ! -x $pathtar ]; then - echo "Application [ TAR ] Not found, Can't proceed." - echo "Application [ TAR ] Not found, Can't proceed. [ $now ]" >> $errorlog - exitnow -fi +# Reputation function to condense an IP range if a 'Max' amount of IP addresses are found in a /24 range per individual list. +reputation_max() { + sort "${pfbdeny}${alias}.txt" | uniq > "${tempfile}" + data="$(cut -d '.' -f 1-3 ${tempfile} | awk -v max=${max} '{a[$0]++}END{for(i in a){if(a[i] > max){print i}}}')" + + # Classify repeat offenders by Country code + if [ ! -z "${data}" ]; then + for ip in ${data}; do + ccheck="$(${pathgeoip} -f ${pathgeoipdat} ${ip}.1 | cut -c 24-25)" + case "${cc}" in + *$ccheck*) + countr="$((countr + 1))" + if [ "${ccwhite}" == 'match' ] || [ "${ccblack}" == 'match' ]; then + echo "${ip}." >> "${matchfile}" + fi + ;; + *) + count="$((count + 1))" + echo "${ip}." >> "${dupfile}" + ;; + esac + done + else + countr=0; count=0 + fi -if [ -s $pfborig$alias".zip" ]; then + # Collect match file details + if [ -s "${matchfile}" ] && [ "${dedup}" != 'on' ] && [ "${ccwhite}" == 'match' ]; then + mon="$(sed -e 's/^/^/' -e 's/\./\\\./g' ${matchfile})" + for ip in ${mon}; do + grep "${ip}" "${tempfile}" >> "${tempfile2}" + done + counts="$(grep -c ^ ${tempfile2})" + if [ "${ccwhite}" == 'match' ]; then + sed 's/$/0\/24/' "${matchfile}" >> "${tempmatchfile}" + sed 's/^/\!/' "${tempfile2}" >> "${tempmatchfile}" + fi + fi - $pathtar -xf $pfborig$alias".zip" -C $tmpxlsx - $pathtar -xOf $tmpxlsx*.[xX][lL][sS][xX] xl/sharedStrings.xml | - grep -aoEw "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" | sort | uniq > $pfborig$alias".orig" - rm -r $tmpxlsx* + # If no matches found remove previous matchoutfile if exists. + matchoutfile="match${header}.txt" + if [ ! -s "${tempmatchfile}" ] && [ -f "${matchoutfile}" ]; then rm -r "${matchoutfile}"; fi + # Move match file to the match folder by individual blocklist name + if [ -s "${tempmatchfile}" ]; then mv -f "${tempmatchfile}" "${pfbmatch}${matchoutfile}"; fi + + # Find repeat offenders in each individual blocklist outfile + if [ -s "${dupfile}" ]; then + > "${tempfile2}" + dup="$(sed -e 's/^/^/' -e 's/\./\\\./g' ${dupfile})" + for ip in ${dup}; do + grep "${ip}" "${tempfile}" >> "${tempfile2}" + done + countb="$(grep -c ^ ${tempfile2})" + + if [ "${ccblack}" == 'block' ]; then + awk 'FNR==NR{a[$0];next}!($0 in a)' "${tempfile2}" "${tempfile}" > "${pfbdeny}${alias}.txt" + sed 's/$/0\/24/' "${dupfile}" >> "${pfbdeny}${alias}.txt" + elif [ "${ccblack}" == 'match' ]; then + sed 's/$/0\/24/' "${dupfile}" >> "${tempmatchfile}" + sed 's/^/\!/' "${tempfile2}" >> "${tempmatchfile}" + else + : + fi + fi - cocount=$(grep -cv "^1\.1\.1\.1" $pfborig$alias".orig") - echo; echo "Download file count [ ZIP file ] Outfile count [ $cocount ]" -else - echo "XLSX Download File Missing" - echo " [ $alias ] XLSX Download File Missing [ $now ]" >> $errorlog -fi -exitnow + if [ "${count}" -gt 0 ]; then + echo; echo " Reputation (Max=${max}) - Range(s)" + cat "${dupfile}" | tr '\n' '|'; echo + sort "${pfbdeny}${alias}.txt" | uniq > "${tempfile}"; mv -f "${tempfile}" "${pfbdeny}${alias}.txt" + fi + + if [ "${count}" -gt 0 ] || [ "${countr}" -gt 0 ]; then + echo; echo ' Reputation -Max Stats' + echo ' ------------------------------' + printf "%-17s %-10s\n" ' Blacklisted' 'Match' + printf "%-8s %-8s %-8s %-8s\n" ' Ranges' 'IPs' 'Ranges' 'IPs' + echo ' ------------------------------' + printf "%-8s %-8s %-8s %-8s\n" " ${count}" "${countb}" "${countr}" "${counts}" + echo + fi } -closingprocess() { -# Write "1.1.1.1" to empty Final Blocklist Files -emptyfiles=$(find $pfbdeny -size 0) -for i in $emptyfiles; do echo "1.1.1.1" > $i; done +# Reputation function 'dMax' utilizing MaxMind GeoIP Country code. +reputation_dmax() { + echo; echo '===[ Reputation - dMax ]======================================' + echo; echo " Querying for repeat offenders ( dMax=${max} ) [ ${now} ]" + data="$(find ${pfbdeny}*.txt ! -name pfB*.txt ! -name *_v6.txt -type f | xargs cut -d '.' -f 1-3 | \ + awk -v max=${max} '{a[$0]++}END{for(i in a){if(a[i] > max){print i}}}' | grep -v '^1\.1\.1')" + + # Classify repeat offenders by Country code + if [ ! -z "${data}" ]; then + echo ' Classifying repeat offenders by GeoIP' + for ip in ${data}; do + ccheck="$(${pathgeoip} -f ${pathgeoipdat} ${ip}.1 | cut -c 24-25)" + case "${cc}" in + *$ccheck*) + countr="$((countr + 1))" + if [ "${ccwhite}" == 'match' ] || [ "${ccblack}" == 'match' ]; then + echo "${ip}." >> "${matchfile}" + fi + ;; + *) + count="$((count + 1))" + echo "${ip}." >> "${dupfile}" + ;; + esac + done + else + countr=0; count=0 + fi -if [ -d "$pfborig" ] && [ "$(ls -A $pfborig)" ]; then - fcount=$(find $pfborig*.orig | xargs cat | grep -cv '^#\|^$') -else - fcount=0 -fi + if [ "${ccwhite}" == 'match' ] && [ -s "${matchfile}" ]; then + echo ' Processing [ Match ] IPs' + match="$(sed -e 's/^/^/' -e 's/\./\\\./g' ${matchfile})" -if [ "$alias" == "on" ]; then - sort -o $masterfile $masterfile - sort -t . -k 1,1n -k 2,2n -k 3,3n -k 4,4n $mastercat > $tempfile; mv -f $tempfile $mastercat - - echo; echo "===[ FINAL Processing ]====================================="; echo - echo " [ Original count ] [ $fcount ]" - count=$(grep -c ^ $masterfile) - echo; echo " [ Processed Count ] [ $count ]"; echo - - s1=$(grep -cv "1\.1\.1\.1" $masterfile) - s2=$(find $pfbdeny ! -name "*_v6.txt" -type f | xargs cat | grep -cv "^1\.1\.1\.1") - s3=$(sort $mastercat | uniq -d | tail -30) - s4=$(find $pfbdeny ! -name "*_v6.txt" -type f | xargs cat | sort | uniq -d | tail -30 | grep -v "^1\.1\.1\.1") - - if [ -d "$pfbpermit" ] && [ "$(ls -A $pfbpermit)" ]; then - echo; echo "===[ Permit List IP Counts ]========================="; echo - wc -l $pfbpermit* | sort -n -r - fi - if [ -d "$pfbmatch" ] && [ "$(ls -A $pfbmatch)" ]; then - echo; echo "===[ Match List IP Counts ]=========================="; echo - wc -l $pfbmatch* | sort -n -r - fi - if [ -d "$pfbdeny" ] && [ "$(ls -A $pfbdeny)" ]; then - echo; echo "===[ Deny List IP Counts ]==========================="; echo - wc -l $pfbdeny* | sort -n -r - fi - if [ -d "$pfbnative" ] && [ "$(ls -A $pfbnative)" ]; then - echo; echo "===[ Native List IP Counts ] ==================================="; echo - wc -l $pfbnative* | sort -n -r - fi - if [ -d "$pfbdeny" ] && [ "$(ls -A $pfbdeny)" ]; then - emptylists=$(grep "1\.1\.1\.1" $pfbdeny* | sed -e 's/^.*[a-zA-Z]\///' -e 's/\.txt:1.1.1.1/ /') - if [ ! -z "$emptylists" ]; then - echo; echo "====================[ Empty Lists w/1.1.1.1 ]=================="; echo - for list in $emptylists; do - echo $list - done - fi + for mfile in ${match}; do + grep "${mfile}" "${pfbdeny}"*.txt >> "${tempfile}" + done + + sed 's/$/0\/24/' "${matchfile}" >> "${tempmatchfile}" + sed -e 's/.*://' -e 's/^/\!/' "${tempfile}" >> "${tempmatchfile}" + mv -f "${tempmatchfile}" "${pfbmatch}${matchdedup}" + countm="$(grep -c ^ ${tempfile})" + counts="$((countm + counts))" fi - if [ -d "$pfborig" ] && [ "$(ls -A $pfborig)" ]; then - echo; echo "====================[ Last Updated List Summary ]=============="; echo - ls -lahtr $pfborig* | sed -e 's/\/.*\// /' -e 's/.orig//' | awk -v OFS='\t' '{print $6" "$7,$8,$9}' - fi - echo "==============================================================="; echo - echo "Sanity Check (Not Including IPv6) ** These two Counts should Match! **" - echo "------------" - echo "Masterfile Count [ $s1 ]" - echo "Deny folder Count [ $s2 ]"; echo - echo "Duplication Sanity Check (Pass=No IPs reported)" - echo "------------------------" - echo "Masterfile/Deny Folder Uniq check" - if [ ! -z "$s3" ]; then echo $s3; fi - echo "Deny Folder/Masterfile Uniq check" - if [ ! -z "$s4" ]; then echo $s4; fi - echo; echo "Sync Check (Pass=No IPs reported)" - echo "----------" -else - echo; echo "===[ FINAL Processing ]============================================="; echo - echo " [ Original count ] [ $fcount ]" - if [ -d "$pfbpermit" ] && [ "$(ls -A $pfbpermit)" ]; then - echo; echo "===[ Permit List IP Counts ]========================="; echo - wc -l $pfbpermit* | sort -n -r - fi - if [ -d "$pfbmatch" ] && [ "$(ls -A $pfbmatch)" ]; then - echo; echo "===[ Match List IP Counts ]=========================="; echo - wc -l $pfbmatch* | sort -n -r - fi - if [ -d "$pfbdeny" ] && [ "$(ls -A $pfbdeny)" ]; then - echo; echo "===[ Deny List IP Counts ]==========================="; echo - wc -l $pfbdeny* | sort -n -r - fi - if [ -d "$pfbnative" ] && [ "$(ls -A $pfbnative)" ]; then - echo; echo "===[ Native List IP Counts ] ==================================="; echo - wc -l $pfbnative* | sort -n -r - fi - if [ -d "$pfbdeny" ] && [ "$(ls -A $pfbdeny)" ]; then - emptylists=$(grep "1\.1\.1\.1" $pfbdeny* | sed -e 's/^.*[a-zA-Z]\///' -e 's/\.txt:1.1.1.1/ /') - if [ ! -z "$emptylists" ]; then - echo; echo "====================[ Empty Lists w/1.1.1.1 ]=================="; echo - for list in $emptylists; do - echo $list + + # Find repeat offenders in each individual blocklist outfile + if [ "${count}" -gt 0 ]; then + echo ' Processing [ Block ] IPs' + dup="$(cat ${dupfile})" + + for ip in ${dup}; do + runonce=0; ii="$(echo ^${ip} | sed 's/\./\\\./g')" + list="$(find ${pfbdeny}*.txt ! -name pfB*.txt ! -name *_v6.txt -type f | xargs grep -al ${ii})" + + for blfile in ${list}; do + header="$(echo ${blfile##*/} | cut -d '.' -f1)" + grep "${ii}" "${blfile}" > "${tempfile}" + + if [ "${ccblack}" == 'block' ]; then + awk 'FNR==NR{a[$0];next}!($0 in a)' "${tempfile}" "${blfile}" > "${tempfile2}"; mv -f "${tempfile2}" "${blfile}" + if [ "${runonce}" -eq 0 ]; then + echo "${ip}0/24" >> "${blfile}" + echo "${header}" "${ip}" >> "${dedupfile}" + echo "${header}" "${ip}0/24" >> "${addfile}" + runonce=1 + else + echo "${header}" "${ip}" >> "${dedupfile}" + fi + else + if [ "${runonce}" -eq 0 ]; then + matchoutfile="match${header}.txt" + echo "${ip}0/24" >> "${pfbmatch}${matchoutfile}" + sed 's/^/\!/' "${tempfile}" >> "${pfbmatch}${matchoutfile}" + countm="$(grep -c ^ ${pfbmatch}${matchoutfile})" + counts="$((countm + counts))" + runonce=1 + fi + fi done - fi + done + + # Remove repeat offenders in masterfiles + echo ' Removing [ Block ] IPs' + > "${tempfile}"; > "${tempfile2}" + sed 's/\./\\\./g' "${dedupfile}" > "${tempfile2}" + while IFS=' ' read -r ips; do grep "${ips}" "${masterfile}" >> "${tempfile}"; done < "${tempfile2}" + countb="$(grep -c ^ ${tempfile})" + awk 'FNR==NR{a[$0];next}!($0 in a)' "${tempfile}" "${masterfile}" > "${tempfile2}"; mv -f "${tempfile2}" "${masterfile}" + cat "${addfile}" >> "${masterfile}" + cut -d ' ' -f2 "${masterfile}" > "${mastercat}" + + echo; echo ' Removed the following IP ranges:' + sed -e 's/^.* //' -e 's/0\/24//' "${addfile}" | tr '\n' '|'; echo fi - if [ -d "$pfborig" ] && [ "$(ls -A $pfborig)" ]; then - echo; echo "====================[ Last Updated List Summary ]=============="; echo - ls -lahtr $pfborig* | sed -e 's/\/.*\// /' -e 's/.orig//' | awk -v OFS='\t' '{print $6" "$7,$8,$9}' - echo "===============================================================" + + if [ "${count}" -gt 0 ] || [ "${countr}" -gt 0 ]; then + echo; echo ' Reputation - dMax Stats' + echo ' ------------------------------' + printf "%-17s %-10s\n" ' Blacklisted' 'Match' + printf "%-8s %-8s %-8s %-8s\n" ' Ranges' 'IPs' 'Ranges' 'IPs' + echo ' ------------------------------' + printf "%-8s %-8s %-8s %-8s\n" " ${count}" "${countb}" "${countr}" "${counts}" + + emptyfiles # Call emptyfiles function + else + echo ' Reputation -dMax ( None )' fi -fi +} + + +# Reputation function 'pMax'. (No Country code exclusions) +reputation_pmax(){ + echo; echo; echo '===[ Reputation - pMax ]======================================' + echo; echo " Querying for repeat offenders ( pMax=${max} ) [ ${now} ]" + data="$(find ${pfbdeny}*.txt ! -name pfB*.txt ! -name *_v6.txt -type f | xargs cut -d '.' -f 1-3 | + awk -v max=${max} '{a[$0]++}END{for(i in a){if(a[i] > max){print i}}}' | grep -v '^1\.1\.1')" + + if [ ! -z "${data}" ]; then + # Find repeat offenders in each individual blocklist outfile + echo ' Processing [ Block ] IPs' + count=0 + + for ip in ${data}; do + count="$((count + 1))" + runonce=0; ii="$(echo ^${ip}. | sed 's/\./\\\./g')" + list="$(find ${pfbdeny}*.txt ! -name pfB*.txt ! -name *_v6.txt -type f | xargs grep -al ${ii})" + + for blfile in ${list}; do + header="$(echo ${blfile##*/} | cut -d '.' -f1)" + grep "${ii}" "${blfile}" > "${tempfile}" + awk 'FNR==NR{a[$0];next}!($0 in a)' "${tempfile}" "${blfile}" > "${tempfile2}"; mv -f "${tempfile2}" "${blfile}" + + if [ "${runonce}" -eq 0 ]; then + echo "${ip}.0/24" >> "${blfile}" + echo "${header}" "${ip}." >> "${dedupfile}" + echo "${header}" "${ip}.0/24" >> "${addfile}" + runonce=1 + else + echo "${header}" "${ip}." >> "${dedupfile}" + fi + done + done -echo; echo "IPv4 Alias Table IP Total"; echo "-----------------------------" -find $pfsense_alias_dir ! -name "*_v6.txt" -type f | xargs cat | grep -c ^ + # Remove repeat offenders in masterfile + echo ' Removing [ Block ] IPs' + > "${tempfile}"; > "${tempfile2}" + sed 's/\./\\\./g' "${dedupfile}" > "${tempfile2}" + while IFS=' ' read -r ips; do grep "${ips}" "${masterfile}" >> "${tempfile}"; done < "${tempfile2}" + countb="$(grep -c ^ ${tempfile})" + awk 'FNR==NR{a[$0];next}!($0 in a)' "${tempfile}" "${masterfile}" > "${tempfile2}"; mv -f "${tempfile2}" "${masterfile}" + cat "${addfile}" >> "${masterfile}" + cut -d ' ' -f2 "${masterfile}" > "${mastercat}" + + echo; echo ' Removed the following IP ranges:' + sed -e 's/^.* //' -e 's/0\/24//' "${addfile}" | tr '\n' '|'; echo + + echo; echo ' Reputation - pMax Stats' + echo ' ----------------' + printf "%-8s %-8s\n" ' Ranges' 'IPs' + echo ' ----------------' + printf "%-8s %-8s\n" " ${count}" "${countb}" + + emptyfiles # Call emptyfiles function + else + echo ' Reputation -pMax ( None )' + fi +} -echo; echo "IPv6 Alias Table IP Total"; echo "-----------------------------" -find $pfsense_alias_dir -name "*_v6.txt" -type f | xargs cat | grep -c ^ -echo; echo "Alias Table IP Counts"; echo "-----------------------------" -wc -l $pfsense_alias_dir*.txt | sort -n -r +# Function to split ET Pro IPREP into category files and compile selected blocked categories into outfile. +processet() { + if [ -s "${pfborig}${alias}.orig" ]; then + # Remove previous ET IPRep files + [ -d "${etdir}" ] && [ "$(ls -A ${etdir})" ] && rm -r "${etdir}/ET_"* + > "${tempfile}"; > "${tempfile2}" + + # ET CSV format (IP, Category, Score) + echo; echo; echo 'Compiling ET IPREP IQRisk based upon user selected categories' + while IFS=',' read i j k; do + # Some ET categories are not in use (For future use) + case "${j}" in + 1) echo "${i}" >> "${etdir}/ET_Cnc.txt";; + 2) echo "${i}" >> "${etdir}/ET_Bot.txt";; + 3) echo "${i}" >> "${etdir}/ET_Spam.txt";; + 4) echo "${i}" >> "${etdir}/ET_Drop.txt";; + 5) echo "${i}" >> "${etdir}/ET_Spywarecnc.txt";; + 6) echo "${i}" >> "${etdir}/ET_Onlinegaming.txt";; + 7) echo "${i}" >> "${etdir}/ET_Drivebysrc.txt";; + 8) echo "${i}" >> "${etdir}/ET_Cat8.txt";; + 9) echo "${i}" >> "${etdir}/ET_Chatserver.txt";; + 10) echo "${i}" >> "${etdir}/ET_Tornode.txt";; + 11) echo "${i}" >> "${etdir}/ET_Cat11.txt";; + 12) echo "${i}" >> "${etdir}/ET_Cat12.txt";; + 13) echo "${i}" >> "${etdir}/ET_Compromised.txt";; + 14) echo "${i}" >> "${etdir}/ET_Cat14.txt";; + 15) echo "${i}" >> "${etdir}/ET_P2P.txt";; + 16) echo "${i}" >> "${etdir}/ET_Proxy.txt";; + 17) echo "${i}" >> "${etdir}/ET_Ipcheck.txt";; + 18) echo "${i}" >> "$[etdir}/ET_Cat18.txt";; + 19) echo "${i}" >> "${etdir}/ET_Utility.txt";; + 20) echo "${i}" >> "${etdir}/ET_DDos.txt";; + 21) echo "${i}" >> "${etdir}/ET_Scanner.txt";; + 22) echo "${i}" >> "${etdir}/ET_Cat22.txt";; + 23) echo "${i}" >> "${etdir}/ET_Brute.txt";; + 24) echo "${i}" >> "${etdir}/ET_Fakeav.txt";; + 25) echo "${i}" >> "${etdir}/ET_Dyndns.txt";; + 26) echo "${i}" >> "${etdir}/ET_Undesireable.txt";; + 27) echo "${i}" >> "${etdir}/ET_Abusedtld.txt";; + 28) echo "${i}" >> "${etdir}/ET_Selfsignedssl.txt";; + 29) echo "${i}" >> "${etdir}/ET_Blackhole.txt";; + 30) echo "${i}" >> "${etdir}/ET_RAS.txt";; + 31) echo "${i}" >> "${etdir}/ET_P2Pcnc.txt";; + 32) echo "${i}" >> "${etdir}/ET_Sharedhosting.txt";; + 33) echo "${i}" >> "${etdir}/ET_Parking.txt";; + 34) echo "${i}" >> "${etdir}/ET_VPN.txt";; + 35) echo "${i}" >> "${etdir}/ET_Exesource.txt";; + 36) echo "${i}" >> "${etdir}/ET_Cat36.txt";; + 37) echo "${i}" >> "${etdir}/ET_Mobilecnc.txt";; + 38) echo "${i}" >> "${etdir}/ET_Mobilespyware.txt";; + 39) echo "${i}" >> "${etdir}/ET_Skypenode.txt";; + 40) echo "${i}" >> "${etdir}/ET_Bitcoin.txt";; + 41) echo "${i}" >> "${etdir}/ET_DDosattack.txt";; + *) echo "${i}" >> "${etdir}/ET_Unknown.txt";; + esac + done < "${pfborig}${alias}.orig" + data="$(ls ${etdir})" + printf "%-10s %-25s\n" ' Action' 'Category' + echo '-------------------------------------------' + + for list in ${data}; do + case "${etblock}" in + *$list*) + printf "%-10s %-25s\n" ' Block: ' "${list}" + cat "${etdir}/${list}" >> "${tempfile}" + ;; + esac + case "${etmatch}" in + *$list*) + printf "%-10s %-25s\n" ' Match: ' "${list}" + cat "${etdir}/${list}" >> "${tempfile2}" + ;; + esac + done + echo '-------------------------------------------' -echo; echo "pfSense Table Stats"; echo "-------------------" -$pathpfctl -s memory | grep "table-entries" -pfctlcount=$($pathpfctl -vvsTables | awk '/Addresses/ {s+=$2}; END {print s}') -echo "Table Usage Count " $pfctlcount -exitnow + if [ -f "${tempfile}" ]; then mv -f "${tempfile}" "${pfborig}${alias}.orig"; fi + if [ "${etmatch}" != 'x' ]; then mv -f "${tempfile2}" "${pfbmatch}/ETMatch.txt"; fi + counto="$(cat ${etdir}/ET_* | grep -cv '^#\|^$')"; countf="$(grep -cv '^1\.1\.1\.1$' ${pfborig}${alias}.orig)" + echo; echo "All ET Folder count [ ${counto} ] Final count [ ${countf} ]" + else + echo; echo 'No ET .orig File Found!' + fi } -remove() { -# Remove Lists from Masterfiles and Delete Associated Files -echo -for i in $cc; do - header=$(echo "${i%*,}") - if [ ! "$header" == "" ]; then - # Make sure that Alias Exists in Masterfile before removal. - masterchk=$(grep -m1 "$header[[:space:]]" $masterfile) - if [ ! -z "$masterchk" ]; then - # Grep Header with a Trailing Space character - grep "$header[[:space:]]" $masterfile > $tempfile - awk 'FNR==NR{a[$0];next}!($0 in a)' $tempfile $masterfile > $tempfile2; mv -f $tempfile2 $masterfile - cut -d' ' -f2 $masterfile > $mastercat - fi - rm -rf $pfborig$header*; rm -rf $pfbdeny$header*; rm -rf $pfbmatch$header*; rm -rf $pfbpermit$header*; rm -rf $pfbnative$header* - echo "The Following list has been REMOVED [ $header ]" + +# Function to extract IP addresses from XLSX files. +processxlsx() { + if [ ! -x "${pathtar}" ]; then + log='Application [ TAR ] Not found, cannot proceed.' + echo "${log}" | tee -a "${errorlog}" + exitnow fi - echo -done -# Delete Masterfiles if they are empty -emptychk=$(find $masterfile -size 0) -if [ ! "$emptychk" == "" ]; then - rm -r $masterfile; rm -r $mastercat -fi -exitnow -} + if [ -s "${pfborig}${alias}.raw" ]; then + "${pathtar}" -xf "${pfborig}${alias}.raw" -C "${tmpxlsx}" + "${pathtar}" -xOf "${tmpxlsx}"*.[xX][lL][sS][xX] "xl/sharedStrings.xml" | \ + grep -aoEw "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" | sort | uniq > "${pfborig}${alias}.orig" + rm -r "${tmpxlsx}"* -# Process to restore aliasables from archive on reboot ( NanoBSD and Ramdisk Installations only ) -aliastables() { - if [ "${PLATFORM}" != "pfSense" ] || [ ${USE_MFS_TMPVAR} -gt 0 ] || [ "${DISK_TYPE}" = "md" ]; then - [ -f $aliasarchive ] && cd $pfsense_alias_dir && /usr/bin/tar -jxvf $aliasarchive + countf="$(grep -cv '^1\.1\.1\.1$' ${pfborig}${alias}.orig)" + echo; echo "Final count [ ${countf} ]" + else + echo 'XLSX download file missing' + echo " [ ${alias} ] XLSX download file missing [ ${now} ]" >> "${errorlog}" fi - exitnow } -########## -# CALL APPROPRIATE PROCESSES using Script Argument $1 -case $1 in - continent) - continent +# Function to report final pfBlockerNG statistics. +closingprocess() { + counto=0 + echo; echo '===[ FINAL Processing ]====================================='; echo + if [ -d "${pfborig}" ] && [ "$(ls -A ${pfborig})" ]; then + counto="$(find ${pfborig}*.orig 2>/dev/null | xargs cat | grep -cv '^#\|^$')" + fi + + # Execute when 'de-duplication' is enabled + if [ "${alias}" == 'on' ]; then + sort -o "${masterfile}" "${masterfile}" + sort -t . -k 1,1n -k 2,2n -k 3,3n -k 4,4n "${mastercat}" > "${tempfile}"; mv -f "${tempfile}" "${mastercat}" + + echo " [ Original IP count ] [ ${counto} ]" + countm="$(grep -c ^ ${masterfile})" + echo; echo " [ Final IP Count ] [ ${countm} ]"; echo + + s1="$(grep -cv '1\.1\.1\.1$' ${masterfile})" + s2="$(find ${pfbdeny}*.txt ! -name *_v6.txt -type f 2>/dev/null | xargs cat | grep -cv '^1\.1\.1\.1$')" + s3="$(sort ${mastercat} | uniq -d | tail -30)" + s4="$(find ${pfbdeny}*.txt ! -name *_v6.txt -type f 2>/dev/null | xargs cat | sort | uniq -d | tail -30 | grep -v '^1\.1\.1\.1$')" + else + echo " [ Original IP count ] [ ${counto} ]" + fi + + if [ -d "${pfbpermit}" ] && [ "$(ls -A ${pfbpermit})" ]; then + echo; echo '===[ Permit List IP Counts ]========================='; echo + wc -l "${pfbpermit}"*.txt 2>/dev/null | sort -n -r + fi + if [ -d "${pfbmatch}" ] && [ "$(ls -A ${pfbmatch})" ]; then + echo; echo '===[ Match List IP Counts ]=========================='; echo + wc -l "${pfbmatch}"*.txt 2>/dev/null | sort -n -r + fi + if [ -d "${pfbdeny}" ] && [ "$(ls -A ${pfbdeny})" ]; then + echo; echo '===[ Deny List IP Counts ]==========================='; echo + wc -l "${pfbdeny}"*.txt 2>/dev/null | sort -n -r + fi + if [ -d "${pfbnative}" ] && [ "$(ls -A ${pfbnative})" ]; then + echo; echo '===[ Native List IP Counts ] ==================================='; echo + wc -l "${pfbnative}"*.txt 2>/dev/null | sort -n -r + fi + if [ -d "${pfbdeny}" ] && [ "$(ls -A ${pfbdeny})" ]; then + emptylists="$(grep '^1\.1\.1\.1$' ${pfbdeny}*.txt | sed -e 's/^.*[a-zA-Z]\///' -e 's/\.txt:1.1.1.1/ /')" + if [ ! -z "${emptylists}" ]; then + echo; echo '====================[ Empty Lists w/1.1.1.1 ]=================='; echo + for list in ${emptylists}; do + echo "${list}" + done + fi + fi + if [ -d "${pfbdomain}" ] && [ "$(ls -A ${pfbdomain})" ]; then + echo; echo '===[ DNSBL Domain/IP Counts ] ==================================='; echo + wc -l "${pfbdomain}"* 2>/dev/null | sort -n -r + fi + if [ -d "${pfborig}" ] && [ "$(ls -A ${pfborig})" ]; then + echo; echo '====================[ Last Updated List Summary ]=============='; echo + ls -lahtr "${pfborig}"*.orig | sed -e 's/\/.*\// /' -e 's/.orig//' | awk -v OFS='\t' '{print $6" "$7,$8,$9}' + fi + + # Execute when 'de-duplication' is enabled + if [ "${alias}" == 'on' ]; then + echo '==============================================================='; echo + if [ "${s1} == ${s2}" ]; then + echo 'Database Sanity check [ PASSED ]' + else + echo 'Database Sanity check [ FAILED ] ** These two counts should match! **' + echo '------------' + echo "Masterfile Count [ ${s1} ]" + echo "Deny folder Count [ ${s2} ]"; echo + echo 'Duplication sanity check (Pass=No IPs reported)' + fi + echo '------------------------' + echo 'Masterfile/Deny folder uniq check' + if [ ! -z "${s3}" ]; then echo "${s3}"; fi + echo 'Deny folder/Masterfile uniq check' + if [ ! -z "${s4}" ]; then echo "${s4}"; fi + echo; echo 'Sync check (Pass=No IPs reported)' + echo '----------' + fi + + echo; echo 'IPv4 alias tables IP count'; echo '-----------------------------' + find "${pfsensealias}"pfB_*.txt ! -name "*_v6.txt" -type f 2>/dev/null | xargs cat | grep -c ^ + + echo; echo 'IPv6 alias tables IP count'; echo '-----------------------------' + find "${pfsensealias}"pfB_*.txt -name "*_v6.txt" -type f 2>/dev/null | xargs cat | grep -c ^ + + echo; echo 'Alias table IP Counts'; echo '-----------------------------' + wc -l "${pfsensealias}"pfB_*.txt 2>/dev/null | sort -n -r + + echo; echo 'pfSense Table Stats'; echo '-------------------' + "${pathpfctl}" -s memory | grep 'table-entries' + pfctlcount="$(${pathpfctl} -vvsTables | awk '/Addresses/ {s+=$2}; END {print s}')" + echo "Table Usage Count ${pfctlcount}" +} + +# Call appropriate processes using script argument $1. +case "${1}" in + _*) + if [ "$(echo ${1} | grep -c '_255')" -gt 0 ]; then process255; fi + if [ "$(echo ${1} | grep -c '_agg')" -gt 0 ]; then cidr_aggregate; fi + if [ "$(echo ${1} | grep -c '_rep')" -gt 0 ]; then reputation_depends; reputation_max; fi + if [ "$(echo ${1} | grep -c '_dup')" -gt 0 ]; then duplicate; fi ;; - duplicate) - process255 + continent) duplicate ;; + domainduplicate) + domainduplicate + ;; + cidr_aggregate) + agg_folder=true + cidr_aggregate + ;; + whoisconvert) + whoisconvert + ;; suppress) suppress ;; - p24) - process24 - ;; - dedup) - deduplication + dmax) + reputation_depends + reputation_dmax ;; - pdup) - pdeduplication + pmax) + reputation_depends + reputation_pmax ;; et) processet @@ -965,17 +970,17 @@ case $1 in xlsx) processxlsx ;; - closing) - closingprocess - ;; remove) remove ;; aliastables) aliastables ;; + closing) + emptyfiles + closingprocess + ;; *) - exitnow ;; esac -exitnow +exitnow
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng.widget.php b/config/pfblockerng/pfblockerng.widget.php index c9522cd7..c70bd05b 100644 --- a/config/pfblockerng/pfblockerng.widget.php +++ b/config/pfblockerng/pfblockerng.widget.php @@ -3,19 +3,17 @@ pfBlockerNG.widget.php pfBlockerNG - Copyright (C) 2015 BBcan177@gmail.com + Copyright (c) 2015 BBcan177@gmail.com All rights reserved. Based Upon pfblocker : - Copyright 2011 Thomas Schaefer - Tomschaefer.org - Copyright 2011 Marcello Coutinho - Part of pfSense widgets (www.pfsense.org) + Copyright (c) 2011 Thomas Schaefer + Copyright (c) 2011 Marcello Coutinho Adapted From: snort_alerts.widget.php - Copyright (C) 2009 Jim Pingle - mod 24-07-2012 - mod 28-02-2015 by Bill Meeks + Copyright (c) 2015 Electric Sheep Fencing, LLC. All rights reserved. + Copyright (c) 2015 Bill Meeks Javascript and Integration modifications by J. Nieuwenhuizen @@ -43,9 +41,9 @@ POSSIBILITY OF SUCH DAMAGE. */ $nocsrf = true; -@require_once("/usr/local/www/widgets/include/widget-pfblockerng.inc"); -@require_once("/usr/local/pkg/pfblockerng/pfblockerng.inc"); -@require_once("guiconfig.inc"); +@require_once('/usr/local/www/widgets/include/widget-pfblockerng.inc'); +@require_once('/usr/local/pkg/pfblockerng/pfblockerng.inc'); +@require_once('guiconfig.inc'); pfb_global(); @@ -58,71 +56,62 @@ $pfb['err'] = "<img src ='/themes/{$g['theme']}/images/icons/icon_wzd_nsaved.png $pfb['RowOddClass'] = "style='background-color: #FFFFFF;'"; $pfb['RowEvenClass'] = "style='background-color: #F0F0F0;'"; $pfb['RowEvenClass2'] = "style='background-color: #D0D0D0;'"; -$pfb['ColClass'] = "listMRr"; +$pfb['ColClass'] = 'listMRr'; -$pfb['global'] = &$config['installedpackages']['pfblockerngglobal']; - -// Define default widget customizations -if (!isset($pfb['global']['widget-maxfails'])) { - $pfb['global']['widget-maxfails'] = '3'; -} -if (!isset($pfb['global']['widget-maxpivot'])) { - $pfb['global']['widget-maxpivot'] = '200'; -} -if (!isset($pfb['global']['widget-sortcolumn'])) { - $pfb['global']['widget-sortcolumn'] = 'none'; -} -if (!isset($pfb['global']['widget-sortdir'])) { - $pfb['global']['widget-sortdir'] = 'asc'; -} -if (!isset($pfb['global']['widget-popup'])) { - $pfb['global']['widget-popup'] = 'on'; -} - -// Collect variables -if (is_array($pfb['global'])) { - $pfb['maxfails'] = $pfb['global']['widget-maxfails']; - $pfb['maxpivot'] = $pfb['global']['widget-maxpivot']; - $pfb['sortcolumn'] = $pfb['global']['widget-sortcolumn']; - $pfb['sortdir'] = $pfb['global']['widget-sortdir']; - $pfb['popup'] = $pfb['global']['widget-popup']; +// Widget customizations +$wglobal_array = array('popup' => 'off', 'sortcolumn' => 'none', 'sortdir' => 'asc', 'maxfails' => 3, 'maxpivot' => 200); +$pfb['wglobal'] = &$config['installedpackages']['pfblockerngglobal']; +foreach ($wglobal_array as $type => $value) { + $pfb[$type] = $pfb['wglobal']['widget-' . "{$type}"] ?: $value; } // Save widget customizations -if ($_POST) { - if (is_numeric($_POST['pfb_maxfails'])) { - $pfb['global']['widget-maxfails'] = $_POST['pfb_maxfails']; - } - if (is_numeric($_POST['pfb_maxpivot'])) { - $pfb['global']['widget-maxpivot'] = $_POST['pfb_maxpivot']; - } - if (!empty($_POST['pfb_popup'])) { - $pfb['global']['widget-popup'] = $_POST['pfb_popup']; - } - if (!empty($_POST['pfb_sortcolumn'])) { - $pfb['global']['widget-sortcolumn'] = $_POST['pfb_sortcolumn']; +if (isset($_POST['pfb_submit'])) { + $pfb['wglobal']['widget-popup'] = htmlspecialchars($_POST['pfb_popup']) ?: 'off'; + $pfb['wglobal']['widget-sortcolumn'] = htmlspecialchars($_POST['pfb_sortcolumn']) ?: 'none'; + $pfb['wglobal']['widget-sortdir'] = htmlspecialchars($_POST['pfb_sortdir']) ?: 'asc'; + + if (ctype_digit(htmlspecialchars($_POST['pfb_maxfails']))) { + $pfb['wglobal']['widget-maxfails'] = htmlspecialchars($_POST['pfb_maxfails']); } - if (!empty($_POST['pfb_sortdir'])) { - $pfb['global']['widget-sortdir'] = $_POST['pfb_sortdir']; + if (ctype_digit(htmlspecialchars($_POST['pfb_maxpivot']))) { + $pfb['wglobal']['widget-maxpivot'] = htmlspecialchars($_POST['pfb_maxpivot']); } - write_config("pfBlockerNG: Saved Widget customizations via Dashboard"); - header("Location: ../../index.php"); + + write_config('pfBlockerNG: Saved Widget customizations via Dashboard'); + header('Location: ../../index.php'); } // Ackwnowlege failed downloads if (isset($_POST['pfblockerngack'])) { - exec("/usr/bin/sed -i '' 's/FAIL/Fail/g' {$pfb['errlog']}"); - header("Location: ../../index.php"); + exec("{$pfb['sed']} -i '' 's/FAIL/Fail/g' {$pfb['errlog']}"); + header('Location: ../../index.php'); } // Called by Ajax to update table contents if (isset($_GET['getNewCounts'])) { - pfBlockerNG_get_table("js"); + pfBlockerNG_get_table('js'); return; } +// Reset DNSBL Alias packet counters +if (isset($_POST['pfblockerngdnsblclear'])) { + $dnsbl_info = array_map('str_getcsv', @file("{$pfb['dnsbl_info']}")); + if (!empty ($dnsbl_info)) { + $handle = fopen("{$pfb['dnsbl_info']}", 'w'); + foreach ($dnsbl_info as $line) { + if (substr($line[0], 0, 1) != '#') { + $line[3] = '0'; + } + fputcsv($handle, $line); + } + fclose ($handle); + } + header('Location: ../../index.php'); +} + // Sort widget table according to user configuration -function pfbsort(&$array, $subkey="id", $sort_ascending=FALSE) { +function pfbsort(&$array, $subkey='id', $sort_ascending=FALSE) { if (empty($array)) { return; } @@ -130,12 +119,16 @@ function pfbsort(&$array, $subkey="id", $sort_ascending=FALSE) { $temp_array[key($array)] = array_shift($array); } + if ($subkey == 'alias') { + $subkey = 0; + } + foreach ($array as $key => $val) { $offset = 0; $found = FALSE; foreach ($temp_array as $tmp_key => $tmp_val) { - if (!$found and strtolower($val[$subkey]) > strtolower($tmp_val[$subkey])) { - $temp_array = array_merge((array)array_slice($temp_array,0,$offset), array($key => $val), array_slice($temp_array,$offset)); + if (!$found && strtolower($val[$subkey]) > strtolower($tmp_val[$subkey])) { + $temp_array = array_merge((array)array_slice($temp_array, 0, $offset), array($key => $val), array_slice($temp_array, $offset)); $found = TRUE; } $offset++; @@ -156,14 +149,14 @@ function pfbsort(&$array, $subkey="id", $sort_ascending=FALSE) { // Collect all pfBlockerNG statistics function pfBlockerNG_get_counts() { global $config, $pfb; - $pfb_table = array(); + $pfb_table = $pfb_dtable = array(); /* Alias Table Definitions - 'update' - Last Updated Timestamp 'rule' - Total number of Firewall rules per alias 'count' - Total Line Count per alias 'packets' - Total number of pf packets per alias */ - exec("/sbin/pfctl -vvsTables | grep -A4 'pfB_'", $pfb_pfctl); + exec("{$pfb['pfctl']} -vvsTables | {$pfb['grep']} -A4 'pfB_'", $pfb_pfctl); if (!empty($pfb_pfctl)) { foreach($pfb_pfctl as $line) { $line = trim(str_replace(array( '[', ']' ), '', $line)); @@ -173,9 +166,9 @@ function pfBlockerNG_get_counts() { unset($pfb_alias); continue; } - exec("/usr/bin/grep -cv '^1\.1\.1\.1' {$pfb['aliasdir']}/{$pfb_alias}.txt", $match); + exec("{$pfb['grep']} -cv '^1\.1\.1\.1$' {$pfb['aliasdir']}/{$pfb_alias}.txt", $match); $pfb_table[$pfb_alias] = array('count' => $match[1], 'img' => $pfb['down']); - exec("ls -ld {$pfb['aliasdir']}/{$pfb_alias}.txt | awk '{ print $6,$7,$8 }'", $update); + exec("{$pfb['ls']} -ld {$pfb['aliasdir']}/{$pfb_alias}.txt | {$pfb['awk']} '{ print $6,$7,$8 }'", $update); $pfb_table[$pfb_alias]['update'] = $update[0]; $pfb_table[$pfb_alias]['rule'] = 0; unset($match, $update); @@ -198,21 +191,21 @@ function pfBlockerNG_get_counts() { } else { // Error. No pf labels found. - $pfb['pfctl'] = TRUE; + $pfb['pfctlerr'] = TRUE; } // Determine if firewall rules are defined - if (is_array($config['filter']['rule'])) { + if (isset($config['filter']['rule'])) { foreach ($config['filter']['rule'] as $rule) { // Skip disabled rules if (isset($rule['disabled'])) { continue; } - if (stripos($rule['source']['address'], "pfb_") !== FALSE) { + if (stripos($rule['source']['address'], 'pfb_') !== FALSE) { $pfb_table[$rule['source']['address']]['img'] = $pfb['up']; $pfb_table[$rule['source']['address']]['rule'] += 1; } - if (stripos($rule['destination']['address'], "pfb_") !== FALSE) { + if (stripos($rule['destination']['address'], 'pfb_') !== FALSE) { $pfb_table[$rule['destination']['address']]['img'] = $pfb['up']; $pfb_table[$rule['destination']['address']]['rule'] += 1; } @@ -220,79 +213,115 @@ function pfBlockerNG_get_counts() { } // Collect packet fence rule numbers - exec("/sbin/pfctl -vv -sr | grep 'pfB_'", $pfrules); + exec("{$pfb['pfctl']} -vv -sr | {$pfb['grep']} 'pfB_'", $pfrules); if (!empty($pfrules)) { foreach ($pfrules as $result) { // Sample : @112(0) block return in log quick on em1 from any to <pfB_PRI1:160323> label "USER_RULE: pfB_PRI1" - if (preg_match("/@(\d+)\(\d+\).*\<(pfB_\w+):\d+\>/", $result, $rule)) { - $pfb_table[$rule[2]]['rules'] .= $rule[1] . '|'; + $id = strstr($result, '(', FALSE); + $id = ltrim(strstr($id, ')', TRUE), '('); + $descr = ltrim(stristr($result, '<pfb_', FALSE), '<'); + $descr = strstr($descr, ':', TRUE); + + if (!empty($id) && !empty($descr) && strpos($pfb_table[$descr]['rules'], $id) === FALSE) { + $pfb_table[$descr]['rules'] .= $id . '|'; + } + } + } + + // DNSBL collect statistics + if ($pfb['enable'] == 'on' && $pfb['dnsbl'] == 'on' && file_exists ("{$pfb['dnsbl_info']}")) { + $dnsbl_info = array_map('str_getcsv', @file("{$pfb['dnsbl_info']}")); + if (!empty($dnsbl_info)) { + foreach ($dnsbl_info as $line) { + if (substr($line[0], 0, 1) != '#') { + if ($line[2] == 'disabled') { + $pfb_dtable[$line[0]] = array ('count' => 'disabled', 'img' => $pfb['down']); + } else { + $pfb_dtable[$line[0]] = array ('count' => $line[2], 'img' => $pfb['up']); + } + $pfb_dtable[$line[0]]['update'] = "{$line[1]}"; + $pfb_dtable[$line[0]]['packets'] = "{$line[3]}"; + } } } } // Sort tables per sort customization - if ($pfb['sortcolumn'] != "none") { - if ($pfb['sortdir'] == "asc") { - pfbsort($pfb_table, $pfb['sortcolumn'], TRUE); - } else { + if ($pfb['sortcolumn'] != 'none') { + if ($pfb['sortdir'] == 'asc') { pfbsort($pfb_table, $pfb['sortcolumn'], FALSE); + pfbsort($pfb_dtable, $pfb['sortcolumn'], FALSE); + } else { + pfbsort($pfb_table, $pfb['sortcolumn'], TRUE); + pfbsort($pfb_dtable, $pfb['sortcolumn'], TRUE); } } + $pfb_table = array_merge($pfb_table, $pfb_dtable); return $pfb_table; } // Called on initial load and Ajax to update table contents -function pfBlockerNG_get_table($mode="") { +function pfBlockerNG_get_table($mode='') { global $pfb; $counter = 0; $dcounter = 1; $response = ''; $pfb_table = pfBlockerNG_get_counts(); if (!empty($pfb_table)) { foreach ($pfb_table as $pfb_alias => $values) { - // Add firewall rules count associated with alias - $values['img'] = $values['img'] . "<span title='Alias Firewall Rule count' ><small>({$values['rule']})</small></span>"; - - // If packet fence errors found, display error. - if ($pfb['pfctl']) { - $values['img'] = $pfb['err']; - } - - // Alias table popup - if ($values['count'] > 0 && $pfb['popup'] == "on") { - $alias_popup = rule_popup($pfb_alias, '', '', ''); - $alias_span = $alias_popup['src']; - $alias_span_end = $alias_popup['src_end']; - } - else { - $alias_span = ''; - $alias_span_end = ''; - } + if (strpos($pfb_alias, 'DNSBL_') !== FALSE) { + $alias_span = $alias_span_end = ''; + $packets = $values['packets']; + $dnsbl = TRUE; + } else { + // Add firewall rules count associated with alias + $values['img'] = $values['img'] . "<span title='Alias Firewall Rule count' ><small>({$values['rule']})</small></span>"; + + // If packet fence errors found, display error. + if ($pfb['pfctlerr']) { + $values['img'] = $pfb['err']; + } - // Packet column pivot to Alerts Tab - if ($values['packets'] > 0) { - $rules = rtrim($values['rules'], '|'); - if ($values['packets'] > $pfb['maxpivot']) { - $aentries = $pfb['maxpivot']; - } else { - $aentries = $values['packets']; + // Alias table popup + if ($values['count'] > 0 && $pfb['popup'] == 'on') { + $alias_popup = rule_popup($pfb_alias, '', '', ''); + $alias_span = $alias_popup['src']; + $alias_span_end = $alias_popup['src_end']; + } + else { + $alias_span = $alias_span_end = ''; } - $packets = "<a target='_new' href='/pfblockerng/pfblockerng_alerts.php?rule={$rules}&entries={$aentries}' "; - $packets .= "style='text-decoration: underline;' title='Click to view these packets in Alerts tab' >{$values['packets']}</a>"; - } - else { - $packets = $values['packets']; + // Packet column pivot to Alerts Tab + if ($values['packets'] > 0) { + $rules = rtrim($values['rules'], '|'); + if ($values['packets'] > $pfb['maxpivot']) { + $aentries = $pfb['maxpivot']; + } else { + $aentries = $values['packets']; + } + + $packets = "<a target='_blank' href='/pfblockerng/pfblockerng_alerts.php?rule={$rules}&entries={$aentries}' "; + $packets .= "title='Click to view these packets in Alerts tab' >{$values['packets']}</a>"; + } + else { + $packets = $values['packets']; + } } - if ($mode == "js") { - echo $response = $alias_span . $pfb_alias . $alias_span_end . "||" . $values['count'] . "||" . $packets . "||" . $values['update'] - . "||" . $values['img'] . "\n"; + if ($mode == 'js') { + echo $response = "{$alias_span}{$pfb_alias}{$alias_span_end}||{$values['count']}||{$packets}||{$values['update']}||{$values['img']}\n"; } else { - $RowClass = $counter % 2 ? $pfb['RowEvenClass'] : $pfb['RowOddClass']; - $counter++; + // Print darker shading for DNSBL + if ($dnsbl) { + $RowClass = $dcounter % 2 ? $pfb['RowEvenClass2'] : $pfb['RowOddClass']; + $dcounter++; + } else { + $RowClass = $counter % 2 ? $pfb['RowEvenClass'] : $pfb['RowOddClass']; + $counter++; + } echo (" <tr {$RowClass}> - <td class='listMRr ellipsis'>" . $alias_span . $pfb_alias . $alias_span_end . "</td> + <td class='listMRr ellipsis'>{$alias_span}{$pfb_alias}{$alias_span_end}</td> <td class='listMRr' align='center'>{$values['count']}</td> <td class='listMRr' sorttable_customkey='{$values['packets']}' align='center'>{$packets}</td> <td class='listMRr' align='center'>{$values['update']}</td> @@ -304,29 +333,51 @@ function pfBlockerNG_get_table($mode="") { } // Status indicator if pfBlockerNG is enabled/disabled -if ("{$pfb['enable']}" == "on") { - $pfb_status = "/themes/{$g['theme']}/images/icons/icon_pass.gif"; - $pfb_msg = "pfBlockerNG is Active."; +if ($pfb['enable'] == 'on') { + $mode = 'pass'; + $pfb_msg = 'pfBlockerNG is Active.'; + + if ($pfb['config']['enable_dup'] == 'on') { + // Check Masterfile Database Sanity + $db_sanity = exec("{$pfb['grep']} 'Sanity check' {$pfb['logdir']}/pfblockerng.log | {$pfb['grep']} -o 'PASSED' | tail -1"); + if ($db_sanity != 'PASSED') { + $mode = 'reject'; + $pfb_msg = 'pfBlockerNG deDuplication is out of sync. Perform a Force Reload to correct.'; + } + } +} else { + $mode = 'block'; + $pfb_msg = 'pfBlockerNG is Disabled.'; +} +$pfb_status = "/themes/{$g['theme']}/images/icons/icon_{$mode}.gif"; + +// Status indicator if DNSBL is actively running +if ($pfb['dnsbl'] == 'on' && $pfb['unbound_state'] == 'on' && $pfb['enable'] == 'on' && + strpos(file_get_contents("{$pfb['dnsbldir']}/unbound.conf"), 'pfb_dnsbl') !== FALSE) { + $mode = 'pass'; + $dnsbl_msg = 'DNSBL is Active.'; } else { - $pfb_status = "/themes/{$g['theme']}/images/icons/icon_block.gif"; - $pfb_msg = "pfBlockerNG is Disabled."; + $mode = 'block'; + $dnsbl_msg = 'DNSBL is Disabled.'; } +$dnsbl_status = "/themes/{$g['theme']}/images/icons/icon_{$mode}.gif"; // Collect total IP/Cidr counts -$dcount = exec("cat {$pfb['denydir']}/*.txt | grep -cv '^#\|^$\|^1\.1\.1\.1'"); -$pcount = exec("cat {$pfb['permitdir']}/*.txt | grep -cv '^#\|^$\|^1\.1\.1\.1'"); -$mcount = exec("cat {$pfb['matchdir']}/*.txt | grep -cv '^#\|^$\|^1\.1\.1\.1'"); -$ncount = exec("cat {$pfb['nativedir']}/*.txt | grep -cv '^#\|^$\|^1\.1\.1\.1'"); +$dcount = exec("{$pfb['cat']} {$pfb['denydir']}/*.txt | {$pfb['grep']} -cv '^#\|^$\|^1\.1\.1\.1$'"); +$pcount = exec("{$pfb['cat']} {$pfb['permitdir']}/*.txt | {$pfb['grep']} -cv '^#\|^$\|^1\.1\.1\.1$'"); +$mcount = exec("{$pfb['cat']} {$pfb['matchdir']}/*.txt | {$pfb['grep']} -cv '^#\|^$\|^1\.1\.1\.1$'"); +$ncount = exec("{$pfb['cat']} {$pfb['nativedir']}/*.txt | {$pfb['grep']} -cv '^#\|^$\|^1\.1\.1\.1$'"); +$scount = exec("{$pfb['grep']} -c ^ {$pfb['dnsbl_file']}.conf"); +$maxver = exec("grep -o 'Last-.*' /var/log/pfblockerng/maxmind_ver"); // Collect number of suppressed hosts +$pfbsupp_cnt = 0; if (file_exists("{$pfb['supptxt']}")) { - $pfbsupp_cnt = exec ("/usr/bin/grep -c ^ {$pfb['supptxt']}"); -} else { - $pfbsupp_cnt = 0; + $pfbsupp_cnt = exec("{$pfb['grep']} -c ^ {$pfb['supptxt']}"); } // Collect any failed downloads -exec("grep $(date +%m/%d/%y) {$pfb['errlog']} | grep 'FAIL'", $results); +exec("{$pfb['grep']} 'FAIL' {$pfb['errlog']} | {$pfb['grep']} $(date +%m/%d/%y)", $results); $results = array_reverse($results); ?> @@ -343,7 +394,7 @@ $results = array_reverse($results); </tr> <tr> <td width="22%" class="vncellt" valign="top" ><input type="text" size="3" name="pfb_maxfails" class="formfld unknown" id="pfb_maxfails" - title="Tha maximum number of Failed Download Alerts to be shown. Refer to the error.log for add'l details" + title="The maximum number of Failed Download Alerts to be shown. Refer to the error.log for add'l details" value="<?= $pfb['maxfails'] ?>" /></td> <td width="78%" class="listr" ><?=gettext("Enter number of download fails to display (default:3)");?></td> </tr> @@ -357,9 +408,7 @@ $results = array_reverse($results); <td width="22" class="vncellt" valign="top" > <select name="pfb_sortcolumn" id="pfb_sortcolumn" class="formselect" title="The Column to be sorted" > <?php - $pfbsort = array( 'none' => 'None', 'alias' => 'Alias', 'count' => 'Count', - 'packets' => 'Packets', 'updated' => 'Updated' - ); + $pfbsort = array( 'none' => 'None', 'alias' => 'Alias', 'count' => 'Count', 'packets' => 'Packets', 'updated' => 'Updated' ); foreach ($pfbsort as $sort => $sorttype): ?> <option value="<?=$sort; ?>" <?php if ($sort == $pfb['sortcolumn']) echo 'selected'; ?> ><?=$sorttype; ?></option> <?php endforeach; ?> @@ -383,40 +432,64 @@ $results = array_reverse($results); <!-- Print widget status bar items --> <div class="marinarea"> - <table id="pfb_table" border="0" cellspacing="0" cellpadding="0"> + <table id="pfb_table" width="100%" border="0" cellspacing="0" cellpadding="0"> <thead> <tr> - <td valign="middle"> <img src="<?= $pfb_status ?>" width="13" height="13" border="0" title="<?=gettext($pfb_msg) ?>" alt="" /></td> - <td valign="middle"> </td> - <td valign="middle" p style="font-size:10px"> - <?php if ($dcount != 0): ?> - <?=gettext("Deny:"); echo(" <strong>" . $dcount . "</strong>") ?> - <?php endif; ?> - <?php if ($pcount != 0): ?> - <?=gettext(" Permit:"); echo(" <strong>" . $pcount . "</strong>") ?> - <?php endif; ?> - <?php if ($mcount != 0): ?> - <?=gettext(" Match:"); echo(" <strong>" . $mcount . "</strong>"); ?> - <?php endif; ?> - <?php if ($ncount != 0): ?> - <?=gettext(" Native:"); echo(" <strong>" . $ncount . "</strong>"); ?> - <?php endif; ?> - <?php if ($pfbsupp_cnt != 0): ?> - <?=gettext(" Supp:"); echo(" <strong>" . $pfbsupp_cnt . "</strong>"); ?> - <?php endif; ?></td> - <td valign="middle"> </td> - <td valign="top"><a href="pfblockerng/pfblockerng_log.php"><img src="/themes/<?=$g['theme']; ?>/images/icons/icon_logs.gif" - width="13" height="13" border="0" title="<?=gettext("View pfBlockerNG Logs TAB") ?>" alt="" /></a> - <td valign="top"> + <td style="font-size:10px;white-space: nowrap;"> <img src="<?= $pfb_status ?>" + width="13" height="13" border="0" title="<?=gettext($pfb_msg) ?>" alt="" /> + + <?=gettext(" ") ?> + <?php if ($dcount != 0): ?> + <?php echo("IP- Deny: <strong>{$dcount}</strong>"); ?> + <?php endif; ?> + <?php if ($pcount != 0): ?> + <?php echo("Permit: <strong>{$pcount}</strong>"); ?> + <?php endif; ?> + <?php if ($mcount != 0): ?> + <?php echo("Match: <strong>{$mcount}</strong>"); ?> + <?php endif; ?> + <?php if ($ncount != 0): ?> + <?php echo("Native: <strong>{$ncount}</strong>"); ?> + <?php endif; ?> + <?php if ($pfbsupp_cnt != 0): ?> + <?php echo("Supp: <strong>{$pfbsupp_cnt}</strong>"); ?> + <?php endif; ?> + <?=gettext(" ") ?> + + <a target='_blank' href="pfblockerng/pfblockerng_log.php"><img src="/themes/<?=$g['theme']; ?>/images/icons/icon_logs.gif" + width="13" height="13" border="0" title="<?=gettext("View pfBlockerNG Logs TAB") ?>" alt="" /></a> + <?php if (!empty($results)): ?> <!--Hide "Ack" Button when Failed Downloads are Empty--> - <form action="/widgets/widgets/pfblockerng.widget.php" method="post" name="widget_pfblockerng_ack"> + <form style="display:inline;" action="/widgets/widgets/pfblockerng.widget.php" method="post" name="widget_pfblockerng_ack"> <input type="hidden" value="clearack" name="pfblockerngack" /> - <input class="vexpl" type="image" name="pfblockerng_ackbutton" src="/themes/<?=$g['theme']; ?>/images/icons/icon_x.gif" - width="14" height="14" border="0" title="<?=gettext("Clear Failed Downloads") ?>"/> + <input class="vexpl" type="image" name="pfblockerng_ackbutton" src="/themes/<?=$g['theme']; ?> + /images/icons/icon_x.gif" width="14" height="14" border="0" title="<?=gettext("Clear Failed Downloads") ?>"/> </form> <?php endif; ?> </td> </tr> + + <?php if ($pfb['dnsbl'] == 'on'): ?> <!--Enable DNSBL widget statistics if enabled--> + <tr> + <td style="font-size:10px"> <img src="<?= $dnsbl_status ?>" width="13" height="13" border="0" + title="<?=gettext($dnsbl_msg); ?>" alt="" /> + <?php if ($scount != 0): ?> + <?php echo(" DNSBL- <strong>{$scount}</strong> "); ?> + <?php endif; ?> + <form style="display:inline"; action="/widgets/widgets/pfblockerng.widget.php" method="post" name="widget_pfblockerng_dnsblclear"> + <input type="hidden" value="dnsblclear" name="pfblockerngdnsblclear" /> + <input class="vexpl" type="image" name="dnsblclearbutton" src="/themes/<?=$g['theme']; ?>/images/icons/icon_x.gif" + width="14" height="14" border="0" title="<?=gettext("Clear DNSBL Packets") ?>"/> + </form> + </td> + </tr> + <?php endif; ?> + + <tr> + <td > + <?php echo "<br /> MaxMind: {$maxver}"; ?> + </td> + </tr> </thead> </table> </div> @@ -426,17 +499,18 @@ $results = array_reverse($results); <?php // Report any failed downloads -$counter = 0; if (!empty($results)) { + $counter = 1; + $entries = count($results); foreach ($results as $result) { $RowClass = $counter % 2 ? $pfb['RowEvenClass'] : $pfb['RowOddClass']; - echo(" <tr " . $RowClass . "><td class='" . $pfb['ColClass'] . "'>" . $result . "</td><tr>"); - $counter++; - if ($counter > $pfb['maxfails']) { + if ($counter > $pfb['maxfails'] && $entries > $pfb['maxfails']) { // To many errors stop displaying - echo(" <tr " . $RowClass . "><td class='" . $pfb['ColClass'] . "'>" . (count($results) - $pfb['maxfails']) . " more error(s)...</td><tr>"); + echo("<tr {$RowClass}><td class='{$pfb['ColClass']}'>" . ($entries - $pfb['maxfails']) . ' more error(s)...</td><tr>'); break; } + echo("<tr {$RowClass}><td class='{$pfb['ColClass']}'>{$result}</td><tr>"); + $counter++; } } diff --git a/config/pfblockerng/pfblockerng.xml b/config/pfblockerng/pfblockerng.xml index d3b2cb16..c7f2c068 100644 --- a/config/pfblockerng/pfblockerng.xml +++ b/config/pfblockerng/pfblockerng.xml @@ -1,20 +1,19 @@ <?xml version="1.0" encoding="utf-8" ?> -<!DOCTYPE packagegui SYSTEM "./schema/packages.dtd"> -<?xml-stylesheet type="text/xsl" href="./xsl/package.xsl"?> +<!DOCTYPE packagegui SYSTEM "../schema/packages.dtd"> +<?xml-stylesheet type="text/xsl" href="../xsl/package.xsl"?> <packagegui> <copyright> <![CDATA[ -/* $Id$ */ /* ======================================================================================= */ /* pfBlockerNG.xml pfBlockerNG - Copyright (C) 2015 BBcan177@gmail.com + Copyright (c) 2015 BBcan177@gmail.com All rights reserved. Based upon pfblocker for pfSense - Copyright (C) 2011 Marcello Coutinho + Copyright (c) 2011 Marcello Coutinho All rights reserved. /* /* ====================================================================================== */ @@ -49,7 +48,7 @@ <requirements>Describe your package requirements here</requirements> <faq>Currently there are no FAQ items provided.</faq> <name>pfblockerng</name> - <version>1.09</version> + <version>2.0</version> <title>pfBlockerNG: General Settings</title> <include_file>/usr/local/pkg/pfblockerng/pfblockerng.inc</include_file> <addedit_string>pfBlockerNG: Save General Settings</addedit_string> @@ -60,84 +59,91 @@ <section>Firewall</section> <url>/pkg_edit.php?xml=pfblockerng.xml</url> </menu> + <service> + <name>dnsbl</name> + <rcfile>dnsbl.sh</rcfile> + <executable>lighttpd_pfb</executable> + <description>pfBlockerNG DNSBL Web Server</description> + </service> <additional_files_needed> <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng.priv.inc</item> <prefix>/etc/inc/priv/</prefix> - <chmod>0644</chmod> </additional_files_needed> <additional_files_needed> <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng.inc</item> <prefix>/usr/local/pkg/pfblockerng/</prefix> - <chmod>0644</chmod> </additional_files_needed> <additional_files_needed> <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng_install.inc</item> <prefix>/usr/local/pkg/pfblockerng/</prefix> </additional_files_needed> <additional_files_needed> + <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng_extra.inc</item> + <prefix>/usr/local/pkg/pfblockerng/</prefix> + </additional_files_needed> + <additional_files_needed> <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng.php</item> <prefix>/usr/local/www/pfblockerng/</prefix> - <chmod>0644</chmod> </additional_files_needed> <additional_files_needed> <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng_alerts.php</item> <prefix>/usr/local/www/pfblockerng/</prefix> - <chmod>0644</chmod> + </additional_files_needed> + <additional_files_needed> + <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng_alerts_ar.php</item> + <prefix>/usr/local/www/pfblockerng/</prefix> </additional_files_needed> <additional_files_needed> <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng_update.php</item> <prefix>/usr/local/www/pfblockerng/</prefix> - <chmod>0644</chmod> </additional_files_needed> <additional_files_needed> <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng_log.php</item> <prefix>/usr/local/www/pfblockerng/</prefix> - <chmod>0644</chmod> </additional_files_needed> <additional_files_needed> - <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng_diag_dns.php</item> + <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng_threats.php</item> <prefix>/usr/local/www/pfblockerng/</prefix> - <chmod>0644</chmod> </additional_files_needed> <additional_files_needed> <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng.widget.php</item> <prefix>/usr/local/www/widgets/widgets/</prefix> - <chmod>0644</chmod> </additional_files_needed> <additional_files_needed> <item>https://packages.pfsense.org/packages/config/pfblockerng/widget-pfblockerng.inc</item> <prefix>/usr/local/www/widgets/include/</prefix> - <chmod>0644</chmod> </additional_files_needed> <additional_files_needed> <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng.js</item> <prefix>/usr/local/www/widgets/javascript/</prefix> - <chmod>0644</chmod> </additional_files_needed> <additional_files_needed> <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng_top20.xml</item> <prefix>/usr/local/pkg/pfblockerng/</prefix> - <chmod>0644</chmod> + </additional_files_needed> + <additional_files_needed> + <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng_dnsbl.xml</item> + <prefix>/usr/local/pkg/pfblockerng/</prefix> + </additional_files_needed> + <additional_files_needed> + <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng_dnsbl_lists.xml</item> + <prefix>/usr/local/pkg/pfblockerng/</prefix> + </additional_files_needed> + <additional_files_needed> + <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng_dnsbl_easylist.xml</item> + <prefix>/usr/local/pkg/pfblockerng/</prefix> </additional_files_needed> <additional_files_needed> <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng_v4lists.xml</item> <prefix>/usr/local/pkg/pfblockerng/</prefix> - <chmod>0644</chmod> </additional_files_needed> <additional_files_needed> <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng_v6lists.xml</item> <prefix>/usr/local/pkg/pfblockerng/</prefix> - <chmod>0644</chmod> </additional_files_needed> <additional_files_needed> <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng_sync.xml</item> <prefix>/usr/local/pkg/pfblockerng/</prefix> - <chmod>0644</chmod> - </additional_files_needed> - <additional_files_needed> - <item>https://packages.pfsense.org/packages/config/pfblockerng/countrycodes.tar.bz2</item> - <prefix>/var/db/pfblockerng/</prefix> - <chmod>0444</chmod> </additional_files_needed> <additional_files_needed> <item>https://packages.pfsense.org/packages/config/pfblockerng/pfblockerng.sh</item> @@ -145,14 +151,14 @@ <chmod>0755</chmod> </additional_files_needed> <additional_files_needed> - <item>https://packages.pfsense.org/packages/config/pfblockerng/geoipupdate.sh</item> - <prefix>/usr/local/pkg/pfblockerng/</prefix> + <item>https://packages.pfsense.org/packages/config/pfblockerng/index.php</item> + <prefix>/usr/local/www/pfblockerng/www/</prefix> <chmod>0755</chmod> </additional_files_needed> <tabs> <tab> <text>General</text> - <url>/pkg_edit.php?xml=pfblockerng.xml&id=0</url> + <url>/pkg_edit.php?xml=pfblockerng.xml</url> <active/> </tab> <tab> @@ -165,47 +171,23 @@ </tab> <tab> <text>Reputation</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml</url> </tab> <tab> <text>IPv4</text> - <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml&id=0</url> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml</url> </tab> <tab> <text>IPv6</text> - <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml&id=0</url> - </tab> - <tab> - <text>Top20</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml&id=0</url> - </tab> - <tab> - <text>Africa</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Africa.xml&id=0</url> - </tab> - <tab> - <text>Asia</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Asia.xml&id=0</url> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml</url> </tab> <tab> - <text>Europe</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Europe.xml&id=0</url> + <text>DNSBL</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl.xml</url> </tab> <tab> - <text>N.A.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_NorthAmerica.xml&id=0</url> - </tab> - <tab> - <text>Oceania</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Oceania.xml&id=0</url> - </tab> - <tab> - <text>S.A.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_SouthAmerica.xml&id=0</url> - </tab> - <tab> - <text>P.S.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_ProxyandSatellite.xml&id=0</url> + <text>Country</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml</url> </tab> <tab> <text>Logs</text> @@ -213,7 +195,7 @@ </tab> <tab> <text>Sync</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml</url> </tab> </tabs> <fields> @@ -224,8 +206,8 @@ <field> <fielddescr>LINKS</fielddescr> <fieldname></fieldname> - <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a> - <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> + <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a>  + <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> </description> <type>info</type> </field> @@ -241,7 +223,7 @@ <fieldname>pfb_keep</fieldname> <type>checkbox</type> <description><![CDATA[Keep Settings: <br /><font color='red'>Note:</font> - with 'Keep settings' enabled, pfBlockerNG will maintain run state - on Installation/Upgrade<br />If 'Keep Settings' is not 'enabled' on pkg Install/De-Install, all Settings will be Wiped!<br /><br /> + on Installation/Upgrade<br />If 'Keep Settings' is not 'enabled' on pkg Install/De-Install, all settings will be Wiped!<br /><br /> <font color='red'>Note: </font>To clear all downloaded lists, uncheck these two checkboxes and 'Save'. re-check both boxes and run a 'Force Update']]> </description> @@ -258,8 +240,8 @@ <fielddescr>Hour Interval</fielddescr> <fieldname>pfb_interval</fieldname> <description><![CDATA[Default: <strong>Every hour</strong><br /> - Select the cron Hour Interval. The interval selected will be used with the Start min/hour below.<br /> - <strong>Ensure that all List 'Update Settings' are within the selected Interval/Start Hour Settings.</strong>]]> + Select the cron hour interval. The interval selected will be used with the start min/hour below.<br /> + <strong>Ensure that all list 'Update settings' are within the selected interval/start hour settings.</strong>]]> </description> <type>select</type> <options> @@ -295,7 +277,7 @@ <fielddescr>Start Hour</fielddescr> <fieldname>pfb_hour</fieldname> <description><![CDATA[Default: <strong>0</strong><br /> - Select the Start Hour]]> + Select the start hour]]> </description> <type>select</type> <options> @@ -330,7 +312,7 @@ <field> <fielddescr><![CDATA['Daily/Weekly'<br />Start Hour]]></fielddescr> <fieldname>pfb_dailystart</fieldname> - <description><![CDATA[Default: <strong>0</strong><br />This is used for the 'Daily/Weekly' Scheduler Only.]]></description> + <description><![CDATA[Default: <strong>0</strong><br />This is used by the 'Daily/Weekly' scheduler only.]]></description> <type>select</type> <options> <option><name>0</name><value>0</value></option> @@ -368,13 +350,19 @@ <description>Only for IPv4 Lists</description> </field> <field> + <fielddescr>Enable Aggregation of CIDRs</fielddescr> + <fieldname>enable_agg</fieldname> + <type>checkbox</type> + <description>Optimise CIDRs (not recommended for slow systems with large lists)</description> + </field> + <field> <fielddescr>Enable Suppression</fielddescr> <fieldname>suppression</fieldname> <type>checkbox</type> - <description><![CDATA[This will prevent Selected IPs from being Blocked. Only for IPv4 Lists (/32 and /24).<br /> - Country Blocking Lists cannot be Suppressed.<br />This will also remove any RFC1918 addresses from all Lists.<br /><br /> - Alerts can be Suppressed using the '+' icon in the Alerts Tab and IPs added to the 'pfBlockerNGSuppress' Alias<br /> - A Blocked IP in a CIDR other than /32 or /24 will need a 'Whitelist Alias' w/ List Action: 'Permit Outbound' Firewall Rule + <description><![CDATA[This will prevent Selected IPs from being blocked. Only for IPv4 lists (/32 and /24).<br /> + Country blocking lists cannot be suppressed.<br />This will also remove any RFC1918 addresses from all lists.<br /><br /> + Alerts can be suppressed using the '+' icon in the Alerts tab and IPs added to the 'pfBlockerNGSuppress' alias<br /> + A blocked IP in a CIDR other than /32 or /24 will need a 'Whitelist alias' w/ list action: 'Permit Outbound' Firewall rule <br />Do not use the pfBlockerNGSuppress Alias in a Firewall Rule. This alias is used during the cron download process only.]]> </description> @@ -383,17 +371,44 @@ <fielddescr>Global Enable Logging</fielddescr> <fieldname>enable_log</fieldname> <type>checkbox</type> - <description><![CDATA[Firewall Rule logging - Enable Global Logging to [ Status: System Logs: FIREWALL Log ]<br /> - This overrides any Log Settings in the Alias Tabs.]]> + <description><![CDATA[Firewall Rule logging - Enable Global logging to [ Status: System Logs: FIREWALL Log ]<br /> + This overrides any log settings in the Alias tabs.]]> </description> </field> <field> - <fielddescr>Disable MaxMind Country Database CRON Updates</fielddescr> + <fielddescr>Disable MaxMind Country database CRON updates</fielddescr> <fieldname>database_cc</fieldname> <type>checkbox</type> - <description><![CDATA[This will Disable the MaxMind Monthly Country Database Cron Update.<br /> - This does not affect the MaxMind Binary Cron Task]]> + <description><![CDATA[This will disable the MaxMind monthly Country database Cron update.<br /> + This does not affect the MaxMind binary cron task]]> + </description> + </field> + <field> + <fielddescr>Max daily download failure threshold</fielddescr> + <fieldname>skipfeed</fieldname> + <description><![CDATA[Default: <strong>0</strong> (Disabled)<br /> + Select max daily download failure threshold via CRON. Clear widget 'failed downloads' to reset.]]> </description> + <type>select</type> + <options> + <option><name>0</name><value>0</value></option> + <option><name>1</name><value>1</value></option> + <option><name>2</name><value>2</value></option> + <option><name>3</name><value>3</value></option> + <option><name>4</name><value>4</value></option> + <option><name>5</name><value>5</value></option> + <option><name>6</name><value>6</value></option> + </options> + <default_value>0</default_value> + </field> + <field> + <fielddescr>Restore previous download on failure</fielddescr> + <fieldname>restore_feed</fieldname> + <type>checkbox</type> + <description><![CDATA[Default: <strong>Enabled</strong><br /> + When 'selected', on a download failure, the previously downloaded list is restored.]]> + </description> + <default_value>on</default_value> </field> <field> <fielddescr>Logfile Size</fielddescr> @@ -423,25 +438,26 @@ <field> <fieldname>inbound_interface</fieldname> <fielddescr>Interface(s)</fielddescr> - <description>Select the Inbound interface(s) you want to Apply Auto Rules to</description> + <description>Select the Inbound interface(s) you want to apply auto rules to:</description> <type>interfaces_selection</type> <hideinterfaceregex>loopback</hideinterfaceregex> <required/> <multiple/> <combinefields/> + <default_value>wan</default_value> </field> <field> <fielddescr>Rule Action</fielddescr> <fieldname>inbound_deny_action</fieldname> - <description><![CDATA[Default: <strong>Block</strong><br />Select 'Rule Action' for Inbound Rules]]></description> + <description><![CDATA[Default: <strong>Block</strong><br />Select 'Rule action' for Inbound rules:]]></description> <type>select</type> <options> <option><name>Block</name><value>block</value></option> <option><name>Reject</name><value>reject</value></option> </options> - <default_value>block</default_value> <required/> <combinefields>end</combinefields> + <default_value>block</default_value> </field> <field> <fielddescr>Outbound Firewall Rules</fielddescr> @@ -450,38 +466,39 @@ <field> <fielddescr>Interface(s)</fielddescr> <fieldname>outbound_interface</fieldname> - <description>Select the Outbound interface(s) you want to Apply Auto Rules to</description> + <description>Select the Outbound interface(s) you want to apply auto rules to:</description> <type>interfaces_selection</type> <hideinterfaceregex>loopback</hideinterfaceregex> <required/> <multiple/> <combinefields/> + <default_value>lan</default_value> </field> <field> <fielddescr>Rule Action</fielddescr> <fieldname>outbound_deny_action</fieldname> - <description><![CDATA[Default: <strong>Reject</strong><br />Select 'Rule Action' for Outbound rules]]></description> + <description><![CDATA[Default: <strong>Reject</strong><br />Select 'Rule action' for Outbound rules:]]></description> <type>select</type> <options> <option><name>Reject</name><value>reject</value></option> <option><name>Block</name><value>block</value></option> </options> - <default_value>reject</default_value> <required/> + <default_value>reject</default_value> <combinefields>end</combinefields> </field> <field> <fielddescr>OpenVPN Interface</fielddescr> <fieldname>openvpn_action</fieldname> <type>checkbox</type> - <description>Select to add Auto-Rules for OpenVPN. These will be added to 'Floating Rules' or OpenVPN Rules Tab.</description> + <description>Select to add auto-rules for OpenVPN. These will be added to 'Floating Rules' or OpenVPN rules tab.</description> </field> <field> <fielddescr>Floating Rules</fielddescr> <fieldname>enable_float</fieldname> <type>checkbox</type> - <description><![CDATA[<strong>Enabled:</strong> Auto-Rules will be generated in the 'Floating Rules' Tab<br /><br /> - <strong>Disabled:</strong> Auto-Rules will be generated in the Selected Inbound/Outbound Interfaces<br /><br /> + <description><![CDATA[<strong>Enabled:</strong> Auto-rules will be generated in the 'Floating Rules' tab<br /><br /> + <strong>Disabled:</strong> Auto-rules will be generated in the selected Inbound/Outbound interfaces<br /><br /> <strong>Rules will be ordered by the selection below.</strong>]]> </description> </field> @@ -490,8 +507,8 @@ <fieldname>pass_order</fieldname> <description><![CDATA[<br />Default Order:<strong> | pfB_Block/Reject | All other Rules | (original format)<br /></strong><br /> Select The '<strong>Order</strong>' of the Rules<br /> - Selecting 'original format', sets pfBlockerNG rules at the top of the Firewall TAB.<br /> - Selecting any other 'Order' will re-order <strong>all the Rules to the format indicated!</strong>]]> +  Selecting 'original format', sets pfBlockerNG rules at the top of the Firewall TAB.<br /> +  Selecting any other 'Order' will re-order <strong>all the rules to the format indicated!</strong>]]> </description> <type>select</type> <options> @@ -506,7 +523,7 @@ <fielddescr>Auto Rule Suffix</fielddescr> <fieldname>autorule_suffix</fieldname> <description><![CDATA[Default: <strong>auto rule</strong><br /> - Select 'Auto Rule' Description Suffix for Auto Defined rules. pfBlockerNG Must be Disabled to Modify Suffix]]> + Select 'Auto Rule' description suffix for auto defined rules. pfBlockerNG must be disabled to modify suffix]]> </description> <type>select</type> <options> @@ -517,6 +534,14 @@ <default_value>autorule</default_value> </field> <field> + <fielddescr>Kill States</fielddescr> + <fieldname>killstates</fieldname> + <type>checkbox</type> + <description><![CDATA[When 'Enabled', after a cron event or any 'Force' commands, any blocked IPs found in the <br /> + Firewall states will be cleared.]]> + </description> + </field> + <field> <name><![CDATA[Acknowledgements]]></name> <type>listtopic</type> </field> @@ -525,11 +550,11 @@ <fieldname>credits</fieldname> <type>info</type> <description><![CDATA[<strong>pfBlockerNG </strong> - Created in 2015 by <a target=_new href='https://forum.pfsense.org/index.php?action=profile;u=238481'>BBcan177.</a><br /><br /> + Created in 2015 by <a target='_blank' href='https://forum.pfsense.org/index.php?action=profile;u=238481'>BBcan177.</a><br /><br /> Based upon pfBlocker by Marcello Coutinho and Tom Schaefer.<br /> - Country Database GeoLite distributed under the Creative Commons Attribution-ShareAlike 3.0 Unported License by: - MaxMind Inc. @ <a target=_new href='http://www.maxmind.com'>MaxMind.com</a>. - The Database is Automatically Updated the First Tuesday of Each Month]]> + Country database GeoLite distributed under the Creative Commons Attribution-ShareAlike 3.0 Unported License by: + MaxMind Inc. @ <a target='_blank' href='http://www.maxmind.com'>MaxMind.com</a>. + The database is automatically updated the first Tuesday of each month]]> </description> </field> <field> @@ -540,7 +565,7 @@ </description> </field> <field> - <name><![CDATA[<center>Click to SAVE Settings and/or Rule Edits. Changes are Applied via CRON or + <name><![CDATA[<center>Click to SAVE Settings and/or Rule edits.   Changes are applied via CRON or 'Force Update'</center>]]></name> <type>listtopic</type> </field> @@ -556,11 +581,15 @@ ]]> </custom_php_deinstall_command> <custom_php_validation_command> + <![CDATA[ pfblockerng_validate_input($_POST, $input_errors); + ]]> </custom_php_validation_command> <custom_php_resync_config_command> + <![CDATA[ global $pfb; $pfb['save'] = TRUE; sync_package_pfblockerng(); + ]]> </custom_php_resync_config_command> </packagegui>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng_alerts.php b/config/pfblockerng/pfblockerng_alerts.php index 7253d04d..79cd0d62 100644 --- a/config/pfblockerng/pfblockerng_alerts.php +++ b/config/pfblockerng/pfblockerng_alerts.php @@ -3,14 +3,14 @@ pfBlockerNG_Alerts.php pfBlockerNG - Copyright (C) 2015 BBcan177@gmail.com + Copyright (c) 2015 BBcan177@gmail.com All rights reserved. Portions of this code are based on original work done for pfSense from the following contributors: Parts based on works from Snort_alerts.php - Copyright (C) 2015 Bill Meeks + Copyright (c) 2015 Bill Meeks All rights reserved. Javascript Hostname Lookup modifications by J. Nieuwenhuizen @@ -39,392 +39,538 @@ POSSIBILITY OF SUCH DAMAGE. */ -// Auto-Resolve Hostnames -if (isset($_REQUEST['getpfhostname'])) { - $getpfhostname = trim(htmlspecialchars($_REQUEST['getpfhostname'])); - if (strlen($getpfhostname) >= 8) { - $hostname = htmlspecialchars(gethostbyaddr($getpfhostname), ENT_QUOTES); - } else { - $hostname = $getpfhostname; - } - if ($hostname == $getpfhostname) { - $hostname = 'unknown'; - } - echo $hostname; - die; -} +require_once('util.inc'); +require_once('guiconfig.inc'); +require_once('/usr/local/pkg/pfblockerng/pfblockerng.inc'); -require_once("util.inc"); -require_once("guiconfig.inc"); -require_once("/usr/local/pkg/pfblockerng/pfblockerng.inc"); -global $rule_list, $pfb_localsub; +global $g, $pfb, $rule_list, $pfb_localsub; pfb_global(); -$pfs_version = substr(trim(file_get_contents("/etc/version")),0,3); - -if ($pfs_version == "2.2") { - $prefix = "/usr/pbi/pfblockerng-" . php_uname("m"); -} else { - $prefix = "/usr/local"; -} - -// Application Paths -$pathgeoip = "{$prefix}/bin/geoiplookup"; -$pathgeoip6 = "{$prefix}/bin/geoiplookup6"; +// Application paths +$pathgeoip = "{$pfb['prefix']}/bin/geoiplookup"; +$pathgeoip6 = "{$pfb['prefix']}/bin/geoiplookup6"; -// Define File Locations +// Define file locations $filter_logfile = "{$g['varlog_path']}/filter.log"; -$pathgeoipdat = "{$prefix}/share/GeoIP/GeoIP.dat"; -$pathgeoipdat6 = "{$prefix}/share/GeoIP/GeoIPv6.dat"; +$pathgeoipdat = "{$pfb['geoipshare']}/GeoIP.dat"; +$pathgeoipdat6 = "{$pfb['geoipshare']}/GeoIPv6.dat"; -// Emerging Threats IQRisk Header Name Reference -$pfb['et_header'] = TRUE; +// Proofpoint ET IQRisk header name reference $et_header = $config['installedpackages']['pfblockerngreputation']['config'][0]['et_header']; +$pfb['et_header'] = TRUE; if (empty($et_header)) { $pfb['et_header'] = FALSE; } -// Collect pfBlockerNGSuppress Alias and Create pfbsuppression.txt -if ($pfb['supp'] == "on") { +// Collect pfBlockerNGSuppress alias and create pfbsuppression.txt +if ($pfb['supp'] == 'on') { pfb_create_suppression_file(); } -// Collect Number of Suppressed Hosts +// Collect number of suppressed hosts +$pfbsupp_cnt = 0; if (file_exists("{$pfb['supptxt']}")) { - $pfbsupp_cnt = exec ("/usr/bin/grep -c ^ {$pfb['supptxt']}"); -} else { - $pfbsupp_cnt = 0; + $pfbsupp_cnt = exec("{$pfb['grep']} -c ^ {$pfb['supptxt']}"); } -$pfb['global'] = &$config['installedpackages']['pfblockerngglobal']; - -if (!isset($pfb['global']['pfbdenycnt'])) { - $pfb['global']['pfbdenycnt'] = '25'; -} -if (!isset($pfb['global']['pfbpermitcnt'])) { - $pfb['global']['pfbpermitcnt'] = '5'; -} -if (!isset($pfb['global']['pfbmatchcnt'])) { - $pfb['global']['pfbmatchcnt'] = '5'; -} -if (!isset($pfb['global']['pfbdnscnt'])) { - $pfb['global']['pfbdnscnt'] = '5'; -} -if (empty($pfb['global']['alertrefresh'])) { - $pfb['global']['alertrefresh'] = 'off'; -} -if (empty($pfb['global']['hostlookup'])) { - $pfb['global']['hostlookup'] = 'off'; +// Alerts tab customizations +$aglobal_array = array('pfbdenycnt' => 25, 'pfbpermitcnt' => 5, 'pfbmatchcnt' => 5, 'pfbdnscnt' => 5, 'alertrefresh' => 'on', 'hostlookup' => 'on'); +$pfb['aglobal'] = &$config['installedpackages']['pfblockerngglobal']; +foreach ($aglobal_array as $type => $value) { + ${"$type"} = $pfb['aglobal'][$type] != '' ? $pfb['aglobal'][$type] : $value; } +// Save Alerts tab customizations if (isset($_POST['save'])) { - if (!is_array($pfb['global'])) { - $pfb['global'] = array(); - } - $pfb['global']['alertrefresh'] = $_POST['alertrefresh'] ? 'on' : 'off'; - $pfb['global']['hostlookup'] = $_POST['hostlookup'] ? 'on' : 'off'; - if (is_numeric($_POST['pfbdenycnt'])) { - $pfb['global']['pfbdenycnt'] = $_POST['pfbdenycnt']; - } - if (is_numeric($_POST['pfbpermitcnt'])) { - $pfb['global']['pfbpermitcnt'] = $_POST['pfbpermitcnt']; - } - if (is_numeric($_POST['pfbmatchcnt'])) { - $pfb['global']['pfbmatchcnt'] = $_POST['pfbmatchcnt']; - } - if (is_numeric($_POST['pfbdnscnt'])) { - $pfb['global']['pfbdnscnt'] = $_POST['pfbdnscnt']; + $pfb['aglobal']['alertrefresh'] = htmlspecialchars($_POST['alertrefresh']) ?: 'off'; + $pfb['aglobal']['hostlookup'] = htmlspecialchars($_POST['hostlookup']) ?: 'off'; + unset($aglobal_array['alertrefresh'], $aglobal_array['hostlookup']); + + foreach ($aglobal_array as $type => $value) { + if (ctype_digit(htmlspecialchars($_POST[$type]))) { + $pfb['aglobal'][$type] = htmlspecialchars($_POST[$type]); + } } - write_config("pfBlockerNG pkg: updated ALERTS tab settings."); - header("Location: " . $_SERVER['PHP_SELF']); - exit; -} -if (is_array($pfb['global'])) { - $alertrefresh = $pfb['global']['alertrefresh']; - $hostlookup = $pfb['global']['hostlookup']; - $pfbdenycnt = $pfb['global']['pfbdenycnt']; - $pfbpermitcnt = $pfb['global']['pfbpermitcnt']; - $pfbmatchcnt = $pfb['global']['pfbmatchcnt']; - $pfbdnscnt = $pfb['global']['pfbdnscnt']; + write_config('pfBlockerNG pkg: updated ALERTS tab settings.'); + header('Location: /pfblockerng/pfblockerng_alerts.php'); + exit; } - -// Define Alerts Log filter Rollup window variable and collect Widget Alert Pivot details +// Define alerts log filter rollup window variable and collect widget alert pivot details if (isset($_REQUEST['rule'])) { - $filterfieldsarray[0] = $_REQUEST['rule']; - $pfbdenycnt = $pfbpermitcnt = $pfbmatchcnt = $_REQUEST['entries']; - $pfb['filterlogentries'] = TRUE; -} -else { - $pfb['filterlogentries'] = FALSE; + $filterfieldsarray[0] = htmlspecialchars($_REQUEST['rule']); + $pfbdenycnt = $pfbpermitcnt = $pfbmatchcnt = htmlspecialchars($_REQUEST['entries']); + $pfb['filterlogentries'] = TRUE; +} else { + $pfb['filterlogentries'] = FALSE; } - -function pfb_match_filter_field($flent, $fields) { - foreach ($fields as $key => $field) { - if ($field == null) { - continue; - } - if ((strpos($field, '!') === 0)) { - $field = substr($field, 1); - $field_regex = str_replace('/', '\/', str_replace('\/', '/', $field)); - if (@preg_match("/{$field_regex}/i", $flent[$key])) { - return false; - } - } - else { - $field_regex = str_replace('/', '\/', str_replace('\/', '/', $field)); - if (!@preg_match("/{$field_regex}/i", $flent[$key])) { - return false; - } +// Re-enable any Alert 'filter settings' on page refresh +if (isset($_REQUEST['refresh'])) { + $refresharr = unserialize(urldecode($_REQUEST['refresh'])); + if (isset($refresharr)) { + foreach ($refresharr as $key => $type) { + $filterfieldsarray[htmlspecialchars($key)] = htmlspecialchars($type) ?: null; } } - return true; + $pfb['filterlogentries'] = TRUE; } - -if ($_POST['filterlogentries_submit']) { - // Set flag for filtering alert entries +// Filter Alerts based on user defined 'filter settings' +if (isset($_POST['filterlogentries_submit'])) { $pfb['filterlogentries'] = TRUE; - - // Note the order of these fields must match the order decoded from the alerts log $filterfieldsarray = array(); - $filterfieldsarray[0] = $_POST['filterlogentries_rule'] ? $_POST['filterlogentries_rule'] : null; - $filterfieldsarray[2] = $_POST['filterlogentries_int'] ? $_POST['filterlogentries_int'] : null; - $filterfieldsarray[6] = strtolower($_POST['filterlogentries_proto']) ? $_POST['filterlogentries_proto'] : null; - // Remove any zero-length spaces added to the IP address that could creep in from a copy-paste operation - $filterfieldsarray[7] = $_POST['filterlogentries_srcip'] ? str_replace("\xE2\x80\x8B", "", $_POST['filterlogentries_srcip']) : null; - $filterfieldsarray[8] = $_POST['filterlogentries_dstip'] ? str_replace("\xE2\x80\x8B", "", $_POST['filterlogentries_dstip']) : null; + foreach (array( 0 => 'rule', 2 => 'int', 6 => 'proto', 7 => 'srcip', 8 => 'dstip', + 9 => 'srcport', 10 => 'dstport', 90 => 'dnsbl', 99 => 'date') as $key => $type) { - $filterfieldsarray[9] = $_POST['filterlogentries_srcport'] ? $_POST['filterlogentries_srcport'] : null; - $filterfieldsarray[10] = $_POST['filterlogentries_dstport'] ? $_POST['filterlogentries_dstport'] : null; - $filterfieldsarray[99] = $_POST['filterlogentries_date'] ? $_POST['filterlogentries_date'] : null; + $type = htmlspecialchars($_POST['filterlogentries_' . "{$type}"]) ?: null; + if ($key == 6) { + $type = strtolower("{$type}"); + } + $filterfieldsarray[$key] = $type ?: null; + } } - -if ($_POST['filterlogentries_clear']) { - $pfb['filterlogentries'] = TRUE; +if (isset($_POST['filterlogentries_clear'])) { + $pfb['filterlogentries'] = FALSE; $filterfieldsarray = array(); } - -// Collect pfBlockerNG Rule Names and Number -$rule_list = array(); -exec("/sbin/pfctl -vv -sr | grep 'pfB_'", $results); -if (!empty($results)) { - foreach ($results as $result) { - - // Find Rule Descriptions - $descr = ""; - if (preg_match("/USER_RULE: (\w+)/",$result,$desc)) { - $descr = $desc[1]; - } - - preg_match ("/@(\d+)\(/",$result, $rule); - - $id = $rule[1]; - // Create array of Rule Description and pfctl Rule Number - $rule_list['id'][] = $id; - $rule_list[$id]['name'] = $descr; - } -} - -// Add IP to the Suppression Alias +// Add IP to the suppression alias if (isset($_POST['addsuppress'])) { - $ip = ""; if (isset($_POST['ip'])) { - $ip = $_POST['ip']; - $table = $_POST['table']; - $descr = $_POST['descr']; - $cidr = $_POST['cidr']; + $ip = htmlspecialchars($_POST['ip']); + $table = htmlspecialchars($_POST['table']); + $descr = htmlspecialchars($_POST['descr']); + $cidr = htmlspecialchars($_POST['cidr']); - // If Description or CIDR field is empty, exit. + // If description or CIDR field is empty, exit. if (empty($descr) || empty($cidr)) { - header("Location: " . $_SERVER['PHP_SELF']); + header('Location: /pfblockerng/pfblockerng_alerts.php'); exit; } if (is_ipaddr($ip)) { - $savemsg1 = "Host IP address {$ip}"; if (is_ipaddrv4($ip)) { - $iptrim1 = preg_replace("/(\d{1,3})\.(\d{1,3}).(\d{1,3}).(\d{1,3})/", '$1.$2.$3.0/24', $ip); - $iptrim2 = preg_replace("/(\d{1,3})\.(\d{1,3}).(\d{1,3}).(\d{1,3})/", '$1.$2.$3.', $ip); - $iptrim3 = preg_replace("/(\d{1,3})\.(\d{1,3}).(\d{1,3}).(\d{1,3})/", '$4', $ip); - - if ($cidr == "32") { - $pfb_pfctl = exec ("/sbin/pfctl -t {$table} -T show | grep {$iptrim1} 2>&1"); - - if ($pfb_pfctl == "") { - $savemsg2 = " : Removed /32 entry"; - exec ("/sbin/pfctl -t {$table} -T delete {$ip}"); + // Explode IP into evaluation strings + $ix = ip_explode($ip); + + if ($cidr == 32) { + $pfb_pfctl = exec("{$pfb['pfctl']} -t {$table} -T show | grep {$ip} 2>&1"); + if (!empty($pfb_pfctl)) { + $savemsg2 = ' : Removed /32 entry'; + exec("{$pfb['pfctl']} -t {$table} -T delete {$ip}"); } else { - $savemsg2 = " : Removed /24 entry, added 254 addr"; - exec ("/sbin/pfctl -t {$table} -T delete {$iptrim1}"); - for ($add_ip=0; $add_ip <= 255; $add_ip++){ - if ($add_ip != $iptrim3) { - exec ("/sbin/pfctl -t {$table} -T add {$iptrim2}{$add_ip}"); + exec("{$pfb['pfctl']} -t {$table} -T delete {$ix[5]} 2>&1", $pfb_pfctl); + if (preg_grep("/1\/1 addresses deleted/", $pfb_pfctl)) { + $savemsg2 = ' : Removed /24 entry, added 254 addr'; + for ($k=0; $k <= 255; $k++) { + if ($k != $ix[4]) { + exec("{$pfb['pfctl']} -t {$table} -T add {$ix[6]}{$k}"); + } } } + else { + $savemsg = gettext("Not Suppressed. Host IP address {$ip} is blocked by a CIDR other than /24"); + header('Location: /pfblockerng/pfblockerng_alerts.php'); + exit; + } } } else { $cidr = 24; - $savemsg2 = " : Removed /24 entry"; - exec ("/sbin/pfctl -t {$table} -T delete {$iptrim1} 2>&1", $pfb_pfctl); + $savemsg2 = ' : Removed /24 entry'; + exec("{$pfb['pfctl']} -t {$table} -T delete {$ix[5]} 2>&1", $pfb_pfctl); if (!preg_grep("/1\/1 addresses deleted/", $pfb_pfctl)) { - $savemsg2 = " : Removed all entries"; - // Remove 0-255 IP Address from Alias Table - for ($del_ip=0; $del_ip <= 255; $del_ip++){ - exec ("/sbin/pfctl -t {$table} -T delete {$iptrim2}{$del_ip}"); + $savemsg2 = ' : Removed all entries'; + // Remove 0-255 IP address from alias table + for ($j=0; $j <= 255; $j++) { + exec("{$pfb['pfctl']} -t {$table} -T delete {$ix[6]}{$j}"); } } } } + elseif (is_ipaddrv6($ip)) { + $cidr = ''; + $savemsg2 = ' : Removed entry'; + exec("{$pfb['pfctl']} -t {$table} -T delete {$ip}"); + } + + // Collect pfBlockerNGSuppress alias contents + $pfbfound = $pfbupdate = FALSE; + if (isset($config['aliases']['alias'])) { + foreach ($config['aliases']['alias'] as $pfb_key => $alias) { + if ($alias['name'] == 'pfBlockerNGSuppress') { + $slist = array(explode(' ', $alias['address']), explode('||', $alias['detail'])); + $pfbfound = TRUE; + break; - // Collect pfBlockerNGSuppress Alias Contents - $pfb_sup_list = array(); - $pfb_sup_array = array(); - $pfb['found'] = FALSE; - $pfb['update'] = FALSE; - if (is_array($config['aliases']['alias'])) { - foreach ($config['aliases']['alias'] as $alias) { - if ($alias['name'] == "pfBlockerNGSuppress") { - $data = $alias['address']; - $data2 = $alias['detail']; - $arr1 = explode(" ",$data); - $arr2 = explode("||",$data2); - - if (!empty($data)) { - $row = 0; - foreach ($arr1 as $host) { - $pfb_sup_list[] = $host; - $pfb_sup_array[$row]['host'] = $host; - $row++; - } - $row = 0; - foreach ($arr2 as $detail) { - $pfb_sup_array[$row]['detail'] = $detail; - $row++; - } - } - $pfb['found'] = TRUE; } } } - // Call Function to Create Suppression Alias if not found. - if (!$pfb['found']) { + // Call function to create suppression alias if not found. + if (!$pfbfound) { + $pfb_key = @max($pfb_key, 0) ? ++$pfb_key : 0; pfb_create_suppression_alias(); } - // Save New Suppress IP to pfBlockerNGSuppress Alias - if (in_array($ip . '/' . $cidr, $pfb_sup_list)) { - $savemsg = gettext("Host IP address {$ip} already exists in the pfBlockerNG Suppress Table."); + // Save new suppress IP to pfBlockerNGSuppress alias + if (in_array("{$ix[5]}", $slist[0]) || in_array("{$ip}/32", $slist[0])) { + $savemsg = gettext("Host IP address {$ip} already exists in the pfBlockerNG suppress table."); } else { - if (!$pfb['found'] && empty($pfb_sup_list)) { - $next_id = 0; + if ($cidr == 24) { + $slist[0][] = "{$ix[5]}"; + } elseif ($cidr == 32) { + $slist[0][] = "{$ip}/32"; } else { - $next_id = count($pfb_sup_list); + $slist[0][] = "{$ip}"; } - $pfb_sup_array[$next_id]['host'] = $ip . '/' . $cidr; - $pfb_sup_array[$next_id]['detail'] = $descr; - - $address = ""; - $detail = ""; - foreach ($pfb_sup_array as $pfb_sup) { - $address .= $pfb_sup['host'] . " "; - $detail .= $pfb_sup['detail'] . "||"; + $slist[1][] = $descr; + + // Sort suppress list and save + array_multisort($slist[0], SORT_ASC, SORT_NUMERIC, $slist[1]); + $config['aliases']['alias'][$pfb_key]['address'] = implode(' ', $slist[0]); + $config['aliases']['alias'][$pfb_key]['detail'] = implode('||', $slist[1]); + $savemsg = gettext($savemsg1) . gettext($savemsg2) . gettext(' and added Host to the pfBlockerNG Suppress Table.'); + $pfbupdate = TRUE; + } + + if ($pfbupdate) { + // Save Suppress alias changes to pfSense config file + write_config("pfBlockerNG: Added {$ip} to IP Suppress List"); + } + } + } +} + +// Add domain to the suppression list +if (isset($_POST['addsuppressdom'])) { + $domain = htmlspecialchars($_POST['domain']); + $domainparse = str_replace('.', '\.', $domain); + $pfb['dsupp'] = &$config['installedpackages']['pfblockerngdnsblsettings']['config'][0]['suppression']; + + // Collect existing suppression list + $dnssupp_ex = collectsuppression(); + + // Query for domain in Unbound DNSBL file. + $dnsbl_query = exec("/usr/bin/grep -Hm1 ' \"{$domain} 60 IN A' {$pfb['dnsbl_file']}.conf"); + + // Save new suppress domain to suppress list. + if (empty($dnsbl_query)) { + $savemsg = gettext("Domain: [ {$domain} ] does not exist in the Unbound Resolver DNSBL"); + exec("/usr/local/sbin/unbound-control -c {$pfb['dnsbldir']}/unbound.conf flush {$domain}."); + } else { + // Remove domain from Unbound resolver pfb_dnsbl.conf file + exec("{$pfb['sed']} -i '' '/ \"{$domain} 60 IN A/d' {$pfb['dnsbl_file']}.conf"); + + $cache_dumpfile = '/var/tmp/unbound_cache'; + unlink_if_exists("{$cache_dumpfile}"); + $chroot_cmd = "chroot -u unbound -g unbound / /usr/local/sbin/unbound-control -c {$g['unbound_chroot_path']}/unbound.conf"; + + exec("{$chroot_cmd} dump_cache > $cache_dumpfile"); + exec("{$chroot_cmd} reload"); + + if (file_exists($cache_dumpfile) && filesize($cache_dumpfile) > 0) { + exec("{$chroot_cmd} load_cache < $cache_dumpfile"); + } + + exec("/usr/local/sbin/unbound-control -c {$pfb['dnsbldir']}/unbound.conf flush {$domain}"); + + if (!in_array($domain, $dnssupp_ex)) { + $dnssupp_ex[] = $domain; + $dnssupp_new = base64_encode(implode("\n", $dnssupp_ex)); + $pfb['dsupp'] = "{$dnssupp_new}"; + write_config("pfBlockerNG: Added {$domain} to DNSBL suppress list"); + } + $savemsg = gettext("Removed Domain: [ {$domain} ] from Unbound Resolver DNSBL. You may need to flush your browsers DNS Cache"); + } +} + +// Collect pfBlockerNG rule names and tracker ids +$rule_list = array(); +exec("{$pfb['pfctl']} -vv -sr | {$pfb['grep']} 'pfB_'", $results); +if (!empty($results)) { + foreach ($results as $result) { + + // Find rule tracker ids + $id = strstr($result, '(', FALSE); + $id = ltrim(strstr($id, ')', TRUE), '('); + + // Find rule descriptions + $descr = ltrim(stristr($result, '<pfb_', FALSE), '<'); + $descr = strstr($descr, ':', TRUE); + + // Create array of rule description and tracker id + $rule_list['id'][] = $id; + $rule_list[$id]['name'] = $descr; + } +} + +// Define common variables and arrays for report tables +$fields_array = $pfb_local = $pfb_localsub = $dnsbl_int = $local_hosts = array(); + +$pfblines = exec("/usr/local/sbin/clog {$filter_logfile} | {$pfb['grep']} -c ^"); +$fields_array = conv_log_filter_lite($filter_logfile, $pfblines, $pfblines, $pfbdenycnt, $pfbpermitcnt, $pfbmatchcnt); +$continents = array('pfB_Africa', 'pfB_Antartica', 'pfB_Asia', 'pfB_Europe', 'pfB_NAmerica', 'pfB_Oceania', 'pfB_SAmerica', 'pfB_Top'); + +$supp_ip_txt = "Clicking this Suppression Icon, will immediately remove the block.\n\nSuppressing a /32 CIDR is better than suppressing the full /24"; +$supp_ip_txt .= " CIDR.\nThe Host will be added to the pfBlockerNG suppress alias table.\n\nOnly 32 or 24 CIDR IPs can be suppressed with the '+' icon."; +$supp_ip_txt .= "\nTo manually add host(s), edit the 'pfBlockerNGSuppress' alias in the alias Tab.\nManual entries will not remove existing blocked hosts"; + +// Collect gateway IP addresses for inbound/outbound list matching +$int_gateway = get_interfaces_with_gateway(); +if (isset($int_gateway)) { + foreach ($int_gateway as $gateway) { + $convert = get_interface_ip($gateway); + $pfb_local[] = $convert; + } +} + +// Collect virtual IP aliases for inbound/outbound list matching +if (isset($config['virtualip']['vip'])) { + foreach ($config['virtualip']['vip'] as $list) { + if (!empty($list['subnet']) && !empty($list['subnet_bits'])) { + if ($list['subnet_bits'] >= 24) { + $pfb_local = array_merge(subnetv4_expand("{$list['subnet']}/{$list['subnet_bits']}"), $pfb_local); + } else { + $pfb_localsub[] = "{$list['subnet']}/{$list['subnet_bits']}"; + } + + // Collect VIP for Alerts hostlookup + $local_hosts[$list['subnet']] = strtolower("{$list['descr']}"); + } + } +} + +// Collect NAT IP addresses for inbound/outbound list matching +if (isset($config['nat']['rule'])) { + foreach ($config['nat']['rule'] as $natent) { + $pfb_local[] = $natent['target']; + + // Collect NAT for Alerts hostlookup + $local_hosts[$natent['target']] = strtolower("{$natent['descr']}"); + } +} + +// Collect 1:1 NAT IP addresses for inbound/outbound list matching +if (isset($config['nat']['onetoone'])) { + foreach ($config['nat']['onetoone'] as $onetoone) { + $pfb_local[] = $onetoone['source']['address']; + } +} + +// Convert any 'Firewall Aliases' to IP address format +if (isset($config['aliases']['alias'])) { + for ($cnt = 0; $cnt <= count($pfb_local); $cnt++) { + foreach ($config['aliases']['alias'] as $i=> $alias) { + if (isset($alias['name']) && isset($pfb_local[$cnt])) { + if ($alias['name'] == $pfb_local[$cnt]) { + $pfb_local[$cnt] = $alias['address']; } + } + } + } +} - // Find pfBlockerNGSuppress Array ID Number - if (is_array($config['aliases']['alias'])) { - $pfb_id = 0; - foreach ($config['aliases']['alias'] as $alias) { - if ($alias['name'] == "pfBlockerNGSuppress") { - break; - } - $pfb_id++; - } +// Collect all interface addresses for inbound/outbound list matching +if (isset($config['interfaces'])) { + foreach ($config['interfaces'] as $int) { + if ($int['ipaddr'] != 'dhcp') { + if (!empty($int['ipaddr']) && !empty($int['subnet'])) { + if ($int['subnet'] >= 24) { + $pfb_local = array_merge(subnetv4_expand("{$int['ipaddr']}/{$int['subnet']}"), $pfb_local); + } else { + $pfb_localsub[] = "{$int['ipaddr']}/{$int['subnet']}"; } - $config['aliases']['alias'][$pfb_id]['address'] = rtrim($address, " "); - $config['aliases']['alias'][$pfb_id]['detail'] = rtrim($detail, "||"); - $savemsg = gettext($savemsg1) . gettext($savemsg2) . gettext(" and added Host to the pfBlockerNG Suppress Table."); - $pfb['update'] = TRUE; + // Collect DNSBL Interfaces + $dnsbl_int[] = array("{$int['ipaddr']}/{$int['subnet']}", "{$int['descr']}"); + + } + } + } +} + +// Remove any duplicate IPs +$pfb_local = array_unique($pfb_local); +$pfb_localsub = array_unique($pfb_localsub); + +// Collect DHCP hostnames/IPs +$local_hosts = array(); + +// Collect dynamic DHCP hostnames/IPs +$leasesfile = "{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases"; +if (file_exists("{$leasesfile}")) { + $leases = file("{$leasesfile}"); + if (!empty($leases)) { + foreach ($leases as $line) { + if (strpos($line, '{') !== FALSE) { + $end = FALSE; + $data = explode(' ', $line); + $ip = $data[1]; + } + if (strpos($line, 'client-hostname') !== FALSE) { + $data = explode(' ', $line); + $hostname = str_replace(array('"', ';'), '', $data[3]); + } + if (strpos($line, '}') !== FALSE) { + $end = TRUE; } + if ($end) { + if (!empty($ip) && !empty($hostname)) { + $local_hosts[$ip] = $hostname; + } + $ip = $hostname = ''; + } + } + } +} - if ($pfb['found'] || $pfb['update']) { - // Save all Changes to pfsense config file - write_config("pfBlockerNG: Added {$ip} to IP Suppress List"); +// Collect static DHCP hostnames/IPs +if (isset($config['dhcpd'])) { + foreach ($config['dhcpd'] as $dhcp) { + if (isset($dhcp['staticmap'])) { + foreach ($dhcp['staticmap'] as $smap) { + $local_hosts[$smap['ipaddr']] = strtolower("{$smap['hostname']}"); } } } } +// Collect Unbound Host overrides +$hosts = $config['unbound']['hosts']; +if (isset($hosts)) { + foreach ($hosts as $host) { + $local_hosts[$host['ip']] = strtolower("{$host['descr']}"); + } +} + +// Collect configured pfSense interfaces +$pf_int = get_configured_ip_addresses(); +if (isset($pf_int)) { + $local_hosts = array_merge($local_hosts, array_flip(array_filter($pf_int))); +} +$pf_int = get_configured_ipv6_addresses(); +if (isset($pf_int)) { + $local_hosts = array_merge($local_hosts, array_flip(array_filter($pf_int))); +} + +// FUNCTION DEFINITIONS + + +// Collect existing suppression list +function collectsuppression() { + global $pfb; + $dnssupp_ex = array(); + + $custom_list = pfbng_text_area_decode($pfb['dnsblconfig']['suppression']); + if (!empty($custom_list)) { + $dnssupp_ex = array_filter( explode("\n", pfbng_text_area_decode($pfb['dnsblconfig']['suppression']))); + } + return ($dnssupp_ex); +} + -// Host Resolve Function lookup -function getpfbhostname($type = 'src', $hostip, $countme = 0) { - $hostnames['src'] = ''; - $hostnames['dst'] = ''; - $hostnames[$type] = '<div id="gethostname_' . $countme . '" name="' . $hostip . '"></div>'; +// Host resolve function lookup +function getpfbhostname($type = 'src', $hostip, $countme = 0, $host) { + global $local_hosts; + + $hostnames['src'] = $hostnames['dst'] = ''; + $hostnames[$type] = "<div id='gethostname_{$countme}' name='{$hostip}'></div>"; + + // Report DHCP hostnames if found. + if (isset($local_hosts[$host])) { + if ($type == 'src') { + $hostnames['dst'] = $local_hosts[$host]; + } else { + $hostnames['src'] = $local_hosts[$host]; + } + } return $hostnames; } -// For subnet addresses - Determine if Alert Host 'Dest' is within a Local IP Range. +// Function to Filter Alerts report on user defined input +function pfb_match_filter_field($flent, $fields) { + if (isset($fields)) { + foreach ($fields as $key => $field) { + if (empty($field)) { + continue; + } + + if (strpos($field, '!') !== FALSE) { + $field = substr($field, 1); + $field_regex = str_replace('/', '\/', str_replace('\/', '/', $field)); + if (@preg_match("/{$field_regex}/i", $flent[$key])) { + return FALSE; + } + } + else { + $field_regex = str_replace('/', '\/', str_replace('\/', '/', $field)); + if (!@preg_match("/{$field_regex}/i", $flent[$key])) { + return FALSE; + } + } + } + } + return TRUE; +} + + +// For subnet addresses - Determine if alert host 'dest' is within a local IP range. function ip_in_pfb_localsub($subnet) { global $pfb_localsub; if (!empty($pfb_localsub)) { foreach ($pfb_localsub as $line) { if (ip_in_subnet($subnet, $line)) { - return true; + return TRUE; } } } - return false; + return FALSE; } -// Parse Filter log for pfBlockerNG Alerts +// Parse filter log for pfBlockerNG alerts function conv_log_filter_lite($logfile, $nentries, $tail, $pfbdenycnt, $pfbpermitcnt, $pfbmatchcnt) { global $pfb, $rule_list, $filterfieldsarray; $fields_array = array(); - $logarr = ""; - $denycnt = 0; - $permitcnt = 0; - $matchcnt = 0; + $denycnt = $permitcnt = $matchcnt = 0; + $logarr = ''; if (file_exists($logfile)) { - exec("/usr/local/sbin/clog " . escapeshellarg($logfile) . " | grep -v \"CLOG\" | grep -v \"\033\" | /usr/bin/grep 'filterlog:' | /usr/bin/tail -r -n {$tail}", $logarr); + // Collect filter.log entries + exec("/usr/local/sbin/clog {$logfile} | {$pfb['grep']} -v '\"CLOG\"\|\"\033\"' | {$pfb['grep']} 'filterlog:' | /usr/bin/tail -r -n {$tail}", $logarr); + } else { + return; } - else return; if (!empty($logarr) && !empty($rule_list['id'])) { foreach ($logarr as $logent) { - $pfbalert = array(); - $log_split = ""; - if (!preg_match("/(.*)\s(.*)\sfilterlog:\s(.*)$/", $logent, $log_split)) { - continue; + $pfbalert = array(); + $flog = explode(' ', $logent); + // Remove 'extra space' from single date entry (days 1-9) + if (empty($flog[1])) { + array_splice($flog, 1, 1); } + $rule_data = explode(',', $flog[5]); - list($all, $pfbalert[99], $host, $rule) = $log_split; - $rule_data = explode(",", $rule); - $pfbalert[0] = $rule_data[0]; // Rulenum - - // Skip Alert if Rule is not a pfBNG Alert - if (!in_array($pfbalert[0], $rule_list['id'])) { + // Skip alert if rule is not a pfBNG alert + if (!in_array($rule_data[3], $rule_list['id'])) { continue; } - $pfbalert[1] = $rule_data[4]; // Realint - $pfbalert[3] = $rule_data[6]; // Act - $pfbalert[4] = $rule_data[8]; // Version + $pfbalert[0] = $rule_data[3]; // Rulenum + $pfbalert[1] = $rule_data[4]; // Realint + $pfbalert[3] = $rule_data[6]; // Act + $pfbalert[4] = $rule_data[8]; // Version - if ($pfbalert[4] == "4") { + if ($pfbalert[4] == 4) { $pfbalert[5] = $rule_data[15]; // Protocol ID $pfbalert[6] = $rule_data[16]; // Protocol $pfbalert[7] = $rule_data[18]; // SRC IP @@ -442,104 +588,106 @@ function conv_log_filter_lite($logfile, $nentries, $tail, $pfbdenycnt, $pfbpermi $pfbalert[11] = $rule_data[20]; // TCP Flags } - if ($pfbalert[5] == "6" || $pfbalert[5] == "17") { + if ($pfbalert[5] == 6 || $pfbalert[5] == 17) { // skip } else { - $pfbalert[9] = ""; - $pfbalert[10] = ""; - $pfbalert[11] = ""; + $pfbalert[9] = $pfbalert[10] = $pfbalert[11] = ''; } - // Skip Repeated Alerts - if (($pfbalert[1] . $pfbalert[3] . $pfbalert[7] . $pfbalert[8] . $pfbalert[10]) == $previous_alert) { + $pfbalert[99] = "{$flog[0]} {$flog[1]} {$flog[2]}"; // Date/Timestamp + + // Skip repeated alerts + if ("{$pfbalert[1]}{$pfbalert[3]}{$pfbalert[7]}{$pfbalert[8]}{$pfbalert[10]}" == $previous_alert) { continue; } $pfbalert[2] = convert_real_interface_to_friendly_descr($rule_data[4]); // Friendly Interface Name - $pfbalert[6] = str_replace("TCP", "TCP-", strtoupper($pfbalert[6]), $pfbalert[6]) . $pfbalert[11]; // Protocol Flags + $pfbalert[6] = str_replace('TCP', 'TCP-', strtoupper($pfbalert[6]), $pfbalert[6]) . $pfbalert[11]; // Protocol Flags - // If Alerts Filtering is selected, process Filters as required. + // If alerts filtering is selected, process filters as required. if ($pfb['filterlogentries'] && !pfb_match_filter_field($pfbalert, $filterfieldsarray)) { continue; } - if ($pfbalert[3] == "block") { + if ($pfbalert[3] == 'block') { if ($denycnt < $pfbdenycnt) { $fields_array['Deny'][] = $pfbalert; $denycnt++; } } - elseif ($pfbalert[3] == "pass") { + elseif ($pfbalert[3] == 'pass') { if ($permitcnt < $pfbpermitcnt) { $fields_array['Permit'][] = $pfbalert; $permitcnt++; } } - elseif ($pfbalert[3] == "unkn(%u)" || $pfbalert[3] == "unkn(11)") { + elseif ($pfbalert[3] == 'unkn(%u)') { if ($matchcnt < $pfbmatchcnt) { $fields_array['Match'][] = $pfbalert; $matchcnt++; } } - // Exit function if Sufficinet Matches found. + // Exit function if sufficinet matches found. if ($denycnt >= $pfbdenycnt && $permitcnt >= $pfbpermitcnt && $matchcnt >= $pfbmatchcnt) { - unset ($pfbalert, $logarr); + unset($pfbalert, $logarr); return $fields_array; } - // Collect Details for Repeated Alert Comparison - $previous_alert = $pfbalert[1] . $pfbalert[3] . $pfbalert[7] . $pfbalert[8] . $pfbalert[10]; + // Collect details for repeated alert comparison + $previous_alert = "{$pfbalert[1]}{$pfbalert[3]}{$pfbalert[7]}{$pfbalert[8]}{$pfbalert[10]}"; } - unset ($pfbalert, $logarr); + unset($pfbalert, $logarr); return $fields_array; } } -$pgtitle = gettext("pfBlockerNG: Alerts"); -include_once("head.inc"); + +$pgtitle = gettext('pfBlockerNG: Alerts'); +include_once('head.inc'); ?> <body link="#000000" vlink="#0000CC" alink="#000000"> -<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post"> +<form action="/pfblockerng/pfblockerng_alerts.php" method="post"> <input type="hidden" name="ip" id="ip" value=""/> <input type="hidden" name="table" id="table" value=""/> <input type="hidden" name="descr" id="descr" value=""/> <input type="hidden" name="cidr" id="cidr" value=""/> +<input type="hidden" name="domain" id="domain" value=""/> <?php -include_once("fbegin.inc"); +include_once('fbegin.inc'); -/* refresh every 60 secs */ +// refresh every 60 secs if ($alertrefresh == 'on') { - echo "<meta http-equiv=\"refresh\" content=\"60;url={$_SERVER['PHP_SELF']}\" />\n"; + if ($pfb['filterlogentries']) { + // Refresh page with 'Filter options' if defined. + $refreshentries = urlencode(serialize($filterfieldsarray)); + echo "<meta http-equiv=\"refresh\" content=\"60;url=/pfblockerng/pfblockerng_alerts.php?refresh={$refreshentries}\" />\n"; + } else { + echo "<meta http-equiv=\"refresh\" content=\"60;url=/pfblockerng/pfblockerng_alerts.php\" />\n"; + } } if ($savemsg) { print_info_box($savemsg); } -$skipcount = 0; $counter = 0; +$skipcount = $counter = $resolvecounter = 0; ?> <table width="100%" border="0" cellpadding="0" cellspacing="0"> <tr> <td> <?php $tab_array = array(); - $tab_array[] = array(gettext("General"), false, "/pkg_edit.php?xml=pfblockerng.xml&id=0"); + $tab_array[] = array(gettext("General"), false, "/pkg_edit.php?xml=pfblockerng.xml"); $tab_array[] = array(gettext("Update"), false, "/pfblockerng/pfblockerng_update.php"); $tab_array[] = array(gettext("Alerts"), true, "/pfblockerng/pfblockerng_alerts.php"); - $tab_array[] = array(gettext("Reputation"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml&id=0"); + $tab_array[] = array(gettext("Reputation"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml"); $tab_array[] = array(gettext("IPv4"), false, "/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml"); $tab_array[] = array(gettext("IPv6"), false, "/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml"); - $tab_array[] = array(gettext("Top 20"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml&id=0"); - $tab_array[] = array(gettext("Africa"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_Africa.xml&id=0"); - $tab_array[] = array(gettext("Asia"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_Asia.xml&id=0"); - $tab_array[] = array(gettext("Europe"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_Europe.xml&id=0"); - $tab_array[] = array(gettext("N.A."), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_NorthAmerica.xml&id=0"); - $tab_array[] = array(gettext("Oceania"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_Oceania.xml&id=0"); - $tab_array[] = array(gettext("S.A."), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_SouthAmerica.xml&id=0"); - $tab_array[] = array(gettext("P.S."), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_ProxyandSatellite.xml&id=0"); + $tab_array[] = array(gettext("DNSBL"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl.xml"); + $tab_array[] = array(gettext("Country"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml"); $tab_array[] = array(gettext("Logs"), false, "/pfblockerng/pfblockerng_log.php"); - $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml&id=0"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml"); display_top_tabs($tab_array, true); ?> </td> @@ -558,24 +706,29 @@ $skipcount = 0; $counter = 0; <td width="90%" class="vtable"> <input name="pfbdenycnt" type="text" class="formfld unknown" id="pdbdenycnt" size="1" title="Enter the number of 'Deny' Alerts to Show" value="<?=htmlspecialchars($pfbdenycnt);?>"/> - <?php printf(gettext('%sDeny%s. ') , '<strong>', '</strong>'); ?> + <?php printf(gettext('%sDeny%s. ') , '<strong>', '</strong>'); ?> + <?php if ($pfb['dnsbl'] == "on"): ?> + <input name="pfbdnscnt" type="text" class="formfld unknown" id="pdbdnscnt" size="1" + title="Enter the number of 'DNSBL' Alerts to Show" value="<?=htmlspecialchars($pfbdnscnt);?>"/> + <?php printf(gettext('%sDNSBL%s. ') , '<strong>', '</strong>'); ?> + <?php endif; ?> <input name="pfbpermitcnt" type="text" class="formfld unknown" id="pdbpermitcnt" size="1" title="Enter the number of 'Permit' Alerts to Show" value="<?=htmlspecialchars($pfbpermitcnt);?>"/> - <?php printf(gettext('%sPermit%s. '), '<strong>', '</strong>'); ?> + <?php printf(gettext('%sPermit%s. '), '<strong>', '</strong>'); ?> <input name="pfbmatchcnt" type="text" class="formfld unknown" id="pdbmatchcnt" size="1" title="Enter the number of 'Match' Alerts to Show" value="<?=htmlspecialchars($pfbmatchcnt); ?>"/> <?php printf(gettext('%sMatch%s.'), '<strong>', '</strong>'); ?> - <?php echo gettext(' Click to Auto-Refresh');?> <input name="alertrefresh" type="checkbox" value="on" + <?php echo gettext(' Auto-Refresh');?> <input name="alertrefresh" type="checkbox" value="on" title="Click to enable Auto-Refresh of this Tab once per minute" <?php if ($config['installedpackages']['pfblockerngglobal']['alertrefresh']=="on") echo "checked"; ?>/> - <?php echo gettext(' Click to Auto-Resolve');?> <input name="hostlookup" type="checkbox" value="on" + <?php echo gettext(' Auto-Resolve');?> <input name="hostlookup" type="checkbox" value="on" title="Click to enable Auto-Resolve of Hostnames. Country Blocks/Permit/Match Lists will not auto-resolve" - <?php if ($config['installedpackages']['pfblockerngglobal']['hostlookup']=="on") echo "checked"; ?>/> + <?php if ($config['installedpackages']['pfblockerngglobal']['hostlookup']=="on") echo "checked"; ?>/>  <input name="save" type="submit" class="formbtns" value="Save" title="<?=gettext('Save settings');?>"/><br /> - <?php printf(gettext('Enter number of log entries to view.')); ?> + <?php printf(gettext('Enter number of log entries to view.')); ?>  <?php printf(gettext("Currently Suppressing %s$pfbsupp_cnt%s Hosts."), '<strong>', '</strong>');?> </td> </tr> @@ -587,7 +740,7 @@ $skipcount = 0; $counter = 0; <td width="90%" class="vtable"> <input name="show_filter" id="show_filter" type="button" class="formbtns" value="<?=gettext("Show Filter");?>" onclick="enable_showFilter();" /> - <?=gettext("Click to display advanced filtering options dialog");?> +  <?=gettext("Click to display advanced filtering options dialog");?> </td> </tr> <tr id="filter_options_row" style="display:<?php if (!$pfb['filterlogentries']) {echo "none;";} else {echo "table-row;";} ?>"> @@ -622,7 +775,7 @@ $skipcount = 0; $counter = 0; type="text" size="15" value="<?= $filterfieldsarray[0] ?>" /></div> </td> <td valign="top"> - <div align="center"><?=gettext("Destination IP Address");?></div> + <div align="center"><?=gettext("Destination IP Address/Domain Name");?></div> <div align="center"><input id="filterlogentries_dstip" name="filterlogentries_dstip" class="formfld search" type="text" size="28" value="<?= $filterfieldsarray[8] ?>" /></div> </td> @@ -640,10 +793,30 @@ $skipcount = 0; $counter = 0; </td> </tr> + + <?php if ($pfb['dnsbl'] == 'on'): ?> + <tr> + <td valign="top"> + <div align="center"><?=gettext("DNSBL URL");?></div> + <div align="center"><input id="filterlogentries_dnsbl" name="filterlogentries_dnsbl" + class="formfld search" type="text" size="15" value="<?= $filterfieldsarray[90] ?>" /></div> + </td> + <td valign="top" colspan="3"> + + </td> + </tr> + <?php else: ?> + <tr> + <td valign="top" colspan="3"> + + </td> + </tr> + <?php endif; ?> + <tr> <td colspan="3" style="vertical-align:bottom"> <br /><?printf(gettext('Regex Style Matching Only! %1$s Regular Expression Help link%2$s.'), ' - <a target="_blank" href="http://www.php.net/manual/en/book.pcre.php">', '</a>');?> + <a target="_blank" href="http://www.php.net/manual/en/book.pcre.php">', '</a>');?>  <?=gettext("Precede with exclamation (!) as first character to exclude match.) ");?> <br /><?printf(gettext("Example: ( ^80$ - Match Port 80, ^80$|^8080$ - Match both port 80 & 8080 ) "));?><br /> </td> @@ -652,9 +825,9 @@ $skipcount = 0; $counter = 0; <td colspan="3" style="vertical-align:bottom"> <div align="left"><input id="filterlogentries_submit" name="filterlogentries_submit" type="submit" class="formbtns" value="<?=gettext("Apply Filter");?>" title="<?=gettext("Apply filter"); ?>" /> - <input id="filterlogentries_clear" name="filterlogentries_clear" type="submit" +  <input id="filterlogentries_clear" name="filterlogentries_clear" type="submit" class="formbtns" value="<?=gettext("Clear");?>" title="<?=gettext("Remove filter");?>" /> - <input id="filterlogentries_hide" name="filterlogentries_hide" type="button" +  <input id="filterlogentries_hide" name="filterlogentries_hide" type="button" class="formbtns" value="<?=gettext("Hide");?>" onclick="enable_hideFilter();" title="<?=gettext("Hide filter options");?>" /></div> </td> @@ -663,166 +836,236 @@ $skipcount = 0; $counter = 0; </td> </tr> -<!--Create Three Output Windows 'Deny', 'Permit' and 'Match'--> -<?php foreach (array ( "Deny" => $pfb['denydir'] . " " . $pfb['nativedir'], "Permit" => $pfb['permitdir'], "Match" => $pfb['matchdir']) as $type => $pfbfolder ): +<!--Create three output windows 'Deny', 'DNSBL', 'Permit' and 'Match'--> +<?php foreach (array ( 'Deny' => "{$pfb['denydir']}/* {$pfb['nativedir']}/*", + 'DNSBL' => "{$pfb['dnsdir']}", + 'Permit' => "{$pfb['permitdir']}/* {$pfb['nativedir']}/*", + 'Match' => "{$pfb['matchdir']}/* {$pfb['nativedir']}/*" ) as $type => $pfbfolder ): + switch($type) { - case "Deny": - $rtype = "block"; + case 'Deny': + $rtype = 'block'; $pfbentries = "{$pfbdenycnt}"; break; - case "Permit": - $rtype = "pass"; + case 'Permit': + $rtype = 'pass'; $pfbentries = "{$pfbpermitcnt}"; break; - case "Match": - $rtype = "unkn(%u)"; + case 'Match': + $rtype = 'unkn(%u)'; $pfbentries = "{$pfbmatchcnt}"; break; + case 'DNSBL': + $pfbentries = "{$pfbdnscnt}"; } - // Skip Table output if $pfbentries is zero. - if ($pfbentries == 0 && $skipcount != 2) { + // Skip table output if $pfbentries is zero. + if ($pfbentries == 0 && $skipcount != 3) { $skipcount++; continue; } + + // Print alternating line shading + $alertRowEvenClass = "style='background-color: #D8D8D8;'"; + $alertRowOddClass = "style='background-color: #E8E8E8;'"; ?> <table id="maintable" class="tabcont" width="100%" border="0" cellspacing="0" cellpadding="6"> <tr> - <!--Print Table Info--> - <td colspan="2" class="listtopic"><?php printf(gettext(" {$type} - Last %s Alert Entries."),"{$pfbentries}"); ?> - <?php if ($type == "Deny"): ?> - <?php echo gettext("Firewall Rule changes can unsync these Alerts."); ?> - <?php endif; ?> + <!--Print table info--> + <td colspan="2" class="listtopic"> + <?php printf(gettext(" {$type}  - Last %s Alert Entries."),"{$pfbentries}"); ?> </td> </tr> <td width="100%" colspan="2"> <table id="pfbAlertsTable" style="table-layout: fixed;" width="100%" class="sortable" border="0" cellpadding="0" cellspacing="0"> + +<?php +// Process dns array for: DNSBL and generate output +if ($pfb['dnsbl'] == 'on' && $type == 'DNSBL') { +?> + <colgroup> - <col width="7%" align="center" axis="date"> - <col width="6%" align="center" axis="string"> - <col width="15%" align="center" axis="string"> - <col width="6%" align="center" axis="string"> - <col width="21%" align="center" axis="string"> - <col width="21%" align="center" axis="string"> - <col width="3%" align="center" axis="string"> - <col width="13%" align="center" axis="string"> + <col width="8%" align="center" axis="date"> + <col width="7%" align="center" axis="string"> + <col width="12%" align="center" axis="string"> + <col width="59%" align="center" axis="string"> + <col width="14%" align="center" axis="string"> </colgroup> <thead> <tr class="sortableHeaderRowIdentifier"> <th class="listhdrr" axis="date"><?php echo gettext("Date"); ?></th> <th class="listhdrr" axis="string"><?php echo gettext("IF"); ?></th> - <th class="listhdrr" axis="string"><?php echo gettext("Rule"); ?></th> - <th class="listhdrr" axis="string"><?php echo gettext("Proto"); ?></th> <th class="listhdrr" axis="string"><?php echo gettext("Source"); ?></th> - <th class="listhdrr" axis="string"><?php echo gettext("Destination"); ?></th> - <th class="listhdrr" axis="string"><?php echo gettext("CC"); ?></th> + <th class="listhdrr" axis="string"><?php echo gettext("Domain/Referer|URI|Agent"); ?></th> <th class="listhdrr" axis="string"><?php echo gettext("List"); ?></th> </tr> </thead> <tbody> -<?php -$pfb['runonce'] = TRUE; -if (isset($pfb['load'])) { - $pfb['runonce'] = FALSE; -} - -// Execute the following once per refresh -if ($pfb['runonce']) { - $pfb['load'] = TRUE; - $resolvecounter = 0; - $fields_array = array(); - - $pfblines = exec("/usr/local/sbin/clog {$filter_logfile} | /usr/bin/grep -c ^"); - $fields_array = conv_log_filter_lite($filter_logfile, $pfblines, $pfblines, $pfbdenycnt, $pfbpermitcnt, $pfbmatchcnt); - $continents = array('pfB_Africa','pfB_Antartica','pfB_Asia','pfB_Europe','pfB_NAmerica','pfB_Oceania','pfB_SAmerica','pfB_Top'); - - $supp_ip_txt = "Clicking this Suppression Icon, will immediately remove the Block.\n\nSuppressing a /32 CIDR is better than Suppressing the full /24"; - $supp_ip_txt .= " CIDR.\nThe Host will be added to the pfBlockerNG Suppress Alias Table.\n\nOnly 32 or 24 CIDR IPs can be Suppressed with the '+' Icon."; - $supp_ip_txt .= "\nTo manually add Host(s), edit the 'pfBlockerNGSuppress' Alias in the Alias Tab.\nManual entries will not remove existing Blocked Hosts"; - - // Array of all Local IPs for Alert Analysis - $pfb_local = array(); - $pfb_localsub = array(); - - // Collect Gateway IP Addresses for Inbound/Outbound List matching - $int_gateway = get_interfaces_with_gateway(); - if (is_array($int_gateway)) { - foreach ($int_gateway as $gateway) { - $convert = get_interface_ip($gateway); - $pfb_local[] = $convert; - } - } +<?php + $dns_array = $final = array(); + if (file_exists("{$pfb['dnslog']}")) { + if (($handle = fopen("{$pfb['dnslog']}", 'r')) !== FALSE) { + while (($line = fgetcsv($handle)) !== FALSE) { + + // Define missing data for HTTPS alerts + if ($line[0] == 'DNSBL Reject HTTPS') { + $line[3] = '<small>Unknown</small>'; + $line[4] = ' Not available for HTTPS alerts'; + } - // Collect Virtual IP Aliases for Inbound/Outbound List Matching - if (is_array($config['virtualip']['vip'])) { - foreach ($config['virtualip']['vip'] as $list) { - if ($list['subnet'] != "" && $list['subnet_bits'] != "") { - if ($list['subnet_bits'] >= 24) { - $pfb_local = array_merge(subnetv4_expand("{$list['subnet']}/{$list['subnet_bits']}"), $pfb_local); - } else { - $pfb_localsub[] = "{$list['subnet']}/{$list['subnet_bits']}"; + // Remove duplicate domain/srcips + if (("{$line[2]}{$line[3]}") != $pdomain) { + $final[] = $line; } + $pdomain = "{$line[2]}{$line[3]}"; } } - } + fclose($handle); - // Collect NAT IP Addresses for Inbound/Outbound List Matching - if (is_array($config['nat']['rule'])) { - foreach ($config['nat']['rule'] as $natent) { - $pfb_local[] = $natent['target']; + if (!empty($final)) { + $dns_array = array_slice(array_reverse($final), 0, $pfbentries); } } - // Collect 1:1 NAT IP Addresses for Inbound/Outbound List Matching - if (is_array($config['nat']['onetoone'])) { - foreach ($config['nat']['onetoone'] as $onetoone) { - $pfb_local[] = $onetoone['source']['address']; - } - } + if (!empty($dns_array)) { - // Convert any 'Firewall Aliases' to IP Address Format - if (is_array($config['aliases']['alias'])) { - for ($cnt = 0; $cnt <= count($pfb_local); $cnt++) { - foreach ($config['aliases']['alias'] as $i=> $alias) { - if (isset($alias['name']) && isset($pfb_local[$cnt])) { - if ($alias['name'] == $pfb_local[$cnt]) { - $pfb_local[$cnt] = $alias['address']; + $supp_dom_txt = "Clicking this Suppression icon, will immediately remove the blocked domain from Unbound Resolver.\n\n"; + $supp_dom_txt .= "To manually add Domain(s), edit the 'Domain Suppression' list in the DNSBL tab.\n"; + $supp_dom_txt .= "Manual entries will not immediatelty remove existing blocked hosts."; + + foreach ($dns_array as $aline) { + + // Determine interface name based on Source IP address + $pfbalertdnsbl[1] = 'LAN'; // Define LAN Interface as 'default' + if (!empty($dnsbl_int)) { + foreach ($dnsbl_int as $subnet) { + if (strpos($aline[3], 'Unknown') !== FALSE) { + $pfbalertdnsbl[1] = 'Unknown'; + break; + } elseif (ip_in_subnet($aline[3], $subnet[0])) { + $pfbalertdnsbl[1] = "{$subnet[1]}"; + break; } } } - } - } - // Collect all Interface Addresses for Inbound/Outbound List Matching - if (is_array($config['interfaces'])) { - foreach ($config['interfaces'] as $int) { - if ($int['ipaddr'] != "dhcp") { - if ($int['ipaddr'] != "" && $int['subnet'] != "") { - if ($int['subnet'] >= 24) { - $pfb_local = array_merge(subnetv4_expand("{$int['ipaddr']}/{$int['subnet']}"), $pfb_local); - } else { - $pfb_localsub[] = "{$int['ipaddr']}/{$int['subnet']}"; - } - } + $pfbalertdnsbl[99] = $aline[1]; // Timestamp + + // SRC IP Address and Hostname + if (isset($local_hosts[$aline[3]])) { + $pfbalertdnsbl[7] = "{$aline[3]}<br /><small>{$local_hosts[$aline[3]]}</small>"; + } else { + $pfbalertdnsbl[7] = $aline[3]; } + + $pfbalertdnsbl[8] = $aline[2]; // Blocked Domain + $pfbalertdnsbl[90] = $aline[4]; // DNSBL URL + + // Add 'https' icon to Domains as required. + $pfb_https = ''; + if (strpos($aline[4], 'https://') !== FALSE || strpos($aline[4], 'Not available for HTTPS alerts') !== FALSE) { + $pfb_https = "<img src=\"/themes/{$g['theme']}/images/icons/icon_frmfld_pwd.png\" alt='' width='11' height='11' border='0' + title='HTTPS alerts are not fully logged due to Browser security' />"; + } + + // If alerts filtering is selected, process filters as required. + if ($pfb['filterlogentries'] && !pfb_match_filter_field($pfbalertdnsbl, $filterfieldsarray)) { + continue; + } + + // Collect the list that contains the blocked domain + $domain = str_replace('.', '\.', $aline[2]); + $sed_cmd = "{$pfb['sed']} -e 's/^.*[a-zA-Z]\///' -e 's/:.*//' -e 's/\..*/ /'"; + $pfb_query = exec("{$pfb['grep']} -Hm1 ' \"{$domain} 60 IN A' {$pfb['dnsdir']}/* | {$sed_cmd}"); + $pfb_alias = exec("{$pfb['grep']} -Hm1 ' \"{$domain} 60 IN A' {$pfb['dnsalias']}/* | {$sed_cmd}"); + + if (empty($pfb_query)) { + $pfb_query = 'no match'; + } + + // Truncate long list names + $pfb_matchtitle = "The DNSBL Feed and Alias that blocked the indicated Domain."; + if (strlen($pfb_query) >= 17 || strlen($pfb_alias) >= 25) { + $pfb_matchtitle = "Feed: {$pfb_query} | Alias: {$pfb_alias}"; + $pfb_query = substr($pfb_query, 0, 16) . '...'; + $pfb_alias = substr($pfb_alias, 0, 24) . '...'; + } + + // Print alternating line shading + $alertRowClass = $counter % 2 ? $alertRowEvenClass : $alertRowOddClass; + + $alert_dom = "<a href='/pfblockerng/pfblockerng_threats.php?domain={$aline[2]}' title=\" " . gettext("Resolve Domain via DNS lookup"); + $alert_dom .= "\"> <img src=\"/themes/{$g['theme']}/images/icons/icon_log.gif\" width='11' height='11' border='0' "; + $alert_dom .= "alt=\"Icon Reverse Resolve with DNS\" style=\"cursor: pointer;\" /></a>"; + + // Collect existing suppression list + $dnssupp_ex = collectsuppression(); + if (!in_array($pfbalertdnsbl[8], $dnssupp_ex)) { + $supp_dom = "<input type='image' name='addsuppressdom[]' onclick=\"domainlistid('{$domain}');\" "; + $supp_dom .= "src=\"../themes/{$g['theme']}/images/icons/icon_pass_add.gif\" alt='' title=\""; + $supp_dom .= gettext($supp_dom_txt) . "\" border='0' width='11' height='11' /> "; + } + else { + $supp_dom = "<img src=\"../themes/{$g['theme']}/images/icons/icon_plus_d.gif\" alt='' border='0' width='11' height='11' "; + $supp_dom .= "title='" . gettext("This domain is already in the DNSBL Suppress List") . "' /> "; + } + + // Truncate long URLs + $url_title = ''; + if (strlen($pfbalertdnsbl[90]) >= 72) { + $url_title = "{$pfbalertdnsbl[90]}"; + $pfbalertdnsbl[90] = substr(str_replace(array('?', '-'), '', $pfbalertdnsbl[90]), 0, 69) . '...'; + } + + echo "<tr {$alertRowClass}> + <td class='listMRr' align='center'>{$pfbalertdnsbl[99]}</td> + <td class='listMRr' align='center'><small>{$pfbalertdnsbl[1]}</small></td> + <td class='listMRr' align='center'>{$pfbalertdnsbl[7]}</td> + <td class='listMRr' align='left' title='{$url_title}' sorttable_customkey='{$pfbalertdnsbl[8]}'> + {$alert_dom} {$supp_dom}{$pfbalertdnsbl[8]} {$pfb_https}<br />   <small>{$pfbalertdnsbl[90]}</small></td> + <td class='listbg' align='center' title='{$pfb_matchtitle}' style='white-space: word;'> + {$pfb_query}<br /><small>{$pfb_alias}</small></td></tr>"; + $counter++; } } +} - // Remove any Duplicate IPs - $pfb_local = array_unique($pfb_local); - $pfb_localsub = array_unique($pfb_localsub); +if ($type != 'DNSBL') { +?> + + <colgroup> + <col width="7%" align="center" axis="date"> + <col width="6%" align="center" axis="string"> + <col width="15%" align="center" axis="string"> + <col width="6%" align="center" axis="string"> + <col width="21%" align="center" axis="string"> + <col width="21%" align="center" axis="string"> + <col width="3%" align="center" axis="string"> + <col width="13%" align="center" axis="string"> + </colgroup> + <thead> + <tr class="sortableHeaderRowIdentifier"> + <th class="listhdrr" axis="date"><?php echo gettext("Date"); ?></th> + <th class="listhdrr" axis="string"><?php echo gettext("IF"); ?></th> + <th class="listhdrr" axis="string"><?php echo gettext("Rule"); ?></th> + <th class="listhdrr" axis="string"><?php echo gettext("Proto"); ?></th> + <th class="listhdrr" axis="string"><?php echo gettext("Source"); ?></th> + <th class="listhdrr" axis="string"><?php echo gettext("Destination"); ?></th> + <th class="listhdrr" axis="string"><?php echo gettext("CC"); ?></th> + <th class="listhdrr" axis="string"><?php echo gettext("List"); ?></th> + </tr> + </thead> + <tbody> + +<?php } -// Process Fields_array and generate Output -if (!empty($fields_array[$type]) && !empty($rule_list)) { - $key = 0; +// Process fields array for: Deny/Permit/Match and generate output +if (!empty($fields_array[$type]) && !empty($rule_list) && $type != 'DNSBL') { foreach ($fields_array[$type] as $fields) { - $rulenum = ""; - $alert_ip = ""; - $supp_ip = ""; - $pfb_query = ""; + $rulenum = $alert_ip = $supp_ip = $pfb_query = ''; /* Fields_array Reference [0] = Rulenum [6] = Protocol [1] = Real Interface [7] = SRC IP @@ -834,205 +1077,176 @@ if (!empty($fields_array[$type]) && !empty($rule_list)) { $rulenum = $fields[0]; if ($counter < $pfbentries) { - // Cleanup Port Output - if ($fields[6] == "ICMP" || $fields[6] == "ICMPV6") { - $srcport = ""; - $dstport = ""; + // Cleanup port output + if ($fields[6] == 'ICMP' || $fields[6] == 'ICMPV6') { + $srcport = ''; } else { - $srcport = ":" . $fields[9]; - $dstport = ":" . $fields[10]; + $srcport = ":{$fields[9]}"; + $dstport = ":{$fields[10]}"; } - // Don't add Suppress Icon to Country Block Lines + // Don't add suppress icon to Country block lines if (in_array(substr($rule_list[$rulenum]['name'], 0, -3), $continents)) { - $pfb_query = "Country"; + $pfb_query = 'Country'; } - // Add DNS Resolve and Suppression Icons to External IPs only. GeoIP Code to External IPs only. + // Add DNS resolve and suppression icons to external IPs only. GeoIP code to external IPs only. if (in_array($fields[8], $pfb_local) || ip_in_pfb_localsub($fields[8])) { - // Destination is Gateway/NAT/VIP - $rule = $rule_list[$rulenum]['name'] . "<br />(" . $rulenum .")"; + // Destination is gateway/NAT/VIP + $rule = "{$rule_list[$rulenum]['name']}<br /><small>({$rulenum})</small>"; $host = $fields[7]; - $alert_ip = "<a href='/pfblockerng/pfblockerng_diag_dns.php?host={$host}' title=\" " . gettext("Resolve host via Rev. DNS lookup"); + $alert_ip = "<a href='/pfblockerng/pfblockerng_threats.php?host={$host}' title=\" " . gettext("Resolve host via Rev. DNS lookup"); $alert_ip .= "\"> <img src=\"/themes/{$g['theme']}/images/icons/icon_log.gif\" width='11' height='11' border='0' "; $alert_ip .= "alt=\"Icon Reverse Resolve with DNS\" style=\"cursor: pointer;\" /></a>"; - if ($pfb_query != "Country" && $rtype == "block" && $pfb['supp'] == "on") { + if ($pfb_query != 'Country' && $rtype == 'block' && $pfb['supp'] == 'on') { $supp_ip = "<input type='image' name='addsuppress[]' onclick=\"hostruleid('{$host}','{$rule_list[$rulenum]['name']}');\" "; - $supp_ip .= "src=\"../themes/{$g['theme']}/images/icons/icon_pass_add.gif\" title=\""; + $supp_ip .= "src=\"../themes/{$g['theme']}/images/icons/icon_pass_add.gif\" alt='' title=\""; $supp_ip .= gettext($supp_ip_txt) . "\" border='0' width='11' height='11' />"; } - if ($pfb_query != "Country" && $rtype == "block" && $hostlookup == "on") { - $hostname = getpfbhostname('src', $fields[7], $counter); + if ($rtype == 'block' && $hostlookup == 'on') { + $hostname = getpfbhostname('src', $fields[7], $counter, $fields[8]); } else { - $hostname = ""; + $hostname = ''; } - $src_icons = $alert_ip . " " . $supp_ip . " "; - $dst_icons = ""; + $src_icons_1 = "{$alert_ip} {$supp_ip} "; + $src_icons_2 = "{$alert_ip} "; + $dst_icons_1 = ''; + $dst_icons_2 = ''; + } else { // Outbound - $rule = $rule_list[$rulenum]['name'] . "<br />(" . $rulenum .")"; + $rule = "{$rule_list[$rulenum]['name']}<br /><small>({$rulenum})</small>"; $host = $fields[8]; - $alert_ip = "<a href='/pfblockerng/pfblockerng_diag_dns.php?host={$host}' title=\"" . gettext("Resolve host via Rev. DNS lookup"); + $alert_ip = "<a href='/pfblockerng/pfblockerng_threats.php?host={$host}' title=\"" . gettext("Resolve host via Rev. DNS lookup"); $alert_ip .= "\"> <img src=\"/themes/{$g['theme']}/images/icons/icon_log.gif\" width='11' height='11' border='0' "; $alert_ip .= "alt=\"Icon Reverse Resolve with DNS\" style=\"cursor: pointer;\" /></a>"; - if ($pfb_query != "Country" && $rtype == "block" && $pfb['supp'] == "on") { + if ($pfb_query != 'Country' && $rtype == 'block' && $pfb['supp'] == 'on') { $supp_ip = "<input type='image' name='addsuppress[]' onclick=\"hostruleid('{$host}','{$rule_list[$rulenum]['name']}');\" "; - $supp_ip .= "src=\"../themes/{$g['theme']}/images/icons/icon_pass_add.gif\" title=\""; + $supp_ip .= "src=\"../themes/{$g['theme']}/images/icons/icon_pass_add.gif\" alt='' title=\""; $supp_ip .= gettext($supp_ip_txt) . "\" border='0' width='11' height='11' />"; } - if ($pfb_query != "Country" && $rtype == "block" && $hostlookup == "on") { - $hostname = getpfbhostname('dst', $fields[8], $counter); + if ($rtype == 'block' && $hostlookup == 'on') { + $hostname = getpfbhostname('dst', $fields[8], $counter, $fields[7]); } else { - $hostname = ""; + $hostname = ''; } - $src_icons = ""; - $dst_icons = $alert_ip . " " . $supp_ip . " "; + $src_icons_1 = ''; + $src_icons_2 = ''; + $dst_icons_1 = "{$alert_ip} {$supp_ip} "; + $dst_icons_2 = "{$alert_ip} "; } - // Determine Country Code of Host + // Determine Country code of host if (is_ipaddrv4($host)) { - $country = substr(exec("$pathgeoip -f $pathgeoipdat $host"),23,2); + $country = substr(exec("{$pathgeoip} -f {$pathgeoipdat} {$host}"), 23, 2); } else { - $country = substr(exec("$pathgeoip6 -f $pathgeoipdat6 $host"),26,2); + $country = substr(exec("{$pathgeoip6} -f {$pathgeoipdat6} {$host}"), 26, 2); } - // IP Query Grep Exclusion - $pfb_ex1 = "grep -v 'pfB\_\|\_v6\.txt'"; - $pfb_ex2 = "grep -v 'pfB\_\|/32\|/24\|\_v6\.txt' | grep -m1 '/'"; - - // Find List which contains Blocked IP Host - if (is_ipaddrv4($host) && $pfb_query != "Country") { - // Search for exact IP Match - $host1 = preg_replace("/(\d{1,3})\.(\d{1,3}).(\d{1,3}).(\d{1,3})/", '\'$1\.$2\.$3\.$4\'', $host); - $pfb_query = exec("/usr/bin/grep -rHm1 {$host1} {$pfbfolder} | sed -e 's/^.*[a-zA-Z]\///' -e 's/:.*//' -e 's/\..*/ /' | {$pfb_ex1}"); - // Search for IP in /24 CIDR - if (empty($pfb_query)) { - $host1 = preg_replace("/(\d{1,3})\.(\d{1,3}).(\d{1,3}).(\d{1,3})/", '\'$1\.$2\.$3\.0/24\'', $host); - $pfb_query = exec("/usr/bin/grep -rHm1 {$host1} {$pfbfolder} | sed -e 's/^.*[a-zA-Z]\///' -e 's/\.txt:/ /' | {$pfb_ex1}"); - } - // Search for First Two IP Octets in CIDR Matches Only. Skip any pfB (Country Lists) or /32,/24 Addresses. - if (empty($pfb_query)) { - $host1 = preg_replace("/(\d{1,3})\.(\d{1,3}).(\d{1,3}).(\d{1,3})/", '\'^$1\.$2\.\'', $host); - $pfb_query = exec("/usr/bin/grep -rH {$host1} {$pfbfolder} | sed -e 's/^.*[a-zA-Z]\///' -e 's/\.txt:/ /' | {$pfb_ex2}"); - } - // Search for First Two IP Octets in CIDR Matches Only (Subtract 1 from second Octet on each loop). - // Skip (Country Lists) or /32,/24 Addresses. - if (empty($pfb_query)) { - $host1 = preg_replace("/(\d{1,3})\.(\d{1,3}).(\d{1,3}).(\d{1,3})/", '\'^$1\.', $host); - $host2 = preg_replace("/(\d{1,3})\.(\d{1,3}).(\d{1,3}).(\d{1,3})/", '$2', $host); - for ($cnt = 1; $cnt <= 5; $cnt++) { - $host3 = $host2 - $cnt . '\''; - $pfb_query = exec("/usr/bin/grep -rH {$host1}{$host3} {$pfbfolder} | sed -e 's/^.*[a-zA-Z]\///' -e 's/\.txt:/ /' | {$pfb_ex2}"); - // Break out of loop if found. - if (!empty($pfb_query)) { - $cnt = 6; - } - } - } - // Search for First Three Octets - if (empty($pfb_query)) { - $host1 = preg_replace("/(\d{1,3})\.(\d{1,3}).(\d{1,3}).(\d{1,3})/", '\'^$1\.$2\.$3\.\'', $host); - $pfb_query = exec("/usr/bin/grep -rH {$host1} {$pfbfolder} | sed -e 's/^.*[a-zA-Z]\///' -e 's/\.txt:/ /' | {$pfb_ex2}"); - } - // Search for First Two Octets - if (empty($pfb_query)) { - $host1 = preg_replace("/(\d{1,3})\.(\d{1,3}).(\d{1,3}).(\d{1,3})/", '\'^$1\.$2\.\'', $host); - $pfb_query = exec("/usr/bin/grep -rH {$host1} {$pfbfolder} | sed -e 's/^.*[a-zA-Z]\///' -e 's/\.txt:/ /' | {$pfb_ex2}"); + // Find the header which alerted this host + if ($pfb_query != 'Country') { + if (strpos($rule, 'pfB_DNSBLIP') !== FALSE) { + $pfb_match[1] = 'DNSBLIP'; // Default pfB_DNSBLIP + $pfb_match[2] = ''; } - // Report Specific ET IQRisk Details - if ($pfb['et_header'] && preg_match("/{$et_header}/", $pfb_query)) { - $host1 = preg_replace("/(\d{1,3})\.(\d{1,3}).(\d{1,3}).(\d{1,3})/", '\'$1\.$2\.$3\.$4\'', $host); - $pfb_query = exec("/usr/bin/grep -Hm1 {$host1} {$pfb['etdir']}/* | sed -e 's/^.*[a-zA-Z]\///' -e 's/:.*//' -e 's/\..*/ /' -e 's/ET_/ET IPrep /' "); - if (empty($pfb_query)) { - $host1 = preg_replace("/(\d{1,3})\.(\d{1,3}).(\d{1,3}).(\d{1,3})/", '\'$1.$2.$3.0/24\'', $host); - $pfb_query = exec("/usr/bin/grep -rHm1 {$host1} {$pfbfolder} | sed -e 's/^.*[a-zA-Z]\///' -e 's/\.txt:/ /' | {$pfb_ex1}"); + else { + // Report specific ET IQRisk details + if ($pfb['et_header'] && strpos($pfb_query, "{$et_header}") !== FALSE) { + $pfbfolder = "{$pfb['etdir']}/*"; } - } - } - elseif (is_ipaddrv6($host) && $pfb_query != "Country") { - $pfb_query = exec("/usr/bin/grep -Hm1 {$host} {$pfbfolder} | sed -e 's/^.*[a-zA-Z]\///' -e 's/\.txt:/ /' | grep -v 'pfB\_'"); - } - // Default to "No Match" if not found. - if (empty($pfb_query)) { - $pfb_query = "No Match"; - } + $pfb_query = find_reported_header($host, $pfbfolder, FALSE); - // Split List Column into Two lines. - unset ($pfb_match); - if ($pfb_query == "No Match") { - $pfb_match[1] = "{$pfb_query}"; - $pfb_match[2] = ""; - } else { - preg_match ("/(.*)\s(.*)/", $pfb_query, $pfb_match); - if ($pfb_match[1] == "") { - $pfb_match[1] = "{$pfb_query}"; - $pfb_match[2] = ""; + // Split list column into two lines. + $pfb_match[1] = "{$pfb_query[1]}"; + $pfb_match[2] = "{$pfb_query[0]}"; + + // Remove Suppression Icon for 'no match' and all subnets except for '/32 & /24'. + if ($pfb_query[2]) { + $src_icons = $src_icons_1; + $dst_icons = $dst_icons_1; + } else { + $src_icons = $src_icons_2; + $dst_icons = $dst_icons_2; + } } } + else { + $pfb_match[1] = 'Country'; + $pfb_match[2] = ''; + $src_icons = $src_icons_2; // Remove 'suppress icon' + $dst_icons = $dst_icons_2; + } - // Add []'s to IPv6 Addresses and add a zero-width space as soft-break opportunity after each colon if we have an IPv6 address (from Snort) - if ($fields[4] == "6") { - $fields[97] = "[" . str_replace(":", ":​", $fields[7]) . "]"; - $fields[98] = "[" . str_replace(":", ":​", $fields[8]) . "]"; + // Add []'s to IPv6 addresses and add a zero-width space as soft-break opportunity after each colon if we have an IPv6 address (from Snort) + if ($fields[4] == '6') { + $fields[97] = '[' . str_replace(':', ':​', $fields[7]) . ']'; + $fields[98] = '[' . str_replace(':', ':​', $fields[8]) . ']'; } else { $fields[97] = $fields[7]; $fields[98] = $fields[8]; } - // Truncate Long List Names - $pfb_matchtitle = "Country Block Rules cannot be suppressed.\n\nTo allow a particular Country IP, either remove the particular Country or add the Host\nto a Permit Alias in the Firewall Tab.\n\nIf the IP is not listed beside the List, this means that the Block is a /32 entry.\nOnly /32 or /24 CIDR Hosts can be suppressed.\n\nIf (Duplication) Checking is not enabled. You may see /24 and /32 CIDR Blocks for a given blocked Host"; + // Truncate long list names + $pfb_matchtitle = "Country Block rules cannot be Suppressed.\n\n To allow a particular Country IP, either remove the particular Country or add the host\nto a Permit Alias in the Firewall tab.\n\nIf the IP is not listed beside the list, this means that the block is a /32 entry.\nOnly /32 or /24 CIDR hosts can be suppressed.\n\nIf (Duplication) Checking is not enabled. You may see /24 and /32 CIDR blocks for a given blocked host"; if (strlen($pfb_match[1]) >= 17) { $pfb_matchtitle = $pfb_match[1]; $pfb_match[1] = substr($pfb_match[1], 0, 16) . '...'; } - // Print Alternating Line Shading - $alertRowEvenClass = "style='background-color: #D8D8D8;'"; - $alertRowOddClass = "style='background-color: #E8E8E8;'"; - + // Print alternating line shading $alertRowClass = $counter % 2 ? $alertRowEvenClass : $alertRowOddClass; echo "<tr {$alertRowClass}> <td class='listMRr' align='center'>{$fields[99]}</td> - <td class='listMRr' align='center'>{$fields[2]}</td> + <td class='listMRr' align='center'><small>{$fields[2]}</small></td> <td class='listMRr' align='center' title='The pfBlockerNG Rule that Blocked this Host.'>{$rule}</td> - <td class='listMRr' align='center'>{$fields[6]}</td> - <td class='listMRr' align='center' sorttable_customkey='{$fields[97]}'>{$src_icons}{$fields[97]}{$srcport}<br /><small>{$hostname['src']}</small></td> - <td class='listMRr' align='center' sorttable_customkey='{$fields[98]}'>{$dst_icons}{$fields[98]}{$dstport}<br /><small>{$hostname['dst']}</small></td> + <td class='listMRr' align='center'><small>{$fields[6]}</small></td> + <td class='listMRr' align='center' sorttable_customkey='{$fields[97]}'>{$src_icons}{$fields[97]}{$srcport}<br /> + <small>{$hostname['src']}</small></td> + <td class='listMRr' align='center' sorttable_customkey='{$fields[98]}'>{$dst_icons}{$fields[98]}{$dstport}<br /> + <small>{$hostname['dst']}</small></td> <td class='listMRr' align='center'>{$country}</td> - <td class='listbg' align='center' title='{$pfb_matchtitle}' style=\"font-size: 10px word-wrap:break-word;\">{$pfb_match[1]}<br />{$pfb_match[2]}</td></tr>"; + <td class='listbg' align='center' title='{$pfb_matchtitle}' style=\"font-size: 10px word-wrap:break-word;\"> + {$pfb_match[1]}<br /><small>{$pfb_match[2]}</small></td></tr>"; $counter++; - if ($rtype == "block") { + if ($rtype == 'block') { $resolvecounter = $counter; } } } } ?> + </tbody> <tr> - <!--Print Final Table Info--> + <!--Print final table info--> <?php if ($pfbentries != $counter) { - $msg = " - Insufficient Firewall Alerts found."; + $msg = ' - Insufficient Firewall Alerts found.'; } - echo (" <td colspan='8' style='font-size:10px; background-color: #F0F0F0;' >Found {$counter} Alert Entries {$msg}</td>"); + if ($type == 'DNSBL') { + $colspan = "colspan='7'"; + } else { + $colspan = "colspan='8'"; + } + + echo (" <td {$colspan} style='font-size:10px; background-color: #F0F0F0;' >Found {$counter} Alert Entries {$msg}</td>"); $counter = 0; $msg = ''; ?> </tr> </table> </table> -<?php endforeach; ?> <!--End - Create Three Output Windows 'Deny', 'Permit' and 'Match'--> +<?php endforeach; ?> <!--End - Create three output windows 'Deny', 'Permit' and 'Match'--> <?php unset ($fields_array); ?> </td></tr> </table> @@ -1041,7 +1255,7 @@ if (!empty($fields_array[$type]) && !empty($rule_list)) { <script type="text/javascript"> //<![CDATA[ -// This function stuffs the passed HOST, Table values into hidden Form Fields for postback. +// This function inserts the passed HOST and table values into a hidden Form fields for postback. function hostruleid(host,table) { document.getElementById("ip").value = host; document.getElementById("table").value = table; @@ -1055,10 +1269,15 @@ function hostruleid(host,table) { } } -// Auto-Resolve of Alerted Hostnames +// This function collects the domain and list for the DNSBL suppression function. +function domainlistid(domain,domainlist) { + document.getElementById("domain").value = domain; +} + +// Auto-resolve of alerted hostnames function findhostnames(counter) { getip = jQuery('#gethostname_' + counter).attr('name'); - geturl = "<?php echo $_SERVER['PHP_SELF']; ?>"; + geturl = "/pfblockerng/pfblockerng_alerts_ar.php"; jQuery.get( geturl, { "getpfhostname": getip } ) .done(function( data ) { jQuery('#gethostname_' + counter).prop('title' , data ); @@ -1071,7 +1290,7 @@ function findhostnames(counter) { var alertlines = <?php echo $resolvecounter; ?>; var autoresolve = "<?php echo $config['installedpackages']['pfblockerngglobal']['hostlookup']; ?>"; -if ( autoresolve == "on" ) { +if ( autoresolve == 'on' ) { for (alertcount = 0; alertcount < alertlines; alertcount++) { setTimeout(findhostnames(alertcount), 30); } @@ -1089,7 +1308,7 @@ function enable_hideFilter() { //]]> </script> -<?php include("fend.inc"); ?> +<?php include('fend.inc'); ?> </form> </body> </html>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng_alerts_ar.php b/config/pfblockerng/pfblockerng_alerts_ar.php new file mode 100644 index 00000000..8de850f3 --- /dev/null +++ b/config/pfblockerng/pfblockerng_alerts_ar.php @@ -0,0 +1,52 @@ +<?php +/* + pfBlockerNG_Alerts_AR.php + + pfBlockerNG + Copyright (c) 2015 BBcan177@gmail.com + All rights reserved. + + Portions of this code are based on original work done for + pfSense from the following contributors: + + Javascript Hostname Lookup modifications by J. Nieuwenhuizen + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +// Auto-resolve hostnames +if (isset($_REQUEST['getpfhostname'])) { + $getpfhostname = trim(htmlspecialchars($_REQUEST['getpfhostname'])); + if (strlen($getpfhostname) >= 8) { + $hostname = htmlspecialchars(gethostbyaddr($getpfhostname), ENT_QUOTES); + } else { + $hostname = $getpfhostname; + } + if ($hostname == $getpfhostname) { + $hostname = 'unknown'; + } + echo $hostname; +} + +?> diff --git a/config/pfblockerng/pfblockerng_diag_dns.php b/config/pfblockerng/pfblockerng_diag_dns.php deleted file mode 100644 index fa238b7a..00000000 --- a/config/pfblockerng/pfblockerng_diag_dns.php +++ /dev/null @@ -1,320 +0,0 @@ -<?php -/* - pfBlockerNG_diag_dns.php - - pfBlockerNG - Copyright (C) 2015 BBcan177@gmail.com - All rights reserved. - - Original Code by: - Copyright (C) 2009 Jim Pingle (jpingle@gmail.com) - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -$pgtitle = array(gettext("pfBlockerNG"),gettext("DNS/Threat Source Lookup")); -require("guiconfig.inc"); - -$host = trim($_REQUEST['host'], " \t\n\r\0\x0B[];\"'"); -$host_esc = escapeshellarg($host); - -if (is_array($config['aliases']['alias'])) { - $a_aliases = &$config['aliases']['alias']; -} else { - $a_aliases = array(); -} -$aliasname = str_replace(array(".","-"), "_", $host); -$alias_exists = false; -$counter = 0; -foreach ($a_aliases as $a) { - if ($a['name'] == $aliasname) { - $alias_exists = true; - $id = $counter; - } - $counter++; -} - -if (isset($_POST['create_alias']) && (is_hostname($host) || is_ipaddr($host))) { - if ($_POST['override']) { - $override = true; - } - $resolved = gethostbyname($host); - $type = "hostname"; - if ($resolved) { - $resolved = array(); - exec("/usr/bin/drill {$host_esc} A | /usr/bin/grep {$host_esc} | /usr/bin/grep -v ';' | /usr/bin/awk '{ print $5 }'", $resolved); - $isfirst = true; - foreach ($resolved as $re) { - if ($re <> "") { - if (!$isfirst) { - $addresses .= " "; - } - $addresses .= rtrim($re) . "/32"; - $isfirst = false; - } - } - $newalias = array(); - if ($override) { - $alias_exists = false; - } - if ($alias_exists == false) { - $newalias['name'] = $aliasname; - $newalias['type'] = "network"; - $newalias['address'] = $addresses; - $newalias['descr'] = "Created from Diagnostics-> DNS Lookup"; - if ($override) { - $a_aliases[$id] = $newalias; - } else { - $a_aliases[] = $newalias; - } - write_config(); - $createdalias = true; - } - } -} - -if ($_POST) { - unset($input_errors); - - $reqdfields = explode(" ", "host"); - $reqdfieldsn = explode(",", "Host"); - - do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors); - - if (!is_hostname($host) && !is_ipaddr($host)) { - $input_errors[] = gettext("Host must be a valid hostname or IP address."); - } else { - // Test resolution speed of each DNS server. - $dns_speeds = array(); - $dns_servers = array(); - exec("/usr/bin/grep nameserver /etc/resolv.conf | /usr/bin/cut -f2 -d' '", $dns_servers); - foreach ($dns_servers as $dns_server) { - $query_time = exec("/usr/bin/drill {$host_esc} " . escapeshellarg("@" . trim($dns_server)) . " | /usr/bin/grep Query | /usr/bin/cut -d':' -f2"); - if ($query_time == "") { - $query_time = gettext("No response"); - } - $new_qt = array(); - $new_qt['dns_server'] = $dns_server; - $new_qt['query_time'] = $query_time; - $dns_speeds[] = $new_qt; - unset($new_qt); - } - } - - $type = "unknown"; - $resolved = ""; - $ipaddr = ""; - $hostname = ""; - if (!$input_errors) { - if (is_ipaddr($host)) { - $type = "ip"; - $resolved = gethostbyaddr($host); - $ipaddr = $host; - if ($host != $resolved) { - $hostname = $resolved; - } - } elseif (is_hostname($host)) { - $type = "hostname"; - $resolved = gethostbyname($host); - if ($resolved) { - $resolved = array(); - exec("/usr/bin/drill {$host_esc} A | /usr/bin/grep {$host_esc} | /usr/bin/grep -v ';' | /usr/bin/awk '{ print $5 }'", $resolved); - } - $hostname = $host; - if ($host != $resolved) { - $ipaddr = $resolved[0]; - } - } - - if ($host == $resolved) { - $resolved = gettext("No record found"); - } - } -} - -if ( ($_POST['host']) && ($_POST['dialog_output']) ) { - display_host_results ($host,$resolved,$dns_speeds); - exit; -} - -function display_host_results ($address,$hostname,$dns_speeds) { - $map_lengths = function($element) { return strlen($element[0]); }; - - echo gettext("IP Address") . ": {$address} \n"; - echo gettext("Host Name") . ": {$hostname} \n"; - echo "\n"; - $text_table = array(); - $text_table[] = array(gettext("Server"), gettext("Query Time")); - if (is_array($dns_speeds)) { - foreach ($dns_speeds as $qt) { - $text_table[] = array(trim($qt['dns_server']), trim($qt['query_time'])); - } - } - $col0_padlength = max(array_map($map_lengths, $text_table)) + 4; - foreach ($text_table as $text_row) { - echo str_pad($text_row[0], $col0_padlength) . $text_row[1] . "\n"; - } -} - -include("head.inc"); ?> -<body link="#0000CC" vlink="#0000CC" alink="#0000CC"> -<?php include("fbegin.inc"); ?> -<table width="100%" border="0" cellpadding="0" cellspacing="0" summary="pfblockerng diag dns"> - <tr> - <td> -<?php if ($input_errors) print_input_errors($input_errors); ?> - <form action="/pfblockerng/pfblockerng_diag_dns.php" method="post" name="iform" id="iform"> - <table width="100%" border="0" cellpadding="6" cellspacing="0" summary="tabcont"> - <tr> - <td colspan="2" valign="top" class="listtopic"> <?=gettext("Resolve DNS hostname or IP");?></td> - </tr> - <tr> - <td width="22%" valign="top" class="vncellreq"><?=gettext("Hostname or IP");?></td> - <td width="78%" class="vtable"> - <?=$mandfldhtml;?> - <table summary="results"> - <tr><td valign="top"> - <input name="host" type="text" class="formfld unknown" id="host" size="20" value="<?=htmlspecialchars($host);?>"> - </td> - <?php if ($resolved && $type) { ?> - <td valign="middle"> </td><td> - <font size="+1"> -<?php - $found = 0; - if (is_array($resolved)) { - foreach ($resolved as $hostitem) { - if ($hostitem <> "") { - echo $hostitem . "<br />"; - $found++; - } - } - } else { - echo $resolved; - } - if ($found > 0) { ?> - <br /></font><font size='-2'> - <?php if ($alias_exists) { ?> - An alias already exists for the hostname <?= htmlspecialchars($host) ?>. <br /> - <input type="hidden" name="override" value="true"/> - <input type="submit" name="create_alias" value="Overwrite Alias"/> - <?php } else { - if (!$createdalias) { ?> - <input type="submit" name="create_alias" value="Create Alias from These Entries"/> - <?php } else { ?> - Alias created with name <?= htmlspecialchars($newalias['name']) ?> - <?php } - } - } -?> - - <?php } ?> - </font></td></tr></table> - </td> - </tr> -<?php if ($_POST): ?> - <tr> - <td width="22%" valign="top" class="vncell"><?=gettext("Resolution time per server");?></td> - <td width="78%" class="vtable"> - <table width="170" border="0" cellpadding="6" cellspacing="0" summary="resolution time"> - <tr> - <td class="listhdrr"> - <?=gettext("Server");?> - </td> - <td class="listhdrr"> - <?=gettext("Query time");?> - </td> - </tr> -<?php - if (is_array($dns_speeds)) - foreach ($dns_speeds as $qt): -?> - <tr> - <td class="listlr"> - <?=$qt['dns_server']?> - </td> - <td class="listr"> - <?=$qt['query_time']?> - </td> - </tr> -<?php - endforeach; -?> - </table> - </td> - </tr> - <?php endif; ?> - <?php if (!$input_errors && $ipaddr) { ?> - <tr> - <td width="22%" valign="top" class="vncell"><?=gettext("More Information:");?></td> - <td width="78%" class="vtable"> - <a target="_new" href ="/diag_ping.php?host=<?=htmlspecialchars($host)?>&interface=wan&count=3"><?=gettext("Ping");?></a> <br /> - <a target="_new" href ="/diag_traceroute.php?host=<?=htmlspecialchars($host)?>&ttl=18"><?=gettext("Traceroute");?></a> - <p/> - <?=gettext("NOTE: The following links are to external services, so their reliability cannot be guaranteed.");?><br/><br /> - <a target="_new" href="http://private.dnsstuff.com/tools/whois.ch?ip=<?php echo $ipaddr; ?>"><?=gettext("IP WHOIS @ DNS Stuff");?></a><br /> - <a target="_new" href="http://private.dnsstuff.com/tools/ipall.ch?ip=<?php echo $ipaddr; ?>"><?=gettext("IP Info @ DNS Stuff");?></a> - - <?=gettext("NOTE: The following links are to external services, so their reliability cannot be guaranteed.");?><br /><br /> - <a target="_new" href="http://kb.bothunter.net/ipInfo/nowait.php?IP=<?php echo $ipaddr; ?>"><?=gettext("BOTHunter");?></a><br /> - <a target="_new" href="http://www.ipvoid.com/scan/<?php echo $ipaddr; ?>/"><?=gettext("IPVOID");?></a><br /> - <a target="_new" href="http://www.tcpiputils.com/browse/ip-address/<?php echo $ipaddr; ?>/"><?=gettext("TCPUtils");?></a><br /> - <a target="_new" href="https://www.herdprotect.com/ip-address-<?php echo $ipaddr; ?>.aspx"><?=gettext("Herd Protect");?></a><br /> - <a target="_new" href="https://www.senderbase.org/lookup/ip/?search_string=<?php echo $ipaddr; ?>"><?=gettext("SenderBase");?></a><br /> - <a target="_new" href="http://www.ip-tracker.org/locator/ip-lookup.php?ip=<?php echo $ipaddr; ?>"><?=gettext("IP Tracker");?></a><br /> - - <a target="_new" href="https://www.fortiguard.com/ip_rep/index.php?data=/<?php echo $ipaddr; ?>?"><?=gettext("FortiGuard");?></a><br /> - <a target="_new" href="https://www.projecthoneypot.org/ip_<?php echo $ipaddr; ?>"><?=gettext("Project HoneyPot");?></a><br /> - <a target="_new" href="https://www.virustotal.com/en/ip-address/<?php echo $ipaddr; ?>/information"><?=gettext("VirusTotal Info");?></a><br /> - <a target="_new" href="https://www.mcafee.com/threat-intelligence/ip/default.aspx?ip=<?php echo $ipaddr; ?>"><?=gettext("McAfee Threat Center");?></a><br /> - <a target="_new" href="http://sitecheck2.sucuri.net/results/<?php echo $ipaddr; ?>"><?=gettext("Securi SiteCheck");?></a><br /> - <a target="_new" href="https://www.dshield.org/ipinfo.html?IP=<?php echo $ipaddr; ?>"><?=gettext("DShield Threat Lookup");?></a><br /> - <a target="_new" href="https://isc.sans.edu/ipinfo.html?ip=<?php echo $ipaddr; ?>"><?=gettext("Internet Storm Center");?></a><br /> - <a target="_new" href="https://www.mywot.com/en/scorecard/<?php echo $ipaddr; ?>"><?=gettext("Web of Trust (WOT) Scorecard");?></a><br /> - <a target="_new" href="https://quttera.com/sitescan/<?php echo $ipaddr; ?>"><?=gettext("Quattera");?></a><br /> - <a target="_new" href="https://www.iblocklist.com/search.php?string=<?php echo $ipaddr; ?>"><?=gettext("I-Block List");?></a><br /> - <p/> - <?=gettext("NOTE: Mail Server DNSRBL Lookups");?><br /><br /> - <a target="_new" href="https://senderscore.org/lookup.php?lookup=<?php echo $ipaddr; ?>&ipLookup=Go"><?=gettext("SenderScore");?></a><br /> - <a target="_new" href="http://www.spamhaus.org/query/bl?ip=<?php echo $ipaddr; ?>"><?=gettext("Spamhaus Blocklist");?></a><br /> - <a target="_new" href="http://www.spamcop.net/w3m?action=checkblock&ip=<?php echo $ipaddr; ?>"><?=gettext("SPAMcop Blocklist");?></a><br /> - <a target="_new" href="http://multirbl.valli.org/lookup/<?php echo $ipaddr; ?>.html"><?=gettext("multirbl RBL Lookup");?></a><br /> - <a target="_new" href="http://mxtoolbox.com/SuperTool.aspx?action=blacklist%3a<?php echo $ipaddr; ?>&run=toolpage"><?=gettext("MXToolbox");?></a><br /> - - </td> - </tr> - <?php } ?> - <tr> - <td width="22%" valign="top"> </td> - <td width="78%"> - <br /> - <input name="Submit" type="submit" class="formbtn" value="<?=gettext("DNS Lookup");?>"> - </td> - </tr> - </table> -</form> -</td></tr></table> -<?php include("fend.inc"); ?> -</body> -</html>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng_dnsbl.xml b/config/pfblockerng/pfblockerng_dnsbl.xml new file mode 100644 index 00000000..b6a09b62 --- /dev/null +++ b/config/pfblockerng/pfblockerng_dnsbl.xml @@ -0,0 +1,597 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE packagegui SYSTEM "../schema/packages.dtd"> +<?xml-stylesheet type="text/xsl" href="../xsl/package.xsl"?> +<packagegui> + <copyright> + <![CDATA[ +/* ========================================================================== */ +/* + pfBlockerNG_dnsbl.xml + + pfBlockerNG + Copyright (c) 2015 BBcan177@gmail.com + All rights reserved. + +*/ +/* ========================================================================== */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +/* ========================================================================== */ + ]]> + </copyright> + <description>Describe your package here</description> + <requirements>Describe your package requirements here</requirements> + <faq>Currently there are no FAQ items provided.</faq> + <name>pfblockerngdnsblsettings</name> + <version>1.0</version> + <title>pfBlockerNG: DNSBL: Settings</title> + <include_file>/usr/local/pkg/pfblockerng/pfblockerng.inc</include_file> + <addedit_string>pfBlockerNG: Save DNSBL general settings</addedit_string> + <menu> + <name>pfBlockerNG</name> + <tooltiptext></tooltiptext> + <section>Firewall</section> + <configfile>pfblockerng_dnsbl.xml</configfile> + </menu> + <tabs> + <tab> + <text>General</text> + <url>/pkg_edit.php?xml=pfblockerng.xml</url> + <tooltiptext></tooltiptext> + </tab> + <tab> + <text>Update</text> + <url>/pfblockerng/pfblockerng_update.php</url> + </tab> + <tab> + <text>Alerts</text> + <url>/pfblockerng/pfblockerng_alerts.php</url> + </tab> + <tab> + <text>Reputation</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml</url> + </tab> + <tab> + <text>IPv4</text> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml</url> + </tab> + <tab> + <text>IPv6</text> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml</url> + </tab> + <tab> + <text>DNSBL</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl.xml</url> + </tab> + <tab> + <text>Country</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml</url> + </tab> + <tab> + <text>Logs</text> + <url>/pfblockerng/pfblockerng_log.php</url> + </tab> + <tab> + <text>Sync</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml</url> + </tab> + <tab> + <text>DNSBL</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl.xml</url> + <tab_level>2</tab_level> + <active/> + </tab> + <tab> + <text>DNSBL Feeds</text> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_dnsbl_lists.xml</url> + <tab_level>2</tab_level> + </tab> + <tab> + <text>DNSBL EasyList</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl_easylist.xml</url> + <tab_level>2</tab_level> + </tab> + </tabs> + <fields> + <field> + <name><![CDATA[DNS Block List Configuration   Run 'Force Update' to deploy new Settings.]]></name> + <type>listtopic</type> + </field> + <field> + <fielddescr>LINKS</fielddescr> + <fieldname></fieldname> + <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a>  + <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> + </description> + <type>info</type> + </field> + <field> + <type>info</type> + <description><![CDATA[<font color='red'>Note: </font>DNSBL requires the DNS Resolver (Unbound) to be used as the DNS service.<br /> + When a DNS request is made for a domain that is listed in DNSBL, the request is redirected to the Virtual IP address<br /> + where an instance of Lighttpd Web Server will collect the packet statistics and push a '1x1' GIF image to the Browser. + If browsing is slow, check for Firewall LAN Rules/Limiters that might be blocking access to the DNSBL VIP.<br /><br /> + + <font color='red'>Note: </font>DNSBL will block and <u>partially</u> log Alerts for HTTPS requests. + To debug issues with 'False Positives', the following tools below can be used:<br /><ul> + + <li>1. Browser Dev mode (F12) and goto 'Console' to review any error messages.</li> + <li>2. Execute the following command from pfSense Shell (Changing the interface 're1' to the pfSense Lan Interface):<br /> + <li> <strong>tcpdump -nnvli re1 port 53 | grep -B1 'A 10.10.10.1'</strong></li> + <li>3. Packet capture software such as Wireshark.</li></ul>]]> + </description> + </field> + <field> + <fielddescr>Enable DNSBL</fielddescr> + <fieldname>pfb_dnsbl</fieldname> + <type>checkbox</type> + <description><![CDATA[This will enable DNS Block List for Malicious and/or unwanted Adverts Domains<br /> + To Utilize, <strong>Unbound DNS Resolver</strong> must be enabled.]]> + </description> + </field> + <field> + <fielddescr>DNSBL Virtual IP</fielddescr> + <fieldname>pfb_dnsvip</fieldname> + <type>input</type> + <size>13</size> + <description><![CDATA[Example ( 10.10.10.1 )<br /> + Enter a  <strong>single IPv4 VIP address</strong>  that is RFC1918 Compliant.<br /><br /> + This address should be in an Isolated Range than what is used in your Network.<br /> + Rejected DNS Requests will be forwarded to this VIP (Virtual IP)<br /> + RFC1918 Compliant - (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)]]> + </description> + <default_value>10.10.10.1</default_value> + </field> + <field> + <fielddescr>DNSBL Listening Port</fielddescr> + <fieldname>pfb_dnsport</fieldname> + <type>input</type> + <size>3</size> + <description><![CDATA[Example ( 8081 )<br /> + Enter a  <strong>single PORT</strong>  that is in the range of 1 - 65535<br /><br /> + This Port must not be in use by any other process.]]> + </description> + <default_value>8081</default_value> + </field> + <field> + <fielddescr>DNSBL SSL Listening Port</fielddescr> + <fieldname>pfb_dnsport_ssl</fieldname> + <type>input</type> + <size>3</size> + <description><![CDATA[Example ( 8443 )<br /> + Enter a  <strong>single PORT</strong>  that is in the range of 1 - 65535<br /><br /> + This Port must not be in use by any other process.]]> + </description> + <default_value>8443</default_value> + </field> + <field> + <fielddescr>DNSBL Listening Interface</fielddescr> + <fieldname>dnsbl_interface</fieldname> + <description><![CDATA[Select the interface you want DNSBL to Listen on.<br /> + Default: <strong>LAN</strong> - Selected Interface should be a Local Interface only.]]> + </description> + <type>interfaces_selection</type> + <hideinterfaceregex>wan|loopback</hideinterfaceregex> + <default_value>lan</default_value> + </field> + <field> + <fielddescr>DNSBL Firewall Rule</fielddescr> + <fieldname>pfb_dnsbl_rule</fieldname> + <type>checkbox</type> + <usecolspan2/> + <combinefields>begin</combinefields> + </field> + <field> + <fieldname>dnsbl_allow_int</fieldname> + <description><![CDATA[This will create a 'Floating' Firewall rule to allow traffic from the Selected Interface(s) below<br /> + to access the DNSBL VIP on the LAN interface. This is only required for multiple LAN Segments.]]> + </description> + <type>interfaces_selection</type> + <hideinterfaceregex>wan</hideinterfaceregex> + <multiple/> + <usecolspan2/> + <dontdisplayname/> + <combinefields>end</combinefields> + </field> + <field> + <name>DNSBL IP Firewall Rule Settings</name> + <type>listtopic</type> + </field> + <field> + <description>Configure settings for Firewall Rules when any DNSBL Feed contain IP Addresses</description> + <type>info</type> + </field> + <field> + <fielddescr>List Action</fielddescr> + <description><![CDATA[Default: <strong>Disabled</strong><br /><br /> + Select the <strong>Action</strong> for Firewall Rules when any DNSBL Feed contain IP addresses.<br /><br /> + <strong><u>'Disabled' Rule:</u></strong> Disables selection and does nothing to selected Alias.<br /><br /> + + <strong><u>'Deny' Rules:</u></strong><br /> + 'Deny' rules create high priority 'block' or 'reject' rules on the stated interfaces. They don't change the 'pass' rules on other + interfaces. Typical uses of 'Deny' rules are:<br /> + <ul><li><strong>Deny Both</strong> - blocks all traffic in both directions, if the source or destination IP is in the block list</li> + <li><strong>Deny Inbound/Deny Outbound</strong> - blocks all traffic in one direction <u>unless</u> it is part of a session started by + traffic sent in the other direction. Does not affect traffic in the other direction.</li> + <li>One way 'Deny' rules can be used to selectively block <u>unsolicited</u> incoming (new session) packets in one direction, while + still allowing <u>deliberate</u> outgoing sessions to be created in the other direction.</li></ul> + <strong><u>'Alias' Rule:</u></strong><br /> + <strong>'Alias'</strong> rules create an <a href="/firewall_aliases.php">alias</a> for the list (and do nothing else). + This enables a pfBlockerNG list to be used by name, in any firewall rule or pfSense function, as desired.]]> + </description> + <fieldname>action</fieldname> + <type>select</type> + <options> + <option><name>Disabled</name><value>Disabled</value></option> + <option><name>Deny Inbound</name><value>Deny_Inbound</value></option> + <option><name>Deny Outbound</name><value>Deny_Outbound</value></option> + <option><name>Deny Both</name><value>Deny_Both</value></option> + <option><name>Alias Deny</name><value>Alias_Deny</value></option> + </options> + </field> + <field> + <fielddescr>Enable Logging</fielddescr> + <fieldname>aliaslog</fieldname> + <description><![CDATA[Default: <strong>Enable</strong><br /> + Select - Logging to Status: System Logs: FIREWALL ( Log )<br /> + This can be overriden by the 'Global Logging' Option in the General Tab.]]> + </description> + <type>select</type> + <options> + <option><name>Enable</name><value>enabled</value></option> + <option><name>Disable</name><value>disabled</value></option> + </options> + </field> + <field> + <name>Advanced Inbound Firewall Rule Settings</name> + <type>listtopic</type> + </field> + <field> + <type>info</type> + <description><![CDATA[<font color='red'>Note: </font>In general, Auto-Rules are created as follows:<br /> + <ul>Inbound  - 'any' port, 'any' protocol and 'any' destination<br /> + Outbound - 'any' port, 'any' protocol and 'any' destination address in the lists</ul> + Configuring the Adv. Inbound Rule settings, will allow for more customization of the Inbound Auto-Rules.<br /> + <strong>Select the pfSense 'Port' and/or 'Destination' Alias below:</strong>]]> + </description> + </field> + <field> + <fieldname>autoports</fieldname> + <fielddescr>Enable Custom Port</fielddescr> + <type>checkbox</type> + <enablefields>aliasports</enablefields> + <usecolspan2/> + <combinefields>begin</combinefields> + </field> + <field> + <fielddescr>Define Alias</fielddescr> + <fieldname>aliasports</fieldname> + <description><![CDATA[<a href="/firewall_aliases.php?tab=port">Click Here to add/edit Aliases</a> + Do not manually enter port numbers. <br />Do not use 'pfB_' in the Port Alias name.]]> + </description> + <size>21</size> + <type>aliases</type> + <typealiases>port</typealiases> + <dontdisplayname/> + <usecolspan2/> + <combinefields>end</combinefields> + </field> + <field> + <fieldname>autodest</fieldname> + <fielddescr>Enable Custom Destination</fielddescr> + <type>checkbox</type> + <enablefields>aliasdest,autonot</enablefields> + <usecolspan2/> + <combinefields>begin</combinefields> + </field> + <field> + <fieldname>aliasdest</fieldname> + <description><![CDATA[<a href="/firewall_aliases.php?tab=ip">Click Here to add/edit Aliases</a> + Do not manually enter Addresses(es). <br />Do not use 'pfB_' in the 'IP Network Type' Alias name.]]> + </description> + <size>21</size> + <type>aliases</type> + <typealiases>network</typealiases> + <dontdisplayname/> + <usecolspan2/> + <combinefields/> + </field> + <field> + <fielddescr>Invert</fielddescr> + <fieldname>autonot</fieldname> + <description><![CDATA[<div style="padding-left: 22px;"><strong>Invert</strong> - Option to invert the sense of the match.<br /> + ie - Not (!) Destination Address(es)</div>]]> + </description> + <type>checkbox</type> + <dontdisplayname/> + <usecolspan2/> + <combinefields>end</combinefields> + </field> + <field> + <fielddescr>Custom Protocol</fielddescr> + <fieldname>autoproto</fieldname> + <description><![CDATA[<strong>Default: any</strong><br />Select the Protocol used for Inbound Firewall Rule(s).<br /> + Do not use 'any' with Adv. Inbound Rules as it will bypass these settings!]]></description> + <type>select</type> + <options> + <option><name>any</name><value></value></option> + <option><name>TCP</name><value>tcp</value></option> + <option><name>UDP</name><value>udp</value></option> + <option><name>TCP/UDP</name><value>tcp/udp</value></option> + </options> + <size>4</size> + <default_value></default_value> + </field> + <field> + <name><![CDATA[Alexa Whitelist]]></name> + <type>listtopic</type> + </field> + <field> + <fielddescr>Enable Alexa</fielddescr> + <fieldname>alexa_enable</fieldname> + <description><![CDATA[Alexa provides a <a target="_blank" href="https://aws.amazon.com/alexa-top-sites/">Top 1 million sites list.</a> + (Global 1 month average traffic ranking)<br /><br /> + Alexa can be used to whitelist the most popular domain names to avoid false positives. + To use this feature, select the number of 'Top Domains' to whitelist. You can also 'include' which TLDs to whitelist.<br /> + + <br /><font color='red'>Recommendation: </font> + <ul>Alexa also contains the 'Top' AD Servers, so its recommended to configure the first DNSBL Alias with AD Server<br /> + (ie. yoyo, Adaway...) based feeds. Alexa whitelisting can be disabled for this first defined Alias.<br /><br /> + Generally, Alexa should be used for feeds that post full URLs like PhishTank, OpenPhish or MalwarePatrol.<br /><br /> + To bypass an Alexa domain, add the Domain to the first defined Alias 'Custom Block list' with Alexa disabled in this alias.</ul> + + The complete 'Top 1M list' can be downloaded from + <a target=_blank href="https://s3.amazonaws.com/alexa-static/top-1m.csv.zip">Here</a> (Database is free to use.)<br /> + When enabled, this list will be automatically updated once per month along with the MaxMind Database.]]> + </description> + <type>checkbox</type> + </field> + <field> + <fielddescr><![CDATA[Number of Alexa<br />Top Domains to Whitelisting]]></fielddescr> + <fieldname>alexa_count</fieldname> + <description><![CDATA[<strong>Default: Top 1k</strong><br /> + Select the <strong>number</strong> of Alexa 'Top Domain global ranking' to whitelist.]]></description> + <type>select</type> + <options> + <option><name>Top 100</name><value>100</value></option> + <option><name>Top 1k</name><value>1000</value></option> + <option><name>Top 10k</name><value>10000</value></option> + <option><name>Top 100k</name><value>100000</value></option> + <option><name>Top 250k</name><value>250000</value></option> + <option><name>Top 500k</name><value>500000</value></option> + <option><name>Top 750k</name><value>750000</value></option> + <option><name>Top 1M</name><value>1000000</value></option> + </options> + <default_value>1000</default_value> + </field> + <field> + <fielddescr>Alexa TLD Inclusion</fielddescr> + <fieldname>alexa_inclusion</fieldname> + <description><![CDATA[Select the TLDs for Whitelist. ( Only showing the Top 150 TLDs )<br /> + <strong>Default: COM, NET, ORG, CA, CO, IO</strong><br /><br /> + Detailed listing : <a target=_blank href="http://www.iana.org/domains/root/db">Root Zone top-level domains.</a> ]]> + </description> + <type>select</type> + <options> + <option><name>AE</name><value>ae</value></option> + <option><name>AERO</name><value>aero</value></option> + <option><name>AG</name><value>ag</value></option> + <option><name>AL</name><value>al</value></option> + <option><name>AM</name><value>am</value></option> + <option><name>AR</name><value>ar</value></option> + <option><name>AE</name><value>ae</value></option> + <option><name>AERO</name><value>aero</value></option> + <option><name>AG</name><value>ag</value></option> + <option><name>AL</name><value>al</value></option> + <option><name>AM</name><value>am</value></option> + <option><name>AR</name><value>ar</value></option> + <option><name>ASIA</name><value>asia</value></option> + <option><name>AT</name><value>at</value></option> + <option><name>AU (16)</name><value>au</value></option> + <option><name>AZ</name><value>az</value></option> + <option><name>BA</name><value>ba</value></option> + <option><name>BD</name><value>bd</value></option> + <option><name>BE</name><value>be</value></option> + <option><name>BG</name><value>bg</value></option> + <option><name>BIZ</name><value>biz</value></option> + <option><name>BO</name><value>bo</value></option> + <option><name>BR (7)</name><value>br</value></option> + <option><name>BY</name><value>by</value></option> + <option><name>BZ</name><value>bz</value></option> + <option><name>CA (21)</name><value>ca</value></option> + <option><name>CAT</name><value>cat</value></option> + <option><name>CC</name><value>cc</value></option> + <option><name>CF</name><value>cf</value></option> + <option><name>CH</name><value>ch</value></option> + <option><name>CL</name><value>cl</value></option> + <option><name>CLUB</name><value>club</value></option> + <option><name>CN (14)</name><value>cn</value></option> + <option><name>CO (22)</name><value>co</value></option> + <option><name>COM (1)</name><value>com</value></option> + <option><name>COOP</name><value>coop</value></option> + <option><name>CR</name><value>cr</value></option> + <option><name>CU</name><value>cu</value></option> + <option><name>CY</name><value>cy</value></option> + <option><name>CZ (23)</name><value>cz</value></option> + <option><name>DE (5)</name><value>de</value></option> + <option><name>DEV</name><value>dev</value></option> + <option><name>DK</name><value>dk</value></option> + <option><name>DO</name><value>do</value></option> + <option><name>DZ</name><value>dz</value></option> + <option><name>EC</name><value>ec</value></option> + <option><name>EDU</name><value>edu</value></option> + <option><name>EE</name><value>ee</value></option> + <option><name>EG</name><value>eg</value></option> + <option><name>ES (18)</name><value>es</value></option> + <option><name>EU (25)</name><value>eu</value></option> + <option><name>FI</name><value>fi</value></option> + <option><name>FM</name><value>fm</value></option> + <option><name>FR (12)</name><value>fr</value></option> + <option><name>GA</name><value>ga</value></option> + <option><name>GE</name><value>ge</value></option> + <option><name>GOV</name><value>gov</value></option> + <option><name>GR (20)</name><value>gr</value></option> + <option><name>GT</name><value>gt</value></option> + <option><name>GURU</name><value>guru</value></option> + <option><name>HK</name><value>hk</value></option> + <option><name>HR</name><value>hr</value></option> + <option><name>HU</name><value>hu</value></option> + <option><name>ID</name><value>id</value></option> + <option><name>IE</name><value>ie</value></option> + <option><name>IL</name><value>il</value></option> + <option><name>IM</name><value>im</value></option> + <option><name>IN (9)</name><value>in</value></option> + <option><name>INFO (15)</name><value>info</value></option> + <option><name>INT</name><value>int</value></option> + <option><name>IO</name><value>io</value></option> + <option><name>IR (13)</name><value>ir</value></option> + <option><name>IS</name><value>is</value></option> + <option><name>IT (11)</name><value>it</value></option> + <option><name>JO</name><value>jo</value></option> + <option><name>JOBS</name><value>jobs</value></option> + <option><name>JP (6)</name><value>jp</value></option> + <option><name>KE</name><value>ke</value></option> + <option><name>KG</name><value>kg</value></option> + <option><name>KR (19)</name><value>kr</value></option> + <option><name>KW</name><value>kw</value></option> + <option><name>KZ</name><value>kz</value></option> + <option><name>LA</name><value>la</value></option> + <option><name>LI</name><value>li</value></option> + <option><name>LINK</name><value>link</value></option> + <option><name>LK</name><value>lk</value></option> + <option><name>LT</name><value>lt</value></option> + <option><name>LU</name><value>lu</value></option> + <option><name>LV</name><value>lv</value></option> + <option><name>LY</name><value>ly</value></option> + <option><name>MA</name><value>ma</value></option> + <option><name>MD</name><value>md</value></option> + <option><name>ME</name><value>me</value></option> + <option><name>MK</name><value>mk</value></option> + <option><name>ML</name><value>ml</value></option> + <option><name>MN</name><value>mn</value></option> + <option><name>MOBI</name><value>mobi</value></option> + <option><name>MX</name><value>mx</value></option> + <option><name>MY</name><value>my</value></option> + <option><name>NAME</name><value>name</value></option> + <option><name>NET (2)</name><value>net</value></option> + <option><name>NG</name><value>ng</value></option> + <option><name>NINJA</name><value>ninja</value></option> + <option><name>NL (17)</name><value>nl</value></option> + <option><name>NO</name><value>no</value></option> + <option><name>NP</name><value>np</value></option> + <option><name>NU</name><value>nu</value></option> + <option><name>NZ</name><value>nz</value></option> + <option><name>OM</name><value>om</value></option> + <option><name>ORG (4)</name><value>org</value></option> + <option><name>PA</name><value>pa</value></option> + <option><name>PE</name><value>pe</value></option> + <option><name>PH</name><value>ph</value></option> + <option><name>PK</name><value>pk</value></option> + <option><name>PL (10)</name><value>pl</value></option> + <option><name>PRO</name><value>pro</value></option> + <option><name>PT</name><value>pt</value></option> + <option><name>PW</name><value>pw</value></option> + <option><name>PY</name><value>py</value></option> + <option><name>QA</name><value>qa</value></option> + <option><name>RO</name><value>ro</value></option> + <option><name>RS</name><value>rs</value></option> + <option><name>RU (3)</name><value>ru</value></option> + <option><name>SA</name><value>sa</value></option> + <option><name>SE</name><value>se</value></option> + <option><name>SG</name><value>sg</value></option> + <option><name>SI</name><value>si</value></option> + <option><name>SK</name><value>sk</value></option> + <option><name>SO</name><value>so</value></option> + <option><name>SPACE</name><value>space</value></option> + <option><name>SU</name><value>su</value></option> + <option><name>TH</name><value>th</value></option> + <option><name>TK</name><value>tk</value></option> + <option><name>TN</name><value>tn</value></option> + <option><name>TO</name><value>to</value></option> + <option><name>TODAY</name><value>today</value></option> + <option><name>TOP</name><value>top</value></option> + <option><name>TR</name><value>tr</value></option> + <option><name>TRAVEL</name><value>travel</value></option> + <option><name>TV</name><value>tv</value></option> + <option><name>TW (24)</name><value>tw</value></option> + <option><name>TZ</name><value>tz</value></option> + <option><name>UA</name><value>ua</value></option> + <option><name>UK (8)</name><value>uk</value></option> + <option><name>US</name><value>us</value></option> + <option><name>UY</name><value>uy</value></option> + <option><name>UZ</name><value>uz</value></option> + <option><name>VC</name><value>vc</value></option> + <option><name>VE</name><value>ve</value></option> + <option><name>VN</name><value>vn</value></option> + <option><name>WEBSITE</name><value>website</value></option> + <option><name>WS</name><value>ws</value></option> + <option><name>XN--P1AI</name><value>xn--p1ai</value></option> + <option><name>XXX</name><value>xxx</value></option> + <option><name>XYZ</name><value>xyz</value></option> + <option><name>ZA</name><value>za</value></option> + </options> + <default_value><![CDATA[com,net,org,ca,co,io]]></default_value> + <size>10</size> + <multiple/> + </field> + <field> + <name><![CDATA[Custom Domain Suppression]]></name> + <type>listtopic</type> + </field> + <field> + <fielddescr>Custom List</fielddescr> + <fieldname>suppression</fieldname> + <description><![CDATA[No Regex Entries Allowed!<br /><br /> + Enter one   <strong>Domain Name</strong>  per line<br /> + You may use "<strong>#</strong>" after any Domain name to add comments. example ( google.com # Suppress Google.com )<br /> + This List is stored as 'Base64' format in the config.xml file.<br /><br /> + <font color='red'>Note: </font>These entries are only suppressed when Feeds are downloaded or on a + <font color='red'>'Force Reload'.</font><br /> + Use the Alerts Tab '+' Suppression icon to immediately remove a domain from Unbound DNSBL.]]> + </description> + <type>textarea</type> + <cols>50</cols> + <rows>25</rows> + <encoding>base64</encoding> + </field> + <field> + <name><![CDATA[<center>Click to SAVE Settings and/or Rule Edits.   Changes are Applied via CRON or + 'Force Update'</center>]]></name> + <type>listtopic</type> + </field> + </fields> + <custom_php_validation_command> + <![CDATA[ + pfblockerng_validate_input($_POST, $input_errors); + ]]> + </custom_php_validation_command> + <custom_php_resync_config_command> + <![CDATA[ + global $pfb; + $pfb['save'] = TRUE; + sync_package_pfblockerng(); + ]]> + </custom_php_resync_config_command> +</packagegui>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng_dnsbl_easylist.xml b/config/pfblockerng/pfblockerng_dnsbl_easylist.xml new file mode 100644 index 00000000..f416e7d8 --- /dev/null +++ b/config/pfblockerng/pfblockerng_dnsbl_easylist.xml @@ -0,0 +1,284 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE packagegui SYSTEM "../schema/packages.dtd"> +<?xml-stylesheet type="text/xsl" href="../xsl/package.xsl"?> +<packagegui> + <copyright> + <![CDATA[ +/* ========================================================================== */ +/* + pfBlockerNG_dnsbl_easylist.xml + + pfBlockerNG + Copyright (c) 2015 BBcan177@gmail.com + All rights reserved. + +*/ +/* ========================================================================== */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +/* ========================================================================== */ + ]]> + </copyright> + <description>Describe your package here</description> + <requirements>Describe your package requirements here</requirements> + <faq>Currently there are no FAQ items provided.</faq> + <name>pfblockerngdnsbleasylist</name> + <version>1.0</version> + <title>pfBlockerNG: DNSBL: EasyList</title> + <include_file>/usr/local/pkg/pfblockerng/pfblockerng.inc</include_file> + <addedit_string>pfBlockerNG: Save DNSBL Easylist settings</addedit_string> + <menu> + <name>pfBlockerNG</name> + <tooltiptext></tooltiptext> + <section>Firewall</section> + <configfile>pfblockerng_dnsbl_easylist.xml</configfile> + </menu> + <tabs> + <tab> + <text>General</text> + <url>/pkg_edit.php?xml=pfblockerng.xml</url> + <tooltiptext></tooltiptext> + </tab> + <tab> + <text>Update</text> + <url>/pfblockerng/pfblockerng_update.php</url> + </tab> + <tab> + <text>Alerts</text> + <url>/pfblockerng/pfblockerng_alerts.php</url> + </tab> + <tab> + <text>Reputation</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml</url> + </tab> + <tab> + <text>IPv4</text> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml</url> + </tab> + <tab> + <text>IPv6</text> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml</url> + </tab> + <tab> + <text>DNSBL</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl.xml</url> + </tab> + <tab> + <text>Country</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml</url> + </tab> + <tab> + <text>Logs</text> + <url>/pfblockerng/pfblockerng_log.php</url> + </tab> + <tab> + <text>Sync</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml</url> + </tab> + <tab> + <text>DNSBL</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl.xml</url> + <tab_level>2</tab_level> + </tab> + <tab> + <text>DNSBL Feeds</text> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_dnsbl_lists.xml</url> + <tab_level>2</tab_level> + </tab> + <tab> + <text>DNSBL EasyList</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl_easylist.xml</url> + <tab_level>2</tab_level> + <active/> + </tab> + </tabs> + <fields> + <field> + <name><![CDATA[DNSBL - EasyList   Run 'Force Update' to deploy new Settings.]]></name> + <type>listtopic</type> + </field> + <field> + <fielddescr>LINKS</fielddescr> + <fieldname></fieldname> + <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a>  + <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> + </description> + <type>info</type> + </field> + <field> + <fielddescr>DNS GROUP Name</fielddescr> + <fieldname>aliasname</fieldname> + <description><![CDATA[Enter DNS Group Name.  Example: EasyList]]></description> + <type>input</type> + <size>20</size> + </field> + <field> + <fielddescr>Description</fielddescr> + <fieldname>description</fieldname> + <type>input</type> + <size>90</size> + </field> + <field> + <fielddescr><![CDATA[<strong>EasyList Feeds</strong>]]></fielddescr> + <description><![CDATA[Add Easylist Feed]]></description> + <fieldname></fieldname> + <type>rowhelper</type> + <rowhelper> + <rowhelperfield> + <fielddescr>State</fielddescr> + <fieldname>state</fieldname> + <type>select</type> + <options> + <option><name>ON</name><value>Enabled</value></option> + <option><name>OFF</name><value>Disabled</value></option> + <option><name>HOLD</name><value>Hold</value></option> + <option><name>FLEX</name><value>Flex</value></option> + </options> + </rowhelperfield> + <rowhelperfield> + <fielddescr>EasyList Feed</fielddescr> + <fieldname>url</fieldname> + <type>select</type> + <options> + <option> + <name>EasyList w/o Elements</name> + <value>https://easylist-downloads.adblockplus.org/easylist_noelemhide.txt</value> + </option> + <option> + <name>EasyPrivacy</name> + <value>https://easylist-downloads.adblockplus.org/easyprivacy.txt</value> + </option> + </options> + </rowhelperfield> + <rowhelperfield> + <fielddescr>Header</fielddescr> + <fieldname>header</fieldname> + <type>input</type> + <size>15</size> + </rowhelperfield> + </rowhelper> + </field> + <field> + <name><![CDATA[DNSBL - EasyList Settings]]></name> + <type>listtopic</type> + </field> + <field> + <fielddescr>Categories</fielddescr> + <description><![CDATA[Select the categories you wish to block that match the EasyList Feeds selected above.<br /><br /> + DNSBL EasyList utilizing the following hardcoded URLs:  + <a href="https://easylist-downloads.adblockplus.org/easylist_noelemhide.txt" target="_blank" >EasyList w/o Elements |</a> + <a href="https://easylist-downloads.adblockplus.org/easyprivacy.txt" target="_blank" >EasyPrivacy</a><br /> + List distributed under the Creative Commons Attribution-ShareAlike License. + <a href="https://easylist.adblockplus.org/" target="_blank" >(Credits)</a><br /><br /> + <strong>Use CTRL + CLICK to select/unselect the EasyList categories.</strong>]]> + </description> + <fieldname>easycat</fieldname> + <type>select</type> + <options> + <option><name>EASYLIST Adservers</name><value>ea</value></option> + <option><name>EASYLIST Adservers Popup</name><value>eap</value></option> + <option><name>EASYLIST Adult Adservers</name><value>aa</value></option> + <option><name>EASYLIST Adult Adservers Popup</name><value>aap</value></option> + <option><name>EASYPRIVACY Tracking Servers</name><value>epts</value></option> + <option><name>EASYPRIVACY Tracking International</name><value>epti</value></option> + </options> + <size>6</size> + <multiple/> + </field> + <field> + <fielddescr>List Action</fielddescr> + <description><![CDATA[Default: <strong>Disabled</strong><br /> + Select <strong>Unbound</strong> to enable 'DNSBL' blocking for this Alias.]]> + </description> + <fieldname>action</fieldname> + <type>select</type> + <options> + <option><name>Disabled</name><value>Disabled</value></option> + <option><name>Unbound</name><value>unbound</value></option> + </options> + </field> + <field> + <fielddescr>Update Frequency</fielddescr> + <fieldname>cron</fieldname> + <description><![CDATA[Default: <strong>Never</strong><br /> + Select how often Feed will be downloaded. <strong>This must be within the Cron Interval/Start Hour settings.</strong>]]> + </description> + <type>select</type> + <options> + <option><name>Never</name><value>Never</value></option> + <option><name>Every Hour</name><value>01hour</value></option> + <option><name>Every 2 Hours</name><value>02hours</value></option> + <option><name>Every 3 Hours</name><value>03hours</value></option> + <option><name>Every 4 Hours</name><value>04hours</value></option> + <option><name>Every 6 Hours</name><value>06hours</value></option> + <option><name>Every 8 Hours</name><value>08hours</value></option> + <option><name>Every 12 Hours</name><value>12hours</value></option> + <option><name>Once a day</name><value>EveryDay</value></option> + <option><name>Weekly</name><value>Weekly</value></option> + </options> + </field> + <field> + <fielddescr>Weekly (Day of Week)</fielddescr> + <fieldname>dow</fieldname> + <description><![CDATA[Default: <strong>Monday</strong><br /> + Select the 'Weekly' ( Day of the Week ) to Update <br /> + This is only required for the 'Weekly' Frequency Selection. The 24 Hour Download 'Time' will be used.]]> + </description> + <type>select</type> + <options> + <option><name>Monday</name><value>1</value></option> + <option><name>Tuesday</name><value>2</value></option> + <option><name>Wednesday</name><value>3</value></option> + <option><name>Thursday</name><value>4</value></option> + <option><name>Friday</name><value>5</value></option> + <option><name>Saturday</name><value>6</value></option> + <option><name>Sunday</name><value>7</value></option> + </options> + </field> + <field> + <fielddescr>Enable Alexa Whitelist</fielddescr> + <fieldname>filter_alexa</fieldname> + <description>Filter Alias via Alexa</description> + <type>checkbox</type> + </field> + <field> + <name><![CDATA[<center>Click to SAVE Settings and/or Rule Edits.   Changes are Applied via CRON or + 'Force Update'</center>]]></name> + <type>listtopic</type> + </field> + </fields> + <custom_php_validation_command> + <![CDATA[ + pfblockerng_validate_input($_POST, $input_errors); + ]]> + </custom_php_validation_command> + <custom_php_resync_config_command> + <![CDATA[ + global $pfb; + $pfb['save'] = TRUE; + sync_package_pfblockerng(); + ]]> + </custom_php_resync_config_command> +</packagegui>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng_dnsbl_lists.xml b/config/pfblockerng/pfblockerng_dnsbl_lists.xml new file mode 100644 index 00000000..0519e01a --- /dev/null +++ b/config/pfblockerng/pfblockerng_dnsbl_lists.xml @@ -0,0 +1,335 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE packagegui SYSTEM "../schema/packages.dtd"> +<?xml-stylesheet type="text/xsl" href="../xsl/package.xsl"?> +<packagegui> + <copyright> + <![CDATA[ +/* ========================================================================== */ +/* + pfBlockerNG_dnsbl_lists.xml + + pfBlockerNG + Copyright (c) 2015 BBcan177@gmail.com + All rights reserved. + +*/ +/* ========================================================================== */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +/* ========================================================================== */ + ]]> + </copyright> + <description>Describe your package here</description> + <requirements>Describe your package requirements here</requirements> + <faq>Currently there are no FAQ items provided.</faq> + <name>pfblockerngdnsbl</name> + <version>1.0</version> + <title>pfBlockerNG: DNSBL: Lists</title> + <include_file>/usr/local/pkg/pfblockerng/pfblockerng.inc</include_file> + <addedit_string>pfBlockerNG: Save DNSBL Feeds settings</addedit_string> + <menu> + <name>pfBlockerNG</name> + <section>Firewall</section> + <configfile>pfblockerng_dnsbl_lists.xml</configfile> + </menu> + <tabs> + <tab> + <text>General</text> + <url>/pkg_edit.php?xml=pfblockerng.xml</url> + </tab> + <tab> + <text>Update</text> + <url>/pfblockerng/pfblockerng_update.php</url> + </tab> + <tab> + <text>Alerts</text> + <url>/pfblockerng/pfblockerng_alerts.php</url> + </tab> + <tab> + <text>Reputation</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml</url> + </tab> + <tab> + <text>IPv4</text> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml</url> + </tab> + <tab> + <text>IPv6</text> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml</url> + </tab> + <tab> + <text>DNSBL</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl.xml</url> + </tab> + <tab> + <text>Country</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml</url> + </tab> + <tab> + <text>Logs</text> + <url>/pfblockerng/pfblockerng_log.php</url> + </tab> + <tab> + <text>Sync</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml</url> + </tab> + <tab> + <text>DNSBL</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl.xml</url> + <tab_level>2</tab_level> + </tab> + <tab> + <text>DNSBL Feeds</text> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_dnsbl_lists.xml</url> + <tab_level>2</tab_level> + <active/> + </tab> + <tab> + <text>DNSBL EasyList</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl_easylist.xml</url> + <tab_level>2</tab_level> + </tab> + </tabs> + <adddeleteeditpagefields> + <columnitem> + <fielddescr>DNS Group Name</fielddescr> + <fieldname>aliasname</fieldname> + </columnitem> + <columnitem> + <fielddescr>DNS Group Description</fielddescr> + <fieldname>description</fieldname> + </columnitem> + <columnitem> + <fielddescr>Action</fielddescr> + <fieldname>action</fieldname> + </columnitem> + <columnitem> + <fielddescr>Frequency</fielddescr> + <fieldname>cron</fieldname> + </columnitem> + <addtext>Add a new Alias</addtext> + <movable>on</movable> + </adddeleteeditpagefields> + <fields> + <field> + <name><![CDATA[DNS Domain Name Block List   Run 'Force Update' to deploy new Settings.]]></name> + <type>listtopic</type> + </field> + <field> + <fielddescr>LINKS</fielddescr> + <fieldname></fieldname> + <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a>  + <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> + </description> + <type>info</type> + </field> + <field> + <fielddescr>DNS GROUP Name</fielddescr> + <fieldname>aliasname</fieldname> + <description><![CDATA[Enter DNS Group Name.  Example: Ads]]></description> + <type>input</type> + <size>20</size> + </field> + <field> + <fielddescr>Description</fielddescr> + <fieldname>description</fieldname> + <type>input</type> + <size>90</size> + </field> + <field> + <fieldname>InfoLists</fieldname> + <type>info</type> + <description><![CDATA[<strong><u>'Format'</u></strong>: Select the Format type.<br /><br /> + <strong><u>'State'</u></strong>: Select the run state.<br /><br /> + <strong><u>'Source'</u></strong>: + <ul><li><strong>'URL'</strong>: External link to source: + Example: <a target="_blank" href='http://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&mimetype=plaintext'>yoyo</a>, + <a target="_blank" href='http://someonewhocares.org/hosts/hosts'>SomeoneWhoCares</a>, + <a target="_blank" href='https://adaway.org/hosts.txt'>Adaway</a></li></ul> + <ul><li><strong>'Local File'</strong>: http(s)://127.0.0.1/filename +  <strong>or</strong>  /var/db/pfblockerng/filename</li></ul> + + <strong><u>'Header/Label'</u></strong>: This field must be <u>unique.</u> This names the file and is referenced in the widget. + (ie: hpHosts_ads, hpHosts_partial)<br /><br /> + + <strong>AdBlock Easylists <u>cannot</u> be used in this Tab</strong><br /><br />]]> + </description> + </field> + <field> + <fielddescr><![CDATA[<strong>DNSBL</strong>]]></fielddescr> + <description><![CDATA[<br /><strong>'Format'</strong>: Select the file format that URL will retrieve.<br /> + <ul><li><strong>'auto'</strong> - Default parser</li> + <li><strong>'rsync'</strong> - RSync Lists</li></ul> + <strong>'State'</strong>: Select the Run State for each list.<br /> + <ul><li><strong>'ON/OFF'</strong> - Enabled / Disabled</li> + <li><strong>'HOLD'</strong> - Once a List has been Downloaded, list will remain Static.</li> + <li><strong>'FLEX'</strong> - Not Recommended - Allow lower SSL connections</li></ul> + <strong>'Note'</strong>: Downloaded or pfsense local file must have only one Domain Name per line.]]> + </description> + <type>rowhelper</type> + <sortablefields/> + <rowhelper> + <rowhelperfield> + <fielddescr>Format</fielddescr> + <fieldname>format</fieldname> + <type>select</type> + <options> + <option><name>Auto</name><value>auto</value></option> + <option><name>RSync</name><value>rsync</value></option> + </options> + <default_value>auto</default_value> + </rowhelperfield> + <rowhelperfield> + <fielddescr>State</fielddescr> + <fieldname>state</fieldname> + <type>select</type> + <options> + <option><name>ON</name><value>Enabled</value></option> + <option><name>OFF</name><value>Disabled</value></option> + <option><name>HOLD</name><value>Hold</value></option> + <option><name>FLEX</name><value>Flex</value></option> + </options> + <default_value>Enabled</default_value> + </rowhelperfield> + <rowhelperfield> + <fielddescr>Source</fielddescr> + <fieldname>url</fieldname> + <type>input</type> + <size>50</size> + </rowhelperfield> + <rowhelperfield> + <fielddescr>Header/Label</fielddescr> + <fieldname>header</fieldname> + <type>input</type> + <size>15</size> + <sortablefields/> + </rowhelperfield> + </rowhelper> + </field> + <field> + <fielddescr>List Action</fielddescr> + <description><![CDATA[Default: <strong>Disabled</strong><br /> + Select <strong>Unbound</strong> to enable 'Domain Name' blocking for this Alias.]]> + </description> + <fieldname>action</fieldname> + <type>select</type> + <options> + <option><name>Disabled</name><value>Disabled</value></option> + <option><name>Unbound</name><value>unbound</value></option> + </options> + </field> + <field> + <fielddescr>Update Frequency</fielddescr> + <fieldname>cron</fieldname> + <description><![CDATA[Default: <strong>Never</strong><br /> + Select how often List files will be downloaded. <strong>This must be within the Cron Interval/Start Hour settings.</strong>]]> + </description> + <type>select</type> + <options> + <option><name>Never</name><value>Never</value></option> + <option><name>Every Hour</name><value>01hour</value></option> + <option><name>Every 2 Hours</name><value>02hours</value></option> + <option><name>Every 3 Hours</name><value>03hours</value></option> + <option><name>Every 4 Hours</name><value>04hours</value></option> + <option><name>Every 6 Hours</name><value>06hours</value></option> + <option><name>Every 8 Hours</name><value>08hours</value></option> + <option><name>Every 12 Hours</name><value>12hours</value></option> + <option><name>Once a day</name><value>EveryDay</value></option> + <option><name>Weekly</name><value>Weekly</value></option> + </options> + </field> + <field> + <fielddescr>Weekly (Day of Week)</fielddescr> + <fieldname>dow</fieldname> + <description><![CDATA[Default: <strong>Monday</strong><br /> + Select the 'Weekly' ( Day of the Week ) to Update <br /> + This is only required for the 'Weekly' Frequency Selection. The 24 Hour Download 'Time' will be used.]]> + </description> + <type>select</type> + <options> + <option><name>Monday</name><value>1</value></option> + <option><name>Tuesday</name><value>2</value></option> + <option><name>Wednesday</name><value>3</value></option> + <option><name>Thursday</name><value>4</value></option> + <option><name>Friday</name><value>5</value></option> + <option><name>Saturday</name><value>6</value></option> + <option><name>Sunday</name><value>7</value></option> + </options> + </field> + <field> + <fielddescr>Enable Alexa Whitelist</fielddescr> + <fieldname>filter_alexa</fieldname> + <description>Filter Alias via Alexa</description> + <type>checkbox</type> + </field> + <field> + <name><![CDATA[Custom Block List]]></name> + <type>listtopic</type> + </field> + <field> + <fielddescr>Custom Domain Name Block List</fielddescr> + <fieldname>custom</fieldname> + <description><![CDATA[No Regex Entries Allowed!<br /><br /> + Enter one   <strong>'Domain Name'</strong>   per line<br /><br /> + You may use "<strong>#</strong>" after any Domain name to add comments. example ( ads.google.com # Block Google Ads )<br /> + This List is stored as 'Base64' format in the config.xml file.]]> + </description> + <type>textarea</type> + <cols>80</cols> + <rows>20</rows> + <encoding>base64</encoding> + </field> + <field> + <fielddescr>Update Custom List</fielddescr> + <fieldname>custom_update</fieldname> + <description><![CDATA[Select - '<strong>Default</strong>' to update Custom List as per Update Frequency setting.<br /> + Select - '<strong>Update Custom List</strong>' followed by a 'Force Update' to apply Custom List Changes.<br /> + Cron will also resync this Custom List at the next Update Frequency.]]> + </description> + <type>select</type> + <options> + <option><name>Default</name><value>disabled</value></option> + <option><name>Update Custom List</name><value>enabled</value></option> + </options> + </field> + <field> + <name><![CDATA[<center>Click to SAVE Settings and/or Rule Edits.   Changes are Applied via CRON or + 'Force Update'</center>]]></name> + <type>listtopic</type> + </field> + </fields> + <custom_php_validation_command> + <![CDATA[ + pfblockerng_validate_input($_POST, $input_errors); + ]]> + </custom_php_validation_command> + <custom_php_resync_config_command> + <![CDATA[ + global $pfb; + $pfb['save'] = TRUE; + sync_package_pfblockerng(); + ]]> + </custom_php_resync_config_command> +</packagegui>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng_extra.inc b/config/pfblockerng/pfblockerng_extra.inc new file mode 100644 index 00000000..576f1bc8 --- /dev/null +++ b/config/pfblockerng/pfblockerng_extra.inc @@ -0,0 +1,131 @@ +<?php +/* + pfBlockerNG_extra.inc + + pfBlockerNG + Copyright (c) 2015 BBcan177@gmail.com + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +*/ + +// This file is used to 'include functions' not yet merged into pfSense + + +// IPv6 Range to CIDR function used courtesey from: +// https://github.com/stilez/pfsense-leases/blob/50cc0fa81dba5fe91bcddaea016c245d1b8479cc/etc/inc/util.inc +function ip_range_to_subnet_array_temp($ip1, $ip2) { + + if (is_ipaddrv4($ip1) && is_ipaddrv4($ip2)) { + $proto = 'ipv4'; // for clarity + $bits = 32; + $ip1bin = decbin(ip2long32($ip1)); + $ip2bin = decbin(ip2long32($ip2)); + } elseif (is_ipaddrv6($ip1) && is_ipaddrv6($ip2)) { + $proto = 'ipv6'; + $bits = 128; + $ip1bin = Net_IPv6::_ip2Bin($ip1); + $ip2bin = Net_IPv6::_ip2Bin($ip2); + } else + return array(); + + // it's *crucial* that binary strings are guaranteed the expected length; do this for certainty even though for IPv6 it's redundant + $ip1bin = str_pad($ip1bin, $bits, '0', STR_PAD_LEFT); + $ip2bin = str_pad($ip2bin, $bits, '0', STR_PAD_LEFT); + + if ($ip1bin === $ip2bin) + return array($ip1 . '/' . $bits); + + if (strcmp($ip1bin, $ip2bin) > 0) + list ($ip1bin, $ip2bin) = array($ip2bin, $ip1bin); // swap contents of ip1 <= ip2 + + $rangesubnets = array(); + $netsize = 0; + + do { + // at loop start, $ip1 is guaranteed strictly less than $ip2 (important for edge case trapping and preventing accidental binary wrapround) + // which means the assignments $ip1 += 1 and $ip2 -= 1 will always be "binary-wrapround-safe" + + // step #1 if start ip (as shifted) ends in any '1's, then it must have a single cidr to itself (any cidr would include the '0' below it) + + if (substr($ip1bin, -1, 1) == '1') { + // the start ip must be in a separate one-IP cidr range + $new_subnet_ip = substr($ip1bin, $netsize, $bits - $netsize) . str_repeat('0', $netsize); + $rangesubnets[$new_subnet_ip] = $bits - $netsize; + $n = strrpos($ip1bin, '0'); //can't be all 1's + $ip1bin = ($n == 0 ? '' : substr($ip1bin, 0, $n)) . '1' . str_repeat('0', $bits - $n - 1); // BINARY VERSION OF $ip1 += 1 + } + + // step #2, if end ip (as shifted) ends in any zeros then that must have a cidr to itself (as cidr cant span the 1->0 gap) + + if (substr($ip2bin, -1, 1) == '0') { + // the end ip must be in a separate one-IP cidr range + $new_subnet_ip = substr($ip2bin, $netsize, $bits - $netsize) . str_repeat('0', $netsize); + $rangesubnets[$new_subnet_ip] = $bits - $netsize; + $n = strrpos($ip2bin, '1'); //can't be all 0's + $ip2bin = ($n == 0 ? '' : substr($ip2bin, 0, $n)) . '0' . str_repeat('1', $bits - $n - 1); // BINARY VERSION OF $ip2 -= 1 + // already checked for the edge case where end = start+1 and start ends in 0x1, above, so it's safe + } + + // this is the only edge case arising from increment/decrement. + // it happens if the range at start of loop is exactly 2 adjacent ips, that spanned the 1->0 gap. (we will have enumerated both by now) + + if (strcmp($ip2bin, $ip1bin) < 0) + continue; + + // step #3 the start and end ip MUST now end in '0's and '1's respectively + // so we have a non-trivial range AND the last N bits are no longer important for CIDR purposes. + + $shift = $bits - max(strrpos($ip1bin, '0'), strrpos($ip2bin, '1')); // num of low bits which are '0' in ip1 and '1' in ip2 + $ip1bin = str_repeat('0', $shift) . substr($ip1bin, 0, $bits - $shift); + $ip2bin = str_repeat('0', $shift) . substr($ip2bin, 0, $bits - $shift); + $netsize += $shift; + if ($ip1bin === $ip2bin) { + // we're done. + $new_subnet_ip = substr($ip1bin, $netsize, $bits - $netsize) . str_repeat('0', $netsize); + $rangesubnets[$new_subnet_ip] = $bits - $netsize; + continue; + } + + // at this point there's still a remaining range, and either startip ends with '1', or endip ends with '0'. So repeat cycle. + } while (strcmp($ip1bin, $ip2bin) < 0); + + // subnets are ordered by bit size. Re sort by IP ("naturally") and convert back to IPv4/IPv6 + + ksort($rangesubnets, SORT_STRING); + $out = array(); + + foreach ($rangesubnets as $ip => $netmask) { + if ($proto == 'ipv4') { + $i = str_split($ip, 8); + $out[] = implode('.', array( bindec($i[0]),bindec($i[1]),bindec($i[2]),bindec($i[3]))) . '/' . $netmask; + } else + $out[] = Net_IPv6::compress(Net_IPv6::_bin2Ip($ip)) . '/' . $netmask; + } + + return $out; +} + +?>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng_install.inc b/config/pfblockerng/pfblockerng_install.inc index 28fe373f..d8a2bdae 100644 --- a/config/pfblockerng/pfblockerng_install.inc +++ b/config/pfblockerng/pfblockerng_install.inc @@ -3,7 +3,7 @@ pfBlockerNG_install.inc pfBlockerNG - Copyright (C) 2015 BBcan177@gmail.com + Copyright (c) 2015 BBcan177@gmail.com All rights reserved. Redistribution and use in source and binary forms, with or without @@ -31,52 +31,173 @@ */ -// Install pfBlockerNG package, launched from pfblockerng.xml - require_once('/usr/local/pkg/pfblockerng/pfblockerng.inc'); require_once('/usr/local/www/pfblockerng/pfblockerng.php'); -global $config, $pfb; +global $config, $pfb, $static_output; pfb_global(); -// Remove previously used CC folder location if exists -@rmdir_recursive("{$pfb['dbdir']}/cc"); +function update_static_output($text) { + global $static_output; + + $static_output .= "{$text}"; + update_output_window("{$static_output}"); + return; +} + + +// Set 'Install flag' to skip sync process during installations. +$g['pfblockerng_install'] = true; + +// Remove previous ccdir location files if exist +$old_ccfiles = glob('/usr/pbi/pfblockerng-' . php_uname('m') . '/share/GeoIP/*_v?.txt'); +if (!empty($old_ccfiles)) { + foreach ($old_ccfiles as $oldfile) { + unlink_if_exists("{$oldfile}"); + } +} + +update_static_output("\nDownloading MaxMind Country databases.\n This may take a minute..."); -// Uncompress Country Code File -@copy("{$pfb['dbdir']}/countrycodes.tar.bz2", "{$pfb['ccdir']}/countrycodes.tar.bz2"); -exec("/usr/bin/tar -jx -C {$pfb['ccdir']} -f {$pfb['ccdir']}/countrycodes.tar.bz2"); -// Download MaxMind Files and Create Country Code files and Build Continent XML Files -update_output_window(gettext("Downloading MaxMind Country Databases. This may take a minute...")); -exec("/bin/sh /usr/local/pkg/pfblockerng/geoipupdate.sh all >> {$pfb['geolog']} 2>&1"); +// Only Download the MaxMind Database files (Skip Alexa) +unset($pfb['extras'][5]); + +if (!pfblockerng_download_extras()) { + update_static_output(" MaxMind download failed!\nFetching MaxMind archive from pfSense package repo..."); + // Fetch archived MaxMind database + $url = 'https://packages.pfsense.org/packages/config/pfblockerng/countrycodes.tar.bz2'; + exec("/usr/bin/fetch -o /tmp/countrycodes.tar.bz2 {$url}"); + // Uncompress archived Country code file + exec("/usr/bin/tar -jx -C {$pfb['ccdir']} -f /tmp/countrycodes.tar.bz2"); + update_static_output(" done.\n"); +} +else { + update_static_output(" done.\n"); +} -update_output_window(gettext("MaxMind Country Database downloads completed...")); -update_output_window(gettext("Converting MaxMind Country Databases for pfBlockerNG. This may take a few minutes...")); +update_static_output("Converting MaxMind Country databases for pfBlockerNG.\n This may take a few minutes..."); pfblockerng_uc_countries(); -update_output_window(gettext("Creating pfBlockerNG Continent XML Files...")); +update_static_output(" done.\nCreating pfBlockerNG Continent XML files..."); pfblockerng_get_countries(); -update_output_window(gettext("Completed Creating pfBlockerNG Continent XML Files...")); - -// Remove Original Maxmind Database Files -@unlink_if_exists("{$pfb['dbdir']}/GeoIPCountryCSV.zip"); -@unlink_if_exists("{$pfb['dbdir']}/GeoIPCountryWhois.csv"); -@unlink_if_exists("{$pfb['dbdir']}/GeoIPv6.csv"); -@unlink_if_exists("{$pfb['dbdir']}/country_continent.csv"); - -// Add Widget to Dashboard -update_output_window(gettext("Adding pfBlockerNG Widget to Dashboard.")); -if ($pfb['keep'] == "on" && !empty($pfb['widgets'])) { - // Restore previous Widget setting if "Keep" is enabled. + +if ($pfb['keep'] == 'on' && isset($pfb['widgets']) && strpos($pfb['widgets'], 'pfblockerng-container') !== FALSE) { + update_static_output(" done.\nRestoring previous pfBlockerNG Widget settings..."); + // Restore previous widget setting if 'keep' is enabled. $config['widgets']['sequence'] = $pfb['widgets']; + write_config('pfBlockerNG: Save widget'); } else { + update_static_output(" done.\nAdding pfBlockerNG Widget to the Dashboard..."); $widgets = $config['widgets']['sequence']; - if (!preg_match("/pfblockerng-container/", $widgets)) { + if (strpos($widgets, 'pfblockerng-container') === FALSE) { if (empty($widgets)) { - $config['widgets']['sequence'] = "pfblockerng-container:col2:show"; + $config['widgets']['sequence'] = 'pfblockerng-container:col2:show'; } else { - $config['widgets']['sequence'] .= ",pfblockerng-container:col2:show"; + $config['widgets']['sequence'] .= ',pfblockerng-container:col2:show'; } + write_config('pfBlockerNG: Save widget'); + } +} + +update_static_output(" done.\nRemove any existing and create link for DNSBL lighttpd executable..."); +unlink_if_exists('/usr/local/sbin/lighttpd_pfb'); +link('/usr/local/sbin/lighttpd', '/usr/local/sbin/lighttpd_pfb'); + +update_static_output(" done.\nCreating DNSBL web server start-up script..."); +$rc = array(); +$rc['file'] = 'dnsbl.sh'; +$rc['start'] = <<<EOF + + # Start DNSBL Lighttpd webserver + if [ -f '{$pfb['dnsbl_conf']}' ]; then + /usr/local/sbin/lighttpd_pfb -f '{$pfb['dnsbl_conf']}' + fi + + # Terminate DNSBL HTTPS Daemon if found + pidnum="$(/bin/ps -wax | /usr/bin/grep '[p]fblockerng.inc dnsbl' | /usr/bin/awk '{print $1}')" + if [ ! -z "\${pidnum}" ]; then + /bin/kill -9 "\${pidnum}" + /bin/sleep 2 + fi + + # Start DNSBL HTTPS Daemon + /usr/local/bin/php -f /usr/local/pkg/pfblockerng/pfblockerng.inc dnsbl & + +EOF; + +$rc['stop'] = <<<EOF + + # Terminate DNSBL Lighttpd webserver, if found. + pidnum="$(/bin/pgrep lighttpd_pfb)" + if [ ! -z "\${pidnum}" ]; then + /usr/bin/killall lighttpd_pfb + fi + + # Terminate DNSBL HTTPS Daemon, if found. + pidnum="$(/bin/ps -wax | /usr/bin/grep '[p]fblockerng.inc dnsbl' | /usr/bin/awk '{print $1}')" + if [ ! -z "\${pidnum}" ]; then + /bin/kill -9 "\${pidnum}" + /bin/sleep 2 + fi + +EOF; + +write_rcfile($rc); +update_static_output(" done.\n"); + +if ($pfb['enable'] == 'on' && $pfb['dnsbl'] == 'on' && !empty($pfb['dnsbl_port']) && !empty($pfb['dnsbl_port_ssl'])) { + update_static_output("Creating DNSBL web server config ..."); + + $pfb_conf = <<<EOF +# +#pfBlockerNG Lighttpd DNSBL configuration file +# +server.bind = "0.0.0.0" +server.port = "{$pfb['dnsbl_port']}" +server.event-handler = "freebsd-kqueue" +server.network-backend = "freebsd-sendfile" +server.dir-listing = "disable" +server.document-root = "/usr/local/www/pfblockerng/www/" +server.errorlog = "/var/log/pfblockerng/dnsbl_error.log" +server.pid-file = "/var/run/dnsbl.pid" +server.modules = ( "mod_access", "mod_fastcgi", "mod_rewrite" ) + +server.indexfiles = ( "index.php" ) +mimetype.assign = ( ".html" => "text/html", ".gif" => "image/gif" ) +url.access-deny = ( "~", ".inc" ) +fastcgi.server = ( ".php" => ( "localhost" => ( "socket" => "/var/run/php-fpm.socket", "broken-scriptfilename" => "enable" ) ) ) + +debug.log-condition-handling = "enable" + +\$HTTP["host"] =~ ".*" { + url.rewrite-once = ( ".*" => "index.php" ) +} + +\$SERVER["socket"] == "0.0.0.0:{$pfb['dnsbl_port_ssl']}" { + ssl.engine = "enable" + ssl.pemfile = "{$pfb['dnsbl_cert']}" + ssl.use-sslv2 = "disable" + ssl.use-sslv3 = "disable" + ssl.honor-cipher-order = "enable" + ssl.cipher-list = "AES128+EECDH:AES256+EECDH:AES128+EDH:AES256+EDH:AES128-SHA:AES256-SHA:!aNULL:!eNULL:!DSS" + + \$HTTP["host"] =~ ".*" { + url.rewrite-once = ( ".*" => "index.php" ) } } + +EOF; + + @file_put_contents($pfb['dnsbl_conf'], $pfb_conf, LOCK_EX); + unset($pfb_conf); + update_static_output(" done.\n"); + + update_static_output("Starting DNSBL Service..."); + start_service('dnsbl'); + update_static_output(" done.\n"); +} + +unset($g['pfblockerng_install']); // Remove 'Install flag' +update_static_output("Custom commands completed ... "); return TRUE; ?>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng_log.php b/config/pfblockerng/pfblockerng_log.php index a235f20a..9d823038 100644 --- a/config/pfblockerng/pfblockerng_log.php +++ b/config/pfblockerng/pfblockerng_log.php @@ -9,15 +9,16 @@ Portions of this code are based on original work done for the Snort package for pfSense from the following contributors: - Copyright (C) 2005 Bill Marquette <bill.marquette@gmail.com>. - Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>. - Copyright (C) 2006 Scott Ullrich - Copyright (C) 2009 Robert Zelaya Sr. Developer - Copyright (C) 2012 Ermal Luci + Copyright (c) 2015 Electric Sheep Fencing, LLC. All rights reserved. + Copyright (c) 2009 Robert Zelaya Sr. Developer + Copyright (c) 2005 Bill Marquette + Copyright (c) 2004-2005 Scott Ullrich + Copyright (c) 2004 Manuel Kasper (BSD 2 clause) + All rights reserved. Adapted for Suricata by: - Copyright (C) 2015 Bill Meeks + Copyright (c) 2015 Bill Meeks All rights reserved. Javascript and Integration modifications by J. Nieuwenhuizen @@ -46,9 +47,9 @@ POSSIBILITY OF SUCH DAMAGE. */ -require_once("guiconfig.inc"); -require_once("globals.inc"); -require_once("/usr/local/pkg/pfblockerng/pfblockerng.inc"); +require_once('guiconfig.inc'); +require_once('globals.inc'); +require_once('/usr/local/pkg/pfblockerng/pfblockerng.inc'); pfb_global(); @@ -61,10 +62,10 @@ function getlogs($logdir, $log_extentions = array('log')) { // Get logfiles $log_filenames = array(); foreach ($log_extentions as $extention) { - if ($extention <> '*') { - $log_filenames = array_merge($log_filenames, glob($logdir . "*." . $extention)); + if ($extention != '*') { + $log_filenames = array_merge($log_filenames, glob($logdir . '*.' . $extention)); } else { - $log_filenames = array_merge($log_filenames, glob($logdir . "*")); + $log_filenames = array_merge($log_filenames, glob($logdir . '*')); } } @@ -91,22 +92,28 @@ function getlogs($logdir, $log_extentions = array('log')) { $pfb_logtypes = array( 'defaultlogs' => array('name' => 'Log Files', 'logdir' => "{$pfb['logdir']}/", - 'logs' => array("pfblockerng.log", "error.log", "geoip.log", "maxmind_ver"), + 'logs' => array('pfblockerng.log', 'error.log', 'dnsbl.log', 'extras.log', 'maxmind_ver'), 'download' => TRUE, 'clear' => TRUE ), 'masterfiles' => array('name' => 'Masterfiles', 'logdir' => "{$pfb['dbdir']}/", - 'logs' => array("masterfile", "mastercat"), + 'logs' => array('masterfile', 'mastercat'), 'download' => TRUE, 'clear' => FALSE ), - 'originallogs' => array('name' => 'Original Files', + 'originallogs' => array('name' => 'Original IP Files', 'ext' => array('orig', 'raw'), 'logdir' => "{$pfb['origdir']}/", 'download' => TRUE, 'clear' => TRUE ), + 'origdnslogs' => array('name' => 'Original DNS Files', + 'ext' => array('orig', 'raw'), + 'logdir' => "{$pfb['dnsorigdir']}/", + 'download' => TRUE, + 'clear' => TRUE + ), 'denylogs' => array('name' => 'Deny Files', 'ext' => 'txt', 'txt' => 'deny', @@ -114,6 +121,13 @@ $pfb_logtypes = array( 'defaultlogs' => array('name' => 'Log Files', 'download' => TRUE, 'clear' => TRUE ), + 'dnsbl' => array('name' => 'DNSBL Files', + 'ext' => array('txt', 'ip'), + 'txt' => 'dnsbl', + 'logdir' => "{$pfb['dnsdir']}/", + 'download' => TRUE, + 'clear' => TRUE + ), 'permitlogs' => array('name' => 'Permit Files', 'ext' => 'txt', 'txt' => 'permit', @@ -151,13 +165,19 @@ $pfb_logtypes = array( 'defaultlogs' => array('name' => 'Log Files', 'logdir' => "{$pfb['ccdir']}/", 'download' => TRUE, 'clear' => FALSE + ), + 'unbound' => array('name' => 'Unbound', + 'ext' => 'conf', + 'logdir' => "{$pfb['dnsbldir']}/", + 'download' => TRUE, + 'clear' => FALSE ) ); // Check logtypes $logtypeid = 'defaultlogs'; if (isset($_POST['logtype'])) { - $logtypeid = $_POST['logtype']; + $logtypeid = htmlspecialchars($_POST['logtype']); } elseif (isset($_GET['logtype'])) { $logtypeid = htmlspecialchars($_GET['logtype']); } @@ -165,17 +185,17 @@ if (isset($_POST['logtype'])) { // Check if POST has been set if (isset($_POST['file'])) { clearstatcache(); - $pfb_logfilename = $_POST['file']; + $pfb_logfilename = htmlspecialchars($_POST['file']); $pfb_ext = pathinfo($pfb_logfilename, PATHINFO_EXTENSION); // Load log if ($_POST['action'] == 'load') { if (!is_file($pfb_logfilename)) { - echo "|3|" . gettext("Log file is empty or does not exist") . ".|"; + echo "|3|" . gettext('Log file is empty or does not exist') . ".|"; } else { $data = file_get_contents($pfb_logfilename); if ($data === false) { - echo "|1|" . gettext("Failed to read log file") . ".|"; + echo "|1|" . gettext('Failed to read log file') . ".|"; } else { $data = base64_encode($data); echo "|0|" . $pfb_logfilename . "|" . $data . "|"; @@ -186,7 +206,7 @@ if (isset($_POST['file'])) { } if (isset($_POST['logFile'])) { - $s_logfile = $_POST['logFile']; + $s_logfile = htmlspecialchars($_POST['logFile']); // Clear selected file if (isset($_POST['clear'])) { @@ -201,32 +221,33 @@ if (isset($_POST['logFile'])) { header('Pragma: '); header('Cache-Control: '); } else { - header("Pragma: private"); - header("Cache-Control: private, must-revalidate"); + header('Pragma: private'); + header('Cache-Control: private, must-revalidate'); } - header("Content-Type: application/octet-stream"); - header("Content-length: " . filesize($s_logfile)); - header("Content-disposition: attachment; filename = " . basename($s_logfile)); + header('Content-Type: application/octet-stream'); + header('Content-length: ' . filesize($s_logfile)); + header('Content-disposition: attachment; filename = ' . basename($s_logfile)); ob_end_clean(); //important or other post will fail readfile($s_logfile); } } } else { - $s_logfile = ""; + $s_logfile = ''; } -$pgtitle = gettext("pfBlockerNG: Log Browser"); -include_once("head.inc"); +$pgtitle = gettext('pfBlockerNG: Log Browser'); +include_once('head.inc'); ?> <body link="#000000" vlink="#0000CC" alink="#000000"> <?php -include_once("fbegin.inc"); +include_once('fbegin.inc'); if ($input_errors) { print_input_errors($input_errors); } ?> + <script type="text/javascript" src="/javascript/base64.js"></script> <script type="text/javascript"> //<![CDATA[ @@ -238,7 +259,7 @@ if ($input_errors) { jQuery("#fbTarget").html(""); jQuery.ajax( - "<?=$_SERVER['SCRIPT_NAME'];?>", { + "/pfblockerng/pfblockerng_log.php", { type: 'POST', data: "instance=" + jQuery("#instance").val() + "&action=load&file=" + jQuery("#logFile").val(), complete: loadComplete @@ -271,7 +292,7 @@ if ($input_errors) { </script> <?php -echo("<form action='" . $_SERVER['PHP_SELF'] . "' method='post' id='formbrowse'>"); +echo("<form action='/pfblockerng/pfblockerng_log.php' method='post' id='formbrowse'>"); if ($savemsg) { print_info_box($savemsg); } @@ -282,22 +303,16 @@ if ($savemsg) { <td> <?php $tab_array = array(); - $tab_array[] = array(gettext("General"), false, "/pkg_edit.php?xml=pfblockerng.xml&id=0"); + $tab_array[] = array(gettext("General"), false, "/pkg_edit.php?xml=pfblockerng.xml"); $tab_array[] = array(gettext("Update"), false, "/pfblockerng/pfblockerng_update.php"); $tab_array[] = array(gettext("Alerts"), false, "/pfblockerng/pfblockerng_alerts.php"); - $tab_array[] = array(gettext("Reputation"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml&id=0"); + $tab_array[] = array(gettext("Reputation"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml"); $tab_array[] = array(gettext("IPv4"), false, "/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml"); $tab_array[] = array(gettext("IPv6"), false, "/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml"); - $tab_array[] = array(gettext("Top 20"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml&id=0"); - $tab_array[] = array(gettext("Africa"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_Africa.xml&id=0"); - $tab_array[] = array(gettext("Asia"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_Asia.xml&id=0"); - $tab_array[] = array(gettext("Europe"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_Europe.xml&id=0"); - $tab_array[] = array(gettext("N.A."), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_NorthAmerica.xml&id=0"); - $tab_array[] = array(gettext("Oceania"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_Oceania.xml&id=0"); - $tab_array[] = array(gettext("S.A."), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_SouthAmerica.xml&id=0"); - $tab_array[] = array(gettext("P.S."), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_ProxyandSatellite.xml&id=0"); + $tab_array[] = array(gettext("DNSBL"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl.xml"); + $tab_array[] = array(gettext("Country"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml"); $tab_array[] = array(gettext("Logs"), true, "/pfblockerng/pfblockerng_log.php"); - $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml&id=0"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml"); display_top_tabs($tab_array, true); ?> </td> @@ -311,9 +326,9 @@ if ($savemsg) { <td colspan="2" class="listtopic"><?php echo gettext("Log/File Browser Selections"); ?></td> </tr> <tr> - <td colspan="3" class="vncell" align="left"><?php echo gettext("LINKS :"); ?> - <a href='/firewall_aliases.php' target="_blank"><?php echo gettext("Firewall Alias"); ?></a> - <a href='/firewall_rules.php' target="_blank"><?php echo gettext("Firewall Rules"); ?></a> + <td colspan="3" class="vncell" align="left"><?php echo gettext("LINKS :"); ?>  + <a href='/firewall_aliases.php' target="_blank"><?php echo gettext("Firewall Alias"); ?></a>  + <a href='/firewall_rules.php' target="_blank"><?php echo gettext("Firewall Rules"); ?></a>  <a href='/diag_logs_filter.php' target="_blank"><?php echo gettext("Firewall Logs"); ?></a><br /></td> </tr> <tr> @@ -324,16 +339,16 @@ if ($savemsg) { $clearable = FALSE; $downloadable = FALSE; foreach ($pfb_logtypes as $id => $logtype) { - $selected = ""; + $selected = ''; if ($id == $logtypeid) { - $selected = " selected"; + $selected = ' selected'; $clearable = $logtype['clear']; $downloadable = $logtype['download']; } echo("<option value='" . $id . "'" . $selected . ">" . $logtype['name'] . "</option>\n"); } ?> - </select> <?php echo gettext('Choose which type of log/file you want to view.'); ?> + </select> <?php echo gettext('Choose which type of log/file you want to view.'); ?> </td> </tr> <tr> @@ -347,14 +362,14 @@ if ($savemsg) { $logs = getlogs($pfb_logtypes[$logtypeid]['logdir'], $pfb_logtypes[$logtypeid]['ext']); } foreach ($logs as $log) { - $selected = ""; + $selected = ''; if ($log == $pfb_logfilename) { - $selected = " selected"; + $selected = ' selected'; } echo("<option value='" . $pfb_logtypes[$logtypeid]['logdir'] . $log . "'" . $selected . ">" . $log . "</option>\n"); } ?> - </select> <?php echo gettext('Choose which log/file you want to view.'); ?> + </select> <?php echo gettext('Choose which log/file you want to view.'); ?> </td> </tr> <tr> @@ -424,6 +439,6 @@ if ($savemsg) { //]]> </script> <?php endif; ?> -<?php include("fend.inc"); ?> +<?php include('fend.inc'); ?> </body> </html>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng_sync.xml b/config/pfblockerng/pfblockerng_sync.xml index 03b86dce..b5faa4ef 100644 --- a/config/pfblockerng/pfblockerng_sync.xml +++ b/config/pfblockerng/pfblockerng_sync.xml @@ -1,20 +1,19 @@ <?xml version="1.0" encoding="utf-8" ?> -<!DOCTYPE packagegui SYSTEM "./schema/packages.dtd"> -<?xml-stylesheet type="text/xsl" href="./xsl/package.xsl"?> +<!DOCTYPE packagegui SYSTEM "../schema/packages.dtd"> +<?xml-stylesheet type="text/xsl" href="../xsl/package.xsl"?> <packagegui> <copyright> <![CDATA[ -/* $Id$ */ /* ========================================================================== */ /* pfBlockerNG_sync.xml pfBlockerNG - Copyright (C) 2015 BBcan177@gmail.com + Copyright (c) 2015 BBcan177@gmail.com All rights reserved. Based upon pfblocker for pfSense - Copyright (C) 2011 Marcello Coutinho + Copyright (c) 2011 Marcello Coutinho All rights reserved. */ /* ========================================================================== */ @@ -57,12 +56,12 @@ <name>pfBlockerNG</name> <tooltiptext>Configure pfBlockerNG</tooltiptext> <section>Services</section> - <url>pkg_edit.php?xml=pfblockerng.xml&id=0</url> + <url>pkg_edit.php?xml=pfblockerng.xml</url> </menu> <tabs> <tab> <text>General</text> - <url>/pkg_edit.php?xml=pfblockerng.xml&id=0</url> + <url>/pkg_edit.php?xml=pfblockerng.xml</url> </tab> <tab> <text>Update</text> @@ -74,47 +73,23 @@ </tab> <tab> <text>Reputation</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml</url> </tab> <tab> <text>IPv4</text> - <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml&id=0</url> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml</url> </tab> <tab> <text>IPv6</text> - <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml&id=0</url> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml</url> </tab> <tab> - <text>Top 20</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml&id=0</url> + <text>DNSBL</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl.xml</url> </tab> <tab> - <text>Africa</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Africa.xml&id=0</url> - </tab> - <tab> - <text>Asia</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Asia.xml&id=0</url> - </tab> - <tab> - <text>Europe</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Europe.xml&id=0</url> - </tab> - <tab> - <text>N.A.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_NorthAmerica.xml&id=0</url> - </tab> - <tab> - <text>Oceania</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Oceania.xml&id=0</url> - </tab> - <tab> - <text>S.A.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_SouthAmerica.xml&id=0</url> - </tab> - <tab> - <text>P.S.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_ProxyandSatellite.xml&id=0</url> + <text>Country</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml</url> </tab> <tab> <text>Logs</text> @@ -122,7 +97,7 @@ </tab> <tab> <text>Sync</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml</url> <active/> </tab> </tabs> @@ -133,8 +108,8 @@ </field> <field> <fielddescr>LINKS</fielddescr> - <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a> - <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> + <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a>  + <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> </description> <type>info</type> </field> @@ -163,9 +138,9 @@ <size>5</size> </field> <field> - <fielddescr><![CDATA[Disable 'General Tab' sync]]></fielddescr> + <fielddescr><![CDATA[Disable 'General/DNSBL tab' sync]]></fielddescr> <fieldname>syncinterfaces</fieldname> - <description>When selected, the 'General' Tab Customizations will not be sync'd</description> + <description>When selected, the 'General' tab and 'DNSBL' tab customizations will not be sync'd</description> <type>checkbox</type> </field> <field> @@ -194,9 +169,9 @@ </options> </rowhelperfield> <rowhelperfield> - <fielddescr>Target IP Address</fielddescr> + <fielddescr>Target IP/Hostname</fielddescr> <fieldname>varsyncipaddress</fieldname> - <description><![CDATA[IP Address of the destination host.]]></description> + <description><![CDATA[IP Address or Hostname of the destination host.]]></description> <type>input</type> <size>15</size> </rowhelperfield> @@ -224,23 +199,21 @@ </rowhelper> </field> <field> - <name><![CDATA[<center>Click to SAVE Settings and/or Rule Edits. Changes are Applied via CRON or + <name><![CDATA[<center>Click to SAVE Settings and/or Rule Edits.   Changes are Applied via CRON or 'Force Update'</center>]]></name> <type>listtopic</type> </field> </fields> - <custom_php_install_command> - pfblockerng_php_install_command(); - </custom_php_install_command> - <custom_php_deinstall_command> - pfblockerng_php_deinstall_command(); - </custom_php_deinstall_command> <custom_php_validation_command> + <![CDATA[ pfblockerng_validate_input($_POST, $input_errors); + ]]> </custom_php_validation_command> <custom_php_resync_config_command> + <![CDATA[ require_once("/usr/local/pkg/pfblockerng/pfblockerng.inc"); write_config("[pfBlockerNG] XMLRPC sync configurations saved."); pfblockerng_sync_on_changes(); + ]]> </custom_php_resync_config_command> </packagegui>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng_threats.php b/config/pfblockerng/pfblockerng_threats.php new file mode 100644 index 00000000..d02d100f --- /dev/null +++ b/config/pfblockerng/pfblockerng_threats.php @@ -0,0 +1,142 @@ +<?php +/* + pfBlockerNG_threats.php + + pfBlockerNG + Copyright (c) 2015 BBcan177@gmail.com + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +$pgtitle = array(gettext('pfBlockerNG'), gettext('Threat Source Lookup')); +require('guiconfig.inc'); + +if (isset($_REQUEST['host'])) { + $host = htmlspecialchars($_REQUEST['host']); +} + +if (isset($_REQUEST['domain'])) { + $domain = htmlspecialchars($_REQUEST['domain']); +} + +include('head.inc'); +include('fbegin.inc'); +?> + +<tr> + <td> + <div id="mainarea"> + <body link="#0000CC" vlink="#0000CC" alink="#0000CC"> + <table width="100%" border="0" cellpadding="6" cellspacing="0" summary="tabcont"> + <tbody> + <tr> + <td colspan="2" class="listtopic"><?php echo gettext("Threat"); ?></td> + </tr> + <tr> + <td colspan="2" class="listr"><font size="3"><?php echo " {$host}{$domain}"; ?></font></td> + </tr> + <tr> + <td colspan="2" class="vncell"></td> + </tr> + <tr> + <td colspan="2" class="listtopic"><?php echo gettext("Threat Lookups"); ?></td> + </tr> + <tr> + <td width="14%" valign="top" class="vncell"></td> + <td width="86%" class="listr"> + <?=gettext("NOTE:");?><br /><br /> + <?=gettext("The following links are to external services, so their reliability cannot be guaranteed.");?><br /> + <?=gettext("It is also recommended to open these links in a different Browser.");?><br /><br /> + + <?php if (isset($_REQUEST['host'])) { ?> + + <a target="_blank" href="http://www.ipvoid.com/scan/<?php echo $host; ?>/"> + <?=gettext("IPVOID");?></a><br /> + <a target="_blank" href="http://www.tcpiputils.com/browse/ip-address/<?php echo $host; ?>/"> + <?=gettext("TCPUtils");?></a><br /> + <a target="_blank" href="https://www.herdprotect.com/ip-address-<?php echo $host; ?>.aspx"> + <?=gettext("Herd Protect");?></a><br /> + <a target="_blank" href="https://www.senderbase.org/lookup/ip/?search_string=<?php echo $host; ?>"> + <?=gettext("SenderBase");?></a><br /> + <a target="_blank" href="http://www.ip-tracker.org/locator/ip-lookup.php?ip=<?php echo $host; ?>"> + <?=gettext("IP Tracker");?></a><br /> + <a target="_blank" href="https://www.fortiguard.com/ip_rep/index.php?data=/<?php echo $host; ?>?"> + <?=gettext("FortiGuard");?></a><br /> + <a target="_blank" href="https://www.projecthoneypot.org/ip_<?php echo $host; ?>"> + <?=gettext("Project HoneyPot");?></a><br /> + <a target="_blank" href="https://www.virustotal.com/en/ip-address/<?php echo $host; ?>/information"> + <?=gettext("VirusTotal Info");?></a><br /> + <a target="_blank" href="https://www.mcafee.com/threat-intelligence/ip/default.aspx?ip=<?php echo $host; ?>"> + <?=gettext("McAfee Threat Center");?></a><br /> + <a target="_blank" href="https://sitecheck.sucuri.net/results/<?php echo $host; ?>"> + <?=gettext("Securi SiteCheck");?></a><br /> + <a target="_blank" href="https://www.dshield.org/ipinfo.html?IP=<?php echo $host; ?>"> + <?=gettext("DShield Threat Lookup");?></a><br /> + <a target="_blank" href="https://isc.sans.edu/ipinfo.html?ip=<?php echo $host; ?>"> + <?=gettext("Internet Storm Center");?></a><br /> + <a target="_blank" href="https://www.mywot.com/en/scorecard/<?php echo $host; ?>"> + <?=gettext("Web of Trust (WOT) Scorecard");?></a><br /> + <a target="_blank" href="https://quttera.com/sitescan/<?php echo $host; ?>"> + <?=gettext("Quattera");?></a><br /> + <a target="_blank" href="https://www.iblocklist.com/search.php?string=<?php echo $host; ?>"> + <?=gettext("I-Block List");?></a><br /> + <p/> + + <?=gettext("Mail Server DNSRBL Lookups");?><br /><br /> + <a target="_blank" href="https://senderscore.org/lookup.php?lookup=<?php echo $host; ?>&ipLookup=Go"> + <?=gettext("SenderScore");?></a><br /> + <a target="_blank" href="https://www.spamhaus.org/query/bl?ip=<?php echo $host; ?>"> + <?=gettext("Spamhaus Blocklist");?></a><br /> + <a target="_blank" href="https://www.spamcop.net/w3m?action=checkblock&ip=<?php echo $host; ?>"> + <?=gettext("SPAMcop Blocklist");?></a><br /> + <a target="_blank" href="http://multirbl.valli.org/lookup/<?php echo $host; ?>.html"> + <?=gettext("multirbl RBL Lookup");?></a><br /> + <a target="_blank" href="https://mxtoolbox.com/SuperTool.aspx?action=blacklist%3a<?php echo $host; ?>&run=toolpage"> + <?=gettext("MXToolbox");?></a><br /> + + <?php } else { ?> + + <a target="_blank" href="http://www.alexa.com/siteinfo/<?php echo $domain; ?>"> + <?=gettext("Alexa");?></a><br /> + <a target="_blank" href="https://www.c-sirt.org/en/incidents-on-domain/<?php echo $domain; ?>"> + <?=gettext("C-SIRT");?></a><br /> + <a target="_blank" href="https://www.herdprotect.com/domain-<?php echo $domain; ?>.aspx"> + <?=gettext("HerdProtect");?></a><br /> + <a target="_blank" href="https://sitecheck.sucuri.net/results/<?php echo $domain; ?>"> + <?=gettext("Sucuri");?></a><br /> + + <?php } ?> + + </td> + </tr> + </tbody> + </table> + </div> + </td> +</tr> + +<?php include('fend.inc'); ?> +</body> +</html>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng_top20.xml b/config/pfblockerng/pfblockerng_top20.xml index 030c1385..6200a6a9 100644 --- a/config/pfblockerng/pfblockerng_top20.xml +++ b/config/pfblockerng/pfblockerng_top20.xml @@ -1,20 +1,19 @@ <?xml version="1.0" encoding="utf-8" ?> -<!DOCTYPE packagegui SYSTEM "./schema/packages.dtd"> -<?xml-stylesheet type="text/xsl" href="./xsl/package.xsl"?> +<!DOCTYPE packagegui SYSTEM "../schema/packages.dtd"> +<?xml-stylesheet type="text/xsl" href="../xsl/package.xsl"?> <packagegui> <copyright> <![CDATA[ -/* $Id$ */ /* ========================================================================== */ /* pfBlockerNG_Top20.xml pfBlockerNG - Copyright (C) 2015 BBcan177@gmail.com + Copyright (c) 2015 BBcan177@gmail.com All rights reserved. Based upon pfblocker for pfSense - Copyright (C) 2011 Marcello Coutinho + Copyright (c) 2011 Marcello Coutinho All rights reserved. */ /* ========================================================================== */ @@ -57,12 +56,12 @@ <name>pfBlockerNG</name> <tooltiptext>Configure pfblockerNG</tooltiptext> <section>Firewall</section> - <url>pkg_edit.php?xml=pfblockerng.xml&id=0</url> + <url>pkg_edit.php?xml=pfblockerng.xml</url> </menu> <tabs> <tab> <text>General</text> - <url>/pkg_edit.php?xml=pfblockerng.xml&id=0</url> + <url>/pkg_edit.php?xml=pfblockerng.xml</url> </tab> <tab> <text>Update</text> @@ -74,48 +73,64 @@ </tab> <tab> <text>Reputation</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml</url> </tab> <tab> <text>IPv4</text> - <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml&id=0</url> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml</url> </tab> <tab> <text>IPv6</text> - <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml&id=0</url> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml</url> + </tab> + <tab> + <text>DNSBL</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl.xml</url> + </tab> + <tab> + <text>Country</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml</url> </tab> <tab> <text>Top 20</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml</url> + <tab_level>2</tab_level> <active/> </tab> <tab> <text>Africa</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Africa.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Africa.xml</url> + <tab_level>2</tab_level> </tab> <tab> <text>Asia</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Asia.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Asia.xml</url> + <tab_level>2</tab_level> </tab> <tab> <text>Europe</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Europe.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Europe.xml</url> + <tab_level>2</tab_level> </tab> <tab> - <text>N.A.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_NorthAmerica.xml&id=0</url> + <text>North America</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_NorthAmerica.xml</url> + <tab_level>2</tab_level> </tab> <tab> <text>Oceania</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Oceania.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Oceania.xml</url> + <tab_level>2</tab_level> </tab> <tab> - <text>S.A.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_SouthAmerica.xml&id=0</url> + <text>South America</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_SouthAmerica.xml</url> + <tab_level>2</tab_level> </tab> <tab> - <text>P.S.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_ProxyandSatellite.xml&id=0</url> + <text>Proxy and Satellite</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_ProxyandSatellite.xml</url> + <tab_level>2</tab_level> </tab> <tab> <text>Logs</text> @@ -123,12 +138,12 @@ </tab> <tab> <text>Sync</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml</url> </tab> </tabs> <fields> <field> - <name><![CDATA[TOP 20 - Spammer Countries (Geolite Data by Maxmind Inc. - ISO 3166)]]></name> + <name><![CDATA[TOP 20 - Spammer Countries  (Geolite Data by Maxmind Inc. - ISO 3166)]]></name> <type>listtopic</type> </field> <field> @@ -144,15 +159,15 @@ </field> <field> <fielddescr>LINKS</fielddescr> - <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a> - <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> + <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a>  + <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> </description> <type>info</type> </field> <field> <fieldname>countries4</fieldname> <fielddescr><![CDATA[<strong><center>Top 20<br /> Spammer Countries</center></strong><br /> - <center>Use CTRL + CLICK to unselect countries</center>]]> + <center>Use CTRL + CLICK to select/unselect countries</center>]]> </fielddescr> <description><![CDATA[<center><br />IPv4 Countries</center>]]></description> <type>select</type> @@ -176,7 +191,7 @@ <option><name>Columbia-CO</name><value>CO</value></option> <option><name>Taiwan-TW</name><value>TW</value></option> <option><name>Mexico-MX</name><value>MX</value></option> - <option><name>Chilie-CL</name><value>CL</value></option> + <option><name>Chile-CL</name><value>CL</value></option> </options> <size>20</size> <multiple/> @@ -247,11 +262,9 @@ <li>'Alias Deny' can use De-Duplication and Reputation Processes if configured.</li><br /> <li>'Alias Permit' and 'Alias Match' will be saved in the Same folder as the other Permit/Match Auto-Rules</li><br /> <li>'Alias Native' lists are kept in their Native format without any modifications.</li></ul> - <strong>When using 'Alias' rules, change (pfB_) to ( pfb_ ) in the beginning of rule description and Use the 'Exact' spelling of - the Alias (no trailing Whitespace)</strong> Custom 'Alias' rules with 'pfB_ xxx' description will be removed by package if - using Auto Rule Creation.<br /><br /><strong>Tip</strong>: You can create the Auto Rules and remove "<u>auto rule</u>" from the Rule - Descriptions, then disable Auto Rules. This method will 'KEEP' these rules from being 'Deleted' which will allow editing for a Custom - Alias Configuration<br />]]> + <font color='red'>Note: </font><ul>When manually creating 'Alias' type firewall rules; <strong>Do not add</strong> (pfB_) to the + start of the rule description, use (pfb_) (Lowercase prefix). Manually created 'Alias' rules with 'pfB_' in the + description will be auto-removed by package when 'Auto' rules are defined.</ul>]]> </description> <fieldname>action</fieldname> <type>select</type> @@ -289,8 +302,8 @@ </field> <field> <type>info</type> - <description><![CDATA[<font color='red'>Note: </font>In general Auto-Rules are created as follows:<br /> - <ul>Inbound - 'any' port, 'any' protocol and 'any' destination<br /> + <description><![CDATA[<font color='red'>Note: </font>In general, Auto-Rules are created as follows:<br /> + <ul>Inbound  - 'any' port, 'any' protocol and 'any' destination<br /> Outbound - 'any' port, 'any' protocol and 'any' destination address in the lists</ul> Configuring the Adv. Inbound Rule settings, will allow for more customization of the Inbound Auto-Rules.<br /> <strong>Select the pfSense 'Port' and/or 'Destination' Alias below:</strong>]]> @@ -351,7 +364,8 @@ <field> <fielddescr>Custom Protocol</fielddescr> <fieldname>autoproto</fieldname> - <description><![CDATA[<strong>Default: any</strong><br />Select the Protocol used for Inbound Firewall Rule(s).]]></description> + <description><![CDATA[<strong>Default: any</strong><br />Select the Protocol used for Inbound Firewall Rule(s).<br /> + Do not use 'any' with Adv. Inbound Rules as it will bypass these settings!]]></description> <type>select</type> <options> <option><name>any</name><value></value></option> @@ -363,23 +377,21 @@ <default_value></default_value> </field> <field> - <name><![CDATA[<center>Click to SAVE Settings and/or Rule Edits. Changes are Applied via CRON or + <name><![CDATA[<center>Click to SAVE Settings and/or Rule Edits.   Changes are Applied via CRON or 'Force Update'</center>]]></name> <type>listtopic</type> </field> </fields> - <custom_php_install_command> - pfblockerng_php_install_command(); - </custom_php_install_command> - <custom_php_deinstall_command> - pfblockerng_php_deinstall_command(); - </custom_php_deinstall_command> <custom_php_validation_command> + <![CDATA[ pfblockerng_validate_input($_POST, $input_errors); + ]]> </custom_php_validation_command> <custom_php_resync_config_command> + <![CDATA[ global $pfb; $pfb['save'] = TRUE; sync_package_pfblockerng(); + ]]> </custom_php_resync_config_command> </packagegui>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng_update.php b/config/pfblockerng/pfblockerng_update.php index 7911a4e6..8a04f843 100644 --- a/config/pfblockerng/pfblockerng_update.php +++ b/config/pfblockerng/pfblockerng_update.php @@ -3,7 +3,7 @@ /* pfBlockerNG_Update.php pfBlockerNG - Copyright (C) 2015 BBcan177@gmail.com + Copyright (c) 2015 BBcan177@gmail.com All rights reserved. Portions of this code are based on original work done for @@ -11,8 +11,9 @@ pkg_mgr_install.php Part of pfSense (https://www.pfsense.org) - Copyright (C) 2004-2010 Scott Ullrich <sullrich@gmail.com> - Copyright (C) 2005 Colin Smith + Copyright (c) 2015 Electric Sheep Fencing, LLC. All rights reserved. + Copyright (c) 2005 Colin Smith + Copyright (c) 2004-2005 Scott Ullrich All rights reserved. Redistribution and use in source and binary forms, with or without @@ -39,18 +40,18 @@ POSSIBILITY OF SUCH DAMAGE. */ -require_once("guiconfig.inc"); -require_once("globals.inc"); -require_once("pfsense-utils.inc"); -require_once("functions.inc"); -require_once("util.inc"); -require_once("/usr/local/pkg/pfblockerng/pfblockerng.inc"); +require_once('guiconfig.inc'); +require_once('globals.inc'); +require_once('pfsense-utils.inc'); +require_once('functions.inc'); +require_once('util.inc'); +require_once('/usr/local/pkg/pfblockerng/pfblockerng.inc'); pfb_global(); -// Collect pfBlockerNG log file and post Live output to Terminal window. +// Collect pfBlockerNG log file and post live output to terminal window. function pfbupdate_output($text) { - $text = preg_replace("/\n/", "\\n", $text); + $text = str_replace("\n", "\\n", $text); echo "\n<script type=\"text/javascript\">"; echo "\n//<![CDATA["; echo "\nthis.document.forms[0].pfb_output.value = \"" . $text . "\";"; @@ -61,9 +62,9 @@ function pfbupdate_output($text) { ob_flush(); } -// Post Status Message to Terminal window. +// Post status message to terminal window. function pfbupdate_status($status) { - $status = preg_replace("/\n/", "\\n", $status); + $status = str_replace("\n", "\\n", $status); echo "\n<script type=\"text/javascript\">"; echo "\n//<![CDATA["; echo "\nthis.document.forms[0].pfb_status.value=\"" . $status . "\";"; @@ -78,11 +79,10 @@ function pfbupdate_status($status) { function pfb_cron_update($type) { global $pfb; - // Query for any Active pfBlockerNG CRON Jobs - $result_cron = array(); - $cron_event = exec ("/bin/ps -wx", $result_cron); - if (preg_grep("/pfblockerng[.]php\s+cron/", $result_cron) || preg_grep("/pfblockerng[.]php\s+update/", $result_cron)) { - pfbupdate_status(gettext("Force {$type} Terminated - Failed due to Active Running Task")); + // Query for any active pfBlockerNG CRON jobs + exec('/bin/ps -wx', $result_cron); + if (preg_grep("/pfblockerng[.]php\s+?(cron|update)/", $result_cron)) { + pfbupdate_status(gettext("Force {$type} Terminated - Failed due to Active Running Task. Click 'View' for running process")); exit; } @@ -90,103 +90,62 @@ function pfb_cron_update($type) { touch("{$pfb['log']}"); } - // Update Status Window with correct Task - if ($type == "update") { - pfbupdate_status(gettext("Running Force Update Task")); - } elseif ($type == "reload") { - pfbupdate_status(gettext("Running Force Reload Task")); - $type = "update"; + // Update status window with correct task + if ($type == 'update') { + pfbupdate_status(gettext('Running Force Update Task')); + } elseif ($type == 'reload') { + $reload_type = htmlspecialchars($_POST['rmode']); + pfbupdate_status(gettext("Running Force Reload Task - {$reload_type}")); + + switch ($reload_type) { + case 'IP': + $type = 'updateip'; + break; + case 'DNSBL': + $type = 'updatednsbl'; + rmdir_recursive("{$pfb['dnsdir']}"); + break; + case 'All': + default: + $type = 'update'; + rmdir_recursive("{$pfb['dnsdir']}"); + } } else { - pfbupdate_status(gettext("Running Force CRON Task")); + pfbupdate_status(gettext('Running Force CRON Task')); } // Remove any existing pfBlockerNG CRON Jobs - install_cron_job("pfblockerng.php cron", false); + install_cron_job('pfblockerng.php cron', false); - // Execute PHP Process in the Background + // Execute PHP process in the background mwexec_bg("/usr/local/bin/php /usr/local/www/pfblockerng/pfblockerng.php {$type} >> {$pfb['log']} 2>&1"); - // Start at EOF - $lastpos_old = ""; - $len = filesize("{$pfb['log']}"); - $lastpos = $len; - - while (true) { - usleep(300000); //0.3s - clearstatcache(false,$pfb['log']); - $len = filesize("{$pfb['log']}"); - if ($len < $lastpos) { - //file deleted or reset - $lastpos = $len; - } else { - $f = fopen($pfb['log'], "rb"); - if ($f === false) { - die(); - } - fseek($f, $lastpos); - - while (!feof($f)) { - - $pfb_buffer = fread($f, 2048); - $pfb_output .= str_replace( array ("\r", "\")"), "", $pfb_buffer); - // Refresh on new lines only. This allows Scrolling. - if ($lastpos != $lastpos_old) { - pfbupdate_output($pfb_output); - } - $lastpos_old = $lastpos; - ob_flush(); - flush(); - } - $lastpos = ftell($f); - fclose($f); - } - // Capture Remaining Output before closing File - if (preg_match("/(UPDATE PROCESS ENDED)/",$pfb_output)) { - $f = fopen($pfb['log'], "rb"); - fseek($f, $lastpos); - $pfb_buffer = fread($f, 2048); - $pfb_output .= str_replace( "\r", "", $pfb_buffer); - pfbupdate_output($pfb_output); - clearstatcache(false,$pfb['log']); - ob_flush(); - flush(); - fclose($f); - // Call Log Mgmt Function - pfb_log_mgmt(); - die(); - } - } + // Execute Live Tail function + pfb_livetail($pfb['log'], 'force'); } -$pgtitle = gettext("pfBlockerNG: Update"); -include_once("head.inc"); +$pgtitle = gettext('pfBlockerNG: Update'); +include_once('head.inc'); +include_once('fbegin.inc'); ?> <body link="#000000" vlink="#0000CC" alink="#000000"> -<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post"> -<?php include_once("fbegin.inc"); ?> - +<form action="/pfblockerng/pfblockerng_update.php" method="post"> <table width="100%" border="0" cellpadding="0" cellspacing="0"> <tr> <td> <?php $tab_array = array(); - $tab_array[] = array(gettext("General"), false, "/pkg_edit.php?xml=pfblockerng.xml&id=0"); + $tab_array[] = array(gettext("General"), false, "/pkg_edit.php?xml=pfblockerng.xml"); $tab_array[] = array(gettext("Update"), true, "/pfblockerng/pfblockerng_update.php"); $tab_array[] = array(gettext("Alerts"), false, "/pfblockerng/pfblockerng_alerts.php"); - $tab_array[] = array(gettext("Reputation"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml&id=0"); + $tab_array[] = array(gettext("Reputation"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml"); $tab_array[] = array(gettext("IPv4"), false, "/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml"); $tab_array[] = array(gettext("IPv6"), false, "/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml"); - $tab_array[] = array(gettext("Top 20"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml&id=0"); - $tab_array[] = array(gettext("Africa"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_Africa.xml&id=0"); - $tab_array[] = array(gettext("Asia"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_Asia.xml&id=0"); - $tab_array[] = array(gettext("Europe"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_Europe.xml&id=0"); - $tab_array[] = array(gettext("N.A."), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_NorthAmerica.xml&id=0"); - $tab_array[] = array(gettext("Oceania"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_Oceania.xml&id=0"); - $tab_array[] = array(gettext("S.A."), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_SouthAmerica.xml&id=0"); - $tab_array[] = array(gettext("P.S."), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_ProxyandSatellite.xml&id=0"); + $tab_array[] = array(gettext("DNSBL"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl.xml"); + $tab_array[] = array(gettext("Country"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml"); $tab_array[] = array(gettext("Logs"), false, "/pfblockerng/pfblockerng_log.php"); - $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml&id=0"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml"); display_top_tabs($tab_array, true); ?> </td> @@ -195,9 +154,9 @@ include_once("head.inc"); <div id="mainareapkg"> <table id="maintable" class="tabcont" width="100%" border="0" cellspacing="0" cellpadding="2"> <tr> - <td colspan="2" class="vncell" align="left"><?php echo gettext("LINKS :"); ?> - <a href='/firewall_aliases.php' target="_blank"><?php echo gettext("Firewall Alias"); ?></a> - <a href='/firewall_rules.php' target="_blank"><?php echo gettext("Firewall Rules"); ?></a> + <td colspan="2" class="vncell" align="left"><?php echo gettext("LINKS :"); ?>  + <a href='/firewall_aliases.php' target="_blank"><?php echo gettext("Firewall Alias"); ?></a>  + <a href='/firewall_rules.php' target="_blank"><?php echo gettext("Firewall Rules"); ?></a>  <a href='/diag_logs_filter.php' target="_blank"><?php echo gettext("Firewall Logs"); ?></a><br /> </td> </tr> @@ -207,6 +166,7 @@ include_once("head.inc"); <tr> <td colspan="2" class="listr"> <?php + if ($pfb['enable'] == 'on') { /* Legend - Time variables @@ -293,11 +253,11 @@ include_once("head.inc"); <font size=\"3\"><span class=\"red\"> {$nextcron} </span></font> time remaining."; // Query for any active pfBlockerNG CRON jobs - exec ('/bin/ps -wax', $result_cron); - if (preg_grep("/pfblockerng[.]php\s+cron/", $result_cron)) { - echo "<font size=\"2\"><span class=\"red\"> - Active pfBlockerNG CRON Job </span></font> "; - echo "<img src = '/themes/{$g['theme']}/images/icons/icon_pass.gif' width='15' height='15' + exec('/bin/ps -wax', $result_cron); + if (preg_grep("/pfblockerng[.]php\s+?(cron|update)/", $result_cron)) { + echo "<font size=\"2\"><span class=\"red\">   + Active pfBlockerNG CRON Job </span></font> "; + echo "<img src = '/themes/{$g['theme']}/images/icons/icon_pass.gif' alt='' width='15' height='15' border='0' title='pfBockerNG Cron Task is Running.'/>"; } echo "<br /><font size=\"3\"><span class=\"red\">Refresh</span></font> to update current Status and time remaining"; @@ -331,7 +291,10 @@ include_once("head.inc"); <input type="submit" class="formbtns" name="pfbcron" id="pfbcron" value="Force Cron" title="<?=gettext("Run Force Cron Update");?>" /> <input type="submit" class="formbtns" name="pfbreload" id="pfbreload" value="Force Reload" - title="<?=gettext("Run Force Reload");?>" /> + title="<?=gettext("Run Force Reload");?>" /> <?=gettext("Reload Options:");?> + <input name="rmode" type="radio" value="All" <?php echo 'checked'; ?> /><?=gettext("All");?> + <input name="rmode" type="radio" value="IP" /><?=gettext("IP");?> + <input name="rmode" type="radio" value="DNSBL" /><?=gettext("DNSBL"); ?> </td> </tr> <tr> @@ -342,7 +305,7 @@ include_once("head.inc"); </tr> <tr> <td colspan="2" class="listr"><?php echo gettext("Selecting 'Live Log Viewer' will allow viewing a running Cron Update"); ?></td> - </tr> + </tr> <tr> <td colspan="2" class="vncell"> <!-- Log Viewer Buttons --> @@ -350,8 +313,8 @@ include_once("head.inc"); title="<?=gettext("VIEW pfBlockerNG LOG");?>"/> <input type="submit" class="formbtns" name="pfbviewcancel" id="pfbviewcancel" value="End View" title="<?=gettext("END VIEW of pfBlockerNG LOG");?>"/> - <?php echo " " . gettext(" Select 'view' to open ") . "<strong>" . gettext(' pfBlockerNG ') . "</strong>" . - gettext(" Log. (Select 'End View' to terminate the viewer.)"); ?><br /><br /> + <?php echo " " . gettext(" Select 'view' to open ") . "<strong>" . gettext(' pfBlockerNG ') . "</strong>" . + gettext(" Log.   (Select 'End View' to terminate the viewer.)"); ?><br /><br /> </td> </tr> <tr> @@ -371,83 +334,38 @@ include_once("head.inc"); </div> <?php -include("fend.inc"); +include('fend.inc'); -// Execute the Viewer output Window -if (isset($_POST['pfbview'])) { - if (!file_exists("{$pfb['log']}")) { - touch("{$pfb['log']}"); - } - - // Reference: http://stackoverflow.com/questions/3218895/php-how-to-read-a-file-live-that-is-constantly-being-written-to +// Execute the viewer output window +if (isset($_POST['pfbview'])) { pfbupdate_status(gettext("Log Viewing in progress. ** Press 'END VIEW' to Exit ** ")); - $lastpos_old = ""; - $len = filesize("{$pfb['log']}"); - - // Start at EOF ( - 15000) - if ($len > 15000) { - $lastpos = ($len - 15000); - } else { - $lastpos = 0; - } - - while (true) { - usleep(300000); //0.3s - clearstatcache(false,$pfb['log']); - $len = filesize("{$pfb['log']}"); - if ($len < $lastpos) { - //file deleted or reset - $lastpos = $len; - } else { - $f = fopen($pfb['log'], "rb"); - if ($f === false) { - die(); - } - fseek($f, $lastpos); - - while (!feof($f)) { - - $pfb_buffer = fread($f, 4096); - $pfb_output .= str_replace( array ("\r", "\")"), "", $pfb_buffer); - - // Refresh on new lines only. This allows scrolling. - if ($lastpos != $lastpos_old) { - pfbupdate_output($pfb_output); - } - $lastpos_old = $lastpos; - ob_flush(); - flush(); - } - $lastpos = ftell($f); - fclose($f); - } - } + pfb_livetail($pfb['log'], 'view'); } -// End the Viewer output Window +// End the viewer output Window if (isset($_POST['pfbviewcancel'])) { - clearstatcache(false,$pfb['log']); + clearstatcache(false, $pfb['log']); ob_flush(); flush(); fclose("{$pfb['log']}"); } // Execute a Force Update -if (isset($_POST['pfbupdate']) && $pfb['enable'] == "on") { +if (isset($_POST['pfbupdate']) && $pfb['enable'] == 'on') { pfb_cron_update(update); } -// Execute a CRON Command to update any Lists within the Frequency Settings -if (isset($_POST['pfbcron']) && $pfb['enable'] == "on") { +// Execute a CRON command to update any lists within the frequency settings +if (isset($_POST['pfbcron']) && $pfb['enable'] == 'on') { pfb_cron_update(cron); } -// Execute a Reload of all Aliases and Lists -if (isset($_POST['pfbreload']) && $pfb['enable'] == "on") { - // Set 'Reuse' Flag for Reload process - $config['installedpackages']['pfblockerng']['config'][0]['pfb_reuse'] = "on"; - write_config("pfBlockerNG: Executing Force Reload"); +// Execute a reload of all aliases and lists +if (isset($_POST['pfbreload']) && $pfb['enable'] == 'on') { + // Set 'Reuse' flag for reload process + $config['installedpackages']['pfblockerng']['config'][0]['pfb_reuse'] = 'on'; + write_config('pfBlockerNG: Executing Force Reload'); pfb_cron_update(reload); } diff --git a/config/pfblockerng/pfblockerng_v4lists.xml b/config/pfblockerng/pfblockerng_v4lists.xml index 00747a24..9ef3626b 100644 --- a/config/pfblockerng/pfblockerng_v4lists.xml +++ b/config/pfblockerng/pfblockerng_v4lists.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" ?> -<!DOCTYPE packagegui SYSTEM "./schema/packages.dtd"> -<?xml-stylesheet type="text/xsl" href="./xsl/package.xsl"?> +<!DOCTYPE packagegui SYSTEM "../schema/packages.dtd"> +<?xml-stylesheet type="text/xsl" href="../xsl/package.xsl"?> <packagegui> <copyright> <![CDATA[ @@ -9,14 +9,15 @@ pfBlockerNG_v4lists.xml pfBlockerNG - Copyright (C) 2015 BBcan177@gmail.com + Copyright (c) 2015 BBcan177@gmail.com All rights reserved. Based upon pfblocker for pfSense - Copyright (C) 2011 Marcello Coutinho + Copyright (c) 2011 Marcello Coutinho - part of pfSense (http://www.pfSense.com) - Copyright (C) 2010 Scott Ullrich <sullrich@gmail.com> + part of pfSense (http://www.pfSense.org) + Copyright (c) 2015 Electric Sheep Fencing, LLC. All rights reserved. + Copyright (c) 2004-2005 Scott Ullrich All rights reserved. */ /* ========================================================================== */ @@ -64,7 +65,7 @@ <tabs> <tab> <text>General</text> - <url>/pkg_edit.php?xml=pfblockerng.xml&id=0</url> + <url>/pkg_edit.php?xml=pfblockerng.xml</url> <tooltiptext></tooltiptext> </tab> <tab> @@ -77,48 +78,24 @@ </tab> <tab> <text>Reputation</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml</url> </tab> <tab> <text>IPv4</text> - <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml&id=0</url> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml</url> <active/> </tab> <tab> <text>IPv6</text> - <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml&id=0</url> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml</url> </tab> <tab> - <text>Top 20</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml&id=0</url> + <text>DNSBL</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl.xml</url> </tab> <tab> - <text>Africa</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Africa.xml&id=0</url> - </tab> - <tab> - <text>Asia</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Asia.xml&id=0</url> - </tab> - <tab> - <text>Europe</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Europe.xml&id=0</url> - </tab> - <tab> - <text>N.A.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_NorthAmerica.xml&id=0</url> - </tab> - <tab> - <text>Oceania</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Oceania.xml&id=0</url> - </tab> - <tab> - <text>S.A.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_SouthAmerica.xml&id=0</url> - </tab> - <tab> - <text>P.S.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_ProxyandSatellite.xml&id=0</url> + <text>Country</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml</url> </tab> <tab> <text>Logs</text> @@ -126,51 +103,50 @@ </tab> <tab> <text>Sync</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml</url> </tab> </tabs> - <adddeleteeditpagefields> - <columnitem> - <fielddescr>Alias Name</fielddescr> - <fieldname>aliasname</fieldname> - </columnitem> - <columnitem> - <fielddescr>Alias Description</fielddescr> - <fieldname>description</fieldname> - </columnitem> - <columnitem> - <fielddescr>Action</fielddescr> - <fieldname>action</fieldname> - </columnitem> - <columnitem> - <fielddescr>Frequency</fielddescr> - <fieldname>cron</fieldname> - </columnitem> - <columnitem> - <fielddescr>Logging</fielddescr> - <fieldname>aliaslog</fieldname> - </columnitem> - <addtext>Add a new Alias</addtext> - <movable>on</movable> - </adddeleteeditpagefields> + <adddeleteeditpagefields> + <columnitem> + <fielddescr>Alias Name</fielddescr> + <fieldname>aliasname</fieldname> + </columnitem> + <columnitem> + <fielddescr>Alias Description</fielddescr> + <fieldname>description</fieldname> + </columnitem> + <columnitem> + <fielddescr>Action</fielddescr> + <fieldname>action</fieldname> + </columnitem> + <columnitem> + <fielddescr>Frequency</fielddescr> + <fieldname>cron</fieldname> + </columnitem> + <columnitem> + <fielddescr>Logging</fielddescr> + <fieldname>aliaslog</fieldname> + </columnitem> + <addtext>Add a new Alias</addtext> + <movable>on</movable> + </adddeleteeditpagefields> <fields> <field> - <name><![CDATA[IPv4 Network ranges / CIDR lists + <name><![CDATA[IPv4 -   Run 'Force Update' to deploy new Settings.  (When Removing or Re-configuring Lists a 'Reload' is recommended.)]]></name> <type>listtopic</type> </field> <field> <fielddescr>LINKS</fielddescr> - <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a> - <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> + <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a>  + <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> </description> <type>info</type> </field> <field> <fielddescr>Alias Name</fielddescr> <fieldname>aliasname</fieldname> - <description><![CDATA[Enter Alias Name.<br /> - Example: Badguys<br /> + <description><![CDATA[Enter Alias Name ( Example: Badguys )<br /> Do not include <strong>'pfBlocker' or 'pfB_'</strong> in the Alias Name, it's done by package.<br /> <strong>International, special or space characters will be ignored in firewall alias names. </strong><br />]]> @@ -186,37 +162,35 @@ </field> <field> <type>info</type> - <description><![CDATA[<strong><u>'Format'</u></strong>: Select the Format Type<br /><br /> - <strong><u>'URL'</u></strong>: Add direct link to list: - Example: <a target=_new href='http://list.iblocklist.com/?list=bt_ads&fileformat=p2p&archiveformat=gz'>Ads</a>, - <a target=_new href='http://list.iblocklist.com/?list=bt_spyware&fileformat=p2p&archiveformat=gz'>Spyware</a>, - <a target=_new href='http://list.iblocklist.com/?list=bt_proxy&fileformat=p2p&archiveformat=gz'>Proxies</a><br /><br /> - <strong><u>'pfSense Local File'</u></strong> Format:<br /><br /> - http(s)://127.0.0.1/NAME_OF_FILE <strong>or</strong> - /usr/local/www/NAME_OF_FILE (Files can also be placed in the /var/db/pfblockerng folders)<br /><br /> - - <strong><u>'Header'</u></strong>: The <u>'Header' Field</u> must be <u>Unique</u>, it will - name the List File and it will be referenced in the pfBlockerNG Widget. - Use a Unique Prefix per 'Alias Category' followed by a unique descriptor for each List.<br /><br />]]> + <description><![CDATA[<strong><u>'Format'</u></strong>: Select the Format type.<br /><br /> + <strong><u>'State'</u></strong>: Select the run state.<br /><br /> + <strong><u>'Source'</u></strong>: + <ul><li><strong>'URL'</strong>: External link to source +  (ie: <a target="_blank" href='https://rules.emergingthreats.net/blockrules/compromised-ips.txt'>ET Compromised</a>, + <a target="_blank" href='https://rules.emergingthreats.net/fwrules/emerging-Block-IPs.txt'>ET Blocked</a>, + <a target="_blank" href='https://www.spamhaus.org/drop/drop.txt'>Spamhaus Drop</a>)</li></ul> + <ul><li><strong>'Local File'</strong>: http(s)://127.0.0.1/filename +  <strong>or</strong>  /var/db/pfblockerng/filename</li></ul> + <ul><li><strong>'Country code'</strong>: /usr/pbi/pfblockerng-amd64/share/GeoIP/cc/US_v4.txt +  (Change 'US' to required code)</li></ul> + <ul><li><strong>'Whois'</strong>: Domain name or AS (ie: facebook.com or AS13414) +  ( <a target="_blank" href='https://asn.cymru.com/'>Click for ASN Lookup</a> )</li></ul> + <strong><u>'Header/Label'</u></strong>: This field must be <u>unique.</u> This names the file and is referenced in the widget. +  (ie: Spamhaus_drop, Spamhaus_edrop)<br /><br />]]> </description> </field> <field> <fielddescr><![CDATA[<strong>IPv4</strong> Lists]]></fielddescr> - <description><![CDATA[<br /><strong>'Format'</strong> - Select the file format that URL will retrieve.<br /> - <ul><li><strong>'txt'</strong> Plain txt Lists</li> - <li><strong>'gz'</strong> - IBlock GZ Lists in Range Format only</li> - <li><strong>'gz_2'</strong> - Other GZ Lists in IP or CIDR only</li> - <li><strong>'gz_lg'</strong> - Large IBlock GZ Lists in Range Format only</li> - <li><strong>'zip'</strong> - ZIP'd Lists</li> - <li><strong>'block'</strong>- IP x.x.x.0 Block type</li> - <li><strong>'html'</strong> - Web Links</li> - <li><strong>'xlsx'</strong> - Excel Lists</li> - <li><strong>'rsync'</strong> - RSync Lists</li> - <li><strong>'ET' IQRisk</strong> - Only</li></ul> - <strong>'State'</strong> - Select the Run State for each list<br /> + <description><![CDATA[<br /><strong>'Format'</strong>: Select the file format that URL will retrieve.<br /> + <ul><li><strong>'auto'</strong> - Default parser</li> + <li><strong>'regex'</strong> - 'Regex' style parsing (ie: html Lists)</li> + <li><strong>'whois'</strong> - Convert a Domain name or AS into its respective IP addresses.</li> + <li><strong>'rsync'</strong> - RSync Lists</li></ul> + <strong>'State'</strong>: Select the Run State for each list<br /> <ul><li><strong>'ON/OFF'</strong> - Enabled / Disabled</li> - <li><strong>'HOLD'</strong> - Once a List has been Downloaded, list will remain Static</li></ul> - <strong>'Note' -</strong> Downloaded or pfsense local file must have only one network per line and follows the syntax below: + <li><strong>'HOLD'</strong> - Once a List has been Downloaded, list will remain Static</li> + <li><strong>'FLEX'</strong> - Not Recommended - Allow downgraded SSL connections</li></ul> + <strong>'Note'</strong>: Source lists musts follow the syntax below: <ul>Network ranges: <strong>172.16.1.0-172.16.1.255</strong><br /> IP Address: <strong>172.16.1.10</strong><br /> CIDR: <strong>172.16.1.0/24</strong></ul>]]> @@ -228,17 +202,12 @@ <fieldname>format</fieldname> <type>select</type> <options> - <option><name>txt</name><value>txt</value></option> - <option><name>gz</name><value>gz</value></option> - <option><name>gz_2</name><value>gz_2</value></option> - <option><name>gz_lg</name><value>gz_lg</value></option> - <option><name>zip</name><value>zip</value></option> - <option><name>block</name><value>block</value></option> - <option><name>html</name><value>html</value></option> - <option><name>xlsx</name><value>xlsx</value></option> + <option><name>Auto</name><value>auto</value></option> + <option><name>Regex</name><value>regex</value></option> + <option><name>Whois</name><value>whois</value></option> <option><name>RSync</name><value>rsync</value></option> - <option><name>ET</name><value>et</value></option> </options> + <default_value>auto</default_value> </rowhelperfield> <rowhelperfield> <fielddescr>State</fielddescr> @@ -248,16 +217,18 @@ <option><name>ON</name><value>Enabled</value></option> <option><name>OFF</name><value>Disabled</value></option> <option><name>HOLD</name><value>Hold</value></option> + <option><name>FLEX</name><value>Flex</value></option> </options> + <default_value>Enabled</default_value> </rowhelperfield> <rowhelperfield> - <fielddescr>URL or pfSense local file</fielddescr> + <fielddescr>Source</fielddescr> <fieldname>url</fieldname> <type>input</type> <size>50</size> </rowhelperfield> <rowhelperfield> - <fielddescr>Header</fielddescr> + <fielddescr>Header/Label</fielddescr> <fieldname>header</fieldname> <type>input</type> <size>15</size> @@ -296,11 +267,9 @@ <li>'Alias Deny' can use De-Duplication and Reputation Processes if configured.</li><br /> <li>'Alias Permit' and 'Alias Match' will be saved in the Same folder as the other Permit/Match Auto-Rules</li><br /> <li>'Alias Native' lists are kept in their Native format without any modifications.</li></ul> - <strong>When using 'Alias' rules, change (pfB_) to ( pfb_ ) in the beginning of rule description and Use the 'Exact' spelling of - the Alias (no trailing Whitespace)</strong> Custom 'Alias' rules with 'pfB_ xxx' description will be removed by package if - using Auto Rule Creation.<br /><br /><strong>Tip</strong>: You can create the Auto Rules and remove "<u>auto rule</u>" from the Rule - Descriptions, then disable Auto Rules. This method will 'KEEP' these rules from being 'Deleted' which will allow editing for a Custom - Alias Configuration<br />]]> + <font color='red'>Note: </font><ul>When manually creating 'Alias' type firewall rules; <strong>Do not add</strong> (pfB_) to the + start of the rule description, use (pfb_) (Lowercase prefix). Manually created 'Alias' rules with 'pfB_' in the + description will be auto-removed by package when 'Auto' rules are defined.</ul>]]> </description> <fieldname>action</fieldname> <type>select</type> @@ -373,13 +342,24 @@ </options> </field> <field> + <fieldname>stateremoval</fieldname> + <fielddescr>States Removal</fielddescr> + <description>With the 'Kill States' option (General Tab), you can disable States removal for this Alias.</description> + <type>select</type> + <options> + <option><name>Enable</name><value>enabled</value></option> + <option><name>Disable</name><value>disabled</value></option> + </options> + <default_value>enabled</default_value> + </field> + <field> <name>Advanced Inbound Firewall Rule Settings</name> <type>listtopic</type> </field> <field> <type>info</type> - <description><![CDATA[<font color='red'>Note: </font>In general Auto-Rules are created as follows:<br /> - <ul>Inbound - 'any' port, 'any' protocol and 'any' destination<br /> + <description><![CDATA[<font color='red'>Note: </font> In general, Auto-Rules are created as follows:<br /> + <ul>Inbound  - 'any' port, 'any' protocol and 'any' destination<br /> Outbound - 'any' port, 'any' protocol and 'any' destination address in the lists</ul> Configuring the Adv. Inbound Rule settings, will allow for more customization of the Inbound Auto-Rules.<br /> <strong>Select the pfSense 'Port' and/or 'Destination' Alias below:</strong>]]> @@ -440,7 +420,8 @@ <field> <fielddescr>Custom Protocol</fielddescr> <fieldname>autoproto</fieldname> - <description><![CDATA[<strong>Default: any</strong><br />Select the Protocol used for Inbound Firewall Rule(s).]]></description> + <description><![CDATA[<strong>Default: any</strong><br />Select the Protocol used for Inbound Firewall Rule(s).<br /> + Do not use 'any' with Adv. Inbound Rules as it will bypass these settings!]]></description> <type>select</type> <options> <option><name>any</name><value></value></option> @@ -456,14 +437,38 @@ <type>listtopic</type> </field> <field> - <fielddescr>IPv4 Custom Address(es)</fielddescr> + <type>info</type> + <description><![CDATA[<font color='red'>Note: </font> Custom List can be used in <strong>ONE</strong> of two ways:<br /> + <ul>1. IPv4 addresses entered directly into the custom list, as per the required format.</ul> + <ul>2. Domain names or AS numbers, which will be converted into their respective IPv4 addresses.</ul>]]> + </description> + </field> + <field> + <fieldname>whois_convert</fieldname> + <description><![CDATA[Select to enable 'Domain/AS' conversion. + <font color='red'>DO NOT</font> mix IPs with Domains/ASs in this custom list.]]> + </description> + <fielddescr>Enable Domain/AS</fielddescr> + <type>checkbox</type> + </field> + <field> + <fielddescr>Custom Address(es)</fielddescr> <fieldname>custom</fieldname> - <description><![CDATA[Please limit the size of the Custom List as this is stored as 'Base64' format in the config.xml file.<br /> - Follow the syntax below:<br /><br /> + <description><![CDATA[Please limit the size of the Custom List as this is stored as 'Base64' format in the config.xml file.<br /><br /> + <strong>Format IPv4:</strong><br /><br /> Network ranges: <strong>172.16.1.0-172.16.1.255</strong><br /> IP Address: <strong>172.16.1.10</strong><br /> CIDR: <strong>172.16.1.0/24</strong><br /><br /> - You may use "<strong>#</strong>" after any IP/CIDR/Range to add comments. ie: x.x.x.x # Safe IP Address]]> + RFC 1918 addresses may be used in a custom list.<br /> + You may use "<strong>#</strong>" after any IP/CIDR/Range to add comments. ie: x.x.x.x # Safe IP Address<br /><br /> + If you select the <strong>Domain/AS</strong> checkbox above, the custom list can <strong>only</strong> + be used for Domain names/AS's.<br /><br /> + <strong>Format Domain/AS:</strong><br /><br /> + One 'Domain' or 'AS' per line.<br /> + Domains and/or ASs can be used in the same list.<br /><br /> + Conversion of Domains/ASs utilize <a target="_blank" href="http://www.team-cymru.org/IP-ASN-mapping.html">Team CYMRU</a> + and the <a target="_blank" href="http://www.radb.net/">RADb</a> whois registry.<br /> + Configure the 'update frequency', so that it does not <strong>abuse</strong> these free services.]]> </description> <type>textarea</type> <cols>50</cols> @@ -484,23 +489,21 @@ </options> </field> <field> - <name><![CDATA[<center>Click to SAVE Settings and/or Rule Edits. Changes are Applied via CRON or + <name><![CDATA[<center>Click to SAVE Settings and/or Rule Edits.   Changes are Applied via CRON or 'Force Update'</center>]]></name> <type>listtopic</type> </field> </fields> - <custom_php_install_command> - pfblockerng_php_install_command(); - </custom_php_install_command> - <custom_php_deinstall_command> - pfblockerng_php_deinstall_command(); - </custom_php_deinstall_command> <custom_php_validation_command> + <![CDATA[ pfblockerng_validate_input($_POST, $input_errors); + ]]> </custom_php_validation_command> <custom_php_resync_config_command> + <![CDATA[ global $pfb; $pfb['save'] = TRUE; sync_package_pfblockerng(); + ]]> </custom_php_resync_config_command> </packagegui>
\ No newline at end of file diff --git a/config/pfblockerng/pfblockerng_v6lists.xml b/config/pfblockerng/pfblockerng_v6lists.xml index 3e9dbe6f..e5f30caa 100644 --- a/config/pfblockerng/pfblockerng_v6lists.xml +++ b/config/pfblockerng/pfblockerng_v6lists.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" ?> -<!DOCTYPE packagegui SYSTEM "./schema/packages.dtd"> -<?xml-stylesheet type="text/xsl" href="./xsl/package.xsl"?> +<!DOCTYPE packagegui SYSTEM "../schema/packages.dtd"> +<?xml-stylesheet type="text/xsl" href="../xsl/package.xsl"?> <packagegui> <copyright> <![CDATA[ @@ -9,14 +9,15 @@ pfBlockerNG_v6lists.xml pfBlockerNG - Copyright (C) 2015 BBcan177@gmail.com + Copyright (c) 2015 BBcan177@gmail.com All rights reserved. Based upon pfblocker for pfSense - Copyright (C) 2011 Marcello Coutinho + Copyright (c) 2011 Marcello Coutinho - part of pfSense (http://www.pfSense.com) - Copyright (C) 2010 Scott Ullrich <sullrich@gmail.com> + part of pfSense (http://www.pfSense.org) + Copyright (c) 2015 Electric Sheep Fencing, LLC. All rights reserved. + Copyright (c) 2004-2005 Scott Ullrich All rights reserved. */ /* ========================================================================== */ @@ -64,7 +65,7 @@ <tabs> <tab> <text>General</text> - <url>/pkg_edit.php?xml=pfblockerng.xml&id=0</url> + <url>/pkg_edit.php?xml=pfblockerng.xml</url> <tooltiptext></tooltiptext> </tab> <tab> @@ -77,48 +78,24 @@ </tab> <tab> <text>Reputation</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_reputation.xml</url> </tab> <tab> <text>IPv4</text> - <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml&id=0</url> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v4lists.xml</url> </tab> <tab> <text>IPv6</text> - <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml&id=0</url> + <url>/pkg.php?xml=/pfblockerng/pfblockerng_v6lists.xml</url> <active/> </tab> <tab> - <text>Top 20</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml&id=0</url> + <text>DNSBL</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_dnsbl.xml</url> </tab> <tab> - <text>Africa</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Africa.xml&id=0</url> - </tab> - <tab> - <text>Asia</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Asia.xml&id=0</url> - </tab> - <tab> - <text>Europe</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Europe.xml&id=0</url> - </tab> - <tab> - <text>N.A.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_NorthAmerica.xml&id=0</url> - </tab> - <tab> - <text>Oceania</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_Oceania.xml&id=0</url> - </tab> - <tab> - <text>S.A.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_SouthAmerica.xml&id=0</url> - </tab> - <tab> - <text>P.S.</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_ProxyandSatellite.xml&id=0</url> + <text>Country</text> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_top20.xml</url> </tab> <tab> <text>Logs</text> @@ -126,50 +103,49 @@ </tab> <tab> <text>Sync</text> - <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml&id=0</url> + <url>/pkg_edit.php?xml=/pfblockerng/pfblockerng_sync.xml</url> </tab> </tabs> - <adddeleteeditpagefields> - <columnitem> - <fielddescr>Alias Name</fielddescr> - <fieldname>aliasname</fieldname> - </columnitem> - <columnitem> - <fielddescr>Alias Description</fielddescr> - <fieldname>description</fieldname> - </columnitem> - <columnitem> - <fielddescr>Action</fielddescr> - <fieldname>action</fieldname> - </columnitem> - <columnitem> - <fielddescr>Frequency</fielddescr> - <fieldname>cron</fieldname> - </columnitem> - <columnitem> - <fielddescr>Logging</fielddescr> - <fieldname>aliaslog</fieldname> - </columnitem> - <addtext>Add a new Alias</addtext> - <movable>on</movable> - </adddeleteeditpagefields> + <adddeleteeditpagefields> + <columnitem> + <fielddescr>Alias Name</fielddescr> + <fieldname>aliasname</fieldname> + </columnitem> + <columnitem> + <fielddescr>Alias Description</fielddescr> + <fieldname>description</fieldname> + </columnitem> + <columnitem> + <fielddescr>Action</fielddescr> + <fieldname>action</fieldname> + </columnitem> + <columnitem> + <fielddescr>Frequency</fielddescr> + <fieldname>cron</fieldname> + </columnitem> + <columnitem> + <fielddescr>Logging</fielddescr> + <fieldname>aliaslog</fieldname> + </columnitem> + <addtext>Add a new Alias</addtext> + <movable>on</movable> + </adddeleteeditpagefields> <fields> <field> - <name>IPv6 Network ranges / CIDR lists</name> + <name><![CDATA[IPv6 -   Run 'Force Update' to deploy new Settings.  ]]></name> <type>listtopic</type> </field> <field> <fielddescr>LINKS</fielddescr> - <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a> - <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> + <description><![CDATA[<a href="/firewall_aliases.php">Firewall Alias</a>  + <a href="/firewall_rules.php">Firewall Rules</a> <a href="diag_logs_filter.php">Firewall Logs</a>]]> </description> <type>info</type> </field> <field> <fielddescr>Alias Name</fielddescr> <fieldname>aliasname</fieldname> - <description><![CDATA[Enter Alias Name.<br /> - Example: Badguys<br /> + <description><![CDATA[Enter Alias Name ( Example: Badguys )<br /> Do not include <strong>'pfBlocker' or 'pfB_'</strong> in the Alias Name, it's done by package.<br /> <strong>International, special or space characters will be ignored in firewall alias names. </strong><br />]]> @@ -185,38 +161,33 @@ </field> <field> <type>info</type> - <description><![CDATA[<strong><u>'Format'</u></strong>: Select the Format Type<br /><br /> - <strong><u>'URL'</u></strong>: Add direct link to list: - Example: <a target=_new href='http://list.iblocklist.com/?list=bt_ads&fileformat=p2p&archiveformat=gz'>Ads</a>, - <a target=_new href='http://list.iblocklist.com/?list=bt_spyware&fileformat=p2p&archiveformat=gz'>Spyware</a>, - <a target=_new href='http://list.iblocklist.com/?list=bt_proxy&fileformat=p2p&archiveformat=gz'>Proxies</a><br /><br /> - <strong><u>'pfSense Local File'</u></strong> Format:<br /><br /> - http(s)://127.0.0.1/NAME_OF_FILE <strong>or</strong> - /usr/local/www/NAME_OF_FILE (Files can also be placed in the /var/db/pfblockerng folders)<br /><br /> - - <strong><u>'Header'</u></strong>: The <u>'Header' Field</u> must be <u>Unique</u>, it will - name the List File and it will be referenced in the pfBlockerNG Widget. - Use a Unique Prefix per 'Alias Category' followed by a unique descriptor for each List.<br /><br />]]> + <description><![CDATA[<strong><u>'Format'</u></strong>: Select the Format type.<br /><br /> + <strong><u>'State'</u></strong>: Select the run state.<br /><br /> + <strong><u>'Source'</u></strong>: + <ul><li><strong>'URL'</strong>: External link to source +  (ie: <a target="_blank" href='https://lists.blocklist.de/lists/all.txt'>Blocklist.de</a>)</li></ul> + <ul><li><strong>'Local File'</strong>: http(s)://127.0.0.1/filename +  <strong>or</strong>  /var/db/pfblockerng/filename</li></ul> + <ul><li><strong>'Country code'</strong>: /usr/pbi/pfblockerng-amd64/share/GeoIP/cc/US_v6.txt +  (Change 'US' to required code)</li></ul> + <ul><li><strong>'Whois'</strong>: Domain name or AS (ie: facebook.com or AS13414) +  ( <a target="_blank" href='https://asn.cymru.com/'>Click for ASN Lookup</a> )</li></ul> + <strong><u>'Header/Label'</u></strong>: This field must be <u>unique.</u> This names the file and is referenced in the widget. +  (ie: Spamhaus_drop, Spamhaus_edrop)<br /><br />]]> </description> </field> <field> <fielddescr><![CDATA[<strong>IPv6</strong> Lists]]></fielddescr> - <description><![CDATA[<br /><strong>'Format'</strong> - Select the file format that URL will retrieve.<br /> - <ul><li><strong>'txt'</strong> Plain txt Lists</li> - <li><strong>'gz'</strong> - IBlock GZ Lists in Range Format only</li> - <li><strong>'gz_2'</strong> - Other GZ Lists in IP or CIDR only</li> - <li><strong>'zip'</strong> - ZIP'd Lists</li> - <li><strong>'block'</strong>- IP x.x.x.0 Block type</li> - <li><strong>'html'</strong> - Web Links</li> - <li><strong>'xlsx'</strong> - Excel Lists</li> - <li><strong>'rsync'</strong> - RSync Lists</li> - <strong>'State'</strong> - Select the Run State for each list<br /> + <description><![CDATA[<br /><strong>'Format'</strong>: Select the file format that URL will retrieve.<br /> + <ul><li><strong>'auto'</strong> - Default parser</li> + <li><strong>'regex'</strong> - 'Regex' style parsing (ie: html Lists)</li> + <li><strong>'whois'</strong> - Convert a Domain name or AS into its respective IP addresses.</li> + <li><strong>'rsync'</strong> - RSync Lists</li></ul> + <strong>'State'</strong>: Select the Run State for each list<br /> <ul><li><strong>'ON/OFF'</strong> - Enabled / Disabled</li> - <li><strong>'HOLD'</strong> - Once a List has been Downloaded, list will remain Static</li></ul> - <strong>'Note' -</strong> Downloaded or pfsense local file must have only one network per line and follows the syntax below: - <ul>Network ranges: <strong> TBC </strong><br /> - IP Address: <strong> TBC </strong><br /> - CIDR: <strong> TBC </strong></ul>]]> + <li><strong>'HOLD'</strong> - Once a List has been Downloaded, list will remain Static</li> + <li><strong>'FLEX'</strong> - Not Recommended - Allow downgraded SSL connections</li></ul> + <strong>'Note'</strong>: Downloaded or pfsense local file musts have the syntax (See customlist below)</ul>]]> </description> <type>rowhelper</type> <rowhelper> @@ -225,15 +196,12 @@ <fieldname>format</fieldname> <type>select</type> <options> - <option><name>txt</name><value>txt</value></option> - <option><name>gz</name><value>gz</value></option> - <option><name>gz_2</name><value>gz_2</value></option> - <option><name>zip</name><value>zip</value></option> - <option><name>block</name><value>block</value></option> - <option><name>html</name><value>html</value></option> - <option><name>xlsx</name><value>xlsx</value></option> + <option><name>Auto</name><value>auto</value></option> + <option><name>Regex</name><value>regex</value></option> + <option><name>Whois</name><value>whois</value></option> <option><name>RSync</name><value>rsync</value></option> </options> + <default_value>auto</default_value> </rowhelperfield> <rowhelperfield> <fielddescr>State</fielddescr> @@ -243,16 +211,18 @@ <option><name>ON</name><value>Enabled</value></option> <option><name>OFF</name><value>Disabled</value></option> <option><name>HOLD</name><value>Hold</value></option> + <option><name>FLEX</name><value>Flex</value></option> </options> + <default_value>Enabled</default_value> </rowhelperfield> <rowhelperfield> - <fielddescr>URL or pfSense local file</fielddescr> + <fielddescr>Source</fielddescr> <fieldname>url</fieldname> <type>input</type> <size>50</size> </rowhelperfield> <rowhelperfield> - <fielddescr>Header</fielddescr> + <fielddescr>Header/Label</fielddescr> <fieldname>header</fieldname> <type>input</type> <size>15</size> @@ -291,11 +261,9 @@ <li>'Alias Deny' can use De-Duplication and Reputation Processes if configured.</li><br /> <li>'Alias Permit' and 'Alias Match' will be saved in the Same folder as the other Permit/Match Auto-Rules</li><br /> <li>'Alias Native' lists are kept in their Native format without any modifications.</li></ul> - <strong>When using 'Alias' rules, change (pfB_) to ( pfb_ ) in the beginning of rule description and Use the 'Exact' spelling of - the Alias (no trailing Whitespace) </strong> Custom 'Alias' rules with 'pfB_ xxx' description will be removed by package if - using Auto Rule Creation.<br /><br /><strong>Tip</strong>: You can create the Auto Rules and remove "<u>auto rule</u>" from the Rule - Descriptions, then disable Auto Rules. This method will 'KEEP' these rules from being 'Deleted' which will allow editing for a Custom - Alias Configuration<br />]]> + <font color='red'>Note: </font><ul>When manually creating 'Alias' type firewall rules; <strong>Do not add</strong> (pfB_) to the + start of the rule description, use (pfb_) (Lowercase prefix). Manually created 'Alias' rules with 'pfB_' in the + description will be auto-removed by package when 'Auto' rules are defined.</ul>]]> </description> <fieldname>action</fieldname> <type>select</type> @@ -368,13 +336,24 @@ </options> </field> <field> + <fieldname>stateremoval</fieldname> + <fielddescr>States Removal</fielddescr> + <description>With the 'Kill States' option (General Tab), you can disable States removal for this Alias.</description> + <type>select</type> + <options> + <option><name>Enable</name><value>enabled</value></option> + <option><name>Disable</name><value>disabled</value></option> + </options> + <default_value>enabled</default_value> + </field> + <field> <name>Advanced Inbound Firewall Rule Settings</name> <type>listtopic</type> </field> <field> <type>info</type> - <description><![CDATA[<font color='red'>Note: </font>In general Auto-Rules are created as follows:<br /> - <ul>Inbound - 'any' port, 'any' protocol and 'any' destination<br /> + <description><![CDATA[<font color='red'>Note: </font> In general, Auto-Rules are created as follows:<br /> + <ul>Inbound  - 'any' port, 'any' protocol and 'any' destination<br /> Outbound - 'any' port, 'any' protocol and 'any' destination address in the lists</ul> Configuring the Adv. Inbound Rule settings, will allow for more customization of the Inbound Auto-Rules.<br /> <strong>Select the pfSense 'Port' and/or 'Destination' Alias below:</strong>]]> @@ -435,7 +414,8 @@ <field> <fielddescr>Custom Protocol</fielddescr> <fieldname>autoproto</fieldname> - <description><![CDATA[<strong>Default: any</strong><br />Select the Protocol used for Inbound Firewall Rule(s).]]></description> + <description><![CDATA[<strong>Default: any</strong><br />Select the Protocol used for Inbound Firewall Rule(s).<br /> + Do not use 'any' with Adv. Inbound Rules as it will bypass these settings!]]></description> <type>select</type> <options> <option><name>any</name><value></value></option> @@ -451,14 +431,51 @@ <type>listtopic</type> </field> <field> - <fielddescr>IPv6 Custom Address(es)</fielddescr> + <type>info</type> + <description><![CDATA[<font color='red'>Note: </font> Custom List can be used in <strong>ONE</strong> of two ways:<br /> + <ul>1. IPv6 addresses entered directly into the custom list, as per the required format.</ul> + <ul>2. Domain names or AS numbers, which will be converted into their respective IPv6 addresses.</ul>]]> + </description> + </field> + <field> + <fieldname>whois_convert</fieldname> + <description><![CDATA[Select to enable 'Domain/AS' conversion. + <font color='red'>DO NOT</font> mix IPs with Domains/ASs in this custom list.]]> + </description> + <fielddescr>Enable Domain/AS</fielddescr> + <type>checkbox</type> + </field> + <field> + <fielddescr>Custom Address(es)</fielddescr> <fieldname>custom</fieldname> - <description><![CDATA[Please limit the size of the Custom List as this is stored as 'Base64' format in the config.xml file.<br /> - Follow the syntax below:<br /><br /> - Network ranges: <strong> TBC </strong><br /> - IP Address: <strong> TBC </strong><br /> - CIDR: <strong> TBC </strong><br /><br /> - You may use "<strong>#</strong>" after any IP/CIDR/Range to add comments. # Safe IP Address]]> + <description><![CDATA[Please limit the size of the Custom List as this is stored as 'Base64' format in the config.xml file.<br /><br /> + <strong>Format IPv6:</strong><br /><br /> + + Source of Regex and format descriptions: <a href="http://labs.spritelink.net/regex">SpriteLink</a><br /> + fe80:0000:0000:0000:0204:61ff:fe9d:f156 // full form of IPv6<br /> + fe80:0:0:0:204:61ff:fe9d:f156 // drop leading zeroes<br /> + fe80::204:61ff:fe9d:f156 // collapse multiple zeroes to :: in the IPv6 address<br /> + fe80:0000:0000:0000:0204:61ff:254.157.241.086 // IPv4 dotted quad at the end<br /> + fe80:0:0:0:0204:61ff:254.157.241.86 // drop leading zeroes, IPv4 dotted quad at the end<br /> + fe80::204:61ff:254.157.241.86 // dotted quad at the end, multiple zeroes collapsed<br /><br /> + + In addition, the regular expression matches these IPv6 forms:<br /><br /> + + ::1 // localhost<br /> + fe80:: // link-local prefix<br /> + 2000:: // global unicast prefix<br /> + Any slash-notation style prefix<br /><br /> + + Private IPv6 addresses may be used in a custom list.<br /> + You may use "<strong>#</strong>" after any IP/CIDR/Range to add comments. ie: x::x:x:x:x # Safe IP Address<br /><br /> + If you select the <strong>Domain/AS</strong> checkbox above, the custom list can <strong>only</strong> + be used for Domain names/AS's.<br /><br /> + <strong>Format Domain/AS:</strong><br /><br /> + One 'Domain' or 'AS' per line.<br /> + Domains and/or ASs can be used in the same list.<br /><br /> + Conversion of Domains/ASs utilize <a target="_blank" href="http://www.team-cymru.org/IP-ASN-mapping.html">Team CYMRU</a> + and the <a target="_blank" href="http://www.radb.net/">RADb</a> whois registry.<br /> + Configure the 'update frequency', so that it does not <strong>abuse</strong> these free services.]]> </description> <type>textarea</type> <cols>50</cols> @@ -479,23 +496,21 @@ </options> </field> <field> - <name><![CDATA[<center>Click to SAVE Settings and/or Rule Edits. Changes are Applied via CRON or + <name><![CDATA[<center>Click to SAVE Settings and/or Rule Edits.   Changes are Applied via CRON or 'Force Update'</center>]]></name> <type>listtopic</type> </field> </fields> - <custom_php_install_command> - pfblockerng_php_install_command(); - </custom_php_install_command> - <custom_php_deinstall_command> - pfblockerng_php_deinstall_command(); - </custom_php_deinstall_command> <custom_php_validation_command> + <![CDATA[ pfblockerng_validate_input($_POST, $input_errors); + ]]> </custom_php_validation_command> <custom_php_resync_config_command> + <![CDATA[ global $pfb; $pfb['save'] = TRUE; sync_package_pfblockerng(); + ]]> </custom_php_resync_config_command> </packagegui>
\ No newline at end of file |