pcapr-local 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
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