maxkellermann / ferm Goto Github PK
View Code? Open in Web Editor NEWferm is a frontend for iptables
License: GNU General Public License v2.0
ferm is a frontend for iptables
License: GNU General Public License v2.0
Hi,
this might be more feature request as an issue.
Would it be possible to return or @resolve
IP address if the input is IP address?
if type == 'A' and address is IPv4:
return address
if type == 'AAAA' and address is IPv6:
return address
I'm not an expert for neither Linux nor iptables but wanted to get my iptables persistent via ferm. So I installed it on Debian via sudo apt install ferm
and answered that it should be persistent (to to best of my knowledge at least). My ferm rules are stored in /etc/ferm/ferm.conf
and work fine when applied manually (via sudo apt ferm --interactive /etc/ferm/ferm.conf)
. The service was not running so I also started it manually via sudo service ferm start
which also loads the ferm rules fine. However, with each reboot the ferm service is loaded but dead and no rules are applied. Did I do something wrong, did I miss or overlooked something else or is this how ferm is supposed to work?
Hi,
I am trying to use the sane helper module to configure my firewall to allow access to a scanner.
Here is the Ferm configuration I use:
domain ip {
table raw {
chain PREROUTING {
saddr $TRUSTED_NETWORKS proto tcp mod helper helper sane CT;
}
}
}
that produces the following iptable entry:
~# iptables -L -nv -t raw
Chain PREROUTING (policy ACCEPT 112 packets, 15721 bytes)
pkts bytes target prot opt in out source destination
0 0 CT tcp -- * * 0.0.0.0/0 0.0.0.0/0 helper match "sane" CT
Unfortunately it doesn' work (as we can see with the pkts
and bytes
counters).
However, if I use the following raw iptables command : iptables -t raw -A PREROUTING -p tcp -j CT --helper sane
that produces the following entry:
~# iptables -L -nv -t raw
Chain PREROUTING (policy ACCEPT 7 packets, 488 bytes)
pkts bytes target prot opt in out source destination
7 488 CT tcp -- * * 0.0.0.0/0 0.0.0.0/0 CT helper sane
it does work.
Am I missing something in the use of the helper module with Ferm ?
I am using Ferm 2.5.1 on Ubuntu 16.04.6(kernel 4.15.0-76-generic).
Debian sid with its ferm 2.4 .
Write this configuration (ferm.test):
# -*- shell-script -*-
# vim: set ft=sh:
@def &LIMIT_LOG() = mod limit limit 2/sec limit-burst 50;
domain ip {
table raw {
chain PREROUTING policy ACCEPT;
chain OUTPUT policy ACCEPT;
chain PREROUTING {
mod rpfilter invert {
&LIMIT_LOG() NFLOG nflog-prefix "test1:$LINE";
NFLOG nflog-prefix "test2:$LINE";
DROP;
}
}
}
}
Load the config and check the actual iptables configuration:
ferm ferm.test
iptables-save
Here the raw table printed by iptables-save has wrong line numbers, in both cases:
*raw
:PREROUTING ACCEPT [16:1056]
:OUTPUT ACCEPT [1:29]
-A PREROUTING -m rpfilter --invert -m limit --limit 2/sec --limit-burst 50 -j NFLOG --nflog-prefix "test1:4"
-A PREROUTING -m rpfilter --invert -j NFLOG --nflog-prefix "test2:5"
-A PREROUTING -m rpfilter --invert -j DROP
COMMIT
But if you comment the line with the function call, then the line number showed by "test2" is correct:
*raw
:PREROUTING ACCEPT [1:78]
:OUTPUT ACCEPT [0:0]
-A PREROUTING -m rpfilter --invert -j NFLOG --nflog-prefix "test2:14"
-A PREROUTING -m rpfilter --invert -j DROP
COMMIT
Therefore, it is not possible to create functions with optional arguments.
I thought this was not supported and only found this by searching the repository for "zone". Relevant test: test/targets/ct.ferm.
Both eui64 and fuzzy modules descriptions are strangely between double quotes.
Example:
=item B<eui64>
"This module matches the EUI-64 part of a stateless autoconfigured
IPv6 address. It compares the EUI-64 derived from the source MAC
address in Ehternet frame with the lower 64 bits of the IPv6 source
address. But "Universal/Local" bit is not compared. This module
doesn't match other link layer frame, and is only valid in the
PREROUTING, INPUT and FORWARD chains."
mod eui64 ACCEPT;
ferm does not order domains, tables and chains on execution. While this doesn't matter in the end when the ruleset is loaded into iptables-restore, this makes it harder to spot differences introduced by configuration changes.
$ wget http://ferm.foo-projects.org/download/examples/dmz_router.ferm
$ for i in `seq 1 100`; do /usr/sbin/ferm -nl dmz_router.ferm | grep -v "Generated by" > output$i; done
$ $ md5sum output* | sort | cut -d ' ' -f 1 | uniq -c
60 58ae6e333eba0942acb398535247f216
40 c7f8c076953336936f2768f23fceba27
$ diff -u output97 output98
--- output97 2017-03-02 15:07:27.688374585 +0100
+++ output98 2017-03-02 15:07:27.716374709 +0100
@@ -1,3 +1,13 @@
+*nat
+:POSTROUTING ACCEPT [0:0]
+:PREROUTING ACCEPT [0:0]
+-A POSTROUTING --source 192.168.0.0/24 --out-interface eth1 --jump SNAT --to-source 193.43.91.203
+-A POSTROUTING --source 192.168.1.0/24 --out-interface eth1 --jump SNAT --to-source 193.43.91.203
+-A PREROUTING --in-interface eth1 --destination 193.43.91.203 --protocol tcp --dport http --jump DNAT --to-destination 192.168.1.2
+-A PREROUTING --in-interface eth1 --destination 193.43.91.203 --protocol tcp --dport smtp --jump DNAT --to-destination 192.168.1.3
+-A PREROUTING --in-interface eth1 --destination 193.43.91.203 --protocol tcp --dport domain --jump DNAT --to-destination 192.168.1.4
+-A PREROUTING --in-interface eth1 --destination 193.43.91.203 --protocol udp --dport domain --jump DNAT --to-destination 192.168.1.4
+COMMIT
*filter
:FORWARD DROP [0:0]
:INPUT DROP [0:0]
@@ -28,13 +38,3 @@
-A INPUT --in-interface eth1 --protocol tcp --dport 8080 --jump REJECT
-A INPUT --in-interface eth1 --protocol tcp --dport 3128 --jump REJECT
COMMIT
-*nat
-:POSTROUTING ACCEPT [0:0]
-:PREROUTING ACCEPT [0:0]
--A POSTROUTING --source 192.168.0.0/24 --out-interface eth1 --jump SNAT --to-source 193.43.91.203
--A POSTROUTING --source 192.168.1.0/24 --out-interface eth1 --jump SNAT --to-source 193.43.91.203
--A PREROUTING --in-interface eth1 --destination 193.43.91.203 --protocol tcp --dport http --jump DNAT --to-destination 192.168.1.2
--A PREROUTING --in-interface eth1 --destination 193.43.91.203 --protocol tcp --dport smtp --jump DNAT --to-destination 192.168.1.3
--A PREROUTING --in-interface eth1 --destination 193.43.91.203 --protocol tcp --dport domain --jump DNAT --to-destination 192.168.1.4
--A PREROUTING --in-interface eth1 --destination 193.43.91.203 --protocol udp --dport domain --jump DNAT --to-destination 192.168.1.4
-COMMIT
I ran sudo import-ferm
to convert my currrent firewall settings to ferm. It spewed several lines and stopped at 'option 'f' in line 99 not understood'
. seems like something went wrong. the existing firewalls rules were generated by Arno's firewall
correct command:
ebtables -t broute -A BROUTING --protocol IPV4 --match ip --source <IP> --jump ACCEPT
in ferm form:
% cat test.conf
domain eb table broute chain BROUTING {
proto IPV4 mod ip source <IP> ACCEPT;
}
% /usr/sbin/ferm --shell --remote test.conf
...
ebtables -t broute -A BROUTING --protocol IPV4 --match ip --source <IP> --jump ACCEPT
# ebtables ...
Unknown argument: '--match
ssia.
E.g.
chain (INPUT FORWARD) {
@if @eq($CHAIN, INPUT) ...
won't work because $CHAIN contains the array (INPUT FORWARD)
instead of the currently processed one.
Steps to reproduce:
# ebtables -t broute -F
# ebtables -t broute -L
Bridge table: broute
Bridge chain: BROUTING, entries: 0, policy: ACCEPT
domain eb table broute chain BROUTING {
daddr $PrinterMAC DROP;
}
and restart ferm, rule will appear, as expected:
# ebtables -t broute -L
Bridge table: broute
Bridge chain: BROUTING, entries: 1, policy: ACCEPT
-d PrinterMAC -j DROP
2
and restart ferm, the rule will remain:# ebtables -t broute -L
Bridge table: broute
Bridge chain: BROUTING, entries: 1, policy: ACCEPT
-d PrinterMAC -j DROP
http://ferm.foo-projects.org/download/2.5/NEWS
v2.5 - not yet released
REJECT reject-with icmp-proto-unreachable is valid ipv4, but not ipv6
ipv4:
root@host:~# iptables -j REJECT -h | grep "Valid reject types" -A 17
Valid reject types:
icmp-net-unreachable ICMP network unreachable
net-unreach alias
icmp-host-unreachable ICMP host unreachable
host-unreach alias
icmp-proto-unreachable ICMP protocol unreachable
proto-unreach alias
icmp-port-unreachable ICMP port unreachable (default)
port-unreach alias
icmp-net-prohibited ICMP network prohibited
net-prohib alias
icmp-host-prohibited ICMP host prohibited
host-prohib alias
tcp-reset TCP RST packet
tcp-rst alias
icmp-admin-prohibited ICMP administratively prohibited (*)
admin-prohib alias
ipv6:
root@host:~# ip6tables -j REJECT -h | grep "Valid reject types" -A 11
Valid reject types:
icmp6-no-route ICMPv6 no route
no-route alias
icmp6-adm-prohibited ICMPv6 administratively prohibited
adm-prohibited alias
icmp6-addr-unreachable ICMPv6 address unreachable
addr-unreach alias
icmp6-port-unreachable ICMPv6 port unreachable
port-unreach alias
tcp-reset TCP RST packet
tcp-reset alias
Using reject-with icmp-proto-unreachable in a block shared by both ip
and ip6
causes an error
root@host:/etc/ferm# ferm ferm.conf
ip6tables-restore v1.4.21: unknown reject type "icmp6-proto-unreachable"
Error occurred at line: 16
Try `ip6tables-restore -h' or 'ip6tables-restore --help' for more information.
Failed to run /sbin/ip6tables-restore
Firewall rules rolled back.
This means the configuration that could otherwise be combined due to the mapping that ferm already does doesn't work and the configuration has to be duplicated.
Is it possible to have ferm automatically drop icmp-proto-unreachable when the domain is ip6 so that we can keep the configuration the same?
(According to this: https://www.toofishes.net/blog/making-things-ipv6-capable/ we can just drop the reject-with override)
Debian updated ferm from v2.4 to v2.5 recently, after which my config started failing.
Here is a minimal reproducible config I have managed to come up with:
@def $HOSTS = (192.168.0.40 2001:abcd:ef::40);
domain (ip ip6) table nat chain OUTPUT {
proto tcp dport ssh DNAT to @ipfilter($HOSTS);
}
Here is the error:
$ sudo ferm -l ~/test.conf
# Generated by ferm 2.5 (iptables-legacy-save) on Sat Apr 18 14:38:24 2020
*filter
:FORWARD ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
*mangle
:FORWARD ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
COMMIT
*nat
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
-A OUTPUT --protocol tcp --dport ssh --jump DNAT --to-destination deferred=ARRAY(0x55b7a9219368)
COMMIT
iptables-restore v1.8.4 (legacy): Bad IP address "deferred=ARRAY(0x55b7a9219368)"
Error occurred at line: 19
Try `iptables-restore -h' or 'iptables-restore --help' for more information.
Failed to run /usr/sbin/iptables-legacy-restore
# Generated by ferm 2.5 (ip6tables-legacy-save) on Sat Apr 18 14:38:24 2020
*filter
:FORWARD ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
*nat
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
-A OUTPUT --protocol tcp --dport ssh --jump DNAT --to-destination deferred=ARRAY(0x55b7a935b368)
COMMIT
ip6tables-restore v1.8.4 (legacy): Bad IP address "deferred=ARRAY(0x55b7a935b368)"
Error occurred at line: 12
Try `ip6tables-restore -h' or 'ip6tables-restore --help' for more information.
Failed to run /usr/sbin/ip6tables-legacy-restore
Firewall rules rolled back.
We currently use ferm
in our puppet manifest and i would like to be able to run a test which can validate that all the rules loaded in iptables
are the same rules configured in ferm
. This would allow us to create a puppet managed service that ensures the loaded firewall rules match the rules configured so if someone manually added a rule or flushes the table puppet restore rules on the next run.
The simplest way to do this would be something like the following sudo code
if [ "$(iptables-save)" -ne "(ferm -nl --domain ip)" -o "$(ip6tables-save)" -ne "(ferm -nl --domain ip6)" ] ;then
systemctl reload ferm
fi
however the output from iptables-save
and ferm
use slightly different rules for producing output short options vs long options and some difference in the order of selectors. Would it be possible to update ferm
so it uses the same rules for its output as iptables-save
in case others come across this im currently trying to work around this with the following script
https://gerrit.wikimedia.org/r/c/operations/puppet/+/576101/5/modules/ferm/files/ferm_status.py#153
thanks
It may not be specific to module policy or subchains, however this case illustrate an issue with keyword parsing.
Could that be related to deep-copy of nested blocks?
This config works fine:
table filter {
chain INPUT {
mod policy dir in pol none @subchain {
proto tcp ACCEPT;
}
}
}
However this one will result in an error:
table filter {
chain INPUT {
mod policy dir in pol none @subchain {
proto tcp dport 80 ACCEPT;
}
}
}
Error in test.conf line 7:
chain INPUT
{
mod policy dir in pol none @subchain
{
proto tcp dport <--
To use sport or dport, you have to specify "proto tcp" or "proto udp" first
Using icmp-type
after proto icmp
would raise the same type of error.
Any thought on this? I have no clue on the code so far.
Cheers
First of all thanks and congratulations to the ferm-tool - it comes in very handy and is very useful; keep up with the great work!
One (rather minor) option I'm missing from time to time when starting from scratch would be a simple ferm --flush-all
(without a config file provided) to remove any rules although I don't have a ferm.conf file at hand.
Maybe, I'm overlooking some reasoning against something like this, but at the moment I thought it would be a nice-to-have option :-)
The "Basic iptables match keywords" chapter says:
module [module-name]
Load an iptables module. Most modules provide more match keywords. We'll get to that later.
But in the entire document modules are always loaded using "mod". Maybe the previous definition should clarify that both "mod" and "module" are valid keywords.
I was trying to build ferm for opensuse, and I got the following warning:
[ 41s] ferm.noarch: W: incorrect-fsf-address /usr/sbin/ferm
[ 41s] ferm.noarch: W: incorrect-fsf-address /usr/sbin/import-ferm
[ 41s] ferm.noarch: W: incorrect-fsf-address /usr/share/doc/packages/ferm/COPYING
[ 41s] The Free Software Foundation address in this file seems to be outdated or
[ 41s] misspelled. Ask upstream to update the address, or if this is a license file,
[ 41s] possibly the entire file with a new copy available from the FSF.
This is only a warning so it isn't a showstopper but it would be nice to have the gpl2 licenses updated in these files.
Hello,
as I need NAT64 with Jool for IPv6 Migration, I need ferm (as added in 3920629) to support this feature. Unfortunately, there is no official release tag yet with Jool support. This makes it difficult to use proper packages suitable for production usage.
Is there any roadmap, or help needed?
Thanks!
Please change the localtz parameter to kerneltz. localtz is deprecated.
see http://ipset.netfilter.org/iptables-extensions.man.html#lbCH
Hi Ferm Team.
I encountered another interesting issue. Out of nowhere --in-interface
filter statements show up in the rendered file.
Take this ferm
rule file:
@def &MACCEPT($logspec) = {
NFLOG nflog-prefix "C=$CHAIN V=ACCEPT T=$logspec ";
if @eq(@substr($CHAIN, -3, 3), _IN) {
MARK or-mark 0x8;
} @else @if @eq(@substr($CHAIN, -4, 4), _OUT) {
MARK or-mark 0x10;
}
}
@def &PVLAN($subinterface, $chain) = {
chain FORWARD interface ubr mod physdev physdev-out $subinterface jump @cat($chain,'_IN');
chain FORWARD interface ubr mod physdev physdev-in $subinterface jump @cat($chain,'_OUT');
}
table filter {
&PVLAN('enp1s0f1.3006','x');
chain x_IN {
&MACCEPT('debug1');
}
chain x_OUT {
&MACCEPT('debug2');
}
}
Which, when rendered, produces this:
Generated by ferm 2.5.1 (iptables-save) on Mon Mar 2 15:14:57 2020
*filter
:FORWARD ACCEPT [0:0]
:x_IN - [0:0]
:x_OUT - [0:0]
-A FORWARD --in-interface ubr --match physdev --physdev-out enp1s0f1.3006 --jump x_IN
-A FORWARD --in-interface ubr --match physdev --physdev-in enp1s0f1.3006 --jump x_OUT
-A x_IN --jump NFLOG --nflog-prefix "C=x_IN V=ACCEPT T=debug1 "
-A x_IN --in-interface 1 --jump MARK --or-mark 0x8
-A x_OUT --jump NFLOG --nflog-prefix "C=x_OUT V=ACCEPT T=debug2 "
-A x_OUT --in-interface 0 --jump MARK --or-mark 0x8
COMMIT
This output has two problems:
&MACCEPT
macro does not specify anything that should result in --in-interface
._OUT
chains. Maybe I am wrong with understanding how @if
and @eq
works.Checked and @substr
function works just perfectly.
This may or may not be a problem.
Some people may use this to dynamically add rules to chains. However this can be a problem if you re-use a chain name without realising, your firewall starts behaving in ways you do not expect.
I can patch this to make duplicate names be printed as a warning. Making it an error could break working configs.
Here is a test config and example output showing the situation.
% cat test.conf
domain eb table broute chain BROUTING {
proto IPV4 op-source IP ACCEPT;
}
% /usr/sbin/ferm --remote test.conf
ebtables --atomic-file /tmp/ferm.6kouSFtJQQ --atomic-save
Error in test.conf line 2:
domain eb table broute chain BROUTING
{
proto IPV4 op-source <--
Unrecognized keyword: op-source
zsh: exit 25 /usr/sbin/ferm --remote test.conf
It's hard to find the mistake (IPV4
instead of IPv4
) in the example above due to the wrong error Unrecognized keyword: op-source
.
iptables is being phased out, please switch ferm to nftables.
We're thinking of providing our users a default modular ferm ruleset that can be adjusted to their wishes, but updated by us as well. For this we were thinking about shipping files in a directory with a package (rules) and symlink them from another directory that gets included by ferm.conf, similar to conf-available/conf-enabled in Apache.
Unfortunately the code at https://github.com/MaxKellermann/ferm/blob/master/src/ferm#L965 currently checks whether the file is a regular file. Maybe something like this could be implemented?
push @ret, $filename
if -f $filename || (-l $filename && -f readlink($filename));
I have issues with mangle ipsec command order
https://pastebin.com/hbnX1sJX
How i do it with iptables:
sudo iptables -t mangle -A FORWARD --match policy --pol ipsec --dir in -s 10.10.10.10/24 -o eth0 -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 -j TCPMSS --set-mss 1360
How I trying to do it with ferm:
table mangle {
chain FORWARD {
# adjust MSS
mod policy pol ipsec dir in saddr $PEER outerface eth0 proto tcp tcp-flags (SYN RST) SYN mod tcpmss mss 1361:1536 TCPMSS set-mss 1360;
}
}
An error:
Error in /etc/ferm/ferm.conf line 46:
table mangle
{
chain FORWARD
{
mod policy pol ipsec dir in saddr $ PEER outerface eth0 proto tcp tcp-flags <--
Unrecognized keyword: tcp-flags
Am I doing something wrong?
Thanks!
I like the @subchain
feature to define and use a chain on-the-fly.
I'm trying to setup a whitelist for both IPv4 and IPv6, but I reached a limitation(?) of ferm about the @subchain
feature.
I wonder if there is a better way than my workaround.
My goal (that is seems not possible) is:
@def $whitelist_direct = `echo 1.2.3.4; echo 1:2:3:4:5:6:0/64`;
domain (ip ip6) table filter chain INPUT {
@subchain ["whitelistcheck"] {
saddr @ipfilter( ( $whitelist_direct ) ) @subchain ["whitelistaccept"] {
LOG log-prefix 'FW:whitelist: ';
ACCEPT;
}
}
}
My current workaround :
@def $whitelist_direct = `echo 1.2.3.4; echo 1:2:3:4:5:6:0/64`;
domain (ip ip6) table filter chain INPUT {
saddr @ipfilter( ( 0.0.0.0/0 ::0/0 ) )
@subchain ["whitelistcheck"] {
saddr @ipfilter( ( $whitelist_direct ) ) @subchain ["whitelistaccept"] {
LOG log-prefix 'FW:whitelist: ';
ACCEPT;
}
}
}
Is there a better way ?
In ferm.pod, there is:
saddr|daddr [address-spec]
...
Examples:
saddr 192.168/8 ACCEPT; # (identical to the next one:)
saddr 192.168.0.0/255.255.255.0 ACCEPT;
... these two lines are not actually quite identical :)
I take whitelist IPs from a plaintext file.
I'm trying to resolv entries, but some of them are already IP or IP-range (CIDR).
I would like to have:
@def $whitelist = `grep '^[^#]\+' /etc/friends`;
domain (ip ip6) table filter chain INPUT {
saddr @ipfilter( ( @resolve( $whitelist ) ) ACCEPT;
}
There is my current code that split the file content:
@def $whitelist_to_resolve = `grep '^[^#]\+' /etc/friends| grep -v '^[0-9:./]*$'`;
@def $whitelist_direct = `grep '^[^#]\+' /etc/friends | grep '^[0-9:./]*$'`;
domain (ip ip6) table filter chain INPUT {
saddr @ipfilter( ( @resolve( $whitelist_to_resolve ) $whitelist_direct ) ) ACCEPT;
}
The code to test can be:
@def $whitelist_to_resolve = `echo github.com; echo testmyipv6.com`;
@def $whitelist_direct = `echo 1.2.3.4; echo 1:2:3:4:5:6:0/64`;
domain (ip ip6) table filter chain INPUT {
saddr @ipfilter( ( @resolve( $whitelist_to_resolve ) $whitelist_direct ) ) ACCEPT;
}
I dreams a more intelligent @resolve
function that is not tryting to resolve IP/IP-range.
I think @resolv()
can avoid resolution of entries that match ^[0-9:./]$
.
See Subject. Took me a while to figure out why the same command (ferm -n -l
) produced *filter
on one machine, and /sbin/iptables -t filter
on another... :)
There are pairs of each tool: iptables-legacy iptables-nft, ebtables-lagacy ebtables-ntf ...
The question is should ferm call -legacy tools derectly as sometime there are some issues:
# cat /etc/ferm/printer.ferm
domain eb table broute chain BROUTING {
daddr $PrinterMAC DROP;
}
# ferm /etc/ferm/printer.ferm
Policy ACCEPT not allowed for user defined chains.
Cannot rollback domain 'eb' because there is no ebtables-restore
Reference debian bug: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=929416
Hello,
I have the following rules.conf:
table filter chain INPUT proto tcp daddr 4.6.4.6 jump REJECT;
domain ip6 table filter chain INPUT proto TCP daddr fe80::1 jump REJECT;
domain ip table filter chain INPUT proto tcp daddr 4.4.4.4 jump REJECT;
According to the documentation the first line implies domain ip
because when no domain is specified the IPv4 domain is used:
BASIC KEYWORDS
Location keywords
domain [ip|ip6]
Set the domain. "ip" is default and means "IPv4" (iptables). "ip6" is for IPv6 support, using "ip6tables".
When generating the rules for inspection I receive the following expected output:
kim.mein-iserv.de ~ # ferm --noexec --lines rules.conf
# Generated by ferm 2.3 on Fri Jan 18 13:37:34 2019
*mangle
:FORWARD ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
COMMIT
*raw
:OUTPUT ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
COMMIT
*filter
:FORWARD ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT --protocol TCP --destination fe80::1 --jump REJECT
COMMIT
*nat
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
COMMIT
# Generated by ferm 2.3 on Fri Jan 18 13:37:34 2019
*filter
:FORWARD ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT --protocol tcp --destination 4.6.4.6 --jump REJECT
-A INPUT --protocol tcp --destination 4.4.4.4 --jump REJECT
COMMIT
*nat
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
COMMIT
*raw
:OUTPUT ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
COMMIT
*mangle
:FORWARD ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
COMMIT
O.K. so far, so good! Let's assume for some reason we need to handle IPv4 and IPv6 separately, e.g. because we want to save the rules to a file and import them later using iptables-restore. This is made up of course but I do actually have a reason to do this in my toolchain that can't be easily avoided.
For IPv4 everything appears to be just fine:
kim.mein-iserv.de ~ # ferm --domain ip --noexec --lines rules.conf
# Generated by ferm 2.3 on Fri Jan 18 13:41:23 2019
*nat
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
COMMIT
*mangle
:FORWARD ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
COMMIT
*filter
:FORWARD ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT --protocol tcp --destination 4.6.4.6 --jump REJECT
-A INPUT --protocol tcp --destination 4.4.4.4 --jump REJECT
COMMIT
*raw
:OUTPUT ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
COMMIT
And now let's check IPv6 output:
kim.mein-iserv.de ~ # ferm --domain ip6 --noexec --lines rules.conf
# Generated by ferm 2.3 on Fri Jan 18 13:42:21 2019
*nat
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
COMMIT
*filter
:FORWARD ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT --protocol tcp --destination 4.6.4.6 --jump REJECT
-A INPUT --protocol TCP --destination fe80::1 --jump REJECT
COMMIT
*raw
:OUTPUT ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
COMMIT
*mangle
:FORWARD ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
COMMIT
An IPv4 address sneaked into our rules! That breaks our ruleset.
You might think at this point that --domain
has somehow set the default domain and this might sound like reasonable behaviour at first glance, however this makes parsing mixed rulesets a giant pain. The documentation doesn't mention default behaviour overrides either:
--domain {ip|ip6}
Handle only the specified domain. ferm output may be empty if the domain is not configured in the input file.
It actually sounds a lot like unexpected behaviour. This is my reason for filing this bug.
Thank you for looking into this.
Best regards,
Kim-Alexander Brodowski
E.g., we have rule like that:
mod set set front-srvs src mod set set back-srvs dst ACCEPT;
Ferm converts it into such a rule for iptables:
-A FORWARD --match set --match-set front-srvs src --match-set back-srvs dst --jump ACCEPT
And iptables give an error:
iptables-restore v1.6.0: --match-set can be specified only once
Because right rule should look like this:
-A FORWARD -m set --match-set front-srvs src -m set --match-set back-srvs dst -j ACCEPT
Somewhere lost second "-m set".
Hi,
I've been using these statements for years but a recent upgrade has broken it:
@def $y7 = (44.128.0.0/16 fd4d:4045:e5e8::/48);
@def $snat_addr = (172.30.0.48 2a05:d018:563:7900::25);
table nat {
chain POSTROUTING {
saddr @ipfilter($y7) outerface eth0 SNAT to-source @ipfilter($snat_addr);
}
}
And the generated result is (see the end of the line):
-A POSTROUTING --source 44.128.0.0/16 --out-interface eth0 --jump SNAT --to-source deferred=ARRAY(0x558f46950100)
# ferm /etc/ferm.conf
iptables-restore v1.8.4 (legacy): Bad IP address "deferred=ARRAY(0x55d9d68ed478)"
# ferm --version
ferm 2.5.1
Thank you and keep up the good work!
EB domain rules are not applied atomically. Is there any reason why ebtables atomic functionality is not being used?
It appears the maximum chain name has been 28 chars since 2010 ( https://git.netfilter.org/iptables/log/?qt=grep&q=chain+name+length )
When trying to load a firewall with a name that is too long I get this:
jhendry@twigz ~/svn/cfengine/cf3/configroot/platform/firewall/devel/ng/ $ sudo iptables-restore < t
iptables-restore v1.6.0: Invalid chain name DROP_RFC1918_BROADCAST_AND_MCAST' (28 chars max) Error occurred at line: 11 Try
iptables-restore -h' or 'iptables-restore --help' for more information.
Can we add checking of chain name length to ferm?
Is it possible to block the remove of a rule during flush?
I'm using ferm to configure the firewal on a machine running docker.
In this configuration there is a filter chain named DOCKER-USER that is managed my the user, but it is required by docker.
it is configured by docker to be domain (ip ip6) table filter chain DOCKER-USER { jump RETURN; }
.
I reconfigured it using ferm, but when I run it with --flush the DOCKER-USER chain is deleted and the command fail because of a jump to this chain in the docker iptables configuration.
What do you think about shortcuts for mod multiport:
sports -> mod multiport source-ports
dports -> mod multiport destination-ports
?
This, previously working, snippet
proto icmp @subchain "IN_icmp" {
icmp-type (0 3 8 11) ACCEPT;
DROP;
}
had to be modified like this...
proto icmp @subchain "IN_icmp" {
**proto icmp** icmp-type (0 3 8 11) ACCEPT;
DROP;
}
or else generated rules would trigger an error upon execution of the iptables/iptables-restore script...
...
/sbin/iptables -t filter -A IN_icmp --icmp-type 0 --jump ACCEPT
iptables v1.6.1: unknown option "--icmp-type"
Try `iptables -h' or 'iptables --help' for more information.
^ there is clearly missing the "protocol" keyword, which didn't happen previously.
Not sure if this is an actual issue anymore or an intended behaviour, but for me updating to v2.5 did do some breakage.
Edit: forgot to mention - it's a Gentoo system's ferm package version 2.5 and previous version installed was 2.4.1
I have some variables containing multiple networks like (10.0.0.0/8 192.168.0.0/16)
.
I'd like to run a hook with this variable as argument, but hooks only allow string variable.
Is there a way to flatten arrays? I tried @cat
without success so far…
Considere the small and stupid ferm config samples
Sample 1
domain ip table filter {
chain in_test1;
chain INPUT {
protocol tcp daddr 1.2.3.4 jump in_test1;
}
chain in_test1 {
DROP;
}
}
Sample 2
domain ip table filter {
chain INPUT {
protocol tcp daddr 1.2.3.4 @subchain in_test1 {
DROP;
}
}
}
The difference between the both results:
*filter
:INPUT ACCEPT [0:0]
:in_test1 - [0:0]
-A INPUT --protocol tcp --destination 1.2.3.4 --jump in_test1
--A in_test1 --jump DROP
+-A in_test1 --protocol tcp --jump DROP
COMMIT
--protocol tcp
is added ?I also tried a way to force to discard the protocol option, without success.
Sample 3
domain ip table filter {
chain INPUT {
protocol tcp daddr 1.2.3.4 @subchain in_test1 {
protocol all DROP;
}
}
}
I got -A in_test1 --protocol tcp --protocol all --jump DROP
It seems to be the future instead of iptables
Thanks!
At first, thank you very much for nice tool.
I use it with docker. Docker changes some builtin chains and makes serveral new chains. Filter's chain "DOCKER-USER" is one of these. This chain is called from builin chain "FORWARD". So i preserve "FORWARD" and make some rules in "DOCKER-USER" (it is purposed by docker for user's rules). And now I call "ferm -F" and it does not restore empty "DOCKER-USER". Coz it thinks that its new (user's) chain. But it is not. It was there before and it was referenced (by jump) from "FORWARD". So I have error:
iptables-restore v1.4.21: Couldn't load target `DOCKER-USER':No such file or directory
Error occurred at line: 21
Try `iptables-restore -h' or 'iptables-restore --help' for more information.
Failed to run /usr/sbin/iptables-restore
Coz there is "-A FORWARD -j DOCKER-USER" and there is no "DOCKER-USER".
$VERSION = '2.5.1';
on debian buster ferm stop with an error on start.
iptables-restore v1.8.2 (nf_tables):
line 94: RULE_APPEND failed (Invalid argument): rule in chain INPUT
Failed to run /sbin/iptables-restore
it works if I do
ferm --noexec --lines /etc/ferm/ferm.conf > /tmp/myrules
iptables-legacy-restore < /tmp/myrules
I have set FAST=no and CACHE=no in /etc/default/ferm so it start correctly now. It is more an avoidance than a fix ...
Today i try to transport my existing ruleset with import-ferm
and got an error on the xt_recent module.
So i've build an test based on the 2.4 doku and can not get this to work.
My example is:
domain ip {
table filter {
chain FORWARD {
interface wan0 {
mod recent set name ssh-rate rsource mask 255.255.255.0 NFLOG nflog-prefix 'IPT SSH:';
}
}
}
}
I've got an error:
Error in ferm.conf line 5:
chain FORWARD
{
interface wan0
{
mod recent set name ssh-rate rsource mask 255.255.255.0 <--
Unrecognized keyword: 255.255.255.0
So it seems ferm could not handle the mask stuff in recent.
Without the mask
parameter i got a valid iptables rule:
# Generated by ferm 2.4 on Wed Jul 5 14:47:12 2017
*filter
:FORWARD ACCEPT [0:0]
-A FORWARD --in-interface wan0 --match recent --set --name ssh-rate --rsource --jump NFLOG --nflog-prefix "IPT SSH:"
COMMIT
So if i manually insert the mask
it works:
iptables -A FORWARD --in-interface wan0 --match recent --set --name ssh-rate --rsource --mask 255.255.255.0 --jump NFLOG --nflog-prefix "IPT SSH:"
iptables -nvL FORWARD
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 NFLOG all -- wan0 * 0.0.0.0/0 0.0.0.0/0 recent: SET name: ssh-rate side: source mask: 255.255.255.0 nflog-prefix "IPT SSH:"
But then also the import doesn't work:
import-ferm
Possible unintended interpolation of $\ in regex at /usr/bin/ferm line 2644.
# ferm rules generated by import-ferm
# http://ferm.foo-projects.org/
domain ip {
table filter {
chain FORWARD {
policy ACCEPT;
warning: unknown token '255.255.255.0' in line 6
interface wan0 mod recent set name ssh-rate mask rsource NFLOG nflog-prefix 'IPT SSH:';
}
chain OUTPUT policy ACCEPT;
chain INPUT policy ACCEPT;
}
}
It would be nice if ferm provided a geoip match.
The patch is as simple as this:
--- ferm-2.3/src/ferm 2016-03-30 14:16:02.000000000 +0200
+++ /usr/sbin/ferm 2016-07-26 20:32:13.000000000 +0200
@@ -256,6 +256,7 @@
add_match_def 'esp', qw(espspi!);
add_match_def 'eui64';
add_match_def 'fuzzy', qw(lower-limit=s upper-limit=s);
+add_match_def 'geoip', qw(!src-cc=s !dst-cc=s);
add_match_def 'hbh', qw(hbh-len! hbh-opts=c);
add_match_def 'helper', qw(helper);
add_match_def 'hl', qw(hl-eq! hl-lt=s hl-gt=s);
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.