NFTABLES : sets, maps et dictionnaires

NFTABLES :  

Nftables dispose d'un arsenal de modèles permettant de simplifier la réalisation des tests en utilisant des notions analogues à celles des "Ipsets" mais présentant quelques perfectionnements intéressants. 
Il existe plusieurs types de tables dans deux saveurs :

  • Gadgets "nommés", décrits "à part" et utilisés par une règle.
  • Gadgets "inline" non nommés qui peuvent faire partie d'une règle.

Les gadgets nommés permettent de réaliser des ajouts/suppressions "en ligne" gràce aux opérations sur les éléments (de manière analogue à "ipset").

Un certain nombre de "types" de données sont admis pour les éléments :

  • ipv4_addr/ipv6_addr      Adresses IPV4 ou IPV6, avec option "flags interval" pour notation CIDR ou intervalles, nécessite noyau >= 4.7-rc2 et dernière version nftables (à charger et compiler).
  • ether_addr                        Adresse MAC
  • inet_service                     Ports, sous forme numérique ou texte pour les plus connus (ssh, http, https ...)
  • inet_proto                         Prototype : ICMP, TCP ....
  • mark                          Marque posée par une autre règle.

Ces différents types répondent à la plupart des besoins, il manquerait toutefois la possibilité de désigner un réseau sous forme CIDR en plus des adresses IP. Cette possibilité existe dans les "vmap" non nommées, mais pas pour cellles nommées ? Un oubli sans doute ? 
Juin 2016 : 
Cet oubli est corrigé dans la dernière version de Nftables et nécessite un kernel >= 4.7-rc2, la syntaxe de la création du set est légèrement différente, il faut ajouter "flags interval" dans la déclaration du set nommé qui devient : 
set MONSET ( type ipv4-addr; flags interval)

Une autre nouveauté intéressante de ces "gadgets" est donnée par le deuxième élément possible : l'action à réaliser si l'élément "matche", drop, jump table, goto table, accept ..... Cela ouvre des horizons assez sympatiques. 
Par exemple on peut en une seule règle refouler toutes les IP d'un pays à l'aide des listes fournies par différents sites par exemple "ipdeny.com". On peut récupérer la liste des réseaux concernés, mettre en forme la règle (un simple script AWK le fait très bien, générer un fichier au "bon" format et utiliser ce fichier dans un script "Nftables" à l'aide de l'instruction "include" (je vous avais bien dit que la syntaxe Nftables se rapprochait d'un langage !). Dommage d'être obligé d'utiliser un bloc de données non nommé car si on en a besoin plusieurs fois .... par exemple en Entrée et en Forward ou en sortie. 
Exemple de syntaxe pour la règle ci dessus :

add rule INPUT ENT_100 ip saddr vmap { 
1.0.1.0/24 : drop, 
1.0.2.0/23 : drop, 
1.0.8.0/21 : drop, 
........ 
254.254.0.0/24 : drop }

Qui ajoute une règle à la chaine "ENT_100" de la table "INPUT".

Ce fichier est appelé par  l'include suivant dans le script Nftables de création de la table "INPUT" : 
#include "le_chemin_de_mon_fichier" 
Autre petit exemple, répartir sur plusieurs "chaînes" les entrées en fonction de l'interface d'origine pour les compter, on utilisera une "vmap" :

flush table ip ENTREE;

table ip ENTREE { 
    chain INP_INT { 
         counter 
    } 
    chain INP_EXT { 
        counter 
    } 
    chain INP_LOC { 
        counter 
    } 
    chain DEFAUT { 
         type filter hook input priority 0; 
         iifname vmap { br0 : jump INP_EXT, br1 : jump INP_INT, 
                        lo  : jump INP_LOC  } ; 
    } 
}

Après quelques instants on liste :

nft list table ENTREE 
table ip ENTREE { 
    chain INP_INT { 
         counter packets 53 bytes 8010 
    } 
    chain INP_EXT { 
         counter packets 2 bytes 64 
    } 
   chain INP_LOC { 
         counter packets 12 bytes 774 
    }    chain DEFAUT { 
         type filter hook input priority 0; 
         iifname vmap { "lo" : jump INP_LOC, "br1" : jump INP_INT, "br0" : jump INP_EXT} 
    } 
}

C'est bien ce qui était demandé...

Attention en manipulant les sets il existe quelques problèmes lors de la mise à jour d'une table contenant des sets, il est impossible de "flusher" une table tant qu'il y a un set, il faut détruire le set d'abord avant de faire le flush de la table sinon on arrive à un crash système. 
Ce problème est résolu pour les noyaux >= 4.0.0-rc4.