MEDIUM: log/balance: support FQDN for UDP log servers
authorAurelien DARRAGON <adarragon@haproxy.com>
Thu, 9 Nov 2023 15:57:01 +0000 (16:57 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 29 Nov 2023 07:59:27 +0000 (08:59 +0100)
In previous log backend implementation, we created a pseudo log target
for each declared log server, and we made the log target's address point
to the actual server address to save some time and prevent unecessary
copies.

But this was done without knowing that when FQDN is involved (more broadly
when dns/resolution is involved), the "port" part of server addr should
not be relied upon, and we should explicitly use ->svc_port for that
purpose.

With that in mind and thanks to the previous commit, some changes were
required: we allocate a dedicated addr within the log target when target
is in DGRAM mode. The addr is first initialized with known values and it
is then updated automatically by _srv_set_inetaddr() during runtime.
(the change is atomic so readers don't need to worry about it)

addr from server "log target" (INET/DGRAM mode) is made of the combination
of server's address (lacking the port part) and server's svc_port.

include/haproxy/log.h
src/log.c
src/server.c

index 497b486..d36e184 100644 (file)
@@ -91,6 +91,7 @@ int postresolve_logger_list(struct list *loggers, const char *section, const cha
 
 struct logger *dup_logger(struct logger *def);
 void free_logger(struct logger *logger);
+void deinit_log_target(struct log_target *target);
 
 /* Parse "log" keyword and update the linked list. */
 int parse_logger(char **args, struct list *loggers, int do_del, const char *file, int linenum, char **err);
index d77f462..96f53bc 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -745,7 +745,7 @@ static inline void init_log_target(struct log_target *target)
        target->resolv_name = NULL;
 }
 
-static void deinit_log_target(struct log_target *target)
+void deinit_log_target(struct log_target *target)
 {
        ha_free(&target->addr);
        if (!(target->flags & LOG_TARGET_FL_RESOLVED))
@@ -1054,15 +1054,33 @@ static int postcheck_log_backend(struct proxy *be)
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto end;
                }
-               srv->log_target->addr = &srv->addr;
-               if (srv->addr_type.proto_type == PROTO_TYPE_DGRAM)
+               init_log_target(srv->log_target);
+               if (srv->addr_type.proto_type == PROTO_TYPE_DGRAM) {
                        srv->log_target->type = LOG_TARGET_DGRAM;
+                       /* Try to allocate log target addr (only used in DGRAM mode) */
+                       srv->log_target->addr = calloc(1, sizeof(*srv->log_target->addr));
+                       if (!srv->log_target->addr) {
+                               memprintf(&msg, "memory error when allocating log server '%s'\n", srv->id);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto end;
+                       }
+                       /* We must initialize it with known addr:svc_port, it will then
+                        * be updated automatically by the server API for runtime changes
+                        */
+                       ipcpy(&srv->addr, srv->log_target->addr);
+                       set_host_port(srv->log_target->addr, srv->svc_port);
+               }
                else {
                        /* for now BUFFER type only supports TCP server to it's almost
-                        * explicit. This will require ring buffer creation during log
-                        * postresolving step.
+                        * explicit
                         */
                        srv->log_target->type = LOG_TARGET_BUFFER;
+                       srv->log_target->sink = sink_new_from_srv(srv, "log backend");
+                       if (!srv->log_target->sink) {
+                               memprintf(&msg, "error when creating sink from '%s' log server", srv->id);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto end;
+                       }
                }
 
                if (target_type == -1)
@@ -1073,14 +1091,7 @@ static int postcheck_log_backend(struct proxy *be)
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto end;
                }
-               if (target_type == LOG_TARGET_BUFFER) {
-                       srv->log_target->sink = sink_new_from_srv(srv, "log backend");
-                       if (!srv->log_target->sink) {
-                               memprintf(&msg, "error when creating sink from '%s' log server", srv->id);
-                               err_code |= ERR_ALERT | ERR_FATAL;
-                               goto end;
-                       }
-               }
+               srv->log_target->flags |= LOG_TARGET_FL_RESOLVED;
                srv->cur_eweight = 1; /* ignore weights, all servers have the same weight */
                _log_backend_srv_queue(srv);
                srv = srv->next;
index 8ff084a..c854fc1 100644 (file)
@@ -177,6 +177,11 @@ void _srv_set_inetaddr(struct server *srv, const struct sockaddr_storage *addr,
 {
        ipcpy(addr, &srv->addr);
        srv->svc_port = svc_port;
+       if (srv->log_target && srv->log_target->type == LOG_TARGET_DGRAM) {
+               /* server is used as a log target, manually update log target addr for DGRAM */
+               ipcpy(addr, srv->log_target->addr);
+               set_host_port(srv->log_target->addr, svc_port);
+       }
 }
 
 /*
@@ -2819,7 +2824,10 @@ void srv_free_params(struct server *srv)
        free(srv->resolvers_id);
        free(srv->addr_node.key);
        free(srv->lb_nodes);
-       free(srv->log_target);
+       if (srv->log_target) {
+               deinit_log_target(srv->log_target);
+               free(srv->log_target);
+       }
 
        if (xprt_get(XPRT_SSL) && xprt_get(XPRT_SSL)->destroy_srv)
                xprt_get(XPRT_SSL)->destroy_srv(srv);