utilisation de radius pour configurer les switchs en live

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
This commit is contained in:
Jeremie Dimino 2008-09-04 06:13:37 +02:00
parent e209f42707
commit 4fd3644f97
4 changed files with 90 additions and 79 deletions

View file

@ -383,6 +383,22 @@ domains = { 'machineFixe': 'crans.org',
'machineWifi': 'wifi.crans.org', 'machineWifi': 'wifi.crans.org',
'borneWifi': '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 ## ## Mail de bienvenue ##
####################### #######################

View file

@ -23,6 +23,7 @@ from annuaires import chbre_prises, uplink_prises, reverse, bat_manuels, all_swi
from random import shuffle from random import shuffle
from gen_confs import * from gen_confs import *
from time import localtime from time import localtime
import config
from annuaires import bat_switchs from annuaires import bat_switchs
@ -57,31 +58,36 @@ logging 10.231.136.7
%(INTERFACES_CONF)s %(INTERFACES_CONF)s
;-------------------------------------------------------- IP du switch ;-------------------------------------------------------- IP du switch
ip default-gateway 10.231.136.4 ip default-gateway 10.231.136.4
vlan 1 vlan %(vlan_adherent)s
name "DEFAULT_VLAN" name "DEFAULT_VLAN"
%(prises_default)s untagged %(prises_default)s
no ip address no ip address
ip igmp ip igmp
no ip igmp querier no ip igmp querier
exit exit
vlan 2 vlan %(vlan_adm)s
name "Adm" name "Adm"
%(prises_adm)s %(prises_adm)s
ip address %(ip)s 255.255.255.0 ip address %(ip)s 255.255.255.0
exit exit
vlan 3 vlan %(vlan_wifi)s
name "Wifi" name "Wifi"
%(prises_wifi)s %(prises_wifi)s
no ip address no ip address
exit exit
vlan 4 vlan %(vlan_hotspot)s
name "Hotspot" name "Hotspot"
%(prises_hotspot)s %(prises_hotspot)s
no ip address no ip address
exit exit
vlan 6 vlan %(vlan_radin)s
name "Radin" 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 no ip address
exit exit
;------------------------------------------------------- Accès d'administration ;------------------------------------------------------- Accès d'administration
@ -116,7 +122,7 @@ no cdp run
no stack no stack
""" """
interface_template = """interface %(prise)i%(etat)s interface_template = """interface %(prise)i enable
name "%(nom)s" name "%(nom)s"
flow-control%(speed)s flow-control%(speed)s
no lacp no lacp
@ -283,8 +289,10 @@ exit
vlans = { 'wifi_tagged' : [] , 'wifi_untagged' : [] , vlans = { 'wifi_tagged' : [] , 'wifi_untagged' : [] ,
'hotspot_tagged' : [], 'hotspot_untagged' : [], 'hotspot_tagged' : [], 'hotspot_untagged' : [],
'adm_tagged' : [] , 'adm_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 # Génération de la conf de chaque prise
for prise in range(1,nb_prises+1): for prise in range(1,nb_prises+1):
@ -299,11 +307,10 @@ exit
### Prise d'uplink ### Prise d'uplink
prise_params['nom'] = uplink_prises[bat][int(annu_prise)] prise_params['nom'] = uplink_prises[bat][int(annu_prise)]
params['uplinks'].append(prise) params['uplinks'].append(prise)
vlans['default_untagged'].append(prise) vlans['default'].append(prise)
vlans['adm_tagged'].append(prise) vlans['adm_tagged'].append(prise)
vlans['wifi_tagged'].append(prise) vlans['wifi_tagged'].append(prise)
vlans['hotspot_tagged'].append(prise) vlans['hotspot_tagged'].append(prise)
vlans['radin_tagged'].append(prise)
params['INTERFACES_CONF'] += self.interface_template % prise_params params['INTERFACES_CONF'] += self.interface_template % prise_params
continue continue
@ -329,7 +336,7 @@ exit
if len(chbres) > 1 : prise_params['nom'] += 's' if len(chbres) > 1 : prise_params['nom'] += 's'
for chbre in chbres : for chbre in chbres :
prise_params['nom'] += '_%s%s' % (bat.upper(), chbre) prise_params['nom'] += '_%s%s' % (bat.upper(), chbre)
vlans['default_untagged'].append(prise) vlans['default'].append(prise)
else : else :
prise_params['nom'] = "Wifi" prise_params['nom'] = "Wifi"
vlans['hotspot_tagged'].append(prise) vlans['hotspot_tagged'].append(prise)
@ -344,58 +351,36 @@ exit
else : else :
# Tous les vlans # Tous les vlans
prise_params['nom'] = "Prise_crans" prise_params['nom'] = "Prise_crans"
vlans['default_untagged'].append(prise) vlans['default'].append(prise)
vlans['adm_tagged'].append(prise) vlans['adm_tagged'].append(prise)
vlans['wifi_tagged'].append(prise) vlans['wifi_tagged'].append(prise)
vlans['hotspot_tagged'].append(prise) vlans['hotspot_tagged'].append(prise)
vlans['radin_tagged'].append(prise)
params['INTERFACES_CONF'] += self.interface_template % prise_params params['INTERFACES_CONF'] += self.interface_template % prise_params
continue continue
# A quelle chambre correspond la prise ? # Quelle(s) chambre(s) est/sont sur la prise. A cause du
if prise_chbres.has_key(annu_prise) : # cas PDJ il peux y avoir des prises avec plusieurs
chbres = prise_chbres[annu_prise] # chambres.
elif prise_chbres.has_key(annu_prise+'-') : chbres = prise_chbres.get(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
# "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 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 addr-limit %(nbmac)s
aaa port-access mac-based %(prise)s logoff-period 3600 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 } """ % { 'nbmac': 1+2*len(chbres), 'prise': prise }
## Configuration de la prise adhérent # On donne à la prise un nom qui dépend des chambres
# Nom # connectés dessus
if chbres :
prise_params['nom'] = 'Chambre' prise_params['nom'] = 'Chambre'
if len(chbres) > 1 : prise_params['nom'] += 's' if len(chbres) > 1 : prise_params['nom'] += 's'
for chbre in chbres : for chbre in chbres :
prise_params['nom'] += '_%s%s' % (bat.upper(), chbre) 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 : else :
# Sinon tout le monde reste sur le vlan radin prise_params['nom'] = 'Inconnu'
vlans['radin_untagged'].append(prise)
params['INTERFACES_CONF'] += self.interface_template % prise_params params['INTERFACES_CONF'] += self.interface_template % prise_params
@ -442,8 +427,8 @@ aaa port-access mac-based %(prise)s logoff-period 3600
for key, prises in vlans.items() : for key, prises in vlans.items() :
vlans[key]=mk_list(prises) vlans[key]=mk_list(prises)
# Config des vlan # Config des vlans spéciaux (adm et wifi)
for v in ('default', 'adm', 'wifi', 'hotspot', 'radin') : for v in ('adm', 'wifi', 'hotspot') :
params['prises_%s' % v] = '' params['prises_%s' % v] = ''
for t in ('tagged' , 'untagged') : for t in ('tagged' , 'untagged') :
if vlans['%s_%s' % (v,t)] : if vlans['%s_%s' % (v,t)] :
@ -451,6 +436,9 @@ aaa port-access mac-based %(prise)s logoff-period 3600
# Saut de ligne parasite # Saut de ligne parasite
params['prises_%s' % v] = params['prises_%s' % v][4:] params['prises_%s' % v] = params['prises_%s' % v][4:]
for name, number in config.vlans:
params["vlan_%s" % name] = number
# Ecriture # Ecriture
fd = self._open_conf(self.CONF_REP + switch + '.conf') fd = self._open_conf(self.CONF_REP + switch + '.conf')
fd.write(self.config % params) fd.write(self.config % params)

View file

@ -1661,11 +1661,6 @@ class BaseProprietaire(BaseClasseCrans):
ret = '' ret = ''
if self._init_data: if self._init_data:
nouveau = 0 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: else:
nouveau = 1 nouveau = 1
@ -1701,7 +1696,6 @@ class BaseProprietaire(BaseClasseCrans):
self.services_to_restart('conf_wifi_ng') self.services_to_restart('conf_wifi_ng')
self.services_to_restart('ragnarok-dhcp') self.services_to_restart('ragnarok-dhcp')
else: else:
self.services_to_restart('switch', [self.chbre()])
self.services_to_restart('rouge-dhcp') self.services_to_restart('rouge-dhcp')
# Vérification si changement de bât, ce qui obligerai un changement d'IP # 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'): 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.') 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 = '' ret = ''
# Besoin de redémarrer les firewalls ? # Besoin de redémarrer les firewalls ?

View file

@ -7,7 +7,7 @@ from syslog import *
sys.path.append('/usr/scripts/gestion') sys.path.append('/usr/scripts/gestion')
from ldap_crans import crans_ldap, AssociationCrans 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) : def chap_ok(password, challenge, clear_pass) :
""" Test l'authentification chap fournie """ Test l'authentification chap fournie
@ -28,26 +28,37 @@ def chap_ok(password, challenge, clear_pass) :
return False return False
def do_auth(mac): 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 global ann_scol
if not chap_ok(os.getenv('CHAP_PASSWORD'), os.getenv('CHAP_CHALLENGE'), mac): 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 # Mac dans la base LDAP
m = crans_ldap(readonly=True).search('mac=%s' % mac)['machine'] m = crans_ldap(readonly=True).search('mac=%s' % mac)['machine']
if len(m) != 1: if len(m) == 0:
return (-1, "Pb recherche mac (nb résultat %d!=1)" % len(m)) 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 # N'appartient pas au Crans et n'a pas de prise attribuée
# donc sur uplink ou switch non filtré # donc sur uplink ou switch non filtré
# But : éviter le spoof d'une mac d'une machine clef # But : éviter le spoof d'une mac d'une machine clef
proprio = m[0].proprietaire() proprio = m[0].proprietaire()
if proprio.__class__ == AssociationCrans and m[0].prise() == u'N/A': if proprio.__class__ == AssociationCrans and m[0].prise() == u'N/A':
return (-1, "Machine du crans") return (-1, "Machine du crans", "")
# blockliste bloq # blockliste bloq
if 'bloq' in m[0].blacklist_actif(): 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 ? # Paiment ok ?
paid = max(proprio.paiement() + [0]) paid = max(proprio.paiement() + [0])
@ -58,17 +69,17 @@ def do_auth(mac):
# On laisse 3 jours ou les gens ont une page sur squid # On laisse 3 jours ou les gens ont une page sur squid
ann_scol -= 1 ann_scol -= 1
if ann_scol > paid: if ann_scol > paid:
return (-1, "Échec test LDAP") return (0, "N'a pas payé", "accueil")
# C'est bon # C'est bon
return (0, "Accès OK") return (0, "Accès adhérent OK", "adherent")
if __name__ == '__main__' : if __name__ == '__main__' :
# Test chap (comme cela on est sur que c'est bien un switch qui demande) # Test chap (comme cela on est sur que c'est bien un switch qui demande)
mac = os.getenv('USER_NAME', '').replace('"', '') mac = os.getenv('USER_NAME', '').replace('"', '')
# On vérifie si la mac est autorisée # 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 # On logue la prise sur laquelle a lieu la tentative
openlog("radius_auth.py") openlog("radius_auth.py")
@ -77,5 +88,11 @@ if __name__ == '__main__' :
prise += "%02d" % int(os.getenv("NAS_PORT", 0)) prise += "%02d" % int(os.getenv("NAS_PORT", 0))
syslog("%s -> %s [%s]" % (prise, mac, msg)) 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) sys.exit(r)