@ -15,11 +15,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
import sys
import aiohttp
import logging
import asyncio
import socket
import ipaddress
from . base_gns3_vm import BaseGNS3VM
from . gns3_vm_error import GNS3VMError
@ -80,9 +82,6 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
except ValueError :
continue
self . _system_properties [ name . strip ( ) ] = value . strip ( )
if " API Version " in self . _system_properties :
# API version is not consistent between VirtualBox versions, the key is named "API Version" in VirtualBox 7
self . _system_properties [ " API version " ] = self . _system_properties . pop ( " API Version " )
async def _check_requirements ( self ) :
"""
@ -92,16 +91,16 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
if not self . _system_properties :
await self . _get_system_properties ( )
if " API version " not in self . _system_properties :
raise VirtualBox Error( " Can ' t access to VirtualBox API version: \n {} " . format ( self . _system_properties ) )
raise GNS3VM Error( " Can ' t access to VirtualBox API version: \n {} " . format ( self . _system_properties ) )
from cpuinfo import get_cpu_info
cpu_info = await wait_run_in_executor ( get_cpu_info )
vendor_id = cpu_info . get ( ' vendor_id_raw ' )
if vendor_id == " GenuineIntel " :
if parse_version ( self . _system_properties [ " API version " ] ) < parse_version ( " 6_1 " ) :
raise VirtualBox Error( " VirtualBox version 6.1 or above is required to run the GNS3 VM with nested virtualization enabled on Intel processors " )
raise GNS3VM Error( " VirtualBox version 6.1 or above is required to run the GNS3 VM with nested virtualization enabled on Intel processors " )
elif vendor_id == " AuthenticAMD " :
if parse_version ( self . _system_properties [ " API version " ] ) < parse_version ( " 6_0 " ) :
raise VirtualBox Error( " VirtualBox version 6.0 or above is required to run the GNS3 VM with nested virtualization enabled on AMD processors " )
raise GNS3VM Error( " VirtualBox version 6.0 or above is required to run the GNS3 VM with nested virtualization enabled on AMD processors " )
else :
log . warning ( " Could not determine CPU vendor: {} " . format ( vendor_id ) )
@ -162,6 +161,44 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
return True
return False
async def _add_dhcp_server ( self , vboxnet ) :
"""
Add a DHCP server for vboxnet .
: param vboxnet : vboxnet name
"""
hostonlyifs = await self . _execute ( " list " , [ " hostonlyifs " ] )
pattern = r " IPAddress: \ s+( \ d+ \ . \ d+ \ . \ d+ \ . \ d+) \ nNetworkMask: \ s+( \ d+ \ . \ d+ \ . \ d+ \ . \ d+) "
match = re . search ( pattern , hostonlyifs )
if match :
ip_address = match . group ( 1 )
netmask = match . group ( 2 )
else :
raise GNS3VMError ( " Could not find IP address and netmask for vboxnet {} " . format ( vboxnet ) )
try :
interface = ipaddress . IPv4Interface ( f " { ip_address } / { netmask } " )
subnet = ipaddress . IPv4Network ( str ( interface . network ) )
dhcp_server_ip = str ( interface . ip + 1 )
netmask = str ( subnet . netmask )
lower_ip = str ( interface . ip + 2 )
upper_ip = str ( subnet . network_address + subnet . num_addresses - 2 )
except ValueError :
raise GNS3VMError ( " Invalid IP address and netmask for vboxnet {} : {} / {} " . format ( vboxnet , ip_address , netmask ) )
dhcp_server_args = [
" add " ,
" --network=HostInterfaceNetworking- {} " . format ( vboxnet ) ,
" --server-ip= {} " . format ( dhcp_server_ip ) ,
" --netmask= {} " . format ( netmask ) ,
" --lower-ip= {} " . format ( lower_ip ) ,
" --upper-ip= {} " . format ( upper_ip ) ,
" --enable "
]
await self . _execute ( " dhcpserver " , dhcp_server_args )
async def _check_vboxnet_exists ( self , vboxnet , vboxnet_type ) :
"""
Check if the vboxnet interface exists
@ -264,12 +301,20 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
await self . set_hostonly_network ( interface_number , first_available_vboxnet )
vboxnet = first_available_vboxnet
else :
raise GNS3VMError ( ' VirtualBox host-only network " {} " does not exist, please make the sure the network adapter {} configuration is valid for " {} " ' . format ( vboxnet ,
interface_number ,
self . _vmname ) )
try :
await self . _execute ( " hostonlyif " , [ " create " ] )
except GNS3VMError :
raise GNS3VMError ( ' VirtualBox host-only network " {} " does not exist and could not be automatically created, please make the sure the network adapter {} configuration is valid for " {} " ' . format (
vboxnet ,
interface_number ,
self . _vmname
) )
if backend_type == " hostonlyadapter " and not ( await self . _check_dhcp_server ( vboxnet ) ) :
raise GNS3VMError ( ' DHCP must be enabled on VirtualBox host-only network " {} " ' . format ( vboxnet ) )
try :
await self . _add_dhcp_server ( vboxnet )
except GNS3VMError as e :
raise GNS3VMError ( " Could not add DHCP server for vboxnet {} : {} , please configure manually " . format ( vboxnet , e ) )
vm_state = await self . _get_state ( )
log . info ( ' " {} " state is {} ' . format ( self . _vmname , vm_state ) )
@ -302,7 +347,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
except OSError as e :
raise GNS3VMError ( " Error while getting random port: {} " . format ( e ) )
if ( await self . _check_vbox_port_forwarding ( ) ) :
if await self . _check_vbox_port_forwarding ( ) :
# delete the GNS3VM NAT port forwarding rule if it exists
log . info ( " Removing GNS3VM NAT port forwarding rule from interface {} " . format ( nat_interface_number ) )
await self . _execute ( " controlvm " , [ self . _vmname , " natpf {} " . format ( nat_interface_number ) , " delete " , " GNS3VM " ] )