packetgen 2.8.7 → 3.0.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/.rubocop.yml +0 -1
- data/README.md +5 -4
- data/lib/packetgen.rb +6 -12
- data/lib/packetgen/capture.rb +43 -39
- data/lib/packetgen/config.rb +0 -1
- data/lib/packetgen/deprecation.rb +1 -1
- data/lib/packetgen/header.rb +9 -9
- data/lib/packetgen/header/asn1_base.rb +10 -10
- data/lib/packetgen/header/base.rb +42 -101
- data/lib/packetgen/header/dhcp/option.rb +5 -11
- data/lib/packetgen/header/dhcpv6/duid.rb +2 -0
- data/lib/packetgen/header/dhcpv6/option.rb +2 -19
- data/lib/packetgen/header/dhcpv6/options.rb +7 -0
- data/lib/packetgen/header/dns.rb +5 -23
- data/lib/packetgen/header/dns/name.rb +1 -0
- data/lib/packetgen/header/dns/qdsection.rb +1 -0
- data/lib/packetgen/header/dns/question.rb +3 -7
- data/lib/packetgen/header/dns/rr.rb +3 -0
- data/lib/packetgen/header/dns/rrsection.rb +1 -0
- data/lib/packetgen/header/dot11.rb +1 -17
- data/lib/packetgen/header/dot1x.rb +1 -0
- data/lib/packetgen/header/eap.rb +4 -7
- data/lib/packetgen/header/eth.rb +2 -0
- data/lib/packetgen/header/http/headers.rb +3 -0
- data/lib/packetgen/header/http/request.rb +5 -4
- data/lib/packetgen/header/http/response.rb +5 -4
- data/lib/packetgen/header/icmp.rb +6 -0
- data/lib/packetgen/header/icmpv6.rb +6 -0
- data/lib/packetgen/header/igmpv3/mq.rb +2 -0
- data/lib/packetgen/header/ip.rb +32 -30
- data/lib/packetgen/header/ip/addr.rb +1 -0
- data/lib/packetgen/header/ip/option.rb +23 -20
- data/lib/packetgen/header/ip/options.rb +11 -24
- data/lib/packetgen/header/ipv6.rb +45 -34
- data/lib/packetgen/header/ipv6/addr.rb +2 -0
- data/lib/packetgen/header/ipv6/hop_by_hop.rb +7 -31
- data/lib/packetgen/header/mdns.rb +1 -0
- data/lib/packetgen/header/mldv2/mlq.rb +2 -0
- data/lib/packetgen/header/ospfv2/lsa.rb +15 -25
- data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +1 -1
- data/lib/packetgen/header/ospfv3/lsa.rb +8 -25
- data/lib/packetgen/header/snmp.rb +2 -0
- data/lib/packetgen/header/tcp.rb +23 -2
- data/lib/packetgen/header/tcp/option.rb +51 -52
- data/lib/packetgen/header/tcp/options.rb +17 -52
- data/lib/packetgen/header/tftp.rb +3 -0
- data/lib/packetgen/header/udp.rb +8 -0
- data/lib/packetgen/packet.rb +119 -102
- data/lib/packetgen/pcapng/block.rb +4 -10
- data/lib/packetgen/pcapng/epb.rb +4 -4
- data/lib/packetgen/pcapng/file.rb +7 -3
- data/lib/packetgen/pcapng/idb.rb +2 -2
- data/lib/packetgen/pcapng/shb.rb +3 -3
- data/lib/packetgen/pcapng/spb.rb +1 -8
- data/lib/packetgen/pcapng/unknown_block.rb +0 -7
- data/lib/packetgen/types.rb +1 -0
- data/lib/packetgen/types/array.rb +73 -71
- data/lib/packetgen/types/cstring.rb +1 -1
- data/lib/packetgen/types/enum.rb +3 -3
- data/lib/packetgen/types/fields.rb +66 -106
- data/lib/packetgen/types/int.rb +9 -5
- data/lib/packetgen/types/length_from.rb +45 -0
- data/lib/packetgen/types/oui.rb +2 -0
- data/lib/packetgen/types/string.rb +10 -16
- data/lib/packetgen/types/tlv.rb +7 -15
- data/lib/packetgen/utils.rb +8 -8
- data/lib/packetgen/utils/arp_spoofer.rb +1 -2
- data/lib/packetgen/version.rb +1 -1
- metadata +3 -21
- data/lib/packetgen/header/crypto.rb +0 -62
- data/lib/packetgen/header/esp.rb +0 -413
- data/lib/packetgen/header/ike.rb +0 -243
- data/lib/packetgen/header/ike/auth.rb +0 -165
- data/lib/packetgen/header/ike/cert.rb +0 -76
- data/lib/packetgen/header/ike/certreq.rb +0 -66
- data/lib/packetgen/header/ike/id.rb +0 -99
- data/lib/packetgen/header/ike/ke.rb +0 -79
- data/lib/packetgen/header/ike/nonce.rb +0 -40
- data/lib/packetgen/header/ike/notify.rb +0 -176
- data/lib/packetgen/header/ike/payload.rb +0 -315
- data/lib/packetgen/header/ike/sa.rb +0 -561
- data/lib/packetgen/header/ike/sk.rb +0 -261
- data/lib/packetgen/header/ike/ts.rb +0 -270
- data/lib/packetgen/header/ike/vendor_id.rb +0 -39
- data/lib/packetgen/header/netbios.rb +0 -20
- data/lib/packetgen/header/netbios/datagram.rb +0 -105
- data/lib/packetgen/header/netbios/name.rb +0 -67
- data/lib/packetgen/header/netbios/session.rb +0 -64
| @@ -74,6 +74,8 @@ module PacketGen | |
| 74 74 | 
             
                    #  @return [Integer]
         | 
| 75 75 | 
             
                    define_bit_fields_on :u8, :resv, 4, :flag_s, :qrv, 3
         | 
| 76 76 |  | 
| 77 | 
            +
                    undef qqic, qqic=
         | 
| 78 | 
            +
             | 
| 77 79 | 
             
                    # Get QQIC value
         | 
| 78 80 | 
             
                    # @note May return a different value from value previously set, as a
         | 
| 79 81 | 
             
                    #   float encoding is used to encode big values. See {IGMPv3.decode}.
         | 
    
        data/lib/packetgen/header/ip.rb
    CHANGED
    
    | @@ -9,6 +9,22 @@ require 'socket' | |
| 9 9 |  | 
| 10 10 | 
             
            module PacketGen
         | 
| 11 11 | 
             
              module Header
         | 
| 12 | 
            +
                # IP protocol ({https://tools.ietf.org/html/rfc791 RFC 791})
         | 
| 13 | 
            +
                #    0                   1                   2                   3
         | 
| 14 | 
            +
                #    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
         | 
| 15 | 
            +
                #   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         | 
| 16 | 
            +
                #   |Version|  IHL  |Type of Service|          Total Length         |
         | 
| 17 | 
            +
                #   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         | 
| 18 | 
            +
                #   |         Identification        |Flags|      Fragment Offset    |
         | 
| 19 | 
            +
                #   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         | 
| 20 | 
            +
                #   |  Time to Live |    Protocol   |         Header Checksum       |
         | 
| 21 | 
            +
                #   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         | 
| 22 | 
            +
                #   |                       Source Address                          |
         | 
| 23 | 
            +
                #   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         | 
| 24 | 
            +
                #   |                    Destination Address                        |
         | 
| 25 | 
            +
                #   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         | 
| 26 | 
            +
                #   |                    Options                    |    Padding    |
         | 
| 27 | 
            +
                #   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         | 
| 12 28 | 
             
                # A IP header consists of:
         | 
| 13 29 | 
             
                # * a first byte ({#u8} of {Types::Int8} type) composed of:
         | 
| 14 30 | 
             
                #   * a 4-bit {#version} field,
         | 
| @@ -24,7 +40,7 @@ module PacketGen | |
| 24 40 | 
             
                # * a {#checksum} field (+Int16+),
         | 
| 25 41 | 
             
                # * a source IP address ({#src}, {Addr} type),
         | 
| 26 42 | 
             
                # * a destination IP address ({#dst}, +Addr+ type),
         | 
| 27 | 
            -
                # * an optional {#options} field ({ | 
| 43 | 
            +
                # * an optional {#options} field ({Options} type),
         | 
| 28 44 | 
             
                # * and a {#body} ({Types::String} type).
         | 
| 29 45 | 
             
                #
         | 
| 30 46 | 
             
                # == Create a IP header
         | 
| @@ -61,6 +77,14 @@ module PacketGen | |
| 61 77 | 
             
                #  ip[:src]              # => PacketGen::Header::IP::Addr
         | 
| 62 78 | 
             
                #  ip.dst = '127.0.0.2'
         | 
| 63 79 | 
             
                #  ip.body.read 'this is a body'
         | 
| 80 | 
            +
                #
         | 
| 81 | 
            +
                # == Add IP options
         | 
| 82 | 
            +
                # IP has an {#options} attribute used to store datagram options.
         | 
| 83 | 
            +
                #  pkt = PacketGen.gen('IP')
         | 
| 84 | 
            +
                #  # add option from class
         | 
| 85 | 
            +
                #  pkt.ip.options << PacketGen::Header::IP::RA.new
         | 
| 86 | 
            +
                #  # or use a hash
         | 
| 87 | 
            +
                #  pkt.ip.options << { type: 'RR', data: ['192.168.16.4']}
         | 
| 64 88 | 
             
                # @author Sylvain Daubert
         | 
| 65 89 | 
             
                class IP < Base; end
         | 
| 66 90 |  | 
| @@ -84,7 +108,7 @@ module PacketGen | |
| 84 108 | 
             
                  define_field :length, Types::Int16, default: 20
         | 
| 85 109 | 
             
                  # @!attribute id
         | 
| 86 110 | 
             
                  #   @return [Integer] 16-bit ID
         | 
| 87 | 
            -
                  define_field :id, Types::Int16, default: ->( | 
| 111 | 
            +
                  define_field :id, Types::Int16, default: ->(_) { rand(65_535) }
         | 
| 88 112 | 
             
                  # @!attribute frag
         | 
| 89 113 | 
             
                  #   @return [Integer] 16-bit frag word
         | 
| 90 114 | 
             
                  define_field :frag, Types::Int16, default: 0
         | 
| @@ -106,7 +130,8 @@ module PacketGen | |
| 106 130 | 
             
                  # @!attribute options
         | 
| 107 131 | 
             
                  #  @since 2.2.0
         | 
| 108 132 | 
             
                  #  @return [Types::String]
         | 
| 109 | 
            -
                  define_field :options, Options, optional: ->(h) { h.ihl > 5 }
         | 
| 133 | 
            +
                  define_field :options, Options, optional: ->(h) { h.ihl > 5 },
         | 
| 134 | 
            +
                              builder: ->(h, t) { t.new(length_from: -> { (h.ihl - 5) * 4 }) }
         | 
| 110 135 | 
             
                  # @!attribute body
         | 
| 111 136 | 
             
                  #  @return [Types::String,Header::Base]
         | 
| 112 137 | 
             
                  define_field :body, Types::String
         | 
| @@ -164,31 +189,6 @@ module PacketGen | |
| 164 189 | 
             
                    checksum.zero? ? 0xffff : checksum
         | 
| 165 190 | 
             
                  end
         | 
| 166 191 |  | 
| 167 | 
            -
                  # Populate object from a binary string
         | 
| 168 | 
            -
                  # @param [String] str
         | 
| 169 | 
            -
                  # @return [Fields] self
         | 
| 170 | 
            -
                  def read(str)
         | 
| 171 | 
            -
                    return self if str.nil?
         | 
| 172 | 
            -
                    force_binary str
         | 
| 173 | 
            -
                    self[:u8].read str[0, 1]
         | 
| 174 | 
            -
                    self[:tos].read str[1, 1]
         | 
| 175 | 
            -
                    self[:length].read str[2, 2]
         | 
| 176 | 
            -
                    self[:id].read str[4, 2]
         | 
| 177 | 
            -
                    self[:frag].read str[6, 2]
         | 
| 178 | 
            -
                    self[:ttl].read str[8, 1]
         | 
| 179 | 
            -
                    self[:protocol].read str[9, 1]
         | 
| 180 | 
            -
                    self[:checksum].read str[10, 2]
         | 
| 181 | 
            -
                    self[:src].read str[12, 4]
         | 
| 182 | 
            -
                    self[:dst].read str[16, 4]
         | 
| 183 | 
            -
                    opt_size = 0
         | 
| 184 | 
            -
                    if self.ihl > 5
         | 
| 185 | 
            -
                      opt_size = (self.ihl - 5) * 4
         | 
| 186 | 
            -
                      self[:options].read str[20, opt_size]
         | 
| 187 | 
            -
                    end
         | 
| 188 | 
            -
                    self[:body].read str[20 + opt_size..-1]
         | 
| 189 | 
            -
                    self
         | 
| 190 | 
            -
                  end
         | 
| 191 | 
            -
             | 
| 192 192 | 
             
                  # Compute checksum and set +checksum+ field
         | 
| 193 193 | 
             
                  # @return [Integer]
         | 
| 194 194 | 
             
                  def calc_checksum
         | 
| @@ -207,10 +207,12 @@ module PacketGen | |
| 207 207 | 
             
                    self[:checksum].value = IP.reduce_checksum(checksum)
         | 
| 208 208 | 
             
                  end
         | 
| 209 209 |  | 
| 210 | 
            -
                  # Compute  | 
| 210 | 
            +
                  # Compute and set +length+ and +ihl+ field
         | 
| 211 211 | 
             
                  # @return [Integer]
         | 
| 212 | 
            +
                  # @since 3.0.0 add +ihl+ calculation
         | 
| 212 213 | 
             
                  def calc_length
         | 
| 213 214 | 
             
                    Base.calculate_and_set_length self
         | 
| 215 | 
            +
                    self.ihl = 5 + self[:options].sz / 4
         | 
| 214 216 | 
             
                  end
         | 
| 215 217 |  | 
| 216 218 | 
             
                  # Get IP part of pseudo header checksum.
         | 
| @@ -265,7 +267,7 @@ module PacketGen | |
| 265 267 | 
             
                  # Get binary string. Fixup IHL if needed (IP header has options, and IHL
         | 
| 266 268 | 
             
                  # was not set by user).
         | 
| 267 269 | 
             
                  def to_s
         | 
| 268 | 
            -
                    self.ihl = 5 + options.sz / 4 if self.ihl == 5
         | 
| 270 | 
            +
                    self.ihl = 5 + self[:options].sz / 4 if self.ihl == 5
         | 
| 269 271 | 
             
                    super
         | 
| 270 272 | 
             
                  end
         | 
| 271 273 |  | 
| @@ -70,15 +70,32 @@ module PacketGen | |
| 70 70 | 
             
                    # @return [Hash]
         | 
| 71 71 | 
             
                    def self.types
         | 
| 72 72 | 
             
                      return @types if defined? @types
         | 
| 73 | 
            +
             | 
| 73 74 | 
             
                      @types = {}
         | 
| 74 75 | 
             
                      Option.constants.each do |cst|
         | 
| 75 76 | 
             
                        next unless cst.to_s.end_with? '_TYPE'
         | 
| 77 | 
            +
             | 
| 76 78 | 
             
                        optname = cst.to_s.sub(/_TYPE/, '')
         | 
| 77 | 
            -
                        @types[ | 
| 79 | 
            +
                        @types[optname] = Option.const_get(cst)
         | 
| 78 80 | 
             
                      end
         | 
| 79 81 | 
             
                      @types
         | 
| 80 82 | 
             
                    end
         | 
| 81 83 |  | 
| 84 | 
            +
                    # Factory to build an option from its type
         | 
| 85 | 
            +
                    # @return [Option]
         | 
| 86 | 
            +
                    def Option.build(options={})
         | 
| 87 | 
            +
                      type = options.delete(:type)
         | 
| 88 | 
            +
                      klass = case type
         | 
| 89 | 
            +
                              when String
         | 
| 90 | 
            +
                                types.key?(type) ? IP.const_get(type) : self
         | 
| 91 | 
            +
                              when Integer
         | 
| 92 | 
            +
                                types.value?(type) ? IP.const_get(types.key(type)) : self
         | 
| 93 | 
            +
                              else
         | 
| 94 | 
            +
                                self
         | 
| 95 | 
            +
                              end
         | 
| 96 | 
            +
                      klass.new(options)
         | 
| 97 | 
            +
                    end
         | 
| 98 | 
            +
             | 
| 82 99 | 
             
                    def initialize(options={})
         | 
| 83 100 | 
             
                      unless options[:type]
         | 
| 84 101 | 
             
                        opt_name = self.class.to_s.gsub(/.*::/, '')
         | 
| @@ -87,6 +104,7 @@ module PacketGen | |
| 87 104 | 
             
                        end
         | 
| 88 105 | 
             
                      end
         | 
| 89 106 | 
             
                      super
         | 
| 107 | 
            +
                      self.length = sz if respond_to?(:length) && options[:length].nil?
         | 
| 90 108 | 
             
                    end
         | 
| 91 109 |  | 
| 92 110 | 
             
                    # Get binary string. Set {#length} field.
         | 
| @@ -99,7 +117,7 @@ module PacketGen | |
| 99 117 | 
             
                    # Get a human readable string
         | 
| 100 118 | 
             
                    # @return [String]
         | 
| 101 119 | 
             
                    def to_human
         | 
| 102 | 
            -
                      str = self.class == Option ? "unk-#{type}" : self.class.to_s.sub(/.*::/, '')
         | 
| 120 | 
            +
                      str = self.class == Option ? +"unk-#{type}" : self.class.to_s.sub(/.*::/, '')
         | 
| 103 121 | 
             
                      if respond_to?(:length) && (length > 2) && !self[:data].to_s.empty?
         | 
| 104 122 | 
             
                        str << ":#{self[:data].to_s.inspect}"
         | 
| 105 123 | 
             
                      end
         | 
| @@ -114,8 +132,7 @@ module PacketGen | |
| 114 132 | 
             
                  end
         | 
| 115 133 |  | 
| 116 134 | 
             
                  # No OPeration IP option
         | 
| 117 | 
            -
                  class NOP < EOL
         | 
| 118 | 
            -
                  end
         | 
| 135 | 
            +
                  class NOP < EOL; end
         | 
| 119 136 |  | 
| 120 137 | 
             
                  # Loose Source and Record Route IP option
         | 
| 121 138 | 
             
                  class LSRR < Option
         | 
| @@ -124,25 +141,11 @@ module PacketGen | |
| 124 141 | 
             
                    # @!attribute pointer
         | 
| 125 142 | 
             
                    #  8-bit pointer on next address
         | 
| 126 143 | 
             
                    #  @return [Integer]
         | 
| 127 | 
            -
                    define_field :pointer, Types::Int8
         | 
| 144 | 
            +
                    define_field :pointer, Types::Int8, default: 4
         | 
| 128 145 | 
             
                    # @!attribute data
         | 
| 129 146 | 
             
                    #  Array of IP addresses
         | 
| 130 147 | 
             
                    #  @return [Types::Array<IP::Addr>]
         | 
| 131 | 
            -
                    define_field :data, ArrayOfAddr,
         | 
| 132 | 
            -
                                 builder: ->(h, t) { t.new(length_from: -> { h.length - 2 }) }
         | 
| 133 | 
            -
             | 
| 134 | 
            -
                    # Populate object from a binary string
         | 
| 135 | 
            -
                    # @param [String] str
         | 
| 136 | 
            -
                    # @return [Fields] self
         | 
| 137 | 
            -
                    def read(str)
         | 
| 138 | 
            -
                      return self if str.nil?
         | 
| 139 | 
            -
                      force_binary str
         | 
| 140 | 
            -
                      self[:type].read str[0, 1]
         | 
| 141 | 
            -
                      self[:length].read str[1, 1]
         | 
| 142 | 
            -
                      self[:pointer].read str[2, 1]
         | 
| 143 | 
            -
                      self[:data].read str[3, length - 3]
         | 
| 144 | 
            -
                      self
         | 
| 145 | 
            -
                    end
         | 
| 148 | 
            +
                    define_field :data, ArrayOfAddr, builder: ->(h, t) { t.new(length_from: -> { h.length - 3 }) }
         | 
| 146 149 |  | 
| 147 150 | 
             
                    # Get IP address pointer by {#pointer}
         | 
| 148 151 | 
             
                    # @return [Addr]
         | 
| @@ -15,30 +15,6 @@ module PacketGen | |
| 15 15 |  | 
| 16 16 | 
             
                    HUMAN_SEPARATOR = ';'
         | 
| 17 17 |  | 
| 18 | 
            -
                    # Read IP header options from a string
         | 
| 19 | 
            -
                    # @param [String] str binary string
         | 
| 20 | 
            -
                    # @return [self]
         | 
| 21 | 
            -
                    def read(str)
         | 
| 22 | 
            -
                      clear
         | 
| 23 | 
            -
                      return self if str.nil?
         | 
| 24 | 
            -
                      PacketGen.force_binary str
         | 
| 25 | 
            -
             | 
| 26 | 
            -
                      i = 0
         | 
| 27 | 
            -
                      types = Option.types
         | 
| 28 | 
            -
                      while i < str.to_s.length
         | 
| 29 | 
            -
                        type = str[i, 1].unpack('C').first
         | 
| 30 | 
            -
                        this_option = if types[type].nil?
         | 
| 31 | 
            -
                                        Option.new
         | 
| 32 | 
            -
                                      else
         | 
| 33 | 
            -
                                        types[type].new
         | 
| 34 | 
            -
                                      end
         | 
| 35 | 
            -
                        this_option.read str[i, str.size]
         | 
| 36 | 
            -
                        self << this_option
         | 
| 37 | 
            -
                        i += this_option.sz
         | 
| 38 | 
            -
                      end
         | 
| 39 | 
            -
                      self
         | 
| 40 | 
            -
                    end
         | 
| 41 | 
            -
             | 
| 42 18 | 
             
                    # Get binary string
         | 
| 43 19 | 
             
                    # @return [String]
         | 
| 44 20 | 
             
                    def to_s
         | 
| @@ -48,6 +24,17 @@ module PacketGen | |
| 48 24 | 
             
                      end
         | 
| 49 25 | 
             
                      str
         | 
| 50 26 | 
             
                    end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    private
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    def record_from_hash(hsh)
         | 
| 31 | 
            +
                      Option.build(hsh)
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                    def real_type(opt)
         | 
| 35 | 
            +
                      types = Option.types
         | 
| 36 | 
            +
                      types.value?(opt.type) ? IP.const_get(types.key(opt.type)) : opt.class
         | 
| 37 | 
            +
                    end
         | 
| 51 38 | 
             
                  end
         | 
| 52 39 | 
             
                end
         | 
| 53 40 | 
             
              end
         | 
| @@ -10,8 +10,33 @@ require 'ipaddr' | |
| 10 10 |  | 
| 11 11 | 
             
            module PacketGen
         | 
| 12 12 | 
             
              module Header
         | 
| 13 | 
            +
                # IPv6 ({https://tools.ietf.org/html/rfc8200 RFC 8200})
         | 
| 14 | 
            +
                #    0                   1                   2                   3
         | 
| 15 | 
            +
                #    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
         | 
| 16 | 
            +
                #   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         | 
| 17 | 
            +
                #   |Version| Traffic Class |           Flow Label                  |
         | 
| 18 | 
            +
                #   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         | 
| 19 | 
            +
                #   |         Payload Length        |  Next Header  |   Hop Limit   |
         | 
| 20 | 
            +
                #   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         | 
| 21 | 
            +
                #   |                                                               |
         | 
| 22 | 
            +
                #   +                                                               +
         | 
| 23 | 
            +
                #   |                                                               |
         | 
| 24 | 
            +
                #   +                         Source Address                        +
         | 
| 25 | 
            +
                #   |                                                               |
         | 
| 26 | 
            +
                #   +                                                               +
         | 
| 27 | 
            +
                #   |                                                               |
         | 
| 28 | 
            +
                #   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         | 
| 29 | 
            +
                #   |                                                               |
         | 
| 30 | 
            +
                #   +                                                               +
         | 
| 31 | 
            +
                #   |                                                               |
         | 
| 32 | 
            +
                #   +                      Destination Address                      +
         | 
| 33 | 
            +
                #   |                                                               |
         | 
| 34 | 
            +
                #   +                                                               +
         | 
| 35 | 
            +
                #   |                                                               |
         | 
| 36 | 
            +
                #   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         | 
| 37 | 
            +
                #
         | 
| 13 38 | 
             
                # A IPv6 header consists of:
         | 
| 14 | 
            -
                # * a first 32-bit word ({#u32}, of {Types::Int32} type)  | 
| 39 | 
            +
                # * a first 32-bit word ({#u32}, of {Types::Int32} type) composed of:
         | 
| 15 40 | 
             
                #   * a 4-bit {#version} field,
         | 
| 16 41 | 
             
                #   * a 8-bit {#traffic_class} field,
         | 
| 17 42 | 
             
                #   * a 20-bit {#flow_label} field,
         | 
| @@ -20,6 +45,7 @@ module PacketGen | |
| 20 45 | 
             
                # * a hop-limit field ({#hop}, +Int8+ type),
         | 
| 21 46 | 
             
                # * a source address field ({#src}, {IPv6::Addr} type),
         | 
| 22 47 | 
             
                # * a destination address field ({#dst}, +IPv6::Addr+ type),
         | 
| 48 | 
            +
                # * and a {#body} ({Types::String} type).
         | 
| 23 49 | 
             
                #
         | 
| 24 50 | 
             
                # == Create a IPv6 header
         | 
| 25 51 | 
             
                #  # standalone
         | 
| @@ -44,6 +70,18 @@ module PacketGen | |
| 44 70 | 
             
                #  ipv6[:src]              # => PacketGen::Header::IPv6::Addr
         | 
| 45 71 | 
             
                #  ipv6.dst = '2001:1234:5678:abcd::123'
         | 
| 46 72 | 
             
                #  ipv6.body.read 'this is a body'
         | 
| 73 | 
            +
                #
         | 
| 74 | 
            +
                # == Add IPv6 extensions
         | 
| 75 | 
            +
                # In IPv6, optional extensions are encoded in separate headers that
         | 
| 76 | 
            +
                # may be placed between the IPv6 header and the upper-layer header.
         | 
| 77 | 
            +
                #
         | 
| 78 | 
            +
                # In PacketGen, a IPv6 extension is processedf as a classical header:
         | 
| 79 | 
            +
                #  pkt = PacketGen.gen('IPv6')
         | 
| 80 | 
            +
                #  # Add a HopByHop extension
         | 
| 81 | 
            +
                #  pkt.add('IPv6::HopByHop')
         | 
| 82 | 
            +
                #  pkt.ipv6_hopbyhop.options << { type: 'router_alert', value: [0].pack('n') }
         | 
| 83 | 
            +
                #  # Add another header
         | 
| 84 | 
            +
                #  pkt.add('UDP')
         | 
| 47 85 | 
             
                # @author Sylvain Daubert
         | 
| 48 86 | 
             
                class IPv6 < Base; end
         | 
| 49 87 |  | 
| @@ -104,34 +142,14 @@ module PacketGen | |
| 104 142 | 
             
                    sum
         | 
| 105 143 | 
             
                  end
         | 
| 106 144 |  | 
| 107 | 
            -
                  # Send IPv6 packet on wire.
         | 
| 108 | 
            -
                  #
         | 
| 109 | 
            -
                  # When sending packet at IPv6 level, +version+, +flow_label+ and +length+
         | 
| 110 | 
            -
                  # fields are set by kernel. Source address should be a unicast address
         | 
| 111 | 
            -
                  # assigned to the host. To set any of this fields, use {Eth#to_w}.
         | 
| 112 | 
            -
                  # @param [String] iface interface name
         | 
| 145 | 
            +
                  # Send IPv6 packet on wire. All fields may be set (even {#version}).
         | 
| 146 | 
            +
                  # @param [String] _iface interface name (not used)
         | 
| 113 147 | 
             
                  # @return [void]
         | 
| 114 | 
            -
                   | 
| 115 | 
            -
             | 
| 148 | 
            +
                  # @since 3.0.0 no more limitations on +flow_label+, +length+ and +src+ fields.
         | 
| 149 | 
            +
                  def to_w(_iface=nil)
         | 
| 150 | 
            +
                    sock = Socket.new(Socket::AF_INET6, Socket::SOCK_RAW, Socket::IPPROTO_RAW)
         | 
| 116 151 | 
             
                    sockaddrin = Socket.sockaddr_in(0, dst)
         | 
| 117 | 
            -
             | 
| 118 | 
            -
                    # IPv6 RAW sockets don't have IPHDRINCL option to send IPv6 header.
         | 
| 119 | 
            -
                    # So, header must be built using ancillary data.
         | 
| 120 | 
            -
                    # Only src address, traffic_class and hop_limit can be set this way.
         | 
| 121 | 
            -
                    hop_limit = Socket::AncillaryData.int(Socket::AF_INET6,
         | 
| 122 | 
            -
                                                          Socket::IPPROTO_IPV6,
         | 
| 123 | 
            -
                                                          Socket::IPV6_HOPLIMIT, hop)
         | 
| 124 | 
            -
                    tc = Socket::AncillaryData.int(Socket::AF_INET6,
         | 
| 125 | 
            -
                                                   Socket::IPPROTO_IPV6,
         | 
| 126 | 
            -
                                                   Socket::IPV6_TCLASS,
         | 
| 127 | 
            -
                                                   traffic_class)
         | 
| 128 | 
            -
             | 
| 129 | 
            -
                    # src address is set through PKT_INFO, which needs interface index.
         | 
| 130 | 
            -
                    ifaddr = Socket.getifaddrs.find { |ia| ia.name == iface }
         | 
| 131 | 
            -
                    raise WireError, "unknown #{iface} interface" if ifaddr.nil?
         | 
| 132 | 
            -
                    pkt_info = Socket::AncillaryData.ipv6_pktinfo(Addrinfo.ip(src), ifaddr.ifindex)
         | 
| 133 | 
            -
             | 
| 134 | 
            -
                    sock.sendmsg body.to_s, 0, sockaddrin, hop_limit, tc, pkt_info
         | 
| 152 | 
            +
                    sock.send to_s, 0, sockaddrin
         | 
| 135 153 | 
             
                    sock.close
         | 
| 136 154 | 
             
                  end
         | 
| 137 155 |  | 
| @@ -190,13 +208,6 @@ module PacketGen | |
| 190 208 | 
             
                        klass.bind header_klass, args
         | 
| 191 209 | 
             
                      end
         | 
| 192 210 | 
             
                    end
         | 
| 193 | 
            -
                    # Bind a upper header to IPv6 and its defined extension headers.
         | 
| 194 | 
            -
                    # @see Base.bind_header
         | 
| 195 | 
            -
                    # @deprecated USe {bind}.
         | 
| 196 | 
            -
                    def bind_header(header_klass, args={})
         | 
| 197 | 
            -
                      Deprecation.deprecated(self, __method__, 'bind', klass_method: true)
         | 
| 198 | 
            -
                      bind header_klass, args
         | 
| 199 | 
            -
                    end
         | 
| 200 211 | 
             
                  end
         | 
| 201 212 | 
             
                end
         | 
| 202 213 | 
             
              end
         | 
| @@ -52,8 +52,10 @@ module PacketGen | |
| 52 52 | 
             
                    # @return [self]
         | 
| 53 53 | 
             
                    def from_human(str)
         | 
| 54 54 | 
             
                      return self if str.nil?
         | 
| 55 | 
            +
             | 
| 55 56 | 
             
                      addr = IPAddr.new(str)
         | 
| 56 57 | 
             
                      raise ArgumentError, 'string is not a IPv6 address' unless addr.ipv6?
         | 
| 58 | 
            +
             | 
| 57 59 | 
             
                      addri = addr.to_i
         | 
| 58 60 | 
             
                      self.a1 = addri >> 112
         | 
| 59 61 | 
             
                      self.a2 = addri >> 96 & 0xffff
         | 
| @@ -46,23 +46,6 @@ module PacketGen | |
| 46 46 | 
             
                  class Options < Types::Array
         | 
| 47 47 | 
             
                    set_of Option
         | 
| 48 48 |  | 
| 49 | 
            -
                    # Populate object from a binary string
         | 
| 50 | 
            -
                    # @param [String] str
         | 
| 51 | 
            -
                    # @return [self]
         | 
| 52 | 
            -
                    def read(str)
         | 
| 53 | 
            -
                      clear
         | 
| 54 | 
            -
                      return self if str.nil?
         | 
| 55 | 
            -
                      force_binary str
         | 
| 56 | 
            -
                      klass = self.class.class_eval { @klass }
         | 
| 57 | 
            -
                      until str.empty?
         | 
| 58 | 
            -
                        obj = klass.new.read(str)
         | 
| 59 | 
            -
                        obj = Pad1.new.read(str) if obj.type.zero?
         | 
| 60 | 
            -
                        self.push obj
         | 
| 61 | 
            -
                        str.slice!(0, obj.sz)
         | 
| 62 | 
            -
                      end
         | 
| 63 | 
            -
                      self
         | 
| 64 | 
            -
                    end
         | 
| 65 | 
            -
             | 
| 66 49 | 
             
                    # Get options as a binary string. Add padding if needed.
         | 
| 67 50 | 
             
                    # @return [String]
         | 
| 68 51 | 
             
                    def to_s
         | 
| @@ -83,6 +66,12 @@ module PacketGen | |
| 83 66 | 
             
                      end
         | 
| 84 67 | 
             
                      str
         | 
| 85 68 | 
             
                    end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                    private
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                    def real_type(opt)
         | 
| 73 | 
            +
                      opt.type.zero? ? Pad1 : opt.class
         | 
| 74 | 
            +
                    end
         | 
| 86 75 | 
             
                  end
         | 
| 87 76 |  | 
| 88 77 | 
             
                  # Hop-by-hop IPv6 extension
         | 
| @@ -111,20 +100,7 @@ module PacketGen | |
| 111 100 | 
             
                    # @!attribute options
         | 
| 112 101 | 
             
                    #  Specific options of extension header
         | 
| 113 102 | 
             
                    #  @return [Options]
         | 
| 114 | 
            -
                    define_field_before :body, :options, Options
         | 
| 115 | 
            -
             | 
| 116 | 
            -
                    # Populate object from a binary string
         | 
| 117 | 
            -
                    # @param [String] str
         | 
| 118 | 
            -
                    # @return [self]
         | 
| 119 | 
            -
                    def read(str)
         | 
| 120 | 
            -
                      return self if str.nil?
         | 
| 121 | 
            -
                      force_binary str
         | 
| 122 | 
            -
                      self[:next].read str[0, 1]
         | 
| 123 | 
            -
                      self[:length].read str[1, 1]
         | 
| 124 | 
            -
                      self[:options].read str[2, real_length - 2]
         | 
| 125 | 
            -
                      self[:body].read str[real_length..-1]
         | 
| 126 | 
            -
                      self
         | 
| 127 | 
            -
                    end
         | 
| 103 | 
            +
                    define_field_before :body, :options, Options, builder: ->(h, t) { t.new(length_from: -> { h.real_length - 2} ) }
         | 
| 128 104 | 
             
                  end
         | 
| 129 105 | 
             
                end
         | 
| 130 106 |  |