refactor: simplify pgsql_servers_ssl_params schema and pre-parse TLS range

- Drop ssl_capath and ssl_cipher columns (no libpq equivalents)
- Pre-parse ssl_protocol_version_range into ssl_min/max_protocol_version
  at construction time instead of on every backend connection
- Fix Servers_SslParams 3-arg delegating constructor
- Update tests, docs, and all consumers (Connection, Monitor, Kill, Admin)
pull/5583/head
Rahim Kanji 2 weeks ago
parent 4b2334e493
commit e68f8bb74a

@ -16,10 +16,8 @@ CREATE TABLE pgsql_servers_ssl_params (
ssl_ca VARCHAR NOT NULL DEFAULT '',
ssl_cert VARCHAR NOT NULL DEFAULT '',
ssl_key VARCHAR NOT NULL DEFAULT '',
ssl_capath VARCHAR NOT NULL DEFAULT '',
ssl_crl VARCHAR NOT NULL DEFAULT '',
ssl_crlpath VARCHAR NOT NULL DEFAULT '',
ssl_cipher VARCHAR NOT NULL DEFAULT '',
ssl_protocol_version_range VARCHAR NOT NULL DEFAULT '',
comment VARCHAR NOT NULL DEFAULT '',
PRIMARY KEY (hostname, port, username)
@ -33,13 +31,11 @@ CREATE TABLE pgsql_servers_ssl_params (
| `hostname` | Backend server hostname. Must match the `hostname` in `pgsql_servers`. |
| `port` | Backend server port. Default: `5432`. Must match the `port` in `pgsql_servers`. |
| `username` | ProxySQL username. Empty string `''` acts as a wildcard fallback (see Lookup Hierarchy). |
| `ssl_ca` | Path to the CA certificate file. Maps to libpq `sslrootcert`. |
| `ssl_ca` | Path to the CA certificate file (PEM). May contain multiple concatenated CA certs. Maps to libpq `sslrootcert`. |
| `ssl_cert` | Path to the client certificate file. Maps to libpq `sslcert`. |
| `ssl_key` | Path to the client private key file. Maps to libpq `sslkey`. |
| `ssl_capath` | Path to directory containing CA certificates. |
| `ssl_crl` | Path to the certificate revocation list file. Maps to libpq `sslcrl`. |
| `ssl_crlpath` | Path to directory containing CRL files. Maps to libpq `sslcrldir` (PostgreSQL 14+). |
| `ssl_cipher` | SSL cipher specification. |
| `ssl_protocol_version_range` | TLS protocol version constraint. See format below. |
| `comment` | Free-form comment. |
@ -86,6 +82,8 @@ When ProxySQL opens a new connection to a PostgreSQL backend, it looks up SSL pa
This allows you to set a default SSL configuration for a server (empty username) while overriding it for specific users.
> **Important — matching is all-or-nothing.** Once a row in `pgsql_servers_ssl_params` matches (either at step 1 or step 2), ProxySQL uses **only** the SSL fields from that row. Empty columns in the matched row are passed through as empty (libpq defaults), they are **not** silently filled in from `pgsql-ssl_p2s_*`. The global variables are consulted **only** when no row matches at all (step 3). If you want a per-server row to inherit some defaults from the globals, you must copy those values into the row explicitly.
## Usage
### Basic: Same SSL cert for all users connecting to a server
@ -190,4 +188,4 @@ If `use_ssl=0`, the backend connection does not use SSL regardless of `pgsql_ser
- Empty fields in `pgsql_servers_ssl_params` are omitted from the libpq connection string (libpq defaults apply for those fields).
- Per-server SSL params only affect **new** backend connections. Existing pooled connections continue using their original SSL settings. Use the `/* create_new_connection=1 */` query annotation to force ProxySQL to create a new backend connection.
- The `ssl_cipher` column is reserved for future use. libpq does not expose a direct connection string parameter for cipher selection.
- Per-server SSL params apply on the data path (`PgSQL_Connection`), the monitor path (`PgSQL_Monitor`), and the cancel/terminate path (`PgSQL_Backend_Kill_Args`).

@ -61,7 +61,7 @@ enum PgSQL_Param_Name {
PG_SSLROOTCERT, // Specifies the name of a file containing SSL certificate authority (CA) certificate(s)
PG_SSLCRL, // Specifies the file name of the SSL server certificate revocation list (CRL)
PG_SSLCRLDIR, // Specifies the directory name of the SSL server certificate revocation list (CRL)
PG_SSLSNI, // Sets the TLS extension Server Name Indication (SNI) on SSL-enabled connections
PG_SSLSNI, // Sets the TLS extension Server Name Indication (SNI) on SSL-enabled connections
PG_REQUIREPEER, // Specifies the operating-system user name of the server
PG_SSL_MIN_PROTOCOL_VERSION, // Specifies the minimum SSL/TLS protocol version to allow for the connection
PG_SSL_MAX_PROTOCOL_VERSION, // Specifies the maximum SSL/TLS protocol version to allow for the connection
@ -729,6 +729,8 @@ public:
char* sslrootcert;
char* sslcrl;
char* sslcrldir;
char* ssl_min_protocol_version;
char* ssl_max_protocol_version;
} ssl_config;
PgSQL_Backend_Kill_Args(PGconn* conn, const char* user, const char* pass, const char* db, const char* host,

@ -46,7 +46,7 @@
#define MYHGM_PgSQL_SERVERS "CREATE TABLE pgsql_servers ( hostgroup_id INT NOT NULL DEFAULT 0 , hostname VARCHAR NOT NULL , port INT NOT NULL DEFAULT 5432 , weight INT NOT NULL DEFAULT 1 , status INT NOT NULL DEFAULT 0 , compression INT NOT NULL DEFAULT 0 , max_connections INT NOT NULL DEFAULT 1000 , max_replication_lag INT NOT NULL DEFAULT 0 , use_ssl INT NOT NULL DEFAULT 0 , max_latency_ms INT UNSIGNED NOT NULL DEFAULT 0 , comment VARCHAR NOT NULL DEFAULT '' , mem_pointer INT NOT NULL DEFAULT 0 , PRIMARY KEY (hostgroup_id, hostname, port) )"
#define MYHGM_PgSQL_SERVERS_INCOMING "CREATE TABLE pgsql_servers_incoming ( hostgroup_id INT NOT NULL DEFAULT 0 , hostname VARCHAR NOT NULL , port INT NOT NULL DEFAULT 5432 , weight INT NOT NULL DEFAULT 1 , status INT NOT NULL DEFAULT 0 , compression INT NOT NULL DEFAULT 0 , max_connections INT NOT NULL DEFAULT 1000 , max_replication_lag INT NOT NULL DEFAULT 0 , use_ssl INT NOT NULL DEFAULT 0 , max_latency_ms INT UNSIGNED NOT NULL DEFAULT 0 , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostgroup_id, hostname, port))"
#endif /* DEBUG */
#define MYHGM_PgSQL_SERVERS_SSL_PARAMS "CREATE TABLE pgsql_servers_ssl_params (hostname VARCHAR NOT NULL , port INT CHECK (port >= 0 AND port <= 65535) NOT NULL DEFAULT 5432 , username VARCHAR NOT NULL DEFAULT '' , ssl_ca VARCHAR NOT NULL DEFAULT '' , ssl_cert VARCHAR NOT NULL DEFAULT '' , ssl_key VARCHAR NOT NULL DEFAULT '' , ssl_capath VARCHAR NOT NULL DEFAULT '' , ssl_crl VARCHAR NOT NULL DEFAULT '' , ssl_crlpath VARCHAR NOT NULL DEFAULT '' , ssl_cipher VARCHAR NOT NULL DEFAULT '' , ssl_protocol_version_range VARCHAR NOT NULL DEFAULT '' , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostname, port, username) )"
#define MYHGM_PgSQL_SERVERS_SSL_PARAMS "CREATE TABLE pgsql_servers_ssl_params (hostname VARCHAR NOT NULL , port INT CHECK (port >= 0 AND port <= 65535) NOT NULL DEFAULT 5432 , username VARCHAR NOT NULL DEFAULT '' , ssl_ca VARCHAR NOT NULL DEFAULT '' , ssl_cert VARCHAR NOT NULL DEFAULT '' , ssl_key VARCHAR NOT NULL DEFAULT '' , ssl_crl VARCHAR NOT NULL DEFAULT '' , ssl_crlpath VARCHAR NOT NULL DEFAULT '' , ssl_protocol_version_range VARCHAR NOT NULL DEFAULT '' , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostname, port, username) )"
#define MYHGM_PgSQL_REPLICATION_HOSTGROUPS "CREATE TABLE pgsql_replication_hostgroups (writer_hostgroup INT CHECK (writer_hostgroup>=0) NOT NULL PRIMARY KEY , reader_hostgroup INT NOT NULL CHECK (reader_hostgroup<>writer_hostgroup AND reader_hostgroup>=0) , check_type VARCHAR CHECK (LOWER(check_type) IN ('read_only')) NOT NULL DEFAULT 'read_only' , comment VARCHAR NOT NULL DEFAULT '' , UNIQUE (reader_hostgroup))"
#define PGHGM_GEN_ADMIN_RUNTIME_SERVERS "SELECT hostgroup_id, hostname, port, CASE status WHEN 0 THEN \"ONLINE\" WHEN 1 THEN \"SHUNNED\" WHEN 2 THEN \"OFFLINE_SOFT\" WHEN 3 THEN \"OFFLINE_HARD\" WHEN 4 THEN \"SHUNNED\" END status, weight, compression, max_connections, max_replication_lag, use_ssl, max_latency_ms, comment FROM pgsql_servers ORDER BY hostgroup_id, hostname, port"
@ -404,6 +404,7 @@ class PgSQL_HostGroups_Manager : public Base_HostGroups_Manager<PgSQL_HGC> {
PgSQL_GALERA_HOSTGROUPS,
PgSQL_AWS_AURORA_HOSTGROUPS,
PgSQL_HOSTGROUP_ATTRIBUTES,
PgSQL_SERVERS_SSL_PARAMS,
PgSQL_SERVERS,
__HGM_TABLES_SIZE

@ -315,9 +315,9 @@
#define ADMIN_SQLITE_TABLE_RUNTIME_PGSQL_SERVERS "CREATE TABLE runtime_pgsql_servers (hostgroup_id INT CHECK (hostgroup_id>=0) NOT NULL DEFAULT 0 , hostname VARCHAR NOT NULL , port INT CHECK (port >= 0 AND port <= 65535) NOT NULL DEFAULT 5432 , status VARCHAR CHECK (UPPER(status) IN ('ONLINE','SHUNNED','OFFLINE_SOFT', 'OFFLINE_HARD')) NOT NULL DEFAULT 'ONLINE' , weight INT CHECK (weight >= 0 AND weight <=10000000) NOT NULL DEFAULT 1 , compression INT CHECK (compression IN(0,1)) NOT NULL DEFAULT 0 , max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 1000 , max_replication_lag INT CHECK (max_replication_lag >= 0 AND max_replication_lag <= 126144000) NOT NULL DEFAULT 0 , use_ssl INT CHECK (use_ssl IN(0,1)) NOT NULL DEFAULT 0 , max_latency_ms INT UNSIGNED CHECK (max_latency_ms>=0) NOT NULL DEFAULT 0 , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostgroup_id, hostname, port) )"
#define ADMIN_SQLITE_TABLE_PGSQL_SERVERS_SSL_PARAMS "CREATE TABLE pgsql_servers_ssl_params (hostname VARCHAR NOT NULL , port INT CHECK (port >= 0 AND port <= 65535) NOT NULL DEFAULT 5432 , username VARCHAR NOT NULL DEFAULT '' , ssl_ca VARCHAR NOT NULL DEFAULT '' , ssl_cert VARCHAR NOT NULL DEFAULT '' , ssl_key VARCHAR NOT NULL DEFAULT '' , ssl_capath VARCHAR NOT NULL DEFAULT '' , ssl_crl VARCHAR NOT NULL DEFAULT '' , ssl_crlpath VARCHAR NOT NULL DEFAULT '' , ssl_cipher VARCHAR NOT NULL DEFAULT '' , ssl_protocol_version_range VARCHAR NOT NULL DEFAULT '' , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostname, port, username) )"
#define ADMIN_SQLITE_TABLE_PGSQL_SERVERS_SSL_PARAMS "CREATE TABLE pgsql_servers_ssl_params (hostname VARCHAR NOT NULL , port INT CHECK (port >= 0 AND port <= 65535) NOT NULL DEFAULT 5432 , username VARCHAR NOT NULL DEFAULT '' , ssl_ca VARCHAR NOT NULL DEFAULT '' , ssl_cert VARCHAR NOT NULL DEFAULT '' , ssl_key VARCHAR NOT NULL DEFAULT '' , ssl_crl VARCHAR NOT NULL DEFAULT '' , ssl_crlpath VARCHAR NOT NULL DEFAULT '' , ssl_protocol_version_range VARCHAR NOT NULL DEFAULT '' , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostname, port, username) )"
#define ADMIN_SQLITE_TABLE_RUNTIME_PGSQL_SERVERS_SSL_PARAMS "CREATE TABLE runtime_pgsql_servers_ssl_params (hostname VARCHAR NOT NULL , port INT CHECK (port >= 0 AND port <= 65535) NOT NULL DEFAULT 5432 , username VARCHAR NOT NULL DEFAULT '' , ssl_ca VARCHAR NOT NULL DEFAULT '' , ssl_cert VARCHAR NOT NULL DEFAULT '' , ssl_key VARCHAR NOT NULL DEFAULT '' , ssl_capath VARCHAR NOT NULL DEFAULT '' , ssl_crl VARCHAR NOT NULL DEFAULT '' , ssl_crlpath VARCHAR NOT NULL DEFAULT '' , ssl_cipher VARCHAR NOT NULL DEFAULT '' , ssl_protocol_version_range VARCHAR NOT NULL DEFAULT '' , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostname, port, username) )"
#define ADMIN_SQLITE_TABLE_RUNTIME_PGSQL_SERVERS_SSL_PARAMS "CREATE TABLE runtime_pgsql_servers_ssl_params (hostname VARCHAR NOT NULL , port INT CHECK (port >= 0 AND port <= 65535) NOT NULL DEFAULT 5432 , username VARCHAR NOT NULL DEFAULT '' , ssl_ca VARCHAR NOT NULL DEFAULT '' , ssl_cert VARCHAR NOT NULL DEFAULT '' , ssl_key VARCHAR NOT NULL DEFAULT '' , ssl_crl VARCHAR NOT NULL DEFAULT '' , ssl_crlpath VARCHAR NOT NULL DEFAULT '' , ssl_protocol_version_range VARCHAR NOT NULL DEFAULT '' , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostname, port, username) )"
#define ADMIN_SQLITE_TABLE_RUNTIME_PGSQL_USERS "CREATE TABLE runtime_pgsql_users (username VARCHAR NOT NULL , password VARCHAR , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1 , use_ssl INT CHECK (use_ssl IN (0,1)) NOT NULL DEFAULT 0 , default_hostgroup INT NOT NULL DEFAULT 0 , transaction_persistent INT CHECK (transaction_persistent IN (0,1)) NOT NULL DEFAULT 1 , fast_forward INT CHECK (fast_forward IN (0,1)) NOT NULL DEFAULT 0 , backend INT CHECK (backend IN (0,1)) NOT NULL DEFAULT 1 , frontend INT CHECK (frontend IN (0,1)) NOT NULL DEFAULT 1 , max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 10000 , attributes VARCHAR CHECK (JSON_VALID(attributes) OR attributes = '') NOT NULL DEFAULT '', comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (username, backend) , UNIQUE (username, frontend))"
#define ADMIN_SQLITE_TABLE_RUNTIME_PGSQL_LDAP_MAPPING "CREATE TABLE runtime_pgsql_ldap_mapping (priority INTEGER PRIMARY KEY NOT NULL , frontend_entity VARCHAR NOT NULL , backend_entity VARCHAR NOT NULL , comment VARCHAR NOT NULL DEFAULT '' , UNIQUE (frontend_entity))"

@ -57,9 +57,8 @@ class Servers_SslParams {
comment = string(c);
MapKey = "";
}
Servers_SslParams(string _h, int _p, string _u) {
Servers_SslParams(_h, _p, _u, "", "", "", "", "", "", "", "", "");
}
Servers_SslParams(string _h, int _p, string _u)
: Servers_SslParams(_h, _p, _u, "", "", "", "", "", "", "", "", "") {}
virtual ~Servers_SslParams() = default;
string getMapKey(const char *del) {
if (MapKey == "") {
@ -76,7 +75,51 @@ class MySQLServers_SslParams : public Servers_SslParams {
class PgSQLServers_SslParams : public Servers_SslParams {
public:
using Servers_SslParams::Servers_SslParams;
// Pre-parsed from tls_version (= the SQL column ssl_protocol_version_range).
// Populated once at construction so the data path does not have to re-parse
// the range string on every backend connection. Empty when tls_version is
// empty or malformed (in which case libpq defaults apply).
string ssl_min_protocol_version;
string ssl_max_protocol_version;
// PgSQL-specific constructors. libpq has no equivalent for the base class
// ssl_capath / ssl_cipher fields, so they are not exposed here — the base
// class members are forwarded as empty strings and stay unused on the
// PgSQL backend path.
PgSQLServers_SslParams(string _h, int _p, string _u,
string ca, string cert, string key,
string crl, string crlpath, string tls, string c)
: Servers_SslParams(_h, _p, _u, ca, cert, key, "", crl, crlpath, "", tls, c) {
parse_tls_version();
}
PgSQLServers_SslParams(char * _h, int _p, char * _u,
char * ca, char * cert, char * key,
char * crl, char * crlpath, char * tls, char * c)
: Servers_SslParams(_h, _p, _u, ca, cert, key, (char*)"", crl, crlpath, (char*)"", tls, c) {
parse_tls_version();
}
PgSQLServers_SslParams(string _h, int _p, string _u)
: Servers_SslParams(_h, _p, _u) {}
private:
// Parse tls_version into ssl_min_protocol_version / ssl_max_protocol_version.
// Format: "MIN-MAX" for a range, or a single token to pin both ends.
// Empty or malformed values leave both fields empty.
void parse_tls_version() {
if (tls_version.empty()) return;
size_t dash_pos = tls_version.find('-');
if (dash_pos == string::npos) {
ssl_min_protocol_version = tls_version;
ssl_max_protocol_version = tls_version;
return;
}
string min_ver = tls_version.substr(0, dash_pos);
string max_ver = tls_version.substr(dash_pos + 1);
if (!min_ver.empty() && !max_ver.empty()) {
ssl_min_protocol_version = min_ver;
ssl_max_protocol_version = max_ver;
}
}
};
#endif // __CLASS_SERVERS_SSL_PARAMS_H

@ -979,21 +979,13 @@ void PgSQL_Connection::connect_start() {
append_conninfo_param(conninfo, "sslcrl", (char*)ssl_params->ssl_crl.c_str());
if (ssl_params->ssl_crlpath.length() > 0)
append_conninfo_param(conninfo, "sslcrldir", (char*)ssl_params->ssl_crlpath.c_str());
// Parse ssl_protocol_version_range (format: "TLSv1.2-TLSv1.3" or "TLSv1.3")
if (ssl_params->tls_version.length() > 0) {
string tls_ver = ssl_params->tls_version;
size_t dash_pos = tls_ver.find('-');
if (dash_pos != string::npos) {
string min_ver = tls_ver.substr(0, dash_pos);
string max_ver = tls_ver.substr(dash_pos + 1);
append_conninfo_param(conninfo, "ssl_min_protocol_version", (char*)min_ver.c_str());
append_conninfo_param(conninfo, "ssl_max_protocol_version", (char*)max_ver.c_str());
} else {
// Single version = pin to that version
append_conninfo_param(conninfo, "ssl_min_protocol_version", (char*)tls_ver.c_str());
append_conninfo_param(conninfo, "ssl_max_protocol_version", (char*)tls_ver.c_str());
}
}
// ssl_protocol_version_range was pre-parsed at PgSQLServers_SslParams
// construction time (see parse_tls_version()). Empty min/max means
// either unset or malformed — in both cases libpq defaults apply.
if (ssl_params->ssl_min_protocol_version.length() > 0)
append_conninfo_param(conninfo, "ssl_min_protocol_version", (char*)ssl_params->ssl_min_protocol_version.c_str());
if (ssl_params->ssl_max_protocol_version.length() > 0)
append_conninfo_param(conninfo, "ssl_max_protocol_version", (char*)ssl_params->ssl_max_protocol_version.c_str());
} else {
// Fall back to global SSL settings
append_conninfo_param(conninfo, "sslkey", pgsql_thread___ssl_p2s_key);
@ -2972,36 +2964,25 @@ PgSQL_Backend_Kill_Args::PgSQL_Backend_Kill_Args(PGconn* conn, const char* user,
backend_pid = PQbackendPID(conn);
ssl_config.use_ssl = ssl;
if (ssl) {
ssl_config.sslkey = pgsql_thread___ssl_p2s_key ? strdup(pgsql_thread___ssl_p2s_key) : nullptr;
ssl_config.sslcert = pgsql_thread___ssl_p2s_cert ? strdup(pgsql_thread___ssl_p2s_cert) : nullptr;
ssl_config.sslrootcert = pgsql_thread___ssl_p2s_ca ? strdup(pgsql_thread___ssl_p2s_ca) : nullptr;
ssl_config.sslcrl = pgsql_thread___ssl_p2s_crl ? strdup(pgsql_thread___ssl_p2s_crl) : nullptr;
ssl_config.sslcrldir = pgsql_thread___ssl_p2s_crlpath ? strdup(pgsql_thread___ssl_p2s_crlpath) : nullptr;
// Override with per-server SSL params if available
std::unique_ptr<PgSQLServers_SslParams> params {
PgHGM->get_Server_SSL_Params(hostname, port, username)
};
if (params != nullptr) {
if (params->ssl_key.length() > 0) {
free(ssl_config.sslkey);
ssl_config.sslkey = strdup(params->ssl_key.c_str());
}
if (params->ssl_cert.length() > 0) {
free(ssl_config.sslcert);
ssl_config.sslcert = strdup(params->ssl_cert.c_str());
}
if (params->ssl_ca.length() > 0) {
free(ssl_config.sslrootcert);
ssl_config.sslrootcert = strdup(params->ssl_ca.c_str());
}
if (params->ssl_crl.length() > 0) {
free(ssl_config.sslcrl);
ssl_config.sslcrl = strdup(params->ssl_crl.c_str());
}
if (params->ssl_crlpath.length() > 0) {
free(ssl_config.sslcrldir);
ssl_config.sslcrldir = strdup(params->ssl_crlpath.c_str());
}
ssl_config.sslkey = params->ssl_key.length() > 0 ? strdup(params->ssl_key.c_str()) : nullptr;
ssl_config.sslcert = params->ssl_cert.length() > 0 ? strdup(params->ssl_cert.c_str()) : nullptr;
ssl_config.sslrootcert = params->ssl_ca.length() > 0 ? strdup(params->ssl_ca.c_str()) : nullptr;
ssl_config.sslcrl = params->ssl_crl.length() > 0 ? strdup(params->ssl_crl.c_str()) : nullptr;
ssl_config.sslcrldir = params->ssl_crlpath.length() > 0 ? strdup(params->ssl_crlpath.c_str()) : nullptr;
ssl_config.ssl_min_protocol_version = params->ssl_min_protocol_version.length() > 0 ? strdup(params->ssl_min_protocol_version.c_str()) : nullptr;
ssl_config.ssl_max_protocol_version = params->ssl_max_protocol_version.length() > 0 ? strdup(params->ssl_max_protocol_version.c_str()) : nullptr;
} else {
ssl_config.sslkey = pgsql_thread___ssl_p2s_key ? strdup(pgsql_thread___ssl_p2s_key) : nullptr;
ssl_config.sslcert = pgsql_thread___ssl_p2s_cert ? strdup(pgsql_thread___ssl_p2s_cert) : nullptr;
ssl_config.sslrootcert = pgsql_thread___ssl_p2s_ca ? strdup(pgsql_thread___ssl_p2s_ca) : nullptr;
ssl_config.sslcrl = pgsql_thread___ssl_p2s_crl ? strdup(pgsql_thread___ssl_p2s_crl) : nullptr;
ssl_config.sslcrldir = pgsql_thread___ssl_p2s_crlpath ? strdup(pgsql_thread___ssl_p2s_crlpath) : nullptr;
ssl_config.ssl_min_protocol_version = nullptr;
ssl_config.ssl_max_protocol_version = nullptr;
}
} else {
ssl_config.sslkey = nullptr;
@ -3009,6 +2990,8 @@ PgSQL_Backend_Kill_Args::PgSQL_Backend_Kill_Args(PGconn* conn, const char* user,
ssl_config.sslrootcert = nullptr;
ssl_config.sslcrl = nullptr;
ssl_config.sslcrldir = nullptr;
ssl_config.ssl_min_protocol_version = nullptr;
ssl_config.ssl_max_protocol_version = nullptr;
}
}
@ -3022,7 +3005,9 @@ PgSQL_Backend_Kill_Args::~PgSQL_Backend_Kill_Args() {
free(ssl_config.sslrootcert);
free(ssl_config.sslcrl);
free(ssl_config.sslcrldir);
if (cancel_conn)
free(ssl_config.ssl_min_protocol_version);
free(ssl_config.ssl_max_protocol_version);
if (cancel_conn)
PQfreeCancel(cancel_conn);
}
@ -3068,6 +3053,10 @@ void* PgSQL_backend_kill_thread(void* arg) {
append_conninfo_param(conninfo, "sslrootcert", backend_kill_args->ssl_config.sslrootcert);
append_conninfo_param(conninfo, "sslcrl", backend_kill_args->ssl_config.sslcrl);
append_conninfo_param(conninfo, "sslcrldir", backend_kill_args->ssl_config.sslcrldir);
// Per-server TLS protocol pinning was pre-parsed from
// ssl_protocol_version_range when the Kill_Args struct was built.
append_conninfo_param(conninfo, "ssl_min_protocol_version", backend_kill_args->ssl_config.ssl_min_protocol_version);
append_conninfo_param(conninfo, "ssl_max_protocol_version", backend_kill_args->ssl_config.ssl_max_protocol_version);
} else {
conninfo << "sslmode='disable' "; // not supporting SSL
}

@ -1051,6 +1051,7 @@ void PgSQL_HostGroups_Manager::commit_update_checksums_from_tables(SpookyHash& m
CUCFT1(myhash,init,"pgsql_replication_hostgroups","writer_hostgroup", table_resultset_checksum[HGM_TABLES::PgSQL_REPLICATION_HOSTGROUPS]);
CUCFT1(myhash,init,"pgsql_hostgroup_attributes","hostgroup_id", table_resultset_checksum[HGM_TABLES::PgSQL_HOSTGROUP_ATTRIBUTES]);
CUCFT1(myhash,init,"pgsql_servers_ssl_params","hostname,port,username", table_resultset_checksum[HGM_TABLES::PgSQL_SERVERS_SSL_PARAMS]);
}
/**
@ -1848,7 +1849,7 @@ SQLite3_result * PgSQL_HostGroups_Manager::dump_table_pgsql(const string& name)
} else if (name == "cluster_pgsql_servers") {
query = (char *)PGHGM_GEN_CLUSTER_ADMIN_RUNTIME_SERVERS;
} else if (name == "pgsql_servers_ssl_params") {
query=(char *)"SELECT hostname, port, username, ssl_ca, ssl_cert, ssl_key, ssl_capath, ssl_crl, ssl_crlpath, ssl_cipher, ssl_protocol_version_range, comment FROM pgsql_servers_ssl_params ORDER BY hostname, port, username";
query=(char *)"SELECT hostname, port, username, ssl_ca, ssl_cert, ssl_key, ssl_crl, ssl_crlpath, ssl_protocol_version_range, comment FROM pgsql_servers_ssl_params ORDER BY hostname, port, username";
} else {
assert(0);
}
@ -3977,9 +3978,9 @@ void PgSQL_HostGroups_Manager::generate_pgsql_servers_ssl_params_table() {
int rc;
const char * query = (const char *)"INSERT INTO pgsql_servers_ssl_params ("
"hostname, port, username, ssl_ca, ssl_cert, ssl_key, ssl_capath, "
"ssl_crl, ssl_crlpath, ssl_cipher, ssl_protocol_version_range, comment) VALUES "
"(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)";
"hostname, port, username, ssl_ca, ssl_cert, ssl_key, "
"ssl_crl, ssl_crlpath, ssl_protocol_version_range, comment) VALUES "
"(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)";
auto [rc1, statement_unique] = mydb->prepare_v2(query);
ASSERT_SQLITE_OK(rc1, mydb);
@ -4000,12 +4001,10 @@ void PgSQL_HostGroups_Manager::generate_pgsql_servers_ssl_params_table() {
rc=(*proxy_sqlite3_bind_text)(statement, 4, r->fields[3] , -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, mydb); // ssl_ca
rc=(*proxy_sqlite3_bind_text)(statement, 5, r->fields[4] , -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, mydb); // ssl_cert
rc=(*proxy_sqlite3_bind_text)(statement, 6, r->fields[5] , -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, mydb); // ssl_key
rc=(*proxy_sqlite3_bind_text)(statement, 7, r->fields[6] , -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, mydb); // ssl_capath
rc=(*proxy_sqlite3_bind_text)(statement, 8, r->fields[7] , -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, mydb); // ssl_crl
rc=(*proxy_sqlite3_bind_text)(statement, 9, r->fields[8] , -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, mydb); // ssl_crlpath
rc=(*proxy_sqlite3_bind_text)(statement, 10, r->fields[9] , -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, mydb); // ssl_cipher
rc=(*proxy_sqlite3_bind_text)(statement, 11, r->fields[10] , -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, mydb); // ssl_protocol_version_range
rc=(*proxy_sqlite3_bind_text)(statement, 12, r->fields[11] , -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, mydb); // comment
rc=(*proxy_sqlite3_bind_text)(statement, 7, r->fields[6] , -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, mydb); // ssl_crl
rc=(*proxy_sqlite3_bind_text)(statement, 8, r->fields[7] , -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, mydb); // ssl_crlpath
rc=(*proxy_sqlite3_bind_text)(statement, 9, r->fields[8] , -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, mydb); // ssl_protocol_version_range
rc=(*proxy_sqlite3_bind_text)(statement, 10, r->fields[9] , -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, mydb); // comment
SAFE_SQLITE3_STEP2(statement);
rc=(*proxy_sqlite3_clear_bindings)(statement); ASSERT_SQLITE_OK(rc, mydb);
@ -4013,9 +4012,9 @@ void PgSQL_HostGroups_Manager::generate_pgsql_servers_ssl_params_table() {
PgSQLServers_SslParams PSSP(
r->fields[0], atoi(r->fields[1]), r->fields[2],
r->fields[3], r->fields[4], r->fields[5],
r->fields[6], r->fields[7], r->fields[8],
r->fields[9], r->fields[10], r->fields[11]
r->fields[3], r->fields[4], r->fields[5],
r->fields[6], r->fields[7],
r->fields[8], r->fields[9]
);
string MapKey = PSSP.getMapKey(rand_del);
PgSQL_Servers_SSL_Params_map.emplace(MapKey, PSSP);

@ -301,6 +301,9 @@ struct mon_srv_t {
string ssl_p2s_ca;
string ssl_p2s_crl;
string ssl_p2s_crlpath;
// Pre-parsed from ssl_protocol_version_range; empty when unset/malformed.
string ssl_min_protocol_version;
string ssl_max_protocol_version;
} ssl_opt;
};
@ -456,7 +459,9 @@ vector<mon_srv_t> ext_srvs(const unique_ptr<SQLite3_result>& srvs_info) {
ssl_params->ssl_cert,
ssl_params->ssl_ca,
ssl_params->ssl_crl,
ssl_params->ssl_crlpath
ssl_params->ssl_crlpath,
ssl_params->ssl_min_protocol_version,
ssl_params->ssl_max_protocol_version
};
}
}
@ -465,7 +470,9 @@ vector<mon_srv_t> ext_srvs(const unique_ptr<SQLite3_result>& srvs_info) {
string { pgsql_thread___ssl_p2s_cert ? pgsql_thread___ssl_p2s_cert : "" },
string { pgsql_thread___ssl_p2s_ca ? pgsql_thread___ssl_p2s_ca : "" },
string { pgsql_thread___ssl_p2s_crl ? pgsql_thread___ssl_p2s_crl : "" },
string { pgsql_thread___ssl_p2s_crlpath ? pgsql_thread___ssl_p2s_crlpath : ""}
string { pgsql_thread___ssl_p2s_crlpath ? pgsql_thread___ssl_p2s_crlpath : ""},
string { "" },
string { "" }
};
}()
});
@ -1103,6 +1110,13 @@ string build_conn_str(const task_st_t& task_st) {
append_conninfo_param(conninfo, "sslrootcert", srv_info.ssl_opt.ssl_p2s_ca);
append_conninfo_param(conninfo, "sslcrl", srv_info.ssl_opt.ssl_p2s_crl);
append_conninfo_param(conninfo, "sslcrldir", srv_info.ssl_opt.ssl_p2s_crlpath);
// Per-server TLS protocol pinning was pre-parsed from
// ssl_protocol_version_range when the row was loaded into
// PgSQLServers_SslParams. Empty fields => libpq defaults.
if (!srv_info.ssl_opt.ssl_min_protocol_version.empty())
append_conninfo_param(conninfo, "ssl_min_protocol_version", srv_info.ssl_opt.ssl_min_protocol_version);
if (!srv_info.ssl_opt.ssl_max_protocol_version.empty())
append_conninfo_param(conninfo, "ssl_max_protocol_version", srv_info.ssl_opt.ssl_max_protocol_version);
} else {
conninfo << "sslmode='disable' "; // not supporting SSL
}

@ -7730,7 +7730,7 @@ void ProxySQL_Admin::save_pgsql_servers_runtime_to_database(bool _runtime) {
StrQuery = "INSERT INTO ";
if (_runtime)
StrQuery += "runtime_";
StrQuery += "pgsql_servers_ssl_params (hostname, port, username, ssl_ca, ssl_cert, ssl_key, ssl_capath, ssl_crl, ssl_crlpath, ssl_cipher, ssl_protocol_version_range, comment) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)";
StrQuery += "pgsql_servers_ssl_params (hostname, port, username, ssl_ca, ssl_cert, ssl_key, ssl_crl, ssl_crlpath, ssl_protocol_version_range, comment) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)";
auto [rc1, statement_unique] = admindb->prepare_v2(StrQuery.c_str());
rc = rc1;
statement = statement_unique.get();
@ -7744,12 +7744,10 @@ void ProxySQL_Admin::save_pgsql_servers_runtime_to_database(bool _runtime) {
rc=(*proxy_sqlite3_bind_text)(statement, 4, r->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_ca
rc=(*proxy_sqlite3_bind_text)(statement, 5, r->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_cert
rc=(*proxy_sqlite3_bind_text)(statement, 6, r->fields[5], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_key
rc=(*proxy_sqlite3_bind_text)(statement, 7, r->fields[6], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_capath
rc=(*proxy_sqlite3_bind_text)(statement, 8, r->fields[7], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_crl
rc=(*proxy_sqlite3_bind_text)(statement, 9, r->fields[8], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_crlpath
rc=(*proxy_sqlite3_bind_text)(statement, 10, r->fields[9], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_cipher
rc=(*proxy_sqlite3_bind_text)(statement, 11, r->fields[10], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_protocol_version_range
rc=(*proxy_sqlite3_bind_text)(statement, 12, r->fields[11], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // comment
rc=(*proxy_sqlite3_bind_text)(statement, 7, r->fields[6], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_crl
rc=(*proxy_sqlite3_bind_text)(statement, 8, r->fields[7], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_crlpath
rc=(*proxy_sqlite3_bind_text)(statement, 9, r->fields[8], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_protocol_version_range
rc=(*proxy_sqlite3_bind_text)(statement, 10, r->fields[9], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // comment
SAFE_SQLITE3_STEP2(statement);
rc=(*proxy_sqlite3_clear_bindings)(statement); ASSERT_SQLITE_OK(rc, admindb);

@ -151,10 +151,10 @@ static void test_insert_and_select(PGconn* admin) {
ok(exec_ok(admin,
"INSERT INTO pgsql_servers_ssl_params "
"(hostname, port, username, ssl_ca, ssl_cert, ssl_key, ssl_capath, "
"ssl_crl, ssl_crlpath, ssl_cipher, ssl_protocol_version_range, comment) "
"(hostname, port, username, ssl_ca, ssl_cert, ssl_key, "
"ssl_crl, ssl_crlpath, ssl_protocol_version_range, comment) "
"VALUES ('testhost', 5432, 'testuser', '/ca.crt', '/cert.crt', '/key.pem', "
"'/capath', '/crl.pem', '/crlpath', 'AES256', 'TLSv1.2-TLSv1.3', 'test row')"),
"'/crl.pem', '/crlpath', 'TLSv1.2-TLSv1.3', 'test row')"),
"INSERT into pgsql_servers_ssl_params succeeds");
int count = exec_count(admin, "SELECT * FROM pgsql_servers_ssl_params");
@ -438,7 +438,71 @@ static void test_monitor_ssl_with_per_server_params(PGconn* admin) {
diag("After PgSQL_Monitor_ssl_connections_OK: %ld", after_ssl);
ok(after_ssl > initial_ssl,
"Monitor SSL counter increased with use_ssl=1");
"Monitor SSL counter increased with use_ssl=1 and no per-server row");
}
/**
* @brief Verify the monitor path actually consults pgsql_servers_ssl_params.
*
* Inserts a per-server row matching the actual backend with username=''
* (so the monitor's empty-username fallback in get_Server_SSL_Params hits
* it) and an ssl_protocol_version_range pinned to TLSv1 disabled in
* modern PostgreSQL builds. If the monitor honors per-server params and
* propagates tls_version into its libpq conninfo, monitor SSL connections
* must fail and the OK counter must NOT advance over the wait window.
* If the monitor were ignoring per-server params (or dropping tls_version),
* the counter would keep climbing, which is the regression we want to catch.
*/
static void test_monitor_uses_per_server_row(PGconn* admin) {
std::string hostname;
int port;
if (!get_backend_server(admin, hostname, port)) {
ok(0, "Monitor per-server: no backend server found");
ok(0, "Monitor per-server: cleanup restores monitor SSL OK");
return;
}
cleanup_ssl_params(admin);
exec_ok(admin, "UPDATE pgsql_servers SET use_ssl=1");
exec_ok(admin, "LOAD PGSQL SERVERS TO RUNTIME");
// Insert a per-server row matching the backend, with TLSv1 pin so the
// monitor's connection attempt must fail if tls_version flows through.
std::stringstream q;
q << "INSERT INTO pgsql_servers_ssl_params "
"(hostname, port, username, ssl_protocol_version_range) VALUES ('"
<< hostname << "', " << port << ", '', 'TLSv1')";
exec_ok(admin, q.str().c_str());
exec_ok(admin, "LOAD PGSQL SERVERS TO RUNTIME");
long ok_before = getMonitorValue(admin, "PgSQL_Monitor_ssl_connections_OK");
diag("With TLSv1 per-server pin, ssl OK before wait: %ld", ok_before);
usleep(3000000); // 3 seconds — multiple monitor cycles
long ok_after = getMonitorValue(admin, "PgSQL_Monitor_ssl_connections_OK");
diag("With TLSv1 per-server pin, ssl OK after wait: %ld (delta=%ld)",
ok_after, ok_after - ok_before);
ok(ok_after == ok_before,
"Monitor per-server: SSL OK counter does NOT advance when "
"per-server row pins ssl_protocol_version_range to TLSv1");
// Phase 2: remove the row and confirm the monitor recovers, proving
// the previous failure was caused by the per-server row and not by
// some unrelated breakage.
cleanup_ssl_params(admin);
exec_ok(admin, "LOAD PGSQL SERVERS TO RUNTIME");
long recover_before = getMonitorValue(admin, "PgSQL_Monitor_ssl_connections_OK");
usleep(3000000);
long recover_after = getMonitorValue(admin, "PgSQL_Monitor_ssl_connections_OK");
diag("After cleanup, ssl OK recovered from %ld to %ld",
recover_before, recover_after);
ok(recover_after > recover_before,
"Monitor per-server: SSL OK counter resumes advancing after "
"removing the per-server row");
}
// ============================================================================
@ -446,7 +510,7 @@ static void test_monitor_ssl_with_per_server_params(PGconn* admin) {
// ============================================================================
int main(int argc, char** argv) {
plan(31);
plan(34);
if (cl.getEnv()) {
BAIL_OUT("Failed to get environment variables");
@ -482,6 +546,8 @@ int main(int argc, char** argv) {
test_tls_version_pin_causes_failure(a);
test_per_server_overrides_global(a);
test_remove_per_server_fallback_to_global(a);
test_monitor_ssl_with_per_server_params(a);
test_monitor_uses_per_server_row(a);
// Cleanup
remove_bogus_cert_file();
cleanup_ssl_params(a);

@ -47,6 +47,23 @@ static void test_base_constructor_string() {
ok(p.comment == "test comment", "string ctor: comment");
}
static void test_base_constructor_3arg() {
Servers_SslParams p(string("db3.example.com"), 5434, string("readonly"));
ok(p.hostname == "db3.example.com", "3-arg ctor: hostname");
ok(p.port == 5434, "3-arg ctor: port");
ok(p.username == "readonly", "3-arg ctor: username");
ok(p.ssl_ca == "", "3-arg ctor: ssl_ca defaults to empty");
ok(p.ssl_cert == "", "3-arg ctor: ssl_cert defaults to empty");
ok(p.ssl_key == "", "3-arg ctor: ssl_key defaults to empty");
ok(p.ssl_capath == "", "3-arg ctor: ssl_capath defaults to empty");
ok(p.ssl_crl == "", "3-arg ctor: ssl_crl defaults to empty");
ok(p.ssl_crlpath == "", "3-arg ctor: ssl_crlpath defaults to empty");
ok(p.ssl_cipher == "", "3-arg ctor: ssl_cipher defaults to empty");
ok(p.tls_version == "", "3-arg ctor: tls_version defaults to empty");
ok(p.comment == "", "3-arg ctor: comment defaults to empty");
}
static void test_base_constructor_charptr() {
char h[] = "db2.example.com";
char u[] = "admin";
@ -110,16 +127,48 @@ static void test_pgsql_derived_class() {
PgSQLServers_SslParams p(
string("pghost"), 5432, string("pguser"),
string("/pg/ca.crt"), string("/pg/cert.crt"), string("/pg/key.pem"),
string(""), string(""), string(""),
string(""), string("TLSv1.2-TLSv1.3"), string("pg comment")
string(""), string(""),
string("TLSv1.2-TLSv1.3"), string("pg comment")
);
ok(p.hostname == "pghost", "PgSQL derived: hostname inherited");
ok(p.ssl_ca == "/pg/ca.crt", "PgSQL derived: ssl_ca inherited");
ok(p.tls_version == "TLSv1.2-TLSv1.3", "PgSQL derived: tls_version inherited");
ok(p.ssl_min_protocol_version == "TLSv1.2", "PgSQL derived: parsed min from range");
ok(p.ssl_max_protocol_version == "TLSv1.3", "PgSQL derived: parsed max from range");
string key = p.getMapKey("|");
ok(key == "pghost|5432|pguser", "PgSQL derived: getMapKey inherited");
// Single token pins both ends
PgSQLServers_SslParams pin(
string("pinhost"), 5432, string(""),
string(""), string(""), string(""),
string(""), string(""),
string("TLSv1.3"), string("")
);
ok(pin.ssl_min_protocol_version == "TLSv1.3", "PgSQL derived: single-token pin -> min");
ok(pin.ssl_max_protocol_version == "TLSv1.3", "PgSQL derived: single-token pin -> max");
// Empty tls_version leaves both empty
PgSQLServers_SslParams empty(
string("eh"), 5432, string(""),
string(""), string(""), string(""),
string(""), string(""),
string(""), string("")
);
ok(empty.ssl_min_protocol_version == "", "PgSQL derived: empty tls_version -> empty min");
ok(empty.ssl_max_protocol_version == "", "PgSQL derived: empty tls_version -> empty max");
// Malformed (one side missing) leaves both empty
PgSQLServers_SslParams bad(
string("bh"), 5432, string(""),
string(""), string(""), string(""),
string(""), string(""),
string("TLSv1.2-"), string("")
);
ok(bad.ssl_min_protocol_version == "", "PgSQL derived: malformed -> empty min");
ok(bad.ssl_max_protocol_version == "", "PgSQL derived: malformed -> empty max");
}
static void test_pgsql_storable_in_map() {
@ -127,13 +176,15 @@ static void test_pgsql_storable_in_map() {
PgSQLServers_SslParams p1(
string("host1"), 5432, string("user1"),
string("/ca1"), string(""), string(""), string(""),
string(""), string(""), string(""), string(""), string("")
string("/ca1"), string(""), string(""),
string(""), string(""),
string(""), string("")
);
PgSQLServers_SslParams p2(
string("host2"), 5433, string("user2"),
string("/ca2"), string(""), string(""), string(""),
string(""), string(""), string(""), string(""), string("")
string("/ca2"), string(""), string(""),
string(""), string(""),
string(""), string("")
);
m.emplace("key1", p1);
@ -149,29 +200,31 @@ static void test_pgsql_storable_in_map() {
// ============================================================================
static void populate_ssl_params() {
SQLite3_result *result = new SQLite3_result(12);
// Schema columns: hostname, port, username, ssl_ca, ssl_cert, ssl_key,
// ssl_crl, ssl_crlpath, ssl_protocol_version_range, comment
SQLite3_result *result = new SQLite3_result(10);
char *row1[] = {
(char*)"host1", (char*)"5432", (char*)"testuser",
(char*)"/certs/ca1.crt", (char*)"/certs/cert1.crt", (char*)"/certs/key1.pem",
(char*)"", (char*)"", (char*)"",
(char*)"", (char*)"TLSv1.3", (char*)"exact match row"
(char*)"", (char*)"",
(char*)"TLSv1.3", (char*)"exact match row"
};
result->add_row(row1);
char *row2[] = {
(char*)"host1", (char*)"5432", (char*)"",
(char*)"/certs/ca_fallback.crt", (char*)"/certs/cert_fb.crt", (char*)"/certs/key_fb.pem",
(char*)"", (char*)"", (char*)"",
(char*)"", (char*)"", (char*)"fallback row"
(char*)"", (char*)"",
(char*)"", (char*)"fallback row"
};
result->add_row(row2);
char *row3[] = {
(char*)"host2", (char*)"5433", (char*)"admin",
(char*)"/certs/ca2.crt", (char*)"", (char*)"",
(char*)"", (char*)"", (char*)"",
(char*)"AES256", (char*)"TLSv1.2-TLSv1.3", (char*)"host2 row"
(char*)"", (char*)"",
(char*)"TLSv1.2-TLSv1.3", (char*)"host2 row"
};
result->add_row(row3);
@ -246,11 +299,13 @@ static void test_lookup_different_host() {
);
ok(p != NULL, "different host: found host2:5433:admin");
if (p) {
ok(p->ssl_cipher == "AES256", "different host: ssl_cipher correct");
ok(p->ssl_ca == "/certs/ca2.crt", "different host: ssl_ca correct");
ok(p->tls_version == "TLSv1.2-TLSv1.3", "different host: tls_version correct");
ok(p->ssl_min_protocol_version == "TLSv1.2", "different host: parsed min");
ok(p->ssl_max_protocol_version == "TLSv1.3", "different host: parsed max");
delete p;
} else {
skip(2, "host2 not found");
skip(4, "host2 not found");
}
}
@ -259,11 +314,12 @@ static void test_lookup_different_host() {
// ============================================================================
int main() {
plan(45);
plan(67);
test_init_minimal();
test_base_constructor_string();
test_base_constructor_3arg();
test_base_constructor_charptr();
test_getMapKey();
test_getMapKey_empty_username();

Loading…
Cancel
Save