}
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";
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
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;
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;
}
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;
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;
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,
"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);
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);
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);
.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);
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)
}
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;
}
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)
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);
}
const char *service;
guid_128_t conn_guid;
struct ip_addr ip;
+ struct ip_addr dest_ip;
pid_t pid;
};