From 4fd3644f975c3441d3e1ac746d4fb6ea111f5d24 Mon Sep 17 00:00:00 2001 From: Jeremie Dimino Date: Thu, 4 Sep 2008 06:13:37 +0200 Subject: [PATCH] utilisation de radius pour configurer les switchs en live MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Maintenant radius dit aux switchs quel vlan mettre en non taggé. Ça permet de switcher facilement sur le bon vlan suivant le type de compte et ça évite la désynchronisation de la configuration des switchs. darcs-hash:20080904041337-af139-665172ad09d19f439c6aa8ee6c529752c0e80d95.gz --- gestion/config.py | 16 ++++++ gestion/gen_confs/switchs.py | 104 ++++++++++++++++------------------- gestion/ldap_crans.py | 10 ---- radius_auth.py | 39 +++++++++---- 4 files changed, 90 insertions(+), 79 deletions(-) diff --git a/gestion/config.py b/gestion/config.py index 306d173d..f177b868 100644 --- a/gestion/config.py +++ b/gestion/config.py @@ -383,6 +383,22 @@ domains = { 'machineFixe': 'crans.org', 'machineWifi': 'wifi.crans.org', 'borneWifi': 'wifi.crans.org' } +# VLans +vlans = { + # VLan d'administration + 'adm' : 2, + # VLan pour le wifi + 'wifi' : 3, + # VLan pour le wifi de l'ens + 'hotspot' : 4, + # VLan des gens qui paient + 'adherent' : 1, + # VLan des inconnus + 'accueil' : 7, + # VLan des radins + 'radin' : 6 + } + ####################### ## Mail de bienvenue ## ####################### diff --git a/gestion/gen_confs/switchs.py b/gestion/gen_confs/switchs.py index 3ef0407c..13903409 100755 --- a/gestion/gen_confs/switchs.py +++ b/gestion/gen_confs/switchs.py @@ -23,6 +23,7 @@ from annuaires import chbre_prises, uplink_prises, reverse, bat_manuels, all_swi from random import shuffle from gen_confs import * from time import localtime +import config from annuaires import bat_switchs @@ -57,31 +58,36 @@ logging 10.231.136.7 %(INTERFACES_CONF)s ;-------------------------------------------------------- IP du switch ip default-gateway 10.231.136.4 -vlan 1 +vlan %(vlan_adherent)s name "DEFAULT_VLAN" - %(prises_default)s + untagged %(prises_default)s no ip address ip igmp no ip igmp querier exit -vlan 2 +vlan %(vlan_adm)s name "Adm" - %(prises_adm)s + %(prises_adm)s ip address %(ip)s 255.255.255.0 exit -vlan 3 +vlan %(vlan_wifi)s name "Wifi" %(prises_wifi)s no ip address exit -vlan 4 +vlan %(vlan_hotspot)s name "Hotspot" %(prises_hotspot)s no ip address exit -vlan 6 +vlan %(vlan_radin)s name "Radin" - %(prises_radin) + tagged %(prises_default)s + no ip address + exit +vlan %(vlan_accueil)s + name "Accueil" + tagged %(prises_default)s no ip address exit ;------------------------------------------------------- Accès d'administration @@ -116,7 +122,7 @@ no cdp run no stack """ - interface_template = """interface %(prise)i%(etat)s + interface_template = """interface %(prise)i enable name "%(nom)s" flow-control%(speed)s no lacp @@ -283,8 +289,10 @@ exit vlans = { 'wifi_tagged' : [] , 'wifi_untagged' : [] , 'hotspot_tagged' : [], 'hotspot_untagged' : [], 'adm_tagged' : [] , 'adm_untagged' : [] , - 'default_tagged' : [] , 'default_untagged' : [], - 'radin_tagged' : [], 'radin_untagged' : [] } + + # VLans pour le reste: le vlan des adhérents, des + # inconnus et de ceux qui ne paie pas + 'default' : [] } # Génération de la conf de chaque prise for prise in range(1,nb_prises+1): @@ -299,11 +307,10 @@ exit ### Prise d'uplink prise_params['nom'] = uplink_prises[bat][int(annu_prise)] params['uplinks'].append(prise) - vlans['default_untagged'].append(prise) + vlans['default'].append(prise) vlans['adm_tagged'].append(prise) vlans['wifi_tagged'].append(prise) vlans['hotspot_tagged'].append(prise) - vlans['radin_tagged'].append(prise) params['INTERFACES_CONF'] += self.interface_template % prise_params continue @@ -329,7 +336,7 @@ exit if len(chbres) > 1 : prise_params['nom'] += 's' for chbre in chbres : prise_params['nom'] += '_%s%s' % (bat.upper(), chbre) - vlans['default_untagged'].append(prise) + vlans['default'].append(prise) else : prise_params['nom'] = "Wifi" vlans['hotspot_tagged'].append(prise) @@ -344,58 +351,36 @@ exit else : # Tous les vlans prise_params['nom'] = "Prise_crans" - vlans['default_untagged'].append(prise) + vlans['default'].append(prise) vlans['adm_tagged'].append(prise) vlans['wifi_tagged'].append(prise) vlans['hotspot_tagged'].append(prise) - vlans['radin_tagged'].append(prise) params['INTERFACES_CONF'] += self.interface_template % prise_params continue - - # A quelle chambre correspond la prise ? - if prise_chbres.has_key(annu_prise) : - chbres = prise_chbres[annu_prise] - elif prise_chbres.has_key(annu_prise+'-') : - # Prise en 10 - prise_params['speed'] = '\n speed-duplex auto-10' - chbres = prise_chbres[annu_prise+'-'] - else : - # Prise non référencée dans l'annuaire - prise_params['nom'] = "Pas_dans_l'annuaire" - prise_params['etat']='\n disable' - params['INTERFACES_CONF'] += self.interface_template % prise_params - continue - + + # Quelle(s) chambre(s) est/sont sur la prise. A cause du + # cas PDJ il peux y avoir des prises avec plusieurs + # chambres. + chbres = prise_chbres.get(annu_prise, []) + + # "unauth-vid" est le vlan sur lequel sont envoyé les + # inconnus, qui est le vlan d'accueil params['INTERFACES_CONF'] += """aaa port-access mac-based %(prise)s aaa port-access mac-based %(prise)s addr-limit %(nbmac)s aaa port-access mac-based %(prise)s logoff-period 3600 +aaa port-access mac-based %(prise)s unauth-vid 7 """ % { 'nbmac': 1+2*len(chbres), 'prise': prise } - ## Configuration de la prise adhérent - # Nom - prise_params['nom'] = 'Chambre' - if len(chbres) > 1 : prise_params['nom'] += 's' - for chbre in chbres : - prise_params['nom'] += '_%s%s' % (bat.upper(), chbre) - - # Besoin d'activer la prise ? - prise_params['etat']='\n disable' - for chbre in chbres : - res = self.db.search('chbre=%s%s' % (bat.upper(), chbre) ) - quelqu_un_a_paye = False - for res in res['adherent'] + res['club'] : - if res.adherentPayant() : - quelqu_un_a_paye = True - if 'bloq' not in res.blacklist_actif() : - prise_params['etat']='' - break - if quelqu_un_a_paye : - # Si quelqu'un a payé on lui met le vlan default - vlans['default_untagged'].append(prise) - else : - # Sinon tout le monde reste sur le vlan radin - vlans['radin_untagged'].append(prise) + # On donne à la prise un nom qui dépend des chambres + # connectés dessus + if chbres : + prise_params['nom'] = 'Chambre' + if len(chbres) > 1 : prise_params['nom'] += 's' + for chbre in chbres : + prise_params['nom'] += '_%s%s' % (bat.upper(), chbre) + else : + prise_params['nom'] = 'Inconnu' params['INTERFACES_CONF'] += self.interface_template % prise_params @@ -442,15 +427,18 @@ aaa port-access mac-based %(prise)s logoff-period 3600 for key, prises in vlans.items() : vlans[key]=mk_list(prises) - # Config des vlan - for v in ('default', 'adm', 'wifi', 'hotspot', 'radin') : + # Config des vlans spéciaux (adm et wifi) + for v in ('adm', 'wifi', 'hotspot') : params['prises_%s' % v] = '' for t in ('tagged' , 'untagged') : if vlans['%s_%s' % (v,t)] : params['prises_%s' % v] += '\n %s %s' % (t, vlans['%s_%s' % (v,t)]) # Saut de ligne parasite params['prises_%s' % v] = params['prises_%s' % v][4:] - + + for name, number in config.vlans: + params["vlan_%s" % name] = number + # Ecriture fd = self._open_conf(self.CONF_REP + switch + '.conf') fd.write(self.config % params) diff --git a/gestion/ldap_crans.py b/gestion/ldap_crans.py index f71e2c8e..7fb905bc 100755 --- a/gestion/ldap_crans.py +++ b/gestion/ldap_crans.py @@ -1661,11 +1661,6 @@ class BaseProprietaire(BaseClasseCrans): ret = '' if self._init_data: nouveau = 0 - # Reconfiguration switch si changement de chambre et si machine fixe - if 'chbre' in self.modifs: - if self.machines_fixes(): - self.services_to_restart('switch', [self._data['chbre'][0]]) - self.services_to_restart('switch', [self._init_data.get('chbre', '')[0]]) else: nouveau = 1 @@ -1701,7 +1696,6 @@ class BaseProprietaire(BaseClasseCrans): self.services_to_restart('conf_wifi_ng') self.services_to_restart('ragnarok-dhcp') else: - self.services_to_restart('switch', [self.chbre()]) self.services_to_restart('rouge-dhcp') # Vérification si changement de bât, ce qui obligerai un changement d'IP @@ -2893,10 +2887,6 @@ class Machine(BaseClasseCrans): if self.proprietaire().__class__ == AssociationCrans and not (isadm() or user_tests.getuser() == 'www-data'): raise EnvironmentError(u'Il faut être administrateur pour effectuer cette opération.') - if not self._init_data: - # Nouvelle machine => configuration prise - self.services_to_restart('switch', [self.proprietaire().chbre()]) - ret = '' # Besoin de redémarrer les firewalls ? diff --git a/radius_auth.py b/radius_auth.py index 5758c956..cd68f4e2 100755 --- a/radius_auth.py +++ b/radius_auth.py @@ -7,7 +7,7 @@ from syslog import * sys.path.append('/usr/scripts/gestion') from ldap_crans import crans_ldap, AssociationCrans -from config import ann_scol, dat +from config import ann_scol, dat, vlans def chap_ok(password, challenge, clear_pass) : """ Test l'authentification chap fournie @@ -28,27 +28,38 @@ def chap_ok(password, challenge, clear_pass) : return False def do_auth(mac): + """Effectue l'authentification. Renvoie (success, msg, + vlan). success est 0 si l'authentification est réussie, msg est + pour les logs et vlan est le vlan non taggé à utiliser pour la + prise.""" + global ann_scol if not chap_ok(os.getenv('CHAP_PASSWORD'), os.getenv('CHAP_CHALLENGE'), mac): - return (-1, "Échec test CHAP") + return (-1, "Échec test CHAP", "") # Mac dans la base LDAP m = crans_ldap(readonly=True).search('mac=%s' % mac)['machine'] - if len(m) != 1: - return (-1, "Pb recherche mac (nb résultat %d!=1)" % len(m)) + if len(m) == 0: + return (0, "Mac inconnue", "accueil") + elif len(m) > 1: + return (-1, "Pb recherche mac (nb résultat %d!=1)" % len(m), "") # N'appartient pas au Crans et n'a pas de prise attribuée # donc sur uplink ou switch non filtré # But : éviter le spoof d'une mac d'une machine clef proprio = m[0].proprietaire() if proprio.__class__ == AssociationCrans and m[0].prise() == u'N/A': - return (-1, "Machine du crans") + return (-1, "Machine du crans", "") # blockliste bloq if 'bloq' in m[0].blacklist_actif(): - return (-1, "Bloquage total des services pour cette machine") + return (-1, "Bloquage total des services pour cette machine", "") + # L'adherent ne paie pas, on le met sur le vlan radin + if not proprio.adherentPayant(): + return (0, "Ne paie pas", "radin") + # Paiment ok ? paid = max(proprio.paiement() + [0]) if dat[1] in (8, 9): @@ -58,17 +69,17 @@ def do_auth(mac): # On laisse 3 jours ou les gens ont une page sur squid ann_scol -= 1 if ann_scol > paid: - return (-1, "Échec test LDAP") + return (0, "N'a pas payé", "accueil") # C'est bon - return (0, "Accès OK") + return (0, "Accès adhérent OK", "adherent") if __name__ == '__main__' : # Test chap (comme cela on est sur que c'est bien un switch qui demande) mac = os.getenv('USER_NAME', '').replace('"', '') # On vérifie si la mac est autorisée - (r, msg) = do_auth(mac) + (r, msg, vlan) = do_auth(mac) # On logue la prise sur laquelle a lieu la tentative openlog("radius_auth.py") @@ -76,6 +87,12 @@ if __name__ == '__main__' : prise = (len(switch) == 6 and (switch[3] + switch[5]) or (switch + "-")) prise += "%02d" % int(os.getenv("NAS_PORT", 0)) syslog("%s -> %s [%s]" % (prise, mac, msg)) - - print msg + + if vlan: + # Cela indique au switch comment configurer le vlan par défaut + # pour cette prise + print ", ".join(["Tunnel-Type = VLAN", + "Tunnel-Medium-Type = IEEE-802", + "Tunnel-Private-Group-Id = \"%d\"" % vlans[vlan]]) + sys.exit(r)