Iptable - petites questions

Bon, ça fait un moment que mon serveur maison tourne avec le script suivant, j’ai suivis différents documents glanés ça et là. Les services:

  • Web vers * ou/et vers le réseau maison suivant les cas
  • NFS vers le réseau maison
  • ssh vers le réseau maison

Mon but est de choisir l’état du serveur au lancement du script, à savoir ouvrir le http vers le web ou pas, etc… J’ai donc différentes fonctions qui si je ne me suis pas trompé font ce que je veux. Mes questions:

  • Est-ce raisonnable de mixer un NFS et un serveur web sur la même machine ou vaut-il mieux éviter?
  • J’ai l’impression d’avoir des chaînes superflues, est-ce la cas?

Merci.

[code]#!/bin/bash

firewall une interface

laisser passer le trafic http depuis le net et/ou l’intèrieur suivant ce qu’on veut

laisser passer le trafic nfs sur les adresses qui vont bien.

IPTABLES="/sbin/iptables"
ANYWHERE="0.0.0.0/0"
PRIVPORTS="0:1023"
UNPRIVPORTS="1024:65535"
CUICUI=“192.168.1.102”

parano() {

Effacement de toutes les règles

echo -en “Effacement des anciennes regles :”
$IPTABLES -F
$IPTABLES -X
$IPTABLES -t nat -F
$IPTABLES -t nat -X
$IPTABLES -t mangle -F
$IPTABLES -t mangle -X
echo -e “OK”

echo -en “Mise en place de la polique par defaut :”
$IPTABLES -P INPUT DROP # drop all incoming packets
$IPTABLES -P OUTPUT DROP # drop all outcoming packets
$IPTABLES -P FORWARD DROP # drop all forwarded packets
echo -e “###################### rien ne passe (en theorie) ########################”
}

stop() {
$IPTABLES -F
$IPTABLES -X
$IPTABLES -P INPUT ACCEPT
$IPTABLES -P FORWARD ACCEPT
$IPTABLES -P OUTPUT ACCEPT
echo -e “######################## firewall desactive ##########################”
}

minimum-client() {

autorise trafic entrant sur connexion deja etablie.

$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

L’interface de loopback etant consideree comme sure, toutes les

connexions sont autoriees

$IPTABLES -A INPUT -i lo -j ACCEPT
$IPTABLES -A OUTPUT -o lo -j ACCEPT
echo -e "loopback OK"

client DNS.

$IPTABLES -A OUTPUT -o eth0 -p udp \
         --sport $UNPRIVPORTS \
	 --dport 53 -j ACCEPT
$IPTABLES -A INPUT -i eth0 -p udp \
         --sport 53 \
         --dport $UNPRIVPORTS -j ACCEPT
echo -e "DNS client OK"

Gérer les connexions aux serveurs ftp

$IPTABLES -A INPUT -i eth0 -p tcp --sport 21 -m state --state ESTABLISHED -j ACCEPT
$IPTABLES -A OUTPUT -o eth0 -p tcp --dport 21 -m state --state NEW,ESTABLISHED -j ACCEPT 
$IPTABLES -A INPUT -i eth0 -p tcp --sport 20 -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A OUTPUT -o eth0 -p tcp --dport 20 -m state --state ESTABLISHED -j ACCEPT 
$IPTABLES -A INPUT -i eth0 -p tcp --sport $UNPRIVPORTS --dport $UNPRIVPORTS -m state --state ESTABLISHED -j ACCEPT
$IPTABLES -A OUTPUT -o eth0 -p tcp --sport $UNPRIVPORTS --dport $UNPRIVPORTS -m state --state ESTABLISHED,RELATED -j ACCEPT
echo -e "FTP client OK"

Gérer l’accès aux sites web en tant que client

Note :

Si le client DNS n’est pas autorisé, alors il est uniquement possible de naviguer sur Internet

en employant les addresse ip des sites webs.

# Libérer le port 80 (input et output)
$IPTABLES -A OUTPUT -o eth0 -p tcp --sport $UNPRIVPORTS --dport 80 -s $CUICUI -j ACCEPT 
    $IPTABLES -A INPUT -i eth0 -p tcp --sport 80 --dport $UNPRIVPORTS -s $ANYWHERE -d $CUICUI -j ACCEPT
# Libérer le port 443 (input et output)
$IPTABLES -A OUTPUT -o eth0 -p tcp --sport $UNPRIVPORTS --dport 443 -s $CUICUI -j ACCEPT 
$IPTABLES -A INPUT -i eth0 -p tcp --sport 443 --dport $UNPRIVPORTS -s $ANYWHERE -d $CUICUI -j ACCEPT
echo -e "http client OK"

Gérer le ping vers l’extérieur

Note :

Le ping est basé sur le protocol ICMP.

L’ICMP-type 8 correspond à l’envoi de echo vers l’extérieur

L’ICMP-type 0 correspond à la réception d’un echo-reply

# Autoriser l'envoie d'un echo 
$IPTABLES -A OUTPUT -o eth0 -p icmp --icmp-type 8 -j ACCEPT
# Autoriser la réception d'un echo-reply
$IPTABLES -A INPUT -i eth0 -p icmp --icmp-type 0 -j ACCEPT
echo -e "un peu d'ICMP quand meme..."

}

serveur-web() {

autoriser connexion deja etablie

$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
parano
minimum-client

le ssh en local

    $IPTABLES -A INPUT -p tcp -i eth0 -s 192.168.1.100/24 --dport ssh -j ACCEPT
    $IPTABLES -A OUTPUT -p tcp -o eth0 --sport ssh -d 192.168.1.100/24 -j ACCEPT
    $IPTABLES -A INPUT -p tcp -i eth0 -d 192.168.1.100/24 --sport ssh -j ACCEPT
    $IPTABLES -A OUTPUT -p tcp -o eth0 --dport ssh -s 192.168.1.100/24 -j ACCEPT

Gérer un serveur web (80)

    $IPTABLES -A INPUT -i eth0 -p tcp -s $ANYWHERE --sport $UNPRIVPORTS -d $CUICUI --dport 80 -j ACCEPT
    $IPTABLES -A OUTPUT -o eth0 -p tcp -s $CUICUI --sport 80 -d $ANYWHERE  --dport $UNPRIVPORTS -j ACCEPT

}

serveur-lan() {
minimum-client

le ssh en local

$IPTABLES -A INPUT -p tcp -i eth0 -s 192.168.1.100/24 --dport ssh -j ACCEPT
$IPTABLES -A OUTPUT -p tcp -o eth0 --sport ssh -d 192.168.1.100/24 -j ACCEPT
$IPTABLES -A INPUT -p tcp -i eth0 -d 192.168.1.100/24 --sport ssh -j ACCEPT
$IPTABLES -A OUTPUT -p tcp -o eth0 --dport ssh -s 192.168.1.100/24 -j ACCEPT

Gérer un serveur web (80) en interne

$IPTABLES -A INPUT -i eth0 -p tcp -s 192.168.1.100/24 --sport $UNPRIVPORTS -d $CUICUI --dport 80 -j ACCEPT
$IPTABLES -A OUTPUT -o eth0 -p tcp -s $CUICUI --sport 80 -d 192.168.1.100/24 --dport $UNPRIVPORTS -j ACCEPT

le NFS en local

$IPTABLES -A INPUT -i eth0 -p udp -s 192.168.1.100/24  -d $CUICUI --dport 111 -j ACCEPT
$IPTABLES -A INPUT -i eth0 -p tcp -s 192.168.1.100/24  -d $CUICUI --dport 111 -j ACCEPT
$IPTABLES -A INPUT -i eth0 -p udp -s 192.168.1.100/24  -d $CUICUI --dport 2049 -j ACCEPT
$IPTABLES -A INPUT -i eth0 -p tcp -s 192.168.1.100/24  -d $CUICUI --dport 2049 -j ACCEPT
$IPTABLES -A INPUT -i eth0 -p udp -s 192.168.1.100/24  -d $CUICUI --dport 32765:32769 -j ACCEPT
$IPTABLES -A INPUT -i eth0 -p tcp -s 192.168.1.100/24  -d $CUICUI --dport 32765:32769 -j ACCEPT
$IPTABLES -A INPUT -i eth0 -p udp -s 192.168.1.100/24  -d $CUICUI --dport 113 -j ACCEPT
$IPTABLES -A INPUT -i eth0 -p tcp -s 192.168.1.100/24  -d $CUICUI --dport 113 -j ACCEPT

$IPTABLES -A OUTPUT -o eth0 -p udp -d 192.168.1.100/24  -s $CUICUI --sport 111 -j ACCEPT
$IPTABLES -A OUTPUT -o eth0 -p tcp -d 192.168.1.100/24  -s $CUICUI --sport 111 -j ACCEPT
$IPTABLES -A OUTPUT -o eth0 -p udp -d 192.168.1.100/24  -s $CUICUI --sport 2049 -j ACCEPT
$IPTABLES -A OUTPUT -o eth0 -p tcp -d 192.168.1.100/24  -s $CUICUI --sport 2049 -j ACCEPT
$IPTABLES -A OUTPUT -o eth0 -p udp -d 192.168.1.100/24  -s $CUICUI --sport 32765:32769 -j ACCEPT
$IPTABLES -A OUTPUT -o eth0 -p tcp -d 192.168.1.100/24  -s $CUICUI --sport 32765:32769 -j ACCEPT
$IPTABLES -A OUTPUT -o eth0 -p udp -d 192.168.1.100/24  -s $CUICUI --sport 113 -j ACCEPT
$IPTABLES -A OUTPUT -o eth0 -p tcp -d 192.168.1.100/24  -s $CUICUI --sport 113 -j ACCEPT

echo “NFS, enlever ce qui est superflu, sur la chaine OUTPUT… TODO!”
}

restart() {
stop
sleep 2
start
}

case “$1” in
’client’ )
parano
minimum-client
;;
‘web’ )
parano
serveur-web
;;
‘lan’ )
parano
serveur-lan
;;
‘parano’ )
parano
;;
‘stop’ )
stop
;;
‘start’ )
parano
serveur-web
serveur-lan
;;
‘restart’ )
restart
;;
‘status’ )
$IPTABLES -L -n -v

echo "Usage: /etc/init.d/firewall {start|stop|restart|status|parano|client|web|lan}"

esac
[/code]

ben tu as fait un découpage un peu bizarre de tes subs, qui s’entreappelle dans tous les sens et font trop de choses à la fois.
Par exemple, serveur-web appelle parano, et dans ton start, tu fais parano, puis serveur-web, ce qui te fait faire deux fois parano.
Tu devrais redécouper tes subs pour qu’elles ne fassent qu’une chose: close-all, open-lo, open-ssh, open-http, open-ftp, open-nfs, open-icmp. Ensuite, pour chaque fonction, tu crées une variable correspondante $INITALL,$INITLO,$INITSSH, etc, que tu mets à 0 au début du script, et que tu testes au début de chacune des fonctions: si elle est à 1, tu sors tout de suite de la sub puisque tu l’as déjà faite, sinon, tu executes le reste de la sub, et tu mets la variable à 1 pour dire “ça y est c’est fait”.
Comme ça, même si tu appelles plusieurs fois la même sub, elle ne s’execute qu’une fois. Aprés, tu pourras reconstruire parano, serveur-web, etc sur la base de ces briques minimales.

Par ailleurs, pourquoi ne pas avoir mis 192.168.1.100/24 dans une variable ?
Autre truc: au lieu de --sport 80, tu peux mettre --sport http, et ça marche avec tous les ports définis dans /etc/services, et si les ports que tu utilises n’y sont pas définis, rien ne t’empêche de leur donner un nom et de les ajouter dans /etc/services. Ca rend le tout plus lisible.

Sinon, pour nfs, bah ça pourrait être dangereux si il y avait moyen de sniffer de l’extèrieur ce qu’il y a sur ton réseau, mais comme ce n’est pas le cas…

Voili voilou…

[quote=“mattotop”]ben tu as fait un découpage un peu bizarre de tes subs, qui s’entreappelle dans tous les sens et font trop de choses à la fois.
Par exemple, serveur-web appelle parano, et dans ton start, tu fais parano, puis serveur-web, ce qui te fait faire deux fois parano.[/quote]
C’est noté, encore un truc que j’ai fait à une heure pas possible, et que j’ai pas relu à partir du moment où “ça a marché”

[quote=“mattotop”]
Tu devrais redécouper tes subs pour qu’elles ne fassent qu’une chose: close-all, open-lo, open-ssh, open-http, open-ftp, open-nfs, open-icmp. Ensuite, pour chaque fonction, tu crées une variable correspondante $INITALL,$INITLO,$INITSSH, etc, que tu mets à 0 au début du script, et que tu testes au début de chacune des fonctions: si elle est à 1, tu sors tout de suite de la sub puisque tu l’as déjà faite, sinon, tu executes le reste de la sub, et tu mets la variable à 1 pour dire “ça y est c’est fait”.
Comme ça, même si tu appelles plusieurs fois la même sub, elle ne s’execute qu’une fois. Aprés, tu pourras reconstruire parano, serveur-web, etc sur la base de ces briques minimales.[/quote]
Bonne idée le coup des variables, ça me rappelle mes études quand on écrivait des lexeurs en java. J’étais nullos mais j’aimais bien ça, les maths m’ont rattrapé…

Ça c’est la faute à Vim (j’ai du faire :% s/adresse/192.168.1.100/24/gc au lieu de définir simplement une variable…)

Noté.

[quote=“mattotop”]
Sinon, pour nfs, bah ça pourrait être dangereux si il y avait moyen de sniffer de l’extèrieur ce qu’il y a sur ton réseau, mais comme ce n’est pas le cas…

Voili voilou…[/quote]
Merci, c’est sympa! Je vais mettre en application…

quote="ziouplaboum"
Bonne idée le coup des variables, ça me rappelle mes études quand on écrivait des lexeurs en java. J’étais nullos mais j’aimais bien ça, les maths m’ont rattrapé…
(…)[/quote] Bah j’ai rien inventé, si tu as fait du C/C++, c’est le même truc que le:

#ifndef __TRUC_H #define __TRUC_H ... #endifQui permet de ne pas inclure deux fois le code d’un .h

Je crois comprendre l’analogie avec les fichiers headers, bien que je n’ai jamais eu à faire du C.

Aucun rapport mais as-tu dèja fait un pare-feu avec packet filter sur *BSD. J’avais vaguement discuté de ça avec un type dont c’est le boulot, et il avait l’air de dire que c’était vachement plus compréhensible que iptable au niveau syntaxe (c’eût été étonnant qu’il ne défende pas sa chapelle), et que ça permettait de faire plus de choses que iptable.

Non, jamais utilisé. Il semble y avoir des fonctionnalités avancées de qos et de gestion de bp qui existent mais sont moins utilisées sur iptables (on utilise plutot d’autres outils pour ça sous nux, il me semble), mais AMA, les deux doivent être comparables en terme de fonctionnalités.
Pour ce que j’en ai vu, pf est plus verbeux qu’ipt, mais aprés, c’est surment une question de gout et d’habitude quant à la lisibilité.

Pour répondre à une de tes questions : non, il n’y a pas de chaînes superflues, pour la bonne raison qu’il n’y a que les chaînes prédéfinies, et aucune chaîne utilisateur. On peut difficilement faire moins !

Ensuinte, je ne me prononcerai pas sur le script lui-même, Matt a déjà répondu sur ce point, mais j’ai quelques remarques sur tes règles iptables.

ANYWHERE=“0.0.0.0/0” => ça ne sert à rien et ça alourdit l’écriture des règles inutilement. Tout ce qui alourdit l’écriture des règles nuit à leur compréhension.
N’importe quelle adresse => pas d’option -s ou -d, tout simplement. Viendrait-il à l’idée d’écrire “–sport 0:65535” pour signifier n’importe quel port source ?

$IPTABLES -A INPUT -i eth0 -p udp --sport 53 --dport $UNPRIVPORTS -j ACCEPT
Erreur classique. En voulant accepter les réponses DNS, en fait cette règle laisse passer tout paquet UDP ayant le port source 53 vers n’importe quel ports non privilégié. En plus elle est redondante puisque les paquets de réponse sont déjà acceptés par la règle autorisant le trafic entrant sur connexion déjà établie. La même remarque vaut pour les règles avec des --sport censées accepter les paquets retour HTTP(S), SSH…

En revanche bravo pour la qualité de la gestion des connexions FTP, c’est rare. Mais franchement c’est presque trop, et malheureusement les restrictions des ports en INPUT sont court-circuitées par la règle générale acceptant le trafic établi/lié. Je trouve que ces trois règles sont suffisantes :
$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A OUTPUT -o eth0 -p tcp --dport ftp -j ACCEPT

$IPTABLES -A INPUT -i eth0 -p icmp --icmp-type 0 -j ACCEPT
Redondante puisque les réponses au ping sont déjà acceptées par la règle générale acceptant le trafic établi/lié.

Avec le suivi de connexion, on n’a pas besoin de se préoccuper des paquets retour. Il suffit d’accepter les paquets NEW spécifiques dans la direction initiale, et la règle générale fait le reste.

Accessoirement, pour améliorer la lisibilité on peut remplacer le type ICMP numérique par son équivalent texte comme “echo-request”, “echo-reply”… (cf. iptables -p icmp -h pour la liste)

192.168.1.100/24 => le .100 est ignoré puisqu’il est en dehors du préfixe /24. Il est plus logique d’écrire 192.168.1.0/24.

[quote=“PascalHambourg”]Pour répondre à une de tes questions : non, il n’y a pas de chaînes superflues, pour la bonne raison qu’il n’y a que les chaînes prédéfinies, et aucune chaîne utilisateur. On peut difficilement faire moins !
[/quote]
C’est noté merci.

Effectivement, autant améliorer la lisibilité des règles. Disons que pour un lecteur de règle iptables non expérimenté que je suis ça m’a aidé à comprendre ce que j’écrivais, c’était plus explicite même si c’était superflu. Avec un peu plus de recul c’est clairement nuisible!

Noté, merci.

Je n’ai pas de mérite, je me suis fortement inspiré des choses trouvées sur le net. Pour faire mon script j’ai ouvert 6- onglets à partir d’une recherche, j’ai fait ma tambouille et quand ça marchait j’ai tout fermé donc je ne retrouve pas mes sources (il faudrait que je les recherche…)

C’est noté.

Merci pour tes conseils. Il n’y a donc pas de chaines superflues mais il y a quand mêmes quelques règles inutiles, redondantes et des options dont on peut se passer! Il me faut mettre en œuvre toutes vos remarques maintenant.

p.s. Lire de la doc c’est bien mais pouvoir avoir un retour avec des personnes compétentes c’est mieux! Merci à vous!