Merge pull request #6342 from mitchellh/f-ipv6
IPv6 Host-Only Networks (VirtualBox)
This commit is contained in:
commit
0a096ec5f8
|
@ -1,10 +1,21 @@
|
||||||
|
require "ipaddr"
|
||||||
|
|
||||||
module Vagrant
|
module Vagrant
|
||||||
module Util
|
module Util
|
||||||
module NetworkIP
|
module NetworkIP
|
||||||
# Returns the network address of the given IP and subnet.
|
# Returns the network address of the given IP and subnet.
|
||||||
#
|
#
|
||||||
|
# If the IP address is an IPv6 address, subnet should be a prefix
|
||||||
|
# length such as "64".
|
||||||
|
#
|
||||||
# @return [String]
|
# @return [String]
|
||||||
def network_address(ip, subnet)
|
def network_address(ip, subnet)
|
||||||
|
# If this is an IPv6 address, then just mask it
|
||||||
|
if subnet.to_s =~ /^\d+$/
|
||||||
|
ip = IPAddr.new(ip)
|
||||||
|
return ip.mask(subnet.to_i).to_s
|
||||||
|
end
|
||||||
|
|
||||||
ip = ip_parts(ip)
|
ip = ip_parts(ip)
|
||||||
netmask = ip_parts(subnet)
|
netmask = ip_parts(subnet)
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ module VagrantPlugins
|
||||||
autoload :MessageNotRunning, File.expand_path("../action/message_not_running", __FILE__)
|
autoload :MessageNotRunning, File.expand_path("../action/message_not_running", __FILE__)
|
||||||
autoload :MessageWillNotDestroy, File.expand_path("../action/message_will_not_destroy", __FILE__)
|
autoload :MessageWillNotDestroy, File.expand_path("../action/message_will_not_destroy", __FILE__)
|
||||||
autoload :Network, File.expand_path("../action/network", __FILE__)
|
autoload :Network, File.expand_path("../action/network", __FILE__)
|
||||||
|
autoload :NetworkFixIPv6, File.expand_path("../action/network_fix_ipv6", __FILE__)
|
||||||
autoload :Package, File.expand_path("../action/package", __FILE__)
|
autoload :Package, File.expand_path("../action/package", __FILE__)
|
||||||
autoload :PackageVagrantfile, File.expand_path("../action/package_vagrantfile", __FILE__)
|
autoload :PackageVagrantfile, File.expand_path("../action/package_vagrantfile", __FILE__)
|
||||||
autoload :PrepareNFSSettings, File.expand_path("../action/prepare_nfs_settings", __FILE__)
|
autoload :PrepareNFSSettings, File.expand_path("../action/prepare_nfs_settings", __FILE__)
|
||||||
|
@ -63,6 +64,7 @@ module VagrantPlugins
|
||||||
b.use PrepareNFSSettings
|
b.use PrepareNFSSettings
|
||||||
b.use ClearNetworkInterfaces
|
b.use ClearNetworkInterfaces
|
||||||
b.use Network
|
b.use Network
|
||||||
|
b.use NetworkFixIPv6
|
||||||
b.use ForwardPorts
|
b.use ForwardPorts
|
||||||
b.use SetHostname
|
b.use SetHostname
|
||||||
b.use SaneDefaults
|
b.use SaneDefaults
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
require "ipaddr"
|
||||||
require "set"
|
require "set"
|
||||||
|
|
||||||
require "log4r"
|
require "log4r"
|
||||||
|
@ -248,7 +249,6 @@ module VagrantPlugins
|
||||||
auto_config: true,
|
auto_config: true,
|
||||||
mac: nil,
|
mac: nil,
|
||||||
nic_type: nil,
|
nic_type: nil,
|
||||||
netmask: "255.255.255.0",
|
|
||||||
type: :static
|
type: :static
|
||||||
}.merge(options)
|
}.merge(options)
|
||||||
|
|
||||||
|
@ -258,31 +258,47 @@ module VagrantPlugins
|
||||||
# Default IP is in the 20-bit private network block for DHCP based networks
|
# Default IP is in the 20-bit private network block for DHCP based networks
|
||||||
options[:ip] = "172.28.128.1" if options[:type] == :dhcp && !options[:ip]
|
options[:ip] = "172.28.128.1" if options[:type] == :dhcp && !options[:ip]
|
||||||
|
|
||||||
# Calculate our network address for the given IP/netmask
|
ip = IPAddr.new(options[:ip])
|
||||||
netaddr = network_address(options[:ip], options[:netmask])
|
if ip.ipv4?
|
||||||
|
options[:netmask] ||= "255.255.255.0"
|
||||||
|
|
||||||
# Verify that a host-only network subnet would not collide
|
# Calculate our network address for the given IP/netmask
|
||||||
# with a bridged networking interface.
|
netaddr = network_address(options[:ip], options[:netmask])
|
||||||
#
|
|
||||||
# If the subnets overlap in any way then the host only network
|
# Verify that a host-only network subnet would not collide
|
||||||
# will not work because the routing tables will force the
|
# with a bridged networking interface.
|
||||||
# traffic onto the real interface rather than the VirtualBox
|
#
|
||||||
# interface.
|
# If the subnets overlap in any way then the host only network
|
||||||
@env[:machine].provider.driver.read_bridged_interfaces.each do |interface|
|
# will not work because the routing tables will force the
|
||||||
that_netaddr = network_address(interface[:ip], interface[:netmask])
|
# traffic onto the real interface rather than the VirtualBox
|
||||||
raise Vagrant::Errors::NetworkCollision if \
|
# interface.
|
||||||
netaddr == that_netaddr && interface[:status] != "Down"
|
@env[:machine].provider.driver.read_bridged_interfaces.each do |interface|
|
||||||
|
that_netaddr = network_address(interface[:ip], interface[:netmask])
|
||||||
|
raise Vagrant::Errors::NetworkCollision if \
|
||||||
|
netaddr == that_netaddr && interface[:status] != "Down"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Split the IP address into its components
|
||||||
|
ip_parts = netaddr.split(".").map { |i| i.to_i }
|
||||||
|
|
||||||
|
# Calculate the adapter IP, which we assume is the IP ".1" at
|
||||||
|
# the end usually.
|
||||||
|
adapter_ip = ip_parts.dup
|
||||||
|
adapter_ip[3] += 1
|
||||||
|
options[:adapter_ip] ||= adapter_ip.join(".")
|
||||||
|
elsif ip.ipv6?
|
||||||
|
# Default subnet prefix length
|
||||||
|
options[:netmask] ||= 64
|
||||||
|
|
||||||
|
# IPv6 we just mask the address and use that as the adapter
|
||||||
|
options[:adapter_ip] ||= ip.mask(options[:netmask].to_i).to_s
|
||||||
|
|
||||||
|
# Append a 6 to the end of the type
|
||||||
|
options[:type] = "#{options[:type]}6".to_sym
|
||||||
|
else
|
||||||
|
raise "BUG: Unknown IP type: #{ip.inspect}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Split the IP address into its components
|
|
||||||
ip_parts = netaddr.split(".").map { |i| i.to_i }
|
|
||||||
|
|
||||||
# Calculate the adapter IP, which we assume is the IP ".1" at
|
|
||||||
# the end usually.
|
|
||||||
adapter_ip = ip_parts.dup
|
|
||||||
adapter_ip[3] += 1
|
|
||||||
options[:adapter_ip] ||= adapter_ip.join(".")
|
|
||||||
|
|
||||||
dhcp_options = {}
|
dhcp_options = {}
|
||||||
if options[:type] == :dhcp
|
if options[:type] == :dhcp
|
||||||
# Calculate the DHCP server IP, which is the network address
|
# Calculate the DHCP server IP, which is the network address
|
||||||
|
@ -456,8 +472,16 @@ module VagrantPlugins
|
||||||
|
|
||||||
@env[:machine].provider.driver.read_host_only_interfaces.each do |interface|
|
@env[:machine].provider.driver.read_host_only_interfaces.each do |interface|
|
||||||
return interface if config[:name] && config[:name] == interface[:name]
|
return interface if config[:name] && config[:name] == interface[:name]
|
||||||
return interface if this_netaddr == \
|
|
||||||
network_address(interface[:ip], interface[:netmask])
|
if interface[:ip] != ""
|
||||||
|
return interface if this_netaddr == \
|
||||||
|
network_address(interface[:ip], interface[:netmask])
|
||||||
|
end
|
||||||
|
|
||||||
|
if interface[:ipv6] != ""
|
||||||
|
return interface if this_netaddr == \
|
||||||
|
network_address(interface[:ipv6], interface[:ipv6_prefix])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
nil
|
nil
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
require "ipaddr"
|
||||||
|
require "socket"
|
||||||
|
|
||||||
|
require "log4r"
|
||||||
|
|
||||||
|
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 someties lose the
|
||||||
|
# route to that machine.
|
||||||
|
class NetworkFixIPv6
|
||||||
|
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] == ""
|
||||||
|
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
|
||||||
|
|
||||||
|
# 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] == ""
|
||||||
|
|
||||||
|
# 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)}")
|
||||||
|
|
||||||
|
@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
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -263,6 +263,14 @@ module VagrantPlugins
|
||||||
def read_vms
|
def read_vms
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Reconfigure the hostonly network given by interface (the result
|
||||||
|
# of read_host_only_networks). This is a sad function that only
|
||||||
|
# exists to work around VirtualBox bugs.
|
||||||
|
#
|
||||||
|
# @return nil
|
||||||
|
def reconfig_host_only(interface)
|
||||||
|
end
|
||||||
|
|
||||||
# Removes the DHCP server identified by the provided network name.
|
# Removes the DHCP server identified by the provided network name.
|
||||||
#
|
#
|
||||||
# @param [String] network_name The the full network name associated
|
# @param [String] network_name The the full network name associated
|
||||||
|
|
|
@ -109,6 +109,7 @@ module VagrantPlugins
|
||||||
:read_state,
|
:read_state,
|
||||||
:read_used_ports,
|
:read_used_ports,
|
||||||
:read_vms,
|
:read_vms,
|
||||||
|
:reconfig_host_only,
|
||||||
:remove_dhcp_server,
|
:remove_dhcp_server,
|
||||||
:resume,
|
:resume,
|
||||||
:set_mac_address,
|
:set_mac_address,
|
||||||
|
|
|
@ -48,10 +48,19 @@ module VagrantPlugins
|
||||||
interface = execute("hostonlyif", "create")
|
interface = execute("hostonlyif", "create")
|
||||||
name = interface[/^Interface '(.+?)' was successfully created$/, 1]
|
name = interface[/^Interface '(.+?)' was successfully created$/, 1]
|
||||||
|
|
||||||
# Configure it
|
# Get the IP so we can determine v4 vs v6
|
||||||
execute("hostonlyif", "ipconfig", name,
|
ip = IPAddr.new(options[:adapter_ip])
|
||||||
"--ip", options[:adapter_ip],
|
|
||||||
"--netmask", options[:netmask])
|
# Configure
|
||||||
|
if ip.ipv4?
|
||||||
|
execute("hostonlyif", "ipconfig", name,
|
||||||
|
"--ip", options[:adapter_ip],
|
||||||
|
"--netmask", options[:netmask])
|
||||||
|
elsif ip.ipv6?
|
||||||
|
execute("hostonlyif", "ipconfig", name,
|
||||||
|
"--ipv6", options[:adapter_ip],
|
||||||
|
"--netmasklengthv6", options[:netmask].to_s)
|
||||||
|
end
|
||||||
|
|
||||||
# Return the details
|
# Return the details
|
||||||
return {
|
return {
|
||||||
|
@ -320,6 +329,10 @@ module VagrantPlugins
|
||||||
info[:ip] = ip
|
info[:ip] = ip
|
||||||
elsif netmask = line[/^NetworkMask:\s+(.+?)$/, 1]
|
elsif netmask = line[/^NetworkMask:\s+(.+?)$/, 1]
|
||||||
info[:netmask] = netmask
|
info[:netmask] = netmask
|
||||||
|
elsif line =~ /^IPV6Address:\s+(.+?)$/
|
||||||
|
info[:ipv6] = $1.to_s.strip
|
||||||
|
elsif line =~ /^IPV6NetworkMaskPrefixLength:\s+(.+?)$/
|
||||||
|
info[:ipv6_prefix] = $1.to_s.strip
|
||||||
elsif status = line[/^Status:\s+(.+?)$/, 1]
|
elsif status = line[/^Status:\s+(.+?)$/, 1]
|
||||||
info[:status] = status
|
info[:status] = status
|
||||||
end
|
end
|
||||||
|
@ -429,6 +442,11 @@ module VagrantPlugins
|
||||||
results
|
results
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reconfig_host_only(interface)
|
||||||
|
execute("hostonlyif", "ipconfig", interface[:name],
|
||||||
|
"--ipv6", interface[:ipv6])
|
||||||
|
end
|
||||||
|
|
||||||
def remove_dhcp_server(network_name)
|
def remove_dhcp_server(network_name)
|
||||||
execute("dhcpserver", "remove", "--netname", network_name)
|
execute("dhcpserver", "remove", "--netname", network_name)
|
||||||
end
|
end
|
||||||
|
|
|
@ -48,10 +48,19 @@ module VagrantPlugins
|
||||||
interface = execute("hostonlyif", "create")
|
interface = execute("hostonlyif", "create")
|
||||||
name = interface[/^Interface '(.+?)' was successfully created$/, 1]
|
name = interface[/^Interface '(.+?)' was successfully created$/, 1]
|
||||||
|
|
||||||
# Configure it
|
# Get the IP so we can determine v4 vs v6
|
||||||
execute("hostonlyif", "ipconfig", name,
|
ip = IPAddr.new(options[:adapter_ip])
|
||||||
"--ip", options[:adapter_ip],
|
|
||||||
"--netmask", options[:netmask])
|
# Configure
|
||||||
|
if ip.ipv4?
|
||||||
|
execute("hostonlyif", "ipconfig", name,
|
||||||
|
"--ip", options[:adapter_ip],
|
||||||
|
"--netmask", options[:netmask])
|
||||||
|
elsif ip.ipv6?
|
||||||
|
execute("hostonlyif", "ipconfig", name,
|
||||||
|
"--ipv6", options[:adapter_ip],
|
||||||
|
"--netmasklengthv6", options[:netmask].to_s)
|
||||||
|
end
|
||||||
|
|
||||||
# Return the details
|
# Return the details
|
||||||
return {
|
return {
|
||||||
|
@ -325,6 +334,10 @@ module VagrantPlugins
|
||||||
info[:ip] = ip
|
info[:ip] = ip
|
||||||
elsif netmask = line[/^NetworkMask:\s+(.+?)$/, 1]
|
elsif netmask = line[/^NetworkMask:\s+(.+?)$/, 1]
|
||||||
info[:netmask] = netmask
|
info[:netmask] = netmask
|
||||||
|
elsif line =~ /^IPV6Address:\s+(.+?)$/
|
||||||
|
info[:ipv6] = $1.to_s.strip
|
||||||
|
elsif line =~ /^IPV6NetworkMaskPrefixLength:\s+(.+?)$/
|
||||||
|
info[:ipv6_prefix] = $1.to_s.strip
|
||||||
elsif status = line[/^Status:\s+(.+?)$/, 1]
|
elsif status = line[/^Status:\s+(.+?)$/, 1]
|
||||||
info[:status] = status
|
info[:status] = status
|
||||||
end
|
end
|
||||||
|
@ -434,6 +447,11 @@ module VagrantPlugins
|
||||||
results
|
results
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reconfig_host_only(interface)
|
||||||
|
execute("hostonlyif", "ipconfig", interface[:name],
|
||||||
|
"--ipv6", interface[:ipv6])
|
||||||
|
end
|
||||||
|
|
||||||
def remove_dhcp_server(network_name)
|
def remove_dhcp_server(network_name)
|
||||||
execute("dhcpserver", "remove", "--netname", network_name)
|
execute("dhcpserver", "remove", "--netname", network_name)
|
||||||
end
|
end
|
||||||
|
|
|
@ -46,12 +46,21 @@ module VagrantPlugins
|
||||||
def create_host_only_network(options)
|
def create_host_only_network(options)
|
||||||
# Create the interface
|
# Create the interface
|
||||||
execute("hostonlyif", "create") =~ /^Interface '(.+?)' was successfully created$/
|
execute("hostonlyif", "create") =~ /^Interface '(.+?)' was successfully created$/
|
||||||
name = $1.to_s
|
name = $1.to_s
|
||||||
|
|
||||||
# Configure it
|
# Get the IP so we can determine v4 vs v6
|
||||||
execute("hostonlyif", "ipconfig", name,
|
ip = IPAddr.new(options[:adapter_ip])
|
||||||
"--ip", options[:adapter_ip],
|
|
||||||
"--netmask", options[:netmask])
|
# Configure
|
||||||
|
if ip.ipv4?
|
||||||
|
execute("hostonlyif", "ipconfig", name,
|
||||||
|
"--ip", options[:adapter_ip],
|
||||||
|
"--netmask", options[:netmask])
|
||||||
|
elsif ip.ipv6?
|
||||||
|
execute("hostonlyif", "ipconfig", name,
|
||||||
|
"--ipv6", options[:adapter_ip],
|
||||||
|
"--netmasklengthv6", options[:netmask].to_s)
|
||||||
|
end
|
||||||
|
|
||||||
# Return the details
|
# Return the details
|
||||||
return {
|
return {
|
||||||
|
@ -356,6 +365,10 @@ module VagrantPlugins
|
||||||
info[:ip] = $1.to_s
|
info[:ip] = $1.to_s
|
||||||
elsif line =~ /^NetworkMask:\s+(.+?)$/
|
elsif line =~ /^NetworkMask:\s+(.+?)$/
|
||||||
info[:netmask] = $1.to_s
|
info[:netmask] = $1.to_s
|
||||||
|
elsif line =~ /^IPV6Address:\s+(.+?)$/
|
||||||
|
info[:ipv6] = $1.to_s.strip
|
||||||
|
elsif line =~ /^IPV6NetworkMaskPrefixLength:\s+(.+?)$/
|
||||||
|
info[:ipv6_prefix] = $1.to_s.strip
|
||||||
elsif line =~ /^Status:\s+(.+?)$/
|
elsif line =~ /^Status:\s+(.+?)$/
|
||||||
info[:status] = $1.to_s
|
info[:status] = $1.to_s
|
||||||
end
|
end
|
||||||
|
@ -465,6 +478,11 @@ module VagrantPlugins
|
||||||
results
|
results
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reconfig_host_only(interface)
|
||||||
|
execute("hostonlyif", "ipconfig", interface[:name],
|
||||||
|
"--ipv6", interface[:ipv6])
|
||||||
|
end
|
||||||
|
|
||||||
def remove_dhcp_server(network_name)
|
def remove_dhcp_server(network_name)
|
||||||
execute("dhcpserver", "remove", "--netname", network_name)
|
execute("dhcpserver", "remove", "--netname", network_name)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
require 'ipaddr'
|
||||||
require 'log4r'
|
require 'log4r'
|
||||||
|
|
||||||
require "vagrant/util/platform"
|
require "vagrant/util/platform"
|
||||||
|
@ -46,12 +47,21 @@ module VagrantPlugins
|
||||||
def create_host_only_network(options)
|
def create_host_only_network(options)
|
||||||
# Create the interface
|
# Create the interface
|
||||||
execute("hostonlyif", "create") =~ /^Interface '(.+?)' was successfully created$/
|
execute("hostonlyif", "create") =~ /^Interface '(.+?)' was successfully created$/
|
||||||
name = $1.to_s
|
name = $1.to_s
|
||||||
|
|
||||||
# Configure it
|
# Get the IP so we can determine v4 vs v6
|
||||||
execute("hostonlyif", "ipconfig", name,
|
ip = IPAddr.new(options[:adapter_ip])
|
||||||
"--ip", options[:adapter_ip],
|
|
||||||
"--netmask", options[:netmask])
|
# Configure
|
||||||
|
if ip.ipv4?
|
||||||
|
execute("hostonlyif", "ipconfig", name,
|
||||||
|
"--ip", options[:adapter_ip],
|
||||||
|
"--netmask", options[:netmask])
|
||||||
|
elsif ip.ipv6?
|
||||||
|
execute("hostonlyif", "ipconfig", name,
|
||||||
|
"--ipv6", options[:adapter_ip],
|
||||||
|
"--netmasklengthv6", options[:netmask].to_s)
|
||||||
|
end
|
||||||
|
|
||||||
# Return the details
|
# Return the details
|
||||||
return {
|
return {
|
||||||
|
@ -62,6 +72,11 @@ module VagrantPlugins
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reconfig_host_only(interface)
|
||||||
|
execute("hostonlyif", "ipconfig", interface[:name],
|
||||||
|
"--ipv6", interface[:ipv6])
|
||||||
|
end
|
||||||
|
|
||||||
def delete
|
def delete
|
||||||
execute("unregistervm", @uuid, "--delete")
|
execute("unregistervm", @uuid, "--delete")
|
||||||
end
|
end
|
||||||
|
@ -366,6 +381,10 @@ module VagrantPlugins
|
||||||
info[:ip] = $1.to_s
|
info[:ip] = $1.to_s
|
||||||
elsif line =~ /^NetworkMask:\s+(.+?)$/
|
elsif line =~ /^NetworkMask:\s+(.+?)$/
|
||||||
info[:netmask] = $1.to_s
|
info[:netmask] = $1.to_s
|
||||||
|
elsif line =~ /^IPV6Address:\s+(.+?)$/
|
||||||
|
info[:ipv6] = $1.to_s.strip
|
||||||
|
elsif line =~ /^IPV6NetworkMaskPrefixLength:\s+(.+?)$/
|
||||||
|
info[:ipv6_prefix] = $1.to_s.strip
|
||||||
elsif line =~ /^Status:\s+(.+?)$/
|
elsif line =~ /^Status:\s+(.+?)$/
|
||||||
info[:status] = $1.to_s
|
info[:status] = $1.to_s
|
||||||
end
|
end
|
||||||
|
|
|
@ -46,12 +46,23 @@ module VagrantPlugins
|
||||||
def create_host_only_network(options)
|
def create_host_only_network(options)
|
||||||
# Create the interface
|
# Create the interface
|
||||||
execute("hostonlyif", "create") =~ /^Interface '(.+?)' was successfully created$/
|
execute("hostonlyif", "create") =~ /^Interface '(.+?)' was successfully created$/
|
||||||
name = $1.to_s
|
name = $1.to_s
|
||||||
|
|
||||||
# Configure it
|
# Get the IP so we can determine v4 vs v6
|
||||||
execute("hostonlyif", "ipconfig", name,
|
ip = IPAddr.new(options[:adapter_ip])
|
||||||
"--ip", options[:adapter_ip],
|
|
||||||
"--netmask", options[:netmask])
|
# Configure
|
||||||
|
if ip.ipv4?
|
||||||
|
execute("hostonlyif", "ipconfig", name,
|
||||||
|
"--ip", options[:adapter_ip],
|
||||||
|
"--netmask", options[:netmask])
|
||||||
|
elsif ip.ipv6?
|
||||||
|
execute("hostonlyif", "ipconfig", name,
|
||||||
|
"--ipv6", options[:adapter_ip],
|
||||||
|
"--netmasklengthv6", options[:netmask].to_s)
|
||||||
|
else
|
||||||
|
raise "BUG: Unknown IP type: #{ip.inspect}"
|
||||||
|
end
|
||||||
|
|
||||||
# Return the details
|
# Return the details
|
||||||
return {
|
return {
|
||||||
|
@ -366,6 +377,10 @@ module VagrantPlugins
|
||||||
info[:ip] = $1.to_s
|
info[:ip] = $1.to_s
|
||||||
elsif line =~ /^NetworkMask:\s+(.+?)$/
|
elsif line =~ /^NetworkMask:\s+(.+?)$/
|
||||||
info[:netmask] = $1.to_s
|
info[:netmask] = $1.to_s
|
||||||
|
elsif line =~ /^IPV6Address:\s+(.+?)$/
|
||||||
|
info[:ipv6] = $1.to_s.strip
|
||||||
|
elsif line =~ /^IPV6NetworkMaskPrefixLength:\s+(.+?)$/
|
||||||
|
info[:ipv6_prefix] = $1.to_s.strip
|
||||||
elsif line =~ /^Status:\s+(.+?)$/
|
elsif line =~ /^Status:\s+(.+?)$/
|
||||||
info[:status] = $1.to_s
|
info[:status] = $1.to_s
|
||||||
end
|
end
|
||||||
|
@ -475,6 +490,11 @@ module VagrantPlugins
|
||||||
results
|
results
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reconfig_host_only(interface)
|
||||||
|
execute("hostonlyif", "ipconfig", interface[:name],
|
||||||
|
"--ipv6", interface[:ipv6])
|
||||||
|
end
|
||||||
|
|
||||||
def remove_dhcp_server(network_name)
|
def remove_dhcp_server(network_name)
|
||||||
execute("dhcpserver", "remove", "--netname", network_name)
|
execute("dhcpserver", "remove", "--netname", network_name)
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
#VAGRANT-BEGIN
|
||||||
|
# The contents below are automatically generated by Vagrant. Do not modify.
|
||||||
|
auto eth<%= options[:interface] %>
|
||||||
|
iface eth<%= options[:interface] %> inet6 static
|
||||||
|
address <%= options[:ip] %>
|
||||||
|
netmask <%= options[:netmask] %>
|
||||||
|
<% if options[:gateway] %>
|
||||||
|
gateway <%= options[:gateway] %>
|
||||||
|
<% end %>
|
||||||
|
#VAGRANT-END
|
|
@ -159,6 +159,7 @@ shared_examples "a version 4.x virtualbox driver" do |options|
|
||||||
name: 'vboxnet0',
|
name: 'vboxnet0',
|
||||||
ip: '172.28.128.1',
|
ip: '172.28.128.1',
|
||||||
netmask: '255.255.255.0',
|
netmask: '255.255.255.0',
|
||||||
|
ipv6_prefix: '0',
|
||||||
status: 'Up',
|
status: 'Up',
|
||||||
}])
|
}])
|
||||||
end
|
end
|
||||||
|
@ -196,11 +197,40 @@ shared_examples "a version 4.x virtualbox driver" do |options|
|
||||||
|
|
||||||
it "returns a list with one entry for each interface" do
|
it "returns a list with one entry for each interface" do
|
||||||
expect(subject.read_host_only_interfaces).to eq([
|
expect(subject.read_host_only_interfaces).to eq([
|
||||||
{name: 'vboxnet0', ip: '172.28.128.1', netmask: '255.255.255.0', status: 'Up'},
|
{name: 'vboxnet0', ip: '172.28.128.1', netmask: '255.255.255.0', ipv6_prefix: "0", status: 'Up'},
|
||||||
{name: 'vboxnet1', ip: '10.0.0.1', netmask: '255.255.255.0', status: 'Up'},
|
{name: 'vboxnet1', ip: '10.0.0.1', netmask: '255.255.255.0', ipv6_prefix: "0", status: 'Up'},
|
||||||
])
|
])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "with an IPv6 host-only interface" do
|
||||||
|
let(:output) {
|
||||||
|
<<-OUTPUT.gsub(/^ */, '')
|
||||||
|
Name: vboxnet1
|
||||||
|
GUID: 786f6276-656e-4174-8000-0a0027000001
|
||||||
|
DHCP: Disabled
|
||||||
|
IPAddress: 192.168.57.1
|
||||||
|
NetworkMask: 255.255.255.0
|
||||||
|
IPV6Address: fde4:8dba:82e1::
|
||||||
|
IPV6NetworkMaskPrefixLength: 64
|
||||||
|
HardwareAddress: 0a:00:27:00:00:01
|
||||||
|
MediumType: Ethernet
|
||||||
|
Status: Up
|
||||||
|
VBoxNetworkName: HostInterfaceNetworking-vboxnet1
|
||||||
|
OUTPUT
|
||||||
|
}
|
||||||
|
|
||||||
|
it "returns a list with one entry describing that interface" do
|
||||||
|
expect(subject.read_host_only_interfaces).to eq([{
|
||||||
|
name: 'vboxnet1',
|
||||||
|
ip: '192.168.57.1',
|
||||||
|
netmask: '255.255.255.0',
|
||||||
|
ipv6: 'fde4:8dba:82e1::',
|
||||||
|
ipv6_prefix: '64',
|
||||||
|
status: 'Up',
|
||||||
|
}])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "remove_dhcp_server" do
|
describe "remove_dhcp_server" do
|
||||||
|
|
|
@ -13,5 +13,17 @@ describe Vagrant::Util::NetworkIP do
|
||||||
it "calculates it properly" do
|
it "calculates it properly" do
|
||||||
expect(klass.network_address("192.168.2.234", "255.255.255.0")).to eq("192.168.2.0")
|
expect(klass.network_address("192.168.2.234", "255.255.255.0")).to eq("192.168.2.0")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "calculates it properly with integer submask" do
|
||||||
|
expect(klass.network_address("192.168.2.234", "24")).to eq("192.168.2.0")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "calculates it properly for IPv6" do
|
||||||
|
expect(klass.network_address("fde4:8dba:82e1::c4", "64")).to eq("fde4:8dba:82e1::")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "calculates it properly for IPv6" do
|
||||||
|
expect(klass.network_address("fde4:8dba:82e1::c4", 64)).to eq("fde4:8dba:82e1::")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -74,6 +74,35 @@ reachable.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
## IPv6
|
||||||
|
|
||||||
|
You can specify a static IP via IPv6. DHCP for IPv6 is not supported.
|
||||||
|
To use IPv6, just specify an IPv6 address as the IP:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.vm.network "private_network", ip: "fde4:8dba:82e1::c4"
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
This will assign that IP to the machine. The entire `/64` subnet will
|
||||||
|
be reserved. Please make sure to use the reserved local addresses approved
|
||||||
|
for IPv6.
|
||||||
|
|
||||||
|
You can also modify the prefix length by changing the `netmask` option
|
||||||
|
(defaults to 64):
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.vm.network "private_network",
|
||||||
|
ip: "fde4:8dba:82e1::c4",
|
||||||
|
netmask: "96"
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
IPv6 supports for private networks was added in Vagrant 1.7.5 and may
|
||||||
|
not work with every provider.
|
||||||
|
|
||||||
## Disable Auto-Configuration
|
## Disable Auto-Configuration
|
||||||
|
|
||||||
If you want to manually configure the network interface yourself, you
|
If you want to manually configure the network interface yourself, you
|
||||||
|
|
Loading…
Reference in New Issue