<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<article>
  <!--$Id$-->

  <articleinfo>
    <title>Extension Scripts</title>

    <authorgroup>
      <author>
        <firstname>Tom</firstname>

        <surname>Eastep</surname>
      </author>
    </authorgroup>

    <pubdate><?dbtimestamp format="Y/m/d"?></pubdate>

    <copyright>
      <year>2001-2007</year>

      <holder>Thomas M. Eastep</holder>
    </copyright>

    <legalnotice>
      <para>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
      <quote><ulink url="GnuCopyright.htm">GNU Free Documentation
      License</ulink></quote>.</para>
    </legalnotice>
  </articleinfo>

  <caution>
    <para>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.</para>
  </caution>

  <section id="Scripts">
    <title>Extension Scripts</title>

    <para>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
    <quote>source</quote> mechanism.</para>

    <caution>
      <orderedlist>
        <listitem>
          <para>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.</para>
        </listitem>

        <listitem>
          <para>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.</para>
        </listitem>
      </orderedlist>
    </caution>

    <para>The following scripts can be supplied:</para>

    <itemizedlist>
      <listitem>
        <para>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.</para>
      </listitem>

      <listitem>
        <para>init -- invoked early in <quote>shorewall start</quote> and
        <quote>shorewall restart</quote></para>
      </listitem>

      <listitem>
        <para>initdone -- invoked after Shorewall has flushed all existing
        rules but before any rules have been added to the builtin
        chains.</para>
      </listitem>

      <listitem>
        <para>start -- invoked after the firewall has been started or
        restarted.</para>
      </listitem>

      <listitem>
        <para>started -- invoked after the firewall has been marked as
        'running'.</para>
      </listitem>

      <listitem>
        <para>stop -- invoked as a first step when the firewall is being
        stopped.</para>
      </listitem>

      <listitem>
        <para>stopped -- invoked after the firewall has been stopped.</para>
      </listitem>

      <listitem>
        <para>clear -- invoked after the firewall has been cleared.</para>
      </listitem>

      <listitem>
        <para>tcclear -- invoked to clear traffic shaping when CLEAR_TC=Yes in
        <ulink
        url="manpages/shorewall.conf.html">shorewall.conf</ulink>.</para>
      </listitem>

      <listitem>
        <para>refresh -- invoked while the firewall is being refreshed but
        before the blacklst chains have been rebuilt.</para>
      </listitem>

      <listitem>
        <para>refreshed -- invoked after the firewall has been
        refreshed.</para>
      </listitem>

      <listitem>
        <para>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 <emphasis>start</emphasis> script.
        This script is invoked earlier in the [re]start process than is the
        <emphasis>initdone</emphasis> script described above (Not used by
        Shorewall Perl).</para>
      </listitem>

      <listitem>
        <para>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).</para>
      </listitem>

      <listitem>
        <para>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
        <filename>/etc/shorewall/providers</filename>. $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).</para>

        <para>Example:<programlisting># Ping a gateway through the passed interface
case $1 in
    eth0)
        ping -c 4 -t 1 -I eth0 206.124.146.254 &gt; /dev/null 2&gt;&amp;1
        return
        ;;
    eth1)
        ping -c 4 -t 1 -I eth1 192.168.12.254 &gt; /dev/null 2&gt;&amp;1
        return
        ;;
    *)
        # No additional testing of other interfaces
        return 0
        ;;
esac</programlisting><caution>
            <para>We recommend that this script only be used with
            ADMINISABSENTMINDED=Yes.</para>

            <para>The firewall state when this script is invoked is
            indeterminent. So if you have ADMINISABSENTMINDED=No in <ulink
            url="manpages/shorewall.conf.html">shorewall.conf</ulink>(8) and
            output on an interface is not allowed by <ulink
            url="manpages/shorewall.conf.html">routestopped</ulink>(8) then
            the isuasable script must blow it's own holes in the firewall
            before probing.</para>
          </caution></para>
      </listitem>

      <listitem>
        <para>save -- (Added in Shorewall version 4.2.0 Beta2). This script is
        invoked during execution of the <command>shorewall save</command> and
        <command>shorewall-lite save</command> commands.</para>
      </listitem>
    </itemizedlist>

    <para><emphasis role="bold">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.</emphasis> 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.</para>

    <para>There are a couple of special considerations for commands in
    extension scripts:</para>

    <itemizedlist>
      <listitem>
        <para>When you want to run <command>iptables</command>, use the
        command <command>run_iptables</command> instead.
        <command>run_iptables</command> will run the iptables utility passing
        the arguments to <command>run_iptables</command> and if the command
        fails, the firewall will be stopped (or restored from the last
        <command>save</command> command, if any).</para>
      </listitem>

      <listitem>
        <para>If you wish to generate a log message, use <emphasis
        role="bold">log_rule_limit</emphasis>. Parameters are:</para>

        <itemizedlist>
          <listitem>
            <para>Log Level</para>
          </listitem>

          <listitem>
            <para>Chain to insert the rule into</para>
          </listitem>

          <listitem>
            <para>Chain name to display in the message (this can be different
            from the preceding argument — see the <ulink
            url="PortKnocking.html">Port Knocking article</ulink> for an
            example of how to use this).</para>
          </listitem>

          <listitem>
            <para>Disposition to report in the message (ACCEPT, DROP,
            etc)</para>
          </listitem>

          <listitem>
            <para>Rate Limit (if passed as "" then $LOGLIMIT is assumed — see
            the LOGLIMIT option in <ulink
            url="Documentation.htm#Conf">/etc/shorewall/shorewall.conf</ulink>)</para>
          </listitem>

          <listitem>
            <para>Log Tag ("" if none)</para>
          </listitem>

          <listitem>
            <para>Command (-A or -I for append or insert).</para>
          </listitem>

          <listitem>
            <para>The remaining arguments are passed "as is" to
            iptables</para>
          </listitem>
        </itemizedlist>
      </listitem>

      <listitem>
        <para>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.</para>

        <programlisting>if [ $COMMAND = start ]; then
   ...</programlisting>
      </listitem>
    </itemizedlist>

    <para></para>

    <section id="v3.2.9">
      <title>Shorewall-shell</title>

      <para>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.</para>

      <note>
        <para>The <filename>/etc/shorewall/params</filename> script is
        processed only during compilation if EXPORTPARAMS=No in
        <filename>shorewall.conf</filename>. 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 <filename>init</filename> extension script (if
        you need variable values in the <filename>stop</filename> or
        <filename>stopped</filename> scripts, you will need to set their value
        in <filename>stop</filename> since <filename>init</filename> is not
        invoked when processing the <command>stop</command> and
        <command>clear</command> commands).</para>

        <para>When EXPORTPARAMS=Yes (the default), the
        <filename>/etc/shorewall/params</filename> script is processed during
        compilation <emphasis role="bold">and</emphasis> 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
        <command>shorewall compile</command> command to compile a program then
        run that program at a later time or if you use Shorewall Lite.</para>
      </note>

      <note>
        <para>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 <filename
        class="directory">/etc/shorewall/A</filename> exists then it will be
        processed by the compiler rather than copied into the compiled
        script.</para>
      </note>
    </section>

    <section id="Perl">
      <title>Shorewall-perl</title>

      <para>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.</para>

      <para>The following table summarizes when the various extension scripts
      are run:<informaltable frame="all">
          <tgroup cols="3">
            <tbody>
              <row>
                <entry><emphasis role="bold">Compile-time</emphasis></entry>

                <entry><emphasis role="bold">Run-time</emphasis></entry>

                <entry><emphasis role="bold">Eliminated</emphasis></entry>
              </row>

              <row>
                <entry>compile</entry>

                <entry>clear</entry>

                <entry>continue</entry>
              </row>

              <row>
                <entry>initdone</entry>

                <entry>init</entry>

                <entry></entry>
              </row>

              <row>
                <entry>maclog</entry>

                <entry>isusable</entry>

                <entry></entry>
              </row>

              <row>
                <entry>Per-chain (including those associated with
                actions)</entry>

                <entry>start</entry>

                <entry></entry>
              </row>

              <row>
                <entry></entry>

                <entry>started</entry>

                <entry></entry>
              </row>

              <row>
                <entry></entry>

                <entry>stop</entry>

                <entry></entry>
              </row>

              <row>
                <entry></entry>

                <entry>stopped</entry>

                <entry></entry>
              </row>

              <row>
                <entry></entry>

                <entry>tcclear</entry>
              </row>

              <row>
                <entry></entry>

                <entry>refresh</entry>
              </row>

              <row>
                <entry></entry>

                <entry>refreshed</entry>
              </row>
            </tbody>
          </tgroup>
        </informaltable></para>

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

      <para>Beginning with Shorewall version 4.0.6, each compile-time script
      is implicitly prefaced with:</para>

      <programlisting>package Shorewall::User;</programlisting>

      <para>Most scripts will need to begin with the following
      line:<programlisting>use Shorewall::Chains;</programlisting>For more
      complex scripts, you may need to 'use' other Shorewall Perl modules --
      browse <filename
      class="directory">/usr/share/shorewall-perl/Shorewall/</filename> to see
      what's available.</para>

      <para>When a script is invoked, the <emphasis
      role="bold">$chainref</emphasis> scalar variable will hold a reference
      to a chain table entry.<simplelist>
          <member><emphasis role="bold">$chainref-&gt;{name}</emphasis>
          contains the name of the chain</member>

          <member><emphasis role="bold">$chainref-&gt;{table}</emphasis> holds
          the table name</member>
        </simplelist></para>

      <para>To add a rule to the chain:<programlisting>add_rule( $chainref, &lt;<emphasis>the rule</emphasis>&gt; );</programlisting>Where<simplelist>
          <member>&lt;<emphasis>the rule</emphasis>&gt; is a scalar argument
          holding the rule text. Do not include "-A &lt;<emphasis>chain
          name</emphasis>&gt;"</member>
        </simplelist>Example:<programlisting>add_rule( $chainref, '-j ACCEPT' );</programlisting></para>

      <para>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 <emphasis role="bold">--dports</emphasis> 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
      <emphasis role="bold">--dports</emphasis> list.</para>

      <para>To insert a rule into the chain:<programlisting> insert_rule( $chainref, &lt;<emphasis>rulenum</emphasis>&gt;, &lt;<emphasis>the rule</emphasis>&gt; );</programlisting>The
      <emphasis role="bold">log_rule_limit()</emphasis> function works like it
      does in the shell compiler with three exceptions:<itemizedlist>
          <listitem>
            <para>You pass the chain reference rather than the name of the
            chain.</para>
          </listitem>

          <listitem>
            <para>The commands are 'add' and 'insert' rather than '-A' and
            '-I'.</para>
          </listitem>

          <listitem>
            <para>There is only a single "pass as-is to iptables" argument (so
            you must quote that part).</para>
          </listitem>
        </itemizedlist>Example:<programlisting>log_rule_limit(
               'info' , 
               $chainref ,            
               $chainref-&gt;{name},
               'DROP' , 
               '',      #Limit
               '' ,     #Log tag
               'add',   #Command
               '-p tcp' #Pass as-is
               );</programlisting>Note that in the 'initdone' script, there is
      no default chain (<emphasis role="bold">$chainref</emphasis>). You can
      obtain a reference to a standard chain by:<programlisting>my $chainref = $chain_table{&lt;<emphasis>table</emphasis>&gt;}{&lt;<emphasis>chain name</emphasis>&gt;};</programlisting>Example:<programlisting>my $chainref = $chain_table{filter}{INPUT};</programlisting></para>

      <para>You can also use the hash references <emphasis
      role="bold">$filter_table</emphasis>, <emphasis
      role="bold">$mangle_table</emphasis> and <emphasis
      role="bold">$nat_table</emphasis> to access chain references in the
      three main tables.</para>

      <para>Example:</para>

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

      <para>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 ruleset is instantianted atomically by
      table.</para>
    </section>
  </section>
</article>
