Class: PacketFu::IPHeader

Inherits:
Struct
  • Object
show all
Includes:
StructFu
Defined in:
lib/packetfu/protos/ip/header.rb

Overview

IPHeader is a complete IP struct, used in IPPacket. Most traffic on most networks today is IP-based.

For more on IP packets, see www.networksorcery.com/enp/protocol/ip.htm

Header Definition

Integer (4 bits) :ip_v,     Default: 4
Integer (4 bits) :ip_hl,    Default: 5
Int8             :ip_tos,   Default: 0           # TODO: Break out the bits
Int16            :ip_len,   Default: calculated
Int16            :ip_id,    Default: calculated  # IRL, hardly random.
Int16            :ip_frag,  Default: 0           # TODO: Break out the bits
Int8             :ip_ttl,   Default: 64          # https://www.iana.org/assignments/ip-parameters/ip-parameters.xml
Int8             :ip_proto, Default: 0x01        # TCP: 0x06, UDP 0x11, ICMP 0x01
Int16            :ip_sum,   Default: calculated
Octets           :ip_src
Octets           :ip_dst
String           :body

Note that IPPackets will always be somewhat incorrect upon initalization, and want an IPHeader#recalc() to become correct before a Packet#to_f or Packet#to_w.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from StructFu

#clone, #set_endianness, #sz, #typecast

Methods inherited from Struct

#force_binary

Constructor Details

#initialize(args = {}) ⇒ IPHeader

Returns a new instance of IPHeader.



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/packetfu/protos/ip/header.rb', line 125

def initialize(args={})
  @random_id = rand(0xffff)
  super(
    (args[:ip_v] || 4),
    (args[:ip_hl] || 5),
    Int8.new(args[:ip_tos]),
    Int16.new(args[:ip_len] || 20),
    Int16.new(args[:ip_id] || ip_calc_id),
    Int16.new(args[:ip_frag]),
    Int8.new(args[:ip_ttl] || 64),
    Int8.new(args[:ip_proto]),
    Int16.new(args[:ip_sum] || ip_calc_sum),
    Octets.new.read(args[:ip_src] || "\x00\x00\x00\x00"),
    Octets.new.read(args[:ip_dst] || "\x00\x00\x00\x00"),
    StructFu::String.new.read(args[:body])
  )
end

Instance Attribute Details

#bodyObject

Returns the value of attribute body

Returns:

  • (Object)

    the current value of body



120
121
122
# File 'lib/packetfu/protos/ip/header.rb', line 120

def body
  @body
end

#ip_dstObject

Getter for the destination IP address.



120
121
122
# File 'lib/packetfu/protos/ip/header.rb', line 120

def ip_dst
  @ip_dst
end

#ip_fragObject

Getter for the fragmentation ID.



120
121
122
# File 'lib/packetfu/protos/ip/header.rb', line 120

def ip_frag
  @ip_frag
end

#ip_hlObject

Getter for the header length (multiply by 4)



120
121
122
# File 'lib/packetfu/protos/ip/header.rb', line 120

def ip_hl
  @ip_hl
end

#ip_idObject

Getter for the identication number.



120
121
122
# File 'lib/packetfu/protos/ip/header.rb', line 120

def ip_id
  @ip_id
end

#ip_lenObject

Getter for total length.



120
121
122
# File 'lib/packetfu/protos/ip/header.rb', line 120

def ip_len
  @ip_len
end

#ip_protoObject

Getter for the protocol number.



120
121
122
# File 'lib/packetfu/protos/ip/header.rb', line 120

def ip_proto
  @ip_proto
end

#ip_srcObject

Getter for the source IP address.



120
121
122
# File 'lib/packetfu/protos/ip/header.rb', line 120

def ip_src
  @ip_src
end

#ip_sumObject

Getter for the checksum.



120
121
122
# File 'lib/packetfu/protos/ip/header.rb', line 120

def ip_sum
  @ip_sum
end

#ip_tosObject

Getter for the differentiated services



120
121
122
# File 'lib/packetfu/protos/ip/header.rb', line 120

def ip_tos
  @ip_tos
end

#ip_ttlObject

Getter for the time to live.



120
121
122
# File 'lib/packetfu/protos/ip/header.rb', line 120

def ip_ttl
  @ip_ttl
end

#ip_vObject

Getter for the version.



120
121
122
# File 'lib/packetfu/protos/ip/header.rb', line 120

def ip_v
  @ip_v
end

Class Method Details

.octet_array(addr) ⇒ Object

Translate various formats of IPv4 Addresses to an array of digits.



286
287
288
289
290
291
292
293
294
295
296
# File 'lib/packetfu/protos/ip/header.rb', line 286

def self.octet_array(addr)
  if addr.class == String
    oa = addr.split('.').collect {|x| x.to_i}
  elsif addr.kind_of? Integer
    oa = IPAddr.new(addr, Socket::AF_INET).to_s.split('.')
  elsif addr.kind_of? Array
    oa = addr
  else
    raise ArgumentError, "IP Address should be a dotted quad string, an array of ints, or a bignum"
  end
end

Instance Method Details

#ip_calc_idObject

Retrieve the IP ID



259
260
261
# File 'lib/packetfu/protos/ip/header.rb', line 259

def ip_calc_id
  @random_id
end

#ip_calc_lenObject

Calulcate the true length of the packet.



232
233
234
# File 'lib/packetfu/protos/ip/header.rb', line 232

def ip_calc_len
  (ip_hl * 4) + body.to_s.length
end

#ip_calc_sumObject

Calculate the true checksum of the packet. (Yes, this is the long way to do it, but it’s e-z-2-read for mathtards like me.)



243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/packetfu/protos/ip/header.rb', line 243

def ip_calc_sum
  checksum =  (((self.ip_v  <<  4) + self.ip_hl) << 8) + self.ip_tos
  checksum += self.ip_len
  checksum +=	self.ip_id
  checksum += self.ip_frag
  checksum +=	(self.ip_ttl << 8) + self.ip_proto
  checksum += (self.ip_src >> 16)
  checksum += (self.ip_src & 0xffff)
  checksum += (self.ip_dst >> 16)
  checksum += (self.ip_dst & 0xffff)
  checksum = checksum % 0xffff
  checksum = 0xffff - checksum
  checksum == 0 ? 0xffff : checksum
end

#ip_daddrObject Also known as: ip_dst_readable

Returns a more readable IP destination address.



281
282
283
# File 'lib/packetfu/protos/ip/header.rb', line 281

def ip_daddr
  self[:ip_dst].to_x
end

#ip_daddr=(addr) ⇒ Object

Sets a more readable IP address.



276
277
278
# File 'lib/packetfu/protos/ip/header.rb', line 276

def ip_daddr=(addr)
  self[:ip_dst].read_quad(addr)
end

#ip_hlenObject

Return the claimed header length



237
238
239
# File 'lib/packetfu/protos/ip/header.rb', line 237

def ip_hlen
  (ip_hl * 4)
end

#ip_id_readableObject



325
326
327
# File 'lib/packetfu/protos/ip/header.rb', line 325

def ip_id_readable
  "0x%04x" % ip_id
end

#ip_recalc(arg = :all) ⇒ Object

Recalculate the calculated IP fields. Valid arguments are:

:all
:ip_len
:ip_sum
:ip_id


303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/packetfu/protos/ip/header.rb', line 303

def ip_recalc(arg=:all)
  case arg
  when :ip_len
    self.ip_len=ip_calc_len
  when :ip_sum
    self.ip_sum=ip_calc_sum
  when :ip_id
    @random_id = rand(0xffff)
  when :all
    self.ip_id=		ip_calc_id
    self.ip_len=	ip_calc_len
    self.ip_sum=	ip_calc_sum
  else
    raise ArgumentError, "No such field `#{arg}'"
  end
end

#ip_saddrObject Also known as: ip_src_readable

Returns a more readable IP source address.



271
272
273
# File 'lib/packetfu/protos/ip/header.rb', line 271

def ip_saddr
  self[:ip_src].to_x
end

#ip_saddr=(addr) ⇒ Object

Sets a more readable IP address. If you wants to manipulate individual octets, (eg, for host scanning in one network), it would be better use ip_src.o1 through ip_src.o4 instead.



266
267
268
# File 'lib/packetfu/protos/ip/header.rb', line 266

def ip_saddr=(addr)
  self[:ip_src].read_quad(addr)
end

#ip_sum_readableObject



329
330
331
# File 'lib/packetfu/protos/ip/header.rb', line 329

def ip_sum_readable
  "0x%04x" % ip_sum
end

#read(str) ⇒ Object

Reads a string to populate the object.



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/packetfu/protos/ip/header.rb', line 150

def read(str)
  force_binary(str)
  return self if str.nil?
  self[:ip_v] = str[0,1].unpack("C").first >> 4
  self[:ip_hl] = str[0,1].unpack("C").first.to_i & 0x0f
  self[:ip_tos].read(str[1,1])
  self[:ip_len].read(str[2,2])
  self[:ip_id].read(str[4,2])
  self[:ip_frag].read(str[6,2])
  self[:ip_ttl].read(str[8,1])
  self[:ip_proto].read(str[9,1])
  self[:ip_sum].read(str[10,2])
  self[:ip_src].read(str[12,4])
  self[:ip_dst].read(str[16,4])
  self[:body].read(str[20,str.size]) if str.size > 20
  self
end

#to_sObject

Returns the object in string form.



144
145
146
147
# File 'lib/packetfu/protos/ip/header.rb', line 144

def to_s
  byte_v_hl = [(self.ip_v << 4) + self.ip_hl].pack("C")
  byte_v_hl + (self.to_a[2,10].map {|x| x.to_s}.join)
end