packetfu 1.1.2 → 1.1.3

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.
Files changed (67) hide show
  1. data/.gitignore +3 -0
  2. data/INSTALL.rdoc +40 -0
  3. data/LICENSE.txt +25 -0
  4. data/examples/100kpackets.rb +41 -0
  5. data/examples/ackscan.rb +38 -0
  6. data/examples/arp.rb +60 -0
  7. data/examples/arphood.rb +59 -0
  8. data/examples/dissect_thinger.rb +22 -0
  9. data/examples/ethernet.rb +10 -0
  10. data/examples/examples.rb +3 -0
  11. data/examples/ids.rb +4 -0
  12. data/examples/idsv2.rb +6 -0
  13. data/examples/new-simple-stats.rb +52 -0
  14. data/examples/oui.txt +84177 -0
  15. data/examples/packetfu-shell.rb +113 -0
  16. data/examples/simple-sniffer.rb +40 -0
  17. data/examples/simple-stats.rb +50 -0
  18. data/examples/slammer.rb +33 -0
  19. data/examples/uniqpcap.rb +15 -0
  20. data/lib/packetfu.rb +147 -0
  21. data/lib/packetfu/capture.rb +169 -0
  22. data/lib/packetfu/config.rb +58 -0
  23. data/lib/packetfu/inject.rb +65 -0
  24. data/lib/packetfu/packet.rb +533 -0
  25. data/lib/packetfu/pcap.rb +594 -0
  26. data/lib/packetfu/protos/arp.rb +268 -0
  27. data/lib/packetfu/protos/eth.rb +296 -0
  28. data/lib/packetfu/protos/hsrp.rb +206 -0
  29. data/lib/packetfu/protos/icmp.rb +179 -0
  30. data/lib/packetfu/protos/invalid.rb +55 -0
  31. data/lib/packetfu/protos/ip.rb +378 -0
  32. data/lib/packetfu/protos/ipv6.rb +250 -0
  33. data/lib/packetfu/protos/tcp.rb +1127 -0
  34. data/lib/packetfu/protos/udp.rb +240 -0
  35. data/lib/packetfu/structfu.rb +294 -0
  36. data/lib/packetfu/utils.rb +194 -0
  37. data/lib/packetfu/version.rb +50 -0
  38. data/packetfu.gemspec +21 -0
  39. data/setup.rb +1586 -0
  40. data/test/all_tests.rb +41 -0
  41. data/test/ethpacket_spec.rb +74 -0
  42. data/test/packet_spec.rb +73 -0
  43. data/test/packet_subclasses_spec.rb +13 -0
  44. data/test/packetfu_spec.rb +90 -0
  45. data/test/ptest.rb +16 -0
  46. data/test/sample-ipv6.pcap +0 -0
  47. data/test/sample.pcap +0 -0
  48. data/test/sample2.pcap +0 -0
  49. data/test/sample_hsrp_pcapr.cap +0 -0
  50. data/test/structfu_spec.rb +335 -0
  51. data/test/tcp_spec.rb +101 -0
  52. data/test/test_arp.rb +135 -0
  53. data/test/test_eth.rb +91 -0
  54. data/test/test_hsrp.rb +20 -0
  55. data/test/test_icmp.rb +54 -0
  56. data/test/test_inject.rb +31 -0
  57. data/test/test_invalid.rb +28 -0
  58. data/test/test_ip.rb +69 -0
  59. data/test/test_ip6.rb +68 -0
  60. data/test/test_octets.rb +37 -0
  61. data/test/test_packet.rb +174 -0
  62. data/test/test_pcap.rb +209 -0
  63. data/test/test_structfu.rb +112 -0
  64. data/test/test_tcp.rb +327 -0
  65. data/test/test_udp.rb +73 -0
  66. data/test/vlan-pcapr.cap +0 -0
  67. metadata +85 -6
@@ -0,0 +1,594 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module StructFu
4
+
5
+ # Set the endianness for the various Int classes. Takes either :little or :big.
6
+ def set_endianness(e=nil)
7
+ unless [:little, :big].include? e
8
+ raise ArgumentError, "Unknown endianness for #{self.class}"
9
+ end
10
+ @int32 = e == :little ? Int32le : Int32be
11
+ @int16 = e == :little ? Int16le : Int16be
12
+ return e
13
+ end
14
+
15
+ # Instead of returning the "size" of the object, which is usually the
16
+ # number of elements of the Struct, returns the size of the object after
17
+ # a to_s. Essentially, a short version of self.to_size.size
18
+ def sz
19
+ self.to_s.size
20
+ end
21
+
22
+ end
23
+
24
+ module PacketFu
25
+
26
+ # PcapHeader represents the header portion of a libpcap file (the packets
27
+ # themselves are in the PcapPackets array). See
28
+ # http://wiki.wireshark.org/Development/LibpcapFileFormat for details.
29
+ #
30
+ # Depending on the endianness (set with :endian), elements are either
31
+ # :little endian or :big endian.
32
+ #
33
+ # ==== PcapHeader Definition
34
+ #
35
+ # Symbol :endian Default: :little
36
+ # Int32 :magic Default: 0xa1b2c3d4 # :big is 0xd4c3b2a1
37
+ # Int16 :ver_major Default: 2
38
+ # Int16 :ver_minor Default: 4
39
+ # Int32 :thiszone
40
+ # Int32 :sigfigs
41
+ # Int32 :snaplen Default: 0xffff
42
+ # Int32 :network Default: 1
43
+ class PcapHeader < Struct.new(:endian, :magic, :ver_major, :ver_minor,
44
+ :thiszone, :sigfigs, :snaplen, :network)
45
+ include StructFu
46
+
47
+ MAGIC_INT32 = 0xa1b2c3d4
48
+ MAGIC_LITTLE = [MAGIC_INT32].pack("V")
49
+ MAGIC_BIG = [MAGIC_INT32].pack("N")
50
+
51
+ def initialize(args={})
52
+ set_endianness(args[:endian] ||= :little)
53
+ init_fields(args)
54
+ super(args[:endian], args[:magic], args[:ver_major],
55
+ args[:ver_minor], args[:thiszone], args[:sigfigs],
56
+ args[:snaplen], args[:network])
57
+ end
58
+
59
+ # Called by initialize to set the initial fields.
60
+ def init_fields(args={})
61
+ args[:magic] = @int32.new(args[:magic] || PcapHeader::MAGIC_INT32)
62
+ args[:ver_major] = @int16.new(args[:ver_major] || 2)
63
+ args[:ver_minor] ||= @int16.new(args[:ver_minor] || 4)
64
+ args[:thiszone] ||= @int32.new(args[:thiszone])
65
+ args[:sigfigs] ||= @int32.new(args[:sigfigs])
66
+ args[:snaplen] ||= @int32.new(args[:snaplen] || 0xffff)
67
+ args[:network] ||= @int32.new(args[:network] || 1)
68
+ return args
69
+ end
70
+
71
+ # Returns the object in string form.
72
+ def to_s
73
+ self.to_a[1,7].map {|x| x.to_s}.join
74
+ end
75
+
76
+ # Reads a string to populate the object.
77
+ # TODO: Need to test this by getting a hold of a big endian pcap file.
78
+ # Conversion from big to little shouldn't be that big of a deal.
79
+ def read(str)
80
+ force_binary(str)
81
+ return self if str.nil?
82
+ str.force_encoding("binary") if str.respond_to? :force_encoding
83
+ if str[0,4] == self[:magic].to_s
84
+ self[:magic].read str[0,4]
85
+ self[:ver_major].read str[4,2]
86
+ self[:ver_minor].read str[6,2]
87
+ self[:thiszone].read str[8,4]
88
+ self[:sigfigs].read str[12,4]
89
+ self[:snaplen].read str[16,4]
90
+ self[:network].read str[20,4]
91
+ else
92
+ raise "Incorrect magic for libpcap"
93
+ end
94
+ self
95
+ end
96
+
97
+ end
98
+
99
+ # The Timestamp class defines how Timestamps appear in libpcap files.
100
+ #
101
+ # ==== Header Definition
102
+ #
103
+ # Symbol :endian Default: :little
104
+ # Int32 :sec
105
+ # Int32 :usec
106
+ class Timestamp < Struct.new(:endian, :sec, :usec)
107
+ include StructFu
108
+
109
+ def initialize(args={})
110
+ set_endianness(args[:endian] ||= :little)
111
+ init_fields(args)
112
+ super(args[:endian], args[:sec], args[:usec])
113
+ end
114
+
115
+ # Called by initialize to set the initial fields.
116
+ def init_fields(args={})
117
+ args[:sec] = @int32.new(args[:sec])
118
+ args[:usec] = @int32.new(args[:usec])
119
+ return args
120
+ end
121
+
122
+ # Returns the object in string form.
123
+ def to_s
124
+ self.to_a[1,2].map {|x| x.to_s}.join
125
+ end
126
+
127
+ # Reads a string to populate the object.
128
+ def read(str)
129
+ force_binary(str)
130
+ return self if str.nil?
131
+ self[:sec].read str[0,4]
132
+ self[:usec].read str[4,4]
133
+ self
134
+ end
135
+
136
+ end
137
+
138
+ # PcapPacket defines how individual packets are stored in a libpcap-formatted
139
+ # file.
140
+ #
141
+ # ==== Header Definition
142
+ #
143
+ # Timestamp :timestamp
144
+ # Int32 :incl_len
145
+ # Int32 :orig_len
146
+ # String :data
147
+ class PcapPacket < Struct.new(:endian, :timestamp, :incl_len,
148
+ :orig_len, :data)
149
+ include StructFu
150
+ def initialize(args={})
151
+ set_endianness(args[:endian] ||= :little)
152
+ init_fields(args)
153
+ super(args[:endian], args[:timestamp], args[:incl_len],
154
+ args[:orig_len], args[:data])
155
+ end
156
+
157
+ # Called by initialize to set the initial fields.
158
+ def init_fields(args={})
159
+ args[:timestamp] = Timestamp.new(:endian => args[:endian]).read(args[:timestamp])
160
+ args[:incl_len] = args[:incl_len].nil? ? @int32.new(args[:data].to_s.size) : @int32.new(args[:incl_len])
161
+ args[:orig_len] = @int32.new(args[:orig_len])
162
+ args[:data] = StructFu::String.new.read(args[:data])
163
+ end
164
+
165
+ # Returns the object in string form.
166
+ def to_s
167
+ self.to_a[1,4].map {|x| x.to_s}.join
168
+ end
169
+
170
+ # Reads a string to populate the object.
171
+ def read(str)
172
+ return unless str
173
+ force_binary(str)
174
+ self[:timestamp].read str[0,8]
175
+ self[:incl_len].read str[8,4]
176
+ self[:orig_len].read str[12,4]
177
+ self[:data].read str[16,self[:incl_len].to_i]
178
+ self
179
+ end
180
+
181
+ end
182
+
183
+ # PcapPackets is a collection of PcapPacket objects.
184
+ class PcapPackets < Array
185
+
186
+ include StructFu
187
+
188
+ attr_accessor :endian # probably ought to be read-only but who am i.
189
+
190
+ def initialize(args={})
191
+ @endian = args[:endian] || :little
192
+ end
193
+
194
+ def force_binary(str)
195
+ str.force_encoding "binary" if str.respond_to? :force_encoding
196
+ end
197
+
198
+ # Reads a string to populate the object. Note, this read takes in the
199
+ # whole pcap file, since we need to see the magic to know what
200
+ # endianness we're dealing with.
201
+ def read(str)
202
+ force_binary(str)
203
+ return self if str.nil?
204
+ if str[0,4] == PcapHeader::MAGIC_BIG
205
+ @endian = :big
206
+ elsif str[0,4] == PcapHeader::MAGIC_LITTLE
207
+ @endian = :little
208
+ else
209
+ raise ArgumentError, "Unknown file format for #{self.class}"
210
+ end
211
+ body = str[24,str.size]
212
+ while body.size > 16 # TODO: catch exceptions on malformed packets at end
213
+ p = PcapPacket.new(:endian => @endian)
214
+ p.read(body)
215
+ self<<p
216
+ body = body[p.sz,body.size]
217
+ end
218
+ self
219
+ end
220
+
221
+ def to_s
222
+ self.join
223
+ end
224
+
225
+ end
226
+
227
+ # PcapFile is a complete libpcap file struct, made up of two elements, a
228
+ # PcapHeader and PcapPackets.
229
+ #
230
+ # See http://wiki.wireshark.org/Development/LibpcapFileFormat
231
+ #
232
+ # PcapFile also can behave as a singleton class, which is usually the better
233
+ # way to handle pcap files of really any size, since it doesn't require
234
+ # storing packets before handing them off to a given block. This is really
235
+ # the way to go.
236
+ class PcapFile < Struct.new(:endian, :head, :body)
237
+ include StructFu
238
+
239
+ class << self
240
+
241
+ # Takes a given file and returns an array of the packet bytes. Here
242
+ # for backwards compatibilty.
243
+ def file_to_array(fname)
244
+ PcapFile.new.file_to_array(:f => fname)
245
+ end
246
+
247
+ # Takes a given file name, and reads out the packets. If given a block,
248
+ # it will yield back a PcapPacket object per packet found.
249
+ def read(fname,&block)
250
+ file_header = PcapHeader.new
251
+ pcap_packets = PcapPackets.new
252
+ unless File.readable? fname
253
+ raise ArgumentError, "Cannot read file `#{fname}'"
254
+ end
255
+ begin
256
+ file_handle = File.open(fname, "rb")
257
+ file_header.read file_handle.read(24)
258
+ packet_count = 0
259
+ pcap_packet = PcapPacket.new(:endian => file_header.endian)
260
+ while pcap_packet.read file_handle.read(16) do
261
+ len = pcap_packet.incl_len
262
+ pcap_packet.data = StructFu::String.new.read(file_handle.read(len.to_i))
263
+ packet_count += 1
264
+ if pcap_packet.data.size < len.to_i
265
+ warn "Packet ##{packet_count} is corrupted: expected #{len.to_i}, got #{pcap_packet.data.size}. Exiting."
266
+ break
267
+ end
268
+ pcap_packets << pcap_packet.clone
269
+ yield pcap_packets.last if block
270
+ end
271
+ ensure
272
+ file_handle.close
273
+ end
274
+ block ? packet_count : pcap_packets
275
+ end
276
+
277
+ # Takes a filename, and an optional block. If a block is given,
278
+ # yield back the raw packet data from the given file. Otherwise,
279
+ # return an array of parsed packets.
280
+ def read_packet_bytes(fname,&block)
281
+ count = 0
282
+ packets = [] unless block
283
+ read(fname) do |packet|
284
+ if block
285
+ count += 1
286
+ yield packet.data.to_s
287
+ else
288
+ packets << packet.data.to_s
289
+ end
290
+ end
291
+ block ? count : packets
292
+ end
293
+
294
+ alias :file_to_array :read_packet_bytes
295
+
296
+ # Takes a filename, and an optional block. If a block is given,
297
+ # yield back parsed packets from the given file. Otherwise, return
298
+ # an array of parsed packets.
299
+ #
300
+ # This is a brazillian times faster than the old methods of extracting
301
+ # packets from files.
302
+ def read_packets(fname,&block)
303
+ count = 0
304
+ packets = [] unless block
305
+ read_packet_bytes(fname) do |packet|
306
+ if block
307
+ count += 1
308
+ yield Packet.parse(packet)
309
+ else
310
+ packets << Packet.parse(packet)
311
+ end
312
+ end
313
+ block ? count : packets
314
+ end
315
+
316
+ end
317
+
318
+ def initialize(args={})
319
+ init_fields(args)
320
+ super(args[:endian], args[:head], args[:body])
321
+ end
322
+
323
+ # Called by initialize to set the initial fields.
324
+ def init_fields(args={})
325
+ args[:head] = PcapHeader.new(:endian => args[:endian]).read(args[:head])
326
+ args[:body] = PcapPackets.new(:endian => args[:endian]).read(args[:body])
327
+ return args
328
+ end
329
+
330
+ # Returns the object in string form.
331
+ def to_s
332
+ self[:head].to_s + self[:body].map {|p| p.to_s}.join
333
+ end
334
+
335
+ # Clears the contents of the PcapFile.
336
+ def clear
337
+ self[:body].clear
338
+ end
339
+
340
+ # Reads a string to populate the object. Note that this appends new packets to
341
+ # any existing packets in the PcapFile.
342
+ def read(str)
343
+ force_binary(str)
344
+ self[:head].read str[0,24]
345
+ self[:body].read str
346
+ self
347
+ end
348
+
349
+ # Clears the contents of the PcapFile prior to reading in a new string.
350
+ def read!(str)
351
+ clear
352
+ force_binary(str)
353
+ self.read str
354
+ end
355
+
356
+ # A shorthand method for opening a file and reading in the packets. Note
357
+ # that readfile clears any existing packets, since that seems to be the
358
+ # typical use.
359
+ def readfile(file)
360
+ fdata = File.open(file, "rb") {|f| f.read}
361
+ self.read! fdata
362
+ end
363
+
364
+ # file_to_array() translates a libpcap file into an array of packets.
365
+ # Note that this strips out pcap timestamps -- if you'd like to retain
366
+ # timestamps and other libpcap file information, you will want to
367
+ # use read() instead.
368
+ def file_to_array(args={})
369
+ filename = args[:filename] || args[:file] || args[:f]
370
+ if filename
371
+ self.read! File.open(filename, "rb") {|f| f.read}
372
+ end
373
+ if args[:keep_timestamps] || args[:keep_ts] || args[:ts]
374
+ self[:body].map {|x| {x.timestamp.to_s => x.data.to_s} }
375
+ else
376
+ self[:body].map {|x| x.data.to_s}
377
+ end
378
+ end
379
+
380
+ alias_method :f2a, :file_to_array
381
+
382
+ # Takes an array of packets (as generated by file_to_array), and writes them
383
+ # to a file. Valid arguments are:
384
+ #
385
+ # :filename
386
+ # :array # Can either be an array of packet data, or a hash-value pair of timestamp => data.
387
+ # :timestamp # Sets an initial timestamp
388
+ # :ts_inc # Sets the increment between timestamps. Defaults to 1 second.
389
+ # :append # If true, then the packets are appended to the end of a file.
390
+ def array_to_file(args={})
391
+ if args.kind_of? Hash
392
+ filename = args[:filename] || args[:file] || args[:f]
393
+ arr = args[:array] || args[:arr] || args[:a]
394
+ ts = args[:timestamp] || args[:ts] || Time.now.to_i
395
+ ts_inc = args[:timestamp_increment] || args[:ts_inc] || 1
396
+ append = !!args[:append]
397
+ elsif args.kind_of? Array
398
+ arr = args
399
+ filename = append = nil
400
+ else
401
+ raise ArgumentError, "Unknown argument. Need either a Hash or Array."
402
+ end
403
+ unless arr.kind_of? Array
404
+ raise ArgumentError, "Need an array to read packets from"
405
+ end
406
+ arr.each_with_index do |p,i|
407
+ if p.kind_of? Hash # Binary timestamps are included
408
+ this_ts = p.keys.first
409
+ this_incl_len = p.values.first.size
410
+ this_orig_len = this_incl_len
411
+ this_data = p.values.first
412
+ else # it's an array
413
+ this_ts = Timestamp.new(:endian => self[:endian], :sec => ts + (ts_inc * i)).to_s
414
+ this_incl_len = p.to_s.size
415
+ this_orig_len = this_incl_len
416
+ this_data = p.to_s
417
+ end
418
+ this_pkt = PcapPacket.new({:endian => self[:endian],
419
+ :timestamp => this_ts,
420
+ :incl_len => this_incl_len,
421
+ :orig_len => this_orig_len,
422
+ :data => this_data }
423
+ )
424
+ self[:body] << this_pkt
425
+ end
426
+ if filename
427
+ self.to_f(:filename => filename, :append => append)
428
+ else
429
+ self
430
+ end
431
+ end
432
+
433
+ alias_method :a2f, :array_to_file
434
+
435
+ # Just like array_to_file, but clears any existing packets from the array first.
436
+ def array_to_file!(arr)
437
+ clear
438
+ array_to_file(arr)
439
+ end
440
+
441
+ alias_method :a2f!, :array_to_file!
442
+
443
+ # Writes the PcapFile to a file. Takes the following arguments:
444
+ #
445
+ # :filename # The file to write to.
446
+ # :append # If set to true, the packets are appended to the file, rather than overwriting.
447
+ def to_file(args={})
448
+ filename = args[:filename] || args[:file] || args[:f]
449
+ unless (!filename.nil? || filename.kind_of?(String))
450
+ raise ArgumentError, "Need a :filename for #{self.class}"
451
+ end
452
+ append = args[:append]
453
+ if append
454
+ if File.exists? filename
455
+ File.open(filename,'ab') {|file| file.write(self.body.to_s)}
456
+ else
457
+ File.open(filename,'wb') {|file| file.write(self.to_s)}
458
+ end
459
+ else
460
+ File.open(filename,'wb') {|file| file.write(self.to_s)}
461
+ end
462
+ [filename, self.body.sz, self.body.size]
463
+ end
464
+
465
+ alias_method :to_f, :to_file
466
+
467
+ # Shorthand method for writing to a file. Can take either :file => 'name.pcap' or
468
+ # simply 'name.pcap'
469
+ def write(filename='out.pcap')
470
+ if filename.kind_of?(Hash)
471
+ f = filename[:filename] || filename[:file] || filename[:f] || 'out.pcap'
472
+ else
473
+ f = filename.to_s
474
+ end
475
+ self.to_file(:filename => f.to_s, :append => false)
476
+ end
477
+
478
+ # Shorthand method for appending to a file. Can take either :file => 'name.pcap' or
479
+ # simply 'name.pcap'
480
+ def append(filename='out.pcap')
481
+ if filename.kind_of?(Hash)
482
+ f = filename[:filename] || filename[:file] || filename[:f] || 'out.pcap'
483
+ else
484
+ f = filename.to_s
485
+ end
486
+ self.to_file(:filename => f, :append => true)
487
+ end
488
+
489
+ end
490
+
491
+ end
492
+
493
+ module PacketFu
494
+
495
+ # Read is largely deprecated. It was current in PacketFu 0.2.0, but isn't all that useful
496
+ # in 0.3.0 and beyond. Expect it to go away completely by version 1.0. So, the main use
497
+ # of this class is to learn how to do exactly the same things using the PcapFile object.
498
+ class Read
499
+
500
+ class << self
501
+
502
+ # Reads the magic string of a pcap file, and determines
503
+ # if it's :little or :big endian.
504
+ def get_byte_order(pcap_file)
505
+ byte_order = ((pcap_file[0,4] == PcapHeader::MAGIC_LITTLE) ? :little : :big)
506
+ return byte_order
507
+ end
508
+
509
+ # set_byte_order is pretty much totally deprecated.
510
+ def set_byte_order(byte_order)
511
+ PacketFu.instance_variable_set(:@byte_order,byte_order)
512
+ return true
513
+ end
514
+
515
+ # A wrapper for PcapFile#file_to_array, but only returns the array. Actually
516
+ # using the PcapFile object is going to be more useful.
517
+ def file_to_array(args={})
518
+ filename = args[:filename] || args[:file] || args[:out]
519
+ raise ArgumentError, "Need a :filename in string form to read from." if (filename.nil? || filename.class != String)
520
+ PcapFile.new.file_to_array(args)
521
+ end
522
+
523
+ alias_method :f2a, :file_to_array
524
+
525
+ end
526
+
527
+ end
528
+
529
+ end
530
+
531
+ module PacketFu
532
+
533
+ # Write is largely deprecated. It was current in PacketFu 0.2.0, but isn't all that useful
534
+ # in 0.3.0 and beyond. Expect it to go away completely by version 1.0, as working with
535
+ # PacketFu::PcapFile directly is generally going to be more rewarding.
536
+ class Write
537
+
538
+ class << self
539
+
540
+ # format_packets: Pretty much totally deprecated.
541
+ def format_packets(args={})
542
+ arr = args[:arr] || args[:array] || []
543
+ ts = args[:ts] || args[:timestamp] || Time.now.to_i
544
+ ts_inc = args[:ts_inc] || args[:timestamp_increment]
545
+ pkts = PcapFile.new.array_to_file(:endian => PacketFu.instance_variable_get(:@byte_order),
546
+ :arr => arr,
547
+ :ts => ts,
548
+ :ts_inc => ts_inc)
549
+ pkts.body
550
+ end
551
+
552
+ # array_to_file is a largely deprecated function for writing arrays of pcaps to a file.
553
+ # Use PcapFile#array_to_file instead.
554
+ def array_to_file(args={})
555
+ filename = args[:filename] || args[:file] || args[:out] || :nowrite
556
+ arr = args[:arr] || args[:array] || []
557
+ ts = args[:ts] || args[:timestamp] || args[:time_stamp] || Time.now.to_f
558
+ ts_inc = args[:ts_inc] || args[:timestamp_increment] || args[:time_stamp_increment]
559
+ byte_order = args[:byte_order] || args[:byteorder] || args[:endian] || args[:endianness] || :little
560
+ append = args[:append]
561
+ Read.set_byte_order(byte_order) if [:big, :little].include? byte_order
562
+ pf = PcapFile.new
563
+ pf.array_to_file(:endian => PacketFu.instance_variable_get(:@byte_order),
564
+ :arr => arr,
565
+ :ts => ts,
566
+ :ts_inc => ts_inc)
567
+ if filename && filename != :nowrite
568
+ if append
569
+ pf.append(filename)
570
+ else
571
+ pf.write(filename)
572
+ end
573
+ return [filename,pf.to_s.size,arr.size,ts,ts_inc]
574
+ else
575
+ return [nil,pf.to_s.size,arr.size,ts,ts_inc]
576
+ end
577
+
578
+ end
579
+
580
+ alias_method :a2f, :array_to_file
581
+
582
+ # Shorthand method for appending to a file. Also shouldn't use.
583
+ def append(args={})
584
+ array_to_file(args.merge(:append => true))
585
+ end
586
+
587
+ end
588
+
589
+ end
590
+
591
+ end
592
+
593
+
594
+ # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby