#!/usr/bin/perl
###############################################################################
# Copyright 2006-2012, Way to the Web Limited
# URL: http://www.configserver.com
# Email: sales@waytotheweb.com
###############################################################################
# start main
use POSIX qw(:sys_wait_h sysconf strftime);
open (IN, "</proc/sys/kernel/hostname");
$hostname = <IN>;
chomp $hostname;
close (IN);
$hostshort = (split(/\./,$hostname))[0];
$tz = strftime("%z", localtime);

$ipv4reg = $ipv6reg = qr/(?:(?: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]?)/;
if ($config{IPV6}) {$ipv6reg = qr/((([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}))|:)))(%.+)?/}

if ($FORM{action} ne "" and !&checkip($FORM{ip})) {
	print "<table align='center' width='95%' border='0' cellspacing='0' cellpadding='4' bgcolor='#FFFFFF' style='border:1px solid #990000'>\n";
	print "<tr bgcolor='#FFFFFF'><td>";
	print "[$FORM{ip}] is not a valid IP address\n";
	print "</td></tr></table>\n";
	print "<p align='center'><form action='$script' method='post'><input type='submit' value='Return'></form></p>\n";
} else {
	if ($FORM{action} eq "qallow" and $rprivs{$ENV{REMOTE_USER}}{ALLOW}) {
		print "<table align='center' width='95%' border='0' cellspacing='0' cellpadding='4' bgcolor='#FFFFFF' style='border:1px solid #990000'>\n";
		print "<tr bgcolor='#FFFFFF'><td>";
		print "<p>Allowing $FORM{ip}...</p>\n<p><pre style='font-family: Courier New, Courier; font-size: 12px'>\n";
		my $text = &printcmd("/etc/csf/csf.pl -a $FORM{ip} ALLOW by Reseller $ENV{REMOTE_USER}");
		print "</p>\n<p>...<b>Done</b>.</p>\n";
		print "</td></tr></table>\n";
		print "<p align='center'><form action='$script' method='post'><input type='hidden' name='mobi' value='$FORM{mobi}'><input type='submit' value='Return'></form></p>\n";
		if ($rprivs{$ENV{REMOTE_USER}}{ALERT}) {
			open (IN, "</etc/csf/reselleralert.txt");
			my @alert = <IN>;
			close (IN);
			chomp @alert;

			my @message;
			foreach my $line (@alert) {
				$line =~ s/\[reseller\]/$ENV{REMOTE_USER}/ig;
				$line =~ s/\[action\]/ALLOW/ig;
				$line =~ s/\[ip\]/$FORM{ip}/ig;
				$line =~ s/\[rip\]/$ENV{REMOTE_HOST}/ig;
				$line =~ s/\[text\]/Result of ALLOW:\n\n$text/ig;
				push @message, $line;
			}
			&sendmail(@message);
		}
		&logfile("cPanel Reseller [$ENV{REMOTE_USER}]: ALLOW $FORM{ip}");
	}
	elsif ($FORM{action} eq "qdeny" and $rprivs{$ENV{REMOTE_USER}}{DENY}) {
		print "<table align='center' width='95%' border='0' cellspacing='0' cellpadding='4' bgcolor='#FFFFFF' style='border:1px solid #990000'>\n";
		print "<tr bgcolor='#FFFFFF'><td>";
		print "<p>Blocking $FORM{ip}...</p>\n<p><pre style='font-family: Courier New, Courier; font-size: 12px'>\n";
		my $text = &printcmd("/etc/csf/csf.pl -d $FORM{ip} DENY by Reseller $ENV{REMOTE_USER}");
		print "</p>\n<p>...<b>Done</b>.</p>\n";
		print "</td></tr></table>\n";
		print "<p align='center'><form action='$script' method='post'><input type='hidden' name='mobi' value='$FORM{mobi}'><input type='submit' value='Return'></form></p>\n";
		if ($rprivs{$ENV{REMOTE_USER}}{ALERT}) {
			open (IN, "</etc/csf/reselleralert.txt");
			my @alert = <IN>;
			close (IN);
			chomp @alert;

			my @message;
			foreach my $line (@alert) {
				$line =~ s/\[reseller\]/$ENV{REMOTE_USER}/ig;
				$line =~ s/\[action\]/DENY/ig;
				$line =~ s/\[ip\]/$FORM{ip}/ig;
				$line =~ s/\[rip\]/$ENV{REMOTE_HOST}/ig;
				$line =~ s/\[text\]/Result of DENY:\n\n$text/ig;
				push @message, $line;
			}
			&sendmail(@message);
		}
		&logfile("cPanel Reseller [$ENV{REMOTE_USER}]: DENY $FORM{ip}");
	}
	elsif ($FORM{action} eq "qkill" and $rprivs{$ENV{REMOTE_USER}}{UNBLOCK}) {
		my $text = "";
		if ($rprivs{$ENV{REMOTE_USER}}{ALERT}) {
			my ($childin, $childout);
			my $pid = open3($childin, $childout, $childout, "/etc/csf/csf.pl -g $FORM{ip}");
			while (<$childout>) {$text .= $_}
			waitpid ($pid, 0);
		}
		print "<table align='center' width='95%' border='0' cellspacing='0' cellpadding='4' bgcolor='#FFFFFF' style='border:1px solid #990000'>\n";
		print "<tr bgcolor='#FFFFFF'><td>";
		print "<p>Unblock $FORM{ip}, trying permanent blocks...</p>\n<p><pre style='font-family: Courier New, Courier; font-size: 12px'>\n";
		my $text1 = &printcmd("/etc/csf/csf.pl -dr $FORM{ip}");
		print "</p>\n<p>...<b>Done</b>.</p>\n";
		print "<p>Unblock $FORM{ip}, trying temporary blocks...</p>\n<p><pre style='font-family: Courier New, Courier; font-size: 12px'>\n";
		my $text2 = &printcmd("/etc/csf/csf.pl -tr $FORM{ip}");
		print "</p>\n<p>...<b>Done</b>.</p>\n";
		print "</td></tr></table>\n";
		print "<p align='center'><form action='$script' method='post'><input type='hidden' name='mobi' value='$FORM{mobi}'><input type='submit' value='Return'></form></p>\n";
		if ($rprivs{$ENV{REMOTE_USER}}{ALERT}) {
			open (IN, "</etc/csf/reselleralert.txt");
			my @alert = <IN>;
			close (IN);
			chomp @alert;

			my @message;
			foreach my $line (@alert) {
				$line =~ s/\[reseller\]/$ENV{REMOTE_USER}/ig;
				$line =~ s/\[action\]/UNBLOCK/ig;
				$line =~ s/\[ip\]/$FORM{ip}/ig;
				$line =~ s/\[rip\]/$ENV{REMOTE_HOST}/ig;
				$line =~ s/\[text\]/Result of GREP before UNBLOCK:\n$text\n\nResult of UNBLOCK:\nPermanent:\n$text1\nTemporary:\n$text2\n/ig;
				push @message, $line;
			}
			&sendmail(@message);
		}
		&logfile("cPanel Reseller [$ENV{REMOTE_USER}]: UNBLOCK $FORM{ip}");
	}
	elsif ($FORM{action} eq "grep" and $rprivs{$ENV{REMOTE_USER}}{GREP}) {
		print "<table align='center' width='95%' border='0' cellspacing='0' cellpadding='4' bgcolor='#FFFFFF' style='border:1px solid #990000'>\n";
		print "<tr bgcolor='#FFFFFF'><td>";
		print "<p>Searching for $FORM{ip}...</p>\n<p><pre style='font-family: Courier New, Courier; font-size: 12px'>\n";
		&printcmd("/etc/csf/csf.pl -g $FORM{ip}");
		print "</p>\n<p>...<b>Done</b>.</p>\n";
		print "</td></tr></table>\n";
		print "<p align='center'><form action='$script' method='post'><input type='submit' value='Return'></form></p>\n";
	}
	else {
		print "<table align='center' width='95%' border='0' cellspacing='0' cellpadding='4' bgcolor='#FFFFFF' style='border:1px solid #990000'>\n";
		print "<tr><th align='left' colspan='2'>csf - ConfigServer Firewall</th></tr>";
		if ($rprivs{$ENV{REMOTE_USER}}{ALLOW}) {print "<tr bgcolor='#F4F4EA'><form action='$script' method='post'><td><input type='hidden' name='action' value='qallow'><input type='submit' value='Quick Allow'></td><td width='100%'>Allow IP address <input name='ip' value='' size='18' style='background-color: lightgreen'> through the firewall and add to the allow file (csf.allow)</td></form></tr>\n"}
		if ($rprivs{$ENV{REMOTE_USER}}{DENY}) {print "<tr bgcolor='#F4F4EA'><form action='$script' method='post'><td><input type='hidden' name='action' value='qdeny'><input type='submit' value='Quick Deny'></td><td width='100%'>Block IP address <input name='ip' value='' size='18' style='background-color: pink'> in the firewall and add to the deny file (csf.deny)</td></form></tr>\n"}
		if ($rprivs{$ENV{REMOTE_USER}}{UNBLOCK}) {print "<tr bgcolor='#F4F4EA'><form action='$script' method='post'><td><input type='hidden' name='action' value='qkill'><input type='submit' value='Quick Unblock'></td><td width='100%'>Unblock IP address <input name='ip' value='' size='18'> from the firewall (temp and perm blocks)</td></form></tr>\n"}
		if ($rprivs{$ENV{REMOTE_USER}}{GREP}) {print "<tr bgcolor='#F4F4EA'><form action='$script' method='post'><td><input type='hidden' name='action' value='grep'><input type='submit' value='Search for IP'></td><td width='100%'>Search iptables for IP address <input name='ip' value='' size='18'></td></form></tr>\n"}
		print "</table><br>\n";
	}
}

print "<pre style='font-family: Courier New, Courier; font-size: 12px'>csf: v$myv</pre>";
print "<p>&copy;2006-2012, <a href='http://www.configserver.com' target='_blank'>ConfigServer Services</a> (Way to the Web Limited)</p>\n";
# end main
###############################################################################
# start printcmd
sub printcmd {
	my $cmd = shift;
	my $text;
	my ($childin, $childout);
	my $pid = open3($childin, $childout, $childout, $cmd);
	while (<$childout>) {print $_ ; $text .= $_}
	waitpid ($pid, 0);
	return $text;
}
# end printcmd
###############################################################################
# start checkip
sub checkip {
	my $line = shift;
	my $ret = 0;
	my ($ip,$cidr) = split(/\//,$line);
	if ($cidr ne "") {
		unless ($cidr =~ /^\d+$/) {return 0}
	}
	if ($ip =~ /^$ipv4reg$/) {
		$ret = 4;
		if ($cidr) {
			unless ($cidr >= 1 && $cidr <= 32) {return 0}
		}
		if ($ip eq "127.0.0.1") {return 0}
	}
	if ($config{IPV6} and $ip =~ /^$ipv6reg$/) {
		$ret = 6;
		if ($cidr) {
			unless ($cidr >= 1 && $cidr <= 128) {return 0}
		}
		$ip =~ s/://g;
		$ip =~ s/^0*//g;
		if ($ip == 1) {return 0}
	}
	return $ret;
}
# end checkip
###############################################################################
# start sendmail
sub sendmail {
	my @message = @_;
	my $time = localtime(time);
	&loadconfig;
	my $from = $config{LF_ALERT_FROM};

	if ($from =~ /([\w\.\=\-\_]+\@[\w\.\-\_]+)/) {$from = $1}
	if ($from eq "") {$from = "root"}

	open (MAIL, "|$config{SENDMAIL} -f $from -t");
	my $header = 1;
	foreach my $line (@message) {
		$line =~ s/\r//;
		if ($line eq "") {$header = 0}
		$line =~ s/\[time\]/$time $tz/ig;
		$line =~ s/\[hostname\]/$hostname/ig;
		if ($header) {
			if ($config{LF_ALERT_TO}) {$line =~ s/^To:.*$/To: $config{LF_ALERT_TO}/i}
			if ($config{LF_ALERT_FROM}) {$line =~ s/^From:.*$/From: $config{LF_ALERT_FROM}/i}
		}
		print MAIL $line."\n";
	}
	close (MAIL);
}
# end sendmail
###############################################################################
# loadconfig
sub loadconfig {
	sysopen (IN, "/etc/csf/csf.conf", O_RDWR | O_CREAT) or die "Unable to open file: $!";
	flock (IN, LOCK_SH);
	my @config = <IN>;
	close (IN);
	chomp @config;

	foreach my $line (@config) {
		if ($line =~ /^\#/) {next}
		if ($line !~ /=/) {next}
		my ($name,$value) = split (/=/,$line);
		$name =~ s/\s//g;
		if ($value =~ /\"(.*)\"/) {
			$value = $1;
		} else {
			&error(__LINE__,"Invalid configuration line");
		}
		$config{$name} = $value;
	}
}
# end loadconfig
###############################################################################
# start logfile
sub logfile {
	my $line = shift;
	my @ts = split(/\s+/,scalar localtime);
	if ($ts[2] < 10) {$ts[2] = " ".$ts[2]}
	sysopen (LOGFILE,"/var/log/lfd.log", O_WRONLY | O_APPEND | O_CREAT);
	flock (LOGFILE, LOCK_EX);
	print LOGFILE "$ts[1] $ts[2] $ts[3] $hostshort lfd[$$]: $line\n";
	close (LOGFILE);
}
# end logfile
###############################################################################

1;
