Permission de sortie : 30 minutes
Le Besoin
- Un firewall qui interdit tout sauf le port 443 local de la machine.
- Un système permettant d'ouvrir pour 30 minutes seulement l'accès a un port du firewall donné
Les ingrédients
- FreeBSD 8.0
- PF
- AT
- /bin/sh
- sudo
Recette
PF
scrub in all
set skip on lo0
pass out all
block in all
table <allowips> persist
pass in quick inet proto tcp port https keep state
pass in quick inet proto tcp from <allowips> to port 8080 keep state
Voila tout simple tout beau, en gros on bloque tout sauf le https. On autorise toutes les ips qui sont contenu dans la table allowips
Problème : comme rajouter des adresses IPs dans la table allowips et surtout comment les supprimer au bout de 30 minutes
CGI shell
Nous créons donc un script cgi qui après une authentification "ultra basique" ajoutera l'adresse IP du demandeur dans la table allowips et schedulera la supression de celle ci
#!/bin/sh
if [ "$REQUEST_METHOD" = "POST" ];then
query="dd count=$CONTENT_LENGTH bs=1 2> /dev/null"
else
echo "Bad request"
return
fi
# Ceci n'est pas super clean, il y a mieux à faire mais flemme :)
eval $query
if [ -z $passwd ]; then
echo "Bad request"
return
fi
decodedpasswd=$(echo $passwd | awk '"'BEGIN{for(i=0;i<10;i++)hex[i]=i;hex["A"]=hex["a"]=10;hex["B"]=hex["b"]=11;hex["C"]=hex["c"]=12;hex["D"]=hex["d"]=13;hex["E"]=hex["e"]=14;hex["F"]=hex["f"]=15;}{gsub(/\+/," ");i=$0;while(match(i,/%../)){;if(RSTART>1);printf"%s",substr(i,1,RSTART-1);printf"%c",hex[substr(i,RSTART+1,1)]*16+hex[substr(i,RSTART+2,1)];i=substr(i,RSTART+RLENGTH);}print i;}'"')
if [ -f /usr/local/etc/authpasswd ]; then
read encryptpasswd < /usr/local/etc/authpasswd
else
echo "No password file"
return
fi
cryptpasswd=$(echo $decodedpasswd | /sbin/sha256)
if [ "$cryptpasswd" = "$encryptpasswd" ]; then
/usr/local/bin/sudo /sbin/pfctl -t allowips -T add $REMOTE_ADDR
echo "/usr/local/bin/sudo /sbin/pfctl -t allowips -T delete $REMOTE_ADDR" | /usr/bin/at now + 30 minute
echo "Acces granted for 30 minutes"
else
echo "Acces refused"
fi
C'est pas terrible mais suffisant : le mot de passe de référence est stocké dans /usr/local/etc/authpasswd et est en sha256
Il faut maintenant autoriser l'utilisateur www à pouvoir utiliser at :
$ echo "www" > /var/at/at.allow
Ensuite rajouter les entrées sudo qui vont bien dans /usr/local/etc/sudoers
%www ALL=NOPASSWD: /sbin/pfctl -t allowips *
Il vous reste à faire un fichier html qui appelle le script CGI via la méthode POST en lui fournissant le mot de passe donné dans une variable "passwd". Mettre le tout à dispo via un serveur web supportant le CGI.
Après on me demande pourquoi j'aime les Unix...
EDIT : alors on me dit dans l'oreillette que pfctl -t allowips -T expire 1800 lancé toutes les minutes dans une crontab ferait le même boulot mais je préfère ma solution à coup de at puisque at est géré par cron sous FreeBSD et que ce n'est exécuté qu'au besoin et non toutes les minutes