bettercap 1.6.0 → 1.6.1
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.
- checksums.yaml +4 -4
- data/lib/bettercap.rb +2 -0
- data/lib/bettercap/context.rb +33 -13
- data/lib/bettercap/discovery/agents/ndp.rb +43 -0
- data/lib/bettercap/discovery/thread.rb +1 -1
- data/lib/bettercap/firewalls/base.rb +2 -2
- data/lib/bettercap/firewalls/bsd.rb +13 -2
- data/lib/bettercap/firewalls/linux.rb +38 -7
- data/lib/bettercap/monkey/packetfu/utils.rb +219 -1
- data/lib/bettercap/network/ndp_reader.rb +35 -0
- data/lib/bettercap/network/network.rb +32 -4
- data/lib/bettercap/network/target.rb +1 -1
- data/lib/bettercap/network/validator.rb +33 -0
- data/lib/bettercap/options/core_options.rb +26 -3
- data/lib/bettercap/options/options.rb +5 -0
- data/lib/bettercap/options/proxy_options.rb +73 -1
- data/lib/bettercap/options/spoof_options.rb +10 -2
- data/lib/bettercap/proxy/http/proxy.rb +6 -1
- data/lib/bettercap/proxy/http/response.rb +8 -2
- data/lib/bettercap/proxy/http/ssl/bettercap-ca.pem +52 -48
- data/lib/bettercap/proxy/http/sslstrip/strip.rb +3 -9
- data/lib/bettercap/proxy/http/streamer.rb +1 -1
- data/lib/bettercap/proxy/udp/module.rb +85 -0
- data/lib/bettercap/proxy/udp/pool.rb +86 -0
- data/lib/bettercap/proxy/udp/proxy.rb +92 -0
- data/lib/bettercap/shell.rb +8 -2
- data/lib/bettercap/sniffer/parsers/https.rb +13 -4
- data/lib/bettercap/spoofers/ndp.rb +144 -0
- data/lib/bettercap/version.rb +1 -1
- metadata +15 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 490c8b7f32ca7a9764aba54e0b7a5e8fb6d42f0f
|
4
|
+
data.tar.gz: d004aed04c55b7244ca61fd9a1c0dbbdd86d9042
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 341644a5eb60a927046fd9c8300bbff5be5df6bacc8f4a381fa4d48624a52f712be07532869e73f63b4ecdbad207dbee8a30229236fbffd2c9edc733ceaeb809
|
7
|
+
data.tar.gz: 736d8de6d05140d0252c8abad7eb5e59fc69c84f8a2a4ff59b12e9d7e72f37eaeab0bf2e55dd77d74873c8d18c5d06a75a1bffa420c24dc75b6e9fbecfbc201f
|
data/lib/bettercap.rb
CHANGED
data/lib/bettercap/context.rb
CHANGED
@@ -80,12 +80,6 @@ class Context
|
|
80
80
|
|
81
81
|
# Update the Context state parsing network related informations.
|
82
82
|
def update!
|
83
|
-
gw = @options.core.gateway || Network.get_gateway
|
84
|
-
raise BetterCap::Error, "Could not detect the gateway address for interface #{@options.core.iface}, "\
|
85
|
-
'make sure you\'ve specified the correct network interface to use and to have the '\
|
86
|
-
'correct network configuration, this could also happen if bettercap '\
|
87
|
-
'is launched from a virtual environment.' unless Network::Validator.is_ip?(gw)
|
88
|
-
|
89
83
|
unless @options.core.use_mac.nil?
|
90
84
|
cfg = PacketFu::Utils.ifconfig @options.core.iface
|
91
85
|
raise BetterCap::Error, "Could not determine IPv4 address of '#{@options.core.iface}', make sure this interface "\
|
@@ -100,14 +94,34 @@ class Context
|
|
100
94
|
|
101
95
|
cfg = PacketFu::Utils.ifconfig @options.core.iface
|
102
96
|
raise BetterCap::Error, "Could not determine IPv4 address of '#{@options.core.iface}', make sure this interface "\
|
103
|
-
'is active and connected.' if cfg[:ip4_obj].nil?
|
97
|
+
'is active and connected.' if ( cfg[:ip4_obj].nil? and cfg[:ip6_saddr].nil? )
|
98
|
+
|
99
|
+
# check if we're on an IPv6 interface
|
100
|
+
if @options.core.use_ipv6
|
101
|
+
@iface = Network::Target.new( cfg[:ip6_saddr], cfg[:eth_saddr], cfg[:ip6_obj], cfg[:iface] )
|
102
|
+
else
|
103
|
+
@iface = Network::Target.new( cfg[:ip_saddr], cfg[:eth_saddr], cfg[:ip4_obj], cfg[:iface] )
|
104
|
+
end
|
104
105
|
|
105
|
-
@gateway = Network::Target.new gw
|
106
|
-
@targets = @options.core.targets unless @options.core.targets.nil?
|
107
|
-
@iface = Network::Target.new( cfg[:ip_saddr], cfg[:eth_saddr], cfg[:ip4_obj], cfg[:iface] )
|
108
106
|
raise BetterCap::Error, "Could not determine MAC address of '#{@options.core.iface}', make sure this interface "\
|
109
107
|
'is active and connected.' unless Network::Validator::is_mac?(@iface.mac)
|
110
108
|
|
109
|
+
if @options.core.use_ipv6
|
110
|
+
gw = @options.core.gateway || Network.get_ipv6_gateway
|
111
|
+
raise BetterCap::Error, "Could not detect the gateway address for interface #{@options.core.iface}, "\
|
112
|
+
'make sure you\'ve specified the correct network interface to use and to have the '\
|
113
|
+
'correct network configuration, this could also happen if bettercap '\
|
114
|
+
'is launched from a virtual environment.' unless Network::Validator.is_ipv6?(gw)
|
115
|
+
|
116
|
+
else
|
117
|
+
gw = @options.core.gateway || Network.get_gateway
|
118
|
+
raise BetterCap::Error, "Could not detect the gateway address for interface #{@options.core.iface}, "\
|
119
|
+
'make sure you\'ve specified the correct network interface to use and to have the '\
|
120
|
+
'correct network configuration, this could also happen if bettercap '\
|
121
|
+
'is launched from a virtual environment.' unless Network::Validator.is_ip?(gw)
|
122
|
+
end
|
123
|
+
|
124
|
+
@gateway = Network::Target.new gw
|
111
125
|
Logger.info "[#{@iface.name.green}] #{@iface.to_s(false)}"
|
112
126
|
|
113
127
|
Logger.debug '----- NETWORK INFORMATIONS -----'
|
@@ -116,9 +130,10 @@ class Context
|
|
116
130
|
Logger.debug " local_ip = #{@iface.ip}"
|
117
131
|
Logger.debug "--------------------------------\n"
|
118
132
|
|
133
|
+
@targets = @options.core.targets unless @options.core.targets.nil?
|
119
134
|
@packets = Network::PacketQueue.new( @iface.name, @options.core.packet_throttle, 4 )
|
120
135
|
# Spoofers need the context network data to be initialized.
|
121
|
-
@spoofer = @options.spoof.parse_spoofers
|
136
|
+
@spoofer = @options.spoof.parse_spoofers(self)
|
122
137
|
|
123
138
|
if @options.core.discovery?
|
124
139
|
tstart = Time.now
|
@@ -204,7 +219,7 @@ class Context
|
|
204
219
|
|
205
220
|
Logger.debug 'Disabling port redirections ...'
|
206
221
|
@redirections.each do |r|
|
207
|
-
@firewall.del_port_redirection( r )
|
222
|
+
@firewall.del_port_redirection( r, @options.core.use_ipv6 )
|
208
223
|
end
|
209
224
|
|
210
225
|
Logger.debug 'Restoring firewall state ...'
|
@@ -223,7 +238,7 @@ class Context
|
|
223
238
|
@redirections = @options.get_redirections(@iface)
|
224
239
|
@redirections.each do |r|
|
225
240
|
Logger.debug "Redirecting #{r.protocol} traffic from #{r.src_address.nil? ? '*' : r.src_address}:#{r.src_port} to #{r.dst_address}:#{r.dst_port}"
|
226
|
-
@firewall.add_port_redirection( r )
|
241
|
+
@firewall.add_port_redirection( r, @options.core.use_ipv6 )
|
227
242
|
end
|
228
243
|
end
|
229
244
|
|
@@ -250,6 +265,11 @@ class Context
|
|
250
265
|
@proxies << Proxy::TCP::Proxy.new( @iface.ip, @options.proxies.tcp_proxy_port, @options.proxies.tcp_proxy_upstream_address, @options.proxies.tcp_proxy_upstream_port )
|
251
266
|
end
|
252
267
|
|
268
|
+
# create UP proxy
|
269
|
+
if @options.proxies.udp_proxy
|
270
|
+
@proxies << Proxy::UDP::Proxy.new( @iface.ip, @options.proxies.udp_proxy_port, @options.proxies.udp_proxy_upstream_address, @options.proxies.udp_proxy_upstream_port )
|
271
|
+
end
|
272
|
+
|
253
273
|
@proxies.each do |proxy|
|
254
274
|
proxy.start
|
255
275
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Parse the NDP table searching for new hosts.
|
2
|
+
module BetterCap
|
3
|
+
module Discovery
|
4
|
+
module Agents
|
5
|
+
# Class responsible of sending NDP probes to each possible IP on the network.
|
6
|
+
class Ndp < Discovery::Agents::Base
|
7
|
+
private
|
8
|
+
|
9
|
+
# Send a Neighbor Solicitation packet in order to update neighbor discovery table,
|
10
|
+
# with target's mac.
|
11
|
+
# The packet is a broadcast message, so mac is created by "33:33:ff" prefix plus the
|
12
|
+
# 24 least significant bits of the address.
|
13
|
+
# Similar rule applies to the destination address. Multicast address is formed from
|
14
|
+
# the network prefix ff02::1:ff00:0/104 and the 24 least significant bits of the address.
|
15
|
+
def get_probe( ip )
|
16
|
+
split_ip = ip.split(':')
|
17
|
+
dst_mac = "33:33:ff:" + split_ip[-2][-2,2] + ":" + split_ip[-1][0,2] + ":" + split_ip[-1][2,2]
|
18
|
+
dst_ip = "ff02::1:ff" + split_ip[-2][-2,2] + ":" + split_ip[-1]
|
19
|
+
|
20
|
+
p = PacketFu::NDPPacket.new
|
21
|
+
|
22
|
+
p.eth_daddr = dst_mac
|
23
|
+
p.eth_saddr = @ctx.iface.mac
|
24
|
+
p.eth_proto = 0x86dd
|
25
|
+
|
26
|
+
p.ipv6_saddr = @ctx.iface.ip
|
27
|
+
p.ipv6_daddr = dst_ip
|
28
|
+
|
29
|
+
p.ndp_type = 135
|
30
|
+
p.ndp_taddr = ip.to_s
|
31
|
+
p.ndp_opt_type = 1
|
32
|
+
p.ndp_opt_len = 1
|
33
|
+
p.ndp_lladdr = @ctx.iface.mac
|
34
|
+
|
35
|
+
p.ipv6_recalc
|
36
|
+
p.ndp_recalc
|
37
|
+
|
38
|
+
p
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -81,13 +81,13 @@ class Base
|
|
81
81
|
|
82
82
|
# Apply the +r+ BetterCap::Firewalls::Redirection port redirection object.
|
83
83
|
# Raise NotImplementedError
|
84
|
-
def add_port_redirection( r )
|
84
|
+
def add_port_redirection( r, use_ipv6 )
|
85
85
|
not_implemented_method!
|
86
86
|
end
|
87
87
|
|
88
88
|
# Remove the +r+ BetterCap::Firewalls::Redirection port redirection object.
|
89
89
|
# Raise NotImplementedError
|
90
|
-
def del_port_redirection( r )
|
90
|
+
def del_port_redirection( r, use_ipv6 )
|
91
91
|
not_implemented_method!
|
92
92
|
end
|
93
93
|
|
@@ -25,6 +25,12 @@ class BSD < Base
|
|
25
25
|
Shell.execute("sysctl -w net.inet.ip.forwarding=#{enabled ? 1 : 0}")
|
26
26
|
end
|
27
27
|
|
28
|
+
# If +enabled+ is true will enable packet forwarding, otherwise it will
|
29
|
+
# disable it.
|
30
|
+
def enable_ipv6_forwarding(enabled)
|
31
|
+
Shell.execute("sysctl -w net.inet6.ip6.forwarding=#{enabled ? 1 : 0}")
|
32
|
+
end
|
33
|
+
|
28
34
|
# If +enabled+ is true will enable packet icmp_echo_ignore_broadcasts, otherwise it will
|
29
35
|
# disable it.
|
30
36
|
def enable_icmp_bcast(enabled)
|
@@ -36,6 +42,11 @@ class BSD < Base
|
|
36
42
|
Shell.execute('sysctl net.inet.ip.forwarding').strip.split(' ')[1] == '1'
|
37
43
|
end
|
38
44
|
|
45
|
+
# Return true if packet forwarding for IPv6 is currently enabled, otherwise false.
|
46
|
+
def ipv6_forwarding_enabled?
|
47
|
+
Shell.execute('sysctl net.inet6.ip6.forwarding').strip.split(' ')[1] == '1'
|
48
|
+
end
|
49
|
+
|
39
50
|
# This method is ignored on OSX.
|
40
51
|
def enable_send_redirects(enabled); end
|
41
52
|
|
@@ -47,7 +58,7 @@ class BSD < Base
|
|
47
58
|
end
|
48
59
|
|
49
60
|
# Apply the +r+ BetterCap::Firewalls::Redirection port redirection object.
|
50
|
-
def add_port_redirection( r )
|
61
|
+
def add_port_redirection( r, use_ipv6 )
|
51
62
|
# create the pf config file
|
52
63
|
File.open( @filename, 'a+t' ) do |f|
|
53
64
|
f.write "#{gen_rule(r)}\n"
|
@@ -59,7 +70,7 @@ class BSD < Base
|
|
59
70
|
end
|
60
71
|
|
61
72
|
# Remove the +r+ BetterCap::Firewalls::Redirection port redirection object.
|
62
|
-
def del_port_redirection( r )
|
73
|
+
def del_port_redirection( r, use_ipv6 )
|
63
74
|
# remove the redirection rule from the existing file
|
64
75
|
rule = gen_rule(r)
|
65
76
|
rules = File.readlines(@filename).collect(&:strip).reject(&:empty?)
|
@@ -20,12 +20,20 @@ class Linux < Base
|
|
20
20
|
IP_FORWARD_PATH = IPV4_PATH + "/ip_forward"
|
21
21
|
ICMP_BCAST_PATH = IPV4_PATH + "/icmp_echo_ignore_broadcasts"
|
22
22
|
SEND_REDIRECTS_PATH = IPV4_PATH + "/conf/all/send_redirects"
|
23
|
+
IPV6_PATH = "/proc/sys/net/ipv6"
|
24
|
+
IPV6_FORWARD_PATH = IPV6_PATH + "/conf/all/forwarding"
|
23
25
|
|
24
26
|
def supported?
|
25
27
|
# Avoids stuff like this https://github.com/evilsocket/bettercap/issues/341
|
26
28
|
File.file?(IP_FORWARD_PATH)
|
27
29
|
end
|
28
30
|
|
31
|
+
# If +enabled+ is true will enable packet forwarding, otherwise it will
|
32
|
+
# disable it.
|
33
|
+
def enable_ipv6_forwarding(enabled)
|
34
|
+
File.open(IPV6_FORWARD_PATH,'w') { |f| f.puts "#{enabled ? 1 : 0}"}
|
35
|
+
end
|
36
|
+
|
29
37
|
# If +enabled+ is true will enable packet forwarding, otherwise it will
|
30
38
|
# disable it.
|
31
39
|
def enable_forwarding(enabled)
|
@@ -37,6 +45,12 @@ class Linux < Base
|
|
37
45
|
File.open(IP_FORWARD_PATH) { |f| f.read.strip == '1' }
|
38
46
|
end
|
39
47
|
|
48
|
+
# Return true if packet forwarding for IPv6 is currently enabled, otherwise false.
|
49
|
+
def ipv6_forwarding_enabled?
|
50
|
+
File.open(IPV6_FORWARD_PATH) { |f| f.read.strip == '1' }
|
51
|
+
end
|
52
|
+
|
53
|
+
|
40
54
|
# If +enabled+ is true will enable packet icmp_echo_ignore_broadcasts, otherwise it will
|
41
55
|
# disable it.
|
42
56
|
def enable_icmp_bcast(enabled)
|
@@ -50,21 +64,38 @@ class Linux < Base
|
|
50
64
|
end
|
51
65
|
|
52
66
|
# Apply the +r+ BetterCap::Firewalls::Redirection port redirection object.
|
53
|
-
def add_port_redirection( r )
|
67
|
+
def add_port_redirection( r, use_ipv6 )
|
68
|
+
table = 'iptables'
|
69
|
+
cal_dst_address = r.dst_address
|
70
|
+
if use_ipv6
|
71
|
+
table = 'ip6tables'
|
72
|
+
# Prevent sending out ICMPv6 Redirect packets.
|
73
|
+
Shell.execute("#{table} -I OUTPUT -p icmpv6 --icmpv6-type redirect -j DROP")
|
74
|
+
|
75
|
+
# Ipv6 uses a different ip + port representation
|
76
|
+
cal_dst_address = "[#{r.dst_address}]"
|
77
|
+
end
|
54
78
|
# post route
|
55
|
-
Shell.execute(
|
79
|
+
Shell.execute("#{table} -t nat -I POSTROUTING -s 0/0 -j MASQUERADE")
|
56
80
|
# accept all
|
57
|
-
Shell.execute(
|
81
|
+
Shell.execute("#{table} -P FORWARD ACCEPT")
|
58
82
|
# add redirection
|
59
|
-
Shell.execute("
|
83
|
+
Shell.execute("#{table} -t nat -A PREROUTING -i #{r.interface} -p #{r.protocol} #{r.src_address.nil? ? '' : "-d #{r.src_address}"} --dport #{r.src_port} -j DNAT --to #{cal_dst_address}:#{r.dst_port}")
|
60
84
|
end
|
61
85
|
|
62
86
|
# Remove the +r+ BetterCap::Firewalls::Redirection port redirection object.
|
63
|
-
def del_port_redirection( r )
|
87
|
+
def del_port_redirection( r, use_ipv6 )
|
88
|
+
table = 'iptables'
|
89
|
+
cal_dst_address = r.dst_address
|
90
|
+
if use_ipv6
|
91
|
+
table = 'ip6tables'
|
92
|
+
# Ipv6 uses a different ip + port representation
|
93
|
+
cal_dst_address = "[#{r.dst_address}]"
|
94
|
+
end
|
64
95
|
# remove post route
|
65
|
-
Shell.execute(
|
96
|
+
Shell.execute("#{table} -t nat -D POSTROUTING -s 0/0 -j MASQUERADE")
|
66
97
|
# remove redirection
|
67
|
-
Shell.execute("
|
98
|
+
Shell.execute("#{table} -t nat -D PREROUTING -i #{r.interface} -p #{r.protocol} #{r.src_address.nil? ? '' : "-d #{r.src_address}"} --dport #{r.src_port} -j DNAT --to #{cal_dst_address}:#{r.dst_port}")
|
68
99
|
end
|
69
100
|
end
|
70
101
|
end
|
@@ -130,7 +130,7 @@ module PacketFu
|
|
130
130
|
ret[:ip_src] = [IPAddr.new($1).to_i].pack('N')
|
131
131
|
ret[:ip4_obj] = IPAddr.new($1)
|
132
132
|
ret[:ip4_obj] = ret[:ip4_obj].mask($3) if $3
|
133
|
-
when /
|
133
|
+
when /(fe80[^\/\s]*)/
|
134
134
|
begin
|
135
135
|
ret[:ip6_saddr] = $1
|
136
136
|
ret[:ip6_obj] = IPAddr.new($1)
|
@@ -207,4 +207,222 @@ module PacketFu
|
|
207
207
|
end
|
208
208
|
|
209
209
|
end
|
210
|
+
|
211
|
+
class NDPHeader < Struct.new(:ndp_type, :ndp_code, :ndp_sum,
|
212
|
+
:ndp_reserved, :ndp_tgt, :ndp_opt_type,
|
213
|
+
:ndp_opt_len, :ndp_lla, :body)
|
214
|
+
include StructFu
|
215
|
+
|
216
|
+
PROTOCOL_NUMBER = 58
|
217
|
+
|
218
|
+
def initialize(args={})
|
219
|
+
super(
|
220
|
+
Int8.new(args[:ndp_type]),
|
221
|
+
Int8.new(args[:ndp_code]),
|
222
|
+
Int16.new(args[:ndp_sum]),
|
223
|
+
Int32.new(args[:ndp_reserved]),
|
224
|
+
AddrIpv6.new.read(args[:ndp_tgt] || ("\x00" * 16)),
|
225
|
+
Int8.new(args[:ndp_opt_type]),
|
226
|
+
Int8.new(args[:ndp_opt_len]),
|
227
|
+
EthMac.new.read(args[:ndp_lla])
|
228
|
+
)
|
229
|
+
end
|
230
|
+
|
231
|
+
# Returns the object in string form.
|
232
|
+
def to_s
|
233
|
+
self.to_a.map {|x| x.to_s}.join
|
234
|
+
end
|
235
|
+
|
236
|
+
# Reads a string to populate the object.
|
237
|
+
def read(str)
|
238
|
+
force_binary(str)
|
239
|
+
return self if str.nil?
|
240
|
+
self[:ndp_type].read(str[0,1])
|
241
|
+
self[:ndp_code].read(str[1,1])
|
242
|
+
self[:ndp_sum].read(str[2,2])
|
243
|
+
self[:ndp_reserved].read(str[4,4])
|
244
|
+
self[:ndp_tgt].read(str[8,16])
|
245
|
+
self[:ndp_opt_type].read(str[24,1])
|
246
|
+
self[:ndp_opt_len].read(str[25,1])
|
247
|
+
self[:ndp_lla].read(str[26,2])
|
248
|
+
self
|
249
|
+
end
|
250
|
+
|
251
|
+
# Setter for the type.
|
252
|
+
def ndp_type=(i); typecast i; end
|
253
|
+
# Getter for the type.
|
254
|
+
def ndp_type; self[:ndp_type].to_i; end
|
255
|
+
# Setter for the code.
|
256
|
+
def ndp_code=(i); typecast i; end
|
257
|
+
# Getter for the code.
|
258
|
+
def ndp_code; self[:ndp_code].to_i; end
|
259
|
+
# Setter for the checksum. Note, this is calculated automatically with
|
260
|
+
# ndp_calc_sum.
|
261
|
+
def ndp_sum=(i); typecast i; end
|
262
|
+
# Getter for the checksum.
|
263
|
+
def ndp_sum; self[:ndp_sum].to_i; end
|
264
|
+
# Setter for the reserved.
|
265
|
+
def ndp_reserved=(i); typecast i; end
|
266
|
+
# Getter for the reserved.
|
267
|
+
def ndp_reserved; self[:ndp_reserved].to_i; end
|
268
|
+
# Setter for the target address.
|
269
|
+
def ndp_tgt=(i); typecast i; end
|
270
|
+
# Getter for the target address.
|
271
|
+
def ndp_tgt; self[:ndp_tgt].to_i; end
|
272
|
+
# Setter for the options type field.
|
273
|
+
def ndp_opt_type=(i); typecast i; end
|
274
|
+
# Getter for the options type field.
|
275
|
+
def ndp_opt_type; self[:ndp_opt_type].to_i; end
|
276
|
+
# Setter for the options length.
|
277
|
+
def ndp_opt_len=(i); typecast i; end
|
278
|
+
# Getter for the options length.
|
279
|
+
def ndp_opt_len; self[:ndp_opt_len].to_i; end
|
280
|
+
# Setter for the link local address.
|
281
|
+
def ndp_lla=(i); typecast i; end
|
282
|
+
# Getter for the link local address.
|
283
|
+
def ndp_lla; self[:ndp_lla].to_s; end
|
284
|
+
|
285
|
+
# Get target address in a more readable form.
|
286
|
+
def ndp_taddr
|
287
|
+
self[:ndp_tgt].to_x
|
288
|
+
end
|
289
|
+
|
290
|
+
# Set the target address in a more readable form.
|
291
|
+
def ndp_taddr=(str)
|
292
|
+
self[:ndp_tgt].read_x(str)
|
293
|
+
end
|
294
|
+
|
295
|
+
# Sets the link local address in a more readable way.
|
296
|
+
def ndp_lladdr=(mac)
|
297
|
+
mac = EthHeader.mac2str(mac)
|
298
|
+
self[:ndp_lla].read mac
|
299
|
+
self[:ndp_lla]
|
300
|
+
end
|
301
|
+
|
302
|
+
# Gets the link local address in a more readable way.
|
303
|
+
def ndp_lladdr
|
304
|
+
EthHeader.str2mac(self[:ndp_lla].to_s)
|
305
|
+
end
|
306
|
+
|
307
|
+
def ndp_sum_readable
|
308
|
+
"0x%04x" % ndp_sum
|
309
|
+
end
|
310
|
+
|
311
|
+
# Set flag bits (First three are flag bits, the rest are reserved).
|
312
|
+
def ndp_set_flags=(bits)
|
313
|
+
case bits
|
314
|
+
when "000"
|
315
|
+
self.ndp_reserved = 0x00000000
|
316
|
+
when "001"
|
317
|
+
self.ndp_reserved = 0x20000000
|
318
|
+
when "010"
|
319
|
+
self.ndp_reserved = 0x40000000
|
320
|
+
when "011"
|
321
|
+
self.ndp_reserved = 0x60000000
|
322
|
+
when "100"
|
323
|
+
self.ndp_reserved = 0x80000000
|
324
|
+
when "101"
|
325
|
+
self.ndp_reserved = 0xa0000000
|
326
|
+
when "110"
|
327
|
+
self.ndp_reserved = 0xc0000000
|
328
|
+
when "111"
|
329
|
+
self.ndp_reserved = 0xe0000000
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
alias :ndp_tgt_readable :ndp_taddr
|
334
|
+
alias :ndp_lla_readable :ndp_lladdr
|
335
|
+
|
336
|
+
end
|
337
|
+
|
338
|
+
module NDPHeaderMixin
|
339
|
+
def ndp_type=(v); self.ndp_header.ndp_type= v; end
|
340
|
+
def ndp_type; self.ndp_header.ndp_type; end
|
341
|
+
def ndp_code=(v); self.ndp_header.ndp_code= v; end
|
342
|
+
def ndp_code; self.ndp_header.ndp_code; end
|
343
|
+
def ndp_sum=(v); self.ndp_header.ndp_sum= v; end
|
344
|
+
def ndp_sum; self.ndp_header.ndp_sum; end
|
345
|
+
def ndp_sum_readable; self.ndp_header.ndp_sum_readable; end
|
346
|
+
def ndp_reserved=(v); self.ndp_header.ndp_reserved= v; end
|
347
|
+
def ndp_reserved; self.ndp_header.ndp_reserved; end
|
348
|
+
def ndp_tgt=(v); self.ndp_header.ndp_tgt= v; end
|
349
|
+
def ndp_tgt; self.ndp_header.ndp_tgt; end
|
350
|
+
def ndp_taddr=(v); self.ndp_header.ndp_taddr= v; end
|
351
|
+
def ndp_taddr; self.ndp_header.ndp_taddr; end
|
352
|
+
def ndp_tgt_readable; self.ndp_header.ndp_tgt_readable; end
|
353
|
+
def ndp_opt_type=(v); self.ndp_header.ndp_opt_type= v; end
|
354
|
+
def ndp_opt_type; self.ndp_header.ndp_opt_type; end
|
355
|
+
def ndp_opt_len=(v); self.ndp_header.ndp_opt_len=v; end
|
356
|
+
def ndp_opt_len;self.ndp_header.ndp_opt_len; end
|
357
|
+
def ndp_lla=(v); self.ndp_header.ndp_lla=v; end
|
358
|
+
def ndp_lla;self.ndp_header.ndp_lla; end
|
359
|
+
def ndp_laddr=(v); self.ndp_header.ndp_laddr= v; end
|
360
|
+
def ndp_laddr; self.ndp_header.ndp_laddr; end
|
361
|
+
def ndp_lla_readable; self.ndp_header.ndp_lla_readable; end
|
362
|
+
def ndp_set_flags=(v); self.ndp_header.ndp_set_flags= v; end
|
363
|
+
end
|
364
|
+
|
365
|
+
|
366
|
+
class NDPPacket < Packet
|
367
|
+
include ::PacketFu::EthHeaderMixin
|
368
|
+
include ::PacketFu::IPv6HeaderMixin
|
369
|
+
include PacketFu::NDPHeaderMixin
|
370
|
+
|
371
|
+
attr_accessor :eth_header, :ipv6_header, :ndp_header
|
372
|
+
|
373
|
+
def initialize(args={})
|
374
|
+
@eth_header = EthHeader.new(args).read(args[:eth])
|
375
|
+
@ipv6_header = IPv6Header.new(args).read(args[:ipv6])
|
376
|
+
@ipv6_header.ipv6_next = PacketFu::NDPHeader::PROTOCOL_NUMBER
|
377
|
+
@ndp_header = NDPHeader.new(args).read(args[:ndp])
|
378
|
+
|
379
|
+
@ipv6_header.body = @ndp_header
|
380
|
+
@eth_header.body = @ipv6_header
|
381
|
+
|
382
|
+
@headers = [@eth_header, @ipv6_header, @ndp_header]
|
383
|
+
super
|
384
|
+
ndp_calc_sum
|
385
|
+
end
|
386
|
+
|
387
|
+
# Calculates the checksum for the object.
|
388
|
+
def ndp_calc_sum
|
389
|
+
checksum = 0
|
390
|
+
|
391
|
+
# Compute sum on pseudo-header
|
392
|
+
[ipv6_src, ipv6_dst].each do |iaddr|
|
393
|
+
8.times { |i| checksum += (iaddr >> (i*16)) & 0xffff }
|
394
|
+
end
|
395
|
+
checksum += PacketFu::NDPHeader::PROTOCOL_NUMBER
|
396
|
+
checksum += ipv6_len
|
397
|
+
# Continue with entire ICMPv6 message.
|
398
|
+
checksum += (ndp_type.to_i << 8) + ndp_code.to_i
|
399
|
+
checksum += ndp_reserved.to_i >> 16
|
400
|
+
checksum += ndp_reserved.to_i & 0xffff
|
401
|
+
8.times { |i| checksum += (ndp_tgt.to_i >> (i*16)) & 0xffff }
|
402
|
+
checksum += (ndp_opt_type.to_i << 8) + ndp_opt_len.to_i
|
403
|
+
|
404
|
+
mac2int = ndp_lla.to_s.unpack('H*').first.to_i(16)
|
405
|
+
3.times { |i| checksum += (mac2int >> (i*16)) & 0xffff }
|
406
|
+
|
407
|
+
checksum = checksum % 0xffff
|
408
|
+
checksum = 0xffff - checksum
|
409
|
+
checksum == 0 ? 0xffff : checksum
|
410
|
+
|
411
|
+
end
|
412
|
+
|
413
|
+
# Recalculates the calculatable fields for NDP.
|
414
|
+
def ndp_recalc(arg=:all)
|
415
|
+
arg = arg.intern if arg.respond_to? :intern
|
416
|
+
case arg
|
417
|
+
when :ndp_sum
|
418
|
+
self.ndp_sum = ndp_calc_sum
|
419
|
+
when :all
|
420
|
+
self.ndp_sum = ndp_calc_sum
|
421
|
+
else
|
422
|
+
raise ArgumentError, "No such field `#{arg}'"
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
end
|
427
|
+
|
210
428
|
end
|