bettercap 1.6.0 → 1.6.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|