From 2b68e140a846db4f24f4e29dfa16db73dc35c37f Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Fri, 27 May 2022 23:03:02 +0100 Subject: [PATCH] Handle a v4mapped sender address given us by a proxy. Bug 2855 --- doc/doc-txt/ChangeLog | 3 +++ src/exim_monitor/em_main.c | 48 ++++++++++++++++++++++++++++++-------- src/src/host.c | 11 +++++---- src/src/spool_out.c | 4 ++-- test/runtest | 2 +- test/stdout/0035 | 28 +++++++++++----------- test/stdout/3415 | 20 ++++++++-------- 7 files changed, 75 insertions(+), 41 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 72cd3c667..3e6da9185 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -148,6 +148,9 @@ JH/32 Fix CHUNKING for a second message on a connection when the first was JH/33 Fis ${srs_encode ...} to handle an empty sender address, now returning an empty address. Previously the expansion returned an error. +HS/01 Bug 2855: Handle a v4mapped sender address given us by a frontending + proxy. Previously these were misparsed, leading to paniclog entries. + Exim version 4.95 ----------------- diff --git a/src/exim_monitor/em_main.c b/src/exim_monitor/em_main.c index 69de8dc4d..5714b999c 100644 --- a/src/exim_monitor/em_main.c +++ b/src/exim_monitor/em_main.c @@ -197,19 +197,47 @@ Returns: 0 if there is no port, else the port number. */ int -host_address_extract_port(uschar *address) +host_address_extract_port(uschar * address) { -int skip = -3; /* Skip 3 dots in IPv4 addresses */ -address--; -while (*(++address) != 0) +int port = 0; +uschar *endptr; + +/* Handle the "bracketed with colon on the end" format */ + +if (*address == '[') + { + uschar *rb = address + 1; + while (*rb != 0 && *rb != ']') rb++; + if (*rb++ == 0) return 0; /* Missing ]; leave invalid address */ + if (*rb == ':') + { + port = Ustrtol(rb + 1, &endptr, 10); + if (*endptr != 0) return 0; /* Invalid port; leave invalid address */ + } + else if (*rb != 0) return 0; /* Bad syntax; leave invalid address */ + memmove(address, address + 1, rb - address - 2); + rb[-2] = 0; + } + +/* Handle the "dot on the end" format */ + +else { - int ch = *address; - if (ch == ':') skip = 0; /* Skip 0 dots in IPv6 addresses */ - else if (ch == '.' && skip++ >= 0) break; + int skip = -3; /* Skip 3 dots in IPv4 addresses */ + address--; + while (*(++address) != 0) + { + int ch = *address; + if (ch == ':') skip = 0; /* Skip 0 dots in IPv6 addresses */ + else if (ch == '.' && skip++ >= 0) break; + } + if (*address == 0) return 0; + port = Ustrtol(address + 1, &endptr, 10); + if (*endptr != 0) return 0; /* Invalid port; leave invalid address */ + *address = 0; } -if (*address == 0) return 0; -*address++ = 0; -return Uatoi(address); + +return port; } diff --git a/src/src/host.c b/src/src/host.c index f69e0341a..e43b507e5 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -370,15 +370,18 @@ while ((name = string_nextinlist(&list, &sep, NULL, 0))) * Extract port from address string * *************************************************/ -/* In the spool file, and in the -oMa and -oMi options, a host plus port is -given as an IP address followed by a dot and a port number. This function -decodes this. +/* In the -oMa and -oMi options, a host plus port is given as an IP address +followed by a dot and a port number. This function decodes this. An alternative format for the -oMa and -oMi options is [ip address]:port which -is what Exim 4 uses for output, because it seems to becoming commonly used, +is what Exim uses for output, because it seems to becoming commonly used, whereas the dot form confuses some programs/people. So we recognize that form too. +The spool file used to use the first form, but this breaks with a v4mapped ipv6 +hybrid, because the parsing here is not clever. So for spool we now use the +second form. + Argument: address points to the string; if there is a port, the '.' in the string is overwritten with zero to terminate the address; if the string diff --git a/src/src/spool_out.c b/src/src/spool_out.c index 713584091..510eda6c1 100644 --- a/src/src/spool_out.c +++ b/src/src/spool_out.c @@ -191,7 +191,7 @@ if (sender_helo_name) spool_var_write(fp, US"helo_name", sender_helo_name); if (sender_host_address) { if (is_tainted(sender_host_address)) putc('-', fp); - fprintf(fp, "-host_address %s.%d\n", sender_host_address, sender_host_port); + fprintf(fp, "-host_address [%s]:%d\n", sender_host_address, sender_host_port); if (sender_host_name) spool_var_write(fp, US"host_name", sender_host_name); } @@ -205,7 +205,7 @@ if (sender_host_auth_pubname) if (interface_address) { if (is_tainted(interface_address)) putc('-', fp); - fprintf(fp, "-interface_address %s.%d\n", interface_address, interface_port); + fprintf(fp, "-interface_address [%s]:%d\n", interface_address, interface_port); } if (smtp_active_hostname != primary_hostname) diff --git a/test/runtest b/test/runtest index c88a8929e..4a304a8aa 100755 --- a/test/runtest +++ b/test/runtest @@ -792,7 +792,7 @@ RESET_AFTER_EXTRA_LINE_READ: } # Port in host address in spool file output from -Mvh - s/^(--?host_address) (.*)\.\d+/$1 $2.9999/; + s/^(--?host_address) (.*[:.])\d+$/$1 ${2}9999/; if ($dynamic_socket and $dynamic_socket->opened and my $port = $dynamic_socket->sockport) { s/^Connecting to 127\.0\.0\.1 port \K$port//; diff --git a/test/stdout/0035 b/test/stdout/0035 index 2a2bc285c..c2f2cf56f 100644 --- a/test/stdout/0035 +++ b/test/stdout/0035 @@ -147,8 +147,8 @@ ddddddddd 0 -received_time_usec .uuuuuu -received_time_complete tttt.uuuuuu --helo_name rhu.barb --host_address 127.0.0.1.9999 --interface_address 127.0.0.1.1225 +-host_address [127.0.0.1]:9999 +-interface_address [127.0.0.1]:1112 -received_protocol esmtp -body_linecount 0 -max_received_linelength 0 @@ -170,8 +170,8 @@ ddddddddd 0 -received_time_usec .uuuuuu -received_time_complete tttt.uuuuuu --helo_name rhu.barb --host_address 127.0.0.1.9999 --interface_address 127.0.0.1.1225 +-host_address [127.0.0.1]:9999 +-interface_address [127.0.0.1]:1112 -received_protocol esmtp -body_linecount 0 -max_received_linelength 0 @@ -196,8 +196,8 @@ ddddddddd 0 -received_time_usec .uuuuuu -received_time_complete tttt.uuuuuu --helo_name rhu.barb --host_address 127.0.0.1.9999 --interface_address 127.0.0.1.1225 +-host_address [127.0.0.1]:9999 +-interface_address [127.0.0.1]:1112 -received_protocol esmtp -body_linecount 0 -max_received_linelength 0 @@ -220,8 +220,8 @@ ddddddddd 0 -received_time_usec .uuuuuu -received_time_complete tttt.uuuuuu --helo_name rhu.barb --host_address 127.0.0.1.9999 --interface_address 127.0.0.1.1225 +-host_address [127.0.0.1]:9999 +-interface_address [127.0.0.1]:1112 -received_protocol esmtp -body_linecount 0 -max_received_linelength 25 @@ -244,8 +244,8 @@ ddddddddd 0 -received_time_usec .uuuuuu -received_time_complete tttt.uuuuuu --helo_name rhu.barb --host_address 127.0.0.1.9999 --interface_address 127.0.0.1.1225 +-host_address [127.0.0.1]:9999 +-interface_address [127.0.0.1]:1112 -received_protocol esmtp -body_linecount 0 -max_received_linelength 25 @@ -271,8 +271,8 @@ ddddddddd 0 -received_time_usec .uuuuuu -received_time_complete tttt.uuuuuu --helo_name rhu.barb --host_address 127.0.0.1.9999 --interface_address 127.0.0.1.1225 +-host_address [127.0.0.1]:9999 +-interface_address [127.0.0.1]:1112 -received_protocol esmtp -body_linecount 0 -max_received_linelength 25 @@ -298,8 +298,8 @@ ddddddddd 0 -received_time_usec .uuuuuu -received_time_complete tttt.uuuuuu --helo_name rhu.barb --host_address 127.0.0.1.9999 --interface_address 127.0.0.1.1225 +-host_address [127.0.0.1]:9999 +-interface_address [127.0.0.1]:1112 -received_protocol esmtp -body_linecount 0 -max_received_linelength 25 diff --git a/test/stdout/3415 b/test/stdout/3415 index 0ce6f1909..11060a1b9 100644 --- a/test/stdout/3415 +++ b/test/stdout/3415 @@ -158,10 +158,10 @@ ddddddddd 0 -received_time_usec .uuuuuu -received_time_complete tttt.uuuuuu --helo_name rhu.barb --host_address 127.0.0.1.9999 +-host_address [127.0.0.1]:9999 -host_auth au1 -host_auth_pubname PLAIN --interface_address 127.0.0.1.1225 +-interface_address [127.0.0.1]:1112 -received_protocol esmtpa -body_linecount 0 -max_received_linelength 0 @@ -188,10 +188,10 @@ ddddddddd 0 -received_time_usec .uuuuuu -received_time_complete tttt.uuuuuu --helo_name rhu.barb --host_address 127.0.0.1.9999 +-host_address [127.0.0.1]:9999 -host_auth au1 -host_auth_pubname PLAIN --interface_address 127.0.0.1.1225 +-interface_address [127.0.0.1]:1112 -received_protocol esmtpa -body_linecount 0 -max_received_linelength 0 @@ -216,10 +216,10 @@ ddddddddd 0 -received_time_usec .uuuuuu -received_time_complete tttt.uuuuuu --helo_name rhu.barb --host_address 127.0.0.1.9999 +-host_address [127.0.0.1]:9999 -host_auth au1 -host_auth_pubname PLAIN --interface_address 127.0.0.1.1225 +-interface_address [127.0.0.1]:1112 -received_protocol esmtpa -body_linecount 0 -max_received_linelength 0 @@ -244,10 +244,10 @@ ddddddddd 0 -received_time_usec .uuuuuu -received_time_complete tttt.uuuuuu --helo_name rhu.barb --host_address 127.0.0.1.9999 +-host_address [127.0.0.1]:9999 -host_auth au1 -host_auth_pubname PLAIN --interface_address 127.0.0.1.1225 +-interface_address [127.0.0.1]:1112 -received_protocol esmtpa -body_linecount 0 -max_received_linelength 0 @@ -272,10 +272,10 @@ ddddddddd 0 -received_time_usec .uuuuuu -received_time_complete tttt.uuuuuu --helo_name rhu.barb --host_address 127.0.0.1.9999 +-host_address [127.0.0.1]:9999 -host_auth au1 -host_auth_pubname PLAIN --interface_address 127.0.0.1.1225 +-interface_address [127.0.0.1]:1112 -received_protocol esmtpa -body_linecount 0 -max_received_linelength 15 -- 2.30.2