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



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

define_field :body, Types::String

#checksumInteger

Returns 16-bit IP header checksum.

Returns:

  • (Integer)

    16-bit IP header checksum



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

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

#dstAddr

Returns destination IP address.

Returns:

  • (Addr)

    destination IP address



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

define_field :dst, Addr, default: '127.0.0.1'

#flag_dfBoolean

Returns Don’t Fragment flag.

Returns:

  • (Boolean)

    Don’t Fragment flag



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

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



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

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



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

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



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

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

#fragment_offsetInteger

Returns 13-bit fragment offset.

Returns:

  • (Integer)

    13-bit fragment offset



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

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

#idInteger

Returns 16-bit ID.

Returns:

  • (Integer)

    16-bit ID



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

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



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

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

#lengthInteger

Returns 16-bit IP total length.

Returns:

  • (Integer)

    16-bit IP total length



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

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

#optionsTypes::String

Returns:

Since:

  • 2.2.0



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

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



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

define_field :protocol, Types::Int8

#srcAddr

Returns source IP address.

Returns:

  • (Addr)

    source IP address



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

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



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

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

#ttlInteger

Returns 8-bit Time To Live self.

Returns:

  • (Integer)

    8-bit Time To Live self



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

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.



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

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

#versionInteger

Returns 4-bit version attribute.

Returns:

  • (Integer)

    4-bit version attribute



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

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



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

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)


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

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)


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

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



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

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

#inspectString

Returns:

  • (String)


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

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?]


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

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

#pseudo_header_checksumInteger

Get IP part of pseudo header checksum.

Returns:

  • (Integer)


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

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



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

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



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

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



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

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