Page 1 of 1

Add support for -port -direction to: -a, --add ip & -cta, --add ip

Posted: 03 Oct 2019, 04:55
by whattheserver
Currently, it is a pain to add custom port allow rules as they have to be crafted by hand.

I just noticed that the -ta, --tempallow option has this functionality. but the main -a add ip does not.

-ta, --tempallow ip ttl [-p port] [-d direction] [comment]
Add an IP to the temp IP allow list (default:inout)

root@ols:~# csf -a 1.2.3.4 -p 1812 Allow Radius
iptables: No chain/target/match by that name.
ACCEPT tcp opt -- in !lo out * 1.2.3.4 -> 0.0.0.0/0 tcp dpt:1812
iptables: No chain/target/match by that name.
ACCEPT tcp opt -- in * out !lo 0.0.0.0/0 -> 1.2.3.4 tcp dpt:1812
csf: 1.2.3.4 allowed on port 1812 for 3600 seconds in and outbound
root@ols:~#

root@ols:/etc/csf# csf -t

A/D IP address Port Dir Time To Live Comment
ALLOW 1.2.3.4 1812 inout 46m 8s Allow Radius
root@ols:/etc/csf#


Whereas the -a does not support this and add just general allow.

root@ols:/etc/csf# csf -a 1.2.3.4 -p 1812 Allow Radius
Adding 1.2.3.4 to csf.allow and iptables ACCEPT...
iptables: No chain/target/match by that name.
ACCEPT all opt -- in !lo out * 1.2.3.4 -> 0.0.0.0/0
iptables: No chain/target/match by that name.
ACCEPT all opt -- in * out !lo 0.0.0.0/0 -> 1.2.3.4
root@ols:/etc/csf#

So to add permanent rules still requires a lot more confusing advanced rules to configure and add manually to the csf.allow file.
echo 'tcp|in,out|d=1812|d=1.2.3.4' >> /etc/csf/csf.allow && csf -r;

Seems like the code already exists and could be added to the other -a and cluster -ca options so permanent rules can be easily added via the CLI without a restart of CSF and manual file editing.

It would be nice to be able to make custom rules via the CLI with same capabilities as the manual rule editing.


allow

Code: Select all

###############################################################################
# start doadd
sub doadd {
	my ($ip,$comment) = split (/\s/,$input{argument},2);
	my $checkip = checkip(\$ip);

	&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 == 6 and !$config{IPV6}) {
		print "add failed: [$ip] is valid IPv6 but IPV6 is not enabled in csf.conf\n";
		return;
	}

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

	my $hit;
	my @deny = slurp("/etc/csf/csf.deny");
	foreach my $line (@deny) {
        $line =~ s/$cleanreg//g;
		if ($line eq "") {next}
		if ($line =~ /^\s*\#|Include/) {next}
		my ($ipd,$commentd) = split (/\s/,$line,2);
		checkip(\$ipd);
		if ($ipd eq $ip) {
			$hit = 1;
			last;
		}
	}
	if ($hit) {
		print "Removing $ip from csf.deny...\n";
		$input{argument} = $ip;
		&dokill;
	}

	my $allowmatches;
	my @allow = slurp("/etc/csf/csf.allow");
	foreach my $line (@allow) {
		if ($line =~ /^Include\s*(.*)$/) {
			my @incfile = slurp($1);
			push @allow,@incfile;
		}
	}
	foreach my $line (@allow) {
        $line =~ s/$cleanreg//g;
		if ($line eq "") {next}
		if ($line =~ /^\s*\#|Include/) {next}
		my ($ipd,$commentd) = split (/\s/,$line,2);
		checkip(\$ipd);
		if ($ipd eq $ip) {
			$allowmatches = 1;
			last;
		}
	}

	my $ipstring = quotemeta($ip);
	sysopen (my $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 $text = join("", <$ALLOW>);
	@allow = split(/$slurpreg/,$text);
	chomp @allow;
	unless ($allowmatches) {
		if ($comment eq "") {$comment = "Manually allowed: ".iplookup($ip)}
		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: $!");
	return;
}
# end doadd
###############################################################################
vs tempallow

Code: Select all

###############################################################################
# start dotempallow
sub dotempallow {
	my $cftemp = shift;
	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);
	if ($iptype == 6 and !$config{IPV6}) {
		print "failed: [$ip] is valid IPv6 but IPV6 is not enabled in csf.conf\n";
	}

	unless ($iptype) {
		print "csf: [$ip] is not a valid IP\n";
		return;
	}
	if ($timeout =~ /\D/) {
		$portdir = join(" ",$timeout,$portdir);
		$timeout = 0;
	}

	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*([\w\,\*\;]+)/) {$port = $1}
	my $comment = $portdir;
	$comment =~ s/\-d\s*out//ig;
	$comment =~ s/\-d\s*inout//ig;
	$comment =~ s/\-d\s*in//ig;
	$comment =~ s/\-p\s*[\w\,\*\;]+//ig;
	$comment =~ s/^\s*|\s*$//g;
	if ($comment eq "") {$comment = "Manually added: ".iplookup($ip)}

	my @allow = slurp("/etc/csf/csf.allow");
	foreach my $line (@allow) {
		if ($line =~ /^Include\s*(.*)$/) {
			my @incfile = slurp($1);
			push @allow,@incfile;
		}
	}
	if (grep {$_ =~ /^$ip\b/} @allow) {
		print "csf: $ip is already permanently allowed\n";
		exit 0;
	}
	open (my $IN, "<", "/var/lib/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 0;
	}

	if ($timeout < 2) {$timeout = 3600}
	if ($port =~ /\*/) {$port = ""}

	&getethdev;

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

	if ($config{CF_ENABLE} and $cftemp) {$comment .= " (CF_ENABLE)"}

	sysopen (my $OUT, "/var/lib/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|$comment\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";
	return;
}
# end dotempallow
###############################################################################

Re: Add support for -port -direction to: -a, --add ip & -cta, --add ip

Posted: 03 Oct 2019, 05:40
by BallyBasic79
Nice observation!

Re: Add support for -port -direction to: -a, --add ip & -cta, --add ip

Posted: 03 Oct 2019, 21:31
by whattheserver
Thanks. I'm looking into adding better support for custom port management via CSF into Cyberpanel's CSF management page.

This can be done with firewalld
sudo firewall-cmd --permanent --zone=public --add-rich-rule='" + ruleFamily + " " + sourceAddress + " " + ruleProtocol + " " + rulePort + " " + "accept'"

Having that functionality in CSF -a would make integration a cinch and less error-prone

See the Cyberpanel UI for CSF is lacking a lot of CSF's features:
https://github.com/usmannasir/cyberpane ... cal/csf.py

Compared to firewalld:
https://github.com/usmannasir/cyberpane ... ilities.py

I much prefer CSF over firewalld and looking to learn python more and help.

I have a handy rule generator in PHP for this already.
https://wizardassistant.app/csf