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
-
.file_to_array(fname) ⇒ Object
Takes a filename, and an optional block.
-
.read(fname, &block) ⇒ Object
Takes a given file name, and reads out the packets.
-
.read_packet_bytes(fname, &block) ⇒ Object
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.
-
#read_packet_bytes(fname = @filename, &block) ⇒ Object
Calls the class method with this object’s @filename.
-
#read_packets(fname = @filename, &block) ⇒ Object
Calls the class method with this object’s @filename.
-
#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.
323 324 325 326 327 |
# File 'lib/packetfu/pcap.rb', line 323 def initialize(args={}) init_fields(args) @filename = args.delete :filename super(args[:endian], args[:head], args[:body]) end |
Instance Attribute Details
#body ⇒ Object
Returns the value of attribute body
238 239 240 |
# File 'lib/packetfu/pcap.rb', line 238 def body @body end |
#endian ⇒ Object
Returns the value of attribute endian
238 239 240 |
# File 'lib/packetfu/pcap.rb', line 238 def endian @endian end |
#head ⇒ Object
Returns the value of attribute head
238 239 240 |
# File 'lib/packetfu/pcap.rb', line 238 def head @head end |
Class Method Details
.file_to_array(fname) ⇒ Object
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.
245 246 247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/packetfu/pcap.rb', line 245 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(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.
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 276 277 278 279 280 |
# File 'lib/packetfu/pcap.rb', line 251 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 if block yield pcap_packet else pcap_packets << pcap_packet.clone end end ensure file_handle.close end block ? packet_count : pcap_packets end |
.read_packet_bytes(fname, &block) ⇒ Object
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.
285 286 287 288 289 290 291 292 293 294 295 296 297 |
# File 'lib/packetfu/pcap.rb', line 285 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.
307 308 309 310 311 312 313 314 315 316 317 318 319 |
# File 'lib/packetfu/pcap.rb', line 307 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’
498 499 500 501 502 503 504 505 |
# File 'lib/packetfu/pcap.rb', line 498 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.
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
# File 'lib/packetfu/pcap.rb', line 408 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.dup 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.
454 455 456 457 |
# File 'lib/packetfu/pcap.rb', line 454 def array_to_file!(arr) clear array_to_file(arr) end |
#clear ⇒ Object
Clears the contents of the PcapFile.
342 343 344 |
# File 'lib/packetfu/pcap.rb', line 342 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.
386 387 388 389 390 391 392 393 394 395 396 |
# File 'lib/packetfu/pcap.rb', line 386 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.
330 331 332 333 334 |
# File 'lib/packetfu/pcap.rb', line 330 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.
348 349 350 351 352 353 |
# File 'lib/packetfu/pcap.rb', line 348 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.
356 357 358 359 360 |
# File 'lib/packetfu/pcap.rb', line 356 def read!(str) clear force_binary(str) self.read str end |
#read_packet_bytes(fname = @filename, &block) ⇒ Object
Calls the class method with this object’s @filename
371 372 373 374 |
# File 'lib/packetfu/pcap.rb', line 371 def read_packet_bytes(fname=@filename,&block) raise ArgumentError, "Need a file" unless fname return self.class.read_packet_bytes(fname, &block) end |
#read_packets(fname = @filename, &block) ⇒ Object
Calls the class method with this object’s @filename
377 378 379 380 |
# File 'lib/packetfu/pcap.rb', line 377 def read_packets(fname=@filename,&block) raise ArgumentError, "Need a file" unless fname return self.class.read_packets(fname, &block) 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.
365 366 367 368 |
# File 'lib/packetfu/pcap.rb', line 365 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.
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 |
# File 'lib/packetfu/pcap.rb', line 465 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.exist? 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.
337 338 339 |
# File 'lib/packetfu/pcap.rb', line 337 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’
487 488 489 490 491 492 493 494 |
# File 'lib/packetfu/pcap.rb', line 487 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 |