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, #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
# File 'lib/packetgen/header/ip.rb', line 184

def self.reduce_checksum(checksum)
  checksum = (checksum & 0xffff) + (checksum >> 16) while checksum > 0xffff
  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*').sum

  hdr.checksum = old_checksum if old_checksum

  sum
end

Instance Method Details

#calc_checksumInteger

Compute checksum and set checksum field

Returns:

  • (Integer)

192
193
194
195
196
197
198
199
# File 'lib/packetgen/header/ip.rb', line 192

def calc_checksum
  # Checksum is only on header, so cannot use IP.sum16,
  # which also calculates checksum on #body.
  nb_words = ihl * 2
  self.checksum = 0
  checksum = to_s.unpack("n#{nb_words}").sum
  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


204
205
206
207
# File 'lib/packetgen/header/ip.rb', line 204

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

#inspectString

Returns:

  • (String)

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

def inspect
  super do |attr|
    case attr
    when :u8
      inspect_u8
    when :frag
      inspect_frag
    end
  end
end

#parse?Boolean

Check version field

Returns:

  • (Boolean)

See Also:

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

243
244
245
# File 'lib/packetgen/header/ip.rb', line 243

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

#pseudo_header_checksumInteger

Get IP part of pseudo header checksum.

Returns:

  • (Integer)

211
212
213
214
# File 'lib/packetgen/header/ip.rb', line 211

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


257
258
259
260
# File 'lib/packetgen/header/ip.rb', line 257

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).


249
250
251
252
# File 'lib/packetgen/header/ip.rb', line 249

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


222
223
224
225
226
227
# File 'lib/packetgen/header/ip.rb', line 222

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