summaryrefslogtreecommitdiff
path: root/lib/Vyatta/IpTables/Mgr.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Vyatta/IpTables/Mgr.pm')
-rw-r--r--lib/Vyatta/IpTables/Mgr.pm341
1 files changed, 341 insertions, 0 deletions
diff --git a/lib/Vyatta/IpTables/Mgr.pm b/lib/Vyatta/IpTables/Mgr.pm
new file mode 100644
index 0000000..39a03f1
--- /dev/null
+++ b/lib/Vyatta/IpTables/Mgr.pm
@@ -0,0 +1,341 @@
+#
+# Module: Vyatta::IpTables::Mgr.pm
+#
+# **** License ****
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# This code was originally developed by Vyatta, Inc.
+# Portions created by Vyatta are Copyright (C) 2010 Vyatta, Inc.
+# All Rights Reserved.
+#
+# Author: Stig Thormodsrud
+# Date: June 2010
+# Description: common iptables routines
+#
+# **** End License ****
+#
+
+package Vyatta::IpTables::Mgr;
+
+use strict;
+use warnings;
+
+use base 'Exporter';
+our @EXPORT = qw(ipt_find_chain_rule ipt_enable_conntrack
+ ipt_disable_conntrack count_iptables_rules
+ chain_referenced ipt_get_queue_target
+ run_ipt_cmd create_ipt_chain delete_ipt_chain
+ flush_ipt_chain insert_ipt_rule append_ipt_rule
+ delete_ipt_rule delete_ipt_rulenum ipt_find_comment_rule);
+
+## TODO - in future, we could use perl's libiptc module instead of
+## running system commands in the following function for iptables.
+## However, that would need integrating the libiptc module into the system
+## and also adding other functionality to it, including IPv6 support.
+sub run_ipt_cmd {
+ my ($cmd) = shift;
+ my $error = system("$cmd");
+
+ my $debug = "false";
+ my $syslog = "false";
+ my $logger = "sudo logger -t Vyatta::IPTables::Mgr -p local0.warn --";
+
+ if ($syslog eq "true") {
+ my $func = (caller(1))[3];
+ system("$logger [$func] [$cmd] = [$error]");
+ }
+ if ($debug eq "true") {
+ my $func = (caller(1))[3];
+ print "\n[$func] [$cmd] = [$error]";
+ }
+ return $error;
+}
+
+sub create_ipt_chain {
+ my ($ipt_cmd, $table, $chain) = @_;
+ my ($cmd, $error);
+
+ $cmd = "sudo $ipt_cmd -t $table -N $chain";
+ $error = run_ipt_cmd($cmd);
+ return "create_ipt_chain [$ipt_cmd -t $table -N $chain] failed: [error code - $error]" if $error;
+
+ return;
+}
+
+sub flush_ipt_chain {
+ my ($ipt_cmd, $table, $chain) = @_;
+ my ($cmd, $error);
+
+ $cmd = "sudo $ipt_cmd -t $table -F $chain";
+ $error = run_ipt_cmd($cmd);
+ return "flush_ipt_chain [$ipt_cmd -t $table -F $chain] failed: [error code - $error]" if $error;
+
+ return;
+}
+
+sub delete_ipt_chain {
+ my ($ipt_cmd, $table, $chain) = @_;
+ my ($cmd, $error);
+
+ $cmd = "sudo $ipt_cmd -t $table -X $chain";
+ $error = run_ipt_cmd($cmd);
+ return "delete_ipt_chain [$ipt_cmd -t $table -X $chain] failed: [error code - $error]" if $error;
+
+ return;
+}
+
+sub insert_ipt_rule {
+ my ($ipt_cmd, $table, $chain, $jump_target, $insert_num, $append_options) = @_;
+ my ($cmd, $error);
+
+ $insert_num = 1 if (!defined $insert_num);
+ $cmd = "sudo $ipt_cmd -t $table -I $chain $insert_num -j $jump_target ";
+ $cmd .= $append_options if defined $append_options;
+ $error = run_ipt_cmd($cmd);
+ return "insert_ipt_rule [$ipt_cmd -t $table -I $chain $insert_num -j $jump_target] failed: [error code - $error]" if $error;
+
+ return;
+}
+
+sub append_ipt_rule {
+ my ($ipt_cmd, $table, $chain, $jump_target, $append_options) = @_;
+ my ($cmd, $error);
+
+ $cmd = "sudo $ipt_cmd -t $table -A $chain -j $jump_target ";
+ $cmd .= $append_options if defined $append_options;
+ $error = run_ipt_cmd($cmd);
+ return "append_ipt_rule [$ipt_cmd -t $table -A $chain -j $jump_target] failed: [error code - $error]" if $error;
+
+ return;
+}
+
+# delete rule based on jump target. should only be used if jump_target is unique in that chain
+sub delete_ipt_rule {
+ my ($ipt_cmd, $table, $chain, $jump_target) = @_;
+ my ($cmd, $error);
+
+ $cmd = "sudo $ipt_cmd -t $table -D $chain -j $jump_target";
+ $error = run_ipt_cmd($cmd);
+ return "delete_ipt_rule [$ipt_cmd -t $table -D $chain -j $jump_target] failed: [error code - $error]" if $error;
+
+ return;
+}
+
+# delete rule based on rule number
+sub delete_ipt_rulenum {
+ my ($ipt_cmd, $table, $chain, $delete_num) = @_;
+ my ($cmd, $error);
+
+ $cmd = "sudo $ipt_cmd -t $table -D $chain $delete_num";
+ $error = run_ipt_cmd($cmd);
+ return "delete_ipt_rulenum [$ipt_cmd -t $table -D $chain $delete_num] failed: [error code - $error]" if $error;
+
+ return;
+}
+
+# searches and returns first found rule based on jump target
+sub ipt_find_chain_rule {
+ my ($iptables_cmd, $table, $chain, $search) = @_;
+
+ my ($num, $chain2) = (undef, undef);
+ my $cmd = "$iptables_cmd -t $table -L $chain -vn --line";
+ my @lines = `sudo $cmd 2> /dev/null | egrep ^[0-9]`;
+ if (scalar(@lines) < 1) {
+ return;
+ }
+ foreach my $line (@lines) {
+ ($num, undef, undef, $chain2) = split /\s+/, $line;
+ last if $chain2 eq $search;
+ ($num, $chain2) = (undef, undef);
+ }
+
+ return $num if defined $num;
+ return;
+}
+
+# searches and returns first found rule based on matching text in rule comment
+sub ipt_find_comment_rule {
+ my ($iptables_cmd, $table, $chain, $search) = @_;
+
+ my $cmd = "$iptables_cmd -t $table -L $chain -vn --line";
+ my @lines = `sudo $cmd 2> /dev/null | egrep ^[0-9]`;
+ if (scalar(@lines) < 1) {
+ return;
+ }
+
+ my ($num, $rule_txt, $comment) = (undef, undef);
+ foreach my $line (@lines) {
+ ($rule_txt, $comment) = split /\/\*/, $line;
+
+ #print "rule_txt : $rule_txt, comment : $comment\n";
+ if (defined $comment && $comment =~ m/$search/) {
+
+ #print "found $search in $comment \n";
+ ($num) = split /\s+/, $rule_txt if defined $rule_txt;
+ return $num;
+ }
+ ($rule_txt, $comment) = (undef, undef);
+ }
+ return;
+}
+my %conntrack_hook_hash =(
+ 'PREROUTING' => 'VYATTA_CT_PREROUTING_HOOK',
+ 'OUTPUT' => 'VYATTA_CT_OUTPUT_HOOK',
+);
+
+sub ipt_enable_conntrack {
+ my ($iptables_cmd, $chain) = @_;
+ my $hookCtHelper = 'false';
+
+ if (($chain eq 'FW_CONNTRACK') or ($chain eq 'NAT_CONNTRACK')) {
+ $hookCtHelper = 'true';
+ }
+
+ system("sudo $iptables_cmd -t raw -L $chain -n >& /dev/null");
+ if ($? >> 8) {
+
+ # chain does not exist yet. set up conntrack.
+ system("sudo $iptables_cmd -t raw -N $chain");
+ system("sudo $iptables_cmd -t raw -A $chain -j ACCEPT");
+
+ foreach my $label ('PREROUTING', 'OUTPUT') {
+ my $index;
+ my $conntrack_hook = $conntrack_hook_hash{$label};
+ $index = ipt_find_chain_rule($iptables_cmd, 'raw',$label, $conntrack_hook);
+ if (!defined($index)) {
+ print "Error: unable to find [$label] [$conntrack_hook]\n";
+ return 1;
+ }
+ $index++;
+ system("sudo $iptables_cmd -t raw -I $label $index -j $chain");
+
+ if ($hookCtHelper eq 'true') {
+
+ # we want helper hook only for Firewall / NAT.
+ $conntrack_hook = "VYATTA_CT_HELPER";
+ $index = ipt_find_chain_rule($iptables_cmd, 'raw',$label, $conntrack_hook);
+ if (!defined($index)) {
+
+ # this index does not change now but maybe later we change it, so being defensive.
+ my $cttimeout_index = ipt_find_chain_rule($iptables_cmd, 'raw', $label, "VYATTA_CT_TIMEOUT");
+ if (defined($cttimeout_index)) {
+
+ # $cttimeout_index++; fixing 8173
+ # currently we have cttimeout at 1 index, it might change in future.
+ # helper chain should be before timeout chain
+ system("sudo $iptables_cmd -t raw -I $label $cttimeout_index -j VYATTA_CT_HELPER");
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+sub remove_cthelper_hook {
+ my ($iptables_cmd, $label, $chain) =@_;
+
+ #label is PREROUTING / OUTPUT, chain is FW_CONNTRACK/NAT_CONNTRACK etc.
+ my $index;
+
+ # find if we need to remove VYATTA_CT_HELPER
+ my $cthelper_index = ipt_find_chain_rule($iptables_cmd, 'raw',$label, 'VYATTA_CT_HELPER');
+ if(!defined($cthelper_index)) {
+
+ # not an error: this hook is only for FW / NAT
+ return 0;
+ }
+
+ # if this chain is FW_CONNTRACK, look if NAT is using it, else remove
+ if ($chain eq 'FW_CONNTRACK') {
+ $index = ipt_find_chain_rule($iptables_cmd, 'raw',$label, 'NAT_CONNTRACK');
+ if (!defined($index)) {
+
+ # NAT, only other user of helpers, not enabled, can remove VYATTA_CT_HELPER
+ system("sudo $iptables_cmd -t raw -D $label $cthelper_index");
+ return 0;
+ }
+ } elsif ($chain eq 'NAT_CONNTRACK') {
+ $index = ipt_find_chain_rule($iptables_cmd, 'raw',$label, 'FW_CONNTRACK');
+ if (!defined($index)) {
+
+ # Firewall, only other user of helpers, not enabled, can remove VYATTA_CT_HELPER
+ system("sudo $iptables_cmd -t raw -D $label $cthelper_index");
+ return 0;
+ }
+ }
+}
+
+sub ipt_disable_conntrack {
+ my ($iptables_cmd, $chain) = @_;
+
+ my $debug = 0;
+ my @lines;
+ foreach my $label ('PREROUTING', 'OUTPUT') {
+ my $index;
+ my $conntrack_hook = $conntrack_hook_hash{$label};
+ $index = ipt_find_chain_rule($iptables_cmd, 'raw',$label, $chain);
+ if (!defined($index)) {
+ if ($debug > 0) {
+ print "Error: ipt_disable_conntrack failed to find ". "[$label][$chain]\n";
+ }
+ return 1;
+ }
+ system("sudo $iptables_cmd -t raw -D $label $index");
+
+ remove_cthelper_hook($iptables_cmd, $label, $chain);
+ }
+
+ system("sudo $iptables_cmd -t raw -F $chain >& /dev/null");
+ system("sudo $iptables_cmd -t raw -X $chain >& /dev/null");
+
+ return 0;
+}
+
+my %queue_target_hash =(
+ 'SNORT' => 'NFQUEUE',
+ 'VG_HTTPS' => 'NFQUEUE --queue-num 1',
+);
+
+sub ipt_get_queue_target {
+ my ($app) = @_;
+
+ my $target = $queue_target_hash{$app};
+ return $target;
+}
+
+sub count_iptables_rules {
+ my ($iptables_cmd, $table, $chain) = @_;
+
+ my $cmd = "$iptables_cmd -t $table -L $chain -n --line";
+ my @lines = `sudo $cmd 2> /dev/null`;
+ my $cnt = 0;
+ foreach my $line (@lines) {
+ $cnt++ if $line =~ /^\d/;
+ }
+ return $cnt;
+}
+
+sub chain_referenced {
+ my ($table, $chain, $iptables_cmd) = @_;
+
+ my $cmd = "$iptables_cmd -t $table -n -L $chain";
+ my $line = `sudo $cmd 2>/dev/null |head -n1`;
+ chomp $line;
+ my $found = 0;
+ if ($line =~ m/^Chain $chain \((\d+) references\)$/) {
+ if ($1 > 0) {
+ $found = 1;
+ }
+ }
+ return $found;
+}
+
+1;