Re: Combine ipv4 and ipv6 in a set

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Marc,

On Wed, 31 Jan 2024, at 10:54 AM, Marc Haber wrote:
> On Tue, Jan 30, 2024 at 03:17:32PM +0000, Kerin Millar wrote:
>> On Tue, 30 Jan 2024, at 1:08 PM, Marc Haber wrote:
>> > This is one of my pet peeves with nft, actually. For iptables, there was
>> > tooling like ferm which made it possible to write dual-stack rule sets
>> > very easily. This kind of tooling seems to be completely missing in the
>> > nftables world. Am I missing something here?
>> 
>> Quite possibly. Currently, nftables supports:
>> 
>> - mixed rulesets (using tables bearing the "inet" family)
>> - mixed rules (wherever it makes sense)
>> - first-class sets of any kind (irrespective of the type of table enclosing them)
>
> That nicely shows another issue with nft: Docs. Neither the search
> function on the nftables wiki nor the nft manual page have matches for
> "mixed" or "first-class".
>
> How would I use a mixed ruleset? How would I use a mixed rule?

It wasn't intended as jargon, so the onus is upon me to clarify.

Firstly, I mentioned both tables and the "inet" family. If you search for inet in the man page, you should land in the ADDRESS FAMILY section, which indicates that the purpose of an address family is to define the type of packets that can be processed. It goes on to say that "all nftables objects exist in address family specific namespaces, therefore all identifiers include an address family".

Now, if we look at the defined grammar for creating tables in the TABLES section, it is - in part - presented as "{add | create} table [family] table". That shows that that the family can be specified at the time of creating a table. But wait, why is it in square brackets? It means that the argument specifying the family is optional. It goes on to say, "when no address family is specified, ip is used by default".

In summary, a table must always have an address family. If you do not explicitly specify the family at the time of creation, the family shall be "ip". If you specify "inet" as the family, the objects within the table (hooks, chains, rules etc) will be able to handle *both* IPv4 and IPv6 packets. That is what I meant by mixed.

Secondly, by mixed rules, I meant that generalised rules within an inet table can handle both IPv4 and IPv6 packets. Consider a very simple rule such as "tcp dport 22 accept". It will match both IPv4 and IPv6 without issue. As you well know, iptables is incapable of doing this.

Thirdly, by first-class, I meant that sets are an intrinsic feature of nftables. That is, they are not a feature bolted on by way of a separate kernel subsystem, along a separate userspace tool to manage them (ipset), requiring an iptables extension to glue them together. Consequently, it is possible to use sets in many interesting ways which are simply not possible in iptables. I am aware that this comes at the cost of some administrative complexity.

>
>> Granted, one cannot create a set that is typed in such a way that an
>> element can be either an IPv4 or IPv6 address/interval. Conversely,
>> iptables does not natively support sets at all, though it can
>> integrate with sets that are managed by ipset(8). Now, can an ipset
>> contain addresses of mixed types? No, it cannot.
>
> In ferm, a tool that has been available for over 20 years, you can
> (beginning ten years ago, I think) write things like:
>
> @def $h_cadencia=(192.168.251.9 2001:db8:42bc:a102::9:100);
> @def $h_chasse=(192.168.181.161 2001:db8:42bc:a181::a1:100);
> @def $g_dnsrec=($h_cadencia $h_chasse)
>
> domain (ip ip6) {
>   table filter {
>     chain FORWARD {
>       iface internal0 daddr $g_dnsrec proto (tcp udp) dport 53 ACCEPT;
>     }
>   }
> }

I would agree that fermi is a fine wrapper and that its author has put considerable thought into its syntax.

>
> which creates (if I calculated correctly) four IPv4 rules and four IPv6
> rules automatically. Ferm solves this trivially by dropping any
> generated rules where address type and domain doesn't match.
>
> This approach of course makes the sheer number of rules explode, but it
> makes writing rules easier. My time is precious, CPU time is generously
> available. In the situation where CPU time is precious as well, I might
> be willing to spend some more time writing _efficient_ rules but that's
> like 2 percent of all the cases and I am not willing to make my life
> harder in the other 98 percent.
>
>> As far as the present topic is concerned, the only tangible advantage
>> that ipset has is the ability to create a set whose sole purpose is to
>> act as a superset of other - potentially mixed - sets. This advantage
>> is rather diminished by the fact that one also has to two manage two
>> entirely separate rulesets with iptables and ip6tables,
>> notwithstanding that wrappers such as fermi exist.
>
> Of course one could have an nft preprocessor solving those issues, but
> given that nft is already open source, reads a text file and configures
> the nftables kernel backend, the natural approach would be to modify nft
> to not only translate input 1:1 to kernel entries, but also add some
> bells and whistles that makes life easier for those people writing
> firewall rules.
>
> With iptables, where people are encouraged to put their firewall rules
> into shell scripts, things were entirely different, and this approach
> was very inconvenient (proven by the fact that many iptables frontends
> didnt write iptables scripts but files that could be read by
> iptables-restore.
>
>> At any rate, the follow nftables ruleset is valid.
>> 
>> table inet filter {
>>         set block4 {
>>                 type ipv4_addr
>>         }
>>         set block6 {
>>                 type ipv6_addr
>>         }
>>         chain INPUT {
>>                 type filter hook input priority filter; policy accept
>>                 ip saddr @block4 drop
>>                 ip6 saddr @block6 drop
>>         }
>> }
>
> Isnt that clumsy! Wouldn't it be so much nicer to be able to write:

I don't find it particularly clumsy; it is rather low on my list of nftables-related grievances. I don't know whether you are a programmer yourself but, sometimes, I wonder whether there is a culture clash of sorts between programming admins and non-programming admins. Though I am no Netfilter hacker, it is intuitive to me that sets are strongly typed and that the protocols are different. That being said ...

>
> table inet filter {
>         set block46 {
>                 type ipv46_addr
>         }
>         chain INPUT {
>                 type filter hook input priority filter; policy accept
>                 ip46 saddr @block46 drop
>         }
> }
>
> Having to write distinct rules makes things more complex and
> error-prone.

... I can certainly appreciate this perspective and why it might ease the cognitive burden for maintaining some rulesets. 

-- 
Kerin Millar




[Index of Archives]     [Linux Netfilter Development]     [Linux Kernel Networking Development]     [Netem]     [Berkeley Packet Filter]     [Linux Kernel Development]     [Advanced Routing & Traffice Control]     [Bugtraq]

  Powered by Linux