Supprimer une connexion TCP ouverte sans envoyer de RST

En regardant dans nginx: ignorer certaines requêtes sans en-tête d’hôte approprié m’a fait penser qu’il n’est pas réellement possible de close(2) une connexion TCP sans que le système d’exploitation mette correctement fin à la connexion TCP sous-jacente en envoyant un RST (et / ou FIN ) à l’autre extrémité. .

Une solution de contournement consisterait à utiliser quelque chose comme tcpdrop(8) . Cependant, comme le montre usr.sbin/tcpdrop/tcpdrop.c sur OpenBSD et FreeBSD , il est implémenté via une interface basée sur sysctl et peut avoir des problèmes de portabilité en dehors de BSD. (En fait, il semble que même l’implémentation basée sur sysctl puisse être suffisamment différente entre OpenBSD et FreeBSD pour exiger une couche de portage – OpenBSD utilise la structure tcp_ident_mapping (qui contient ensuite deux éléments sockaddr_storage , plus d’autres informations), FreeBSD , DragonFly et NetBSD utilisent directement un tableau de deux éléments sockaddr_storage .) Il s’avère que tcpdrop d’OpenBSD semble envoyer le paquet R comme tcpdump(8) par tcpdump(8) , et peut être confirmé en regardant /sys/netinet/tcp_subr.c :: tcp_drop() , qui appelle tcp_close() (et tcp_close() est confirmé que tcp_close() envoie RST ailleurs sur SO ), il semble donc que cela ne fonctionnerait même pas non plus.

Si j’établis moi-même la connexion via C, existe-t-il un moyen de la supprimer par la suite sans accusé de réception de l’autre côté, par exemple, sans initier la RST ?

Si j’établis moi-même la connexion via C, existe-t-il un moyen de la supprimer par la suite sans accusé de réception de l’autre côté, par exemple, sans initier la RST?

Non. Même s’il y en avait, si le pair envoyait ensuite quelque chose, il recevrait une réponse de la TVD.

NB La terminaison TCP normale utilise une FIN, pas une RST.

Tricher un attaquant de cette manière pourrait être une bonne idée. Bien entendu, dans ce cas, vous réservez déjà des ressources de serveur pour la connexion établie. Dans le mode de base, vous pouvez utiliser netfilter pour supprimer tout segment sortant TCP avec les indicateurs RST ou FIN définis. Cette règle iptables rule pourrait être un exemple:

 sudo iptables -A OUTPUT -p tcp --tcp-flags FIN,RST SYN -j DROP 

Bien entendu, cette règle affectera toutes vos connexions TCP . Je l’ai écrit pour vous montrer comment vous pouvez le faire. Rendez-vous sur https://www.netfilter.org/ pour obtenir davantage d’idées sur votre solution. Fondamentalement, vous devriez pouvoir faire la même chose uniquement pour les connexions sélectionnées.

En raison du fonctionnement de TCP, si vous parvenez à l’implémenter, le client (ou l’attaquant) maintiendra la connexion ouverte pendant une longue période. Pour comprendre l’effet que cela aurait sur un client, lisez ceci : TCP, la fonction recv est suspendue malgré KEEPALIVE où je fournis les résultats d’un test dans lequel l’autre partie ne renvoie aucun segment TCP (pas même un ACK). Dans ma configuration, le socket met un délai de 13 minutes pour entrer un état d’erreur (cela dépend de parameters Linux tels que tcp_resortinges1 et tcp_resortinges2).

Il suffit de penser qu’une attaque par déni de service impliquera généralement des connexions provenant de milliers de périphériques différents et pas nécessairement beaucoup de connexions du même périphérique. Ceci est très facile à détecter et à bloquer dans le pare-feu. Il est donc très improbable que vous génériez un épuisement des ressources chez le client. De plus, cette solution ne fonctionnera pas dans les cas d’attaque de connexion semi-ouverte.