A VB script to stop a network trace based on trace contents

Blue Bar separator

I like Wireshark, I really do but it has one glaring flaw, you cannot let it run writing a trace file and then automatically stop the trace when a key packet is seen in the trace or when the packet is not seen. For example, I want to stop the trace when a FIN or RST packet is seen from a particular host on a particular port. Or when a particular host stops sending out ICMP echo reply packets.

The following kill_dumpcapVBS script lets me do this. Basically, in one command window I start dumpcap, using the "-w" and "-b" arguments to create a ring of files of a particular size. In another command window I run the kill_dumpcap.vbs script. Basically, every N seconds it monitors the current directory looking for a new dumpcap output file. If it finds one (or several) it scans the files with ngrep. If ngrep finds the key packet (or doesn't if it is a negative search) it terminates the dumpcap process based on its PID which you can find with the list_dumpcap VBS script. Two searches are needed. The ngrep search is done first and all the output is redirected into a file. The problem is that even if ngrep does not find anything the file will not be empty and depending on the number of new dumpcap output files the ngrep output file can be rather large. If ngrep is looking for a string in the packet that string will also be listed so you need another, different, search to confirm that the packet is actually found (see the examples). Why require the PID instead of just the process name. I thought that at some point I might want to run two dumpcap processes, each tracing a different interface.

The relationship between the sleep time between polls looking for new files and the number of files and size of the files is more art than science, you will probably need to experiment to find the optimum polling period. Then again the cost of extra polls is not all that significant.

File size may also be an issue for negative searches. If you are looking lets say a ping failure because a system crashed you have to make sure that the a new file is created faster than the system can be booted so that the file does not contain a response. Even one response will cause the script not to terminate the dumpcap process. Other packet types might not be as sensitive to reboot times. Actually for a ping failure test take a look at ping_trigger.vbs. You could modify the script to terminate the dumpcap process directory or send out a ping to a unique address and have this script trigger on that (see example 5).

Usage

cscript kill_dumpcap "Base Name" "Match String" "Packet Specification" "Confirm String" PID SleepTime Flag
Where
Base Nameis the base name of the files being created by dumpcap
Match Stringis an ngrep match condition that is looked for in the trace
Packet Specificationis an ngrep Berkeley Packet Filter condition that is looked for in the trace
Confirm Stringis a string in the ngrep output that confirms ngrep found the correct string
PIDis the process ID of the dumpcap process to terminate. Use list_dumpcap to find it
Sleep Timeis the time in seconds between polls
Flagindicates if dumpcap should be stopped if the "Confirm String" is found (+) or not found (-)

Examples

Example 1 - kill dumpcap when the trace contains a packet with the string "Please stop tracing now"

In the top command window you see the dumpcap command, hi-lighted in yellow. The base file name is "example1", there will be five files, each about 10240 K-bytes (10 meg) in size.

In the bottom command window you see an execution of the list_dumpcap.vbs script hi-lighted in yellow. Note that the returned process ID is 6340. Next in the bottom window, hi-lighted in cyan, is the execution on the kill_dumpcap script. The match string is "Please stop tracing now", there is no BPF string and the confirmation string is "255:666". Next is the PID returned from the list_dumpcap execution. The polling time is 10 seconds and this will be a positive search, that is, kill_dumpcap will kill the dumpcap process when it sees the confirmation string. The first thing that the script does, and the last line hi-lighted in cyan, is to echo back its arguments.

Back to the top command window you see hi-lighted in cyan, the execution of the dumpcap command. It shows the current file being written and on the next line it updates the total number of packets written to all files. When the current file reaches its prescribed size it writes the new file name and goes to a new line.

Back in the bottom window with yellow highlighting again is a list of "new files". The kill_dumpcap will report the file name when it sees a new file right before it scans it. Note that the file currently being written, in this case, example1_00005_20120518131016 has not yet been scanned.

Staying in the bottom window you see a message indicating that the kill_dumpcap script found the confirmation string and terminated the process. The script then terminates itself. In the top command window you also see that we are back to the command prompt.

To the right of the command windows is the ngrep_13_4_55.txt output. This is the text written by the ngrep command. The first line is the name of the file and the second line is the condition that ngrep is looking for. In this case matching on the string "Please stop tracing now". I knew that this string was sent by a program that sends broadcasts to port 666 so the last part of the destination address is "255:666", this was my confirmation string.

Figure 1

Example 2 - kill dumpcap when the trace contains an ICMP echo request from 172.16.1.36

In the top command window you see the dumpcap command, hi-lighted in yellow. The base file name is "example2", there will be five files, each about 10240 K-bytes (10 meg) in size.

In the bottom command window you see an execution of the list_dumpcap.vbs script hi-lighted in yellow. Note that the returned process ID is 5288. Next in the bottom window, hi-lighted in cyan is the execution of the kill_dumpcap script. The match string is null and the ngrep BPF string indicates that a source IP address of 172.16.1.36 and it has to be an ICMP packet. The confirmation string of "50 8:0" is the last part of the packet header, the final octet of the destination is 50 and the ICMP type and code are 8 and 0. Next is the PID returned from the list_dumpcap execution. The polling time is 10 seconds and this will be a positive search.

Back to the top command window you see hi-lighted in cyan the execution of the dumpcap command.

Back in the bottom window with yellow highlighting again is the list of "new files".

Staying in the bottom window you see a message indicating that the kill_dumpcap script found the confirmation string and terminated the process. The script then terminates itself. In the top command window you also see that we are back to the command prompt.

To the right of the command windows is the ngrep_13_23_49.txt output. Note the second line is the BPF string and not a matching string. The 172.16.1.36 host sent 4 echo requests AKA pings (ICMP type 8) to the 172.168.12.50 host, so that is where the "50 8:0" confirmation string came from.

Figure 2

Example 3 - kill dumpcap when the trace contains either a FIN or a RST from 172.16.1.116 port 666

In the top command window you see the dumpcap command, hi-lighted in yellow. The base file name is "example3", there will be five files, each about 10240 K-bytes (10 meg) in size.

In the middle command window you see an execution of the list_dumpcap.vbs script hi-lighted in yellow. Note that the returned process ID is 6028. Next in the middle window, hi-lighted in cyan is the execution on the kill_dumpcap script. The match string is null and the ngrep BPF string indicates that a source IP address of 172.16.1.116 and a port of 666. The confirmation string is "R]", circled in blue. This corresponds to the TCP reset flag. Next is the PID returned from the list_dumpcap execution. The polling time is 10 seconds and this will be a positive search.

In the bottom command window there is another execution of the kill_dumpcap.vbs script. The command line is almost identical. The only difference is that the confirmation string is F], circled in red, which corresponds to the TCP FIN flag.

Back to the top command window you see hi-lighted in cyan the execution of the dumpcap command.

Back in the middle window with yellow highlighting again is the list of "new files".

Staying in the middle window you see a message indicating that the kill_dumpcap script found the confirmation string and terminated the process. The script then terminates itself. In the top command window you also see that we are back to the command prompt. Note in the bottom command window that that instance of the kill_dumpcap.vbs script is still running. At this point all it will do is wake up once every 10 seconds, check the files, see that there are no new files and go back to sleep.

To the right of the command windows are two ngrep_hh-mm-ss.txt output files. Both files show exactly the same thing. This is not surprising since the BPF specifications were the same. The only difference in the two executions is the confirmation string, one looking for "F]" and the other from "R]", which is the last packet displayed. If you wanted to there is no reason why you couldn't use two completely different packet specifications if the situation calls for it.

Figure 3

Example 4 - kill dumpcap when the trace does not contain an ICMP echo reply packet from 172.16.1.36

At this point the format of the example should be familiar. I want to point out just two things. First in the bottom window the list_dumpcap shows two processes, the first (hi-lighted in yellow) is actually an execution of Wireshark. The second (hi-lighted in cyan) is the dumpcap execution that we are interested in.

Second, this is using a negative match, note the "-" flag value circled in light green at the end of the kill_dumpcap command line. The idea is to kill the trace when the source 172.16.1.36 is no longer sending ping replies (ICMP type 0 code 0) to the 192.168.12.50 host.

To the right of the command windows are two versions of the ngrep.txt output. In the top window you see the results of scan of the first file example4_00002*. You can see that ngrep found ICMP packets from 172.16.1.36 and that the confirmation string "50 0:0" is found in at least one of the packets. While I don't show it the results of scanning files 1 and 3 were the same. The bottom ngrep.txt window shows the results of scanning file 4. In this file there are no packets listed so the confirmation string is not found and the script kills the dumpcap process.

Figure 4

Example 5 - kill dumpcap when system fails to respond to 2 pings out of 4 are lost"

In the top left command window there is again the execution of the dumpcap program. Observant readers will notice that the path is different from the previous examples and the interface index is also different. If you concluded that this example was done on a different system - you would be correct.

In the bottom command window we have the execution of the list_dumpcap script showing both an execution from the Wireshark GUI and the dumpcap command that I started for this example.. Next in the bottom window is the execution of the kill_dumpcap script. Note that there is no match string and the packet filer indicates anything with a destination of 1.1.1.1. The confirmation string is 8:0 which we saw in example 3 is part of the header for an ICMP type 8 code 0 packet. You can see that the packets were found in example_00006_20120519185011.

In the top right command window there is an execution of the ping_trigger script. This script will execute a command when a certain number of pings to a host fail. In this case the host is 192.168.0.22 and the command is to ping 1.1.1.1.

Finally in the notepad window at bottom right you can see the ngrep_18_48_8.txt file showing the packets found by ngrep and the 8:0 string in the headers.

Figure 5

A word about Berkeley Packet Filters

You can find a description of Berkely Packet Filters here and here. Or just search for "Berkeley Packet Filter" in your favorite search engine. I suggest that you test any filter you create by running ngrep manually.

kill_dumpcap.vbs

REM == kill_dumpcap.vbs starts here                                       
REM
REM kill_dumpcap.vbs
REM version 1.0 12-05-18
REM Noah Davids - noah@noahdavids.org

REM
REM This software is provided on an "AS IS" basis, WITHOUT ANY WARRANTY OR ANY SUPPORT OF ANY KIND. 
REM The AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
REM PARTICULAR PURPOSE.  This disclaimer applies, despite any verbal representations of any kind provided
REM by the author or anyone else.
REM

option explicit
  Dim fso, folder, colFiles, sFolder
  Dim baseName, baseNameLen, matchString, BPFString, confirmString, confirmStringFound, flag, PID, sleepTime, ngrepOut, terminatePID
  Dim maxIndex, maxIndex9, index, fileList, folderIdx, ngrepRun, oldFileList, sLine
  Dim wShell
  DIM objWMIService, colProcessList, objProcess
  
  If WScript.Arguments.Count <> 7 then
    WScript.Echo "Usage:"
    WScript.Echo "   csript kill_dumpcap ""Base Name"" ""matchString String"" ""Confirm String"" PID SleepTime Flag"
    WScript.Echo vbtab & "   ""Base Name"" is the base name of the files being created by dumpcap"
    WScript.Echo vbtab & "   ""match String String"" is an ngrep match condition that is looked for in the trace"
    Wscript.Echo vbtab & "   ""Packet Specification"" is an ngrep Berkely Packet Filter condition that is looked for in the trace"
    WScript.Echo vbtab & "   ""Confirm String"" is a string in the ngrep output that confirms"
    Wscript.Echo vbtab & vbtab & "ngrep found the correct string"
    Wscript.Echo vbtab & "   PID is the process ID of the dumpcap process to terminate. "
    Wscript.Echo vbtab & vbtab & "Use list_dumpcap to find it"
    Wscript.Echo vbtab & "   SleepTime is time in seconds"
    Wscript.Echo vbtab & "   Flag indictaes if dumpcap should be stopped if the ""Confirm String"" "
    Wscript.Echo vbtab & vbtab & "is found (+) or not found (-)."
    WScript.Echo
    WScript.Quit
  End If

  Set fso = CreateObject("Scripting.FileSystemObject")
  Set wShell = CreateObject("WScript.Shell")
  
  baseName = Wscript.Arguments.Item (0)
  baseNameLen = len (baseName)
  matchString = Wscript.Arguments.Item (1)
  BPFString = Wscript.Arguments.Item (2)
  confirmString = Wscript.Arguments.Item (3)
  PID = Wscript.Arguments.Item (4)
  sleepTime = Wscript.Arguments.Item (5)
  flag = Wscript.Arguments.Item (6)
  
  if flag <> "+" AND flag <> "-" Then
     Wscript.Echo "The Flag argument must be either a + or - character not """ & flag & """"
     Wscript.Quit
  End If
  
  if len (matchString) = 0 AND len (BPFString) = 0 Then
     Wscript.Echo "Either match string OR BPF string must be specified - both cannot be null"
     WScript.Quit
  End If
  
  Wscript.Echo "cscript kill_dumpcap """ & basename & """ """ & matchString & """ """ & _
       BPFString & """ """ & confirmString & """ " & PID & " " & sleepTime & " " & flag

REM General flow of program
REM
REM Create an output file name to accummunate the results of the ngrep command by appending a time string HH_MM_SS
REM to "ngrep_". This allows you to run multiples copies of the script to trigger on different things. There is
REM of course a window where two instances could create the same output file but its a small window.
REM Loop forever
REM   delete the ngrep_HH_MM_SS.txt file. Note that the HH_MM_SS corresponds to when the script was started
REM   create a collection of files that are in the current dir
REM   loop through the file collection and find the maximum index for the dumpcap base name. If it weren't for the
REM      fact that the index rolls over from 99999 to 00001 this would be easy. What I do is collect two maximum index
REM      values one for indexes starting with 9, that is 9XXXX named maxIndex9 and one for all others named maxIndex. 
REM      if maxIndex is the initial value of 00000 I used the maxIndex9 value or if the first character of maxIndex is 8
REM      and the first character of maxIndex9 is 9 I use the maxIndex9 value otherwise I use the maxIndex value. If
REM      you configure dumpcap to collect more than 10,000 files, that is yuo can files 89999 through 99999 and then 00001
REM      this algorithm will incorrectly pick 99999 as the maxindex. It will eventually scan the file so I am not sure
REM      this is a fatal flaw. At any rate collecting more than 10,000 trace files seems excessive so I am not going
REM      to worry about it.
REM   loop the the file collection (again).
REM      For each file that matches the base name, see if it also matches the max index. If it doesn't match the max
REM         index add it to a file list string and then search the old file list string to see if its already there.
REM         NOTE that if the dumpcap ring of files is large enough we will probably exceed some maximum string size.
REM         I tested this with 100 files without problems.
REM         if there is a file that is not in the old file list then run ngrep on the file looking for the
REM               match string or packet specification. Put the output in the ngrep_HH_MM_SS.txt file. It is
REM               possible that there could be several new files so all the output is accummulated in the
REM               ngrep_HH_MM_ss.txt file. Note that if a match string is found don't include the -e argument
REM               -e causes all the packets with no data to be matched as well. You need the -e when using
REM               a BPF string so the confirmation string can be one of the TCP flags.
REM   If ngrep was run then the file list string built in the previous loop is different from the old list
REM      so the first thing to do is update the old file list. Then open the ngrep_HH_mm-ss.txt file and read
REM      each line looking for the confirmation string. This second test is needed because I couldn't figure
REM      out how to confirm that the ngrep found at least 1 packet that meet its specifictaions (or didn't
REM      as indicated by the flag variable just by looking at the ngre_HH_MM_SS.txt You cannot do it based
REM      on file size. We can stop reading as soon as 1 confirmation string is seen.
REM   If the confirmation string is found and the flag is positive we need to terminate dumpcap. If the 
REM      confirmation string is not found and the flag is negative we need to terminate dumpcap.
REM   To terminate dumpcap we search the process list for the process ID that was provided as an input
REM      argument. Once found it is terminated and we quit out of this program as well. If the process
REM      cannot be found we report that and we just quit out of this program.
REM   Assuming we do quit the program we sleep for the indicated time and then start the loop again

  ngrepOut = "ngrep_" & Hour (Time) & "_" & Minute (Time) & "_" & Second (Time) & ".txt"
    
  oldFileList = ""
  While (1)
    fileList = ""
    wShell.Run "cmd.exe /c DEL " & ngrepOut, 7, 1
    ngrepRun = 0  
    Set folder = fso.GetFolder(".")
    Set colFiles = folder.Files
    maxIndex = "00000"
    maxIndex9 = "00000"
    For each folderIdx In colFiles 
       if mid (folderIdx.Name, 1, baseNameLen) = baseName Then
          index = mid (folderIdx.Name, baseNameLen +2, 5)
          if mid (index, 1, 1) = "9" Then
             if StrComp (maxIndex9, index, 1) = -1 Then maxIndex9 = index
          Else
             if StrComp (maxIndex, index, 1) = -1 Then maxIndex = index
          End If
       End If
    Next
    If mid (maxIndex, 1, 1) = "8" and mid (maxIndex9, 1, 1) = "9" Then
       maxIndex = maxIndex9
    Else 
       If maxIndex = "00000" Then maxIndex = maxIndex9
    End If
    For each folderIdx In colFiles
       if mid (folderIdx.Name, 1, baseNameLen) = baseName Then 
          if mid (folderIdx.Name, 1, baseNameLen + 6) <> baseName & "_" & maxIndex Then
             fileList = fileList & folderIdx.Name & " "
             if instr (oldFileList, folderIdx.Name) = 0 Then
                Wscript.Echo "New file " & folderIdx.Name
                if len (matchString) > 0 Then
                   wShell.Run "cmd.exe /c ngrep -q -I" & folderIdx.Name & _
                		" """ & matchString & """ " & BPFString & " >>" & ngrepOut, 7, 1
                Else wShell.Run "cmd.exe /c ngrep -q -e -I" & folderIdx.Name & _
                		" """ & matchString & """ " & """" & BPFString & """ >>" & ngrepOut, 7, 1
                End If
                ngrepRun = 1
             End If
          End If
       End If
    Next
    if ngrepRun Then
       oldFileList = fileList
       confirmStringFound = 0
       Set colFiles = fso.OpenTextFile (ngrepOut)
       Do Until colFiles.AtEndOfStream
          sLine = colFiles.ReadLine
          if instr (sLine, confirmString) > 0 Then
             confirmStringFound = 1
             Exit Do
          End If
       Loop
       colFiles.Close
       
       terminatePID = 0
       If Flag = "+" AND confirmStringFound = 1 Then
          Wscript.Echo "Found confirmation string """ & confirmString & """"
          terminatePID = 1
       ElseIf Flag = "-" AND confirmStringFound = 0 Then
          Wscript.Echo "Did not find confirmation string """ & confirmString & """"
          terminatePID = 1
       End If
       
       if TerminatePID = 1 Then
          Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\.\root\cimv2")
          Set colProcessList = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE " & _
              "ProcessId = '" & PID & "'")
          if colProcessList.Count = 0 Then
             Wscript.Echo "Could not find process with PID = " & PID
             Wscript.Echo "Terminating kill_dumpcap at " & (Date) & "_" & (Time)
             Wscript.Quit
          Else
             For Each objProcess in colProcessList
                 Wscript.Echo "Terminating process with PID = " & objProcess.ProcessId & _
                    " at " & (Date) & "_" & (Time) 
	             objProcess.Terminate()
             NEXT
          End If
          Wscript.Quit
       End If
       
    End If
    Wscript.sleep sleepTime * 1000
  Wend
REM
REM == kill_dumpcap.vbs end  here 


list_dumpcap.vbs

REM == list_dumpcap.vbs starts here                                       
REM
REM list_dumpcap.vbs
REM version 1.0 12-05-20
REM Noah Davids - noah@noahdavids.org

REM
REM This software is provided on an "AS IS" basis, WITHOUT ANY WARRANTY OR ANY SUPPORT OF ANY KIND. 
REM The AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
REM PARTICULAR PURPOSE.  This disclaimer applies, despite any verbal representations of any kind provided
REM by the author or anyone else.
REM

option explicit
  Dim wShell
  DIM objWMIService, colProcessList, objProcess

  Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\.\root\cimv2")
  Set colProcessList = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE " & "Name = 'dumpcap.exe'")
  if colProcessList.Count = 0 Then
     Wscript.Echo "Could not find a dumpcap.exe process"
  Else
     For Each objProcess in colProcessList
         Wscript.Echo objProcess.CommandLine & " started on " & objProcess.CreationDate & _
           " PID = " & objProcess.ProcessId
	 NEXT
  End IF               
REM
REM == list_dumpcap.vbs end  here 


Blue Bar separator
This page was last modified on 12-05-20
mailbox Send comments and suggestions
to noah@noahdavids.org