packetfu 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. data/.document +4 -0
  2. data/CHANGES +36 -0
  3. data/INSTALL +40 -0
  4. data/LICENSE +28 -0
  5. data/README +25 -0
  6. data/TODO +25 -0
  7. data/examples/ackscan.rb +38 -0
  8. data/examples/arp.rb +60 -0
  9. data/examples/arphood.rb +56 -0
  10. data/examples/ethernet.rb +10 -0
  11. data/examples/examples.rb +3 -0
  12. data/examples/ids.rb +4 -0
  13. data/examples/idsv2.rb +6 -0
  14. data/examples/oui.txt +84177 -0
  15. data/examples/packetfu-shell.rb +111 -0
  16. data/examples/simple-stats.rb +42 -0
  17. data/examples/slammer.rb +33 -0
  18. data/examples/uniqpcap.rb +15 -0
  19. data/lib/packetfu.rb +108 -0
  20. data/lib/packetfu/arp.rb +239 -0
  21. data/lib/packetfu/capture.rb +169 -0
  22. data/lib/packetfu/config.rb +55 -0
  23. data/lib/packetfu/eth.rb +264 -0
  24. data/lib/packetfu/icmp.rb +153 -0
  25. data/lib/packetfu/inject.rb +65 -0
  26. data/lib/packetfu/invalid.rb +41 -0
  27. data/lib/packetfu/ip.rb +318 -0
  28. data/lib/packetfu/ipv6.rb +230 -0
  29. data/lib/packetfu/packet.rb +492 -0
  30. data/lib/packetfu/pcap.rb +502 -0
  31. data/lib/packetfu/structfu.rb +274 -0
  32. data/lib/packetfu/tcp.rb +1061 -0
  33. data/lib/packetfu/udp.rb +210 -0
  34. data/lib/packetfu/utils.rb +182 -0
  35. data/test/all_tests.rb +37 -0
  36. data/test/ptest.rb +10 -0
  37. data/test/sample.pcap +0 -0
  38. data/test/sample2.pcap +0 -0
  39. data/test/test_arp.rb +135 -0
  40. data/test/test_eth.rb +90 -0
  41. data/test/test_icmp.rb +54 -0
  42. data/test/test_inject.rb +33 -0
  43. data/test/test_invalid.rb +28 -0
  44. data/test/test_ip.rb +69 -0
  45. data/test/test_ip6.rb +68 -0
  46. data/test/test_octets.rb +37 -0
  47. data/test/test_packet.rb +41 -0
  48. data/test/test_pcap.rb +210 -0
  49. data/test/test_structfu.rb +112 -0
  50. data/test/test_tcp.rb +327 -0
  51. data/test/test_udp.rb +73 -0
  52. metadata +144 -0
@@ -0,0 +1,153 @@
1
+ module PacketFu
2
+
3
+ # ICMPHeader is a complete ICMP struct, used in ICMPPacket. ICMP is typically used for network
4
+ # administration and connectivity testing.
5
+ #
6
+ # For more on ICMP packets, see 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
+ end
87
+
88
+ # ICMPPacket is used to construct ICMP Packets. They contain an EthHeader, an IPHeader, and a ICMPHeader.
89
+ #
90
+ # == Example
91
+ #
92
+ # icmp_pkt.new
93
+ # icmp_pkt.icmp_type = 8
94
+ # icmp_pkt.icmp_code = 0
95
+ # icmp_pkt.payload = "ABC, easy as 123. As simple as do-re-mi. ABC, 123, baby, you and me!"
96
+ #
97
+ # icmp_pkt.ip_saddr="1.2.3.4"
98
+ # icmp_pkt.ip_daddr="5.6.7.8"
99
+ #
100
+ # icmp_pkt.recalc
101
+ # icmp_pkt.to_f('/tmp/icmp.pcap')
102
+ #
103
+ # == Parameters
104
+ #
105
+ # :eth
106
+ # A pre-generated EthHeader object.
107
+ # :ip
108
+ # A pre-generated IPHeader object.
109
+ # :flavor
110
+ # TODO: Sets the "flavor" of the ICMP packet. Pings, in particular, often betray their true
111
+ # OS.
112
+ # :config
113
+ # A hash of return address details, often the output of Utils.whoami?
114
+ class ICMPPacket < Packet
115
+
116
+ attr_accessor :eth_header, :ip_header, :icmp_header
117
+
118
+ def initialize(args={})
119
+ @eth_header = EthHeader.new(args).read(args[:eth])
120
+ @ip_header = IPHeader.new(args).read(args[:ip])
121
+ @ip_header.ip_proto = 1
122
+ @icmp_header = ICMPHeader.new(args).read(args[:icmp])
123
+
124
+ @ip_header.body = @icmp_header
125
+ @eth_header.body = @ip_header
126
+
127
+ @headers = [@eth_header, @ip_header, @icmp_header]
128
+ super
129
+ end
130
+
131
+ # Peek provides summary data on packet contents.
132
+ def peek(args={})
133
+ peek_data = ["C "] # I is taken by IP
134
+ peek_data << "%-5d" % self.to_s.size
135
+ type = case self.icmp_type.to_i
136
+ when 8
137
+ "ping"
138
+ when 0
139
+ "pong"
140
+ else
141
+ "%02x-%02x" % [self.icmp_type, self.icmp_code]
142
+ end
143
+ peek_data << "%-21s" % "#{self.ip_saddr}:#{type}"
144
+ peek_data << "->"
145
+ peek_data << "%21s" % "#{self.ip_daddr}"
146
+ peek_data << "%23s" % "I:"
147
+ peek_data << "%04x" % self.ip_id
148
+ peek_data.join
149
+ end
150
+
151
+ end
152
+
153
+ end
@@ -0,0 +1,65 @@
1
+ module PacketFu
2
+
3
+ # The Inject class handles injecting arrays of binary data on the wire.
4
+ #
5
+ # To inject single packets, use PacketFu::Packet.to_w() instead.
6
+ class Inject
7
+ attr_accessor :array, :stream, :show_live # Leave these public and open.
8
+ attr_reader :iface, :snaplen, :promisc, :timeout # Cant change after the init.
9
+
10
+ def initialize(args={})
11
+ @array = [] # Where the packet array goes.
12
+ @stream = [] # Where the stream goes.
13
+ @iface = args[:iface] || ENV['IFACE'] || Pcap.lookupdev || "lo"
14
+ @snaplen = args[:snaplen] || 0xffff
15
+ @promisc = args[:promisc] || false # Sensible for some Intel wifi cards
16
+ @timeout = args[:timeout] || 1
17
+ @show_live = nil
18
+ end
19
+
20
+ # Takes an array, and injects them onto an interface. Note that
21
+ # complete packets (Ethernet headers on down) are expected.
22
+ #
23
+ # === Parameters
24
+ #
25
+ # :array || arr
26
+ # An array of binary data (usually packet.to_s style).
27
+ # :int || sleep
28
+ # Number of seconds to sleep between injections (in float format)
29
+ # :show_live || :live
30
+ # If true, puts data about what was injected to stdout.
31
+ #
32
+ # === Example
33
+ #
34
+ # inj = PacketFu::Inject.new
35
+ # inj.array_to_wire(:array => [pkt1, pkt2, pkt3], :sleep => 0.1)
36
+ #
37
+ def array_to_wire(args={})
38
+ pkt_array = args[:array] || args[:arr] || @array
39
+ interval = args[:int] || args[:sleep]
40
+ show_live = args[:show_live] || args[:live] || @show_live
41
+
42
+ @stream = Pcap.open_live(@iface,@snaplen,@promisc,@timeout)
43
+ pkt_count = 0
44
+ pkt_array.each do |pkt|
45
+ @stream.inject(pkt)
46
+ sleep interval if interval
47
+ pkt_count +=1
48
+ puts "Sent Packet \##{pkt_count} (#{pkt.size})" if show_live
49
+ end
50
+ # Return # of packets sent, array size, and array total size
51
+ [pkt_count, pkt_array.size, pkt_array.join.size]
52
+ end
53
+
54
+ # Equivalent to array_to_wire
55
+ def a2w(args={})
56
+ array_to_wire(args)
57
+ end
58
+
59
+ # Equivalent to array_to_wire
60
+ def inject(args={})
61
+ array_to_wire(args)
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,41 @@
1
+ module PacketFu
2
+
3
+ # InvalidHeader catches all packets that we don't already have a Struct for,
4
+ # or for whatever reason, violates some basic packet rules for other packet
5
+ # types.
6
+ class InvalidHeader < Struct.new(:body)
7
+ include StructFu
8
+
9
+ def initialize(args={})
10
+ args[:body] ||= StructFu::String.new
11
+ super(args[:body])
12
+ end
13
+
14
+ # Returns the object in string form.
15
+ def to_s
16
+ self.to_a.map {|x| x.to_s}.join
17
+ end
18
+
19
+ # Reads a string to populate the object.
20
+ def read(str)
21
+ force_binary(str)
22
+ return self if str.nil?
23
+ self[:body].read str
24
+ self
25
+ end
26
+
27
+ end
28
+
29
+ # You probably don't want to write invalid packets on purpose.
30
+ class InvalidPacket < Packet
31
+ attr_accessor :invalid_header
32
+
33
+ def initialize(args={})
34
+ @invalid_header = (args[:invalid] || InvalidHeader.new)
35
+ @headers = [@invalid_header]
36
+ end
37
+ end
38
+
39
+ end # module PacketFu
40
+
41
+ # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
@@ -0,0 +1,318 @@
1
+ require 'ipaddr'
2
+ module PacketFu
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
55
+
56
+ end
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
102
+
103
+ # Returns the object in string form.
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); typecast i; end
166
+ # Getter for the source IP address.
167
+ def ip_src; self[:ip_src].to_i; end
168
+ # Setter for the destination IP address.
169
+ def ip_dst=(i); typecast i; end
170
+ # Getter for the destination IP address.
171
+ def ip_dst; self[:ip_dst].to_i; end
172
+
173
+ # Calulcate the true length of the packet.
174
+ def ip_calc_len
175
+ (ip_hl * 4) + body.to_s.length
176
+ end
177
+
178
+ # Calculate the true checksum of the packet.
179
+ # (Yes, this is the long way to do it, but it's e-z-2-read for mathtards like me.)
180
+ def ip_calc_sum
181
+ checksum = (((self.ip_v << 4) + self.ip_hl) << 8) + self.ip_tos
182
+ checksum += self.ip_len
183
+ checksum += self.ip_id
184
+ checksum += self.ip_frag
185
+ checksum += (self.ip_ttl << 8) + self.ip_proto
186
+ checksum += (self.ip_src >> 16)
187
+ checksum += (self.ip_src & 0xffff)
188
+ checksum += (self.ip_dst >> 16)
189
+ checksum += (self.ip_dst & 0xffff)
190
+ checksum = checksum % 0xffff
191
+ checksum = 0xffff - checksum
192
+ checksum == 0 ? 0xffff : checksum
193
+ end
194
+
195
+ # Retrieve the IP ID
196
+ def ip_calc_id
197
+ @random_id
198
+ end
199
+
200
+ # Sets a more readable IP address. If you wants to manipulate individual octets,
201
+ # (eg, for host scanning in one network), it would be better use ip_src.o1 through
202
+ # ip_src.o4 instead.
203
+ def ip_saddr=(addr)
204
+ self[:ip_src].read_quad(addr)
205
+ end
206
+
207
+ # Returns a more readable IP source address.
208
+ def ip_saddr
209
+ self[:ip_src].to_x
210
+ end
211
+
212
+ # Sets a more readable IP address.
213
+ def ip_daddr=(addr)
214
+ self[:ip_dst].read_quad(addr)
215
+ end
216
+
217
+ # Returns a more readable IP destination address.
218
+ def ip_daddr
219
+ self[:ip_dst].to_x
220
+ end
221
+
222
+ # Translate various formats of IPv4 Addresses to an array of digits.
223
+ def self.octet_array(addr)
224
+ if addr.class == String
225
+ oa = addr.split('.').collect {|x| x.to_i}
226
+ elsif addr.class == Fixnum
227
+ oa = IPAddr.new(addr, Socket::AF_INET).to_s.split('.')
228
+ elsif addr.class == Bignum
229
+ oa = IPAddr.new(addr, Socket::AF_INET).to_s.split('.')
230
+ elsif addr.class == Array
231
+ oa = addr
232
+ else
233
+ raise ArgumentError, "IP Address should be a dotted quad string, an array of ints, or a bignum"
234
+ end
235
+ end
236
+
237
+ # Recalculate the calculated IP fields. Valid arguments are:
238
+ # :all
239
+ # :ip_len
240
+ # :ip_sum
241
+ # :ip_id
242
+ def ip_recalc(arg=:all)
243
+ case arg
244
+ when :ip_len
245
+ self.ip_len=ip_calc_len
246
+ when :ip_sum
247
+ self.ip_sum=ip_calc_sum
248
+ when :ip_id
249
+ @random_id = rand(0xffff)
250
+ when :all
251
+ self.ip_id= ip_calc_id
252
+ self.ip_len= ip_calc_len
253
+ self.ip_sum= ip_calc_sum
254
+ else
255
+ raise ArgumentError, "No such field `#{arg}'"
256
+ end
257
+ end
258
+
259
+ end
260
+
261
+ # IPPacket is used to construct IP packets. They contain an EthHeader, an IPHeader, and usually
262
+ # a transport-layer protocol such as UDPHeader, TCPHeader, or ICMPHeader.
263
+ #
264
+ # == Example
265
+ #
266
+ # require 'packetfu'
267
+ # ip_pkt = PacketFu::IPPacket.new
268
+ # ip_pkt.ip_saddr="10.20.30.40"
269
+ # ip_pkt.ip_daddr="192.168.1.1"
270
+ # ip_pkt.ip_proto=1
271
+ # ip_pkt.ip_ttl=64
272
+ # ip_pkt.ip_payload="\x00\x00\x12\x34\x00\x01\x00\x01"+
273
+ # "Lovingly hand-crafted echo responses delivered directly to your door."
274
+ # ip_pkt.recalc
275
+ # ip_pkt.to_f('/tmp/ip.pcap')
276
+ #
277
+ # == Parameters
278
+ #
279
+ # :eth
280
+ # A pre-generated EthHeader object.
281
+ # :ip
282
+ # A pre-generated IPHeader object.
283
+ # :flavor
284
+ # TODO: Sets the "flavor" of the IP packet. This might include known sets of IP options, and
285
+ # certainly known starting TTLs.
286
+ # :config
287
+ # A hash of return address details, often the output of Utils.whoami?
288
+ class IPPacket < Packet
289
+
290
+ attr_accessor :eth_header, :ip_header
291
+
292
+ # Creates a new IPPacket object.
293
+ def initialize(args={})
294
+ @eth_header = EthHeader.new(args).read(args[:eth])
295
+ @ip_header = IPHeader.new(args).read(args[:ip])
296
+ @eth_header.body=@ip_header
297
+
298
+ @headers = [@eth_header, @ip_header]
299
+ super
300
+ end
301
+
302
+ # Peek provides summary data on packet contents.
303
+ def peek(args={})
304
+ peek_data = ["I "]
305
+ peek_data << "%-5d" % to_s.size
306
+ peek_data << "%-21s" % "#{ip_saddr}"
307
+ peek_data << "->"
308
+ peek_data << "%21s" % "#{ip_daddr}"
309
+ peek_data << "%23s" % "I:"
310
+ peek_data << "%04x" % ip_id.to_i
311
+ peek_data.join
312
+ end
313
+
314
+ end
315
+
316
+ end
317
+
318
+ # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby