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.
- data/.document +5 -0
- data/LICENSE.txt +20 -0
- data/README.md +64 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/bin/pcap2par +49 -0
- data/bin/startpcapr +40 -0
- data/bin/stoppcapr +33 -0
- data/bin/xtractr +5 -0
- data/lib/environment.rb +106 -0
- data/lib/exe/xtractr +0 -0
- data/lib/mu/pcap.rb +110 -0
- data/lib/mu/pcap/ethernet.rb +148 -0
- data/lib/mu/pcap/header.rb +75 -0
- data/lib/mu/pcap/io_pair.rb +67 -0
- data/lib/mu/pcap/io_wrapper.rb +76 -0
- data/lib/mu/pcap/ip.rb +61 -0
- data/lib/mu/pcap/ipv4.rb +257 -0
- data/lib/mu/pcap/ipv6.rb +148 -0
- data/lib/mu/pcap/packet.rb +104 -0
- data/lib/mu/pcap/pkthdr.rb +155 -0
- data/lib/mu/pcap/reader.rb +61 -0
- data/lib/mu/pcap/reader/http_family.rb +170 -0
- data/lib/mu/pcap/sctp.rb +367 -0
- data/lib/mu/pcap/sctp/chunk.rb +123 -0
- data/lib/mu/pcap/sctp/chunk/data.rb +134 -0
- data/lib/mu/pcap/sctp/chunk/init.rb +100 -0
- data/lib/mu/pcap/sctp/chunk/init_ack.rb +68 -0
- data/lib/mu/pcap/sctp/parameter.rb +110 -0
- data/lib/mu/pcap/sctp/parameter/ip_address.rb +48 -0
- data/lib/mu/pcap/stream_packetizer.rb +72 -0
- data/lib/mu/pcap/tcp.rb +505 -0
- data/lib/mu/pcap/udp.rb +69 -0
- data/lib/mu/scenario/pcap.rb +164 -0
- data/lib/mu/scenario/pcap/fields.rb +50 -0
- data/lib/mu/scenario/pcap/rtp.rb +71 -0
- data/lib/pcapr_local.rb +159 -0
- data/lib/pcapr_local/config.rb +336 -0
- data/lib/pcapr_local/db.rb +197 -0
- data/lib/pcapr_local/scanner.rb +250 -0
- data/lib/pcapr_local/server.rb +178 -0
- data/lib/pcapr_local/www/favicon.ico +0 -0
- data/lib/pcapr_local/www/favicon.png +0 -0
- data/lib/pcapr_local/www/home/index.html +138 -0
- data/lib/pcapr_local/www/static/image/16x16/Cancel.png +0 -0
- data/lib/pcapr_local/www/static/image/16x16/Cancel.png.1 +0 -0
- data/lib/pcapr_local/www/static/image/16x16/Download.png +0 -0
- data/lib/pcapr_local/www/static/image/16x16/Folder3.png +0 -0
- data/lib/pcapr_local/www/static/image/16x16/Full Size.png +0 -0
- data/lib/pcapr_local/www/static/image/16x16/Minus.png +0 -0
- data/lib/pcapr_local/www/static/image/16x16/Plus.png +0 -0
- data/lib/pcapr_local/www/static/image/16x16/Search.png +0 -0
- data/lib/pcapr_local/www/static/image/16x16/User.png +0 -0
- data/lib/pcapr_local/www/static/image/48x48/Phone.png +0 -0
- data/lib/pcapr_local/www/static/image/48x48/Video.png +0 -0
- data/lib/pcapr_local/www/static/image/bar-orange.gif +0 -0
- data/lib/pcapr_local/www/static/image/beta.png +0 -0
- data/lib/pcapr_local/www/static/image/bg.png +0 -0
- data/lib/pcapr_local/www/static/image/blockquote.png +0 -0
- data/lib/pcapr_local/www/static/image/body-bg.png +0 -0
- data/lib/pcapr_local/www/static/image/body-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl1-bg.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl1-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl1-readmore.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl2-bg.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl2-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl2-readmore.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl3-bg.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl3-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl3-readmore.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl4-bg.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl4-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl4-readmore.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl5-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl6-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl7-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl8-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-readmore.png +0 -0
- data/lib/pcapr_local/www/static/image/bottom-bg.png +0 -0
- data/lib/pcapr_local/www/static/image/bottom-l.png +0 -0
- data/lib/pcapr_local/www/static/image/bottom-r.png +0 -0
- data/lib/pcapr_local/www/static/image/btn-search.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-1.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-2.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-3.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-4.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-5.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-6.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-7.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-hl1.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-hl2.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-hl3.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-hl4.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-pathway.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-section1.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-section2.png +0 -0
- data/lib/pcapr_local/www/static/image/collapsed.gif +0 -0
- data/lib/pcapr_local/www/static/image/crosslink.png +0 -0
- data/lib/pcapr_local/www/static/image/expanded.gif +0 -0
- data/lib/pcapr_local/www/static/image/favicon.ico +0 -0
- data/lib/pcapr_local/www/static/image/favicon.png +0 -0
- data/lib/pcapr_local/www/static/image/icon-author.png +0 -0
- data/lib/pcapr_local/www/static/image/icon-created.png +0 -0
- data/lib/pcapr_local/www/static/image/p-expand.gif +0 -0
- data/lib/pcapr_local/www/static/image/pcapr-logo.png +0 -0
- data/lib/pcapr_local/www/static/image/powered-by.png +0 -0
- data/lib/pcapr_local/www/static/image/section1-bg.png +0 -0
- data/lib/pcapr_local/www/static/image/section1-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/section1-readmore.png +0 -0
- data/lib/pcapr_local/www/static/image/section2-bg.png +0 -0
- data/lib/pcapr_local/www/static/image/section2-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/section2-readmore.png +0 -0
- data/lib/pcapr_local/www/static/image/status-alert.png +0 -0
- data/lib/pcapr_local/www/static/image/status-download.png +0 -0
- data/lib/pcapr_local/www/static/image/status-info.png +0 -0
- data/lib/pcapr_local/www/static/image/status-note.png +0 -0
- data/lib/pcapr_local/www/static/image/tab-round.png +0 -0
- data/lib/pcapr_local/www/static/image/throbber.gif +0 -0
- data/lib/pcapr_local/www/static/image/user.jpg +0 -0
- data/lib/pcapr_local/www/static/script/closet/async.js +421 -0
- data/lib/pcapr_local/www/static/script/closet/closet.api.js +241 -0
- data/lib/pcapr_local/www/static/script/closet/closet.folders.js +94 -0
- data/lib/pcapr_local/www/static/script/closet/closet.js +187 -0
- data/lib/pcapr_local/www/static/script/closet/closet.mr.js +219 -0
- data/lib/pcapr_local/www/static/script/closet/closet.options.js +359 -0
- data/lib/pcapr_local/www/static/script/closet/closet.quantity.js +73 -0
- data/lib/pcapr_local/www/static/script/closet/closet.render.js +205 -0
- data/lib/pcapr_local/www/static/script/closet/closet.report.js +86 -0
- data/lib/pcapr_local/www/static/script/closet/closet.reports.http.js +135 -0
- data/lib/pcapr_local/www/static/script/closet/closet.reports.overview.js +163 -0
- data/lib/pcapr_local/www/static/script/closet/closet.reports.sip.js +159 -0
- data/lib/pcapr_local/www/static/script/closet/closet.reports.tcp.js +72 -0
- data/lib/pcapr_local/www/static/script/closet/closet.reports.visualize.js +263 -0
- data/lib/pcapr_local/www/static/script/closet/closet.util.js +40 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery-1.4.2.min.js +154 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery-ui.js +10921 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.flot.js +2123 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.flot.selection.js +184 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.flot.stack.js +184 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.form.js +643 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.jsonp.min.js +3 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.menu.js +142 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.suggest.js +308 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.ui.core.js +203 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.ui.slider.js +629 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.ui.sortable.js +1055 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.ui.widget.js +236 -0
- data/lib/pcapr_local/www/static/script/json2.js +481 -0
- data/lib/pcapr_local/www/static/script/sammy/plugins/sammy.cache.js +115 -0
- data/lib/pcapr_local/www/static/script/sammy/plugins/sammy.template.js +117 -0
- data/lib/pcapr_local/www/static/script/sammy/sammy.js +1696 -0
- data/lib/pcapr_local/www/static/script/tipsy/jquery.tipsy.js +104 -0
- data/lib/pcapr_local/www/static/style/c3p0.css +116 -0
- data/lib/pcapr_local/www/static/style/jquery.suggest.css +27 -0
- data/lib/pcapr_local/www/static/style/page.css +1113 -0
- data/lib/pcapr_local/www/static/style/tipsy.css +7 -0
- data/lib/pcapr_local/www/templates/browse.services.template +10 -0
- data/lib/pcapr_local/www/templates/browse.template +77 -0
- data/lib/pcapr_local/www/templates/flows.template +38 -0
- data/lib/pcapr_local/www/templates/pcap.template +63 -0
- data/lib/pcapr_local/www/templates/sip.calls.template +35 -0
- data/lib/pcapr_local/www/templates/statistics.template +6 -0
- data/lib/pcapr_local/xtractr.rb +179 -0
- data/lib/pcapr_local/xtractr/instance.rb +172 -0
- data/pcapr-local.gemspec +297 -0
- data/test/mu/pcap/reader/tc_http_family.rb +251 -0
- data/test/mu/pcap/tc_ethernet.rb +71 -0
- data/test/mu/pcap/tc_header.rb +56 -0
- data/test/mu/pcap/tc_ipv4.rb +103 -0
- data/test/mu/pcap/tc_ipv6.rb +83 -0
- data/test/mu/pcap/tc_packet.rb +44 -0
- data/test/mu/pcap/tc_pair.rb +58 -0
- data/test/mu/pcap/tc_pkthdr.rb +33 -0
- data/test/mu/pcap/tc_reader.rb +76 -0
- data/test/mu/pcap/tc_tcp.rb +426 -0
- data/test/mu/pcap/tc_udp.rb +33 -0
- data/test/mu/pcap/tc_wrapper.rb +80 -0
- data/test/mu/scenario/pcap/tc_fields.rb +67 -0
- data/test/mu/scenario/pcap/tc_rtp.rb +135 -0
- data/test/mu/scenario/sip_signalled_call_1.pcap +0 -0
- data/test/mu/scenario/tc_pcap.rb +190 -0
- data/test/mu/scenario/test_data/arp.pcap +0 -0
- data/test/mu/scenario/test_data/dns.pcap +0 -0
- data/test/mu/scenario/test_data/http-v6.pcap +0 -0
- data/test/mu/scenario/test_data/http.pcap +0 -0
- data/test/mu/scenario/test_data/http_chunked.pcap +0 -0
- data/test/mu/scenario/test_data/http_deflate.pcap +0 -0
- data/test/mu/scenario/test_data/httpauth3.pcap +0 -0
- data/test/mu/scenario/test_data/icmp.pcap +0 -0
- data/test/mu/scenario/test_data/sip_signalled_call_1.pcap +0 -0
- data/test/mu/tc_pcap.rb +39 -0
- data/test/mu/testcase.rb +86 -0
- data/test/pcapr_local/arp.pcap +0 -0
- data/test/pcapr_local/data.js +3 -0
- data/test/pcapr_local/http_chunked.pcap +0 -0
- data/test/pcapr_local/tc_api.rb +181 -0
- data/test/pcapr_local/test.tgz +0 -0
- data/test/pcapr_local/test_scanner.rb +241 -0
- data/test/pcapr_local/test_xtractr.rb +219 -0
- data/test/pcapr_local/testcase.rb +107 -0
- data/test/test_export_to_scenario.sh +25 -0
- data/test/test_pcapr_local.rb +29 -0
- 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
|