bettercap 1.4.6 → 1.5.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/bin/bettercap +1 -1
  3. data/lib/bettercap.rb +1 -0
  4. data/lib/bettercap/context.rb +63 -70
  5. data/lib/bettercap/discovery/agents/base.rb +2 -2
  6. data/lib/bettercap/discovery/thread.rb +5 -4
  7. data/lib/bettercap/firewalls/base.rb +2 -4
  8. data/lib/bettercap/firewalls/{osx.rb → bsd.rb} +3 -3
  9. data/lib/bettercap/firewalls/linux.rb +2 -2
  10. data/lib/bettercap/firewalls/redirection.rb +5 -2
  11. data/lib/bettercap/logger.rb +6 -11
  12. data/lib/bettercap/memory.rb +56 -0
  13. data/lib/bettercap/monkey/em-proxy/proxy.rb +23 -0
  14. data/lib/bettercap/monkey/packetfu/pcap.rb +51 -0
  15. data/lib/bettercap/network/arp_reader.rb +2 -2
  16. data/lib/bettercap/network/network.rb +2 -2
  17. data/lib/bettercap/network/packet_queue.rb +2 -2
  18. data/lib/bettercap/network/protos/base.rb +8 -5
  19. data/lib/bettercap/network/protos/dhcp.rb +5 -124
  20. data/lib/bettercap/network/target.rb +7 -2
  21. data/lib/bettercap/options/core_options.rb +189 -0
  22. data/lib/bettercap/options/options.rb +167 -0
  23. data/lib/bettercap/options/proxy_options.rb +258 -0
  24. data/lib/bettercap/options/server_options.rb +71 -0
  25. data/lib/bettercap/options/sniff_options.rb +90 -0
  26. data/lib/bettercap/options/spoof_options.rb +71 -0
  27. data/lib/bettercap/proxy/{module.rb → http/module.rb} +8 -4
  28. data/lib/bettercap/proxy/{modules → http/modules}/injectcss.rb +2 -2
  29. data/lib/bettercap/proxy/{modules → http/modules}/injecthtml.rb +2 -2
  30. data/lib/bettercap/proxy/{modules → http/modules}/injectjs.rb +2 -2
  31. data/lib/bettercap/proxy/{proxy.rb → http/proxy.rb} +5 -2
  32. data/lib/bettercap/proxy/{request.rb → http/request.rb} +4 -0
  33. data/lib/bettercap/proxy/{response.rb → http/response.rb} +3 -0
  34. data/lib/bettercap/proxy/{ssl → http/ssl}/authority.rb +3 -1
  35. data/lib/bettercap/proxy/{ssl → http/ssl}/bettercap-ca.pem +0 -0
  36. data/lib/bettercap/proxy/{ssl → http/ssl}/server.rb +3 -1
  37. data/lib/bettercap/proxy/{sslstrip → http/sslstrip}/cookiemonitor.rb +2 -0
  38. data/lib/bettercap/proxy/{sslstrip → http/sslstrip}/lock.ico +0 -0
  39. data/lib/bettercap/proxy/{sslstrip → http/sslstrip}/strip.rb +4 -2
  40. data/lib/bettercap/proxy/{streamer.rb → http/streamer.rb} +7 -4
  41. data/lib/bettercap/proxy/stream_logger.rb +25 -9
  42. data/lib/bettercap/proxy/tcp/module.rb +75 -0
  43. data/lib/bettercap/proxy/tcp/proxy.rb +123 -0
  44. data/lib/bettercap/proxy/thread_pool.rb +1 -1
  45. data/lib/bettercap/sniffer/parsers/post.rb +1 -1
  46. data/lib/bettercap/sniffer/parsers/url.rb +1 -1
  47. data/lib/bettercap/sniffer/sniffer.rb +23 -17
  48. data/lib/bettercap/spoofers/arp.rb +21 -9
  49. data/lib/bettercap/spoofers/base.rb +12 -16
  50. data/lib/bettercap/spoofers/icmp.rb +4 -5
  51. data/lib/bettercap/spoofers/none.rb +0 -1
  52. data/lib/bettercap/version.rb +1 -1
  53. metadata +48 -19
  54. data/lib/bettercap/firewalls/openbsd.rb +0 -77
  55. data/lib/bettercap/options.rb +0 -600
@@ -0,0 +1,75 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+
4
+ BETTERCAP
5
+
6
+ Author : Simone 'evilsocket' Margaritelli
7
+ Email : evilsocket@gmail.com
8
+ Blog : http://www.evilsocket.net/
9
+
10
+ This project is released under the GPL 3 license.
11
+
12
+ =end
13
+
14
+ module BetterCap
15
+ module Proxy
16
+ module TCP
17
+
18
+ # Base class for transparent TCP proxy modules, example:
19
+ #
20
+ # class SampleModule < BetterCap::Proxy::TCP::Module
21
+ # def on_data( event )
22
+ # event.data = 'aaa'
23
+ # end
24
+ #
25
+ # def on_response( event )
26
+ # event.data = 'bbb'
27
+ # end
28
+ # end
29
+ class Module
30
+ # This callback is called when the target is sending data to the upstream server.
31
+ # +event+ is an instance of the BetterCap::Proxy::TCP::Event class.
32
+ def on_data( event ); end
33
+ # This callback is called when the upstream server is sending data to the target.
34
+ # +event+ is an instance of the BetterCap::Proxy::TCP::Event class.
35
+ def on_response( event ); end
36
+ # This callback is called when the connection is terminated.
37
+ # +event+ is an instance of the BetterCap::Proxy::TCP::Event class.
38
+ def on_finish( event ); end
39
+
40
+ # Loaded modules.
41
+ @@loaded = {}
42
+
43
+ class << self
44
+ # Called when a class inherits this base class.
45
+ def inherited(subclass)
46
+ name = subclass.name.upcase
47
+ @@loaded[name] = subclass
48
+ end
49
+
50
+ # Load +file+ as a proxy module.
51
+ def load( file )
52
+ begin
53
+ require file
54
+ rescue LoadError
55
+ raise BetterCap::Error, "Invalid TCP proxy module specified."
56
+ end
57
+
58
+ @@loaded.each do |name,mod|
59
+ @@loaded[name] = mod.new
60
+ end
61
+ end
62
+
63
+ # Execute method +even_name+ for each loaded module instance using +event+
64
+ # as its argument.
65
+ def dispatch( event_name, event )
66
+ @@loaded.each do |name,mod|
67
+ mod.send( event_name, event )
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,123 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+
4
+ BETTERCAP
5
+
6
+ Author : Simone 'evilsocket' Margaritelli
7
+ Email : evilsocket@gmail.com
8
+ Blog : http://www.evilsocket.net/
9
+
10
+ This project is released under the GPL 3 license.
11
+
12
+ =end
13
+
14
+ module BetterCap
15
+ module Proxy
16
+ module TCP
17
+
18
+ # Class used to encapsulate ( and keep references ) of a single TCP event-.
19
+ # http://stackoverflow.com/questions/161510/pass-parameter-by-reference-in-ruby
20
+ class Event
21
+ # The source IP address of this event.
22
+ attr_accessor :ip
23
+ # Source port.
24
+ attr_accessor :port
25
+ # Reference to the buffer being transmitted.
26
+ attr_accessor :data
27
+
28
+ def initialize( ip, port, data = nil )
29
+ @ip = ip
30
+ @port = port
31
+ @data = data
32
+ end
33
+ end
34
+
35
+ # Transparent TCP proxy class.
36
+ class Proxy
37
+ # Initialize the TCP proxy with given arguments.
38
+ def initialize( address, port, up_address, up_port )
39
+ @address = address
40
+ @port = port
41
+ @upstream_address = up_address
42
+ @upstream_port = up_port
43
+ @ctx = BetterCap::Context.get
44
+ @worker = nil
45
+ end
46
+
47
+ # Start the proxy.
48
+ def start
49
+ Logger.info "[#{'TCP PROXY'.green}] Starting on #{@address}:#{@port} ( -> #{@upstream_address}:#{@upstream_port} ) ..."
50
+ @worker = Thread.new &method(:worker)
51
+ # If the upstream server is in this network, we need to make sure that its MAC
52
+ # address is discovered and put in the ARP cache before we even start the proxy,
53
+ # otherwise internal connections won't be spoofed and the proxy will be useless
54
+ # until some random event will fill the ARP cache for the server.
55
+ if @ctx.ifconfig[:ip4_obj].include?( @upstream_address )
56
+ Logger.debug "[#{'TCP PROXY'.green}] Sending probe to upstream server address ..."
57
+ BetterCap::Network.get_hw_address( @ctx, @upstream_address )
58
+ # wait for the system to acknowledge the ARP cache changes.
59
+ sleep( 1 )
60
+ end
61
+ end
62
+
63
+ # Stop the proxy.
64
+ def stop
65
+ Logger.info "Stopping TCP proxy ..."
66
+ ::Proxy.stop
67
+ @worker.join
68
+ end
69
+
70
+ private
71
+
72
+ def worker
73
+ begin
74
+ up_addr = @upstream_address
75
+ up_port = @upstream_port
76
+ up_svc = BetterCap::StreamLogger.service( :tcp, @upstream_port )
77
+
78
+ ::Proxy.start(:host => @address, :port => @port) do |conn|
79
+ conn.server :srv, :host => up_addr, :port => up_port
80
+
81
+ # ip -> upstream
82
+ conn.on_data do |data|
83
+ ip, port = peer
84
+ event = Event.new( ip, port, data )
85
+
86
+ Logger.info "[#{'TCP PROXY'.green}] #{ip} #{'->'.green} #{'upstream'.yellow}:#{up_svc} ( #{event.data.bytesize} bytes )"
87
+
88
+ Module.dispatch( 'on_data', event )
89
+ event.data
90
+ end
91
+
92
+ # upstream -> ip
93
+ conn.on_response do |backend, resp|
94
+ ip, port = peer
95
+ event = Event.new( ip, port, resp )
96
+
97
+ Logger.info "[#{'TCP PROXY'.green}] #{'upstream'.yellow}:#{up_svc} #{'->'.green} #{ip} ( #{event.data.bytesize} bytes )"
98
+
99
+ Module.dispatch( 'on_response', event )
100
+ event.data
101
+ end
102
+
103
+ # termination
104
+ conn.on_finish do |backend, name|
105
+ ip, port = peer
106
+ event = Event.new( ip, port )
107
+
108
+ Logger.info "[#{'TCP PROXY'.green}] #{ip} <- #{'closed'.red} -> #{'upstream'.yellow}:#{up_svc}"
109
+
110
+ Module.dispatch( 'on_finish', event )
111
+ unbind
112
+ end
113
+ end
114
+ rescue Exception => e
115
+ Logger.error e.message
116
+ Logger.exception e
117
+ end
118
+ end
119
+ end
120
+
121
+ end
122
+ end
123
+ end
@@ -13,7 +13,7 @@ This project is released under the GPL 3 license.
13
13
 
14
14
  module BetterCap
15
15
  module Proxy
16
- # Thread pool class used by the BetterCap::Proxy::Proxy.
16
+ # Thread pool class used by the BetterCap::Proxy::*.
17
17
  # Tnx to Puma ThreadPool!
18
18
  class ThreadPool
19
19
 
@@ -19,7 +19,7 @@ class Post < Base
19
19
  s = pkt.to_s
20
20
  if s =~ /POST\s+[^\s]+\s+HTTP.+/
21
21
  begin
22
- req = BetterCap::Proxy::Request.parse(pkt.payload)
22
+ req = BetterCap::Proxy::HTTP::Request.parse(pkt.payload)
23
23
  # the packet could be incomplete
24
24
  unless req.body.nil? or req.body.empty?
25
25
  StreamLogger.log_raw( pkt, "POST", req.to_url(1000) )
@@ -20,7 +20,7 @@ class Url < Base
20
20
  if s =~ /GET\s+([^\s]+)\s+HTTP.+Host:\s+([^\s]+).+/m
21
21
  host = $2
22
22
  url = $1
23
- if not url =~ /.+\.(png|jpg|jpeg|bmp|gif|img|ttf|woff|css|js).*/i
23
+ unless url =~ /.+\.(png|jpg|jpeg|bmp|gif|img|ttf|woff|css|js).*/i
24
24
  StreamLogger.log_raw( pkt, 'GET', "http://#{host}#{url}" )
25
25
  end
26
26
  end
@@ -31,7 +31,7 @@ class Sniffer
31
31
 
32
32
  setup( ctx )
33
33
 
34
- start = Time.now.to_i
34
+ start = Time.now
35
35
  skipped = 0
36
36
  processed = 0
37
37
 
@@ -52,11 +52,11 @@ class Sniffer
52
52
  end
53
53
  end
54
54
 
55
- stop = Time.now.to_i
56
- delta = stop - start
55
+ stop = Time.now
56
+ delta = ( stop - start ) * 1000.0
57
57
  total = skipped + processed
58
58
 
59
- Logger.info "[#{'SNIFFER'.green}] #{total} packets processed in #{delta} s ( #{skipped} skipped packets, #{processed} processed packets )"
59
+ Logger.info "[#{'SNIFFER'.green}] #{total} packets processed in #{delta} ms ( #{skipped} skipped packets, #{processed} processed packets )"
60
60
  }
61
61
  end
62
62
 
@@ -64,13 +64,19 @@ class Sniffer
64
64
 
65
65
  # Return the current PCAP stream.
66
66
  def self.stream
67
- if @@ctx.options.sniffer_src.nil?
68
- @@cap.stream
67
+ if @@ctx.options.sniff.src.nil?
68
+ return @@cap.stream
69
69
  else
70
- Logger.info "[#{'SNIFFER'.green}] Reading packets from #{@@ctx.options.sniffer_src} ..."
70
+ Logger.info "[#{'SNIFFER'.green}] Reading packets from #{@@ctx.options.sniff.src} ..."
71
71
 
72
- PacketFu::PcapFile.file_to_array @@ctx.options.sniffer_src
72
+ begin
73
+ return PacketFu::PcapFile.file_to_array @@ctx.options.sniff.src
74
+ rescue Exception => e
75
+ Logger.error "Error while parsing #{@@ctx.options.sniff.src}: #{e.message}"
76
+ Logger.exception e
77
+ end
73
78
  end
79
+ return []
74
80
  end
75
81
 
76
82
  # Return true if the +pkt+ packet instance must be skipped.
@@ -81,7 +87,7 @@ class Sniffer
81
87
  # not IP packet
82
88
  return true unless pkt.is_ip?
83
89
  # skip if local packet and --local|-L was not specified.
84
- unless @@ctx.options.local
90
+ unless @@ctx.options.sniff.local
85
91
  return ( pkt.ip_saddr == @@ctx.ifconfig[:ip_saddr] or pkt.ip_daddr == @@ctx.ifconfig[:ip_saddr] )
86
92
  end
87
93
  rescue; end
@@ -103,7 +109,7 @@ class Sniffer
103
109
  def self.append_packet( p )
104
110
  begin
105
111
  @@pcap.array_to_file(
106
- filename: @@ctx.options.sniffer_pcap,
112
+ filename: @@ctx.options.sniff.output,
107
113
  array: [p],
108
114
  append: true ) unless @@pcap.nil?
109
115
  rescue Exception => e
@@ -115,20 +121,20 @@ class Sniffer
115
121
  def self.setup( ctx )
116
122
  @@ctx = ctx
117
123
 
118
- unless @@ctx.options.sniffer_pcap.nil?
124
+ unless @@ctx.options.sniff.output.nil?
119
125
  @@pcap = PacketFu::PcapFile.new
120
- Logger.info "[#{'SNIFFER'.green}] Saving packets to #{@@ctx.options.sniffer_pcap} ."
126
+ Logger.info "[#{'SNIFFER'.green}] Saving packets to #{@@ctx.options.sniff.output} ."
121
127
  end
122
128
 
123
- if @@ctx.options.custom_parser.nil?
124
- @@parsers = Parsers::Base.load_by_names @@ctx.options.parsers
129
+ if @@ctx.options.sniff.custom_parser.nil?
130
+ @@parsers = Parsers::Base.load_by_names @@ctx.options.sniff.parsers
125
131
  else
126
- @@parsers = Parsers::Base.load_custom @@ctx.options.custom_parser
132
+ @@parsers = Parsers::Base.load_custom @@ctx.options.sniff.custom_parser
127
133
  end
128
134
 
129
135
  @@cap = Capture.new(
130
- iface: @@ctx.options.iface,
131
- filter: @@ctx.options.sniffer_filter,
136
+ iface: @@ctx.options.core.iface,
137
+ filter: @@ctx.options.sniff.filter,
132
138
  start: true
133
139
  )
134
140
  end
@@ -18,7 +18,6 @@ class Arp < Base
18
18
  # Initialize the BetterCap::Spoofers::Arp object.
19
19
  def initialize
20
20
  @ctx = Context.get
21
- @gateway = nil
22
21
  @forwarding = @ctx.firewall.forwarding_enabled?
23
22
  @spoof_thread = nil
24
23
  @sniff_thread = nil
@@ -46,12 +45,12 @@ class Arp < Base
46
45
 
47
46
  # Start the ARP spoofing.
48
47
  def start
49
- Logger.debug "Starting ARP spoofer ( #{@ctx.options.half_duplex ? 'Half' : 'Full'} Duplex ) ..."
48
+ Logger.debug "Starting ARP spoofer ( #{@ctx.options.spoof.half_duplex ? 'Half' : 'Full'} Duplex ) ..."
50
49
 
51
50
  stop() if @running
52
51
  @running = true
53
52
 
54
- if @ctx.options.kill
53
+ if @ctx.options.spoof.kill
55
54
  Logger.warn "Disabling packet forwarding."
56
55
  @ctx.firewall.enable_forwarding(false) if @forwarding
57
56
  else
@@ -77,7 +76,7 @@ class Arp < Base
77
76
  Logger.debug "Restoring ARP table of #{@ctx.targets.size} targets ..."
78
77
 
79
78
  @ctx.targets.each do |target|
80
- unless target.ip.nil? or target.mac.nil?
79
+ if target.spoofable?
81
80
  5.times do
82
81
  spoof(target, true)
83
82
  sleep 0.3
@@ -96,18 +95,31 @@ class Arp < Base
96
95
  # restore its ARP cache instead.
97
96
  def spoof( target, restore = false )
98
97
  if restore
99
- send_spoofed_packet( @gateway.ip, @gateway.mac, target.ip, 'ff:ff:ff:ff:ff:ff' )
100
- send_spoofed_packet( target.ip, target.mac, @gateway.ip, 'ff:ff:ff:ff:ff:ff' ) unless @ctx.options.half_duplex
98
+ send_spoofed_packet( @ctx.gateway.ip, @ctx.gateway.mac, target.ip, 'ff:ff:ff:ff:ff:ff' )
99
+ send_spoofed_packet( target.ip, target.mac, @ctx.gateway.ip, 'ff:ff:ff:ff:ff:ff' ) unless @ctx.options.spoof.half_duplex
100
+ @ctx.targets.each do |e|
101
+ if e.spoofable? and e.ip != target.ip and e.ip != @ctx.gateway.ip
102
+ send_spoofed_packet( e.ip, e.mac, target.ip, 'ff:ff:ff:ff:ff:ff' )
103
+ end
104
+ end
101
105
  else
102
- send_spoofed_packet( @gateway.ip, @ctx.ifconfig[:eth_saddr], target.ip, target.mac )
103
- send_spoofed_packet( target.ip, @ctx.ifconfig[:eth_saddr], @gateway.ip, @gateway.mac ) unless @ctx.options.half_duplex
106
+ # tell the target we're the gateway
107
+ send_spoofed_packet( @ctx.gateway.ip, @ctx.ifconfig[:eth_saddr], target.ip, target.mac )
108
+ # tell the gateway we're the target
109
+ send_spoofed_packet( target.ip, @ctx.ifconfig[:eth_saddr], @ctx.gateway.ip, @ctx.gateway.mac ) unless @ctx.options.spoof.half_duplex
110
+ # tell the target we're everybody else in the network :D
111
+ @ctx.targets.each do |e|
112
+ if e.spoofable? and e.ip != target.ip and e.ip != @ctx.gateway.ip
113
+ send_spoofed_packet( e.ip, @ctx.ifconfig[:eth_saddr], target.ip, target.mac )
114
+ end
115
+ end
104
116
  end
105
117
  end
106
118
 
107
119
  # Main spoofer loop.
108
120
  def arp_spoofer
109
121
  spoof_loop(1) { |target|
110
- unless target.ip.nil? or target.mac.nil?
122
+ if target.spoofable?
111
123
  spoof(target)
112
124
  end
113
125
  }
@@ -57,7 +57,7 @@ private
57
57
  def sniff_packets( filter )
58
58
  begin
59
59
  @capture = PacketFu::Capture.new(
60
- iface: @ctx.options.iface,
60
+ iface: @ctx.options.core.iface,
61
61
  filter: filter,
62
62
  start: true
63
63
  )
@@ -67,10 +67,10 @@ private
67
67
 
68
68
  @capture.stream.each do |p|
69
69
  begin
70
- if not @running
71
- Logger.debug 'Stopping thread ...'
72
- Thread.exit
73
- break
70
+ unless @running
71
+ Logger.debug 'Stopping thread ...'
72
+ Thread.exit
73
+ break
74
74
  end
75
75
 
76
76
  pkt = PacketFu::Packet.parse p rescue nil
@@ -92,7 +92,7 @@ private
92
92
  break
93
93
  end
94
94
 
95
- # Logger.debug "Spoofing #{@ctx.targets.size} targets ..."
95
+ Logger.debug "Spoofing #{@ctx.targets.size} targets ..."
96
96
 
97
97
  update_targets!
98
98
 
@@ -106,17 +106,13 @@ private
106
106
 
107
107
  # Get the MAC address of the gateway and update it.
108
108
  def update_gateway!
109
- hw = Network.get_hw_address( @ctx, @ctx.gateway )
110
-
111
- raise BetterCap::Error, "Couldn't determine router MAC" if ( @ctx.need_gateway? and hw.nil? )
112
-
113
- @gateway = Network::Target.new( @ctx.gateway, hw )
114
-
115
- # notify the system that the gateway mac is resolved, this will prevent
116
- # the gateway ip to be unnecessarily probed from discovery agents.
117
- @ctx.gateway_mac_resolved = !hw.nil?
109
+ unless @ctx.gateway.spoofable?
110
+ hw = Network.get_hw_address( @ctx, @ctx.gateway.ip )
111
+ raise BetterCap::Error, "Couldn't determine router MAC" if ( @ctx.options.need_gateway? and hw.nil? )
112
+ @ctx.gateway.mac = hw unless hw.nil?
113
+ end
118
114
 
119
- Logger.info "[#{'GATEWAY'.green}] #{@gateway.to_s(false)}"
115
+ Logger.info "[#{'GATEWAY'.green}] #{@ctx.gateway.to_s(false)}"
120
116
  end
121
117
 
122
118
  # Update each target that needs to be updated.
@@ -79,7 +79,6 @@ class Icmp < Base
79
79
  def initialize
80
80
  @ctx = Context.get
81
81
  @forwarding = @ctx.firewall.forwarding_enabled?
82
- @gateway = nil
83
82
  @local = @ctx.ifconfig[:ip_saddr]
84
83
  @spoof_thread = nil
85
84
  @watch_thread = nil
@@ -93,12 +92,12 @@ class Icmp < Base
93
92
  # Send ICMP redirect to the +target+, redirecting the gateway ip and
94
93
  # everything in the @entries list of addresses to us.
95
94
  def send_spoofed_packet( target )
96
- ( [@gateway.ip] + @entries ).each do |address|
95
+ ( [@ctx.gateway.ip] + @entries ).each do |address|
97
96
  begin
98
97
  Logger.debug "Sending ICMP Redirect to #{target.to_s_compact} redirecting #{address} to us ..."
99
98
 
100
99
  pkt = ICMPRedirectPacket.new
101
- pkt.update!( @gateway, target, @local, address )
100
+ pkt.update!( @ctx.gateway, target, @local, address )
102
101
  @ctx.packets.push(pkt)
103
102
  rescue Exception => e
104
103
  Logger.debug "#{self.class.name} : #{e.message}"
@@ -113,7 +112,7 @@ class Icmp < Base
113
112
  stop() if @running
114
113
  @running = true
115
114
 
116
- if @ctx.options.kill
115
+ if @ctx.options.spoof.kill
117
116
  Logger.warn "Disabling packet forwarding."
118
117
  @ctx.firewall.enable_forwarding(false) if @forwarding
119
118
  else
@@ -194,7 +193,7 @@ class Icmp < Base
194
193
  # Main spoofer loop.
195
194
  def icmp_spoofer
196
195
  spoof_loop(3) { |target|
197
- unless target.ip.nil? or target.mac.nil?
196
+ if target.spoofable?
198
197
  send_spoofed_packet target
199
198
  end
200
199
  }