]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
anvil, doveadm: Add support for tracking proxy session destination IP
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 17 Jan 2022 10:59:30 +0000 (11:59 +0100)
committerTimo Sirainen <timo.sirainen@open-xchange.com>
Tue, 8 Feb 2022 09:48:24 +0000 (10:48 +0100)
src/anvil/anvil-connection.c
src/anvil/connect-limit.c
src/anvil/connect-limit.h
src/anvil/test-connect-limit.c
src/doveadm/doveadm-who.c
src/doveadm/doveadm-who.h

index 92b14b8cb21f896ae4ef1c1dd0f63e0238de222e..8d6b3725dfaf3a5329b5d256905107fad65601dc 100644 (file)
@@ -121,13 +121,24 @@ anvil_connection_request(struct anvil_connection *conn,
                        }
                        args++;
                }
+               struct ip_addr dest_ip;
+               i_zero(&dest_ip);
+               if (args[0] != NULL) {
+                       if (args[0][0] != '\0' &&
+                           net_addr2ip(args[0], &dest_ip) < 0) {
+                               *error_r = "CONNECT: Invalid dest_ip";
+                               return -1;
+                       }
+                       args++;
+               }
                const char *const *alt_usernames = NULL;
                if (args[0] != NULL) {
                        alt_usernames = t_strsplit_tabescaped(args[0]);
                        args++;
                }
                connect_limit_connect(connect_limit, pid, &key,
-                                     conn_guid, kick_type, alt_usernames);
+                                     conn_guid, kick_type, &dest_ip,
+                                     alt_usernames);
        } else if (strcmp(cmd, "DISCONNECT") == 0) {
                if (args[0] == NULL || args[1] == NULL) {
                        *error_r = "DISCONNECT: Not enough parameters";
index 1b05e0feba21c873dcee05889442081ff663caef..c339e122f3960f7d1c1382a493d8b42c27238d6c 100644 (file)
@@ -46,6 +46,7 @@ struct session {
        struct userip *userip;
        struct process *process;
        guid_128_t conn_guid;
+       struct ip_addr dest_ip;
 
        /* Fields in the same order as connect_limit.alt_username_fields.
           Note that these may be session-specific, which is why they're not in
@@ -350,6 +351,7 @@ void connect_limit_connect(struct connect_limit *limit, pid_t pid,
                           const struct connect_limit_key *key,
                           const guid_128_t conn_guid,
                           enum kick_type kick_type,
+                          const struct ip_addr *dest_ip,
                           const char *const *alt_usernames)
 {
        struct session *session, *first_user_session;
@@ -362,12 +364,14 @@ void connect_limit_connect(struct connect_limit *limit, pid_t pid,
        session = hash_table_lookup(limit->session_hash, conn_guid);
        if (session != NULL) {
                i_error("connect limit: connection for duplicate connection GUID %s "
-                       "(pid=%s -> %s, user=%s -> %s, service=%s -> %s, ip=%s -> %s)",
+                       "(pid=%s -> %s, user=%s -> %s, service=%s -> %s, "
+                       "ip=%s -> %s, dest_ip=%s -> %s)",
                        guid_128_to_string(conn_guid),
                        dec2str(session->process->pid), dec2str(pid),
                        session->userip->username, key->username,
                        session->userip->service, key->service,
-                       net_ip2addr(&session->userip->ip), net_ip2addr(&key->ip));
+                       net_ip2addr(&session->userip->ip), net_ip2addr(&key->ip),
+                       net_ip2addr(&session->dest_ip), net_ip2addr(dest_ip));
                return;
        }
 
@@ -398,6 +402,8 @@ void connect_limit_connect(struct connect_limit *limit, pid_t pid,
        session = i_new(struct session, 1);
        session->userip = userip;
        guid_128_copy(session->conn_guid, conn_guid);
+       if (dest_ip != NULL)
+               session->dest_ip = *dest_ip;
        T_BEGIN {
                session_set_alt_usernames(limit, session, alt_usernames);
        } T_END;
@@ -525,6 +531,9 @@ void connect_limit_dump(struct connect_limit *limit, struct ostream *output)
                        str_append(str, net_ip2addr(&session->userip->ip));
                str_append_c(str, '\t');
                str_append_tabescaped(str, guid_128_to_string(session->conn_guid));
+               str_append_c(str, '\t');
+               if (session->dest_ip.family != 0)
+                       str_append(str, net_ip2addr(&session->dest_ip));
                str_append_c(str, '\n');
                ret = o_stream_send(output, str_data(str), str_len(str));
        } T_END;
index f0eccb514ff25c26d83998468837cf3539c656d4..5b9ae2c0ebbbcc6946e48bc280271f7d8346243c 100644 (file)
@@ -41,6 +41,7 @@ void connect_limit_connect(struct connect_limit *limit, pid_t pid,
                           const struct connect_limit_key *key,
                           const guid_128_t conn_guid,
                           enum kick_type kick_type,
+                          const struct ip_addr *dest_ip,
                           const char *const *alt_usernames);
 void connect_limit_disconnect(struct connect_limit *limit, pid_t pid,
                              const struct connect_limit_key *key,
index af42eb1465b46290bf7bde31dcd4aa72129a0dc4..f999fc6bf4e08a312bc741983dbba58c08be9fcc 100644 (file)
@@ -71,10 +71,13 @@ static void test_connect_limit(void)
                "altkey2", "altvalueB",
                NULL
        };
+       struct ip_addr dest_ip;
+       i_zero(&dest_ip);
        test_assert(net_addr2ip("1.2.3.4", &key.ip) == 0);
+       test_assert(net_addr2ip("55.44.33.22", &dest_ip) == 0);
        connect_limit_connect(limit, 501, &key, session1_guid, KICK_TYPE_NONE,
-                             alt_usernames1);
-#define TEST_SESSION1_STR "501\tuser1\tservice1\t1.2.3.4\t"SESSION1_HEX"\n"
+                             &dest_ip, alt_usernames1);
+#define TEST_SESSION1_STR "501\tuser1\tservice1\t1.2.3.4\t"SESSION1_HEX"\t55.44.33.22\n"
        test_session_dump(limit, TEST_SESSION1_STR);
        test_assert(connect_limit_lookup(limit, &key) == 1);
 
@@ -90,9 +93,10 @@ static void test_connect_limit(void)
                NULL
        };
        test_assert(net_addr2ip("1.2.3.4", &key2.ip) == 0);
+       i_zero(&dest_ip);
        connect_limit_connect(limit, 501, &key2, session2_guid, KICK_TYPE_NONE,
-                             alt_usernames2);
-#define TEST_SESSION2_STR "501\tuser1\tservice1\t1.2.3.4\t"SESSION2_HEX"\n"
+                             &dest_ip, alt_usernames2);
+#define TEST_SESSION2_STR "501\tuser1\tservice1\t1.2.3.4\t"SESSION2_HEX"\t\n"
        test_session_dump(limit, TEST_SESSION1_STR TEST_SESSION2_STR);
        test_assert(connect_limit_lookup(limit, &key) == 2);
 
@@ -108,9 +112,10 @@ static void test_connect_limit(void)
                NULL
        };
        test_assert(net_addr2ip("4.3.2.1", &key3.ip) == 0);
+       test_assert(net_addr2ip("1.0.0.2", &dest_ip) == 0);
        connect_limit_connect(limit, 600, &key3, session3_guid, KICK_TYPE_SIGNAL,
-                             alt_usernames3);
-#define TEST_SESSION3_STR "600\tuser2\tservice2\t4.3.2.1\t"SESSION3_HEX"\n"
+                             &dest_ip, alt_usernames3);
+#define TEST_SESSION3_STR "600\tuser2\tservice2\t4.3.2.1\t"SESSION3_HEX"\t1.0.0.2\n"
        test_session_dump(limit, TEST_SESSION1_STR TEST_SESSION2_STR TEST_SESSION3_STR);
        test_assert(connect_limit_lookup(limit, &key) == 2);
        test_assert(connect_limit_lookup(limit, &key3) == 1);
@@ -121,9 +126,10 @@ static void test_connect_limit(void)
                .service = "service3",
        };
        test_assert(net_addr2ip("4.3.2.1", &key4.ip) == 0);
-       test_expect_error_string("connect limit: connection for duplicate connection GUID "SESSION2_HEX" (pid=501 -> 600, user=user1 -> user3, service=service1 -> service3, ip=1.2.3.4 -> 4.3.2.1)");
+       test_assert(net_addr2ip("1.0.0.3", &dest_ip) == 0);
+       test_expect_error_string("connect limit: connection for duplicate connection GUID "SESSION2_HEX" (pid=501 -> 600, user=user1 -> user3, service=service1 -> service3, ip=1.2.3.4 -> 4.3.2.1, dest_ip= -> 1.0.0.3)");
        connect_limit_connect(limit, 600, &key4, session2_guid, KICK_TYPE_SIGNAL,
-                             alt_usernames3);
+                             &dest_ip, alt_usernames3);
        test_expect_no_more_errors();
        test_session_dump(limit, TEST_SESSION1_STR TEST_SESSION2_STR TEST_SESSION3_STR);
 
index ebb454cb8c74e563f5e4cf62134ff710737efb67..be45e7d318dfadcab113c43fbdfc45d78ce4db71 100644 (file)
@@ -83,8 +83,8 @@ static int who_parse_line(const char *line, struct who_line *line_r)
        const char *const *args = t_strsplit_tabescaped(line);
        i_zero(line_r);
 
-       /* <pid> <username> <service> <ip> <conn-guid> */
-       if (str_array_length(args) < 5)
+       /* <pid> <username> <service> <ip> <conn-guid> <dest-ip> */
+       if (str_array_length(args) < 6)
                return -1;
 
        if (str_to_pid(args[0], &line_r->pid) < 0)
@@ -97,6 +97,10 @@ static int who_parse_line(const char *line, struct who_line *line_r)
        }
        if (guid_128_from_string(args[4], line_r->conn_guid) < 0)
                return -1;
+       if (args[5][0] != '\0') {
+               if (net_addr2ip(args[5], &line_r->dest_ip) < 0)
+                       return -1;
+       }
        return 0;
 }
 
@@ -297,6 +301,7 @@ static void who_print_line(struct who_context *ctx,
        doveadm_print(line->service);
        doveadm_print(dec2str(line->pid));
        doveadm_print(net_ip2addr(&line->ip));
+       doveadm_print(net_ip2addr(&line->dest_ip));
 }
 
 static void cmd_who(struct doveadm_cmd_context *cctx)
@@ -331,6 +336,7 @@ static void cmd_who(struct doveadm_cmd_context *cctx)
                doveadm_print_header("service", "proto", 0);
                doveadm_print_header_simple("pid");
                doveadm_print_header_simple("ip");
+               doveadm_print_header_simple("dest_ip");
                who_lookup(&ctx, who_print_line);
        }
 
index ed21df218c77cfa85ef201da26e35aff7f922a0f..474d2039d1bf3cfd129b20958b0fc182bd2e6e31 100644 (file)
@@ -8,6 +8,7 @@ struct who_line {
        const char *service;
        guid_128_t conn_guid;
        struct ip_addr ip;
+       struct ip_addr dest_ip;
        pid_t pid;
 };