From 5fc9328aa2f42e4015090dae71bc2130840ce169 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 16 Sep 2020 18:25:03 +0200 Subject: [PATCH] MINOR: tools: make str2sa_range() directly return the protocol We'll need this so that it can return pointers to stacked protocol in the future (for QUIC). In addition this removes a lot of tests for protocol validity in the callers. Some of them were checked further apart, or after a call to str2listener() and they were simplified as well. There's still a trick, we can fail to return a protocol in case the caller accepts an fqdn for use later. This is what servers do and in this case it is valid to return no protocol. A typical example is: server foo localhost:1111 --- include/haproxy/tools.h | 7 +++---- src/cfgparse-listen.c | 15 ++++++--------- src/cfgparse.c | 36 ++++++++---------------------------- src/check.c | 5 ++--- src/cli.c | 5 ++--- src/hlua.c | 2 +- src/log.c | 2 +- src/server.c | 20 ++++++++------------ src/tcpcheck.c | 5 ++--- src/tools.c | 23 ++++++++++++++++++++++- 10 files changed, 55 insertions(+), 65 deletions(-) diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index 25a66f8fd0..4080d7a5d2 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -241,10 +241,9 @@ static inline int is_idchar(char c) * If is non-null, it is used as a string prefix before any path-based * address (typically the path to a unix socket). */ -struct sockaddr_storage *str2sa_range(const char *str, - int *port, int *low, int *high, int *fd, - char **err, const char *pfx, - char **fqdn, unsigned int opts); +struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int *high, int *fd, + struct protocol **proto, char **err, + const char *pfx, char **fqdn, unsigned int opts); /* converts to a struct in_addr containing a network mask. It can be * passed in dotted form (255.255.255.0) or in CIDR form (24). It returns 1 diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c index d29505a3eb..a2a9911701 100644 --- a/src/cfgparse-listen.c +++ b/src/cfgparse-listen.c @@ -2600,7 +2600,7 @@ stats_error_parsing: else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) err_code |= ERR_WARN; - sk = str2sa_range(args[1], NULL, &port1, &port2, NULL, + sk = str2sa_range(args[1], NULL, &port1, &port2, NULL, &proto, &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_STREAM | PA_O_XPRT); if (!sk) { ha_alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, args[0], errmsg); @@ -2608,8 +2608,7 @@ stats_error_parsing: goto out; } - proto = protocol_by_family(sk->ss_family); - if (!proto || !proto->connect) { + if (!proto->connect) { ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n", file, linenum, args[0], args[1]); err_code |= ERR_ALERT | ERR_FATAL; @@ -2859,7 +2858,7 @@ stats_error_parsing: curproxy->conn_src.iface_name = NULL; curproxy->conn_src.iface_len = 0; - sk = str2sa_range(args[1], NULL, &port1, &port2, NULL, + sk = str2sa_range(args[1], NULL, &port1, &port2, NULL, &proto, &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_STREAM); if (!sk) { ha_alert("parsing [%s:%d] : '%s %s' : %s\n", @@ -2868,8 +2867,7 @@ stats_error_parsing: goto out; } - proto = protocol_by_family(sk->ss_family); - if (!proto || !proto->connect) { + if (!proto->connect) { ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n", file, linenum, args[0], args[1]); err_code |= ERR_ALERT | ERR_FATAL; @@ -2938,7 +2936,7 @@ stats_error_parsing: } else { struct sockaddr_storage *sk; - sk = str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, NULL, + sk = str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, NULL, &proto, &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_STREAM); if (!sk) { ha_alert("parsing [%s:%d] : '%s %s' : %s\n", @@ -2947,8 +2945,7 @@ stats_error_parsing: goto out; } - proto = protocol_by_family(sk->ss_family); - if (!proto || !proto->connect) { + if (!proto->connect) { ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n", file, linenum, args[cur_arg], args[cur_arg+1]); err_code |= ERR_ALERT | ERR_FATAL; diff --git a/src/cfgparse.c b/src/cfgparse.c index c4dd262ff2..b876fbd257 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -127,19 +127,13 @@ int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf, *next++ = 0; } - ss2 = str2sa_range(str, NULL, &port, &end, &fd, err, + ss2 = str2sa_range(str, NULL, &port, &end, &fd, &proto, err, curproxy == global.stats_fe ? NULL : global.unix_bind.prefix, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_PORT_RANGE | PA_O_SOCKET_FD | PA_O_STREAM | PA_O_XPRT); if (!ss2) goto fail; - proto = protocol_by_family(ss2->ss_family); - if (!proto) { - memprintf(err, "unsupported protocol family %d fr address '%s'", ss2->ss_family, str); - goto fail; - } - /* OK the address looks correct */ if (!create_listeners(bind_conf, ss2, port, end, fd, proto, err)) { memprintf(err, "%s for address '%s'.\n", *err, str); @@ -183,19 +177,13 @@ int str2receiver(char *str, struct proxy *curproxy, struct bind_conf *bind_conf, *next++ = 0; } - ss2 = str2sa_range(str, NULL, &port, &end, &fd, err, + ss2 = str2sa_range(str, NULL, &port, &end, &fd, &proto, err, curproxy == global.stats_fe ? NULL : global.unix_bind.prefix, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_PORT_RANGE | PA_O_SOCKET_FD | PA_O_DGRAM | PA_O_XPRT); if (!ss2) goto fail; - proto = protocol_by_family(ss2->ss_family); - if (!proto) { - memprintf(err, "unsupported protocol family %d fr address '%s'", ss2->ss_family, str); - goto fail; - } - /* OK the address looks correct */ if (!create_listeners(bind_conf, ss2, port, end, fd, proto, err)) { memprintf(err, "%s for address '%s'.\n", *err, str); @@ -642,7 +630,7 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) } } newpeer->addr = l->rx.addr; - newpeer->proto = protocol_by_family(newpeer->addr.ss_family); + newpeer->proto = l->rx.proto; cur_arg++; } @@ -1001,7 +989,6 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm) else if (strcmp(args[0], "nameserver") == 0) { /* nameserver definition */ struct sockaddr_storage *sk; int port1, port2; - struct protocol *proto; if (!*args[2]) { ha_alert("parsing [%s:%d] : '%s' expects and [:] as arguments.\n", @@ -1040,21 +1027,14 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm) newnameserver->conf.line = linenum; newnameserver->id = strdup(args[1]); - sk = str2sa_range(args[2], NULL, &port1, &port2, NULL, &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_DGRAM); + sk = str2sa_range(args[2], NULL, &port1, &port2, NULL, NULL, + &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_DGRAM); if (!sk) { ha_alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } - proto = protocol_by_family(sk->ss_family); - if (!proto) { - ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n", - file, linenum, args[0], args[1]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - newnameserver->addr = *sk; } else if (strcmp(args[0], "parse-resolv-conf") == 0) { @@ -1410,15 +1390,15 @@ int cfg_parse_mailers(const char *file, int linenum, char **args, int kwm) newmailer->id = strdup(args[1]); - sk = str2sa_range(args[2], NULL, &port1, &port2, NULL, &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_STREAM | PA_O_XPRT); + sk = str2sa_range(args[2], NULL, &port1, &port2, NULL, &proto, + &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_STREAM | PA_O_XPRT); if (!sk) { ha_alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } - proto = protocol_by_family(sk->ss_family); - if (!proto || !proto->connect || proto->sock_prot != IPPROTO_TCP) { + if (!proto->connect || proto->sock_prot != IPPROTO_TCP) { ha_alert("parsing [%s:%d] : '%s %s' : TCP not supported for this address family.\n", file, linenum, args[0], args[1]); err_code |= ERR_ALERT | ERR_FATAL; diff --git a/src/check.c b/src/check.c index 40788ae98e..be9461e298 100644 --- a/src/check.c +++ b/src/check.c @@ -2638,15 +2638,14 @@ static int srv_parse_addr(char **args, int *cur_arg, struct proxy *curpx, struct goto error; } - sk = str2sa_range(args[*cur_arg+1], NULL, &port1, &port2, NULL, errmsg, NULL, NULL, + sk = str2sa_range(args[*cur_arg+1], NULL, &port1, &port2, NULL, &proto, errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_STREAM); if (!sk) { memprintf(errmsg, "'%s' : %s", args[*cur_arg], *errmsg); goto error; } - proto = protocol_by_family(sk->ss_family); - if (!proto || !proto->connect) { + if (!proto->connect) { memprintf(errmsg, "'%s %s' : connect() not supported for this address family.", args[*cur_arg], args[*cur_arg+1]); goto error; diff --git a/src/cli.c b/src/cli.c index 2892d882f4..f34f9916f2 100644 --- a/src/cli.c +++ b/src/cli.c @@ -2475,15 +2475,14 @@ int mworker_cli_proxy_create() newsrv->conf.line = 0; memprintf(&msg, "sockpair@%d", child->ipc_fd[0]); - if ((sk = str2sa_range(msg, &port, &port1, &port2, NULL, + if ((sk = str2sa_range(msg, &port, &port1, &port2, NULL, &proto, &errmsg, NULL, NULL, PA_O_STREAM)) == 0) { goto error; } free(msg); msg = NULL; - proto = protocol_by_family(sk->ss_family); - if (!proto || !proto->connect) { + if (!proto->connect) { goto error; } diff --git a/src/hlua.c b/src/hlua.c index 5589482b02..390191e05f 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -2534,7 +2534,7 @@ __LJMP static int hlua_socket_connect(struct lua_State *L) } /* Parse ip address. */ - addr = str2sa_range(ip, NULL, &low, &high, NULL, NULL, NULL, NULL, PA_O_PORT_OK | PA_O_STREAM); + addr = str2sa_range(ip, NULL, &low, &high, NULL, NULL, NULL, NULL, NULL, PA_O_PORT_OK | PA_O_STREAM); if (!addr) { xref_unlock(&socket->xref, peer); WILL_LJMP(luaL_error(L, "connect: cannot parse destination address '%s'", ip)); diff --git a/src/log.c b/src/log.c index ee99870515..2a49561075 100644 --- a/src/log.c +++ b/src/log.c @@ -1019,7 +1019,7 @@ int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err) goto done; } - sk = str2sa_range(args[1], NULL, &port1, &port2, &fd, + sk = str2sa_range(args[1], NULL, &port1, &port2, &fd, NULL, err, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_RAW_FD | PA_O_DGRAM); if (!sk) goto error; diff --git a/src/server.c b/src/server.c index 84b66f734c..6c5f172990 100644 --- a/src/server.c +++ b/src/server.c @@ -659,15 +659,14 @@ static int srv_parse_source(char **args, int *cur_arg, } /* 'sk' is statically allocated (no need to be freed). */ - sk = str2sa_range(args[*cur_arg + 1], NULL, &port_low, &port_high, NULL, + sk = str2sa_range(args[*cur_arg + 1], NULL, &port_low, &port_high, NULL, &proto, &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_RANGE | PA_O_STREAM); if (!sk) { memprintf(err, "'%s %s' : %s\n", args[*cur_arg], args[*cur_arg + 1], errmsg); goto err; } - proto = protocol_by_family(sk->ss_family); - if (!proto || !proto->connect) { + if (!proto->connect) { ha_alert("'%s %s' : connect() not supported for this address family.\n", args[*cur_arg], args[*cur_arg + 1]); goto err; @@ -745,15 +744,14 @@ static int srv_parse_source(char **args, int *cur_arg, int port1, port2; /* 'sk' is statically allocated (no need to be freed). */ - sk = str2sa_range(args[*cur_arg + 1], NULL, &port1, &port2, NULL, + sk = str2sa_range(args[*cur_arg + 1], NULL, &port1, &port2, NULL, &proto, &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_STREAM); if (!sk) { ha_alert("'%s %s' : %s\n", args[*cur_arg], args[*cur_arg + 1], errmsg); goto err; } - proto = protocol_by_family(sk->ss_family); - if (!proto || !proto->connect) { + if (!proto->connect) { ha_alert("'%s %s' : connect() not supported for this address family.\n", args[*cur_arg], args[*cur_arg + 1]); goto err; @@ -842,15 +840,14 @@ static int srv_parse_socks4(char **args, int *cur_arg, } /* 'sk' is statically allocated (no need to be freed). */ - sk = str2sa_range(args[*cur_arg + 1], NULL, &port_low, &port_high, NULL, + sk = str2sa_range(args[*cur_arg + 1], NULL, &port_low, &port_high, NULL, &proto, &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_STREAM); if (!sk) { memprintf(err, "'%s %s' : %s\n", args[*cur_arg], args[*cur_arg + 1], errmsg); goto err; } - proto = protocol_by_family(sk->ss_family); - if (!proto || !proto->connect) { + if (!proto->connect) { ha_alert("'%s %s' : connect() not supported for this address family.\n", args[*cur_arg], args[*cur_arg + 1]); goto err; } @@ -2030,7 +2027,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr if (!parse_addr) goto skip_addr; - sk = str2sa_range(args[cur_arg], &port, &port1, &port2, NULL, + sk = str2sa_range(args[cur_arg], &port, &port1, &port2, NULL, &proto, &errmsg, NULL, &fqdn, (initial_resolve ? PA_O_RESOLVE : 0) | PA_O_PORT_OK | PA_O_PORT_OFS | PA_O_STREAM | PA_O_XPRT); if (!sk) { ha_alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg); @@ -2038,8 +2035,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr goto out; } - proto = protocol_by_family(sk->ss_family); - if (!fqdn && (!proto || !proto->connect)) { + if (!fqdn && !proto->connect) { ha_alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n", file, linenum, args[0], args[1]); err_code |= ERR_ALERT | ERR_FATAL; diff --git a/src/tcpcheck.c b/src/tcpcheck.c index 8da89559b8..7d9569c0d3 100644 --- a/src/tcpcheck.c +++ b/src/tcpcheck.c @@ -2224,15 +2224,14 @@ struct tcpcheck_rule *parse_tcpcheck_connect(char **args, int cur_arg, struct pr goto error; } - sk = str2sa_range(args[cur_arg+1], NULL, &port1, &port2, NULL, + sk = str2sa_range(args[cur_arg+1], NULL, &port1, &port2, NULL, &proto, errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_STREAM); if (!sk) { memprintf(errmsg, "'%s' : %s.", args[cur_arg], *errmsg); goto error; } - proto = protocol_by_family(sk->ss_family); - if (!proto || !proto->connect) { + if (!proto->connect) { memprintf(errmsg, "'%s' : connect() not supported for this address family.\n", args[cur_arg]); goto error; diff --git a/src/tools.c b/src/tools.c index 0f0bbae80a..f2553a62a4 100644 --- a/src/tools.c +++ b/src/tools.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -864,13 +865,18 @@ struct sockaddr_storage *str2ip2(const char *str, struct sockaddr_storage *sa, i * the address when cast to sockaddr_in and the address family is * AF_CUST_EXISTING_FD. * + * The matching protocol will be set into if non-null. + * * Any known file descriptor is also assigned to if non-null, otherwise it * is forced to -1. */ -struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int *high, int *fd, char **err, const char *pfx, char **fqdn, unsigned int opts) +struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int *high, int *fd, + struct protocol **proto, char **err, + const char *pfx, char **fqdn, unsigned int opts) { static THREAD_LOCAL struct sockaddr_storage ss; struct sockaddr_storage *ret = NULL; + struct protocol *new_proto = NULL; char *back, *str2; char *port1, *port2; int portl, porth, porta; @@ -1170,6 +1176,19 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int ss.ss_family = AF_CUST_UDP4; } + if (proto) { + /* Note: if the caller asks for a proto, we must find one, + * except if we return with an fqdn that will resolve later, + * in which case the address is not known yet (this is only + * for servers actually). + */ + new_proto = protocol_by_family(ss.ss_family); + if (!new_proto && (!fqdn || !*fqdn)) { + memprintf(err, "unsupported protocol family %d for address '%s'", ss.ss_family, str); + goto out; + } + } + ret = &ss; out: if (port) @@ -1180,6 +1199,8 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int *high = porth; if (fd) *fd = new_fd; + if (proto) + *proto = new_proto; free(back); return ret; } -- 2.39.5