packetfu 1.1.8 → 1.1.9
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/README.rdoc +11 -12
- data/bench/octets.rb +9 -9
- data/examples/100kpackets.rb +13 -12
- data/examples/ackscan.rb +17 -16
- data/examples/arp.rb +36 -35
- data/examples/arphood.rb +37 -36
- data/examples/dissect_thinger.rb +7 -6
- data/examples/ethernet.rb +1 -0
- data/examples/examples.rb +1 -0
- data/examples/ifconfig.rb +1 -0
- data/examples/new-simple-stats.rb +24 -23
- data/examples/packetfu-shell.rb +26 -25
- data/examples/simple-sniffer.rb +10 -9
- data/examples/simple-stats.rb +24 -23
- data/examples/slammer.rb +4 -3
- data/lib/packetfu.rb +128 -127
- data/lib/packetfu/capture.rb +170 -169
- data/lib/packetfu/config.rb +53 -52
- data/lib/packetfu/inject.rb +57 -56
- data/lib/packetfu/packet.rb +529 -528
- data/lib/packetfu/pcap.rb +580 -579
- data/lib/packetfu/protos/arp.rb +91 -90
- data/lib/packetfu/protos/arp/header.rb +159 -158
- data/lib/packetfu/protos/arp/mixin.rb +37 -36
- data/lib/packetfu/protos/eth.rb +45 -44
- data/lib/packetfu/protos/eth/header.rb +244 -243
- data/lib/packetfu/protos/eth/mixin.rb +4 -3
- data/lib/packetfu/protos/hsrp.rb +70 -69
- data/lib/packetfu/protos/hsrp/header.rb +108 -107
- data/lib/packetfu/protos/hsrp/mixin.rb +30 -29
- data/lib/packetfu/protos/icmp.rb +72 -71
- data/lib/packetfu/protos/icmp/header.rb +83 -82
- data/lib/packetfu/protos/icmp/mixin.rb +15 -14
- data/lib/packetfu/protos/invalid.rb +50 -49
- data/lib/packetfu/protos/ip.rb +70 -69
- data/lib/packetfu/protos/ip/header.rb +292 -291
- data/lib/packetfu/protos/ip/mixin.rb +41 -40
- data/lib/packetfu/protos/ipv6.rb +51 -50
- data/lib/packetfu/protos/ipv6/header.rb +189 -188
- data/lib/packetfu/protos/ipv6/mixin.rb +30 -29
- data/lib/packetfu/protos/lldp.rb +3 -1
- data/lib/packetfu/protos/lldp/header.rb +1 -0
- data/lib/packetfu/protos/lldp/mixin.rb +1 -0
- data/lib/packetfu/protos/tcp.rb +177 -176
- data/lib/packetfu/protos/tcp/ecn.rb +36 -35
- data/lib/packetfu/protos/tcp/flags.rb +75 -74
- data/lib/packetfu/protos/tcp/header.rb +269 -268
- data/lib/packetfu/protos/tcp/hlen.rb +33 -32
- data/lib/packetfu/protos/tcp/mixin.rb +47 -46
- data/lib/packetfu/protos/tcp/option.rb +322 -321
- data/lib/packetfu/protos/tcp/options.rb +96 -95
- data/lib/packetfu/protos/tcp/reserved.rb +36 -35
- data/lib/packetfu/protos/udp.rb +117 -116
- data/lib/packetfu/protos/udp/header.rb +92 -91
- data/lib/packetfu/protos/udp/mixin.rb +4 -3
- data/lib/packetfu/structfu.rb +281 -280
- data/lib/packetfu/utils.rb +211 -208
- data/lib/packetfu/version.rb +42 -41
- data/packetfu.gemspec +1 -1
- data/spec/ethpacket_spec.rb +48 -48
- data/spec/packet_spec.rb +57 -57
- data/spec/packet_subclasses_spec.rb +8 -8
- data/spec/packetfu_spec.rb +59 -59
- data/spec/structfu_spec.rb +268 -268
- data/spec/tcp_spec.rb +75 -75
- data/test/all_tests.rb +13 -13
- data/test/func_lldp.rb +3 -3
- data/test/ptest.rb +2 -2
- data/test/test_arp.rb +116 -116
- data/test/test_capture.rb +45 -45
- data/test/test_eth.rb +68 -68
- data/test/test_hsrp.rb +9 -9
- data/test/test_icmp.rb +52 -52
- data/test/test_inject.rb +18 -18
- data/test/test_invalid.rb +16 -16
- data/test/test_ip.rb +36 -36
- data/test/test_ip6.rb +48 -48
- data/test/test_octets.rb +21 -21
- data/test/test_packet.rb +154 -154
- data/test/test_pcap.rb +170 -170
- data/test/test_structfu.rb +97 -97
- data/test/test_tcp.rb +320 -320
- data/test/test_udp.rb +76 -76
- metadata +2 -2
data/lib/packetfu/capture.rb
CHANGED
@@ -1,172 +1,173 @@
|
|
1
|
+
# -*- coding: binary -*-
|
1
2
|
module PacketFu
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
4
|
+
# The Capture class is used to construct PcapRub objects in order to collect
|
5
|
+
# packets from an interface.
|
6
|
+
#
|
7
|
+
# This class requires PcapRub. In addition, you will need root (or root-like) privileges
|
8
|
+
# in order to capture from the interface.
|
9
|
+
#
|
10
|
+
# Note, on some wireless cards, setting :promisc => true will disable capturing.
|
11
|
+
#
|
12
|
+
# == Example
|
13
|
+
#
|
14
|
+
# # Typical use
|
15
|
+
# cap = PacketFu::Capture.new(:iface => 'eth0', :promisc => true)
|
16
|
+
# cap.start
|
17
|
+
# sleep 10
|
18
|
+
# cap.save
|
19
|
+
# first_packet = cap.array[0]
|
20
|
+
#
|
21
|
+
# # Tcpdump-like use
|
22
|
+
# cap = PacketFu::Capture.new(:start => true)
|
23
|
+
# cap.show_live(:save => true, :filter => 'tcp and not port 22')
|
24
|
+
#
|
25
|
+
# == See Also
|
26
|
+
#
|
27
|
+
# Read, Write
|
28
|
+
class Capture
|
29
|
+
attr_accessor :array, :stream # Leave these public and open.
|
30
|
+
attr_reader :iface, :snaplen, :promisc, :timeout, :filter
|
31
|
+
|
32
|
+
def initialize(args={})
|
33
|
+
@array = [] # Where the packet array goes.
|
34
|
+
@stream = [] # Where the stream goes.
|
35
|
+
@iface = (args[:iface] || ENV['IFACE'] || Pcap.lookupdev || "lo").to_s
|
36
|
+
@snaplen = args[:snaplen] || 0xffff
|
37
|
+
@promisc = args[:promisc] || false # Sensible for some Intel wifi cards
|
38
|
+
@timeout = args[:timeout] || 1
|
39
|
+
@filter = args[:filter] || args[:bpf]
|
40
|
+
setup_params(args)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Used by new().
|
44
|
+
def setup_params(args={})
|
45
|
+
filter = args[:filter] || args[:bpf] || @filter
|
46
|
+
start = args[:start] || false
|
47
|
+
capture if start
|
48
|
+
bpf(:filter=>filter) if filter
|
49
|
+
end
|
50
|
+
|
51
|
+
# capture() initializes the @stream varaible. Valid arguments are:
|
52
|
+
#
|
53
|
+
# :filter
|
54
|
+
# Provide a bpf filter to enable for the capture. For example, 'ip and not tcp'
|
55
|
+
# :start
|
56
|
+
# When true, start capturing packets to the @stream variable. Defaults to true
|
57
|
+
def capture(args={})
|
58
|
+
if Process.euid.zero?
|
59
|
+
filter = args[:filter] || args[:bpf] || @filter
|
60
|
+
start = args[:start] || true
|
61
|
+
if start
|
62
|
+
begin
|
63
|
+
@stream = Pcap.open_live(@iface,@snaplen,@promisc,@timeout)
|
64
|
+
rescue RuntimeError
|
65
|
+
$stderr.print "Are you sure you're root? Error: "
|
66
|
+
raise
|
67
|
+
end
|
68
|
+
bpf(:filter=>filter) if filter
|
69
|
+
else
|
70
|
+
@stream = []
|
71
|
+
end
|
72
|
+
@stream
|
73
|
+
else
|
74
|
+
raise RuntimeError,"Not root, so can't capture packets. Error: "
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# start() is equivalent to capture().
|
79
|
+
def start(args={})
|
80
|
+
capture(args)
|
81
|
+
end
|
82
|
+
|
83
|
+
# clear() clears the @stream and @array variables, essentially starting the
|
84
|
+
# capture session over. Valid arguments are:
|
85
|
+
#
|
86
|
+
# :array
|
87
|
+
# If true, the @array is cleared.
|
88
|
+
# :stream
|
89
|
+
# If true, the @stream is cleared.
|
90
|
+
def clear(args={})
|
91
|
+
array = args[:array] || true
|
92
|
+
stream = args[:stream] || true
|
93
|
+
@array = [] if array
|
94
|
+
@stream = [] if stream
|
95
|
+
end
|
96
|
+
|
97
|
+
# bpf() sets a bpf filter on a capture session. Valid arugments are:
|
98
|
+
#
|
99
|
+
# :filter
|
100
|
+
# Provide a bpf filter to enable for the capture. For example, 'ip and not tcp'
|
101
|
+
def bpf(args={})
|
102
|
+
filter = args[:filter] || args[:bpf] || @filter
|
103
|
+
capture if @stream.class == Array
|
104
|
+
@stream.setfilter(filter) if filter
|
105
|
+
@filter = filter
|
106
|
+
end
|
107
|
+
|
108
|
+
alias :filter :bpf
|
109
|
+
|
110
|
+
# wire_to_array() saves a packet stream as an array of binary strings. From here,
|
111
|
+
# packets may accessed by other functions. Note that the wire_to_array empties
|
112
|
+
# the stream, so multiple calls will append new packets to @array.
|
113
|
+
# Valid arguments are:
|
114
|
+
#
|
115
|
+
# :filter
|
116
|
+
# Provide a bpf filter to apply to packets moving from @stream to @array.
|
117
|
+
def wire_to_array(args={})
|
118
|
+
filter = args[:filter] || args[:bpf] || @filter
|
119
|
+
bpf(:filter=>filter) if filter
|
120
|
+
|
121
|
+
while this_pkt = @stream.next
|
122
|
+
@array << this_pkt
|
123
|
+
end
|
124
|
+
@array.size
|
125
|
+
end
|
126
|
+
|
127
|
+
# next() exposes the Stream object's next method to the outside world.
|
128
|
+
def next
|
129
|
+
return @stream.next
|
130
|
+
end
|
131
|
+
|
132
|
+
# w2a() is a equivalent to wire_to_array()
|
133
|
+
def w2a(args={})
|
134
|
+
wire_to_array(args)
|
135
|
+
end
|
136
|
+
|
137
|
+
# save() is a equivalent to wire_to_array()
|
138
|
+
def save(args={})
|
139
|
+
wire_to_array(args)
|
140
|
+
end
|
141
|
+
|
142
|
+
# show_live() is a method to capture packets and display peek() data to stdout. Valid arguments are:
|
143
|
+
#
|
144
|
+
# :filter
|
145
|
+
# Provide a bpf filter to captured packets.
|
146
|
+
# :save
|
147
|
+
# Save the capture in @array
|
148
|
+
# :verbose
|
149
|
+
# TODO: Not implemented yet; do more than just peek() at the packets.
|
150
|
+
# :quiet
|
151
|
+
# TODO: Not implemented yet; do less than peek() at the packets.
|
152
|
+
def show_live(args={})
|
153
|
+
filter = args[:filter] || args[:bpf] || @filter
|
154
|
+
save = args[:save]
|
155
|
+
verbose = args[:verbose] || args[:v] || false
|
156
|
+
quiet = args[:quiet] || args[:q] || false # Setting q and v doesn't make a lot of sense but hey.
|
157
|
+
|
158
|
+
# Ensure the capture's started.
|
159
|
+
if @stream.class == Array
|
160
|
+
capture
|
161
|
+
end
|
162
|
+
|
163
|
+
@stream.setfilter(filter) if filter
|
164
|
+
while true
|
165
|
+
@stream.each do |pkt|
|
166
|
+
puts Packet.parse(pkt).peek
|
167
|
+
@array << pkt if args[:save]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
172
173
|
end
|
data/lib/packetfu/config.rb
CHANGED
@@ -1,58 +1,59 @@
|
|
1
|
+
# -*- coding: binary -*-
|
1
2
|
module PacketFu
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
4
|
+
# The Config class holds various bits of useful default information
|
5
|
+
# for packet creation. If initialized without arguments, @iface will be
|
6
|
+
# set to ENV['IFACE'] or Pcap.lookupdev (or lo), and the @pcapfile will
|
7
|
+
# be set to "/tmp/out.pcap" # (yes, it's Linux-biased, sorry, fixing
|
8
|
+
# this is a TODO.)
|
9
|
+
#
|
10
|
+
# Any number of instance variables can be passed in to the intialize function (as a
|
11
|
+
# hash), though only the expected network-related variables will be readable and
|
12
|
+
# writeable directly.
|
13
|
+
#
|
14
|
+
# == Examples
|
15
|
+
#
|
16
|
+
# PacketFu::Config.new(:ip_saddr => "1.2.3.4").ip_saddr #=> "1.2.3.4"
|
17
|
+
# PacketFu::Config.new(:foo=>"bar").foo #=> NomethodError: undefined method `foo'...
|
18
|
+
#
|
19
|
+
# The config() function, however, does provide access to custom variables:
|
20
|
+
#
|
21
|
+
# PacketFu::Config.new(:foo=>"bar").config[:foo] #=> "bar"
|
22
|
+
# obj = PacketFu::Config.new(:foo=>"bar")
|
23
|
+
# obj.config(:baz => "bat")
|
24
|
+
# obj.config #=> {:iface=>"eth0", :baz=>"bat", :pcapfile=>"/tmp/out.pcap", :foo=>"bar"}
|
25
|
+
class Config
|
26
|
+
attr_accessor :eth_saddr, # The discovered eth_saddr
|
27
|
+
:eth_daddr, # The discovered eth_daddr (ie, the gateway)
|
28
|
+
:eth_src, # The discovered eth_src in binary form.
|
29
|
+
:eth_dst, # The discovered eth_dst (gateway) in binary form.
|
30
|
+
:ip_saddr, # The discovered ip_saddr
|
31
|
+
:ip_src, # The discovered ip_src in binary form.
|
32
|
+
:iface, # The declared interface.
|
33
|
+
:pcapfile # A declared default file to write to.
|
34
|
+
|
35
|
+
def initialize(args={})
|
36
|
+
if Process.euid.zero?
|
37
|
+
@iface = args[:iface] || ENV['IFACE'] || Pcap.lookupdev || "lo"
|
38
|
+
end
|
39
|
+
@pcapfile = "/tmp/out.pcap"
|
40
|
+
args.each_pair { |k,v| self.instance_variable_set(("@#{k}"),v) }
|
41
|
+
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
43
|
+
# Returns all instance variables as a hash (including custom variables set at initialization).
|
44
|
+
def config(arg=nil)
|
45
|
+
if arg
|
46
|
+
arg.each_pair {|k,v| self.instance_variable_set(("@" + k.to_s).intern, v)}
|
47
|
+
else
|
48
|
+
config_hash = {}
|
49
|
+
self.instance_variables.each do |v|
|
50
|
+
key = v.to_s.gsub(/^@/,"").to_sym
|
51
|
+
config_hash[key] = self.instance_variable_get(v)
|
52
|
+
end
|
53
|
+
config_hash
|
54
|
+
end
|
55
|
+
end
|
55
56
|
|
56
|
-
|
57
|
+
end
|
57
58
|
|
58
59
|
end
|