From: Amaury Denoyelle Date: Mon, 8 Mar 2021 15:36:46 +0000 (+0100) Subject: REORG: server: use flags for parse_server X-Git-Tag: v2.4-dev13~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=30c0537f5ad5758f7544a63fdc94a52c2042b954;p=thirdparty%2Fhaproxy.git REORG: server: use flags for parse_server Modify the API of parse_server function. Use flags to describe the type of the parsed server instead of discrete arguments. These flags can be used to specify if a server/default-server/server-template is parsed. Additional parameters are also specified (parsing of the address required, resolve of a name must be done immediately). It is now unneeded to use strcmp on args[0] in parse_server. Also, the calls to parse_server are more explicit thanks to the flags. --- diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h index e59ba4de19..647cdae3db 100644 --- a/include/haproxy/server-t.h +++ b/include/haproxy/server-t.h @@ -432,6 +432,12 @@ struct srv_kw_list { struct srv_kw kw[VAR_ARRAY]; }; +#define SRV_PARSE_DEFAULT_SERVER 0x01 /* 'default-server' keyword */ +#define SRV_PARSE_TEMPLATE 0x02 /* 'server-template' keyword */ +#define SRV_PARSE_IN_PEER_SECTION 0x04 /* keyword in a peer section */ +#define SRV_PARSE_PARSE_ADDR 0x08 /* required to parse the server address in the second argument */ +#define SRV_PARSE_INITIAL_RESOLVE 0x10 /* resolve immediately the fqdn to an ip address */ + #endif /* _HAPROXY_SERVER_T_H */ /* diff --git a/include/haproxy/server.h b/include/haproxy/server.h index 518c20a0ff..d3dc1d6442 100644 --- a/include/haproxy/server.h +++ b/include/haproxy/server.h @@ -45,7 +45,7 @@ extern struct dict server_key_dict; 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, const struct proxy *defproxy, int parse_addr, int in_peers_section, int initial_resolve); +int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, const struct proxy *defproxy, int parse_flags); int srv_update_addr(struct server *s, void *ip, int ip_sin_family, const char *updater); const char *srv_update_addr_port(struct server *s, const char *addr, const char *port, char *updater); const char *srv_update_check_addr_port(struct server *s, const char *addr, const char *port); diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c index 07878330f6..aa2b5eb077 100644 --- a/src/cfgparse-listen.c +++ b/src/cfgparse-listen.c @@ -342,10 +342,27 @@ 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") == 0 || - strcmp(args[0], "default-server") == 0 || - strcmp(args[0], "server-template") == 0) { - err_code |= parse_server(file, linenum, args, curproxy, curr_defproxy, 1, 0, 0); + if ((strcmp(args[0], "server") == 0)) { + err_code |= parse_server(file, linenum, args, + curproxy, curr_defproxy, + SRV_PARSE_PARSE_ADDR); + + if (err_code & ERR_FATAL) + goto out; + } + else if (strcmp(args[0], "default-server") == 0) { + err_code |= parse_server(file, linenum, args, + curproxy, curr_defproxy, + SRV_PARSE_DEFAULT_SERVER); + + if (err_code & ERR_FATAL) + goto out; + } + else if (strcmp(args[0], "server-template") == 0) { + err_code |= parse_server(file, linenum, args, + curproxy, curr_defproxy, + SRV_PARSE_TEMPLATE|SRV_PARSE_PARSE_ADDR); + if (err_code & ERR_FATAL) goto out; } diff --git a/src/cfgparse.c b/src/cfgparse.c index f6ff36161d..a718cd6149 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -706,7 +706,8 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) err_code |= ERR_ALERT | ERR_ABORT; goto out; } - err_code |= parse_server(file, linenum, args, curpeers->peers_fe, NULL, 0, 1, 1); + err_code |= parse_server(file, linenum, args, curpeers->peers_fe, NULL, + SRV_PARSE_DEFAULT_SERVER|SRV_PARSE_IN_PEER_SECTION|SRV_PARSE_INITIAL_RESOLVE); } else if (strcmp(args[0], "log") == 0) { if (init_peers_frontend(file, linenum, NULL, curpeers) != 0) { @@ -768,6 +769,7 @@ 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 */ int local_peer, peer; + int parse_addr = 0; peer = *args[0] == 'p'; local_peer = strcmp(args[1], localpeer) == 0; @@ -815,7 +817,9 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) * The server address is parsed only if we are parsing a "peer" line, * or if we are parsing a "server" line and the current peer is not the local one. */ - err_code |= parse_server(file, linenum, args, curpeers->peers_fe, NULL, peer || !local_peer, 1, 1); + parse_addr = (peer || !local_peer) ? SRV_PARSE_PARSE_ADDR : 0; + err_code |= parse_server(file, linenum, args, curpeers->peers_fe, NULL, + SRV_PARSE_IN_PEER_SECTION|parse_addr|SRV_PARSE_INITIAL_RESOLVE); if (!curpeers->peers_fe->srv) { /* Remove the newly allocated peer. */ if (newpeer != curpeers->local) { diff --git a/src/resolvers.c b/src/resolvers.c index f3564927fe..c14b9706ad 100644 --- a/src/resolvers.c +++ b/src/resolvers.c @@ -2971,7 +2971,8 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm) HA_SPIN_INIT(&curr_resolvers->lock); } else if (strcmp(args[0],"server") == 0) { - err_code |= parse_server(file, linenum, args, curr_resolvers->px, NULL, 1, 0, 1); + err_code |= parse_server(file, linenum, args, curr_resolvers->px, NULL, + SRV_PARSE_PARSE_ADDR|SRV_PARSE_INITIAL_RESOLVE); } else if (strcmp(args[0], "nameserver") == 0) { /* nameserver definition */ struct dns_nameserver *newnameserver = NULL; diff --git a/src/server.c b/src/server.c index cbeae85d1a..3c26243f0c 100644 --- a/src/server.c +++ b/src/server.c @@ -2326,161 +2326,155 @@ static int _srv_parse_tmpl_init(struct server *srv, struct proxy *px) * of memory exhaustion, ERR_ABORT is set. If the server cannot be allocated, * will be set to NULL. */ -static int _srv_parse_init(struct server **srv, char **args, int *cur_arg, struct proxy *curproxy, - int parse_addr, int in_peers_section, int initial_resolve, - char **errmsg) +static int _srv_parse_init(struct server **srv, char **args, int *cur_arg, + struct proxy *curproxy, + int parse_flags, char **errmsg) { struct server *newsrv = NULL; const char *err = NULL; int err_code = 0; char *fqdn = NULL; + int tmpl_range_low = 0, tmpl_range_high = 0; *srv = NULL; - if (strcmp(args[0], "server") == 0 || - strcmp(args[0], "peer") == 0 || - strcmp(args[0], "default-server") == 0 || - strcmp(args[0], "server-template") == 0) { - int defsrv = (*args[0] == 'd'); - int srv_kw = !defsrv && (*args[0] == 'p' || strcmp(args[0], "server") == 0); - int srv_tmpl = !defsrv && !srv_kw; - int tmpl_range_low = 0, tmpl_range_high = 0; - - /* There is no mandatory first arguments for default server. */ - if (srv_kw && parse_addr) { - if (!*args[2]) { - /* 'server' line number of argument check. */ - memprintf(errmsg, "'%s' expects and [:] as arguments.", + /* There is no mandatory first arguments for default server. */ + if (parse_flags & SRV_PARSE_PARSE_ADDR) { + if (parse_flags & SRV_PARSE_TEMPLATE) { + if (!*args[3]) { + /* 'server-template' line number of argument check. */ + memprintf(errmsg, "'%s' expects [:] as arguments.", args[0]); err_code |= ERR_ALERT | ERR_FATAL; goto out; } - err = invalid_char(args[1]); + err = invalid_prefix_char(args[1]); } - else if (srv_tmpl) { - if (!*args[3]) { - /* 'server-template' line number of argument check. */ - memprintf(errmsg, "'%s' expects [:] as arguments.", + else { + if (!*args[2]) { + /* 'server' line number of argument check. */ + memprintf(errmsg, "'%s' expects and [:] as arguments.", args[0]); err_code |= ERR_ALERT | ERR_FATAL; goto out; } - err = invalid_prefix_char(args[1]); + err = invalid_char(args[1]); } if (err) { memprintf(errmsg, "character '%c' is not permitted in %s %s '%s'.", - *err, args[0], srv_kw ? "name" : "prefix", args[1]); + *err, args[0], !(parse_flags & SRV_PARSE_TEMPLATE) ? "name" : "prefix", args[1]); err_code |= ERR_ALERT | ERR_FATAL; goto out; } + } - *cur_arg = 2; - if (srv_tmpl) { - /* Parse server-template arg. */ - if (_srv_parse_tmpl_range(newsrv, args[*cur_arg], &tmpl_range_low, &tmpl_range_high) < 0) { - memprintf(errmsg, "Wrong %s number or range arg '%s'.", - args[0], args[*cur_arg]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - (*cur_arg)++; + *cur_arg = 2; + if (parse_flags & SRV_PARSE_TEMPLATE) { + /* Parse server-template arg. */ + if (_srv_parse_tmpl_range(newsrv, args[*cur_arg], &tmpl_range_low, &tmpl_range_high) < 0) { + memprintf(errmsg, "Wrong %s number or range arg '%s'.", + 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; + if (!(parse_flags & SRV_PARSE_DEFAULT_SERVER)) { + struct sockaddr_storage *sk; + int port1, port2, port; - *srv = newsrv = new_server(curproxy); - if (!newsrv) { - memprintf(errmsg, "out of memory."); - err_code |= ERR_ALERT | ERR_ABORT; - goto out; - } + *srv = newsrv = new_server(curproxy); + if (!newsrv) { + memprintf(errmsg, "out of memory."); + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } - if (srv_tmpl) { - newsrv->tmpl_info.nb_low = tmpl_range_low; - newsrv->tmpl_info.nb_high = tmpl_range_high; - } + if (parse_flags & SRV_PARSE_TEMPLATE) { + newsrv->tmpl_info.nb_low = tmpl_range_low; + newsrv->tmpl_info.nb_high = tmpl_range_high; + } - /* 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_kw) - 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) - * - IP: => port=+0, relative - * - IP:N => port=N, absolute - * - 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, NULL, NULL, - errmsg, NULL, &fqdn, - (initial_resolve ? PA_O_RESOLVE : 0) | PA_O_PORT_OK | PA_O_PORT_OFS | PA_O_STREAM | PA_O_XPRT | PA_O_CONNECT); - if (!sk) { - memprintf(errmsg, "'%s %s' : %s", args[0], args[1], *errmsg); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } + /* 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 (!(parse_flags & SRV_PARSE_TEMPLATE)) + 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) + * - IP: => port=+0, relative + * - IP:N => port=N, absolute + * - IP:+N => port=+N, relative + * - IP:-N => port=-N, relative + */ + if (!(parse_flags & SRV_PARSE_PARSE_ADDR)) + goto skip_addr; + + sk = str2sa_range(args[*cur_arg], &port, &port1, &port2, NULL, NULL, + errmsg, NULL, &fqdn, + (parse_flags & SRV_PARSE_INITIAL_RESOLVE ? PA_O_RESOLVE : 0) | PA_O_PORT_OK | PA_O_PORT_OFS | PA_O_STREAM | PA_O_XPRT | PA_O_CONNECT); + if (!sk) { + memprintf(errmsg, "'%s %s' : %s", args[0], args[1], *errmsg); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } - if (!port1 || !port2) { - /* no port specified, +offset, -offset */ - newsrv->flags |= SRV_F_MAPPORTS; - } + if (!port1 || !port2) { + /* no port specified, +offset, -offset */ + newsrv->flags |= SRV_F_MAPPORTS; + } - /* save hostname and create associated name resolution */ - if (fqdn) { - if (fqdn[0] == '_') { /* SRV record */ - /* Check if a SRV request already exists, and if not, create it */ - if ((newsrv->srvrq = find_srvrq_by_name(fqdn, curproxy)) == NULL) - newsrv->srvrq = new_resolv_srvrq(newsrv, fqdn); - if (newsrv->srvrq == NULL) { - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - } - else if (srv_prepare_for_resolution(newsrv, fqdn) == -1) { - memprintf(errmsg, "Can't create DNS resolution for server '%s'", - newsrv->id); + /* save hostname and create associated name resolution */ + if (fqdn) { + if (fqdn[0] == '_') { /* SRV record */ + /* Check if a SRV request already exists, and if not, create it */ + if ((newsrv->srvrq = find_srvrq_by_name(fqdn, curproxy)) == NULL) + newsrv->srvrq = new_resolv_srvrq(newsrv, fqdn); + if (newsrv->srvrq == NULL) { err_code |= ERR_ALERT | ERR_FATAL; goto out; } } - - newsrv->addr = *sk; - newsrv->svc_port = port; - // we don't need to lock the server here, because - // we are in the process of initializing - srv_set_addr_desc(newsrv); - - if (!newsrv->srvrq && !newsrv->hostname && !protocol_by_family(newsrv->addr.ss_family)) { - memprintf(errmsg, "Unknown protocol family %d '%s'", - newsrv->addr.ss_family, args[*cur_arg]); + else if (srv_prepare_for_resolution(newsrv, fqdn) == -1) { + memprintf(errmsg, "Can't create DNS resolution for server '%s'", + newsrv->id); err_code |= ERR_ALERT | ERR_FATAL; 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); - } else { - *srv = newsrv = &curproxy->defsrv; - *cur_arg = 1; - newsrv->resolv_opts.family_prio = AF_INET6; - newsrv->resolv_opts.accept_duplicate_ip = 0; + newsrv->addr = *sk; + newsrv->svc_port = port; + // we don't need to lock the server here, because + // we are in the process of initializing + srv_set_addr_desc(newsrv); + + if (!newsrv->srvrq && !newsrv->hostname && !protocol_by_family(newsrv->addr.ss_family)) { + memprintf(errmsg, "Unknown protocol family %d '%s'", + newsrv->addr.ss_family, args[*cur_arg]); + err_code |= ERR_ALERT | ERR_FATAL; + 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); + } + else { + *srv = newsrv = &curproxy->defsrv; + *cur_arg = 1; + newsrv->resolv_opts.family_prio = AF_INET6; + newsrv->resolv_opts.accept_duplicate_ip = 0; } free(fqdn); @@ -2501,9 +2495,9 @@ out: * A mask of errors is returned. ERR_FATAL is set if the parsing should be * interrupted. */ -static int _srv_parse_kw(struct server *srv, int defsrv, char **args, int *cur_arg, struct proxy *curproxy, - int parse_addr, int in_peers_section, int initial_resolve, - char **errmsg) +static int _srv_parse_kw(struct server *srv, char **args, int *cur_arg, + struct proxy *curproxy, + int parse_flags, char **errmsg) { int err_code = 0; struct srv_kw *kw; @@ -2529,7 +2523,7 @@ static int _srv_parse_kw(struct server *srv, int defsrv, char **args, int *cur_a goto out; } - if (defsrv && !kw->default_ok) { + if ((parse_flags & SRV_PARSE_DEFAULT_SERVER) && !kw->default_ok) { memprintf(errmsg, "'%s' option is not accepted in default-server sections", args[*cur_arg]); err_code = ERR_ALERT; @@ -2606,87 +2600,79 @@ static int _srv_parse_finalize(char **args, int cur_arg, return 0; } -int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, - const struct proxy *defproxy, int parse_addr, int in_peers_section, int initial_resolve) +int parse_server(const char *file, int linenum, char **args, + struct proxy *curproxy, const struct proxy *defproxy, + int parse_flags) { struct server *newsrv = NULL; char *errmsg = NULL; int err_code = 0; - if (strcmp(args[0], "server") == 0 || - strcmp(args[0], "peer") == 0 || - strcmp(args[0], "default-server") == 0 || - strcmp(args[0], "server-template") == 0) { - int cur_arg; - int defsrv = (*args[0] == 'd'); - int srv = !defsrv && (*args[0] == 'p' || strcmp(args[0], "server") == 0); - int srv_tmpl = !defsrv && !srv; - - if (!defsrv && curproxy == defproxy) { - ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - else if (failifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) { - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } + int cur_arg; - if (srv && parse_addr) { - if (!*args[2]) { - if (in_peers_section) - return 0; - } - } - err_code = _srv_parse_init(&newsrv, args, &cur_arg, curproxy, - parse_addr, in_peers_section, initial_resolve, &errmsg); - if (errmsg) { - ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg); - free(errmsg); - } + if (!(parse_flags & SRV_PARSE_DEFAULT_SERVER) && curproxy == defproxy) { + ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + else if (failifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) { + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } - /* the servers are linked backwards first */ - if (newsrv && !defsrv) { - newsrv->next = curproxy->srv; - curproxy->srv = newsrv; - } + if ((parse_flags & (SRV_PARSE_IN_PEER_SECTION|SRV_PARSE_PARSE_ADDR)) == + (SRV_PARSE_IN_PEER_SECTION|SRV_PARSE_PARSE_ADDR)) { + if (!*args[2]) + return 0; + } - if (err_code & ERR_CODE) - goto out; + err_code = _srv_parse_init(&newsrv, args, &cur_arg, curproxy, + parse_flags, &errmsg); + if (errmsg) { + ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg); + free(errmsg); + } + + /* the servers are linked backwards first */ + if (newsrv && !(parse_flags & SRV_PARSE_DEFAULT_SERVER)) { + newsrv->next = curproxy->srv; + curproxy->srv = newsrv; + } - newsrv->conf.file = strdup(file); - newsrv->conf.line = linenum; + if (err_code & ERR_CODE) + goto out; - while (*args[cur_arg]) { - errmsg = NULL; - err_code |= _srv_parse_kw(newsrv, defsrv, args, &cur_arg, - curproxy, - parse_addr, in_peers_section, initial_resolve, &errmsg); + newsrv->conf.file = strdup(file); + newsrv->conf.line = linenum; - if (err_code & ERR_ALERT) { - display_parser_err(file, linenum, args, cur_arg, err_code, &errmsg); - free(errmsg); - } + while (*args[cur_arg]) { + errmsg = NULL; + err_code = _srv_parse_kw(newsrv, args, &cur_arg, curproxy, + parse_flags, &errmsg); - if (err_code & ERR_FATAL) - goto out; + if (err_code & ERR_ALERT) { + display_parser_err(file, linenum, args, cur_arg, err_code, &errmsg); + free(errmsg); } - if (!defsrv) { - err_code |= _srv_parse_finalize(args, cur_arg, newsrv, curproxy, &errmsg); - if (err_code) { - display_parser_err(file, linenum, args, cur_arg, err_code, &errmsg); - free(errmsg); - } + if (err_code & ERR_FATAL) + goto out; + } - if (err_code & ERR_FATAL) - goto out; + if (!(parse_flags & SRV_PARSE_DEFAULT_SERVER)) { + err_code |= _srv_parse_finalize(args, cur_arg, newsrv, curproxy, &errmsg); + if (err_code) { + display_parser_err(file, linenum, args, cur_arg, err_code, &errmsg); + free(errmsg); } - if (srv_tmpl) - _srv_parse_tmpl_init(newsrv, curproxy); + if (err_code & ERR_FATAL) + goto out; } + if (parse_flags & SRV_PARSE_TEMPLATE) + _srv_parse_tmpl_init(newsrv, curproxy); + return 0; out: diff --git a/src/sink.c b/src/sink.c index 88dbe90957..f734b07c93 100644 --- a/src/sink.c +++ b/src/sink.c @@ -812,7 +812,8 @@ int cfg_parse_ring(const char *file, int linenum, char **args, int kwm) } } else if (strcmp(args[0],"server") == 0) { - err_code |= parse_server(file, linenum, args, cfg_sink->forward_px, NULL, 1, 0, 1); + err_code |= parse_server(file, linenum, args, cfg_sink->forward_px, NULL, + SRV_PARSE_PARSE_ADDR|SRV_PARSE_INITIAL_RESOLVE); } else if (strcmp(args[0],"timeout") == 0) { if (!cfg_sink || !cfg_sink->forward_px) {