smtp: retain enhanced relay failure status
Debian Trixie package bundle / packages (push) Successful in 22m13s
Debian Trixie package bundle / packages (push) Successful in 22m13s
This commit is contained in:
@@ -26,6 +26,8 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <nmap.h>
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
SMTPCommand command;
|
||||
@@ -793,6 +795,44 @@ SMTPFormatDsnRcptOptions(int notify_explicit,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
SMTPDeliveryResultFromReply(unsigned int reply_code,
|
||||
const char *reply_text)
|
||||
{
|
||||
const char *enhanced = reply_text;
|
||||
|
||||
if (reply_code / 100U == 2U) return DELIVER_SUCCESS;
|
||||
if (reply_code / 100U == 4U) return DELIVER_TRY_LATER;
|
||||
if (reply_code / 100U != 5U) return DELIVER_TRY_LATER;
|
||||
if (enhanced == NULL) return DELIVER_FAILURE;
|
||||
if (isdigit((unsigned char)enhanced[0]) &&
|
||||
isdigit((unsigned char)enhanced[1]) &&
|
||||
isdigit((unsigned char)enhanced[2]) &&
|
||||
(enhanced[3] == ' ' || enhanced[3] == '-'))
|
||||
enhanced += 4;
|
||||
while (*enhanced == ' ' || *enhanced == '\t') enhanced++;
|
||||
if (enhanced[0] != '5' || enhanced[1] != '.' ||
|
||||
!isdigit((unsigned char)enhanced[2]) || enhanced[3] != '.' ||
|
||||
!isdigit((unsigned char)enhanced[4]))
|
||||
return DELIVER_FAILURE;
|
||||
if (enhanced[2] == '1' && enhanced[4] == '1')
|
||||
return DELIVER_USER_UNKNOWN;
|
||||
if (enhanced[2] == '1' && enhanced[4] == '3')
|
||||
return DELIVER_BOGUS_NAME;
|
||||
if (enhanced[2] == '2' && enhanced[4] == '2')
|
||||
return DELIVER_QUOTA_EXCEEDED;
|
||||
if (enhanced[2] == '4' && enhanced[4] == '1')
|
||||
return DELIVER_REFUSED;
|
||||
if (enhanced[2] == '4' && enhanced[4] == '4')
|
||||
return DELIVER_HOST_UNKNOWN;
|
||||
if (enhanced[2] == '4' && enhanced[4] == '6')
|
||||
return DELIVER_HOPCOUNT_EXCEEDED;
|
||||
if (enhanced[2] == '4' && enhanced[4] == '7')
|
||||
return DELIVER_TIMEOUT;
|
||||
if (enhanced[2] == '7') return DELIVER_BLOCKED;
|
||||
return DELIVER_FAILURE;
|
||||
}
|
||||
|
||||
static int
|
||||
OrcptValid(const char *value, size_t length, int smtp_utf8)
|
||||
{
|
||||
|
||||
@@ -115,6 +115,8 @@ int SMTPFormatDsnRcptOptions(int notify_explicit,
|
||||
const char *original_recipient,
|
||||
int smtp_utf8, char *options,
|
||||
size_t options_size);
|
||||
int SMTPDeliveryResultFromReply(unsigned int reply_code,
|
||||
const char *reply_text);
|
||||
int SMTPRequireTlsHasAuthenticatedPolicy(int mx_dnssec_authenticated,
|
||||
int dane_authenticated,
|
||||
int mta_sts_enforced,
|
||||
|
||||
+42
-8
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -908,6 +909,34 @@ FormatDsnOptions(const SMTPClient *queue, const RecipStruct *recipient,
|
||||
rcpt_options, rcpt_options_size);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char reply[CONN_BUFSIZE + 1U];
|
||||
} SMTPRelayTrace;
|
||||
|
||||
static int
|
||||
CaptureRelayReply(CURL *curl, curl_infotype type, char *data,
|
||||
size_t size, void *user_data)
|
||||
{
|
||||
SMTPRelayTrace *trace = user_data;
|
||||
size_t length;
|
||||
|
||||
(void)curl;
|
||||
if (trace == NULL || type != CURLINFO_HEADER_IN || size < 4U ||
|
||||
!isdigit((unsigned char)data[0]) ||
|
||||
!isdigit((unsigned char)data[1]) ||
|
||||
!isdigit((unsigned char)data[2]) ||
|
||||
(data[3] != ' ' && data[3] != '-'))
|
||||
return 0;
|
||||
length = size < sizeof(trace->reply) - 1U
|
||||
? size : sizeof(trace->reply) - 1U;
|
||||
while (length > 0U &&
|
||||
(data[length - 1U] == '\r' || data[length - 1U] == '\n'))
|
||||
length--;
|
||||
memcpy(trace->reply, data, length);
|
||||
trace->reply[length] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
DeliverRelay(SMTPClient *queue, RecipStruct *recipient,
|
||||
const SMTPRelayRoute *route)
|
||||
@@ -932,7 +961,9 @@ DeliverRelay(SMTPClient *queue, RecipStruct *recipient,
|
||||
long response = 0;
|
||||
BOOL success = FALSE;
|
||||
BongoMailAuthStatus senderStatus;
|
||||
SMTPRelayTrace relayTrace;
|
||||
|
||||
memset(&relayTrace, 0, sizeof(relayTrace));
|
||||
recipient->Result = DELIVER_TRY_LATER;
|
||||
if (route == NULL || route->host == NULL || route->host[0] == '\0' ||
|
||||
route->port < 1 || route->port > 65535 ||
|
||||
@@ -1078,13 +1109,17 @@ DeliverRelay(SMTPClient *queue, RecipStruct *recipient,
|
||||
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30L);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 300L);
|
||||
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curlError);
|
||||
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, CaptureRelayReply);
|
||||
curl_easy_setopt(curl, CURLOPT_DEBUGDATA, &relayTrace);
|
||||
code = curl_easy_perform(curl);
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
|
||||
if (code == CURLE_OK && response >= 200 && response < 300) {
|
||||
recipient->Result = DELIVER_SUCCESS;
|
||||
success = TRUE;
|
||||
} else if (response >= 500 && code != CURLE_LOGIN_DENIED) {
|
||||
recipient->Result = DELIVER_FAILURE;
|
||||
recipient->Result = SMTPDeliveryResultFromReply(
|
||||
(unsigned int)response, relayTrace.reply);
|
||||
}
|
||||
Log(success ? LOG_INFO : LOG_WARN,
|
||||
"%s %s returned %ld (%s) for message %s to %s",
|
||||
@@ -1771,8 +1806,8 @@ beginConversation:
|
||||
|
||||
if (!ReadRemoteSMTPReply(Remote, &ReplyCode, NULL, NULL) ||
|
||||
ReplyCode != 250U) {
|
||||
Recip->Result = ReplyCode / 100U == 5U
|
||||
? DELIVER_FAILURE : DELIVER_TRY_LATER;
|
||||
Recip->Result = SMTPDeliveryResultFromReply(
|
||||
ReplyCode, Remote->line);
|
||||
goto finalization;
|
||||
}
|
||||
|
||||
@@ -1798,9 +1833,8 @@ beginConversation:
|
||||
* 4xx are temporary failures and should be re-attempted
|
||||
* 5xx are fatal errors */
|
||||
if (ReplyCode / 100U == 5U) {
|
||||
Recip->Result = DELIVER_FAILURE;
|
||||
|
||||
/* TODO: am i supposed to bounce the mail here? */
|
||||
Recip->Result = SMTPDeliveryResultFromReply(
|
||||
ReplyCode, Remote->line);
|
||||
goto finalization;
|
||||
} else if (ReplyCode / 100U != 2U) {
|
||||
/* all other errors will be re-tried later */
|
||||
@@ -1815,8 +1849,8 @@ beginConversation:
|
||||
|
||||
if (!ReadRemoteSMTPReply(Remote, &ReplyCode, NULL, NULL) ||
|
||||
ReplyCode != 354U) {
|
||||
Recip->Result = ReplyCode / 100U == 5U
|
||||
? DELIVER_FAILURE : DELIVER_TRY_LATER;
|
||||
Recip->Result = SMTPDeliveryResultFromReply(
|
||||
ReplyCode, Remote->line);
|
||||
goto finalization;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <nmap.h>
|
||||
|
||||
static void
|
||||
TestCommands(void)
|
||||
{
|
||||
@@ -399,6 +401,19 @@ TestDsnOptions(void)
|
||||
assert(!strcmp(options, ""));
|
||||
assert(!SMTPFormatDsnRcptOptions(
|
||||
1, SMTP_NOTIFY_NEVER, NULL, 0, options, sizeof(options)));
|
||||
|
||||
assert(SMTPDeliveryResultFromReply(
|
||||
250U, "250 2.1.5 Recipient accepted") == DELIVER_SUCCESS);
|
||||
assert(SMTPDeliveryResultFromReply(
|
||||
451U, "451 4.3.0 Try later") == DELIVER_TRY_LATER);
|
||||
assert(SMTPDeliveryResultFromReply(
|
||||
550U, "550 5.1.1 No such user") == DELIVER_USER_UNKNOWN);
|
||||
assert(SMTPDeliveryResultFromReply(
|
||||
552U, "5.2.2 Mailbox full") == DELIVER_QUOTA_EXCEEDED);
|
||||
assert(SMTPDeliveryResultFromReply(
|
||||
550U, "550 5.7.1 Policy rejection") == DELIVER_BLOCKED);
|
||||
assert(SMTPDeliveryResultFromReply(
|
||||
550U, "550 Rejected") == DELIVER_FAILURE);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
Reference in New Issue
Block a user