Class: PacketGen::PcapNG::File

Inherits:
Object
  • Object
show all
Defined in:
lib/packetgen/pcapng/file.rb

Overview

PcapNG::File is a complete Pcap-NG file handler.

Author:

  • Sylvain Daubert

Constant Summary collapse

{
  LINKTYPE_ETHERNET => 'Eth',
  LINKTYPE_IEEE802_11 => 'Dot11',
  LINKTYPE_IEEE802_11_RADIOTAP => 'RadioTap',
  LINKTYPE_PPI => 'PPI',
  LINKTYPE_IPV4 => 'IP',
  LINKTYPE_IPV6 => 'IPv6'
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeFile

Returns a new instance of File.



27
28
29
# File 'lib/packetgen/pcapng/file.rb', line 27

def initialize
  @sections = []
end

Instance Attribute Details

#sectionsArray

Get file sections

Returns:

  • (Array)


25
26
27
# File 'lib/packetgen/pcapng/file.rb', line 25

def sections
  @sections
end

Instance Method Details

#append(filename = 'out.pcapng') ⇒ Array

Shorthand method for appending to a file.

Parameters:

  • filename (#to_s) (defaults to: 'out.pcapng')

Returns:

  • (Array)

    see return value from #to_file



210
211
212
# File 'lib/packetgen/pcapng/file.rb', line 210

def append(filename='out.pcapng')
  self.to_file(filename.to_s, append: true)
end

#array_to_file(ary) ⇒ self #array_to_file(options = {}) ⇒ Array

Overloads:

  • #array_to_file(ary) ⇒ self

    Update PacketGen::PcapNG::File object with packets.

    Parameters:

    Returns:

    • (self)
  • #array_to_file(options = {}) ⇒ Array

    Update PacketGen::PcapNG::File and/or write it to a file

    Parameters:

    • options (Hash) (defaults to: {})

    Options Hash (options):

    • :filename (String)

      file written on disk only if given

    • :array (Array)

      can either be an array of packet data, or a hash-value pair of timestamp => data.

    • :timestamp (Time)

      set an initial timestamp

    • :ts_inc (Integer)

      set the increment between timestamps. Defaults to 1

    • :append (Boolean)

      if true, append packets to the end of the file

    Returns:

    • (Array)

      see return value from #to_file



231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
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
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/packetgen/pcapng/file.rb', line 231

def array_to_file(options={})
  case options
  when Hash
    filename = options[:filename] || options[:file]
    ary = options[:array] || options[:arr]
    unless ary.is_a? Array
      raise ArgumentError, ':array parameter needs to be an array'
    end
    ts = options[:timestamp] || options[:ts] || Time.now
    ts_inc = options[:ts_inc] || 1
    append = !options[:append].nil?
  when Array
    ary = options
    ts = Time.now
    ts_inc = 1
    filename = nil
    append = false
  else
    raise ArgumentError, 'unknown argument. Need either a Hash or Array'
  end

  section = SHB.new
  @sections << section
  itf = IDB.new(endian: section.endian)
  classify_block section, itf

  ary.each_with_index do |pkt, i|
    case pkt
    when Hash
      this_ts = pkt.keys.first.to_i
      this_cap_len = pkt.values.first.to_s.size
      this_data = pkt.values.first.to_s
    else
      this_ts = (ts + ts_inc * i).to_i
      this_cap_len = pkt.to_s.size
      this_data = pkt.to_s
    end
    this_ts = (this_ts / itf.ts_resol).to_i
    this_tsh = this_ts >> 32
    this_tsl = this_ts & 0xffffffff
    this_pkt = EPB.new(endian:       section.endian,
                       interface_id: 0,
                       tsh:          this_tsh,
                       tsl:          this_tsl,
                       cap_len:      this_cap_len,
                       orig_len:     this_cap_len,
                       data:         this_data)
    classify_block section, this_pkt
  end

  if filename
    self.to_f(filename, append: append)
  else
    self
  end
end

#clearvoid

This method returns an undefined value.

Clear the contents of the Pcapng::File.



150
151
152
# File 'lib/packetgen/pcapng/file.rb', line 150

def clear
  @sections.clear
end

#file_to_array(options = {}) ⇒ Array<Packet>, Array<Hash>

Translates a PacketGen::PcapNG::File into an array of packets.

Parameters:

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :filename (String)

    if given, object is cleared and filename is analyzed before generating array. Else, array is generated from self

  • :file (String)

    same as :filename

  • :keep_timestamps (Boolean)

    if true (default value: false), generates an array of hashes, each one with timestamp as key and packet as value. There is one hash per packet.

  • :keep_ts (Boolean)

    same as :keep_timestamp

Returns:

  • (Array<Packet>, Array<Hash>)


164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/packetgen/pcapng/file.rb', line 164

def file_to_array(options={})
  filename = options[:filename] || options[:file]
  if filename
    clear
    readfile filename
  end

  ary = []
  @sections.each do |section|
    section.interfaces.each do |itf|
      if options[:keep_timestamps] || options[:keep_ts]
        ary.concat(itf.packets.map { |pkt| { pkt.timestamp => pkt.data.to_s } })
      else
        ary.concat(itf.packets.map { |pkt| pkt.data.to_s })
      end
    end
  end
  ary
end

#read(str) ⇒ self

Read a string to populate the object. Note that this appends new blocks to the Pcapng::File object.

Parameters:

  • str (String)

Returns:

  • (self)


35
36
37
38
39
40
# File 'lib/packetgen/pcapng/file.rb', line 35

def read(str)
  PacketGen.force_binary(str)
  io = StringIO.new(str)
  parse_section(io)
  self
end

#read!(str) ⇒ self

Clear the contents of the Pcapng::File prior to reading in a new string. This string should contain a Section Header Block and an Interface Description Block to create a conform pcapng file.

Parameters:

  • str (String)

Returns:

  • (self)


47
48
49
50
# File 'lib/packetgen/pcapng/file.rb', line 47

def read!(str)
  clear
  read(str)
end

#read_packet_bytes(fname) ⇒ Array #read_packet_bytes(fname) {|raw, interface's| ... } ⇒ Integer

Give an array of raw packets (raw data from packets). If a block is given, yield raw packet data from the given file.

Overloads:

  • #read_packet_bytes(fname) ⇒ Array

    Returns array of packet raw data.

    Parameters:

    • fname (String)

      pcapng file name

    Returns:

    • (Array)

      array of packet raw data

  • #read_packet_bytes(fname) {|raw, interface's| ... } ⇒ Integer

    Returns number of packets.

    Parameters:

    • fname (String)

      pcapng file name

    Yield Parameters:

    • raw (String)

      packet raw data

    • interface's (Integer)

      link_type from which packet was captured

    Returns:

    • (Integer)

      number of packets

Raises:

  • (ArgumentError)

    cannot read fname



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/packetgen/pcapng/file.rb', line 93

def read_packet_bytes(fname, &blk)
  count = 0
  packets = [] unless blk

  readfile(fname) do |packet|
    if blk
      count += 1
      yield packet.data.to_s, packet.interface.link_type
    else
      packets << packet.data.to_s
    end
  end

  blk ? count : packets
end

#read_packets(fname) ⇒ Array<Packet> #read_packets(fname) {|packet| ... } ⇒ Integer

Return an array of parsed packets. If a block is given, yield parsed packets from the given file.

Overloads:

  • #read_packets(fname) ⇒ Array<Packet>

    Parameters:

    • fname (String)

      pcapng file name

    Returns:

  • #read_packets(fname) {|packet| ... } ⇒ Integer

    Returns number of packets.

    Parameters:

    • fname (String)

      pcapng file name

    Yield Parameters:

    Returns:

    • (Integer)

      number of packets

Raises:

  • (ArgumentError)

    cannot read fname



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/packetgen/pcapng/file.rb', line 119

def read_packets(fname, &blk)
  count = 0
  packets = [] unless blk

  read_packet_bytes(fname) do |packet, link_type|
    first_header = KNOWN_LINK_TYPES[link_type]
    parsed_pkt = if first_header.nil?
                   # unknown link type, try to guess
                   Packet.parse(packet)
                 else
                   Packet.parse(packet, first_header: first_header)
                 end
    if blk
      count += 1
      yield parsed_pkt
    else
      packets << parsed_pkt
    end
  end

  blk ? count : packets
end

#readfile(fname) {|block| ... } ⇒ Integer

Read a given file and analyze it. If given a block, it will yield PcapNG::EPB or PcapNG::SPB objects. This is the only way to get packet timestamps.

Parameters:

  • fname (String)

    pcapng file name

Yield Parameters:

Returns:

  • (Integer)

    return number of yielded blocks (only if a block is given)

Raises:

  • (ArgumentError)

    cannot read fname



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/packetgen/pcapng/file.rb', line 59

def readfile(fname, &blk)
  unless ::File.readable?(fname)
    raise ArgumentError, "cannot read file #{fname}"
  end

  ::File.open(fname, 'rb') do |f|
    parse_section(f) until f.eof?
  end

  return unless blk

  count = 0
  @sections.each do |section|
    section.interfaces.each do |intf|
      intf.packets.each do |pkt|
        count += 1
        yield pkt
      end
    end
  end
  count
end

#to_file(filename, options = {}) ⇒ Array Also known as: to_f

Writes the PacketGen::PcapNG::File to a file.

Parameters:

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :append (Boolean) — default: default: +false+

    if set to true, the packets are appended to the file, rather than overwriting it

Returns:

  • (Array)

    array of 2 elements: filename and size written



189
190
191
192
193
194
195
196
197
# File 'lib/packetgen/pcapng/file.rb', line 189

def to_file(filename, options={})
  mode = if options[:append] && ::File.exist?(filename)
           'ab'
         else
           'wb'
         end
  ::File.open(filename, mode) { |f| f.write(self.to_s) }
  [filename, self.to_s.size]
end

#to_sString

Return the object as a String

Returns:

  • (String)


144
145
146
# File 'lib/packetgen/pcapng/file.rb', line 144

def to_s
  @sections.map(&:to_s).join
end

#write(filename = 'out.pcapng') ⇒ Array

Shorthand method for writing to a file.

Parameters:

  • filename (#to_s) (defaults to: 'out.pcapng')

Returns:

  • (Array)

    see return value from #to_file



203
204
205
# File 'lib/packetgen/pcapng/file.rb', line 203

def write(filename='out.pcapng')
  self.to_file(filename.to_s, append: false)
end