The WallFire HOWTO

1 - About this document

This document has been started on May 1st 2004 by Grégoire HUBERT <greg AT coolkeums DOT org>.

Revisions:


2 - What is WallFire

WallFire is a coherent toolset to help managing firewalls.
Considering the fact that most firewalls have powerful but complicated and sophisticated languages, the aim of this project is to offer comprehensive tools to set the network security policy whatever the underlying firewall may be. WallFire makes it possible to configure your firewall in few operations. It comes with his own high-level rules langage that can be translated into different firwalls rulesets. For the moment, support for netfilter (almost working) and ipfilter is planned.
WallFire currently provides the following tools:

What can I do with WallFire now?

you can only set a simple firewall script to test the language. WallFire is still under heavy development and we need your feedback and/or bug reports to make it the perfect firewall toolkit. ;-)

3 - The WallFire language

3.1 - Introduction

As described above, the WallFire language is a high level ruleset description language. It can be translated into a netfilter ruleset using the wfconvert tool.

firewall $fw {
	interface ppp0 {
		zone $internet;
	}
}

accept {
	from $internet to $fw dport ssh;
	from $fw to $internet;
};

This simple WallFire script will set up a firewall accepting SSH only. You will find in this document the complete WallFire language guide.


3.2 - Structure

The language is divided in two main parts: a head (declarations) and a body (rules). The head part is also separated in 5 parts.

3.3 - Syntax

3.3.1 - Comments

WallFire has several comment types:


3.3.2 - The WallFire variables

All WallFire variables are prefixed by $ symbol. For now, supported objects are:

3.3.3 - Zones

The zones section enables to declare networks by associating a name to their addresses.
There is a special builtin zone which is called internet, which is already declared by default (by definition, it has no network address). This is generally the zone where the firewall's defaut gateway points to.
The zones section can be empty when there is no zone (no other zone than internet). You can define several zones.

# DMZ zone
zone $dmz = 192.168.1.0/28;

# LAN zone
zone $lan = 10.0.0.0/255.255.0.0;


3.3.4 - Firewalls

The firewalls section enables to declare one or more firewalls, with their interfaces.
You have to define at least one firewall, but you can describe several ones if needed.
The syntax is:

firewall $name {
	interface name {
		[macaddr;]
		[addr;]
		[broadcast;]
		zone $zone;
	}
}

The lines into brackets are optional parameters.

Each interface must have an associated declared zone. If we considere the previous zones $lan and $dmz we can declare the following firewall:

firewall $fw {
	interface ppp0 {
		zone internet;
	}
	interface eth0 {
		static address 192.168.1.1;
		zone $dmz;
	}
	interface eth1 {
		static address 10.0.0.1;
		broadcast 10.0.255.255;
		zone $lan;
	}
}


3.3.5 - The metahost and metaport keywords

You can identify several hosts, networks in a wallfire variable using the metahost keyword.

metahost $web_server = 192.168.11.80;
metahost $dns = (192.168.11.53, 10.0.0.53);
metahost $servers = ($web_server, $dns, $dmz);

You can also define UDP or TCP ports with the metaport keyword:

metaport $forbidden = (111, telnet, 340:353);


3.3.6 - The group statement

Inline groups

Inline groups are similar to inline functions in C or C++. An inline group is a kind of macro: the bits of rules it contains are simply substituted into its caller.

The syntax of its definition is:

inline groupdef mygroup((ARGS) {
  RULES
}

ARGS is optional. If no arguments are given, () can be omitted.
ARGS is a list of variables (such as metahost or metaport) separated by commas. Each can be given a default value with sign '=' (like in C++).
RULES do not have to contain a target.

inline groupdef dns {
	proto udp dport domain;
	proto tcp dport domain;
}
accept from toto to dnsservers group dns;

is strictly equivalent to:

accept from toto to dnsservers {
	proto udp dport domain;
	proto tcp dport domain;
};

Now, let's declare an inline-group named toproxy:

inline groupdef toproxy(metahost $proxy = 192.168.0.2) {
	to $proxy proto tcp dport 8080;
}

The $proxy argument will be set to default value 192.168.0.2 if $proxy is not defined when calling toproxy group.

accept from toto to dnsservers group toproxy($proxy: 10.0.0.3);
accept from toto to dnsservers group toproxy;

is strictly equivalent to:

accept from toto to dnsservers to 10.0.0.3 proto tcp dport 8080;
accept from toto to dnsservers to 192.168.0.2 proto tcp dport 8080;

Groups (non-inline)

Groups (non inline ones) are groups of rules (each rule must contain a target). They behave like netfilter/iptables's chains, or ipfilter groups.
When translated into the target firewalling language, the wallfire groups will not be substituted at the caller's place, but will take advantage of the underlying facilities (chains, groups).

groupdef logdrop {
	log;
	drop;
}

When translated into netfilter/iptables, the example above will create a logdrop chain with the corresponding rules:

iptables -N logdrop
iptables -A logdrop -j LOG
iptables -A logdrop -j DROP

3.3.7 - The rules

A rule is a combinaison of instructions. Here are the supported keywords:

where

Simple example:

from $internet to $fw accept proto tcp dport ssh;

Example using a bloc:

from $internet to $fw {
	accept proto tcp dport ssh;
	reject proto tcp dport auth;
	# drop packets without logging them
	drop group samba;
	# log and drop everything else according to our logdrop group definition (see 3.3.6).
	logdrop;
};

from $network to $metahost {
	reject with tcp-reset proto tcp dport ident;
	reject with icmp-host-unreachable proto udp sport domain;
	log "Virus:" proto (udp, tcp) dport 12345;
};

4.0 - Example: A Dual-DMZ network


zone $public_dmz = 212.155.209.128/29;
zone $private_dmz = 192.168.101.0/24;
zone $lan = 10.0.0.0/255.255.0.0;

firewall $obiwan {
	interface eth0 {
		static address 212.155.209.128;
		zone $internet;
	}
	interface eth1 {
		static address 212.155.209.128;
		zone $public_dmz;
	}
	interface eth2 {
		static address 192.168.101.1;
		zone $private_dmz;
	}
	interface tr0 {
		static address 10.0.0.1;
		zone $lan;
	}
}

metahost $dns_servers = (192.168.101.69, 192.168.101.45);
metahost $proxy_cache = 212.155.209.134;
metahost $web_cluster = 192.168.101.80;
metahost $web_servers = 192.168.101.81-192.168.101.84;
metahost $database = 192.168.101.132;
metahost $mail_relay = 212.155.209.130;
metahost $mail_server = 192.168.101.25;
metahost $backup_server = 192.168.101.250;
metahost $admins = (10.0.1.100, 10.0.1.101, 10.0.1.103);

inline groupdef dns {
	proto udp dport domain;
	proto tcp dport domain;
}

groupdef logdrop {
	log;
	drop;
}
	
to $obiwan {
	from $admins accept proto tcp dport ssh;
	accept from ($lan, $private_dmz, $public_dmz) proto icmp;
	group logdrop;
};

to $public_dmz {
	from $internet {
		accept proto tcp {
			dport www to $proxy_cache;
			dport smtp to $mail_relay;
		};
	};
	accept proto (tcp, udp) from $backup_server;
	reject from $private_dmz;
	accept from $admins proto tcp dport ssh;
	from $lan {
		accept proto tcp dport www to $proxy_cache;
		reject;
	};
};
accept from $obiwan;

to $private_dmz {
	from $public_dmz {
		accept group dns to $dns_servers;
		accept proto tcp {
			dport www from $proxy_cache to $web_cluster;
			dport smtp from $mail_relay to $mail_server;
		};
	};
	from $lan {
		accept group dns to $dns_servers;
		accept proto tcp {
			dport ssh from $admins;
			dport www to $web_cluster;
			dport smtp to $mail_server;
			dport 5432 to $database;
		};
		reject;
	};
	from $obiwan accept;
};

reject to $lan from ($private_dmz, $obiwan);