VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/CloudGateway.cpp@ 94521

Last change on this file since 94521 was 94521, checked in by vboxsync, 2 years ago

libs/libssh,Main,FE/VBoxManage,Devices/Network/DrvCloudTunnel|ai: Add support for proxies, bugref:9469

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.0 KB
Line 
1/* $Id: CloudGateway.cpp 94521 2022-04-07 15:18:48Z vboxsync $ */
2/** @file
3 * Implementation of local and cloud gateway management.
4 */
5
6/*
7 * Copyright (C) 2019-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define LOG_GROUP LOG_GROUP_MAIN_CONSOLE
19
20/* Make sure all the stdint.h macros are included - must come first! */
21#ifndef __STDC_LIMIT_MACROS
22# define __STDC_LIMIT_MACROS
23#endif
24#ifndef __STDC_CONSTANT_MACROS
25# define __STDC_CONSTANT_MACROS
26#endif
27
28#include "LoggingNew.h"
29#include "ApplianceImpl.h"
30#include "CloudNetworkImpl.h"
31#include "CloudGateway.h"
32
33#include <iprt/http.h>
34#include <iprt/inifile.h>
35#include <iprt/net.h>
36#include <iprt/path.h>
37#include <iprt/vfs.h>
38#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
50
51static HRESULT setMacAddress(const Utf8Str& str, RTMAC& mac)
52{
53 int rc = RTNetStrToMacAddr(str.c_str(), &mac);
54 if (RT_FAILURE(rc))
55 {
56 LogRel(("CLOUD-NET: Invalid MAC address '%s'\n", str.c_str()));
57 return E_INVALIDARG;
58 }
59 return S_OK;
60}
61
62
63HRESULT GatewayInfo::setCloudMacAddress(const Utf8Str& mac)
64{
65 return setMacAddress(mac, mCloudMacAddress);
66}
67
68
69HRESULT GatewayInfo::setLocalMacAddress(const Utf8Str& mac)
70{
71 return setMacAddress(mac, mLocalMacAddress);
72}
73
74
75class CloudError
76{
77public:
78 CloudError(HRESULT hrc, const Utf8Str& strText) : mHrc(hrc), mText(strText) {};
79 HRESULT getRc() { return mHrc; };
80 Utf8Str getText() { return mText; };
81
82private:
83 HRESULT mHrc;
84 Utf8Str mText;
85};
86
87
88static void handleErrors(HRESULT hrc, const char *pszFormat, ...)
89{
90 if (FAILED(hrc))
91 {
92 va_list va;
93 va_start(va, pszFormat);
94 Utf8Str strError(pszFormat, va);
95 va_end(va);
96 LogRel(("CLOUD-NET: %s (rc=%x)\n", strError.c_str(), hrc));
97 throw CloudError(hrc, strError);
98 }
99
100}
101
102
103class CloudClient
104{
105public:
106 CloudClient(ComPtr<IVirtualBox> virtualBox, const Bstr& strProvider, const Bstr& strProfile);
107 ~CloudClient() {};
108
109 void startCloudGateway(const ComPtr<ICloudNetwork> &network, GatewayInfo& gateway);
110 void stopCloudGateway(const GatewayInfo& gateway);
111
112private:
113 ComPtr<ICloudProviderManager> mManager;
114 ComPtr<ICloudProvider> mProvider;
115 ComPtr<ICloudProfile> mProfile;
116 ComPtr<ICloudClient> mClient;
117};
118
119
120CloudClient::CloudClient(ComPtr<IVirtualBox> virtualBox, const Bstr& strProvider, const Bstr& strProfile)
121{
122 HRESULT hrc = virtualBox->COMGETTER(CloudProviderManager)(mManager.asOutParam());
123 handleErrors(hrc, "Failed to obtain cloud provider manager object");
124 hrc = mManager->GetProviderByShortName(strProvider.raw(), mProvider.asOutParam());
125 handleErrors(hrc, "Failed to obtain cloud provider '%ls'", strProvider.raw());
126 hrc = mProvider->GetProfileByName(strProfile.raw(), mProfile.asOutParam());
127 handleErrors(hrc, "Failed to obtain cloud profile '%ls'", strProfile.raw());
128 hrc = mProfile->CreateCloudClient(mClient.asOutParam());
129 handleErrors(hrc, "Failed to create cloud client");
130}
131
132
133void CloudClient::startCloudGateway(const ComPtr<ICloudNetwork> &network, GatewayInfo& gateway)
134{
135 ComPtr<IProgress> progress;
136 ComPtr<ICloudNetworkGatewayInfo> gatewayInfo;
137 HRESULT hrc = mClient->StartCloudNetworkGateway(network, Bstr(gateway.mPublicSshKey).raw(),
138 gatewayInfo.asOutParam(), progress.asOutParam());
139 handleErrors(hrc, "Failed to launch compute instance");
140 hrc = progress->WaitForCompletion(-1);
141 handleErrors(hrc, "Failed to launch compute instance (wait)");
142
143 Bstr instanceId;
144 hrc = gatewayInfo->COMGETTER(InstanceId)(instanceId.asOutParam());
145 handleErrors(hrc, "Failed to get launched compute instance id");
146 gateway.mGatewayInstanceId = instanceId;
147
148 Bstr publicIP;
149 hrc = gatewayInfo->COMGETTER(PublicIP)(publicIP.asOutParam());
150 handleErrors(hrc, "Failed to get cloud gateway public IP address");
151 gateway.mCloudPublicIp = publicIP;
152
153 Bstr secondaryPublicIP;
154 hrc = gatewayInfo->COMGETTER(SecondaryPublicIP)(secondaryPublicIP.asOutParam());
155 handleErrors(hrc, "Failed to get cloud gateway secondary public IP address");
156 gateway.mCloudSecondaryPublicIp = secondaryPublicIP;
157
158 Bstr macAddress;
159 hrc = gatewayInfo->COMGETTER(MacAddress)(macAddress.asOutParam());
160 handleErrors(hrc, "Failed to get cloud gateway public IP address");
161 gateway.setCloudMacAddress(macAddress);
162}
163
164
165void CloudClient::stopCloudGateway(const GatewayInfo& gateway)
166{
167 ComPtr<IProgress> progress;
168 HRESULT hrc = mClient->TerminateInstance(Bstr(gateway.mGatewayInstanceId).raw(), progress.asOutParam());
169 handleErrors(hrc, "Failed to terminate compute instance");
170#if 0
171 /* Someday we may want to wait until the cloud gateway has terminated. */
172 hrc = progress->WaitForCompletion(-1);
173 handleErrors(hrc, "Failed to terminate compute instance (wait)");
174#endif
175}
176
177
178HRESULT startCloudGateway(ComPtr<IVirtualBox> virtualBox, ComPtr<ICloudNetwork> network, GatewayInfo& gateway)
179{
180 HRESULT hrc = S_OK;
181
182 try {
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);
187 }
188 catch (CloudError e)
189 {
190 hrc = e.getRc();
191 }
192
193 return hrc;
194}
195
196
197HRESULT stopCloudGateway(ComPtr<IVirtualBox> virtualBox, GatewayInfo& gateway)
198{
199 if (gateway.mGatewayInstanceId.isEmpty())
200 return S_OK;
201
202 LogRel(("CLOUD-NET: Terminating cloud gateway instance '%s'...\n", gateway.mGatewayInstanceId.c_str()));
203
204 HRESULT hrc = S_OK;
205 try {
206 CloudClient client(virtualBox, gateway.mCloudProvider, gateway.mCloudProfile);
207 client.stopCloudGateway(gateway);
208#if 0
209# ifdef DEBUG
210 char szKeyPath[RTPATH_MAX];
211
212 int rc = GetVBoxUserHomeDirectory(szKeyPath, sizeof(szKeyPath), false /* fCreateDir */);
213 if (RT_SUCCESS(rc))
214 {
215 rc = RTPathAppend(szKeyPath, sizeof(szKeyPath), "gateway-key.pem");
216 AssertRCReturn(rc, rc);
217 rc = RTFileDelete(szKeyPath);
218 if (RT_FAILURE(rc))
219 LogRel(("WARNING! Failed to delete private key %s with rc=%d\n", szKeyPath, rc));
220 }
221 else
222 LogRel(("WARNING! Failed to get VirtualBox user home directory with '%Rrc'\n", rc));
223# endif /* DEBUG */
224#endif
225 }
226 catch (CloudError e)
227 {
228 hrc = e.getRc();
229 LogRel(("CLOUD-NET: Failed to terminate cloud gateway instance (rc=%x).\n", hrc));
230 }
231 gateway.mGatewayInstanceId.setNull();
232 return hrc;
233}
234
235
236HRESULT generateKeys(GatewayInfo& gateway)
237{
238#ifndef VBOX_WITH_LIBSSH
239 RT_NOREF(gateway);
240 return E_NOTIMPL;
241#else /* VBOX_WITH_LIBSSH */
242 ssh_key single_use_key;
243 int rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 2048, &single_use_key);
244 if (rc != SSH_OK)
245 {
246 LogRel(("Failed to generate a key pair. rc = %d\n", rc));
247 return E_FAIL;
248 }
249
250 char *pstrKey = NULL;
251 rc = ssh_pki_export_privkey_base64(single_use_key, NULL, NULL, NULL, &pstrKey);
252 if (rc != SSH_OK)
253 {
254 LogRel(("Failed to export private key. rc = %d\n", rc));
255 return E_FAIL;
256 }
257 gateway.mPrivateSshKey = pstrKey;
258#if 0
259# ifdef DEBUG
260 char szConfigPath[RTPATH_MAX];
261
262 rc = GetVBoxUserHomeDirectory(szConfigPath, sizeof(szConfigPath), false /* fCreateDir */);
263 if (RT_SUCCESS(rc))
264 {
265 rc = RTPathAppend(szConfigPath, sizeof(szConfigPath), "gateway-key.pem");
266 AssertRCReturn(rc, rc);
267 rc = ssh_pki_export_privkey_file(single_use_key, NULL, NULL, NULL, szConfigPath);
268 if (rc != SSH_OK)
269 {
270 LogRel(("Failed to export private key to %s with rc=%d\n", szConfigPath, rc));
271 return E_FAIL;
272 }
273# ifndef RT_OS_WINDOWS
274 rc = RTPathSetMode(szConfigPath, RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR); /* Satisfy ssh client */
275 AssertRCReturn(rc, rc);
276# endif
277 }
278 else
279 {
280 LogRel(("Failed to get VirtualBox user home directory with '%Rrc'\n", rc));
281 return E_FAIL;
282 }
283# endif /* DEBUG */
284#endif
285 ssh_string_free_char(pstrKey);
286 pstrKey = NULL;
287 rc = ssh_pki_export_pubkey_base64(single_use_key, &pstrKey);
288 if (rc != SSH_OK)
289 {
290 LogRel(("Failed to export public key. rc = %d\n", rc));
291 return E_FAIL;
292 }
293 gateway.mPublicSshKey = Utf8StrFmt("ssh-rsa %s single-use-key", pstrKey);
294 ssh_string_free_char(pstrKey);
295 ssh_key_free(single_use_key);
296
297 return S_OK;
298#endif /* VBOX_WITH_LIBSSH */
299}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use