Kernel AODV Proxy ARP

From YobiWiki
Revision as of 01:07, 26 February 2008 by <bdi>PhilippeTeuwen</bdi> (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Converted with HTML::WikiConverter::MediaWiki from my old phpwiki site


Utilisation de Proxy-ARP pour le projet KernelAodvReseauCitoyen

Nous allons encore une fois devoir hacker, cette fois en installant un Proxy-ARP sur mesure pour donner un coup de pouce au KernelAodvDhcpd.

Récapitulatif du problème:

cf KernelAodvDhcpd:
Si on délivre une <IP-RC du client> + netmask 255.255.255.255 + gw = <IP-RC du noeud> ça ne marche que pour les clients Windows car il y a une incohérence dans les paramètres fournis par le serveur DHCP: l'IP du gateway est hors du réseau (de taille /32) du client et on a besoin d'abord d'une route explicite vers le gateway.

Première idée:

Nous délivrons une configuration DHCP "cohérente" c-à-d <IP-RC du client> + netmask 255.0.0.0 + gw = <IP-RC du noeud> et nous rattrappons les dégâts générés c-à-d que lorsque le client va vouloir parler à une IP-RC quelconque, il va croire que la machine est dans son réseau donc dans son environnement immédiat et il va envoyer une ARP request.
L'idée est que le noeud réponde systématiquement aux requêtes ARP du client et le reste suivra naturellement.
Attention aux éventuels problèmes de communication entre 2 clients qui sont en vue directe, accrochés au même noeud ou à un noeud différent peu importe ou les problèmes entre le client et un autre noeud en vue directe

Sources d'information sur ARP et les proxy-ARP:

Outils de spoof

  • Dsniff sniffer by Dug Song includes a program named “arpredirect” to forge ARP replies.
    Tel quel il s'utilise ainsi:
    arpspoof [-i interf] [-t target] host
  • arp-sk
  • arptool.c

Implémentations possibles d'un Proxy-ARP:

Plusieurs solutions:

  • Utiliser le proxy-arp du kernel: echo 1 > /proc/sys/net/ipv4/conf/eth0/proxy_arp
    Dans le cas où les clients sont dans le subnet 10.0.0.0/8 tout comme les autres noeuds RC, cela se complique car nous n'avons qu'une interface et nous devons pouvoir filtrer de qui vient la ARP request avant de répondre (si l'ARP request vient d'un noeud voisin et non du client pas question de répondre si le noeud ne s'adressait pas à nous!)
    -> utiliser conjointement à de l'ARP filtering...?
    Le proxy_arp se base sur la table de routage pour décider de répondre ou non aux ARP requests.
    Pour que le proxy-ARP fonctionne, il doit exister à la fois une route vers la source sur l'interface correcte et une route vers la destination de l'ARP request sur une autre interface.
    Une solution simple consiste à créer une route vers lo:
    • route add <dest to spoof> lo
  • S'inspirer des Proxy ARP Scripts ?
    Cela revient à insérer des entrées dans la table ARP et les rendre publiques de la sorte:
    arp -s $IPADDR -i $INTERFACE -D $INTERFACE pub
    -s: IP destination d'une ARP request
    -i: interface sur laquelle on enverra les ARP replies
    -D: utiliser la MAC de cette interface
    pub: proxy-arp pour cette entrée
    Cela marche pour un petit nombre d'IP destinations d'ARP requests mais pas pour tout un réseau (le flag netmask n'est plus accepté dans les nouveaux kernels) et les IP spoofées sont sensées être accessibles via une autre interface.
  • Utiliser les outils de spoof décrits plus haut
    Problème de ces softs: tels quels ils fonctionnent pour spoofer UNE machine vis-à-vis de notre client par un ARP poisoning actif (envoi de ARP replies toutes les 2 secondes) or il est préférable de faire du ARP spoofing uniquement en réponse aux ARP requests du client surtout si nous devons spoofer un réseau complet or si le netmask est 255.0.0.0 le client émettra des ARP requests à la recherche de n'importe quel hôte de son réseau "local" c-à-d du réseau RC.

Comme on le voit, spoofer un réseau entier (de classe A!) n'est pas aisé.
Sans compter que même si on y arrive les risques de collision sont réels et non négligeables: toute situation où l'IP recherchée par un noeud ou client de l'environnement immédiat existe dans cet environnement immédiat -> collision d'ARP responses. Et il ne suffit pas que le noeud vérifie lui-même si cette IP est dans le voisinage car elle peut être cachée du noeud mais visible par celui qui fait la requête.

Idée testée lors du second essai de KernelAodvDhcpd: retour à une solution de type Peer-to-peer

En fait un netmask 255.255.255.255 ne marchait pas car le gateway était hors du sous-réseau du client et si on veut incorporer l'IP-RC du gateway dans le sous-réseau du client il faut donner come sous-réseau au client le réseau RC complet de classe A et cela engendre de nombreuses difficultés au niveau ARP.

Apportons une solution immédiate à ces problèmes de netmask et ARP et voyons comment corriger le tir une fois de plus car cette solution va elle aussi engendrer quelques soucis mais que nous espérons plus simples à résoudre.

Topologie P-t-P

L'idéal est une topologie peer-to-peer: le sous-réseau du client est /31 et ne comporte donc que 2 IP.
Une pour le client et l'autre pour son gateway.
Le client s'adressera donc toujours au gateway quelle que soit l'IP à atteindre.
Plus exactement le client utilisera l'adresse hardware (la MAC address) de son gateway mais il n'y a aucune raison pour le client utilise directement l'IP du gateway pour autre chose qu'une ARP request à la recherche de la MAC address de son gateway.
Le noeud devra donc simplement répondre aux ARP requests de son client à la recherche de son gateway par sa propre MAC address.

Risque de collision ARP?

Il y a bien un risque de collision ARP mais il est très très peu probable: l'IP du gateway pourrait être une IP-RC déjà utilisée.
Mais l'IP du gateway n'étant pas assignée au noeud le seul risque est si la machine possédant cette IP-RC est dans l'environnement immédiat du client. Le client recevrait alors 2 ARP responses différentes et pourrait utiliser le mauvais gateway.
Il faut donc que l'IP du gateway soit déjà une IP-RC et qu'elle soit dans l'environnement immédiat du noeud.
Pour rappel il y a toujours un risque de collision de 2 IP-RC au sein du réseau et ce risque est (même s'il est faible) nettement plus grand que le risque de collision ARP décrit ici.

Implémentation

L'IP du client est dictée par sa MAC address, c'est le principe-même des IP-RC.
On choisit un netmask, cela dicte de manière univoque l'IP du gateway:
<IP-GW> = <IP-CLIENT> XOR NOT <NETMASK>
Cela implique à nouveau un changement dans KernelAodvDhcpd...
Maintenant l'IP du gateway et l'IP réelle du noeud diffèrent, le noeud va devoir faire du proxy-arp vis-à-vis du client à la recherche de son gateway.

arp -s <IP-GW> -i <wifi-if> -D <wifi-if> pub

Ainsi on répond à toute ARP request à destination de l'IP du gateway.
Bien entendu nous aurons autant de gateways fictifs à proxifier que de clients.

Filtre ARP

Bien que le risque soit très faible qu'une telle ARP request arrive en provenance d'une autre machine que le client on peut mettre en place un filtre ARP pour ne répondre qu'au client.

Netmask /31 ou /30 ?

Petit rappel:
The network mask for an un-sub-networked IP network number is simply a dotted quad which has all the 'network bits' of the network number set to '1' and all the host bits set to '0'.

Le netmask le plus évident pour un réseau comportant 2 IP semble être 255.255.255.254
Mais cela amène des questions sur le choix de l'IP du gateway.
Il se peut que des cartes wifi issues du même lot portent des MAC addresses consécutives.
Il est donc préférable d'utiliser un autre netmask.
In principle, there is absolutely no reason to follow the above way of subnetworking where network mask bits are added from the most significant host bit to the least significant host bit. However, if you do not do it this way, the resulting IP numbers will be in a very odd sequence! This makes it extremely difficult for us humans to decide to which subnetwork an IP number belongs as we are not too good at thinking in binary (computers on the other hand are and will use whatever scheme you tell them with equal equanimity).
Par exemple en jouant sur le bit de poids fort de la partie de la MAC address qui sert à construire une IP-RC:
255.0b01111111.255.255 c-à-d 255.127.255.255 ou en jouant sur le bit suivant:
255.0b10111111.255.255 c-à-d 255.191.255.255, de quoi en dérouter plus d'un ;-)

Nous avons une seconde bonne raison de ne pas suivre la manière habituelle de créer un netmask:
En fait lorsqu'on crée un subnet, 2 adresses sont réservées, cf IP Subnetworking HOWTO:

  • l'adresse network
    A network number will always have the interface (host) bits of the address space set to 0
  • l'adresse broadcast
    Broadcast addresses for a network always have the interface (host) bits of the the address space set to 1

cf aussi RFC:1878
Pour notre subnet de 2 adresses cela ne laisse plus grand-chose une fois ces 2 IP réservées enlevées.
Il faut donc augmenter le subnet à 4 IP mais il faut prendre garde que l'IP-RC du client ne soit pas identique à l'adresse network ou broadcast du subnet.

Un netmask /30 est un netmask comortant 30 bits à 1 et 2 à 0
Nous avons donc 2 host bits ce qui donne 4 IP à répartir comme suit (IP client et gateway sont interchangeables):

  • 00: adresse network
  • 01: \ / IP-RC du client
  • 10: / \ IP du gateway
  • 11: adresse broadcast du client

Oui mais comment être sûr que les host bits de l'IP-RC du client seront bien 01 ou 10?
En prenant les host bits dans les 8 premiers bits de l'IP-RC car ils sont toujours les mêmes (10.X.X.X)
On doit donc prendre un des 2 bits "1" et un des 6 bits "0" du 10 = 0b00001010 pour constituer les host bits.
Nous avons 12 possibilités: (0|2|4|5|6|7 + 1|3)
En comptant les bits depuis le LSB=bit0

 +-------+-----------------+-----+-----+-----+-----+-----+-----+
 |       |    bits 0&1     | 0&3 | 2&1 | 2&3 | ... | 6&3 | ... |
 +-------+-----------------+-----+-----+-----+-----+-----+-----+
 |Netmask| 252.255.255.255 | 246 | 249 | 243 | ... | 183 | ... |
 |Network|   8.  X.  X.  X |   2 |   8 |   2 | ... |   2 | ... |
 |Gateway|   9.  X.  X.  X |   3 |  12 |   6 | ... |  66 | ... |
 | IP-RC |  10.  X.  X.  X |  10 |  10 |  10 | ... |  10 | ... |
 | Bcast |  11.  X.  X.  X |  11 |  14 |  14 | ... |  74 | ... |
 +-------+-----------------+-----+-----+-----+-----+-----+-----+

De plus se servir des 8 premiers bits pour nos host bits a d'autres avantages:

  • Plus de collision ARP possible car le gateway aura toujours une IP hors RC.
  • Debug plus facile car on repère tout de suite l'IP d'un gateway d'un client ou de son IP de broadcast.
  • Implémentation plus facile car on construit l'IP du gateway très facilement à partir de l'IP-RC du client.

En principe le client n'a pas à chercher à joindre son gateway par son IP pour autre chose qu'une requête ARP.
Sinon le noeud recevra un paquet et le forwardera vers Internet puisque l'IP du gateway correspond à une IP publique!
Cela ne devrait pas prêter à conséquence mais il est plus sage que le noeud ait une règle Netfiler pour jeter ces paquets.
Un souci qu'il nous reste est un éventuel broadcast de la part d'un client (Windows est par exemple très doué pour broadcaster à tous vents: NetBEUI, UPnP,...)
Le client va forger un paquet broadcast avec son IP broadcast qui est en fait une autre IP publique elle aussi.
De plus la MAC de destination sera FF:FF:FF:FF:FF:FF ce qui signifie que toutes les machines dans l'environnement immédiat du client recevront ce paquet! Et si certaines d'entre elles acceptent de router le paquet,...
En principe, ce qui nous sauve c'est que d'une part le TTL d'un paquet broadcast est sensé être égal à 1 (et les voisins renverraient des erreurs ICMP??) et d'autre part que le paquet utilisant la MAC broadcast, il pourrait bien être reconnu comme étant effectivement un paquet broadcast même par les voisins qui ont une autre IP broadcast et donc le paquet ne serait pas routé (un routeur ne route pas de broadcast) tout cela est à vérifier...

Remarque: d'après ipcalc, un netmask autre que des "1" puis des "0" est illégal.
Il faudra s'assurer si tous les clients acceptent bien de tels masques ou non.

Conclusions:

cf les tests faits lors du second essai de KernelAodvDhcpd:

  • Linux refuse lui aussi un netmask autre que des "1" puis des "0".
  • Le troisième essai part dans une autre direction: on choisit un autre subnet pour les clients et on bricole.
  • On utilisera effectivement une règle Netfilter pour récupérer les paquets du client destinés au gateway (et on s'appropriera ces paquets plutôt que les jeter, on ne sait jamais qu'un client DHCP susceptible n'aime pas que son gateway ne réponde pas)
  • On n'a plus besoin de s'occuper des broadcasts puisqu'ils devraient être reconnus comme tels par les voisins.
  • On utilise une des méthodes de proxy-arp décrites sur cette page: le proxy-arp du kernel et l'ajout de routes adéquates.