Class: PacketFu::IPHeader

Inherits:
Struct
  • Object
show all
Includes:
StructFu
Defined in:
lib/packetfu/protos/ip.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

Fixnum (4 bits)  :ip_v,     Default: 4
Fixnum (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: 0xff        # Changes per flavor
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.



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/packetfu/protos/ip.rb', line 85

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] || 32),
		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



80
81
82
# File 'lib/packetfu/protos/ip.rb', line 80

def body
  @body
end

#ip_dstObject

Getter for the destination IP address.



80
81
82
# File 'lib/packetfu/protos/ip.rb', line 80

def ip_dst
  @ip_dst
end

#ip_fragObject

Getter for the fragmentation ID.



80
81
82
# File 'lib/packetfu/protos/ip.rb', line 80

def ip_frag
  @ip_frag
end

#ip_hlObject

Getter for the header length (multiply by 4)



80
81
82
# File 'lib/packetfu/protos/ip.rb', line 80

def ip_hl
  @ip_hl
end

#ip_idObject

Getter for the identication number.



80
81
82
# File 'lib/packetfu/protos/ip.rb', line 80

def ip_id
  @ip_id
end

#ip_lenObject

Getter for total length.



80
81
82
# File 'lib/packetfu/protos/ip.rb', line 80

def ip_len
  @ip_len
end

#ip_protoObject

Getter for the protocol number.



80
81
82
# File 'lib/packetfu/protos/ip.rb', line 80

def ip_proto
  @ip_proto
end

#ip_srcObject

Getter for the source IP address.



80
81
82
# File 'lib/packetfu/protos/ip.rb', line 80

def ip_src
  @ip_src
end

#ip_sumObject

Getter for the checksum.



80
81
82
# File 'lib/packetfu/protos/ip.rb', line 80

def ip_sum
  @ip_sum
end

#ip_tosObject

Getter for the differentiated services



80
81
82
# File 'lib/packetfu/protos/ip.rb', line 80

def ip_tos
  @ip_tos
end

#ip_ttlObject

Getter for the time to live.



80
81
82
# File 'lib/packetfu/protos/ip.rb', line 80

def ip_ttl
  @ip_ttl
end

#ip_vObject

Getter for the version.



80
81
82
# File 'lib/packetfu/protos/ip.rb', line 80

def ip_v
  @ip_v
end

Class Method Details

.octet_array(addr) ⇒ Object

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



246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/packetfu/protos/ip.rb', line 246

def self.octet_array(addr)
	if addr.class == String
		oa = addr.split('.').collect {|x| x.to_i}
	elsif addr.class == Fixnum
		oa = IPAddr.new(addr, Socket::AF_INET).to_s.split('.')
	elsif addr.class == Bignum
		oa = IPAddr.new(addr, Socket::AF_INET).to_s.split('.')
	elsif addr.class == 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



219
220
221
# File 'lib/packetfu/protos/ip.rb', line 219

def ip_calc_id
	@random_id
end

#ip_calc_lenObject

Calulcate the true length of the packet.



192
193
194
# File 'lib/packetfu/protos/ip.rb', line 192

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



203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/packetfu/protos/ip.rb', line 203

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.



241
242
243
# File 'lib/packetfu/protos/ip.rb', line 241

def ip_daddr
	self[:ip_dst].to_x
end

#ip_daddr=(addr) ⇒ Object

Sets a more readable IP address.



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

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

#ip_hlenObject

Return the claimed header length



197
198
199
# File 'lib/packetfu/protos/ip.rb', line 197

def ip_hlen
	(ip_hl * 4)
end

#ip_id_readableObject



287
288
289
# File 'lib/packetfu/protos/ip.rb', line 287

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


265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# File 'lib/packetfu/protos/ip.rb', line 265

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.



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

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.



226
227
228
# File 'lib/packetfu/protos/ip.rb', line 226

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

#ip_sum_readableObject



291
292
293
# File 'lib/packetfu/protos/ip.rb', line 291

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

#read(str) ⇒ Object

Reads a string to populate the object.



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/packetfu/protos/ip.rb', line 110

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.



104
105
106
107
# File 'lib/packetfu/protos/ip.rb', line 104

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