Design Extreme White List IP Request

Server White Listing for Clients

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&rsquo;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]) : '&mdash;').'</td>
      <td>'.((isset($a[3]) && $a[3] != NULL) ? htmlspecialchars($a[3]) : '&mdash;').'</td>
      <td>'.((isset($a[4]) && $a[4] != NULL) ? htmlspecialchars($a[4]) : '&mdash;').'</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&rsquo;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

2 thoughts on “Server White Listing for Clients”

  1. 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.

  2. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *