/plugins/providers/virtualbox/action/network_fix_ipv6.rb
Ruby | 84 lines | 58 code | 16 blank | 10 comment | 12 complexity | 09c7a53893cb59b89a7994f4727ecd0b MD5 | raw file
Possible License(s): MIT
- require "ipaddr"
- require "socket"
- require "log4r"
- require "vagrant/util/presence"
- require "vagrant/util/scoped_hash_override"
- module VagrantPlugins
- module ProviderVirtualBox
- module Action
- # This middleware works around a bug in VirtualBox where booting
- # a VM with an IPv6 host-only network will sometimes lose the
- # route to that machine.
- class NetworkFixIPv6
- include Vagrant::Util::Presence
- include Vagrant::Util::ScopedHashOverride
- def initialize(app, env)
- @logger = Log4r::Logger.new("vagrant::plugins::virtualbox::network")
- @app = app
- end
- def call(env)
- @env = env
- # Determine if we have an IPv6 network
- has_v6 = false
- env[:machine].config.vm.networks.each do |type, options|
- next if type != :private_network
- options = scoped_hash_override(options, :virtualbox)
- next if options[:ip].to_s.strip == ""
- if IPAddr.new(options[:ip]).ipv6?
- has_v6 = true
- break
- end
- end
- # Call up
- @app.call(env)
- # If we have no IPv6, forget it
- return if !has_v6
- link_local_range = IPAddr.new("fe80::/10")
- host_only_interfaces(env).each do |interface|
- next if !present?(interface[:ipv6])
- next if interface[:status] != "Up"
- ip = IPAddr.new(interface[:ipv6])
- ip |= ("1" * (128 - interface[:ipv6_prefix].to_i)).to_i(2)
- next if link_local_range.include?(ip)
- @logger.info("testing IPv6: #{ip}")
- begin
- UDPSocket.new(Socket::AF_INET6).connect(ip.to_s, 80)
- rescue Errno::EHOSTUNREACH
- @logger.info("IPv6 host unreachable. Fixing: #{ip}")
- env[:machine].provider.driver.reconfig_host_only(interface)
- end
- end
- end
- # The list of interface names for host-only adapters.
- # @return [Array<String>]
- def host_only_interface_names(env)
- env[:machine].provider.driver.read_network_interfaces
- .map { |_, i| i[:hostonly] if i[:type] == :hostonly }.compact
- end
- # The list of host_only_interfaces that are tied to a host-only adapter.
- # @return [Array]
- def host_only_interfaces(env)
- iface_names = self.host_only_interface_names(env)
- env[:machine].provider.driver.read_host_only_interfaces
- .select { |interface| iface_names.include?(interface[:name]) }
- end
- end
- end
- end
- end