Extension Scripts

Tom Eastep

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover, and with no Back-Cover Texts. A copy of the license is included in the section entitled “GNU Free Documentation License”.

2009/06/17


Table of Contents

Extension Scripts
Shorewall-shell
Shorewall-perl

Caution

This article applies to Shorewall 4.0 and later. If you are running a version of Shorewall earlier than Shorewall 4.0.0 then please see the documentation for that release.

Extension Scripts

Extension scripts are user-provided scripts that are invoked at various points during firewall start, restart, stop and clear. The scripts are placed in /etc/shorewall and are processed using the Bourne shell “source” mechanism.

Caution

  1. Be sure that you actually need to use an extension script to do what you want. Shorewall has a wide range of features that cover most requirements.

  2. DO NOT SIMPLY COPY RULES THAT YOU FIND ON THE NET INTO AN EXTENSION SCRIPT AND EXPECT THEM TO WORK AND TO NOT BREAK SHOREWALL. TO USE SHOREWALL EXTENSION SCRIPTS YOU MUST KNOW WHAT YOU ARE DOING WITH RESPECT TO iptables/Netfilter AND SHOREWALL.

The following scripts can be supplied:

  • compile -- (Added in Shorewall-perl version 4.0.6). Invoked by the Shorewall-perl compiler early in the compilation process. Must be written in Perl.

  • init -- invoked early in “shorewall start” and “shorewall restart

  • initdone -- invoked after Shorewall has flushed all existing rules but before any rules have been added to the builtin chains.

  • start -- invoked after the firewall has been started or restarted. The script is also invoked by Shorewall-shell after a successful 'restore'.

  • started -- invoked after the firewall has been marked as 'running'. The script is also invoked by Shorewall-shell after a successful 'restore'.

  • stop -- invoked as a first step when the firewall is being stopped.

  • stopped -- invoked after the firewall has been stopped.

  • clear -- invoked after the firewall has been cleared.

  • tcclear -- invoked to clear traffic shaping when CLEAR_TC=Yes in shorewall.conf.

  • refresh -- invoked while the firewall is being refreshed but before the blacklst chains have been rebuilt.

  • refreshed -- invoked after the firewall has been refreshed.

  • continue -- invoked to allow you to insert special rules to allow traffic while Shorewall is [re]starting. Any rules added in this script should be deleted in your start script. This script is invoked earlier in the [re]start process than is the initdone script described above (Not used by Shorewall Perl).

  • maclog -- invoked while mac filtering rules are being created. It is invoked once for each interface having 'maclist' specified and it is invoked just before the logging rule is added to the current chain (the name of that chain will be in $CHAIN).

  • isusable -- (Added in Shorewall-perl version 4.0.3) invoked when Shorewall is trying to determine the usability of the network interface associated with an optional entry in /etc/shorewall/providers. $1 is the name of the interface which will have been determined to be up and configured before the script is invoked. The return value from the script indicates whether or not the interface is usable (0 = usable, other = unusable).

    Example:

    # Ping a gateway through the passed interface
    case $1 in
        eth0)
            ping -c 4 -t 1 -I eth0 206.124.146.254 > /dev/null 2>&1
            return
            ;;
        eth1)
            ping -c 4 -t 1 -I eth1 192.168.12.254 > /dev/null 2>&1
            return
            ;;
        *)
            # No additional testing of other interfaces
            return 0
            ;;
    esac

    Caution

    We recommend that this script only be used with ADMINISABSENTMINDED=Yes.

    The firewall state when this script is invoked is indeterminate. So if you have ADMINISABSENTMINDED=No in shorewall.conf(8) and output on an interface is not allowed by routestopped(8) then the isuasable script must blow it's own holes in the firewall before probing.

  • save -- (Added in Shorewall version 4.2.0 Beta2). This script is invoked during execution of the shorewall save and shorewall-lite save commands.

  • restored -- (Added in Shorewall-perl version 4.2.6). This script is invoked at the completion of a successful shorewall restore and shorewall-lite restore.

  • findgw -- (Added in Shorewall-perl version 4.2.10). This script is invoked when Shorewall is attempting to discover the gateway through a dynamic interface. The script is most often used when the interface is managed by dhclient which has no standardized location/name for its lease database. Scripts for use with dhclient on several distributions are available at http://www.shorewall.net/pub/shorewall/contrib/findgw/

If your version of Shorewall doesn't have the file that you want to use from the above list, you can simply create the file yourself. You can also supply a script with the same name as any of the filter chains in the firewall and the script will be invoked after the /etc/shorewall/rules file has been processed but before the /etc/shorewall/policy file has been processed.

The following table indicate which commands invoke the various scripts.

scriptShorewall-shellShorewall-perl
clearclearclear
compile-check, compile, export, load, refresh, reload, restart, restore,start
continueload, refresh, reload, restart, restore, start 
initload, refresh, reload, restart, restore, startload, refresh, reload, restart restore, start
initdonerefresh, restart, restore, startcheck, compile, export, refresh, restart, start
isusablerefresh, restart, restore, startrefresh, restart, restore, start
maclogload, refresh, reload, restart, restore, startcheck, compile, export, refresh, restart, start
refreshrefreshrefresh
refreshedrefreshrefresh
restored-restore
savesavesave
startload, reload, restart, restore, startload, reload, restart, start
startedload, reload, restart, restore, startload, reload, restart, start
stopstop, clearstop, clear
stoppedstop, clearstop, clear
tcclearload, reload, restart, restore, startload, reload, restart, restore, start

There are a couple of special considerations for commands in extension scripts:

  • When you want to run iptables, use the command run_iptables instead. run_iptables will run the iptables utility passing the arguments to run_iptables and if the command fails, the firewall will be stopped (or restored from the last save command, if any). Note that when Shorewall-shell invokes this script during restore, The run_iptables function does nothing; calls to that function are effectively ignored. run_iptables should not be called from the started or restored scripts.

  • If you wish to generate a log message, use log_rule_limit. Parameters are:

    • Log Level

    • Chain to insert the rule into

    • Chain name to display in the message (this can be different from the preceding argument — see the Port Knocking article for an example of how to use this).

    • Disposition to report in the message (ACCEPT, DROP, etc)

    • Rate Limit (if passed as "" then $LOGLIMIT is assumed — see the LOGLIMIT option in /etc/shorewall/shorewall.conf)

    • Log Tag ("" if none)

    • Command (-A or -I for append or insert).

    • The remaining arguments are passed "as is" to iptables

  • Many of the extension scripts get executed for both the shorewall start and shorewall restart commands. You can determine which command is being executed using the contents of $COMMAND.

    if [ $COMMAND = start ]; then
       ...

Shorewall-shell

When compiling your firewall configuration, Shorewall copies most extension scripts directly into the "compiled" program where they are executed in-line during processing of the start, restart and restore commands. When copying a script, Shorewall indents the script to match the surrounding code; if you have 'awk' installed on the system where the configuration is being compiled, Shorewall can correctly handle line continuation in your script ("\" as the last character on a line). If you do not have awk, you may not use line continuation in your scripts. Also beware that quoted strings continued from one line to another will have extra whitespace inserted as a result of indentation.

Note

The /etc/shorewall/params script is processed only during compilation if EXPORTPARAMS=No in shorewall.conf. So shell variables set in that file may be used in Shorewall configuration files only. Any variables that your extension scripts require at run-time on the firewall system should be set in the init extension script (if you need variable values in the stop or stopped scripts, you will need to set their value in stop since init is not invoked when processing the stop and clear commands).

When EXPORTPARAMS=Yes (the default), the /etc/shorewall/params script is processed during compilation and copied into the compiled script as described above. So shell variables set during compilation may be used in Shorewall configuration files while those set at run-time are available to your other extension scripts.Note that if you assign dynamic values to variables, there is no guarantee that the value calculated at compile time will be the same as what is calculated at run time. This is particularly true if you use the shorewall compile command to compile a program then run that program at a later time or if you use Shorewall Lite.

Note

Extension scripts associated with a particular chain or action are not copied into the compiled script; they are rather processed directly by the compiler using the Bourne shell "." command. For example, if A is an action then if /etc/shorewall/A exists then it will be processed by the compiler rather than copied into the compiled script.

Shorewall-perl

Because the compiler is written in Perl, some of your extension scripts from earlier versions will no longer work because Shorewall-perl runs those extension scripts at compile-time rather than at run-time.

The following table summarizes when the various extension scripts are run:

Compile-timeRun-timeEliminated
compileclearcontinue
initdoneinit 
maclogisusable 
Per-chain (including those associated with actions)start 
 started 
 stop 
 stopped 
 tcclear 
 refresh 
 refreshed 
 restored 

Compile-time extension scripts are executed using the Perl 'eval `cat <file>`' mechanism. Be sure that each script returns a 'true' value; otherwise, the compiler will assume that the script failed and will abort the compilation.

Beginning with Shorewall version 4.0.6, each compile-time script is implicitly prefaced with:

package Shorewall::User;

Most scripts will need to begin with the following line:

use Shorewall::Chains;

For more complex scripts, you may need to 'use' other Shorewall Perl modules -- browse /usr/share/shorewall-perl/Shorewall/ to see what's available.

When a script is invoked, the $chainref scalar variable will hold a reference to a chain table entry.

$chainref->{name} contains the name of the chain
$chainref->{table} holds the table name

To add a rule to the chain:

add_rule( $chainref, <the rule> );

Where

<the rule> is a scalar argument holding the rule text. Do not include "-A <chain name>"

Example:

add_rule( $chainref, '-j ACCEPT' );

Beginning with Shorewall 4.0.5, add_rule() accepts an optional third argument; If that argument evaluates to true and the passed rule contains a --dports or --sports list with more than 15 ports (a port range counts as two ports), the rule will be split into multiple rules where each resulting rule has 15 or fewer ports in its --dports and --sports lists.

To insert a rule into the chain:

 insert_rule( $chainref, <rulenum>, <the rule> );

The log_rule_limit() function works like it does in the shell compiler with three exceptions:

  • You pass the chain reference rather than the name of the chain.

  • The commands are 'add' and 'insert' rather than '-A' and '-I'.

  • There is only a single "pass as-is to iptables" argument (so you must quote that part).

Example:

log_rule_limit(
               'info' , 
               $chainref ,            
               $chainref->{name},
               'DROP' , 
               '',      #Limit
               '' ,     #Log tag
               'add',   #Command
               '-p tcp' #Pass as-is
               );

Note that in the 'initdone' script, there is no default chain ($chainref). You can obtain a reference to a standard chain by:

my $chainref = $chain_table{<table>}{<chain name>};

Example:

my $chainref = $chain_table{filter}{INPUT};

You can also use the hash references $filter_table, $mangle_table and $nat_table to access chain references in the three main tables.

Example:

my $chainref = $filter_table->{INPUT}; #Same as above with a few less keystrokes; runs faster too

The 'continue' script has been eliminated because it no longer make any sense under Shorewall-perl. That script was designed to allow you to add special temporary rules during [re]start. Shorewall-perl doesn't need such rules since the rule set is instantiated atomically by table.