{
    @tcp_acl_rules = ();
    # Define a function which can be used in subsequent fragments
    # This function collects a list of TCP ports, and whether
    # or not inbound TCP connections are permitted to the port
    # The list is later used in the "adjust" section of the overall
    # mask script to set up chains and rules which implement the
    # policy
    sub allow_tcp_in
    {
        my $port = shift;
        my $allow = shift;
        my $target = $allow ? "ACCEPT" : "denylog";
        push @tcp_acl_rules, "    adjust_tcp_in $port $target";
        return "";
    }
    @udp_acl_rules = ();
    # This function collects a list of UDP ports, and whether
    # or not inbound UDP packets are permitted to the port
    # The list is later used in the "adjust" section of the overall
    # mask script to set up chains and rules which implement the
    # policy
    sub allow_udp_in
    {
        my $port = shift;
        my $allow = shift;
        my $target = $allow ? "ACCEPT" : "denylog";
        push @udp_acl_rules, "    adjust_udp_in $port $target";
        return "";
    }
    @tcp_forward_acl_rules = ();
    # This function performs the same function as allow_tcp_in, except that
    # it works with the FORWARD chain instead of the INPUT chain.
    sub allow_tcp_forward
    {
        my $port = shift;
        my $allow = shift;
        my $target = $allow ? "ACCEPT" : "denylog";
        push @tcp_forward_acl_rules, "    adjust_tcp_in $port $target";
        return "";
    }
    @udp_forward_acl_rules = ();
    # This function performs the same function as allow_udp_in, except that
    # it works with the FORWARD chain instead of the INPUT chain.
    sub allow_udp_forward
    {
        my $port = shift;
        my $allow = shift;
        my $target = $allow ? "ACCEPT" : "denylog";
        push @udp_forward_acl_rules, "    adjust_udp_in $port $target";
        return "";
    }
    "";
}

adjust_tcp_in() \{
    local dport=$1
    local target=$2
    local chain=$3
    local dnet=$4
    # Add the rule requested.
    rule="/sbin/iptables --append $chain --protocol tcp --dport $dport"
    if [ -n "$dnet" ]; then
        rule="$rule --destination $dnet"
    fi
    rule="$rule --in-interface $\{OUTERIF:-$INTERNALIF\} --jump $target"
    $rule
    \}

adjust_udp_in() \{
    local dport=$1
    local target=$2
    local chain=$3
    local dnet=$4
    # Add the rule requested.
    rule="/sbin/iptables --append $chain --protocol udp --dport $dport"
    if [ -n "$dnet" ]; then
        rule="$rule --destination $dnet"
    fi
    rule="$rule --in-interface $\{OUTERIF:-$INTERNALIF\} --jump $target"
    $rule
    \}

get_safe_id() \{
    # Expect arguments of, chain_name, table, mode, where mode can be either
    # find or new
    local chain_name=$1
    local table=$2
    local mode=$3

    # Find the existing numbered chain.
    current=$(/sbin/iptables --table $table --list $chain_name --numeric |\
        sed -n '3s/ .*//p')
    if [ "x$current" = "x" ]; then
        # We didn't find it.
        echo "ERROR: Cannot find chain $chain_name in table $table" 1>&2
        exit 1
    fi

    # If we're in find mode, return this chain.
    case "$mode" in
    find) 
        echo $current ;;

    new)
        # Make sure the number on this chain doesn't conflict with our
        # process ID.
        current_id=$(echo $current |\
        sed -n -e "s/^$chain_name//" -e "s/^_//p")
        if [ "x$current_id" = "x" ]
        then
        echo "ERROR: Cannot find process ID on chain name" 1>&2
        exit 1
        fi
        # If it conflicts with our process ID, add one to ours.
        if [ $current_id -eq $$ ]
        then
        echo $\{chain_name\}_$(expr $$ + 1)
        else
        echo $\{chain_name\}_$$
        fi
    ;;
    esac
\}
