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,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'