diff options
-rw-r--r-- | Makefile.am | 3 | ||||
-rwxr-xr-x | lib/Vyatta/Zone.pm | 43 | ||||
-rw-r--r-- | scripts/vyatta-zone-ips.pl | 755 | ||||
-rw-r--r-- | templates-cfg/zone-policy/node.def | 11 | ||||
-rw-r--r-- | templates-cfg/zone-policy/zone/node.def | 36 | ||||
-rw-r--r-- | templates-cfg/zone-policy/zone/node.tag/from/node.def | 28 | ||||
-rw-r--r-- | templates-cfg/zone-policy/zone/node.tag/from/node.tag/content-inspection/.ipv6-enable/node.def | 46 | ||||
-rw-r--r-- | templates-cfg/zone-policy/zone/node.tag/from/node.tag/content-inspection/enable/node.def | 46 | ||||
-rw-r--r-- | templates-cfg/zone-policy/zone/node.tag/from/node.tag/content-inspection/node.def | 1 | ||||
-rw-r--r-- | templates-cfg/zone-policy/zone/node.tag/interface/node.def | 34 | ||||
-rw-r--r-- | templates-cfg/zone-policy/zone/node.tag/local-zone/node.def | 28 |
11 files changed, 996 insertions, 35 deletions
diff --git a/Makefile.am b/Makefile.am index 0deeb65..f9a0f4c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,7 +3,8 @@ opdir = $(datadir)/vyatta-op/templates share_perl5dir = $(datarootdir)/perl5/Vyatta bin_sudo_usersdir = $(bindir)/sudo-users -sbin_SCRIPTS = scripts/vyatta-zone.pl +sbin_SCRIPTS = scripts/vyatta-zone.pl +sbin_SCRIPTS += scripts/vyatta-zone-ips.pl share_perl5_DATA = lib/Vyatta/Zone.pm diff --git a/lib/Vyatta/Zone.pm b/lib/Vyatta/Zone.pm index b23bc74..0559753 100755 --- a/lib/Vyatta/Zone.pm +++ b/lib/Vyatta/Zone.pm @@ -34,21 +34,33 @@ my $debug="false"; my $syslog="false"; my $logger = 'sudo logger -t zone.pm -p local0.warn --'; +my %script_to_feature_hash = ( + 'vyatta-zone.pl' => 'ZONE-FW', + 'vyatta-zone-ips.pl' => 'ZONE-IPS'); + sub run_cmd { my $cmd = shift; my $error = system("$cmd"); if ($syslog eq "true") { my $func = (caller(1))[3]; - system("$logger [$func] [$cmd] = [$error]"); + my $feature = zone_feature((caller(1))[1]); + system("$logger [$feature] [$func] [$cmd] = [$error]"); } if ($debug eq "true") { my $func = (caller(1))[3]; - print "[$func] [$cmd] = [$error]\n"; + my $feature = zone_feature((caller(1))[1]); + print "[$feature] [$func] [$cmd] = [$error]\n"; } return $error; } +sub zone_feature { + my ($script) = @_; + $script =~ s/\/opt\/vyatta\/sbin\///; + return $script_to_feature_hash{$script}; +} + sub is_fwruleset_active { my ($value_func, $ruleset_type, $fw_ruleset) = @_; my $config = new Vyatta::Config; @@ -86,12 +98,25 @@ sub is_local_zone { return $config->$value_func("zone-policy zone $zone_name local-zone"); } +sub is_ips_enabled { + my ($value_func, $zone_name, $from_zone, $ips_type) = @_; + $ips_type =~ s/name/enable/; + my $config = new Vyatta::Config; + return $config->$value_func("zone-policy zone $zone_name from $from_zone + content-inspection $ips_type") +} + sub get_zone_default_policy { my ($value_func, $zone_name) = @_; my $config = new Vyatta::Config; return $config->$value_func("zone-policy zone $zone_name default-action"); } +sub get_ips_zone_default_policy { + my ($value_func, $zone_name) = @_; + return 'accept'; +} + sub rule_exists { my ($command, $table, $chain_name, $target, $interface) = @_; my $cmd = @@ -107,7 +132,19 @@ sub rule_exists { sub get_zone_chain { my ($value_func, $zone, $localout) = @_; - my $chain = "VZONE_$zone"; + my $chain_prefix = "VZONE_$zone"; # should be same length as ips_zone_chain + return get_zone_chain_name($value_func, $zone, $localout, $chain_prefix); +} + +sub get_ips_zone_chain { + my ($value_func, $zone, $localout) = @_; + my $chain_prefix = "VZIPS_$zone"; # should be same length as zone_chain + return get_zone_chain_name($value_func, $zone, $localout, $chain_prefix); +} + +sub get_zone_chain_name { + my ($value_func, $zone, $localout, $chain_prefix) = @_; + my $chain = $chain_prefix; if (defined(is_local_zone($value_func, $zone))) { # local zone if (defined $localout) { diff --git a/scripts/vyatta-zone-ips.pl b/scripts/vyatta-zone-ips.pl new file mode 100644 index 0000000..0c8e3d1 --- /dev/null +++ b/scripts/vyatta-zone-ips.pl @@ -0,0 +1,755 @@ +#!/usr/bin/perl +# +# Module: vyatta-zone.pl +# +# **** 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: Mohit Mehta +# Date: October 2010 +# Description: Script for Zone Based IPS +# +# **** End License **** +# + +use Getopt::Long; +use POSIX; + +use lib "/opt/vyatta/share/perl5"; +use Vyatta::Zone; +use Vyatta::IpTables::Mgr; + +use warnings; +use strict; + +# IPS mapping from config node to iptables command. Similar to FW. +my %cmd_hash = ( 'name' => '/sbin/iptables', + 'ipv6-name' => '/sbin/ip6tables'); + +# IPS mapping from config node to iptables/ip6tables table +my %table_hash = ( 'name' => 'filter', + 'ipv6-name' => 'filter'); + +# mapping from vyatta 'default-policy' to iptables jump target +my %policy_hash = ( 'drop' => 'DROP', + 'reject' => 'REJECT', + 'accept' => 'RETURN'); + +sub setup_default_policy { + my ($zone_name, $default_policy, $localoutchain) = @_; + my ($cmd, $error); + my $zone_chain=Vyatta::Zone::get_ips_zone_chain("exists", + $zone_name, $localoutchain); + + # add default policy for zone chains in filter, ip6filter tables + foreach my $tree (keys %cmd_hash) { + + # set default policy for zone chain + $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} -A " . + "$zone_chain -j $policy_hash{$default_policy}"; + $error = Vyatta::Zone::run_cmd("$cmd"); + return "Error: set default policy $zone_chain failed [$error]" if $error; + + my $rule_cnt = Vyatta::IpTables::Mgr::count_iptables_rules($cmd_hash{$tree}, + $table_hash{$tree}, $zone_chain); + + # If there's a return all rule at rule_cnt - 1 then remove that. + # In IPS zone chain a return all target can only be for default policy + if ($rule_cnt > 1) { + my $in_intf = '$6'; + # set IPv6 params if using ip6tables + if ($cmd_hash{$tree} =~ '6') { + $in_intf = '$5'; + } + my $penultimate_rule_num=$rule_cnt-1; + $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} " . + "-L $zone_chain $penultimate_rule_num -v " . + "| awk {'print \$3\" \"$in_intf'}"; + my $target=`$cmd`; + chomp $target; + if (defined $target && ($target eq 'RETURN any')) { + $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} -D " . + "$zone_chain $penultimate_rule_num"; + $error = Vyatta::Zone::run_cmd("$cmd"); + return "Error: delete rule $penultimate_rule_num with $target +in $zone_name chain failed [$error]" if $error; + } + } + } + return; +} + +sub create_zone_chain { + my ($zone_name, $localoutchain) = @_; + my ($cmd, $error); + my $zone_chain=Vyatta::Zone::get_ips_zone_chain("exists", + $zone_name, $localoutchain); + + # create zone chains in filter, ip6filter tables + foreach my $tree (keys %cmd_hash) { + $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} " . + "-L $zone_chain >&/dev/null"; + $error = Vyatta::Zone::run_cmd($cmd); + if ($error) { + # chain does not exist, go ahead create it + $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} -N $zone_chain"; + $error = Vyatta::Zone::run_cmd($cmd); + return "Error: create $zone_name chain with failed [$error]" if $error; + } + } + + return; +} + +sub delete_zone_chain { + my ($zone_name, $localoutchain) = @_; + my ($cmd, $error); + my $zone_chain=Vyatta::Zone::get_ips_zone_chain("existsOrig", + $zone_name, $localoutchain); + # delete zone chains from filter, ip6filter tables + foreach my $tree (keys %cmd_hash) { + # flush all rules from zone chain + $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} -F $zone_chain"; + $error = Vyatta::Zone::run_cmd($cmd); + return "Error: flush all rules in $zone_name chain failed [$error]" if $error; + + # delete zone chain + $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} -X $zone_chain"; + $error = Vyatta::Zone::run_cmd($cmd); + return "Error: delete $zone_name chain failed [$error]" if $error; + } + return; +} + +sub insert_from_rule { + my ($zone_name, $from_zone, $interface, $ruleset_type, $ruleset, + $direction, $zone_chain) = @_; + my ($cmd, $error); + my $ruleset_name; + + if (defined $ruleset) { # called from node.def + $ruleset_name=$ruleset; + } else { # called from do_ips_interface_zone() + $ruleset_name = 'VYATTA_SNORT_all_HOOK' if defined + Vyatta::Zone::is_ips_enabled("exists", + $zone_name, $from_zone, $ruleset_type); + } + + if (defined $ruleset_name) { + # get number of rules in ruleset_name + my $rule_cnt = Vyatta::IpTables::Mgr::count_iptables_rules($cmd_hash{$ruleset_type}, + $table_hash{$ruleset_type}, "$zone_chain"); + # append rule before last RETURN all rule + my $insert_at_rule_num=1; + if ( $rule_cnt > 1 ) { + $insert_at_rule_num=$rule_cnt; + } + my $result = Vyatta::Zone::rule_exists ($cmd_hash{$ruleset_type}, + $table_hash{$ruleset_type}, "$zone_chain", $ruleset_name, $interface); + if ($result < 1) { + # append rule before RETURN rule to jump to ruleset for in\out interface + $cmd = "sudo $cmd_hash{$ruleset_type} -t $table_hash{$ruleset_type} " . +"-I $zone_chain $insert_at_rule_num $direction $interface -j $ruleset_name"; + $error = Vyatta::Zone::run_cmd($cmd); + return "Error: insert rule for $direction $interface into zone-chain +$zone_chain with target $ruleset_name failed [$error]" if $error; + + } + } + + return; +} + + +sub add_fromzone_intf_ruleset { + my ($zone_name, $from_zone, $interface, $ruleset_type, $ruleset) = @_; + my $zone_chain=Vyatta::Zone::get_ips_zone_chain("exists", $zone_name); + my $error = insert_from_rule ($zone_name, $from_zone, $interface, + $ruleset_type, $ruleset, '-i', $zone_chain); + return ($error, ) if $error; + return; +} + +sub add_fromlocalzone_ruleset { + my ($zone_name, $from_zone, $interface, $ruleset_type, $ruleset) = @_; + my $zone_chain=Vyatta::Zone::get_ips_zone_chain("exists", $from_zone, "localout"); + + my $error = insert_from_rule ($zone_name, $from_zone, $interface, + $ruleset_type, $ruleset, '-o', $zone_chain); + return ($error, ) if $error; + + return; +} + +sub delete_from_rule { + + my ($zone_name, $from_zone, $interface, $ruleset_type, $ruleset, + $direction, $zone_chain) = @_; + my ($cmd, $error); + my $ruleset_name; + + if (defined $ruleset) { # called from node.def + $ruleset_name=$ruleset; + } else { # called from undo_ips_interface_zone() + $ruleset_name = 'VYATTA_SNORT_all_HOOK' if defined + Vyatta::Zone::is_ips_enabled("exists", + $zone_name, $from_zone, $ruleset_type); + } + + if (defined $ruleset_name) { + # delete rule to jump to ruleset for in|out interface in zone chain + $cmd = "sudo $cmd_hash{$ruleset_type} -t $table_hash{$ruleset_type} " . + "-D $zone_chain $direction $interface -j $ruleset_name"; + $error = Vyatta::Zone::run_cmd($cmd); + return "Error: call to delete rule for $direction $interface +in zone chain $zone_chain with target $ruleset_name failed [$error]" if $error; + } + + return; +} + +sub delete_fromzone_intf_ruleset { + my ($zone_name, $from_zone, $interface, $ruleset_type, $ruleset) = @_; + my $zone_chain=Vyatta::Zone::get_ips_zone_chain("existsOrig", $zone_name); + my $error = delete_from_rule ($zone_name, $from_zone, $interface, + $ruleset_type, $ruleset, '-i', $zone_chain); + return ($error, ) if $error; + return; +} + +sub delete_fromlocalzone_ruleset { + my ($zone_name, $from_zone, $interface, $ruleset_type, $ruleset) = @_; + my $zone_chain=Vyatta::Zone::get_ips_zone_chain("existsOrig", + $from_zone, "localout"); + + my ($cmd, $error); + $error = delete_from_rule ($zone_name, $from_zone, $interface, + $ruleset_type, $ruleset, '-o', $zone_chain); + return ($error, ) if $error; + + return; +} + +sub do_ips_interface_zone { + my ($zone_name, $interface) = @_; + my $zone_chain=Vyatta::Zone::get_ips_zone_chain("exists", $zone_name); + my ($cmd, $error); + foreach my $tree (keys %cmd_hash) { + + my $result = Vyatta::Zone::rule_exists ($cmd_hash{$tree}, + $table_hash{$tree}, "$zone_chain", "RETURN", $interface); + if ($result < 1) { + # add rule to allow same zone to same zone traffic + $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} -I $zone_chain " . + "-i $interface -j RETURN"; + $error = Vyatta::Zone::run_cmd($cmd); + return "Error: call to add $interface to its zone-chain $zone_chain +failed [$error]" if $error; + } + + # need to do this as an append before ACCEPT rule at the end + my $rule_cnt = Vyatta::IpTables::Mgr::count_iptables_rules($cmd_hash{$tree}, + $table_hash{$tree}, "VYATTA_POST_FW_FWD_HOOK"); + my $insert_at_rule_num=1; + if ( $rule_cnt > 1 ) { + $insert_at_rule_num=$rule_cnt; + } + $result = Vyatta::Zone::rule_exists ($cmd_hash{$tree}, $table_hash{$tree}, + "VYATTA_POST_FW_FWD_HOOK", "$zone_chain", $interface); + if ($result < 1) { + $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} -I VYATTA_POST_FW_FWD_HOOK " . + "$insert_at_rule_num -o $interface -j $zone_chain"; + $error = Vyatta::Zone::run_cmd($cmd); + return "Error: call to add jump rule for outgoing interface $interface +to its $zone_chain chain failed [$error]" if $error; + } + } + + # get all zones in which this zone is being used as a from zone + # then in chains for those zones, add rules for this incoming interface + my @all_zones = Vyatta::Zone::get_all_zones("listNodes"); + foreach my $zone (@all_zones) { + if (!($zone eq $zone_name)) { + my @from_zones = Vyatta::Zone::get_from_zones("listEffectiveNodes", + $zone); + if (scalar(grep(/^$zone_name$/, @from_zones)) > 0) { + foreach my $tree (keys %cmd_hash) { + # call function to append rules to $zone's chain + $error = add_fromzone_intf_ruleset($zone, $zone_name, + $interface, $tree); + return "Error: $error" if $error; + } + } + } + } + + # if this zone has a local from zone, add interface to local zone out chain + my @my_from_zones = Vyatta::Zone::get_from_zones("listEffectiveNodes", + $zone_name); + foreach my $fromzone (@my_from_zones) { + if (defined(Vyatta::Zone::is_local_zone("exists", $fromzone))) { + foreach my $tree (keys %cmd_hash) { + $error = add_fromlocalzone_ruleset($zone_name, $fromzone, + $interface, $tree); + return "Error: $error" if $error; + } + } + } + + return; +} + +sub undo_ips_interface_zone { + my ($zone_name, $interface) = @_; + my ($cmd, $error); + my $zone_chain=Vyatta::Zone::get_ips_zone_chain("existsOrig", $zone_name); + + foreach my $tree (keys %cmd_hash) { + + # delete rule to allow same zone to same zone traffic + $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} -D VYATTA_POST_FW_FWD_HOOK " . + "-o $interface -j $zone_chain"; + $error = Vyatta::Zone::run_cmd($cmd); + return "Error: call to delete jump rule for outgoing interface $interface +to $zone_chain chain failed [$error]" if $error; + + # delete ruleset jump for this in interface + $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} -D $zone_chain " . + "-i $interface -j RETURN"; + $error = Vyatta::Zone::run_cmd($cmd); + return "Error: call to delete interface $interface from zone-chain +$zone_chain with failed [$error]" if $error; + } + + # delete rules for this intf where this zone is being used as a from zone + my @all_zones = Vyatta::Zone::get_all_zones("listOrigNodes"); + foreach my $zone (@all_zones) { + if (!($zone eq $zone_name)) { + my @from_zones = Vyatta::Zone::get_from_zones("listEffectiveNodes", + $zone); + if (scalar(grep(/^$zone_name$/, @from_zones)) > 0) { + foreach my $tree (keys %cmd_hash) { + # call function to delete rules from $zone's chain + $error = delete_fromzone_intf_ruleset($zone, $zone_name, + $interface, $tree); + return "Error: $error" if $error; + } + } + } + } + + # if you have local from zone, delete interface to local zone out chain + my @my_from_zones = Vyatta::Zone::get_from_zones("listEffectiveNodes", + $zone_name); + foreach my $fromzone (@my_from_zones) { + if (defined(Vyatta::Zone::is_local_zone("existsOrig", $fromzone))) { + foreach my $tree (keys %cmd_hash) { + $error = delete_fromlocalzone_ruleset($zone_name, $fromzone, + $interface, $tree); + return "Error: $error" if $error; + } + } + } + + return; +} + +sub do_ips_localzone { + my ($zone_name) = @_; + my ($cmd, $error); + my $zone_chain=Vyatta::Zone::get_ips_zone_chain("exists", $zone_name); + foreach my $tree (keys %cmd_hash) { + + my $rule_cnt = Vyatta::IpTables::Mgr::count_iptables_rules($cmd_hash{$tree}, + $table_hash{$tree}, "VYATTA_POST_FW_IN_HOOK"); + my $insert_at_rule_num=1; + if ( $rule_cnt > 1 ) { + $insert_at_rule_num=$rule_cnt; + } + my $result = Vyatta::Zone::rule_exists ($cmd_hash{$tree}, + $table_hash{$tree}, "VYATTA_POST_FW_IN_HOOK", $zone_chain); + + if ($result < 1) { + # insert rule to filter local traffic from interface per ruleset + $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} -I " . + "VYATTA_POST_FW_IN_HOOK $insert_at_rule_num -j $zone_chain"; + $error = Vyatta::Zone::run_cmd($cmd); + return "Error: call to add jump rule for local zone +$zone_chain chain failed [$error]" if $error; + } + } + + # get all zones in which local zone is being used as a from zone + # filter traffic from local zone to those zones + my @all_zones = Vyatta::Zone::get_all_zones("listNodes"); + foreach my $zone (@all_zones) { + if (!($zone eq $zone_name)) { + my @from_zones = Vyatta::Zone::get_from_zones("listEffectiveNodes", + $zone); + if (scalar(grep(/^$zone_name$/, @from_zones)) > 0) { + foreach my $tree (keys %cmd_hash) { + my @zone_interfaces = + Vyatta::Zone::get_zone_interfaces("returnValues", $zone); + foreach my $intf (@zone_interfaces) { + $error = add_fromlocalzone_ruleset($zone, $zone_name, + $intf, $tree); + return "Error: $error" if $error; + } + } + } + } + } + return; +} + +sub undo_ips_localzone { + my ($zone_name) = @_; + my ($cmd, $error); + my $zone_chain=Vyatta::Zone::get_ips_zone_chain("existsOrig", $zone_name); + + foreach my $tree (keys %cmd_hash) { + + # delete rule to filter traffic destined for system + $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} -D " . + "VYATTA_POST_FW_IN_HOOK -j $zone_chain"; + $error = Vyatta::Zone::run_cmd($cmd); + return "Error: call to delete local zone +$zone_chain chain failed [$error]" if $error; + } + + # get all zones in which local zone is being used as a from zone + # remove filter for traffic from local zone to those zones + my @all_zones = Vyatta::Zone::get_all_zones("listOrigNodes"); + foreach my $zone (@all_zones) { + if (!($zone eq $zone_name)) { + my @from_zones = Vyatta::Zone::get_from_zones("listEffectiveNodes", + $zone); + if (scalar(grep(/^$zone_name$/, @from_zones)) > 0) { + foreach my $tree (keys %cmd_hash) { + my @zone_interfaces = + Vyatta::Zone::get_zone_interfaces("returnOrigValues", $zone); + foreach my $intf (@zone_interfaces) { + $error = delete_fromlocalzone_ruleset($zone, $zone_name, + $intf, $tree); + return "Error: $error" if $error; + } + } + } + } + } + return; +} + +sub add_zone { + my $zone_name = shift; + # perform IPS related actions for this zone + my $error = create_zone_chain ($zone_name); + return ($error, ) if $error; + + if (defined(Vyatta::Zone::is_local_zone("exists", $zone_name))) { + # make local out chain as well + $error = create_zone_chain ($zone_name, "localout"); + return ($error, ) if $error; + + # allow traffic sourced from and destined to localhost + my $cmd; + my @localchains=(); + $localchains[0] = Vyatta::Zone::get_ips_zone_chain("exists", $zone_name); + $localchains[1] = Vyatta::Zone::get_ips_zone_chain("exists", $zone_name, + 'localout'); + + foreach my $tree (keys %cmd_hash) { + foreach my $chain (@localchains) { + my $loopback_intf = ''; + if ($chain =~ m/_IN/) { + + # if the chain is INPUT chain + $loopback_intf = '$6'; + + # set IPv6 params if using ip6tables + if ($cmd_hash{$tree} =~ '6') { + $loopback_intf = '$5'; + } + + } else { + + # if the chain is OUTPUT chain + $loopback_intf = '$7'; + + # set IPv6 params if using ip6tables + if ($cmd_hash{$tree} =~ '6') { + $loopback_intf = '$6'; + } + + } + + $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} -L $chain 1 -vn " . + "| awk {'print \$3 \" \" $loopback_intf'} ". + "| grep 'RETURN lo\$' | wc -l"; + + my $result=`$cmd`; + if ($result < 1) { + + $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} -I $chain "; + + if ($chain =~ m/_IN/) { + + # rule for INPUT chain + $cmd .= "-i lo -j RETURN"; + + } else { + + # rule for OUTPUT chain + $cmd .= "-o lo -j RETURN"; + + } + + $error = Vyatta::Zone::run_cmd($cmd); + return "Error: adding rule to allow localhost traffic failed [$error]" if $error; + + } + } + } + + } + + # set default policy + my $default_policy = Vyatta::Zone::get_ips_zone_default_policy("returnValue", + $zone_name); + $error = set_default_policy($zone_name, $default_policy); + return $error if $error; + + return; +} + +sub delete_zone { + my $zone_name = shift; + # undo IPS related actions for this zone + my $error = delete_zone_chain ($zone_name); + return ($error, ) if $error; + if (defined(Vyatta::Zone::is_local_zone("existsOrig", $zone_name))) { + # delete local out chain as well + $error = delete_zone_chain ($zone_name, "localout"); + return ($error, ) if $error; + } + return; +} + +sub add_localzone { + my ($zone_name) = @_; + my $error; + # do IPS related stuff + $error = do_ips_localzone ($zone_name); + return ($error, ) if $error; + return; +} + +sub delete_localzone { + my ($zone_name) = @_; + my $error; + # undo IPS related stuff + $error = undo_ips_localzone ($zone_name); + return ($error, ) if $error; + return; +} + +sub add_zone_interface { + my ($zone_name, $interface) = @_; + return("Error: undefined interface", ) if ! defined $interface; + my $error; + # do IPS related stuff + $error = do_ips_interface_zone ($zone_name, $interface); + return ($error, ) if $error; + return; +} + +sub delete_zone_interface { + my ($zone_name, $interface) = @_; + return("Error: undefined interface", ) if ! defined $interface; + # undo IPS related stuff + my $error = undo_ips_interface_zone ($zone_name, $interface); + return ($error, ) if $error; + return; +} + +sub add_fromzone_ips { + my ($zone, $from_zone, $ruleset_type, $ruleset_name) = @_; + my ($cmd, $error); + + # for all interfaces in from zone apply ruleset to filter traffic + # from this zone to specified zone (i.e. $zone) + my @from_zone_interfaces = + Vyatta::Zone::get_zone_interfaces("returnValues", $from_zone); + if (scalar(@from_zone_interfaces) > 0) { + foreach my $intf (@from_zone_interfaces) { + $error = add_fromzone_intf_ruleset($zone, $from_zone, $intf, + $ruleset_type, $ruleset_name); + return "Error: $error" if $error; + } + } else { + if (defined(Vyatta::Zone::is_local_zone("exists", $from_zone))) { + # local from zone + my @zone_interfaces = + Vyatta::Zone::get_zone_interfaces("returnValues", $zone); + foreach my $intf (@zone_interfaces) { + $error = add_fromlocalzone_ruleset($zone, $from_zone, $intf, + $ruleset_type, $ruleset_name); + return "Error: $error" if $error; + } + } + + my $zone_chain=Vyatta::Zone::get_ips_zone_chain("exists", + $from_zone, 'localout'); + # add jump to local-zone-out chain in OUTPUT chains for [ip and ip6]tables + foreach my $tree (keys %cmd_hash) { + # if jump to localzoneout chain not inserted, then insert rule + my $rule_cnt = Vyatta::IpTables::Mgr::count_iptables_rules($cmd_hash{$tree}, + $table_hash{$tree}, "VYATTA_POST_FW_OUT_HOOK"); + my $insert_at_rule_num=1; + if ( $rule_cnt > 1 ) { + $insert_at_rule_num=$rule_cnt; + } + my $result = Vyatta::Zone::rule_exists ($cmd_hash{$tree}, + $table_hash{$tree}, "VYATTA_POST_FW_OUT_HOOK", $zone_chain); + if ($result < 1) { + my $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} " . + "-I VYATTA_POST_FW_OUT_HOOK $insert_at_rule_num -j $zone_chain"; + $error = Vyatta::Zone::run_cmd($cmd); + return "Error: call to add jump rule for local zone out +$zone_chain chain failed [$error]" if $error; + } + } + + } # end of else + + return; +} + +sub delete_fromzone_ips { + my ($zone, $from_zone, $ruleset_type, $ruleset_name) = @_; + my ($cmd, $error); + + # for all interfaces in from zone remove ruleset to filter traffic + # from this zone to specified zone (i.e. $zone) + my @from_zone_interfaces = + Vyatta::Zone::get_zone_interfaces("returnOrigValues", $from_zone); + if (scalar(@from_zone_interfaces) > 0) { + foreach my $intf (@from_zone_interfaces) { + $error = delete_fromzone_intf_ruleset($zone, $from_zone, $intf, + $ruleset_type, $ruleset_name); + return "Error: $error" if $error; + } + } else { + if (defined(Vyatta::Zone::is_local_zone("existsOrig", $from_zone))) { + # local from zone + my @zone_interfaces = + Vyatta::Zone::get_zone_interfaces("returnOrigValues", $zone); + foreach my $intf (@zone_interfaces) { + $error = delete_fromlocalzone_ruleset($zone, $from_zone, $intf, + $ruleset_type, $ruleset_name); + return "Error: $error" if $error; + } + } + + my $zone_chain=Vyatta::Zone::get_ips_zone_chain("existsOrig", + $from_zone, 'localout'); + # if only RETURN rule & localhost allow rule in $zone_chain in both + # [ip and ip6]tables then delete jump from OUTPUT chain in both + foreach my $tree (keys %cmd_hash) { + my $rule_cnt = Vyatta::IpTables::Mgr::count_iptables_rules($cmd_hash{$tree}, + $table_hash{$tree}, $zone_chain); + if ($rule_cnt > 2) { + # atleast one of [ip or ip6]tables has local-zone as a from zone + return; + } + } + + foreach my $tree (keys %cmd_hash) { + $cmd = "sudo $cmd_hash{$tree} -t $table_hash{$tree} " . + "-D VYATTA_POST_FW_OUT_HOOK -j $zone_chain"; + $error = Vyatta::Zone::run_cmd($cmd); + return "Error: call to delete jump rule for local zone out +$zone_chain chain failed [$error]" if $error; + } + + } # end of else + return; +} + +sub set_default_policy { + my ($zone, $default_policy) = @_; + # setup default policy for zone + my $error = setup_default_policy ($zone, $default_policy); + return ($error, ) if $error; + if (defined(Vyatta::Zone::is_local_zone("exists", $zone))) { + # set default policy for local out chain as well + $error = setup_default_policy ($zone, $default_policy, "localout"); + return ($error, ) if $error; + } + return; +} + +# +# main +# + +my ($action, $zone_name, $interface, $from_zone, $ruleset_type, $ruleset_name); + +GetOptions("action=s" => \$action, + "zone-name=s" => \$zone_name, + "interface=s" => \$interface, + "from-zone=s" => \$from_zone, + "ruleset-type=s" => \$ruleset_type, + "ruleset-name=s" => \$ruleset_name, +); + +die "undefined action" if ! defined $action; +die "undefined zone" if ! defined $zone_name; + +my ($error, $warning); + +($error, $warning) = add_zone($zone_name) if $action eq 'add-zone'; + +($error, $warning) = delete_zone($zone_name) if $action eq 'delete-zone'; + +($error, $warning) = add_zone_interface($zone_name, $interface) + if $action eq 'add-zone-interface'; + +($error, $warning) = delete_zone_interface($zone_name, $interface) + if $action eq 'delete-zone-interface'; + +($error, $warning) = add_fromzone_ips($zone_name, $from_zone, $ruleset_type, + $ruleset_name) if $action eq 'add-fromzone-ips'; + +($error, $warning) = delete_fromzone_ips($zone_name, $from_zone, $ruleset_type, + $ruleset_name) if $action eq 'delete-fromzone-ips'; + +($error, $warning) = add_localzone($zone_name) + if $action eq 'add-localzone'; + +($error, $warning) = delete_localzone($zone_name) + if $action eq 'delete-localzone'; + +if (defined $warning) { + print "$warning\n"; +} + +if (defined $error) { + print "$error\n"; + exit 1; +} + +exit 0; + +# end of file diff --git a/templates-cfg/zone-policy/node.def b/templates-cfg/zone-policy/node.def index 440d397..52a6b68 100644 --- a/templates-cfg/zone-policy/node.def +++ b/templates-cfg/zone-policy/node.def @@ -1,6 +1,11 @@ priority: 250 # after zone-policy/zone/node.tag/from/ + help: Configure zone-policy -begin: -if ! /opt/vyatta/sbin/vyatta-zone.pl --action=validity-checks --zone-name=none --silent-validate=false; then - exit 1 + +begin: +if ! /opt/vyatta/sbin/vyatta-zone.pl \ + --action=validity-checks \ + --zone-name=none \ + --silent-validate=false; then + exit 1 fi diff --git a/templates-cfg/zone-policy/zone/node.def b/templates-cfg/zone-policy/zone/node.def index eb8c3c8..56c09c2 100644 --- a/templates-cfg/zone-policy/zone/node.def +++ b/templates-cfg/zone-policy/zone/node.def @@ -10,15 +10,31 @@ syntax:expression: pattern $VAR(@) "^[^-]" ; "Zone name cannot start with \"-\"" syntax:expression: pattern $VAR(@) "^[^;]*$" ; "Zone name cannot contain ';'" create: - if ! /opt/vyatta/sbin/vyatta-zone.pl \ - --action=add-zone \ - --zone-name="$VAR(@)"; then - exit 1 - fi + # fw zone actions + if ! /opt/vyatta/sbin/vyatta-zone.pl \ + --action=add-zone \ + --zone-name="$VAR(@)"; then + exit 1 + fi + + # ips zone actions + if ! /opt/vyatta/sbin/vyatta-zone-ips.pl \ + --action=add-zone \ + --zone-name="$VAR(@)"; then + exit 1 + fi delete: - if ! /opt/vyatta/sbin/vyatta-zone.pl \ - --action=delete-zone \ - --zone-name="$VAR(@)"; then - exit 1 - fi + # fw zone actions + if ! /opt/vyatta/sbin/vyatta-zone.pl \ + --action=delete-zone \ + --zone-name="$VAR(@)"; then + exit 1 + fi + + # ips zone actions + if ! /opt/vyatta/sbin/vyatta-zone-ips.pl \ + --action=delete-zone \ + --zone-name="$VAR(@)"; then + exit 1 + fi diff --git a/templates-cfg/zone-policy/zone/node.tag/from/node.def b/templates-cfg/zone-policy/zone/node.tag/from/node.def index 433f423..62cd3cb 100644 --- a/templates-cfg/zone-policy/zone/node.tag/from/node.def +++ b/templates-cfg/zone-policy/zone/node.tag/from/node.def @@ -9,8 +9,11 @@ allowed: echo -n "${zones[@]}" begin: -if ! /opt/vyatta/sbin/vyatta-zone.pl --action=validity-checks --zone-name=none --silent-validate=true; then - exit 1 +if ! /opt/vyatta/sbin/vyatta-zone.pl \ + --action=validity-checks \ + --zone-name=none \ + --silent-validate=true; then + exit 1 fi create: @@ -33,10 +36,27 @@ create: echo Undefined from zone [$VAR(@)] under zone $parent_zone exit 1 else - if ! /opt/vyatta/sbin/vyatta-zone.pl --action=add-zone --zone-name="$parent_zone"; then + # fw zone actions + if ! /opt/vyatta/sbin/vyatta-zone.pl \ + --action=add-zone \ + --zone-name="$parent_zone"; then + exit 1 + fi + if ! /opt/vyatta/sbin/vyatta-zone.pl \ + --action=add-zone \ + --zone-name="$VAR(@)"; then + exit 1 + fi + + # ips zone actions + if ! /opt/vyatta/sbin/vyatta-zone-ips.pl \ + --action=add-zone \ + --zone-name="$parent_zone"; then exit 1 fi - if ! /opt/vyatta/sbin/vyatta-zone.pl --action=add-zone --zone-name="$VAR(@)"; then + if ! /opt/vyatta/sbin/vyatta-zone-ips.pl \ + --action=add-zone \ + --zone-name="$VAR(@)"; then exit 1 fi fi diff --git a/templates-cfg/zone-policy/zone/node.tag/from/node.tag/content-inspection/.ipv6-enable/node.def b/templates-cfg/zone-policy/zone/node.tag/from/node.tag/content-inspection/.ipv6-enable/node.def new file mode 100644 index 0000000..87a2ea1 --- /dev/null +++ b/templates-cfg/zone-policy/zone/node.tag/from/node.tag/content-inspection/.ipv6-enable/node.def @@ -0,0 +1,46 @@ +help: Option to enable IPv6 content-inspection + +# check if traffic-filter is set +commit:expression: +exec " +if cli-shell-api existsEffective \ +content-inspection traffic-filter ipv6-preset; then \ + exit 0; \ +fi; \ +if cli-shell-api existsEffective \ +content-inspection traffic-filter ipv6-custom; then \ + exit 0; \ +fi; \ +echo IPv6 content-inspection traffic-filter not set; \ +exit 1" + +# make sure inspect-all is not enabled +commit:expression: +exec " +if ! cli-shell-api existsEffective \ +content-inspection inspect-all ipv6-enable; then \ + exit 0; \ +fi; \ +echo IPv6 content-inspection enabled for all traffic. Not \ +allowed to configure inspection on a per-zone basis.; \ +exit 1" + +create: + if ! /opt/vyatta/sbin/vyatta-zone-ips.pl \ + --action=add-fromzone-ips \ + --zone-name="$VAR(../../../@)" \ + --from-zone="$VAR(../../@)" \ + --ruleset-type=ipv6-name \ + --ruleset-name=VYATTA_SNORT_all_HOOK; then + exit 1 + fi + +delete: + if ! /opt/vyatta/sbin/vyatta-zone-ips.pl \ + --action=delete-fromzone-ips \ + --zone-name="$VAR(../../../@)" \ + --from-zone="$VAR(../../@)" \ + --ruleset-type=ipv6-name \ + --ruleset-name=VYATTA_SNORT_all_HOOK; then + exit 1 + fi diff --git a/templates-cfg/zone-policy/zone/node.tag/from/node.tag/content-inspection/enable/node.def b/templates-cfg/zone-policy/zone/node.tag/from/node.tag/content-inspection/enable/node.def new file mode 100644 index 0000000..484780a --- /dev/null +++ b/templates-cfg/zone-policy/zone/node.tag/from/node.tag/content-inspection/enable/node.def @@ -0,0 +1,46 @@ +help: Option to enable IPv4 content-inspection + +# check if traffic-filter is set +commit:expression: +exec " +if cli-shell-api existsEffective \ +content-inspection traffic-filter preset; then \ + exit 0; \ +fi; \ +if cli-shell-api existsEffective \ +content-inspection traffic-filter custom; then \ + exit 0; \ +fi; \ +echo IPv4 content-inspection traffic-filter not set; \ +exit 1" + +# make sure inspect-all is not enabled +commit:expression: +exec " +if ! cli-shell-api existsEffective \ +content-inspection inspect-all enable; then \ + exit 0; \ +fi; \ +echo IPv4 content-inspection enabled for all traffic. Not \ +allowed to configure inspection on a per-zone basis.; \ +exit 1" + +create: + if ! /opt/vyatta/sbin/vyatta-zone-ips.pl \ + --action=add-fromzone-ips \ + --zone-name="$VAR(../../../@)" \ + --from-zone="$VAR(../../@)" \ + --ruleset-type=name \ + --ruleset-name=VYATTA_SNORT_all_HOOK; then + exit 1 + fi + +delete: + if ! /opt/vyatta/sbin/vyatta-zone-ips.pl \ + --action=delete-fromzone-ips \ + --zone-name="$VAR(../../../@)" \ + --from-zone="$VAR(../../@)" \ + --ruleset-type=name \ + --ruleset-name=VYATTA_SNORT_all_HOOK; then + exit 1 + fi diff --git a/templates-cfg/zone-policy/zone/node.tag/from/node.tag/content-inspection/node.def b/templates-cfg/zone-policy/zone/node.tag/from/node.tag/content-inspection/node.def new file mode 100644 index 0000000..9ba25ef --- /dev/null +++ b/templates-cfg/zone-policy/zone/node.tag/from/node.tag/content-inspection/node.def @@ -0,0 +1 @@ +help: Content-inspection options diff --git a/templates-cfg/zone-policy/zone/node.tag/interface/node.def b/templates-cfg/zone-policy/zone/node.tag/interface/node.def index 36ff3e2..c9137c4 100644 --- a/templates-cfg/zone-policy/zone/node.tag/interface/node.def +++ b/templates-cfg/zone-policy/zone/node.tag/interface/node.def @@ -8,17 +8,35 @@ syntax:expression: $VAR(@) != "lo" ; "Cannot assign loopback interface to a tran create: /opt/vyatta/sbin/vyatta-interfaces.pl --dev=$VAR(@) --warn create: - if ! /opt/vyatta/sbin/vyatta-zone.pl \ - --action=add-zone-interface \ - --zone-name="$VAR(../@)" \ - --interface="$VAR(@)"; then + # fw zone actions + if ! /opt/vyatta/sbin/vyatta-zone.pl \ + --action=add-zone-interface \ + --zone-name="$VAR(../@)" \ + --interface="$VAR(@)"; then + exit 1 + fi + + # ips zone actions + if ! /opt/vyatta/sbin/vyatta-zone-ips.pl \ + --action=add-zone-interface \ + --zone-name="$VAR(../@)" \ + --interface="$VAR(@)"; then exit 1 fi delete: - if ! /opt/vyatta/sbin/vyatta-zone.pl \ - --action=delete-zone-interface \ - --zone-name="$VAR(../@)" \ - --interface="$VAR(@)"; then + # fw zone actions + if ! /opt/vyatta/sbin/vyatta-zone.pl \ + --action=delete-zone-interface \ + --zone-name="$VAR(../@)" \ + --interface="$VAR(@)"; then + exit 1 + fi + + # ips zone actions + if ! /opt/vyatta/sbin/vyatta-zone-ips.pl \ + --action=delete-zone-interface \ + --zone-name="$VAR(../@)" \ + --interface="$VAR(@)"; then exit 1 fi diff --git a/templates-cfg/zone-policy/zone/node.tag/local-zone/node.def b/templates-cfg/zone-policy/zone/node.tag/local-zone/node.def index 4db0f63..07c3d55 100644 --- a/templates-cfg/zone-policy/zone/node.tag/local-zone/node.def +++ b/templates-cfg/zone-policy/zone/node.tag/local-zone/node.def @@ -1,15 +1,31 @@ help: Zone to be local-zone create: - if ! /opt/vyatta/sbin/vyatta-zone.pl \ - --action=add-localzone \ - --zone-name="$VAR(../@)"; then + # fw zone actions + if ! /opt/vyatta/sbin/vyatta-zone.pl \ + --action=add-localzone \ + --zone-name="$VAR(../@)"; then + exit 1 + fi + + # ips zone actions + if ! /opt/vyatta/sbin/vyatta-zone-ips.pl \ + --action=add-localzone \ + --zone-name="$VAR(../@)"; then exit 1 fi delete: - if ! /opt/vyatta/sbin/vyatta-zone.pl \ - --action=delete-localzone \ - --zone-name="$VAR(../@)"; then + # fw zone actions + if ! /opt/vyatta/sbin/vyatta-zone.pl \ + --action=delete-localzone \ + --zone-name="$VAR(../@)"; then + exit 1 + fi + + # ips zone actions + if ! /opt/vyatta/sbin/vyatta-zone-ips.pl \ + --action=delete-localzone \ + --zone-name="$VAR(../@)"; then exit 1 fi |