scripts/gestion/gen_confs/bind.py
cohen 51509e973a Ajouts de paramtres Sender Policy Framework aux DNS.
darcs-hash:20061119225001-f6463-1c02171c994003f25e45b11276b74dad2919afcc.gz
2006-11-19 23:50:01 +01:00

263 lines
10 KiB
Python
Executable file

#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
""" Génération de la configuration pour bind9
Copyright (C) Frédéric Pauget
Licence : GPLv2
"""
import time, sys
sys.path.append('/usr/scripts/gestion')
from gen_confs import gen_config
from iptools import AddrInNet, AddrInNets
class dns(gen_config) :
"""
Génération des fichiers de configuration de bind9 :
* fichier DNS_CONF qui contient les définitions de zone conformément
à zone_template. Ce fichier doit être inclus à partir de la config statique
de bind
* les fichiers de zones, ce sont eux qui contiennent les données du
dns, ils ont appellés par le fichier DNS_CONF et sont générés dans DNS_DIR
Leur entète est générée à partir de zone_entete.
Les fichiers générés placent bind comme autoritaire sur les noms de
zones_direct et les adresses de zones_reverse. Les données proviennent de
la base LDAP
"""
######################################PARTIE DE CONFIGURATION
### Fichiers à écrire
# Répertoire d'écriture des fichiers de zone
DNS_DIR='/etc/bind/generated/' # Avec un / à la fin
# Fichier de définition des zones pour le maître
DNS_CONF=DNS_DIR + 'zones_crans'
### Sur quelles zones on a autorité ?
## En cas de modification de ces zones penser à regéner le fichier de
## zone des esclaves (python /usr/scripts/gestion/gen_confs/bind.py)
# Résolution directe
zones_direct = [ 'crans.org' , 'crans.ens-cachan.fr', 'wifi.crans.org' , 'ferme.crans.org' , 'clubs.ens-cachan.fr', 'adm.crans.org' ]
# Résolution inverse
zones_reverse = [ '138.231.136.0/21', '138.231.144.0/24', '138.231.148.0/22' ]
### Liste DNS
# Le premier est doit être le maitre
DNSs = [ 'rouge.crans.org' , 'sila.crans.org' , 'freebox.crans.org' ]
### Liste des délégations de zone
# Pour les demandes des ces zones, le DNS dira d'aller voir les serveurs listés ici
# Pour les noms des serveurs on met l'IP sans point ou le nom avec un point
DELEG = { 'tv.crans.org' : ['rouge.crans.org.' , 'sila.crans.org.' , 'freebox.crans.org.', 'mouton.ferme.crans.org.'] }
### Serveurs de mail
# format : [ priorité serveur , .... ]
MXs = ['10 smtp.crans.org', '20 freebox.crans.org' ]
### Entète des fichiers de zone
zone_entete="""
$ORIGIN %(zone)s.
$TTL 86400
@\tIN\tSOA rouge.crans.org. root.crans.org. (
%(serial)i ; numero de serie
21600 ; refresh (s)
3600 ; retry (s)
1209600 ; expire (s)
86400 ; TTL (s)
)
"""
# Syntaxe utilisée dans le fichier DNS_CONF pour définir une zone sur le maître
zone_template="""
zone "%(NOM_zone)s" {
type master;
file "%(FICHIER_zone)s";
};
"""
# Syntaxe utilisée dans le fichier DNS_CONF pour définir une zone sur le maître
zone_template_slave="""
zone "%(NOM_zone)s" {
type slave;
file "%(FICHIER_zone)s";
masters { 138.231.136.3; };
};
"""
### Verbosité
# Si =2, ralera (chaine warnings) si machines hors zone trouvée
# Si =1, comme ci-dessus, mais ne ralera pas pour freebox
# Si =0, ralera seulement contre les machines ne pouvant être classées
verbose = 1
restart_cmd = '/etc/init.d/bind9 reload'
######################################FIN PARTIE DE CONFIGURATION
def __str__(self) :
return "DNS"
def gen_slave(self) :
""" Génération du fichier de config de zone pour les esclaves """
zones = self.zones_direct
# Ajout des zones reverse
for net in self.zones_reverse :
n = map(int,net.split('/')[0].split('.')[:3])
while 1 :
if not AddrInNet("%d.%d.%d.1" % tuple(n),net):
break
else :
n.reverse()
zones.append("%d.%d.%d.in-addr.arpa" % tuple(n))
n.reverse()
n[2] += 1
# Ecriture
fd = self._open_conf(self.DNS_CONF,'//')
for zone in zones :
fd.write(self.zone_template_slave % { 'NOM_zone' : zone,
'FICHIER_zone' : self.DNS_DIR + 'db.' + zone })
fd.close()
def _gen(self) :
### Génération du numéro de série
# Le + 1000.... s'explique pas l'idée précédente et peu pratique d'avoir
# le numéro de série du type AAAAMMJJNN (année, mois, jour, incrément par jour)
serial = time.time() + 1000000000
### DNS
DNS='; DNS de la zone par ordre de priorité\n'
for d in self.DNSs :
DNS += '@\tIN\tNS %s.\n' % d
DNS += '\n'
### Serveurs de mail
MX='; Serveurs de mails\n'
for m in self.MXs :
MX += '%(zone)s.\t' # Sera remplacé par le nom de zone plus tard
MX += 'IN\tMX\t%s.\n' % m
MX += '\n'
direct = {} # format : { zone : [ lignes correspondantes] }
reverse = {}
warnings = ''
# P'tit lien vers irc.rezosup.org
direct["crans.org"] = "\n; irc.crans.org -> irc.rezosup.org\n"
direct["crans.org"] += "irc\tIN\tCNAME\tirc.rezosup.org.\n\n"
### Ajout des parametres SPF
direct['crans.org'] +='; Parametres SPF\n'
direct['crans.org'] +='crans.org.\tIN\tTXT\t"v=spf1 a +all"'
direct['crans.ens-cachan.fr'] +='; Parametres SPF\n'
direct['crans.ens-cachan.fr'] +='crans.ens-cachan.fr.\tIN\tTXT\t"v=spf1 a:crans.org +all"'
### Tri des machines
self.anim.iter=len(self.machines)
for machine in self.machines :
self.anim.cycle()
# Calculs préliminaires
try :
nom , zone = machine.nom().split('.',1)
zone = zone.encode('iso-8859-1')
except :
warnings += u'Machine ignorée (mid=%s) : format nom incorrect (%s)\n' % ( machine.id().encode('iso-8859-1'), machine.nom().encode('iso-8859-1') )
continue
# Le direct
if zone in self.zones_direct :
ligne = "%s\tIN\tA\t%s\n" % ( nom, machine.ip() )
try : direct[zone] += ligne
except : direct[zone] = ligne
elif self.verbose :
warnings += u'Résolution directe ignorée (mid=%s) : zone non autoritaire (%s)\n' % ( machine.id().encode('iso-8859-1'), zone.encode('iso-8859-1') )
# Le direct avec alias
for alias in machine.alias() :
# Cas particulier : nom de l'alias = nom de la zone
if alias in self.zones_direct :
ligne = "@\tIN\tA\t%s\n" % machine.ip()
ligne = ligne.encode('iso-8859-1')
alias = alias.encode('iso-8859-1')
try : direct[alias] += ligne
except : direct[alias] = ligne
continue
# Bon format ?
alias_l = alias.split('.')
ok = 0
for i in range(len(alias_l)) :
zone_essai = '.'.join(alias_l[i:])
if zone_essai in self.zones_direct :
# On est autoritaire sur cette zone
# On place donc l'alias dans le fichier de cette zone
zone = zone_essai
nom = '.'.join(alias_l[:i])
ok = 1
break
if not ok:
warnings += u'Alias ignoré (mid=%s) : %s\n' % ( machine.id().encode('iso-8859-1'), alias.encode('iso-8859-1') )
continue
zone = zone.encode('iso-8859-1')
ligne = "%s\tIN\tCNAME\t%s.\n" % ( nom, machine.nom() )
try : direct[zone] += ligne
except : direct[zone] = ligne
# Le reverse
if AddrInNets(machine.ip(), self.zones_reverse) :
base_ip = machine.ip().split('.')
base_ip.reverse()
zone = "%s.%s.%s.in-addr.arpa" % tuple(base_ip[1:])
zone = zone.encode('iso-8859-1')
ligne = '%s\tIN\tPTR\t%s.\n' % (base_ip[0],machine.nom())
try : reverse[zone] += ligne
except : reverse[zone] = ligne
elif self.verbose >= 2 or machine.nom() not in ('freebox.crans.org', 'mosan.crans.org'):
warnings += u'Résolution inverse ignorée (mid=%s) : ip sur zone non autoritaire (%s)\n' % ( machine.id().encode('iso-8859-1'), machine.ip().encode('iso-8859-1') )
### Ajouts pour les fichiers de résolution directs
for zone in direct.keys() :
# MXs
direct[zone] = MX % { 'zone' : zone } + direct[zone]
### Ajout des délégations de zones
for deleg in self.DELEG.keys():
nom, zone = deleg.split('.',1)
if not zone in direct.keys():
warnings += u'Délégation ignorée %s : on ne génère pas la zone parent\n' % deleg
continue
for serv in self.DELEG[deleg]:
direct[zone] = direct[zone] + "%s\tIN\tNS\t%s\n" % ( nom, serv )
### Ecriture des fichiers de zone et préparation du fichier de définition
f = ''
for zone, lignes in direct.items() + reverse.items() :
file = self.DNS_DIR + 'db.' + zone
fd = self._open_conf(file,';')
fd.write(self.zone_entete % \
{ 'zone' : zone, 'serveur_autoritaire' : self.DNSs[0] , 'serial' : serial } )
fd.write('\n')
fd.write(DNS)
fd.write(lignes)
fd.close()
f += self.zone_template % { 'NOM_zone' : zone, 'FICHIER_zone' : file }
### Ecriture fichier de définition
fd = self._open_conf(self.DNS_CONF,'//')
fd.write(f)
fd.close()
return warnings
if __name__ == '__main__' :
from socket import gethostname
if gethostname().split(".")[0] == 'rouge' :
print "Ce serveur est maître !, utiliser generate."
else :
print "Reconfiguration de bind en esclave (penser à le relancer)."
c = dns()
c.gen_slave()