Class: PacketGen::Header::Base Abstract

Inherits:
BinStruct::Struct
  • Object
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 attributes to forge a response.

Base class defines Base.bind method, to bind headers to outer ones.

Author:

  • Sylvain Daubert

  • LemonTree55

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, #to_s

Constructor Details

#initialize(options = {}) ⇒ Base

Returns a new instance of Base.

See Also:

  • BinStruct::Struct#initialize


219
220
221
222
# File 'lib/packetgen/header/base.rb', line 219

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

Class Attribute Details

.known_headersHash{Headerable => Bindings} (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:



153
154
155
# File 'lib/packetgen/header/base.rb', line 153

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 TCP to IP when protocol attribute from IP has a value of 66
PacketGen::Header::IP.bind PacketGen::Header::TCP, protocol: 66
# Bind UDP to IP when protocol from IP has a value of 177
# and tos has value 43 or 44
PacketGen::Header::IP .bind PacketGen::Header::UDP, protocol: 177, tos: 43
PacketGen::Header::IP .bind PacketGen::Header::UDP, protocol: 177, tos: 44

Defining a binding on a field using a lambda.

# Bind DHCP to Eth when ethertype from Eth has a value
# greater or equal to 44. When adding a DHCP to a Eth
# with Packet#add, force value to 44.
PacketGen::Header::Eth.bind PacketGen::Header::DHCP, ethertype: ->(v) { v.nil? ? 44 : v >= 44 }

Defining a binding using procs key

# Bind IPv6 to IP when protocol from IP has a value of 255
# and first two bytes of IP's body are 0x6000.
# When adding a IPv6 to a IP with Packet#add, force value to 255.
PacketGen::Header::IP.bind PacketGen::Header::IPv6, procs: [->(hdr) { hdr.protocol = 255 },
                                                            ->(hdr) { hdr.protocol == 255 && hdr.body[0..1] == "\x60\x00" }]

Parameters:

  • header_klass (Class)

    header class to bind to current class

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

    current class attributes 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



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

def bind(header_klass, args={})
  bindings = @known_headers[header_klass]
  if bindings.nil?
    bindings = Bindings.new
    @known_headers[header_klass] = bindings
  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



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

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 inheritance, create @known_header class variable

Parameters:

  • klass (Class)


144
145
146
147
# File 'lib/packetgen/header/base.rb', line 144

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)

    header id

Raises:



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

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:



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

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 nor 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 (Eth or Dot11) header from given header

Parameters:

Returns:

Raises:



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

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