Configuration - FoobarOy/foomuuri GitHub Wiki
Configuration
Configuration files
Foomuuri reads configuration files from /etc/foomuuri/*.conf in alphabetical
order, including all sub directories. Foomuuri also reads static configuration
from /usr/share/foomuuri/*.conf which can be overwritten in /etc/foomuuri.
Raw nftables rules can be written to /etc/foomuuri/*.nft and they will be
included to generated ruleset.
See best practices for recommendations how to split different sections to multiple configuration files.
foomuuri
This section can be usually omitted as default values should be fine.
This section defines common options for Foomuuri. If really needed, it is usually better to override single value, not full section. Example:
foomuuri {
# Change rpfilter's value, keep everything else as default
rpfilter no
}
Full list of default values are:
foomuuri {
log_rate "1/second burst 3"
log_input yes
log_output yes
log_forward yes
log_rpfilter yes
log_invalid no
log_smurfs no
log_prefix "$(szone)-$(dzone) $(statement)"
log_level "level info flags skuid"
localhost_zone localhost
dbus_zone public
rpfilter yes
counter no
set_size 65535
recursion_limit 10000
priority_offset 5
dbus_firewalld no
nft_bin nft
try-reload_timeout 15
}
log_rate is the default logging rate per source IP. Default value is to
log first three entries per source IP and then one additional entry per second.
Rate specification is the same as in rate limit rule.
log_input ... log_smurfs defines default value for specific logging.
Value can be:
yesto log it withlog_ratenoto not log"3/second burst 10"to log it with specific rate
log_prefix defines the default log prefix for logging.
log_level is the syslog level of logging. For possible values see
rule specific version.
localhost_zone is the name of zone used for the computer running Foomuuri,
similar to "localhost" in hostnames. See zone and
zone-zone sections for more information.
dbus_zone is the name of your outgoing internet zone. This is used in
D-Bus support.
rpfilter is to enable or disable reverse path filtering. Value can be:
yesto enable it to all interfacesnoto disable iteth0 eth1 eth2to enable it to specified interfaceseth0 eth1 eth2-eth1 -eth2to enable it to all other interfaces thaneth1 eth2
counter is to add anonymous byte and packet counter to
all rules. Value can be:
yesto add it to all rulesnoto not add itlocalhost-public public-localhostto add it to all rules inlocalhost-publicandpublic-localhostsections
set_size is the size for rate limit sets. Value 65535 is fine for normal
hosts. For company firewall larger value is required, like 262143 (=2^18 - 1).
This is the maximum amount of rate limit entries in kernel. If set is full,
new entry can't be added and the traffic is accepted without rate limit. See
foomuuri list for content of your active sets.
recursion_limit is the internal limit to avoid macro and template expansion
loop. Increase this value if you get false "Possible macro or template loop"
error.
priority_offset is the chain priority offset for rules generated by Foomuuri.
Tune this value if you have multiple software adding chains and want to
process them in some particular order. For example, iptables uses offset 0
and FirewallD uses 10. Lowest priority is processed first. So to process
Foomuuri rules first, use value -5. To process them last, use 20.
dbus_firewalld is to enable or disable FirewallD D-Bus emulation inside
Foomuuri. NetworkManager can tell FirewallD to attach and detach interfaces
to zones via D-Bus call. This option enables Foomuuri to listen to FirewallD
D-Bus and do the same thing.
nft_bin is the name for nft binary. Full path can be specified if required.
try-reload_timeout is the timeout in seconds for foomuuri try-reload
command.
zone
This section is required on all configurations. It lists all known zones.
zone {
localhost
public
}
Above example defines two zones, localhost and public. All configurations
must have zone localhost, which is the computer running Foomuuri,
similar to "localhost" in hostnames. See
best practices for recommended zone names.
Above example assumes that you are using FirewallD D-Bus (dbus_firewalld
config option) emulation where interfaces are attached and detached to zones
by NetworkManager. It is the recommended way for laptops and personal servers.
This config option will be turned on by default when installing
foomuuri-firewalld package.
You can also define default interface to zone mapping by specifying interface name(s) after zone name. This is useful for corporate servers with static network configuration. This method can be used with or without FirewallD D-Bus emulation. This mapping is only default, not static. Interfaces can still be moved to other zones with D-Bus calls.
zone {
localhost # Localhost must be left empty
public eth0 # eth0 is attached to public
dmz eth1 eth2 # eth1 and eth2 are in dmz
}
It is also possible to use wildcard interface names. If you define wg*
then make sure that NetworkManager doesn't try to assing wg0 to any zone.
It would create "interval overlap" error as wg* and wg0 conflicts.
zone {
localhost
public eth0
wireguard wg* # Matches wg0, wg1, wgfoo, and so on
}
macro
Instead of writing rule tcp 443 it is easier and more readable to use rule
https. These alias names are called macros. Macro can be used in any part
of rule you want to, defining rule fully or partially.
macro {
# Define service as macro
smtp tcp 25
https tcp 443; udp 443
googlemeet udp 3478 19302-19309; https
# Define rate limit as macro
ssh_rate saddr_rate "5/minute burst 5"
# Long macro can be split to multiple lines with "+" (append to previous) or
# "\" (continue in next line).
# Warning: Using "+" or "\" does not add ";". You must add it yourself when
# needed.
good_hosts 10.0.0.1 fd00:f00::1
good_hosts + 10.0.0.2 fd00:f00::2
another 10.0.0.3 \
10.0.0.4
semicolon http
semicolon + ; https
}
You can use macros in other sections, like in zone-zone:
localhost-public {
https daddr good_hosts # Allow https to specific IP addresses
tcp 23 daddr good_hosts # Allow TCP 23 to specific IP addresses
https reject # Reject all other https traffic
googlemeet # Allow Google Meet to everywhere
}
public-localhost {
ssh ssh_rate # Allow incoming ssh with rate limit
}
Macro can include other macros, as googlemeet in above example does.
Using ; in macro splits it to multiple rule lines. You must use it
when macro contains two different rules, like tcp 443 and udp 443 in
https macro, or udp XXX and https in googlemeet macro.
Do not use it when creating list of items (IP addresses for example)
for single rule, like in good_hosts.
All
known macros
can be listed with foomuuri list macro command.
zone-zone
FromZone-ToZone section defines rules for traffic coming from FromZone and going to ToZone. Normally you first accept some traffic and then reject or drop everything else as final rule. Rules inside zone-zone section are (mostly, see below) processed in listed order. Example:
public-localhost {
# Allow some incoming traffic
dhcp-client
ping
ssh
# Drop everything else
drop log
}
localhost-public {
# Allow some outgoing traffic
dhcp-server
domain
https
ping
ssh
# Reject everything else
reject log
}
Foomuuri will automatically add final drop log (or reject log for
localhost-something) rule to zone-zone section if not specified. It is
always better to add explicit final rule to configuration.
Zone-zone section localhost-localhost [new in version 0.22] (aka loopback
traffic, aka 127.0.0.1 and ::1) is special case. It's final rule is
accept. Usually there is no need to add localhost-localhostsection.
Normal use case for localhost-localhost is to deny some traffic and then
accept everything else.
localhost-localhost {
# Don't allow user "untrusted" to connect local services
uid untrusted drop log
# Don't allow local http traffic
http reject log
# Accept everything else
accept
}
Please note that loopback traffic from your public IP to your public IP
belongs to localhost-localhost, not public-public.
If you have a lot of zones there will be a lot of zone-zone pairs. See best practices for recommendations how to split them to multiple files.
"Mostly": Rules inside zone-zone section are automatically sorted and processed in following block order:
- ICMP rules in listed order
- Previously accepted established and related traffic is accepted by conntrack
- Incoming multicast and broadcast rules in listed order
- Everything else in listed order
iplist
[This section is for version 0.28 or newer. For older versions see below old resolve and old iplist sections.]
Instead of using static IP addresses Foomuuri can perform periodical DNS hostname lookups and download external IP-lists. These addresses are then stored to sets and are cached across reboots and single lookup failures.
First word in line is set name, which must begin with @ character.
Next words can be:
- IPv4 or IPv6 address, with or without mask
- DNS hostname
- Filename containing IP addresses, with or without mask
- URL for file containing IP addresses, with or without mask
Example:
iplist {
# Resolve known good hostnames
@goodhost foobar.fi mydomain.com
# Download Finnish IPv4 and IPv6 addresses from https://github.com/ipverse/rir-ip
@fi https://raw.githubusercontent.com/ipverse/rir-ip/master/country/fi/ipv4-aggregated.txt
@fi + https://raw.githubusercontent.com/ipverse/rir-ip/master/country/fi/ipv6-aggregated.txt
# Download Finnish Elisa operator IP addresses from https://github.com/ipverse/asn-ip
@elisa https://raw.githubusercontent.com/ipverse/asn-ip/master/as/719/ipv4-aggregated.txt
@elisa + https://raw.githubusercontent.com/ipverse/asn-ip/master/as/719/ipv6-aggregated.txt
# Read blacklist from text files
@blacklist /etc/foomuuri/blacklist*.txt
# Read content from file and add some extra IPs to it
@whitelist /etc/foomuuri/whitelist*.txt 10.0.0.0/8 192.0.2.32
# Manipulate this list with "foomuuri iplist add mylist 10.0.0.1" command.
# See command line help for "foomuuri add/del/flush" commands.
@mylist
}
public-localhost {
# Allow SSH from known good hosts
ssh saddr @goodhost
# Don't allow blacklisted addresses to IMAP
imap saddr @blacklist drop log "public-localhost DROP-blacklist"
# Allow mylist entries to IMAP without rate
imap saddr @mylist
# Allow Finnish users to IMAP with fast 1 per second rate
imap saddr @fi saddr_rate "1/second burst 10"
# Allow everybody to IMAP with slow 1 per minute rate. This includes
# over rate limit Finnish users.
imap saddr_rate "1/minute burst 1"
# ...rest of the rules...
}
Hostnames are refreshed every 15 minutes and they will timeout after 24 hours. URLs are refreshed once a day and timeout is 10 days. These values can be changed globally or per set.
iplist {
# Define global timeouts
dns_refresh=15m
dns_timeout=24h
url_refresh=1d
url_timeout=10d
# Define per set timeout
@fasturl https://some/url url_refresh=1h30m url_timeout=2d
}
Above timeouts are rounded to 15 minutes. This can be configured with
systemctl edit foomuuri-iplist.timer command.
Downloaded content can be filtered by adding |filter after filename,
URL or hostname. Multiple filters can be chained.
|shell:/path/to/commandpipe it via external command|json:filteruse externaljqcommand to parse it as JSON data|html:XPathparse it as HTML data, using XPath filter|xml:XPathparse it as XML data, using XPath filter|missing-okdon't print warning if download or DNS resolve fails
Example:
iplist {
# Download Github IP address list and parse it as JSON, returning
# "actions" list.
@github https://api.github.com/meta|json:.actions[]
# Download network scanner IP address list and parse it from HTML page.
@netscanner https://internet-measurement.com/|html://div/pre/text()
}
Optional -merge option disables IP address auto-merge. Normally it is
recommended to keep it enabled. For fail2ban alike scenarios (see below)
it is recommended to be disabled. [New in version 0.30]
Iplists can be manipulated from command line, for example by fail2ban
external program. Command foomuuri iplist add @setname ipaddress adds IP
address to @setname. Other commands are foomuuri iplist list,
foomuuri iplist del and foomuuri iplist flush. See command line help for
usage. Example:
iplist {
@blacklist -merge
}
# Manipulate with command:
#
# foomuuri iplist add @blacklist 10.0.0.1
# foomuuri iplist del @blacklist 10.0.0.1
Another example how to create a macro to allow access to Valve Steam:
iplist {
# Create iplist from Valve's IP addresses
@valve_as https://raw.githubusercontent.com/ipverse/asn-ip/master/as/32590/ipv4-aggregated.txt
@valve_as + https://raw.githubusercontent.com/ipverse/asn-ip/master/as/32590/ipv6-aggregated.txt
}
macro {
# Create macro to allow outgoing traffic to Valve iplist
valve-steam udp 3478 4379-4380 27000-27100 daddr @valve_as;
valve-steam + tcp 27015-27050 daddr @valve_as
}
localhost-public {
# Allow outgoing traffic to Valve Steam
valve-steam
}
resolve (old)
[This section is for version 0.27 or older only. For newer versions see above iplist section.]
Instead of using static IP addresses Foomuuri can perform periodical DNS
lookups for hostnames and store their IPv4 and IPv6 addresses to set. Set
name must begin with @ character. Static IPv4 or IPv6 address with or
without mask can also be used [new in version 0.25].
resolve {
# Resolve foobar.fi and store its IP addresses to @foobar_fi set
@foobar_fi foobar.fi
# Resolve multiple hostnames to set @fooweb
@fooweb foo-web.foobar.fi bar-web.foobar.fi
@fooweb + baz-web.foobar.fi
# Mixing hostnames and IP addresses
@one_ip 10.0.0.1
@mixed foobar.fi 192.0.2.0/24
}
localhost-public {
https daddr @fooweb # Allow https to above hostnames
https reject # Reject all other https
}
Lookups are refreshed every 15 minutes. This interval can be changed using
systemctl edit foomuuri-resolve.timer. Single lookup failure does not
matter, Foomuuri will cache results for 24 hours. These results are also
saved for reloads and reboots.
iplist (old)
[This section is for version 0.27 or older only. For newer versions see above iplist section.]
This is similar to resolve but set content can be specified as:
- Filename containing one IP address per line, with or without mask
- URL for file, as above
- IPv4 or IPv6 address, with or without mask [new in version 0.25]
iplist can be used to blacklist or whitelist IP addresses, or to
download IP address country databases (aka geolocation). Set name must
begin with @ character.
Set name without filename or URL configures an empty set. Its entries can be
manipulated with foomuuri iplist add and foomuuri iplist del commands.
iplist {
# Download Finnish IPv4 and IPv6 addresses from https://github.com/ipverse/rir-ip
@fi https://raw.githubusercontent.com/ipverse/rir-ip/master/country/fi/ipv4-aggregated.txt
@fi + https://raw.githubusercontent.com/ipverse/rir-ip/master/country/fi/ipv6-aggregated.txt
# Download Finnish Elisa operator IP addresses from https://github.com/ipverse/asn-ip
@elisa https://raw.githubusercontent.com/ipverse/asn-ip/master/as/719/ipv4-aggregated.txt
@elisa + https://raw.githubusercontent.com/ipverse/asn-ip/master/as/719/ipv6-aggregated.txt
# Read blacklist from text files
@blacklist /etc/foomuuri/blacklist*.txt
# Read content from file and add some extra IPs to it
@whitelist /etc/foomuuri/whitelist*.txt 10.0.0.0/8 192.0.2.32
# Manipulate this list with "foomuuri iplist add mylist 10.0.0.1" command.
@mylist
}
public-localhost {
# Don't allow blacklisted addresses to IMAP
imap saddr @blacklist drop log "public-localhost DROP-blacklist"
# Allow mylist entries to IMAP without rate
imap saddr @mylist
# Allow Finnish users to IMAP with fast 1 per second rate
imap saddr @fi saddr_rate "1/second burst 10"
# Allow everybody to IMAP with slow 1 per minute rate. This includes
# over rate limit Finnish users.
imap saddr_rate "1/minute burst 1"
# ...rest of the rules...
}
Lookups are refreshed every 24 hours. Like in resolve, lookups are
cached for 10 days for lookup failures, reloads and reboots.
Refresh interval can be configured [new in version 0.22] globally or
per-iplist with refresh option:
iplist {
# Set global refresh interval
refresh 4h15m
# Use global refresh interval
@blacklist /etc/foomuuri/blacklist*.txt
# Use per-iplist refresh interval
@whitelist /etc/foomuuri/whitelist*.txt refresh=1h15m
}
Interval is rounded to 15 minutes. This can be configured with
systemctl edit foomuuri-iplist.timer command.
zone-any, any-zone, any-any
These sections are similar to zone-zone section, except that they match any destination (zone-any), any source (any-zone) or all (any-any) traffic. These rules are processed first and then normal zone-zone rules. Example:
localhost-any {
# Allow ping and SSH for all traffic from localhost, no matter where
# it is going. Normally reject/drop statement is added to specific
# localhost-zone section, not to localhost-any.
ping
ssh
}
localhost-public {
# Accept HTTPS to public, in addition to localhost-any rules.
https
reject log
}
localhost-internal {
# Accept DNS queries to internal, in addition to localhost-any rules.
domain
reject log
}
Matcher szone -public can be used in rule to skip adding it to
public-localhost [new in version 0.24]. Example:
any-localhost {
ssh # allow ssh from anywhere
https szone -public # allow https from anywhere except from public
}
localhost-any {
ssh # allow ssh to anywhere
vnc dzone -public # allow vnc to anywhere except to public
}
template
Template is very similar to macro. It's just another
way to define list of rules. Usually macro refers to single service
(like domain or facetime) while template refers to list of different
services. Example:
template outgoing_services {
# Define template called "outgoing_services"
dhcp-server
domain
https
ntp
ping
ssh
}
localhost-public {
# Include template's content here
template outgoing_services
# Continue with other rules
http
reject log
}
dmz-public {
# Use same template for traffic coming from dmz zone
template outgoing_services
# Continue with other rules
reject log
}
zonemap
Normally Foomuuri will map incoming and outgoing traffic to zones by source and destination network interface. These interfaces are assigned to zones dynamically by NetworkManager, or configured in zone section.
Zonemap section can be used to map traffic to different zone by using standard rules. Example:
zonemap {
# Map outgoing IPsec traffic that is going to zone "public" to use zone
# "vpn" instead.
dipsec dzone public new_dzone vpn
# Same for incoming.
sipsec szone public new_szone vpn
}
localhost-public {
# Rules for non-IPsec traffic
ipsec # You must allow IPsec traffic here and in public-localhost
...accept some traffic...
reject log
}
localhost-vpn {
# Rules for IPsec traffic
...accept some traffic...
reject log
}
Above example, splitting traffic to IPsec and non-IPsec zones is the most
common use case. You can use any matcher, for example daddr or saddr to
map some IP addresses to own zones, or uid or gid to map outgoing
traffic from some local user to own zone:
zonemap {
# Map IP address 10.2.3.0/24 from internal to dmz
saddr 10.2.3.0/24 szone internal new_szone dmz
daddr 10.2.3.0/24 dzone internal new_dzone dmz
# Map outgoing traffic from user myservice to myzone
uid myservice szone localhost new_szone myzone
# Map all outgoing IPsec traffic to xxx-vpn, no matter what the original
# dzone was
dipsec new_dzone vpn
}
snat
Source NAT is used to mangle traffic by using standard rules. Example:
snat {
# Masquerade all traffic from 10.0.0.0/8 going to eth0 interface.
# New outgoing IP is eth0's IP address.
saddr 10.0.0.0/8 oifname eth0 masquerade
# Use outgoing IP 192.0.2.32 to all non-IPsec traffic coming from
# 10.0.0.0/8 and going to eth1 interface.
saddr 10.0.0.0/8 oifname eth1 -dipsec snat to 192.0.2.32
# IPv6-to-IPv6 Network Prefix Translation (NPTv6) [new in version 0.29]
saddr fd00:f00:4444::/64 oifname eth2 snat_prefix to 2a03:1111:222:8888::/64
}
Remember to accept SNAT'ed traffic in zone-zone section. See dnat below for more examples.
dnat
Destination NAT is used to mangle traffic by using standard rules. Example:
dnat {
# http traffic to 10.0.0.1 is DNAT'ed to 10.0.0.2 port 8080
daddr 10.0.0.1 http dnat to 10.0.0.2:8080
# http traffic to fd00:f00::1 is DNAT'ed to fd00:f00::2 port 8080
# [new in version 0.22]
daddr fd00:f00::1 http dnat to [fd00:f00::2]:8080
# http traffic to 10.0.0.6 is DNAT'ed to 10.0.0.7, port doesn't change
daddr 10.0.0.6 http dnat to 10.0.0.7
# All smtp traffic from eth2 is DNAT'ed to 10.0.0.8 or fd00:f00::8,
# port doesn't change
iifname eth2 smtp dnat to 10.0.0.8 fd00:f00::8
# All traffic from eth1 inteface is DNAT'ed to 10.0.0.3
iifname eth1 dnat to 10.0.0.3
# http traffic to 10.0.0.4 coming from interface eth2 is DNAT'ed to 10.0.0.5
iifname eth2 daddr 10.0.0.4 http dnat to 10.0.0.5
}
Remember to accept DNAT'ed traffic in zone-zone section. This can be done
with specific rule or with ct_status matcher. Example:
public-internal {
# Specific rule to accept https
https daddr 10.0.0.9
# Generic rule to accept all DNAT'ed traffic
ct_status dnat
}
prerouting, postrouting, forward, input, output
These sections are used to specify packet mangle rules. Mangle rules are processed before normal zone-zone filtering rules.
preroutingis for all incoming packetspostroutingis for all outgoing packetsforwardis for all forwarded packets (for exampleinternal-public)inputis for all packets targetted tolocalhost(public-localhost) [new in version 0.29]outputis for all locally generated packets (localhost-public)
Normally these sections are used to set packet mark value or MSS clamping.
Example:
prerouting {
# Do nothing if mark is already set
mark_match -0x0000/0xff00 accept
# Set default mark 0x100 to packet
mark_set 0x100/0xff00
# Change mark to 0x200 if it is coming from eth2
iifname eth2 mark_set 0x200/0xff00
# Use mark 0x300 for SSH traffic from eth2
iifname eth2 ssh mark_set 0x300/0xff00
}
Chain type and hook priority can also be specified [new in version 0.28]. Example:
prerouting filter raw {
...
}
postrouting nat srcnat + 20 {
...
}
invalid, rpfilter, smurfs
Packets entering invalid, rpfilter or smurfs chains will be dropped.
These sections can be used to specify more rules to them [new in version 0.23].
For example load balanced IPVS traffic might enter to invalid chain and must
be accepted:
invalid {
# Accept HTTPS IPVS traffic
https
}
hook
Foomuuri can run external command before/after starting and stopping. This section configures those commands. Example:
hook {
pre_start command-to-run with arguments before loading ruleset
post_start echo firewall started
pre_stop /etc/foomuuri/pre_stop.sh
post_stop /etc/foomuuri/post_stop.sh with arguments
}
target, group
Foomuuri includes simple network connectivity monitor. These sections are used to configure it.
Miscellaneous
Comments can be written as # comment.
Long line can be split to multiple lines by adding \ to end of line.
Multiple words can be combined to single word by writing them in quotes.
For example ssh accept log "accept ssh for testing" will accept SSH
traffic with log message accept ssh for testing.
Macro expansion can be skipped by writing word in
quotes. For example "ssh" is kept as ssh and not expanded to tcp 22.
Output from external command can be used to generate rules. It can return
single line, multiple lines or part of line. Syntax is
$(shell command to run). Command is run with shell so pipes and ; will
work. Be careful to run only trusted commands.
Example:
# This is a comment
macro {
# Define local_port_range macro by reading correct value from /proc file
local_port_range $(shell sed s/\\t/-/ < /proc/sys/net/ipv4/ip_local_port_range)
}
localhost-public {
ssh # This is a comment
smtp \
daddr 192.0.2.32 # Allow SMTP to single IP
}
public-localhost {
tcp local_port_range # Allow TCP to ports 32768-60999 (default range)
}