Les caractéristiques de netfilter sous Linux 2.4

Denis Ducamp / Hervé Schauer Consultants

Septembre 2000


Reproduction strictement interdite

1. Introduction

  • Cette présentation va aborder les aspects suivants dans netfilter :

    • le filtrage IP,

    • la traduction d'adresses.

  • Tout en essayant de présenter quelques points techniques...

  • Tous les tests ont été réalisés début juillet 2000 avec :

    • la version 2.4.0-test2 de Linux datant du 24 juin 2000.
      Aucun patch utilisé pour la partie noyau de netfilter.

    • la version 1.1.0 des utilitaires iptables en provenance du serveur cvs.

    • sur un système Slackware 7.0 - glibc 2.1.2 - egcs 2.91.66
      < http://www.slackware.com/>

    • et la version 2-beta53 de hping pour générer des paquets à la demande ;-)
      < http://www.kyuzz.org/antirez/hping/>

  • Une mise à jour a été réalisée mi-septembre 2000.

1.1 Historique

  • Linux 1.1 (fin 1994), Alan Cox porte ipfw depuis BSD.

  • Linux 2.0 , Jos Vos et d'autres l'améliorent et créent ipfwadm.

  • Linux 2.2 (mi 1998), Rusty Russel et Michael Neuling réécrivent le filtrage IP et créent ipchains.

  • Linux 2.4 (mi 1999), Rusty Russel réécrit à nouveau le filtrage IP (netfilter : la partie noyau), et crée iptables (les utilitaires de configuration).

    • Version 1.0.0 : mars 2000 / linux 2.3.99-pre2
    • Version 1.1.0 : mai 2000 / linux 2.3.99-pre8
    • Version 1.1.1 : juillet 2000 / linux 2.4.0-test4

  • Rusty Russel travaille chez watchguard < http://www.watchguard.com/>, éditeur de solutions de sécurité autour de Firebox.

2. Filtrage IP

  • Principe des chaines

  • Possibilités de filtrage

  • Traçage de connexions

  • Exemple

  • Tests techniques

  • Autres possibilités

2.1 Principe des chaines

  • chaine ~ sous-programme

  • un paquet correspondant à une règle sera dirigé vers une chaine

  • un paquet passe toujours tout d'abord par l'une de ces 3 chaines :

    • INPUT : un paquet à destination du système entrant dans une interface
    • OUTPUT : un paquet généré par le système sortant par une interface
    • FORWARD : un paquet traversant le système

                              _____
    Incoming                 /     \         Outgoing
           -->[Routing ]--->|FORWARD|------->
              [Decision]     \_____/        ^
                   |                        |
                   v                      ____
                  ___                    /    \
                 /   \                  |OUTPUT|
                |INPUT|                  \____/
                 \___/                      ^
                   |                        |
                    ----> Local Process ----
    (c)2000 Rusty Russell
    

  • les 6 chaines suivantes ne peuvent être redéfinies :

    • ACCEPT : le paquet est accepté,
    • DROP : le paquet est ignoré,
    • RETURN : fin du sous-programme courant ou application de la politique par défaut pour INPUT , OUTPUT et FORWARD,
    • REJECT : le paquet est rejeté avec un message d'erreur,
    • LOG : le paquet est journalisé,
    • QUEUE : le paquet est redirigé vers une application utilisateur pour décider de son sort.

2.2 Possibilités de filtrage

  • entrée ou sortie d'interface :

    • INPUT : toujours en entrée d'interface,
    • OUTPUT : toujours en sortie d'interface,
    • FORWARD : en entrée ou en sortie d'interface.

  • adresses source et destination, avec ou sans netmask,
  • type de service,
  • protocole ip,
  • fragment ou non,
  • icmp : type et code,
  • tcp et udp : ports source et destination, avec ou sans intervalle,
  • tcp :

    • options tcp : SYN, ACK, FIN, RST, URG et PSH,
    • demande de connexion ou transfert de données.

2.3 Traçage de connexions

  • Traçage des connexions tcp, udp et icmp

  • Options possibles :

    • INVALID : un paquet invalide
      • erreur interne lors du traitement du paquet
      • un paquet icmp d'erreur ne correspondant pas à une connexion en cours

    • ESTABLISHED : un paquet correspond à une connexion en cours

    • RELATED :
      • un paquet d'erreur correspondant à une connexion en cours : reset et icmp
      • un paquet correspondant à la demande d'une connexion ftp data attendue :
        modes passif et actif.

    • NEW : un paquet ne correspondant à aucune connexion en cours
      • Attention : ne correspond pas obligatoirement à une demande de connexion

  • Liste des connexions tracées : cat /proc/net/ip_conntrack

  • Nombre de connexions (par défaut 8184) :
    • echo 16384 > /proc/sys/net/ipv4/ip_conntrack_max

2.4 Exemple

  • Le firewall et le réseau interne peuvent tout faire, pas Internet.

  • Les adresses du réseau interne sont masquées pour sortir vers Internet.
    IFACE=eth0
    
  • # Masquerade out eth0
    iptables -t nat -A POSTROUTING -o $IFACE -j MASQUERADE
    
  • # Create chain which blocks new connections, except if coming from inside.
    iptables -N block
    iptables -A block -m state --state INVALID -j DROP
    iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
    iptables -A block -m state --state NEW -i ! $IFACE -p icmp --icmp-type echo-request -j ACCEPT
    iptables -A block -m state --state NEW -i ! $IFACE -p udp -j ACCEPT
    iptables -A block -m state --state NEW -i ! $IFACE -p tcp --syn -j ACCEPT
    iptables -A block -i $IFACE -m limit --limit 3/s -j LOG --log-prefix "Bad packet from $IFACE:"
    iptables -A block -i ! $IFACE -m limit --limit 3/s -j LOG --log-prefix "Bad packet not from $IFACE:"
    iptables -A block -j DROP
    
  • # Jump to that chain from INPUT and FORWARD chains.
    iptables -A INPUT -j block
    iptables -A FORWARD -j block
    
  • # Turn on IP forwarding
    echo 1 > /proc/sys/net/ipv4/ip_forward
    

2.5 Tests techniques

  • ICMP (ping) :
    • un paquet echo-reply du serveur ne correspondant pas à une "connexion" est ignoré
    • un paquet echo-request du client ouvre une "connexion" durant 30s.
    • tout paquet echo-request du client réinitialise le compte à rebours à 30s.
    • un paquet echo-reply du serveur ferme immédiatement la "connexion".

  • UDP :
    • un paquet udp du serveur ne correspondant pas à une "connexion" est ignoré
    • un paquet udp du client ouvre une "connexion" dans l'étât UNREPLIED durant 30s.
      • un paquet udp du client réinitialise le compte à rebours à 30s.
    • un paquet udp du serveur passe la "connexion" en mode "connecté" durant 180s.
      • un paquet udp du client ou du serveur réinitialise le compte à rebours à 180s.
    • à tout moment, un paquet icmp port unreachable est transféré mais ne ferme pas la "connexion".

  • TCP :
    • Avant que le client ait envoyé un paquet SYN ou SYN-FIN : aucun paquet ne passe.
    • Un paquet SYN ou SYN-FIN du client ouvre une connexion dans l'étât SYN_SENT.
      Tant que le serveur n'a pas répondu :
      • seuls les paquets SYN et SYN-FIN passent depuis le client en réinitialisant à "zéro" (120s.) l'étât SYN_SENT.
      • un paquet RST ou SYN-RST :
        • depuis le client ferme immédiatement la connexion sans être transféré
        • depuis le serveur met immédiatement la connexion dans l'étât CLOSE pendant 10s. sans être transféré
    • Un paquet SYN-ACK de la part du serveur passe la connexion dans l'étât ESTABLISHED.
      Le compte à rebours est initialisé à 432000 secondes... soit 5 jours !!!
      A partir de ce moment :
      • Tout paquet RST ou SYN-RST ferme immédiatement la connexion sans être transféré.
      • Tout paquet FIN-ACK de l'un met la connexion dans l'étât CLOSE_WAIT pendant 60s.
        Tout paquet FIN-ACK de l'autre met la connexion dans l'étât TIME_WAIT pendant 120s.

    • màj 09/00 : corrigé par le patch nommé patch-test4-pre3-synflood aujourd'hui intégré en standard. La partie nommée "Rusty's poor-man's sequence track." permet :
      • de contrôler les numéros de séquence sur les 3 paquets de l'établissement de connexion.
      • de ne considérer une connexion comme établie qu'après le passage des trois paquets d'établissement de connexion.

  • Défauts :
    • Dès que la table des connexions est remplie, il n'est plus possible de se connecter.
      • màj 09/00 : auparavant, des SYN flood sur les ports ouverts suffisaient : seuls les 2 premiers paquets étaient nécesssaires pour mettre une connexion dans un étât ESTABLISHED.
      • màj 09/00 : vérifier le comportement lorsque la table des connexions est remplie.
    • Les numéros de séquence ne sont pas contrôlés.
      • moins bien qu'ipfilter, mais ipfilter est-il toujours nécessaire ?
        • màj 09/00 : un patch de Jozsef Kadlecsik nommé tcp-window-tracking.patch se trouve en test dans le patch-o-matic. Ce patch implémente le traçage de connexions TCP tel que décrit dans le document 'Real Stateful TCP Packet Filtering in IP Filter' par Guido van Rooij
          voir <http://www.iae.nl/users/guido/papers/tcp_filtering.ps.gz>)
          note : ce patche casse actuellement la NAT pour IRC et FTP.
      • il est possible de vider soit même la table des connexions avec un simple filtre :
        cat /proc/net/ip_conntrack | \
        awk -F '[ \t]+|=' '{print "hping",$8,"-a",$6,"-s",$10,"-p",$12,"-R -c 1"}'
        
        en se plaçant du bon côté du "firewall"
        • màj 09/00 : cette commande ne fonctionne plus en raison de la vérification des numéros de séquence lors de l'établissement de connexion.

        Mais pourquoi n'y a-t'il pas une commande pour cela ?

2.6 Autres possibilités

  • mac : vérifie l'adresse mac source

  • limit : limite le rythme maximal de correspondance d'une règle (défaut 3/h)

    • limite le nombre de paquets journalisés par seconde :
      • iptables -A FORWARD -m limit --limit 3/s -j LOG
    • limite le nombre de paquets SYN par seconde :
      • iptables -A FORWARD -p tcp --syn -m limit --limit 1/s -j ACCEPT
    • limite l'efficacité des scanners de ports
      • iptables -A FORWARD -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j ACCEPT
    • limite le nombre de requêtes icmp de type echo-request par seconde
      • iptables -A FORWARD -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT
      • iptables -A FORWARD -p icmp --icmp-type echo-request -j DROP

  • owner : correspond à un paquet généré localement par :

    • un utilisateur (uid) : --uid-owner userid
      • iptables -A OUTPUT -m state --state NEW -p tcp --syn --dport 80 -m owner ! --uid-owner 0 -j ACCEPT
      • iptables -A OUTPUT -p tcp --syn --dport 80 -j DROP
    • un groupe (gid) : --uid-owner groupid
    • un processus (pid) : --pid-owner processid
    • une session (sid) : --sid-owner processid

    Attention :

    • owner ne peut être appliqué qu'à la chaine OUTPUT
    • certains paquets n'ont pas de propriétaire : les réponses icmp...

    Cette option est unique : aucun autre filtre IP ne la possède sous Unix.

3. Traduction d'adresses

  • les chaines impliquées

  • la traduction de source

  • la traduction de destination

  • quelques comportements

3.1 Chaines impliquées

  • 3 chaines sont impliquéess dans la traduction d'adresse :

    • PREROUTING : traduction de la destination quand les paquets rentrent
    • POSTROUTING : traduction de la source quand les paquets sortent
    • OUTPUT : traduction de la destination pour les paquets générés localement

          _____                                     _____
         /     \                                   /     \
       PREROUTING -->[Routing ]----------------->POSTROUTING----->
         \D-NAT/     [Decision]                    \S-NAT/
                         |                            ^
                         |                          __|__
                         |                         /     \
                         |                        | OUTPUT|
                         |                         \D-NAT/
                         |                            ^
                         |                            |
                         --------> Local Process ------
    (c)2000 Rusty Russell
    

  • remarques :

    • La traduction de source est toujours réalisée en dernier
      • "masquerading" est une traduction de source

    • La traduction de destination est toujours réalisée en premier
      • "port forwarding" , "load sharing" et "transparent proxying" sont des traductions de destination.

3.2 Traduction de source

  • La traduction de source est toujours réalisée en dernier dans la chaine POSTROUTING .

    • Le routage et le filtrage voient le paquet inchangé.

  • Exemples :

    • # Change source addresses to 1.2.3.4.
      iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4
      
    • # Change source addresses to 1.2.3.4, 1.2.3.5 or 1.2.3.6
      iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4-1.2.3.6
      
    • # Change source addresses to 1.2.3.4, ports 1-1023
      iptables -t nat -A POSTROUTING -p tcp -o eth0 -j SNAT --to 1.2.3.4:1-1023
      
    • Masquage d'adresses :

      • # Masquerade everything out eth0.
        iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
        
      • # Masquerade tcp out eth0 using a range of source ports
        iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE -p tcp --to 2222-3333
        

3.3 Traduction de destination

  • La traduction de destination est toujours réalisée en premier :

    • soit dans la chaine OUTPUT pour les paquets générés localement,
    • soit dans le chaine PREROUTING pour les paquets entrant.

  • Exemples :

    • # Change destination addresses to 5.6.7.8
      iptables -t nat -A PREROUTING -i eth1 -j DNAT --to 5.6.7.8
      
    • # Change destination addresses to 5.6.7.8, 5.6.7.9 or 5.6.7.10.
      iptables -t nat -A PREROUTING -i eth1 -j DNAT --to 5.6.7.8-5.6.7.10
      
    • # Change destination addresses of web traffic to 5.6.7.8, port 8080.
      iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth1 -j DNAT --to 5.6.7.8:8080
      
    • # Redirect local packets to 1.2.3.4 to loopback.
      iptables -t nat -A OUTPUT -d 1.2.3.4 -j DNAT --to 127.0.0.1
      

    • Redirection :

      • # Send incoming port-80 web traffic to our squid (transparent) proxy
        iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 -j REDIRECT --to-port 3128
        

        Les connexions générées par des processus locaux ne sont pas redirigés.

3.4 Comportements

  • traduction vers un ensemble d'adresses :

    • l'adresse la moins utilisée actuellement est choisie.
    • permet de mettre en place du "load-balancing" de base.

      Cette répartition de charge est trop simple : si le service tombe sur l'un des serveurs, il refusera toutes les requêtes et se retrouvera avec le moins de requêtes en cours ;-)

  • traduction du port source : le port source n'est pas modifié par défaut sauf si la combinaison des couples adresse:port sources et destinations sont déja en cours d'utilisation.

  • 3 classes de ports existent :

    • 1 - 511
    • 512 - 1023
    • 1024 - 65535

    Par défaut, un port est toujours traduit par un port de la même classe.

4. Conclusion

  • aimer se tirer sur le pied :
    • syntaxe nouvelle et complexe

  • tout en étant sur le fil du rasoir (kernel: Oops: 0000) :
    • version de netfilter et iptables en cours de développement...
      màj 09/00 : depuis le 28/08/00, netfilter est en code freeze (seules les correction de bugs critiques sont envoyés à Linux Torvalds) et ipfilter le sera dès la sortie de la version 1.1.2 .
    • linux également !
      màj 09/00 : depuis les version 2.4.0-test , Linux s'est bien stabilisé (aucun oops ni redémarrage spontané ne sont apparus durant ces 3 derniers mois sur mon firewall personnel).

  • ne dispense pas des bonnes vieilles habitudes :
    • filtrage applicatif : tcpwrapper
    • et fonctionnalités noyau (rp_filter = anti-spoofing grâce au routage).

  • option unique (aucun autre filtre IP sous Unix ne la possède) :
    • filtrage suivant utilisateur, groupe, processus ou sesssion

  • atteindra à court terme de nombreuses offres professionnelles :
    • filtrage à étâts non parfait :
      • la gestion des numéros de séquence n'est que minimale (effectuée seulement dans l'établissement de la connexion).
      • il pourra être amélioré à court terme grace à un patch en court de test (ne devrait pas se trouver dans les premières versions de linux 2.4).
      mais très souvent suffisant
    • de nombreux relais existant sous ipchains attendent d'être portés sous netfilter
      • màj 09/00 : IRC et snmp sont en cours de tests dans le patch-o-matic.

5. Références

5.1 Documentations


HSC ® © Hervé Schauer Consultants 2000 - 4 bis, rue de la gare - 92300 Levallois-Perret
Téléphone : +33 141 409 700 - Télécopie : +33 141 409 709 - Courriel : <secretariat@hsc.fr>