From d2df62be8541b0cd36765b2b4c33409488e16ac5 Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Wed, 17 Jul 2024 20:05:52 +0200 Subject: [PATCH 01/19] Remove deprecated features --- .github/workflows/rubocop-analysis.yml | 2 +- lib/packetgen/header/dot11/sub_mngt.rb | 14 --- lib/packetgen/packet.rb | 4 +- lib/packetgen/pcapng/file.rb | 94 --------------- lib/packetgen/types.rb | 1 - lib/packetgen/types/abstract_tlv.rb | 25 +--- lib/packetgen/types/tlv.rb | 161 ------------------------- spec/packet_spec.rb | 18 +++ spec/pcapng/file_spec.rb | 134 -------------------- spec/types/abstract_tlv_spec.rb | 22 ---- spec/types/tlv_spec.rb | 108 ----------------- 11 files changed, 27 insertions(+), 556 deletions(-) delete mode 100644 lib/packetgen/types/tlv.rb delete mode 100644 spec/types/tlv_spec.rb diff --git a/.github/workflows/rubocop-analysis.yml b/.github/workflows/rubocop-analysis.yml index 3181c2b..765e54e 100644 --- a/.github/workflows/rubocop-analysis.yml +++ b/.github/workflows/rubocop-analysis.yml @@ -50,6 +50,6 @@ jobs: " - name: Upload Sarif output - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@v3 with: sarif_file: rubocop.sarif diff --git a/lib/packetgen/header/dot11/sub_mngt.rb b/lib/packetgen/header/dot11/sub_mngt.rb index 2b676e0..019624c 100644 --- a/lib/packetgen/header/dot11/sub_mngt.rb +++ b/lib/packetgen/header/dot11/sub_mngt.rb @@ -21,20 +21,6 @@ class Dot11 class SubMngt < Base # @return [Array] define_field :elements, ArrayOfElements - - # Add an {Element} to header - # @param [Integer,String] type element type - # @param [Object] value element value - # @return [self] - # @since 2.1.3 - # @since 3.1.1 #elements in no more an Array but an {ArrayOfElements} - # @deprecated Prefer use of +submngt.element << {type: type, value: value}+ - def add_element(type:, value:) - Deprecation.deprecated(self.class, __method__, 'elements') - element = Element.new(type: type, value: value) - self.elements << element - self - end end # IEEE 802.11 Association Request frame diff --git a/lib/packetgen/packet.rb b/lib/packetgen/packet.rb index 039ca4e..15a0510 100644 --- a/lib/packetgen/packet.rb +++ b/lib/packetgen/packet.rb @@ -120,8 +120,8 @@ def self.read(filename) # @return [void] def self.write(filename, packets) pf = PcapNG::File.new - pf.array_to_file packets - pf.to_f filename + pf.read_array(packets) + pf.to_f(filename) end # @private diff --git a/lib/packetgen/pcapng/file.rb b/lib/packetgen/pcapng/file.rb index dd27be7..33cd9ae 100644 --- a/lib/packetgen/pcapng/file.rb +++ b/lib/packetgen/pcapng/file.rb @@ -140,35 +140,6 @@ def clear @sections.clear end - # @deprecated - # Prefer use of {#to_a} or {#to_h}. - # Translates a {File} into an array of packets. - # @param [Hash] options - # @option options [String] :file if given, object is cleared and filename - # is analyzed before generating array. Else, array is generated from +self+ - # @option options [Boolean] :keep_timestamps 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. - # @return [Array,Array] - def file_to_array(options={}) - Deprecation.deprecated(self.class, __method__) - - file = options[:file] || options[:filename] - reread file - - ary = [] - blk = if options[:keep_timestamps] || options[:keep_ts] - proc { |pkt| { pkt.timestamp => pkt.data.to_s } } - else - proc { |pkt| pkt.data.to_s } - end - each_packet_with_interface do |pkt, _itf| - ary << blk.call(pkt) - end - - ary - end - # Translates a {File} into an array of packets. # @return [Array] # @since 3.1.6 @@ -223,41 +194,6 @@ def append(filename='out.pcapng') self.to_file(filename.to_s, append: true) end - # @deprecated Prefer use of {#read_array} or {#read_hash}. - # @overload array_to_file(ary) - # Update {File} object with packets. - # @param [Array] ary as generated by {#file_to_array} or Array of Packet objects. - # Update {File} object without writing file on disk - # @return [self] - # @overload array_to_file(options={}) - # Update {File} and/or write it to a file - # @param [Hash] options - # @option options [String] :file file written on disk only if given - # @option options [Array] :array can either be an array of packet data, - # or a hash-value pair of timestamp => data. - # @option options [Time] :timestamp set an initial timestamp - # @option options [Integer] :ts_inc set the increment between timestamps. - # Defaults to 1 - # @option options [Boolean] :append if +true+, append packets to the end of - # the file - # @return [Array] see return value from {#to_file} - def array_to_file(options={}) - filename, ary, ts, ts_inc, append = array_to_file_options(options) - - section = create_new_shb_section - - ary.each do |pkt| - classify_block(section, epb_from_pkt(pkt, section, ts)) - ts += ts_inc - end - - if filename - self.to_f(filename, append: append) - else - self - end - end - # Update current object from an array of packets # @param [Array] packets # @param [Time, nil] timestamp initial timestamp, used for first packet @@ -376,36 +312,6 @@ def classify_block(shb, block) end end - def array_to_file_options(options) - case options - when Hash - array_to_file_options_from_hash(options) - when Array - [nil, options, Time.now, 1, false] - else - raise ArgumentError, 'unknown argument. Need either a Hash or Array' - end - end - - # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity - # Extract and check options for #array_to_file - def array_to_file_options_from_hash(options) - %i[filename arr ts].each do |deprecated_opt| - Deprecation.deprecated_option(self.class, :array_to_file, deprecated_opt) if options[deprecated_opt] - end - - filename = options[:filename] || options[:file] - ary = options[:array] || options[:arr] - raise ArgumentError, ':array parameter needs to be an array' unless ary.is_a? Array - - ts = options[:timestamp] || options[:ts] || Time.now - ts_inc = options[:ts_inc] || 1 - append = !options[:append].nil? - - [filename, ary, ts, ts_inc, append] - end - # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity - def create_new_shb_section section = SHB.new @sections << section diff --git a/lib/packetgen/types.rb b/lib/packetgen/types.rb index 9e33ced..ce52fac 100644 --- a/lib/packetgen/types.rb +++ b/lib/packetgen/types.rb @@ -23,4 +23,3 @@ module Types require_relative 'types/array' require_relative 'types/oui' require_relative 'types/abstract_tlv' -require_relative 'types/tlv' diff --git a/lib/packetgen/types/abstract_tlv.rb b/lib/packetgen/types/abstract_tlv.rb index 574f4de..f35acc2 100644 --- a/lib/packetgen/types/abstract_tlv.rb +++ b/lib/packetgen/types/abstract_tlv.rb @@ -67,8 +67,6 @@ class AbstractTLV < Types::Fields class << self # @return [Hash] attr_accessor :aliases - # @deprecated - attr_accessor :header_in_length # @private attr_accessor :field_in_length @@ -78,21 +76,16 @@ class << self # @param [Class] type_class Class to use for +type+ # @param [Class] length_class Class to use for +length+ # @param [Class] value_class Class to use for +value+ - # @param [Boolean] header_in_length if +true +, +type+ and +length+ fields are - # included in length. Deprecated, use +field_in_length+ instead. # @param [String] field_order give field order. Each character in [T,L,V] MUST be present once, in the desired order. # @param [String] field_in_length give fields to compute length on. # @return [Class] - # @since 3.1.4 Add +header_in_length+ parameter - # @since 3.3.1 Add +field_order+ and +field_in_length' parameters. Deprecate +header_in_length+ parameter. + # @since 3.3.1 Add +field_order+ and +field_in_length' parameters def create(type_class: Int8Enum, length_class: Int8, value_class: String, - aliases: {}, header_in_length: false, field_order: 'TLV', field_in_length: 'V') - Deprecation.deprecated_option(self, 'create', 'header_in_length', klass_method: true) if header_in_length + aliases: {}, field_order: 'TLV', field_in_length: 'V') raise Error, '.create cannot be called on a subclass of PacketGen::Types::AbstractTLV' unless self.equal?(AbstractTLV) klass = Class.new(self) klass.aliases = aliases - klass.header_in_length = header_in_length klass.field_in_length = field_in_length check_field_in_length(field_in_length) @@ -186,7 +179,6 @@ def generate_fields(klass, field_order, type_class, length_class, value_class) # @option options [Integer] :length # @option options [Object] :value def initialize(options={}) - @header_in_length = self.class.header_in_length @field_in_length = self.class.field_in_length self.class.aliases.each do |al, orig| options[orig] = options[al] if options.key?(al) @@ -252,7 +244,6 @@ def to_human # @since 3.4.0 def calc_length fil = @field_in_length - fil = 'TLV' if @header_in_length length = 0 fil.each_char do |field_type| @@ -264,14 +255,10 @@ def calc_length private def real_length - if @header_in_length - self.length - self[:type].sz - self[:length].sz - else - length = self.length - length -= self[:type].sz if @field_in_length.include?('T') - length -= self[:length].sz if @field_in_length.include?('L') - length - end + length = self.length + length -= self[:type].sz if @field_in_length.include?('T') + length -= self[:length].sz if @field_in_length.include?('L') + length end end end diff --git a/lib/packetgen/types/tlv.rb b/lib/packetgen/types/tlv.rb deleted file mode 100644 index 3c09f01..0000000 --- a/lib/packetgen/types/tlv.rb +++ /dev/null @@ -1,161 +0,0 @@ -# coding: utf-8 -# frozen_string_literal: true - -# This file is part of PacketGen -# See https://github.com/lemontree55/packetgen for more informations -# Copyright (C) 2016 Sylvain Daubert -# Copyright (C) 2024 LemonTree55 -# This program is published under MIT license. - -module PacketGen - module Types - # Class to handle Type-Length-Value attributes - # - # TLV fields handles three subfields: - # * a tag/type field (defaults: {Int8} type), - # * a length field (defaults: {Int8} type), - # * a value field (defaults: {String} type). - # - # {#initialize} supports options to change tag and length type. By example, to - # declare a TLV using {Int16}: - # define_field :tlv, PacketGen::Types::TLV, builder: ->(obj) { PacketGen::Types::TLV.new(t: PacketGen::Types::Int16, l: PacketGen::Types::Int16) } - # - # == Subclasses - # A subclass may defined a constant hash TYPES. This hash defines human readable - # types versus their integer values. Hash keys are integer values, and hash values - # are types as strings. - # - # If TYPES is defined, a subclass may: - # * print human readable type using {#human_type}, - # * set type as String with {#type=}. - # @author Sylvain Daubert - # @deprecated Use {AbstractTLV} instead. - # @since 3.1.0 deprecated - class TLV < Fields - include Fieldable - - # @!attribute type - # @return [Integer] - define_field :type, Int8 - # @!attribute length - # @return [Integer] - define_field :length, Int8 - # @!attribute value - # @return [String] - define_field :value, String - - # @param [Hash] options - # @option options [Integer] :type - # @option options [Integer] :length - # @option options [String] :value - # @option options [Class] :t {Int} subclass for +:type+ attribute. - # Default: {Int8}. - # @option options [Class] :l {Int} subclass for +:length+ attribute. - # Default: {Int8}. - # @option options [Class] :v {String} subclass for +:value+ attribute. - # Default: {Types::String}. - def initialize(options={}) - Deprecation.deprecated_class(self.class, AbstractTLV) - super - initialize_types(options) - initialize_values(options) - end - - # Populate object from a binary string - # @param [String] str - # @return [Fields] self - def read(str) - idx = 0 - self[:type].read str[idx, self[:type].sz] - idx += self[:type].sz - self[:length].read str[idx, self[:length].sz] - idx += self[:length].sz - self[:value].read str[idx, self.length] - self - end - - # @private - alias old_type= type= - - undef type=, value=, value - - # Set type - # @param [::String,Integer] val - # @return [Integer] - # @raise [TypeError] class does not define TYPES - # @raise [ArgumentError] unknown string type - def type=(val) - case val - when Integer - self.old_type = val - else - raise TypeError, 'need an Integer' unless human_types? - - new_val = self.class::TYPES.key(val.to_s) - raise ArgumentError, "unknown #{val} type" if new_val.nil? - - self.old_type = new_val - end - end - - # Set +value+. May set +length+ if value is a {Types::String}. - # @param [::String,Integer] val - # @return [::String,Integer] - def value=(val) - self[:value].from_human val - self.length = self[:value].sz - val - end - - # Get +value+ - # @return [Object] depend on +value+ type - def value - self[:value].to_human - end - - # Return human readable type, if TYPES is defined - # @return [String] - def human_type - if human_types? - htype = self.class::TYPES[type] - htype = type if htype.nil? - htype.to_s - else - type.to_s - end - end - - # @return [String] - def to_human - name = self.class.to_s.gsub(/.*::/, '') - @typestr ||= if human_types? - types = self.class::TYPES.values - "%-#{types.max_by(&:length).size}s" - else - '%s' - end - lenstr = "%-#{(2**self[:length].nbits - 1).to_s.size}u" - "#{name} type:#{@typestr} length:#{lenstr} value:#{value.inspect}" % [human_type, - length] - end - - private - - def human_types? - self.class.const_defined? :TYPES - end - - def initialize_types(options) - self[:type] = options[:t].new(self.type) if options[:t] - self[:length] = options[:l].new(self.length) if options[:l] - self[:value] = options[:v].new if options[:v] - end - - def initialize_values(options) - self.type = options[:type] if options[:type] - self.value = options[:value] if options[:value] - self.length = options[:length] if options[:length] - end - end - end -end diff --git a/spec/packet_spec.rb b/spec/packet_spec.rb index 7fb50b7..b93bcaa 100644 --- a/spec/packet_spec.rb +++ b/spec/packet_spec.rb @@ -200,6 +200,24 @@ module PacketGen it 'raises on unknown association' do expect { @pkt.add 'Eth' }.to raise_error(BindingError, /IP\.bind_layer\(.*Eth/) end + + context '(bug #91)' do + it 'may set a CString' do + pkt = Packet.gen('BOOTP', file: 'test.txt') + expect(pkt.bootp.file).to eq('test.txt') + expect(pkt.bootp[:file].to_s).to eq("test.txt#{([0] * 120).pack('C*')}") + end + + it 'may set a IntString' do + class AddIntStringTest < Header::Base + define_field :field, Types::IntString + end + Header.add_class AddIntStringTest + pkt = Packet.gen('AddIntStringTest', field: 'This is a string') + expect(pkt.addintstringtest[:field].to_human).to eq('This is a string') + expect(pkt.addintstringtest[:field].to_s).to eq("\x10This is a string") + end + end end describe '#is?' do diff --git a/spec/pcapng/file_spec.rb b/spec/pcapng/file_spec.rb index 2cb85cc..e168482 100644 --- a/spec/pcapng/file_spec.rb +++ b/spec/pcapng/file_spec.rb @@ -164,46 +164,6 @@ module PcapNG end end - describe '#file_to_array' do - it 'generates an array from object state' do - pcapng.readfile @file - ary = pcapng.file_to_array - expect(ary).to be_a(Array) - ary.each do |p| - expect(p).to be_a(String) - end - expect(ary[0]).to eq(pcapng.sections[0].interfaces[0].packets[0].data) - end - - it 'generates an array from given file, clearing object state' do - pcapng.readfile @file - ary = pcapng.file_to_array(file: @file_spb) - expect(pcapng.sections.size).to eq(1) - expect(pcapng.sections[0].interfaces[0].packets[0]).to be_a(SPB) - - expect(ary).to be_a(Array) - ary.each do |p| - expect(p).to be_a(String) - end - expect(ary[0]).to eq(pcapng.sections[0].interfaces[0].packets[0].data) - end - - it 'generates an array with timestamps' do - pcapng.readfile @file - ary = pcapng.file_to_array(keep_timestamps: true) - expect(ary).to be_a(Array) - ary.each do |p| - expect(p).to be_a(Hash) - expect(p.keys.first).to be_a(Time) - expect(p.values.first).to be_a(String) - end - - packet1 = pcapng.sections[0].interfaces[0].packets[0] - expect(ary[0].keys.first).to eq(packet1.timestamp) - expect(ary[0].values.first).to eq(packet1.data) - end - end - describe '#to_a' do it 'generates an array from object state' do pcapng.readfile @file @@ -288,100 +248,6 @@ module PcapNG end end - describe '#array_to_file' do - before(:each) do - tmpfile = Tempfile.new('packetfu') - @tmpfilename = tmpfile.path - tmpfile.close - tmpfile.unlink - end - after(:each) { ::File.unlink @tmpfilename if ::File.exist? @tmpfilename } - - it 'gets an array of Packet objects' do - packets = pcapng.read_packets(@file) - - pcapng.clear - pcapng.array_to_file(packets) - pcapng.write @tmpfilename - - pcapng.clear - packets2 = pcapng.read_packets(@tmpfilename) - expect(packets2.map(&:to_s).join).to eq(packets.map(&:to_s).join) - end - - it 'gets a hash containing an array of Packet objects' do - packets = pcapng.read_packets(@file)[0..1] - - pcapng.clear - pcapng.array_to_file(array: packets) - pcapng.write @tmpfilename - - pcapng.clear - packets2 = pcapng.read_packets(@tmpfilename) - expect(packets2.map(&:to_s).join).to eq(packets.map(&:to_s).join) - end - - it 'gets a hash containing an array of Packet objects and a :timestamp key' do - packets = pcapng.read_packets(@file)[0..1] - - pcapng.clear - pcapng.array_to_file(array: packets, - timestamp: Time.utc(2000, 1, 1), - ts_inc: 3600 * 24) - pcapng.write @tmpfilename - - pcapng.clear - pcapng.readfile(@tmpfilename) - pcapng.sections[0].interfaces[0].packets.each_with_index do |pkt, i| - expect(pkt.data).to eq(packets[i].to_s) - expect(pkt.timestamp).to eq(Time.utc(2000, 1, 1 + i)) - end - end - - it 'gets a hash containing couples of Time and Packet objects' do - packets = pcapng.read_packets(@file)[0..3] - timestamp = Time.utc(2000, 1, 1) - ts_inc = 3600 * 24 * 2 - array = [] - packets.each_with_index do |pkt, i| - array << { (timestamp + ts_inc * i) => pkt } - end - - pcapng.clear - pcapng.array_to_file(array: array) - pcapng.write @tmpfilename - - pcapng.clear - pcapng.readfile(@tmpfilename) - pcapng.sections[0].interfaces[0].packets.each_with_index do |pkt, i| - expect(pkt.data).to eq(packets[i].to_s) - expect(pkt.timestamp).to eq(Time.utc(2000, 1, 1 + 2 * i)) - end - end - - it 'gets a hash containing a :file key' do - packets = pcapng.read_packets(@file)[0..2] - - pcapng.clear - pcapng.array_to_file(array: packets, file: @tmpfilename) - - pcapng.clear - packets2 = pcapng.read_packets(@tmpfilename) - expect(packets2.map(&:to_s).join).to eq(packets.map(&:to_s).join) - end - - it 'raises when :array argument is not an Array' do - packets = pcapng.read_packets(@file)[0..2] - expect { pcapng.array_to_file array: packets.map(&:to_s).join } - .to raise_error(ArgumentError, /needs to be an array/) - end - - it 'raises when argument is nor an Array neither a Hash' do - packets = pcapng.read_packets(@file)[0..2] - expect { pcapng.array_to_file packets.map(&:to_s).join } - .to raise_error(ArgumentError, /Need either/) - end - end describe '#read_array' do let(:ref_pcapng) { file = File.new; file.readfile(@file_spb); file } diff --git a/spec/types/abstract_tlv_spec.rb b/spec/types/abstract_tlv_spec.rb index 9ffda26..dd762c4 100644 --- a/spec/types/abstract_tlv_spec.rb +++ b/spec/types/abstract_tlv_spec.rb @@ -67,22 +67,6 @@ module Types expect(tlv.length).to eq(3) expect(tlv.value).to eq(binary("\x12\x34\x56")) end - - it 'reads a TLV from a binary string when header_in_length is set' do - tlv = AbstractTLV.create(header_in_length: true).new - - bin_str = [1, 2].pack('C*') - tlv.read(bin_str) - expect(tlv.type).to eq(1) - expect(tlv.length).to eq(2) - expect(tlv.value).to eq('') - - bin_str = [1, 5, 'abc'].pack('C2A3') - tlv.read(bin_str) - expect(tlv.type).to eq(1) - expect(tlv.length).to eq(5) - expect(tlv.value).to eq('abc') - end end describe '#human_type' do @@ -120,12 +104,6 @@ module Types expect(tlv.length).to eq(6) end - it 'sets #length when header_in_length is set' do - tlv = AbstractTLV.create(type_class: Int16, length_class: Int16, header_in_length: true).new - tlv.value = 'abcdef' - expect(tlv.length).to eq(10) - end - it 'sets #length when field_in_length contains "L"' do tlv = AbstractTLV.create(type_class: Int16, length_class: Int16, field_in_length: 'TLV').new tlv.value = 'abcdef' diff --git a/spec/types/tlv_spec.rb b/spec/types/tlv_spec.rb deleted file mode 100644 index 66fbc15..0000000 --- a/spec/types/tlv_spec.rb +++ /dev/null @@ -1,108 +0,0 @@ -require_relative '../spec_helper' - -module PacketGen - module Types - describe TLV do - - class TLVTest < TLV - TYPES = { 1 => 'one', 2 => 'two' } - end - - describe '#initialize' do - it 'returns a TLV with default values' do - tlv = TLV.new - expect(tlv[:type]).to be_a(Int8) - expect(tlv[:length]).to be_a(Int8) - expect(tlv[:value]).to be_a(String) - end - - it 'builds a TLV with others sizes for T and L' do - tlv = TLV.new(t: Int16) - expect(tlv[:type]).to be_a(Int16) - expect(tlv[:length]).to be_a(Int8) - expect(tlv[:value]).to be_a(String) - - tlv = TLV.new(l: Int16) - expect(tlv[:type]).to be_a(Int8) - expect(tlv[:length]).to be_a(Int16) - expect(tlv[:value]).to be_a(String) - end - - it 'accepts field options' do - tlv = TLV.new(type: 45, value: 'abc', length: 2) - expect(tlv.type).to eq(45) - expect(tlv.length).to eq(2) - expect(tlv.value).to eq('abc') - end - end - - describe '#read' do - it 'reads a TLV from a binary string' do - bin_str = [1, 2, 0x12345678].pack('CCN') - tlv = TLV.new.read(bin_str) - expect(tlv.type).to eq(1) - expect(tlv.length).to eq(2) - expect(tlv.value).to eq(binary "\x12\x34") - - bin_str = [1, 3, 0x12345678].pack('nnN') - tlv = TLV.new(l: Int16, t: Int16).read(bin_str) - expect(tlv.type).to eq(1) - expect(tlv.length).to eq(3) - expect(tlv.value).to eq(binary "\x12\x34\x56") - end - end - - describe '#type=' do - it 'raises when setting a String and there is no TYPES constant' do - expect { TLV.new.type = 'TRUC' }.to raise_error(TypeError, 'need an Integer') - end - - it 'accepts a String if subclass defines a TYPES constant' do - tlv = TLVTest.new - expect { tlv.type = 'two' }.to_not raise_error - expect(tlv.type).to eq(2) - end - - it 'raises if String is unknown from TYPES hash' do - tlv = TLVTest.new - expect { tlv.type = 'three' }.to raise_error(ArgumentError, /unknown/) - end - end - - describe '#human_type' do - it 'returns human readable type, if TYPES is defined' do - tlv = TLVTest.new - tlv.type = 'one' - expect(tlv.type).to eq(1) - expect(tlv.human_type).to eq('one') - end - - it 'returns integer string, if TYPES is undefined or type has no string' do - tlv = TLVTest.new - tlv.type = 3 - expect(tlv.type).to eq(3) - expect(tlv.human_type).to eq('3') - - tlv = TLV.new - tlv.type = 12 - expect(tlv.human_type).to eq('12') - end - end - - describe '#to_human' do - it 'returns a string for subtypes with a TYPES constant' do - tlv = TLVTest.new(type: 1, value: 'abcdef') - expect(tlv.to_human).to eq('TLVTest type:one length:6 value:"abcdef"') - end - - it 'returns a string for subtypes without a TYPES constant' do - tlv = TLV.new - expect(tlv.to_human).to eq('TLV type:0 length:0 value:""') - tlv.type = 156 - tlv.value = 'abcd' - expect(tlv.to_human).to eq('TLV type:156 length:4 value:"abcd"') - end - end - end - end -end From 89be1bff9886c13f6730218db375dfd2ec12c3e7 Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Sun, 21 Jul 2024 15:18:32 +0200 Subject: [PATCH 02/19] Remove Types module (extracted to bin_struct gem) --- lib/packetgen/types.rb | 25 -- lib/packetgen/types/abstract_tlv.rb | 265 ------------ lib/packetgen/types/array.rb | 287 ------------- lib/packetgen/types/cstring.rb | 109 ----- lib/packetgen/types/enum.rb | 171 -------- lib/packetgen/types/fieldable.rb | 66 --- lib/packetgen/types/fields.rb | 622 ---------------------------- lib/packetgen/types/int.rb | 473 --------------------- lib/packetgen/types/int_string.rb | 102 ----- lib/packetgen/types/length_from.rb | 54 --- lib/packetgen/types/oui.rb | 52 --- lib/packetgen/types/string.rb | 97 ----- spec/types/abstract_tlv_spec.rb | 160 ------- spec/types/array_spec.rb | 76 ---- spec/types/cstring_spec.rb | 95 ----- spec/types/enum_spec.rb | 231 ----------- spec/types/fields_spec.rb | 313 -------------- spec/types/int_spec.rb | 388 ----------------- spec/types/int_string_spec.rb | 73 ---- spec/types/oui_spec.rb | 55 --- spec/types/string_spec.rb | 36 -- 21 files changed, 3750 deletions(-) delete mode 100644 lib/packetgen/types.rb delete mode 100644 lib/packetgen/types/abstract_tlv.rb delete mode 100644 lib/packetgen/types/array.rb delete mode 100644 lib/packetgen/types/cstring.rb delete mode 100644 lib/packetgen/types/enum.rb delete mode 100644 lib/packetgen/types/fieldable.rb delete mode 100644 lib/packetgen/types/fields.rb delete mode 100644 lib/packetgen/types/int.rb delete mode 100644 lib/packetgen/types/int_string.rb delete mode 100644 lib/packetgen/types/length_from.rb delete mode 100644 lib/packetgen/types/oui.rb delete mode 100644 lib/packetgen/types/string.rb delete mode 100644 spec/types/abstract_tlv_spec.rb delete mode 100644 spec/types/array_spec.rb delete mode 100644 spec/types/cstring_spec.rb delete mode 100644 spec/types/enum_spec.rb delete mode 100644 spec/types/fields_spec.rb delete mode 100644 spec/types/int_spec.rb delete mode 100644 spec/types/int_string_spec.rb delete mode 100644 spec/types/oui_spec.rb delete mode 100644 spec/types/string_spec.rb diff --git a/lib/packetgen/types.rb b/lib/packetgen/types.rb deleted file mode 100644 index ce52fac..0000000 --- a/lib/packetgen/types.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -# This file is part of PacketGen -# See https://github.com/lemontree55/packetgen for more informations -# Copyright (C) 2016 Sylvain Daubert -# Copyright (C) 2024 LemonTree55 -# This program is published under MIT license. - -module PacketGen - # Module to group all type definitions - module Types - end -end - -require_relative 'types/length_from' -require_relative 'types/fieldable' -require_relative 'types/int' -require_relative 'types/enum' -require_relative 'types/string' -require_relative 'types/int_string' -require_relative 'types/cstring' -require_relative 'types/fields' -require_relative 'types/array' -require_relative 'types/oui' -require_relative 'types/abstract_tlv' diff --git a/lib/packetgen/types/abstract_tlv.rb b/lib/packetgen/types/abstract_tlv.rb deleted file mode 100644 index f35acc2..0000000 --- a/lib/packetgen/types/abstract_tlv.rb +++ /dev/null @@ -1,265 +0,0 @@ -# coding: utf-8 -# frozen_string_literal: true - -# This file is part of PacketGen -# See https://github.com/lemontree55/packetgen for more informations -# Copyright (C) 2016 Sylvain Daubert -# Copyright (C) 2024 LemonTree55 -# This program is published under MIT license. - -module PacketGen - module Types - # This class is an abstract class to define type-length-value data. - # - # This class supersedes {TLV} class, which is not well defined on some corner - # cases. - # - # ===Usage - # To simply define a new TLV class, do: - # MyTLV = PacketGen::Types::AbstractTLV.create - # MyTLV.define_type_enum 'one' => 1, 'two' => 2 - # This will define a new +MyTLV+ class, subclass of {Fields}. This class will - # define 3 fields: - # * +#type+, as a {Int8Enum} by default, - # * +#length+, as a {Int8} by default, - # * and +#value+, as a {String} by default. - # +.define_type_enum+ is, here, necessary to define enum hash to be used - # for +#type+ accessor, as this one is defined as an {Enum}. - # - # This class may then be used as older {TLV} class: - # tlv = MyTLV.new(type: 1, value: 'abcd') # automagically set #length from value - # tlv.type #=> 1 - # tlv.human_type #=> 'one' - # tlv.length #=> 4 - # tlv.value #=> "abcd" - # - # ===Advanced usage - # Each field's type may be changed at generating TLV class: - # MyTLV = PacketGen::Types::AbstractTLV.create(type_class: PacketGen::Types::Int16, - # length_class: PacketGen::Types::Int16, - # value_class: PacketGen::Header::IP::Addr) - # tlv = MyTLV.new(type: 1, value: '1.2.3.4') - # tlv.type #=> 1 - # tlv.length #=> 4 - # tlv.value #=> '1.2.3.4' - # tlv.to_s #=> "\x00\x01\x00\x04\x01\x02\x03\x04" - # - # Some aliases may also be defined. For example, to create a TLV type - # whose +type+ field should be named +code+: - # MyTLV = PacketGen::Types::AbstractTLV.create(type_class: PacketGen::Types::Int16, - # length_class: PacketGen::Types::Int16, - # aliases: { code: :type }) - # tlv = MyTLV.new(code: 1, value: 'abcd') - # tlv.code #=> 1 - # tlv.type #=> 1 - # tlv.length #=> 4 - # tlv.value #=> 'abcd' - # - # @author Sylvain Daubert - # @since 3.1.0 - # @since 3.1.1 add +:aliases+ keyword to {#initialize} - class AbstractTLV < Types::Fields - include Fieldable - - # @private - FIELD_TYPES = { 'T' => :type, 'L' => :length, 'V' => :value }.freeze - - class << self - # @return [Hash] - attr_accessor :aliases - # @private - attr_accessor :field_in_length - - # rubocop:disable Metrics/ParameterLists - - # Generate a TLV class - # @param [Class] type_class Class to use for +type+ - # @param [Class] length_class Class to use for +length+ - # @param [Class] value_class Class to use for +value+ - # @param [String] field_order give field order. Each character in [T,L,V] MUST be present once, in the desired order. - # @param [String] field_in_length give fields to compute length on. - # @return [Class] - # @since 3.3.1 Add +field_order+ and +field_in_length' parameters - def create(type_class: Int8Enum, length_class: Int8, value_class: String, - aliases: {}, field_order: 'TLV', field_in_length: 'V') - raise Error, '.create cannot be called on a subclass of PacketGen::Types::AbstractTLV' unless self.equal?(AbstractTLV) - - klass = Class.new(self) - klass.aliases = aliases - klass.field_in_length = field_in_length - - check_field_in_length(field_in_length) - check_field_order(field_order) - generate_fields(klass, field_order, type_class, length_class, value_class) - - aliases.each do |al, orig| - klass.instance_eval do - alias_method al, orig if klass.method_defined?(orig) - alias_method :"#{al}=", :"#{orig}=" if klass.method_defined?(:"#{orig}=") - end - end - - klass - end - # rubocop:enable Metrics/ParameterLists - - # @!attribute type - # @abstract Type attribute for real TLV class - # @return [Integer] - # @!attribute length - # @abstract Length attribute for real TLV class - # @return [Integer] - # @!attribute value - # @abstract Value attribute for real TLV class - # @return [Object] - - # @abstract Should only be called on real TLV classes, created by {.create}. - # Set enum hash for {#type} field. - # @param [Hash{String, Symbol => Integer}] hsh enum hash - # @return [void] - def define_type_enum(hsh) - field_defs[:type][:enum].clear - field_defs[:type][:enum].merge!(hsh) - end - - # @abstract Should only be called on real TLV classes, created by {.create}. - # Set default value for {#type} field. - # @param [Integer,String,Symbol,nil] default default value from +hsh+ for type - # @return [void] - # @since 3.4.0 - def define_type_default(default) - field_defs[:type][:default] = default - end - - private - - def check_field_in_length(field_in_length) - return if /^[TLV]{1,3}$/.match?(field_in_length) - - raise 'field_in_length must only contain T, L and/or V characters' - end - - def check_field_order(field_order) - return if field_order.match(/^[TLV]{3,3}$/) && (field_order[0] != field_order[1]) && (field_order[0] != field_order[2]) && (field_order[1] != field_order[2]) - - raise 'field_order must contain all three letters TLV, each once' - end - - def generate_fields(klass, field_order, type_class, length_class, value_class) - field_order.each_char do |field_type| - case field_type - when 'T' - if type_class < Enum - klass.define_field(:type, type_class, enum: {}) - else - klass.define_field(:type, type_class) - end - when 'L' - klass.define_field(:length, length_class) - when 'V' - klass.define_field(:value, value_class) - end - end - end - end - - # @!attribute type - # @abstract Type attribute - # @return [Integer] - # @!attribute length - # @abstract Length - # @return [Integer] - # @!attribute value - # @abstract Value attribute - # @return [Object] - - # @abstract Should only be called on real TLV classes, created by {.create}. - # @param [Hash] options - # @option options [Integer] :type - # @option options [Integer] :length - # @option options [Object] :value - def initialize(options={}) - @field_in_length = self.class.field_in_length - self.class.aliases.each do |al, orig| - options[orig] = options[al] if options.key?(al) - end - - super - # used #value= defined below, which set length if needed - self.value = options[:value] if options[:value] - calc_length unless options.key?(:length) - end - - # @abstract Should only be called on real TLV class instances. - # Populate object from a binary string - # @param [String,nil] str - # @return [Fields] self - def read(str) - return self if str.nil? - - idx = 0 - fields.each do |field_name| - field = self[field_name] - length = field_name == :value ? real_length : field.sz - field.read(str[idx, length]) - idx += field.sz - end - - self - end - - # @abstract Should only be called on real TLV class instances. - # Set +value+. May set +length+ if value is a {Types::String}. - # @param [Object] val - # @return [Object] - # @since 3.4.0 Base on field's +#from_human+ method - def value=(val) - if val.is_a?(self[:value].class) - self[:value] = val - elsif self[:value].respond_to?(:from_human) - self[:value].from_human(val) - else - self[:value].read(val) - end - calc_length - val - end - - # @abstract Should only be called on real TLV class instances. - # Get human-readable type - # @return [String] - def human_type - self[:type].to_human.to_s - end - - # @abstract Should only be called on real TLV class instances. - # @return [String] - def to_human - my_value = self[:value].is_a?(String) ? self[:value].inspect : self[:value].to_human - 'type:%s,length:%u,value:%s' % [human_type, length, my_value] - end - - # Calculate length - # @return [void] - # @since 3.4.0 - def calc_length - fil = @field_in_length - - length = 0 - fil.each_char do |field_type| - length += self[FIELD_TYPES[field_type]].sz - end - self.length = length - end - - private - - def real_length - length = self.length - length -= self[:type].sz if @field_in_length.include?('T') - length -= self[:length].sz if @field_in_length.include?('L') - length - end - end - end -end diff --git a/lib/packetgen/types/array.rb b/lib/packetgen/types/array.rb deleted file mode 100644 index cfce054..0000000 --- a/lib/packetgen/types/array.rb +++ /dev/null @@ -1,287 +0,0 @@ -# frozen_string_literal: true - -# This file is part of PacketGen -# See https://github.com/lemontree55/packetgen for more informations -# Copyright (C) 2016 Sylvain Daubert -# Copyright (C) 2024 LemonTree55 -# This program is published under MIT license. - -require 'forwardable' - -module PacketGen - module Types - # @abstract Base class to define set of {Fields} subclasses. - # == #record_from_hash - # Subclasses should define private method +#record_from_hash+. This method - # is called by {#push} to add an object to the set. - # - # A default method is defined by {Array}: it calls constructor of class defined - # by {.set_of}. - # - # == #real_type - # Subclasses should define private method +#real_type+ if {.set_of} type - # may be subclassed. This method should return real class to use. It - # takes an only argument, which is of type given by {.set_of}. - # - # Default behaviour of this method is to return argument's class. - # - # @author Sylvain Daubert - class Array - extend Forwardable - include Enumerable - include Fieldable - include LengthFrom - - # @!method [](index) - # Return the element at +index+. - # @param [integer] index - # @return [Object] - # @!method clear - # Clear array. - # @return [void] - # @!method each - # Calls the given block once for each element in self, passing that - # element as a parameter. Returns the array itself. - # @return [Array] - # @method empty? - # Return +true+ if contains no element. - # @return [Booelan] - # @!method first - # Return first element - # @return [Object] - # @!method last - # Return last element. - # @return [Object] - # @!method size - # Get number of element in array - # @return [Integer] - def_delegators :@array, :[], :clear, :each, :empty?, :first, :last, :size - alias length size - - # Separator used in {#to_human}. - # May be ovverriden by subclasses - HUMAN_SEPARATOR = ',' - - # rubocop:disable Naming/AccessorMethodName - class << self - # Get class set with {.set_of}. - # @return [Class] - # @since 3.0.0 - def set_of_klass - @klass - end - - # Define type of objects in set. Used by {#read} and {#push}. - # @param [Class] klass - # @return [void] - def set_of(klass) - @klass = klass - end - end - # rubocop:enable Naming/AccessorMethodName - - # @param [Hash] options - # @option options [Int] counter Int object used as a counter for this set - def initialize(options={}) - @counter = options[:counter] - @array = [] - initialize_length_from(options) - end - - # Initialize array for copy: - # * duplicate internal array. - def initialize_copy(_other) - @array = @array.dup - end - - def ==(other) - @array == case other - when Array - other.to_a - else - other - end - end - - # Clear array. Reset associated counter, if any. - # @return [void] - def clear! - @array.clear - @counter&.read(0) - end - - # Delete an object from this array. Update associated counter if any - # @param [Object] obj - # @return [Object] deleted object - def delete(obj) - deleted = @array.delete(obj) - @counter.read(@counter.to_i - 1) if @counter && deleted - deleted - end - - # Delete element at +index+. - # @param [Integer] index - # @return [Object,nil] deleted object - def delete_at(index) - deleted = @array.delete_at(index) - @counter.read(@counter.to_i - 1) if @counter && deleted - deleted - end - - # @abstract depend on private method +#record_from_hash+ which should be - # declared by subclasses. - # Add an object to this array - # @param [Object] obj type depends on subclass - # @return [Array] self - def push(obj) - obj = case obj - when Hash - record_from_hash obj - else - obj - end - @array << obj - self - end - - # @abstract depend on private method +#record_from_hash+ which should be - # declared by subclasses. - # Add an object to this array, and increment associated counter, if any - # @param [Object] obj type depends on subclass - # @return [Array] self - def <<(obj) - push obj - @counter&.read(@counter.to_i + 1) - self - end - - # Populate object from a string or from an array of hashes - # @param [String, Array] data - # @return [self] - def read(data) - clear - case data - when ::Array - read_from_array(data) - else - read_from_string(data) - end - self - end - - # Get size in bytes - # @return [Integer] - def sz - to_s.size - end - - # Return an Array - # @return [::Array] - def to_a - @array - end - - # Get binary string - # @return [String] - def to_s - @array.map(&:to_s).join - end - - # Get a human readable string - # @return [String] - def to_human - @array.map(&:to_human).join(self.class::HUMAN_SEPARATOR) - end - - private - - # rubocop:disable Metrics/CyclomaticComplexity - - def read_from_string(str) - return self if str.nil? || @counter&.to_i&.zero? - - str = read_with_length_from(str) - until str.empty? || (@counter && self.size == @counter.to_i) - obj = create_object_from_str(str) - @array << obj - str.slice!(0, obj.sz) - end - end - # rubocop:enable Metrics/CyclomaticComplexity - - def read_from_array(ary) - return self if ary.empty? - - ary.each do |hsh| - self << hsh - end - end - - def record_from_hash(hsh) - obj_klass = self.class.set_of_klass - raise NotImplementedError, 'class should define #record_from_hash or declare type of elements in set with .set_of' unless obj_klass - - obj = obj_klass.new(hsh) if obj_klass - klass = real_type(obj) - klass == obj_klass ? obj : klass.new(hsh) - end - - def real_type(_obj) - self.class.set_of_klass - end - - def create_object_from_str(str) - klass = self.class.set_of_klass - obj = klass.new.read(str) - real_klass = real_type(obj) - - if real_klass == klass - obj - else - real_klass.new.read(str) - end - end - end - - # @private - module ArrayOfIntMixin - def read_from_array(ary) - return self if ary.empty? - - ary.each do |i| - self << self.class.set_of_klass.new(i) - end - end - end - - # Specialized array to handle serie of {Int8}. - class ArrayOfInt8 < Array - include ArrayOfIntMixin - set_of Int8 - end - - # Specialized array to handle serie of {Int16}. - class ArrayOfInt16 < Array - include ArrayOfIntMixin - set_of Int16 - end - - # Specialized array to handle serie of {Int16le}. - class ArrayOfInt16le < Array - include ArrayOfIntMixin - set_of Int16le - end - - # Specialized array to handle serie of {Int32}. - class ArrayOfInt32 < Types::Array - include ArrayOfIntMixin - set_of Types::Int32 - end - - # Specialized array to handle serie of {Int32le}. - class ArrayOfInt32le < Types::Array - include ArrayOfIntMixin - set_of Types::Int32le - end - end -end diff --git a/lib/packetgen/types/cstring.rb b/lib/packetgen/types/cstring.rb deleted file mode 100644 index 57a5f11..0000000 --- a/lib/packetgen/types/cstring.rb +++ /dev/null @@ -1,109 +0,0 @@ -# coding: utf-8 -# frozen_string_literal: true - -# This file is part of PacketGen -# See https://github.com/lemontree55/packetgen for more informations -# Copyright (C) 2016 Sylvain Daubert -# Copyright (C) 2024 LemonTree55 -# This program is published under MIT license. - -require 'forwardable' - -module PacketGen - module Types - # This class handles null-terminated strings (aka C strings). - # @author Sylvain Daubert - # @since 3.1.6 no more a subclass or regular String - class CString - extend Forwardable - include Fieldable - - def_delegators :@string, :[], :length, :size, :inspect, :==, - :unpack, :force_encoding, :encoding, :index, :empty?, - :encode, :slice, :slice! - - # @return [::String] - attr_reader :string - # @return [Integer] - attr_reader :static_length - - # @param [Hash] options - # @option options [Integer] :static_length set a static length for this string - def initialize(options={}) - register_internal_string(+'') - @static_length = options[:static_length] - end - - # @param [::String] str - # @return [String] self - def read(str) - s = str.to_s - s = s[0, static_length] if static_length? - register_internal_string s - remove_null_character - self - end - - # get null-terminated string - # @return [String] - def to_s - if static_length? - s = string[0, static_length - 1] - s << "\x00" * (static_length - s.length) - else - s = "#{string}\x00" - end - PacketGen.force_binary(s) - end - - # Append the given string to CString - # @param [#to_s] str - # @return [self] - def <<(str) - @string << str.to_s - remove_null_character - self - end - - # @return [Integer] - def sz - if static_length? - static_length - else - to_s.size - end - end - - # Say if a static length is defined - # @return [Boolean] - # @since 3.1.6 - def static_length? - !static_length.nil? - end - - # Populate CString from a human readable string - # @param [String] str - # @return [self] - def from_human(str) - read str - end - - # @return [String] - def to_human - string - end - - private - - def register_internal_string(str) - @string = str - PacketGen.force_binary(@string) - end - - def remove_null_character - idx = string.index(0.chr) - register_internal_string(string[0, idx]) unless idx.nil? - end - end - end -end diff --git a/lib/packetgen/types/enum.rb b/lib/packetgen/types/enum.rb deleted file mode 100644 index 95ce3f0..0000000 --- a/lib/packetgen/types/enum.rb +++ /dev/null @@ -1,171 +0,0 @@ -# coding: utf-8 -# frozen_string_literal: true - -# This file is part of PacketGen -# See https://github.com/lemontree55/packetgen for more informations -# Copyright (C) 2016 Sylvain Daubert -# Copyright (C) 2024 LemonTree55 -# This program is published under MIT license. - -module PacketGen - module Types - # @abstract Base enum class to handle binary integers with limited - # authorized values - # An {Enum} type is used to handle an {Int} field with limited - # and named values. - # - # == Simple example - # enum = Int8Enum.new('low' => 0, 'medium' => 1, 'high' => 2}) - # In this example, +enum+ is a 8-bit field which may take one - # among three values: +low+, +medium+ or +high+: - # enum.value = 'high' - # enum.value # => 2 - # enum.value = 1 - # enum.value # => 1 - # enum.to_human # => "medium" - # Setting an unknown value will raise an exception: - # enum.value = 4 # => raise! - # enum.value = 'unknown' # => raise! - # But {#read} will not raise when reading an outbound value. This - # to enable decoding (or forging) of bad packets. - # @since 2.1.3 - # @author Sylvain Daubert - class Enum < Int - # @return [Hash] - attr_reader :enum - - # @param [Hash] enum enumerated values. Default value is taken from - # first element unless given. - # @param [:little,:big,nil] endian - # @param [Integer,nil] width - # @param [Integer,nil] default default value - def initialize(enum, endian=nil, width=nil, default=nil) - default ||= enum[enum.keys.first] - super(nil, endian, width, default) - @enum = enum - end - - # Setter for value attribute - # @param [#to_i, String,nil] value value as an Integer or as a String - # from enumration - # @return [Integer] - # @raise [ArgumentError] String value is unknown - def value=(value) - ival = case value - when NilClass - nil - when ::String - raise ArgumentError, "#{value.inspect} not in enumeration" unless @enum.key? value - - @enum[value] - else - value.to_i - end - @value = ival - end - - # To handle human API: set value from a String - alias from_human value= - - # Get human readable value (enum name) - # @return [String] - def to_human - @enum.key(to_i) || "" - end - - def format_inspect - format_str % [to_human, to_i] - end - end - - # Enumeration on one byte. See {Enum}. - # @author Sylvain Daubert - # @since 2.1.3 - class Int8Enum < Enum - # @param [Integer] default - # @param [Hash] enum - def initialize(enum, default=nil) - super(enum, nil, 1, default) - @packstr = { nil => 'C' } - end - end - - # Enumeration on 2-byte integer. See {Enum}. - # @author Sylvain Daubert - # @since 2.1.3 - class Int16Enum < Enum - # @param [Hash] enum - # @param [:big, :little] endian - # @param [Integer,nil] default default value - def initialize(enum, endian=:big, default=nil) - super(enum, endian, 2, default) - @packstr = { big: 'n', little: 'v' } - end - end - - # Enumeration on big endian 2-byte integer. See {Enum}. - # @author Sylvain Daubert - # @since 2.1.3 - class Int16beEnum < Int16Enum - undef endian= - - # @param [Hash] enum - # @param [Integer,nil] default default value - def initialize(enum, default=nil) - super(enum, :big, default) - end - end - - # Enumeration on big endian 2-byte integer. See {Enum}. - # @author Sylvain Daubert - # @since 2.1.3 - class Int16leEnum < Int16Enum - undef endian= - - # @param [Hash] enum - # @param [Integer,nil] default default value - def initialize(enum, default=nil) - super(enum, :little, default) - end - end - - # Enumeration on 4-byte integer. See {Enum}. - # @author Sylvain Daubert - # @since 2.1.3 - class Int32Enum < Enum - # @param [Hash] enum - # @param [:big, :little] endian - # @param [Integer,nil] default default value - def initialize(enum, endian=:big, default=nil) - super(enum, endian, 4, default) - @packstr = { big: 'N', little: 'V' } - end - end - - # Enumeration on big endian 4-byte integer. See {Enum}. - # @author Sylvain Daubert - # @since 2.1.3 - class Int32beEnum < Int32Enum - undef endian= - - # @param [Hash] enum - # @param [Integer,nil] default default value - def initialize(enum, default=nil) - super(enum, :big, default) - end - end - - # Enumeration on big endian 4-byte integer. See {Enum}. - # @author Sylvain Daubert - # @since 2.1.3 - class Int32leEnum < Int32Enum - undef endian= - - # @param [Hash] enum - # @param [Integer,nil] default default value - def initialize(enum, default=nil) - super(enum, :little, default) - end - end - end -end diff --git a/lib/packetgen/types/fieldable.rb b/lib/packetgen/types/fieldable.rb deleted file mode 100644 index ea8a74f..0000000 --- a/lib/packetgen/types/fieldable.rb +++ /dev/null @@ -1,66 +0,0 @@ -# frozen_string_literal: true - -# This file is part of PacketGen -# See https://github.com/lemontree55/packetgen for more informations -# Copyright (C) 2016 Sylvain Daubert -# Copyright (C) 2024 LemonTree55 -# This program is published under MIT license. - -module PacketGen - module Types - # Mixin to define minimal API for a class to be embbeded as a field in - # {Fields} type. - # - # == Optional methods - # These methods may, optionally, be defined by fieldable types: - # * +from_human+ to load data from a human-readable string. - # @author Sylvain Daubert - # @since 3.1.6 - module Fieldable - # Get type name - # @return [String] - def type_name - self.class.to_s.split('::').last - end - - # rubocop:disable Lint/UselessMethodDefinition - # These methods are defined for documentation. - - # Populate object from a binary string - # @param [String] str - # @return [Fields] self - # @abstract subclass should overload it. - def read(str) - super - end - - # Return object as a binary string - # @return [String] - # @abstract subclass should overload it. - def to_s - super - end - - # Size of object as binary string - # @return [Integer] - def sz - to_s.size - end - - # Return a human-readbale string - # @return [String] - # @abstract subclass should overload it. - def to_human - super - end - - # rubocop:enable Lint/UselessMethodDefinition - - # Format object when inspecting a {Fields} object - # @return [String] - def format_inspect - to_human - end - end - end -end diff --git a/lib/packetgen/types/fields.rb b/lib/packetgen/types/fields.rb deleted file mode 100644 index 5bedace..0000000 --- a/lib/packetgen/types/fields.rb +++ /dev/null @@ -1,622 +0,0 @@ -# frozen_string_literal: true - -# This file is part of PacketGen -# See https://github.com/lemontree55/packetgen for more informations -# Copyright (C) 2016 Sylvain Daubert -# Copyright (C) 2024 LemonTree55 -# This program is published under MIT license. - -# rubocop:disable Metrics/ClassLength - -module PacketGen - module Types - # @abstract Set of fields - # This class is a base class to define headers or anything else with a binary - # format containing multiple fields. - # - # == Basics - # A {Fields} subclass is generaly composed of multiple binary fields. These fields - # have each a given type. All {Fieldable} types are supported. - # - # To define a new subclass, it has to inherit from {Fields}. And some class - # methods have to be used to declare attributes/fields: - # class MyBinaryStructure < PacketGen::Types::Fields - # # define a first Int8 attribute, with default value: 1 - # define_field :attr1, PacketGen::Types::Int8, default: 1 - # #define a second attribute, of kind Int32 - # define_field :attr2, PacketGen::Types::Int32 - # end - # - # These defintions create 4 methods: +#attr1+, +#attr1=+, +#attr2+ and +#attr2=+. - # All these methods take and/or return Integers. - # - # Fields may also be accessed through {#[]} ans {#[]=}. These methods give access - # to type object: - # mybs = MyBinaryStructure.new - # mybs.attr1 # => Integer - # mybs[:attr1] # => PacketGen::Types::Int8 - # - # {#initialize} accepts an option hash to populate attributes. Keys are attribute - # name symbols, and values are those expected by writer accessor. - # - # {#read} is able to populate object from a binary string. - # - # {#to_s} returns binary string from object. - # - # == Add Fields - # {.define_field} adds a field to Fields subclass. A lot of field types may be - # defined: integer types, string types (to handle a stream of bytes). More - # complex field types may be defined using others Fields subclasses: - # # define a 16-bit little-endian integer field, named type - # define_field :type, PacketGen::Types::Int16le - # # define a string field - # define_field :body, PacketGen::Types::String - # # define a field using a complex type (Fields subclass) - # define_field :mac_addr, PacketGen::Eth::MacAddr - # - # This example creates six methods on our Fields subclass: +#type+, +#type=+, - # +#body+, +#body=+, +#mac_addr+ and +#mac_addr=+. - # - # {.define_field} has many options (third optional Hash argument): - # * +:default+ gives default field value. It may be a simple value (an Integer - # for an Int field, for example) or a lambda, - # * +:builder+ to give a builder/constructor lambda to create field. The lambda - # takes 2 argument: {Fields} subclass object owning field, and type class as passes - # as second argument to .define_field, - # * +:optional+ to define this field as optional. This option takes a lambda - # parameter used to say if this field is present or not. The lambda takes an argument - # ({Fields} subclass object owning field), - # * +:enum+ to define Hash enumeration for an {Enum} type. - # For example: - # # 32-bit integer field defaulting to 1 - # define_field :type, PacketGen::Types::Int32, default: 1 - # # 16-bit integer field, created with a random value. Each instance of this - # # object will have a different value. - # define_field :id, PacketGen::Types::Int16, default: ->(obj) { rand(65535) } - # # a size field - # define_field :body_size, PacketGen::Types::Int16 - # # String field which length is taken from body_size field - # define_field :body, PacketGen::Types::String, builder: ->(obj, type) { type.new(length_from: obj[:body_size]) } - # # 16-bit enumeration type. As :default not specified, default to first value of enum - # define_field :type_class, PacketGen::Types::Int16Enum, enum: { 'class1' => 1, 'class2' => 2} - # # optional field. Only present if another field has a certain value - # define_field :opt1, PacketGen::Types::Int16, optional: ->(h) { h.type == 42 } - # - # {.define_field_before} and {.define_field_after} are also defined to relatively - # create a field from anoher one (for example, when adding a field in a subclass). - # == Generating bit fields - # {.define_bit_fields_on} creates a bit field on a previuously declared integer - # field. For example, +frag+ field in IP header: - # define_field :frag, Types::Int16, default: 0 - # define_bit_fields_on :frag, :flag_rsv, :flag_df, :flag_mf, :fragment_offset, 13 - # - # This example generates methods: - # * +#frag+ and +#frag=+ to access +frag+ field as a 16-bit integer, - # * +#flag_rsv?+, +#flag_rsv=+, +#flag_df?+, +#flag_df=+, +#flag_mf?+ and +#flag_mf=+ - # to access Boolean RSV, MF and DF flags from +frag+ field, - # * +#fragment_offset+ and +#fragment_offset=+ to access 13-bit integer fragment - # offset subfield from +frag+ field. - # - # == Creating a new field class from another one - # Some methods may help in this case: - # * {.define_field_before} to define a new field before an existing one, - # * {.define_field_after} to define a new field after an existing onr, - # * {.remove_field} to remove an existing field, - # * {.uptade_fied} to change options of a field (but not its type), - # * {.remove_bit_fields_on} to remove a bit fields definition. - # - # @author Sylvain Daubert - class Fields - # @private - FieldDef = Struct.new(:type, :default, :builder, :optional, :enum, :options) - # @private field names, ordered as they were declared - @ordered_fields = [] - # @private field definitions - @field_defs = {} - # @private bit field definitions - @bit_fields = {} - - class << self - # Get field definitions for this class. - # @return [Hash] - # @since 3.1.0 - attr_reader :field_defs - # Get bit fields defintions for this class - # @return [Hash] - # @since 3.1.5 - attr_reader :bit_fields - - # On inheritage, create +@field_defs+ class variable - # @param [Class] klass - # @return [void] - def inherited(klass) - super - - field_defs = {} - @field_defs.each do |k, v| - field_defs[k] = v.clone - end - ordered = @ordered_fields.clone - bf = bit_fields.clone - - klass.class_eval do - @ordered_fields = ordered - @field_defs = field_defs - @bit_fields = bf - end - end - - # Get field names - # @return [Array] - def fields - @ordered_fields - end - - # Define a field in class - # class BinaryStruct < PacketGen::Types::Fields - # # 8-bit value - # define_field :value1, Types::Int8 - # # 16-bit value - # define_field :value2, Types::Int16 - # # specific class, may use a specific constructor - # define_field :value3, MyClass, builder: ->(obj, type) { type.new(obj) } - # end - # - # bs = BinaryStruct.new - # bs[value1] # => Types::Int8 - # bs.value1 # => Integer - # @param [Symbol] name field name - # @param [Fieldable] type class or instance - # @param [Hash] options Unrecognized options are passed to object builder if - # +:builder+ option is not set. - # @option options [Object] :default default value. May be a proc. This lambda - # take one argument: the caller object. - # @option options [Lambda] :builder lambda to construct this field. - # Parameters to this lambda is the caller object and the field type class. - # @option options [Lambda] :optional define this field as optional. Given lambda - # is used to known if this field is present or not. Parameter to this lambda is - # the being defined Field object. - # @option options [Hash] :enum mandatory option for an {Enum} type. - # Define enumeration: hash's keys are +String+, and values are +Integer+. - # @return [void] - def define_field(name, type, options={}) - fields << name - field_defs[name] = FieldDef.new(type, - options.delete(:default), - options.delete(:builder), - options.delete(:optional), - options.delete(:enum), - options) - - add_methods(name, type) - end - - # Define a field, before another one - # @param [Symbol,nil] other field name to create a new one before. If +nil+, - # new field is appended. - # @param [Symbol] name field name to create - # @param [Fieldable] type class or instance - # @param [Hash] options See {.define_field}. - # @return [void] - # @see .define_field - def define_field_before(other, name, type, options={}) - define_field name, type, options - return if other.nil? - - fields.delete name - idx = fields.index(other) - raise ArgumentError, "unknown #{other} field" if idx.nil? - - fields[idx, 0] = name - end - - # Define a field, after another one - # @param [Symbol,nil] other field name to create a new one after. If +nil+, - # new field is appended. - # @param [Symbol] name field name to create - # @param [Fieldable] type class or instance - # @param [Hash] options See {.define_field}. - # @return [void] - # @see .define_field - def define_field_after(other, name, type, options={}) - define_field name, type, options - return if other.nil? - - fields.delete name - idx = fields.index(other) - raise ArgumentError, "unknown #{other} field" if idx.nil? - - fields[idx + 1, 0] = name - end - - # Remove a previously defined field - # @param [Symbol] name - # @return [void] - # @since 2.8.4 - def remove_field(name) - fields.delete name - @field_defs.delete name - undef_method name if method_defined?(name) - undef_method :"#{name}=" if method_defined?(:"#{name}=") - end - - # Update a previously defined field - # @param [Symbol] field field name to create - # @param [Hash] options See {.define_field}. - # @return [void] - # @see .define_field - # @raise [ArgumentError] unknown +field+ - # @since 2.8.4 - def update_field(field, options) - check_existence_of field - - %i[default builder optional enum].each do |property| - field_defs_property_from(field, property, options) - end - - field_defs[field].options.merge!(options) - end - - # Define a bitfield on given attribute - # class MyHeader < PacketGen::Types::Fields - # define_field :flags, Types::Int16 - # # define a bit field on :flag attribute: - # # flag1, flag2 and flag3 are 1-bit fields - # # type and stype are 3-bit fields. reserved is a 6-bit field - # define_bit_fields_on :flags, :flag1, :flag2, :flag3, :type, 3, :stype, 3, :reserved, 7 - # end - # A bitfield of size 1 bit defines 2 methods: - # * +#field?+ which returns a Boolean, - # * +#field=+ which takes and returns a Boolean. - # A bitfield of more bits defines 2 methods: - # * +#field+ which returns an Integer, - # * +#field=+ which takes and returns an Integer. - # @param [Symbol] attr attribute name (attribute should be a {Types::Int} - # subclass) - # @param [Array] args list of bitfield names. Name may be followed - # by bitfield size. If no size is given, 1 bit is assumed. - # @raise [ArgumentError] unknown +attr+ - # @return [void] - def define_bit_fields_on(attr, *args) - check_existence_of attr - - type = field_defs[attr].type - raise TypeError, "#{attr} is not a PacketGen::Types::Int" unless type < Types::Int - - total_size = type.new.nbits - idx = total_size - 1 - - until args.empty? - field = args.shift - next unless field.is_a? Symbol - - size = size_from(args) - - unless field == :_ - add_bit_methods(attr, field, size, total_size, idx) - register_bit_field_size(attr, field, size) - end - - idx -= size - end - end - - # Remove all bit fields defined on +attr+ - # @param [Symbol] attr attribute defining bit fields - # @return [void] - # @since 2.8.4 - def remove_bit_fields_on(attr) - fields = bit_fields.delete(attr) - return if fields.nil? - - fields.each do |field, size| - undef_method :"#{field}=" - undef_method(size == 1 ? "#{field}?" : field) - end - end - - private - - def add_methods(name, type) - define = [] - if type < Types::Enum - define << "def #{name}; self[:#{name}].to_i; end" - define << "def #{name}=(val) self[:#{name}].value = val; end" - else - # rubocop:disable Layout/LineContinuationLeadingSpace - define << "def #{name}\n" \ - " to_and_from_human?(:#{name}) ? self[:#{name}].to_human : self[:#{name}]\n" \ - 'end' - define << "def #{name}=(val)\n" \ - " to_and_from_human?(:#{name}) ? self[:#{name}].from_human(val) : self[:#{name}].read(val)\n" \ - 'end' - # rubocop:enable Layout/LineContinuationLeadingSpace - end - - define.delete_at(1) if instance_methods.include?(:"#{name}=") - define.delete_at(0) if instance_methods.include? name - class_eval define.join("\n") - end - - def add_bit_methods(attr, name, size, total_size, idx) - shift = idx - (size - 1) - - if size == 1 - add_single_bit_methods(attr, name, size, total_size, shift) - else - add_multibit_methods(attr, name, size, total_size, shift) - end - end - - def compute_field_mask(size, shift) - (2**size - 1) << shift - end - - def compute_clear_mask(total_size, field_mask) - (2**total_size - 1) & (~field_mask & (2**total_size - 1)) - end - - def add_single_bit_methods(attr, name, size, total_size, shift) - field_mask = compute_field_mask(size, shift) - clear_mask = compute_clear_mask(total_size, field_mask) - - class_eval <<-METHODS - def #{name}? # def bit? - val = (self[:#{attr}].to_i & #{field_mask}) >> #{shift} # val = (self[:attr}].to_i & 1}) >> 1 - val != 0 # val != 0 - end # end - def #{name}=(v) # def bit=(v) - val = v ? 1 : 0 # val = v ? 1 : 0 - self[:#{attr}].value = self[:#{attr}].to_i & #{clear_mask} # self[:attr].value = self[:attr].to_i & 0xfffd - self[:#{attr}].value |= val << #{shift} # self[:attr].value |= val << 1 - end # end - METHODS - end - - def add_multibit_methods(attr, name, size, total_size, shift) - field_mask = compute_field_mask(size, shift) - clear_mask = compute_clear_mask(total_size, field_mask) - - class_eval <<-METHODS - def #{name} # def multibit - (self[:#{attr}].to_i & #{field_mask}) >> #{shift} # (self[:attr].to_i & 6) >> 1 - end # end - def #{name}=(v) # def multibit=(v) - self[:#{attr}].value = self[:#{attr}].to_i & #{clear_mask} # self[:attr].value = self[:attr].to_i & 0xfff9 - self[:#{attr}].value |= (v & #{2**size - 1}) << #{shift} # self[:attr].value |= (v & 3) << 1 - end # end - METHODS - end - - def register_bit_field_size(attr, field, size) - bit_fields[attr] = {} if bit_fields[attr].nil? - bit_fields[attr][field] = size - end - - def field_defs_property_from(field, property, options) - field_defs[field].send(:"#{property}=", options.delete(property)) if options.key?(property) - end - - def size_from(args) - if args.first.is_a? Integer - args.shift - else - 1 - end - end - - def check_existence_of(field) - raise ArgumentError, "unknown #{field} field for #{self}" unless field_defs.key?(field) - end - end - - # Create a new fields object - # @param [Hash] options Keys are symbols. They should have name of object - # attributes, as defined by {.define_field} and by {.define_bit_fields_on}. - def initialize(options={}) - @fields = {} - @optional_fields = {} - - self.class.fields.each do |field| - build_field field - initialize_value field, options[field] - initialize_optional field - end - - self.class.bit_fields.each_value do |hsh| - hsh.each_key do |bit_field| - self.send(:"#{bit_field}=", options[bit_field]) if options[bit_field] - end - end - end - - # Get field object - # @param [Symbol] field - # @return [Fieldable] - def [](field) - @fields[field] - end - - # Set field object - # @param [Symbol] field - # @param [Object] obj - # @return [Object] - def []=(field, obj) - @fields[field] = obj - end - - # Get all field names - # @return [Array] - def fields - self.class.fields - end - - # Get all optional field name - # @return[Array,nil] - def optional_fields - @optional_fields.keys - end - - # Say if this field is optional - # @return [Boolean] - def optional?(field) - @optional_fields.key? field - end - - # Say if an optional field is present - # @return [Boolean] - def present?(field) - return true unless optional?(field) - - @optional_fields[field].call(self) - end - - # Populate object from a binary string - # @param [String] str - # @return [Fields] self - def read(str) - return self if str.nil? - - force_binary str - start = 0 - fields.each do |field| - next unless present?(field) - - obj = self[field].read str[start..] - start += self[field].sz - self[field] = obj unless obj == self[field] - end - - self - end - - # Common inspect method for headers. - # - # A block may be given to differently format some attributes. This - # may be used by subclasses to handle specific fields. - # @yieldparam attr [Symbol] attribute to inspect - # @yieldreturn [String,nil] the string to print for +attr+, or +nil+ - # to let +inspect+ generate it - # @return [String] - def inspect - str = Inspect.dashed_line(self.class, 1) - fields.each do |attr| - next if attr == :body - next unless present?(attr) - - result = yield(attr) if block_given? - str << (result || Inspect.inspect_attribute(attr, self[attr], 1)) - end - str - end - - # Return object as a binary string - # @return [String] - def to_s - fields.select { |f| present?(f) } - .map! { |f| force_binary @fields[f].to_s }.join - end - - # Size of object as binary string - # @return [nteger] - def sz - to_s.size - end - - # Return object as a hash - # @return [Hash] keys: attributes, values: attribute values - def to_h - fields.to_h { |f| [f, @fields[f].to_human] } - end - - # Get offset of given field in {Fields} structure. - # @param [Symbol] field - # @return [Integer] - # @raise [ArgumentError] unknown field - def offset_of(field) - raise ArgumentError, "#{field} is an unknown field of #{self.class}" unless @fields.include?(field) - - offset = 0 - fields.each do |f| - break offset if f == field - next unless present?(f) - - offset += self[f].sz - end - end - - # Get bit fields definition for given field. - # @param [Symbol] field defining bit fields - # @return [Hash,nil] keys: bit fields, values: their size in bits - # @since 2.8.3 - def bits_on(field) - self.class.bit_fields[field] - end - - private - - # Deeply duplicate +@fields+ - # @return [void] - def initialize_copy(_other) - fields = {} - @fields.each { |k, v| fields[k] = v.dup } - @fields = fields - end - - # Force str to binary encoding - # @param [String] str - # @return [String] - def force_binary(str) - PacketGen.force_binary(str) - end - - # @param [Symbol] attr attribute - # @return [Boolean] +tru+e if #from_human and #to_human are both defined for given attribute - def to_and_from_human?(attr) - self[attr].respond_to?(:to_human) && self[attr].respond_to?(:from_human) - end - - def field_defs - self.class.field_defs - end - - # rubocop:disable Metrics/AbcSize - def build_field(field) - type = field_defs[field].type - - @fields[field] = if field_defs[field].builder - field_defs[field].builder.call(self, type) - elsif field_defs[field].enum - type.new(field_defs[field].enum) - elsif !field_defs[field].options.empty? - type.new(field_defs[field].options) - else - type.new - end - end - # rubocop:enable Metrics/AbcSize - - def initialize_value(field, val) - type = field_defs[field].type - default = field_defs[field].default - default = default.to_proc.call(self) if default.is_a?(Proc) - - value = val || default - if value.class <= type - @fields[field] = value - elsif @fields[field].respond_to? :from_human - @fields[field].from_human(value) - else - @fields[field].read(value) - end - end - - def initialize_optional(field) - optional = field_defs[field].optional - @optional_fields[field] = optional if optional - end - end - end -end - -# rubocop:enable Metrics/ClassLength diff --git a/lib/packetgen/types/int.rb b/lib/packetgen/types/int.rb deleted file mode 100644 index eef9122..0000000 --- a/lib/packetgen/types/int.rb +++ /dev/null @@ -1,473 +0,0 @@ -# coding: utf-8 -# frozen_string_literal: true - -# This file is part of PacketGen -# See https://github.com/lemontree55/packetgen for more informations -# Copyright (C) 2016 Sylvain Daubert -# Copyright (C) 2024 LemonTree55 -# This program is published under MIT license. - -module PacketGen - module Types - # Base integer class to handle binary integers - # @abstract - # @author Sylvain Daubert - # @since 3.3.1 support native endianess - class Int - include Fieldable - - # Integer value - # @return [Integer] - attr_accessor :value - # Integer endianness - # @return [:little,:big,:native] - # @since 3.3.1 add :native - attr_accessor :endian - # Integer size, in bytes - # @return [Integer] - attr_accessor :width - # Integer default value - # @return [Integer] - attr_accessor :default - - # @param [Integer,nil] value - # @param [:little,:big,nil] endian - # @param [Integer,nil] width - # @param [Integer] default - def initialize(value=nil, endian=nil, width=nil, default=0) - @value = value - @endian = endian - @width = width - @default = default - end - - # @abstract - # Read an Int from a binary string or an integer - # @param [Integer, #to_s] value - # @return [self] - # @raise [ParseError] when reading +#to_s+ objects with abstract Int class. - def read(value) - @value = if value.is_a?(Integer) - value.to_i - elsif defined? @packstr - value.to_s.unpack1(@packstr[@endian]) - else - raise ParseError, 'Int#read is abstract and cannot read' - end - self - end - - # @abstract - # @return [::String] - # @raise [ParseError] This is an abstrat method and must be redefined - def to_s - raise ParseError, 'PacketGen::Types::Int#to_s is an abstract method' unless defined? @packstr - - [to_i].pack(@packstr[@endian]) - end - - # Convert Int to Integer - # @return [Integer] - def to_i - @value || @default - end - alias to_human to_i - alias from_human value= - - # Convert Int to Float - # @return [Float] - def to_f - to_i.to_f - end - - # Give size in bytes of self - # @return [Integer] - def sz - width - end - - # Format Int type when inspecting header or packet - # @return [String] - def format_inspect - format_str % [to_i.to_s, to_i] - end - - # Return the number of bits used to encode this Int - # @return [Integer] - # @since 3.2.1 - def nbits - width * 8 - end - - private - - def format_str - "%-16s (0x%0#{width * 2}x)" - end - end - - # One byte unsigned integer - # @author Sylvain Daubert - class Int8 < Int - # @param [Integer,nil] value - def initialize(value=nil) - super(value, nil, 1) - @packstr = { nil => 'C' } - end - end - - # One byte signed integer - # @author Sylvain Daubert - # @since 2.8.2 - class SInt8 < Int - # @param [Integer,nil] value - def initialize(value=nil) - super(value, nil, 1) - @packstr = { nil => 'c' } - end - end - - # 2-byte unsigned integer - # @author Sylvain Daubert - class Int16 < Int - # @param [Integer,nil] value - # @param [:big, :little, :native] endian - def initialize(value=nil, endian=:big) - super(value, endian, 2) - @packstr = { big: 'n', little: 'v', native: 'S' } - end - end - - # big endian 2-byte unsigned integer - # @author Sylvain Daubert - class Int16be < Int16 - undef endian= - end - - # little endian 2-byte unsigned integer - # @author Sylvain Daubert - class Int16le < Int16 - # @param [Integer,nil] value - undef endian= - - # @param [Integer, nil] value - def initialize(value=nil) - super(value, :little) - end - end - - # native endian 2-byte unsigned integer - # @author Sylvain Daubert - # @since 3.3.1 - class Int16n < Int16 - # @param [Integer,nil] value - undef endian= - - # @param [Integer, nil] value - def initialize(value=nil) - super(value, :native) - end - end - - # 2-byte signed integer - # @author Sylvain Daubert - # @since 2.8.2 - class SInt16 < Int16 - # @param [Integer,nil] value - # @param [:big, :little] endian - def initialize(value=nil, endian=:big) - super - @packstr = { big: 's>', little: 's<', native: 's' } - end - end - - # big endian 2-byte signed integer - # @author Sylvain Daubert - # @since 2.8.2 - class SInt16be < SInt16 - undef endian= - end - - # little endian 2-byte signed integer - # @author Sylvain Daubert - # @since 2.8.2 - class SInt16le < SInt16 - # @param [Integer,nil] value - undef endian= - - # @param [Integer, nil] value - def initialize(value=nil) - super(value, :little) - end - end - - # native endian 2-byte signed integer - # @author Sylvain Daubert - # @since 3.3.1 - class SInt16n < SInt16 - # @param [Integer,nil] value - undef endian= - - # @param [Integer, nil] value - def initialize(value=nil) - super(value, :native) - end - end - - # 3-byte unsigned integer - # @author Sylvain Daubert - # @since 2.1.4 - class Int24 < Int - # @param [Integer,nil] value - # @param [:big, :little, :native] endian - def initialize(value=nil, endian=:big) - if endian == :native - endian = if [1].pack('S').unpack1('n') == 1 - :big - else - :little - end - end - super(value, endian, 3) - end - - # Read an 3-byte Int from a binary string or an integer - # @param [Integer, String] value - # @return [self] - def read(value) - return self if value.nil? - - @value = if value.is_a?(Integer) - value.to_i - else - up8 = down16 = 0 - if @endian == :big - up8, down16 = value.to_s.unpack('Cn') - else - down16, up8 = value.to_s.unpack('vC') - end - (up8 << 16) | down16 - end - self - end - - # @return [::String] - def to_s - up8 = to_i >> 16 - down16 = to_i & 0xffff - if @endian == :big - [up8, down16].pack('Cn') - else - [down16, up8].pack('vC') - end - end - end - - # big endian 3-byte unsigned integer - # @author Sylvain Daubert - # @since 2.1.4 - class Int24be < Int24 - undef endian= - end - - # little endian 3-byte unsigned integer - # @author Sylvain Daubert - # @since 2.1.4 - class Int24le < Int24 - # @param [Integer,nil] value - undef endian= - - # @param [Integer, nil] value - def initialize(value=nil) - super(value, :little) - end - end - - # native endian 3-byte unsigned integer - # @author Sylvain Daubert - # @since 3.3.1 - class Int24n < Int24 - # @param [Integer,nil] value - undef endian= - - # @param [Integer, nil] value - def initialize(value=nil) - super(value, :native) - end - end - - # 4-byte unsigned integer - # @author Sylvain Daubert - class Int32 < Int - # @param [Integer,nil] value - # @param [:big, :little, :native] endian - def initialize(value=nil, endian=:big) - super(value, endian, 4) - @packstr = { big: 'N', little: 'V', native: 'L' } - end - end - - # big endian 4-byte unsigned integer - # @author Sylvain Daubert - class Int32be < Int32 - undef endian= - end - - # little endian 4-byte unsigned integer - # @author Sylvain Daubert - class Int32le < Int32 - # @param [Integer,nil] value - undef endian= - - # @param [Integer, nil] value - def initialize(value=nil) - super(value, :little) - end - end - - # native endian 4-byte unsigned integer - # @author Sylvain Daubert - # @since 3.3.1 - class Int32n < Int32 - # @param [Integer,nil] value - undef endian= - - # @param [Integer, nil] value - def initialize(value=nil) - super(value, :native) - end - end - - # 4-byte unsigned integer - # @author Sylvain Daubert - # @since 2.8.2 - class SInt32 < Int32 - # @param [Integer,nil] value - # @param [:big, :little] endian - def initialize(value=nil, endian=:big) - super - @packstr = { big: 'l>', little: 'l<', native: 'l' } - end - end - - # big endian 4-byte unsigned integer - # @author Sylvain Daubert - # @since 2.8.2 - class SInt32be < SInt32 - undef endian= - end - - # little endian 4-byte unsigned integer - # @author Sylvain Daubert - # @since 2.8.2 - class SInt32le < SInt32 - # @param [Integer,nil] value - undef endian= - - # @param [Integer, nil] value - def initialize(value=nil) - super(value, :little) - end - end - - # native endian 4-byte unsigned integer - # @author Sylvain Daubert - # @since 3.3.1 - class SInt32n < SInt32 - # @param [Integer,nil] value - undef endian= - - # @param [Integer, nil] value - def initialize(value=nil) - super(value, :native) - end - end - - # 8-byte unsigned integer - # @author Sylvain Daubert - class Int64 < Int - # @param [Integer,nil] value - # @param [:big, :little, :native] endian - def initialize(value=nil, endian=:big) - super(value, endian, 8) - @packstr = { big: 'Q>', little: 'Q<', native: 'Q' } - end - end - - # big endian 8-byte unsigned integer - # @author Sylvain Daubert - class Int64be < Int64 - undef endian= - end - - # little endian 8-byte unsigned integer - # @author Sylvain Daubert - class Int64le < Int64 - # @param [Integer,nil] value - undef endian= - - # @param [Integer, nil] value - def initialize(value=nil) - super(value, :little) - end - end - - # native endian 8-byte unsigned integer - # @author Sylvain Daubert - # @since 3.3.1 - class Int64n < Int64 - # @param [Integer,nil] value - undef endian= - - # @param [Integer, nil] value - def initialize(value=nil) - super(value, :native) - end - end - - # 8-byte unsigned integer - # @author Sylvain Daubert - # @since 2.8.2 - class SInt64 < Int64 - # @param [Integer,nil] value - # @param [:big, :little, :native] endian - def initialize(value=nil, endian=:big) - super - @packstr = { big: 'q>', little: 'q<', native: 'q' } - end - end - - # big endian 8-byte unsigned integer - # @author Sylvain Daubert - # @since 2.8.2 - class SInt64be < SInt64 - undef endian= - end - - # little endian 8-byte unsigned integer - # @author Sylvain Daubert - # @since 2.8.2 - class SInt64le < SInt64 - # @param [Integer,nil] value - undef endian= - - # @param [Integer, nil] value - def initialize(value=nil) - super(value, :little) - end - end - - # native endian 8-byte unsigned integer - # @author Sylvain Daubert - # @since 3.3.1 - class SInt64n < SInt64 - # @param [Integer,nil] value - undef endian= - - # @param [Integer, nil] value - def initialize(value=nil) - super(value, :native) - end - end - end -end diff --git a/lib/packetgen/types/int_string.rb b/lib/packetgen/types/int_string.rb deleted file mode 100644 index 081b274..0000000 --- a/lib/packetgen/types/int_string.rb +++ /dev/null @@ -1,102 +0,0 @@ -# coding: utf-8 -# frozen_string_literal: true - -# This file is part of PacketGen -# See https://github.com/lemontree55/packetgen for more informations -# Copyright (C) 2016 Sylvain Daubert -# Copyright (C) 2024 LemonTree55 -# This program is published under MIT license. - -module PacketGen - module Types - # Provides a class for creating strings preceeded by their length as a {Int}. - # By default, a null string will have one byte length (length byte set to 0). - # @author Sylvain Daubert - class IntString - include Fieldable - - # internal string - # @return [String] - attr_reader :string - - # @param [Class] len_type should be a {Int} subclass - # @param [::String] string - def initialize(len_type=Int8, string: '') - @string = Types::String.new.read(string) - @length = len_type.new - calc_length - end - - # @param [::String] str - # @return [IntString] self - def read(str) - unless str[0, @length.width].size == @length.width - raise ParseError, - "String too short for type #{@length.class.to_s.gsub(/.*::/, '')}" - end - @length.read str[0, @length.width] - @string.read str[@length.width, @length.to_i] - self - end - - # @param [Integer] len - # @return [Integer] - def length=(len) - @length.read len - len - end - - # @return [Integer] - def length - @length.to_i - end - - # @param [#to_s] str - # @return [String] - def string=(str) - @length.value = str.to_s.size - @string = str.to_s - end - - # Get binary string - # @return [::String] - def to_s - @length.to_s << @string.to_s - end - - # Set from a human readable string - # @param [String] str - # @return [self] - def from_human(str) - @string.read str - calc_length - self - end - - # Get human readable string - # @return [::String] - # @since 2.2.0 - def to_human - @string - end - - # Set length from internal string length - # @return [Integer] - def calc_length - @length.read @string.length - end - - # Give binary string length (including +length+ field) - # @return [Integer] - def sz - to_s.size - end - - # Say if IntString is empty - # @return [Boolean] - def empty? - length.zero? - end - end - end -end diff --git a/lib/packetgen/types/length_from.rb b/lib/packetgen/types/length_from.rb deleted file mode 100644 index ac97d9a..0000000 --- a/lib/packetgen/types/length_from.rb +++ /dev/null @@ -1,54 +0,0 @@ -# coding: utf-8 -# frozen_string_literal: true - -# This file is part of PacketGen -# See https://github.com/lemontree55/packetgen for more informations -# Copyright (C) 2016 Sylvain Daubert -# Copyright (C) 2024 LemonTree55 -# This program is published under MIT license. - -module PacketGen - module Types - # This module is a mixin adding +length_from+ capacity to a type. - # +length_from+ capacity is the capacity, for a type, to gets its - # length from another object. - # @author Sylvain Daubert - # @since 3.0.0 - module LengthFrom - # Max value returned by {#sz_to_read}. - MAX_SZ_TO_READ = 65_535 - - # Initialize +length from+ capacity. - # Should be call by extensed object's initialize. - # @param [Hash] options - # @option options [Types::Int,Proc] :length_from object or proc from which - # takes length when reading - # @return [void] - def initialize_length_from(options) - @length_from = options[:length_from] - end - - # Return a substring from +str+ of length given in another object. - # @param [#to_s] str - # @return [String] - def read_with_length_from(str) - s = PacketGen.force_binary(str.to_s) - s[0, sz_to_read] - end - - # Size to read, from length_from - # @return [Integer] - def sz_to_read - len = case @length_from - when Types::Int - @length_from.to_i - when Proc - @length_from.call - else - MAX_SZ_TO_READ - end - [0, len].max - end - end - end -end diff --git a/lib/packetgen/types/oui.rb b/lib/packetgen/types/oui.rb deleted file mode 100644 index d688fc9..0000000 --- a/lib/packetgen/types/oui.rb +++ /dev/null @@ -1,52 +0,0 @@ -# coding: utf-8 -# frozen_string_literal: true - -# This file is part of PacketGen -# See https://github.com/lemontree55/packetgen for more informations -# Copyright (C) 2016 Sylvain Daubert -# Copyright (C) 2024 LemonTree55 -# This program is published under MIT license. - -module PacketGen - module Types - # OUI type, defined as a set of 3 bytes - # oui = OUI.new - # oui.from_human('00:01:02') - # oui.to_human # => "00:01:02" - # @author Sylvain Daubert - class OUI < Types::Fields - include Fieldable - - # @attribute b2 - # @return [Integer] left-most byte - define_field :b2, Types::Int8 - # @attribute b1 - # @return [Integer] center byte - define_field :b1, Types::Int8 - # @attribute b0 - # @return [Integer] right-most byte - define_field :b0, Types::Int8 - - # Read a human-readable string to populate object - # @param [String] str - # @return [OUI] self - def from_human(str) - return self if str.nil? - - bytes = str.split(':') - raise ArgumentError, 'not a OUI' unless bytes.size == 3 - - self[:b2].read(bytes[0].to_i(16)) - self[:b1].read(bytes[1].to_i(16)) - self[:b0].read(bytes[2].to_i(16)) - self - end - - # Get OUI in human readable form (colon-separated bytes) - # @return [String] - def to_human - fields.map { |m| '%02x' % self[m] }.join(':') - end - end - end -end diff --git a/lib/packetgen/types/string.rb b/lib/packetgen/types/string.rb deleted file mode 100644 index cc17283..0000000 --- a/lib/packetgen/types/string.rb +++ /dev/null @@ -1,97 +0,0 @@ -# coding: utf-8 -# frozen_string_literal: true - -# This file is part of PacketGen -# See https://github.com/lemontree55/packetgen for more informations -# Copyright (C) 2016 Sylvain Daubert -# Copyright (C) 2024 LemonTree55 -# This program is published under MIT license. - -require 'forwardable' - -module PacketGen - module Types - # This class mimics regular String, but it is {Fieldable}. - # @author Sylvain Daubert - # @since 3.1.6 no more a subclass or regular String - class String - extend Forwardable - include Fieldable - include LengthFrom - - def_delegators :@string, :[], :to_s, :length, :size, :inspect, :==, - :unpack, :force_encoding, :encoding, :index, :empty?, - :encode, :slice, :slice!, :[]= - - # @return [::String] - attr_reader :string - # @return [Integer] - attr_reader :static_length - - # @param [Hash] options - # @option options [Types::Int,Proc] :length_from object or proc from which - # takes length when reading - # @option options [Integer] :static_length set a static length for this string - def initialize(options={}) - register_internal_string(+'') - initialize_length_from(options) - @static_length = options[:static_length] - end - - def initialize_copy(_orig) - @string = @string.dup - end - - # @param [::String] str - # @return [String] self - def read(str) - s = read_with_length_from(str) - register_internal_string s - self - end - - alias old_sz_to_read sz_to_read - private :old_sz_to_read - - # Size to read. - # Computed from static_length or length_from, if defined. - # @return [Integer] - # @since 3.1.6 - def sz_to_read - return static_length if static_length? - - old_sz_to_read - end - - # Say if a static length is defined - # @return [Boolean] - # @since 3.1.6 - def static_length? - !static_length.nil? - end - - def format_inspect - inspect - end - - # Append the given string to String - # @param [#to_s] str - # @return [self] - def <<(str) - @string << str.to_s - self - end - - alias sz length - alias to_human to_s - alias from_human read - - private - - def register_internal_string(str) - @string = str - PacketGen.force_binary(@string) - end - end - end -end diff --git a/spec/types/abstract_tlv_spec.rb b/spec/types/abstract_tlv_spec.rb deleted file mode 100644 index dd762c4..0000000 --- a/spec/types/abstract_tlv_spec.rb +++ /dev/null @@ -1,160 +0,0 @@ -require_relative '../spec_helper' - -TestEnumTLV = PacketGen::Types::AbstractTLV.create -TestEnumTLV.define_type_enum 'one' => 1, 'two' => 2 - -TestNoEnumTLV = PacketGen::Types::AbstractTLV.create(type_class: PacketGen::Types::Int8) - -module PacketGen - module Types - describe AbstractTLV do - describe '.create' do - let(:tlv_class) { AbstractTLV.create } - it 'returns a class, subclass of Types::Fields' do - expect(tlv_class).to be_a(Class) - expect(tlv_class).to be < Fields - end - - it 'returns a class, with type attribute a Types::Int8Enum' do - expect(tlv_class.field_defs[:type][:type]).to eq(Int8Enum) - end - - it 'returns a class, with length attribute a Types::Int8' do - expect(tlv_class.field_defs[:length][:type]).to eq(Int8) - end - - it 'returns a class, with value attribute a Types::String' do - expect(tlv_class.field_defs[:value][:type]).to eq(Types::String) - end - - it 'accepts a type argument' do - tlv_class = AbstractTLV.create(type_class: Int16) - expect(tlv_class.field_defs[:type][:type]).to eq(Int16) - end - - it 'accepts a length argument' do - tlv_class = AbstractTLV.create(length_class: Int16) - expect(tlv_class.field_defs[:length][:type]).to eq(Int16) - end - - it 'accepts a value argument' do - tlv_class = AbstractTLV.create(value_class: Int32) - expect(tlv_class.field_defs[:value][:type]).to eq(Int32) - end - - it 'raises when called on a subclass' do - expect { TestEnumTLV.create }.to raise_error(Error) - end - - it 'accepts an aliases argument' do - tlv_class = AbstractTLV.create(aliases: { code: :type }) - tlv = tlv_class.new - expect(tlv).to respond_to(:type) - expect(tlv).to respond_to(:type=) - expect(tlv).to respond_to(:code) - expect(tlv).to respond_to(:code=) - end - end - - context 'use of instance of generated class' do - let(:tlv) { AbstractTLV.create(type_class: Int16, length_class: Int16).new } - - describe '#read' do - it 'reads a TLV from a binary string' do - bin_str = [1, 3, 0x12345678].pack('nnN') - tlv.read(bin_str) - expect(tlv.type).to eq(1) - expect(tlv.length).to eq(3) - expect(tlv.value).to eq(binary("\x12\x34\x56")) - end - end - - describe '#human_type' do - it 'returns human readable type, if type is an Enum' do - tlv = TestEnumTLV.new(type: 'one') - expect(tlv.type).to eq(1) - expect(tlv.human_type).to eq('one') - end - - it 'returns a string, if type is not an enum' do - tlv = TestNoEnumTLV.new(type: 3) - expect(tlv.type).to eq(3) - expect(tlv.human_type).to eq('3') - end - end - - describe '#to_human' do - it 'returns a string (type is an Enum)' do - tlv = TestEnumTLV.new(type: 1, value: 'abcdef') - expect(tlv.to_human).to eq('type:one,length:6,value:"abcdef"') - end - - it 'returns a string (type is not an Enum)' do - tlv = TestNoEnumTLV.new - expect(tlv.to_human).to eq('type:0,length:0,value:""') - tlv.type = 156 - tlv.value = 'abcd' - expect(tlv.to_human).to eq('type:156,length:4,value:"abcd"') - end - end - - describe '#value=' do - it 'sets #length' do - tlv.value = 'abcdef' - expect(tlv.length).to eq(6) - end - - it 'sets #length when field_in_length contains "L"' do - tlv = AbstractTLV.create(type_class: Int16, length_class: Int16, field_in_length: 'TLV').new - tlv.value = 'abcdef' - expect(tlv.length).to eq(10) - end - end - - describe 'use of aliases' do - let(:tlv_class) { AbstractTLV.create(aliases: { code: :type }) } - - it '#initialize accepts alias as argument' do - tlv = tlv_class.new(code: 42) - expect(tlv.type).to eq(42) - end - - it 'accepts alias method name' do - tlv = tlv_class.new(code: 42) - expect(tlv.code).to eq(42) - end - - it 'accepts alias as a write accessor' do - tlv = tlv_class.new(type: 0) - expect(tlv.code).to eq(0) - expect(tlv.type).to eq(0) - tlv.code = 54 - expect(tlv.code).to eq(54) - expect(tlv.type).to eq(54) - end - end - end - - context 'use of instance with inverted type and length' do - let(:ltv) { AbstractTLV.create(type_class: Int16, length_class: Int16, field_order: 'LTV', field_in_length: 'LTV').new } - - describe '#read' do - it 'reads a TLV from a binary string' do - bin_str = [7, 1, 0x12345678].pack('nnN') - ltv.read(bin_str) - expect(ltv.length).to eq(7) - expect(ltv.type).to eq(1) - expect(ltv.value).to eq(binary("\x12\x34\x56")) - end - end - - describe '#value=' do - it 'sets #length when field_in_length contains "L"' do - ltv.value = 'abcdef' - expect(ltv.length).to eq(10) - end - end - end - end - end -end diff --git a/spec/types/array_spec.rb b/spec/types/array_spec.rb deleted file mode 100644 index 973ca20..0000000 --- a/spec/types/array_spec.rb +++ /dev/null @@ -1,76 +0,0 @@ -require_relative '../spec_helper' - -module PacketGen - module Types - describe Array do - - MyTLV = AbstractTLV.create(type_class: Int8) - class GoodClass < Array - set_of MyTLV - end - class GoodClass2 < Array - def record_from_hash(obj) - MyTLV.new(obj) - end - end - class BadClass < Array; end - - let(:tlv) { MyTLV.new } - - context '#push' do - let(:g) { GoodClass.new } - let(:g2) { GoodClass.new } - let(:b) { BadClass.new } - - it 'accepts an object' do - expect { g.push tlv }.to change { g.size }.by(1) - expect { g2.push tlv }.to change { g2.size }.by(1) - expect { b.push tlv }.to change { b.size }.by(1) - end - - it 'accepts a Hash when .set_of is used' do - expect { g << { type: 1, value: '43' } }.to change { g.size }.by(1) - expect(g.size). to eq(1) - expect(g.first).to be_a(MyTLV) - expect(g.first.type).to eq(1) - expect(g.first.value).to eq('43') - end - - it 'accepts a Hash when #record_from_hash is redefined' do - expect { g2 << { type: 1, value: '43' } }.to change { g2.size }.by(1) - expect(g2.size). to eq(1) - expect(g2.first).to be_a(MyTLV) - expect(g2.first.type).to eq(1) - expect(g2.first.value).to eq('43') - end - - it 'raises when a Hash is passed and .set_of is used nor #record_from_hash is redefined' do - expect { b << { type: 1, value: '43' } }.to raise_error(NotImplementedError) - end - - it 'does not update counter if one was declared at initialization' do - int32 = Int32.new - ary = Array.new(counter: int32) - expect { ary.push tlv }.to_not change { int32.to_i } - end - end - - context '#<<' do - it 'updates counter if one was declared at initialization' do - int32 = Int32.new - ary = Array.new(counter: int32) - expect { ary << tlv }.to change { int32.to_i }.by(1) - end - end - - context '#delete' do - it 'updates counter if one was declared at initialization' do - int32 = Int32.new - ary = Array.new(counter: int32) - ary << tlv - expect { ary.delete tlv }.to change { int32.to_i }.by(-1) - end - end - end - end -end diff --git a/spec/types/cstring_spec.rb b/spec/types/cstring_spec.rb deleted file mode 100644 index f8eb437..0000000 --- a/spec/types/cstring_spec.rb +++ /dev/null @@ -1,95 +0,0 @@ -require_relative '../spec_helper' - -module PacketGen - module Types - describe CString do - describe '#initialize' do - it 'build a CString with default value' do - cs = CString.new - expect(cs).to eq('') - expect(cs.sz).to eq(1) - end - - it 'accepts a static_length option' do - cs = CString.new(static_length: 8) - expect(cs.sz).to eq(8) - expect(cs).to eq('') - end - end - - describe '#read' do - it 'reads a CString' do - cs = CString.new - cs.read binary("abcd\x00") - expect(cs.sz).to eq(5) - expect(cs.length).to eq(4) - expect(cs).to eq('abcd') - end - - it 'reads a CString with static length' do - cs = CString.new(static_length: 8) - cs.read binary("abcd\x00\x00\x00\x00") - expect(cs.sz).to eq(8) - expect(cs.length).to eq(4) - expect(cs).to eq('abcd') - end - end - - describe '#to_s' do - it 'generates a null-terminated string' do - cs = CString.new - cs.read 'This is a String' - expect(cs.to_s).to eq(binary("This is a String\x00")) - expect(cs.length).to eq(16) - expect(cs.sz).to eq(17) - end - - it 'gets binary form for CString with previously forced length' do - cs = CString.new(static_length: 20) - cs.read 'This is a String' - expect(cs.to_s).to eq(binary("This is a String\x00\x00\x00\x00")) - expect(cs.length).to eq(16) - expect(cs.sz).to eq(20) - - cs.read 'This is a too too long string' - expect(cs.length).to eq(20) - expect(cs).to eq('This is a too too lo') - expect(cs.sz).to eq(20) - expect(cs.to_s).to eq(binary("This is a too too l\x00")) - end - end - - context 'check Packet#add may set a CString (bug #91)' do - it 'is fixed' do - pkt = Packet.gen('BOOTP', file: 'test.txt') - expect(pkt.bootp.file).to eq('test.txt') - expect(pkt.bootp[:file].to_s).to eq('test.txt' + ([0] * 120).pack('C*')) - end - end - end - - describe '#<<' do - let(:cs) { CString.new } - it 'accepts a string' do - cs.read "abcd\x00" - cs << 'efgh' - expect(cs.to_human).to eq('abcdefgh') - end - - it 'accepts another CString' do - cs.read "abcd\x00" - cs2 = CString.new - cs2.read "efgh\x00" - cs << cs2 - expect(cs.to_human).to eq('abcdefgh') - end - - it 'returns itself' do - cs.read "abcd\x00" - cs2 = cs << 'efgh' - expect(cs2.to_human).to eq('abcdefgh') - expect(cs2.object_id).to eq(cs.object_id) - end - end - end -end diff --git a/spec/types/enum_spec.rb b/spec/types/enum_spec.rb deleted file mode 100644 index aed78c5..0000000 --- a/spec/types/enum_spec.rb +++ /dev/null @@ -1,231 +0,0 @@ -require_relative '../spec_helper' - -ENUM_HASH = {'low' => 0, 'medium' => 1, 'high' => 2}.freeze - -module PacketGen - module Types - describe Enum do - let(:enum) { Enum.new(ENUM_HASH) } - - describe '#value=' do - it 'accepts Integers in enum range' do - 3.times do |i| - enum.value = i - expect(enum.value).to eq(i) - end - end - - it 'accepts known strings' do - ENUM_HASH.each do |key, value| - enum.value = key - expect(enum.value).to eq(value) - end - end - - it 'accepts out of range Integers' do - expect { enum.value = 155 }.to_not raise_error - expect(enum.to_i).to eq(155) - end - - it 'raises on unknown strings' do - expect { enum.value = 'azerty' }.to raise_error(ArgumentError) - end - end - - describe '#value' do - it 'always returns an Integer' do - enum.value = 2 - expect(enum.value).to be_a(Integer) - expect(enum.value).to eq(2) - enum.value = 'low' - expect(enum.value).to be_a(Integer) - expect(enum.value).to eq(0) - end - end - - describe '#from_human' do - it 'accepts human redable values' do - enum.from_human(1) - expect(enum.to_i).to eq(1) - enum.from_human('high') - expect(enum.to_i).to eq(2) - end - end - - describe '#to_human' do - it 'always returns a String' do - enum.value = 2 - expect(enum.to_human).to be_a(::String) - expect(enum.to_human).to eq('high') - enum.value = 'low' - expect(enum.to_human).to be_a(::String) - expect(enum.to_human).to eq('low') - end - - it 'returns "" for out of range values' do - enum.instance_eval { @value = 155 } - expect(enum.to_human).to eq('') - end - end - end - - describe Int8Enum do - let(:enum8) { Int8Enum.new(ENUM_HASH)} - - describe '#read' do - it 'reads a single byte in enum range' do - enum8.read("\x01") - expect(enum8.to_human).to eq('medium') - end - - it 'reads a single byte, even out of range' do - enum8.read("\x7f") - expect(enum8.to_human).to eq('') - expect(enum8.value).to eq(127) - end - end - - describe '#to_s' do - it 'returns binary string from value' do - enum8.value = 2 - expect(enum8.to_s).to eq("\x02") - enum8.value = 'low' - expect(enum8.to_s).to eq("\x00") - end - - it 'returns binary string from value, even out of range' do - enum8.read("\x7f") - expect(enum8.to_s).to eq("\x7f") - end - end - end - - [Int16Enum, Int16beEnum].each do |klass| - describe klass do - let(:enum16) { klass.new(ENUM_HASH)} - - describe '#read' do - it 'reads two bytes in enum range' do - enum16.read("\x00\x01") - expect(enum16.to_human).to eq('medium') - end - - it 'reads two bytes, even out of range' do - enum16.read("\x7f\x01") - expect(enum16.to_human).to eq('') - expect(enum16.value).to eq(0x7f01) - end - end - - describe '#to_s' do - it 'returns binary string from value' do - enum16.value = 2 - expect(enum16.to_s).to eq("\x00\x02") - enum16.value = 'low' - expect(enum16.to_s).to eq("\x00\x00") - end - - it 'returns binary string from value, even out of range' do - enum16.read("\x01\x7f") - expect(enum16.to_s).to eq("\x01\x7f") - end - end - end - end - - describe Int16leEnum do - let(:enum16le) { Int16leEnum.new(ENUM_HASH)} - - describe '#read' do - it 'reads two bytes in enum range' do - enum16le.read("\x01\x00") - expect(enum16le.to_human).to eq('medium') - end - - it 'reads two bytes, even out of range' do - enum16le.read("\x01\x7f") - expect(enum16le.to_human).to eq('') - expect(enum16le.value).to eq(0x7f01) - end - end - - describe '#to_s' do - it 'returns binary string from value' do - enum16le.value = 2 - expect(enum16le.to_s).to eq("\x02\x00") - enum16le.value = 'low' - expect(enum16le.to_s).to eq("\x00\x00") - end - - it 'returns binary string from value, even out of range' do - enum16le.read("\x7f\x01") - expect(enum16le.to_s).to eq("\x7f\x01") - end - end - end - - [Int32Enum, Int32beEnum].each do |klass| - describe klass do - let(:enum32) { klass.new(ENUM_HASH)} - - describe '#read' do - it 'reads two bytes in enum range' do - enum32.read(binary("\x00\x00\x00\x01")) - expect(enum32.to_human).to eq('medium') - end - - it 'reads two bytes, even out of range' do - enum32.read(binary("\x7f\x00\x00\x01")) - expect(enum32.to_human).to eq('') - expect(enum32.value).to eq(0x7f000001) - end - end - - describe '#to_s' do - it 'returns binary string from value' do - enum32.value = 2 - expect(enum32.to_s).to eq(binary("\x00\x00\x00\x02")) - enum32.value = 'low' - expect(enum32.to_s).to eq(binary("\x00\x00\x00\x00")) - end - - it 'returns binary string from value, even out of range' do - enum32.read(binary("\x01\x00\x00\x7f")) - expect(enum32.to_s).to eq(binary("\x01\x00\x00\x7f")) - end - end - end - end - - describe Int32leEnum do - let(:enum32le) { Int32leEnum.new(ENUM_HASH)} - - describe '#read' do - it 'reads two bytes in enum range' do - enum32le.read(binary("\x01\x00\x00\x00")) - expect(enum32le.to_human).to eq('medium') - end - - it 'reads two bytes, even out of range' do - enum32le.read(binary("\x00\x01\x7f\x00")) - expect(enum32le.to_human).to eq('') - expect(enum32le.value).to eq(0x7f0100) - end - end - - describe '#to_s' do - it 'returns binary string from value' do - enum32le.value = 2 - expect(enum32le.to_s).to eq(binary("\x02\x00\x00\x00")) - enum32le.value = 'low' - expect(enum32le.to_s).to eq(binary("\x00\x00\x00\x00")) - end - - it 'returns binary string from value, even out of range' do - enum32le.read(binary("\x00\x7f\x01\x00")) - expect(enum32le.to_s).to eq(binary("\x00\x7f\x01\x00")) - end - end - end - end -end diff --git a/spec/types/fields_spec.rb b/spec/types/fields_spec.rb deleted file mode 100644 index 1fde501..0000000 --- a/spec/types/fields_spec.rb +++ /dev/null @@ -1,313 +0,0 @@ -# frozen_string_literal: true - -require_relative '../spec_helper' - -module PacketGen - module Types - describe Fields do - - class FTest < Fields; end - - after(:each) do - FTest.class_eval do - @ordered_fields.clear - @field_defs.clear - @bit_fields.clear - %i[b0 b1 b2 b3 b4 b5 b6 b7 f1 f2 f3 f4 f5 u8 u81 u82].each do |meth| - undef_method meth if method_defined?(meth) - undef_method "#{meth}=" if method_defined?("#{meth}=") - undef_method "#{meth}?" if method_defined?("#{meth}?") - end - end - end - - describe '.define_field' do - it 'adds a field to class' do - expect(FTest.new.fields).to be_empty - FTest.class_eval { define_field :f1, Int8 } - expect(FTest.new.fields).to eq([:f1]) - end - - it 'adds a field with specified type' do - FTest.class_eval { define_field :f1, Int8 } - ft = FTest.new - expect(ft[:f1]).to be_a(Int8) - expect(ft.f1).to be_a(Integer) - ft.f1 = 123 - expect(ft[:f1].value).to eq(123) - - FTest.class_eval { define_field :f2, Int32 } - ft = FTest.new - expect(ft[:f2]).to be_a(Int32) - expect(ft.f2).to be_a(Integer) - ft.f2 = 1234 - expect(ft[:f2].value).to eq(1234) - - FTest.class_eval { define_field :f3, String } - ft = FTest.new - expect(ft[:f3]).to be_a(String) - expect(ft.f3).to be_a(::String) - ft.f3 = 'abcd' - expect(ft[:f3]).to eq('abcd') - end - - it 'adds a field with default value' do - FTest.class_eval { define_field :f1, Int8, default: 255 } - expect(FTest.new.f1).to eq(255) - - FTest.class_eval { define_field :f2, Int16, default: ->(_h) { rand(1...9) } } - expect(FTest.new.f2).to be > 0 - expect(FTest.new.f2).to be < 9 - end - - it 'adds a field with given builder' do - FTest.class_eval { define_field :f1, Int8, builder: ->(_x, _t) { Int16.new } } - expect(FTest.new[:f1]).to be_a(Int16) - end - end - - describe '.define_field_before' do - before(:each) do - FTest.class_eval { define_field :f1, Int8; define_field :f2, Int8 } - end - - it 'adds a field before another one' do - FTest.class_eval { define_field_before :f1, :f3, Int8 } - expect(FTest.new.fields).to eq(%i[f3 f1 f2]) - - FTest.class_eval { define_field_before :f2, :f4, Int8 } - expect(FTest.new.fields).to eq(%i[f3 f1 f4 f2]) - end - - it 'raises on unknown before field' do - expect { FTest.class_eval { define_field_before :unk, :f3, Int8 } } - .to raise_error(ArgumentError, 'unknown unk field') - end - end - - describe '.define_field_after' do - before(:each) do - FTest.class_eval { define_field :f1, Int8; define_field :f2, Int8 } - end - - it 'adds a field after another one' do - FTest.class_eval { define_field_after :f1, :f3, Int8 } - expect(FTest.new.fields).to eq(%i[f1 f3 f2]) - - FTest.class_eval { define_field_after :f2, :f4, Int8 } - expect(FTest.new.fields).to eq(%i[f1 f3 f2 f4]) - end - - it 'raises on unknown after field' do - expect { FTest.class_eval { define_field_after :unk, :f3, Int8 } } - .to raise_error(ArgumentError, 'unknown unk field') - end - end - - describe '.update_field' do - before(:each) do - FTest.class_eval { define_field :f1, Int8; define_field :f2, Int8 } - end - - it 'updates default value of given field' do - FTest.update_field :f1, default: 45 - expect(FTest.new.f1).to eq(45) - end - - it 'updates builder of given field' do - FTest.update_field :f2, builder: ->(_h, _t) { Int16.new } - expect(FTest.new[:f2]).to be_a(Int16) - end - - it 'updates optional attribute of given field' do - FTest.update_field :f2, optional: ->(h) { h.f1 > 0x7f } - expect(FTest.new(f1: 0x45).present?(:f2)).to be(false) - expect(FTest.new(f1: 0xff).present?(:f2)).to be(true) - end - - it 'updates enum attribute of given field' do - FTest.class_eval { define_field :f3, Int8Enum, enum: { 'two' => 2 } } - expect(FTest.new[:f3].to_human).to eq('two') - FTest.update_field :f3, enum: { 'one' => 1 } - expect(FTest.new[:f3].to_human).to eq('one') - end - end - - describe '.define_bit_fields_on' do - before(:each) do - FTest.class_eval { define_field :u8, Int8 } - end - - it 'adds bit fields on an Int attribute' do - FTest.class_eval do - define_bit_fields_on :u8, :b0, :b1, :b2, :b3, :b4, :b5, :b6, :b7 - end - ft = FTest.new - 8.times do |i| - expect(ft).to respond_to("b#{i}?".to_sym) - expect(ft).to respond_to("b#{i}=".to_sym) - end - - expect(ft.u8).to eq(0) - ft.u8 = 0x40 - expect(ft.b0?).to be(false) - expect(ft.b1?).to be(true) - expect(ft.b2?).to be(false) - - ft.b7 = true - ft.b1 = false - expect(ft.u8).to eq(1) - end - - it 'adds muliple-bit fields on an Int attribute' do - FTest.class_eval do - define_bit_fields_on :u8, :f1, 4, :f2, :f3, 3 - end - ft = FTest.new - expect(ft).to respond_to(:f1) - expect(ft).to respond_to(:f1=) - expect(ft).to respond_to(:f2?) - expect(ft).to respond_to(:f2=) - expect(ft).to respond_to(:f3) - expect(ft).to respond_to(:f3=) - ft.u8 = 0xc9 - expect(ft.f1).to eq(0xc) - expect(ft.f2?).to eq(true) - expect(ft.f3).to eq(1) - ft.f1 = 0xf - ft.f2 = false - ft.f3 = 7 - expect(ft.u8).to eq(0xf7) - end - - it 'raises on unknown attribute' do - expect { FTest.class_eval { define_bit_fields_on :unk, :bit } } - .to raise_error(ArgumentError, /^unknown unk field/) - end - - it 'raises on non-Int attribute' do - FTest.class_eval { define_field :f1, Types::String } - expect { FTest.class_eval { define_bit_fields_on :f1, :bit } } - .to raise_error(TypeError, 'f1 is not a PacketGen::Types::Int') - end - end - - describe '.remove_bit_fields_on' do - before(:each) do - FTest.class_eval { define_field :u8, Int8 } - end - - it 'removes defined bit fields' do - FTest.class_eval do - define_bit_fields_on :u8, :b0, :b1, :b2, :b3, :b4, :b5, :b6, :b7 - end - ft = FTest.new - expect(ft).to respond_to(:b0?) - expect(ft).to respond_to(:b0=) - expect(ft).to respond_to(:b7?) - expect(ft).to respond_to(:b7=) - - FTest.class_eval { remove_bit_fields_on :u8 } - expect(ft).to_not respond_to(:b0?) - expect(ft).to_not respond_to(:b0=) - expect(ft).to_not respond_to(:b7?) - expect(ft).to_not respond_to(:b7=) - end - - it 'does nothing on an attribute with no bit field' do - expect { FTest.class_eval { remove_bit_fields_on :u8 } }.to_not raise_error - end - end - - describe '#offset_of' do - it 'gives offset of given field in structure' do - class OffsetTest < Fields - define_field :one, Types::Int8 - define_field :two, Types::Int16 - define_field :three, Types::Int32 - define_field :four, Types::Int24 - end - - test = OffsetTest.new - expect(test.offset_of(:one)).to eq(0) - expect(test.offset_of(:two)).to eq(1) - expect(test.offset_of(:three)).to eq(3) - expect(test.offset_of(:four)).to eq(7) - end - - it 'gives offset of given field in structure with some variable field lengths' do - class OffsetTest2 < Fields - define_field :variable, Types::String - define_field :one, Types::Int8 - end - - test = OffsetTest2.new - expect(test.offset_of(:one)).to eq(0) - test.variable = '0123' - expect(test.offset_of(:one)).to eq(4) - end - end - - describe '#bits_on' do - before(:each) do - FTest.class_eval do - define_field :u81, Int8 - define_field :u82, Int8 - define_bit_fields_on :u81, :f1, :f2, :f3, :f4, :f5, 4 - end - @ft = FTest.new - end - - it 'returns a hash: keys are bit fields, values are their size' do - expect(@ft.bits_on(:u81)).to eq(f1: 1, f2: 1, f3: 1, f4: 1, f5: 4) - end - - it 'return nil on field which does not define bits' do - expect(@ft.bits_on(:u82)).to be(nil) - end - end - - context 'may define an optional field' do - class FOptional < Fields - define_field :u8, Types::Int32 - define_bit_fields_on :u8, :has_optional, :others, 31 - define_field :optional, Types::Int32, optional: ->(fo) { fo.has_optional? } - end - - let(:f) { FOptional.new } - - it 'which is listed in optional fields' do - expect(f.optional?(:optional)).to be(true) - expect(f.optional_fields).to include(:optional) - expect(f.optional_fields).to_not include(:u8) - end - - it 'which may be parsed' do - f.read(binary("\x80\x00\x00\x00\x01\x23\x45\x67")) - expect(f.has_optional?).to be(true) - expect(f.present?(:optional)).to be(true) - expect(f.optional).to eq(0x1234567) - end - - it 'which may be not parsed' do - f.read(binary("\x00\x00\x00\x00\x01\x23\x45\x67")) - expect(f.has_optional?).to be(false) - expect(f.present?(:optional)).to be(false) - expect(f.optional).to eq(0) - end - - it 'which may be serialized' do - f.has_optional = true - f.optional = 0x89abcdef - expect(f.to_s).to eq(binary("\x80\x00\x00\x00\x89\xab\xcd\xef")) - end - - it 'which may be not serialized' do - f.has_optional = false - f.optional = 0x89abcdef - expect(f.to_s).to eq(binary("\x00\x00\x00\x00")) - end - end - end - end -end diff --git a/spec/types/int_spec.rb b/spec/types/int_spec.rb deleted file mode 100644 index ed45dbd..0000000 --- a/spec/types/int_spec.rb +++ /dev/null @@ -1,388 +0,0 @@ -require_relative '../spec_helper' -module PacketGen - module Types - describe Int do - describe '#initialize' do - it 'generates an Int with default value 0' do - expect(Int.new.to_i).to eq(0) - expect(Int.new.value).to be_nil - end - it 'generates an Int with given value' do - expect(Int.new(42).value).to eq(42) - end - it 'accepts endianness as second argument' do - int = nil - expect { int = Int.new(42, :little) }.to_not raise_error - expect(int.endian).to eq(:little) - end - it 'accepts width as third argument' do - int = nil - expect { int = Int.new(42, :little, 1) }.to_not raise_error - expect(int.width).to eq(1) - end - it 'accepts default value as fourth argument' do - int = nil - expect { int = Int.new(nil, :little, 1, 5) }.to_not raise_error - expect(int.default).to eq(5) - end - end - - describe '#read' do - let(:int) { Int.new } - it 'reads an integer and populate value' do - int.read(42) - expect(int.value).to eq(42) - end - it 'raises on reading a string' do - expect { int.read("\x2a") }.to raise_error(ParseError) - end - end - - describe '#to_s' do - it 'raises' do - expect { Int.new.to_s }.to raise_error(StandardError, /abstract/) - end - end - - describe '#to_f' do - it 'returns value as a float' do - expect(Int.new(42).to_f).to be_within(0.1).of(42.0) - end - end - - context 'responds to human API' do - let(:int) { Int.new } - - it '#from_human' do - int.from_human 42 - expect(int.value).to eq(42) - end - - it '#to_human' do - int.from_human 49 - expect(int.to_human).to eq(49) - end - end - end - - describe Int8 do - let(:int) { Int8.new } - it '#read an unsigned 8-bit integer' do - expect(int.read("\x7f").to_i).to eq(127) - expect(int.read("\x80").to_i).to eq(128) - end - it 'transforms #to_s an unsigned 8-bit integer' do - expect(int.read(127).to_s).to eq(binary("\x7f")) - expect(int.read(128).to_s).to eq(binary("\x80")) - end - it '#sz returns 1' do - expect(int.sz).to eq(1) - end - end - - describe SInt8 do - let(:int) { SInt8.new } - it '#read a signed 8-bit integer' do - expect(int.read("\x7f").to_i).to eq(127) - expect(int.read("\x80").to_i).to eq(-128) - end - it 'transforms #to_s a signed 8-bit integer' do - expect(int.read(127).to_s).to eq(binary("\x7f")) - expect(int.read(-128).to_s).to eq(binary("\x80")) - end - end - - describe Int16 do - let(:int) { Int16.new } - it '#read an unsigned 16-bit big-endian integer' do - expect(int.read("\x7f\xff").to_i).to eq(32_767) - expect(int.read("\x80\x00").to_i).to eq(32_768) - end - it 'transforms #to_s an unsigned 16-bit big-endian integer' do - expect(int.read(32_767).to_s).to eq(binary("\x7f\xff")) - expect(int.read(32_768).to_s).to eq(binary("\x80\x00")) - end - it '#sz returns 2' do - expect(int.sz).to eq(2) - end - end - - describe Int16le do - let(:int) { Int16le.new } - it '#read an unsigned 16-bit little-endian integer' do - expect(int.read("\xff\x7f").to_i).to eq(32_767) - expect(int.read("\x00\x80").to_i).to eq(32_768) - end - it 'transforms #to_s an unsigned 16-bit little-endian integer' do - expect(int.read(32_767).to_s).to eq(binary("\xff\x7f")) - expect(int.read(32_768).to_s).to eq(binary("\x00\x80")) - end - end - - describe Int16n do - let(:int) { Int16n.new } - it '#read an unsigned 16-bit native-endian integer' do - expect(int.read([0x7fff].pack('S')).to_i).to eq(32_767) - expect(int.read([0x8000].pack('S')).to_i).to eq(32_768) - end - it 'transforms #to_s an unsigned 16-bit little-endian integer' do - expect(int.read(32_767).to_s).to eq([0x7fff].pack('S')) - expect(int.read(32_768).to_s).to eq([0x8000].pack('S')) - end - end - - describe SInt16 do - let(:int) { SInt16.new } - it '#read a signed 16-bit big-endian integer' do - expect(int.read("\x7f\xff").to_i).to eq(32_767) - expect(int.read("\x80\x00").to_i).to eq(-32_768) - end - it 'transforms #to_s a signed 16-bit big-endian integer' do - expect(int.read(32_767).to_s).to eq(binary("\x7f\xff")) - expect(int.read(-32_768).to_s).to eq(binary("\x80\x00")) - end - end - - describe SInt16le do - let(:int) { SInt16le.new } - it '#read a signed 16-bit little-endian integer' do - expect(int.read("\xff\x7f").to_i).to eq(32_767) - expect(int.read("\x00\x80").to_i).to eq(-32_768) - end - it 'transforms #to_s a signed 16-bit little-endian integer' do - expect(int.read(32_767).to_s).to eq(binary("\xff\x7f")) - expect(int.read(-32_768).to_s).to eq(binary("\x00\x80")) - end - end - - describe SInt16n do - let(:int) { SInt16n.new } - it '#read a signed 16-bit native-endian integer' do - expect(int.read([0x7fff].pack('s')).to_i).to eq(32_767) - expect(int.read([0x8000].pack('s')).to_i).to eq(-32_768) - end - it 'transforms #to_s a signed 16-bit native-endian integer' do - expect(int.read(32_767).to_s).to eq([0x7fff].pack('s')) - expect(int.read(-32_768).to_s).to eq([0x8000].pack('s')) - end - end - - describe Int24 do - let(:int) { Int24.new } - let(:strint1) { binary("\x7f\xff\xff") } - let(:strint2) { binary("\x80\x00\x00") } - it '#read an unsigned 24-bit big-endian integer' do - expect(int.read(strint1).to_i).to eq(0x7f_ffff) - expect(int.read(strint2).to_i).to eq(0x80_0000) - end - it 'transforms #to_s an unsigned 24-bit big-endian integer' do - expect(int.read(0x7f_ffff).to_s).to eq(strint1) - expect(int.read(0x80_0000).to_s).to eq(strint2) - end - it '#sz returns 3' do - expect(int.sz).to eq(3) - end - end - - describe Int24le do - let(:int) { Int24le.new } - let(:strint1) { binary("\xff\xff\x7f") } - let(:strint2) { binary("\x00\x00\x80") } - it '#read an unsigned 24-bit little-endian integer' do - expect(int.read(strint1).to_i).to eq(0x7f_ffff) - expect(int.read(strint2).to_i).to eq(0x80_0000) - end - it 'transforms #to_s an unsigned 24-bit little-endian integer' do - expect(int.read(0x7f_ffff).to_s).to eq(strint1) - expect(int.read(0x80_0000).to_s).to eq(strint2) - end - end - - describe Int24n do - let(:int) { Int24n.new } - let(:endianess) { [1].pack('S').unpack('n') == 1 ? :big : :little } - let(:strint1) { binary(endianess == :big ? "\x7f\xff\xff" : "\xff\xff\x7f") } - let(:strint2) { binary(endianess == :big ? "\x80\x00\x00" : "\x00\x00\x80") } - it '#read an unsigned 24-bit little-endian integer' do - expect(int.read(strint1).to_i).to eq(0x7f_ffff) - expect(int.read(strint2).to_i).to eq(0x80_0000) - end - it 'transforms #to_s an unsigned 24-bit little-endian integer' do - expect(int.read(0x7f_ffff).to_s).to eq(strint1) - expect(int.read(0x80_0000).to_s).to eq(strint2) - end - end - - describe Int32 do - let(:int) { Int32.new } - it '#read an unsigned 32-bit big-endian integer' do - expect(int.read("\x7f\xff\xff\xff").to_i).to eq(0x7fff_ffff) - expect(int.read("\x80\x00\x00\x00").to_i).to eq(0x8000_0000) - end - it 'transforms #to_s an unsigned 32-bit big-endian integer' do - expect(int.read(0x7fff_ffff).to_s).to eq(binary("\x7f\xff\xff\xff")) - expect(int.read(0x8000_0000).to_s).to eq(binary("\x80\x00\x00\x00")) - end - it '#sz returns 4' do - expect(int.sz).to eq(4) - end - end - - describe Int32le do - let(:int) { Int32le.new } - it '#read an unsigned 32-bit little-endian integer' do - expect(int.read("\xff\xff\xff\x7f").to_i).to eq(0x7fff_ffff) - expect(int.read("\x00\x00\x00\x80").to_i).to eq(0x8000_0000) - end - it 'transforms #to_s an unsigned 32-bit little-endian integer' do - expect(int.read(0x7fff_ffff).to_s).to eq(binary("\xff\xff\xff\x7f")) - expect(int.read(0x8000_0000).to_s).to eq(binary("\x00\x00\x00\x80")) - end - end - - describe Int32n do - let(:int) { Int32n.new } - it '#read an unsigned 32-bit little-endian integer' do - expect(int.read([0x7fff_ffff].pack('L')).to_i).to eq(0x7fff_ffff) - expect(int.read([0x8000_0000].pack('L')).to_i).to eq(0x8000_0000) - end - it 'transforms #to_s an unsigned 32-bit little-endian integer' do - expect(int.read(0x7fff_ffff).to_s).to eq([0x7fff_ffff].pack('L')) - expect(int.read(0x8000_0000).to_s).to eq([0x8000_0000].pack('L')) - end - end - - describe SInt32 do - let(:int) { SInt32.new } - it '#read a signed 32-bit big-endian integer' do - expect(int.read("\x7f\xff\xff\xff").to_i).to eq(0x7fff_ffff) - expect(int.read("\x80\x00\x00\x00").to_i).to eq(-0x8000_0000) - end - it 'transforms #to_s a signed 32-bit big-endian integer' do - expect(int.read(0x7fff_ffff).to_s).to eq(binary("\x7f\xff\xff\xff")) - expect(int.read(-0x8000_0000).to_s).to eq(binary("\x80\x00\x00\x00")) - end - end - - describe SInt32le do - let(:int) { SInt32le.new } - it '#read a signed 32-bit little-endian integer' do - expect(int.read("\xff\xff\xff\x7f").to_i).to eq(0x7fff_ffff) - expect(int.read("\x00\x00\x00\x80").to_i).to eq(-0x8000_0000) - end - it 'transforms #to_s a signed 32-bit little-endian integer' do - expect(int.read(0x7fff_ffff).to_s).to eq(binary("\xff\xff\xff\x7f")) - expect(int.read(-0x8000_0000).to_s).to eq(binary("\x00\x00\x00\x80")) - end - end - - describe SInt32n do - let(:int) { SInt32n.new } - it '#read a signed 32-bit little-endian integer' do - expect(int.read([0x7fff_ffff].pack('L')).to_i).to eq(0x7fff_ffff) - expect(int.read([0x8000_0000].pack('L')).to_i).to eq(-0x8000_0000) - end - it 'transforms #to_s a signed 32-bit little-endian integer' do - expect(int.read(0x7fff_ffff).to_s).to eq([0x7fff_ffff].pack('L')) - expect(int.read(-0x8000_0000).to_s).to eq([0x8000_0000].pack('L')) - end - end - - INT64 = { - big: { - unsigned: [ - { - int: 0x7fff_ffff_ffff_ffff, - str: "\x7f\xff\xff\xff\xff\xff\xff\xff" - }, - { - int: 0x8000_0000_0000_0000, - str: "\x80\x00\x00\x00\x00\x00\x00\x00" - } - ], - signed: [ - { - int: 0x7fff_ffff_ffff_ffff, - str: "\x7f\xff\xff\xff\xff\xff\xff\xff" - }, - { - int: -0x8000_0000_0000_0000, - str: "\x80\x00\x00\x00\x00\x00\x00\x00" - } - ] - }, - little: { - unsigned: [ - { - int: 0x7fff_ffff_ffff_ffff, - str: "\xff\xff\xff\xff\xff\xff\xff\x7f" - }, - { - int: 0x8000_0000_0000_0000, - str: "\x00\x00\x00\x00\x00\x00\x00\x80" - } - ], - signed: [ - { - int: 0x7fff_ffff_ffff_ffff, - str: "\xff\xff\xff\xff\xff\xff\xff\x7f" - }, - { - int: -0x8000_0000_0000_0000, - str: "\x00\x00\x00\x00\x00\x00\x00\x80" - } - ] - }, - native: { - unsigned: [ - { - int: 0x7fff_ffff_ffff_ffff, - str: [0x7fff_ffff_ffff_ffff].pack('Q') - }, - { - int: 0x8000_0000_0000_0000, - str: [0x8000_0000_0000_0000].pack('Q') - } - ], - signed: [ - { - int: 0x7fff_ffff_ffff_ffff, - str: [0x7fff_ffff_ffff_ffff].pack('q') - }, - { - int: -0x8000_0000_0000_0000, - str: [0x8000_0000_0000_0000].pack('q') - } - ] - }, - }.freeze - - %i[unsigned signed].each do |us| - %i[big little native].each do |endian| - suffix = case endian - when :little then 'le' - when :native then 'n' - else '' - end - prefix = us == :signed ? 'S' : '' - klass = Types.const_get("#{prefix}Int64#{suffix}") - describe klass do - before(:each) { @int = klass.new } - it "#read an unsigned 64-bit #{endian}-endian integer" do - fixtures = INT64[endian][us] - expect(@int.read(fixtures[0][:str]).to_i).to eq(fixtures[0][:int]) - expect(@int.read(fixtures[1][:str]).to_i).to eq(fixtures[1][:int]) - end - it "transforms #to_s an unsigned 64-bit #{endian}-endian integer" do - fixtures = INT64[endian][us] - expect(@int.read(fixtures[0][:int]).to_s).to eq(binary(fixtures[0][:str])) - expect(@int.read(fixtures[1][:int]).to_s).to eq(binary(fixtures[1][:str])) - end - it '#sz returns 8' do - expect(@int.sz).to eq(8) - end - end - end - end - end -end diff --git a/spec/types/int_string_spec.rb b/spec/types/int_string_spec.rb deleted file mode 100644 index c0af294..0000000 --- a/spec/types/int_string_spec.rb +++ /dev/null @@ -1,73 +0,0 @@ -require_relative '../spec_helper' - -module PacketGen - module Types - describe IntString do - describe '#initialize' do - it 'accepts a len_type option' do - is = IntString.new - expect(is.sz).to eq(1) - - is = IntString.new(Int16) - expect(is.sz).to eq(2) - is = IntString.new( Int32) - expect(is.sz).to eq(4) - is = IntString.new( Int64) - expect(is.sz).to eq(8) - end - end - - describe '#read' do - let(:is8) { IntString.new } - let(:is32) { IntString.new(Int32) } - - it 'reads an IntString' do - is8.read binary("\x04abcd") - expect(is8.length).to eq(4) - expect(is8.string).to eq('abcd') - - is32.read binary("\x00\x00\x00\x06abcdef") - expect(is32.length).to eq(6) - expect(is32.string).to eq('abcdef') - end - - it 'raises on too short string for given type' do - str = "\x01a" - expect { is32.read str }.to raise_error(ParseError, /too short/) - end - end - - describe '#to_s' do - let(:is8) { IntString.new } - let(:is16) { IntString.new(Int16) } - - it 'gets binary form for IntString' do - is8.string = 'This is a String' - expect(is8.to_s).to eq(binary("\x10This is a String")) - is16.string = 'This is another String' - expect(is16.to_s).to eq(binary("\x00\x16This is another String")) - end - - it 'gets binary form for IntString with previously forced length' do - is8.string = 'This is a String' - is8.length = 17 - expect(is8.to_s).to eq(binary("\x11This is a String")) - is8.length = 10 - expect(is8.to_s).to eq(binary("\x0aThis is a String")) - end - end - - context 'check Packet#add may set a IntString (bug #91)' do - it 'is fixed' do - class AddIntStringTest < Header::Base - define_field :field, IntString - end - Header.add_class AddIntStringTest - pkt = Packet.gen('AddIntStringTest', field: 'This is a string') - expect(pkt.addintstringtest[:field].to_human).to eq('This is a string') - expect(pkt.addintstringtest[:field].to_s).to eq("\x10This is a string") - end - end - end - end -end diff --git a/spec/types/oui_spec.rb b/spec/types/oui_spec.rb deleted file mode 100644 index 15ff86d..0000000 --- a/spec/types/oui_spec.rb +++ /dev/null @@ -1,55 +0,0 @@ -require_relative '../spec_helper' - -module PacketGen - module Types - describe OUI do - - describe '#initialize' do - it 'returns a OUI with default values' do - oui = OUI.new - expect(oui.b2).to eq(0) - expect(oui.b1).to eq(0) - expect(oui.b0).to eq(0) - end - - it 'accepts field options' do - oui = OUI.new(b2: 45, b1: 2, b0: 128) - expect(oui.b2).to eq(45) - expect(oui.b1).to eq(2) - expect(oui.b0).to eq(128) - end - end - - describe '#read' do - it 'reads a OUI from a binary string' do - bin_str = [1, 2, 3].pack('C3') - oui = OUI.new.read(bin_str) - expect(oui.b2).to eq(1) - expect(oui.b1).to eq(2) - expect(oui.b0).to eq(3) - end - end - - describe '#to_human' do - it 'returns a human readable string' do - oui = OUI.new(b2: 0x81, b1: 0x5f, b0: 0xde) - expect(oui.to_human).to eq('81:5f:de') - end - end - describe '#from_human' do - it 'sets OUI from a human readable string' do - oui = OUI.new - oui.from_human '81:5f:de' - expect(oui.b2).to eq(0x81) - expect(oui.b1).to eq(0x5f) - expect(oui.b0).to eq(0xde) - end - - it 'raises on malformed string' do - oui = OUI.new - expect { oui.from_human '01:02' }.to raise_error(ArgumentError, 'not a OUI') - end - end - end - end -end diff --git a/spec/types/string_spec.rb b/spec/types/string_spec.rb deleted file mode 100644 index a34d3b3..0000000 --- a/spec/types/string_spec.rb +++ /dev/null @@ -1,36 +0,0 @@ -require_relative '../spec_helper' - -module PacketGen - module Types - describe String do - - it '#initialize accepts a option hash' do - expect { String.new(length_from: nil) }.to_not raise_error - end - - context '#read' do - it 'reads all given string when no length_from option was given' do - str = String.new - read_str = (0..15).to_a.pack('C*') - str.read read_str - expect(str.sz).to eq(16) - expect(str).to eq(read_str) - end - - it 'reads only start of given string when length_from option was given' do - len = Int8.new(6) - str = String.new(length_from: len) - read_str = (0..15).to_a.pack('C*') - str.read read_str - expect(str.sz).to eq(6) - expect(str).to eq(read_str[0..5]) - - len.value = 12 - str.read read_str - expect(str.sz).to eq(12) - expect(str).to eq(read_str[0..11]) - end - end - end - end -end From 45014860735a3f4441f5a9616574f798eb53bd46 Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Sun, 21 Jul 2024 15:19:58 +0200 Subject: [PATCH 03/19] Update code to use BinStruct instead of Types --- Gemfile | 2 +- lib/packetgen.rb | 7 +- lib/packetgen/header.rb | 4 +- lib/packetgen/header/arp.rb | 26 ++-- lib/packetgen/header/asn1_base.rb | 2 +- lib/packetgen/header/base.rb | 24 ++-- lib/packetgen/header/bootp.rb | 54 ++++---- lib/packetgen/header/dhcp.rb | 6 +- lib/packetgen/header/dhcp/option.rb | 38 +++--- lib/packetgen/header/dhcp/options.rb | 2 +- lib/packetgen/header/dhcpv6.rb | 12 +- lib/packetgen/header/dhcpv6/duid.rb | 30 ++--- lib/packetgen/header/dhcpv6/option.rb | 102 +++++++-------- lib/packetgen/header/dhcpv6/options.rb | 2 +- lib/packetgen/header/dhcpv6/relay.rb | 10 +- lib/packetgen/header/dns.rb | 24 ++-- lib/packetgen/header/dns/name.rb | 14 +-- lib/packetgen/header/dns/opt.rb | 2 +- lib/packetgen/header/dns/option.rb | 22 ++-- lib/packetgen/header/dns/question.rb | 12 +- lib/packetgen/header/dns/rr.rb | 32 ++--- lib/packetgen/header/dns/rrsection.rb | 4 +- lib/packetgen/header/dot11.rb | 116 +++++++++--------- lib/packetgen/header/dot11/control.rb | 20 +-- lib/packetgen/header/dot11/data.rb | 30 ++--- lib/packetgen/header/dot11/element.rb | 8 +- lib/packetgen/header/dot11/management.rb | 14 +-- lib/packetgen/header/dot11/sub_mngt.rb | 78 ++++++------ lib/packetgen/header/dot1q.rb | 16 +-- lib/packetgen/header/dot1x.rb | 18 +-- lib/packetgen/header/eap.rb | 40 +++--- lib/packetgen/header/eap/fast.rb | 8 +- lib/packetgen/header/eap/md5.rb | 12 +- lib/packetgen/header/eap/tls.rb | 16 +-- lib/packetgen/header/eap/ttls.rb | 16 +-- lib/packetgen/header/eth.rb | 36 +++--- lib/packetgen/header/gre.rb | 18 +-- lib/packetgen/header/http/headers.rb | 2 +- lib/packetgen/header/http/request.rb | 26 ++-- lib/packetgen/header/http/response.rb | 28 ++--- lib/packetgen/header/icmp.rb | 16 +-- lib/packetgen/header/icmpv6.rb | 6 +- lib/packetgen/header/igmp.rb | 16 +-- lib/packetgen/header/igmpv3.rb | 14 +-- lib/packetgen/header/igmpv3/group_record.rb | 24 ++-- lib/packetgen/header/igmpv3/mq.rb | 16 +-- lib/packetgen/header/igmpv3/mr.rb | 8 +- lib/packetgen/header/ip.rb | 44 +++---- lib/packetgen/header/ip/addr.rb | 24 ++-- lib/packetgen/header/ip/option.rb | 40 +++--- lib/packetgen/header/ip/options.rb | 2 +- lib/packetgen/header/ipv6.rb | 28 ++--- lib/packetgen/header/ipv6/addr.rb | 28 ++--- lib/packetgen/header/ipv6/extension.rb | 16 +-- lib/packetgen/header/ipv6/hop_by_hop.rb | 18 +-- lib/packetgen/header/llc.rb | 34 ++--- lib/packetgen/header/mld.rb | 12 +- .../header/mldv2/mcast_address_record.rb | 22 ++-- lib/packetgen/header/mldv2/mlq.rb | 26 ++-- lib/packetgen/header/mldv2/mlr.rb | 16 +-- lib/packetgen/header/ospfv2.rb | 42 +++---- lib/packetgen/header/ospfv2/db_description.rb | 18 +-- lib/packetgen/header/ospfv2/hello.rb | 22 ++-- lib/packetgen/header/ospfv2/ls_ack.rb | 2 +- lib/packetgen/header/ospfv2/ls_request.rb | 18 +-- lib/packetgen/header/ospfv2/ls_update.rb | 6 +- lib/packetgen/header/ospfv2/lsa.rb | 86 ++++++------- lib/packetgen/header/ospfv2/lsa_header.rb | 18 +-- lib/packetgen/header/ospfv3.rb | 42 +++---- lib/packetgen/header/ospfv3/db_description.rb | 22 ++-- lib/packetgen/header/ospfv3/hello.rb | 24 ++-- lib/packetgen/header/ospfv3/ipv6_prefix.rb | 16 +-- lib/packetgen/header/ospfv3/ls_ack.rb | 4 +- lib/packetgen/header/ospfv3/ls_request.rb | 18 +-- lib/packetgen/header/ospfv3/ls_update.rb | 8 +- lib/packetgen/header/ospfv3/lsa.rb | 76 ++++++------ lib/packetgen/header/ospfv3/lsa_header.rb | 18 +-- lib/packetgen/header/sctp.rb | 10 +- lib/packetgen/header/sctp/chunk.rb | 64 +++++----- lib/packetgen/header/sctp/error.rb | 104 ++++++++-------- lib/packetgen/header/sctp/parameter.rb | 76 ++++++------ lib/packetgen/header/snmp.rb | 2 +- lib/packetgen/header/tcp.rb | 36 +++--- lib/packetgen/header/tcp/option.rb | 80 ++++++------ lib/packetgen/header/tcp/options.rb | 2 +- lib/packetgen/header/tftp.rb | 24 ++-- lib/packetgen/header/udp.rb | 14 +-- lib/packetgen/headerable.rb | 2 +- lib/packetgen/inspect.rb | 4 +- lib/packetgen/packet.rb | 2 +- lib/packetgen/pcapng.rb | 8 +- lib/packetgen/pcapng/block.rb | 18 +-- lib/packetgen/pcapng/epb.rb | 18 +-- lib/packetgen/pcapng/file.rb | 6 +- lib/packetgen/pcapng/idb.rb | 10 +- lib/packetgen/pcapng/shb.rb | 20 +-- lib/packetgen/pcapng/spb.rb | 6 +- lib/packetgen/pcapng/unknown_block.rb | 4 +- packetgen.gemspec | 3 +- spec/header/arp_spec.rb | 2 +- spec/header/asn1_base_spec.rb | 4 +- spec/header/base_spec.rb | 20 +-- spec/header/dns/name_spec.rb | 2 +- spec/header/dns/qdsection_spec.rb | 8 +- spec/header/dns/rrsection_spec.rb | 8 +- spec/header/dns_spec.rb | 2 +- spec/header/dot11_spec.rb | 6 +- spec/header/eap_spec.rb | 2 +- spec/header/eth_spec.rb | 2 +- spec/header/gre_spec.rb | 10 +- spec/header/http/headers_spec.rb | 4 +- spec/header/icmp_spec.rb | 2 +- spec/header/icmpv6_spec.rb | 2 +- spec/header/igmp_spec.rb | 2 +- spec/header/igmpv3_spec.rb | 2 +- spec/header/ipv6_spec.rb | 2 +- spec/header/mld_spec.rb | 4 +- spec/header/mldv2_spec.rb | 4 +- spec/header/ospfv2_spec.rb | 2 +- spec/header/ospfv3_spec.rb | 2 +- spec/header/sctp/sack_chunk_spec.rb | 2 +- spec/header/tcp_option_spec.rb | 8 +- spec/header/tcp_spec.rb | 2 +- spec/header/udp_spec.rb | 2 +- spec/header_spec.rb | 4 +- spec/inspect_spec.rb | 12 +- spec/packet_spec.rb | 6 +- spec/pcapng/file_spec.rb | 4 +- 128 files changed, 1218 insertions(+), 1210 deletions(-) diff --git a/Gemfile b/Gemfile index 9f2e791..4d1fb96 100644 --- a/Gemfile +++ b/Gemfile @@ -8,11 +8,11 @@ gemspec gem 'bundler', '>=2.2', '<3' group :develoment do + gem 'debug' gem 'rake', '~> 13.0' gem 'rspec', '~> 3.12' gem 'ruby-lsp' gem 'yard', '~> 0.9' - gem 'debug' end group :noci do diff --git a/lib/packetgen.rb b/lib/packetgen.rb index 1c113ad..ad7b782 100644 --- a/lib/packetgen.rb +++ b/lib/packetgen.rb @@ -8,6 +8,7 @@ # This program is published under MIT license. require 'packetgen/version' +require 'bin_struct' require 'interfacez' # PacketGen is a network packet generator and analyzor. @@ -100,12 +101,13 @@ def self.force_binary(str) def self.default_iface return @default_iface if defined? @default_iface - @default_iface = Interfacez.raw_interface_addresses.each do |iface| + Interfacez.raw_interface_addresses.each do |iface| next unless iface.broadaddr next unless Interfacez.ipv4_address_of(iface.name) next unless Interfacez.ipv6_address_of(iface.name) - break iface.name + @default_iface = iface.name + break end end @@ -133,7 +135,6 @@ def self.header(protocol, options={}) require 'packetgen/deprecation' require 'packetgen/inspect' -require 'packetgen/types' require 'packetgen/pcapng' require 'packetgen/pcap' require 'packetgen/packet' diff --git a/lib/packetgen/header.rb b/lib/packetgen/header.rb index 5edbd66..5c047d2 100644 --- a/lib/packetgen/header.rb +++ b/lib/packetgen/header.rb @@ -17,8 +17,8 @@ module PacketGen # First, define the new header class. By example: # module MyModule # class MyHeader < PacketGen::Header::Base - # define_field :field1, PacketGen::Types::Int32 - # define_field :field2, PacketGen::Types::Int32 + # define_attr :field1, BinStruct::Int32 + # define_attr :field2, BinStruct::Int32 # end # end # Then, class must be declared to PacketGen: diff --git a/lib/packetgen/header/arp.rb b/lib/packetgen/header/arp.rb index 7cef2ff..089dd5b 100644 --- a/lib/packetgen/header/arp.rb +++ b/lib/packetgen/header/arp.rb @@ -9,9 +9,9 @@ module PacketGen module Header # An ARP header consists of: - # * a hardware type ({#hrd} or {#htype}) field ({Types::Int16}), + # * a hardware type ({#hrd} or {#htype}) field ({BinStruct::Int16}), # * a protocol type ({#pro} or {#ptype}) field (+Int16+), - # * a hardware address length ({#hln} or {#hlen}) field ({Types::Int8}), + # * a hardware address length ({#hln} or {#hlen}) field ({BinStruct::Int8}), # * a protocol address length ({#pln} or {#plen}) field (+Int8+), # * a {#opcode} (or {#op}) field (+Int16+), # * a source hardware address ({#sha} or {#src_mac}) field ({Eth::MacAddr}), @@ -33,42 +33,42 @@ class ARP < Base # @!attribute hrd # 16-bit hardware protocol type # # @return [Integer] - define_field :hrd, Types::Int16, default: 1 + define_attr :hrd, BinStruct::Int16, default: 1 # @!attribute pro # 16-bit internet protocol type # # @return [Integer] - define_field :pro, Types::Int16, default: 0x800 + define_attr :pro, BinStruct::Int16, default: 0x800 # @!attribute hln # 8-bit hardware address length # # @return [Integer] - define_field :hln, Types::Int8, default: 6 + define_attr :hln, BinStruct::Int8, default: 6 # @!attribute pln # 8-bit internet address length # # @return [Integer] - define_field :pln, Types::Int8, default: 4 + define_attr :pln, BinStruct::Int8, default: 4 # @!attribute op # 16-bit operation code # # @return [Integer] - define_field :op, Types::Int16Enum, enum: { 'request' => 1, 'reply' => 2 } + define_attr :op, BinStruct::Int16Enum, enum: { 'request' => 1, 'reply' => 2 } # @!attribute sha # source hardware address # @return [Eth::MacAddr] - define_field :sha, Eth::MacAddr + define_attr :sha, Eth::MacAddr # @!attribute spa # source protocol address # @return [IP::Addr] - define_field :spa, IP::Addr + define_attr :spa, IP::Addr # @!attribute tha # target hardware address # @return [Eth::MacAddr] - define_field :tha, Eth::MacAddr + define_attr :tha, Eth::MacAddr # @!attribute tpa # target protocol address # @return [IP::Addr] - define_field :tpa, IP::Addr + define_attr :tpa, IP::Addr # @!attribute body - # @return [Types::String,Header::Base] - define_field :body, Types::String + # @return [BinStruct::String,Header::Base] + define_attr :body, BinStruct::String # @param [Hash] options # @option options [Integer] :hrd network protocol type (default: 1) diff --git a/lib/packetgen/header/asn1_base.rb b/lib/packetgen/header/asn1_base.rb index 71108cc..433fb75 100644 --- a/lib/packetgen/header/asn1_base.rb +++ b/lib/packetgen/header/asn1_base.rb @@ -21,7 +21,7 @@ class ASN1Base < RASN1::Model include Headerable class << self - # Define some methods from given ASN.1 fields to mimic {Base} attributes + # Define some methods from given ASN.1 attributes.to mimic {Base} attributes # @param [Array] attributes # @return [void] def define_attributes(*attributes) diff --git a/lib/packetgen/header/base.rb b/lib/packetgen/header/base.rb index 04da079..9312bc1 100644 --- a/lib/packetgen/header/base.rb +++ b/lib/packetgen/header/base.rb @@ -13,28 +13,28 @@ module Header # * +#calc_checksum+, which computes header checksum, # * +#calc_length+, which computes header length, # * {#parse?}, - # * +#reply!+, which inverts needed fields to forge a response. + # * +#reply!+, which inverts needed attributes.to forge a response. # @author Sylvain Daubert - class Base < Types::Fields + class Base < BinStruct::Struct include Headerable # @api private # Simple class to handle a header association - class Binding < Struct.new(:key, :value) + class Binding < ::Struct.new(:key, :value) # Check +fields+ responds to binding - # @param [Types::Fields] fields + # @param [BinStruct::Struct] fields # @return [Boolean] def check?(fields) case self[:value] when Proc - self[:value].call fields.send(self[:key]) + self[:value].call(fields.send(self[:key])) else fields.send(self[:key]) == self[:value] end end # Set +fields+ field to binding value - # @param [Types::Fields] fields + # @param [BinStruct::Struct] fields # @return [void] def set(fields) case self[:value] @@ -62,14 +62,14 @@ def initialize(procs) end # Check +fields+ responds to binding - # @param [Types::Fields] fields + # @param [BinStruct::Struct] fields # @return [Boolean] def check?(fields) @check.call(fields) end # Set +fields+ field to binding value - # @param [Types::Fields] fields + # @param [BinStruct::Struct] fields # @return [void] def set(fields) @set.call(fields) @@ -120,14 +120,14 @@ def to_h end # Check +fields+ responds to set of bindings - # @param [Types::Fields] fields + # @param [BinStruct::Struct] fields # @return [Boolean] def check?(fields) @bindings.any? { |group| group.all? { |binding| binding.check?(fields) } } end # Set +fields+ to bindings value - # @param [Types::Fields] fields + # @param [BinStruct::Struct] fields # @return [void] def set(fields) @bindings.first.each { |b| b.set fields } @@ -151,7 +151,7 @@ class << self # 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+ + # @param [Hash] args 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 @@ -213,7 +213,7 @@ def calculate_and_set_length(hdr, header_in_size: true) end end - # @see Types::Fields#initialize + # @see BinStruct::Struct#initialize def initialize(options={}) @packet = options.delete(:packet) if options.key?(:packet) super diff --git a/lib/packetgen/header/bootp.rb b/lib/packetgen/header/bootp.rb index f3fe8dd..fa9ebd0 100644 --- a/lib/packetgen/header/bootp.rb +++ b/lib/packetgen/header/bootp.rb @@ -12,23 +12,23 @@ module Header # RFC 951} # # A BOOTP header consists of: - # * an operation code field ({#op} of type {Types::Int8Enum}), - # * a hardware address type ({#htype} of type {Types::Int8}), - # * a hardware address length ({#hlen} of type {Types::Int8}), - # * a {#hops} field ({Types::Int8}), - # * a transaction ID ({#xid} of type {Types::Int32}), - # * a {#secs} field (){Types::Int16}), - # * a {#flags} field (){Types::Int16}): + # * an operation code field ({#op} of type {BinStruct::Int8Enum}), + # * a hardware address type ({#htype} of type {BinStruct::Int8}), + # * a hardware address length ({#hlen} of type {BinStruct::Int8}), + # * a {#hops} field ({BinStruct::Int8}), + # * a transaction ID ({#xid} of type {BinStruct::Int32}), + # * a {#secs} field (){BinStruct::Int16}), + # * a {#flags} field (){BinStruct::Int16}): # * a 1-bit broadcast flag ({#b}), # * a 15-bit Must Be Zero field ({#mbz}), # * a {#ciaddr} field ({IP::Addr}), # * a {#yiaddr} field ({IP::Addr}), # * a {#siaddr} field ({IP::Addr}), # * a {#giaddr} field ({IP::Addr}), - # * a {#chaddr} field (16-byte {Types::String}), - # * a {#sname} field (64-byte {Types::CString}), - # * a {#file} field (128-byte {Types::CString}), - # * and a body ({Types::String}). + # * a {#chaddr} field (16-byte {BinStruct::String}), + # * a {#sname} field (64-byte {BinStruct::CString}), + # * a {#file} field (128-byte {BinStruct::CString}), + # * and a body ({BinStruct::String}). # # == Create a BOOTP header # # standalone @@ -52,76 +52,76 @@ class BOOTP < Base # @!attribute op # 8-bit opcode # @return [Integer] - define_field :op, Types::Int8Enum, enum: OPCODES + define_attr :op, BinStruct::Int8Enum, enum: OPCODES # @!attribute htype # 8-bit hardware address type # @return [Integer] - define_field :htype, Types::Int8, default: 1 + define_attr :htype, BinStruct::Int8, default: 1 # @!attribute hlen # 8-bit hardware address length # @return [Integer] - define_field :hlen, Types::Int8, default: 6 + define_attr :hlen, BinStruct::Int8, default: 6 # @!attribute hops # @return [Integer] - define_field :hops, Types::Int8 + define_attr :hops, BinStruct::Int8 # @!attribute xid # 32-bit Transaction ID # @return [Integer] - define_field :xid, Types::Int32 + define_attr :xid, BinStruct::Int32 # @!attribute secs # 16-bit integer: number of seconds elapsed since client began address # acquisition or renewal process # @return [Integer] - define_field :secs, Types::Int16 + define_attr :secs, BinStruct::Int16 # @!attribute flags # 16-bit flag field # @return [Integer] - define_field :flags, Types::Int16 + define_attr :flags, BinStruct::Int16 # @!attribute ciaddr # client IP address # @return [String] - define_field :ciaddr, IP::Addr + define_attr :ciaddr, IP::Addr # @!attribute yiaddr # 'your' (client) IP address # @return [String] - define_field :yiaddr, IP::Addr + define_attr :yiaddr, IP::Addr # @!attribute siaddr # IP address of next server to use in bootstrap # @return [String] - define_field :siaddr, IP::Addr + define_attr :siaddr, IP::Addr # @!attribute giaddr # Relay agent IP address, used in booting via a relay agent # @return [String] - define_field :giaddr, IP::Addr + define_attr :giaddr, IP::Addr # @!attribute chaddr # client hardware address # @return [String] - define_field :chaddr, Types::String, static_length: 16 + define_attr :chaddr, BinStruct::String, static_length: 16 # @!attribute sname # optional server hostname, null-terminated string # @return [String] - define_field :sname, Types::CString, static_length: 64 + define_attr :sname, BinStruct::CString, static_length: 64 # @!attribute file # Boot file name, null terminated string # @return [String] - define_field :file, Types::CString, static_length: 128 + define_attr :file, BinStruct::CString, static_length: 128 # @!attribute body # @return [String] - define_field :body, Types::String + define_attr :body, BinStruct::String # @!attribute b # Broadcast flag, from {#flags} @@ -129,7 +129,7 @@ class BOOTP < Base # @!attribute mbz # 15-bit Must Be Zero bits, from {#flags} # @return [Boolean] - define_bit_fields_on :flags, :b, :mbz, 15 + define_bit_attrs_on :flags, :b, :mbz, 15 # @return [String] def inspect diff --git a/lib/packetgen/header/dhcp.rb b/lib/packetgen/header/dhcp.rb index d624e7d..47d768a 100644 --- a/lib/packetgen/header/dhcp.rb +++ b/lib/packetgen/header/dhcp.rb @@ -12,7 +12,7 @@ module Header # RFC 2131} # # A DHCP header is quite simple. It is composed of: - # * a {#magic} field ({Types::Int32}) to retrieve it in a BOOTP header, + # * a {#magic} field ({BinStruct::Int32}) to retrieve it in a BOOTP header, # * a, {#options} field ({Options} type, which is a collection of DHCP # options). # @@ -50,10 +50,10 @@ class DHCP < Base # @!attribute magic # @return [Integer] - define_field :magic, Types::Int32, default: 0x63825563 + define_attr :magic, BinStruct::Int32, default: 0x63825563 # @!attribute options # @return [DHCP::Options] - define_field :options, DHCP::Options + define_attr :options, DHCP::Options # differentiate from BOOTP by checking presence of DHCP magic # @return [Boolean] diff --git a/lib/packetgen/header/dhcp/option.rb b/lib/packetgen/header/dhcp/option.rb index 0066f40..472e22c 100644 --- a/lib/packetgen/header/dhcp/option.rb +++ b/lib/packetgen/header/dhcp/option.rb @@ -59,51 +59,51 @@ class DHCP # @!parse # # Option class with string value. {#type #type} and {#length #length} are - # # {Types::Int8}. + # # {BinStruct::Int8}. # # # # See also {IPAddrOption}, {Int8Option}, {Int16Option} and {Int32Option}. # # @since 2.2.0 - # # @since 3.1.0 subclass of {Types::AbstractTLV} - # class Option < Types::AbstractTLV; end + # # @since 3.1.0 subclass of {BinStruct::AbstractTLV} + # class Option < BinStruct::AbstractTLV; end # @private - Option = Types::AbstractTLV.create + Option = BinStruct::AbstractTLV.create Option.define_type_enum DHCP_OPTIONS # @!parse # # {Option} class with IP address value # # @since 2.2.0 - # # @since 3.1.0 subclass of {Types::AbstractTLV} - # class IPAddrOption < Types::AbstractTLV; end + # # @since 3.1.0 subclass of {BinStruct::AbstractTLV} + # class IPAddrOption < BinStruct::AbstractTLV; end # @private - IPAddrOption = Types::AbstractTLV.create(value_class: IP::Addr) + IPAddrOption = BinStruct::AbstractTLV.create(value_class: IP::Addr) IPAddrOption.define_type_enum DHCP_OPTIONS # @!parse # # {Option} class with int8 value # # @since 2.2.0 - # # @since 3.1.0 subclass of {Types::AbstractTLV} - # class Int8Option < Types::AbstractTLV; end + # # @since 3.1.0 subclass of {BinStruct::AbstractTLV} + # class Int8Option < BinStruct::AbstractTLV; end # @private - Int8Option = Types::AbstractTLV.create(value_class: Types::Int8) + Int8Option = BinStruct::AbstractTLV.create(value_class: BinStruct::Int8) Int8Option.define_type_enum DHCP_OPTIONS # @!parse # # {Option} class with int16 value # # @since 2.2.0 - # # @since 3.1.0 subclass of {Types::AbstractTLV} - # class Int16Option < Types::AbstractTLV; end + # # @since 3.1.0 subclass of {BinStruct::AbstractTLV} + # class Int16Option < BinStruct::AbstractTLV; end # @private - Int16Option = Types::AbstractTLV.create(value_class: Types::Int16) + Int16Option = BinStruct::AbstractTLV.create(value_class: BinStruct::Int16) Int16Option.define_type_enum DHCP_OPTIONS # @!parse # # {Option} class with int32 value # # @since 2.2.0 - # # @since 3.1.0 subclass of {Types::AbstractTLV} - # class Int32Option < Types::AbstractTLV; end + # # @since 3.1.0 subclass of {BinStruct::AbstractTLV} + # class Int32Option < BinStruct::AbstractTLV; end # @private - Int32Option = Types::AbstractTLV.create(value_class: Types::Int32) + Int32Option = BinStruct::AbstractTLV.create(value_class: BinStruct::Int32) Int32Option.define_type_enum DHCP_OPTIONS # Class to indicate DHCP options end - class End < Types::Int8 - def initialize(value=255) + class End < BinStruct::Int8 + def initialize(options={ value: 255 }) super end @@ -115,7 +115,7 @@ def to_human # Class to indicate padding after DHCP options class Pad < End - def initialize(value=0) + def initialize(options={ value: 0 }) super end end diff --git a/lib/packetgen/header/dhcp/options.rb b/lib/packetgen/header/dhcp/options.rb index 05e591f..3f25c34 100644 --- a/lib/packetgen/header/dhcp/options.rb +++ b/lib/packetgen/header/dhcp/options.rb @@ -22,7 +22,7 @@ class DHCP # # And finish with padding # options << { type: 'pad' } # @author Sylvain Daubert - class Options < Types::Array + class Options < BinStruct::Array set_of Option private diff --git a/lib/packetgen/header/dhcpv6.rb b/lib/packetgen/header/dhcpv6.rb index a718bdf..2ed3d3e 100644 --- a/lib/packetgen/header/dhcpv6.rb +++ b/lib/packetgen/header/dhcpv6.rb @@ -22,8 +22,8 @@ module Header # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # A DHCPv6 header is made of: - # * a {#msg_type} field ({Types::Int8Enum}), - # * a {#transaction_id} field ({Types::Int24}), + # * a {#msg_type} field ({BinStruct::Int8Enum}), + # * a {#transaction_id} field ({BinStruct::Int24}), # * and an {#options} field ({DHCPv6::Options}). # # == Create a DHCPv6 header @@ -72,20 +72,20 @@ class DHCPv6 # @!attribute msg_type # 8-bit message type # @return [Integer] - define_field :msg_type, Types::Int8Enum, enum: MESSAGE_TYPES + define_attr :msg_type, BinStruct::Int8Enum, enum: MESSAGE_TYPES # @!attribute transaction_id # 24-bit transaction ID # @return [Integer] - define_field :transaction_id, Types::Int24 + define_attr :transaction_id, BinStruct::Int24 # @!attribute options # @return [DHCPv6::Options] - define_field :options, DHCPv6::Options + define_attr :options, DHCPv6::Options # Populate object from string # @param [String] str # @return [DHCPv6,DHCPv6::Relay] def read(str) - msg_type = Types::Int8.new.read(str) + msg_type = BinStruct::Int8.new.read(str) case msg_type when 12, 13 diff --git a/lib/packetgen/header/dhcpv6/duid.rb b/lib/packetgen/header/dhcpv6/duid.rb index 9c862ae..772922a 100644 --- a/lib/packetgen/header/dhcpv6/duid.rb +++ b/lib/packetgen/header/dhcpv6/duid.rb @@ -11,8 +11,8 @@ module Header class DHCPv6 # @abstract Base class for DUID (DHCP Unique ID) # @author Sylvain Daubert - class DUID < Types::Fields - include Types::Fieldable + class DUID < BinStruct::Struct + include BinStruct::Structable TYPES = { 'DUID-LLT' => 1, @@ -23,12 +23,12 @@ class DUID < Types::Fields # @!attribute type # 16-bit DUID type # @return [Integer] - define_field :type, Types::Int16Enum, enum: TYPES + define_attr :type, BinStruct::Int16Enum, enum: TYPES # @!attribute body - # @abstract replaced by specific fields in subclasses + # @abstract replaced by specific attributes.in subclasses # DUID data. # @return [String] - define_field :body, Types::String + define_attr :body, BinStruct::String alias private_read read private :private_read @@ -72,7 +72,7 @@ def human_type # DUID Based on Link-layer Address Plus Time # @author Sylvain Daubert class DUID_LLT < DUID - remove_field :body + remove_attr :body # Base time for time computation BASE_TIME = Time.utc(2000, 1, 1) @@ -80,14 +80,14 @@ class DUID_LLT < DUID # @!attribute htype # 16-bit hardware protocol type # @return [Integer] - define_field :htype, Types::Int16, default: 1 + define_attr :htype, BinStruct::Int16, default: 1 # @!attribute time # 32-bit time information # @return [Time] - define_field :time, Types::Int32, default: (Time.now - BASE_TIME).to_i + define_attr :time, BinStruct::Int32, default: (Time.now - BASE_TIME).to_i # @!attribute link_addr # @return [Eth::MacAddr] - define_field :link_addr, Eth::MacAddr + define_attr :link_addr, Eth::MacAddr undef time, time= @@ -112,15 +112,15 @@ def to_human # DUID Based on Enterprise Number # @author Sylvain Daubert class DUID_EN < DUID - remove_field :body + remove_attr :body # @!attribute en # 32-bit entreprise number # @return [Integer] - define_field :en, Types::Int32 + define_attr :en, BinStruct::Int32 # @!attribute identifier # @return [String] - define_field :identifier, Types::String + define_attr :identifier, BinStruct::String # Get human-readable DUID description # @return [String] @@ -132,15 +132,15 @@ def to_human # DUID Based on Link-layer # @author Sylvain Daubert class DUID_LL < DUID - remove_field :body + remove_attr :body # @!attribute htype # 16-bit hardware protocol type # @return [Integer] - define_field :htype, Types::Int16, default: 1 + define_attr :htype, BinStruct::Int16, default: 1 # @!attribute link_addr # @return [Eth::MacAddr] - define_field :link_addr, Eth::MacAddr + define_attr :link_addr, Eth::MacAddr # Get human-readable DUID description # @return [String] diff --git a/lib/packetgen/header/dhcpv6/option.rb b/lib/packetgen/header/dhcpv6/option.rb index f038b80..eb4dd7b 100644 --- a/lib/packetgen/header/dhcpv6/option.rb +++ b/lib/packetgen/header/dhcpv6/option.rb @@ -10,29 +10,29 @@ module PacketGen module Header class DHCPv6 # A DHCPv6 consists of: - # * a {#type} ({Types::Int16}), - # * a {#length} ({Types::Int16}), - # * and a {#data} ({Types::String}). + # * a {#type} ({BinStruct::Int16}), + # * a {#length} ({BinStruct::Int16}), + # * and a {#data} ({BinStruct::String}). # # Subclasses handles known options. These subclasses may remove {#data} # field to replace it by specific option field(s). # @author Sylvain Daubert - class Option < Types::Fields - include Types::Fieldable + class Option < BinStruct::Struct + include BinStruct::Structable # @!attribute type # 16-bit option type # @return [Integer] - define_field :type, Types::Int16 + define_attr :type, BinStruct::Int16 # @!attribute length # 16-bit option length # @return [Integer] - define_field :length, Types::Int16 + define_attr :length, BinStruct::Int16 # @!attribute data # variable length option data. # @return [String] - define_field :data, Types::String, - builder: ->(h, t) { t.new(length_from: h[:length]) } + define_attr :data, BinStruct::String, + builder: ->(h, t) { t.new(length_from: h[:length]) } class << self # Get Option subclasses @@ -111,12 +111,12 @@ def to_human # DHCPv6 Client ID option # @author Sylvain Daubert class ClientID < Option - update_field :type, default: 1 - remove_field :data + update_attr :type, default: 1 + remove_attr :data # @!attribute duid # @return [DUID] - define_field :duid, DUID + define_attr :duid, DUID # Get human-readable data (DUID) # @return [String] @@ -128,32 +128,32 @@ def human_data # DHCPv6 Server ID option # @author Sylvain Daubert class ServerID < ClientID - update_field :type, default: 2 + update_attr :type, default: 2 end # DHCPv6 Identity Association for Non-temporary Addresses Option # @author Sylvain Daubert class IANA < Option - update_field :type, default: 3 - remove_field :data + update_attr :type, default: 3 + remove_attr :data # @!attribute iaid # 32-bit IAID field # @return [Integer] - define_field :iaid, Types::Int32 + define_attr :iaid, BinStruct::Int32 # @!attribute t1 # 32-bit T1 field # @return [Integer] - define_field :t1, Types::Int32 + define_attr :t1, BinStruct::Int32 # @!attribute t2 # 32-bit T2 field # @return [Integer] - define_field :t2, Types::Int32 + define_attr :t2, BinStruct::Int32 # @!attribute options # options field # @return [String] - define_field :options, Types::String, - builder: ->(h, t) { t.new length_from: -> { h[:length].to_i - 12 } } + define_attr :options, BinStruct::String, + builder: ->(h, t) { t.new length_from: -> { h[:length].to_i - 12 } } # Get human-readable data (IAID, T1 and T2) # @return [String] @@ -165,18 +165,18 @@ def human_data # DHCPv6 Identity Association for Temporary Addresses Option # @author Sylvain Daubert class IATA < Option - update_field :type, default: 4 - remove_field :data + update_attr :type, default: 4 + remove_attr :data # @!attribute iaid # 32-bit IAID field # @return [Integer] - define_field :iaid, Types::Int32 + define_attr :iaid, BinStruct::Int32 # @!attribute options # options field # @return [String] - define_field :options, Types::String, - builder: ->(h, t) { t.new length_from: -> { h[:length].to_i - 4 } } + define_attr :options, BinStruct::String, + builder: ->(h, t) { t.new length_from: -> { h[:length].to_i - 4 } } # Get human-readable data (IAID) # @return [String] @@ -188,26 +188,26 @@ def human_data # DHCPv6 IA Address option # @author Sylvain Daubert class IAAddr < Option - update_field :type, default: 5 - remove_field :data + update_attr :type, default: 5 + remove_attr :data # @attribute ipv6 # IPv6 address # @return [IPv6::Addr] - define_field :ipv6, IPv6::Addr + define_attr :ipv6, IPv6::Addr # @attribute preferred_lifetime # 32-bit preferred lifetime # @return [Integer] - define_field :preferred_lifetime, Types::Int32 + define_attr :preferred_lifetime, BinStruct::Int32 # @attribute valid_lifetime # 32-bit valid lifetime # @return [Integer] - define_field :valid_lifetime, Types::Int32 + define_attr :valid_lifetime, BinStruct::Int32 # @!attribute options # options field # @return [String] - define_field :options, Types::String, - builder: ->(h, t) { t.new length_from: -> { h[:length].to_i - 24 } } + define_attr :options, BinStruct::String, + builder: ->(h, t) { t.new length_from: -> { h[:length].to_i - 24 } } # Get human-readable data (ipv6, preferred lifetime and valid lifetime) # @return [String] @@ -217,21 +217,21 @@ def human_data end # List of requested options for {ORO} option. - # Set of {Types::Int16} + # Set of {BinStruct::Int16} # @author Sylvain Daubert - class RequestedOptions < Types::Array - set_of Types::Int16 + class RequestedOptions < BinStruct::Array + set_of BinStruct::Int16 end # DHCPv6 Option Request Option # @author Sylvain Daubert class ORO < Option - update_field :type, default: 6 - remove_field :data + update_attr :type, default: 6 + remove_attr :data # @!attribute options # @return [RequestedOptions] - define_field :options, RequestedOptions, builder: ->(h, t) { t.new(length_from: h[:length]) } + define_attr :options, RequestedOptions, builder: ->(h, t) { t.new(length_from: h[:length]) } # Get human-readable data # @return [String] @@ -243,13 +243,13 @@ def human_data # DHCPv6 Preference option # @author Sylvain Daubert class Preference < Option - update_field :type, default: 7 - remove_field :data + update_attr :type, default: 7 + remove_attr :data # @!attribute value # 8-bit value # @return [Integer] - define_field :value, Types::Int8 + define_attr :value, BinStruct::Int8 # Get human-readable data (value) # @return [String] @@ -261,13 +261,13 @@ def human_data # DHCPv6 Elapsed Time option # @author Sylvain Daubert class ElapsedTime < Option - update_field :type, default: 8 - remove_field :data + update_attr :type, default: 8 + remove_attr :data # @!attribute value # 16-bit value # @return [Integer] - define_field :value, Types::Int16 + define_attr :value, BinStruct::Int16 # Get human-readable data (value) # @return [String] @@ -279,19 +279,19 @@ def human_data # DHCPv6 Relay Message option # @author Sylvain Daubert class RelayMessage < Option - update_field :type, default: 9 + update_attr :type, default: 9 end # DHCPv6 Server Unicast option # @author Sylvain Daubert class ServerUnicast < Option - update_field :type, default: 12 - remove_field :data + update_attr :type, default: 12 + remove_attr :data # @!attribute addr # IPv6 server address # @return [IPv6::Addr] - define_field :addr, IPv6::Addr + define_attr :addr, IPv6::Addr # Get human-readable data (addr) # @return [String] @@ -303,14 +303,14 @@ def human_data # DHCPv6 Status Code option # @author Sylvain Daubert class StatusCode < ElapsedTime - update_field :type, default: 13 + update_attr :type, default: 13 end # DHCPv6 Rapid Commit option # @author Sylvain Daubert class RapidCommit < Option - update_field :type, default: 14 - remove_field :data + update_attr :type, default: 14 + remove_attr :data end end end diff --git a/lib/packetgen/header/dhcpv6/options.rb b/lib/packetgen/header/dhcpv6/options.rb index 0ba6701..777530a 100644 --- a/lib/packetgen/header/dhcpv6/options.rb +++ b/lib/packetgen/header/dhcpv6/options.rb @@ -19,7 +19,7 @@ class DHCPv6 # duid = PacketGen::Header::DHCPv6::DUID_LL.new(link_addr: '08:00:27:fe:8f:95') # options << { type: 1, duid: duid } # @author Sylvain Daubert - class Options < Types::Array + class Options < BinStruct::Array set_of DHCPv6::Option # Separator used in {#to_human}. diff --git a/lib/packetgen/header/dhcpv6/relay.rb b/lib/packetgen/header/dhcpv6/relay.rb index a691486..b5dc4ef 100644 --- a/lib/packetgen/header/dhcpv6/relay.rb +++ b/lib/packetgen/header/dhcpv6/relay.rb @@ -21,25 +21,25 @@ class Relay < Base # @!attribute msg_type # 8-bit message type # @return [Integer] - define_field :msg_type, Types::Int8Enum, enum: MESSAGE_TYPES + define_attr :msg_type, BinStruct::Int8Enum, enum: MESSAGE_TYPES # @!attribute hop_count # 8-bit hop count (number of relay agents that have relayed # this message) # @return [Integer] - define_field :hop_count, Types::Int8 + define_attr :hop_count, BinStruct::Int8 # @!attribute link # Link address: address that will be used by the server to identify # the link on which the client is located # @return [IPv6::Addr] - define_field :link, IPv6::Addr + define_attr :link, IPv6::Addr # @!attribute peer # Peer address: the address of the client or relay agent from which # the message to be relayed was received # @return [IPv6::Addr] - define_field :peer, IPv6::Addr + define_attr :peer, IPv6::Addr # @!attribute options # @return [DHCPv6::Options] - define_field :options, DHCPv6::Options + define_attr :options, DHCPv6::Options end end diff --git a/lib/packetgen/header/dns.rb b/lib/packetgen/header/dns.rb index 134c240..b47d136 100644 --- a/lib/packetgen/header/dns.rb +++ b/lib/packetgen/header/dns.rb @@ -141,34 +141,34 @@ class DNS # @!attribute id # @return [Integer] - define_field :id, Types::Int16 + define_attr :id, BinStruct::Int16 # @!attribute u16 # @return [Integer] - define_field :u16, Types::Int16 + define_attr :u16, BinStruct::Int16 # @!attribute qdcount # @return [Integer] - define_field :qdcount, Types::Int16 + define_attr :qdcount, BinStruct::Int16 # @!attribute ancount # @return [Integer] - define_field :ancount, Types::Int16 + define_attr :ancount, BinStruct::Int16 # @!attribute nscount # @return [Integer] - define_field :nscount, Types::Int16 + define_attr :nscount, BinStruct::Int16 # @!attribute arcount # @return [Integer] - define_field :arcount, Types::Int16 + define_attr :arcount, BinStruct::Int16 # @!attribute qd # @return [QDSection] - define_field :qd, QDSection, builder: ->(h, t) { t.new(h, h[:qdcount]) } + define_attr :qd, QDSection, builder: ->(h, t) { t.new(h, h[:qdcount]) } # @!attribute an # @return [RRSection] - define_field :an, RRSection, builder: ->(h, t) { t.new(h, h[:ancount]) } + define_attr :an, RRSection, builder: ->(h, t) { t.new(h, h[:ancount]) } # @!attribute ns # @return [RRSection] - define_field :ns, RRSection, builder: ->(h, t) { t.new(h, h[:nscount]) } + define_attr :ns, RRSection, builder: ->(h, t) { t.new(h, h[:nscount]) } # @!attribute ar # @return [RRSection] - define_field :ar, RRSection, builder: ->(h, t) { t.new(h, h[:arcount]) } + define_attr :ar, RRSection, builder: ->(h, t) { t.new(h, h[:arcount]) } # @!attribute qr # @return [Boolean] query (+false+) or response (+true+) @@ -188,8 +188,8 @@ class DNS # @return [Boolean] Checking Disabled # @!attribute rcode # @return [Integer] Response code. See {RCODES}. - define_bit_fields_on :u16, :qr, :opcode, 4, :aa, :tc, :rd, :ra, :z, - :ad, :cd, :rcode, 4 + define_bit_attrs_on :u16, :qr, :opcode, 4, :aa, :tc, :rd, :ra, :z, + :ad, :cd, :rcode, 4 undef opcode=, rcode= diff --git a/lib/packetgen/header/dns/name.rb b/lib/packetgen/header/dns/name.rb index 580bf80..6363dc4 100644 --- a/lib/packetgen/header/dns/name.rb +++ b/lib/packetgen/header/dns/name.rb @@ -9,9 +9,9 @@ module PacketGen module Header class DNS - # DNS Name, defined as a suite of labels. A label is of type {Types::IntString}. + # DNS Name, defined as a suite of labels. A label is of type {BinStruct::IntString}. # @author Sylvain Daubert - class Name < Types::Array + class Name < BinStruct::Array # Mask to decode a pointer on another label POINTER_MASK = 0xc000 @@ -25,10 +25,10 @@ def initialize end # @!method push(label) - # @param [Types::IntString] label + # @param [BinStruct::IntString] label # @return [Name] self # @!method <<(label) - # @param [Types::IntString] label + # @param [BinStruct::IntString] label # @return [Name] self # Read a set of labels form a dotted string @@ -39,9 +39,9 @@ def from_human(str) return self if str.nil? str.split('.').each do |label| - self << Types::IntString.new(string: label) + self << BinStruct::IntString.new(string: label) end - self << Types::IntString.new + self << BinStruct::IntString.new end # Clear name @@ -119,7 +119,7 @@ def record_from_hash(_hsh) end def add_label_from(str) - label = Types::IntString.new + label = BinStruct::IntString.new label.read(str) self << label label diff --git a/lib/packetgen/header/dns/opt.rb b/lib/packetgen/header/dns/opt.rb index e41a318..160b380 100644 --- a/lib/packetgen/header/dns/opt.rb +++ b/lib/packetgen/header/dns/opt.rb @@ -20,7 +20,7 @@ class DNS class OPT < RR # @!attribute options # @return [ArrayOfOptions] - define_field_after :rdata, :options, ArrayOfOptions + define_attr_after :rdata, :options, ArrayOfOptions # @param [DNS] dns # @param [Hash] options diff --git a/lib/packetgen/header/dns/option.rb b/lib/packetgen/header/dns/option.rb index 1cc7c85..11b3b01 100644 --- a/lib/packetgen/header/dns/option.rb +++ b/lib/packetgen/header/dns/option.rb @@ -11,28 +11,28 @@ module Header class DNS # @!parse # # DNS option is a TLV object: - # # * {#code} is a {Types::Int16}, - # # * {#length} is a {Types::Int16}, - # # * {#data} is a {Types::String}. + # # * {#code} is a {BinStruct::Int16}, + # # * {#length} is a {BinStruct::Int16}, + # # * {#data} is a {BinStruct::String}. # # # # @since 1.3.0 - # # @since 3.1.0 defined with {Types::AbstractTLV} - # # @!parse class Option < Types::AbstractTLV; end + # # @since 3.1.0 defined with {BinStruct::AbstractTLV} + # # @!parse class Option < BinStruct::AbstractTLV; end # # @!attribute code # # Alias for {#type} # # @return [Integer] # # @!attribute data # # Alias for {#value} - # # @return [Types::String] - # class Option < Types::AbstractTLV; end + # # @return [BinStruct::String] + # class Option < BinStruct::AbstractTLV; end # @private - Option = Types::AbstractTLV.create(type_class: Types::Int16, - length_class: Types::Int16, - aliases: { code: :type, data: :value }) + Option = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16, + length_class: BinStruct::Int16, + aliases: { code: :type, data: :value }) # Array of {Option}. # @since 3.1.1 - class ArrayOfOptions < Types::Array + class ArrayOfOptions < BinStruct::Array set_of Option end end diff --git a/lib/packetgen/header/dns/question.rb b/lib/packetgen/header/dns/question.rb index 48e1fb3..43d10df 100644 --- a/lib/packetgen/header/dns/question.rb +++ b/lib/packetgen/header/dns/question.rb @@ -11,8 +11,8 @@ module Header class DNS # DNS Question # @author Sylvain Daubert - class Question < Types::Fields - include Types::Fieldable + class Question < BinStruct::Struct + include BinStruct::Structable # Ressource Record types TYPES = { @@ -59,15 +59,15 @@ class Question < Types::Fields # @!attribute name # Question domain name # @return [String] - define_field :name, Name, default: '.' + define_attr :name, Name, default: '.' # @!attribute type # 16-bit question type # @return [Integer] - define_field :type, Types::Int16Enum, default: 1, enum: TYPES + define_attr :type, BinStruct::Int16Enum, default: 1, enum: TYPES # @!attribute rrclass # 16-bit question class # @return [Integer] - define_field :rrclass, Types::Int16Enum, default: 1, enum: CLASSES + define_attr :rrclass, BinStruct::Int16Enum, default: 1, enum: CLASSES # @param [DNS] dns # @param [Hash] options @@ -95,7 +95,7 @@ def rrclass=(val) end raise ArgumentError, "unknown class #{val.inspect}" unless v - self[:rrclass].read v + self[:rrclass].from_human(v) end # Check type diff --git a/lib/packetgen/header/dns/rr.rb b/lib/packetgen/header/dns/rr.rb index e0888fa..9c984f5 100644 --- a/lib/packetgen/header/dns/rr.rb +++ b/lib/packetgen/header/dns/rr.rb @@ -15,15 +15,15 @@ class RR < Question # @!attribute ttl # 32-bit time to live # @return [Integer] - define_field :ttl, Types::Int32 + define_attr :ttl, BinStruct::Int32 # @!attribute rdlength # 16-bit {#rdata} length # @return [Integer] - define_field :rdlength, Types::Int16 + define_attr :rdlength, BinStruct::Int16 # @!attribute rdata - # @return [Types::String] - define_field :rdata, Types::String, - builder: ->(rr, t) { t.new(length_from: rr[:rdlength]) } + # @return [BinStruct::String] + define_attr :rdata, BinStruct::String, + builder: ->(rr, t) { t.new(length_from: rr[:rdlength]) } # @param [DNS] dns # @param [Hash] options @@ -47,8 +47,8 @@ def initialize(dns, options={}) # @param [String] data # @return [void] def rdata=(data) - self[:rdlength].read data.size - self[:rdata].read data + self[:rdlength].from_human(data.size) + self[:rdata].read(data) end # rubocop:disable Metrics/AbcSize @@ -108,7 +108,7 @@ def human_mx_data name = Name.new name.dns = self[:name].dns - pref = Types::Int16.new.read(self[:rdata][0, 2]) + pref = BinStruct::Int16.new.read(self[:rdata][0, 2]) exchange = name.read(self[:rdata][2..]).to_human '%u %s' % [pref.to_i, exchange] @@ -121,11 +121,11 @@ def human_soa_rdata mname = name.read(self[:rdata]).dup rname = name.read(self[:rdata][mname.sz..]) - serial = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz, 4]) - refresh = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz + 4, 4]) - retryi = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz + 8, 4]) - expire = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz + 12, 4]) - minimum = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz + 16, 4]) + serial = BinStruct::Int32.new.read(self[:rdata][mname.sz + rname.sz, 4]) + refresh = BinStruct::Int32.new.read(self[:rdata][mname.sz + rname.sz + 4, 4]) + retryi = BinStruct::Int32.new.read(self[:rdata][mname.sz + rname.sz + 8, 4]) + expire = BinStruct::Int32.new.read(self[:rdata][mname.sz + rname.sz + 12, 4]) + minimum = BinStruct::Int32.new.read(self[:rdata][mname.sz + rname.sz + 16, 4]) "#{mname.to_human} #{rname.to_human} #{serial.to_i} #{refresh.to_i} " \ "#{retryi.to_i} #{expire.to_i} #{minimum.to_i}" @@ -135,9 +135,9 @@ def human_srv_data name = Name.new name.dns = self[:name].dns - priority = Types::Int16.new.read(self[:rdata][0, 2]) - weight = Types::Int16.new.read(self[:rdata][2, 2]) - port = Types::Int16.new.read(self[:rdata][4, 2]) + priority = BinStruct::Int16.new.read(self[:rdata][0, 2]) + weight = BinStruct::Int16.new.read(self[:rdata][2, 2]) + port = BinStruct::Int16.new.read(self[:rdata][4, 2]) target = name.read(self[:rdata][6, self[:rdata].size]).to_human "#{priority.to_i} #{weight.to_i} #{port.to_i} #{target}" diff --git a/lib/packetgen/header/dns/rrsection.rb b/lib/packetgen/header/dns/rrsection.rb index 6e1c7c2..962ee3d 100644 --- a/lib/packetgen/header/dns/rrsection.rb +++ b/lib/packetgen/header/dns/rrsection.rb @@ -11,10 +11,10 @@ module Header class DNS # Define a DNS Ressource Record Section # @author Sylvain Daubert - class RRSection < Types::Array + class RRSection < BinStruct::Array # @api private # @param [DNS] dns - # @param [Types::Int] counter + # @param [BinStruct::Int] counter def initialize(dns, counter) super(counter: counter) @dns = dns diff --git a/lib/packetgen/header/dot11.rb b/lib/packetgen/header/dot11.rb index 5e3a034..ce99afe 100644 --- a/lib/packetgen/header/dot11.rb +++ b/lib/packetgen/header/dot11.rb @@ -17,25 +17,25 @@ module Header class PPI < Base # @!attribute version # @return [Integer] 8-bit PPI version - define_field :version, Types::Int8, default: 0 + define_attr :version, BinStruct::Int8, default: 0 # @!attribute flags # @return [Integer] 8-bit PPI flags - define_field :flags, Types::Int8 + define_attr :flags, BinStruct::Int8 # @!attribute length # @return [Integer] 16-bit PPI header length - define_field :length, Types::Int16le, default: 8 + define_attr :length, BinStruct::Int16le, default: 8 # @!attribute dlt # @return [Integer] 32-bit PPI data link type - define_field :dlt, Types::Int32le + define_attr :dlt, BinStruct::Int32le # @!attribute ppi_fields # @return [Type::String] concatenation of PPI fields - define_field :ppi_fields, Types::String, builder: ->(h, t) { t.new(length_from: -> { h.length - 8 }) } + define_attr :ppi_fields, BinStruct::String, builder: ->(h, t) { t.new(length_from: -> { h.length - 8 }) } # @!attribute body # @return [Type::String] - define_field :body, Types::String + define_attr :body, BinStruct::String # @!attribute align # @return [Boolean] align flag from {#flags} attribute - define_bit_fields_on :flags, :reserved, 7, :align + define_bit_attrs_on :flags, :reserved, 7, :align # Check version field # @see [Base#parse?] @@ -65,22 +65,22 @@ def to_w(iface) class RadioTap < Base # @!attribute version # @return [Integer] 8-bit version - define_field :version, Types::Int8, default: 0 + define_attr :version, BinStruct::Int8, default: 0 # @!attribute pad # @return [Integer] 8-bit pad - define_field :pad, Types::Int8, default: 0 + define_attr :pad, BinStruct::Int8, default: 0 # @!attribute length # @return [Integer] 16-bit RadioTap header length - define_field :length, Types::Int16le, default: 8 + define_attr :length, BinStruct::Int16le, default: 8 # @!attribute present_flags # @return [Integer] 32-bit integer - define_field :present_flags, Types::Int32le + define_attr :present_flags, BinStruct::Int32le # @!attribute radio_fields # @return [Type::String] concatenation of RadioTap fields - define_field :radio_fields, Types::String, builder: ->(h, t) { t.new(length_from: -> { h.length - 8 }) } + define_attr :radio_fields, BinStruct::String, builder: ->(h, t) { t.new(length_from: -> { h.length - 8 }) } # @!attribute body # @return [Type::String] - define_field :body, Types::String + define_attr :body, BinStruct::String # Check version field # @see [Base#parse?] @@ -108,18 +108,18 @@ def to_w(iface) # @abstract This is a base class to demultiplex different IEEE 802.11 frames when # parsing. # A IEEE 802.11 header may consist of at least: - # * a {#frame_ctrl} ({Types::Int16}), - # * a {#id}/duration ({Types::Int16le}), + # * a {#frame_ctrl} ({BinStruct::Int16}), + # * a {#id}/duration ({BinStruct::Int16le}), # * and a {#mac1} ({Eth::MacAddr}). # Depending on frame type and subtype, it may also contains: # * a {#mac2} ({Eth::MacAddr}), # * a {#mac3} ({Eth::MacAddr}), - # * a {#sequence_ctrl} ({Types::Int16}), + # * a {#sequence_ctrl} ({BinStruct::Int16}), # * a {#mac4} ({Eth::MacAddr}), - # * a {#qos_ctrl} ({Types::Int16}), - # * a {#ht_ctrl} ({Types::Int32}), - # * a {#body} (a {Types::String} or another {Base} class), - # * a Frame check sequence ({#fcs}, of type {Types::Int32le}) + # * a {#qos_ctrl} ({BinStruct::Int16}), + # * a {#ht_ctrl} ({BinStruct::Int32}), + # * a {#body} (a {BinStruct::String} or another {Base} class), + # * a Frame check sequence ({#fcs}, of type {BinStruct::Int32le}) # # == Header accessors # As Dot11 header types are defined under Dot11 namespace, Dot11 header accessors @@ -189,37 +189,37 @@ class << self # @!attribute frame_ctrl # @return [Integer] 16-bit frame control word - define_field :frame_ctrl, Types::Int16, default: 0 + define_attr :frame_ctrl, BinStruct::Int16, default: 0 # @!attribute id # @return [Integer] 16-bit ID/Duration word - define_field :id, Types::Int16le, default: 0 + define_attr :id, BinStruct::Int16le, default: 0 # @!attribute mac1 # @return [Eth::MacAddr] - define_field :mac1, Eth::MacAddr + define_attr :mac1, Eth::MacAddr # @!attribute mac2 # @return [Eth::MacAddr] - define_field :mac2, Eth::MacAddr + define_attr :mac2, Eth::MacAddr # @!attribute mac3 # @return [Eth::MacAddr] - define_field :mac3, Eth::MacAddr + define_attr :mac3, Eth::MacAddr # @!attribute sequence_ctrl # @return [Integer] 16-bit sequence control word - define_field :sequence_ctrl, Types::Int16le, default: 0 + define_attr :sequence_ctrl, BinStruct::Int16le, default: 0 # @!attribute mac4 # @return [Eth::MacAddr] - define_field :mac4, Eth::MacAddr + define_attr :mac4, Eth::MacAddr # @!attribute qos_ctrl # @return [Integer] 16-bit QoS control word - define_field :qos_ctrl, Types::Int16 + define_attr :qos_ctrl, BinStruct::Int16 # @!attribute ht_ctrl # @return [Integer] 16-bit HT control word - define_field :ht_ctrl, Types::Int32 + define_attr :ht_ctrl, BinStruct::Int32 # @!attribute body - # @return [Types::String] - define_field :body, Types::String + # @return [BinStruct::String] + define_attr :body, BinStruct::String # @!attribute fcs - # @return [Types::Int32le] - define_field :fcs, Types::Int32le + # @return [BinStruct::Int32le] + define_attr :fcs, BinStruct::Int32le # @!attribute subtype # @return [Integer] 4-bit frame subtype from {#frame_ctrl} @@ -243,8 +243,8 @@ class << self # @return [Boolean] from_ds flag from {#frame_ctrl} # @!attribute to_ds # @return [Boolean] to_ds flag from {#frame_ctrl} - define_bit_fields_on :frame_ctrl, :subtype, 4, :type, 2, :proto_version, 2, - :order, :wep, :md, :pwmngt, :retry, :mf, :from_ds, :to_ds + define_bit_attrs_on :frame_ctrl, :subtype, 4, :type, 2, :proto_version, 2, + :order, :wep, :md, :pwmngt, :retry, :mf, :from_ds, :to_ds # @!attribute sequence_number (12-bit field from {#sequence_ctrl}) # @return [Integer] @@ -252,23 +252,23 @@ class << self # @!attribute fragment_number (4-bit field from {#sequence_ctrl}) # @return [Integer] # @since 2.1.3 - define_bit_fields_on :sequence_ctrl, :sequence_number, 12, :fragment_number, 4 + define_bit_attrs_on :sequence_ctrl, :sequence_number, 12, :fragment_number, 4 alias duration id # @private - alias old_fields fields + alias old_attributes attributes # @param [Hash] options # @see Base#initialize def initialize(options={}) super - @applicable_fields = old_fields + @applicable_attributes = old_attributes end # Get all used field names # @return [Array] - def fields - @applicable_fields + def attributes + @applicable_attributes end # @private @@ -312,8 +312,8 @@ def calc_checksum # @return [String] def to_s - define_applicable_fields - @applicable_fields.map { |f| force_binary @fields[f].to_s }.join + define_applicable_attributes + @applicable_attributes.map { |f| force_binary @attributes[f].to_s }.join end # Get human readable type @@ -332,11 +332,11 @@ def inspect Inspect.dashed_line(self.class.to_s, 1) end - define_applicable_fields - @applicable_fields.each do |attr| + define_applicable_attributes + @applicable_attributes.each do |attr| next if attr == :body - str << Inspect.inspect_attribute(attr, @fields[attr], 1) + str << Inspect.inspect_attribute(attr, @attributes[attr], 1) end str end @@ -361,39 +361,39 @@ def added_to_packet(packet) private - def remove_from_applicable_fields(fields) - fields = [fields] unless fields.is_a? Array - @applicable_fields -= fields + def remove_from_applicable_attributes(attributes) + attributes = [attributes] unless attributes.is_a? Array + @applicable_attributes -= attributes end def handle_mac4 if to_ds? && from_ds? - @applicable_fields[6, 0] = :mac4 unless @applicable_fields.include? :mac4 + @applicable_attributes[6, 0] = :mac4 unless @applicable_attributes.include? :mac4 else - remove_from_applicable_fields :mac4 + remove_from_applicable_attributes :mac4 end end def handle_ht_ctrl if order? - unless @applicable_fields.include? :ht_ctrl - idx = @applicable_fields.index(:body) - @applicable_fields[idx, 0] = :ht_ctrl + unless @applicable_attributes.include? :ht_ctrl + idx = @applicable_attributes.index(:body) + @applicable_attributes[idx, 0] = :ht_ctrl end else - remove_from_applicable_fields %i[ht_ctrl] + remove_from_applicable_attributes %i[ht_ctrl] end end def handle_fcs if Dot11.fcs? - @applicable_fields << :fcs unless @applicable_fields.include? :fcs + @applicable_attributes << :fcs unless @applicable_attributes.include? :fcs else - remove_from_applicable_fields :fcs + remove_from_applicable_attributes :fcs end end - def define_applicable_fields + def define_applicable_attributes handle_mac4 handle_ht_ctrl handle_fcs @@ -401,7 +401,7 @@ def define_applicable_fields def private_read(str, fcs) self[:frame_ctrl].read str[0, 2] - define_applicable_fields + define_applicable_attributes if fcs old_read str[0...-4] self[:fcs].read str[-4..] diff --git a/lib/packetgen/header/dot11/control.rb b/lib/packetgen/header/dot11/control.rb index 44dd8be..d22a532 100644 --- a/lib/packetgen/header/dot11/control.rb +++ b/lib/packetgen/header/dot11/control.rb @@ -16,12 +16,12 @@ class Dot11 # (control frame). # # A IEEE 802.11 control header consists of: - # * a {#frame_ctrl} ({Types::Int16}), - # * a {#id}/duration ({Types::Int16le}), + # * a {#frame_ctrl} ({BinStruct::Int16}), + # * a {#id}/duration ({BinStruct::Int16le}), # * a {#mac1} ({Eth::MacAddr}). # * sometimes a {#mac2} ({Eth::MacAddr}), - # * a {#body} (a {Types::String} or another {Base} class), - # * and a Frame check sequence ({#fcs}, of type {Types::Int32le}). + # * a {#body} (a {BinStruct::String} or another {Base} class), + # * and a Frame check sequence ({#fcs}, of type {BinStruct::Int32le}). # @author Sylvain Daubert class Control < Dot11 # Control subtypes @@ -44,8 +44,8 @@ class Control < Dot11 # @see Base#initialize def initialize(options={}) super({ type: 1 }.merge!(options)) - @applicable_fields -= %i[mac3 sequence_ctrl mac4 qos_ctrl ht_ctrl] - define_applicable_fields + @applicable_attributes -= %i[mac3 sequence_ctrl mac4 qos_ctrl ht_ctrl] + define_applicable_attributes end # Get human readable subtype @@ -56,12 +56,12 @@ def human_subtype private - def define_applicable_fields + def define_applicable_attributes super - if @applicable_fields.include? :mac2 - @applicable_fields -= %i[mac2] unless SUBTYPES_WITH_MAC2.include? self.subtype + if @applicable_attributes.include? :mac2 + @applicable_attributes -= %i[mac2] unless SUBTYPES_WITH_MAC2.include? self.subtype elsif SUBTYPES_WITH_MAC2.include? self.subtype - @applicable_fields[3, 0] = :mac2 + @applicable_attributes[3, 0] = :mac2 end end end diff --git a/lib/packetgen/header/dot11/data.rb b/lib/packetgen/header/dot11/data.rb index a85ea05..ec21140 100644 --- a/lib/packetgen/header/dot11/data.rb +++ b/lib/packetgen/header/dot11/data.rb @@ -16,23 +16,23 @@ class Dot11 # (data frame). # # A IEEE 802.11 data header consists of: - # * a {#frame_ctrl} ({Types::Int16}), - # * a {#id}/duration ({Types::Int16le}), + # * a {#frame_ctrl} ({BinStruct::Int16}), + # * a {#id}/duration ({BinStruct::Int16le}), # * a {#mac2} ({Eth::MacAddr}), # * a {#mac3} ({Eth::MacAddr}), - # * a {#sequence_ctrl} ({Types::Int16}), + # * a {#sequence_ctrl} ({BinStruct::Int16}), # * sometimes a {#mac4} ({Eth::MacAddr}), - # * sometimes a {#qos_ctrl} ({Types::Int16}), - # * a {#body} (a {Types::String} or another {Base} class), - # * and a Frame check sequence ({#fcs}, of type {Types::Int32le}). + # * sometimes a {#qos_ctrl} ({BinStruct::Int16}), + # * a {#body} (a {BinStruct::String} or another {Base} class), + # * and a Frame check sequence ({#fcs}, of type {BinStruct::Int32le}). # @author Sylvain Daubert class Data < Dot11 # @param [Hash] options # @see Base#initialize def initialize(options={}) super({ type: 2 }.merge!(options)) - @applicable_fields -= %i[mac4 qos_ctrl ht_ctrl] - define_applicable_fields + @applicable_attributes -= %i[mac4 qos_ctrl ht_ctrl] + define_applicable_attributes end # Invert source and destination addresses (see Table 8-19 from @@ -111,19 +111,19 @@ def src_dst_from_mac end end - def define_applicable_fields + def define_applicable_attributes super - if (subtype >= 8) && !@applicable_fields.include?(:qos_ctrl) + if (subtype >= 8) && !@applicable_attributes.include?(:qos_ctrl) # Insert after mac4, if present # else insert after sequence_ctrl - if @applicable_fields.include? :mac4 - idx = @applicable_fields.index(:mac4) - @applicable_fields[idx, 0] = :qos_ctrl + if @applicable_attributes.include? :mac4 + idx = @applicable_attributes.index(:mac4) + @applicable_attributes[idx, 0] = :qos_ctrl else - @applicable_fields[6, 0] = :qos_ctrl + @applicable_attributes[6, 0] = :qos_ctrl end elsif subtype < 8 - @applicable_fields -= %i[qos_ctrl] + @applicable_attributes -= %i[qos_ctrl] end end diff --git a/lib/packetgen/header/dot11/element.rb b/lib/packetgen/header/dot11/element.rb index e5e2a35..1f1fbb1 100644 --- a/lib/packetgen/header/dot11/element.rb +++ b/lib/packetgen/header/dot11/element.rb @@ -15,10 +15,10 @@ class Dot11 # # # # An {Element} is a piece of data contained in a Dot11 management frame. # # @since 1.4.0 - # # @since 3.1.0 subclass of {Types::AbstractTLV} - # class Element < Types::AbstractTLV; end + # # @since 3.1.0 subclass of {BinStruct::AbstractTLV} + # class Element < BinStruct::AbstractTLV; end # @private - Element = Types::AbstractTLV.create + Element = BinStruct::AbstractTLV.create class Element # Known element types @@ -44,7 +44,7 @@ class Element # Array of {Element}. # @since 3.1.1 - class ArrayOfElements < Types::Array + class ArrayOfElements < BinStruct::Array set_of Element end end diff --git a/lib/packetgen/header/dot11/management.rb b/lib/packetgen/header/dot11/management.rb index 446093e..5e4eeaa 100644 --- a/lib/packetgen/header/dot11/management.rb +++ b/lib/packetgen/header/dot11/management.rb @@ -16,14 +16,14 @@ class Dot11 # (management frame). # # A IEEE 802.11 management header consists of: - # * a {#frame_ctrl} ({Types::Int16}), - # * a {#id}/duration ({Types::Int16le}), + # * a {#frame_ctrl} ({BinStruct::Int16}), + # * a {#id}/duration ({BinStruct::Int16le}), # * a {#mac1} ({Eth::MacAddr}). # * a {#mac2} ({Eth::MacAddr}), # * a {#mac3} ({Eth::MacAddr}), - # * a {#sequence_ctrl} ({Types::Int16}), - # * a {#body} (a {Types::String} or another {Base} class), - # * and a Frame check sequence ({#fcs}, of type {Types::Int32le}). + # * a {#sequence_ctrl} ({BinStruct::Int16}), + # * a {#body} (a {BinStruct::String} or another {Base} class), + # * and a Frame check sequence ({#fcs}, of type {BinStruct::Int32le}). # # Management frames should be constructed with more headers from # {SubMngt} subclasses. @@ -44,8 +44,8 @@ class Management < Dot11 # @see Base#initialize def initialize(options={}) super({ type: 0 }.merge!(options)) - @applicable_fields -= %i[mac4 qos_ctrl ht_ctrl] - define_applicable_fields + @applicable_attributes -= %i[mac4 qos_ctrl ht_ctrl] + define_applicable_attributes end # Add an {Element} diff --git a/lib/packetgen/header/dot11/sub_mngt.rb b/lib/packetgen/header/dot11/sub_mngt.rb index 019624c..57d4c62 100644 --- a/lib/packetgen/header/dot11/sub_mngt.rb +++ b/lib/packetgen/header/dot11/sub_mngt.rb @@ -20,7 +20,7 @@ class Dot11 # @author Sylvain Daubert class SubMngt < Base # @return [Array] - define_field :elements, ArrayOfElements + define_attr :elements, ArrayOfElements end # IEEE 802.11 Association Request frame @@ -28,16 +28,16 @@ class SubMngt < Base # Specialize {Dot11::Management} with +subtype+ set to 0. # # Add fields: - # * {#cap} ({Types::Int16le}), - # * {#listen_interval} ({Types::Int16le}). + # * {#cap} ({BinStruct::Int16le}), + # * {#listen_interval} ({BinStruct::Int16le}). # @author Sylvain Daubert class AssoReq < SubMngt # @!attribute cap # @return [Integer] 16-bit capabillities word - define_field_before :elements, :cap, Types::Int16le + define_attr_before :elements, :cap, BinStruct::Int16le # @!attribute listen_interval # @return [Integer] 16-bit listen interval value - define_field_before :elements, :listen_interval, Types::Int16le, default: 0x00c8 + define_attr_before :elements, :listen_interval, BinStruct::Int16le, default: 0x00c8 end Header.add_class AssoReq Management.bind AssoReq, type: 0, subtype: 0 @@ -47,20 +47,20 @@ class AssoReq < SubMngt # Specialize {Dot11::Management} with +subtype+ set to 1. # # Add fields: - # * {#cap} ({Types::Int16le}), - # * {#status} ({Types::Int16le}), - # * {#aid} ({Types::Int16le}). + # * {#cap} ({BinStruct::Int16le}), + # * {#status} ({BinStruct::Int16le}), + # * {#aid} ({BinStruct::Int16le}). # @author Sylvain Daubert class AssoResp < SubMngt # @!attribute cap # @return [Integer] 16-bit capabillities word - define_field_before :elements, :cap, Types::Int16le + define_attr_before :elements, :cap, BinStruct::Int16le # @!attribute status # @return [Integer] 16-bit status word - define_field_before :elements, :status, Types::Int16le + define_attr_before :elements, :status, BinStruct::Int16le # @!attribute aid # @return [Integer] 16-bit AID word - define_field_before :elements, :aid, Types::Int16le + define_attr_before :elements, :aid, BinStruct::Int16le end Header.add_class AssoResp Management.bind AssoResp, type: 0, subtype: 1 @@ -70,14 +70,14 @@ class AssoResp < SubMngt # Specialize {Dot11::Management} with +subtype+ set to 2. # # Add fields: - # * {#cap} ({Types::Int16le}), - # * {#listen_interval} ({Types::Int16le}), + # * {#cap} ({BinStruct::Int16le}), + # * {#listen_interval} ({BinStruct::Int16le}), # * {#current_ap} ({Eth::MacAddr}). # @author Sylvain Daubert class ReAssoReq < AssoReq # @!attribute current_ap # @return [Eth::MAcAddr] - define_field_before :elements, :current_ap, Eth::MacAddr + define_attr_before :elements, :current_ap, Eth::MacAddr end Header.add_class ReAssoReq Management.bind ReAssoReq, type: 0, subtype: 2 @@ -87,9 +87,9 @@ class ReAssoReq < AssoReq # Specialize {Dot11::Management} with +subtype+ set to 3. # # Add fields: - # * {#cap} ({Types::Int16le}), - # * {#status} ({Types::Int16le}), - # * {#aid} ({Types::Int16le}). + # * {#cap} ({BinStruct::Int16le}), + # * {#status} ({BinStruct::Int16le}), + # * {#aid} ({BinStruct::Int16le}). # @author Sylvain Daubert class ReAssoResp < AssoResp end @@ -112,20 +112,20 @@ class ProbeReq < SubMngt # Specialize {Dot11::Management} with +subtype+ set to 5. # # Add fields: - # * {#timestamp} ({Types::Int64le}), - # * {#beacon_interval} ({Types::Int16le}), - # * {#cap} ({Types::Int16le}). + # * {#timestamp} ({BinStruct::Int64le}), + # * {#beacon_interval} ({BinStruct::Int16le}), + # * {#cap} ({BinStruct::Int16le}). # @author Sylvain Daubert class ProbeResp < SubMngt # @!attribute timestamp # @return [Integer] 64-bit timestamp - define_field_before :elements, :timestamp, Types::Int64le + define_attr_before :elements, :timestamp, BinStruct::Int64le # @!attribute beacon_interval # @return [Integer] 16-bit beacon interval value - define_field_before :elements, :beacon_interval, Types::Int16le, default: 0x0064 + define_attr_before :elements, :beacon_interval, BinStruct::Int16le, default: 0x0064 # @!attribute cap # @return [Integer] 16-bit capabillities word - define_field_before :elements, :cap, Types::Int16le + define_attr_before :elements, :cap, BinStruct::Int16le end Header.add_class ProbeResp Management.bind ProbeResp, type: 0, subtype: 5 @@ -135,20 +135,20 @@ class ProbeResp < SubMngt # Specialize {Dot11::Management} with +subtype+ set to 8. # # Add fields: - # * {#timestamp} ({Types::Int64le}), - # * {#interval} ({Types::Int16le}), - # * {#cap} ({Types::Int16le}). + # * {#timestamp} ({BinStruct::Int64le}), + # * {#interval} ({BinStruct::Int16le}), + # * {#cap} ({BinStruct::Int16le}). # @author Sylvain Daubert class Beacon < SubMngt # @!attribute timestamp # @return [Integer] 64-bit timestamp - define_field_before :elements, :timestamp, Types::Int64le + define_attr_before :elements, :timestamp, BinStruct::Int64le # @!attribute interval # @return [Integer] 16-bit interval value - define_field_before :elements, :interval, Types::Int16le, default: 0x64 + define_attr_before :elements, :interval, BinStruct::Int16le, default: 0x64 # @!attribute cap # @return [Integer] 16-bit capabillities word - define_field_before :elements, :cap, Types::Int16le + define_attr_before :elements, :cap, BinStruct::Int16le end Header.add_class Beacon Management.bind Beacon, type: 0, subtype: 8 @@ -168,12 +168,12 @@ class ATIM < SubMngt; end # Specialize {Dot11::Management} with +subtype+ set to 10. # # Add fields: - # * {#reason} ({Types::Int16le}). + # * {#reason} ({BinStruct::Int16le}). # @author Sylvain Daubert class Disas < SubMngt # @!attribute reason # @return [Integer] 16-bit reason value - define_field_before :elements, :reason, Types::Int16le + define_attr_before :elements, :reason, BinStruct::Int16le end Header.add_class Disas Management.bind Disas, type: 0, subtype: 10 @@ -183,20 +183,20 @@ class Disas < SubMngt # Specialize {Dot11::Management} with +subtype+ set to 11. # # Add fields: - # * {#algo} ({Types::Int16le}), - # * {#seqnum} ({Types::Int16le}), - # * {#status} ({Types::Int16le}). + # * {#algo} ({BinStruct::Int16le}), + # * {#seqnum} ({BinStruct::Int16le}), + # * {#status} ({BinStruct::Int16le}). # @author Sylvain Daubert class Auth < SubMngt # @!attribute algo # @return [Integer] 16-bit algo value - define_field_before :elements, :algo, Types::Int16le + define_attr_before :elements, :algo, BinStruct::Int16le # @!attribute seqnum # @return [Integer] 16-bit seqnum value - define_field_before :elements, :seqnum, Types::Int16le + define_attr_before :elements, :seqnum, BinStruct::Int16le # @!attribute status # @return [Integer] 16-bit status word - define_field_before :elements, :status, Types::Int16le + define_attr_before :elements, :status, BinStruct::Int16le end Header.add_class Auth Management.bind Auth, type: 0, subtype: 11 @@ -206,12 +206,12 @@ class Auth < SubMngt # Specialize {Dot11::Management} with +subtype+ set to 12. # # Add fields: - # * {#reason} ({Types::Int16le}). + # * {#reason} ({BinStruct::Int16le}). # @author Sylvain Daubert class DeAuth < SubMngt # @!attribute reason # @return [Integer] 16-bit reason value - define_field_before :elements, :reason, Types::Int16le + define_attr_before :elements, :reason, BinStruct::Int16le end Header.add_class DeAuth Management.bind DeAuth, type: 0, subtype: 12 diff --git a/lib/packetgen/header/dot1q.rb b/lib/packetgen/header/dot1q.rb index a8cfacd..3a2d81f 100644 --- a/lib/packetgen/header/dot1q.rb +++ b/lib/packetgen/header/dot1q.rb @@ -11,9 +11,9 @@ module Header # IEEE 802.1Q VLAN tagging # # A VLAN tag consists of: - # * a {#tci Tag Control Information} ({Types::Int16}), - # * a {#ethertype} ({Types::Int16}), - # * and a body (a {Types::String} or another Header class). + # * a {#tci Tag Control Information} ({BinStruct::Int16}), + # * a {#ethertype} ({BinStruct::Int16}), + # * and a body (a {BinStruct::String} or another Header class). # # == Create a Dot1q header # # Create a IP packet in VLAN #43 @@ -23,13 +23,13 @@ module Header class Dot1q < Base # @!attribute tci # @return [Integer] 16-bit Tag Control Information - define_field :tci, Types::Int16 + define_attr :tci, BinStruct::Int16 # @!attribute ethertype # @return [Integer] 16-bit EtherType - define_field :ethertype, Types::Int16 + define_attr :ethertype, BinStruct::Int16 # @!attribute body - # @return [Types::String,Header::Base] - define_field :body, Types::String + # @return [BinStruct::String,Header::Base] + define_attr :body, BinStruct::String # @!attribute pcp # @return [Integer] 3-bit Priority Code Point from {#tci} @@ -37,7 +37,7 @@ class Dot1q < Base # @return [Boolean] Drop Eligible Indicator from {#tci} # @!attribute vid # @return [Integer] 12-bit VLAN ID from {#tci} - define_bit_fields_on :tci, :pcp, 3, :dei, :vid, 12 + define_bit_attrs_on :tci, :pcp, 3, :dei, :vid, 12 end Eth.bind Dot1q, ethertype: 0x8100 diff --git a/lib/packetgen/header/dot1x.rb b/lib/packetgen/header/dot1x.rb index 9422cae..d5bfdb3 100644 --- a/lib/packetgen/header/dot1x.rb +++ b/lib/packetgen/header/dot1x.rb @@ -11,10 +11,10 @@ module Header # IEEE 802.1X / EAPOL # # A IEEE 802.1X header consists of: - # * a {#version} ({Types::Int8}), - # * a packet {#type} ({Types::Int8}), - # * a {#length} ({Types::Int16}), - # * and a body (a {Types::String} or another Header class). + # * a {#version} ({BinStruct::Int8}), + # * a packet {#type} ({BinStruct::Int8}), + # * a {#length} ({BinStruct::Int16}), + # * and a body (a {BinStruct::String} or another Header class). # == Create a Dot1x header # pkt1 = PacketGen.gen('Eth').add('Dot1x', type: 1) # pkt2 = PacketGen.gen('Eth').add('Dot1x') @@ -37,16 +37,16 @@ class Dot1x < Base # @!attribute version # @return [Integer] 8-bit Protocol Version - define_field :version, Types::Int8, default: 1 + define_attr :version, BinStruct::Int8, default: 1 # @!attribute type # @return [Integer] 8-bit Packet Type - define_field :type, Types::Int8Enum, enum: TYPES + define_attr :type, BinStruct::Int8Enum, enum: TYPES # @!attribute length # @return [Integer] 16-bit body length - define_field :length, Types::Int16 + define_attr :length, BinStruct::Int16 # @!attribute body - # @return [Types::String,Header::Base] - define_field :body, Types::String, builder: ->(h, t) { t.new(length_from: h[:length]) } + # @return [BinStruct::String,Header::Base] + define_attr :body, BinStruct::String, builder: ->(h, t) { t.new(length_from: h[:length]) } # Get human readable type # @return [String] diff --git a/lib/packetgen/header/eap.rb b/lib/packetgen/header/eap.rb index fcb5d70..b9620ab 100644 --- a/lib/packetgen/header/eap.rb +++ b/lib/packetgen/header/eap.rb @@ -12,15 +12,15 @@ module Header # {https://tools.ietf.org/html/rfc3748 RFC 3748} # # A EAP header has: - # * a {#code} field ({Types::Int8Enum}), - # * a {#id} field ({Types::Int8}), - # * a {#length} field ({Types::Int16}). + # * a {#code} field ({BinStruct::Int8Enum}), + # * a {#id} field ({BinStruct::Int8}), + # * a {#length} field ({BinStruct::Int16}). # Request (code 1) and Response (code 2) packets also have: - # * a {#type} field (+Types::Int8Enum+). + # * a {#type} field (+BinStruct::Int8Enum+). # And Expanded Types (type 254) packets also have: - # * a {#vendor_id} field ({Types::Int24}), - # * a {#vendor_type} field ({Types::Int32}). - # Finally, all packets have a {#body} ({Types::String}). + # * a {#vendor_id} field ({BinStruct::Int24}), + # * a {#vendor_type} field ({BinStruct::Int32}). + # Finally, all packets have a {#body} ({BinStruct::String}). # # == Create EAP headers # An EAP header may be created this way: @@ -82,41 +82,41 @@ class EAP < Base # @!attribute code # @return [Integer] 8-bit EAP code - define_field :code, Types::Int8Enum, enum: CODES + define_attr :code, BinStruct::Int8Enum, enum: CODES # @!attribute id # @return [Integer] 8-bit identifier - define_field :id, Types::Int8 + define_attr :id, BinStruct::Int8 # @!attribute length # @return [Integer] 16-bit length of EAP packet - define_field :length, Types::Int16, default: 4 + define_attr :length, BinStruct::Int16, default: 4 # @!attribute type # This field is present only for Request or Response packets, # with type different from Expanded Types (254). # @return [Integer] 8-bit request or response type - define_field :type, Types::Int8Enum, - enum: TYPES, - optional: ->(eap) { eap.type? } + define_attr :type, BinStruct::Int8Enum, + enum: TYPES, + optional: lambda(&:type?) # @!attribute vendor_id # This field is present only for Request or Response packets, # with type equal to +Expanded Types+ (254). # @return [Integer] 24-bit vendor ID - define_field :vendor_id, Types::Int24, - optional: ->(eap) { eap.type? && (eap.type == 254) } + define_attr :vendor_id, BinStruct::Int24, + optional: ->(eap) { eap.type? && (eap.type == 254) } # @!attribute vendor_type # This field is present only for Request or Response packets, # with type equal to +Expanded Types+ (254). # @return [Integer] 32-bit vendor type - define_field :vendor_type, Types::Int32, - optional: ->(eap) { eap.type? && (eap.type == 254) } + define_attr :vendor_type, BinStruct::Int32, + optional: ->(eap) { eap.type? && (eap.type == 254) } # @!attribute body - # @return [Types::String, Header::Base] - define_field :body, Types::String + # @return [BinStruct::String, Header::Base] + define_attr :body, BinStruct::String # @return [EAP] def initialize(options={}) @@ -132,7 +132,7 @@ def initialize(options={}) # @return [Dot11] may return a subclass object if a more specific class # may be determined def read(str) - super(str) + super return self unless self.instance_of?(EAP) return self unless type? diff --git a/lib/packetgen/header/eap/fast.rb b/lib/packetgen/header/eap/fast.rb index ae06fdf..7830318 100644 --- a/lib/packetgen/header/eap/fast.rb +++ b/lib/packetgen/header/eap/fast.rb @@ -13,13 +13,13 @@ class EAP # Secure Tunneling, {https://tools.ietf.org/html/rfc4851 RFC 4851} # # {EAP::FAST} has following fields: - # * {#flags} ({Types::Int8}), - # * optionally {#message_length} ({Types::Int32}), if +#l?+ is +true+, - # * {#body} ({Types::String}). + # * {#flags} ({BinStruct::Int8}), + # * optionally {#message_length} ({BinStruct::Int32}), if +#l?+ is +true+, + # * {#body} ({BinStruct::String}). # @author Sylvain Daubert # @since 2.1.4 class FAST < TTLS - update_field :type, default: 43 + update_attr :type, default: 43 end end end diff --git a/lib/packetgen/header/eap/md5.rb b/lib/packetgen/header/eap/md5.rb index 88a0595..4a718cf 100644 --- a/lib/packetgen/header/eap/md5.rb +++ b/lib/packetgen/header/eap/md5.rb @@ -14,19 +14,19 @@ class EAP # @author Sylvain Daubert # @since 2.1.4 class MD5 < EAP - update_field :type, default: 4 - remove_field :body + update_attr :type, default: 4 + remove_attr :body # @!attribute value_size # @return [Integer] 8-bit value size - define_field :value_size, Types::Int8 + define_attr :value_size, BinStruct::Int8 # @!attribute value # @return [::String] - define_field :value, Types::String, - builder: ->(h, t) { t.new(length_from: h[:value_size]) } + define_attr :value, BinStruct::String, + builder: ->(h, t) { t.new(length_from: h[:value_size]) } # @!attribute optional_name # @return [::String] - define_field :optional_name, Types::String + define_attr :optional_name, BinStruct::String end end end diff --git a/lib/packetgen/header/eap/tls.rb b/lib/packetgen/header/eap/tls.rb index b970f5a..4a6f6cb 100644 --- a/lib/packetgen/header/eap/tls.rb +++ b/lib/packetgen/header/eap/tls.rb @@ -13,16 +13,16 @@ class EAP # {https://tools.ietf.org/html/rfc5216 RFC 5216} # # {EAP::TLS} has following fields: - # * {#flags} ({Types::Int8}), - # * optionally {#tls_length} ({Types::Int32}), if +#l?+ is +true+, - # * {#body} ({Types::String}). + # * {#flags} ({BinStruct::Int8}), + # * optionally {#tls_length} ({BinStruct::Int32}), if +#l?+ is +true+, + # * {#body} ({BinStruct::String}). # @author Sylvain Daubert # @since 2.1.4 class TLS < EAP - update_field :type, default: 13 + update_attr :type, default: 13 # @!attribute flags # @return [Integer] 8-bit flags - define_field_before :body, :flags, Types::Int8 + define_attr_before :body, :flags, BinStruct::Int8 # @!attribute l # Say if length field is included. Defined on {#flags} field. @@ -33,7 +33,7 @@ class TLS < EAP # @!attribute s # If set, this message is a TLS-Start. Defined on {#flags} field. # @return [Boolean] - define_bit_fields_on :flags, :l, :m, :s, :reserved, 5 + define_bit_attrs_on :flags, :l, :m, :s, :reserved, 5 alias length_present? l? alias more_fragments? m? alias tls_start? s? @@ -43,8 +43,8 @@ class TLS < EAP # TLS message or set of messages that is being fragmented. So, it # cannot be automatically calculated (no +#calc_length+ method). # @return [Integer] 32-bit TLS length - define_field_before :body, :tls_length, Types::Int32, - optional: ->(h) { h.l? } + define_attr_before :body, :tls_length, BinStruct::Int32, + optional: lambda(&:l?) # @return [String] def inspect diff --git a/lib/packetgen/header/eap/ttls.rb b/lib/packetgen/header/eap/ttls.rb index 95069ee..355a522 100644 --- a/lib/packetgen/header/eap/ttls.rb +++ b/lib/packetgen/header/eap/ttls.rb @@ -13,16 +13,16 @@ class EAP # {https://tools.ietf.org/html/rfc5281 RFC 5281} # # {EAP::TTLS} has following fields: - # * {#flags} ({Types::Int8}), - # * optionally {#message_length} ({Types::Int32}), if +#l?+ is +true+, - # * {#body} ({Types::String}). + # * {#flags} ({BinStruct::Int8}), + # * optionally {#message_length} ({BinStruct::Int32}), if +#l?+ is +true+, + # * {#body} ({BinStruct::String}). # @author Sylvain Daubert # @since 2.1.4 class TTLS < EAP - update_field :type, default: 21 + update_attr :type, default: 21 # @!attribute flags # @return [Integer] 8-bit flags - define_field_before :body, :flags, Types::Int8 + define_attr_before :body, :flags, BinStruct::Int8 # @!attribute l # Say if length field is included. Defined on {#flags} field. @@ -37,7 +37,7 @@ class TTLS < EAP # @return [Integer] 2-bit reserved integer # @!attribute version # @return [Integer] 3-bit version - define_bit_fields_on :flags, :l, :m, :s, :reserved, 2, :version, 3 + define_bit_attrs_on :flags, :l, :m, :s, :reserved, 2, :version, 3 alias length_present? l? alias more_fragments? m? alias tls_start? s? @@ -47,8 +47,8 @@ class TTLS < EAP # raw data message sequence prior to fragmentation. So, it # cannot be automatically calculated (no +#calc_length+ method). # @return [Integer] 32-bit message length - define_field_before :body, :message_length, Types::Int32, - optional: ->(h) { h.l? } + define_attr_before :body, :message_length, BinStruct::Int32, + optional: lambda(&:l?) # @return [String] def inspect diff --git a/lib/packetgen/header/eth.rb b/lib/packetgen/header/eth.rb index 66b589d..af9a318 100644 --- a/lib/packetgen/header/eth.rb +++ b/lib/packetgen/header/eth.rb @@ -11,8 +11,8 @@ module Header # An Ethernet header consists of: # * a destination MAC address ({MacAddr}), # * a source MAC address (MacAddr), - # * a {#ethertype} ({Types::Int16}), - # * and a body (a {Types::String} or another Header class). + # * a {#ethertype} ({BinStruct::Int16}), + # * and a body (a {BinStruct::String} or another Header class). # # == Create a Ethernet header # # standalone @@ -33,27 +33,27 @@ module Header class Eth < Base # Ethernet MAC address, as a group of 6 bytes # @author Sylvain Daubert - class MacAddr < Types::Fields - include Types::Fieldable + class MacAddr < BinStruct::Struct + include BinStruct::Structable # @!attribute a0 # @return [Integer] first byte from MacAddr - define_field :a0, Types::Int8 + define_attr :a0, BinStruct::Int8 # @!attribute a1 # @return [Integer] second byte from MacAddr - define_field :a1, Types::Int8 + define_attr :a1, BinStruct::Int8 # @!attribute a2 # @return [Integer] third byte from MacAddr - define_field :a2, Types::Int8 + define_attr :a2, BinStruct::Int8 # @!attribute a3 # @return [Integer] fourth byte from MacAddr - define_field :a3, Types::Int8 + define_attr :a3, BinStruct::Int8 # @!attribute a4 # @return [Integer] fifth byte from MacAddr - define_field :a4, Types::Int8 + define_attr :a4, BinStruct::Int8 # @!attribute a5 # @return [Integer] sixth byte from MacAddr - define_field :a5, Types::Int8 + define_attr :a5, BinStruct::Int8 # Read a human-readable string to populate +MacAddr+ # @param [String] str @@ -65,7 +65,7 @@ def from_human(str) raise ArgumentError, 'not a MAC address' unless bytes.size == 6 6.times do |i| - self[:"a#{i}"].read(bytes[i].to_i(16)) + self[:"a#{i}"].from_human(bytes[i].to_i(16)) end self end @@ -73,27 +73,27 @@ def from_human(str) # +MacAddr+ in human readable form (colon format) # @return [String] def to_human - fields.map { |m| '%02x' % self[m] }.join(':') + attributes.map { |m| '%02x' % self[m] }.join(':') end def ==(other) other.is_a?(self.class) && - fields.all? { |attr| self[attr].value == other[attr].value } + attributes.all? { |attr| self[attr].value == other[attr].value } end end # @!attribute dst # @return [MacAddr] Destination MAC address - define_field :dst, MacAddr, default: '00:00:00:00:00:00' + define_attr :dst, MacAddr, default: '00:00:00:00:00:00' # @!attribute src # @return [MacAddr] Source MAC address - define_field :src, MacAddr, default: '00:00:00:00:00:00' + define_attr :src, MacAddr, default: '00:00:00:00:00:00' # @!attribute ethertype # @return [Integer] 16-bit integer to determine payload type - define_field :ethertype, Types::Int16, default: 0 + define_attr :ethertype, BinStruct::Int16, default: 0 # @!attribute body - # @return [Types::String,Header::Base] - define_field :body, Types::String + # @return [BinStruct::String,Header::Base] + define_attr :body, BinStruct::String # send Eth packet on wire. # @param [String] iface interface name diff --git a/lib/packetgen/header/gre.rb b/lib/packetgen/header/gre.rb index d5c78cf..15dba61 100644 --- a/lib/packetgen/header/gre.rb +++ b/lib/packetgen/header/gre.rb @@ -26,7 +26,7 @@ class GRE < Base # IP protocol number for GRE IP_PROTOCOL = 47 - define_field :u16, Types::Int16 + define_attr :u16, BinStruct::Int16 # @!attribute c # @return [Boolean] @@ -38,26 +38,26 @@ class GRE < Base # @return [Integer] # @!attribute ver # @return [Integer] - define_bit_fields_on :u16, :c, :r, :k, :s, :reserved0, 9, :ver, 3 + define_bit_attrs_on :u16, :c, :r, :k, :s, :reserved0, 9, :ver, 3 # @!attribute protocol_type # @return [Integer] - define_field :protocol_type, Types::Int16 + define_attr :protocol_type, BinStruct::Int16 # @!attribute checksum # @return [Integer] - define_field :checksum, Types::Int16, default: 0, optional: ->(gre) { gre.c? } + define_attr :checksum, BinStruct::Int16, default: 0, optional: lambda(&:c?) # @!attribute reserved1 # @return [Integer] - define_field :reserved1, Types::Int16, default: 0, optional: ->(gre) { gre.c? } + define_attr :reserved1, BinStruct::Int16, default: 0, optional: lambda(&:c?) # @!attribute key # @return [Integer] - define_field :key, Types::Int32, optional: ->(gre) { gre.k? } + define_attr :key, BinStruct::Int32, optional: lambda(&:k?) # @!attribute sequence_number # @return [Integer] - define_field :sequence_number, Types::Int32, optional: ->(gre) { gre.s? } + define_attr :sequence_number, BinStruct::Int32, optional: lambda(&:s?) # @!attribute body - # @return [Types::String,Header::Base] - define_field :body, Types::String + # @return [BinStruct::String,Header::Base] + define_attr :body, BinStruct::String alias seqnum sequence_number alias seqnum= sequence_number= diff --git a/lib/packetgen/header/http/headers.rb b/lib/packetgen/header/http/headers.rb index 7b5f12d..0d5d833 100644 --- a/lib/packetgen/header/http/headers.rb +++ b/lib/packetgen/header/http/headers.rb @@ -13,7 +13,7 @@ module HTTP # @abstract Base class for HTTP headers. # @author Kent 'picat' Gruber class Headers - include Types::Fieldable + include BinStruct::Structable # Underlying Headers data (or nil). # @return [Hash, nil] diff --git a/lib/packetgen/header/http/request.rb b/lib/packetgen/header/http/request.rb index b81b212..a300316 100644 --- a/lib/packetgen/header/http/request.rb +++ b/lib/packetgen/header/http/request.rb @@ -10,9 +10,9 @@ module PacketGen module Header module HTTP # An HTTP/1.1 Request packet consists of: - # * the http verb ({Types::String}). - # * the path ({Types::String}). - # * the version ({Types::String}). + # * the http verb ({BinStruct::String}). + # * the path ({BinStruct::String}). + # * the version ({BinStruct::String}). # * associated http headers ({HTTP::Headers}). # # == Create a HTTP Request header @@ -38,22 +38,22 @@ module HTTP # @since 3.1.0 Rename +#method+ into {#verb} to not mask +Object#method+. class Request < Base # @!attribute verb - # @return [Types::String] + # @return [BinStruct::String] # @since 3.1.0 - define_field :verb, Types::String + define_attr :verb, BinStruct::String # @!attribute path - # @return [Types::String] - define_field :path, Types::String + # @return [BinStruct::String] + define_attr :path, BinStruct::String # @!attribute version - # @return [Types::String] - define_field :version, Types::String, default: 'HTTP/1.1' + # @return [BinStruct::String] + define_attr :version, BinStruct::String, default: 'HTTP/1.1' # @!attribute headers # associated http/1.1 headers # @return [HTTP::Headers] - define_field :headers, HTTP::Headers + define_attr :headers, HTTP::Headers # @!attribute body - # @return [Types::String] - define_field :body, Types::String + # @return [BinStruct::String] + define_attr :body, BinStruct::String # @param [Hash] options # @option options [String] :verb @@ -61,7 +61,7 @@ class Request < Base # @option options [String] :version # @option options [Hash] :headers def initialize(options={}) - super(options) + super self.headers ||= options[:headers] end diff --git a/lib/packetgen/header/http/response.rb b/lib/packetgen/header/http/response.rb index a68726b..81032f1 100644 --- a/lib/packetgen/header/http/response.rb +++ b/lib/packetgen/header/http/response.rb @@ -10,11 +10,11 @@ module PacketGen module Header module HTTP # An HTTP/1.1 Response packet consists of: - # * the version ({Types::String}). - # * the status code ({Types::String}). - # * the status message ({Types::String}). + # * the version ({BinStruct::String}). + # * the status code ({BinStruct::String}). + # * the status message ({BinStruct::String}). # * associated http headers ({HTTP::Headers}). - # * the actual http payload body ({Types::String}). + # * the actual http payload body ({BinStruct::String}). # # == Create a HTTP Response header # # standalone @@ -38,21 +38,21 @@ module HTTP # @author Kent 'picat' Gruber class Response < Base # @!attribute version - # @return [Types::String] - define_field :version, Types::String, default: 'HTTP/1.1' + # @return [BinStruct::String] + define_attr :version, BinStruct::String, default: 'HTTP/1.1' # @!attribute status_code - # @return [Types::String] - define_field :status_code, Types::String + # @return [BinStruct::String] + define_attr :status_code, BinStruct::String # @!attribute status_mesg - # @return [Types::String] - define_field :status_mesg, Types::String + # @return [BinStruct::String] + define_attr :status_mesg, BinStruct::String # @!attribute headers # associated http/1.1 headers - # @return [Types::String] - define_field :headers, HTTP::Headers + # @return [BinStruct::String] + define_attr :headers, HTTP::Headers # @!attribute body # @return [HTTP::PHeaders] - define_field :body, Types::String + define_attr :body, BinStruct::String # @param [Hash] options # @option options [String] :version @@ -61,7 +61,7 @@ class Response < Base # @option options [String] :body # @option options [Hash] :headers def initialize(options={}) - super(options) + super self.headers ||= options[:headers] end diff --git a/lib/packetgen/header/icmp.rb b/lib/packetgen/header/icmp.rb index 511bda1..add1172 100644 --- a/lib/packetgen/header/icmp.rb +++ b/lib/packetgen/header/icmp.rb @@ -15,9 +15,9 @@ module Header # | Type | Code | Checksum | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # A ICMP header consists of: - # * a {#type} field ({Types::Int8} type), - # * a {#code} field ({Types::Int8} type), - # * a {#checksum} field ({Types::Int16} type), + # * a {#type} field ({BinStruct::Int8} type), + # * a {#code} field ({BinStruct::Int8} type), + # * a {#checksum} field ({BinStruct::Int16} type), # * and a {#body}. # # == Create a ICMP header @@ -41,18 +41,18 @@ class ICMP < Base # @!attribute type # 8-bit ICMP type # @return [Integer] - define_field :type, Types::Int8 + define_attr :type, BinStruct::Int8 # @!attribute code # 8-bit ICMP code # @return [Integer] - define_field :code, Types::Int8 + define_attr :code, BinStruct::Int8 # @!attribute checksum # 16-bit ICMP checksum # @return [Integer] - define_field :checksum, Types::Int16 + define_attr :checksum, BinStruct::Int16 # @!attribute body - # @return [Types::String,Header::Base] - define_field :body, Types::String + # @return [BinStruct::String,Header::Base] + define_attr :body, BinStruct::String # Compute checksum and set +checksum+ field # @return [Integer] diff --git a/lib/packetgen/header/icmpv6.rb b/lib/packetgen/header/icmpv6.rb index b9c0514..65e5f62 100644 --- a/lib/packetgen/header/icmpv6.rb +++ b/lib/packetgen/header/icmpv6.rb @@ -15,9 +15,9 @@ module Header # | Type | Code | Checksum | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # A ICMPv6 header consists of: - # * a +type+ field ({Types::Int8} type), - # * a +code+ field ({Types::Int8} type), - # * a +checksum+ field ({Types::Int16} type), + # * a +type+ field ({BinStruct::Int8} type), + # * a +code+ field ({BinStruct::Int8} type), + # * a +checksum+ field ({BinStruct::Int16} type), # * and a +body+. # # == Create a ICMPv6 header diff --git a/lib/packetgen/header/igmp.rb b/lib/packetgen/header/igmp.rb index 09234fc..e4559d5 100644 --- a/lib/packetgen/header/igmp.rb +++ b/lib/packetgen/header/igmp.rb @@ -20,9 +20,9 @@ module Header # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # # A IGMP header consists of: - # * a {#type} field ({Types::Int8Enum} type), - # * a {#max_resp_time} field ({Types::Int8} type), - # * a {#checksum} field ({Types::Int16} type), + # * a {#type} field ({BinStruct::Int8Enum} type), + # * a {#max_resp_time} field ({BinStruct::Int8} type), + # * a {#checksum} field ({BinStruct::Int16} type), # * a {#group_addr} field ({Header::IP::Addr} type), # * and a {#body} (unused for IGMPv2). # @@ -56,22 +56,22 @@ class IGMP < Base # @!attribute type # 8-bit IGMP Type # @return [Integer] - define_field :type, Types::Int8Enum, enum: TYPES + define_attr :type, BinStruct::Int8Enum, enum: TYPES # @!attribute max_resp_time # 8-bit IGMP Max Response Time # @return [Integer] - define_field :max_resp_time, Types::Int8 + define_attr :max_resp_time, BinStruct::Int8 # @!attribute checksum # 16-bit IGMP Checksum # @return [Integer] - define_field :checksum, Types::Int16 + define_attr :checksum, BinStruct::Int16 # @!attribute group_addr # IP Group address # @return [IP::Addr] - define_field :group_addr, IP::Addr, default: '0.0.0.0' + define_attr :group_addr, IP::Addr, default: '0.0.0.0' # @!attribute body # @return [String,Base] - define_field :body, Types::String + define_attr :body, BinStruct::String # @api private # @note This method is used internally by PacketGen and should not be diff --git a/lib/packetgen/header/igmpv3.rb b/lib/packetgen/header/igmpv3.rb index 5661045..0db5833 100644 --- a/lib/packetgen/header/igmpv3.rb +++ b/lib/packetgen/header/igmpv3.rb @@ -18,12 +18,12 @@ module Header # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # # A IGMP header consists of: - # * a {#type} field ({Types::Int8Enum} type), - # * a {#max_resp_time} field ({Types::Int8} type), - # * a {#checksum} field ({Types::Int16} type), + # * a {#type} field ({BinStruct::Int8Enum} type), + # * a {#max_resp_time} field ({BinStruct::Int8} type), + # * a {#checksum} field ({BinStruct::Int16} type), # * and a {#body}, containing more fields (see below). # - # A IGMPv3 header may have additionnal fields. These fields are handled by + # A IGMPv3 header may have additionnal fields. These attributes.are handled by # additional headers (see {IGMPv3::MQ}). # # == Create a IGMPv3 header @@ -50,14 +50,14 @@ module Header # igmp.max_resp_code #=> 9728 error due to encoding as a floating point value # # === IGMPv3 Membership Query - # With IGMPv3, a Membership Query packet has more fields than with IGMPv2. To + # With IGMPv3, a Membership Query packet has more attributes.than with IGMPv2. To # handle those fields, an additional header should be used: # pkt = PacketGen.gen('IP').add('IGMPv3', type: 'MembershipQuery').add('IGMPv3::MQ') # pkt.igmpv3 #=> PacketGen::Header::IGMPv3 # pkt.igmpv3_mq #=> PacketGen::Header::IGMPv3::MQ # # === IGMPv3 Membership Report - # With IGMPv3, a Membership Report packet has more fields than with IGMPv2. To + # With IGMPv3, a Membership Report packet has more attributes.than with IGMPv2. To # handle those fields, an additional header should be used: # pkt = PacketGen.gen('IP').add('IGMPv3', type: 'MembershipQuery').add('IGMPv3::MR') # pkt.igmpv3 #=> PacketGen::Header::IGMPv3 @@ -71,7 +71,7 @@ class IGMPv3 < IGMP 'MembershipReport' => 0x22, }.freeze - remove_field :group_addr + remove_attr :group_addr # Encode value for IGMPv3 Max Resp Code and QQIC. # Value may be encoded as a float, so some error may occur. diff --git a/lib/packetgen/header/igmpv3/group_record.rb b/lib/packetgen/header/igmpv3/group_record.rb index 0e73e71..4638d48 100644 --- a/lib/packetgen/header/igmpv3/group_record.rb +++ b/lib/packetgen/header/igmpv3/group_record.rb @@ -11,7 +11,7 @@ module Header class IGMPv3 # Class to handle IGMPv3 Group Records. # - # A Group Record is a block of fields containing information + # A Group Record is a block of attributes.containing information # pertaining to the sender's membership in a single multicast group on # the interface from which the Report is sent. # @@ -40,8 +40,8 @@ class IGMPv3 # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # @author Sylvain Daubert - class GroupRecord < Types::Fields - include Types::Fieldable + class GroupRecord < BinStruct::Struct + include BinStruct::Structable # Known record types RECORD_TYPES = { @@ -56,29 +56,29 @@ class GroupRecord < Types::Fields # @!attribute type # 8-bit record type # @return [Integer] - define_field :type, Types::Int8Enum, enum: RECORD_TYPES + define_attr :type, BinStruct::Int8Enum, enum: RECORD_TYPES # @!attribute aux_data_len # 8-bit length of of the Auxiliary Data field ({#aux_data}), in unit of # 32-bit words # @return [Integer] - define_field :aux_data_len, Types::Int8, default: 0 + define_attr :aux_data_len, BinStruct::Int8, default: 0 # @!attribute number_of_sources # 16-bit Number of source addresses in {#source_addr} # @return [Integer] - define_field :number_of_sources, Types::Int16, default: 0 + define_attr :number_of_sources, BinStruct::Int16, default: 0 # @!attribute multicast_addr # IP multicast address to which this Group Record pertains # @return [IP::Addr] - define_field :multicast_addr, IP::Addr, default: '0.0.0.0' + define_attr :multicast_addr, IP::Addr, default: '0.0.0.0' # @!attribute source_addr # Array of source addresses # @return [IP::ArrayOfAddr] - define_field :source_addr, IP::ArrayOfAddr, - builder: ->(h, t) { t.new(counter: h[:number_of_sources]) } + define_attr :source_addr, IP::ArrayOfAddr, + builder: ->(h, t) { t.new(counter: h[:number_of_sources]) } # @!attribute aux_data # @return [String] - define_field :aux_data, Types::String, - builder: ->(h, t) { t.new(length_from: -> { h[:aux_data_len].to_i * 4 }) } + define_attr :aux_data, BinStruct::String, + builder: ->(h, t) { t.new(length_from: -> { h[:aux_data_len].to_i * 4 }) } def human_type self[:type].to_human @@ -91,7 +91,7 @@ def to_human # Class to handle series of {GroupRecord}. # @author Sylvain Daubert - class GroupRecords < Types::Array + class GroupRecords < BinStruct::Array set_of GroupRecord # Separator used in {#to_human}. diff --git a/lib/packetgen/header/igmpv3/mq.rb b/lib/packetgen/header/igmpv3/mq.rb index 8c04387..8d8d7ef 100644 --- a/lib/packetgen/header/igmpv3/mq.rb +++ b/lib/packetgen/header/igmpv3/mq.rb @@ -31,7 +31,7 @@ class IGMPv3 # | Source Address [N] | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # - # Fields are: + # Struct are: # * 32-bit {#group_addr} field ({Header::IP::Addr} type), # * 4-bit {#resv}, a reserved field, # * 1-bit {#flag_s} (Suppress Router-Side Processing), @@ -44,25 +44,25 @@ class MQ < Base # @!attribute group_addr # IP Group address # @return [IP::Addr] - define_field :group_addr, IP::Addr, default: '0.0.0.0' + define_attr :group_addr, IP::Addr, default: '0.0.0.0' # @!attribute u8 # First 8-bit field, composed of {#resv}, {#flag_s} and {#qrv} # @return [Integer] - define_field :u8, Types::Int8 + define_attr :u8, BinStruct::Int8 # @!attribute qqic # 8-bit QQIC # @return [Integer,Float] - define_field :qqic, Types::Int8 + define_attr :qqic, BinStruct::Int8 # @!attribute number_of_sources # 16-bit Number of Sources in {#source_addr} # @return [Integer] - define_field :number_of_sources, Types::Int16 + define_attr :number_of_sources, BinStruct::Int16 # @!attribute source_addr # Array of IP source addresses # @return [IP::ArrayOfAddr] - define_field :source_addr, IP::ArrayOfAddr, - builder: ->(h, t) { t.new(counter: h[:number_of_sources]) } + define_attr :source_addr, IP::ArrayOfAddr, + builder: ->(h, t) { t.new(counter: h[:number_of_sources]) } # @!attribute resv # 4-bit reserved field in @@ -73,7 +73,7 @@ class MQ < Base # @!attribute qrv # 3-bit Querier's Robustness Variable # @return [Integer] - define_bit_fields_on :u8, :resv, 4, :flag_s, :qrv, 3 + define_bit_attrs_on :u8, :resv, 4, :flag_s, :qrv, 3 undef qqic, qqic= diff --git a/lib/packetgen/header/igmpv3/mr.rb b/lib/packetgen/header/igmpv3/mr.rb index a2b2b4e..ed577e8 100644 --- a/lib/packetgen/header/igmpv3/mr.rb +++ b/lib/packetgen/header/igmpv3/mr.rb @@ -49,17 +49,17 @@ class MR < Base # @!attribute reserved # 16-bit reserved field # @return [Integer] - define_field :reserved, Types::Int16, default: 0 + define_attr :reserved, BinStruct::Int16, default: 0 # @!attribute number_of_gr # 16-bit Number of group records in {#group_records} # @return [Integer] - define_field :number_of_gr, Types::Int16, default: 0 + define_attr :number_of_gr, BinStruct::Int16, default: 0 # @!attribute group_records # Array of group records # @return [GroupRecords] - define_field :group_records, GroupRecords, - builder: ->(h, t) { t.new(counter: h[:number_of_gr]) } + define_attr :group_records, GroupRecords, + builder: ->(h, t) { t.new(counter: h[:number_of_gr]) } end end diff --git a/lib/packetgen/header/ip.rb b/lib/packetgen/header/ip.rb index 100b2e5..3ef4fe0 100644 --- a/lib/packetgen/header/ip.rb +++ b/lib/packetgen/header/ip.rb @@ -27,11 +27,11 @@ module Header # | Options | Padding | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # A IP header consists of: - # * a first byte ({#u8} of {Types::Int8} type) composed of: + # * a first byte ({#u8} of {BinStruct::Int8} type) composed of: # * a 4-bit {#version} field, # * a 4-bit IP header length ({#ihl}) field, - # * a Type of Service field ({#tos}, {Types::Int8} type), - # * a total length ({#length}, {Types::Int16} type), + # * a Type of Service field ({#tos}, {BinStruct::Int8} type), + # * a total length ({#length}, {BinStruct::Int16} type), # * a ID ({#id}, +Int16+ type), # * a {#frag} worg (+Int16+) composed of: # * 3 1-bit flags ({#flag_rsv}, {#flag_df} and {#flag_mf}), @@ -42,7 +42,7 @@ module Header # * a source IP address ({#src}, {Addr} type), # * a destination IP address ({#dst}, +Addr+ type), # * an optional {#options} field ({Options} type), - # * and a {#body} ({Types::String} type). + # * and a {#body} ({BinStruct::String} type). # # == Create a IP header # # standalone @@ -100,48 +100,48 @@ class IP # @!attribute u8 # First byte of IP header. May be accessed through {#version} and {#ihl}. # @return [Integer] first byte of IP header. - define_field :u8, Types::Int8, default: 0x45 + define_attr :u8, BinStruct::Int8, default: 0x45 # @!attribute tos # @return [Integer] 8-bit Type of Service self[attr] - define_field :tos, Types::Int8, default: 0 + define_attr :tos, BinStruct::Int8, default: 0 # @!attribute length # @return [Integer] 16-bit IP total length - define_field :length, Types::Int16, default: 20 + define_attr :length, BinStruct::Int16, default: 20 # @!attribute id # @return [Integer] 16-bit ID - define_field :id, Types::Int16, default: ->(_) { rand(65_535) } + define_attr :id, BinStruct::Int16, default: ->(_) { rand(65_535) } # @!attribute frag # @return [Integer] 16-bit frag word - define_field :frag, Types::Int16, default: 0 + define_attr :frag, BinStruct::Int16, default: 0 # @!attribute ttl # @return [Integer] 8-bit Time To Live self[attr] - define_field :ttl, Types::Int8, default: 64 + define_attr :ttl, BinStruct::Int8, default: 64 # @!attribute protocol # @return [Integer] 8-bit upper protocol self[attr] - define_field :protocol, Types::Int8 + define_attr :protocol, BinStruct::Int8 # @!attribute checksum # @return [Integer] 16-bit IP header checksum - define_field :checksum, Types::Int16, default: 0 + define_attr :checksum, BinStruct::Int16, default: 0 # @!attribute src # @return [Addr] source IP address - define_field :src, Addr, default: '127.0.0.1' + define_attr :src, Addr, default: '127.0.0.1' # @!attribute dst # @return [Addr] destination IP address - define_field :dst, Addr, default: '127.0.0.1' + define_attr :dst, Addr, default: '127.0.0.1' # @!attribute options # @since 2.2.0 - # @return [Types::String] - define_field :options, Options, optional: ->(h) { h.ihl > 5 }, - builder: ->(h, t) { t.new(length_from: -> { (h.ihl - 5) * 4 }) } + # @return [BinStruct::String] + define_attr :options, Options, optional: ->(h) { h.ihl > 5 }, + builder: ->(h, t) { t.new(length_from: -> { (h.ihl - 5) * 4 }) } # @!attribute body - # @return [Types::String,Header::Base] - define_field :body, Types::String + # @return [BinStruct::String,Header::Base] + define_attr :body, BinStruct::String # @!attribute version # @return [Integer] 4-bit version attribute # @!attribute ihl # @return [Integer] 4-bit IP header length attribute - define_bit_fields_on :u8, :version, 4, :ihl, 4 + define_bit_attrs_on :u8, :version, 4, :ihl, 4 # @!attribute flag_rsv # @return [Boolean] reserved bit from flags @@ -151,7 +151,7 @@ class IP # @return [Boolean] More Fragment flags # @!attribute fragment_offset # @return [Integer] 13-bit fragment offset - define_bit_fields_on :frag, :flag_rsv, :flag_df, :flag_mf, :fragment_offset, 13 + define_bit_attrs_on :frag, :flag_rsv, :flag_df, :flag_mf, :fragment_offset, 13 # Helper method to compute sum of 16-bit words. Used to compute IP-style # checksums. @@ -216,7 +216,7 @@ def pseudo_header_checksum # Send IP packet on wire. # - # When sending packet at IP level, +checksum+ and +length+ fields are set by + # When sending packet at IP level, +checksum+ and +length+ attributes.are set by # kernel, so bad IP packets cannot be sent this way. To do so, use {Eth#to_w}. # @param [String,nil] _iface interface name. Not used # @return [void] diff --git a/lib/packetgen/header/ip/addr.rb b/lib/packetgen/header/ip/addr.rb index cf9d460..9496b56 100644 --- a/lib/packetgen/header/ip/addr.rb +++ b/lib/packetgen/header/ip/addr.rb @@ -11,21 +11,21 @@ module Header class IP # IP address, as a group of 4 bytes # @author Sylvain Daubert - class Addr < Types::Fields - include Types::Fieldable + class Addr < BinStruct::Struct + include BinStruct::Structable # @!attribute a1 # @return [Integer] IP address first byte - define_field :a1, Types::Int8 + define_attr :a1, BinStruct::Int8 # @!attribute a2 # @return [Integer] IP address seconf byte - define_field :a2, Types::Int8 + define_attr :a2, BinStruct::Int8 # @!attribute a3 # @return [Integer] IP address third byte - define_field :a3, Types::Int8 + define_attr :a3, BinStruct::Int8 # @!attribute a4 # @return [Integer] IP address fourth byte - define_field :a4, Types::Int8 + define_attr :a4, BinStruct::Int8 IPV4_ADDR_REGEX = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.freeze @@ -37,10 +37,10 @@ def from_human(str) m = str.match(IPV4_ADDR_REGEX) if m - self[:a1].read m[1].to_i - self[:a2].read m[2].to_i - self[:a3].read m[3].to_i - self[:a4].read m[4].to_i + self[:a1].from_human(m[1].to_i) + self[:a2].from_human(m[2].to_i) + self[:a3].from_human(m[3].to_i) + self[:a4].from_human(m[4].to_i) end self end @@ -48,7 +48,7 @@ def from_human(str) # Addr in human readable form (dotted format) # @return [String] def to_human - fields.map { |f| self[f].to_i.to_s }.join('.') + attributes.map { |f| self[f].to_i.to_s }.join('.') end # Addr as an integer @@ -66,7 +66,7 @@ def mcast? def ==(other) other.is_a?(self.class) && - fields.all? { |attr| self[attr].value == other[attr].value } + attributes.all? { |attr| self[attr].value == other[attr].value } end end end diff --git a/lib/packetgen/header/ip/option.rb b/lib/packetgen/header/ip/option.rb index 636ca62..9146e3f 100644 --- a/lib/packetgen/header/ip/option.rb +++ b/lib/packetgen/header/ip/option.rb @@ -11,7 +11,7 @@ module Header class IP # Class to handle series of IP addresses # @author Sylvain Daubert - class ArrayOfAddr < Types::Array + class ArrayOfAddr < BinStruct::Array set_of IP::Addr # Push a IP address to the array @@ -20,14 +20,14 @@ class ArrayOfAddr < Types::Array # array << '192.168.1.12' def push(addr) addr = Addr.new.from_human(addr) unless addr.is_a?(Addr) - super(addr) + super end end # Base class for IP options # @author Sylvain Daubert - class Option < Types::Fields - include Types::Fieldable + class Option < BinStruct::Struct + include BinStruct::Structable # EOL option type EOL_TYPE = 0x00 @@ -47,16 +47,16 @@ class Option < Types::Fields # @!attribute type # 8-bit option type # @return [Integer] - define_field :type, Types::Int8 + define_attr :type, BinStruct::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 } + define_attr :length, BinStruct::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 }) } + define_attr :data, BinStruct::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 @@ -68,7 +68,7 @@ class Option < Types::Fields # !@attribute number # 5-bit option number from {#type} field # @return [Integer] - define_bit_fields_on :type, :copied, :option_class, 2, :number, 5 + define_bit_attrs_on :type, :copied, :option_class, 2, :number, 5 # @return [Hash] def self.types @@ -133,7 +133,7 @@ def initialize_length_if_needed(options) end def initialize_data_if_needed(options) - return unless fields.include?(:data) && self[:data].respond_to?(:from_human) && options.key?(:data) + return unless attributes.include?(:data) && self[:data].respond_to?(:from_human) && options.key?(:data) # Force data if data is set in options but not length self.length += options[:data].size @@ -143,8 +143,8 @@ def initialize_data_if_needed(options) # End-of-option-List IP option class EOL < Option - remove_field :length - remove_field :data + remove_attr :length + remove_attr :data end # No OPeration IP option @@ -152,16 +152,16 @@ class NOP < EOL; end # Loose Source and Record Route IP option class LSRR < Option - remove_field :data + remove_attr :data # @!attribute pointer # 8-bit pointer on next address # @return [Integer] - define_field :pointer, Types::Int8, default: 4 + define_attr :pointer, BinStruct::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 }) } + # @return [BinStruct::Array] + define_attr :data, ArrayOfAddr, builder: ->(h, t) { t.new(length_from: -> { h.length - 3 }) } # Get IP address pointer by {#pointer} # @return [Addr] @@ -185,12 +185,12 @@ class RR < LSRR; end # Stream Identifier IP option class SI < Option - remove_field :data + remove_attr :data # @!attribute id # 16-bit stream ID # @return [Integer] - define_field :id, Types::Int16 + define_attr :id, BinStruct::Int16 def to_human super << ":#{self.id}" @@ -199,12 +199,12 @@ def to_human # Router Alert IP option class RA < Option - remove_field :data + remove_attr :data # @!attribute value # 16-bit value. Should be 0. # @return [Integer] - define_field :value, Types::Int16, default: 0 + define_attr :value, BinStruct::Int16, default: 0 def to_human super << ":#{self.value}" diff --git a/lib/packetgen/header/ip/options.rb b/lib/packetgen/header/ip/options.rb index e3c4399..b4293c4 100644 --- a/lib/packetgen/header/ip/options.rb +++ b/lib/packetgen/header/ip/options.rb @@ -11,7 +11,7 @@ module Header class IP # Class to handle IP options # @author Sylvain Daubert - class Options < Types::Array + class Options < BinStruct::Array set_of Option HUMAN_SEPARATOR = ';' diff --git a/lib/packetgen/header/ipv6.rb b/lib/packetgen/header/ipv6.rb index d22d5b5..d1182e1 100644 --- a/lib/packetgen/header/ipv6.rb +++ b/lib/packetgen/header/ipv6.rb @@ -37,16 +37,16 @@ module Header # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # # A IPv6 header consists of: - # * a first 32-bit word ({#u32}, of {Types::Int32} type) composed of: + # * a first 32-bit word ({#u32}, of {BinStruct::Int32} type) composed of: # * a 4-bit {#version} field, # * a 8-bit {#traffic_class} field, # * a 20-bit {#flow_label} field, - # * a payload length field ({#length}, {Types::Int16} type}), - # * a next header field ({#next}, {Types::Int8} type), + # * a payload length field ({#length}, {BinStruct::Int16} type}), + # * a next header field ({#next}, {BinStruct::Int8} type), # * a hop-limit field ({#hop}, +Int8+ type), # * a source address field ({#src}, {IPv6::Addr} type), # * a destination address field ({#dst}, +IPv6::Addr+ type), - # * and a {#body} ({Types::String} type). + # * and a {#body} ({BinStruct::String} type). # # == Create a IPv6 header # # standalone @@ -95,30 +95,30 @@ class IPv6 # @!attribute u32 # First 32-bit word of IPv6 header # @return [Integer] - define_field :u32, Types::Int32, default: 0x6000_0000 + define_attr :u32, BinStruct::Int32, default: 0x6000_0000 # @!attribute length # 16-bit word of IPv6 payload length # @return [Integer] - define_field :length, Types::Int16 + define_attr :length, BinStruct::Int16 # @!attribute next # 8-bit IPv6 next payload value # @return [Integer] - define_field :next, Types::Int8 + define_attr :next, BinStruct::Int8 # @!attribute hop # 8-bit IPv6 hop limit # @return [Integer] - define_field :hop, Types::Int8, default: 64 + define_attr :hop, BinStruct::Int8, default: 64 # @!attribute src # IPv6 source address # @return [Addr] - define_field :src, Addr, default: '::1' + define_attr :src, Addr, default: '::1' # @!attribute dst # IPv6 destination address # @return [Addr] - define_field :dst, Addr, default: '::1' + define_attr :dst, Addr, default: '::1' # @!attribute body - # @return [Types::String,Header::Base] - define_field :body, Types::String + # @return [BinStruct::String,Header::Base] + define_attr :body, BinStruct::String # @!attribute version # @return [Integer] 4-bit version attribute @@ -126,7 +126,7 @@ class IPv6 # @return [Integer] 8-bit traffic_class attribute # @!attribute flow_label # @return [Integer] 20-bit flow_label attribute - define_bit_fields_on :u32, :version, 4, :traffic_class, 8, :flow_label, 20 + define_bit_attrs_on :u32, :version, 4, :traffic_class, 8, :flow_label, 20 # Compute length and set +len+ field # @return [Integer] @@ -143,7 +143,7 @@ def pseudo_header_checksum sum end - # Send IPv6 packet on wire. All fields may be set (even {#version}). + # Send IPv6 packet on wire. All attributes.may be set (even {#version}). # @param [String] _iface interface name (not used) # @return [void] # @since 3.0.0 no more limitations on +flow_label+, +length+ and +src+ fields. diff --git a/lib/packetgen/header/ipv6/addr.rb b/lib/packetgen/header/ipv6/addr.rb index 735099f..61c05a0 100644 --- a/lib/packetgen/header/ipv6/addr.rb +++ b/lib/packetgen/header/ipv6/addr.rb @@ -14,41 +14,41 @@ module Header class IPv6 # IPv6 address, as a group of 8 2-byte words # @author Sylvain Daubert - class Addr < Types::Fields - include Types::Fieldable + class Addr < BinStruct::Struct + include BinStruct::Structable # @!attribute a1 # 1st 2-byte word of IPv6 address # @return [Integer] - define_field :a1, Types::Int16 + define_attr :a1, BinStruct::Int16 # @!attribute a2 # 2nd 2-byte word of IPv6 address # @return [Integer] - define_field :a2, Types::Int16 + define_attr :a2, BinStruct::Int16 # @!attribute a3 # 3rd 2-byte word of IPv6 address # @return [Integer] - define_field :a3, Types::Int16 + define_attr :a3, BinStruct::Int16 # @!attribute a4 # 4th 2-byte word of IPv6 address # @return [Integer] - define_field :a4, Types::Int16 + define_attr :a4, BinStruct::Int16 # @!attribute a5 # 5th 2-byte word of IPv6 address # @return [Integer] - define_field :a5, Types::Int16 + define_attr :a5, BinStruct::Int16 # @!attribute a6 # 6th 2-byte word of IPv6 address # @return [Integer] - define_field :a6, Types::Int16 + define_attr :a6, BinStruct::Int16 # @!attribute a7 # 7th 2-byte word of IPv6 address # @return [Integer] - define_field :a7, Types::Int16 + define_attr :a7, BinStruct::Int16 # @!attribute a8 # 8th 2-byte word of IPv6 address # @return [Integer] - define_field :a8, Types::Int16 + define_attr :a8, BinStruct::Int16 # rubocop:disable Metrics/AbcSize @@ -83,7 +83,7 @@ def to_human # Return an array of address 16-bit words # @return [Array] def to_a - @fields.values + @attributes.values end # Return true if this address is a multicast one @@ -94,13 +94,13 @@ def mcast? def ==(other) other.is_a?(self.class) && - fields.all? { |attr| self[attr].value == other[attr].value } + attributes.all? { |attr| self[attr].value == other[attr].value } end end # Class to handle series of IPv6 addresses # @author Sylvain Daubert - class ArrayOfAddr < Types::Array + class ArrayOfAddr < BinStruct::Array set_of IPv6::Addr # Push a IPv6 address to the array @@ -109,7 +109,7 @@ class ArrayOfAddr < Types::Array # array << '2001:1234::125' def push(addr) addr = Addr.new.from_human(addr) unless addr.is_a?(Addr) - super(addr) + super end end end diff --git a/lib/packetgen/header/ipv6/extension.rb b/lib/packetgen/header/ipv6/extension.rb index 9cdda4f..775b8f2 100644 --- a/lib/packetgen/header/ipv6/extension.rb +++ b/lib/packetgen/header/ipv6/extension.rb @@ -25,29 +25,29 @@ class IPv6 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # # Such a header consists of: - # * a {#next} header field ({Types::Int8}), - # * a {#length} field ({Types::Int8}), - # * an {#options} field ({Types::String}), + # * a {#next} header field ({BinStruct::Int8}), + # * a {#length} field ({BinStruct::Int8}), + # * an {#options} field ({BinStruct::String}), # * and a {#body}, containing next header. # @author Sylvain Daubert class Extension < Base # @!attribute next # 8-bit Next header field # @return [Integer] - define_field :next, Types::Int8 + define_attr :next, BinStruct::Int8 # @!attribute length # 8-bit extension length, in 8-octets units, not including the # first 8 octets. # @return [Integer] - define_field :length, Types::Int8 + define_attr :length, BinStruct::Int8 # @!attribute options # Specific options of extension header # @return [String] - define_field :options, Types::String, - builder: ->(h, t) { t.new(length_from: -> { h.real_length }) } + define_attr :options, BinStruct::String, + builder: ->(h, t) { t.new(length_from: -> { h.real_length }) } # @!attribute body # @return [String,Base] - define_field :body, Types::String + define_attr :body, BinStruct::String # Get real extension header length # @return [Integer] diff --git a/lib/packetgen/header/ipv6/hop_by_hop.rb b/lib/packetgen/header/ipv6/hop_by_hop.rb index 171afba..869b4ff 100644 --- a/lib/packetgen/header/ipv6/hop_by_hop.rb +++ b/lib/packetgen/header/ipv6/hop_by_hop.rb @@ -11,10 +11,10 @@ module Header class IPv6 # @!parse # # Option for {HopByHop} IPv6 extension header. - # # @since 3.1.0 subclass of {Types::AbstractTLV} + # # @since 3.1.0 subclass of {BinStruct::AbstractTLV} # class Option (h, t) { t.new(length_from: -> { h.real_length - 2 }) } + define_attr_before :body, :options, Options, builder: ->(h, t) { t.new(length_from: -> { h.real_length - 2 }) } end end diff --git a/lib/packetgen/header/llc.rb b/lib/packetgen/header/llc.rb index 8c16a7d..be74355 100644 --- a/lib/packetgen/header/llc.rb +++ b/lib/packetgen/header/llc.rb @@ -12,25 +12,25 @@ module Header # Logical-Link Control header # # A LLC header consists of: - # * a {#dsap} ({Types::Int8}), - # * a {#ssap} ({Types::Int8}), - # * a {#control} ({Types::Int8}), - # * and a {#body} (a {Types::String} or another {Base} class). + # * a {#dsap} ({BinStruct::Int8}), + # * a {#ssap} ({BinStruct::Int8}), + # * a {#control} ({BinStruct::Int8}), + # * and a {#body} (a {BinStruct::String} or another {Base} class). # @author Sylvain Daubert # @since 1.4.0 class LLC < Base # @!attribute dsap # @return [Integer] 8-bit dsap value - define_field :dsap, Types::Int8 + define_attr :dsap, BinStruct::Int8 # @!attribute ssap # @return [Integer] 8-bit ssap value - define_field :ssap, Types::Int8 + define_attr :ssap, BinStruct::Int8 # @!attribute control # @return [Integer] 8-bit control value - define_field :control, Types::Int8 + define_attr :control, BinStruct::Int8 # @!attribute body - # @return [Types::String,Header::Base] - define_field :body, Types::String + # @return [BinStruct::String,Header::Base] + define_attr :body, BinStruct::String end self.add_class LLC Dot11::Data.bind LLC, type: 2, wep?: false @@ -38,21 +38,21 @@ class LLC < Base # Sub-Network Access Protocol # # A SNAP header consists of: - # * a {#oui} ({Types::OUI}), - # * a {#proto_id} ({Types::Int16}), - # * and a {#body} (a {Types::String} or another {Base} class). + # * a {#oui} ({BinStruct::OUI}), + # * a {#proto_id} ({BinStruct::Int16}), + # * and a {#body} (a {BinStruct::String} or another {Base} class). # @author Sylvain Daubert # @since 1.4.0 class SNAP < Base # @!attribute oui - # @return [Types::OUI] - define_field :oui, Types::OUI + # @return [BinStruct::OUI] + define_attr :oui, BinStruct::OUI # @!attribute proto_id # @return [Integer] 16-bit protocol id - define_field :proto_id, Types::Int16 + define_attr :proto_id, BinStruct::Int16 # @!attribute body - # @return [Types::String,Header::Base] - define_field :body, Types::String + # @return [BinStruct::String,Header::Base] + define_attr :body, BinStruct::String end self.add_class SNAP LLC.bind SNAP, dsap: 170, ssap: 170, control: 3 diff --git a/lib/packetgen/header/mld.rb b/lib/packetgen/header/mld.rb index 5ef57da..7e7eef7 100644 --- a/lib/packetgen/header/mld.rb +++ b/lib/packetgen/header/mld.rb @@ -26,8 +26,8 @@ module Header # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # # A MLD header consists of: - # * a {#max_resp_delay} field ({Types::Int16} type), - # * a {#reserved} field ({Types::Int16} type), + # * a {#max_resp_delay} field ({BinStruct::Int16} type), + # * a {#reserved} field ({BinStruct::Int16} type), # * a {#mcast_addr} field ({Header::IPv6::Addr} type), # * and a {#body} (unused for MLDv1). # @@ -49,20 +49,20 @@ class MLD < Base # @!attribute max_resp_delay # 16-bit MLD Max Response Delay # @return [Integer] - define_field :max_resp_delay, Types::Int16 + define_attr :max_resp_delay, BinStruct::Int16 alias max_resp_code max_resp_delay alias max_resp_code= max_resp_delay= # @!attribute reserved # 16-bit Reserved field # @return [Integer] - define_field :reserved, Types::Int16 + define_attr :reserved, BinStruct::Int16 # @!attribute mcast_addr # IPv6 Multicast address # @return [IPv6::Addr] - define_field :mcast_addr, IPv6::Addr, default: '::' + define_attr :mcast_addr, IPv6::Addr, default: '::' # @!attribute body # @return [String,Base] - define_field :body, Types::String + define_attr :body, BinStruct::String # @api private # @note This method is used internally by PacketGen and should not be diff --git a/lib/packetgen/header/mldv2/mcast_address_record.rb b/lib/packetgen/header/mldv2/mcast_address_record.rb index 5fc604e..636f7d4 100644 --- a/lib/packetgen/header/mldv2/mcast_address_record.rb +++ b/lib/packetgen/header/mldv2/mcast_address_record.rb @@ -52,8 +52,8 @@ module MLDv2 # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # @author Sylvain Daubert - class McastAddressRecord < Types::Fields - include Types::Fieldable + class McastAddressRecord < BinStruct::Struct + include BinStruct::Structable # Known record types RECORD_TYPES = IGMPv3::GroupRecord::RECORD_TYPES @@ -61,29 +61,29 @@ class McastAddressRecord < Types::Fields # @!attribute type # 8-bit record type # @return [Integer] - define_field :type, Types::Int8Enum, enum: RECORD_TYPES + define_attr :type, BinStruct::Int8Enum, enum: RECORD_TYPES # @!attribute aux_data_len # 8-bit length of of the Auxiliary Data field ({#aux_data}), in unit of # 32-bit words # @return [Integer] - define_field :aux_data_len, Types::Int8, default: 0 + define_attr :aux_data_len, BinStruct::Int8, default: 0 # @!attribute number_of_sources # 16-bit Number of source addresses in {#source_addr} # @return [Integer] - define_field :number_of_sources, Types::Int16, default: 0 + define_attr :number_of_sources, BinStruct::Int16, default: 0 # @!attribute multicast_addr # IP multicast address to which this Multicast Address Record pertains # @return [IPv6::Addr] - define_field :multicast_addr, IPv6::Addr, default: '::' + define_attr :multicast_addr, IPv6::Addr, default: '::' # @!attribute source_addr # Array of source addresses # @return [IPv6::ArrayOfAddr] - define_field :source_addr, IPv6::ArrayOfAddr, - builder: ->(h, t) { t.new(counter: h[:number_of_sources]) } + define_attr :source_addr, IPv6::ArrayOfAddr, + builder: ->(h, t) { t.new(counter: h[:number_of_sources]) } # @!attribute aux_data # @return [String] - define_field :aux_data, Types::String, - builder: ->(h, t) { t.new(length_from: -> { h[:aux_data_len].to_i * 4 }) } + define_attr :aux_data, BinStruct::String, + builder: ->(h, t) { t.new(length_from: -> { h[:aux_data_len].to_i * 4 }) } def human_type self[:type].to_human @@ -96,7 +96,7 @@ def to_human # Class to handle series of {McastAddressRecord}. # @author Sylvain Daubert - class McastAddressRecords < Types::Array + class McastAddressRecords < BinStruct::Array set_of McastAddressRecord # Separator used in {#to_human}. diff --git a/lib/packetgen/header/mldv2/mlq.rb b/lib/packetgen/header/mldv2/mlq.rb index 211ebef..71ab52c 100644 --- a/lib/packetgen/header/mldv2/mlq.rb +++ b/lib/packetgen/header/mldv2/mlq.rb @@ -57,18 +57,18 @@ module MLDv2 # * * # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - # +type+, +code+ and +checksum+ are fields from {ICMPv6} header. + # +type+, +code+ and +checksum+ are attributes.from {ICMPv6} header. # - # MLQ fields are: - # * {#max_resp_code #max_resp_code} ({Types::Int16}), - # * {#reserved #reserved} ({Types::Int16}), + # MLQ attributes.are: + # * {#max_resp_code #max_resp_code} ({BinStruct::Int16}), + # * {#reserved #reserved} ({BinStruct::Int16}), # * {#mcast_addr #mcast_addr} ({IPv6::Addr}), - # * {#flags} ({Types::Int8}), with sub-fields: + # * {#flags} ({BinStruct::Int8}), with sub-fields: # * a 4-bit {#flag_resv} field, # * a 1-bit {#flag_s} boolean, # * a 3-bit {#flag_qrv} field, - # * {#qqic} ({Types::Int8}), - # * {#number_of_sources} ({Types::Int16}), + # * {#qqic} ({BinStruct::Int8}), + # * {#number_of_sources} ({BinStruct::Int16}), # * and {#source_addr}, a {IPv6::ArrayOfAddr}. # # == Max Resp Delay @@ -80,20 +80,20 @@ class MLQ < MLD # @!attribute flags # 8-bit flags # @return [Integer] - define_field_before :body, :flags, Types::Int8 + define_attr_before :body, :flags, BinStruct::Int8 # @!attribute qqic # 8-bit QQIC # @return [Integer] - define_field_before :body, :qqic, Types::Int8 + define_attr_before :body, :qqic, BinStruct::Int8 # @!attribute number_of_sources # 16-bit number of sources # @return [Integer] - define_field_before :body, :number_of_sources, Types::Int16 + define_attr_before :body, :number_of_sources, BinStruct::Int16 # @!attribute source_addr # Array of IPv6 source addresses # @return [IPv6::ArrayOfAddr] - define_field_before :body, :source_addr, IPv6::ArrayOfAddr, - builder: ->(h, t) { t.new(counter: h[:number_of_sources]) } + define_attr_before :body, :source_addr, IPv6::ArrayOfAddr, + builder: ->(h, t) { t.new(counter: h[:number_of_sources]) } # @!attribute flag_resv # 4-bit reserved field in {#flags} @@ -104,7 +104,7 @@ class MLQ < MLD # @!attribute flag_qrv # 3-bit QRV (Querier's Robustness Variable) # @return [Integer] - define_bit_fields_on :flags, :flag_resv, 4, :flag_s, :flag_qrv, 3 + define_bit_attrs_on :flags, :flag_resv, 4, :flag_s, :flag_qrv, 3 # Getter for +max_resp_code+ for MLDv2 packets. Use {MLDv2.decode}. # @return [Integer] diff --git a/lib/packetgen/header/mldv2/mlr.rb b/lib/packetgen/header/mldv2/mlr.rb index 131a2f9..067f288 100644 --- a/lib/packetgen/header/mldv2/mlr.rb +++ b/lib/packetgen/header/mldv2/mlr.rb @@ -38,28 +38,28 @@ module MLDv2 # . . # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - # +type+, +code+ and +checksum+ are fields from {ICMPv6} header. + # +type+, +code+ and +checksum+ are attributes.from {ICMPv6} header. # - # MLR fields are: - # * {#reserved} ({Types::Int16}), - # * {#number_of_mar} (number of mcast address records, {Types::Int16}), + # MLR attributes.are: + # * {#reserved} ({BinStruct::Int16}), + # * {#number_of_mar} (number of mcast address records, {BinStruct::Int16}), # * {#records} ({McastAddressRecords}). # @author Sylvain Daubert class MLR < Base # @!attribute reserved # 16-bit reserved field # @return [Integer] - define_field :reserved, Types::Int16, default: 0 + define_attr :reserved, BinStruct::Int16, default: 0 # @!attribute number_of_mar # 16-bit Number of group records in {#records} # @return [Integer] - define_field :number_of_mar, Types::Int16, default: 0 + define_attr :number_of_mar, BinStruct::Int16, default: 0 # @!attribute records # Array of Mcast Address Records # @return [McastAddressRecords] - define_field :records, McastAddressRecords, - builder: ->(h, t) { t.new(counter: h[:number_of_mar]) } + define_attr :records, McastAddressRecords, + builder: ->(h, t) { t.new(counter: h[:number_of_mar]) } end end diff --git a/lib/packetgen/header/ospfv2.rb b/lib/packetgen/header/ospfv2.rb index 5860938..9fcd5eb 100644 --- a/lib/packetgen/header/ospfv2.rb +++ b/lib/packetgen/header/ospfv2.rb @@ -28,15 +28,15 @@ module Header # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # # An OSPFv2 header consists of: - # * a {#version} field ({Types::Int8}), - # * a {#type} field ({Types::Int8Enum}), - # * a {#length} field ({Types::Int16}). The length includes the header, - # * a {#router_id} field ({Types::Int32}), - # * an {#area_id} field ({Types::Int32}), - # * a {#checksum} field ({Types::Int16}), - # * an {#au_type} field ({Types::Int16Enum}), - # * an {#authentication} field ({Types::Int64}), - # * and a {#body} ({Types::String}). + # * a {#version} field ({BinStruct::Int8}), + # * a {#type} field ({BinStruct::Int8Enum}), + # * a {#length} field ({BinStruct::Int16}). The length includes the header, + # * a {#router_id} field ({BinStruct::Int32}), + # * an {#area_id} field ({BinStruct::Int32}), + # * a {#checksum} field ({BinStruct::Int16}), + # * an {#au_type} field ({BinStruct::Int16Enum}), + # * an {#authentication} field ({BinStruct::Int64}), + # * and a {#body} ({BinStruct::String}). # # == Create an OSPFv2 header # # standalone @@ -94,38 +94,38 @@ class OSPFv2 < Base # @!attribute version # 8-bit OSPF version # @return [Integer] - define_field :version, Types::Int8, default: 2 + define_attr :version, BinStruct::Int8, default: 2 # @!attribute type # 8-bit OSPF packet type. Types are defined in {TYPES}. # @return [Integer] - define_field :type, Types::Int8Enum, enum: TYPES + define_attr :type, BinStruct::Int8Enum, enum: TYPES # @!attribute length # 16-bit OSPF packet length # @return [Integer] - define_field :length, Types::Int16 + define_attr :length, BinStruct::Int16 # @!attribute router_id # 32-bit router ID # @return [Integer] - define_field :router_id, Types::Int32 + define_attr :router_id, BinStruct::Int32 # @!attribute area_id # 32-bit area ID # @return [Integer] - define_field :area_id, Types::Int32 + define_attr :area_id, BinStruct::Int32 # @!attribute checksum # 16-bit OSPF packet checksum # @return [Integer] - define_field :checksum, Types::Int16 + define_attr :checksum, BinStruct::Int16 # @!attribute au_type # 16-bit authentication type. Types are defined in {AU_TYPES}. # @return [Integer] - define_field :au_type, Types::Int16Enum, enum: AU_TYPES + define_attr :au_type, BinStruct::Int16Enum, enum: AU_TYPES # @!attribute authentication # 64-bit authentication data # @return [Integer] - define_field :authentication, Types::Int64 + define_attr :authentication, BinStruct::Int64 # @!attribute body # @return [String,Base] - define_field :body, Types::String + define_attr :body, BinStruct::String # @api private # Helper class method to define an OSPFv2 options field. @@ -158,9 +158,9 @@ class OSPFv2 < Base # @!attribute mt_opt # @return [Boolean] def self.define_options(hdr) - hdr.define_field :options, Types::Int8 - hdr.define_bit_fields_on :options, :dn_opt, :o_opt, :dc_opt, :l_opt, - :n_opt, :mc_opt, :e_opt, :mt_opt + hdr.define_attr :options, BinStruct::Int8 + hdr.define_bit_attrs_on :options, :dn_opt, :o_opt, :dc_opt, :l_opt, + :n_opt, :mc_opt, :e_opt, :mt_opt end # @api private diff --git a/lib/packetgen/header/ospfv2/db_description.rb b/lib/packetgen/header/ospfv2/db_description.rb index ce7d575..b98a4a3 100644 --- a/lib/packetgen/header/ospfv2/db_description.rb +++ b/lib/packetgen/header/ospfv2/db_description.rb @@ -31,13 +31,13 @@ class OSPFv2 # | ... | # # A DB description payload is composed of: - # * a 16-bit {#mtu} field ({Types::Int16}), - # * a 8-bit {#options} field ({Types::Int8}), - # * a 8-bit {#flags} field ({Types::Int8}). Supported flags are: + # * a 16-bit {#mtu} field ({BinStruct::Int16}), + # * a 8-bit {#options} field ({BinStruct::Int8}), + # * a 8-bit {#flags} field ({BinStruct::Int8}). Supported flags are: # * {i_flag}, # * {m_flag}, # * {ms_flag}, - # * a 32-bit {#sequence_number} field ({Types::Int32}), + # * a 32-bit {#sequence_number} field ({BinStruct::Int32}), # * and an array of {LSAHeader LSAHeaders} ({#lsas}, {ArrayOfLSA}). # # == Create a DbDescription payload @@ -64,7 +64,7 @@ class DbDescription < Base # @!attribute mtu # 16-bit interface MTU # @return [Integer] - define_field :mtu, Types::Int16 + define_attr :mtu, BinStruct::Int16 # @!macro define_options OSPFv2.define_options(self) @@ -72,7 +72,7 @@ class DbDescription < Base # @!attribute flags # 8-bit interface flags ({#i_flag}, {#m_flag} and {#ms_flag}) # @return [Integer] - define_field :flags, Types::Int8 + define_attr :flags, BinStruct::Int8 # @!attribute i_flag # Init bit # @return [Boolean] @@ -82,20 +82,20 @@ class DbDescription < Base # @!attribute ms_flag # Master/Slave bit # @return [Boolean] - define_bit_fields_on :flags, :zero, 5, :i_flag, :m_flag, :ms_flag + define_bit_attrs_on :flags, :zero, 5, :i_flag, :m_flag, :ms_flag # @!attribute sequence_number # 32-bit DD sequence number, used to sequence the collection of Database # Description Packets. # @return [Integer] - define_field :sequence_number, Types::Int32 + define_attr :sequence_number, BinStruct::Int32 alias seqnum sequence_number alias seqnum= sequence_number= # @!attribute lsas # Array of LSA headers # @return [ArrayOfLSAHeader] - define_field :lsas, ArrayOfLSA, builder: ->(_h, t) { t.new(only_headers: true) } + define_attr :lsas, ArrayOfLSA, builder: ->(_h, t) { t.new(only_headers: true) } end end diff --git a/lib/packetgen/header/ospfv2/hello.rb b/lib/packetgen/header/ospfv2/hello.rb index b24fc74..3466223 100644 --- a/lib/packetgen/header/ospfv2/hello.rb +++ b/lib/packetgen/header/ospfv2/hello.rb @@ -29,10 +29,10 @@ class OSPFv2 # | ... | # A HELLO payload consists of: # * a {#network_mask} field ({IP::Addr}), - # * a {#hello_interval} field ({Types::Int16}), - # * an {#options} field ({Types::Int8}), - # * a {#priority} field ({Types::Int8}), - # * a {#dead_interval} field ({Types::Int32}), + # * a {#hello_interval} field ({BinStruct::Int16}), + # * an {#options} field ({BinStruct::Int8}), + # * a {#priority} field ({BinStruct::Int8}), + # * a {#dead_interval} field ({BinStruct::Int32}), # * a {#designated_router} field ({IP::Addr}), # * a {#backup_designated_router} field ({IP::Addr}), # * a {#neighbors} array containing neighbors as {IP::Addr}. @@ -63,11 +63,11 @@ class Hello < Base # @!attribute network_mask # The network mask associated with this interface. # @return [String] - define_field :network_mask, IP::Addr + define_attr :network_mask, IP::Addr # @!attribute hello_interval # The number of seconds between this router's Hello packets. # @return [Integer] - define_field :hello_interval, Types::Int16 + define_attr :hello_interval, BinStruct::Int16 # @!macro define_options OSPFv2.define_options(self) @@ -76,25 +76,25 @@ class Hello < Base # This router's Router Priority. Used in (Backup) Designated # Router election. # @return [Integer] - define_field :priority, Types::Int8 + define_attr :priority, BinStruct::Int8 # @!attribute dead_interval # The number of seconds before declaring a silent router down. # @return [Integer] - define_field :dead_interval, Types::Int32 + define_attr :dead_interval, BinStruct::Int32 # @!attribute designated_router # The identity of the Designated Router for this network, in the # view of the sending router. # @return [String] - define_field :designated_router, IP::Addr + define_attr :designated_router, IP::Addr # @!attribute backup_designated_router # The identity of the Backup Designated Router for this network, # in the view of the sending router. # @return [String] - define_field :backup_designated_router, IP::Addr + define_attr :backup_designated_router, IP::Addr # @!attribute neighbors # Array of neighbors # @return [IP::ArrayOfAddr] - define_field :neighbors, IP::ArrayOfAddr + define_attr :neighbors, IP::ArrayOfAddr end end diff --git a/lib/packetgen/header/ospfv2/ls_ack.rb b/lib/packetgen/header/ospfv2/ls_ack.rb index a2b7cae..025158b 100644 --- a/lib/packetgen/header/ospfv2/ls_ack.rb +++ b/lib/packetgen/header/ospfv2/ls_ack.rb @@ -45,7 +45,7 @@ class LSAck < Base # @!attribute lsas # Array of LSA headers # @return [ArrayOfLSA] - define_field :lsas, ArrayOfLSA, builder: ->(_h, t) { t.new(only_headers: true) } + define_attr :lsas, ArrayOfLSA, builder: ->(_h, t) { t.new(only_headers: true) } end end diff --git a/lib/packetgen/header/ospfv2/ls_request.rb b/lib/packetgen/header/ospfv2/ls_request.rb index 7c06626..77926b1 100644 --- a/lib/packetgen/header/ospfv2/ls_request.rb +++ b/lib/packetgen/header/ospfv2/ls_request.rb @@ -9,27 +9,27 @@ module PacketGen module Header class OSPFv2 - # This class handle a LS request, which is composed 3 {Types::Int32} fields: + # This class handle a LS request, which is composed 3 {BinStruct::Int32} fields: # * {#type}, # * {#link_state_id}, # * and {#advertising_router}. # @author Sylvain Daubert - class LSR < Types::Fields - include Types::Fieldable + class LSR < BinStruct::Struct + include BinStruct::Structable # @!attribute type # The type of the LSA to request. # @return [Integer] - define_field :type, Types::Int32Enum, enum: LSAHeader::TYPES + define_attr :type, BinStruct::Int32Enum, enum: LSAHeader::TYPES # @!attribute link_state_id # This field identifies the portion of the internet environment # that is being described by the LSA to request. # @return [String] - define_field :link_state_id, IP::Addr + define_attr :link_state_id, IP::Addr # @!attribute advertising_router # The Router ID of the requested LSA. # @return [String] - define_field :advertising_router, IP::Addr + define_attr :advertising_router, IP::Addr # Get human-readable type # @return [String] @@ -43,10 +43,10 @@ def to_human end end - # This class defines a specialized {Types::Array array} to handle series + # This class defines a specialized {BinStruct::Array array} to handle series # of {LSR LSRs}. # @author Sylvain Daubert - class ArrayOfLSR < Types::Array + class ArrayOfLSR < BinStruct::Array set_of LSR end @@ -82,7 +82,7 @@ class LSRequest < Base # @!attribute lsrs # Array of {LSR} # @return [ArrayOfLSR] - define_field :lsrs, ArrayOfLSR + define_attr :lsrs, ArrayOfLSR end end diff --git a/lib/packetgen/header/ospfv2/ls_update.rb b/lib/packetgen/header/ospfv2/ls_update.rb index 4937a52..89b30d5 100644 --- a/lib/packetgen/header/ospfv2/ls_update.rb +++ b/lib/packetgen/header/ospfv2/ls_update.rb @@ -22,7 +22,7 @@ class OSPFv2 # +- +-+ # | ... | # This paylod is implemented with two fields: - # * {#lsas_count}, a {Types::Int32} field, + # * {#lsas_count}, a {BinStruct::Int32} field, # * and {#lsas}, an {ArrayOfLSA} object. # # == Create a LSUpdate payload @@ -47,11 +47,11 @@ class LSUpdate < Base # @!attribute lsas_count # Count of LSAs included in this update # @return [Integer] - define_field :lsas_count, Types::Int32 + define_attr :lsas_count, BinStruct::Int32 # @!attribute lsas # Array of {LSA LSAs} # @return [ArrayOfLSA] - define_field :lsas, ArrayOfLSA, builder: ->(h, t) { t.new(counter: h[:lsas_count]) } + define_attr :lsas, ArrayOfLSA, builder: ->(h, t) { t.new(counter: h[:lsas_count]) } # Calculate checksums of all LSAs # @return [void] diff --git a/lib/packetgen/header/ospfv2/lsa.rb b/lib/packetgen/header/ospfv2/lsa.rb index 0248a1d..942fdec 100644 --- a/lib/packetgen/header/ospfv2/lsa.rb +++ b/lib/packetgen/header/ospfv2/lsa.rb @@ -16,28 +16,28 @@ class LSA < LSAHeader # @!attribute body # LSA body # @return [String] - define_field :body, Types::String, - builder: ->(h, t) { t.new(length_from: -> { h.length - 20 }) } + define_attr :body, BinStruct::String, + builder: ->(h, t) { t.new(length_from: -> { h.length - 20 }) } end # This class handles TOS metrics for {Link links} in a {LSARouter # LSA router payload}. # @author Sylvain Daubert - class TosMetric < Types::Fields - include Types::Fieldable + class TosMetric < BinStruct::Struct + include BinStruct::Structable # @!attribute tos # 8-bit IP Type of Service that this metric refers to. # @return [Integer] - define_field :tos, Types::Int8 + define_attr :tos, BinStruct::Int8 # @!attribute reserved # 8-bit reserved field. # @return [Integer] - define_field :reserved, Types::Int8, default: 0 + define_attr :reserved, BinStruct::Int8, default: 0 # @!attribute tos_metric # 16-bit TOS-specific metric information.. # @return [Integer] - define_field :tos_metric, Types::Int16 + define_attr :tos_metric, BinStruct::Int16 # @return [String] def to_human @@ -45,37 +45,37 @@ def to_human end end - # This class defines a specialized {Types::Array array} to handle series + # This class defines a specialized {BinStruct::Array array} to handle series # of {TosMetric TOS metrics}. # @author Sylvain Daubert - class ArrayOfTosMetric < Types::Array + class ArrayOfTosMetric < BinStruct::Array set_of TosMetric end # This class handles links in a {LSARouter LSA router payload}. # @author Sylvain Daubert - class Link < Types::Fields - include Types::Fieldable + class Link < BinStruct::Struct + include BinStruct::Structable # @!attribute id # @return [IP::Addr] - define_field :id, IP::Addr + define_attr :id, IP::Addr # @!attribute data # @return [IP::Addr] - define_field :data, IP::Addr + define_attr :data, IP::Addr # @!attribute type # @return [Integer] - define_field :type, Types::Int8 + define_attr :type, BinStruct::Int8 # @!attribute tos_count # @return [Integer] - define_field :tos_count, Types::Int8 + define_attr :tos_count, BinStruct::Int8 # @!attribute metric # @return [Integer] - define_field :metric, Types::Int16 + define_attr :metric, BinStruct::Int16 # @!attribute tos # Additionnal TOS metrics # @return [ArrayOfTosMetric] - define_field :tos, ArrayOfTosMetric, builder: ->(h, t) { t.new(counter: h[:tos_count]) } + define_attr :tos, ArrayOfTosMetric, builder: ->(h, t) { t.new(counter: h[:tos_count]) } # @return [String] def to_human @@ -83,10 +83,10 @@ def to_human end end - # This class defines a specialized {Types::Array array} to handle series + # This class defines a specialized {BinStruct::Array array} to handle series # of {Link Links}. # @author Sylvain Daubert - class ArrayOfLink < Types::Array + class ArrayOfLink < BinStruct::Array set_of Link end @@ -94,22 +94,22 @@ class ArrayOfLink < Types::Array # # A LSA router payload is composed of: # * a header (see methods inherited from {LSAHeader}), - # * a 16-bit flag word {#u16} ({Types::Int16}), - # * a 16-bit {#link_count} field ({Types::Int16}), + # * a 16-bit flag word {#u16} ({BinStruct::Int16}), + # * a 16-bit {#link_count} field ({BinStruct::Int16}), # * an array of {#links} ({ArrayOfLink}). # @author Sylvain Daubert class LSARouter < LSAHeader # @attribute u16 # 16-bit flag word # @return [Integer] - define_field :u16, Types::Int16 + define_attr :u16, BinStruct::Int16 # @attribute link_count # Number of links # @return [Integer] - define_field :link_count, Types::Int16 + define_attr :link_count, BinStruct::Int16 # @attribute links # @return [ArrayOfLink] - define_field :links, ArrayOfLink, builder: ->(h, t) { t.new(counter: h[:link_count]) } + define_attr :links, ArrayOfLink, builder: ->(h, t) { t.new(counter: h[:link_count]) } # @attribute v_flag # @return [Boolean] @@ -117,7 +117,7 @@ class LSARouter < LSAHeader # @return [Boolean] # @attribute b_flag # @return [Boolean] - define_bit_fields_on :u16, :z, 5, :v_flag, :e_flag, :b_flag, :zz, 8 + define_bit_attrs_on :u16, :z, 5, :v_flag, :e_flag, :b_flag, :zz, 8 end # This class handles LSA Network payloads. @@ -130,37 +130,37 @@ class LSARouter < LSAHeader class LSANetwork < LSAHeader # @!attribute netmask # @return [IP::Addr] - define_field :netmask, IP::Addr + define_attr :netmask, IP::Addr # @!attribute routers # List of routers in network # @return [IP::ArrayOfAddr] - define_field :routers, IP::ArrayOfAddr, - builder: ->(h, t) { t.new(length_from: -> { h.length - 24 }) } + define_attr :routers, IP::ArrayOfAddr, + builder: ->(h, t) { t.new(length_from: -> { h.length - 24 }) } end # This class handles external links in {LSAASExternal LSA AS-External payloads}. # @author Sylvain Daubert - class External < Types::Fields - include Types::Fieldable + class External < BinStruct::Struct + include BinStruct::Structable # @!attribute u8 # @return [Integer] - define_field :u8, Types::Int8 + define_attr :u8, BinStruct::Int8 # @!attribute metric # @return [Integer] - define_field :metric, Types::Int24 + define_attr :metric, BinStruct::Int24 # @!attribute forwarding_addr # @return [IP::Addr] - define_field :forwarding_addr, IP::Addr + define_attr :forwarding_addr, IP::Addr # @!attribute ext_route_tag # @return [Integer] - define_field :ext_route_tag, Types::Int32 + define_attr :ext_route_tag, BinStruct::Int32 # @!attribute e_flag # @return [Boolean] # @!attribute tos # @return [Integer] - define_bit_fields_on :u8, :e_flag, :tos, 7 + define_bit_attrs_on :u8, :e_flag, :tos, 7 # @return [String] def to_human @@ -168,10 +168,10 @@ def to_human end end - # This class defines a specialized {Types::Array array} to handle series + # This class defines a specialized {BinStruct::Array array} to handle series # of {External Externals}. # @author Sylvain Daubert - class ArrayOfExternal < Types::Array + class ArrayOfExternal < BinStruct::Array set_of External end @@ -185,22 +185,22 @@ class ArrayOfExternal < Types::Array class LSAASExternal < LSAHeader # @!attribute netmask # @return [IP::Addr] - define_field :netmask, IP::Addr + define_attr :netmask, IP::Addr # @!attribute externals # List of external destinations # @return [ArrayOfExternal] - define_field :externals, ArrayOfExternal, - builder: ->(h, t) { t.new(length_from: -> { h.length - 24 }) } + define_attr :externals, ArrayOfExternal, + builder: ->(h, t) { t.new(length_from: -> { h.length - 24 }) } end - # This class defines a specialized {Types::Array array} to handle series + # This class defines a specialized {BinStruct::Array array} to handle series # of {LSA LSAs}. It recognizes known LSA types and infers correct type. # @author Sylvain Daubert - class ArrayOfLSA < Types::Array + class ArrayOfLSA < BinStruct::Array set_of LSAHeader # @param [Hash] options - # @option options [Types::Int] counter Int object used as a counter for this set + # @option options [BinStruct::Int] counter Int object used as a counter for this set # @option options [Boolean] only_headers if +true+, only {LSAHeader LSAHeaders} # will be added to this array. def initialize(options={}) diff --git a/lib/packetgen/header/ospfv2/lsa_header.rb b/lib/packetgen/header/ospfv2/lsa_header.rb index 61d595b..b9d6236 100644 --- a/lib/packetgen/header/ospfv2/lsa_header.rb +++ b/lib/packetgen/header/ospfv2/lsa_header.rb @@ -29,8 +29,8 @@ class OSPFv2 # LSA headers are used as-is in {DbDescription} payload. But this class # is also a base class for different LSA class, as {LSARouter}. # @author Sylvain Daubert - class LSAHeader < Types::Fields - include Types::Fieldable + class LSAHeader < BinStruct::Struct + include BinStruct::Structable # LSA Types TYPES = { @@ -44,36 +44,36 @@ class LSAHeader < Types::Fields # @!attribute age # The time in seconds since the LSA was originated. # @return [Integer] - define_field :age, Types::Int16 + define_attr :age, BinStruct::Int16 # @!macro define_options OSPFv2.define_options(self) # @!attribute type # The type of the LSA. # @return [Integer] - define_field :type, Types::Int8Enum, enum: TYPES + define_attr :type, BinStruct::Int8Enum, enum: TYPES # @!attribute link_state_id # This field identifies the portion of the internet environment # that is being described by the LSA. # @return [String] - define_field :link_state_id, IP::Addr + define_attr :link_state_id, IP::Addr # @!attribute advertising_router # The Router ID of the router that originated the LSA. # @return [String] - define_field :advertising_router, IP::Addr + define_attr :advertising_router, IP::Addr # @!attribute sequence_number # @return [Integer] - define_field :sequence_number, Types::Int32 + define_attr :sequence_number, BinStruct::Int32 alias seqnum sequence_number alias seqnum= sequence_number= # @!attribute checksum # The Fletcher checksum of the complete contents of the LSA, # including the LSA header but excluding the LS age field. # @return [Integer] - define_field :checksum, Types::Int16 + define_attr :checksum, BinStruct::Int16 # @!attribute length # Length of the LSA, including the header. # @return [Integer] - define_field :length, Types::Int16 + define_attr :length, BinStruct::Int16 # Compute and set Fletcher-16 checksum on LSA # @return [Integer] diff --git a/lib/packetgen/header/ospfv3.rb b/lib/packetgen/header/ospfv3.rb index b7e09aa..0930765 100644 --- a/lib/packetgen/header/ospfv3.rb +++ b/lib/packetgen/header/ospfv3.rb @@ -24,15 +24,15 @@ module Header # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # # An OSPFv3 header consists of: - # * a {#version} field ({Types::Int8}), - # * a {#type} field ({Types::Int8Enum}), - # * a {#length} field ({Types::Int16}). The length includes the header, - # * a {#router_id} field ({Types::Int32}), - # * an {#area_id} field ({Types::Int32}), - # * a {#checksum} field ({Types::Int16}), - # * an {#instance_id} field ({Types::Int8}), - # * a {#reserved} field ({Types::Int8}), - # * and a {#body} ({Types::String}). + # * a {#version} field ({BinStruct::Int8}), + # * a {#type} field ({BinStruct::Int8Enum}), + # * a {#length} field ({BinStruct::Int16}). The length includes the header, + # * a {#router_id} field ({BinStruct::Int32}), + # * an {#area_id} field ({BinStruct::Int32}), + # * a {#checksum} field ({BinStruct::Int16}), + # * an {#instance_id} field ({BinStruct::Int8}), + # * a {#reserved} field ({BinStruct::Int8}), + # * and a {#body} ({BinStruct::String}). # # == Create an OSPFv3 header # # standalone @@ -74,38 +74,38 @@ class OSPFv3 < Base # @!attribute version # 8-bit OSPF version # @return [Integer] - define_field :version, Types::Int8, default: 3 + define_attr :version, BinStruct::Int8, default: 3 # @!attribute type # 8-bit OSPF packet type. Types are defined in {TYPES}. # @return [Integer] - define_field :type, Types::Int8Enum, enum: TYPES + define_attr :type, BinStruct::Int8Enum, enum: TYPES # @!attribute length # 16-bit OSPF packet length # @return [Integer] - define_field :length, Types::Int16 + define_attr :length, BinStruct::Int16 # @!attribute router_id # 32-bit router ID # @return [Integer] - define_field :router_id, Types::Int32 + define_attr :router_id, BinStruct::Int32 # @!attribute area_id # 32-bit area ID # @return [Integer] - define_field :area_id, Types::Int32 + define_attr :area_id, BinStruct::Int32 # @!attribute checksum # 16-bit OSPF packet checksum # @return [Integer] - define_field :checksum, Types::Int16 + define_attr :checksum, BinStruct::Int16 # @!attribute instance_id # 8-bit instance ID. # @return [Integer] - define_field :instance_id, Types::Int8 + define_attr :instance_id, BinStruct::Int8 # @!attribute reserved # 8-bit reserved field. # @return [Integer] - define_field :reserved, Types::Int8, default: 0 + define_attr :reserved, BinStruct::Int8, default: 0 # @!attribute body # @return [String,Base] - define_field :body, Types::String + define_attr :body, BinStruct::String # @api private # Helper class method to define an OSPFv3 options field. @@ -136,9 +136,9 @@ class OSPFv3 < Base # routing calculations. # @return [Boolean] def self.define_options(hdr) - hdr.define_field :options, Types::Int24 - hdr.define_bit_fields_on :options, :z, 18, :dc_opt, :r_opt, - :n_opt, :x_opt, :e_opt, :v6_opt + hdr.define_attr :options, BinStruct::Int24 + hdr.define_bit_attrs_on :options, :z, 18, :dc_opt, :r_opt, + :n_opt, :x_opt, :e_opt, :v6_opt end # @api private diff --git a/lib/packetgen/header/ospfv3/db_description.rb b/lib/packetgen/header/ospfv3/db_description.rb index a5dd44e..2835db4 100644 --- a/lib/packetgen/header/ospfv3/db_description.rb +++ b/lib/packetgen/header/ospfv3/db_description.rb @@ -33,14 +33,14 @@ class OSPFv3 # | ... | # # A DB description payload is composed of: - # * a 8-bit {#reserved} field ({Types::Int8}), - # * a 24-bit {#options} field ({Types::Int24}), - # * a 16-bit {#mtu} field ({Types::Int16}), - # * a 16-bit {#flags} field ({Types::Int16}). Supported flags are: + # * a 8-bit {#reserved} field ({BinStruct::Int8}), + # * a 24-bit {#options} field ({BinStruct::Int24}), + # * a 16-bit {#mtu} field ({BinStruct::Int16}), + # * a 16-bit {#flags} field ({BinStruct::Int16}). Supported flags are: # * {i_flag}, # * {m_flag}, # * {ms_flag}, - # * a 32-bit {#sequence_number} field ({Types::Int32}), + # * a 32-bit {#sequence_number} field ({BinStruct::Int32}), # * and an array of {LSAHeader LSAHeaders} ({#lsas}, {ArrayOfLSA}). # # == Create a DbDescription payload @@ -68,7 +68,7 @@ class DbDescription < Base # @!attribute reserved # 8-bit zero field before {#options} one # @return [Integer] - define_field :reserved, Types::Int8, default: 0 + define_attr :reserved, BinStruct::Int8, default: 0 # @!macro define_options OSPFv3.define_options(self) @@ -76,11 +76,11 @@ class DbDescription < Base # @!attribute mtu # 16-bit interface MTU # @return [Integer] - define_field :mtu, Types::Int16 + define_attr :mtu, BinStruct::Int16 # @!attribute flags # 16-bit interface flags ({#i_flag}, {#m_flag} and {#ms_flag}) # @return [Integer] - define_field :flags, Types::Int16 + define_attr :flags, BinStruct::Int16 # @!attribute i_flag # Init bit from {#flags} field # @return [Boolean] @@ -90,20 +90,20 @@ class DbDescription < Base # @!attribute ms_flag # Master/Slave bit from {#flags} field # @return [Boolean] - define_bit_fields_on :flags, :zz, 13, :i_flag, :m_flag, :ms_flag + define_bit_attrs_on :flags, :zz, 13, :i_flag, :m_flag, :ms_flag # @!attribute sequence_number # 32-bit DD sequence number, used to sequence the collection of Database # Description Packets. # @return [Integer] - define_field :sequence_number, Types::Int32 + define_attr :sequence_number, BinStruct::Int32 alias seqnum sequence_number alias seqnum= sequence_number= # @!attribute lsas # Array of LSA headers # @return [ArrayOfLSAHeader] - define_field :lsas, ArrayOfLSA, builder: ->(_h, t) { t.new(only_headers: true) } + define_attr :lsas, ArrayOfLSA, builder: ->(_h, t) { t.new(only_headers: true) } end end diff --git a/lib/packetgen/header/ospfv3/hello.rb b/lib/packetgen/header/ospfv3/hello.rb index 7933bc6..00cabbc 100644 --- a/lib/packetgen/header/ospfv3/hello.rb +++ b/lib/packetgen/header/ospfv3/hello.rb @@ -28,11 +28,11 @@ class OSPFv3 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | ... | # A HELLO payload consists of: - # * a {#interface_id} field ({Types::Int32}), - # * a {#priority} field ({Types::Int8}), - # * an {#options} field ({Types::Int24}), - # * a {#hello_interval} field ({Types::Int16}), - # * a {#dead_interval} field ({Types::Int16}), + # * a {#interface_id} field ({BinStruct::Int32}), + # * a {#priority} field ({BinStruct::Int8}), + # * an {#options} field ({BinStruct::Int24}), + # * a {#hello_interval} field ({BinStruct::Int16}), + # * a {#dead_interval} field ({BinStruct::Int16}), # * a {#designated_router} field ({IP::Addr}), # * a {#backup_designated_router} field ({IP::Addr}), # * a {#neighbors} array containing neighbors as {IP::Addr}. @@ -65,36 +65,36 @@ class Hello < Base # @!attribute interface_id # The network mask associated with this interface. # @return [String] - define_field :interface_id, Types::Int32 + define_attr :interface_id, BinStruct::Int32 # @!attribute priority # This router's Router Priority. Used in (Backup) Designated # Router election. # @return [Integer] - define_field :priority, Types::Int8 + define_attr :priority, BinStruct::Int8 # @!macro define_ospfv3_options OSPFv3.define_options(self) # @!attribute hello_interval # The number of seconds between this router's Hello packets. # @return [Integer] - define_field :hello_interval, Types::Int16 + define_attr :hello_interval, BinStruct::Int16 # @!attribute dead_interval # The number of seconds before declaring a silent router down. # @return [Integer] - define_field :dead_interval, Types::Int16 + define_attr :dead_interval, BinStruct::Int16 # @!attribute designated_router # The identity of the Designated Router for this network, in the # view of the sending router. # @return [String] - define_field :designated_router, IP::Addr + define_attr :designated_router, IP::Addr # @!attribute backup_designated_router # The identity of the Backup Designated Router for this network, # in the view of the sending router. # @return [String] - define_field :backup_designated_router, IP::Addr + define_attr :backup_designated_router, IP::Addr # @!attribute neighbors # Array of neighbors # @return [IP::ArrayOfAddr] - define_field :neighbors, IP::ArrayOfAddr + define_attr :neighbors, IP::ArrayOfAddr end end diff --git a/lib/packetgen/header/ospfv3/ipv6_prefix.rb b/lib/packetgen/header/ospfv3/ipv6_prefix.rb index 532f12f..e91ef59 100644 --- a/lib/packetgen/header/ospfv3/ipv6_prefix.rb +++ b/lib/packetgen/header/ospfv3/ipv6_prefix.rb @@ -17,26 +17,26 @@ class OSPFv3 # * and an array of 32-bit words to encode prefix itself ({#prefix}). This # array consumes ((PrefixLength + 31) / 32) 32-bit words. # @author Sylvain Daubert - class IPv6Prefix < Types::Fields - include Types::Fieldable + class IPv6Prefix < BinStruct::Struct + include BinStruct::Structable # @!attribute length # Prefix length, in bits # @return [Integer] - define_field :length, Types::Int8 + define_attr :length, BinStruct::Int8 # @!attribute options # Prefix capabilities. See also capability bits: {#dn_opt}, {#p_opt}, # {#la_opt} and {#nu_opt}. # @return [Options] - define_field :options, Types::Int8 + define_attr :options, BinStruct::Int8 # @!attribute reserved # Reserved field in most of LSA types. # @return [Integer] - define_field :reserved, Types::Int16 + define_attr :reserved, BinStruct::Int16 # @!attribute prefix # IPv6 Prefix as an array of 32-bit words # @return [Prefix] - define_field :prefix, Types::ArrayOfInt32, builder: ->(h, t) { t.new(length_from: -> { h.length / 8 }) } + define_attr :prefix, BinStruct::ArrayOfInt32, builder: ->(h, t) { t.new(length_from: -> { h.length / 8 }) } # @!attribute dn_opt # This bit controls an inter-area-prefix-LSAs or AS-external-LSAs @@ -54,7 +54,7 @@ class IPv6Prefix < Types::Fields # The "no unicast" capability bit. If set, the prefix should be # excluded from IPv6 unicast calculations. # @return [Boolean] - define_bit_fields_on :options, :zz, 3, :dn_opt, :p_opt, :z, :la_opt, :nu_opt + define_bit_attrs_on :options, :zz, 3, :dn_opt, :p_opt, :z, :la_opt, :nu_opt # Get human-readable prefix # @return [String] @@ -100,7 +100,7 @@ def ary_and_prefix_len_from_str(str) # Array of {IPv6Prefix} # @author Sylvain Daubert - class ArrayOfIPv6Prefix < Types::Array + class ArrayOfIPv6Prefix < BinStruct::Array set_of IPv6Prefix end end diff --git a/lib/packetgen/header/ospfv3/ls_ack.rb b/lib/packetgen/header/ospfv3/ls_ack.rb index 10d6c4b..3964903 100644 --- a/lib/packetgen/header/ospfv3/ls_ack.rb +++ b/lib/packetgen/header/ospfv3/ls_ack.rb @@ -40,8 +40,8 @@ class LSAck < Base # @!attribute lsas # Array of {LSA LSAs} # @return [ArrayOfLSA] - define_field :lsas, ArrayOfLSA, - builder: ->(_h, t) { t.new(only_headers: true) } + define_attr :lsas, ArrayOfLSA, + builder: ->(_h, t) { t.new(only_headers: true) } end end diff --git a/lib/packetgen/header/ospfv3/ls_request.rb b/lib/packetgen/header/ospfv3/ls_request.rb index 779f292..b049c92 100644 --- a/lib/packetgen/header/ospfv3/ls_request.rb +++ b/lib/packetgen/header/ospfv3/ls_request.rb @@ -27,26 +27,26 @@ class OSPFv3 # * a 32-bit {#link_state_id} field, # * and a 32-bit {#advertising_router} field. # @author Sylvain Daubert - class LSR < Types::Fields - include Types::Fieldable + class LSR < BinStruct::Struct + include BinStruct::Structable # @!attribute reserved # reserved field. # @return [Integer] - define_field :reserved, Types::Int16, default: 0 + define_attr :reserved, BinStruct::Int16, default: 0 # @!attribute type # The type of the LSA to request. # @return [Integer] - define_field :type, Types::Int16Enum, enum: LSAHeader::TYPES + define_attr :type, BinStruct::Int16Enum, enum: LSAHeader::TYPES # @!attribute link_state_id # This field identifies the portion of the internet environment # that is being described by the LSA to request. # @return [String] - define_field :link_state_id, IP::Addr + define_attr :link_state_id, IP::Addr # @!attribute advertising_router # The Router ID of the requested LSA. # @return [String] - define_field :advertising_router, IP::Addr + define_attr :advertising_router, IP::Addr # Get human-readable type # @return [String] @@ -60,10 +60,10 @@ def to_human end end - # This class defines a specialized {Types::Array array} to handle series + # This class defines a specialized {BinStruct::Array array} to handle series # of {LSR LSRs}. # @author Sylvain Daubert - class ArrayOfLSR < Types::Array + class ArrayOfLSR < BinStruct::Array set_of LSR end @@ -100,7 +100,7 @@ class LSRequest < Base # @!attribute lsrs # Array of {LSR} # @return [ArrayOfLSR] - define_field :lsrs, ArrayOfLSR + define_attr :lsrs, ArrayOfLSR end end diff --git a/lib/packetgen/header/ospfv3/ls_update.rb b/lib/packetgen/header/ospfv3/ls_update.rb index 9c72ae2..3db8728 100644 --- a/lib/packetgen/header/ospfv3/ls_update.rb +++ b/lib/packetgen/header/ospfv3/ls_update.rb @@ -23,7 +23,7 @@ class OSPFv3 # | ... | # # This paylod is implemented with two fields: - # * {#lsas_count}, a {Types::Int32} field, + # * {#lsas_count}, a {BinStruct::Int32} field, # * and {#lsas}, an {ArrayOfLSA} object. # # == Create a LSUpdate payload @@ -48,12 +48,12 @@ class LSUpdate < Base # @!attribute lsas_count # Count of LSAs included in this update # @return [Integer] - define_field :lsas_count, Types::Int32 + define_attr :lsas_count, BinStruct::Int32 # @!attribute lsas # Array of {LSA LSAs} # @return [ArrayOfLSA] - define_field :lsas, ArrayOfLSA, - builder: ->(h, t) { t.new(counter: h[:lsas_count]) } + define_attr :lsas, ArrayOfLSA, + builder: ->(h, t) { t.new(counter: h[:lsas_count]) } # Calculate checksums of all LSAs # @return [void] diff --git a/lib/packetgen/header/ospfv3/lsa.rb b/lib/packetgen/header/ospfv3/lsa.rb index efa6207..0ee4fd6 100644 --- a/lib/packetgen/header/ospfv3/lsa.rb +++ b/lib/packetgen/header/ospfv3/lsa.rb @@ -11,27 +11,27 @@ module Header class OSPFv3 # This class handles links in a {LSARouter OSPFv3 LSA router payload}. # @author Sylvain Daubert - class Link < Types::Fields - include Types::Fieldable + class Link < BinStruct::Struct + include BinStruct::Structable # @!attribute type # @return [Integer] - define_field :type, Types::Int8 + define_attr :type, BinStruct::Int8 # @!attribute reserved # @return [Integer] - define_field :reserved, Types::Int8, default: 0 + define_attr :reserved, BinStruct::Int8, default: 0 # @!attribute metric # @return [Integer] - define_field :metric, Types::Int16 + define_attr :metric, BinStruct::Int16 # @!attribute interface_id # @return [Integer] - define_field :interface_id, Types::Int32 + define_attr :interface_id, BinStruct::Int32 # @!attribute neighbor_interface_id # @return [Integer] - define_field :neighbor_interface_id, Types::Int32 + define_attr :neighbor_interface_id, BinStruct::Int32 # @!attribute neighbor_router_id # @return [String] - define_field :neighbor_router_id, IP::Addr + define_attr :neighbor_router_id, IP::Addr # @return [String] def to_human @@ -40,10 +40,10 @@ def to_human end end - # This class defines a specialized {Types::Array array} to handle series + # This class defines a specialized {BinStruct::Array array} to handle series # of {Link Links}. # @author Sylvain Daubert - class ArrayOfLink < Types::Array + class ArrayOfLink < BinStruct::Array set_of Link end @@ -54,28 +54,28 @@ class LSA < LSAHeader # @!attribute body # LSA body # @return [String] - define_field :body, Types::String, - builder: ->(h, t) { t.new(length_from: -> { h.length - 20 }) } + define_attr :body, BinStruct::String, + builder: ->(h, t) { t.new(length_from: -> { h.length - 20 }) } end # This class handles OSPFv3 LSA Router payloads. # # A LSA router payload is composed of: # * a header (see methods inherited from {LSAHeader}), - # * a 8-bit flag word {#flags} ({Types::Int8}), - # * a 24-bit {#options} field ({Types::Int24}), + # * a 8-bit flag word {#flags} ({BinStruct::Int8}), + # * a 24-bit {#options} field ({BinStruct::Int24}), # * and an array of {#links} ({ArrayOfLink}). # @author Sylvain Daubert class LSARouter < LSAHeader # @attribute flags # 8-bit flag word # @return [Integer] - define_field :flags, Types::Int8 + define_attr :flags, BinStruct::Int8 # @!macro define_ospfv3_options OSPFv3.define_options(self) # @attribute links # @return [ArrayOfLink] - define_field :links, ArrayOfLink, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:links) }) } + define_attr :links, ArrayOfLink, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:links) }) } # @!attribute nt_flag # @return [Boolean] @@ -85,8 +85,8 @@ class LSARouter < LSAHeader # @return [Boolean] # @!attribute b_flag # @return [Boolean] - define_bit_fields_on :flags, :zz, 3, :nt_flag, :x_flag, :v_flag, :e_flag, - :b_flag + define_bit_attrs_on :flags, :zz, 3, :nt_flag, :x_flag, :v_flag, :e_flag, + :b_flag end # This class handles OSPFv3 LSA Network payloads. @@ -100,20 +100,20 @@ class LSARouter < LSAHeader class LSANetwork < LSAHeader # @!attribute reserved # @return [Integer] - define_field :reserved, Types::Int8 + define_attr :reserved, BinStruct::Int8 # @!macro define_ospfv3_options OSPFv3.define_options(self) # @!attribute routers # List of routers attached to the link. # @return [IP::ArrayOfAddr] - define_field :routers, IP::ArrayOfAddr, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:routers) }) } + define_attr :routers, IP::ArrayOfAddr, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:routers) }) } end # This class handles OSPFv3 LSA Intra-Area-Prefix payloads. # # An Intra-Area-Prefix payloads is composed of: - # * a 16-bit {#prefix_count} field ({Types::Int16}), - # * a 16-bit {#ref_ls_type} field ({Types::Int16Enum}), + # * a 16-bit {#prefix_count} field ({BinStruct::Int16}), + # * a 16-bit {#ref_ls_type} field ({BinStruct::Int16Enum}), # * a 32-bit {#ref_link_state_id} ({IP::Addr}), # * a 32-bit {#ref_advertising_router} ({IP::Addr}), # * and an array of {IPv6Prefix} ({#prefixes}, {ArrayOfIPv6Prefix}). In @@ -123,40 +123,40 @@ class LSAIntraAreaPrefix < LSAHeader # @!attribute prefix_count # The number of IPv6 address prefixes contained in the LSA. # @return [Integer] - define_field :prefix_count, Types::Int16 + define_attr :prefix_count, BinStruct::Int16 # @!attribute ref_ls_type # Used to identify the router-LSA or network-LSA with which the IPv6 # address prefixes should be associated, in association with # {#ref_link_state_id} and {#ref_advertising_router}. # @return [Integer] - define_field :ref_ls_type, Types::Int16Enum, enum: TYPES + define_attr :ref_ls_type, BinStruct::Int16Enum, enum: TYPES # @!attribute ref_link_state_id # Used to identify the router-LSA or network-LSA with which the IPv6 # address prefixes should be associated, in association with # {#ref_ls_type} and {#ref_advertising_router}. # @return [String] - define_field :ref_link_state_id, IP::Addr + define_attr :ref_link_state_id, IP::Addr # @!attribute ref_advertising_router # Used to identify the router-LSA or network-LSA with which the IPv6 # address prefixes should be associated, in association with # {#ref_link_state_id} and {#ref_ls_type}. # @return [String] - define_field :ref_advertising_router, IP::Addr + define_attr :ref_advertising_router, IP::Addr # @!attribute prefixes # Array of {IPv6Prefix}. Note for this LSA, {IPv6Prefix#reserved} is # used as +metric+ value. # @return [ArrayOfIPv6Prefix] - define_field :prefixes, ArrayOfIPv6Prefix, - builder: ->(h, t) { t.new(counter: h[:prefix_count]) } + define_attr :prefixes, ArrayOfIPv6Prefix, + builder: ->(h, t) { t.new(counter: h[:prefix_count]) } end # This class handles OSPFv3 LSA Link payloads. # # A Link payloads is composed of: - # * a 8-bit {#router_priority} field ({Types::Int8}), - # * a 24-bit {#options} field ({Types::Int24}), + # * a 8-bit {#router_priority} field ({BinStruct::Int8}), + # * a 24-bit {#options} field ({BinStruct::Int24}), # * a 128-bit IPv6 {#interface_addr} ({IPv6::Addr}), - # * a 32-bit {#prefix_count} field ({Types::Int32}), + # * a 32-bit {#prefix_count} field ({BinStruct::Int32}), # * and an array of {IPv6Prefix} ({#prefixes}, {ArrayOfIPv6Prefix}). # @author Sylvain Daubert class LSALink < LSAHeader @@ -164,32 +164,32 @@ class LSALink < LSAHeader # The Router Priority of the interface attaching the originating # router to the link. # @return [Integer] - define_field :router_priority, Types::Int8 + define_attr :router_priority, BinStruct::Int8 # @!macro define_ospfv3_options OSPFv3.define_options(self) # @!attribute interface_addr # The originating router's link-local interface address on the link. # @return [String] - define_field :interface_addr, IPv6::Addr + define_attr :interface_addr, IPv6::Addr # @!attribute prefix_count # The number of IPv6 address prefixes contained in the LSA. # @return [Integer] - define_field :prefix_count, Types::Int32 + define_attr :prefix_count, BinStruct::Int32 # @!attribute prefixes # List of IPv6 prefixes to be associated with the link. # @return [ArrayOfIPv6Prefix] - define_field :prefixes, ArrayOfIPv6Prefix, builder: ->(h, t) { t.new(counter: h[:prefix_count]) } + define_attr :prefixes, ArrayOfIPv6Prefix, builder: ->(h, t) { t.new(counter: h[:prefix_count]) } end - # This class defines a specialized {Types::Array array} to handle series + # This class defines a specialized {BinStruct::Array array} to handle series # of {LSA LSAs} or {LSAHeader LSAHeaders}. It recognizes known LSA types # and infers correct type. # @author Sylvain Daubert - class ArrayOfLSA < Types::Array + class ArrayOfLSA < BinStruct::Array set_of LSAHeader # @param [Hash] options - # @option options [Types::Int] counter Int object used as a counter for this set + # @option options [BinStruct::Int] counter Int object used as a counter for this set # @option options [Boolean] only_headers if +true+, only {LSAHeader LSAHeaders} # will be added to this array. def initialize(options={}) diff --git a/lib/packetgen/header/ospfv3/lsa_header.rb b/lib/packetgen/header/ospfv3/lsa_header.rb index 4f7d82e..770e965 100644 --- a/lib/packetgen/header/ospfv3/lsa_header.rb +++ b/lib/packetgen/header/ospfv3/lsa_header.rb @@ -29,8 +29,8 @@ class OSPFv3 # LSA headers are used as-is in {DbDescription} and {LSAck} payloads. # But this class is also a base class for different LSA class, as {LSARouter}. # @author Sylvain Daubert - class LSAHeader < Types::Fields - include Types::Fieldable + class LSAHeader < BinStruct::Struct + include BinStruct::Structable # LSA known types TYPES = { @@ -47,34 +47,34 @@ class LSAHeader < Types::Fields # @!attribute age # The time in seconds since the LSA was originated. # @return [Integer] - define_field :age, Types::Int16 + define_attr :age, BinStruct::Int16 # @!attribute type # The type of the LSA. # @return [Integer] - define_field :type, Types::Int16Enum, enum: TYPES + define_attr :type, BinStruct::Int16Enum, enum: TYPES # @!attribute link_state_id # This field identifies the portion of the internet environment # that is being described by the LSA. # @return [String] - define_field :link_state_id, IP::Addr + define_attr :link_state_id, IP::Addr # @!attribute advertising_router # The Router ID of the router that originated the LSA. # @return [String] - define_field :advertising_router, IP::Addr + define_attr :advertising_router, IP::Addr # @!attribute sequence_number # @return [Integer] - define_field :sequence_number, Types::Int32 + define_attr :sequence_number, BinStruct::Int32 alias seqnum sequence_number alias seqnum= sequence_number= # @!attribute checksum # The Fletcher checksum of the complete contents of the LSA, # including the LSA header but excluding the LS age field. # @return [Integer] - define_field :checksum, Types::Int16 + define_attr :checksum, BinStruct::Int16 # @!attribute length # Length of the LSA, including the header. # @return [Integer] - define_field :length, Types::Int16 + define_attr :length, BinStruct::Int16 # Compute and set Fletcher-16 checksum on LSA # @return [Integer] diff --git a/lib/packetgen/header/sctp.rb b/lib/packetgen/header/sctp.rb index 0f91cdd..2b203d7 100644 --- a/lib/packetgen/header/sctp.rb +++ b/lib/packetgen/header/sctp.rb @@ -46,23 +46,23 @@ class SCTP < Base # @!attribute sport # 16-bit TCP source port # @return [Integer] - define_field :sport, Types::Int16 + define_attr :sport, BinStruct::Int16 # @!attribute dport # 16-bit TCP destination port # @return [Integer] - define_field :dport, Types::Int16 + define_attr :dport, BinStruct::Int16 # @!attribute verification_tag # 32-bit verification tag # @return [Integer] - define_field :verification_tag, Types::Int32 + define_attr :verification_tag, BinStruct::Int32 # @!attribute checksum # 32-bit TCP checksum # @return [Integer] - define_field :checksum, Types::Int32le + define_attr :checksum, BinStruct::Int32le # @!attribute chunks # List of chunks this packet transports # @return [ArrayOfChunk] - define_field :chunks, ArrayOfChunk + define_attr :chunks, ArrayOfChunk # Compute SCTP checksum def calc_checksum diff --git a/lib/packetgen/header/sctp/chunk.rb b/lib/packetgen/header/sctp/chunk.rb index 918775a..02e00e9 100644 --- a/lib/packetgen/header/sctp/chunk.rb +++ b/lib/packetgen/header/sctp/chunk.rb @@ -42,15 +42,15 @@ class BaseChunk < Base # @!attribute type # 8-bit SCTP chunk type # @return [Integer] - define_field :type, Types::Int8Enum, enum: TYPES + define_attr :type, BinStruct::Int8Enum, enum: TYPES # @!attribute type # 8-bit SCTP chunk flags # @return [Integer] - define_field :flags, Types::Int8 + define_attr :flags, BinStruct::Int8 # @!attribute length # 16-bit SCTP chunk length # @return [Integer] - define_field :length, Types::Int16 + define_attr :length, BinStruct::Int16 # Get human-redable chunk # @return [::String] @@ -91,7 +91,7 @@ module Header class SCTP # Embed chunks for a given {SCTP} packet. # @author Sylvain Daubert - class ArrayOfChunk < Types::Array + class ArrayOfChunk < BinStruct::Array set_of BaseChunk private @@ -121,7 +121,7 @@ class UnknownChunk < BaseChunk # @!attribute body # SCTP chunk value # @return [String] - define_field :body, Types::String, builder: ->(h, t) { t.new(length_from: -> { h.length - 4 }) } + define_attr :body, BinStruct::String, builder: ->(h, t) { t.new(length_from: -> { h.length - 4 }) } end # Data chunk @@ -145,23 +145,23 @@ class DataChunk < BaseChunk # @!attribute tsn # 32-bit TSN for this DATA chunk # @return [Integer] - define_field :tsn, Types::Int32 + define_attr :tsn, BinStruct::Int32 # @!attribute stream_id # 16-bit stream identifier # @return [Integer] - define_field :stream_id, Types::Int16 + define_attr :stream_id, BinStruct::Int16 # @!attribute stream_sn # 16-bit stream sequence number # @return [Integer] - define_field :stream_sn, Types::Int16 + define_attr :stream_sn, BinStruct::Int16 # @!attribute ppid # 32-bit payload protocol identifier # @return [Integer] - define_field :ppid, Types::Int32 + define_attr :ppid, BinStruct::Int32 # @!attribute body # SCTP chunk value # @return [String] - define_field :body, Types::String, builder: ->(h, t) { t.new(length_from: -> { h.length - 4 }) } + define_attr :body, BinStruct::String, builder: ->(h, t) { t.new(length_from: -> { h.length - 4 }) } # @!attribute flag_i # IMMEDIATE flag @@ -175,7 +175,7 @@ class DataChunk < BaseChunk # @!attribute flag_e # ENDING fragment flag # @return [Boolean] - define_bit_fields_on :flags, :flag_res, 4, :flag_i, :flag_u, :flag_b, :flag_e + define_bit_attrs_on :flags, :flag_res, 4, :flag_i, :flag_u, :flag_b, :flag_e private @@ -212,27 +212,27 @@ class InitChunk < BaseChunk # @!attribute initiate_tag # 32-bit Initiate Tag # @return [Integer] - define_field :initiate_tag, Types::Int32 + define_attr :initiate_tag, BinStruct::Int32 # @!attribute a_wrnd # 32-bit Advertised Receiver Window Credit (a_rwnd) # @return [Integer] - define_field :a_rwnd, Types::Int32 + define_attr :a_rwnd, BinStruct::Int32 # @!attribute nos # 16-bit Number of Outbound Streams # @return [Integer] - define_field :nos, Types::Int16 + define_attr :nos, BinStruct::Int16 # @!attribute nis # 16-bit Number of Inbound Streams # @return [Integer] - define_field :nis, Types::Int16 + define_attr :nis, BinStruct::Int16 # @!attribute initial_tsn # 32-bit Initial TSN # @return [Integer] - define_field :initial_tsn, Types::Int32 + define_attr :initial_tsn, BinStruct::Int32 # @!attribute parameters # List of parameters # @return [ArrayOfParameter] - define_field :parameters, ArrayOfParameter + define_attr :parameters, ArrayOfParameter def initialize(options={}) options[:type] = BaseChunk::TYPES['INIT'] unless options.key?(:type) @@ -315,28 +315,28 @@ class SackChunk < BaseChunk # @!attribute ctsn_ack # 32-bit Cumulative TSN Ack # @return [Integer] - define_field :ctsn_ack, Types::Int32 + define_attr :ctsn_ack, BinStruct::Int32 # @!attribute a_rwnd # 32-bit Advertised Receiver Window Credit # @return [Integer] - define_field :a_rwnd, Types::Int32 + define_attr :a_rwnd, BinStruct::Int32 # @!attribute num_gap # 16-bit Number of Gap Ack Blocks # @return [Integer] - define_field :num_gap, Types::Int32 + define_attr :num_gap, BinStruct::Int32 # @!attribute num_dup_tsn # 16-bit Number of Duplicate TSNs # @return [Integer] - define_field :num_dup_tsn, Types::Int32 + define_attr :num_dup_tsn, BinStruct::Int32 # @!attribute gaps # Array of 32-bit Integers, encoding boudaries of a Gap Ack Block. # 16 most significant bits encode block start. 16 least significant bits encode block end. - # @return [Types::ArrayOfInt32] - define_field :gaps, Types::ArrayOfInt32 + # @return [BinStruct::ArrayOfInt32] + define_attr :gaps, BinStruct::ArrayOfInt32 # @!attribute dup_tsns # Array of 32-bit Duplicate TSNs. - # @return [Types::ArrayOfInt32] - define_field :dup_tsns, Types::ArrayOfInt32 + # @return [BinStruct::ArrayOfInt32] + define_attr :dup_tsns, BinStruct::ArrayOfInt32 def initialize(options={}) options[:type] = BaseChunk::TYPES['SACK'] unless options.key?(:type) @@ -358,8 +358,8 @@ def initialize(options={}) class HeartbeatChunk < BaseChunk # @!attribute info # Array of Heartbeat information TLV. - # @return [Types::ArrayOfInt32] - define_field :info, HearbeatInfoParameter + # @return [BinStruct::ArrayOfInt32] + define_attr :info, HearbeatInfoParameter def initialize(options={}) options[:type] = BaseChunk::TYPES['HEARTBEAT'] unless options.key?(:type) @@ -399,7 +399,7 @@ def initialize(options={}) class ErrorChunk < BaseChunk # @!attribute error_causes # @return [ArrayofError] - define_field :error_causes, ArrayOfError + define_attr :error_causes, ArrayOfError def initialize(options={}) options[:type] = BaseChunk::TYPES['ERROR'] unless options.key?(:type) @@ -437,7 +437,7 @@ def to_human class AbortChunk < ErrorChunk # @!attribute flag_t # @return [Boolean] - define_bit_fields_on :flags, :flag_res, 7, :flag_t + define_bit_attrs_on :flags, :flag_res, 7, :flag_t def initialize(options={}) options[:type] = BaseChunk::TYPES['ABORT'] unless options.key?(:type) @@ -464,7 +464,7 @@ class ShutdownChunk < BaseChunk # @!attribute cstn_ack # 32-bit cumulative TSN ack # @return [Integer] - define_field :ctsn_ack, Types::Int32 + define_attr :ctsn_ack, BinStruct::Int32 def initialize(options={}) options[:type] = BaseChunk::TYPES['SHUTDOWN'] unless options.key?(:type) @@ -501,7 +501,7 @@ def initialize(options={}) class CookieEchoChunk < BaseChunk # @!attribute cookie # @return [String] - define_field :cookie, Types::String + define_attr :cookie, BinStruct::String def initialize(options={}) options[:type] = BaseChunk::TYPES['COOKIE_ECHO'] unless options.key?(:type) @@ -534,7 +534,7 @@ def initialize(options={}) class ShutdownCompleteChunk < BaseChunk # @!attribute flag_t # @return [Boolean] - define_bit_fields_on :flags, :flag_res, 7, :flag_t + define_bit_attrs_on :flags, :flag_res, 7, :flag_t def initialize(options={}) options[:type] = BaseChunk::TYPES['SHUTDOWN_COMPLETE'] unless options.key?(:type) diff --git a/lib/packetgen/header/sctp/error.rb b/lib/packetgen/header/sctp/error.rb index 88d22b6..e9b90d6 100644 --- a/lib/packetgen/header/sctp/error.rb +++ b/lib/packetgen/header/sctp/error.rb @@ -26,9 +26,9 @@ def to_human end end - Error = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - field_in_length: 'TLV') + Error = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + attr_in_length: 'TLV') # Base class/factory for {AbortChunk} and {ErrorChunk} error causes # @author Sylvain Daubert @@ -65,7 +65,7 @@ def from_human(value) # Handle array of {Error} and {ErrorMixin} classes. # @author Sylvain Daubert - class ArrayOfError < Types::Array + class ArrayOfError < BinStruct::Array set_of Error private @@ -83,10 +83,10 @@ def real_klass_name(type_name) end end - InvalidStreamIdError = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - value_class: Types::Int32, - field_in_length: 'TLV') + InvalidStreamIdError = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + value_class: BinStruct::Int32, + attr_in_length: 'TLV') # InvalidStreamIdentifier error # @author Sylvain Daubert @@ -115,16 +115,16 @@ def to_human # @param [Integer] val def from_human(val) super - self.value <<= 16 if self[:value] < Types::Int + self.value <<= 16 if self[:value] < BinStruct::Int end end InvalidStreamIdError.define_type_enum(Error::TYPES) InvalidStreamIdError.define_type_default('InvalidStreamId') - MissingMandatoryParameterError = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - value_class: Types::ArrayOfInt16, - field_in_length: 'TLV') + MissingMandatoryParameterError = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + value_class: BinStruct::ArrayOfInt16, + attr_in_length: 'TLV') # MissingMandatoryParameter error. Indicate that one or more # mandatory TLV parameters are missing in a received {InitChunk} @@ -141,10 +141,10 @@ def to_human MissingMandatoryParameterError.define_type_enum(Error::TYPES) MissingMandatoryParameterError.define_type_default('MissingMandatoryParameter') - StaleCookieError = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - value_class: Types::Int32, - field_in_length: 'TLV') + StaleCookieError = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + value_class: BinStruct::Int32, + attr_in_length: 'TLV') # StaleCookie error. Indicates the receipt of a valid State Cookie that # has expired. @@ -155,9 +155,9 @@ class StaleCookieError StaleCookieError.define_type_enum(Error::TYPES) StaleCookieError.define_type_default('StaleCookie') - OutOfResourceError = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - field_in_length: 'TLV') + OutOfResourceError = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + attr_in_length: 'TLV') # Out of ressource error. Indicates that the sender is out of resource. # @author Sylvain Daubert @@ -172,10 +172,10 @@ def to_human OutOfResourceError.define_type_enum(Error::TYPES) OutOfResourceError.define_type_default('OutOfResource') - UnresolvableAddressError = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - value_class: Parameter, - field_in_length: 'TLV') + UnresolvableAddressError = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + value_class: Parameter, + attr_in_length: 'TLV') # Out of ressource error. Indicates that the sender is out of resource. # @author Sylvain Daubert @@ -203,10 +203,10 @@ def to_human UnresolvableAddressError.define_type_enum(Error::TYPES) UnresolvableAddressError.define_type_default('UnresolvableAddress') - UnrecognizedChunkTypeError = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - value_class: BaseChunk, - field_in_length: 'TLV') + UnrecognizedChunkTypeError = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + value_class: BaseChunk, + attr_in_length: 'TLV') # Unrecognized chunk type error. The receiver does not understand the chunk and the upper bits of the 'Chunk Type' # are set to 01 or 11. @@ -222,9 +222,9 @@ def to_human UnrecognizedChunkTypeError.define_type_enum(Error::TYPES) UnrecognizedChunkTypeError.define_type_default('UnrecognizedChunkType') - InvalidMandatoryParameterError = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - field_in_length: 'TLV') + InvalidMandatoryParameterError = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + attr_in_length: 'TLV') # Invalid mandatory parameter error. Returned to the originator of an INIT or INIT ACK chunk when one of the # mandatory parameters is set to an invalid value. @@ -240,10 +240,10 @@ def to_human InvalidMandatoryParameterError.define_type_enum(Error::TYPES) InvalidMandatoryParameterError.define_type_default('InvalidMandatoryParameter') - UnrecognizedParametersError = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - value_class: ArrayOfParameter, - field_in_length: 'TLV') + UnrecognizedParametersError = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + value_class: ArrayOfParameter, + attr_in_length: 'TLV') # Unrecognized parameters error. Returned to the originator of the INIT ACK chunk if the receiver does not # recognize one or more Optional TLV parameters in the INIT ACK chunk. @@ -259,10 +259,10 @@ def to_human UnrecognizedParametersError.define_type_enum(Error::TYPES) UnrecognizedParametersError.define_type_default('UnrecognizedParameters') - NoUserDataError = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - value_class: Types::Int32, - field_in_length: 'TLV') + NoUserDataError = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + value_class: BinStruct::Int32, + attr_in_length: 'TLV') # No user data error. Returned when a received {DataChunk} was received with no data. # @author Sylvain Daubert @@ -272,9 +272,9 @@ class NoUserDataError NoUserDataError.define_type_enum(Error::TYPES) NoUserDataError.define_type_default('NoUserData') - CookieReceivedWhileShuttingDownError = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - field_in_length: 'TLV') + CookieReceivedWhileShuttingDownError = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + attr_in_length: 'TLV') # Cookie received while shutting down error. # A COOKIE ECHO chunk was received while the endpoint was in the SHUTDOWN-ACK-SENT state. @@ -290,10 +290,10 @@ def to_human CookieReceivedWhileShuttingDownError.define_type_enum(Error::TYPES) CookieReceivedWhileShuttingDownError.define_type_default('CookieReceivedWhileShuttingDown') - RestartAssociationWithNewAddressError = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - value_class: ArrayOfParameter, - field_in_length: 'TLV') + RestartAssociationWithNewAddressError = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + value_class: ArrayOfParameter, + attr_in_length: 'TLV') # Cookie received while shutting down error. # A COOKIE ECHO chunk was received while the endpoint was in the SHUTDOWN-ACK-SENT state. @@ -309,9 +309,9 @@ def to_human RestartAssociationWithNewAddressError.define_type_enum(Error::TYPES) RestartAssociationWithNewAddressError.define_type_default('RestartAssociationWithNewAddress') - UserInitiatedAbortError = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - field_in_length: 'TLV') + UserInitiatedAbortError = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + attr_in_length: 'TLV') # User-Initiated abort error. # @author Sylvain Daubert @@ -326,9 +326,9 @@ def to_human UserInitiatedAbortError.define_type_enum(Error::TYPES) UserInitiatedAbortError.define_type_default('UserInitiatedAbort') - ProtocolViolationError = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - field_in_length: 'TLV') + ProtocolViolationError = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + attr_in_length: 'TLV') # Protocol violation error. # @author Sylvain Daubert diff --git a/lib/packetgen/header/sctp/parameter.rb b/lib/packetgen/header/sctp/parameter.rb index 9cd4bd9..d2e8819 100644 --- a/lib/packetgen/header/sctp/parameter.rb +++ b/lib/packetgen/header/sctp/parameter.rb @@ -26,9 +26,9 @@ def to_human end end - Parameter = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - field_in_length: 'TLV') + Parameter = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + attr_in_length: 'TLV') # Base class/factory for {InitChunk} and {InitAckChunk} parameters # @author Sylvain Daubert class Parameter @@ -62,10 +62,10 @@ def from_human(value) end Parameter.define_type_enum(Parameter::TYPES) - IPv4Parameter = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - value_class: IP::Addr, - field_in_length: 'TLV') + IPv4Parameter = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + value_class: IP::Addr, + attr_in_length: 'TLV') # IPv4 address parameter # @author Sylvain Daubert @@ -75,10 +75,10 @@ class IPv4Parameter IPv4Parameter.define_type_enum(Parameter::TYPES) IPv4Parameter.define_type_default('IPv4') - IPv6Parameter = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - value_class: IPv6::Addr, - field_in_length: 'TLV') + IPv6Parameter = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + value_class: IPv6::Addr, + attr_in_length: 'TLV') # IPv6 address parameter # @author Sylvain Daubert @@ -88,10 +88,10 @@ class IPv6Parameter IPv6Parameter.define_type_enum(Parameter::TYPES) IPv6Parameter.define_type_default('IPv6') - StateCookieParameter = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - value_class: Types::String, - field_in_length: 'TLV') + StateCookieParameter = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + value_class: BinStruct::String, + attr_in_length: 'TLV') # State Cookie parameter # @author Sylvain Daubert @@ -106,10 +106,10 @@ def to_human StateCookieParameter.define_type_enum(Parameter::TYPES) StateCookieParameter.define_type_default('StateCookie') - UnrecognizedParameter = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - value_class: Parameter, - field_in_length: 'TLV') + UnrecognizedParameter = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + value_class: Parameter, + attr_in_length: 'TLV') # Unrecognized parameter # @author Sylvain Daubert @@ -124,10 +124,10 @@ def to_human UnrecognizedParameter.define_type_enum(Parameter::TYPES) UnrecognizedParameter.define_type_default('Unrecognized') - HostnameParameter = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - value_class: Types::CString, - field_in_length: 'TLV') + HostnameParameter = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + value_class: BinStruct::CString, + attr_in_length: 'TLV') # Hostname address parameter # @author Sylvain Daubert @@ -137,10 +137,10 @@ class HostnameParameter HostnameParameter.define_type_enum(Parameter::TYPES) HostnameParameter.define_type_default('Hostname') - SupportedAddrTypesParameter = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - value_class: Types::ArrayOfInt16, - field_in_length: 'TLV') + SupportedAddrTypesParameter = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + value_class: BinStruct::ArrayOfInt16, + attr_in_length: 'TLV') # Supported address types parameter # @author Sylvain Daubert @@ -158,10 +158,10 @@ def to_human SupportedAddrTypesParameter.define_type_enum(Parameter::TYPES) SupportedAddrTypesParameter.define_type_default('SupportedAddrTypes') - CookiePreservativeParameter = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - value_class: Types::Int32, - field_in_length: 'TLV') + CookiePreservativeParameter = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + value_class: BinStruct::Int32, + attr_in_length: 'TLV') # Cookie Preservative parameter # @author Sylvain Daubert @@ -176,9 +176,9 @@ def to_human CookiePreservativeParameter.define_type_enum(Parameter::TYPES) CookiePreservativeParameter.define_type_default('CookiePreservative') - ECNParameter = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - field_in_length: 'TLV') + ECNParameter = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + attr_in_length: 'TLV') # ECN parameter # @author Sylvain Daubert @@ -193,9 +193,9 @@ def to_human ECNParameter.define_type_enum(Parameter::TYPES) ECNParameter.define_type_default('ECN') - HearbeatInfoParameter = Types::AbstractTLV.create(type_class: Types::Int16Enum, - length_class: Types::Int16, - field_in_length: 'TLV') + HearbeatInfoParameter = BinStruct::AbstractTLV.create(type_class: BinStruct::Int16Enum, + length_class: BinStruct::Int16, + attr_in_length: 'TLV') # Heartbeat Information parameter # @author Sylvain Daubert @@ -207,7 +207,7 @@ class HearbeatInfoParameter # Array of {Parameter}s and {ParameterMixin}. # @author Sylvain Daubert - class ArrayOfParameter < Types::Array + class ArrayOfParameter < BinStruct::Array set_of Parameter private diff --git a/lib/packetgen/header/snmp.rb b/lib/packetgen/header/snmp.rb index 2a5574e..20c8ce1 100644 --- a/lib/packetgen/header/snmp.rb +++ b/lib/packetgen/header/snmp.rb @@ -286,7 +286,7 @@ def initialize(options={}) end # accessor to data payload - # @return [ASN1::Types::Choice] + # @return [ASN1::BinStruct::Choice] def data @elements[:data] end diff --git a/lib/packetgen/header/tcp.rb b/lib/packetgen/header/tcp.rb index 81f86e9..fa8df96 100644 --- a/lib/packetgen/header/tcp.rb +++ b/lib/packetgen/header/tcp.rb @@ -29,9 +29,9 @@ module Header # | data | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # A TCP header consists of: - # * a source port ({#sport}, {Types::Int16} type), + # * a source port ({#sport}, {BinStruct::Int16} type), # * a destination port ({#dport}, +Int16+ type), - # * a sequence number ({#seqnum}, {Types::Int32} type), + # * a sequence number ({#seqnum}, {BinStruct::Int32} type), # * an acknownledge number ({#acknum}, +Int32+ type), # * a 16-bit field ({#u16}, +Int16+ type) composed of: # * a 4-bit {#data_offset} self[attr], @@ -41,7 +41,7 @@ module Header # * a {#checksum} field (+Int16+ type), # * a urgent pointer ({#urg_pointer}, +Int16+ type), # * an optional {#options} field ({Options} type), - # * and a {#body} ({Types::String} type). + # * and a {#body} ({BinStruct::String} type). # # == Create a TCP header # # standalone @@ -78,7 +78,7 @@ class TCP < Base end end -# Need to load Options now, as this is used through define_bit_fields_on, +# Need to load Options now, as this is used through define_bit_attrs_on, # which make a call to TCP.new, which needs Options require_relative 'tcp/options' @@ -91,41 +91,41 @@ class TCP # @!attribute sport # 16-bit TCP source port # @return [Integer] - define_field :sport, Types::Int16 + define_attr :sport, BinStruct::Int16 # @!attribute dport # 16-bit TCP destination port # @return [Integer] - define_field :dport, Types::Int16 + define_attr :dport, BinStruct::Int16 # @!attribute seqnum # 32-bit TCP sequence number # @return [Integer] - define_field :seqnum, Types::Int32, default: ->(_) { rand(2**32) } + define_attr :seqnum, BinStruct::Int32, default: ->(_) { rand(2**32) } # @!attribute acknum # 32-bit TCP acknowledgement number # @return [Integer] - define_field :acknum, Types::Int32 + define_attr :acknum, BinStruct::Int32 # @!attribute u16 # @return [Integer] 16-bit word used by flags and bit fields - define_field :u16, Types::Int16 + define_attr :u16, BinStruct::Int16 # @!attribute window # 16-bit TCP window size # @return [Integer] - define_field :window, Types::Int16 + define_attr :window, BinStruct::Int16 # @!attribute checksum # 16-bit TCP checksum # @return [Integer] - define_field :checksum, Types::Int16 + define_attr :checksum, BinStruct::Int16 # @!attribute urg_pointer # 16-bit TCP urgent data pointer # @return [Integer] - define_field :urg_pointer, Types::Int16 + define_attr :urg_pointer, BinStruct::Int16 # @!attribute options # TCP options # @return [Options] - define_field :options, TCP::Options, builder: ->(h, t) { t.new(length_from: -> { h.data_offset > 5 ? (h.data_offset - 5) * 4 : 0 }) } + define_attr :options, TCP::Options, builder: ->(h, t) { t.new(length_from: -> { h.data_offset > 5 ? (h.data_offset - 5) * 4 : 0 }) } # @!attribute body - # @return [Types::String,Header::Base] - define_field :body, Types::String + # @return [BinStruct::String,Header::Base] + define_attr :body, BinStruct::String alias source_port sport alias source_port= sport= @@ -166,7 +166,7 @@ def initialize(options={}) # @return [Integer] 3-bit reserved from {#u16} # @!attribute flags # @return [Integer] 9-bit flags from {#u16} - define_bit_fields_on :u16, :data_offset, 4, :reserved, 3, :flags, 9 + define_bit_attrs_on :u16, :data_offset, 4, :reserved, 3, :flags, 9 alias hlen data_offset alias hlen= data_offset= @@ -188,8 +188,8 @@ def initialize(options={}) # @return [Boolean] 1-bit SYN flag # @!attribute flag_fin # @return [Boolean] 1-bit FIN flag - define_bit_fields_on :u16, :_, 7, :flag_ns, :flag_cwr, :flag_ece, :flag_urg, - :flag_ack, :flag_psh, :flag_rst, :flag_syn, :flag_fin + define_bit_attrs_on :u16, :_, 7, :flag_ns, :flag_cwr, :flag_ece, :flag_urg, + :flag_ack, :flag_psh, :flag_rst, :flag_syn, :flag_fin # Compute checksum and set +checksum+ field # @return [Integer] diff --git a/lib/packetgen/header/tcp/option.rb b/lib/packetgen/header/tcp/option.rb index 8b5c420..1495db6 100644 --- a/lib/packetgen/header/tcp/option.rb +++ b/lib/packetgen/header/tcp/option.rb @@ -11,8 +11,8 @@ module Header class TCP # Base class to describe a TCP option # @author Sylvain Daubert - class Option < Types::Fields - include Types::Fieldable + class Option < BinStruct::Struct + include BinStruct::Structable # EOL option value EOL_KIND = 0 @@ -36,15 +36,15 @@ class Option < Types::Fields # @!attribute kind # Option kind # @return [Integer] 8-bit option kind - define_field :kind, Types::Int8 + define_attr :kind, BinStruct::Int8 # @!attribute length # Option length # @return [Integer] 8-bit option length - define_field :length, Types::Int8, optional: ->(h) { h.length? } + define_attr :length, BinStruct::Int8, optional: lambda(&:length?) # @!attribute value # @return [Integer,String] option value - define_field :value, Types::String, optional: ->(h) { h.length? && h.length > 2 }, - builder: ->(h, t) { t.new(length_from: -> { h.length - 2 }) } + define_attr :value, BinStruct::String, optional: ->(h) { h.length? && h.length > 2 }, + builder: ->(h, t) { t.new(length_from: -> { h.length - 2 }) } # @param [hash] options # @option options [Integer] :kind @@ -55,18 +55,18 @@ def initialize(options={}) case options[:value] when Integer klass = case self[:length].to_i - when 3 then Types::Int8 - when 4 then Types::Int16 - when 6 then Types::Int32 + when 3 then BinStruct::Int8 + when 4 then BinStruct::Int16 + when 6 then BinStruct::Int32 else raise ArgumentError, 'impossible length' end - self[:value] = klass.new(options[:value]) + self[:value] = klass.new(value: options[:value]) when NilClass # Nothing to do else - self[:value] = Types::String.new.read(options[:value]) - self[:length].read(self[:value].sz + 2) unless options[:length] + self[:value] = BinStruct::String.new.read(options[:value]) + self[:length].from_human(self[:value].sz + 2) unless options[:length] end end @@ -83,7 +83,7 @@ def length? # @return [String, Integer] def value case self[:value] - when Types::Int + when BinStruct::Int self[:value].to_i else self[:value].to_s @@ -92,16 +92,22 @@ def value alias old_set_value value= # Setter for value attribute - # @param[String,Integer] + # @param[String,Integer] val # @return [String, Integer] def value=(val) case self[:value] - when Types::Int + when BinStruct::Int self.length = 2 + self[:value].sz - when Types::String - self.length = 2 + Types::String.new.read(val).sz + when BinStruct::String + self.length = 2 + BinStruct::String.new.read(val).sz + end + + case val + when Integer + self[:value].from_human(val) + else + self[:value].read(val) end - self[:value].read val val end @@ -131,26 +137,26 @@ def inspect # End Of Option TCP option # @author Sylvain Daubert class EOL < Option - update_field :kind, default: EOL_KIND + update_attr :kind, default: EOL_KIND end # No OPeration TCP option # @author Sylvain Daubert class NOP < Option # @see Option#initialize - update_field :kind, default: NOP_KIND + update_attr :kind, default: NOP_KIND end # Maximum Segment Size TCP option # @author Sylvain Daubert class MSS < Option - update_field :kind, default: MSS_KIND - update_field :length, default: 4 + update_attr :kind, default: MSS_KIND + update_attr :length, default: 4 # @see Option#initialize def initialize(options={}) super - self[:value] = Types::Int16.new(options[:value]) + self[:value] = BinStruct::Int16.new(value: options[:value]) end # @return [String] @@ -162,13 +168,13 @@ def to_human # Window Size TCP option # @author Sylvain Daubert class WS < Option - update_field :kind, default: WS_KIND - update_field :length, default: 3 + update_attr :kind, default: WS_KIND + update_attr :length, default: 3 # @see Option#initialize def initialize(options={}) super - self[:value] = Types::Int8.new(options[:value]) + self[:value] = BinStruct::Int8.new(value: options[:value]) end # @return [String] @@ -180,26 +186,26 @@ def to_human # Selective Acknowledgment OK TCP option # @author Sylvain Daubert class SACKOK < Option - update_field :kind, default: SACKOK_KIND - update_field :length, default: 2 + update_attr :kind, default: SACKOK_KIND + update_attr :length, default: 2 end # Selective Acknowledgment TCP option # @author Sylvain Daubert class SACK < Option - update_field :kind, default: SACK_KIND + update_attr :kind, default: SACK_KIND end # Echo TCP option # @author Sylvain Daubert class ECHO < Option - update_field :kind, default: ECHO_KIND - update_field :length, default: 6 + update_attr :kind, default: ECHO_KIND + update_attr :length, default: 6 # @see Option#initialize def initialize(options={}) super - self[:value] = Types::Int32.new(options[:value]) + self[:value] = BinStruct::Int32.new(value: options[:value]) end # @return [String] @@ -211,13 +217,13 @@ def to_human # Echo Reply TCP option # @author Sylvain Daubert class ECHOREPLY < Option - update_field :kind, default: ECHOREPLY_KIND - update_field :length, default: 6 + update_attr :kind, default: ECHOREPLY_KIND + update_attr :length, default: 6 # @see Option#initialize def initialize(options={}) super - self[:value] = Types::Int32.new(options[:value]) + self[:value] = BinStruct::Int32.new(value: options[:value]) end # @return [String] @@ -229,8 +235,8 @@ def to_human # Timestamp TCP option # @author Sylvain Daubert class TS < Option - update_field :kind, default: TS_KIND - update_field :length, default: 10 + update_attr :kind, default: TS_KIND + update_attr :length, default: 10 # @see Option#initialize def initialize(options={}) diff --git a/lib/packetgen/header/tcp/options.rb b/lib/packetgen/header/tcp/options.rb index f0a2111..078b2e5 100644 --- a/lib/packetgen/header/tcp/options.rb +++ b/lib/packetgen/header/tcp/options.rb @@ -13,7 +13,7 @@ module Header class TCP # Container for TCP options in {TCP TCP header}. # @author Sylvain Daubert - class Options < Types::Array + class Options < BinStruct::Array set_of Option # Get {Option} subclasses diff --git a/lib/packetgen/header/tftp.rb b/lib/packetgen/header/tftp.rb index e6a695e..bfe7954 100644 --- a/lib/packetgen/header/tftp.rb +++ b/lib/packetgen/header/tftp.rb @@ -10,7 +10,7 @@ module PacketGen module Header # A TFTP (Trivial File Transfer Protocol, # {https://tools.ietf.org/html/rfc1350 RFC 1350}) header consists of: - # * a {#opcode} ({Types::Int16Enum}), + # * a {#opcode} ({BinStruct::Int16Enum}), # * and a body. Its content depends on opcode. # # Specialized subclasses exists to handle {TFTP::RRQ Read Request}, @@ -60,11 +60,11 @@ class TFTP < Base # @!attribute opcode # 16-bit operation code # @return [Integer] - define_field :opcode, Types::Int16Enum, enum: OPCODES + define_attr :opcode, BinStruct::Int16Enum, enum: OPCODES # @!attribute body # @return [String] - define_field :body, Types::String + define_attr :body, BinStruct::String def initialize(options={}) type = protocol_name.sub(/^.*::/, '') @@ -147,17 +147,17 @@ def decode_tftp_packet(pkt) # TFTP Read Request header class RRQ < TFTP - remove_field :body + remove_attr :body # @!attribute filename # Filename to access # @return [String] - define_field :filename, Types::CString + define_attr :filename, BinStruct::CString # @!attribute mode # Mode used. Should be +netascii+, +octet+ or +mail+ # @return [String] - define_field :mode, Types::CString + define_attr :mode, BinStruct::CString end # TFTP Write Request header @@ -168,32 +168,32 @@ class DATA < TFTP # @!attribute block_num # 16-bit block number # @return [Integer] - define_field_before :body, :block_num, Types::Int16 + define_attr_before :body, :block_num, BinStruct::Int16 end # TFTP ACK header class ACK < TFTP - remove_field :body + remove_attr :body # @!attribute block_num # 16-bit block number # @return [Integer] - define_field :block_num, Types::Int16 + define_attr :block_num, BinStruct::Int16 end # TFTP ERROR header class ERROR < TFTP - remove_field :body + remove_attr :body # @!attribute error_code # 16-bit error code # @return [Integer] - define_field :error_code, Types::Int16 + define_attr :error_code, BinStruct::Int16 # @!attribute error_msg # Error message # @return [String] - define_field :error_msg, Types::CString + define_attr :error_msg, BinStruct::CString alias error_message error_msg end end diff --git a/lib/packetgen/header/udp.rb b/lib/packetgen/header/udp.rb index 70104fb..83727a0 100644 --- a/lib/packetgen/header/udp.rb +++ b/lib/packetgen/header/udp.rb @@ -17,7 +17,7 @@ module Header # | Length | Checksum | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # A UDP header consists of: - # * a source port field ({#sport}, {Types::Int16} type), + # * a source port field ({#sport}, {BinStruct::Int16} type), # * a destination port field ({#dport}, +Int16+ type), # * a UDP length field ({#length}, +Int16+ type), # * a {#checksum} field (+Int16+ type), @@ -46,22 +46,22 @@ class UDP < Base # @!attribute sport # 16-bit UDP source port # @return [Integer] - define_field :sport, Types::Int16 + define_attr :sport, BinStruct::Int16 # @!attribute dport # 16-bit UDP destination port # @return [Integer] - define_field :dport, Types::Int16 + define_attr :dport, BinStruct::Int16 # @!attribute length # 16-bit UDP length # @return [Integer] - define_field :length, Types::Int16, default: 8 + define_attr :length, BinStruct::Int16, default: 8 # @!attribute checksum # 16-bit UDP checksum # @return [Integer] - define_field :checksum, Types::Int16 + define_attr :checksum, BinStruct::Int16 # @!attribute body - # @return [Types::String,Header::Base] - define_field :body, Types::String + # @return [BinStruct::String,Header::Base] + define_attr :body, BinStruct::String alias source_port sport alias source_port= sport= diff --git a/lib/packetgen/headerable.rb b/lib/packetgen/headerable.rb index 528e4f9..751f461 100644 --- a/lib/packetgen/headerable.rb +++ b/lib/packetgen/headerable.rb @@ -51,7 +51,7 @@ def method_name end # @abstract Should be redefined by subclasses. This method should check invariant - # fields from header. + # attributes.from header. # Called by {Packet#parse} when guessing first header to check if header is correct # @return [Boolean] def parse? diff --git a/lib/packetgen/inspect.rb b/lib/packetgen/inspect.rb index a212e65..2d4ce1a 100644 --- a/lib/packetgen/inspect.rb +++ b/lib/packetgen/inspect.rb @@ -63,7 +63,7 @@ def self.format(type, attr, value, level=1) # Format an attribute for +#inspect+. # 3 cases are handled: - # * attribute value is a {Types::Int}: show value as integer and in + # * attribute value is a {BinStruct::Int}: show value as integer and in # hexdecimal format, # * attribute value responds to +#to_human+: call it, # * else, +#to_s+ is used to format attribute value. @@ -78,7 +78,7 @@ def self.inspect_attribute(attr, value, level=1) # Format a ASN.1 attribute for +#inspect+. # 4 cases are handled: - # * attribute value is a =RANS1::Types::Enumerated+: show named value and + # * attribute value is a =RANS1::BinStruct::Enumerated+: show named value and # its integer value as hexdecimal format, # * attribute value is a +RASN1::Types::Integer+: show value as integer and in # hexdecimal format, diff --git a/lib/packetgen/packet.rb b/lib/packetgen/packet.rb index 15a0510..180ee5b 100644 --- a/lib/packetgen/packet.rb +++ b/lib/packetgen/packet.rb @@ -337,7 +337,7 @@ def ===(other) end end - # Invert all possible fields in packet to create a reply. + # Invert all possible attributes.in packet to create a reply. # @return [self] # @since 2.7.0 def reply! diff --git a/lib/packetgen/pcapng.rb b/lib/packetgen/pcapng.rb index f35dda1..0a94992 100644 --- a/lib/packetgen/pcapng.rb +++ b/lib/packetgen/pcapng.rb @@ -14,13 +14,13 @@ module PacketGen # @author Sylvain Daubert module PcapNG # Section Header Block type number - SHB_TYPE = Types::Int32.new(0x0A0D0D0A, :little).freeze + SHB_TYPE = BinStruct::Int32.new(value: 0x0A0D0D0A, endian: :little).freeze # Interface Description Block type number - IDB_TYPE = Types::Int32.new(1, :little).freeze + IDB_TYPE = BinStruct::Int32.new(value: 1, endian: :little).freeze # Simple Packet Block type number - SPB_TYPE = Types::Int32.new(3, :little).freeze + SPB_TYPE = BinStruct::Int32.new(value: 3, endian: :little).freeze # Enhanced Packet Block type number - EPB_TYPE = Types::Int32.new(6, :little).freeze + EPB_TYPE = BinStruct::Int32.new(value: 6, endian: :little).freeze # IEEE 802.3 Ethernet (10Mb, 100Mb, 1000Mb, and up) LINKTYPE_ETHERNET = 1 diff --git a/lib/packetgen/pcapng/block.rb b/lib/packetgen/pcapng/block.rb index ec41f8a..865afa4 100644 --- a/lib/packetgen/pcapng/block.rb +++ b/lib/packetgen/pcapng/block.rb @@ -10,22 +10,22 @@ module PacketGen module PcapNG # @abstract Base class for all block types # @author Sylvain Daubert - class Block < Types::Fields + class Block < BinStruct::Struct # @return [:little, :big] attr_accessor :endian # @!attribute type # 32-bit block type # @return [Integer] - define_field :type, Types::Int32 + define_attr :type, BinStruct::Int32 # @!attribute block_len # 32-bit block length # @return [Integer] - define_field :block_len, Types::Int32 + define_attr :block_len, BinStruct::Int32 # @!attribute block_len # 32-bit block length # @return [Integer] - define_field :block_len2, Types::Int32 + define_attr :block_len2, BinStruct::Int32 def initialize(options={}) super @@ -35,22 +35,22 @@ def initialize(options={}) # @return [Boolean] # @since 2.7.0 def options? - @fields.key?(:options) && @fields[:options].sz.positive? + @attributes.key?(:options) && @attributes[:options].sz.positive? end # Calculate block length and update :block_len and block_len2 fields # @return [void] def recalc_block_len - len = fields.map { |f| @fields[f].to_s }.join.size + len = attributes.map { |f| @attributes[f].to_s }.join.size self.block_len = self.block_len2 = len end # Pad given field to 32 bit boundary, if needed - # @param [Array] fields block fields to pad + # @param [Array] attributes.block attributes.to pad # @return [void] def pad_field(*fields) fields.each do |field| - obj = @fields[field] + obj = @attributes[field] pad_size = (obj.sz % 4).zero? ? 0 : (4 - (obj.sz % 4)) obj << "\x00" * pad_size end @@ -66,7 +66,7 @@ def endianness(endian) raise ArgumentError, "unknown endianness for #{self.class}" unless %i[little big].include?(endian) @endian = endian - @fields.each_value { |v| v.endian = endian if v.is_a?(Types::Int) } + @attributes.each_value { |v| v.endian = endian if v.is_a?(BinStruct::Int) } endian end diff --git a/lib/packetgen/pcapng/epb.rb b/lib/packetgen/pcapng/epb.rb index 37e7670..d6a6592 100644 --- a/lib/packetgen/pcapng/epb.rb +++ b/lib/packetgen/pcapng/epb.rb @@ -34,29 +34,29 @@ class EPB < Block # @!attribute interface_id # 32-bit interface ID # @return [Integer] - define_field_before :block_len2, :interface_id, Types::Int32, default: 0 + define_attr_before :block_len2, :interface_id, BinStruct::Int32, default: 0 # @!attribute tsh # high 32-bit timestamp value # @return [Integer] - define_field_before :block_len2, :tsh, Types::Int32, default: 0 + define_attr_before :block_len2, :tsh, BinStruct::Int32, default: 0 # @!attribute tsl # low 32-bit imestamp value # @return [Integer] - define_field_before :block_len2, :tsl, Types::Int32, default: 0 + define_attr_before :block_len2, :tsl, BinStruct::Int32, default: 0 # @!attribute cap_len # 32-bit capture length # @return [Integer] - define_field_before :block_len2, :cap_len, Types::Int32, default: 0 + define_attr_before :block_len2, :cap_len, BinStruct::Int32, default: 0 # @!attribute orig_len # 32-bit original length # @return [Integer] - define_field_before :block_len2, :orig_len, Types::Int32, default: 0 + define_attr_before :block_len2, :orig_len, BinStruct::Int32, default: 0 # @!attribute data - # @return [Types::String] - define_field_before :block_len2, :data, Types::String + # @return [BinStruct::String] + define_attr_before :block_len2, :data, BinStruct::String # @!attribute options - # @return [Types::String] - define_field_before :block_len2, :options, Types::String + # @return [BinStruct::String] + define_attr_before :block_len2, :options, BinStruct::String # @param [Hash] options # @option options [:little, :big] :endian set block endianness diff --git a/lib/packetgen/pcapng/file.rb b/lib/packetgen/pcapng/file.rb index 33cd9ae..240ffda 100644 --- a/lib/packetgen/pcapng/file.rb +++ b/lib/packetgen/pcapng/file.rb @@ -271,13 +271,13 @@ def parse_section(io) # @param [IO] io stream from which parse SHB # @return [SHB] def parse_shb(shb, io) - type = Types::Int32.new(0, shb.endian).read(io.read(4)) + type = BinStruct::Int32.new(value: 0, endian: shb.endian).read(io.read(4)) io.seek(-4, IO::SEEK_CUR) parse(type, io, shb) end # Parse a block from its type - # @param [Types::Int32] type + # @param [BinStruct::Int32] type # @param [IO] io stream from which parse block # @param [SHB] shb header of current section # @return [Block] @@ -288,7 +288,7 @@ def parse(type, io, shb) end # Guess class to use from type - # @param [Types::Int] type + # @param [BinStruct::Int] type # @return [Block] def guess_block_type(type) BLOCK_TYPES.key?(type.to_i) ? BLOCK_TYPES[type.to_i] : UnknownBlock diff --git a/lib/packetgen/pcapng/idb.rb b/lib/packetgen/pcapng/idb.rb index 62b39c1..40fdba4 100644 --- a/lib/packetgen/pcapng/idb.rb +++ b/lib/packetgen/pcapng/idb.rb @@ -36,18 +36,18 @@ class IDB < Block # @!attribute link_type # 16-bit link type # @return [Integer] - define_field_before :block_len2, :link_type, Types::Int16, default: 1 + define_attr_before :block_len2, :link_type, BinStruct::Int16, default: 1 # @!attribute reserved # 16-bit reserved field # @return [Integer] - define_field_before :block_len2, :reserved, Types::Int16, default: 0 + define_attr_before :block_len2, :reserved, BinStruct::Int16, default: 0 # @!attribute snaplen # 32-bit snap length # @return [Integer] - define_field_before :block_len2, :snaplen, Types::Int32, default: 0 + define_attr_before :block_len2, :snaplen, BinStruct::Int32, default: 0 # @!attribute options - # @return [Types::String] - define_field_before :block_len2, :options, Types::String + # @return [BinStruct::String] + define_attr_before :block_len2, :options, BinStruct::String # @param [Hash] options # @option options [:little, :big] :endian set block endianness diff --git a/lib/packetgen/pcapng/shb.rb b/lib/packetgen/pcapng/shb.rb index 7488095..bf09108 100644 --- a/lib/packetgen/pcapng/shb.rb +++ b/lib/packetgen/pcapng/shb.rb @@ -45,23 +45,23 @@ class SHB < Block # @!attribute magic # 32-bit magic number # @return [Integer] - define_field_before :block_len2, :magic, Types::Int32, default: MAGIC_INT32 + define_attr_before :block_len2, :magic, BinStruct::Int32, default: MAGIC_INT32 # @!attribute ver_major # 16-bit major version number # @return [Integer] - define_field_before :block_len2, :ver_major, Types::Int16, default: 1 + define_attr_before :block_len2, :ver_major, BinStruct::Int16, default: 1 # @!attribute ver_major # 16-bit minor version number # @return [Integer] - define_field_before :block_len2, :ver_minor, Types::Int16, default: 0 + define_attr_before :block_len2, :ver_minor, BinStruct::Int16, default: 0 # @!attribute section_len # 64-bit section length # @return [Integer] - define_field_before :block_len2, :section_len, Types::Int64, - default: SECTION_LEN_UNDEFINED + define_attr_before :block_len2, :section_len, BinStruct::Int64, + default: SECTION_LEN_UNDEFINED # @!attribute options - # @return [Types::String] - define_field_before :block_len2, :options, Types::String + # @return [BinStruct::String] + define_attr_before :block_len2, :options, BinStruct::String # @param [Hash] options # @option options [:little, :big] :endian set block endianness @@ -135,12 +135,12 @@ def add_unknown_block(block) def force_endianness(endian) @endian = endian %i[type block_len magic block_len2].each do |attr| - self[attr] = Types::Int32.new(0, endian).read(self[attr].to_s) + self[attr] = BinStruct::Int32.new(value: 0, endian: endian).read(self[attr].to_s) end %i[ver_major ver_minor].each do |attr| - self[attr] = Types::Int16.new(0, endian).read(self[attr].to_s) + self[attr] = BinStruct::Int16.new(value: 0, endian: endian).read(self[attr].to_s) end - self[:section_len] = Types::Int64.new(0, endian).read(self[:section_len].to_s) + self[:section_len] = BinStruct::Int64.new(value: 0, endian: endian).read(self[:section_len].to_s) end # Check io contains a SHB diff --git a/lib/packetgen/pcapng/spb.rb b/lib/packetgen/pcapng/spb.rb index bd556fe..dd444ea 100644 --- a/lib/packetgen/pcapng/spb.rb +++ b/lib/packetgen/pcapng/spb.rb @@ -29,10 +29,10 @@ class SPB < Block # @!attribute orig_len # 32-bit original length # @return [Integer] - define_field_before :block_len2, :orig_len, Types::Int32, default: 0 + define_attr_before :block_len2, :orig_len, BinStruct::Int32, default: 0 # @!attribute data - # @return [Types::String] - define_field_before :block_len2, :data, Types::String + # @return [BinStruct::String] + define_attr_before :block_len2, :data, BinStruct::String # @param [Hash] options # @option options [:little, :big] :endian set block endianness diff --git a/lib/packetgen/pcapng/unknown_block.rb b/lib/packetgen/pcapng/unknown_block.rb index 0c55519..95e9017 100644 --- a/lib/packetgen/pcapng/unknown_block.rb +++ b/lib/packetgen/pcapng/unknown_block.rb @@ -20,8 +20,8 @@ class UnknownBlock < Block attr_accessor :section # @!attribute body - # @return [Types::String] - define_field_before :block_len2, :body, Types::String + # @return [BinStruct::String] + define_attr_before :block_len2, :body, BinStruct::String # @option options [:little, :big] :endian set block endianness # @option options [Integer] :type diff --git a/packetgen.gemspec b/packetgen.gemspec index 4897444..271b593 100644 --- a/packetgen.gemspec +++ b/packetgen.gemspec @@ -38,8 +38,9 @@ Gem::Specification.new do |spec| spec.required_ruby_version = '>= 2.7.0' + spec.add_dependency 'bin_struct', '>=0.2.0' + spec.add_dependency 'digest-crc', '~> 0' spec.add_dependency 'interfacez', '~>1.0' spec.add_dependency 'pcaprub', '~>0.13.0' spec.add_dependency 'rasn1', '~>0.13', '>=0.13.1' - spec.add_dependency 'digest-crc', '~> 0' end diff --git a/spec/header/arp_spec.rb b/spec/header/arp_spec.rb index 739feaa..952da76 100644 --- a/spec/header/arp_spec.rb +++ b/spec/header/arp_spec.rb @@ -152,7 +152,7 @@ module Header arp = ARP.new str = arp.inspect expect(str).to be_a(String) - (arp.fields - %i(body)).each do |attr| + (arp.attributes - %i(body)).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/asn1_base_spec.rb b/spec/header/asn1_base_spec.rb index 704c3c4..e868344 100644 --- a/spec/header/asn1_base_spec.rb +++ b/spec/header/asn1_base_spec.rb @@ -8,8 +8,8 @@ module Header describe ASN1Base do class TestBase2 < Base - define_field :field1, Types::Int8 - define_field :field2, Types::Int8 + define_attr :field1, BinStruct::Int8 + define_attr :field2, BinStruct::Int8 end class ASN1ToBind < ASN1Base diff --git a/spec/header/base_spec.rb b/spec/header/base_spec.rb index 5877402..41777e7 100644 --- a/spec/header/base_spec.rb +++ b/spec/header/base_spec.rb @@ -5,15 +5,15 @@ module PGTest class Base < PacketGen::Header::Base - define_field :field1, PacketGen::Types::Int8 - define_field :field2, PacketGen::Types::Int8 - define_field :body, PacketGen::Types::String + define_attr :field1, BinStruct::Int8 + define_attr :field2, BinStruct::Int8 + define_attr :body, BinStruct::String end PacketGen::Header.add_class Base class ToBind < PacketGen::Header::Base - define_field :field, PacketGen::Types::Int32, default: 1 - define_field :str, PacketGen::Types::String + define_attr :field, BinStruct::Int32, default: 1 + define_attr :str, BinStruct::String def added_to_packet(_packet) $global_var = true end @@ -68,7 +68,7 @@ module Header it 'binds a header using procs' do PGTest::Base.bind PGTest::ToBind, procs: [->(h) { h.field1 = 42 }, - ->(h) { h.field1 == 42 && Types::Int32.new.read(h.body[0..3]).to_i > 0 }] + ->(h) { h.field1 == 42 && BinStruct::Int32.new.read(h.body[0..3]).to_i > 0 }] expect(PGTest::Base).to know_header(PGTest::ToBind).with(field1: 42, body: [1].pack('N')) pkt = Packet.new.add('PGTest::Base').add('PGTest::ToBind') @@ -86,7 +86,7 @@ module Header pkt3 = Packet.parse(pkt.to_s, first_header: 'PGTest::Base') expect(pkt3.is?('Base')).to be(true) expect(pkt3.is?('PGTest::ToBind')).to be(false) - expect(pkt3.base[:body]).to be_a(Types::String) + expect(pkt3.base[:body]).to be_a(BinStruct::String) end it 'binds a header with multiple possibility (multiple calls to .bind)' do @@ -115,7 +115,7 @@ module Header context 'adding header to a packet' do before(:all) do class PacketTest < Base - define_field :field, Types::Int8, default: ->(h) { h.packet ? h.packet.ip.tos : 255 } + define_attr :field, BinStruct::Int8, default: ->(h) { h.packet ? h.packet.ip.tos : 255 } end Header.add_class PacketTest IP.bind PacketTest, protocol: 255 @@ -137,7 +137,7 @@ class PacketTest < Base context 'when parsing a packet' do before(:all) do class PacketTest < Base - define_field :field, Types::Int8, builder: ->(h, _) { lt = h.packet && (h.packet.ip.tos > 0) ? Types::Int16 : Types::Int8; lt.new } + define_attr :field, BinStruct::Int8, builder: ->(h, _) { lt = h.packet && (h.packet.ip.tos > 0) ? BinStruct::Int16 : BinStruct::Int8; lt.new } end Header.add_class PacketTest IP.bind PacketTest, protocol: 255 @@ -149,7 +149,7 @@ class PacketTest < Base pkt = Packet.parse(str) expect(pkt.is?('IP')).to be(true) expect(pkt.is?('PacketTest')).to be(true) - expect(pkt.packettest[:field]).to be_a(Types::Int16) + expect(pkt.packettest[:field]).to be_a(BinStruct::Int16) end end diff --git a/spec/header/dns/name_spec.rb b/spec/header/dns/name_spec.rb index 803fe42..7abc219 100644 --- a/spec/header/dns/name_spec.rb +++ b/spec/header/dns/name_spec.rb @@ -29,7 +29,7 @@ class DNS offset = DNS.new.sz str = binary("\x03www" + [0xc0, offset].pack('C2')) - name.read str + name.read(str) expect(name.to_human).to eq('www.example.net.') end end diff --git a/spec/header/dns/qdsection_spec.rb b/spec/header/dns/qdsection_spec.rb index 7562a59..0b6adcc 100644 --- a/spec/header/dns/qdsection_spec.rb +++ b/spec/header/dns/qdsection_spec.rb @@ -8,7 +8,7 @@ class DNS before(:each) do @dns = DNS.new - @counter = Types::Int32.new(0) + @counter = BinStruct::Int32.new(value: 0) @section = QDSection.new(@dns, @counter) end @@ -17,11 +17,11 @@ class DNS q1 = Question.new(@dns, name: 'example.org') q2 = Question.new(@dns, name: 'example.com.') str = q1.to_s << q2.to_s - @section.read str + @section.read(str) expect(@section.size).to eq(0) - @counter.read 2 - @section.read str + @counter.from_human(2) + @section.read(str) expect(@section.size).to eq(2) expect(@section.all? { |q| q.is_a? Question }).to be(true) expect(@section[0].to_s).to eq(q1.to_s) diff --git a/spec/header/dns/rrsection_spec.rb b/spec/header/dns/rrsection_spec.rb index bf9f8ce..b6bfdae 100644 --- a/spec/header/dns/rrsection_spec.rb +++ b/spec/header/dns/rrsection_spec.rb @@ -8,7 +8,7 @@ class DNS before(:each) do @dns = DNS.new - @counter = Types::Int32.new(0) + @counter = BinStruct::Int32.new(value: 0) @section = RRSection.new(@dns, @counter) end @@ -88,11 +88,11 @@ class DNS rr1 = RR.new(@dns, name: 'example.org.', type: 'CNAME', rdata: 'example.com.') rr2 = RR.new(@dns, name: 'example.org.', rdata: IPAddr.new('10.0.0.1').hton) str = rr1.to_s << rr2.to_s - @section.read str + @section.read(str) expect(@section.size).to eq(0) - @counter.read 2 - @section.read str + @counter.from_human(2) + @section.read(str) expect(@section.size).to eq(2) expect(@section.all? { |rr| rr.is_a? RR }).to be(true) expect(@section[0].to_s).to eq(rr1.to_s) diff --git a/spec/header/dns_spec.rb b/spec/header/dns_spec.rb index 76fde3f..c600ebf 100644 --- a/spec/header/dns_spec.rb +++ b/spec/header/dns_spec.rb @@ -200,7 +200,7 @@ module Header dns = DNS.new str = dns.inspect expect(str).to be_a(String) - (dns.fields - %i(u16) + %i(flags opcode rcode)).each do |attr| + (dns.attributes - %i(u16) + %i(flags opcode rcode)).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/dot11_spec.rb b/spec/header/dot11_spec.rb index c46bc9c..bcabbe1 100644 --- a/spec/header/dot11_spec.rb +++ b/spec/header/dot11_spec.rb @@ -9,7 +9,7 @@ module Header ppi.calc_length expect(ppi.length).to eq(8) - # Force length greater then ppi_fields real length to enable reading + # Force length greater then ppi_attributes.real length to enable reading ppi.length = 1_000 ppi.ppi_fields = '12345' ppi.calc_length # Compute real length @@ -25,7 +25,7 @@ module Header rt.calc_length expect(rt.length).to eq(8) - # Force length greater then radio_fields real length to enable reading + # Force length greater then radio_attributes.real length to enable reading rt.length = 1_000 rt.radio_fields = '123456' rt.calc_length # Compute real length @@ -75,7 +75,7 @@ module Header expect(dot11.qos_ctrl).to eq(0) expect(dot11.ht_ctrl).to eq(0) expect(dot11.fcs).to eq(0) - expect(dot11.fields.size).to eq(11) + expect(dot11.attributes.size).to eq(11) end it 'accepts options' do diff --git a/spec/header/eap_spec.rb b/spec/header/eap_spec.rb index eb57a75..129ced3 100644 --- a/spec/header/eap_spec.rb +++ b/spec/header/eap_spec.rb @@ -148,7 +148,7 @@ module Header it 'returns a string with type and vendor fields' do eap = EAP.new(code: 'Request', type: 254) str = eap.inspect - (eap.fields - %i[body]).each do |attr| + (eap.attributes - %i[body]).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/eth_spec.rb b/spec/header/eth_spec.rb index b669833..4a3781b 100644 --- a/spec/header/eth_spec.rb +++ b/spec/header/eth_spec.rb @@ -121,7 +121,7 @@ module Header eth = Eth.new str = eth.inspect expect(str).to be_a(String) - (eth.fields - %i(body)).each do |attr| + (eth.attributes - %i(body)).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/gre_spec.rb b/spec/header/gre_spec.rb index 79a3efa..e987cab 100644 --- a/spec/header/gre_spec.rb +++ b/spec/header/gre_spec.rb @@ -159,7 +159,7 @@ module Header gre.u16 = 0xb000 str = gre.inspect expect(str).to be_a(String) - (gre.fields - %i(body)).each do |attr| + (gre.attributes - %i(body)).each do |attr| expect(str).to include(attr.to_s) end end @@ -168,12 +168,12 @@ module Header gre.u16 = 0x8000 str = gre.inspect expect(str).to be_a(String) - fields = gre.fields - %i[body] - fields -= gre.optional_fields.reject { |f| gre.present?(f) } - fields.each do |attr| + attributes = gre.attributes - %i[body] + attributes -= gre.optional_attributes.reject { |f| gre.present?(f) } + attributes.each do |attr| expect(str).to include(attr.to_s) end - gre.optional_fields.reject { |f| gre.present?(f) }.each do |attr| + gre.optional_attributes.reject { |f| gre.present?(f) }.each do |attr| expect(str).to_not include(attr.to_s) end end diff --git a/spec/header/http/headers_spec.rb b/spec/header/http/headers_spec.rb index cc2fd68..1d460ef 100644 --- a/spec/header/http/headers_spec.rb +++ b/spec/header/http/headers_spec.rb @@ -8,8 +8,8 @@ module HTTP let(:hsh) { { 'Content-Type' => 'text/html', 'Connection' => 'keep-alive' } } let(:encoded_headers) { "Content-Type: text/html\r\nConnection: keep-alive\r\n\r\n" } - it 'is Fieldable' do - Headers < Types::Fieldable + it 'is BinStruct::Structable' do + Headers < BinStruct::Structable end describe '#read' do diff --git a/spec/header/icmp_spec.rb b/spec/header/icmp_spec.rb index f69920e..c3cfe6a 100644 --- a/spec/header/icmp_spec.rb +++ b/spec/header/icmp_spec.rb @@ -86,7 +86,7 @@ module Header icmp = ICMP.new str = icmp.inspect expect(str).to be_a(String) - (icmp.fields - %i(body)).each do |attr| + (icmp.attributes - %i(body)).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/icmpv6_spec.rb b/spec/header/icmpv6_spec.rb index 338e390..c9042ee 100644 --- a/spec/header/icmpv6_spec.rb +++ b/spec/header/icmpv6_spec.rb @@ -96,7 +96,7 @@ module Header icmpv6 = ICMPv6.new str = icmpv6.inspect expect(str).to be_a(String) - (icmpv6.fields - %i(body)).each do |attr| + (icmpv6.attributes - %i(body)).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/igmp_spec.rb b/spec/header/igmp_spec.rb index 09d91a4..05097ef 100644 --- a/spec/header/igmp_spec.rb +++ b/spec/header/igmp_spec.rb @@ -85,7 +85,7 @@ module Header igmp = IGMP.new str = igmp.inspect expect(str).to be_a(String) - (igmp.fields - %i(body)).each do |attr| + (igmp.attributes - %i(body)).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/igmpv3_spec.rb b/spec/header/igmpv3_spec.rb index 368f9f6..ecba89a 100644 --- a/spec/header/igmpv3_spec.rb +++ b/spec/header/igmpv3_spec.rb @@ -79,7 +79,7 @@ module Header igmp = IGMPv3.new str = igmp.inspect expect(str).to be_a(String) - (igmp.fields - %i(body)).each do |attr| + (igmp.attributes - %i(body)).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/ipv6_spec.rb b/spec/header/ipv6_spec.rb index 9b3589d..f3c25b3 100644 --- a/spec/header/ipv6_spec.rb +++ b/spec/header/ipv6_spec.rb @@ -220,7 +220,7 @@ module Header ip = IPv6.new str = ip.inspect expect(str).to be_a(String) - (ip.fields - %i(body) + %i(version tclass flow_label)).each do |attr| + (ip.attributes - %i(body) + %i(version tclass flow_label)).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/mld_spec.rb b/spec/header/mld_spec.rb index fd407b8..7fddbef 100644 --- a/spec/header/mld_spec.rb +++ b/spec/header/mld_spec.rb @@ -50,7 +50,7 @@ module Header pkt = PacketGen.gen('IPv6', src: 'fe80::1', dst: 'ff02::1', hop: 1). add('IPv6::HopByHop'). add('ICMPv6', type: 130, code: 0) - pkt.ipv6_hopbyhop.options << { type: 'router_alert', value: Types::Int16.new(0).to_s } + pkt.ipv6_hopbyhop.options << { type: 'router_alert', value: BinStruct::Int16.new(value: 0).to_s } pkt.body = "\x00\x7f\x00\x00" + ([0] * 16).pack('C*') pkt.calc @@ -79,7 +79,7 @@ module Header mld = MLD.new str = mld.inspect expect(str).to be_a(String) - (mld.fields - %i(body)).each do |attr| + (mld.attributes - %i(body)).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/mldv2_spec.rb b/spec/header/mldv2_spec.rb index 6ff2d21..2065bbe 100644 --- a/spec/header/mldv2_spec.rb +++ b/spec/header/mldv2_spec.rb @@ -56,7 +56,7 @@ module MLDv2 pkt = PacketGen.gen('IPv6', src: 'fe80::1', dst: 'ff02::1', hop: 1). add('IPv6::HopByHop'). add('ICMPv6', type: 130, code: 0) - pkt.ipv6_hopbyhop.options << { type: 'router_alert', value: Types::Int16.new(0).to_s } + pkt.ipv6_hopbyhop.options << { type: 'router_alert', value: BinStruct::Int16.new(value: 0).to_s } pkt.body = "\x00\x7f\x00\x00" + ([0] * 16).pack('C*') + [1, 0x2000, 0, 0, 0, 0, 0, 0, 1].pack('Nn*') pkt.calc @@ -141,7 +141,7 @@ module MLDv2 mlq = MLDv2::MLQ.new str = mlq.inspect expect(str).to be_a(String) - (mlq.fields - %i(body)).each do |attr| + (mlq.attributes - %i(body)).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/ospfv2_spec.rb b/spec/header/ospfv2_spec.rb index aba7b8c..ef7990f 100644 --- a/spec/header/ospfv2_spec.rb +++ b/spec/header/ospfv2_spec.rb @@ -114,7 +114,7 @@ module Header ospf = OSPFv2.new str = ospf.inspect expect(str).to be_a(String) - (ospf.fields - %i(body)).each do |attr| + (ospf.attributes - %i(body)).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/ospfv3_spec.rb b/spec/header/ospfv3_spec.rb index 7d71625..51c56b7 100644 --- a/spec/header/ospfv3_spec.rb +++ b/spec/header/ospfv3_spec.rb @@ -110,7 +110,7 @@ module Header ospf = OSPFv3.new str = ospf.inspect expect(str).to be_a(String) - (ospf.fields - %i(body)).each do |attr| + (ospf.attributes - %i(body)).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/sctp/sack_chunk_spec.rb b/spec/header/sctp/sack_chunk_spec.rb index 80c422d..c4351f1 100644 --- a/spec/header/sctp/sack_chunk_spec.rb +++ b/spec/header/sctp/sack_chunk_spec.rb @@ -34,7 +34,7 @@ class SCTP data = SackChunk.new(options) options.each do |key, value| val = data.send(key) - val = val.map(&:to_human) if val.is_a?(Types::Array) + val = val.map(&:to_human) if val.is_a?(BinStruct::Array) expect(val).to eq(value) end end diff --git a/spec/header/tcp_option_spec.rb b/spec/header/tcp_option_spec.rb index 8fa8260..3e6e223 100644 --- a/spec/header/tcp_option_spec.rb +++ b/spec/header/tcp_option_spec.rb @@ -10,20 +10,20 @@ class TCP opt = Option.new expect(opt.kind).to eq(0) expect(opt[:length].value).to be(nil) - expect(opt[:value]).to be_a(Types::String) + expect(opt[:value]).to be_a(BinStruct::String) end it 'infers correct Int subclass when value is an integer' do opt = Option.new(length: 3, value: 0x80) - expect(opt[:value]).to be_a(Types::Int8) + expect(opt[:value]).to be_a(BinStruct::Int8) expect(opt.value).to eq(0x80) opt = Option.new(length: 4, value: 0x8000) - expect(opt[:value]).to be_a(Types::Int16) + expect(opt[:value]).to be_a(BinStruct::Int16) expect(opt.value).to eq(0x8000) opt = Option.new(length: 6, value: 0x80000000) - expect(opt[:value]).to be_a(Types::Int32) + expect(opt[:value]).to be_a(BinStruct::Int32) expect(opt.value).to eq(0x80000000) end diff --git a/spec/header/tcp_spec.rb b/spec/header/tcp_spec.rb index 84fa74a..0171032 100644 --- a/spec/header/tcp_spec.rb +++ b/spec/header/tcp_spec.rb @@ -167,7 +167,7 @@ module Header tcp = TCP.new str = tcp.inspect expect(str).to be_a(String) - (tcp.fields - %i(body) + %i(data_offset reserved flags)).each do |attr| + (tcp.attributes - %i(body) + %i(data_offset reserved flags)).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/udp_spec.rb b/spec/header/udp_spec.rb index abbc6e0..7841e93 100644 --- a/spec/header/udp_spec.rb +++ b/spec/header/udp_spec.rb @@ -121,7 +121,7 @@ module Header udp = UDP.new str = udp.inspect expect(str).to be_a(String) - (udp.fields - %i(body)).each do |attr| + (udp.attributes - %i(body)).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header_spec.rb b/spec/header_spec.rb index 1f8e4c3..5828b8b 100644 --- a/spec/header_spec.rb +++ b/spec/header_spec.rb @@ -2,8 +2,8 @@ module PGTestModule class TestHeader < PacketGen::Header::Base - define_field :field1, PacketGen::Types::Int32 - define_field :field2, PacketGen::Types::Int32 + define_attr :field1, BinStruct::Int32 + define_attr :field2, BinStruct::Int32 end end diff --git a/spec/inspect_spec.rb b/spec/inspect_spec.rb index d4d2d5f..d51ff96 100644 --- a/spec/inspect_spec.rb +++ b/spec/inspect_spec.rb @@ -3,28 +3,28 @@ module PacketGen describe Inspect do describe '.inspect_attribute' do - it 'return a formatted string for a Types::Int attribute' do - int8 = Types::Int8.new(52) + it 'return a formatted string for a BinStruct::Int attribute' do + int8 = BinStruct::Int8.new(value: 52) inspect = Inspect.inspect_attribute('my_int8', int8) expect(inspect).to eq(" Int8 my_int8: 52 (0x34)\n") - int16 = Types::Int16.new(45) + int16 = BinStruct::Int16.new(value: 45) inspect = Inspect.inspect_attribute('my_int16', int16) expect(inspect).to eq(" Int16 my_int16: 45 (0x002d)\n") - enum = Types::Int32leEnum.new({'one' => 1, 'two' => 2}) + enum = BinStruct::Int32leEnum.new(enum: {'one' => 1, 'two' => 2}) inspect = Inspect.inspect_attribute('my_enum', enum) expect(inspect).to eq(" Int32leEnum my_enum: one (0x00000001)\n") end it 'return a formatted string for an attribute responding to #to_human' do - oui = Types::OUI.new(b2: 0x45, b1: 0xfe, b0: 0x12) + oui = BinStruct::OUI.new(b2: 0x45, b1: 0xfe, b0: 0x12) inspect = Inspect.inspect_attribute('my_oui', oui) expect(inspect).to eq(" OUI my_oui: 45:fe:12\n") end it 'return a formatted string for another attribute type' do - str = Types::String.new.read('abc') + str = BinStruct::String.new.read('abc') inspect = Inspect.inspect_attribute('my_str', str) expect(inspect).to eq(" String my_str: \"abc\"\n") end diff --git a/spec/packet_spec.rb b/spec/packet_spec.rb index b93bcaa..a8e5dac 100644 --- a/spec/packet_spec.rb +++ b/spec/packet_spec.rb @@ -187,7 +187,7 @@ module PacketGen expect(@pkt.ip(2).protocol).to eq(0) end - it 'sets provided fields in arguments' do + it 'sets provided attributes.in arguments' do @pkt.add('TCP', sport: 12_345, dport: 5_678) expect(@pkt.tcp.sport).to eq(12_345) expect(@pkt.tcp.dport).to eq(5_678) @@ -210,7 +210,7 @@ module PacketGen it 'may set a IntString' do class AddIntStringTest < Header::Base - define_field :field, Types::IntString + define_attr :field, BinStruct::IntString end Header.add_class AddIntStringTest pkt = Packet.gen('AddIntStringTest', field: 'This is a string') @@ -286,7 +286,7 @@ class AddIntStringTest < Header::Base expect(packet.ip.checksum).to eq(0x75df) end - it 'does not calculate calculatable fields if calc is false', :sudo do + it 'does not calculate calculatable attributes.if calc is false', :sudo do Thread.new { sleep 0.1; pkt.to_w('lo', calc: false) } packets = Packet.capture(iface: 'lo', max: 1, filter: 'ether dst ff:ff:ff:ff:ff:ff', diff --git a/spec/pcapng/file_spec.rb b/spec/pcapng/file_spec.rb index e168482..6d408a2 100644 --- a/spec/pcapng/file_spec.rb +++ b/spec/pcapng/file_spec.rb @@ -4,13 +4,13 @@ require_relative '../spec_helper' require_relative 'file_spec_helper' -# Clear options fields from a PcapNG::Block +# Clear options attributes.from a PcapNG::Block def block_clear_options(blk) blk.options = '' blk.recalc_block_len end -# Clear options fields from a PcapNG::File +# Clear options attributes.from a PcapNG::File def file_clear_options(file) file.sections.each do |sec| block_clear_options(sec) From 0c8c9250fb71cc7e8fc8f772a2f3fee2adb0288c Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Sun, 21 Jul 2024 15:20:16 +0200 Subject: [PATCH 04/19] Rakefile: add rubocop tasks --- Rakefile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Rakefile b/Rakefile index a7ff991..11beff5 100644 --- a/Rakefile +++ b/Rakefile @@ -21,3 +21,12 @@ YARD::Rake::YardocTask.new do |t| t.options = ['--no-private'] t.files = ['lib/**/*.rb', '-', 'LICENSE'] end + +begin + require 'rubocop/rake_task' + + RuboCop::RakeTask.new do |task| + task.patterns = ['lib/**/*.rb'] + end +rescue LoadError # rubocop:disable Lint/SuppressedException +end From 09e0a5464b6db346a9d36d26c7843d6e40fa5ddf Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Sun, 21 Jul 2024 16:21:42 +0200 Subject: [PATCH 05/19] Fix README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8d2ac27..f2c0ced 100644 --- a/README.md +++ b/README.md @@ -107,14 +107,14 @@ PacketGen.write('more_packets.pcapng', packets) ``` ### Add custom header/protocol -Since v1.1.0, PacketGen permits adding your own header classes. +PacketGen permits adding your own header classes. First, define the new header class. For example: ```ruby module MyModule class MyHeader < PacketGen::Header::Base - define_field :field1, PacketGen::Types::Int32 - define_field :field2, PacketGen::Types::Int32 + define_attr :field1, BinStruct::Int32 + define_attr :field2, BinStruct::Int32 end end ``` @@ -135,8 +135,8 @@ PacketGen::Header::IP.bind_header MyModule::MyHeader, protocol: 254 And use it: ```ruby -pkt = Packet.gen('IP').add('MyHeader', field1: 0x12345678) -pkt.myheader.field2.read 0x01 +pkt = Packet.gen('IP').add('MyHeader', field1: 0x12345678, field2: 0x87654321) +pkt.to_w # Send it on wire ``` ## Interactive console From 4df8c76239d334eab8810203b5b7c17ee61d0a61 Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Wed, 24 Jul 2024 11:41:49 +0200 Subject: [PATCH 06/19] Clean up packet class and add some sepcs --- lib/packetgen/packet.rb | 74 +++++++++++++++++++++++------------------ spec/packet_spec.rb | 33 ++++++++++++++++++ 2 files changed, 75 insertions(+), 32 deletions(-) diff --git a/lib/packetgen/packet.rb b/lib/packetgen/packet.rb index 180ee5b..6ea0ee4 100644 --- a/lib/packetgen/packet.rb +++ b/lib/packetgen/packet.rb @@ -61,20 +61,20 @@ class Packet # @param [Hash] options specific options for +protocol+ # @return [Packet] def self.gen(protocol, options={}) - self.new.add protocol, options + self.new.add(protocol, options) end # Parse a binary string and generate a Packet from it. # # auto-detect first header - # Packet.parse str + # Packet.parse(str) # # force decoding a Ethernet header for first header - # Packet.parse str, first_header: 'Eth' + # Packet.parse(str, first_header: 'Eth') # @param [String] binary_str # @param [String,nil] first_header First protocol header. +nil+ means discover it! # @return [Packet] # @raise [ArgumentError] +first_header+ is an unknown header def self.parse(binary_str, first_header: nil) - new.parse binary_str, first_header: first_header + new.parse(binary_str, first_header: first_header) end # Capture packets from wire. @@ -142,7 +142,7 @@ def add(protocol, options={}) # options[:packet]= self is speedier than options.merge(packet: self) options[:packet] = self header = klass.new(options) - add_header header + add_header(header) self end @@ -159,7 +159,7 @@ def insert(prev, protocol, options={}) # options[:packet]= self is speedier than options.merge(packet: self) options[:packet] = self header = klass.new(options) - add_header header, previous_header: prev + add_header(header, previous_header: prev) idx = headers.index(prev) + 1 headers[idx, 0] = header header[:body] = nxt @@ -173,7 +173,7 @@ def insert(prev, protocol, options={}) # @return [Boolean] # @raise [ArgumentError] unknown protocol def is?(protocol) - klass = check_protocol protocol + klass = check_protocol(protocol) headers.any?(klass) end @@ -181,7 +181,7 @@ def is?(protocol) # @return [void] def calc_checksum headers.reverse_each do |header| - header.calc_checksum if header.respond_to? :calc_checksum + header.calc_checksum if header.respond_to?(:calc_checksum) end end @@ -189,21 +189,24 @@ def calc_checksum # @return [void] def calc_length headers.reverse_each do |header| - header.calc_length if header.respond_to? :calc_length + header.calc_length if header.respond_to?(:calc_length) end end # Recalculate all calculatable fields (for now: length and checksum) # @return [void] + # @author LemonTree55 def calc - calc_length - calc_checksum + headers.reverse_each do |header| + header.calc_length if header.respond_to?(:calc_length) + header.calc_checksum if header.respond_to?(:calc_checksum) + end end # Get packet body # @return [Types] def body - last_header[:body] if last_header.respond_to? :body + last_header[:body] if last_header.respond_to?(:body) end # Set packet body @@ -229,7 +232,7 @@ def to_f(filename) alias write to_f # Send packet on wire. Use first header +#to_w+ method. - # @param [String] iface interface name. Default to first non-loopback interface + # @param [String,nil] iface interface name. Default to first non-loopback interface # @param [Boolean] calc if +true+, call {#calc} on packet before sending it. # @param [Integer] number number of times to send the packets # @param [Integer,Float] interval time, in seconds, between sending 2 packets @@ -239,12 +242,12 @@ def to_f(filename) def to_w(iface=nil, calc: true, number: 1, interval: 1) iface ||= PacketGen.default_iface - if first_header.respond_to? :to_w + if first_header.respond_to?(:to_w) self.calc if calc number.times do first_header.to_w(iface) - sleep interval if number > 1 + sleep(interval) if number > 1 end else type = first_header.protocol_name @@ -257,12 +260,12 @@ def to_w(iface=nil, calc: true, number: 1, interval: 1) # @param [Boolean] parsing set to +true+ to not update last current header field # from binding with first other's one. Use only when current header field # has its value set accordingly. - # @return [self] +self+ with new headers from +other+ + # @return [self] +self+ updated with new headers from +other+ # @raise [BindingError] do not known how to encapsulate # @since 1.1.0 def encapsulate(other, parsing: false) other.headers.each_with_index do |h, i| - add_header h, parsing: i.positive? || parsing + add_header(h, parsing: i.positive? || parsing) end end @@ -286,8 +289,8 @@ def decapsulate(*hdrs) # Parse a binary string and populate Packet from it. # @param [String] binary_str - # @param [String,nil] first_header First protocol header. +nil+ means discover it! - # @return [Packet] self + # @param [String,nil] first_header First protocol header name. +nil+ means discover it! + # @return [self] # @raise [ParseError] +first_header+ is an unknown header # @raise [BindingError] unknwon binding between some headers def parse(binary_str, first_header: nil) @@ -299,7 +302,7 @@ def parse(binary_str, first_header: nil) raise ParseError, "cannot identify first header in string: #{binary_str.inspect}" if first_header.nil? end - add first_header + add(first_header) headers[-1, 1] = last_header.read(binary_str) # Decode upper headers recursively @@ -317,12 +320,14 @@ def inspect str << Inspect.inspect_body(body) end + # Check equality at binary level # @param [Packet] other # @return [Boolean] def ==(other) to_s == other.to_s end + # +true+ is {#==} is +true+ with another packet, or if +other+ is a protocol name String, whose protocol is in Packet. # @param [Packet] other # @return [Boolean] # @since 3.1.2 @@ -331,7 +336,7 @@ def ===(other) when PacketGen::Packet self == other when String - is? other + is?(other) else false end @@ -363,7 +368,7 @@ def reply def initialize_copy(_other) @headers = headers.map(&:dup) headers.each do |header| - add_magic_header_method header + add_magic_header_method(header) end invalidate_header_cache end @@ -410,17 +415,20 @@ def next_header(hdr) end # @overload header(klass, layer=1) + # Get a header given its class and its layer (example: IP-in-IP encapsulation) # @param [Class] klass # @param [Integer] layer # @overload header(klass, options={}) + # Get a header given its class, and set some attributes # @param [String] klass - # @param [Hash] options - # @raise [ArgumentError] unknown option - # @return [Header::Base] + # @param [Hash] options attributes to set + # @raise [ArgumentError] unknown attribute + # @return [Header::Base,nil] def header(klass, arg) layer = arg.is_a?(Integer) ? arg : 1 header = find_header(klass, layer) - return header unless arg.is_a? Hash + return nil if header.nil? + return header unless arg.is_a?(Hash) arg.each do |key, value| raise ArgumentError, "unknown #{key} attribute for #{klass}" unless header.respond_to?(:"#{key}=") @@ -434,12 +442,14 @@ def header(klass, arg) # Get header from cache, or find it in packet # @param [Class] klass # @param [Integer] layer - # @return [Header::Base] + # @return [Header::Base,nil] def find_header(klass, layer) header = fetch_header_from_cache(klass, layer) return header if header - header = headers.select { |h| h.is_a? klass }[layer - 1] + header = headers.select { |h| h.is_a?(klass) }[layer - 1] + return nil if header.nil? + add_header_to_cache(header, klass, layer) header end @@ -468,9 +478,9 @@ def add_header(header, previous_header: nil, parsing: false) header.packet = self headers << header unless previous_header - return if respond_to? header.method_name + return if respond_to?(header.method_name) - add_magic_header_method header + add_magic_header_method(header) end # Bind +header+ to +prev_header+. @@ -497,7 +507,7 @@ def add_magic_header_method(header) # Try to guess header from +binary_str+ # @param [String] binary_str - # @return [String] header/protocol name + # @return [String,nil] header/protocol name, or nil if cannot be guessed def guess_first_header(binary_str) first_header = nil Header.all.each do |hklass| @@ -529,7 +539,7 @@ def decode_bottom_up nheader = nheader.read(last_known_hdr.body) next unless nheader.parse? - add_header nheader, parsing: true + add_header(nheader, parsing: true) break if last_header == last_known_hdr end end diff --git a/spec/packet_spec.rb b/spec/packet_spec.rb index a8e5dac..de52b3d 100644 --- a/spec/packet_spec.rb +++ b/spec/packet_spec.rb @@ -220,6 +220,39 @@ class AddIntStringTest < Header::Base end end + describe 'protocol magical method' do + let(:pkt) { Packet.gen('Eth').add('IP').add('IP').add('TCP') } + + it 'gets header from given protocol' do + tcp = pkt.tcp + expect(tcp).to eq(pkt.headers[-1]) + expect(tcp).to be_a(Header::TCP) + end + + it 'gets header from given protocol and layer' do + ip1 = pkt.ip + ip2 = pkt.ip(2) + expect(ip1).not_to eq(ip2) + expect(ip1).to eq(pkt.headers[1]) + expect(ip2).to eq(pkt.headers[2]) + end + + it 'gets nil if layer is too big' do + bad_ip = pkt.ip(55) + expect(bad_ip).to be_nil + end + + it 'raises if protocol is not in packet' do + expect { pkt.udp }.to raise_error(NoMethodError) + end + + it 'sets header attributes when feeding with a Hash' do + pkt.tcp(dport: 143, sport: 45_555) + expect(pkt.tcp.dport).to eq(143) + expect(pkt.tcp.sport).to eq(45_555) + end + end + describe '#is?' do before(:each) do @pkt = Packet.gen('IP') From 7d22e6b83b9a493b74de1d9bd6ca206ad3e3ebdb Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Wed, 24 Jul 2024 12:09:30 +0200 Subject: [PATCH 07/19] PcapNG: factorize code in Block#initialize --- lib/packetgen/pcapng/block.rb | 19 ++++++++++--------- lib/packetgen/pcapng/epb.rb | 10 ++++------ lib/packetgen/pcapng/idb.rb | 8 +++----- lib/packetgen/pcapng/shb.rb | 8 +++----- lib/packetgen/pcapng/spb.rb | 12 +++++------- lib/packetgen/pcapng/unknown_block.rb | 19 ++++--------------- 6 files changed, 29 insertions(+), 47 deletions(-) diff --git a/lib/packetgen/pcapng/block.rb b/lib/packetgen/pcapng/block.rb index 865afa4..2d3c4bb 100644 --- a/lib/packetgen/pcapng/block.rb +++ b/lib/packetgen/pcapng/block.rb @@ -22,13 +22,15 @@ class Block < BinStruct::Struct # 32-bit block length # @return [Integer] define_attr :block_len, BinStruct::Int32 - # @!attribute block_len + # @!attribute block_len2 # 32-bit block length # @return [Integer] define_attr :block_len2, BinStruct::Int32 def initialize(options={}) super + endianness(options[:endian] || :little) + recalc_block_len end # Has this block option? @@ -38,7 +40,7 @@ def options? @attributes.key?(:options) && @attributes[:options].sz.positive? end - # Calculate block length and update :block_len and block_len2 fields + # Calculate block length and update +block_len+ and +block_len2+ fields # @return [void] def recalc_block_len len = attributes.map { |f| @attributes[f].to_s }.join.size @@ -46,20 +48,19 @@ def recalc_block_len end # Pad given field to 32 bit boundary, if needed - # @param [Array] attributes.block attributes.to pad + # @param [Array] fields fields to pad # @return [void] + # @author LemonTree55 def pad_field(*fields) fields.each do |field| obj = @attributes[field] - pad_size = (obj.sz % 4).zero? ? 0 : (4 - (obj.sz % 4)) - obj << "\x00" * pad_size + obj << "\x00" * -(obj.sz % -4) end end private # Set the endianness for the various Int classes handled by self. - # Must be called by all subclass #initialize method. # @param [:little, :big] endian # @return [:little, :big] returns endian def endianness(endian) @@ -75,19 +76,19 @@ def check_len_coherency end def to_io(str_or_io) - return str_or_io if str_or_io.respond_to? :read + return str_or_io if str_or_io.respond_to?(:read) StringIO.new(force_binary(str_or_io.to_s)) end def remove_padding(io, data_len) data_pad_len = (4 - (data_len % 4)) % 4 - io.read data_pad_len + io.read(data_pad_len) data_pad_len end def read_blocklen2_and_check(io) - self[:block_len2].read io.read(4) + self[:block_len2].read(io.read(4)) check_len_coherency end end diff --git a/lib/packetgen/pcapng/epb.rb b/lib/packetgen/pcapng/epb.rb index d6a6592..d430f4b 100644 --- a/lib/packetgen/pcapng/epb.rb +++ b/lib/packetgen/pcapng/epb.rb @@ -74,8 +74,6 @@ class EPB < Block # @option options [Integer] :block_len2 block total length def initialize(options={}) super - endianness(options[:endian] || :little) - recalc_block_len self.type = options[:type] || PcapNG::EPB_TYPE.to_i end @@ -87,9 +85,9 @@ def read(str_or_io) return self if io.eof? %i[type block_len interface_id tsh tsl cap_len orig_len].each do |attr| - self[attr].read io.read(self[attr].sz) + self[attr].read(io.read(self[attr].sz)) end - self[:data].read io.read(self.cap_len) + self[:data].read(io.read(self.cap_len)) read_options(io) read_blocklen2_and_check(io) @@ -115,7 +113,7 @@ def timestamp=(time) # Return the object as a String # @return [String] def to_s - pad_field :data, :options + pad_field(:data, :options) recalc_block_len super end @@ -133,7 +131,7 @@ def ts_resol def read_options(io) data_pad_len = remove_padding(io, self.cap_len) options_len = self.block_len - self.cap_len - data_pad_len - MIN_SIZE - self[:options].read io.read(options_len) + self[:options].read(io.read(options_len)) end end end diff --git a/lib/packetgen/pcapng/idb.rb b/lib/packetgen/pcapng/idb.rb index 40fdba4..6dd2a62 100644 --- a/lib/packetgen/pcapng/idb.rb +++ b/lib/packetgen/pcapng/idb.rb @@ -61,10 +61,8 @@ class IDB < Block # @option options [Integer] :block_len2 block total length def initialize(options={}) super - endianness(options[:endian] || :little) @packets = [] @options_decoded = false - recalc_block_len self.type = options[:type] || PcapNG::IDB_TYPE.to_i end @@ -76,9 +74,9 @@ def read(str_or_io) return self if io.eof? %i[type block_len link_type reserved snaplen].each do |attr| - self[attr].read io.read(self[attr].sz) + self[attr].read(io.read(self[attr].sz)) end - self[:options].read io.read(self.block_len - MIN_SIZE) + self[:options].read(io.read(self.block_len - MIN_SIZE)) read_blocklen2_and_check(io) self @@ -107,7 +105,7 @@ def ts_resol(force: false) # Return the object as a String # @return [String] def to_s - pad_field :options + pad_field(:options) recalc_block_len super << @packets.map(&:to_s).join end diff --git a/lib/packetgen/pcapng/shb.rb b/lib/packetgen/pcapng/shb.rb index bf09108..b556d73 100644 --- a/lib/packetgen/pcapng/shb.rb +++ b/lib/packetgen/pcapng/shb.rb @@ -81,8 +81,6 @@ def initialize(options={}) super @interfaces = [] @unknown_blocks = [] - endianness(options[:endian] || :little) - recalc_block_len self.type = options[:type] || PcapNG::SHB_TYPE.to_i end @@ -93,9 +91,9 @@ def read(str_or_io) io = to_io(str_or_io) return self if io.eof? - self[:type].read check_shb(io) + self[:type].read(check_shb(io)) %i[block_len magic ver_major ver_minor section_len].each do |attr| - self[attr].read io.read(self[attr].sz) + self[attr].read(io.read(self[attr].sz)) end handle_magic_and_check(self[:magic].to_s) @@ -120,7 +118,7 @@ def to_s body = @interfaces.map(&:to_s).join self.section_len = body.size unless self.section_len == SECTION_LEN_UNDEFINED - pad_field :options + pad_field(:options) recalc_block_len super + body end diff --git a/lib/packetgen/pcapng/spb.rb b/lib/packetgen/pcapng/spb.rb index dd444ea..cc11441 100644 --- a/lib/packetgen/pcapng/spb.rb +++ b/lib/packetgen/pcapng/spb.rb @@ -45,8 +45,6 @@ class SPB < Block # @option options [Integer] :block_len2 block total length def initialize(options={}) super - endianness(options[:endian] || :little) - recalc_block_len self.type = options[:type] || PcapNG::SPB_TYPE.to_i end @@ -64,11 +62,11 @@ def read(str_or_io) io = to_io(str_or_io) return self if io.eof? - self[:type].read io.read(4) - self[:block_len].read io.read(4) - self[:orig_len].read io.read(4) + self[:type].read(io.read(4)) + self[:block_len].read(io.read(4)) + self[:orig_len].read(io.read(4)) data_len = compute_data_len - self[:data].read io.read(data_len) + self[:data].read(io.read(data_len)) remove_padding(io, data_len) read_blocklen2_and_check(io) @@ -79,7 +77,7 @@ def read(str_or_io) # Return the object as a String # @return [String] def to_s - pad_field :data + pad_field(:data) recalc_block_len super end diff --git a/lib/packetgen/pcapng/unknown_block.rb b/lib/packetgen/pcapng/unknown_block.rb index 95e9017..64ae42c 100644 --- a/lib/packetgen/pcapng/unknown_block.rb +++ b/lib/packetgen/pcapng/unknown_block.rb @@ -23,17 +23,6 @@ class UnknownBlock < Block # @return [BinStruct::String] define_attr_before :block_len2, :body, BinStruct::String - # @option options [:little, :big] :endian set block endianness - # @option options [Integer] :type - # @option options [Integer] :block_len block total length - # @option options [::String] :body - # @option options [Integer] :block_len2 block total length - def initialize(options={}) - super - endianness(options[:endian] || :little) - recalc_block_len - end - # Has this block options? # @return [false] # @since 2.7.0 @@ -48,9 +37,9 @@ def read(str_or_io) io = to_io(str_or_io) return self if io.eof? - self[:type].read io.read(4) - self[:block_len].read io.read(4) - self[:body].read io.read(self[:block_len].to_i - MIN_SIZE) + self[:type].read(io.read(4)) + self[:block_len].read(io.read(4)) + self[:body].read(io.read(self[:block_len].to_i - MIN_SIZE)) read_blocklen2_and_check(io) self @@ -59,7 +48,7 @@ def read(str_or_io) # Return the object as a String # @return [String] def to_s - pad_field :body + pad_field(:body) recalc_block_len super end From f2735603075d359d48b919ee3af6c8db80fc6357 Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Wed, 24 Jul 2024 12:16:27 +0200 Subject: [PATCH 08/19] Clean up some code/doc --- lib/packetgen/pcap.rb | 7 ++++--- lib/packetgen/pcaprub_wrapper.rb | 3 ++- lib/packetgen/proto.rb | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/packetgen/pcap.rb b/lib/packetgen/pcap.rb index 709adeb..4175784 100644 --- a/lib/packetgen/pcap.rb +++ b/lib/packetgen/pcap.rb @@ -9,7 +9,6 @@ module PacketGen # Module to read PCAP files - # @author Sylvain Daubert # @api private # @since 3.1.4 module Pcap @@ -17,10 +16,12 @@ module Pcap # @param [String] filename # @return [Array] # @author Kent Gruber + # @author LemonTree55 def self.read(filename) packets = [] - PCAPRUBWrapper.read_pcap(filename: filename) do |packet| - next unless (packet = PacketGen.parse(packet.to_s)) + PCAPRUBWrapper.read_pcap(filename: filename) do |raw_packet| + packet = PacketGen.parse(raw_packet.to_s) + next if packet.nil? packets << packet end diff --git a/lib/packetgen/pcaprub_wrapper.rb b/lib/packetgen/pcaprub_wrapper.rb index 18075b7..fb961a9 100644 --- a/lib/packetgen/pcaprub_wrapper.rb +++ b/lib/packetgen/pcaprub_wrapper.rb @@ -35,8 +35,9 @@ def self.open_iface(iface:, snaplen: DEFAULT_SNAPLEN, promisc: DEFAULT_PROMISC, pcap.setpromisc(promisc) pcap.settimeout(TIMEOUT) # Monitor MUST be set before pcap is activated - pcap.setmonitor monitor unless monitor.nil? + pcap.setmonitor(monitor) unless monitor.nil? pcap.activate + pcap end # Capture packets from a network interface diff --git a/lib/packetgen/proto.rb b/lib/packetgen/proto.rb index 85a3c62..78842ec 100644 --- a/lib/packetgen/proto.rb +++ b/lib/packetgen/proto.rb @@ -10,7 +10,7 @@ require 'socket' module PacketGen - # Module handling some helper methods for protocols + # Module handling some helper methods for well_known protocols # @author Sylvain Daubert # @since 2.1.2 module Proto From ca052bfe6345e64c9a452ed0a59e96df5009f806 Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Wed, 24 Jul 2024 15:37:40 +0200 Subject: [PATCH 09/19] lean up code --- lib/packetgen/capture.rb | 4 ++-- lib/packetgen/config.rb | 1 - lib/packetgen/deprecation.rb | 8 ++++---- lib/packetgen/header.rb | 15 +++++++-------- lib/packetgen/headerable.rb | 14 ++++++++++++-- 5 files changed, 25 insertions(+), 17 deletions(-) diff --git a/lib/packetgen/capture.rb b/lib/packetgen/capture.rb index cceeb8a..bcc5cf2 100644 --- a/lib/packetgen/capture.rb +++ b/lib/packetgen/capture.rb @@ -61,7 +61,7 @@ def initialize(iface: nil, max: nil, timeout: nil, filter: nil, promisc: false, @packets = [] @raw_packets = [] @timestamps = [] - set_options iface, max, timeout, filter, promisc, parse, snaplen, monitor + set_options(iface, max, timeout, filter, promisc, parse, snaplen, monitor) end # Start capture @@ -75,7 +75,7 @@ def initialize(iface: nil, max: nil, timeout: nil, filter: nil, promisc: false, # @author Sylvain Daubert # @author optix2000 - add monitor argument def start(iface: nil, max: nil, timeout: nil, filter: nil, promisc: false, parse: true, snaplen: nil, monitor: nil, &block) - set_options iface, max, timeout, filter, promisc, parse, snaplen, monitor + set_options(iface, max, timeout, filter, promisc, parse, snaplen, monitor) @cap_thread = Thread.new do PCAPRUBWrapper.capture(**capture_args) do |packet| diff --git a/lib/packetgen/config.rb b/lib/packetgen/config.rb index b9d34e3..4c86843 100644 --- a/lib/packetgen/config.rb +++ b/lib/packetgen/config.rb @@ -12,7 +12,6 @@ module PacketGen # Config class to provide +config+ object to pgconsole # @author Sylvain Daubert - # @author Kent 'picat' Gruber # @since 1.4.1 # @since 2.1.3 Config is singleton class Config diff --git a/lib/packetgen/deprecation.rb b/lib/packetgen/deprecation.rb index 9a5fd60..8f7eb53 100644 --- a/lib/packetgen/deprecation.rb +++ b/lib/packetgen/deprecation.rb @@ -8,7 +8,7 @@ module PacketGen module Deprecation # Default remove version for deprecated classes/methods # @since 3.1.0 - REMOVE_VERSION = '4.0.0' + REMOVE_VERSION = '5.0.0' # @private # @param [String] remove_version @@ -35,7 +35,7 @@ def self.deprecated(klass, deprecated_method, new_method=nil, klass_method: fals message = +"#{file}:#{line}: #{complete_deprecated_method_name} is deprecated" message << " in favor of #{complete_new_method_name}" unless new_method.nil? message << '. ' << self.removed(remove_version) - warn message + warn(message) end # Warn when using a deprecated method @@ -49,7 +49,7 @@ def self.deprecated_class(klass, new_klass=nil, remove_version: REMOVE_VERSION) message = +"#{file}:#{line}: #{klass} is deprecated" message << " in favor of #{new_klass}" unless new_klass.nil? message << '. ' << self.removed(remove_version) - warn message + warn(message) end # Warn when using a deprecated method's option @@ -66,7 +66,7 @@ def self.deprecated_option(klass, method, option, klass_method: false, remove_ve method_name = "#{base_name}#{method}" message = +"option #{option} is deprecated for method #{method_name}. " message << self.removed(remove_version) - warn message + warn(message) end end end diff --git a/lib/packetgen/header.rb b/lib/packetgen/header.rb index 5c047d2..f88da0c 100644 --- a/lib/packetgen/header.rb +++ b/lib/packetgen/header.rb @@ -13,7 +13,7 @@ module PacketGen # This namespace handles all buitlin headers, such as {IP} or {TCP}. # # == Add a foreign header class - # PacketGen permits adding you own header classes. + # PacketGen permits adding your own header classes. # First, define the new header class. By example: # module MyModule # class MyHeader < PacketGen::Header::Base @@ -22,13 +22,12 @@ module PacketGen # end # end # Then, class must be declared to PacketGen: - # PacketGen::Header.add_class MyModule::MyHeader + # PacketGen::Header.add_class(MyModule::MyHeader) # Finally, bindings must be declared: # # bind MyHeader as IP protocol number 254 (needed by Packet#parse and Packet#add) - # PacketGen::Header::IP.bind_header MyModule::MyHeader, protocol: 254 + # PacketGen::Header::IP.bind_header(MyModule::MyHeader, protocol: 254) # And use it: - # pkt = Packet.gen('IP').add('MyHeader', field1: 0x12345678) - # pkt.myheader.field2.read 0x01 + # pkt = Packet.gen('IP').add('MyHeader', field1: 0x12345678, field3: 0x87654321) # @author Sylvain Daubert module Header @added_header_classes = {} @@ -54,7 +53,7 @@ def add_class(klass) @header_classes = nil end - # Remove a foreign header (previously added by {.add_header_class} + # Remove a foreign header previously added by {.add_header_class} # from known header classes. # @param [Class] klass # @return [void] @@ -70,8 +69,8 @@ def remove_class(klass) # @return [Class,nil] # @since 1.1.0 def get_header_class_by_name(name) - if Header.const_defined? name - Header.const_get name + if Header.const_defined?(name) + Header.const_get(name) else @added_header_classes[name] end diff --git a/lib/packetgen/headerable.rb b/lib/packetgen/headerable.rb index 751f461..4d1525e 100644 --- a/lib/packetgen/headerable.rb +++ b/lib/packetgen/headerable.rb @@ -33,7 +33,7 @@ def protocol_name # @param [Class] klass # @return [void] def self.included(klass) - klass.extend ClassMethods + klass.extend(ClassMethods) end # Return header protocol name @@ -65,7 +65,7 @@ def packet end # @api private - # Set packet to which this header belongs + # Set packet to which this header belongs to # @param [Packet] packet # @return [Packet] packet def packet=(packet) @@ -91,5 +91,15 @@ def read(str) super end + + # @abstract This method MUST be redefined by subclasses. + # Generate binary string from header + # @return [String] + # @raise [NotImplementedError] + def to_s + raise NotImplementedError, "#{self.class} should implement #to_s" if method(:to_s).super_method.nil? + + super + end end end From 8ffb29542e8612f9563ee764a6b38800d07ca9c9 Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Wed, 24 Jul 2024 16:02:33 +0200 Subject: [PATCH 10/19] Clean ARPSpoofer. Make #active? return false on unknown target IP --- lib/packetgen/utils/arp_spoofer.rb | 37 +++++++++++++++--------------- spec/utils/arp_spoofer_spec.rb | 4 ++-- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/lib/packetgen/utils/arp_spoofer.rb b/lib/packetgen/utils/arp_spoofer.rb index 571ac59..b32a11b 100644 --- a/lib/packetgen/utils/arp_spoofer.rb +++ b/lib/packetgen/utils/arp_spoofer.rb @@ -22,15 +22,15 @@ module Utils # @author Sylvain Daubert # @since 2.1.3 class ARPSpoofer - # @param [Integer,Float,nil] timeout spoof will happen for this amount + # @param [Numeric,nil] timeout spoof will happen for this amount # of time - # @param [Integer,Float] interval time between 2 ARP packets + # @param [Numeric] interval time between 2 ARP packets # @param [String,nil] iface network interface on which do spoofing. # Defaults to {PacketGen.default_iface} def initialize(timeout: nil, interval: 1.0, iface: nil) @timeout = timeout @timeout = @timeout.to_f if @timeout - @interval = interval + @interval = interval.to_f @iface = iface || PacketGen.default_iface @targets = {} @arp_packets = {} @@ -56,19 +56,19 @@ def add(target_ip, spoofed_ip, options={}) # @param [String] target_ip target IP address # @return [void] def remove(target_ip) - @targets.delete target_ip - @arp_packets.delete target_ip + @targets.delete(target_ip) + @arp_packets.delete(target_ip) end # Get registered targets (all targets, registered with {#add} and {#start}) - # @return [Array] list of target IP addresses + # @return [Array] list of registeres IP addresses def registered_targets @targets.keys end # Get active targets (registered with {#start}, or all after using # {#start_all}) - # @return [Array] list of target IP addresses + # @return [Array] list of active IP addresses def active_targets @arp_packets.keys end @@ -83,23 +83,23 @@ def active_targets # an ARP request is made to get it. # @return [void] def start(target_ip, spoofed_ip, options={}) - add target_ip, spoofed_ip, options - activate target_ip + add(target_ip, spoofed_ip, options) + activate(target_ip) end # Stop spoofing on given target # @param [String] target_ip target IP address # @return [void] def stop(target_ip) - deactivate target_ip - remove target_ip + deactivate(target_ip) + remove(target_ip) end # Start spoofing on all targets added with {#add}. # @return [void] def start_all @targets.each_key do |target_ip| - activate target_ip + activate(target_ip) end end @@ -107,7 +107,7 @@ def start_all # @return [void] def stop_all @targets.each_key do |target_ip| - deactivate target_ip + deactivate(target_ip) end end @@ -115,9 +115,7 @@ def stop_all # @param [String] target_ip target IP address # @return [Boolean] def active?(target_ip) - # rubocop:disable Style/ReturnNilInPredicateMethodDefinition - return unless @targets.key?(target_ip) - # rubocop:enable Style/ReturnNilInPredicateMethodDefinition + return false unless @targets.key?(target_ip) @targets[target_ip][:active] end @@ -126,6 +124,7 @@ def active?(target_ip) # was set on {#initialize}. def wait @spoof_thread.join + @spoof_thread = nil end private @@ -143,7 +142,7 @@ def activate(target_ip) # Create spoof thread def create_spoof_thread @spoof_thread = Thread.new(@queue, @timeout, @interval) do |queue, timeout, interval| - while timeout.nil? || timeout > 0.0 + while timeout.nil? || timeout.positive? packets = queue.pop unless queue.empty? send_packets_on_wire(packets) unless packets.empty? timeout -= interval if timeout @@ -161,9 +160,9 @@ def send_packets_on_wire(packets) # @param [String] target_ip # @return [void] def deactivate(target_ip) - @arp_packets.delete target_ip + @arp_packets.delete(target_ip) if @arp_packets.empty? - @spoof_thread.kill + @spoof_thread&.kill @spoof_thread = nil else @queue << @arp_packets.values diff --git a/spec/utils/arp_spoofer_spec.rb b/spec/utils/arp_spoofer_spec.rb index 97cd844..71a34f0 100644 --- a/spec/utils/arp_spoofer_spec.rb +++ b/spec/utils/arp_spoofer_spec.rb @@ -112,8 +112,8 @@ module Utils expect(as.active?('1.2.3.4')).to be(false) end - it 'returns nil for unknown target' do - expect(as.active?('10.0.0.1')).to be(nil) + it 'returns false for unknown target' do + expect(as.active?('10.0.0.1')).to be(false) end end end From 9b89623f7e4355a241968ce0a16ec07bad293046 Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Thu, 25 Jul 2024 11:48:41 +0200 Subject: [PATCH 11/19] Clean header classes code --- lib/packetgen/header/base.rb | 11 ++-- lib/packetgen/header/dhcpv6/duid.rb | 2 +- lib/packetgen/header/dhcpv6/option.rb | 2 +- lib/packetgen/header/dns/name.rb | 10 ++- lib/packetgen/header/dns/qdsection.rb | 2 +- lib/packetgen/header/dns/rr.rb | 81 ++++++++++++++---------- lib/packetgen/header/dns/rrsection.rb | 4 +- lib/packetgen/header/dot11.rb | 36 +++++------ lib/packetgen/header/dot11/control.rb | 6 +- lib/packetgen/header/dot11/data.rb | 10 +-- lib/packetgen/header/dot11/management.rb | 2 +- lib/packetgen/header/eap.rb | 4 +- lib/packetgen/header/http/headers.rb | 2 +- lib/packetgen/header/http/request.rb | 7 +- lib/packetgen/header/http/response.rb | 7 +- lib/packetgen/header/http/verbs.rb | 4 +- lib/packetgen/header/ip.rb | 12 ++-- lib/packetgen/header/ip/option.rb | 8 +-- lib/packetgen/header/ipv6.rb | 2 +- lib/packetgen/header/mdns.rb | 2 +- lib/packetgen/header/ospfv2/lsa.rb | 6 +- lib/packetgen/header/ospfv3/lsa.rb | 6 +- lib/packetgen/header/snmp.rb | 2 +- lib/packetgen/header/tcp/options.rb | 2 +- lib/packetgen/header/tftp.rb | 8 +-- lib/packetgen/header/udp.rb | 2 +- 26 files changed, 128 insertions(+), 112 deletions(-) diff --git a/lib/packetgen/header/base.rb b/lib/packetgen/header/base.rb index 9312bc1..d58ad69 100644 --- a/lib/packetgen/header/base.rb +++ b/lib/packetgen/header/base.rb @@ -130,12 +130,12 @@ def check?(fields) # @param [BinStruct::Struct] fields # @return [void] def set(fields) - @bindings.first.each { |b| b.set fields } + @bindings.first.each { |b| b.set(fields) } end end # @private - # On inheritage, create +@known_header+ class variable + # On inheritance, create +@known_header+ class variable # @param [Class] klass # @return [void] def self.inherited(klass) @@ -182,11 +182,10 @@ class << self # ->(hdr) { hdr.field1 == 41 && hdr.body[0..1] == "\x00\x00" }] # @since 2.7.0 def bind(header_klass, args={}) - if @known_headers[header_klass].nil? + bindings = @known_headers[header_klass] + if bindings.nil? bindings = Bindings.new @known_headers[header_klass] = bindings - else - bindings = @known_headers[header_klass] end bindings.new_set args.each do |key, value| @@ -242,7 +241,7 @@ def header_id(header) 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? + raise FormatError, 'no IP nor IPv6 header in packet' if iph.nil? iph end diff --git a/lib/packetgen/header/dhcpv6/duid.rb b/lib/packetgen/header/dhcpv6/duid.rb index 772922a..3e7dafc 100644 --- a/lib/packetgen/header/dhcpv6/duid.rb +++ b/lib/packetgen/header/dhcpv6/duid.rb @@ -50,7 +50,7 @@ def read(str) self end else - private_read str + private_read(str) end end diff --git a/lib/packetgen/header/dhcpv6/option.rb b/lib/packetgen/header/dhcpv6/option.rb index eb4dd7b..b30729c 100644 --- a/lib/packetgen/header/dhcpv6/option.rb +++ b/lib/packetgen/header/dhcpv6/option.rb @@ -63,7 +63,7 @@ def new(options={}) when String if DHCPv6.const_defined?(options[:type]) klass = DHCPv6.const_get(options[:type]) - options.delete :type + options.delete(:type) klass.new(options) if klass < Option end else diff --git a/lib/packetgen/header/dns/name.rb b/lib/packetgen/header/dns/name.rb index 6363dc4..0026c3a 100644 --- a/lib/packetgen/header/dns/name.rb +++ b/lib/packetgen/header/dns/name.rb @@ -11,6 +11,7 @@ module Header class DNS # DNS Name, defined as a suite of labels. A label is of type {BinStruct::IntString}. # @author Sylvain Daubert + # @author LemonTree55 class Name < BinStruct::Array # Mask to decode a pointer on another label POINTER_MASK = 0xc000 @@ -18,7 +19,10 @@ class Name < BinStruct::Array # @return [DNS] attr_accessor :dns - def initialize + # @param [Hash] options + # @option options [DNS] :dns + def initialize(options={}) + @dns = options.delete(:dns) super @pointer = nil @pointer_name = nil @@ -59,11 +63,11 @@ def read(str) clear return self if str.nil? - PacketGen.force_binary str + PacketGen.force_binary(str) start = 0 loop do index = str[start, 2].unpack1('n') - if pointer? index + if pointer?(index) # Pointer on another label @pointer = str[start, 2] break diff --git a/lib/packetgen/header/dns/qdsection.rb b/lib/packetgen/header/dns/qdsection.rb index cfbfe96..25c4f69 100644 --- a/lib/packetgen/header/dns/qdsection.rb +++ b/lib/packetgen/header/dns/qdsection.rb @@ -36,7 +36,7 @@ def read(str) while !str.empty? && (self.size < @counter.to_i) question = Question.new(@dns).read(str) str.slice!(0, question.sz) - push question + push(question) end self end diff --git a/lib/packetgen/header/dns/rr.rb b/lib/packetgen/header/dns/rr.rb index 9c984f5..0c23382 100644 --- a/lib/packetgen/header/dns/rr.rb +++ b/lib/packetgen/header/dns/rr.rb @@ -11,6 +11,7 @@ module Header class DNS # DNS Ressource Record # @author Sylvain Daubert + # @author LemonTree55 class RR < Question # @!attribute ttl # 32-bit time to live @@ -25,6 +26,41 @@ class RR < Question define_attr :rdata, BinStruct::String, builder: ->(rr, t) { t.new(length_from: rr[:rdlength]) } + # @private RData struct + class RData < BinStruct::Struct + attr_accessor :dns + + def initialize(options={}) + @dns = options.delete(:dns) + super + end + end + + # @private MX struct + class MX < RData + define_attr :pref, BinStruct::Int16 + define_attr :exchange, Name, builder: ->(h, t) { t.new(dns: h.dns) } + end + + # @private SOA struct + class SOA < RData + define_attr :mname, Name, builder: ->(h, t) { t.new(dns: h.dns) } + define_attr :rname, Name, builder: ->(h, t) { t.new(dns: h.dns) } + define_attr :serial, BinStruct::Int32 + define_attr :refresh, BinStruct::Int32 + define_attr :retryi, BinStruct::Int32 + define_attr :expire, BinStruct::Int32 + define_attr :minimum, BinStruct::Int32 + end + + # @private SRV struct + class SRV < RData + define_attr :priority, BinStruct::Int16 + define_attr :weight, BinStruct::Int16 + define_attr :port, BinStruct::Int16 + define_attr :target, Name, builder: ->(h, t) { t.new(dns: h.dns) } + end + # @param [DNS] dns # @param [Hash] options # @option options [String] :name domain as a dotted string @@ -60,8 +96,7 @@ def human_rdata case type when TYPES['NS'], TYPES['PTR'], TYPES['CNAME'] - name = Name.new - name.dns = self[:name].dns + name = Name.new(dns: self[:name].dns) str = name.read(self[:rdata]).to_human when TYPES['SOA'] str = human_soa_rdata @@ -78,7 +113,7 @@ def human_rdata # Get human readable class # @return [String] def human_rrclass - if self[:name].dns.is_a? MDNS + if self[:name].dns.is_a?(MDNS) str = self.class::CLASSES.key(self.rrclass & 0x7fff) || '0x%04x' % (self.rrclass & 0x7fff) str += ' CACHE-FLUSH' if (self.rrclass & 0x8000).positive? str @@ -105,44 +140,22 @@ def human_ip_rdata end def human_mx_data - name = Name.new - name.dns = self[:name].dns - - pref = BinStruct::Int16.new.read(self[:rdata][0, 2]) - exchange = name.read(self[:rdata][2..]).to_human - - '%u %s' % [pref.to_i, exchange] + mx = MX.new(dns: self[:name].dns).read(self[:rdata]) + "#{mx.pref} #{mx.exchange}" end - # rubocop:disable Metrics/AbcSize + # /rubocop:disable Metrics/AbcSize def human_soa_rdata - name = Name.new - name.dns = self[:name].dns - mname = name.read(self[:rdata]).dup - rname = name.read(self[:rdata][mname.sz..]) - - serial = BinStruct::Int32.new.read(self[:rdata][mname.sz + rname.sz, 4]) - refresh = BinStruct::Int32.new.read(self[:rdata][mname.sz + rname.sz + 4, 4]) - retryi = BinStruct::Int32.new.read(self[:rdata][mname.sz + rname.sz + 8, 4]) - expire = BinStruct::Int32.new.read(self[:rdata][mname.sz + rname.sz + 12, 4]) - minimum = BinStruct::Int32.new.read(self[:rdata][mname.sz + rname.sz + 16, 4]) - - "#{mname.to_human} #{rname.to_human} #{serial.to_i} #{refresh.to_i} " \ - "#{retryi.to_i} #{expire.to_i} #{minimum.to_i}" + soa = SOA.new(dns: self[:name].dns).read(self[:rdata]) + + "#{soa.mname} #{soa.rname} #{soa.serial} #{soa.refresh} " \ + "#{soa.retryi} #{soa.expire} #{soa.minimum}" end def human_srv_data - name = Name.new - name.dns = self[:name].dns - - priority = BinStruct::Int16.new.read(self[:rdata][0, 2]) - weight = BinStruct::Int16.new.read(self[:rdata][2, 2]) - port = BinStruct::Int16.new.read(self[:rdata][4, 2]) - target = name.read(self[:rdata][6, self[:rdata].size]).to_human - - "#{priority.to_i} #{weight.to_i} #{port.to_i} #{target}" + srv = SRV.new(dns: self[:name].dns).read(self[:rdata]) + "#{srv.priority} #{srv.weight} #{srv.port} #{srv.target}" end - # rubocop:enable Metrics/AbcSize end end end diff --git a/lib/packetgen/header/dns/rrsection.rb b/lib/packetgen/header/dns/rrsection.rb index 962ee3d..9444d51 100644 --- a/lib/packetgen/header/dns/rrsection.rb +++ b/lib/packetgen/header/dns/rrsection.rb @@ -32,7 +32,7 @@ def read(str) rr = RR.new(@dns).read(str) rr = OPT.new(@dns).read(str) if rr.type?('OPT') str.slice!(0, rr.sz) - push rr + push(rr) end self end @@ -40,7 +40,7 @@ def read(str) private def record_from_hash(hsh) - if hsh.key? :rtype + if hsh.key?(:rtype) case hsh.delete(:rtype) when 'Question' Question.new(@dns, hsh) diff --git a/lib/packetgen/header/dot11.rb b/lib/packetgen/header/dot11.rb index ce99afe..d709ee0 100644 --- a/lib/packetgen/header/dot11.rb +++ b/lib/packetgen/header/dot11.rb @@ -281,24 +281,24 @@ def attributes def read(str) fcs = Dot11.fcs? - if self.instance_of? Dot11 + if self.instance_of?(Dot11) return self if str.nil? force_binary str - self[:frame_ctrl].read str[0, 2] + self[:frame_ctrl].read(str[0, 2]) case type when 0 - Dot11::Management.new.read str + Dot11::Management.new.read(str) when 1 - Dot11::Control.new.read str + Dot11::Control.new.read(str) when 2 - Dot11::Data.new.read str + Dot11::Data.new.read(str) else - private_read str, fcs + private_read(str, fcs) end else - private_read str, fcs + private_read(str, fcs) end end @@ -324,9 +324,9 @@ def human_type # @return [String] def inspect - str = if self.instance_of? Dot11 + str = if self.instance_of?(Dot11) Inspect.dashed_line("#{self.class} #{human_type}", 1) - elsif self.respond_to? :human_subtype + elsif self.respond_to?(:human_subtype) Inspect.dashed_line("#{self.class} #{human_subtype}", 1) else Inspect.dashed_line(self.class.to_s, 1) @@ -354,7 +354,7 @@ def to_w(iface) # @param [Packet] packet # @return [void] def added_to_packet(packet) - return if packet.respond_to? :dot11 + return if packet.respond_to?(:dot11) packet.instance_eval("def dot11(arg=nil); header(#{self.class}, arg); end") # def dot11(arg=nil); header(Dot11, arg); end end @@ -368,15 +368,15 @@ def remove_from_applicable_attributes(attributes) def handle_mac4 if to_ds? && from_ds? - @applicable_attributes[6, 0] = :mac4 unless @applicable_attributes.include? :mac4 + @applicable_attributes[6, 0] = :mac4 unless @applicable_attributes.include?(:mac4) else - remove_from_applicable_attributes :mac4 + remove_from_applicable_attributes(:mac4) end end def handle_ht_ctrl if order? - unless @applicable_attributes.include? :ht_ctrl + unless @applicable_attributes.include?(:ht_ctrl) idx = @applicable_attributes.index(:body) @applicable_attributes[idx, 0] = :ht_ctrl end @@ -387,9 +387,9 @@ def handle_ht_ctrl def handle_fcs if Dot11.fcs? - @applicable_attributes << :fcs unless @applicable_attributes.include? :fcs + @applicable_attributes << :fcs unless @applicable_attributes.include?(:fcs) else - remove_from_applicable_attributes :fcs + remove_from_applicable_attributes(:fcs) end end @@ -403,10 +403,10 @@ def private_read(str, fcs) self[:frame_ctrl].read str[0, 2] define_applicable_attributes if fcs - old_read str[0...-4] - self[:fcs].read str[-4..] + old_read(str[0...-4]) + self[:fcs].read(str[-4..]) else - old_read str + old_read(str) end self end diff --git a/lib/packetgen/header/dot11/control.rb b/lib/packetgen/header/dot11/control.rb index d22a532..ac72d78 100644 --- a/lib/packetgen/header/dot11/control.rb +++ b/lib/packetgen/header/dot11/control.rb @@ -58,9 +58,9 @@ def human_subtype def define_applicable_attributes super - if @applicable_attributes.include? :mac2 - @applicable_attributes -= %i[mac2] unless SUBTYPES_WITH_MAC2.include? self.subtype - elsif SUBTYPES_WITH_MAC2.include? self.subtype + if @applicable_attributes.include?(:mac2) + @applicable_attributes -= %i[mac2] unless SUBTYPES_WITH_MAC2.include?(self.subtype) + elsif SUBTYPES_WITH_MAC2.include?(self.subtype) @applicable_attributes[3, 0] = :mac2 end end diff --git a/lib/packetgen/header/dot11/data.rb b/lib/packetgen/header/dot11/data.rb index ec21140..da5ab63 100644 --- a/lib/packetgen/header/dot11/data.rb +++ b/lib/packetgen/header/dot11/data.rb @@ -45,22 +45,22 @@ def reply! case ds when 0 # MAC1: RA/DA, MAC2: TA/SA - invert_mac :mac1, :mac2 + invert_mac(:mac1, :mac2) when 1 # MAC1: RA/BSSID, MAC2: TA/SA, MAC3: DA - invert_mac :mac1, :mac2 + invert_mac(:mac1, :mac2) self.to_ds = false self.from_ds = true when 2 # MAC1: RA/DA, MAC2: BSSID, MAC3: SA or BSSID - invert_mac :mac1, :mac2 + invert_mac(:mac1, :mac2) self.to_ds = true self.from_ds = false when 3 # MAC1: RA, MAC2: TA - invert_mac :mac1, :mac2 + invert_mac(:mac1, :mac2) # MAC3: DA, MAC4: SA - invert_mac :mac3, :mac4 + invert_mac(:mac3, :mac4) end self end diff --git a/lib/packetgen/header/dot11/management.rb b/lib/packetgen/header/dot11/management.rb index 5e4eeaa..cccdd44 100644 --- a/lib/packetgen/header/dot11/management.rb +++ b/lib/packetgen/header/dot11/management.rb @@ -54,7 +54,7 @@ def initialize(options={}) # @return [self] # @since 2.1.3 def add_element(type:, value:) - raise FormatError, 'Before adding an Element, you have to add a Dot11::SubMngt subclass instance' unless self[:body].is_a? SubMngt + raise FormatError, 'Before adding an Element, you have to add a Dot11::SubMngt subclass instance' unless self[:body].is_a?(SubMngt) self[:body].elements << { type: type, value: value } self diff --git a/lib/packetgen/header/eap.rb b/lib/packetgen/header/eap.rb index b9620ab..d79dfcc 100644 --- a/lib/packetgen/header/eap.rb +++ b/lib/packetgen/header/eap.rb @@ -201,7 +201,7 @@ def desired_auth_type # Calculate length field from content # @return [Integer] def calc_length - Base.calculate_and_set_length self + Base.calculate_and_set_length(self) end # Say is this EAP header has {#type} field @@ -217,7 +217,7 @@ def type? # @param [Packet] packet # @return [void] def added_to_packet(packet) - return if packet.respond_to? :eap + return if packet.respond_to?(:eap) packet.instance_eval("def eap(arg=nil); header(#{self.class}, arg); end") # def eap(arg=nil); header(EAP, arg); end end diff --git a/lib/packetgen/header/http/headers.rb b/lib/packetgen/header/http/headers.rb index 0d5d833..8b7d495 100644 --- a/lib/packetgen/header/http/headers.rb +++ b/lib/packetgen/header/http/headers.rb @@ -76,7 +76,7 @@ def to_human end # Read human-readable data to populate header data. - # @param [String, Hash] data + # @param [Hash] data # @return [self] def from_human(data) read(data) diff --git a/lib/packetgen/header/http/request.rb b/lib/packetgen/header/http/request.rb index a300316..4ab432b 100644 --- a/lib/packetgen/header/http/request.rb +++ b/lib/packetgen/header/http/request.rb @@ -35,6 +35,7 @@ module HTTP # # @author Kent 'picat' Gruber # @author Sylvain Daubert + # @author LemonTree55 # @since 3.1.0 Rename +#method+ into {#verb} to not mask +Object#method+. class Request < Base # @!attribute verb @@ -70,9 +71,9 @@ def initialize(options={}) def read(str) lines = lines(str) first_line_words = lines.shift.split - self[:verb].read first_line_words[0] - self[:path].read first_line_words[1] - self[:version].read first_line_words[2] + self[:verb].read(first_line_words[0]) + self[:path].read(first_line_words[1]) + self[:version].read(first_line_words[2]) # requests can sometimes have a payload headers, data = headers_and_payload_from_lines(lines) diff --git a/lib/packetgen/header/http/response.rb b/lib/packetgen/header/http/response.rb index 81032f1..f575f32 100644 --- a/lib/packetgen/header/http/response.rb +++ b/lib/packetgen/header/http/response.rb @@ -36,6 +36,7 @@ module HTTP # http_resp.headers = { "Host": "tcpdump.org" } # even a hash # # @author Kent 'picat' Gruber + # @author LemonTree55 class Response < Base # @!attribute version # @return [BinStruct::String] @@ -125,9 +126,9 @@ def extract_info_from_first_line(headers) first_line = headers.shift.split return if first_line.size < 3 - self[:version].read first_line[0] - self[:status_code].read first_line[1] - self[:status_mesg].read first_line[2..].join(' ') + self[:version].read(first_line[0]) + self[:status_code].read(first_line[1]) + self[:status_mesg].read(first_line[2..].join(' ')) end def raise_on_bad_version_status diff --git a/lib/packetgen/header/http/verbs.rb b/lib/packetgen/header/http/verbs.rb index c4a74f4..cb6547d 100644 --- a/lib/packetgen/header/http/verbs.rb +++ b/lib/packetgen/header/http/verbs.rb @@ -9,10 +9,8 @@ module PacketGen module Header # @since 2.2.0 + # @author Kent 'picat' Gruber module HTTP - # @abstract Collection of useful HTTP verbs. - # @author Kent 'picat' Gruber - # Valid HTTP Verbs VERBS = %w[GET HEAD POST PUT DELETE CONNECT OPTIONS TRACE PATCH].freeze diff --git a/lib/packetgen/header/ip.rb b/lib/packetgen/header/ip.rb index 3ef4fe0..8c6a64d 100644 --- a/lib/packetgen/header/ip.rb +++ b/lib/packetgen/header/ip.rb @@ -160,7 +160,7 @@ class IP # @return [Integer] def self.sum16(hdr) old_checksum = nil - if hdr.respond_to? :checksum= + if hdr.respond_to?(:checksum) old_checksum = hdr.checksum hdr.checksum = 0 end @@ -178,8 +178,8 @@ def self.sum16(hdr) # This method: # * checks a checksum is not greater than 0xffff. If it is, # reduces it. - # * inverts reduced self[attr]. - # * forces self[attr] to 0xffff if computed self[attr] is 0. + # * inverts reduced checksum. + # * forces checksum to 0xffff if computed checksum is 0. # @param [Integer] checksum checksum to reduce # @return [Integer] reduced checksum def self.reduce_checksum(checksum) @@ -203,7 +203,7 @@ def calc_checksum # @return [Integer] # @since 3.0.0 add +ihl+ calculation def calc_length - Base.calculate_and_set_length self + Base.calculate_and_set_length(self) self.ihl = 5 + self[:options].sz / 4 end @@ -216,14 +216,14 @@ def pseudo_header_checksum # Send IP packet on wire. # - # When sending packet at IP level, +checksum+ and +length+ attributes.are set by + # When sending packet at IP level, +checksum+ and +length+ attributes are set by # kernel, so bad IP packets cannot be sent this way. To do so, use {Eth#to_w}. # @param [String,nil] _iface interface name. Not used # @return [void] def to_w(_iface=nil) sock = Socket.new(Socket::AF_INET, Socket::SOCK_RAW, Socket::IPPROTO_RAW) sockaddrin = Socket.sockaddr_in(0, dst) - sock.send to_s, 0, sockaddrin + sock.send(to_s, 0, sockaddrin) sock.close end diff --git a/lib/packetgen/header/ip/option.rb b/lib/packetgen/header/ip/option.rb index 9146e3f..715b395 100644 --- a/lib/packetgen/header/ip/option.rb +++ b/lib/packetgen/header/ip/option.rb @@ -76,7 +76,7 @@ def self.types @types = {} Option.constants.each do |cst| - next unless cst.to_s.end_with? '_TYPE' + next unless cst.to_s.end_with?('_TYPE') optname = cst.to_s.sub('_TYPE', '') @types[optname] = Option.const_get(cst) @@ -109,7 +109,7 @@ def initialize(options={}) # Get binary string. Set {#length} field. # @return [String] def to_s - self.length = super.size if respond_to? :length + self.length = super.size if respond_to?(:length) super end @@ -124,8 +124,8 @@ def to_human private def class2type - opt_name = self.class.to_s.gsub(/.*::/, '') - Option.const_get(:"#{opt_name}_TYPE") if Option.const_defined? :"#{opt_name}_TYPE" + opt_sym = :"#{self.class.to_s.gsub(/.*::/, '')}_TYPE" + Option.const_get(opt_sym) if Option.const_defined?(opt_sym) end def initialize_length_if_needed(options) diff --git a/lib/packetgen/header/ipv6.rb b/lib/packetgen/header/ipv6.rb index d1182e1..064d456 100644 --- a/lib/packetgen/header/ipv6.rb +++ b/lib/packetgen/header/ipv6.rb @@ -150,7 +150,7 @@ def pseudo_header_checksum def to_w(_iface=nil) sock = Socket.new(Socket::AF_INET6, Socket::SOCK_RAW, Socket::IPPROTO_RAW) sockaddrin = Socket.sockaddr_in(0, dst) - sock.send to_s, 0, sockaddrin + sock.send(to_s, 0, sockaddrin) sock.close end diff --git a/lib/packetgen/header/mdns.rb b/lib/packetgen/header/mdns.rb index 9a050ca..5fc2615 100644 --- a/lib/packetgen/header/mdns.rb +++ b/lib/packetgen/header/mdns.rb @@ -47,7 +47,7 @@ def mdnsize def added_to_packet(packet) mdns_idx = packet.headers.size packet.instance_eval "def mdnsize() @headers[#{mdns_idx}].mdnsize; end" # def mdnsize() @headers[4].mdnsize; end - return unless packet.is? 'UDP' + return unless packet.is?('UDP') return unless packet.udp.sport.zero? packet.udp.sport = UDP_PORT diff --git a/lib/packetgen/header/ospfv2/lsa.rb b/lib/packetgen/header/ospfv2/lsa.rb index 942fdec..91ac3f5 100644 --- a/lib/packetgen/header/ospfv2/lsa.rb +++ b/lib/packetgen/header/ospfv2/lsa.rb @@ -211,7 +211,7 @@ def initialize(options={}) private def record_from_hash(hsh) - raise ArgumentError, 'hash should have :type key' unless hsh.key? :type + raise ArgumentError, 'hash should have :type key' unless hsh.key?(:type) klass = if @only_headers LSAHeader @@ -231,8 +231,8 @@ def record_from_hash(hsh) def get_lsa_class_by_human_type(htype) klassname = "LSA#{htype.to_s.delete('-')}" begin - if OSPFv2.const_defined? klassname - OSPFv2.const_get klassname + if OSPFv2.const_defined?(klassname) + OSPFv2.const_get(klassname) else LSA end diff --git a/lib/packetgen/header/ospfv3/lsa.rb b/lib/packetgen/header/ospfv3/lsa.rb index 0ee4fd6..a08e230 100644 --- a/lib/packetgen/header/ospfv3/lsa.rb +++ b/lib/packetgen/header/ospfv3/lsa.rb @@ -200,7 +200,7 @@ def initialize(options={}) private def record_from_hash(hsh) - raise ArgumentError, 'hash should have :type key' unless hsh.key? :type + raise ArgumentError, 'hash should have :type key' unless hsh.key?(:type) klass = if @only_headers LSAHeader @@ -220,8 +220,8 @@ def record_from_hash(hsh) def get_lsa_class_by_human_type(htype) klassname = "LSA#{htype.to_s.delete('-')}" begin - if OSPFv3.const_defined? klassname - OSPFv3.const_get klassname + if OSPFv3.const_defined?(klassname) + OSPFv3.const_get(klassname) else LSA end diff --git a/lib/packetgen/header/snmp.rb b/lib/packetgen/header/snmp.rb index 20c8ce1..be7718a 100644 --- a/lib/packetgen/header/snmp.rb +++ b/lib/packetgen/header/snmp.rb @@ -319,7 +319,7 @@ def inspect # @since 2.7.0 Set UDP sport according to bindings, only if sport is 0. # Needed by new bind API. def added_to_packet(packet) - return unless packet.is? 'UDP' + return unless packet.is?('UDP') return unless packet.udp.sport.zero? packet.udp.sport = packet.udp.dport diff --git a/lib/packetgen/header/tcp/options.rb b/lib/packetgen/header/tcp/options.rb index 078b2e5..f9e91b6 100644 --- a/lib/packetgen/header/tcp/options.rb +++ b/lib/packetgen/header/tcp/options.rb @@ -23,7 +23,7 @@ def self.option_classes @klasses = [] Option.constants.each do |cst| - next unless cst.to_s.end_with? '_KIND' + next unless cst.to_s.end_with?('_KIND') optname = cst.to_s.sub('_KIND', '') @klasses[Option.const_get(cst)] = TCP.const_get(optname) diff --git a/lib/packetgen/header/tftp.rb b/lib/packetgen/header/tftp.rb index bfe7954..aa3bea0 100644 --- a/lib/packetgen/header/tftp.rb +++ b/lib/packetgen/header/tftp.rb @@ -86,12 +86,12 @@ def read(str) if self.instance_of? TFTP super if OPCODES.value? opcode - TFTP.const_get(human_opcode).new.read str + TFTP.const_get(human_opcode).new.read(str) else self end else - old_read str + old_read(str) end end @@ -130,7 +130,7 @@ def human_opcode # @param [Packet] packet # @return [void] def added_to_packet(packet) - return if packet.respond_to? :tftp + return if packet.respond_to?(:tftp) packet.instance_eval("def tftp(arg=nil); header(#{self.class}, arg); end") # def tftp(arg=nil); header(TFTP, arg); end end @@ -140,7 +140,7 @@ def added_to_packet(packet) def decode_tftp_packet(pkt) tftp = Packet.parse(pkt.body, first_header: 'TFTP') udp_dport = pkt.udp.dport - pkt.encapsulate tftp + pkt.encapsulate(tftp) # need to fix it as #encapsulate force it to 69 pkt.udp.dport = udp_dport end diff --git a/lib/packetgen/header/udp.rb b/lib/packetgen/header/udp.rb index 83727a0..d8fc4d5 100644 --- a/lib/packetgen/header/udp.rb +++ b/lib/packetgen/header/udp.rb @@ -89,7 +89,7 @@ def calc_checksum # Compute length and set +length+ field # @return [Integer] def calc_length - Base.calculate_and_set_length self + Base.calculate_and_set_length(self) end # Invert source and destination port numbers From 6dcd9bdb5362487471c2652eaa54058e6b959424 Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Sat, 7 Sep 2024 14:21:18 +0200 Subject: [PATCH 12/19] Fix doc on UnknownPacket --- lib/packetgen/unknown_packet.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/packetgen/unknown_packet.rb b/lib/packetgen/unknown_packet.rb index e3eb80c..79f540c 100644 --- a/lib/packetgen/unknown_packet.rb +++ b/lib/packetgen/unknown_packet.rb @@ -30,7 +30,7 @@ def is?(_protocol) end # Get packet body - # @return [Types] + # @return [String] def body @binary_str end @@ -66,7 +66,7 @@ def inspect str << Inspect.inspect_body(body) end - # equality if {#to_s} is equal + # equality if {#to_s} are equal # @return [Boolean] def ==(other) to_s == other.to_s From 4c8260499fa254c520228d042c13a49418bbce87 Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Sat, 7 Sep 2024 16:00:10 +0200 Subject: [PATCH 13/19] Add ability to write pcap files --- lib/packetgen/packet.rb | 15 +++++++++++---- lib/packetgen/pcap.rb | 12 +++++++++++- lib/packetgen/pcaprub_wrapper.rb | 15 +++++++++++++++ spec/packet_spec.rb | 20 ++++++++++++++++---- 4 files changed, 53 insertions(+), 9 deletions(-) diff --git a/lib/packetgen/packet.rb b/lib/packetgen/packet.rb index 6ea0ee4..f760bb3 100644 --- a/lib/packetgen/packet.rb +++ b/lib/packetgen/packet.rb @@ -112,16 +112,23 @@ def self.read(filename) Pcap.read(filename) end - # Write packets to +filename+ + # Write packets to +filename+, as pcap or PcapNG file # # For more options, see {PcapNG::File}. # @param [String] filename # @param [Array] packets packets to write # @return [void] + # @since 4.0.0 write a pcap file if filename extension is +.pcap+ + # @author Sylvain Daubert + # @author LemonTree55 (pcap) def self.write(filename, packets) - pf = PcapNG::File.new - pf.read_array(packets) - pf.to_f(filename) + if filename.end_with?('.pcap') + Pcap.write(filename, packets) + else + pf = PcapNG::File.new + pf.read_array(packets) + pf.to_f(filename) + end end # @private diff --git a/lib/packetgen/pcap.rb b/lib/packetgen/pcap.rb index 4175784..c7ef45b 100644 --- a/lib/packetgen/pcap.rb +++ b/lib/packetgen/pcap.rb @@ -8,7 +8,7 @@ require_relative 'pcaprub_wrapper' module PacketGen - # Module to read PCAP files + # Module to read/write PCAP files # @api private # @since 3.1.4 module Pcap @@ -27,5 +27,15 @@ def self.read(filename) end packets end + + # Write binary packets to a PCAP file + # @param [String] filename + # @param [Array] packets + # @return [void] + # @since 4.0.0 + # @author LemonTree55 + def self.write(filename, packets) + PCAPRUBWrapper.pcap_write(filename, packets.map(&:to_s)) + end end end diff --git a/lib/packetgen/pcaprub_wrapper.rb b/lib/packetgen/pcaprub_wrapper.rb index fb961a9..4ef16a4 100644 --- a/lib/packetgen/pcaprub_wrapper.rb +++ b/lib/packetgen/pcaprub_wrapper.rb @@ -10,6 +10,7 @@ module PacketGen # Wrapper around PCAPRUB # @author Sylvain Daubert + # @author LemonTree55 # @api private # @since 3.1.4 module PCAPRUBWrapper @@ -75,5 +76,19 @@ def self.inject(iface:, data:) def self.read_pcap(filename:, &block) PCAPRUB::Pcap.open_offline(filename).each_packet(&block) end + + # Write binary packets to a PCAP file + # @param [String] filename + # @param [Array] packets + # @return [void] + # @since 4.0.0 + # @author LemonTree55 + def self.write_pcap(filename:, packets:) + PCAPRUB::Pcap.dump_open(filename) do |pcap| + packets.each do |packet| + pcap.dump(packet) + end + end + end end end diff --git a/spec/packet_spec.rb b/spec/packet_spec.rb index de52b3d..64a082b 100644 --- a/spec/packet_spec.rb +++ b/spec/packet_spec.rb @@ -125,14 +125,26 @@ module PacketGen end describe '.write' do - let(:file) { ::File.join(__dir__, 'pcapng', 'sample.pcapng') } - - it '.write writes a Array of Packet to a file' do + it 'writes an Array of Packet to a PcapNG file' do + file = ::File.join(__dir__, 'pcapng', 'sample.pcapng') ary = Packet.read(file) write_file = Tempfile.new('pcapng') begin Packet.write(write_file.path, ary) - expect(Packet.read(write_file.path)).to eq(ary) + expect(PcapNG::File.new.read_packets(write_file.path)).to eq(ary) + ensure + write_file.close + write_file.unlink + end + end + + it 'writes an Array of Packet to a pcap file' do + file = ::File.join(__dir__, 'sample.pcap') + ary = Packet.read(file) + write_file = Tempfile.new('test.pcap') + begin + Packet.write(write_file.path, ary) + expect(Pcap.read(write_file.path)).to eq(ary) ensure write_file.close write_file.unlink From f2a74d3b3963edc606d87c0e30ed396f04f3e37d Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Mon, 16 Sep 2024 19:33:12 +0200 Subject: [PATCH 14/19] Update README.md --- README.md | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index f2c0ced..8ccfd04 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,27 @@ [![Gem Version](https://badge.fury.io/rb/packetgen.svg)](https://badge.fury.io/rb/packetgen) [![Action status](https://github.com/lemontree55/packetgen/workflows/ci/badge.svg?branch=master)](https://github.com/lemontree55/packetgen/actions?query=workflow%3Aci) + # PacketGen PacketGen provides simple ways to generate, send and capture network packets. ## Installation + PacketGen depends on PcapRub, which needs pcap development files to install. On Debian, you have to do: - $ sudo apt install libpcap-dev +```bash +sudo apt install libpcap-dev +``` Installation using RubyGems is then easy: - $ gem install packetgen +```bash +gem install packetgen +``` Or add it to a Gemfile: + ```ruby gem 'packetgen' ``` @@ -22,6 +29,7 @@ gem 'packetgen' ## Usage ### Easily create packets + ```ruby PacketGen.gen('IP') # generate a IP packet object PacketGen.gen('TCP') # generate a TCP over IP packet object @@ -37,6 +45,7 @@ PacketGen.gen('IP').to_s ``` ### Send packets on wire + ```ruby # send Ethernet packet PacketGen.gen('Eth', src: '00:00:00:00:00:01', dst: '00:00:00:00:00:02').to_w @@ -52,11 +61,13 @@ PacketGen.gen('RadioTap'). ``` ### Parse packets from binary data + ```ruby packet = PacketGen.parse(binary_data) ``` ### Capture packets from wire + ```ruby # Capture packets from first network interface, action from a block PacketGen.capture do |packet| @@ -71,6 +82,7 @@ packets = PacketGen.capture(iface: 'eth0', filter: 'ip src 1.1.1.2', max: 1) ``` ### Easily manipulate packets + ```ruby # access header fields pkt = PacketGen.gen('IP').add('TCP') @@ -96,6 +108,7 @@ pkt2.decapsulate(pkt2.ip) # pkt2 is now inner IP/TCP packet ``` ### Read/write PcapNG files + ```ruby # read a PcapNG file, containing multiple packets packets = PacketGen.read('file.pcapng') @@ -107,6 +120,7 @@ PacketGen.write('more_packets.pcapng', packets) ``` ### Add custom header/protocol + PacketGen permits adding your own header classes. First, define the new header class. For example: @@ -140,19 +154,22 @@ pkt.to_w # Send it on wire ``` ## Interactive console + PacketGen provides an interactive console: `pgconsole`. In this console, context includes PacketGen module to give direct access to PacketGen classes. A special `config` object gives local network configuration: - $ pgconsole - pg(main)> config - => # - pg(main)> packets = capture(max: 5) - pg(main)> exit +```text +$ pgconsole +pg(main)> config +=> # +pg(main)> packets = capture(max: 5) +pg(main)> exit +``` If `pry` gem is installed, it is used as backend for `pgconsole`, else IRB is used. @@ -167,19 +184,20 @@ Available plugins (available as gem) are: ## See also -Wiki: https://github.com/lemontree55/packetgen/wiki +Wiki: -API documentation: http://www.rubydoc.info/gems/packetgen +API documentation: ## Contributing -Bug reports and pull requests are welcome on GitHub at https://github.com/lemontree55/packetgen. +Bug reports and pull requests are welcome on GitHub at . ## License MIT License (see [LICENSE](https://github.com/lemontree55/packetgen/blob/master/LICENSE)) ### Other sources + All original code maintains its copyright from its original authors and licensing. This is mainly for PcapNG (originally copied from [PacketFu](https://github.com/packetfu/packetfu), From 9b107f708b046650b296c47ec736c15646e224db Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Sun, 6 Oct 2024 10:50:40 +0200 Subject: [PATCH 15/19] Update .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 9ab5042..1504e85 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ /.vscode/ *~ tags +.ruby-version +bin/rdbg From 40220a4f9fc7ccdb56cd1d05ced3d2ab52051c41 Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Sat, 23 Nov 2024 18:14:24 +0100 Subject: [PATCH 16/19] [specs] Clean up specs --- lib/packetgen/header.rb | 2 +- spec/capture_spec.rb | 20 +++--- spec/config_spec.rb | 3 +- spec/header/arp_spec.rb | 42 ++++++----- spec/header/asn1_base_spec.rb | 72 +++++++++++-------- spec/header/base_spec.rb | 67 +++++++++-------- spec/header/bootp_spec.rb | 13 ++-- spec/header/dhcp_spec.rb | 11 +-- spec/header/dhcpv6_spec.rb | 17 +++-- spec/header/dns/name_spec.rb | 9 +-- spec/header/dns/opt_spec.rb | 30 ++++---- spec/header/dns/qdsection_spec.rb | 8 +-- spec/header/dns/question_spec.rb | 11 +-- spec/header/dns/rr_spec.rb | 39 +++++----- spec/header/dns/rrsection_spec.rb | 12 ++-- spec/header/dns_spec.rb | 44 ++++++------ spec/header/dot11_spec.rb | 48 +++++++------ spec/header/dot1q_spec.rb | 5 +- spec/header/dot1x_spec.rb | 15 ++-- spec/header/eap_spec.rb | 35 +++++---- spec/header/eth_spec.rb | 27 +++---- spec/header/gre_spec.rb | 36 ++++++---- spec/header/http/headers_spec.rb | 4 +- spec/header/http/request_spec.rb | 61 +++++++++------- spec/header/http/response_spec.rb | 70 ++++++++++-------- spec/header/icmp_spec.rb | 13 ++-- spec/header/icmpv6_spec.rb | 19 ++--- spec/header/igmp_spec.rb | 22 +++--- spec/header/igmpv3_spec.rb | 30 ++++---- spec/header/ip_spec.rb | 34 +++++---- spec/header/ipv6_spec.rb | 64 +++++++++-------- spec/header/mdns_spec.rb | 28 ++++---- spec/header/mld_spec.rb | 34 ++++----- spec/header/mldv2_spec.rb | 44 ++++++------ spec/header/ospfv2_spec.rb | 83 ++++++++++++---------- spec/header/ospfv3_spec.rb | 51 ++++++------- spec/header/sctp/abort_error_chunk_spec.rb | 63 ++++++++-------- spec/header/sctp/cookie_chunk_spec.rb | 20 +++--- spec/header/sctp/data_chunk_spec.rb | 18 ++--- spec/header/sctp/heartbeat_chunk_spec.rb | 12 ++-- spec/header/sctp/init_chunk_spec.rb | 31 ++++---- spec/header/sctp/sack_chunk_spec.rb | 22 +++--- spec/header/sctp/shutdown_chunk_spec.rb | 28 ++++---- spec/header/sctp_spec.rb | 12 ++-- spec/header/snmp_spec.rb | 18 ++--- spec/header/tcp_option_spec.rb | 45 ++++++------ spec/header/tcp_options_spec.rb | 40 +++++------ spec/header/tcp_spec.rb | 49 +++++++------ spec/header/tftp_spec.rb | 33 +++++---- spec/header/udp_spec.rb | 26 ++++--- spec/header_spec.rb | 36 +++++----- spec/inspect_spec.rb | 14 ++-- spec/packet_spec.rb | 50 ++++++++----- spec/packetgen_spec.rb | 24 ++++--- spec/pcapng/epb_spec.rb | 16 ++--- spec/pcapng/file_spec_helper.rb | 67 +++++++++-------- spec/pcapng/idb_spec.rb | 14 ++-- spec/pcapng/shb_spec.rb | 12 ++-- spec/pcapng/spb_spec.rb | 12 ++-- spec/pcapng/unknown_block_spec.rb | 14 ++-- spec/proto_spec.rb | 2 + spec/shared_examples_for_headerable.rb | 3 + spec/spec_helper.rb | 1 + spec/support/binding_helper.rb | 16 ++--- spec/support/capture_helper.rb | 8 ++- spec/support/label_helper.rb | 4 +- spec/unknown_packet_spec.rb | 14 ++-- spec/utils/arp_spoofer_spec.rb | 18 ++--- spec/utils_spec.rb | 39 +++++----- 69 files changed, 1059 insertions(+), 845 deletions(-) diff --git a/lib/packetgen/header.rb b/lib/packetgen/header.rb index f88da0c..6d1e327 100644 --- a/lib/packetgen/header.rb +++ b/lib/packetgen/header.rb @@ -53,7 +53,7 @@ def add_class(klass) @header_classes = nil end - # Remove a foreign header previously added by {.add_header_class} + # Remove a foreign header previously added by {.add_class} # from known header classes. # @param [Class] klass # @return [void] diff --git a/spec/capture_spec.rb b/spec/capture_spec.rb index 3ab0eba..ed2c713 100644 --- a/spec/capture_spec.rb +++ b/spec/capture_spec.rb @@ -9,13 +9,13 @@ module PacketGen describe '#initialize' do it 'accepts no options' do cap = nil - expect { cap = Capture.new }.to_not raise_error + expect { cap = Capture.new }.not_to raise_error expect(cap).to be_a(Capture) end it 'accepts options' do options = { max: 12, timeout: 30, filter: 'ip', promisc: true, snaplen: 45, monitor: true } - expect { Capture.new(**options) }.to_not raise_error + expect { Capture.new(**options) }.not_to raise_error end end @@ -27,11 +27,9 @@ module PacketGen packets = cap.packets expect(packets).to be_a(Array) - expect(packets.size).to be >= 6 # some packets may be send by system during test - expect(packets.all? { |p| p.is_a? Packet }).to be(true) - packets.each do |packet| - expect(packet).to respond_to(:eth) - end + expect(packets.size).to be >= 6 # some packets may be send by system during test + expect(packets).to all(be_a(Packet)) + expect(packets).to all(respond_to(:eth)) end it 'captures unknown packets' do @@ -43,7 +41,7 @@ module PacketGen end packet = cap.packets.find { |pkt| pkt.is_a?(UnknownPacket) } - expect(packet).to_not be(nil) + expect(packet).not_to be_nil expect(packet.body).to eq(bin_str) end @@ -73,7 +71,7 @@ module PacketGen packets = cap.raw_packets expect(packets).to be_a(Array) - expect(packets.all? { |p| p.is_a? String }).to be(true) + expect(packets).to all(be_a(String)) end it 'captures :max packets' do @@ -118,9 +116,7 @@ module PacketGen cap_thread.join(0.5) expect(cap.packets.size).to be >= 2 expect(timestamps.size).to eq(cap.packets.size) - timestamps.each do |ts| - expect(ts).to be_a(Time) - end + expect(timestamps).to all(be_a(Time)) end it 'yields raw packet timestamp' do diff --git a/spec/config_spec.rb b/spec/config_spec.rb index 978e264..e646ff5 100644 --- a/spec/config_spec.rb +++ b/spec/config_spec.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + require 'spec_helper' require 'packetgen/config' module PacketGen - describe Config do let(:config) { Config.instance } diff --git a/spec/header/arp_spec.rb b/spec/header/arp_spec.rb index 952da76..8ed88fc 100644 --- a/spec/header/arp_spec.rb +++ b/spec/header/arp_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen @@ -7,18 +9,20 @@ module Header it 'in Eth packets' do expect(Eth).to know_header(ARP).with(ethertype: 0x806) end + it 'accepts to be added in Eth packets' do pkt = PacketGen.gen('Eth') - expect { pkt.add('ARP') }.to_not raise_error + expect { pkt.add('ARP') }.not_to raise_error expect(pkt.eth.ethertype).to eq(0x806) end it 'in Dot1q packets' do expect(Dot1q).to know_header(ARP).with(ethertype: 0x806) end + it 'accepts to be added in Dot1q packets' do pkt = PacketGen.gen('Dot1q') - expect { pkt.add('ARP') }.to_not raise_error + expect { pkt.add('ARP') }.not_to raise_error expect(pkt.dot1q.ethertype).to eq(0x806) end end @@ -40,16 +44,16 @@ module Header it 'accepts options' do options = { - htype: 0xf000, - ptype: 0x1234, - hlen: 255, - plen: 254, - opcode: 2, - src_mac: '01:02:03:03:03:03', - dst_mac: 'ff:ff:ff:ff:ff:ff', - src_ip: '10.0.0.1', - dst_ip: '10.0.0.2' - } + htype: 0xf000, + ptype: 0x1234, + hlen: 255, + plen: 254, + opcode: 2, + src_mac: '01:02:03:03:03:03', + dst_mac: 'ff:ff:ff:ff:ff:ff', + src_ip: '10.0.0.1', + dst_ip: '10.0.0.2' + } arp = ARP.new(options) options.each do |key, value| expect(arp.send(key)).to eq(value) @@ -61,7 +65,7 @@ module Header let(:arp) { ARP.new } it 'sets header from a string' do - str = (0...arp.sz).to_a.pack('C*') + 'arp body' + str = (0...arp.sz).to_a.pack('C*') << 'arp body' arp.read str expect(arp.htype).to eq(0x0001) expect(arp.ptype).to eq(0x0203) @@ -77,7 +81,7 @@ module Header end describe 'setters' do - before(:each) do + before do @arp = ARP.new end @@ -109,28 +113,28 @@ module Header it '#src_mac= accepts a MAC address string' do @arp.src_mac = 'ff:fe:fd:fc:fb:fa' 6.times do |i| - expect(@arp[:sha]["a#{i}".to_sym].to_i).to eq(0xff - i) + expect(@arp[:sha][:"a#{i}"].to_i).to eq(0xff - i) end end it '#dst_mac= accepts a MAC address string' do @arp.dst_mac = 'ff:fe:fd:fc:fb:fa' 6.times do |i| - expect(@arp[:tha]["a#{i}".to_sym].to_i).to eq(0xff - i) + expect(@arp[:tha][:"a#{i}"].to_i).to eq(0xff - i) end end it '#src_ip= accepts a IP address string' do @arp.src_ip = '128.129.130.131' 4.times do |i| - expect(@arp[:spa]["a#{i+1}".to_sym].to_i).to eq(128+i) + expect(@arp[:spa][:"a#{i + 1}"].to_i).to eq(128 + i) end end it '#dst_ip= accepts a IP address string' do @arp.dst_ip = '1.2.3.4' 4.times do |i| - expect(@arp[:tpa]["a#{i+1}".to_sym].to_i).to eq(1+i) + expect(@arp[:tpa][:"a#{i + 1}"].to_i).to eq(1 + i) end end end @@ -152,7 +156,7 @@ module Header arp = ARP.new str = arp.inspect expect(str).to be_a(String) - (arp.attributes - %i(body)).each do |attr| + (arp.attributes - %i[body]).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/asn1_base_spec.rb b/spec/header/asn1_base_spec.rb index e868344..3965b2f 100644 --- a/spec/header/asn1_base_spec.rb +++ b/spec/header/asn1_base_spec.rb @@ -1,59 +1,70 @@ +# frozen_string_literal: true + require_relative '../spec_helper' require_relative '../shared_examples_for_headerable' -$global_var = false +module PacketGenAsn1BaseTests + class TestBase2 < PacketGen::Header::Base + define_attr :field1, BinStruct::Int8 + define_attr :field2, BinStruct::Int8 + end + + class ASN1ToBind < PacketGen::Header::ASN1Base + boolean(:bool) + + def added_to_packet(packet) + packet.instance_eval('@added = true') + end + end +end module PacketGen module Header describe ASN1Base do - - class TestBase2 < Base - define_attr :field1, BinStruct::Int8 - define_attr :field2, BinStruct::Int8 + before(:all) do + PacketGen::Header.add_class(PacketGenAsn1BaseTests::TestBase2) + PacketGen::Header.add_class(PacketGenAsn1BaseTests::ASN1ToBind) end - class ASN1ToBind < ASN1Base - boolean(:bool) - - def added_to_packet(packet) - $global_var = true - end + after(:all) do + PacketGen::Header.remove_class(PacketGenAsn1BaseTests::TestBase2) + PacketGen::Header.remove_class(PacketGenAsn1BaseTests::ASN1ToBind) end - context '.bind' do - after(:each) { clear_bindings TestBase2 } + describe '.bind' do + after { clear_bindings(PacketGenAsn1BaseTests::TestBase2) } it 'binds a ASN1 header to another header with a single value' do - TestBase2.bind ASN1ToBind, field1: 55 - expect(TestBase2).to know_header(ASN1ToBind).with(field1: 55) + PacketGenAsn1BaseTests::TestBase2.bind(PacketGenAsn1BaseTests::ASN1ToBind, field1: 55) + expect(PacketGenAsn1BaseTests::TestBase2).to know_header(PacketGenAsn1BaseTests::ASN1ToBind).with(field1: 55) pkt = Packet.new.add('TestBase2').add('ASN1ToBind') expect(pkt.testbase2.field1).to eq(55) expect(pkt.testbase2.field2).to eq(0) end it 'binds a ASN1 header to another header with multiple field' do - TestBase2.bind ASN1ToBind, field1: 55, field2: 2 - expect(TestBase2).to know_header(ASN1ToBind).with(field1: 55, field2: 2) + PacketGenAsn1BaseTests::TestBase2.bind(PacketGenAsn1BaseTests::ASN1ToBind, field1: 55, field2: 2) + expect(PacketGenAsn1BaseTests::TestBase2).to know_header(PacketGenAsn1BaseTests::ASN1ToBind).with(field1: 55, field2: 2) pkt = Packet.new.add('TestBase2').add('ASN1ToBind') expect(pkt.testbase2.field1).to eq(55) expect(pkt.testbase2.field2).to eq(2) end it 'binds a ASN1 header to another header using a lambda' do - TestBase2.bind ASN1ToBind, field1: ->(v) { v.nil? ? 128 : v > 127 } - expect(TestBase2).to_not know_header(ASN1ToBind).with(field1: 127) - expect(TestBase2).to know_header(ASN1ToBind).with(field1: 128) - expect(TestBase2).to know_header(ASN1ToBind).with(field1: 129) - expect(TestBase2).to know_header(ASN1ToBind).with(field1: 255) + PacketGenAsn1BaseTests::TestBase2.bind(PacketGenAsn1BaseTests::ASN1ToBind, field1: ->(v) { v.nil? ? 128 : v > 127 }) + expect(PacketGenAsn1BaseTests::TestBase2).not_to know_header(PacketGenAsn1BaseTests::ASN1ToBind).with(field1: 127) + expect(PacketGenAsn1BaseTests::TestBase2).to know_header(PacketGenAsn1BaseTests::ASN1ToBind).with(field1: 128) + expect(PacketGenAsn1BaseTests::TestBase2).to know_header(PacketGenAsn1BaseTests::ASN1ToBind).with(field1: 129) + expect(PacketGenAsn1BaseTests::TestBase2).to know_header(PacketGenAsn1BaseTests::ASN1ToBind).with(field1: 255) pkt = Packet.new.add('TestBase2').add('ASN1ToBind') expect(pkt.testbase2.field1).to eq(128) end it 'binds a header with multiple possibility (multiple calls to .bind)' do - TestBase2.bind ASN1ToBind, field1: 55, field2: 2 - TestBase2.bind ASN1ToBind, field1: 54, field2: 3 - expect(TestBase2).to know_header(ASN1ToBind).with(field1: 55, field2: 2) - expect(TestBase2).to know_header(ASN1ToBind).with(field1: 54, field2: 3) + PacketGenAsn1BaseTests::TestBase2.bind(PacketGenAsn1BaseTests::ASN1ToBind, field1: 55, field2: 2) + PacketGenAsn1BaseTests::TestBase2.bind(PacketGenAsn1BaseTests::ASN1ToBind, field1: 54, field2: 3) + expect(PacketGenAsn1BaseTests::TestBase2).to know_header(PacketGenAsn1BaseTests::ASN1ToBind).with(field1: 55, field2: 2) + expect(PacketGenAsn1BaseTests::TestBase2).to know_header(PacketGenAsn1BaseTests::ASN1ToBind).with(field1: 54, field2: 3) pkt = Packet.new.add('TestBase2').add('ASN1ToBind') expect(pkt.testbase2.field1).to eq(55) @@ -61,16 +72,15 @@ def added_to_packet(packet) end end - context 'adding header to a packet' do + context 'when adding header to a packet' do it 'calls #added_to_packet' do - $global_var = false - Packet.gen('ASN1ToBind') - expect($global_var).to be(true) + p = Packet.gen('ASN1ToBind') + expect(p.instance_eval('@added')).to be(true) end end # Use of a real class, as ASN1Base cannot be instanciated - include_examples 'headerable', ASN1ToBind + include_examples 'headerable', PacketGenAsn1BaseTests::ASN1ToBind end end end diff --git a/spec/header/base_spec.rb b/spec/header/base_spec.rb index 41777e7..0f07d24 100644 --- a/spec/header/base_spec.rb +++ b/spec/header/base_spec.rb @@ -1,8 +1,8 @@ +# frozen_string_literal: true + require_relative '../spec_helper' require_relative '../shared_examples_for_headerable' -$global_var = false - module PGTest class Base < PacketGen::Header::Base define_attr :field1, BinStruct::Int8 @@ -14,22 +14,36 @@ class Base < PacketGen::Header::Base class ToBind < PacketGen::Header::Base define_attr :field, BinStruct::Int32, default: 1 define_attr :str, BinStruct::String - def added_to_packet(_packet) - $global_var = true + def added_to_packet(packet) + packet.instance_eval('@tobind_added = true') end + # used to check behaviour on Packet#is?, and on magic header method. def protocol_name self.class.to_s end end PacketGen::Header.add_class ToBind +end + +module PacketGenBaseTests + class PacketTest < PacketGen::Header::Base + define_attr :field, BinStruct::Int8, default: ->(h) { h.packet ? h.packet.ip.tos : 255 } + end + class PacketTest2 < PacketGen::Header::Base + define_attr :field, BinStruct::Int8, builder: lambda { |h, _| + lt = h.packet && (h.packet.ip.tos > 0) ? BinStruct::Int16 : BinStruct::Int8 + lt.new + } + end end + module PacketGen module Header describe Base do describe '.bind' do - after(:each) { clear_bindings PGTest::Base } + after { clear_bindings PGTest::Base } it 'binds a header with a single value' do PGTest::Base.bind PGTest::ToBind, field1: 55 @@ -55,7 +69,7 @@ module Header it 'binds a header using a lambda' do PGTest::Base.bind PGTest::ToBind, field1: ->(v) { v.nil? ? 128 : v > 127 } - expect(PGTest::Base).to_not know_header(PGTest::ToBind).with(field1: 127) + expect(PGTest::Base).not_to know_header(PGTest::ToBind).with(field1: 127) expect(PGTest::Base).to know_header(PGTest::ToBind).with(field1: 128) expect(PGTest::Base).to know_header(PGTest::ToBind).with(field1: 129) expect(PGTest::Base).to know_header(PGTest::ToBind).with(field1: 255) @@ -68,7 +82,7 @@ module Header it 'binds a header using procs' do PGTest::Base.bind PGTest::ToBind, procs: [->(h) { h.field1 = 42 }, - ->(h) { h.field1 == 42 && BinStruct::Int32.new.read(h.body[0..3]).to_i > 0 }] + ->(h) { h.field1 == 42 && BinStruct::Int32.new.read(h.body[0..3]).to_i > 0 }] expect(PGTest::Base).to know_header(PGTest::ToBind).with(field1: 42, body: [1].pack('N')) pkt = Packet.new.add('PGTest::Base').add('PGTest::ToBind') @@ -101,9 +115,9 @@ module Header end end - context 'in header plugin context' do - before(:all) { PGTest::Base.bind PGTest::ToBind, field1: 55 } - after(:all) { clear_bindings PGTest::Base } + context 'with a header from a plugin' do + before(:all) { PGTest::Base.bind(PGTest::ToBind, field1: 55) } + after(:all) { clear_bindings(PGTest::Base) } it 'Packet#add sets given fields' do pkt = PacketGen.gen('PGTest::Base').add('PGTest::ToBind', field: 42, str: '123') @@ -112,20 +126,17 @@ module Header end end - context 'adding header to a packet' do + context 'when adding header to a packet' do before(:all) do - class PacketTest < Base - define_attr :field, BinStruct::Int8, default: ->(h) { h.packet ? h.packet.ip.tos : 255 } - end - Header.add_class PacketTest - IP.bind PacketTest, protocol: 255 + Header.add_class(PacketGenBaseTests::PacketTest) + IP.bind(PacketGenBaseTests::PacketTest, protocol: 255) end - after(:all) { remove_binding IP, PacketTest} + + after(:all) { remove_binding(IP, PacketGenBaseTests::PacketTest) } it 'calls #added_to_packet' do - $global_var = false - Packet.gen('PGTest::ToBind') - expect($global_var).to be(true) + p = Packet.gen('PGTest::ToBind') + expect(p.instance_eval('@tobind_added')).to be(true) end it 'subclass may access to previous headers' do @@ -136,20 +147,18 @@ class PacketTest < Base context 'when parsing a packet' do before(:all) do - class PacketTest < Base - define_attr :field, BinStruct::Int8, builder: ->(h, _) { lt = h.packet && (h.packet.ip.tos > 0) ? BinStruct::Int16 : BinStruct::Int8; lt.new } - end - Header.add_class PacketTest - IP.bind PacketTest, protocol: 255 + Header.add_class(PacketGenBaseTests::PacketTest2) + IP.bind(PacketGenBaseTests::PacketTest2, protocol: 255) end - after(:all) { remove_binding IP, PacketTest} + + after(:all) { remove_binding(IP, PacketGenBaseTests::PacketTest) } it 'subclass may access to previous headers' do - str = Packet.gen('IP', tos: 45).add('PacketTest').to_s + str = Packet.gen('IP', tos: 45).add('PacketTest2').to_s pkt = Packet.parse(str) expect(pkt.is?('IP')).to be(true) - expect(pkt.is?('PacketTest')).to be(true) - expect(pkt.packettest[:field]).to be_a(BinStruct::Int16) + expect(pkt.is?('PacketTest2')).to be(true) + expect(pkt.packettest2[:field]).to be_a(BinStruct::Int16) end end diff --git a/spec/header/bootp_spec.rb b/spec/header/bootp_spec.rb index f034214..459456a 100644 --- a/spec/header/bootp_spec.rb +++ b/spec/header/bootp_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen @@ -8,9 +10,10 @@ module Header expect(UDP).to know_header(BOOTP).with(sport: 67, dport: 68) expect(UDP).to know_header(BOOTP).with(sport: 68, dport: 67) end + it 'accepts to be added in UDP packets' do pkt = PacketGen.gen('UDP') - expect { pkt.add('BOOTP') }.to_not raise_error + expect { pkt.add('BOOTP') }.not_to raise_error expect(pkt.udp.sport).to eq(67) expect(pkt.udp.dport).to eq(68) end @@ -20,13 +23,13 @@ module Header it 'read a BOOTP header' do raw = read_raw_packets('dhcp.pcapng').first pkt = PacketGen.parse(raw) - expect(pkt.is? 'BOOTP').to be(true) + expect(pkt.is?('BOOTP')).to be(true) bootp = pkt.bootp expect(bootp.op).to eq(1) expect(bootp.htype).to eq(1) expect(bootp.hlen).to eq(6) expect(bootp.hops).to eq(0) - expect(bootp.xid).to eq(15645) + expect(bootp.xid).to eq(15_645) expect(bootp.secs).to eq(0) expect(bootp.flags).to eq(0) expect(bootp.ciaddr).to eq('0.0.0.0') @@ -34,7 +37,7 @@ module Header expect(bootp.siaddr).to eq('0.0.0.0') expect(bootp.giaddr).to eq('0.0.0.0') chaddr = "\x00\v\x82\x01\xFCB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - expect(bootp.chaddr).to eq(binary chaddr) + expect(bootp.chaddr).to eq(binary(chaddr)) expect(bootp.sname).to eq('') expect(bootp.file).to eq('') end @@ -45,7 +48,7 @@ module Header raws = read_raw_packets('dhcp.pcapng') packets = read_packets('dhcp.pcapng') packets.each_with_index do |pkt, i| - expect(pkt.to_s).to eq(binary raws[i]) + expect(pkt.to_s).to eq(binary(raws[i])) end end end diff --git a/spec/header/dhcp_spec.rb b/spec/header/dhcp_spec.rb index 7145ed5..ac39186 100644 --- a/spec/header/dhcp_spec.rb +++ b/spec/header/dhcp_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen @@ -7,9 +9,10 @@ module Header it 'in BOOTP packets' do expect(BOOTP).to know_header(DHCP) end + it 'accepts to be added in BOOTP packets' do pkt = PacketGen.gen('BOOTP') - expect { pkt.add('DHCP') }.to_not raise_error + expect { pkt.add('DHCP') }.not_to raise_error end end @@ -17,8 +20,8 @@ module Header it 'read a DHCP header' do raw = read_raw_packets('dhcp.pcapng').first pkt = PacketGen.parse(raw) - expect(pkt.is? 'BOOTP').to be(true) - expect(pkt.is? 'DHCP').to be(true) + expect(pkt.is?('BOOTP')).to be(true) + expect(pkt.is?('DHCP')).to be(true) dhcp = pkt.dhcp expect(dhcp.magic).to eq(0x63825363) @@ -34,7 +37,7 @@ module Header let(:dhcp) { DHCP.new } it 'accepts an option as a hash' do - dhcp.options << { type: 'router', value: '10.0.0.1'} + dhcp.options << { type: 'router', value: '10.0.0.1' } expect(dhcp.options.size).to eq(1) expect(dhcp.options.first.type).to eq(3) expect(dhcp.options.first.human_type).to eq('router') diff --git a/spec/header/dhcpv6_spec.rb b/spec/header/dhcpv6_spec.rb index 92faa9b..34d3176 100644 --- a/spec/header/dhcpv6_spec.rb +++ b/spec/header/dhcpv6_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' DUID_LLT_DATA = binary("\x00\x01\x00\x01\x29\xc0\xde\x21\x00\x11\x22\x33\x44\x55").freeze @@ -13,14 +15,15 @@ module Header expect(UDP).to know_header(DHCPv6) expect(UDP).to know_header(DHCPv6::Relay) end + it 'accepts to be added in UDP packets' do pkt = PacketGen.gen('UDP') - expect { pkt.add('DHCPv6') }.to_not raise_error + expect { pkt.add('DHCPv6') }.not_to raise_error expect(pkt.udp.sport).to eq(546) expect(pkt.udp.dport).to eq(547) pkt = PacketGen.gen('UDP') - expect { pkt.add('DHCPv6::Relay') }.to_not raise_error + expect { pkt.add('DHCPv6::Relay') }.not_to raise_error expect(pkt.udp.sport).to eq(546) end end @@ -29,7 +32,7 @@ module Header it 'reads a DHCPv6 header' do raw = read_raw_packets('dhcpv6.pcapng').first pkt = PacketGen.parse(raw) - expect(pkt.is? 'DHCPv6').to be(true) + expect(pkt.is?('DHCPv6')).to be(true) dhcpv6 = pkt.dhcpv6 expect(dhcpv6.msg_type).to eq(1) @@ -41,7 +44,7 @@ module Header expect(dhcpv6.options.first.duid.to_human).to eq('DUID_LLT<2015-01-02 21:52:08 UTC,08:00:27:fe:8f:95>') end - it 'reads a DHCPv6::Relay header' # TODO: need a file to parse + it 'reads a DHCPv6::Relay header' # TODO: need a file to parse end describe '#options' do @@ -211,15 +214,15 @@ module Header end describe DHCPv6::DUID_LLT do - describe "#time=" do + describe '#time=' do it 'sets time' do new_time = Time.utc(2011, 1, 1, 12, 13, 14) duid = DHCPv6::DUID_LLT.new old_time = duid.time duid.time = new_time - expect(duid.time).to_not eq(old_time) + expect(duid.time).not_to eq(old_time) expect(duid.time).to eq(new_time) - expect(duid[:time].to_i).to eq(347199194) + expect(duid[:time].to_i).to eq(347_199_194) end end end diff --git a/spec/header/dns/name_spec.rb b/spec/header/dns/name_spec.rb index 7abc219..3e1d16b 100644 --- a/spec/header/dns/name_spec.rb +++ b/spec/header/dns/name_spec.rb @@ -1,9 +1,10 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' module PacketGen module Header class DNS - describe Name do let(:name) { Name.new } let(:dns) { DNS.new } @@ -16,10 +17,10 @@ class DNS describe '#read' do it 'sets Name from a binary string' do - name.read(binary "\0") + name.read(binary("\0")) expect(name.to_human).to eq('.') - name.read generate_label_str(['www', 'example', 'net']) + name.read generate_label_str(%w[www example net]) expect(name.to_human).to eq('www.example.net.') end @@ -28,7 +29,7 @@ class DNS name.dns = dns offset = DNS.new.sz - str = binary("\x03www" + [0xc0, offset].pack('C2')) + str = binary("\x03www#{[0xc0, offset].pack('C2')}") name.read(str) expect(name.to_human).to eq('www.example.net.') end diff --git a/spec/header/dns/opt_spec.rb b/spec/header/dns/opt_spec.rb index 7a27c17..6fd6d29 100644 --- a/spec/header/dns/opt_spec.rb +++ b/spec/header/dns/opt_spec.rb @@ -1,9 +1,10 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' module PacketGen module Header class DNS - describe OPT do let(:dns) { DNS.new } @@ -16,7 +17,7 @@ class DNS expect(opt.ttl).to eq(0) expect(opt.ext_rcode).to eq(0) expect(opt.version).to eq(0) - expect(opt.do?).to eq(false) + expect(opt.do?).to be(false) expect(opt.rdlength).to eq(0) expect(opt.rdata).to eq('') end @@ -34,10 +35,10 @@ class DNS } opt = OPT.new(dns, options) - expect(opt.name).to eq(options.delete :name) + expect(opt.name).to eq(options.delete(:name)) options.each do |key, value| meth = key.to_s - meth << '?' if value.is_a?(TrueClass) or value.is_a?(FalseClass) + meth << '?' if value.is_a?(TrueClass) || value.is_a?(FalseClass) expect(opt.send(meth)).to eq(value) end end @@ -52,7 +53,7 @@ class DNS expect(opt.udp_size).to eq(1024) expect(opt.ext_rcode).to eq(0x10) expect(opt.version).to eq(1) - expect(opt.do?).to eq(true) + expect(opt.do?).to be(true) expect(opt.z).to eq(0x41ac) end end @@ -91,24 +92,24 @@ class DNS describe '#to_s' do it 'returns a binary string' do opt = OPT.new(dns, name: 'example.net', udp_size: 512, version: 10) - expected_str = [7, 'example', 3, 'net', 0, 41, 512, 0xa0000, 0]. - pack('CA7CA3CnnNn') - expect(opt.to_s).to eq(binary expected_str) + expected_str = [7, 'example', 3, 'net', 0, 41, 512, 0xa0000, 0] + .pack('CA7CA3CnnNn') + expect(opt.to_s).to eq(binary(expected_str)) end end describe '#to_human' do it 'returns a human readable string' do opt = OPT.new(dns, udp_size: 600, ext_rcode: 45, version: 1, do: true) - expect(opt.to_human).to eq('. OPT UDPsize:600 extRCODE:45 EDNSversion:1' \ - ' flags:do options:none') + expect(opt.to_human).to eq('. OPT UDPsize:600 extRCODE:45 EDNSversion:1 ' \ + 'flags:do options:none') opt = OPT.new(dns, name: 'org') - expect(opt.to_human).to eq('org. OPT UDPsize:512 extRCODE:0 EDNSversion:0' \ - ' flags:none options:none') + expect(opt.to_human).to eq('org. OPT UDPsize:512 extRCODE:0 EDNSversion:0 ' \ + 'flags:none options:none') end end - context '(DNS options)' do + context 'with DNS options' do let(:opt) { OPT.new(dns) } it 'accepts DNS options' do @@ -123,8 +124,7 @@ class DNS it 'sets DNS options in binary string' do opt.options << { code: 48, data: '12' } - expect(opt.to_s).to eq([0, 41, 512, 0, 0].pack('CnnNn') + - "\x00\x30\x00\x0212") + expect(opt.to_s).to eq("#{[0, 41, 512, 0, 0].pack('CnnNn')}\x00\x30\x00\x0212") end end end diff --git a/spec/header/dns/qdsection_spec.rb b/spec/header/dns/qdsection_spec.rb index 0b6adcc..4d9c41b 100644 --- a/spec/header/dns/qdsection_spec.rb +++ b/spec/header/dns/qdsection_spec.rb @@ -1,12 +1,12 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' module PacketGen module Header class DNS - describe QDSection do - - before(:each) do + before do @dns = DNS.new @counter = BinStruct::Int32.new(value: 0) @section = QDSection.new(@dns, @counter) @@ -23,7 +23,7 @@ class DNS @counter.from_human(2) @section.read(str) expect(@section.size).to eq(2) - expect(@section.all? { |q| q.is_a? Question }).to be(true) + expect(@section).to all(be_a(Question)) expect(@section[0].to_s).to eq(q1.to_s) expect(@section[1].to_s).to eq(q2.to_s) end diff --git a/spec/header/dns/question_spec.rb b/spec/header/dns/question_spec.rb index 3f9774e..c130a9f 100644 --- a/spec/header/dns/question_spec.rb +++ b/spec/header/dns/question_spec.rb @@ -1,9 +1,10 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' module PacketGen module Header class DNS - describe Question do let(:dns) { DNS.new } @@ -23,7 +24,7 @@ class DNS } q = Question.new(dns, options) - expect(q.name).to eq(options.delete :name) + expect(q.name).to eq(options.delete(:name)) options.each do |key, value| expect(q.send(key)).to eq(value) end @@ -38,7 +39,7 @@ class DNS expect(q.type).to eq(2) expect(q.rrclass).to eq(3) - str = generate_label_str(%w(example org)) << [1, 1].pack('nn') + str = generate_label_str(%w[example org]) << [1, 1].pack('nn') q = Question.new(dns).read(str) expect(q.name).to eq('example.org.') expect(q.type).to eq(1) @@ -49,8 +50,8 @@ class DNS describe '#to_s' do it 'returns a binary string' do q = Question.new(dns, name: 'example.net') - expected_str = generate_label_str(%w(example net)) << [1, 1].pack('nn') - expect(q.to_s).to eq(binary expected_str) + expected_str = generate_label_str(%w[example net]) << [1, 1].pack('nn') + expect(q.to_s).to eq(binary(expected_str)) end end diff --git a/spec/header/dns/rr_spec.rb b/spec/header/dns/rr_spec.rb index 5e3553b..a51d32e 100644 --- a/spec/header/dns/rr_spec.rb +++ b/spec/header/dns/rr_spec.rb @@ -1,9 +1,10 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' module PacketGen module Header class DNS - describe RR do let(:dns) { DNS.new } @@ -29,7 +30,7 @@ class DNS } rr = RR.new(dns, options) - expect(rr.name).to eq(options.delete :name) + expect(rr.name).to eq(options.delete(:name)) options.each do |key, value| expect(rr.send(key)).to eq(value) end @@ -44,7 +45,7 @@ class DNS expect(rr.type).to eq(2) expect(rr.rrclass).to eq(3) - str = generate_label_str(%w(example org)) + str = generate_label_str(%w[example org]) str << [1, 1, 0x3_0000, 4, 192, 168, 1, 1].pack('nnNnC4') rr.read(str) expect(rr.name).to eq('example.org.') @@ -77,9 +78,9 @@ class DNS describe '#to_s' do it 'returns a binary string' do rr = RR.new(dns, name: 'example.net') - expected_str = generate_label_str(%w(example net)) + expected_str = generate_label_str(%w[example net]) expected_str << [1, 1, 0, 0].pack('nnNn') - expect(rr.to_s).to eq(binary expected_str) + expect(rr.to_s).to eq(binary(expected_str)) end end @@ -99,25 +100,25 @@ class DNS expect(rr.human_rdata).to eq(ip) end - %w(NS PTR CNAME).each do |type| - it 'handles IN/#{type} records' do + %w[NS PTR CNAME].each do |type| + it "handles IN/#{type} records" do rr.type = type - rr.rdata = generate_label_str(%w(example net)) + rr.rdata = generate_label_str(%w[example net]) expect(rr.human_rdata).to eq('example.net.') end end it 'handles IN/MX records' do rr.type = 'MX' - rr.rdata = [10].pack('n') + generate_label_str(%w(example net)) + rr.rdata = [10].pack('n') + generate_label_str(%w[example net]) expect(rr.human_rdata).to eq('10 example.net.') end it 'handles IN/SRV records' do - str = [1, 2, 12345].pack('n*') + generate_label_str(%w(example net)) + str = [1, 2, 12_345].pack('n*') + generate_label_str(%w[example net]) rr.type = 'SRV' rr.rdata = str - expect(rr.human_rdata).to eq("1 2 12345 example.net.") + expect(rr.human_rdata).to eq('1 2 12345 example.net.') end it 'returns quotted binary string for others records' do @@ -138,30 +139,30 @@ class DNS it 'returns a human readable string (IN class, AAAA type)' do ip6addr = '2a00:1:2:3:4::12e' rr = RR.new(dns, name: 'example.net', type: 'AAAA', - ttl: 3600, rdata: IPAddr.new(ip6addr).hton) + ttl: 3600, rdata: IPAddr.new(ip6addr).hton) expect(rr.to_human).to eq("AAAA IN example.net. TTL 3600 #{ip6addr}") end - %w(PTR NS CNAME).each do |type| + %w[PTR NS CNAME].each do |type| it "returns a human readable string (#{type} type)" do rr = RR.new(dns, name: 'example.net', type: type, rrclass: 3, - ttl: 0x10000, rdata: generate_label_str([])) + ttl: 0x10000, rdata: generate_label_str([])) expect(rr.to_human).to eq("#{type} CH example.net. TTL 65536 .") end end it 'returns a human readable string (MX type)' do rr = RR.new(dns, name: 'example.net', type: 'MX', rrclass: 4, - rdata: "\x00\x20" + generate_label_str(%w(mail example net))) + rdata: "\x00\x20#{generate_label_str(%w[mail example net])}") expect(rr.to_human).to eq('MX HS example.net. TTL 0 32 mail.example.net.') end it 'returns a human readable string (SOA type)' do - rdata = generate_label_str(%w(dns example net)) - rdata << generate_label_str(%w(mailbox example.net)) - rdata << [0xf_0000, 15000, 14999, 14998, 13210].pack('N*') + rdata = generate_label_str(%w[dns example net]) + rdata << generate_label_str(%w[mailbox example.net]) + rdata << [0xf_0000, 15_000, 14_999, 14_998, 13_210].pack('N*') rr = RR.new(dns, name: 'example.net', type: 6, rrclass: 3, - rdata: rdata) + rdata: rdata) expected_str = 'SOA CH example.net. TTL 0 dns.example.net. ' \ 'mailbox.example.net. 983040 15000 14999 14998 13210' diff --git a/spec/header/dns/rrsection_spec.rb b/spec/header/dns/rrsection_spec.rb index b6bfdae..2a8e390 100644 --- a/spec/header/dns/rrsection_spec.rb +++ b/spec/header/dns/rrsection_spec.rb @@ -1,12 +1,12 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' module PacketGen module Header class DNS - describe RRSection do - - before(:each) do + before do @dns = DNS.new @counter = BinStruct::Int32.new(value: 0) @section = RRSection.new(@dns, @counter) @@ -33,7 +33,7 @@ class DNS it 'does not increment counter associated to section' do obj = Object.new - expect { @section.push obj }.to_not change { @counter.value } + expect { @section.push obj }.not_to(change { @counter.value }) end end @@ -72,7 +72,7 @@ class DNS @section << obj expect(@section).to include(obj) deleted = @section.delete obj - expect(@section).to_not include(obj) + expect(@section).not_to include(obj) expect(deleted).to eql(obj) end @@ -94,7 +94,7 @@ class DNS @counter.from_human(2) @section.read(str) expect(@section.size).to eq(2) - expect(@section.all? { |rr| rr.is_a? RR }).to be(true) + expect(@section).to all(be_a(RR)) expect(@section[0].to_s).to eq(rr1.to_s) expect(@section[1].to_s).to eq(rr2.to_s) end diff --git a/spec/header/dns_spec.rb b/spec/header/dns_spec.rb index c600ebf..7d364e7 100644 --- a/spec/header/dns_spec.rb +++ b/spec/header/dns_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen @@ -12,14 +14,16 @@ module Header expect(TCP).to know_header(DNS).with(sport: 53) expect(TCP).to know_header(DNS).with(dport: 53) end + it 'accepts to be added in UDP packets' do pkt = PacketGen.gen('UDP') - expect { pkt.add('DNS') }.to_not raise_error + expect { pkt.add('DNS') }.not_to raise_error expect(pkt.udp.dport).to eq(53) end + it 'accepts to be added in TCP packets' do pkt = PacketGen.gen('TCP') - expect { pkt.add('DNS') }.to_not raise_error + expect { pkt.add('DNS') }.not_to raise_error expect(pkt.tcp.dport).to eq(53) end end @@ -66,14 +70,14 @@ module Header options.each do |key, value| meth = key.to_s - meth << '?' if value.is_a?(TrueClass) or value.is_a?(FalseClass) + meth << '?' if value.is_a?(TrueClass) || value.is_a?(FalseClass) expect(dns.send(meth.to_sym)).to eq(value) end end - end + end describe '#read' do - let(:dns) { DNS.new} + let(:dns) { DNS.new } it 'sets header from a string' do str = (0...dns.sz).to_a.pack('C*') @@ -91,7 +95,7 @@ module Header it 'also sets others sections from a string' do str = read_raw_packets(dns_pcapng).last - dns.read str[0x3e..-1] + dns.read str[0x3e..] expect(dns.id).to eq(0xd10) expect(dns.u16.to_i).to be(0x8180) expect(dns.response?).to be(true) @@ -124,7 +128,7 @@ module Header end describe 'setters' do - let(:dns) { DNS.new} + let(:dns) { DNS.new } it '#id= accepts integers' do dns.id = 0x8000 @@ -189,7 +193,7 @@ module Header strings = read_raw_packets(dns_pcapng) strings.each do |str| pkt = Packet.parse(str) - expect(pkt.is? 'DNS').to be(true) + expect(pkt.is?('DNS')).to be(true) expect(pkt.to_s).to eq(str) end end @@ -200,7 +204,7 @@ module Header dns = DNS.new str = dns.inspect expect(str).to be_a(String) - (dns.attributes - %i(u16) + %i(flags opcode rcode)).each do |attr| + (dns.attributes - %i[u16] + %i[flags opcode rcode]).each do |attr| expect(str).to include(attr.to_s) end end @@ -211,22 +215,22 @@ module Header it 'may add a Question to question section' do q = DNS::Question.new(dns, name: 'www.example.org') - expect { dns.qd << q }.to change { dns.qdcount }.by(1) - expected_str = "\x00" * 5 + "\x01" + "\x00" * 6 + - generate_label_str(%w(www example org)) + + expect { dns.qd << q }.to change(dns, :qdcount).by(1) + expected_str = +"\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00" << + generate_label_str(%w[www example org]) << "\x00\x01\x00\x01" - expect(dns.to_s).to eq(binary expected_str) + expect(dns.to_s).to eq(binary(expected_str)) end it 'may add a RR to answer section' do an = DNS::RR.new(dns, name: 'www.example.org', type: 'AAAA', ttl: 3600, - rdata: IPAddr.new('2000::1').hton) - expect { dns.an << an }.to change { dns.ancount }.by(1) - expected_str = "\x00" * 7 + "\x01" + "\x00" * 4 + - generate_label_str(%w(www example org)) + - "\x00\x1c\x00\x01\x00\x00\x0e\x10\x00\x10\x20" + - "\x00" * 14 + "\x01" - expect(dns.to_s).to eq(binary expected_str) + rdata: IPAddr.new('2000::1').hton) + expect { dns.an << an }.to change(dns, :ancount).by(1) + expected_str = +"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00" << + generate_label_str(%w[www example org]) << + "\x00\x1c\x00\x01\x00\x00\x0e\x10\x00\x10\x20" \ + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" + expect(dns.to_s).to eq(binary(expected_str)) end end end diff --git a/spec/header/dot11_spec.rb b/spec/header/dot11_spec.rb index bcabbe1..0459ef3 100644 --- a/spec/header/dot11_spec.rb +++ b/spec/header/dot11_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen @@ -43,18 +45,20 @@ module Header it 'in PPI packets' do expect(PPI).to know_header(Dot11).with(dlt: 105) end + it 'accepts to be added in PPI packets' do pkt = PacketGen.gen('PPI') - expect { pkt.add('Dot11') }.to_not raise_error + expect { pkt.add('Dot11') }.not_to raise_error expect(pkt.ppi.dlt).to eq(105) end it 'in RadioTap packets' do expect(RadioTap).to know_header(Dot11) end + it 'accepts to be added in RadioTap packets' do pkt = PacketGen.gen('RadioTap') - expect { pkt.add('Dot11') }.to_not raise_error + expect { pkt.add('Dot11') }.not_to raise_error end end @@ -109,15 +113,15 @@ module Header Dot11.fcs = true expect(pkts.map { |pkt| pkt.headers.last.class }).to eq(classes) - expect(pkts[0].is? 'Dot11::Management').to be(true) + expect(pkts[0].is?('Dot11::Management')).to be(true) expect(pkts[0].dot11_beacon.timestamp).to eq(0x26bbb9189) expect(pkts[0].dot11_beacon.elements.first.human_type).to eq('SSID') expect(pkts[0].dot11_beacon.elements.first.value).to eq('martinet3') - expect(pkts[1].is? 'Dot11::Management').to be(true) + expect(pkts[1].is?('Dot11::Management')).to be(true) expect(pkts[1].dot11_probereq.elements[1].human_type).to eq('Rates') - expect(pkts[1].dot11_probereq.elements[1].value). - to eq(binary "\x82\x84\x8b\x96\x0c\x12\x18\x24") - expect(pkts[3].is? 'Dot11::Management').to be(true) + expect(pkts[1].dot11_probereq.elements[1].value) + .to eq(binary("\x82\x84\x8b\x96\x0c\x12\x18\x24")) + expect(pkts[3].is?('Dot11::Management')).to be(true) expect(pkts[3].dot11_proberesp.timestamp).to eq(0x26bbcad38) expect(pkts[3].dot11_proberesp.beacon_interval).to eq(0x64) expect(pkts[3].dot11_proberesp.cap).to eq(0x0411) @@ -125,22 +129,22 @@ module Header expect(pkts[3].dot11_proberesp.elements[2].value).to eq("\x0b") expect(pkts[4].dot11.human_type).to eq('Control') expect(pkts[4].dot11.human_subtype).to eq('Ack') - expect(pkts[5].is? 'Dot11::Beacon').to be(true) - expect(pkts[6].is? 'Dot11::Management').to be(true) - expect(pkts[6].is? 'Dot11::Auth').to be(true) + expect(pkts[5].is?('Dot11::Beacon')).to be(true) + expect(pkts[6].is?('Dot11::Management')).to be(true) + expect(pkts[6].is?('Dot11::Auth')).to be(true) expect(pkts[6].dot11_auth.algo).to eq(0) expect(pkts[6].dot11_auth.seqnum).to eq(1) expect(pkts[6].dot11_auth.status).to eq(0) expect(pkts[6].dot11_auth.elements.size).to eq(0) - expect(pkts[8].is? 'Dot11::Auth').to be(true) + expect(pkts[8].is?('Dot11::Auth')).to be(true) expect(pkts[8].dot11_auth.seqnum).to eq(2) expect(pkts[8].dot11_auth.elements.size).to eq(1) - expect(pkts[10].is? 'Dot11::AssoReq').to be(true) + expect(pkts[10].is?('Dot11::AssoReq')).to be(true) expect(pkts[10].dot11_assoreq.cap).to eq(0x411) expect(pkts[10].dot11_assoreq.listen_interval).to eq(10) expect(pkts[10].dot11_assoreq.elements.size).to eq(4) expect(pkts[10].dot11_assoreq.elements[2].human_type).to eq('ESRates') - expect(pkts[12].is? 'Dot11::AssoResp').to be(true) + expect(pkts[12].is?('Dot11::AssoResp')).to be(true) expect(pkts[12].dot11_assoresp.cap).to eq(0x411) expect(pkts[12].dot11_assoresp.status).to eq(0) expect(pkts[12].dot11_assoresp.aid).to eq(0xc004) @@ -177,7 +181,8 @@ module Header end describe '#calc_checksum' do - before(:each) { @pkt = PcapNG::File.new.read_packets(data_file)[0] } + before { @pkt = PcapNG::File.new.read_packets(data_file)[0] } + it 'calculates checksum' do expected_fcs = @pkt.dot11_data.fcs expect(@pkt.dot11_data.calc_checksum).to eq(expected_fcs) @@ -202,20 +207,20 @@ module Header data_str = PcapNG::File.new.read_packet_bytes(data_file).first pkt = Packet.parse(mngt_str) - expect(pkt.is? 'Dot11::Beacon').to be(true) + expect(pkt.is?('Dot11::Beacon')).to be(true) expect(pkt.to_s).to eq(mngt_str) pkt = Packet.parse(ctrl_str, first_header: 'Dot11') - expect(pkt.is? 'Dot11::Control').to be(true) + expect(pkt.is?('Dot11::Control')).to be(true) expect(pkt.to_s).to eq(ctrl_str) pkt = Packet.parse(wep_str, first_header: 'RadioTap') - expect(pkt.is? 'Dot11::Data').to be(true) + expect(pkt.is?('Dot11::Data')).to be(true) expect(pkt.dot11.wep?).to be(true) expect(pkt.to_s).to eq(wep_str) pkt = Packet.parse(data_str) - expect(pkt.is? 'Dot11::Data').to be(true) + expect(pkt.is?('Dot11::Data')).to be(true) expect(pkt.dot11.wep?).to be(false) expect(pkt.to_s).to eq(data_str[0..-5]) # remove FCS ensure @@ -236,7 +241,7 @@ module Header dot11 = Dot11::Control.new str = dot11.inspect expect(str).to be_a(String) - expect(dot11.to_h.keys).to_not include(:mac3, :sequence_ctrl, :mac4, + expect(dot11.to_h.keys).not_to include(:mac3, :sequence_ctrl, :mac4, :qos_ctrl, :ht_ctrl) (dot11.to_h.keys - %i[body]).each do |attr| expect(str).to include(attr.to_s) @@ -248,7 +253,7 @@ module Header it 'builds a Dot11::Beacon packet' do expect { PacketGen.gen('Beacon') }.to raise_error(ArgumentError, /^unknown/) pkt = nil - expect { pkt = PacketGen.gen('Dot11::Management').add('Dot11::Beacon') }.to_not raise_error + expect { pkt = PacketGen.gen('Dot11::Management').add('Dot11::Beacon') }.not_to raise_error expect(pkt.headers.last).to be_a(Dot11::Beacon) expect(pkt.dot11).to eq(pkt.dot11_management) @@ -272,7 +277,7 @@ module Header it 'builds a IP packet over IEEE 802.11 (no encryption)' do pkt = PacketGen.gen('Dot11::Data', mac1: '00:01:02:03:04:05', - mac2: '06:07:08:09:0a:0b', mac3: '0c:0d:0e:0f:10:11') + mac2: '06:07:08:09:0a:0b', mac3: '0c:0d:0e:0f:10:11') expect { pkt.add('IP') }.to raise_error(BindingError, /no layer assoc/) pkt.add('LLC').add('SNAP').add('IP', src: '192.168.0.1', dst: '192.168.0.2') @@ -288,6 +293,7 @@ module Header describe Dot11::Management do let(:ctrl_mngt_pkts) { read_packets('ieee802.11-join.pcapng') } + describe '#reply!' do it 'inverts source and destination addresses' do pkt = ctrl_mngt_pkts[10] diff --git a/spec/header/dot1q_spec.rb b/spec/header/dot1q_spec.rb index 6df919b..25ad175 100644 --- a/spec/header/dot1q_spec.rb +++ b/spec/header/dot1q_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen @@ -7,9 +9,10 @@ module Header it 'in Eth packets' do expect(Eth).to know_header(Dot1q).with(ethertype: 0x8100) end + it 'accepts to be added in Eth packets' do pkt = PacketGen.gen('Eth') - expect { pkt.add('Dot1q') }.to_not raise_error + expect { pkt.add('Dot1q') }.not_to raise_error expect(pkt.eth.ethertype).to eq(0x8100) end end diff --git a/spec/header/dot1x_spec.rb b/spec/header/dot1x_spec.rb index 902e610..d939188 100644 --- a/spec/header/dot1x_spec.rb +++ b/spec/header/dot1x_spec.rb @@ -1,25 +1,28 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen module Header - describe Dot1x do describe 'binding' do it 'in Eth packets' do expect(Eth).to know_header(Dot1x).with(ethertype: 0x888e) end + it 'in SNAP packets' do expect(SNAP).to know_header(Dot1x).with(proto_id: 0x888e) end it 'accepts to be added in Eth packets' do pkt = PacketGen.gen('Eth') - expect { pkt.add('Dot1x') }.to_not raise_error + expect { pkt.add('Dot1x') }.not_to raise_error expect(pkt.eth.ethertype).to eq(0x888e) end + it 'accepts to be added in SNAP packets' do pkt = PacketGen.gen('SNAP') - expect { pkt.add('Dot1x') }.to_not raise_error + expect { pkt.add('Dot1x') }.not_to raise_error expect(pkt.snap.proto_id).to eq(0x888e) end end @@ -61,7 +64,7 @@ module Header it 'decodes a complex string' do packets = read_packets('dot1x.pcapng') - expect(packets[0].is? 'Dot1x').to be(true) + expect(packets[0].is?('Dot1x')).to be(true) expect(packets[0].dot1x.type).to eq(1) expect(packets[0].dot1x.human_type).to eq('Start') expect(packets[0].dot1x.length).to eq(0) @@ -81,7 +84,7 @@ module Header it 'returns a binary string' do dot1x = Dot1x.new expected = "\x01\x00\x00\x00" - expect(dot1x.to_s).to eq(binary expected) + expect(dot1x.to_s).to eq(binary(expected)) end end @@ -90,7 +93,7 @@ module Header dot1x = Dot1x.new str = dot1x.inspect expect(str).to be_a(String) - (dot1x.to_h.keys - %i(body)).each do |attr| + (dot1x.to_h.keys - %i[body]).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/eap_spec.rb b/spec/header/eap_spec.rb index 129ced3..85e2900 100644 --- a/spec/header/eap_spec.rb +++ b/spec/header/eap_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen @@ -7,9 +9,10 @@ module Header it 'in Dot1x packets' do expect(Dot1x).to know_header(EAP).with(type: 0) end + it 'accepts to be added in Dot1x packets' do pkt = PacketGen.gen('Dot1x') - expect { pkt.add('EAP') }.to_not raise_error + expect { pkt.add('EAP') }.not_to raise_error expect(pkt.dot1x.type).to eq(0) end end @@ -59,7 +62,7 @@ module Header expect(eap.type).to eq(5) expect(eap.body).to eq('body') - str = (3..(EAP.new.sz+2)).to_a.pack('C*') + 'body' + str = (3..(EAP.new.sz + 2)).to_a.pack('C*') + 'body' eap.read str expect(eap.code).to eq(3) expect(eap.id).to eq(4) @@ -73,9 +76,9 @@ module Header raws = PcapNG::File.new.read_packet_bytes(file) pkt = Packet.parse(raws[2]) - expect(pkt.is? 'Dot11::Data').to be(true) - expect(pkt.is? 'Dot1x').to be(true) - expect(pkt.is? 'EAP').to be(true) + expect(pkt.is?('Dot11::Data')).to be(true) + expect(pkt.is?('Dot1x')).to be(true) + expect(pkt.is?('EAP')).to be(true) expect(pkt.eap).to be_a_response expect(pkt.eap.code).to eq(2) expect(pkt.eap.human_code).to eq('Response') @@ -85,7 +88,7 @@ module Header expect(pkt.body).to eq('WFA-SimpleConfig-Enrollee-1-0') pkt = Packet.parse(raws[3]) - expect(pkt.is? 'EAP').to be(true) + expect(pkt.is?('EAP')).to be(true) expect(pkt.eap).to be_a_request expect(pkt.eap.code).to eq(1) expect(pkt.eap.human_code).to eq('Request') @@ -97,9 +100,9 @@ module Header expect(pkt.body).to eq(binary("\x01\x00")) pkt = Packet.parse(raws.last) - expect(pkt.is? 'EAP').to be(true) + expect(pkt.is?('EAP')).to be(true) expect(pkt.eap).to be_a_failure - expect(pkt.eap).to_not be_a_success + expect(pkt.eap).not_to be_a_success expect(pkt.eap.human_code).to eq('Failure') expect(pkt.eap.id).to eq(18) end @@ -130,7 +133,7 @@ module Header expect(str).to include(attr.to_s) end %i[type vendor_id vendor_type].each do |attr| - expect(str).to_not include(attr.to_s) + expect(str).not_to include(attr.to_s) end end @@ -141,7 +144,7 @@ module Header expect(str).to include(attr.to_s) end %i[vendor_id vendor_type].each do |attr| - expect(str).to_not include(attr.to_s) + expect(str).not_to include(attr.to_s) end end @@ -197,16 +200,16 @@ module Header it 'decodes complex strings' do pkt = @packets[3] - expect(pkt.is? 'EAP').to be(true) + expect(pkt.is?('EAP')).to be(true) expect(pkt.eap).to be_a_request expect(pkt.eap.human_type).to eq('EAP-TLS') expect(pkt.eap_tls.flags).to eq(0x20) - expect(pkt.eap_tls).to_not be_length_present - expect(pkt.eap_tls).to_not be_more_fragments + expect(pkt.eap_tls).not_to be_length_present + expect(pkt.eap_tls).not_to be_more_fragments expect(pkt.eap_tls).to be_tls_start pkt = @packets[4] - expect(pkt.is? 'EAP::TLS').to be(true) + expect(pkt.is?('EAP::TLS')).to be(true) expect(pkt.eap).to be_a_response expect(pkt.eap.human_type).to eq('EAP-TLS') expect(pkt.eap_tls.flags).to eq(0) @@ -216,9 +219,10 @@ module Header describe '#inspect' do let(:eaptls) { EAP::TLS.new } + it 'only prints present fields' do str = eaptls.inspect - expect(str).to_not include('tls_length') + expect(str).not_to include('tls_length') eaptls2 = EAP::TLS.new(l: true) str = eaptls2.inspect @@ -234,6 +238,7 @@ module Header describe EAP::TTLS do let(:eapttls) { EAP::TTLS.new } + describe '#initialize' do it 'creates a EAP::TTLS header with default values' do expect(eapttls.type?).to be(true) diff --git a/spec/header/eth_spec.rb b/spec/header/eth_spec.rb index 4a3781b..ab48e4f 100644 --- a/spec/header/eth_spec.rb +++ b/spec/header/eth_spec.rb @@ -1,10 +1,11 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen module Header - describe Eth::MacAddr do - before(:each) do + before do @mac = Eth::MacAddr.new.from_human('00:01:02:03:04:05') end @@ -23,7 +24,6 @@ module Header end describe Eth do - describe '#initialize' do it 'creates a Ethernet header with default values' do eth = Eth.new @@ -48,7 +48,7 @@ module Header end describe '#read' do - let(:eth) { Eth.new} + let(:eth) { Eth.new } it 'sets header from a string' do str = (0...eth.sz).to_a.pack('C*') + 'body' @@ -61,21 +61,21 @@ module Header end describe 'setters' do - before(:each) do + before do @eth = Eth.new end it '#dst= accepts a MAC address string' do @eth.dst = 'ff:fe:fd:fc:fb:fa' 6.times do |i| - expect(@eth[:dst]["a#{i}".to_sym].to_i).to eq(0xff - i) + expect(@eth[:dst][:"a#{i}"].to_i).to eq(0xff - i) end end it '#src= accepts a MAC address string' do @eth.src = 'ff:fe:fd:fc:fb:fa' 6.times do |i| - expect(@eth[:src]["a#{i}".to_sym].to_i).to eq(0xff - i) + expect(@eth[:src][:"a#{i}"].to_i).to eq(0xff - i) end end @@ -93,13 +93,16 @@ module Header it 'send a Eth header on wire', :sudo do body = binary("\x00" * 64) pkt = Packet.gen('Eth', dst: 'ff:ff:ff:ff:ff:ff', - src: 'ff:ff:ff:ff:ff:ff').add('IP', body: body) - Thread.new { sleep 0.1; pkt.eth.to_w('lo') } + src: 'ff:ff:ff:ff:ff:ff').add('IP', body: body) + Thread.new do + sleep 0.1 + pkt.eth.to_w('lo') + end packets = Packet.capture(iface: 'lo', max: 1, filter: 'ether dst ff:ff:ff:ff:ff:ff', timeout: 2) packet = packets.first - expect(packet.is? 'Eth').to be(true) + expect(packet.is?('Eth')).to be(true) expect(packet.eth.dst).to eq('ff:ff:ff:ff:ff:ff') expect(packet.eth.src).to eq('ff:ff:ff:ff:ff:ff') expect(packet.eth.ethertype).to eq(0x0800) @@ -111,7 +114,7 @@ module Header it 'returns a binary string' do ethx = Eth.new(dst: '00:01:02:03:04:05', ethertype: 0x800).to_s expected = binary("\x00\x01\x02\x03\x04\x05" \ - "\x00\x00\x00\x00\x00\x00\x08\x00") + "\x00\x00\x00\x00\x00\x00\x08\x00") expect(ethx).to eq(expected) end end @@ -121,7 +124,7 @@ module Header eth = Eth.new str = eth.inspect expect(str).to be_a(String) - (eth.attributes - %i(body)).each do |attr| + (eth.attributes - %i[body]).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/gre_spec.rb b/spec/header/gre_spec.rb index e987cab..3d3db4d 100644 --- a/spec/header/gre_spec.rb +++ b/spec/header/gre_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen @@ -7,36 +9,40 @@ module Header it 'in IP packets' do expect(IP).to know_header(GRE).with(protocol: 47) end + it 'accepts to be added in IP packets' do pkt = PacketGen.gen('IP') - expect { pkt.add('GRE') }.to_not raise_error + expect { pkt.add('GRE') }.not_to raise_error expect(pkt.ip.protocol).to eq(47) end it 'in IPv6 packets' do expect(IPv6).to know_header(GRE).with(next: 47) end + it 'accepts to be added in IPv6 packets' do pkt = PacketGen.gen('IPv6') - expect { pkt.add('GRE') }.to_not raise_error + expect { pkt.add('GRE') }.not_to raise_error expect(pkt.ipv6.next).to eq(47) end it 'of IP packets' do expect(GRE).to know_header(IP).with(protocol_type: 0x800) end + it 'accepts IP headers to be added' do pkt = PacketGen.gen('GRE') - expect { pkt.add('IP') }.to_not raise_error + expect { pkt.add('IP') }.not_to raise_error expect(pkt.gre.protocol_type).to eq(0x800) end it 'of IPv6 packets' do expect(GRE).to know_header(IPv6).with(protocol_type: 0x86dd) end + it 'accepts IPv6 headers to be added' do pkt = PacketGen.gen('GRE') - expect { pkt.add('IPv6') }.to_not raise_error + expect { pkt.add('IPv6') }.not_to raise_error expect(pkt.gre.protocol_type).to eq(0x86dd) end end @@ -104,9 +110,9 @@ module Header it 'parses a complete GRE packet' do pkt = Packet.read(File.join(__dir__, 'gre.pcapng')).first - expect(pkt.is? 'IP').to be(true) - expect(pkt.is? 'GRE').to be(true) - expect(pkt.is? 'ICMP').to be(true) + expect(pkt.is?('IP')).to be(true) + expect(pkt.is?('GRE')).to be(true) + expect(pkt.is?('ICMP')).to be(true) expect(pkt.ip(1)).to be_a(Header::IP) expect(pkt.ip(1).body).to be_a(Header::GRE) expect(pkt.ip(2)).to be_a(Header::IP) @@ -124,7 +130,7 @@ module Header end describe '#to_s' do - let(:gre) { GRE.new} + let(:gre) { GRE.new } it 'returns a binary string' do gre.u16 = 0xb000 @@ -134,8 +140,8 @@ module Header gre.seqnum = 0x53535353 gre.body = 'body' expected_str = binary("\xb0\x00\x08\x00\xca\xfe\x00\x00" \ - "\xac\xac\xac\xac\x53\x53\x53\x53" \ - 'body') + "\xac\xac\xac\xac\x53\x53\x53\x53" \ + 'body') expect(gre.to_s).to eq(expected_str) end @@ -146,20 +152,20 @@ module Header gre.seqnum = 0x53535353 gre.body = 'body' expected_str = binary("\x30\x00\x08\x00" \ - "\xac\xac\xac\xac\x53\x53\x53\x53" \ - 'body') + "\xac\xac\xac\xac\x53\x53\x53\x53" \ + 'body') expect(gre.to_s).to eq(expected_str) end end describe '#inspect' do - let(:gre) { GRE.new} + let(:gre) { GRE.new } it 'returns a String with all attributes' do gre.u16 = 0xb000 str = gre.inspect expect(str).to be_a(String) - (gre.attributes - %i(body)).each do |attr| + (gre.attributes - %i[body]).each do |attr| expect(str).to include(attr.to_s) end end @@ -174,7 +180,7 @@ module Header expect(str).to include(attr.to_s) end gre.optional_attributes.reject { |f| gre.present?(f) }.each do |attr| - expect(str).to_not include(attr.to_s) + expect(str).not_to include(attr.to_s) end end end diff --git a/spec/header/http/headers_spec.rb b/spec/header/http/headers_spec.rb index 1d460ef..5f5019e 100644 --- a/spec/header/http/headers_spec.rb +++ b/spec/header/http/headers_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' module PacketGen @@ -9,7 +11,7 @@ module HTTP let(:encoded_headers) { "Content-Type: text/html\r\nConnection: keep-alive\r\n\r\n" } it 'is BinStruct::Structable' do - Headers < BinStruct::Structable + expect(Headers < BinStruct::Structable).to be(true) end describe '#read' do diff --git a/spec/header/http/request_spec.rb b/spec/header/http/request_spec.rb index f474b05..9e14f59 100644 --- a/spec/header/http/request_spec.rb +++ b/spec/header/http/request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' module PacketGen @@ -19,7 +21,7 @@ module HTTP it 'issue-112: adding a HTTP::Request does not raise' do pkt = PacketGen.gen('IP').add('TCP') - expect { pkt.add('HTTP::Request') }.to_not raise_error + expect { pkt.add('HTTP::Request') }.not_to raise_error end end @@ -28,68 +30,77 @@ module HTTP http_req = Request.new expect(http_req).to be_a(Request) end + it 'creates a TCP header with given options' do - http_req = Request.new(verb: "GET", path: "/", headers: {'User-Agent' => 'dummy/1.0' }) + http_req = Request.new(verb: 'GET', path: '/', headers: { 'User-Agent' => 'dummy/1.0' }) expect(http_req).to be_a(Request) - expect(http_req.verb).to eq("GET") - expect(http_req.path).to eq("/") - expect(http_req.headers).to eq({'User-Agent' => 'dummy/1.0' }) + expect(http_req.verb).to eq('GET') + expect(http_req.path).to eq('/') + expect(http_req.headers).to eq({ 'User-Agent' => 'dummy/1.0' }) end end describe 'setters' do let(:http_req) { Request.new } + it '#verb= accepts strings' do - http_req.verb = "GET" - expect(http_req.verb).to eq("GET") + http_req.verb = 'GET' + expect(http_req.verb).to eq('GET') end + it '#path= accepts strings' do - http_req.path = "/" - expect(http_req.path).to eq("/") + http_req.path = '/' + expect(http_req.path).to eq('/') end + it '#version= accepts strings' do - http_req.version = "HTTP/1.1" - expect(http_req.version).to eq("HTTP/1.1") + http_req.version = 'HTTP/1.1' + expect(http_req.version).to eq('HTTP/1.1') end end describe '#to_s' do let(:http_req) { Request.new } + it 'errors out without needed fields' do - expect{ http_req.to_s }.to raise_error(FormatError) - http_req.verb = "GET" - expect{ http_req.to_s }.to raise_error(FormatError) - http_req.path = "/" + expect { http_req.to_s }.to raise_error(FormatError) + http_req.verb = 'GET' + expect { http_req.to_s }.to raise_error(FormatError) + http_req.path = '/' expect(http_req.to_s).to be_a(String) end + it 'returns a string with the needed fields' do - http_req.verb = "GET" - http_req.path = "/" + http_req.verb = 'GET' + http_req.path = '/' expect(http_req.to_s).to be_a(String) end end describe '#read' do let(:http_req) { Request.new } + it 'parses http request data from a string' do http_req.read("GET / HTTP/1.1\r\nUser-Agent: dummy/1.0\r\n\r\n") - expect(http_req.verb).to eq("GET") - expect(http_req.path).to eq("/") - expect(http_req.version).to eq("HTTP/1.1") - expect(http_req.headers).to eq({"User-Agent" => "dummy/1.0"}) + expect(http_req.verb).to eq('GET') + expect(http_req.path).to eq('/') + expect(http_req.version).to eq('HTTP/1.1') + expect(http_req.headers).to eq({ 'User-Agent' => 'dummy/1.0' }) end + it 'parses weird http request data from a string with invalid encoding' do http_req.read("GET / HTTP/1.1\r\nUser-Agent: dummy/1.0\r\n\r\n\r\xD1") - expect(http_req.verb).to eq("GET") - expect(http_req.path).to eq("/") - expect(http_req.version).to eq("HTTP/1.1") - expect(http_req.headers).to eq({"User-Agent" => "dummy/1.0"}) + expect(http_req.verb).to eq('GET') + expect(http_req.path).to eq('/') + expect(http_req.version).to eq('HTTP/1.1') + expect(http_req.headers).to eq({ 'User-Agent' => 'dummy/1.0' }) expect(http_req.body.bytes).to eq("\r\xD1".bytes) end end describe '#inspect' do let(:http_req) { Request.new } + it 'returns a String with all attributes' do expect(http_req.inspect).to be_a(String) end diff --git a/spec/header/http/response_spec.rb b/spec/header/http/response_spec.rb index fdbee36..d32095e 100644 --- a/spec/header/http/response_spec.rb +++ b/spec/header/http/response_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' module PacketGen @@ -11,7 +13,7 @@ module HTTP it 'adding a HTTP::Response does not raise' do pkt = PacketGen.gen('IP').add('TCP') - expect { pkt.add('HTTP::Response') }.to_not raise_error + expect { pkt.add('HTTP::Response') }.not_to raise_error end end @@ -20,50 +22,57 @@ module HTTP http_resp = Response.new expect(http_resp).to be_a(Response) end + it 'creates a HTTP Response header with given options' do - http_resp = Response.new(status_code: "200", status_mesg: "OK") - expect(http_resp.status_code).to eq("200") - expect(http_resp.status_mesg).to eq("OK") + http_resp = Response.new(status_code: '200', status_mesg: 'OK') + expect(http_resp.status_code).to eq('200') + expect(http_resp.status_mesg).to eq('OK') expect(http_resp).to be_a(Response) end end describe 'setters' do let(:http_resp) { Response.new } + it '#version= accepts strings' do - http_resp.version = "HTTP/1.1" - expect(http_resp.version).to eq("HTTP/1.1") + http_resp.version = 'HTTP/1.1' + expect(http_resp.version).to eq('HTTP/1.1') end + it '#status_code= accepts strings' do - http_resp.status_code = "200" - expect(http_resp.status_code).to eq("200") + http_resp.status_code = '200' + expect(http_resp.status_code).to eq('200') end + it '#status_mesg= accepts strings' do - http_resp.status_mesg = "OK" - expect(http_resp.status_mesg).to eq("OK") + http_resp.status_mesg = 'OK' + expect(http_resp.status_mesg).to eq('OK') end + it '#body= accepts strings' do - http_resp.body = "this is a body" - expect(http_resp.body).to eq("this is a body") + http_resp.body = 'this is a body' + expect(http_resp.body).to eq('this is a body') end end describe '#to_s' do let(:http_resp) { Response.new } + it 'errors out without needed fields' do - expect{ http_resp.to_s }.to raise_error(FormatError) - http_resp.version = "HTTP/1.1" - expect{ http_resp.to_s }.to raise_error(FormatError) - http_resp.status_code = "200" - expect{ http_resp.to_s }.to raise_error(FormatError) - http_resp.status_mesg = "OK" + expect { http_resp.to_s }.to raise_error(FormatError) + http_resp.version = 'HTTP/1.1' + expect { http_resp.to_s }.to raise_error(FormatError) + http_resp.status_code = '200' + expect { http_resp.to_s }.to raise_error(FormatError) + http_resp.status_mesg = 'OK' expect(http_resp.to_s).to be_a(String) expect(http_resp.to_s).to eq("HTTP/1.1 200 OK\r\n") end + it 'returns a string with the needed fields' do - http_resp.version = "HTTP/1.1" - http_resp.status_code = "200" - http_resp.status_mesg = "OK" + http_resp.version = 'HTTP/1.1' + http_resp.status_code = '200' + http_resp.status_mesg = 'OK' expect(http_resp.to_s).to be_a(String) expect(http_resp.to_s).to eq("HTTP/1.1 200 OK\r\n") end @@ -71,25 +80,28 @@ module HTTP describe '#read' do let(:http_resp) { Response.new } + it 'parses http response data from a string' do http_resp.read("HTTP/1.1 200 OK\r\nHost: tcpdump.org\r\ndogs: lol\r\n\r\n") - expect(http_resp.version).to eq("HTTP/1.1") - expect(http_resp.status_code).to eq("200") - expect(http_resp.status_mesg).to eq("OK") - expect(http_resp.headers).to eq({"Host"=>"tcpdump.org", "dogs"=>"lol"}) + expect(http_resp.version).to eq('HTTP/1.1') + expect(http_resp.status_code).to eq('200') + expect(http_resp.status_mesg).to eq('OK') + expect(http_resp.headers).to eq({ 'Host' => 'tcpdump.org', 'dogs' => 'lol' }) end + it 'parses weird http response data from a string with invalid encoding' do http_resp.read("HTTP/1.1 200 OK\r\nHost: tcpdump.org\r\ndogs: lol\r\n\r\n\r\xD1") - expect(http_resp.version).to eq("HTTP/1.1") - expect(http_resp.status_code).to eq("200") - expect(http_resp.status_mesg).to eq("OK") - expect(http_resp.headers).to eq({"Host"=>"tcpdump.org", "dogs"=>"lol"}) + expect(http_resp.version).to eq('HTTP/1.1') + expect(http_resp.status_code).to eq('200') + expect(http_resp.status_mesg).to eq('OK') + expect(http_resp.headers).to eq({ 'Host' => 'tcpdump.org', 'dogs' => 'lol' }) expect(http_resp.body.bytes).to eq("\r\xD1".bytes) end end describe '#inspect' do let(:http_resp) { Response.new } + it 'returns a String with all attributes' do expect(http_resp.inspect).to be_a(String) end diff --git a/spec/header/icmp_spec.rb b/spec/header/icmp_spec.rb index c3cfe6a..8a713ad 100644 --- a/spec/header/icmp_spec.rb +++ b/spec/header/icmp_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen @@ -7,9 +9,10 @@ module Header it 'in IP packets' do expect(IP).to know_header(ICMP).with(protocol: 1) end + it 'accepts to be added in IP packets' do pkt = PacketGen.gen('IP') - expect { pkt.add('ICMP') }.to_not raise_error + expect { pkt.add('ICMP') }.not_to raise_error expect(pkt.ip.protocol).to eq(1) end end @@ -34,7 +37,7 @@ module Header end describe '#read' do - let(:icmp) { ICMP.new} + let(:icmp) { ICMP.new } it 'sets header from a string' do str = (1..icmp.sz).to_a.pack('C*') + 'body' @@ -55,7 +58,7 @@ module Header end describe 'setters' do - let(:icmp) { ICMP.new} + let(:icmp) { ICMP.new } it '#type= accepts integers' do icmp.type = 0xef @@ -69,7 +72,7 @@ module Header it '#checksum= accepts integers' do icmp.checksum = 0xffff - expect(icmp[:checksum].to_i).to eq(65535) + expect(icmp[:checksum].to_i).to eq(65_535) end end @@ -86,7 +89,7 @@ module Header icmp = ICMP.new str = icmp.inspect expect(str).to be_a(String) - (icmp.attributes - %i(body)).each do |attr| + (icmp.attributes - %i[body]).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/icmpv6_spec.rb b/spec/header/icmpv6_spec.rb index c9042ee..2fa4477 100644 --- a/spec/header/icmpv6_spec.rb +++ b/spec/header/icmpv6_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen @@ -9,9 +11,10 @@ module Header it 'in IP packets' do expect(IPv6).to know_header(ICMPv6).with(next: 58) end + it 'accepts to be added in IPv6 packets' do pkt = PacketGen.gen('IPv6') - expect { pkt.add('ICMPv6') }.to_not raise_error + expect { pkt.add('ICMPv6') }.not_to raise_error expect(pkt.ipv6.next).to eq(58) end end @@ -36,7 +39,7 @@ module Header end describe '#read' do - let(:icmp) { ICMPv6.new} + let(:icmp) { ICMPv6.new } it 'sets header from a string' do str = PcapNG::File.new.read_packet_bytes(pcapng_file).first @@ -47,7 +50,7 @@ module Header expected = "\0\0\0\0\x2a\x01\x0e\x35\x8b\x7f\x9c\x10\x12\x8b" \ "\x3c\x32\xc3\xe4\xc0\x1b\x01\x01\x68\xa3\x78\x03" \ "\xcc\xb2" - expect(icmp.body).to eq(binary expected) + expect(icmp.body).to eq(binary(expected)) end end @@ -57,7 +60,7 @@ module Header packets.each do |pkt| checksum = pkt.icmpv6.checksum pkt.icmpv6.checksum = 0 - expect(pkt.icmpv6.checksum).to_not eq(checksum) + expect(pkt.icmpv6.checksum).not_to eq(checksum) pkt.calc expect(pkt.icmpv6.checksum).to eq(checksum) end @@ -65,7 +68,7 @@ module Header end describe 'setters' do - let(:icmp) { ICMPv6.new} + let(:icmp) { ICMPv6.new } it '#type= accepts integers' do icmp.type = 0xef @@ -79,7 +82,7 @@ module Header it '#checksum= accepts integers' do icmp.checksum = 0xffff - expect(icmp[:checksum].to_i).to eq(65535) + expect(icmp[:checksum].to_i).to eq(65_535) end end @@ -87,7 +90,7 @@ module Header it 'returns a binary string' do str = PcapNG::File.new.read_packet_bytes(pcapng_file).first icmp = Packet.parse(str) - expect(icmp.to_s).to eq(str) + expect(icmp.to_s).to eq(str) end end @@ -96,7 +99,7 @@ module Header icmpv6 = ICMPv6.new str = icmpv6.inspect expect(str).to be_a(String) - (icmpv6.attributes - %i(body)).each do |attr| + (icmpv6.attributes - %i[body]).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/igmp_spec.rb b/spec/header/igmp_spec.rb index 05097ef..85f529f 100644 --- a/spec/header/igmp_spec.rb +++ b/spec/header/igmp_spec.rb @@ -1,16 +1,18 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen module Header - describe IGMP do describe 'bindings' do it 'in IP packets' do expect(IP).to know_header(IGMP).with(protocol: 2, frag: 0, ttl: 1, tos: 0) end + it 'accepts to be added in IP packets' do pkt = PacketGen.gen('IP') - expect { pkt.add('IGMP') }.to_not raise_error + expect { pkt.add('IGMP') }.not_to raise_error expect(pkt.ip.protocol).to eq(2) expect(pkt.ip.frag).to eq(0) expect(pkt.ip.ttl).to eq(1) @@ -29,7 +31,7 @@ module Header it 'accepts options' do igmp = IGMP.new(type: 255, max_resp_time: 254, checksum: 0x1234, - group_addr: '224.0.0.1') + group_addr: '224.0.0.1') expect(igmp.type).to eq(255) expect(igmp.max_resp_time).to eq(254) expect(igmp.checksum).to eq(0x1234) @@ -38,7 +40,7 @@ module Header end describe '#read' do - let(:igmp) { IGMP.new} + let(:igmp) { IGMP.new } it 'sets header from a string' do str = (1..igmp.sz).to_a.pack('C*') + 'body' @@ -51,11 +53,11 @@ module Header it 'reads a IGMP header in a real packet' do pkt = PacketGen.gen('IP', src: '192.168.0.1', dst: '224.0.0.1', - ttl: 1, protocol: 2) + ttl: 1, protocol: 2) pkt.body = "\x11\x00\xee\xff\x00\x00\x00\x00" parsed_pkt = PacketGen.parse(pkt.to_s) - expect(parsed_pkt.is? 'IP').to be(true) - expect(parsed_pkt.is? 'IGMP').to be(true) + expect(parsed_pkt.is?('IP')).to be(true) + expect(parsed_pkt.is?('IGMP')).to be(true) expect(parsed_pkt.igmp.human_type).to eq('MembershipQuery') expect(parsed_pkt.igmp.max_resp_time).to eq(0) expect(parsed_pkt.igmp.group_addr).to eq('0.0.0.0') @@ -73,7 +75,7 @@ module Header describe '#to_s' do it 'returns a binary string' do igmp = IGMP.new(type: 'MembershipQuery', max_resp_time: 20, - group_addr: '224.0.0.1') + group_addr: '224.0.0.1') igmp.calc_checksum expected = binary("\x11\x14\x0e\xea\xe0\x00\x00\x01") expect(igmp.to_s).to eq(expected) @@ -85,7 +87,7 @@ module Header igmp = IGMP.new str = igmp.inspect expect(str).to be_a(String) - (igmp.attributes - %i(body)).each do |attr| + (igmp.attributes - %i[body]).each do |attr| expect(str).to include(attr.to_s) end end @@ -99,7 +101,7 @@ module Header expect(pkt.ip.ttl).to eq(1) expect(pkt.ip.options.size).to eq(1) expect(pkt.ip.options[0]).to be_a(IP::RA) - expected = "\x46\x00\x00\x20\x00\x00\x00\x00\x01\x02\xd7\x92" + expected = +"\x46\x00\x00\x20\x00\x00\x00\x00\x01\x02\xd7\x92" expected << "\x4b\x0c\x22\x38\xe0\x00\x00\x01\x94\x04\x00\x00" expected << "\x11\x00\xee\xff\x00\x00\x00\x00" expect(pkt.to_s).to eq(binary(expected)) diff --git a/spec/header/igmpv3_spec.rb b/spec/header/igmpv3_spec.rb index ecba89a..ac289a2 100644 --- a/spec/header/igmpv3_spec.rb +++ b/spec/header/igmpv3_spec.rb @@ -1,16 +1,18 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen module Header - describe IGMPv3 do describe 'bindings' do it 'in IP packets' do expect(IP).to know_header(IGMPv3).with(protocol: 2, frag: 0, ttl: 1, tos: 0xc0) end + it 'accepts to be added in IP packets' do pkt = PacketGen.gen('IP') - expect { pkt.add('IGMPv3') }.to_not raise_error + expect { pkt.add('IGMPv3') }.not_to raise_error expect(pkt.ip.protocol).to eq(2) expect(pkt.ip.frag).to eq(0) expect(pkt.ip.ttl).to eq(1) @@ -35,7 +37,7 @@ module Header end describe '#read' do - let(:igmp) { IGMPv3.new} + let(:igmp) { IGMPv3.new } it 'sets header from a string' do str = (1..igmp.sz).to_a.pack('C*') + 'body' @@ -47,11 +49,11 @@ module Header it 'reads a IGMPv3 header in a real packet' do pkt = PacketGen.gen('IP', src: '192.168.0.1', dst: '224.0.0.1', - ttl: 1, protocol: 2, tos: 0xc0) + ttl: 1, protocol: 2, tos: 0xc0) pkt.body = "\x11\x00\xee\xff" parsed_pkt = PacketGen.parse(pkt.to_s) - expect(parsed_pkt.is? 'IP').to be(true) - expect(parsed_pkt.is? 'IGMPv3').to be(true) + expect(parsed_pkt.is?('IP')).to be(true) + expect(parsed_pkt.is?('IGMPv3')).to be(true) expect(parsed_pkt.igmpv3.human_type).to eq('MembershipQuery') expect(parsed_pkt.igmpv3.max_resp_time).to eq(0) end @@ -79,7 +81,7 @@ module Header igmp = IGMPv3.new str = igmp.inspect expect(str).to be_a(String) - (igmp.attributes - %i(body)).each do |attr| + (igmp.attributes - %i[body]).each do |attr| expect(str).to include(attr.to_s) end end @@ -94,7 +96,7 @@ module Header expect(pkt.ip.ttl).to eq(1) expect(pkt.ip.options.size).to eq(1) expect(pkt.ip.options[0]).to be_a(IP::RA) - expected = "\x46\xc0\x00\x1c\x00\x00\x00\x00\x01\x02\xd6\xd6" + expected = +"\x46\xc0\x00\x1c\x00\x00\x00\x00\x01\x02\xd6\xd6" expected << "\x4b\x0c\x22\x38\xe0\x00\x00\x01\x94\x04\x00\x00" expected << "\x11\x00\xee\xff" expect(pkt.to_s).to eq(binary(expected)) @@ -102,10 +104,10 @@ module Header end describe '#max_resp_time' do - let (:igmp) { IGMPv3.new } + let(:igmp) { IGMPv3.new } it 'sets IGMPv3 encoded Max Resp Time' do - igmp.max_resp_time = 10000 + igmp.max_resp_time = 10_000 expect(igmp[:max_resp_time].value).to eq(0xe3) end @@ -120,9 +122,9 @@ module Header it 'decodes a V3 extended Membership Query' do pkt = packets.first - expect(pkt.is? 'IGMPv3').to be(true) + expect(pkt.is?('IGMPv3')).to be(true) expect(pkt.igmpv3.type).to eq(0x11) - expect(pkt.is? 'IGMPv3::MQ').to be(true) + expect(pkt.is?('IGMPv3::MQ')).to be(true) expect(pkt.igmpv3_mq.group_addr).to eq('224.0.0.9') expect(pkt.igmpv3_mq.u8).to eq(0xf) expect(pkt.igmpv3_mq.flag_s?).to be(true) @@ -135,11 +137,11 @@ module Header it 'decodes a V3 extended Membership Report' do pkt = packets.last - expect(pkt.is? 'IGMPv3').to be(true) + expect(pkt.is?('IGMPv3')).to be(true) expect(pkt.igmpv3.type).to eq(0x22) expect(pkt.igmpv3.max_resp_code).to eq(0) expect(pkt.igmpv3.checksum).to eq(0x276d) - expect(pkt.is? 'IGMPv3::MR').to be(true) + expect(pkt.is?('IGMPv3::MR')).to be(true) expect(pkt.igmpv3_mr.reserved).to eq(0) expect(pkt.igmpv3_mr.number_of_gr).to eq(1) expect(pkt.igmpv3_mr.group_records.size).to eq(1) diff --git a/spec/header/ip_spec.rb b/spec/header/ip_spec.rb index 6b0a351..5e98938 100644 --- a/spec/header/ip_spec.rb +++ b/spec/header/ip_spec.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen module Header describe IP::Addr do - before(:each) do + before do @ipaddr = IP::Addr.new.from_human('192.168.25.43') end @@ -28,27 +30,30 @@ module Header it 'in Eth packets' do expect(Eth).to know_header(IP).with(ethertype: 0x800) end + it 'accepts to be added in Eth packets' do pkt = PacketGen.gen('Eth') - expect { pkt.add('IP') }.to_not raise_error + expect { pkt.add('IP') }.not_to raise_error expect(pkt.eth.ethertype).to eq(0x800) end it 'in SNAP packets' do expect(SNAP).to know_header(IP).with(proto_id: 0x800) end + it 'accepts to be added in SNAP packets' do pkt = PacketGen.gen('SNAP') - expect { pkt.add('IP') }.to_not raise_error + expect { pkt.add('IP') }.not_to raise_error expect(pkt.snap.proto_id).to eq(0x800) end it 'in IP packets' do expect(IP).to know_header(IP).with(protocol: 4) end + it 'accepts to be added in IP packets' do pkt = PacketGen.gen('IP') - expect { pkt.add('IP') }.to_not raise_error + expect { pkt.add('IP') }.not_to raise_error expect(pkt.ip.protocol).to eq(4) end end @@ -115,7 +120,7 @@ module Header it 'reads a IP header with options' do pkt = PacketGen.read(File.join(__dir__, 'ip_opts.pcapng')).first - expect(pkt.is? 'IP').to be(true) + expect(pkt.is?('IP')).to be(true) ip = pkt.ip expect(ip.ihl).to eq(11) @@ -150,7 +155,7 @@ module Header end describe 'setters' do - before(:each) do + before do @ip = IP.new end @@ -192,7 +197,7 @@ module Header it '#src= accepts dotted addresses' do @ip.src = '1.2.3.4' 1.upto(4) do |i| - expect(@ip[:src]["a#{i}".to_sym].to_i).to eq(i) + expect(@ip[:src][:"a#{i}"].to_i).to eq(i) end expect(@ip[:src].to_i).to eq(0x01020304) end @@ -200,7 +205,7 @@ module Header it '#dst= accepts dotted addresses' do @ip.dst = '1.2.3.4' 1.upto(4) do |i| - expect(@ip[:dst]["a#{i}".to_sym].to_i).to eq(i) + expect(@ip[:dst][:"a#{i}"].to_i).to eq(i) end expect(@ip[:dst].to_i).to eq(0x01020304) end @@ -214,12 +219,15 @@ module Header it 'sends a IP header on wire', :sudo do body = binary("\x00" * 64) pkt = Packet.gen('IP').add('UDP', sport: 35_535, dport: 65_535, body: body) - Thread.new { sleep 0.1; pkt.ip.to_w('lo') } + Thread.new do + sleep 0.1 + pkt.ip.to_w('lo') + end packets = Packet.capture(iface: 'lo', max: 1, filter: 'ip dst 127.0.0.1 and ip proto 17 and port 35535', timeout: 2) packet = packets.first - expect(packet.is? 'IP').to be(true) + expect(packet.is?('IP')).to be(true) expect(packet.ip.dst).to eq('127.0.0.1') expect(packet.ip.protocol).to eq(UDP::IP_PROTOCOL) expect(packet.udp.sport).to eq(35_535) @@ -235,7 +243,7 @@ module Header idx = [ip.id].pack('n') expected = "\x45\x00\x00\x14#{idx}\x00\x00\x40\x00\x00\x00" \ "\x7f\x00\x00\x01\x7f\x00\x00\x01" - expect(ip.to_s).to eq(binary expected) + expect(ip.to_s).to eq(binary(expected)) end end @@ -353,9 +361,9 @@ module Header .to eq('RR:1.2.3.4,5.6.7.8') expect(IP::Option.build(type: 'SI', id: 0xfedc).to_human) .to eq('SI:65244') - expect(IP::Option.build(type: 'RA', value: 12345).to_human) + expect(IP::Option.build(type: 'RA', value: 12_345).to_human) .to eq('RA:12345') - expect(IP::Option.build(type: 0x7f, data: "abcd").to_human) + expect(IP::Option.build(type: 0x7f, data: 'abcd').to_human) .to eq('unk-127:"abcd"') end end diff --git a/spec/header/ipv6_spec.rb b/spec/header/ipv6_spec.rb index f3c25b3..396099c 100644 --- a/spec/header/ipv6_spec.rb +++ b/spec/header/ipv6_spec.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen module Header describe IPv6::Addr do - before(:each) do + before do @ipv6addr = IPv6::Addr.new.from_human('fe80::21a:c5ff:fe00:152') end @@ -23,7 +25,7 @@ module Header end it '#read gets a IPv6 address from a binary string' do - bin_str = "\xfe\x80" << "\x00" * 6 << "\x02\x1a\xc5\xff\xfe\x00\x01\x52" + bin_str = +"\xfe\x80" << "\x00" * 6 << "\x02\x1a\xc5\xff\xfe\x00\x01\x52" ipv6addr = IPv6::Addr.new.read(bin_str) expect(ipv6addr.to_human).to eq('fe80::21a:c5ff:fe00:152') end @@ -34,27 +36,30 @@ module Header it 'in Eth packets' do expect(Eth).to know_header(IPv6).with(ethertype: 0x86dd) end + it 'accepts to be added in Eth packets' do pkt = PacketGen.gen('Eth') - expect { pkt.add('IPv6') }.to_not raise_error + expect { pkt.add('IPv6') }.not_to raise_error expect(pkt.eth.ethertype).to eq(0x86dd) end it 'in SNAP packets' do expect(SNAP).to know_header(IPv6).with(proto_id: 0x86dd) end + it 'accepts to be added in SNAP packets' do pkt = PacketGen.gen('SNAP') - expect { pkt.add('IPv6') }.to_not raise_error + expect { pkt.add('IPv6') }.not_to raise_error expect(pkt.snap.proto_id).to eq(0x86dd) end it 'in IP packets' do expect(IP).to know_header(IPv6).with(protocol: 41) end + it 'accepts to be added in IP packets' do pkt = PacketGen.gen('IP') - expect { pkt.add('IPv6') }.to_not raise_error + expect { pkt.add('IPv6') }.not_to raise_error expect(pkt.ip.protocol).to eq(41) end end @@ -94,7 +99,7 @@ module Header end describe '#read' do - let(:ipv6) { IPv6.new} + let(:ipv6) { IPv6.new } it 'sets header from a string' do str = (1..ipv6.sz).to_a.pack('C*') + 'body' @@ -112,9 +117,9 @@ module Header it 'parses IPv6 extension headers' do pkt = PacketGen.read(File.join(__dir__, 'mldv2.pcapng'))[0] - expect(pkt.is? 'IPv6').to be(true) - expect(pkt.is? 'ICMPv6').to be(true) - expect(pkt.is? 'IPv6::HopByHop').to be(true) + expect(pkt.is?('IPv6')).to be(true) + expect(pkt.is?('ICMPv6')).to be(true) + expect(pkt.is?('IPv6::HopByHop')).to be(true) expect(pkt.ipv6_hopbyhop.options.size).to eq(11) ra = pkt.ipv6_hopbyhop.options[6] expect(ra.human_type).to eq('router_alert') @@ -141,36 +146,36 @@ module Header end describe 'setters' do - before(:each) do + before do @ipv6 = IPv6.new end it '#length= accepts integers' do - @ipv6.length = 65530 - expect(@ipv6[:length].to_i).to eq(65530) + @ipv6.length = 65_530 + expect(@ipv6[:length].to_i).to eq(65_530) end it '#next= accepts integers' do - @ipv6.next = 65530 - expect(@ipv6[:next].to_i).to eq(65530) + @ipv6.next = 65_530 + expect(@ipv6[:next].to_i).to eq(65_530) end it '#hop= accepts integers' do - @ipv6.hop = 65530 - expect(@ipv6[:hop].to_i).to eq(65530) + @ipv6.hop = 65_530 + expect(@ipv6[:hop].to_i).to eq(65_530) end it '#src= accepts integers' do @ipv6.src = '1:2:3:4:5:6:7:8' 1.upto(8) do |i| - expect(@ipv6[:src]["a#{i}".to_sym].to_i).to eq(i) + expect(@ipv6[:src][:"a#{i}"].to_i).to eq(i) end end it '#dst= accepts integers' do @ipv6.dst = '1:2:3:4:5:6:7:8' 1.upto(8) do |i| - expect(@ipv6[:dst]["a#{i}".to_sym].to_i).to eq(i) + expect(@ipv6[:dst][:"a#{i}"].to_i).to eq(i) end end end @@ -180,16 +185,19 @@ module Header expect(IPv6.new).to respond_to(:to_w) end - it 'sends a IPv6 header on wire', :sudo, :notravis do + it 'sends a IPv6 header on wire', :notravis, :sudo do body = (0..63).to_a.pack('C*') - pkt = Packet.gen('IPv6', traffic_class: 0x40, flow_label: 0x12345, hop: 0x22, src: '::2'). - add('UDP', sport: 35535, dport: 65535, body: body) - Thread.new { sleep 0.1; pkt.ipv6.to_w('lo') } + pkt = Packet.gen('IPv6', traffic_class: 0x40, flow_label: 0x12345, hop: 0x22, src: '::2') + .add('UDP', sport: 35_535, dport: 65_535, body: body) + Thread.new do + sleep 0.1 + pkt.ipv6.to_w('lo') + end packets = PacketGen.capture(iface: 'lo', max: 1, filter: 'ip6 dst ::1 and ip6 proto 17', timeout: 2) packet = packets.first - expect(packet.is? 'IPv6').to be(true) + expect(packet.is?('IPv6')).to be(true) expect(packet.ipv6.traffic_class).to eq(0x40) expect(packet.ipv6.flow_label).to eq(0x12345) expect(packet.ipv6.length).to eq(0) @@ -197,8 +205,8 @@ module Header expect(packet.ipv6.hop).to eq(0x22) expect(packet.ipv6.dst).to eq('::1') expect(packet.ipv6.src).to eq('::2') - expect(packet.udp.sport).to eq(35535) - expect(packet.udp.dport).to eq(65535) + expect(packet.udp.sport).to eq(35_535) + expect(packet.udp.dport).to eq(65_535) expect(packet.body).to eq(body) end end @@ -208,8 +216,8 @@ module Header ipv6 = IPv6.new ipv6.body = 'body' ipv6.calc_length - expected = "\x60\x00\x00\x00\x00\x04\x00\x40" - expected << ("\x00" * 15 + "\x01") * 2 << 'body' + expected = +"\x60\x00\x00\x00\x00\x04\x00\x40" + expected << ("\x00" * 15 << "\x01") * 2 << 'body' binary expected expect(ipv6.to_s).to eq(expected) end @@ -220,7 +228,7 @@ module Header ip = IPv6.new str = ip.inspect expect(str).to be_a(String) - (ip.attributes - %i(body) + %i(version tclass flow_label)).each do |attr| + (ip.attributes - %i[body] + %i[version tclass flow_label]).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/mdns_spec.rb b/spec/header/mdns_spec.rb index 39ff932..78f8107 100644 --- a/spec/header/mdns_spec.rb +++ b/spec/header/mdns_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen @@ -10,41 +12,42 @@ module Header expect(UDP).to know_header(MDNS).with(sport: 5353) expect(UDP).to know_header(MDNS).with(dport: 5353) end + it 'accepts to be added in UDP packets' do pkt = PacketGen.gen('UDP') - expect { pkt.add('MDNS') }.to_not raise_error + expect { pkt.add('MDNS') }.not_to raise_error expect(pkt.udp.dport).to eq(5353) end end - context 'sections' do + context 'with sections' do let(:dns) { MDNS.new } it 'may add a Question to question section' do q = DNS::Question.new(dns, name: 'www.example.org') - expect { dns.qd << q }.to change { dns.qdcount }.by(1) - expected_str = "\x00" * 5 + "\x01" + "\x00" * 6 + - generate_label_str(%w(www example org)) + + expect { dns.qd << q }.to change(dns, :qdcount).by(1) + expected_str = "\x00" * 5 << "\x01" << "\x00" * 6 << + generate_label_str(%w[www example org]) << "\x00\x01\x00\x01" - expect(dns.to_s).to eq(binary expected_str) + expect(dns.to_s).to eq(binary(expected_str)) end it 'may add a RR to answer section' do an = DNS::RR.new(dns, name: 'www.example.org', type: 'AAAA', ttl: 3600, - rdata: IPAddr.new('2000::1').hton) - expect { dns.an << an }.to change { dns.ancount }.by(1) + rdata: IPAddr.new('2000::1').hton) + expect { dns.an << an }.to change(dns, :ancount).by(1) expected_str = "\x00" * 7 + "\x01" + "\x00" * 4 + - generate_label_str(%w(www example org)) + + generate_label_str(%w[www example org]) + "\x00\x1c\x00\x01\x00\x00\x0e\x10\x00\x10\x20" + "\x00" * 14 + "\x01" - expect(dns.to_s).to eq(binary expected_str) + expect(dns.to_s).to eq(binary(expected_str)) end end describe '#read' do it 'reads a mDNS question header' do pkt = Packet.parse(mdns_raw_packets[0]) - expect(pkt.is? 'MDNS').to be(true) + expect(pkt.is?('MDNS')).to be(true) mdns = pkt.mdns expect(mdns.qr?).to be(false) @@ -62,7 +65,7 @@ module Header it 'reads a mDNS question header' do pkt = Packet.parse(mdns_raw_packets[1]) - expect(pkt.is? 'MDNS').to be(true) + expect(pkt.is?('MDNS')).to be(true) mdns = pkt.mdns expect(mdns.qr?).to be(true) @@ -91,6 +94,7 @@ module Header expect(pkt.ip.dst).to eq('224.0.0.251') end end + context '(IPv6)' do let(:pkt) { Packet.gen('Eth').add('IPv6').add('UDP').add('MDNS') } diff --git a/spec/header/mld_spec.rb b/spec/header/mld_spec.rb index 7fddbef..f0b231b 100644 --- a/spec/header/mld_spec.rb +++ b/spec/header/mld_spec.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen module Header - describe MLD do describe 'bindings' do it 'in ICMPv6 packets' do @@ -10,9 +11,10 @@ module Header expect(ICMPv6).to know_header(MLD).with(type: 131) expect(ICMPv6).to know_header(MLD).with(type: 132) end + it 'accepts to be added in ICMPv6 packets' do pkt = PacketGen.gen('ICMPv6') - expect { pkt.add('MLD') }.to_not raise_error + expect { pkt.add('MLD') }.not_to raise_error expect(pkt.icmpv6.type).to eq(130) end end @@ -36,7 +38,7 @@ module Header end describe '#read' do - let(:mld) { MLD.new} + let(:mld) { MLD.new } it 'sets header from a string' do str = (1..mld.sz).to_a.pack('C*') + 'body' @@ -47,17 +49,17 @@ module Header end it 'reads a MLD header in a real packet' do - pkt = PacketGen.gen('IPv6', src: 'fe80::1', dst: 'ff02::1', hop: 1). - add('IPv6::HopByHop'). - add('ICMPv6', type: 130, code: 0) + pkt = PacketGen.gen('IPv6', src: 'fe80::1', dst: 'ff02::1', hop: 1) + .add('IPv6::HopByHop') + .add('ICMPv6', type: 130, code: 0) pkt.ipv6_hopbyhop.options << { type: 'router_alert', value: BinStruct::Int16.new(value: 0).to_s } - pkt.body = "\x00\x7f\x00\x00" + + pkt.body = +"\x00\x7f\x00\x00" << ([0] * 16).pack('C*') pkt.calc parsed_pkt = PacketGen.parse(pkt.to_s) - expect(parsed_pkt.is? 'IPv6').to be(true) - expect(parsed_pkt.is? 'ICMPv6').to be(true) - expect(parsed_pkt.is? 'MLD').to be(true) + expect(parsed_pkt.is?('IPv6')).to be(true) + expect(parsed_pkt.is?('ICMPv6')).to be(true) + expect(parsed_pkt.is?('MLD')).to be(true) expect(parsed_pkt.mld.max_resp_delay).to eq(127) expect(parsed_pkt.mld.reserved).to eq(0) expect(parsed_pkt.mld.mcast_addr).to eq('::') @@ -68,7 +70,7 @@ module Header it 'returns a binary string' do mld = MLD.new(max_resp_delay: 20, mcast_addr: 'ff02::1') - expected = "\x00\x14\x00\x00" + expected = +"\x00\x14\x00\x00" expected << [0xff02, 0, 0, 0, 0, 0, 0, 1].pack('n*') expect(mld.to_s).to eq(expected) end @@ -79,7 +81,7 @@ module Header mld = MLD.new str = mld.inspect expect(str).to be_a(String) - (mld.attributes - %i(body)).each do |attr| + (mld.attributes - %i[body]).each do |attr| expect(str).to include(attr.to_s) end end @@ -94,16 +96,16 @@ module Header expect(pkt.ipv6.hop).to eq(1) expect(pkt.ipv6.next).to eq(0) expect(pkt.ipv6.length).to eq(32) - expect(pkt.is? 'IPv6::HopByHop').to be(true) + expect(pkt.is?('IPv6::HopByHop')).to be(true) expect(pkt.ipv6_hopbyhop.options.size).to eq(2) expect(pkt.ipv6_hopbyhop.options[0].human_type).to eq('router_alert') expect(pkt.ipv6_hopbyhop.options[0].value).to eq("\x00\x00") expect(pkt.ipv6_hopbyhop.options[1].to_human).to eq('pad2') expect(pkt.ipv6_hopbyhop.next).to eq(ICMPv6::IP_PROTOCOL) expect(pkt.icmpv6.checksum).to eq(0x7daa) - expected = "\x60\x00\x00\x00\x00\x20\x00\x01" - expected << "\x00" * 15 + "\x01" - expected << "\x00" * 15 + "\x02" + expected = +"\x60\x00\x00\x00\x00\x20\x00\x01" + expected << "\x00" * 15 << "\x01" + expected << "\x00" * 15 << "\x02" expected << "\x3a\x00\x05\x02\x00\x00\x01\x00" expected << "\x82\x00\x7d\xaa" expected << "\x00\x00\x00\x00" diff --git a/spec/header/mldv2_spec.rb b/spec/header/mldv2_spec.rb index 2065bbe..f859f83 100644 --- a/spec/header/mldv2_spec.rb +++ b/spec/header/mldv2_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen @@ -8,9 +10,10 @@ module MLDv2 it 'in ICMPv6 packets' do expect(ICMPv6).to know_header(MLQ).with(type: 130, body: '0' * 24) end + it 'accepts to be added in ICMPv6 packets' do pkt = PacketGen.gen('ICMPv6') - expect { pkt.add('MLDv2::MLQ') }.to_not raise_error + expect { pkt.add('MLDv2::MLQ') }.not_to raise_error expect(pkt.icmpv6.type).to eq(130) end end @@ -39,7 +42,7 @@ module MLDv2 end describe '#read' do - let(:mlq) { MLDv2::MLQ.new} + let(:mlq) { MLDv2::MLQ.new } it 'sets header from a string' do str = (1..mlq.sz).to_a.pack('C*') @@ -53,17 +56,17 @@ module MLDv2 end it 'reads a MLDv2 MLQ header from a real packet' do - pkt = PacketGen.gen('IPv6', src: 'fe80::1', dst: 'ff02::1', hop: 1). - add('IPv6::HopByHop'). - add('ICMPv6', type: 130, code: 0) + pkt = PacketGen.gen('IPv6', src: 'fe80::1', dst: 'ff02::1', hop: 1) + .add('IPv6::HopByHop') + .add('ICMPv6', type: 130, code: 0) pkt.ipv6_hopbyhop.options << { type: 'router_alert', value: BinStruct::Int16.new(value: 0).to_s } - pkt.body = "\x00\x7f\x00\x00" + ([0] * 16).pack('C*') + + pkt.body = +"\x00\x7f\x00\x00" << ([0] * 16).pack('C*') << [1, 0x2000, 0, 0, 0, 0, 0, 0, 1].pack('Nn*') pkt.calc parsed_pkt = PacketGen.parse(pkt.to_s) - expect(parsed_pkt.is? 'IPv6').to be(true) - expect(parsed_pkt.is? 'ICMPv6').to be(true) - expect(parsed_pkt.is? 'MLDv2::MLQ').to be(true) + expect(parsed_pkt.is?('IPv6')).to be(true) + expect(parsed_pkt.is?('ICMPv6')).to be(true) + expect(parsed_pkt.is?('MLDv2::MLQ')).to be(true) expect(parsed_pkt.mldv2_mlq.max_resp_delay).to eq(127) expect(parsed_pkt.mldv2_mlq.reserved).to eq(0) expect(parsed_pkt.mldv2_mlq.mcast_addr).to eq('::') @@ -77,7 +80,7 @@ module MLDv2 it 'reads a MLDv2 MLQ header from a pcap' do pkt = PacketGen.read(File.join(__dir__, 'mldv2.pcapng'))[1] - expect(pkt.is? 'MLDv2::MLQ').to be(true) + expect(pkt.is?('MLDv2::MLQ')).to be(true) mlq = pkt.mldv2_mlq expect(mlq.max_resp_code).to eq(0) expect(mlq.mcast_addr).to eq('ff02::1') @@ -96,11 +99,11 @@ module MLDv2 let(:mlq) { MLDv2::MLQ.new } it 'sets encoded Max Resp Code' do - [1, 1000, 32767].each do |value| + [1, 1000, 32_767].each do |value| mlq.max_resp_delay = value expect(mlq.max_resp_code).to eq(value) end - mlq.max_resp_delay = 32768 + mlq.max_resp_delay = 32_768 expect(mlq.max_resp_code).to eq(0x8000) mlq.max_resp_delay = 8_387_583 expect(mlq.max_resp_code).to eq(0xfffe) @@ -111,12 +114,12 @@ module MLDv2 end it 'gets decoded Max Resp Delay' do - [1, 1000, 32767].each do |value| + [1, 1000, 32_767].each do |value| mlq.max_resp_code = value expect(mlq.max_resp_delay).to eq(value) end mlq.max_resp_code = 0x8000 - expect(mlq.max_resp_delay).to eq(32768) + expect(mlq.max_resp_delay).to eq(32_768) mlq.max_resp_code = 0xfffe expect(mlq.max_resp_delay).to eq(8_386_560) mlq.max_resp_code = 0xffff @@ -127,9 +130,9 @@ module MLDv2 describe '#to_s' do it 'returns a binary string' do mlq = MLDv2::MLQ.new(max_resp_delay: 20, - mcast_addr: 'ff02::1') + mcast_addr: 'ff02::1') mlq.source_addr << '2000::1' - expected = "\x00\x14\x00\x00" + expected = +"\x00\x14\x00\x00" expected << [0xff02, 0, 0, 0, 0, 0, 0, 1].pack('n*') expected << [1, 0x2000, 0, 0, 0, 0, 0, 0, 1].pack('Nn*') expect(mlq.to_s).to eq(expected) @@ -141,7 +144,7 @@ module MLDv2 mlq = MLDv2::MLQ.new str = mlq.inspect expect(str).to be_a(String) - (mlq.attributes - %i(body)).each do |attr| + (mlq.attributes - %i[body]).each do |attr| expect(str).to include(attr.to_s) end end @@ -153,9 +156,10 @@ module MLDv2 it 'in ICMPv6 packets' do expect(ICMPv6).to know_header(MLR).with(type: 143) end + it 'accepts to be added in ICMPv6 packets' do pkt = PacketGen.gen('ICMPv6') - expect { pkt.add('MLDv2::MLR') }.to_not raise_error + expect { pkt.add('MLDv2::MLR') }.not_to raise_error expect(pkt.icmpv6.type).to eq(143) end end @@ -163,8 +167,8 @@ module MLDv2 describe '#read' do it 'parses a MLDv2::MLR packet' do pkt = PacketGen.read(File.join(__dir__, 'mldv2.pcapng'))[0] - expect(pkt.is? 'ICMPv6').to be(true) - expect(pkt.is? 'MLDv2::MLR').to be(true) + expect(pkt.is?('ICMPv6')).to be(true) + expect(pkt.is?('MLDv2::MLR')).to be(true) expect(pkt.mldv2_mlr.number_of_mar).to eq(1) expect(pkt.mldv2_mlr.records.size).to eq(1) mar = pkt.mldv2_mlr.records.first diff --git a/spec/header/ospfv2_spec.rb b/spec/header/ospfv2_spec.rb index ef7990f..06a7f97 100644 --- a/spec/header/ospfv2_spec.rb +++ b/spec/header/ospfv2_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' OSPFv2_PCAP = File.join(__dir__, 'ospfv2.pcapng') @@ -9,9 +11,10 @@ module Header it 'in IP packets with protocol 89' do expect(IP).to know_header(OSPFv2).with(protocol: 89) end + it 'accepts to be added in IP packets' do pkt = PacketGen.gen('IP') - expect { pkt.add('OSPFv2') }.to_not raise_error + expect { pkt.add('OSPFv2') }.not_to raise_error expect(pkt.ip.protocol).to eq(89) end end @@ -32,7 +35,7 @@ module Header end it 'accepts options' do - options = { + options = { version: 1, type: 'LS_ACK', length: 152, @@ -42,9 +45,9 @@ module Header au_type: 2, authentication: 0xff000000_00000011 } - ospf = OSPFv2.new(options) + ospf = OSPFv2.new(options) options.each do |opt, val| - opt = :human_type if opt == :type + opt = :human_type if opt == :type expect(ospf.send(opt)).to eq(val) end end @@ -54,7 +57,7 @@ module Header let(:ospf) { OSPFv2.new } it 'sets header from a string' do - str = (1..ospf.sz).to_a.pack('C*') + str = (1..ospf.sz).to_a.pack('C*') ospf.read(str) expect(ospf.version).to eq(1) expect(ospf.type).to eq(2) @@ -70,10 +73,10 @@ module Header raw_pkt = PcapNG::File.new.read_packet_bytes(OSPFv2_PCAP)[0] pkt = Packet.parse(raw_pkt) - expect(pkt.is? 'IP').to be(true) - expect(pkt.is? 'OSPFv2').to be(true) + expect(pkt.is?('IP')).to be(true) + expect(pkt.is?('OSPFv2')).to be(true) - ospf = pkt.ospfv2 + ospf = pkt.ospfv2 expect(ospf.version).to eq(2) expect(ospf.human_type).to eq('HELLO') expect(ospf.length).to eq(44) @@ -98,12 +101,12 @@ module Header describe '#to_s' do it 'returns a binary string' do - ospf = OSPFv2.new(router_id: 0xc0a8aa08, area_id: 1) + ospf = OSPFv2.new(router_id: 0xc0a8aa08, area_id: 1) ospf.calc_length ospf.calc_checksum - expected = binary("\x02\x01\x00\x18\xc0\xa8\xaa\x08" + - "\x00\x00\x00\x01\x93\x34\x00\x00") + expected = binary("\x02\x01\x00\x18\xc0\xa8\xaa\x08" \ + "\x00\x00\x00\x01\x93\x34\x00\x00") expected << [0].pack('Q') expect(ospf.to_s).to eq(expected) end @@ -114,7 +117,7 @@ module Header ospf = OSPFv2.new str = ospf.inspect expect(str).to be_a(String) - (ospf.attributes - %i(body)).each do |attr| + (ospf.attributes - %i[body]).each do |attr| expect(str).to include(attr.to_s) end end @@ -129,14 +132,14 @@ module Header end it 'sets TTL to 1 if destination address is a mcast one' do - pkt.ip.dst = '224.0.0.5' + pkt.ip.dst = '224.0.0.5' pkt.ospfize expect(pkt.ip.ttl).to eq(1) end it 'sets TTL to 1 when setting a mcast destination address' do pkt.ospfize - expect(pkt.ip.ttl).to_not eq(1) + expect(pkt.ip.ttl).not_to eq(1) pkt.ospfize(dst: '224.0.0.6') expect(pkt.ip.ttl).to eq(1) end @@ -165,8 +168,8 @@ module Header expect(hello.hello_interval).to eq(10) expect(hello.options).to eq(2) expect(hello.e_opt?).to be(true) - %w(mt mc n l dc o dn).each do |attr| - expect(hello.send("#{attr}_opt?")).to be(false) + %w[mt mc n l dc o dn].each do |attr| + expect(hello.send(:"#{attr}_opt?")).to be(false) end expect(hello.priority).to eq(1) expect(hello.dead_interval).to eq(40) @@ -211,7 +214,7 @@ module Header lsah = lsa.to_lsa_header expect(lsah).to be_a(OSPFv2::LSAHeader) lsa_hash = lsa.to_h - %i(netmask routers).each { |sym| lsa_hash.delete(sym) } + %i[netmask routers].each { |sym| lsa_hash.delete(sym) } expect(lsah.to_h).to eq(lsa_hash) end end @@ -271,25 +274,25 @@ module Header expect(lsr.lsrs.size).to eq(7) expected = [{ type: 'Router', link_state_id: '192.168.170.3', - advertising_router: '192.168.170.3'}, - { type: 'AS-External', - link_state_id: '80.212.16.0', - advertising_router: '192.168.170.2'}, - { type: 'AS-External', - link_state_id: '148.121.171.0', - advertising_router: '192.168.170.2'}, - { type: 'AS-External', - link_state_id: '192.130.120.0', - advertising_router: '192.168.170.2'}, - { type: 'AS-External', - link_state_id: '192.168.0.0', - advertising_router: '192.168.170.2'}, - { type: 'AS-External', - link_state_id: '192.168.1.0', - advertising_router: '192.168.170.2'}, - { type: 'AS-External', - link_state_id: '192.168.172.0', - advertising_router: '192.168.170.2'}] + advertising_router: '192.168.170.3' }, + { type: 'AS-External', + link_state_id: '80.212.16.0', + advertising_router: '192.168.170.2' }, + { type: 'AS-External', + link_state_id: '148.121.171.0', + advertising_router: '192.168.170.2' }, + { type: 'AS-External', + link_state_id: '192.130.120.0', + advertising_router: '192.168.170.2' }, + { type: 'AS-External', + link_state_id: '192.168.0.0', + advertising_router: '192.168.170.2' }, + { type: 'AS-External', + link_state_id: '192.168.1.0', + advertising_router: '192.168.170.2' }, + { type: 'AS-External', + link_state_id: '192.168.172.0', + advertising_router: '192.168.170.2' }] expect(lsr.lsrs.map(&:to_h)).to eq(expected) end end @@ -361,6 +364,7 @@ module Header describe '#calc_checksum' do let(:lsupdate) { packets[4].ospfv2_lsupdate } + it 'computes checksum on all LSAs' do checksums = lsupdate.lsas.map(&:checksum) lsupdate.lsas.each { |lsa| lsa.checksum = 0 } @@ -373,6 +377,7 @@ module Header describe '#calc_length' do let(:lsupdate) { packets[4].ospfv2_lsupdate } + it 'computes length on all LSAs' do lengths = lsupdate.lsas.map(&:length) lsupdate.lsas.each { |lsa| lsa.length = 0 } @@ -393,10 +398,10 @@ module Header lsack = ospf.body expect(lsack.lsas.size).to eq(13) - lsack.lsas.each { |lsa| expect(lsa).to be_a(OSPFv2::LSAHeader) } + expect(lsack.lsas).to all(be_a(OSPFv2::LSAHeader)) types = lsack.lsas.map(&:human_type) - expect(types).to eq(%w(Router) + %w(AS-External) * 12) + expect(types).to eq(%w[Router] + %w[AS-External] * 12) end end end @@ -440,7 +445,7 @@ module Header end it '#push adds a basic LSA' do - %w(Summary-IP Summary-ABSR).each do |t| + %w[Summary-IP Summary-ABSR].each do |t| lsa_array << { type: t } expect(lsa_array.last).to be_a(OSPFv2::LSA) end diff --git a/spec/header/ospfv3_spec.rb b/spec/header/ospfv3_spec.rb index 51c56b7..240e61e 100644 --- a/spec/header/ospfv3_spec.rb +++ b/spec/header/ospfv3_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' OSPFv3_PCAP = File.join(__dir__, 'ospfv3.pcapng') @@ -9,16 +11,17 @@ module Header it 'in IP packets with protocol 89' do expect(IPv6).to know_header(OSPFv3).with(next: 89) end + it 'accepts to be added in IPv6 packets' do pkt = PacketGen.gen('IPv6') - expect { pkt.add('OSPFv3') }.to_not raise_error + expect { pkt.add('OSPFv3') }.not_to raise_error expect(pkt.ipv6.next).to eq(89) end end describe '#initialize' do it 'creates an OSPFv3 header with default values' do - ospf = OSPFv3.new + ospf = OSPFv3.new expect(ospf.version).to eq(3) expect(ospf.type).to eq(1) expect(ospf.human_type).to eq('HELLO') @@ -31,7 +34,7 @@ module Header end it 'accepts options' do - options = { + options = { version: 45, type: 'LS_ACK', length: 152, @@ -68,8 +71,8 @@ module Header raw_pkt = PcapNG::File.new.read_packet_bytes(OSPFv3_PCAP)[0] pkt = Packet.parse(raw_pkt) - expect(pkt.is? 'IPv6').to be(true) - expect(pkt.is? 'OSPFv3').to be(true) + expect(pkt.is?('IPv6')).to be(true) + expect(pkt.is?('OSPFv3')).to be(true) ospf = pkt.ospfv3 expect(ospf.version).to eq(3) @@ -99,8 +102,8 @@ module Header pkt.ospfv3.calc_length pkt.ospfv3.calc_checksum - expected = binary("\x03\x01\x00\x10\xc0\xa8\xaa\x08" + - "\x00\x00\x00\x01\x91\xd1\x00\x00") + expected = binary("\x03\x01\x00\x10\xc0\xa8\xaa\x08" \ + "\x00\x00\x00\x01\x91\xd1\x00\x00") expect(pkt.ospfv3.to_s).to eq(expected) end end @@ -110,7 +113,7 @@ module Header ospf = OSPFv3.new str = ospf.inspect expect(str).to be_a(String) - (ospf.attributes - %i(body)).each do |attr| + (ospf.attributes - %i[body]).each do |attr| expect(str).to include(attr.to_s) end end @@ -125,14 +128,14 @@ module Header end it 'sets Hop-limit to 1 if destination address is a mcast one' do - pkt.ipv6.dst = 'ff02::5' + pkt.ipv6.dst = 'ff02::5' pkt.ospfize expect(pkt.ipv6.hop).to eq(1) end it 'sets Hop-limit to 1 when setting a mcast destination address' do pkt.ospfize - expect(pkt.ipv6.hop).to_not eq(1) + expect(pkt.ipv6.hop).not_to eq(1) pkt.ospfize(dst: 'ff02::5') expect(pkt.ipv6.hop).to eq(1) end @@ -164,8 +167,8 @@ module Header expect(hello.r_opt?).to be(true) expect(hello.e_opt?).to be(true) expect(hello.v6_opt?).to be(true) - %w(x n dc).each do |attr| - expect(hello.send("#{attr}_opt?")).to be(false) + %w[x n dc].each do |attr| + expect(hello.send(:"#{attr}_opt?")).to be(false) end expect(hello.hello_interval).to eq(10) expect(hello.dead_interval).to eq(40) @@ -226,7 +229,7 @@ module Header lsah = lsa.to_lsa_header expect(lsah).to be_a(OSPFv3::LSAHeader) lsa_hash = lsa.to_h - %i(router_priority options interface_addr prefix_count prefixes).each do |attr| + %i[router_priority options interface_addr prefix_count prefixes].each do |attr| lsa_hash.delete(attr) end expect(lsah.to_h).to eq(lsa_hash) @@ -315,27 +318,27 @@ module Header expected = [{ type: 'Router', reserved: 0, link_state_id: '0.0.0.0', - advertising_router: '2.2.2.2'}, + advertising_router: '2.2.2.2' }, { type: 'Inter-Area-Prefix', reserved: 0, link_state_id: '0.0.0.3', - advertising_router: '2.2.2.2'}, + advertising_router: '2.2.2.2' }, { type: 'Inter-Area-Prefix', reserved: 0, link_state_id: '0.0.0.2', - advertising_router: '2.2.2.2'}, + advertising_router: '2.2.2.2' }, { type: 'Inter-Area-Prefix', reserved: 0, link_state_id: '0.0.0.1', - advertising_router: '2.2.2.2'}, + advertising_router: '2.2.2.2' }, { type: 'Inter-Area-Prefix', reserved: 0, link_state_id: '0.0.0.0', - advertising_router: '2.2.2.2'}, + advertising_router: '2.2.2.2' }, { type: 'Link', reserved: 0, link_state_id: '0.0.0.5', - advertising_router: '2.2.2.2'}] + advertising_router: '2.2.2.2' }] expect(lsr.lsrs.map(&:to_h)).to eq(expected) expect(lsr.lsrs[0].to_human).to eq('LSR') end @@ -343,7 +346,7 @@ module Header end describe OSPFv3::LSUpdate do - before(:each) do + before do @lsup = OSPFv3::LSUpdate.new @lsup.lsas << { type: 'Router', age: 36, link_state_id: '0.0.0.1', advertising_router: '1.1.1.1', sequence_number: 1 } @@ -356,8 +359,8 @@ module Header expect(@lsup.lsas_count).to eq(2) @lsup.calc_checksum - expect(@lsup.lsas[0].checksum).to_not eq(0) - expect(@lsup.lsas[1].checksum).to_not eq(0) + expect(@lsup.lsas[0].checksum).not_to eq(0) + expect(@lsup.lsas[1].checksum).not_to eq(0) end end @@ -460,10 +463,10 @@ module Header lsack = ospf.body expect(lsack.lsas.size).to eq(6) - lsack.lsas.each { |lsa| expect(lsa).to be_a(OSPFv3::LSAHeader) } + expect(lsack.lsas).to all(be_a(OSPFv3::LSAHeader)) types = lsack.lsas.map(&:human_type) - expect(types).to eq(%w(Router) + %w(Inter-Area-Prefix) * 4 + %w(Link)) + expect(types).to eq(%w[Router] + %w[Inter-Area-Prefix] * 4 + %w[Link]) end end end diff --git a/spec/header/sctp/abort_error_chunk_spec.rb b/spec/header/sctp/abort_error_chunk_spec.rb index 654a3d4..fec1190 100644 --- a/spec/header/sctp/abort_error_chunk_spec.rb +++ b/spec/header/sctp/abort_error_chunk_spec.rb @@ -1,30 +1,31 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' -COMMON_ERROR_CAUSES = (',,,' + - ',>,>,' + - '>,>>,' + - ',: "\x01\x02\x03">,<: "">>,' + - ',,,>,,').freeze +COMMON_ERROR_CAUSES = ',,,' \ + ',>,>,' \ + '>,>>,' \ + ',: "\x01\x02\x03">,<: "">>,' \ + ',,,>,,' HUMAN_ABORT_CHUNK = "" HUMAN_ERROR_CHUNK = "" -COMMON_BINARY_ERROR_CAUSES = binary("\x00\x01\x00\x08\x12\x34\x00\x00" + - "\x00\x02\x00\x0a\x00\x01\x00\x02\x00\x03\x00\x00" + - "\x00\x03\x00\x08\x00\x06\xf6\x1d" + - "\x00\x04\x00\x04" + - "\x00\x05\x00\x0c\x00\x05\x00\x08\x01\x02\x03\x04" + - "\x00\x05\x00\x18\x00\x06\x00\x14" + ([0] * 15 + [1]).pack('C*') + - "\x00\x05\x00\x14\x00\x0b\x00\x10example.org\x00" + - "\x00\x06\x00\x10\x42\x00\x00\x0c\x00\x00\x00\x00\xff\xff\xff\xff" + - "\x00\x07\x00\x04" + - "\x00\x08\x00\x10\x00\x42\x00\x07\x01\x02\x03\x00\x00\x43\x00\x04" + - "\x00\x09\x00\x08\x11\x22\x33\x44" + - "\x00\x0a\x00\x04" + - "\x00\x0b\x00\x20\x00\x05\x00\x08\x01\x01\x01\x0f\x00\x06\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02" + - "\x00\x0c\x00\x07abc\x00" + - "\x00\x0d\x00\x06ef\x00\x00" - ).freeze +COMMON_BINARY_ERROR_CAUSES = binary("\x00\x01\x00\x08\x12\x34\x00\x00" \ + "\x00\x02\x00\x0a\x00\x01\x00\x02\x00\x03\x00\x00" \ + "\x00\x03\x00\x08\x00\x06\xf6\x1d" \ + "\x00\x04\x00\x04" \ + "\x00\x05\x00\x0c\x00\x05\x00\x08\x01\x02\x03\x04" \ + "\x00\x05\x00\x18\x00\x06\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" \ + "\x00\x05\x00\x14\x00\x0b\x00\x10example.org\x00" \ + "\x00\x06\x00\x10\x42\x00\x00\x0c\x00\x00\x00\x00\xff\xff\xff\xff" \ + "\x00\x07\x00\x04" \ + "\x00\x08\x00\x10\x00\x42\x00\x07\x01\x02\x03\x00\x00\x43\x00\x04" \ + "\x00\x09\x00\x08\x11\x22\x33\x44" \ + "\x00\x0a\x00\x04" \ + "\x00\x0b\x00\x20\x00\x05\x00\x08\x01\x01\x01\x0f\x00\x06\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02" \ + "\x00\x0c\x00\x07abc\x00" \ + "\x00\x0d\x00\x06ef\x00\x00").freeze BINARY_ABORT_CHUNK = binary("\x06\x01\x00\xbc") + COMMON_BINARY_ERROR_CAUSES BINARY_ERROR_CHUNK = binary("\x09\x00\x00\xbc") + COMMON_BINARY_ERROR_CAUSES @@ -48,8 +49,8 @@ def add_error_causes(obj) bad_addr1 = MySCTP::IPv4Parameter.new(value: '1.1.1.15') bad_addr2 = MySCTP::IPv6Parameter.new(value: '::2') obj.error_causes << { type: 'RestartAssociationWithNewAddress', value: [bad_addr1, bad_addr2] } - obj.error_causes << { type: 'UserInitiatedAbort', value: "abc" } - obj.error_causes << { type: 'ProtocolViolation', value: "ef" } + obj.error_causes << { type: 'UserInitiatedAbort', value: 'abc' } + obj.error_causes << { type: 'ProtocolViolation', value: 'ef' } end module PacketGen @@ -69,10 +70,10 @@ class SCTP it 'accepts options' do options = { - type: 0xffff, - flags: 0x1234, - length: 42, - } + type: 0xffff, + flags: 0x1234, + length: 42, + } obj = klass.new(options) options.each do |key, value| expect(obj.send(key)).to eq(value) @@ -85,7 +86,7 @@ class SCTP describe AbortChunk do describe '#to_human' do it 'returns a String with type' do - expect(AbortChunk.new.to_human).to eq("") + expect(AbortChunk.new.to_human).to eq('') end it 'returns human readable parameters' do @@ -112,11 +113,11 @@ class SCTP describe ErrorChunk do describe '#to_human' do it 'returns a String with type' do - expect(ErrorChunk.new.to_human).to eq("") + expect(ErrorChunk.new.to_human).to eq('') end it 'returns human readable parameters' do - obj = ErrorChunk.new() + obj = ErrorChunk.new add_error_causes(obj) output = obj.to_human diff --git a/spec/header/sctp/cookie_chunk_spec.rb b/spec/header/sctp/cookie_chunk_spec.rb index 1c69fb7..15988a9 100644 --- a/spec/header/sctp/cookie_chunk_spec.rb +++ b/spec/header/sctp/cookie_chunk_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' module PacketGen @@ -16,11 +18,11 @@ class SCTP it 'accepts options' do options = { - type: 0xffff, - flags: 0x1234, - length: 42, - cookie: 'qwerty', - } + type: 0xffff, + flags: 0x1234, + length: 42, + cookie: 'qwerty', + } cookie = CookieEchoChunk.new(options) options.each do |key, value| expect(cookie.send(key)).to eq(value) @@ -56,10 +58,10 @@ class SCTP it 'accepts options' do options = { - type: 0xffff, - flags: 0x1234, - length: 42, - } + type: 0xffff, + flags: 0x1234, + length: 42, + } cookie = CookieAckChunk.new(options) options.each do |key, value| expect(cookie.send(key)).to eq(value) diff --git a/spec/header/sctp/data_chunk_spec.rb b/spec/header/sctp/data_chunk_spec.rb index 6631a49..c43d7ef 100644 --- a/spec/header/sctp/data_chunk_spec.rb +++ b/spec/header/sctp/data_chunk_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' module PacketGen @@ -20,14 +22,14 @@ class SCTP it 'accepts options' do options = { - type: 0x1234, - flags: 0x5678, - length: 42, - tsn: 0x01020304, - stream_id: 0xabcd, - stream_sn: 0xef01, - ppid: 0xf0e0d0c0, - } + type: 0x1234, + flags: 0x5678, + length: 42, + tsn: 0x01020304, + stream_id: 0xabcd, + stream_sn: 0xef01, + ppid: 0xf0e0d0c0, + } data = DataChunk.new(options) options.each do |key, value| expect(data.send(key)).to eq(value) diff --git a/spec/header/sctp/heartbeat_chunk_spec.rb b/spec/header/sctp/heartbeat_chunk_spec.rb index eaac560..d4f1cef 100644 --- a/spec/header/sctp/heartbeat_chunk_spec.rb +++ b/spec/header/sctp/heartbeat_chunk_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' module PacketGen @@ -16,11 +18,11 @@ class SCTP it 'accepts options' do options = { - type: 0x1234, - flags: 0xaa, - length: 42, - info: HearbeatInfoParameter.new(value: 'abcd') - } + type: 0x1234, + flags: 0xaa, + length: 42, + info: HearbeatInfoParameter.new(value: 'abcd') + } data = HeartbeatChunk.new(options) options.each do |key, value| expect(data.send(key)).to eq(value) diff --git a/spec/header/sctp/init_chunk_spec.rb b/spec/header/sctp/init_chunk_spec.rb index 3f2e866..e9f153a 100644 --- a/spec/header/sctp/init_chunk_spec.rb +++ b/spec/header/sctp/init_chunk_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' INIT_CHUNK_WITH_PARAMS = ',,,: "abc">,,,,>' @@ -23,15 +25,15 @@ class SCTP it 'accepts options' do options = { - type: 0xffff, - flags: 0x1234, - length: 42, - initiate_tag: 0x01020304, - a_rwnd: 0x05060708, - nos: 0x8000, - nis: 0xf00E, - initial_tsn: 0x090a0b0c, - } + type: 0xffff, + flags: 0x1234, + length: 42, + initiate_tag: 0x01020304, + a_rwnd: 0x05060708, + nos: 0x8000, + nis: 0xf00E, + initial_tsn: 0x090a0b0c, + } init = InitChunk.new(options) options.each do |key, value| expect(init.send(key)).to eq(value) @@ -48,10 +50,10 @@ class SCTP init = InitChunk.new init.parameters << { type: 'IPv4', value: '92.168.52.17' } init.parameters << { type: 'IPv6', value: '2c00:5d3::42' } - init.parameters << { type: 'StateCookie', value: "cookie" } + init.parameters << { type: 'StateCookie', value: 'cookie' } init.parameters << { type: 'Unrecognized', value: Parameter.new(type: 42, value: 'abc') } init.parameters << { type: 'Hostname', value: 'www.example.com' } - init.parameters << { type: 'SupportedAddrTypes', value: [5, 6]} + init.parameters << { type: 'SupportedAddrTypes', value: [5, 6] } init.parameters << { type: 'CookiePreservative', value: 1_545 } init.parameters << { type: 'ECN' } @@ -64,6 +66,7 @@ class SCTP let(:init) { InitChunk.new } let(:param1) { Parameter.new(type: 42, value: 'AAAA') } let(:param2) { IPv4Parameter.new(type: 'IPv4', value: '10.0.0.1') } + it 'accepts Parameter using <<' do init.parameters << param1 init.parameters << param2 @@ -73,9 +76,9 @@ class SCTP end it 'accepts Hash describing a Parameter using <<' do - init.parameters << { type: 42, value: 'AAAA'} - init.parameters << { type: 5, value: '10.0.0.1'} - init.parameters << { type: 'IPv4', value: '10.0.0.1'} + init.parameters << { type: 42, value: 'AAAA' } + init.parameters << { type: 5, value: '10.0.0.1' } + init.parameters << { type: 'IPv4', value: '10.0.0.1' } expect(init.parameters.size).to eq(3) expect(init.parameters[0]).to be_a(Parameter) expect(init.parameters[0].to_s).to eq(param1.to_s) diff --git a/spec/header/sctp/sack_chunk_spec.rb b/spec/header/sctp/sack_chunk_spec.rb index c4351f1..ea3ed3c 100644 --- a/spec/header/sctp/sack_chunk_spec.rb +++ b/spec/header/sctp/sack_chunk_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' module PacketGen @@ -21,16 +23,16 @@ class SCTP it 'accepts options' do options = { - type: 0x1234, - flags: 0x5678, - length: 42, - ctsn_ack: 0x01020304, - a_rwnd: 0x05060708, - num_gap: 2, - num_dup_tsn: 1, - gaps: [0x000010002, 0x00100020], - dup_tsns: [0x12345678] - } + type: 0x1234, + flags: 0x5678, + length: 42, + ctsn_ack: 0x01020304, + a_rwnd: 0x05060708, + num_gap: 2, + num_dup_tsn: 1, + gaps: [0x000010002, 0x00100020], + dup_tsns: [0x12345678] + } data = SackChunk.new(options) options.each do |key, value| val = data.send(key) diff --git a/spec/header/sctp/shutdown_chunk_spec.rb b/spec/header/sctp/shutdown_chunk_spec.rb index 5d0a36e..8e2be69 100644 --- a/spec/header/sctp/shutdown_chunk_spec.rb +++ b/spec/header/sctp/shutdown_chunk_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' module PacketGen @@ -16,11 +18,11 @@ class SCTP it 'accepts options' do options = { - type: 0xffff, - flags: 0x1234, - length: 42, - ctsn_ack: 0x01020304, - } + type: 0xffff, + flags: 0x1234, + length: 42, + ctsn_ack: 0x01020304, + } shutdown = ShutdownChunk.new(options) options.each do |key, value| expect(shutdown.send(key)).to eq(value) @@ -55,10 +57,10 @@ class SCTP it 'accepts options' do options = { - type: 0xffff, - flags: 0x1234, - length: 42, - } + type: 0xffff, + flags: 0x1234, + length: 42, + } shutdown = ShutdownAckChunk.new(options) options.each do |key, value| expect(shutdown.send(key)).to eq(value) @@ -93,10 +95,10 @@ class SCTP it 'accepts options' do options = { - type: 0xffff, - flags: 0x1234, - length: 42, - } + type: 0xffff, + flags: 0x1234, + length: 42, + } shutdown = ShutdownCompleteChunk.new(options) options.each do |key, value| expect(shutdown.send(key)).to eq(value) diff --git a/spec/header/sctp_spec.rb b/spec/header/sctp_spec.rb index 22b0db4..31e3704 100644 --- a/spec/header/sctp_spec.rb +++ b/spec/header/sctp_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen @@ -8,14 +10,16 @@ module Header expect(IP).to know_header(SCTP).with(protocol: 132) expect(IPv6).to know_header(SCTP).with(next: 132) end + it 'accepts to be added in IP packets' do pkt = PacketGen.gen('IP') - expect { pkt.add('SCTP') }.to_not raise_error + expect { pkt.add('SCTP') }.not_to raise_error expect(pkt.ip.protocol).to eq(132) end + it 'accepts to be added in IPv6 packets' do pkt = PacketGen.gen('IPv6') - expect { pkt.add('SCTP') }.to_not raise_error + expect { pkt.add('SCTP') }.not_to raise_error expect(pkt.ipv6.next).to eq(132) end end @@ -180,8 +184,8 @@ module Header chunk0 = sctp.chunks[0] chunk1 = sctp.chunks[1] - chunk0.body << "1234" - chunk1.body << "12345678" + chunk0.body << '1234' + chunk1.body << '12345678' sctp.calc_length expect(chunk0.length).to eq(8) expect(chunk1.length).to eq(12) diff --git a/spec/header/snmp_spec.rb b/spec/header/snmp_spec.rb index 8907f94..cbb9a01 100644 --- a/spec/header/snmp_spec.rb +++ b/spec/header/snmp_spec.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen module Header - describe SNMP do let(:ber) { read_raw_packets('snmp.pcapng') } @@ -13,9 +14,10 @@ module Header expect(UDP).to know_header(SNMP).with(sport: 162) expect(UDP).to know_header(SNMP).with(dport: 162) end + it 'accepts to be added in UDP packets' do pkt = PacketGen.gen('UDP') - expect { pkt.add('SNMP') }.to_not raise_error + expect { pkt.add('SNMP') }.not_to raise_error expect(pkt.udp.dport).to eq(161) end end @@ -36,7 +38,7 @@ module Header snmp = SNMP.new(options) expect(snmp.version).to eq('v3') expect(snmp.community).to eq('community') - expect(snmp.pdu).to be(nil) + expect(snmp.pdu).to be_nil end it 'accepts a PDU' do @@ -50,7 +52,7 @@ module Header expect(pdu[:varbindlist][0]).to be_a(SNMP::VarBind) expect(pdu[:varbindlist][0][:name].value).to eq('1.2.3.4') expect(pdu[:varbindlist][0][:value]).to be_a(RASN1::Types::Any) - expect(pdu[:varbindlist][0][:value].value).to be(nil) + expect(pdu[:varbindlist][0][:value].value).to be_nil end end @@ -58,14 +60,14 @@ module Header let(:snmp) { SNMP.new } it 'reads a getRequest from a string' do - snmp.read ber[0][42..-1] + snmp.read ber[0][42..] expect(snmp.version).to eq('v1') expect(snmp.community).to eq('public') expect(snmp.data.root.chosen).to eq(SNMP::PDU_GET) end it 'reads a getResponse from a string' do - snmp.read ber[1][42..-1] + snmp.read ber[1][42..] expect(snmp.version).to eq('v1') expect(snmp.community).to eq('public') expect(snmp.data.root.chosen).to eq(SNMP::PDU_RESPONSE) @@ -103,7 +105,7 @@ module Header value: RASN1::Types::Null.new } varlist << { name: '1.3.6.1.2.1.1.6.0', value: RASN1::Types::Null.new } - expect(snmp.to_s).to eq(ber[0][42..-1]) + expect(snmp.to_s).to eq(ber[0][42..]) end end @@ -114,7 +116,7 @@ module Header %w[version community data].each do |attr| expect(str).to include(attr) end - expect(str).to_not include('ASN.1 content') + expect(str).not_to include('ASN.1 content') end it 'returns a String with PDU data' do diff --git a/spec/header/tcp_option_spec.rb b/spec/header/tcp_option_spec.rb index 3e6e223..4cb403f 100644 --- a/spec/header/tcp_option_spec.rb +++ b/spec/header/tcp_option_spec.rb @@ -1,15 +1,16 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen module Header class TCP describe Option do - describe '#initialize' do it 'creates a TCP option' do opt = Option.new expect(opt.kind).to eq(0) - expect(opt[:length].value).to be(nil) + expect(opt[:length].value).to be_nil expect(opt[:value]).to be_a(BinStruct::String) end @@ -49,7 +50,7 @@ class TCP opt = Option.new.read("\xfd\x06\x00\x00\x00\x01") expect(opt.kind).to eq(253) expect(opt.length).to eq(6) - expect(opt.value).to eq(binary "\x00\x00\x00\x01") + expect(opt.value).to eq(binary("\x00\x00\x00\x01")) end it 'reads a long Option' do @@ -63,21 +64,21 @@ class TCP describe '#to_s' do it 'generates a string for Option with only a kind' do opt = Option.new(kind: 1) - expect(opt.to_s).to eq(binary "\x01") + expect(opt.to_s).to eq(binary("\x01")) end it 'generates a string for complete Option' do opt = Option.new(kind: 253, length: 4, value: 1) expected = "\xfd\x04\x00\x01" - expect(opt.to_s).to eq(binary expected) + expect(opt.to_s).to eq(binary(expected)) opt = Option.new(kind: 253, length: 6, value: 1) expected = "\xfd\x06\x00\x00\x00\x01" - expect(opt.to_s).to eq(binary expected) + expect(opt.to_s).to eq(binary(expected)) opt = Option.new(kind: 32, value: 'abcdefg') expected = "\x20\x09abcdefg" - expect(opt.to_s).to eq(binary expected) + expect(opt.to_s).to eq(binary(expected)) end end end @@ -98,7 +99,7 @@ class TCP end it 'is a single byte option' do - expect(NOP.new.to_s).to eq(binary "\x01") + expect(NOP.new.to_s).to eq(binary("\x01")) end end @@ -109,9 +110,9 @@ class TCP it 'is a 4-byte option' do mss = MSS.new - expect(mss.to_s).to eq(binary "\x02\x04\x00\x00") + expect(mss.to_s).to eq(binary("\x02\x04\x00\x00")) mss.value = 0x123 - expect(mss.to_s).to eq(binary "\x02\x04\x01\x23") + expect(mss.to_s).to eq(binary("\x02\x04\x01\x23")) end end @@ -122,9 +123,9 @@ class TCP it 'is a 3-byte option' do ws = WS.new - expect(ws.to_s).to eq(binary "\x03\x03\x00") + expect(ws.to_s).to eq(binary("\x03\x03\x00")) ws.value = 0x12 - expect(ws.to_s).to eq(binary "\x03\x03\x12") + expect(ws.to_s).to eq(binary("\x03\x03\x12")) end end @@ -134,7 +135,7 @@ class TCP end it 'is a 2-byte option' do - expect(SACKOK.new.to_s).to eq(binary "\x04\x02") + expect(SACKOK.new.to_s).to eq(binary("\x04\x02")) end end @@ -145,11 +146,11 @@ class TCP it 'is a multi-byte option' do sack = SACK.new - expect(sack.to_s).to eq(binary "\x05\x02") + expect(sack.to_s).to eq(binary("\x05\x02")) 1.upto(12) do |i| sack.value = 'z' * i expected = [5, 2 + i].pack('C*') + 'z' * i - expect(sack.to_s).to eq(binary expected) + expect(sack.to_s).to eq(binary(expected)) end end end @@ -161,9 +162,9 @@ class TCP it 'is a 6-byte option' do echo = ECHO.new - expect(echo.to_s).to eq(binary "\x06\x06\x00\x00\x00\x00") + expect(echo.to_s).to eq(binary("\x06\x06\x00\x00\x00\x00")) echo.value = 0xff010203 - expect(echo.to_s).to eq(binary "\x06\x06\xff\x01\x02\x03") + expect(echo.to_s).to eq(binary("\x06\x06\xff\x01\x02\x03")) end end @@ -174,9 +175,9 @@ class TCP it 'is a 6-byte option' do echor = ECHOREPLY.new - expect(echor.to_s).to eq(binary "\x07\x06\x00\x00\x00\x00") + expect(echor.to_s).to eq(binary("\x07\x06\x00\x00\x00\x00")) echor.value = 0xff010203 - expect(echor.to_s).to eq(binary "\x07\x06\xff\x01\x02\x03") + expect(echor.to_s).to eq(binary("\x07\x06\xff\x01\x02\x03")) end end @@ -187,9 +188,9 @@ class TCP it 'is a 10-byte option' do ts = TS.new - expect(ts.to_s).to eq(binary("\x08\x0a" + "\x00" * 8)) - ts.value = "\x7f" + "\x01" * 7 - expect(ts.to_s).to eq(binary("\x08\x0a\x7f" + "\x01" * 7)) + expect(ts.to_s).to eq(binary(+"\x08\x0a" << "\x00" * 8)) + ts.value = +"\x7f" << "\x01" * 7 + expect(ts.to_s).to eq(binary(+"\x08\x0a\x7f" << "\x01" * 7)) end end end diff --git a/spec/header/tcp_options_spec.rb b/spec/header/tcp_options_spec.rb index 51caa96..df26509 100644 --- a/spec/header/tcp_options_spec.rb +++ b/spec/header/tcp_options_spec.rb @@ -1,23 +1,23 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen module Header class TCP - SINGLES = [[EOL, "\x00"], [NOP, "\x01"], [MSS, "\x02\x04\x12\x23"], [WS, "\x03\x03\xff"], [SACKOK, "\x04\x02"], [SACK, "\x05\x05\x01\x02\x03"], - [SACK, "\x05\x12"+(16..31).to_a.pack('C*')], + [SACK, "\x05\x12#{(16..31).to_a.pack('C*')}"], [ECHO, "\x06\x06\x04\x03\x02\x01"], [ECHOREPLY, "\x07\x06\x04\x03\x02\x01"], - [TS, "\x08\x0a" + "\x00" * 8] - ] + [TS, "\x08\x0a#{"\x00" * 8}"]].freeze describe Options do before(:all) do file = File.join(__dir__, '..', 'pcapng', 'ipv6_tcp.pcapng') @packets = PcapNG::File.new.read_packet_bytes(file) - end + end let(:opts) { Options.new } @@ -37,8 +37,8 @@ class TCP when SACK sack = opts.first case sack.length - when 5; expect(sack.value).to eq("\x01\x02\x03") - when 18; expect(sack.value).to eq((16..31).to_a.pack('C*')) + when 5 then expect(sack.value).to eq("\x01\x02\x03") + when 18 then expect(sack.value).to eq((16..31).to_a.pack('C*')) end when ECHO, ECHOREPLY expect(opts.first.value).to eq(0x04030201) @@ -49,7 +49,7 @@ class TCP end it 'reads multiple options from a string' do - str = @packets.first[0x4a..-1] + str = @packets.first[0x4a..] opts.read str expect(opts.size).to eq(5) expect(opts[0]).to be_a(MSS) @@ -61,15 +61,15 @@ class TCP expect(opts[4]).to be_a(WS) expect(opts[4].value).to eq(7) - str = @packets[2][0x4a..-1] + str = @packets[2][0x4a..] opts.read str expect(opts.size).to eq(3) - expect(opts.map { |o| o.class }).to eq([NOP, NOP, TS]) + expect(opts.map(&:class)).to eq([NOP, NOP, TS]) end it 'decodes unrecognized options' do str = "\x13\x14111111111111111111\x13\x14222222222222222222" - expect { opts.read(str) }.to_not raise_error + expect { opts.read(str) }.not_to raise_error expect(opts.size).to eq(2) expect(opts.first.kind).to eq(0x13) expect(opts.first.value).to eq('1' * 18) @@ -98,7 +98,7 @@ class TCP end it 'may be serialized with another #add' do - options << { opt: 'SACK' } << {opt: 'MSS', value: 500} + options << { opt: 'SACK' } << { opt: 'MSS', value: 500 } options << { opt: 'NOP' } << { opt: 'NOP' } expect(options.size).to eq(4) expect(options.sz).to eq(8) @@ -109,8 +109,8 @@ class TCP end it 'raises on unknown option' do - expect { options.push opt: 'UNKNOWN' }. - to raise_error(ArgumentError, /^opt should be/) + expect { options.push opt: 'UNKNOWN' } + .to raise_error(ArgumentError, /^opt should be/) end end @@ -145,17 +145,17 @@ class TCP end it 'raises on unknown option' do - expect { options << { opt: 'UNKNOWN' } }. - to raise_error(ArgumentError, /^opt should be/) - expect { options << { opt: 'Options' } }. - to raise_error(ArgumentError, /^opt should be/) + expect { options << { opt: 'UNKNOWN' } } + .to raise_error(ArgumentError, /^opt should be/) + expect { options << { opt: 'Options' } } + .to raise_error(ArgumentError, /^opt should be/) end end describe '#to_s' do it 'returns encoded options' do @packets.each do |pkt| - str_opts = pkt[0x4a..-1] + str_opts = pkt[0x4a..] opts.read str_opts expect(opts.to_s).to eq(str_opts) end @@ -168,7 +168,7 @@ class TCP 'MSS:1410,SACKOK,TS:2583455884;36978029,NOP,WS:7', 'NOP,NOP,TS:36978033;2583455884'] @packets.each_with_index do |pkt, i| - str_opts = pkt[0x4a..-1] + str_opts = pkt[0x4a..] opts.read str_opts expect(opts.to_human).to eq(expected[i]) end diff --git a/spec/header/tcp_spec.rb b/spec/header/tcp_spec.rb index 0171032..e6b9c0a 100644 --- a/spec/header/tcp_spec.rb +++ b/spec/header/tcp_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen @@ -8,14 +10,16 @@ module Header expect(IP).to know_header(TCP).with(protocol: 6) expect(IPv6).to know_header(TCP).with(next: 6) end + it 'accepts to be added in IP packets' do pkt = PacketGen.gen('IP') - expect { pkt.add('TCP') }.to_not raise_error + expect { pkt.add('TCP') }.not_to raise_error expect(pkt.ip.protocol).to eq(6) end + it 'accepts to be added in IPv6 packets' do pkt = PacketGen.gen('IPv6') - expect { pkt.add('TCP') }.to_not raise_error + expect { pkt.add('TCP') }.not_to raise_error expect(pkt.ipv6.next).to eq(6) end end @@ -26,7 +30,7 @@ module Header expect(tcp).to be_a(TCP) expect(tcp.sport).to eq(0) expect(tcp.dport).to eq(0) - expect(tcp.seqnum).to_not eq(0) + expect(tcp.seqnum).not_to eq(0) expect(tcp.acknum).to eq(0) expect(tcp.hlen).to eq(5) expect(tcp.reserved).to eq(0) @@ -61,12 +65,12 @@ module Header end describe '#read' do - let(:tcp) { TCP.new} + let(:tcp) { TCP.new } it 'sets header from a string' do ary = (0...tcp.sz).to_a ary[12] |= 0x50 - str = ary.pack('C*') + 'body' + str = ary.pack('C*') << 'body' tcp.read str expect(tcp.sport).to eq(0x0001) expect(tcp.dport).to eq(0x0203) @@ -89,7 +93,7 @@ module Header packets.each do |pkt| checksum = pkt.tcp.checksum pkt.tcp.checksum = 0 - expect(pkt.tcp.checksum).to_not eq(checksum) + expect(pkt.tcp.checksum).not_to eq(checksum) pkt.tcp.calc_checksum expect(pkt.tcp.checksum).to eq(checksum) end @@ -97,10 +101,10 @@ module Header it 'computes TCP over IPv6 header checksum' do pkt = Packet.read(File.join(__dir__, '..', 'pcapng', 'ipv6_tcp.pcapng'))[1] - expect(pkt.is? 'IPv6').to be(true) + expect(pkt.is?('IPv6')).to be(true) checksum = pkt.tcp.checksum pkt.tcp.checksum = 0 - expect(pkt.tcp.checksum).to_not eq(checksum) + expect(pkt.tcp.checksum).not_to eq(checksum) pkt.tcp.calc_checksum expect(pkt.tcp.checksum).to eq(checksum) end @@ -130,20 +134,19 @@ module Header end it '#window= accepts integers' do - tcp.window = 60000 - expect(tcp[:window].value).to eq(60000) + tcp.window = 60_000 + expect(tcp[:window].value).to eq(60_000) end it '#checksum= accepts integers' do - tcp.checksum = 65500 - expect(tcp[:checksum].value).to eq(65500) + tcp.checksum = 65_500 + expect(tcp[:checksum].value).to eq(65_500) end it '#urg_pointer= accepts integers' do - tcp.urg_pointer = 37560 - expect(tcp[:urg_pointer].value).to eq(37560) + tcp.urg_pointer = 37_560 + expect(tcp[:urg_pointer].value).to eq(37_560) end - end describe '#to_s' do @@ -167,28 +170,28 @@ module Header tcp = TCP.new str = tcp.inspect expect(str).to be_a(String) - (tcp.attributes - %i(body) + %i(data_offset reserved flags)).each do |attr| + (tcp.attributes - %i[body] + %i[data_offset reserved flags]).each do |attr| expect(str).to include(attr.to_s) end end end - context 'flags field' do + context 'with flags field' do let(:tcp) { TCP.new } it 'may be accessed through all flag_* methods' do - all_flags = (%i(flag_ns flag_cwr flag_ece flag_urg flag_ack flag_psh) + - %i(flag_rst flag_syn flag_fin)).reverse + all_flags = (%i[flag_ns flag_cwr flag_ece flag_urg flag_ack flag_psh] + + %i[flag_rst flag_syn flag_fin]).reverse 8.downto(0) do |i| - expect(tcp.send "#{all_flags[i]}?").to eq(false) + expect(tcp.send(:"#{all_flags[i]}?")).to be(false) tcp.flags = 1 << i - expect(tcp.send "#{all_flags[i]}?").to eq(true) - tcp.send "#{all_flags[i]}=", false + expect(tcp.send(:"#{all_flags[i]}?")).to be(true) + tcp.send :"#{all_flags[i]}=", false expect(tcp.flags).to eq(0) end tcp.flags = 0x155 - 9.times { |i| expect(tcp.send "#{all_flags[i]}?").to be(i % 2 == 0) } + 9.times { |i| expect(tcp.send(:"#{all_flags[i]}?")).to be(i.even?) } end end end diff --git a/spec/header/tftp_spec.rb b/spec/header/tftp_spec.rb index 475abb6..a3be3da 100644 --- a/spec/header/tftp_spec.rb +++ b/spec/header/tftp_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen @@ -7,9 +9,10 @@ module Header it 'in UDP packets' do expect(UDP).to know_header(TFTP).with(dport: 69) end + it 'accepts to be added in UDP packets' do pkt = PacketGen.gen('UDP') - expect { pkt.add('TFTP') }.to_not raise_error + expect { pkt.add('TFTP') }.not_to raise_error expect(pkt.udp.dport).to eq(69) end end @@ -32,47 +35,47 @@ module Header mytftp = tftp.read(raw) expect(mytftp.opcode).to eq(8) expect(mytftp.human_opcode).to eq('') - expect(mytftp.body).to eq(binary "\x09\x0a\x0b\x0c\x0d\x0e\x0f") + expect(mytftp.body).to eq(binary("\x09\x0a\x0b\x0c\x0d\x0e\x0f")) end end end describe '#decode!' do - let (:packets) { read_packets('tftp.pcapng') } + let(:packets) { read_packets('tftp.pcapng') } it 'decodes subsequent TFTP packets from first request' do tftp = packets.shift - expect(tftp.is? 'TFTP').to be(true) - expect(tftp.is? 'TFTP::RRQ').to be(true) + expect(tftp.is?('TFTP')).to be(true) + expect(tftp.is?('TFTP::RRQ')).to be(true) packets.each do |pkt| - expect(pkt.is? 'TFTP').to be(false) + expect(pkt.is?('TFTP')).to be(false) end tftp.tftp.decode!(packets) packets.each do |pkt| - expect(pkt.is? 'TFTP').to be(true) + expect(pkt.is?('TFTP')).to be(true) end - expect(packets[0].is? 'TFTP::DATA').to be(true) + expect(packets[0].is?('TFTP::DATA')).to be(true) expect(packets[0].udp.sport).to eq(3445) - expect(packets[0].udp.dport).to eq(50618) + expect(packets[0].udp.dport).to eq(50_618) expect(packets[0].tftp.opcode).to eq(3) expect(packets[0].tftp.block_num).to eq(1) expect(packets[0].udp.length - 8 - 4).to eq(512) - expect(packets[1].is? 'TFTP::ACK').to be(true) + expect(packets[1].is?('TFTP::ACK')).to be(true) expect(packets[1].udp.dport).to eq(3445) - expect(packets[1].udp.sport).to eq(50618) + expect(packets[1].udp.sport).to eq(50_618) expect(packets[1].tftp.opcode).to eq(4) expect(packets[1].tftp.block_num).to eq(1) - expect(packets[2].is? 'TFTP::DATA').to be(true) + expect(packets[2].is?('TFTP::DATA')).to be(true) expect(packets[2].udp.sport).to eq(3445) - expect(packets[2].udp.dport).to eq(50618) + expect(packets[2].udp.dport).to eq(50_618) expect(packets[2].tftp.opcode).to eq(3) expect(packets[2].tftp.block_num).to eq(2) expect(packets[2].udp.length - 8 - 4).to be < 512 - expect(packets[3].is? 'TFTP::ACK').to be(true) + expect(packets[3].is?('TFTP::ACK')).to be(true) expect(packets[3].udp.dport).to eq(3445) - expect(packets[3].udp.sport).to eq(50618) + expect(packets[3].udp.sport).to eq(50_618) expect(packets[3].tftp.opcode).to eq(4) expect(packets[3].tftp.block_num).to eq(2) end diff --git a/spec/header/udp_spec.rb b/spec/header/udp_spec.rb index 7841e93..a261914 100644 --- a/spec/header/udp_spec.rb +++ b/spec/header/udp_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen @@ -8,14 +10,16 @@ module Header expect(IP).to know_header(UDP).with(protocol: 17) expect(IPv6).to know_header(UDP).with(next: 17) end + it 'accepts to be added in IP packets' do pkt = PacketGen.gen('IP') - expect { pkt.add('UDP') }.to_not raise_error + expect { pkt.add('UDP') }.not_to raise_error expect(pkt.ip.protocol).to eq(17) end + it 'accepts to be added in IPv6 packets' do pkt = PacketGen.gen('IPv6') - expect { pkt.add('UDP') }.to_not raise_error + expect { pkt.add('UDP') }.not_to raise_error expect(pkt.ipv6.next).to eq(17) end end @@ -51,10 +55,10 @@ module Header end describe '#read' do - let(:udp) { UDP.new} + let(:udp) { UDP.new } it 'sets header from a string' do - str = (0...udp.sz).to_a.pack('C*') + 'body' + str = (0...udp.sz).to_a.pack('C*') << 'body' udp.read str expect(udp.sport).to eq(0x0001) expect(udp.dport).to eq(0x0203) @@ -66,15 +70,15 @@ module Header describe '#calc_checksum' do it 'computes UDP over IP header checksum' do - pkt = Packet.gen('IP').add('UDP', sport: 1, dport: 65000) + pkt = Packet.gen('IP').add('UDP', sport: 1, dport: 65_000) pkt.body = 'abcd' pkt.calc expect(pkt.udp.checksum).to eq(0x3f23) end it 'computes UDP over IPv6 header checksum' do - pkt = Packet.gen('IPv6', src: '2145::1', dst: '1:2:3:4:5:6:7:809'). - add('UDP', sport: 41000, dport: 42000) + pkt = Packet.gen('IPv6', src: '2145::1', dst: '1:2:3:4:5:6:7:809') + .add('UDP', sport: 41_000, dport: 42_000) pkt.body = 'abcd' pkt.calc expect(pkt.udp.checksum).to eq(0xcd6b) @@ -82,7 +86,7 @@ module Header end describe 'setters' do - before(:each) do + before do @udp = UDP.new end @@ -111,8 +115,8 @@ module Header it 'returns a binary string' do udp = UDP.new(body: [0, 1, 2, 3].pack('C*')) udp.calc_length - expected_str = "\x00" * 4 + "\x00\x0c\x00\x00\x00\x01\x02\x03" - expect(udp.to_s).to eq(binary expected_str) + expected_str = "\x00" * 4 << "\x00\x0c\x00\x00\x00\x01\x02\x03" + expect(udp.to_s).to eq(binary(expected_str)) end end @@ -121,7 +125,7 @@ module Header udp = UDP.new str = udp.inspect expect(str).to be_a(String) - (udp.attributes - %i(body)).each do |attr| + (udp.attributes - %i[body]).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header_spec.rb b/spec/header_spec.rb index 5828b8b..24e3c4a 100644 --- a/spec/header_spec.rb +++ b/spec/header_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative 'spec_helper' module PGTestModule @@ -8,7 +10,6 @@ class TestHeader < PacketGen::Header::Base end module PacketGen - describe Header do it '.all returns all header classes' do expect(Header.all).to include(Header::Eth, Header::IP, Header::ICMP, Header::ARP, @@ -18,13 +19,14 @@ module PacketGen end describe '.add_class' do - after(:each) { Header.remove_class PGTestModule::TestHeader } + after { Header.remove_class PGTestModule::TestHeader } it 'adds a foreign header' do - expect(Header.all).to_not include(PGTestModule::TestHeader) + expect(Header.all).not_to include(PGTestModule::TestHeader) Header.add_class PGTestModule::TestHeader expect(Header.all).to include(PGTestModule::TestHeader) end + it 'adds a class only once' do Header.add_class PGTestModule::TestHeader Header.add_class PGTestModule::TestHeader @@ -35,30 +37,31 @@ module PacketGen end describe '.remove_class' do - before(:each) { Header.add_class PGTestModule::TestHeader } - after(:each) { Header.remove_class PGTestModule::TestHeader } + before { Header.add_class PGTestModule::TestHeader } + after { Header.remove_class PGTestModule::TestHeader } it 'removes a foreign header from known headers' do expect(Header.all).to include(PGTestModule::TestHeader) Header.remove_class PGTestModule::TestHeader - expect(Header.all).to_not include(PGTestModule::TestHeader) + expect(Header.all).not_to include(PGTestModule::TestHeader) end end end - context 'foreign headers' do + context 'with foreign headers' do before(:all) do - PacketGen::Header.add_class PGTestModule::TestHeader - PacketGen::Header::IP.bind PGTestModule::TestHeader, protocol: 254 + PacketGen::Header.add_class(PGTestModule::TestHeader) + PacketGen::Header::IP.bind(PGTestModule::TestHeader, protocol: 254) end + after(:all) do - PacketGen::Header.remove_class PGTestModule::TestHeader + PacketGen::Header.remove_class(PGTestModule::TestHeader) end it 'may be used by Packet.gen' do pkt = nil - expect { pkt = PacketGen.gen('TestHeader', field1: 1) }. - to_not raise_error + expect { pkt = PacketGen.gen('TestHeader', field1: 1) } + .not_to raise_error expect(pkt.headers.size).to eq(1) expect(pkt.headers.first).to be_a(PGTestModule::TestHeader) expect(pkt.testheader).to be_a(PGTestModule::TestHeader) @@ -67,7 +70,7 @@ module PacketGen it 'may be used by Packet#add' do pkt = PacketGen.gen('IP') - expect { pkt.add('TestHeader', field2: 2) }.to_not raise_error + expect { pkt.add('TestHeader', field2: 2) }.not_to raise_error expect(pkt.headers.size).to eq(2) expect(pkt.headers.first).to be_a(Header::IP) expect(pkt.headers.last).to be_a(PGTestModule::TestHeader) @@ -76,13 +79,14 @@ module PacketGen end it 'may be used while parsing' do - field1, field2 = rand(2**32), rand(2**32) + field1 = rand(2**32) + field2 = rand(2**32) pkt = PacketGen.gen('IP', protocol: 254, body: [field1, field2].pack('N2')) new_pkt = PacketGen.parse(pkt.to_s) expect(new_pkt.headers.size).to eq(2) - expect(new_pkt.is? 'IP').to be(true) - expect(new_pkt.is? 'TestHeader').to be(true) + expect(new_pkt.is?('IP')).to be(true) + expect(new_pkt.is?('TestHeader')).to be(true) expect(new_pkt.testheader).to be_a(PGTestModule::TestHeader) expect(new_pkt.testheader.field1.to_i).to eq(field1) expect(new_pkt.testheader.field2.to_i).to eq(field2) diff --git a/spec/inspect_spec.rb b/spec/inspect_spec.rb index d51ff96..37434cb 100644 --- a/spec/inspect_spec.rb +++ b/spec/inspect_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' module PacketGen @@ -12,7 +14,7 @@ module PacketGen inspect = Inspect.inspect_attribute('my_int16', int16) expect(inspect).to eq(" Int16 my_int16: 45 (0x002d)\n") - enum = BinStruct::Int32leEnum.new(enum: {'one' => 1, 'two' => 2}) + enum = BinStruct::Int32leEnum.new(enum: { 'one' => 1, 'two' => 2 }) inspect = Inspect.inspect_attribute('my_enum', enum) expect(inspect).to eq(" Int32leEnum my_enum: one (0x00000001)\n") end @@ -32,7 +34,7 @@ module PacketGen describe '.inspect_asn1_attribute' do it 'returns a formatted string for a RASN1::Types::Enumerated' do - enum = RASN1::Types::Enumerated.new(enum: { one: 1, two: 2}) + enum = RASN1::Types::Enumerated.new(enum: { one: 1, two: 2 }) enum.value = 2 inspect = Inspect.inspect_asn1_attribute('my_enum', enum) expect(inspect).to eq(" ENUMERATED my_enum: two (0x02)\n") @@ -53,7 +55,7 @@ module PacketGen it 'returns a formatted string for others types' do os = RASN1::Types::OctetString.new - os.value = "abcd" + os.value = 'abcd' inspect = Inspect.inspect_asn1_attribute('my_str', os) expect(inspect).to eq(" OCTET STRING my_str: \"abcd\"\n") @@ -75,12 +77,12 @@ module PacketGen it 'returns a string for body' do body = (0..17).to_a.pack('C*') << (0x2a..0x2c).to_a.pack('C*') str = Inspect.inspect_body(body) - expected = '---- Body ' << '-' * 60 << "\n" + expected = +'---- Body ' << '-' * 60 << "\n" expected << " 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15\n" expected << '-' * 70 << "\n" - expected << " 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + expected << ' 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f' expected << ' ' << '.' * 16 << "\n" - expected << " 10 11 2a 2b 2c" + expected << ' 10 11 2a 2b 2c' expected << ' ' * 35 << "..*+,\n" expected << '-' * 70 << "\n" expect(str).to eq(expected) diff --git a/spec/packet_spec.rb b/spec/packet_spec.rb index 64a082b..f44bae8 100644 --- a/spec/packet_spec.rb +++ b/spec/packet_spec.rb @@ -1,10 +1,18 @@ +# frozen_string_literal: true + require_relative 'spec_helper' require 'tempfile' +module PacketGenTests + class AddIntStringTest < PacketGen::Header::Base + define_attr :field, BinStruct::IntString + end +end + module PacketGen describe Packet do describe '.gen' do - before(:each) do + before do @pkt = Packet.gen('IP') end @@ -45,7 +53,7 @@ module PacketGen end describe '.parse' do - before(:each) do + before do file = PcapNG::File.new fname = File.join(__dir__, 'pcapng', 'sample.pcapng') @raw_pkts = file.read_packet_bytes(fname) @@ -110,13 +118,13 @@ module PacketGen it 'reads a PcapNG file and returns a Array of Packet' do ary = Packet.read(pcapng_file) expect(ary).to be_a(Array) - expect(ary.all? { |el| el.is_a? Packet }).to be(true) + expect(ary).to all(be_a(Packet)) end it 'reads a pcap file and returns a Array of Packet' do ary = Packet.read(pcap_file) expect(ary).to be_a(Array) - expect(ary.all? { |el| el.is_a? Packet }).to be(true) + expect(ary).to all(be_a(Packet)) end it 'raises error on unknown file' do @@ -175,7 +183,7 @@ module PacketGen end describe '#add' do - before(:each) do + before do @pkt = Packet.gen('IP') end @@ -221,10 +229,7 @@ module PacketGen end it 'may set a IntString' do - class AddIntStringTest < Header::Base - define_attr :field, BinStruct::IntString - end - Header.add_class AddIntStringTest + Header.add_class(PacketGenTests::AddIntStringTest) pkt = Packet.gen('AddIntStringTest', field: 'This is a string') expect(pkt.addintstringtest[:field].to_human).to eq('This is a string') expect(pkt.addintstringtest[:field].to_s).to eq("\x10This is a string") @@ -266,7 +271,7 @@ class AddIntStringTest < Header::Base end describe '#is?' do - before(:each) do + before do @pkt = Packet.gen('IP') end @@ -304,7 +309,10 @@ class AddIntStringTest < Header::Base end it 'sends a packet on wire', :sudo do - Thread.new { sleep 0.1; pkt.to_w('lo') } + Thread.new do + sleep 0.1 + pkt.to_w('lo') + end packets = Packet.capture(iface: 'lo', max: 1, filter: 'ether dst ff:ff:ff:ff:ff:ff', timeout: 2) @@ -320,7 +328,10 @@ class AddIntStringTest < Header::Base pkt.body = '123' pkt.ip.id = 0 # to remove randomness on checksum computation - Thread.new { sleep 0.1; pkt.to_w('lo') } + Thread.new do + sleep 0.1 + pkt.to_w('lo') + end packets = Packet.capture(iface: 'lo', max: 1, filter: 'ether dst ff:ff:ff:ff:ff:ff', timeout: 2) @@ -332,7 +343,10 @@ class AddIntStringTest < Header::Base end it 'does not calculate calculatable attributes.if calc is false', :sudo do - Thread.new { sleep 0.1; pkt.to_w('lo', calc: false) } + Thread.new do + sleep 0.1 + pkt.to_w('lo', calc: false) + end packets = Packet.capture(iface: 'lo', max: 1, filter: 'ether dst ff:ff:ff:ff:ff:ff', timeout: 2) @@ -362,8 +376,12 @@ class AddIntStringTest < Header::Base end describe '#to_f' do - before(:each) { @write_file = Tempfile.new('packet') } - after(:each) { @write_file.close; @write_file.unlink } + before { @write_file = Tempfile.new('packet') } + + after do + @write_file.close + @write_file.unlink + end it 'writes packet as a PcapNG file' do pkt1 = Packet.gen('Eth').add('IP', src: '1.1.1.1', dst: '2.2.2.2', id: 0xffff) @@ -433,7 +451,7 @@ class AddIntStringTest < Header::Base .add('IP', src: '1.0.0.1', dst: '1.0.0.2') .add('IP', src: '10.0.0.1', dst: '10.0.0.2') .add('ICMP', type: 8, code: 0) - pkt.decapsulate(pkt. eth, pkt.ip) + pkt.decapsulate(pkt.eth, pkt.ip) expect(pkt.headers.size).to eq(2) expect(pkt.is?('IP')).to be(true) expect(pkt.is?('ICMP')).to be(true) diff --git a/spec/packetgen_spec.rb b/spec/packetgen_spec.rb index 1fb5d04..603deb7 100644 --- a/spec/packetgen_spec.rb +++ b/spec/packetgen_spec.rb @@ -1,8 +1,15 @@ +# frozen_string_literal: true + require_relative 'spec_helper' require 'tempfile' +module PacketGenTest1 + class TestHeader < PacketGen::Header::Base + end +end + describe PacketGen do - let(:file) { ::File.join(__dir__, 'pcapng', 'sample.pcapng') } + let(:file) { File.join(__dir__, 'pcapng', 'sample.pcapng') } describe '.gen' do it 'generate a Packet' do @@ -12,7 +19,7 @@ end describe '.parse' do - before(:each) do + before do @raw_pkts = PacketGen::PcapNG::File.new.read_packet_bytes(file) end @@ -25,8 +32,8 @@ expect(pkt.eth.dst).to eq('00:03:2f:1a:74:de') expect(pkt.udp.checksum).to eq(0x8bf8) - expect { pkt = PacketGen.parse(@raw_pkts.first, first_header: 'Eth') }. - not_to raise_error + expect { pkt = PacketGen.parse(@raw_pkts.first, first_header: 'Eth') } + .not_to raise_error end end @@ -34,7 +41,7 @@ it 'generates packets from a file' do ary = PacketGen.read(file) expect(ary).to be_a(Array) - expect(ary.all? { |el| el.is_a? PacketGen::Packet }).to be(true) + expect(ary).to all(be_a(PacketGen::Packet)) end end @@ -52,7 +59,7 @@ end end - describe '.capture', :sudo do + describe '.capture', :sudo do it 'captures packets' do yielded_packets = [] packets = nil @@ -68,11 +75,6 @@ end describe '.header' do - module PacketGenTest1 - class TestHeader < PacketGen::Header::Base - end - end - after(:all) do PacketGen::Header.remove_class PacketGenTest1::TestHeader end diff --git a/spec/pcapng/epb_spec.rb b/spec/pcapng/epb_spec.rb index 5f0bef3..ddb44b5 100644 --- a/spec/pcapng/epb_spec.rb +++ b/spec/pcapng/epb_spec.rb @@ -5,9 +5,9 @@ module PacketGen module PcapNG describe EPB do - before(:each) { @epb = EPB.new } + before { @epb = EPB.new } - it 'should have correct initialization values' do + it 'has correct initialization values' do expect(@epb).to be_a(EPB) expect(@epb.endian).to eq(:little) expect(@epb.type).to eq(PcapNG::EPB_TYPE.to_i) @@ -21,9 +21,9 @@ module PcapNG end context 'when reading' do - it 'should accept a String' do + it 'accepts a String' do str = ::File.read(::File.join(__dir__, 'sample.pcapng'))[84, 112] - expect { @epb.read(str) }.to_not raise_error + expect { @epb.read(str) }.not_to raise_error expect(@epb.type).to eq(PcapNG::EPB_TYPE.to_i) expect(@epb.block_len).to eq(112) expect(@epb.interface_id).to eq(0) @@ -34,7 +34,7 @@ module PcapNG expect(@epb.options?).to be(false) end - it 'should accept an IO' do + it 'accepts an IO' do ::File.open(::File.join(__dir__, 'sample.pcapng')) do |f| f.seek(84, :CUR) @epb.read f @@ -50,7 +50,7 @@ module PcapNG end end - it 'should decode packet timestamp with default resolution' do + it 'decodes packet timestamp with default resolution' do ::File.open(::File.join(__dir__, 'sample.pcapng')) do |f| f.seek(84, :CUR) @epb.read f @@ -59,7 +59,7 @@ module PcapNG expect(@epb.timestamp.round).to eq(Time.utc(2009, 10, 11, 19, 29, 6)) end - it 'should decode packet timestamp with interface resolution' do + it 'decodes packet timestamp with interface resolution' do ::File.open(::File.join(__dir__, 'sample.pcapng')) do |f| f.seek(84, :CUR) @epb.read f @@ -76,7 +76,7 @@ module PcapNG expect(@epb.timestamp.round).to eq(Time.utc(2009, 10, 11, 19, 29, 6)) end - context '#timestamp=' do + describe '#timestamp=' do it 'sets timestamp from a Time object' do @epb.timestamp = Time.utc(2009, 10, 11, 19, 29, 6.244202r) expect(@epb.tsh).to eq(292_269) diff --git a/spec/pcapng/file_spec_helper.rb b/spec/pcapng/file_spec_helper.rb index 0ad7b32..cceaa76 100644 --- a/spec/pcapng/file_spec_helper.rb +++ b/spec/pcapng/file_spec_helper.rb @@ -1,6 +1,7 @@ +# frozen_string_literal: true + module PacketGen module PcapNG - # Hash containing attended structure for each test file. # Hash's values are arrays. Each element of these arrays are a section in # pcapng file. A section is described as a hash which keys are block types @@ -8,38 +9,36 @@ module PcapNG # These files are copied from PacketFu (see {Types} for license # information). PCAPNG_TEST_FILES = { - "basic/test001.pcapng"=>[{:idb=>1, :epb=>4, :spb=>0, :unknown=>0}], - "basic/test002.pcapng"=>[{:idb=>0, :epb=>0, :spb=>0, :unknown=>0}], - "basic/test003.pcapng"=>[{:idb=>1, :epb=>0, :spb=>0, :unknown=>0}], - "basic/test004.pcapng"=>[{:idb=>2, :epb=>4, :spb=>0, :unknown=>0}], - "basic/test005.pcapng"=>[{:idb=>2, :epb=>4, :spb=>0, :unknown=>0}], - "basic/test006.pcapng"=>[{:idb=>2, :epb=>5, :spb=>0, :unknown=>0}], - "basic/test007.pcapng"=>[{:idb=>1, :epb=>1, :spb=>0, :unknown=>0}], - "basic/test008.pcapng"=>[{:idb=>2, :epb=>4, :spb=>0, :unknown=>0}], - "basic/test009.pcapng"=>[{:idb=>1, :epb=>2, :spb=>0, :unknown=>0}], - "basic/test010.pcapng"=>[{:idb=>1, :epb=>0, :spb=>4, :unknown=>0}], - "basic/test011.pcapng"=>[{:idb=>1, :epb=>2, :spb=>2, :unknown=>0}], - "basic/test012.pcapng"=>[{:idb=>1, :epb=>2, :spb=>2, :unknown=>0}], - "basic/test013.pcapng"=>[{:idb=>1, :epb=>0, :spb=>0, :unknown=>1}], - "basic/test014.pcapng"=>[{:idb=>3, :epb=>0, :spb=>0, :unknown=>3}], - "basic/test015.pcapng"=>[{:idb=>1, :epb=>0, :spb=>0, :unknown=>1}], - "basic/test016.pcapng"=>[{:idb=>1, :epb=>2, :spb=>2, :unknown=>3}], - "basic/test017.pcapng"=>[{:idb=>0, :epb=>0, :spb=>0, :unknown=>4}], - "basic/test018.pcapng"=>[{:idb=>1, :epb=>2, :spb=>2, :unknown=>4}], - "advanced/test100.pcapng"=>[{:idb=>3, :epb=>3, :spb=>2, :unknown=>5}], - "advanced/test101.pcapng"=>[{:idb=>3, :epb=>3, :spb=>1, :unknown=>6}], - "advanced/test102.pcapng"=>[{:idb=>3, :epb=>4, :spb=>1, :unknown=>12}], - "difficult/test200.pcapng"=>[{:idb=>1, :epb=>0, :spb=>0, :unknown=>0}, - {:idb=>1, :epb=>0, :spb=>0, :unknown=>0}, - {:idb=>1, :epb=>0, :spb=>0, :unknown=>0}], - "difficult/test201.pcapng"=>[{:idb=>2, :epb=>1, :spb=>0, :unknown=>1}, - {:idb=>1, :epb=>1, :spb=>1, :unknown=>1}, - {:idb=>2, :epb=>1, :spb=>0, :unknown=>2}], - "difficult/test202.pcapng"=>[{:idb=>2, :epb=>3, :spb=>0, :unknown=>4}, - {:idb=>1, :epb=>2, :spb=>2, :unknown=>4}, - {:idb=>2, :epb=>1, :spb=>0, :unknown=>4}] - } - + 'basic/test001.pcapng' => [{ idb: 1, epb: 4, spb: 0, unknown: 0 }], + 'basic/test002.pcapng' => [{ idb: 0, epb: 0, spb: 0, unknown: 0 }], + 'basic/test003.pcapng' => [{ idb: 1, epb: 0, spb: 0, unknown: 0 }], + 'basic/test004.pcapng' => [{ idb: 2, epb: 4, spb: 0, unknown: 0 }], + 'basic/test005.pcapng' => [{ idb: 2, epb: 4, spb: 0, unknown: 0 }], + 'basic/test006.pcapng' => [{ idb: 2, epb: 5, spb: 0, unknown: 0 }], + 'basic/test007.pcapng' => [{ idb: 1, epb: 1, spb: 0, unknown: 0 }], + 'basic/test008.pcapng' => [{ idb: 2, epb: 4, spb: 0, unknown: 0 }], + 'basic/test009.pcapng' => [{ idb: 1, epb: 2, spb: 0, unknown: 0 }], + 'basic/test010.pcapng' => [{ idb: 1, epb: 0, spb: 4, unknown: 0 }], + 'basic/test011.pcapng' => [{ idb: 1, epb: 2, spb: 2, unknown: 0 }], + 'basic/test012.pcapng' => [{ idb: 1, epb: 2, spb: 2, unknown: 0 }], + 'basic/test013.pcapng' => [{ idb: 1, epb: 0, spb: 0, unknown: 1 }], + 'basic/test014.pcapng' => [{ idb: 3, epb: 0, spb: 0, unknown: 3 }], + 'basic/test015.pcapng' => [{ idb: 1, epb: 0, spb: 0, unknown: 1 }], + 'basic/test016.pcapng' => [{ idb: 1, epb: 2, spb: 2, unknown: 3 }], + 'basic/test017.pcapng' => [{ idb: 0, epb: 0, spb: 0, unknown: 4 }], + 'basic/test018.pcapng' => [{ idb: 1, epb: 2, spb: 2, unknown: 4 }], + 'advanced/test100.pcapng' => [{ idb: 3, epb: 3, spb: 2, unknown: 5 }], + 'advanced/test101.pcapng' => [{ idb: 3, epb: 3, spb: 1, unknown: 6 }], + 'advanced/test102.pcapng' => [{ idb: 3, epb: 4, spb: 1, unknown: 12 }], + 'difficult/test200.pcapng' => [{ idb: 1, epb: 0, spb: 0, unknown: 0 }, + { idb: 1, epb: 0, spb: 0, unknown: 0 }, + { idb: 1, epb: 0, spb: 0, unknown: 0 }], + 'difficult/test201.pcapng' => [{ idb: 2, epb: 1, spb: 0, unknown: 1 }, + { idb: 1, epb: 1, spb: 1, unknown: 1 }, + { idb: 2, epb: 1, spb: 0, unknown: 2 }], + 'difficult/test202.pcapng' => [{ idb: 2, epb: 3, spb: 0, unknown: 4 }, + { idb: 1, epb: 2, spb: 2, unknown: 4 }, + { idb: 2, epb: 1, spb: 0, unknown: 4 }] + }.freeze end end - diff --git a/spec/pcapng/idb_spec.rb b/spec/pcapng/idb_spec.rb index 60196ee..f395fed 100644 --- a/spec/pcapng/idb_spec.rb +++ b/spec/pcapng/idb_spec.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen module PcapNG describe IDB do - before(:each) { @idb = IDB.new } + before { @idb = IDB.new } - it 'should have correct initialization values' do + it 'has correct initialization values' do expect(@idb).to be_a(IDB) expect(@idb.endian).to eq(:little) expect(@idb.type).to eq(PcapNG::IDB_TYPE.to_i) @@ -15,7 +17,7 @@ module PcapNG expect(@idb.block_len2).to eq(@idb.block_len) end - it 'should decode tsresol on demand from its options' do + it 'decodes tsresol on demand from its options' do @idb[:options].read [9, 1, 4].pack('vvC') expect(@idb.ts_resol).to eq(1E-4) @@ -24,9 +26,9 @@ module PcapNG end context 'when reading' do - it 'should accept a String' do + it 'accepts a String' do str = ::File.read(::File.join(__dir__, 'sample.pcapng'))[52, 32] - expect { @idb.read(str) }.to_not raise_error + expect { @idb.read(str) }.not_to raise_error expect(@idb.type).to eq(PcapNG::IDB_TYPE.to_i) expect(@idb.block_len).to eq(32) expect(@idb.link_type).to eq(PcapNG::LINKTYPE_ETHERNET) @@ -34,7 +36,7 @@ module PcapNG expect(@idb.options?).to be(true) end - it 'should accept an IO' do + it 'accepts an IO' do ::File.open(::File.join(__dir__, 'sample.pcapng')) do |f| f.seek(52, :CUR) @idb.read f diff --git a/spec/pcapng/shb_spec.rb b/spec/pcapng/shb_spec.rb index a985268..08c744b 100644 --- a/spec/pcapng/shb_spec.rb +++ b/spec/pcapng/shb_spec.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen module PcapNG describe SHB do - before(:each) { @shb = SHB.new } + before { @shb = SHB.new } - it 'should have correct initialization values' do + it 'has correct initialization values' do expect(@shb).to be_a(SHB) expect(@shb.endian).to eq(:little) expect(@shb.type).to eq(PcapNG::SHB_TYPE.to_i) @@ -20,14 +22,14 @@ module PcapNG end context 'when reading' do - it 'should accept a String' do + it 'accepts a String' do str = ::File.read(::File.join(__dir__, 'sample.pcapng'), 52) - expect { @shb.read(str) }.to_not raise_error + expect { @shb.read(str) }.not_to raise_error expect(@shb.block_len).to eq(52) expect(@shb.options?).to be(true) end - it 'should accept an IO' do + it 'accepts an IO' do ::File.open(::File.join(__dir__, 'sample.pcapng')) do |f| @shb.read(f) end diff --git a/spec/pcapng/spb_spec.rb b/spec/pcapng/spb_spec.rb index 9333b7e..35645bd 100644 --- a/spec/pcapng/spb_spec.rb +++ b/spec/pcapng/spb_spec.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen module PcapNG describe SPB do - before(:each) { @spb = SPB.new } + before { @spb = SPB.new } - it 'should have correct initialization values' do + it 'has correct initialization values' do expect(@spb).to be_a(SPB) expect(@spb.endian).to eq(:little) expect(@spb.type).to eq(PcapNG::SPB_TYPE.to_i) @@ -15,16 +17,16 @@ module PcapNG end context 'when reading' do - it 'should accept a String' do + it 'accepts a String' do str = ::File.read(::File.join(__dir__, 'sample-spb.pcapng'))[128, 0x14c] - expect { @spb.read str }.to_not raise_error + expect { @spb.read str }.not_to raise_error expect(@spb.type).to eq(PcapNG::SPB_TYPE.to_i) expect(@spb.block_len).to eq(0x14c) expect(@spb.orig_len).to eq(0x13a) expect(@spb.data.size).to eq(0x13a) end - it 'should accept an IO' do + it 'accepts an IO' do ::File.open(::File.join(__dir__, 'sample-spb.pcapng')) do |f| f.seek(128, :CUR) @spb.read f diff --git a/spec/pcapng/unknown_block_spec.rb b/spec/pcapng/unknown_block_spec.rb index d2566da..9612bf6 100644 --- a/spec/pcapng/unknown_block_spec.rb +++ b/spec/pcapng/unknown_block_spec.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + require_relative '../spec_helper' module PacketGen module PcapNG describe UnknownBlock do - before(:each) { @ub = UnknownBlock.new } + before { @ub = UnknownBlock.new } - it 'should have correct initialization values' do + it 'has correct initialization values' do expect(@ub).to be_a(UnknownBlock) expect(@ub.endian).to eq(:little) expect(@ub.type).to eq(0) @@ -15,14 +17,14 @@ module PcapNG end context 'when reading' do - it 'should accept a String' do + it 'accepts a String' do str = "\xff\xff\xff\xff\x0c\x00\x00\x00\x0c\x00\x00\x00" - expect { @ub.read(str) }.to_not raise_error + expect { @ub.read(str) }.not_to raise_error expect(@ub.type).to eq(0xffffffff) expect(@ub.block_len).to eq(12) end - it 'should accept an IO' do + it 'accepts an IO' do ::File.open(::File.join(__dir__, 'sample.pcapng')) do |f| @ub.read(f) end @@ -32,7 +34,7 @@ module PcapNG end describe '#to_s' do - it 'should pad body field' do + it 'pads body field' do @ub.type = 42 @ub.body = '123' diff --git a/spec/proto_spec.rb b/spec/proto_spec.rb index 9e70002..583f7f4 100644 --- a/spec/proto_spec.rb +++ b/spec/proto_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative 'spec_helper' module PacketGen diff --git a/spec/shared_examples_for_headerable.rb b/spec/shared_examples_for_headerable.rb index 0c2b098..c3d70bc 100644 --- a/spec/shared_examples_for_headerable.rb +++ b/spec/shared_examples_for_headerable.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative 'spec_helper' shared_examples 'headerable' do |klass| @@ -26,6 +28,7 @@ it 'responds to #packet=' do expect(object).to respond_to(:packet=) end + it 'responds to #added_to_packet' do expect(object).to respond_to(:added_to_packet) end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 88f5e08..0fd74ba 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + Warning[:deprecated] = true begin diff --git a/spec/support/binding_helper.rb b/spec/support/binding_helper.rb index 4d00adb..5bdb3b9 100644 --- a/spec/support/binding_helper.rb +++ b/spec/support/binding_helper.rb @@ -1,9 +1,7 @@ # frozen_string_literal: true module BindingHelper - class KnowHeaderMatcher - def initialize(header) @header = header @args = nil @@ -11,10 +9,11 @@ def initialize(header) def matches?(prev_header) @prev_header = prev_header - result = prev_header.known_headers.keys.include?(@header) - if @args and @args.is_a? Hash + result = prev_header.known_headers.key?(@header) + if @args.is_a?(Hash) bindings = prev_header.known_headers[@header] return false unless bindings + result &&= bindings.one? do |subbindings| subbindings.all? do |binding| if binding.is_a?(PacketGen::Header::Base::ProcBinding) @@ -34,7 +33,7 @@ def matches?(prev_header) end def failure_message - str = +"expected #@header to be a known header from #{@prev_header}" + str = +"expected #{@header} to be a known header from #{@prev_header}" if @bad_args str << "\n expected: #{@bad_args.inspect}" str << "\nto be included in: " \ @@ -47,8 +46,8 @@ def failure_message_when_negated str = "expected #{@header} to not be a known header from #{@prev_header}" if @bad_args str << "\n expected: #{@bad_args.inspect}" - str << "\nto not be included in: " \ - "#{@prev_header.known_headers[@header].inspect}" + str << "\nto not be included in: " \ + "#{@prev_header.known_headers[@header].inspect}" end str end @@ -68,6 +67,7 @@ def clear_bindings(klass) end def remove_binding(klass1, klass2) - klass1.known_headers.delete klass2 + klass1.known_headers.delete(klass2) + PacketGen::Header.remove_class(klass2) end end diff --git a/spec/support/capture_helper.rb b/spec/support/capture_helper.rb index 32628ef..ed59a2e 100644 --- a/spec/support/capture_helper.rb +++ b/spec/support/capture_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module CaptureHelper SYS_ENV = { 'LC_ALL' => 'C' }.freeze @@ -20,12 +22,12 @@ def ping(addr, options={}) end # capture(options) { system 'ping -c 125 127.0.0.1 } - def capture(options={}, &blk) + def capture(options={}) timeout = options[:timeout] || 0 cap = PacketGen::Capture.new - cap_thread = Thread.new { cap.start(**options) } + Thread.new { cap.start(**options) } sleep 0.1 - blk.call + yield sleep timeout + 2 cap.stop cap diff --git a/spec/support/label_helper.rb b/spec/support/label_helper.rb index 57df0a1..691e843 100644 --- a/spec/support/label_helper.rb +++ b/spec/support/label_helper.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + module LabelHelper def generate_label_str(labels) - str = '' + str = +'' labels.each do |label| str << [label.length].pack('C') << label end diff --git a/spec/unknown_packet_spec.rb b/spec/unknown_packet_spec.rb index 94caef4..d288f2f 100644 --- a/spec/unknown_packet_spec.rb +++ b/spec/unknown_packet_spec.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require_relative 'spec_helper' require 'tempfile' module PacketGen describe UnknownPacket do - before(:each) do + before do @bin_str = Packet.gen('Eth', ethertype: 42, body: (1..4).to_a.pack('C*')).to_s @pkt = UnknownPacket.new @pkt.body = @bin_str @@ -24,8 +26,12 @@ module PacketGen end describe '#to_f' do - before(:each) { @write_file = Tempfile.new('unknown_packet') } - after(:each) { @write_file.close; @write_file.unlink } + before { @write_file = Tempfile.new('unknown_packet') } + + after do + @write_file.close + @write_file.unlink + end it 'writes packet as a PcapNG file' do @pkt.to_f(@write_file.path) @@ -44,7 +50,7 @@ module PacketGen end it 'returns false if #to_s is not equal' do - expect(@pkt == "12345").to be(false) + expect(@pkt == '12345').to be(false) end end diff --git a/spec/utils/arp_spoofer_spec.rb b/spec/utils/arp_spoofer_spec.rb index 71a34f0..bef371b 100644 --- a/spec/utils/arp_spoofer_spec.rb +++ b/spec/utils/arp_spoofer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' require 'packetgen/utils' @@ -19,15 +21,15 @@ module Utils describe '#initialize' do it 'accepts Integer value for timeout' do - expect { ARPSpoofer.new timeout: 45 }.to_not raise_error + expect { ARPSpoofer.new timeout: 45 }.not_to raise_error end it 'accepts nil value for timeout' do - expect { ARPSpoofer.new timeout: nil }.to_not raise_error + expect { ARPSpoofer.new timeout: nil }.not_to raise_error end it 'accepts Float value for timeout' do - expect { ARPSpoofer.new timeout: 125.5 }.to_not raise_error + expect { ARPSpoofer.new timeout: 125.5 }.not_to raise_error end end @@ -36,13 +38,13 @@ module Utils as.add '1.2.3.4', '5.6.7.8' as.add '1.2.3.8', '5.6.7.9' expect(as.registered_targets).to include('1.2.3.4', '1.2.3.8') - expect(as.registered_targets).to_not include('5.6.7.8', '5.6.7.9') + expect(as.registered_targets).not_to include('5.6.7.8', '5.6.7.9') expect(as.active?('1.2.3.4')).to be(false) end it 'accepts options' do expect { as.add '1.2.3.4', '5.6.7.8', mac: '00:00:00:00:00:00' } - .to_not raise_error + .not_to raise_error end end @@ -51,7 +53,7 @@ module Utils as.add '1.2.3.4', '5.6.7.8' expect(as.registered_targets).to include('1.2.3.4') as.remove '1.2.3.4' - expect(as.registered_targets).to_not include('1.2.3.4') + expect(as.registered_targets).not_to include('1.2.3.4') end end @@ -87,7 +89,7 @@ module Utils as.wait expect(as.all_packets.last.length).to eq(1) packet = as.all_packets.last.first - expect(packet.arp.tpa).to_not eq('1.2.3.4') + expect(packet.arp.tpa).not_to eq('1.2.3.4') end it 'stops sending thread when last target is removed' do @@ -95,7 +97,7 @@ module Utils target_mac: '00:00:00:00:00:01' sleep(0.1) as.stop '1.2.3.4' - expect(as.instance_eval { @spoof_thread }).to be(nil) + expect(as.instance_eval { @spoof_thread }).to be_nil end end diff --git a/spec/utils_spec.rb b/spec/utils_spec.rb index ce35722..d92e22f 100644 --- a/spec/utils_spec.rb +++ b/spec/utils_spec.rb @@ -1,16 +1,18 @@ +# frozen_string_literal: true + require 'packetgen/utils' require_relative 'spec_helper' -ARP_OUTPUT = """? (192.168.1.1) at 00:01:02:03:04:05 [ether] on eth0 +ARP_OUTPUT = "? (192.168.1.1) at 00:01:02:03:04:05 [ether] on eth0 ? (192.168.1.2) at 00:11:22:33:44:55 on wlan0 -""" +" -IP_OUTPUT = """192.168.1.1 dev wlp4s0 lladdr 05:04:03:02:01:00 REACHABLE +IP_OUTPUT = "192.168.1.1 dev wlp4s0 lladdr 05:04:03:02:01:00 REACHABLE 192.168.1.2 dev ens33 lladdr 55:44:33:22:11:00 REACHABLE -""" +" def double_config - config = class_double("PacketGen::Config").as_stubbed_const + config = class_double(PacketGen::Config).as_stubbed_const config_inst = instance_double(PacketGen::Config) allow(config).to receive(:instance).and_return(config_inst) @@ -18,42 +20,42 @@ def double_config end def double_capture_class - capture = class_double("PacketGen::Capture").as_stubbed_const + capture = class_double(PacketGen::Capture).as_stubbed_const capture_inst = instance_double(PacketGen::Capture) - expect(capture).to receive(:new).and_return(capture_inst) + allow(capture).to receive(:new).and_return(capture_inst) [capture, capture_inst] end def double_pcaprubwrapper_module - class_double("PacketGen::PCAPRUBWrapper").as_stubbed_const + class_double(PacketGen::PCAPRUBWrapper).as_stubbed_const end def double_arp_spoof_class - klass_dbl = class_double("PacketGen::Utils::ARPSpoofer").as_stubbed_const + klass_dbl = class_double(PacketGen::Utils::ARPSpoofer).as_stubbed_const inst_dbl = instance_double(PacketGen::Utils::ARPSpoofer) - expect(klass_dbl).to receive(:new).and_return(inst_dbl) + allow(klass_dbl).to receive(:new).and_return(inst_dbl) [klass_dbl, inst_dbl] end module PacketGen describe Utils do - it ".cache_from_arp_command ets ARP cache from arp command" do + it '.cache_from_arp_command ets ARP cache from arp command' do cache = Utils.cache_from_arp_command(ARP_OUTPUT) expect(cache.size).to eq(2) expect(cache['192.168.1.1']).to eq(['00:01:02:03:04:05', 'eth0']) expect(cache['192.168.1.2']).to eq(['00:11:22:33:44:55', 'wlan0']) end - it ".cache_from_ip_command gets ARP cache from ip neigh command" do + it '.cache_from_ip_command gets ARP cache from ip neigh command' do cache = Utils.cache_from_ip_command(IP_OUTPUT) expect(cache.size).to eq(2) expect(cache['192.168.1.1']).to eq(['05:04:03:02:01:00', 'wlp4s0']) expect(cache['192.168.1.2']).to eq(['55:44:33:22:11:00', 'ens33']) end - it ".arp returns a IP addrdess from a MAC one (no_cache: true)" do + it '.arp returns a IP addrdess from a MAC one (no_cache: true)' do _config, config_inst = double_config _capture, capture_inst = double_capture_class inject = double_pcaprubwrapper_module @@ -65,8 +67,7 @@ module PacketGen reply = PacketGen.gen('Eth', dst: my_mac, src: target_mac) .add('ARP', tha: my_mac, tpa: my_ip, spa: target_ip, sha: target_mac) - allow(config_inst).to receive(:hwaddr).and_return(my_mac) - allow(config_inst).to receive(:ipaddr).and_return(my_ip) + allow(config_inst).to receive_messages(hwaddr: my_mac, ipaddr: my_ip) expected_pkt = PacketGen.gen('Eth', dst: 'ff:ff:ff:ff:ff:ff', src: my_mac) .add('ARP', sha: my_mac, spa: my_ip, tpa: target_ip) @@ -116,10 +117,10 @@ module PacketGen _capture, capture_inst = double_capture_class inject = double_pcaprubwrapper_module - expect(arp_spoofer_inst).to receive(:add).with(target1, target2, {iface: 'iface0'}) - expect(arp_spoofer_inst).to receive(:add).with(target2, target1, {iface: 'iface0'}) + expect(arp_spoofer_inst).to receive(:add).with(target1, target2, { iface: 'iface0' }) + expect(arp_spoofer_inst).to receive(:add).with(target2, target1, { iface: 'iface0' }) expect(config_inst).to receive(:hwaddr).and_return(my_mac) - expect(config_inst).to receive(:ipaddr).and_return({'iface0' => my_ip}) + expect(config_inst).to receive(:ipaddr).and_return({ 'iface0' => my_ip }) expect(arp_spoofer_inst).to receive(:start_all) allow(Utils).to receive(:arp).with(target1).and_return(mac1) allow(Utils).to receive(:arp).with(target2).and_return(mac2) @@ -137,4 +138,4 @@ module PacketGen Utils.mitm(target1, target2, iface: 'iface0') { |pkt| pkt } end end -end \ No newline at end of file +end From 17aaf10c061708b36bdc84e3338bfe3b40e33778 Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Sat, 23 Nov 2024 18:16:00 +0100 Subject: [PATCH 17/19] [spec] remove EspHelper (useless) --- spec/spec_helper.rb | 1 - spec/support/esp_helper.rb | 25 ------------------------- 2 files changed, 26 deletions(-) delete mode 100644 spec/support/esp_helper.rb diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0fd74ba..9694d26 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -28,7 +28,6 @@ RSpec.configure do |c| c.include CaptureHelper c.include BindingHelper - c.include EspHelper c.include LabelHelper end diff --git a/spec/support/esp_helper.rb b/spec/support/esp_helper.rb deleted file mode 100644 index 347a06e..0000000 --- a/spec/support/esp_helper.rb +++ /dev/null @@ -1,25 +0,0 @@ -require 'openssl' - -module EspHelper - def get_packets_from(file, icv_length:nil) - black_pkt, red_pkt, = PacketGen.read(file) - - red_pkt.decapsulate red_pkt.eth - black_pkt.decapsulate black_pkt.eth - - if icv_length - black_pkt.esp.icv_length = icv_length - # Re-read ESP header to get actual ICV - black_pkt.esp.read black_pkt.esp.to_s - end - - [black_pkt, red_pkt] - end - - def get_cipher(mode, ed, key) - cipher = OpenSSL::Cipher.new("aes-#{key.size*8}-#{mode}") - cipher.send ed - cipher.key = key - cipher - end -end From cf70b7e02efab62e0ae7590b1cb7beed4a75d9fe Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Sun, 24 Nov 2024 10:48:13 +0100 Subject: [PATCH 18/19] Fix some rubocop offenses --- .rubocop.yml | 8 ++++---- lib/packetgen/header/dns/opt.rb | 2 +- lib/packetgen/header/dns/rr.rb | 2 +- lib/packetgen/pcapng/idb.rb | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index c789f6f..0df68c6 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,7 +1,7 @@ require: - rubocop-performance AllCops: - TargetRubyVersion: '2.7' + TargetRubyVersion: "2.7" NewCops: enable Exclude: - .git/**/* @@ -20,11 +20,11 @@ Lint/EmptyWhen: Lint/Void: Enabled: false Metrics/AbcSize: - Max: 20 + Max: 20 Metrics/ClassLength: - Max: 200 + Max: 200 Metrics/MethodLength: - Max: 20 + Max: 20 Metrics/ParameterLists: MaxOptionalParameters: 4 Style/AccessModifierDeclarations: diff --git a/lib/packetgen/header/dns/opt.rb b/lib/packetgen/header/dns/opt.rb index 160b380..ef32cb2 100644 --- a/lib/packetgen/header/dns/opt.rb +++ b/lib/packetgen/header/dns/opt.rb @@ -94,7 +94,7 @@ def do=(value=nil) self[:ttl].value = self[:ttl].to_i & (0xffffffff & ~(1 << 15)) self[:ttl].value |= (b & 1) << 15 end - ((self[:ttl].to_i >> 15) & 1) == 1 + self[:ttl].to_i.anybits?(0x8000) end alias do? do= diff --git a/lib/packetgen/header/dns/rr.rb b/lib/packetgen/header/dns/rr.rb index 0c23382..a994854 100644 --- a/lib/packetgen/header/dns/rr.rb +++ b/lib/packetgen/header/dns/rr.rb @@ -115,7 +115,7 @@ def human_rdata def human_rrclass if self[:name].dns.is_a?(MDNS) str = self.class::CLASSES.key(self.rrclass & 0x7fff) || '0x%04x' % (self.rrclass & 0x7fff) - str += ' CACHE-FLUSH' if (self.rrclass & 0x8000).positive? + str += ' CACHE-FLUSH' if self.rrclass.anybits?(0x8000) str else self.class::CLASSES.key(self.rrclass) || '0x%04x' % self.rrclass diff --git a/lib/packetgen/pcapng/idb.rb b/lib/packetgen/pcapng/idb.rb index 6dd2a62..d89d0b1 100644 --- a/lib/packetgen/pcapng/idb.rb +++ b/lib/packetgen/pcapng/idb.rb @@ -117,7 +117,7 @@ def decode_ts_resol @options_decoded = true return @ts_resol = 1E-6 if tsresol.nil? - @ts_resol = if (tsresol & 0x80).zero? + @ts_resol = if tsresol.nobits?(0x80) 10**-tsresol else 2**-(tsresol & 0x7f) From a7213ab18f392608b6c6fa4c9dc608889a7baf7f Mon Sep 17 00:00:00 2001 From: lemontree55 Date: Mon, 2 Dec 2024 18:31:34 +0100 Subject: [PATCH 19/19] Update bin_struct to v0.3.0 Redefine all flags using Struct.define_bit_attr --- lib/packetgen/header/bootp.rb | 16 ++-- lib/packetgen/header/dns.rb | 45 ++++++------ lib/packetgen/header/dns/name.rb | 2 +- lib/packetgen/header/dns/question.rb | 2 - lib/packetgen/header/dot11.rb | 73 +++++++++---------- lib/packetgen/header/dot1q.rb | 16 ++-- lib/packetgen/header/eap/tls.rb | 16 ++-- lib/packetgen/header/eap/ttls.rb | 16 ++-- lib/packetgen/header/gre.rb | 4 +- lib/packetgen/header/igmpv3/mq.rb | 22 +++--- lib/packetgen/header/ip.rb | 63 ++++------------ lib/packetgen/header/ip/option.rb | 24 +++--- lib/packetgen/header/ipv6.rb | 16 ++-- lib/packetgen/header/mldv2/mlq.rb | 22 +++--- lib/packetgen/header/ospfv2.rb | 20 +++-- lib/packetgen/header/ospfv2/db_description.rb | 9 +-- lib/packetgen/header/ospfv2/lsa.rb | 28 +++---- lib/packetgen/header/ospfv3.rb | 16 ++-- lib/packetgen/header/ospfv3/db_description.rb | 9 +-- lib/packetgen/header/ospfv3/ipv6_prefix.rb | 28 ++++--- lib/packetgen/header/ospfv3/lsa.rb | 22 +++--- lib/packetgen/header/sctp/chunk.rb | 21 +++--- lib/packetgen/header/tcp.rb | 73 +++++++++++-------- packetgen.gemspec | 2 +- spec/header/dns_spec.rb | 4 +- spec/header/ip_spec.rb | 4 +- spec/header/sctp/abort_error_chunk_spec.rb | 4 +- spec/header/sctp/data_chunk_spec.rb | 2 +- spec/header/sctp/shutdown_chunk_spec.rb | 2 +- 29 files changed, 259 insertions(+), 322 deletions(-) diff --git a/lib/packetgen/header/bootp.rb b/lib/packetgen/header/bootp.rb index fa9ebd0..fab9beb 100644 --- a/lib/packetgen/header/bootp.rb +++ b/lib/packetgen/header/bootp.rb @@ -82,7 +82,13 @@ class BOOTP < Base # @!attribute flags # 16-bit flag field # @return [Integer] - define_attr :flags, BinStruct::Int16 + # @!attribute b + # Broadcast flag, from {#flags} + # @return [Boolean] + # @!attribute mbz + # 15-bit Must Be Zero bits, from {#flags} + # @return [Boolean] + define_bit_attr :flags, b: 1, mbz: 15 # @!attribute ciaddr # client IP address @@ -123,14 +129,6 @@ class BOOTP < Base # @return [String] define_attr :body, BinStruct::String - # @!attribute b - # Broadcast flag, from {#flags} - # @return [Boolean] - # @!attribute mbz - # 15-bit Must Be Zero bits, from {#flags} - # @return [Boolean] - define_bit_attrs_on :flags, :b, :mbz, 15 - # @return [String] def inspect super do |attr| diff --git a/lib/packetgen/header/dns.rb b/lib/packetgen/header/dns.rb index b47d136..4adb4e8 100644 --- a/lib/packetgen/header/dns.rb +++ b/lib/packetgen/header/dns.rb @@ -144,7 +144,27 @@ class DNS define_attr :id, BinStruct::Int16 # @!attribute u16 # @return [Integer] - define_attr :u16, BinStruct::Int16 + # @!attribute qr + # @return [Boolean] query (+false+) or response (+true+) + # @!attribute opcode + # @return [Integer] Kind of query. See {OPCODES}. + # @!attribute aa + # @return [Boolean] Authoritative answer + # @!attribute tc + # @return [Boolean] Truncation + # @!attribute rd + # @return [Boolean] Recursion Desired + # @!attribute ra + # @return [Boolean] Recursion Available + # @!attribute ad + # @return [Boolean] Authentic Data + # @!attribute cd + # @return [Boolean] Checking Disabled + # @!attribute rcode + # @return [Integer] Response code. See {RCODES}. + define_bit_attr :u16, qr: 1, opcode: 4, aa: 1, tc: 1, rd: 1, ra: 1, z: 1, ad: 1, cd: 1, rcode: 4 + undef opcode=, rcode= + # @!attribute qdcount # @return [Integer] define_attr :qdcount, BinStruct::Int16 @@ -170,29 +190,6 @@ class DNS # @return [RRSection] define_attr :ar, RRSection, builder: ->(h, t) { t.new(h, h[:arcount]) } - # @!attribute qr - # @return [Boolean] query (+false+) or response (+true+) - # @!attribute opcode - # @return [Integer] Kind of query. See {OPCODES}. - # @!attribute aa - # @return [Boolean] Authoritative answer - # @!attribute tc - # @return [Boolean] Truncation - # @!attribute rd - # @return [Boolean] Recursion Desired - # @!attribute ra - # @return [Boolean] Recursion Available - # @!attribute ad - # @return [Boolean] Authentic Data - # @!attribute cd - # @return [Boolean] Checking Disabled - # @!attribute rcode - # @return [Integer] Response code. See {RCODES}. - define_bit_attrs_on :u16, :qr, :opcode, 4, :aa, :tc, :rd, :ra, :z, - :ad, :cd, :rcode, 4 - - undef opcode=, rcode= - # Set opcode # @param [Integer,String] value # @return [Integer] diff --git a/lib/packetgen/header/dns/name.rb b/lib/packetgen/header/dns/name.rb index 0026c3a..2a02786 100644 --- a/lib/packetgen/header/dns/name.rb +++ b/lib/packetgen/header/dns/name.rb @@ -43,7 +43,7 @@ def from_human(str) return self if str.nil? str.split('.').each do |label| - self << BinStruct::IntString.new(string: label) + self << BinStruct::IntString.new(value: label) end self << BinStruct::IntString.new end diff --git a/lib/packetgen/header/dns/question.rb b/lib/packetgen/header/dns/question.rb index 43d10df..142456e 100644 --- a/lib/packetgen/header/dns/question.rb +++ b/lib/packetgen/header/dns/question.rb @@ -77,8 +77,6 @@ class Question < BinStruct::Struct def initialize(dns, options={}) super(options) self[:name].dns = dns - self.type = options[:type] if options[:type] - self.rrclass = options[:rrclass] if options[:rrclass] end undef rrclass= diff --git a/lib/packetgen/header/dot11.rb b/lib/packetgen/header/dot11.rb index d709ee0..11e2bb2 100644 --- a/lib/packetgen/header/dot11.rb +++ b/lib/packetgen/header/dot11.rb @@ -20,7 +20,9 @@ class PPI < Base define_attr :version, BinStruct::Int8, default: 0 # @!attribute flags # @return [Integer] 8-bit PPI flags - define_attr :flags, BinStruct::Int8 + # @!attribute align + # @return [Boolean] align flag from {#flags} attribute + define_bit_attr :flags, reserved: 7, align: 1 # @!attribute length # @return [Integer] 16-bit PPI header length define_attr :length, BinStruct::Int16le, default: 8 @@ -33,9 +35,6 @@ class PPI < Base # @!attribute body # @return [Type::String] define_attr :body, BinStruct::String - # @!attribute align - # @return [Boolean] align flag from {#flags} attribute - define_bit_attrs_on :flags, :reserved, 7, :align # Check version field # @see [Base#parse?] @@ -189,7 +188,30 @@ class << self # @!attribute frame_ctrl # @return [Integer] 16-bit frame control word - define_attr :frame_ctrl, BinStruct::Int16, default: 0 + # @!attribute subtype + # @return [Integer] 4-bit frame subtype from {#frame_ctrl} + # @!attribute type + # @return [Integer] 2-bit frame type from {#frame_ctrl} + # @!attribute proto_version + # @return [Integer] 2-bit protocol version from {#frame_ctrl} + # @!attribute order + # @return [Boolean] order flag from {#frame_ctrl} + # @!attribute wep + # @return [Boolean] wep flag from {#frame_ctrl} + # @!attribute md + # @return [Boolean] md flag from {#frame_ctrl} + # @!attribute pwmngt + # @return [Boolean] pwmngt flag from {#frame_ctrl} + # @!attribute retry + # @return [Boolean] retry flag from {#frame_ctrl} + # @!attribute mf + # @return [Boolean] mf flag from {#frame_ctrl} + # @!attribute from_ds + # @return [Boolean] from_ds flag from {#frame_ctrl} + # @!attribute to_ds + # @return [Boolean] to_ds flag from {#frame_ctrl} + define_bit_attr :frame_ctrl, subtype: 4, type: 2, proto_version: 2, order: 1, + wep: 1, md: 1, pwmngt: 1, retry: 1, mf: 1, from_ds: 1, to_ds: 1 # @!attribute id # @return [Integer] 16-bit ID/Duration word define_attr :id, BinStruct::Int16le, default: 0 @@ -204,7 +226,13 @@ class << self define_attr :mac3, Eth::MacAddr # @!attribute sequence_ctrl # @return [Integer] 16-bit sequence control word - define_attr :sequence_ctrl, BinStruct::Int16le, default: 0 + # @!attribute sequence_number (12-bit field from {#sequence_ctrl}) + # @return [Integer] + # @since 2.1.3 + # @!attribute fragment_number (4-bit field from {#sequence_ctrl}) + # @return [Integer] + # @since 2.1.3 + define_bit_attr :sequence_ctrl, sequence_number: 12, fragment_number: 4 # @!attribute mac4 # @return [Eth::MacAddr] define_attr :mac4, Eth::MacAddr @@ -221,39 +249,6 @@ class << self # @return [BinStruct::Int32le] define_attr :fcs, BinStruct::Int32le - # @!attribute subtype - # @return [Integer] 4-bit frame subtype from {#frame_ctrl} - # @!attribute type - # @return [Integer] 2-bit frame type from {#frame_ctrl} - # @!attribute proto_version - # @return [Integer] 2-bit protocol version from {#frame_ctrl} - # @!attribute order - # @return [Boolean] order flag from {#frame_ctrl} - # @!attribute wep - # @return [Boolean] wep flag from {#frame_ctrl} - # @!attribute md - # @return [Boolean] md flag from {#frame_ctrl} - # @!attribute pwmngt - # @return [Boolean] pwmngt flag from {#frame_ctrl} - # @!attribute retry - # @return [Boolean] retry flag from {#frame_ctrl} - # @!attribute mf - # @return [Boolean] mf flag from {#frame_ctrl} - # @!attribute from_ds - # @return [Boolean] from_ds flag from {#frame_ctrl} - # @!attribute to_ds - # @return [Boolean] to_ds flag from {#frame_ctrl} - define_bit_attrs_on :frame_ctrl, :subtype, 4, :type, 2, :proto_version, 2, - :order, :wep, :md, :pwmngt, :retry, :mf, :from_ds, :to_ds - - # @!attribute sequence_number (12-bit field from {#sequence_ctrl}) - # @return [Integer] - # @since 2.1.3 - # @!attribute fragment_number (4-bit field from {#sequence_ctrl}) - # @return [Integer] - # @since 2.1.3 - define_bit_attrs_on :sequence_ctrl, :sequence_number, 12, :fragment_number, 4 - alias duration id # @private alias old_attributes attributes diff --git a/lib/packetgen/header/dot1q.rb b/lib/packetgen/header/dot1q.rb index 3a2d81f..83b64e3 100644 --- a/lib/packetgen/header/dot1q.rb +++ b/lib/packetgen/header/dot1q.rb @@ -23,21 +23,19 @@ module Header class Dot1q < Base # @!attribute tci # @return [Integer] 16-bit Tag Control Information - define_attr :tci, BinStruct::Int16 - # @!attribute ethertype - # @return [Integer] 16-bit EtherType - define_attr :ethertype, BinStruct::Int16 - # @!attribute body - # @return [BinStruct::String,Header::Base] - define_attr :body, BinStruct::String - # @!attribute pcp # @return [Integer] 3-bit Priority Code Point from {#tci} # @!attribute dei # @return [Boolean] Drop Eligible Indicator from {#tci} # @!attribute vid # @return [Integer] 12-bit VLAN ID from {#tci} - define_bit_attrs_on :tci, :pcp, 3, :dei, :vid, 12 + define_bit_attr :tci, pcp: 3, dei: 1, vid: 12 + # @!attribute ethertype + # @return [Integer] 16-bit EtherType + define_attr :ethertype, BinStruct::Int16 + # @!attribute body + # @return [BinStruct::String,Header::Base] + define_attr :body, BinStruct::String end Eth.bind Dot1q, ethertype: 0x8100 diff --git a/lib/packetgen/header/eap/tls.rb b/lib/packetgen/header/eap/tls.rb index 4a6f6cb..745dc70 100644 --- a/lib/packetgen/header/eap/tls.rb +++ b/lib/packetgen/header/eap/tls.rb @@ -22,18 +22,16 @@ class TLS < EAP update_attr :type, default: 13 # @!attribute flags # @return [Integer] 8-bit flags - define_attr_before :body, :flags, BinStruct::Int8 - # @!attribute l - # Say if length field is included. Defined on {#flags} field. - # @return [Boolean] + # Say if length field is included + # @return [Integer] # @!attribute m - # Say if there are more fragments. Defined on {#flags} field. - # @return [Boolean] + # Say if there are more fragments + # @return [Integer] # @!attribute s - # If set, this message is a TLS-Start. Defined on {#flags} field. - # @return [Boolean] - define_bit_attrs_on :flags, :l, :m, :s, :reserved, 5 + # If set, this message is a TLS-Start + # @return [Integer] + define_bit_attr_before :body, :flags, l: 1, m: 1, s: 1, reserved: 5 alias length_present? l? alias more_fragments? m? alias tls_start? s? diff --git a/lib/packetgen/header/eap/ttls.rb b/lib/packetgen/header/eap/ttls.rb index 355a522..95444cd 100644 --- a/lib/packetgen/header/eap/ttls.rb +++ b/lib/packetgen/header/eap/ttls.rb @@ -22,22 +22,20 @@ class TTLS < EAP update_attr :type, default: 21 # @!attribute flags # @return [Integer] 8-bit flags - define_attr_before :body, :flags, BinStruct::Int8 - # @!attribute l - # Say if length field is included. Defined on {#flags} field. - # @return [Boolean] + # Say if length field is included + # @return [Integer] # @!attribute m - # Say if there are more fragments. Defined on {#flags} field. - # @return [Boolean] + # Say if there are more fragments + # @return [Integer] # @!attribute s - # If set, this message is a TLS-Start. Defined on {#flags} field. - # @return [Boolean] + # If set, this message is a TLS-Start + # @return [Integer] # @!attribute reserved # @return [Integer] 2-bit reserved integer # @!attribute version # @return [Integer] 3-bit version - define_bit_attrs_on :flags, :l, :m, :s, :reserved, 2, :version, 3 + define_bit_attr_before :body, :flags, l: 1, m: 1, s: 1, reserved: 2, version: 3 alias length_present? l? alias more_fragments? m? alias tls_start? s? diff --git a/lib/packetgen/header/gre.rb b/lib/packetgen/header/gre.rb index 15dba61..d9c22b2 100644 --- a/lib/packetgen/header/gre.rb +++ b/lib/packetgen/header/gre.rb @@ -26,8 +26,6 @@ class GRE < Base # IP protocol number for GRE IP_PROTOCOL = 47 - define_attr :u16, BinStruct::Int16 - # @!attribute c # @return [Boolean] # @!attribute k @@ -38,7 +36,7 @@ class GRE < Base # @return [Integer] # @!attribute ver # @return [Integer] - define_bit_attrs_on :u16, :c, :r, :k, :s, :reserved0, 9, :ver, 3 + define_bit_attr :u16, c: 1, r: 1, k: 1, s: 1, reserved0: 9, ver: 3 # @!attribute protocol_type # @return [Integer] diff --git a/lib/packetgen/header/igmpv3/mq.rb b/lib/packetgen/header/igmpv3/mq.rb index 8d8d7ef..58811fc 100644 --- a/lib/packetgen/header/igmpv3/mq.rb +++ b/lib/packetgen/header/igmpv3/mq.rb @@ -48,7 +48,16 @@ class MQ < Base # @!attribute u8 # First 8-bit field, composed of {#resv}, {#flag_s} and {#qrv} # @return [Integer] - define_attr :u8, BinStruct::Int8 + # @!attribute resv + # 4-bit reserved field in + # @return [Integer] + # @!attribute flag_s + # 1-bit S flag (Suppress Router-Side Processing) + # @return [Integer] + # @!attribute qrv + # 3-bit Querier's Robustness Variable + # @return [Integer] + define_bit_attr :u8, resv: 4, flag_s: 1, qrv: 3 # @!attribute qqic # 8-bit QQIC # @return [Integer,Float] @@ -64,17 +73,6 @@ class MQ < Base define_attr :source_addr, IP::ArrayOfAddr, builder: ->(h, t) { t.new(counter: h[:number_of_sources]) } - # @!attribute resv - # 4-bit reserved field in - # @return [Integer] - # @!attribute flag_s - # 1-bit S flag (Suppress Router-Side Processing) - # @return [Boolean] - # @!attribute qrv - # 3-bit Querier's Robustness Variable - # @return [Integer] - define_bit_attrs_on :u8, :resv, 4, :flag_s, :qrv, 3 - undef qqic, qqic= # Get QQIC value diff --git a/lib/packetgen/header/ip.rb b/lib/packetgen/header/ip.rb index 8c6a64d..64680a1 100644 --- a/lib/packetgen/header/ip.rb +++ b/lib/packetgen/header/ip.rb @@ -100,7 +100,11 @@ class IP # @!attribute u8 # First byte of IP header. May be accessed through {#version} and {#ihl}. # @return [Integer] first byte of IP header. - define_attr :u8, BinStruct::Int8, default: 0x45 + # @!attribute version + # @return [Integer] 4-bit version attribute + # @!attribute ihl + # @return [Integer] 4-bit IP header length attribute + define_bit_attr :u8, default: 0x45, version: 4, ihl: 4 # @!attribute tos # @return [Integer] 8-bit Type of Service self[attr] define_attr :tos, BinStruct::Int8, default: 0 @@ -112,7 +116,15 @@ class IP define_attr :id, BinStruct::Int16, default: ->(_) { rand(65_535) } # @!attribute frag # @return [Integer] 16-bit frag word - define_attr :frag, BinStruct::Int16, default: 0 + # @!attribute flag_rsv + # @return [Boolean] reserved bit from flags + # @!attribute flag_df + # @return [Boolean] Don't Fragment flag + # @!attribute flag_mf + # @return [Boolean] More Fragment flags + # @!attribute fragment_offset + # @return [Integer] 13-bit fragment offset + define_bit_attr :frag, flag_rsv: 1, flag_df: 1, flag_mf: 1, fragment_offset: 13 # @!attribute ttl # @return [Integer] 8-bit Time To Live self[attr] define_attr :ttl, BinStruct::Int8, default: 64 @@ -137,22 +149,6 @@ class IP # @return [BinStruct::String,Header::Base] define_attr :body, BinStruct::String - # @!attribute version - # @return [Integer] 4-bit version attribute - # @!attribute ihl - # @return [Integer] 4-bit IP header length attribute - define_bit_attrs_on :u8, :version, 4, :ihl, 4 - - # @!attribute flag_rsv - # @return [Boolean] reserved bit from flags - # @!attribute flag_df - # @return [Boolean] Don't Fragment flag - # @!attribute flag_mf - # @return [Boolean] More Fragment flags - # @!attribute fragment_offset - # @return [Integer] 13-bit fragment offset - define_bit_attrs_on :frag, :flag_rsv, :flag_df, :flag_mf, :fragment_offset, 13 - # Helper method to compute sum of 16-bit words. Used to compute IP-style # checksums. # @param [#to_s] hdr header or other object on which calculates a sum @@ -227,18 +223,6 @@ def to_w(_iface=nil) sock.close end - # @return [String] - def inspect - super do |attr| - case attr - when :u8 - inspect_u8 - when :frag - inspect_frag - end - end - end - # Check version field # @see [Base#parse?] def parse? @@ -259,25 +243,6 @@ def reply! self[:src], self[:dst] = self[:dst], self[:src] self end - - private - - def inspect_u8 - shift = Inspect.shift_level - str = Inspect.inspect_attribute(:u8, self[:u8]) - str << shift << Inspect::FMT_ATTR % ['', 'version', version] - str << shift << Inspect::FMT_ATTR % ['', 'ihl', ihl] - end - - def inspect_frag - shift = Inspect.shift_level - str = Inspect.inspect_attribute(:frag, self[:frag]) - flags = %i[rsv df mf].select { |flag| send(:"flag_#{flag}?") }.map(&:upcase) - flags_str = flags.empty? ? 'none' : flags.join(',') - str << shift << Inspect::FMT_ATTR % ['', 'flags', flags_str] - foff = Inspect.int_dec_hex(fragment_offset, 4) - str << shift << Inspect::FMT_ATTR % ['', 'frag_offset', foff] - end end self.add_class IP diff --git a/lib/packetgen/header/ip/option.rb b/lib/packetgen/header/ip/option.rb index 715b395..84cd3c5 100644 --- a/lib/packetgen/header/ip/option.rb +++ b/lib/packetgen/header/ip/option.rb @@ -47,20 +47,9 @@ class Option < BinStruct::Struct # @!attribute type # 8-bit option type # @return [Integer] - define_attr :type, BinStruct::Int8 - # @!attribute length - # 8-bit option length. If 0, there is no +length+ field in option - # @return [Integer] - define_attr :length, BinStruct::Int8, default: 0, optional: ->(h) { h.type > 1 } - # @!attribute data - # option data - # @return [String] - define_attr :data, BinStruct::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] + # @return [Integer] # @!attribute option_class # 2-bit option class (0: control, 2: debug and measurement, 1 and 3: # reserved) from {#type} field @@ -68,7 +57,16 @@ class Option < BinStruct::Struct # !@attribute number # 5-bit option number from {#type} field # @return [Integer] - define_bit_attrs_on :type, :copied, :option_class, 2, :number, 5 + define_bit_attr :type, copied: 1, option_class: 2, number: 5 + # @!attribute length + # 8-bit option length. If 0, there is no +length+ field in option + # @return [Integer] + define_attr :length, BinStruct::Int8, default: 0, optional: ->(h) { h.type > 1 } + # @!attribute data + # option data + # @return [String] + define_attr :data, BinStruct::String, optional: ->(h) { h.length > 2 }, + builder: ->(h, t) { t.new(length_from: -> { h.length - 2 }) } # @return [Hash] def self.types diff --git a/lib/packetgen/header/ipv6.rb b/lib/packetgen/header/ipv6.rb index 064d456..6b52a1c 100644 --- a/lib/packetgen/header/ipv6.rb +++ b/lib/packetgen/header/ipv6.rb @@ -95,7 +95,13 @@ class IPv6 # @!attribute u32 # First 32-bit word of IPv6 header # @return [Integer] - define_attr :u32, BinStruct::Int32, default: 0x6000_0000 + # @!attribute version + # @return [Integer] 4-bit version attribute + # @!attribute traffic_class + # @return [Integer] 8-bit traffic_class attribute + # @!attribute flow_label + # @return [Integer] 20-bit flow_label attribute + define_bit_attr :u32, default: 0x60000000, version: 4, traffic_class: 8, flow_label: 20 # @!attribute length # 16-bit word of IPv6 payload length # @return [Integer] @@ -120,14 +126,6 @@ class IPv6 # @return [BinStruct::String,Header::Base] define_attr :body, BinStruct::String - # @!attribute version - # @return [Integer] 4-bit version attribute - # @!attribute traffic_class - # @return [Integer] 8-bit traffic_class attribute - # @!attribute flow_label - # @return [Integer] 20-bit flow_label attribute - define_bit_attrs_on :u32, :version, 4, :traffic_class, 8, :flow_label, 20 - # Compute length and set +len+ field # @return [Integer] def calc_length diff --git a/lib/packetgen/header/mldv2/mlq.rb b/lib/packetgen/header/mldv2/mlq.rb index 71ab52c..1e4add0 100644 --- a/lib/packetgen/header/mldv2/mlq.rb +++ b/lib/packetgen/header/mldv2/mlq.rb @@ -80,7 +80,16 @@ class MLQ < MLD # @!attribute flags # 8-bit flags # @return [Integer] - define_attr_before :body, :flags, BinStruct::Int8 + # @!attribute flag_resv + # 4-bit reserved field in {#flags} + # @return [Integer] + # @!attribute flag_s + # S Flag (Suppress Router-Side Processing) + # @return [Integer] + # @!attribute flag_qrv + # 3-bit QRV (Querier's Robustness Variable) + # @return [Integer] + define_bit_attr_before :body, :flags, flag_resv: 4, flag_s: 1, flag_qrv: 3 # @!attribute qqic # 8-bit QQIC # @return [Integer] @@ -95,17 +104,6 @@ class MLQ < MLD define_attr_before :body, :source_addr, IPv6::ArrayOfAddr, builder: ->(h, t) { t.new(counter: h[:number_of_sources]) } - # @!attribute flag_resv - # 4-bit reserved field in {#flags} - # @return [Integer] - # @!attribute flag_s - # S Flag (Suppress Router-Side Processing) - # @return [Boolean] - # @!attribute flag_qrv - # 3-bit QRV (Querier's Robustness Variable) - # @return [Integer] - define_bit_attrs_on :flags, :flag_resv, 4, :flag_s, :flag_qrv, 3 - # Getter for +max_resp_code+ for MLDv2 packets. Use {MLDv2.decode}. # @return [Integer] # @note May return a different value from value previously set, as a diff --git a/lib/packetgen/header/ospfv2.rb b/lib/packetgen/header/ospfv2.rb index 9fcd5eb..f34db41 100644 --- a/lib/packetgen/header/ospfv2.rb +++ b/lib/packetgen/header/ospfv2.rb @@ -137,30 +137,28 @@ class OSPFv2 < Base # {#n_opt}, {#l_opt}, {#dc_opt}, {#o_opt} and {#dn_opt}. # @return [Integer] # @!attribute dn_opt - # @return [Boolean] + # @return [Integer] # @!attribute o_opt - # @return [Boolean] + # @return [Integer] # @!attribute dc_opt # This bit describes the router's handling of demand circuits. - # @return [Boolean] + # @return [Integer] # @!attribute l_opt # This specifies if a LLS Data block is present. - # @return [Boolean] + # @return [Integer] # @!attribute n_opt # This bit specifies if NSSA is supported. - # @return [Boolean] + # @return [Integer] # @!attribute mc_opt # This bit describes whether IP multicast datagrams are forwarded. - # @return [Boolean] + # @return [Integer] # @!attribute e_opt # This bit describes the way AS-external-LSAs are flooded. - # @return [Boolean] + # @return [Integer] # @!attribute mt_opt - # @return [Boolean] + # @return [Integer] def self.define_options(hdr) - hdr.define_attr :options, BinStruct::Int8 - hdr.define_bit_attrs_on :options, :dn_opt, :o_opt, :dc_opt, :l_opt, - :n_opt, :mc_opt, :e_opt, :mt_opt + hdr.define_bit_attr :options, dn_opt: 1, o_opt: 1, dc_opt: 1, l_opt: 1, n_opt: 1, mc_opt: 1, e_opt: 1, mt_opt: 1 end # @api private diff --git a/lib/packetgen/header/ospfv2/db_description.rb b/lib/packetgen/header/ospfv2/db_description.rb index b98a4a3..ce08d54 100644 --- a/lib/packetgen/header/ospfv2/db_description.rb +++ b/lib/packetgen/header/ospfv2/db_description.rb @@ -72,17 +72,16 @@ class DbDescription < Base # @!attribute flags # 8-bit interface flags ({#i_flag}, {#m_flag} and {#ms_flag}) # @return [Integer] - define_attr :flags, BinStruct::Int8 # @!attribute i_flag # Init bit - # @return [Boolean] + # @return [Integer] # @!attribute m_flag # More bit - # @return [Boolean] + # @return [Integer] # @!attribute ms_flag # Master/Slave bit - # @return [Boolean] - define_bit_attrs_on :flags, :zero, 5, :i_flag, :m_flag, :ms_flag + # @return [Integer] + define_bit_attr :flags, zero: 5, i_flag: 1, m_flag: 1, ms_flag: 1 # @!attribute sequence_number # 32-bit DD sequence number, used to sequence the collection of Database diff --git a/lib/packetgen/header/ospfv2/lsa.rb b/lib/packetgen/header/ospfv2/lsa.rb index 91ac3f5..ee7050a 100644 --- a/lib/packetgen/header/ospfv2/lsa.rb +++ b/lib/packetgen/header/ospfv2/lsa.rb @@ -102,7 +102,13 @@ class LSARouter < LSAHeader # @attribute u16 # 16-bit flag word # @return [Integer] - define_attr :u16, BinStruct::Int16 + # @attribute v_flag + # @return [Integer] + # @attribute e_flag + # @return [Integer] + # @attribute b_flag + # @return [Integer] + define_bit_attr :u16, z: 5, v_flag: 1, e_flag: 1, b_flag: 1, zz: 8 # @attribute link_count # Number of links # @return [Integer] @@ -110,14 +116,6 @@ class LSARouter < LSAHeader # @attribute links # @return [ArrayOfLink] define_attr :links, ArrayOfLink, builder: ->(h, t) { t.new(counter: h[:link_count]) } - - # @attribute v_flag - # @return [Boolean] - # @attribute e_flag - # @return [Boolean] - # @attribute b_flag - # @return [Boolean] - define_bit_attrs_on :u16, :z, 5, :v_flag, :e_flag, :b_flag, :zz, 8 end # This class handles LSA Network payloads. @@ -145,7 +143,11 @@ class External < BinStruct::Struct # @!attribute u8 # @return [Integer] - define_attr :u8, BinStruct::Int8 + # @!attribute e_flag + # @return [Integer] + # @!attribute tos + # @return [Integer] + define_bit_attr :u8, e_flag: 1, tos: 7 # @!attribute metric # @return [Integer] define_attr :metric, BinStruct::Int24 @@ -156,12 +158,6 @@ class External < BinStruct::Struct # @return [Integer] define_attr :ext_route_tag, BinStruct::Int32 - # @!attribute e_flag - # @return [Boolean] - # @!attribute tos - # @return [Integer] - define_bit_attrs_on :u8, :e_flag, :tos, 7 - # @return [String] def to_human "" diff --git a/lib/packetgen/header/ospfv3.rb b/lib/packetgen/header/ospfv3.rb index 0930765..bc3dbb9 100644 --- a/lib/packetgen/header/ospfv3.rb +++ b/lib/packetgen/header/ospfv3.rb @@ -118,27 +118,25 @@ class OSPFv3 < Base # @return [Integer] # @!attribute dc_opt # This bit describes the router's handling of demand circuits. - # @return [Boolean] + # @return [Integer] # @!attribute r_opt # This bit indicates whether the originator is an active router. - # @return [Boolean] + # @return [Integer] # @!attribute n_opt # This bit indicates whether or not the router is attached to an NSSA. - # @return [Boolean] + # @return [Integer] # @!attribute x_opt # This bit should be set to 0, and ignored when received. - # @return [Boolean] + # @return [Integer] # @!attribute e_opt # This bit describes the way AS-external-LSAs are flooded. - # @return [Boolean] + # @return [Integer] # @!attribute v6_opt # If this bit is clear, the router/link should be excluded from IPv6 # routing calculations. - # @return [Boolean] + # @return [Integer] def self.define_options(hdr) - hdr.define_attr :options, BinStruct::Int24 - hdr.define_bit_attrs_on :options, :z, 18, :dc_opt, :r_opt, - :n_opt, :x_opt, :e_opt, :v6_opt + hdr.define_bit_attr :options, z: 18, dc_opt: 1, r_opt: 1, n_opt: 1, x_opt: 1, e_opt: 1, v6_opt: 1 end # @api private diff --git a/lib/packetgen/header/ospfv3/db_description.rb b/lib/packetgen/header/ospfv3/db_description.rb index 2835db4..71ccfd1 100644 --- a/lib/packetgen/header/ospfv3/db_description.rb +++ b/lib/packetgen/header/ospfv3/db_description.rb @@ -80,17 +80,16 @@ class DbDescription < Base # @!attribute flags # 16-bit interface flags ({#i_flag}, {#m_flag} and {#ms_flag}) # @return [Integer] - define_attr :flags, BinStruct::Int16 # @!attribute i_flag # Init bit from {#flags} field - # @return [Boolean] + # @return [Integer] # @!attribute m_flag # More bit from {#flags} field - # @return [Boolean] + # @return [Integer] # @!attribute ms_flag # Master/Slave bit from {#flags} field - # @return [Boolean] - define_bit_attrs_on :flags, :zz, 13, :i_flag, :m_flag, :ms_flag + # @return [Integer] + define_bit_attr :flags, zz: 13, i_flag: 1, m_flag: 1, ms_flag: 1 # @!attribute sequence_number # 32-bit DD sequence number, used to sequence the collection of Database diff --git a/lib/packetgen/header/ospfv3/ipv6_prefix.rb b/lib/packetgen/header/ospfv3/ipv6_prefix.rb index e91ef59..151e548 100644 --- a/lib/packetgen/header/ospfv3/ipv6_prefix.rb +++ b/lib/packetgen/header/ospfv3/ipv6_prefix.rb @@ -28,33 +28,31 @@ class IPv6Prefix < BinStruct::Struct # Prefix capabilities. See also capability bits: {#dn_opt}, {#p_opt}, # {#la_opt} and {#nu_opt}. # @return [Options] - define_attr :options, BinStruct::Int8 - # @!attribute reserved - # Reserved field in most of LSA types. - # @return [Integer] - define_attr :reserved, BinStruct::Int16 - # @!attribute prefix - # IPv6 Prefix as an array of 32-bit words - # @return [Prefix] - define_attr :prefix, BinStruct::ArrayOfInt32, builder: ->(h, t) { t.new(length_from: -> { h.length / 8 }) } - # @!attribute dn_opt # This bit controls an inter-area-prefix-LSAs or AS-external-LSAs # re-advertisement in a VPN environment. - # @return [Boolean] + # @return [Integer] # @!attribute p_opt # The "propagate" bit. Set on NSSA area prefixes that should be # readvertised by the translating NSSA area border. - # @return [Boolean] + # @return [Integer] # @!attribute la_opt # The "local address" capability bit. If set, the prefix is # actually an IPv6 interface address of the Advertising Router. - # @return [Boolean] + # @return [Integer] # @!attribute nu_opt # The "no unicast" capability bit. If set, the prefix should be # excluded from IPv6 unicast calculations. - # @return [Boolean] - define_bit_attrs_on :options, :zz, 3, :dn_opt, :p_opt, :z, :la_opt, :nu_opt + # @return [Integer] + define_bit_attr :options, zz: 3, dn_opt: 1, p_opt: 1, z: 1, la_opt: 1, nu_opt: 1 + # @!attribute reserved + # Reserved field in most of LSA types. + # @return [Integer] + define_attr :reserved, BinStruct::Int16 + # @!attribute prefix + # IPv6 Prefix as an array of 32-bit words + # @return [Prefix] + define_attr :prefix, BinStruct::ArrayOfInt32, builder: ->(h, t) { t.new(length_from: -> { h.length / 8 }) } # Get human-readable prefix # @return [String] diff --git a/lib/packetgen/header/ospfv3/lsa.rb b/lib/packetgen/header/ospfv3/lsa.rb index a08e230..e03307b 100644 --- a/lib/packetgen/header/ospfv3/lsa.rb +++ b/lib/packetgen/header/ospfv3/lsa.rb @@ -70,23 +70,21 @@ class LSARouter < LSAHeader # @attribute flags # 8-bit flag word # @return [Integer] - define_attr :flags, BinStruct::Int8 + # @!attribute nt_flag + # @return [Integer] + # @!attribute v_flag + # @return [Integer] + # @!attribute e_flag + # @return [Integer] + # @!attribute b_flag + # @return [Integer] + define_bit_attr :flags, zz: 3, nt_flag: 1, x_flag: 1, v_flag: 1, e_flag: 1, b_flag: 1 # @!macro define_ospfv3_options OSPFv3.define_options(self) # @attribute links # @return [ArrayOfLink] define_attr :links, ArrayOfLink, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:links) }) } - # @!attribute nt_flag - # @return [Boolean] - # @!attribute v_flag - # @return [Boolean] - # @!attribute e_flag - # @return [Boolean] - # @!attribute b_flag - # @return [Boolean] - define_bit_attrs_on :flags, :zz, 3, :nt_flag, :x_flag, :v_flag, :e_flag, - :b_flag end # This class handles OSPFv3 LSA Network payloads. @@ -190,7 +188,7 @@ class ArrayOfLSA < BinStruct::Array # @param [Hash] options # @option options [BinStruct::Int] counter Int object used as a counter for this set - # @option options [Boolean] only_headers if +true+, only {LSAHeader LSAHeaders} + # @option options [Integer] only_headers if +true+, only {LSAHeader LSAHeaders} # will be added to this array. def initialize(options={}) super diff --git a/lib/packetgen/header/sctp/chunk.rb b/lib/packetgen/header/sctp/chunk.rb index 02e00e9..6ede142 100644 --- a/lib/packetgen/header/sctp/chunk.rb +++ b/lib/packetgen/header/sctp/chunk.rb @@ -163,19 +163,20 @@ class DataChunk < BaseChunk # @return [String] define_attr :body, BinStruct::String, builder: ->(h, t) { t.new(length_from: -> { h.length - 4 }) } + remove_attr :flags # @!attribute flag_i # IMMEDIATE flag - # @return [Boolean] + # @return [Integer] # @!attribute flag_u # UNORDERED flag - # @return [Boolean] + # @return [Integer] # @!attribute flag_b # BEGINNING fragment flag - # @return [Boolean] + # @return [Integer] # @!attribute flag_e # ENDING fragment flag - # @return [Boolean] - define_bit_attrs_on :flags, :flag_res, 4, :flag_i, :flag_u, :flag_b, :flag_e + # @return [Integer] + define_bit_attr_after :type, :flags, flag_res: 4, flag_i: 1, flag_u: 1, flag_b: 1, flag_e: 1 private @@ -435,9 +436,10 @@ def to_human # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # @author Sylvain Daubert class AbortChunk < ErrorChunk + remove_attr :flags # @!attribute flag_t - # @return [Boolean] - define_bit_attrs_on :flags, :flag_res, 7, :flag_t + # @return [Integer] + define_bit_attr_after :type, :flags, flag_res: 7, flag_t: 1 def initialize(options={}) options[:type] = BaseChunk::TYPES['ABORT'] unless options.key?(:type) @@ -532,9 +534,10 @@ def initialize(options={}) # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # @author Sylvain Daubert class ShutdownCompleteChunk < BaseChunk + remove_attr :flags # @!attribute flag_t - # @return [Boolean] - define_bit_attrs_on :flags, :flag_res, 7, :flag_t + # @return [Integer] + define_bit_attr_after :type, :flags, flag_res: 7, flag_t: 1 def initialize(options={}) options[:type] = BaseChunk::TYPES['SHUTDOWN_COMPLETE'] unless options.key?(:type) diff --git a/lib/packetgen/header/tcp.rb b/lib/packetgen/header/tcp.rb index fa8df96..7fc6523 100644 --- a/lib/packetgen/header/tcp.rb +++ b/lib/packetgen/header/tcp.rb @@ -78,7 +78,7 @@ class TCP < Base end end -# Need to load Options now, as this is used through define_bit_attrs_on, +# Need to load Options now, as this is used through define_bit_attr, # which make a call to TCP.new, which needs Options require_relative 'tcp/options' @@ -106,7 +106,34 @@ class TCP define_attr :acknum, BinStruct::Int32 # @!attribute u16 # @return [Integer] 16-bit word used by flags and bit fields - define_attr :u16, BinStruct::Int16 + # @!attribute data_offset + # @return [Integer] 4-bit data offset from {#u16} + # @!attribute reserved + # @return [Integer] 3-bit reserved from {#u16} + # @!attribute flags + # @return [Integer] 9-bit flags from {#u16} + # @!attribute flag_ns + # @return [Integer] 1-bit NS flag + # @!attribute flag_cwr + # @return [Integer] 1-bit CWR flag + # @!attribute flag_ece + # @return [Integer] 1-bit ECE flag + # @!attribute flag_urg + # @return [Integer] 1-bit URG flag + # @!attribute flag_ack + # @return [Integer] 1-bit ACK flag + # @!attribute flag_psh + # @return [Integer] 1-bit PSH flag + # @!attribute flag_rst + # @return [Integer] 1-bit RST flag + # @!attribute flag_syn + # @return [Integer] 1-bit SYN flag + # @!attribute flag_fin + # @return [Integer] 1-bit FIN flag + define_bit_attr :u16, data_offset: 4, reserved: 3, flag_ns: 1, flag_cwr: 1, flag_ece: 1, flag_urg: 1, flag_ack: 1, flag_psh: 1, + flag_rst: 1, flag_syn: 1, flag_fin: 1 + alias hlen data_offset + alias hlen= data_offset= # @!attribute window # 16-bit TCP window size # @return [Integer] @@ -158,38 +185,22 @@ class TCP def initialize(options={}) opts = { data_offset: 5 }.merge!(options) super(opts) + self.flags = opts[:flags] if opts.key?(:flags) end - # @!attribute data_offset - # @return [Integer] 4-bit data offset from {#u16} - # @!attribute reserved - # @return [Integer] 3-bit reserved from {#u16} - # @!attribute flags - # @return [Integer] 9-bit flags from {#u16} - define_bit_attrs_on :u16, :data_offset, 4, :reserved, 3, :flags, 9 - alias hlen data_offset - alias hlen= data_offset= + # Get all flags value from [#u16] + # @return [Integer] + def flags + self.u16 & 0x1ff + end - # @!attribute flag_ns - # @return [Boolean] 1-bit NS flag - # @!attribute flag_cwr - # @return [Boolean] 1-bit CWR flag - # @!attribute flag_ece - # @return [Boolean] 1-bit ECE flag - # @!attribute flag_urg - # @return [Boolean] 1-bit URG flag - # @!attribute flag_ack - # @return [Boolean] 1-bit ACK flag - # @!attribute flag_psh - # @return [Boolean] 1-bit PSH flag - # @!attribute flag_rst - # @return [Boolean] 1-bit RST flag - # @!attribute flag_syn - # @return [Boolean] 1-bit SYN flag - # @!attribute flag_fin - # @return [Boolean] 1-bit FIN flag - define_bit_attrs_on :u16, :_, 7, :flag_ns, :flag_cwr, :flag_ece, :flag_urg, - :flag_ack, :flag_psh, :flag_rst, :flag_syn, :flag_fin + # Set all flags at once + # @parameter [Integer] value + # @return [Integer] + def flags=(value) + new_u16 = (self.u16 & 0xfe00) | (value & 0x1ff) + self[:u16].from_human(new_u16) + end # Compute checksum and set +checksum+ field # @return [Integer] diff --git a/packetgen.gemspec b/packetgen.gemspec index 271b593..de08bbe 100644 --- a/packetgen.gemspec +++ b/packetgen.gemspec @@ -38,7 +38,7 @@ Gem::Specification.new do |spec| spec.required_ruby_version = '>= 2.7.0' - spec.add_dependency 'bin_struct', '>=0.2.0' + spec.add_dependency 'bin_struct', '~>0.3.0' spec.add_dependency 'digest-crc', '~> 0' spec.add_dependency 'interfacez', '~>1.0' spec.add_dependency 'pcaprub', '~>0.13.0' diff --git a/spec/header/dns_spec.rb b/spec/header/dns_spec.rb index 7d364e7..d80e543 100644 --- a/spec/header/dns_spec.rb +++ b/spec/header/dns_spec.rb @@ -157,7 +157,7 @@ module Header it '#opcode= accepts integers' do dns.opcode = 1 - expect((dns[:u16].value & 0x7800) >> 11).to eq(1) + expect((dns[:u16].to_i & 0x7800) >> 11).to eq(1) end it '#opcode= accepts known string opcodes' do @@ -173,7 +173,7 @@ module Header it '#rcode= accepts integers' do dns.rcode = 8 - expect(dns[:u16].value & 0xf).to eq(8) + expect(dns[:u16].to_i & 0xf).to eq(8) end it '#rcode= accepts known string opcodes' do diff --git a/spec/header/ip_spec.rb b/spec/header/ip_spec.rb index 5e98938..6e0cca5 100644 --- a/spec/header/ip_spec.rb +++ b/spec/header/ip_spec.rb @@ -252,14 +252,14 @@ module Header ip = IP.new str = ip.inspect expect(str).to be_a(String) - (ip.to_h.keys - %i[body options] + %i[version ihl flags frag_offset]).each do |attr| + (ip.to_h.keys - %i[body options] + %i[version ihl flag_df flag_mf fragment_offset]).each do |attr| expect(str).to include(attr.to_s) end ip = IP.new(ihl: 6) str = ip.inspect expect(str).to be_a(String) - (ip.to_h.keys - %i[body] + %i[version ihl flags frag_offset]).each do |attr| + (ip.to_h.keys - %i[body] + %i[version ihl flag_df flag_mf fragment_offset]).each do |attr| expect(str).to include(attr.to_s) end end diff --git a/spec/header/sctp/abort_error_chunk_spec.rb b/spec/header/sctp/abort_error_chunk_spec.rb index fec1190..5105cc9 100644 --- a/spec/header/sctp/abort_error_chunk_spec.rb +++ b/spec/header/sctp/abort_error_chunk_spec.rb @@ -59,7 +59,7 @@ class SCTP [AbortChunk, ErrorChunk].each do |klass| describe klass do describe '#initialize' do - it 'creates an InitChunk header with default values' do + it "creates an #{klass} header with default values" do obj = klass.new expect(obj).to be_a(klass) expect(obj.type).to eq(klass == AbortChunk ? 6 : 9) @@ -71,7 +71,7 @@ class SCTP it 'accepts options' do options = { type: 0xffff, - flags: 0x1234, + flags: 0x42, length: 42, } obj = klass.new(options) diff --git a/spec/header/sctp/data_chunk_spec.rb b/spec/header/sctp/data_chunk_spec.rb index c43d7ef..b99423e 100644 --- a/spec/header/sctp/data_chunk_spec.rb +++ b/spec/header/sctp/data_chunk_spec.rb @@ -23,7 +23,7 @@ class SCTP it 'accepts options' do options = { type: 0x1234, - flags: 0x5678, + flags: 0x56, length: 42, tsn: 0x01020304, stream_id: 0xabcd, diff --git a/spec/header/sctp/shutdown_chunk_spec.rb b/spec/header/sctp/shutdown_chunk_spec.rb index 8e2be69..ed82311 100644 --- a/spec/header/sctp/shutdown_chunk_spec.rb +++ b/spec/header/sctp/shutdown_chunk_spec.rb @@ -96,7 +96,7 @@ class SCTP it 'accepts options' do options = { type: 0xffff, - flags: 0x1234, + flags: 0x42, length: 42, } shutdown = ShutdownCompleteChunk.new(options)