From 12582eb8e50a88cd9d27b12ed6c97dada227b980 Mon Sep 17 00:00:00 2001 From: Aurelien DARRAGON Date: Thu, 9 Nov 2023 11:19:24 +0100 Subject: [PATCH] MINOR: tools: make str2sa_range() directly return type hints str2sa_range() already allows the caller to provide in order to get a pointer on the protocol matching with the string input thanks to 5fc9328a ("MINOR: tools: make str2sa_range() directly return the protocol") However, as stated into the commit message, there is 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" In this case, we're unable to return protocol because the protocol lookup depends on both the [proto type + xprt type] and the [family type] to be known. While family type might not be directly resolved when fqdn is involved (because family type might be discovered using DNS queries), proto type and xprt type are already known. As such, the caller might be interested in knowing those address related hints even if the address family type is not yet resolved and thus the matching protocol cannot be looked up. Thus in this patch we add the optional net_addr_type (custom type) argument to str2sa_range to enable the caller to check the protocol type and transport type when the function succeeds. --- include/haproxy/tools-t.h | 6 ++++++ include/haproxy/tools.h | 4 ++-- src/cfgparse-listen.c | 6 +++--- src/cfgparse.c | 6 +++--- src/check.c | 2 +- src/cli.c | 2 +- src/hlua.c | 2 +- src/http_client.c | 2 +- src/log.c | 2 +- src/resolvers.c | 2 +- src/server.c | 8 ++++---- src/tcpcheck.c | 2 +- src/tools.c | 16 +++++++++++----- 13 files changed, 36 insertions(+), 24 deletions(-) diff --git a/include/haproxy/tools-t.h b/include/haproxy/tools-t.h index 805ade6a3..32d8193fe 100644 --- a/include/haproxy/tools-t.h +++ b/include/haproxy/tools-t.h @@ -157,4 +157,10 @@ struct net_addr { } addr; }; +/* holds socket and xprt types for a given address */ +struct net_addr_type { + int proto_type; // socket layer + int xprt_type; // transport layer +}; + #endif /* _HAPROXY_TOOLS_T_H */ diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index 2fc92bb90..e3b847905 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -284,8 +284,8 @@ static inline int is_idchar(char c) * address (typically the path to a unix socket). */ 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); + struct protocol **proto, struct net_addr_type *sa_type, + char **err, const char *pfx, char **fqdn, unsigned int opts); /* converts and into a string representation of the address and port. This is sort diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c index 0b6f7fa07..6c7cc6382 100644 --- a/src/cfgparse-listen.c +++ b/src/cfgparse-listen.c @@ -2518,7 +2518,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) 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, NULL, + sk = str2sa_range(args[1], NULL, &port1, &port2, NULL, NULL, NULL, &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_STREAM | PA_O_XPRT | PA_O_CONNECT); if (!sk) { @@ -2852,7 +2852,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) ha_free(&curproxy->conn_src.iface_name); curproxy->conn_src.iface_len = 0; - sk = str2sa_range(args[1], NULL, &port1, &port2, NULL, NULL, + sk = str2sa_range(args[1], NULL, &port1, &port2, NULL, NULL, NULL, &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_STREAM | PA_O_CONNECT); if (!sk) { ha_alert("parsing [%s:%d] : '%s %s' : %s\n", @@ -2926,7 +2926,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) } else { struct sockaddr_storage *sk; - sk = str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, NULL, NULL, + sk = str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, NULL, NULL, NULL, &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_STREAM | PA_O_CONNECT); if (!sk) { ha_alert("parsing [%s:%d] : '%s %s' : %s\n", diff --git a/src/cfgparse.c b/src/cfgparse.c index 11d262455..312b1d709 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -155,7 +155,7 @@ int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf, *next++ = 0; } - ss2 = str2sa_range(str, NULL, &port, &end, &fd, &proto, err, + ss2 = str2sa_range(str, NULL, &port, &end, &fd, &proto, NULL, err, (curproxy == global.cli_fe || curproxy == mworker_proxy) ? 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); @@ -241,7 +241,7 @@ int str2receiver(char *str, struct proxy *curproxy, struct bind_conf *bind_conf, *next++ = 0; } - ss2 = str2sa_range(str, NULL, &port, &end, &fd, &proto, err, + ss2 = str2sa_range(str, NULL, &port, &end, &fd, &proto, NULL, err, curproxy == global.cli_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); @@ -1178,7 +1178,7 @@ 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, &proto, + sk = str2sa_range(args[2], NULL, &port1, &port2, NULL, &proto, NULL, &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_STREAM | PA_O_XPRT | PA_O_CONNECT); if (!sk) { diff --git a/src/check.c b/src/check.c index 91fdbcb8c..51c028189 100644 --- a/src/check.c +++ b/src/check.c @@ -2033,7 +2033,7 @@ 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, NULL, errmsg, NULL, NULL, + sk = str2sa_range(args[*cur_arg+1], NULL, &port1, &port2, NULL, NULL, NULL, errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_STREAM | PA_O_CONNECT); if (!sk) { memprintf(errmsg, "'%s' : %s", args[*cur_arg], *errmsg); diff --git a/src/cli.c b/src/cli.c index 0a78ed780..b176d5232 100644 --- a/src/cli.c +++ b/src/cli.c @@ -3052,7 +3052,7 @@ 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, &proto, + if ((sk = str2sa_range(msg, &port, &port1, &port2, NULL, &proto, NULL, &errmsg, NULL, NULL, PA_O_STREAM)) == 0) { goto error; } diff --git a/src/hlua.c b/src/hlua.c index 7e0580d35..c5a1c615b 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -3228,7 +3228,7 @@ __LJMP static int hlua_socket_connect(struct lua_State *L) csk_ctx->srv = socket_tcp; /* Parse ip address. */ - addr = str2sa_range(ip, NULL, &low, &high, NULL, NULL, NULL, NULL, NULL, PA_O_PORT_OK | PA_O_STREAM); + addr = str2sa_range(ip, NULL, &low, &high, NULL, 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/http_client.c b/src/http_client.c index e8fdf42a1..fca13a297 100644 --- a/src/http_client.c +++ b/src/http_client.c @@ -455,7 +455,7 @@ int httpclient_set_dst(struct httpclient *hc, const char *dst) sockaddr_free(&hc->dst); /* 'sk' is statically allocated (no need to be freed). */ - sk = str2sa_range(dst, NULL, NULL, NULL, NULL, NULL, + sk = str2sa_range(dst, NULL, NULL, NULL, NULL, NULL, NULL, &errmsg, NULL, NULL, PA_O_PORT_OK | PA_O_STREAM | PA_O_XPRT | PA_O_CONNECT); if (!sk) { diff --git a/src/log.c b/src/log.c index 3458f93f9..5efc08b3a 100644 --- a/src/log.c +++ b/src/log.c @@ -1123,7 +1123,7 @@ static int parse_log_target(char *raw, struct log_target *target, char **err) target->type = LOG_TARGET_DGRAM; // default type /* parse the target address */ - sk = str2sa_range(raw, NULL, &port1, &port2, &fd, &proto, + sk = str2sa_range(raw, NULL, &port1, &port2, &fd, &proto, NULL, err, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_RAW_FD | PA_O_DGRAM | PA_O_STREAM | PA_O_DEFAULT_DGRAM); if (!sk) diff --git a/src/resolvers.c b/src/resolvers.c index c820d9cfb..4ef55b913 100644 --- a/src/resolvers.c +++ b/src/resolvers.c @@ -3521,7 +3521,7 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm) } } - sk = str2sa_range(args[2], NULL, &port1, &port2, NULL, &proto, + sk = str2sa_range(args[2], NULL, &port1, &port2, NULL, &proto, NULL, &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_DGRAM | PA_O_STREAM | PA_O_DEFAULT_DGRAM); if (!sk) { ha_alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg); diff --git a/src/server.c b/src/server.c index ca48f2875..80e26ab94 100644 --- a/src/server.c +++ b/src/server.c @@ -1432,7 +1432,7 @@ 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, NULL, + sk = str2sa_range(args[*cur_arg + 1], NULL, &port_low, &port_high, NULL, NULL, NULL, &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_RANGE | PA_O_STREAM | PA_O_CONNECT); if (!sk) { @@ -1520,7 +1520,7 @@ 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, NULL, + sk = str2sa_range(args[*cur_arg + 1], NULL, &port1, &port2, NULL, NULL, NULL, &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_STREAM | PA_O_CONNECT); if (!sk) { @@ -1610,7 +1610,7 @@ 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, NULL, + sk = str2sa_range(args[*cur_arg + 1], NULL, &port_low, &port_high, NULL, NULL, NULL, &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_STREAM | PA_O_CONNECT); if (!sk) { @@ -3006,7 +3006,7 @@ static int _srv_parse_init(struct server **srv, char **args, int *cur_arg, if (!(parse_flags & SRV_PARSE_PARSE_ADDR)) goto skip_addr; - sk = str2sa_range(args[*cur_arg], &port, &port1, &port2, NULL, &newsrv->addr_proto, + sk = str2sa_range(args[*cur_arg], &port, &port1, &port2, NULL, &newsrv->addr_proto, NULL, &errmsg, NULL, &fqdn, (parse_flags & SRV_PARSE_INITIAL_RESOLVE ? PA_O_RESOLVE : 0) | PA_O_PORT_OK | (parse_flags & SRV_PARSE_IN_PEER_SECTION ? PA_O_PORT_MAND : PA_O_PORT_OFS) | diff --git a/src/tcpcheck.c b/src/tcpcheck.c index c00c47fed..d30ecb57e 100644 --- a/src/tcpcheck.c +++ b/src/tcpcheck.c @@ -2413,7 +2413,7 @@ 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, NULL, + sk = str2sa_range(args[cur_arg+1], NULL, &port1, &port2, NULL, NULL, NULL, errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_STREAM | PA_O_CONNECT); if (!sk) { memprintf(errmsg, "'%s' : %s.", args[cur_arg], *errmsg); diff --git a/src/tools.c b/src/tools.c index 45f519ab8..d67356f8e 100644 --- a/src/tools.c +++ b/src/tools.c @@ -947,13 +947,15 @@ struct sockaddr_storage *str2ip2(const char *str, struct sockaddr_storage *sa, i * AF_CUST_EXISTING_FD. * * The matching protocol will be set into if non-null. + * The address protocol and transport types hints which are directly resolved + * will be set into if not 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, - struct protocol **proto, char **err, - const char *pfx, char **fqdn, unsigned int opts) + struct protocol **proto, struct net_addr_type *sa_type, + char **err, const char *pfx, char **fqdn, unsigned int opts) { static THREAD_LOCAL struct sockaddr_storage ss; struct sockaddr_storage *ret = NULL; @@ -963,8 +965,8 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int int portl, porth, porta; int abstract = 0; int new_fd = -1; - enum proto_type proto_type; - int ctrl_type; + enum proto_type proto_type = 0; // to shut gcc warning + int ctrl_type = 0; // to shut gcc warning portl = porth = porta = 0; if (fqdn) @@ -1383,6 +1385,10 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int *fd = new_fd; if (proto) *proto = new_proto; + if (sa_type) { + sa_type->proto_type = proto_type; + sa_type->xprt_type = (ctrl_type == SOCK_DGRAM) ? PROTO_TYPE_DGRAM : PROTO_TYPE_STREAM; + } free(back); return ret; } @@ -6018,7 +6024,7 @@ const char *hash_ipanon(uint32_t scramble, char *ipstring, int hasport) sa = &ss; } else { - sa = str2sa_range(ipstring, NULL, NULL, NULL, NULL, NULL, &errmsg, NULL, NULL, + sa = str2sa_range(ipstring, NULL, NULL, NULL, NULL, NULL, NULL, &errmsg, NULL, NULL, PA_O_PORT_OK | PA_O_STREAM | PA_O_DGRAM | PA_O_XPRT | PA_O_CONNECT | PA_O_PORT_RANGE | PA_O_PORT_OFS | PA_O_RESOLVE); if (sa == NULL) {