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.
- data/.document +4 -0
- data/CHANGES +36 -0
- data/INSTALL +40 -0
- data/LICENSE +28 -0
- data/README +25 -0
- data/TODO +25 -0
- data/examples/ackscan.rb +38 -0
- data/examples/arp.rb +60 -0
- data/examples/arphood.rb +56 -0
- data/examples/ethernet.rb +10 -0
- data/examples/examples.rb +3 -0
- data/examples/ids.rb +4 -0
- data/examples/idsv2.rb +6 -0
- data/examples/oui.txt +84177 -0
- data/examples/packetfu-shell.rb +111 -0
- data/examples/simple-stats.rb +42 -0
- data/examples/slammer.rb +33 -0
- data/examples/uniqpcap.rb +15 -0
- data/lib/packetfu.rb +108 -0
- data/lib/packetfu/arp.rb +239 -0
- data/lib/packetfu/capture.rb +169 -0
- data/lib/packetfu/config.rb +55 -0
- data/lib/packetfu/eth.rb +264 -0
- data/lib/packetfu/icmp.rb +153 -0
- data/lib/packetfu/inject.rb +65 -0
- data/lib/packetfu/invalid.rb +41 -0
- data/lib/packetfu/ip.rb +318 -0
- data/lib/packetfu/ipv6.rb +230 -0
- data/lib/packetfu/packet.rb +492 -0
- data/lib/packetfu/pcap.rb +502 -0
- data/lib/packetfu/structfu.rb +274 -0
- data/lib/packetfu/tcp.rb +1061 -0
- data/lib/packetfu/udp.rb +210 -0
- data/lib/packetfu/utils.rb +182 -0
- data/test/all_tests.rb +37 -0
- data/test/ptest.rb +10 -0
- data/test/sample.pcap +0 -0
- data/test/sample2.pcap +0 -0
- data/test/test_arp.rb +135 -0
- data/test/test_eth.rb +90 -0
- data/test/test_icmp.rb +54 -0
- data/test/test_inject.rb +33 -0
- data/test/test_invalid.rb +28 -0
- data/test/test_ip.rb +69 -0
- data/test/test_ip6.rb +68 -0
- data/test/test_octets.rb +37 -0
- data/test/test_packet.rb +41 -0
- data/test/test_pcap.rb +210 -0
- data/test/test_structfu.rb +112 -0
- data/test/test_tcp.rb +327 -0
- data/test/test_udp.rb +73 -0
- metadata +144 -0
@@ -0,0 +1,230 @@
|
|
1
|
+
module PacketFu
|
2
|
+
|
3
|
+
# AddrIpv6 handles addressing for IPv6Header
|
4
|
+
#
|
5
|
+
# ==== Header Definition
|
6
|
+
#
|
7
|
+
# Int32 :a1
|
8
|
+
# Int32 :a2
|
9
|
+
# Int32 :a3
|
10
|
+
# Int32 :a4
|
11
|
+
class AddrIpv6 < Struct.new(:a1, :a2, :a3, :a4)
|
12
|
+
|
13
|
+
include StructFu
|
14
|
+
|
15
|
+
def initialize(args={})
|
16
|
+
super(
|
17
|
+
Int32.new(args[:a1]),
|
18
|
+
Int32.new(args[:a2]),
|
19
|
+
Int32.new(args[:a3]),
|
20
|
+
Int32.new(args[:a4]))
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the address in string format.
|
24
|
+
def to_s
|
25
|
+
self.to_a.map {|x| x.to_s}.join
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns the address as a fairly ginormous integer.
|
29
|
+
def to_i
|
30
|
+
(a1.to_i << 96) + (a2.to_i << 64) + (a3.to_i << 32) + a4.to_i
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns the address as a colon-delimited hex string.
|
34
|
+
def to_x
|
35
|
+
IPAddr.new(self.to_i, Socket::AF_INET6).to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
# Reads in a string and casts it as an IPv6 address
|
39
|
+
def read(str)
|
40
|
+
force_binary(str)
|
41
|
+
return self if str.nil?
|
42
|
+
self[:a1].read str[0,4]
|
43
|
+
self[:a2].read str[4,4]
|
44
|
+
self[:a3].read str[8,4]
|
45
|
+
self[:a4].read str[12,4]
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
# Reads in a colon-delimited hex string and casts it as an IPv6 address.
|
50
|
+
def read_x(str)
|
51
|
+
addr = IPAddr.new(str).to_i
|
52
|
+
self[:a1]=Int32.new(addr >> 96)
|
53
|
+
self[:a2]=Int32.new((addr & 0x00000000ffffffff0000000000000000) >> 64)
|
54
|
+
self[:a3]=Int32.new((addr & 0x0000000000000000ffffffff00000000) >> 32)
|
55
|
+
self[:a4]=Int32.new(addr & 0x000000000000000000000000ffffffff)
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
# IPv6Header is complete IPv6 struct, used in IPv6Packet.
|
62
|
+
#
|
63
|
+
# ==== Header Definition
|
64
|
+
#
|
65
|
+
# Fixnum (4 bits) :ipv6_v Default: 6 # Versiom
|
66
|
+
# Fixnum (8 bits) :ipv6_class Defualt: 0 # Class
|
67
|
+
# Fixnum (20 bits) :ipv6_label Defualt: 0 # Label
|
68
|
+
# Int16 :ipv6_len Default: calc # Payload length
|
69
|
+
# Int8 :ipv6_next # Next Header
|
70
|
+
# Int8 :ipv6_hop Default: 0xff # Hop limit
|
71
|
+
# AddrIpv6 :ipv6_src
|
72
|
+
# AddrIpv6 :ipv6_dst
|
73
|
+
# String :body
|
74
|
+
class IPv6Header < Struct.new(:ipv6_v, :ipv6_class, :ipv6_label,
|
75
|
+
:ipv6_len, :ipv6_next, :ipv6_hop,
|
76
|
+
:ipv6_src, :ipv6_dst, :body)
|
77
|
+
include StructFu
|
78
|
+
|
79
|
+
def initialize(args={})
|
80
|
+
super(
|
81
|
+
(args[:ipv6_v] || 6),
|
82
|
+
(args[:ipv6_class] || 0),
|
83
|
+
(args[:ipv6_label] || 0),
|
84
|
+
Int16.new(args[:ipv6_len]),
|
85
|
+
Int8.new(args[:ipv6_next]),
|
86
|
+
Int8.new(args[:ipv6_hop] || 0xff),
|
87
|
+
AddrIpv6.new.read(args[:ipv6_src] || ("\x00" * 16)),
|
88
|
+
AddrIpv6.new.read(args[:ipv6_dst] || ("\x00" * 16)),
|
89
|
+
StructFu::String.new.read(args[:body])
|
90
|
+
)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Returns the object in string form.
|
94
|
+
def to_s
|
95
|
+
bytes_v_class_label = [(self.ipv6_v << 28) +
|
96
|
+
(self.ipv6_class << 20) +
|
97
|
+
self.ipv6_label].pack("N")
|
98
|
+
bytes_v_class_label + (self.to_a[3,6].map {|x| x.to_s}.join)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Reads a string to populate the object.
|
102
|
+
def read(str)
|
103
|
+
force_binary(str)
|
104
|
+
return self if str.nil?
|
105
|
+
self[:ipv6_v] = str[0,1].unpack("C").first >> 4
|
106
|
+
self[:ipv6_class] = (str[0,2].unpack("n").first & 0x0ff0) >> 4
|
107
|
+
self[:ipv6_label] = str[0,4].unpack("N").first & 0x000fffff
|
108
|
+
self[:ipv6_len].read(str[4,2])
|
109
|
+
self[:ipv6_next].read(str[6,1])
|
110
|
+
self[:ipv6_hop].read(str[7,1])
|
111
|
+
self[:ipv6_src].read(str[8,16])
|
112
|
+
self[:ipv6_dst].read(str[24,16])
|
113
|
+
self[:body].read(str[40,str.size]) if str.size > 40
|
114
|
+
self
|
115
|
+
end
|
116
|
+
|
117
|
+
# Setter for the version (usually, 6).
|
118
|
+
def ipv6_v=(i); self[:ip_v] = i.to_i; end
|
119
|
+
# Getter for the version (usually, 6).
|
120
|
+
def ipv6_v; self[:ipv6_v].to_i; end
|
121
|
+
# Setter for the traffic class.
|
122
|
+
def ipv6_class=(i); self[:ip_class] = i.to_i; end
|
123
|
+
# Getter for the traffic class.
|
124
|
+
def ipv6_class; self[:ipv6_class].to_i; end
|
125
|
+
# Setter for the flow label.
|
126
|
+
def ipv6_label=(i); self[:ip_label] = i.to_i; end
|
127
|
+
# Getter for the flow label.
|
128
|
+
def ipv6_label; self[:ipv6_label].to_i; end
|
129
|
+
# Setter for the payload length.
|
130
|
+
def ipv6_len=(i); typecast i; end
|
131
|
+
# Getter for the payload length.
|
132
|
+
def ipv6_len; self[:ipv6_len].to_i; end
|
133
|
+
# Setter for the next protocol header.
|
134
|
+
def ipv6_next=(i); typecast i; end
|
135
|
+
# Getter for the next protocol header.
|
136
|
+
def ipv6_next; self[:ipv6_next].to_i; end
|
137
|
+
# Setter for the hop limit.
|
138
|
+
def ipv6_hop=(i); typecast i; end
|
139
|
+
# Getter for the hop limit.
|
140
|
+
def ipv6_hop; self[:ipv6_hop].to_i; end
|
141
|
+
# Setter for the source address.
|
142
|
+
def ipv6_src=(i); typecast i; end
|
143
|
+
# Getter for the source address.
|
144
|
+
def ipv6_src; self[:ipv6_src].to_i; end
|
145
|
+
# Setter for the destination address.
|
146
|
+
def ipv6_dst=(i); typecast i; end
|
147
|
+
# Getter for the destination address.
|
148
|
+
def ipv6_dst; self[:ipv6_dst].to_i; end
|
149
|
+
|
150
|
+
# Calculates the payload length.
|
151
|
+
def ipv6_calc_len
|
152
|
+
self[:ipv6_len] = body.to_s.length
|
153
|
+
end
|
154
|
+
|
155
|
+
# Recalculates the calculatable fields for this object.
|
156
|
+
def ipv6_recalc(arg=:all)
|
157
|
+
case arg
|
158
|
+
when :ipv6_len
|
159
|
+
ipv6_calc_len
|
160
|
+
when :all
|
161
|
+
ipv6_recalc(:len)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Get the source address in a more readable form.
|
166
|
+
def ipv6_saddr
|
167
|
+
self[:ipv6_src].to_x
|
168
|
+
end
|
169
|
+
|
170
|
+
# Set the source address in a more readable form.
|
171
|
+
def ipv6_saddr=(str)
|
172
|
+
self[:ipv6_src].read_x(str)
|
173
|
+
end
|
174
|
+
|
175
|
+
# Get the destination address in a more readable form.
|
176
|
+
def ipv6_daddr
|
177
|
+
self[:ipv6_dst].to_x
|
178
|
+
end
|
179
|
+
|
180
|
+
# Set the destination address in a more readable form.
|
181
|
+
def ipv6_daddr=(str)
|
182
|
+
self[:ipv6_dst].read_x(str)
|
183
|
+
end
|
184
|
+
|
185
|
+
end # class IPv6Header
|
186
|
+
|
187
|
+
# IPv6Packet is used to construct IPv6 Packets. They contain an EthHeader and an IPv6Header, and in
|
188
|
+
# the distant, unknowable future, will take interesting IPv6ish payloads.
|
189
|
+
#
|
190
|
+
# This mostly complete, but not very useful. It's intended primarily as an example protocol.
|
191
|
+
#
|
192
|
+
# == Parameters
|
193
|
+
#
|
194
|
+
# :eth
|
195
|
+
# A pre-generated EthHeader object.
|
196
|
+
# :ip
|
197
|
+
# A pre-generated IPHeader object.
|
198
|
+
# :flavor
|
199
|
+
# TODO: Sets the "flavor" of the IPv6 packet. No idea what this will look like, haven't done much IPv6 fingerprinting.
|
200
|
+
# :config
|
201
|
+
# A hash of return address details, often the output of Utils.whoami?
|
202
|
+
class IPv6Packet < Packet
|
203
|
+
|
204
|
+
attr_accessor :eth_header, :ipv6_header
|
205
|
+
|
206
|
+
def initialize(args={})
|
207
|
+
@eth_header = (args[:eth] || EthHeader.new)
|
208
|
+
@ipv6_header = (args[:ipv6] || IPv6Header.new)
|
209
|
+
@eth_header.eth_proto = 0x86dd
|
210
|
+
@eth_header.body=@ipv6_header
|
211
|
+
|
212
|
+
@headers = [@eth_header, @ipv6_header]
|
213
|
+
super
|
214
|
+
end
|
215
|
+
|
216
|
+
# Peek provides summary data on packet contents.
|
217
|
+
def peek(args={})
|
218
|
+
peek_data = ["6 "]
|
219
|
+
peek_data << "%-5d" % self.to_s.size
|
220
|
+
peek_data << "%-31s" % self.ipv6_saddr
|
221
|
+
peek_data << "-> "
|
222
|
+
peek_data << "%-31s" % self.ipv6_daddr
|
223
|
+
peek_data << " N:"
|
224
|
+
peek_data << self.ipv6_next.to_s(16)
|
225
|
+
peek_data.join
|
226
|
+
end
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
@@ -0,0 +1,492 @@
|
|
1
|
+
module PacketFu
|
2
|
+
|
3
|
+
# Packet is the parent class of EthPacket, IPPacket, UDPPacket, TCPPacket, and all
|
4
|
+
# other packets.
|
5
|
+
class Packet
|
6
|
+
attr_reader :flavor # Packet Headers are responsible for their own specific flavor methods.
|
7
|
+
attr_accessor :headers # All packets have a header collection, useful for determining protocol trees.
|
8
|
+
attr_accessor :iface # Default inferface to send packets to
|
9
|
+
|
10
|
+
# Force strings into binary.
|
11
|
+
def self.force_binary(str)
|
12
|
+
str.force_encoding "binary" if str.respond_to? :force_encoding
|
13
|
+
end
|
14
|
+
|
15
|
+
# Parse() creates the correct packet type based on the data, and returns the apporpiate
|
16
|
+
# Packet subclass.
|
17
|
+
#
|
18
|
+
# There is an assumption here that all incoming packets are either EthPacket
|
19
|
+
# or InvalidPacket types.
|
20
|
+
#
|
21
|
+
# New packet types should get an entry here.
|
22
|
+
def self.parse(packet,args={})
|
23
|
+
force_binary(packet)
|
24
|
+
if packet.size >= 14 # Min size for Ethernet. No check for max size, yet.
|
25
|
+
case packet[12,2] # Check the Eth protocol field.
|
26
|
+
when "\x08\x00" # It's IP.
|
27
|
+
if 1.respond_to? :ord
|
28
|
+
ipv = packet[14,1][0].ord >> 4
|
29
|
+
else
|
30
|
+
ipv = packet[14,1][0] >> 4
|
31
|
+
end
|
32
|
+
case ipv # Check the IP version field.
|
33
|
+
when 4; # It's IPv4.
|
34
|
+
case packet[23,1] # Check the IP protocol field.
|
35
|
+
when "\x06"; p = TCPPacket.new # Returns a TCPPacket.
|
36
|
+
when "\x11"; p = UDPPacket.new # Returns a UDPPacket.
|
37
|
+
when "\x01"; p = ICMPPacket.new # Returns an ICMPPacket.
|
38
|
+
else; p = IPPacket.new # Returns an IPPacket since we can't tell the transport layer.
|
39
|
+
end
|
40
|
+
else; p = IPPacket.new # Returns an EthPacket since we don't know any other IP version.
|
41
|
+
end
|
42
|
+
when "\x08\x06" # It's arp
|
43
|
+
if packet.size >= 28 # Min size for complete arp
|
44
|
+
p = ARPPacket.new
|
45
|
+
else; p = EthPacket.new # Returns an EthPacket since we can't deal with tiny arps.
|
46
|
+
end
|
47
|
+
when "\x86\xdd" # It's IPv6
|
48
|
+
if packet.size >= 54 # Min size for a complete IPv6 packet.
|
49
|
+
p = IPv6Packet.new
|
50
|
+
else; p = EthPacket.new # Returns an EthPacket since we can't deal with tiny Ipv6.
|
51
|
+
end
|
52
|
+
else; p = EthPacket.new # Returns an EthPacket since we can't tell the network layer.
|
53
|
+
end
|
54
|
+
else
|
55
|
+
p = InvalidPacket.new # Not the right size for Ethernet (jumbo frames are okay)
|
56
|
+
end
|
57
|
+
parsed_packet = p.read(packet,args)
|
58
|
+
return parsed_packet
|
59
|
+
end
|
60
|
+
|
61
|
+
#method_missing() delegates protocol-specific field actions to the apporpraite
|
62
|
+
#class variable (which contains the associated packet type)
|
63
|
+
#This register-of-protocols style switch will work for the
|
64
|
+
#forseeable future (there aren't /that/ many packet types), and it's a handy
|
65
|
+
#way to know at a glance what packet types are supported.
|
66
|
+
def method_missing(sym, *args)
|
67
|
+
case sym.to_s
|
68
|
+
when /^invalid_/
|
69
|
+
@invalid_header.send(sym,*args)
|
70
|
+
when /^eth_/
|
71
|
+
@eth_header.send(sym,*args)
|
72
|
+
when /^arp_/
|
73
|
+
@arp_header.send(sym,*args)
|
74
|
+
when /^ip_/
|
75
|
+
@ip_header.send(sym,*args)
|
76
|
+
when /^icmp_/
|
77
|
+
@icmp_header.send(sym,*args)
|
78
|
+
when /^udp_/
|
79
|
+
@udp_header.send(sym,*args)
|
80
|
+
when /^tcp_/
|
81
|
+
@tcp_header.send(sym,*args)
|
82
|
+
when /^ipv6_/
|
83
|
+
@ipv6_header.send(sym,*args)
|
84
|
+
else
|
85
|
+
raise NoMethodError, "Unknown method `#{sym}' for this packet object."
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Get the binary string of the entire packet.
|
90
|
+
def to_s
|
91
|
+
@headers[0].to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
# In the event of no proper decoding, at least send it to the inner-most header.
|
95
|
+
def write(io)
|
96
|
+
@headers[0].write(io)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Get the outermost payload (body) of the packet; this is why all packet headers
|
100
|
+
# should have a body type.
|
101
|
+
def payload
|
102
|
+
@headers.last.body
|
103
|
+
end
|
104
|
+
|
105
|
+
# Set the outermost payload (body) of the packet.
|
106
|
+
def payload=(args)
|
107
|
+
@headers.last.body=(args)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Converts a packet to libpcap format. Bit of a hack?
|
111
|
+
def to_pcap(args={})
|
112
|
+
p = PcapPacket.new(:endian => args[:endian],
|
113
|
+
:timestamp => Timestamp.new.to_s,
|
114
|
+
:incl_len => self.to_s.size,
|
115
|
+
:orig_len => self.to_s.size,
|
116
|
+
:data => self)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Put the entire packet into a libpcap file. XXX: this is a
|
120
|
+
# hack for now just to confirm that packets are getting created
|
121
|
+
# correctly. Now with append! XXX: Document this!
|
122
|
+
def to_f(filename=nil,mode='w')
|
123
|
+
filename ||= 'out.pcap'
|
124
|
+
mode = mode.to_s[0,1] + "b"
|
125
|
+
raise ArgumentError, "Unknown mode: #{mode.to_s}" unless mode =~ /^[wa]/
|
126
|
+
if(mode == 'w' || !(File.exists?(filename)))
|
127
|
+
data = [PcapHeader.new, self.to_pcap].map {|x| x.to_s}.join
|
128
|
+
else
|
129
|
+
data = self.to_pcap
|
130
|
+
end
|
131
|
+
File.open(filename, mode) {|f| f.write data}
|
132
|
+
return [filename, 1, data.size]
|
133
|
+
end
|
134
|
+
|
135
|
+
# Put the entire packet on the wire by creating a temporary PacketFu::Inject object.
|
136
|
+
# TODO: Do something with auto-checksumming?
|
137
|
+
def to_w(iface=nil)
|
138
|
+
iface = iface || self.iface || PacketFu::Config.new.config[:iface]
|
139
|
+
inj = PacketFu::Inject.new(:iface => iface)
|
140
|
+
inj.array = [@headers[0].to_s]
|
141
|
+
inj.inject
|
142
|
+
end
|
143
|
+
|
144
|
+
# Recalculates all the calcuated fields for all headers in the packet.
|
145
|
+
# This is important since read() wipes out all the calculated fields
|
146
|
+
# such as length and checksum and what all.
|
147
|
+
def recalc(arg=:all)
|
148
|
+
case arg
|
149
|
+
when :ip
|
150
|
+
ip_recalc(:all)
|
151
|
+
when :icmp
|
152
|
+
icmp_recalc(:all)
|
153
|
+
when :udp
|
154
|
+
udp_recalc(:all)
|
155
|
+
when :tcp
|
156
|
+
tcp_recalc(:all)
|
157
|
+
when :all
|
158
|
+
ip_recalc(:all) if @ip_header
|
159
|
+
icmp_recalc(:all) if @icmp_header
|
160
|
+
udp_recalc(:all) if @udp_header
|
161
|
+
tcp_recalc(:all) if @tcp_header
|
162
|
+
else
|
163
|
+
raise ArgumentError, "Recalculating `#{arg}' unsupported. Try :all"
|
164
|
+
end
|
165
|
+
@headers[0]
|
166
|
+
end
|
167
|
+
|
168
|
+
# Read() takes (and trusts) the io input and shoves it all into a well-formed Packet.
|
169
|
+
# Note that read is a destructive process, so any existing data will be lost.
|
170
|
+
#
|
171
|
+
# TODO: This giant if tree is a mess, and worse, is decieving. You need to define
|
172
|
+
# actions both here and in parse(). All read() does is make a (good) guess as to
|
173
|
+
# what @headers to expect, and reads data to them.
|
174
|
+
#
|
175
|
+
# To take strings and turn them into packets without knowing ahead of time what kind of
|
176
|
+
# packet it is, use Packet.parse instead; parse() handles the figuring-out part.
|
177
|
+
#
|
178
|
+
# A note on the :strip => true argument: If :strip is set, defined lengths of data will
|
179
|
+
# be believed, and any trailers (such as frame check sequences) will be chopped off. This
|
180
|
+
# helps to ensure well-formed packets, at the cost of losing perhaps important FCS data.
|
181
|
+
#
|
182
|
+
# If :strip is false, header lengths are /not/ believed, and all data will be piped in.
|
183
|
+
# When capturing from the wire, this is usually fine, but recalculating the length before
|
184
|
+
# saving or re-transmitting will absolutely change the data payload; FCS data will become
|
185
|
+
# part of the TCP data as far as tcp_len is concerned. Some effort has been made to preserve
|
186
|
+
# the "real" payload for the purposes of checksums, but currently, it's impossible to seperate
|
187
|
+
# new payload data from old trailers, so things like pkt.payload += "some data" will not work
|
188
|
+
# correctly.
|
189
|
+
#
|
190
|
+
# So, to summarize; if you intend to alter the data, use :strip. If you don't, don't. Also,
|
191
|
+
# this is a horrid XXX hack. Stripping is useful (and fun!), but the default behavior really
|
192
|
+
# should be to create payloads correctly, and /not/ treat extra FCS data as a payload.
|
193
|
+
#
|
194
|
+
# Update: This scheme is so lame. Need to fix. Seriously.
|
195
|
+
# Update: still sucks. Really.
|
196
|
+
def read(io,args={})
|
197
|
+
begin
|
198
|
+
if io.size >= 14
|
199
|
+
@eth_header.read(io)
|
200
|
+
eth_proto_num = io[12,2].unpack("n")[0]
|
201
|
+
if eth_proto_num == 0x0800 # It's IP.
|
202
|
+
if 1.respond_to? :ord
|
203
|
+
ipv = io[14].ord
|
204
|
+
else
|
205
|
+
ipv = io[14]
|
206
|
+
end
|
207
|
+
ip_hlen=(ipv & 0x0f) * 4
|
208
|
+
ip_ver=(ipv >> 4) # It's IPv4. Other versions, all bets are off!
|
209
|
+
if ip_ver == 4
|
210
|
+
ip_proto_num = io[23,1].unpack("C")[0]
|
211
|
+
@ip_header.read(io[14,ip_hlen])
|
212
|
+
if ip_proto_num == 0x06 # It's TCP.
|
213
|
+
tcp_len = io[16,2].unpack("n")[0] - 20
|
214
|
+
if args[:strip] # Drops trailers like frame check sequence (FCS). Often desired for cleaner packets.
|
215
|
+
tcp_all = io[ip_hlen+14,tcp_len] # Believe the tcp_len value; chop off anything that's not in range.
|
216
|
+
else
|
217
|
+
tcp_all = io[ip_hlen+14,0xffff] # Don't believe the tcp_len value; suck everything up.
|
218
|
+
end
|
219
|
+
tcp_hlen = ((tcp_all[12,1].unpack("C")[0]) >> 4) * 4
|
220
|
+
if tcp_hlen.to_i >= 20
|
221
|
+
@tcp_header.read(tcp_all)
|
222
|
+
@ip_header.body = @tcp_header
|
223
|
+
else # It's a TCP packet with an impossibly small hlen, so it can't be real TCP. Abort! Abort!
|
224
|
+
@ip_header.body = io[16,io.size-16]
|
225
|
+
end
|
226
|
+
elsif ip_proto_num == 0x11 # It's UDP.
|
227
|
+
udp_len = io[16,2].unpack("n")[0] - 20
|
228
|
+
if args[:strip] # Same deal as with TCP. We might have stuff at the end of the packet that's not part of the payload.
|
229
|
+
@udp_header.read(io[ip_hlen+14,udp_len])
|
230
|
+
else # ... Suck it all up. BTW, this will change the lengths if they are ever recalc'ed. Bummer.
|
231
|
+
@udp_header.read(io[ip_hlen+14,0xffff])
|
232
|
+
end
|
233
|
+
@ip_header.body = @udp_header
|
234
|
+
elsif ip_proto_num == 1 # It's ICMP
|
235
|
+
@icmp_header.read(io[ip_hlen+14,0xffff])
|
236
|
+
@ip_header.body = @icmp_header
|
237
|
+
else # It's an IP packet for a protocol we don't have a decoder for.
|
238
|
+
@ip_header.body = io[16,io.size-16]
|
239
|
+
end
|
240
|
+
else # It's not IPv4, so no idea what should come next. Just dump it all into an ip_header and ip payload.
|
241
|
+
@ip_header.read(io[14,ip_hlen])
|
242
|
+
@ip_header.body = io[16,io.size-16]
|
243
|
+
end
|
244
|
+
@eth_header.body = @ip_header
|
245
|
+
elsif eth_proto_num == 0x0806 # It's ARP
|
246
|
+
@arp_header.read(io[14,0xffff]) # You'll nearly have a trailer and you'll never know what size.
|
247
|
+
@eth_header.body=@arp_header
|
248
|
+
@eth_header.body
|
249
|
+
elsif eth_proto_num == 0x86dd # It's IPv6
|
250
|
+
@ipv6_header.read(io[14,0xffff])
|
251
|
+
@eth_header.body=@ipv6_header
|
252
|
+
else # It's an Ethernet packet for a protocol we don't have a decoder for
|
253
|
+
@eth_header.body = io[14,io.size-14]
|
254
|
+
end
|
255
|
+
if (args[:fix] || args[:recalc])
|
256
|
+
# Unfortunately, we cannot simply recalc with abandon, since
|
257
|
+
# we may have unaccounted trailers that will sneak into the checksum.
|
258
|
+
# The better way to handle this is to put trailers in their own
|
259
|
+
# StructFu field, but I'm not a-gonna right now. :/
|
260
|
+
ip_recalc(:ip_sum) if respond_to? :ip_header
|
261
|
+
recalc(:tcp) if respond_to? :tcp_header
|
262
|
+
recalc(:udp) if respond_to? :udp_header
|
263
|
+
end
|
264
|
+
else # You're not big enough for Ethernet.
|
265
|
+
@invalid_header.read(io)
|
266
|
+
end
|
267
|
+
# @headers[0]
|
268
|
+
self
|
269
|
+
rescue ::Exception => e
|
270
|
+
# remove last header
|
271
|
+
# nested_types = self.headers.collect {|header| header.class}
|
272
|
+
# nested_types.pop # whatever this packet type is, we weren't able to parse it
|
273
|
+
self.headers.pop
|
274
|
+
return_header_type = self.headers[self.headers.length-1].class.to_s
|
275
|
+
retklass = PacketFu::InvalidPacket
|
276
|
+
seekpos = 0
|
277
|
+
target_header = @invalid_header
|
278
|
+
case return_header_type.to_s
|
279
|
+
when "PacketFu::EthHeader"
|
280
|
+
retklass = PacketFu::EthPacket
|
281
|
+
seekpos = 0x0e
|
282
|
+
target_header = @eth_header
|
283
|
+
when "PacketFu::IPHeader"
|
284
|
+
retklass = PacketFu::IPPacket
|
285
|
+
seekpos = 0x0e + @ip_header.ip_hl * 4
|
286
|
+
target_header = @ip_header
|
287
|
+
when "PacketFu::TCPHeader"
|
288
|
+
retklass = PacketFu::TCPPacket
|
289
|
+
seekpos = 0x0e + @ip_header.ip_hl * 4 + @tcpheader.tcp_hlen
|
290
|
+
target_header = @tcp_header
|
291
|
+
when "PacketFu::UDPHeader"
|
292
|
+
retklass = PacketFu::UDPPacket
|
293
|
+
when "PacketFu::ARPHeader"
|
294
|
+
retklass = PacketFu::ARPPacket
|
295
|
+
when "PacketFu::ICMPHeader"
|
296
|
+
retklass = PacketFu::ICMPPacket
|
297
|
+
when "PacketFu::IPv6Header"
|
298
|
+
retklass = PacketFu::IPv6Packet
|
299
|
+
else
|
300
|
+
end
|
301
|
+
|
302
|
+
io = io[seekpos,io.length - seekpos]
|
303
|
+
target_header.body = io
|
304
|
+
p = retklass.new
|
305
|
+
p.headers = self.headers
|
306
|
+
p
|
307
|
+
raise e if $debug
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
# Peek provides summary data on packet contents.
|
312
|
+
# Each packet type should provide its own peek method, and shouldn't exceed 80 characters wide (for
|
313
|
+
# easy reading in normal irb shells). If they don't, this default summary will step in.
|
314
|
+
def peek(args={})
|
315
|
+
peek_data = ["? "]
|
316
|
+
peek_data << "%-5d" % self.to_s.size
|
317
|
+
peek_data << "%68s" % self.to_s[0,34].unpack("H*")[0]
|
318
|
+
peek_data.join
|
319
|
+
end
|
320
|
+
|
321
|
+
# Hexify provides a neatly-formatted dump of binary data, familar to hex readers.
|
322
|
+
def hexify(str)
|
323
|
+
hexascii_lines = str.to_s.unpack("H*")[0].scan(/.{1,32}/)
|
324
|
+
chars = str.to_s.gsub(/[\x00-\x1f\x7f-\xff]/,'.')
|
325
|
+
chars_lines = chars.scan(/.{1,16}/)
|
326
|
+
ret = []
|
327
|
+
hexascii_lines.size.times {|i| ret << "%-48s %s" % [hexascii_lines[i].gsub(/(.{2})/,"\\1 "),chars_lines[i]]}
|
328
|
+
ret.join("\n")
|
329
|
+
end
|
330
|
+
|
331
|
+
# Returns a hex-formatted representation of the packet.
|
332
|
+
#
|
333
|
+
# ==== Arguments
|
334
|
+
#
|
335
|
+
# 0..9 : If a number is given only the layer in @header[arg] will be displayed. Note that this will include all @headers included in that header.
|
336
|
+
# :layers : If :layers is specified, the dump will return an array of headers by layer level.
|
337
|
+
# :all : An alias for arg=0.
|
338
|
+
#
|
339
|
+
# ==== Examples
|
340
|
+
#
|
341
|
+
# irb(main):003:0> pkt = TCPPacket.new
|
342
|
+
# irb(main):003:0> puts pkt.inspect_hex(:layers)
|
343
|
+
# 00 1a c5 00 00 00 00 1a c5 00 00 00 08 00 45 00 ..............E.
|
344
|
+
# 00 28 83 ce 00 00 ff 06 38 02 00 00 00 00 00 00 .(......8.......
|
345
|
+
# 00 00 a6 0f 00 00 ac 89 7b 26 00 00 00 00 50 00 ........{&....P.
|
346
|
+
# 40 00 a2 25 00 00 @..%..
|
347
|
+
# 45 00 00 28 83 ce 00 00 ff 06 38 02 00 00 00 00 E..(......8.....
|
348
|
+
# 00 00 00 00 a6 0f 00 00 ac 89 7b 26 00 00 00 00 ..........{&....
|
349
|
+
# 50 00 40 00 a2 25 00 00 P.@..%..
|
350
|
+
# a6 0f 00 00 ac 89 7b 26 00 00 00 00 50 00 40 00 ......{&....P.@.
|
351
|
+
# a2 25 00 00 .%..
|
352
|
+
# => nil
|
353
|
+
# irb(main):004:0> puts pkt.inspect_hex(:layers)[2]
|
354
|
+
# a6 0f 00 00 ac 89 7b 26 00 00 00 00 50 00 40 00 ......{&....P.@.
|
355
|
+
# a2 25 00 00 .%..
|
356
|
+
# => nil
|
357
|
+
#
|
358
|
+
# TODO: Colorize this! Everyone loves colorized irb output.
|
359
|
+
def inspect_hex(arg=0)
|
360
|
+
case arg
|
361
|
+
when :layers
|
362
|
+
ret = []
|
363
|
+
@headers.size.times do |i|
|
364
|
+
ret << hexify(@headers[i])
|
365
|
+
end
|
366
|
+
ret
|
367
|
+
when (0..9)
|
368
|
+
if @headers[arg]
|
369
|
+
hexify(@headers[arg])
|
370
|
+
else
|
371
|
+
nil
|
372
|
+
end
|
373
|
+
when :all
|
374
|
+
inspect_hex(0)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
# For packets, inspect is overloaded as inspect_hex(0).
|
379
|
+
# Not sure if this is a great idea yet, but it sure makes
|
380
|
+
# the irb output more sane.
|
381
|
+
#
|
382
|
+
# If you hate this, you can run PacketFu.toggle_inspect to return
|
383
|
+
# to the typical (and often unreadable) Object#inspect format.
|
384
|
+
def inspect
|
385
|
+
self.proto.join("|") + "\n" + self.inspect_hex
|
386
|
+
end
|
387
|
+
|
388
|
+
# Returns the size of the packet (as a binary string)
|
389
|
+
def size
|
390
|
+
self.to_s.size
|
391
|
+
end
|
392
|
+
|
393
|
+
# Returns an array of protocols contained in this packet. For example:
|
394
|
+
#
|
395
|
+
# t = PacketFu::TCPPacket.new
|
396
|
+
# => 00 1a c5 00 00 00 00 1a c5 00 00 00 08 00 45 00 ..............E.
|
397
|
+
# 00 28 3c ab 00 00 ff 06 7f 25 00 00 00 00 00 00 .(<......%......
|
398
|
+
# 00 00 93 5e 00 00 ad 4f e4 a4 00 00 00 00 50 00 ...^...O......P.
|
399
|
+
# 40 00 4a 92 00 00 @.J...
|
400
|
+
# t.proto
|
401
|
+
# => ["Eth", "IP", "TCP"]
|
402
|
+
#
|
403
|
+
def proto
|
404
|
+
type_array = []
|
405
|
+
self.headers.each {|header| type_array << header.class.to_s.split('::').last.gsub(/Header$/,'')}
|
406
|
+
type_array
|
407
|
+
end
|
408
|
+
|
409
|
+
alias_method :protocol, :proto
|
410
|
+
|
411
|
+
# Returns true if this is an Invalid packet. Else, false.
|
412
|
+
def is_invalid? ; self.proto.include? "Invalid"; end
|
413
|
+
# Returns true if this is an Ethernet packet. Else, false.
|
414
|
+
def is_ethernet? ; self.proto.include? "Eth"; end
|
415
|
+
alias_method :is_eth?, :is_ethernet?
|
416
|
+
# Returns true if this is an IP packet. Else, false.
|
417
|
+
def is_ip? ; self.proto.include? "IP"; end
|
418
|
+
# Returns true if this is an TCP packet. Else, false.
|
419
|
+
def is_tcp? ; self.proto.include? "TCP"; end
|
420
|
+
# Returns true if this is an UDP packet. Else, false.
|
421
|
+
def is_udp? ; self.proto.include? "UDP"; end
|
422
|
+
# Returns true if this is an ARP packet. Else, false.
|
423
|
+
def is_arp? ; self.proto.include? "ARP"; end
|
424
|
+
# Returns true if this is an IPv6 packet. Else, false.
|
425
|
+
def is_ipv6? ; self.proto.include? "IPv6" ; end
|
426
|
+
# Returns true if this is an ICMP packet. Else, false.
|
427
|
+
def is_icmp? ; self.proto.include? "ICMP" ; end
|
428
|
+
# Returns true if this is an IPv6 packet. Else, false.
|
429
|
+
def is_ipv6? ; self.proto.include? "IPv6" ; end
|
430
|
+
# Returns true if the outermost layer has data. Else, false.
|
431
|
+
def has_data? ; self.payload.size.zero? ? false : true ; end
|
432
|
+
|
433
|
+
alias_method :length, :size
|
434
|
+
|
435
|
+
def initialize(args={})
|
436
|
+
if args[:config]
|
437
|
+
args[:config].each_pair do |k,v|
|
438
|
+
case k
|
439
|
+
when :eth_daddr; @eth_header.eth_daddr=v if @eth_header
|
440
|
+
when :eth_saddr; @eth_header.eth_saddr=v if @eth_header
|
441
|
+
when :ip_saddr; @ip_header.ip_saddr=v if @ip_header
|
442
|
+
when :iface; @iface = v
|
443
|
+
end
|
444
|
+
end
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
end # class Packet
|
449
|
+
|
450
|
+
@@inspect_style = :pretty
|
451
|
+
|
452
|
+
# If @@inspect_style is :ugly, set the inspect method to the usual inspect.
|
453
|
+
# By default, @@inspect_style is :pretty. This default may change if people
|
454
|
+
# hate it.
|
455
|
+
# Since PacketFu is designed with irb in mind, the normal inspect is way too
|
456
|
+
# verbose when new packets are created, and it ruins the aesthetics of the
|
457
|
+
# PacketFu console or quick hping-like exercises in irb.
|
458
|
+
#
|
459
|
+
# However, there are cases where knowing things like object id numbers, the complete
|
460
|
+
# @header array, etc. is useful (especially in debugging). So, toggle_inspect
|
461
|
+
# provides a means for a script to declar which style of inspect to use.
|
462
|
+
#
|
463
|
+
# This method may be an even worse idea than the original monkeypatch to Packet.inspect,
|
464
|
+
# since it would almost certainly be better to redefine inspect just in the PacketFu console.
|
465
|
+
# We'll see what happens.
|
466
|
+
#
|
467
|
+
# == Example
|
468
|
+
#
|
469
|
+
# irb(main):001:0> p = PacketFu::TCPPacket.new
|
470
|
+
# => Eth|IP|TCP
|
471
|
+
# 00 1a c5 00 00 00 00 1a c5 00 00 00 08 00 45 00 ..............E.
|
472
|
+
# 00 28 ea d7 00 00 ff 06 d0 f8 00 00 00 00 00 00 .(..............
|
473
|
+
# 00 00 a9 76 00 00 f9 28 7e 95 00 00 00 00 50 00 ...v...(~.....P.
|
474
|
+
# 40 00 4e b0 00 00 @.N...
|
475
|
+
# irb(main):002:0> PacketFu.toggle_inspect
|
476
|
+
# => :ugly
|
477
|
+
# irb(main):003:0> p = PacketFu::TCPPacket.new
|
478
|
+
# => #<PacketFu::TCPPacket:0xb7aaf96c @ip_header=#<struct PacketFu::IPHeader ip_v=4, ip_hl=5, ip_tos=#<struct StructFu::Int8 value=nil, endian=nil, width=1, default=0>, ip_len=#<struct StructFu::Int16 value=20, endian=:big, width=2, default=0>, ip_id=#<struct StructFu::Int16 value=58458, endian=:big, width=2, default=0>, ip_frag=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, ip_ttl=#<struct StructFu::Int8 value=32, endian=nil, width=1, default=0>, ip_proto=#<struct StructFu::Int8 value=6, endian=nil, width=1, default=0>, ip_sum=#<struct StructFu::Int16 value=65535, endian=:big, width=2, default=0>, ip_src=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, ip_dst=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, body=#<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">>, @tcp_header=#<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">, @eth_header=#<struct PacketFu::EthHeader eth_dst=#<struct PacketFu::EthMac oui=#<struct PacketFu::EthOui b0=nil, b1=nil, b2=nil, b3=nil, b4=nil, b5=nil, local=0, multicast=nil, oui=428>, nic=#<struct PacketFu::EthNic n0=nil, n1=nil, n2=nil>>, eth_src=#<struct PacketFu::EthMac oui=#<struct PacketFu::EthOui b0=nil, b1=nil, b2=nil, b3=nil, b4=nil, b5=nil, local=0, multicast=nil, oui=428>, nic=#<struct PacketFu::EthNic n0=nil, n1=nil, n2=nil>>, eth_proto=#<struct StructFu::Int16 value=2048, endian=:big, width=2, default=0>, body=#<struct PacketFu::IPHeader ip_v=4, ip_hl=5, ip_tos=#<struct StructFu::Int8 value=nil, endian=nil, width=1, default=0>, ip_len=#<struct StructFu::Int16 value=20, endian=:big, width=2, default=0>, ip_id=#<struct StructFu::Int16 value=58458, endian=:big, width=2, default=0>, ip_frag=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, ip_ttl=#<struct StructFu::Int8 value=32, endian=nil, width=1, default=0>, ip_proto=#<struct StructFu::Int8 value=6, endian=nil, width=1, default=0>, ip_sum=#<struct StructFu::Int16 value=65535, endian=:big, width=2, default=0>, ip_src=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, ip_dst=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, body=#<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">>>, @headers=[#<struct PacketFu::EthHeader eth_dst=#<struct PacketFu::EthMac oui=#<struct PacketFu::EthOui b0=nil, b1=nil, b2=nil, b3=nil, b4=nil, b5=nil, local=0, multicast=nil, oui=428>, nic=#<struct PacketFu::EthNic n0=nil, n1=nil, n2=nil>>, eth_src=#<struct PacketFu::EthMac oui=#<struct PacketFu::EthOui b0=nil, b1=nil, b2=nil, b3=nil, b4=nil, b5=nil, local=0, multicast=nil, oui=428>, nic=#<struct PacketFu::EthNic n0=nil, n1=nil, n2=nil>>, eth_proto=#<struct StructFu::Int16 value=2048, endian=:big, width=2, default=0>, body=#<struct PacketFu::IPHeader ip_v=4, ip_hl=5, ip_tos=#<struct StructFu::Int8 value=nil, endian=nil, width=1, default=0>, ip_len=#<struct StructFu::Int16 value=20, endian=:big, width=2, default=0>, ip_id=#<struct StructFu::Int16 value=58458, endian=:big, width=2, default=0>, ip_frag=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, ip_ttl=#<struct StructFu::Int8 value=32, endian=nil, width=1, default=0>, ip_proto=#<struct StructFu::Int8 value=6, endian=nil, width=1, default=0>, ip_sum=#<struct StructFu::Int16 value=65535, endian=:big, width=2, default=0>, ip_src=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, ip_dst=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, body=#<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">>>, #<struct PacketFu::IPHeader ip_v=4, ip_hl=5, ip_tos=#<struct StructFu::Int8 value=nil, endian=nil, width=1, default=0>, ip_len=#<struct StructFu::Int16 value=20, endian=:big, width=2, default=0>, ip_id=#<struct StructFu::Int16 value=58458, endian=:big, width=2, default=0>, ip_frag=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, ip_ttl=#<struct StructFu::Int8 value=32, endian=nil, width=1, default=0>, ip_proto=#<struct StructFu::Int8 value=6, endian=nil, width=1, default=0>, ip_sum=#<struct StructFu::Int16 value=65535, endian=:big, width=2, default=0>, ip_src=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, ip_dst=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, body=#<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">>, #<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">]>
|
479
|
+
# irb(main):004:0>
|
480
|
+
def toggle_inspect
|
481
|
+
if @@inspect_style == :pretty
|
482
|
+
eval("class Packet; def inspect; super; end; end")
|
483
|
+
@@inspect_style = :ugly
|
484
|
+
else
|
485
|
+
eval("class Packet; def inspect; self.proto.join('|') + \"\n\" + self.inspect_hex; end; end")
|
486
|
+
@@inspect_style = :pretty
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
end
|
491
|
+
|
492
|
+
# vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
|