aboutsummaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/ndpi_main.c3
-rw-r--r--src/lib/protocols/mail_imap.c65
-rw-r--r--src/lib/protocols/mail_smtp.c97
-rw-r--r--src/lib/protocols/nats.c7
4 files changed, 126 insertions, 46 deletions
diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c
index 907cc019f..0ab5e6c9a 100644
--- a/src/lib/ndpi_main.c
+++ b/src/lib/ndpi_main.c
@@ -7247,7 +7247,8 @@ u_int8_t ndpi_extra_dissection_possible(struct ndpi_detection_module_struct *ndp
case NDPI_PROTOCOL_MAIL_IMAP:
case NDPI_PROTOCOL_MAIL_SMTP:
if(flow->protos.ftp_imap_pop_smtp.password[0] == '\0' &&
- flow->protos.ftp_imap_pop_smtp.auth_tls == 0)
+ flow->protos.ftp_imap_pop_smtp.auth_tls == 0 &&
+ flow->protos.ftp_imap_pop_smtp.auth_done == 0)
return(1);
break;
diff --git a/src/lib/protocols/mail_imap.c b/src/lib/protocols/mail_imap.c
index 7646b9e82..b3c087ea2 100644
--- a/src/lib/protocols/mail_imap.c
+++ b/src/lib/protocols/mail_imap.c
@@ -47,7 +47,7 @@ void ndpi_search_mail_imap_tcp(struct ndpi_detection_module_struct *ndpi_struct,
NDPI_LOG_DBG(ndpi_struct, "search IMAP_IMAP\n");
#ifdef IMAP_DEBUG
- printf("%s() [%s]\n", __FUNCTION__, packet->payload);
+ printf("%s() [%.*s]\n", __FUNCTION__, packet->payload_packet_len, packet->payload);
#endif
if(flow->l4.tcp.mail_imap_starttls == 2) {
@@ -66,8 +66,7 @@ void ndpi_search_mail_imap_tcp(struct ndpi_detection_module_struct *ndpi_struct,
flow->l4.tcp.mail_imap_stage += 1;
saw_command = 1;
} else {
-
- if(flow->l4.tcp.mail_imap_stage < 4) {
+ if(flow->l4.tcp.mail_imap_stage < 5) {
// search for the first space character (end of the tag)
while (i < 20 && i < packet->payload_packet_len) {
if(i > 0 && packet->payload[i] == ' ') {
@@ -121,6 +120,13 @@ void ndpi_search_mail_imap_tcp(struct ndpi_detection_module_struct *ndpi_struct,
&& (packet->payload[command_start + 2] == 'D' || packet->payload[command_start + 2] == 'd')) {
flow->l4.tcp.mail_imap_stage += 1;
saw_command = 1;
+ } else if((packet->payload[command_start] == 'N' || packet->payload[command_start] == 'n')
+ && (packet->payload[command_start + 1] == 'O' || packet->payload[command_start + 1] == 'o')
+ && packet->payload[command_start + 2] == ' ') {
+ flow->l4.tcp.mail_imap_stage += 1;
+ if(flow->l4.tcp.mail_imap_starttls == 1)
+ flow->l4.tcp.mail_imap_starttls = 2;
+ saw_command = 1;
}
}
if((command_start + 10) < packet->payload_packet_len) {
@@ -159,40 +165,29 @@ void ndpi_search_mail_imap_tcp(struct ndpi_detection_module_struct *ndpi_struct,
&& (packet->payload[command_start + 2] == 'G' || packet->payload[command_start + 2] == 'g')
&& (packet->payload[command_start + 3] == 'I' || packet->payload[command_start + 3] == 'i')
&& (packet->payload[command_start + 4] == 'N' || packet->payload[command_start + 4] == 'n')) {
- /* xxxx LOGIN "username" "password" */
- char str[256], *item;
- u_int len = packet->payload_packet_len >= sizeof(str) ? sizeof(str)-1 : packet->payload_packet_len;
+ /* xxxx LOGIN "username" "password"
+ xxxx LOGIN username password */
+ char str[256], *user, *saveptr;
+ u_int len = ndpi_min(packet->payload_packet_len - (command_start + 5), (int)sizeof(str) - 1);
- ndpi_set_risk(ndpi_struct, flow, NDPI_CLEAR_TEXT_CREDENTIALS);
-
- strncpy(str, (const char*)packet->payload, len);
+ strncpy(str, (const char*)packet->payload + command_start + 5, len);
str[len] = '\0';
- item = strchr(str, '"');
- if(item) {
- char *column;
-
- item++;
- column = strchr(item, '"');
+ user = strtok_r(str, " \"\r\n", &saveptr);
+ if(user) {
+ char *pwd;
- if(column) {
- column[0] = '\0';
- snprintf(flow->protos.ftp_imap_pop_smtp.username,
- sizeof(flow->protos.ftp_imap_pop_smtp.username),
- "%s", item);
+ snprintf(flow->protos.ftp_imap_pop_smtp.username,
+ sizeof(flow->protos.ftp_imap_pop_smtp.username),
+ "%s", user);
- column = strchr(&column[1], '"');
- if(column) {
- item = &column[1];
- column = strchr(item, '"');
+ ndpi_set_risk(ndpi_struct, flow, NDPI_CLEAR_TEXT_CREDENTIALS);
- if(column) {
- column[0] = '\0';
- snprintf(flow->protos.ftp_imap_pop_smtp.password,
- sizeof(flow->protos.ftp_imap_pop_smtp.password),
- "%s", item);
- }
- }
+ pwd = strtok_r(NULL, " \"\r\n", &saveptr);
+ if(pwd) {
+ snprintf(flow->protos.ftp_imap_pop_smtp.password,
+ sizeof(flow->protos.ftp_imap_pop_smtp.password),
+ "%s", pwd);
}
}
@@ -242,6 +237,10 @@ void ndpi_search_mail_imap_tcp(struct ndpi_detection_module_struct *ndpi_struct,
&& (packet->payload[command_start + 10] == 'T' || packet->payload[command_start + 10] == 't')
&& (packet->payload[command_start + 11] == 'E' || packet->payload[command_start + 11] == 'e')) {
flow->l4.tcp.mail_imap_stage += 1;
+ /* Authenticate phase may have multiple messages. Ignore them since they are
+ somehow encrypted anyway. */
+ flow->l4.tcp.mail_imap_starttls = 2;
+ flow->detected_protocol_stack[0] = NDPI_PROTOCOL_MAIL_IMAPS;
saw_command = 1;
}
}
@@ -320,7 +319,7 @@ void ndpi_search_mail_imap_tcp(struct ndpi_detection_module_struct *ndpi_struct,
if((flow->l4.tcp.mail_imap_stage == 3)
|| (flow->l4.tcp.mail_imap_stage == 5)
|| (flow->l4.tcp.mail_imap_stage == 7)
- ) {
+ ) {
if((flow->protos.ftp_imap_pop_smtp.username[0] != '\0')
|| (flow->l4.tcp.mail_imap_stage >= 7)) {
NDPI_LOG_INFO(ndpi_struct, "found MAIL_IMAP\n");
@@ -344,7 +343,7 @@ void ndpi_search_mail_imap_tcp(struct ndpi_detection_module_struct *ndpi_struct,
// skip over possible authentication hashes etc. that cannot be identified as imap commands or responses
// if the packet count is low enough and at least one command or response was seen before
if((packet->payload_packet_len >= 2 && ntohs(get_u_int16_t(packet->payload, packet->payload_packet_len - 2)) == 0x0d0a)
- && flow->packet_counter < 6 && flow->l4.tcp.mail_imap_stage >= 1) {
+ && flow->packet_counter < 8 && flow->l4.tcp.mail_imap_stage >= 1) {
NDPI_LOG_DBG2(ndpi_struct,
"no imap command or response but packet count < 6 and imap stage >= 1 -> skip\n");
return;
diff --git a/src/lib/protocols/mail_smtp.c b/src/lib/protocols/mail_smtp.c
index 7ee1cdd8d..551f67886 100644
--- a/src/lib/protocols/mail_smtp.c
+++ b/src/lib/protocols/mail_smtp.c
@@ -38,12 +38,13 @@
#define SMTP_BIT_HELO_EHLO 0x20
#define SMTP_BIT_MAIL 0x40
#define SMTP_BIT_RCPT 0x80
-#define SMTP_BIT_AUTH 0x100
+#define SMTP_BIT_AUTH_LOGIN 0x100
#define SMTP_BIT_STARTTLS 0x200
#define SMTP_BIT_DATA 0x400
#define SMTP_BIT_NOOP 0x800
#define SMTP_BIT_RSET 0x1000
#define SMTP_BIT_TlRM 0x2000
+#define SMTP_BIT_AUTH_PLAIN 0x4000
/* #define SMTP_DEBUG 1 */
@@ -65,6 +66,53 @@ static void smtpInitExtraPacketProcessing(struct ndpi_flow_struct *flow);
/* **************************************** */
+static void get_credentials_auth_plain(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow,
+ const u_int8_t *line, u_int16_t line_len)
+{
+ u_int8_t buf[255];
+ u_char *out;
+ size_t i, out_len;
+ unsigned int user_len = 0;
+
+ /* AUTH PLAIN XXXXXX */
+ if(line_len <= 11)
+ return;
+
+ line += 11;
+ line_len -= 11;
+
+ ndpi_user_pwd_payload_copy(buf, sizeof(buf), 0, line, line_len);
+ out = ndpi_base64_decode(buf, strlen((char *)buf), &out_len);
+ if(!out)
+ return;
+ /* No guarantee that out is null terminated:
+ UTF8NUL authcid UTF8NUL passwd */
+ for(i = 1; i < out_len; i++) {
+ if(out[i] == '\0')
+ user_len = i - 1;
+ }
+ if(user_len > 0) {
+ user_len = ndpi_min(user_len, sizeof(flow->protos.ftp_imap_pop_smtp.username) - 1);
+
+ memcpy(flow->protos.ftp_imap_pop_smtp.username, out + 1, user_len);
+ flow->protos.ftp_imap_pop_smtp.username[user_len] = '\0';
+
+ ndpi_set_risk(ndpi_struct, flow, NDPI_CLEAR_TEXT_CREDENTIALS);
+
+ if(1 + user_len + 1 < out_len) {
+ unsigned int pwd_len;
+
+ pwd_len = ndpi_min(out_len - (1 + user_len + 1), sizeof(flow->protos.ftp_imap_pop_smtp.password) - 1);
+ memcpy(flow->protos.ftp_imap_pop_smtp.password, out + 1 + user_len + 1, pwd_len);
+ flow->protos.ftp_imap_pop_smtp.password[pwd_len] = '\0';
+ }
+ }
+ ndpi_free(out);
+}
+
+/* **************************************** */
+
void ndpi_search_mail_smtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
@@ -102,10 +150,14 @@ void ndpi_search_mail_smtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
len = ndpi_min(len, sizeof(flow->host_server_name)-1);
strncpy((char*)flow->host_server_name, (char*)&packet->line[a].ptr[4], len);
flow->host_server_name[len] = '\0';
-
- ndpi_match_hostname_protocol(ndpi_struct, flow, NDPI_PROTOCOL_MAIL_SMTP,
- (char *)flow->host_server_name,
- strlen((const char *)flow->host_server_name));
+ if(ndpi_match_hostname_protocol(ndpi_struct, flow, NDPI_PROTOCOL_MAIL_SMTP,
+ (char *)flow->host_server_name,
+ strlen((const char *)flow->host_server_name))) {
+ /* We set the protocols; we need to initialize extra dissection
+ to search for credentials */
+ NDPI_LOG_DBG(ndpi_struct, "SMTP: hostname matched\n");
+ smtpInitExtraPacketProcessing(flow);
+ }
}
}
}
@@ -139,6 +191,8 @@ void ndpi_search_mail_smtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
&& packet->line[a].ptr[4] == ' ') {
flow->l4.tcp.smtp_command_bitmask |= SMTP_BIT_MAIL;
flow->protos.ftp_imap_pop_smtp.auth_found = 0;
+ /* We shouldn't be here if there are credentials */
+ flow->protos.ftp_imap_pop_smtp.auth_done = 1;
} else if((packet->line[a].ptr[0] == 'R' || packet->line[a].ptr[0] == 'r')
&& (packet->line[a].ptr[1] == 'C' || packet->line[a].ptr[1] == 'c')
&& (packet->line[a].ptr[2] == 'P' || packet->line[a].ptr[2] == 'p')
@@ -146,6 +200,8 @@ void ndpi_search_mail_smtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
&& packet->line[a].ptr[4] == ' ') {
flow->l4.tcp.smtp_command_bitmask |= SMTP_BIT_RCPT;
flow->protos.ftp_imap_pop_smtp.auth_found = 0;
+ /* We shouldn't be here if there are credentials */
+ flow->protos.ftp_imap_pop_smtp.auth_done = 1;
} else if((packet->line[a].ptr[0] == 'A' || packet->line[a].ptr[0] == 'a')
&& (packet->line[a].ptr[1] == 'U' || packet->line[a].ptr[1] == 'u')
&& (packet->line[a].ptr[2] == 'T' || packet->line[a].ptr[2] == 't')
@@ -154,16 +210,27 @@ void ndpi_search_mail_smtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
#ifdef SMTP_DEBUG
printf("%s() AUTH [%.*s]\n", __FUNCTION__, packet->line[a].len, packet->line[a].ptr);
#endif
-
- flow->l4.tcp.smtp_command_bitmask |= SMTP_BIT_AUTH;
flow->protos.ftp_imap_pop_smtp.auth_found = 1;
+ if(packet->line[a].len >= 6) {
+ if(packet->line[a].ptr[5] == 'L' || packet->line[a].ptr[5] == 'l') {
+ flow->l4.tcp.smtp_command_bitmask |= SMTP_BIT_AUTH_LOGIN;
+ /* AUTH LOGIN: Username and pwd on the next messages */
+ } else if(packet->line[a].ptr[5] == 'P' || packet->line[a].ptr[5] == 'p') {
+ flow->l4.tcp.smtp_command_bitmask |= SMTP_BIT_AUTH_PLAIN;
+ /* AUTH PLAIN: username and pwd here */
+ get_credentials_auth_plain(ndpi_struct, flow,
+ packet->line[a].ptr, packet->line[a].len);
+ flow->protos.ftp_imap_pop_smtp.auth_done = 1;
+ }
+ }
} else {
if(packet->line[a].ptr[3] != ' ') {
#ifdef SMTP_DEBUG
printf("%s() => [%.*s]\n", __FUNCTION__, packet->line[a].len, packet->line[a].ptr);
#endif
- if(flow->protos.ftp_imap_pop_smtp.auth_found) {
+ if(flow->protos.ftp_imap_pop_smtp.auth_found &&
+ (flow->l4.tcp.smtp_command_bitmask & SMTP_BIT_AUTH_LOGIN)) {
if(flow->protos.ftp_imap_pop_smtp.username[0] == '\0') {
/* Username */
u_int8_t buf[48];
@@ -214,6 +281,8 @@ void ndpi_search_mail_smtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
}
ndpi_set_risk(ndpi_struct, flow, NDPI_CLEAR_TEXT_CREDENTIALS);
+
+ flow->protos.ftp_imap_pop_smtp.auth_done = 1;
} else {
flow->host_server_name[0] = '\0';
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
@@ -234,6 +303,8 @@ void ndpi_search_mail_smtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
&& (packet->line[a].ptr[6] == 'L' || packet->line[a].ptr[6] == 'l')
&& (packet->line[a].ptr[7] == 'S' || packet->line[a].ptr[7] == 's')) {
flow->l4.tcp.smtp_command_bitmask |= SMTP_BIT_STARTTLS;
+ flow->protos.ftp_imap_pop_smtp.auth_tls = 1;
+ flow->protos.ftp_imap_pop_smtp.auth_done = 1;
}
}
@@ -274,8 +345,12 @@ void ndpi_search_mail_smtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
bit_count, flow->protos.ftp_imap_pop_smtp.password);
#endif
- ndpi_int_mail_smtp_add_connection(ndpi_struct, flow);
- smtpInitExtraPacketProcessing(flow);
+ /* Only if we don't have already set the protocol via hostname matching */
+ if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN &&
+ flow->detected_protocol_stack[1] == NDPI_PROTOCOL_UNKNOWN) {
+ ndpi_int_mail_smtp_add_connection(ndpi_struct, flow);
+ smtpInitExtraPacketProcessing(flow);
+ }
return;
}
@@ -324,7 +399,7 @@ static void smtpInitExtraPacketProcessing(struct ndpi_flow_struct *flow) {
#endif
flow->check_extra_packets = 1;
- /* At most 7 packets should almost always be enough */
+ /* At most 12 packets should almost always be enough */
flow->max_extra_packets_to_check = 12;
flow->extra_packets_func = ndpi_extra_search_mail_smtp_tcp;
}
diff --git a/src/lib/protocols/nats.c b/src/lib/protocols/nats.c
index a036303e8..d93c11b76 100644
--- a/src/lib/protocols/nats.c
+++ b/src/lib/protocols/nats.c
@@ -51,10 +51,15 @@ void ndpi_search_nats_tcp(struct ndpi_detection_module_struct *ndpi_struct,
for(i=0; commands[i] != NULL; i++) {
char *match = ndpi_strnstr((const char *)packet->payload,
commands[i],
- packet->payload_packet_len);
+ ndpi_min(strlen(commands[i]), packet->payload_packet_len));
if(!match) continue;
+ /* These commands are used by POP3 too. To avoid false positives, look for the other ones */
+ if((strcmp(commands[i], "+OK") == 0) || (strcmp(commands[i], "-ERR") == 0)) {
+ return;
+ }
+
if(ndpi_strnstr((const char *)match, "\r\n",
packet->payload_packet_len - ((size_t)match - (size_t)packet->payload)) != NULL) {
NDPI_LOG_INFO(ndpi_struct, "found NATS\n");