Coder Social home page Coder Social logo

ferm's People

Contributors

apoikos avatar atonkyra avatar awelzel avatar benschweizer avatar bk2204 avatar brenard avatar call-cc avatar costasd avatar fd1e4020 avatar ivandeex avatar jbenden avatar jhendryuk avatar jsoref avatar krenair avatar l9i avatar marschap avatar maxkellermann avatar mxey avatar nepella avatar ogelpre avatar omenwild avatar paravoid avatar petercolberg avatar profitware avatar real-dam avatar seblu avatar shartge avatar sofar avatar verement avatar yrro avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ferm's Issues

@resolve of IP should return IP

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

Ferm rules not persistent (surviving a reboot) ?

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?

mod helper issue

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).

Wrong $LINE value

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

ferm.pod: minor correction

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;

Order domains/tables/chains on execution

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

import-ferm failing

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

domain eb ip match wrong rule

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

broute table is not flushed

Steps to reproduce:

  1. clear broute table:
# ebtables -t broute -F
# ebtables -t broute -L
Bridge table: broute

Bridge chain: BROUTING, entries: 0, policy: ACCEPT
  1. update ferm configuration, add:
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 
  1. undo step 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 

Map reject-with icmp-proto-unreachable with ipv6

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)

Using @ipfilter in DNAT results in deferred=ARRAY(0x55b7a9219368) in v2.5

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.

Feature Request: can `ferm -nl --domain ip` output match iptables-save

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

Errors when mixing module policy with subchains

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

New option 'ferm --flush-all' ?

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 :-)

ferm.pod: add "mod" keyword

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.

GPL license needs to be updated.

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.

Release with ferm

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!

interface selectors showing up

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:

  • The &MACCEPT macro does not specify anything that should result in --in-interface.
  • Wrong mark flag gets flipped, 0x10 should be set to 1 instead of 0x8 on the _OUT chains. Maybe I am wrong with understanding how @if and @eq works.

Checked and @substr function works just perfectly.

Ferm allows the use of duplicate chain names

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.

iptables.ferm.txt
iptables.output.txt

Wrong proto gives wrong error

% 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.

Allow symbolic links on include

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));

command order. Unrecognized keyword

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!

Use @subchain without rule ?

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 ?

ferm.pod: netmasks messed up in examples

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 :)

Feature request: a more intelligent `@resolve` (support CIDR notation)

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:./]$.

shoud ferm call legacy tools directly

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

Incorrect behaviour when default domain is used

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

Two "--match-set" in same rule doesn't work properly

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".

Two ipfilters in one rule leads to rendering error

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!

Add chain name length checking

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?

Keep rule on flush

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.

multiport shortcuts

What do you think about shortcuts for mod multiport:
sports -> mod multiport source-ports
dports -> mod multiport destination-ports
?

Older config breaks (pre 2.5). Protocol doesn't propagate to subchains.

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

Flattening arrays

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…

Each line of a generated subchain herite the "--protocol" from the calling line

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
  • Why the --protocol tcp is added ?
  • Is it a bug ?

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

flushing error

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';

error on start on debian Buster.

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 ...

recent match module doesn't work

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;
    }
}

Add geoip match

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);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.