You are not logged in.

#1 2018-08-07 13:54:19

Superhansel
Member
Registered: 2018-03-10
Posts: 10

Portknocking with nftables doesn't work due to a wired behavior

I am desperate for help!

The last 2 days I read the man pages of nft and in addition checked their wiki[1] which contains additional information about otherwise undocumented features. Now that I feel confident that I understood how it works, I try to setup a portknocking sequence (TCP): 30 -> 31 -> Allow access to some service

I found a basic setup on how to do this here[2], but wanted to keep my ruleset small which is why I tried a solution on my own:

# Just a minimal version for the IPv4 part of my portknocking setup


table inet filter { # handle 7
        set trusted_ipv4 { # handle 2
                type ipv4_addr . inet_service
                flags timeout
        }

        chain input { # handle 1
                type filter hook input priority 0; policy accept;
                jump portknock # handle 5
        }

        chain portknock { # handle 4
                tcp dport 30 add @trusted_ipv4 { ip saddr . 0x1f [invalid type] timeout 15s }  # handle 8
                tcp dport 31 ip saddr . tcp dport @trusted_ipv4 add @trusted_ipv4 { ip saddr . 0x16 [invalid type] timeout 1m }  # handle 7
        }
}

For those interested in testing: run sudo nft -i and paste:

flush ruleset                                                                                                                                                                 
create table inet filter                                                                                                                                                                                        
create chain inet filter input { type filter hook input priority 0; }                                                                                                                                           
add set inet filter trusted_ipv4 { type ipv4_addr . inet_service ; flags timeout; }                                                                                                                             
create chain inet filter portknock                                                                                                                                                                              
add rule inet filter input jump portknock                                                                                                                                                                       
add rule inet filter portknock tcp dport 30 add @trusted_ipv4 { ip saddr . 31 timeout 15s }                                                                                                                            
add rule inet filter portknock tcp dport 31 ip saddr . tcp dport @trusted_ipv4 add @trusted_ipv4 { ip saddr . 22 timeout 1m }                                                                                  

So the basic idea is

  1. When someone knocks on port 30 -> insert a tuple to the set trusted_ipv4 with the source IP address of the request and the next port that is expected to be knocked.

  2. When someone knocks on port 31 -> check whether there is a tuple (consisting of <source IP address, 31>) within the set @trusted_ipv4.
    If thats the case, a new entry in the set is then added (so another rule can check the existence of the new tuple, etc.).

So theoretically, the setup SHOULD work. When I manually add a tuple to the trusted_ipv4 set like below and then knock on port 31, a new tuple is inserted to the set <ip saddr, 22>, just as expected!

add element inet filter trusted_ipv4 { 127.0.0.1 . 31 timeout 15s }

If I knock on port 30, the tuple <ip saddr, 22> is also added to the set but the lookup won't work correctly. If I now knock on port 31 nothing happens because the lookup fails. If a now add the tuple manually to the set (with the command above)  and afterwards knock on port 30, there are two seemingly identical tuples in the set. But this is what shouldn't be possible in a set, should it? (I also cannot add the same tuple multiple times into the set).

$ sudo nft list set inet filter trusted_ipv4
table inet filter {
        set trusted_ipv4 {
                type ipv4_addr . inet_service
                flags timeout
                elements = { 127.0.0.1 . 31 expires 9s284ms,
                             127.0.0.1 . 31 timeout 15s expires 13s607ms }
        }
}

So I expect that something is wrong with the rule-based pushing of the tuple. If you look closely to the ruleset above you will see that there is also an indication that 0x1f is an "[invalid type]" which is probably because its not a valid service number. However, I cannot use a plain integer because it has a variable size and thus cannot be used for concatenation.

I would really appreciate any help on this. Thanks!

[1] https://wiki.nftables.org/
[2] https://wiki.nftables.org/wiki-nftables … ng_example

Offline

#2 2018-08-07 14:15:29

progandy
Member
Registered: 2012-05-17
Posts: 5,192

Re: Portknocking with nftables doesn't work due to a wired behavior

I suggest you use two sets instead of concatenating.


| alias CUTF='LANG=en_XX.UTF-8@POSIX ' |

Offline

#3 2018-08-07 15:35:10

Superhansel
Member
Registered: 2018-03-10
Posts: 10

Re: Portknocking with nftables doesn't work due to a wired behavior

progandy wrote:

I suggest you use two sets instead of concatenating.

While that would certainly work (and is also proposed in the referenced link), I would like to keep my ruleset small and concise. Especially because i am used to define ONE datastructure for ONE task. Its probably because I am new to the whole nffilters stuff, but it seems awkward to me to define a portknocking-aware firewall in such a verbose way.

Offline

Board footer

Powered by FluxBB