#! /usr/bin/env python # -*- coding: iso-8859-15 -*- # Serveur SSL qui renvoie la MAC correspondant à une IP # Ce serveur est utilisé sur Nectaris par les bornes wifi pour faire # les requêtes ARP. # On utilise twisted # http://twistedmatrix.com/documents/current/howto/tutorial/intro from twisted.internet import protocol, reactor, defer, utils from twisted.internet.ssl import ContextFactory from twisted.protocols import basic from twisted.application import internet, service import sys sys.path.append('/usr/scripts/gestion') # LDAP from ldap_crans import crans_ldap # Divers from iptools import AddrInNet from OpenSSL import SSL import re class ServerContextFactory(ContextFactory): def getContext(self): """Création d'un contexte SSL côté serveur.""" ctx = SSL.Context(SSL.SSLv23_METHOD) ctx.use_certificate_file('/etc/ssl/certs/nectaris.pem') ctx.use_privatekey_file('/etc/ssl/private/nectaris.pem') return ctx class ARPProtocol(basic.LineReceiver): """Protocole de communication pour récupérer une adresse MAC. Chaque lignee reçue contient une adresse IP et le serveur répond avec l'adresse MAC correspondante ou avec `unknown' si celle-ci est inconnue (ou non autorisée). """ def lineReceived(self, IP): self.factory.getMac(IP ).addErrback(lambda _: "Internal error in server" ).addCallback(lambda m: (self.answerMac(m))) def answerMac(self, m): """Renvoie au client la bonne adresse MAC. `m' peut être None. """ if m: return self.transport.write(str(m) + "\r\n") else: return self.transport.write("unknown\r\n") class ARPFactory(protocol.ServerFactory): """Backend du serveur. Effectue la résolution IP/MAC.""" protocol = ARPProtocol def __init__(self, network='0.0.0.0/0'): self.ldap = crans_ldap() self.network = network def getMac(self, IP): return defer.succeed(self._getMac(IP)) def _getMac(self, IP): """Fonction réelle, synchrone, qui obtient l'adresse MAC.""" try: if AddrInNet(IP, self.network): results = self.ldap.search('ip=%s' % IP)['machine'] if results: # On a au moins un résultat, on retourne le premier return results[0].mac().strip() else: # On a rien return None else: # L'IP n'est pas autorisée return None except ValueError: # A priori, ce n'était pas une IP return None # Corps du programme # On écoute sur le port 5243 et on ne répond qu'aux requêtes concernant le # sous-réseau wifi application = service.Application('arp') factory = ARPFactory('138.231.148.0/22') internet.SSLServer(5243, factory, ServerContextFactory()).setServiceParent(service.IServiceCollection(application))