The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

BSD::Ipfwgen - Module to aid in the creation of ipfw-based firewalls

SYNOPSIS

        use BSD::Ipfwgen;

        outside qw(**interface list**);
        leaf qw(**interface list**);

        consolidate qw(**network list**);
        us qw(**network list**);
        not_us qw(**network list**);
        to_us qw(**network list**);
        from_us qw(**network list**);
        symmetric qw(**network list**);

        count_by_interface();
        count_by_address qw(**network list**);
        count_by_udp qw(**port list**);
        count_by_tcp qw(**port list**);

        no_looping()
        no_spoofing_us()
        no_spoofing_by_us()
        no_leaf_spoofing()

        tcp_from_rules($port, $rules);
        tcp_to_rules($port, $rules);
        udp_from_rules($port, $rules);
        udp_to_rules($port, $rules);

        from_net_rules($network, $rules);
        to_net_rules($network, $rules);

        to_me_rules($rules)
        not_to_me_rules($rules)
        from_me_rules($rules)
        not_from_me_rules($rules)

        in_interface_rules($interface, $rules);
        out_interface_rules($interface, $rules);

        drop_unwanted qw(**network list**);

        generate qw(**options**)

        **port list** is a list of integers.  80, 23, etc.
        **network list** is a list of network address.  207.33.90.32/27 etc.
        **interface list** is a list of interface names.  de0, fxp1 etc
        **options** is a list of the valid options: DEFAULT-ACCEPT, INSECURE
        $rules is a newline separated set of L<ipfw> rules.

DESCRIPTION

Ipfwgen is designed to make writing complex firewalls easier and safer. It handles generating some of the harder rulesets: anti-spoofing, anti-looping, and anti land-attack.

Ipfwgen does not try to reduce the complexity of firewall building. What it does do is allow you to write a perl program which generates a firewal. It's expected that the firewalls generated by Ipfwgen will be examined by a human and installed manually.

Ipfwgen commands must be given in a particular sequence. First are the declaritive commands: outside, leaf, consolidate, us, not_us, and symmetric.

Then the rule-specification commands: almost everything else. Ipfwgen keeps an internal database of the rules that are in progress. After all the rule-specification commands are done, then the firewall gets compiled.

The generate command compiles the specifications into actuall ipfw commands and dumps them on STDOUT.

DECLARATIVE COMMANDS

The declaritive commands must preceed all others.

outside(INTERFACEs)

Specifies that an interface is connected to the Internet at large and that the packets coming in from that interface should not be from "us".

leaf(INTERFACEs)

Specifies that an interface leads to a network with no other connections. Routing to a leaf can be assumed to be symmetric.

consolidate(NETWORKSs)

Specifies that addresses within the network specified should be ignored and that the network address should be used instead when a list of IP addresses for the firewall system is needed. This is primarily used to avoid needing to list a large number of IP addresses on web servers with many virtual hosts.

us(NETWORKs)

Specifies network ranges that comprise the address space that is routed by "us". The us command implies that we are the only source of routes for the addresses specifed.

not_us(NETWORKs)

Specifies networks that are within "us" but should not be. For example, "us" may claim to include 209.66.121.0/24, but in reality, the first few addresses aren't ours. This situation can be handled using "not_us".

to_us(NETWORKs)

Specifies networks that we may legitimately receive traffic on behalf of. Don't filter it when incomming at the edges.

from_us(NETWORKs)

Specifies networks that we may legitimately send traffic on behalf of. Don't filter it when outgoing at the edges.

symmetric(NETWORKs)

Specifies that the routes to a network are expected to be symmetric.

COUNTING SPECIFICATIONS

These are all optional.

count_by_interface()

Requests that traffic be counted by interface. Both incoming and outgoing will be counted.

count_by_address(NETWORKs)

Requests that traffic be tracked on a per NETWORK bases.

count_by_udp(PORTs)

Requests that traffic be tracked on a per PORT basis for udp.

count_by_tcp(PORTs)

Requests that traffic be tracked on a per PORT basis for udp.

SPOOFING AND LOOPING

Ipfwgen makes an attempt to generate all the anti-looping and anti-spoofing rules. These are all optional, but anti land-attack rules will be added automatically.

no_looping()

Specifies that obvious packet loops should be prevented. For example, do not route packets meant for us out and outside interface.

no_spoofing_us()

Specifies that if there is an "outside" interface, the packets arriving on it should be checked to make sure that they don't claim to come from ourselves.

no_spoofing_by_us()

Specifies that we should only route packets out our "outside" interface that came from us.

no_leaf_spoofing()

Only accept packets from a leaf interface that come from and address that routes over the leaf interface. Do not accept any packets from anyone that claim to be from addresses that route over a leaf interface unless that came in over the leaf interface.

FILTER BY ADDRESSES RULES

These are all optional.

from_net_rules(network,rules)

Apply the specified ruleset to packets that came from an address with the network specified.

to_net_rules(network,rules)

Apply the specified ruleset to packets that are destined for an address with the network specified.

drop_unwanted(networks)

A quick way to list the networks that you do not with to communicate with.

FITLER BY PORT

These are all optional.

tcp_from_rules(port,rules)

Apply the rules specified to tcp packets that came from the specified port.

tcp_to_rules(port,rules)

Apply the rules specified to tcp packets that are destined for the specified port.

udp_from_rules(port,rules)

Apply the rules specified to udp packets that came from the specified port.

udp_to_rules(port,rules)

Apply the rules specified to udp packets that are destined for the specified port.

ORIGINATION AND TERMINATION

These are all optional. These filters will be generated anyway to handle the anti land-attack rules.

to_me_rules(rules)

Apply the specified rules to packets that are destined for this machine.

not_to_me_rules(rules)

Apply the specified rules to packets that are not destined for this machine.

from_me_rules(rules)

Apply the specified rules to packets that are sent from this machine.

not_from_me_rules(rules)

Apply the specified rules to packets that came from some other machine.

FILTER BY INTERFACE

These are all optional, but these filters will be generated anyway to do the anti-looping and anti-spoofing rules.

in_interface_rules(interface,rules)

Apply the specified rules to packets that arrived on the specified interface.

out_interface_rules(interface,rules)

Apply the specified rules to packets that are departing over the specified interface.

GENERATE OPTIONS

Once the rules have been declared, they must be compiled into actual firewall commands. The command to compile them is generate(options). The generate command should be given last.

The compiled rules are dumped on STDOUT. They are not automatically executed. Running generate() cannot harm your system. Running the output from a program that includes generate() can harm your system so be careful!

The following options are understood.

DEFAULT-ACCEPT

Specifies that unless packets are specifically rejected, they should be accepted. The default is that packets that are not specifically accpeted are rejected.

INSECURE

When building the firewall, add in a rule to accept all packets as a temporary measure. When the firewall is completely built, remove the rule. This creates a window of opportunity for attack. On the other hand, it helps prevent accididental computer death when rebuilding the firewall. It's a good idea to use INSECURE while testing your firewall, but not to use it for final deployment.

LOG_DENIES

Specifies that in general, when packets are denied, they should be logged. Some rules will still not log: the anti-looping rules tend to deny a lot of packets and logging those is both boring and wasteful. Rules that are defined by hand will that use =deny will log the denies if this is set.

RULE LANGUAGE

Whenever a command argument includes filtering rules, the rules are expected to be passed in as a single string with the individual rules separated with newlines.

META RULES

Ipfwgen rule generation can be modified with special "rules".

=label name

Specifies a skipto target label. Don't worry about the numbering of the rules. Add a label wherever needed. Some labels are already defined so don't be alarmed if you get an un-expected duplicate.

=rulenum num

If possible, set the current rule number to num.

=gap [size]

Make a gap in the rule numbering by rounding up to the next multiple of size.

=countby num

When incrementing rule numbers, increment by num.

META ACTIONS

In addtion to the standard actions defined by ipfw, there are some new ones defined by Ipfwgen.

=skiprule

Specifies that the action for this filter rule is to skip over the following rule.

=skipto label

Specifies that the action for this filter rule is to skip to the rule after where the label is specified.

=deny

Specifies that the action for this filter rule is to deny the packet. Packets denied using =deny will be logged if the generate option LOG_DENIES is specified.

=deny_log

Specifies that the action for this filter is to deny the packet. Just plain deny log can be used insted.

=deny_no_log

Specifies that the action for this filter is to deny the packet. Just plain deny can be used instead.

META SPECIFIERS

Ipfwgen provides a shorthand way to specify certain things.

=ME

The =ME specifier will be replaced by the IP address of the firewall system. If the firewall system has more than one IP address the rule will be replicated as necessary to put them all in. =skiprule still works.

=US

The =US specifier will be replaced by the network defined by the us() command. If more than one network was defined, then the rule with the =US specifier will be replicated as necessary to put them all in. =skiprule still works.

=TOUS

The =US specifier will be replaced by the network defined by the to_us() command. If more than one network was defined, then the rule with the =US specifier will be replicated as necessary to put them all in. =skiprule still works.

=FROMUS

The =FROMUS specifier will be replaced by the network defined by the from_us() command. If more than one network was defined, then the rule with the =US specifier will be replicated as necessary to put them all in. =skiprule still works.

=IN

The =IN specifier will be replaced by the interfaces that the firewall system has. This will likely require replicating the rule with the specifier. =skiprule still works.

=host:hostname

The =host:hostname specifier will be replaced with the IP address of the hosthame given. Only one IP address will be substituted in so do not use this with hosts that have multiple IP addresses. The =host:hostname specifier is the only specifier that can be used more than once in a rule and the only one that can be combined with other specifiers.

=IF0

FreeBSD treats the first interface a specially. The =IF0 specifier will be replaced by the name of the first interface. =IF0 can be combined with other meta specifiers.

SEQUENCE

The rules generated by Ipfwgen are processed in the following sequence:

  1. Counting rules. Count packets in by interfaces; count packets out by interface; count packets from udp ports; count packets to udp ports; count packets from tcp ports; count packets to tcp pots; count packets from and to particular networks.

  2. Apply filters on packets that are from the firewall system (to_me_rules). Apply filters on packets that are not from the firewall system (not_to_me_rules).

  3. Apply filters on packets that are to the firewall system (from_me_rules). Apply filters on packets that are not to the firewall system (not_from_me_rules).

  4. Apply filters for packets that came in via a particular interface. (in_interface_rules). This includes loop prevention on point-to-point interfaces. This also includes preventing others from spoofing us and leaf nodes from spoofing anyone.

  5. Apply filters for packets that are going out via a particular interface (out_interface_rules). This includes loop prevention on outside interfaces and on broadcast networks. This also includes preventing us from spoofing others.

  6. Accept packets that are part of established TCP connections.

  7. Apply filters for packets that are coming from a particular network (from_net_rules). This includes preventing anyone from spoofing traffic from leaf nodes.

  8. Apply filters for packets that are going to a particular network (to_net_rules). This includes dropping unwanted networks.

  9. Apply filters for packets that are coming from a particular udp port.

  10. Apply filters for packets that are going to a particular udp port.

  11. Apply filters for packets that are coming from a particular tcp port.

  12. Apply filters for packets that are going to a particular tcp port.

  13. Accept or deny the rest as per the DEFAULT-ACCEPT option.

EXAMPLE

        #/usr/local/bin/perl -w

        use strict;
        use BSD::Ipfwgen;
        use IO::Handle;

        outside 'fxp0';
        leaf 'etha32';
        consolidate '209.66.121.128/25';
        us qw(
                140.174.82.0/24 
                207.33.232.0/22 
                207.33.184.0/22 
                207.33.240.0/21 
                209.157.64.0/19 
                140.174.154.0/24 
                207.33.66.0/24 
                209.66.121.0/24
            );
        not_us qw(
                209.66.121.0/29
        );
        symmetric qw(
                209.66.121.0/27
            );


        count_by_interface();
        count_by_tcp qw(80 119 21 53 25 871 513 23 6667);
        count_by_address qw();
        drop_unwanted qw(
                192.168.0.0:255.255.0.0
                172.16.0.0:255.240.0.0
                10.0.0.0:255.0.0.0
            );

        no_looping();
        no_spoofing_us();
        no_spoofing_by_us();
        no_leaf_spoofing();

        to_me_rules <<'';
                =deny udp from not 140.174.82.0/26 to any 111,2049 # portmap, NFS
                =deny tcp from not 140.174.82.0/26 to any 111 # portmap

        from_me_rules <<'';
                =deny udp from any 111,2049 to not 140.174.82.0/26 # portmap, NFS
                =deny tcp from any 111 to not 140.174.82.0/26 # portmap

        to_net_rules ('=host:mac84', <<'');
                =skiprule tcp from 140.174.82.32/27 to =host:mac84 6000 # mac84
                =deny tcp from any to =host:mac84 6000

        generate qw(INSECURE DEFAULT-ACCEPT);

REQUIREMENTS

Ipfwgen generates commands that work with FreeBSD 2.2.5's firewall program: ipfw. Ipfwgen makes use of features that were only recently added to ipfw: skipto, xmit, recv.

BUGS

Ipfwgen cannot currently deal non-exclusive thru traffic. For ISPs this means that it cannot deal with customers that have redundent connections. Fixing this is not terribly hard.

The firewalls generated by Ipfwgen are often not optimal. If anyone wishes to write an optimizer, that would be great!

The firewalls generated by Ipfwgen can be hard to read.

Ipfwgen expects the netmasks on point to point links to be accurate. Nothing else really cares about such netmasks so this may lead to some problems.

Some of the internal structures aren't very enlightened. For example, everything having to do with get_netmask() and mark_addresses() could be redone for clarity and speed.

COPYRIGHT

Copyright (C) 1998, David Muir Sharnoff. All rights reserved. License hearby granted for anyone to use this module at their own risk. Please feed useful changes back to muir@idiom.com.