<?php
/*
* @(#) $Header: /var/cvsroot/phphilter/class.phphilter.php,v 1.7 2009/06/11 12:30:00 cvs Exp $
*/
/*
A simple class to allow access via iptables
Copyright (C) 2009- Giuseppe Lucarelli <hide@address.com>
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation.
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
*/
define('_IPTABLES', '/usr/bin/sudo /usr/sbin/iptables');
define('_CHAIN', 'INPUT');
define('_PROTOCOL', 'tcp');
define('_PORT', '9521');
define('_ACCEPT', 'ACCEPT');
define('_DROP', 'DROP');
define('_DENY', 'REJECT');
define('_HOST_ALLOW', '127.0.0.1'); // '123.456.789.012' or '11.22.333.444/24' or 'ALL'
define('_HOST_DENY', ''); // '123.456.789.012' or '11.22.333.444/24' or 'ALL'
$passwd = array(
'nopasswd' => '',
'someuser' => 'passthru',
);
class PhPhilter
{
/* public */
/* private */
var $hostallow = '';
var $hostdeny = '';
var $filter = '';
var $debug = false;
private function Init() {
$this->hostallow = explode(',',_HOST_ALLOW);
$this->hostdeny = explode(',',_HOST_DENY);
$this->remoteip = $_SERVER['REMOTE_ADDR'];
$this->remotebinip = $this->GetBinaryValue($this->remoteip);
}
private function ToggleAccess($ip,$action) {
$pattern='/^([0-9])+[ \t]+('.$action.')[ \t]+'._PROTOCOL.'[ \t]+[-A-Za-z0-9]+[ \t]+'.
str_replace("/","\\/",$ip).'/im';
if($this->debug) {
echo "[DEBUG] ToggleAccess:\n-----------------\n$pattern\n-----------------\n";
}
if(!preg_match($pattern, $this->filter, $matches, PREG_OFFSET_CAPTURE)) {
return;
}
$cmd = sprintf("%s -D %s %s 2>&1",
_IPTABLES, _CHAIN, $matches[1][0]);
$handle = popen($cmd, 'r');
if($this->debug) {
echo "[DEBUG] ToggleAccess [$cmd]:\n----------------\n".
fread($handle, 2096).
"\n------------------------\n";
}
}
private function CheckAccess() {
global $passwd;
$state = -1;
foreach($this->hostallow as $token) {
if(strlen($token) <= 0)
continue;
if(!strcasecmp($token,'all')) // allow access to all
return true;
$this->ToggleAccess($token,_DENY.'|'._DROP);
$ipchain = $this->GetBinaryValue($token,$mask);
if(!strcmp(substr($ipchain,0,$mask),substr($this->remotebinip,0,$mask))) {
$state=true;
}
}
foreach($this->hostdeny as $token) {
if(strlen($token) <= 0)
continue;
if(!strcasecmp($token,'all')) // deny access to all
return false;
$this->ToggleAccess($token,_ACCEPT);
$ipchain = $this->GetBinaryValue($token,$mask);
if(!strcmp(substr($ipchain,0,$mask),substr($this->remotebinip,0,$mask))) {
$state=false;
}
}
if($state != -1)
return $state;
if (!$_SERVER['PHP_AUTH_USER']) {
header("WWW-Authenticate: Basic realm=\"PhPhilter\"");
header("HTTP/1.0 401 Unauthorized");
exit;
} else {
if (!isset($passwd[$_SERVER['PHP_AUTH_USER']]) ||
$_SERVER['PHP_AUTH_PW'] != $passwd[$_SERVER['PHP_AUTH_USER']]) {
exit;
}
}
return true;
}
private function InitChain() {
$state = false;
foreach($this->hostallow as $token) {
if(strlen($token) <= 0)
continue;
$cmd = sprintf("%s -A %s -p %s -s %s --dport %s -j %s 2>&1",
_IPTABLES, _CHAIN, _PROTOCOL, $token, _PORT, _ACCEPT);
if($this->debug) {
echo "setting: $cmd\n";
}
$handle = popen($cmd, 'r');
if($this->debug) {
echo "[DEBUG] InitChain [$cmd]:\n----------------\n".
fread($handle, 2096).
"\n------------------------\n";
}
pclose($handle);
}
foreach($this->hostdeny as $token) {
if(strlen($token) <= 0)
continue;
$cmd = sprintf("%s -A %s -p %s -s %s --dport %s -j %s 2>&1",
_IPTABLES, _CHAIN, _PROTOCOL, $token, _PORT, _DENY);
if($this->debug) {
echo "setting: $cmd\n";
}
$handle = popen($cmd, 'r');
if($this->debug) {
echo "[DEBUG] InitChain [$cmd]:\n----------------\n".
fread($handle, 2096).
"\n------------------------\n";
}
pclose($handle);
}
$cmd = sprintf("%s -A %s -p %s --dport %s -j %s 2>&1",
_IPTABLES, _CHAIN, _PROTOCOL, _PORT, _DROP);
$handle = popen($cmd, 'r');
if($this->debug) {
echo "[DEBUG] InitChain [$cmd]:\n----------------\n".
fread($handle, 2096).
"\n------------------------\n";
}
pclose($handle);
}
//-----------------------------------------------------------------
// public function ClearFilterList() {
// $handle = popen(_IPTABLES.' -F '._CHAIN.' 2>&1', 'r');
// pclose($handle);
// $this->InitChain();
// }
//-----------------------------------------------------------------
private function GetFilterList() {
$handle = popen(_IPTABLES.' -L '._CHAIN. ' -n --line-numbers 2>&1', 'r');
$this->filter = fread($handle, 2096);
if($this->debug) {
echo "[DEBUG] filter situation:\n----------------\n$this->filter\n---------------\n";
}
if(eregi('(password|root|privilege)', $this->filter)) {
die('oops! it seems there is no access to ['._IPTABLES.'] check your script privileges and retry. ');
}
pclose($handle);
}
public function GetBinaryValue($ip, & $mask = 32) {
$retval = '';
if($pos = strpos($ip,'/')) {
$mask = (Int) substr($ip,$pos+1);
} else {
$mask = 32;
$pos = 32;
}
$parts = explode('.',substr($ip,0,$pos));
$retval=sprintf("%08b%08b%08b%08b",$parts[0],
($parts[1] ? $parts[1] : 0),
($parts[2] ? $parts[2] : 0),
($parts[3] ? $parts[3] : 0));
return $retval;
}
private function CheckFilterList() {
if(!preg_match('/^[0-9]+.*'._PROTOCOL.'/im',$this->filter)) { // empty chain
$this->InitChain();
$this->GetFilterList();
}
//--------------------------------------------------------------------------------------
// if(preg_match('/^[0-9]+[ \t]+'._ACCEPT.'[ \t]+'._PROTOCOL.'[ \t]+[-A-Za-z0-9]+[ \t]+'.
// $this->remoteip.'/im', $this->filter, $matches, PREG_OFFSET_CAPTURE)) {
// if($this->debug) {
// echo "[DEBUG] ip [".$this->remoteip."] access granted yet\n";
// }
// return;
// }
//--------------------------------------------------------------------------------------
// check if remote ip is allowed/denied
$mask = -1;
$filter = explode("\n",$this->filter);
for($i=2; $i < sizeof($filter); $i++) {
$token = preg_split("/\s+/",trim($filter[$i]));
$ipchain = $this->GetBinaryValue($token[4],$mask);
if($mask == 0)
continue;
if($this->debug) {
echo "ip [".$token[4]."]: ".substr($ipchain,0,$mask)." [$mask]\n";
}
if(!strcmp(substr($ipchain,0,$mask),substr($this->remotebinip,0,$mask))) {
return;
}
}
// no match, insert remote IP
$cmd = sprintf("%s -I %s 1 -p %s -s %s --dport %s -j %s 2>&1",
_IPTABLES, _CHAIN, _PROTOCOL, $this->remoteip, _PORT, _ACCEPT);
$handle = popen($cmd, 'r');
$read = fread($handle, 2096);
if($this->debug) {
echo "[DEBUG] apply filter:\n----------------\n$cmd\n---------------\n";
echo "[DEBUG] filter result:\n----------------\n$read\n---------------\n";
}
pclose($handle);
return;
}
function run() {
$this->Init();
$this->GetFilterList();
if($this->CheckAccess() != true) {
die("sorry, access denied for this ip [$this->remoteip]");
}
$this->CheckFilterList();
}
};
?>