diff --git a/source/SharedCrtResourceManager.cpp b/source/SharedCrtResourceManager.cpp index 9f0f1138..25e9f2e4 100644 --- a/source/SharedCrtResourceManager.cpp +++ b/source/SharedCrtResourceManager.cpp @@ -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) diff --git a/source/tunneling/SecureTunnelWrapper.cpp b/source/tunneling/SecureTunnelWrapper.cpp index a7c8b3bc..606f05ae 100644 --- a/source/tunneling/SecureTunnelWrapper.cpp +++ b/source/tunneling/SecureTunnelWrapper.cpp @@ -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(); diff --git a/source/tunneling/SecureTunnelWrapper.h b/source/tunneling/SecureTunnelWrapper.h index af07c071..babf0124 100644 --- a/source/tunneling/SecureTunnelWrapper.h +++ b/source/tunneling/SecureTunnelWrapper.h @@ -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, @@ -47,7 +69,7 @@ namespace Aws virtual bool IsValid(); - std::unique_ptr secureTunnel; + std::shared_ptr secureTunnel; private: /** diff --git a/source/tunneling/SecureTunnelingContext.cpp b/source/tunneling/SecureTunnelingContext.cpp index 15f91a83..9ee4dccb 100644 --- a/source/tunneling/SecureTunnelingContext.cpp +++ b/source/tunneling/SecureTunnelingContext.cpp @@ -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 manager, + const Aws::Crt::Http::HttpClientConnectionProxyOptions &proxyOptions, + const Aws::Crt::Optional &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) { } @@ -191,21 +205,44 @@ namespace Aws const Aws::Iotsecuretunneling::OnStreamReset &onStreamReset, const Aws::Iotsecuretunneling::OnSessionReset &onSessionReset) { - return std::make_shared( - 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( + 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( + 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 SecureTunnelingContext::CreateTcpForward() diff --git a/source/tunneling/SecureTunnelingContext.h b/source/tunneling/SecureTunnelingContext.h index d0aed1ef..abc4518c 100644 --- a/source/tunneling/SecureTunnelingContext.h +++ b/source/tunneling/SecureTunnelingContext.h @@ -47,6 +47,15 @@ namespace Aws const int port, const OnConnectionShutdownFn &onConnectionShutdown); + SecureTunnelingContext( + std::shared_ptr manager, + const Aws::Crt::Http::HttpClientConnectionProxyOptions &proxyOptions, + const Aws::Crt::Optional &rootCa, + const std::string &accessToken, + const std::string &endpoint, + const int port, + const OnConnectionShutdownFn &onConnectionShutdown); + /** * \brief Constructor */ @@ -178,6 +187,11 @@ namespace Aws */ std::shared_ptr mSharedCrtResourceManager; + /** + * \brief HTTP proxy strategy and auth config + */ + Aws::Crt::Http::HttpClientConnectionProxyOptions mProxyOptions; + /** * \brief Path to the Amazon root CA */ @@ -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 */ diff --git a/source/tunneling/SecureTunnelingFeature.cpp b/source/tunneling/SecureTunnelingFeature.cpp index a77ab697..97972cc9 100644 --- a/source/tunneling/SecureTunnelingFeature.cpp +++ b/source/tunneling/SecureTunnelingFeature.cpp @@ -94,6 +94,38 @@ 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; @@ -101,13 +133,14 @@ namespace Aws if (!config.tunneling.subscribeNotification) { - auto context = unique_ptr(new SecureTunnelingContext( - mSharedCrtResourceManager, - mRootCa, - *config.tunneling.destinationAccessToken, - GetEndpoint(*config.tunneling.region), - static_cast(config.tunneling.port.value()), - bind(&SecureTunnelingFeature::OnConnectionShutdown, this, placeholders::_1))); + auto context = createContext(*config.tunneling.destinationAccessToken, *config.tunneling.region, static_cast(config.tunneling.port.value())); + // auto context = unique_ptr(new SecureTunnelingContext( + // mSharedCrtResourceManager, + // mRootCa, + // *config.tunneling.destinationAccessToken, + // GetEndpoint(*config.tunneling.region), + // static_cast(config.tunneling.port.value()), + // bind(&SecureTunnelingFeature::OnConnectionShutdown, this, placeholders::_1))); mContexts.push_back(std::move(context)); } } @@ -257,6 +290,7 @@ namespace Aws { return std::unique_ptr(new SecureTunnelingContext( mSharedCrtResourceManager, + proxyOptions, mRootCa, accessToken, GetEndpoint(region), diff --git a/source/tunneling/SecureTunnelingFeature.h b/source/tunneling/SecureTunnelingFeature.h index e7b85554..f07642c7 100644 --- a/source/tunneling/SecureTunnelingFeature.h +++ b/source/tunneling/SecureTunnelingFeature.h @@ -9,6 +9,7 @@ #include "../SharedCrtResourceManager.h" #include "IotSecureTunnelingClientWrapper.h" #include "SecureTunnelingContext.h" +#include "aws/crt/http/HttpProxyStrategy.h" #include #include @@ -177,6 +178,11 @@ namespace Aws */ std::shared_ptr mClientBaseNotifier; + /** + * \brief HTTP proxy strategy and auth config + */ + Aws::Crt::Http::HttpClientConnectionProxyOptions proxyOptions; + /** * \brief The ThingName to use */