Gestion du hotspot, import initial
darcs-hash:20051109102226-d1718-26be50de87fd13d1c0ea11772f39b8d0921669ed.gz
This commit is contained in:
parent
1a28a11027
commit
552d7673e5
2 changed files with 197 additions and 0 deletions
138
wifi/hotspot.py
Executable file
138
wifi/hotspot.py
Executable file
|
@ -0,0 +1,138 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
# -*- encoding: iso-8859-15 -*-
|
||||||
|
|
||||||
|
# Gestion du portail captif :
|
||||||
|
# - lecture d'une socket pour les IP à ajouter
|
||||||
|
# - lecture du fichier de lease DHCP pour les expirer
|
||||||
|
|
||||||
|
import os
|
||||||
|
from popen2 import Popen4
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from syslog import openlog, syslog, LOG_ERR, LOG_LOCAL4, LOG_INFO, LOG_LOCAL3, LOG_PERROR, LOG_PID
|
||||||
|
from lease import Leases
|
||||||
|
from select import select
|
||||||
|
|
||||||
|
class Server:
|
||||||
|
"""Serveur (sur socket) gérant le hotspot"""
|
||||||
|
|
||||||
|
def __init__(self, socket):
|
||||||
|
"""Initialise le serveur.
|
||||||
|
|
||||||
|
Il écoutera sur le pipe nommé `socket'."""
|
||||||
|
# syslog
|
||||||
|
openlog("hotspot.py", LOG_PERROR | LOG_PID)
|
||||||
|
syslog(LOG_INFO | LOG_LOCAL4, "Demarrage du demon hotspot")
|
||||||
|
# Initialisation de la socket
|
||||||
|
self._socket_name = socket
|
||||||
|
self._dontclean = False
|
||||||
|
os.mkfifo(socket, 0600)
|
||||||
|
self.socket = file(socket, "a+")
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
try:
|
||||||
|
self.socket.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if not self._dontclean:
|
||||||
|
os.unlink(self._socket_name)
|
||||||
|
|
||||||
|
def execute(self,cmd):
|
||||||
|
"""Exécute une commande.
|
||||||
|
|
||||||
|
Gère les erreurs par log dans syslog."""
|
||||||
|
p = Popen4(cmd)
|
||||||
|
p.tochild.close()
|
||||||
|
out = p.fromchild.read()
|
||||||
|
p.fromchild.close()
|
||||||
|
exit = os.WEXITSTATUS(p.wait())
|
||||||
|
if exit:
|
||||||
|
# Une erreur a eu lieu
|
||||||
|
syslog(LOG_ERR | LOG_LOCAL4,
|
||||||
|
"Error %d executing `%s' : %s" % (exit, cmd.strip(), out.strip()))
|
||||||
|
else:
|
||||||
|
return out
|
||||||
|
|
||||||
|
def add_ip(self,ip):
|
||||||
|
"""Ajout d'une IP au firewall"""
|
||||||
|
cmd = "pfctl -t clients_hotspot_autorises -Tadd %s" % ip
|
||||||
|
if self.execute(cmd):
|
||||||
|
syslog(LOG_INFO | LOG_LOCAL3, "Nouveau client hotspots: %s" % ip)
|
||||||
|
|
||||||
|
|
||||||
|
def del_ip(self,ip):
|
||||||
|
"""Retire une règle du firewall"""
|
||||||
|
cmd = "pfctl -t clients_hotspot_autorises -Tdelete %s" % ip
|
||||||
|
if self.execute(cmd):
|
||||||
|
syslog(LOG_INFO | LOG_LOCAL3, "Suppression du client: %s" % ip)
|
||||||
|
|
||||||
|
def list_ips(self):
|
||||||
|
"""Liste les IP actuellement dans le firewall"""
|
||||||
|
cmd = "pfctl -t clients_hotspot_autorises -Tshow"
|
||||||
|
ips = self.execute(cmd)
|
||||||
|
if not ips:
|
||||||
|
return []
|
||||||
|
return filter(lambda y: y.strip() != '',
|
||||||
|
map(lambda x: x.strip(), ips.split("\n")))
|
||||||
|
|
||||||
|
def prune_ips(self):
|
||||||
|
"""Vire les IP qui ne sont plus utilisées"""
|
||||||
|
l = Leases().leases
|
||||||
|
deleted = False
|
||||||
|
for ip in self.list_ips():
|
||||||
|
match = filter(lambda x: x.ip == ip, l)
|
||||||
|
if not match:
|
||||||
|
# Plus de bail du tout
|
||||||
|
self.del_ip(ip)
|
||||||
|
deleted = True
|
||||||
|
else:
|
||||||
|
# On vérifie si le bail n'a pas expiré depuis plus de une minute
|
||||||
|
if match[0].end < time.gmtime(time.time()-60):
|
||||||
|
self.del_ip(ip)
|
||||||
|
deleted=True
|
||||||
|
if deleted:
|
||||||
|
syslog(LOG_INFO | LOG_LOCAL3, "Clients hotspots: %s" % (", ".join(self.list_ips())) or "aucun")
|
||||||
|
|
||||||
|
def daemonize(self):
|
||||||
|
"""Passe en arrière plan"""
|
||||||
|
# Fork
|
||||||
|
if os.fork() > 0:
|
||||||
|
self._dontclean = True
|
||||||
|
sys.exit(0)
|
||||||
|
# Bon répertoire
|
||||||
|
os.chdir("/")
|
||||||
|
# Masque indépendant de l'utilisateur
|
||||||
|
os.umask(022)
|
||||||
|
# Chef de file
|
||||||
|
os.setsid()
|
||||||
|
# Second fork pour avoir son groupe
|
||||||
|
if os.fork() > 0:
|
||||||
|
self._dontclean = True
|
||||||
|
sys.exit(0)
|
||||||
|
# Redirection des E/S
|
||||||
|
si = file('/dev/null', 'r')
|
||||||
|
so = file('/dev/null', 'a+')
|
||||||
|
se = file('/dev/null', 'a+', 0)
|
||||||
|
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||||
|
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||||
|
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
"""Boucle principale"""
|
||||||
|
s = self.socket.fileno()
|
||||||
|
while True:
|
||||||
|
# On attend du monde sur la socket
|
||||||
|
result = select([s],[],[],60)[0]
|
||||||
|
if result:
|
||||||
|
# On a quelqu'un, on lit une ligne
|
||||||
|
ip = self.socket.readline().strip()
|
||||||
|
self.add_ip(ip)
|
||||||
|
# Dans tous les cas, on vire les IP inutiles
|
||||||
|
self.prune_ips()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
s = Server("/tmp/hotspot.socket")
|
||||||
|
s.daemonize()
|
||||||
|
s.start()
|
||||||
|
|
59
wifi/lease.py
Executable file
59
wifi/lease.py
Executable file
|
@ -0,0 +1,59 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
# -*- encoding: iso-8859-15 -*-
|
||||||
|
|
||||||
|
# Gestion en lecture d'un fichier lease (issu du DHCPD d'Open)
|
||||||
|
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
|
class Lease:
|
||||||
|
"""Classe représentant un bail (lease)."""
|
||||||
|
|
||||||
|
def __init__(self, texte):
|
||||||
|
"""Instanciation d'un bail
|
||||||
|
|
||||||
|
L'instanciation se fait en fournissant `texte' qui est la
|
||||||
|
forme textuelle du bail qui se trouve dans
|
||||||
|
/var/db/dhcpd.leases de la forme :
|
||||||
|
|
||||||
|
lease 10.231.149.89 {
|
||||||
|
starts 3 2005/11/09 07:58:52;
|
||||||
|
ends 3 2005/11/09 08:13:52;
|
||||||
|
hardware ethernet 00:0c:f1:37:54:2c;
|
||||||
|
uid 01:00:0c:f1:37:54:2c;
|
||||||
|
client-hostname "FCDVIRELY";
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
mo = re.search("\\blease ([0-9\\.]*) \\{", texte)
|
||||||
|
if not mo:
|
||||||
|
raise ValueError, u"Pas de bail trouvé"
|
||||||
|
self.ip = mo.group(1)
|
||||||
|
|
||||||
|
mo = re.search("\\bstarts [0-7] ([0-9/]* [0-9:]*);", texte)
|
||||||
|
if not mo:
|
||||||
|
raise ValueError, u"Pas de date de début de bail"
|
||||||
|
self.start = time.strptime(mo.group(1), "%Y/%m/%d %H:%M:%S")
|
||||||
|
|
||||||
|
mo = re.search("\\bends [0-7] ([0-9/]* [0-9:]*);", texte)
|
||||||
|
if not mo:
|
||||||
|
raise ValueError, u"Pas de date de fin de bail"
|
||||||
|
self.end = time.strptime(mo.group(1), "%Y/%m/%d %H:%M:%S")
|
||||||
|
|
||||||
|
mo = re.search("\\bhardware ethernet ([0-9a-f:]*);", texte)
|
||||||
|
if not mo:
|
||||||
|
raise ValueError, u"Pas d'adresse Ethernet pour le bail"
|
||||||
|
self.mac = mo.group(1)
|
||||||
|
|
||||||
|
# On n'est pas intéressé par le reste
|
||||||
|
|
||||||
|
class Leases:
|
||||||
|
"""Classe représentant un ensemble de bails."""
|
||||||
|
|
||||||
|
def __init__(self, fichier="/var/db/dhcpd.leases"):
|
||||||
|
"""Instanciation à partir du fichier de leases."""
|
||||||
|
self.leases = []
|
||||||
|
# Méthode rapide :
|
||||||
|
for lease in " ".join(file(fichier).readlines()).split("}")[:-1]:
|
||||||
|
self.leases.append(Lease(lease))
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue