packetfu 1.1.5 → 1.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -2
- data/.gitignore +1 -0
- data/LICENSE.txt +1 -1
- data/bench/after-2012-07-28.txt +25 -0
- data/bench/before-2012-07-28.txt +25 -0
- data/bench/benchit.rb +68 -0
- data/bench/calc_delta.rb +17 -0
- data/bench/octets.rb +22 -0
- data/bench/octets_after.txt +8 -0
- data/bench/octets_after_refactor.txt +8 -0
- data/bench/octets_before.txt +8 -0
- data/lib/packetfu.rb +8 -3
- data/lib/packetfu/packet.rb +2 -2
- data/lib/packetfu/pcap.rb +20 -4
- data/lib/packetfu/protos/arp.rb +7 -160
- data/lib/packetfu/protos/arp/header.rb +160 -0
- data/lib/packetfu/protos/arp/mixin.rb +38 -0
- data/lib/packetfu/protos/eth.rb +5 -247
- data/lib/packetfu/protos/eth/header.rb +247 -0
- data/lib/packetfu/protos/eth/mixin.rb +20 -0
- data/lib/packetfu/protos/hsrp.rb +13 -123
- data/lib/packetfu/protos/hsrp/header.rb +120 -0
- data/lib/packetfu/protos/hsrp/mixin.rb +31 -0
- data/lib/packetfu/protos/icmp.rb +10 -97
- data/lib/packetfu/protos/icmp/header.rb +93 -0
- data/lib/packetfu/protos/icmp/mixin.rb +17 -0
- data/lib/packetfu/protos/ip.rb +7 -295
- data/lib/packetfu/protos/ip/header.rb +335 -0
- data/lib/packetfu/protos/ip/mixin.rb +43 -0
- data/lib/packetfu/protos/ipv6.rb +7 -191
- data/lib/packetfu/protos/ipv6/header.rb +190 -0
- data/lib/packetfu/protos/ipv6/mixin.rb +31 -0
- data/lib/packetfu/protos/tcp.rb +13 -939
- data/lib/packetfu/protos/tcp/ecn.rb +42 -0
- data/lib/packetfu/protos/tcp/flags.rb +83 -0
- data/lib/packetfu/protos/tcp/header.rb +307 -0
- data/lib/packetfu/protos/tcp/hlen.rb +40 -0
- data/lib/packetfu/protos/tcp/mixin.rb +48 -0
- data/lib/packetfu/protos/tcp/option.rb +323 -0
- data/lib/packetfu/protos/tcp/options.rb +106 -0
- data/lib/packetfu/protos/tcp/reserved.rb +42 -0
- data/lib/packetfu/protos/udp.rb +12 -110
- data/lib/packetfu/protos/udp/header.rb +107 -0
- data/lib/packetfu/protos/udp/mixin.rb +23 -0
- data/lib/packetfu/utils.rb +24 -24
- data/lib/packetfu/version.rb +1 -1
- data/packetfu.gemspec +2 -2
- data/test/test_ip.rb +0 -19
- data/test/test_octets.rb +18 -21
- data/test/test_tcp.rb +10 -0
- data/test/test_udp.rb +17 -0
- metadata +79 -50
@@ -0,0 +1,31 @@
|
|
1
|
+
module PacketFu
|
2
|
+
# This Mixin simplifies access to the HSRPHeaders. Mix this in with your
|
3
|
+
# packet interface, and it will add methods that essentially delegate to
|
4
|
+
# the 'hsrp_header' method (assuming that it is a HSRPHeader object)
|
5
|
+
module HSRPHeaderMixin
|
6
|
+
def hsrp_version=(v); self.hsrp_header.hsrp_version= v; end
|
7
|
+
def hsrp_version; self.hsrp_header.hsrp_version; end
|
8
|
+
def hsrp_opcode=(v); self.hsrp_header.hsrp_opcode= v; end
|
9
|
+
def hsrp_opcode; self.hsrp_header.hsrp_opcode; end
|
10
|
+
def hsrp_state=(v); self.hsrp_header.hsrp_state= v; end
|
11
|
+
def hsrp_state; self.hsrp_header.hsrp_state; end
|
12
|
+
def hsrp_hellotime=(v); self.hsrp_header.hsrp_hellotime= v; end
|
13
|
+
def hsrp_hellotime; self.hsrp_header.hsrp_hellotime; end
|
14
|
+
def hsrp_holdtime=(v); self.hsrp_header.hsrp_holdtime= v; end
|
15
|
+
def hsrp_holdtime; self.hsrp_header.hsrp_holdtime; end
|
16
|
+
def hsrp_priority=(v); self.hsrp_header.hsrp_priority= v; end
|
17
|
+
def hsrp_priority; self.hsrp_header.hsrp_priority; end
|
18
|
+
def hsrp_group=(v); self.hsrp_header.hsrp_group= v; end
|
19
|
+
def hsrp_group; self.hsrp_header.hsrp_group; end
|
20
|
+
def hsrp_reserved=(v); self.hsrp_header.hsrp_reserved= v; end
|
21
|
+
def hsrp_reserved; self.hsrp_header.hsrp_reserved; end
|
22
|
+
def hsrp_addr=(v); self.hsrp_header.hsrp_addr= v; end
|
23
|
+
def hsrp_addr; self.hsrp_header.hsrp_addr; end
|
24
|
+
def hsrp_vip_readable; self.hsrp_header.hsrp_vip_readable; end
|
25
|
+
def hsrp_password_readable; self.hsrp_header.hsrp_password_readable; end
|
26
|
+
def hsrp_password; self.hsrp_header.hsrp_password; end
|
27
|
+
def hsrp_password=(v); self.hsrp_header.hsrp_password= v; end
|
28
|
+
def hsrp_vip; self.hsrp_header.hsrp_vip; end
|
29
|
+
def hsrp_vip=(v); self.hsrp_header.hsrp_vip= v; end
|
30
|
+
end
|
31
|
+
end
|
data/lib/packetfu/protos/icmp.rb
CHANGED
@@ -1,97 +1,13 @@
|
|
1
|
-
|
1
|
+
require 'packetfu/protos/eth/header'
|
2
|
+
require 'packetfu/protos/eth/mixin'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
#
|
6
|
-
# For more on ICMP packets, see
|
7
|
-
# http://www.networksorcery.com/enp/protocol/icmp.htm
|
8
|
-
#
|
9
|
-
# ==== Header Definition
|
10
|
-
#
|
11
|
-
# Int8 :icmp_type # Type
|
12
|
-
# Int8 :icmp_code # Code
|
13
|
-
# Int16 :icmp_sum Default: calculated # Checksum
|
14
|
-
# String :body
|
15
|
-
class ICMPHeader < Struct.new(:icmp_type, :icmp_code, :icmp_sum, :body)
|
4
|
+
require 'packetfu/protos/ip/header'
|
5
|
+
require 'packetfu/protos/ip/mixin'
|
16
6
|
|
17
|
-
|
18
|
-
|
19
|
-
def initialize(args={})
|
20
|
-
super(
|
21
|
-
Int8.new(args[:icmp_type]),
|
22
|
-
Int8.new(args[:icmp_code]),
|
23
|
-
Int16.new(args[:icmp_sum] || icmp_calc_sum),
|
24
|
-
StructFu::String.new.read(args[:body])
|
25
|
-
)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Returns the object in string form.
|
29
|
-
def to_s
|
30
|
-
self.to_a.map {|x| x.to_s}.join
|
31
|
-
end
|
32
|
-
|
33
|
-
# Reads a string to populate the object.
|
34
|
-
def read(str)
|
35
|
-
force_binary(str)
|
36
|
-
return self if str.nil?
|
37
|
-
self[:icmp_type].read(str[0,1])
|
38
|
-
self[:icmp_code].read(str[1,1])
|
39
|
-
self[:icmp_sum].read(str[2,2])
|
40
|
-
self[:body].read(str[4,str.size])
|
41
|
-
self
|
42
|
-
end
|
43
|
-
|
44
|
-
# Setter for the type.
|
45
|
-
def icmp_type=(i); typecast i; end
|
46
|
-
# Getter for the type.
|
47
|
-
def icmp_type; self[:icmp_type].to_i; end
|
48
|
-
# Setter for the code.
|
49
|
-
def icmp_code=(i); typecast i; end
|
50
|
-
# Getter for the code.
|
51
|
-
def icmp_code; self[:icmp_code].to_i; end
|
52
|
-
# Setter for the checksum. Note, this is calculated automatically with
|
53
|
-
# icmp_calc_sum.
|
54
|
-
def icmp_sum=(i); typecast i; end
|
55
|
-
# Getter for the checksum.
|
56
|
-
def icmp_sum; self[:icmp_sum].to_i; end
|
57
|
-
|
58
|
-
# Calculates and sets the checksum for the object.
|
59
|
-
def icmp_calc_sum
|
60
|
-
checksum = (icmp_type.to_i << 8) + icmp_code.to_i
|
61
|
-
chk_body = (body.to_s.size % 2 == 0 ? body.to_s : body.to_s + "\x00")
|
62
|
-
if 1.respond_to? :ord
|
63
|
-
chk_body.scan(/../).map { |x| (x[0].ord << 8) + x[1].ord }.each { |y| checksum += y }
|
64
|
-
else
|
65
|
-
chk_body.scan(/../).map { |x| (x[0] << 8) + x[1] }.each { |y| checksum += y }
|
66
|
-
end
|
67
|
-
checksum = checksum % 0xffff
|
68
|
-
checksum = 0xffff - checksum
|
69
|
-
checksum == 0 ? 0xffff : checksum
|
70
|
-
end
|
71
|
-
|
72
|
-
# Recalculates the calculatable fields for ICMP.
|
73
|
-
def icmp_recalc(arg=:all)
|
74
|
-
# How silly is this, you can't intern a symbol in ruby 1.8.7pl72?
|
75
|
-
# I'm this close to monkey patching Symbol so you can force it...
|
76
|
-
arg = arg.intern if arg.respond_to? :intern
|
77
|
-
case arg
|
78
|
-
when :icmp_sum
|
79
|
-
self.icmp_sum=icmp_calc_sum
|
80
|
-
when :all
|
81
|
-
self.icmp_sum=icmp_calc_sum
|
82
|
-
else
|
83
|
-
raise ArgumentError, "No such field `#{arg}'"
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
# Readability aliases
|
88
|
-
|
89
|
-
def icmp_sum_readable
|
90
|
-
"0x%04x" % icmp_sum
|
91
|
-
end
|
92
|
-
|
93
|
-
end
|
7
|
+
require 'packetfu/protos/icmp/header'
|
8
|
+
require 'packetfu/protos/icmp/mixin'
|
94
9
|
|
10
|
+
module PacketFu
|
95
11
|
# ICMPPacket is used to construct ICMP Packets. They contain an EthHeader, an IPHeader, and a ICMPHeader.
|
96
12
|
#
|
97
13
|
# == Example
|
@@ -119,6 +35,9 @@ module PacketFu
|
|
119
35
|
# :config
|
120
36
|
# A hash of return address details, often the output of Utils.whoami?
|
121
37
|
class ICMPPacket < Packet
|
38
|
+
include ::PacketFu::EthHeaderMixin
|
39
|
+
include ::PacketFu::IPHeaderMixin
|
40
|
+
include ::PacketFu::ICMPHeaderMixin
|
122
41
|
|
123
42
|
attr_accessor :eth_header, :ip_header, :icmp_header
|
124
43
|
|
@@ -133,10 +52,6 @@ module PacketFu
|
|
133
52
|
def read(str=nil, args={})
|
134
53
|
raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
|
135
54
|
@eth_header.read(str)
|
136
|
-
@ip_header.read(str[14,str.size])
|
137
|
-
@eth_header.body = @ip_header
|
138
|
-
@icmp_header.read(str[14+(@ip_header.ip_hlen),str.size])
|
139
|
-
@ip_header.body = @icmp_header
|
140
55
|
super(args)
|
141
56
|
self
|
142
57
|
end
|
@@ -173,7 +88,5 @@ module PacketFu
|
|
173
88
|
peek_data << "%04x" % self.ip_id
|
174
89
|
peek_data.join
|
175
90
|
end
|
176
|
-
|
177
91
|
end
|
178
|
-
|
179
92
|
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module PacketFu
|
2
|
+
# ICMPHeader is a complete ICMP struct, used in ICMPPacket. ICMP is
|
3
|
+
# typically used for network administration and connectivity testing.
|
4
|
+
#
|
5
|
+
# For more on ICMP packets, see
|
6
|
+
# http://www.networksorcery.com/enp/protocol/icmp.htm
|
7
|
+
#
|
8
|
+
# ==== Header Definition
|
9
|
+
#
|
10
|
+
# Int8 :icmp_type # Type
|
11
|
+
# Int8 :icmp_code # Code
|
12
|
+
# Int16 :icmp_sum Default: calculated # Checksum
|
13
|
+
# String :body
|
14
|
+
class ICMPHeader < Struct.new(:icmp_type, :icmp_code, :icmp_sum, :body)
|
15
|
+
|
16
|
+
include StructFu
|
17
|
+
|
18
|
+
def initialize(args={})
|
19
|
+
super(
|
20
|
+
Int8.new(args[:icmp_type]),
|
21
|
+
Int8.new(args[:icmp_code]),
|
22
|
+
Int16.new(args[:icmp_sum] || icmp_calc_sum),
|
23
|
+
StructFu::String.new.read(args[:body])
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the object in string form.
|
28
|
+
def to_s
|
29
|
+
self.to_a.map {|x| x.to_s}.join
|
30
|
+
end
|
31
|
+
|
32
|
+
# Reads a string to populate the object.
|
33
|
+
def read(str)
|
34
|
+
force_binary(str)
|
35
|
+
return self if str.nil?
|
36
|
+
self[:icmp_type].read(str[0,1])
|
37
|
+
self[:icmp_code].read(str[1,1])
|
38
|
+
self[:icmp_sum].read(str[2,2])
|
39
|
+
self[:body].read(str[4,str.size])
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
# Setter for the type.
|
44
|
+
def icmp_type=(i); typecast i; end
|
45
|
+
# Getter for the type.
|
46
|
+
def icmp_type; self[:icmp_type].to_i; end
|
47
|
+
# Setter for the code.
|
48
|
+
def icmp_code=(i); typecast i; end
|
49
|
+
# Getter for the code.
|
50
|
+
def icmp_code; self[:icmp_code].to_i; end
|
51
|
+
# Setter for the checksum. Note, this is calculated automatically with
|
52
|
+
# icmp_calc_sum.
|
53
|
+
def icmp_sum=(i); typecast i; end
|
54
|
+
# Getter for the checksum.
|
55
|
+
def icmp_sum; self[:icmp_sum].to_i; end
|
56
|
+
|
57
|
+
# Calculates and sets the checksum for the object.
|
58
|
+
def icmp_calc_sum
|
59
|
+
checksum = (icmp_type.to_i << 8) + icmp_code.to_i
|
60
|
+
chk_body = (body.to_s.size % 2 == 0 ? body.to_s : body.to_s + "\x00")
|
61
|
+
if 1.respond_to? :ord
|
62
|
+
chk_body.scan(/../).map { |x| (x[0].ord << 8) + x[1].ord }.each { |y| checksum += y }
|
63
|
+
else
|
64
|
+
chk_body.scan(/../).map { |x| (x[0] << 8) + x[1] }.each { |y| checksum += y }
|
65
|
+
end
|
66
|
+
checksum = checksum % 0xffff
|
67
|
+
checksum = 0xffff - checksum
|
68
|
+
checksum == 0 ? 0xffff : checksum
|
69
|
+
end
|
70
|
+
|
71
|
+
# Recalculates the calculatable fields for ICMP.
|
72
|
+
def icmp_recalc(arg=:all)
|
73
|
+
# How silly is this, you can't intern a symbol in ruby 1.8.7pl72?
|
74
|
+
# I'm this close to monkey patching Symbol so you can force it...
|
75
|
+
arg = arg.intern if arg.respond_to? :intern
|
76
|
+
case arg
|
77
|
+
when :icmp_sum
|
78
|
+
self.icmp_sum=icmp_calc_sum
|
79
|
+
when :all
|
80
|
+
self.icmp_sum=icmp_calc_sum
|
81
|
+
else
|
82
|
+
raise ArgumentError, "No such field `#{arg}'"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Readability aliases
|
87
|
+
|
88
|
+
def icmp_sum_readable
|
89
|
+
"0x%04x" % icmp_sum
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module PacketFu
|
2
|
+
# This Mixin simplifies access to the ICMPHeaders. Mix this in with your
|
3
|
+
# packet interface, and it will add methods that essentially delegate to
|
4
|
+
# the 'icmp_header' method (assuming that it is a ICMPHeader object)
|
5
|
+
module ICMPHeaderMixin
|
6
|
+
def icmp_type=(v); self.icmp_header.icmp_type= v; end
|
7
|
+
def icmp_type; self.icmp_header.icmp_type; end
|
8
|
+
def icmp_code=(v); self.icmp_header.icmp_code= v; end
|
9
|
+
def icmp_code; self.icmp_header.icmp_code; end
|
10
|
+
def icmp_sum=(v); self.icmp_header.icmp_sum= v; end
|
11
|
+
def icmp_sum; self.icmp_header.icmp_sum; end
|
12
|
+
def icmp_calc_sum; self.icmp_header.icmp_calc_sum; end
|
13
|
+
def icmp_recalc(*v); self.icmp_header.icmp_recalc(*v); end
|
14
|
+
def icmp_sum_readable; self.icmp_header.icmp_sum_readable; end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
data/lib/packetfu/protos/ip.rb
CHANGED
@@ -1,298 +1,10 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
|
4
|
-
# Octets implements the addressing scheme for IP.
|
5
|
-
#
|
6
|
-
# ==== Header Definition
|
7
|
-
#
|
8
|
-
# Int8 :o1
|
9
|
-
# Int8 :o2
|
10
|
-
# Int8 :o3
|
11
|
-
# Int8 :o4
|
12
|
-
class Octets < Struct.new(:o1, :o2, :o3, :o4)
|
13
|
-
include StructFu
|
14
|
-
|
15
|
-
def initialize(args={})
|
16
|
-
super(
|
17
|
-
Int8.new(args[:o1]),
|
18
|
-
Int8.new(args[:o2]),
|
19
|
-
Int8.new(args[:o3]),
|
20
|
-
Int8.new(args[:o4]))
|
21
|
-
end
|
22
|
-
|
23
|
-
# Returns the object in string form.
|
24
|
-
def to_s
|
25
|
-
self.to_a.map {|x| x.to_s}.join
|
26
|
-
end
|
27
|
-
|
28
|
-
# Reads a string to populate the object.
|
29
|
-
def read(str)
|
30
|
-
force_binary(str)
|
31
|
-
return self if str.nil?
|
32
|
-
self[:o1].read str[0,1]
|
33
|
-
self[:o2].read str[1,1]
|
34
|
-
self[:o3].read str[2,1]
|
35
|
-
self[:o4].read str[3,1]
|
36
|
-
self
|
37
|
-
end
|
38
|
-
|
39
|
-
# Returns an address in dotted-quad format.
|
40
|
-
def to_x
|
41
|
-
ip_str = [o1, o2, o3, o4].map {|x| x.to_i.to_s}.join('.')
|
42
|
-
IPAddr.new(ip_str).to_s
|
43
|
-
end
|
44
|
-
|
45
|
-
# Returns an address in numerical format.
|
46
|
-
def to_i
|
47
|
-
ip_str = [o1, o2, o3, o4].map {|x| x.to_i.to_s}.join('.')
|
48
|
-
IPAddr.new(ip_str).to_i
|
49
|
-
end
|
50
|
-
|
51
|
-
# Set the IP Address by reading a dotted-quad address.
|
52
|
-
def read_quad(str)
|
53
|
-
read([IPAddr.new(str).to_i].pack("N"))
|
54
|
-
end
|
1
|
+
require 'packetfu/protos/eth/header'
|
2
|
+
require 'packetfu/protos/eth/mixin'
|
55
3
|
|
56
|
-
|
57
|
-
|
58
|
-
# IPHeader is a complete IP struct, used in IPPacket. Most traffic on most networks today is IP-based.
|
59
|
-
#
|
60
|
-
# For more on IP packets, see http://www.networksorcery.com/enp/protocol/ip.htm
|
61
|
-
#
|
62
|
-
# ==== Header Definition
|
63
|
-
#
|
64
|
-
# Fixnum (4 bits) :ip_v, Default: 4
|
65
|
-
# Fixnum (4 bits) :ip_hl, Default: 5
|
66
|
-
# Int8 :ip_tos, Default: 0 # TODO: Break out the bits
|
67
|
-
# Int16 :ip_len, Default: calculated
|
68
|
-
# Int16 :ip_id, Default: calculated # IRL, hardly random.
|
69
|
-
# Int16 :ip_frag, Default: 0 # TODO: Break out the bits
|
70
|
-
# Int8 :ip_ttl, Default: 0xff # Changes per flavor
|
71
|
-
# Int8 :ip_proto, Default: 0x01 # TCP: 0x06, UDP 0x11, ICMP 0x01
|
72
|
-
# Int16 :ip_sum, Default: calculated
|
73
|
-
# Octets :ip_src
|
74
|
-
# Octets :ip_dst
|
75
|
-
# String :body
|
76
|
-
#
|
77
|
-
# Note that IPPackets will always be somewhat incorrect upon initalization,
|
78
|
-
# and want an IPHeader#recalc() to become correct before a
|
79
|
-
# Packet#to_f or Packet#to_w.
|
80
|
-
class IPHeader < Struct.new(:ip_v, :ip_hl, :ip_tos, :ip_len,
|
81
|
-
:ip_id, :ip_frag, :ip_ttl, :ip_proto,
|
82
|
-
:ip_sum, :ip_src, :ip_dst, :body)
|
83
|
-
include StructFu
|
84
|
-
|
85
|
-
def initialize(args={})
|
86
|
-
@random_id = rand(0xffff)
|
87
|
-
super(
|
88
|
-
(args[:ip_v] || 4),
|
89
|
-
(args[:ip_hl] || 5),
|
90
|
-
Int8.new(args[:ip_tos]),
|
91
|
-
Int16.new(args[:ip_len] || 20),
|
92
|
-
Int16.new(args[:ip_id] || ip_calc_id),
|
93
|
-
Int16.new(args[:ip_frag]),
|
94
|
-
Int8.new(args[:ip_ttl] || 32),
|
95
|
-
Int8.new(args[:ip_proto]),
|
96
|
-
Int16.new(args[:ip_sum] || ip_calc_sum),
|
97
|
-
Octets.new.read(args[:ip_src] || "\x00\x00\x00\x00"),
|
98
|
-
Octets.new.read(args[:ip_dst] || "\x00\x00\x00\x00"),
|
99
|
-
StructFu::String.new.read(args[:body])
|
100
|
-
)
|
101
|
-
end
|
4
|
+
require 'packetfu/protos/ip/header'
|
5
|
+
require 'packetfu/protos/ip/mixin'
|
102
6
|
|
103
|
-
|
104
|
-
def to_s
|
105
|
-
byte_v_hl = [(self.ip_v << 4) + self.ip_hl].pack("C")
|
106
|
-
byte_v_hl + (self.to_a[2,10].map {|x| x.to_s}.join)
|
107
|
-
end
|
108
|
-
|
109
|
-
# Reads a string to populate the object.
|
110
|
-
def read(str)
|
111
|
-
force_binary(str)
|
112
|
-
return self if str.nil?
|
113
|
-
self[:ip_v] = str[0,1].unpack("C").first >> 4
|
114
|
-
self[:ip_hl] = str[0,1].unpack("C").first.to_i & 0x0f
|
115
|
-
self[:ip_tos].read(str[1,1])
|
116
|
-
self[:ip_len].read(str[2,2])
|
117
|
-
self[:ip_id].read(str[4,2])
|
118
|
-
self[:ip_frag].read(str[6,2])
|
119
|
-
self[:ip_ttl].read(str[8,1])
|
120
|
-
self[:ip_proto].read(str[9,1])
|
121
|
-
self[:ip_sum].read(str[10,2])
|
122
|
-
self[:ip_src].read(str[12,4])
|
123
|
-
self[:ip_dst].read(str[16,4])
|
124
|
-
self[:body].read(str[20,str.size]) if str.size > 20
|
125
|
-
self
|
126
|
-
end
|
127
|
-
|
128
|
-
# Setter for the version.
|
129
|
-
def ip_v=(i); self[:ip_v] = i.to_i; end
|
130
|
-
# Getter for the version.
|
131
|
-
def ip_v; self[:ip_v].to_i; end
|
132
|
-
# Setter for the header length (divide by 4)
|
133
|
-
def ip_hl=(i); self[:ip_hl] = i.to_i; end
|
134
|
-
# Getter for the header length (multiply by 4)
|
135
|
-
def ip_hl; self[:ip_hl].to_i; end
|
136
|
-
# Setter for the differentiated services
|
137
|
-
def ip_tos=(i); typecast i; end
|
138
|
-
# Getter for the differentiated services
|
139
|
-
def ip_tos; self[:ip_tos].to_i; end
|
140
|
-
# Setter for total length.
|
141
|
-
def ip_len=(i); typecast i; end
|
142
|
-
# Getter for total length.
|
143
|
-
def ip_len; self[:ip_len].to_i; end
|
144
|
-
# Setter for the identication number.
|
145
|
-
def ip_id=(i); typecast i; end
|
146
|
-
# Getter for the identication number.
|
147
|
-
def ip_id; self[:ip_id].to_i; end
|
148
|
-
# Setter for the fragmentation ID.
|
149
|
-
def ip_frag=(i); typecast i; end
|
150
|
-
# Getter for the fragmentation ID.
|
151
|
-
def ip_frag; self[:ip_frag].to_i; end
|
152
|
-
# Setter for the time to live.
|
153
|
-
def ip_ttl=(i); typecast i; end
|
154
|
-
# Getter for the time to live.
|
155
|
-
def ip_ttl; self[:ip_ttl].to_i; end
|
156
|
-
# Setter for the protocol number.
|
157
|
-
def ip_proto=(i); typecast i; end
|
158
|
-
# Getter for the protocol number.
|
159
|
-
def ip_proto; self[:ip_proto].to_i; end
|
160
|
-
# Setter for the checksum.
|
161
|
-
def ip_sum=(i); typecast i; end
|
162
|
-
# Getter for the checksum.
|
163
|
-
def ip_sum; self[:ip_sum].to_i; end
|
164
|
-
# Setter for the source IP address.
|
165
|
-
def ip_src=(i)
|
166
|
-
case i
|
167
|
-
when Numeric
|
168
|
-
self[:ip_src] = Octets.new.read([i].pack("N"))
|
169
|
-
when Octets
|
170
|
-
self[:ip_src] = i
|
171
|
-
else
|
172
|
-
typecast i
|
173
|
-
end
|
174
|
-
end
|
175
|
-
# Getter for the source IP address.
|
176
|
-
def ip_src; self[:ip_src].to_i; end
|
177
|
-
# Setter for the destination IP address.
|
178
|
-
def ip_dst=(i)
|
179
|
-
case i
|
180
|
-
when Numeric
|
181
|
-
self[:ip_dst] = Octets.new.read([i].pack("N"))
|
182
|
-
when Octets
|
183
|
-
self[:ip_dst] = i
|
184
|
-
else
|
185
|
-
typecast i
|
186
|
-
end
|
187
|
-
end
|
188
|
-
# Getter for the destination IP address.
|
189
|
-
def ip_dst; self[:ip_dst].to_i; end
|
190
|
-
|
191
|
-
# Calulcate the true length of the packet.
|
192
|
-
def ip_calc_len
|
193
|
-
(ip_hl * 4) + body.to_s.length
|
194
|
-
end
|
195
|
-
|
196
|
-
# Return the claimed header length
|
197
|
-
def ip_hlen
|
198
|
-
(ip_hl * 4)
|
199
|
-
end
|
200
|
-
|
201
|
-
# Calculate the true checksum of the packet.
|
202
|
-
# (Yes, this is the long way to do it, but it's e-z-2-read for mathtards like me.)
|
203
|
-
def ip_calc_sum
|
204
|
-
checksum = (((self.ip_v << 4) + self.ip_hl) << 8) + self.ip_tos
|
205
|
-
checksum += self.ip_len
|
206
|
-
checksum += self.ip_id
|
207
|
-
checksum += self.ip_frag
|
208
|
-
checksum += (self.ip_ttl << 8) + self.ip_proto
|
209
|
-
checksum += (self.ip_src >> 16)
|
210
|
-
checksum += (self.ip_src & 0xffff)
|
211
|
-
checksum += (self.ip_dst >> 16)
|
212
|
-
checksum += (self.ip_dst & 0xffff)
|
213
|
-
checksum = checksum % 0xffff
|
214
|
-
checksum = 0xffff - checksum
|
215
|
-
checksum == 0 ? 0xffff : checksum
|
216
|
-
end
|
217
|
-
|
218
|
-
# Retrieve the IP ID
|
219
|
-
def ip_calc_id
|
220
|
-
@random_id
|
221
|
-
end
|
222
|
-
|
223
|
-
# Sets a more readable IP address. If you wants to manipulate individual octets,
|
224
|
-
# (eg, for host scanning in one network), it would be better use ip_src.o1 through
|
225
|
-
# ip_src.o4 instead.
|
226
|
-
def ip_saddr=(addr)
|
227
|
-
self[:ip_src].read_quad(addr)
|
228
|
-
end
|
229
|
-
|
230
|
-
# Returns a more readable IP source address.
|
231
|
-
def ip_saddr
|
232
|
-
self[:ip_src].to_x
|
233
|
-
end
|
234
|
-
|
235
|
-
# Sets a more readable IP address.
|
236
|
-
def ip_daddr=(addr)
|
237
|
-
self[:ip_dst].read_quad(addr)
|
238
|
-
end
|
239
|
-
|
240
|
-
# Returns a more readable IP destination address.
|
241
|
-
def ip_daddr
|
242
|
-
self[:ip_dst].to_x
|
243
|
-
end
|
244
|
-
|
245
|
-
# Translate various formats of IPv4 Addresses to an array of digits.
|
246
|
-
def self.octet_array(addr)
|
247
|
-
if addr.class == String
|
248
|
-
oa = addr.split('.').collect {|x| x.to_i}
|
249
|
-
elsif addr.class == Fixnum
|
250
|
-
oa = IPAddr.new(addr, Socket::AF_INET).to_s.split('.')
|
251
|
-
elsif addr.class == Bignum
|
252
|
-
oa = IPAddr.new(addr, Socket::AF_INET).to_s.split('.')
|
253
|
-
elsif addr.class == Array
|
254
|
-
oa = addr
|
255
|
-
else
|
256
|
-
raise ArgumentError, "IP Address should be a dotted quad string, an array of ints, or a bignum"
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
# Recalculate the calculated IP fields. Valid arguments are:
|
261
|
-
# :all
|
262
|
-
# :ip_len
|
263
|
-
# :ip_sum
|
264
|
-
# :ip_id
|
265
|
-
def ip_recalc(arg=:all)
|
266
|
-
case arg
|
267
|
-
when :ip_len
|
268
|
-
self.ip_len=ip_calc_len
|
269
|
-
when :ip_sum
|
270
|
-
self.ip_sum=ip_calc_sum
|
271
|
-
when :ip_id
|
272
|
-
@random_id = rand(0xffff)
|
273
|
-
when :all
|
274
|
-
self.ip_id= ip_calc_id
|
275
|
-
self.ip_len= ip_calc_len
|
276
|
-
self.ip_sum= ip_calc_sum
|
277
|
-
else
|
278
|
-
raise ArgumentError, "No such field `#{arg}'"
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
|
-
# Readability aliases
|
283
|
-
|
284
|
-
alias :ip_src_readable :ip_saddr
|
285
|
-
alias :ip_dst_readable :ip_daddr
|
286
|
-
|
287
|
-
def ip_id_readable
|
288
|
-
"0x%04x" % ip_id
|
289
|
-
end
|
290
|
-
|
291
|
-
def ip_sum_readable
|
292
|
-
"0x%04x" % ip_sum
|
293
|
-
end
|
294
|
-
|
295
|
-
end
|
7
|
+
module PacketFu
|
296
8
|
|
297
9
|
# IPPacket is used to construct IP packets. They contain an EthHeader, an IPHeader, and usually
|
298
10
|
# a transport-layer protocol such as UDPHeader, TCPHeader, or ICMPHeader.
|
@@ -322,6 +34,8 @@ module PacketFu
|
|
322
34
|
# :config
|
323
35
|
# A hash of return address details, often the output of Utils.whoami?
|
324
36
|
class IPPacket < Packet
|
37
|
+
include ::PacketFu::EthHeaderMixin
|
38
|
+
include ::PacketFu::IPHeaderMixin
|
325
39
|
|
326
40
|
attr_accessor :eth_header, :ip_header
|
327
41
|
|
@@ -343,8 +57,6 @@ module PacketFu
|
|
343
57
|
def read(str=nil, args={})
|
344
58
|
raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
|
345
59
|
@eth_header.read(str)
|
346
|
-
@ip_header.read(str[14,str.size])
|
347
|
-
@eth_header.body = @ip_header
|
348
60
|
super(args)
|
349
61
|
self
|
350
62
|
end
|