PI Services

Le blog des collaborateurs de PI Services

Manipuler les enregistrements DNS en Powershell 2

Problème rencontré

Lors d'un changement complet du plan d'adressage des serveurs d’un datacenter, il était nécessaire de changer les enregistrements DNS. Au delà des enregistrements NS des serveurs DNS, il fallait aussi mettre à jour l'intégralité des enregistrements statiques A et PTR. Il était nécessaire de proposer une solution qui soit simple à mettre en œuvre (peu d’intervention utilisateur), puisque près de 600 enregistrements était à modifier. Il n'était pas faisable de faire cela manuellement.

Solution proposée

Comme indiqué dans l'intitulé, il a été choisi que cette opération serait réalisée par un script Powershell. Actuellement, il y a encore peu de parcs informatique utilisant Powershell 3 avec le module DNS pour Windows 8/2012. Le module DNS fournit par Powershell 3 peut donc seulement être utilisé dans des cas très limités. La solution proposée utilisait les classes WMI. Il s'agissait ensuite de loguer un maximum d'informations pour avoir un maximum de contrôle sur les modifications apportées.

Les classes WMI

Voici un listing des classes WMI pour les enregistrements DNS les plus courants :
- Enregistrements PTR : MicrosoftDNS_PTRType
- Enregistrements A : MicrosoftDNS_AType
- Enregistrements CNAME : MicrosoftDNS_CNAMEType
- Enregistrements MX : MicrosoftDNS_MXType
- Enregistrements NS : MicrosoftDNS_NSType

Récupération d'enregistrements DNS

Voici un exemple de récupération d'un enregistrement A.

On déclare la zone dans laquelle on veut effectuer la recherche.

001
002
$DNSZone = "myenterprise.lan"

 

On définit le serveur DNS sur lequel on effectue la recherche.

001
002
$DNSServer = "SRVDNS01" 

 

On cherche l'enregistrement via l'attribut OwnerName qui est le nom DNS complet.

001
002
$OwnerName = "SRV01.$DNSZone" 

 

On utilise une requête WMI sur le serveur DNS avec un filtre sur la zone et l'enregistrement à chercher.

001
002
003
004
$Record = Get-WMIObject -Computer $DNSServer `
-Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_AType" `
-Filter "ContainerName='$DNSZone' AND OwnerName='$OwnerName'" 

Si l'on souhaite obtenir toutes les propriétés de cet enregistrement et notamment voir les autres attributs sur lesquels on peut effectuer une recherche il suffit d'appeler la variable : $Record

Mis à jour d'enregistrements DNS :

En reprenant l'enregistrement précédent, on peut rapidement modifier son addresse IP (ou TTL) via la méthode Modify().

001
002
$NewRecord = $Record.Modify($Record.TTL, "10.0.1.1") 

 

Détecter si un enregistrement est dynamique :

Aussi, il peut être intéressant de ne mettre à jour que les enregistrements statiques. On peut détecter les enregistrements dynamiques via leur timestamp qui n'est pas nulle :

001
002
003
004
if($Record.Timestamp -ne 0){ 
    $NewRecord = $Record.Modify($Record.TTL, "$newRecordAddress") 
} 

Il suffit donc juste d'utiliser une structure conditionnelle si sinon sur l'attribut timestamp de notre enregistrement DNS.

Exemple avec un enregistrement PTR :

Pour réaliser cette opération on réutilise les variables $DNSServer, $DNSZone et $OwnerName déclarées plus haut et définir la zone où chercher l'enregistrement PTR.

001
002
$DNSZonePTR = "10.in-addr.arpa" 

 

La syntaxe pour rechercher un enregistrement PTR est similaire. Seuls la classe WMI et le champ de recherche (PTRDomainName au lieu de Ownername).

001
002
003
004
$PTRRecord = Get-WMIObject -Computer $DNSServer `
-Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_PTRType" `
-Filter "ContainerName='$ZonePTR' AND PTRDomainName='$OwnerName.'" 

 

Attention, il n'est pas possible de modifier l'IP d'un enregistrement PTR, il faut d'abord supprimer l'enregistrement puis le recréer.

Avant, on récupère la TTL pour la réutiliser afin qu'elle soit identique lors du nouvel enregistrement :

001
002
$TTL = $PTRRecord.TTL 

 

On supprime l'enregistrement DNS en supprimant l'objet WMI

001
002
$PTRRecord | Remove-WmiObject 

 

On déclare la nouvelle valeur de notre enregistrement. Si IP vaut 10.B.C.D dans la zone "10.in-addr.arpa" alors celui-ci vaudra D.C.B.10.in-addr.arpa

001
002
$PTROwnerName = "1.1.0.10.in-addr.arpa"

 

On déclare le type de notre enregistrement, ici PTR :

001
002
003
$PTRTypeClass = [WMIClass]"\\$DNSServer\root\MicrosoftDNS:MicrosoftDNS_PTRType" 

$PTRNewRecord = $PTRTypeClass.CreateInstanceFromPropertyData("$DNSServer.myenterprise.lan",$ZonePTR,$PTROwnerName,$null,$TTL,"$OwnerName.") 

 

Le 4ème attribut est dénommé record class : par défaut il s'agit de IN. La valeur à insérer est 1 ou $null.

Exemple sous Powershell v3 avec module DNS :

Pour terminer, voici comment réaliser les mêmes opérations (Récupération/Mis à jour d'enregistrements DNS) avec le module DNS Powershell v3. Il faut posséder un poste sous Windows 8/2012 pour exécuter ses commandes et avoir installé l'outil de gestion des serveurs DNS (via les outils d'administration).

On commence par déclarer la zone, le serveur DNS et le nom de l'enregistrement :

001
002
003
004
005
$DNSZone = "myenterprise.lan" 
$DNSServer = "DNS01" 
$RecordName = "SERV01" 
$NewRecordAddress = "10.0.1.1" 

 

Le type est renseigné dans le paramètre RRType. Attention, il est important de stocker l'objet dans une variable car nous allons le réutiliser pour le modifier.

001
002
003
$Record = Get-DnsServerResourceRecord -ZoneName "$DNSZone" -Name "$RecordName" `
-RRType "A" -ComputerName "$DNSServer" 

 

Pour valider les modifications nous aurons besoin de l'enregistrement DNS avant et après sa mise à jour. Il faut donc réaliser une deuxième récupération de l'enregistrement DNS dans une autre variable.

001
002
003
$NewRecord = Get-DnsServerResourceRecord -ZoneName "$DNSZone" -Name "$RecordName" `
-RRType "A" -ComputerName "$DNSServer" 

 

Ensuite, il faut modifier la propriété qui nous intéresse, ici l'adresse IP.

001
002
$NewRecord.RecordData.IPv4Address.IPAddressToString = "$NewRecordAddress" 

 

Enfin, on enregistre les modifications en passant les 2 objets (avant et après modification), la zone et le nom du serveur DNS :

001
002
003
Set-DnsServerResourceRecord -NewInputObject $NewRecord -OldInputObject $Record -ZoneName "$DNSZone" `
-ComputerName "$DNSServer" 

Réseau – L’adresse résolue par PING n’est pas celle attendue !

Beaucoup de programmes TCP/IP comme Ping et FTP utilisent la fonction WinSock INET_ADDR() :

unsigned long inet_addr( __in const char *cp );

pour convertir les adresses IPv4 du format chaine de caractère avec séparateur ”.” dans un format IN_ADDR qui n’est qu’une structure.

typedef struct in_addr { union { struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; struct { u_short s_w1,s_w2; } S_un_w; u_long S_addr; } S_un; } IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;

Toute adresse IPv4 sera formatée dans cette structure sous le format d’un entier long non signé (u_long).

La fonction INET_ADDR accepte les chaines de caractères au format suivant :

  • a.b.c.d
  • a.b.c
  • a.b
  • a
    Les différentes parties qui définissent l’adresse IP dans son format caractère avec séparateur “.” peuvent avoir des valeurs décimales , octales ou hexadécimales.

Ainsi pinger l’adresse 172.19.0.40 revient à pinger  l’adresse 0254.023.0.050 en octal et l’adresse 0xAC.0x13.0.0x28 en hexadécimal.

172.19.0.40

image

0254.023.0.050

image

0xAC.0x13.0.0x28

image

Lors du traitement de la chaine de caractère en entrée, la fonction INET_ADDR traitera les nombre selon les règles suivantes :

  • Tout nombre commençant par  0x ou 0X sera traité comme un chiffre hexadécimal
  • Tout nombre commençant par 0 sera traité comme étant un nombre octal
  • Les autres cas seront traité comme des nombres décimaux.

Ainsi il faut faire attention à ne pas utiliser un Zéro à gauche au niveau d’une partie de l’adresse IP si vous voulez la pinger car la partie qui commence par zéro sera traité comme étant un nombre octal et le Ping sera dirigé vers une autre adresse qui ne correspond pas à celle que vous avez tapé.

2008 R2 - Anomalies dans la liste des serveurs DNS racine de Windows Server 2008 R2 ?

En configurant le service DNS de Windows Server 2008 R2, j’ai détecté une anomalie assez étonnante : les adresses IP des serveurs DNS racines B.root-servers.net et L.root-servers.net sont erronées dans la configuration du DNS de Windows Server 2008 R2 !

En effet, on nous indique les adresses IP suivantes :

  • Pour le serveur B.root-servers.net : 128.9.0.107 dans la configuration du service DNS Windows Server contre 192.228.79.201 sur le site http://www.root-servers.org/
  • Pour le serveur L.root-servers.net : 198.32.64.12 dans la configuration du service DNS Windows Server contre 199.7.83.42 sur le site http://www.root-servers.org/

En ce qui concerne le serveur « L » appartenant à l’ICANN, on peut retrouver sur leur site un billet indiquant à tous les opérateurs de services DNS de mettre à jour l’adresse IP avant la date de la bascule prévue le 1er novembre 2007…

La liste des nouvelles adresses IP est aussi consultables sur le site de l’Internic (ftp://rs.internic.net/domain/named.root).

La liste des « root hints » de Windows Server 2008, Windows Server 2003 R2 et des versions précédentes semble également touchée.