# frozen_string_literal: true # This file is part of PacketGen # See https://github.com/sdaubert/packetgen for more informations # Copyright (C) 2016 Sylvain Daubert # This program is published under MIT license. module PacketGen module Header class IP # Class to handle series of IP addresses # @author Sylvain Daubert class ArrayOfAddr < Types::Array set_of IP::Addr # Push a IP address to the array # @param [String,Addr] addr # @return [self] # array << '192.168.1.12' def push(addr) addr = addr.is_a?(Addr) ? addr : Addr.new.from_human(addr) super(addr) end end # Base class for IP options # @author Sylvain Daubert class Option < Types::Fields # EOL option type EOL_TYPE = 0x00 # NOP option type NOP_TYPE = 0x01 # LSRR option type LSRR_TYPE = 0x83 # SSRR option type SSRR_TYPE = 0x84 # RR option type RR_TYPE = 0x07 # SI option type SI_TYPE = 0x88 # RA option type RA_TYPE = 0x94 # @!attribute type # 8-bit option type # @return [Integer] define_field :type, Types::Int8 # @!attribute length # 8-bit option length. If 0, there is no +length+ field in option # @return [Integer] define_field :length, Types::Int8, default: 0, optional: ->(h) { h.type > 1 } # @!attribute data # option data # @return [String] define_field :data, Types::String, optional: ->(h) { h.length > 2 }, builder: ->(h, t) { t.new(length_from: -> { h.length - 2 }) } # @!attribute copied # 1-bit copied flag from {#type} field # @return [Boolean] # @!attribute option_class # 2-bit option class (0: control, 2: debug and measurement, 1 and 3: # reserved) from {#type} field # @return [Integer] # !@attribute number # 5-bit option number from {#type} field # @return [Integer] define_bit_fields_on :type, :copied, :option_class, 2, :number, 5 # @return [Hash] def self.types return @types if defined? @types @types = {} Option.constants.each do |cst| next unless cst.to_s.end_with? '_TYPE' optname = cst.to_s.sub(/_TYPE/, '') @types[optname] = Option.const_get(cst) end @types end # Factory to build an option from its type # @return [Option] def self.build(options={}) type = options.delete(:type) klass = case type when String types.key?(type) ? IP.const_get(type) : self when Integer types.value?(type) ? IP.const_get(types.key(type)) : self else self end klass.new(options) end def initialize(options={}) unless options[:type] opt_name = self.class.to_s.gsub(/.*::/, '') options[:type] = Option.const_get("#{opt_name}_TYPE") if Option.const_defined? "#{opt_name}_TYPE" end super self.length = sz if respond_to?(:length) && options[:length].nil? end # Get binary string. Set {#length} field. # @return [String] def to_s self.length = super.size if respond_to? :length super end # Get a human readable string # @return [String] def to_human str = self.class == Option ? +"unk-#{type}" : self.class.to_s.sub(/.*::/, '') if respond_to?(:length) && (length > 2) && !self[:data].to_s.empty? str << ":#{self[:data].to_s.inspect}" end str end end # End-of-option-List IP option class EOL < Option remove_field :length remove_field :data end # No OPeration IP option class NOP < EOL; end # Loose Source and Record Route IP option class LSRR < Option remove_field :data # @!attribute pointer # 8-bit pointer on next address # @return [Integer] define_field :pointer, Types::Int8, default: 4 # @!attribute data # Array of IP addresses # @return [Types::Array] define_field :data, ArrayOfAddr, builder: ->(h, t) { t.new(length_from: -> { h.length - 3 }) } # Get IP address pointer by {#pointer} # @return [Addr] def pointed_addr data[pointer / 4 - 1] end # Get a human readable string # @return [String] def to_human str = self.class.to_s.sub(/.*::/, '') str << ':' << self[:data].to_human end end # Strict Source and Record Route IP option class SSRR < LSRR; end # Record Route IP option class RR < LSRR; end # Stream Identifier IP option class SI < Option remove_field :data # @!attribute id # 16-bit stream ID # @return [Integer] define_field :id, Types::Int16 end # Router Alert IP option class RA < Option remove_field :data # @!attribute value # 16-bit value. Should be 0. # @return [Integer] define_field :value, Types::Int16, default: 0 end end end end