I just finished rewriting an old firewall tool from Perl to Python. Since it’s in Python and about firewalling I dubbed it Pyroman.

I investigated a dozen of firewall-tools before, including shorewall and firehol. Each had it’s stength and its weaknesses. After writing iptables rules in a shell script every now and then for a more complex project (with like 6 networks of which 3 are bridged together) and two dozen of differently configured hosts, NATs, VPN, everything. My predecessor had written a shell script to configure the firewall, but this was really bad to maintain.

So I ended up writing a perl application to generate the rules from a modular configuration (read: usually one file per host, containing a perl hashmap)

Well, after happily using this script for two years, I dedcided it’s about time to rewrite it and document it extensively. I chose python for the rewrite. You can get the result here: Pyroman 0.1.1.

The good:

  • Written in pretty python
  • Extensively documented (Python docstrings)
  • Much faster than sh+awk based solutions
  • Really easy syntax to add hosts, nats
  • You can add custom iptables rules when needed
  • Designed for complex networks
  • Lots of verification checks done before execution
  • Designed to use the same configuration files on multiple hosts (e.g. failover firewalls or the destination host itself; it will detect if you are talking about a local or a remote host
  • It will report file name and line number on parser errors, verification errors and execution errors.
  • If any rule fails to setup, a rollback will occur, restoring your previous firewall
  • (will likely have auto-rollback if you lock yourself out in the next version with a simple timer)
  • Extensive configuration example

The bad:

  • Not yet tested in production
  • Doesn’t completely hide iptables complexity (some core config files are just containing iptables rules, but why invent a new syntax?)
  • Only iptables, no TC/Shaping, no IPsec, proxy arp setup, VPN, ifconfig (I use other tools for that, e.g. heartbeat)

To tease you a little more into testing, here’s an example host configuration: (“dmz” is an interface alias - where the web server is connected to -, as are “INT”, “DMZ” and “ANY” for clients on these interfaces)

"""
A really simple webserver configuration.
These examples are just boring... ;-)
But without NAT they would be even more boring. ;-)
"""
# web server
add_host(
        name="web",
        ip="10.100.1.2",
        iface="dmz"
)
# offering, well, web service.
allow(
        client="ANY DMZ INT",
        server="web",
        service="www ssh ping"
)
# internal hosts may access FTP, too
allow(
        client="INT",
        server="web",
        service="ftp"
)
# setup NAT
add_nat(
        client="ANY INT",
        server="web",
        ip="12.34.56.80"
)

(Yes, this is a python script. No, you probably won’t care to write your configuration in a programming language, will you?)