]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: cfgparse: SSL/TLS binding in "peers" sections.
authorFrédéric Lécaille <flecaille@haproxy.com>
Fri, 11 Jan 2019 13:06:12 +0000 (14:06 +0100)
committerWilly Tarreau <w@1wt.eu>
Fri, 18 Jan 2019 13:26:21 +0000 (14:26 +0100)
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
src/cfgparse-listen.c
src/cfgparse.c
src/server.c

index b3a9b877f935377abc0a05c69d8425a0463f3fef..436ffb5d5ef78b6bd328a26b389232fc0120de19 100644 (file)
@@ -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);
index 1af86ded4f0b4122bc840946b759b3195550e77d..2a7ed5337455cd5549eb7055ab9557929b974c52 100644 (file)
@@ -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;
        }
index a5343ea9fb12305d4c1876e244bdcbf392ae662a..a12c4ee29f3c02d7f4c08edb75f5b12c0e186a28 100644 (file)
@@ -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 <linenum> in file <file>
+ * to be added to <peers>.
+ * 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 <listen>, <frontend> or <backend> 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)) {
index cea50c2281ce2f206573c8bd96c9a943a2080212..678b723fcc313abdd1bbcd029e4b36c9bee76129 100644 (file)
@@ -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 <name> and <addr>[:<port>] 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;