scripts/gestion/gen_confs/bind.py
Vincent Le Gallic 2ce185720e Éclatement de config.py en plusieurs sous-module de config. L'API reste à peu près la même, il faut juste penser à import config.submodule avant d'utilisr config.submodule (confid.dns, config.upload par exemple)
Tous les autres fichiers modifiés le sont pour compatibilité avec ce changement.

Ce commit implique des commits du même genre dans l'intranet2, lc_ldap et bcfg2.
2013-03-26 16:24:31 +01:00

560 lines
24 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, re, hashlib, base64, os
sys.path.append('/usr/scripts/gestion')
from socket import gethostname
from gen_confs import gen_config
import config
import config.dns
from iptools import AddrInNet, AddrInNets
import ip6tools
import netaddr
import ldap_crans
def short_name(fullhostname):
return fullhostname.split(".")[0]
def netv4_to_arpa(net):
addr, prefixlen = net.split('/')
if prefixlen == '8':
return ["%s.in-addr.arpa" % addr.split('.')[0]]
if prefixlen == '16':
return ["%s.in-addr.arpa" % '.'.join(reversed(addr.split('.')[0:2]))]
zones=[]
n = map(int,net.split('/')[0].split('.')[:3])
while 1 :
try:
innet = AddrInNet("%d.%d.%d.1" % tuple(n),net)
except ValueError:
break
else:
if not innet:
break
else :
n.reverse()
zones.append("%d.%d.%d.in-addr.arpa" % tuple(n))
n.reverse()
n[2] += 1
return zones
def netv6_to_arpa(net):
n = netaddr.IPNetwork(net)
network_reverse = netaddr.IPAddress(n.first).reverse_dns
zone = network_reverse.split('.')[(128-n.prefixlen)/4:-1]
return '.'.join(zone)
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
DNSSEC_DIR = '/etc/bind/signed/' # Avec un / à la fin
# Fichier de définition des zones pour le maître
DNS_CONF = 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"
### Sur quelles zones on a autorité ?
## En cas de modification de ces zones penser à regéner le fichier de
## zone des esclaves (sur le serveur principal de bcfg2 : python /usr/scripts/gestion/gen_confs/bind.py puis lancer bcfg2 sur les miroirs)
# Résolution directe
zones_direct = config.dns.zones_direct
# Zones signée par opendnssec sur le serveur maitre
zones_dnssec = config.dns.zones_dnssec
# Zones alias pour les enregistrement A AAAA CNAME TXT et SSHFP
zone_alias = config.dns.zone_alias
zones_v4_to_v6 = {
'wifi.crans.eu': 'wifi.v6.crans.eu',
'crans.eu': 'v6.crans.eu',
'crans.org': 'v6.crans.org',
'wifi.crans.org': 'wifi.v6.crans.org',
'adm.crans.org': 'adm.v6.crans.org',
'ferme.crans.org': 'ferme.v6.crans.org',
}
# Résolution inverse
zones_reverse = config.dns.zones_reverse
zones_v6_to_net = {
'crans.eu': config.prefix["fil"][0],
'crans.org': config.prefix["fil"][0],
'wifi.crans.org': config.prefix["wifi"][0],
'adm.crans.org': config.prefix["adm"][0],
'ferme.crans.org': config.prefix["fil"][0],
# Hack pour générer un fichier de zone vide
'##HACK##': config.prefix["subnet"][0],
}
### Liste DNS
# Le premier doit être le maitre
DNSs = ['sable.crans.org', 'freebox.crans.org', 'ovh.crans.org']
DNSs_private = []
ip_master_DNS = config.dns.master
zone_multicast = 'tv.crans.org'
### Liste des délégations de zone
# Pour les demandes de 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 = {
zone_multicast : [ 'sable.crans.org.' , 'mdr.crans.org.', 'freebox.crans.org.', 'ovh.crans.org.'] ,
}
### Serveurs de mail
# format : [ priorité serveur , .... ]
MXs = ['10 redisdead.crans.org', '20 ovh.crans.org', '20 freebox.crans.org']
SRVs = [
'_jabber._tcp.crans.org. 86400 IN SRV 5 0 5269 xmpp.crans.org.',
'_xmpp-server._tcp.crans.org. 86400 IN SRV 5 0 5269 xmpp.crans.org.',
'_xmpp-client._tcp.crans.org. 86400 IN SRV 5 0 5222 xmpp.crans.org.',
'_sip._udp.crans.org. 86400 IN SRV 5 0 5060 asterisk.crans.org.',
'_sip._tcp.crans.org. 86400 IN SRV 5 0 5060 asterisk.crans.org.',
'_sips._tcp.crans.org. 86400 IN SRV 5 0 5061 asterisk.crans.org.',
]
# DS à publier dans zone parentes : { parent : [ zone. TTL IN DS key_id algo_id 1 hash ] }
# ex : { 'crans.eu' : ['wifi.crans.eu. 86400 IN DS 33131 8 1 3B573B0E2712D8A8B1B0C3'] }
# /!\ Il faut faire attention au rollback des keys, il faudrait faire quelque chose d'automatique avec opendnssec
DS = {
'crans.eu': [
'wifi.crans.eu. 3600 IN DS 49739 8 2 de49579462a8f439c9b1853c2a06d337ae4e5ffbd41c21449d4c7112794254ed',
'v6.crans.eu. 3600 IN DS 81 8 2 36fa8d4782ecdbc25f0455e2c14aea899b86cf497ce78c7d90d1cf85647f5190',
],
'v6.crans.eu' : [
'wifi.v6.crans.eu. 3600 IN DS 1799 8 2 52a40a7dfb3e9c88aee032c21c59be756c8d3de29149c408ed8b699d83e30032',
],
'crans.org': [
'v6.crans.org. 3600 IN DS 23641 8 2 3fff97a2581f0f2f49257b4914d5badf8ccb0a49c5a6f4cbf2f520b97de332d0',
'adm.crans.org. 3600 IN DS 565 8 2 498f6cd5bcf291aae4129700a7569fa6e9a86821185bd655f0b9efc6a3bf547e',
'ferme.crans.org. 3600 IN DS 35156 8 2 b63a1443b3d7434429e879e046bc8ba89056cdcb4b9c3566853e64fd521895b8',
'wifi.crans.org. 3600 IN DS 41320 8 2 024799c1d53f1e827f03d17bc96709b85ee1c05d77eb0ebeadcfbe207ee776a4',
'tv.crans.org. 3600 IN DS 30910 8 2 3317f684081867ab94402804fbb3cd187e29655cc7f34cb92c938183fe0b71f5',
],
'v6.crans.org' : [
'adm.v6.crans.org. 3600 IN DS 1711 8 2 f154eeb8eb346d2ca5cffb3f9cc464a17c0c4d69ee425b4fe44eaed7f5dd253b',
'ferme.v6.crans.org. 3600 IN DS 44434 8 2 fb87cb4216599cb6574add543078a9e48d0e50438483386585a9960557434ab0',
'wifi.v6.crans.org. 3600 IN DS 59539 8 2 dbe86f2f2e92d6a27bd1436f03ec1588f2948a2aa02124de0383be801cced85e',
]
}
### Entète des fichiers de zone
zone_entete="""
$ORIGIN %(zone)s.
$TTL 3600
@\tIN\tSOA %(serveur_autoritaire)s. root.crans.org. (
%(serial)i ; numero de serie
21600 ; refresh (s)
3600 ; retry (s)
1209600 ; expire (s)
3600 ; 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_BCFG2 pour définir une zone sur un esclave
zone_template_slave="""
zone "%(NOM_zone)s" {
type slave;
file "%(FICHIER_zone)s";
masters { %(ip_master_DNS)s; };
};
"""
### 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
hostname = short_name(gethostname())
if hostname == short_name(DNSs[0]):
restart_cmd = '/usr/sbin/ods-signer sign --all && /etc/init.d/bind9 reload'
else:
restart_cmd = '/etc/init.d/bind9 reload'
######################################FIN PARTIE DE CONFIGURATION
def __str__(self) :
return "DNS"
def reverse(self, net, ip):
"""Renvoie la zone DNS inverse correspondant au réseau et à
l'adresse donnés, ainsi que le nombre d'éléments de l'ip a
mettre dans le fichier de zone."""
n = netaddr.IPNetwork(net)
a = netaddr.IPAddress(ip)
rev_dns_a = a.reverse_dns.split('.')[:-1]
assert a in n
if n.version == 4:
if n.prefixlen == 16:
return ('.'.join(rev_dns_a[2:]), 2)
else:
return ('.'.join(rev_dns_a[1:]), 1)
elif n.version == 6:
return ('.'.join(rev_dns_a[(128-n.prefixlen)/4:]), (128-n.prefixlen)/4)
def gen_tv(self):
serial = time.time() + 1000000000
zone_reverse=netv4_to_arpa(config.NETs['multicast'][0])[0]
sap=open('/tmp/chaines_recup_sap.txt').readlines()
DNS='; DNS de la zone par ordre de priorité\n'
for d in self.DELEG[self.zone_multicast] :
DNS += '@\tIN\tNS %s\n' % d
DNS += '\n'
lignes_d = '\n'
lignes_r = '\n'
lignes_d +='@\tIN\tA\t%s\n' % '138.231.136.243'
for line in sap:
[nom,ip]=line.split(':')
nom=re.sub('TNT([0-9]*) ','',nom) # on enlève les TNT## des noms
nom=re.sub(' +([^ ])','-\g<1>',nom) # on remplaces les espaces intérieur par un tiret
nom=re.sub('[ .():,"\'+<>]','',nom) # on enlève tous les caractères illégaux
nom=nom.lower()
try:
[ip1,ip2,ip3,ip4]=ip.strip().split('.')
lignes_r += '%s.%s.%s\tIN\tPTR\t%s.%s.\n' % (ip4,ip3,ip2,nom,self.zone_multicast)
lignes_d +='%s\tIN\tA\t%s' % (nom,ip)
except:
pass
# Écriture de la zone directe
file = self.DNS_DIR + 'db.' + self.zone_multicast
fd = self._open_conf(file,';')
fd.write(self.zone_entete % \
{ 'zone' : self.zone_multicast, 'serveur_autoritaire' : self.DELEG[self.zone_multicast][0][0:-1] , 'serial' : serial } )
fd.write('\n')
fd.write(DNS)
fd.write(lignes_d)
fd.close()
# Écriture du reverse
file = self.DNS_DIR + 'db.' + zone_reverse
fd = self._open_conf(file,';')
fd.write(self.zone_entete % \
{ 'zone' : zone_reverse, 'serveur_autoritaire' : self.DELEG[self.zone_multicast][0][0:-1] , 'serial' : serial } )
fd.write('\n')
fd.write(DNS)
fd.write(lignes_r)
fd.close()
def gen_slave(self) :
""" Génération du fichier de config de zone pour les esclaves """
zones = self.zones_direct
zones.extend(self.zones_v4_to_v6.values())
# Ajout des zones reverse
for net in self.zones_reverse:
# IPv4 reverse
zones.extend(netv4_to_arpa(net))
for net in set(self.zones_v6_to_net.values()):
# IPv6 reverse
zones.append(netv6_to_arpa(net))
# Ecriture
fd = self._open_conf(self.DNS_CONF_BCFG2,'//')
for zone in zones :
if zone in self.zones_dnssec:
path=self.DNSSEC_DIR + 'db.' + zone
else:
path=self.DNS_DIR + 'db.' + zone
fd.write(self.zone_template_slave % { 'NOM_zone' : zone,
'FICHIER_zone' : path,
'ip_master_DNS': self.ip_master_DNS})
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 = ''
direct['crans.org'] = ""
# 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 mx ?all"\n'
for m in self.MXs:
direct['crans.org'] +='%s.\tIN\tTXT\t"v=spf1 a ?all"\n' % m.split()[-1]
direct['crans.org'] += '\n'
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 mx ?all"\n\n'
### Ajout d'eventuels champs SRV
direct['crans.org'] +='; Champs SRV\n'
for s in self.SRVs:
direct['crans.org'] += s + '\n'
direct['crans.org'] += '\n'
### 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() )
# Si la machine est une borne wifi, on ajoute la position
if isinstance(machine,ldap_crans.BorneWifi) and machine.position():
ligne +="%s\tIN\tTXT\t\"LOC %s,%s \"\n" % (nom,machine.position()[0],machine.position()[1])
# Si la machine à des clefs ssh, on ajoute les champs SSFP correspondant
for sshkey in machine.sshFingerprint():
try:
[algo_txt,key]=sshkey.split()[:2]
algo=None
for value in config.sshfp_algo.values():
if algo_txt == value[1]:
algo=value[0]
break
if not algo:
raise ValueError("Invalid Algorithms %s" % algo_txt)
key=hashlib.sha1(base64.b64decode(key)).hexdigest()
ligne +="%s\tIN\tSSHFP\t%s\t1\t%s\n" % (nom,algo,key)
except(ValueError,TypeError): pass
direct[zone] = direct.get(zone, "") + ligne
if zone in self.zone_alias:
for alias in self.zone_alias[zone]:
direct[alias] = direct.get(alias, "") + ligne
elif self.verbose and machine.nom() != "ftp.federez.net":
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') )
# IPv6
if zone in self.zones_v4_to_v6:
# Direct
zone_v6 = self.zones_v4_to_v6[zone]
ipv6 = machine.ipv6()
net_v6 = machine.netv6()
ligne = "%s\tIN\tAAAA\t%s\n" % (nom, ipv6)
direct[zone_v6] = direct.get(zone_v6, "") + ligne
if machine.dnsIpv6():
direct[zone] = direct.get(zone, "") + ligne
if zone in self.zone_alias:
for alias in self.zone_alias[zone]:
if alias in self.zones_v4_to_v6:
alias_v6=self.zones_v4_to_v6[alias]
direct[alias_v6] = direct.get(alias_v6, "") + ligne
if machine.dnsIpv6():
direct[alias] = direct.get(alias, "") + ligne
# Reverse
zone_rev, length = self.reverse(net_v6, ipv6)
rev = '.'.join(ipv6.reverse_dns.split('.')[:length])
ligne = "%s\tIN\tPTR\t%s.\n" % (rev, machine.nom6())
reverse[zone_rev] = reverse.get(zone_rev, "") + ligne
# Le direct avec alias
for alias in machine.alias() :
alias = alias.encode('iso-8859-1')
# 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')
direct[alias] = direct.get(alias, "") + ligne
if alias in self.zone_alias:
for alias2 in self.zone_alias[alias]: direct[alias2] = direct.get(alias2, "") + ligne
if machine.dnsIpv6():
ligne = "@\tIN\tAAAA\t%s\n" % machine.ipv6()
ligne = ligne.encode('iso-8859-1')
direct[alias]= direct.get(alias, "") + ligne
if alias in self.zone_alias:
for alias2 in self.zone_alias[alias]: direct[alias2] = direct.get(alias2, "") + ligne
if alias in self.zones_v4_to_v6:
ligne = "@\tIN\tAAAA\t%s\n" % machine.ipv6()
ligne = ligne.encode('iso-8859-1')
zone6 = self.zones_v4_to_v6[alias]
direct[zone6] = direct.get(zone6, '') + ligne
if alias in self.zone_alias:
for alias2 in self.zone_alias[alias]:
if alias2 in self.zones_v4_to_v6:
alias26=self.zones_v4_to_v6[alias2]
direct[alias26] = direct.get(alias26, "") + 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() )
direct[zone] = direct.get(zone, '') + ligne
if zone in self.zones_v4_to_v6:
zone6 = self.zones_v4_to_v6[zone]
ligne = "%s\tIN\tCNAME\t%s.\n" % ( nom, machine.nom6() )
direct[zone6] = direct.get(zone6, '') + ligne
if zone in self.zone_alias:
for alias in self.zone_alias[zone]:
direct[alias] = direct.get(alias, '') + ligne
if alias in self.zones_v4_to_v6:
alias6 = self.zones_v4_to_v6[alias]
direct[alias6] = direct.get(alias6, '') + ligne
# Le reverse
ip = machine.ip()
net = AddrInNets(ip, self.zones_reverse)
if net:
base_ip = ip.split('.')
base_ip.reverse()
zone, length = self.reverse(net, ip)
zone = zone.encode('iso-8859-1')
ligne = '%s\tIN\tPTR\t%s.\n' % ('.'.join(base_ip[:length]), machine.nom())
try : reverse[zone] += ligne
except : reverse[zone] = ligne
elif self.verbose >= 2 or machine.nom() not in ('freebox.crans.org', 'ovh.crans.org', 'kokarde.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]
### XXX: création de la zone inverse pour le /48 IPv6 complet du Cr@ns
full_net_v6 = self.zones_v6_to_net["##HACK##"]
zone_rev, length = self.reverse(full_net_v6, netaddr.IPNetwork(full_net_v6).first)
reverse[zone_rev] = reverse.get(zone_rev, "")
### 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 )
### Ajout d'eventuel champs DS pour les délégation dnssec
for zone,ds in self.DS.items():
for s in ds:
direct[zone] += s + '\n'
direct[zone] += '\n'
### Ecriture des fichiers de zone et préparation du fichier de définition
f = ''
for zone, lignes in direct.items() + reverse.items() :
if zone in self.zones_dnssec:
path = self.DNSSEC_DIR + 'db.' + zone
else:
path = self.DNS_DIR + 'db.' + zone
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()
os.chmod(file,0664)
if short_name(gethostname()) in map(short_name, dns.DNSs[1:]):
f += self.zone_template_slave % {'NOM_zone': zone, 'FICHIER_zone': path,
'ip_master_DNS': self.ip_master_DNS}
else:
f += self.zone_template % { 'NOM_zone' : zone, 'FICHIER_zone' : path }
### Ecriture fichier de définition
fd = self._open_conf(self.DNS_CONF,'//')
fd.write(f)
fd.close()
return warnings
if __name__ == '__main__' :
from config import bcfg2_main
hostname = short_name(gethostname())
if hostname == short_name(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()
if hostname == short_name(dns.DNSs[0]):
print "Ce serveur est également serveur maitre, mais la reconfiguration du DNS maitre se fait par generate."
elif hostname == short_name(dns.DELEG['tv.crans.org'][0][0:-1]):
print "Serveur ma�tre pour tv.crans.org, génération de la zone"
c = dns()
c.gen_tv()
import subprocess
args="/usr/sbin/ods-signer sign tv.crans.org".split()
p=subprocess.Popen(args,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
ret=p.communicate()
print ret[0].strip()
print ret[1].strip()
if hostname == short_name(dns.DNSs[0]):
print "Ce serveur est également serveur maitre, mais la reconfiguration du DNS maitre se fait par generate."
elif hostname == short_name(dns.DNSs[0]):
print "Ce serveur est maître ! Utilisez generate."
elif hostname in map(lambda fullhostname : short_name(fullhostname),dns.DNSs[1:]+dns.DNSs_private):
print "Ce serveur est esclave! Lancez ce script sur %s, puis lancez bcfg2 ici" % bcfg2_main
else:
print "Ce serveur ne correspond à rien pour la configuration DNS."