Commentaires et nettoyage dans bind.
This commit is contained in:
parent
15e83e1844
commit
4b652b69b6
3 changed files with 415 additions and 156 deletions
|
@ -3,8 +3,10 @@
|
|||
|
||||
""" Variables de configuration pour la gestion du DNS """
|
||||
|
||||
import os
|
||||
|
||||
# import des variables génériques
|
||||
import config
|
||||
import gestion.config as config
|
||||
|
||||
#: ariane et ariane2 pour la zone parente
|
||||
parents = [
|
||||
|
@ -31,17 +33,61 @@ zone_tv = 'tv.crans.org'
|
|||
secours_relay = '10.231.136.14';
|
||||
|
||||
#: Serveurs autoritaires pour les zones crans, le master doit être le premier
|
||||
DNSs = ['sable.crans.org', 'freebox.crans.org', 'soyouz.crans.org']
|
||||
DNSs = [
|
||||
'sable.crans.org',
|
||||
'freebox.crans.org',
|
||||
'soyouz.crans.org',
|
||||
]
|
||||
|
||||
MXs = {
|
||||
'redisdead.crans.org': {
|
||||
'prio': 10,
|
||||
'spf': 'v=spf1 ptr ~all',
|
||||
},
|
||||
'freebox.crans.org': {
|
||||
'prio': 25,
|
||||
'spf': 'v=spf1 ptr ~all',
|
||||
},
|
||||
'soyouz.crans.org': {
|
||||
'prio': 15,
|
||||
'spf': 'v=spf1',
|
||||
},
|
||||
}
|
||||
|
||||
#: Résolution DNS directe, liste de toutes les zones crans hors reverse
|
||||
zones_direct = [ 'crans.org', 'crans.ens-cachan.fr', 'wifi.crans.org', 'clubs.ens-cachan.fr', 'adm.crans.org','crans.eu','wifi.crans.eu', 'tv.crans.org', 'ap.crans.org' ]
|
||||
zones_direct = [
|
||||
'crans.org',
|
||||
'crans.ens-cachan.fr',
|
||||
'wifi.crans.org',
|
||||
'clubs.ens-cachan.fr',
|
||||
'adm.crans.org',
|
||||
'crans.eu',
|
||||
'wifi.crans.eu',
|
||||
'tv.crans.org',
|
||||
'ap.crans.org',
|
||||
]
|
||||
#: Les zones apparaissant dans des objets lc_ldap
|
||||
zones_ldap = [ 'crans.org', 'crans.ens-cachan.fr', 'wifi.crans.org', 'clubs.ens-cachan.fr', 'adm.crans.org', 'tv.crans.org' ]
|
||||
zones_ldap = [
|
||||
'crans.org',
|
||||
'crans.ens-cachan.fr',
|
||||
'wifi.crans.org',
|
||||
'clubs.ens-cachan.fr',
|
||||
'adm.crans.org',
|
||||
'tv.crans.org',
|
||||
]
|
||||
#: Zones signée par opendnssec sur le serveur master
|
||||
zones_dnssec = ['crans.org', 'wifi.crans.org', 'adm.crans.org', 'tv.crans.org', 'crans.eu']
|
||||
zones_dnssec = [
|
||||
'crans.org',
|
||||
'wifi.crans.org',
|
||||
'adm.crans.org',
|
||||
'tv.crans.org',
|
||||
'crans.eu',
|
||||
]
|
||||
#: Zones alias : copie les valeur des enregistrement pour la racine de la zone et utilise un enregistemenr DNAME pour les sous domaines
|
||||
zone_alias = {
|
||||
'crans.org' : ['crans.eu'],
|
||||
'crans.org' : [
|
||||
'crans.eu',
|
||||
],
|
||||
}
|
||||
|
||||
#: Résolution inverse v4
|
||||
|
@ -51,15 +97,49 @@ zones_reverse_v6 = config.prefix['fil'] + config.prefix['wifi'] + config.prefix
|
|||
|
||||
#: Serveurs DNS récursifs :
|
||||
recursiv = {
|
||||
'fil' : ['138.231.136.98', '138.231.136.152'],
|
||||
'wifi' : ['138.231.136.98', '138.231.136.152'],
|
||||
'evenementiel' : ['138.231.136.98', '138.231.136.152'],
|
||||
'adm' : ['10.231.136.98', '10.231.136.152'],
|
||||
'gratuit' : ['10.42.0.164'],
|
||||
'accueil' : ['10.51.0.10'],
|
||||
'isolement' : ['10.52.0.10'],
|
||||
'personnel-ens' : ['10.2.9.10', '138.231.136.98', '138.231.136.152'],
|
||||
'fil' : [
|
||||
'138.231.136.98',
|
||||
'138.231.136.152',
|
||||
],
|
||||
'wifi' : [
|
||||
'138.231.136.98',
|
||||
'138.231.136.152',
|
||||
],
|
||||
'evenementiel' : [
|
||||
'138.231.136.98',
|
||||
'138.231.136.152',
|
||||
],
|
||||
'adm' : [
|
||||
'10.231.136.98',
|
||||
'10.231.136.152',
|
||||
],
|
||||
'gratuit' : [
|
||||
'10.42.0.164',
|
||||
],
|
||||
'accueil' : [
|
||||
'10.51.0.10',
|
||||
],
|
||||
'isolement' : [
|
||||
'10.52.0.10',
|
||||
],
|
||||
'personnel-ens' : [
|
||||
'10.2.9.10',
|
||||
'138.231.136.98',
|
||||
'138.231.136.152',
|
||||
],
|
||||
}
|
||||
|
||||
#: Les ip/net des vlans limité vue par les récursifs
|
||||
menteur_clients = [ "138.231.136.210", "138.231.136.10" ] + config.prefix['evenementiel']
|
||||
menteur_clients = [
|
||||
"138.231.136.210",
|
||||
"138.231.136.10",
|
||||
] + config.prefix['evenementiel']
|
||||
|
||||
# Chemins de fichiers/dossiers utiles.
|
||||
DNS_DIR = '/etc/bind/generated/'
|
||||
DNSSEC_DIR = '/etc/bind/signed/'
|
||||
# Fichier de définition des zones pour le maître
|
||||
DNS_CONF = os.path.join(DNS_DIR, 'zones_crans')
|
||||
|
||||
# Fichier de définition des zones pour les esclaves géré par BCfg2
|
||||
DNS_CONF_BCFG2 = "/var/lib/bcfg2/Cfg/etc/bind/generated/zones_crans/zones_crans"
|
||||
|
|
|
@ -6,6 +6,7 @@ Copyright (C) Valentin Samir
|
|||
Licence : GPLv3
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import ssl
|
||||
import time
|
||||
|
@ -37,24 +38,31 @@ def short_name(fullhostname):
|
|||
return fullhostname.split(".")[0]
|
||||
|
||||
class ResourceRecord(object):
|
||||
def __init__(self, type, name, value, ttl=None):
|
||||
self._type=type
|
||||
self._name=name
|
||||
self._value=value
|
||||
"""Classe standard définissant une ressource DNS"""
|
||||
|
||||
def __init__(self, r_type, name, value, ttl=None):
|
||||
"""Affecte les valeurs de base de l'enregistrement"""
|
||||
self.r_type = r_type
|
||||
self.name = name
|
||||
self.value = value
|
||||
self._ttl = ttl
|
||||
|
||||
def __str__(self):
|
||||
"""Retourne une chaîne printable dans un fichier bind"""
|
||||
if self._ttl:
|
||||
return "%s\t%s\tIN\t%s\t%s" % (self._name, self._ttl, self._type, self._value)
|
||||
return "%s\t%s\tIN\t%s\t%s" % (self.name, self._ttl, self.r_type, self.value)
|
||||
else:
|
||||
return "%s\tIN\t%s\t%s" % (self._name, self._type, self._value)
|
||||
return "%s\tIN\t%s\t%s" % (self.name, self.r_type, self.value)
|
||||
|
||||
def __repr__(self):
|
||||
"""__repr__ == __str__"""
|
||||
return str(self)
|
||||
|
||||
class TLSA(ResourceRecord):
|
||||
def __init__(self, name, port, proto, cert, certtype, reftype, selector=0, compat=True, format='pem', ttl=None):
|
||||
"""
|
||||
name: nom du domaine du certificat
|
||||
"""Enregistrement TLSA pour stocker des certifs dans un enregistrement DNS"""
|
||||
|
||||
def __init__(self, name, port, proto, cert, certtype, reftype, selector=0, compat=True, r_format='pem', ttl=None):
|
||||
""" name: nom du domaine du certificat
|
||||
port: port où écoute le service utilisant le certificat
|
||||
proto: udp ou tcp
|
||||
cert: le certificat au format ``format`` (pem ou der) (selector est donc toujours à 0)
|
||||
|
@ -62,8 +70,9 @@ class TLSA(ResourceRecord):
|
|||
reftype: 0 = plain cert, 1 = sha256, 2 = sha512
|
||||
compat: on génère un enregistement compris même par les serveurs dns n'implémentant pas TLSA
|
||||
"""
|
||||
if not format in ['pem', 'der']:
|
||||
if not r_format in ['pem', 'der']:
|
||||
raise ValueError("format should be pem or der")
|
||||
|
||||
if cert is None and proto == 'tcp' and name[-1] == '.':
|
||||
try:
|
||||
cert = ssl.get_server_certificate((name[:-1], port), ca_certs='/etc/ssl/certs/ca-certificates.crt')
|
||||
|
@ -71,12 +80,15 @@ class TLSA(ResourceRecord):
|
|||
raise ValueError("Unable de retrieve cert dynamically: %s" % e)
|
||||
elif cert is None:
|
||||
raise ValueError("cert can only be retrive if proto is tcp and name fqdn")
|
||||
if format is not 'der':
|
||||
|
||||
if r_format is not 'der':
|
||||
dercert = ssl.PEM_cert_to_DER_cert(cert)
|
||||
else:
|
||||
dercert = cert
|
||||
|
||||
if not dercert:
|
||||
raise ValueError("Impossible de convertir le certificat au format DER %s %s %s\n%s" % (name, port, proto, cert))
|
||||
|
||||
certhex = TLSA.hashCert(reftype, str(dercert))
|
||||
if compat:
|
||||
super(TLSA, self).__init__(
|
||||
|
@ -95,7 +107,7 @@ class TLSA(ResourceRecord):
|
|||
|
||||
@staticmethod
|
||||
def hashCert(reftype, certblob):
|
||||
"""
|
||||
"""Retourne un hash d'un certif DER en MAJUSCULES.
|
||||
certblob: un certificat au format DER
|
||||
"""
|
||||
if reftype == 0:
|
||||
|
@ -111,98 +123,164 @@ class TLSA(ResourceRecord):
|
|||
return hashobj.hexdigest().upper()
|
||||
|
||||
class SOA(ResourceRecord):
|
||||
"""Ressource pour une entrée DNS SOA"""
|
||||
def __init__(self, master, email, serial, refresh, retry, expire, ttl):
|
||||
super(SOA, self).__init__('SOA', '@', '%s. %s. (\n %s ; numero de serie\n %s ; refresh (s)\n %s ; retry (s)\n %s ; expire (s)\n %s ; TTL (s)\n )' % (master, email, serial, refresh, retry, expire, ttl))
|
||||
|
||||
class A(ResourceRecord):
|
||||
"""Entrée DNS pour une IPv4"""
|
||||
def __init__(self, name, value, ttl=None):
|
||||
super(A, self).__init__('A', name, value, ttl)
|
||||
|
||||
class DS(ResourceRecord):
|
||||
"""Entrée DNS pour l'empreinte d'une clef DNSSEC"""
|
||||
def __init__(self, name, value, ttl=None):
|
||||
super(DS, self).__init__('DS', name, value, ttl)
|
||||
|
||||
class PTR(ResourceRecord):
|
||||
"""Entrée DNS inverse (pour obtenir l'IP à partir du NDD"""
|
||||
def __init__(self, name, value, ttl=None):
|
||||
super(PTR, self).__init__('PTR', name, value, ttl)
|
||||
|
||||
class AAAA(ResourceRecord):
|
||||
"""Entrée DNS pour une IPv6"""
|
||||
def __init__(self, name, value, ttl=None):
|
||||
super(AAAA, self).__init__('AAAA', name, value, ttl)
|
||||
|
||||
class TXT(ResourceRecord):
|
||||
"""Entrée DNS pour un champ TXT"""
|
||||
def __init__(self, name, value, ttl=None):
|
||||
super(TXT, self).__init__('TXT', name, value, ttl)
|
||||
|
||||
class CNAME(ResourceRecord):
|
||||
"""Entrée DNS pour un alias (toto -> redisdead)"""
|
||||
def __init__(self, name, value, ttl=None):
|
||||
super(CNAME, self).__init__('CNAME', name, value, ttl)
|
||||
|
||||
class DNAME(ResourceRecord):
|
||||
"""Entrée DNS pour un alias de domaine (crans.eu -> crans.org)"""
|
||||
def __init__(self, name, value, ttl=None):
|
||||
super(DNAME, self).__init__('DNAME', name, value, ttl)
|
||||
|
||||
class MX(ResourceRecord):
|
||||
"""Entrée DNS pour un serveur mail. crans.org IN MX 5 redisdead.crans.org veut dire
|
||||
que redisdead est responsable de recevoir les mails destinés à toto@crans.org avec
|
||||
une priorité 5 (plus c'est faible, plus c'est prioritaire.
|
||||
"""
|
||||
def __init__(self, name, priority, value, ttl=None):
|
||||
super(MX, self).__init__('MX', name, '%s\t%s' % (priority, value), ttl)
|
||||
|
||||
class NS(ResourceRecord):
|
||||
"""Entrée DNS pour donner les serveurs autoritaires pour un nom de domaine"""
|
||||
def __init__(self, name, value, ttl=None):
|
||||
super(NS, self).__init__('NS', name, value, ttl)
|
||||
|
||||
class SPF(ResourceRecord):
|
||||
"""Entrée DNS pour les champs SPF"""
|
||||
def __init__(self, name, value, ttl=None):
|
||||
super(SPF, self).__init__('SPF', name, value, ttl)
|
||||
|
||||
class SRV(ResourceRecord):
|
||||
"""Entrée DNS pour les champs SRV"""
|
||||
def __init__(self, service, proto, priority, weight, port, target, ttl=None):
|
||||
super(SRV, self).__init__('SRV', '_%s._%s' % (service, proto), '%s\t%s\t%s\t%s' % (priority, weight, port, target), ttl)
|
||||
|
||||
class NAPTR(ResourceRecord):
|
||||
"""Entrée DNS pour les NAPTR"""
|
||||
def __init__(self, name, order, preference, flag, service, replace_regexpr, value, ttl=None):
|
||||
super(NAPTR, self).__init__('NAPTR', name, '%s\t%s\t"%s"\t"%s"\t"%s"\t%s' % (order, preference, flag, service, replace_regexpr, value), ttl)
|
||||
|
||||
class SSHFP(ResourceRecord):
|
||||
def __init__(self, name, hash, algo, key, ttl=None):
|
||||
if not hash in config.sshfp_hash.keys():
|
||||
raise ValueError('Hash %s invalid, valid hash are %s' % (hash, ', '.join(config.sshfp_host.keys())))
|
||||
"""Entrée DNS stockant une fingerprint SSH"""
|
||||
def __init__(self, name, r_hash, algo, key, ttl=None):
|
||||
"""Vérifie que hash/algo sont supportés dans la config"""
|
||||
if not r_hash in config.sshfp_hash.keys():
|
||||
raise ValueError('Hash %s invalid, valid hash are %s' % (r_hash, ', '.join(config.sshfp_hash.keys())))
|
||||
|
||||
if not algo in config.sshfp_algo.keys():
|
||||
raise ValueError('Algo %s unknown, valid values are %s' % (algo, ', '.join(config.sshfp_algo.keys())))
|
||||
super(SSHFP, self).__init__('SSHFP', name, '%s\t%s\t%s' % (config.sshfp_algo[algo][0], config.sshfp_hash[hash], getattr(hashlib, hash)(base64.b64decode(key)).hexdigest()), ttl)
|
||||
|
||||
class ZoneBase(object):
|
||||
super(SSHFP, self).__init__('SSHFP', name, '%s\t%s\t%s' % (config.sshfp_algo[algo][0], config.sshfp_hash[r_hash], getattr(hashlib, r_hash)(base64.b64decode(key)).hexdigest()), ttl)
|
||||
|
||||
class ZoneBase(list):
|
||||
"""Classe abstraite décrivant une zone.
|
||||
|
||||
Elle surcharge une liste, car l'ensemble des enregistrements de cette
|
||||
zone sera contenu en elle-même."""
|
||||
def __init__(self, zone_name):
|
||||
self._rrlist=[]
|
||||
"""Affecte un nom de zone"""
|
||||
super(ZoneBase, self).__init__()
|
||||
self.zone_name = zone_name
|
||||
|
||||
self.ttl = 3600
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s %s>" % (self.__class__.__name__, self.zone_name)
|
||||
|
||||
def __str__(self):
|
||||
ret="%s\n$ORIGIN %s.\n$TTL %s\n" % (disclamer.replace('//', ';'), self.zone_name, self.ttl)
|
||||
for rr in self._rrlist:
|
||||
ret+="%s\n" % rr
|
||||
return ret
|
||||
"""Version enregistrable en fichier d'une zone."""
|
||||
_ret = "%s\n$ORIGIN %s.\n$TTL %s\n" % (disclamer.replace('//', ';'), self.zone_name, self.ttl)
|
||||
for rr in self:
|
||||
_ret += "%s\n" % rr
|
||||
return _ret
|
||||
|
||||
def add(self, rr):
|
||||
"""Ajout d'un enregistrement DNS"""
|
||||
if isinstance(rr, ResourceRecord):
|
||||
self._rrlist.append(rr)
|
||||
self.append(rr)
|
||||
else:
|
||||
raise ValueError("You can only add ResourceRecords to a Zone")
|
||||
def extend(self, rr_list):
|
||||
for rr in rr_list:
|
||||
self.add(rr)
|
||||
|
||||
def write(self, path):
|
||||
"""Pour dumper le tout dans le fichier idoine."""
|
||||
with open(path, 'w') as f:
|
||||
f.write("%s" % self)
|
||||
|
||||
|
||||
|
||||
class ZoneClone(ZoneBase):
|
||||
"""Zone clone d'une autre zone."""
|
||||
def __init__(self, zone_name, zone_clone, soa):
|
||||
"""La zone clone possède, outre son nom, un pointeur vers
|
||||
la zone qu'elle duplique.
|
||||
|
||||
Le SOA est fourni manuellement, et la première entrée de la zone clonée
|
||||
est ignorée. (c'est a priori le SOA de celle-ci)
|
||||
"""
|
||||
super(ZoneClone, self).__init__(zone_name)
|
||||
self.zone_clone = zone_clone
|
||||
self.ttl = zone_clone.ttl
|
||||
|
||||
# On met un SOA custom.
|
||||
self.add(soa)
|
||||
|
||||
# On ajoute un DNAME, qui indique que la zone est un clone.
|
||||
self.add(DNAME('', "%s." % self.zone_clone.zone_name))
|
||||
for rr in self.zone_clone._rrlist[1:]:
|
||||
if rr._name in ['', '@']:
|
||||
|
||||
# Et on extrait les données nécessaires de la zone clônée
|
||||
# à savoir, celles de l'apex (la base du domaine, qui elle
|
||||
# n'est pas clônée, seuls les sous-domaines le sont)
|
||||
for rr in self.zone_clone[1:]:
|
||||
# Si pas de nom ou si le nom est @, on duplique bêtement l'enregistrement
|
||||
if rr.name in ['', '@']:
|
||||
self.add(rr)
|
||||
if rr._name in ["%s." % self.zone_clone.zone_name]:
|
||||
self.add(ResourceRecord(rr._type, "%s." % self.zone_name, rr._value))
|
||||
|
||||
# Si le nom de domaine concerné est celui de la zone clonée, pareil, on
|
||||
# "duplique", en créant un enregistrement idoine.
|
||||
if rr.name in ["%s." % self.zone_clone.zone_name]:
|
||||
self.add(ResourceRecord(rr.r_type, "%s." % self.zone_name, rr.value))
|
||||
|
||||
|
||||
class Zone(ZoneBase):
|
||||
def __init__(self, zone_name, ttl, soa, ns_list, ipv6=True, ipv4=True, other_zones=[]):
|
||||
"""Une zone standard"""
|
||||
def __init__(self, zone_name, ttl, soa, ns_list, ipv6=True, ipv4=True, other_zones=None):
|
||||
"""Héritage, plus quelques propriétés en plus
|
||||
|
||||
On définit ici si la zone comporte des ipv4/ipv6,
|
||||
ainsi que des données utiles pour le comportement de celles-ci.
|
||||
|
||||
other_zones contient la liste de sous-zones "indépendantes".
|
||||
(exemple avec wifi.crans.org qui est une sous-zone de crans.org)"""
|
||||
|
||||
if other_zones is None:
|
||||
other_zones = []
|
||||
super(Zone, self).__init__(zone_name)
|
||||
self.ttl = ttl
|
||||
self.ipv4 = ipv4
|
||||
|
@ -215,13 +293,24 @@ class Zone(ZoneBase):
|
|||
self.add(NS('@', '%s.' % ns))
|
||||
|
||||
def name_in_subzone(self, hostname):
|
||||
"""Teste si le nom qu'on observe est dans une
|
||||
sous-zone (toto.wifi.crans.org. est dans wifi.crans.org., et non
|
||||
dans crans.org..
|
||||
"""
|
||||
for zone in self.subzones:
|
||||
if str(hostname).endswith(".%s" % zone):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_name(self, hostname):
|
||||
# le hostname fini bien par la zone courante, et il n'appartient pas à une sous-zone
|
||||
"""Retourne la base du nom d'un hôte. Teste si celui-ci appartient bien
|
||||
à la zone courante et s'il n'est pas lié à une sous-zone.
|
||||
|
||||
Si tout est bon, le nom peut valoir "", auquel cas, l'entrée concerne le domaine
|
||||
courant, donc @.
|
||||
|
||||
Dans le cas où ce nom ne devrait pas être là, on retourne None.
|
||||
"""
|
||||
if str(hostname) == self.zone_name or str(hostname).endswith(".%s" % self.zone_name) and not self.name_in_subzone(hostname):
|
||||
ret = str(hostname)[0:-len(self.zone_name)-1]
|
||||
if ret == "":
|
||||
|
@ -232,65 +321,90 @@ class Zone(ZoneBase):
|
|||
return None
|
||||
|
||||
def get_name_vi(self, nom, i):
|
||||
"""Kludge foireux pour retourner toto.v4.crans.org à partir
|
||||
de toto.crans.org (sous-zones v4/v6)."""
|
||||
if not i in [4, 6]:
|
||||
raise ValueError("i should be 4 or 6")
|
||||
if nom == '@':
|
||||
return 'v%s' % i
|
||||
# On considère que le "vrai" nom est la partie avant le premier .
|
||||
elif '.' in nom:
|
||||
nom_1, nom_2 = nom.split('.', 1)
|
||||
return "%s.v%s.%s" % (nom_1, i, nom_2)
|
||||
else:
|
||||
return "%s.v%s" % (nom, i)
|
||||
|
||||
def add_delegation(zone, server):
|
||||
zone = self.het_name(zone)
|
||||
def add_delegation(self, zone, server):
|
||||
"""Lorsqu'on veut offrir une délégation DNS à une machine
|
||||
pour un nom de domaine"""
|
||||
zone = self.get_name(zone)
|
||||
if zone:
|
||||
self.add(NS('@', '%s.' % server))
|
||||
|
||||
def add_a_record(self, nom, machine):
|
||||
"""Ajout d'une entrée A."""
|
||||
# Fait-on de l'IPv4 dans cette zone ?
|
||||
if self.ipv4:
|
||||
for ip in machine.get('ipHostNumber', []):
|
||||
self.add(A(nom, ip))
|
||||
# Fait-on aussi de l'IPv6 ?
|
||||
if self.ipv6:
|
||||
# Bon bah alors on ajoute nom.v4.crans.org en plus.
|
||||
self.add(A(self.get_name_vi(nom, 4), ip))
|
||||
|
||||
def add_aaaa_record(self, nom, machine):
|
||||
"""Ajout d'une entrée AAAA (for the AAAAAAAAwesome)."""
|
||||
# Fait-on de l'IPv6 dans cette zone ?
|
||||
if self.ipv6:
|
||||
for ip in machine.get('ip6HostNumber', []):
|
||||
if machine.get('dnsIpv6', [True])[0]:
|
||||
# Si dnsIpv6 est à True dans la base LDAP, on ajoute l'entrée.
|
||||
# On l'ajoute quand même si la zone ne fait pas d'IPv4, parce que
|
||||
# ça semble assez dommage d'avoir une machine qui a une IPv6, pas
|
||||
# d'IPv4, et pas d'entrée DNS pour la contacter, non mais oh.
|
||||
dnsipv6 = machine.get('dnsIpv6', [True])[0]
|
||||
if dnsipv6 or not self.ipv4:
|
||||
self.add(AAAA(nom, ip))
|
||||
# Si on fait aussi de l'IPv4...
|
||||
if self.ipv4:
|
||||
self.add(AAAA(self.get_name_vi(nom, 6), ip))
|
||||
|
||||
def add_sshfp_record(self, nom, machine):
|
||||
"""Ajoute une fingerprint SSH"""
|
||||
for sshkey in machine.get('sshFingerprint', []):
|
||||
try:
|
||||
algo_txt, key = str(sshkey).split()[:2]
|
||||
algo = config.sshfs_ralgo[algo_txt][1]
|
||||
for hash in config.sshfp_hash.keys():
|
||||
self.add(SSHFP(nom, hash, algo, key))
|
||||
if self.ipv4 and self.ipv6:
|
||||
self.add(SSHFP(self.get_name_vi(nom, 4), hash, algo, key))
|
||||
self.add(SSHFP(self.get_name_vi(nom, 6), hash, algo, key))
|
||||
for r_hash in config.sshfp_hash.keys():
|
||||
self.add(SSHFP(nom, r_hash, algo, key))
|
||||
if self.ipv4:
|
||||
self.add(SSHFP(self.get_name_vi(nom, 4), r_hash, algo, key))
|
||||
if self.ipv6:
|
||||
self.add(SSHFP(self.get_name_vi(nom, 6), r_hash, algo, key))
|
||||
# KeyError is l'algo dans ldap n'est pas connu
|
||||
# TypeError si la clef n'est pas bien en base64
|
||||
except (KeyError, TypeError):
|
||||
pass
|
||||
|
||||
def add_tlsa_record(self, cert):
|
||||
"""Ajout d'un certif dans le DNS"""
|
||||
if 'TLSACert' in cert['objectClass']:
|
||||
for host in cert['hostCert']:
|
||||
nom = self.get_name(host)
|
||||
if nom is None: continue
|
||||
for port in cert['portTCPin']:
|
||||
self.add(TLSA(nom, port, 'tcp', cert['certificat'][0], cert['certificatUsage'][0], cert['matchingType'][0], cert['selector'][0], format='der'))
|
||||
self.add(TLSA(nom, port, 'tcp', cert['certificat'][0], cert['certificatUsage'][0], cert['matchingType'][0], cert['selector'][0], r_format='der'))
|
||||
for port in cert['portUDPin']:
|
||||
self.add(TLSA(nom, port, 'udp', cert['certificat'][0], cert['certificatUsage'][0], cert['matchingType'][0], cert['selector'][0], format='der'))
|
||||
self.add(TLSA(nom, port, 'udp', cert['certificat'][0], cert['certificatUsage'][0], cert['matchingType'][0], cert['selector'][0], r_format='der'))
|
||||
|
||||
def add_machine(self, machine):
|
||||
"""Ajout d'une machine, à savoir chaînage d'ajout
|
||||
d'IP, d'IPv6, de fingerprint et de TLSA, pour chaque
|
||||
entrée "host" dans la base LDAP."""
|
||||
for host in machine['host']:
|
||||
# Le nom peut être None (machine appartenant à une sous-zone, ou à une autre zone)
|
||||
nom = self.get_name(host)
|
||||
if nom is None: continue
|
||||
if nom is None:
|
||||
continue
|
||||
|
||||
self.add_a_record(nom, machine)
|
||||
self.add_aaaa_record(nom, machine)
|
||||
|
@ -298,14 +412,23 @@ class Zone(ZoneBase):
|
|||
for cert in machine.certificats():
|
||||
self.add_tlsa_record(cert)
|
||||
|
||||
|
||||
# Si la machine a bien un nom en "host", on lui ajoute aussi
|
||||
# les aliases, sous forme de CNAME vers le premier nom.
|
||||
if machine['host']:
|
||||
for alias in machine.get('hostAlias', []):
|
||||
# Si l'alias pointe dans une autre zone, on passe. (ça sera fait quand on refera le add_machine
|
||||
# en toutnant dans la sous-zone
|
||||
if str(alias) in self.other_zones and str(alias) != self.zone_name:
|
||||
continue
|
||||
|
||||
alias = self.get_name(alias)
|
||||
if alias is None: continue
|
||||
if alias is None:
|
||||
continue
|
||||
|
||||
to_nom = self.get_name(machine['host'][0])
|
||||
|
||||
# Si l'alias est sur le nom de la zone, il faut ajouter
|
||||
# des entrées standard.
|
||||
if alias in ['@', '%s.' % self.zone_name]:
|
||||
self.add_a_record(alias, machine)
|
||||
self.add_aaaa_record(alias, machine)
|
||||
|
@ -315,14 +438,23 @@ class Zone(ZoneBase):
|
|||
if self.ipv4 and self.ipv6:
|
||||
self.add(CNAME(self.get_name_vi(alias, 6), self.get_name_vi(to_nom, 6)))
|
||||
self.add(CNAME(self.get_name_vi(alias, 4), self.get_name_vi(to_nom, 4)))
|
||||
# Ne devrait pas arriver.
|
||||
else:
|
||||
self.add(CNAME(alias, "%s." % machine['host'][0]))
|
||||
|
||||
|
||||
class ZoneReverse(Zone):
|
||||
"""Zone inverse, listant des PTR (toto.crans.org IN PTR 138.231...)"""
|
||||
def __init__(self, net, ttl, soa, ns_list):
|
||||
"""Initialise une zone reverse.
|
||||
net est un truc de la forme fe80::/64, ou 138.231.136.0/24
|
||||
En v4, il faut que net soit un /32, un /24, un /16 ou un /8
|
||||
En gros, il faut que network_to_arpanets retourne une liste à un élément."""
|
||||
|
||||
# Comme dit, liste à un élément.
|
||||
if len(ZoneReverse.network_to_arpanets(net)) != 1:
|
||||
raise ValueError("%s n'est pas un réseau valide pour une zone de reverse dns" % net)
|
||||
|
||||
self.net = net
|
||||
zone_name = ZoneReverse.reverse(net)[0]
|
||||
if '.' in net:
|
||||
|
@ -333,6 +465,7 @@ class ZoneReverse(Zone):
|
|||
ipv4 = False
|
||||
else:
|
||||
raise ValueError("net should be an ipv4 ou ipv6 network")
|
||||
|
||||
super(ZoneReverse, self).__init__(zone_name, ttl, soa, ns_list, ipv6=ipv6, ipv4=ipv4)
|
||||
|
||||
@staticmethod
|
||||
|
@ -341,29 +474,43 @@ class ZoneReverse(Zone):
|
|||
l'adresse donnés, ainsi que le nombre d'éléments de l'ip a
|
||||
mettre dans le fichier de zone si elle est fournie, n'importe
|
||||
quoi sinon."""
|
||||
n = netaddr.IPNetwork(net)
|
||||
a = netaddr.IPAddress(ip if ip else n.ip)
|
||||
rev_dns_a = a.reverse_dns.split('.')[:-1]
|
||||
assert a in n
|
||||
if n.version == 4:
|
||||
if n.prefixlen == 8:
|
||||
# Initialise la plage d'IP à partir de net
|
||||
_network = netaddr.IPNetwork(net)
|
||||
# Prend la première adresse ip de la plage, sauf si une est fournie
|
||||
_address = netaddr.IPAddress(ip if ip else _network.ip)
|
||||
# retourne le reverse splitté. (un reverse ressemble à 0.136.231.138.in-addr.arpa.)
|
||||
rev_dns_a = _address.reverse_dns.split('.')[:-1]
|
||||
|
||||
# Si la config est foireuse (donc si on a fourni une IP hors de la plage, ça
|
||||
# va planter ici.
|
||||
assert _address in _network
|
||||
|
||||
# En v4, le reverse étant de la forme 0.136.231.138.in-addr.arpa., soit
|
||||
# on a un /8, soit un /16, soit un /24.
|
||||
if _network.version == 4:
|
||||
if _network.prefixlen == 8:
|
||||
return ('.'.join(rev_dns_a[3:]), 3)
|
||||
elif n.prefixlen == 16:
|
||||
elif _network.prefixlen == 16:
|
||||
return ('.'.join(rev_dns_a[2:]), 2)
|
||||
elif n.prefixlen == 24:
|
||||
elif _network.prefixlen == 24:
|
||||
return ('.'.join(rev_dns_a[1:]), 1)
|
||||
else:
|
||||
raise ValueError("Bad network %s" % n)
|
||||
elif n.version == 6:
|
||||
return ('.'.join(rev_dns_a[(128-n.prefixlen)/4:]), (128-n.prefixlen)/4)
|
||||
raise ValueError("Bad network %s" % _network)
|
||||
# En v6 c'est plus calme.
|
||||
# Le reverse a cette tronche : 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa.
|
||||
# Du coup c'est aussi fin qu'on le souhaite.
|
||||
elif _network.version == 6:
|
||||
return ('.'.join(rev_dns_a[(128 - _network.prefixlen)/4:]), (128 - _network.prefixlen)/4)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def network_to_arpanets(nets):
|
||||
"""
|
||||
retourne une liste de reseaux ne contenant que
|
||||
des préfixes de taille 32, 24, 16 ou 8 en ipv4
|
||||
et laisse inchangé les réseaux ipv6.
|
||||
"""Dans reverse(net, ip), on a constaté qu'en v4, on ne pouvait définir
|
||||
que des plages reverse en /24, /16 ou /8. Cette fonction vise à retourner
|
||||
une liste des plages en tenant compte de ce critère (donc de taille
|
||||
32/24/16/8)
|
||||
|
||||
Ne touche à rien pour l'IPv6.
|
||||
"""
|
||||
if not isinstance(nets, list):
|
||||
nets = [nets]
|
||||
|
@ -371,6 +518,8 @@ class ZoneReverse(Zone):
|
|||
for net in nets:
|
||||
if not isinstance(net, netaddr.IPNetwork):
|
||||
net = netaddr.IPNetwork(net)
|
||||
# Si on est en v4, on fragmente les subnets
|
||||
# dans les tailles qui vont bien.
|
||||
if net.version == 4:
|
||||
if net.prefixlen > 24:
|
||||
subnets.extend(net.subnet(32))
|
||||
|
@ -380,12 +529,13 @@ class ZoneReverse(Zone):
|
|||
subnets.extend(net.subnet(16))
|
||||
else:
|
||||
subnets.extend(net.subnet(8))
|
||||
# En v6 c'est tout pété.
|
||||
elif net.version == 6:
|
||||
subnets.append(net)
|
||||
return subnets
|
||||
|
||||
|
||||
def add_machine(self, machine):
|
||||
"""Ajout d'un reverse pour une machine."""
|
||||
if machine['host']:
|
||||
if self.ipv4:
|
||||
attr = 'ipHostNumber'
|
||||
|
@ -393,33 +543,42 @@ class ZoneReverse(Zone):
|
|||
attr = 'ip6HostNumber'
|
||||
else:
|
||||
raise ValueError("A reverse zone should be ipv6 or ipv6")
|
||||
|
||||
for ip in machine[attr]:
|
||||
try:
|
||||
zone, length = ZoneReverse.reverse(self.net, str(ip))
|
||||
nom = '.'.join(ip.value.reverse_dns.split('.')[:length])
|
||||
|
||||
# La zone retournée n'est pas le nom de la zone. A priori
|
||||
# on aurait dû tomber en AssertionError.
|
||||
if zone != self.zone_name:
|
||||
continue
|
||||
if attr != 'ip6HostNumber' or machine.get('dnsIpv6', [True])[0]: # Hack pour envoyer le reverse vers l'adresse .v6 dans le cas où dnsIpv6 = False
|
||||
|
||||
if attr != 'ip6HostNumber' or machine.get('dnsIpv6', [True])[0]:
|
||||
self.add(PTR(nom, '%s.' % machine['host'][0]))
|
||||
# Gros kludge pour ajouter le reverse vers le .v6 quand on est sur
|
||||
# une reverse v6 et que dnsIpv6 est faux.
|
||||
else:
|
||||
rev_nom, rev_zone = str(machine['host'][0]).split('.', 1)
|
||||
self.add(PTR(nom, '%s.v6.%s.' % (rev_nom, rev_zone)))
|
||||
except AssertionError:
|
||||
# L'ip n'est pas dans la zone reverse, donc on continue silencieusement.
|
||||
pass
|
||||
|
||||
|
||||
class dns(gen_config):
|
||||
"""Classe de configuration du DNS (les services, generate, toussa)"""
|
||||
######################################PARTIE DE CONFIGURATION
|
||||
|
||||
### Fichiers à écrire
|
||||
# Répertoire d'écriture des fichiers de zone
|
||||
DNS_DIR = '/etc/bind/generated/' # Avec un / à la fin
|
||||
DNSSEC_DIR = '/etc/bind/signed/' # Avec un / à la fin
|
||||
DNS_DIR = config.dns.DNS_DIR
|
||||
DNSSEC_DIR = config.dns.DNSSEC_DIR
|
||||
# Fichier de définition des zones pour le maître
|
||||
DNS_CONF = DNS_DIR + 'zones_crans'
|
||||
DNS_CONF = config.dns.DNS_CONF
|
||||
|
||||
# Fichier de définition des zones pour les esclaves géré par BCfg2
|
||||
DNS_CONF_BCFG2 = "/var/lib/bcfg2/Cfg/etc/bind/generated/zones_crans/zones_crans"
|
||||
DNS_CONF_BCFG2 = config.dns.DNS_CONF_BCFG2
|
||||
|
||||
### Liste DNS
|
||||
# Le premier doit être le maitre
|
||||
|
@ -432,11 +591,8 @@ class dns(gen_config) :
|
|||
|
||||
### Serveurs de mail
|
||||
# format : [ priorité serveur , .... ]
|
||||
MXs = [
|
||||
MX('@',10, 'redisdead.crans.org.'),
|
||||
MX('@',15, 'soyouz.crans.org.'),
|
||||
MX('@',25, 'freebox.crans.org.'),
|
||||
]
|
||||
MXs = [MX('@', config.dns.MXs[_mx].get('prio', 25), _mx) for _mx in config.dns.MXs]
|
||||
|
||||
SRVs = {
|
||||
'crans.org': [
|
||||
SRV('jabber', 'tcp', 5, 0, 5269, 'xmpp'),
|
||||
|
@ -446,14 +602,14 @@ class dns(gen_config) :
|
|||
SRV('sip', 'tcp', 5, 0, 5060, 'asterisk'),
|
||||
SRV('sips', 'tcp', 5, 0, 5061, 'asterisk'),
|
||||
SRV('stun', 'udp', 5, 0, 3478, 'asterisk'),
|
||||
]
|
||||
],
|
||||
}
|
||||
NATPRs = {
|
||||
'crans.org' : [
|
||||
NAPTR('@', 5, 100, "S", "SIPS+D2T", "", '_sips._tcp.crans.org.', ttl=86400),
|
||||
NAPTR('@', 10, 100, "S", "SIP+D2U", "", '_sip._udp.crans.org.', ttl=86400),
|
||||
NAPTR('@', 15, 100, "S", "SIP+D2T", "", '_sip._tcp.crans.org.', ttl=86400),
|
||||
]
|
||||
],
|
||||
}
|
||||
|
||||
# DS à publier dans zone parentes : { parent : [ zone. TTL IN DS key_id algo_id 1 hash ] }
|
||||
|
@ -478,17 +634,22 @@ class dns(gen_config) :
|
|||
restart_cmd = '/etc/init.d/bind9 reload'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Surcharge pour affecter EXTRAS"""
|
||||
self.EXTRAS = {}
|
||||
self.anim = None
|
||||
super(dns, self).__init__(*args, **kwargs)
|
||||
|
||||
def gen_soa(self, ns_list, serial, ttl):
|
||||
"""Génère l'enregistrement SOA pour le domaine"""
|
||||
return SOA(ns_list[0], 'root.crans.org', serial, 21600, 3600, 1209600, ttl)
|
||||
|
||||
|
||||
def populate_zones(self, zones, machines):
|
||||
"""On peuple les fichiers de zones"""
|
||||
self.anim.iter = len(zones.values())
|
||||
for zone in zones.values():
|
||||
# On met les mêmes MX pour toutes les zones.
|
||||
zone.extend(self.MXs)
|
||||
# Les RR définis ici sont ajoutés aux zones idoines, de façon à se simplifier la vie.
|
||||
for rr_type in [self.SRVs, self.NATPRs, self.DSs, self.EXTRAS]:
|
||||
if zone.zone_name in rr_type.keys():
|
||||
zone.extend(rr_type[zone.zone_name])
|
||||
|
@ -498,31 +659,43 @@ class dns(gen_config) :
|
|||
return zones
|
||||
|
||||
def gen_zones_ldap(self, ttl, ns_list, serial, zones={}, zones_ldap=config.dns.zones_ldap):
|
||||
"""On génère la liste des zones ldap, à partir de config.dns. C'est un peu ici que tout commence.
|
||||
Le dico zones passé en argument est modifié en place."""
|
||||
for zone in zones_ldap:
|
||||
# On crée la zone et on l'ajoute au dico.
|
||||
zones[zone] = Zone(zone, ttl, self.gen_soa(ns_list, serial, ttl), ns_list, other_zones=config.dns.zones_direct)
|
||||
return zones
|
||||
|
||||
def gen_zones_reverse(self, ttl, ns_list, serial, zones={},
|
||||
zones_reverse_v4=config.dns.zones_reverse, zones_reverse_v6=config.dns.zones_reverse_v6):
|
||||
zones_reverse_v4=config.dns.zones_reverse,
|
||||
zones_reverse_v6=config.dns.zones_reverse_v6):
|
||||
"""Deuxième gros morceau, les reverses, pareil, on peuple depuis config.dns, et on crée toutes les zones
|
||||
idoines. Pareil, ici, le dico zones est modifié en place"""
|
||||
for net in ZoneReverse.network_to_arpanets(zones_reverse_v4 + zones_reverse_v6):
|
||||
# On crée la zone et on l'ajoute au dico.
|
||||
zones[str(net)] = ZoneReverse(str(net), ttl, self.gen_soa(ns_list, serial, ttl), ns_list)
|
||||
return zones
|
||||
|
||||
def gen_zones_clone(self, ttl, ns_list, serial, zones={}):
|
||||
for zone_clone, zones_alias in config.dns.zone_alias.items():
|
||||
"""Les clônes, à savoir crans.eu et cie, dico zones modifié en place."""
|
||||
for zone_clone, zones_alias in config.dns.zone_alias.iteritems():
|
||||
for zone in zones_alias:
|
||||
# On crée la zone et on l'ajoute au dico.
|
||||
zones[zone] = ZoneClone(zone, zones[zone_clone], self.gen_soa(ns_list, serial, ttl))
|
||||
# Et on ajoute les enregistrements concernant la zone clône (pas la clônée, ça
|
||||
# a déjà été fait à l'init) à la main.
|
||||
for rr_type in [self.SRVs, self.NATPRs, self.DSs]:
|
||||
if zones[zone].zone_name in rr_type.keys():
|
||||
zones[zone].extend(rr_type[zones[zone].zone_name])
|
||||
return zones
|
||||
|
||||
|
||||
def gen_zones(self, ttl, serial, ns_list, populate=True):
|
||||
"""On chaîne les différents gen_zones_*"""
|
||||
zones = {}
|
||||
self.gen_zones_ldap(ttl, ns_list, serial, zones)
|
||||
self.gen_zones_reverse(ttl, ns_list, serial, zones)
|
||||
|
||||
# Si populate, on remplit les zones avec les enregistrements \o/
|
||||
if populate:
|
||||
conn = lc_ldap.shortcuts.lc_ldap_admin()
|
||||
machines = conn.search(u"mid=*", sizelimit=10000)
|
||||
|
@ -534,14 +707,15 @@ class dns(gen_config) :
|
|||
self.gen_zones_clone(ttl, ns_list, serial, zones)
|
||||
return zones
|
||||
|
||||
|
||||
def gen_tv(self, populate=True):
|
||||
"""Génération de la TV, un peu à part."""
|
||||
self.anim = affich_tools.anim('\tgénération de la zone tv')
|
||||
zones = {}
|
||||
serial = self.serial
|
||||
self.gen_zones_reverse(self.TTL, config.dns.DNSs, serial, zones, zones_reverse_v4=config.NETs['multicast'], zones_reverse_v6=[])
|
||||
self.gen_zones_ldap(self.TTL, config.dns.DNSs, serial, zones, zones_ldap=[config.dns.zone_tv])
|
||||
|
||||
# Pareil, si on doit peupler on ajoute ce qu'il faut niveau machines.
|
||||
if populate:
|
||||
conn = lc_ldap.shortcuts.lc_ldap_admin()
|
||||
machines = conn.machinesMulticast()
|
||||
|
@ -549,13 +723,16 @@ class dns(gen_config) :
|
|||
self.populate_zones(zones, machines)
|
||||
|
||||
for zone in zones.values():
|
||||
zone.write(self.DNS_DIR + 'db.' + zone.zone_name)
|
||||
zone.write(os.path.join(self.DNS_DIR, 'db.%s' % (zone.zone_name,)))
|
||||
|
||||
self.anim.reinit()
|
||||
print affich_tools.OK
|
||||
return zones
|
||||
|
||||
def gen_master(self):
|
||||
"""Pour le serveur maître.
|
||||
|
||||
Appelle gen_zones puis écrit les fichiers."""
|
||||
# Syntaxe utilisée dans le fichier DNS_CONF pour définir une zone sur le maître
|
||||
zone_template = """
|
||||
zone "%(zone_name)s" {
|
||||
|
@ -567,14 +744,16 @@ zone "%(zone_name)s" {
|
|||
with open(self.DNS_CONF, 'w') as f:
|
||||
f.write(disclamer)
|
||||
for zone in zones.values():
|
||||
zone.write(self.DNS_DIR + 'db.' + zone.zone_name)
|
||||
zone.write(os.path.join(self.DNS_DIR, 'db.%s' % (zone.zone_name,)))
|
||||
if zone.zone_name in config.dns.zones_dnssec:
|
||||
zone_path = self.DNSSEC_DIR + 'db.' + zone.zone_name
|
||||
zone_path = os.path.join(self.DNSSEC_DIR, 'db.%s' % (zone.zone_name,))
|
||||
else:
|
||||
zone_path = self.DNS_DIR + 'db.' + zone.zone_name
|
||||
zone_path = os.path.join(self.DNS_DIR, 'db.%s' % (zone.zone_name,))
|
||||
f.write(zone_template % {'zone_name' : zone.zone_name, 'zone_path' : zone_path})
|
||||
|
||||
def gen_slave(self):
|
||||
"""Pour les slaves, fait l'écriture de la conf dans bcfg2, mais on ne peuple rien !
|
||||
On ne fait qu'écrire le fichier zone_crans."""
|
||||
zone_template = """
|
||||
zone "%(zone_name)s" {
|
||||
type slave;
|
||||
|
@ -587,9 +766,9 @@ zone "%(zone_name)s" {
|
|||
f.write(disclamer)
|
||||
for zone in zones.values():
|
||||
if zone.zone_name in config.dns.zones_dnssec:
|
||||
zone_path = self.DNSSEC_DIR + 'db.' + zone.zone_name
|
||||
zone_path = os.path.join(self.DNSSEC_DIR, 'db.%s' % (zone.zone_name,))
|
||||
else:
|
||||
zone_path = self.DNS_DIR + 'db.' + zone.zone_name
|
||||
zone_path = os.path.join(self.DNS_DIR, 'db.%s' % (zone.zone_name,))
|
||||
f.write(zone_template % {'zone_name' : zone.zone_name, 'zone_path' : zone_path, 'master_ip' : config.dns.master})
|
||||
|
||||
def _gen(self):
|
||||
|
@ -600,27 +779,27 @@ zone "%(zone_name)s" {
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
hostname = short_name(gethostname())
|
||||
if hostname == short_name(config.bcfg2_main):
|
||||
HOSTNAME = short_name(gethostname())
|
||||
if HOSTNAME == short_name(config.bcfg2_main):
|
||||
print "Reconfiguration du fichier de BCfg2 pour configurer le bind d'un serveur en esclave (pensez à lancer bcfg2 sur les esclaves)."
|
||||
c = dns()
|
||||
c.gen_slave()
|
||||
elif hostname == short_name(config.dns.DNSs[0]):
|
||||
CONFIG = dns()
|
||||
CONFIG.gen_slave()
|
||||
elif HOSTNAME == short_name(config.dns.DNSs[0]):
|
||||
print "Serveur maître :"
|
||||
c = dns()
|
||||
zones = c.gen_tv()
|
||||
CONFIG = dns()
|
||||
ZONES = CONFIG.gen_tv()
|
||||
import subprocess
|
||||
for zone in zones.values():
|
||||
if zone.zone_name in config.dns.zones_dnssec:
|
||||
args=("/usr/sbin/ods-signer sign %s" % zone.zone_name).split()
|
||||
p=subprocess.Popen(args,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
|
||||
ret=p.communicate()
|
||||
print ret[0].strip()
|
||||
if ret[1].strip():
|
||||
print ret[1].strip()
|
||||
for ZONE in ZONES.values():
|
||||
if ZONE.zone_name in config.dns.zones_dnssec:
|
||||
ARGS = ("/usr/sbin/ods-signer sign %s" % ZONE.zone_name).split()
|
||||
PROCESS = subprocess.Popen(ARGS, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
RET = PROCESS.communicate()
|
||||
print RET[0].strip()
|
||||
if RET[1].strip():
|
||||
print RET[1].strip()
|
||||
print "Ce serveur est également serveur maitre pour les autres zones dns, mais leur reconfiguration se fait par generate."
|
||||
elif hostname in map(lambda fullhostname : short_name(fullhostname),config.dns.DNSs[1:]):
|
||||
print "Ce serveur est esclave! Lancez ce script sur %s, puis lancez bcfg2 ici" % bcfg2_main
|
||||
elif HOSTNAME in [short_name(FULLHOSTNAME) for FULLHOSTNAME in config.dns.DNSs[1:]]:
|
||||
print "Ce serveur est esclave! Lancez ce script sur %s, puis lancez bcfg2 ici" % (config.bcfg2_main,)
|
||||
else:
|
||||
print "Ce serveur ne correspond à rien pour la configuration DNS."
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue