From c47156cb81dd8b3a9b04967da91310740cdf211f Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 16 Oct 2018 12:29:01 +0100 Subject: [PATCH] [Fix] Fix various issues with parsing of the received headers --- src/libmime/email_addr.c | 26 +++++++++++++ src/libmime/email_addr.h | 13 +++++++ src/libmime/message.h | 1 + src/ragel/smtp_received.rl | 5 +-- src/ragel/smtp_received_parser.rl | 61 +++++++++++++++---------------- 5 files changed, 71 insertions(+), 35 deletions(-) diff --git a/src/libmime/email_addr.c b/src/libmime/email_addr.c index 8376e8f78..3b9f31de9 100644 --- a/src/libmime/email_addr.c +++ b/src/libmime/email_addr.c @@ -485,3 +485,29 @@ rspamd_email_address_list_destroy (gpointer ptr) g_ptr_array_free (ar, TRUE); } + +void rspamd_smtp_maybe_process_smtp_comment (struct rspamd_task *task, + const char *data, size_t len, + struct received_header *rh) +{ + if (!rh->by_hostname) { + /* Heuristic to detect IP addresses like in Exim received: + * [xxx]:port or [xxx] + */ + + if (*data == '[' && len > 2) { + const gchar *p = data + 1; + gsize iplen = rspamd_memcspn (p, "]", len - 1); + + if (iplen > 0) { + guchar tbuf[sizeof(struct in6_addr) + sizeof(guint32)]; + + if (rspamd_parse_inet_address_ip4 (p, iplen, tbuf) || + rspamd_parse_inet_address_ip6 (p, iplen, tbuf)) { + rh->comment_ip = rspamd_mempool_alloc (task->task_pool, iplen + 1); + rspamd_strlcpy (rh->comment_ip, p, iplen + 1); + } + } + } + } +} \ No newline at end of file diff --git a/src/libmime/email_addr.h b/src/libmime/email_addr.h index 8c9b54713..129d2ba44 100644 --- a/src/libmime/email_addr.h +++ b/src/libmime/email_addr.h @@ -51,6 +51,19 @@ struct rspamd_email_address { guchar flags; }; +struct received_header; +struct rspamd_task; +/** + * Try to parse SMTP comment to process stupid Exim received headers + * @param task + * @param data + * @param len + * @param rh + */ +void rspamd_smtp_maybe_process_smtp_comment (struct rspamd_task *task, + const char *data, size_t len, + struct received_header *rh); + /** * Create email address from a single rfc822 address (e.g. from mail from:) * @param str string to use diff --git a/src/libmime/message.h b/src/libmime/message.h index 205bf5bb2..17077860d 100644 --- a/src/libmime/message.h +++ b/src/libmime/message.h @@ -144,6 +144,7 @@ struct received_header { gchar *real_ip; gchar *by_hostname; gchar *for_mbox; + gchar *comment_ip; rspamd_inet_addr_t *addr; struct rspamd_mime_header *hdr; time_t timestamp; diff --git a/src/ragel/smtp_received.rl b/src/ragel/smtp_received.rl index b13259fed..f43ad167c 100644 --- a/src/ragel/smtp_received.rl +++ b/src/ragel/smtp_received.rl @@ -24,12 +24,9 @@ ( address_literal >Real_Domain_Start %Real_Domain_End FWS "(" TCP_info ")" ) | address_literal >Real_IP_Start %Real_IP_End; # Not RFC conforming, but many MTA try this - exim_real_ip = "[" (IPv4_addr|IPv6_simple) >IP4_start %IP4_end "]" - >Real_IP_Start %Real_IP_End (":" digit{1,4})?; - exim_content = exim_real_ip; ccontent = ctext | FWS | '(' @{ fcall balanced_ccontent; }; balanced_ccontent := ccontent* ')' @{ fret; }; - comment = "(" (FWS? ccontent|exim_content)* FWS? ")"; + comment = "(" ((FWS? ccontent)* FWS?) >Comment_Start %Comment_End ")"; CFWS = ((FWS? comment)+ FWS?) | FWS; From_domain = "FROM"i FWS Extended_Domain >From_Start %From_End; diff --git a/src/ragel/smtp_received_parser.rl b/src/ragel/smtp_received_parser.rl index 565a20b7f..836a02384 100644 --- a/src/ragel/smtp_received_parser.rl +++ b/src/ragel/smtp_received_parser.rl @@ -100,33 +100,19 @@ } action Real_IP_Start { - if (real_ip_end == NULL) { + if (real_ip_end == NULL && real_ip_start == NULL) { real_ip_start = p; } } action Real_IP_End { - if (ip_start && ip_end && ip_end > ip_start) { - real_ip_start = ip_start; - real_ip_end = ip_end; - } - else { - real_ip_end = p; - } - - ip_start = NULL; - ip_end = NULL; - } - action Reported_IP_Start { - reported_ip_start = p; - } - action Reported_IP_End { - - if (ip_start && ip_end && ip_end > ip_start) { - reported_ip_start = ip_start; - reported_ip_end = ip_end; - } - else { - reported_ip_end = p; + if (real_ip_end == NULL && real_ip_start != NULL) { + if (ip_start && ip_end && ip_end > ip_start) { + real_ip_start = ip_start; + real_ip_end = ip_end; + } + else { + real_ip_end = p; + } } ip_start = NULL; @@ -225,6 +211,21 @@ } } + action Comment_Start { + cstart = p; + } + + action Comment_End { + cend = p; + + if (cend && cstart && cend > cstart) { + rspamd_smtp_maybe_process_smtp_comment (task, cstart, cend - cstart, rh); + } + + cend = NULL; + cstart = NULL; + } + include smtp_whitespace "smtp_whitespace.rl"; include smtp_ip "smtp_ip.rl"; include smtp_date "smtp_date.rl"; @@ -246,9 +247,8 @@ rspamd_smtp_received_parse (struct rspamd_task *task, const char *data, size_t l const char *real_domain_start, *real_domain_end, *real_ip_start, *real_ip_end, *reported_domain_start, *reported_domain_end, - *reported_ip_start, *reported_ip_end, *ip_start, *ip_end, *date_start, - *for_start, *for_end, *tmp; + *for_start, *for_end, *tmp, *cstart, *cend; struct tm tm; const char *p = data, *pe = data + len, *eof; int cs, in_v6 = 0, *stack = NULL; @@ -269,13 +269,13 @@ rspamd_smtp_received_parse (struct rspamd_task *task, const char *data, size_t l real_ip_end = NULL; reported_domain_start = NULL; reported_domain_end = NULL; - reported_ip_start = NULL; - reported_ip_end = NULL; ip_start = NULL; ip_end = NULL; date_start = NULL; for_start = NULL; for_end = NULL; + cstart = NULL; + cend = NULL; rh->type = RSPAMD_RECEIVED_UNKNOWN; memset (&for_addr, 0, sizeof (for_addr)); @@ -290,10 +290,9 @@ rspamd_smtp_received_parse (struct rspamd_task *task, const char *data, size_t l rh->real_ip = rspamd_mempool_alloc (task->task_pool, tmplen + 1); rspamd_strlcpy (rh->real_ip, real_ip_start, tmplen + 1); } - if (reported_ip_end && reported_ip_start && reported_ip_end > reported_ip_start) { - tmplen = reported_ip_end - reported_ip_start; - rh->from_ip = rspamd_mempool_alloc (task->task_pool, tmplen + 1); - rspamd_strlcpy (rh->from_ip, reported_ip_start, tmplen + 1); + + if (!rh->real_ip && rh->comment_ip) { + rh->real_ip = rh->comment_ip; } if (rh->real_ip && !rh->from_ip) { -- 2.39.5