jeudi, octobre 12, 2006

Bizarreries Réseau (2)

Bon en fait c'est plus qu'une bizarrerie, c'est un gros bug. Gros gros, qui montre que le passage de MacOS des processeurs PowerPC à Intel est pas si tranquille que ça.

Je développe un logiciel de détection d'anomalie de trafic réseau, un petit truc qui doit permettre de repérer les malins qui font du SSH dans HTTPS ou un tunnel IP dans DNS ... Pour cela, il est nécessaire d'écouter le réseau, mais également de reconstruire le trafic afin d'obtenir le flux de données tel qu'il est lu à l'autre bout. Cela nécessite donc de réassembler le trafic TCP, ce qui n'est pas très simple, et ce que fait (imparfaitement) par exemple libnids. J'ai parlé de ce truc en gestation à SSTIC06.

Quand j'ai commencé à porter ce petit travail sur mon Mac, libnids ne reconnaissait aucun trafic. J'ai commencé par penser que le portage de libnids était un peu moisi (ce qu'il est), puis j'ai examiné le trafic remontré par libpcap (dans tcpdump ou ethereal), et j'ai constaté que tous les checksums des paquets TCP envoyés par ma machine étaient faux.
10:39:29.784579 IP (tos 0x10, ttl 64, id 30135, offset 0, flags [DF], proto: TCP (6), length: 52) 192.70.106.104.61090 > 192.70.106.100.22: .,cksum 0x5580 (incorrect (-> 0x7e1c), 192:192(0) ack 2657 win 65312
Jusque là, ce n'est pas un bug en fait: les cartes Ethernet récentes savent calculer les checksums TCP en hardware, dans mon cas, les paquets émis au final sur le réseau étaient corrects (on peut juste regretter que libpcap n'aie pas accès au vrai paquet).

Je suis donc parti à la recherche d'une option permettant de désactiver la gestion hardware des checksums TCP, et après avoir pas mal cherché dans les forums de geeks MacOS qui font du réseau (c'est pas la majorité), je suis tombé sur deux sysctl \o/:
net.link.ether.inet.apple_hwcksum_tx: 1
net.link.ether.inet.apple_hwcksum_rx: 1

Il y avait donc plus qu'à les mettre à 0 pour que le système se mette à les générer (et à les vérifier) au lieu de laisser la carte le faire. Je fais donc:
1007 root@khany:~> sysctl -w net.link.ether.inet.apple_hwcksum_tx=0
net.link.ether.inet.apple_hwcksum_tx: 1 -> 0
1008 root@khany:~> sysctl -w net.link.ether.inet.apple_hwcksum_rx=0
net.link.ether.inet.apple_hwcksum_rx: 1 -> 0
Et la c'est le drame : plus moyen d'ouvrir un terminal, plus moyen de faire sudo, la résolution de nom marche plus, plus aucune appli ne se lance. C'est un symptôme assez connu sur MacOS qui indique que le réseau est mort : le système passe son temps à se causer sur lui même sur 127.0.0.1 pour interroger NetInfo (une vieille réminisence de NextStep de 1990 qui résiste, on se plaint pas, ca pourrait être du XML et du SOAP) . Quand le réseau est mort, le reste va suivre assez vite. Si vous avez de la chance vous avez encore votre shell root ouvert et vous remettez les deux valeurs à 1. Si vous avez pas de chance vous faites un ON/OFF brutal.

Vous réfléchissez, vous recommencez prêt à remettre la valeur à 1, vous regardez ce que donne tcpdump -lnvv -i lo0 et vous vous apercevez que les checksums TCP calculés par MacOS sur Intel sont faux. Ils sont faux sur Ethernet, mais la carte les recalcule quand même, ce qui fait que vous gardez votre connectivité avec les autres machines. Ils sont faux aussi sur le loopack et comme par le deuxième sysctl vous avez demandé à les vérifier, tous les paquets sont rejetés. Ils sont sans doute faux pour un bête problème d'Endianness et de raccourci dans les calculs, j'avoue que je n'ai pas cherché _ou_ ça merdait.

J'ai posté ce bug avec sa description sur bugreport.apple.com le 1er Mai, on m'a attribué le bug #4532260. 5 jours plus tard j'ai reçu un mail me disant que mon bug était un duplicate d'un autre (comment le savoir ?) et que "After further investigation it has been determined that this is a known issue, which is currently being investigated by engineering." Depuis il y a eu 4 updates de systèmes, et le bug est toujours la dans MacOS 10.4.8.

Ce bug est grave parce qu'il montre qu'il y a des problèmes d'Endianness qui trainent dans le portage Intel. Il en est des plus faciles à contourner (j'en ai un autre sous le coude dont je vous parlerais), mais il y en a probablement qui ont des conséquences sur la sécurité. Il est grave aussi parce que en gros ça marche par miracle et que la qualité est pas là ... Ce que je n'ai pas encore compris, c'est pourquoi les checksums TCP sont corrects sur ppp ...

Pour finir, il n'est donc pas possible sur MacOS Intel de faire un système de détection d'intrusion réseau(NIDS) valide : il est en effet impossible de savoir si les paquets émis par la machine ont vraiment un checksum invalide ou pas, et il faut donc se résoudre à ça:
/* AT 20060501 Grrr
if (my_tcp_check(this_tcphdr, iplen - 4 * this_iphdr->ip_hl,
this_iphdr->ip_src.s_addr, this_iphdr->ip_dst.s_addr)) {
nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_HDR, this_iphdr,
this_tcphdr);
return;
} */
Autant dire que c'est dangereux, parce que quelqu'un de malin va balancer des paquets contenant des données vues comme normales, alors qu'elles ne seront pas acceptées par le système distant.

1 commentaire:

Anonyme a dit…

> un tunnel IP dans DNS

Oh, comment c'est possible ? Il y en a qui osent faire ça ? Je le crois pas...