Skip to content

Commit

Permalink
FIX docker#2624 reject duplicate hostonlyifs name/IP
Browse files Browse the repository at this point in the history
Signed-off-by: David Gageot <david@gageot.net>
  • Loading branch information
dgageot committed Dec 21, 2015
1 parent 906ac38 commit 3c4fd63
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 26 deletions.
38 changes: 18 additions & 20 deletions drivers/virtualbox/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ const (
)

var (
reHostonlyInterfaceCreated = regexp.MustCompile(`Interface '(.+)' was successfully created`)
errDuplicateHostOnlyInterfaceNetworks = errors.New("VirtualBox is configured with multiple host-only interfaces with the same IP. Please remove all of them but one.")
errNewHostOnlyInterfaceNotVisible = errors.New("The host-only interface we just created is not visible. This is a well known bug of VirtualBox. You might want to uninstall it and reinstall the version listed here: https://www.virtualbox.org/ticket/14437?cversion=0&cnum_hist=42")
reHostonlyInterfaceCreated = regexp.MustCompile(`Interface '(.+)' was successfully created`)
errNewHostOnlyInterfaceNotVisible = errors.New("The host-only interface we just created is not visible. This is a well known bug of VirtualBox. You might want to uninstall it and reinstall the version listed here: https://www.virtualbox.org/ticket/14437?cversion=0&cnum_hist=42")
)

// Host-only network.
Expand Down Expand Up @@ -75,7 +74,8 @@ func listHostOnlyNetworks(vbox VBoxManager) (map[string]*hostOnlyNetwork, error)
return nil, err
}

m := map[string]*hostOnlyNetwork{}
byName := map[string]*hostOnlyNetwork{}
byIP := map[string]*hostOnlyNetwork{}
n := &hostOnlyNetwork{}

err = parseKeyValues(out, reColonLine, func(key, val string) error {
Expand Down Expand Up @@ -110,7 +110,19 @@ func listHostOnlyNetworks(vbox VBoxManager) (map[string]*hostOnlyNetwork, error)
n.Status = val
case "VBoxNetworkName":
n.NetworkName = val
m[val] = n

if _, present := byName[n.NetworkName]; present {
return fmt.Errorf("VirtualBox is configured with multiple host-only interfaces with the same name %q. Please remove one.", n.NetworkName)
}
byName[n.NetworkName] = n

if len(n.IPv4.IP) != 0 {
if _, present := byIP[n.IPv4.IP.String()]; present {
return fmt.Errorf("VirtualBox is configured with multiple host-only interfaces with the same IP %q. Please remove one.", n.IPv4.IP)
}
byIP[n.IPv4.IP.String()] = n
}

n = &hostOnlyNetwork{}
}

Expand All @@ -120,7 +132,7 @@ func listHostOnlyNetworks(vbox VBoxManager) (map[string]*hostOnlyNetwork, error)
return nil, err
}

return m, nil
return byName, nil
}

func getHostOnlyNetwork(nets map[string]*hostOnlyNetwork, hostIP net.IP, netmask net.IPMask) *hostOnlyNetwork {
Expand All @@ -143,10 +155,6 @@ func getOrCreateHostOnlyNetwork(hostIP net.IP, netmask net.IPMask, dhcpIP net.IP
return nil, err
}

if len(nets) != countUniqueIps(nets) {
return nil, errDuplicateHostOnlyInterfaceNetworks
}

hostOnlyNet := getHostOnlyNetwork(nets, hostIP, netmask)
if hostOnlyNet != nil {
return hostOnlyNet, nil
Expand Down Expand Up @@ -188,16 +196,6 @@ func getOrCreateHostOnlyNetwork(hostIP net.IP, netmask net.IPMask, dhcpIP net.IP
return hostOnlyNet, nil
}

func countUniqueIps(nets map[string]*hostOnlyNetwork) int {
ips := map[string]bool{}

for _, n := range nets {
ips[n.IPv4.IP.String()] = true
}

return len(ips)
}

// DHCP server info.
type dhcpServer struct {
NetworkName string
Expand Down
34 changes: 28 additions & 6 deletions drivers/virtualbox/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ VBoxNetworkName: HostInterfaceNetworking-vboxnet0
Name: vboxnet1
GUID: 786f6276-656e-4174-8000-0a0027000001
DHCP: Disabled
IPAddress: 192.168.99.1
IPAddress: 169.254.37.187
NetworkMask: 255.255.255.0
IPV6Address:
IPV6NetworkMaskPrefixLength: 0
Expand Down Expand Up @@ -185,7 +185,7 @@ func TestListTwoHostOnlyNetworks(t *testing.T) {
assert.Equal(t, "vboxnet1", net.Name)
assert.Equal(t, "786f6276-656e-4174-8000-0a0027000001", net.GUID)
assert.False(t, net.DHCP)
assert.Equal(t, "192.168.99.1", net.IPv4.IP.String())
assert.Equal(t, "169.254.37.187", net.IPv4.IP.String())
assert.Equal(t, "ffffff00", net.IPv4.Mask.String())
assert.Empty(t, net.IPv6.IP)
assert.Equal(t, "0a:00:27:00:00:01", net.HwAddr.String())
Expand Down Expand Up @@ -230,16 +230,38 @@ func TestGetHostOnlyNetwork(t *testing.T) {
assert.NoError(t, err)
}

func TestFailWithDuplicateHostOnlyNetworks(t *testing.T) {
func TestFailIfTwoNetworksHaveSameIP(t *testing.T) {
vbox := &VBoxManagerMock{
args: "list hostonlyifs",
stdOut: stdOutTwoHostOnlyNetwork,
args: "list hostonlyifs",
stdOut: `Name: vboxnet0
IPAddress: 192.168.99.1
NetworkMask: 255.255.255.0
VBoxNetworkName: HostInterfaceNetworking-vboxnet0
Name: vboxnet1
IPAddress: 192.168.99.1
NetworkMask: 255.255.255.0
VBoxNetworkName: HostInterfaceNetworking-vboxnet1`,
}

net, err := getOrCreateHostOnlyNetwork(net.ParseIP("192.168.99.1"), parseIPv4Mask("255.255.255.0"), nil, nil, nil, vbox)

assert.Nil(t, net)
assert.EqualError(t, err, `VirtualBox is configured with multiple host-only interfaces with the same IP "192.168.99.1". Please remove one.`)
}

func TestFailIfTwoNetworksHaveSameName(t *testing.T) {
vbox := &VBoxManagerMock{
args: "list hostonlyifs",
stdOut: `Name: vboxnet0
VBoxNetworkName: HostInterfaceNetworking-vboxnet0
Name: vboxnet0
VBoxNetworkName: HostInterfaceNetworking-vboxnet0`,
}

net, err := getOrCreateHostOnlyNetwork(net.ParseIP("192.168.99.1"), parseIPv4Mask("255.255.255.0"), nil, nil, nil, vbox)

assert.Nil(t, net)
assert.Equal(t, errDuplicateHostOnlyInterfaceNetworks, err)
assert.EqualError(t, err, `VirtualBox is configured with multiple host-only interfaces with the same name "HostInterfaceNetworking-vboxnet0". Please remove one.`)
}

func TestGetDHCPServers(t *testing.T) {
Expand Down
5 changes: 5 additions & 0 deletions drivers/virtualbox/virtualbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,11 @@ func (d *Driver) PreCreateCheck() error {
return err
}

// Check that Host-only interfaces are ok
if _, err = listHostOnlyNetworks(d.VBoxManager); err != nil {
return err
}

return nil
}

Expand Down

0 comments on commit 3c4fd63

Please sign in to comment.