Video Screencast Help

Protocol.vbs -A Windows VBScript to test TCP Service Response

Created: 30 Sep 2013 • Updated: 01 Oct 2013
ianatkin's picture
+2 2 Votes
Login to vote

Today I’m going to introduce you to a handy script I made to provide a Transmission Control Protocol (TCP)  ‘ping-like’ facility on the command-line. I distribute this to my server estate so I always have something to hand which can punch that little bit harder than telnet for my TCP port testing.

If you are into service monitoring, it has uses here too. The script’s advanced mode allows you to test beyond a  basic TCP port ping to perform a preliminary protocol test. In such cases, running this as a scheduled task can alert you to those any TCP services which might be running but actually no longer responding as anticipated.

I have to say right now that I class this as an advanced tool. Using it beyond its most basic mode requires knowledge of TCP protocols. Further, its dependence on 32-bit active controls means it only functions in a 32-bit space (on 64-bit systems you must call the WOW layer).

Sections to this article are,

1. Installing the Script
2. Protocol.vbs and OS architecture considerations
3. Protocol.vbs command-line Arguments
4. Basic Port Testing
     4.1 Testing for Open Ports with Telnet
     4.2 Testing for Open Ports With Protocol.vbs
5. More Advanced Service Testing
      5.1 How to Tell if a Service is Running
      5.2 Using Protocol.vbs to Check IIS on a Notification Server
      5.3 Using Protocol.vbs to Check the DB Manager Service on DS6.9
               5.3.1 Identifying the TCP port of a Process
               5.3.2 Using Wireshark to capture Traffic
6. Caveats and Further Thoughts
      6.1 Performance Counters
      6.2 Log Files and Event Logs
      6.3 Workload Simulation

 

1. Installing the Script

Attached to this article you’ll find a zip archive holding the following files,

  1. Protocol.vbs
    This vbscript performs the protocol tests.  This needs to be executed through command-line version of the Windows script host, cscript.exe
     
  2. MSWINSCK.OCX
    Microsoft’s 32-bit Windows Sockets control for exchanging data over the User Datagram Protocol (UDP) and the Transmission Control Protocol (TCP)
     
  3. WINSCKW.OCX
    Gurgen Alaverdian’s inspired 32-bit OCX wrapper to MSWINSCK.OCX to make MS Winsock transparent to vbscript.

 

Download the zip and extract the files to say C:\bin.

Open up an elevated command prompt and register these OCX controls with the command line registration tool, regsrvr32.exe,

C:\bin> regsvr32.exe mswinsck.ocx

C:\bin> regsvr32.exe winsckw.ocx

C:\bin>_

 

Once these ActiveX controls have been registered, you’ll be able to start using the protocol script.

 

2. Protocol.vbs and OS architecture considerations

One of the drawbacks of using scripts rather than fully compiled code is that it introduces a complication on 64-bit machines.  You see, as this vbscript uses 32-bit ActiveX controls, we must run it in a 32-bit space. On 64-bit machines, we must therefore explicitly ensure that we take advantage of the Windows-On-Windows subsystem by either,

  1. Calling cscript.exe from a 32-bit command shell
    (c:\windows\SysWOW64\cmd.exe)
     
  2. Calling 32-bit cscript from the 64-bit command shell
    (c:\windows\SysWOW64\cscript.exe)

If do by chance forget to call the script in a 32-bit space, it will exit instantly informing you to rerun using the 32-bit cscript (I have ideas about how to work around this, or but that adds a complexity which is better left for a later version).

In all the examples from this point on, cscript.exe is being executed in 32-bit command shell for example readability. If you are using a 64-bit system, it’s best you replace all references to cscript.exe below with c:\windows\syswow64\cscript.exe

 

3. Protocol.vbs command-line Arguments

In order to see what the script can do, let’s take a look at the command-line arguments it accepts. To view the argument options you can use either of the /? Or the /help switches.

c:\bin>cscript protocol.vbs /?
Microsoft (R) Windows Script Host Version 5.8
Copyright (C) Microsoft Corporation. All rights reserved.

 

Simple Protocol Testing script for TCP troubleshooting.

Usage:  /ip:<Remote IP>
        /port:<tcp port>
        /timeout:<seconds> (optional)
        /send:<string to send> (optional)
        /test:<response substring> (optional)
        /log:<Logfile> (optional)
        /debug (optional)
        /help or /? (prints help)

c:\bin>

 

 

In the basic mode (for TCP port pings) the only arguments required are,

  • /ip: <Remote IP>
    This is the IP address (or name if your name resolution allows) of the machine you’d like to perform the test on. For the local machine, type 127.0.0.1 here.
     
  • /port:<tcp port>
    This is the TCP port number for the service under test.

 

If we need to actually test a TCP port with a request and sample a response, we require two additional arguments,

  • /send: <protocol string>
    This is the string which we want to send to the remote TCP port to test the protocol. In the case of an HTTP protocol test, it might be a GET command for a web page or file. Note that protocols may require special characters and to that end this string supports the following substring substitutions at runtime,

    *NULL*   -the NULL character. Hexadecimal x0
    *CR*       -a carriage return. Hexadecimal  x0D
    *LF*        -a line feed. Hexadecimal  x0A
    *CRLF*   -a carriage return followed by a line feed. Hexadecimal  x0D0A)
     

  • /test:<substring>
    This  string is used to test the response of the server to the request. In the case of an HTTP protocol request this could simply be an HTTP OK response, or a known string in the file being requested.

The other optional arguments are,

  • /timeout:<n>
    This is the timeout in seconds which the script should use when waiting for a response to the TCP handshake and/or protocol sent string. The default value is 30.
     
  • /logfile:<Filename>
    If you specify a file without a folder path, the logfile will be created in the same folder as the script. Note that as these filenames will have a day string added to ensure logs are rotated.
     
  • /debug

This is simply a logfile-to-screen switch which exposes the internal steps the script executes for troubleshooting purposes.

The return is of protocol.vbs is always a number followed by a colon and some text, <n>:<text>. The number n is the  script’s return code and the text after the colon is the human readable string for that return code.

The possible return codes for protocol.vbs are,

prot4.png

 

4. Basic Port Testing

When troubleshooting TCP-based services, one of the most common tasks to perform is a TCP port ping.  This type of ping simply tests to see if a TCP handshake is acknowledged on the port.  Let’s take a look at how this can be done both with a  tool native to Windows and prototol.vbs
 

4.1 Testing for Open Ports with Telnet

Telnet is a great native Windows tool for raw TCP actions like port pings. This is possible with telnet as it can be used to initiate TCP sessions on ports other than 23 by simply typing the desired TCP port number after the IP address.

For example if we want to know if TCP port 445 (for SMB over TCP/IP) is open on a remote machine at IP 192.168.157.1 we can use the telnet command as follows,

C:\> telnet 192.168.157.1 445
 

 

If the connection is successful, the command window will suddenly be cleared, leaving a flashing cursor to signify that the target machine is awaiting a command. At this point you can type a plain text protocol command (although they aren’t echoed) or simply exit out with CRTL+] and then type QUIT.

Although this can be a bit cumbersome to use, it is ubiquitously available on the Windows platforms so is extraordinarily useful.
 

4.2 Testing for Open Ports With Protocol.vbs

Let’s now try the equivalent test to the telnet function above by opening TCP port 445 with protocol.vbs.  The Two arguments required here are just the same as with telnet, an IP address and a port. The  telnet replacement command is therefore going to look like,

c:\bin> cscript /nologo protocol.vbs /ip:192.168.157.1 /port:445

0:Success

 

Here we can see the instant response that this TCP port ping met with 0:Success and thus we know that there is a client-server process attached on the target machine to that port.

If however the TCP handcshake fails (perhaps the host has a firewall which blocks the connection), the script output would let us know as shown below,

c:\bin> cscript /nologo protocol.vbs /ip:192.168.157.1 /port:445

1: No response

 

5. More Advanced Service Testing

Advanced testing can be required in scenarios where a simple TCP port ping isn’t a sufficient test of a running service. This can become complex, as understanding whether a Windows service is running can often require more than seeing if a service executable is loaded into memory. What we sometimes need to know is whether the service is actually doing useful work.

Let’s take a look at the common techniques employed for service monitoring and discuss the pros and cons before seeing how protocol.vbs can be help.
 

5.1 How to Tell if a Service is Running

In many instances, a quick TCP port ping coupled with the knowledge that the remote box has the service running is all that’s required to be confident all is well for consumers of your TCP service.

The most common test which decides whether a service is running on a server (TCP service or not)  is to check its status. You can use a WMI call using the Win32_Service class in a vbscript for this,

strComputer = "."
Set objWMIService = GetObject( "winmgmts:\\" & strComputer & "\root\CIMV2")
Set colitems = objWMIService.ExecQuery("SELECT * FROM Win32_Service where name ='Spooler'",,48)

for each item in colitems
    Msgbox "Service Status: " & item.status
next

Or the command line you can use the Windows service controller command, sc as follows,

sc query Spooler | find /i “Running”

These techniques are brilliant to test for scenarios where processes can crash. One problem however is the definition of ‘running’. 

You  see a Windows Service is really a program like any other; it’s susceptible to bugs and unintended consequences just like any other piece of code. It is therefore possible for services to fall into coding black-holes (from which there is no escape) and cul-de-sacs (where you might be able to do something to get the service turned around without restarting it). These geographical features in the coding landscape can render services powerless to perform useful work even though they are still technically ‘running’ according to the Windows service manager.

Windows will report that a service is running simply by checking if the process is in loaded in memory and passed its initial start-up checks. There doesn’t seem to be a unified framework for services whereby the Windows service manager can at some point later just ask services the question “Are you still alright?”. 

Here lays my core motivation for writing this protocol script. I wanted to test TCP ports at the service protocol level rather than just with a TCP handshake.  This would allow me to establish whether a service is actually responding and able to do work, allowing me to be confident that other service consumers are likewise being responded to appropriately.
 

5.2 Using Protocol.vbs to Check IIS on a Notification Server

Although telnet can be used for advanced testing, it is incredibly cumbersome.  In a bind though, it can be used and I’ve often resorted to it in situations where no other avenues are available. A nicely documented example of how telnet can be used to troubleshoot a TCP server is Microsoft’s article “XFOR: Telnet to Port 25 to Test SMTP Communication”. I recommend that all server administrators try this out to get a feel for not only how protocols are built, but also how we can ‘talk’ to services over TCP (albeit slowly and manually in the telnet case!).

 To manually test Microsoft’s Internet Information Services (IIS) on my Notification Server I simply fire up a webpage and ask for the root webpage. IIS will respond to this HTTP GET request by presenting me the ‘Under Construction’ page which my browser renders.

If I want to replicate the essence of this exchange as a command-line test, I’ll first have to extract the relevant protocol commands using a protocol analyser like Wireshark. This can monitor the packets exchanged during my web browser’s session to the Altiris Server, and re-assemble the conversation as plain text.

Below is a Wireshark capture of one such conversation. It shows the HTTP request as sent by the client (highlighted in red below) and the server response (highlighted in blue),
 

GET / HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*

Accept-Language: en-gb
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E)

Accept-Encoding: gzip, deflate

Host: altiris.it.acme.org

Connection: Keep-Alive

Cookie: ASP.NET_SessionId=mgxu0355r5pxq155qd4tk2ro; AWDefaultPresentationName_conWorker=AltirisConsole; ASPSESSIONIDAAQCSDDB=BLGIFPBAOBNIBLLLEEEGHODD

 

HTTP/1.1 200 OK

Content-Length: 1435

Content-Type: text/html

Last-Modified: Wed, 16 Aug 2006 08:50:49 GMT

Accept-Ranges: bytes

ETag: "f072631211c1c61:586d"

Server: Microsoft-IIS/6.0

X-Powered-By: ASP.NET

Date: Sun, 29 Sep 2013 21:47:13 GMT

 

The trick now is to whittle this exchange down to its bare minimum to facilitate emulation with the protocol script. With a bit of playing around it seems the request data critical to the exchange is this,

GET / HTTP/1.1
Host: altiris.it.acme.org

And,  of course, the only text critical to us in the response is the HTTP OK message,

HTTP/1.1 200 OK

 

This reduced exchange permits us to test the server using the protocol script. Here the sending string will be,

GET / HTTP/1.1*CRLF*Host: altiris.it.acme.org*CRLF**CRLF*"

Where we’ve used our special strings to ensure the protocol is consistent with the expected carriage return and line feed characters.

The test string will be,

HTTP/1.1 200 OK

The cscript.exe call to protocol.vbs will therefore look as follows to test our IIS on our Notification Server,

cscript.exe //nologo protocol.vbs
  /ip:altiris.it.acme.org

  /port:80

  /send:"GET / HTTP/1.1*CRLF*Host: altiris.it.acme.org*CRLF**CRLF*"

  /test:"HTTP/1.1 200 OK"

 

 

This script will therefore only return success if a TCP connection can be made AND the GET request is also successful.
 

5.3 Using Protocol.vbs to Check the DB Manager Service on DS6.9

The Altiris Data Manager service is a good example of a service to test with this script as it’s protocol is undocumented. The process I generally go through is,

  1. Identify the process tcp port
     
  2. Wireshark the TCP port to capture traffic
     
  3. Isolate a new conversation and attempt to replicate with protocol.vbs

So, let’s proceed now to cover how I do this. Note that the phrase “there is more than one way to skin a cat” applies well here!
 

5.3.1 Identifying the TCP port of a Process

Identifying the process port can be a quick are your google-fu allows, but in the end it’s just a couple of commands away. First on the server I do a quick WMI command-line query so I can get the service information (I could just use the GUI, but that’s no fun).

The following table is a prettied up version of what you see when you use WMIC to present the pathnames for all the services which begin with the string “Altiris”. The wildcard here is useful as it stops you having to remember exactly what the service is called.

C:\>wmic service where "Name like 'Altiris%'" get Name,PathName
 

Name
Altiris Deployment Agent       
Altiris Deployment Server Console Manager 
Altiris Deployment Server Data Manager 
Altiris Deployment Server DB Management 
Altiris eXpress Server       
Altiris PXE Config Helper
Altiris PXE Manager       
Altiris PXE MTFTP Server 
Altiris PXE Server                        
AltirisAgentProvider

PathName
dagent.exe -load=default.dll,config.dll,autoupdate.dll
ConsoleManager.exe
DataManager.exe
dbmanager.exe –service
axengine.exe –service
PxeCfgService.exe
PxeMgr.exe
Pxemtftp.exe
PXEService.exe
AltirisAgentProvider.exe

                   

So this then tells us that the DB Management service uses the process dbmanager.exe.

 Next, to find the TCP port that the process attaches to, we use netstat to enumerate the current TCP connections ,

C:\> netstat –b >ports.txt

 

 

Here I’ve used the –b switch to force the display of the process name as it enumerates active ports. If you open up the file ports.txt you then be able to locate the dbmanager.exe process and identify its port number. Below is a text file showing the ports and here we can see we are looking at TCP 505 for dbmanager.exe

prot3.png

 

5.3.2 Using Wireshark to capture Traffic

This is the point where some knowledge of the service and how it is consumed is helpful.  

I know that this service is for example critical to the opening up a Deployment Console, so to capture the traffic I do the following,

  1. Open Wireshark and start capturing on the Ethernet adapter the service is communicating on. This is generally performed on the client machine rather than the server.
     
  2.  Open up a Deployment Console on the client
     
  3. Stop the wireshark capture and filter with the string tcp.port==505 to limit the view to dbmanager TCP traffic.

 

Hint: If you are running this on a production box which has lots of TCP 505 traffic, you’ll want to isolate the traffic displayed to show only your session for clarity. A more advanced filter will help. For example the filter tcp.port==505 and ip.addr=192.168.157.20 will show only those packets on TCP port 505 which are sent to, or come from, the IP 192.168.157.20.
 

Below is a screenshot of Wireshark in action with the TCP port filter.

Prot1.png

Once we’ve identified what looks like a TCP session being created (which in this case begins at number 3828 with a TCP SYN) we can ask Wireshark to display the conversation by asking it to “follow TCP stream”,

prot2.png

This capture tells us that we should be able to simulate a session being created by sending the service the following the command string “Request=CreateSession” followed by x0A and x00 special characters (CR and NULL).

To test success, the substring we need to look for is “Result=Success”

The command therefore to test the service is therefore using protocol.vbs is therefore,

cscript.exe //nologo protocol.vbs
  /ip:altiris.it.acme.org

  /port:505

  /send:"Request=CreateSession*CR**NULL*”

  /test:"Result=Success"

 

 

6. Caveats and Further Thoughts

 Here is where I start waving my hands and say “Don’t blame me if it all goes wrong!”.  If you use protocol.vbs to test undocumented protocols, please test and test again as what you are doing is likely unsupported.

So follow these basic steps if you ever think of automating such tests on a schedule,

  1. On a test box, run the protocol.vbs in a loop in logging mode.
     
  2. Monitor the service stats on the server (CPU and RAM).

The idea here is to fit say a month’s worth of service sampling in an hour and see if the service is stable against such testing. If the service appears stable, then out-of-hours try the same on a production server. If that also appears stable, then excellent. You can now move on to investigating services which might be suitable to such protocol level testing.

There are of course other ways to test services to see if they are working properly, and these should not be ignored. Here are my thoughts on a few that spring instantly to mind.

6.1 Performance Counters

If you are lucky, you might have a service which has installed performance counters which can be monitored to alert you of problems. If not, you might have to fall back on the native process monitors for CPU and general  I/O.

 One drawback with performance counters is they necessarily introduce a time delay between a service failure and you being able to detect it as failed. For example, consider a service which has busy periods and idle periods throughout the day. Producing an alert on a counter idle time should therefore take into account that there are naturally times when a service will be doing less work, perhaps even zero work.

Performance counters therefore naturally lend themselves best to services have a natural background of business which it can be quickly measured against. For servers which tend to have very idle periods by nature, it may well be that you need to look at data over the last half hour before deciding whether a service has zombied out on you.

6.2 Log Files and Event Logs

If you are again lucky, your service might have log files and/or useful events which can be monitored for indications of service zombification.  For example you might have heart-beat characteristics which you can look for, or specific errors. Again, this might involve a time delay before deciding whether your service is truly running or not, but is certainly another useful tactic.

6.3 Workload Simulation

Creating test workloads is a brilliant way to test if a service is functioning, but often requires detailed service knowledge to permit the test. For example, you can test your Altiris Deployment services by configuring scheduled tasks to running test job binary imports and execute jobs.  This can be very illuminating and will often highlight very quickly when the service is experiencing difficulties.