Class: PacketFu::PcapFile
- Includes:
- StructFu
- Defined in:
- lib/packetfu/pcap.rb
Overview
PcapFile is a complete libpcap file struct, made up of two elements, a PcapHeader and PcapPackets.
See wiki.wireshark.org/Development/LibpcapFileFormat
PcapFile also can behave as a singleton class, which is usually the better way to handle pcap files of really any size, since it doesn’t require storing packets before handing them off to a given block. This is really the way to go.
Instance Attribute Summary collapse
-
#body ⇒ Object
Returns the value of attribute body.
-
#endian ⇒ Object
Returns the value of attribute endian.
-
#head ⇒ Object
Returns the value of attribute head.
Class Method Summary collapse
-
.read(fname, &block) ⇒ Object
Takes a given file name, and reads out the packets.
-
.read_packet_bytes(fname, &block) ⇒ Object
(also: file_to_array)
Takes a filename, and an optional block.
-
.read_packets(fname, &block) ⇒ Object
Takes a filename, and an optional block.
Instance Method Summary collapse
-
#append(filename = 'out.pcap') ⇒ Object
Shorthand method for appending to a file.
-
#array_to_file(args = {}) ⇒ Object
(also: #a2f)
Takes an array of packets (as generated by file_to_array), and writes them to a file.
-
#array_to_file!(arr) ⇒ Object
(also: #a2f!)
Just like array_to_file, but clears any existing packets from the array first.
-
#clear ⇒ Object
Clears the contents of the PcapFile.
-
#file_to_array(args = {}) ⇒ Object
(also: #f2a)
file_to_array() translates a libpcap file into an array of packets.
-
#init_fields(args = {}) ⇒ Object
Called by initialize to set the initial fields.
-
#initialize(args = {}) ⇒ PcapFile
constructor
A new instance of PcapFile.
-
#read(str) ⇒ Object
Reads a string to populate the object.
-
#read!(str) ⇒ Object
Clears the contents of the PcapFile prior to reading in a new string.
-
#readfile(file) ⇒ Object
A shorthand method for opening a file and reading in the packets.
-
#to_file(args = {}) ⇒ Object
(also: #to_f)
Writes the PcapFile to a file.
-
#to_s ⇒ Object
Returns the object in string form.
-
#write(filename = 'out.pcap') ⇒ Object
Shorthand method for writing to a file.
Methods included from StructFu
#clone, #set_endianness, #sz, #typecast
Methods inherited from Struct
Constructor Details
#initialize(args = {}) ⇒ PcapFile
Returns a new instance of PcapFile.
318 319 320 321 |
# File 'lib/packetfu/pcap.rb', line 318 def initialize(args={}) init_fields(args) super(args[:endian], args[:head], args[:body]) end |
Instance Attribute Details
#body ⇒ Object
Returns the value of attribute body
236 237 238 |
# File 'lib/packetfu/pcap.rb', line 236 def body @body end |
#endian ⇒ Object
Returns the value of attribute endian
236 237 238 |
# File 'lib/packetfu/pcap.rb', line 236 def endian @endian end |
#head ⇒ Object
Returns the value of attribute head
236 237 238 |
# File 'lib/packetfu/pcap.rb', line 236 def head @head end |
Class Method Details
.read(fname, &block) ⇒ Object
Takes a given file name, and reads out the packets. If given a block, it will yield back a PcapPacket object per packet found.
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/packetfu/pcap.rb', line 249 def read(fname,&block) file_header = PcapHeader.new pcap_packets = PcapPackets.new unless File.readable? fname raise ArgumentError, "Cannot read file `#{fname}'" end begin file_handle = File.open(fname, "rb") file_header.read file_handle.read(24) packet_count = 0 pcap_packet = PcapPacket.new(:endian => file_header.endian) while pcap_packet.read file_handle.read(16) do len = pcap_packet.incl_len pcap_packet.data = StructFu::String.new.read(file_handle.read(len.to_i)) packet_count += 1 if pcap_packet.data.size < len.to_i warn "Packet ##{packet_count} is corrupted: expected #{len.to_i}, got #{pcap_packet.data.size}. Exiting." break end pcap_packets << pcap_packet.clone yield pcap_packets.last if block end ensure file_handle.close end block ? packet_count : pcap_packets end |
.read_packet_bytes(fname, &block) ⇒ Object Also known as: file_to_array
Takes a filename, and an optional block. If a block is given, yield back the raw packet data from the given file. Otherwise, return an array of parsed packets.
280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/packetfu/pcap.rb', line 280 def read_packet_bytes(fname,&block) count = 0 packets = [] unless block read(fname) do |packet| if block count += 1 yield packet.data.to_s else packets << packet.data.to_s end end block ? count : packets end |
.read_packets(fname, &block) ⇒ Object
Takes a filename, and an optional block. If a block is given, yield back parsed packets from the given file. Otherwise, return an array of parsed packets.
This is a brazillian times faster than the old methods of extracting packets from files.
302 303 304 305 306 307 308 309 310 311 312 313 314 |
# File 'lib/packetfu/pcap.rb', line 302 def read_packets(fname,&block) count = 0 packets = [] unless block read_packet_bytes(fname) do |packet| if block count += 1 yield Packet.parse(packet) else packets << Packet.parse(packet) end end block ? count : packets end |
Instance Method Details
#append(filename = 'out.pcap') ⇒ Object
Shorthand method for appending to a file. Can take either :file => ‘name.pcap’ or simply ‘name.pcap’
480 481 482 483 484 485 486 487 |
# File 'lib/packetfu/pcap.rb', line 480 def append(filename='out.pcap') if filename.kind_of?(Hash) f = filename[:filename] || filename[:file] || filename[:f] || 'out.pcap' else f = filename.to_s end self.to_file(:filename => f, :append => true) end |
#array_to_file(args = {}) ⇒ Object Also known as: a2f
Takes an array of packets (as generated by file_to_array), and writes them to a file. Valid arguments are:
:filename
:array # Can either be an array of packet data, or a hash-value pair of timestamp => data.
:timestamp # Sets an initial timestamp
:ts_inc # Sets the increment between timestamps. Defaults to 1 second.
:append # If true, then the packets are appended to the end of a file.
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 |
# File 'lib/packetfu/pcap.rb', line 390 def array_to_file(args={}) if args.kind_of? Hash filename = args[:filename] || args[:file] || args[:f] arr = args[:array] || args[:arr] || args[:a] ts = args[:timestamp] || args[:ts] || Time.now.to_i ts_inc = args[:timestamp_increment] || args[:ts_inc] || 1 append = !!args[:append] elsif args.kind_of? Array arr = args filename = append = nil else raise ArgumentError, "Unknown argument. Need either a Hash or Array." end unless arr.kind_of? Array raise ArgumentError, "Need an array to read packets from" end arr.each_with_index do |p,i| if p.kind_of? Hash # Binary timestamps are included this_ts = p.keys.first this_incl_len = p.values.first.size this_orig_len = this_incl_len this_data = p.values.first else # it's an array this_ts = Timestamp.new(:endian => self[:endian], :sec => ts + (ts_inc * i)).to_s this_incl_len = p.to_s.size this_orig_len = this_incl_len this_data = p.to_s end this_pkt = PcapPacket.new({:endian => self[:endian], :timestamp => this_ts, :incl_len => this_incl_len, :orig_len => this_orig_len, :data => this_data } ) self[:body] << this_pkt end if filename self.to_f(:filename => filename, :append => append) else self end end |
#array_to_file!(arr) ⇒ Object Also known as: a2f!
Just like array_to_file, but clears any existing packets from the array first.
436 437 438 439 |
# File 'lib/packetfu/pcap.rb', line 436 def array_to_file!(arr) clear array_to_file(arr) end |
#clear ⇒ Object
Clears the contents of the PcapFile.
336 337 338 |
# File 'lib/packetfu/pcap.rb', line 336 def clear self[:body].clear end |
#file_to_array(args = {}) ⇒ Object Also known as: f2a
file_to_array() translates a libpcap file into an array of packets. Note that this strips out pcap timestamps – if you’d like to retain timestamps and other libpcap file information, you will want to use read() instead.
368 369 370 371 372 373 374 375 376 377 378 |
# File 'lib/packetfu/pcap.rb', line 368 def file_to_array(args={}) filename = args[:filename] || args[:file] || args[:f] if filename self.read! File.open(filename, "rb") {|f| f.read} end if args[:keep_timestamps] || args[:keep_ts] || args[:ts] self[:body].map {|x| {x..to_s => x.data.to_s} } else self[:body].map {|x| x.data.to_s} end end |
#init_fields(args = {}) ⇒ Object
Called by initialize to set the initial fields.
324 325 326 327 328 |
# File 'lib/packetfu/pcap.rb', line 324 def init_fields(args={}) args[:head] = PcapHeader.new(:endian => args[:endian]).read(args[:head]) args[:body] = PcapPackets.new(:endian => args[:endian]).read(args[:body]) return args end |
#read(str) ⇒ Object
Reads a string to populate the object. Note that this appends new packets to any existing packets in the PcapFile.
342 343 344 345 346 347 |
# File 'lib/packetfu/pcap.rb', line 342 def read(str) force_binary(str) self[:head].read str[0,24] self[:body].read str self end |
#read!(str) ⇒ Object
Clears the contents of the PcapFile prior to reading in a new string.
350 351 352 353 354 |
# File 'lib/packetfu/pcap.rb', line 350 def read!(str) clear force_binary(str) self.read str end |
#readfile(file) ⇒ Object
A shorthand method for opening a file and reading in the packets. Note that readfile clears any existing packets, since that seems to be the typical use.
359 360 361 362 |
# File 'lib/packetfu/pcap.rb', line 359 def readfile(file) fdata = File.open(file, "rb") {|f| f.read} self.read! fdata end |
#to_file(args = {}) ⇒ Object Also known as: to_f
Writes the PcapFile to a file. Takes the following arguments:
:filename # The file to write to.
:append # If set to true, the packets are appended to the file, rather than overwriting.
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 |
# File 'lib/packetfu/pcap.rb', line 447 def to_file(args={}) filename = args[:filename] || args[:file] || args[:f] unless (!filename.nil? || filename.kind_of?(String)) raise ArgumentError, "Need a :filename for #{self.class}" end append = args[:append] if append if File.exists? filename File.open(filename,'ab') {|file| file.write(self.body.to_s)} else File.open(filename,'wb') {|file| file.write(self.to_s)} end else File.open(filename,'wb') {|file| file.write(self.to_s)} end [filename, self.body.sz, self.body.size] end |
#to_s ⇒ Object
Returns the object in string form.
331 332 333 |
# File 'lib/packetfu/pcap.rb', line 331 def to_s self[:head].to_s + self[:body].map {|p| p.to_s}.join end |
#write(filename = 'out.pcap') ⇒ Object
Shorthand method for writing to a file. Can take either :file => ‘name.pcap’ or simply ‘name.pcap’
469 470 471 472 473 474 475 476 |
# File 'lib/packetfu/pcap.rb', line 469 def write(filename='out.pcap') if filename.kind_of?(Hash) f = filename[:filename] || filename[:file] || filename[:f] || 'out.pcap' else f = filename.to_s end self.to_file(:filename => f.to_s, :append => false) end |