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