diff options
author | Bob Gilligan <gilligan@sydney.vyatta.com> | 2007-12-10 17:40:27 -0800 |
---|---|---|
committer | Bob Gilligan <gilligan@sydney.vyatta.com> | 2007-12-10 17:40:27 -0800 |
commit | a6d5039dd4936734b0a28d04a1e497280a342491 (patch) | |
tree | 880fc1a49a87850129c1b8be50f97646cf79cd86 /scripts | |
download | vyatta-cfg-firewall-a6d5039dd4936734b0a28d04a1e497280a342491.tar.gz vyatta-cfg-firewall-a6d5039dd4936734b0a28d04a1e497280a342491.zip |
Initial setup of vyatta-cfg-firewall package.
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/firewall/VyattaIpTablesAddressFilter.pm | 250 | ||||
-rw-r--r-- | scripts/firewall/VyattaIpTablesRule.pm | 262 | ||||
-rwxr-xr-x | scripts/firewall/firewall.init | 45 | ||||
-rw-r--r-- | scripts/firewall/firewall.tp | 557 | ||||
-rwxr-xr-x | scripts/firewall/vyatta-firewall.pl | 374 | ||||
-rwxr-xr-x | scripts/firewall/vyatta-show-firewall.pl | 90 |
6 files changed, 1578 insertions, 0 deletions
diff --git a/scripts/firewall/VyattaIpTablesAddressFilter.pm b/scripts/firewall/VyattaIpTablesAddressFilter.pm new file mode 100644 index 0000000..4747e5e --- /dev/null +++ b/scripts/firewall/VyattaIpTablesAddressFilter.pm @@ -0,0 +1,250 @@ +package VyattaIpTablesAddressFilter; + +use VyattaConfig; + +my %_protocolswithports = ( + tcp => 1, + udp => 1, + 6 => 1, + 17 => 1, +); + +my %fields = ( + _srcdst => undef, + _range_start => undef, + _range_stop => undef, + _network => undef, + _address => undef, + _portname => undef, + _portrange_start => undef, + _portrange_stop => undef, + _portnumber => undef, + _protocol => undef, + _src_mac => undef, +); + +sub new { + my $that = shift; + my $class = ref ($that) || $that; + my $self = { + %fields, + }; + + bless $self, $class; + return $self; +} + +sub setup { + my ($self, $level) = @_; + my $config = new VyattaConfig; + + $config->setLevel("$level"); + + # setup needed parent nodes + $self->{_srcdst} = $config->returnParent(".."); + $self->{_protocol} = $config->returnValue(".. protocol"); + + # setup address filter nodes + $self->{_range_start} = $config->returnValue("range start"); + $self->{_range_stop} = $config->returnValue("range stop"); + $self->{_network} = $config->returnValue("network"); + $self->{_address} = $config->returnValue("address"); + my @tmp = $config->returnValues("port-number"); + $self->{_portnumber} = [ @tmp ]; + @tmp = $config->returnValues("port-name"); + $self->{_portname} = [ @tmp ]; + $self->{_portrange_start} = $config->returnValue("port-range start"); + $self->{_portrange_stop} = $config->returnValue("port-range stop"); + + $self->{_src_mac} = $config->returnValue("mac-address"); + + return 0; +} + +sub setupOrig { + my ($self, $level) = @_; + my $config = new VyattaConfig; + + $config->setLevel("$level"); + + # setup needed parent nodes + $self->{_srcdst} = $config->returnParent(".."); + $self->{_protocol} = $config->returnOrigValue(".. protocol"); + + # setup address filter nodes + $self->{_range_start} = $config->returnOrigValue("range start"); + $self->{_range_stop} = $config->returnOrigValue("range stop"); + $self->{_network} = $config->returnOrigValue("network"); + $self->{_address} = $config->returnOrigValue("address"); + my @tmp = $config->returnOrigValues("port-number"); + $self->{_portnumber} = [ @tmp ]; + @tmp = $config->returnOrigValues("port-name"); + $self->{_portname} = [ @tmp ]; + $self->{_portrange_start} = $config->returnOrigValue("port-range start"); + $self->{_portrange_stop} = $config->returnOrigValue("port-range stop"); + + $self->{_src_mac} = $config->returnValue("mac-address"); + + return 0; +} + +sub print { + my ($self) = @_; + + print "srcdst: $self->{_srcdst}\n" if defined $self->{_srcdst}; + print "range start: $self->{_range_start}\n" if defined $self->{_range_start}; + print "range stop: $self->{_range_stop}\n" if defined $self->{_range_stop}; + print "network: $self->{_network}\n" if defined $self->{_network}; + print "address: $self->{_address}\n" if defined $self->{_address}; + print "port-name: " . (join ',', $self->{_portname}) . "\n" + if defined $self->{_portname}; + print "port-range start: $self->{_portrange_start}\n" if defined $self->{_portrange_start}; + print "port-range stop: $self->{_portrange_stop}\n" if defined $self->{_portrange_stop}; + print "port-number: " . (join ',', $self->{_portnumber}) . "\n" + if defined $self->{_portnumber}; + print "protocol: $self->{_protocol}\n" if defined $self->{_protocol}; + print "src-mac: $self->{_src_mac}\n" if defined $self->{_src_mac}; + + return 0; +} + +sub handle_ports { + my $num_ref = shift; + my $name_ref = shift; + my $pstart = shift; + my $pstop = shift; + my $can_use_port = shift; + my $prefix = shift; + my $proto = shift; + + my $rule_str = ""; + my ($ports, $prange) = (0, 0); + my @pnums = @{$num_ref}; + my @pnames = @{$name_ref}; + $ports = ($#pnums + 1) + ($#pnames + 1); + + if (defined($pstart) && defined($pstop)) { + if ($pstop < $pstart) { + return (undef, "invalid port range $pstart-$pstop"); + } + $ports += ($pstop - $pstart + 1); + $prange = ($pstop - $pstart - 1); + } + if (($ports > 0) && (!$can_use_port)) { + return (undef, "ports can only be specified when protocol is \"tcp\" " + . "or \"udp\" (currently \"$proto\")"); + } + if (($ports - $prange) > 15) { + return (undef, "source/destination port specification only supports " + . "up to 15 ports (port range counts as 2)"); + } + if ($ports > 1) { + $rule_str .= " -m multiport --${prefix}ports "; + my $first = 1; + if ($#pnums >= 0) { + my $pstr = join(',', @pnums); + $rule_str .= "$pstr"; + $first = 0; + } + if ($#pnames >= 0) { + if ($first == 0) { + $rule_str .= ","; + } + my $pstr = join(',', @pnames); + $rule_str .= "$pstr"; + $first = 0; + } + if (defined($pstart) && defined($pstop)) { + if ($first == 0) { + $rule_str .= ","; + } + if ($pstart == $pstop) { + $rule_str .= "$pstart"; + } else { + $rule_str .= "$pstart:$pstop"; + } + $first = 0; + } + } elsif ($ports > 0) { + $rule_str .= " --${prefix}port "; + if ($#pnums >= 0) { + $rule_str .= "$pnums[0]"; + } elsif ($#pnames >= 0) { + $rule_str .= "$pnames[0]"; + } else { + # no number, no name, range of 1 + $rule_str .= "$pstart"; + } + } + return ($rule_str, undef); +} + +sub rule { + my ($self) = @_; + my $rule = ""; + my $can_use_port = 1; + + if (!defined($self->{_protocol}) + || !defined($_protocolswithports{$self->{_protocol}})) { + $can_use_port = 0; + } + + if (($self->{_srcdst} eq "source") && (defined($self->{_src_mac}))) { + # handle src mac + my $str = $self->{_src_mac}; + $str =~ s/^\!(.*)$/! $1/; + $rule .= "-m mac --mac-source $str "; + } + + # set the address filter parameters + if (defined($self->{_network})) { + my $str = $self->{_network}; + $str =~ s/^\!(.*)$/! $1/; + $rule .= "--$self->{_srcdst} $str "; + } elsif (defined($self->{_address})) { + my $str = $self->{_address}; + $str =~ s/^\!(.*)$/! $1/; + $rule .= "--$self->{_srcdst} $str "; + } elsif ((defined $self->{_range_start}) && (defined $self->{_range_stop})) { + if ("$self->{_srcdst}" eq "source") { + $rule .= ("-m iprange " + . "--src-range $self->{_range_start}-$self->{_range_stop} "); + } + elsif ("$self->{_srcdst}" eq "destination") { + $rule .= ("-m iprange " + . "--dst-range $self->{_range_start}-$self->{_range_stop} "); + } + } + + my ($port_str, $port_err) + = handle_ports($self->{_portnumber}, + $self->{_portname}, + $self->{_portrange_start}, + $self->{_portrange_stop}, + $can_use_port, + ($self->{_srcdst} eq "source") ? "s" : "d", + $self->{_protocol}); + return (undef, $port_err) if (!defined($port_str)); + $rule .= $port_str; + return ($rule, undef); +} + +sub outputXmlElem { + my ($name, $value, $fh) = @_; + print $fh " <$name>$value</$name>\n"; +} + +sub outputXml { + my ($self, $prefix, $fh) = @_; + outputXmlElem("${prefix}_addr", $self->{_address}, $fh); + outputXmlElem("${prefix}_net", $self->{_network}, $fh); + outputXmlElem("${prefix}_addr_start", $self->{_range_start}, $fh); + outputXmlElem("${prefix}_addr_stop", $self->{_range_stop}, $fh); + outputXmlElem("${prefix}_port_num", + (join ',', @{$self->{_portnumber}}), $fh); + outputXmlElem("${prefix}_port_name", + (join ',', @{$self->{_portname}}), $fh); + outputXmlElem("${prefix}_port_start", $self->{_portrange_start}, $fh); + outputXmlElem("${prefix}_port_stop", $self->{_portrange_stop}, $fh); +} + diff --git a/scripts/firewall/VyattaIpTablesRule.pm b/scripts/firewall/VyattaIpTablesRule.pm new file mode 100644 index 0000000..c2174c4 --- /dev/null +++ b/scripts/firewall/VyattaIpTablesRule.pm @@ -0,0 +1,262 @@ +package VyattaIpTablesRule; + +use VyattaConfig; +use VyattaIpTablesAddressFilter; + +my $src = new VyattaIpTablesAddressFilter; +my $dst = new VyattaIpTablesAddressFilter; + +my %fields = ( + _name => undef, + _rule_number => undef, + _protocol => undef, + _state => { + _established => undef, + _new => undef, + _related => undef, + _invalid => undef, + }, + _action => undef, + _log => undef, + _icmp_code => undef, + _icmp_type => undef, +); + +my %dummy_rule = ( + _rule_number => 1025, + _protocol => "all", + _state => { + _established => undef, + _new => undef, + _related => undef, + _invalid => undef, + }, + _action => "DROP", + _log => undef, + _icmp_code => undef, + _icmp_type => undef, +); + +sub new { + my $that = shift; + my $class = ref ($that) || $that; + my $self = { + %fields, + }; + + bless $self, $class; + return $self; +} + +sub setupDummy { + my $self = shift; + %{$self} = %dummy_rule; + $src = new VyattaIpTablesAddressFilter; + $dst = new VyattaIpTablesAddressFilter; +} + +sub setup { + my ( $self, $level ) = @_; + my $config = new VyattaConfig; + + $config->setLevel("$level"); + + # for documentation sake. nodes returns an array so must transform + # and ".. .. .." means go up three levels in the current hierarchy + $self->{_name} = $config->returnParent(".. .. .."); + $self->{_rule_number} = $config->returnParent(".."); + + $self->{_protocol} = $config->returnValue("protocol"); + $self->{_state}->{_established} = $config->returnValue("state established"); + $self->{_state}->{_new} = $config->returnValue("state new"); + $self->{_state}->{_related} = $config->returnValue("state related"); + $self->{_state}->{_invalid} = $config->returnValue("state invalid"); + $self->{_action} = $config->returnValue("action"); + $self->{_log} = $config->returnValue("log"); + $self->{_icmp_code} = $config->returnValue("icmp code"); + $self->{_icmp_type} = $config->returnValue("icmp type"); + + # TODO: need $config->exists("$level source") in VyattaConfig.pm + $src->setup("$level source"); + $dst->setup("$level destination"); + + return 0; +} + +sub setupOrig { + my ( $self, $level ) = @_; + my $config = new VyattaConfig; + + $config->setLevel("$level"); + + # for documentation sake. nodes returns an array so must transform + # and ".. .. .." means go up three levels in the current hierarchy + $self->{_name} = $config->returnParent(".. .. .."); + $self->{_rule_number} = $config->returnParent(".."); + + $self->{_protocol} = $config->returnOrigValue("protocol"); + $self->{_state}->{_established} + = $config->returnOrigValue("state established"); + $self->{_state}->{_new} = $config->returnOrigValue("state new"); + $self->{_state}->{_related} = $config->returnOrigValue("state related"); + $self->{_state}->{_invalid} = $config->returnOrigValue("state invalid"); + $self->{_action} = $config->returnOrigValue("action"); + $self->{_log} = $config->returnOrigValue("log"); + $self->{_icmp_code} = $config->returnOrigValue("icmp code"); + $self->{_icmp_type} = $config->returnOrigValue("icmp type"); + + # TODO: need $config->exists("$level source") in VyattaConfig.pm + $src->setupOrig("$level source"); + $dst->setupOrig("$level destination"); + + return 0; +} + +sub print { + my ( $self ) = @_; + + print "name: $self->{_name}\n" if defined $self->{_name}; + print "rulenum: $self->{_rule_number}\n" if defined $self->{_rule_number}; + print "protocol: $self->{_protocol}\n" if defined $self->{_protocol}; + print "state: $self->{_state}\n" if defined $self->{_state}; + print "action: $self->{_action}\n" if defined $self->{_action}; + print "log: $self->{_log}\n" if defined $self->{_log}; + print "icmp code: $self->{_icmp_code}\n" if defined $self->{_icmp_code}; + print "icmp type: $self->{_icmp_type}\n" if defined $self->{_icmp_type}; + + $src->print(); + $dst->print(); + +} + +sub is_stateful { + my $self = shift; + my @states = qw(established new related invalid); + foreach (@states) { + if (defined($self->{_state}->{"_$_"}) + && $self->{_state}->{"_$_"} eq "enable") { + return 1; + } + } + return 0; +} + +sub get_state_str { + my $self = shift; + my @states = qw(established new related invalid); + my @add_states = (); + foreach (@states) { + if (defined($self->{_state}->{"_$_"}) + && $self->{_state}->{"_$_"} eq "enable") { + push @add_states, $_; + } + } + if ($#add_states >= 0) { + my $str = join ',', @add_states; + return $str; + } else { + return ""; + } +} + +sub get_num_ipt_rules { + my $self = shift; + my $ipt_rules = 1; + if (("$self->{_log}" eq "enable") && (("$self->{_action}" eq "drop") + || ("$self->{_action}" eq "accept") + || ("$self->{_action}" eq "reject"))) { + $ipt_rules += 1; + } + return $ipt_rules; +} + +sub rule { + my ( $self ) = @_; + my $rule = undef; + my $srcrule = $dstrule = undef; + my $err_str = undef; + + # set the protocol + if (defined($self->{_protocol})) { + my $str = $self->{_protocol}; + $str =~ s/^\!(.*)$/! $1/; + $rule .= "--protocol $str "; + } + + # set the session state if protocol tcp + my $state_str = uc (get_state_str($self)); + if ($state_str ne "") { + $rule .= "-m state --state $state_str "; + } + + # set the icmp code and type if applicable + if (($self->{_protocol} eq "icmp") || ($self->{_protocol} eq "1")) { + if (defined $self->{_icmp_type}) { + $rule .= "--icmp-type $self->{_icmp_type}"; + if (defined $self->{_icmp_code}) { + $rule .= "/$self->{_icmp_code}"; + } + $rule .= " "; + } elsif (defined $self->{_icmp_code}) { + return ("ICMP code can only be defined if ICMP type is defined", ); + + } + } elsif (defined($self->{_icmp_type}) || defined($self->{_icmp_code})) { + return ("ICMP type/code can only be defined if protocol is ICMP", ); + } + + # add the source and destination rules + ($srcrule, $err_str) = $src->rule(); + return ($err_str, ) if (!defined($srcrule)); + ($dstrule, $err_str) = $dst->rule(); + return ($err_str, ) if (!defined($dstrule)); + $rule .= " $srcrule $dstrule "; + + my $chain = $self->{_name}; + my $rule_num = $self->{_rule_number}; + my $rule2 = undef; + # set the jump target. Depends on action and log + if ("$self->{_log}" eq "enable") { + $rule2 = $rule; + $rule2 .= "-j LOG --log-prefix '[$chain $rule_num $self->{_action}] ' "; + } + if ("$self->{_action}" eq "drop") { + $rule .= "-j DROP "; + } elsif ("$self->{_action}" eq "accept") { + $rule .= "-j RETURN "; + } elsif ("$self->{_action}" eq "reject") { + $rule .= "-j REJECT "; + } else { + return ("\"action\" must be defined", ); + } + if (defined($rule2)) { + my $tmp = $rule2; + $rule2 = $rule; + $rule = $tmp; + } + return (undef, $rule, $rule2, ); +} + +sub outputXmlElem { + my ($name, $value, $fh) = @_; + print $fh " <$name>$value</$name>\n"; +} + +sub outputXml { + my ($self, $fh) = @_; + outputXmlElem("protocol", $self->{_protocol}, $fh); + my $state_str = get_state_str($self); + if ($state_str ne "") { + $state_str =~ s/,/%2C/g; + $state_str .= "+"; + } + outputXmlElem("state", $state_str, $fh); + outputXmlElem("action", uc($self->{_action}), $fh); + outputXmlElem("log", $self->{_log}, $fh); + outputXmlElem("icmp_type", $self->{_icmp_type}, $fh); + outputXmlElem("icmp_code", $self->{_icmp_code}, $fh); + + $src->outputXml("src", $fh); + $dst->outputXml("dst", $fh); +} + diff --git a/scripts/firewall/firewall.init b/scripts/firewall/firewall.init new file mode 100755 index 0000000..b58d4d5 --- /dev/null +++ b/scripts/firewall/firewall.init @@ -0,0 +1,45 @@ +#!/bin/sh + +# source the shared functions +. /etc/init.d/vyatta-functions + +ACTION=$1 + +start() { + echo -n "Initializing firewall: " + # progress_indicator "start" $INIT_PID + + OUTPUT=`/opt/vyatta/sbin/vyatta-firewall.pl --setup 2>&1`; + # progress_indicator "stop" $INIT_PID + + echo "OK" +} + +stop() { + echo -n "Reseting firewall: " + # progress_indicator "start" $INIT_PID + OUTPUT=`/opt/vyatta/sbin/vyatta-firewall.pl --setup 2>&1`; + + # progress_indicator "stop" $INIT_PID + echo "OK" +} + +case "$ACTION" in + start) + start + ;; + stop) + stop + ;; + restart) + stop + start + ;; + *) + echo "usage: $0 {start|stop|restart}" + exit 1 + ;; +esac + +exit 0 + diff --git a/scripts/firewall/firewall.tp b/scripts/firewall/firewall.tp new file mode 100644 index 0000000..08d2cbe --- /dev/null +++ b/scripts/firewall/firewall.tp @@ -0,0 +1,557 @@ +/* + * Module: firewall.tp + * + * **** License **** + * Version: VPL 1.0 + * + * The contents of this file are subject to the Vyatta Public License + * Version 1.0 ("License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.vyatta.com/vpl + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * This code was originally developed by Vyatta, Inc. + * Portions setd by Vyatta are Copyright (C) 2005, 2006, 2007 Vyatta, Inc. + * All Rights Reserved. + * + * Author: Michael Larson + * Date: 2005 + * Description: + * + * **** End License **** + * + */ +firewall { + targetname: txt = "rl_firewall"; +/* disable: toggle = true;*/ + + log-martians: txt = "enable"; + send-redirects: txt = "disable"; + receive-redirects:txt = "disable"; + ip-src-route: txt = "disable"; + broadcast-ping: txt = "disable"; + syn-cookies: txt = "enable"; + + name @: txt { + description: txt; + rule @: u32 { + protocol: txt = "all"; + icmp { + type: txt; + code: txt; + } + + state { + established: txt; + new: txt; + related: txt; + invalid: txt; + } + + action: txt; + log: txt = "disable"; + + source { + address: ipv4; + network: ipv4net; + range { + start: ipv4; + stop: ipv4; + } + + port-number: u32; + port-name: txt; + port-range { + start: u32; + stop: u32; + } + + } + destination { + address: ipv4; + network: ipv4net; + range { + start: ipv4; + stop: ipv4; + } + + port-number: u32; + port-name: txt; + port-range { + start: u32; + stop: u32; + } + } + } + } +} + +interfaces { + ethernet @: txt { + firewall { + + in { + name: txt; + } + out { + name: txt; + } + local { + name: txt; + } + } + + vif @: txt { + firewall { + in { + name: txt; + } + out { + name: txt; + } + local { + name: txt; + } + } + } + } +} + +firewall { + %help: short "Firewall configuration"; + %modinfo: provides firewall; + + %modinfo: path "libexec/xorp/xorp_rl_firewall"; + %modinfo: default_targetname "rl_firewall"; + %modinfo: start_commit program "/opt/vyatta/sbin/xorp_tmpl_tool cleanup"; + %modinfo: end_commit program "/opt/vyatta/sbin/xorp_tmpl_tool commit"; + %modinfo: status_method xrl "$(firewall.targetname)/common/0.1/get_status->status:u32&reason:txt"; + /* + %modinfo: shutdown_method xrl "$(firewall.targetname)/rl_firewall/0.1/shutdown_firewall"; + */ + %modinfo: shutdown_method program "/opt/vyatta/sbin/xorp_tmpl_tool cleanup && /opt/vyatta/sbin/xorp_tmpl_tool delete firewall && /opt/vyatta/sbin/xorp_tmpl_tool commit && /opt/vyatta/sbin/xorp_tmpl_tool rtrmgr_indirect_cleanup"; + + /* + %delete: xrl "$(firewall.targetname)/rl_firewall/0.1/delete_rl_firewall"; + */ + %delete: ; + + targetname { + %user-hidden: "XRL target name"; + %help: short "Set the target name"; + } + + log-martians { + %help: short "Configure log martians"; + %allow: $(@) "enable" %help: "Enable log martians"; + %allow: $(@) "disable" %help: "Disable log martians"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall log-martians $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall log-martians"; + } + + send-redirects { + %help: short "Configure send redirects"; + %allow: $(@) "enable" %help: "Enable send redirects"; + %allow: $(@) "disable" %help: "Disable send redirects"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall send-redirects $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall send-redirects"; + } + + receive-redirects { + %help: short "Configure receive redirects"; + %allow: $(@) "enable" %help: "Enable receive redirects"; + %allow: $(@) "disable" %help: "Disable receive redirects"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall receive-redirects $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall receive-redirects"; + } + + ip-src-route { + %help: short "Configure IP source route"; + %allow: $(@) "enable" %help: "Enable IP source route"; + %allow: $(@) "disable" %help: "Disable IP source route"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall ip-src-route $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall ip-src-route"; + } + + broadcast-ping { + %help: short "Configure broadcast ping"; + %allow: $(@) "enable" %help: "Enable broadcast ping"; + %allow: $(@) "disable" %help: "Disable broadcast ping"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall broadcast-ping $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall broadcast-ping"; + } + + syn-cookies { + %help: short "Configure SYN cookies"; + %allow: $(@) "enable" %help: "Enable SYN cookies"; + %allow: $(@) "disable" %help: "Disable SYN cookies"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall syn-cookies $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall syn-cookies"; + } + name @: txt { + %help: short "Configure firewall rule set name"; + + %create: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name '$(@)'"; + %update: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name '$(@)'"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name '$(@)'"; + + description { + %help: short "Firewall description"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) description '$(@)'"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) description"; + + } + + rule @: u32 { + %help: short "Firewall rule number in range from 1 to 1024"; + %order: sorted-numeric; + %allow-range: $(@) "1" "1024" %help: "Firewall rule number"; + + %create: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(@)"; + %update: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(@)"; + + protocol { + %help: short "Configure Protocol"; + %allow: $(@) "all" %help: ""; + %allow: $(@) "tcp" %help: ""; + %allow: $(@) "udp" %help: ""; + %allow: $(@) "icmp" %help: ""; + %allow: $(@) "igmp" %help: ""; + %allow: $(@) "ipencap" %help: ""; + %allow: $(@) "gre" %help: ""; + %allow: $(@) "esp" %help: ""; + %allow: $(@) "ah" %help: ""; + %allow: $(@) "ospf" %help: ""; + %allow: $(@) "pim" %help: ""; + %allow: $(@) "vrrp" %help: ""; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) protocol $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) protocol"; + } + + icmp { + %help: short "ICMP type and code settings"; + %mandatory: $(@.type); + + type { + %help: short "ICMP type"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) icmp type $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) icmp type"; + } + + code { + %help: short "ICMP code"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) icmp code $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) icmp code"; + } + } + + state { + %help: short "Rule state"; + + established { + %help: short "Configure established state"; + %allow: $(@) "enable" %help: "Enable established state"; + %allow: $(@) "disable" %help: "Disable established state"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) state established $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) state established"; + } + + new { + %help: short "Configure new state"; + %allow: $(@) "enable" %help: "Enable new state"; + %allow: $(@) "disable" %help: "Disable new state"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) state new $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) state new"; + } + + related { + %help: short "Configure related state"; + %allow: $(@) "enable" %help: "Enable related state"; + %allow: $(@) "disable" %help: "Disable related state"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) state related $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) state related"; + } + + invalid { + %help: short "Configure invalid state"; + %allow: $(@) "enable" %help: "Enable invalid state"; + %allow: $(@) "disable" %help: "Disable invalid state"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) state invalid $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) state invalid"; + } + } + + action { + %help: short "Configure rule action"; + %allow: $(@) "accept" %help: "Accept packet"; + %allow: $(@) "drop" %help: "Silently drop packet"; + %allow: $(@) "reject" %help: "Reject packet with TCP reset"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) action $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) action"; + } + + log { + %help: short "Configure firewall logging"; + %allow: $(@) "enable" %help: "Enable firewall logging"; + %allow: $(@) "disable" %help: "Disable firewall logging"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) log $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) log"; + } + + source { + %help: short "Firewall source parameters"; + + address { + %help: short "Source address"; + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) source address $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) source address"; + } + + network { + %help: short "Source network"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) source network $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) source network"; + } + range { + %mandatory: $(@.start); + %mandatory: $(@.stop); + %help: short "Source range start and stop"; + + start { + %help: short "Source range start"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) source range start $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) source range start"; + } + stop { + %help: short "Source range stop"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) source range stop $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) source range stop"; + } + } + + port-number { + %help: short "Source port number"; + %allow-range: $(@) "1" "65535" %help: ""; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) source port-number $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) source port-number"; + } + + port-name { + %help: short "Source port name"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) source port-name $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) source port-name"; + } + + port-range { + %help: short "Source port range start and stop"; + %mandatory: $(@.start); + %mandatory: $(@.stop); + + start { + %help: short "Source port range start"; + %allow-range: $(@) "1" "65535" %help: ""; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) source port-range start $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) source port-range start"; + + } + stop { + %help: short "Source port range stop"; + %allow-range: $(@) "1" "65535" %help: ""; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) source port-range stop $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) source port-range stop"; + } + } + } + destination { + %help: short "Firewall destination parameters"; + + address { + %help: short "Destination address"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) destination address $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) destination address"; + } + + network { + %help: short "Destination network"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) destination network $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) destination network"; + } + + range { + %help: short "Destination range start and stop"; + %mandatory: $(@.start); + %mandatory: $(@.stop); + + start { + %help: short "Destination range start"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) destination range start $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) destination range start"; + } + + stop { + %help: short "Destination range stop"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) destination range stop $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) destination range stop"; + } + } + + port-number { + %help: short "Destination port number"; + %allow-range: $(@) "1" "65535" %help: ""; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) destination port-number $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) destination port-number"; + } + + port-name { + %help: short "Destination port name"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) destination port-name $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) destination port-name"; + } + + port-range { + %help: short "Port range start and stop"; + %mandatory: $(@.start); + %mandatory: $(@.stop); + + start { + %help: short "Destination port range start"; + %allow-range: $(@) "1" "65535" %help: ""; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) destination port-range start $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) destination port-range start"; + } + stop { + %help: short "Destination port range stop"; + %allow-range: $(@) "1" "65535" %help: ""; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) destination port-range stop $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) destination port-range stop"; + } + } + } + } + } +} + +interfaces { + ethernet @: txt { + firewall { + %help: short "Configure firewall options"; + + in { + %mandatory: $(@.name); + %help: short "Filter forwarded packets on inbound interface"; + + name { + %help: short "Inbound interface filter name"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set interfaces ethernet $(ethernet.@) firewall in name $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete interfaces ethernet $(ethernet.@) firewall in name"; + } + + } + + out { + %mandatory: $(@.name); + %help: short "Filter forwarded packets on outbound interface"; + + name { + %help: short "Outbound interface filter name"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set interfaces ethernet $(ethernet.@) firewall out name $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete interfaces ethernet $(ethernet.@) firewall out name"; + } + + } + + local { + %mandatory: $(@.name); + %help: short "Filter packets destined for this router"; + + name { + %help: short "Local filter name"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set interfaces ethernet $(ethernet.@) firewall local name $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete interfaces ethernet $(ethernet.@) firewall local name"; + } + + } + } + + vif @: txt { + firewall { + %help: short "Configure firewall options"; + + in { + %mandatory: $(@.name); + %help: short "Filter forwarded packets on inbound interface"; + + name { + %help: short "Inbound interface filter name"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set interfaces ethernet $(ethernet.@) vif $(vif.@) firewall in name $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete interfaces ethernet $(ethernet.@) vif $(vif.@) firewall in name"; + } + } + + out { + %mandatory: $(@.name); + %help: short "Filter forwarded packets on outbound interface"; + + name { + %help: short "Outbound interface filter name"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set interfaces ethernet $(ethernet.@) vif $(vif.@) firewall out name $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete interfaces ethernet $(ethernet.@) vif $(vif.@) firewall out name"; + } + } + + local { + %mandatory: $(@.name); + %help: short "Filter packets destined for this router"; + + name { + %help: short "Local filter name"; + + %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set interfaces ethernet $(ethernet.@) vif $(vif.@) firewall local name $(@)"; + %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete interfaces ethernet $(ethernet.@) vif $(vif.@) firewall local name"; + } + } + } + } + } +} diff --git a/scripts/firewall/vyatta-firewall.pl b/scripts/firewall/vyatta-firewall.pl new file mode 100755 index 0000000..93cbd09 --- /dev/null +++ b/scripts/firewall/vyatta-firewall.pl @@ -0,0 +1,374 @@ +#!/usr/bin/perl + +use lib "/opt/vyatta/share/perl5/"; +use VyattaConfig; +use VyattaIpTablesRule; +use VyattaIpTablesAddressFilter; +use Getopt::Long; + +my @updateints = (); +GetOptions("setup" => \$setup, + "teardown" => \$teardown, + "update-rules" => \$updaterules, + "update-interfaces=s{4}" => \@updateints, +); + +if (defined $setup) { + setup_iptables(); + exit 0; +} + +if (defined $updaterules) { + update_rules(); + exit 0; +} + +if ($#updateints == 3) { + update_ints(@updateints); + exit 0; +} + +if (defined $teardown) { + teardown_iptables(); + exit 0; +} + +help(); +exit 1; + +sub help() { + print "usage: vyatta-firewall.pl\n"; + print "\t--setup setup Vyatta specific iptables settings\n"; + print "\t--update-rules update iptables with the current firewall rules\n"; + print "\t--update-interfaces update the rules applpied to interfaces\n"; + print "\t (<action> <interface> <direction> <chain name>)\n"; + print "\t--teardown teardown all user rules and iptables settings\n"; + print "\n"; +} + +sub update_rules() { + my $config = new VyattaConfig; + my $name = undef; + my %nodes = (); + + $config->setLevel("firewall name"); + + %nodes = $config->listNodeStatus(); + if ((scalar (keys %nodes)) == 0) { + # no names. teardown the user chains and return. + teardown_iptables(); + return; + } + + # by default, nothing needs to be tracked. + my $stateful = 0; + + for $name (keys %nodes) { + if ($nodes{$name} eq "static") { + # not changed. check if stateful. + $config->setLevel("firewall name $name rule"); + my @rules = $config->listOrigNodes(); + foreach (sort numerically @rules) { + my $node = new VyattaIpTablesRule; + $node->setupOrig("firewall name $name rule $_"); + if ($node->is_stateful()) { + $stateful = 1; + last; + } + } + next; + } elsif ($nodes{$name} eq "added") { + # create the chain + print "creating chain $name\n"; + setup_chain("$name"); + # handle the rules below. + } elsif ($nodes{$name} eq "deleted") { + # delete the chain + print "deleting chain $name\n"; + delete_chain("$name"); + next; + } elsif ($nodes{$name} eq "changed") { + # handle the rules below. + } + + print "firewall name $name\n"; + #print "-----------------------------------------------\n"; + + # set our config level to rule and get the rule numbers + $config->setLevel("firewall name $name rule"); + + # Let's find the status of the rule nodes + my %rulehash = (); + %rulehash = $config->listNodeStatus(); + if ((scalar (keys %rulehash)) == 0) { + # no rules. flush the user rules. + # note that this clears the counters on the default DROP rule. + # we could delete rule one by one if those are important. + system("iptables -F $name"); + system("iptables -A $name -j DROP"); + next; + } + + my $iptablesrule = 1; + foreach $rule (sort numerically keys %rulehash) { + #print "rule: $rule\t\t$rulehash{$rule}\n"; + + if ("$rulehash{$rule}" eq "static") { + my $node = new VyattaIpTablesRule; + $node->setupOrig("firewall name $name rule $rule"); + if ($node->is_stateful()) { + $stateful = 1; + } + my $ipt_rules = $node->get_num_ipt_rules(); + $iptablesrule += $ipt_rules; + } elsif ("$rulehash{$rule}" eq "added") { + # create a new iptables object of the current rule + my $node = new VyattaIpTablesRule; + $node->setup("firewall name $name rule $rule"); + if ($node->is_stateful()) { + $stateful = 1; + } + + #print "node print:\n"; + #$node->print(); + my ($err_str, @rule_strs) = $node->rule(); + if (defined($err_str)) { + print STDERR "Firewall config error: $err_str\n"; + exit 1; + } + foreach (@rule_strs) { + if (!defined) { + last; + } + print "iptables --insert $name $iptablesrule $_\n"; + system ("iptables --insert $name $iptablesrule $_") == 0 + || die "iptables error: $? - $_\n"; + $iptablesrule++; + } + } elsif ("$rulehash{$rule}" eq "changed") { + # create a new iptables object of the current rule + my $oldnode = new VyattaIpTablesRule; + $oldnode->setupOrig("firewall name $name rule $rule"); + my $node = new VyattaIpTablesRule; + $node->setup("firewall name $name rule $rule"); + if ($node->is_stateful()) { + $stateful = 1; + } + + my ($err_str, @rule_strs) = $node->rule(); + if (defined($err_str)) { + print STDERR "Firewall config error: $err_str\n"; + exit 1; + } + + my $ipt_rules = $oldnode->get_num_ipt_rules(); + for (1 .. $ipt_rules) { + print "iptables --delete $name $iptablesrule\n"; + system ("iptables --delete $name $iptablesrule") == 0 + || die "iptables error: $? - $rule\n"; + } + + foreach (@rule_strs) { + if (!defined) { + last; + } + print "iptables --insert $name $iptablesrule $_\n"; + system ("iptables --insert $name $iptablesrule $_") == 0 + || die "iptables error: $? - $rule_str\n"; + $iptablesrule++; + } + } elsif ("$rulehash{$rule}" eq "deleted") { + my $node = new VyattaIpTablesRule; + $node->setupOrig("firewall name $name rule $rule"); + + my $ipt_rules = $node->get_num_ipt_rules(); + for (1 .. $ipt_rules) { + print "iptables --delete $name $iptablesrule\n"; + system ("iptables --delete $name $iptablesrule") == 0 + || die "iptables error: $? - $rule\n"; + } + } + } + } + if ($stateful) { + enable_fw_conntrack(); + } else { + disable_fw_conntrack(); + } +} + +sub chain_configured($) { + my $chain = shift; + + my $config = new VyattaConfig; + my %chains = (); + $config->setLevel("firewall name"); + %chains = $config->listNodeStatus(); + + if (grep(/^$chain$/, (keys %chains))) { + if ($chains{$chain} ne "deleted") { + return 1; + } + } + return 0; +} + +sub update_ints() { + my ($action, $int_name, $direction, $chain) = @_; + my $interface = undef; + + if (! defined $action || ! defined $int_name || ! defined $direction || ! defined $chain) { + return -1; + } + + if ($action eq "update") { + # make sure chain exists + setup_chain($chain); + } + + $_ = $direction; + my $dir_str = $direction; + + CASE: { + /^in/ && do { + $direction = "FORWARD"; + $interface = "--in-interface $int_name"; + last CASE; + }; + + /^out/ && do { + $direction = "FORWARD"; + $interface = "--out-interface $int_name"; + last CASE; + }; + + /^local/ && do { + $direction = "INPUT"; + $interface = "--in-interface $int_name"; + last CASE; + }; + } + + my $grep = "| grep $int_name"; + my $line = `iptables -L $direction -n -v --line-numbers | egrep ^[0-9] $grep`; + my ($num, $ignore, $ignore, $oldchain, $ignore, $ignore, $in, $out, $ignore, $ignore) = split /\s+/, $line; + + if ("$action" eq "update") { + if (($num =~ /.+/) && (($dir_str eq "in" && $in eq $int_name) + || ($dir_str eq "out" && $out eq $int_name) + || ($dir_str eq "local"))) { + $action = "replace"; + $rule = "--replace $direction $num $interface --jump $chain"; + } else { + $rule = "--append $direction $interface --jump $chain"; + } + } + else { + $rule = "--$action $direction $num"; + } + + print "iptables $rule\n"; + $ret = system("iptables $rule"); + if ($ret >> 8) { + exit 1; + } + if ($action eq "replace" || $action eq "delete") { + if (!chain_configured($oldchain)) { + if (!chain_referenced($oldchain)) { + delete_chain($oldchain); + } + } + } + return 0; +} + +sub enable_fw_conntrack { + # potentially we can add rules in the FW_CONNTRACK chain to provide + # finer-grained control over which packets are tracked. + system("iptables -t raw -R FW_CONNTRACK 1 -j ACCEPT"); +} + +sub disable_fw_conntrack { + system("iptables -t raw -R FW_CONNTRACK 1 -j RETURN"); +} + +sub teardown_iptables() { + my @chains = `iptables -L -n`; + my $chain; + + # $chain is going to look like this... + # Chain inbound (0 references) + foreach $chain (@chains) { + # chains start with Chain + if ($chain =~ s/^Chain//) { + # all we need to do is make sure this is a user chain + # by looking at the references keyword and then + if ($chain =~ /references/) { + ($chain) = split /\(/, $chain; + $chain =~ s/\s//g; + delete_chain("$chain"); + } + } + } + + # remove the conntrack setup. + my @lines + = `iptables -t raw -L PREROUTING -vn --line-numbers | egrep ^[0-9]`; + foreach (@lines) { + my ($num, $ignore, $ignore, $chain, $ignore, $ignore, $in, $out, + $ignore, $ignore) = split /\s+/; + if ($chain eq "FW_CONNTRACK") { + system("iptables -t raw -D PREROUTING $num"); + system("iptables -t raw -D OUTPUT $num"); + system("iptables -t raw -F FW_CONNTRACK"); + system("iptables -t raw -X FW_CONNTRACK"); + last; + } + } +} + +sub setup_iptables() { + teardown_iptables(); + # by default, nothing is tracked (the last rule in raw/PREROUTING). + system("iptables -t raw -N FW_CONNTRACK"); + system("iptables -t raw -A FW_CONNTRACK -j RETURN"); + system("iptables -t raw -I PREROUTING 1 -j FW_CONNTRACK"); + system("iptables -t raw -I OUTPUT 1 -j FW_CONNTRACK"); + return 0; +} + +sub setup_chain($) { + my $chain = shift; + my $configured = `iptables -n -L $chain 2>&1 | head -1`; + + $_ = $configured; + if (!/^Chain $chain/) { + system("iptables --new-chain $chain") == 0 || die "iptables error: $chain --new-chain: $?\n"; + system("iptables -A $chain -j DROP"); + } +} + +sub chain_referenced($) { + my $chain = shift; + my $line = `iptables -n -L $chain |head -n1`; + if ($line =~ m/^Chain $chain \((\d+) references\)$/) { + if ($1 > 0) { + return 1; + } + } + return 0; +} + +sub delete_chain($) { + my $chain = shift; + my $configured = `iptables -n -L $chain 2>&1 | head -1`; + + if ($configured =~ /^Chain $chain/) { + system("iptables --flush $chain") == 0 || die "iptables error: $chain --flush: $?\n"; + if (!chain_referenced($chain)) { + system("iptables --delete-chain $chain") == 0 || die "iptables error: $chain --delete-chain: $?\n"; + } + } +} + +sub numerically { $a <=> $b; } diff --git a/scripts/firewall/vyatta-show-firewall.pl b/scripts/firewall/vyatta-show-firewall.pl new file mode 100755 index 0000000..241a03a --- /dev/null +++ b/scripts/firewall/vyatta-show-firewall.pl @@ -0,0 +1,90 @@ +#!/usr/bin/perl + +use lib "/opt/vyatta/share/perl5/"; +use VyattaConfig; +use VyattaIpTablesRule; +use VyattaIpTablesAddressFilter; + +exit 1 if ($#ARGV < 1); +my $chain_name = $ARGV[0]; +my $xsl_file = $ARGV[1]; +my $rule_num = $ARGV[2]; # rule number to match (optional) + +sub numerically { $a <=> $b; } + +sub show_chain { + my $chain = shift; + my $fh = shift; + + open(STATS, "iptables -L $chain -vn |") or exit 1; + my @stats = (); + while (<STATS>) { + if (!/^\s*(\d+[KMG]?)\s+(\d+[KMG]?)\s/) { + next; + } + push @stats, ($1, $2); + } + close STATS; + + print $fh "<opcommand name='firewallrules'><format type='row'>\n"; + my $config = new VyattaConfig; + $config->setLevel("firewall name $chain rule"); + my @rules = sort numerically $config->listOrigNodes(); + foreach (@rules) { + # just take the stats from the 1st iptables rule and remove unneeded stats + # (if this rule corresponds to multiple iptables rules). note that + # depending on how our rule is translated into multiple iptables rules, + # this may actually need to be the sum of all corresponding iptables stats + # instead of just taking the first pair. + my $pkts = shift @stats; + my $bytes = shift @stats; + my $rule = new VyattaIpTablesRule; + $rule->setupOrig("firewall name $chain rule $_"); + my $ipt_rules = $rule->get_num_ipt_rules(); + splice(@stats, 0, (($ipt_rules - 1) * 2)); + + if (defined($rule_num) && $rule_num != $_) { + next; + } + print $fh " <row>\n"; + print $fh " <rule_number>$_</rule_number>\n"; + print $fh " <pkts>$pkts</pkts>\n"; + print $fh " <bytes>$bytes</bytes>\n"; + $rule->outputXml($fh); + print $fh " </row>\n"; + } + if (!defined($rule_num)) { + # dummy rule + print $fh " <row>\n"; + print $fh " <rule_number>1025</rule_number>\n"; + my $pkts = shift @stats; + my $bytes = shift @stats; + print $fh " <pkts>$pkts</pkts>\n"; + print $fh " <bytes>$bytes</bytes>\n"; + my $rule = new VyattaIpTablesRule; + $rule->setupDummy(); + $rule->outputXml($fh); + print $fh " </row>\n"; + } + print $fh "</format></opcommand>\n"; +} + +if ($chain_name eq "-all") { + my $config = new VyattaConfig; + $config->setLevel("firewall name"); + my @chains = $config->listOrigNodes(); + foreach (@chains) { + print "Firewall \"$_\":\n"; + open(RENDER, "| /opt/vyatta/libexec/xorp/render_xml $xsl_file") or exit 1; + show_chain($_, *RENDER{IO}); + close RENDER; + print "-" x 80 . "\n"; + } +} else { + open(RENDER, "| /opt/vyatta/libexec/xorp/render_xml $xsl_file") or exit 1; + show_chain($chain_name, *RENDER{IO}); + close RENDER; +} + +exit 0; + |