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',
'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 ##
#######################

View file

@ -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)

View file

@ -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 ?

View file

@ -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)