Skip to content

Commit

Permalink
add http proxy support for secure tunneling
Browse files Browse the repository at this point in the history
  • Loading branch information
RogerZhongAWS committed Dec 11, 2023
1 parent d11c527 commit fb58d1f
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 25 deletions.
3 changes: 2 additions & 1 deletion source/SharedCrtResourceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,11 +340,12 @@ int SharedCrtResourceManager::establishConnection(const PlainConfig &config)
{
proxyOptions.HostName = proxyConfig.proxyHost->c_str();
proxyOptions.Port = proxyConfig.proxyPort.value();
proxyOptions.ProxyConnectionType = Aws::Crt::Http::AwsHttpProxyConnectionType::Tunneling;

LOGM_INFO(
TAG,
"Attempting to establish MQTT connection with proxy: %s:%u",
proxyConfig.proxyHost->c_str(),
proxyOptions.HostName.c_str(),
proxyConfig.proxyPort.value());

if (proxyConfig.httpProxyAuthEnabled)
Expand Down
37 changes: 37 additions & 0 deletions source/tunneling/SecureTunnelWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,43 @@ SecureTunnelWrapper::SecureTunnelWrapper(
onSessionReset))
{
}

SecureTunnelWrapper::SecureTunnelWrapper(
Aws::Crt::Allocator *allocator,
Aws::Crt::Io::ClientBootstrap *bootstrap,
const Aws::Crt::Io::SocketOptions &socketOptions,
const Aws::Crt::Http::HttpClientConnectionProxyOptions &proxyOptions,
const std::string &accessToken,
aws_secure_tunneling_local_proxy_mode localProxyMode,
const std::string &endpoint,
const std::string &rootCa,
const Aws::Iotsecuretunneling::OnConnectionComplete &onConnectionComplete,
const Aws::Iotsecuretunneling::OnConnectionShutdown &onConnectionShutdown,
const Aws::Iotsecuretunneling::OnSendDataComplete &onSendDataComplete,
const Aws::Iotsecuretunneling::OnDataReceive &onDataReceive,
const Aws::Iotsecuretunneling::OnStreamStart &onStreamStart,
const Aws::Iotsecuretunneling::OnStreamReset &onStreamReset,
const Aws::Iotsecuretunneling::OnSessionReset &onSessionReset)
: secureTunnel((Aws::Iotsecuretunneling::SecureTunnelBuilder(
allocator,
*bootstrap,
socketOptions,
accessToken,
localProxyMode,
endpoint))
.WithHttpClientConnectionProxyOptions(proxyOptions)
.WithRootCa(rootCa)
.WithOnConnectionComplete(onConnectionComplete)
.WithOnConnectionShutdown(onConnectionShutdown)
.WithOnSendDataComplete(onSendDataComplete)
.WithOnDataReceive(onDataReceive)
.WithOnStreamStart(onStreamStart)
.WithOnStreamReset(onSessionReset)
.WithOnSessionReset(onSessionReset)
.Build())
{
}

int SecureTunnelWrapper::Connect()
{
return secureTunnel->Connect();
Expand Down
24 changes: 23 additions & 1 deletion source/tunneling/SecureTunnelWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,32 @@ namespace Aws
public:
SecureTunnelWrapper() = default;
virtual ~SecureTunnelWrapper() = default;

// Without HTTP Proxy
SecureTunnelWrapper(
Aws::Crt::Allocator *allocator,
Aws::Crt::Io::ClientBootstrap *clientBootstrap,
const Aws::Crt::Io::SocketOptions &socketOptions,

const std::string &accessToken,
aws_secure_tunneling_local_proxy_mode localProxyMode,
const std::string &endpointHost,
const std::string &rootCa,

const Aws::Iotsecuretunneling::OnConnectionComplete &onConnectionComplete,
const Aws::Iotsecuretunneling::OnConnectionShutdown &onConnectionShutdown,
const Aws::Iotsecuretunneling::OnSendDataComplete &onSendDataComplete,
const Aws::Iotsecuretunneling::OnDataReceive &onDataReceive,
const Aws::Iotsecuretunneling::OnStreamStart &onStreamStart,
const Aws::Iotsecuretunneling::OnStreamReset &onStreamReset,
const Aws::Iotsecuretunneling::OnSessionReset &onSessionReset);

// With HTTP Proxy
SecureTunnelWrapper(
Aws::Crt::Allocator *allocator,
Aws::Crt::Io::ClientBootstrap *clientBootstrap,
const Aws::Crt::Io::SocketOptions &socketOptions,
const Aws::Crt::Http::HttpClientConnectionProxyOptions &proxyOptions,

const std::string &accessToken,
aws_secure_tunneling_local_proxy_mode localProxyMode,
Expand All @@ -47,7 +69,7 @@ namespace Aws

virtual bool IsValid();

std::unique_ptr<Aws::Iotsecuretunneling::SecureTunnel> secureTunnel;
std::shared_ptr<Aws::Iotsecuretunneling::SecureTunnel> secureTunnel;

private:
/**
Expand Down
69 changes: 53 additions & 16 deletions source/tunneling/SecureTunnelingContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,21 @@ namespace Aws
const int port,
const OnConnectionShutdownFn &onConnectionShutdown)
: mSharedCrtResourceManager(manager), mRootCa(rootCa.has_value() ? rootCa.value() : ""),
mAccessToken(accessToken), mEndpoint(endpoint), mPort(port),
mAccessToken(accessToken), mEndpoint(endpoint), mPort(port), isHTTPProxyEnabled(false),
mOnConnectionShutdown(onConnectionShutdown)
{
}

SecureTunnelingContext::SecureTunnelingContext(
shared_ptr<SharedCrtResourceManager> manager,
const Aws::Crt::Http::HttpClientConnectionProxyOptions &proxyOptions,
const Aws::Crt::Optional<std::string> &rootCa,
const string &accessToken,
const string &endpoint,
const int port,
const OnConnectionShutdownFn &onConnectionShutdown)
: mSharedCrtResourceManager(manager), mProxyOptions(proxyOptions), mRootCa(rootCa.has_value() ? rootCa.value() : ""),
mAccessToken(accessToken), mEndpoint(endpoint), mPort(port), isHTTPProxyEnabled(true),
mOnConnectionShutdown(onConnectionShutdown)
{
}
Expand Down Expand Up @@ -191,21 +205,44 @@ namespace Aws
const Aws::Iotsecuretunneling::OnStreamReset &onStreamReset,
const Aws::Iotsecuretunneling::OnSessionReset &onSessionReset)
{
return std::make_shared<SecureTunnelWrapper>(
mSharedCrtResourceManager->getAllocator(),
mSharedCrtResourceManager->getClientBootstrap(),
Crt::Io::SocketOptions(),
mAccessToken,
AWS_SECURE_TUNNELING_DESTINATION_MODE,
mEndpoint,
mRootCa,
onConnectionComplete,
onConnectionShutdown,
onSendDataComplete,
onDataReceive,
onStreamStart,
onStreamReset,
onSessionReset);
// const Aws::Crt::Http::HttpClientConnectionProxyOptions& proxyOptions = mProxyOptions;

if (isHTTPProxyEnabled) {
LOGM_INFO(TAG, "Creating Secure Tunneling with proxy to: %s", mProxyOptions.HostName.c_str());
return std::make_shared<SecureTunnelWrapper>(
mSharedCrtResourceManager->getAllocator(),
mSharedCrtResourceManager->getClientBootstrap(),
Crt::Io::SocketOptions(),
mProxyOptions,
mAccessToken,
AWS_SECURE_TUNNELING_DESTINATION_MODE,
mEndpoint,
mRootCa,
onConnectionComplete,
nullptr, // TODO: long term fix needed for onConnectionShutdown callback
onSendDataComplete,
onDataReceive,
onStreamStart,
onStreamReset,
onSessionReset);
}
else {
return std::make_shared<SecureTunnelWrapper>(
mSharedCrtResourceManager->getAllocator(),
mSharedCrtResourceManager->getClientBootstrap(),
Crt::Io::SocketOptions(),
mAccessToken,
AWS_SECURE_TUNNELING_DESTINATION_MODE,
mEndpoint,
mRootCa,
onConnectionComplete,
nullptr, // TODO: long term fix needed for onConnectionShutdown callback
onSendDataComplete,
onDataReceive,
onStreamStart,
onStreamReset,
onSessionReset);
}
}

std::shared_ptr<TcpForward> SecureTunnelingContext::CreateTcpForward()
Expand Down
19 changes: 19 additions & 0 deletions source/tunneling/SecureTunnelingContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ namespace Aws
const int port,
const OnConnectionShutdownFn &onConnectionShutdown);

SecureTunnelingContext(
std::shared_ptr<SharedCrtResourceManager> manager,
const Aws::Crt::Http::HttpClientConnectionProxyOptions &proxyOptions,
const Aws::Crt::Optional<std::string> &rootCa,
const std::string &accessToken,
const std::string &endpoint,
const int port,
const OnConnectionShutdownFn &onConnectionShutdown);

/**
* \brief Constructor
*/
Expand Down Expand Up @@ -178,6 +187,11 @@ namespace Aws
*/
std::shared_ptr<SharedCrtResourceManager> mSharedCrtResourceManager;

/**
* \brief HTTP proxy strategy and auth config
*/
Aws::Crt::Http::HttpClientConnectionProxyOptions mProxyOptions;

/**
* \brief Path to the Amazon root CA
*/
Expand All @@ -198,6 +212,11 @@ namespace Aws
*/
uint16_t mPort{22};

/**
* \brief boolean for HTTP proxy enablement
*/
bool isHTTPProxyEnabled;

/**
* \brief Callback when the secure tunnel is shutdown
*/
Expand Down
48 changes: 41 additions & 7 deletions source/tunneling/SecureTunnelingFeature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,20 +94,53 @@ namespace Aws

void SecureTunnelingFeature::LoadFromConfig(const PlainConfig &config)
{
// Aws::Crt::Http::HttpClientConnectionProxyOptions proxyOptions;
PlainConfig::HttpProxyConfig proxyConfig = config.httpProxyConfig;

if (proxyConfig.httpProxyEnabled)
{
proxyOptions.HostName = proxyConfig.proxyHost->c_str();
proxyOptions.Port = proxyConfig.proxyPort.value();
proxyOptions.ProxyConnectionType = Aws::Crt::Http::AwsHttpProxyConnectionType::Tunneling;

LOGM_INFO(
TAG,
"Attempting to establish tunneling connection with proxy: %s:%u",
proxyOptions.HostName.c_str(),
proxyOptions.Port);

if (proxyConfig.httpProxyAuthEnabled)
{
LOG_INFO(TAG, "Proxy Authentication is enabled");
Aws::Crt::Http::HttpProxyStrategyBasicAuthConfig basicAuthConfig;
basicAuthConfig.ConnectionType = Aws::Crt::Http::AwsHttpProxyConnectionType::Tunneling;
proxyOptions.AuthType = Aws::Crt::Http::AwsHttpProxyAuthenticationType::Basic;
basicAuthConfig.Username = proxyConfig.proxyUsername->c_str();
basicAuthConfig.Password = proxyConfig.proxyPassword->c_str();
proxyOptions.ProxyStrategy =
Aws::Crt::Http::HttpProxyStrategy::CreateBasicHttpProxyStrategy(basicAuthConfig, Aws::Crt::g_allocator);
}
else
{
LOG_INFO(TAG, "Proxy Authentication is disabled");
proxyOptions.AuthType = Aws::Crt::Http::AwsHttpProxyAuthenticationType::None;
}
}
mThingName = *config.thingName;
mRootCa = config.rootCa;
mSubscribeNotification = config.tunneling.subscribeNotification;
mEndpoint = config.tunneling.endpoint;

if (!config.tunneling.subscribeNotification)
{
auto context = unique_ptr<SecureTunnelingContext>(new SecureTunnelingContext(
mSharedCrtResourceManager,
mRootCa,
*config.tunneling.destinationAccessToken,
GetEndpoint(*config.tunneling.region),
static_cast<uint16_t>(config.tunneling.port.value()),
bind(&SecureTunnelingFeature::OnConnectionShutdown, this, placeholders::_1)));
auto context = createContext(*config.tunneling.destinationAccessToken, *config.tunneling.region, static_cast<uint16_t>(config.tunneling.port.value()));
// auto context = unique_ptr<SecureTunnelingContext>(new SecureTunnelingContext(
// mSharedCrtResourceManager,
// mRootCa,
// *config.tunneling.destinationAccessToken,
// GetEndpoint(*config.tunneling.region),
// static_cast<uint16_t>(config.tunneling.port.value()),
// bind(&SecureTunnelingFeature::OnConnectionShutdown, this, placeholders::_1)));
mContexts.push_back(std::move(context));
}
}
Expand Down Expand Up @@ -257,6 +290,7 @@ namespace Aws
{
return std::unique_ptr<SecureTunnelingContext>(new SecureTunnelingContext(
mSharedCrtResourceManager,
proxyOptions,
mRootCa,
accessToken,
GetEndpoint(region),
Expand Down
6 changes: 6 additions & 0 deletions source/tunneling/SecureTunnelingFeature.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "../SharedCrtResourceManager.h"
#include "IotSecureTunnelingClientWrapper.h"
#include "SecureTunnelingContext.h"
#include "aws/crt/http/HttpProxyStrategy.h"
#include <aws/iotdevicecommon/IotDevice.h>
#include <aws/iotsecuretunneling/SecureTunnelingNotifyResponse.h>

Expand Down Expand Up @@ -177,6 +178,11 @@ namespace Aws
*/
std::shared_ptr<ClientBaseNotifier> mClientBaseNotifier;

/**
* \brief HTTP proxy strategy and auth config
*/
Aws::Crt::Http::HttpClientConnectionProxyOptions proxyOptions;

/**
* \brief The ThingName to use
*/
Expand Down

0 comments on commit fb58d1f

Please sign in to comment.