VirtualBox

Changeset 93312 in vbox for trunk/src/VBox/Main/src-client


Ignore:
Timestamp:
Jan 18, 2022 1:15:12 PM (3 years ago)
Author:
vboxsync
Message:

CloudNet: ​bugref:9469 Replace local gateway with DrvCloudTunnel. Build 25519 encryption support in libssh. Add missing version bump in machine settings to 1.18 if cloud attachment is used.

Location:
trunk/src/VBox/Main/src-client
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-client/CloudGateway.cpp

    r93115 r93312  
    3737#include <iprt/vfs.h>
    3838#include <iprt/uri.h>
     39#ifdef DEBUG
     40#include <iprt/file.h>
     41#include <VBox/com/utils.h>
     42#endif
     43
     44#ifdef VBOX_WITH_LIBSSH
     45/* Prevent inclusion of Winsock2.h */
     46#define _WINSOCK2API_
     47#include <libssh/libssh.h>
     48#endif /* VBOX_WITH_LIBSSH */
     49
    3950
    4051static HRESULT setMacAddress(const Utf8Str& str, RTMAC& mac)
     
    4960}
    5061
     62
    5163HRESULT GatewayInfo::setCloudMacAddress(const Utf8Str& mac)
    5264{
     
    5466}
    5567
     68
    5669HRESULT GatewayInfo::setLocalMacAddress(const Utf8Str& mac)
    5770{
     
    5972}
    6073
    61 Utf8Str GatewayInfo::getCloudMacAddressWithoutColons() const
    62 {
    63     return Utf8StrFmt("%02X%02X%02X%02X%02X%02X",
    64                       mCloudMacAddress.au8[0], mCloudMacAddress.au8[1], mCloudMacAddress.au8[2],
    65                       mCloudMacAddress.au8[3], mCloudMacAddress.au8[4], mCloudMacAddress.au8[5]);
    66 }
    67 
    68 Utf8Str GatewayInfo::getLocalMacAddressWithoutColons() const
    69 {
    70     return Utf8StrFmt("%02X%02X%02X%02X%02X%02X",
    71                       mLocalMacAddress.au8[0], mLocalMacAddress.au8[1], mLocalMacAddress.au8[2],
    72                       mLocalMacAddress.au8[3], mLocalMacAddress.au8[4], mLocalMacAddress.au8[5]);
    73 }
    74 
    75 Utf8Str GatewayInfo::getLocalMacAddressWithColons() const
    76 {
    77     return Utf8StrFmt("%RTmac", &mLocalMacAddress);
    78 }
    7974
    8075class CloudError
     
    8984    Utf8Str mText;
    9085};
     86
    9187
    9288static void handleErrors(HRESULT hrc, const char *pszFormat, ...)
     
    104100}
    105101
     102
    106103class CloudClient
    107104{
     
    110107    ~CloudClient() {};
    111108
    112     void startCloudGateway(const ComPtr<ICloudNetwork> &network, GatewayInfo& gateways);
    113     void stopCloudGateway(const GatewayInfo& gateways);
     109    void startCloudGateway(const ComPtr<ICloudNetwork> &network, GatewayInfo& gateway);
     110    void stopCloudGateway(const GatewayInfo& gateway);
    114111
    115112private:
     
    119116    ComPtr<ICloudClient>          mClient;
    120117};
     118
    121119
    122120CloudClient::CloudClient(ComPtr<IVirtualBox> virtualBox, const Bstr& strProvider, const Bstr& strProfile)
     
    132130}
    133131
    134 void CloudClient::startCloudGateway(const ComPtr<ICloudNetwork> &network, GatewayInfo& gateways)
     132
     133void CloudClient::startCloudGateway(const ComPtr<ICloudNetwork> &network, GatewayInfo& gateway)
    135134{
    136135    ComPtr<IProgress> progress;
    137136    ComPtr<ICloudNetworkGatewayInfo> gatewayInfo;
    138     HRESULT hrc = mClient->StartCloudNetworkGateway(network, Bstr(gateways.mPublicSshKey).raw(),
     137    HRESULT hrc = mClient->StartCloudNetworkGateway(network, Bstr(gateway.mPublicSshKey).raw(),
    139138                                                    gatewayInfo.asOutParam(), progress.asOutParam());
    140139    handleErrors(hrc, "Failed to launch compute instance");
     
    145144    hrc = gatewayInfo->COMGETTER(InstanceId)(instanceId.asOutParam());
    146145    handleErrors(hrc, "Failed to get launched compute instance id");
    147     gateways.mGatewayInstanceId = instanceId;
     146    gateway.mGatewayInstanceId = instanceId;
    148147
    149148    Bstr publicIP;
    150149    hrc = gatewayInfo->COMGETTER(PublicIP)(publicIP.asOutParam());
    151150    handleErrors(hrc, "Failed to get cloud gateway public IP address");
    152     gateways.mCloudPublicIp = publicIP;
     151    gateway.mCloudPublicIp = publicIP;
    153152
    154153    Bstr secondaryPublicIP;
    155154    hrc = gatewayInfo->COMGETTER(SecondaryPublicIP)(secondaryPublicIP.asOutParam());
    156155    handleErrors(hrc, "Failed to get cloud gateway secondary public IP address");
    157     gateways.mCloudSecondaryPublicIp = secondaryPublicIP;
     156    gateway.mCloudSecondaryPublicIp = secondaryPublicIP;
    158157
    159158    Bstr macAddress;
    160159    hrc = gatewayInfo->COMGETTER(MacAddress)(macAddress.asOutParam());
    161160    handleErrors(hrc, "Failed to get cloud gateway public IP address");
    162     gateways.setCloudMacAddress(macAddress);
    163 }
    164 
    165 void CloudClient::stopCloudGateway(const GatewayInfo& gateways)
     161    gateway.setCloudMacAddress(macAddress);
     162}
     163
     164
     165void CloudClient::stopCloudGateway(const GatewayInfo& gateway)
    166166{
    167167    ComPtr<IProgress> progress;
    168     HRESULT hrc = mClient->TerminateInstance(Bstr(gateways.mGatewayInstanceId).raw(), progress.asOutParam());
     168    HRESULT hrc = mClient->TerminateInstance(Bstr(gateway.mGatewayInstanceId).raw(), progress.asOutParam());
    169169    handleErrors(hrc, "Failed to terminate compute instance");
    170170#if 0
     
    176176
    177177
    178 static HRESULT startCloudGateway(ComPtr<IVirtualBox> virtualBox, ComPtr<ICloudNetwork> network, GatewayInfo& gateways)
     178HRESULT startCloudGateway(ComPtr<IVirtualBox> virtualBox, ComPtr<ICloudNetwork> network, GatewayInfo& gateway)
    179179{
    180180    HRESULT hrc = S_OK;
    181181
    182182    try {
    183         hrc = network->COMGETTER(Provider)(gateways.mCloudProvider.asOutParam());
    184         hrc = network->COMGETTER(Profile)(gateways.mCloudProfile.asOutParam());
    185         CloudClient client(virtualBox, gateways.mCloudProvider, gateways.mCloudProfile);
    186         client.startCloudGateway(network, gateways);
     183        hrc = network->COMGETTER(Provider)(gateway.mCloudProvider.asOutParam());
     184        hrc = network->COMGETTER(Profile)(gateway.mCloudProfile.asOutParam());
     185        CloudClient client(virtualBox, gateway.mCloudProvider, gateway.mCloudProfile);
     186        client.startCloudGateway(network, gateway);
    187187    }
    188188    catch (CloudError e)
     
    195195
    196196
    197 static HRESULT attachToLocalNetwork(ComPtr<ISession> aSession, const com::Utf8Str &aCloudNetwork)
    198 {
    199     ComPtr<IMachine> sessionMachine;
    200     HRESULT hrc = aSession->COMGETTER(Machine)(sessionMachine.asOutParam());
    201     if (FAILED(hrc))
    202     {
    203         LogRel(("CLOUD-NET: Failed to obtain a mutable machine. hrc=%x\n", hrc));
    204         return hrc;
    205     }
    206 
    207     ComPtr<INetworkAdapter> networkAdapter;
    208     hrc = sessionMachine->GetNetworkAdapter(1, networkAdapter.asOutParam());
    209     if (FAILED(hrc))
    210     {
    211         LogRel(("CLOUD-NET: Failed to locate the second network adapter. hrc=%x\n", hrc));
    212         return hrc;
    213     }
    214 
    215     BstrFmt network("cloud-%s", aCloudNetwork.c_str());
    216     hrc = networkAdapter->COMSETTER(InternalNetwork)(network.raw());
    217     if (FAILED(hrc))
    218     {
    219         LogRel(("CLOUD-NET: Failed to set network name for the second network adapter. hrc=%x\n", hrc));
    220         return hrc;
    221     }
    222 
    223     hrc = sessionMachine->SaveSettings();
    224     if (FAILED(hrc))
    225         LogRel(("CLOUD-NET: Failed to save 'lgw' settings. hrc=%x\n", hrc));
    226     return hrc;
    227 }
    228 
    229 static HRESULT startLocalGateway(ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> aSession, const com::Utf8Str &aCloudNetwork, GatewayInfo& gateways)
    230 {
    231     /*
    232      * It would be really beneficial if we do not create a local gateway VM each time a target starts.
    233      * We probably just need to make sure its configuration matches the one required by the cloud network
    234      * attachment and update configuration if necessary.
    235      */
    236     Bstr strGatewayVM = BstrFmt("lgw-%ls", gateways.mTargetVM.raw());
    237     ComPtr<IMachine> machine;
    238     HRESULT hrc = virtualBox->FindMachine(strGatewayVM.raw(), machine.asOutParam());
    239     if (SUCCEEDED(hrc))
    240     {
    241         hrc = machine->LockMachine(aSession, LockType_Write);
    242         if (FAILED(hrc))
    243         {
    244             LogRel(("CLOUD-NET: Failed to lock '%ls' for modifications. hrc=%x\n", strGatewayVM.raw(), hrc));
    245             return hrc;
    246         }
    247 
    248         hrc = attachToLocalNetwork(aSession, aCloudNetwork);
    249     }
    250     else
    251     {
    252         SafeArray<IN_BSTR> groups;
    253         groups.push_back(Bstr("/gateways").mutableRaw());
    254         hrc = virtualBox->CreateMachine(NULL, Bstr(strGatewayVM).raw(), ComSafeArrayAsInParam(groups), Bstr("Ubuntu_64").raw(), Bstr("").raw(), machine.asOutParam());
    255         if (FAILED(hrc))
    256         {
    257             LogRel(("CLOUD-NET: Failed to create '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc));
    258             return hrc;
    259         }
    260         /* Initial configuration */
    261         hrc = machine->ApplyDefaults(NULL);
    262         if (FAILED(hrc))
    263         {
    264             LogRel(("CLOUD-NET: Failed to apply defaults to '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc));
    265             return hrc;
    266         }
    267 
    268         /* Add second network adapter */
    269         ComPtr<INetworkAdapter> networkAdapter;
    270         hrc = machine->GetNetworkAdapter(1, networkAdapter.asOutParam());
    271         if (FAILED(hrc))
    272         {
    273             LogRel(("CLOUD-NET: Failed to locate the second network adapter. hrc=%x\n", hrc));
    274             return hrc;
    275         }
    276 
    277         hrc = networkAdapter->COMSETTER(AttachmentType)(NetworkAttachmentType_Internal);
    278         if (FAILED(hrc))
    279         {
    280             LogRel(("CLOUD-NET: Failed to set attachment type for the second network adapter. hrc=%x\n", hrc));
    281             return hrc;
    282         }
    283 
    284         BstrFmt network("cloud-%s", aCloudNetwork.c_str());
    285         hrc = networkAdapter->COMSETTER(InternalNetwork)(network.raw());
    286         if (FAILED(hrc))
    287         {
    288             LogRel(("CLOUD-NET: Failed to set network name for the second network adapter. hrc=%x\n", hrc));
    289             return hrc;
    290         }
    291 
    292         hrc = networkAdapter->COMSETTER(PromiscModePolicy)(NetworkAdapterPromiscModePolicy_AllowAll);
    293         if (FAILED(hrc))
    294         {
    295             LogRel(("CLOUD-NET: Failed to set promiscuous mode policy for the second network adapter. hrc=%x\n", hrc));
    296             return hrc;
    297         }
    298 
    299         hrc = networkAdapter->COMSETTER(Enabled)(TRUE);
    300         if (FAILED(hrc))
    301         {
    302             LogRel(("CLOUD-NET: Failed to enable the second network adapter. hrc=%x\n", hrc));
    303             return hrc;
    304         }
    305 
    306         /* No need for audio -- disable it. */
    307         ComPtr<IAudioAdapter> audioAdapter;
    308         hrc = machine->GetNetworkAdapter(1, networkAdapter.asOutParam());
    309         if (FAILED(hrc))
    310         {
    311             LogRel(("CLOUD-NET: Failed to locate the second network adapter. hrc=%x\n", hrc));
    312             return hrc;
    313         }
    314 
    315         hrc = machine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam());
    316         if (FAILED(hrc))
    317         {
    318             LogRel(("CLOUD-NET: Failed to set attachment type for the second network adapter. hrc=%x\n", hrc));
    319             return hrc;
    320         }
    321 
    322         hrc = audioAdapter->COMSETTER(Enabled)(FALSE);
    323         if (FAILED(hrc))
    324         {
    325             LogRel(("CLOUD-NET: Failed to disable the audio adapter. hrc=%x\n", hrc));
    326             return hrc;
    327         }
    328 
    329         /** @todo Disable USB? */
    330 
    331         /* Register the local gateway VM */
    332         hrc = virtualBox->RegisterMachine(machine);
    333         if (FAILED(hrc))
    334         {
    335             LogRel(("CLOUD-NET: Failed to register '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc));
    336             return hrc;
    337         }
    338 
    339         /*
    340         * Storage can only be attached to registered VMs which means we need to use session
    341         * to lock VM in order to make it mutable again.
    342         */
    343         ComPtr<ISystemProperties> systemProperties;
    344         ComPtr<IMedium> hd;
    345         Bstr defaultMachineFolder;
    346         hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
    347         if (FAILED(hrc))
    348         {
    349             LogRel(("CLOUD-NET: Failed to obtain system properties. hrc=%x\n", hrc));
    350             return hrc;
    351         }
    352         hrc = systemProperties->COMGETTER(DefaultMachineFolder)(defaultMachineFolder.asOutParam());
    353         if (FAILED(hrc))
    354         {
    355             LogRel(("CLOUD-NET: Failed to obtain default machine folder. hrc=%x\n", hrc));
    356             return hrc;
    357         }
    358         hrc = virtualBox->OpenMedium(BstrFmt("%ls\\gateways\\lgw.vdi", defaultMachineFolder.raw()).raw(), DeviceType_HardDisk, AccessMode_ReadWrite, FALSE, hd.asOutParam());
    359         if (FAILED(hrc))
    360         {
    361             LogRel(("CLOUD-NET: Failed to open medium for '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc));
    362             return hrc;
    363         }
    364 
    365         hrc = machine->LockMachine(aSession, LockType_Write);
    366         if (FAILED(hrc))
    367         {
    368             LogRel(("CLOUD-NET: Failed to lock '%ls' for modifications. hrc=%x\n", strGatewayVM.raw(), hrc));
    369             return hrc;
    370         }
    371 
    372         ComPtr<IMachine> sessionMachine;
    373         hrc = aSession->COMGETTER(Machine)(sessionMachine.asOutParam());
    374         if (FAILED(hrc))
    375         {
    376             LogRel(("CLOUD-NET: Failed to obtain a mutable machine. hrc=%x\n", hrc));
    377             return hrc;
    378         }
    379 
    380         hrc = sessionMachine->AttachDevice(Bstr("SATA").raw(), 0, 0, DeviceType_HardDisk, hd);
    381         if (FAILED(hrc))
    382         {
    383             LogRel(("CLOUD-NET: Failed to attach HD to '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc));
    384             return hrc;
    385         }
    386 
    387         /* Save settings */
    388         hrc = sessionMachine->SaveSettings();
    389         if (FAILED(hrc))
    390         {
    391             LogRel(("CLOUD-NET: Failed to save '%ls' settings. hrc=%x\n", strGatewayVM.raw(), hrc));
    392             return hrc;
    393         }
    394     }
    395     /* Unlock the machine before start, it will be re-locked by LaunchVMProcess */
    396     aSession->UnlockMachine();
    397 
    398 #ifdef DEBUG
    399  #define LGW_FRONTEND "gui"
    400 #else
    401  #define LGW_FRONTEND "headless"
    402 #endif
    403     ComPtr<IProgress> progress;
    404     hrc = machine->LaunchVMProcess(aSession, Bstr(LGW_FRONTEND).raw(), ComSafeArrayNullInParam(), progress.asOutParam());
    405     if (FAILED(hrc))
    406     {
    407         LogRel(("CLOUD-NET: Failed to launch '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc));
    408         return hrc;
    409     }
    410 
    411     hrc = progress->WaitForCompletion(-1);
    412     if (FAILED(hrc))
    413         LogRel(("CLOUD-NET: Failed to launch '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc));
    414 
    415     gateways.mGatewayVM = strGatewayVM;
    416 
    417     ComPtr<IEventSource> es;
    418     hrc = virtualBox->COMGETTER(EventSource)(es.asOutParam());
    419     ComPtr<IEventListener> listener;
    420     hrc = es->CreateListener(listener.asOutParam());
    421     com::SafeArray <VBoxEventType_T> eventTypes(1);
    422     eventTypes.push_back(VBoxEventType_OnGuestPropertyChanged);
    423     hrc = es->RegisterListener(listener, ComSafeArrayAsInParam(eventTypes), false);
    424 
    425     Bstr publicKey;
    426     Bstr aMachStrGuid;
    427     machine->COMGETTER(Id)(aMachStrGuid.asOutParam());
    428     Guid aMachGuid(aMachStrGuid);
    429 
    430     uint64_t u64Started = RTTimeMilliTS();
    431     do
    432     {
    433         ComPtr<IEvent> ev;
    434         hrc = es->GetEvent(listener, 1000 /* seconds */, ev.asOutParam());
    435         if (ev)
    436         {
    437             VBoxEventType_T aType;
    438             hrc = ev->COMGETTER(Type)(&aType);
    439             if (aType == VBoxEventType_OnGuestPropertyChanged)
    440             {
    441                 ComPtr<IGuestPropertyChangedEvent> gpcev = ev;
    442                 Assert(gpcev);
    443                 Bstr aNextStrGuid;
    444                 gpcev->COMGETTER(MachineId)(aNextStrGuid.asOutParam());
    445                 if (aMachGuid != Guid(aNextStrGuid))
    446                     continue;
    447                 Bstr aNextName;
    448                 gpcev->COMGETTER(Name)(aNextName.asOutParam());
    449                 if (aNextName == "/VirtualBox/Gateway/PublicKey")
    450                 {
    451                     gpcev->COMGETTER(Value)(publicKey.asOutParam());
    452                     LogRel(("CLOUD-NET: Got public key from local gateway '%ls'\n", publicKey.raw()));
    453                     break;
    454                 }
    455             }
    456 
    457         }
    458     } while (RTTimeMilliTS() - u64Started < 300 * 1000); /** @todo reasonable timeout */
    459 
    460     if (publicKey.isEmpty())
    461     {
    462         LogRel(("CLOUD-NET: Failed to get ssh public key from '%ls'\n", strGatewayVM.raw()));
    463         return E_FAIL;
    464     }
    465 
    466     gateways.mPublicSshKey = publicKey;
    467 
    468     return hrc;
    469 }
    470 
     197#if 0 /* Disabled until proxy support is implemented */
    471198static bool getProxyForIpAddr(ComPtr<IVirtualBox> virtualBox, const com::Utf8Str &strIpAddr, Bstr &strProxyType, Bstr &strProxyHost, Bstr &strProxyPort)
    472199{
     
    598325#endif /* VBOX_WITH_PROXY_INFO */
    599326}
    600 
    601 
    602 static HRESULT exchangeInfoBetweenGateways(ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> aSession, GatewayInfo& gateways)
    603 {
    604     RT_NOREF(virtualBox);
    605     HRESULT hrc = S_OK;
    606     do
    607     {
    608         ComPtr<IConsole> console;
    609         hrc = aSession->COMGETTER(Console)(console.asOutParam());
    610         if (FAILED(hrc))
    611         {
    612             LogRel(("CLOUD-NET: Failed to obtain console for 'lgw'. hrc=%x\n", hrc));
    613             break;
    614         }
    615 
    616         ComPtr<IGuest> guest;
    617         hrc = console->COMGETTER(Guest)(guest.asOutParam());
    618         if (FAILED(hrc))
    619         {
    620             LogRel(("CLOUD-NET: Failed to obtain guest for 'lgw'. hrc=%x\n", hrc));
    621             break;
    622         }
    623 
    624         ComPtr<IGuestSession> guestSession;
    625 
    626         GuestSessionWaitResult_T enmWaitResult = GuestSessionWaitResult_None;
    627         for (int cTriesLeft = 6; cTriesLeft > 0; cTriesLeft--)
    628         {
    629             RTThreadSleep(5000 /* ms */);
    630             hrc = guest->CreateSession(Bstr("vbox").raw(), Bstr("vbox").raw(), NULL, Bstr("Cloud Gateway Impersonation").raw(), guestSession.asOutParam());
    631             if (FAILED(hrc))
    632             {
    633                 LogRel(("CLOUD-NET: Failed to create guest session for 'lgw'%s. hrc=%x\n", cTriesLeft > 1 ? ", will re-try" : "", hrc));
    634                 continue;
    635             }
    636             hrc = guestSession->WaitFor(GuestSessionWaitForFlag_Start, 30 * 1000, &enmWaitResult);
    637             if (FAILED(hrc))
    638             {
    639                 LogRel(("CLOUD-NET: WARNING! Failed to wait in guest session for 'lgw'%s. waitResult=%x hrc=%x\n",
    640                         cTriesLeft > 1 ? ", will re-try" : "", enmWaitResult, hrc));
    641                 guestSession->Close();
    642                 guestSession.setNull();
    643                 continue;
    644             }
    645             if (enmWaitResult == GuestSessionWaitResult_Start)
    646                 break;
    647             LogRel(("CLOUD-NET: WARNING! 'lgw' guest session waitResult=%x%s\n",
    648                     enmWaitResult, cTriesLeft > 1 ? ", will re-try" : ""));
    649             guestSession->Close();
    650             guestSession.setNull();
    651         }
    652 
    653         if (FAILED(hrc))
    654         {
    655             LogRel(("CLOUD-NET: Failed to start guest session for 'lgw'. waitResult=%x hrc=%x\n", enmWaitResult, hrc));
    656             break;
    657         }
    658 
    659         GuestSessionStatus_T enmSessionStatus;
    660         hrc = guestSession->COMGETTER(Status)(&enmSessionStatus);
    661         if (FAILED(hrc))
    662         {
    663             LogRel(("CLOUD-NET: Failed to get guest session status for 'lgw'. hrc=%x\n", hrc));
    664             break;
    665         }
    666         LogRel(("CLOUD-NET: Session status: %d\n", enmSessionStatus));
    667 
    668         Bstr strPrimaryProxyType;
    669         Bstr strPrimaryProxyHost;
    670         Bstr strPrimaryProxyPort;
    671         Bstr strSecondaryProxyType;
    672         Bstr strSecondaryProxyHost;
    673         Bstr strSecondaryProxyPort;
    674 
    675         ComPtr<IGuestProcess> guestProcess;
    676         com::SafeArray<IN_BSTR> aArgs;
    677         com::SafeArray<IN_BSTR> aEnv;
    678         com::SafeArray<ProcessCreateFlag_T> aCreateFlags;
    679         com::SafeArray<ProcessWaitForFlag_T> aWaitFlags;
    680         aCreateFlags.push_back(ProcessCreateFlag_WaitForStdOut);
    681         aCreateFlags.push_back(ProcessCreateFlag_WaitForStdErr);
    682 #define GUEST_CMD "/bin/sh"
    683         aArgs.push_back(Bstr(GUEST_CMD).mutableRaw());
    684         aArgs.push_back(Bstr("-x").mutableRaw());
    685         aArgs.push_back(Bstr("/home/vbox/local-bridge.sh").mutableRaw());
    686         aArgs.push_back(Bstr(gateways.mCloudPublicIp).mutableRaw());
    687         aArgs.push_back(Bstr(gateways.mCloudSecondaryPublicIp).mutableRaw());
    688         aArgs.push_back(Bstr(gateways.getLocalMacAddressWithColons()).mutableRaw());
    689         if (getProxyForIpAddr(virtualBox, gateways.mCloudPublicIp, strPrimaryProxyType, strPrimaryProxyHost, strPrimaryProxyPort))
    690         {
    691             aArgs.push_back(strPrimaryProxyType.mutableRaw());
    692             aArgs.push_back(strPrimaryProxyHost.mutableRaw());
    693             aArgs.push_back(strPrimaryProxyPort.mutableRaw());
    694             if (getProxyForIpAddr(virtualBox, gateways.mCloudSecondaryPublicIp, strSecondaryProxyType, strSecondaryProxyHost, strSecondaryProxyPort))
    695             {
    696                 aArgs.push_back(strSecondaryProxyType.mutableRaw());
    697                 aArgs.push_back(strSecondaryProxyHost.mutableRaw());
    698                 aArgs.push_back(strSecondaryProxyPort.mutableRaw());
    699             }
    700         }
    701         hrc = guestSession->ProcessCreate(Bstr(GUEST_CMD).raw(),
    702                                         ComSafeArrayAsInParam(aArgs),
    703                                         ComSafeArrayAsInParam(aEnv),
    704                                         ComSafeArrayAsInParam(aCreateFlags),
    705                                         180 * 1000 /* ms */,
    706                                         guestProcess.asOutParam());
    707         if (FAILED(hrc))
    708         {
    709             LogRel(("CLOUD-NET: Failed to create guest process '/bin/sh' for 'lgw'. hrc=%x\n", hrc));
    710             break;
    711         }
    712 
    713         ProcessWaitResult_T waitResult;
    714         hrc = guestProcess->WaitFor(ProcessWaitForFlag_Start, 10 * 1000 /* ms */, &waitResult);
    715         if (FAILED(hrc) || (waitResult != ProcessWaitResult_Start))
    716         {
    717             LogRel(("CLOUD-NET: Failed to wait for guest process to start for 'lgw'. waitResult=%x hrc=%x\n",
    718                     waitResult, hrc));
    719             break;
    720         }
    721         LogRel(("CLOUD-NET: waitResult=%x\n", waitResult));
    722 
    723         uint32_t cNotSupported = 0;
    724         bool fRead, fDone = false;
    725         uint64_t u64Start = RTTimeMilliTS();
    726         do
    727         {
    728             /** @todo wait for stdout when it becomes supported! */
    729             hrc = guestProcess->WaitFor(ProcessWaitForFlag_Terminate | ProcessWaitForFlag_StdOut, 1000 /* ms */, &waitResult);
    730             if (FAILED(hrc))
    731             {
    732                 LogRel(("CLOUD-NET: Failed to get output from guest process for 'lgw'. waitResult=%x hrc=%x\n",
    733                         waitResult, hrc));
    734                 break;
    735             }
    736             if (waitResult == ProcessWaitResult_WaitFlagNotSupported)
    737                 ++cNotSupported;
    738             else
    739             {
    740                 if (cNotSupported)
    741                 {
    742                     LogRel(("CLOUD-NET: waitResult=9, repeated %u times\n", cNotSupported));
    743                     cNotSupported = 0;
    744                 }
    745                 LogRel(("CLOUD-NET: waitResult=%x\n", waitResult));
    746             }
    747 
    748             fRead = false;
    749             switch (waitResult)
    750             {
    751                 case ProcessWaitResult_WaitFlagNotSupported:
    752                     RTThreadYield();
    753                     /* Fall through */
    754                 case ProcessWaitResult_StdOut:
    755                     fRead = true;
    756                     break;
    757                 case ProcessWaitResult_Terminate:
    758                     fDone = true;
    759                     break;
    760                 case ProcessWaitResult_Timeout:
    761                 {
    762                     ProcessStatus_T enmProcStatus;
    763                     hrc = guestProcess->COMGETTER(Status)(&enmProcStatus);
    764                     if (FAILED(hrc))
    765                     {
    766                         LogRel(("CLOUD-NET: Failed to query guest process status for 'lgw'. hrc=%x\n", hrc));
    767                         fDone = true;
    768                     }
    769                     else
    770                     {
    771                         LogRel(("CLOUD-NET: Guest process timeout for 'lgw'. status=%d\n", enmProcStatus));
    772                         if (   enmProcStatus == ProcessStatus_TimedOutKilled
    773                             || enmProcStatus == ProcessStatus_TimedOutAbnormally)
    774                         fDone = true;
    775                     }
    776                     fRead = true;
    777                     break;
    778                 }
    779                 default:
    780                     LogRel(("CLOUD-NET: Unexpected waitResult=%x\n", waitResult));
    781                     break;
    782             }
    783 
    784             if (fRead)
    785             {
    786                 SafeArray<BYTE> aStdOutData, aStdErrData;
    787                 hrc = guestProcess->Read(1 /* StdOut */, _64K, 60 * 1000 /* ms */, ComSafeArrayAsOutParam(aStdOutData));
    788                 if (FAILED(hrc))
    789                 {
    790                     LogRel(("CLOUD-NET: Failed to read stdout from guest process for 'lgw'. hrc=%x\n", hrc));
    791                     break;
    792                 }
    793                 hrc = guestProcess->Read(2 /* StdErr */, _64K, 60 * 1000 /* ms */, ComSafeArrayAsOutParam(aStdErrData));
    794                 if (FAILED(hrc))
    795                 {
    796                     LogRel(("CLOUD-NET: Failed to read stderr from guest process for 'lgw'. hrc=%x\n", hrc));
    797                     break;
    798                 }
    799 
    800                 size_t cbStdOutData = aStdOutData.size();
    801                 size_t cbStdErrData = aStdErrData.size();
    802                 if (cbStdOutData == 0 && cbStdErrData == 0)
    803                 {
    804                     //LogRel(("CLOUD-NET: Empty output from guest process for 'lgw'. hrc=%x\n", hrc));
    805                     continue;
    806                 }
    807 
    808                 if (cNotSupported)
    809                 {
    810                     LogRel(("CLOUD-NET: waitResult=9, repeated %u times\n", cNotSupported));
    811                     cNotSupported = 0;
    812                 }
    813                 if (cbStdOutData)
    814                     LogRel(("CLOUD-NET: Got stdout from 'lgw':\n%.*s", aStdOutData.size(), aStdOutData.raw()));
    815                 if (cbStdErrData)
    816                     LogRel(("CLOUD-NET: Got stderr from 'lgw':\n%.*s", aStdErrData.size(), aStdErrData.raw()));
    817             }
    818         }
    819         while (!fDone && RTTimeMilliTS() - u64Start < 180 * 1000 /* ms */);
    820 
    821     } while (false);
    822 
    823     return hrc;
    824 }
    825 
    826 
    827 HRESULT destroyLocalGateway(ComPtr<IVirtualBox> virtualBox, const GatewayInfo& gateways)
    828 {
    829     if (gateways.mGatewayVM.isEmpty())
     327#endif
     328
     329HRESULT stopCloudGateway(ComPtr<IVirtualBox> virtualBox, GatewayInfo& gateway)
     330{
     331    if (gateway.mGatewayInstanceId.isEmpty())
    830332        return S_OK;
    831333
    832     LogRel(("CLOUD-NET: Shutting down local gateway '%s'...\n", gateways.mGatewayVM.c_str()));
    833 
    834     ComPtr<IMachine> localGateway;
    835     HRESULT hrc = virtualBox->FindMachine(Bstr(gateways.mGatewayVM).raw(), localGateway.asOutParam());
    836     if (FAILED(hrc))
    837     {
    838         LogRel(("CLOUD-NET: Failed to locate '%s'. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc));
    839         return hrc;
    840     }
    841 
    842     MachineState_T tmp;
    843     hrc = localGateway->COMGETTER(State)(&tmp);
    844     if (tmp == MachineState_Running)
    845     {
    846         /* If the gateway VM is running we need to stop it */
    847         ComPtr<ISession> session;
    848         hrc = session.createInprocObject(CLSID_Session);
    849         if (FAILED(hrc))
    850         {
    851             LogRel(("CLOUD-NET: Failed to create a session. hrc=%x\n", hrc));
    852             return hrc;
    853         }
    854 
    855         hrc = localGateway->LockMachine(session, LockType_Shared);
    856         if (FAILED(hrc))
    857         {
    858             LogRel(("CLOUD-NET: Failed to lock '%s' for control. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc));
    859             return hrc;
    860         }
    861 
    862         ComPtr<IConsole> console;
    863         hrc = session->COMGETTER(Console)(console.asOutParam());
    864         if (FAILED(hrc))
    865         {
    866             LogRel(("CLOUD-NET: Failed to obtain console for '%s'. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc));
    867             return hrc;
    868         }
    869 
    870         ComPtr<IProgress> progress;
    871         console->PowerDown(progress.asOutParam()); /* We assume the gateway disk to be immutable! */
    872 
    873 #if 0
    874         hrc = progress->WaitForCompletion(-1);
    875         if (FAILED(hrc))
    876             LogRel(("CLOUD-NET: Failed to stop '%s'. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc));
    877 #endif
    878         session->UnlockMachine();
    879     }
    880 #if 0
    881     /*
    882      * Unfortunately we cannot unregister a machine we've just powered down and unlocked.
    883      * It takes some time for the machine to unlock completely.
    884      */
    885     /** @todo Removal of VM should probably be optional in the future. */
    886     SafeIfaceArray<IMedium> media;
    887     hrc = pLocalGateway->Unregister(CleanupMode_DetachAllReturnHardDisksOnly, ComSafeArrayAsOutParam(media));
    888     if (FAILED(hrc))
    889     {
    890         LogRel(("CLOUD-NET: Failed to unregister '%s'. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc));
    891         return hrc;
    892     }
    893     ComPtr<IProgress> removalProgress;
    894     hrc = pLocalGateway->DeleteConfig(ComSafeArrayAsInParam(media), removalProgress.asOutParam());
    895     if (FAILED(hrc))
    896     {
    897         LogRel(("CLOUD-NET: Failed to delete machine files for '%s'. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc));
    898     }
    899 #endif
    900     return hrc;
    901 }
    902 
    903 static HRESULT terminateCloudGateway(ComPtr<IVirtualBox> virtualBox, const GatewayInfo& gateways)
    904 {
    905     if (gateways.mGatewayInstanceId.isEmpty())
    906         return S_OK;
    907 
    908     LogRel(("CLOUD-NET: Terminating cloud gateway instance '%s'...\n", gateways.mGatewayInstanceId.c_str()));
     334    LogRel(("CLOUD-NET: Terminating cloud gateway instance '%s'...\n", gateway.mGatewayInstanceId.c_str()));
    909335
    910336    HRESULT hrc = S_OK;
    911337    try {
    912         CloudClient client(virtualBox, gateways.mCloudProvider, gateways.mCloudProfile);
    913         client.stopCloudGateway(gateways);
     338        CloudClient client(virtualBox, gateway.mCloudProvider, gateway.mCloudProfile);
     339        client.stopCloudGateway(gateway);
     340#if 0
     341# ifdef DEBUG
     342        char szKeyPath[RTPATH_MAX];
     343
     344        int rc = GetVBoxUserHomeDirectory(szKeyPath, sizeof(szKeyPath), false /* fCreateDir */);
     345        if (RT_SUCCESS(rc))
     346        {
     347            rc = RTPathAppend(szKeyPath, sizeof(szKeyPath), "gateway-key.pem");
     348            AssertRCReturn(rc, rc);
     349            rc = RTFileDelete(szKeyPath);
     350            if (RT_FAILURE(rc))
     351                LogRel(("WARNING! Failed to delete private key %s with rc=%d\n", szKeyPath, rc));
     352        }
     353        else
     354            LogRel(("WARNING! Failed to get VirtualBox user home directory with '%Rrc'\n", rc));
     355# endif /* DEBUG */
     356#endif
    914357    }
    915358    catch (CloudError e)
     
    918361        LogRel(("CLOUD-NET: Failed to terminate cloud gateway instance (rc=%x).\n", hrc));
    919362    }
     363    gateway.mGatewayInstanceId.setNull();
    920364    return hrc;
    921365}
    922366
    923 HRESULT startGateways(ComPtr<IVirtualBox> virtualBox, ComPtr<ICloudNetwork> network, GatewayInfo& gateways)
    924 {
    925     /* Session used to launch and control the local gateway VM */
    926     ComPtr<ISession> session;
    927     Bstr strNetwork;
    928     HRESULT hrc = session.createInprocObject(CLSID_Session);
    929     if (FAILED(hrc))
    930         LogRel(("CLOUD-NET: Failed to create a session. hrc=%x\n", hrc));
     367
     368HRESULT generateKeys(GatewayInfo& gateway)
     369{
     370#ifndef VBOX_WITH_LIBSSH
     371    RT_NOREF(gateway);
     372    return E_NOTIMPL;
     373#else /* VBOX_WITH_LIBSSH */
     374    ssh_key single_use_key;
     375    int rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 2048, &single_use_key);
     376    if (rc != SSH_OK)
     377    {
     378        LogRel(("Failed to generate a key pair. rc = %d\n", rc));
     379        return E_FAIL;
     380    }
     381
     382    char *pstrKey = NULL;
     383    rc = ssh_pki_export_privkey_base64(single_use_key, NULL, NULL, NULL, &pstrKey);
     384    if (rc != SSH_OK)
     385    {
     386        LogRel(("Failed to export private key. rc = %d\n", rc));
     387        return E_FAIL;
     388    }
     389    gateway.mPrivateSshKey = pstrKey;
     390#if 0
     391# ifdef DEBUG
     392    char szConfigPath[RTPATH_MAX];
     393
     394    rc = GetVBoxUserHomeDirectory(szConfigPath, sizeof(szConfigPath), false /* fCreateDir */);
     395    if (RT_SUCCESS(rc))
     396    {
     397        rc = RTPathAppend(szConfigPath, sizeof(szConfigPath), "gateway-key.pem");
     398        AssertRCReturn(rc, rc);
     399        rc = ssh_pki_export_privkey_file(single_use_key, NULL, NULL, NULL, szConfigPath);
     400        if (rc != SSH_OK)
     401        {
     402            LogRel(("Failed to export private key to %s with rc=%d\n", szConfigPath, rc));
     403            return E_FAIL;
     404        }
     405#  ifndef RT_OS_WINDOWS
     406        rc = RTPathSetMode(szConfigPath, RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR); /* Satisfy ssh client */
     407        AssertRCReturn(rc, rc);
     408#  endif
     409    }
    931410    else
    932         hrc = network->COMGETTER(NetworkName)(strNetwork.asOutParam());
    933     if (SUCCEEDED(hrc))
    934         hrc = startLocalGateway(virtualBox, session, strNetwork, gateways);
    935     if (SUCCEEDED(hrc))
    936         hrc = startCloudGateway(virtualBox, network, gateways);
    937     if (SUCCEEDED(hrc))
    938         hrc = exchangeInfoBetweenGateways(virtualBox, session, gateways);
    939 
    940     session->UnlockMachine();
    941     /** @todo Destroy gateways if unsuccessful (cleanup) */
    942 
    943     return hrc;
    944 }
    945 
    946 HRESULT stopGateways(ComPtr<IVirtualBox> virtualBox, const GatewayInfo& gateways)
    947 {
    948     HRESULT hrc = destroyLocalGateway(virtualBox, gateways);
    949     AssertComRC(hrc);
    950     hrc = terminateCloudGateway(virtualBox, gateways);
    951     AssertComRC(hrc);
    952     return hrc;
    953 }
     411    {
     412        LogRel(("Failed to get VirtualBox user home directory with '%Rrc'\n", rc));
     413        return E_FAIL;
     414    }
     415# endif /* DEBUG */
     416#endif
     417    ssh_string_free_char(pstrKey);
     418    pstrKey = NULL;
     419    rc = ssh_pki_export_pubkey_base64(single_use_key, &pstrKey);
     420    if (rc != SSH_OK)
     421    {
     422        LogRel(("Failed to export public key. rc = %d\n", rc));
     423        return E_FAIL;
     424    }
     425    gateway.mPublicSshKey = Utf8StrFmt("ssh-rsa %s single-use-key", pstrKey);
     426    ssh_string_free_char(pstrKey);
     427    ssh_key_free(single_use_key);
     428
     429    return S_OK;
     430#endif /* VBOX_WITH_LIBSSH */
     431}
  • trunk/src/VBox/Main/src-client/ConsoleImpl.cpp

    r93115 r93312  
    657657    }
    658658
    659 #ifdef VBOX_WITH_CLOUD_NET
    660     {
    661         ComPtr<IVirtualBox> pVirtualBox;
    662         HRESULT rc = mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
    663         AssertComRC(rc);
    664         if (SUCCEEDED(rc) && !pVirtualBox.isNull())
    665             stopGateways(pVirtualBox, mGateways);
    666     }
    667 #endif /* VBOX_WITH_CLOUD_NET */
    668659    LogFlowThisFunc(("initFailed()=%d\n", autoUninitSpan.initFailed()));
    669660    if (mVmListener)
     
    89468937                break;
    89478938
     8939#ifdef VBOX_WITH_CLOUD_NET
     8940            /*
     8941             * We stop cloud gateway here because we may have failed to connect to it,
     8942             * configure it, or establish a tunnel. We definitely do not want an orphaned
     8943             * instance running in the cloud.
     8944             */
     8945            {
     8946                ComPtr<IVirtualBox> pVirtualBox;
     8947                HRESULT rc = that->mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
     8948                AssertComRC(rc);
     8949                if (SUCCEEDED(rc) && !pVirtualBox.isNull())
     8950                    stopCloudGateway(pVirtualBox, that->mGateway);
     8951            }
     8952#endif /* VBOX_WITH_CLOUD_NET */
    89488953            /* Terminate host interface networking. If pUVM is NULL, we've been
    89498954             * manually called from powerUpThread() either before calling
  • trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp

    r93115 r93312  
    335335{
    336336    InsertConfigString(pNode, pcszName, Utf8Str(rBstrValue));
     337}
     338
     339/**
     340 * Helper that calls CFGMR3InsertPassword and throws an RTCError if that
     341 * fails (Utf8Str variant).
     342 * @param   pNode           See CFGMR3InsertPasswordN.
     343 * @param   pcszName        See CFGMR3InsertPasswordN.
     344 * @param   rStrValue       The string value.
     345 */
     346static void InsertConfigPassword(PCFGMNODE pNode,
     347                               const char *pcszName,
     348                               const Utf8Str &rStrValue)
     349{
     350    int vrc = CFGMR3InsertPasswordN(pNode,
     351                                    pcszName,
     352                                    rStrValue.c_str(),
     353                                    rStrValue.length());
     354    if (RT_FAILURE(vrc))
     355        throw ConfigError("CFGMR3InsertPasswordLengthKnown", vrc, pcszName);
    337356}
    338357
     
    27582777            if (eAttachmentType == NetworkAttachmentType_Cloud)
    27592778            {
    2760                 mGateways.setLocalMacAddress(macAddrUtf8);
     2779                mGateway.setLocalMacAddress(macAddrUtf8);
    27612780                /* We'll insert cloud MAC later, when it becomes known. */
    27622781            }
     
    63816400                ComPtr<ICloudNetwork> network;
    63826401                hrc = aNetworkAdapter->COMGETTER(CloudNetwork)(bstr.asOutParam());            H();
    6383                 hrc = pMachine->COMGETTER(Name)(mGateways.mTargetVM.asOutParam());            H();
     6402                hrc = pMachine->COMGETTER(Name)(mGateway.mTargetVM.asOutParam());            H();
    63846403                hrc = virtualBox->FindCloudNetworkByName(bstr.raw(), network.asOutParam());   H();
    6385                 hrc = startGateways(virtualBox, network, mGateways);                          H();
    6386                 InsertConfigBytes(pDevCfg, "MAC", &mGateways.mCloudMacAddress, sizeof(mGateways.mCloudMacAddress));
     6404                hrc = generateKeys(mGateway);
     6405                if (FAILED(hrc))
     6406                {
     6407                    if (hrc == E_NOTIMPL)
     6408                        return VMSetError(VMR3GetVM(mpUVM), VERR_NOT_FOUND, RT_SRC_POS,
     6409                                N_("Failed to generate a key pair due to missing libssh\n"
     6410                                    "To fix this problem, either build VirtualBox with libssh "
     6411                                    "support or switch to another network attachment type in "
     6412                                    "the VM settings.\n"));
     6413                    else
     6414                        return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
     6415                                N_("Failed to generate a key pair due to libssh error!\n"));
     6416                }
     6417                hrc = startCloudGateway(virtualBox, network, mGateway);                      H();
     6418                InsertConfigBytes(pDevCfg, "MAC", &mGateway.mCloudMacAddress, sizeof(mGateway.mCloudMacAddress));
    63876419                if (!bstr.isEmpty())
    63886420                {
    6389                     InsertConfigString(pLunL0, "Driver", "IntNet");
     6421                    InsertConfigString(pLunL0, "Driver", "CloudTunnel");
    63906422                    InsertConfigNode(pLunL0, "Config", &pCfg);
    6391                     InsertConfigString(pCfg, "Network", BstrFmt("cloud-%ls", bstr.raw()));
    6392                     InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
    6393                     InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
     6423                    InsertConfigPassword(pCfg, "SshKey", mGateway.mPrivateSshKey);
     6424                    InsertConfigString(pCfg, "PrimaryIP", mGateway.mCloudPublicIp);
     6425                    InsertConfigString(pCfg, "SecondaryIP", mGateway.mCloudSecondaryPublicIp);
     6426                    InsertConfigBytes(pCfg, "TargetMAC", &mGateway.mLocalMacAddress, sizeof(mGateway.mLocalMacAddress));
    63946427                    networkName = bstr;
    63956428                    trunkType = Bstr(TRUNKTYPE_WHATEVER);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette