diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 7d04d3664e..43fcfc2274 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -131,6 +131,7 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options, #define DefaultTargetSessionAttrs "any" #ifdef USE_SSL #define DefaultSSLMode "prefer" +#define DefaultSSLTermination "server" #else #define DefaultSSLMode "disable" #endif @@ -293,6 +294,11 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "SSL-Mode", "", 12, /* sizeof("verify-full") == 12 */ offsetof(struct pg_conn, sslmode)}, + {"ssltermination", "PGSSLTERMINATION", DefaultSSLMode, NULL, + "SSL-Termination-Mode", "", 6, /* sizeof("server") == 6 */ + offsetof(struct pg_conn, ssltermination)}, + + {"sslcompression", "PGSSLCOMPRESSION", "0", NULL, "SSL-Compression", "", 1, offsetof(struct pg_conn, sslcompression)}, @@ -1278,6 +1284,16 @@ connectOptions2(PGconn *conn) return false; } + if (strcmp(conn->ssltermination, "server") != 0 + && strcmp(conn->ssltermination, "proxy") != 0) + { + conn->status = CONNECTION_BAD; + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("invalid %s value: \"%s\"\n"), + "ssltermination", conn->ssltermination); + return false; + } + #ifndef USE_SSL switch (conn->sslmode[0]) { @@ -2915,6 +2931,13 @@ keep_going: /* We will come back to here until there is if (conn->allow_ssl_try && !conn->wait_ssl_try && !conn->ssl_in_use) { + /* + * SSL termination is handled by proxy/load-balancer, no need to send SSLRequest + */ + if(conn->ssltermination[0]=='p'){ + conn->status = CONNECTION_SSL_STARTUP; + return PGRES_POLLING_WRITING; + } ProtocolVersion pv; /* @@ -2995,77 +3018,89 @@ keep_going: /* We will come back to here until there is if (!conn->ssl_in_use) { /* - * We use pqReadData here since it has the logic to - * distinguish no-data-yet from connection closure. Since - * conn->ssl isn't set, a plain recv() will occur. + * Skip SSLRequest package and initialize ssl directly with proxy */ - char SSLok; - int rdresult; - - rdresult = pqReadData(conn); - if (rdresult < 0) - { - /* errorMessage is already filled in */ - goto error_return; - } - if (rdresult == 0) - { - /* caller failed to wait for data */ - return PGRES_POLLING_READING; - } - if (pqGetc(&SSLok, conn) < 0) - { - /* should not happen really */ - return PGRES_POLLING_READING; - } - if (SSLok == 'S') + if (conn->ssltermination[0]=='p') { /* mark byte consumed */ conn->inStart = conn->inCursor; /* Set up global SSL state if required */ if (pqsecure_initialize(conn) != 0) goto error_return; - } - else if (SSLok == 'N') - { - /* mark byte consumed */ - conn->inStart = conn->inCursor; - /* OK to do without SSL? */ - if (conn->sslmode[0] == 'r' || /* "require" */ - conn->sslmode[0] == 'v') /* "verify-ca" or - * "verify-full" */ + } else { + /* + * We use pqReadData here since it has the logic to + * distinguish no-data-yet from connection closure. Since + * conn->ssl isn't set, a plain recv() will occur. + */ + char SSLok; + int rdresult; + + rdresult = pqReadData(conn); + if (rdresult < 0) { - /* Require SSL, but server does not want it */ - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("server does not support SSL, but SSL was required\n")); + /* errorMessage is already filled in */ + goto error_return; + } + if (rdresult == 0) + { + /* caller failed to wait for data */ + return PGRES_POLLING_READING; + } + if (pqGetc(&SSLok, conn) < 0) + { + /* should not happen really */ + return PGRES_POLLING_READING; + } + if (SSLok == 'S') + { + /* mark byte consumed */ + conn->inStart = conn->inCursor; + /* Set up global SSL state if required */ + if (pqsecure_initialize(conn) != 0) + goto error_return; + } + else if (SSLok == 'N') + { + /* mark byte consumed */ + conn->inStart = conn->inCursor; + /* OK to do without SSL? */ + if (conn->sslmode[0] == 'r' || /* "require" */ + conn->sslmode[0] == 'v') /* "verify-ca" or + * "verify-full" */ + { + /* Require SSL, but server does not want it */ + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("server does not support SSL, but SSL was required\n")); + goto error_return; + } + /* Otherwise, proceed with normal startup */ + conn->allow_ssl_try = false; + conn->status = CONNECTION_MADE; + return PGRES_POLLING_WRITING; + } + else if (SSLok == 'E') + { + /* + * Server failure of some sort, such as failure to + * fork a backend process. We need to process and + * report the error message, which might be formatted + * according to either protocol 2 or protocol 3. + * Rather than duplicate the code for that, we flip + * into AWAITING_RESPONSE state and let the code there + * deal with it. Note we have *not* consumed the "E" + * byte here. + */ + conn->status = CONNECTION_AWAITING_RESPONSE; + goto keep_going; + } + else + { + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("received invalid response to SSL negotiation: %c\n"), + SSLok); goto error_return; } - /* Otherwise, proceed with normal startup */ - conn->allow_ssl_try = false; - conn->status = CONNECTION_MADE; - return PGRES_POLLING_WRITING; - } - else if (SSLok == 'E') - { - /* - * Server failure of some sort, such as failure to - * fork a backend process. We need to process and - * report the error message, which might be formatted - * according to either protocol 2 or protocol 3. - * Rather than duplicate the code for that, we flip - * into AWAITING_RESPONSE state and let the code there - * deal with it. Note we have *not* consumed the "E" - * byte here. - */ - conn->status = CONNECTION_AWAITING_RESPONSE; - goto keep_going; - } - else - { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("received invalid response to SSL negotiation: %c\n"), - SSLok); - goto error_return; } } diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c index d609a38bbe..d05d8a78f4 100644 --- a/src/interfaces/libpq/fe-secure-openssl.c +++ b/src/interfaces/libpq/fe-secure-openssl.c @@ -1044,6 +1044,7 @@ initialize_SSL(PGconn *conn) * it doesn't really matter.) */ if (!(conn->ssl = SSL_new(SSL_context)) || + !SSL_set_tlsext_host_name(conn->ssl, conn->connhost[conn->whichhost].host) || !SSL_set_app_data(conn->ssl, conn) || !my_SSL_set_fd(conn, conn->sock)) { diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 1de91ae295..7f5b03d518 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -356,6 +356,7 @@ struct pg_conn char *keepalives_count; /* maximum number of TCP keepalive * retransmits */ char *sslmode; /* SSL mode (require,prefer,allow,disable) */ + char *ssltermination; /* SSL termination (proxy,server) */ char *sslcompression; /* SSL compression (0 or 1) */ char *sslkey; /* client key filename */ char *sslcert; /* client certificate filename */