Hello HAProxy ML,
On 04/10/2017 05:00 PM, Baptiste wrote:
On Mon, Apr 10, 2017 at 2:30 PM, Willy Tarreau <[email protected]
<mailto:[email protected]>> wrote:
On Mon, Apr 10, 2017 at 10:02:29AM +0200, Frederic Lecaille wrote:
> With server templates, haproxy could preallocate 'server' objects which
> would derive from 'default-server' (with same settings as default server
> settings), but with remaining parameters which are unknown at parsing time
> (for instance their names, addresses, anything else). In fact here, names
or
> addresses are particular settings: a default server has not any default
name
> or default address.
Absolutely. And this combined with the recent features of dynamic
consistent
cookies and with Baptiste's upcoming DNS patches will easily result
in pretty
dynamic backends!
Willy
I just had a look at the implementation of server-templates. To make it
work with DNS resolution, we need to find a way to provide a fqdn to
the default-server directive. This might not be too complicated.
After this, the magic will happen!!!!
After this first patches for server template new feature, here is a new
set attached to this mail which takes into an account what have been
discussed with Baptiste and Willy.
#0001 patch fixes a minor bug which may be backported to haproxy 1.7 and
1.6.
#0002 upto #0005 patches implement server template feature.
"server-template" new keyword is added and supported in "backend" and
"listen" sections.
Its syntax:
server-temlate <prefix> <nb | range> <fqdn>[:port] <params*>
This may be used to initialize a list of servers with the same
parameters, especially the same FQDN as requested by Baptiste.
#0006 patch updates the documentation.
Fill free to review/comment/test as needed.
Regards,
Fred.
>From ceeb3a4e39242924dd061438f0be27ed58d648a3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20L=C3=A9caille?= <[email protected]>
Date: Thu, 20 Apr 2017 13:36:25 +0200
Subject: [PATCH 6/6] DOC: Add documentation for new "server-template" keyword.
---
doc/configuration.txt | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/doc/configuration.txt b/doc/configuration.txt
index e6ea2cf..488d8e2 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -1969,6 +1969,7 @@ rspirep - X X X
rsprep - X X X
server - - X X
server-state-file-name X - X X
+server-template - - X X
source X - X X
srvtimeout (deprecated) X - X X
stats admin - X X X
@@ -7521,6 +7522,44 @@ server-state-file-name [<file>]
See also: "server-state-file-base", "load-server-state-from-file", and
"show servers state"
+server-template <prefix> <nb | range> <fqdn>[:<port>] [params*]
+ Set a template for this backend to initialize servers with shared parameters.
+ This server names are built from <prefix> and <nb | range> parameters.
+ May be used in sections : defaults | frontend | listen | backend
+ no | no | yes | yes
+
+ Arguments:
+ <prefix> a prefix for the server names to be built.
+
+ <nb | range>
+ If <nb> is provided, this template initializes <nb> servers
+ with 1 upto <nb> as server name suffixes. A range <nb_low>-<nb_high>
+ may also been used to use <nb_low> upto <nb_high> as server name
+ suffixes.
+
+ <fqdn> A FQDN for all the servers this template initializes.
+
+ <port> Same meaning as "server" <port> argument (see "server" keyword).
+
+ <params*>
+ Remaining server parameter among all those supported by "server"
+ keyword.
+
+ Examples:
+ # Initializes 5 servers with srv_1, srv_2 and srv_3 as names,
+ # google.com as FQDN, and health-check enabled.
+ server-template srv 1-3 google.com:80 check
+
+ # or
+ server-template srv 3 google.com:80 check
+
+ # would be equivalent to:
+ server srv1 google.com:80 check
+ server srv2 google.com:80 check
+ server srv3 google.com:80 check
+
+
+
source <addr>[:<port>] [usesrc { <addr2>[:<port2>] | client | clientip } ]
source <addr>[:<port>] [usesrc { <addr2>[:<port2>] | hdr_ip(<hdr>[,<occ>]) } ]
source <addr>[:<port>] [interface <name>]
--
2.1.4
>From 960693685da4d73f7c3c4ee6065aa7f5ae7134aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20L=C3=A9caille?= <[email protected]>
Date: Fri, 14 Apr 2017 13:28:00 +0200
Subject: [PATCH 5/6] MINOR: server: Add server_template_init() function to
initialize servers from a templates.
This patch adds server_template_init() function used to initialize servers
from server templates. It is called just after having parsed a 'server-template'
line.
---
src/server.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 132 insertions(+), 2 deletions(-)
diff --git a/src/server.c b/src/server.c
index 9f07788..69c1ec3 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1650,14 +1650,73 @@ static void srv_ssl_settings_cpy(struct server *srv, struct server *src)
#endif
/*
+ * Allocate <srv> server dns resolution.
+ * May be safely called with a default server as <src> argument (without hostname).
+ */
+static void srv_alloc_dns_resolution(struct server *srv, const char *hostname)
+{
+ char *hostname_dn;
+ int hostname_dn_len;
+ struct dns_resolution *dst_dns_rslt;
+
+ if (!hostname)
+ return;
+
+ srv->hostname = strdup(hostname);
+ dst_dns_rslt = calloc(1, sizeof *dst_dns_rslt);
+ hostname_dn_len = dns_str_to_dn_label_len(hostname);
+ hostname_dn = calloc(hostname_dn_len + 1, sizeof(char));
+
+ if (!srv->hostname || !dst_dns_rslt || !hostname_dn)
+ goto err;
+
+ srv->resolution = dst_dns_rslt;
+ srv->resolution->hostname_dn = hostname_dn;
+ srv->resolution->hostname_dn_len = hostname_dn_len;
+
+ if (!dns_str_to_dn_label(srv->hostname,
+ srv->resolution->hostname_dn,
+ srv->resolution->hostname_dn_len + 1))
+ goto err;
+
+ srv->resolution->requester = srv;
+ srv->resolution->requester_cb = snr_resolution_cb;
+ srv->resolution->requester_error_cb = snr_resolution_error_cb;
+ srv->resolution->status = RSLV_STATUS_NONE;
+ srv->resolution->step = RSLV_STEP_NONE;
+ /* a first resolution has been done by the configuration parser */
+ srv->resolution->last_resolution = 0;
+
+ return;
+
+ err:
+ free(srv->hostname);
+ srv->hostname = NULL;
+ free(hostname_dn);
+ free(dst_dns_rslt);
+}
+
+/*
* Copy <src> server settings to <srv> server allocating
* everything needed.
+ * This function is not supposed to be called at any time, but only
+ * during server settings parsing or during server allocations from
+ * a server template, and just after having calloc()'ed a new server.
+ * So, <src> may only be a default server (when parsing server settings)
+ * or a server template (during server allocations from a server template).
+ * <srv_tmpl> distinguishes these two cases (must be 1 if <srv> is a template,
+ * 0 if not).
*/
-static void srv_settings_cpy(struct server *srv, struct server *src)
+static void srv_settings_cpy(struct server *srv, struct server *src, int srv_tmpl)
{
/* Connection source settings copy */
srv_conn_src_cpy(srv, src);
+ if (srv_tmpl) {
+ srv->addr = src->addr;
+ srv->svc_port = src->svc_port;
+ }
+
srv->pp_opts = src->pp_opts;
if (src->rdr_pfx != NULL) {
srv->rdr_pfx = strdup(src->rdr_pfx);
@@ -1999,6 +2058,75 @@ static int srv_tmpl_parse_range(struct server *srv, const char *arg, int *nb_low
return 0;
}
+static inline void srv_set_id_from_prefix(struct server *srv, const char *prefix, int nb)
+{
+ chunk_printf(&trash, "%s%d", prefix, nb);
+ free(srv->id);
+ srv->id = strdup(trash.str);
+}
+
+/*
+ * Initialize as much as possible servers from <srv> server template.
+ * Note that a server template is a special server with
+ * a few different parameters than a server which has
+ * been parsed mostly the same way as a server.
+ * Returns the number of servers succesfully allocated,
+ * 'srv' template included.
+ */
+static int server_template_init(struct server *srv, struct proxy *px)
+{
+ int i;
+ struct server *newsrv;
+
+ for (i = srv->tmpl_info.nb_low + 1; i <= srv->tmpl_info.nb_high; i++) {
+ int check_init_state;
+ int agent_init_state;
+
+ newsrv = new_server(px);
+ if (!newsrv)
+ goto err;
+
+ srv_settings_cpy(newsrv, srv, 1);
+ srv_alloc_dns_resolution(newsrv, srv->hostname);
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+ if (newsrv->sni_expr) {
+ newsrv->ssl_ctx.sni = srv_sni_sample_parse_expr(newsrv, px, NULL, 0, NULL);
+ if (!newsrv->ssl_ctx.sni)
+ goto err;
+ }
+#endif
+ /* Set this new server ID. */
+ srv_set_id_from_prefix(newsrv, srv->tmpl_info.prefix, i);
+
+ /* Initial checks states. */
+ check_init_state = CHK_ST_CONFIGURED | CHK_ST_ENABLED;
+ agent_init_state = CHK_ST_CONFIGURED | CHK_ST_ENABLED | CHK_ST_AGENT;
+
+ if (do_health_check_init(newsrv, px->options2 & PR_O2_CHK_ANY, check_init_state) ||
+ do_server_agent_check_init(newsrv, agent_init_state))
+ goto err;
+
+ /* Linked backwards first. This will be restablished after parsing. */
+ newsrv->next = px->srv;
+ px->srv = newsrv;
+ }
+ srv_set_id_from_prefix(srv, srv->tmpl_info.prefix, srv->tmpl_info.nb_low);
+
+ return i - srv->tmpl_info.nb_low;
+
+ err:
+ srv_set_id_from_prefix(srv, srv->tmpl_info.prefix, srv->tmpl_info.nb_low);
+ if (newsrv) {
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+ release_sample_expr(newsrv->ssl_ctx.sni);
+#endif
+ free_check(&newsrv->agent);
+ free_check(&newsrv->check);
+ }
+ free(newsrv);
+ return i - srv->tmpl_info.nb_low;
+}
+
int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy)
{
struct server *newsrv = NULL;
@@ -2174,7 +2302,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
}
/* Copy default server settings to new server settings. */
- srv_settings_cpy(newsrv, &curproxy->defsrv);
+ srv_settings_cpy(newsrv, &curproxy->defsrv, 0);
cur_arg++;
} else {
newsrv = &curproxy->defsrv;
@@ -2609,6 +2737,8 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
err_code |= server_finalize_init(file, linenum, args, cur_arg, newsrv, curproxy);
if (err_code & ERR_FATAL)
goto out;
+ if (srv_tmpl)
+ server_template_init(newsrv, curproxy);
}
free(fqdn);
return 0;
--
2.1.4
>From 93d44078107c151978073d4e009f70db410639ba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20L=C3=A9caille?= <[email protected]>
Date: Thu, 13 Apr 2017 18:24:23 +0200
Subject: [PATCH 4/6] MINOR: server: Add 'server-template' new keyword
supported in backend sections.
This patch makes backend sections support 'server-template' new keyword.
Such 'server-template' objects are parsed similarly to a 'server' object
by parse_server() function, but its first arguments are as follows:
server-template <ID prefix> <nb | range> <ip | fqdn>:<port> ...
The remaining arguments are the same as for 'server' lines.
With such server template declarations, servers may be allocated with IDs
built from <ID prefix> and <nb | range> arguments.
For instance declaring:
server-template foo 1-5 google.com:80 ...
or
server-template foo 5 google.com:80 ...
would be equivalent to declare:
server foo1 google.com:80 ...
server foo2 google.com:80 ...
server foo3 google.com:80 ...
server foo4 google.com:80 ...
server foo5 google.com:80 ...
---
include/common/standard.h | 9 +++-
include/types/server.h | 9 ++++
src/cfgparse.c | 4 +-
src/server.c | 107 +++++++++++++++++++++++++++++++++++++++-------
src/standard.c | 25 +++++++++--
5 files changed, 133 insertions(+), 21 deletions(-)
diff --git a/include/common/standard.h b/include/common/standard.h
index be719f7..6827111 100644
--- a/include/common/standard.h
+++ b/include/common/standard.h
@@ -259,13 +259,20 @@ unsigned int round_2dig(unsigned int i);
extern const char *invalid_char(const char *name);
/*
- * Checks <domainname> for invalid characters. Valid chars are [A-Za-z0-9_.-].
+ * Checks <name> for invalid characters. Valid chars are [A-Za-z0-9_.-].
* If an invalid character is found, a pointer to it is returned.
* If everything is fine, NULL is returned.
*/
extern const char *invalid_domainchar(const char *name);
/*
+ * Checks <name> for invalid characters. Valid chars are [A-Za-z_.-].
+ * If an invalid character is found, a pointer to it is returned.
+ * If everything is fine, NULL is returned.
+ */
+extern const char *invalid_prefix_char(const char *name);
+
+/*
* converts <str> to a locally allocated struct sockaddr_storage *, and a
* port range consisting in two integers. The low and high end are always set
* even if the port is unspecified, in which case (0,0) is returned. The low
diff --git a/include/types/server.h b/include/types/server.h
index bfaa941..8d68dcb 100644
--- a/include/types/server.h
+++ b/include/types/server.h
@@ -274,6 +274,15 @@ struct server {
int line; /* line where the section appears */
struct eb32_node id; /* place in the tree of used IDs */
} conf; /* config information */
+ /* Template information used only for server objects which
+ * serve as template filled at parsing time and used during
+ * server allocations from server templates.
+ */
+ struct {
+ char *prefix;
+ int nb_low;
+ int nb_high;
+ } tmpl_info;
};
/* Descriptor for a "server" keyword. The ->parse() function returns 0 in case of
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 348b9e8..d44949a 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -2859,7 +2859,9 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
curproxy->conf.args.line = linenum;
/* Now let's parse the proxy-specific keywords */
- if (!strcmp(args[0], "server") || !strcmp(args[0], "default-server")) {
+ if (!strcmp(args[0], "server") ||
+ !strcmp(args[0], "default-server") ||
+ !strcmp(args[0], "server-template")) {
err_code |= parse_server(file, linenum, args, curproxy, &defproxy);
if (err_code & ERR_FATAL)
goto out;
diff --git a/src/server.c b/src/server.c
index f25a7a0..9f07788 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1969,18 +1969,53 @@ static int server_finalize_init(const char *file, int linenum, char **args, int
return 0;
}
+/*
+ * Parse as much as possible such a range string argument: low[-high]
+ * Set <nb_low> and <nb_high> values so that they may be reused by this loop
+ * for(int i = nb_low; i <= nb_high; i++)... with nb_low >= 1.
+ * Fails if 'low' < 0 or 'high' is present and not higher than 'low'.
+ * Returns 0 if succeeded, -1 if not.
+ */
+static int srv_tmpl_parse_range(struct server *srv, const char *arg, int *nb_low, int *nb_high)
+{
+ char *nb_high_arg;
+
+ *nb_high = 0;
+ chunk_printf(&trash, "%s", arg);
+ *nb_low = atoi(trash.str);
+
+ if ((nb_high_arg = strchr(trash.str, '-'))) {
+ *nb_high_arg++ = '\0';
+ *nb_high = atoi(nb_high_arg);
+ }
+ else {
+ *nb_high += *nb_low;
+ *nb_low = 1;
+ }
+
+ if (*nb_low < 0 || *nb_high < *nb_low)
+ return -1;
+
+ return 0;
+}
+
int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy)
{
struct server *newsrv = NULL;
- const char *err;
+ const char *err = NULL;
char *errmsg = NULL;
int err_code = 0;
unsigned val;
char *fqdn = NULL;
- if (!strcmp(args[0], "server") || !strcmp(args[0], "default-server")) { /* server address */
+ if (!strcmp(args[0], "server") ||
+ !strcmp(args[0], "default-server") ||
+ !strcmp(args[0], "server-template")) {
int cur_arg;
int defsrv = (*args[0] == 'd');
+ int srv = !defsrv && !strcmp(args[0], "server");
+ int srv_tmpl = !defsrv && !srv;
+ int tmpl_range_low = 0, tmpl_range_high = 0;
if (!defsrv && curproxy == defproxy) {
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
@@ -1990,21 +2025,49 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
err_code |= ERR_ALERT | ERR_FATAL;
- if (!defsrv && !*args[2]) {
- Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
- file, linenum, args[0]);
- err_code |= ERR_ALERT | ERR_FATAL;
- goto out;
+ /* There is no mandatory first arguments for default server. */
+ if (srv) {
+ if (!*args[2]) {
+ /* 'server' line number of argument check. */
+ Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
+ file, linenum, args[0]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+
+ err = invalid_char(args[1]);
+ }
+ else if (srv_tmpl) {
+ if (!*args[3]) {
+ /* 'server-template' line number of argument check. */
+ Alert("parsing [%s:%d] : '%s' expects <prefix> <nb | range> <addr>[:<port>] as arguments.\n",
+ file, linenum, args[0]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+
+ err = invalid_prefix_char(args[1]);
}
- err = invalid_char(args[1]);
- if (err && !defsrv) {
- Alert("parsing [%s:%d] : character '%c' is not permitted in server name '%s'.\n",
- file, linenum, *err, args[1]);
+ if (err) {
+ Alert("parsing [%s:%d] : character '%c' is not permitted in %s %s '%s'.\n",
+ file, linenum, *err, args[0], srv ? "name" : "prefix", args[1]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
+ cur_arg = 2;
+ if (srv_tmpl) {
+ /* Parse server-template <nb | range> arg. */
+ if (srv_tmpl_parse_range(newsrv, args[cur_arg], &tmpl_range_low, &tmpl_range_high) < 0) {
+ Alert("parsing [%s:%d] : Wrong %s number or range arg '%s'.\n",
+ file, linenum, args[0], args[cur_arg]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ cur_arg++;
+ }
+
if (!defsrv) {
struct sockaddr_storage *sk;
int port1, port2, port;
@@ -2018,12 +2081,24 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
goto out;
}
+ if (srv_tmpl) {
+ newsrv->tmpl_info.nb_low = tmpl_range_low;
+ newsrv->tmpl_info.nb_high = tmpl_range_high;
+ }
+
/* the servers are linked backwards first */
newsrv->next = curproxy->srv;
curproxy->srv = newsrv;
newsrv->conf.file = strdup(file);
newsrv->conf.line = linenum;
- newsrv->id = strdup(args[1]);
+ /* Note: for a server template, its id is its prefix.
+ * This is a temporary id which will be used for server allocations to come
+ * after parsing.
+ */
+ if (srv)
+ newsrv->id = strdup(args[1]);
+ else
+ newsrv->tmpl_info.prefix = strdup(args[1]);
/* several ways to check the port component :
* - IP => port=+0, relative (IPv4 only)
@@ -2032,7 +2107,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
* - IP:+N => port=+N, relative
* - IP:-N => port=-N, relative
*/
- sk = str2sa_range(args[2], &port, &port1, &port2, &errmsg, NULL, &fqdn, 0);
+ sk = str2sa_range(args[cur_arg], &port, &port1, &port2, &errmsg, NULL, &fqdn, 0);
if (!sk) {
Alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg);
err_code |= ERR_ALERT | ERR_FATAL;
@@ -2073,7 +2148,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
goto skip_name_resolution;
if ((dns_str_to_dn_label(newsrv->hostname, curr_resolution->hostname_dn, curr_resolution->hostname_dn_len + 1)) == NULL) {
Alert("parsing [%s:%d] : Invalid hostname '%s'\n",
- file, linenum, args[2]);
+ file, linenum, args[cur_arg]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
@@ -2093,14 +2168,14 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
if (!newsrv->hostname && !protocol_by_family(newsrv->addr.ss_family)) {
Alert("parsing [%s:%d] : Unknown protocol family %d '%s'\n",
- file, linenum, newsrv->addr.ss_family, args[2]);
+ file, linenum, newsrv->addr.ss_family, args[cur_arg]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
/* Copy default server settings to new server settings. */
srv_settings_cpy(newsrv, &curproxy->defsrv);
- cur_arg = 3;
+ cur_arg++;
} else {
newsrv = &curproxy->defsrv;
cur_arg = 1;
diff --git a/src/standard.c b/src/standard.c
index 99f7066..6abedb4 100644
--- a/src/standard.c
+++ b/src/standard.c
@@ -592,17 +592,18 @@ const char *invalid_char(const char *name)
}
/*
- * Checks <domainname> for invalid characters. Valid chars are [A-Za-z0-9_.-].
+ * Checks <name> for invalid characters. Valid chars are [_.-] and those
+ * accepted by <f> function.
* If an invalid character is found, a pointer to it is returned.
* If everything is fine, NULL is returned.
*/
-const char *invalid_domainchar(const char *name) {
+static inline const char *__invalid_char(const char *name, int (*f)(int)) {
if (!*name)
return name;
while (*name) {
- if (!isalnum((int)(unsigned char)*name) && *name != '.' &&
+ if (!f((int)(unsigned char)*name) && *name != '.' &&
*name != '_' && *name != '-')
return name;
@@ -613,6 +614,24 @@ const char *invalid_domainchar(const char *name) {
}
/*
+ * Checks <name> for invalid characters. Valid chars are [A-Za-z0-9_.-].
+ * If an invalid character is found, a pointer to it is returned.
+ * If everything is fine, NULL is returned.
+ */
+const char *invalid_domainchar(const char *name) {
+ return __invalid_char(name, isalnum);
+}
+
+/*
+ * Checks <name> for invalid characters. Valid chars are [A-Za-z_.-].
+ * If an invalid character is found, a pointer to it is returned.
+ * If everything is fine, NULL is returned.
+ */
+const char *invalid_prefix_char(const char *name) {
+ return __invalid_char(name, isalpha);
+}
+
+/*
* converts <str> to a struct sockaddr_storage* provided by the caller. The
* caller must have zeroed <sa> first, and may have set sa->ss_family to force
* parse a specific address format. If the ss_family is 0 or AF_UNSPEC, then
--
2.1.4
>From 9b18429362bf296c348f40fd02792b385d237332 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20L=C3=A9caille?= <[email protected]>
Date: Thu, 30 Mar 2017 17:32:36 +0200
Subject: [PATCH 3/6] MINOR: server: Extract the code which finalizes server
initializations after 'server' lines parsing.
This patch moves the code which is responsible of finalizing server initializations
after having fully parsed a 'server' line (health-check, agent check and SNI expression
initializations) from parse_server() to new functions.
---
src/server.c | 343 +++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 218 insertions(+), 125 deletions(-)
diff --git a/src/server.c b/src/server.c
index cd3a2b4..f25a7a0 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1529,20 +1529,26 @@ const char *server_parse_maxconn_change_request(struct server *sv,
}
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
-static int server_parse_sni_expr(struct server *newsrv, struct proxy *px, char **err)
+static struct sample_expr *srv_sni_sample_parse_expr(struct server *srv, struct proxy *px,
+ const char *file, int linenum, char **err)
{
int idx;
- struct sample_expr *expr;
const char *args[] = {
- newsrv->sni_expr,
+ srv->sni_expr,
NULL,
};
idx = 0;
- proxy->conf.args.ctx = ARGC_SRV;
+ px->conf.args.ctx = ARGC_SRV;
+
+ return sample_parse_expr((char **)args, &idx, file, linenum, err, &px->conf.args);
+}
+
+static int server_parse_sni_expr(struct server *newsrv, struct proxy *px, char **err)
+{
+ struct sample_expr *expr;
- expr = sample_parse_expr((char **)args, &idx, px->conf.file, px->conf.line,
- err, &proxy->conf.args);
+ expr = srv_sni_sample_parse_expr(newsrv, px, px->conf.file, px->conf.line, err);
if (!expr) {
memprintf(err, "error detected while parsing sni expression : %s", *err);
return ERR_ALERT | ERR_FATAL;
@@ -1552,7 +1558,7 @@ static int server_parse_sni_expr(struct server *newsrv, struct proxy *px, char *
memprintf(err, "error detected while parsing sni expression : "
" fetch method '%s' extracts information from '%s', "
"none of which is available here.\n",
- args[0], sample_src_names(expr->fetch->use));
+ newsrv->sni_expr, sample_src_names(expr->fetch->use));
return ERR_ALERT | ERR_FATAL;
}
@@ -1762,6 +1768,207 @@ static struct server *new_server(struct proxy *proxy)
return srv;
}
+/*
+ * Validate <srv> server health-check settings.
+ * Returns 0 if everything is OK, -1 if not.
+ */
+static int server_healthcheck_validate(const char *file, int linenum, struct server *srv)
+{
+ struct tcpcheck_rule *r = NULL;
+ struct list *l;
+
+ /*
+ * We need at least a service port, a check port or the first tcp-check rule must
+ * be a 'connect' one when checking an IPv4/IPv6 server.
+ */
+ if ((srv_check_healthcheck_port(&srv->check) != 0) ||
+ (!is_inet_addr(&srv->check.addr) && (is_addr(&srv->check.addr) || !is_inet_addr(&srv->addr))))
+ return 0;
+
+ r = (struct tcpcheck_rule *)srv->proxy->tcpcheck_rules.n;
+ if (!r) {
+ Alert("parsing [%s:%d] : server %s has neither service port nor check port. "
+ "Check has been disabled.\n",
+ file, linenum, srv->id);
+ return -1;
+ }
+
+ /* search the first action (connect / send / expect) in the list */
+ l = &srv->proxy->tcpcheck_rules;
+ list_for_each_entry(r, l, list) {
+ if (r->action != TCPCHK_ACT_COMMENT)
+ break;
+ }
+
+ if ((r->action != TCPCHK_ACT_CONNECT) || !r->port) {
+ Alert("parsing [%s:%d] : server %s has neither service port nor check port "
+ "nor tcp_check rule 'connect' with port information. Check has been disabled.\n",
+ file, linenum, srv->id);
+ return -1;
+ }
+
+ /* scan the tcp-check ruleset to ensure a port has been configured */
+ l = &srv->proxy->tcpcheck_rules;
+ list_for_each_entry(r, l, list) {
+ if ((r->action == TCPCHK_ACT_CONNECT) && (!r->port)) {
+ Alert("parsing [%s:%d] : server %s has neither service port nor check port, "
+ "and a tcp_check rule 'connect' with no port information. Check has been disabled.\n",
+ file, linenum, srv->id);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Initialize <srv> health-check structure.
+ * Returns the error string in case of memory allocation failure, NULL if not.
+ */
+static const char *do_health_check_init(struct server *srv, int check_type, int state)
+{
+ const char *ret;
+
+ if (!srv->do_check)
+ return NULL;
+
+ ret = init_check(&srv->check, check_type);
+ if (ret)
+ return ret;
+
+ if (srv->resolution)
+ srv->resolution->opts = &srv->dns_opts;
+
+ srv->check.state |= state;
+ global.maxsock++;
+
+ return NULL;
+}
+
+static int server_health_check_init(const char *file, int linenum,
+ struct server *srv, struct proxy *curproxy)
+{
+ const char *ret;
+
+ if (!srv->do_check)
+ return 0;
+
+ if (srv->trackit) {
+ Alert("parsing [%s:%d]: unable to enable checks and tracking at the same time!\n",
+ file, linenum);
+ return ERR_ALERT | ERR_FATAL;
+ }
+
+ if (server_healthcheck_validate(file, linenum, srv) < 0)
+ return ERR_ALERT | ERR_ABORT;
+
+ /* note: check type will be set during the config review phase */
+ ret = do_health_check_init(srv, 0, CHK_ST_CONFIGURED | CHK_ST_ENABLED);
+ if (ret) {
+ Alert("parsing [%s:%d] : %s.\n", file, linenum, ret);
+ return ERR_ALERT | ERR_ABORT;
+ }
+
+ return 0;
+}
+
+/*
+ * Initialize <srv> agent check structure.
+ * Returns the error string in case of memory allocation failure, NULL if not.
+ */
+static const char *do_server_agent_check_init(struct server *srv, int state)
+{
+ const char *ret;
+
+ if (!srv->do_agent)
+ return NULL;
+
+ ret = init_check(&srv->agent, PR_O2_LB_AGENT_CHK);
+ if (ret)
+ return ret;
+
+ if (!srv->agent.inter)
+ srv->agent.inter = srv->check.inter;
+
+ srv->agent.state |= state;
+ global.maxsock++;
+
+ return NULL;
+}
+
+static int server_agent_check_init(const char *file, int linenum,
+ struct server *srv, struct proxy *curproxy)
+{
+ const char *ret;
+
+ if (!srv->do_agent)
+ return 0;
+
+ if (!srv->agent.port) {
+ Alert("parsing [%s:%d] : server %s does not have agent port. Agent check has been disabled.\n",
+ file, linenum, srv->id);
+ return ERR_ALERT | ERR_FATAL;
+ }
+
+ ret = do_server_agent_check_init(srv, CHK_ST_CONFIGURED | CHK_ST_ENABLED | CHK_ST_AGENT);
+ if (ret) {
+ Alert("parsing [%s:%d] : %s.\n", file, linenum, ret);
+ return ERR_ALERT | ERR_ABORT;
+ }
+
+ return 0;
+}
+
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+static int server_sni_expr_init(const char *file, int linenum, char **args, int cur_arg,
+ struct server *srv, struct proxy *proxy)
+{
+ int ret;
+ char *err = NULL;
+
+ if (!srv->sni_expr)
+ return 0;
+
+ ret = server_parse_sni_expr(srv, proxy, &err);
+ if (!ret)
+ return 0;
+
+ display_parser_err(file, linenum, args, cur_arg, &err);
+ free(err);
+
+ return ret;
+}
+#endif
+
+/*
+ * Server initializations finalization.
+ * Initialize health check, agent check and SNI expression if enabled.
+ * Must not be called for a default server instance.
+ */
+static int server_finalize_init(const char *file, int linenum, char **args, int cur_arg,
+ struct server *srv, struct proxy *px)
+{
+ int ret;
+
+ if ((ret = server_health_check_init(file, linenum, srv, px)) != 0 ||
+ (ret = server_agent_check_init(file, linenum, srv, px)) != 0) {
+ return ret;
+ }
+
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+ if ((ret = server_sni_expr_init(file, linenum, args, cur_arg, srv, px)) != 0)
+ return ret;
+#endif
+
+ if (srv->flags & SRV_F_BACKUP)
+ px->srv_bck++;
+ else
+ px->srv_act++;
+ srv_lb_commit_status(srv);
+
+ return 0;
+}
+
int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy)
{
struct server *newsrv = NULL;
@@ -2323,124 +2530,10 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
}
}
- /* This check is done only for 'server' instances. */
- if (!defsrv && newsrv->do_check) {
- const char *ret;
-
- if (newsrv->trackit) {
- Alert("parsing [%s:%d]: unable to enable checks and tracking at the same time!\n",
- file, linenum);
- err_code |= ERR_ALERT | ERR_FATAL;
- goto out;
- }
-
- /*
- * We need at least a service port, a check port or the first tcp-check rule must
- * be a 'connect' one when checking an IPv4/IPv6 server.
- */
- if ((srv_check_healthcheck_port(&newsrv->check) == 0) &&
- (is_inet_addr(&newsrv->check.addr) ||
- (!is_addr(&newsrv->check.addr) && is_inet_addr(&newsrv->addr)))) {
- struct tcpcheck_rule *r = NULL;
- struct list *l;
-
- r = (struct tcpcheck_rule *)newsrv->proxy->tcpcheck_rules.n;
- if (!r) {
- Alert("parsing [%s:%d] : server %s has neither service port nor check port. Check has been disabled.\n",
- file, linenum, newsrv->id);
- err_code |= ERR_ALERT | ERR_FATAL;
- goto out;
- }
- /* search the first action (connect / send / expect) in the list */
- l = &newsrv->proxy->tcpcheck_rules;
- list_for_each_entry(r, l, list) {
- if (r->action != TCPCHK_ACT_COMMENT)
- break;
- }
- if ((r->action != TCPCHK_ACT_CONNECT) || !r->port) {
- Alert("parsing [%s:%d] : server %s has neither service port nor check port nor tcp_check rule 'connect' with port information. Check has been disabled.\n",
- file, linenum, newsrv->id);
- err_code |= ERR_ALERT | ERR_FATAL;
- goto out;
- }
- else {
- /* scan the tcp-check ruleset to ensure a port has been configured */
- l = &newsrv->proxy->tcpcheck_rules;
- list_for_each_entry(r, l, list) {
- if ((r->action == TCPCHK_ACT_CONNECT) && (!r->port)) {
- Alert("parsing [%s:%d] : server %s has neither service port nor check port, and a tcp_check rule 'connect' with no port information. Check has been disabled.\n",
- file, linenum, newsrv->id);
- err_code |= ERR_ALERT | ERR_FATAL;
- goto out;
- }
- }
- }
- }
-
- /* note: check type will be set during the config review phase */
- ret = init_check(&newsrv->check, 0);
- if (ret) {
- Alert("parsing [%s:%d] : %s.\n", file, linenum, ret);
- err_code |= ERR_ALERT | ERR_ABORT;
- goto out;
- }
-
- if (newsrv->resolution)
- newsrv->resolution->opts = &newsrv->dns_opts;
-
- newsrv->check.state |= CHK_ST_CONFIGURED | CHK_ST_ENABLED;
- global.maxsock++;
- }
-
- if (!defsrv && newsrv->do_agent) {
- const char *ret;
-
- if (!newsrv->agent.port) {
- Alert("parsing [%s:%d] : server %s does not have agent port. Agent check has been disabled.\n",
- file, linenum, newsrv->id);
- err_code |= ERR_ALERT | ERR_FATAL;
- goto out;
- }
-
- if (!newsrv->agent.inter)
- newsrv->agent.inter = newsrv->check.inter;
-
- ret = init_check(&newsrv->agent, PR_O2_LB_AGENT_CHK);
- if (ret) {
- Alert("parsing [%s:%d] : %s.\n", file, linenum, ret);
- err_code |= ERR_ALERT | ERR_ABORT;
- goto out;
- }
-
- newsrv->agent.state |= CHK_ST_CONFIGURED | CHK_ST_ENABLED | CHK_ST_AGENT;
- global.maxsock++;
- }
-
- if (!defsrv) {
- if (newsrv->flags & SRV_F_BACKUP)
- curproxy->srv_bck++;
- else
- curproxy->srv_act++;
-
- srv_lb_commit_status(newsrv);
- }
-#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
- if (!defsrv && newsrv->sni_expr) {
- int code;
- char *err;
-
- err = NULL;
-
- code = server_parse_sni_expr(newsrv, curproxy, &err);
- err_code |= code;
- if (code) {
- display_parser_err(file, linenum, args, cur_arg, &err);
- free(err);
- if (code & ERR_FATAL)
- goto out;
- }
- }
-#endif
+ if (!defsrv)
+ err_code |= server_finalize_init(file, linenum, args, cur_arg, newsrv, curproxy);
+ if (err_code & ERR_FATAL)
+ goto out;
}
free(fqdn);
return 0;
--
2.1.4
>From 43a0bece055224dc05a284d12e59a2dc2f1f97ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20L=C3=A9caille?= <[email protected]>
Date: Thu, 30 Mar 2017 14:18:30 +0200
Subject: [PATCH 2/6] MINOR: server: Extract the code responsible of copying
default-server settings.
This patch moves the code responsible of copying default server settings
to a new server instance from parse_server() function to new defsrv_*_cpy()
functions which may be used both during server lines parsing and during server
templates initializations to come.
These defsrv_*_cpy() do not make any reference to anything else than default
server settings.
---
src/server.c | 334 ++++++++++++++++++++++++++++++++++-------------------------
1 file changed, 191 insertions(+), 143 deletions(-)
diff --git a/src/server.c b/src/server.c
index c9a19ed..cd3a2b4 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1575,6 +1575,193 @@ static void display_parser_err(const char *file, int linenum, char **args, int c
file, linenum, args[0], args[1], args[cur_arg]);
}
+static void srv_conn_src_sport_range_cpy(struct server *srv,
+ struct server *src)
+{
+ int range_sz;
+
+ range_sz = src->conn_src.sport_range->size;
+ if (range_sz > 0) {
+ srv->conn_src.sport_range = port_range_alloc_range(range_sz);
+ if (srv->conn_src.sport_range != NULL) {
+ int i;
+
+ for (i = 0; i < range_sz; i++) {
+ srv->conn_src.sport_range->ports[i] =
+ src->conn_src.sport_range->ports[i];
+ }
+ }
+ }
+}
+
+/*
+ * Copy <src> server connection source settings to <srv> server everything needed.
+ */
+static void srv_conn_src_cpy(struct server *srv, struct server *src)
+{
+ srv->conn_src.opts = src->conn_src.opts;
+ srv->conn_src.source_addr = src->conn_src.source_addr;
+
+ /* Source port range copy. */
+ if (src->conn_src.sport_range != NULL)
+ srv_conn_src_sport_range_cpy(srv, src);
+
+#ifdef CONFIG_HAP_TRANSPARENT
+ if (src->conn_src.bind_hdr_name != NULL) {
+ srv->conn_src.bind_hdr_name = strdup(src->conn_src.bind_hdr_name);
+ srv->conn_src.bind_hdr_len = strlen(src->conn_src.bind_hdr_name);
+ }
+ srv->conn_src.bind_hdr_occ = src->conn_src.bind_hdr_occ;
+ srv->conn_src.tproxy_addr = src->conn_src.tproxy_addr;
+#endif
+ if (src->conn_src.iface_name != NULL)
+ srv->conn_src.iface_name = strdup(src->conn_src.iface_name);
+}
+
+/*
+ * Copy <src> server SSL settings to <srv> server allocating
+ * everything needed.
+ */
+#if defined(USE_OPENSSL)
+static void srv_ssl_settings_cpy(struct server *srv, struct server *src)
+{
+ if (src->ssl_ctx.ca_file != NULL)
+ srv->ssl_ctx.ca_file = strdup(src->ssl_ctx.ca_file);
+ if (src->ssl_ctx.crl_file != NULL)
+ srv->ssl_ctx.crl_file = strdup(src->ssl_ctx.crl_file);
+ if (src->ssl_ctx.client_crt != NULL)
+ srv->ssl_ctx.client_crt = strdup(src->ssl_ctx.client_crt);
+
+ srv->ssl_ctx.verify = src->ssl_ctx.verify;
+
+ if (src->ssl_ctx.verify_host != NULL)
+ srv->ssl_ctx.verify_host = strdup(src->ssl_ctx.verify_host);
+ if (src->ssl_ctx.ciphers != NULL)
+ srv->ssl_ctx.ciphers = strdup(src->ssl_ctx.ciphers);
+ if (src->sni_expr != NULL)
+ srv->sni_expr = strdup(src->sni_expr);
+}
+#endif
+
+/*
+ * Copy <src> server settings to <srv> server allocating
+ * everything needed.
+ */
+static void srv_settings_cpy(struct server *srv, struct server *src)
+{
+ /* Connection source settings copy */
+ srv_conn_src_cpy(srv, src);
+
+ srv->pp_opts = src->pp_opts;
+ if (src->rdr_pfx != NULL) {
+ srv->rdr_pfx = strdup(src->rdr_pfx);
+ srv->rdr_len = src->rdr_len;
+ }
+ if (src->cookie != NULL) {
+ srv->cookie = strdup(src->cookie);
+ srv->cklen = src->cklen;
+ }
+ srv->use_ssl = src->use_ssl;
+ srv->check.addr = srv->agent.addr = src->check.addr;
+ srv->check.use_ssl = src->check.use_ssl;
+ srv->check.port = src->check.port;
+ /* Note: 'flags' field has potentially been already initialized. */
+ srv->flags |= src->flags;
+ srv->do_check = src->do_check;
+ srv->do_agent = src->do_agent;
+ if (srv->check.port)
+ srv->flags |= SRV_F_CHECKPORT;
+ srv->check.inter = src->check.inter;
+ srv->check.fastinter = src->check.fastinter;
+ srv->check.downinter = src->check.downinter;
+ srv->agent.use_ssl = src->agent.use_ssl;
+ srv->agent.port = src->agent.port;
+ if (src->agent.send_string != NULL)
+ srv->agent.send_string = strdup(src->agent.send_string);
+ srv->agent.send_string_len = src->agent.send_string_len;
+ srv->agent.inter = src->agent.inter;
+ srv->agent.fastinter = src->agent.fastinter;
+ srv->agent.downinter = src->agent.downinter;
+ srv->maxqueue = src->maxqueue;
+ srv->minconn = src->minconn;
+ srv->maxconn = src->maxconn;
+ srv->slowstart = src->slowstart;
+ srv->observe = src->observe;
+ srv->onerror = src->onerror;
+ srv->onmarkeddown = src->onmarkeddown;
+ srv->onmarkedup = src->onmarkedup;
+ if (src->trackit != NULL)
+ srv->trackit = strdup(src->trackit);
+ srv->consecutive_errors_limit = src->consecutive_errors_limit;
+ srv->uweight = srv->iweight = src->iweight;
+
+ srv->check.send_proxy = src->check.send_proxy;
+ /* health: up, but will fall down at first failure */
+ srv->check.rise = srv->check.health = src->check.rise;
+ srv->check.fall = src->check.fall;
+
+ /* Here we check if 'disabled' is the default server state */
+ if (src->admin & (SRV_ADMF_CMAINT | SRV_ADMF_FMAINT)) {
+ srv->admin |= SRV_ADMF_CMAINT | SRV_ADMF_FMAINT;
+ srv->state = SRV_ST_STOPPED;
+ srv->check.state |= CHK_ST_PAUSED;
+ srv->check.health = 0;
+ }
+
+ /* health: up but will fall down at first failure */
+ srv->agent.rise = srv->agent.health = src->agent.rise;
+ srv->agent.fall = src->agent.fall;
+
+ if (src->resolvers_id != NULL)
+ srv->resolvers_id = strdup(src->resolvers_id);
+ srv->dns_opts.family_prio = src->dns_opts.family_prio;
+ if (srv->dns_opts.family_prio == AF_UNSPEC)
+ srv->dns_opts.family_prio = AF_INET6;
+ memcpy(srv->dns_opts.pref_net,
+ src->dns_opts.pref_net,
+ sizeof srv->dns_opts.pref_net);
+ srv->dns_opts.pref_net_nb = src->dns_opts.pref_net_nb;
+
+ srv->init_addr_methods = src->init_addr_methods;
+ srv->init_addr = src->init_addr;
+#if defined(USE_OPENSSL)
+ srv_ssl_settings_cpy(srv, src);
+#endif
+#ifdef TCP_USER_TIMEOUT
+ srv->tcp_ut = src->tcp_ut;
+#endif
+}
+
+static struct server *new_server(struct proxy *proxy)
+{
+ struct server *srv;
+
+ srv = calloc(1, sizeof *srv);
+ if (!srv)
+ return NULL;
+
+ srv->obj_type = OBJ_TYPE_SERVER;
+ srv->proxy = proxy;
+ LIST_INIT(&srv->actconns);
+ LIST_INIT(&srv->pendconns);
+ LIST_INIT(&srv->priv_conns);
+ LIST_INIT(&srv->idle_conns);
+ LIST_INIT(&srv->safe_conns);
+
+ srv->state = SRV_ST_RUNNING; /* early server setup */
+ srv->last_change = now.tv_sec;
+
+ srv->check.status = HCHK_STATUS_INI;
+ srv->check.server = srv;
+ srv->check.tcpcheck_rules = &proxy->tcpcheck_rules;
+
+ srv->agent.status = HCHK_STATUS_INI;
+ srv->agent.server = srv;
+ srv->xprt = srv->check.xprt = srv->agent.xprt = xprt_get(XPRT_RAW);
+
+ return srv;
+}
+
int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy)
{
struct server *newsrv = NULL;
@@ -1617,7 +1804,8 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
struct protocol *proto;
struct dns_resolution *curr_resolution;
- if ((newsrv = calloc(1, sizeof(*newsrv))) == NULL) {
+ newsrv = new_server(curproxy);
+ if (!newsrv) {
Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
err_code |= ERR_ALERT | ERR_ABORT;
goto out;
@@ -1626,20 +1814,8 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
/* the servers are linked backwards first */
newsrv->next = curproxy->srv;
curproxy->srv = newsrv;
- newsrv->proxy = curproxy;
newsrv->conf.file = strdup(file);
newsrv->conf.line = linenum;
-
- newsrv->obj_type = OBJ_TYPE_SERVER;
- LIST_INIT(&newsrv->actconns);
- LIST_INIT(&newsrv->pendconns);
- LIST_INIT(&newsrv->priv_conns);
- LIST_INIT(&newsrv->idle_conns);
- LIST_INIT(&newsrv->safe_conns);
- newsrv->flags = 0;
- newsrv->admin = 0;
- newsrv->state = SRV_ST_RUNNING; /* early server setup */
- newsrv->last_change = now.tv_sec;
newsrv->id = strdup(args[1]);
/* several ways to check the port component :
@@ -1707,7 +1883,6 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
skip_name_resolution:
newsrv->addr = *sk;
newsrv->svc_port = port;
- newsrv->xprt = newsrv->check.xprt = newsrv->agent.xprt = xprt_get(XPRT_RAW);
if (!newsrv->hostname && !protocol_by_family(newsrv->addr.ss_family)) {
Alert("parsing [%s:%d] : Unknown protocol family %d '%s'\n",
@@ -1716,135 +1891,8 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
goto out;
}
- /*
- * In this section we copy default-server connection source settings to
- * the new server object connection source
- * (newsrv->conn_src <- curproxy->defsrv.conn_src).
- */
- newsrv->conn_src.opts = curproxy->defsrv.conn_src.opts;
- newsrv->conn_src.source_addr = curproxy->defsrv.conn_src.source_addr;
- if (curproxy->defsrv.conn_src.sport_range != NULL) {
- int i, def_sport_range_sz;
- struct server *default_srv;
-
- default_srv = &curproxy->defsrv;
- def_sport_range_sz = default_srv->conn_src.sport_range->size;
- if (def_sport_range_sz > 0) {
- newsrv->conn_src.sport_range = port_range_alloc_range(def_sport_range_sz);
- if (newsrv->conn_src.sport_range) {
- for (i = 0; i < def_sport_range_sz; i++)
- newsrv->conn_src.sport_range->ports[i] = default_srv->conn_src.sport_range->ports[i];
- }
- }
- }
-#ifdef CONFIG_HAP_TRANSPARENT
- if (curproxy->defsrv.conn_src.bind_hdr_name != NULL) {
- newsrv->conn_src.bind_hdr_name = strdup(curproxy->defsrv.conn_src.bind_hdr_name);
- newsrv->conn_src.bind_hdr_len = strlen(curproxy->defsrv.conn_src.bind_hdr_name);
- }
- newsrv->conn_src.bind_hdr_occ = curproxy->defsrv.conn_src.bind_hdr_occ;
- newsrv->conn_src.tproxy_addr = curproxy->defsrv.conn_src.tproxy_addr;
-#endif
- if (curproxy->defsrv.conn_src.iface_name != NULL)
- newsrv->conn_src.iface_name = strdup(curproxy->defsrv.conn_src.iface_name);
-
- newsrv->pp_opts = curproxy->defsrv.pp_opts;
- if (curproxy->defsrv.rdr_pfx != NULL) {
- newsrv->rdr_pfx = strdup(curproxy->defsrv.rdr_pfx);
- newsrv->rdr_len = curproxy->defsrv.rdr_len;
- }
- if (curproxy->defsrv.cookie != NULL) {
- newsrv->cookie = strdup(curproxy->defsrv.cookie);
- newsrv->cklen = curproxy->defsrv.cklen;
- }
- newsrv->use_ssl = curproxy->defsrv.use_ssl;
- newsrv->check.addr = newsrv->agent.addr = curproxy->defsrv.check.addr;
- newsrv->check.use_ssl = curproxy->defsrv.check.use_ssl;
- newsrv->check.port = curproxy->defsrv.check.port;
- /* Note: 'flags' field has potentially been already initialized. */
- newsrv->flags |= curproxy->defsrv.flags;
- newsrv->do_check = curproxy->defsrv.do_check;
- newsrv->do_agent = curproxy->defsrv.do_agent;
- if (newsrv->check.port)
- newsrv->flags |= SRV_F_CHECKPORT;
- newsrv->check.inter = curproxy->defsrv.check.inter;
- newsrv->check.fastinter = curproxy->defsrv.check.fastinter;
- newsrv->check.downinter = curproxy->defsrv.check.downinter;
- newsrv->agent.use_ssl = curproxy->defsrv.agent.use_ssl;
- newsrv->agent.port = curproxy->defsrv.agent.port;
- if (curproxy->defsrv.agent.send_string != NULL)
- newsrv->agent.send_string = strdup(curproxy->defsrv.agent.send_string);
- newsrv->agent.send_string_len = curproxy->defsrv.agent.send_string_len;
- newsrv->agent.inter = curproxy->defsrv.agent.inter;
- newsrv->agent.fastinter = curproxy->defsrv.agent.fastinter;
- newsrv->agent.downinter = curproxy->defsrv.agent.downinter;
- newsrv->maxqueue = curproxy->defsrv.maxqueue;
- newsrv->minconn = curproxy->defsrv.minconn;
- newsrv->maxconn = curproxy->defsrv.maxconn;
- newsrv->slowstart = curproxy->defsrv.slowstart;
- newsrv->observe = curproxy->defsrv.observe;
- newsrv->onerror = curproxy->defsrv.onerror;
- newsrv->onmarkeddown = curproxy->defsrv.onmarkeddown;
- newsrv->onmarkedup = curproxy->defsrv.onmarkedup;
- if (curproxy->defsrv.trackit != NULL)
- newsrv->trackit = strdup(curproxy->defsrv.trackit);
- newsrv->consecutive_errors_limit
- = curproxy->defsrv.consecutive_errors_limit;
- newsrv->uweight = newsrv->iweight
- = curproxy->defsrv.iweight;
-
- newsrv->check.status = HCHK_STATUS_INI;
- newsrv->check.send_proxy = curproxy->defsrv.check.send_proxy;
- newsrv->check.rise = curproxy->defsrv.check.rise;
- newsrv->check.fall = curproxy->defsrv.check.fall;
- newsrv->check.health = newsrv->check.rise; /* up, but will fall down at first failure */
- /* Here we check if 'disabled' is the default server state */
- if (curproxy->defsrv.admin & (SRV_ADMF_CMAINT | SRV_ADMF_FMAINT)) {
- newsrv->admin |= SRV_ADMF_CMAINT | SRV_ADMF_FMAINT;
- newsrv->state = SRV_ST_STOPPED;
- newsrv->check.state |= CHK_ST_PAUSED;
- newsrv->check.health = 0;
- }
- newsrv->check.server = newsrv;
- newsrv->check.tcpcheck_rules = &curproxy->tcpcheck_rules;
-
- newsrv->agent.status = HCHK_STATUS_INI;
- newsrv->agent.rise = curproxy->defsrv.agent.rise;
- newsrv->agent.fall = curproxy->defsrv.agent.fall;
- newsrv->agent.health = newsrv->agent.rise; /* up, but will fall down at first failure */
- newsrv->agent.server = newsrv;
- if (curproxy->defsrv.resolvers_id != NULL)
- newsrv->resolvers_id = strdup(curproxy->defsrv.resolvers_id);
- newsrv->dns_opts.family_prio = curproxy->defsrv.dns_opts.family_prio;
- if (newsrv->dns_opts.family_prio == AF_UNSPEC)
- newsrv->dns_opts.family_prio = AF_INET6;
- memcpy(newsrv->dns_opts.pref_net,
- curproxy->defsrv.dns_opts.pref_net,
- sizeof(newsrv->dns_opts.pref_net));
- newsrv->dns_opts.pref_net_nb = curproxy->defsrv.dns_opts.pref_net_nb;
- newsrv->init_addr_methods = curproxy->defsrv.init_addr_methods;
- newsrv->init_addr = curproxy->defsrv.init_addr;
-#if defined(USE_OPENSSL)
- /* SSL config. */
- if (curproxy->defsrv.ssl_ctx.ca_file != NULL)
- newsrv->ssl_ctx.ca_file = strdup(curproxy->defsrv.ssl_ctx.ca_file);
- if (curproxy->defsrv.ssl_ctx.crl_file != NULL)
- newsrv->ssl_ctx.crl_file = strdup(curproxy->defsrv.ssl_ctx.crl_file);
- if (curproxy->defsrv.ssl_ctx.client_crt != NULL)
- newsrv->ssl_ctx.client_crt = strdup(curproxy->defsrv.ssl_ctx.client_crt);
- newsrv->ssl_ctx.verify = curproxy->defsrv.ssl_ctx.verify;
- if (curproxy->defsrv.ssl_ctx.verify_host != NULL)
- newsrv->ssl_ctx.verify_host = strdup(curproxy->defsrv.ssl_ctx.verify_host);
- if (curproxy->defsrv.ssl_ctx.ciphers != NULL)
- newsrv->ssl_ctx.ciphers = strdup(curproxy->defsrv.ssl_ctx.ciphers);
- if (curproxy->defsrv.sni_expr != NULL)
- newsrv->sni_expr = strdup(curproxy->defsrv.sni_expr);
-#endif
-
-#ifdef TCP_USER_TIMEOUT
- newsrv->tcp_ut = curproxy->defsrv.tcp_ut;
-#endif
-
+ /* Copy default server settings to new server settings. */
+ srv_settings_cpy(newsrv, &curproxy->defsrv);
cur_arg = 3;
} else {
newsrv = &curproxy->defsrv;
--
2.1.4
>From a33291931e26c88330cf8722ccb5e399b8284d7e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20L=C3=A9caille?= <[email protected]>
Date: Thu, 20 Apr 2017 12:17:50 +0200
Subject: [PATCH 1/6] BUG/MINOR: server: missing default server 'resolvers'
setting duplication.
'resolvers' setting was not duplicated from default server setting to
new server instances when parsing 'server' lines.
This fix is simple: strdup() default resolvers <id> string argument after
having allocated a new server when parsing 'server' lines.
This patch must be backported to 1.7 and 1.6.
---
src/server.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/server.c b/src/server.c
index 878293f..c9a19ed 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1813,6 +1813,8 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
newsrv->agent.fall = curproxy->defsrv.agent.fall;
newsrv->agent.health = newsrv->agent.rise; /* up, but will fall down at first failure */
newsrv->agent.server = newsrv;
+ if (curproxy->defsrv.resolvers_id != NULL)
+ newsrv->resolvers_id = strdup(curproxy->defsrv.resolvers_id);
newsrv->dns_opts.family_prio = curproxy->defsrv.dns_opts.family_prio;
if (newsrv->dns_opts.family_prio == AF_UNSPEC)
newsrv->dns_opts.family_prio = AF_INET6;
@@ -1939,6 +1941,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
cur_arg += 2;
}
else if (!strcmp(args[cur_arg], "resolvers")) {
+ free(newsrv->resolvers_id);
newsrv->resolvers_id = strdup(args[cur_arg + 1]);
cur_arg += 2;
}
--
2.1.4