Iptables: faire correspondre le trafic sortant avec conntrack et le propriétaire. Fonctionne avec des gouttes étranges


11

Dans mon script iptables, j'ai expérimenté l'écriture de règles aussi fines que possible. Je limite les utilisateurs autorisés à utiliser quels services, en partie pour des raisons de sécurité et en partie comme exercice d'apprentissage.

Utiliser iptables v1.4.16.2 sur Debian 6.0.6 exécutant le noyau 3.6.2.

Cependant, j'ai rencontré un problème que je ne comprends pas encore ...

ports sortants pour tous les utilisateurs

Cela fonctionne parfaitement bien. Je n'ai pas de règles de suivi d'état génériques.

## Port sortant 81
$ IPTABLES -A OUTPUT -p tcp --dport 81 -m conntrack --ctstate NOUVEAU, ÉTABLI -j ACCEPTER
$ IPTABLES -A INPUT -p tcp --sport 81 -s $ MYIP -m conntrack --ctstate ESTABLISHED -j ACCEPT

ports sortants avec correspondance utilisateur

## port sortant 80 pour compte d'utilisateur
$ IPTABLES -A OUTPUT --match owner --uid-owner useraccount -p tcp --dport 80 -m conntrack --ctstate NOUVEAU, ÉTABLI --sport 1024: 65535 -j ACCEPT
$ IPTABLES -A INPUT -p tcp --sport 80 --dport 1024: 65535 -d $ MYIP -m conntrack --ctstate ESTABLISHED -j ACCEPT

Cela autorise le port 80 à sortir uniquement pour le compte "compte d'utilisateur", mais des règles comme celle-ci pour le trafic TCP ont des problèmes.

## Journal sortant par défaut + règles de blocage
$ IPTABLES -A OUTPUT -j LOG --log-prefix "BAD OUTGOING" --log-ip-options --log-tcp-options --log-uid
$ IPTABLES -A SORTIE -j DROP

Le problème

Ce qui précède fonctionne, l'utilisateur "useraccount" peut obtenir des fichiers parfaitement bien. Aucun autre utilisateur du système ne peut établir de connexions sortantes avec le port 80.

useraccount @ host: $ wget http://cachefly.cachefly.net/10mb.test

Mais le wget ci-dessus laisse x7 entrées perdues dans mon syslog:

18 octobre 02:00:35 noyau xxxx: MAUVAIS SORTIE EN = SORTIE = eth0 SRC = xx.xx.xx.xx DST = 205.234.175.175 LEN = 40 TOS = 0x00 PREC = 0x00 TTL = 64 ID = 12170 DF PROTO = TCP SPT = 37792 DPT = 80 SEQ = 164520678 ACK = 3997126942 WINDOW = 979 RES = 0x00 ACK URGP = 0  

Je ne reçois pas ces baisses pour des règles similaires avec le trafic UDP. J'ai déjà des règles en place qui limitent les utilisateurs qui peuvent effectuer des requêtes DNS.

Les paquets ACK sortants abandonnés semblent provenir du compte root (URGP = 0) que je ne comprends pas. Même lorsque j'échange le compte utilisateur pour root.

Je crois que les paquets ACK sont classés comme nouveaux parce que conntrack commence à suivre les connexions après la 3e étape de la prise de contact à 3 voies, mais pourquoi sont-ils abandonnés?

Ces gouttes peuvent-elles être ignorées en toute sécurité?

Éditer

Je vois donc souvent des règles comme celles-ci, qui fonctionnent bien pour moi:

$ IPTABLES -A OUTPUT -s $ MYIP -p tcp -m tcp --dport 80 -m state --state NOUVEAU, ÉTABLI -j ACCEPTER
$ IPTABLES -A INPUT -p tcp -m tcp --sport 80 -d $ MYIP -m state --state ESTABLISHED -j ACCEPT

J'ai remplacé "-m state --state" par "-m conntrack --ctstate" car la correspondance d'état est apparemment obsolète.

Est-il préférable d'avoir des règles de suivi d'état génériques? Les règles ci-dessus ne sont-elles pas considérées comme correctes?

Pour un contrôle strict des connexions des utilisateurs sortants, quelque chose comme ça serait-il mieux?

$ IPTABLES -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT
$ IPTABLES -A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT

$ IPTABLES -A OUTPUT -p tcp --dport 80 -s $ SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m owner --uid-owner useraccount -j ACCEPT

$ IPTABLES -A OUTPUT -p tcp --dport 80 -s $ SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m owner --uid-owner otheraccount -j ACCEPT

Pourriez-vous s'il vous plaît publier toutes les règles, y compris la chaîne FORWARD et la table nat si cet hôte achemine également le trafic à partir du LAN.
Serge

Cet hôte ne fait aucun routage, le trafic provient de la machine avec ces règles. Je n'ai publié que les règles pertinentes pour le trafic sortant spécifique.
arcX

Réponses:


16

Pour faire court, cet ACK a été envoyé lorsque le socket n'appartenait à personne. Au lieu d'autoriser les paquets appartenant à un socket appartenant à l'utilisateur x, autorisez les paquets appartenant à une connexion initiée par un socket de l'utilisateur x.

L'histoire la plus longue.

Pour comprendre le problème, il permet de comprendre comment wgetet les requêtes HTTP fonctionnent en général.

Dans

wget http://cachefly.cachefly.net/10mb.test

wgetétablit une connexion TCP à cachefly.cachefly.net, et une fois établie envoie une demande dans le protocole HTTP qui dit: "Veuillez m'envoyer le contenu de /10mb.test( GET /10mb.test HTTP/1.1) et en passant, pourriez-vous s'il vous plaît ne pas fermer la connexion après avoir terminé ( Connection: Keep-alive). La raison c'est parce que si le serveur répond avec une redirection pour une URL sur la même adresse IP, il peut réutiliser la connexion.

Maintenant, le serveur peut répondre par l'un ou l'autre: "voici les données que vous avez demandées, méfiez-vous qu'il fait 10 Mo de large ( Content-Length: 10485760), et oui, je laisse la connexion ouverte". Ou s'il ne connaît pas la taille des données, "Voici les données, désolé je ne peux pas laisser la connexion ouverte mais je dirai quand vous pouvez arrêter de télécharger les données en fermant ma fin de connexion".

Dans l'URL ci-dessus, nous sommes dans le premier cas.

Ainsi, dès qu'il wgeta obtenu les en-têtes de la réponse, il sait que son travail est terminé une fois qu'il a téléchargé 10 Mo de données.

Fondamentalement, ce wgetqui est lu les données jusqu'à ce que 10 Mo aient été reçus et quittent. Mais à ce stade, il reste encore beaucoup à faire. Et le serveur? On lui a dit de laisser la connexion ouverte.

Avant de quitter, wgetferme ( closeappel système) le descripteur de fichier du socket. Le close, le système termine d'acquitter les données envoyées par le serveur et envoie un FINpour dire: "Je n'enverrai plus de données". À ce point closerevient et wgetsort. Il n'y a plus de socket associé à la connexion TCP (du moins pas un appartenant à un utilisateur). Mais ce n'est pas encore fini. A réception de cela FIN, le serveur HTTP voit la fin du fichier lors de la lecture de la prochaine requête du client. En HTTP, cela signifie "plus de demande, je vais fermer ma fin". Donc, il envoie également son FIN, pour dire: "Je n'enverrai rien non plus, cette connexion est en train de disparaître".

A réception de cette FIN, le client envoie un "ACK". Mais, à ce stade, a wgetdisparu depuis longtemps, de sorte que ACK ne provient d'aucun utilisateur. C'est pourquoi il est bloqué par votre pare-feu. Parce que le serveur ne reçoit pas le ACK, il va envoyer le FIN encore et encore jusqu'à ce qu'il abandonne et vous verrez plus de ACK abandonnés. Cela signifie également qu'en supprimant ces ACK, vous utilisez inutilement les ressources du serveur (qui doit maintenir un socket dans l'état LAST-ACK) pendant un certain temps.

Le comportement aurait été différent si le client n'avait pas demandé "Keep-alive" ou si le serveur n'avait pas répondu "Keep-alive".

Comme déjà mentionné, si vous utilisez le traqueur de connexion, ce que vous voulez faire, c'est laisser passer chaque paquet dans les états ESTABLISHED et RELATED et ne vous souciez que des NEWpaquets.

Si vous autorisez les NEWpaquets de l'utilisateur xmais pas les paquets de l'utilisateur y, alors d'autres paquets pour les connexions établies par l'utilisateur xpasseront, et parce qu'il ne peut pas y avoir de connexions établies par l'utilisateur y(puisque nous bloquons les NEWpaquets qui établiraient la connexion), il n'y aura aucun paquet pour les yconnexions des utilisateurs .


3

Cela autorise le port 80 uniquement pour le compte "compte utilisateur"

- au moins, les règles que vous avez montrées n'impliquent pas cela, en fait.

Il y a aussi une place pour des conseils - ne faites pas de vérification des utilisateurs sur les flux ESTABLISHED, faites simplement cette vérification sur NEW. Je ne vois pas non plus d'intérêt à vérifier le port source lorsque je vérifie Incoming ESTABLISHED, quelle est la différence de quel port il s'agissait, il est déjà à l'état ESTABLISHED du PoV de conntrack. Le pare-feu doit être aussi simple que possible mais efficace pour le moment, donc l' approche du rasoir d'Occam est la meilleure solution.


1
Merci pour le conseil. Habituellement, je suis tout pour la simplicité, mais ce n'est pas le but de cet exercice particulier.
arcX

1
@arcX, cet exercice peut échouer car il est trop complexe et incohérent - IOW, le comportement que vous voyez peut ne pas être dû à des internes de netfilter (bugs, bizarreries), mais à la façon dont vous l'utilisez. Essayez d'abord de simplifier le jeu de règles…
poige
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.