File: shb.rb

package info (click to toggle)
ruby-packetfu 2.0.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,520 kB
  • sloc: ruby: 8,344; makefile: 2
file content (146 lines) | stat: -rw-r--r-- 4,658 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
require 'stringio'

module PacketFu
  module PcapNG

    # PcapngSHB represents a Section Header Block (SHB) of a pcapng file.
    #
    # == PcapngSHB Definition
    #   Int32   :type           Default: 0x0A0D0D0A
    #   Int32   :block_len
    #   Int32   :magic          Default: 0x1A2B3C4D  # :big is 0x4D3C2C1A
    #   Int16   :ver_major      Default: 1
    #   Int16   :ver_minor      Default: 0
    #   Int64   :section_len
    #   String  :options        Default: ''
    #   Int32   :block_len2
    class SHB < Struct.new(:type, :block_len, :magic, :ver_major, :ver_minor,
                           :section_len, :options, :block_len2)
      include StructFu
      include Block
      attr_accessor :endian
      attr_reader :interfaces
      # Get unsupported blocks given in pcapng file as raw data
      attr_reader :unknown_blocks

      MAGIC_INT32  = 0x1A2B3C4D
      MAGIC_LITTLE = [MAGIC_INT32].pack('V')
      MAGIC_BIG    = [MAGIC_INT32].pack('N')

      MIN_SIZE     = 7*4
      SECTION_LEN_UNDEFINED = 0xffffffff_ffffffff

      def initialize(args={})
        @endian = set_endianness(args[:endian] || :little)
        @interfaces = []
        @unknown_blocks = []
        init_fields(args)
        super(args[:type], args[:block_len], args[:magic], args[:ver_major],
              args[:ver_minor], args[:section_len], args[:options], args[:block_len2])
      end

      # Used by #initialize to set the initial fields
      def init_fields(args={})
        args[:type]  = @int32.new(args[:type] || PcapNG::SHB_TYPE.to_i)
        args[:block_len] = @int32.new(args[:block_len] || MIN_SIZE)
        args[:magic] = @int32.new(args[:magic] || MAGIC_INT32)
        args[:ver_major] = @int16.new(args[:ver_major] || 1)
        args[:ver_minor] = @int16.new(args[:ver_minor] || 0)
        args[:section_len] = @int64.new(args[:section_len] || SECTION_LEN_UNDEFINED)
        args[:options] = StructFu::String.new(args[:options] || '')
        args[:block_len2] = @int32.new(args[:block_len2] || MIN_SIZE)
        args
      end

      def has_options?
        self[:options].size > 0
      end

      # Reads a String or a IO to populate the object
      def read(str_or_io)
        if str_or_io.respond_to? :read
          io = str_or_io
        else
          io = StringIO.new(force_binary(str_or_io.to_s))
        end
        return self if io.eof?

        type_str = io.read(4)
        unless type_str == PcapNG::SHB_TYPE.to_s
          type = type_str.unpack('H*').join
          raise InvalidFileError, "Incorrect type (#{type})for Section Header Block"
        end

        block_len_str = io.read(4)

        magic_str = io.read(4)
        case @endian
        when :little
          case magic_str
          when MAGIC_LITTLE
          when MAGIC_BIG
            force_endianness :big
          else
            raise InvalidFileError, 'Incorrect magic for Section Header Block'
          end
        when :big
          case magic_str
          when MAGIC_BIG
          when MAGIC_LITTLE
            force_endianness :little
          else
            raise InvalidFileError, 'Incorrect magic for Section Header Block'
          end
        end

        self[:type].read type_str
        self[:block_len].read block_len_str
        self[:magic].read magic_str
        self[:ver_major].read io.read(2)
        self[:ver_minor].read io.read(2)
        self[:section_len].read io.read(8)
        self[:options].read io.read(self[:block_len].to_i - MIN_SIZE)
        self[:block_len2].read io.read(4)

        unless self[:block_len].to_i == self[:block_len2].to_i
          raise InvalidFileError, 'Incoherency in Section Header Block'
        end

        self
      end

      # Add a IDB to this section
      def <<(idb)
        @interfaces << idb
      end

      # Return the object as a String
      def to_s
        body = @interfaces.map(&:to_s).join
        unless self[:section_len].to_i == SECTION_LEN_UNDEFINED
          self.section_len.value = body.size
        end
        pad_field :options
        recalc_block_len
        to_a.map(&:to_s).join + body
      end


      private

      def force_endianness(endian)
        set_endianness endian
        @endian = endian
        self[:type]  = @int32.new(self[:type].to_i)
        self[:block_len] = @int32.new(self[:block_len].to_i)
        self[:magic] = @int32.new(self[:magic].to_i)
        self[:ver_major] = @int16.new(self[:ver_major].to_i)
        self[:ver_minor] = @int16.new(self[:ver_minor].to_i)
        self[:section_len] = @int64.new(self[:section_len].to_i)
        self[:block_len2] = @int32.new(self[:block_len2].to_i)
      end

    end

  end
end