MINOR: diag: diag if servers use the same cookie value

Add a diagnostic to check that two servers of the same backend does not
use the same cookie value. Ignore backup servers as it is quite common
for them to share a cookie value with a primary one.
This commit is contained in:
Amaury Denoyelle 2021-03-30 17:35:19 +02:00
parent 5a6926dcf0
commit de2fab55aa
1 changed files with 52 additions and 0 deletions

View File

@ -1,8 +1,12 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <import/ebistree.h>
#include <haproxy/cfgdiag.h> #include <haproxy/cfgdiag.h>
#include <haproxy/log.h> #include <haproxy/log.h>
#include <haproxy/proxy.h>
#include <haproxy/server.h>
/* Use this fonction to emit diagnostic. /* Use this fonction to emit diagnostic.
* This can be used as a shortcut to set value pointed by <ret> to 1 at the * This can be used as a shortcut to set value pointed by <ret> to 1 at the
@ -33,6 +37,51 @@ static inline void *diag_alloc(size_t size)
return out; return out;
} }
/* Checks that two servers from the same backend does not share the same cookie
* value. Backup servers are not taken into account as it can be quite common to
* share cookie values in this case.
*/
static void check_server_cookies(int *ret)
{
struct cookie_entry {
struct ebpt_node node;
};
struct proxy *px;
struct server *srv;
struct eb_root cookies_tree = EB_ROOT_UNIQUE;
struct ebpt_node *cookie_node;
struct cookie_entry *cookie_entry;
struct ebpt_node *node;
for (px = proxies_list; px; px = px->next) {
for (srv = px->srv; srv; srv = srv->next) {
/* do not take into account backup servers */
if (!srv->cookie || (srv->flags & SRV_F_BACKUP))
continue;
cookie_node = ebis_lookup(&cookies_tree, srv->cookie);
if (cookie_node) {
diag_warning(ret, "parsing [%s:%d] : 'server %s' : same cookie value is set for a previous non-backup server in the same backend, it may break connection persistence\n",
srv->conf.file, srv->conf.line, srv->id);
continue;
}
cookie_entry = diag_alloc(sizeof(*cookie_entry));
cookie_entry->node.key = srv->cookie;
ebis_insert(&cookies_tree, &cookie_entry->node);
}
/* clear the tree and free its entries */
while ((node = ebpt_first(&cookies_tree))) {
cookie_entry = ebpt_entry(node, struct cookie_entry, node);
eb_delete(&node->node);
free(cookie_entry);
}
}
}
/* Placeholder to execute various diagnostic checks after the configuration file /* Placeholder to execute various diagnostic checks after the configuration file
* has been fully parsed. It will output a warning for each diagnostic found. * has been fully parsed. It will output a warning for each diagnostic found.
* *
@ -41,5 +90,8 @@ static inline void *diag_alloc(size_t size)
int cfg_run_diagnostics() int cfg_run_diagnostics()
{ {
int ret = 0; int ret = 0;
check_server_cookies(&ret);
return ret; return ret;
} }