Class: PacketGen::Header::Base Abstract

Inherits:
Types::Fields show all
Includes:
PacketGen::Headerable
Defined in:
lib/packetgen/header/base.rb

Overview

This class is abstract.

Base class for all header types. Subclasses may define magic methods:

  • #calc_checksum, which computes header checksum,

  • #calc_length, which computes header length,

  • PacketGen::Headerable#parse?,

  • #reply!, which inverts needed fields to forge a response.

Author:

  • Sylvain Daubert

Defined Under Namespace

Classes: Binding, Bindings, ProcBinding

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from PacketGen::Headerable

#added_to_packet, included, #method_name, #packet, #packet=, #parse?, #protocol_name, #read

Methods inherited from Types::Fields

#[], #[]=, #bits_on, define_bit_fields_on, define_field, define_field_after, define_field_before, fields, #fields, #inspect, #offset_of, #optional?, #optional_fields, #present?, #read, remove_bit_fields_on, remove_field, #sz, #to_h, #to_s, update_field

Constructor Details

#initialize(options = {}) ⇒ Base

Returns a new instance of Base.



217
218
219
220
# File 'lib/packetgen/header/base.rb', line 217

def initialize(options={})
  @packet = options.delete(:packet) if options.key?(:packet)
  super
end

Class Attribute Details

.known_headersHash (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Get known headers

Returns:

  • (Hash)

    keys: header classes, values: hashes



150
151
152
# File 'lib/packetgen/header/base.rb', line 150

def known_headers
  @known_headers
end

Class Method Details

.bind(header_klass, args = {}) ⇒ void

This method returns an undefined value.

Bind a upper header to current one.

Examples:

Basic examples

# Bind Header2 to Header1 when field1 from Header1 has a value of 42
Header1.bind Header2, field1: 42
# Bind Header3 to Header1 when field1 from Header1 has a value of 43
# and field2 has value 43 or 44
Header1.bind Header3, field1: 43, field2: 43
Header1.bind Header3, field1: 43, field2: 44

Defining a binding on a field using a lambda.

# Bind Header4 to Header1 when field1 from Header1 has a value
# greater or equal to 44. When adding a Header2 to a Header1
# with Packet#add, force value to 44.
Header1.bind Header4, field1: ->(v) { v.nil? ? 44 : v >= 44 }

Defining a binding using procs key

# Bind Header5 to Header1 when field1 from Header1 has a value of 41
# and first two bytes of header1's body are null.
# When adding a Header2 to a Header1 with Packet#add, force value to 44.
Header1.bind Header5, procs: [->(hdr) { hdr.field1 = 41 }
                              ->(hdr) { hdr.field1 == 41 && hdr.body[0..1] == "\x00\x00" }]

Parameters:

  • header_klass (Class)

    header class to bind to current class

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

    current class fields and their value when header_klass is embedded in current class.

    Given value may be a lambda, whose alone argument is the value extracted from header field (or nil when lambda is used to set field while adding a header).

    Special key procs may be used to set 2 lambdas, the former to set fields, the latter to check bindings. This may be used when multiple and non-trivial checks should be made.

Since:

  • 2.7.0



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/packetgen/header/base.rb', line 184

def bind(header_klass, args={})
  if @known_headers[header_klass].nil?
    bindings = Bindings.new
    @known_headers[header_klass] = bindings
  else
    bindings = @known_headers[header_klass]
  end
  bindings.new_set
  args.each do |key, value|
    bindings << if key == :procs
                  ProcBinding.new(value)
                else
                  Binding.new(key, value)
                end
  end
end

.calculate_and_set_length(hdr, header_in_size: true) ⇒ Object

Helper method to calculate length of hdr and set its length field. To be used by #calc_length in Base subclasses.

Parameters:

  • hdr (Base)
  • header_in_size (Boolean) (defaults to: true)

    if true header is included in length, if false, only body is taken into account



206
207
208
209
210
211
212
213
# File 'lib/packetgen/header/base.rb', line 206

def calculate_and_set_length(hdr, header_in_size: true)
  length = if header_in_size
             hdr.sz
           else
             hdr[:body].sz
           end
  hdr.length = length
end

.inherited(klass) ⇒ void

This method returns an undefined value.

On inheritage, create @known_header class variable

Parameters:

  • klass (Class)


141
142
143
144
# File 'lib/packetgen/header/base.rb', line 141

def self.inherited(klass)
  super
  klass.class_eval { @known_headers = {} }
end

Instance Method Details

#header_id(header) ⇒ Integer

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Get header id in Packet#headers array

Parameters:

Returns:

  • (Integer)

Raises:



227
228
229
230
231
232
233
234
# File 'lib/packetgen/header/base.rb', line 227

def header_id(header)
  raise FormatError, "header of type #{header.class} not in a packet" if packet.nil?

  id = packet.headers.index(header)
  raise FormatError, "header of type #{header.class} not in packet #{packet}" if id.nil?

  id
end

#ip_header(header) ⇒ Header

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Get IP or IPv6 previous header from header

Parameters:

Returns:

Raises:



242
243
244
245
246
247
248
# File 'lib/packetgen/header/base.rb', line 242

def ip_header(header)
  hid = header_id(header)
  iph = packet.headers[0...hid].reverse.find { |h| h.is_a?(IP) || h.is_a?(IPv6) }
  raise FormatError, 'no IP or IPv6 header in packet' if iph.nil?

  iph
end

#ll_header(header) ⇒ Header

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Get link layer header from given header

Parameters:

Returns:

Raises:



256
257
258
259
260
261
262
# File 'lib/packetgen/header/base.rb', line 256

def ll_header(header)
  hid = header_id(header)
  llh = packet.headers[0...hid].reverse.find { |h| h.is_a?(Eth) || h.is_a?(Dot11) }
  raise FormatError, 'no link layer header in packet' if llh.nil?

  llh
end