Portail captif simple au niveau 3 du modèle OSI

[ Articles -> Conception d'un portail captif simple (niveau 3 du modèle OSI) ]

Introduction

Cet article a pour objectif de décrire la conception d'un portail captif simple, en environnement GNU/Linux, opérant au niveau 3 du modèle OSI. De bonnes connaissances en réseau sont nécessaires pour la compréhension de cet article.

Le portail captif est une technique mise en oeuvre sur une passerelle d'accès permettant de bloquer toute commutation externe et de forcer le client à se connecter sur une page Web, en redirigeant toutes les requêtes HTTP vers le serveur cible.

Cette technique a principalement pour objectif l'authentification du client sur le réseau. C'est une alternative légère et plus simple à utiliser pour les clients néophytes que l'authentification 802.1x (radius), c'est pourquoi elle est couramment utilisée sur les réseaux Wi-Fi ouverts.


Architecture

Pour la suite de l'article, nous prendrons en considération le réseau 10.100.1.0/24, ayant pour passerelle (route par défaut des clients) 10.100.1.1. Notre passerelle a pour interface "interne" eth1 (10.100.1.1) et pour interface "externe" eth0. Il existe 2 types de portails qui agissent respectivement aux niveaux 2 (liaison) et 3 (réseau) du modèle OSI. Le plus courant est le portail captif de niveau 3, c'est donc sur celui-ci que nous nous attarderons.

Nous ferons abstraction du routage (éventuellement du NAT en postrouting), qui n'est pas le propos de l'article, et qui est considéré comme acquis et déjà en place.

Pré-requis logiciel

La passerelle tourne sous un OS à base de Debian (Linux). Les paquets suivants doivent être installés :


Règles de pare-feu (Netfilter) sur la passerelle

Les règles configurées avec IPtables doivent permettre trois choses :

Pour la suite, on définit quatre variables Bash :

1	INT_IF=eth1
2	EXT_IF=eth0
3	IP_CAPTIVE_PORTAL=10.100.1.1
4	IPTABLES=/sbin/iptables

Blocage du forwarding

Très simple :

1	### Deny FORWARD by default
2	$IPTABLES -A FORWARD -i $INT_IF -o $EXT_IF -j DROP

Redirection des clients non authentifiés vers le serveur web local, et "forcing" du DNS

Le fait de forcer le serveur DNS est utile pour la suite (déclaration d'un domaine local), et permet d'éviter les tunnels IP over DNS (d'autant que de toute façon la commutation est bloquée).
Là encore, la configuration iptables est très simple :

1	### Redirects HTTP requests from unloggued users to the logon web page - DNS forcing
2
3	$IPTABLES -t nat -I PREROUTING -i $INT_IF -p tcp --dport 80 -j DNAT --to-destination $IP_CAPTIVE_PORTAL
4	$IPTABLES -t nat -I PREROUTING -i $INT_IF -p udp --dport 53 -j DNAT --to-destination $IP_CAPTIVE_PORTAL

Autorisation du forwarding de certains réseaux

Il peut être intéressant, quand on est FAI, d'autoriser les clients non authentifiés à se connecter au site web du-dit FAI, afin d'enregistrer des abonnements.
En supposant que l'IP du serveur hébergant le site web du FAI soit 212.27.48.10, on entre les commandes suivantes :

1	# Allow free forwarding for 212.27.48.10
2
3	$IPTABLES -t nat -I PREROUTING -i $INT_IF -d 212.27.48.10 -j ACCEPT
4	$IPTABLES -I FORWARD -i $INT_IF -d 212.27.48.10 -j ACCEPT

On peut aussi autoriser le trafic à destination de PayPal, utile en cas de paiement en ligne pour l'abonnement :

1	# Allow free forwarding for PayPal
2
3	$IPTABLES -t nat -I PREROUTING -i $INT_IF -d 66.211.169.0/24 -j ACCEPT
4	$IPTABLES -t nat -I PREROUTING -i $INT_IF -d 64.4.241.0/24 -j ACCEPT
5	$IPTABLES -t nat -I PREROUTING -i $INT_IF -d 72.246.0.0/15 -j ACCEPT
6	$IPTABLES -t nat -I PREROUTING -i $INT_IF -d 216.113.160.0/19 -j ACCEPT
7	$IPTABLES -t nat -I PREROUTING -i $INT_IF -d 66.235.128.0/19 -j ACCEPT
8	$IPTABLES -t nat -I PREROUTING -i $INT_IF -d 66.135.192.0/19 -j ACCEPT
9	$IPTABLES -t nat -I PREROUTING -i $INT_IF -d 66.151.153.9 -j ACCEPT
10	$IPTABLES -t nat -I PREROUTING -i $INT_IF -d 173.0.80.0/20 -j ACCEPT
11
12	$IPTABLES -I FORWARD -i $INT_IF -d 66.211.169.0/24 -j ACCEPT
13	$IPTABLES -I FORWARD -i $INT_IF -d 64.4.241.0/24 -j ACCEPT
14	$IPTABLES -I FORWARD -i $INT_IF -d 72.246.0.0/15 -j ACCEPT
15	$IPTABLES -I FORWARD -i $INT_IF -d 216.113.160.0/19 -j ACCEPT
16	$IPTABLES -I FORWARD -i $INT_IF -d 66.235.128.0/19 -j ACCEPT
17	$IPTABLES -I FORWARD -i $INT_IF -d 66.135.192.0/19 -j ACCEPT
18	$IPTABLES -I FORWARD -i $INT_IF -d 66.151.153.9 -j ACCEPT
19	$IPTABLES -I FORWARD -i $INT_IF -d 173.0.80.0/20 -j ACCEPT

Autoriser un client particulier à se connecter (via son adresse MAC)

Bloquer et rediriger le trafic est une chose, mais lorsque le client est authentifié, il faut pouvoir l'autoriser à bypasser le portail captif.
Libre à vous d'utiliser le langage de programmation de votre choix pour l'interface client, il vous faudra après authentification rajouter deux règles iptables pour l'adresse MAC spécifique.
Par exemple, pour autoriser l'adresse MAC 5E:FF:56:A2:AF:15 à se connecter, on exécute les commandes suivantes :

1	/sbin/iptables -t nat -I PREROUTING -m mac --mac-source 5E:FF:56:A2:AF:15 -j ACCEPT
2	/sbin/iptables -I FORWARD -m mac --mac-source 5E:FF:56:A2:AF:15 -j ACCEPT

Exemple d'implémentation de l'autorisation en PHP

Le but du portail est bien sûr de pouvoir authentifier de façon automatique des utilisateurs.
Pour ce faire, le programme executé sur le serveur doit posséder des droits suffisants pour faire appel à iptables (root). En prenant l'exemple d'un script PHP, appelé par Apache (serveur web), apache doit posséder des droits suffisants.

Pour ce faire, on utilise sudo, en rajoutant la ligne suivante dans le sudoers (avec la commande visudo) :

1	# visudo
2	www-data ALL = NOPASSWD: /sbin/iptables

En PHP, l'implémentation d'une fonction permettant d'autoriser une adresse MAC à se connecter peut donner le code suivant :

1	<?php	
2
3	function enableMac($mac='inconnue')
4	{
5		if($mac == 'inconnue')
6		{
7			$mac = shell_exec('/usr/sbin/arp -na '.$_SERVER['REMOTE_ADDR']);
8			preg_match('/..:..:..:..:..:../',$mac , $matches);
9			@$mac = $matches[0];
10		}
11
12		$r1 = shell_exec("sudo /sbin/iptables -t nat -I PREROUTING -m mac --mac-source $mac -j ACCEPT");
13		$r2 = shell_exec("sudo /sbin/iptables -I FORWARD -m mac --mac-source $mac -j ACCEPT");
14	
15		return $r1.$r2;
16	}
17
18	?>

Conclusion

Ainsi s'achève la conception de notre portail captif de niveau 3.
À titre d'exemple d'amélioration, il est possible prévoir une redirection du client sur un domaine dédié à l'authentification (ex : auth.mon-fai.fr), avec un bon paramétrage DNS. Il est aussi possible (et conseillé) de proposer une version HTTPS (SSL / TLS) du portail captif, afin de garantir la sécurité de l'authentification sur réseau ouvert.

J'espère avoir correctement traité ce sujet, et je tiens à remercier l'association Quantic Télécom pour les sources et codes présentés ici.


comments powered by Disqus