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:
yes
to log it withlog_rate
no
to 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:
yes
to enable it to all interfacesno
to disable iteth0 eth1 eth2
to enable it to specified interfaceseth0 eth1 eth2
-eth1 -eth2
to enable it to all other interfaces thaneth1 eth2
counter
is to add anonymous byte and packet counter to
all rules. Value can be:
yes
to add it to all rulesno
to not add itlocalhost-public public-localhost
to add it to all rules inlocalhost-public
andpublic-localhost
sections
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-localhost
section.
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 again by conntrack
- Incoming multicast and broadcast rules in listed order
- Everything else in listed order
iplist
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, as above
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/command
pipe it via external command|json:filter
use externaljq
command to parse it as JSON data|html:XPath
parse it as HTML data, using XPath filter|xml:XPath
parse it as XML data, using XPath filter|missing-ok
don'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()
}
Iplists can be manipulated from command line, for example by fail2ban
.
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.
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
This section is deprecated in version 0.28. Use iplist instead. This documentation is for older version only.
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.
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
}
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, output, forward
These sections are used to specify packet mangle rules. prerouting
is for
all incoming packets, postrouting
is for all outgoing packets,
output
is for all locally generated packets and forward
is for all
forwarded packets. Mangle rules are processed before normal zone-zone
filtering rules.
Normally these sections are used to set packet mark value. 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
Foomuuri includes simple network connectivity monitor. It can monitor your internet connection by pinging some external server. Command can be run if network link goes up or down. Example script to send an email to root is included in doc directory. Another example is multi-ISP configuration and script.
Minimal configuration is:
target google {
command fping 8.8.4.4
}
This creates monitor called google
and runs fping
command pinging
IP 8.8.4.4 every second. Foomuuri parses its output and logs up and down
events. Multiple targets can be defined.
Better real life example is:
target my-isp-router {
command fping --interval 2000 172.25.31.149
command_up /etc/foomuuri/monitor.event
command_down /etc/foomuuri/monitor.event
}
This pings IP 172.25.31.149 every two seconds and runs monitor.event
script when link goes up or down. That script sends an email to root.
See man fping
or their website for description
of fping
parameters.
"Up" and "down" are defined with parameters:
target my-isp-router {
history_size 100 # how many results are saved
history_up 80 # count of UPs => n => UP
history_down 30 # count of DOWNs >= n => DOWN
consecutive_up 20 # last n were UP => UP
consecutive_down 10 # last n were DOWN => DOWN
...
}
Target is considered up if 80 of the last 100 pings were successful (allowing failures in between) and last 20 pings were successful (no failures allowed).
Target is considered down if 30 of the last 100 pings were failures or last 10 pings were failures.
curl
and other programs can also be used instead of fping
. See example
shell script
how to use them.
It is recommended to use IP address instead of hostname as fping target. Hostname lookup will fail if network is down when fping starts. Foomuuri will handle this but it will cause 30 second delay and possible fping restart loop.
Optional command_down_interval
can be specified [new in version 0.29].
Foomuuri will run it every down_interval
seconds (default to 600, every
10 minutes). Example:
target my-isp-router {
# Connectivity is still down. Ask NetworkManager to re-initialize
# eth0 connection.
command_down_interval nmcli connection up eth0
# Run it every 15 minutes
down_interval 900
...
}
Monitor statistics are written to a file once a minute.
group
Multiple network connectivity monitor targets can be grouped to single monitor. Example:
group my-isp-group {
target my-isp-router google
command_up /etc/foomuuri/monitor.event
command_down /etc/foomuuri/monitor.event
}
This creates monitor called my-isp-group
which includes two targets.
Group is considered up if any of the targets is up. It is considered down
if all of the targets are down.
Optional command_down_interval
and down_interval
can also be defined.
See above for description. It's usually better
idea to define them in group {}
with multiple targets than in single
target {}
.
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)
}