Kernel AODV DHCPd

From YobiWiki
Revision as of 22:32, 24 November 2010 by <bdi>PhilippeTeuwen</bdi> (talk | contribs) (Reverted edits by Etegohy (Talk) to last revision by PhilippeTeuwen)
(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


Modification du code d'un serveur DHCP pour allouer des IP "RC" pour le projet KernelAodvReseauCitoyen

Infos sur le DHCP


Pour rappel les IP "RC" sont des IP du subnet 10.0.0.0/8 dont les trois derniers bytes sont égaux aux trois derniers bytes de la MAC address d'un noeud RC après conversion HEX -> DEC, cf ReseauCitoyen:ExtensionPlanAdressage

ReseauCitoyen:PhilippeVanhaesendonck a réalisé cette modification dans le udhcpd de la busybox et je l'ai portée sur le paquet Debian: cf également ReseauCitoyen:PatchesUdhcpd


Premier essai:

Le démon udhcpd configure le client comme suit:

  • IP basé sur la MAC address
  • NETMASK = 255.255.255.255 car le client ne peut pas parler directement aux autres noeuds
  • GATEWAY = IP du noeud

Conclusions:

  • kernel_aodv n'empêche pas le démon DHCP de fonctionner, c'est déjà ça
  • le dhcpd délivre des adresses IP RC comme voulu
  • Mais: les routes du client linux ne sont pas correctes (sont inexistantes tout simplement)
    car le DHCP server envoie en fait les mêmes instructions que:
    ifconfig ethX <my-RC-ip> netmask 255.255.255.255
    route add default gw <noeud>
    Mais Linux refuse d'insérer cette route car il ne sait pas sur quelle interface se trouve <noeud>.
    Il faudrait lui donner d'abord cette route:
    route add <noeud> <wifi dev>
    Mais ce n'est pas possible en dépit des nombreuses options supportées par DHCP, cf RFC:2132
    L'autre méthode serait de donner un netmask 255.0.0.0 et une route style
    route add -net 10.0.0.0 netmask 255.0.0.0 gw <noeud>
    mais les options supoprtées par DHCP ne permettent pas de créer de routes statiques vers des réseaux mais uniquement vers des hôtes.
  • Pour un client Windows XP, j'ai testé, ça marche (cf aussi http://www.southwestern.edu/ITS/netreg/archive/0884.html)
  • Pour un client Mac ça ne marche pas, paraît-il (cf le même lien)
  • Pour un client PhilipsStreamium ça ne marche pas

Cette solution n'est pas acceptable car elle ne fonctionne que pour des clients Windows
Oui, je sais, c'est déjà ça diront certains, surtout ceux qui n'ont qu'une machine qui tourne sous Windows mais ce n'est même pas garanti que cela fonctionne pour toutes les versions de Windows.

Second essai:

Utiliser le serveur DHCP mais avec cette fois un masque tel que le gateway fasse partie du sous-réseau du client (par exemple 255.0.0.0) afin que le gateway soit accepté comme tel.
Et ajouter un KernelAodvProxyArp car le client fera des ARP request sur toute IP qu'il croit être dans son environnement immédiat.

Une solution possible qui nécessite un second patch du udhcpd est présentée sur KernelAodvProxyArp.
Il faut implémenter les fonctionnalités suivantes dans le serveur DHCP:

  • if (mac_lease=='yes' AND mac_lease_magic_gw=='yes') then opt router=IP-RC XOR NOT mac_lease_mask

Le démon udhcpd configure alors le client comme suit:

  • IP = 10.M.A.C (basé sur la MAC address du client)
  • NETMASK = 252.255.255.255
  • GATEWAY = 9.M.A.C (basé aussi sur la MAC du client!)

Pour le proxy-ARP nous utiliserons ceci:

  • echo 1 > /proc/sys/net/ipv4/conf/eth1/proxy_arp
  • route add 9.M.A.C lo

Donc un pseudo-gateway et une pseudo-route par client

Conclusions:

Ô rage, ô désespoir!
Pour un client Windows, ça marche.
Pour un client Linux, ça ne marche pas car ifconfig refuse un netmask 252.255.255.255!!!
Là j'avoue être quelque peu sidéré...

Troisième essai:

Là il faut se faire à l'idée qu'on se contentera d'assigner une IP de cette manière:

  • IP = X.C.L.I (basé sur la MAC address du client)
  • NETMASK = 255.0.0.0
  • GATEWAY = X.N.O.D (basé sur la MAC du noeud RC)

Pour le proxy-ARP nous utiliserons ceci:

  • echo 1 > /proc/sys/net/ipv4/conf/eth1/proxy_arp
  • route add X.N.O.D lo
  • route add X.C.L.I eth1

Donc un seul pseudo-gateway et une pseudo-route vers le gateway pour tous les clients mais aussi une pseudo-route vers le client pour chacun.
Cela signifie outre les probs de routage qu'on sacrifie un des espaces X.0.0.0/8!
cf http://www.iana.org/assignments/ipv4-address-space pour désigner notre victime. Quoique il y a peut-être moyen de router cet espace par ARPproxy et beaucoup de gymnastique...
Donc nous devons choisir X pour utiliser un réseau de classe A: X.0.0.0
Par rapport aux solutions précédentes, cette fois-ci les clients ne sont plus dans le même subnet que les noeuds RC, il faudra donc user et abuser de iptables pour corriger le tir.

  • Pour les paquets du client vers le pseudo-gateway (pas pour que le client puisse joindre son gateway car on n'en a pas besoin mais plutôt pour éviter que le noeud ne cherche cette pseudo-IP sur AODV)
    iptables -t nat -A PREROUTING -s 1.C.L.I -d 1.N.O.D -j DNAT --to-destination 10.N.O.D
  • Pour les paquets qui transitent vers le client:
    iptables -t nat -A PREROUTING -d 10.C.L.I -j DNAT --to-destination 1.C.L.I
  • Pour les paquets générés localement à destination du client:
    iptables -t nat -A OUTPUT -d 10.C.L.I -j DNAT --to-destination 1.C.L.I
    Attention il faut avoir autorisé le NAT sur les paquets locaux lors de la compilation du noyau: CONFIG_IP_NF_NAT_LOCAL=y
  • Pour les paquets du client vers le nuage AODV:
    iptables -t nat -A POSTROUTING -s 1.C.L.I -j SNAT --to-source 10.C.L.I

Et il faudra injecter non seulement l'IP 10.C.L.I dans AODV mais aussi l'IP réellement utilisée pour le routage: 1.C.L.I

Conclusions:

Windows refuse X=0 ou plutôt dans ce cas il n'accepte pas le gateway et se prend lui-même comme gateway, allez comprendre.
Utilisons alors X=1 (dixit IANA: 001/8 Sep 81 IANA - Reserved)
Nous arrivons à une configuration distribuée par DHCP qui devrait être acceptée par tous les devices possibles et imaginables qui ont un client DHCP.
Récapitulons:

  • Pour le client, l'IP du client est 1.M.A.C (les 3 derniers bytes de son IP étant égaux aux 3 derniers bytes de sa MAC address)
  • Pour le noeud, l'IP du client peut être indistinctement 1.M.A.C ou 10.M.A.C mais en interne seule l'IP 1.M.A.C est utilisée pour le routage.
  • Pour les autres noeuds, l'IP du client est 10.M.A.C (bien que par effet de bord l'IP 1.M.A.C soit présente dans le nuage AODV)
  • Pour les autres clients du même noeud, ils peuvent se parler via les IP 10.x.x.x en se servant du noeud comme relai mais ils devraient également être capables de se parler directement (pour autant qu'ils soient à vue) via les IP 1.x.x.x.

En fait le routage aurait pu être simplifié si netfilter permettait des règles telles que:

  • iptables -t nat/mangle -A PREROUTING -s 1.M.A.C -j SNAT --to-source 10.M.A.C
  • iptables -t nat/mangle -A POSTROUTING -d 10.M.A.C -j DNAT --to-destination 1.M.A.C

Ainsi le noeud aurait eu la même vue que les autres noeuds et on n'aurait pas besoin d'injecter 1.M.A.C dans sa table AODV.

Patch supplémentaire:

Le démon glue doit détecter l'arrivée potentielle d'un client.
Il peut le faire en surveillant les écritures de sendACK via syslog dans /var/log/messages

  • Jan 1 22:50:34 mercure udhcpd: sending ACK to 1.34.43.104

Mais cela peut poser problème notamment dans les noeuds embarqués qui ne génèrent pas de logs locaux.
Pour faciliter la tâche du démon glue, nous allons ajouter à la fonction d'envoi d'un DHCP ACK le même mécanisme d'appel d'une commande externe que notify_file (Execute FILE after the lease information is written. By default, no file is executed.)
Cela s'appelera notify_ack (Execute FILE after an ACK was sent to a client. By default, no file is executed.)
Nous ajoutons donc un code très similaire à notify_file dans la fonction sendACK (dans serverpacket.c), l'essentiel étant:


if (server_config.notify_ack) {
       sprintf(buf, "%s %s", server_config.notify_ack, inet_ntoa(addr));
       system(buf);
}

Résultat:


Autres pistes non explorées: