|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic Internet Routines IcmpSendEcho: Perform a Tracert (Trace Route) in VB |
|
Posted: | Sunday October 30, 2000 |
Updated: | Monday December 26, 2011 |
Applies to: | VB4-32, VB5, VB6 |
Developed with: | VB6, Windows NT4 |
OS restrictions: | None |
Author: | VBnet - Randy Birch, Jim Huff |
Related: | IcmpSendEcho: Perform a Tracert (Trace Route) in VB with Host Name Resolution gethostbyname: Determine Network Host Name and IP Address gethostbyaddr: Obtain Host Name from IP Address IcmpSendEcho: Ping a Machine by IP Address IcmpSendEcho: Ping a Machine by Host Name |
Prerequisites |
Network or DUN connection. |
|
Another
popular request is how to perform a network router trace via VB, without using Shell to run the DOS command line app tracert.exe. This demo
shows how to perform a true tracert using Visual Basic, and is loosely based on some old VB4 code I found by Jim Huff.
Rather than attempt to explain what is going on in a tracert, I found interesting text explaining what tracert does at Connected: An Internet Encyclopaedia. Unfortunately, the link is no longer active. However, the main portion of the page is duplicated in the explanation below. Traceroute If you've been paying attention, you already know that the only facilities TCP/IP provide for tracing packet routes are IP packet options (record route and its variants) that are poorly specified, rarely implemented in a useful way, and often disabled for security reasons. Traceroute does not depend on any of these facilities. Traceroute, to put it simply, is a hack. How Traceroute Works +--------+ +--------+ | SENDER | | TARGET | +--------+ +--------+ | ^| [============( Router )=====( Router )=====( Router )==|====] ^ ^ ^ | | TTL=1 | TTL=2 | TTL=3 | TTL=4 Traceroute | | | | shows these -----+--------------+--------------+------------/ IP addresses In a typical traceroute session, a group of packets with TTL=1 are sent. A single router should respond, using the IP address of the interface it transmits the ICMP Timeout messages on, which should be the same as the interface it received the original packets on. The user is told this IP address, and DNS is used to convert this into a symbolic domain address. Also, round trip times are reported for each packet in the group. Traceroute reports any additional ICMP messages (such as destination unreachables) using a rather cryptic syntax - !N means network unreachable, !H means host unreachable, etc. Once this first group of packets has been processed (this can take 10 seconds or no time at all), the second group (TTL=2) begins transmitting, and the whole process repeats. Problems you might encounter Changing paths No sending addresses Routing problems Buggy TCP/IP implementations |
BAS Module Code |
Place the following code into the general declarations area of a bas module: |
|
Form Code |
To a form add a command button (Command1), check box (disabled - Check1), a combo (Combo1) and four text boxes (Text1 - Text 4). Text 4 is the tracert output box. Label as desired, and add the following code: |
|
Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Const WSADescription_Len As Long = 255 '256, 0-based Private Const WSASYS_Status_Len As Long = 127 '128, 0-based Private Const WS_VERSION_REQD As Long = &H101 Private Const SOCKET_ERROR As Long = -1 Private Const AF_INET As Long = 2 Private Const IP_SUCCESS As Long = 0 Private Const MIN_SOCKETS_REQD As Long = 1 Private Const EM_SETTABSTOPS As Long = &HCB Private Type WSADATA wVersion As Integer wHighVersion As Integer szDescription(0 To WSADescription_Len) As Byte szSystemStatus(0 To WSASYS_Status_Len) As Byte imaxsockets As Integer imaxudp As Integer lpszvenderinfo As Long End Type Private Type ICMP_OPTIONS ttl As Byte 'Time To Live Tos As Byte 'Timeout Flags As Byte 'option flags OptionsSize As Long ' OptionsData As Long ' End Type Private Type ICMP_ECHO_REPLY Address As Long 'replying address Status As Long 'reply status code RoundTripTime As Long 'round-trip time, in milliseconds datasize As Integer 'reply data size. Always an Int. Reserved As Integer 'reserved for future use DataPointer As Long 'pointer to the data in Data below Options As ICMP_OPTIONS 'reply options, used in tracert ReturnedData As String * 256 'the returned data follows the 'reply message. The data string 'must be sufficiently large enough 'to hold the returned data. End Type Private Declare Function SendMessage Lib "user32" _ Alias "SendMessageA" _ (ByVal hwnd As Long, _ ByVal wMsg As Long, _ ByVal wParam As Long, _ lParam As Any) As Long Private Declare Function WSAStartup Lib "wsock32" _ (ByVal VersionReq As Long, _ WSADataReturn As WSADATA) As Long Private Declare Function WSACleanup Lib "wsock32" () As Long Private Declare Function inet_addr Lib "wsock32" _ (ByVal s As String) As Long Private Declare Function gethostbyaddr Lib "wsock32" _ (haddr As Long, _ ByVal hnlen As Long, _ ByVal addrtype As Long) As Long Private Declare Function gethostname Lib "wsock32" _ (ByVal szHost As String, _ ByVal dwHostLen As Long) As Long Private Declare Function gethostbyname Lib "wsock32" _ (ByVal szHost As String) As Long Private Declare Sub CopyMemory Lib "kernel32" _ Alias "RtlMoveMemory" _ (Dest As Any, _ Source As Any, _ ByVal nbytes As Long) Private Declare Function inet_ntoa Lib "wsock32.dll" _ (ByVal addr As Long) As Long Private Declare Function lstrcpyA Lib "kernel32" _ (ByVal RetVal As String, _ ByVal Ptr As Long) As Long Private Declare Function lstrlenA Lib "kernel32" _ (ByVal Ptr As Any) As Long Private Declare Function IcmpCreateFile Lib "icmp.dll" () As Long Private Declare Function IcmpCloseHandle Lib "icmp.dll" _ (ByVal IcmpHandle As Long) As Long Private Declare Function IcmpSendEcho Lib "icmp.dll" _ (ByVal IcmpHandle As Long, _ ByVal DestinationAddress As Long, _ ByVal RequestData As String, _ ByVal RequestSize As Long, _ RequestOptions As ICMP_OPTIONS, _ ReplyBuffer As ICMP_ECHO_REPLY, _ ByVal ReplySize As Long, _ ByVal Timeout As Long) As Long Private Sub Form_Load() With Combo1 .AddItem "www.mvps.org" .AddItem "www.gov.on.ca" .AddItem "www.microsoft.com" .AddItem "www.yahoo.com" .ListIndex = 1 End With Text1.Text = "" Text4.Text = "" ReDim TabArray(0 To 3) As Long TabArray(0) = 30 TabArray(1) = 54 TabArray(2) = 105 TabArray(3) = 182 'Clear existing tabs 'and set the text tabstops Call SendMessage(Text4.hwnd, EM_SETTABSTOPS, 0&, ByVal 0&) Call SendMessage(Text4.hwnd, EM_SETTABSTOPS, 4&, TabArray(0)) Text4.Refresh End Sub Private Sub Command1_Click() Command1.Enabled = False Call TraceRT Command1.Enabled = True End Sub Private Function TraceRT() Dim ipo As ICMP_OPTIONS Dim echo As ICMP_ECHO_REPLY Dim ttl As Integer Dim ttlAdjust As Integer Dim hPort As Long Dim nChrsPerPacket As Long Dim dwAddress As Long Dim sAddress As String Dim sHostIP As String 'set up Text1.Text = "" 'the target IP Text2.Text = "1" 'force the no of packets = 1 for a tracert Text4.Text = "" 'clear the output window List1.Clear 'for info/debuging only 'the chars per packet - can be between 32 and 128 If IsNumeric(Text3.Text) Then If Val(Text3.Text) < 32 Then Text3.Text = "32" If Val(Text3.Text) > 128 Then Text3.Text = "128" Else Text3.Text = "32" End If nChrsPerPacket = Val(Text3.Text) If SocketsInitialize() Then 'returns the IP Address for the Host in Combo 1 'ie returns 209.68.48.118 for www.mvps.org sAddress = GetIPFromHostName(Combo1.Text) 'convert the address into an internet address. 'ie returns 1982874833 when passed 209.68.48.118 dwAddress = inet_addr(sAddress) 'open an internet file handle hPort = IcmpCreateFile() If hPort <> 0 Then 'update the textboxes Text1.Text = sAddress Text4.Text = "Tracing Route to " + Combo1.Text + ":" & vbCrLf & vbCrLf 'The heart of the call. See the VBnet 'page description of the TraceRt TTL 'member and its use in performing a 'Trace Route. For ttl = 1 To 255 '-------------------------------- 'for demo/dedbugging only. The 'list will show each TTL passed 'to the calls. Duplicate TTL's 'mean the request timed out, and 'additional attempts to obtain 'the route were tried. List1.AddItem ttl '-------------------------------- 'set the IPO time to live 'value to the current hop ipo.ttl = ttl 'Call the API. ' 'Two items of consequence happen here. 'First, the return value of the call is 'assigned to an 'adjustment' variable. If 'the call was successful, the adjustment 'is 0, and the Next will increment the TTL 'to obtain the next hop. If the return value 'is 1, 1 is subtacted from the TTL value, so 'when the next increments the TTL counter it 'will be the same value as the last pass. In 'doing this, routers that time out are retried 'to ensure a completed route is determined. '(The values in the List1 show the actual ' hops/tries that the method made.) 'i.e. if the TTL = 3 and it times out, ' adjust = 1 so ttl - 1 = 2. On ' encountering the Next, TTL is ' reset to 3 and the route is tried again. 'The second thing happening concerns the 'sHostIP member of the call. When the call 'returns, sHostIP will contain the name 'of the traced host IP. If it matches the 'string initially used to create the address '(above) were at the target, so end. ttlAdjust = TraceRTSendEcho(hPort, _ dwAddress, _ nChrsPerPacket, _ sHostIP, _ echo, _ ipo) ttl = ttl - ttlAdjust 'need some processing time DoEvents If sHostIP = Text1.Text Then 'we're done Text4.Text = Text4.Text & vbCrLf + "Trace Route Complete" Exit For End If Next ttl 'clean up Call IcmpCloseHandle(hPort) Else MsgBox "Unable to Open an Icmp File Handle", vbOKOnly, "VBnet TraceRT Demo" End If 'If hPort 'clean up Call SocketsCleanup Else MsgBox "Unable to initialize the Windows Sockets", vbOKOnly, "VBnet TraceRT Demo" End If 'if SocketsInitialize() End Function Private Function GetIPFromHostName(ByVal sHostName As String) As String 'converts a host name to an IP address. Dim ptrHosent As Long 'address of hostent structure Dim ptrName As Long 'address of name pointer Dim ptrAddress As Long 'address of address pointer Dim ptrIPAddress As Long 'address of string holding final IP address Dim dwAddress As Long 'the final IP address ptrHosent = gethostbyname(sHostName & vbNullChar) If ptrHosent <> 0 Then 'assign pointer addresses and offset 'ptrName is the official name of the host (PC). 'If using the DNS or similar resolution system, 'it is the Fully Qualified Domain Name (FQDN) 'that caused the server to return a reply. 'If using a local hosts file, it is the first 'entry after the IP address. ptrName = ptrHosent 'Null-terminated list of addresses for the host. 'The Address is offset 12 bytes from the start of 'the HOSENT structure. Addresses are returned 'in network byte order. ptrAddress = ptrHosent + 12 'get the actual IP address CopyMemory ptrAddress, ByVal ptrAddress, 4 CopyMemory ptrIPAddress, ByVal ptrAddress, 4 CopyMemory dwAddress, ByVal ptrIPAddress, 4 GetIPFromHostName = GetIPFromAddress(dwAddress) End If End Function Private Sub SocketsCleanup() 'only show error if unable to clean up the sockets If WSACleanup() <> 0 Then MsgBox "Windows Sockets error occurred during Cleanup.", vbExclamation End If End Sub Private Function SocketsInitialize() As Boolean Dim WSAD As WSADATA 'when the socket version returned == version 'required, return True SocketsInitialize = WSAStartup(WS_VERSION_REQD, WSAD) = IP_SUCCESS End Function Private Function GetIPFromAddress(Address As Long) As String Dim ptrString As Long ptrString = inet_ntoa(Address) GetIPFromAddress = GetStrFromPtrA(ptrString) End Function Private Function GetStrFromPtrA(ByVal lpszA As Long) As String GetStrFromPtrA = String$(lstrlenA(ByVal lpszA), 0) Call lstrcpyA(ByVal GetStrFromPtrA, ByVal lpszA) End Function Private Sub ShowResults(timeToLive As Byte, _ tripTime As Long, _ sHostIP As String) Dim sTripTime As String Dim buff As String Dim tmp As String 'format a string representing 'the round trip time Select Case tripTime Case Is < 10: sTripTime = "<10 ms" Case Is > 1200: sTripTime = "*" Case Else: sTripTime = CStr(tripTime) & " ms" End Select 'cache the textbox buff = Text4.Text 'create a new entry tmp = "Hop #" & vbTab & _ CStr(timeToLive) & vbTab & _ sTripTime & vbTab & _ sHostIP & vbCrLf 'update textbox Text4.Text = buff & tmp End Sub Private Function TraceRTSendEcho(hPort As Long, _ dwAddress As Long, _ nChrsPerPacket As Long, _ sHostIP As String, _ echo As ICMP_ECHO_REPLY, _ ipo As ICMP_OPTIONS) As Integer Dim sData As String Dim sError As String Dim sHostName As String Dim ttl As Integer 'create a buffer to send sData = String$(nChrsPerPacket, "a") If IcmpSendEcho(hPort, _ dwAddress, _ sData, _ Len(sData), _ ipo, _ echo, _ Len(echo) + 8, _ 2400) = 1 Then 'a reply was received, so update the display sHostIP = GetIPFromAddress(echo.Address) ShowResults ipo.ttl, echo.RoundTripTime, sHostIP 'return 0 to continue with retrieval TraceRTSendEcho = 0 Else 'a timeout was received, so set the 'return value to 1. In the TraceRT 'calling routine, the TTL will be 'de-incremented by 1, causing the 'for / next to retry this hop. TraceRTSendEcho = 1 End If End Function |
Comments |
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |