class PacketGen::Header::Base
@abstract Base
class for all header types.
Subclasses may define magic methods: * +#calc_checksum+, which computes header checksum, * +#calc_length+, which computes header length, * {#parse?}, * +#reply!+, which inverts needed fields to forge a response.
@author Sylvain Daubert
Attributes
@api private Get known headers @return [Hash] keys: header classes, values: hashes
Public Class Methods
Bind a upper header to current one. @param [Class] header_klass header class to bind to current class @param [Hash] args 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.
@return [void] @example 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
@example 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 }
@example 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" }]
@since 2.7.0
# File lib/packetgen/header/base.rb, line 183 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
Helper method to calculate length of hdr
and set its length
field. To be used by #calc_length
in Base
subclasses. @param [Base] hdr @param [Boolean] header_in_size if true
header is included in length,
if +false+, only +body+ is taken into account
# File lib/packetgen/header/base.rb, line 205 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
@private On inheritage, create +@known_header+ class variable @param [Class] klass @return [void]
# File lib/packetgen/header/base.rb, line 140 def self.inherited(klass) super klass.class_eval { @known_headers = {} } end
@see Types::Fields#initialize
# File lib/packetgen/header/base.rb, line 216 def initialize(options={}) @packet = options.delete(:packet) if options.key?(:packet) super end
Public Instance Methods
@api private Get header
id in {Packet#headers} array @param [Header] header @return [Integer] @raise [FormatError] header
not in a packet
# File lib/packetgen/header/base.rb, line 226 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
@api private Get {IP} or {IPv6} previous header from header
@param [Header] header @return [Header] @raise [FormatError] no IP
or IPv6
header previous header
in packet @raise [FormatError] header
not in a packet
# File lib/packetgen/header/base.rb, line 241 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
@api private Get link layer header from given header @param [Header] header @return [Header] @raise [FormatError] no link layer header in packet @raise [FormatError] header
not in a packet
# File lib/packetgen/header/base.rb, line 255 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