pcapr-local 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. data/.document +5 -0
  2. data/LICENSE.txt +20 -0
  3. data/README.md +64 -0
  4. data/Rakefile +57 -0
  5. data/VERSION +1 -0
  6. data/bin/pcap2par +49 -0
  7. data/bin/startpcapr +40 -0
  8. data/bin/stoppcapr +33 -0
  9. data/bin/xtractr +5 -0
  10. data/lib/environment.rb +106 -0
  11. data/lib/exe/xtractr +0 -0
  12. data/lib/mu/pcap.rb +110 -0
  13. data/lib/mu/pcap/ethernet.rb +148 -0
  14. data/lib/mu/pcap/header.rb +75 -0
  15. data/lib/mu/pcap/io_pair.rb +67 -0
  16. data/lib/mu/pcap/io_wrapper.rb +76 -0
  17. data/lib/mu/pcap/ip.rb +61 -0
  18. data/lib/mu/pcap/ipv4.rb +257 -0
  19. data/lib/mu/pcap/ipv6.rb +148 -0
  20. data/lib/mu/pcap/packet.rb +104 -0
  21. data/lib/mu/pcap/pkthdr.rb +155 -0
  22. data/lib/mu/pcap/reader.rb +61 -0
  23. data/lib/mu/pcap/reader/http_family.rb +170 -0
  24. data/lib/mu/pcap/sctp.rb +367 -0
  25. data/lib/mu/pcap/sctp/chunk.rb +123 -0
  26. data/lib/mu/pcap/sctp/chunk/data.rb +134 -0
  27. data/lib/mu/pcap/sctp/chunk/init.rb +100 -0
  28. data/lib/mu/pcap/sctp/chunk/init_ack.rb +68 -0
  29. data/lib/mu/pcap/sctp/parameter.rb +110 -0
  30. data/lib/mu/pcap/sctp/parameter/ip_address.rb +48 -0
  31. data/lib/mu/pcap/stream_packetizer.rb +72 -0
  32. data/lib/mu/pcap/tcp.rb +505 -0
  33. data/lib/mu/pcap/udp.rb +69 -0
  34. data/lib/mu/scenario/pcap.rb +164 -0
  35. data/lib/mu/scenario/pcap/fields.rb +50 -0
  36. data/lib/mu/scenario/pcap/rtp.rb +71 -0
  37. data/lib/pcapr_local.rb +159 -0
  38. data/lib/pcapr_local/config.rb +336 -0
  39. data/lib/pcapr_local/db.rb +197 -0
  40. data/lib/pcapr_local/scanner.rb +250 -0
  41. data/lib/pcapr_local/server.rb +178 -0
  42. data/lib/pcapr_local/www/favicon.ico +0 -0
  43. data/lib/pcapr_local/www/favicon.png +0 -0
  44. data/lib/pcapr_local/www/home/index.html +138 -0
  45. data/lib/pcapr_local/www/static/image/16x16/Cancel.png +0 -0
  46. data/lib/pcapr_local/www/static/image/16x16/Cancel.png.1 +0 -0
  47. data/lib/pcapr_local/www/static/image/16x16/Download.png +0 -0
  48. data/lib/pcapr_local/www/static/image/16x16/Folder3.png +0 -0
  49. data/lib/pcapr_local/www/static/image/16x16/Full Size.png +0 -0
  50. data/lib/pcapr_local/www/static/image/16x16/Minus.png +0 -0
  51. data/lib/pcapr_local/www/static/image/16x16/Plus.png +0 -0
  52. data/lib/pcapr_local/www/static/image/16x16/Search.png +0 -0
  53. data/lib/pcapr_local/www/static/image/16x16/User.png +0 -0
  54. data/lib/pcapr_local/www/static/image/48x48/Phone.png +0 -0
  55. data/lib/pcapr_local/www/static/image/48x48/Video.png +0 -0
  56. data/lib/pcapr_local/www/static/image/bar-orange.gif +0 -0
  57. data/lib/pcapr_local/www/static/image/beta.png +0 -0
  58. data/lib/pcapr_local/www/static/image/bg.png +0 -0
  59. data/lib/pcapr_local/www/static/image/blockquote.png +0 -0
  60. data/lib/pcapr_local/www/static/image/body-bg.png +0 -0
  61. data/lib/pcapr_local/www/static/image/body-h3.png +0 -0
  62. data/lib/pcapr_local/www/static/image/body-hl1-bg.png +0 -0
  63. data/lib/pcapr_local/www/static/image/body-hl1-h3.png +0 -0
  64. data/lib/pcapr_local/www/static/image/body-hl1-readmore.png +0 -0
  65. data/lib/pcapr_local/www/static/image/body-hl2-bg.png +0 -0
  66. data/lib/pcapr_local/www/static/image/body-hl2-h3.png +0 -0
  67. data/lib/pcapr_local/www/static/image/body-hl2-readmore.png +0 -0
  68. data/lib/pcapr_local/www/static/image/body-hl3-bg.png +0 -0
  69. data/lib/pcapr_local/www/static/image/body-hl3-h3.png +0 -0
  70. data/lib/pcapr_local/www/static/image/body-hl3-readmore.png +0 -0
  71. data/lib/pcapr_local/www/static/image/body-hl4-bg.png +0 -0
  72. data/lib/pcapr_local/www/static/image/body-hl4-h3.png +0 -0
  73. data/lib/pcapr_local/www/static/image/body-hl4-readmore.png +0 -0
  74. data/lib/pcapr_local/www/static/image/body-hl5-h3.png +0 -0
  75. data/lib/pcapr_local/www/static/image/body-hl6-h3.png +0 -0
  76. data/lib/pcapr_local/www/static/image/body-hl7-h3.png +0 -0
  77. data/lib/pcapr_local/www/static/image/body-hl8-h3.png +0 -0
  78. data/lib/pcapr_local/www/static/image/body-readmore.png +0 -0
  79. data/lib/pcapr_local/www/static/image/bottom-bg.png +0 -0
  80. data/lib/pcapr_local/www/static/image/bottom-l.png +0 -0
  81. data/lib/pcapr_local/www/static/image/bottom-r.png +0 -0
  82. data/lib/pcapr_local/www/static/image/btn-search.png +0 -0
  83. data/lib/pcapr_local/www/static/image/bullet-1.png +0 -0
  84. data/lib/pcapr_local/www/static/image/bullet-2.png +0 -0
  85. data/lib/pcapr_local/www/static/image/bullet-3.png +0 -0
  86. data/lib/pcapr_local/www/static/image/bullet-4.png +0 -0
  87. data/lib/pcapr_local/www/static/image/bullet-5.png +0 -0
  88. data/lib/pcapr_local/www/static/image/bullet-6.png +0 -0
  89. data/lib/pcapr_local/www/static/image/bullet-7.png +0 -0
  90. data/lib/pcapr_local/www/static/image/bullet-hl1.png +0 -0
  91. data/lib/pcapr_local/www/static/image/bullet-hl2.png +0 -0
  92. data/lib/pcapr_local/www/static/image/bullet-hl3.png +0 -0
  93. data/lib/pcapr_local/www/static/image/bullet-hl4.png +0 -0
  94. data/lib/pcapr_local/www/static/image/bullet-pathway.png +0 -0
  95. data/lib/pcapr_local/www/static/image/bullet-section1.png +0 -0
  96. data/lib/pcapr_local/www/static/image/bullet-section2.png +0 -0
  97. data/lib/pcapr_local/www/static/image/collapsed.gif +0 -0
  98. data/lib/pcapr_local/www/static/image/crosslink.png +0 -0
  99. data/lib/pcapr_local/www/static/image/expanded.gif +0 -0
  100. data/lib/pcapr_local/www/static/image/favicon.ico +0 -0
  101. data/lib/pcapr_local/www/static/image/favicon.png +0 -0
  102. data/lib/pcapr_local/www/static/image/icon-author.png +0 -0
  103. data/lib/pcapr_local/www/static/image/icon-created.png +0 -0
  104. data/lib/pcapr_local/www/static/image/p-expand.gif +0 -0
  105. data/lib/pcapr_local/www/static/image/pcapr-logo.png +0 -0
  106. data/lib/pcapr_local/www/static/image/powered-by.png +0 -0
  107. data/lib/pcapr_local/www/static/image/section1-bg.png +0 -0
  108. data/lib/pcapr_local/www/static/image/section1-h3.png +0 -0
  109. data/lib/pcapr_local/www/static/image/section1-readmore.png +0 -0
  110. data/lib/pcapr_local/www/static/image/section2-bg.png +0 -0
  111. data/lib/pcapr_local/www/static/image/section2-h3.png +0 -0
  112. data/lib/pcapr_local/www/static/image/section2-readmore.png +0 -0
  113. data/lib/pcapr_local/www/static/image/status-alert.png +0 -0
  114. data/lib/pcapr_local/www/static/image/status-download.png +0 -0
  115. data/lib/pcapr_local/www/static/image/status-info.png +0 -0
  116. data/lib/pcapr_local/www/static/image/status-note.png +0 -0
  117. data/lib/pcapr_local/www/static/image/tab-round.png +0 -0
  118. data/lib/pcapr_local/www/static/image/throbber.gif +0 -0
  119. data/lib/pcapr_local/www/static/image/user.jpg +0 -0
  120. data/lib/pcapr_local/www/static/script/closet/async.js +421 -0
  121. data/lib/pcapr_local/www/static/script/closet/closet.api.js +241 -0
  122. data/lib/pcapr_local/www/static/script/closet/closet.folders.js +94 -0
  123. data/lib/pcapr_local/www/static/script/closet/closet.js +187 -0
  124. data/lib/pcapr_local/www/static/script/closet/closet.mr.js +219 -0
  125. data/lib/pcapr_local/www/static/script/closet/closet.options.js +359 -0
  126. data/lib/pcapr_local/www/static/script/closet/closet.quantity.js +73 -0
  127. data/lib/pcapr_local/www/static/script/closet/closet.render.js +205 -0
  128. data/lib/pcapr_local/www/static/script/closet/closet.report.js +86 -0
  129. data/lib/pcapr_local/www/static/script/closet/closet.reports.http.js +135 -0
  130. data/lib/pcapr_local/www/static/script/closet/closet.reports.overview.js +163 -0
  131. data/lib/pcapr_local/www/static/script/closet/closet.reports.sip.js +159 -0
  132. data/lib/pcapr_local/www/static/script/closet/closet.reports.tcp.js +72 -0
  133. data/lib/pcapr_local/www/static/script/closet/closet.reports.visualize.js +263 -0
  134. data/lib/pcapr_local/www/static/script/closet/closet.util.js +40 -0
  135. data/lib/pcapr_local/www/static/script/jquery/jquery-1.4.2.min.js +154 -0
  136. data/lib/pcapr_local/www/static/script/jquery/jquery-ui.js +10921 -0
  137. data/lib/pcapr_local/www/static/script/jquery/jquery.flot.js +2123 -0
  138. data/lib/pcapr_local/www/static/script/jquery/jquery.flot.selection.js +184 -0
  139. data/lib/pcapr_local/www/static/script/jquery/jquery.flot.stack.js +184 -0
  140. data/lib/pcapr_local/www/static/script/jquery/jquery.form.js +643 -0
  141. data/lib/pcapr_local/www/static/script/jquery/jquery.jsonp.min.js +3 -0
  142. data/lib/pcapr_local/www/static/script/jquery/jquery.menu.js +142 -0
  143. data/lib/pcapr_local/www/static/script/jquery/jquery.suggest.js +308 -0
  144. data/lib/pcapr_local/www/static/script/jquery/jquery.ui.core.js +203 -0
  145. data/lib/pcapr_local/www/static/script/jquery/jquery.ui.slider.js +629 -0
  146. data/lib/pcapr_local/www/static/script/jquery/jquery.ui.sortable.js +1055 -0
  147. data/lib/pcapr_local/www/static/script/jquery/jquery.ui.widget.js +236 -0
  148. data/lib/pcapr_local/www/static/script/json2.js +481 -0
  149. data/lib/pcapr_local/www/static/script/sammy/plugins/sammy.cache.js +115 -0
  150. data/lib/pcapr_local/www/static/script/sammy/plugins/sammy.template.js +117 -0
  151. data/lib/pcapr_local/www/static/script/sammy/sammy.js +1696 -0
  152. data/lib/pcapr_local/www/static/script/tipsy/jquery.tipsy.js +104 -0
  153. data/lib/pcapr_local/www/static/style/c3p0.css +116 -0
  154. data/lib/pcapr_local/www/static/style/jquery.suggest.css +27 -0
  155. data/lib/pcapr_local/www/static/style/page.css +1113 -0
  156. data/lib/pcapr_local/www/static/style/tipsy.css +7 -0
  157. data/lib/pcapr_local/www/templates/browse.services.template +10 -0
  158. data/lib/pcapr_local/www/templates/browse.template +77 -0
  159. data/lib/pcapr_local/www/templates/flows.template +38 -0
  160. data/lib/pcapr_local/www/templates/pcap.template +63 -0
  161. data/lib/pcapr_local/www/templates/sip.calls.template +35 -0
  162. data/lib/pcapr_local/www/templates/statistics.template +6 -0
  163. data/lib/pcapr_local/xtractr.rb +179 -0
  164. data/lib/pcapr_local/xtractr/instance.rb +172 -0
  165. data/pcapr-local.gemspec +297 -0
  166. data/test/mu/pcap/reader/tc_http_family.rb +251 -0
  167. data/test/mu/pcap/tc_ethernet.rb +71 -0
  168. data/test/mu/pcap/tc_header.rb +56 -0
  169. data/test/mu/pcap/tc_ipv4.rb +103 -0
  170. data/test/mu/pcap/tc_ipv6.rb +83 -0
  171. data/test/mu/pcap/tc_packet.rb +44 -0
  172. data/test/mu/pcap/tc_pair.rb +58 -0
  173. data/test/mu/pcap/tc_pkthdr.rb +33 -0
  174. data/test/mu/pcap/tc_reader.rb +76 -0
  175. data/test/mu/pcap/tc_tcp.rb +426 -0
  176. data/test/mu/pcap/tc_udp.rb +33 -0
  177. data/test/mu/pcap/tc_wrapper.rb +80 -0
  178. data/test/mu/scenario/pcap/tc_fields.rb +67 -0
  179. data/test/mu/scenario/pcap/tc_rtp.rb +135 -0
  180. data/test/mu/scenario/sip_signalled_call_1.pcap +0 -0
  181. data/test/mu/scenario/tc_pcap.rb +190 -0
  182. data/test/mu/scenario/test_data/arp.pcap +0 -0
  183. data/test/mu/scenario/test_data/dns.pcap +0 -0
  184. data/test/mu/scenario/test_data/http-v6.pcap +0 -0
  185. data/test/mu/scenario/test_data/http.pcap +0 -0
  186. data/test/mu/scenario/test_data/http_chunked.pcap +0 -0
  187. data/test/mu/scenario/test_data/http_deflate.pcap +0 -0
  188. data/test/mu/scenario/test_data/httpauth3.pcap +0 -0
  189. data/test/mu/scenario/test_data/icmp.pcap +0 -0
  190. data/test/mu/scenario/test_data/sip_signalled_call_1.pcap +0 -0
  191. data/test/mu/tc_pcap.rb +39 -0
  192. data/test/mu/testcase.rb +86 -0
  193. data/test/pcapr_local/arp.pcap +0 -0
  194. data/test/pcapr_local/data.js +3 -0
  195. data/test/pcapr_local/http_chunked.pcap +0 -0
  196. data/test/pcapr_local/tc_api.rb +181 -0
  197. data/test/pcapr_local/test.tgz +0 -0
  198. data/test/pcapr_local/test_scanner.rb +241 -0
  199. data/test/pcapr_local/test_xtractr.rb +219 -0
  200. data/test/pcapr_local/testcase.rb +107 -0
  201. data/test/test_export_to_scenario.sh +25 -0
  202. data/test/test_pcapr_local.rb +29 -0
  203. metadata +450 -0
@@ -0,0 +1,76 @@
1
+ # http://www.mudynamics.com
2
+ # http://labs.mudynamics.com
3
+ # http://www.pcapr.net
4
+
5
+ require 'mu/testcase'
6
+ require 'mu/pcap/reader'
7
+
8
+ module Mu
9
+ class Pcap
10
+ class Reader
11
+
12
+ class Test < Mu::TestCase
13
+ class MyReader < Reader
14
+ FAMILY_TO_READER[:my_reader] = self
15
+
16
+ def do_read_message! bytes, state
17
+ state[:bytes_recv] ||= 0
18
+ if bytes.size >= 10
19
+ state[:bytes_recv] += 10
20
+ bytes.slice!(0,10)
21
+ end
22
+ end
23
+
24
+ def do_record_write bytes, state
25
+ state[:bytes_sent] ||= 0
26
+ state[:bytes_sent] += bytes.size
27
+ end
28
+ end
29
+
30
+ def test_basics
31
+ # initialize
32
+ reader = MyReader.new
33
+
34
+ # read_message/record_write
35
+ bytes = "a" * 11
36
+ state = {}
37
+ assert_equal "a"*10, reader.read_message(bytes, state)
38
+ assert_equal "a"*11, bytes
39
+ assert_equal "a"*10, reader.read_message!(bytes, state)
40
+ assert_equal "a", bytes
41
+ assert_equal 20, state[:bytes_recv]
42
+ assert_nil reader.read_message('a', state)
43
+ reader.record_write "foo", state
44
+ assert_equal 3, state[:bytes_sent]
45
+ reader.record_write "foo", state
46
+ assert_equal 6, state[:bytes_sent]
47
+ end
48
+
49
+ def test_family
50
+ reader = Reader.reader(:my_reader)
51
+ assert_kind_of MyReader, reader
52
+ assert_nil Reader.reader(:none)
53
+ assert_raises(ArgumentError) { Reader.reader(:lkjlkjkl) }
54
+ end
55
+
56
+ def test_exception
57
+ reader = MyReader.new
58
+ state = {}
59
+ def reader.do_read_message! bytes, state
60
+ raise "Yikes!"
61
+ end
62
+ def reader.do_record_write bytes, state
63
+ raise "Huh?"
64
+ end
65
+
66
+ reader.pcap2scenario = true
67
+ # Return nil instead of raising an exception during pcap2scenario
68
+ assert_nil reader.read_message('a'*10, state)
69
+ assert_nil reader.record_write('a'*10, state)
70
+
71
+ end
72
+ end
73
+
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,426 @@
1
+ # http://www.mudynamics.com
2
+ # http://labs.mudynamics.com
3
+ # http://www.pcapr.net
4
+
5
+ require 'mu/testcase'
6
+ require 'mu/pcap'
7
+
8
+ module Mu
9
+ class Pcap
10
+ class TCP
11
+
12
+ class Test < Mu::TestCase
13
+ def test_basics
14
+ tcp = TCP.new
15
+ tcp.src_port = 0x3039
16
+ tcp.dst_port = 0x0050
17
+ tcp.flags = 2
18
+ tcp.seq = 0
19
+ tcp.ack = 0
20
+ tcp.window = 0x3de0
21
+ tcp.urgent = 0
22
+ tcp.payload = 'hello'
23
+ tcp.payload_raw = 'hello'
24
+
25
+ bytes =
26
+ "\x30\x39" + # src port
27
+ "\x00\x50" + # dst port
28
+ "\x00\x00\x00\x00" + # seq
29
+ "\x00\x00\x00\x00" + # dst
30
+ "\x50" + # offset
31
+ "\x02" + # flags
32
+ "\x3d\xe0" + # window
33
+ "\x00\x00" + # checksum
34
+ "\x00\x00" + # urp
35
+ 'hello'
36
+ tcp_in = TCP.from_bytes bytes
37
+ assert_equal tcp_in, tcp
38
+ end
39
+
40
+ def test_reorder
41
+ # empty stream
42
+ assert_equal [], TCP.reorder([])
43
+
44
+ # one flow
45
+ tcp = tcp(:client, 'hello')
46
+ assert_equal [tcp], TCP.reorder([tcp])
47
+
48
+ # different flows
49
+ tcp1 = tcp(:client, 'hello')
50
+ tcp2 = tcp(:server, 'hello')
51
+ assert_equal [tcp1, tcp2], TCP.reorder([tcp1, tcp2])
52
+
53
+ # hello, world
54
+ tcp1 = tcp(:client, 'hello')
55
+ tcp2 = tcp(:client, 'world', 5)
56
+ assert_equal [tcp1, tcp2], TCP.reorder([tcp1, tcp2])
57
+
58
+ # world, discard old hello
59
+ tcp1 = tcp(:client, 'world', 5)
60
+ tcp2 = tcp(:client, 'hello')
61
+ assert_equal [tcp1], TCP.reorder([tcp1, tcp2])
62
+
63
+ # discard duplicate
64
+ tcp1 = tcp(:client, 'hello')
65
+ tcp2 = tcp(:client, 'hello')
66
+ assert_equal [tcp1], TCP.reorder([tcp1, tcp2])
67
+
68
+ # overlap
69
+ tcp1 = tcp(:client, 'hello')
70
+ tcp2 = tcp(:client, 'oworld', 4)
71
+ TCP.reorder [tcp1, tcp2]
72
+
73
+ # out of order packets
74
+ tcp1 = tcp(:client, 'hello')
75
+ tcp2 = tcp(:client, 'ld', 8)
76
+ tcp3 = tcp(:client, 'wor', 5)
77
+ assert_equal [tcp1, tcp3, tcp2], TCP.reorder([tcp1, tcp2, tcp3])
78
+
79
+ # out of order packets
80
+ tcp1 = tcp(:client, 'hello')
81
+ tcp2 = tcp(:client, 'wor', 5)
82
+ tcp3 = tcp(:client, 'l', 8)
83
+ tcp4 = tcp(:client, 'd', 9)
84
+ [[tcp2, tcp3, tcp4],
85
+ [tcp2, tcp4, tcp3],
86
+ [tcp3, tcp2, tcp4],
87
+ [tcp3, tcp4, tcp2],
88
+ [tcp4, tcp2, tcp3],
89
+ [tcp4, tcp3, tcp2]].each do |tcps|
90
+ assert_equal [tcp1, tcp2, tcp3, tcp4],
91
+ TCP.reorder([tcp1, *tcps])
92
+ end
93
+
94
+ # unfilled gap
95
+ tcp1 = tcp(:client, 'hello')
96
+ tcp2 = tcp(:client, 'world', 6)
97
+ assert_raises ReorderError do
98
+ TCP.reorder [tcp1, tcp2]
99
+ end
100
+
101
+ # syn
102
+ tcp1 = tcp(:client, '', 0, TCP::TH_SYN)
103
+ tcp2 = tcp(:client, 'hello', 1)
104
+ assert_equal [tcp1, tcp2], TCP.reorder([tcp1, tcp2])
105
+
106
+ # wrap sequence number
107
+ tcp1 = tcp(:client, 'hello', 2**32 - 1)
108
+ tcp2 = tcp(:client, 'world', 4)
109
+ assert_equal [tcp1, tcp2], TCP.reorder([tcp1, tcp2])
110
+ end
111
+
112
+ def test_merge
113
+ assert_equal [], TCP.merge([])
114
+
115
+ # Ethernet
116
+ ethernet = Ethernet.new
117
+ assert_equal [ethernet], TCP.merge([ethernet])
118
+
119
+ # IPv4
120
+ ipv4 = IPv4.new
121
+ ipv4.src = '10.0.0.1'
122
+ ipv4.dst = '10.0.0.2'
123
+ ipv4.proto = IPv4::IPPROTO_TCP
124
+ ethernet = Ethernet.new
125
+ ethernet.type = Ethernet::ETHERTYPE_IP
126
+ ethernet.payload = ipv4
127
+ assert_equal [ethernet], TCP.merge([ethernet])
128
+
129
+ # TCP, no data
130
+ tcp = tcp(:client, '')
131
+ assert_equal [], TCP.merge([tcp])
132
+
133
+ # TCP
134
+ tcp = tcp(:client, 'hello')
135
+ assert_equal [tcp], TCP.merge([tcp])
136
+
137
+ # Two TCP in different directions
138
+ tcp1 = tcp(:client, 'hello')
139
+ tcp2 = tcp(:server, 'world')
140
+ assert_equal [tcp1, tcp2], TCP.merge([tcp1, tcp2])
141
+
142
+ # Basic merge (original payloads not modified)
143
+ tcp1 = tcp(:client, 'hello')
144
+ tcp2 = tcp(:client, 'world', 5)
145
+ tcp3 = tcp(:client, 'three', 10)
146
+ tcp = tcp(:client, 'helloworldthree')
147
+ assert_equal [tcp], TCP.merge([tcp1, tcp2, tcp3])
148
+ assert_equal 'hello', tcp1.payload.payload.payload
149
+ assert_equal 'world', tcp2.payload.payload.payload
150
+
151
+ # overlap - favor second packet
152
+ tcp1 = tcp(:client, 'hello')
153
+ tcp2 = tcp(:client, 'Xworld', 4)
154
+ tcp3 = tcp(:client, 'three', 10)
155
+ tcp = tcp(:client, 'helloworldthree')
156
+ assert_equal [tcp], TCP.merge([tcp1, tcp2, tcp3])
157
+
158
+ # gap - raise error
159
+ tcp1 = tcp(:client, 'hello')
160
+ tcp2 = tcp(:client, 'world', 6)
161
+ assert_raises MergeError do
162
+ TCP.merge([tcp1, tcp2])
163
+ end
164
+
165
+ # sequence number wrap
166
+ tcp1 = tcp(:client, 'hello', 2**32 - 1)
167
+ tcp2 = tcp(:client, 'world', 4)
168
+ tcp = tcp(:client, 'helloworld', 2**32 - 1)
169
+ assert_equal [tcp], TCP.merge([tcp1, tcp2])
170
+
171
+ # sequence number wrap with overlap
172
+ tcp1 = tcp(:client, 'hello', 2**32 - 1)
173
+ tcp2 = tcp(:client, 'Xworld', 3)
174
+ tcp = tcp(:client, 'helloworld', 2**32 - 1)
175
+ assert_equal [tcp], TCP.merge([tcp1, tcp2])
176
+ end
177
+
178
+ def http_wrap bytes
179
+ "GET / HTTP/1.1\r\n" +
180
+ "some-header: foo\r\n" +
181
+ "some-length: 34\r\n" +
182
+ "Content-Length: #{bytes.length}\r\n" +
183
+ "Content-Something: baz\r\n" +
184
+ "\r\n" +
185
+ bytes
186
+ end
187
+
188
+ def make_stream bytes, direction, connection=1, offset=0, seg_size=1
189
+ io = StringIO.new bytes
190
+ packets = []
191
+ while bytes = io.read(seg_size)
192
+ packets << tcp(direction, bytes, offset, 0, connection)
193
+ offset += bytes.length
194
+ end
195
+ packets
196
+ end
197
+
198
+ TCP_FLAGS = 0
199
+ def test_message_assembly
200
+ message_1 = http_wrap("0123456789" * 100).freeze
201
+ message_2 = http_wrap("abcdefghij" * 100).freeze
202
+ message_3 = http_wrap("ABCDEFGHIJ" * 100).freeze
203
+
204
+ # Reassemble segments into message
205
+ packets = make_stream message_1, :client, 1
206
+ assert_equal [tcp(:client, message_1)], TCP.merge(packets)
207
+
208
+ # Insert server packet in front (should have no effect)
209
+ packets = make_stream message_1, :client, 1
210
+ server_packet = tcp(:server, "bytes")
211
+ packets.unshift server_packet
212
+ expect = [
213
+ server_packet,
214
+ tcp(:client, message_1, 0, TCP_FLAGS, 1)
215
+ ]
216
+ assert_equal expect, TCP.merge(packets)
217
+
218
+ # One interleaved packet from a different connection.
219
+ # HTTP message should be reassembled and appear second.
220
+ packets = make_stream message_1, :client, 1
221
+ extra_packet = tcp(:server, "X"*40, 0, TCP_FLAGS, 3)
222
+ packets[packets.length/2, 0] = [extra_packet]
223
+ expect = [
224
+ extra_packet,
225
+ tcp(:client, message_1, 0, TCP_FLAGS, 1)
226
+ ]
227
+ assert_equal expect, TCP.merge(packets)
228
+
229
+ # Two messages in a row with one interleaved packet
230
+ # from a different connection in middle of first message
231
+ #
232
+ # The first message should be ressambled after the extra packet.
233
+ packets = make_stream message_1 + message_2, :client, 1
234
+ extra_packet = tcp(:server, "XXXXXX", 0, TCP_FLAGS, 3)
235
+ packets[packets.length/4, 0] = [extra_packet]
236
+ expect = [
237
+ extra_packet,
238
+ tcp(:client, message_1, 0, TCP_FLAGS, 1),
239
+ tcp(:client, message_2, message_1.length, TCP_FLAGS, 1),
240
+ ]
241
+ assert_equal expect, TCP.merge(packets) # wrong?
242
+
243
+ # Two messages in a row with one interleaved packet
244
+ # from a different connection in middle of second message
245
+ # The second message should be reassembled after the
246
+ # extra packet.
247
+ packets = make_stream message_1 + message_2, :client, 1
248
+ extra_packet = tcp(:server, "bytes", 0, TCP_FLAGS, 3)
249
+ packets[(packets.length*0.75).to_i, 0] = [extra_packet]
250
+ expect = [
251
+ tcp(:client, message_1, 0, TCP_FLAGS, 1),
252
+ extra_packet,
253
+ tcp(:client, message_2, message_1.length, TCP_FLAGS, 1),
254
+ ]
255
+ assert_equal expect, TCP.merge(packets)
256
+
257
+ # Http message, followed by non http message with interleaved
258
+ # packet. Packets should not be merged or split because one
259
+ # of the flows has an incomplete message.
260
+ part1 = message_1
261
+ part2 = "X"*50
262
+ part3 = "Z"*50
263
+ message_bytes = part1 + part2 + part3
264
+ packets = make_stream message_bytes, :client, 1
265
+ extra_packet = tcp(:server, "EXTRA", 0, TCP_FLAGS, 3)
266
+ packets[-50, 0] = [extra_packet]
267
+ seq = 0
268
+ expect = [
269
+ tcp(:client, part1+part2, seq, TCP_FLAGS, 1),
270
+ extra_packet,
271
+ tcp(:client, part3, (part1.size + part2.size), TCP_FLAGS, 1),
272
+ ]
273
+ assert_equal expect, TCP.merge(packets)
274
+
275
+ # 3 Messages with interleaved packets from a different connection
276
+ # in the middle of the 2nd message and between the 2nd and 3rd
277
+ # messages.
278
+ packets = make_stream message_1 + message_2, :client, 1
279
+ extra_packet_1 = tcp(:client, "request", 0, TCP_FLAGS, 3)
280
+ packets[-packets.length/4, 0] = [extra_packet_1]
281
+ extra_packet_2 = tcp(:client, "request2", 0, TCP_FLAGS, 4)
282
+ packets << extra_packet_2
283
+ packets.concat make_stream(message_3, :client, 1, (message_1 + message_2).size)
284
+ seq = 0
285
+ expect = [
286
+ tcp(:client, message_1, seq, TCP_FLAGS, 1),
287
+ extra_packet_1,
288
+ tcp(:client, message_2, seq+=message_1.size, TCP_FLAGS, 1),
289
+ extra_packet_2,
290
+ tcp(:client, message_3, seq+=message_2.size, TCP_FLAGS, 1),
291
+ ]
292
+ assert_equal expect, TCP.merge(packets)
293
+
294
+ # One interleaved packet from server side of same connection,
295
+ # message should be reassembled.
296
+ packets = make_stream message_1, :client, 1
297
+ part1 = TCP.merge(packets[0...packets.length/2])
298
+ part2 = TCP.merge(packets[packets.length/2..-1])
299
+ extra_packet = tcp(:server, message_2, 0, TCP_FLAGS, 1)
300
+ packets = [part1, extra_packet, part2].flatten
301
+ expect = [
302
+ extra_packet,
303
+ tcp(:client, message_1, 0, TCP_FLAGS, 1),
304
+ ]
305
+ assert_equal expect, TCP.merge(packets)
306
+
307
+ # Alternate packets from different connections, messages should be assembled.
308
+ stream_1 = make_stream message_1, :client, 1
309
+ stream_2 = make_stream message_2, :server, 2
310
+ packets = stream_1.zip(stream_2).flatten
311
+ expect = [
312
+ tcp(:client, message_1, 0, TCP_FLAGS, 1),
313
+ tcp(:server, message_2, 0, TCP_FLAGS, 2)
314
+ ]
315
+ assert_equal expect, TCP.merge(packets)
316
+
317
+ # Switch first packet
318
+ stream_1 = make_stream message_1, :client, 1
319
+ stream_2 = make_stream message_2, :server, 2
320
+ packets = stream_2.zip(stream_1).flatten
321
+ expect = [
322
+ tcp(:server, message_2, 0, TCP_FLAGS, 2),
323
+ tcp(:client, message_1, 0, TCP_FLAGS, 1)
324
+ ]
325
+ assert_equal expect, TCP.merge(packets)
326
+
327
+ # Alternate packets from different sides of same connection,
328
+ # messages should be reassmbled.
329
+ stream_1 = make_stream message_1, :client, 1
330
+ stream_2 = make_stream message_2, :server, 1
331
+ packets = stream_1.zip(stream_2).flatten
332
+ stream_1 = make_stream message_1, :client, 1
333
+ stream_2 = make_stream message_2, :server, 1
334
+ expect = [
335
+ tcp(:client, message_1, 0, TCP_FLAGS, 1),
336
+ tcp(:server, message_2, 0, TCP_FLAGS, 1),
337
+ ]
338
+ assert_equal expect, TCP.merge(packets)
339
+
340
+ # Messages should not be merged because they
341
+ # are too big and would need to be split into
342
+ # 64K chunks.
343
+ part_2 = http_wrap("Z" * 80 * 1024)
344
+ part_1 = part_2.slice!(0,70*1024)
345
+ packets = [
346
+ tcp(:client, part_1, 0, TCP_FLAGS),
347
+ tcp(:server, message_2, 0, TCP_FLAGS),
348
+ tcp(:client, part_2, 0, TCP_FLAGS),
349
+ ]
350
+ expect = [
351
+ tcp(:client, part_1, 0, TCP_FLAGS),
352
+ tcp(:server, message_2, 0, TCP_FLAGS),
353
+ tcp(:client, part_2, 0, TCP_FLAGS),
354
+ ]
355
+ assert_equal expect, TCP.merge(packets)
356
+ end
357
+
358
+ def test_split
359
+ assert_equal [], TCP.split([])
360
+
361
+ tcp = tcp(:client, 'A' * (65535 - 54))
362
+ assert_equal [tcp], TCP.split([tcp])
363
+
364
+ tcp = tcp(:client, 'A' * 65535)
365
+ tcp1 = tcp(:client, 'A' * (65535 - 54))
366
+ tcp2 = tcp(:client, 'A' * 54, (65535 - 54))
367
+ assert_equal [tcp1, tcp2], TCP.split([tcp])
368
+ end
369
+
370
+ def test_tcp_seq_sub
371
+ assert_equal 1, TCP.seq_sub(2, 1)
372
+ assert_equal 0, TCP.seq_sub(1, 1)
373
+ assert_equal 1, TCP.seq_sub(0, 2**32-1)
374
+ assert_equal(-1, TCP.seq_sub(2**32-1, 0))
375
+ assert_equal 0, TCP.seq_sub(2**32-1, 2**32-1)
376
+
377
+ assert TCP.seq_eq(0, 0)
378
+ assert TCP.seq_eq(2**32, 0)
379
+ assert TCP.seq_eq(0, 2**32)
380
+
381
+ assert TCP.seq_lt(1, 2)
382
+ assert !TCP.seq_lt(2, 1)
383
+ assert !TCP.seq_lt(2, 2)
384
+ assert TCP.seq_lt(2**32-1, 0)
385
+ assert !TCP.seq_lt(0, 2**32-1)
386
+
387
+ assert TCP.seq_lte(1, 2)
388
+ assert !TCP.seq_lte(2, 1)
389
+ assert TCP.seq_lte(2, 2)
390
+ assert TCP.seq_lt(2**32-1, 0)
391
+ assert !TCP.seq_lt(0, 2**32-1)
392
+ end
393
+
394
+ def tcp sender, payload, seq=0, flags=0, connection=1
395
+ tcp = TCP.new
396
+ ipv4 = IPv4.new
397
+ ethernet = Ethernet.new
398
+ if sender == :client
399
+ ethernet.src = '00:01:00:00:00:01'
400
+ ethernet.dst = '00:01:00:00:00:02'
401
+ ipv4.src = '10.0.0.1'
402
+ ipv4.dst = '10.0.0.2'
403
+ tcp.src_port = connection
404
+ tcp.dst_port = connection + 10000
405
+ else
406
+ ethernet.src = '00:01:00:00:00:02'
407
+ ethernet.dst = '00:01:00:00:00:01'
408
+ ipv4.src = '10.0.0.2'
409
+ ipv4.dst = '10.0.0.1'
410
+ tcp.src_port = connection + 10000
411
+ tcp.dst_port = connection
412
+ end
413
+ tcp.flags = flags
414
+ tcp.seq = seq
415
+ tcp.payload = payload
416
+ ipv4.proto = IPv4::IPPROTO_TCP
417
+ ipv4.payload = tcp
418
+ ethernet.type = Ethernet::ETHERTYPE_IP
419
+ ethernet.payload = ipv4
420
+ return ethernet
421
+ end
422
+ end
423
+
424
+ end
425
+ end
426
+ end