Débogage en Bash

Il y a certaines choses qui peuvent être faites avec Bash pour nous aider à déboguer nos scripts contenant les tables de règles. Un des premiers problèmes quand on trouve un bogue est de savoir dans quelle ligne il se trouve. Ceci peut être résolu de deux façons différentes, soit en utilisant le fanion -x du Bash, soit en tapant simplement echo pour trouver l'endroit où le problème apparaît. Idéalement, vous pouvez avec echo, ajouter quelque chose comme les états suivants à intervalles réguliers dans le code :

  ...
  echo "Debugging message 1."
  ...
  echo "Debugging message 2."
  ...
      

Dans mon cas, j'utilise des messages insignifiants, tant qu'ils ont quelque chose d'unique je peux retrouver le message d'erreur par un simple grep ou une recherche dans le script. Maintenant, si le message d'erreur apparaît après le "Debugging message 1", mais avant le "Debugging message 2", nous savons alors que la ligne de code erronée est quelque part entre les deux messages. Comme vous pouvez le comprendre, Bash n'est pas réellement mauvais, et a au moins l'idée de continuer à exécuter les commandes même s'il y a une erreur dans une commande précédente. Dans Netfilter, ceci peut provoquer certains problèmes très intéressants. L'idée d'utiliser les états echo pour trouver les erreurs est très simple, mais vous pouvez en même temps cerner l'ensemble du problème à une seule ligne de code.

La seconde possibilité pour trouver le problème est d'utiliser la variable Bash -x, comme dit précédemment. Ceci peut bien sûr être gênant, particulièrement si votre script est volumineux, et que le tampon de votre console n'est pas assez important. Ce que la variable -x indique est très simple, elle précise au script d'envoyer un écho pour chaque ligne de code de votre script vers la sortie standard du shell (généralement la console). Pour cela changez la ligne de début du script qui doit se présenter comme :

#!/bin/bash
      

en la ligne suivante :

#!/bin/bash -x
      

Comme vous pouvez le voir, ceci ne modifie peut être que deux lignes, dans le total important de données en sortie. Le code vous indique chaque ligne de commande qui est exécutée, et avec quelles valeurs de variables, etc. Chaque ligne exécutée est affichée sur votre écran. Une chose intéressante, est que les lignes de sortie Bash sont préfixées par un signe +. Ceci rend plus facile de discerner les messages d'erreur et d'avertissement provenant du script.

L'option -x est aussi très intéressante pour déboguer les problèmes communs qu'on rencontre dans les tables de règles plus complexes. Le premier est de trouver ce qui se passe avec ce que vous pensiez être une simple boucle. Voyons l'exemple ci-dessous.

  #!/bin/bash 
  iptables="/sbin/iptables"
  $iptables -N output_int_iface
  cat /etc/configs/machines | while read host; do
    $iptables -N output-$host
    $iptables -A output_int_iface -p tcp -d $host -j output-$host

    cat /etc/configs/${host}/ports | while read row2; do
      $iptables -A output-$host -p tcp --dport $row2 -d $host -j ACCEPT
    done
  done
      

Ces règles peuvent sembler simples, mais le problème existe toujours. Nous obtenons les messages d'erreur suivants que nous savons provenir du code ci-dessus en utilisant un simple écho comme méthode de débogage.

work3:~# ./test.sh
Bad argument `output-'
Try `iptables -h' or 'iptables --help' for more information.
cat: /etc/configs//ports: No such file or directory
      

Activons l'option -x du Bash et regardons la sortie. Celle-ci est indiquée ci-dessous, comme vous pouvez le voir il y a quelque chose de très mystérieux. Il existe un couple de commandes où les variables $host et $row2 ne sont remplacées par rien. En regardant de plus près, nous voyons que c'est seulement la dernière itération du code qui cause problème. Soit nous avons fait une erreur de programmation, soit il y a quelque chose d'étrange avec la donnée. Dans ce cas c'est une simple erreur avec la donnée, qui contient un saut de ligne en trop à la fin du fichier. Ceci crée une boucle d'itération. En supprimant simplement ce saut de ligne du fichier, le problème est résolu. Ceci peut ne pas être une solution très élégante, mais pour un usage privé c'est suffisant. D'un autre côté nous avons ajouté du code qui indique qu'il y a certaines données dans les variables $host et $row2.

work3:~# ./test.sh
+ iptables=/sbin/iptables
+ /sbin/iptables -N output_int_iface
+ cat /etc/configs/machines
+ read host
+ /sbin/iptables -N output-sto-as-101
+ /sbin/iptables -A output_int_iface -p tcp -d sto-as-101 -j output-sto-as-101
+ cat /etc/configs/sto-as-101/ports
+ read row2
+ /sbin/iptables -A output-sto-as-101 -p tcp --dport 21 -d sto-as-101 -j ACCEPT
+ read row2
+ /sbin/iptables -A output-sto-as-101 -p tcp --dport 22 -d sto-as-101 -j ACCEPT
+ read row2
+ /sbin/iptables -A output-sto-as-101 -p tcp --dport 23 -d sto-as-101 -j ACCEPT
+ read row2
+ read host
+ /sbin/iptables -N output-sto-as-102
+ /sbin/iptables -A output_int_iface -p tcp -d sto-as-102 -j output-sto-as-102
+ cat /etc/configs/sto-as-102/ports
+ read row2
+ /sbin/iptables -A output-sto-as-102 -p tcp --dport 21 -d sto-as-102 -j ACCEPT
+ read row2
+ /sbin/iptables -A output-sto-as-102 -p tcp --dport 22 -d sto-as-102 -j ACCEPT
+ read row2
+ /sbin/iptables -A output-sto-as-102 -p tcp --dport 23 -d sto-as-102 -j ACCEPT
+ read row2
+ read host
+ /sbin/iptables -N output-sto-as-103
+ /sbin/iptables -A output_int_iface -p tcp -d sto-as-103 -j output-sto-as-103
+ cat /etc/configs/sto-as-103/ports
+ read row2
+ /sbin/iptables -A output-sto-as-103 -p tcp --dport 21 -d sto-as-103 -j ACCEPT
+ read row2
+ /sbin/iptables -A output-sto-as-103 -p tcp --dport 22 -d sto-as-103 -j ACCEPT
+ read row2
+ /sbin/iptables -A output-sto-as-103 -p tcp --dport 23 -d sto-as-103 -j ACCEPT
+ read row2
+ read host
+ /sbin/iptables -N output-
+ /sbin/iptables -A output_int_iface -p tcp -d -j output-
Bad argument `output-'
Try `iptables -h' or 'iptables --help' for more information.
+ cat /etc/configs//ports
cat: /etc/configs//ports: No such file or directory
+ read row2
+ read host
      

Le troisième et dernier problème peut être partiellement résolu avec l'aide de l'option -x si vous exécutez le script du pare-feu par SSH, la console se suspend au milieu de l'exécution du script, elle ne vous rend pas la main, ni vous ne pouvez vous connecter par SSH à nouveau. Dans 99% des cas, ceci indique qu'il y a certains problèmes dans le script avec un couple de règles. En activant l'option -x, vous verrez exactement à quelle ligne ça bloque. Il y a une ou deux circonstances où ce n'est pas vrai, malheureusement. Par exemple, si le script initialise une règle qui bloque le trafic entrant, mais que le serveur ssh/telnet envoie un écho en premier comme trafic sortant, netfilter enregistrera la connexion, et donc permettra le trafic entrant de toutes destinations si vous avez une règle qui maintient les états de connexion.

Comme vous pouvez le voir, il peut être tout à fait complexe de déboguer vos tables de règles. Cependant, ce n'est pas impossible. Vous pouvez aussi avoir noté, si vous travaillez à distance sur votre pare-feu via SSH par exemple, que le pare-feu peut se figer quand vous chargez des règles incorrectes. Une des choses supplémentaires que vous pouvez faire dans ces circonstances, est de faire une sauvegarde par jour. Cron est un excellent moyen pour faire ça. Exemple, vous travaillez sur un pare-feu en étant à 50 km de distance, vous ajoutez et supprimez des règles. Le pare-feu se bloque, et vous ne pouvez plus rien faire. le seul moyen est de vous déplacer à l'endroit où se trouve physiquement le pare-feu et régler le problème, à moins que vous n'ayez pris des précautions de ce genre !