From 355b2033ec0c89660db179b23d6f77b678d8c26d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fr=C3=A9d=C3=A9ric=20L=C3=A9caille?= Date: Fri, 11 Jan 2019 14:06:12 +0100 Subject: [PATCH] MINOR: cfgparse: SSL/TLS binding in "peers" sections. Make "bind" keywork be supported in "peers" sections. All "bind" settings are supported on this line. Add "default-bind" option to parse the binding options excepted the bind address. Do not parse anymore the bind address for local peers on "server" lines. Do not use anymore list_for_each_entry() to set the "peers" section listener parameters because there is only one listener by "peers" section. May be backported to 1.5 and newer. --- include/proto/server.h | 2 +- src/cfgparse-listen.c | 2 +- src/cfgparse.c | 280 ++++++++++++++++++++++++++++++++++------- src/server.c | 10 +- 4 files changed, 245 insertions(+), 49 deletions(-) diff --git a/include/proto/server.h b/include/proto/server.h index b3a9b877f9..436ffb5d5e 100644 --- a/include/proto/server.h +++ b/include/proto/server.h @@ -39,7 +39,7 @@ int srv_downtime(const struct server *s); int srv_lastsession(const struct server *s); int srv_getinter(const struct check *check); -int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy); +int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy, int parse_addr); int update_server_addr(struct server *s, void *ip, int ip_sin_family, const char *updater); const char *update_server_addr_port(struct server *s, const char *addr, const char *port, char *updater); struct server *server_find_by_id(struct proxy *bk, int id); diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c index 1af86ded4f..2a7ed53374 100644 --- a/src/cfgparse-listen.c +++ b/src/cfgparse-listen.c @@ -675,7 +675,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) if (!strcmp(args[0], "server") || !strcmp(args[0], "default-server") || !strcmp(args[0], "server-template")) { - err_code |= parse_server(file, linenum, args, curproxy, &defproxy); + err_code |= parse_server(file, linenum, args, curproxy, &defproxy, 1); if (err_code & ERR_FATAL) goto out; } diff --git a/src/cfgparse.c b/src/cfgparse.c index a5343ea9fb..a12c4ee29f 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -515,11 +515,75 @@ static int init_peers_frontend(const char *file, int linenum, p->id = strdup(id); free(p->conf.file); p->conf.args.file = p->conf.file = strdup(file); - p->conf.args.line = p->conf.line = linenum; + if (linenum != -1) + p->conf.args.line = p->conf.line = linenum; return 0; } +/* Only change ->file, ->line and ->arg struct bind_conf member values + * if already present. + */ +static struct bind_conf *bind_conf_uniq_alloc(struct proxy *p, + const char *file, int line, + const char *arg, struct xprt_ops *xprt) +{ + struct bind_conf *bind_conf; + + if (!LIST_ISEMPTY(&p->conf.bind)) { + bind_conf = LIST_ELEM((&p->conf.bind)->n, typeof(bind_conf), by_fe); + free(bind_conf->file); + bind_conf->file = strdup(file); + bind_conf->line = line; + if (arg) { + free(bind_conf->arg); + bind_conf->arg = strdup(arg); + } + } + else { + bind_conf = bind_conf_alloc(p, file, line, arg, xprt); + } + + return bind_conf; +} + +/* + * Allocate a new struct peer parsed at line in file + * to be added to . + * Returns the new allocated structure if succeeded, NULL if not. + */ +static struct peer *cfg_peers_add_peer(struct peers *peers, + const char *file, int linenum, + const char *id, int local) +{ + struct peer *p; + + p = calloc(1, sizeof *p); + if (!p) { + ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum); + return NULL; + } + + /* the peers are linked backwards first */ + peers->count++; + p->next = peers->remote; + peers->remote = p; + p->conf.file = strdup(file); + p->conf.line = linenum; + p->last_change = now.tv_sec; + p->xprt = xprt_get(XPRT_RAW); + p->sock_init_arg = NULL; + HA_SPIN_INIT(&p->lock); + if (id) + p->id = strdup(id); + if (local) { + p->local = 1; + peers->local = p; + } + + return p; +} + /* * Parse a line in a , or section. * Returns the error code, 0 if OK, or any combination of : @@ -539,15 +603,117 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) struct listener *l; int err_code = 0; char *errmsg = NULL; + static int bind_line, peer_line; + + if (strcmp(args[0], "bind") == 0 || strcmp(args[0], "default-bind") == 0) { + int cur_arg; + static int kws_dumped; + struct bind_conf *bind_conf; + struct bind_kw *kw; + char *kws; + + cur_arg = 1; - if (strcmp(args[0], "default-server") == 0) { if (init_peers_frontend(file, linenum, NULL, curpeers) != 0) { err_code |= ERR_ALERT | ERR_ABORT; goto out; } - err_code |= parse_server(file, linenum, args, curpeers->peers_fe, NULL); + + bind_conf = bind_conf_uniq_alloc(curpeers->peers_fe, file, linenum, + NULL, xprt_get(XPRT_RAW)); + if (*args[0] == 'b') { + struct listener *l; + + if (peer_line) { + ha_alert("parsing [%s:%d] : mixing \"peer\" and \"bind\" line is forbidden\n", file, linenum); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + if (!str2listener(args[1], curpeers->peers_fe, bind_conf, file, linenum, &errmsg)) { + if (errmsg && *errmsg) { + indent_msg(&errmsg, 2); + ha_alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg); + } + else + ha_alert("parsing [%s:%d] : '%s %s' : error encountered while parsing listening address %s.\n", + file, linenum, args[0], args[1], args[2]); + err_code |= ERR_FATAL; + goto out; + } + l = LIST_ELEM(bind_conf->listeners.n, typeof(l), by_bind); + l->maxaccept = 1; + l->maxconn = curpeers->peers_fe->maxconn; + l->backlog = curpeers->peers_fe->backlog; + l->accept = session_accept_fd; + l->analysers |= curpeers->peers_fe->fe_req_ana; + l->default_target = curpeers->peers_fe->default_target; + l->options |= LI_O_UNLIMITED; /* don't make the peers subject to global limits */ + global.maxsock += l->maxconn; + + bind_line = 1; + if (cfg_peers->local) { + newpeer = cfg_peers->local; + } + else { + /* This peer is local. + * Note that we do not set the peer ID. This latter is initialized + * when parsing "peer" or "server" line. + */ + newpeer = cfg_peers_add_peer(curpeers, file, linenum, NULL, 1); + if (!newpeer) { + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + } + newpeer->addr = l->addr; + newpeer->proto = protocol_by_family(newpeer->addr.ss_family); + cur_arg++; + } + + while (*args[cur_arg] && (kw = bind_find_kw(args[cur_arg]))) { + int ret; + + ret = kw->parse(args, cur_arg, curpeers->peers_fe, bind_conf, &errmsg); + err_code |= ret; + if (ret) { + if (errmsg && *errmsg) { + indent_msg(&errmsg, 2); + ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg); + } + else + ha_alert("parsing [%s:%d]: error encountered while processing '%s'\n", + file, linenum, args[cur_arg]); + if (ret & ERR_FATAL) + goto out; + } + cur_arg += 1 + kw->skip; + } + kws = NULL; + if (!kws_dumped) { + kws_dumped = 1; + bind_dump_kws(&kws); + indent_msg(&kws, 4); + } + if (*args[cur_arg] != 0) { + ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section.%s%s\n", + file, linenum, args[cur_arg], cursection, + kws ? " Registered keywords :" : "", kws ? kws: ""); + free(kws); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + } + else if (strcmp(args[0], "default-server") == 0) { + if (init_peers_frontend(file, -1, NULL, curpeers) != 0) { + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + err_code |= parse_server(file, linenum, args, curpeers->peers_fe, NULL, 0); } else if (strcmp(args[0], "peers") == 0) { /* new peers section */ + /* Initialize these static variables when entering a new "peers" section*/ + bind_line = peer_line = 0; if (!*args[1]) { ha_alert("parsing [%s:%d] : missing name for peers section.\n", file, linenum); err_code |= ERR_ALERT | ERR_ABORT; @@ -593,28 +759,51 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) } else if (strcmp(args[0], "peer") == 0 || strcmp(args[0], "server") == 0) { /* peer or server definition */ - if ((newpeer = calloc(1, sizeof(*newpeer))) == NULL) { - ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum); - err_code |= ERR_ALERT | ERR_ABORT; - goto out; - } - - /* the peers are linked backwards first */ - curpeers->count++; - newpeer->next = curpeers->remote; - curpeers->remote = newpeer; - newpeer->conf.file = strdup(file); - newpeer->conf.line = linenum; + int local_peer; - newpeer->last_change = now.tv_sec; - newpeer->id = strdup(args[1]); + local_peer = !strcmp(args[1], localpeer); + /* The local peer may have already partially been parsed on a "bind" line. */ + if (*args[0] == 'p') { + if (bind_line) { + ha_alert("parsing [%s:%d] : mixing \"peer\" and \"bind\" line is forbidden\n", file, linenum); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + peer_line = 1; + } + if (cfg_peers->local && !cfg_peers->local->id && local_peer) { + /* The local peer has already been initialized on a "bind" line. + * Let's use it and store its ID. + */ + newpeer = cfg_peers->local; + newpeer->id = strdup(localpeer); + } + else { + if (local_peer && cfg_peers->local) { + ha_alert("parsing [%s:%d] : '%s %s' : local peer name already referenced at %s:%d. %s\n", + file, linenum, args[0], args[1], + curpeers->peers_fe->conf.file, curpeers->peers_fe->conf.line, cfg_peers->local->id); + err_code |= ERR_FATAL; + goto out; + } + newpeer = cfg_peers_add_peer(curpeers, file, linenum, args[1], local_peer); + if (!newpeer) { + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + } - if (init_peers_frontend(file, linenum, newpeer->id, curpeers) != 0) { + /* Line number and peer ID are updated only if this peer is the local one. */ + if (init_peers_frontend(file, + newpeer->local ? linenum: -1, + newpeer->local ? newpeer->id : NULL, + curpeers) != 0) { err_code |= ERR_ALERT | ERR_ABORT; goto out; } - err_code |= parse_server(file, linenum, args, curpeers->peers_fe, NULL); + /* This initializes curpeer->peers->peers_fe->srv. */ + err_code |= parse_server(file, linenum, args, curpeers->peers_fe, NULL, !local_peer); if (!curpeers->peers_fe->srv) goto out; @@ -624,23 +813,16 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) newpeer->sock_init_arg = NULL; HA_SPIN_INIT(&newpeer->lock); - if (strcmp(newpeer->id, localpeer) != 0) { + if (!newpeer->local) { newpeer->srv = curpeers->peers_fe->srv; goto out; } - if (cfg_peers->local) { - ha_alert("parsing [%s:%d] : '%s %s' : local peer name already referenced at %s:%d.\n", - file, linenum, args[0], args[1], - curpeers->peers_fe->conf.file, curpeers->peers_fe->conf.line); - err_code |= ERR_FATAL; + /* The lines above are reserved to "peer" lines. */ + if (*args[0] == 's') goto out; - } - - /* Current is local peer, it define a frontend */ - newpeer->local = 1; - bind_conf = bind_conf_alloc(curpeers->peers_fe, file, linenum, args[2], xprt_get(XPRT_RAW)); + bind_conf = bind_conf_uniq_alloc(curpeers->peers_fe, file, linenum, args[2], xprt_get(XPRT_RAW)); if (!str2listener(args[2], curpeers->peers_fe, bind_conf, file, linenum, &errmsg)) { if (errmsg && *errmsg) { @@ -653,17 +835,16 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) err_code |= ERR_FATAL; goto out; } - list_for_each_entry(l, &bind_conf->listeners, by_bind) { - l->maxaccept = 1; - l->maxconn = curpeers->peers_fe->maxconn; - l->backlog = curpeers->peers_fe->backlog; - l->accept = session_accept_fd; - l->analysers |= curpeers->peers_fe->fe_req_ana; - l->default_target = curpeers->peers_fe->default_target; - l->options |= LI_O_UNLIMITED; /* don't make the peers subject to global limits */ - global.maxsock += l->maxconn; - } - cfg_peers->local = newpeer; + + l = LIST_ELEM(bind_conf->listeners.n, typeof(l), by_bind); + l->maxaccept = 1; + l->maxconn = curpeers->peers_fe->maxconn; + l->backlog = curpeers->peers_fe->backlog; + l->accept = session_accept_fd; + l->analysers |= curpeers->peers_fe->fe_req_ana; + l->default_target = curpeers->peers_fe->default_target; + l->options |= LI_O_UNLIMITED; /* don't make the peers subject to global limits */ + global.maxsock += l->maxconn; } /* neither "peer" nor "peers" */ else if (!strcmp(args[0], "disabled")) { /* disables this peers section */ curpeers->state = PR_STSTOPPED; @@ -3637,9 +3818,20 @@ out_uri_auth_compat: else { p = curpeers->remote; while (p) { - if (p->srv && p->srv->use_ssl && - xprt_get(XPRT_SSL) && xprt_get(XPRT_SSL)->prepare_srv) - cfgerr += xprt_get(XPRT_SSL)->prepare_srv(p->srv); + if (p->srv) { + if (p->srv->use_ssl && xprt_get(XPRT_SSL) && xprt_get(XPRT_SSL)->prepare_srv) + cfgerr += xprt_get(XPRT_SSL)->prepare_srv(p->srv); + } + else if (!LIST_ISEMPTY(&curpeers->peers_fe->conf.bind)) { + struct list *l; + struct bind_conf *bind_conf; + + l = &curpeers->peers_fe->conf.bind; + bind_conf = LIST_ELEM(l->n, typeof(bind_conf), by_fe); + if (bind_conf->xprt->prepare_bind_conf && + bind_conf->xprt->prepare_bind_conf(bind_conf) < 0) + cfgerr++; + } p = p->next; } if (!peers_init_sync(curpeers)) { diff --git a/src/server.c b/src/server.c index cea50c2281..678b723fcc 100644 --- a/src/server.c +++ b/src/server.c @@ -2078,7 +2078,7 @@ static int server_template_init(struct server *srv, struct proxy *px) return i - srv->tmpl_info.nb_low; } -int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy) +int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy, int parse_addr) { struct server *newsrv = NULL; const char *err = NULL; @@ -2106,7 +2106,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr err_code |= ERR_WARN; /* There is no mandatory first arguments for default server. */ - if (srv) { + if (srv && parse_addr) { if (!*args[2]) { /* 'server' line number of argument check. */ ha_alert("parsing [%s:%d] : '%s' expects and [:] as arguments.\n", @@ -2186,6 +2186,9 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr * - IP:+N => port=+N, relative * - IP:-N => port=-N, relative */ + if (!parse_addr) + goto skip_addr; + sk = str2sa_range(args[cur_arg], &port, &port1, &port2, &errmsg, NULL, &fqdn, 0); if (!sk) { ha_alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg); @@ -2242,10 +2245,11 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr goto out; } + cur_arg++; + skip_addr: /* Copy default server settings to new server settings. */ srv_settings_cpy(newsrv, &curproxy->defsrv, 0); HA_SPIN_INIT(&newsrv->lock); - cur_arg++; } else { newsrv = &curproxy->defsrv; cur_arg = 1; -- 2.39.5