DAXFi is a Python package useful to configure and manage several different kinds of firewalls in a consistent way, without the need to worry about firewall-dependent issues. To stay firewall-independent, DAXFi defines a common way to describe firewalls rules: it uses a XML representation.
Fortunately, DAXFi doesn't require you to rewrite all your rules in XML from scratch: if you already have a firewall with your rules running, you can use the daxfidump script to get a set of XML files with your rules. Obviously, it's possible that you want to modify these rules, so keep reading this how-to.
If you want to write a XML rule for DAXFi, in a file or directly in a Python script, you have to begin with the XML prolog:
<?xml version='1.0'?>
It must be at the very begin of the file or string (no white spaces, tabs or newlines are allowed before this line).
Now you can point, optionally, to a DTD with a line like:
<!DOCTYPE ruleset SYSTEM '/etc/daxfid/dtd.d/daxfifw_0.5.dtd'>
where the string after 'SYSTEM' must point to the DTD file and the string after 'DOCTYPE' ('ruleset', in this example) is the name of the main tag.
A XML document looks like a SGML or HTML file: there are normal tags, empty tags and they can have attributes. Some things you must remember to write a valid XML:
In the next sections, DAXFi specific tags and attributes are described; some notes for attribute values:
Within a XML file or string, you may decide to put one or more rule definition.
If you want to have the same action applied to one or more rules, you can begin with an 'action tag' as described in the next chapter; example:
<action> <rule1 /> <rule2 /> ... </action>
If you want to have different actions (applied to different rules), you have to use 'ruleset' as the main tag (wrapping many action tags) , as:
<ruleset> <action1> <rule1a /> <rule1b /> ... </action1> <action2> <rule2a /> <rule2b /> ... </action2> ... </ruleset>
Every rule or set of rules must be enclosed in what I call an 'action tag'; this is one of the valid actions enumerated below and are used to tell DAXFi what to do with this rule (e.g.: append this rule at the end of a chain, purge a chain, delete a given rule and so on).
Inside the action tag there must be one or more rules. The action is applied to these rules.
Examples of valid action tags are:
<append>...</append>
And:
<insert rule-number='5'>...</insert>
In the 'rule' tag are included the attributes that belongs to every IP packets (e.g.: the source and destination addresses, the interface name, if we must consider only fragments, etc. etc.)
Examples; match entering packets from the 127.0.0.1/8 subnet on interface ppp0:
<rule direction='in' source-ip='127.0.0.1/8' interface='ppp0'> ... </rule>
Match only the first fragment of fragmented outgoing packets from 127.0.0.1 directed to 4.5.6.0/24:
<rule direction='out' source-ip='127.0.0.1' destination-ip='4.5.6.0/24' fragment-only='yes'> ... </rule>
Inside a rule tag, you can put an empty tag with the name of one of the main protocols (TCP, UDP and ICMP) or a 'protocol' tag with a 'protocol' attribute. E.g., for matching only tcp packets:
<tcp />
For udp:
<udp />
And for icmp:
<icmp />
If you want to match against a different protocol:
<protocol protocol='igmp' />
Examples; match TCP packets from the 1234 port:
<tcp source-port='1234' />
Match UDP to the identd daemon:
<udp destination-port='auth' />
Match the first packets of a connection to any UDP except the range 100-200:
<udp syn-only='yes' destination-port='! 100:200' />
Match 'host-redirect' ICMP packets:
<icmp icmp-type='host-redirect' />
The same, using ICMP type/code:
<icmp icmp-type='5/1' />
Now you want to tell DAXFi what to do with the matched packets. You can use an empty tag named 'accept', 'reject' or 'drop', or you can use a 'target' tag with a 'target' attribute. The target tag must be omitted writing a NAT rule.
Examples; accept the patched packets (the packets will pass through the firewall):
<accept />
Drop packets (they will be silently discarded):
<drop />
Reject packets (packets will be dropped, and an ICMP error code sent back):
<reject />
It's equivalent to:
<target target='reject' />
Example; reject packets sending back a 'network-prohibited' ICMP:
<reject reject-with='network-prohibited' />
With this empty tag, you set up a rule to do Network Address Translation.
Sometimes you need to mangle the source or destination of a packet; we define, with empty tags, four operation: with 'snat' you alter the source address of matched packets; you have to specify the new source IP address and optionally a port or range of ports. The 'dnat' tag is used when you need to redirect a packet directed to a given IP address to another one; you have to specify the new destination address and, optionally, a new port or range of ports. 'masq' is a special case of 'snat', useful with dial-up: you don't have to specify the new source IP since the one of the outgoing interface is used; optionally you can specify a port or range of ports. 'redirect' is a special case of 'dnat': the matched packets are sent to the local machine (IP 12.7.0.0.1); optionally it's possible to specify a new destination port. The generic 'nat' tag can also be used, and requires a 'nat' attribute to specify the type of NAT you need.
Examples; TCP packets from 1.2.3.4 are NATed as they are coming from 5.6.7.8 on interface 'le1' with a new port, in the range 1-1024:
<rule source-ip='1.2.3.4' interface='le1'> <tcp /> <snat to-address='5.6.7.8' to-port='1:1024' /> </rule>
Packets directed to IP address 7.7.7.7 are redirected to one IP in the range from 1.1.1.1 to 3.3.3.3:
<rule destination-ip'7.7.7.7'> <dnat to-address='1.1.1.1:3.3.3.3' /> </rule>
TCP packets from 1.2.3.0/24 tcp port 80 are redirected to the local port 8080:
<rule source-ip='1.2.3.0/24'> <tcp source-port='80' /> <redirect to-port='8080' /> </rule>
Packets from 192.168.1.0/24 will be rewritten as they are coming from the address of the 'ppp0' interface:
<rule source-ip='192.16.1.0/24' interface='ppp0'> <masq /> </rule>
Sometimes you need to leave a message in the system logs when a given packets is received.
A 'log' empty tag can be used.
Examples; log with priority 'info' and with facility 'local1':
<log facility='local1' priority='info' />
Actually, this empty tag is supported only by the iptables firewall and it's safely ignored by others. It set limits for matched packets.
Example; match three packets in an hour, with a burst of 10:
<limit rate='3/h' burst='10' />
Sometimes you need to give special instructions to the XML parser. You can add a processing instruction right below the XML prolog, with the syntax:
<?daxfi-process attributeName='attributeValue'?>
Valid attributes are:
Example; a set of rules to be executed only if the firewall is not iptables or ipfilter:
<?xml version='1.0'?> <?daxfi-process not-for='iptables,ipfilter'?> <ruleset> ... </ruleset>
If you're using a dial-up connection normally you don't know what IP address will be assigned to you by the provider and the name of the network interface used by the pppd daemon. Using a DAXFi-based program you can leave in your XML files some placeholders and tell the program to substitute these strings with other data.
The Firewall class in the daxfi Python package takes as constructor parameter the 'substitutionDict' keyword, that must be a Python dictionary in the form {'placeHolder1': 'value1', 'placeHolder2': 'value2', ...}. Before any operation on XML files or strings, the Firewall object will replace the strings 'placeHolder1', 'placeHolder2' and so on with 'value1', 'value2', etc.
As example, the daxfid script will search for '%REMOTE_IP', '%LOCAL_IP' and '%INTERFACE', replacing these strings with the remote IP, the local assigned IP and the interface of the connection.
Accept any incoming TCP packet from the network 192.196.1.0/24, to the port 80. | <?xml version='1.0'?> <append> <rule source-ip='192.196.1.0/24' direction='in'> <tcp destination-port='80' /> <accept /> </rule> </append> |
iptables |
|
ipchains |
|
ipfwadm |
|
ipfilter |
|
Example of more than one rule in a single file. Note the use of the boolean 'fragment-only' option in the second rule. | <?xml version='1.0'?> <ruleset> <append> <rule direction='in' source-ip='192.168.1.0/24'> <tcp /> <accept /> </rule> <rule direction='out' fragment-only='yes' destination-ip='192.168.1.0/24'> <tcp /> <accept /> </rule> </append> <flush> <rule direction='out' /> </flush> </ruleset> |
iptables |
|
ipchains |
|
ipfwadm |
|
ipfilter |
|
Insert a rule in the third position of the 'input chain'. | <?xml version='1.0'?> <insert rule-number='3'> <rule source-ip='192.196.1.0/24' destination-ip='1.2.3.4' interface='ppp0' direction='in'> <accept /> </rule> </insert> |
iptables |
|
ipchains |
|
ipfwadm |
|
ipfilter |
|
Flush the 'output chain'. | <?xml version='1.0'?> <flush> <rule direction='out' /> </flush> |
iptables |
|
ipchains |
|
ipfwadm |
|
ipfilter |
|
This rule replaces the one in the second position of the 'input chain'. | <?xml version='1.0'?> <replace rule-number='2'> <rule source-ip='1.2.3.4' direction='in'> <udp /> <accept /> </rule> </replace> |
iptables |
|
ipchains |
|
ipfwadm |
|
ipfilter |
|
Delete the seventh rule in the 'output chain'. | <?xml version='1.0'?> <delete rule-number='7'> <rule direction='out' /> </delete> |
iptables |
|
ipchains |
|
ipfwadm |
|
ipfilter |
|
Remove the defined rule. | <?xml version='1.0'?> <delete> <rule direction='out' source-ip='192.168.2.0/24'> <tcp /> <accept /> </rule> </delete> |
iptables |
|
ipchains |
|
ipfwadm |
|
ipfilter |
|
Some rules using icmp. | <?xml version='1.0'?> <append> <rule direction='in'> <tcp syn-only='no' source-port='!123:239' /> <reject reject-with='network-prohibited' /> </rule> <rule direction='in'> <icmp icmp-type='host-redirect'/> <drop /> </rule> <rule direction='in'> <icmp icmp-type='3/2'/> <drop /> </rule> </append> |
iptables |
|
ipchains |
|
ipfwadm |
|
ipfilter |
|
Any packet from IPs in '192.168.3.0/24' on interface 'le1' have the source IP modified to '5.6.7.8' and a new source port in the range between 1 and 1024. | <?xml version='1.0'?> <append> <rule direction='in' source-ip='192.168.3.0/24' interface='le1'> <snat to-address='5.6.7.8' to-port='1:1024' /> </rule> </append> |
iptables |
|
ipchains |
|
ipfwadm |
|
ipfilter |
|
Masquerade every packet from '192.16.1.0/24' on 'ppp0' interface as they are coming from the local machine. | <?xml version='1.0'?> <append> <rule source-ip='192.16.1.0/24' interface='ppp0'> <masq /> </rule> </append> |
iptables |
|
ipchains |
|
ipfwadm |
|
ipfilter |
|
Any TCP packet from IPs in '1.2.3.0/24' on interface 'le2', to port '80' are redirected to the local machine, port 8080. | <?xml version='1.0'?> <append> <rule source-ip='1.2.3.0/24' interface='le2'> <tcp source-port='80' /> <redirect to-port='8080' /> </rule> </append> |
iptables |
|
ipchains |
|
ipfwadm |
|
ipfilter |
|
Write a log for matching packets. | <?xml version='1.0'?> <append> <rule direction='in' interface='ppp0' destination-ip='127.0.0.1/8'> <drop /> <log priority='warn' facility='local2' /> </rule> </append> |
iptables |
|
ipchains |
|
ipfwadm |
|
ipfilter |
|
Packets incoming on interface 'ppp0' to address '127.0.0.1/8 are accepted only if part of an already established connection. | <?xml version='1.0'?> <append> <rule direction='in'> <tcp state='related'/> <accept /> </rule> </append> |
iptables |
|
ipchains |
|
ipfwadm |
|
ipfilter |
|
Use of processing instructions: the defined rule is valid only for firewalls that are not 'iptables' or 'ipfilter'. | <?xml version='1.0'?> <?daxfi-process not-for='iptables,ipfilter'?> <append> <rule direction='out' destination-ip='127.0.0.1' fragment-only='no'> <drop /> </rule> </append> |
iptables |
|
ipchains |
|
ipfwadm |
|
ipfilter |
|
Copyright 2001, 2002 Davide Alberani <alberanid@libero.it>
Redistribution and use in source (SGML DocBook) and 'compiled' forms (SGML, HTML, PDF, PostScript, RTF and so forth) with or without modification, are permitted provided that the following conditions are met:
Important: THIS DOCUMENTATION IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.