MINOR: tools: make str2sa_range() directly return type hints
authorAurelien DARRAGON <adarragon@haproxy.com>
Thu, 9 Nov 2023 10:19:24 +0000 (11:19 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 10 Nov 2023 16:49:57 +0000 (17:49 +0100)
str2sa_range() already allows the caller to provide <proto> 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.

13 files changed:
include/haproxy/tools-t.h
include/haproxy/tools.h
src/cfgparse-listen.c
src/cfgparse.c
src/check.c
src/cli.c
src/hlua.c
src/http_client.c
src/log.c
src/resolvers.c
src/server.c
src/tcpcheck.c
src/tools.c

index 805ade6..32d8193 100644 (file)
@@ -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 */
index 2fc92bb..e3b8479 100644 (file)
@@ -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 <addr> and <port> into a string representation of the address and port. This is sort
index 0b6f7fa..6c7cc63 100644 (file)
@@ -2518,7 +2518,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, 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 @@ stats_error_parsing:
                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 @@ stats_error_parsing:
                                } 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",
index 11d2624..312b1d7 100644 (file)
@@ -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) {
index 91fdbcb..51c0281 100644 (file)
@@ -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);
index 0a78ed7..b176d52 100644 (file)
--- 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;
                }
index 7e0580d..c5a1c61 100644 (file)
@@ -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));
index e8fdf42..fca13a2 100644 (file)
@@ -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) {
index 3458f93..5efc08b 100644 (file)
--- 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)
index c820d9c..4ef55b9 100644 (file)
@@ -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);
index ca48f28..80e26ab 100644 (file)
@@ -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) |
index c00c47f..d30ecb5 100644 (file)
@@ -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);
index 45f519a..d67356f 100644 (file)
@@ -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 <proto> if non-null.
+ * The address protocol and transport types hints which are directly resolved
+ * will be set into <sa_type> if not NULL.
  *
  * Any known file descriptor is also assigned to <fd> 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) {