mansz81

chaosreader0.94.pl

Mar 8th, 2022 (edited)
375
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 188.29 KB | None | 0 0
  1. #!/usr/bin/perl
  2. #
  3. # Chaosreader can trace TCP/UDP/... sessions and fetch application data
  4. #  from tcpdump or snoop logs. This is like an "any-snarf" program, it will
  5. #  fetch telnet sessions, FTP files, HTTP transfers (HTML, GIF, JPEG, ...),
  6. #  SMTP emails, etc ... from the captured data inside the network traffic
  7. #  logs. It creates a html index file that links to all the session details,
  8. #  including realtime replay programs for telnet, rlogin or IRC sessions;
  9. #  and reports such as image reports and HTTP GET/POST content reports.
  10. #  It also creates replay programs for telnet sessions, so that you can
  11. #  play them back in realtime (or even different speeds).
  12. #
  13. # Chaosreader can also run in standalone mode - where it invokes tcpdump or
  14. #  snoop (if they are available) to create the log files and then processes
  15. #  them.
  16. #
  17. #
  18. # 05-May-2004, ver 0.94  (check for new versions, http://www.brendangregg.com)
  19. #            (or run a web search for "chaosreader")
  20. #
  21. #
  22. # QUICK USAGE:
  23. #   tcpdump -s9000 -w out1; chaosreader out1; netscape index.html
  24. #  or,
  25. #   snoop -o out1; chaosreader out1; netscape index.html
  26. #  or,
  27. #   ethereal (save as "out1"); chaosreader out1; netscape index.html
  28. #  or,
  29. #   chaosreader -s 5; netscape index.html
  30. #
  31. #
  32. # USAGE: chaosreader [-aehikqrvxAHIRTUXY] [-D dir]
  33. #                    [-b port[,...]] [-B port[,...]]
  34. #                    [-j IPaddr[,...]] [-J IPaddr[,...]]
  35. #                    [-l port[,...]] [-L port[,...]] [-m bytes[k]]
  36. #                    [-M bytes[k]] [-o "time"|"size"|"type"|"ip"]
  37. #                    [-p port[,...]] [-P port[,...]]
  38. #                    infile [infile2 ...]
  39. #
  40. #        chaosreader -s [mins] | -S [mins[,count]]  
  41. #              [-z] [-f 'filter']
  42. #
  43. #    chaosreader           # Create application session files, indexes
  44. #
  45. #    -a, --application     # Create application session files (default)
  46. #    -e, --everything      # Create HTML 2-way & hex files for everything
  47. #    -h                    # Print a brief help
  48. #    --help                # Print verbose help (this) and version
  49. #    --help2               # Print massive help
  50. #    -i, --info            # Create info file
  51. #    -q, --quiet           # Quiet, no output to screen
  52. #    -r, --raw             # Create raw files
  53. #    -v, --verbose         # Verbose - Create ALL files .. (except -e)
  54. #    -x, --index           # Create index files (default)
  55. #    -A, --noapplication   # Exclude application session files
  56. #    -H, --hex             # Include hex dumps (slow)
  57. #    -I, --noinfo          # Exclude info files
  58. #    -R, --noraw           # Exclude raw files
  59. #    -T, --notcp           # Exclude TCP traffic
  60. #    -U, --noudp           # Exclude UDP traffic
  61. #    -Y, --noicmp          # Exclude ICMP traffic
  62. #    -X, --noindex         # Exclude index files
  63. #    -k, --keydata         # Create extra files for keystroke analysis
  64. #    -D dir    --dir dir        # Output all files to this directory
  65. #    -b 25,79  --playtcp 25,79  # replay these TCP ports as well (playback)
  66. #    -B 36,42  --playudp 36,42  # replay these UDP ports as well (playback)
  67. #    -l 7,79   --htmltcp 7,79   # Create HTML for these TCP ports as well
  68. #    -L 7,123  --htmludp 7,123  # Create HTML for these UDP ports as well
  69. #    -m 1k     --min 1k         # Min size of connection to save ("k" for Kb)
  70. #    -M 1024k  --max 1k         # Max size of connection to save ("k" for Kb)
  71. #    -o size   --sort size      # sort Order: time/size/type/ip (Default time)
  72. #    -p 21,23  --port 21,23     # Only examine these ports (TCP & UDP)
  73. #    -P 80,81  --noport 80,81   # Exclude these ports (TCP & UDP)
  74. #    -s 5      --runonce 5      # Standalone. Run tcpdump/snoop for 5 mins.
  75. #    -S 5,10   --runmany 5,10   # Standalone, many. 10 samples of 5 mins each.
  76. #    -S 5      --runmany 5      # Standalone, endless. 5 min samples forever.
  77. #    -z        --runredo        # Standalone, redo. Rereads last run's logs.
  78. #    -j 10.1.2.1  --ipaddr 10.1.2.1    # Only examine these IPs
  79. #    -J 10.1.2.1  --noipaddr 10.1.2.1  # Exclude these IPs
  80. #    -f 'port 7'  --filter 'port 7'    # With standalone, use this dump filter.
  81. #
  82. # eg1,
  83. #      tcpdump -s9000 -w output1        # create tcpdump capture file
  84. #      chaosreader output1              # extract recognised sessions, or,
  85. #      chaosreader -ve output1          # gimme everything, or,
  86. #      chaosreader -p 20,21,23 output1  # only ftp and telnet...
  87. # eg2,
  88. #      snoop -o output1                 # create snoop capture file instead
  89. #      chaosreader output1              # extract recognised sessions...
  90. # eg3,
  91. #      chaosreader -S 2,5      # Standalone, sniff network 5 times for 2 mins
  92. #                              # each. View index.html for progress (or .text)
  93. #
  94. # Output Files: Many will be created, run this in a clean directory.
  95. #  Short example,
  96. #   index.html          Html index (full details)
  97. #   index.text          Text index
  98. #   index.file          File index for standalone redo mode
  99. #   image.html          HTML report of images
  100. #   getpost.html        HTML report of HTTP GET/POST requests
  101. #   session_0001.info       Info file describing TCP session #1
  102. #   session_0001.telnet.html    HTML coloured 2-way capture (time sorted)
  103. #   session_0001.telnet.raw Raw data 2-way capture (time sorted)
  104. #   session_0001.telnet.raw1    Raw 1-way capture (assembeled) server->client
  105. #   session_0001.telnet.raw2    Raw 1-way capture (assembeled) client->server
  106. #   session_0002.web.html   HTML coloured 2-way
  107. #   session_0002.part_01.html   HTTP portion of the above, a HTML file
  108. #   session_0003.web.html   HTML coloured 2-way
  109. #   session_0003.part_01.jpeg   HTTP portion of the above, a JPEG file
  110. #   session_0004.web.html   HTML coloured 2-way
  111. #   session_0004.part_01.gif    HTTP portion of the above, a GIF file
  112. #   session_0005.part_01.ftp-data.gz    An FTP transfer, a gz file.
  113. #   ...
  114. #  The convention is,
  115. #   session_*       TCP Sessions
  116. #   stream_*        UDP Streams
  117. #   icmp_*      ICMP packets
  118. #   index.html      HTML Index
  119. #   index.text      Text Index
  120. #   index.file      File Index for standalone redo mode only
  121. #   image.html      HTML report of images
  122. #   getpost.html    HTML report of HTTP GET/POST requests
  123. #   *.info      Info file describing the Session/Stream
  124. #   *.raw       Raw data 2-way capture (time sorted)
  125. #   *.raw1      Raw 1-way capture (assembeled) server->client
  126. #   *.raw2      Raw 1-way capture (assembeled) client->server
  127. #   *.replay        Session replay program (perl)
  128. #   *.partial.*     Partial capture (tcpdump/snoop were aware of drops)
  129. #   *.hex.html      2-way Hex dump, rendered in coloured HTML
  130. #   *.hex.text      2-way Hex dump in plain text
  131. #   *.X11.replay    X11 replay script (talks X11)
  132. #   *.textX11.replay    X11 communicated text replay script (text only)
  133. #   *.textX11.html  2-way text report, rendered in red/blue HTML
  134. #   *.keydata       Keystroke delay data file. Used for SSH analysis.
  135. #
  136. # Modes:
  137. #  * Normal - eg "chaosreader infile", this is where a tcpdump/snoop file
  138. #    was created previously and chaosreader reads and processes it.
  139. #  * Standalone, once - eg "chaosreader -s 10", this is where chaosreader
  140. #    runs tcpdump/snoop and generates the log file, in this case for 10 i
  141. #    minutes, and then processes the result. Some OS's may not have
  142. #    tcpdump or snoop available so this will not work (instead you may be
  143. #    able to get Ethereal, run it, save to a file, then use normal mode).
  144. #    There is a master index.html and the report index.html in a sub dir,
  145. #    which is of the format out_YYYYMMDD-hhmm, eg "out_20031003-2221".
  146. #  * Standalone, many - eg "chaosreader -S 5,12", this is where chaosreader
  147. #    runs tcpdump/snoop and generates many log files, in this case it
  148. #    samples 12 times for 5 minutes each. While this is running, the master
  149. #    index.html can be viewed to watch progress, which links to minor
  150. #    index.html reports in each sub directory.
  151. #  * Standalone, redo - eg "chaosreader -ve -z", (the -z), this is where
  152. #    a standalone capture was previously performed - and now you would like
  153. #    to reprocess the logs - perhaps with different options (in this case,
  154. #    "-ve"). It reads index.file to determine which capture logs to read.
  155. #  * Standalone, endless - eg "chaosreader -S 5", like standalone many -
  156. #    but runs forever (if you ever had the need?). Watch your disk space!
  157. #
  158. # Note: this is a work in progress, some of the code is a little unpolished.
  159. #
  160. # Advice:
  161. #  * Run chaosreader in an empty directory.
  162. #  * Create small packet dumps. Chaosreader uses around 5x the dump size
  163. #    in memory. A 100Mb file could need 500Mb of RAM to process.
  164. #  * Your tcpdump may allow "-s0" (entire packet) instead of "-s9000".
  165. #  * Beware of using too much disk space, especially standalone mode.
  166. #  * If you capture too many small connections giving a huge index.html,
  167. #    try using the -m option to ignore small connections. eg "-m 1k".
  168. #  * snoop logs may actually work better. Snoop logs are based on RFC1761,
  169. #    however there are many varients of tcpdump/libpcap and this program
  170. #    cannot read them all. If you have Ethereal you can create snoop logs
  171. #    during the "save as" option. On Solaris use "snoop -o logfile".
  172. #  * tcpdump logs may not be portable between OSs that use different sized
  173. #    timestamps or endian.
  174. #  * Logs are best created in a memory filesystem for speed, usually /tmp.
  175. #  * For X11 or VNC playbacks, first practise by replaying a recent captured
  176. #    session of your own. The biggest problem is colour depth, your screen
  177. #    must match the capture. For X11 check authentication (xhost +), for
  178. #    VNC check the viewers options (-8bit, "Hextile", ...)
  179. #  * SSH analysis can be performed with the "sshkeydata" program as
  180. #    demonstrated on http://www.brendangregg.com/sshanalysis.html .
  181. #    chaosreader provides the input files (*.keydata) that sshkeydata
  182. #    analyses.
  183. #
  184. # Bugs: The following assumptions may cause problems (check for new vers);
  185. #  * A lower port number = the service type. Eg with ports 31247 and 23,
  186. #    the actual type of session is telnet (23). This may not work for
  187. #    some things (eg, VNC).
  188. #  * Time based order is more important for 2-way sessions (eg telnet),
  189. #    SEQ order is more import for 1-way transfers (eg ftp-data).
  190. #  * One particular TCP session isn't active for long enough that the SEQ
  191. #    number loops (or even wraps).
  192. #
  193. # WARNING: Please don't use this software for anything illegal. That definition
  194. #  differs for every country, please check the law first.
  195. #  This is a great network troubleshooting and development tool, not a
  196. #  "cracking" or "hacking" tool - a misidentification that could render owning
  197. #  this software illegal in some countries.
  198. #
  199. # SEE ALSO: ethereal (GUI packet viewer), dsniff (sniffing toolkit)
  200. #
  201. # COPYRIGHT: Copyright (c) 2003, 2004 Brendan Gregg.
  202. #
  203. #  This program is free software; you can redistribute it and/or
  204. #  modify it under the terms of the GNU General Public License
  205. #  as published by the Free Software Foundation; either version 2
  206. #  of the License, or (at your option) any later version.
  207. #
  208. #  This program is distributed in the hope that it will be useful,
  209. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  210. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  211. #  GNU General Public License for more details.
  212. #
  213. #  You should have received a copy of the GNU General Public License
  214. #  along with this program; if not, write to the Free Software Foundation,
  215. #  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  216. #
  217. #  (http://www.gnu.org/copyleft/gpl.html)
  218. #
  219. # Author: Brendan Gregg  [Sydney, Australia]
  220. #
  221. # Todo:
  222. #  * Rework code to improve structure.
  223. #  * Add more application protocol filters. ARP, RARP.
  224. #  * Ensure current application filters are robust (more testing).
  225. #  * Process captured filenames from FTP, HTTP and NFS transfers.
  226. #  * Add more file types (magic numbers/frequency analysis).
  227. #  * Process more IPv6 extension headers, ICMP types.
  228. #
  229. # 28-Sep-2003   Brendan Gregg   Began writing this.
  230. # 08-Oct-2003      "      " Released version 0.7 beta
  231. # 09-Oct-2003      "      "     Added telnet replays
  232. # 12-Oct-2003      "      "     Added IRC ports and replays
  233. # 19-Oct-2003      "      "     Made code more robust on different OSs
  234. # 01-Nov-2003      "      " Code cleanup, complex data types, IPv6, ICMP
  235. # 03-Nov-2003      "      " Added Standalone mode, standalone redo, ...
  236. # 05-Nov-2003      "      " Added Image indexes, GETPOST indexes
  237. # 15-Nov-2003      "      " Added HTTP proxy style log, hex dumps
  238. # 27-Jan-2004      "      " Released experimental X11 & VNC processing
  239. # 30-Mar-2004      "      " 802.11b, sorts, less RAM used, tun packets.
  240. # 01-May-2004      "      " CLI enhanced, faster, SSH analysis.
  241.  
  242.  
  243. use Getopt::Long;
  244. use Benchmark;
  245.  
  246.  
  247. #####################
  248. # --- Variables ---
  249. #
  250.  
  251. #
  252. #  Some defaults
  253. #
  254. $PERL = "/usr/bin/perl";        # perl path for replay scripts
  255. $integerSize = length(pack('I',0)); # can make a difference for tcpdumps
  256. $the_date = scalar localtime();     # this is printed in the reports
  257. $WRAP = 108;                # wordwrap chars
  258. $BM = 0;                # benchmark counter
  259. $| = 1;                 # flush output
  260.  
  261. #
  262. #  The following is needed for old perl5 multiline matching. New perl5 uses
  263. #  a "/s" on the RE (which is used in this program as well).
  264. #
  265. $* = 1;                 # old perl5
  266.  
  267. #
  268. #  These ports have been selected to be saved as coloured 2-way HTML files
  269. #
  270. @Save_As_HTML_TCP_Ports = (21,23,25,79,80,109,110,119,143,513,514,1080,
  271.  3128,4110,5000,5555,6660,6665,6666,6667,6668,7000,8000,8080,9000);
  272. @Save_As_HTML_UDP_Ports = (53);
  273.  
  274. #
  275. #  These ports have been selected to be saved as realtime playback scripts
  276. #  (telnet, login, and numerous IRC ports)
  277. #
  278. @Save_As_TCP_Playback_Ports = (23,513,4110,5000,5555,6660,6666,6667,
  279.  6668,7000,8000,9000);
  280. @Save_As_UDP_Playback_Ports = (7);
  281.  
  282. #
  283. #  These are the X11 ports to save as X11 playback scripts
  284. #
  285. @Save_As_X11_Playback_Ports = (6000,6001,6002,6003,6004,6005,6006,6007);
  286.  
  287. #
  288. #  These X11 ports will have the text saved as coloured 2-way HTML files
  289. #
  290. @Save_As_HTML_X11_Ports = (6000,6001,6002,6003,6004,6005,6006,6007);
  291.  
  292. #
  293. #  These are the VNC ports to save as VNC playback scripts
  294. #
  295. @Save_As_VNC_Playback_Ports = (5900,5901,5902,5903,5904,5905,5906,5907);
  296.  
  297. #
  298. # --- Arguments ---
  299. #
  300. &Process_Command_Line_Arguments();
  301.  
  302. ### Record program start  
  303. $Bench{++$BM}{mark} = new Benchmark if $Arg{bench};
  304. $Bench{$BM}{text} = "Program Start";
  305.  
  306. #
  307. #  Load some lookup tables for number -> name translations.
  308. #
  309. &Load_Etc_Services();
  310. &Set_IP_Protocols();
  311. &Set_ICMP_Types();
  312. &Set_Result_Names();
  313. &Set_X11_Codes();
  314. &Set_X11_KeyCodes();
  315. &Set_VNC_Codes();
  316.  
  317.  
  318. ###########################
  319. # --- MODE 1 - Normal --- #
  320. ###########################
  321.  
  322. #
  323. #  Process log files,
  324. #
  325. if ($Arg{normal}) {
  326.     #
  327.     #  Initial values
  328.     #
  329.     $frame = 0; $number = 0;
  330.     %IP = (); %TCP = (); %UDP = (); %ICMP = (); %Count = (); %Hex = ();
  331.  
  332.     ### Print version
  333.     &Print_Welcome();
  334.  
  335.     ######################################
  336.     # --- INPUT - Read Packet Log(s) ---
  337.     #
  338.  
  339.     foreach $filename (@{$Arg{infiles}}) {
  340.         #
  341.         #  Check input file type and Open
  342.         #
  343.         &Open_Input_File($filename);
  344.  
  345.         #
  346.         #  Read though the entire input file, saving all packet
  347.         #  data in memory (mainly %TCP and %UDP).
  348.         #
  349.         &Read_Input_File();
  350.     }
  351.  
  352.  
  353.     #############################################
  354.     # --- OUTPUT - Process TCP/UDP Sessions ---
  355.     #
  356.  
  357.     ### cd to output
  358.     &Chdir($Arg{output_dir});
  359.     &Print_Header2();
  360.  
  361.     ### Determine Session and Stream time order
  362.     %Index = (); %Image = (); %GETPOST = ();
  363.     &Sort_Index();
  364.  
  365.     #
  366.     #  Process %TCP and create session* output files, write %Index
  367.     #
  368.     &Process_TCP_Sessions();
  369.  
  370.     #
  371.     #  Process %UDP and create session* output files, write %Index
  372.     #
  373.     &Process_UDP_Streams();
  374.  
  375.     #
  376.     # Process %ICMP
  377.     #
  378.     &Process_ICMP();
  379.  
  380.     #
  381.     #  Create Index Files from %Index
  382.     #
  383.     &Create_Index_Files();
  384.     &Create_Log_Files();
  385.  
  386.     ###############
  387.     # --- END ---
  388.     #
  389.     &Print_Footer1();
  390. }
  391.  
  392.  
  393. ###############################
  394. # --- MODE 2 - Standalone --- #
  395. ###############################
  396.  
  397. elsif ($Arg{standalone}) {
  398.  
  399.    ############################################################
  400.    # --- STANDALONE - Create Packet Logs and Process them ---
  401.    #
  402.  
  403.    $limit = $Arg{count};
  404.    $filenum = 0;
  405.  
  406.    ### Check for the sniffer command
  407.    &Check_Command();
  408.  
  409.    ### cd to output
  410.    &Chdir($Arg{output_dir});
  411.  
  412.    ### Print welcome
  413.    &Print_Welcome();
  414.  
  415.    #
  416.    #  MAIN LOOP
  417.    #
  418.    while ($limit != 0) {
  419.     #
  420.     #  Create a meaningful directory and filename
  421.     #
  422.     @Times = localtime();
  423.     $dirname = sprintf("out_%d%02d%02d-%02d%02d",($Times[5]+1900),
  424.      $Times[4],$Times[3],$Times[2],$Times[1]);
  425.     $filename = "$dirname.log";
  426.  
  427.     #
  428.     #  Initial values
  429.     #
  430.     $frame = 0; $number = 0;
  431.     %IP = (); %TCP = (); %UDP = (); %ICMP = (); %Count = (); %Hex = ();
  432.  
  433.     #
  434.     #  Record details in a Master Index
  435.     #
  436.     $Master[$filenum]{starttime} = scalar localtime();
  437.     $Master[$filenum]{duration} = - time();         # will +end time
  438.     $Master[$filenum]{dir} = $dirname;
  439.     $Master[$filenum]{file} = $filename;
  440.  
  441.     #
  442.     #  Create and cd to output dir
  443.     #
  444.     mkdir ("$dirname",0755) || die "ERROR01: Couldn't mkdir (perms?): $!\n";
  445.     chdir "$dirname" || die "ERROR02: Couldn't cd $dirname: $!\n";
  446.  
  447.     print "\nCreating log: $dirname/$filename\n" unless $Arg{quiet};
  448.  
  449.     #  
  450.     #  fork, so that one process can exec tcpdump/snoop while the other
  451.     #  sleeps and then kills it.
  452.     #
  453.     $pid = fork();
  454.     die "ERROR03: Can't fork (resources?): $!\n" if (! defined $pid);
  455.  
  456.     if ($pid == 0) {
  457.         ###############################
  458.         # --- CREATE - Packet Log ---
  459.         #
  460.  
  461.         print "Running: $command $filename $Arg{filter}\n"
  462.          unless $Arg{quiet};
  463.         ### exec, so $pid points to sniffer
  464.         exec("$command $filename $Arg{filter}") &&
  465.             die "ERROR04: couldn't run $command file: $!\n";
  466.     } else {
  467.         ### Wait for logfile to be populated
  468.         sleep($Arg{mins} * 60);
  469.  
  470.         ### Kill child (TERM, INT)
  471.         kill 15, $pid;
  472.         kill 2, $pid;
  473.     }
  474.     exit if $pid == 0;  # check for impossibility
  475.  
  476.  
  477.     ### Record end time, duration, size
  478.     $Master[$filenum]{endtime} = scalar localtime();
  479.     $Master[$filenum]{duration} += time();
  480.     # finish writing the log before reading it's size
  481.     system("sync") if (($^O eq "linux") || ($^O eq "solaris"));
  482.     $Master[$filenum]{size} = -s "$filename";
  483.  
  484.     print "\nProcessing:   $dirname/$filename\n" unless $Arg{quiet};
  485.     $bak = $Arg{quiet}; $Arg{quiet} = 1;
  486.  
  487.     ###############################
  488.     # --- INPUT - Process Log ---
  489.     #
  490.     &Open_Input_File($filename);
  491.  
  492.     ### Populate memory (%TCP, %UDP, ...).
  493.     &Read_Input_File();
  494.  
  495.     #############################################
  496.     # --- OUTPUT - Process TCP/UDP Sessions ---
  497.     #
  498.  
  499.     ### Determine Session and Stream time order
  500.     %Index = (); %Image = (); %GETPOST = ();
  501.     &Sort_Index();
  502.  
  503.     ### Process %TCP, %UDP, ..., create output fies, write %Index
  504.     &Process_TCP_Sessions();
  505.     &Process_UDP_Streams();
  506.     &Process_ICMP();
  507.  
  508.     ### Create Index Files from %Index
  509.     &Create_Index_Files();
  510.     &Create_Log_Files();
  511.  
  512.  
  513.     chdir ".." || die "ERROR05: Couldn't cd ..: $!\n";
  514.  
  515.     $Arg{quiet} = $bak;
  516.  
  517.     ### Create Master Index from @Master
  518.     &Create_Index_Master();
  519.  
  520.     $limit--;
  521.     $filenum++;
  522.    }
  523.  
  524. }
  525.  
  526.  
  527. ##########################
  528. # --- MODE 3 - Redo  --- #
  529. ##########################
  530.  
  531. elsif ($Arg{redo}) {
  532.  
  533.    #############################################################
  534.    # --- STANDALONE REDO - Redo last run from sniffer logs ---
  535.    #
  536.  
  537.    $filenum = 0;
  538.  
  539.    ### Read index.file for logs to process
  540.    &Load_Index_File();
  541.  
  542.    ### Print welcome
  543.    &Print_Welcome();
  544.  
  545.    #
  546.    #  MAIN LOOP
  547.    #
  548.    for ($index=0; $index <= $#Master; $index++) {
  549.  
  550.     ### Get previous run values
  551.     $dirname = $Master[$index]{dir};
  552.     $filename = $Master[$index]{file};
  553.  
  554.     ### Initial values
  555.     $frame = 0; $number = 0;
  556.     %IP = (); %TCP = (); %UDP = (); %ICMP = (); %Count = (); %Hex = ();
  557.  
  558.     ### Create and cd to output dir
  559.     chdir "$dirname" || die "ERROR06: Couldn't cd $dirname: $!\n";
  560.  
  561.     print "Processing:   $dirname/$filename\n" unless $Arg{quiet};
  562.     $bak = $Arg{quiet}; $Arg{quiet} = 1;
  563.  
  564.     ###############################
  565.     # --- INPUT - Process Log ---
  566.     #
  567.     &Open_Input_File($filename);
  568.  
  569.     ### Populate memory (%TCP, %UDP, ...).
  570.     &Read_Input_File();
  571.  
  572.     #############################################
  573.     # --- OUTPUT - Process TCP/UDP Sessions ---
  574.     #
  575.  
  576.     ### Determine Session and Stream time order
  577.     %Index = (); %Image = (); %GETPOST = ();
  578.     &Sort_Index();
  579.  
  580.     ### Process %TCP, %UDP, ..., create output fies, write %Index
  581.     &Process_TCP_Sessions();
  582.     &Process_UDP_Streams();
  583.     &Process_ICMP();
  584.  
  585.     ### Create Index Files from %Index
  586.     &Create_Index_Files();
  587.     &Create_Log_Files();
  588.  
  589.     chdir ".." || die "ERROR07: Couldn't cd ..: $!\n";
  590.     $Arg{quiet} = $bak;
  591.  
  592.     $limit--;
  593.     $filenum++;
  594.    }
  595.    ### Create Master Index from @Master
  596.    &Create_Index_Master();
  597. }
  598.  
  599.  
  600. #
  601. #  BENCHMARK REPORT
  602. #
  603. if ($Arg{bench}) {
  604.     $Bench{++$BM}{mark} = new Benchmark;
  605.     $Bench{$BM}{text} = "Program End";
  606.  
  607.     print "\nBenchmarks,\n\n";
  608.     for ($bm=1; $bm <= $BM; $bm++) {
  609.         $bdiff = timediff($Bench{$bm}{mark},$Bench{1}{mark});
  610.         printf(" %-32s %s\n",$Bench{$bm}{text},timestr($bdiff));
  611.     }
  612. }
  613.  
  614.  
  615. #####################
  616. # --- SUBROUTINES ---
  617.  
  618. # (Most of these subroutines are used as shortcuts to code, not traditional
  619. #  scoped subroutines as with other languages)
  620.  
  621.  
  622.  
  623. # Open_Input_File - open the packet log specified. This checks the header
  624. #   of the file to determine whether it is a tcpdump/libpcap or snoop
  625. #   log (including several styles of tcpdump/libpcap).
  626. #
  627. sub Open_Input_File {
  628.  
  629.     my $infile = shift;
  630.     my ($length,$size);
  631.  
  632.     $Bench{++$BM}{mark} = new Benchmark if $Arg{bench};
  633.     $Bench{$BM}{text} = "Open Input File";
  634.  
  635.     print "Opening, $infile\n\n" unless $Arg{quiet};
  636.  
  637.     #
  638.     #  Open packet log
  639.     #
  640.     open(INFILE,$infile) || die "Can't open $infile: $!\n";
  641.     binmode(INFILE);    # for backward OSs
  642.    
  643.     #
  644.     #  Fetch header
  645.     #
  646.     $length = read(INFILE,$header,8);
  647.     die "ERROR08: Can't read from $infile\n" if $length < 8;
  648.  
  649.     ### Print status
  650.     print "Reading file contents,\n" unless $Arg{quiet};
  651.     $SIZE = -s $infile;
  652.  
  653.     #
  654.     #  Try to determine if this is a tcpdump or a snoop file
  655.     #
  656.     ($ident) = unpack('a8',$header);
  657.  
  658.     if ($ident =~ /^snoop/) {
  659.    
  660.         $TYPE = "snoop";
  661.         $length = read(INFILE,$header,8);
  662.         ($version,$type) = unpack('NN',$header);
  663.  
  664.     } elsif ($ident =~ /^\241\262\303\324|^\324\303\262\241/ ||
  665.          $ident =~ /^\241\262\315\064|^\064\315\262\241/) {
  666.  
  667.         $TYPE = "tcpdump";
  668.         $ident = unpack('a4',$header);  # try again
  669.         # standard/modified defines style, 1/2 defines endian
  670.         if ($ident =~ /^\241\262\303\324/) { $STYLE = "standard1"; }
  671.         if ($ident =~ /^\324\303\262\241/) { $STYLE = "standard2"; }
  672.         if ($ident =~ /^\241\262\315\064/) { $STYLE = "modified1"; }
  673.         if ($ident =~ /^\064\315\262\241/) { $STYLE = "modified2"; }
  674.         if ($STYLE =~ /1$/) {
  675.             # reread in big-endian
  676.             ($ident,$major,$minor) = unpack('a4nn',$header);
  677.         } else {
  678.             # reread in little-endian
  679.             ($ident,$major,$minor) = unpack('a4vv',$header);
  680.         }
  681.  
  682.         #
  683.         #  Check tcpdump header carefully to ensure this is ver 2.4.
  684.         #
  685.         if ($major != 2 && $minor != 4) {
  686.             #
  687.             #  Die if this is an unknown version. (there could
  688.             #  be new vers of tcpdump/libpcap in the future).
  689.             #
  690.             print STDERR "ERROR09: Wrong tcpdump version ";
  691.             print STDERR "($version.$type).\n(expected 2.4).\n";
  692.             exit 1;
  693.     }
  694.         #
  695.         #  Nudge the filehandle past the rest of the header...
  696.         #
  697.         $length = read(INFILE,$header_rest,16);
  698.    
  699.     } else {
  700.         #
  701.         #  Die - unknown file format
  702.         #
  703.         print STDERR "ERROR10: Input dosen't look like a tcpdump or ";
  704.         print STDERR "snoop output file.\n\tIf it is tcpdump, it ";
  705.         print STDERR "may be a wrong or new version.\n";
  706.         exit 1;
  707.     }
  708.  
  709.     ### Record the filename into the global %Arg
  710.     $Arg{infile} = $infile;
  711. }
  712.  
  713.  
  714.  
  715. # Read_Input_File - this subroutine loops through the records in the packet
  716. #  log, storing all the TCP and UDP data into %TCP and %UDP. (see the end
  717. #  of the program for the structure of these data types). %Count is also
  718. #  populated with various frequency counts.
  719. #
  720. sub Read_Input_File {
  721.    my ($trailers,$pppoe_verNtype,$pppoe_code,$pppoe_id,$pppoe_length,
  722.     $ppp_protocol,$wless_fc,$wless_version,$wless_type,$wless_duration,
  723.     $wless_subtype,$wless_from,$wless_to,$wless_flag,$wless_WEP,
  724.     $wless_bss,$wless_src,$wless_dest,$wless_cksum,$llc_head,$llc_control,
  725.     $llc_org,$llc_type,$wless_OK,$bytes,$counter,$packets);
  726.  
  727.    $Bench{++$BM}{mark} = new Benchmark if $Arg{bench};
  728.    $Bench{$BM}{text} = "Read Input File - start";
  729.  
  730.    local $packet = 0;           # counter
  731.    if ($TYPE eq "snoop") {
  732.     $bytes = 16;
  733.    } else {
  734.     $bytes = 24;
  735.    }
  736.  
  737.    #
  738.    # --- Pass #1, Store IP data in memory (%IP) --
  739.    #
  740.    while (1) {
  741.     #
  742.     # --- Read Record from Log ---
  743.     #
  744.     if ($TYPE eq "snoop") {
  745.         &Read_Snoop_Record();       # will "last" on error
  746.         $packet_data = $snoop_data;
  747.         $packet_time = $snoop_seconds;
  748.         $packet_timefull = $snoop_seconds + $snoop_msecs/1000000;
  749.         $record_size = $snoop_length_rec;
  750.     } else {
  751.         &Read_Tcpdump_Record();     # will "last" on error
  752.         $packet_data = $tcpdump_data;
  753.         $packet_time = $tcpdump_seconds;
  754.         $packet_timefull = $tcpdump_seconds + $tcpdump_msecs/1000000;
  755.         $record_size = $tcpdump_length + ($integerSize * 2 + 8);
  756.     }
  757.  
  758.     ### Print status summary
  759.     unless ($Arg{quiet}) {
  760.         $bytes += $record_size;
  761.         if (($packet % 16) == 0) {
  762.             printf("%s %2.0f%% (%d/%d)","\b"x24,
  763.              (100*$bytes/$SIZE),$bytes,$SIZE);
  764.         }
  765.     }
  766.  
  767.     #
  768.     # --- Parse TCP/IP layers (a little ;) ---
  769.     #
  770.  
  771.     #-------------------------------------------------------------------
  772.     #
  773.     #  Wireless, 802.11b
  774.     #
  775.  
  776.     $decoded = 0;       # this flag is true if wireless was found
  777.  
  778.     # unpack a little first, (efficiency)
  779.     ($wless_fc) = unpack('H4',$packet_data);
  780.  
  781.     # this matches on possible send or receive wireless traffic, however
  782.     # this could also be the start of an 802.3 frame - making this part
  783.     # of a MAC address. (The IEEE list on OUIs had these as unassigned).
  784.     if ($wless_fc =~ /^080[1256]/) {
  785.         # now dig deeper,
  786.         # (this is one form of 802.11 - the form we are interested
  787.         # in, however note that there is a lot more to 802.11).
  788.         ($wless_fc,$wless_duration,$wless_bss,$wless_src,
  789.          $wless_dest,$wless_cksum,$llc_head,$llc_control,$llc_org,
  790.          $llc_type,$ether_data)
  791.          = unpack('nnH12H12H12na2CH6H4a*',$packet_data);
  792.    
  793.         $wless_to = $wless_fc & 1;
  794.  
  795.         # Check this is IP and encapsulated Ethernet,
  796.         if (($llc_type eq "0800") && ($llc_org eq "000000")) {
  797.  
  798.            ### Populate ether variables for use later on
  799.            $ether_type = $llc_type;
  800.            if ($wless_to) {
  801.             $ether_dest = $wless_dest;
  802.             $ether_src = $wless_src;
  803.            } else {
  804.             $ether_dest = $wless_src;
  805.             $ether_src = $wless_dest;
  806.            }
  807.  
  808.            $decoded = 1;    # remember we did this
  809.         }
  810.         # (else try redecoding this using 802.3)
  811.     }
  812.  
  813.     #-------------------------------------------------------------------
  814.     #
  815.     #  Tun device
  816.     #
  817.  
  818.     # unpack a little first, (efficiency)
  819.     ($tun_id) = unpack('H8',$packet_data);
  820.  
  821.     # this checks if the frame looks like a tun device frame
  822.     if ($tun_id eq "02000000") {
  823.         # now dig deeper,
  824.         ($tun_id,$ether_data) = unpack('a4a*',$packet_data);
  825.         $ether_src = "0";
  826.         $ether_dest = "0";
  827.         $ether_type = "0800";
  828.  
  829.         $decoded = 1;       # remember we did this
  830.     }
  831.  
  832.     #-------------------------------------------------------------------
  833.     #
  834.     #  Ethernet, 802.3
  835.     #
  836.  
  837.     ### Unpack ether data
  838.     ($ether_dest,$ether_src,$ether_type,$ether_data) =
  839.      unpack('H12H12H4a*',$packet_data) unless $decoded;
  840.  
  841.     ### Count ether types seen
  842.     $Count{EtherType}{$ether_type}++;
  843.     $CountMaster{EtherType}{$ether_type}++;
  844.    
  845.     #
  846.     #  Process extended Ethernet types (wireless, PPPoE)
  847.     #
  848.  
  849.     ### PPPoE
  850.     if ($ether_type eq "8864") {
  851.         ($pppoe_verNtype,$pppoe_code,$pppoe_id,$pppoe_length,
  852.          $ppp_protocol,$ether_data) = unpack("CCnnna*",$ether_data);
  853.        
  854.         ### Skip anything but data (we just want data - code 0)
  855.         next if $pppoe_code != 0;
  856.  
  857.         # (May like to add code here later to process $ppp_protocol,
  858.         # eg, to process LCP).
  859.     }
  860.  
  861.     elsif (($ether_type ne "0800") && ($ether_type ne "86dd")) {
  862.         next;
  863.     }
  864.  
  865.     #-------------------------------------------------------------------
  866.     #
  867.     #  IP
  868.     #
  869.    
  870.     ### Check for IP ver
  871.     ($ip_verNihl,$ip_rest) = unpack('Ca*',$ether_data);
  872.     $ip_ver = $ip_verNihl & 240;
  873.     $ip_ver = $ip_ver >> 4;
  874.  
  875.     if ($ip_ver == 4) {
  876.  
  877.         #-----------------------------------------------------------
  878.         #
  879.         #  IPv4
  880.         #
  881.  
  882.         ### Unpack IP data
  883.         ($ip_verNihl,$ip_tos,$ip_length,$ip_ident,$ip_flagNfrag,
  884.          $ip_ttl,$ip_protocol,$ip_checksum,@ip_src[0..3],
  885.          @ip_dest[0..3],$ip_data) = unpack('CCnnnCCa2CCCCCCCCa*',
  886.          $ether_data);
  887.  
  888.         ### Get frag and flag data
  889.         $ip_frag = $ip_flagNfrag & 8191;
  890.         $ip_flag = $ip_flagNfrag & 57344;
  891.         $ip_flag = $ip_flag >> 13;
  892.         $ip_MF = $ip_flag & 1;
  893.  
  894.         ### Strip off IP options if present
  895.         $ip_ihl = $ip_verNihl & 15;
  896.         $ip_ihl = $ip_ihl << 2;
  897.         $ip_options_num = $ip_ihl - 20;
  898.         if ($ip_options_num > 0) {
  899.             ($ip_options,$ip_data) =
  900.              unpack("a${ip_options_num}a*",$ip_data);
  901.         }
  902.  
  903.         ### Strip off Ethernet trailers
  904.         $ip_dlength = $ip_length - $ip_options_num - 20;
  905.         ($ip_data,$trailers) = unpack("a${ip_dlength}a*",$ip_data);
  906.  
  907.         ### Build text strings of IP addresses
  908.         $ip_src = sprintf("%u.%u.%u.%u",@ip_src);
  909.         $ip_dest = sprintf("%u.%u.%u.%u",@ip_dest);
  910.  
  911.     } elsif ($ip_ver == 6) {
  912.  
  913.         #-----------------------------------------------------------
  914.         #
  915.         #  IPv6
  916.         #
  917.         ($ip_verNihl,$ip_flow,$ip_length,$ip_next,$ip_hop,
  918.          @ip_src[0..15],@ip_dest[0..15],$ip_data) =
  919.          unpack('Ca3nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCa*',
  920.          $ether_data);
  921.         $ip_protocol = $ip_next;
  922.  
  923.         ### Build text strings of IP addresses
  924.         $ip_src = sprintf("%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x",
  925.          @ip_src);
  926.         $ip_dest = sprintf("%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x",
  927.          @ip_dest);
  928.    
  929.         ### Compress IPv6 text Address
  930.         $ip_src =~ s/:00:/:0:/g;
  931.         $ip_src =~ s/:00:/:0:/g;
  932.         $ip_dest =~ s/:00:/:0:/g;
  933.         $ip_dest =~ s/:00:/:0:/g;
  934.         $ip_src =~ s/(:0)+/::/;
  935.         $ip_dest =~ s/(:0)+/::/;
  936.  
  937.  
  938.         #
  939.         #  Check for IPv6 Fragmentation (embedded)
  940.         #
  941.         if ($ip_protocol == 44) {
  942.             ($ip_next,$ip_reserved,$ip_fragNmf,$ip_ident,$ip_data)
  943.              = unpack('CCnNa*',$ip_data);
  944.              $ip_protocol = $ip_next;
  945.             $ip_MF = $ip_fragNmf & 1;
  946.             $ip_frag = $ip_fragNmf >> 3;
  947.         } else {
  948.             $ip_MF = 0;
  949.             $ip_ident = 0;
  950.             $ip_frag = 0;
  951.         }
  952.        
  953.     } else {
  954.         ### Not IPv4 or IPv6 - could be LCP (skip for now)
  955.         next;
  956.     }
  957.  
  958.     ### Count IP Protocols seen
  959.     $Count{IPprotocol}{$ip_protocol}++;
  960.     $CountMaster{IPprotocol}{$ip_protocol}++;
  961.  
  962.     ### Count IP Addresses seen
  963.     $Count{IP}{$ip_src}++;
  964.     $CountMaster{IP}{$ip_src}++;
  965.  
  966.     ### Generate unique IP id (not just the ident)
  967.     $ip_id = &Generate_IP_ID($ip_src,$ip_dest,$ip_ident);
  968.    
  969.     #
  970.     #  Store IP data in %IP so we can do frag reassembly next
  971.     #
  972.     if (! defined $IP{id}{$ip_id}{StartTime}) {
  973.         $IP{time}{$packet_timefull}{ver} = $ip_ver;
  974.         $IP{time}{$packet_timefull}{src} = $ip_src;
  975.         $IP{time}{$packet_timefull}{dest} = $ip_dest;
  976.         $IP{time}{$packet_timefull}{protocol} = $ip_protocol;
  977.         $IP{time}{$packet_timefull}{frag}{$ip_frag} = $ip_data;
  978.         if ($snoop_drops || $tcpdump_drops) {
  979.             $IP{time}{$packet_timefull}{drops} = 1;
  980.         }
  981.         #
  982.         #  If there are more fragments, remember this starttime
  983.         #
  984.         unless (($ip_MF == 0) && ($ip_frag == 0)) {
  985.             $IP{id}{$ip_id}{StartTime} = $packet_timefull;
  986.         }
  987.         if (($ip_MF == 1) || ($ip_frag > 0)) {
  988.             $IP{time}{$packet_timefull}{fragged} = 1;
  989.         }
  990.     } else {
  991.         $start_time = $IP{id}{$ip_id}{StartTime};
  992.         $IP{time}{$start_time}{frag}{$ip_frag} = $ip_data;
  993.         if ($snoop_drops || $tcpdump_drops) {
  994.             $IP{time}{$packet_timefull}{drops} = 1;
  995.         }
  996.         if ($ip_MF == 0) {
  997.             #
  998.             #  Comlpete this IP packet. This assumes that the
  999.             #  last frag arrives last.
  1000.             #
  1001.             undef $IP{ident}{StartTime}{$ip_id};
  1002.         }
  1003.     }
  1004.     $packet++;
  1005.    }
  1006.  
  1007.    close INFILE;
  1008.  
  1009.    ### Print status summary
  1010.    unless ($Arg{quiet}) {
  1011.     printf("%s %2.0f%% (%d/%d)","\b"x24,
  1012.      100,$bytes,$SIZE);
  1013.     print "\nReassembling packets,\n";
  1014.    }
  1015.  
  1016.  
  1017.  
  1018.    ###################################################################
  1019.    #  --- Pass #2, Reassemble IP data in %IP; create %TCP and %UDP ---
  1020.    #
  1021.    
  1022.    &Print_Header1() if $Arg{debug};
  1023.    $packets = $packet;
  1024.    $packet = 0;
  1025.    @Times = sort { $a <=> $b } ( keys(%{$IP{time}}) );
  1026.    foreach $time (@Times) {
  1027.    
  1028.     ### Print status summary
  1029.     unless ($Arg{quiet}) {
  1030.         if (($packet % 16) == 0) {
  1031.             printf("%s %2.0f%% (%d/%d)","\b"x32,
  1032.              (100*$packet/$packets),$packet,$packets);
  1033.         }
  1034.     }
  1035.  
  1036.     #
  1037.     #  Get IP data from %IP
  1038.     #
  1039.     $ip_ver = $IP{time}{$time}{ver};
  1040.     $ip_src = $IP{time}{$time}{src};
  1041.     $ip_dest = $IP{time}{$time}{dest};
  1042.     $ip_protocol = $IP{time}{$time}{protocol};
  1043.     $drops = $IP{time}{$time}{drops};
  1044.     undef $ip_data;
  1045.  
  1046.     #
  1047.     #  Reassemble IP frags
  1048.     #
  1049.     if (defined $IP{time}{$time}{fragged}) {
  1050.         @IP_Frags = sort {$a <=> $b} (keys(%{$IP{time}{$time}{frag}}));
  1051.  
  1052.         ### If never recieved the start of the packet, skip
  1053.         if ($IP_Frags[0] != 0) { next; }
  1054.  
  1055.         foreach $ip_frag (@IP_Frags) {
  1056.             $ip_data .= $IP{time}{$time}{frag}{$ip_frag};
  1057.         }
  1058.     } else {
  1059.         $ip_data = $IP{time}{$time}{frag}{0};
  1060.     }
  1061.     $length = length($ip_data);
  1062.  
  1063.     #
  1064.     # --- UDP ---
  1065.     #
  1066.     if ($ip_protocol == 17 && $Arg{output_UDP}) {
  1067.         &Process_UDP_Packet($ip_data,$ip_src,$ip_dest,$time,$drops);
  1068.     }
  1069.  
  1070.     #
  1071.     # --- TCP ---
  1072.     #
  1073.     if ($ip_protocol == 6 && $Arg{output_TCP}) {
  1074.         &Process_TCP_Packet($ip_data,$ip_src,$ip_dest,$time,$drops);
  1075.     }
  1076.  
  1077.     #
  1078.     # --- ICMP ---
  1079.     #
  1080.     if ($ip_protocol == 1 && $Arg{output_ICMP}) {
  1081.         &Process_ICMP_Packet($ip_data,$ip_src,$ip_dest,$time,$drops,
  1082.          "ICMP");
  1083.     }
  1084.  
  1085.     #
  1086.     # --- ICMPv6 ---
  1087.     #
  1088.     if ($ip_protocol == 58 && $Arg{output_ICMP}) {
  1089.         &Process_ICMP_Packet($ip_data,$ip_src,$ip_dest,$time,$drops,
  1090.          "ICMPv6");
  1091.     }
  1092.  
  1093.     #
  1094.     #  Skip packet if it isn't TCP (protocol = 6). (Will add routines for
  1095.     #  ICMP, ARP, RARP later on)...
  1096.     #
  1097.  
  1098.     $packet++;
  1099.  
  1100.     ### Memory Cleanup
  1101.     delete $IP{time}{$time};
  1102.  
  1103.    }
  1104.  
  1105.    ### Memory Cleanup
  1106.    undef %IP;
  1107.  
  1108.    ### Print status summary
  1109.    unless ($Arg{quiet}) {
  1110.     printf("%s %2.0f%% (%d/%d)\n","\b"x24,
  1111.      100,$packet,$packets);
  1112.    }
  1113.  
  1114.    $Bench{++$BM}{mark} = new Benchmark if $Arg{bench};
  1115.    $Bench{$BM}{text} = "Read Input File - end";
  1116. }
  1117.  
  1118.  
  1119.  
  1120. # Process_TCP_Packet - process a TCP packet and store it in memory. It takes
  1121. #   the raw ip data and populates the data structure %TCP. (and %Count).
  1122. #
  1123. sub Process_TCP_Packet {
  1124.  
  1125.     my $ip_data = shift;
  1126.     my $ip_src = shift;
  1127.     my $ip_dest = shift;
  1128.     my $time = shift;
  1129.     my $drops = shift;
  1130.     my $copy;
  1131.  
  1132.     #-------------------------------------------------------------------
  1133.     #
  1134.     #  TCP
  1135.     #
  1136.  
  1137.     ### Unpack TCP data
  1138.     ($tcp_src_port,$tcp_dest_port,$tcp_seq,$tcp_ack,$tcp_offset,$tcp_flags,
  1139.      $tcp_header_rest,$tcp_data) = unpack('nnNNCCa6a*',$ip_data);
  1140.  
  1141.     ### Strip off TCP options, if present
  1142.     $tcp_offset = $tcp_offset >> 4;     # chuck out reserved bits
  1143.     $tcp_offset = $tcp_offset << 2;     # now times by 4
  1144.     $tcp_options_num = $tcp_offset - 20;
  1145.     if ($tcp_options_num > 0) {
  1146.         ($tcp_options,$tcp_data) =
  1147.          unpack("a${tcp_options_num}a*",$tcp_data);
  1148.     }
  1149.  
  1150.     ### Fetch length and FIN,RST flags
  1151.     $tcp_length_data = length($tcp_data);
  1152.     $tcp_fin = $tcp_flags & 1;
  1153.     $tcp_syn = $tcp_flags & 2;
  1154.     $tcp_rst = $tcp_flags & 4;
  1155.     $tcp_ack = $tcp_flags & 16;
  1156.  
  1157.     $copy = $tcp_data;
  1158.  
  1159.     #
  1160.     #  Generate $session_id as a unique id for this stream
  1161.     #  (this is built from host:port,host:port - sorting on port).
  1162.     #
  1163.     ($session_id,$from_server) = &Generate_SessionID($ip_src,$tcp_src_port,
  1164.      $ip_dest,$tcp_dest_port,"TCP");
  1165.  
  1166.     ### Record direction if single SYN was seen
  1167.     if ($tcp_syn && ! $tcp_ack) {
  1168.         $TCP{id}{$session_id}{source} = $ip_src;
  1169.         # better repeat this,
  1170.         ($session_id,$from_server) = &Generate_SessionID($ip_src,
  1171.          $tcp_src_port,$ip_dest,$tcp_dest_port,"TCP");
  1172.     }
  1173.  
  1174.     ### Count TCP Ports seen
  1175.     if ($from_server) {
  1176.         $Count{TCPport}{$tcp_src_port}++;
  1177.         $CountMaster{TCPport}{$tcp_src_port}++;
  1178.     } else {
  1179.         $Count{TCPport}{$tcp_dest_port}++;
  1180.         $CountMaster{TCPport}{$tcp_dest_port}++;
  1181.     }
  1182.  
  1183.     #
  1184.     #  Flag this session as a Partial if either tcpdump or snoop
  1185.     #  confesses to dropping packets.
  1186.     #
  1187.     $TCP{id}{$session_id}{Partial}++ if $drops;
  1188.  
  1189.     ### Store size
  1190.     $TCP{id}{$session_id}{size} += length($tcp_data);
  1191.  
  1192.     ### Store the packet timestamp for the first seen packet
  1193.     if (! defined $TCP{id}{$session_id}{StartTime}) {
  1194.         $TCP{id}{$session_id}{StartTime} = $time;
  1195.  
  1196.         ### Store other info once
  1197.         if ($from_server) {
  1198.             $TCP{id}{$session_id}{src} = $ip_dest;
  1199.             $TCP{id}{$session_id}{dest} = $ip_src;
  1200.             $TCP{id}{$session_id}{src_port} = $tcp_dest_port;
  1201.             $TCP{id}{$session_id}{dest_port} = $tcp_src_port;
  1202.         } else {
  1203.             $TCP{id}{$session_id}{src} = $ip_src;
  1204.             $TCP{id}{$session_id}{dest} = $ip_dest;
  1205.             $TCP{id}{$session_id}{src_port} = $tcp_src_port;
  1206.             $TCP{id}{$session_id}{dest_port} = $tcp_dest_port;
  1207.         }
  1208.     }
  1209.  
  1210.     ### Store the packet timestamp in case this is the last packet
  1211.     $TCP{id}{$session_id}{EndTime} = $time;
  1212.  
  1213.     ### Print status line
  1214.     printf "%6s  %-45s  %s\n",$packet,$session_id,$length
  1215.      if $Arg{debug};
  1216.  
  1217.  
  1218.     #
  1219.     # --- Store Session Data in Memory ---
  1220.     #
  1221.     # Since TCP is usually the bulk of the data, we minimise
  1222.     # the number of copies of data in memory. UDP and ICMP
  1223.     # are handled differently.
  1224.  
  1225.     if ($from_server) {
  1226.         #
  1227.         #  Populate %TCP{id}{}{time} with raw traffic by time.
  1228.         #  This is the master structure to store the data.
  1229.         #
  1230.         $TCP{id}{$session_id}{time}{$time}{data} .= $tcp_data;
  1231.         $TCP{id}{$session_id}{time}{$time}{dir} .= "A";
  1232.  
  1233.         #
  1234.         #
  1235.         #  Populate %TCP{id}{}{Aseq} with server to client
  1236.         #  1-way raw traffic, with the TCP sequence number as
  1237.         #  the key (for future reassembly).
  1238.         #
  1239.         #  This is a pointer to the time structure above,
  1240.         #  to save on memory used (originally stored a
  1241.         #  duplicate copy of the data).
  1242.         #
  1243.         if ((! defined $TCP{id}{$session_id}{Aseq}{$tcp_seq}) ||
  1244.          (length(${$TCP{id}{$session_id}{Aseq}{$tcp_seq}}) <
  1245.          length($tcp_data))) {
  1246.             $TCP{id}{$session_id}{Aseq}{$tcp_seq} =
  1247.              \$TCP{id}{$session_id}{time}{$time}{data};
  1248.         }
  1249.  
  1250.         #
  1251.         #  Populate %Hex{TCP}{} with coloured HTML 2-way
  1252.         #  traffic, if needed.
  1253.         #
  1254.         if ($Arg{output_hex}) {
  1255.             &Process_Hex("TCP",$session_id,$tcp_data,"blue");
  1256.         }
  1257.  
  1258.        } else {
  1259.         #
  1260.         #  Populate %TCP{id}{}{Btime} with raw 1-way traffic by time.
  1261.         #  This is the master structure to store the data.
  1262.         #
  1263.         $TCP{id}{$session_id}{time}{$time}{data} .= $tcp_data;
  1264.         $TCP{id}{$session_id}{time}{$time}{dir} .= "B";
  1265.  
  1266.         #
  1267.         #
  1268.         #  Populate %TCP{id}{}{Bseq} with client to server
  1269.         #  1-way raw traffic, with the TCP sequence number as
  1270.         #  the key (for future reassembly).
  1271.         #
  1272.         #  This is a pointer to the time structure above,
  1273.         #  to save on memory used (originally stored a
  1274.         #  duplicate copy of the data).
  1275.         #
  1276.         if ((! defined $TCP{id}{$session_id}{Bseq}{$tcp_seq}) ||
  1277.          (length(${$TCP{id}{$session_id}{Bseq}{$tcp_seq}}) <
  1278.          length($tcp_data))) {
  1279.             $TCP{id}{$session_id}{Bseq}{$tcp_seq} =
  1280.              \$TCP{id}{$session_id}{time}{$time}{data};
  1281.         }
  1282.  
  1283.         #
  1284.         #  Populate %Hex{TCP}{} with coloured HTML 2-way
  1285.         #  traffic, if needed.
  1286.         #
  1287.         if ($Arg{output_hex}) {
  1288.             &Process_Hex("TCP",$session_id,$tcp_data,"red");
  1289.         }
  1290.  
  1291.     }
  1292.  
  1293. }
  1294.  
  1295.  
  1296.  
  1297. # Process_UDP_Packet - process a UDP packet and store it in memory. It takes
  1298. #   the raw ip data and populates the data structure %UDP.
  1299. #
  1300. sub Process_UDP_Packet {
  1301.  
  1302.     my $ip_data = shift;
  1303.     my $ip_src = shift;
  1304.     my $ip_dest = shift;
  1305.     my $time = shift;
  1306.     my $drops = shift;
  1307.     my $copy;
  1308.  
  1309.     #-------------------------------------------------------------------
  1310.     #
  1311.     #  UDP
  1312.     #
  1313.  
  1314.     ### Unpack UDP data
  1315.     ($udp_src_port,$udp_dest_port,$udp_length,$udp_checksum,
  1316.      $udp_data) = unpack('nnnna*',$ip_data);
  1317.  
  1318.     #
  1319.     #  Generate $session_id as a unique id for this stream
  1320.     #  (this is built from host:port,host:port - sorting on port).
  1321.     #
  1322.     ($session_id,$from_server) = &Generate_SessionID($ip_src,$udp_src_port,
  1323.      $ip_dest,$udp_dest_port,"UDP");
  1324.  
  1325.     #
  1326.     #  Flag this session as a Partial if either tcpdump or snoop
  1327.     #  confesses to dropping packets.
  1328.     #
  1329.     $UDP{id}{$session_id}{Partial}++ if $drops;
  1330.  
  1331.     ### Store size
  1332.     $UDP{id}{$session_id}{size} += length($udp_data);
  1333.  
  1334.     ### Count UDP ports seen
  1335.     if ($from_server) {
  1336.         $Count{UDPport}{$udp_src_port}++;
  1337.         $CountMaster{UDPport}{$udp_src_port}++;
  1338.     } else {
  1339.         $Count{UDPport}{$udp_dest_port}++;
  1340.         $CountMaster{UDPport}{$udp_dest_port}++;
  1341.     }
  1342.  
  1343.     #
  1344.     # --- Store Stream Data in Memory ---
  1345.     #
  1346.  
  1347.     if ($from_server) {
  1348.         #
  1349.         #  Populate %UDP{id}{}{RawA} with server to client
  1350.         #  1-way raw traffic
  1351.         #
  1352.         $UDP{id}{$session_id}{RawA} .= $udp_data;  
  1353.  
  1354.         #
  1355.         #  Populate %UDP{id}{}{BothHTML} with coloured HTML
  1356.         #  2-way traffic, blue for server to client
  1357.         #
  1358.         $copy = &Desex_HTML($udp_data);
  1359.         $UDP{id}{$session_id}{BothHTML} .=
  1360.             "<font color=\"blue\">$copy</font>";
  1361.  
  1362.         #
  1363.         #  Populate %Hex{UDP}{} with coloured HTML 2-way
  1364.         #  traffic, if needed.
  1365.         #
  1366.         if ($Arg{output_hex}) {
  1367.             &Process_Hex("UDP",$session_id,$udp_data,"blue");
  1368.         }
  1369.  
  1370.     } else {
  1371.         #
  1372.         #  Populate %UDP{id}{}{RawB} with client to server
  1373.         #  1-way raw traffic
  1374.         #
  1375.         $UDP{id}{$session_id}{RawB} .= $udp_data;  
  1376.  
  1377.         #
  1378.         #  Populate %UDP{id}{}{BothHTML} with coloured HTML
  1379.         #  2-way traffic, red for client to server
  1380.         #
  1381.         $copy = &Desex_HTML($udp_data);
  1382.         $UDP{id}{$session_id}{BothHTML} .=
  1383.             "<font color=\"red\">$copy</font>";
  1384.         #
  1385.         #  Populate %Hex{UDP}{} with coloured HTML 2-way
  1386.         #  traffic, if needed.
  1387.         #
  1388.         if ($Arg{output_hex}) {
  1389.             &Process_Hex("UDP",$session_id,$udp_data,"red");
  1390.         }
  1391.  
  1392.     }
  1393.     #
  1394.     #  Populate %UDP{id}{}{time}{} with raw 1-way traffic by time
  1395.     #
  1396.     $UDP{id}{$session_id}{time}{$time} .= $udp_data;
  1397.  
  1398.     ### Store the packet timestamp for the first seen packet
  1399.     if (! defined $UDP{id}{$session_id}{StartTime}) {
  1400.         $UDP{id}{$session_id}{StartTime} = $time;
  1401.  
  1402.         ### Store other info once
  1403.         if ($from_server) {
  1404.             $UDP{id}{$session_id}{src} = $ip_dest;
  1405.             $UDP{id}{$session_id}{dest} = $ip_src;
  1406.             $UDP{id}{$session_id}{src_port} = $udp_dest_port;
  1407.             $UDP{id}{$session_id}{dest_port} = $udp_src_port;
  1408.         } else {
  1409.             $UDP{id}{$session_id}{src} = $ip_src;
  1410.             $UDP{id}{$session_id}{dest} = $ip_dest;
  1411.             $UDP{id}{$session_id}{src_port} = $udp_src_port;
  1412.             $UDP{id}{$session_id}{dest_port} = $udp_dest_port;
  1413.         }
  1414.     }
  1415.  
  1416.     ### Store the packet timestamp in case this is the last packet
  1417.     $UDP{id}{$session_id}{EndTime} = $time;
  1418.  
  1419.     ### Print status line
  1420.     printf "%6s  %-45s  %s\n",$packet,$session_id,$length
  1421.      if $Arg{debug};
  1422.    
  1423. }
  1424.  
  1425.  
  1426.  
  1427. # Process_ICMP_Packet - process a ICMP packet and store it in memory. It takes
  1428. #   the raw ip data and populates the data structure %ICMP.
  1429. #   time is the session_id.
  1430. #
  1431. sub Process_ICMP_Packet {
  1432.  
  1433.     my $ip_data = shift;
  1434.     my $ip_src = shift;
  1435.     my $ip_dest = shift;
  1436.     my $time = shift;
  1437.     my $drops = shift;
  1438.     my $ver = shift;
  1439.  
  1440.     #-------------------------------------------------------------------
  1441.     #
  1442.     #  ICMP
  1443.     #
  1444.  
  1445.     ### Unpack ICMP data
  1446.     ($icmp_type,$icmp_code,$icmp_cksum,$icmp_rest) =
  1447.      unpack('CCna*',$ip_data);
  1448.  
  1449.     #
  1450.     # --- Store ICMP data in memory ---
  1451.     #
  1452.  
  1453.     ### Store Fields
  1454.     $ICMP{time}{$time}{type} = $icmp_type;
  1455.     $ICMP{time}{$time}{code} = $icmp_code;
  1456.     $ICMP{time}{$time}{src} = $ip_src;
  1457.     $ICMP{time}{$time}{dest} = $ip_dest;
  1458.     $ICMP{time}{$time}{ver} = $ver;
  1459.  
  1460.     #
  1461.     #  Flag this session as a Partial if either tcpdump or snoop
  1462.     #  confesses to dropping packets.
  1463.     #
  1464.     $ICMP{time}{$time}{Partial}++ if $drops;
  1465.  
  1466.     #
  1467.     #  Save data if ICMP echo/reply
  1468.     #
  1469.     if (($icmp_type == 0) || ($icmp_type == 8) ||
  1470.      ($icmp_type == 128) || ($icmp_type == 129) || 1) {
  1471.         ### Unpack some more
  1472.         ($icmp_type,$icmp_code,$icmp_cksum,$icmp_id,$icmp_seq,
  1473.          $icmp_data) = unpack('CCnnna*',$ip_data);
  1474.         ### Save extra fields
  1475.         $ICMP{time}{$time}{id} = $icmp_id;
  1476.         $ICMP{time}{$time}{seq} = $icmp_seq;
  1477.         $ICMP{time}{$time}{data} = $icmp_data;
  1478.     }
  1479.  
  1480.     ### Store size
  1481.     $ICMP{time}{$time}{size} += length($icmp_data);
  1482.  
  1483.     if ($icmp_data ne "") {
  1484.         #
  1485.         #  Populate %ICMP{time}{}{BothHTML} with coloured HTML
  1486.         #  1-way traffic, blue
  1487.         #
  1488.         $copy = &Desex_HTML($icmp_data);
  1489.         $ICMP{time}{$time}{BothHTML} .=
  1490.             "<font color=\"blue\">$copy</font>";
  1491.     }
  1492.  
  1493.     #
  1494.     #  Populate %Hex{ICMP}{} with coloured HTML
  1495.     #  traffic, if needed.
  1496.     #
  1497.     if ($Arg{output_hex}) {
  1498.         &Process_Hex("ICMP",$time,$icmp_data,"blue");
  1499.     }
  1500.  
  1501.     ### Print status line
  1502.     printf "%6s  %-45s  %s\n",$packet,"$ip_src,$ip_dest",$length
  1503.      if $Arg{debug};
  1504. }
  1505.  
  1506.  
  1507.  
  1508. # Process_TCP_Sessions - this subroutine processes %TCP, saving the
  1509. #   sessions to various "session*" files on disk. It populates %Index
  1510. #   with information on files that it has created. It also checks
  1511. #   the application port numbers and triggers further processing -
  1512. #   eg telnet replay files. Min/Max size checks are also done here.
  1513. #
  1514. sub Process_TCP_Sessions {
  1515.  
  1516.    my ($filename,$id_text,$id_html,$rawboth,$time,$raw);
  1517.    my @Time;
  1518.  
  1519.    $Bench{++$BM}{mark} = new Benchmark if $Arg{bench};
  1520.    $Bench{$BM}{text} = "Process TCP Sessions - start";
  1521.  
  1522.    #
  1523.    #  Loop through all TCP sessions
  1524.    #
  1525.    foreach $session_id (keys %{$TCP{id}}) {
  1526.     $number = $Index{Sort_Lookup}{"TCP:$session_id"};
  1527.  
  1528.     #
  1529.     #  Determine the service - usually by the lowest numbered port, eg,
  1530.     #  ports 51321 and 23 would give 23 (telnet).
  1531.     #
  1532.     $ip_src = $TCP{id}{$session_id}{src};
  1533.     $ip_dest = $TCP{id}{$session_id}{dest};
  1534.     $tcp_src_port = $TCP{id}{$session_id}{src_port};
  1535.     $tcp_dest_port = $TCP{id}{$session_id}{dest_port};
  1536.     ($service,$client) = &Pick_Service_Port("TCP",$session_id,
  1537.      $tcp_src_port,$tcp_dest_port);
  1538.  
  1539.     ### Fetch text name for this port
  1540.     $service_name = $Services_TCP{$service} || $service || "0";
  1541.  
  1542.     #
  1543.     #  Don't actually save any files if CLI args say not to
  1544.     #
  1545.     if ($Arg{port_reject} && $Arg{Port_Rejected}{$service}) { next; }
  1546.     if ($Arg{port_accept} && !$Arg{Port_Accepted}{$service}) { next; }
  1547.     if ($Arg{ip_reject}) {
  1548.         if ($Arg{IP_Rejected}{$ip_src} || $Arg{IP_Rejected}{$ip_dest}) {
  1549.             next;
  1550.         }
  1551.     }
  1552.     if ($Arg{ip_accept}) {
  1553.         unless ($Arg{IP_Accepted}{$ip_src} ||
  1554.          $Arg{IP_Accepted}{$ip_dest}) {
  1555.             next;
  1556.         }
  1557.     }
  1558.  
  1559.     #
  1560.     # --- Fetch RawBoth ---
  1561.     #
  1562.     # rawboth will contain the raw data in time order.
  1563.     $rawboth = "";
  1564.     foreach $time (sort {$a <=> $b}
  1565.      (keys (%{$TCP{id}{$session_id}{time}}))) {
  1566.         $rawboth .= $TCP{id}{$session_id}{time}{$time}{data};
  1567.     }
  1568.     $length = length($rawboth);
  1569.  
  1570.     #
  1571.     # --- Check for Min and Max size ---
  1572.     #
  1573.     next if $length < $Arg{minbytes};
  1574.     next if (($Arg{maxbytes} != 0) && ($length > $Arg{maxbytes}));
  1575.  
  1576.     ### Print status line
  1577.     $numtext = sprintf("%04d",$number);
  1578.     printf "%6s  %-45s  %s\n",$numtext,$session_id,$service_name
  1579.      unless $Arg{quiet};
  1580.  
  1581.     #
  1582.     # --- Save Info File to Disk ---
  1583.     #
  1584.     if ($Arg{output_info}) {
  1585.         $filename = "session_${numtext}.info";
  1586.         $firsttime = localtime($TCP{id}{$session_id}{StartTime});
  1587.         $lasttime = localtime($TCP{id}{$session_id}{EndTime});
  1588.         $duration = ($TCP{id}{$session_id}{EndTime} -
  1589.          $TCP{id}{$session_id}{StartTime});
  1590.         $duration = sprintf("%.0f",$duration);
  1591.         if ($TCP{id}{$session_id}{Partial}) { $partial = "yes"; }
  1592.          else { $partial = "no"; }
  1593.  
  1594.         ### Build output text
  1595.         $outtext = "$numtext===$session_id===$service===" .
  1596.          "$service_name===$length\n\n" .
  1597.          "Source addr : $ip_src\n" .
  1598.          "Source port : $tcp_src_port\n" .
  1599.          "Dest addr   : $ip_dest\n" .
  1600.          "Dest port   : $tcp_dest_port\n" .
  1601.          "Dest service: $service_name\n" .
  1602.          "Length bytes: $length\n" .
  1603.          "First time  : $firsttime\n" .
  1604.          "Last time   : $lasttime\n" .
  1605.          "Duration    : $duration seconds\n" .
  1606.          "Partial     : $partial\n";
  1607.  
  1608.         ### Write info file
  1609.         open (OUT,">$filename") ||
  1610.          die "ERROR11: creating $filename $!\n";
  1611.         print OUT $outtext;
  1612.         close OUT;
  1613.     }
  1614.  
  1615.  
  1616.     #
  1617.     # --- Save Index data to Memory ---
  1618.     #
  1619.  
  1620.     ## Fetch times
  1621.     $starttime = scalar localtime($TCP{id}{$session_id}{StartTime});
  1622.     $duration = ($TCP{id}{$session_id}{EndTime} -
  1623.      $TCP{id}{$session_id}{StartTime});
  1624.     $duration = sprintf("%.0f",$duration);
  1625.  
  1626.     ### Generate session strings
  1627.     ($id_text,$id_html) = &Generate_TCP_IDs($session_id);
  1628.  
  1629.     ### Construct HTML table row containing session data
  1630.     $Index{HTML}[$number] = "<tr><td><i>$number.</i></td>" .
  1631.      "<td><b>$starttime</b></td><td>$duration s</td><td> " .
  1632.      "<font color=\"blue\">$id_html " .
  1633.      "</font></td><td> <font color=\"red\">" .
  1634.      "$service_name</font></td><td> <font color=\"green\"> " .
  1635.      "$length bytes</font></td><td>\n";
  1636.  
  1637.     ### Construct text line containing session data
  1638.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s bytes\n",$number,
  1639.      $id_text,"($service_name)",$length);
  1640.  
  1641.     ### Construct image info line (in case it is needed)
  1642.     $Image{HTML}[$number]{info} = "<tr><td><i>$number.</i>" .
  1643.      "</td><td><b>$starttime</b></td><td> " .
  1644.      "<font color=\"blue\">$id_html </font></td><td><td>\n";
  1645.  
  1646.     ### Construct GETPOST info line (in case it is needed)
  1647.     # starttime and host:port... are formatted differently so that
  1648.     # they are narrow and leave more room for the sub table.
  1649.     $GETPOST{HTML}[$number]{info} = "<tr><td><i>$number.</i>" .
  1650.      "</td><td><b>$starttime</b></td><td> " .
  1651.      "<font color=\"blue\">$id_html </font></td><td><td>\n";
  1652.  
  1653.  
  1654.     #
  1655.     # --- Save Raw Sessions to Disk ---
  1656.     #
  1657.  
  1658.     if ($Arg{output_raw}) {
  1659.  
  1660.         #
  1661.         #  Save ".raw" file, all raw 2-way data time-sorted.
  1662.         #
  1663.         $filename = "session_${numtext}.${service_name}.raw";
  1664.         open (OUT,">$filename") ||
  1665.          die "ERROR12: creating $filename $!\n";
  1666.         binmode(OUT);       # for backward OSs
  1667.         print OUT $rawboth;
  1668.         close OUT;
  1669.  
  1670.         ### Update HTML index table with link
  1671.         $Index{HTML}[$number] .= "<li><a href=\"$filename\">raw</a> ";
  1672.  
  1673.         #
  1674.         #  Save ".raw1" file, server->client 1-way data assembled.
  1675.         #
  1676.         $filename = "session_${numtext}.${service_name}.raw1";
  1677.         open (OUT,">$filename") ||
  1678.          die "ERROR13: creating $filename $!\n";
  1679.         binmode(OUT);       # for backward OSs
  1680.         print OUT &TCP_Follow_RawA($session_id);
  1681.         close OUT;
  1682.  
  1683.         ### Update HTML index table with link
  1684.         $Index{HTML}[$number] .= "<a href=\"$filename\">raw1</a> ";
  1685.  
  1686.         #
  1687.         #  Save ".raw2" file, client->server 1-way data assembled.
  1688.         #
  1689.         $filename = "session_${numtext}.${service_name}.raw2";
  1690.         open (OUT,">$filename") ||
  1691.          die "ERROR14: creating $filename $!\n";
  1692.         binmode(OUT);       # for backward OSs
  1693.         print OUT &TCP_Follow_RawB($session_id);
  1694.         close OUT;
  1695.  
  1696.         ### Update HTML index table with link
  1697.         $Index{HTML}[$number] .= "<a href=\"$filename\">raw2</a></li> ";
  1698.     }
  1699.  
  1700.     next unless $Arg{output_apps};
  1701.  
  1702.     #
  1703.     # --- Save Session as HTML ---
  1704.     #
  1705.     if ($Arg{Save_As_TCP_HTML}{$service} || $Arg{output_allhtml}) {
  1706.         &Save_Both_HTML("TCP",$session_id,$number,$service_name,
  1707.          $id_html);
  1708.     }
  1709.  
  1710.     #
  1711.     # --- Save X11 Session as HTML ---
  1712.     #
  1713.     if ($Arg{Save_As_X11_HTML}{$service}) {
  1714.         #
  1715.         #  HTML Postprocessing can go here
  1716.         #
  1717.         &Generate_X11_HTML($session_id);
  1718.         &Process_BothHTML("TCP",$session_id,1);
  1719.  
  1720.         &Save_Both_HTML("TCP",$session_id,$number,"text$service_name",
  1721.          $id_html);
  1722.     }
  1723.  
  1724.  
  1725.     #
  1726.     # --- Save Hex Dump as HTML ---
  1727.     #
  1728.     if ($Arg{output_hex}) {
  1729.         &Process_Hex_Finish("TCP",$session_id);
  1730.         &Save_Hex_HTML("TCP",$session_id,$number,$service_name,
  1731.          $id_html);
  1732.         &Save_Hex_Text("TCP",$session_id,$number,$service_name,
  1733.          $id_text);
  1734.     }
  1735.  
  1736.     #
  1737.     # --- Process Application Data ---
  1738.     #
  1739.  
  1740.     if ($service == 20) {
  1741.         &Save_FTP_File($session_id,$number);
  1742.     }
  1743.     if ($service == 22) {
  1744.         &Save_Session_textSSH_files($session_id,$number,
  1745.          "SSH",$id_html);
  1746.     }
  1747.     if ($Arg{keydata} && $Arg{Save_As_TCP_Playback}{$service}) {
  1748.         # The following is for special analysis,
  1749.         &Save_Session_Keydata($session_id,$number,
  1750.          $service_name,$id_html);
  1751.     }
  1752.     if ($service == 25) {
  1753.         &Save_SMTP_Emails($session_id,$number);
  1754.     }
  1755.     if ($service == 80 or $service == 8080 or
  1756.      $service == 3127 or $service == 1080)  {
  1757.         &Save_HTTP_Files($session_id,$number,$service_name);
  1758.         &Process_HTTP($session_id);
  1759.     }
  1760.  
  1761.     if ($Arg{Save_As_X11_Playback}{$service}) {
  1762.         &Save_Session_XReplay($session_id,$number,$service_name);
  1763.     }
  1764.  
  1765.     if ($Arg{Save_As_VNC_Playback}{$service}) {
  1766.         &Save_Session_VNCReplay_andHTML($session_id,$number,
  1767.          $service_name,$id_html);
  1768.     }
  1769.    
  1770.     $raw = &TCP_Follow_RawB($session_id);
  1771.     if ($raw =~ /^\200\0\0p0\211/) {
  1772.         &Save_NFS_File($session_id,$number);
  1773.     }
  1774.  
  1775.     if ($Arg{Save_As_TCP_Playback}{$service}) {
  1776.         &Save_Session_Replay($session_id,$number,$service_name);
  1777.     }
  1778.    }
  1779.  
  1780.    $Bench{++$BM}{mark} = new Benchmark if $Arg{bench};
  1781.    $Bench{$BM}{text} = "Process TCP Sessions - end";
  1782. }
  1783.  
  1784.  
  1785. # Process_UDP_Streams - this subroutine processes %UDP, saving the
  1786. #   sessions to various "session*" files on disk. It populates %Index
  1787. #   with information on the files that were created. It also checks
  1788. #   the application port numbers and triggers further processing -
  1789. #   eg DNS html output files.
  1790. #
  1791. sub Process_UDP_Streams {
  1792.  
  1793.    my ($filename,$id_html,$id_text,$time,$rawboth);
  1794.  
  1795.    $Bench{++$BM}{mark} = new Benchmark if $Arg{bench};
  1796.    $Bench{$BM}{text} = "Process UDP Sessions - start";
  1797.  
  1798.    #
  1799.    #  Loop through all UDP Streams
  1800.    #
  1801.    foreach $session_id (keys %{$UDP{id}}) {
  1802.     $number = $Index{Sort_Lookup}{"UDP:$session_id"};
  1803.  
  1804.         #
  1805.         #  Determine the service - usually by the lowest numbered port, eg,
  1806.         #  ports 51327 and 53 would give 53 (dns). (big assumption!)
  1807.         #
  1808.     $ip_src = $UDP{id}{$session_id}{src};
  1809.     $ip_dest = $UDP{id}{$session_id}{dest};
  1810.     $udp_src_port = $UDP{id}{$session_id}{src_port};
  1811.     $udp_dest_port = $UDP{id}{$session_id}{dest_port};
  1812.     ($service,$client) = &Pick_Service_Port("UDP",$session_id,
  1813.      $udp_src_port,$udp_dest_port);
  1814.  
  1815.     ### Fetch text name for this port
  1816.     $service_name = $Services_UDP{$service} || $service || "0";
  1817.  
  1818.         #
  1819.         #  Don't actually save any files if CLI args say not to
  1820.         #
  1821.     if ($Arg{port_reject} && $Arg{Port_Rejected}{$service}) { next; }
  1822.     if ($Arg{port_accept} && !$Arg{Port_Accepted}{$service}) { next; }
  1823.     if ($Arg{ip_reject}) {
  1824.         if ($Arg{IP_Rejected}{$ip_src} || $Arg{IP_Rejected}{$ip_dest}) {
  1825.             next;
  1826.         }
  1827.     }
  1828.     if ($Arg{ip_accept}) {
  1829.         unless ($Arg{IP_Accepted}{$ip_src} ||
  1830.          $Arg{IP_Accepted}{$ip_dest}) {
  1831.             next;
  1832.         }
  1833.     }
  1834.  
  1835.     #
  1836.     # --- Fetch RawBoth ---
  1837.     #
  1838.     # rawboth will contain the raw data in time order.
  1839.     $rawboth = "";
  1840.     foreach $time (sort {$a <=> $b}
  1841.      (keys (%{$UDP{id}{$session_id}{time}}))) {
  1842.         $rawboth .= $UDP{id}{$session_id}{time}{$time};
  1843.     }
  1844.     $length = length($rawboth);
  1845.  
  1846.     #
  1847.     # --- Check for Min and Max Size ---
  1848.     #
  1849.     next if $length < $Arg{minbytes};
  1850.     next if (($Arg{maxbytes} != 0) && ($length > $Arg{maxbytes}));
  1851.  
  1852.     ### Print status line
  1853.     $numtext = sprintf("%04d",$number);
  1854.     printf "%6s  %-45s  %s\n",$numtext,$session_id,$service_name
  1855.      unless $Arg{quiet};
  1856.  
  1857.     #
  1858.     # --- Save Info File to Disk ---
  1859.     #
  1860.     if ($Arg{output_info}) {
  1861.         $filename = "stream_${numtext}.info";
  1862.                 $firsttime = localtime($UDP{id}{$session_id}{StartTime});
  1863.                 $lasttime = localtime($UDP{id}{$session_id}{EndTime});
  1864.                 $duration = ($UDP{id}{$session_id}{EndTime} -
  1865.                  $UDP{id}{$session_id}{StartTime});
  1866.         $duration = sprintf("%.0f",$duration);
  1867.         if ($UDP{id}{$session_id}{Partial}) { $partial = "yes"; }
  1868.          else { $partial = "no"; }
  1869.  
  1870.                 ### Build output text
  1871.                 $outtext = "$numtext===$session_id===$service===" .
  1872.                  "$service_name===$length\n\n" .
  1873.                  "Source addr : $ip_src\n" .
  1874.                  "Source port : $udp_src_port\n" .
  1875.                  "Dest addr   : $ip_dest\n" .
  1876.                  "Dest port   : $udp_dest_port\n" .
  1877.                  "Dest service: $service_name\n" .
  1878.                  "Length bytes: $length\n" .
  1879.                  "First time  : $firsttime\n" .
  1880.                  "Last time   : $lasttime\n" .
  1881.                  "Duration    : $duration seconds\n" .
  1882.                  "Partial     : $partial\n";
  1883.  
  1884.                 ### Write info file
  1885.                 open (OUT,">$filename") ||
  1886.                  die "ERROR15: creating $filename $!\n";
  1887.                 print OUT $outtext;
  1888.                 close OUT;
  1889.     }
  1890.  
  1891.  
  1892.     #
  1893.     # --- Save Index data in Memory ---
  1894.     #
  1895.  
  1896.     ### Fetch Times
  1897.     $starttime = scalar localtime($UDP{id}{$session_id}{StartTime});
  1898.     $duration = ($UDP{id}{$session_id}{EndTime} -
  1899.      $UDP{id}{$session_id}{StartTime});
  1900.     $duration = sprintf("%.0f",$duration);
  1901.  
  1902.     ### Construct HTML table row containing stream data
  1903.     $id_html = "$ip_src:$udp_src_port &lt;-&gt; $ip_dest:$udp_dest_port";
  1904.     $Index{HTML}[$number] = "<tr><td><i>$number.</i></td>" .
  1905.      "<td><b>$starttime</b></td><td>$duration s</td><td> " .
  1906.      "<font color=\"blue\">$id_html " .
  1907.      "</font></td><td> <font color=\"red\">" .
  1908.      "<i>$service_name</i></font></td><td> <font color=\"green\"> " .
  1909.      "$length bytes</font></td><td>\n";
  1910.  
  1911.     ### Construct text line containing session data
  1912.     $id_text = "$ip_src:$udp_src_port <-> $ip_dest:$udp_dest_port";
  1913.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s bytes\n",$number,
  1914.      $id_text,"($service_name)",$length);
  1915.  
  1916.  
  1917.     #
  1918.     # --- Save Raw Stream to Disk ---
  1919.     #
  1920.  
  1921.     if ($Arg{output_raw}) {
  1922.  
  1923.         #
  1924.         #  Save ".raw" file, all raw 2-way data time-sorted.
  1925.         #
  1926.         $filename = "stream_${numtext}.${service_name}.raw";
  1927.         open (OUT,">$filename") ||
  1928.          die "ERROR16: creating $filename $!\n";
  1929.         binmode(OUT);       # for backward OSs
  1930.         print OUT $rawboth;
  1931.         close OUT;
  1932.  
  1933.         ### Update HTML index table with link
  1934.         $Index{HTML}[$number] .= "<li><a href=\"$filename\">raw</a> ";
  1935.  
  1936.         #
  1937.         #  Save ".raw1" file, server->client 1-way data time-sorted.
  1938.         #
  1939.         $filename = "stream_${numtext}.${service_name}.raw1";
  1940.         open (OUT,">$filename") ||
  1941.          die "ERROR17: creating $filename $!\n";
  1942.         binmode(OUT);       # for backward OSs
  1943.         print OUT $UDP{id}{$session_id}{RawA};
  1944.         close OUT;
  1945.  
  1946.         ### Update HTML index table with link
  1947.         $Index{HTML}[$number] .= "<a href=\"$filename\">raw1</a> ";
  1948.  
  1949.         #
  1950.         #  Save ".raw2" file, client->server 1-way data time-sorted.
  1951.         #
  1952.         $filename = "stream_${numtext}.${service_name}.raw2";
  1953.         open (OUT,">$filename") ||
  1954.          die "ERROR18: creating $filename $!\n";
  1955.         binmode(OUT);       # for backward OSs
  1956.         print OUT $UDP{id}{$session_id}{RawB};
  1957.         close OUT;
  1958.  
  1959.         ### Update HTML index table with link
  1960.         $Index{HTML}[$number] .= "<a href=\"$filename\">raw2</a></li> ";
  1961.     }
  1962.  
  1963.     next unless $Arg{output_apps};
  1964.  
  1965.     #
  1966.     # --- Save Stream as HTML ---
  1967.     #
  1968.  
  1969.     if ($Arg{Save_As_UDP_HTML}{$service} || $Arg{output_allhtml}) {
  1970.         #
  1971.         #  HTML Postprocessing can go here
  1972.         #
  1973.         &Process_BothHTML("UDP",$session_id);
  1974.  
  1975.         &Save_Both_HTML("UDP",$session_id,$number,$service_name);
  1976.     }
  1977.  
  1978.     #
  1979.     # --- Save Hex Dump as HTML ---
  1980.     #
  1981.     if ($Arg{output_hex}) {
  1982.         &Process_Hex_Finish("UDP",$session_id);
  1983.         &Save_Hex_HTML("UDP",$session_id,$number,$service_name,
  1984.          $id_html);
  1985.         &Save_Hex_Text("UDP",$session_id,$number,$service_name,
  1986.          $id_text);
  1987.     }
  1988.  
  1989.  
  1990.     #
  1991.     # --- Process Application Data ---
  1992.     #
  1993.     if ($Arg{Save_As_UDP_Playback}{$service}) {
  1994.         &Save_Stream_Replay($session_id,$number,$service_name);
  1995.     }
  1996.  
  1997.    }
  1998.  
  1999.    $Bench{++$BM}{mark} = new Benchmark if $Arg{bench};
  2000.    $Bench{$BM}{text} = "Process UDP Sessions - end";
  2001. }
  2002.  
  2003.  
  2004.  
  2005. # Process_ICMP - this subroutine processes %ICMP.
  2006. #
  2007. sub Process_ICMP {
  2008.  
  2009.    my ($filename,$id_text,$id_html);
  2010.  
  2011.    $Bench{++$BM}{mark} = new Benchmark if $Arg{bench};
  2012.    $Bench{$BM}{text} = "Process ICMP Sessions - start";
  2013.  
  2014.    #
  2015.    #  Loop through all ICMP Streams
  2016.    #
  2017.    foreach $time (keys %{$ICMP{time}}) {
  2018.     $number = $Index{Sort_Lookup}{"ICMP:$time"};
  2019.  
  2020.    
  2021.     ### Fetch Data
  2022.     $icmp_type = $ICMP{time}{$time}{type};
  2023.     $icmp_code = $ICMP{time}{$time}{code};
  2024.     $icmp_ver = $ICMP{time}{$time}{ver};
  2025.     $ip_src = $ICMP{time}{$time}{src};
  2026.     $ip_dest = $ICMP{time}{$time}{dest};
  2027.     $session_id = "$ip_src,$ip_dest";
  2028.  
  2029.     ### Fetch text name for this port
  2030.     $type_name = $ICMP_Types{$icmp_type} || $icmp_type || "0";
  2031.     $service_name = $icmp_type;
  2032.  
  2033.         #
  2034.         #  Don't actually save any files if CLI args say not to
  2035.         #
  2036.     if ($Arg{ip_reject}) {
  2037.         if ($Arg{IP_Rejected}{$ip_src} || $Arg{IP_Rejected}{$ip_dest}){
  2038.             next;
  2039.         }
  2040.     }
  2041.     if ($Arg{ip_accept}) {
  2042.         unless ($Arg{IP_Accepted}{$ip_src} ||
  2043.          $Arg{IP_Accepted}{$ip_dest}) {
  2044.             next;
  2045.         }
  2046.     }
  2047.  
  2048.     #
  2049.     # --- Check for Min and Max Size ---
  2050.     #
  2051.     $length = length($ICMP{time}{$time}{data});
  2052.     next if $length < $Arg{minbytes};
  2053.     next if (($Arg{maxbytes} != 0) && ($length > $Arg{maxbytes}));
  2054.  
  2055.     ### Print status line
  2056.     $numtext = sprintf("%04d",$number);
  2057.     printf "%6s  %-45s  ICMP %s\n",$numtext,$session_id,$type_name
  2058.      unless $Arg{quiet};
  2059.  
  2060.     #
  2061.     # --- Save Info File to Disk ---
  2062.     #
  2063.     if (($Arg{output_info}) && ($length > 0)) {
  2064.         $filename = "icmp_${numtext}.${service_name}.info";
  2065.         if ($ICMP{time}{$time}{Partial}) { $partial = "yes"; }
  2066.          else { $partial = "no"; }
  2067.         $starttime = scalar localtime($time);
  2068.  
  2069.                 ### Build output text
  2070.                 $outtext = "$numtext===$session_id===$icmp_type===" .
  2071.                  "$type_name===$length\n\n" .
  2072.                  "Source addr : $ip_src\n" .
  2073.                  "Dest addr   : $ip_dest\n" .
  2074.                  "ICMP version: $icmp_ver\n" .
  2075.                  "ICMP type   : $icmp_type\n" .
  2076.                  "ICMP code   : $icmp_code\n" .
  2077.                  "ICMP name   : $type_name\n" .
  2078.                  "Length bytes: $length\n" .
  2079.                  "Time        : $starttime\n" .
  2080.                  "Partial     : $partial\n";
  2081.  
  2082.                 ### Write info file
  2083.                 open (OUT,">$filename") ||
  2084.                  die "ERROR19: creating $filename $!\n";
  2085.                 print OUT $outtext;
  2086.                 close OUT;
  2087.     }
  2088.  
  2089.  
  2090.     #
  2091.     # --- Save Index data in Memory ---
  2092.     #
  2093.  
  2094.     ### Fetch Times
  2095.     $starttime = scalar localtime($time);
  2096.  
  2097.     ### Construct HTML table row containing stream data
  2098.     $id_html = "$ip_src -&gt; $ip_dest";
  2099.     $Index{HTML}[$number] = "<tr><td><i>$number.</i></td>" .
  2100.      "<td><b>$starttime</b></td><td>0 s</td><td> " .
  2101.      "<font color=\"blue\">$id_html" .
  2102.      "</font></td><td> <font color=\"red\">" .
  2103.      "<i>$icmp_ver</i></font></td><td> <font color=\"green\"> " .
  2104.      "$length bytes</font></td><td>$type_name\n";
  2105.  
  2106.     ### Construct text line containing session data
  2107.     $id_text = "$ip_src -> $ip_dest";
  2108.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s bytes\n",$number,
  2109.      $id_text, "($icmp_ver $type_name)",$length);
  2110.  
  2111.  
  2112.     #
  2113.     # --- Save Raw Stream to Disk ---
  2114.     #
  2115.  
  2116.     if (($Arg{output_raw}) && ($length > 0)) {
  2117.  
  2118.         #
  2119.         #  Save ".raw" file, all raw 2-way data time-sorted.
  2120.         #
  2121.         $filename = "icmp_${numtext}.${service_name}.raw";
  2122.         open (OUT,">$filename") ||
  2123.          die "ERROR20: creating $filename $!\n";
  2124.         binmode(OUT);       # for backward OSs
  2125.         print OUT $ICMP{time}{$time}{data};
  2126.         close OUT;
  2127.  
  2128.         ### Update HTML index table with link
  2129.         $Index{HTML}[$number] .= "<li><a href=\"$filename\">raw</a> ";
  2130.  
  2131.     }
  2132.  
  2133.     #
  2134.     # --- Save Stream as HTML ---
  2135.     #
  2136.  
  2137.     if ($Arg{output_allhtml}) {
  2138.         #
  2139.         #  HTML Postprocessing can go here
  2140.         #
  2141.         &Process_BothHTML("ICMP",$time);
  2142.  
  2143.         &Save_Both_HTML("ICMP",$time,$number,$service_name,$id_html);
  2144.     }
  2145.  
  2146.     #
  2147.     # --- Save Hex Dump as HTML ---
  2148.     #
  2149.     if ($Arg{output_hex}) {
  2150.         &Process_Hex_Finish("ICMP",$time);
  2151.         &Save_Hex_HTML("ICMP",$time,$number,$service_name,$id_html);
  2152.         &Save_Hex_Text("ICMP",$time,$number,$service_name,$id_text);
  2153.     }
  2154.    }
  2155.  
  2156.    $Bench{++$BM}{mark} = new Benchmark if $Arg{bench};
  2157.    $Bench{$BM}{text} = "Process ICMP Sessions - end";
  2158. }
  2159.  
  2160.  
  2161. # Process_HTTP - HTTP processing. Looks for GETs and POSTs, and process them
  2162. #       into %GETPOST. Constructs a HTTP log in %HTTPlog.
  2163. #
  2164. sub Process_HTTP {
  2165.     my ($junk,$var,$value,$term,$data,$request,$site,$post,$get,$reply);
  2166.     my ($start,$src,$num,$req,$recv,$type,$status,$time1,$duration,$dest);
  2167.     my @Terms; 
  2168.     my $index = 0;
  2169.     my $indexA = 0;
  2170.     my $indexB = 0;
  2171.  
  2172.     ### Input
  2173.     my $session_id = shift;
  2174.  
  2175.     $src = $TCP{id}{$session_id}{src};
  2176.     $dest = $TCP{id}{$session_id}{dest};
  2177.  
  2178.     #
  2179.     #  Process
  2180.     #
  2181.  
  2182.     ### Get packet times (may need to use seqs instead)
  2183.     @Times = sort{$a <=> $b} (keys(%{$TCP{id}{$session_id}{time}}));
  2184.  
  2185.     ### Step through each packet
  2186.         for ($i=0; $i <= $#Times; $i++) {
  2187.  
  2188.            ### Fetch data from mem
  2189.            $time = $Times[$i];
  2190.            $request = $TCP{id}{$session_id}{time}{$time}{data};
  2191.        $request =~ s/^\0\0*//;
  2192.  
  2193.        #
  2194.        # --- Do HTTPlog Processing ---
  2195.        #
  2196.  
  2197.        next unless $request =~ /^(GET|POST)\s/; # speed
  2198.  
  2199.        ### Calc duration
  2200.            $time1 = $Times[$i+1] || $time;
  2201.        $duration = $time1 - $time;
  2202.  
  2203.        # some magic
  2204.        $reply = "";
  2205.        foreach $inc (1..16) {
  2206.         $next = $TCP{id}{$session_id}{time}{$Times[$i+$inc]}{data};
  2207.         $next =~ s/^\0\0*//;
  2208.         if ($next =~ /^U*\0*HTTP/) {
  2209.             $reply = $next;
  2210.             $time1 = $Times[$i+$inc] || $time;
  2211.                 $duration = $time1 - $time;
  2212.             last;
  2213.         } else {
  2214.             $request .= $next;
  2215.         }
  2216.        }
  2217.        $i++; # speed
  2218.  
  2219.        if ($request =~ /^GET \S* HTTP/) {
  2220.  
  2221.         ### Get the site string
  2222.         ($site) = $request =~ /^GET (\S*)\s/;
  2223.         if ($site =~ m:^/:) {
  2224.             # assume this was a http, missing the "http://host"
  2225.             $site = "http://${dest}$site";
  2226.         }
  2227.  
  2228.         ### Get the status and mime type from reply
  2229.         ($status)  = $reply =~ /HTTP\/\S*\s(\S*)/s;
  2230.         ($type) = $reply =~ /Content-Type:\s(\S*)/s;
  2231.         ($size) = $reply =~ /Content-Length:\s(\S*)/s;
  2232.         $type = "-" if $type eq "";
  2233.         $size = 0 if $size eq "";
  2234.         $result = $Result_Names{$status} || "TCP_HIT";
  2235.        
  2236.         ### Store the log entry
  2237.         $HTTPlog{time}{$time} =
  2238.          sprintf("%9d.%03d %6d %s %s/%03d %d %s %s %s %s%s/%s %s\n",
  2239.          int($time),(($time - int($time))*1000),($duration*1000),
  2240.          $src,$result,$status,$size,"GET",$site,"-","NONE","",
  2241.          "-",$type);
  2242.         $HTTPlog{notempty} = 1;
  2243.  
  2244.        } elsif ($request =~ /^POST .* HTTP/) {
  2245.         ### Get the site string
  2246.         ($site) = $request =~ /^POST (\S*)\s/;
  2247.         if ($site =~ m:^/:) {
  2248.             # assume this was a http, missing the "http://host"
  2249.             $site = "http://${dest}$site";
  2250.         }
  2251.  
  2252.         ### Get the status and mime type
  2253.         ($status)  = $reply =~ /HTTP\/\S*\s(\S*)/s;
  2254.         ($type) = $reply =~ /Content-Type:\s(\S*)/s;
  2255.         ($size) = $reply =~ /Content-Length:\s(\S*)/s;
  2256.         $type = "-" if $type eq "";
  2257.         $size = length($TCP{id}{$session_id}) if $size eq "";
  2258.         $result = $Result_Names{$status} || "TCP_HIT";
  2259.        
  2260.         ### Store the log entry
  2261.         $HTTPlog{time}{$time} =
  2262.          sprintf("%9d.%03d %6d %s %s/%03d %d %s %s %s %s%s/%s %s\n",
  2263.          int($time),(($time - int($time))*1000),($duration*1000),
  2264.          $src,$result,$status,$size,"POST",$site,"-","NONE","",
  2265.          "-",$type);
  2266.         $HTTPlog{notempty} = 1;
  2267.  
  2268.        }
  2269.  
  2270.        #
  2271.        # --- Do GETPOST Processing ---
  2272.        #
  2273.        if ($request =~ /^GET \S*\?\S* HTTP/) {
  2274.        
  2275.          ### Get the GET string
  2276.          ($site,$get) = $request =~ /^GET (\S*)\?(\S*)\s/;
  2277.  
  2278.          # check it looks like a GET,
  2279.          if ($get =~ /=/) {
  2280.  
  2281.         #
  2282.         #  Populate %GETPOST with a table containing the GET data
  2283.         #
  2284.         if (! defined $GETPOST{HTML}[$number]{query}) {
  2285.             $GETPOST{HTML}[$number]{info} .=
  2286.              "<font color=\"red\">GET</font></td><td width=70%>";
  2287.             $GETPOST{notempty} = 1;
  2288.         } else {
  2289.             $GETPOST{HTML}[$number]{query} .= "<hr>\n";
  2290.         }
  2291.            
  2292.         #
  2293.         #  Generate table of query key value pairs
  2294.         #
  2295.         $GETPOST{HTML}[$number]{query} .= "$site<br><table border=1>\n";
  2296.         @Terms = split(/&/,$get);
  2297.         foreach $term (@Terms) {
  2298.             ($var,$value) = split(/=/,$term);
  2299.             $value =~ tr/+/ /;
  2300.             $value =~ s/%([a-f0-9][a-f0-9])/pack("C",hex($1))/egi;
  2301.             $value =~ s/</&lt;/g;
  2302.             $value =~ s/>/&gt;/g;
  2303.             $value =~ s/\n/<br>\n/g;
  2304.             $GETPOST{HTML}[$number]{query} .=
  2305.              "<tr><td><b>$var</b></td>" .
  2306.              "<td><font face=\"Courier\">$value</font></td></tr>\n";
  2307.         }
  2308.         $GETPOST{HTML}[$number]{query} .= "</table>\n";
  2309.          }
  2310.  
  2311.        } elsif ($request =~ /^POST .* HTTP/) {
  2312.  
  2313.          ### Get the POST strings
  2314.          ($junk,$post,$junk1) = split(/\n\n|\r\n\r\n/,$request);
  2315.  
  2316.          # check it looks like a POST
  2317.          if ($post =~ /=/) {
  2318.  
  2319.         #
  2320.         #  Populate %GETPOST with a table containing the POST data
  2321.         #
  2322.         if (! defined $GETPOST{HTML}[$number]{query}) {
  2323.             $GETPOST{HTML}[$number]{info} .=
  2324.              "<font color=\"red\">POST</font></td><td width=70%>";
  2325.             $GETPOST{notempty} = 1;
  2326.         } else {
  2327.             $GETPOST{HTML}[$number]{query} .= "<hr>\n";
  2328.         }
  2329.            
  2330.         ($site) = $request =~ /^POST (\S*)\s/;
  2331.    
  2332.         $post =~ s/HTTP .*//s;
  2333.  
  2334.         #
  2335.         #  Generate table of query key value pairs
  2336.         #
  2337.         $GETPOST{HTML}[$number]{query} .= "$site<br><table border=1>\n";
  2338.         @Terms = split(/&/,$post);
  2339.         foreach $term (@Terms) {
  2340.             ($var,$value) = split(/=/,$term);
  2341.             $value =~ tr/+/ /;
  2342.             $value =~
  2343.              s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
  2344.             $value =~ s/</&lt;/g;
  2345.             $value =~ s/>/&gt;/g;
  2346.             $value =~ s/\n/<br>/g;
  2347.             $GETPOST{HTML}[$number]{query} .=
  2348.              "<tr><td><b>$var</b></td>" .
  2349.              "<td><font face=\"Courier\">$value</font></td></tr>\n";
  2350.         }
  2351.         $GETPOST{HTML}[$number]{query} .= "</table>\n";
  2352.          }
  2353.        }
  2354.     }
  2355. }
  2356.  
  2357.  
  2358. # Sort_Index - this creates a sort order for the master index.html, based
  2359. #   on the sort argument (defaults to sort by time).
  2360. #
  2361. sub Sort_Index {
  2362.  
  2363.     if ($Arg{sort} eq "size") {
  2364.         &Sort_Index_By_Size();
  2365.     } elsif ($Arg{sort} eq "type") {
  2366.         &Sort_Index_By_Type();
  2367.     } elsif ($Arg{sort} eq "ip") {
  2368.         &Sort_Index_By_IP();
  2369.     } else {
  2370.         &Sort_Index_By_Time();
  2371.     }
  2372. }
  2373.  
  2374.  
  2375. # Sort_Index_By_Time - this calculates an appropriate order for the index
  2376. #   files based on session start time.
  2377. #
  2378. sub Sort_Index_By_Time {
  2379.     my ($session_id,$time,$number);
  2380.  
  2381.     #
  2382.     #  Determine Session and Stream time order
  2383.     #
  2384.     foreach $session_id (keys %{$TCP{id}}) {
  2385.         $Index{Time_Order}{"TCP:$session_id"} =
  2386.          $TCP{id}{$session_id}{StartTime};
  2387.     }
  2388.     foreach $session_id (keys %{$UDP{id}}) {
  2389.         $Index{Time_Order}{"UDP:$session_id"} =
  2390.          $UDP{id}{$session_id}{StartTime};
  2391.     }
  2392.     foreach $time (keys %{$ICMP{time}}) {
  2393.         $Index{Time_Order}{"ICMP:$time"} = $time;
  2394.     }
  2395.     $number = 0;
  2396.     foreach $session (sort {$Index{Time_Order}{$a} <=>
  2397.      $Index{Time_Order}{$b}} keys %{$Index{Time_Order}}) {
  2398.         $number++;
  2399.         $Index{Sort_Lookup}{$session} = $number;
  2400.     }
  2401. }
  2402.  
  2403.  
  2404. # Sort_Index_By_Size - this calculates an appropriate order for the index
  2405. #   files based on session size.
  2406. #
  2407. sub Sort_Index_By_Size {
  2408.     my ($session_id,$time,$number);
  2409.  
  2410.     #
  2411.     #  Determine Session and Stream size order
  2412.     #
  2413.     foreach $session_id (keys %{$TCP{id}}) {
  2414.         $Index{Size_Order}{"TCP:$session_id"} =
  2415.          $TCP{id}{$session_id}{size};
  2416.     }
  2417.     foreach $session_id (keys %{$UDP{id}}) {
  2418.         $Index{Size_Order}{"UDP:$session_id"} =
  2419.          $UDP{id}{$session_id}{size};
  2420.     }
  2421.     foreach $time (keys %{$ICMP{time}}) {
  2422.         $Index{Size_Order}{"ICMP:$time"} =
  2423.          $ICMP{time}{$time}{size};
  2424.     }
  2425.     $number = 0;
  2426.     foreach $session (sort {$Index{Size_Order}{$b} <=>
  2427.      $Index{Size_Order}{$a}} keys %{$Index{Size_Order}}) {
  2428.         $number++;
  2429.         $Index{Sort_Lookup}{$session} = $number;
  2430.     }
  2431. }
  2432.  
  2433.  
  2434. # Sort_Index_By_Type - this calculates an appropriate order for the index
  2435. #   files based on session type, followed by time.
  2436. #
  2437. sub Sort_Index_By_Type {
  2438.     my ($service,$tcp_src_port,$tcp_dest_port,$client,$udp_src_port,
  2439.      $udp_dest_port,$session_id,$time,$number);
  2440.  
  2441.     #
  2442.     #  Determine Session and Stream time order
  2443.     #
  2444.     foreach $session_id (keys %{$TCP{id}}) {
  2445.         # Determine the service - usually by the lowest numbered port
  2446.         $tcp_src_port = $TCP{id}{$session_id}{src_port};
  2447.         $tcp_dest_port = $TCP{id}{$session_id}{dest_port};
  2448.         ($service,$client) = &Pick_Service_Port("TCP",$session_id,
  2449.          $tcp_src_port,$tcp_dest_port);
  2450.  
  2451.         $Index{Type_Order}{"TCP:$session_id"}{1} = 1;
  2452.         $Index{Type_Order}{"TCP:$session_id"}{2} = $service;
  2453.         $Index{Type_Order}{"TCP:$session_id"}{3} =
  2454.          $TCP{id}{$session_id}{StartTime};
  2455.     }
  2456.     foreach $session_id (keys %{$UDP{id}}) {
  2457.             # Determine the service - usually by the lowest numbered port
  2458.         $udp_src_port = $UDP{id}{$session_id}{src_port};
  2459.         $udp_dest_port = $UDP{id}{$session_id}{dest_port};
  2460.         ($service,$client) = &Pick_Service_Port("UDP",$session_id,
  2461.          $udp_src_port,$udp_dest_port);
  2462.  
  2463.         $Index{Type_Order}{"UDP:$session_id"}{1} = 2;
  2464.         $Index{Type_Order}{"UDP:$session_id"}{2} = $service;
  2465.         $Index{Type_Order}{"UDP:$session_id"}{3} =
  2466.          $UDP{id}{$session_id}{StartTime};
  2467.     }
  2468.     foreach $time (keys %{$ICMP{time}}) {
  2469.         $Index{Type_Order}{"ICMP:$time"}{1} = 3;
  2470.         $Index{Type_Order}{"ICMP:$time"}{2} = 0;
  2471.         $Index{Type_Order}{"ICMP:$time"}{3} = $time;
  2472.     }
  2473.  
  2474.     # now we sort by TCP->UDP->IP then port then time.
  2475.     $number = 0;
  2476.     foreach $session (sort {
  2477.         $Index{Type_Order}{$a}{1} <=> $Index{Type_Order}{$b}{1} ||
  2478.         $Index{Type_Order}{$a}{2} <=> $Index{Type_Order}{$b}{2} ||
  2479.         $Index{Type_Order}{$a}{3} <=> $Index{Type_Order}{$b}{3}
  2480.      } keys %{$Index{Type_Order}}) {
  2481.         $number++;
  2482.         $Index{Sort_Lookup}{$session} = $number;
  2483.     }
  2484. }
  2485.  
  2486.  
  2487. # Sort_Index_By_IP - this calculates an appropriate order for the index
  2488. #   files based on client IP, followed by time.
  2489. #
  2490. sub Sort_Index_By_IP {
  2491.     my ($service,$ip,$ip_dest,$ip_src,$client,
  2492.      $session_id,$time,$number,$text,$html,$rest);
  2493.     my @IP;
  2494.  
  2495.     #
  2496.     #  Determine Session and Stream time order
  2497.     #
  2498.     foreach $session_id (keys %{$TCP{id}}) {
  2499.         # Determine source IP
  2500.         # here we use the same subroutine as the index.html
  2501.         # so that they match up.
  2502.         ($text,$html) = &Generate_TCP_IDs($session_id);
  2503.         ($ip,$rest) = split(/:/,$text,2);
  2504.  
  2505.         # Split on IPv4 or IPv6
  2506.         $IP = ();
  2507.         if ($ip =~ /\./) { @IP = split(/\./,$ip); }
  2508.          else { $IP[0] = $ip; }
  2509.  
  2510.         $Index{Type_Order}{"TCP:$session_id"}{1} = $IP[0];
  2511.         $Index{Type_Order}{"TCP:$session_id"}{2} = $IP[1];
  2512.         $Index{Type_Order}{"TCP:$session_id"}{3} = $IP[2];
  2513.         $Index{Type_Order}{"TCP:$session_id"}{4} = $IP[3];
  2514.         $Index{Type_Order}{"TCP:$session_id"}{5} =
  2515.          $TCP{id}{$session_id}{StartTime};
  2516.     }
  2517.     foreach $session_id (keys %{$UDP{id}}) {
  2518.         # Determine source IP
  2519.         $ip = $UDP{id}{$session_id}{src};
  2520.  
  2521.         # Split on IPv4 or IPv6
  2522.         $IP = ();
  2523.         if ($ip =~ /\./) { @IP = split(/\./,$ip); }
  2524.          else { $IP[0] = $ip; }
  2525.  
  2526.         $Index{Type_Order}{"UDP:$session_id"}{1} = $IP[0];
  2527.         $Index{Type_Order}{"UDP:$session_id"}{2} = $IP[1];
  2528.         $Index{Type_Order}{"UDP:$session_id"}{3} = $IP[2];
  2529.         $Index{Type_Order}{"UDP:$session_id"}{4} = $IP[3];
  2530.         $Index{Type_Order}{"UDP:$session_id"}{5} =
  2531.          $UDP{id}{$session_id}{StartTime};
  2532.     }
  2533.     foreach $time (keys %{$ICMP{time}}) {
  2534.         # Determine source IP
  2535.         $ip = $ICMP{time}{$time}{src};
  2536.  
  2537.         # Split on IPv4 or IPv6
  2538.         $IP = ();
  2539.         if ($ip =~ /\./) { @IP = split(/\./,$ip); }
  2540.          else { $IP[0] = $ip; }
  2541.  
  2542.         $Index{Type_Order}{"ICMP:$time"}{1} = $IP[0];
  2543.         $Index{Type_Order}{"ICMP:$time"}{2} = $IP[1];
  2544.         $Index{Type_Order}{"ICMP:$time"}{3} = $IP[2];
  2545.         $Index{Type_Order}{"ICMP:$time"}{4} = $IP[3];
  2546.         $Index{Type_Order}{"ICMP:$time"}{5} = $time;
  2547.     }
  2548.  
  2549.     # now we sort by IP then time
  2550.     $number = 0;
  2551.     foreach $session (sort {
  2552.         $Index{Type_Order}{$a}{1} <=> $Index{Type_Order}{$b}{1} ||
  2553.         $Index{Type_Order}{$a}{2} <=> $Index{Type_Order}{$b}{2} ||
  2554.         $Index{Type_Order}{$a}{3} <=> $Index{Type_Order}{$b}{3} ||
  2555.         $Index{Type_Order}{$a}{4} <=> $Index{Type_Order}{$b}{4} ||
  2556.         $Index{Type_Order}{$a}{1} cmp $Index{Type_Order}{$b}{1} ||
  2557.         $Index{Type_Order}{$a}{5} <=> $Index{Type_Order}{$b}{5}
  2558.      } keys %{$Index{Type_Order}}) {
  2559.         $number++;
  2560.         $Index{Sort_Lookup}{$session} = $number;
  2561.     }
  2562. }
  2563.  
  2564.  
  2565. # Print_Welcome - print short program welcome message.
  2566. #
  2567. sub Print_Welcome {
  2568.     unless ($Arg{quiet}) {
  2569.         print "Chaosreader ver 0.94\n\n";
  2570.     }
  2571. }
  2572.  
  2573.  
  2574. # Print_Header1 - print program welcome message.
  2575. #
  2576. sub Print_Header1 {
  2577.     unless ($Arg{quiet}) {
  2578.         print "Reading $TYPE log...\n";
  2579.         printf "%6s  %-45s  %s\n","Packet",
  2580.             "Session (host:port <=> host:port)","Length";
  2581.     }
  2582. }
  2583.  
  2584.  
  2585. # Print_Header2 - print header before loading the file
  2586. #
  2587. sub Print_Header2 {
  2588.     print "\nCreating files...\n" unless $Arg{quiet};
  2589.     printf "%6s  %-45s  %s\n","Num","Session (host:port <=> host:port)",
  2590.      "Service" unless $Arg{quiet};
  2591. }
  2592.  
  2593.  
  2594. # Print_Footer1 - print footer at end of program.
  2595. #
  2596. sub Print_Footer1 {
  2597.     if ($Arg{output_index}) {
  2598.         print "\nindex.html created.\n" unless $Arg{quiet};
  2599.     }
  2600. }
  2601.  
  2602.  
  2603. # Chdir - change directory with error
  2604. #
  2605. sub Chdir {
  2606.     my $dir = shift;
  2607.     #
  2608.     #  This can be invoked with $Arg{output_dir}, so $dir won't
  2609.     #  always be defined - which is okay.
  2610.     #
  2611.     if (defined $dir) {
  2612.         chdir "$dir" ||
  2613.          die "ERROR21: Can't cd to $dir: $!\n";
  2614.     }
  2615. }
  2616.  
  2617.  
  2618. # Create_Index_Files - Create the HTML and text index files. This reads
  2619. #   %Index and creates the files on disk.
  2620. #
  2621. sub Create_Index_Files {
  2622.    my ($html_index,$html_line,$html_links,$image_empty,$getpost_empty);
  2623.    $getpost_empty = $image_empty = "";
  2624.  
  2625.    if ($Arg{output_index}) {
  2626.  
  2627.  
  2628.     ######################
  2629.     # --- index.html ---
  2630.  
  2631.     $image_empty = "(Empty) " unless $Image{notempty};
  2632.     $getpost_empty = "(Empty) " unless $GETPOST{notempty};
  2633.     $httplog_empty = "(Empty) " unless $HTTPlog{notempty};
  2634.     #
  2635.     #  Create HTML Index file containing all reports
  2636.     #
  2637.     open(FILE,">index.html") || die "ERROR22: creating index: $!\n";
  2638.     print FILE <<END_HTML;
  2639. <html>
  2640. <head><title>Chaosreader Report, $Arg{infile}</title></head>
  2641. <body bgcolor="white" textcolor="black">
  2642. <font size=+3>Chaosreader Report</font><br>
  2643. <font size=+1>File: $Arg{infile}, Type: $TYPE, Created at: $the_date</font><p>
  2644. <a href="image.html"><font color="blue"><b>Image Report</b></font></a>
  2645.  $image_empty - Click here for a report on captured images.<br>
  2646. <a href="getpost.html"><font color="blue"><b>GET/POST Report</b></font></a>
  2647.  $getpost_empty - Click here for a report on HTTP GETs and POSTs.<br>
  2648. <a href="httplog.text"><font color="blue"><b>HTTP Proxy Log</b></font></a>
  2649.  $httplog_empty - Click here for a generated proxy style HTTP log.<p>
  2650. <font size=+2>TCP/UDP/... Sessions</font><br>
  2651. <table border=2>
  2652. END_HTML
  2653.     for ($html_index=0; $html_index <= $#{$Index{HTML}}; $html_index++) {
  2654.         $html_line = $Index{HTML}[$html_index];
  2655.         next unless defined $html_line;
  2656.         print FILE "$html_line </td></tr>\n";
  2657.     }
  2658.     print FILE <<END_HTML;
  2659. </table><p>
  2660. <font size=+2>IP Count</font><br>
  2661. <table border=2>
  2662. END_HTML
  2663.     foreach $IP (sort {$Count{IP}{$b} <=> $Count{IP}{$a}}
  2664.      keys %{$Count{IP}}) {
  2665.         print FILE "<tr><td>$IP</td><td>$Count{IP}{$IP}</td></tr>\n";
  2666.     }
  2667.     print FILE <<END_HTML;
  2668. </table><p>
  2669. <font size=+2>TCP Port Count</font><br>
  2670. <table border=2>
  2671. END_HTML
  2672.     foreach $port (sort {$Count{TCPport}{$b} <=> $Count{TCPport}{$a}}
  2673.      keys %{$Count{TCPport}}) {
  2674.         $port_text = $Services_TCP{$port} || $port || "0";
  2675.         print FILE "<tr><td>$port_text</td><td>$Count{TCPport}{$port}" .
  2676.          "</td></tr>\n";
  2677.     }
  2678.     print FILE <<END_HTML;
  2679. </table><p>
  2680. <font size=+2>UDP Port Count</font><br>
  2681. <table border=2>
  2682. END_HTML
  2683.     foreach $port (sort {$Count{UDPport}{$b} <=> $Count{UDPport}{$a}}
  2684.      keys %{$Count{UDPport}}) {
  2685.         $port_text = $Services_UDP{$port} || $port || "0";
  2686.         print FILE "<tr><td>$port_text</td><td>$Count{UDPport}{$port}" .
  2687.          "</td></tr>\n";
  2688.     }
  2689.     print FILE <<END_HTML;
  2690. </table><p>
  2691. <font size=+2>IP Protocol Count</font><br>
  2692. <table border=2>
  2693. END_HTML
  2694.     foreach $protocol (sort {$Count{IPprotocol}{$b} <=>
  2695.      $Count{IPprotocol}{$a}} keys %{$Count{IPprotocol}}) {
  2696.         $protocol_text = $IP_Protocols{$protocol};
  2697.         print FILE "<tr><td>$protocol_text</td><td>" .
  2698.          "$Count{IPprotocol}{$protocol}</td></tr>\n";
  2699.     }
  2700.     print FILE <<END_HTML;
  2701. </table><p>
  2702. <font size=+2>Ethernet Type Count</font><br>
  2703. <table border=2>
  2704. END_HTML
  2705.     foreach $type (sort {$Count{EtherType}{$b} <=> $Count{EtherType}{$a}}
  2706.      keys %{$Count{EtherType}}) {
  2707.         print FILE "<tr><td>$type</td><td>$Count{EtherType}{$type}" .
  2708.          "</td></tr>\n";
  2709.     }
  2710.     print FILE <<END_HTML;
  2711. </table>
  2712. </body>
  2713. </html>
  2714. END_HTML
  2715.    
  2716.  
  2717.     ######################
  2718.     # --- index.text ---
  2719.  
  2720.     #
  2721.     #  Create Text index file
  2722.     #
  2723.     open(FILE,">index.text") || die "ERROR23: creating index: $!\n";
  2724.     print FILE "TCP/UDP/... Sessions\nFile: $Arg{infile}, "
  2725.      . "Type: $TYPE, Created at: $the_date\n\n";
  2726.     print FILE @{$Index{Text}};
  2727.     close FILE;
  2728.  
  2729.  
  2730.     ######################
  2731.     # --- image.html ---
  2732.  
  2733.     #
  2734.     #  Create HTML Image Index file to display images
  2735.     #
  2736.     open(FILE,">image.html") || die "ERROR24: creating index: $!\n";
  2737.     print FILE <<END_HTML;
  2738. <html>
  2739. <head><title>Chaosreader Image Report</title></head>
  2740. <body bgcolor="white" textcolor="black">
  2741. <font size=+3>Chaosreader Image Report</font><br>
  2742. <font size=+1>Created at: $the_date, Type: $TYPE</font><p>
  2743. <font size=+2>Images</font><br>
  2744. <table border=2>
  2745. END_HTML
  2746.     for ($html_index=0; $html_index <= $#{$Index{HTML}}; $html_index++) {
  2747.         $html_line = $Image{HTML}[$html_index]{info};
  2748.         $html_links = $Image{HTML}[$html_index]{links};
  2749.         next unless defined $html_links;
  2750.         print FILE "$html_line $html_links </td></tr>\n";
  2751.     }
  2752.     print FILE <<END_HTML;
  2753. </table><p>
  2754. </body>
  2755. </html>
  2756. END_HTML
  2757.  
  2758.  
  2759.     ######################
  2760.     # --- getpost.html ---
  2761.  
  2762.     #
  2763.     #  Create HTML GETPOST Index file to show HTTP GETs and POSTs
  2764.     #
  2765.     open(FILE,">getpost.html") || die "ERROR25: creating index: $!\n";
  2766.     print FILE <<END_HTML;
  2767. <html>
  2768. <head><title>Chaosreader GET/POST Report</title></head>
  2769. <body bgcolor="white" textcolor="black">
  2770. <font size=+3>Chaosreader GET/POST Report</font><br>
  2771. <font size=+1>Created at: $the_date, Type: $TYPE</font><p>
  2772. <font size=+2>HTTP GETs and POSTs</font><br>
  2773. <table border=2>
  2774. END_HTML
  2775.     for ($html_index=0; $html_index <= $#{$GETPOST{HTML}}; $html_index++) {
  2776.         $html_line = $GETPOST{HTML}[$html_index]{info};
  2777.         $html_links = $GETPOST{HTML}[$html_index]{query};
  2778.         next unless defined $html_links;
  2779.         print FILE "$html_line $html_links </td></tr>\n";
  2780.     }
  2781.     print FILE <<END_HTML;
  2782. </table><p>
  2783. </body>
  2784. </html>
  2785. END_HTML
  2786.  
  2787.    }
  2788. }
  2789.  
  2790.  
  2791.  
  2792. # Create_Index_Master - Create the HTML and text master index files. This
  2793. #   reads @Master and creates the files on disk.
  2794. #
  2795. sub Create_Index_Master {
  2796.  
  2797.    my ($start,$end,$dir,$file,$index,$duration);
  2798.  
  2799.    if ($Arg{output_index}) {
  2800.  
  2801.     #
  2802.     #  Create most recent link
  2803.     #
  2804.  
  2805.     $dir = $Master[$#Master]{dir};
  2806.     $recentname = "most_recent_index";
  2807.     unlink("$recentname");
  2808.     # don't die on symlink error, it's not essential
  2809.     symlink("$dir","$recentname");
  2810.  
  2811.     #
  2812.     #  Create HTML Index file containing all reports
  2813.     #
  2814.     open(FILE,">index.html") || die "ERROR26: creating index: $!\n";
  2815.     print FILE <<END_HTML;
  2816. <html>
  2817. <head><title>Chaosreader Master Index</title></head>
  2818. <body bgcolor="white" textcolor="black" vlink="blue">
  2819. <font size=+3>Chaosreader Master Index</font><br>
  2820. <font size=+1>Created at: $the_date, Type: $TYPE</font><p>
  2821. <a href="$recentname/index.html"><font color="red">
  2822. <b>Most Recent Report</b></font></a>
  2823.  - Click here for the most recent index, and click reload for updates.<p>
  2824. <font size=+2>Chaosreader Reports</font><br>
  2825. <table border=2>
  2826. END_HTML
  2827.     for ($index=0; $index <= $#Master; $index++) {
  2828.         $start = $Master[$index]{starttime};
  2829.         $end = $Master[$index]{endtime};
  2830.         $dir = $Master[$index]{dir};
  2831.         $file = $Master[$index]{file};
  2832.         $size = $Master[$index]{size};
  2833.         $duration = $Master[$index]{duration};
  2834.         $html_line = "<tr><td><i>". ($index+1) . "</i></td>" .
  2835.          "<td><b>$start</b></td><td><b>$end</b></td>\n" .
  2836.          "<td>$duration s</td>" . "<td><font color=\"green\"> " .
  2837.          "$size bytes</font></td>" .
  2838.          "<td><a href=\"$dir/index.html\">$dir/$file</a></td></tr>\n";
  2839.         print FILE "$html_line </td></tr>\n";
  2840.     }
  2841.     print FILE <<END_HTML;
  2842. </table><p>
  2843. <font size=+2>IP Count</font><br>
  2844. <table border=2>
  2845. END_HTML
  2846.     foreach $IP (sort {$CountMaster{IP}{$b} <=> $CountMaster{IP}{$a}}
  2847.      keys %{$CountMaster{IP}}) {
  2848.         print FILE "<tr><td>$IP</td><td>$CountMaster{IP}{$IP}" .
  2849.          "</td></tr>\n";
  2850.     }
  2851.     print FILE <<END_HTML;
  2852. </table><p>
  2853. <font size=+2>TCP Port Count</font><br>
  2854. <table border=2>
  2855. END_HTML
  2856.     foreach $port (sort {$CountMaster{TCPport}{$b} <=>
  2857.      $CountMaster{TCPport}{$a}} keys %{$CountMaster{TCPport}}) {
  2858.         $port_text = $Services_TCP{$port} || $port || "0";
  2859.         print FILE "<tr><td>$port_text</td><td>" .
  2860.          "$CountMaster{TCPport}{$port}</td></tr>\n";
  2861.     }
  2862.     print FILE <<END_HTML;
  2863. </table><p>
  2864. <font size=+2>UDP Port Count</font><br>
  2865. <table border=2>
  2866. END_HTML
  2867.     foreach $port (sort {$CountMaster{UDPport}{$b} <=>
  2868.      $CountMaster{UDPport}{$a}} keys %{$CountMaster{UDPport}}) {
  2869.         $port_text = $Services_UDP{$port} || $port || "0";
  2870.         print FILE "<tr><td>$port_text</td><td>" .
  2871.          "$CountMaster{UDPport}{$port}</td></tr>\n";
  2872.     }
  2873.     print FILE <<END_HTML;
  2874. </table><p>
  2875. <font size=+2>IP Protocol Count</font><br>
  2876. <table border=2>
  2877. END_HTML
  2878.     foreach $protocol (sort {$CountMaster{IPprotocol}{$b} <=>
  2879.      $CountMaster{IPprotocol}{$a}} keys %{$CountMaster{IPprotocol}}) {
  2880.         $protocol_text = $IP_Protocols{$protocol};
  2881.         print FILE "<tr><td>$protocol_text</td><td>" .
  2882.          "$CountMaster{IPprotocol}{$protocol}</td></tr>\n";
  2883.     }
  2884.     print FILE <<END_HTML;
  2885. </table><p>
  2886. <font size=+2>Ethernet Type Count</font><br>
  2887. <table border=2>
  2888. END_HTML
  2889.     foreach $type (sort {$CountMaster{EtherType}{$b} <=>
  2890.      $CountMaster{EtherType}{$a}} keys %{$CountMaster{EtherType}}) {
  2891.         print FILE "<tr><td>$type</td><td>" .
  2892.          "$CountMaster{EtherType}{$type}</td></tr>\n";
  2893.     }
  2894.     print FILE <<END_HTML;
  2895. </table>
  2896. </body>
  2897. </html>
  2898. END_HTML
  2899.    
  2900.     #
  2901.     #  Create Text index file
  2902.     #
  2903.     open(FILE,">index.text") || die "ERROR27: creating index: $!\n";
  2904.     print FILE "Master Indexes\nCreated at: $the_date, Type: $TYPE\n\n";
  2905.     for ($index=0; $index <= $#Master; $index++) {
  2906.         $start = $Master[$index]{starttime};
  2907.         $end = $Master[$index]{endtime};
  2908.         $dir = $Master[$index]{dir};
  2909.         $file = $Master[$index]{file};
  2910.         $size = $Master[$index]{size};
  2911.         $duration = $Master[$index]{duration};
  2912.         printf FILE "%-25s %3s s %8s b  %s\n",$start,$duration,
  2913.          $size,"$dir/index.text";
  2914.     }
  2915.     close FILE;
  2916.  
  2917.  
  2918.     #
  2919.     #  Create index.file for redos
  2920.     #
  2921.     open(FILE,">index.file") || die "ERROR28: creating index: $!\n";
  2922.     for ($index=0; $index <= $#Master; $index++) {
  2923.         $dir = $Master[$index]{dir};
  2924.         $file = $Master[$index]{file};
  2925.         $start = $Master[$index]{starttime};
  2926.         $end = $Master[$index]{endtime};
  2927.         $duration = $Master[$index]{duration};
  2928.         print FILE "$dir\t$file\t$duration\t$start\t$end\n";
  2929.     }
  2930.     close FILE;
  2931.    }
  2932. }
  2933.  
  2934.  
  2935. # Create_Log_Files - create log files such as the HTTP log.
  2936. #
  2937. sub Create_Log_Files {
  2938.     #BDG some memory debug
  2939.     #system("pmap -x $$");
  2940.  
  2941.     #
  2942.     #  Create HTTPlog.text
  2943.     #
  2944.     open(FILE,">httplog.text") || die "ERROR29: creating HTTP log: $!\n";
  2945.  
  2946.     foreach $time (sort { $a <=> $b }(keys (%{$HTTPlog{time}}))) {
  2947.         print FILE $HTTPlog{time}{$time};
  2948.     }
  2949.  
  2950.     close FILE;
  2951. }
  2952.  
  2953.  
  2954.  
  2955. # File_Type - return file extension for given data, else "data".
  2956. #
  2957. sub File_Type {
  2958.     my $data = $_[0];
  2959.     my $type = "";
  2960.  
  2961.     if ($data =~ /^GIF8[7-9]/)      { $type = "gif"; }
  2962.     elsif ($data =~ /^\377.....(JPEG|JFIF)/)    { $type = "jpeg"; }
  2963.     elsif ($data =~ /^PK\003\004/)      { $type = "zip"; }
  2964.     elsif ($data =~ /^\%PDF/)       { $type = "pdf"; }
  2965.     elsif ($data =~ /^\037\213/)        { $type = "gz"; }
  2966.     elsif ($data =~ /^BZh/)         { $type = "bz2"; }
  2967.     elsif ($data =~ /^\177ELF/)         { $type = "elf"; }
  2968.     elsif ($data =~ /^\%!/)         { $type = "ps"; }
  2969.     elsif ($data =~ /<html>/i)      { $type = "html"; }
  2970.     else { $type = "data"; }
  2971.  
  2972.     return $type;
  2973. }
  2974.  
  2975.  
  2976. # Is_Image - returns true if extension is for an image.
  2977. #
  2978. sub Is_Image {
  2979.     my $ext = shift;
  2980.  
  2981.     return 1 if ($ext eq "jpeg");
  2982.     return 1 if ($ext eq "gif");
  2983.  
  2984.     return 0;
  2985. }
  2986.  
  2987.  
  2988. # Desex_HTML - Removes HTML tags ("<" and ">") from data, so that it no
  2989. #       longer interferes when printed as HTML.
  2990. #
  2991. sub Desex_HTML {
  2992.     ### Input
  2993.     my $data = shift;
  2994.  
  2995.     ### Process
  2996.     # remove "<" and ">"s
  2997.     $data =~ s/</&lt;/g;
  2998.     $data =~ s/>/&gt;/g;
  2999.  
  3000.     ### Return
  3001.     return $data;
  3002. }
  3003.  
  3004.  
  3005.  
  3006. # Process_BothHTML - Process the HTML 2-way session. Remove binary junk
  3007. #           that dosen't render well in a browser.
  3008. #
  3009. sub Process_BothHTML {
  3010.     ### Input
  3011.     my $type = shift;
  3012.     my $session_id = shift;
  3013.     my $plain = shift;
  3014.     my $wrapped = "";
  3015.     my $index = 0;
  3016.     my $counter = 0;
  3017.     my $intag = 0;
  3018.     my ($char,$data);
  3019.  
  3020.     if ($type eq "TCP") {
  3021.         $data = $TCP{id}{$session_id}{BothHTML};
  3022.     } elsif ($type eq "UDP") {
  3023.         $data = $UDP{id}{$session_id}{BothHTML};
  3024.     } elsif ($type eq "ICMP") {
  3025.         $data = $ICMP{time}{$session_id}{BothHTML};
  3026.     }
  3027.  
  3028.     ### Process (order dependant)
  3029.     $data =~ s/font color="red">     \0</font color="red"></g;
  3030.     $data =~ tr/\040-\176\n\r\f/./c;        # max 376, was 245
  3031.     if (defined $plain) {
  3032.        # This is a plain style of line wrap
  3033.        $data =~ s/([^\n\f<>]{$WRAP})/$&\n/g;
  3034.     } else {
  3035.        # This is a fancy line wrap, a green ">" starts the wrapped lines
  3036.        $data =~ s/([^\n\f<>]{$WRAP})/$&\n<font color="green">&gt;<\/font>/g;
  3037.     }
  3038.  
  3039.     ### Save
  3040.     if ($type eq "TCP") {
  3041.         $TCP{id}{$session_id}{BothHTML} = $data;
  3042.     } elsif ($type eq "UDP") {
  3043.         $UDP{id}{$session_id}{BothHTML} = $data;
  3044.     } elsif ($type eq "ICMP") {
  3045.         $ICMP{time}{$session_id}{BothHTML} = $data;
  3046.     }
  3047.  
  3048. }
  3049.  
  3050. # Process_This_HTML - Process the HTML 2-way session. Remove binary junk
  3051. #           that dosen't render well in a browser.
  3052. #
  3053. sub Process_This_HTML {
  3054.     ### Input
  3055.     my $data = shift;
  3056.     my $plain = shift;
  3057.     my $wrapped = "";
  3058.     my $index = 0;
  3059.     my $counter = 0;
  3060.     my $intag = 0;
  3061.     my ($char);
  3062.  
  3063.     ### Process (order dependant)
  3064.     $data =~ s/font color="red">     \0</font color="red"></g;
  3065.     $data =~ tr/\040-\176\n\r\f/./c;        # max 376, was 245
  3066.     if (defined $plain) {
  3067.        # This is a plain style of line wrap
  3068.        $data =~ s/([^\n\f<>]{$WRAP})/$&\n/g;
  3069.     } else {
  3070.        # This is a fancy line wrap, a green ">" starts the wrapped lines
  3071.        $data =~ s/([^\n\f<>]{$WRAP})/$&\n<font color="green">&gt;<\/font>/g;
  3072.     }
  3073.  
  3074.     return $data;
  3075. }
  3076.  
  3077.  
  3078. # Process_Hex - Create the coloured HTML 2-way hex dump, and a text dump.
  3079. #       For code reuse it uses it's own data structure %Hex.
  3080. #       (Originally used %TCP{id}{$session_id}{hex}).
  3081. #
  3082. sub Process_Hex {
  3083.     ### Input
  3084.     my $type = shift;
  3085.     my $session_id = shift;
  3086.     my $data = shift;
  3087.     my $colour = shift;
  3088.     my $pos = $Hex{$type}{$session_id}{pos};
  3089.     my $offset = $Hex{$type}{$session_id}{offset};
  3090.     my $hexhtml = $Hex{$type}{$session_id}{hexhtml};
  3091.     my $viewhtml = $Hex{$type}{$session_id}{viewhtml};
  3092.     my $hextext = $Hex{$type}{$session_id}{hextext};
  3093.     my $viewtext = $Hex{$type}{$session_id}{viewtext};
  3094.     my (@Bytes,$byte,$view,$view2);
  3095.    
  3096.  
  3097.     $pos = 1 unless defined $pos;
  3098.     $offset = 0 unless defined $offset;
  3099.     $hexhtml .= "<font color=\"$colour\">";
  3100.     $viewhtml .= "<font color=\"$colour\">";
  3101.  
  3102.     ### Process
  3103.     @Bytes = unpack("C*",$data);
  3104.     foreach $byte (@Bytes) {
  3105.         $view = chr($byte);
  3106.         $view =~ tr/\040-\176/./c;
  3107.         $view2 = $view;
  3108.         $view2 =~ s/</&lt;/g;
  3109.         $view2 =~ s/>/&gt;/g;
  3110.         $viewhtml .= $view2;
  3111.         $viewtext .= $view;
  3112.         $hexhtml .= sprintf("%2.2x",$byte);
  3113.         $hextext .= sprintf("%2.2x",$byte);
  3114.         $pos++;
  3115.         if ($pos > 16) {
  3116.             ### Save text version
  3117.             $Hex{$type}{$session_id}{text} .=
  3118.              sprintf("%6.08x",$offset) . "  $hextext  $viewtext\n";
  3119.  
  3120.             ### Save HTML version
  3121.             $Hex{$type}{$session_id}{HTML} .=
  3122.              '<font color="green">' . sprintf("%6.08x",$offset) .
  3123.              "</font>  $hexhtml  $viewhtml\n";
  3124.  
  3125.             $pos = 1;
  3126.             $offset += 16;
  3127.             $hexhtml = "</font><font color=\"$colour\">";
  3128.             $viewhtml = "</font><font color=\"$colour\">";
  3129.             $hextext = $viewtext = "";
  3130.         }
  3131.         if ( ($pos != 1) && (($pos %2) == 1) ) {
  3132.             $hexhtml .= " ";
  3133.             $hextext .= " ";
  3134.         }
  3135.     }
  3136.     $hexhtml .= "</font>";
  3137.     $viewhtml .= "</font>";
  3138.  
  3139.     $Hex{$type}{$session_id}{pos} = $pos;
  3140.     $Hex{$type}{$session_id}{offset} = $offset;
  3141.     $Hex{$type}{$session_id}{hexhtml} = $hexhtml;
  3142.     $Hex{$type}{$session_id}{viewhtml} = $viewhtml;
  3143.     $Hex{$type}{$session_id}{hextext} = $hextext;
  3144.     $Hex{$type}{$session_id}{viewtext} = $viewtext;
  3145. }
  3146.  
  3147.  
  3148.  
  3149. # Process_Hex_Finish - Finish the hex dumps.
  3150. #
  3151. sub Process_Hex_Finish {
  3152.     ### Input
  3153.     my $type = shift;
  3154.     my $session_id = shift;
  3155.     my $pos = $Hex{$type}{$session_id}{pos};
  3156.     my $offset = $Hex{$type}{$session_id}{offset};
  3157.     my $hexhtml = $Hex{$type}{$session_id}{hexhtml};
  3158.     my $viewhtml = $Hex{$type}{$session_id}{viewhtml};
  3159.     my $hextext = $Hex{$type}{$session_id}{hextext};
  3160.     my $viewtext = $Hex{$type}{$session_id}{viewtext};
  3161.     my ($short);
  3162.  
  3163.     return unless defined $pos;
  3164.     return if $pos == 1;
  3165.  
  3166.     $short = 39 - length($hextext);
  3167.     $hexhtml .= " " x $short;
  3168.     $hextext .= " " x $short;
  3169.  
  3170.     ### Save text version
  3171.     $Hex{$type}{$session_id}{text} .=
  3172.      sprintf("%6.08x",$offset) . "  $hextext  $viewtext\n";
  3173.  
  3174.     ### Save HTML version
  3175.     $Hex{$type}{$session_id}{HTML} .=
  3176.      '<font color="green">' . sprintf("%6.08x",$offset) .
  3177.      "</font>  $hexhtml  $viewhtml\n";
  3178.  
  3179. }
  3180.  
  3181.  
  3182. # Generate_X11_HTML - fetch the text from an X11 session and save
  3183. #   as bidirectional 2-way coloured HTML.
  3184. #
  3185. # Todo: check if a text or keypress event can be split during
  3186. #  transmission and add code similar to X11 replay to handle this.
  3187. #
  3188. sub Generate_X11_HTML {
  3189.     my ($filename,$data,$copy,$xcode,$xbyte,$xlength,$xrest,$d,
  3190.      $xlv,$xvalue,$pad,$y,$yold,$chars,$colour,$session_data,
  3191.      $service_name,$colourold,$store,$keytype,$gotsome);
  3192.     my @Times;
  3193.  
  3194.     $session_data = "";
  3195.  
  3196.     ### Input
  3197.     my $session_id = shift;
  3198.     $data = "";
  3199.     $service_name = "X11";
  3200.  
  3201.     ### Processing
  3202.     my $session_text = $session_id;
  3203.     $session_text =~ s/,/ <-> /;
  3204.  
  3205.     ### Fetch raw data
  3206.     $xserver = &TCP_Follow_RawA($session_id);
  3207.  
  3208.     #
  3209.     #  Determine endian of this transfer.
  3210.     #
  3211.     ($xjunk,$xvalue,$xjunk) = unpack('nna*',$xserver);
  3212.     #
  3213.     #  Create aliases for "n" and "N".
  3214.     #
  3215.     if ($xvalue < 256) {
  3216.         $n = "n"; $N = "N";
  3217.     } else {
  3218.         $n = "v"; $N = "V";
  3219.     }
  3220.     #
  3221.     #  Determine keymap style - see &Set_X11_KeyCodes()
  3222.     #
  3223.     if ($xserver =~
  3224.      /q...Q.*w...W.*e...E.*r...R.*t...T.*y...Y.*u...U.*i...I.*o...O.*p/) {
  3225.         $keytype = "linux";
  3226.     } else {
  3227.         $keytype = "sun";
  3228.     }
  3229.  
  3230.     #
  3231.     #  Fetch data from both directions, sorting on timestamps
  3232.     #
  3233.     @Times = sort{$a <=> $b} (keys %{$TCP{id}{$session_id}{time}});
  3234.  
  3235.     #
  3236.     # --- Main Loop ---
  3237.     #
  3238.     # (this needs to be a for loop!)
  3239.     for ($i=0; $i <= $#Times; $i++) {
  3240.        $time = $Times[$i];
  3241.  
  3242.        ### Fetch X11 data and direction as a colour
  3243.        if (defined $TCP{id}{$session_id}{time}{$time}{dir}) {
  3244.         $copy = $TCP{id}{$session_id}{time}{$time}{data};
  3245.         if ($TCP{id}{$session_id}{time}{$time}{dir} eq "A") {
  3246.             $colour = "red";
  3247.         } else {
  3248.             $colour = "blue";
  3249.         }
  3250.        }
  3251.  
  3252.        $xrest = $copy;
  3253.        #
  3254.        #  Process through X11 codes
  3255.        #
  3256.        while (length($xrest) > 0) {
  3257.         ### Fetch xcode and other values
  3258.         ($xcode,$xbyte,$xlength,$xrest) = unpack("CC${n}a*",$xrest);
  3259.         $chars = "";
  3260.  
  3261.         #
  3262.         #  Fetch code values from $xrest, and trim
  3263.         #  $xrest. For most requests, the value length
  3264.         #  is a field (bytes 3,4) except for XErrors
  3265.         #  (code 0) where the total length is always 32.
  3266.         #
  3267.         if ($xcode == 0) {
  3268.             $xlv = 28;
  3269.         } else {
  3270.             $xlv = ($xlength - 1) * 4;
  3271.             $xlv = -$xlv if $xlv < 0;
  3272.         }
  3273.  
  3274.         ### Fetch values for this xcode
  3275.         ($xvalue,$xrest) = unpack("a${xlv}a*",$xrest);
  3276.  
  3277.         $store = 0;
  3278.  
  3279.         #
  3280.         #  Process a draw text event (76, 77)
  3281.         #
  3282.         if (($colour eq "blue") && (($xcode == 76)||($xcode == 77))) {
  3283.             # Check if this is a xImageText16Req
  3284.             if ($xcode == 77) { $xbyte *= 2; }
  3285.  
  3286.             ($pad,$y,$chars) = unpack("a10${n}a$xbyte",$xvalue);
  3287.             if ($yold != $y) { $chars = "\n$chars"; }
  3288.             $chars =~ s/\0//g;
  3289.  
  3290.             $store = 1;
  3291.             $yold = $y;
  3292.         }
  3293.  
  3294.         #
  3295.         #  Process a key pressed event (2)
  3296.         #
  3297.         if (($colour eq "red") && ($xcode = "2")) {
  3298.             ($pad,$caps,$pad) = unpack("a24${n}a*",$xvalue);
  3299.  
  3300.             #
  3301.             #  Translate the X11 KeyCode to the actual char
  3302.             #  (try "xmodmap -pke")
  3303.             #
  3304.             $chars = $KeyCode{$keytype}{$caps}{$xbyte};
  3305.  
  3306.             ### Don't keep red \n's for neatness (keep blue ones)
  3307.             unless ($chars eq "\n") {
  3308.                 $store = 1;
  3309.             }
  3310.         }
  3311.        
  3312.         #
  3313.         #  Process a text scroll event (by using 62 - copy area)
  3314.         #
  3315.         if (($colour eq "blue") && ($xcode == 62)) {
  3316.             $chars = "\n";
  3317.             $store = 1;
  3318.         }
  3319.  
  3320.         ### Store data
  3321.         if ($store) {
  3322.             if ($colour ne $colourold) {
  3323.                 $session_data .=
  3324.                  "</font><font color=\"$colour\">$chars";
  3325.             } else {
  3326.                 $session_data .= $chars;
  3327.             }
  3328.             $colourold = $colour;
  3329.         }
  3330.        }
  3331.     }
  3332.  
  3333.     $TCP{id}{$session_id}{BothHTML} = $session_data;
  3334. }
  3335.  
  3336.  
  3337. # Save_Both_HTML - Save bidirectional (coloured) data into a html file.
  3338. #
  3339. sub Save_Both_HTML {
  3340.     my ($filename);
  3341.  
  3342.     ### Input
  3343.     my $type = shift;
  3344.     my $session_id = shift;
  3345.     my $number = shift;
  3346.     my $service_name = shift;
  3347.     my $session_text = shift;
  3348.     my $numtext = sprintf("%04d",$number);
  3349.     my ($base,$raw);
  3350.  
  3351.     $session_text = $session_id unless defined $session_text;
  3352.  
  3353.     ### Processing
  3354.     $session_text =~ s/,/ <-> /;
  3355.  
  3356.     ### Checks
  3357.     $ext = "";
  3358.     $session_data = "";
  3359.     if ($type eq "TCP") {
  3360.        $base = "session";
  3361.        #
  3362.        # Note, the following is similar code for TCP, UDP and ICMP.
  3363.        # However UDP and ICMP use a simple strategy to store and fetch
  3364.        # the processed HTML; whereas TCP uses a complex yet memory
  3365.        # efficient strategy. This is intentional - the way TCP has
  3366.        # been stored has been tuned to reduce memory usage, as TCP has
  3367.        # the bulk of the data (and the bulk of the memory problem). This
  3368.        # has not been necessary with UDP and ICMP (yet).
  3369.        #
  3370.        if ($TCP{id}{$session_id}{BothHTML} ne "") {
  3371.         #
  3372.         #  If the BothHTML report has already been calculated, fetch
  3373.         #
  3374.         $session_data = $TCP{id}{$session_id}{BothHTML};
  3375.        } else {
  3376.         #
  3377.         #  Generate a BothHTML report by following packets by time
  3378.         #
  3379.         foreach $time (sort {$a <=> $b}
  3380.          (keys (%{$TCP{id}{$session_id}{time}}))) {
  3381.            $raw = $TCP{id}{$session_id}{time}{$time}{data};
  3382.            $raw = &Desex_HTML($raw);
  3383.            next unless length($raw);
  3384.            if ($TCP{id}{$session_id}{time}{$time}{dir} eq "A") {
  3385.             $session_data .= "<font color=\"blue\">$raw</font>";
  3386.            } else {
  3387.             $session_data .= "<font color=\"red\">$raw</font>";
  3388.            }
  3389.         }
  3390.         $session_data = &Process_This_HTML($session_data);
  3391.         $base = "session";
  3392.         if ($TCP{id}{$session_id}{Partial}) { $ext = ".partial"; }
  3393.        }
  3394.  
  3395.     } elsif ($type eq "UDP") {
  3396.         $base = "stream";
  3397.         $session_data = $UDP{id}{$session_id}{BothHTML};
  3398.         if ($UDP{id}{$session_id}{Partial}) { $ext = ".partial"; }
  3399.     } elsif ($type eq "ICMP") {
  3400.         $base = "icmp";
  3401.         $session_data = $ICMP{time}{$session_id}{BothHTML};
  3402.         if ($ICMP{time}{$session_id}{Partial}) { $ext = ".partial"; }
  3403.     } else {
  3404.         $base = "are_belong_to_us";
  3405.     }
  3406.  
  3407.     ### Do nothing if there is no data ("26" is mostly due to colour tags)
  3408.     return unless ((defined $session_data)&&(length($session_data) > 26));
  3409.  
  3410.     ### Output
  3411.         $filename = "${base}_${numtext}.${service_name}${ext}.html";
  3412.     open (OUT,">$filename") || die "ERROR30: file create, $filename: $!\n";
  3413.     binmode(OUT);
  3414.     print OUT "<HTML>\n<HEAD><TITLE>$number</TITLE></HEAD>" .
  3415.      "<BODY bgcolor=\"white\">\n" .
  3416.      "<H1>$service_name: $session_text</H1>\n" .
  3417.      "<H2>File $Arg{infile}, Session $number</H2>\n" .
  3418.      "<PRE WRAP=\"virtual\">\n" .
  3419.          $session_data . "</PRE>\n</BODY>\n</HTML>\n";
  3420.         close OUT;
  3421.  
  3422.     ### Global Vars
  3423.     my $length = length($session_data);
  3424.     $Index{HTML}[$number] .= "<li><a href=\"$filename\">as_html</a></li>\n";
  3425.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s bytes\n",
  3426.      '"' , "   $filename","",$length);
  3427. }
  3428.  
  3429.  
  3430.  
  3431. # Save_Hex_HTML - Save bidirectional (coloured) hex data into a html file.
  3432. #
  3433. sub Save_Hex_HTML {
  3434.     my ($filename);
  3435.  
  3436.     ### Input
  3437.     my $type = shift;
  3438.     my $session_id = shift;
  3439.     my $number = shift;
  3440.     my $service_name = shift;
  3441.     my $session_text = shift;
  3442.     my $session_data = $Hex{$type}{$session_id}{HTML};
  3443.     my $numtext = sprintf("%04d",$number);
  3444.     my ($base);
  3445.  
  3446.     $session_text = $session_id unless defined $session_text;
  3447.     $session_data = "" unless defined $session_data;
  3448.    
  3449.  
  3450.     ### Processing
  3451.     $session_text =~ s/,/ <-> /;
  3452.  
  3453.     ### Checks
  3454.     $ext = "";
  3455.     if ($type eq "TCP") {
  3456.         $base = "session";
  3457.         if ($TCP{id}{$session_id}{Partial}) { $ext = ".partial"; }
  3458.     } elsif ($type eq "UDP") {
  3459.         $base = "stream";
  3460.         if ($UDP{id}{$session_id}{Partial}) { $ext = ".partial"; }
  3461.     } elsif ($type eq "ICMP") {
  3462.         $base = "icmp";
  3463.         if ($ICMP{id}{$session_id}{Partial}) { $ext = ".partial"; }
  3464.     }
  3465.  
  3466.     ### Output
  3467.         $filename = "${base}_${numtext}.${service_name}${ext}.hex.html";
  3468.     open (OUT,">$filename") || die "ERROR31: file create, $filename: $!\n";
  3469.     binmode(OUT);
  3470.     print OUT "<HTML>\n<HEAD><TITLE>$number</TITLE></HEAD>" .
  3471.      "<BODY bgcolor=\"white\">\n" .
  3472.      "<H1>$service_name: $session_text</H1>\n" .
  3473.      "<H2>File $Arg{infile}, Session $number</H2>\n" .
  3474.      "<PRE WRAP=\"virtual\">\n" .
  3475.          $session_data . "</PRE>\n</BODY>\n</HTML>\n";
  3476.         close OUT;
  3477.  
  3478.     ### Global Vars
  3479.     my $length = length($session_data);
  3480.     $Index{HTML}[$number] .= "<li>";
  3481.     $Index{HTML}[$number] .= "<a href=\"$filename\">hex</a></li>\n";
  3482.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s bytes\n",
  3483.      '"' , "   $filename","",$length);
  3484. }
  3485.  
  3486.  
  3487.  
  3488. # Save_Hex_Text - Save bidirectional hex data into a text file.
  3489. #
  3490. sub Save_Hex_Text {
  3491.     my ($filename);
  3492.  
  3493.     ### Input
  3494.     my $type = shift;
  3495.     my $session_id = shift;
  3496.     my $number = shift;
  3497.     my $session_text = shift;
  3498.     my $session_data = $Hex{$type}{$session_id}{text};
  3499.     my $numtext = sprintf("%04d",$number);
  3500.     my ($base);
  3501.  
  3502.     $session_text = $session_id unless defined $session_text;
  3503.     $session_data = "" unless defined $session_data;
  3504.  
  3505.     ### Processing
  3506.     $session_text =~ s/,/ <-> /;
  3507.  
  3508.     ### Checks
  3509.     $ext = "";
  3510.     if ($type eq "TCP") {
  3511.         $base = "session";
  3512.         if ($TCP{id}{$session_id}{Partial}) { $ext = ".partial"; }
  3513.     } elsif ($type eq "UDP") {
  3514.         $base = "stream";
  3515.         if ($UDP{id}{$session_id}{Partial}) { $ext = ".partial"; }
  3516.     } elsif ($type eq "ICMP") {
  3517.         $base = "icmp";
  3518.         if ($ICMP{id}{$session_id}{Partial}) { $ext = ".partial"; }
  3519.     }
  3520.  
  3521.     ### Output
  3522.         $filename = "${base}_${numtext}.${service_name}${ext}.hex.text";
  3523.     open (OUT,">$filename") || die "ERROR32: file create, $filename: $!\n";
  3524.     binmode(OUT);
  3525.     print OUT "$service_name: $session_text\n" .
  3526.      "File $Arg{infile}, Session $number\n\n$session_data\n";
  3527.         close OUT;
  3528.  
  3529.     ### Global Vars
  3530.     my $length = length($session_data);
  3531.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s bytes\n",
  3532.      '"' , "   $filename","",$length);
  3533. }
  3534.  
  3535.  
  3536. # Save_FTP_File - Save files from an active FTP session.
  3537. #
  3538. sub Save_FTP_File {
  3539.     my ($filename,$ftp_data,$length);
  3540.     my $session_id = shift;
  3541.     my $number = shift;
  3542.     my $numtext = sprintf("%04d",$number);
  3543.     my $service_name = "ftp-data";
  3544.  
  3545.     ### Input
  3546.     $ftp_data = &TCP_Follow_RawB($session_id);
  3547.     if (! defined $ftp_data) {
  3548.         $ftp_data = &TCP_Follow_RawA($session_id);
  3549.     }
  3550.  
  3551.     ### Checks
  3552.     $ftp_type = &File_Type($ftp_data);
  3553.     if ($TCP{id}{$session_id}{Partial}) { $ext = ".partial"; }
  3554.      else { $ext = ""; }
  3555.  
  3556.     ### Output
  3557.         $filename = "session_${numtext}.part_01.$service_name${ext}.$ftp_type";
  3558.         open (OUT,">$filename") || die "ERROR33: file create, $filename: $!\n";
  3559.     binmode(OUT);       # for backward OSs
  3560.         print OUT $ftp_data;
  3561.         close OUT;
  3562.  
  3563.     ### Global Vars
  3564.     $length = length($ftp_data);
  3565.     $Index{HTML}[$number] .=
  3566.      "<li><a href=\"$filename\">$filename</a> $length bytes</li>\n";
  3567.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s bytes\n",
  3568.      '"' , "   $filename","",$length);
  3569.     if (&Is_Image($ftp_type)) {
  3570.         $Image{HTML}[$number]{links} .=
  3571.          "<img src=\"$filename\"> ";
  3572.         $Image{notempty} = 1;
  3573.     }
  3574. }
  3575.  
  3576. # NOTE On Replays
  3577. #
  3578. # The essence of these is to playback the client/server data so that
  3579. # the original session can be replayed. There are two styles,
  3580. #  
  3581. # Text Replays. These playback the text component to the application
  3582. # data to the screen. These usally work well. The actual text data is not
  3583. # cleaned up in any way, so to preserve escape sequences necessary to
  3584. # redisplay in the original style. Eg, telnet.
  3585. #
  3586. # GUI Replays, or Server/Client Replays. These often use TCP/IP to send
  3587. # the data back to the server or client to playback the session. These
  3588. # are less robust, mainly becuase negotiation can occur slightly differently
  3589. # causing nothing to be displayed. There is code here to redo the
  3590. # negotiation - but it is very difficult for this to be 100% robust.
  3591. # The main reasons the GUI replays fail are colour depth mismatch
  3592. # and dropped packets. Eg, X11.
  3593. #
  3594. # Both styles print the binary data within single quotes ' '. This
  3595. # creates perl programs that can't be "cat" (use cat -vet), or edited
  3596. # in vi (use vim) due to the raw binary data. A neater style would be to
  3597. # translate the binary data into octal or hex text streams, eg
  3598. # 'print "\015\012\087\012"'... Currently this is not used, as it would
  3599. # roughly increase the file size by a factor of 4. However plopping
  3600. # data in the middle of perl programs creates problems of it's own
  3601. # (see the unusual seds). At some point I may opt for the easier,
  3602. # although lengthier, method.
  3603.  
  3604.  
  3605. # Save_Session_Replay - Save a replay program for this session. eg, telnet.
  3606. #
  3607. sub Save_Session_Replay {
  3608.     my ($filename,$duration,$time);
  3609.     my $session_id = shift;
  3610.     my $number = shift;
  3611.     my $service_name = shift;
  3612.     my $numtext = sprintf("%04d",$number);
  3613.  
  3614.     ### Output
  3615.     $filename = "session_${numtext}.${service_name}.replay";
  3616.     $duration = ($TCP{id}{$session_id}{EndTime} -
  3617.      $TCP{id}{$session_id}{StartTime});
  3618.     $duration = sprintf("%.0f",$duration);
  3619.     open (REPLAY,">$filename") ||
  3620.      die "ERROR34: creating $filename $!\n";
  3621.     binmode(REPLAY);    # for backward OSs
  3622.  
  3623.     #
  3624.     #  Create a perl program, that when run itself will print out
  3625.     #  the contents of the server 1-way stream, with pauses based on
  3626.     #  the packet arrival times (replay the session in realtime).
  3627.     #
  3628.     print REPLAY "#!$PERL\n";
  3629.     print REPLAY <<'END';
  3630. #
  3631. # This is a telnet/login replay program. It will replay a session using
  3632. # the timestamps from the packet log.
  3633. #
  3634. # USAGE: run the script as normal. You can provide a factor as an
  3635. #   argument, eg "2" to run twice as fast, or "0.5" to run
  3636. #   at half time. eg,
  3637. #       ./session_0002.telnet.replay 2
  3638. #
  3639. # Auto generated by Chaosreader.
  3640. #
  3641. $| = 1;
  3642. $factor = $ARGV[0] || 1;
  3643. sub ms {
  3644.     $ms = shift;
  3645.     $ms = $ms / $factor;
  3646.     select(undef, undef, undef, $ms);
  3647. }
  3648. END
  3649.  
  3650.     #
  3651.     #  Sort the data on the timestamps, calculating timestamp differences
  3652.     #  to record in the replay program.
  3653.     #
  3654.     @Times = ();
  3655.     foreach $time (keys (%{$TCP{id}{$session_id}{time}})) {
  3656.         if ($TCP{id}{$session_id}{time}{$time}{dir} eq "A") {
  3657.             push(@Times,$time)
  3658.         }
  3659.     }
  3660.     @Times = sort { $a <=> $b } @Times;
  3661.  
  3662.     for ($i=0; $i <= $#Times; $i++) {       # required
  3663.  
  3664.         ### Calculate time diff if possible
  3665.         if ($i == $#Times) {
  3666.             $timediff = 0;
  3667.         } else {
  3668.             $timediff = $Times[$i+1] - $Times[$i];
  3669.             if ($timediff < 0) { $timediff = 0; }
  3670.         }
  3671.         $time = $Times[$i];
  3672.  
  3673.         ### Fetch data from mem
  3674.         $data = $TCP{id}{$session_id}{time}{$time}{data};
  3675.  
  3676.         #
  3677.         #  Clean the data a little (order important)
  3678.         #
  3679.         $data =~ s/\\/\\\\/g;   # backslash the backslashes
  3680.         $data =~ s/'/\\'/g; # backslash single quotes
  3681.  
  3682.         #
  3683.         #  Now output the data in the replay program
  3684.         #
  3685.         print REPLAY "print '" . $data . "';\n";
  3686.  
  3687.         #
  3688.         #  This causes the replay program to pause
  3689.         #
  3690.         print REPLAY "ms($timediff);\n";
  3691.     }
  3692.     close REPLAY;
  3693.  
  3694.     ### Better make it executable
  3695.     chmod (0755, "$filename");
  3696.  
  3697.     ### Global Vars
  3698.     $Index{HTML}[$number] .= "<li><a href=\"$filename\">$filename" .
  3699.      "</a> $duration seconds</li>\n";
  3700.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s seconds\n",
  3701.      '"' , "   $filename","",$duration);
  3702. }
  3703.  
  3704.  
  3705. # Save_Session_textSSH_files - Save a replay program to display the SSH
  3706. #   session in a text format, a html form of this, and a key delay
  3707. #   data file.
  3708. #
  3709. # The program "sshkeydata" will take the key delay data file and estimate
  3710. # the original typed commands. (It also needs a key delay data file
  3711. # from a plaintext session such as telnet, which is generated by the
  3712. # Save_Session_Keydata subroutine).
  3713. #
  3714. # This has been designed with SSH ver 2 in mind.
  3715. #
  3716. sub Save_Session_textSSH_files {
  3717.     my ($filename1,$filename2,$filename3,$duration,$time,$data,$length,
  3718.      $time0,$time1,$time2,$data0,$data1,$data2,$length0,$length1,$length2,
  3719.      $dir0,$dir1,$dir2,$timediff,$timediff2,$outtime,$outsize,$datah,
  3720.      $data00);
  3721.     my $session_id = shift;
  3722.     my $number = shift;
  3723.     my $service_name = shift;
  3724.     my $session_text = shift;
  3725.     my $numtext = sprintf("%04d",$number);
  3726.     my $delay = "";         # a text list of key delays
  3727.     my $html = "";          # a html form of output
  3728.     my $bytes = 0;          # data bytes of the connection
  3729.     my $minsize;            # The min client packet size
  3730.     my $state;
  3731.  
  3732.     $duration = ($TCP{id}{$session_id}{EndTime} -
  3733.      $TCP{id}{$session_id}{StartTime});
  3734.     $duration2 = sprintf("%.2f",$duration);
  3735.     $duration = sprintf("%.0f",$duration);
  3736.  
  3737.     ### Output
  3738.     $filename1 = "session_${numtext}.text${service_name}.replay";
  3739.     open (REPLAY,">$filename1") ||
  3740.      die "ERROR35: creating $filename1 $!\n";
  3741.     binmode(REPLAY);    # for backward OSs
  3742.  
  3743.     #
  3744.     #  Create a perl program that replays details of the original
  3745.     #  SSH session. We print the direction of traffic and size,
  3746.     #  paused using the original delays.
  3747.     #
  3748.     print REPLAY "#!$PERL\n";
  3749.     print REPLAY <<'END';
  3750. #
  3751. # This is a text SSH replay program. It will replay details of the
  3752. # original SSH session using timestamps from the packet capture log.
  3753. #
  3754. # USAGE: run the script as normal. You can provide a factor as an
  3755. #   argument, eg "2" to run twice as fast, or "0.5" to run
  3756. #   at half time. eg,
  3757. #       ./session_0002.textSSH.replay 2
  3758. #
  3759. # Auto generated by Chaosreader.
  3760. #
  3761. $| = 1;
  3762. $factor = $ARGV[0] || 1;
  3763. sub ms {
  3764.     $ms = shift;
  3765.     $ms = $ms / $factor;
  3766.     select(undef, undef, undef, $ms);
  3767. }
  3768. print <<'SUBEND';
  3769. SSH text analysis replay
  3770. ------------------------
  3771. "*" is client traffic (including keystrokes), "." is the return text.
  3772. A number is a multiple of the previous char, eg ".32" is 32 return chars.
  3773.  
  3774. SUBEND
  3775. END
  3776.  
  3777.     #
  3778.     #  Sort the data on the timestamps, calculating timestamp differences
  3779.     #  to record in the replay program.
  3780.     #
  3781.     @Times = ();
  3782.     %PacketSize = ();
  3783.     foreach $time (keys (%{$TCP{id}{$session_id}{time}})) {
  3784.         if (length($TCP{id}{$session_id}{time}{$time}{data}) == 0) {
  3785.             next;
  3786.         }
  3787.         push(@Times,$time);
  3788.         if ($TCP{id}{$session_id}{time}{$time}{dir} eq "B") {
  3789.             ### Frequency count sent sizes
  3790.             $data = $TCP{id}{$session_id}{time}{$time}{data};
  3791.             $length = length($data);
  3792.             $PacketSize{$length}++ if $length < 100;
  3793.         }
  3794.     }
  3795.     @Times = sort { $a <=> $b } @Times;
  3796.     $outtime = $Times[0];
  3797.     $outsize = 0;
  3798.  
  3799.     #
  3800.     #  Determine the client min size - this is the minimum length of
  3801.     #  a data packet, eg a keystroke.
  3802.     #
  3803.     foreach $length (sort {$PacketSize{$b} <=> $PacketSize{$a}}
  3804.      (keys(%PacketSize))) {
  3805.         $minsize = $length;
  3806.         last;
  3807.     }
  3808.  
  3809.     # The very first packet
  3810.     $data00 = $TCP{id}{$session_id}{time}{$Times[0]}{data};
  3811.  
  3812.     ### Process data
  3813.     for ($i=0; $i <= $#Times; $i++) {       # required
  3814.  
  3815.        ### Calculate time diff if possible
  3816.        $time0 = $Times[$i];
  3817.        $time1 = $Times[$i+1];
  3818.        $time2 = $Times[$i+2];
  3819.        $time3 = $Times[$i+3];
  3820.        if ($i == $#Times) {
  3821.         $timediff1 = 0;
  3822.         $timediff2 = 0;
  3823.        } else {
  3824.         $timediff1 = $time1 - $time0;
  3825.         $timediff2 = $time2 - $time0;
  3826.         if ($timediff1 < 0) { $timediff1 = 0; }
  3827.        }
  3828.    
  3829.        ### Fetch data from mem, "0" is this packet...
  3830.        $data0 = $TCP{id}{$session_id}{time}{$time0}{data};
  3831.        $data1 = $TCP{id}{$session_id}{time}{$time1}{data};
  3832.        $data2 = $TCP{id}{$session_id}{time}{$time2}{data};
  3833.        $dir0 = $TCP{id}{$session_id}{time}{$time0}{dir};
  3834.        $dir1 = $TCP{id}{$session_id}{time}{$time1}{dir};
  3835.        $dir2 = $TCP{id}{$session_id}{time}{$time2}{dir};
  3836.        $dir3 = $TCP{id}{$session_id}{time}{$time3}{dir};
  3837.        $length0 = length($data0);
  3838.        $length1 = length($data1);
  3839.        $length2 = length($data2);
  3840.  
  3841.        # working variables
  3842.        $bytes += $length0;
  3843.        $length = $length0;
  3844.        $data = $data0;
  3845.  
  3846.        ##################
  3847.        #  Process Data
  3848.        #
  3849.        #  This is designed for a command line SSH session and
  3850.        #  the calculations are based on many assumptions.
  3851.        #
  3852.        #  For example: if the client sends a small packet (which
  3853.        #  we'll assume is a keystroke) and the server responds
  3854.        #  with large packets (beyond merely echoing the keystroke),
  3855.        #  then we can assume that this keystroke was the enter key,
  3856.        #  and the large response was the output of the command.
  3857.        #
  3858.        #  There are two states - keystrokes and output text.
  3859.        #
  3860.        #  The follow code works well most of the time, and provides
  3861.        #  meaningful results for non command line sessions.
  3862.        #
  3863.    
  3864.        #
  3865.        # --- Server to Client ---
  3866.        #
  3867.        if ($dir0 eq "A") {
  3868.         if ($i > 3 || $data00 !~ /^ssh/i) {
  3869.             # a "." represents an encrypted server to client packet
  3870.             $data = ".";
  3871.             $html .= '<font color="blue">' . $data;
  3872.         } else {
  3873.             ### Process initial plaintext negotiation
  3874.            
  3875.             # first we clean up the data,
  3876.             $data =~ tr/\040-\176/./c;
  3877.             $data =~ s/\\/\\\\/g;
  3878.             $data =~ s/'/\\'/g;
  3879.             $data .= "\n";
  3880.             $hdata = $data;
  3881.             $hdata = &Desex_HTML($hdata);
  3882.  
  3883.             # This is a fancy line wrap, adds a green ">"
  3884.             $hdata =~
  3885.            s/([^\n\f<>]{$WRAP})/$&\n<font color="green">&gt;<\/font>/g;
  3886.             $html .= '<font color="blue">' . $hdata;
  3887.         }
  3888.  
  3889.         if ($state eq "output") {
  3890.            if ($length0 > $minsize && $i > 3) {
  3891.             # This prints the length in the replay files
  3892.             # as a number following the symbol,
  3893.             # eg ".60" would mean a "." with length 60.
  3894.             # length actually means size beyond minsize.
  3895.             $length -= $minsize;
  3896.             $data .= "$length";
  3897.             $html .= "$length";
  3898.             $outsize += $length;
  3899.            }
  3900.  
  3901.         ### Data -> Keystrokes
  3902.         if ($dir1 eq "B" && $length1 == $minsize) {
  3903.             # Process the transition from command output back
  3904.             # to keystrokes.
  3905.             $data .= "\n";
  3906.             $html .= "\n";
  3907.             $delay .= "s $outsize\n";
  3908.             $delay .= sprintf("t %.6f\n",$time0 - $outtime);
  3909.             $delay .= "  \n";   # command delimiter
  3910.             $outsize = 0;
  3911.             $outtime = $time0;
  3912.             $state = "key";
  3913.            }
  3914.         }
  3915.         $html .= '</font>';
  3916.        }
  3917.  
  3918.        #
  3919.        # --- Client to Server ---
  3920.        #
  3921.        else {
  3922.         if ($i == 1) {
  3923.            # PuTTY appears to have an unusual way to send keystrokes
  3924.            # to the server, that differs to OpenSSH and Sun's SSH.
  3925.            # Remember if this is a PuTTY session.
  3926.            $sshtype = "putty" if $data =~ /PuTTY/;
  3927.         }
  3928.  
  3929.         ### Keystroke
  3930.         if ($sshtype eq "") {
  3931.            # If the client is sending a minsize packet and the server
  3932.            # then responds, we assume this is a keystroke.
  3933.            if ($length0 == $minsize && $dir1 eq "A") {
  3934.             $delay .= "k \n";
  3935.            }
  3936.         } elsif ($sshtype eq "putty") {
  3937.            # if the client is sending a minsize packet, followed by
  3938.            # another packet, then a reply packet, and then a server
  3939.            # response; we assume that this is a keystroke.
  3940.            # (This processes PuTTY's doubled keystrokes).
  3941.            if ($length0 == $minsize && $dir1 eq "B" && $dir2 eq "A") {
  3942.             $delay .= "k \n";
  3943.            }
  3944.         }
  3945.  
  3946.         ### Process initial plaintext negotiation
  3947.         if ($i > 3 || $data00 !~ /^ssh/i) {
  3948.             # a "*" represents an encrypted client to server packet
  3949.             $data = "*";
  3950.             $html .= '<font color="red">' . $data;
  3951.         } else {
  3952.             ### Process initial plaintext negotiation
  3953.            
  3954.             # first we clean up the data,
  3955.             $data =~ tr/\040-\176/*/c;
  3956.             $data =~ s/\\/\\\\/g;
  3957.             $data =~ s/'/\\'/g;
  3958.             $data .= "\n";
  3959.             $hdata = $data;
  3960.             $hdata = &Desex_HTML($hdata);
  3961.  
  3962.             # This is a fancy line wrap, adds a green ">"
  3963.             $hdata =~
  3964.            s/([^\n\f<>]{$WRAP})/$&\n<font color="green">&gt;<\/font>/g;
  3965.             $html .= '<font color="red">' . $hdata;
  3966.         }
  3967.  
  3968.         ### Keystroke -> Keystroke delay
  3969.         if ($sshtype eq "") {
  3970.            if ($length0 == $minsize && $dir1 eq "A" && $dir2 eq "B" &&
  3971.             $length2 == $minsize) {
  3972.             # If this is a keystroke packet, and the next packet
  3973.             # is a response, and then another keystroke packet
  3974.             # is sent; then measure the keystroke delay.
  3975.             $timediff2 = $time2 - $time0;
  3976.             $delay .= sprintf("d %.6f\n",$timediff2);
  3977.             $outsize = 0;
  3978.             $outtime = $time0;
  3979.            }
  3980.         } elsif ($sshtype eq "putty") {
  3981.            if ($length0 == $minsize && $dir1 eq "A" && $dir2 eq "B" &&
  3982.             $length2 == $minsize && $dir3 eq "B") {
  3983.             # This is the same idea as the above, but processes
  3984.             # PuTTY's doubled keystrokes.
  3985.             $timediff2 = $time2 - $time0;
  3986.             $delay .= sprintf("d %.6f\n",$timediff2);
  3987.             $outsize = 0;
  3988.             $outtime = $time0;
  3989.            }
  3990.         }
  3991.  
  3992.         if ($length0 > $minsize && $i > 3) {
  3993.             #
  3994.             # This prints the length in the replay files
  3995.             # as a number following the symbol,
  3996.             # eg ".60" would mean a "." with length 60.
  3997.             # length actually means size beyond minsize.
  3998.             $length -= $minsize;
  3999.             $data .= "$length";
  4000.             $html .= "$length";
  4001.         }
  4002.         $html .= '</font>';
  4003.  
  4004.         ### Keystrokes -> Data
  4005.         if ( ($length0 == $minsize &&
  4006.          (($length1 + $length2) > ($minsize * 2))) ||
  4007.          ($dir1 eq "A" && $dir2 eq "A") ) {
  4008.             $data .= "\n";
  4009.             $html .= "\n";
  4010.             #
  4011.             # "r" describes the response packet. This value
  4012.             # may or may not be meaningful depending on the
  4013.             # SSH software.
  4014.             if ($length1 > $minsize) {
  4015.                $delay .= "r 1\n";
  4016.                $delay .= sprintf("p %.6f\n",$timediff1);
  4017.             } else {
  4018.                $delay .= "r 2\n";
  4019.                $delay .= sprintf("p %.6f\n",$timediff2);
  4020.             }
  4021.             $state = "output";
  4022.         }
  4023.        }
  4024.  
  4025.        ### Now output the data in the replay program
  4026.        print REPLAY "print '" . $data . "';\n";
  4027.  
  4028.        ### This causes the replay program to pause
  4029.        print REPLAY "ms($timediff1);\n";
  4030.     }
  4031.     $speed = sprintf("%.2f",$bytes / (1024 * $duration));
  4032.     print REPLAY "print \"\n\n" .
  4033.      "Summary: $duration2 seconds, $bytes bytes, $speed Kb/sec\\n\";";
  4034.     close REPLAY;
  4035.  
  4036.     ### Better make it executable
  4037.     chmod (0755, "$filename1");
  4038.  
  4039.     #
  4040.     #  HTML version of the replay script
  4041.     #
  4042.     $filename2 = "session_${numtext}.text${service_name}.html";
  4043.     open (HTML,">$filename2") ||
  4044.      die "ERROR36: Can't write to file, $filename2 $!\n";
  4045.     $html = "<html><head><title>SSH text analysis</title></head>\n" .
  4046.     "<body bgcolor=\"white\">" .
  4047.     "<H1>$service_name: $session_text</H1>\n" .
  4048.     "<H2>File $Arg{infile}, Session $number</H2>\n" .
  4049.     "<h3>$duration2 seconds, $bytes bytes, $speed Kb/sec</h3>\n" .
  4050.     '"*" is client traffic (including ' .
  4051.     'keystrokes), "." is the return ' .
  4052.     'text.<br>A number is a multiple of the previous char, eg ".32" ' .
  4053.     'is 32 return chars.<br>' .
  4054.     "\n<b><pre>$html</pre></b>\n</body>\n</html>\n";
  4055.     print HTML $html;
  4056.     close HTML;
  4057.  
  4058.     #
  4059.     #  Text Database of time delays between possible keystrokes
  4060.     #
  4061.     $filename3 = "session_${numtext}.text${service_name}.keydata";
  4062.     open (DELAY,">$filename3") ||
  4063.      die "ERROR37: Can't write keydata file: $filename3 $!\n";
  4064.     $delay = "$delay  \n";
  4065.     print DELAY $delay;
  4066.     close DELAY;
  4067.  
  4068.     #
  4069.     #  Update Global Vars to remember new filenames
  4070.     #
  4071.     $Index{HTML}[$number] .= "<li><a href=\"$filename1\">$filename1" .
  4072.      "</a> $duration seconds</li>\n";
  4073.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s seconds\n",
  4074.      '"' , "   $filename1","",$duration);
  4075.     $Index{HTML}[$number] .= "<li><a href=\"$filename2\">$filename2" .
  4076.      "</a> </li>\n";
  4077.     $length = length($html);
  4078.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s bytes\n",
  4079.      '"' , "   $filename2","",$length);
  4080.     $Index{HTML}[$number] .= "<li><a href=\"$filename3\">$filename3" .
  4081.      "</a> </li>\n";
  4082.     $length = length($delay);
  4083.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s bytes\n",
  4084.      '"' , "   $filename3","",$length);
  4085. }
  4086.  
  4087.  
  4088. # Save_Session_Keydata - Save a key delay data file to assist SSH analysis.
  4089. #
  4090. # This code is intentionally designed to be similar to the SSH processing
  4091. # code, so that both their outputs can be compared. As a standalone
  4092. # subroutine this wouldn't make too much sense; instead bear in mind that
  4093. # I'd like the processing to mimic how SSH was processed. That way we
  4094. # run this on plenty of known text (telnet) and become familiar with
  4095. # exactly what will happen for the unknown text (SSH).
  4096. #
  4097. sub Save_Session_Keydata {
  4098.     my ($filename1,$filename2,$filename3,$duration,$time,$data,$length,
  4099.      $time0,$time1,$time2,$data0,$data1,$data2,$length0,$length1,$length2,
  4100.      $dir0,$dir1,$dir2,$timediff,$timediff2,$outtime,$outsize);
  4101.     my $session_id = shift;
  4102.     my $number = shift;
  4103.     my $service_name = shift;
  4104.     my $session_text = shift;
  4105.     my $numtext = sprintf("%04d",$number);
  4106.     my $delay = "";         # a text list of key delays
  4107.     my $minsize;            # The min client packet size
  4108.     my $state = "key";
  4109.  
  4110.     ### Sort the data by timestamps
  4111.     @Times = ();
  4112.     %PacketSize = ();
  4113.     foreach $time (keys (%{$TCP{id}{$session_id}{time}})) {
  4114.         if (length($TCP{id}{$session_id}{time}{$time}{data}) == 0) {
  4115.             next;
  4116.         }
  4117.         push(@Times,$time);
  4118.     }
  4119.     @Times = sort { $a <=> $b } @Times;
  4120.     $outtime = $Times[0];
  4121.     $outsize = 0;
  4122.     $minsize = 1;               # known for telnet
  4123.  
  4124.     ### Process data
  4125.     for ($i=0; $i <= $#Times; $i++) {       # required
  4126.  
  4127.        ### Calculate time diff if possible
  4128.        $time0 = $Times[$i];
  4129.        $time1 = $Times[$i+1];
  4130.        $time2 = $Times[$i+2];
  4131.        if ($i == $#Times) {
  4132.         $timediff1 = 0;
  4133.         $timediff2 = 0;
  4134.        } else {
  4135.         $timediff1 = $time1 - $time0;
  4136.         $timediff2 = $time2 - $time0;
  4137.         if ($timediff1 < 0) { $timediff1 = 0; }
  4138.        }
  4139.  
  4140.        ### Fetch data from mem, "0" is this packet...
  4141.        $data0 = $TCP{id}{$session_id}{time}{$time0}{data};
  4142.        $data1 = $TCP{id}{$session_id}{time}{$time1}{data};
  4143.        $data2 = $TCP{id}{$session_id}{time}{$time2}{data};
  4144.        $data0 = "\n" if $data0 eq "\r\n";
  4145.        $data1 = "\n" if $data1 eq "\r\n";
  4146.        $data2 = "\n" if $data2 eq "\r\n";
  4147.        $data0 = "\n" if $data0 =~ /\r./;
  4148.        $data1 = "\n" if $data1 =~ /\r./;
  4149.        $data2 = "\n" if $data2 =~ /\r./;
  4150.        $dir0 = $TCP{id}{$session_id}{time}{$time0}{dir};
  4151.        $dir1 = $TCP{id}{$session_id}{time}{$time1}{dir};
  4152.        $dir2 = $TCP{id}{$session_id}{time}{$time2}{dir};
  4153.        $length0 = length($data0);
  4154.        $length1 = length($data1);
  4155.        $length2 = length($data2);
  4156.  
  4157.        $length = $length0;
  4158.        $data = $data0;
  4159.  
  4160.        #
  4161.        #  Process Data
  4162.        #
  4163.        if ($dir0 eq "A") {
  4164.         if ($state eq "output") {
  4165.             if ($length0 > $minsize) {
  4166.                 $length -= $minsize;
  4167.                 $outsize += $length;
  4168.             }
  4169.  
  4170.             ### Data -> Keystrokes
  4171.             if ($dir1 eq "B" && $length1 == $minsize) {
  4172.                 $delay .= "s $outsize\n";
  4173.                 $delay .= sprintf("t %.6f\n",$time0 - $outtime);
  4174.                 $delay .= "  \n";
  4175.                 $outsize = 0;
  4176.                 $outtime = $time0;
  4177.                 $state = "key";
  4178.             }
  4179.         }
  4180.        } else {
  4181.         ### Keystroke
  4182.         if ($length0 == $minsize) {
  4183.             if ($data0 eq "\n") {
  4184.                 $delay .= "k \\n\n";
  4185.             } else {
  4186.                 $delay .= "k $data0\n";
  4187.             }
  4188.         }
  4189.         ### Keystroke -> Keystroke delay
  4190.         if ($length0 == $minsize && $dir1 eq "A" && $dir2 eq "B" &&
  4191.          $length2 == $minsize) {
  4192.             $timediff2 = $time2 - $time0;
  4193.             $delay .= sprintf("d %.6f\n",$timediff2);
  4194.             $outsize = 0;
  4195.             $outtime = $time0;
  4196.         }
  4197.  
  4198.         if ($length0 > $minsize) {
  4199.             $length -= $minsize;
  4200.         }
  4201.  
  4202.         ### Keystrokes -> Data
  4203.         if ( ($length0 == $minsize &&
  4204.          (($length1 + $length2) > ($minsize * 2))) ||
  4205.          ($dir1 eq "A" && $dir2 eq "A") ) {
  4206.             if ($length1 > $minsize) {
  4207.                $delay .= "r 1\n";
  4208.                $delay .= sprintf("p %.6f\n",$timediff1);
  4209.             } else {
  4210.                $delay .= "r 2\n";
  4211.                $delay .= sprintf("p %.6f\n",$timediff2);
  4212.             }
  4213.             $state = "output";
  4214.         }
  4215.        }
  4216.     }
  4217.  
  4218.     #
  4219.     #  Text Database of time delays between possible keystrokes
  4220.     #
  4221.     $filename3 = "session_${numtext}.${service_name}.keydata";
  4222.     open (DELAY,">$filename3") ||
  4223.      die "ERROR38: A pink jelly hits you. You die. $filename3 $!\n";
  4224.     print DELAY "$delay  \n";
  4225.     close DELAY;
  4226.  
  4227.     #
  4228.     #  Update Global Vars to remember new filenames
  4229.     #
  4230.     $Index{HTML}[$number] .= "<li><a href=\"$filename3\">$filename3" .
  4231.      "</a> </li>\n";
  4232.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s\n",
  4233.      '"' , "   $filename3","","");
  4234. }
  4235.  
  4236.  
  4237. # Save_Stream_Replay - Save a replay program for this stream. eg, dns.
  4238. #
  4239. sub Save_Stream_Replay {
  4240.     my ($filename,$duration);
  4241.     my $session_id = shift;
  4242.     my $number = shift;
  4243.     my $service_name = shift;
  4244.     my $numtext = sprintf("%04d",$number);
  4245.  
  4246.     ### Output
  4247.     $filename = "stream_${numtext}.${service_name}.replay";
  4248.     $duration = ($UDP{id}{$session_id}{EndTime} -
  4249.      $UDP{id}{$session_id}{StartTime});
  4250.     $duration = sprintf("%.0f",$duration);
  4251.     open (REPLAY,">$filename") ||
  4252.      die "ERROR39: creating $filename $!\n";
  4253.     binmode(REPLAY);    # for backward OSs
  4254.  
  4255.     #
  4256.     #  Create a perl program, that when run itself will print out
  4257.     #  the contents of the server 1-way stream, with pauses based on
  4258.     #  the packet arrival times (replay the stream in realtime).
  4259.     #
  4260.     print REPLAY "#!$PERL\n";
  4261.     print REPLAY <<'END';
  4262. #
  4263. # This is a UDP replay program. It will replay a stream using
  4264. # the timestamps from the packet log.
  4265. #
  4266. # USAGE: run the script as normal. You can provide a factor as an
  4267. #   argument, eg "2" to run twice as fast, or "0.5" to run
  4268. #   at half time. eg,
  4269. #       ./stream_0002.telnet.replay 2
  4270. #
  4271. # Auto generated by Chaosreader.
  4272. #
  4273. $| = 1;
  4274. $factor = $ARGV[0] || 1;
  4275. sub ms {
  4276.     $ms = shift;
  4277.     $ms = $ms / $factor;
  4278.     select(undef, undef, undef, $ms);
  4279. }
  4280. END
  4281.  
  4282.     #
  4283.     #  Sort the data on the timestamps, calculating timestamp differences
  4284.     #  to record in the replay program.
  4285.     #
  4286.     @Times = keys (%{$UDP{id}{$session_id}{time}});
  4287.     @Times = sort { $a <=> $b } @Times;
  4288.  
  4289.     for ($i=0; $i <= $#Times; $i++) {   # required
  4290.  
  4291.         ### Calculate time diff if possible
  4292.         if ($i == $#Times) {
  4293.             $timediff = 0;
  4294.         } else {
  4295.             $timediff = $Times[$i+1] - $Times[$i];
  4296.             if ($timediff < 0) { $timediff = 0; }
  4297.         }
  4298.         $time = $Times[$i];
  4299.  
  4300.         ### Fetch data from mem
  4301.         $data = $UDP{id}{$session_id}{time}{$time};
  4302.         delete $UDP{id}{$session_id}{time}{$time};
  4303.  
  4304.         #
  4305.         #  Clean the data a little (order important)
  4306.         #
  4307.         $data =~ s/\\/\\\\/g;   # backslash the backslashes
  4308.         $data =~ s/'/\\'/g; # backslash single quotes
  4309.  
  4310.         #
  4311.         #  Now output the data in the replay program
  4312.         #
  4313.         print REPLAY "print '" . $data . "';\n";
  4314.  
  4315.         #
  4316.         #  This causes the replay program to pause
  4317.         #
  4318.         print REPLAY "ms($timediff);\n";
  4319.     }
  4320.     close REPLAY;
  4321.  
  4322.     ### Better make it executable
  4323.     chmod (0755, "$filename");
  4324.  
  4325.     ### Global Vars
  4326.     $Index{HTML}[$number] .= "<li><a href=\"$filename\">$filename" .
  4327.      "</a> $duration seconds</li>\n";
  4328.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s seconds\n",
  4329.      '"' , "   $filename","",$duration);
  4330. }
  4331.  
  4332.  
  4333. # Save_Session_XReplay - Save a replay program for this session. eg, X11.
  4334. #   This processes far more of the X11 protocol than I was hoping.
  4335. #   (xscope and ethereal were used to analyse X11).
  4336. #
  4337. sub Save_Session_XReplay {
  4338.     my $session_id = shift;
  4339.     my $number = shift;
  4340.     my $service_name = shift;
  4341.     my $numtext = sprintf("%04d",$number);
  4342.     my ($filename,$duration,$xcode,$xres_old,$xrest,$xwnum,$xdiff,
  4343.      $xlength,$xmsb,$xstart,$xjunk,$xvalue,$readnow,$data,$newdata,
  4344.      $n,$N,$chars,$y,$timediff,$texttimediff,$checkdepth,$filename2,
  4345.      $x11type);
  4346.     my @xWords;
  4347.  
  4348.     ### Initials
  4349.     $xmsb = "";
  4350.     $readnow = 0;
  4351.     $xres_old = -1;
  4352.     $checkdepth = 0;
  4353.  
  4354.     #
  4355.     #  Output - Main X11 replay program
  4356.     #
  4357.     $filename = "session_${numtext}.${service_name}.replay";
  4358.     $duration = ($TCP{id}{$session_id}{EndTime} -
  4359.      $TCP{id}{$session_id}{StartTime});
  4360.     $duration = sprintf("%.0f",$duration);
  4361.     open (REPLAY,">$filename") ||
  4362.      die "ERROR40: creating $filename $!\n";
  4363.     binmode(REPLAY);    # for backward OSs
  4364.  
  4365.     #
  4366.     #  Output - Text (keystroke replay)
  4367.     #
  4368.     $filename2 = "session_${numtext}.text${service_name}.replay";
  4369.     open (REPLAY2,">$filename2") ||
  4370.      die "ERROR41: creating $filename2 $!\n";
  4371.     binmode(REPLAY2);   # for backward OSs
  4372.  
  4373.  
  4374.     #  --- textX11 ---
  4375.     #
  4376.     #  Create a perl program, that when run itself will print out
  4377.     #  the contents of the server 1-way stream, with pauses based on
  4378.     #  the packet arrival times (replay the session in realtime).
  4379.     #
  4380.     print REPLAY2 "#!$PERL\n";
  4381.     print REPLAY2 <<'END';
  4382. #
  4383. # This is an X11 text replay program. It will replay keystrokes and text
  4384. # of an X11 session using the timestamps from the packet log.
  4385. #
  4386. # USAGE: run the script as normal. You can provide a factor as an
  4387. #   argument, eg "2" to run twice as fast, or "0.5" to run
  4388. #   at half time. eg,
  4389. #       ./session_0002.textX11.replay 2
  4390. #
  4391. # Auto generated by Chaosreader.
  4392. #
  4393. $| = 1;
  4394. $factor = $ARGV[0] || 1;
  4395. sub ms {
  4396.     $ms = shift;
  4397.     $ms = $ms / $factor;
  4398.     select(undef, undef, undef, $ms);
  4399. }
  4400. END
  4401.  
  4402.  
  4403.     #  --- X11 ---
  4404.     #
  4405.     #  Create a perl program, that when run itself will print out
  4406.     #  the contents of the server 1-way stream, with pauses based on
  4407.     #  the packet arrival times (replay the session in realtime).
  4408.     #
  4409.     print REPLAY "#!$PERL\n";
  4410.     print REPLAY <<'END';
  4411. #
  4412. # This is a X11 replay program. It will replay a session using
  4413. # the timestamps from the packet log, and transpose the X11 protocol so
  4414. # that it can be redisplayed. You must have captured from the start
  4415. # of the connection for this to work.
  4416. #
  4417. # USAGE: ./session_0001.X11.replay [-d destination host] [-p port] factor
  4418. #
  4419. #   just run the script as normal. You can provide a factor as an
  4420. #   argument, eg "2" to run twice as fast, or "0.5" to run
  4421. #   at half time. eg,
  4422. #       ./session_0002.X11.replay 2
  4423. #   a different host and port can be specified if needed. eg,
  4424. #       ./session_0002.X11.replay -d 192.168.1.5 -p 6001
  4425. #
  4426. # PROBLEMS: you may need to authorise this connection to the X11 server
  4427. #   before it works. You could run "xhost +hostname" beforehand.
  4428. #   The playback needs to have captured the start of the connection.
  4429. #   Check you support the same colour depth as the playback. And check
  4430. #   the playback file simply isn't too big! (more than 500 Kb is
  4431. #   currently problematic).
  4432. #  
  4433. #
  4434. # Auto generated by Chaosreader.
  4435. #
  4436.  
  4437. use IO::Socket;
  4438. use Getopt::Std;
  4439.  
  4440. if ($ARGV[0] =~ /^-h$|^--help$/) { &help(); }
  4441.  
  4442. # Try fetching values from $DISPLAY
  4443. ($hostdef,$portdef) = $ENV{DISPLAY} =~ /([^:]*):(\d*)/;
  4444. $hostdef = "127.0.0.1" if $hostdef eq "";
  4445. $portdef += 6000;
  4446.  
  4447. # Command line options take preference
  4448. &getopts('d:p:');
  4449. if (defined $opt_d) { $host = $opt_d; } else { $host = $hostdef; }
  4450. if (defined $opt_p) { $port = $opt_p; } else { $port = $portdef; }
  4451. $factor = $ARGV[0] || 1;
  4452. $DEBUG = 0;
  4453. $| = 1;
  4454.  
  4455. print "Chaosreader X11 Replay (experimental)\n\n";
  4456. print "Connecting to $host:$port\n";
  4457. print "(problems? try running \"xhost +hostname\" first).\n\n";
  4458.  
  4459.  
  4460. # --- Open Socket ---
  4461. #
  4462. $remote = IO::Socket::INET->new( Proto => "tcp",
  4463.                 PeerAddr  => $host,
  4464.                 PeerPort  => $port,
  4465.                 );
  4466. unless ($remote) { die "ERROR42: Can't connect to X11 daemon on $host:$port"; }
  4467. $remote->autoflush(1);
  4468.  
  4469.  
  4470. # --- Subroutines ---
  4471. #
  4472.  
  4473. # ms - sleeps for specified milliseconds
  4474. #
  4475. sub ms {
  4476.     $ms = shift;
  4477.     $ms = $ms / $factor;
  4478.     select(undef, undef, undef, $ms);
  4479. }
  4480. # help - print help
  4481. #
  4482. sub help {
  4483.         open (MYSELF,"$0") || die "ERROR43: I can't see myself: $!\n";
  4484.         @Myself = <MYSELF>;
  4485.         close MYSELF;
  4486.         ### Print comment from top of code
  4487.         foreach $line (@Myself) {
  4488.                 last if $line !~ /^#/;
  4489.                 next if $line =~ m:^#!/usr/bin/perl:;
  4490.                 $line =~ s/^#/ /;
  4491.                 print $line;
  4492.         }
  4493.         print "\n";
  4494.         exit(0);
  4495. }
  4496. # R - recalculates and prints a resourse setting
  4497. #     The single character subroutine name saves on file space below.
  4498. #
  4499. sub R {
  4500.     #$offset = shift;
  4501.     #$new = $res + $offset;
  4502.     my $rid = shift;
  4503.     my $new;
  4504.  
  4505.     # final checks
  4506.     $diff = $rid - $ridbaseold;
  4507.     $diff = -$diff if $diff < 0;
  4508.     if ((($rid < $ridbaseold) && ($rid < 8196)) || ($diff > 8196)) {
  4509.        if ($msb) { return pack('N',$rid); }
  4510.         else { return pack('V',$rid); }
  4511.     }
  4512.    
  4513.     $new = $rid & $ridmaskold;
  4514.     $new = $new | $ridbase;
  4515.     if ($msb) { return pack('N',$new); }
  4516.          else { return pack('V',$new); }
  4517. }
  4518. # D - prints the new Drawable, usually the rootid.
  4519. #
  4520. sub D {
  4521.     my $rid = shift;
  4522.    
  4523.     # final checks
  4524.     if ($rid >= $ridbaseold) {
  4525.         # return mapped resource id
  4526.         return R($rid);
  4527.     }
  4528.     # return rootid
  4529.     if ($msb) { return pack('N',$rootid); }
  4530.          else { return pack('V',$rootid); }
  4531. }
  4532. # C - prints the new Colour map.
  4533. #
  4534. sub C {
  4535.     my $rid = shift;
  4536.    
  4537.     # final checks
  4538.     if ($rid >= $ridbaseold) {
  4539.         # return mapped resource id
  4540.         return R($rid);
  4541.     }
  4542.     # return colour map
  4543.     if ($msb) { return pack('N',$colour); }
  4544.          else { return pack('V',$colour); }
  4545. }
  4546. # M - Returns a generic mapped id. Can be rootid, colour, or resource.
  4547. #     These are used in Xcodes involving a mask.
  4548. #
  4549. sub M {
  4550.     my $rid = shift;
  4551.    
  4552.     # final checks
  4553.     if ($rid >= $ridbaseold) {
  4554.         # return mapped resource id
  4555.         return R($rid);
  4556.     }
  4557.     # return rootid map
  4558.     if ($rid == $rootidold) {
  4559.        if ($msb) { return pack('N',$rootid); }
  4560.         else { return pack('V',$rootid); }
  4561.     }
  4562.     # return colour map
  4563.     if ($rid == $colourold) {
  4564.        if ($msb) { return pack('N',$colour); }
  4565.         else { return pack('V',$colour); }
  4566.     }
  4567.     # return other
  4568.     if ($msb) { return pack('N',$rid); }
  4569.         else { return pack('V',$rid); }
  4570. }
  4571. # P - Check depth pixels, print warning if there is a mismatch.
  4572. #
  4573. sub P {
  4574.     my $depth = shift;
  4575.     if (! defined $Depth{$depth}) {
  4576.         print "\nWARNING: requested depth $depth may not be ".
  4577.          "supported by the server?\n";
  4578.     }
  4579. }
  4580. # debug - print out a value
  4581. #
  4582. sub debug {
  4583.     my $word = shift;
  4584.     my $num = shift;
  4585.     my $pack = pack("N",$num);
  4586.     print "$word: $num ",
  4587.      sprintf("%2.2x%2.2x%2.2x%2.2x\n",unpack("C*",$pack));
  4588. }
  4589.  
  4590.  
  4591. # --- MAIN ---
  4592. #
  4593. print "Sending X11 traffic:";
  4594. END
  4595.     ### Fetch raw data
  4596.     $xserver = &TCP_Follow_RawA($session_id);
  4597.  
  4598.     #
  4599.     #  Determine endian of this transfer. Reading the
  4600.     #  second short on MSB gives 11, and on LSB 2816
  4601.     #  (at least in testing). We split the difference
  4602.     #  on 256 (is case there is a little variation).
  4603.     #
  4604.     ($xjunk,$xvalue,$xjunk) = unpack('nna*',$xserver);
  4605.     #
  4606.     #  Create aliases for "n" and "N" so I can think
  4607.     #  in big endian.
  4608.     #
  4609.     if ($xvalue < 256) {
  4610.         $xmsb = 1;
  4611.         $n = "n";
  4612.         $N = "N";
  4613.     } else {
  4614.         $xmsb = 0;
  4615.         $n = "v";
  4616.         $N = "V";
  4617.     }
  4618.     my ($success,$major,$minor,$length,$release,$ridbase,
  4619.      $ridmask,$mbsize,$vendor,$reqmax,$roots,$formats,$ibo,
  4620.      $bbo,$bslu,$bslp,$keymin,$keymax,$pad,$rest) =
  4621.      unpack("a2$n$n$n$N$N$N$N$n${n}CCCCCCCC${N}a*",$xserver);
  4622.  
  4623.     ($x11type,$rest) = unpack("a${vendor}a*",$rest);
  4624.     $pad = ((4 - ($vendor % 4)) % 4);
  4625.     ($junk,$rest) = unpack("a${pad}a*",$rest);
  4626.  
  4627.     foreach $i (1..$formats) {
  4628.         ($junk,$rest) = unpack("a8a*",$rest);
  4629.     }
  4630.     ($rootid,$colour,$junk) = unpack("$N${N}a*",$rest);
  4631.  
  4632.     #
  4633.     #  Sort the data on the timestamps, calculating timestamp differences
  4634.     #  to record in the replay program.
  4635.     #
  4636.     @Times = ();
  4637.     foreach $time (keys (%{$TCP{id}{$session_id}{time}})) {
  4638.         if ($TCP{id}{$session_id}{time}{$time}{dir} eq "B") {
  4639.             push(@Times,$time)
  4640.         }
  4641.     }
  4642.     @Times = sort { $a <=> $b } @Times;
  4643.    
  4644.     #
  4645.     # --- Main Loop ---
  4646.     #
  4647.     # (this needs to be a for loop!)
  4648.     for ($i=0; $i <= $#Times; $i++) {
  4649.  
  4650.         ### Calculate time diff if possible
  4651.         if ($i == $#Times) {
  4652.             $timediff = 0;
  4653.         } else {
  4654.             $timediff = $Times[$i+1] - $Times[$i];
  4655.             # just in case,
  4656.             if ($timediff < 0) { $timediff = 0; }
  4657.         }
  4658.         $time = $Times[$i];
  4659.         $texttimediff += $timediff;
  4660.  
  4661.         ### Fetch data from mem
  4662.         $data = $TCP{id}{$session_id}{time}{$time}{data};
  4663.  
  4664.         ### If initial request was fetched,
  4665.         if ($readnow == 0) {
  4666.             ### Populate $xstart with initial request
  4667.             $xstart .= $data;
  4668.  
  4669.             #
  4670.             #  This triggers the replay program to ask the X11
  4671.             #  server for the connection data - which
  4672.             #  needs to be processed so that various
  4673.             #  resource offsets can be used later on.
  4674.             #
  4675.             if (length($xstart) >= 12)  {
  4676.                $readnow = 1;
  4677.             }
  4678.  
  4679.         } else {
  4680.            #
  4681.            #  Change resource offsets
  4682.            #  (reads $data and writes to $data)
  4683.            #
  4684.            $xrest = $data;
  4685.            $data = "";      # output stream of data & subs
  4686.  
  4687.            #
  4688.            #  Process through X11 codes
  4689.            #
  4690.            while (length($xrest) > 0) {
  4691.             ($xcode,$xbyte,$xlength,$xrest) =
  4692.              unpack("CC${n}a*",$xrest);
  4693.  
  4694.             ### Add xcode to output stream $data
  4695.             $d = pack("CC${n}",$xcode,$xbyte,$xlength);
  4696.             # the unusual seds
  4697.             $d =~ s/\\/\\\\/g;
  4698.             $d =~ s/'/\\'/g;
  4699.             $d =~ s/\015\012/'."\\015\\012".'/gs;
  4700.             $data .= $d;
  4701.  
  4702.             #
  4703.             #  Fetch code values from $xrest, and trim
  4704.             #  $xrest. For most requests, the value length
  4705.             #  is a field (bytes 3,4) except for XErrors
  4706.             #  (code 0) where the total length is always 32.
  4707.             #
  4708.             if ($xcode == 0) {
  4709.                 $xlv = 28;
  4710.             } else {
  4711.                 $xlv = ($xlength - 1) * 4;
  4712.                 $xlv = -$xlv if $xlv < 0;
  4713.             }
  4714.             while (length($xrest) < $xlv) {
  4715.                 # some more magic
  4716.                 $i++;
  4717.                 last if ($i > $#Times);
  4718.  
  4719.                 $next = $Times[$i];
  4720.  
  4721.                 ### Fetch data from mem
  4722.                 $xrest .=
  4723.                  $TCP{id}{$session_id}{time}{$next}{data};
  4724.             }
  4725.  
  4726.             ($xvalue,$xrest) = unpack("a${xlv}a*",$xrest);
  4727.  
  4728.             #$format = "%2.2x%2.2x " x ($xlv/2);
  4729.             #printf("X$xcode: $xbyte,$xlength $format\n",
  4730.             # unpack("C*",$xvalue));   ### Debug
  4731.            
  4732.             $xwnum = 0;
  4733.             @xWords = unpack("${N}*",$xvalue);
  4734.  
  4735.             #
  4736.             #  If this is a text event, save the text to the
  4737.             #  textX11 replay program.
  4738.             #
  4739.             if (($xcode == 76) || ($xcode == 77)) {
  4740.  
  4741.                 # Check if this is a xImageText16Req
  4742.                 if ($xcode == 77) { $xbyte *= 2; }
  4743.                
  4744.                 ($pad,$y,$chars) =
  4745.                  unpack("a10${n}a$xbyte",$xvalue);
  4746.                 if ($yold != $y) { $chars = "\n$chars"; }
  4747.  
  4748.                 ### Clean the data a little (order important)
  4749.                 $chars =~ s/\\/\\\\/g;
  4750.                 $chars =~ s/'/\\'/g;
  4751.                 $chars =~ s/\0//g;
  4752.  
  4753.                 ### Now output the data in the replay program
  4754.                 print REPLAY2 "print '" . $chars . "';\n";
  4755.  
  4756.                 ### This causes the replay program to pause
  4757.                 print REPLAY2 "ms($texttimediff);\n"
  4758.                  unless $texttimediff < 0.002;
  4759.  
  4760.                 $yold = $y;
  4761.                 $texttimediff = 0;
  4762.             }
  4763.             #
  4764.             #  Process a text scroll event (by using 62 - copy area)
  4765.             #
  4766.             if ($xcode == 62) {
  4767.                 print REPLAY2 "print \"\\n\";\n";
  4768.                 $chars = "\n";
  4769.             }
  4770.  
  4771.  
  4772.             #
  4773.             #  If this is a create window event, check the depth.
  4774.             #
  4775.             if (($xcode == 1) && ($checkdepth == 0)) {
  4776.                 $data .= "',P($xbyte),'";
  4777.                 $checkdepth = 1;
  4778.             }
  4779.  
  4780.             #
  4781.             #  Print the X11 data with embedded subroutines
  4782.             #  to transpose the resource IDs.
  4783.             #
  4784.             foreach $xw (@xWords) {
  4785.                 $xwnum++;
  4786.                 if ($X11_Codes[$xcode][$xwnum] == 1) {
  4787.                     $data .= "',R($xw),'";
  4788.                     #print "XCODER: $xcode, $xwnum\n";
  4789.                 } elsif ($X11_Codes[$xcode][$xwnum] == 2) {
  4790.                     $data .= "',D($xw),'";
  4791.                     #print "XCODED: $xcode, $xwnum\n";
  4792.                 } elsif ($X11_Codes[$xcode][$xwnum] == 3) {
  4793.                     $data .= "',C($xw),'";
  4794.                     #print "XCODEC: $xcode, $xwnum\n";
  4795.                 } elsif ($X11_Codes[$xcode][$xwnum] == 4) {
  4796.                     $data .= "',M($xw),'";
  4797.                     #print "XCODEM: $xcode, $xwnum\n";
  4798.                 } else {
  4799.                     $d = pack("$N",$xw);
  4800.                     $d =~ s/\\/\\\\/g;
  4801.                     $d =~ s/'/\\'/g;
  4802.                     $d =~ s/\015\012/'."\\015\\012".'/gs;
  4803.                     $data .= $d;
  4804.                 }
  4805.             }
  4806.            }
  4807.         }
  4808.            
  4809.         #
  4810.         #  Now output the data in the replay program
  4811.         #
  4812.         print REPLAY "print '.';\n";
  4813.         print REPLAY "print \$remote '" . $data . "';\n";
  4814.  
  4815.         if ($readnow == 1) {
  4816.             $readnow = 2;
  4817.             print REPLAY "\$msb = $xmsb;\n";
  4818.             print REPLAY "\$ridbaseold = $ridbase;\n";
  4819.             print REPLAY "\$ridmaskold = $ridmask;\n";
  4820.             print REPLAY "\$rootidold = $rootid;\n";
  4821.             print REPLAY "\$colourold = $colour;\n";
  4822.             #
  4823.             #  The following code implements the client to
  4824.             #  server connection - we need to read the
  4825.             #  resource and window IDs which are necessary
  4826.             #  when transposing the replay traffic to
  4827.             #  these new values.
  4828.             #
  4829.             print REPLAY <<'END';
  4830. if ($msb) {
  4831.     $n = "n";
  4832.     $N = "N";
  4833. } else {
  4834.     $n = "v";
  4835.     $N = "V";
  4836. }
  4837.  
  4838.  
  4839. read($remote,$in,40);       # (xConnSetup)
  4840. ($success,$major,$minor,$length,$release,$ridbase,$ridmask,$mbsize,$vendor,
  4841. $reqmax,$roots,$formats,$ibo,$bbo,$bslu,$bslp,$keymin,$keymax,$pad) =
  4842. unpack("a2$n$n$n$N$N$N$N$n${n}CCCCCCCC${N}a*",$in);
  4843.  
  4844. read($remote,$in,$vendor);
  4845. print "\nX11 Server Type: $in\n";
  4846. read($remote,$in,((4 - ($vendor % 4)) % 4));
  4847.  
  4848. foreach $i (1..$formats) {
  4849.     read($remote,$in,8);    # (xPixmapFormat)
  4850.     ($depth,$junk) = unpack("Ca*",$in);
  4851.     $Depth{$depth} = 1;
  4852.     next if $depth == 1;
  4853.     print "X11 server supports $depth bit resolution\n";
  4854. }
  4855. read($remote,$in,8);    # (xWindowRoot)
  4856. ($rootid,$colour,$junk) = unpack("$N$N",$in) unless defined $rootid;
  4857.  
  4858. if ($DEBUG) {
  4859.     debug("Resource ID new: ",$ridbase);
  4860.     debug("Resource ID old: ",$ridbaseold);
  4861.     debug("Root ID new: ",$rootid);
  4862.     debug("Root ID old: ",$rootidold);
  4863.     debug("Colour map new: ",$colour);
  4864.     debug("Colour map old: ",$colourold);
  4865. }
  4866. END
  4867.         }
  4868.  
  4869.         #
  4870.         #  This causes the replay program to pause
  4871.         #
  4872.         print REPLAY "ms($timediff);\n"
  4873.          unless $timediff < 0.002;  # (efficiency).
  4874.     }
  4875.     print REPLAY "print \"\n\";\n";
  4876.     print REPLAY "close \$remote;\n";
  4877.     close REPLAY;
  4878.  
  4879.     ### Better make it executable
  4880.     chmod (0755, "$filename");
  4881.  
  4882.     close REPLAY2;
  4883.     ### Better make it executable
  4884.     chmod (0755, "$filename2");
  4885.  
  4886.     ### Global Vars
  4887.     $Index{HTML}[$number] .= "<li><a href=\"$filename\">$filename" .
  4888.      "</a> $duration seconds</li>\n";
  4889.     $Index{HTML}[$number] .= "<li><a href=\"$filename2\">$filename2" .
  4890.      "</a> $duration seconds</li>\n";
  4891.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s seconds\n",
  4892.      '"' , "   $filename","",$duration);
  4893.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s seconds\n",
  4894.      '"' , "   $filename2","",$duration);
  4895. }
  4896.  
  4897.  
  4898.  
  4899. # Save_Session_VNCReplay_andHTML - Save a replay program for this session.
  4900. #   This creates a program that is used in conjunction with vncviewer.
  4901. #   It also saves the HTML version (it would have been redundant to
  4902. #   create a seperate subroutine for that).
  4903. #
  4904. sub Save_Session_VNCReplay_andHTML {
  4905.     my $session_id = shift;
  4906.     my $number = shift;
  4907.     my $service_name = shift;
  4908.     my $session_text = shift;
  4909.     my $numtext = sprintf("%04d",$number);
  4910.     my ($filename,$filename2,$filename3,$duration,$code,$rest,$extra,
  4911.      $length,$start,$junk,$down,$value,$data,$oldtimediff,$printed,$chars,
  4912.      $char,$timediff,$checkdepth,$html);
  4913.     my @xWords;
  4914.  
  4915.     $oldtimediff = 0;
  4916.     $printed = 0;
  4917.     $html = "";
  4918.  
  4919.  
  4920.     #
  4921.     #  Output - Text (keystroke replay)
  4922.     #
  4923.     $filename2 = "session_${numtext}.text${service_name}.replay";
  4924.     open (REPLAY2,">$filename2") ||
  4925.      die "ERROR44: creating $filename2 $!\n";
  4926.     binmode(REPLAY2);   # for backward OSs
  4927.  
  4928.     #
  4929.     #  --- textVNC ---
  4930.     #
  4931.     #  Create a perl program, that when run itself will print out
  4932.     #  the contents of the client 1-way stream, with pauses based on
  4933.     #  the packet arrival times (replay the session in realtime).
  4934.     #
  4935.     print REPLAY2 "#!$PERL\n";
  4936.     print REPLAY2 <<'END';
  4937. #
  4938. # This is an VNC text replay program. It will replay keystrokes from
  4939. # a VNC session using the timestamps from the packet log.
  4940. #
  4941. # USAGE: run the script as normal. You can provide a factor as an
  4942. #   argument, eg "2" to run twice as fast, or "0.5" to run
  4943. #   at half time. eg,
  4944. #       ./session_0002.textVNC.replay 2
  4945. #
  4946. # Auto generated by Chaosreader.
  4947. #
  4948. $| = 1;
  4949. $factor = $ARGV[0] || 1;
  4950. sub ms {
  4951.     $ms = shift;
  4952.     $ms = $ms / $factor;
  4953.     select(undef, undef, undef, $ms);
  4954. }
  4955. END
  4956.  
  4957.     #
  4958.     #  Sort the data on the timestamps, calculating timestamp differences
  4959.     #  to record in the replay program.
  4960.     #
  4961.     @Times = ();
  4962.     foreach $time (keys (%{$TCP{id}{$session_id}{time}})) {
  4963.         if ($TCP{id}{$session_id}{time}{$time}{dir} eq "B") {
  4964.             push(@Times,$time)
  4965.         }
  4966.     }
  4967.     @Times = sort { $a <=> $b } @Times;
  4968.    
  4969.     #
  4970.     # --- Main Loop ---
  4971.     #
  4972.     # (this needs to be a for loop!)
  4973.     for ($i=0; $i <= $#Times; $i++) {
  4974.  
  4975.         ### Calculate time diff if possible
  4976.         if ($i == $#Times) {
  4977.             $timediff = 0;
  4978.         } else {
  4979.             $timediff = $Times[$i+1] - $Times[$i];
  4980.             # just in case,
  4981.             if ($timediff < 0) { $timediff = 0; }
  4982.         }
  4983.         $time = $Times[$i];
  4984.  
  4985.         ### Fetch data from mem
  4986.         $data = $TCP{id}{$session_id}{time}{$time}{data};
  4987.         ($code) = unpack("C",$data);
  4988.    
  4989.         $chars = "";
  4990.  
  4991.         # skip code 0's
  4992.         if ($code > 0) {
  4993.            #
  4994.            #  Process through VNC client codes
  4995.            #
  4996.            $chars = "";
  4997.            while (length($data) > 0) {
  4998.             ($code) = unpack("C",$data);
  4999.             $length = $VNC_Code_Size{$code};
  5000.             $length--;
  5001.             last if $length <= 0;
  5002.  
  5003.             # Fetch this code only
  5004.             ($code,$value,$data) = unpack("Ca${length}a*",$data);
  5005.  
  5006.             ### Process Key Pressed
  5007.             if ($code == 4) {
  5008.                ($down,$junk,$extra,$char) = unpack("Ca4Ca",$value);
  5009.            
  5010.                next if $down == 0;      # record key-ups
  5011.  
  5012.                if ($extra == 0) {
  5013.                 $chars .= $char;
  5014.                } else {
  5015.                 if (defined $KeyCode{vnc}{0}{$char}) {
  5016.                    $chars .= $KeyCode{vnc}{0}{$char};
  5017.                 }
  5018.                }
  5019.                $html .= $chars;
  5020.             }
  5021.            }
  5022.            
  5023.         }
  5024.            
  5025.         $chars =~ s/\\/\\\\/g;
  5026.         $chars =~ s/'/\\'/g;
  5027.  
  5028.         ### Now output the data in the replay program
  5029.         unless (length($chars) == 0) {
  5030.             print REPLAY2 "ms($oldtimediff);\n"
  5031.              unless $oldtimediff < 0.002;
  5032.  
  5033.             ### Print the data
  5034.             print REPLAY2 "print '" . $chars . "';\n";
  5035.  
  5036.             # these counters are for efficiency, otherwise
  5037.             # we print too many sequiential sleeps
  5038.             $printed = 1;
  5039.             $oldtimediff = 0;
  5040.         } else {
  5041.             $printed = 0;
  5042.             $oldtimediff += $timediff;
  5043.             next;
  5044.         }
  5045.  
  5046.         ### This causes the replay program to pause
  5047.         print REPLAY2 "ms($timediff);\n"
  5048.          unless $timediff < 0.002;
  5049.     }
  5050.     close REPLAY2;
  5051.  
  5052.     ### Better make it executable
  5053.     chmod (0755, "$filename2");
  5054.  
  5055.  
  5056.     #  --- HTML ---
  5057.     #
  5058.     #  Create a HTML page showing the keystrokes
  5059.  
  5060.     ### Clean up html
  5061.     $html = &Desex_HTML($html);
  5062.  
  5063.     ### Output
  5064.         $filename3 = "session_${numtext}.text${service_name}${ext}.html";
  5065.     open (OUT,">$filename3") ||die "ERROR45: file create, $filename3: $!\n";
  5066.     binmode(OUT);
  5067.     print OUT "<HTML>\n<BODY bgcolor=\"white\">\n" .
  5068.      "<H1>$service_name: $session_text</H1>\n" .
  5069.      "<H2>File $Arg{infile}, Session $number</H2>\n" .
  5070.      "<PRE WRAP=\"virtual\">\n" .
  5071.          "<font color=\"red\">" .$html. "</font></PRE>\n</BODY>\n</HTML>\n";
  5072.         close OUT;
  5073.  
  5074.     ### Global Vars
  5075.     $length = length($html);
  5076.     $Index{HTML}[$number] .=
  5077.      "<li><a href=\"$filename3\">keystrokes</a></li>\n";
  5078.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s bytes\n",
  5079.      '"' , "   $filename3","",$length);
  5080.  
  5081.  
  5082.     #
  5083.     #  Output - Main VNC replay program
  5084.     #
  5085.     $filename = "session_${numtext}.${service_name}.replay";
  5086.     $duration = ($TCP{id}{$session_id}{EndTime} -
  5087.      $TCP{id}{$session_id}{StartTime});
  5088.     $duration = sprintf("%.0f",$duration);
  5089.     open (REPLAY,">$filename") ||
  5090.      die "ERROR46: creating $filename $!\n";
  5091.     binmode(REPLAY);    # for backward OSs
  5092.  
  5093.     #
  5094.     #  --- VNC ---
  5095.     #
  5096.     #  Create a perl program, that when run itself will create a
  5097.     #  playback VNC server that listens on a port. When a vncviewer
  5098.     #  connects, the contents of the server 1-way stream arew played back,
  5099.     #  with pauses.
  5100.     #
  5101.     print REPLAY "#!$PERL\n";
  5102.     print REPLAY <<'END';
  5103. #
  5104. # This is a VNC replay program. This runs as a server and listens on a port,
  5105. # then vncviewer is run to connect to that port - at which point the playback
  5106. # commences.
  5107. #
  5108. # USAGE: ./session_0001.VNC.replay [-p port] factor
  5109. #
  5110. #   just run the script as normal. You can provide a factor as an
  5111. #   argument, eg "2" to run twice as fast, or "0.5" to run
  5112. #   at half time. eg,
  5113. #       ./session_0002.VNC.replay 2
  5114. #   a different host and port can be specified if needed. eg,
  5115. #       ./session_0002.VNC.replay -p 5925
  5116. #
  5117. #   After the script is running, connect using vncviewer. eg,
  5118. #       vncviewer -viewonly localhost:25
  5119. #
  5120. # PROBLEMS: The playback needs to have captured the start of the connection,
  5121. #   you need to be at the same colour depth as the playback (or more may
  5122. #   work), and your screen should be at least as big as the playback
  5123. #   resolution. Newer versions of vncviewer may be tuned to match the
  5124. #   playback (eg "-8bit").
  5125. #
  5126. # Auto generated by Chaosreader.
  5127. #
  5128.  
  5129. use IO::Socket;
  5130. use Getopt::Std;
  5131. use Net::hostent;
  5132.  
  5133. $| = 1;
  5134.  
  5135. if ($ARGV[0] =~ /^-h$|^--help$/) { &help(); }
  5136.  
  5137. # Command line options take preference
  5138. &getopts('p:');
  5139. if (defined $opt_p) { $port = $opt_p; } else { $port = 5921; }
  5140. $vncport = $port - 5900;
  5141. if ($vncport < 0) { die "ERROR47: Port $port too low, use at least 5901.\n"; }
  5142. $factor = $ARGV[0] || 1;
  5143. $DEBUG = 0;
  5144.  
  5145. print "Chaosreader VNC Replay (experimental)\n\n";
  5146. print "Listening on port $port...\n";
  5147.  
  5148.  
  5149. # --- Open Socket ---
  5150. #
  5151. $server = IO::Socket::INET->new( Proto     => 'tcp',
  5152.                                  LocalPort => $port,
  5153.                                  Listen    => SOMAXCONN,
  5154.                                  Reuse     => 1);
  5155.  
  5156. die "can't setup server" unless $server;
  5157. unless ($server) {
  5158.     die "ERROR48: Can't open port $port. Try a different port.";
  5159. }
  5160.  
  5161. print <<WELCOME;
  5162. Port opened successfully.
  5163.  
  5164. Now run vncviewer and connect to this port. eg,
  5165.     vncviewer -viewonly localhost:$vncport
  5166.  
  5167. If you are prompted for a password, type any character and hit enter.
  5168. Waiting for connection...
  5169. WELCOME
  5170.  
  5171.  
  5172. # --- Subroutines ---
  5173. #
  5174.  
  5175. # ms - sleeps for specified milliseconds
  5176. #
  5177. sub ms {
  5178.     $ms = shift;
  5179.     $ms = $ms / $factor;
  5180.     select(undef, undef, undef, $ms);
  5181. }
  5182. # help - print help
  5183. #
  5184. sub help {
  5185.         open (MYSELF,"$0") || die "ERROR49: I can't see myself: $!\n";
  5186.         @Myself = <MYSELF>;
  5187.         close MYSELF;
  5188.         ### Print comment from top of code
  5189.         foreach $line (@Myself) {
  5190.                 last if $line !~ /^#/;
  5191.                 next if $line =~ m:^#!/usr/bin/perl:;
  5192.                 $line =~ s/^#/ /;
  5193.                 print $line;
  5194.         }
  5195.         print "\n";
  5196.         exit(0);
  5197. }
  5198.  
  5199.  
  5200. #
  5201. # --- MAIN ---
  5202. #
  5203.  
  5204. ### Wait for connection
  5205. $client = $server->accept();
  5206. $client->autoflush(1);
  5207.  
  5208. print "Sending VNC traffic:";
  5209.  
  5210. END
  5211.  
  5212.     #
  5213.     #  Sort the data on the timestamps, calculating timestamp differences
  5214.     #  to record in the replay program.
  5215.     #
  5216.     @Times = ();
  5217.     foreach $time (keys (%{$TCP{id}{$session_id}{time}})) {
  5218.         if ($TCP{id}{$session_id}{time}{$time}{dir} eq "A") {
  5219.             push(@Times,$time)
  5220.         }
  5221.     }
  5222.     @Times = sort { $a <=> $b } @Times;
  5223.    
  5224.     #
  5225.     # --- Main Loop ---
  5226.     #
  5227.     # (this needs to be a for loop!)
  5228.     for ($i=0; $i <= $#Times; $i++) {
  5229.  
  5230.         ### Calculate time diff if possible
  5231.         if ($i == $#Times) {
  5232.             $timediff = 0;
  5233.         } else {
  5234.             $timediff = $Times[$i+1] - $Times[$i];
  5235.             # just in case,
  5236.             if ($timediff < 0) { $timediff = 0; }
  5237.         }
  5238.         $time = $Times[$i];
  5239.  
  5240.         ### Fetch data from mem
  5241.         $data = $TCP{id}{$session_id}{time}{$time}{data};
  5242.  
  5243.         $data =~ s/\\/\\\\/g;
  5244.         $data =~ s/'/\\'/g;
  5245.         $data =~ s/\015\012/'."\\015\\012".'/gs;
  5246.  
  5247.         #
  5248.         #  Now output the data in the replay program
  5249.         #
  5250.         print REPLAY "print '.';\n";
  5251.         print REPLAY "print \$client '" . $data . "';\n";
  5252.  
  5253.         #
  5254.         #  This causes the replay program to pause
  5255.         #
  5256.         print REPLAY "ms($timediff);\n"
  5257.          unless $timediff < 0.002;  # (efficiency).
  5258.     }
  5259.     print REPLAY "print \"\n\";\n";
  5260.     print REPLAY "close \$client;\n";
  5261.     close REPLAY;
  5262.  
  5263.     ### Better make it executable
  5264.     chmod (0755, "$filename");
  5265.  
  5266.     ### Global Vars
  5267.     $Index{HTML}[$number] .= "<li><a href=\"$filename\">$filename" .
  5268.      "</a> $duration seconds</li>\n";
  5269.     $Index{HTML}[$number] .= "<li><a href=\"$filename2\">$filename2" .
  5270.      "</a> $duration seconds</li>\n";
  5271.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s seconds\n",
  5272.      '"' , "   $filename","",$duration);
  5273.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s seconds\n",
  5274.      '"' , "   $filename2","",$duration);
  5275. }
  5276.  
  5277.  
  5278.  
  5279. # Save_SMTP_Emails - Save emails from an SMTP session.
  5280. #
  5281. sub Save_SMTP_Emails {
  5282.     my ($filename);
  5283.     my $session_id = shift;
  5284.     my $number = shift;
  5285.     my $service_name = "smtp";
  5286.     my $numtext = sprintf("%04d",$number);
  5287.  
  5288.  
  5289.     ### Full - Input
  5290.     $snmp_data = &TCP_Follow_RawB($session_id);
  5291.  
  5292.     ### Full - Processing
  5293.     @Snmp_parts = split(/\r\n\.\r\n|\n\.\n/,$snmp_data);
  5294.  
  5295.     ### LOOP
  5296.     $partnum = 0;
  5297.     foreach $snmp_part (@Snmp_parts) {
  5298.  
  5299.         next unless $snmp_part =~ /DATA/;
  5300.         $partnum++;
  5301.         $parttext = sprintf("%02d",$partnum);
  5302.  
  5303.         ### Part - Processing
  5304.         $snmp_part =~ s/^.*DATA\r?\n//s;    # '/s;' is new perl5,
  5305.                             # else '/;' with $* = 1
  5306.  
  5307.         ### Part - Output
  5308.         if ($TCP{id}{$session_id}{Partial}) { $ext = ".partial"; }
  5309.          else { $ext = ""; }
  5310.             $filename = "session_${numtext}.part_${parttext}." .
  5311.          "${service_name}${ext}.email";
  5312.             open (OUT,">$filename") ||
  5313.          die "ERROR50: file create, $filename: $!\n";
  5314.         binmode(OUT);       # for backward OSs
  5315.             print OUT $snmp_part;
  5316.             close OUT;
  5317.  
  5318.         ### Part - Global Vars
  5319.         my $length = length($snmp_part);
  5320.         $Index{HTML}[$number] .= "<li><a href=\"$filename\">$filename" .
  5321.          "</a> $length bytes</li>\n";
  5322.         $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s bytes\n",
  5323.          '"' , "   $filename","",$length);
  5324.     }
  5325. }
  5326.  
  5327.  
  5328. # Save_HTTP_Files - Save HTTP components.
  5329. #
  5330. sub Save_HTTP_Files {
  5331.     my ($filename);
  5332.     my $session_id = shift;
  5333.     my $number = shift;
  5334.     my $service_name = shift;
  5335.     my $numtext = sprintf("%04d",$number);
  5336.  
  5337.     ### Full - Input
  5338.     $http_session = &TCP_Follow_RawA($session_id);
  5339.  
  5340.     ### Full - Processing
  5341.     @HttpParts = split(/HTTP\/[0-9.]* /,$http_session);
  5342.  
  5343.     ### LOOP
  5344.     $partnum = 0;
  5345.     foreach $http_part (@HttpParts) {
  5346.  
  5347.         ### Part - Processing
  5348.         ($http_header,$http_data) = split(/\r\n\r\n|\n\n/,$http_part,2);
  5349.         next if $http_data eq "";
  5350.         next if length($http_data) < 8;
  5351.         $partnum++;
  5352.         $parttext = sprintf("%02d",$partnum);
  5353.  
  5354.         ### Part - Checks
  5355.         $http_type = &File_Type($http_data);
  5356.         if ($TCP{id}{$session_id}{Partial}) { $ext = ".partial"; }
  5357.          else { $ext = ""; }
  5358.  
  5359.         ### Part - Output
  5360.             $filename = "session_${numtext}.part_$parttext${ext}." .
  5361.          "$http_type";
  5362.             open (OUT,">$filename") ||
  5363.          die "ERROR51: file create, $filename: $!\n";
  5364.         binmode(OUT);       # for backward OSs
  5365.             print OUT $http_data;
  5366.             close OUT;
  5367.  
  5368.         ### Part - Global Vars
  5369.         my $length = length($http_data);
  5370.         $Index{HTML}[$number] .= "<li><a href=\"$filename\">$filename" .
  5371.          "</a> $length bytes</li>\n";
  5372.         $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s bytes\n",
  5373.          '"' , "   $filename","",$length);
  5374.         if (&Is_Image($http_type)) {
  5375.             $Image{HTML}[$number]{links} .=
  5376.              "<img src=\"$filename\"> ";
  5377.             $Image{notempty} = 1;
  5378.         }
  5379.     }
  5380. }
  5381.  
  5382.  
  5383. # Save_NFS_File - Save NFS file. Only works well for some files, if the NFS
  5384. #       header can't be processed, a "*.nfs.raw" file is created.
  5385. #
  5386. sub Save_NFS_File {
  5387.     my ($filename);
  5388.     my $session_id = shift;
  5389.     my $number = shift;
  5390.     my $service_name = "nfs";
  5391.     my $numtext = sprintf("%04d",$number);
  5392.  
  5393.     ### Input
  5394.     my $nfs_raw = &TCP_Follow_RawB($session_id);
  5395.  
  5396.     ### Processing
  5397.     ($nfs_start,$nfs_size,$nfs_end) = unpack('a56a4a*',$nfs_raw);
  5398.     $nfs_sizeint = unpack("N",$nfs_size);
  5399.     ($nfs_start,$nfs_data) = split(/$nfs_size....$nfs_size/,$nfs_end,2);
  5400.  
  5401.     ### Checks
  5402.     if (($nfs_sizeint > 4) && (length($nfs_data) >= $nfs_sizeint)) {
  5403.         $nfs_type = &File_Type($nfs_data);
  5404.         if ($nfs_sizeint < length($nfs_data)) {
  5405.             $nfs_data = unpack("a${nfs_sizeint}a*",$nfs_data);
  5406.         }
  5407.     } else {
  5408.         $nfs_type = "raw";
  5409.         $nfs_data = $nfs_raw;
  5410.     }
  5411.     if ($TCP{id}{$session_id}{Partial}) { $ext = ".partial"; }
  5412.      else { $ext = ""; }
  5413.  
  5414.     ### Output
  5415.         $filename = "session_${numtext}.part_01.${service_name}${ext}.nfs." .
  5416.      "$nfs_type";
  5417.     open (OUT,">$filename") || die "ERROR52: file create, $filename: $!\n";
  5418.     binmode(OUT);       # for backward OSs
  5419.     print OUT $nfs_data;
  5420.     close OUT;
  5421.  
  5422.     ### Global Vars
  5423.     my $length = length($nfs_data);
  5424.     $Index{HTML}[$number] .= "<li><a href=\"$filename\">$filename</a>" .
  5425.      " $length bytes</li>\n";
  5426.     $Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s bytes\n",
  5427.      '"' , "   $filename","",$length);
  5428. }
  5429.  
  5430.  
  5431. # TCP_Follow_RawA - process session by TCP Seq numbers 1-way.
  5432. #           (TCP ASSEMBLY)
  5433. #
  5434. sub TCP_Follow_RawA {
  5435.     my $session_id = shift;    
  5436.     my $raw = "";
  5437.  
  5438.     #
  5439.     #  Assemble TCP Sessions. Each hash contains session_ids as keys,
  5440.     #  and the value points to another hash of sequence numbers and data.
  5441.     #  %TCP{id}{}{Aseq} is input, and %TCP{id}{}{RawA} is output.
  5442.     #
  5443.     @Seqs = keys (%{$TCP{id}{$session_id}{Aseq}});
  5444.     foreach $seq (sort { $a <=> $b } @Seqs) {
  5445.         $raw .= ${$TCP{id}{$session_id}{Aseq}{$seq}};
  5446.     }
  5447.  
  5448.     return $raw;
  5449. }
  5450.  
  5451.  
  5452. # TCP_Follow_RawB - process session by TCP Seq numbers 1-way.
  5453. #           (TCP ASSEMBLY)
  5454. #
  5455. sub TCP_Follow_RawB {
  5456.     my $session_id = shift;    
  5457.     my $raw = "";
  5458.  
  5459.     #
  5460.     #  Assemble TCP Sessions. Each hash contains session_ids as keys,
  5461.     #  and the value points to another hash of sequence numbers and data.
  5462.     #  %TCP{id}{}{Aseq} is input, and %TCP{id}{}{RawA} is output.
  5463.     #
  5464.     @Seqs = keys (%{$TCP{id}{$session_id}{Bseq}});
  5465.     foreach $seq (sort { $a <=> $b } @Seqs) {
  5466.         $raw .= ${$TCP{id}{$session_id}{Bseq}{$seq}};
  5467.     }
  5468.  
  5469.     return $raw;
  5470. }
  5471.  
  5472.  
  5473. # Pick_Service_Port - pick which port is the server. Usually is the lower
  5474. #   number, however check if the direction is already known (eg SYN).
  5475. #   The port arguments will not often be needed.
  5476. #
  5477. # NOTE: This code is different to Generate_TCP_IPs - which does the "<->"'s
  5478. #
  5479. sub Pick_Service_Port {
  5480.     my $type = shift;
  5481.     my $id = shift;
  5482.     my $porta = shift;
  5483.     my $portb = shift;
  5484.     my $from_server = 0;
  5485.     my ($hi,$low);
  5486.  
  5487.     # Catch active FTP, etc.
  5488.     ($low,$hi) = sort { $a <=> $b } ($porta,$portb);
  5489.     if ($low < 100) {
  5490.         return ($low,$hi);
  5491.     }
  5492.    
  5493.     if ($type eq "TCP") {
  5494.        if (defined $TCP{id}{$id}{source}) {
  5495.         if ($TCP{id}{$id}{source} eq $TCP{id}{$id}{src}) {
  5496.            return ($TCP{id}{$id}{dest_port},$TCP{id}{$id}{src_port});
  5497.         } else {
  5498.            return ($TCP{id}{$id}{src_port},$TCP{id}{$id}{dest_port});
  5499.         }
  5500.        }
  5501.     } elsif ($type eq "UDP") {
  5502.        return ($UDP{id}{$id}{dest_port},$UDP{id}{$id}{src_port});
  5503.     }
  5504.  
  5505.     # resort to a sort
  5506.     return sort { $a <=> $b } ($porta,$portb);
  5507. }
  5508.  
  5509.  
  5510. # Generate_SessionID - input source and dest IPs and ports, and generate
  5511. #   a unique session_id based on them. this is done by sorting on
  5512. #   ports and then IPs. Also returns a flag if the packet may be
  5513. #   assumed to be from_server - where the lowest port is assumed to
  5514. #   be the server (unless TCP SYNs have been observed).
  5515. #
  5516. sub Generate_SessionID {
  5517.     my $ip_src = shift;
  5518.     my $tcp_src_port = shift;
  5519.     my $ip_dest = shift;
  5520.     my $tcp_dest_port = shift;
  5521.     my $type = shift;
  5522.     my $from_server = 0;
  5523.     my $session_id;
  5524.  
  5525.     #
  5526.     #  Generate session_id string using host:port,host:port sorted on
  5527.     #  port (low port last).
  5528.     #
  5529.     if ($tcp_src_port < $tcp_dest_port) {
  5530.         $session_id = "$ip_dest:$tcp_dest_port,$ip_src:$tcp_src_port";
  5531.         $from_server = 1;
  5532.     } elsif ($tcp_src_port > $tcp_dest_port) {
  5533.         $session_id = "$ip_src:$tcp_src_port,$ip_dest:$tcp_dest_port";
  5534.         $from_server = 0;
  5535.     } else {
  5536.         $session_id =join(",",sort("$ip_src:$tcp_src_port",
  5537.                     "$ip_dest:$tcp_dest_port"));
  5538.         $from_server = 1;
  5539.     }
  5540.  
  5541.     if ($type eq "TCP") {
  5542.         if (defined $TCP{id}{$session_id}{source}) {
  5543.             if ($TCP{id}{$session_id}{source} eq $ip_dest) {
  5544.                 $from_server = 1;
  5545.             } else {
  5546.                 $from_server = 0;
  5547.             }
  5548.         }
  5549.     }
  5550.     return ($session_id,$from_server);
  5551. }
  5552.  
  5553.  
  5554.  
  5555. # Generate_TCP_IDs - generate a text and html version of the session ID, that
  5556. #       displays direction of the TCP session if SYNs and ACKs were
  5557. #       observed, else uses a "<->" symbol to represent unknown
  5558. #       direction. TCP only.
  5559. #
  5560. sub Generate_TCP_IDs {
  5561.     my $session_id = shift;
  5562.     my ($ip_src,$tcp_src_port,$ip_dest,$tcp_dest_port,$text,$html);
  5563.  
  5564.     # try this direction,
  5565.     $ip_src = $TCP{id}{$session_id}{src};
  5566.     $ip_dest = $TCP{id}{$session_id}{dest};
  5567.     $tcp_src_port = $TCP{id}{$session_id}{src_port};
  5568.     $tcp_dest_port = $TCP{id}{$session_id}{dest_port};
  5569.  
  5570.     if (defined $TCP{id}{$session_id}{source}) {
  5571.         if ($TCP{id}{$session_id}{source} eq $ip_dest) {
  5572.             # nope, switch ends
  5573.             $ip_src = $TCP{id}{$session_id}{dest};
  5574.             $ip_dest = $TCP{id}{$session_id}{src};
  5575.             $tcp_src_port = $TCP{id}{$session_id}{dest_port};
  5576.             $tcp_dest_port = $TCP{id}{$session_id}{src_port};
  5577.         }
  5578.         $text = "$ip_src:$tcp_src_port -> $ip_dest:$tcp_dest_port";
  5579.         $html = "$ip_src:$tcp_src_port -&gt; $ip_dest:$tcp_dest_port";
  5580.     } else {
  5581.         $text = "$ip_src:$tcp_src_port <-> $ip_dest:$tcp_dest_port";
  5582.         $html = "$ip_src:$tcp_src_port &lt;-&gt; " .
  5583.          "$ip_dest:$tcp_dest_port";
  5584.     }
  5585.  
  5586.     return ($text,$html);
  5587. }
  5588.  
  5589.  
  5590.  
  5591. # Generate_IP_ID - input source IP, dest IP and ident, and generate a
  5592. #       unique ip_id based on them. This is necessary for IP
  5593. #       fragmentation reassembely. Normally we would assume that
  5594. #       the IP_ident was unique - however this program could
  5595. #       process traffic from many different hosts over a long
  5596. #       period of time - idents alone could clash.
  5597. #
  5598. sub Generate_IP_ID {
  5599.     my $ip_src = shift;
  5600.     my $ip_dest = shift;
  5601.     my $ip_ident = shift;
  5602.     my $ip_id;
  5603.  
  5604.     #
  5605.     #  Generate ip_id string using host:host:ident sorted on IP.
  5606.     #  
  5607.     #
  5608.     $ip_id = join(",",sort("$ip_src","$ip_dest")) . ",$ip_ident";
  5609.  
  5610.     return $ip_id;
  5611. }
  5612.  
  5613.  
  5614.  
  5615. # Read_Tcpdump_Record - Read the next tcpdump record, will "last" if
  5616. #           there are no more records.
  5617. #
  5618. sub Read_Tcpdump_Record {
  5619.     my $more;
  5620.  
  5621.     ### Fetch record header
  5622.     $length = read(INFILE,$header_rec,($integerSize * 2 + 8));
  5623.  
  5624.     ### Quit main loop if at end of file
  5625.     last if $length < 16;
  5626.  
  5627.     ### Throw out extra info in tcpdump/modified1 format
  5628.     if ($STYLE =~ /^modified/) {
  5629.         $length = read(INFILE,$more,8);
  5630.     }
  5631.  
  5632.     $frame++;
  5633.  
  5634.     ## Unpack header, endian sensitive
  5635.     if ($STYLE =~ /1$/) {
  5636.         ($tcpdump_seconds,$tcpdump_msecs,$tcpdump_length,
  5637.          $tcpdump_length_orig)
  5638.          = unpack('NNNN',$header_rec);
  5639.     } else {
  5640.         ($tcpdump_seconds,$tcpdump_msecs,$tcpdump_length,
  5641.          $tcpdump_length_orig)
  5642.          = unpack('VVVV',$header_rec);
  5643.     }
  5644.     $length = read(INFILE,$tcpdump_data,$tcpdump_length);
  5645.     $tcpdump_drops = $tcpdump_length_orig - $tcpdump_length;
  5646. }
  5647.  
  5648.  
  5649. # Read_Snoop_Record - Read the next snoop record, will "last" if
  5650. #           there are no more records.
  5651. #
  5652. sub Read_Snoop_Record {
  5653.     ### Fetch record header
  5654.     $length = read(INFILE,$header_rec,24);
  5655.  
  5656.     ### Quit main loop if at end of file
  5657.     last if $length < 24;
  5658.  
  5659.     $frame++;
  5660.  
  5661.     ### Unpack header
  5662.     ($snoop_length_orig,$snoop_length_inc,$snoop_length_rec,$snoop_drops,
  5663.         $snoop_seconds,$snoop_msecs) = unpack('NNNNNN',$header_rec);
  5664.     $length = read(INFILE,$snoop_data,$snoop_length_inc);
  5665.     $skip = read(INFILE,$pad,($snoop_length_rec - $snoop_length_inc - 24));
  5666. }
  5667.  
  5668.  
  5669. # Load_Index_File - Load the master index file "index.file" into @Master
  5670. #
  5671. sub Load_Index_File {
  5672.  
  5673.     my ($path,$dir,$file,$start,$end,$duration,$index);
  5674.  
  5675.     #
  5676.     #  Load index.file lines into memory
  5677.     #
  5678.     open (FILES,"index.file") || die "ERROR53: Can't read index.file: $!\n"
  5679.      ."Standalone mode needs to have run recently from this directory.\n\n";
  5680.  
  5681.     chomp(@Files = <FILES>);
  5682.     close FILES;
  5683.  
  5684.     #
  5685.     #  Populate @Master
  5686.     #
  5687.     $index = 0;
  5688.     foreach $path (@Files) {
  5689.         ($dir,$file,$duration,$start,$end) = split(/\t/,$path);
  5690.         $Master[$index]{starttime} = $start;
  5691.         $Master[$index]{endtime} = $end;
  5692.         $Master[$index]{dir} = $dir;
  5693.         $Master[$index]{file} = $file;
  5694.         $Master[$index]{duration} = $duration;
  5695.         $Master[$index]{size} = -s "$dir/$file";
  5696.         $index++;
  5697.     }
  5698. }
  5699.  
  5700.  
  5701. # Load_Etc_Services - load /etc/services lookup table into memory,
  5702. #           into %Services_TCP and %Services_UDP.
  5703. #
  5704. sub Load_Etc_Services {
  5705.     my ($line,$name,$service);
  5706.  
  5707.     ### Hardcoded
  5708.     %Services_TCP = (20 => "ftp-data",
  5709.                  21 => "ftp",
  5710.                  23 => "telnet",
  5711.                  25 => "smtp",
  5712.                  80 => "web",
  5713.                  109 => "pop2",
  5714.                  110 => "pop3",
  5715.                  143 => "imap",
  5716.                  513 => "login",
  5717.                  514 => "shell",
  5718.                  3128 => "web",
  5719.                  4110 => "irc4110",
  5720.                  5000 => "irc5000",
  5721.                  6000 => "X11",
  5722.                  6660 => "irc",
  5723.                  6665 => "irc",
  5724.                  6666 => "irc",
  5725.                  6667 => "irc",
  5726.                  6668 => "irc",
  5727.                  6669 => "irc",
  5728.                  7000 => "irc7000",
  5729.                  8000 => "irc8000",
  5730.                  8080 => "web",
  5731.                  9000 => "irc9000");
  5732.     # non standard IRC ports include the number in their name
  5733.  
  5734.     foreach (@Save_As_X11_Playback_Ports) {
  5735.         $Services_TCP{$_} = "X11";
  5736.     }
  5737.  
  5738.     foreach (@Save_As_VNC_Playback_Ports) {
  5739.         $Services_TCP{$_} = "VNC";
  5740.     }
  5741.  
  5742.     %Services_UDP = (53 => "dns");
  5743.                                        
  5744.     ### File input
  5745.     open(SERVICES,"/etc/services") || return;
  5746.     while ($line = <SERVICES>) {
  5747.         next if $line =~ /^#|^\s*$/;    # skip comments, blank lines.
  5748.         if ($line =~ /\d\/tcp/) {
  5749.             $is_tcp = 1;
  5750.         } else {
  5751.             $is_tcp = 0;
  5752.         }
  5753.         $line =~ s:/.*::;
  5754.         ($name,$port) = split(' ',$line);
  5755.         if ($is_tcp) {
  5756.             $Services_TCP{$port} = $name;
  5757.         } else {
  5758.             $Services_UDP{$port} = $name;
  5759.         }
  5760.            
  5761.     }
  5762.     close SERVICES;
  5763. }
  5764.  
  5765.  
  5766. # Set_IP_Protocols - Set a lookup hash for IP Protocols to names.
  5767. #       RFC790, RFC1700.
  5768. #
  5769. sub Set_IP_Protocols {
  5770.     %IP_Protocols = (0 => "Reserved",
  5771.             1 => "ICMP",
  5772.             2 => "Unassigned",
  5773.             3 => "Gateway-to-Gateway",
  5774.             4 => "CCMC Gateway Monitoring Message",
  5775.             5 => "ST",
  5776.             6 => "TCP",
  5777.             7 => "UCL",
  5778.             8 => "Unassigned",
  5779.             9 => "Secure",
  5780.             10 => "BBN RCC Monitoring",
  5781.             11 => "NVP",
  5782.             12 => "PUP",
  5783.             13 => "Pluribus",
  5784.             14 => "Telenet",
  5785.             15 => "XNET",
  5786.             16 => "Chaos",
  5787.             17 => "UDP",
  5788.             18 => "Multiplexing",
  5789.             19 => "DCN",
  5790.             20 => "TAC Monitoring",
  5791.             37 => "DDP",
  5792.             41 => "SIP",
  5793.             42 => "SDRP",
  5794.             44 => "IPv6 Frag",
  5795.             50 => "SIPP-ESP",
  5796.             51 => "SIPP-AH",
  5797.             53 => "SWIPE",
  5798.             50 => "SDRP",
  5799.             58 => "ICMPv6",
  5800.             88 => "IGRP",
  5801.             94 => "IPIP"
  5802.     );
  5803. }
  5804.  
  5805. # Set_ICMP_Types - Set a lookup hash for ICMP Types. RFC792.
  5806. #
  5807. sub Set_ICMP_Types {
  5808.     %ICMP_Types = (0 => "Echo Reply",
  5809.             3 => "Destination Unreachable",
  5810.             4 => "Source Quench",
  5811.             5 => "Redirect",
  5812.             8 => "Echo",
  5813.             11 => "Time Exceeded",
  5814.             12 => "Parameter Problem",
  5815.             13 => "Timestamp",
  5816.             14 => "Timestamp Reply",
  5817.             15 => "Information Request",
  5818.             16 => "Information Reply",
  5819.             128 => "Echo",
  5820.             129 => "Echo Reply",
  5821.             135 => "Neighbor solicitation",
  5822.             136 => "Neighbor advertisement"
  5823.     );
  5824. }
  5825.  
  5826. # Set_Result_Names - Set a lookup hash for squid result codes.
  5827. #       (This needs some fine tuning).
  5828. #
  5829. sub Set_Result_Names {
  5830.     %Result_Names = ("" => "TCP_MISS",
  5831.             000 => "TCP_MISS",
  5832.             200 => "TCP_HIT",
  5833.             302 => "TCP_HIT",
  5834.             304 => "TCP_REFRESH_HIT",
  5835.             404 => "TCP_NEGATIVE_HIT"
  5836.     );
  5837. }
  5838.  
  5839. # Set_X11_Codes - creates a lookup hash needed for X11 transposing.
  5840. #
  5841. sub Set_X11_Codes {
  5842.     #
  5843.     #  This has a row per X11 code, the row describing the 16 bit
  5844.     #  words that make up the values. "1" means resource id.
  5845.     #  (some values are 8 bit, but are fortunately padded).
  5846.     #
  5847.  
  5848.     @X11_Codes = (
  5849. [ 0 ],  # X_Error entry
  5850. [ 0, 2, 2, 0, 0, 0, 1, 0,4,4,4,4,4,4,4,4,4,4,4,4 ], # X_CreateWindow 1
  5851. [ 0, 1, 0 ], # X_ChangeWindowAttributes
  5852. [ 0, 1 ], # X_GetWindowAttributes
  5853. [ 0 ], # X_DestroyWindow?
  5854. [ 0 ], # X_DestroySubwindows?
  5855. [ 0, 1 ], # X_ChangeSaveSet
  5856. [ 0, 1, 1, 0 ], # X_ReparentWindow
  5857. [ 0, 1 ], # X_MapWindow
  5858. [ 0, 1 ], # X_MapSubwindows
  5859. [ 0, 1 ], # X_UnmapWindow 10
  5860. [ 0, 1 ], # X_UnmapSubwindows
  5861. [ 0, 1, 0, 4,4,4,4,4,4,4,4,4,4,4,4 ], # X_ConfigureWindow
  5862. [ 0, 1 ], # X_CirculateWindow
  5863. [ 0, 2 ], # X_GetGeometry
  5864. [ 0, 1 ], # X_QueryTree
  5865. [ 0, 1 ], # X_InternAtom (? else 0,0)
  5866. [ 0 ], # X_GetAtomName?
  5867. [ 0, 1, 0, 0, 1, 0 ], # X_ChangeProperty (? else 0,1,0,0,0,0)
  5868. [ 0, 1, 0 ], # X_DeleteProperty
  5869. [ 0, 2, 0, 0, 0, 0 ], # X_GetProperty 20
  5870. [ 0 ], # X_ListProperties?
  5871. [ 0, 1, 0, 0 ], # X_SetSelectionOwner
  5872. [ 0 ], # X_GetSelectionOwner
  5873. [ 0, 1, 0, 0, 0, 0 ], # X_ConvertSelection
  5874. [ 0, 1, 0 ], # X_SendEvent
  5875. [ 0, 1, 0, 1, 0, 0 ], # X_GrabPointer
  5876. [ 0, 1, 0 ], # X_UngrabPointer?
  5877. [ 0, 1, 0, 1, 0, 0 ], # X_GrabButton
  5878. [ 0, 1, 0 ], # X_UngrabButton
  5879. [ 0, 1, 0, 0 ], # X_ChangeActivePointerGrab 30
  5880. [ 0, 1, 0, 0 ], # X_GrabKeyboard
  5881. [ 0, 1, 0 ], # X_UngrabKeyboard?
  5882. [ 0, 1, 0, 0 ], # X_GrabKey
  5883. [ 0, 1, 0 ], # X_UngrabKey
  5884. [ 0, 0, 0 ], # X_AllowEvents
  5885. [ 0 ], # X_GrabServer?
  5886. [ 0 ], # X_UngrabServer?
  5887. [ 0 ], # X_QueryPointer?
  5888. [ 0, 1, 0, 0 ], # X_GetMotionEvents
  5889. [ 0, 1, 1, 0 ], # X_TranslateCoords 40
  5890. [ 0, 1, 1, 0, 0, 0 ], # X_WarpPointer
  5891. [ 0, 1, 0 ], # X_SetInputFocus
  5892. [ 0 ], # X_GetInputFocus?
  5893. [ 0 ], # X_QueryKeymap?
  5894. [ 0, 1, 0 ], # X_OpenFont
  5895. [ 0, 1 ], # X_CloseFont
  5896. [ 0, 1 ], # X_QueryFont
  5897. [ 0, 1 ], # X_QueryTextExtents
  5898. [ 0, 0 ], # X_ListFonts
  5899. [ 0, 0 ], # X_ListFontsWithInfo 50
  5900. [ 0, 0 ], # X_SetFontPath
  5901. [ 0 ], # X_GetFontPath?
  5902. [ 0, 1, 2, 0 ], # X_CreatePixmap
  5903. [ 0 ], # X_FreePixmap?
  5904. [ 0, 1, 2, 0, 4,4,4,4,4,4,4,4,4,4,4,4 ], # X_CreateGC ?(else 0,1,1,0)
  5905. [ 0, 1, 0, 4,4,4,4,4,4,4,4,4,4,4,4 ], # X_ChangeGC
  5906. [ 0, 1, 1, 0, 4,4,4,4,4,4,4,4,4,4,4,4 ], # X_CopyGC
  5907. [ 0, 1, 0 ], # X_SetDashes
  5908. [ 0, 1, 0 ], # X_SetClipRectangles
  5909. [ 0, 1 ], # X_FreeGC? 60
  5910. [ 0, 1, 0, 0 ], # X_ClearArea
  5911. [ 0, 2, 2, 1, 0, 0, 0 ], # X_CopyArea
  5912. [ 0, 2, 2, 1, 0, 0, 0, 0 ], # X_CopyPlane
  5913. [ 0, 2, 1 ], # X_PolyPoint
  5914. [ 0, 2, 1 ], # X_PolyLine
  5915. [ 0, 2, 1 ], # X_PolySegment
  5916. [ 0, 2, 1 ], # X_PolyRectangle
  5917. [ 0, 2, 1 ], # X_PolyArc
  5918. [ 0, 2, 1, 0 ], # X_FillPoly
  5919. [ 0, 2, 1 ], # X_PolyFillRectangle 70
  5920. [ 0, 2, 1 ], # X_PolyFillArc
  5921. [ 0, 2, 1, 0, 0, 0 ], # X_PutImage
  5922. [ 0, 2, 0, 0, 0 ], # X_GetImage
  5923. [ 0, 2, 1, 0 ], # X_PolyText8
  5924. [ 0, 2, 1, 0 ], # X_PolyText16
  5925. [ 0, 2, 1, 0 ], # X_ImageText8
  5926. [ 0, 2, 1, 0 ], # X_ImageText16
  5927. [ 0, 3, 1, 1 ], # X_CreateColormap
  5928. [ 0 ], # X_FreeColormap?
  5929. [ 0, 3, 3 ], # X_CopyColormapAndFree 80
  5930. [ 0 ], # X_InstallColormap?
  5931. [ 0 ], # X_UninstallColormap?
  5932. [ 0 ], # X_ListInstalledColormaps?
  5933. [ 0, 3, 0, 0 ], # X_AllocColor
  5934. [ 0, 3, 0 ], # X_AllocNamedColor
  5935. [ 0, 3, 0 ], # X_AllocColorCells
  5936. [ 0, 3, 0, 0 ], # X_AllocColorPlanes
  5937. [ 0, 3, 0 ], # X_FreeColors
  5938. [ 0, 3 ], # X_StoreColors
  5939. [ 0, 3, 0, 0 ], # X_StoreNamedColor 90
  5940. [ 0, 3 ], # X_QueryColors
  5941. [ 0, 3, 0 ], # X_LookupColor
  5942. [ 0, 1, 1, 1, 0, 0, 0, 0 ], # X_CreateCursor
  5943. [ 0, 1, 1, 1, 0, 0, 0, 0 ], # X_CreateGlyphCursor
  5944. [ 0 ], # X_FreeCursor?
  5945. [ 0, 1, 0, 0, 0 ], # X_RecolorCursor
  5946. [ 0, 2, 0 ], # X_QueryBestSize
  5947. [ 0, 1 ], # X_QueryExtension (? else 0,0)
  5948. [ 0, 0, 0 ], # X_ListExtensions?
  5949. [ 0, 1, 0 ], # X_ChangeKeyboardMapping 100
  5950. [ 0, 1, 0 ], # X_GetKeyboardMapping
  5951. [ 0, 0, 4,4,4,4,4,4,4,4,4,4,4,4 ], # X_ChangeKeyboardControl
  5952. [ 0, 0, 0 ], # X_GetKeyboardControl?
  5953. [ 0 ], # X_Bell
  5954. [ 0, 0, 0 ], # X_ChangePointerControl
  5955. [ 0, 0, 0 ], # X_GetPointerControl?
  5956. [ 0, 0, 0 ], # X_SetScreenSaver
  5957. [ 0, 0, 0 ], # X_GetScreenSaver?
  5958. [ 0, 0 ], # X_ChangeHosts
  5959. [ 0 ], # X_ListHosts 110
  5960. [ 0 ], # X_SetAccessControl
  5961. [ 0 ], # X_SetCloseDownMode
  5962. [ 0, 0, 0 ], # X_KillClient?
  5963. [ 0, 1, 0 ], # X_RotateProperties
  5964. [ 0 ], # X_ForceScreenSaver
  5965. [ 0 ], # X_SetPointerMapping
  5966. [ 0, 0, 0 ], # X_GetPointerMapping?
  5967. [ 0 ], # X_SetModifierMapping
  5968. [ 0, 0, 0 ], # X_GetModifierMapping?
  5969. [ 0 ], # undef 120
  5970. [ 0 ], # undef
  5971. [ 0 ], # undef
  5972. [ 0 ], # undef
  5973. [ 0 ], # undef
  5974. [ 0 ], # undef
  5975. [ 0 ], # undef
  5976. [ 0, 0, 0 ] # X_NoOperation 127
  5977.     );
  5978.  
  5979. }
  5980.  
  5981. # Set_X11_KeyCodes - creates a lookup hash of X11 Key codes needed
  5982. #   to generate coloured 2-way HTML X11 reports.
  5983. #
  5984. sub Set_X11_KeyCodes {
  5985.     my ($junk,$code,$char1,$char2,$line,
  5986.      $sun_xmodmap_pke,$linux_xmodmap_pke);
  5987.     my %Alias;
  5988.  
  5989.     #
  5990.     # These are generated using "xmodmap -pke" (and trimmed a little).
  5991.     #
  5992.     $sun_xmodmap_pke = <<END;
  5993. keycode   8 = Control_L
  5994. keycode   9 = Control_R
  5995. keycode  10 = Shift_L
  5996. keycode  11 = Shift_R
  5997. keycode  12 = Meta_L
  5998. keycode  13 = Meta_R
  5999. keycode  14 = Alt_L
  6000. keycode  15 = Alt_R
  6001. keycode  16 = space
  6002. keycode  17 = 0 parenright
  6003. keycode  18 = 1 exclam
  6004. keycode  19 = 2 at
  6005. keycode  20 = 3 numbersign
  6006. keycode  21 = 4 dollar
  6007. keycode  22 = 5 percent
  6008. keycode  23 = 6 asciicircum
  6009. keycode  24 = 7 ampersand
  6010. keycode  25 = 8 asterisk
  6011. keycode  26 = 9 parenleft
  6012. keycode  27 = minus underscore
  6013. keycode  28 = equal plus
  6014. keycode  29 = bracketleft braceleft
  6015. keycode  30 = bracketright braceright
  6016. keycode  31 = semicolon colon
  6017. keycode  32 = apostrophe quotedbl
  6018. keycode  33 = grave asciitilde
  6019. keycode  34 = comma less
  6020. keycode  35 = period greater
  6021. keycode  36 = slash question
  6022. keycode  37 = backslash bar
  6023. keycode  38 = a A
  6024. keycode  39 = b B
  6025. keycode  40 = c C
  6026. keycode  41 = d D
  6027. keycode  42 = e E
  6028. keycode  43 = f F
  6029. keycode  44 = g G
  6030. keycode  45 = h H
  6031. keycode  46 = i I
  6032. keycode  47 = j J
  6033. keycode  48 = k K
  6034. keycode  49 = l L
  6035. keycode  50 = m M
  6036. keycode  51 = n N
  6037. keycode  52 = o O
  6038. keycode  53 = p P
  6039. keycode  54 = q Q
  6040. keycode  55 = r R
  6041. keycode  56 = s S
  6042. keycode  57 = t T
  6043. keycode  58 = u U
  6044. keycode  59 = v V
  6045. keycode  60 = w W
  6046. keycode  61 = x X
  6047. keycode  62 = y Y
  6048. keycode  63 = z Z
  6049. keycode  64 = BackSpace
  6050. keycode  65 = Return
  6051. keycode  66 = Tab
  6052. keycode  67 = Escape
  6053. keycode  68 = Delete
  6054. END
  6055.  
  6056.     #
  6057.     # These are generated using "xmodmap -pke" (and trimmed a little).
  6058.     #
  6059.     $linux_xmodmap_pke = <<END;
  6060. keycode   8 =
  6061. keycode   9 = Escape
  6062. keycode  10 = 1 exclam
  6063. keycode  11 = 2 at
  6064. keycode  12 = 3 numbersign
  6065. keycode  13 = 4 dollar
  6066. keycode  14 = 5 percent
  6067. keycode  15 = 6 asciicircum
  6068. keycode  16 = 7 ampersand
  6069. keycode  17 = 8 asterisk
  6070. keycode  18 = 9 parenleft
  6071. keycode  19 = 0 parenright
  6072. keycode  20 = minus underscore
  6073. keycode  21 = equal plus
  6074. keycode  22 = BackSpace Terminate_Server
  6075. keycode  23 = Tab ISO_Left_Tab
  6076. keycode  24 = q Q
  6077. keycode  25 = w W
  6078. keycode  26 = e E
  6079. keycode  27 = r R
  6080. keycode  28 = t T
  6081. keycode  29 = y Y
  6082. keycode  30 = u U
  6083. keycode  31 = i I
  6084. keycode  32 = o O
  6085. keycode  33 = p P
  6086. keycode  34 = bracketleft braceleft
  6087. keycode  35 = bracketright braceright
  6088. keycode  36 = Return
  6089. keycode  37 = Control_L
  6090. keycode  38 = a A
  6091. keycode  39 = s S
  6092. keycode  40 = d D
  6093. keycode  41 = f F
  6094. keycode  42 = g G
  6095. keycode  43 = h H
  6096. keycode  44 = j J
  6097. keycode  45 = k K
  6098. keycode  46 = l L
  6099. keycode  47 = semicolon colon
  6100. keycode  48 = apostrophe quotedbl
  6101. keycode  49 = grave asciitilde
  6102. keycode  50 = Shift_L
  6103. keycode  51 = backslash bar
  6104. keycode  52 = z Z
  6105. keycode  53 = x X
  6106. keycode  54 = c C
  6107. keycode  55 = v V
  6108. keycode  56 = b B
  6109. keycode  57 = n N
  6110. keycode  58 = m M
  6111. keycode  59 = comma less
  6112. keycode  60 = period greater
  6113. keycode  61 = slash question
  6114. keycode  62 = Shift_R
  6115. keycode  64 = Alt_L Meta_L
  6116. keycode  65 = space
  6117. keycode  94 = less greater
  6118. END
  6119.     %Alias = qw(exclam ! at @ dollar $ percent %
  6120.      asciicircum ^ ampersand & asterisk * minus - underscore _
  6121.      equal = plus + bracketleft [ bracketright ] braceleft {
  6122.      braceright } semicolon ; colon : apostrophe ' quotedbl "
  6123.      grave ` asciitilde ~ backslash \ bar | less <
  6124.      period . greater > slash / question ?);
  6125.  
  6126.     # naughty chatacrers (some of these generate warnings)
  6127.     @Alias{"parenleft","parenright","space"} = ("(",")"," ");
  6128.     @Alias{"Tab","Return","numbersign","comma"} = ("\t","\n","#",",");
  6129.    
  6130.  
  6131.     #
  6132.     #  Populate KeyCode aliase
  6133.     #
  6134.     foreach $line (split(/\n/,$sun_xmodmap_pke)) {
  6135.         ($junk,$code,$junk,$char1,$char2) = split(' ',$line);
  6136.         if (defined $Alias{$char1}) { $char1 = $Alias{$char1}; }
  6137.         if (defined $Alias{$char2}) { $char2 = $Alias{$char2}; }
  6138.         if (length($char1) > 1) { $char1 = "."; }
  6139.         if (length($char2) > 1) { $char2 = "."; }
  6140.         $KeyCode{sun}{0}{$code} = $char1;
  6141.         $KeyCode{sun}{1}{$code} = $char2;
  6142.     }
  6143.     foreach $line (split(/\n/,$linux_xmodmap_pke)) {
  6144.         ($junk,$code,$junk,$char1,$char2) = split(' ',$line);
  6145.         if (defined $Alias{$char1}) { $char1 = $Alias{$char1}; }
  6146.         if (defined $Alias{$char2}) { $char2 = $Alias{$char2}; }
  6147.         if (length($char1) > 1) { $char1 = "."; }
  6148.         if (length($char2) > 1) { $char2 = "."; }
  6149.         $KeyCode{linux}{0}{$code} = $char1;
  6150.         $KeyCode{linux}{1}{$code} = $char2;
  6151.     }
  6152.  
  6153. }
  6154.  
  6155.  
  6156. # Set_VNC_Codes - set globals for VNC.
  6157. #
  6158. sub Set_VNC_Codes  {
  6159.  
  6160.     ### set client code to request size hash.
  6161.     %VNC_Code_Size = ( 0 => 20,
  6162.                1 => 6,
  6163.                2 => 4,
  6164.                3 => 10,
  6165.                4 => 8,
  6166.                5 => 6,
  6167.                6 => 8 );
  6168.  
  6169.     ### Some essential keysyms
  6170.     $KeyCode{vnc}{0}{"\010"} = "\b";
  6171.     $KeyCode{vnc}{0}{"\011"} = "\t";
  6172.     $KeyCode{vnc}{0}{"\015"} = "\n";
  6173.  
  6174. }
  6175.    
  6176.  
  6177.  
  6178. # Touch_Vars - This is stops perl -w warnings about vars used only once.
  6179. #       Part of my todo list is to cull this list.
  6180. #  
  6181. #
  6182. sub Touch_Vars {
  6183.     #
  6184.     #  Perl < 5.6 code
  6185.     #
  6186.     #use vars qw($ip_ttl $udp_checksum $ip_ident $tcp_length_data
  6187.     #$ip_tos $tcp_options $opt_A $opt_D $tcp_header_rest $opt_J
  6188.     #$opt_P $opt_U $opt_X $opt_e $opt_h $opt_i $pad $opt_j
  6189.     #$snoop_length_orig $http_header $opt_p $opt_q $opt_r
  6190.     #$header_rest $tcp_ack $ether_dest $ether_src $skip
  6191.     #$ip_length $udp_length $ip_options $ip_checksum
  6192.     #$opt_b $opt_B $opt_l $opt_L $ip_rest $ip_hop $ip_reserved
  6193.     #$ip_flow $icmp_rest $opt_f $opt_z);
  6194.     #
  6195.     #  Perl 5.6 code
  6196.     #
  6197.     #our ($ip_ttl,$udp_checksum,$ip_ident,$tcp_length_data,
  6198.     #$ip_tos,$tcp_options,$opt_A,$opt_D,$tcp_header_rest,$opt_J,
  6199.     #$opt_P,$opt_U,$opt_X,$opt_e,$opt_h,$opt_i,$pad,$opt_j,
  6200.     #$snoop_length_orig,$http_header,$opt_p,$opt_q,$opt_r,
  6201.     #$header_rest,$tcp_ack,$ether_dest,$ether_src,$skip,
  6202.     #$ip_length,$udp_length,$ip_options,$ip_checksum,
  6203.     #$opt_b,$opt_B,$opt_l,$opt_L,$ip_rest,$ip_hop,$ip_reserved,
  6204.     #$ip_flow,$icmp_rest,$opt_f,$opt_z);
  6205.     #
  6206.     #  Perl < 5.6 and 5.6 code (but not elegant)
  6207.     #
  6208.     @Once_is_okay = ($ip_ttl,$udp_checksum,$ip_ident,$tcp_length_data,
  6209.     $ip_tos,$tcp_options,$opt_A,$opt_D,$tcp_header_rest,$opt_J,
  6210.     $opt_P,$opt_U,$opt_X,$opt_e,$opt_h,$opt_i,$pad,$opt_j,
  6211.     $snoop_length_orig,$http_header,$opt_p,$opt_q,$opt_r,
  6212.     $header_rest,$tcp_ack,$ether_dest,$ether_src,$skip,
  6213.     $ip_length,$udp_length,$ip_options,$ip_checksum,$tcp_rst,$tcp_fin,
  6214.     $opt_b,$opt_B,$opt_l,$opt_L,$ip_rest,$ip_hop,$ip_reserved,
  6215.     $ip_flow,$icmp_rest,$opt_f,$opt_z,$junk1,$opt_H,$opt_I,$opt_R);
  6216. }
  6217.  
  6218.  
  6219. # Check_Command - check which is the network sniffing command and save
  6220. #       it to $command.
  6221. #
  6222. sub Check_Command {
  6223.    
  6224.     #
  6225.     #  Check which OS we are on, die if it looks incompatible
  6226.     #
  6227.     if ($^O eq "linux") {
  6228.         #
  6229.         #  The "-s9999" tells tcpdump to keep a packet up to this
  6230.         #  size, otherwise the default is 68 bytes. Some versions of
  6231.         #  tcpdump allow using "-s0" for unlimited.
  6232.         #
  6233.         $command = "tcpdump -s9999 -w";
  6234.     } elsif ($^O eq "solaris") {
  6235.         $command = "snoop -o";
  6236.     } else {
  6237.         die "ERROR54: Can't find the sniffer command for \"$^O\".\n" .
  6238.          "\t Please use log mode instead.\n";
  6239.     }
  6240.  
  6241.     #
  6242.     #  Check username
  6243.     #
  6244.     if ($ENV{LOGNAME} ne "root") {
  6245.         print STDERR "WARNING: Are you root? If not, this probably "
  6246.          . "won't work. Trying anyway...\n";
  6247.     }
  6248. }
  6249.  
  6250.  
  6251. # Process_Command_Line_Arguments - this process the command line arguments
  6252. #   and sets various globals which are kept in %Arg. It also prints
  6253. #   usage and exists if need be.
  6254. #
  6255. sub Process_Command_Line_Arguments {
  6256.     my $result;
  6257.  
  6258.     #
  6259.     #  Process Global Defaults into %Arg
  6260.     #
  6261.     foreach (@Save_As_HTML_TCP_Ports) {
  6262.         $Arg{Save_As_TCP_HTML}{$_} = 1;
  6263.     }
  6264.     foreach (@Save_As_HTML_UDP_Ports) {
  6265.         $Arg{Save_As_UDP_HTML}{$_} = 1;
  6266.     }
  6267.     foreach (@Save_As_TCP_Playback_Ports) {
  6268.         $Arg{Save_As_TCP_Playback}{$_} = 1;
  6269.     }
  6270.     foreach (@Save_As_UDP_Playback_Ports) {
  6271.         $Arg{Save_As_UDP_Playback}{$_} = 1;
  6272.     }
  6273.     foreach (@Save_As_X11_Playback_Ports) {
  6274.         $Arg{Save_As_X11_Playback}{$_} = 1;
  6275.     }
  6276.     foreach (@Save_As_HTML_X11_Ports) {
  6277.         $Arg{Save_As_X11_HTML}{$_} = 1;
  6278.     }
  6279.     foreach (@Save_As_VNC_Playback_Ports) {
  6280.         $Arg{Save_As_VNC_Playback}{$_} = 1;
  6281.     }
  6282.  
  6283.     if (defined $ARGV[0]) {
  6284.         ### Dump full help if asked
  6285.         &Usage_Full if $ARGV[0] eq "--help";
  6286.    
  6287.         ### Dump massive help if asked
  6288.         &Usage_Massive if $ARGV[0] eq "--help2";
  6289.     }
  6290.  
  6291.     #
  6292.     #  Command Line Defaults
  6293.     #
  6294.     $Arg{output_raw} = 0;
  6295.     $Arg{output_hex} = 0;
  6296.     $Arg{output_UDP} = 1;
  6297.     $Arg{output_TCP} = 1;
  6298.     $Arg{output_ICMP} = 1;
  6299.     $Arg{output_info} = 0;
  6300.     $Arg{output_apps} = 1;
  6301.     $Arg{output_index} = 1;
  6302.     $Arg{keydata} = 0;
  6303.     $Arg{debug} = 0;
  6304.  
  6305.     #
  6306.     #  Check correct switches were used
  6307.     #
  6308.     Getopt::Long::Configure ("bundling");
  6309.     $result = GetOptions (
  6310.                 "application!" => \$opt_a,
  6311.                 "a" => \$opt_a,
  6312.                 "e|everything" => \$opt_e,
  6313.                 "h" => \$opt_h,
  6314.                 "info!" => \$opt_i,
  6315.                 "i" => \$opt_i,
  6316.                 "q|quiet" => \$opt_q,
  6317.                 "raw!" => \$opt_r,
  6318.                 "r" => \$opt_r,
  6319.                 "v|verbose" => \$opt_v,
  6320.                 "index!" => \$opt_x,
  6321.                 "x" => \$opt_x,
  6322.                 "A" => \$opt_A,
  6323.                 "H|hex" => \$opt_H,
  6324.                 "I" => \$opt_I,
  6325.                 "R" => \$opt_R,
  6326.                 "U|noudp" => \$opt_U,
  6327.                 "T|notcp" => \$opt_T,
  6328.                 "Y|noicmp" => \$opt_Y,
  6329.                 "X" => \$opt_X,
  6330.                 "D|dir=s" => \$opt_D,
  6331.                 "b|playtcp=s" => \$opt_b,
  6332.                 "B|playudp=s" => \$opt_B,
  6333.                 "l|htmltcp=s" => \$opt_l,
  6334.                 "L|htmludp=s" => \$opt_L,
  6335.                 "m|min=s" => \$opt_m,
  6336.                 "M|max=s" => \$opt_M,
  6337.                 "o|sort=s" => \$opt_o,
  6338.                 "p|port=s" => \$opt_p,
  6339.                 "P|noport=s" => \$opt_P,
  6340.                 "j|ipaddr=s" => \$opt_j,
  6341.                 "J|noipaddr=s" => \$opt_J,
  6342.                 "s|runonce=s" => \$opt_s,
  6343.                 "S|runmany=s" => \$opt_S,
  6344.                 "z|runredo" => \$opt_z,
  6345.                 "f|filter=s" => \$opt_f,
  6346.                 "k|keydata" => \$opt_k,
  6347.                 "debug" => \$opt_debug,
  6348.                 "bench" => \$opt_bench
  6349.      );
  6350.    
  6351.     #
  6352.     #  Process switches
  6353.     #
  6354.     &Usage() if ($opt_h || ! $result);
  6355.     $Arg{output_raw} = 1 if $opt_r or $opt_v;
  6356.     $Arg{output_hex} = 1 if $opt_H or $opt_e;
  6357.     $Arg{output_info} = 1 if $opt_i or $opt_v;
  6358.     $Arg{quiet} = 1 if $opt_q;
  6359.     $Arg{output_UDP} = 0 if $opt_U;
  6360.     $Arg{output_TCP} = 0 if $opt_T;
  6361.     $Arg{output_ICMP} = 0 if $opt_Y;
  6362.     $Arg{output_apps} = 0 if ($opt_A || (defined $opt_a && $opt_a eq "0"));
  6363.     $Arg{output_index} = 0 if ($opt_X || (defined $opt_x && $opt_x eq "0"));
  6364.     $Arg{output_allhtml} = 1 if $opt_e;
  6365.     my $extra_TCPplayback = $opt_b;
  6366.     my $extra_UDPplayback = $opt_B;
  6367.     my $extra_TCPhtml = $opt_l;
  6368.     my $extra_UDPhtml = $opt_L;
  6369.     my $ports_accepted = $opt_p;
  6370.     my $ports_rejected = $opt_P;
  6371.     my $ips_accepted = $opt_j;
  6372.     my $ips_rejected = $opt_J;
  6373.     $Arg{output_dir} = $opt_D;
  6374.     $Arg{filter} = $opt_f || "";
  6375.     $Arg{minbytes} = 0;
  6376.     $Arg{maxbytes} = 0;
  6377.     $Arg{sort} = "time";
  6378.     $Arg{keydata} = 1 if $opt_k;
  6379.     $Arg{debug} = 1 if $opt_debug;
  6380.     $Arg{bench} = 1 if $opt_bench;
  6381.  
  6382.     #
  6383.     #  Check for min/max bytes
  6384.     #
  6385.     if (defined $opt_m) {
  6386.         if ($opt_m =~ /k$/) {
  6387.             $opt_m =~ s/k$//;
  6388.             $opt_m *= 1024;
  6389.         }
  6390.         $Arg{minbytes} = $opt_m;
  6391.     }
  6392.     if (defined $opt_M) {
  6393.         if ($opt_M =~ /k$/) {
  6394.             $opt_M =~ s/k$//;
  6395.             $opt_M *= 1024;
  6396.         }
  6397.         $Arg{maxbytes} = $opt_M;
  6398.     }
  6399.  
  6400.     #
  6401.     #  Check for sort option
  6402.     #
  6403.     if (defined $opt_o) {
  6404.         if ($opt_o !~ /^(time|size|type|ip)$/) {
  6405.             print STDERR "ERROR55: Sort must be \"time\", " .
  6406.              "\"size\", \"type\" or \"ip\".\n";
  6407.             &Usage();
  6408.         }
  6409.         $Arg{sort} = $opt_o;
  6410.     }
  6411.    
  6412.     #
  6413.     #  Check for standalone redo mode
  6414.     #
  6415.     if (defined $opt_z) {
  6416.         $Arg{redo} = 1;
  6417.         if (defined $Arg{output_dir}) {
  6418.             # bad luck
  6419.             die "ERROR56: Can't use an output dir "
  6420.              . "$Arg{output_dir} in redo mode.\n\n";
  6421.         }
  6422.     }
  6423.  
  6424.     #
  6425.     #  Check for standalone mode
  6426.     #
  6427.     elsif (defined $opt_s || defined $opt_S) {
  6428.         $Arg{standalone} = 1;
  6429.         if (defined $opt_s) {
  6430.             if ($opt_s =~ /,/) {
  6431.                 die "ERROR57: Unexpected comma found in " .
  6432.                  "\"-s$opt_s\" (did you mean \"-S$opt_s\"?)\n";
  6433.             }
  6434.             $Arg{mins} = $opt_s;
  6435.             $Arg{count} = 1;
  6436.         } elsif (defined $opt_S) {
  6437.             my ($mins,$count) = split(/,/,$opt_S);
  6438.             $Arg{mins} = $mins;
  6439.             ### -1 means endless
  6440.             $Arg{count} = $count || -1;
  6441.         }
  6442.     }
  6443.  
  6444.     #
  6445.     #  This is normal mode
  6446.     #  
  6447.     else {
  6448.         $Arg{normal} = 1;
  6449.     }
  6450.            
  6451.     #                    
  6452.     #  Build accepted or rejected port list as %Arg{Port_Accepted},...
  6453.     #
  6454.     if (defined $ports_accepted) {
  6455.         $Arg{port_accept} = 1;
  6456.         foreach $port (split(/,/,$ports_accepted)) {
  6457.             $Arg{Port_Accepted}{$port} = 1;
  6458.         }
  6459.     }
  6460.     if (defined $ports_rejected) {
  6461.         $Arg{port_reject} = 1;
  6462.         foreach $port (split(/,/,$ports_rejected)) {
  6463.             $Arg{Port_Rejected}{$port} = 1;
  6464.         }
  6465.     }
  6466.    
  6467.     #
  6468.     #  Build accepted or rejected IP list as %Arg{IP_Accepted},...
  6469.     #
  6470.     if (defined $ips_accepted) {
  6471.         $Arg{ip_accept} = 1;
  6472.         foreach $ip (split(/,/,$ips_accepted)) {
  6473.             $Arg{IP_Accepted}{$ip} = 1;
  6474.         }
  6475.     }
  6476.     if (defined $ips_rejected) {
  6477.         $Arg{ip_reject} = 1;
  6478.         foreach $ip (split(/,/,$ips_rejected)) {
  6479.             $Arg{IP_Rejected}{$ip} = 1;
  6480.         }
  6481.     }
  6482.    
  6483.     #
  6484.     #  Add extra ports to playback or HTML
  6485.     #
  6486.     if (defined $extra_TCPplayback) {
  6487.         foreach $port (split(/,/,$extra_TCPplayback)) {
  6488.             $Arg{Save_As_TCP_Playback}{$port} = 1;
  6489.         }
  6490.     }
  6491.     if (defined $extra_UDPplayback) {
  6492.         foreach $port (split(/,/,$extra_UDPplayback)) {
  6493.             $Arg{Save_As_UDP_Playback}{$port} = 1;
  6494.         }
  6495.     }
  6496.     if (defined $extra_TCPhtml) {
  6497.         foreach $port (split(/,/,$extra_TCPhtml)) {
  6498.             $Arg{Save_As_TCP_HTML}{$port} = 1;
  6499.         }
  6500.     }
  6501.     if (defined $extra_UDPhtml) {
  6502.         foreach $port (split(/,/,$extra_UDPhtml)) {
  6503.             $Arg{Save_As_UDP_HTML}{$port} = 1;
  6504.         }
  6505.     }
  6506.    
  6507.     #
  6508.     #  Check infile was provided, or print usage
  6509.     #
  6510.     if (! defined $ARGV[0] && ! ($Arg{standalone} || $Arg{redo})) {
  6511.         &Usage();
  6512.     }
  6513.     @{$Arg{infiles}} = @ARGV;
  6514. }
  6515.  
  6516.  
  6517. # Usage - print command usage and exit.
  6518. #
  6519. sub Usage {
  6520.         print "USAGE: chaosreader [-aehikqrvxAHIRTUXY] [-D dir]
  6521.                [-b port[,...]] [-B port[,...]]
  6522.                [-j IPaddr[,...]] [-J IPaddr[,...]]
  6523.                [-l port[,...]] [-L port[,...]] [-m bytes[k]]
  6524.                [-M bytes[k]] [-o \"time\"|\"size\"|\"type\"|\"ip\"]
  6525.                   [-p port[,...]] [-P port[,...]]
  6526.                infile [infile2 ...]
  6527.       chaosreader -s [mins] | -S [mins[,count]]  
  6528.                [-z] [-f 'filter']
  6529.   eg, chaosreader infile      # Create application session files, indexes
  6530.       chaosreader -v infile   # Verbose - Create ALL files
  6531.       chaosreader -i infile   # Create info files
  6532.       chaosreader -r infile   # Create raw files
  6533.       chaosreader -S 2,5      # Standalone - sniff network 5 times by 2 mins.
  6534.       chaosreader -h          # Print a brief help (this)
  6535.       chaosreader --help      # Print verbose help and version
  6536.       chaosreader --help2     # Print massive help\n\n";
  6537.         exit(0);
  6538. }
  6539.  
  6540.  
  6541. # Usage Full - print command usage and exit.
  6542. #
  6543. sub Usage_Full {
  6544.         print "Version 0.94, 01-May-2004
  6545.  
  6546. USAGE: chaosreader [-aehikqrvxAHIRTUXY] [-D dir]
  6547.                   [-b port[,...]] [-B port[,...]]
  6548.                   [-j IPaddr[,...]] [-J IPaddr[,...]]
  6549.                   [-l port[,...]] [-L port[,...]] [-m bytes[k]]
  6550.                   [-M bytes[k]] [-o \"time\"|\"size\"|\"type\"|\"ip\"]
  6551.                   [-p port[,...]] [-P port[,...]]
  6552.                   infile [infile2 ...]
  6553.  
  6554.       chaosreader -s [mins] | -S [mins[,count]]  
  6555.                [-z] [-f 'filter']
  6556.  
  6557.   chaosreader           # Create application session files, indexes
  6558.  
  6559.   -a, --application     # Create application session files (default)
  6560.   -e, --everything      # Create HTML 2-way & hex files for everything
  6561.   -h                    # Print a brief help
  6562.   --help                # Print verbose help (this) and version
  6563.   --help2               # Print massive help
  6564.   -i, --info            # Create info file
  6565.   -q, --quiet           # Quiet, no output to screen
  6566.   -r, --raw             # Create raw files
  6567.   -v, --verbose         # Verbose - Create ALL files .. (except -e)
  6568.   -x, --index           # Create index files (default)
  6569.   -A, --noapplication   # Exclude application session files
  6570.   -H, --hex             # Include hex dumps (slow)
  6571.   -I, --noinfo          # Exclude info files
  6572.   -R, --noraw           # Exclude raw files
  6573.   -T, --notcp           # Exclude TCP traffic
  6574.   -U, --noudp           # Exclude UDP traffic
  6575.   -Y, --noicmp          # Exclude ICMP traffic
  6576.   -X, --noindex         # Exclude index files
  6577.   -k, --keydata         # Create extra files for keystroke analysis
  6578.   -D dir    --dir dir        # Output all files to this directory
  6579.   -b 25,79  --playtcp 25,79  # replay these TCP ports as well (playback)
  6580.   -B 36,42  --playudp 36,42  # replay these UDP ports as well (playback)
  6581.   -l 7,79   --htmltcp 7,79   # Create HTML for these TCP ports as well
  6582.   -L 7,123  --htmludp 7,123  # Create HTML for these UDP ports as well
  6583.   -m 1k     --min 1k         # Min size of connection to save (\"k\" for Kb)
  6584.   -M 1024k  --max 1k         # Max size of connection to save (\"k\" for Kb)
  6585.   -o size   --sort size      # sort Order: time/size/type/ip (Default time)
  6586.   -p 21,23  --port 21,23     # Only examine these ports (TCP & UDP)
  6587.   -P 80,81  --noport 80,81   # Exclude these ports (TCP & UDP)
  6588.   -s 5      --runonce 5      # Standalone. Run tcpdump/snoop for 5 mins.
  6589.   -S 5,10   --runmany 5,10   # Standalone, many. 10 samples of 5 mins each.
  6590.   -S 5      --runmany 5      # Standalone, endless. 5 min samples forever.
  6591.   -z        --runredo        # Standalone, redo. Rereads last run's logs.
  6592.   -j 10.1.2.1  --ipaddr 10.1.2.1    # Only examine these IPs
  6593.   -J 10.1.2.1  --noipaddr 10.1.2.1  # Exclude these IPs
  6594.   -f 'port 7'  --filter 'port 7'    # With standalone, use this dump filter.
  6595.  
  6596. eg1,
  6597.     tcpdump -s9000 -w output1          # create tcpdump capture file
  6598.     chaosreader output1                # extract recognised sessions, or,
  6599.     chaosreader -ve output1            # gimme everything, or,
  6600.     chaosreader -p 20,21,23 output1    # only ftp and telnet...
  6601. eg2,
  6602.     snoop -o output1                   # create snoop capture file instead
  6603.     chaosreader output1                # extract recognised sessions...
  6604. eg3,
  6605.      chaosreader -S 2,5     # Standalone, sniff network 5 times for 2 mins
  6606.                 # each. View index.html for progress (or .text)
  6607. ";
  6608.         exit(0);
  6609. }
  6610.  
  6611.  
  6612. # Usage_Massive - print massive help. Actually strip it from the comments
  6613. #       at the top of the code.
  6614. #
  6615. sub Usage_Massive {
  6616.     open (MYSELF,"$0") || die "ERROR58: I can't see myself: $!\n";
  6617.     @Myself = <MYSELF>;
  6618.     close MYSELF;
  6619.  
  6620.     ### Print comment from top of code
  6621.     foreach $line (@Myself) {
  6622.         last if $line !~ /^#/;
  6623.         last if $line =~ /^# Todo:/;
  6624.         next if $line =~ m:^#!/usr/bin/perl:;
  6625.         $line =~ s/^#/ /;
  6626.         print $line;
  6627.     }
  6628.     print "\n";
  6629.  
  6630.         exit(0);
  6631. }
  6632.  
  6633.  
  6634.  
  6635. __END__
  6636.  
  6637. Reminders for myself
  6638. ====================
  6639. /s for multiline match
  6640.  
  6641.  
  6642. Comments style:
  6643.  
  6644. # Micro comment
  6645.  
  6646. ### Tiny Comment
  6647.  
  6648. #
  6649. #  Small comment
  6650. #
  6651.  
  6652. #
  6653. # --- Meduim Comment ---
  6654. #
  6655.  
  6656. #########################
  6657. # --- Large Comment ---
  6658. #
  6659.  
  6660. ########################
  6661. # --- Huge Comment --- #
  6662. ########################
  6663.  
  6664.  
  6665. Error message style
  6666. ===================
  6667.  
  6668. die "ERROR#: message: $!\n";
  6669.  
  6670.  
  6671.  
  6672. Data types,
  6673. ===========
  6674.     %Arg
  6675.         -> @infiles
  6676.         -> output_raw
  6677.         -> output_hex
  6678.         -> output_UDP
  6679.         -> output_info
  6680.         -> output_apps
  6681.         -> output_index
  6682.         -> output_allhtml
  6683.         -> Save_As_TCP_HTML
  6684.             -> $port
  6685.         -> Save_As_UDP_HTML
  6686.             -> $port
  6687.         -> Save_As_TCP_Playback
  6688.             -> $port
  6689.         -> Save_As_UDP_Playback
  6690.             -> $port
  6691.         -> Port_Accepted
  6692.             -> $port
  6693.         -> Port_Rejected
  6694.             -> $port
  6695.         -> ip_accept
  6696.         -> ip_reject
  6697.         -> IP_Accepted
  6698.             -> $ip
  6699.         -> IP_Rejected
  6700.             -> $ip
  6701.         -> debug
  6702.         -> standalone
  6703.         -> redo
  6704.         -> normal
  6705.         -> mins
  6706.         -> count
  6707.         -> output_dir
  6708.         -> quiet
  6709.         -> infile
  6710.         -> minbytes
  6711.         -> maxbytes
  6712.  
  6713.     %IP
  6714.         -> time
  6715.             -> $packet_time
  6716.                 -> ver
  6717.                 -> src
  6718.                 -> dest
  6719.                 -> protocol
  6720.                 -> frag
  6721.                     -> $ip_frag
  6722.                 -> fragged
  6723.                 -> drops
  6724.         -> id
  6725.             -> $ip_id
  6726.                 -> StartTime
  6727.  
  6728.     %TCP
  6729.         -> id
  6730.             -> $session_id
  6731.                 -> src
  6732.                 -> dest
  6733.                 -> source   # SYN seen
  6734.                 -> src_port
  6735.                 -> dest_port
  6736.                 -> Aseq
  6737.                     -> $$tcp_seq
  6738.                 -> Bseq
  6739.                     -> $$tcp_seq
  6740.                 -> time
  6741.                     -> $time
  6742.                         -> dir
  6743.                         -> data
  6744.                 -> BothHTML
  6745.                 -> StartTime
  6746.                 -> EndTime
  6747.                 -> size
  6748.                 -> knowndir
  6749.  
  6750.     %UDP
  6751.         -> id
  6752.             -> $session_id
  6753.                 -> src
  6754.                 -> dest
  6755.                 -> src_port
  6756.                 -> dest_port
  6757.                 -> RawA
  6758.                 -> RawB
  6759.                 -> time
  6760.                     -> $time
  6761.                 -> BothHTML
  6762.                 -> StartTime
  6763.                 -> EndTime
  6764.                 -> size
  6765.  
  6766.     %ICMP
  6767.         -> time
  6768.             -> type
  6769.             -> code
  6770.             -> src
  6771.             -> dest
  6772.             -> Partial
  6773.             -> ver
  6774.             -> size
  6775.  
  6776.     %Count
  6777.         -> IP
  6778.         -> IPprotocols
  6779.         -> TCPports
  6780.         -> UDPports
  6781.         -> EtherType
  6782.  
  6783.     %CountMaster
  6784.         (as above)
  6785.  
  6786.     %Index
  6787.         -> @HTML
  6788.         -> @Text
  6789.         -> Time_Order
  6790.             -> $session_timeid
  6791.         -> Sort_Lookup
  6792.             -> $session_timeid
  6793.  
  6794.     %Image
  6795.         -> @HTML
  6796.             -> links
  6797.             -> info
  6798.         -> notempty
  6799.  
  6800.     %GETPOST
  6801.         -> @HTML
  6802.             -> query
  6803.             -> info
  6804.         -> notempty
  6805.  
  6806.     %Hex
  6807.         -> $type
  6808.             -> $session_id
  6809.                 -> offset
  6810.                 -> pos
  6811.                 -> hextext
  6812.                 -> hexhtml
  6813.                 -> viewtext
  6814.                 -> viewhtml
  6815.  
  6816.     %Filenames
  6817.         -> $time
  6818.             -> filename
  6819.             -> service
  6820.             -> session_id
  6821.  
  6822.     @Master
  6823.         -> starttime
  6824.         -> endtime
  6825.         -> duration
  6826.         -> size
  6827.         -> dir
  6828.         -> file
Add Comment
Please, Sign In to add comment