PageRenderTime 41ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/providers/virtualbox/action/network_fix_ipv6.rb

http://github.com/mitchellh/vagrant
Ruby | 84 lines | 58 code | 16 blank | 10 comment | 12 complexity | 09c7a53893cb59b89a7994f4727ecd0b MD5 | raw file
Possible License(s): MIT
  1. require "ipaddr"
  2. require "socket"
  3. require "log4r"
  4. require "vagrant/util/presence"
  5. require "vagrant/util/scoped_hash_override"
  6. module VagrantPlugins
  7. module ProviderVirtualBox
  8. module Action
  9. # This middleware works around a bug in VirtualBox where booting
  10. # a VM with an IPv6 host-only network will sometimes lose the
  11. # route to that machine.
  12. class NetworkFixIPv6
  13. include Vagrant::Util::Presence
  14. include Vagrant::Util::ScopedHashOverride
  15. def initialize(app, env)
  16. @logger = Log4r::Logger.new("vagrant::plugins::virtualbox::network")
  17. @app = app
  18. end
  19. def call(env)
  20. @env = env
  21. # Determine if we have an IPv6 network
  22. has_v6 = false
  23. env[:machine].config.vm.networks.each do |type, options|
  24. next if type != :private_network
  25. options = scoped_hash_override(options, :virtualbox)
  26. next if options[:ip].to_s.strip == ""
  27. if IPAddr.new(options[:ip]).ipv6?
  28. has_v6 = true
  29. break
  30. end
  31. end
  32. # Call up
  33. @app.call(env)
  34. # If we have no IPv6, forget it
  35. return if !has_v6
  36. link_local_range = IPAddr.new("fe80::/10")
  37. host_only_interfaces(env).each do |interface|
  38. next if !present?(interface[:ipv6])
  39. next if interface[:status] != "Up"
  40. ip = IPAddr.new(interface[:ipv6])
  41. ip |= ("1" * (128 - interface[:ipv6_prefix].to_i)).to_i(2)
  42. next if link_local_range.include?(ip)
  43. @logger.info("testing IPv6: #{ip}")
  44. begin
  45. UDPSocket.new(Socket::AF_INET6).connect(ip.to_s, 80)
  46. rescue Errno::EHOSTUNREACH
  47. @logger.info("IPv6 host unreachable. Fixing: #{ip}")
  48. env[:machine].provider.driver.reconfig_host_only(interface)
  49. end
  50. end
  51. end
  52. # The list of interface names for host-only adapters.
  53. # @return [Array<String>]
  54. def host_only_interface_names(env)
  55. env[:machine].provider.driver.read_network_interfaces
  56. .map { |_, i| i[:hostonly] if i[:type] == :hostonly }.compact
  57. end
  58. # The list of host_only_interfaces that are tied to a host-only adapter.
  59. # @return [Array]
  60. def host_only_interfaces(env)
  61. iface_names = self.host_only_interface_names(env)
  62. env[:machine].provider.driver.read_host_only_interfaces
  63. .select { |interface| iface_names.include?(interface[:name]) }
  64. end
  65. end
  66. end
  67. end
  68. end