#!/usr/bin/perl
###############################################################################
# Copyright 2006-2012, Way to the Web Limited
# URL: http://www.configserver.com
# Email: sales@waytotheweb.com
###############################################################################
# start main
use strict;
use lib '/etc/csf';
use Crypt::CBC;
use Fcntl qw(:DEFAULT :flock);
use File::Basename;
use IO::Socket::INET;
use IPC::Open3;
use LWP::UserAgent;
use Net::CIDR::Lite;
use Socket;

our (%input, %config, $verbose, $version, %ips, %ifaces, %messengerports,
     $logmodule, $noowner, %sanity, %sanitydefault, $warning, $accept,
	 $ipscidr, $ipv6reg, $ipv4reg, $nonat, $ethdevin, $ethdevout, $ipscidr6);

$version = &version;
$ipscidr6 = Net::CIDR::Lite->new;
$ipscidr6->add("::1/128");
$ipscidr = Net::CIDR::Lite->new;
$ipscidr->add("127.0.0.0/8");

&process_input;
&load_config;

if ((-e "/etc/csf/csf.disable") and ($input{command} ne "--enable") and ($input{command} ne "-e")) {
	print "csf and lfd have been disabled, use 'csf -e' to enable\n";
	exit;
}

unless (-e $config{IPTABLES}) {&error(__LINE__,"$config{IPTABLES} (iptables binary location) does not exist!")}
if ($config{IPV6} and !(-e $config{IP6TABLES})) {&error(__LINE__,"$config{IP6TABLES} (ip6tables binary location) does not exist!")}

if ((-e "/etc/csf/csf.error") and ($input{command} ne "--startf") and ($input{command} ne "-sf") and ($input{command} ne "-q") and ($input{command} ne "--startq") and ($input{command} ne "--start") and ($input{command} ne "-s") and ($input{command} ne "--restart") and ($input{command} ne "-r") and ($input{command} ne "--enable") and ($input{command} ne "-e")) {
	print "You have an unresolved error when starting csf. You need to restart csf successfully to remove this warning\n";
	exit;
}

if (($input{command} eq "--status") or ($input{command} eq "-l")) {&dostatus}
elsif (($input{command} eq "--status6") or ($input{command} eq "-l6")) {&dostatus6}
elsif (($input{command} eq "--version") or ($input{command} eq "-v")) {&doversion}
elsif (($input{command} eq "--stop") or ($input{command} eq "-f")) {&csflock("lock");&dostop(0);&csflock("unlock")}
elsif (($input{command} eq "--startf") or ($input{command} eq "-sf")) {&csflock("lock");&dostop(1);&dostart;&csflock("unlock")}
elsif (($input{command} eq "--start") or ($input{command} eq "-s") or ($input{command} eq "--restart") or ($input{command} eq "-r")) {if ($config{LF_QUICKSTART}) {&quickstart} else {&csflock("lock");&dostop(1);&dostart;&csflock("unlock")}}
elsif (($input{command} eq "--startq") or ($input{command} eq "-q")) {&quickstart}
elsif (($input{command} eq "--add") or ($input{command} eq "-a")) {&doadd}
elsif (($input{command} eq "--deny") or ($input{command} eq "-d")) {&dodeny}
elsif (($input{command} eq "--denyrm") or ($input{command} eq "-dr")) {&dokill}
elsif (($input{command} eq "--denyf") or ($input{command} eq "-df")) {&dokillall}
elsif (($input{command} eq "--addrm") or ($input{command} eq "-ar")) {&doakill}
elsif (($input{command} eq "--update") or ($input{command} eq "-u") or ($input{command} eq "-uf")) {&doupdate}
elsif (($input{command} eq "--disable") or ($input{command} eq "-x")) {&csflock("lock");&dodisable;&csflock("unlock")}
elsif (($input{command} eq "--enable") or ($input{command} eq "-e")) {&csflock("lock");&doenable;&csflock("unlock")}
elsif (($input{command} eq "--check") or ($input{command} eq "-c")) {&docheck}
elsif (($input{command} eq "--grep") or ($input{command} eq "-g")) {&dogrep}
elsif (($input{command} eq "--temp") or ($input{command} eq "-t")) {&dotempban}
elsif (($input{command} eq "--temprm") or ($input{command} eq "-tr")) {&dotemprm}
elsif (($input{command} eq "--tempdeny") or ($input{command} eq "-td")) {&dotempdeny}
elsif (($input{command} eq "--tempallow") or ($input{command} eq "-ta")) {&dotempallow}
elsif (($input{command} eq "--tempf") or ($input{command} eq "-tf")) {&dotempf}
elsif (($input{command} eq "--mail") or ($input{command} eq "-m")) {&domail}
elsif (($input{command} eq "--keygen") or ($input{command} eq "-ck")) {&keygen}
elsif (($input{command} eq "--cdeny") or ($input{command} eq "-cd")) {&doclusterdeny}
elsif (($input{command} eq "--callow") or ($input{command} eq "-ca")) {&doclusterallow}
elsif (($input{command} eq "--crm") or ($input{command} eq "-cr")) {&doclusterrm}
elsif (($input{command} eq "--cping") or ($input{command} eq "-cp")) {&clustersend("PING")}
elsif (($input{command} eq "--cconfig") or ($input{command} eq "-cc")) {&docconfig}
elsif (($input{command} eq "--cfile") or ($input{command} eq "-cf")) {&docfile}
elsif (($input{command} eq "--crestart") or ($input{command} eq "-crs")) {&docrestart}
elsif (($input{command} eq "--watch") or ($input{command} eq "-w")) {&dowatch}
elsif (($input{command} eq "--logrun") or ($input{command} eq "-lr")) {&dologrun}
else {&dohelp}

if ($config{TESTING}) {print "*WARNING* TESTING mode is enabled - do not forget to disable it in the configuration\n"}
if ($config{AUTO_UPDATES}) {&autoupdates} elsif (-e "/etc/cron.d/csf_update") {unlink "/etc/cron.d/csf_update"}

if (($input{command} eq "--start") or ($input{command} eq "-s") or ($input{command} eq "--restart") or
	($input{command} eq "-r")) {
	if ($warning) {print $warning}
	foreach my $key (keys %config) {
		my ($insane,$range,$default) = &sanity($key,$config{$key});
		if ($insane) {print "*WARNING* $key sanity check. $key = $config{$key}. Recommended range: $range (Default: $default)\n"}
	}
}

exit;

# end main
###############################################################################
# start csflock
sub csflock {
	my $lock = shift;
	if ($lock eq "lock") {
		sysopen (CSFLOCKFILE, "/etc/csf/csf.lock", O_RDWR | O_CREAT) or &cleanup("Error: Unable to open csf lock file");
		flock (CSFLOCKFILE, LOCK_EX | LOCK_NB) or die "Error: csf is being restarted, try again in a moment";
	} else {
		close (CSFLOCKFILE);
	}
}
# end csflock
###############################################################################
# start load_config
sub load_config {
	my %configsetting;
	open (IN, "</etc/csf/csf.conf") or &error(__LINE__,"Could not open /etc/csf/csf.conf: $!");
	flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/csf.conf:$!");
	my @config = <IN>;
	close (IN) or &error(__LINE__,"Could not close /etc/csf/csf.conf: $!");
	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 [$line]");
		}
		if ($configsetting{$name}) {&error(__LINE__,"Setting $name is repeated in /etc/csf/csf.conf - you must remove the duplicates and then restart csf and lfd.")}
		$config{$name} = $value;
		$configsetting{$name} = 1;
	}

	$verbose = "";
	if ($config{VERBOSE} or $config{DEBUG} >= 1) {$verbose = "-v"}

	$logmodule = "LOG --log-prefix";
	if ($config{ULOG}) {$logmodule = "ULOG --ulog-prefix"}

	if (-e "/var/cpanel/smtpgidonlytweak" and !$config{GENERIC}) {
		$warning .= "*WARNING* The option \"WHM > Security Center > SMTP Tweak\" is incompatible with this firewall. The option must be disabled in WHM and the SMTP_BLOCK alternative in csf used instead\n";
	}
	if (-e "/proc/vz/veinfo") {$config{VPS} = 1}
	if ($config{DROP_IP_LOGGING} and $config{PS_INTERVAL}) {
		$warning .= "Cannot use PS_INTERVAL with DROP_IP_LOGGING enabled. DROP_IP_LOGGING disabled\n";
		$config{DROP_IP_LOGGING} = 0;
	}

	$accept = "ACCEPT";
	if ($config{WATCH_MODE}) {
		$accept = "LOGACCEPT";
		$config{DROP_NOLOG} = "";
		$config{DROP_LOGGING} = "1";
		$config{DROP_IP_LOGGING} = "1";
		$config{DROP_PF_LOGGING} = "1";
		$config{PS_INTERVAL} = "0";
		$config{DROP_ONLYRES} = "0";
	}

	if ($config{MESSENGER}) {
		my $pcnt = 0;
		foreach my $port (split(/\,/,$config{MESSENGER_HTML_IN})) {
			$messengerports{$port} = 1;
			$pcnt++;
		}
		if ($pcnt > 15) {
			$warning .= "*WARNING* MESSENGER_HTML_IN contains more than 15 ports - disabling Messenger Service\n";
			$config{MESSENGER} = 0;
		} else {
			$pcnt = 0;
			foreach my $port (split(/\,/,$config{MESSENGER_TEXT_IN})) {
				$messengerports{$port} = 1;
				$pcnt++;
			}
			if ($pcnt > 15) {
				$warning .= "*WARNING* MESSENGER_TEXT_IN contains more than 15 ports - disabling Messenger Service\n";
				$config{MESSENGER} = 0;
			}
		}
	}
	
	unless ($config{GENERIC}) {
		$config{DNSONLY} = -e '/var/cpanel/dnsonly' ? 1 : undef;
	}

	if ($config{IPV6} and $config{IPV6_SPI}) {
		open (FH, "<", "/proc/sys/kernel/osrelease");
		my @data = <FH>;
		close (FH);
		chomp @data;
		if ($data[0] =~ /^(\d+)\.(\d+)\.(\d+)/) {
			my $maj = $1;
			my $mid = $2;
			my $min = $3;
			if (($maj > 2) or (($maj > 1) and ($mid > 6)) or (($maj > 1) and ($mid > 5) and ($min > 19))) {
			} else {
				print "*WARNING* Kernel $data[0] may not support an ip6tables SPI firewall. You should set IPV6_SPI to \"0\" in /etc/csf/csf.conf\n\n";
			}
		}
	}

	if ($config{VPS}) {
		$nonat = 0;
		my ($childin, $childout);
		my $cmdpid = open3($childin, $childout, $childout, "$config{IPTABLES} -t nat -L POSTROUTING -nv");
		my @ipdata = <$childout>;
		waitpid ($cmdpid, 0);
		chomp @ipdata;
		unless ($ipdata[0] =~ /^Chain POSTROUTING/) {$nonat = 1}
	}

	$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}))|:)))(%.+)?/;}
}
# end load_config
###############################################################################
# start process_input
sub process_input {
	$input{command} = lc $ARGV[0];
	for (my $x = 1;$x < @ARGV ;$x++) {
		$input{argument} .= $ARGV[$x] . " ";
	}
	$input{argument} =~ s/\s$//;;
}
# end process_input
###############################################################################
# start dostatus
sub dostatus {
	&syscommand(__LINE__,"$config{IPTABLES} -v -L -n --line-numbers");
	unless ($nonat) {
		print "\n";
		&syscommand(__LINE__,"$config{IPTABLES} -v -t nat -L -n --line-numbers");
	}
}
# end dostatus
###############################################################################
# start dostatus6
sub dostatus6 {
	if ($config{IPV6}) {
		&syscommand(__LINE__,"$config{IP6TABLES} -v -L -n --line-numbers");
	} else {
		print "csf: IPV6 firewall not enabled\n";
	}
}
# end dostatus
###############################################################################
# start doversion
sub doversion {
	my $generic = " (cPanel)";
	if ($config{GENERIC}) {$generic = " (generic)"}
	if ($config{DIRECTADMIN}) {$generic = " (DirectAdmin)"}
	print "csf: v$version$generic\n";
}
# end doversion
###############################################################################
# start keygen
sub keygen {
	print "Hold on\n";
}
# end keygen
###############################################################################
# start doclusterdeny
sub doclusterdeny {
	my ($ip,$comment) = split (/\s/,$input{argument},2);

	if (!&checkip($ip)) {
		print "[$ip] is not a valid IP/CIDR\n";
		return;
	}

	&clustersend("D $ip");
}
# end doclusterdeny
###############################################################################
# start doclusterrm
sub doclusterrm {
	my ($ip,$comment) = split (/\s/,$input{argument},2);

	if (!&checkip($ip)) {
		print "[$ip] is not a valid IP/CIDR\n";
		return;
	}

	&clustersend("R $ip");
}
# end doclusterrm
###############################################################################
# start doclusterallow
sub doclusterallow {
	my ($ip,$comment) = split (/\s/,$input{argument},2);

	if (!&checkip($ip)) {
		print "[$ip] is not a valid IP/CIDR\n";
		return;
	}

	&clustersend("A $ip");
}
# end doclusterallow
###############################################################################
# start docconfig
sub docconfig {
	my ($name,$value) = split (/\s/,$input{argument},2);
	unless ($config{CLUSTER_CONFIG}) {print "No configuration setting requests allowed\n"; return}
	unless ($name) {print "No configuration setting entered\n"; return}

	&clustersend("C $name $value");
}
###############################################################################
# start docfile
sub docfile {
	my $name = $input{argument};
	unless ($config{CLUSTER_CONFIG}) {print "No configuration setting requests allowed\n"; return}
	unless ($name) {print "No file entered\n"; return}

	if (-e $name) {
		open (FH, "<", $name);
		my @data = <FH>;
		close @data;

		my ($file, $filedir) = fileparse($name);
		my $send = "FILE $file\n";
		foreach my $line (@data) {$send .= $line}

		&clustersend($send);
	} else {
		print "csf: Error [$name] does not exist\n";
	}
}
# end docfile
###############################################################################
# start docrestart
sub docrestart {
	&clustersend("RESTART");
}
# end docrestart
###############################################################################
# start clustersend
sub clustersend {
	my $text = shift;

	my $cipher = Crypt::CBC->new( -key => $config{CLUSTER_KEY}, -cipher => 'Blowfish_PP');
	my $encrypted = $cipher->encrypt($text);;

	foreach my $cip (split(/\,/,$config{CLUSTER_SENDTO})) {
		my $localaddr = "0.0.0.0";
		if ($config{CLUSTER_LOCALADDR}) {$localaddr = $config{CLUSTER_LOCALADDR}}
		my $sock;
		eval {$sock = IO::Socket::INET->new(PeerAddr => $cip, PeerPort => $config{CLUSTER_PORT}, LocalAddr => $localaddr, Timeout => '10');};
		unless (defined $sock) {
			print "Failed to connect to $cip\n";
		} else {
			my $status = send($sock,$encrypted,0);
			unless ($status) {
				print "Failed for $cip: $status\n";
			} else {
				print "Sent to $cip\n";
			}
			shutdown($sock,2);
		}
	}
}
# end clustersend
###############################################################################
# quickstart
sub quickstart {
	open (FH, ">", "/etc/csf/csf.restart") or die "Failed to create csf.restart - $!";
	close (FH);
	print "lfd will restart csf within the next $config{LF_PARSE} seconds\n";
}
# quickstart
###############################################################################
# start dostop
sub dostop {
	my $restart = shift;
	&syscommand(__LINE__,"$config{IPTABLES} $verbose --policy INPUT ACCEPT");
	&syscommand(__LINE__,"$config{IPTABLES} $verbose --policy OUTPUT ACCEPT");
	&syscommand(__LINE__,"$config{IPTABLES} $verbose --policy FORWARD ACCEPT");
	&syscommand(__LINE__,"$config{IPTABLES} $verbose --flush");
	unless ($nonat) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -t nat --flush")}
	&syscommand(__LINE__,"$config{IPTABLES} $verbose --delete-chain");
	unless ($config{GENERIC} or $config{DNSONLY} or $restart) {
		if ($config{LF_CPANEL_BANDMIN}) {
			if ($verbose) {print "Restarting bandmin acctboth chains for cPanel\n"}
			&syscommand(__LINE__,"/usr/local/bandmin/bandminstart");
		}
	}

	if ($config{IPV6}) {
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose --policy INPUT ACCEPT");
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose --policy OUTPUT ACCEPT");
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose --policy FORWARD ACCEPT");
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose --flush");
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose --delete-chain");
	}
	if ($config{TESTING}) {&crontab("remove")}
}
# end dostop
###############################################################################
# start dostart
sub dostart {
	if ($config{TESTING}) {&crontab("add")} else {&crontab("remove")}
	if (-e "/etc/csf/csf.error") {unlink ("/etc/csf/csf.error")}

	&getethdev;

	if (-e $config{MODPROBE}) {
		my @modules = ("ip_tables","ipt_state","ipt_multiport","iptable_filter","ipt_limit","ipt_LOG","ipt_REJECT","ipt_conntrack","ip_conntrack","ip_conntrack_ftp","iptable_mangle","ipt_REDIRECT","iptable_nat");

		unless (&loadmodule("xt_state")) {
			@modules = ("ip_tables","xt_state","xt_multiport","iptable_filter","xt_limit","ipt_LOG","ipt_REJECT","ip_conntrack_ftp","iptable_mangle","xt_conntrack","ipt_REDIRECT","iptable_nat");
		}

		if ($config{SMTP_BLOCK}) {
			push @modules,"ipt_owner";
			push @modules,"xt_owner";
		}
		if ($config{PORTFLOOD} or $config{PORTKNOCKING}) {
			push @modules,"ipt_recent ip_list_tot=1000 ip_list_hash_size=0";
		}
		if ($config{CONNLIMIT}) {
			push @modules,"xt_connlimit";
		}
		if ($config{ULOG}) {
			push @modules,"ipt_ULOG";
		}

		foreach my $module (@modules) {&loadmodule($module)}
	}
	$noowner = 0;
	if ($config{VPS} and $config{SMTP_BLOCK}) {
		my ($childin, $childout);
		my $cmdpid = open3($childin, $childout, $childout, "$config{IPTABLES} -I OUTPUT -p tcp --dport 9999 -m owner --uid-owner 0 -j $accept");
		my @ipdata = <$childout>;
		waitpid ($cmdpid, 0);
		chomp @ipdata;
		if ($ipdata[0] =~ /^iptables: /) {
			$warning .= "*WARNING* Cannot use SMTP_BLOCK on this VPS as the Monolithic kernel does not support the iptables module ipt_owner/xt_owner - SMTP_BLOCK disabled\n";
			$config{SMTP_BLOCK} = 0;
			$noowner = 1;
		} else {
			&syscommand(__LINE__,"$config{IPTABLES} -D OUTPUT -p tcp --dport 9999 -m owner --uid-owner 0 -j $accept",0);
		}
	}

	if (-e "/etc/csf/csfpre.sh") {
		print "Running /etc/csf/csfpre.sh\n";
		&syscommand(__LINE__,"/bin/sh /etc/csf/csfpre.sh");
	}

	if ($config{WATCH_MODE}) {
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -N LOGACCEPT");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOGACCEPT -j ACCEPT");
		if ($config{IPV6}) {
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -N LOGACCEPT");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOGACCEPT -j ACCEPT");
		}
	}

	if ($config{LF_DSHIELD}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N DSHIELD")}
	if ($config{LF_SPAMHAUS}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N SPAMHAUS")}
	if ($config{LF_TOR}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N TOR")}
	if ($config{LF_BOGON}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N BOGON")}
	if ($config{CC_ALLOW_FILTER}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N CC_ALLOWF")}
	if ($config{CC_ALLOW}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N CC_ALLOW")}
	if ($config{CC_DENY}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N CC_DENY")}
	if (($config{LF_TOR} or $config{LF_SPAMHAUS} or $config{LF_DSHIELD} or $config{LF_BOGON}) and ($config{DROP_IP_LOGGING})) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N BLOCKDROP")}
	if (($config{CC_DENY} or $config{CC_ALLOW_FILTER}) and $config{DROP_IP_LOGGING}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N CCDROP")}
	if ($config{GLOBAL_ALLOW}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N GALLOWIN")}
	if ($config{GLOBAL_ALLOW}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N GALLOWOUT")}
	if ($config{GLOBAL_DENY}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N GDENYIN")}
	if ($config{GLOBAL_DENY}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N GDENYOUT")}
	if ($config{DYNDNS}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N ALLOWDYNIN")}
	if ($config{DYNDNS}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N ALLOWDYNOUT")}
	if ($config{GLOBAL_DYNDNS}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N GDYNIN")}
	if ($config{GLOBAL_DYNDNS}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N GDYNOUT")}
	if ($config{SYNFLOOD}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N SYNFLOOD")}
	if ($config{PORTFLOOD}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N PORTFLOOD")}
	if ($config{CONNLIMIT}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -N CONNLIMIT")}
	if ($config{IPV6}) {
		if ($config{GLOBAL_ALLOW}) {&syscommand(__LINE__,"$config{IP6TABLES} $verbose -N GALLOWIN")}
		if ($config{GLOBAL_ALLOW}) {&syscommand(__LINE__,"$config{IP6TABLES} $verbose -N GALLOWOUT")}
		if ($config{GLOBAL_DENY}) {&syscommand(__LINE__,"$config{IP6TABLES} $verbose -N GDENYIN")}
		if ($config{GLOBAL_DENY}) {&syscommand(__LINE__,"$config{IP6TABLES} $verbose -N GDENYOUT")}
	}

	&syscommand(__LINE__,"$config{IPTABLES} $verbose -N LOGDROPIN");
	&syscommand(__LINE__,"$config{IPTABLES} $verbose -N LOGDROPOUT");
	&syscommand(__LINE__,"$config{IPTABLES} $verbose -N LOCALINPUT");
	&syscommand(__LINE__,"$config{IPTABLES} $verbose -N LOCALOUTPUT");
	if ($config{IPV6}) {
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose -N LOGDROPIN");
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose -N LOGDROPOUT");
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose -N LOCALINPUT");
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose -N LOCALOUTPUT");
	}

	if ($config{DROP_LOGGING}) {
		my $dports;
		if ($config{DROP_ONLYRES}) {$dports = "--dport 0:1023"}
		$config{DROP_NOLOG} =~ s/\s//g;
		if ($config{DROP_NOLOG} ne "") {
			foreach my $port (split(/\,/,$config{DROP_NOLOG})) {
				if ($port eq "") {next}
				if ($port !~ /^[\d:]*$/) {&error(__LINE__,"Invalid DROP_NOLOG port [$port]")}
				&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOGDROPIN -p tcp --dport $port -j $config{DROP}");
				&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOGDROPIN -p udp --dport $port -j $config{DROP}");
				if ($config{IPV6}) {
					&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOGDROPIN -p tcp --dport $port -j $config{DROP}");
					&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOGDROPIN -p udp --dport $port -j $config{DROP}");
				}
			}
		}
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOGDROPIN -p tcp $dports -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *TCP_IN Blocked* '");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOGDROPOUT -p tcp $dports -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *TCP_OUT Blocked* '");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOGDROPIN -p udp $dports -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *UDP_IN Blocked* '");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOGDROPOUT -p udp $dports -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *UDP_OUT Blocked* '");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOGDROPIN -p icmp -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *ICMP_IN Blocked* '");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOGDROPOUT -p icmp -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *ICMP_OUT Blocked* '");
		if ($config{IPV6}) {
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOGDROPIN -p tcp $dports -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *TCP6IN Blocked* '");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOGDROPOUT -p tcp $dports -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *TCP6OUT Blocked* '");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOGDROPIN -p udp $dports -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *UDP6IN Blocked* '");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOGDROPOUT -p udp $dports -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *UDP6OUT Blocked* '");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOGDROPIN -p icmpv6 -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *ICMP6IN Blocked* '");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOGDROPOUT -p icmpv6 -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *ICMP6OUT Blocked* '");
		}
		if (($config{LF_TOR} or $config{LF_SPAMHAUS} or $config{LF_DSHIELD} or $config{LF_BOGON}) and ($config{DROP_IP_LOGGING})) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -A BLOCKDROP -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *BLOCK_LIST* '");}
		if (($config{CC_DENY} or $config{CC_ALLOW_FILTER}) and $config{DROP_IP_LOGGING}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -A CCDROP -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *CC_DENY* '");}
		if ($config{PORTFLOOD}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -A PORTFLOOD -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *Port Flood* '");}
	}
	if ($config{CONNLIMIT} and $config{CONNLIMIT_LOGGING}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -A CONNLIMIT -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *ConnLimit* '");}
	if (($config{LF_TOR} or $config{LF_SPAMHAUS} or $config{LF_DSHIELD} or $config{LF_BOGON}) and ($config{DROP_IP_LOGGING})) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -A BLOCKDROP -j $config{DROP}");}
	if (($config{CC_DENY} or $config{CC_ALLOW_FILTER}) and $config{DROP_IP_LOGGING}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -A CCDROP -j $config{DROP}");}
	&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOGDROPIN -j $config{DROP}");
	&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOGDROPOUT -j $config{DROP}");
	if ($config{IPV6}) {
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOGDROPIN -j $config{DROP}");
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOGDROPOUT -j $config{DROP}");
	}

	&dopacketfilters;
	&doportfilters;

	my $skipin = 1;
	my $skipout = 1;

	if ($config{SMTP_BLOCK}) {
		my $dropout = $config{DROP};
		if ($config{DROP_IP_LOGGING}) {$dropout = "LOGDROPOUT"}
		$config{SMTP_PORTS} =~ s/\s//g;
		foreach my $port (split(/\,/,$config{SMTP_PORTS})) {
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT -p tcp --dport $port -j $dropout",1);
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT -p tcp --dport $port -m owner --uid-owner 0 -j $accept",1);
			if ($config{IPV6} and $config{TCP6_OUT} =~ /\b25\b/) {
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I OUTPUT -p tcp --dport $port -j $dropout",1);
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I OUTPUT -p tcp --dport $port -m owner --uid-owner 0 -j $accept",1);
			}
			foreach my $item (split(/\,/,$config{SMTP_ALLOWUSER})) {
				$item =~ s/\s*//g;
				my $uid = (getpwnam($item))[2];
				if ($uid) {
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT -p tcp --dport $port -m owner --uid-owner $uid -j $accept",1);
					if ($config{IPV6} and $config{TCP6_OUT} =~ /\b25\b/) {
						&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I OUTPUT -p tcp --dport $port -m owner --uid-owner $uid -j $accept",1);
					}
				}
			}
			foreach my $item (split(/\,/,$config{SMTP_ALLOWGROUP})) {
				$item =~ s/\s*//g;
				my $gid = (getgrnam($item))[2];
				if ($gid) {
					syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT -p tcp --dport $port -m owner --gid-owner $gid -j $accept",1);
					if ($config{IPV6} and $config{TCP6_OUT} =~ /\b25\b/) {
						syscommand(__LINE__,"$config{IP6TABLES} $verbose -I OUTPUT -p tcp --dport $port -m owner --gid-owner $gid -j $accept",1);
					}
				}
			}
			if ($config{SMTP_ALLOWLOCAL}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT -o lo -p tcp --dport $port -j $accept",1)}
		}
	}

	&syscommand(__LINE__,"$config{IPTABLES} $verbose -I INPUT  -i lo -j $accept");
	&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT -o lo -j $accept");
	&syscommand(__LINE__,"$config{IPTABLES} $verbose -A OUTPUT $ethdevout -j LOGDROPOUT");
	&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -j LOGDROPIN");
	if ($config{IPV6}) {
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I INPUT  -i lo -j $accept");
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I OUTPUT -o lo -j $accept");
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A OUTPUT $ethdevout -j LOGDROPOUT");
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INPUT $ethdevin -j LOGDROPIN");
	}

	unless ($config{DNS_STRICT}) {
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT $ethdevout -p udp --sport 53 -j $accept");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT $ethdevout -p tcp --sport 53 -j $accept");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT $ethdevout -p udp --dport 53 -j $accept");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT $ethdevout -p tcp --dport 53 -j $accept");
		if ($config{IPV6}) {
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I OUTPUT $ethdevout -p udp --sport 53 -j $accept");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I OUTPUT $ethdevout -p tcp --sport 53 -j $accept");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I OUTPUT $ethdevout -p udp --dport 53 -j $accept");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I OUTPUT $ethdevout -p tcp --dport 53 -j $accept");
		}
	}

	unless ($config{DNS_STRICT_NS}) {
		open (IN, "</etc/resolv.conf") or &error(__LINE__,"Could not open /etc/resolv.conf: $!");
		flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/resolv.conf: $!");
		my @resolv = <IN>;
		close (IN);
		chomp @resolv;
		foreach my $line (@resolv) {
			if ($line =~ /^nameserver\s+(\d+\.\d+\.\d+\.\d+)/) {
				my $ip = $1;
				unless ($ips{$ip} or $ipscidr->find($ip)) {
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -I INPUT $ethdevin -s $ip -p udp --sport 53 -j $accept");
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -I INPUT $ethdevin -s $ip -p tcp --sport 53 -j $accept");
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -I INPUT $ethdevin -s $ip -p udp --dport 53 -j $accept");
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -I INPUT $ethdevin -s $ip -p tcp --dport 53 -j $accept");
					$skipin += 4;
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT $ethdevout -d $ip -p udp --sport 53 -j $accept");
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT $ethdevout -d $ip -p tcp --sport 53 -j $accept");
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT $ethdevout -d $ip -p udp --dport 53 -j $accept");
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT $ethdevout -d $ip -p tcp --dport 53 -j $accept");
					$skipout += 4;
				}
			}
		}
	}

	unless ($config{GENERIC} or $config{DNSONLY}) {
		if ($config{LF_CPANEL_BANDMIN}) {
			if ($verbose) {print "Restarting bandmin acctboth chains for cPanel\n"}
			$skipin ++;
			$skipout ++;
			&syscommand(__LINE__,"/usr/local/bandmin/bandminstart");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -D INPUT -j acctboth");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -D OUTPUT -j acctboth");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -I INPUT -j acctboth");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT -j acctboth");
		}
	}
	if ($config{MESSENGER}) {
		$skipin += 2;
		$skipout += 2;
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I INPUT $ethdevin -p tcp --dport $config{MESSENGER_HTML} -m limit --limit $config{MESSENGER_RATE} --limit-burst $config{MESSENGER_BURST} -j $accept");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I INPUT $ethdevin -p tcp --dport $config{MESSENGER_TEXT} -m limit --limit $config{MESSENGER_RATE} --limit-burst $config{MESSENGER_BURST} -j $accept");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT $ethdevout -p tcp --sport $config{MESSENGER_HTML} -m limit --limit $config{MESSENGER_RATE} --limit-burst $config{MESSENGER_BURST} -j $accept");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT $ethdevout -p tcp --sport $config{MESSENGER_TEXT} -m limit --limit $config{MESSENGER_RATE} --limit-burst $config{MESSENGER_BURST} -j $accept");
	}

	&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT $skipout $ethdevout -j LOCALOUTPUT");
	&syscommand(__LINE__,"$config{IPTABLES} $verbose -I INPUT $skipin $ethdevin -j LOCALINPUT");
	if ($config{IPV6}) {
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I OUTPUT $ethdevout -j LOCALOUTPUT");
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I INPUT $ethdevin -j LOCALINPUT");
	}

	$config{ETH_DEVICE_SKIP} =~ s/\s//g;
	if ($config{ETH_DEVICE_SKIP} ne "") {
		foreach my $device (split(/\,/,$config{ETH_DEVICE_SKIP})) {
			if ($ifaces{$device}) {
				&syscommand(__LINE__,"$config{IPTABLES} $verbose -I INPUT  -i $device -j $accept");
				&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT -o $device -j $accept");
				if ($config{IPV6}) {
					&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I INPUT  -i $device -j $accept");
					&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I OUTPUT -o $device -j $accept");
				}
			} else {
				$warning .= "*WARNING* ETH_DEVICE_SKIP device [$device] not listed in ifconfig\n";
			}
		}
	}

	&syscommand(__LINE__,"$config{IPTABLES} $verbose --policy INPUT   DROP",1);
	&syscommand(__LINE__,"$config{IPTABLES} $verbose --policy OUTPUT  DROP",1);
	&syscommand(__LINE__,"$config{IPTABLES} $verbose --policy FORWARD DROP",1);
	if ($config{IPV6}) {
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose --policy INPUT   DROP",1);
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose --policy OUTPUT  DROP",1);
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose --policy FORWARD DROP",1);
	}

	if (-e "/etc/csf/csfpost.sh") {
		print "Running /etc/csf/csfpost.sh\n";
		&syscommand(__LINE__,"/bin/sh /etc/csf/csfpost.sh");
	}

	if (-e "/proc/vz/veinfo") {
		my $status = 0;
		if (-e "/etc/pure-ftpd.conf") {
			open (IN, "</etc/pure-ftpd.conf");
			my @conf = <IN>;
			close (IN);
			chomp @conf;
			if (my @ls = grep {$_ =~ /^PassivePortRange\s+(\d+)\s+(\d+)/} @conf) {
				if ($config{TCP_IN} !~ /\b$1:$2\b/) {$status = 1}
			} else {$status = 1}
			if ($status) {$warning .= "*WARNING* Since the Virtuozzo VPS iptables ip_conntrack_ftp kernel module is currently broken you have to open a PASV port hole in iptables for incoming FTP connections to work correctly. See the csf readme.txt under 'A note about FTP Connection Issues' on how to do this if you have not already done so.\n"}
		}
		elsif (-e "/etc/proftpd.conf") {
			open (IN, "</etc/proftpd.conf");
			my @conf = <IN>;
			close (IN);
			chomp @conf;
			if (my @ls = grep {$_ =~ /^PassivePorts\s+(\d+)\s+(\d+)/} @conf) {
				if ($config{TCP_IN} !~ /\b$1:$2\b/) {$status = 1}
			} else {$status = 1}
			if ($status) {$warning .= "*WARNING* Since the Virtuozzo VPS iptables ip_conntrack_ftp kernel module is currently broken you have to open a PASV port hole in iptables for incoming FTP connections to work correctly. See the csf readme.txt under 'A note about FTP Connection Issues' on how to do this if you have not already done so.\n"}
		}
	}
}
# end dostart
###############################################################################
# start doadd
sub doadd {
	my ($ip,$comment) = split (/\s/,$input{argument},2);

	&getethdev;

	if ($ips{$ip} or $ipscidr->find($ip) or $ipscidr6->find($ip)) {
		print "add failed: $ip is one of this servers addresses!\n";
		return;
	}

	if (!&checkip($ip) and !(($ip =~ /:|\|/) and ($ip =~ /=/))) {
		print "[$ip] is not a valid IP/CIDR\n";
		return;
	}

	open (IN, "</etc/csf/csf.deny") or &error(__LINE__,"Could not open /etc/csf/csf.deny: $!");
	flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/csf.deny: $!");
	my @deny = <IN>;
	close (IN) or &error(__LINE__,"Could not close /etc/csf/csf.deny: $!");
	chomp @deny;

	if (&checkip($ip) and grep {$_ =~ /^$ip\b/i} @deny) {
		sysopen (DENY, "/etc/csf/csf.deny", O_RDWR | O_CREAT) or &error(__LINE__,"Could not open /etc/csf/csf.deny: $!");
		flock (DENY, LOCK_EX) or &error(__LINE__,"Could not lock /etc/csf/csf.deny: $!");
		my @deny = <DENY>;
		chomp @deny;
		seek (DENY, 0, 0);
		truncate (DENY, 0);
		foreach my $line (@deny) {
			if ($line =~ /^$ip\b/i) {next}
			print DENY $line."\n";
		}
		close (DENY) or &error(__LINE__,"Could not close /etc/csf/csf.deny: $!");
		my $dropin = $config{DROP};
		my $dropout = $config{DROP};
		if ($config{DROP_IP_LOGGING}) {$dropin = "LOGDROPIN"}
		if ($config{DROP_IP_LOGGING}) {$dropout = "LOGDROPOUT"}
		print "Removing $ip from csf.deny and iptables DROP...\n";
		&linefilter($ip, "deny", "", 1);
	}

	sysopen (ALLOW, "/etc/csf/csf.allow", O_RDWR | O_CREAT) or &error(__LINE__,"Could not open /etc/csf/csf.allow: $!");
	flock (ALLOW, LOCK_EX) or &error(__LINE__,"Could not lock /etc/csf/csf.allow: $!");
	my @allow = <ALLOW>;
	chomp @allow;
	unless (&checkip($ip) and grep {$_ =~ /^$ip\b/i} @allow) {
		if ($comment eq "") {$comment = "Manually allowed"}
		print ALLOW "$ip \# $comment - ".localtime(time)."\n";
		if ($config{TESTING}) {
			print "Adding $ip to csf.allow only while in TESTING mode (not iptables ACCEPT)\n";
		} else {
			print "Adding $ip to csf.allow and iptables ACCEPT...\n";
			&linefilter($ip, "allow");
		}
	} else {
		print "add failed: $ip is in already in the allow file /etc/csf/csf.allow\n";
	}
	close (ALLOW) or &error(__LINE__,"Could not close /etc/csf/csf.allow: $!");
}
# end doadd
###############################################################################
# start dodeny
sub dodeny {
	my ($ip,$comment) = split (/\s/,$input{argument},2);

	&getethdev;

	if ($ips{$ip} or $ipscidr->find($ip) or $ipscidr6->find($ip)) {
		print "deny failed: [$ip] is one of this servers addresses!\n";
		return;
	}

	if (!&checkip($ip) and !(($ip =~ /:|\|/) and ($ip =~ /=/))) {
		print "deny failed: [$ip] is not a valid IP/CIDR\n";
		return;
	}

	open (IN, "</etc/csf/csf.allow") or &error(__LINE__,"deny failed: Could not open /etc/csf/csf.allow: $!");
	flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/csf.allow: $!");
	my @allow = <IN>;
	close (IN) or &error(__LINE__,"Could not close /etc/csf/csf.allow: $!");
	chomp @allow;
	foreach my $line (@allow) {
		if ($line =~ /^Include\s*(.*)$/) {
			my $incfile = $1;
			open (INCFILE, "<",$incfile) or &error(__LINE__,"Could not open $incfile: $!");
			flock (INCFILE, LOCK_SH) or &error(__LINE__,"Could not lock $incfile: $!");
			my @incallow = <INCFILE>;
			close (INCFILE) or &error(__LINE__,"Could not close $incfile: $!");
			chomp @incallow;
			push @allow,@incallow;
		}
	}
	foreach my $line (@allow) {
		if ($line eq "") {next}
		if ($line =~ /^\s*\#|Include/) {next}
		my ($ipd,$commentd) = split (/\s/,$line,2);
		if ($ipd eq $ip) {
			print "deny failed: $ip is in the allow file /etc/csf/csf.allow\n";
			return;
		}
		elsif ($ipd =~ /(.*\/\d+)/) {
			my $cidrhit = $1;
			if (&checkip($cidrhit)) {
				my $cidr = Net::CIDR::Lite->new;
				eval {$cidr->add($cidrhit)};
				if ($cidr->find($ip)) {
					print "deny failed: $ip is in the allow file /etc/csf/csf.allow\n";
					return;
				}
			}
		}
	}

	open (IN, "</etc/csf/csf.ignore") or &error(__LINE__,"deny failed: Could not open /etc/csf/csf.ignore: $!");
	flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/csf.ignore: $!");
	my @ignore = <IN>;
	close (IN) or &error(__LINE__,"Could not close /etc/csf/csf.ignore: $!");
	chomp @ignore;
	foreach my $line (@ignore) {
		if ($line =~ /^Include\s*(.*)$/) {
			my $incfile = $1;
			open (INCFILE, "<",$incfile) or &error(__LINE__,"Could not open $incfile: $!");
			flock (INCFILE, LOCK_SH) or &error(__LINE__,"Could not lock $incfile: $!");
			my @incignore = <INCFILE>;
			close (INCFILE) or &error(__LINE__,"Could not close $incfile: $!");
			chomp @incignore;
			push @ignore,@incignore;
		}
	}
	foreach my $line (@ignore) {
		if ($line eq "") {next}
		if ($line =~ /^\s*\#|Include/) {next}
		my ($ipd,$commentd) = split (/\s/,$line,2);
		if ($ipd eq $ip) {
			print "deny failed: $ip is in the ignore file /etc/csf/csf.ignore\n";
			return;
		}
		elsif ($ipd =~ /(.*\/\d+)/) {
			my $cidrhit = $1;
			if (&checkip($cidrhit)) {
				my $cidr = Net::CIDR::Lite->new;
				eval {$cidr->add($cidrhit)};
				if ($cidr->find($ip)) {
					print "deny failed: $ip is in the ignore file /etc/csf/csf.ignore\n";
					return;
				}
			}
		}
	}

	sysopen (DENY, "/etc/csf/csf.deny", O_RDWR | O_CREAT) or &error(__LINE__,"Could not open /etc/csf/csf.deny: $!");
	flock (DENY, LOCK_EX) or &error(__LINE__,"Could not lock /etc/csf/csf.deny: $!");
	my @deny = <DENY>;
	chomp @deny;
	unless (&checkip($ip) and grep {$_ =~ /^$ip\b/i} @deny) {
		my $ipcount;
		my @denyips;
		foreach my $line (@deny) {
			if ($line =~ /^(\#|\n)/) {next}
			if ($line =~ /do not delete/i) {next}
			if ($line =~ /^Include/i) {next}
			my ($ipd,$commentd) = split (/\s/,$line,2);
			$ipcount++;
			push @denyips,$line;
		}
		if (($config{DENY_IP_LIMIT} > 0) and ($ipcount >= $config{DENY_IP_LIMIT})) {
			seek (DENY, 0, 0);
			truncate (DENY, 0);
			foreach my $line (@deny) {
				my $hit = 0;
				for (my $x = 0; $x < ($ipcount - $config{DENY_IP_LIMIT})+1;$x++) {
					if ($line eq $denyips[$x]) {$hit = 1;}
				}
				if ($hit) {next}
				print DENY $line."\n";
			}
			print "csf: DENY_IP_LIMIT ($config{DENY_IP_LIMIT}), the following IP's were removed from /etc/csf/csf.deny:\n";
			for (my $x = 0; $x < ($ipcount - $config{DENY_IP_LIMIT})+1;$x++) {
				print "$denyips[$x]\n";
				my ($kip,undef) = split (/\s/,$denyips[$x],2);
				&linefilter($kip, "deny", "", 1);
			}

		}

		if ($comment eq "") {$comment = "Manually denied"}
		print DENY "$ip \# $comment - ".localtime(time)."\n";

		if ($config{TESTING}) {
			print "Adding $ip to csf.deny only while in TESTING mode (not iptables DROP)\n";
		} else {
			print "Adding $ip to csf.deny and iptables DROP...\n";
			&linefilter($ip, "deny");
		}
	} else {
		print "deny failed: $ip is in already in the deny file /etc/csf/csf.deny\n";
	}
	close (DENY) or &error(__LINE__,"Could not close /etc/csf/csf.deny: $!");
}
# end dodeny
###############################################################################
# start dokill
sub dokill {
	my $ip = $input{argument};

	if (!&checkip($ip) and !(($ip =~ /:|\|/) and ($ip =~ /=/))) {
		print "[$ip] is not a valid IP/CIDR\n";
		return;
	}

	&getethdev;

	$ip =~ s/\|/\\|/g;
	sysopen (DENY, "/etc/csf/csf.deny", O_RDWR | O_CREAT) or &error(__LINE__,"Could not open /etc/csf/csf.deny: $!");
	flock (DENY, LOCK_EX) or &error(__LINE__,"Could not lock /etc/csf/csf.deny: $!");
	my @deny = <DENY>;
	chomp @deny;
	seek (DENY, 0, 0);
	truncate (DENY, 0);
	my $hit = 0;
	foreach my $line (@deny) {
		my ($ipd,$commentd) = split (/\s/,$line,2);
		if ($ipd =~ /\b$ip\b/i) {
			print "Removing rule...\n";
			&linefilter($ipd, "deny", "", 1);
			$hit = 1;
			next;
		}
		print DENY $line."\n";
	}
	close (DENY) or &error(__LINE__,"Could not close /etc/csf/csf.deny: $!");
	unless ($hit) {
		print "csf: $ip not found in csf.deny\n";
	}
}
# end dokill
###############################################################################
# start dokillall
sub dokillall {

	&getethdev;

	sysopen (DENY, "/etc/csf/csf.deny", O_RDWR | O_CREAT) or &error(__LINE__,"Could not open /etc/csf/csf.deny: $!");
	flock (DENY, LOCK_EX) or &error(__LINE__,"Could not lock /etc/csf/csf.deny: $!");
	my @deny = <DENY>;
	chomp @deny;
	seek (DENY, 0, 0);
	truncate (DENY, 0);
	my $hit = 0;
	foreach my $line (@deny) {
		if ($line =~ /^(\#|\n|Include)/) {
			print DENY $line."\n";
		}
		elsif ($line =~ /do not delete/i) {
			print DENY $line."\n";
			print "csf: skipped line: $line\n";
		}
		else {
			my ($ipd,$commentd) = split (/\s/,$line,2);
			&linefilter($ipd, "deny", "", 1);
		}
	}
	close (DENY) or &error(__LINE__,"Could not close /etc/csf/csf.deny: $!");
	print "csf: all entries removed from csf.deny\n";
}
# end dokillall
###############################################################################
# start doakill
sub doakill {
	my $ip = $input{argument};

	if (!&checkip($ip) and !(($ip =~ /:|\|/) and ($ip =~ /=/))) {
		print "[$ip] is not a valid IP/CIDR\n";
		return;
	}

	&getethdev;

	$ip =~ s/\|/\\|/g;
	sysopen (ALLOW, "/etc/csf/csf.allow", O_RDWR | O_CREAT) or &error(__LINE__,"Could not open /etc/csf/csf.allow: $!");
	flock (ALLOW, LOCK_EX) or &error(__LINE__,"Could not lock /etc/csf/csf.allow: $!");
	my @allow = <ALLOW>;
	chomp @allow;
	seek (ALLOW, 0, 0);
	truncate (ALLOW, 0);
	my $hit = 0;
	foreach my $line (@allow) {
		my ($ipd,$commentd) = split (/\s/,$line,2);
		if ($ipd =~ /\b$ip\b/i) {
			print "Removing rule...\n";
			&linefilter($ipd, "allow", "", 1);
			$hit = 1;
			next;
		}
		print ALLOW $line."\n";
	}
	close (ALLOW) or &error(__LINE__,"Could not close /etc/csf/csf.allow: $!");
	unless ($hit) {
		print "csf: $ip not found in csf.allow\n";
	}
}
# end doakill
###############################################################################
# start help
sub dohelp {
	my $generic = " (cPanel)";
	if ($config{GENERIC}) {$generic = " (generic)"}
	if ($config{DIRECTADMIN}) {$generic = " (DirectAdmin)"}
	print <<END;
csf: v$version$generic

ConfigServer Security & Firewall
(c)2006-2012, Way to the Web Limited (http://www.configserver.com)

Usage: /usr/sbin/csf [option] [value]

Option              Meaning
-h, --help          Show this message
-l, --status        List/Show iptables configuration
-l6, --status6      List/Show ip6tables configuration
-s, --start         Start firewall rules
-f, --stop          Flush/Stop firewall rules (Note: lfd may restart csf)
-r, --restart       Restart firewall rules
-q, --startq        Quick restart (csf restarted by lfd)
-sf, --startf       Force CLI restart regardless of LF_QUICKSTART setting
-a, --add ip        Allow an IP and add to /etc/csf.allow
-ar, --addrm ip     Remove an IP from /etc/csf.allow and delete rule
-d, --deny ip       Deny an IP and add to /etc/csf.deny
-dr, --denyrm ip    Unblock an IP and remove from /etc/csf.deny
-df, --denyf        Remove and unblock all entries in /etc/csf.deny
-g, --grep ip       Search the iptables rules for an IP match (incl. CIDR)
-t, --temp          Displays the current list of temp IP entries and their TTL
-tr, --temprm ip    Remove an IPs from the temp IP ban and allow list
-td, --tempdeny ip ttl [-p port] [-d direction]
                    Add an IP to the temp IP ban list. ttl is how long to
                    blocks for (default:seconds, can use one suffix of h/m/d).
                    Optional port. Optional direction of block can be one of:
                    in, out or inout (default:in)
-ta, --tempallow ip ttl [-p port] [-d direction]
                    Add an IP to the temp IP allow list (default:inout)
-tf, --tempf        Flush all IPs from the temp IP entries
-cp, --cping        PING all members in an lfd Cluster
-cd, --cdeny ip     Deny an IP in a Cluster and add to /etc/csf.deny
-ca, --callow ip    Allow an IP in a Cluster and add to /etc/csf.allow
-cr, --crm ip       Unblock an IP in a Cluster and remove from /etc/csf.deny
-cc, --cconfig [name] [value]
                    Change configuration option [name] to [value] in a Cluster
-cf, --cfile [file] Send [file] in a Cluster to /etc/csf/
-crs, --crestart    Cluster restart csf and lfd
-w, --watch ip      Log SYN packets for an IP across iptables chains
-m, --mail [addr]   Display Server Check in HTML or email to [addr] if present
-lr, --logrun       Initiate Log Scanner report via lfd
-c, --check         Check for updates to csf but do not upgrade
-u, --update        Check for updates to csf and upgrade if available
-uf                 Force an update of csf
-x, --disable       Disable csf and lfd
-e, --enable        Enable csf and lfd if previously disabled
-v, --version       Show csf version
END

}
# end help
###############################################################################
# start dopacketfilters
sub dopacketfilters {
	if ($config{PACKET_FILTER}) {
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -N INVDROP");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -N INVALID");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVALID -m state --state INVALID -j INVDROP");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVALID -p tcp --tcp-flags ALL NONE -j INVDROP");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVALID -p tcp --tcp-flags ALL ALL -j INVDROP");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVALID -p tcp --tcp-flags SYN,FIN SYN,FIN -j INVDROP");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVALID -p tcp --tcp-flags SYN,RST SYN,RST -j INVDROP");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVALID -p tcp --tcp-flags FIN,RST FIN,RST -j INVDROP");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVALID -p tcp --tcp-flags ACK,FIN FIN -j INVDROP");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVALID -p tcp --tcp-flags ACK,PSH PSH -j INVDROP");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVALID -p tcp --tcp-flags ACK,URG URG -j INVDROP");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVALID -p tcp ! --syn -m state --state NEW -j INVDROP");
		if ($config{IPV6} and $config{IPV6_SPI}) {
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -N INVDROP");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -N INVALID");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVALID -m state --state INVALID -j INVDROP");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVALID -p tcp --tcp-flags ALL NONE -j INVDROP");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVALID -p tcp --tcp-flags ALL ALL -j INVDROP");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVALID -p tcp --tcp-flags SYN,FIN SYN,FIN -j INVDROP");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVALID -p tcp --tcp-flags SYN,RST SYN,RST -j INVDROP");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVALID -p tcp --tcp-flags FIN,RST FIN,RST -j INVDROP");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVALID -p tcp --tcp-flags ACK,FIN FIN -j INVDROP");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVALID -p tcp --tcp-flags ACK,PSH PSH -j INVDROP");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVALID -p tcp --tcp-flags ACK,URG URG -j INVDROP");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVALID -p tcp ! --syn -m state --state NEW -j INVDROP");
		}

		if ($config{DROP_PF_LOGGING}) {
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVDROP -m state --state INVALID -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INVALID* '");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVDROP -p tcp --tcp-flags ALL NONE -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_AN* '");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVDROP -p tcp --tcp-flags ALL ALL -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_AA* '");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVDROP -p tcp --tcp-flags SYN,FIN SYN,FIN -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_SFSF* '");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVDROP -p tcp --tcp-flags SYN,RST SYN,RST -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_SRSR* '");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVDROP -p tcp --tcp-flags FIN,RST FIN,RST -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_FRFR* '");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVDROP -p tcp --tcp-flags ACK,FIN FIN -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_AFF* '");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVDROP -p tcp --tcp-flags ACK,PSH PSH -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_APP* '");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVDROP -p tcp --tcp-flags ACK,URG URG -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_AUU* '");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVDROP -p tcp ! --syn -m state --state NEW -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_NOSYN* '");
			if ($config{IPV6} and $config{IPV6_SPI}) {
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVDROP -m state --state INVALID -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INVALID* '");
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVDROP -p tcp --tcp-flags ALL NONE -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_AN* '");
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVDROP -p tcp --tcp-flags ALL ALL -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_AA* '");
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVDROP -p tcp --tcp-flags SYN,FIN SYN,FIN -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_SFSF* '");
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVDROP -p tcp --tcp-flags SYN,RST SYN,RST -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_SRSR* '");
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVDROP -p tcp --tcp-flags FIN,RST FIN,RST -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_FRFR* '");
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVDROP -p tcp --tcp-flags ACK,FIN FIN -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_AFF* '");
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVDROP -p tcp --tcp-flags ACK,PSH PSH -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_APP* '");
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVDROP -p tcp --tcp-flags ACK,URG URG -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_AUU* '");
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVDROP -p tcp ! --syn -m state --state NEW -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *INV_NOSYN* '");
			}
		}
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INVDROP -j $config{DROP}");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I INPUT $ethdevin -p tcp -j INVALID");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I OUTPUT $ethdevout -p tcp -j INVALID");
		if ($config{IPV6} and $config{IPV6_SPI}) {
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INVDROP -j $config{DROP}");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I INPUT $ethdevin -p tcp -j INVALID");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I OUTPUT $ethdevout -p tcp -j INVALID");
		}
	}
}
# end dopacketfilters
###############################################################################
# start doportfilters
sub doportfilters {
	open (IN, "</etc/csf/csf.sips") or &error(__LINE__,"Could not open /etc/csf/csf.sips: $!");
	flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/csf.sips: $!");
	my @sips = <IN>;
	close (IN) or &error(__LINE__,"Could not close /etc/csf/csf.sips: $!");
	chomp @sips;
	my $dropin = $config{DROP};
	my $dropout = $config{DROP};
	if ($config{DROP_LOGGING}) {$dropin = "LOGDROPIN"}
	if ($config{DROP_LOGGING}) {$dropout = "LOGDROPOUT"}
	foreach my $line (@sips) {
		my ($ip,$comment) = split (/\s/,$line,2);
		if (&checkip($ip)) {
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOCALINPUT $ethdevin -d $ip -j $dropin");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOCALOUTPUT $ethdevout -s $ip -j $dropout");
		}
	}

	if ($config{GLOBAL_DENY}) {
		if (-e "/etc/csf/csf.gdeny") {
			open (IN, "</etc/csf/csf.gdeny") or &error(__LINE__,"Could not open /etc/csf/csf.gdeny: $!");
			flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/csf.gdeny: $!");
			my @gdeny = <IN>;
			close (IN) or &error(__LINE__,"Could not close /etc/csf/csf.gdeny: $!");
			chomp @gdeny;
			foreach my $line (@gdeny) {
				my ($ip,$comment) = split (/\s/,$line,2);
				&linefilter($ip, "deny","GDENY");
			}
		}
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOCALINPUT $ethdevin -j GDENYIN");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOCALOUTPUT $ethdevout -j GDENYOUT");
		if ($config{IPV6}) {
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOCALINPUT $ethdevin -j GDENYIN");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOCALOUTPUT $ethdevout -j GDENYOUT");
		}
	}

	open (IN, "</etc/csf/csf.deny") or &error(__LINE__,"Could not open /etc/csf/csf.deny: $!");
	flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/csf.deny: $!");
	my @deny = <IN>;
	close (IN) or &error(__LINE__,"Could not close /etc/csf/csf.deny: $!");
	chomp @deny;
	foreach my $line (@deny) {
		if ($line =~ /^Include\s*(.*)$/) {
			my $incfile = $1;
			open (INCFILE, "<",$incfile) or &error(__LINE__,"Could not open $incfile: $!");
			flock (INCFILE, LOCK_SH) or &error(__LINE__,"Could not lock $incfile: $!");
			my @incdeny = <INCFILE>;
			close (INCFILE) or &error(__LINE__,"Could not close $incfile: $!");
			chomp @incdeny;
			push @deny,@incdeny;
		}
	}
	foreach my $line (@deny) {
		my ($ip,$comment) = split (/\s/,$line,2);
		&linefilter($ip, "deny");
	}

	if (! -z "/etc/csf/csf.tempban") {
		my $dropin = $config{DROP};
		my $dropout = $config{DROP};
		if ($config{DROP_IP_LOGGING}) {$dropin = "LOGDROPIN"}
		if ($config{DROP_IP_LOGGING}) {$dropout = "LOGDROPOUT"}

		sysopen (TEMPBAN, "/etc/csf/csf.tempban", O_RDWR | O_CREAT);
		flock (TEMPBAN, LOCK_EX);
		my @data = <TEMPBAN>;
		chomp @data;

		my @newdata;
		foreach my $line (@data) {
			my ($time,$ip,$port,$inout,$timeout,$message) = split(/\|/,$line);
			my $iptype = &checkip($ip);
			if (((time - $time) < $timeout) and $iptype) {
				if ($inout =~ /in/) {
					if ($port) {
						foreach my $dport (split(/\,/,$port)) {
							if ($iptype == 6) {
								&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOCALINPUT $ethdevin -p tcp --dport $dport -s $ip -j $dropin");
							} else {
								&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOCALINPUT $ethdevin -p tcp --dport $dport -s $ip -j $dropin");
								if ($messengerports{$dport} and $config{MESSENGER} and $config{MESSENGER_TEMP}) {&domessenger($ip,"A",$dport)}
							}
						}
					} else {
						if ($iptype == 6) {
							&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOCALINPUT $ethdevin -s $ip -j $dropin");
						} else {
							&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOCALINPUT $ethdevin -s $ip -j $dropin");
							if ($config{MESSENGER} and $config{MESSENGER_TEMP}) {&domessenger($ip,"A")}
						}
					}
				}
				if ($inout =~ /out/) {
					if ($iptype == 6) {
						&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOCALOUTPUT $ethdevout -d $ip -j $dropout");
					} else {
						&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOCALOUTPUT $ethdevout -d $ip -j $dropout");
					}
				}
				push @newdata, $line;
			}
		}
		seek (TEMPBAN, 0, 0);
		truncate (TEMPBAN, 0);
		foreach my $line (@newdata) {print TEMPBAN "$line\n"}
		close (TEMPBAN);
	}

	if (! -z "/etc/csf/csf.tempallow") {
		sysopen (TEMPALLOW, "/etc/csf/csf.tempallow", O_RDWR | O_CREAT);
		flock (TEMPALLOW, LOCK_EX);
		my @data = <TEMPALLOW>;
		chomp @data;

		my @newdata;
		foreach my $line (@data) {
			my ($time,$ip,$port,$inout,$timeout,$message) = split(/\|/,$line);
			my $iptype = &checkip($ip);
			if (((time - $time) < $timeout) and $iptype) {
				if ($inout =~ /in/) {
					if ($port) {
						foreach my $dport (split(/\,/,$port)) {
							if ($iptype == 6) {
								&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I LOCALINPUT $ethdevin -p tcp --dport $dport -s $ip -j $accept");
							} else {
								&syscommand(__LINE__,"$config{IPTABLES} $verbose -I LOCALINPUT $ethdevin -p tcp --dport $dport -s $ip -j $accept");
							}
						}
					} else {
						if ($iptype == 6) {
							&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I LOCALINPUT $ethdevin -s $ip -j $accept");
						} else {
							&syscommand(__LINE__,"$config{IPTABLES} $verbose -I LOCALINPUT $ethdevin -s $ip -j $accept");
						}
					}
				}
				if ($inout =~ /out/) {
					if ($iptype == 6) {
						&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I LOCALOUTPUT $ethdevout -d $ip -j $accept");
					} else {
						&syscommand(__LINE__,"$config{IPTABLES} $verbose -I LOCALOUTPUT $ethdevout -d $ip -j $accept");
					}
				}
				push @newdata, $line;
			}
		}
		seek (TEMPALLOW, 0, 0);
		truncate (TEMPALLOW, 0);
		foreach my $line (@newdata) {print TEMPALLOW "$line\n"}
		close (TEMPALLOW);
	}

	if ($config{GLOBAL_ALLOW}) {
		if (-e "/etc/csf/csf.gallow") {
			open (IN, "</etc/csf/csf.gallow") or &error(__LINE__,"Could not open /etc/csf/csf.gallow: $!");
			flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/csf.gallow: $!");
			my @gallow = <IN>;
			close (IN) or &error(__LINE__,"Could not close /etc/csf/csf.gallow: $!");
			chomp @gallow;
			foreach my $line (@gallow) {
				my ($ip,$comment) = split (/\s/,$line,2);
				&linefilter($ip, "allow","GALLOW");
			}
		}
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I LOCALINPUT $ethdevin -j GALLOWIN");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I LOCALOUTPUT $ethdevout -j GALLOWOUT");
		if ($config{IPV6}) {
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I LOCALINPUT $ethdevin -j GALLOWIN");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I LOCALOUTPUT $ethdevout -j GALLOWOUT");
		}
	}

	$config{CC_ALLOW} =~ s/\s//g;
	if ($config{CC_ALLOW}) {
		foreach my $cc (split(/\,/,$config{CC_ALLOW})) {
			$cc = lc $cc;
			if (-e "/etc/csf/zone/$cc.zone") {
				open (IN, "</etc/csf/zone/$cc.zone") or &error(__LINE__,"Could not open /etc/csf/zone/$cc.zone: $!");
				flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/zone/$cc.zone: $!");
				my @cc_allow = <IN>;
				close (IN) or &error(__LINE__,"Could not close /etc/csf/zone/$cc.zone: $!");
				chomp @cc_allow;
				foreach my $line (@cc_allow) {
					my ($ip,undef) = split (/\s/,$line,2);
					if (&checkip($ip)) {
						if ($config{CC_DROP_CIDR} > 0 and $config{CC_DROP_CIDR} < 33) {
							my ($drop_ip,$drop_cidr) = split(/\//,$ip);
							if ($drop_cidr eq "") {$drop_cidr = "32"}
							if ($drop_cidr > $config{CC_DROP_CIDR}) {next}
						}
						&syscommand(__LINE__,"$config{IPTABLES} $verbose -I CC_ALLOW -s $ip -j $accept");
					}
				}
			}
		}
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I LOCALINPUT $ethdevin -j CC_ALLOW");
	}

	if ($config{DYNDNS}) {
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I LOCALINPUT $ethdevin -j ALLOWDYNIN");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I LOCALOUTPUT $ethdevout -j ALLOWDYNOUT");
	}
	if ($config{GLOBAL_DYNDNS}) {
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I LOCALINPUT $ethdevin -j GDYNIN");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I LOCALOUTPUT $ethdevout -j GDYNOUT");
	}

	open (IN, "</etc/csf/csf.allow") or &error(__LINE__,"Could not open /etc/csf/csf.allow: $!");
	flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/csf.allow: $!");
	my @allow = <IN>;
	close (IN) or &error(__LINE__,"Could not close /etc/csf/csf.allow: $!");
	chomp @allow;
	foreach my $line (@allow) {
		if ($line =~ /^Include\s*(.*)$/) {
			my $incfile = $1;
			open (INCFILE, "<",$incfile) or &error(__LINE__,"Could not open $incfile: $!");
			flock (INCFILE, LOCK_SH) or &error(__LINE__,"Could not lock $incfile: $!");
			my @incallow = <INCFILE>;
			close (INCFILE) or &error(__LINE__,"Could not close $incfile: $!");
			chomp @incallow;
			push @allow,@incallow;
		}
	}
	foreach my $line (@allow) {
		my ($ip,$comment) = split (/\s/,$line,2);
		&linefilter($ip, "allow");
	}

	if ($config{LF_DSHIELD}) {
		if (-e "/etc/csf/csf.dshield") {
			my $drop = $config{DROP};
			if ($config{DROP_IP_LOGGING}) {$drop = "BLOCKDROP"}
			open (IN, "</etc/csf/csf.dshield") or &error(__LINE__,"Could not open /etc/csf/csf.dshield: $!");
			flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/csf.dshield: $!");
			my @dshield = <IN>;
			close (IN) or &error(__LINE__,"Could not close /etc/csf/csf.dshield: $!");
			chomp @dshield;
			foreach my $line (@dshield) {
				my ($ip,$comment) = split (/\s/,$line,2);
				if (&checkip($ip)) {
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -I DSHIELD -s $ip -j $drop");
				}
			}
		}
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOCALINPUT $ethdevin -j DSHIELD");
	}

	if ($config{LF_SPAMHAUS}) {
		if (-e "/etc/csf/csf.spamhaus") {
			my $drop = $config{DROP};
			if ($config{DROP_IP_LOGGING}) {$drop = "BLOCKDROP"}
			open (IN, "</etc/csf/csf.spamhaus") or &error(__LINE__,"Could not open /etc/csf/csf.spamhaus: $!");
			flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/csf.spamhaus: $!");
			my @spamhaus = <IN>;
			close (IN) or &error(__LINE__,"Could not close /etc/csf/csf.spamhaus: $!");
			chomp @spamhaus;
			foreach my $line (@spamhaus) {
				my ($ip,$comment) = split (/\s/,$line,2);
				if (&checkip($ip)) {
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -I SPAMHAUS -s $ip -j $drop");
				}
			}
		}
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOCALINPUT $ethdevin -j SPAMHAUS");
	}

	if ($config{LF_TOR}) {
		if (-e "/etc/csf/csf.tor") {
			my $drop = $config{DROP};
			if ($config{DROP_IP_LOGGING}) {$drop = "BLOCKDROP"}
			open (IN, "</etc/csf/csf.tor") or &error(__LINE__,"Could not open /etc/csf/csf.tor: $!");
			flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/csf.tor: $!");
			my @tor = <IN>;
			close (IN) or &error(__LINE__,"Could not close /etc/csf/csf.tor: $!");
			chomp @tor;
			foreach my $line (@tor) {
				my ($ip,$comment) = split (/\s/,$line,2);
				if (&checkip($ip)) {
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -I TOR -s $ip -j $drop");
				}
			}
		}
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOCALINPUT $ethdevin -j TOR");
	}

	$config{CC_DENY} =~ s/\s//g;
	if ($config{CC_DENY}) {
		foreach my $cc (split(/\,/,$config{CC_DENY})) {
			$cc = lc $cc;
			if (-e "/etc/csf/zone/$cc.zone") {
				my $drop = $config{DROP};
				if ($config{DROP_IP_LOGGING}) {$drop = "CCDROP"}
				open (IN, "</etc/csf/zone/$cc.zone") or &error(__LINE__,"Could not open /etc/csf/zone/$cc.zone: $!");
				flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/zone/$cc.zone: $!");
				my @cc_deny = <IN>;
				close (IN) or &error(__LINE__,"Could not close /etc/csf/zone/$cc.zone: $!");
				chomp @cc_deny;
				foreach my $line (@cc_deny) {
					my ($ip,undef) = split (/\s/,$line,2);
					if (&checkip($ip)) {
						if ($config{CC_DROP_CIDR} > 0 and $config{CC_DROP_CIDR} < 33) {
							my ($drop_ip,$drop_cidr) = split(/\//,$ip);
							if ($drop_cidr eq "") {$drop_cidr = "32"}
							if ($drop_cidr > $config{CC_DROP_CIDR}) {next}
						}
						&syscommand(__LINE__,"$config{IPTABLES} $verbose -I CC_DENY -s $ip -j $drop");
					}
				}
			}
		}
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOCALINPUT $ethdevin -j CC_DENY");
	}


	$config{CC_ALLOW_FILTER} =~ s/\s//g;
	if ($config{CC_ALLOW_FILTER}) {
		my $cnt = 0;
		foreach my $cc (split(/\,/,$config{CC_ALLOW_FILTER})) {
			$cc = lc $cc;
			if (-e "/etc/csf/zone/$cc.zone") {
				open (IN, "</etc/csf/zone/$cc.zone") or &error(__LINE__,"Could not open /etc/csf/zone/$cc.zone: $!");
				flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/zone/$cc.zone: $!");
				my @cc_allow = <IN>;
				close (IN) or &error(__LINE__,"Could not close /etc/csf/zone/$cc.zone: $!");
				chomp @cc_allow;
				foreach my $line (@cc_allow) {
					my ($ip,undef) = split (/\s/,$line,2);
					if (&checkip($ip)) {
						if ($config{CC_DROP_CIDR} > 0 and $config{CC_DROP_CIDR} < 33) {
							my ($drop_ip,$drop_cidr) = split(/\//,$ip);
							if ($drop_cidr eq "") {$drop_cidr = "32"}
							if ($drop_cidr > $config{CC_DROP_CIDR}) {next}
						}
						&syscommand(__LINE__,"$config{IPTABLES} $verbose -I CC_ALLOWF -s $ip -j RETURN");
						$cnt++;
					}
				}
			}
		}
		my $drop = $config{DROP};
		if ($config{DROP_IP_LOGGING}) {$drop = "CCDROP"}
		if ($cnt > 0) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -A CC_ALLOWF -j $drop")};
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOCALINPUT $ethdevin -j CC_ALLOWF");
	}

	if ($config{LF_BOGON}) {
		if (-e "/etc/csf/csf.bogon") {
			my $drop = $config{DROP};
			if ($config{DROP_IP_LOGGING}) {$drop = "BLOCKDROP"}
			open (IN, "</etc/csf/csf.bogon") or &error(__LINE__,"Could not open /etc/csf/csf.bogon: $!");
			flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/csf.bogon: $!");
			my @bogon = <IN>;
			close (IN) or &error(__LINE__,"Could not close /etc/csf/csf.bogon: $!");
			chomp @bogon;
			foreach my $line (@bogon) {
				my ($ip,$comment) = split (/\s/,$line,2);
				if (&checkip($ip)) {
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -I BOGON -s $ip -j $drop");
				}
			}
		}
		$config{LF_BOGON_SKIP} =~ s/\s//g;
		if ($config{LF_BOGON_SKIP} ne "") {
			foreach my $device (split(/\,/,$config{LF_BOGON_SKIP})) {
				if ($ifaces{$device}) {
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -I BOGON -i $device -j RETURN");
				} else {
					&error(__LINE__,"Ethernet device [$device] not listed in ifconfig");
				}
			}
		}
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOCALINPUT $ethdevin -j BOGON");
	}

	if ($config{CLUSTER_SENDTO}) {
		foreach my $ip (split(/\,/,$config{CLUSTER_SENDTO})) {
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -I LOCALOUTPUT $ethdevout -p tcp -d $ip --dport $config{CLUSTER_PORT} -j $accept");
		}
	}
	if ($config{CLUSTER_RECVFROM}) {
		foreach my $ip (split(/\,/,$config{CLUSTER_RECVFROM})) {
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -I LOCALINPUT $ethdevin -p tcp -s $ip --dport $config{CLUSTER_PORT} -j $accept");
		}
	}

	if ($config{SYNFLOOD}) {
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A SYNFLOOD -m limit --limit $config{SYNFLOOD_RATE} --limit-burst $config{SYNFLOOD_BURST} -j RETURN");
		if ($config{DROP_LOGGING}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -A SYNFLOOD -m limit --limit 30/m --limit-burst 5 -j $logmodule 'Firewall: *SYNFLOOD Blocked* '")}
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A SYNFLOOD -j DROP");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -I INPUT $ethdevin -p tcp --syn -j SYNFLOOD");
	}

	$config{PORTFLOOD} =~ s/\s//g;
	if ($config{PORTFLOOD}) {
		foreach my $portflood (split(/\,/,$config{PORTFLOOD})) {
			my ($port,$proto,$count,$seconds) = split(/\;/,$portflood);
			if ((($port < 0) or ($port > 65535)) or ($proto !~ /icmp|tcp|udp/) or ($seconds !~ /\d+/)) {&error(__LINE__,"csf: Incorrect PORTFLOOD setting: [$portflood]")}
			if (($count < 1) or ($count > 20)) {
				print "WARNING: count in PORTFLOOD setting should be between 1 and 20: [$portflood]\n";
			}
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -p $proto --dport $port -m state --state NEW -m recent --set --name $port");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -p $proto --dport $port -m state --state NEW -m recent --update --seconds $seconds --hitcount $count --name $port -j PORTFLOOD");
		}
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A PORTFLOOD -j $config{DROP}");
	}

	$config{CONNLIMIT} =~ s/\s//g;
	if ($config{CONNLIMIT}) {
		foreach my $connlimit (split(/\,/,$config{CONNLIMIT})) {
			my ($port,$limit) = split(/\;/,$connlimit);
			if (($port < 0) or ($port > 65535) or ($limit < 1) or ($limit !~ /\d+/)) {&error(__LINE__,"csf: Incorrect CONNLIMIT setting: [$connlimit]")}
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -p tcp --syn --dport $port -m connlimit --connlimit-above $limit -j CONNLIMIT");
		}
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A CONNLIMIT -p tcp -j REJECT --reject-with tcp-reset");
	}

	&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -m state --state ESTABLISHED,RELATED -j $accept");
	&syscommand(__LINE__,"$config{IPTABLES} $verbose -A OUTPUT $ethdevout -m state --state ESTABLISHED,RELATED -j $accept");
	if ($config{IPV6} and $config{IPV6_SPI}) {
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INPUT $ethdevin -m state --state ESTABLISHED,RELATED -j $accept");
		&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A OUTPUT $ethdevout -m state --state ESTABLISHED,RELATED -j $accept");
	}

	$config{PORTKNOCKING} =~ s/\s//g;
	if ($config{PORTKNOCKING}) {
		foreach my $portknock (split(/\,/,$config{PORTKNOCKING})) {
			my ($port,$proto,$timeout,$knocks) = split(/\;/,$portknock,4);
			my @steps = split(/\;/,$knocks);
			my $nsteps = @steps;
			if ($nsteps < 3) {
				print "csf: Error - not enough Port Knocks for port $port [$knocks]\n";
				next;
			}
			for (my $step = 1; $step < $nsteps+1; $step++) {
				my $ar = $step - 1;
				if ($step == 1) {
					if ($config{PORTKNOCKING_LOG}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -p $proto --dport $steps[$ar] -m state --state NEW -m limit --limit 30/m --limit-burst 5 -j LOG --log-prefix 'Knock: *$port\_S$step* '")}
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -p $proto --dport $steps[$ar] -m state --state NEW -m recent --set --name PK\_$port\_S$step");
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -p $proto --dport $steps[$ar] -m state --state NEW -j DROP");
				} else {
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -N PK\_$port\_S$step\_IN");
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -A PK\_$port\_S$step\_IN -m recent --name PK\_$port\_S".($step - 1)." --remove");
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -A PK\_$port\_S$step\_IN -m recent --name PK\_$port\_S$step --set");
					if ($config{PORTKNOCKING_LOG}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -A PK\_$port\_S$step\_IN -m limit --limit 30/m --limit-burst 5 -j LOG --log-prefix 'Knock: *$port\_S$step* '")}
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -A PK\_$port\_S$step\_IN -j DROP");
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -p $proto --dport $steps[$ar] -m state --state NEW -m recent --rcheck --seconds $timeout --name PK\_$port\_S".($step - 1)." -j PK\_$port\_S$step\_IN");
				}
			}
			if ($config{PORTKNOCKING_LOG}) {&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -p $proto --dport $port -m state --state NEW -m recent --rcheck --seconds $timeout --name PK\_$port\_S$nsteps -m limit --limit 30/m --limit-burst 5 -j LOG --log-prefix 'Knock: *$port\_IN* '")}
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -p $proto --dport $port -m state --state NEW -m recent --rcheck --seconds $timeout --name PK\_$port\_S$nsteps -j ACCEPT");
		}
	}

	$config{TCP_IN} =~ s/\s//g;
	if ($config{TCP_IN} ne "") {
		foreach my $port (split(/\,/,$config{TCP_IN})) {
			if ($port eq "") {next}
			if ($port !~ /^[\d:]*$/) {&error(__LINE__,"Invalid TCP_IN port [$port]")}
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -p tcp -m state --state NEW --dport $port -j $accept");
		}
	}
	$config{TCP6_IN} =~ s/\s//g;
	if ($config{IPV6} and $config{TCP6_IN} ne "") {
		foreach my $port (split(/\,/,$config{TCP6_IN})) {
			if ($port eq "") {next}
			if ($port !~ /^[\d:]*$/) {&error(__LINE__,"Invalid TCP6_IN port [$port]")}
			if ($config{IPV6_SPI}) {
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INPUT $ethdevin -p tcp -m state --state NEW --dport $port -j $accept");
			} else {
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INPUT $ethdevin -p tcp --dport $port -j $accept");
			}
		}
	}

	$config{TCP_OUT} =~ s/\s//g;
	if ($config{TCP_OUT} ne "") {
		foreach my $port (split(/\,/,$config{TCP_OUT})) {
			if ($port eq "") {next}
			if ($port !~ /^[\d:]*$/) {&error(__LINE__,"Invalid TCP_OUT port [$port]")}
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A OUTPUT $ethdevout -p tcp -m state --state NEW --dport $port -j $accept");
		}
	}
	$config{TCP6_OUT} =~ s/\s//g;
	if ($config{IPV6} and $config{TCP6_OUT} ne "") {
		foreach my $port (split(/\,/,$config{TCP6_OUT})) {
			if ($port eq "") {next}
			if ($port !~ /^[\d:]*$/) {&error(__LINE__,"Invalid TCP6_OUT port [$port]")}
			if ($config{IPV6_SPI}) {
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A OUTPUT $ethdevout -p tcp -m state --state NEW --dport $port -j $accept");
			} else {
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A OUTPUT $ethdevout -p tcp --dport $port -j $accept");
			}
		}
	}

	$config{UDP_IN} =~ s/\s//g;
	if ($config{UDP_IN} ne "") {
		foreach my $port (split(/\,/,$config{UDP_IN})) {
			if ($port eq "") {next}
			if ($port !~ /^[\d:]*$/) {&error(__LINE__,"Invalid UDP_IN port [$port]")}
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -p udp -m state --state NEW --dport $port -j $accept");
		}
	}
	$config{UDP6_IN} =~ s/\s//g;
	if ($config{IPV6} and $config{UDP6_IN} ne "") {
		foreach my $port (split(/\,/,$config{UDP6_IN})) {
			if ($port eq "") {next}
			if ($port !~ /^[\d:]*$/) {&error(__LINE__,"Invalid UDP6_IN port [$port]")}
			if ($config{IPV6_SPI}) {
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INPUT $ethdevin -p udp -m state --state NEW --dport $port -j $accept");
			} else {
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INPUT $ethdevin -p udp --dport $port -j $accept");
			}
		}
	}

	$config{UDP_OUT} =~ s/\s//g;
	if ($config{UDP_OUT} ne "") {
		foreach my $port (split(/\,/,$config{UDP_OUT})) {
			if ($port eq "") {next}
			if ($port !~ /^[\d:]*$/) {&error(__LINE__,"Invalid UDP_OUT port [$port]")}
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A OUTPUT $ethdevout -p udp -m state --state NEW --dport $port -j $accept");
		}
	}
	$config{UDP6_OUT} =~ s/\s//g;
	if ($config{IPV6} and $config{UDP6_OUT} ne "") {
		foreach my $port (split(/\,/,$config{UDP6_OUT})) {
			if ($port eq "") {next}
			if ($port !~ /^[\d:]*$/) {&error(__LINE__,"Invalid UDP6_OUT port [$port]")}
			if ($config{IPV6_SPI}) {
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A OUTPUT $ethdevout -p udp -m state --state NEW --dport $port -j $accept");
			} else {
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A OUTPUT $ethdevout -p udp --dport $port -j $accept");
			}
		}
	}

#	if ($config{IPV6}) {
#		&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A INPUT $ethdevin -p udp -m frag --fraglast -j $accept");
#	}

	my $icmp_in_rate = "";
	my $icmp_out_rate = "";
	if ($config{ICMP_IN_RATE}) {$icmp_in_rate = "-m limit --limit $config{ICMP_IN_RATE}"}
	if ($config{ICMP_OUT_RATE}) {$icmp_out_rate = "-m limit --limit $config{ICMP_OUT_RATE}"}

	if ($config{ICMP_IN}) {
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -p icmp --icmp-type echo-request $icmp_in_rate -j $accept");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A OUTPUT $ethdevout -p icmp --icmp-type echo-reply $icmp_out_rate -j $accept");
	}

	if ($config{ICMP_OUT}) {
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A OUTPUT $ethdevout -p icmp --icmp-type echo-request $icmp_out_rate -j $accept");
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -p icmp --icmp-type echo-reply $icmp_in_rate -j $accept");
	}

	&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -p icmp --icmp-type time-exceeded -j $accept");
	&syscommand(__LINE__,"$config{IPTABLES} $verbose -A INPUT $ethdevin -p icmp --icmp-type destination-unreachable -j $accept");

	&syscommand(__LINE__,"$config{IPTABLES} $verbose -A OUTPUT $ethdevout -p icmp --icmp-type time-exceeded -j $accept");
	&syscommand(__LINE__,"$config{IPTABLES} $verbose -A OUTPUT $ethdevout -p icmp --icmp-type destination-unreachable -j $accept");

	if ($config{IPV6}) {
		if ($config{IPV6_ICMP_STRICT}) {
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A INPUT $ethdevin -p icmpv6 --icmpv6-type destination-unreachable -j $accept");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A INPUT $ethdevin -p icmpv6 --icmpv6-type packet-too-big -j $accept");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A INPUT $ethdevin -p icmpv6 --icmpv6-type time-exceeded -j $accept");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A INPUT $ethdevin -p icmpv6 --icmpv6-type parameter-problem -j $accept");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A INPUT $ethdevin -p icmpv6 --icmpv6-type echo-request -j $accept");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A INPUT $ethdevin -p icmpv6 --icmpv6-type echo-reply -j $accept");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A INPUT $ethdevin -p icmpv6 --icmpv6-type router-advertisement -m hl --hl-eq 255 -j $accept");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A INPUT $ethdevin -p icmpv6 --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j $accept");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A INPUT $ethdevin -p icmpv6 --icmpv6-type neighbor-advertisement -m hl --hl-eq 255 -j $accept");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A INPUT $ethdevin -p icmpv6 --icmpv6-type redirect -m hl --hl-eq 255 -j $accept");
		} else {
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A INPUT $ethdevin -p icmpv6 -j $accept");
		}

		&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A OUTPUT $ethdevout -p icmpv6 -j $accept");
#		&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A OUTPUT $ethdevout -p icmpv6 --icmpv6-type destination-unreachable -j $accept");
#		&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A OUTPUT $ethdevout -p icmpv6 --icmpv6-type packet-too-big -j $accept");
#		&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A OUTPUT $ethdevout -p icmpv6 --icmpv6-type time-exceeded -j $accept");
#		&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A OUTPUT $ethdevout -p icmpv6 --icmpv6-type parameter-problem -j $accept");
#		&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A OUTPUT $ethdevout -p icmpv6 --icmpv6-type echo-request -j $accept");
#		&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A OUTPUT $ethdevout -p icmpv6 --icmpv6-type echo-reply -j $accept");
#		&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A OUTPUT $ethdevout -p icmpv6 --icmpv6-type router-advertisement -m hl --hl-eq 255 -j $accept");
#		&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A OUTPUT $ethdevout -p icmpv6 --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j $accept");
#		&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A OUTPUT $ethdevout -p icmpv6 --icmpv6-type neighbor-advertisement -m hl --hl-eq 255 -j $accept");
#		&syscommand(__LINE__,"$config{IP6TABLES} $verbose  -A OUTPUT $ethdevout -p icmpv6 --icmpv6-type redirect -m hl --hl-eq 255 -j $accept");
	}

	if (-e "/etc/csf/csf.redirect") {
		open (IN, "</etc/csf/csf.redirect") or &error(__LINE__,"Could not open /etc/csf/csf.redirect: $!");
		flock (IN, LOCK_SH) or &error(__LINE__,"Could not lock /etc/csf/csf.redirect: $!");
		my @redirects = <IN>;
		close (IN) or &error(__LINE__,"Could not close /etc/csf/csf.redirect: $!");
		chomp @redirects;
		my $dnat = 0;
		foreach my $line (@redirects) {
			if ($line =~ /^(\#|\n|\r|\s)/ or $line eq "") {next}
			my ($redirect,$comment) = split (/\s/,$line,2);
			my ($ipx,$porta,$ipy,$portb,$proto) = split (/\|/,$redirect);
			unless ($proto eq "tcp" or $proto eq "udp") {&error(__LINE__,"csf: Incorrect csf.redirect  setting ([$proto]): [$line]")}
			unless ($ipx eq "*" or &checkip($ipx)) {&error(__LINE__,"csf: Incorrect csf.redirect  setting ([$ipx]): [$line]")}
			unless ($porta eq "*" or $porta > 0 or $porta < 65536) {&error(__LINE__,"csf: Incorrect csf.redirect  setting ([$porta]): [$line]")}
			unless ($ipy eq "*" or &checkip($ipy)) {&error(__LINE__,"csf: Incorrect csf.redirect  setting ([$ipy]): [$line]")}
			unless ($portb eq "*" or $portb > 0 or $portb < 65536) {&error(__LINE__,"csf: Incorrect csf.redirect  setting ([$portb]): [$line]")}
			if ($ipy eq "*") {
				if ($ipx eq "*") {&syscommand(__LINE__,"$config{IPTABLES} $verbose -t nat -A PREROUTING $ethdevin -p $proto --dport $porta -j REDIRECT --to-ports $portb")}
				else {&syscommand(__LINE__,"$config{IPTABLES} $verbose -t nat -A PREROUTING $ethdevin -p $proto -d $ipx --dport $porta -j REDIRECT --to-ports $portb")}
			} else {
				unless ($dnat) {
					open (OUT,">","/proc/sys/net/ipv4/ip_forward");
					print OUT "1";
					close (OUT);
					$dnat = 1;
				}
				if ($ipx ne "*" and $porta eq "*") {
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -t nat -A PREROUTING $ethdevin -p $proto -d $ipx -j DNAT --to-destination $ipy");
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -t nat -A POSTROUTING $ethdevout -p $proto -d $ipy -j SNAT --to-source $ipx");
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -A FORWARD $ethdevin -p $proto -d $ipy  -m state --state NEW -j ACCEPT");
				}
				elsif ($ipx ne "*" and $porta ne "*" and $portb ne "*") {
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -t nat -A PREROUTING $ethdevin -p $proto -d $ipx --dport $porta -j DNAT --to-destination $ipy:$portb");
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -t nat -A POSTROUTING $ethdevout -p $proto -d $ipy -j SNAT --to-source $ipx");
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -A FORWARD $ethdevin -p $proto -d $ipy --dport $portb  -m state --state NEW -j ACCEPT");
				}
				else {&error(__LINE__,"csf: Invalid csf.redirect format [$line]")}
			}
		}
		if ($dnat) {
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A FORWARD $ethdevin -m state --state ESTABLISHED,RELATED -j ACCEPT");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A FORWARD $ethdevin -j LOGDROPIN");
		}
	}
}
# end doportfilters
###############################################################################
# start dodisable
sub dodisable {
	open (OUT, ">/etc/csf/csf.disable");
	close OUT;
	unless ($config{GENERIC}) {
		sysopen (CONF, "/etc/chkserv.d/chkservd.conf", O_RDWR | O_CREAT) or &error(__LINE__,"Could not open /etc/chkserv.d/chkservd.conf: $!");
		flock (CONF, LOCK_EX) or &error(__LINE__,"Could not lock /etc/chkserv.d/chkservd.conf: $!");
		my @conf = <CONF>;
		chomp @conf;
		seek (CONF, 0, 0);
		truncate (CONF, 0);
		foreach my $line (@conf) {
			if ($line =~ /^lfd:/) {$line = "lfd:0"}
			print CONF $line."\n";
		}
		close (CONF) or &error(__LINE__,"Could not close /etc/conf: $!");
		&syscommand(__LINE__,"/scripts/restartsrv_chkservd");
	}
	if ($config{DIRECTADMIN}) {
		sysopen (CONF, "/usr/local/directadmin/data/admin/services.status", O_RDWR | O_CREAT) or &error(__LINE__,"Could not open /usr/local/directadmin/data/admin/services.status: $!");
		flock (CONF, LOCK_EX) or &error(__LINE__,"Could not lock /usr/local/directadmin/data/admin/services.status: $!");
		my @conf = <CONF>;
		chomp @conf;
		seek (CONF, 0, 0);
		truncate (CONF, 0);
		foreach my $line (@conf) {
			if ($line =~ /^lfd=/) {$line = "lfd=OFF"}
			print CONF $line."\n";
		}
		close (CONF) or &error(__LINE__,"Could not close /usr/local/directadmin/data/admin/services.status: $!");
	}
	&syscommand(__LINE__,"/etc/init.d/lfd stop");
	&dostop(0);

	print "csf and lfd have been disabled\n";
}
# end dodisable
###############################################################################
# start doenable
sub doenable {
	unless (-e "/etc/csf/csf.disable") {
		print "csf and lfd are not disabled!\n";
		exit;
	}
	unlink ("/etc/csf/csf.disable");
	&dostart;
	&syscommand(__LINE__,"/etc/init.d/lfd start");
	unless ($config{GENERIC}) {
		sysopen (CONF, "/etc/chkserv.d/chkservd.conf", O_RDWR | O_CREAT) or &error(__LINE__,"Could not open /etc/chkserv.d/chkservd.conf: $!");
		flock (CONF, LOCK_EX) or &error(__LINE__,"Could not lock /etc/chkserv.d/chkservd.conf: $!");
		my @conf = <CONF>;
		chomp @conf;
		seek (CONF, 0, 0);
		truncate (CONF, 0);
		foreach my $line (@conf) {
			if ($line =~ /^lfd:/) {$line = "lfd:1"}
			print CONF $line."\n";
		}
		close (CONF) or &error(__LINE__,"Could not close /etc/conf: $!");
		&syscommand(__LINE__,"/scripts/restartsrv_chkservd");
	}
	if ($config{DIRECTADMIN}) {
		sysopen (CONF, "/usr/local/directadmin/data/admin/services.status", O_RDWR | O_CREAT) or &error(__LINE__,"Could not open /usr/local/directadmin/data/admin/services.status: $!");
		flock (CONF, LOCK_EX) or &error(__LINE__,"Could not lock /usr/local/directadmin/data/admin/services.status: $!");
		my @conf = <CONF>;
		chomp @conf;
		seek (CONF, 0, 0);
		truncate (CONF, 0);
		foreach my $line (@conf) {
			if ($line =~ /^lfd=/) {$line = "lfd=ON"}
			print CONF $line."\n";
		}
		close (CONF) or &error(__LINE__,"Could not close /usr/local/directadmin/data/admin/services.status: $!");
	}

	print "csf and lfd have been enabled\n";
}
# end doenable
###############################################################################
# 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 crontab
sub crontab {
	my $act = shift;
	open (CRONTAB, "<","/etc/crontab") or die "Could not open /etc/crontab: $!";
	flock (CRONTAB, LOCK_SH) or die "Could not lock /etc/crontab: $!";
	my @crontab = <CRONTAB>;
	close (CRONTAB) or die "Could not close /etc/crontab: $!";
	chomp @crontab;
	my $hit = 0;
	my @newcrontab;
	foreach my $line (@crontab) {
		if ($line =~ /csf.pl -f/) {
			$hit = 1;
			if ($act eq "add") {
				push @newcrontab, $line;
			}
		} else {
			push @newcrontab, $line;
		}
	}
	if (($act eq "add") and !($hit)) {
		push @newcrontab, "*/$config{TESTING_INTERVAL} * * * * root /etc/csf/csf.pl -f > /dev/null 2>&1";
	}

	if (($act eq "remove") and !($hit)) {
		# don't do anything
	} else {
		sysopen (CRONTAB, "/etc/crontab", O_RDWR | O_CREAT) or die "Could not open /etc/crontab: $!";
		flock (CRONTAB, LOCK_EX) or die "Could not lock /etc/crontab: $!";
		seek (CRONTAB, 0, 0);
		truncate (CRONTAB, 0);
		foreach my $line (@newcrontab) {
			print CRONTAB $line."\n";
		}
		close (CRONTAB) or die "Could not close /etc/crontab: $!";
	}
}
# end crontab
###############################################################################
# start error
sub error {
	my $line = shift;
	my $error = shift;
	my $verbose;
	if ($config{DEBUG} >= 1) {$verbose = "--verbose"}
	system ("$config{IPTABLES} $verbose --policy INPUT ACCEPT");
	system ("$config{IPTABLES} $verbose --policy OUTPUT ACCEPT");
	system ("$config{IPTABLES} $verbose --policy FORWARD ACCEPT");
	system ("$config{IPTABLES} $verbose --flush");
	system ("$config{IPTABLES} $verbose --delete-chain");
	unless ($nonat) {system ("$config{IPTABLES} $verbose -t nat --flush")}

	if ($config{IPV6}) {
		system ("$config{IP6TABLES} $verbose --policy INPUT ACCEPT");
		system ("$config{IP6TABLES} $verbose --policy OUTPUT ACCEPT");
		system ("$config{IP6TABLES} $verbose --policy FORWARD ACCEPT");
		system ("$config{IP6TABLES} $verbose --flush");
		system ("$config{IP6TABLES} $verbose --delete-chain");
	}

	print "Error: $error, at line $line\n";
	open (OUT,">/etc/csf/csf.error");
	close (OUT);
	if ($config{TESTING}) {&crontab("remove")}
	exit;
}
# end error
###############################################################################
# start version
sub version {
	open (IN, "</etc/csf/version.txt") or die "Unable to open version.txt: $!";
	my $myv = <IN>;
	close (IN);
	chomp $myv;
	return $myv;
}
# end version
###############################################################################
# start getethdev
sub getethdev {
	unless (-e $config{IFCONFIG}) {&error(__LINE__,"$config{IFCONFIG} (ifconfig binary location) -v does not exist!")}
	my ($childin, $childout);
	my $pid = open3($childin, $childout, $childout, $config{IFCONFIG});
	my @ifconfig = <$childout>;
	waitpid ($pid, 0);
	chomp @ifconfig;
	my $iface;

	($config{ETH_DEVICE},undef) = split (/:/,$config{ETH_DEVICE},2);

	foreach my $line (@ifconfig) {
		if ($line =~ /^(\w+)/ ) {
			$ifaces{$1} = 1;
		}
		if ($line =~ /inet \w*:\s*(\S+)/) {
			my $ip = $1;
			if (&checkip($ip)) {$ips{$ip} = 1}
		}
		if ($config{IPV6} and $line =~ /inet6 \w*:\s*(\S+)/) {
			my $ip = $1;
			if (&checkip($ip)) {eval {$ipscidr6->add($ip)}}
		}
	}
	if ($config{ETH_DEVICE} eq "") {
		$ethdevin = "! -i lo";
		$ethdevout = "! -o lo";
		return;
	} else {
		$ethdevin = "-i $config{ETH_DEVICE}";
		$ethdevout = "-o $config{ETH_DEVICE}";
	}

	if ($config{ETH_DEVICE} =~ /\+$/) {return}

	unless ($ifaces{$config{ETH_DEVICE}}) {&error(__LINE__,"Main ethernet device [$config{ETH_DEVICE}] not listed in ifconfig")}
}
# end getethdev
###############################################################################
# start linefilter
sub linefilter {
	my $line = shift;
	my $ad = shift;
	my $chain = shift;
	my $delete = shift;
	my $pktin = "$accept";
	my $pktout = "$accept";
	my $inadd = "-I";
	if ($ad eq "deny") {
		$inadd = "-A";
		$pktin = $config{DROP};
		$pktout = $config{DROP};
		if ($config{DROP_IP_LOGGING}) {$pktin = "LOGDROPIN"}
		if ($config{DROP_IP_LOGGING}) {$pktout = "LOGDROPOUT"}
	}
	my $chainin = $chain."IN";
	my $chainout = $chain."OUT";

	$line =~ s/\n|\r//g;
	$line = lc $line;
	if ($line =~ /^\#/) {return}
	if ($line =~ /^Include/) {return}
	if ($line eq "") {return}

	my $checkip = checkip($line);
	my $iptables = $config{IPTABLES};
	my $ipv4 = 1;
	if ($checkip == 6) {
		$iptables = $config{IP6TABLES};
		$ipv4 = 0;
	}

	if ($checkip) {
		if ($chain) {
			&syscommand(__LINE__,"$iptables $verbose -A $chainin $ethdevin -s $line -j $pktin");
			&syscommand(__LINE__,"$iptables $verbose -A $chainout $ethdevout -d $line -j $pktout");
		} else {
			if ($delete) {
				&syscommand(__LINE__,"$iptables $verbose -D LOCALINPUT $ethdevin -s $line -j $pktin");
				&syscommand(__LINE__,"$iptables $verbose -D LOCALOUTPUT $ethdevout -d $line -j $pktout");
				if (($ad eq "deny") and ($ipv4 and $config{MESSENGER} and $config{MESSENGER_PERM})) {&domessenger($line,"D")}
			} else {
				&syscommand(__LINE__,"$iptables $verbose $inadd LOCALINPUT $ethdevin -s $line -j $pktin");
				&syscommand(__LINE__,"$iptables $verbose $inadd LOCALOUTPUT $ethdevout -d $line -j $pktout");
				if (($ad eq "deny") and ($ipv4 and $config{MESSENGER} and $config{MESSENGER_PERM})) {&domessenger($line,"A")}
			}
		}
	}
	elsif ($line =~ /\:|\|/) {
		if ($line !~ /\|/) {$line =~ s/\:/\|/g}
		my $sip;
		my $dip;
		my $sport;
		my $dport;
		my $protocol = "-p tcp";
		my $inout;
		my $from = 0;
		my $uid;
		my $gid;
		my $iptype;

		my @ll = split(/\|/,$line);
		if ($ll[0] eq "tcp") {
			$protocol = "-p tcp";
			$from = 1;
		}
		elsif ($ll[0] eq "udp") {
			$protocol = "-p udp";
			$from = 1;
		}
		elsif ($ll[0] eq "icmp") {
			$protocol = "-p icmp";
			$from = 1;
		}
		for (my $x = $from;$x < 2;$x++) {
			if (($ll[$x] eq "out")) {
				$inout = "out";
				$from = $x + 1;
				last;
			}
			elsif (($ll[$x] eq "in")) {
				$inout = "in";
				$from = $x + 1;
				last;
			}
		}
		for (my $x = $from;$x < 3;$x++) {
			if (($ll[$x] =~ /d=(.*)/)) {
				$dport = "--dport $1";
				$dport =~ s/_/:/g;
				if ($protocol eq "-p icmp") {$dport = "--icmp-type $1"}
				$from = $x + 1;
				last;
			}
			elsif (($ll[$x] =~ /s=(.*)/)) {
				$sport = "--sport $1";
				$sport =~ s/_/:/g;
				if ($protocol eq "-p icmp") {$sport = "--icmp-type $1"}
				$from = $x + 1;
				last;
			}
		}
		for (my $x = $from;$x < 4;$x++) {
			if (($ll[$x] =~ /d=(.*)/)) {
				my $ip = $1;
				my $status = &checkip($ip);
				if ($status) {
					$iptype = $status;
					$dip = "-d $1";
				}
				last;
			}
			elsif (($ll[$x] =~ /s=(.*)/)) {
				my $ip = $1;
				my $status = &checkip($ip);
				if ($status) {
					$iptype = $status;
					$sip = "-s $1";
				}
				last;
			}
		}
		for (my $x = $from;$x < 5;$x++) {
			if (($ll[$x] =~ /u=(.*)/)) {
				$uid = "--uid-owner $1";
				last;
			}
			elsif (($ll[$x] =~ /g=(.*)/)) {
				$gid = "--gid-owner $1";
				last;
			}
		}

		if ($uid or $gid) {
			if ($config{VPS} and $noowner) {
				print "Cannot use UID or GID rules [$ad: $line] on this VPS as the Monolithic kernel does not support the iptables module ipt_owner/xt_owner - rule skipped\n";
			} else {
				if ($chain) {
					&syscommand(__LINE__,"$iptables $verbose -A $chainout $ethdevout $protocol $dport -m owner $uid $gid -j $pktout");
				} else {
					if ($delete) {
						&syscommand(__LINE__,"$iptables $verbose -D LOCALOUTPUT $ethdevout $protocol $dport -m owner $uid $gid -j $pktout");
					} else {
						&syscommand(__LINE__,"$iptables $verbose $inadd LOCALOUTPUT $ethdevout $protocol $dport -m owner $uid $gid -j $pktout");
					}
				}
			}
		}
		elsif (($sip or $dip) and ($dport or $sport)) {
			my $iptables = $config{IPTABLES};
			if ($iptype == 6) {$iptables = $config{IP6TABLES}}
			if (($inout eq "") or ($inout eq "in")) {
				my $bport = $dport;
				$bport =~ s/--dport //o;
				my $bip = $sip;
				$bip =~ s/-s //o;
				if ($chain) {
					&syscommand(__LINE__,"$iptables $verbose -A $chainin $ethdevin $protocol $dip $sip $dport $sport -j $pktin");
				} else {
					if ($delete) {
						&syscommand(__LINE__,"$iptables $verbose -D LOCALINPUT $ethdevin $protocol $dip $sip $dport $sport -j $pktin");
						if ($messengerports{$bport} and ($ad eq "deny") and ($ipv4 and $config{MESSENGER} and $config{MESSENGER_PERM})) {&domessenger($bip,"D","$bport")}
					} else {
						&syscommand(__LINE__,"$iptables $verbose $inadd LOCALINPUT $ethdevin $protocol $dip $sip $dport $sport -j $pktin");
						if ($messengerports{$bport} and ($ad eq "deny") and ($ipv4 and $config{MESSENGER} and $config{MESSENGER_PERM})) {&domessenger($bip,"A","$bport")}
					}
				}
			}
			if ($inout eq "out") {
				if ($chain) {
					&syscommand(__LINE__,"$iptables $verbose -A $chainout $ethdevout $protocol $dip $sip $dport $sport -j $pktout");
				} else {
					if ($delete) {
						&syscommand(__LINE__,"$iptables $verbose -D LOCALOUTPUT $ethdevout $protocol $dip $sip $dport $sport -j $pktout");
					} else {
						&syscommand(__LINE__,"$iptables $verbose $inadd LOCALOUTPUT $ethdevout $protocol $dip $sip $dport $sport -j $pktout");
					}
				}
			}
		}
	}
}
# end linefilter
###############################################################################
# start autoupdates
sub autoupdates {
	my $hour = int (rand(24));
	my $minutes = int (rand(60));

	unless (-d "/etc/cron.d") {mkdir "/etc/cron.d"}
	open (OUT,">/etc/cron.d/csf_update") or &error(__LINE__,"Could not create /etc/cron.d/csf_update: $!");
	flock (OUT, LOCK_EX) or &error(__LINE__,"Could not lock /etc/cron.d/csf_update: $!");
	print OUT <<END;
SHELL=/bin/sh
$minutes $hour * * * root /etc/csf/csf.pl -u
END
	close (OUT);
}
# end autoupdates
###############################################################################
# start doupdate
sub doupdate {
	my $force = 0;
	my $actv = "";
	if ($input{command} eq "-uf") {
		$force = 1;
	} else {
		my ($status, $text) = &urlget("http://www.configserver.com/free/csf/version.txt");
		if ($status) {print "Oops: $text\n"; exit;}
		$actv = $text;
	}

	if ((($actv ne "") and ($actv =~ /^[\d\.]*$/)) or $force) {
		if (($actv > $version) or $force) {
			$| = 1;

			unless ($force) {print "Upgrading csf from v$version to $actv...\n"}
			if (-e "/usr/src/csf.tgz") {unlink ("/usr/src/csf.tgz") or die $!}
			print "Retrieving new csf package...\n";

			my ($status, $text) = &urlget("http://www.configserver.com/free/csf.tgz","/usr/src/csf.tgz");
			if ($status) {print "Oops: $text\n" ; exit;}

			if (! -z "/usr/src/csf/csf.tgz") {
				print "\nUnpacking new csf package...\n";
				system ("cd /usr/src ; tar -xzf csf.tgz ; cd csf ; sh install.sh");
				print "\nTidying up...\n";
				system ("rm -Rfv /usr/src/csf*");
				print "\nRestarting csf and lfd...\n";
				system ("/etc/csf/csf.pl -r ; /etc/init.d/lfd restart");
				print "\n...All done.\n\nChangelog: http://www.configserver.com/free/csf/changelog.txt\n";
			}
		} else {
			if (-t STDOUT) {print "csf is already at the latest version: v$version\n"}
		}
	} else {
		print "Unable to verify the latest version of csf at this time\n";
	}
}
# end doupdate
###############################################################################
# start docheck
sub docheck {
	my ($status, $text) = &urlget("http://www.configserver.com/free/csf/version.txt");
	if ($status) {print "Oops: $text\n"; exit;}

	my $actv = $text;
	my $up = 0;

	if (($actv ne "") and ($actv =~ /^[\d\.]*$/)) {
		if ($actv > $version) {
			print "A newer version of csf is available - Current:v$version New:v$actv\n";
		} else {
			print "csf is already at the latest version: v$version\n";
		}
	} else {
		print "Unable to verify the latest version of csf at this time\n";
	}
}
# end docheck
###############################################################################
# start dogrep
sub dogrep {
	my $ipmatch = $input{argument};
	my $mhit = 0;
	my $head = 0;
	my $oldchain = "INPUT";
	my ($chain,$rest);
	format GREP =
@<<<<<<<<<< @*
$chain, $rest
.
	$~ = "GREP";
	
	my $command = "$config{IPTABLES} -v -L -n --line-numbers";
	unless ($nonat) {$command .= " ; $config{IPTABLES} -v -t nat -L -n --line-numbers"}
	my ($childin, $childout);
	my $pid = open3($childin, $childout, $childout, $command);
	my @output = <$childout>;
	waitpid ($pid, 0);
	chomp @output;
	foreach my $line (@output) {
		if ($line =~ /^Chain\s([\w\_]*)\s/) {$chain = $1}
		if ($chain eq "acctboth") {next}
		if (!$head and ($line =~ /^num/)) {print "\nChain       $line\n"; $head = 1}

		if ($line !~ /\d+/) {next}
		my (undef,undef,undef,$action,undef,undef,undef,undef,$source,$destination,$options) = split(/\s+/,$line,11);
	
		my $hit = 0;
		if ($line =~ /\b$ipmatch\b/i) {
			$hit = 1;
		} else {
			if (($source =~ /\//) and ($source ne "0.0.0.0/0")) {
				if (&checkip($source)) {
					my $cidr = Net::CIDR::Lite->new;
					eval {$cidr->add($source)};
					if ($cidr->find($ipmatch)) {$hit = 1}
				}
			}
			if (!$hit and ($destination =~ /\//) and ($destination ne "0.0.0.0/0")) {
				if (&checkip($destination)) {
					my $cidr = Net::CIDR::Lite->new;
					eval {$cidr->add($destination)};
					if ($cidr->find($ipmatch)) {$hit = 1}
				}
			}
		}
		if ($hit) {
			$rest = $line;
			if ($oldchain ne $chain) {print "\n"}
			write;
			$oldchain = $chain;
			$mhit = 1;
		}
	}
	unless ($mhit) {
		print "No matches found for $ipmatch in iptables\n";
	}

	if ($config{IPV6}) {
		my $mhit = 0;
		my $head = 0;
		my $oldchain = "INPUT";
		print "\n\nip6tables:\n";
		my $command = "$config{IP6TABLES} -v -L -n --line-numbers";
		my ($childin, $childout);
		my $pid = open3($childin, $childout, $childout, $command);
		my @output = <$childout>;
		waitpid ($pid, 0);
		chomp @output;
		foreach my $line (@output) {
			if ($line =~ /^Chain\s([\w\_]*)\s/) {$chain = $1}
			if ($chain eq "acctboth") {next}
			if (!$head and ($line =~ /^num/)) {print "\nChain       $line\n"; $head = 1}

			if ($line !~ /\d+/) {next}
			my (undef,undef,undef,$action,undef,undef,undef,$source,$destination,$options) = split(/\s+/,$line,11);
		
			my $hit = 0;
			if ($line =~ /\b$ipmatch\b/i) {
				$hit = 1;
			} else {
				if (($source =~ /\//) and ($source ne "::/0")) {
					if (&checkip($source)) {
						my $cidr = Net::CIDR::Lite->new;
						eval {$cidr->add($source)};
						if ($cidr->find($ipmatch)) {$hit = 1}
					}
				}
				if (!$hit and ($destination =~ /\//) and ($destination ne "::/0")) {
					if (&checkip($destination)) {
						my $cidr = Net::CIDR::Lite->new;
						eval {$cidr->add($destination)};
						if ($cidr->find($ipmatch)) {$hit = 1}
					}
				}
			}
			if ($hit) {
				$rest = $line;
				if ($oldchain ne $chain) {print "\n"}
				write;
				$oldchain = $chain;
				$mhit = 1;
			}
		}
		unless ($mhit) {
			print "No matches found for $ipmatch in ip6tables\n";
		}
	}

	open (IN, "</etc/csf/csf.tempallow");
	flock (IN, LOCK_SH);
	my @tempallow = <IN>;
	close (IN);
	chomp @tempallow;
	foreach my $line (@tempallow) {
		my ($time,$ipd,$port,$inout,$timeout,$message) = split(/\|/,$line);
		if ($ipd eq $ipmatch) {
			print "\nTemporary Allows: IP:$ipd Port:$port Dir:$inout TTL:$timeout ($message)\n";
		}
		elsif ($ipd =~ /(.*\/\d+)/) {
			my $cidrhit = $1;
			if (&checkip($cidrhit)) {
				my $cidr = Net::CIDR::Lite->new;
				eval {$cidr->add($cidrhit)};
				if ($cidr->find($ipmatch)) {
					print "\nTemporary Allows: IP:$ipd Port:$port Dir:$inout TTL:$timeout ($message)\n";
				}
			}
		}
	}
	open (IN, "</etc/csf/csf.tempban");
	flock (IN, LOCK_SH);
	my @tempdeny = <IN>;
	close (IN);
	chomp @tempdeny;
	foreach my $line (@tempdeny) {
		my ($time,$ipd,$port,$inout,$timeout,$message) = split(/\|/,$line);
		if ($ipd eq $ipmatch) {
			print "\nTemporary Blocks: IP:$ipd Port:$port Dir:$inout TTL:$timeout ($message)\n";
		}
		elsif ($ipd =~ /(.*\/\d+)/) {
			my $cidrhit = $1;
			if (&checkip($cidrhit)) {
				my $cidr = Net::CIDR::Lite->new;
				eval {$cidr->add($cidrhit)};
				if ($cidr->find($ipmatch)) {
					print "\nTemporary Blocks: IP:$ipd Port:$port Dir:$inout TTL:$timeout ($message)\n";
				}
			}
		}
	}
	open (IN, "</etc/csf/csf.deny");
	flock (IN, LOCK_SH);
	my @deny = <IN>;
	close (IN);
	chomp @deny;
	foreach my $line (@deny) {
		if ($line =~ /^Include\s*(.*)$/) {
			my $incfile = $1;
			open (INCFILE, "<",$incfile) or &error(__LINE__,"Could not open $incfile: $!");
			flock (INCFILE, LOCK_SH) or &error(__LINE__,"Could not lock $incfile: $!");
			my @incdeny = <INCFILE>;
			close (INCFILE) or &error(__LINE__,"Could not close $incfile: $!");
			chomp @incdeny;
			push @deny,@incdeny;
		}
	}
	foreach my $line (@deny) {
		if ($line eq "") {next}
		if ($line =~ /^\s*\#|Include/) {next}
		my ($ipd,$commentd) = split (/\s/,$line,2);
		if ($ipd eq $ipmatch) {
			print "\ncsf.deny: $line\n";
		}
		elsif ($ipd =~ /(.*\/\d+)/) {
			my $cidrhit = $1;
			if (&checkip($cidrhit)) {
				my $cidr = Net::CIDR::Lite->new;
				eval {$cidr->add($cidrhit)};
				if ($cidr->find($ipmatch)) {
					print "\nPermanent Blocks (csf.deny): $line\n"
				}
			}
		}
	}
}
# end dogrep
###############################################################################
# start dotempban
sub dotempban {
	my ($ip,$deny,$port,$inout,$time,$timeout,$message);
	format TEMPBAN =
@<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @|||||| @<<<< @<<<<<<<<<<<<<<< @*
$deny, $ip,                                   $port,  $inout,$time,$message
.
	$~ = "TEMPBAN";
	if ((! -z "/etc/csf/csf.tempban") or (! -z "/etc/csf/csf.tempallow")) {
		print "\nA/D   IP address                               Port   Dir   Time To Live     Comment\n";
		if (! -z "/etc/csf/csf.tempban") {
			sysopen (IN, "/etc/csf/csf.tempban", O_RDWR);
			flock (IN, LOCK_SH);
			my @data = <IN>;
			chomp @data;
			close (IN);

			foreach my $line (@data) {
				if ($line eq "") {next}
				($time,$ip,$port,$inout,$timeout,$message) = split(/\|/,$line);
				$time = $timeout - (time - $time);
				if ($port eq "") {$port = "*"}
				if ($inout eq "") {$inout = " *"}
				if ($time < 1) {
					$time = "<1";
				} else {
					my $days = int($time/(24*60*60));
					my $hours = ($time/(60*60))%24;
					my $mins = ($time/60)%60;
					my $secs = $time%60;
					$days = $days < 1 ? '' : $days .'d ';
					$hours = $hours < 1 ? '' : $hours .'h ';
					$mins = $mins < 1 ? '' : $mins . 'm ';
					$time = $days . $hours . $mins . $secs . 's'; 
				}
				$deny = "DENY";
				write;
			}
		}
		if (! -z "/etc/csf/csf.tempallow") {
			sysopen (IN, "/etc/csf/csf.tempallow", O_RDWR);
			flock (IN, LOCK_SH);
			my @data = <IN>;
			chomp @data;
			close (IN);

			foreach my $line (@data) {
				if ($line eq "") {next}
				($time,$ip,$port,$inout,$timeout,$message) = split(/\|/,$line);
				$time = $timeout - (time - $time);
				if ($port eq "") {$port = "*"}
				if ($inout eq "") {$inout = " *"}
				if ($time < 1) {
					$time = "<1";
				} else {
					my $days = int($time/(24*60*60));
					my $hours = ($time/(60*60))%24;
					my $mins = ($time/60)%60;
					my $secs = $time%60;
					$days = $days < 1 ? '' : $days .'d ';
					$hours = $hours < 1 ? '' : $hours .'h ';
					$mins = $mins < 1 ? '' : $mins . 'm ';
					$time = $days . $hours . $mins . $secs . 's'; 
				}
				$deny = "ALLOW";
				write;
			}
		}
	} else {
		print "csf: There are no temporary IP entries\n";
	}
}
# end dotempban
###############################################################################
# start dotempdeny
sub dotempdeny {
	my ($ip,$timeout,$portdir) = split(/\s/,$input{argument},3);
	my $inout = "in";
	my $port = "";
	if ($timeout =~ /^(\d*)(m|h|d)/i) {
		my $secs = $1;
		my $dur = $2;
		if ($dur eq "m") {$timeout = $secs * 60}
		elsif ($dur eq "h") {$timeout = $secs * 60 * 60}
		elsif ($dur eq "d") {$timeout = $secs * 60 * 60 * 24}
		else {$timeout = $secs}
	}

	my $iptype = &checkip($ip);
	unless ($iptype) {
		print "csf: [$ip] is not a valid IP\n";
		return;
	}
	if ($timeout =~ /\D/) {
		print "csf: [$timeout] is not a time in seconds\n";
	}

	open (IN, "</etc/csf/csf.deny");
	flock (IN, LOCK_SH);
	my @deny = <IN>;
	close (IN);
	chomp @deny;
	foreach my $line (@deny) {
		if ($line =~ /^Include\s*(.*)$/) {
			my $incfile = $1;
			open (INCFILE, "<",$incfile) or &error(__LINE__,"Could not open $incfile: $!");
			flock (INCFILE, LOCK_SH) or &error(__LINE__,"Could not lock $incfile: $!");
			my @incdeny = <INCFILE>;
			close (INCFILE) or &error(__LINE__,"Could not close $incfile: $!");
			chomp @incdeny;
			push @deny,@incdeny;
		}
	}
	if (grep {$_ =~ /^$ip\b/} @deny) {
		print "csf: $ip is already permanently blocked\n";
		exit;
	}
	open (IN, "</etc/csf/csf.tempban");
	flock (IN, LOCK_SH);
	@deny = <IN>;
	close (IN);
	chomp @deny;
	if (grep {$_ =~ /\b$ip\|$port\|\b/} @deny) {
		print "csf: $ip is already temporarily blocked\n";
		exit;
	}

	if ($portdir =~ /\-d\s*out/i) {$inout = "out"}
	if ($portdir =~ /\-d\s*inout/i) {$inout = "inout"}
	if ($portdir =~ /\-p\s*(\d+)/i) {$port = $1}

	my $dropin = $config{DROP};
	my $dropout = $config{DROP};
	if ($config{DROP_IP_LOGGING}) {
		$dropin = "LOGDROPIN";
		$dropout = "LOGDROPOUT";
	}
	if ($timeout < 2) {$timeout = 3600}

	&getethdev;

	if ($inout =~ /in/) {
		if ($port) {
			foreach my $dport (split(/\,/,$port)) {
				if ($iptype == 6) {
					&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOCALINPUT $ethdevin -p tcp --dport $dport -s $ip -j $dropin");
				} else {
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOCALINPUT $ethdevin -p tcp --dport $dport -s $ip -j $dropin");
					if ($messengerports{$dport} and $config{MESSENGER} and $config{MESSENGER_TEMP}) {&domessenger($ip,"A",$dport)}
				}
			}
		} else {
			if ($iptype == 6) {
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOCALINPUT $ethdevin -s $ip -j $dropin");
			} else {
				&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOCALINPUT $ethdevin -s $ip -j $dropin");
				if ($config{MESSENGER} and $config{MESSENGER_TEMP}) {&domessenger($ip,"A")}
			}
		}
	}
	if ($inout =~ /out/) {
		if ($iptype == 6) {
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A LOCALOUTPUT $ethdevout -d $ip -j $dropout");
		} else {
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A LOCALOUTPUT $ethdevout -d $ip -j $dropout");
		}
	}

	sysopen (OUT, "/etc/csf/csf.tempban", O_WRONLY | O_APPEND | O_CREAT) or &error(__LINE__,"Error: Can't append out file: $!");
	flock (OUT, LOCK_EX);
	print OUT time."|$ip|$port|$inout|$timeout|Manually added\n";
	close (OUT);

	if ($port eq "") {$port = "*"}
	if ($inout eq "in") {$inout = "inbound"}
	if ($inout eq "out") {$inout = "outbound"}
	if ($inout eq "inout") {$inout = "in and outbound"}
	print "csf: $ip blocked on port $port for $timeout seconds $inout\n";
}
# end dotempdeny
###############################################################################
# start dotempallow
sub dotempallow {
	my ($ip,$timeout,$portdir) = split(/\s/,$input{argument},3);
	my $inout = "inout";
	my $port = "";
	if ($timeout =~ /^(\d*)(m|h|d)/i) {
		my $secs = $1;
		my $dur = $2;
		if ($dur eq "m") {$timeout = $secs * 60}
		elsif ($dur eq "h") {$timeout = $secs * 60 * 60}
		elsif ($dur eq "d") {$timeout = $secs * 60 * 60 * 24}
		else {$timeout = $secs}
	}

	my $iptype = &checkip($ip);
	unless ($iptype) {
		print "csf: [$ip] is not a valid IP\n";
		return;
	}
	if ($timeout =~ /\D/) {
		print "csf: [$timeout] is not a time in seconds\n";
	}

	open (IN, "</etc/csf/csf.allow");
	flock (IN, LOCK_SH);
	my @allow = <IN>;
	close (IN);
	chomp @allow;
	foreach my $line (@allow) {
		if ($line =~ /^Include\s*(.*)$/) {
			my $incfile = $1;
			open (INCFILE, "<",$incfile) or &error(__LINE__,"Could not open $incfile: $!");
			flock (INCFILE, LOCK_SH) or &error(__LINE__,"Could not lock $incfile: $!");
			my @incallow = <INCFILE>;
			close (INCFILE) or &error(__LINE__,"Could not close $incfile: $!");
			chomp @incallow;
			push @allow,@incallow;
		}
	}
	if (grep {$_ =~ /^$ip\b/} @allow) {
		print "csf: $ip is already permanently allowed\n";
		exit;
	}
	open (IN, "</etc/csf/csf.tempallow");
	flock (IN, LOCK_SH);
	@allow = <IN>;
	close (IN);
	chomp @allow;
	if (grep {$_ =~ /\b$ip\|$port\|\b/} @allow) {
		print "csf: $ip is already temporarily allowed\n";
		exit;
	}

	if ($portdir =~ /\-d\s*in/i) {$inout = "in"}
	if ($portdir =~ /\-d\s*out/i) {$inout = "out"}
	if ($portdir =~ /\-d\s*inout/i) {$inout = "inout"}
	if ($portdir =~ /\-p\s*(\d+)/i) {$port = $1}

	if ($timeout < 2) {$timeout = 3600}

	&getethdev;

	if ($inout =~ /in/) {
		if ($port) {
			foreach my $dport (split(/\,/,$port)) {
				if ($iptype == 6) {
					&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I LOCALINPUT $ethdevin -p tcp --dport $dport -s $ip -j $accept");
				} else {
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -I LOCALINPUT $ethdevin -p tcp --dport $dport -s $ip -j $accept");
				}
			}
		} else {
			if ($iptype == 6) {
				&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I LOCALINPUT $ethdevin -s $ip -j $accept");
			} else {
				&syscommand(__LINE__,"$config{IPTABLES} $verbose -I LOCALINPUT $ethdevin -s $ip -j $accept");
			}
		}
	}
	if ($inout =~ /out/) {
		if ($iptype == 6) {
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I LOCALOUTPUT $ethdevout -d $ip -j $accept");
		} else {
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -I LOCALOUTPUT $ethdevout -d $ip -j $accept");
		}
	}

	sysopen (OUT, "/etc/csf/csf.tempallow", O_WRONLY | O_APPEND | O_CREAT) or &error(__LINE__,"Error: Can't append out file: $!");
	flock (OUT, LOCK_EX);
	print OUT time."|$ip|$port|$inout|$timeout|Manually added\n";
	close (OUT);

	if ($port eq "") {$port = "*"}
	if ($inout eq "in") {$inout = "inbound"}
	if ($inout eq "out") {$inout = "outbound"}
	if ($inout eq "inout") {$inout = "in and outbound"}
	print "csf: $ip allowed on port $port for $timeout seconds $inout\n";
}
# end dotempallow
###############################################################################
# start dotemprm
sub dotemprm {
	my $ip = $input{argument};

	if ($ip eq "") {
		print "csf: No IP specified\n";
		return;
	}

	my $iptype = &checkip($ip);
	unless ($iptype) {
		print "csf: [$ip] is not a valid IP\n";
		return;
	}
	&getethdev;
	if (! -z "/etc/csf/csf.tempban") {
		my $unblock = 0;
		sysopen (TEMPBAN, "/etc/csf/csf.tempban", O_RDWR | O_CREAT);
		flock (TEMPBAN, LOCK_EX);
		my @data = <TEMPBAN>;
		chomp @data;

		my @newdata;
		foreach my $line (@data) {
			my ($time,$thisip,$port,$inout,$timeout,$message) = split(/\|/,$line);
			if ($thisip eq $ip) {
				my $dropin = $config{DROP};
				my $dropout = $config{DROP};
				if ($config{DROP_IP_LOGGING}) {$dropin = "LOGDROPIN"}
				if ($config{DROP_IP_LOGGING}) {$dropout = "LOGDROPOUT"}

				if ($inout =~ /in/) {
					if ($port) {
						foreach my $dport (split(/\,/,$port)) {
							if ($iptype == 6) {
								&syscommand(__LINE__,"$config{IP6TABLES} $verbose -D LOCALINPUT $ethdevin -p tcp --dport $dport -s $ip -j $dropin");
							} else {
								&syscommand(__LINE__,"$config{IPTABLES} $verbose -D LOCALINPUT $ethdevin -p tcp --dport $dport -s $ip -j $dropin");
								if ($messengerports{$dport} and $config{MESSENGER} and $config{MESSENGER_TEMP}) {&domessenger($ip,"D",$dport)}
							}
						}
					} else {
						if ($iptype == 6) {
							&syscommand(__LINE__,"$config{IP6TABLES} $verbose -D LOCALINPUT $ethdevin -s $ip -j $dropin");
						} else {
							&syscommand(__LINE__,"$config{IPTABLES} $verbose -D LOCALINPUT $ethdevin -s $ip -j $dropin");
							if ($config{MESSENGER} and $config{MESSENGER_TEMP}) {&domessenger($ip,"D")}
						}
					}
				}
				if ($inout =~ /out/) {
					if ($iptype == 6) {
						&syscommand(__LINE__,"$config{IP6TABLES} $verbose -D LOCALOUTPUT $ethdevout -d $ip -j $dropout");
					} else {
						&syscommand(__LINE__,"$config{IPTABLES} $verbose -D LOCALOUTPUT $ethdevout -d $ip -j $dropout");
					}
				}
				print "csf: $ip temporary block removed\n";
				$unblock = 1;
			} else {
				push @newdata, $line;
			}
		}
		seek (TEMPBAN, 0, 0);
		truncate (TEMPBAN, 0);
		foreach my $line (@newdata) {print TEMPBAN "$line\n"}
		close (TEMPBAN);
		unless ($unblock) {
			print "csf: $ip not found in temporary bans\n";
		}
	} else {
		print "csf: There are no temporary IP bans\n";
	}
	if (! -z "/etc/csf/csf.tempallow") {
		my $unblock = 0;
		sysopen (TEMPALLOW, "/etc/csf/csf.tempallow", O_RDWR | O_CREAT);
		flock (TEMPALLOW, LOCK_EX);
		my @data = <TEMPALLOW>;
		chomp @data;

		my @newdata;
		foreach my $line (@data) {
			my ($time,$thisip,$port,$inout,$timeout,$message) = split(/\|/,$line);
			if ($thisip eq $ip) {
				if ($inout =~ /in/) {
					if ($port) {
						foreach my $dport (split(/\,/,$port)) {
							if ($iptype == 6) {
								&syscommand(__LINE__,"$config{IP6TABLES} $verbose -D LOCALINPUT $ethdevin -p tcp --dport $dport -s $ip -j $accept");
							} else {
								&syscommand(__LINE__,"$config{IPTABLES} $verbose -D LOCALINPUT $ethdevin -p tcp --dport $dport -s $ip -j $accept");
							}
						}
					} else {
						if ($iptype == 6) {
							&syscommand(__LINE__,"$config{IP6TABLES} $verbose -D LOCALINPUT $ethdevin -s $ip -j $accept");
						} else {
							&syscommand(__LINE__,"$config{IPTABLES} $verbose -D LOCALINPUT $ethdevin -s $ip -j $accept");
						}
					}
				}
				if ($inout =~ /out/) {
					if ($iptype == 6) {
						&syscommand(__LINE__,"$config{IP6TABLES} $verbose -D LOCALOUTPUT $ethdevout -d $ip -j $accept");
					} else {
						&syscommand(__LINE__,"$config{IPTABLES} $verbose -D LOCALOUTPUT $ethdevout -d $ip -j $accept");
					}
				}
				print "csf: $ip temporary allow removed\n";
				$unblock = 1;
			} else {
				push @newdata, $line;
			}
		}
		seek (TEMPALLOW, 0, 0);
		truncate (TEMPALLOW, 0);
		foreach my $line (@newdata) {print TEMPALLOW "$line\n"}
		close (TEMPALLOW);
		unless ($unblock) {
			print "csf: $ip not found in temporary allows\n";
		}
	} else {
		print "csf: There are no temporary IP allows\n";
	}
}
# end dotemprm
###############################################################################
# start dotempf
sub dotempf {
	&getethdev;
	if (! -z "/etc/csf/csf.tempban") {
		sysopen (TEMPBAN, "/etc/csf/csf.tempban", O_RDWR | O_CREAT);
		flock (TEMPBAN, LOCK_EX);
		my @data = <TEMPBAN>;
		chomp @data;

		foreach my $line (@data) {
			if ($line eq "") {next}
			my ($time,$ip,$port,$inout,$timeout,$message) = split(/\|/,$line);
			my $iptype = &checkip($ip);
			my $dropin = $config{DROP};
			my $dropout = $config{DROP};
			if ($config{DROP_IP_LOGGING}) {$dropin = "LOGDROPIN"}
			if ($config{DROP_IP_LOGGING}) {$dropout = "LOGDROPOUT"}

			if ($inout =~ /in/) {
				if ($port) {
					foreach my $dport (split(/\,/,$port)) {
						if ($iptype == 6) {
							&syscommand(__LINE__,"$config{IP6TABLES} $verbose -D LOCALINPUT $ethdevin -p tcp --dport $dport -s $ip -j $dropin");
						} else {
							&syscommand(__LINE__,"$config{IPTABLES} $verbose -D LOCALINPUT $ethdevin -p tcp --dport $dport -s $ip -j $dropin");
							if ($messengerports{$dport} and $config{MESSENGER} and $config{MESSENGER_TEMP}) {&domessenger($ip,"D",$dport)}
						}
					}
				} else {
					if ($iptype == 6) {
						&syscommand(__LINE__,"$config{IP6TABLES} $verbose -D LOCALINPUT $ethdevin -s $ip -j $dropin");
					} else {
						&syscommand(__LINE__,"$config{IPTABLES} $verbose -D LOCALINPUT $ethdevin -s $ip -j $dropin");
						if ($config{MESSENGER} and $config{MESSENGER_TEMP}) {&domessenger($ip,"D")}
					}
				}
			}
			if ($inout =~ /out/) {
				if ($iptype == 6) {
					&syscommand(__LINE__,"$config{IP6TABLES} $verbose -D LOCALOUTPUT $ethdevout -d $ip -j $dropout");
				} else {
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -D LOCALOUTPUT $ethdevout -d $ip -j $dropout");
				}
			}
			print "csf: $ip temporary block removed\n";
		}
		seek (TEMPBAN, 0, 0);
		truncate (TEMPBAN, 0);
		close (TEMPBAN);
	} else {
		print "csf: There are no temporary IP bans\n";
	}
	if (! -z "/etc/csf/csf.tempallow") {
		sysopen (TEMPALLOW, "/etc/csf/csf.tempallow", O_RDWR | O_CREAT);
		flock (TEMPALLOW, LOCK_EX);
		my @data = <TEMPALLOW>;
		chomp @data;

		foreach my $line (@data) {
			if ($line eq "") {next}
			my ($time,$ip,$port,$inout,$timeout,$message) = split(/\|/,$line);
			my $iptype = &checkip($ip);
			if ($inout =~ /in/) {
				if ($port) {
					foreach my $dport (split(/\,/,$port)) {
						if ($iptype == 6) {
							&syscommand(__LINE__,"$config{IP6TABLES} $verbose -D LOCALINPUT $ethdevin -p tcp --dport $dport -s $ip -j $accept");
						} else {
							&syscommand(__LINE__,"$config{IPTABLES} $verbose -D LOCALINPUT $ethdevin -p tcp --dport $dport -s $ip -j $accept");
						}
					}
				} else {
					if ($iptype == 6) {
						&syscommand(__LINE__,"$config{IP6TABLES} $verbose -D LOCALINPUT $ethdevin -s $ip -j $accept");
					} else {
						&syscommand(__LINE__,"$config{IPTABLES} $verbose -D LOCALINPUT $ethdevin -s $ip -j $accept");
					}
				}
			}
			if ($inout =~ /out/) {
				if ($iptype == 6) {
					&syscommand(__LINE__,"$config{IP6TABLES} $verbose -D LOCALOUTPUT $ethdevout -d $ip -j $accept");
				} else {
					&syscommand(__LINE__,"$config{IPTABLES} $verbose -D LOCALOUTPUT $ethdevout -d $ip -j $accept");
				}
			}
			print "csf: $ip temporary allow removed\n";
		}
		seek (TEMPALLOW, 0, 0);
		truncate (TEMPALLOW, 0);
		close (TEMPALLOW);
	} else {
		print "csf: There are no temporary IP allows\n";
	}
}
# end dotempf
###############################################################################
# start dowatch
sub dowatch {
	my $ip = $input{argument};

	unless ($config{WATCH_MODE}) {print "WARNING: For best results you should enable WATCH_MODE then restart csf and then lfd\n"}

	if ($ip eq "") {
		print "csf: No IP specified\n";
		return;
	}

	my $checkip = &checkip($ip);
	unless ($checkip) {
		print "csf: [$ip] is not a valid IP\n";
		return;
	}

	if ($checkip == 4) {
		my @chains = ("INPUT","LOCALINPUT","LOGDROPIN");
		if ($config{LF_DSHIELD}) {push @chains,"DSHIELD"}
		if ($config{LF_SPAMHAUS}) {push @chains,"SPAMHAUS"}
		if ($config{LF_TOR}) {push @chains,"TOR"}
		if ($config{LF_BOGON}) {push @chains,"BOGON"}
		if ($config{PACKET_FILTER}) {push @chains,"INVALID","INVDROP"}
		if ($config{CC_ALLOW_FILTER}) {push @chains,"CC_ALLOWF"}
		if ($config{CC_ALLOW}) {push @chains,"CC_ALLOW"}
		if ($config{CC_DENY}) {push @chains,"CC_DENY"}
		if ($config{GLOBAL_ALLOW}) {push @chains,"GALLOWIN"}
		if ($config{GLOBAL_DENY}) {push @chains,"GDENYIN"}
		if ($config{DYNDNS}) {push @chains,"ALLOWDYNIN"}
		if ($config{GLOBAL_DYNDNS}) {push @chains,"GDYNIN"}
		if ($config{SYNFLOOD}) {push @chains,"SYNFLOOD"}
		if ($config{PORTFLOOD}) {push @chains,"PORTFLOOD"}
		if ($config{WATCH_MODE}) {push @chains,"LOGACCEPT"}

		foreach my $chain (@chains) {
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -I $chain -s $ip -p tcp --syn -j LOG --log-prefix 'Firewall: I:$chain '");
			&syscommand(__LINE__,"$config{IPTABLES} $verbose -A $chain -s $ip -p tcp --syn -j LOG --log-prefix 'Firewall: O:$chain '");
		}
	} else {
		my @chains = ("INPUT","LOCALINPUT","LOGDROPIN");
		if ($config{PACKET_FILTER} and $config{IPV6_SPI}) {push @chains,"INVALID","INVDROP"}
		if ($config{GLOBAL_ALLOW}) {push @chains,"GALLOWIN"}
		if ($config{GLOBAL_DENY}) {push @chains,"GDENYIN"}
		if ($config{WATCH_MODE}) {push @chains,"LOGACCEPT"}

		foreach my $chain (@chains) {
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -I $chain -s $ip -p tcp --syn -j LOG --log-prefix 'Firewall: I:$chain '");
			&syscommand(__LINE__,"$config{IP6TABLES} $verbose -A $chain -s $ip -p tcp --syn -j LOG --log-prefix 'Firewall: O:$chain '");
		}
	}
	print "csf: Watching $ip\n";
}
# end dowatch
###############################################################################
# start dologrun
sub dologrun {
	if ($config{LOGSCANNER}) {
		open (OUT, ">", "/etc/csf/csf.logrun") or &error(__LINE__,"Could not create /etc/csf/csf.logrun: $!");
		close (OUT);
	} else {
		print "Option LOGSCANNER needs to be enabled in csf.conf for this feature\n";
	}
}
# end dologrun
###############################################################################
# start domessenger
sub domessenger {
	my $ip = shift;
	my $delete = shift;
	my $ports = shift;
	if ($ports eq "") {$ports = "$config{MESSENGER_HTML_IN},$config{MESSENGER_TEXT_IN}"}

	my $del = "-A";
	if ($delete eq "D") {$del = "-D"}

	my %textin;
	my %htmlin;
	foreach my $port (split(/\,/,$config{MESSENGER_HTML_IN})) {$htmlin{$port} = 1}
	foreach my $port (split(/\,/,$config{MESSENGER_TEXT_IN})) {$textin{$port} = 1}

	my $textports;
	my $htmlports;
	foreach my $port (split(/\,/,$ports)) {
		if ($htmlin{$port}) {
			if ($htmlports eq "") {$htmlports = "$port"} else {$htmlports .= ",$port"}
		}
		if ($textin{$port}) {
			if ($textports eq "") {$textports = "$port"} else {$textports .= ",$port"}
		}
	}
	if ($htmlports ne "") {
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -t nat $del PREROUTING $ethdevin -p tcp -s $ip -m multiport --dports $htmlports -j REDIRECT --to-ports $config{MESSENGER_HTML}");
	}
	if ($textports ne "") {
		&syscommand(__LINE__,"$config{IPTABLES} $verbose -t nat $del PREROUTING $ethdevin -p tcp -s $ip -m multiport --dports $textports -j REDIRECT --to-ports $config{MESSENGER_TEXT}");
	}
}
# end domessenger
###############################################################################
# start domail
sub domail {
	my ($childin, $childout);
	my $pid = open3($childin, $childout, $childout, "/usr/bin/perl /etc/csf/servercheck.pm");
	my @output = <$childout>;
	waitpid ($pid, 0);

	if ($input{argument}) {
		my $hostname;
		if (-e "/proc/sys/kernel/hostname") {
			open (IN, "</proc/sys/kernel/hostname");
			$hostname = <IN>;
			chomp $hostname;
			close (IN);
		} else {
			$hostname = "unknown";
		}
		my $from = $config{LF_ALERT_FROM};
		if ($from eq "") {$from = "root"}
		open (MAIL, "|$config{SENDMAIL} -f $from -t");
		print MAIL <<EOM;
From: $from
To: $input{argument}
Subject: Server Check on $hostname
MIME-Version: 1.0
Content-Type: text/html

EOM
		print MAIL @output;
		close (MAIL);
	} else {
		print @output;
		print "\n";
	}
}
# end domail
###############################################################################
# start loadmodule
sub loadmodule {
	my $module = shift;
	my @output;

	eval {
		local $SIG{__DIE__} = undef;
		local $SIG{'ALRM'} = sub {die};
		alarm(5);
		my ($childin, $childout);
		my $pid = open3($childin, $childout, $childout, "$config{MODPROBE} $module");
		@output = <$childout>;
		waitpid ($pid, 0);
		alarm(0);
	};
	alarm(0);

	return @output;
}
# end loadmodule
###############################################################################
# start syscommand
sub syscommand {
	my $line = shift;
	my $command = shift;
	my $force = shift;
	my $status = 0;

	if ($config{VPS}) {$status = &checkvps}

	if ($status) {
		&error($line,$status);
	} else {
		if ($config{DEBUG} >= 1) {print "debug[$line]: Command:$command\n";}
		my ($childin, $childout);
		my $pid = open3($childin, $childout, $childout, $command);
		my @output = <$childout>;
		waitpid ($pid, 0);
		foreach my $line (@output) {
			if ($line =~ /^Using intrapositioned negation/) {next}
			print $line;
		}
		if ($output[0] =~ /^iptables|Bad/ and ($config{TESTING} or $force)) {
			if ($output[0] =~ /iptables: No chain\/target\/match by that name/) {
				&error($line,"iptables command [$command] failed, you appear to be missing a required iptables module")
			} else {
				&error($line,"iptables command [$command] failed");
			}
		}
		if ($output[0] =~ /^ip6tables|Bad/ and ($config{TESTING} or $force)) {
			if ($output[0] =~ /ip6tables: No chain\/target\/match by that name/) {
				&error($line,"ip6tables command [$command] failed, you appear to be missing a required ip6tables module")
			} else {
				&error($line,"ip6tables command [$command] failed");
			}
		}
	}
}
# end syscommand
###############################################################################
# start checkvps
sub checkvps {
	if (-e "/proc/user_beancounters" and !(-e "/proc/vz/version")) {
		open (INVPS, "</proc/user_beancounters");
		my @data = <INVPS>;
		close (INVPS);
		chomp @data;

		foreach my $line (@data) {
			if ($line =~ /^\s*numiptent\s+(\d*)\s+(\d*)\s+(\d*)\s+(\d*)/) {
				if ($1 > $4 - 10) {return "The VPS iptables rule limit (numiptent) is too low ($1/$4) - stopping firewall to prevent iptables blocking all connections"}
			}
		}
	}
	return 0;
}
# end checkvps
###############################################################################
# start sanity
sub sanity {
	my $sanity_item = shift;
	my $sanity_value = shift;

	$sanity_item =~ s/\s//g;
	$sanity_value =~ s/\s//g;
	unless (defined $sanity{TESTING}) {
		open (IN, "<", "/etc/csf/sanity.txt");
		flock (IN, LOCK_SH);
		my @data = <IN>;
		close (IN);
		chomp @data;
		foreach my $line (@data) {
			my ($name,$value,$def) = split(/\=/,$line);
			$sanity{$name} = $value;
			$sanitydefault{$name} = $def;
		}
	}

	my $insane = 0;
	if (defined $sanity{$sanity_item}) {
		$insane = 1;
		foreach my $check (split(/\|/,$sanity{$sanity_item})) {
			if ($check =~ /-/) {
				my ($from,$to) = split(/\-/,$check);
				if (($sanity_value >= $from) and ($sanity_value <= $to)) {$insane = 0}

			} else {
				if ($sanity_value eq $check) {$insane = 0}
			}
		}
		$sanity{$sanity_item} =~ s/\|/ or /g;
	}
	return ($insane,$sanity{$sanity_item},$sanitydefault{$sanity_item});
}
# end sanity
###############################################################################

###############################################################################
# start urlget
sub urlget {
	my $url = shift;
	my $file = shift;
	my $status = 0;
	my $timeout = 1200;

	use LWP::UserAgent;
	my $ua = LWP::UserAgent->new;
	$ua->timeout(30);
	my $req = HTTP::Request->new(GET => $url);
	my $res;
	my $text;

	($status, $text) = eval {
		local $SIG{__DIE__} = undef;
		local $SIG{'ALRM'} = sub {die "Download timeout after $timeout seconds"};
		alarm($timeout);
		if ($file) {
			$|=1;
			my $expected_length;
			my $bytes_received = 0;
			my $per = 0;
			my $oldper = 0;
			open (OUT, ">$file\.tmp") or return (1, "Unable to open $file\.tmp: $!");
			binmode (OUT);
			print "...0\%\n";
			$res = $ua->request($req,
				sub {
				my($chunk, $res) = @_;
				$bytes_received += length($chunk);
				unless (defined $expected_length) {$expected_length = $res->content_length || 0}
				if ($expected_length) {
					my $per = int(100 * $bytes_received / $expected_length);
					if ((int($per / 5) == $per / 5) and ($per != $oldper)) {
						print "...$per\%\n";
						$oldper = $per;
					}
				} else {
					print ".";
				}
				print OUT $chunk;
			});
			close (OUT);
			print "\n";
		} else {
			$res = $ua->request($req);
		}
		alarm(0);
		if ($res->is_success) {
			if ($file) {
				rename ("$file\.tmp","$file") or return (1, "Unable to rename $file\.tmp to $file: $!");
				return (0, $file);
			} else {
				return (0, $res->content);
			}
		} else {
			return (1, "Unable to download: ".$res->message);
		}
	};
	alarm(0);
	if ($@) {return (1, $@)}
	return ($status,$text);
}
# end urlget
###############################################################################
