NAME
    ferm - a firewall rule parser for linux

SYNOPSYS
    ferm *options* *inputfiles*

DESCRIPTION
    ferm compiles ready to go firewall-rules from a structured rule-
    setup. These rules will be executed by the preferred kernel
    interface, such as ipchains(8) and iptables(8).

    Besides just executing all rules in one command, the obvious
    gain is the possibility to provide a structured description of a
    firewall. No need anymore for tedious typing all firewalls into
    custom scripts, you can now write logically and coherent rules
    using a C-style nesting structure, and let ferm create all rules
    for you.

    ferm will also aid in modularizing firewalls, because it creates
    the possibility to split up the firewall into several different
    files, which can be reloaded at will, so you can dynamically
    adjust your rules.

    ferm, pronounced "firm", stands for "For Easy Rule Making".

STRUCTURE OF A FIREWALL FILE
    The structure of a proper firewall file looks like simplified C-
    code. Only a few syntactic characters are used in ferm-
    configuration files. Besides these special caracters, ferm uses
    'keys' and 'values', think of them as options and parameters, or
    as variables and values, whatever.

    With these words, you define the characteristics of your
    firewall. Every firewall consists of two things: First, look if
    network traffic matches certain conditions, and second, what to
    do with that traffic.

    You may specify conditions that are valid for the kernel
    interface program you are using, probably iptables(8). For
    instance, in iptables, when you are trying to match tcp packets,
    you would say:

        iptables --protocol tcp

    In ferm, this will become:

        protocol tcp;

    Just typing this in ferm doesn't do anything, you need to tell
    ferm (actually, you need to tell iptables(8) and the kernel)
    what to do with any traffic that matches this condition:

        iptables --protocol tcp -j ACCEPT

    Or, translated to ferm:

        protocol tcp accept;

    Noticed the ; character? We're getting to that now, because
    there are some special characters in ferm that make life easy.

    Here's a list of the special characters:

    ;       The effectuation character. This character defines the end
            of a rule. Anything defined before this character will
            be put into one or more rules.

            This character *makes* the rule. It gathers all the
            information, all parameters and targets, special things
            or whatever, that currently is 'valid', and tries to
            make a decent rule out of it. ferm will do nothing
            without this character!

            Example:

                proto tcp ACCEPT;

            THis example shows a single rule, defined by two keys
            and one value.

    {}      The nesting symbol defines a 'block' of rules.

            Anything defined before this block will still be
            available within all rules inside this block. You can
            nest blocks in blocks as far as you like. For every rule
            defined in this block the values defined before this
            block will apply. Usually you would define an often used
            parameter as the protocol in front of this block, and
            anything special inside it.

            You can put as many rules (using the <;> character) as
            you like insode this block. but there should always be
            one or more, although you will get away with none. Not
            very usefull except for when you frequently edit you
            config file, and might want to leave a chain empty.

            Since the nesting block is left associative, it cannot
            be bound to keys defined after the block.

            Example:

                chain INPUT proto tcp {
                    syn DENY;
                    ACCEPT;
                }

            This block shows two rules inside a block, which will
            both be merged with anything in front of it, so you will
            get two rules:

                iptables -A INPUT -p tcp -y -j DENY
                iptables -A INPUT -p tcp -j ACCEPT

    $       Further more, ferm now supports variables, so you can define
            your favorite targets, interfaces etc. before you use
            them. It works like this:

                set IF eth0
                set $IF ACCEPT
                set TARGET $IF

            will result in this:

                $IF = eth0
                $eth0 = ACCEPT
                $TARGET = eth0

    ()      The array symbol. Using the parentheses, you can define a
            'list' of values that should be applied for the key to
            the left of it.

            Example:

                proto ( tcp udp icmp )

            this will result in three rules:

                ... -p tcp ...
                ... -p udp ...
                ... -p icmp ...
                
            Only values can be 'listed', so you cannot do something like this:

                proto tcp ( ACCEPT LOG );

            but you can do this:

                chain (INPUT OUTPUT FORWARD) proto (icmp,udp,tcp) DENY;

            (which will result in nine rules!)

            Values can be separated either by spaces or commas. The
            array symbol is both left- and right-associative, in
            contrast with the nesting block, which is left-
            associative only.

    ` # '   The comment symbol. Anything that follows this symbol up to
            the end of line is ignored.

    These symbols glue all the keywords into a structure, which
    allows you to specify some keys only a few times, and let them
    apply to any key/value pairs defined within an entire block, for
    instance:

        proto tcp {
            dport 22 ACCEPT;
            syn DPORT 0:1023 DENY;
            }
        ACCEPT;

    Now here, the 'proto tcp' is valid within the block, but not
    anymore after is, resulting in:

        ... -p tcp --dport 22 -j accept
        ... -p tcp -y --dport 0:1023 -j deny
        ... -j accept # note '-p tcp' is not in here!

    Some important notes:

    - Ferm inserts the rules 'chronologically', so the first rule
    will be inserted before the second one.

    - Anything defined within a block is no longer valid when that
    block ends.

    - Everything defined within the current block that is
    'effectuated', will be no longer defined immediately after that
    point.

    - Everything defined before a block is undefined when this block
    closes.

    If you do not understand this, don't worry, it alle becomes
    clear by itself.

    Two types of keys exist:

  Firewall keys

            Firewall keys define a set of firewall packet matching
            criteria that is supported by the kernel backend. They
            look like 'name value' pairs or like 'switch'. For
            instance:

                proto tcp

            or:

                syn

            A 'name value' pair lets you fill in a value for a
            certain condition you would like to match packets
            against, switches are like on/off light switches on the
            wall, if you specify a switch, you turn paket matching
            for whatever the switch stands, on. In the latter
            example, you turn SYN-packet matching on for this rule.

            Both types can optionally be preceded by a !. This will
            be handled that you don't want something to be matching
            it:

                !syn

            or:

                ! syn

            Means you want packets which *don't* have the syn-flag
            set to be matched. Or even:

                proto ! tcp

            Means you want to match *anything but* packets from the
            tcp protocol.

            Read iptables(8) or ipchains(8) to see where the ! can
            be used.

  Option keys

            Using option keys alter the behaviour of ferm; they can
            be used to e.g. clear chains before use, or turn off
            certain sanity checks.

            Example:

              option verbose

            This option makes ferm show a lot of information about
            what it is doing.

    The syntax is very simple, let's start with a simple example:

        chain input {
            proto tcp ACCEPT;
        }

    This will add a rule to the predefined input chain, matching and
    accepting all tcp packets. Ok, let's make it more complicated:

        chain (input,output) {
            proto (udp,tcp) ACCEPT;
        }

    This will insert 4 rules, namely 2 in chain input, and 2 in
    chain output, matching and accepting both udp and tcp packets.
    Normally you would type this for ipchains(8):

       ipchains -A input -p tcp ACCEPT
       ipchains -A output -p tcp ACCEPT
       ipchains -A input -p udp ACCEPT
       ipchains -A output -p udp ACCEPT

    Note how much less typing we need to do? :-)

    Basically, this is all there is to it, although you can make it
    quite more complex. Something to look at:

       chain input policy ACCEPT {
           destination 10/8 port ! ftp goto mychain sport :1023 tos 4 settos 8 mark 2;
           destination 10/8 port ftp DENY;
       }

    My point here is, that *you* need to make nice rules, keep them
    readable to you and others, and not make it into a mess.

    It would aid the reader if the resulting firewall rules were
    placed here for reference. Also, you could include the nested
    version with better readability.

    Try using comments to show what you are doing:

        # this line enables transparent http-proxying for the internal network:
        proto tcp if eth0 daddr ! 192.168.0.0/255.255.255.0
            dport http REDIRECT 3128;

    You will be thankfull for it later!

        chain input policy ACCEPT {
            interface (eth0,ppp0) {
                # deny access to notorius hackers, return here if
                # no match was found to resume normal firewalling
                goto badguys;

                protocol tcp goto fw_tcp;
                protocol udp goto fw_udp;
            }
        }

    The more you nest, the better it looks. Make sure the order you
    specify is correct, you would not want to do this:

        chain forward {
            proto ! udp DENY;
            proto tcp dport ftp ACCEPT;
        }

    because the second rule will never match. Best way is to specify
    first everyting that is allowed, and then deny everything else.
    Look at the examples for more good snapshots. Most people do
    something like this:

        proto tcp {
            dport (
                ssh http ftp
            ) ACCEPT;
            dport 1024:65535 ! syn ACCEPT;
            DROP;
        }

  keywords

    To make life easy, ferm allows you to use shorthands for most
    keywords. A list of shorthand notations is available at the end
    of this section.

    What kind of value you provide for a keyword depends on the
    keyword entirely, e.g. 'protocol' expects 'tcp', 'udp' or
    'icmp', 'log-prefix' expects a value like '"whoops, someone rang
    the doorbell"' and 'destination-port' can accept values like
    'http', '80' or '0:1023'. Take a look at the kernel backend
    program manual for possible values and how they look like.

    Note you may put a value in single quotes or double quotes, if
    this may be required because a value contains spaces:

        log-prefix "Dropped tcp package: "

    Please don't use commas, exclamation commas, exclamation marks,
    parentheses, curly brackets or pipe characters between quotes,
    ferm doesn't like that.

    chain [chain-name]
            Specifies a chain that this rule will be inserted to.
            this is a required key for any rule. Chains can be built
            in, like `input', `output' or `forward', or user-defined
            chains.

    interface [interface-name]
            Define the interface name, your outside network card,
            like eth0, or dialup like ppp1, or whatever device you
            want to match for passing packets. It is equivalent to
            the `-i' switch in ipchains(8) and iptables(8).

    outerface [interface-name]
            Same as interface, only for matching the outgoing
            interface for a packet, as in iptables(8). ipchains(8)
            hasn't got this parameter.

    protocol [protocol-name|protocol-number]
            Currently supported by the kernel are tcp, udp and icmp,
            or their respective numbers.

    port [port-spec]
            Specify a port number, name or range

    addr [address-spec]
            Specify a network address, a hostname or ip-number.

    source|destination
            Specify that the values provided for port and addr above
            should be either source or <destination> ports and
            addresses. This works like a toggle, which can be left
            on for the entire configuration file. So, if you say
            source once, all occurences of port will be source
            port's, as well as for addresses.

    saddr|daddr [address-spec]
            Specify an address specifically for the source or
            destination side, read it as a shorthand for source
            address and destination address, although it does not
            'toggle' the source|destination state, which is
            remembered.

    sport|dport [port-spec]
            Specify a port number, name or range for the source or
            destination side, read it as a shorthand for source port
            and destination port>, although it does not 'toggle' the
            source|destination state, which is remembered. Ports can
            be specified for tcp and udp, as well as icmp, only in
            that case it means 'icmp-type' and only works when you
            specify the type numerically.

            Note that you need to specify a protocol, before you can
            use ports, that is because not all protocols support the
            ideas of ports.

            Here are some examples of valid addresses:

                192.168/8 (identical to the next one:)
                192.168.0.0/255.255.255.0
                my.domain.com

            And some examples of valid ports/ranges:

                80
                http
                ssh:http
                0:1023        which is equivalent to     :1023
                1023:65535    which is equivalent to     1023:65535

    icmptype [type]
            To specify an icmp message type. Can be numbers, but
            refer to the manual of the kernel program to retreive a
            list, for ipchains use "ipchains `-h' icmp". Examples:
            ping, pong.

    tos [value]
            Matches a packet on the specified TOS-value. See settos
            for values.

    settos [value]
            Set the tcp package Type Of Service bit to this value.
            This will be used by whatever traffic scheduler is
            willing to, mostly your own linux-machine, but maybe
            more. The original tos-bits are blanked and overwritten
            by this value. Possible values are (look in the
            shorthands for more, and easier values) :

            02 04 08 10

    mark [value]
            matches packets based on their mark-value

    setmark [value]
            Sets the mark-value for a packet, use with the MARK
            target in iptables

    syn     Specify that the SYN flag in a tcp package should be
            matched, which are used to build new tcp connections.
            You can identify incoming connections with this, and
            decide wether you want to allow it or not. Packets that
            do not have this flag are probably from an already
            established connection, so it's considered reasonably
            safe to let these through.

    fragment
            Specify that only fragmented IP packets should be
            matched. When packets are larger that the maximum packet
            size your system can handle (called Maximum Transmission
            Unit or MTU) they will be chopped into bits and sent one
            by one as single packets. See ifconfig(8) if you want to
            find the MTU for your system (the default is usually
            1500 bytes).

            Fragments are frequently used in DOS attacks, because
            there is no way of finding out the origin of a fragment
            packet.

    policy [policy]
            Specifies the default policy for the current chain. Can
            be either of the standard actions (ACCEPT, DENY, REJECT,
            MASQ and REDIRECT). A packet that matches no rules will
            be treated as specified by the policy. You can't specify
            chain names here. Only the predefined (built-in) chains
            have policies.

            To avoid ambiguity, always specify the policies of all
            predefined chains explicitly.

    log     Log all packets that match this rule in the kernel log. Be
            carefull with log flooding. Note the difference with LOG
            in iptables! See LOG as well. In iptables, this makes a
            copy of the current rule, and inserts it with the LOG
            target instead of any other specified target.

            See also log-[level|prefix|tcp-sequence|tcp-options|ip-
            options]

    goto [chain]
            Specify that matching packets should jump to this chain,
            only user defined chains are valid jump targets.

    reverse Instructs the kernel to use this rule twice, the second time
            with source and destination swapped. Unfortunately, this
            doesn't work with iptables.

    LOG     Identical to the 'LOG' target in iptables, logs any packet
            that matches, but doesn't do anything else to it. Only
            valid for iptables, otherwise use 'log'. See log and
            also log-[level|prefix|tcp-sequence|tcp-options|ip-
            options].

    ACCEPT  Accepts matching packets.

    REJECT  Rejects matching packets.

    DENY    Denies matching packets.

    MASQ [port|portrange]
            Masquerades matching packets. Optionally followed by a
            port or port-range for iptables. Specify as "123", "123-
            456" or "123:456". The port range parameter specifies
            what local ports masqueraded connections should
            originate from.

    RETURN  Returns to the parent chain where the current chain was
            called if the packet matches.

    REDIRECT [port|portrange]
            Allows transparent proxying when rule matches, the port
            that is redirected to must immediately follow this
            keyword. The target may also be an IP-number in case you
            are using iptables(8), so something like "REDIRECT
            192.168.0.5:21" is valid there.

    SNAT|DNAT [ip-address|ip-range|ip-port-range]
            Allows source/destination address translation, only
            valid for iptables(8), requires an ip-number, range or
            ip/port value.

    TOS     Changes the packets TOS-field according to the set-tos
            parameter specified, only valid for iptables.

    table [table-name]
            Selects this table for the rule. Valid table names are
            "filter", "nat" and "mangle".

    reject-with [value]
            Rejects a packet with an ICMP value type message.

    limit [value]
            Limits these type of packets to a maximim.

    burst [value]
            Limits bursts of these packets.

    mac [value]
            Matches packets originating from these mac-addresses.

    state [value]
            Matches packets with this state. The value may be
            specified as a normal ferm-list: "(ESTABLISHED,RELATED)"
            but "NEW:RELATED", and single values are also allowed.

    tcp-flags [!] [flagmask] [flagmatch]
            Specify tcp-flags, the ! is optional and has to precede
            the mask, mask and match are mandatory. The list of mask
            or match flags may be specified as a normal ferm-list:
            "(SYN,ACK,RST)", but "SYN:ACK:RST" and single values are
            also allowed.

    tcp-option [value]
            Specify a tcp-option for this rule.

    log-[level|prefix|tcp-sequence|tcp-options|ip-options] [value]
            Specifies several extra tcp/ip options.

    [u|g|p|s]id-owner [value]
            Matches packets originating from this User, Group, Pid
            or Session ID.

    set [name] [value]
            Set variable "name" to value "value", you can
            dereference the variables by "$name". You may also put
            variables within set statements.

SHORTHANDS
    Here's a complete list of possible shorthands, just to reduce
    the amount of typing:

    interface:
        if

    outerface:
        of

    protocol:
        proto

    source:
        src

    destination:
        dest

    fragment:
        frag

    ACCEPT:
        accept

    DENY:
        deny, DROP, drop

    REJECT:
        reject

    MASQ:
        masq

    RETURN:
        return

    REDIRECT:
        redirect, PROXY, proxy

    MARK:
        mark

    QUEUE:
        queue

    SNAT:
        snat

    DNAT:
        dnat

    goto:
        to, jump

    icmptype
        icmp-type

    reverse:
        bidirectional, swap

    tcp-option:
        tcpoption

    mac:
        mac-source, macsource

    burst:
        limit-burst, limitburst

    uid-owner:
        uidowner, uid

    gid-owner:
        gidowner, gid

    pid-owner:
        pidowner, pid

    sid-owner:
        sidowner, sid

    log-level:
        loglev

    log-prefix:
        logprefix

    log-tcp-sequence:
        logseq

    log-tcp-options:
        logtcpopt

    log-ip-options:
        logipopt

    reject-with:
        rejectwith

    setmark
        set-mark

    tos/settos-values:
        The following Type Of Services values may be given:

            mincost min-cost 2 02 0x02

            reliability reliable 4 04 0x04

            max-throughput maxthroughput 8 08 0x08

            lowdelay interactive min-delay 10 0x10

            clear 0 00 0x00

OPTIONS
    Options can be specified with the "option" keyword, which can be
    defined anywhere within the document. Although that may be fine,
    you almost allways want to define them at the beginning of your
    document, because the behaviour changes at the moment they are
    specified.

    All options can also be specified on the command line, which has
    a few more available. The equivalent for the commandline options
    that are also available in the firewall file is mentioned in the
    firewall file options section.

  Command line options

    --noexec    Do not execute the ipchains(8) or iptables(8) commands,
                but skip instead. This way you can parse your data,
                use --lines to view the output.

    --lines     Show the firewall lines that were generated from the
                rules. They will be shown just before they are
                executed, so if you get error messages from
                ipchains(8) etc., you can see which rule caused the
                error.

    --verbose   Shows some more details of the stages of execution of
                the program.

    --relaxed   Do not fuzz about errors, instead continue and let
                ipchains(8) etc. give errors back.

    --help      Show a brief list of available commandline options.

    --version   Shows the version number of the program.

    --use [ipchains|iptables|ipfwadm]
                Use this kernel program to implement the rules into
                the kernel. Also available as firewall file option
                "option [...]". This option must be set, either on
                the commandline or in a ferm config file.

    --automod   Automatically insert the correct module parameter when
                using iptables, making the module parameter
                unnecessary

  Firewall file options

    option clearall
            Clears the entire firewall, deletes all user chains and
            flushes the built in chains. Does not alter policies.

    option flushall
            Flushes all chains but does not delete them.

    option flushchains
            Flushes any chain which is defined in the setup, even
            built-in chains are flushed when referred.

    option createchains
            Creates any chain which is referred to, even when no
            rule is specified for the chain, but is only referred by
            with a "goto" keyword.

    option automod
            Automatically insert the correct module parameter when
            using iptables, making the module parameter unnecessary

    option relaxed
            Makes the program not whining over serious errors,
            although that's not very handy because it will fail to
            install the rules.

    option [iptables|ipchains|ipfwadm]
            Define which kernel program you have to use to install
            rules. This one is required, since on some systems, they
            can both be present, or you want to use a wrapper for an
            older version. Currently defaults to ipchains.

SEE ALSO
    ipchains(8), ipfwadm(8), iptables(8)

NOTES
    A good firewall is not the only step in security, even the
    firewall may be insecure, or someone breaks into your house and
    steals the hard disk out of your PC. Do not rely on this
    firewall tool for the use of mission critical or confidential
    data. It is not fit for such a purpose!

    Instead, use this tool to expand your current use of ipchains(8)
    and routing, create a flexible firewall and look out for
    anything suspicious. Be carefull with open ports and servers,
    always get the latest, patched versions. Read more about
    firewalls before experimenting, you are warned! You might also
    read the COPYING file provided with the package or visit
    www.gnu.org to find more about the license.

EXAMPLES
    The package comes with a directory full of goodies (examples)
    that you can try, adjust for your system or just read if you
    want to understand the syntax and it's possibilities. Look in
    the "examples" directory.

REQUIREMENTS
  Operating system

    The Operating system currently supported is only linux, although
    it may be possible to port this program to support FreeBSD or
    SOLARIS firewall systems, provided they supply a similar
    firewalling scheme. (Does anybody known about that?)

  Software/packages

    Required are 2 packages: Perl5, under which this ferm runs, and
    one of the kernel firewall programs, suited for your system and
    kernel version.

  Kernel

    The respective required kernel versions for each of the kernel
    firewall programs (ipchains(8), ipfwadm(8) or iptables(8)) is
    also needed. This means you have to have a kernel which can use
    the firewalling thing, something you might have to compile a
    kernel for, or set some switches in /proc. Look at the man pages
    of those kernel programs for more information.

RESTRICTIONS
    ferm allows almost anything the used firewall program allows, so
    go ahead and specify complex port ranges, icmp by number or
    worse. Just be warned.

    Although quite sophisticated, the kernel interface programs
    ipchains(8) and iptables(8) are very limited in some respects.
    ferm is only an interface to improve the handling of these
    programs, and is therefore limited by the possibilities of these
    programs.

    Ipfwadm(8) is extremely limited in rule-building, upgrade or
    succomb in it. Nothing ferm can do about it.

BUGS
    The ipfwadm(8) interface is really limited due to being unable
    to test it and having no experience with it at all. I'll be
    concentration on iptables(8), which supports much more options
    and will be quite more flexible.

    Several nasty cleanups are not done well, which may result in
    surviving data. Tried to remove all of them but suspect more of
    them to occur.

    The --log-prefix construct does not allow certain characters to
    be put between "". Make sure you don't use the bracket {} and []
    characters, the ! and , are also not correctly parsed.

TODO
    * Improve ipfwadm(8) handling or removing it altogether

    * Add more examples, with modularized snipplets (include option)

    * Make rpm's for RH and SuSE, or better: get you to do that!

    * Review the second half of the manual page

    * Make ferm bug you more about errors, i.e. increase validity
    checking to high levels

COPYRIGHT
    Copyright (C) 2001, Auke Kok <koka@geo.vu.nl>

LICENSE
    ferm is released under the Gnu Public License, see the COPYING
    file that came with the package or visit www.gnu.org.

    This is free software; see the source for copying conditions.
    There is NO warranty; not even for MERCHANTABILITY or FITNESS
    FOR A PARTICULAR PURPOSE.

AUTHOR
    Auke Kok (koka@geo.vu.nl)

