ConfigServer Firewall has been great at keeping unwanted users at bay on my web servers, but it also causes plenty of problems – notably when the SMTP authentication fails multiple times. This is usually caused by an email account trying to send an email and repeatedly using bad credentials to login. After a short period of time, CSF or cPHulk kicks in and blocks all communication with their website.
Managing this is a pain as there is no way (as far as I can tell) to allow clients to white list themselves when this happens. So, I’ve put up a page on a different server that handles requests for white listing.
There are two components here: one for the self-contained request page and a bash script to handle the white listing quickly, away from cPanel.
<?php /*****************************************************\ * * * REMOTE SERVER CLIENT BLOCK CHECK PAGE * * * * Coded by Noah Hearle, Design Extreme * * http://designextreme.com * * * * Created: 2015/05/06 * * Modified: 2015/05/19 * * * * Post your comments at: * * https://blog.nahoo.co.uk/server-white-listing/ * * * \*****************************************************/ session_start(); chdir(__DIR__); define('EMAIL_SUBJECT', 'IP Whitelist Request'); define('RECIPIENT_NAME', 'Your Name'); define('RECIPIENT_EMAIL', 'rs_wpss_encode_strip@yourdomain.com'); define('ADMIN_CODE', 'SomeRandomCode23234'); define('DATA_FILE', '../ip_log.txt'); define('REMOTE_URL', 'http://yourdomain.com/simple/test/page/'); define('REMOTE_IMAGE_URL', 'http://yourdomain.com/test/image.gif'); define('WHITE_LIST_SCRIPT_PATH', '/path/to/script/whitelist_ip.sh'); define('HISTORY_LENGTH', 10); $ip = getip(); $ignore = (isset($_REQUEST['ignore']) && $_REQUEST['ignore']); $name = (isset($_POST['name']) && $_POST['name'] != NULL) ? preg_replace('/,/','',$_POST['name']) : NULL; $email = (isset($_POST['email']) && $_POST['email'] != NULL) ? preg_replace('/,/','',$_POST['email']) : NULL; $status = (isset($_POST['status']) && $_POST['status'] != NULL) ? preg_replace('/,/','',$_POST['status']) : NULL; $admin = (isset($_GET[ADMIN_CODE])) ? (bool)$_GET[ADMIN_CODE] : ((isset($_SESSION['ip_admin'])) ? $_SESSION['ip_admin'] : FALSE); $email_sent = (isset($_SESSION['ip_email_sent']) && $_SESSION['ip_email_sent'] != NULL) ? $_SESSION['ip_email_sent'] : FALSE; if (!$admin && ((!isset($_SESSION['ip']) || isset($_SESSION['ip']) && $_SESSION['ip'] != $ip) || ($name != NULL && $email != NULL))) { if (!$ignore) { $fp = fopen(DATA_FILE, 'a'); fputs($fp, date("Y-m-d H:i").','.$ip.(($name != NULL && $email != NULL) ? ','.$name.','.$email.','.$status : '')."\n"); fclose($fp); } if (!$email_sent && preg_match('/^\w+([-+.]\w+)*@(\w+([-.]\w+)*\.\w+([-.]\w+)*)$/i',$email) && checkdnsrr(preg_replace('/[^@]*@([^@]+)$/','$1',$email), 'MX')) { if ($ignore) { $email_sent = time(); } else { $data = array( 'sender_email' => $email, 'sender_name' => $name, 'recipient_email' => RECIPIENT_EMAIL, 'recipient_name' => RECIPIENT_NAME, 'subject' => EMAIL_SUBJECT, 'text' => 'New IP Whitelist request from '.$name.' <'.$email.'> on '.date("r").PHP_EOL.PHP_EOL.'Status: '.$status.PHP_EOL.PHP_EOL.'IP: '.$ip.PHP_EOL.PHP_EOL.'sh '.WHITE_LIST_SCRIPT_PATH.' '.$ip ); if (email($data)) { $email_sent = time(); } } } } $_SESSION['ip'] = $ip; $_SESSION['ip_admin'] = $admin; $_SESSION['ip_email_sent'] = $email_sent; if ($admin) { $ip_tail = tail_ip_log(DATA_FILE, HISTORY_LENGTH, FALSE); } function getip() { if( isset( $_SERVER["HTTP_X_FORWARDED_FOR"] ) ) { $realip = $_SERVER["HTTP_X_FORWARDED_FOR"]; } elseif( isset( $_SERVER["HTTP_CLIENT_IP"] ) ) { $realip = $_SERVER["HTTP_CLIENT_IP"]; } else { $realip = $_SERVER["REMOTE_ADDR"]; } return $realip; } function tail_ip_log($file, $count=10, $repeat=TRUE) { $ret = array(); $data = file($file); if (empty($data)) { return $ret; } for ($i = (count($data)-1); $i>0; $i--) { if (!preg_match('/^([^,]+),([^,]+)(?:,([^,]+),([^,]+)(?:,([^,]+))?)?$/i', $data[$i], $m)) { continue; } $k = (!$repeat) ? str_replace('.', '_', $m[2]) : $i; if (!$repeat && array_key_exists($k,$ret)) { continue; } $ret[$k] = array($m[1],$m[2],$m[3],$m[4],$m[5]); $count--; if ($count == 0) { break; } } return $ret; } function email ($data) { $sender_email = (string)$data['sender_email']; $sender_name = (string)$data['sender_name']; $return_email = (isset($data['return_email'])) ? (string)$data['return_email'] : (string)$data['sender_email']; $recipient_email = (string)$data['recipient_email']; $recipient_name = (string)$data['recipient_name']; $subject = (isset($data['subject']) && $data['subject'] != NULL) ? (string)$data['subject'] : 'No Subject'; $text = (isset($data['text'])) ? $data['text'] : NULL; $html = (isset($data['html'])) ? $data['html'] : nl2br(htmlspecialchars($text)); $sender = $sender_name.' <'.$sender_email.'>'; $recipient = $recipient_name.' <'.$recipient_email.'>'; $newline = (preg_match('/win/i',strtolower(php_uname('s')))) ? "\r\n" : "\n"; $headers = 'From: '.$sender.$newline; $headers .= 'Reply-To: '.$sender_email.$newline; $headers .= 'X-Mailer: PHP/'.phpversion().$newline; return mail($recipient, $subject, $text, $headers, '-f '.$return_email); } ?><!doctype html> <html> <head> <meta charset="utf-8"> <!----------------------------------------------------\ | | | REMOTE SERVER CLIENT BLOCK CHECK PAGE | | | | Coded by Noah Hearle, Design Extreme | | http://designextreme.com | | | | Created: 2015/05/06 | | Modified: 2015/05/19 | | | | Post your comments at: | | https://blog.nahoo.co.uk/server-white-listing/ | | | \-----------------------------------------------------> <title>Your IP Address is: <?= htmlspecialchars($ip); ?></title> <link href='http://fonts.googleapis.com/css?family=Slabo+27px&family=Roboto' rel='stylesheet' type='text/css'> <style type="text/css"> <!-- body,td,th,input,button { color:#D6D1A3; font-family:Roboto,Calibri,'Trebuchet MS',Arial; font-size:15px; } html { height:100%; } body { background:#000e00; background:-moz-linear-gradient(top,#000e00 0%,#404a40 100%); background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#000e00),color-stop(100%,#404a40)); background:-webkit-linear-gradient(top,#000e00 0%,#404a40 100%); background:-o-linear-gradient(top,#000e00 0%,#404a40 100%); background:-ms-linear-gradient(top,#000e00 0%,#404a40 100%); background:rgba(0,0,0,0) linear-gradient(to bottom,#000e00 0%,#404a40 100%) repeat scroll 0 0; filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#000e00',endColorstr='#404a40',GradientType=0); } h1 { font-family:'Slabo 27px','Courier New',Courier,monospace; font-size:60px; font-weight:700; text-shadow:0 4px 1px rgba(0,0,0,0.8); margin:40px 0; } h2 { margin:20px 0; font-size:30px; } h3 { margin:20px 0; font-size:25px; } p { line-height:140%; } #main { background-color:rgba(100,255,100,0.08); border:2px solid #6a856a; border-radius:5px; box-shadow:14px 16px 10px rgba(0,0,0,0.09),-9px -5px 32px rgba(133,233,155,0.19) inset; margin:120px auto 0; max-width:1300px; min-width:360px; padding:30px 20px; text-align:center; width:85%; } table { width:320px; margin:20px auto; } table th,table td { text-align:left; padding:6px; } #admin { width:auto; } #admin th,#admin td { text-align:left; padding:6px; border-bottom:1px dashed #D6D1A3; } input { background-color:#eeecc4; border:1px solid #d6d1a3; color:#555f2e; padding:4px 2%; width:96%; } button { background-color:rgba(100,255,100,0.08); border:2px solid #6a856a; border-radius:3px; box-shadow:14px 16px 10px rgba(0,0,0,0.09),-9px -5px 32px rgba(133,233,155,0.19) inset; color:#eeecc4; font-weight:700; padding:4px 0; width:100%; } #circle { font-family:Helvetica,Arial,sans-serif; color:#433F23; border:4px solid #d6d1a3; border-radius:104px; font-size:200px; font-weight:700; height:200px; line-height:104%; margin:0 auto; padding:0; text-align:center; width:200px; transition:all 2s ease-in-out; } #circle_frame { height:212px; border:0 none; overflow:hidden; width:212px; text-align:center; } #circle.allowed { border:4px solid #A8BF27; color:#A8BF27; } #circle.blocked { border:4px solid #D56567; color:#D56567; } #circle.unknown { color:#d6d1a3; } --> </style> <script> <!-- var count = 0; function remote_server_connection(count, status, img) { if (typeof count == 'undefined') { count = 0; } if (typeof status == 'undefined') { status = 'Unknown'; } if (typeof img == 'undefined') { img = null; } var http = new XMLHttpRequest(), url = '<?= REMOTE_URL; ?>', image_url = '<?= REMOTE_IMAGE_URL; ?>'; if (count == 0) { img = new Image(); img.onerror = function () { this.src = null; return 'Blocked'; } img.src = image_url; count++; } else if (count == 1 && img != null) { count++; if (img.height > 0) { status = 'Allowed'; } } else { count++; if (http.open('HEAD', url, false)) { http.send(); status = (http.status == 200) ? 'Allowed' : 'Blocked'; } } if (!document.getElementById('circle')) { document.getElementById('circle_container').innerHTML = '<div id="circle"></div>'; } if (status == null) { status = 'Unknown'; } if (count < 2 && status == 'Unknown') { setTimeout(function() { status = remote_server_connection(count, status, img)}, 400); } else { document.getElementById('server_status').value = status; document.getElementById('circle').className = status.toLowerCase(); document.getElementById('circle').innerHTML = ((status == 'Allowed') ? '☑' : ((status == 'Blocked') ? '☒' : '?')); if (status == 'Unknown') { document.getElementById('circle_container').innerHTML = '<iframe src="<?= REMOTE_URL; ?>" id="circle_frame"></iframe>'; } } if (document.getElementById('current_status_message')) { switch (status) { case 'Allowed': document.getElementById('current_status_message').innerHTML = 'Your IP is not blacklisted and you should have no problems connecting to your website and emails.'; document.getElementById('submission_form').style.opacity = 0.66; break; case 'Blocked': document.getElementById('current_status_message').innerHTML = 'It appears that you’re blocked from accessing your website and emails and your IP may be blacklisted. Please send us your IP address here.'; break; default: break; } } return status; } window.onload = function() { if (document.getElementById('server_status')) { remote_server_connection(count); } else { setInterval(function() { window.location.reload(); }, 120000); } } --> </script> </head> <body> <div id="main"> <form action="./" method="post" id="form"> <h3>Your IP Address is: </h3> <h1><?= htmlspecialchars($ip); ?></h1> <?php if ($admin) { ?> <table id="admin"> <tr> <th style="text-align: right;">Date</th> <th style="text-align: right;">IP</th> <th>Name</th> <th>Email</th> <th>Status</th> </tr> <?php $i = 0; foreach ($ip_tail as $a) { if ($a[0] == NULL) { continue; } echo ' <tr'.(($i > 0) ? ' style="opacity: '.(1-$i/HISTORY_LENGTH) : '').';"> <td style="text-align: right;">'.htmlspecialchars($a[0]).'</td> <td style="text-align: right;">'.htmlspecialchars($a[1]).'</td> <td>'.((isset($a[2]) && $a[2] != NULL) ? htmlspecialchars($a[2]) : '—').'</td> <td>'.((isset($a[3]) && $a[3] != NULL) ? htmlspecialchars($a[3]) : '—').'</td> <td>'.((isset($a[4]) && $a[4] != NULL) ? htmlspecialchars($a[4]) : '—').'</td> </tr> '; $i++; } ?> </table> <?php } else { if (($name != NULL && $email != NULL)) { if (!is_bool($email_sent) && $email_sent == time()) { ?> <p>Your details have been logged and an email notification has been sent.</p> <?php } else { ?> <p>Your details have been logged.</p> <?php } } else { ?> <p>Your IP address is a way to identify your internet connection. </p> <p id="current_status_message">If you’re having problems accessing your website and emails, your IP may be blacklisted. So you may wish to send us your IP address here.</p> <?php } ?> <table id="submission_form"> <tr> <td><input type="text" name="name" id="name" value="<?= htmlspecialchars($name); ?>" placeholder="Your name"></td> </tr> <tr> <td><input type="email" name="email" id="email" value="<?= htmlspecialchars($email); ?>" placeholder="Your email"></td> </tr> <tr> <th><button type="submit" name="send" value="1" id="send">Send Details</button><input type="hidden" id="server_status" name="status" value=""><input type="hidden" id="ignore" name="ignore" value="<?= $ignore; ?>"></th> </tr> </table> <?php } ?> </form> <?php if (!$admin) { ?> <div id="circle_container"></div> <?php } ?></div> </body> </html>
You will need to edit this file and create a log file, preferably above web root, to handle the IP requests. Storing this in a table is an alternative.
Place this page on a different server to your own. Access the logs by adding adding your random code = 1 to the URL, e.g. ?soMeRanD0mCod3234=1. You can contact me if you’re interested in a free sub domain account.
This is the bash script that white lists the IP if there is a genuine request:
#!/bin/sh ####################################################### # # # SIMPLE SERVER WHITE LISTING # # # # Coded by Noah Hearle, Design Extreme # # http://designextreme.com # # # # Created: 2014/10/29 # # # # Post your comments at: # # https://blog.nahoo.co.uk/server-white-listing/ # # # ####################################################### ip=$1 echo "Firewall Log for $ip: "; grep -m 10 $ip /var/log/lfd.log; echo ''; /scripts/cphulkdwhitelist $ip; /usr/sbin/csf -dr $ip; /usr/sbin/csf -a $ip; /usr/sbin/csf -q;
I have mine running at: ip.designextreme.com and there is a simple page on the test server.
Last updated on
I corrected the JavaScript to cycle through a few different attempts to connect using the client browser. It now works consistently with Firefox, Chrome and Internet Explorer.
Recently I have automated some of the white listing processes. If you show you interest here, I will reply individually to you and if there is suitable interest, I’ll update this post with my improvements.