ssl_stats.lua 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. --------------------------------------------------
  2. -- Author: Cecylia Bocovich <cbocovic@uwaterloo.ca>
  3. -- Purpose: Extracts statistics about TLS handshakes
  4. -- Usage: tshark -q <other opts> -Xlua_script:tls_stats.lua -r <trace>
  5. --------------------------------------------------
  6. do
  7. -- Extractor definitions
  8. ip_addr_extractor = Field.new("ip.addr")
  9. tcp_src_port_extractor = Field.new("tcp.srcport")
  10. tcp_dst_port_extractor = Field.new("tcp.dstport")
  11. tcp_stream_extractor = Field.new("tcp.stream")
  12. tls_handshake_type_extractor = Field.new("ssl.handshake.type")
  13. tls_record_type_extractor = Field.new("ssl.record.content_type")
  14. tls_session_id_extractor = Field.new("ssl.handshake.session_id")
  15. tls_ccs_extractor = Field.new("ssl.change_cipher_spec")
  16. icmp_type_extractor = Field.new("icmp.type")
  17. -- TLS states
  18. CLNT_HELLO = "1"
  19. SRVR_HELLO = "2"
  20. NEW_SESSION = "4"
  21. CERT = "11"
  22. SRVR_KEYEX = "12"
  23. SRVR_DONE = "14"
  24. CLNT_KEYEX = "16"
  25. -- Record types
  26. CCS = "20"
  27. ALERT = "21"
  28. HANDSHAKE = "22"
  29. APPLICATION = "23"
  30. local function main()
  31. local tap = Listener.new("ssl")
  32. local file = assert(io.open("handshake_stats", "w"))
  33. file:write("stream,time\n")
  34. file:close()
  35. --------------------------------
  36. ----- Handshake Statistics -----
  37. --------------------------------
  38. -- Each stream has a table that holds the following data:
  39. -- {state = [SHAKING, SHOOK, APPLICATION],
  40. -- clnt_session_id = [Bytes], srvr_session_id = [Bytes],
  41. -- session_ticket = [Bytes], resumed = [Boolean],
  42. -- ccs_received = [Int],
  43. -- start_time = [Float], end_time = [Float], shake_time = [Float]}
  44. local streams = {} -- Table that holds all stream tables
  45. local tls_src_starts = {}
  46. function stats_tls_handshake(pinfo, tvb)
  47. local ip_src, ip_dst = ip_addr_extractor()
  48. local port_src = tcp_src_port_extractor()
  49. local port_dst = tcp_dst_port_extractor()
  50. local stream = tostring(tcp_stream_extractor())
  51. -- check if stream is already saved
  52. local stream_info
  53. if(not streams[stream]) then
  54. streams[stream] = {}
  55. streams[stream]["state"] = "shaking"
  56. streams[stream]["client_ip"] = tostring(ip_src)
  57. streams[stream]["server_ip"] = tostring(ip_dst)
  58. streams[stream]["client_port"] = tostring(port_src)
  59. streams[stream]["server_port"] = tostring(port_dst)
  60. end
  61. stream_info = streams[stream]
  62. local rec_type = tls_record_type_extractor()
  63. local ccs = tls_ccs_extractor()
  64. if( not rec_type) then do return end end
  65. rec_type = tostring(rec_type)
  66. if (rec_type == HANDSHAKE) then
  67. local hs_type = tostring(tls_handshake_type_extractor())
  68. if (hs_type == CLNT_HELLO) then
  69. stream_info["start_time"] = pinfo.abs_ts
  70. local clnt_sess_id = tls_session_id_extractor()
  71. if(clnt_sess_id) then
  72. stream_info["clnt_sess_id"] = clnt_sess_id
  73. end
  74. elseif (hs_type == SRVR_HELLO) then
  75. local srvr_sess_id = tls_session_id_extractor()
  76. if(srvr_sess_id) then
  77. if(stream_info["clnt_sess_id"] == srvr_sess_id) then
  78. stream_info["resumed"] = true
  79. end
  80. end
  81. end
  82. end
  83. if (ccs) then
  84. --check to see if this is the first or second CCS
  85. if(not stream_info["ccs_received"]) then
  86. stream_info["ccs_received"] = 1
  87. elseif (stream_info["ccs_received"] == 1) then
  88. -- handshake has ended
  89. stream_info["end_time"] = pinfo.abs_ts
  90. stream_info["shake_time"] = stream_info["end_time"] - stream_info["start_time"];
  91. stream_info["state"] = "SHOOK"
  92. end
  93. end
  94. if (rec_type == APPLICATION) then
  95. if(not stream_info["app_start_time"]) then
  96. -- this is the first application data
  97. stream_info["app_start_time"] = pinfo.abs_ts
  98. stream_info["state"] = "APP"
  99. elseif( (not stream_info["app_rtt_time"]) and (tostring(ip_src) ~= stream_info["client_ip"]) ) then
  100. stream_info["app_rtt_time"] = pinfo.abs_ts - stream_info["app_start_time"]
  101. end
  102. end
  103. end
  104. -- start/end times
  105. local start_time
  106. local end_time
  107. function stats_start_end_times(pinfo)
  108. if (not start_time) then
  109. start_time = pinfo.abs_ts
  110. end_time = pinfo.abs_ts
  111. else
  112. if ( start_time > pinfo.abs_ts ) then start_time = pinfo.abs_ts end
  113. if ( end_time < pinfo.abs_ts ) then end_time = pinfo.abs_ts end
  114. end
  115. end
  116. function print_resumed_session_stats()
  117. for stream in pairs(streams) do
  118. stream_info = streams[stream]
  119. if (stream_info["resumed"]) then
  120. print(stream .. "," .. tostring(stream_info["shake_time"]))
  121. end
  122. end
  123. end
  124. function print_nonresumed_session_stats()
  125. for stream in pairs(streams) do
  126. stream_info = streams[stream]
  127. if (not stream_info["resumed"]) then
  128. print(stream .. "," .. tostring(stream_info["shake_time"]))
  129. end
  130. end
  131. end
  132. function print_application_stats()
  133. for stream in pairs(streams) do
  134. stream_info = streams[stream]
  135. if (stream_info["app_rtt_time"]) then
  136. print(stream .. "," .. tostring(stream_info["app_rtt_time"]))
  137. end
  138. end
  139. end
  140. function print_stream_info()
  141. for stream in pairs(streams) do
  142. stream_info = streams[stream]
  143. print("Stream " .. stream .. ": " .. stream_info["client_ip"] .. ":" .. stream_info["client_port"] .. " > " .. stream_info["server_ip"] .. ":" .. stream_info["server_port"])
  144. end
  145. end
  146. -------------------
  147. ----- tap functions
  148. -------------------
  149. function tap.reset()
  150. end
  151. function tap.packet(pinfo,tvb,ip)
  152. stats_start_end_times(pinfo)
  153. stats_tls_handshake(pinfo, tvb)
  154. end
  155. function tap.draw()
  156. --print("=== Stream Information ===")
  157. --print_stream_info()
  158. print("=== Handshake Statistics ===")
  159. print("Capture Start Time: " .. tostring(start_time) )
  160. print("Capture End Time: " .. tostring(end_time) )
  161. print("=== Full Handshakes ===")
  162. print_nonresumed_session_stats()
  163. print("=== Resumed sessions ===")
  164. print_resumed_session_stats()
  165. print("\n")
  166. print("=== Application Statistics ===")
  167. print_application_stats()
  168. end
  169. end
  170. main()
  171. end