Class: PacketGen::Header::IP

Inherits:
Base show all
Defined in:
lib/packetgen/header/ip.rb,
lib/packetgen/header/ip.rb,
lib/packetgen/header/ip/addr.rb,
lib/packetgen/header/ip/option.rb,
lib/packetgen/header/ip/options.rb

Overview

IP protocol (RFC 791)

 0                   1                   2                   3
 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          Total Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Identification        |Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Time to Live |    Protocol   |         Header Checksum       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Source Address                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Destination Address                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

A IP header consists of:

Create a IP header

# standalone
ip = PacketGen::Header::IP.new
# in a packet
pkt = PacketGen.gen('IP')
# access to IP header
pkt.ip   # => PacketGen::Header::IP

IP attributes

ip.u8 = 0x45
# the same as
ip.version = 4
ip.ihl = 5

ip.length = 0x43
ip.id = 0x1234

ip.frag = 0x2031
# the same as:
ip.flag_mf = true
ip.fragment_offset = 0x31

ip.flag_rsv?  # => Boolean
ip.flag_df?   # => Boolean
ip.flag_mf?   # => Boolean

ip.ttl = 0x40
ip.protocol = 6
ip.checksum = 0xffff
ip.src = '127.0.0.1'
ip.src                # => "127.0.0.1"
ip[:src]              # => PacketGen::Header::IP::Addr
ip.dst = '127.0.0.2'
ip.body.read 'this is a body'

Add IP options

IP has an #options attribute used to store datagram options.

pkt = PacketGen.gen('IP')
# add option from class
pkt.ip.options << PacketGen::Header::IP::RA.new
# or use a hash
pkt.ip.options << { type: 'RR', data: ['192.168.16.4']}

Author:

  • Sylvain Daubert

Defined Under Namespace

Classes: Addr, ArrayOfAddr, EOL, LSRR, NOP, Option, Options, RA, RR, SI, SSRR

Constant Summary collapse

ETHERTYPE =

IP Ether type

0x0800

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

bind, calculate_and_set_length, #header_id, inherited, #initialize, #ip_header, known_headers, #ll_header

Methods included from PacketGen::Headerable

#added_to_packet, included, #method_name, #packet, #packet=, #protocol_name, #read

Methods inherited from Types::Fields

#[], #[]=, #bits_on, define_bit_fields_on, define_field, define_field_after, define_field_before, #fields, fields, inherited, #initialize, #offset_of, #optional?, #optional_fields, #present?, #read, remove_bit_fields_on, remove_field, #sz, #to_h, update_field

Constructor Details

This class inherits a constructor from PacketGen::Header::Base

Instance Attribute Details

#bodyTypes::String, Header::Base



137
# File 'lib/packetgen/header/ip.rb', line 137

define_field :body, Types::String

#checksumInteger

Returns 16-bit IP header checksum.

Returns:

  • (Integer)

    16-bit IP header checksum



123
# File 'lib/packetgen/header/ip.rb', line 123

define_field :checksum, Types::Int16, default: 0

#dstAddr

Returns destination IP address.

Returns:

  • (Addr)

    destination IP address



129
# File 'lib/packetgen/header/ip.rb', line 129

define_field :dst, Addr, default: '127.0.0.1'

#flag_dfBoolean

Returns Don’t Fragment flag.

Returns:

  • (Boolean)

    Don’t Fragment flag



153
# File 'lib/packetgen/header/ip.rb', line 153

define_bit_fields_on :frag, :flag_rsv, :flag_df, :flag_mf, :fragment_offset, 13

#flag_mfBoolean

Returns More Fragment flags.

Returns:

  • (Boolean)

    More Fragment flags



153
# File 'lib/packetgen/header/ip.rb', line 153

define_bit_fields_on :frag, :flag_rsv, :flag_df, :flag_mf, :fragment_offset, 13

#flag_rsvBoolean

Returns reserved bit from flags.

Returns:

  • (Boolean)

    reserved bit from flags



153
# File 'lib/packetgen/header/ip.rb', line 153

define_bit_fields_on :frag, :flag_rsv, :flag_df, :flag_mf, :fragment_offset, 13

#fragInteger

Returns 16-bit frag word.

Returns:

  • (Integer)

    16-bit frag word



114
# File 'lib/packetgen/header/ip.rb', line 114

define_field :frag, Types::Int16, default: 0

#fragment_offsetInteger

Returns 13-bit fragment offset.

Returns:

  • (Integer)

    13-bit fragment offset



153
# File 'lib/packetgen/header/ip.rb', line 153

define_bit_fields_on :frag, :flag_rsv, :flag_df, :flag_mf, :fragment_offset, 13

#idInteger

Returns 16-bit ID.

Returns:

  • (Integer)

    16-bit ID



111
# File 'lib/packetgen/header/ip.rb', line 111

define_field :id, Types::Int16, default: ->(_) { rand(65_535) }

#ihlInteger

Returns 4-bit IP header length attribute.

Returns:

  • (Integer)

    4-bit IP header length attribute



143
# File 'lib/packetgen/header/ip.rb', line 143

define_bit_fields_on :u8, :version, 4, :ihl, 4

#lengthInteger

Returns 16-bit IP total length.

Returns:

  • (Integer)

    16-bit IP total length



108
# File 'lib/packetgen/header/ip.rb', line 108

define_field :length, Types::Int16, default: 20

#optionsTypes::String

Returns:

Since:

  • 2.2.0



133
134
# File 'lib/packetgen/header/ip.rb', line 133

define_field :options, Options, optional: ->(h) { h.ihl > 5 },
builder: ->(h, t) { t.new(length_from: -> { (h.ihl - 5) * 4 }) }

#protocolInteger

Returns 8-bit upper protocol self.

Returns:

  • (Integer)

    8-bit upper protocol self



120
# File 'lib/packetgen/header/ip.rb', line 120

define_field :protocol, Types::Int8

#srcAddr

Returns source IP address.

Returns:

  • (Addr)

    source IP address



126
# File 'lib/packetgen/header/ip.rb', line 126

define_field :src, Addr, default: '127.0.0.1'

#tosInteger

Returns 8-bit Type of Service self.

Returns:

  • (Integer)

    8-bit Type of Service self



105
# File 'lib/packetgen/header/ip.rb', line 105

define_field :tos, Types::Int8, default: 0

#ttlInteger

Returns 8-bit Time To Live self.

Returns:

  • (Integer)

    8-bit Time To Live self



117
# File 'lib/packetgen/header/ip.rb', line 117

define_field :ttl, Types::Int8, default: 64

#u8Integer

First byte of IP header. May be accessed through #version and #ihl.

Returns:

  • (Integer)

    first byte of IP header.



102
# File 'lib/packetgen/header/ip.rb', line 102

define_field :u8, Types::Int8, default: 0x45

#versionInteger

Returns 4-bit version attribute.

Returns:

  • (Integer)

    4-bit version attribute



143
# File 'lib/packetgen/header/ip.rb', line 143

define_bit_fields_on :u8, :version, 4, :ihl, 4

Class Method Details

.reduce_checksum(checksum) ⇒ Integer

Helper method to reduce an IP checksum. This method:

  • checks a checksum is not greater than 0xffff. If it is, reduces it.

  • inverts reduced self.

  • forces self to 0xffff if computed self is 0.

Parameters:

  • checksum (Integer)

    checksum to reduce

Returns:

  • (Integer)

    reduced checksum



184
185
186
187
188
189
190
# File 'lib/packetgen/header/ip.rb', line 184

def self.reduce_checksum(checksum)
  while checksum > 0xffff
    checksum = (checksum & 0xffff) + (checksum >> 16)
  end
  checksum = ~checksum & 0xffff
  checksum.zero? ? 0xffff : checksum
end

.sum16(hdr) ⇒ Integer

Helper method to compute sum of 16-bit words. Used to compute IP-style checksums.

Parameters:

  • hdr (#to_s)

    header or other object on which calculates a sum of 16-bit words.

Returns:

  • (Integer)


160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/packetgen/header/ip.rb', line 160

def self.sum16(hdr)
  old_checksum = nil
  if hdr.respond_to? :checksum=
    old_checksum = hdr.checksum
    hdr.checksum = 0
  end

  data = hdr.to_s
  data << "\x00" if data.size.odd?
  sum = data.unpack('n*').reduce(:+)

  hdr.checksum = old_checksum if old_checksum

  sum
end

Instance Method Details

#calc_checksumInteger

Compute checksum and set checksum field

Returns:

  • (Integer)


194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/packetgen/header/ip.rb', line 194

def calc_checksum
  # Checksum is only on header, so cannot use IP.sum16,
  # which also calcultes checksum on #body.
  checksum = (self[:u8].to_i << 8) | self.tos
  checksum += self.length
  checksum += self.id
  checksum += self.frag
  checksum += (self.ttl << 8) | self.protocol
  checksum += (self[:src].to_i >> 16)
  checksum += (self[:src].to_i & 0xffff)
  checksum += self[:dst].to_i >> 16
  checksum += self[:dst].to_i & 0xffff
  options.to_s.unpack('n*').each { |x| checksum += x }
  self[:checksum].value = IP.reduce_checksum(checksum)
end

#calc_lengthInteger

Compute and set length and ihl field

Returns:

  • (Integer)

Since:

  • 3.0.0 add ihl calculation



213
214
215
216
# File 'lib/packetgen/header/ip.rb', line 213

def calc_length
  Base.calculate_and_set_length self
  self.ihl = 5 + self[:options].sz / 4
end

#inspectString

Returns:

  • (String)


239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/packetgen/header/ip.rb', line 239

def inspect
  super do |attr|
    case attr
    when :u8
      shift = Inspect.shift_level
      str = Inspect.inspect_attribute(attr, self[attr])
      str << shift << Inspect::FMT_ATTR % ['', 'version', version]
      str << shift << Inspect::FMT_ATTR % ['', 'ihl', ihl]
    when :frag
      shift = Inspect.shift_level
      str = Inspect.inspect_attribute(attr, self[attr])
      flags = flag_rsv? ? %w[RSV] : []
      flags << 'DF' if flag_df?
      flags << 'MF' if flag_mf?
      flags_str = flags.empty? ? 'none' : flags.join(',')
      str << shift << Inspect::FMT_ATTR % ['', 'flags', flags_str]
      foff = Inspect.int_dec_hex(fragment_offset, 4)
      str << shift << Inspect::FMT_ATTR % ['', 'frag_offset', foff]
    end
  end
end

#parse?Boolean

Check version field

Returns:

  • (Boolean)

See Also:

  • PacketGen::Header::IP.[Base[Base#parse?]


263
264
265
# File 'lib/packetgen/header/ip.rb', line 263

def parse?
  (version == 4) && (ihl >= 5)
end

#pseudo_header_checksumInteger

Get IP part of pseudo header checksum.

Returns:

  • (Integer)


220
221
222
223
# File 'lib/packetgen/header/ip.rb', line 220

def pseudo_header_checksum
  checksum = self[:src].to_i + self[:dst].to_i
  (checksum >> 16) + (checksum & 0xffff)
end

#reply!self

Invert source and destination addresses

Returns:

  • (self)

Since:

  • 2.7.0



277
278
279
280
# File 'lib/packetgen/header/ip.rb', line 277

def reply!
  self[:src], self[:dst] = self[:dst], self[:src]
  self
end

#to_sObject

Get binary string. Fixup IHL if needed (IP header has options, and IHL was not set by user).



269
270
271
272
# File 'lib/packetgen/header/ip.rb', line 269

def to_s
  self.ihl = 5 + self[:options].sz / 4 if self.ihl == 5
  super
end

#to_w(_iface = nil) ⇒ void

This method returns an undefined value.

Send IP packet on wire.

When sending packet at IP level, checksum and length fields are set by kernel, so bad IP packets cannot be sent this way. To do so, use Eth#to_w.

Parameters:

  • _iface (String, nil) (defaults to: nil)

    interface name. Not used



231
232
233
234
235
236
# File 'lib/packetgen/header/ip.rb', line 231

def to_w(_iface=nil)
  sock = Socket.new(Socket::AF_INET, Socket::SOCK_RAW, Socket::IPPROTO_RAW)
  sockaddrin = Socket.sockaddr_in(0, dst)
  sock.send to_s, 0, sockaddrin
  sock.close
end