packetgen 3.2.1 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/lib/packetgen/capture.rb +19 -8
 - data/lib/packetgen/header/dhcpv6/duid.rb +6 -0
 - data/lib/packetgen/header/dns/name.rb +3 -3
 - data/lib/packetgen/header/dns/rr.rb +2 -2
 - data/lib/packetgen/header/dot11.rb +1 -1
 - data/lib/packetgen/header/http/headers.rb +16 -1
 - data/lib/packetgen/header/http/request.rb +1 -1
 - data/lib/packetgen/header/http/response.rb +1 -1
 - data/lib/packetgen/header/ip/option.rb +36 -11
 - data/lib/packetgen/header/ipv6/addr.rb +1 -1
 - data/lib/packetgen/header/ospfv2/lsa_header.rb +1 -1
 - data/lib/packetgen/header/ospfv3/lsa_header.rb +1 -1
 - data/lib/packetgen/header/snmp.rb +19 -2
 - data/lib/packetgen/header/tcp/options.rb +1 -1
 - data/lib/packetgen/headerable.rb +1 -1
 - data/lib/packetgen/inspect.rb +6 -3
 - data/lib/packetgen/packet.rb +2 -0
 - data/lib/packetgen/pcapng/file.rb +2 -2
 - data/lib/packetgen/pcaprub_wrapper.rb +2 -2
 - data/lib/packetgen/proto.rb +1 -1
 - data/lib/packetgen/types/array.rb +30 -15
 - data/lib/packetgen/types/fields.rb +4 -2
 - data/lib/packetgen/unknown_packet.rb +3 -2
 - data/lib/packetgen/utils/arp_spoofer.rb +3 -1
 - data/lib/packetgen/utils.rb +24 -15
 - data/lib/packetgen/version.rb +1 -1
 - data/lib/packetgen.rb +3 -1
 - metadata +7 -55
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: de85a6f18ac001823cdbd0802c8946ead811be724c9069266b78c493d99feb6b
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: ef73ca367e87bb47ca4f37ee387c7a73d0ad0f19cebaca151443560f42508559
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: '01605812af7b7d53111bfdc0d4d095cb6f0df4975634db17700d7c15c6acc63ba82585e6c5a5d2d93c130d566f45bb62d9ff3709c27e0f7cf4ea0c20ba7c172f'
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: e4a54c74e032ee12d744f94c657416591c0f056a005da4b104c017294d73819596a28ec59c71597f8d0f2398da79a8b7784809d5e30cd5da9d53fc655101e2f4
         
     | 
    
        data/lib/packetgen/capture.rb
    CHANGED
    
    | 
         @@ -27,6 +27,11 @@ module PacketGen 
     | 
|
| 
       27 
27 
     | 
    
         
             
                # @return [Array<String>]
         
     | 
| 
       28 
28 
     | 
    
         
             
                attr_reader :raw_packets
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
      
 30 
     | 
    
         
            +
                # Get timestamps associated with {#packets} and {#raw_packets}
         
     | 
| 
      
 31 
     | 
    
         
            +
                # @return [Array<Time>]
         
     | 
| 
      
 32 
     | 
    
         
            +
                # @since 3.3.0
         
     | 
| 
      
 33 
     | 
    
         
            +
                attr_reader :timestamps
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
       30 
35 
     | 
    
         
             
                # Get interface name
         
     | 
| 
       31 
36 
     | 
    
         
             
                # @return [String]
         
     | 
| 
       32 
37 
     | 
    
         
             
                attr_reader :iface
         
     | 
| 
         @@ -54,6 +59,7 @@ module PacketGen 
     | 
|
| 
       54 
59 
     | 
    
         | 
| 
       55 
60 
     | 
    
         
             
                  @packets     = []
         
     | 
| 
       56 
61 
     | 
    
         
             
                  @raw_packets = []
         
     | 
| 
      
 62 
     | 
    
         
            +
                  @timestamps = []
         
     | 
| 
       57 
63 
     | 
    
         
             
                  set_options iface, max, timeout, filter, promisc, parse, snaplen, monitor
         
     | 
| 
       58 
64 
     | 
    
         
             
                end
         
     | 
| 
       59 
65 
     | 
    
         | 
| 
         @@ -61,16 +67,18 @@ module PacketGen 
     | 
|
| 
       61 
67 
     | 
    
         
             
                # @see {#initialize} for parameters
         
     | 
| 
       62 
68 
     | 
    
         
             
                # @yieldparam [Packet,String] packet if a block is given, yield each
         
     | 
| 
       63 
69 
     | 
    
         
             
                #    captured packet (Packet or raw data String, depending on +:parse+ option)
         
     | 
| 
      
 70 
     | 
    
         
            +
                # @yieldparam [Time] timestamp packet timestamp
         
     | 
| 
       64 
71 
     | 
    
         
             
                # @since 3.0.0 arguments are kwargs and no more a hash
         
     | 
| 
       65 
72 
     | 
    
         
             
                # @since 3.1.5 add monitor argument
         
     | 
| 
      
 73 
     | 
    
         
            +
                # @since 3.3.0 add packet timestamp as second yield parameter
         
     | 
| 
       66 
74 
     | 
    
         
             
                # @author Sylvain Daubert
         
     | 
| 
       67 
75 
     | 
    
         
             
                # @author optix2000 - add monitor argument
         
     | 
| 
       68 
76 
     | 
    
         
             
                def start(iface: nil, max: nil, timeout: nil, filter: nil, promisc: false, parse: true, snaplen: nil, monitor: nil, &block)
         
     | 
| 
       69 
77 
     | 
    
         
             
                  set_options iface, max, timeout, filter, promisc, parse, snaplen, monitor
         
     | 
| 
       70 
78 
     | 
    
         | 
| 
       71 
79 
     | 
    
         
             
                  @cap_thread = Thread.new do
         
     | 
| 
       72 
     | 
    
         
            -
                    PCAPRUBWrapper.capture(**capture_args) do | 
     | 
| 
       73 
     | 
    
         
            -
                      add_packet( 
     | 
| 
      
 80 
     | 
    
         
            +
                    PCAPRUBWrapper.capture(**capture_args) do |packet|
         
     | 
| 
      
 81 
     | 
    
         
            +
                      add_packet(packet, &block)
         
     | 
| 
       74 
82 
     | 
    
         
             
                      break if defined?(@max) && (raw_packets.size >= @max)
         
     | 
| 
       75 
83 
     | 
    
         
             
                    end
         
     | 
| 
       76 
84 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -119,18 +127,21 @@ module PacketGen 
     | 
|
| 
       119 
127 
     | 
    
         
             
                  PCAPRUBWrapper.filter_on(pcap: pcap, filter: filter)
         
     | 
| 
       120 
128 
     | 
    
         
             
                end
         
     | 
| 
       121 
129 
     | 
    
         | 
| 
       122 
     | 
    
         
            -
                def add_packet( 
     | 
| 
       123 
     | 
    
         
            -
                  raw_packets << data
         
     | 
| 
      
 130 
     | 
    
         
            +
                def add_packet(packet, &block)
         
     | 
| 
      
 131 
     | 
    
         
            +
                  raw_packets << packet.data
         
     | 
| 
      
 132 
     | 
    
         
            +
                  ts = Time.at(packet.time, packet.microsec.to_r, :usec)
         
     | 
| 
      
 133 
     | 
    
         
            +
                  timestamps << ts
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
       124 
135 
     | 
    
         
             
                  if @parse
         
     | 
| 
       125 
136 
     | 
    
         
             
                    begin
         
     | 
| 
       126 
     | 
    
         
            -
                      packet = Packet.parse(data)
         
     | 
| 
      
 137 
     | 
    
         
            +
                      packet = Packet.parse(packet.data)
         
     | 
| 
       127 
138 
     | 
    
         
             
                    rescue ParseError
         
     | 
| 
       128 
     | 
    
         
            -
                      packet = UnknownPacket.new.parse(data)
         
     | 
| 
      
 139 
     | 
    
         
            +
                      packet = UnknownPacket.new.parse(packet.data)
         
     | 
| 
       129 
140 
     | 
    
         
             
                    end
         
     | 
| 
       130 
141 
     | 
    
         
             
                    packets << packet
         
     | 
| 
       131 
     | 
    
         
            -
                    block&.call(packet)
         
     | 
| 
      
 142 
     | 
    
         
            +
                    block&.call(packet, ts)
         
     | 
| 
       132 
143 
     | 
    
         
             
                  elsif block
         
     | 
| 
       133 
     | 
    
         
            -
                    yield data
         
     | 
| 
      
 144 
     | 
    
         
            +
                    yield data, ts
         
     | 
| 
       134 
145 
     | 
    
         
             
                  end
         
     | 
| 
       135 
146 
     | 
    
         
             
                end
         
     | 
| 
       136 
147 
     | 
    
         
             
              end
         
     | 
| 
         @@ -67,9 +67,9 @@ module PacketGen 
     | 
|
| 
       67 
67 
     | 
    
         
             
                          @pointer = str[start, 2]
         
     | 
| 
       68 
68 
     | 
    
         
             
                          break
         
     | 
| 
       69 
69 
     | 
    
         
             
                        else
         
     | 
| 
       70 
     | 
    
         
            -
                          label = add_label_from(str[start 
     | 
| 
      
 70 
     | 
    
         
            +
                          label = add_label_from(str[start..])
         
     | 
| 
       71 
71 
     | 
    
         
             
                          start += label.sz
         
     | 
| 
       72 
     | 
    
         
            -
                          break if label. 
     | 
| 
      
 72 
     | 
    
         
            +
                          break if label.empty? || str[start..].empty?
         
     | 
| 
       73 
73 
     | 
    
         
             
                        end
         
     | 
| 
       74 
74 
     | 
    
         
             
                      end
         
     | 
| 
       75 
75 
     | 
    
         
             
                      # force resolution of compressed names
         
     | 
| 
         @@ -110,7 +110,7 @@ module PacketGen 
     | 
|
| 
       110 
110 
     | 
    
         
             
                      ptr = index & mask
         
     | 
| 
       111 
111 
     | 
    
         
             
                      name = Name.new
         
     | 
| 
       112 
112 
     | 
    
         
             
                      name.dns = @dns
         
     | 
| 
       113 
     | 
    
         
            -
                      @pointer_name = name.read(self.dns.to_s[ptr 
     | 
| 
      
 113 
     | 
    
         
            +
                      @pointer_name = name.read(self.dns.to_s[ptr..]).to_human
         
     | 
| 
       114 
114 
     | 
    
         
             
                    end
         
     | 
| 
       115 
115 
     | 
    
         | 
| 
       116 
116 
     | 
    
         
             
                    def record_from_hash(_hsh)
         
     | 
| 
         @@ -108,7 +108,7 @@ module PacketGen 
     | 
|
| 
       108 
108 
     | 
    
         
             
                      name.dns = self[:name].dns
         
     | 
| 
       109 
109 
     | 
    
         | 
| 
       110 
110 
     | 
    
         
             
                      pref = Types::Int16.new.read(self[:rdata][0, 2])
         
     | 
| 
       111 
     | 
    
         
            -
                      exchange = name.read(self[:rdata][2 
     | 
| 
      
 111 
     | 
    
         
            +
                      exchange = name.read(self[:rdata][2..]).to_human
         
     | 
| 
       112 
112 
     | 
    
         | 
| 
       113 
113 
     | 
    
         
             
                      '%u %s' % [pref.to_i, exchange]
         
     | 
| 
       114 
114 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -118,7 +118,7 @@ module PacketGen 
     | 
|
| 
       118 
118 
     | 
    
         
             
                      name = Name.new
         
     | 
| 
       119 
119 
     | 
    
         
             
                      name.dns = self[:name].dns
         
     | 
| 
       120 
120 
     | 
    
         
             
                      mname = name.read(self[:rdata]).dup
         
     | 
| 
       121 
     | 
    
         
            -
                      rname = name.read(self[:rdata][mname.sz 
     | 
| 
      
 121 
     | 
    
         
            +
                      rname = name.read(self[:rdata][mname.sz..])
         
     | 
| 
       122 
122 
     | 
    
         | 
| 
       123 
123 
     | 
    
         
             
                      serial = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz, 4])
         
     | 
| 
       124 
124 
     | 
    
         
             
                      refresh = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz + 4, 4])
         
     | 
| 
         @@ -34,13 +34,28 @@ module PacketGen 
     | 
|
| 
       34 
34 
     | 
    
         | 
| 
       35 
35 
     | 
    
         
             
                          k, v = h.split(':', 2)
         
     | 
| 
       36 
36 
     | 
    
         
             
                          [k, v.strip]
         
     | 
| 
       37 
     | 
    
         
            -
                        end. 
     | 
| 
      
 37 
     | 
    
         
            +
                        end.compact.to_h
         
     | 
| 
       38 
38 
     | 
    
         
             
                      when Hash
         
     | 
| 
       39 
39 
     | 
    
         
             
                        @data = s_or_h
         
     | 
| 
       40 
40 
     | 
    
         
             
                      end
         
     | 
| 
       41 
41 
     | 
    
         
             
                      self
         
     | 
| 
       42 
42 
     | 
    
         
             
                    end
         
     | 
| 
       43 
43 
     | 
    
         | 
| 
      
 44 
     | 
    
         
            +
                    # Get header value from its name
         
     | 
| 
      
 45 
     | 
    
         
            +
                    # @param [String] header header name
         
     | 
| 
      
 46 
     | 
    
         
            +
                    # @return [String] header value
         
     | 
| 
      
 47 
     | 
    
         
            +
                    def [](header)
         
     | 
| 
      
 48 
     | 
    
         
            +
                      data[header]
         
     | 
| 
      
 49 
     | 
    
         
            +
                    end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                    # Say if +self+ include +header+ header
         
     | 
| 
      
 52 
     | 
    
         
            +
                    # @param [String] header header name
         
     | 
| 
      
 53 
     | 
    
         
            +
                    # @return [Boolean]
         
     | 
| 
      
 54 
     | 
    
         
            +
                    def header?(header)
         
     | 
| 
      
 55 
     | 
    
         
            +
                      data.key?(header)
         
     | 
| 
      
 56 
     | 
    
         
            +
                    end
         
     | 
| 
      
 57 
     | 
    
         
            +
                    alias has_header? header?
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
       44 
59 
     | 
    
         
             
                    # Get binary string.
         
     | 
| 
       45 
60 
     | 
    
         
             
                    # @return [String]
         
     | 
| 
       46 
61 
     | 
    
         
             
                    def to_s
         
     | 
| 
         @@ -107,7 +107,7 @@ module PacketGen 
     | 
|
| 
       107 
107 
     | 
    
         | 
| 
       108 
108 
     | 
    
         
             
                    def headers_and_payload_from_lines(lines)
         
     | 
| 
       109 
109 
     | 
    
         
             
                      if (data_index = lines.find_index(''))
         
     | 
| 
       110 
     | 
    
         
            -
                        data    = lines[data_index + 1 
     | 
| 
      
 110 
     | 
    
         
            +
                        data    = lines[data_index + 1..].join("\n")
         
     | 
| 
       111 
111 
     | 
    
         
             
                        headers = lines[0..data_index - 1].join("\n")
         
     | 
| 
       112 
112 
     | 
    
         
             
                      else
         
     | 
| 
       113 
113 
     | 
    
         
             
                        headers = lines.join("\n")
         
     | 
| 
         @@ -126,7 +126,7 @@ module PacketGen 
     | 
|
| 
       126 
126 
     | 
    
         | 
| 
       127 
127 
     | 
    
         
             
                      self[:version].read first_line[0]
         
     | 
| 
       128 
128 
     | 
    
         
             
                      self[:status_code].read first_line[1]
         
     | 
| 
       129 
     | 
    
         
            -
                      self[:status_mesg].read first_line[2 
     | 
| 
      
 129 
     | 
    
         
            +
                      self[:status_mesg].read first_line[2..].join(' ')
         
     | 
| 
       130 
130 
     | 
    
         
             
                    end
         
     | 
| 
       131 
131 
     | 
    
         | 
| 
       132 
132 
     | 
    
         
             
                    def raise_on_bad_version_status
         
     | 
| 
         @@ -18,7 +18,7 @@ module PacketGen 
     | 
|
| 
       18 
18 
     | 
    
         
             
                    # @return [self]
         
     | 
| 
       19 
19 
     | 
    
         
             
                    #   array << '192.168.1.12'
         
     | 
| 
       20 
20 
     | 
    
         
             
                    def push(addr)
         
     | 
| 
       21 
     | 
    
         
            -
                      addr =  
     | 
| 
      
 21 
     | 
    
         
            +
                      addr = Addr.new.from_human(addr) unless addr.is_a?(Addr)
         
     | 
| 
       22 
22 
     | 
    
         
             
                      super(addr)
         
     | 
| 
       23 
23 
     | 
    
         
             
                    end
         
     | 
| 
       24 
24 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -77,7 +77,7 @@ module PacketGen 
     | 
|
| 
       77 
77 
     | 
    
         
             
                      Option.constants.each do |cst|
         
     | 
| 
       78 
78 
     | 
    
         
             
                        next unless cst.to_s.end_with? '_TYPE'
         
     | 
| 
       79 
79 
     | 
    
         | 
| 
       80 
     | 
    
         
            -
                        optname = cst.to_s.sub( 
     | 
| 
      
 80 
     | 
    
         
            +
                        optname = cst.to_s.sub('_TYPE', '')
         
     | 
| 
       81 
81 
     | 
    
         
             
                        @types[optname] = Option.const_get(cst)
         
     | 
| 
       82 
82 
     | 
    
         
             
                      end
         
     | 
| 
       83 
83 
     | 
    
         
             
                      @types
         
     | 
| 
         @@ -86,25 +86,23 @@ module PacketGen 
     | 
|
| 
       86 
86 
     | 
    
         
             
                    # Factory to build an option from its type
         
     | 
| 
       87 
87 
     | 
    
         
             
                    # @return [Option]
         
     | 
| 
       88 
88 
     | 
    
         
             
                    def self.build(options={})
         
     | 
| 
       89 
     | 
    
         
            -
                      type = options 
     | 
| 
      
 89 
     | 
    
         
            +
                      type = options[:type]
         
     | 
| 
       90 
90 
     | 
    
         
             
                      klass = case type
         
     | 
| 
       91 
91 
     | 
    
         
             
                              when String
         
     | 
| 
       92 
92 
     | 
    
         
             
                                types.key?(type) ? IP.const_get(type) : self
         
     | 
| 
       93 
     | 
    
         
            -
                              when Integer
         
     | 
| 
       94 
     | 
    
         
            -
                                types.value?(type) ? IP.const_get(types.key(type)) : self
         
     | 
| 
       95 
93 
     | 
    
         
             
                              else
         
     | 
| 
       96 
     | 
    
         
            -
                                self
         
     | 
| 
      
 94 
     | 
    
         
            +
                                types.value?(type) ? IP.const_get(types.key(type.to_i)) : self
         
     | 
| 
       97 
95 
     | 
    
         
             
                              end
         
     | 
| 
      
 96 
     | 
    
         
            +
                      options.delete(:type) if klass != self
         
     | 
| 
       98 
97 
     | 
    
         
             
                      klass.new(options)
         
     | 
| 
       99 
98 
     | 
    
         
             
                    end
         
     | 
| 
       100 
99 
     | 
    
         | 
| 
       101 
100 
     | 
    
         
             
                    def initialize(options={})
         
     | 
| 
       102 
     | 
    
         
            -
                      unless options[:type]
         
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
                        options[:type] = Option.const_get("#{opt_name}_TYPE") if Option.const_defined? "#{opt_name}_TYPE"
         
     | 
| 
       105 
     | 
    
         
            -
                      end
         
     | 
| 
      
 101 
     | 
    
         
            +
                      options[:type] = class2type unless options[:type]
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
       106 
103 
     | 
    
         
             
                      super
         
     | 
| 
       107 
     | 
    
         
            -
                       
     | 
| 
      
 104 
     | 
    
         
            +
                      initialize_length_if_needed(options)
         
     | 
| 
      
 105 
     | 
    
         
            +
                      initialize_data_if_needed(options)
         
     | 
| 
       108 
106 
     | 
    
         
             
                    end
         
     | 
| 
       109 
107 
     | 
    
         | 
| 
       110 
108 
     | 
    
         
             
                    # Get binary string. Set {#length} field.
         
     | 
| 
         @@ -121,6 +119,25 @@ module PacketGen 
     | 
|
| 
       121 
119 
     | 
    
         
             
                      str << ":#{self[:data].to_s.inspect}" if respond_to?(:length) && (length > 2) && !self[:data].to_s.empty?
         
     | 
| 
       122 
120 
     | 
    
         
             
                      str
         
     | 
| 
       123 
121 
     | 
    
         
             
                    end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                    private
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                    def class2type
         
     | 
| 
      
 126 
     | 
    
         
            +
                      opt_name = self.class.to_s.gsub(/.*::/, '')
         
     | 
| 
      
 127 
     | 
    
         
            +
                      Option.const_get("#{opt_name}_TYPE") if Option.const_defined? "#{opt_name}_TYPE"
         
     | 
| 
      
 128 
     | 
    
         
            +
                    end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                    def initialize_length_if_needed(options)
         
     | 
| 
      
 131 
     | 
    
         
            +
                      self.length = sz if respond_to?(:length) && options[:length].nil?
         
     | 
| 
      
 132 
     | 
    
         
            +
                    end
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                    def initialize_data_if_needed(options)
         
     | 
| 
      
 135 
     | 
    
         
            +
                      return unless fields.include?(:data) && self[:data].respond_to?(:from_human) && options.key?(:data)
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                      # Force data if data is set in options but not length
         
     | 
| 
      
 138 
     | 
    
         
            +
                      self.length += options[:data].size
         
     | 
| 
      
 139 
     | 
    
         
            +
                      self[:data].from_human(options[:data])
         
     | 
| 
      
 140 
     | 
    
         
            +
                    end
         
     | 
| 
       124 
141 
     | 
    
         
             
                  end
         
     | 
| 
       125 
142 
     | 
    
         | 
| 
       126 
143 
     | 
    
         
             
                  # End-of-option-List IP option
         
     | 
| 
         @@ -173,6 +190,10 @@ module PacketGen 
     | 
|
| 
       173 
190 
     | 
    
         
             
                    #  16-bit stream ID
         
     | 
| 
       174 
191 
     | 
    
         
             
                    #  @return [Integer]
         
     | 
| 
       175 
192 
     | 
    
         
             
                    define_field :id, Types::Int16
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
                    def to_human
         
     | 
| 
      
 195 
     | 
    
         
            +
                      super << ":#{self.id}"
         
     | 
| 
      
 196 
     | 
    
         
            +
                    end
         
     | 
| 
       176 
197 
     | 
    
         
             
                  end
         
     | 
| 
       177 
198 
     | 
    
         | 
| 
       178 
199 
     | 
    
         
             
                  # Router Alert IP option
         
     | 
| 
         @@ -183,6 +204,10 @@ module PacketGen 
     | 
|
| 
       183 
204 
     | 
    
         
             
                    #  16-bit value. Should be 0.
         
     | 
| 
       184 
205 
     | 
    
         
             
                    #  @return [Integer]
         
     | 
| 
       185 
206 
     | 
    
         
             
                    define_field :value, Types::Int16, default: 0
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
                    def to_human
         
     | 
| 
      
 209 
     | 
    
         
            +
                      super << ":#{self.value}"
         
     | 
| 
      
 210 
     | 
    
         
            +
                    end
         
     | 
| 
       186 
211 
     | 
    
         
             
                  end
         
     | 
| 
       187 
212 
     | 
    
         
             
                end
         
     | 
| 
       188 
213 
     | 
    
         
             
              end
         
     | 
| 
         @@ -74,6 +74,18 @@ module PacketGen 
     | 
|
| 
       74 
74 
     | 
    
         
             
                  # @author Sylvain Daubert
         
     | 
| 
       75 
75 
     | 
    
         
             
                  class VariableBindings < RASN1::Model
         
     | 
| 
       76 
76 
     | 
    
         
             
                    sequence_of :bindings, VarBind
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                    # Get 'idx'th element from the list
         
     | 
| 
      
 79 
     | 
    
         
            +
                    # @return [VarBind,nil]
         
     | 
| 
      
 80 
     | 
    
         
            +
                    def [](idx)
         
     | 
| 
      
 81 
     | 
    
         
            +
                      value[idx]
         
     | 
| 
      
 82 
     | 
    
         
            +
                    end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                    # Get element counts in list
         
     | 
| 
      
 85 
     | 
    
         
            +
                    # @return [Integer]
         
     | 
| 
      
 86 
     | 
    
         
            +
                    def size
         
     | 
| 
      
 87 
     | 
    
         
            +
                      value.size
         
     | 
| 
      
 88 
     | 
    
         
            +
                    end
         
     | 
| 
       77 
89 
     | 
    
         
             
                  end
         
     | 
| 
       78 
90 
     | 
    
         | 
| 
       79 
91 
     | 
    
         
             
                  # Class to handle GetRequest PDU
         
     | 
| 
         @@ -119,6 +131,10 @@ module PacketGen 
     | 
|
| 
       119 
131 
     | 
    
         
             
                                       integer(:error, value: 0, enum: ERRORS),
         
     | 
| 
       120 
132 
     | 
    
         
             
                                       integer(:error_index, value: 0),
         
     | 
| 
       121 
133 
     | 
    
         
             
                                       model(:varbindlist, VariableBindings)]
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                    def initialize(args={})
         
     | 
| 
      
 136 
     | 
    
         
            +
                      super
         
     | 
| 
      
 137 
     | 
    
         
            +
                    end
         
     | 
| 
       122 
138 
     | 
    
         
             
                  end
         
     | 
| 
       123 
139 
     | 
    
         | 
| 
       124 
140 
     | 
    
         
             
                  # Class to handle GetNextRequest PDU
         
     | 
| 
         @@ -264,11 +280,12 @@ module PacketGen 
     | 
|
| 
       264 
280 
     | 
    
         
             
                    data.chosen = options[:chosen_pdu] if options[:chosen_pdu]
         
     | 
| 
       265 
281 
     | 
    
         
             
                    return unless options[:pdu]
         
     | 
| 
       266 
282 
     | 
    
         | 
| 
       267 
     | 
    
         
            -
                     
     | 
| 
      
 283 
     | 
    
         
            +
                    klass = data.root.chosen_value.class
         
     | 
| 
      
 284 
     | 
    
         
            +
                    data.root.value[data.chosen] = klass.new(options[:pdu])
         
     | 
| 
       268 
285 
     | 
    
         
             
                  end
         
     | 
| 
       269 
286 
     | 
    
         | 
| 
       270 
287 
     | 
    
         
             
                  # accessor to data payload
         
     | 
| 
       271 
     | 
    
         
            -
                  # @return [ 
     | 
| 
      
 288 
     | 
    
         
            +
                  # @return [ASN1::Types::Choice]
         
     | 
| 
       272 
289 
     | 
    
         
             
                  def data
         
     | 
| 
       273 
290 
     | 
    
         
             
                    @elements[:data]
         
     | 
| 
       274 
291 
     | 
    
         
             
                  end
         
     | 
    
        data/lib/packetgen/headerable.rb
    CHANGED
    
    | 
         @@ -46,7 +46,7 @@ module PacketGen 
     | 
|
| 
       46 
46 
     | 
    
         
             
                def method_name
         
     | 
| 
       47 
47 
     | 
    
         
             
                  return @method_name if defined? @method_name
         
     | 
| 
       48 
48 
     | 
    
         | 
| 
       49 
     | 
    
         
            -
                  @method_name = protocol_name.downcase.gsub( 
     | 
| 
      
 49 
     | 
    
         
            +
                  @method_name = protocol_name.downcase.gsub('::', '_')
         
     | 
| 
       50 
50 
     | 
    
         
             
                end
         
     | 
| 
       51 
51 
     | 
    
         | 
| 
       52 
52 
     | 
    
         
             
                # @abstract Should be redefined by subclasses. This method should check invariant
         
     | 
    
        data/lib/packetgen/inspect.rb
    CHANGED
    
    | 
         @@ -36,7 +36,8 @@ module PacketGen 
     | 
|
| 
       36 
36 
     | 
    
         
             
                # @param [Integer] hexsize
         
     | 
| 
       37 
37 
     | 
    
         
             
                # @return [String]
         
     | 
| 
       38 
38 
     | 
    
         
             
                def self.int_dec_hex(value, hexsize)
         
     | 
| 
       39 
     | 
    
         
            -
                  "%-16s (0x%0#{hexsize}x)" 
     | 
| 
      
 39 
     | 
    
         
            +
                  fmt = "%-16s (0x%0#{hexsize}x)"
         
     | 
| 
      
 40 
     | 
    
         
            +
                  fmt % [value.to_i, value.to_i]
         
     | 
| 
       40 
41 
     | 
    
         
             
                end
         
     | 
| 
       41 
42 
     | 
    
         | 
| 
       42 
43 
     | 
    
         
             
                # @param [String] str
         
     | 
| 
         @@ -44,7 +45,8 @@ module PacketGen 
     | 
|
| 
       44 
45 
     | 
    
         
             
                # @param [Integer] hexsize
         
     | 
| 
       45 
46 
     | 
    
         
             
                # @return [String]
         
     | 
| 
       46 
47 
     | 
    
         
             
                def self.enum_human_hex(str, int, hexsize)
         
     | 
| 
       47 
     | 
    
         
            -
                  "%-16s (0x%0#{hexsize}x)" 
     | 
| 
      
 48 
     | 
    
         
            +
                  fmt = "%-16s (0x%0#{hexsize}x)"
         
     | 
| 
      
 49 
     | 
    
         
            +
                  fmt % [str, int]
         
     | 
| 
       48 
50 
     | 
    
         
             
                end
         
     | 
| 
       49 
51 
     | 
    
         | 
| 
       50 
52 
     | 
    
         
             
                # Simple formatter to inspect an attribute
         
     | 
| 
         @@ -90,7 +92,8 @@ module PacketGen 
     | 
|
| 
       90 
92 
     | 
    
         
             
                  val = case attr
         
     | 
| 
       91 
93 
     | 
    
         
             
                        when RASN1::Types::Enumerated
         
     | 
| 
       92 
94 
     | 
    
         
             
                          hexsize = attr.value_size * 2
         
     | 
| 
       93 
     | 
    
         
            -
                          "%-16s (0x%0#{hexsize}x)" 
     | 
| 
      
 95 
     | 
    
         
            +
                          fmt = "%-16s (0x%0#{hexsize}x)"
         
     | 
| 
      
 96 
     | 
    
         
            +
                          fmt % [attr.value, attr.to_i]
         
     | 
| 
       94 
97 
     | 
    
         
             
                        when RASN1::Types::Integer
         
     | 
| 
       95 
98 
     | 
    
         
             
                          int_dec_hex(attr.value, attr.value_size * 2)
         
     | 
| 
       96 
99 
     | 
    
         
             
                        when RASN1::Model
         
     | 
    
        data/lib/packetgen/packet.rb
    CHANGED
    
    | 
         @@ -81,7 +81,9 @@ module PacketGen 
     | 
|
| 
       81 
81 
     | 
    
         
             
                # @see Capture#initialize
         
     | 
| 
       82 
82 
     | 
    
         
             
                # @yieldparam [Packet,String] packet if a block is given, yield each
         
     | 
| 
       83 
83 
     | 
    
         
             
                #    captured packet (Packet or raw data String, depending on +:parse+ option)
         
     | 
| 
      
 84 
     | 
    
         
            +
                # @yieldparam [Time] timestamp packet timestamp
         
     | 
| 
       84 
85 
     | 
    
         
             
                # @return [Array<Packet>] captured packet
         
     | 
| 
      
 86 
     | 
    
         
            +
                # @since 3.3.0 add packet timestamp as second yield parameter
         
     | 
| 
       85 
87 
     | 
    
         
             
                def self.capture(**kwargs, &block)
         
     | 
| 
       86 
88 
     | 
    
         
             
                  capture = Capture.new(**kwargs)
         
     | 
| 
       87 
89 
     | 
    
         
             
                  if block
         
     | 
| 
         @@ -21,11 +21,11 @@ module PacketGen 
     | 
|
| 
       21 
21 
     | 
    
         
             
                  }.freeze
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
                  # @private
         
     | 
| 
       24 
     | 
    
         
            -
                  BLOCK_TYPES = PcapNG.constants(false).select { |c| c.to_s.include?('_TYPE') }. 
     | 
| 
      
 24 
     | 
    
         
            +
                  BLOCK_TYPES = PcapNG.constants(false).select { |c| c.to_s.include?('_TYPE') }.to_h do |c|
         
     | 
| 
       25 
25 
     | 
    
         
             
                    type_value = PcapNG.const_get(c).to_i
         
     | 
| 
       26 
26 
     | 
    
         
             
                    klass = PcapNG.const_get(c.to_s.delete_suffix('_TYPE'))
         
     | 
| 
       27 
27 
     | 
    
         
             
                    [type_value, klass]
         
     | 
| 
       28 
     | 
    
         
            -
                  end. 
     | 
| 
      
 28 
     | 
    
         
            +
                  end.freeze
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
                  # Get file sections
         
     | 
| 
       31 
31 
     | 
    
         
             
                  # @return [Array]
         
     | 
| 
         @@ -44,7 +44,7 @@ module PacketGen 
     | 
|
| 
       44 
44 
     | 
    
         
             
                # @param [Boolean] promisc
         
     | 
| 
       45 
45 
     | 
    
         
             
                # @param [String] filter BPF filter
         
     | 
| 
       46 
46 
     | 
    
         
             
                # @param [Boolean] monitor
         
     | 
| 
       47 
     | 
    
         
            -
                # @yieldparam [String] packet_data  
     | 
| 
      
 47 
     | 
    
         
            +
                # @yieldparam [String] packet_data packet data
         
     | 
| 
       48 
48 
     | 
    
         
             
                # @return [void]
         
     | 
| 
       49 
49 
     | 
    
         
             
                # @author Sylvain Daubert
         
     | 
| 
       50 
50 
     | 
    
         
             
                # @author optix2000 - add support for setting monitor mode
         
     | 
| 
         @@ -52,7 +52,7 @@ module PacketGen 
     | 
|
| 
       52 
52 
     | 
    
         
             
                def self.capture(iface:, snaplen: DEFAULT_SNAPLEN, promisc: DEFAULT_PROMISC, filter: nil, monitor: nil, &block)
         
     | 
| 
       53 
53 
     | 
    
         
             
                  pcap = self.open_iface(iface: iface, snaplen: snaplen, promisc: promisc, monitor: monitor)
         
     | 
| 
       54 
54 
     | 
    
         
             
                  pcap.setfilter filter unless filter.nil?
         
     | 
| 
       55 
     | 
    
         
            -
                  pcap. 
     | 
| 
      
 55 
     | 
    
         
            +
                  pcap.each_packet(&block)
         
     | 
| 
       56 
56 
     | 
    
         
             
                end
         
     | 
| 
       57 
57 
     | 
    
         | 
| 
       58 
58 
     | 
    
         
             
                # Inject given data onto wire
         
     | 
    
        data/lib/packetgen/proto.rb
    CHANGED
    
    | 
         @@ -19,7 +19,7 @@ module PacketGen 
     | 
|
| 
       19 
19 
     | 
    
         
             
                  proto_constants = Socket.constants.grep(/IPPROTO_/)
         
     | 
| 
       20 
20 
     | 
    
         
             
                  @cache = {}
         
     | 
| 
       21 
21 
     | 
    
         
             
                  proto_constants.each do |const_sym|
         
     | 
| 
       22 
     | 
    
         
            -
                    name = const_sym.to_s[8 
     | 
| 
      
 22 
     | 
    
         
            +
                    name = const_sym.to_s[8..].downcase
         
     | 
| 
       23 
23 
     | 
    
         
             
                    number = Socket.const_get(const_sym)
         
     | 
| 
       24 
24 
     | 
    
         
             
                    @cache[name] = number
         
     | 
| 
       25 
25 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -154,26 +154,19 @@ module PacketGen 
     | 
|
| 
       154 
154 
     | 
    
         
             
                    self
         
     | 
| 
       155 
155 
     | 
    
         
             
                  end
         
     | 
| 
       156 
156 
     | 
    
         | 
| 
       157 
     | 
    
         
            -
                  #  
     | 
| 
       158 
     | 
    
         
            -
             
     | 
| 
       159 
     | 
    
         
            -
                  # Populate object from a string
         
     | 
| 
       160 
     | 
    
         
            -
                  # @param [String] str
         
     | 
| 
      
 157 
     | 
    
         
            +
                  # Populate object from a string or from an array of hashes
         
     | 
| 
      
 158 
     | 
    
         
            +
                  # @param [String, Array<Hash>] data
         
     | 
| 
       161 
159 
     | 
    
         
             
                  # @return [self]
         
     | 
| 
       162 
     | 
    
         
            -
                  def read( 
     | 
| 
      
 160 
     | 
    
         
            +
                  def read(data)
         
     | 
| 
       163 
161 
     | 
    
         
             
                    clear
         
     | 
| 
       164 
     | 
    
         
            -
                     
     | 
| 
       165 
     | 
    
         
            -
                     
     | 
| 
       166 
     | 
    
         
            -
             
     | 
| 
       167 
     | 
    
         
            -
                     
     | 
| 
       168 
     | 
    
         
            -
             
     | 
| 
       169 
     | 
    
         
            -
                      obj = create_object_from_str(str)
         
     | 
| 
       170 
     | 
    
         
            -
                      @array << obj
         
     | 
| 
       171 
     | 
    
         
            -
                      str.slice!(0, obj.sz)
         
     | 
| 
       172 
     | 
    
         
            -
                      break if @counter && self.size == @counter.to_i
         
     | 
| 
      
 162 
     | 
    
         
            +
                    case data
         
     | 
| 
      
 163 
     | 
    
         
            +
                    when ::Array
         
     | 
| 
      
 164 
     | 
    
         
            +
                      read_from_array(data)
         
     | 
| 
      
 165 
     | 
    
         
            +
                    else
         
     | 
| 
      
 166 
     | 
    
         
            +
                      read_from_string(data)
         
     | 
| 
       173 
167 
     | 
    
         
             
                    end
         
     | 
| 
       174 
168 
     | 
    
         
             
                    self
         
     | 
| 
       175 
169 
     | 
    
         
             
                  end
         
     | 
| 
       176 
     | 
    
         
            -
                  # rubocop:enable Metrics/CyclomaticComplexity
         
     | 
| 
       177 
170 
     | 
    
         | 
| 
       178 
171 
     | 
    
         
             
                  # Get size in bytes
         
     | 
| 
       179 
172 
     | 
    
         
             
                  # @return [Integer]
         
     | 
| 
         @@ -201,6 +194,28 @@ module PacketGen 
     | 
|
| 
       201 
194 
     | 
    
         | 
| 
       202 
195 
     | 
    
         
             
                  private
         
     | 
| 
       203 
196 
     | 
    
         | 
| 
      
 197 
     | 
    
         
            +
                  # rubocop:disable Metrics/CyclomaticComplexity
         
     | 
| 
      
 198 
     | 
    
         
            +
             
     | 
| 
      
 199 
     | 
    
         
            +
                  def read_from_string(str)
         
     | 
| 
      
 200 
     | 
    
         
            +
                    return self if str.nil? || @counter&.to_i&.zero?
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
                    str = read_with_length_from(str)
         
     | 
| 
      
 203 
     | 
    
         
            +
                    until str.empty? || (@counter && self.size == @counter.to_i)
         
     | 
| 
      
 204 
     | 
    
         
            +
                      obj = create_object_from_str(str)
         
     | 
| 
      
 205 
     | 
    
         
            +
                      @array << obj
         
     | 
| 
      
 206 
     | 
    
         
            +
                      str.slice!(0, obj.sz)
         
     | 
| 
      
 207 
     | 
    
         
            +
                    end
         
     | 
| 
      
 208 
     | 
    
         
            +
                  end
         
     | 
| 
      
 209 
     | 
    
         
            +
                  # rubocop:enable Metrics/CyclomaticComplexity
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
                  def read_from_array(ary)
         
     | 
| 
      
 212 
     | 
    
         
            +
                    return self if ary.empty?
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
                    ary.each do |hsh|
         
     | 
| 
      
 215 
     | 
    
         
            +
                      self << hsh
         
     | 
| 
      
 216 
     | 
    
         
            +
                    end
         
     | 
| 
      
 217 
     | 
    
         
            +
                  end
         
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
       204 
219 
     | 
    
         
             
                  def record_from_hash(hsh)
         
     | 
| 
       205 
220 
     | 
    
         
             
                    obj_klass = self.class.set_of_klass
         
     | 
| 
       206 
221 
     | 
    
         
             
                    raise NotImplementedError, 'class should define #record_from_hash or declare type of elements in set with .set_of' unless obj_klass
         
     | 
| 
         @@ -322,12 +322,14 @@ module PacketGen 
     | 
|
| 
       322 
322 
     | 
    
         
             
                        define << "def #{name}; self[:#{name}].to_i; end"
         
     | 
| 
       323 
323 
     | 
    
         
             
                        define << "def #{name}=(val) self[:#{name}].value = val; end"
         
     | 
| 
       324 
324 
     | 
    
         
             
                      else
         
     | 
| 
      
 325 
     | 
    
         
            +
                        # rubocop:disable Layout/LineContinuationLeadingSpace
         
     | 
| 
       325 
326 
     | 
    
         
             
                        define << "def #{name}\n" \
         
     | 
| 
       326 
327 
     | 
    
         
             
                                  "  to_and_from_human?(:#{name}) ? self[:#{name}].to_human : self[:#{name}]\n" \
         
     | 
| 
       327 
328 
     | 
    
         
             
                                  'end'
         
     | 
| 
       328 
329 
     | 
    
         
             
                        define << "def #{name}=(val)\n" \
         
     | 
| 
       329 
330 
     | 
    
         
             
                                  "  to_and_from_human?(:#{name}) ? self[:#{name}].from_human(val) : self[:#{name}].read(val)\n" \
         
     | 
| 
       330 
331 
     | 
    
         
             
                                  'end'
         
     | 
| 
      
 332 
     | 
    
         
            +
                        # rubocop:enable Layout/LineContinuationLeadingSpace
         
     | 
| 
       331 
333 
     | 
    
         
             
                      end
         
     | 
| 
       332 
334 
     | 
    
         | 
| 
       333 
335 
     | 
    
         
             
                      define.delete_at(1) if instance_methods.include? "#{name}=".to_sym
         
     | 
| 
         @@ -479,7 +481,7 @@ module PacketGen 
     | 
|
| 
       479 
481 
     | 
    
         
             
                    fields.each do |field|
         
     | 
| 
       480 
482 
     | 
    
         
             
                      next unless present?(field)
         
     | 
| 
       481 
483 
     | 
    
         | 
| 
       482 
     | 
    
         
            -
                      obj = self[field].read str[start 
     | 
| 
      
 484 
     | 
    
         
            +
                      obj = self[field].read str[start..]
         
     | 
| 
       483 
485 
     | 
    
         
             
                      start += self[field].sz
         
     | 
| 
       484 
486 
     | 
    
         
             
                      self[field] = obj unless obj == self[field]
         
     | 
| 
       485 
487 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -523,7 +525,7 @@ module PacketGen 
     | 
|
| 
       523 
525 
     | 
    
         
             
                  # Return object as a hash
         
     | 
| 
       524 
526 
     | 
    
         
             
                  # @return [Hash] keys: attributes, values: attribute values
         
     | 
| 
       525 
527 
     | 
    
         
             
                  def to_h
         
     | 
| 
       526 
     | 
    
         
            -
                    fields. 
     | 
| 
      
 528 
     | 
    
         
            +
                    fields.to_h { |f| [f, @fields[f].to_human] }
         
     | 
| 
       527 
529 
     | 
    
         
             
                  end
         
     | 
| 
       528 
530 
     | 
    
         | 
| 
       529 
531 
     | 
    
         
             
                  # Get offset of given field in {Fields} structure.
         
     | 
| 
         @@ -61,7 +61,8 @@ module PacketGen 
     | 
|
| 
       61 
61 
     | 
    
         | 
| 
       62 
62 
     | 
    
         
             
                # @return [String]
         
     | 
| 
       63 
63 
     | 
    
         
             
                def inspect
         
     | 
| 
       64 
     | 
    
         
            -
                   
     | 
| 
      
 64 
     | 
    
         
            +
                  str = Inspect.dashed_line(self.class)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  str << Inspect.inspect_body(body)
         
     | 
| 
       65 
66 
     | 
    
         
             
                end
         
     | 
| 
       66 
67 
     | 
    
         | 
| 
       67 
68 
     | 
    
         
             
                # equality if {#to_s} is equal
         
     | 
| 
         @@ -74,7 +75,7 @@ module PacketGen 
     | 
|
| 
       74 
75 
     | 
    
         
             
                # @return [Boolean]
         
     | 
| 
       75 
76 
     | 
    
         
             
                def ===(other)
         
     | 
| 
       76 
77 
     | 
    
         
             
                  case other
         
     | 
| 
       77 
     | 
    
         
            -
                  when  
     | 
| 
      
 78 
     | 
    
         
            +
                  when UnknownPacket
         
     | 
| 
       78 
79 
     | 
    
         
             
                    self == other
         
     | 
| 
       79 
80 
     | 
    
         
             
                  else
         
     | 
| 
       80 
81 
     | 
    
         
             
                    false
         
     | 
| 
         @@ -112,9 +112,11 @@ module PacketGen 
     | 
|
| 
       112 
112 
     | 
    
         | 
| 
       113 
113 
     | 
    
         
             
                  # Say if spoofing on given target is active or not
         
     | 
| 
       114 
114 
     | 
    
         
             
                  # @param [String] target_ip target IP address
         
     | 
| 
       115 
     | 
    
         
            -
                  # @return [Boolean 
     | 
| 
      
 115 
     | 
    
         
            +
                  # @return [Boolean]
         
     | 
| 
       116 
116 
     | 
    
         
             
                  def active?(target_ip)
         
     | 
| 
      
 117 
     | 
    
         
            +
                    # rubocop:disable Style/ReturnNilInPredicateMethodDefinition
         
     | 
| 
       117 
118 
     | 
    
         
             
                    return unless @targets.key?(target_ip)
         
     | 
| 
      
 119 
     | 
    
         
            +
                    # rubocop:enable Style/ReturnNilInPredicateMethodDefinition
         
     | 
| 
       118 
120 
     | 
    
         | 
| 
       119 
121 
     | 
    
         
             
                    @targets[target_ip][:active]
         
     | 
| 
       120 
122 
     | 
    
         
             
                  end
         
     | 
    
        data/lib/packetgen/utils.rb
    CHANGED
    
    | 
         @@ -19,29 +19,38 @@ module PacketGen 
     | 
|
| 
       19 
19 
     | 
    
         
             
                # @private
         
     | 
| 
       20 
20 
     | 
    
         
             
                ARP_FILTER = 'arp src %<ipaddr>s and ether dst %<hwaddr>s'
         
     | 
| 
       21 
21 
     | 
    
         
             
                # @private
         
     | 
| 
       22 
     | 
    
         
            -
                MITM_FILTER = '((ip src %<target1>s and not ip dst %<local_ip>s) or' \
         
     | 
| 
       23 
     | 
    
         
            -
                              ' 
     | 
| 
       24 
     | 
    
         
            -
                              ' 
     | 
| 
       25 
     | 
    
         
            -
                              ' 
     | 
| 
       26 
     | 
    
         
            -
                              ' 
     | 
| 
      
 22 
     | 
    
         
            +
                MITM_FILTER = '((ip src %<target1>s and not ip dst %<local_ip>s) or ' \
         
     | 
| 
      
 23 
     | 
    
         
            +
                              '(ip src %<target2>s and not ip dst %<local_ip>s) or ' \
         
     | 
| 
      
 24 
     | 
    
         
            +
                              '(ip dst %<target1>s and not ip src %<local_ip>s) or ' \
         
     | 
| 
      
 25 
     | 
    
         
            +
                              '(ip dst %<target2>s and not ip src %<local_ip>s)) ' \
         
     | 
| 
      
 26 
     | 
    
         
            +
                              'and ether dst %<local_mac>s'
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 29 
     | 
    
         
            +
                ARP_PATH = '/usr/sbin/arp'
         
     | 
| 
      
 30 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 31 
     | 
    
         
            +
                IP_PATH = '/usr/bin/ip'
         
     | 
| 
      
 32 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 33 
     | 
    
         
            +
                ARP_LINE_RE = /\((\d+\.\d+\.\d+\.\d+)\) at (([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2})(?: \[ether\])? on (\w+)/.freeze
         
     | 
| 
      
 34 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 35 
     | 
    
         
            +
                IP_LINE_RE = /^(\d+\.\d+\.\d+\.\d+) dev (\w+) lladdr (([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2})/.freeze
         
     | 
| 
       27 
36 
     | 
    
         | 
| 
       28 
37 
     | 
    
         
             
                # Get local ARP cache
         
     | 
| 
       29 
38 
     | 
    
         
             
                # @return [Hash] key: IP address, value: array containing MAC address and
         
     | 
| 
       30 
39 
     | 
    
         
             
                #    interface name
         
     | 
| 
       31 
40 
     | 
    
         
             
                def self.arp_cache
         
     | 
| 
       32 
     | 
    
         
            -
                  return self.cache_from_arp_command if File.exist?( 
     | 
| 
       33 
     | 
    
         
            -
                  return self.cache_from_ip_command if File.exist?( 
     | 
| 
      
 41 
     | 
    
         
            +
                  return self.cache_from_arp_command if File.exist?(ARP_PATH)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  return self.cache_from_ip_command if File.exist?(IP_PATH)
         
     | 
| 
       34 
43 
     | 
    
         | 
| 
       35 
44 
     | 
    
         
             
                  {}
         
     | 
| 
       36 
45 
     | 
    
         
             
                end
         
     | 
| 
       37 
46 
     | 
    
         | 
| 
       38 
47 
     | 
    
         
             
                # @private
         
     | 
| 
       39 
     | 
    
         
            -
                def self.cache_from_arp_command
         
     | 
| 
       40 
     | 
    
         
            -
                  raw_cache  
     | 
| 
      
 48 
     | 
    
         
            +
                def self.cache_from_arp_command(raw_cache=nil)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  raw_cache ||= `#{ARP_PATH} -an`
         
     | 
| 
       41 
50 
     | 
    
         | 
| 
       42 
51 
     | 
    
         
             
                  cache = {}
         
     | 
| 
       43 
52 
     | 
    
         
             
                  raw_cache.split("\n").each do |line|
         
     | 
| 
       44 
     | 
    
         
            -
                    match = line.match( 
     | 
| 
      
 53 
     | 
    
         
            +
                    match = line.match(ARP_LINE_RE)
         
     | 
| 
       45 
54 
     | 
    
         
             
                    cache[match[1]] = [match[2], match[4]] if match
         
     | 
| 
       46 
55 
     | 
    
         
             
                  end
         
     | 
| 
       47 
56 
     | 
    
         | 
| 
         @@ -49,12 +58,12 @@ module PacketGen 
     | 
|
| 
       49 
58 
     | 
    
         
             
                end
         
     | 
| 
       50 
59 
     | 
    
         | 
| 
       51 
60 
     | 
    
         
             
                # @private
         
     | 
| 
       52 
     | 
    
         
            -
                def self.cache_from_ip_command
         
     | 
| 
       53 
     | 
    
         
            -
                  raw_cache  
     | 
| 
      
 61 
     | 
    
         
            +
                def self.cache_from_ip_command(raw_cache=nil)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  raw_cache ||= `#{IP_PATH} neigh`
         
     | 
| 
       54 
63 
     | 
    
         | 
| 
       55 
64 
     | 
    
         
             
                  cache = {}
         
     | 
| 
       56 
65 
     | 
    
         
             
                  raw_cache.split("\n").each do |line|
         
     | 
| 
       57 
     | 
    
         
            -
                    match = line.match( 
     | 
| 
      
 66 
     | 
    
         
            +
                    match = line.match(IP_LINE_RE)
         
     | 
| 
       58 
67 
     | 
    
         
             
                    cache[match[1]] = [match[3], match[2]] if match
         
     | 
| 
       59 
68 
     | 
    
         
             
                  end
         
     | 
| 
       60 
69 
     | 
    
         | 
| 
         @@ -155,7 +164,7 @@ module PacketGen 
     | 
|
| 
       155 
164 
     | 
    
         
             
                #   end
         
     | 
| 
       156 
165 
     | 
    
         
             
                # @since 2.2.0
         
     | 
| 
       157 
166 
     | 
    
         
             
                # @raise [RuntimeError] user don't have permission to capture packets on network device.
         
     | 
| 
       158 
     | 
    
         
            -
                def self.mitm(target1, target2, options={})
         
     | 
| 
      
 167 
     | 
    
         
            +
                def self.mitm(target1, target2, options={}, &block)
         
     | 
| 
       159 
168 
     | 
    
         
             
                  options = { iface: PacketGen.default_iface }.merge(options)
         
     | 
| 
       160 
169 
     | 
    
         | 
| 
       161 
170 
     | 
    
         
             
                  spoofer = Utils::ARPSpoofer.new(options)
         
     | 
| 
         @@ -168,7 +177,7 @@ module PacketGen 
     | 
|
| 
       168 
177 
     | 
    
         
             
                                        filter: MITM_FILTER % { target1: target1, target2: target2, local_ip: cfg.ipaddr(options[:iface]), local_mac: my_mac })
         
     | 
| 
       169 
178 
     | 
    
         | 
| 
       170 
179 
     | 
    
         
             
                  spoofer.start_all
         
     | 
| 
       171 
     | 
    
         
            -
                  mitm_core(capture, target1, target2, my_mac, & 
     | 
| 
      
 180 
     | 
    
         
            +
                  mitm_core(capture, target1, target2, my_mac, &block)
         
     | 
| 
       172 
181 
     | 
    
         
             
                  spoofer.stop_all
         
     | 
| 
       173 
182 
     | 
    
         
             
                end
         
     | 
| 
       174 
183 
     | 
    
         | 
    
        data/lib/packetgen/version.rb
    CHANGED
    
    
    
        data/lib/packetgen.rb
    CHANGED
    
    | 
         @@ -64,8 +64,10 @@ module PacketGen 
     | 
|
| 
       64 
64 
     | 
    
         
             
              # Shortcut for {Packet.capture}
         
     | 
| 
       65 
65 
     | 
    
         
             
              # Same arguments as {Capture#initialize}
         
     | 
| 
       66 
66 
     | 
    
         
             
              # @see Capture#initialize
         
     | 
| 
       67 
     | 
    
         
            -
              # @yieldparam [Packet] packet
         
     | 
| 
      
 67 
     | 
    
         
            +
              # @yieldparam [Packet,String] packet
         
     | 
| 
      
 68 
     | 
    
         
            +
              # @yieldparam [Time] timestamp
         
     | 
| 
       68 
69 
     | 
    
         
             
              # @return [Array<Packet>]
         
     | 
| 
      
 70 
     | 
    
         
            +
              # @since 3.3.0 add packet timestamp as second yield parameter
         
     | 
| 
       69 
71 
     | 
    
         
             
              def self.capture(**kwargs)
         
     | 
| 
       70 
72 
     | 
    
         
             
                Packet.capture(**kwargs) { |packet| yield packet if block_given? }
         
     | 
| 
       71 
73 
     | 
    
         
             
              end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: packetgen
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 3. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 3.3.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Sylvain Daubert
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date:  
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2023-08-11 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: interfacez
         
     | 
| 
         @@ -30,76 +30,28 @@ dependencies: 
     | 
|
| 
       30 
30 
     | 
    
         
             
                requirements:
         
     | 
| 
       31 
31 
     | 
    
         
             
                - - "~>"
         
     | 
| 
       32 
32 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       33 
     | 
    
         
            -
                    version: 0. 
     | 
| 
      
 33 
     | 
    
         
            +
                    version: 0.13.0
         
     | 
| 
       34 
34 
     | 
    
         
             
              type: :runtime
         
     | 
| 
       35 
35 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       36 
36 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       37 
37 
     | 
    
         
             
                requirements:
         
     | 
| 
       38 
38 
     | 
    
         
             
                - - "~>"
         
     | 
| 
       39 
39 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       40 
     | 
    
         
            -
                    version: 0. 
     | 
| 
      
 40 
     | 
    
         
            +
                    version: 0.13.0
         
     | 
| 
       41 
41 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       42 
42 
     | 
    
         
             
              name: rasn1
         
     | 
| 
       43 
43 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       44 
44 
     | 
    
         
             
                requirements:
         
     | 
| 
       45 
45 
     | 
    
         
             
                - - "~>"
         
     | 
| 
       46 
46 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       47 
     | 
    
         
            -
                    version: '0. 
     | 
| 
       48 
     | 
    
         
            -
                - - ">="
         
     | 
| 
       49 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       50 
     | 
    
         
            -
                    version: 0.8.0
         
     | 
| 
      
 47 
     | 
    
         
            +
                    version: '0.12'
         
     | 
| 
       51 
48 
     | 
    
         
             
              type: :runtime
         
     | 
| 
       52 
49 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       53 
50 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       54 
51 
     | 
    
         
             
                requirements:
         
     | 
| 
       55 
52 
     | 
    
         
             
                - - "~>"
         
     | 
| 
       56 
53 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       57 
     | 
    
         
            -
                    version: '0. 
     | 
| 
       58 
     | 
    
         
            -
                - - ">="
         
     | 
| 
       59 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       60 
     | 
    
         
            -
                    version: 0.8.0
         
     | 
| 
       61 
     | 
    
         
            -
            - !ruby/object:Gem::Dependency
         
     | 
| 
       62 
     | 
    
         
            -
              name: rake
         
     | 
| 
       63 
     | 
    
         
            -
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       64 
     | 
    
         
            -
                requirements:
         
     | 
| 
       65 
     | 
    
         
            -
                - - "~>"
         
     | 
| 
       66 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       67 
     | 
    
         
            -
                    version: '13.0'
         
     | 
| 
       68 
     | 
    
         
            -
              type: :development
         
     | 
| 
       69 
     | 
    
         
            -
              prerelease: false
         
     | 
| 
       70 
     | 
    
         
            -
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       71 
     | 
    
         
            -
                requirements:
         
     | 
| 
       72 
     | 
    
         
            -
                - - "~>"
         
     | 
| 
       73 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       74 
     | 
    
         
            -
                    version: '13.0'
         
     | 
| 
       75 
     | 
    
         
            -
            - !ruby/object:Gem::Dependency
         
     | 
| 
       76 
     | 
    
         
            -
              name: rspec
         
     | 
| 
       77 
     | 
    
         
            -
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       78 
     | 
    
         
            -
                requirements:
         
     | 
| 
       79 
     | 
    
         
            -
                - - "~>"
         
     | 
| 
       80 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       81 
     | 
    
         
            -
                    version: '3.7'
         
     | 
| 
       82 
     | 
    
         
            -
              type: :development
         
     | 
| 
       83 
     | 
    
         
            -
              prerelease: false
         
     | 
| 
       84 
     | 
    
         
            -
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       85 
     | 
    
         
            -
                requirements:
         
     | 
| 
       86 
     | 
    
         
            -
                - - "~>"
         
     | 
| 
       87 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       88 
     | 
    
         
            -
                    version: '3.7'
         
     | 
| 
       89 
     | 
    
         
            -
            - !ruby/object:Gem::Dependency
         
     | 
| 
       90 
     | 
    
         
            -
              name: yard
         
     | 
| 
       91 
     | 
    
         
            -
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       92 
     | 
    
         
            -
                requirements:
         
     | 
| 
       93 
     | 
    
         
            -
                - - "~>"
         
     | 
| 
       94 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       95 
     | 
    
         
            -
                    version: '0.9'
         
     | 
| 
       96 
     | 
    
         
            -
              type: :development
         
     | 
| 
       97 
     | 
    
         
            -
              prerelease: false
         
     | 
| 
       98 
     | 
    
         
            -
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       99 
     | 
    
         
            -
                requirements:
         
     | 
| 
       100 
     | 
    
         
            -
                - - "~>"
         
     | 
| 
       101 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       102 
     | 
    
         
            -
                    version: '0.9'
         
     | 
| 
      
 54 
     | 
    
         
            +
                    version: '0.12'
         
     | 
| 
       103 
55 
     | 
    
         
             
            description: |
         
     | 
| 
       104 
56 
     | 
    
         
             
              PacketGen is a network packet manipulation library. It allows reading, parsing
         
     | 
| 
       105 
57 
     | 
    
         
             
              and sending network packets with fun.
         
     | 
| 
         @@ -260,7 +212,7 @@ required_ruby_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       260 
212 
     | 
    
         
             
              requirements:
         
     | 
| 
       261 
213 
     | 
    
         
             
              - - ">="
         
     | 
| 
       262 
214 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       263 
     | 
    
         
            -
                  version: 2. 
     | 
| 
      
 215 
     | 
    
         
            +
                  version: 2.6.0
         
     | 
| 
       264 
216 
     | 
    
         
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
       265 
217 
     | 
    
         
             
              requirements:
         
     | 
| 
       266 
218 
     | 
    
         
             
              - - ">="
         
     |