Menu Content/Inhalt
Accueil arrow Scripting arrow VBScript arrow VBSPing - Echo ICMP

Syndication

Abonnez-vous à ce fil RSS pour être tenu informé des nouveautés de ce site.

VBSPing - Echo ICMP Convertir en PDF Version imprimable Suggérer par mail
Écrit par Gilles LAURENT   
16-07-2008

Requête Echo ICMP en VBScript avec les API Win32 WinSock et le composant DynaWrap

Dans le but de mettre à l'épreuve ma version étendue du composant COM DynaWrap, j'ai souhaité me lancer dans la manipulation des API Win32 Winsock en écrivant un script VBScript qui reproduit le plus fidèlement possible le fonctionnement du célèbre outil de diagnostique Ping.exe. Rien de bien transcendant dans tout cela néanmoins les API Winsock utilisant principalement des pointeurs et des structures, c'était l'occasion de vérifier la stabilité et la complétude des nouvelles méthodes offertes par ce composant.

Note: Dans le cadre de ce projet, le composant COM DynaWrap est utilisé pour invoquer les API Win32 suivantes :

1- Librairie dynamique ws2_32.dll

  • WSAStartup
  • WSACleanup
  • inet_addr
  • inet_ntoa
  • gethostbyname

2- Librairie dynamique icmp.dll (Windows 2000) ou iphlpapi.dll (Windows XP+)

  • IcmpSendEcho
  • IcmpCreateFile
  • IcmpCloseHandle
  • GetIpErrorString ( Windows XP+ uniquement )

Historique:
Version 1.0 - 20080715 - Première Release Publique

Plateformes supportées:
Windows 2000+

Pré requis:
Winsock 2.0

Listing 1 : VBSPing.vbs

  1. Option Explicit
  2. ' déclaration des constantes DynaWrap
  3. Const dw_BSTR=0
  4. Const dw_BYTE=1
  5. Const dw_DOUBLE=8
  6. Const dw_INT=2
  7. Const dw_LONG=4
  8. ' déclaration des constantes internes
  9. Const TIMEOUT=1000
  10. Const PINGCOUNT=4
  11. ' déclaration des variables
  12. Dim oDyn, oRe
  13. Dim sWSAData, sHostToReach, sIpAddr, sReplyBuffer, sError
  14. Dim dwIpAddr, dwReplyBufferAddr, dwHostentAddr
  15. Dim lRet, lErrorSize
  16. Dim bIsIpErrorStringSupported
  17. Dim nPingCount
  18. Dim hIcmpFile
  19. Dim nTimeout: nTimeout=TIMEOUT
  20. Dim nPingCountRequired: nPingCountRequired=PINGCOUNT
  21. Dim nPingCountReceived: nPingCountReceived=0
  22. Dim nMinTimeResponseReceived: nMinTimeResponseReceived=nTimeout
  23. Dim nMaxTimeResponseReceived: nMaxTimeResponseReceived=0
  24. Dim nTimeResponseReceived: nTimeResponseReceived=0
  25. Dim nTotalTimeResponseReceived: nTotalTimeResponseReceived=0
  26. ' initialisation des objets
  27. Set oDyn=CreateObject("DynamicWrapper")
  28. Set oRe=New RegExp: oRe.Pattern="^(\d+\.){3}\d+$"
  29. ' déclaration dynamique des API Win32 utilisées
  30. oDyn.Register "ws2_32.dll", "WSAStartup", "r=l","i=ll"
  31. oDyn.Register "ws2_32.dll", "WSACleanup", "r=l"
  32. oDyn.Register "ws2_32.dll", "inet_addr", "r=l", "i=s"
  33. oDyn.Register "ws2_32.dll", "inet_ntoa", "r=l", "i=l"
  34. oDyn.Register "ws2_32.dll", "gethostbyname", "r=l", "i=s"
  35. ' gestion des erreurs
  36. ' les API sont disponibles dans des librairies différentes
  37. ' selon le système d'exploitation (Windows 2000 et Windows XP+)
  38. On Error Resume Next
  39. ' tentative de déclaration dynamique pour Windows XP et supérieur
  40. oDyn.Register "iphlpapi.dll", "IcmpSendEcho", "r=l", "i=llslllll"
  41. ' vérification de la disponibilité de la fonction exportée
  42. If Err.Number Then
  43.   ' la plateforme est Windows 2000 (librairie icmp.dll)
  44.   oDyn.Register "icmp.dll", "IcmpSendEcho", "r=l", "i=llslllll"
  45.   oDyn.Register "icmp.dll", "IcmpCreateFile", "r=h"
  46.   oDyn.Register "icmp.dll", "IcmpCloseHandle", "r=b", "i=l"
  47.   ' l'API GetIpErrorString n'est pas supportée
  48.   bIsIpErrorStringSupported=False
  49. Else
  50.   ' la plateforme est Windows XP ou supérieur (librairie iphlpapi.dll)
  51.   oDyn.Register "iphlpapi.dll", "GetIpErrorString", "r=l", "i=lll"
  52.   oDyn.Register "iphlpapi.dll", "IcmpCreateFile", "r=h"
  53.   oDyn.Register "iphlpapi.dll", "IcmpCloseHandle", "r=b", "i=l"
  54.   ' l'API GetIpErrorString est supportée
  55.   bIsIpErrorStringSupported=True
  56. End If
  57. ' fin de la gestion des erreurs
  58. On Error Goto 0
  59. ' initialisation des API Winsock (au moins Winsock v2.0)
  60. sWSAData=String(200, Chr(0))
  61. lRet=odyn.WSAStartup(&h0002, oDyn.GetBSTRAddr(sWSAData))
  62. ' vérification de la disponibilité des API Winsock
  63. If lRet<>0 Then
  64.   ' une erreur est survenue
  65.   WScript.Echo oDyn.FormatMessage(lRet)
  66.   ' libération des ressources et fin de traitement
  67.   oDyn.WSACleanup()
  68.   WScript.Quit()
  69. End If
  70. ' lecture de l'argument (adresse IP ou nom de hôte)
  71. sHostToReach=WScript.Arguments(0)
  72. ' détermination du type d'argument
  73. ' addresse IP ou nom de hôte
  74. If oRe.Test(sHostToReach) Then
  75.   ' l'argument est une adresse IP
  76.   sIpAddr=sHostToReach
  77.   ' détermination de l'adresse réseau
  78.   dwIpAddr=oDyn.inet_addr(oDyn.GetBSTRAddr(sHostToReach))
  79. Else
  80.   ' l'argument est un nom de hôte
  81.   ' il est nécessaire de résoudre le nom de hôte via DNS, WINS, ...
  82.   dwHostentAddr=oDyn.gethostbyname(oDyn.GetBSTRAddr(sHostToReach))
  83.   ' vérification du résultat de l'opération
  84.   If dwHostentAddr=0 Then
  85.     ' une erreur est survenue
  86.     ' affichage du message d'erreur
  87.     WScript.Echo oDyn.FormatMessage(oDyn.GetLastError())
  88.     ' libération des ressources et fin de traitement
  89.     oDyn.WSACleanup()
  90.     WScript.Quit()
  91.   End If
  92.   ' lecture du nom de hôte réel
  93.   ' celui transmis comme argument peut être un alias
  94.   sHostToReach=odyn.GetMemInBSTRAddr( _
  95.     oDyn.GetMemInBSTRAddr( _
  96.       dwHostentAddr, 0, dw_LONG _
  97.     ), 0, dw_BSTR _
  98.   )
  99.   ' lecture de l'adresse réseau
  100.   dwIpAddr=odyn.GetMemInBSTRAddr( _
  101.     oDyn.GetMemInBSTRAddr( _
  102.       oDyn.GetMemInBSTRAddr( _
  103.         dwHostentAddr, 12, dw_LONG _
  104.       ), 0, dw_LONG _
  105.     ), 0, dw_LONG _
  106.   )
  107.   ' lecture de l'adresse IP au format texte
  108.   sIpAddr=oDyn.GetMemInBSTRAddr(oDyn.inet_ntoa(dwIpAddr), 0, dw_BSTR)
  109. End If
  110. ' tout semble en ordre
  111. ' ouverture du handle Echo ICMP IPv4
  112. hIcmpFile=oDyn.IcmpCreateFile()
  113. ' initialisation de la structure nécessaire au ping et récupération
  114. ' de son adresse. Les données transmises ont une taille de 32 octets
  115. sReplyBuffer=String(28/2+32/2, Chr(0))
  116. dwReplyBufferAddr=oDyn.GetBSTRAddr(sReplyBuffer)
  117. ' affichage du header
  118. WScript.Stdout.Write "Envoi d'une requête 'ping' sur " & sHostToReach & " "
  119. If sIpAddr<>sHostToReach Then WScript.Stdout.Write "[" & sIpAddr & "] "
  120. WScript.Echo "avec 32 octets de données :"
  121. WScript.Echo
  122. ' Compteur du nombre de requête Echo ICMP IPv4 (timeout=1s)
  123. For nPingCount=1 to nPingCountRequired
  124.   ' envoi d'un Echo ICMP
  125.   lRet=oDyn.IcmpSendEcho( _
  126.     hIcmpFile, _
  127.     dwIpAddr, _
  128.     "01234567890123456789012345678901", _
  129.     32, _
  130.     0, _
  131.     dwReplyBufferAddr, _
  132.     Lenb(sReplyBuffer), _
  133.     nTimeout _
  134.   )
  135.   ' vérification du résultat de l'opération
  136.   If lRet=0 Then
  137.     ' une erreur est survenue
  138.     ' si l'API GetIpErrorString est supportée alors détermination du message d'erreur
  139.     If bIsIpErrorStringSupported=True Then
  140.       ' allocation du buffer et détermination du message d'erreur
  141.       sError=String(256/2, Chr(0))
  142.       lErrorSize=Lenb(sError)
  143.       oDyn.GetIpErrorString oDyn.GetLastError(), oDyn.GetBSTRAddr(sError), oDyn.GetVariantAddr(lErrorSize)
  144.     Else
  145.       ' l'API GetIpErrorString n'est pas supportée
  146.       ' seul le code d'erreur sera affiché
  147.       ' les messages associés sont disponibles sur le site MSDN
  148.       ' http://msdn.microsoft.com/en-us/library/aa366053(VS.85).aspx
  149.       sError="Une erreur est survenue : [" & oDyn.GetLastError() & "]"
  150.     End If
  151.     ' affichage du message d'erreur
  152.     Wscript.Echo sError
  153.   Else
  154.     ' le requête Echo ICMP a réussi
  155.     nPingCountReceived=nPingCountReceived+1
  156.     ' lecture du temps de réponse de la requête
  157.     nTimeResponseReceived=oDyn.GetMemInBSTRAddr(dwReplyBufferAddr,8,dw_LONG)
  158.     ' incrémentation du temps de réponse total
  159.     nTotalTimeResponseReceived=nTotalTimeResponseReceived+nTimeResponseReceived
  160.     ' affichage des informations
  161.     WScript.Stdout.Write _
  162.       "Réponse de " & oDyn.GetMemInBSTRAddr( _
  163.         oDyn.inet_ntoa( _
  164.           oDyn.GetMemInBSTRAddr( _
  165.             dwReplyBufferAddr, 0, dw_LONG _
  166.           ) _
  167.         ), 0, dw_BSTR _
  168.       ) & " : " & _
  169.       "octets=" & oDyn.GetMemInBSTRAddr(dwReplyBufferAddr, 12, dw_BYTE) & " "
  170.     If nTimeResponseReceived=0 Then WScript.Stdout.Write "temps<1ms "
  171.     If nTimeResponseReceived>0 Then WScript.Stdout.Write "temps=" & nTimeResponseReceived & " ms "
  172.     WScript.Echo "TTL=" & oDyn.GetMemInBSTRAddr(dwReplyBufferAddr, 20, dw_BYTE)
  173.     ' sauvegarde des temps de réponses mini et maxi
  174.     If nTimeResponseReceived > nMaxTimeResponseReceived Then nMaxTimeResponseReceived = nTimeResponseReceived
  175.     If nTimeResponseReceived < nMinTimeResponseReceived Then nMinTimeResponseReceived = nTimeResponseReceived
  176.   End If
  177.   ' temporisation d'une seconde avant la nouvelle requête
  178.   If nPingCount<>nPingCountRequired Then WScript.Sleep(1000)
  179. Next
  180. ' affichage des statistiques
  181. WScript.Echo
  182. WScript.Echo "Statistiques Ping pour " & sIpAddr & ":"
  183. WScript.Echo "    Paquets : envoyés = " & nPingCountRequired & ", reçus = " & nPingCountReceived & ", perdus = " & nPingCountRequired - nPingCountReceived & " (perte " & 100-(nPingCountReceived*100 / nPingCountRequired) & "%)"
  184. ' affichage des statistiques supplémentaires si au moins une réponse a été reçue
  185. If nPingCountReceived Then
  186.   WScript.Echo "Durée approximative des boucles en millisecondes :"
  187.   WScript.Echo "    Minimum = " & nMinTimeResponseReceived & "ms , Maximun = " & nMaxTimeResponseReceived & "ms , Moyenne = " & Fix(nTotalTimeResponseReceived / nPingCountRequired) & "ms"
  188. End If
  189. ' libération des ressources
  190. oDyn.IcmpCloseHandle hIcmpFile
  191. oDyn.WSACleanup()

L'utilisation de ce script est très simple. Il suffit de transmettre en argument l'adresse IPv4 ou le nom de hôte sur lequel envoyer une requête Echo ICMP. Ci-dessous un exemple d'utilisation réalisé sous Windows XP Service Pack 2 avec la console WSH Shell :

                                                                                
WSH D:\Test> ' ping sur un nom de hôte                                          
WSH D:\Test> @cscript VBSPing.vbs www.google.com                                
Microsoft (R) Windows Script Host Version 5.6                                   
Copyright (C) Microsoft Corporation 1996-2001. Tous droits réservés.            
                                                                                
Envoi d'une requête 'ping' sur www.l.google.com [209.85.135.103] avec 32 octets 
de données :                                                                    
                                                                                
Réponse de 209.85.135.103 : octets=32 temps=61 ms TTL=242                       
Réponse de 209.85.135.103 : octets=32 temps=61 ms TTL=242                       
Réponse de 209.85.135.103 : octets=32 temps=70 ms TTL=242                       
Réponse de 209.85.135.103 : octets=32 temps=59 ms TTL=242                       
                                                                                
Statistiques Ping pour 209.85.135.103:                                          
    Paquets : envoyés = 4, reçus = 4, perdus = 0 (perte 0%)                     
Durée approximative des boucles en millisecondes :                              
    Minimum = 59ms , Maximun = 70ms , Moyenne = 62ms                            
                                                                                
WSH D:\Test> ' ping sur une adresse IP V4                                       
WSH D:\Test> @cscript VBSPing.vbs 195.8.214.142                                 
Microsoft (R) Windows Script Host Version 5.6                                   
Copyright (C) Microsoft Corporation 1996-2001. Tous droits réservés.            
                                                                                
Envoi d'une requête 'ping' sur 195.8.214.142 avec 32 octets de données :        
                                                                                
Réponse de 195.8.214.142 : octets=32 temps=45 ms TTL=58                         
Réponse de 195.8.214.142 : octets=32 temps=43 ms TTL=58                         
Réponse de 195.8.214.142 : octets=32 temps=45 ms TTL=58                         
Réponse de 195.8.214.142 : octets=32 temps=43 ms TTL=58                         
                                                                                
Statistiques Ping pour 195.8.214.142:                                           
    Paquets : envoyés = 4, reçus = 4, perdus = 0 (perte 0%)                     
Durée approximative des boucles en millisecondes :                              
    Minimum = 43ms , Maximun = 45ms , Moyenne = 44ms                            
                                                                                
WSH D:\Test> ' ping sur une adresse IP refusant les requêtes Echo entrantes     
WSH D:\Test> @cscript VBSPing.vbs 192.168.0.1                                   
Microsoft (R) Windows Script Host Version 5.6                                   
Copyright (C) Microsoft Corporation 1996-2001. Tous droits réservés.            
                                                                                
Envoi d'une requête 'ping' sur 192.168.0.1 avec 32 octets de données :          
                                                                                
Délai d'attente de la demande dépassé.                                          
Délai d'attente de la demande dépassé.                                          
Délai d'attente de la demande dépassé.                                          
Délai d'attente de la demande dépassé.                                          
                                                                                
Statistiques Ping pour 192.168.0.1:                                             
    Paquets : envoyés = 4, reçus = 0, perdus = 4 (perte 100%)                   
                                                                                
WSH D:\Test> ' Ping sur un nom de hôte non résolu                               
WSH D:\Test> @cscript VBSPing.vbs www.domain.invalid.fr                         
Microsoft (R) Windows Script Host Version 5.6                                   
Copyright (C) Microsoft Corporation 1996-2001. Tous droits réservés.            
                                                                                
Le nom demandé est valide et a été trouvé dans la base de données, mais il ne di
spose pas des données associées recherchées.                                    
                                                                                
                                                                                

Téléchargement:
Guide PDF : -
Archive : VBSPing.zip

 
< Précédent   Suivant >