Retrouvez cet article dans : Linux Magazine 108
Lorsque je suis en déplacement pour plusieurs jours, je suis toujours confronté au même problème : trouver un accès Wireless ouvert. Si très rarement il m’arrive de trouver un Hotspot FON, le plus souvent, je ne dois mon salut qu’à l’inconscience de M. et Mme Michu qui ont fait l’acquisition d’un access point Linksys et l’ont simplement laissé dans sa configuration initiale : ouvert et admin/admin pour l’administration à distance. Si cela peut faire sourire, au regard des nouvelles lois en discussion dans notre beau pays [1], M. et Mme Michu sont responsables de l’accès au Net qu’ils fournissent en méconnaissance de cause.
Pour toutes ces raisons, et parce que " propose à ton prochain ce que tu aimerais qu’on te propose " (Évangile selon Pinpin, ch. 5, al. 8), je nourris depuis un moment déjà le fantasme de créer un Hotspot que j’espère relativement bien construit, et transformer ainsi mon appartement en datacenter pour le plus grand bonheur de ma petite famille.
|
1 |
Cahier des charges : tu ne shareras point |
Partager sa connexion, oui, mais pas n’importe comment. Voici le cahier des charges que je me suis imposé :
● différencier les réseaux wireless et domestique ;
● ne partager qu’une partie de ma bande passante ;
● n’autoriser que quelques ports ;
● loguer l’activité, puisque la loi m’y oblige, tout en respectant l’anonymat de mes usagers ;
● interdire l’accès aux sites suspects, dangereux, pornographiques et consorts ;
● " monitorer " tout ce qui peut l’être.
Ce qui se traduit techniquement par, respectivement :
● un VLAN par réseau, routables entre eux, mais filtrés par access-list ou firewalling ;
● des règles de QoS sur le réseau Wifi public ;
● des access-list par port (switch) et firewalling par port (socket) ;
● l’utilisation massive de SNMP et des capacités d’information des outils déployés ;
● la mise en place d’un proxy HTTP filtrant ;
● l’utilisation d’un système de tracé souple et fiable.
Enfin, pour mettre en pratique ce plan, nous avons à notre disposition le matériel de récup’ suivant :
● un switch manageable muni de diverses possibilités ;
● une pizza-box Sun Netra X1 à 400 MHz dotée de 512 MB de mémoire vive ;
● une machine Intel à 900 MHz dotée elle aussi de 512 MB de mémoire vive ;
● deux access points à bas prix.
Y’a du boulot.
|
2 |
Le routeur : les mains dans le fumier |
La première partie de notre périple est la seule qui n’impliquera pas de logiciels libres, loin s’en faut, puisqu’il va s’agir de configurer un switch manageable dont on peut toujours rêver d’avoir les sources un jour… En l’occurrence, il s’agit d’un switch Foundry ServerIron XL que j’ai obtenu à moindres frais voilà quelques années. Les manipulations que nous allons voir seraient similaires sur un switch de type Cisco Catalyst ou tout autre équipement de ce type supportant VLAN, Layer 3 et access-list étendues par port.
Avant tout, il est donc nécessaire de distinguer les réseaux Wireless et privé. Cette distinction se fait par port :
|
vlan 1 name DEFAULT-VLAN by port no spanning-tree router-interface ve 1 ! vlan 2 name EMPIRE-NET by port untagged ethe 9 to 16 no spanning-tree router-interface ve 2 ! |
Arrêtons-nous un instant sur cette syntaxe peu commune. Sur ce type de matériel, la configuration initiale propose un VLAN par défaut, le VLAN numéro 1. Tout port du switch qui ne sera pas explicitement affecté à un autre VLAN fera de facto partie du VLAN 1. Ainsi, sur notre switch 16 ports, puisque les ports 9 à 16 appartiennent au VLAN 2, les ports 1 à 8 sont affectés au VLAN 1. Nous ne souhaitons pas utiliser le protocole Spanning Tree [2] et les interfaces de nos VLAN ne seront pas taguées [3]. Le VLAN 1 représentera notre réseau domestique privé, le VLAN 2 sera le réseau Wifi public.
Nous allons utiliser le switch comme routeur virtuel entre ces VLAN. Nous déclarons donc une interface de type ve, ou Virtual Ethernet, qui portera une IP représentant la passerelle de nos réseaux. Déclarons tout de suite ces interfaces virtuelles :
|
interface ve 1 ip address 192.168.100.254 255.255.255.0 ! interface ve 2 ip address 192.168.200.254 255.255.255.0 |
Pour activer l’IP forwarding entre ces réseaux, il sera nécessaire d’entrer la commande ip forward.
Pour finir, puisque nous avons fait en sorte que ces réseaux puissent se voir, nous allons appliquer des access-list étendues aux ports où seront connectés nos invités :
|
interface e 9 ip access-group wifiout in ! ip access-list extended wifiout permit ip any host 192.168.200.1 deny ip 192.168.200.0/24 192.168.100.0/24 permit tcp any any eq http permit udp any any eq bootps permit tcp any any eq ssh |
Traduction, nous appliquons au port 9 une access-list nommée " wifiout " et elle s’appliquera en entrée du port. En effet, ce qui " sortira " de nos access points (AP) " rentrera " dans le port 9. La déclaration de l’access list est relativement compréhensible : 192.168.200.1 est la passerelle officielle du réseau Wifi. On autorise donc n’importe quel type d’accès IP en provenance des AP vers cette IP.
On refuse tout type d’accès IP vers le réseau domestique, et, enfin, on autorise de n’importe où vers n’importe où les protocoles HTTP, DHCP Server et SSH. Notez que l’ordre de cette liste est important et exclusif. Ainsi, l’invité ne pourra pas établir de connexion HTTP vers une machine du réseau 192.168.100.0/24, et aucun autre protocole que ceux mentionnés ne pourront transiter.
Nous en avons fini avec cette partie non reluisante de l’architecture. Notez que si nous n’avions pas disposé de ce type de matériel, mais d’un simple switch non manageable, il aurait été tout à fait possible de réaliser une architecture similaire en utilisant les fonctionnalités de marquage 802.1Q [3] de nos OS du bien.
|
3 |
Mise en place du NAT : sur le pont, moussaillon ! |
Dans notre architecture, l’accès WAN sera fourni par une box ADSL tout à fait classique. Pour NATter le trafic, nous utiliserons une de nos reliques, une brave SUN Netra X1 récemment migrée sous OpenBSD 4.3. Cette machine ne réalisera pratiquement aucune autre tâche que le routage public. Ainsi, le fichier /etc/rc.conf.local devra désactiver la quasi-totalité des services démarrés par défaut par /etc/rc :
|
pf="" sendmail_flags=NO inetd=NO lpd_flags=NO |
|
named_flags="-t /var/named -u named" dhcpd_flags="" snmpd_flags="" |
Seuls pf, Bind, dhcpd et snmpd seront démarrés au boot. Bind démarrera en mode chrooté et servira de DNS maître dans notre réseau.
Notre X1 est munie de deux interfaces, la première est raccordée au switch et dispose évidemment d’une IP fixe. On ajoute également une route vers le réseau Wireless. La seconde est reliée à la box ADSL qui lui fournit une IP publique via dhcp :
|
# /etc/hostname.dc0 inet 192.168.100.253 255.255.255.0 NONE !route add -net 192.168.200.0/24 192.168.100.254 # /etc/hostname.dc1 dhcp |
Nous pouvons maintenant donner accès au monde à nos réseaux privés à l’aide de simples règles de NAT :
|
# /etc/pf.conf int="dc0" ext="dc1" nat on $ext from 192.168.100.0/24 to any -> $ext nat on $ext from 192.168.200.0/24 to any -> $ext # on s’assure qu’aucun accès HTTP en provenance du # réseau Wifi n’est issu d’ailleurs que du proxy pass in quick on $int proto tcp from 192.168.200.1 to any port 80 block in on $int proto tcp from 192.168.200.0/24 to any port 80 Que l’on applique simplement : # pfctl -vv -f /etc/pf.conf |
Les serveurs DNS et DHCP bénéficient tous deux de configurations tout à fait banales. Dans Bind, nous autorisons les requêtes récursives en provenance de nos réseaux :
|
acl imilnet { 192.168.100.0/24; 192.168.200.0/24; }; acl clients { localnets; imilnet; ::1; }; options { version "I CAN HAS A VERSHUN ?"; listen-on { any; }; listen-on-v6 { any; }; allow-recursion { clients; }; }; |
Nous déclarons la zone maître qui régit les domaines du réseau Wifi :
|
zone "empire-network.net" { type master; file "master/empire-network.net"; }; |
Et gérons les reverses de cette zone :
|
zone "200.168.192.IN-ADDR.ARPA" { type master; file "master/192.168.200.rev"; }; |
Les deux zones maître sont des plus classiques :
|
# master/empire-network.net $ORIGIN . $TTL 3600 ; 1 hour empire-network.net IN SOA ns1.empire-network.net. imil.imil.net. ( 2008042603 ; serial 21600 ; refresh (6 hours) 3600 ; retry (1 hour) 604800 ; expire (1 week) 172800 ; minimum (2 days) ) NS ns1.empire-network.net. A 192.168.200.1 MX 5 mail.gcu.info. $ORIGIN empire-network.net. ns1 A 192.168.100.252 proxy A 192.168.200.1 wrt1 A 192.168.200.2 wrt2 A 192.168.200.3 # master/192.168.200.rev $TTL 3600 @ IN SOA ns1.empire-network.net. imil.imil.net. ( 2008050902 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 604800 ) ; Negative Cache TTL ; @ IN NS ns1.empire-network.net. 1 IN PTR proxy.empire-network.net. 2 IN PTR wrt1.empire-network.net. 3 IN PTR wrt2.empire-network.net. |
Aucune originalité non plus dans la configuration du serveur DHCP domestique qui se contentera d’attribuer des IP aux machines du réseau privé dans la plage d’adresses 192.168.100.100 – 200 :
|
# /etc/dhcpd.conf.orig shared-network PRIVATE-NET { option domain-name "mondomaineprive.priv"; option domain-name-servers 192.168.100.252; subnet 192.168.17.0 netmask 255.255.255.0 { option routers 192.168.100.254; range 192.168.100.100 192.168.100.200; } } |
Notons enfin l’arrivée dans OpenBSD 4.3 d’un démon SNMP maison. Il ne s’agit pas d’un fork de Net-SNMP, mais bien d’une écriture from scratch. Dans l’immédiat, nous garderons la configuration initiale, nous changerons simplement la valeur listen_addr afin que le démon écoute sur l’interface dc0. Ce paramétrage sera suffisant pour obtenir les informations intéressantes sur le système : utilisation des interfaces, charge et occupation mémoire.
|
4 |
Routeur et proxy : reviens gamin ! C’était pour rire ! |
Attaquons-nous maintenant à l’équipement principal de notre architecture : le routeur du réseau Wireless. Nous utiliserons pour cette tâche un " vieux " PIII 900 sous NetBSD 4.0. Cette machine fournira les services suivants :
● serveur DNS cache pour les invités : Bind ;
● serveur DHCP : ISC dhcpd ;
● proxy http : Squid ;
● serveur http : lighttpd ;
● firewalling et QoS : pf ;
● SNMPd : Net-SNMP.
La seule particularité du serveur DNS réside dans son mode passif. Il est configuré en forwarder, ce qui implique d’ajouter aux options :
|
options { directory "/etc/namedb"; query-source address * port 53; allow-recursion { localhost; localnets; }; forward first; forwarders {192.168.100.252;}; }; |
Le serveur dhcpd bénéficie d’une configuration similaire au serveur DHCP privé :
|
ddns-update-style none; # nous n’utiliserons # pas de mise à jour automatique # du DNS # on réduit à une heure le délai de réinterrogation # du serveur et la réattribution automatique default-lease-time 3600; max-lease-time 3600; shared-network EMPIRE-NET { option domain-name "empire-network.net"; option domain-name-servers 192.168.200.1; subnet 192.168.200.0 netmask 255.255.255.0 { option routers 192.168.200.1; range 192.168.200.100 192.168.200.120; } } |
Le démarrage automatique de ces démons est réalisé en ajoutant au fichier /etc/rc.conf :
|
named=YES named_chrootdir="/var/chroot/named" dhcpd=YES dhcpd_flags="-q" |
Passons à l’un des composants-clés, Squid. Ce dernier s’installe depuis pkgsrc :
|
# cd /usr/pkgsrc/www/squid && \ make install clean |
Il existe plusieurs façons de déployer un proxy HTTP dans ce type d’environnement. Depuis la version 2.6, on l’utilise en mode transparent en remplaçant l’option par défaut http_port 3128 par la directive suivante :
|
http_port 127.0.0.1:3128 transparent |
puis en plaçant une règle de redirection à l’aide de pf :
|
rdr on $int inet proto tcp from any to ! $int port www -> 127.0.0.1 port 3128 |
Seulement voilà, il m’apparaissait important d’avertir l’invité des conditions d’utilisation du réseau sans fil que je mets gracieusement à sa disposition. Nous n’utiliserons donc pas le mode transparent de Squid, mais placerons malgré tout une règle de redirection, qui enverra l’invité sur un portail captif lui expliquant comment configurer son navigateur, pour utiliser le proxy du réseau sur lequel il s’est connecté. Nous y reviendrons.
À la configuration par défaut de Squid, nous ajoutons les ACL suivantes :
|
# on autorise les réseaux qui composent notre architecture acl empire_network src 192.168.200.0/24 acl private src 192.168.100.0/24 # on déclare une ACL dédiée pour les accès SNMP acl snmpcommunity snmp_community convisnmp # et on s’assure qu’aucun trafic nauséabond ne transitera acl sale browser MSIE acl sale browser ^Gator acl windowsupdate dstdomain .windowsupdate.com acl windowsupdate dstdomain .windowsupdate.microsoft.com |
Et les définitions d’accès associées :
|
http_access deny sale http_access deny windowsupdate http_access allow empire_network http_access allow imil_net http_access deny all snmp_port 3401 snmp_access allow snmpcommunity |
Reste à automatiser le démarrage du proxy grâce à la directive suivante à placer dans /etc/rc.conf :
|
squid=YES |
Nous pouvons alors démarrer Squid à l’aide de la commande :
|
# /etc/rc.d/squid start |
Nous pouvons tester le fonctionnement de ce simple proxy en renseignant les champs HTTP Proxy et Port dans les préférences de Firefox par exemple. Dans notre cas, l’adresse sera 192.168.200.1 et le port 3128.
Une des raisons majeures pour lesquelles il est souhaitable de faire transiter l’invité par un proxy HTTP, c’est évidemment de s’assurer qu’il ne profite pas de cet accès providentiel pour remplir son disque dur de HOT XXX TEEN P0RN. S’il est utopique d’imaginer qu’on bloquera l’intégralité de ce pourquoi est fait Internet (souvenez vous, " the Internet is for porn "), nous pouvons malgré tout minimiser les dégâts à l’aide de SquidGuard [4].
SquidGuard est un redirecteur d’URL. En vérifiant la présence de l’URL visitée dans ses blacklists, il permet de rediriger le visiteur indélicat vers une page le prévenant qu’il tente de visualiser un contenu non autorisé sur ce réseau.
Il est bien entendu présent dans pkgsrc. Son installation est triviale :
|
# cd /usr/pkgsrc/www/squidGuard/ && make install clean |
Son activation s’effectue en ajoutant la ligne suivante dans le fichier de configuration de Squid :
|
url_rewrite_program /usr/pkg/bin/squidGuard -c /usr/pkg/etc/squid/squidGuard.conf |
Son fichier de configuration, /usr/pkg/etc/squid/squidGuard.conf, est bien structuré, et c’est dans ce dernier que nous allons annoncer les catégories interdites :
|
dbhome /home/squidGuard/blacklists logdir /var/squid/logs dest ads { domainlist ads/domains urllist ads/urls } dest porn { domainlist porn/domains urllist porn/urls } dest warez { domainlist warez/domains urllist warez/urls } dest hacking { domainlist hacking/domains urllist hacking/urls } dest aggressive { domainlist aggressive/domains urllist aggressive/urls } dest violence { domainlist violence/domains urllist violence/urls } dest suspect { domainlist violence/domains urllist violence/urls } acl { default { pass !aggressive !violence !hacking !ads !porn !warez !suspect all redirect http://proxy.empire-network.net/redirect.php?clientaddr=%a&clientname=%n&clientuser=%i&clientgroup=%s&targetgroup=%t&url=%u } } |
Dans cette configuration, comme on peut facilement le deviner, on accepte tous les contenus sauf aggressive, violence, hacking, ads, porn, warez et suspect. Pour chaque catégorie, on spécifie le chemin relatif à dbhome dans lequel on trouvera la liste des domaines et des URL. Enfin, on déclare une adresse de redirection vers laquelle le visiteur sera dirigé s’il tente d’accéder à l’une de ces catégories. Notons que SquidGuard place un certain nombre de variables que l’on peut passer à sa page de redirection. Ainsi, mon fichier redirect.php contient le " code " suivant :
|
<html> <body> <strong><?php echo $_GET[‘url’]; ?></strong> est classifié <strong><?php echo $_GET[‘targetgroup’]; ?></strong> <br /><br /> La catégorie du site que vous essayez de visualiser est bloquée.<br /> La tentative d’accès est enregistrée. </body> </html> |
Il ne reste plus qu’à générer nos fameuses blacklists. Nous réaliserons cette opération à l’aide d’un script, getlists.sh, proposé dans la FAQ de SquidGuard. Ce script a deux avantages majeurs. Il se cron tout à fait bien et permet ainsi de garantir la fraîcheur des blacklists, mais il tire en plus profit de deux listes maintenues, celle de SquidGuard évidemment, mais également la célèbre liste de l’Université de Toulouse.
Comme on peut s’en douter, le script a été écrit sous GNU/Linux, et quelques petits ajustements sont nécessaires. Aussi, veillez à remplacer toutes les occurrences de wc –lines par wc -l, mais également les valeurs des variables SQUID et SQUIDGUARD par, respectivement, /usr/local/squid/sbin/squid et /usr/local/bin/squidGuard. Enfin, renseignez la variable BLACKDIR non pas avec la valeur de dbhome comme on peut le lire ici ou là, mais avec le répertoire parent de dbhome, soit dans notre cas /home/squidGuard.
En fonction de la puissance de la machine, l’exécution de getlists.sh peut prendre de quelques secondes à quelques minutes. Nous pouvons alors vérifier le bon fonctionnement de notre attrape-pervers de cette façon :
|
echo "http://www.hotteensex.com 192.168.200.1/ - - GET" | \ squidGuard -c /usr/pkg/etc/squid/squidGuard.conf $ http://proxy.empire-network.net/redirect.php?clientaddr=192.168.200.1&clientname=&clientuser=&clientgroup=default&targetgroup=porn&url=http://www.hotteensex.com 192.168.200.1/- - - |
Tremble, pédophile nazi !
Squid/SquidGuard en place, il nous faut nous assurer que notre visiteur sera redirigé vers une page d’information lui expliquant la marche à suivre pour poursuivre son périple. Nous réalisons ce tour de passe-passe à l’aide d’une règle pf :
|
int="fxp0" rdr on $int inet proto tcp from any to <empire_guests> port www -> 127.0.0.1 port 80 |
Évidemment, pour que tout ce joli dispositif fonctionne correctement, il est impératif d’installer un serveur HTTP quelconque. Par souci d’économie et parce que j’ai appris à l’adorer, nous jetterons notre dévolu sur lighttpd, dont l’installation n’est pas plus compliquée qu’un :
|
# cd /usr/pkgsrc/www/lighttpd && make install # echo lighttpd=YES >> /etc/rc.conf |
Nous nous cantonnerons à renseigner/décommenter les valeurs suivantes :
|
# [...] "mod_redirect", "mod_access", "mod_cgi", "mod_accesslog" ) # [...] server.document-root = "/home/imil/www/empirenet" server.errorlog = "/home/imil/logs/lighttpd.error.log" index-file.names = ( "index.php", "index.html", "index.htm", "default.htm" ) # [...] $HTTP["host"] != "proxy.empire-network.net" { url.redirect = ( ".*" => "http://proxy.empire-network.net" ) } |
|
# [...] cgi.assign = ( ".pl" => "/usr/pkg/bin/perl", ".cgi" => "/usr/pkg/bin/perl", ".php" => "/usr/pkg/libexec/cgi-bin/php" ) |
Ce qui aura pour effet :
● de rediriger vers le portail, quelle que soit l’URL tapée si le host ne correspond pas au véritable host qui héberge le serveur http ;
● de traiter les pages .php comme des CGI qui seront exécutés par /usr/pkg/libexec/cgi-bin/php.
Et ce dernier point implique… qu’il faut également installer PHP en mode CGI sur notre serveur. On spécifie tout d’abord que nous souhaitons que le package php supporte les modes cgi et fastcgi :
|
# echo "PKG_OPTIONS.php5=cgi fastcgi" >> /etc/mk.conf |
Puis, on installe le package comme à l’accoutumée :
|
# cd /usr/pkgsrc/lang/php5 && make install clean |
Nous pouvons alors démarrer lighttpd :
|
# /etc/rc.d/lighttpd start |
Pour parfaire notre passerelle publique, nous devons nous assurer que les invités ne se gaveront pas de l’intégralité de notre précieuse bande passante. Là encore, c’est grâce à pf que nous allons insérer de simples règles de QoS.
|
int="fxp0" table <empire_guests> { 192.168.200.0/24, ! 192.168.200.1, ! 192.168.200.2, ! 192.168.200.3 } altq on $int cbq bandwidth 28Mb queue { empirenet_in, empirenet_out } queue empirenet_in bandwidth 2Mb priority 1 cbq(default) queue empirenet_out bandwidth 128Kb priority 7 rdr on $int inet proto tcp from any to <empire_guests> port www -> 127.0.0.1 port 80 pass in on $int from any to <empire_guests> queue empirenet_in pass out on $int from <empire_guests> to any queue empirenet_out |
Nous utilisons ALTQ, intégré dans pf depuis OpenBSD 3.3, pour limiter la bande passante disponible pour nos clients. Avant tout, nous renseignons une table, empire_guests, avec le pool d’adresses qui sera soumis à la politique stricte en excluant la passerelle et les deux AP.
Nous appliquons ensuite à l’interface fxp0 l’algorithme CBQ ou Class Based Queuing (probablement le plus utilisé) et indiquons la bande passante théoriquement fournie par notre Box ADSL. Nous déclarons ensuite les queues associées, soit 2 Mbps entrants et 128 Kbps sortants, afin que les clients potentiels bénéficient d’une connectique raisonnable sans que cela impacte trop notre propre utilisation.
Enfin, nous mettons effectivement en œuvre le contrôle de trafic à l’aide de deux règles pass auxquelles on ajoute les queues associées. Il suffit alors de recharger les règles pf à l’aide de la commande pfctl -f /etc/pf.conf et nous voilà assurés de pouvoir continuer à télécharger de la musique libre sur des trackers légaux à presque pleine vitesse.
Finalement, pour avoir une vision précise de l’utilisation de cette passerelle, nous installons Net-SNMP depuis pkgsrc :
|
# cd /usr/pkgsrc/net/net-snmp && make install clean |
Ce démon SNMP dispose d’une place de choix dans notre réseau. Aussi, nous allons prendre un soin particulier pour sa configuration.
Avant tout, assurons-nous de vérifier l’état des démons fonctionnant sur le serveur :
|
proc squid 10 1 proc dhcpd 2 1 proc named 2 1 proc lighttpd 20 1 |
Il sera également agréable de connaître son load average :
|
load 5 5 5 |
Vient ensuite le moniteur que nous allons scruter avec angoisse, le nombre de leases dhcp en cours. En effet, c’est notre passerelle qui fournira les IP aux invités. Ainsi, en vérifiant l’état du serveur DHCP, nous saurons quelle est l’utilisation ponctuelle, modulo la durée des leases, du réseau.
Nous utiliserons pour cette tâche une extension à ajouter à Net-SNMP, dhcpd-snmp [5]. Ce dernier n’étant pas encore présent dans pkgsrc, nous utiliserons l’archive fournie sur le site du projet. Son installation se résume à un make && make install, mais son utilisation sous NetBSD demande quelques ajustements. Notons d’abord que dhcpd-snmp est un script Perl. Par conséquent, le langage devra être installé sur notre serveur. Ensuite, un rapide coup d’œil à l’en-tête du script nous montre que Perl est appelé de cette façon :
|
#! /usr/bin/perl |
Perl étant un package sous NetBSD, il faudra remplacer cet appel par :
|
#! /usr/pkg/bin/perl |
Le fichier de configuration de l’outil est relativement basique. Il suit le format suivant :
|
leases: /var/lib/dhcp3/dhcpd.leases pool: index, description, ip1-ip2, ip3-ip4... |
Soit, l’emplacement du fichier de leases, /var/db/dhcpd.leases dans notre cas, puis un descriptif du pool à monitorer. Ce qui nous donne :
|
leases: /var/db/dhcpd.leases pool: 1,Empire Network DHCP,192.168.200.100-192.168.200.120 |
L’ajout de l’extension à Net-SNMP s’effectue en ajoutant cette ligne au fichier /usr/pkg/etc/snmpd.conf :
|
pass_persist .1.3.6.1.4.1.21695.1.2 /usr/local/sbin/dhcpd-snmp /usr/local/etc/dhcpd-snmp.conf |
Après un /etc/rc.d/snmpd restart, nous vérifions le bon fonctionnement du module grâce à snmpwalk :
|
snmpwalk -v2c -c communauteconviviale localhost .1.3.6.1.4.1.21695.1.2 SNMPv2-SMI::enterprises.21695.1.2.1 = INTEGER: 1 SNMPv2-SMI::enterprises.21695.1.2.2.1.1 = INTEGER: 1 SNMPv2-SMI::enterprises.21695.1.2.2.2.1 = STRING: "Empire Network DHCP" SNMPv2-SMI::enterprises.21695.1.2.2.3.1 = INTEGER: 21 |
|
SNMPv2-SMI::enterprises.21695.1.2.2.4.1 = INTEGER: 1 SNMPv2-SMI::enterprises.21695.1.2.2.5.1 = INTEGER: 20 SNMPv2-SMI::enterprises.21695.1.2.2.6.1 = INTEGER: 20 |
C’est prêt !
|
5 |
Les points d’accès : anterak 1 et 2, décollage |
Nous descendons doucement vers les points d’entrée du réseau Wifi, les access points.
Comme nous l’avons dit au début de cet article, ce sont deux AP à bas prix que nous avons flashés afin que ces derniers utilisent OpenWrt Kamikaze. Le firmware fonctionne sur une foultitude de matériels différents comme en témoigne la liste du matériel supporté sur le wiki du projet [6]. Aussi, de simples AP achetés à 30€ dans la grande surface du coin conviendront parfaitement à notre expérience météorologique.
La configuration des AP est finalement peu originale. En effet, ces derniers ne servent que de ponts entre le réseau filaire et le réseau sans fil. Voici le contenu des deux fichiers-clés de Kamikaze :
|
# /etc/config/wireless config wifi-device wifi0 option type atheros option channel 6 option disabled 0 option mode 11b option distance 10000 option diversity 0 option txantenna 1 option rxantenna 1 config wifi-iface option device wifi0 option network lan option mode ap option ssid Empire-Network option encryption none option txpower 18 |
Quelques mots sur ce fichier. Le canal 6 a été choisi en raison de l’antenne Ricoré que j’avais préalablement construite grâce aux calculs automatiquement réalisés par le site CantenCalc [7]. Le choix du mode 11b n’a de raison que sa plus grande portée, mais également :
● Je ne fournirai que 2 Mbps aux invités.
● Les deux AP sont raccordés au réseau filaire par le biais de prises type CPL [8] à 14 Mbps.
|
# Copyright (C) 2006 OpenWrt.org config interface loopback option ifname lo option proto static option ipaddr 127.0.0.1 option netmask 255.0.0.0 config interface lan option ifname eth0 ath0 option type bridge |
|
option proto static option ipaddr 192.168.200.1 option netmask 255.255.255.0 |
Rien de bien original ici. Nous bridgeons l’interface Wifi à l’interface Ethernet et affectons une IP à ce pont.
Le petit routeur n’ayant d’autre rôle que celui de rallonge, le serveur dnsmasq ne lui est d’aucune utilité. Nous pouvons donc sans remords effacer le lien /etc/rc.d/S60dnsmasq.
Il sera du meilleur effet de monitorer également nos access points et que, dans leur immense mansuétude, des contributeurs du projet OpenWrt mettent à disposition des packages snmpd, ainsi que leurs dépendances.
Après avoir temporairement ajouté une route par défaut et renseigné le fichier /etc/resolv.conf, nous installons le démon SNMP de cette façon :
|
# ipkg install snmpd-static |
Puis, nous nous assurons de changer la communauté associée aux lectures dans son fichier de configuration :
|
root@Wrt1:~# head -1 /etc/snmp/snmpd.conf com2sec ro default convisnmp |
Pour finir, il me serait agréable de connaître le nombre de clients associés à chaque AP à un instant T. Cette information est obtenue par la lecture du fichier proc /proc/net/madwifi/ath0/associated_sta. Un simple script permet de visualiser le nombre de stations connectées :
|
#!/bin/sh # /jffs/scripts/assoc_count.sh echo $(($(wc -l < /proc/net/madwifi/ath0/associated_sta)/3)) |
Il suffit, pour lire cette information, d’utiliser les capacités de Net-SNMP à faire s’exécuter des programmes tiers afin de récupérer des informations diverses via SNMP :
|
exec assoc_count /jffs/scripts/assoc_count.sh |
Voici une nouvelle valeur sur laquelle nous allons pouvoir figer notre regard.
Un reboot plus tard, et en ayant bien pris soin de raccorder les AP au VLAN Wifi, ces derniers doivent être en mesure de raccorder un client qui aura entré le ssid " Empire-Network ". Venez à moi lutins de tous horizons.
![]() |
![]() |
|
6 |
Supervision et graphes : le monde entier est un Cacti |
Nous en venons maintenant à la représentation graphique de l’architecture. Nirvana de notre travail, nous allons constater sur de jolis graphiques l’utilisation de notre réseau ouvert par M. et Mme Toulemonde. Grisant !
Le candidat idéal à ce type de représentation est Cacti [9]. Ce logiciel de tracé permet de grapher tout et n’importe quoi, en utilisant par exemple de simples scripts ou plus naturellement SNMP. C’est évidemment vers cette seconde option que nous nous tournons, et Cacti nous facilite grandement la tâche.
Commençons par installer l’outil. Cacti a besoin de MySQL, donc :
|
# cd /usr/pkgsrc/databases/mysql5-server \ && make install clean |
Nous utiliserons la version 0.8.7b, dernière en date, via l’archive disponible depuis cacti.net. Son installation ayant été maintes fois décrite, nous n’insisterons que sur les aspects impliquant NetBSD. À nouveau, c’est l’utilisation intensive de Perl qui posera problème. En effet, tous les scripts Cacti écrits dans ce langage font appel à l’interpréteur de cette façon :
|
#!/usr/bin/perl |
Cette fois, point de finesse, la probabilité qu’un upgrade écrase l’ensemble des scripts que nous aurons modifiés, leur nombre, la flemme et l’alcool aidant, nous règlerons ce problème en tapant nonchalamment :
|
# ln -s /usr/pkg/bin/perl /usr/bin/perl |
Oui, je sais. Mais d’un coup d’un seul, c’est Cacti tout entier qui se met en marche.
Le monitoring de l’état de la mémoire de l’hôte local devra se faire via SNMP. En effet, beaucoup de scripts fournis dans l’archive sont évidemment ciblés GNU/Linux et manipulent allègrement /proc et autres switches Linux-only d’outils standards. S’il existe des scripts de type UNIX génériques pour obtenir un statut des processus en cours et du nombre d’utilisateurs logués, rien en revanche ne permet d’obtenir des informations sur l’utilisation de la mémoire.
Un article du hors-série 37 étant déjà dédié à l’utilisation de Cacti, je vous y renvoie donc sans vergogne et n’aborderai que les aspects spécifiques à notre architecture.
Pour tous les graphes d’utilisation de la bande passante et d’utilisation du CPU, rien à signaler, les Host Templates (ucd/net SNMP Host) Graph Templates (Interface – Traffic (bits/sec) et ucd/net – CPU Usage) sont livrés par défaut. Nous pouvons donc d’ores et déjà grapher :
● l’utilisation générale de la bande passante vers et depuis le WAN ;
● l’utilisation de la bande passante vers et depuis le réseau Wifi ;
● l’utilisation CPU de l’hôte local et des access points ;
● le nombre de processus et d’utilisateurs connectés sur l’hôte local.
![]() |
![]() |
![]() |
![]() |
Restent… pratiquement les seules informations intéressantes ! Le nombre de stations connectées aux AP et les leases DHCP en cours. Et, dans ces deux cas, pas de template disponible.
Pour le premier, c’est à nouveau l’intarissable source d’inspiration qu’est la flemme qui nous sort d’affaire. En effet, pour notre plus grand bonheur, l’un des Data Templates se nomme SNMP – Generic OID Template. Impeccable, il ne nous en fallait pas plus. Il suffit pour cette Data Source d’indiquer l’OID SNMP à interroger. Le lecteur attentif se souvient que le nombre de stations connectées à l’AP est obtenu à l’aide d’une directive exec ajoutée au fichier snmpd.conf de l’AP. La documentation de Net-SNMP nous informe que l’obtention des résultats liés aux extensions utilisateur se fait par le biais de l’OID 1.3.6.1.4.1.2021.8.1, exécution :
|
imil@obana:~$ snmpwalk -On -v2c -c convisnmp \ 192.168.200.2 1.3.6.1.4.1.2021.8 .1.3.6.1.4.1.2021.8.1.1.1 = INTEGER: 1 .1.3.6.1.4.1.2021.8.1.2.1 = STRING: assoc_count .1.3.6.1.4.1.2021.8.1.3.1 = STRING: /jffs/scripts/assoc_count.sh .1.3.6.1.4.1.2021.8.1.100.1 = INTEGER: 0 .1.3.6.1.4.1.2021.8.1.101.1 = STRING: 2 .1.3.6.1.4.1.2021.8.1.102.1 = INTEGER: noError(0) .1.3.6.1.4.1.2021.8.1.103.1 = STRING: |
Et effectivement, l’OID recherché est .1.3.6.1.4.1.2021.8.1.101.1, qui renvoie la chaîne de caractères retournée par le script. Nous entrons cet OID dans la section Custom Data de notre Data Source, lui associons un Graph et, quelques minutes plus tard, nous obtenons ce type d’œuvre d’art :
![]() |
![]() |
Pour le tracé des DHCP leases, nous utiliserons le travail de la communauté Cacti. En effet, dans la section " Scripts and Templates " du forum Cacti, on trouve un Graph et un Host Template précisément destinés à dhcpd-snmp [10]. Attention de ne pas vous jeter tête baissée sur le premier post de l’auteur, car, après quelques corrections, ce dernier reposte deux templates corrigés et fonctionnels. Pour en tirer profit, il vous faudra décompresser l’archive (zip…) que fournit l’auteur, puis les importer via la section " Import Templates " de Cacti. Vous devriez désormais pouvoir créer un device ayant pour Host Template " DHCPD SNMP Machine ". Après avoir associé à votre device un Graph Template de type " DHCPD Statistics (SNMP) ", ce type de tracé devrait faire son apparition au bout de quelques minutes :
![]() |
Pour finir, afin d’avoir une vue synthétique de notre réseau, nous nous rendons dans la rubrique " Settings -> Graph Export ", où nous prendrons soin de spécifier un répertoire d’export ayant des permissions suffisantes pour que Cacti puisse y écrire et qui soit hors du répertoire où ce dernier est installé. Cing minutes plus tard, vous devriez être subjugué par ce paysage :
![]() |
|
7 |
Résultats et premiers tests : monde de m*** |
Mon réseau public est ouvert depuis une semaine. Je n’ai de cesse de contempler les dizaines de leds clignoter gaiement, ainsi que mes graphes progresser. Je vois des dizaines de connexions passer… et pourtant, pour 100 stations automatiquement associées, seuls deux invités ont réussi à configurer leur proxy. Deux utilisateurs d’OSX. J’ai pourtant affublé le portail captif de screenshots expliquant pas à pas les menus dans lesquels cliquer pour activer le proxy, rien n’y fait. Le challenge est de bien trop haut niveau pour l’utilisateur moyen. Deux choix s’offrent désormais à moi : utiliser un système de token ? Simplement Chillispot ? Où considérer la question suivante, suggérée par Gaston sur le canal : " un utilisateur incapable de spécifier un proxy dans son navigateur a-t-il réellement le droit d’utiliser Internet ? "
Le constat est simple : le GENS est tout simplement incapable de configurer quoi que ce soit dans les pixels colorés qu’il regarde naïvement. Il va donc falloir s’assurer qu’il passe bien au mois une fois par le portail captif, puis le sortir de captivité lorsque cette étape est réalisée. Le seul moyen qui m’est apparu pour obtenir ce résultat, c’est de mémoriser son adresse MAC.
Pour me simplifier la tâche, j’ai simplement décidé de ne plus autoriser les connexions SSH " classiques ". En effet, si le filtrage par MAC fonctionne sans problème à travers Squid (nous verrons plus loin comment), il n’en va pas de même pour le shell sécurisé. L’une des possibilités qui s’offraient à moi était d’utiliser le filtrage par MAC du binôme brconfig / pf, cette méthode permettant de dynamiquement agréger des adresses MAC sous un marquage commun, puis d’effectuer un filtrage fonction de ce marquage via pf. Malheureusement, cette technique pourtant très alléchante n’est disponible que sous OpenBSD. Or, notre passerelle est équipée d’un NetBSD et j’ai vraiment, vraiment, la flemme de changer ça.
Finalement, il reviendra à l’utilisateur " propre " souhaitant utiliser ssh de passer par un système tel que corkscrew [11] conjointement à la directive ProxyCommand d’OpenSSH. Cette méthode permettra d’utiliser Squid pour faire transiter ses connexions SSH.
Je vous l’accorde, nous nageons en plein paradoxe.
|
8 |
Simplification : la revanche du calamar géant |
L’opération de simplification va s’effectuer en deux temps. La première chose de laquelle il faut s’assurer, c’est que l’utilisateur a bien parcouru le portail captif au moins jusqu’à l’énorme lien " J’accepte ces conditions d’utilisation ". Un clic sur ce lien aura pour effet d’enregistrer son adresse MAC à l’aide de quelques lignes de PHP. Le lien aura pour cible une URI du type /?valid=yes :
|
<?php // on déduit l’adresse MAC du visiteur grace à l’IP contenue dans la variable REMOTE_ADDR $pp = popen("/usr/sbin/arp ".$_SERVER[‘REMOTE_ADDR’]."|/usr/bin/cut -d’ ‘ -f4", "r"); // oui je sais $arp = fread($pp, 1024); pclose($pp); // petit formatage $arp = preg_replace("/[^0-9a-f]/i", "", $arp); // et on "retient" l’adresse if (isset($_GET[‘valid’])) { $fp = fopen("/tmp/empire-macs/$arp", "w"); fwrite($fp, $_SERVER[‘REMOTE_ADDR’]."\n"); fclose($fp); ?> [encore du html] <php? } else { ?> [toujours du html] <a href="/?valid=yes">I accept these terms / J’accepte ces conditions</a> [...] <?php } ?> |
Une fois cette MAC address enregistrée, il revient à Squid de s’assurer que l’utilisateur est connu. Intuitivement, nous pressentons la nécessité de se fendre de quelques lignes de Perl pour réaliser cette petite cuisine, puis de faire appel à la directive url_rewrite_program du proxy une seconde fois. Un peu plus tard, la lecture des FAQ Squid nous apprendra qu’il n’est pas possible de positionner plusieurs redirecteurs d’URL dans la configuration du proxy. La solution peu élégante qui s’offre à nous coule de source : nous devons écrire un script qui gèrera plusieurs redirecteurs. Exécution :
|
#!/usr/pkg/bin/perl # macrecord.pl use FileHandle; use IPC::Open2; my $portal = "http://proxy.empire-network.net"; my $squidguard = "/usr/pkg/bin/squidGuard"; my $squidguardconf = "/usr/pkg/etc/squid/squidGuard.conf"; my $arpbin = "/usr/sbin/arp"; my $macpath = "/tmp/empire-macs"; $|=1; # cette fonction vérifie l’obtention d’une adresse MAC, vérifie sa présence et redirige éventuellement # l’utilisateur vers le portail captif sub macrecord { # squid envoie les informations au redirecteur de cette façon |
|
# URL adresse-ip/fqdn ident method # soit par exemple : # http://www.gnulinuxmag.fr 192.168.200.121/client21.empire-network.net - GET # ici, nous n’aurons besoin que de l’IP, soit le second argument my $ip = $iparg = (split(/ /, $_))[1]; $ip =~ s/([0-9\.]+)\/.*/\1/; # on déduit l’adresse MAC grace à l’outil "arp" my $arp = (split(/ /,`$arpbin $ip 2>/dev/null`))[3]; $arp =~ s/\://g; # on vérifie qu’on a bien obtenu une adresse MAC et que cette dernière est connue # le cas écheant, on redirige vers le portail à l’aide d’un 302 "Moved Temporarily" if ( $arp eq "" || ! -e "$macpath/$arp" ) { print "302:$portal\n"; return 2; }; } # cette fonction exécute squidguard sub squidguard_exec { # on utilise open2() afin de manipuler l’entrée et la sortie standard my $pid = open2( \*IN, \*OUT, "$squidguard -c $squidguardconf" ); OUT->autoflush(); print OUT "$_\n"; my $redir = <IN>; chomp $redir; # puis on mime la sortie de squidguard if (! $redir eq "") { print "$redir\n"; } else { print "\n"; } # on ferme les descripteurs |
|
close(OUT); close(IN); # et on s’assure de ne pas laisser traîner de zombies derrière nous waitpid($pid, 0); } # boucle principale while (<>) { # on passe d’abord par l’analyse de la MAC # si elle a conduit à une redirection on saute l’étape squidguard if ((macrecord $_) == 2) { next; } squidguard_exec $_; } |
Afin de mettre ce script à profit, il faudra remplacer l’appel direct à SquidGuard dans notre squid.conf par :
|
url_rewrite_program /path/vers/macrecord.pl |
et activer ses capacités de proxy transparent :
|
http_port 127.0.0.1:3128 transparent |
Enfin, nous rebroussons chemin et remplaçons le forward automatique pf par :
|
rdr on $int inet proto tcp from <empire_guests> \ to ! $int port { 21, 80, 443 } -> 127.0.0.1 port 3128 |
Afin de renvoyer toute connexion HTTP, HTTPS et FTP vers notre proxy.
Résultat :
Première connexion : accès au portail, on accepte les conditions.
Seconde connexion : accès libre.
Ça va ? C’est assez simple maintenant ?
|
9 |
Conclusion : Va chercher du pr0n, va ! |
Notre architecture " finale " est maintenant sur les rails. J’emploie des guillemets parce que ce coup d’essai n’est probablement pas ce qui se fait de plus sexy en la matière et qu’en bien des points notre HotSpot est perfectible. Il y a donc fort à parier que j’y retouche plus ou moins profondément en tirant certainement profit de l’utilisation à moyen terme de ce réseau par ses invités. Pour ceux d’entre vous que le doux bruit des ventilateurs ne berce pas, il est évidemment tout à fait possible de réduire cette architecture à son plus simple appareil, soit une seule machine munie d’une carte Wifi en utilisant les capacités réseau (VLAN, NAT, firewalling…) de n’importe quel OS du bien™. Ainsi, nous chanterons tous en cœur : " ouvrez, ouvrez la cage auuu réééseauuuuu, regardez-le s’envoler c’eeest beauuuu ".
|
Liens |
|
● [1] http://www.laquadrature.net/ ● [2] http://fr.wikipedia.org/wiki/Spanning_tree_protocol ● [3] http://fr.wikipedia.org/wiki/IEEE_802.1Q ● [4] http://squidguard.org/ ● [5] http://www.net-track.ch/opensource/dhcpd-snmp/ ● [6] http://wiki.openwrt.org/TableOfHardware ● [7] http://kioan.users.uth.gr/wireless/cantenna/ ● [8] http://fr.wikipedia.org/wiki/Courants_porteurs_en_ligne ● [9] http://www.cacti.net/ ● [10] http://forums.cacti.net/about14345.html ● [11] http://www.agroman.net/corkscrew/ |
Retrouvez cet article dans : Linux Magazine 108












