class PacketGen::Header::IP

IP protocol ({tools.ietf.org/html/rfc791 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

Constants

ETHERTYPE

IP Ether type

Public Class Methods

reduce_checksum(checksum) click to toggle source

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.

@param [Integer] checksum checksum to reduce @return [Integer] reduced checksum

# 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) click to toggle source

Helper method to compute sum of 16-bit words. Used to compute IP-style checksums. @param [#to_s] hdr header or other object on which calculates a sum

of 16-bit words.

@return [Integer]

# 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

Public Instance Methods

calc_checksum() click to toggle source

Compute checksum and set checksum field @return [Integer]

# 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_length() click to toggle source

Compute and set length and ihl field @return [Integer] @since 3.0.0 add ihl calculation

# 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
inspect() click to toggle source

@return [String]

Calls superclass method
# 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?() click to toggle source

Check version field @see [Base#parse?]

# File lib/packetgen/header/ip.rb, line 243
def parse?
  (version == 4) && (ihl >= 5)
end
pseudo_header_checksum() click to toggle source

Get IP part of pseudo header checksum. @return [Integer]

# 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!() click to toggle source

Invert source and destination addresses @return [self] @since 2.7.0

# File lib/packetgen/header/ip.rb, line 257
def reply!
  self[:src], self[:dst] = self[:dst], self[:src]
  self
end
to_s() click to toggle source

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

Calls superclass method
# 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) click to toggle source

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}. @param [String,nil] _iface interface name. Not used @return [void]

# 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

Private Instance Methods

inspect_frag() click to toggle source
# File lib/packetgen/header/ip.rb, line 271
def inspect_frag
  shift = Inspect.shift_level
  str = Inspect.inspect_attribute(:frag, self[:frag])
  flags = %i[rsv df mf].select { |flag| send("flag_#{flag}?") }.map(&:upcase)
  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
inspect_u8() click to toggle source
# File lib/packetgen/header/ip.rb, line 264
def inspect_u8
  shift = Inspect.shift_level
  str = Inspect.inspect_attribute(:u8, self[:u8])
  str << shift << Inspect::FMT_ATTR % ['', 'version', version]
  str << shift << Inspect::FMT_ATTR % ['', 'ihl', ihl]
end