Merge pull request #6652 from mitchellh/pr-6596

Only consider the VM interfaces in the IPv6 fixup
This commit is contained in:
Seth Vargo 2015-12-08 11:15:22 -05:00
commit 3ac1bfc6d9
2 changed files with 155 additions and 7 deletions

View File

@ -3,6 +3,7 @@ require "socket"
require "log4r"
require "vagrant/util/presence"
require "vagrant/util/scoped_hash_override"
module VagrantPlugins
@ -12,6 +13,7 @@ module VagrantPlugins
# a VM with an IPv6 host-only network will someties lose the
# route to that machine.
class NetworkFixIPv6
include Vagrant::Util::Presence
include Vagrant::Util::ScopedHashOverride
def initialize(app, env)
@ -41,16 +43,15 @@ module VagrantPlugins
# If we have no IPv6, forget it
return if !has_v6
# We do, so fix them if we must
env[:machine].provider.driver.read_host_only_interfaces.each do |interface|
# Ignore interfaces without an IPv6 address
next if interface[:ipv6] == ""
host_only_interfaces(env).each do |interface|
next if !present?(interface[:ipv6])
next if interface[:status] != "Up"
# Make the test IP. This is just the highest value IP
ip = IPAddr.new(interface[:ipv6])
ip |= IPAddr.new(":#{":FFFF" * (interface[:ipv6_prefix].to_i / 16)}")
ip |= ("1" * (128 - interface[:ipv6_prefix].to_i)).to_i(2)
@logger.info("testing IPv6: #{ip}")
begin
UDPSocket.new(Socket::AF_INET6).connect(ip.to_s, 80)
rescue Errno::EHOSTUNREACH
@ -59,6 +60,21 @@ module VagrantPlugins
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

View File

@ -1,4 +1,5 @@
require_relative "../base"
require 'socket'
describe VagrantPlugins::ProviderVirtualBox::Action::NetworkFixIPv6 do
include_context "unit"
@ -11,11 +12,14 @@ describe VagrantPlugins::ProviderVirtualBox::Action::NetworkFixIPv6 do
end
let(:machine) do
iso_env.machine(iso_env.machine_names[0], :dummy)
iso_env.machine(iso_env.machine_names[0], :dummy).tap do |m|
m.provider.stub(driver: driver)
end
end
let(:env) {{ machine: machine }}
let(:app) { lambda { |*args| }}
let(:driver) { double("driver") }
subject { described_class.new(app, env) }
@ -30,4 +34,132 @@ describe VagrantPlugins::ProviderVirtualBox::Action::NetworkFixIPv6 do
.and_return(private_network: { ip: "" })
expect { subject.call(env) }.to_not raise_error
end
context "with IPv6 interfaces" do
let(:socket) { double("socket") }
before do
# This address is only used to trigger the fixup code. It doesn't matter
# what it is.
allow(machine.config.vm).to receive(:networks)
.and_return(private_network: { ip: 'fe:80::' })
allow(UDPSocket).to receive(:new).with(Socket::AF_INET6)
.and_return(socket)
socket.stub(:connect)
end
it "only checks the interfaces associated with the VM" do
all_networks = [{name: "vboxnet0",
ipv6: "dead:beef::",
ipv6_prefix: 64,
status: 'Up'
},
{name: "vboxnet1",
ipv6: "badd:badd::",
ipv6_prefix: 64,
status: 'Up'
}
]
ifaces = { 1 => {type: :hostonly, hostonly: "vboxnet0"}
}
allow(machine.provider.driver).to receive(:read_network_interfaces)
.and_return(ifaces)
allow(machine.provider.driver).to receive(:read_host_only_interfaces)
.and_return(all_networks)
subject.call(env)
expect(socket).to have_received(:connect)
.with(all_networks[0][:ipv6] + (['ffff']*4).join(':'), 80)
end
it "correctly uses the netmask to figure out the probe address" do
all_networks = [{name: "vboxnet0",
ipv6: "dead:beef::",
ipv6_prefix: 113,
status: 'Up'
}
]
ifaces = { 1 => {type: :hostonly, hostonly: "vboxnet0"}
}
allow(machine.provider.driver).to receive(:read_network_interfaces)
.and_return(ifaces)
allow(machine.provider.driver).to receive(:read_host_only_interfaces)
.and_return(all_networks)
subject.call(env)
expect(socket).to have_received(:connect)
.with(all_networks[0][:ipv6] + '7fff', 80)
end
it "should ignore interfaces that are down" do
all_networks = [{name: "vboxnet0",
ipv6: "dead:beef::",
ipv6_prefix: 64,
status: 'Down'
}
]
ifaces = { 1 => {type: :hostonly, hostonly: "vboxnet0"}
}
allow(machine.provider.driver).to receive(:read_network_interfaces)
.and_return(ifaces)
allow(machine.provider.driver).to receive(:read_host_only_interfaces)
.and_return(all_networks)
subject.call(env)
expect(socket).to_not have_received(:connect)
end
it "should ignore interfaces without an IPv6 address" do
all_networks = [{name: "vboxnet0",
ipv6: "",
ipv6_prefix: 0,
status: 'Up'
}
]
ifaces = { 1 => {type: :hostonly, hostonly: "vboxnet0"}
}
allow(machine.provider.driver).to receive(:read_network_interfaces)
.and_return(ifaces)
allow(machine.provider.driver).to receive(:read_host_only_interfaces)
.and_return(all_networks)
subject.call(env)
expect(socket).to_not have_received(:connect)
end
it "should ignore nat interfaces" do
all_networks = [{name: "vboxnet0",
ipv6: "",
ipv6_prefix: 0,
status: 'Up'
}
]
ifaces = { 1 => {type: :nat}
}
allow(machine.provider.driver).to receive(:read_network_interfaces)
.and_return(ifaces)
allow(machine.provider.driver).to receive(:read_host_only_interfaces)
.and_return(all_networks)
subject.call(env)
expect(socket).to_not have_received(:connect)
end
it "should reconfigure an interface if unreachable" do
all_networks = [{name: "vboxnet0",
ipv6: "dead:beef::",
ipv6_prefix: 64,
status: 'Up'
}
]
ifaces = { 1 => {type: :hostonly, hostonly: "vboxnet0"}
}
allow(machine.provider.driver).to receive(:read_network_interfaces)
.and_return(ifaces)
allow(machine.provider.driver).to receive(:read_host_only_interfaces)
.and_return(all_networks)
allow(socket).to receive(:connect)
.with(all_networks[0][:ipv6] + (['ffff']*4).join(':'), 80)
.and_raise Errno::EHOSTUNREACH
allow(machine.provider.driver).to receive(:reconfig_host_only)
subject.call(env)
expect(machine.provider.driver).to have_received(:reconfig_host_only)
.with(all_networks[0])
end
end
end