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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 51ee5970551588bd53601e02295aaa61d920ffac
4
- data.tar.gz: 6be88ed0348867abc1791019c53c0e610bcef1b0
3
+ metadata.gz: 490c8b7f32ca7a9764aba54e0b7a5e8fb6d42f0f
4
+ data.tar.gz: d004aed04c55b7244ca61fd9a1c0dbbdd86d9042
5
5
  SHA512:
6
- metadata.gz: 8def2b5962b579c2a0164d6e19ddf376cadf67bc73d21ec8084eaa762340c7b0d6bebc1eea7c535ece356c0bfe95bf9b78c03659a660f02470786344b83e8e1a
7
- data.tar.gz: 0135d3bcfe282cac63215b8ec54f78557b8d1347f9ee24a9cae535944f2287efbe52f5ea3eb8e3b113cae93326d7ed64dee852ae381895019e8a1630670c7b28
6
+ metadata.gz: 341644a5eb60a927046fd9c8300bbff5be5df6bacc8f4a381fa4d48624a52f712be07532869e73f63b4ecdbad207dbee8a30229236fbffd2c9edc733ceaeb809
7
+ data.tar.gz: 736d8de6d05140d0252c8abad7eb5e59fc69c84f8a2a4ff59b12e9d7e72f37eaeab0bf2e55dd77d74873c8d18c5d06a75a1bffa420c24dc75b6e9fbecfbc201f
@@ -19,6 +19,8 @@ Encoding.default_internal = Encoding::UTF_8
19
19
 
20
20
  require 'packetfu'
21
21
  require 'em-proxy'
22
+ require 'eventmachine'
23
+ require 'socket'
22
24
  require 'webrick'
23
25
  require 'rubydns'
24
26
  require 'colorize'
@@ -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
@@ -119,7 +119,7 @@ class Thread
119
119
 
120
120
  prev = @ctx.targets
121
121
 
122
- sleep(1) if @ctx.options.core.discovery?
122
+ sleep(1)
123
123
  end
124
124
  end
125
125
  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('iptables -t nat -I POSTROUTING -s 0/0 -j MASQUERADE')
79
+ Shell.execute("#{table} -t nat -I POSTROUTING -s 0/0 -j MASQUERADE")
56
80
  # accept all
57
- Shell.execute('iptables -P FORWARD ACCEPT')
81
+ Shell.execute("#{table} -P FORWARD ACCEPT")
58
82
  # add redirection
59
- Shell.execute("iptables -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 #{r.dst_address}:#{r.dst_port}")
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('iptables -t nat -D POSTROUTING -s 0/0 -j MASQUERADE')
96
+ Shell.execute("#{table} -t nat -D POSTROUTING -s 0/0 -j MASQUERADE")
66
97
  # remove redirection
67
- Shell.execute("iptables -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 #{r.dst_address}:#{r.dst_port}")
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 /inet6 [a-z]+:[\s]*([0-9a-fA-F:\x2f]+)/
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