Browse Source

updated Lua script for extracting stats from capture files

cecylia 7 years ago
parent
commit
aeac5dd931
1 changed files with 136 additions and 105 deletions
  1. 136 105
      tests/ssl_stats.lua

+ 136 - 105
tests/ssl_stats.lua

@@ -1,128 +1,121 @@
 --------------------------------------------------
--- $Header: /cvs/WIP/datcat-import/crawdad/bin/analysis/trace_stats.lua,v 1.1 2007/04/25 15:18:28 emile Exp $
--- extracts various stats (subset of crl_stats)
--- from a trace file, use like:
--- tshark -q <other opts> -Xlua_script:trace_stats.lua <trace>
--- wireshark/tshark needs to be compiled --with-lua
+-- Author: Cecylia Bocovich <cbocovic@uwaterloo.ca>
+-- Purpose: Extracts statistics about TLS handshakes
+-- Usage: tshark -q <other opts> -Xlua_script:tls_stats.lua -r <trace>
 --------------------------------------------------
 
 do
+    -- Extractor definitions
     ip_addr_extractor = Field.new("ip.addr")
     tcp_src_port_extractor = Field.new("tcp.srcport")
     tcp_dst_port_extractor = Field.new("tcp.dstport")
     tcp_stream_extractor = Field.new("tcp.stream")
     tls_handshake_type_extractor = Field.new("ssl.handshake.type")
-    tls_content_type_extractor = Field.new("ssl.record.content_type")
+    tls_record_type_extractor = Field.new("ssl.record.content_type")
+    tls_session_id_extractor = Field.new("ssl.handshake.session_id")
     tls_ccs_extractor = Field.new("ssl.change_cipher_spec")
     icmp_type_extractor = Field.new("icmp.type")
 
-    local function init_listener()
+    -- TLS states
+    CLNT_HELLO = "1"
+    SRVR_HELLO = "2"
+    NEW_SESSION = "4"
+    CERT = "11"
+    SRVR_KEYEX = "12"
+    SRVR_DONE = "14"
+    CLNT_KEYEX = "16"
+
+    -- Record types
+    CCS = "20"
+    ALERT = "21"
+    HANDSHAKE = "22"
+    APPLICATION = "23"
+
+    local function main()
         local tap = Listener.new("ssl")
 
         local file = assert(io.open("handshake_stats", "w"))
         file:write("stream,time\n")
         file:close()
-----------------------
------ stats  functions
-----------------------
-
--- ipv4 counts
-        local ipv4_src_cache = {}
-        local ipv4_dst_cache = {}
-        local ipv4_src_count = 0
-        local ipv4_dst_count = 0
-        function stats_ipv4_counts(pinfo,tvb)
-            local ip_src
-            local ip_dst
-            ip_src, ip_dst = ip_addr_extractor()
-            if ( ip_src ) then 
-                if (not ipv4_src_cache[ tostring(ip_src) ] == true ) then
-                    ipv4_src_cache[ tostring(ip_src) ] = true 
-                    ipv4_src_count = ipv4_src_count + 1
-                else
-                     -- print("src already recorded")
-                end
-
-            else 
-                -- print("NO src") 
-            end
-            if ( ip_dst ) then 
-                if (not ipv4_dst_cache[ tostring(ip_dst) ] == true ) then
-                    ipv4_dst_cache[ tostring(ip_dst) ] = true 
-                    ipv4_dst_count = ipv4_dst_count + 1
-                else
-                    -- print("dst already recorded")
-                end
-            else 
-                -- print("NO dst") 
-            end
-        end
-
--- tcp stream counts
-        local tcp_stream_cache = {}
-        local tcp_stream_count = 0
-        function stats_stream_counts(pinfo,tvb)
-            local stream
-            local sport, dport, saddr, daddr
-            stream = tcp_stream_extractor()
-            saddr, daddr = ip_addr_extractor()
-            sport = tcp_src_port_extractor()
-            dport = tcp_dst_port_extractor()
-            
-            if ( stream ) then 
-                if (not tcp_stream_cache[ tostring(stream) ] == true ) then
-                    tcp_stream_cache[ tostring(stream) ] = true 
-                    tcp_stream_count = tcp_stream_count + 1
-                    print("Stream #" .. tostring(tcp_stream_count) .. " | " .. tostring(saddr) .. ":" .. tostring(sport) .. " > " .. tostring(daddr) .. ":" .. tostring(dport) )
-                else
-                     -- print("stream already recorded")
-                end
 
-            else 
-                -- print("NO stream") 
-            end
-        end
+        --------------------------------
+        ----- Handshake Statistics -----
+        --------------------------------
 
+        -- Each stream has a table that holds the following data:
+        -- {state = [SHAKING, SHOOK, APPLICATION],
+        --  clnt_session_id = [Bytes], srvr_session_id = [Bytes],
+        --  session_ticket = [Bytes], resumed = [Boolean],
+        --  ccs_received = [Int],
+        --  start_time = [Float], end_time = [Float], shake_time = [Float]}
 
--- ssl stats
+        local streams = {} -- Table that holds all stream tables
         local tls_src_starts = {}
-        local tls_ccs_cache = {}
         function stats_tls_handshake(pinfo, tvb)
-            local hs_type, rec_type, ccs, stream
-            hs_type = tls_handshake_type_extractor()
-            ccs = tls_ccs_extractor()
-            stream = tcp_stream_extractor()
-            if(hs_type) then
-                local type_string
-                type_string = tostring(hs_type)
-                if(type_string == "1") then
-                    print("Start time for stream #" .. tostring(stream) .. " is " .. tostring(pinfo.abs_ts))
-                    tls_src_starts[ tostring(stream) ] = pinfo.abs_ts
+            local ip_src, ip_dst = ip_addr_extractor()
+            local port_src = tcp_src_port_extractor()
+            local port_dst = tcp_dst_port_extractor()
+            local stream = tostring(tcp_stream_extractor())
+            -- check if stream is already saved
+            local stream_info
+            if(not streams[stream]) then
+                streams[stream] = {}
+                streams[stream]["state"] = "shaking"
+                streams[stream]["client_ip"] = tostring(ip_src)
+                streams[stream]["server_ip"] = tostring(ip_dst)
+                streams[stream]["client_port"] = tostring(port_src)
+                streams[stream]["server_port"] = tostring(port_dst)
+            end
+            stream_info = streams[stream]
+
+            local rec_type = tls_record_type_extractor()
+            local ccs = tls_ccs_extractor()
+            if( not rec_type) then do return end end
+            rec_type = tostring(rec_type)
+
+            if (rec_type == HANDSHAKE) then
+                local hs_type = tostring(tls_handshake_type_extractor())
+                if (hs_type == CLNT_HELLO) then
+                    stream_info["start_time"] = pinfo.abs_ts
+                    local clnt_sess_id = tls_session_id_extractor()
+                    if(clnt_sess_id) then
+                        stream_info["clnt_sess_id"] = clnt_sess_id
+                    end
+                elseif (hs_type == SRVR_HELLO) then
+                    local srvr_sess_id = tls_session_id_extractor()
+                    if(srvr_sess_id) then
+                        if(stream_info["clnt_sess_id"] == srvr_sess_id) then
+                            stream_info["resumed"] = true
+                        end
+                    end
+                end
+            end
+            if (ccs) then
+                --check to see if this is the first or second CCS
+                if(not stream_info["ccs_received"]) then
+                    stream_info["ccs_received"] = 1
+                elseif (stream_info["ccs_received"] == 1) then
+                    -- handshake has ended
+                    stream_info["end_time"] = pinfo.abs_ts
+                    stream_info["shake_time"] = stream_info["end_time"] - stream_info["start_time"];
+                    stream_info["state"] = "SHOOK"
                 end
-
             end
-            if(ccs) then
-                if (not tls_ccs_cache[ tostring(stream) ] == true ) then
-                    tls_ccs_cache[ tostring(stream) ] = true 
-                    print("Received 1st CCS for stream #" .. tostring(stream))
-                else
-                    if( tls_src_starts[ tostring(stream)] ) then
-                        -- We have received both CCS and Finished messages
-                        local hs_time = pinfo.abs_ts - tls_src_starts[ tostring(stream)] 
-                        print("Total handshake time: " .. tostring(hs_time) )
-                        local file = assert(io.open("handshake_stats", "a"))
-                        file:write(tostring(stream) .. "," .. tostring(hs_time) .. "\n")
-                        file:close()
 
-                    end
+            if (rec_type == APPLICATION) then
+                if(not stream_info["app_start_time"]) then
+                    -- this is the first application data
+                    stream_info["app_start_time"] = pinfo.abs_ts
+                    stream_info["state"] = "APP"
+                elseif( (not stream_info["app_rtt_time"]) and (tostring(ip_src) ~= stream_info["client_ip"]) ) then
+                    stream_info["app_rtt_time"] = pinfo.abs_ts - stream_info["app_start_time"]
                 end
+
             end
             
-
-                
         end
 
--- start/end times
+        -- start/end times
         local start_time
         local end_time
         function stats_start_end_times(pinfo)
@@ -135,6 +128,40 @@ do
             end
         end
 
+        function print_resumed_session_stats()
+            for stream in pairs(streams) do
+                stream_info = streams[stream]
+                if (stream_info["resumed"]) then
+                    print(stream .. "," .. tostring(stream_info["shake_time"]))
+                end
+            end
+        end
+
+        function print_nonresumed_session_stats()
+            for stream in pairs(streams) do
+                stream_info = streams[stream]
+                if (not stream_info["resumed"]) then
+                    print(stream .. "," .. tostring(stream_info["shake_time"]))
+                end
+            end
+        end
+
+        function print_application_stats()
+            for stream in pairs(streams) do
+                stream_info = streams[stream]
+                if (stream_info["app_rtt_time"]) then
+                    print(stream .. "," .. tostring(stream_info["app_rtt_time"]))
+                end
+            end
+        end
+
+        function print_stream_info()
+            for stream in pairs(streams) do
+                stream_info = streams[stream]
+                print("Stream " .. stream .. ": " .. stream_info["client_ip"] .. ":" .. stream_info["client_port"] .. " > " .. stream_info["server_ip"] .. ":" .. stream_info["server_port"])
+            end
+        end
+
 -------------------
 ----- tap functions
 -------------------
@@ -142,22 +169,26 @@ do
         end
 
         function tap.packet(pinfo,tvb,ip)
-            stats_ipv4_counts(pinfo,tvb)
-            stats_stream_counts(pinfo,tvb)
             stats_start_end_times(pinfo)
             stats_tls_handshake(pinfo, tvb)
         end
 
         function tap.draw()
-            print("=== extra stats ===================================================")
-            print("start_time: " .. start_time )
-            print("end_time: " .. end_time )
-            print("ipv4_src_address_count: " .. ipv4_src_count ) 
-            print("ipv4_dst_address_count: " .. ipv4_dst_count )
-            print("tcp_stream_count: " .. tcp_stream_count )
-            print("===================================================================")
+            --print("=== Stream Information ===")
+            --print_stream_info()
+            print("=== Handshake Statistics ===")
+            print("Capture Start Time: " .. tostring(start_time) )
+            print("Capture End Time: " .. tostring(end_time) )
+
+            print("=== Full Handshakes ===")
+            print_nonresumed_session_stats()
+            print("=== Resumed sessions ===")
+            print_resumed_session_stats()
+            print("\n")
+            print("=== Application Statistics ===")
+            print_application_stats()
         end
     end
 
-    init_listener()
+    main()
 end