pcapr-local 0.1.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/lib/mu/pcap/ipv6.rb
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
# http://www.mudynamics.com
|
2
|
+
# http://labs.mudynamics.com
|
3
|
+
# http://www.pcapr.net
|
4
|
+
|
5
|
+
require 'ipaddr'
|
6
|
+
|
7
|
+
module Mu
|
8
|
+
class Pcap
|
9
|
+
|
10
|
+
class IPv6 < IP
|
11
|
+
FORMAT = 'NnCCa16a16'
|
12
|
+
|
13
|
+
attr_accessor :next_header, :hop_limit
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
super
|
17
|
+
@next_header = 0
|
18
|
+
@hop_limit = 64
|
19
|
+
end
|
20
|
+
|
21
|
+
def v6?
|
22
|
+
return true
|
23
|
+
end
|
24
|
+
|
25
|
+
alias :proto :next_header
|
26
|
+
alias :ttl :hop_limit
|
27
|
+
|
28
|
+
def flow_id
|
29
|
+
if not @payload or @payload.is_a? String
|
30
|
+
return [:ipv6, @next_header, @src, @dst]
|
31
|
+
else
|
32
|
+
return [:ipv6, @src, @dst, @payload.flow_id]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.from_bytes bytes
|
37
|
+
Pcap.assert bytes.length >= 40, 'Truncated IPv6 header: ' +
|
38
|
+
"expected at least 40 bytes, got #{bytes.length} bytes"
|
39
|
+
|
40
|
+
vcl, length, next_header, hop_limit, src, dst =
|
41
|
+
bytes[0, 40].unpack FORMAT
|
42
|
+
version = vcl >> 28 & 0x0f
|
43
|
+
traffic_class = vcl >> 20 & 0xff
|
44
|
+
flow_label = vcl & 0xfffff
|
45
|
+
|
46
|
+
Pcap.assert version == 6, "Wrong IPv6 version: got (#{version})"
|
47
|
+
Pcap.assert bytes.length >= (40 + length), 'Truncated IPv6 header: ' +
|
48
|
+
"expected #{length + 40} bytes, got #{bytes.length} bytes"
|
49
|
+
|
50
|
+
ipv6 = IPv6.new
|
51
|
+
ipv6.next_header = next_header
|
52
|
+
ipv6.hop_limit = hop_limit
|
53
|
+
ipv6.src = IPAddr.new_ntoh(src).to_s
|
54
|
+
ipv6.dst = IPAddr.new_ntoh(dst).to_s
|
55
|
+
|
56
|
+
ipv6.payload_raw = bytes[40..-1]
|
57
|
+
ipv6.next_header, ipv6.payload =
|
58
|
+
payload_from_bytes ipv6, ipv6.next_header, bytes[40...40+length]
|
59
|
+
|
60
|
+
return ipv6
|
61
|
+
end
|
62
|
+
|
63
|
+
# Parse bytes and returns next_header and payload. Skips extension
|
64
|
+
# headers.
|
65
|
+
def self.payload_from_bytes ipv6, next_header, bytes
|
66
|
+
begin
|
67
|
+
case next_header
|
68
|
+
when IPPROTO_TCP
|
69
|
+
payload = TCP.from_bytes bytes
|
70
|
+
when IPPROTO_UDP
|
71
|
+
payload = UDP.from_bytes bytes
|
72
|
+
when IPPROTO_SCTP
|
73
|
+
payload = SCTP.from_bytes bytes
|
74
|
+
when IPPROTO_HOPOPTS
|
75
|
+
next_header, payload = eight_byte_header_from_bytes(ipv6,
|
76
|
+
bytes, 'hop-by-hop options')
|
77
|
+
when IPPROTO_ROUTING
|
78
|
+
next_header, payload = eight_byte_header_from_bytes(ipv6,
|
79
|
+
bytes, 'routing')
|
80
|
+
when IPPROTO_DSTOPTS
|
81
|
+
next_header, payload = eight_byte_header_from_bytes(ipv6,
|
82
|
+
bytes, 'destination options')
|
83
|
+
when IPPROTO_FRAGMENT
|
84
|
+
Pcap.assert bytes.length >= 8,
|
85
|
+
"Truncated IPv6 fragment header"
|
86
|
+
Pcap.assert false, 'IPv6 fragments are not supported'
|
87
|
+
when IPPROTO_AH
|
88
|
+
next_header, payload = ah_header_from_bytes(ipv6,
|
89
|
+
bytes, 'authentication header')
|
90
|
+
when IPPROTO_NONE
|
91
|
+
payload = ''
|
92
|
+
else
|
93
|
+
payload = bytes
|
94
|
+
end
|
95
|
+
rescue ParseError => e
|
96
|
+
Pcap.warning e
|
97
|
+
payload = bytes
|
98
|
+
end
|
99
|
+
return [next_header, payload]
|
100
|
+
end
|
101
|
+
|
102
|
+
# Parse extension header that's a multiple of 8 bytes
|
103
|
+
def self.eight_byte_header_from_bytes ipv6, bytes, name
|
104
|
+
Pcap.assert bytes.length >= 8, "Truncated IPv6 #{name} header"
|
105
|
+
length = (bytes[1].ord + 1) * 8
|
106
|
+
Pcap.assert bytes.length >= length, "Truncated IPv6 #{name} header"
|
107
|
+
return payload_from_bytes(ipv6, bytes[0].ord, bytes[length..-1])
|
108
|
+
end
|
109
|
+
|
110
|
+
# Parse authentication header (whose length field is interpeted differently)
|
111
|
+
def self.ah_header_from_bytes ipv6, bytes, name
|
112
|
+
Pcap.assert bytes.length >= 8, "Truncated IPv6 #{name} header"
|
113
|
+
length = (bytes[1].ord + 2) * 4
|
114
|
+
Pcap.assert bytes.length >= length, "Truncated IPv6 #{name} header"
|
115
|
+
return payload_from_bytes(ipv6, bytes[0].ord, bytes[length..-1])
|
116
|
+
end
|
117
|
+
|
118
|
+
def write io
|
119
|
+
if @payload.is_a? String
|
120
|
+
payload = @payload
|
121
|
+
else
|
122
|
+
string_io = StringIO.new
|
123
|
+
@payload.write string_io, self
|
124
|
+
payload = string_io.string
|
125
|
+
end
|
126
|
+
src = IPAddr.new(@src, Socket::AF_INET6).hton
|
127
|
+
dst = IPAddr.new(@dst, Socket::AF_INET6).hton
|
128
|
+
header = [0x60000000, payload.length, @next_header, @hop_limit,
|
129
|
+
src, dst].pack FORMAT
|
130
|
+
io.write header
|
131
|
+
io.write payload
|
132
|
+
end
|
133
|
+
|
134
|
+
def pseudo_header payload_length
|
135
|
+
return IPAddr.new(@src, Socket::AF_INET6).hton +
|
136
|
+
IPAddr.new(@dst, Socket::AF_INET6).hton +
|
137
|
+
[payload_length, '', @next_header].pack('Na3C')
|
138
|
+
end
|
139
|
+
|
140
|
+
def == other
|
141
|
+
return super &&
|
142
|
+
self.next_header == other.next_header &&
|
143
|
+
self.hop_limit == other.hop_limit
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# http://www.mudynamics.com
|
2
|
+
# http://labs.mudynamics.com
|
3
|
+
# http://www.pcapr.net
|
4
|
+
|
5
|
+
module Mu
|
6
|
+
class Pcap
|
7
|
+
|
8
|
+
class Packet
|
9
|
+
attr_accessor :payload, :payload_raw
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@payload = ''
|
13
|
+
@payload_raw = ''
|
14
|
+
end
|
15
|
+
|
16
|
+
# Get payload as bytes. If the payload is a parsed object, returns
|
17
|
+
# raw payload. Otherwise return unparsed bytes.
|
18
|
+
def payload_bytes
|
19
|
+
if @payload.is_a? String
|
20
|
+
return @payload
|
21
|
+
end
|
22
|
+
return @payload_raw
|
23
|
+
end
|
24
|
+
|
25
|
+
def deepdup
|
26
|
+
dup = self.dup
|
27
|
+
if @payload.respond_to? :deepdup
|
28
|
+
dup.payload = @payload.deepdup
|
29
|
+
else
|
30
|
+
dup.payload = @payload.dup
|
31
|
+
end
|
32
|
+
return dup
|
33
|
+
end
|
34
|
+
|
35
|
+
def flow_id
|
36
|
+
raise NotImplementedError
|
37
|
+
end
|
38
|
+
|
39
|
+
# Reassemble, reorder, and merge packets.
|
40
|
+
def self.normalize packets
|
41
|
+
begin
|
42
|
+
packets = TCP.reorder packets
|
43
|
+
rescue TCP::ReorderError => e
|
44
|
+
Pcap.warning e
|
45
|
+
end
|
46
|
+
|
47
|
+
begin
|
48
|
+
packets = SCTP.reorder packets
|
49
|
+
rescue SCTP::ReorderError => e
|
50
|
+
Pcap.warning e
|
51
|
+
end
|
52
|
+
|
53
|
+
begin
|
54
|
+
packets = TCP.merge packets
|
55
|
+
rescue TCP::MergeError => e
|
56
|
+
Pcap.warning e
|
57
|
+
end
|
58
|
+
return packets
|
59
|
+
end
|
60
|
+
|
61
|
+
# Remove non-L7/DNS/DHCP traffic if there is L7 traffic. Returns
|
62
|
+
# original packets if there is no L7 traffic.
|
63
|
+
IGNORE_UDP_PORTS = [
|
64
|
+
53, # DNS
|
65
|
+
67, 68, # DHCP
|
66
|
+
546, 547 # DHCPv6
|
67
|
+
]
|
68
|
+
def self.isolate_l7 packets
|
69
|
+
cleaned_packets = []
|
70
|
+
packets.each do |packet|
|
71
|
+
if TCP.tcp? packet
|
72
|
+
cleaned_packets << packet
|
73
|
+
elsif UDP.udp? packet
|
74
|
+
src_port = packet.payload.payload.src_port
|
75
|
+
dst_port = packet.payload.payload.dst_port
|
76
|
+
if not IGNORE_UDP_PORTS.member? src_port and
|
77
|
+
not IGNORE_UDP_PORTS.member? dst_port
|
78
|
+
cleaned_packets << packet
|
79
|
+
end
|
80
|
+
elsif SCTP.sctp? packet
|
81
|
+
cleaned_packets << packet
|
82
|
+
end
|
83
|
+
end
|
84
|
+
if cleaned_packets.empty?
|
85
|
+
return packets
|
86
|
+
end
|
87
|
+
return cleaned_packets
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_bytes
|
91
|
+
io = StringIO.new
|
92
|
+
write io
|
93
|
+
io.close
|
94
|
+
return io.string
|
95
|
+
end
|
96
|
+
|
97
|
+
def == other
|
98
|
+
return self.class == other.class && self.payload == other.payload &&
|
99
|
+
self.payload_raw == other.payload_raw
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# http://www.mudynamics.com
|
2
|
+
# http://labs.mudynamics.com
|
3
|
+
# http://www.pcapr.net
|
4
|
+
|
5
|
+
module Mu
|
6
|
+
class Pcap
|
7
|
+
|
8
|
+
class Pkthdr
|
9
|
+
attr_accessor :endian, :ts_sec, :ts_usec, :caplen, :len, :pkt, :pkt_raw
|
10
|
+
|
11
|
+
def initialize endian=BIG_ENDIAN, ts_sec=0, ts_usec=0, caplen=0, len=0, pkt=nil
|
12
|
+
@endian = endian
|
13
|
+
@ts_sec = ts_sec
|
14
|
+
@ts_usec = ts_usec
|
15
|
+
@caplen = caplen
|
16
|
+
@len = len
|
17
|
+
@pkt = pkt
|
18
|
+
@pkt_raw = pkt
|
19
|
+
end
|
20
|
+
|
21
|
+
FMT_NNNN = 'NNNN'
|
22
|
+
FMT_VVVV = 'VVVV'
|
23
|
+
def self.read io, endian=BIG_ENDIAN
|
24
|
+
if endian == BIG_ENDIAN
|
25
|
+
format = FMT_NNNN
|
26
|
+
elsif endian == LITTLE_ENDIAN
|
27
|
+
format = FMT_VVVV
|
28
|
+
end
|
29
|
+
bytes = io.read 16
|
30
|
+
if not bytes
|
31
|
+
raise EOFError, 'Missing PCAP packet header'
|
32
|
+
end
|
33
|
+
if not bytes.length == 16
|
34
|
+
raise ParseError, "Truncated PCAP packet header: expected 16 bytes, got #{bytes.length} bytes"
|
35
|
+
end
|
36
|
+
ts_sec, ts_usec, caplen, len = bytes.unpack format
|
37
|
+
pkt = io.read(caplen)
|
38
|
+
if not pkt
|
39
|
+
raise ParseError, 'Missing PCAP packet header packet'
|
40
|
+
end
|
41
|
+
if not pkt.length == caplen
|
42
|
+
raise ParseError, "Truncated PCAP packet header: expected #{pkthdr.caplen} bytes, got #{pkthdr.pkt.length} bytes"
|
43
|
+
end
|
44
|
+
pkthdr = Pkthdr.new endian, ts_sec, ts_usec, caplen, len, pkt
|
45
|
+
return pkthdr
|
46
|
+
end
|
47
|
+
|
48
|
+
def write io
|
49
|
+
if @pkt.is_a? String
|
50
|
+
pkt = @pkt
|
51
|
+
else
|
52
|
+
string_io = StringIO.new
|
53
|
+
@pkt.write string_io
|
54
|
+
pkt = string_io.string
|
55
|
+
end
|
56
|
+
len = pkt.length
|
57
|
+
bytes = [@ts_sec, @ts_usec, len, len].pack FMT_NNNN
|
58
|
+
io.write bytes
|
59
|
+
io.write pkt
|
60
|
+
end
|
61
|
+
|
62
|
+
def decode! endian, linktype
|
63
|
+
@pkt = case linktype
|
64
|
+
when DLT_NULL; Pkthdr.decode_null endian, @pkt
|
65
|
+
when DLT_EN10MB; Pkthdr.decode_en10mb @pkt
|
66
|
+
when DLT_RAW; raise NotImplementedError
|
67
|
+
when DLT_LINUX_SLL; Pkthdr.decode_linux_sll @pkt
|
68
|
+
else raise ParseError, "Unknown PCAP linktype: #{linktype}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# See http://wiki.wireshark.org/NullLoopback
|
73
|
+
# and epan/aftypes.h in wireshark code.
|
74
|
+
BSD_AF_INET6 = [
|
75
|
+
OPENBSD_AF_INET6 = 24,
|
76
|
+
FREEBSD_AF_INET6 = 28,
|
77
|
+
DARWIN_AF_INET6 = 30
|
78
|
+
]
|
79
|
+
|
80
|
+
def self.decode_null endian, bytes
|
81
|
+
Pcap.assert bytes.length >= 4, 'Truncated PCAP packet header: ' +
|
82
|
+
"expected at least 4 bytes, got #{bytes.length} bytes"
|
83
|
+
if endian == BIG_ENDIAN
|
84
|
+
format = 'N'
|
85
|
+
elsif endian == LITTLE_ENDIAN
|
86
|
+
format = 'V'
|
87
|
+
end
|
88
|
+
family = bytes[0, 4].unpack(format)[0]
|
89
|
+
bytes = bytes[4..-1]
|
90
|
+
ethernet = Ethernet.new
|
91
|
+
ethernet.src = '00:01:01:00:00:01'
|
92
|
+
ethernet.dst = '00:01:01:00:00:02'
|
93
|
+
ethernet.payload = ethernet.payload_raw = bytes
|
94
|
+
if family != Socket::AF_INET and family != Socket::AF_INET6 and
|
95
|
+
not BSD_AF_INET6.include?(family)
|
96
|
+
raise ParseError, "Unknown PCAP packet header family: #{family}"
|
97
|
+
end
|
98
|
+
begin
|
99
|
+
case family
|
100
|
+
when Socket::AF_INET
|
101
|
+
ethernet.type = Ethernet::ETHERTYPE_IP
|
102
|
+
ethernet.payload = IPv4.from_bytes ethernet.payload
|
103
|
+
when Socket::AF_INET6, FREEBSD_AF_INET6, OPENBSD_AF_INET6, DARWIN_AF_INET6
|
104
|
+
ethernet.type = Ethernet::ETHERTYPE_IP6
|
105
|
+
ethernet.payload = IPv6.from_bytes ethernet.payload
|
106
|
+
else
|
107
|
+
raise NotImplementedError
|
108
|
+
end
|
109
|
+
rescue ParseError => e
|
110
|
+
Pcap.warning e
|
111
|
+
end
|
112
|
+
return ethernet
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.decode_en10mb bytes
|
116
|
+
return Ethernet.from_bytes(bytes)
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.decode_linux_sll bytes
|
120
|
+
Pcap.assert bytes.length >= 16, 'Truncated PCAP packet header: ' +
|
121
|
+
"expected at least 16 bytes, got #{bytes.length} bytes"
|
122
|
+
packet_type, link_type, addr_len = bytes.unpack('nnn')
|
123
|
+
type = bytes[14, 2].unpack('n')[0]
|
124
|
+
bytes = bytes[16..-1]
|
125
|
+
ethernet = Ethernet.new
|
126
|
+
ethernet.type = type
|
127
|
+
ethernet.src = '00:01:01:00:00:01'
|
128
|
+
ethernet.dst = '00:01:01:00:00:02'
|
129
|
+
ethernet.payload = ethernet.payload_raw = bytes
|
130
|
+
begin
|
131
|
+
case type
|
132
|
+
when Ethernet::ETHERTYPE_IP
|
133
|
+
ethernet.payload = IPv4.from_bytes ethernet.payload
|
134
|
+
when Ethernet::ETHERTYPE_IP6
|
135
|
+
ethernet.payload = IPv6.from_bytes ethernet.payload
|
136
|
+
end
|
137
|
+
rescue ParseError => e
|
138
|
+
Pcap.warning e
|
139
|
+
end
|
140
|
+
return ethernet
|
141
|
+
end
|
142
|
+
|
143
|
+
def == other
|
144
|
+
return self.class == other.class &&
|
145
|
+
self.endian == other.endian &&
|
146
|
+
self.ts_sec == other.ts_sec &&
|
147
|
+
self.ts_usec == other.ts_usec &&
|
148
|
+
self.caplen == other.caplen &&
|
149
|
+
self.len == other.len &&
|
150
|
+
self.pkt == other.pkt
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# http://www.mudynamics.com
|
2
|
+
# http://labs.mudynamics.com
|
3
|
+
# http://www.pcapr.net
|
4
|
+
|
5
|
+
module Mu
|
6
|
+
class Pcap
|
7
|
+
|
8
|
+
class Reader
|
9
|
+
attr_accessor :pcap2scenario
|
10
|
+
|
11
|
+
FAMILY_TO_READER = {}
|
12
|
+
|
13
|
+
# Returns a reader instance of specified family. Returns nil when family is :none.
|
14
|
+
def self.reader family
|
15
|
+
if family == :none
|
16
|
+
return nil
|
17
|
+
end
|
18
|
+
|
19
|
+
if klass = FAMILY_TO_READER[family]
|
20
|
+
return klass.new
|
21
|
+
end
|
22
|
+
|
23
|
+
raise ArgumentError, "Unknown protocol family: '#{family}'"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns family name
|
27
|
+
def family
|
28
|
+
raise NotImplementedError
|
29
|
+
end
|
30
|
+
|
31
|
+
# Notify parser of bytes written. Parser may update state
|
32
|
+
# to serve as a hint for subsequent reads.
|
33
|
+
def record_write bytes, state=nil
|
34
|
+
begin
|
35
|
+
do_record_write bytes, state
|
36
|
+
rescue
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns next complete message from byte stream or nil.
|
42
|
+
def read_message bytes, state=nil
|
43
|
+
read_message! bytes.dup, state
|
44
|
+
end
|
45
|
+
|
46
|
+
# Mutating form of read_message. Removes a complete message
|
47
|
+
# from input stream. Returns the message or nil if there.
|
48
|
+
# is not a complete message.
|
49
|
+
def read_message! bytes, state=nil
|
50
|
+
begin
|
51
|
+
do_read_message! bytes, state
|
52
|
+
rescue
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
require 'mu/pcap/reader/http_family'
|