From: William Lallemand Date: Tue, 23 Jul 2019 13:00:54 +0000 (+0200) Subject: MEDIUM: ssl: lookup and store in a ckch_node tree X-Git-Tag: v2.1-dev2~265 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6af03991dacb3db5860c67cf2156d87f720c8d21;p=thirdparty%2Fhaproxy.git MEDIUM: ssl: lookup and store in a ckch_node tree Don't read a certificate file again if it was already stored in the ckchn tree. It allows HAProxy to start more quickly if the same certificate is used at different places in the configuration. HAProxy lookup in the ssl_sock_load_cert() function, doing it at this level allows to skip the reading of the certificate in the filesystem. If the certificate is not found in the tree, we insert the ckch_node in the tree once the certificate is read on the filesystem, the filename or the bundle name is used as the key. --- diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 29b2a846c7..23f7fbb97f 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -2872,8 +2872,15 @@ struct cert_key_and_chain { struct ckch_node { struct cert_key_and_chain *ckch; int multi; /* is it a multi-cert bundle ? */ + struct ebmb_node node; + char path[0]; }; +/* + * tree used to store the ckchn ordered by filename/bundle name + */ +struct eb_root ckchn_tree = EB_ROOT_UNIQUE; + #define SSL_SOCK_POSSIBLE_KT_COMBOS (1<<(SSL_SOCK_NUM_KEYTYPES)) struct key_combo_ctx { @@ -3088,6 +3095,20 @@ static void ssl_sock_populate_sni_keytypes_hplr(const char *str, struct eb_root } +/* + * lookup a path into the ckchn tree. + */ +static inline struct ckch_node *ckchn_lookup(char *path) +{ + struct ebmb_node *eb; + + eb = ebst_lookup(&ckchn_tree, path); + if (!eb) + return NULL; + + return ebmb_entry(eb, struct ckch_node, node); +} + /* * This function allocate a ckch_node and populate it with certificates from files. */ @@ -3097,7 +3118,7 @@ static struct ckch_node *ckchn_load_cert_file(char *path, int multi, char **err) char fp[MAXPATHLEN+1] = {0}; int n = 0; - ckchn = calloc(1, sizeof(*ckchn)); + ckchn = calloc(1, sizeof(*ckchn) + strlen(path) + 1); if (!ckchn) { memprintf(err, "%sunable to allocate memory.\n", err && *err ? *err : ""); goto end; @@ -3114,6 +3135,9 @@ static struct ckch_node *ckchn_load_cert_file(char *path, int multi, char **err) if (ssl_sock_load_crt_file_into_ckch(path, ckchn->ckch, err) == 1) goto end; + /* insert into the ckchn tree */ + memcpy(ckchn->path, path, strlen(path) + 1); + ebst_insert(&ckchn_tree, &ckchn->node); } else { int found = 0; @@ -3133,12 +3157,18 @@ static struct ckch_node *ckchn_load_cert_file(char *path, int multi, char **err) memprintf(err, "%sDidn't find any certificate.\n", err && *err ? *err : ""); goto end; } + /* insert into the ckchn tree */ + memcpy(ckchn->path, path, strlen(path) + 1); + ebst_insert(&ckchn_tree, &ckchn->node); } return ckchn; end: - if (ckchn) + if (ckchn) { free(ckchn->ckch); + ebmb_delete(&ckchn->node); + } + free(ckchn); return NULL; @@ -3538,6 +3568,16 @@ int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, char **err) int j; #endif + if ((ckchn = ckchn_lookup(path))) { + + /* we found the ckchn in the tree, we can use it directly */ + if (ckchn->multi) + return ssl_sock_load_multi_ckchn(path, ckchn, bind_conf, NULL, NULL, 0, err); + else + return ssl_sock_load_ckchn(path, ckchn, bind_conf, NULL, NULL, 0, err); + + } + if (stat(path, &buf) == 0) { dir = opendir(path); if (!dir) { @@ -3605,7 +3645,8 @@ int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, char **err) } snprintf(fp, sizeof(fp), "%s/%s", path, dp); - ckchn = ckchn_load_cert_file(fp, 1, err); + if ((ckchn = ckchn_lookup(fp)) == NULL) + ckchn = ckchn_load_cert_file(fp, 1, err); if (!ckchn) return 1; cfgerr += ssl_sock_load_multi_ckchn(fp, ckchn, bind_conf, NULL, NULL, 0, err); @@ -3616,7 +3657,8 @@ int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, char **err) } #endif - ckchn = ckchn_load_cert_file(fp, 0, err); + if ((ckchn = ckchn_lookup(fp)) == NULL) + ckchn = ckchn_load_cert_file(fp, 0, err); if (!ckchn) return 1; cfgerr += ssl_sock_load_ckchn(fp, ckchn, bind_conf, NULL, NULL, 0, err);