blob: f8e4a9e082c1a75d3f68140c2c30194c4147a154 [file] [log] [blame]
Amaury Denoyelle5a6926d2021-03-30 17:34:24 +02001#include <stdarg.h>
2#include <stdlib.h>
3
Amaury Denoyellede2fab52021-03-30 17:35:19 +02004#include <import/ebistree.h>
5
Amaury Denoyelle5a6926d2021-03-30 17:34:24 +02006#include <haproxy/cfgdiag.h>
7#include <haproxy/log.h>
Amaury Denoyellede2fab52021-03-30 17:35:19 +02008#include <haproxy/proxy.h>
9#include <haproxy/server.h>
Amaury Denoyelle5a6926d2021-03-30 17:34:24 +020010
Ilya Shipitsinb2be9a12021-04-24 13:25:42 +050011/* Use this function to emit diagnostic.
Amaury Denoyelle5a6926d2021-03-30 17:34:24 +020012 * This can be used as a shortcut to set value pointed by <ret> to 1 at the
13 * same time.
14 */
15static inline void diag_warning(int *ret, char *fmt, ...)
16{
17 va_list argp;
18
19 va_start(argp, fmt);
20 *ret = 1;
21 _ha_vdiag_warning(fmt, argp);
22 va_end(argp);
23}
24
25/* Use this for dynamic allocation in diagnostics.
26 * In case of allocation failure, this will immediately terminates haproxy.
27 */
28static inline void *diag_alloc(size_t size)
29{
30 void *out = NULL;
31
32 if (!(out = malloc(size))) {
33 fprintf(stderr, "out of memory\n");
34 exit(1);
35 }
36
37 return out;
38}
39
Amaury Denoyellede2fab52021-03-30 17:35:19 +020040/* Checks that two servers from the same backend does not share the same cookie
41 * value. Backup servers are not taken into account as it can be quite common to
42 * share cookie values in this case.
43 */
44static void check_server_cookies(int *ret)
45{
46 struct cookie_entry {
47 struct ebpt_node node;
48 };
49
50 struct proxy *px;
51 struct server *srv;
52
53 struct eb_root cookies_tree = EB_ROOT_UNIQUE;
54 struct ebpt_node *cookie_node;
55 struct cookie_entry *cookie_entry;
56 struct ebpt_node *node;
57
58 for (px = proxies_list; px; px = px->next) {
59 for (srv = px->srv; srv; srv = srv->next) {
60 /* do not take into account backup servers */
61 if (!srv->cookie || (srv->flags & SRV_F_BACKUP))
62 continue;
63
64 cookie_node = ebis_lookup(&cookies_tree, srv->cookie);
65 if (cookie_node) {
66 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",
67 srv->conf.file, srv->conf.line, srv->id);
68 continue;
69 }
70
71 cookie_entry = diag_alloc(sizeof(*cookie_entry));
72 cookie_entry->node.key = srv->cookie;
73 ebis_insert(&cookies_tree, &cookie_entry->node);
74 }
75
76 /* clear the tree and free its entries */
77 while ((node = ebpt_first(&cookies_tree))) {
78 cookie_entry = ebpt_entry(node, struct cookie_entry, node);
79 eb_delete(&node->node);
80 free(cookie_entry);
81 }
82 }
83}
84
Amaury Denoyelle5a6926d2021-03-30 17:34:24 +020085/* Placeholder to execute various diagnostic checks after the configuration file
86 * has been fully parsed. It will output a warning for each diagnostic found.
87 *
88 * Returns 0 if no diagnostic message has been found else 1.
89 */
90int cfg_run_diagnostics()
91{
92 int ret = 0;
Amaury Denoyellede2fab52021-03-30 17:35:19 +020093
94 check_server_cookies(&ret);
95
Amaury Denoyelle5a6926d2021-03-30 17:34:24 +020096 return ret;
97}