This is an automated email from the ASF dual-hosted git repository.

cgivre pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/drill.git


The following commit(s) were added to refs/heads/master by this push:
     new 264ac06  DRILL-7795: Add support for overriding hostname to C++ client
264ac06 is described below

commit 264ac06831041498e51af9bc296ede9f0834b3f8
Author: James Duong <[email protected]>
AuthorDate: Fri Oct 9 14:47:48 2020 -0700

    DRILL-7795: Add support for overriding hostname to C++ client
    
    * Add the hostnameOverride property to specify the expected hostname in the 
SSL certificate.
    * Set the TLS SNI property to the host field even if the hostname wasn't 
overridden.
    * Update querySubmitter example to include this new property.
    * Change querySubmitter so that the number of options is detected from the 
options array
    rather than being a constant that requires manual updates.
---
 contrib/native/client/example/querySubmitter.cpp   | 15 +++++---
 contrib/native/client/src/clientlib/channel.cpp    | 22 +++++++----
 contrib/native/client/src/clientlib/channel.hpp    | 44 ++++++++++++++++++++--
 contrib/native/client/src/clientlib/errmsgs.cpp    |  1 +
 contrib/native/client/src/clientlib/errmsgs.hpp    |  7 +++-
 .../native/client/src/clientlib/userProperties.cpp |  1 +
 contrib/native/client/src/include/drill/common.hpp |  1 +
 7 files changed, 72 insertions(+), 19 deletions(-)

diff --git a/contrib/native/client/example/querySubmitter.cpp 
b/contrib/native/client/example/querySubmitter.cpp
index 1ca7668..7c66613 100644
--- a/contrib/native/client/example/querySubmitter.cpp
+++ b/contrib/native/client/example/querySubmitter.cpp
@@ -23,8 +23,6 @@
 #include <boost/algorithm/string/join.hpp>
 #include "drill/drillc.hpp"
 
-int nOptions=27;
-
 struct Option{
     char name[32];
     char desc[128];
@@ -56,7 +54,8 @@ struct Option{
     {"disableCertVerification", "disable certificate verification", false},
     {"useSystemTrustStore", "[Windows only]. Use the system truststore.", 
false},
     {"CustomSSLCtxOptions", "The custom SSL CTX Options", false},
-    {"supportComplexTypes", "Toggle for supporting complex types", false}
+    {"supportComplexTypes", "Toggle for supporting complex types", false},
+    {"hostnameOverride", "Override the SSL server hostname", false}
 };
 
 std::map<std::string, std::string> qsOptionValues;
@@ -165,7 +164,7 @@ void print(const Drill::FieldMetadata* pFieldMetadata, 
void* buf, size_t sz){
 
 void printUsage(){
     std::cerr<<"Usage: querySubmitter ";
-    for(int j=0; j<nOptions ;j++){
+    for(int j=0; j<sizeof(qsOptions)/sizeof(qsOptions[0]) ;j++){
         std::cerr<< " "<< qsOptions[j].name <<"="  << "[" <<qsOptions[j].desc 
<<"]" ;
     }
     std::cerr<<std::endl;
@@ -179,7 +178,7 @@ int parseArgs(int argc, char* argv[]){
         char*v=strtok(NULL, "");
 
         bool found=false;
-        for(int j=0; j<nOptions ;j++){
+        for(int j=0; j<sizeof(qsOptions)/sizeof(qsOptions[0]) ;j++){
             if(!strcmp(qsOptions[j].name, o)){
                 found=true; break;
             }
@@ -196,7 +195,7 @@ int parseArgs(int argc, char* argv[]){
         qsOptionValues[o]=v;
     }
 
-    for(int j=0; j<nOptions ;j++){
+    for(int j=0; j<sizeof(qsOptions)/sizeof(qsOptions[0]) ;j++){
         if(qsOptions[j].required ){
             if(qsOptionValues.find(qsOptions[j].name) == qsOptionValues.end()){
                 std::cerr<< ""<< qsOptions[j].name << " [" <<qsOptions[j].desc 
<<"] " << "is required." << std::endl;
@@ -318,6 +317,7 @@ int main(int argc, char* argv[]) {
         std::string useSystemTrustStore = 
qsOptionValues["useSystemTrustStore"];
         std::string customSSLOptions = qsOptionValues["CustomSSLCtxOptions"];
         std::string supportComplexTypes = 
qsOptionValues["supportComplexTypes"];
+        std::string hostnameOverride = qsOptionValues["hostnameOverride"];
 
         Drill::QueryType type;
 
@@ -426,6 +426,9 @@ int main(int argc, char* argv[]) {
         if (supportComplexTypes.length() > 0){
             props.setProperty(USERPROP_SUPPORT_COMPLEX_TYPES, 
supportComplexTypes);
         }
+        if (hostnameOverride.length() > 0) {
+            props.setProperty(USERPROP_HOSTNAME_OVERRIDE, hostnameOverride);
+        }
 
         if(client.connect(connectStr.c_str(), &props)!=Drill::CONN_SUCCESS){
             std::cerr<< "Failed to connect with error: "<< client.getError() 
<< " (Using:"<<connectStr<<")"<<std::endl;
diff --git a/contrib/native/client/src/clientlib/channel.cpp 
b/contrib/native/client/src/clientlib/channel.cpp
index 5e96388..53c9f0a 100644
--- a/contrib/native/client/src/clientlib/channel.cpp
+++ b/contrib/native/client/src/clientlib/channel.cpp
@@ -210,6 +210,9 @@ ChannelContext* 
ChannelFactory::getChannelContext(channelType_t t, DrillUserProp
                 verifyMode = boost::asio::ssl::context::verify_none;
             }
 
+            std::string hostnameOverride;
+            props->getProp(USERPROP_HOSTNAME_OVERRIDE, hostnameOverride);
+
             long customSSLCtxOptions = 
SSLChannelContext::ApplyMinTLSRestriction(protocol);
             std::string sslOptions;
             props->getProp(USERPROP_CUSTOM_SSLCTXOPTIONS, sslOptions);
@@ -222,7 +225,7 @@ ChannelContext* 
ChannelFactory::getChannelContext(channelType_t t, DrillUserProp
                  }
             }
 
-            pChannelContext = new SSLChannelContext(props, tlsVersion, 
verifyMode, customSSLCtxOptions);
+            pChannelContext = new SSLChannelContext(props, tlsVersion, 
verifyMode, hostnameOverride, customSSLCtxOptions);
         }
             break;
 #endif
@@ -276,20 +279,23 @@ connectionStatus_t Channel::init(){
 }
 
 connectionStatus_t Channel::connect(){
-    connectionStatus_t ret=CONN_FAILURE;
-    if(this->m_state==CHANNEL_INITIALIZED){
-        ret=m_pEndpoint->getDrillbitEndpoint();
-        if(ret==CONN_SUCCESS){
+    connectionStatus_t ret = CONN_FAILURE;
+    if (this->m_state == CHANNEL_INITIALIZED){
+        ret = m_pEndpoint->getDrillbitEndpoint();
+        if (ret == CONN_SUCCESS){
             DRILL_LOG(LOG_TRACE) << "Connecting to drillbit: " 
                 << m_pEndpoint->getHost() 
                 << ":" << m_pEndpoint->getPort() 
                 << "." << std::endl;
-            ret=this->connectInternal();
-        }else{
+            ret = this->setSocketInformation();
+            if (ret == CONN_SUCCESS) {
+                ret = this->connectInternal();
+            }
+        } else {
             handleError(ret, m_pEndpoint->getError()->msg);
         }
     }
-    this->m_state=(ret==CONN_SUCCESS)?CHANNEL_CONNECTED:this->m_state;
+    this->m_state = (ret == CONN_SUCCESS) ? CHANNEL_CONNECTED : this->m_state;
     return ret;
 }
 
diff --git a/contrib/native/client/src/clientlib/channel.hpp 
b/contrib/native/client/src/clientlib/channel.hpp
index 7d4ad60..f7dfe3e 100644
--- a/contrib/native/client/src/clientlib/channel.hpp
+++ b/contrib/native/client/src/clientlib/channel.hpp
@@ -94,7 +94,7 @@ class UserProperties;
             /// @brief Applies Minimum TLS protocol restrictions. 
             ///         tlsv11+ means restrict to TLS version 1.1 and higher.
             ///         tlsv12+ means restrict to TLS version 1.2 and higher.
-            ///  Please note that SSL_OP_NO_TLSv tags are depreecated in 
openSSL 1.1.0.
+            ///  Please note that SSL_OP_NO_TLSv tags are deprecated in 
openSSL 1.1.0.
             /// 
             /// @param in_ver               The protocol version.
             /// 
@@ -113,9 +113,11 @@ class UserProperties;
         SSLChannelContext(DrillUserProperties *props,
                           boost::asio::ssl::context::method tlsVersion,
                           boost::asio::ssl::verify_mode verifyMode,
+                          const std::string& hostnameOverride,
                           const long customSSLCtxOptions = 0) :
                     ChannelContext(props),
                     m_SSLContext(tlsVersion),
+                    m_hostnameOverride(hostnameOverride),
                     m_certHostnameVerificationStatus(true) 
             {
                 m_SSLContext.set_default_verify_paths();
@@ -142,9 +144,17 @@ class UserProperties;
             /// @param in_result                The host name verification 
status.
             void SetCertHostnameVerificationStatus(bool in_result) { 
m_certHostnameVerificationStatus = in_result; }
 
+            /// @brief Returns the overridden hostname used for certificate 
verification
+            ///
+            /// @return the hostname override, or empty if the hostname should 
not be overridden.
+            const std::string& GetHostnameOverride() { return 
m_hostnameOverride; }
+
         private:
             boost::asio::ssl::context m_SSLContext;
 
+            // The hostname to verify. Unused if empty.
+            std::string m_hostnameOverride;
+
             // The flag to indicate the host name verification result.
             bool m_certHostnameVerificationStatus;
     };
@@ -210,6 +220,10 @@ class UserProperties;
                 return handleError(CONN_HANDSHAKE_FAILED, in_err.what());
             }
 
+            virtual connectionStatus_t setSocketInformation() {
+                return CONN_SUCCESS;
+            }
+
             boost::asio::io_service& m_ioService;
             boost::asio::io_service m_ioServiceFallback; // used if 
m_ioService is not provided
             AsioStreamSocket* m_pSocket;
@@ -291,6 +305,21 @@ class UserProperties;
                         getMessage(ERR_CONN_SSL_GENERAL, in_err.what()));
                 }
             }
+
+            connectionStatus_t setSocketInformation() {
+                const char* sniProperty;
+                SSLChannelContext_t& context = *((SSLChannelContext_t 
*)m_pContext);
+                if (!context.GetHostnameOverride().empty()){
+                    sniProperty = context.GetHostnameOverride().c_str();
+                }
+                else{
+                    sniProperty = m_pEndpoint->getHost().c_str();
+                }
+                if (!SSL_set_tlsext_host_name(((SslSocket 
*)m_pSocket)->getSocketStream().native_handle(), sniProperty)) {
+                    return handleError(CONN_SSLERROR, 
getMessage(ERR_CONN_SSL_SNI, sniProperty, 
ERR_func_error_string(ERR_get_error())));
+                }
+                return CONN_SUCCESS;
+            }
 #endif
     };
 
@@ -332,9 +361,16 @@ class UserProperties;
                 // Gets the channel context.
                 SSLChannelContext_t* context = 
(SSLChannelContext_t*)(m_channel->getChannelContext());
 
-                // Retrieve the host before we perform Host name verification.
-                // This is because host with ZK mode is selected after the 
connect() function is called.
-                boost::asio::ssl::rfc2818_verification 
verifier(m_channel->getEndpoint()->getHost().c_str());
+                const char* hostname;
+                if (context->GetHostnameOverride().empty()) {
+                    // Retrieve the host before we perform Host name 
verification.
+                    // This is because host with ZK mode is selected after the 
connect() function is called.
+                    hostname = m_channel->getEndpoint()->getHost().c_str();
+                } else {
+                    hostname = context->GetHostnameOverride().c_str();
+                }
+
+                boost::asio::ssl::rfc2818_verification verifier(hostname);
 
                 // Perform verification.
                 bool verified = verifier(in_preverified, in_ctx);
diff --git a/contrib/native/client/src/clientlib/errmsgs.cpp 
b/contrib/native/client/src/clientlib/errmsgs.cpp
index 5ab8d8e..f3daa4d 100644
--- a/contrib/native/client/src/clientlib/errmsgs.cpp
+++ b/contrib/native/client/src/clientlib/errmsgs.cpp
@@ -61,6 +61,7 @@ static Drill::ErrorMessages errorMessages[]={
     {ERR_CONN_SSL_CN, ERR_CATEGORY_CONN, 0, "SSL certificate host name 
verification failure. [Details: %s]" },
     {ERR_CONN_SSL_CERTVERIFY, ERR_CATEGORY_CONN, 0, "SSL certificate 
verification failed. [Details: %s]"},
     {ERR_CONN_SSL_PROTOVER, ERR_CATEGORY_CONN, 0, "Unsupported TLS protocol 
version. [Details: %s]" },
+    {ERR_CONN_SSL_SNI, ERR_CATEGORY_CONN, 0, "Failed to set TLS SNI. Host: %s 
[Details: %s]"},
     {ERR_QRY_OUTOFMEM, ERR_CATEGORY_QRY, 0, "Out of memory."},
     {ERR_QRY_COMMERR, ERR_CATEGORY_QRY, 0, "Communication error. %s"},
     {ERR_QRY_INVREADLEN, ERR_CATEGORY_QRY, 0, "Internal Error: Received a 
message with an invalid read length."},
diff --git a/contrib/native/client/src/clientlib/errmsgs.hpp 
b/contrib/native/client/src/clientlib/errmsgs.hpp
index 7230611..465adb5 100644
--- a/contrib/native/client/src/clientlib/errmsgs.hpp
+++ b/contrib/native/client/src/clientlib/errmsgs.hpp
@@ -59,7 +59,10 @@ namespace Drill{
 #define ERR_CONN_SSL_CN         DRILL_ERR_START+27
 #define ERR_CONN_SSL_CERTVERIFY DRILL_ERR_START+28
 #define ERR_CONN_SSL_PROTOVER   DRILL_ERR_START+29
-#define ERR_CONN_MAX            DRILL_ERR_START+29
+#define ERR_CONN_SSL_SNI        DRILL_ERR_START+30
+
+// This should be the same as the largest ERR_CONN_* code.
+#define ERR_CONN_MAX            DRILL_ERR_START+30
 
 #define ERR_QRY_OUTOFMEM    ERR_CONN_MAX+1
 #define ERR_QRY_COMMERR     ERR_CONN_MAX+2
@@ -81,6 +84,8 @@ namespace Drill{
 #define ERR_QRY_18          ERR_CONN_MAX+18
 #define ERR_QRY_19          ERR_CONN_MAX+19
 #define ERR_QRY_20          ERR_CONN_MAX+20
+
+// This should be the same as the largest ERR_QRY_* code.
 #define ERR_QRY_MAX         ERR_QRY_20
 
     // Use only Plain Old Data types in this struc. We will declare
diff --git a/contrib/native/client/src/clientlib/userProperties.cpp 
b/contrib/native/client/src/clientlib/userProperties.cpp
index 0ad8af1..d5d96ea 100644
--- a/contrib/native/client/src/clientlib/userProperties.cpp
+++ b/contrib/native/client/src/clientlib/userProperties.cpp
@@ -32,6 +32,7 @@ const std::map<std::string, uint32_t>  
DrillUserProperties::USER_PROPERTIES=boos
     ( USERPROP_USESSL,      USERPROP_FLAGS_BOOLEAN|USERPROP_FLAGS_SSLPROP)
     ( USERPROP_TLSPROTOCOL,      USERPROP_FLAGS_STRING|USERPROP_FLAGS_SSLPROP)
     ( USERPROP_CERTFILEPATH,    
USERPROP_FLAGS_STRING|USERPROP_FLAGS_SSLPROP|USERPROP_FLAGS_FILEPATH)
+    ( USERPROP_HOSTNAME_OVERRIDE,    
USERPROP_FLAGS_STRING|USERPROP_FLAGS_SSLPROP)
     ( USERPROP_DISABLE_HOSTVERIFICATION,    
USERPROP_FLAGS_BOOLEAN|USERPROP_FLAGS_SSLPROP)
     ( USERPROP_DISABLE_CERTVERIFICATION,    
USERPROP_FLAGS_BOOLEAN|USERPROP_FLAGS_SSLPROP)
     ( USERPROP_USESYSTEMTRUSTSTORE,    
USERPROP_FLAGS_BOOLEAN|USERPROP_FLAGS_SSLPROP)
diff --git a/contrib/native/client/src/include/drill/common.hpp 
b/contrib/native/client/src/include/drill/common.hpp
index 9f57446..8bd15f4 100644
--- a/contrib/native/client/src/include/drill/common.hpp
+++ b/contrib/native/client/src/include/drill/common.hpp
@@ -180,6 +180,7 @@ typedef enum{
 // #define USERPROP_CERTPASSWORD "certPassword" // Password for certificate 
file. 
 #define USERPROP_DISABLE_HOSTVERIFICATION "disableHostVerification"
 #define USERPROP_DISABLE_CERTVERIFICATION "disableCertVerification"
+#define USERPROP_HOSTNAME_OVERRIDE "hostnameOverride" //The hostname to verify 
in the SSL Certificate.
 #define USERPROP_USESYSTEMTRUSTSTORE "useSystemTrustStore" //Windows only, use 
the system trust store
 #define USERPROP_IMPERSONATION_TARGET "impersonation_target"
 #define USERPROP_AUTH_MECHANISM "auth"

Reply via email to