diff options
Diffstat (limited to 'src/smtp.c')
-rw-r--r-- | src/smtp.c | 819 |
1 files changed, 453 insertions, 366 deletions
diff --git a/src/smtp.c b/src/smtp.c index dc3ff6089..98b012e3e 100644 --- a/src/smtp.c +++ b/src/smtp.c @@ -53,26 +53,26 @@ gpointer init_smtp (struct rspamd_config *cfg); void start_smtp (struct rspamd_worker *worker); worker_t smtp_worker = { - "smtp", /* Name */ - init_smtp, /* Init function */ - start_smtp, /* Start function */ - TRUE, /* Has socket */ - FALSE, /* Non unique */ - FALSE, /* Non threaded */ - TRUE, /* Killable */ - SOCK_STREAM /* TCP socket */ + "smtp", /* Name */ + init_smtp, /* Init function */ + start_smtp, /* Start function */ + TRUE, /* Has socket */ + FALSE, /* Non unique */ + FALSE, /* Non threaded */ + TRUE, /* Killable */ + SOCK_STREAM /* TCP socket */ }; static gboolean call_stage_filters (struct smtp_session *session, enum rspamd_smtp_stage stage) { - gboolean res = TRUE; - GList *list = session->ctx->smtp_filters[stage]; - struct smtp_filter *filter; - + gboolean res = TRUE; + GList *list = session->ctx->smtp_filters[stage]; + struct smtp_filter *filter; + while (list) { filter = list->data; - if (! filter->filter (session, filter->filter_data)) { + if (!filter->filter (session, filter->filter_data)) { res = FALSE; break; } @@ -85,144 +85,159 @@ call_stage_filters (struct smtp_session *session, enum rspamd_smtp_stage stage) static gboolean read_smtp_command (struct smtp_session *session, f_str_t *line) { - struct smtp_command *cmd; - gchar outbuf[BUFSIZ]; - gint r; - - if (! parse_smtp_command (session, line, &cmd)) { + struct smtp_command *cmd; + gchar outbuf[BUFSIZ]; + gint r; + + if (!parse_smtp_command (session, line, &cmd)) { session->error = SMTP_ERROR_BAD_COMMAND; - session->errors ++; + session->errors++; return FALSE; } - + switch (cmd->command) { - case SMTP_COMMAND_HELO: - case SMTP_COMMAND_EHLO: - if (session->state == SMTP_STATE_GREETING || session->state == SMTP_STATE_HELO) { - if (parse_smtp_helo (session, cmd)) { - session->state = SMTP_STATE_FROM; - } - else { - session->errors ++; - } - if (! call_stage_filters (session, SMTP_STAGE_HELO)) { - return FALSE; - } - return TRUE; + case SMTP_COMMAND_HELO: + case SMTP_COMMAND_EHLO: + if (session->state == SMTP_STATE_GREETING || session->state == + SMTP_STATE_HELO) { + if (parse_smtp_helo (session, cmd)) { + session->state = SMTP_STATE_FROM; } else { - goto improper_sequence; + session->errors++; } - break; - case SMTP_COMMAND_QUIT: - session->state = SMTP_STATE_QUIT; - break; - case SMTP_COMMAND_NOOP: - break; - case SMTP_COMMAND_MAIL: - if (((session->state == SMTP_STATE_GREETING || session->state == SMTP_STATE_HELO) && !session->ctx->helo_required) - || session->state == SMTP_STATE_FROM) { - if (parse_smtp_from (session, cmd)) { - session->state = SMTP_STATE_RCPT; - } - else { - session->errors ++; - return FALSE; - } - if (! call_stage_filters (session, SMTP_STAGE_MAIL)) { - return FALSE; - } + if (!call_stage_filters (session, SMTP_STAGE_HELO)) { + return FALSE; + } + return TRUE; + } + else { + goto improper_sequence; + } + break; + case SMTP_COMMAND_QUIT: + session->state = SMTP_STATE_QUIT; + break; + case SMTP_COMMAND_NOOP: + break; + case SMTP_COMMAND_MAIL: + if (((session->state == SMTP_STATE_GREETING || session->state == + SMTP_STATE_HELO) && !session->ctx->helo_required) + || session->state == SMTP_STATE_FROM) { + if (parse_smtp_from (session, cmd)) { + session->state = SMTP_STATE_RCPT; } else { - goto improper_sequence; + session->errors++; + return FALSE; } - break; - case SMTP_COMMAND_RCPT: - if (session->state == SMTP_STATE_RCPT) { - if (parse_smtp_rcpt (session, cmd)) { - if (! call_stage_filters (session, SMTP_STAGE_RCPT)) { + if (!call_stage_filters (session, SMTP_STAGE_MAIL)) { + return FALSE; + } + } + else { + goto improper_sequence; + } + break; + case SMTP_COMMAND_RCPT: + if (session->state == SMTP_STATE_RCPT) { + if (parse_smtp_rcpt (session, cmd)) { + if (!call_stage_filters (session, SMTP_STAGE_RCPT)) { + return FALSE; + } + /* Make upstream connection */ + if (session->upstream == NULL) { + if (!create_smtp_upstream_connection (session)) { + session->error = SMTP_ERROR_UPSTREAM; + session->state = SMTP_STATE_CRITICAL_ERROR; return FALSE; } - /* Make upstream connection */ - if (session->upstream == NULL) { - if (!create_smtp_upstream_connection (session)) { - session->error = SMTP_ERROR_UPSTREAM; - session->state = SMTP_STATE_CRITICAL_ERROR; - return FALSE; - } - } - else { - /* Send next rcpt to upstream */ - session->state = SMTP_STATE_WAIT_UPSTREAM; - session->upstream_state = SMTP_STATE_BEFORE_DATA; - rspamd_dispatcher_restore (session->upstream_dispatcher); - r = rspamd_snprintf (outbuf, sizeof (outbuf), "RCPT TO: "); - r += smtp_upstream_write_list (session->rcpt->data, outbuf + r, sizeof (outbuf) - r); - session->cur_rcpt = NULL; - return rspamd_dispatcher_write (session->upstream_dispatcher, outbuf, r, FALSE, FALSE); - } - session->state = SMTP_STATE_WAIT_UPSTREAM; - return TRUE; } else { - session->errors ++; - return FALSE; + /* Send next rcpt to upstream */ + session->state = SMTP_STATE_WAIT_UPSTREAM; + session->upstream_state = SMTP_STATE_BEFORE_DATA; + rspamd_dispatcher_restore (session->upstream_dispatcher); + r = rspamd_snprintf (outbuf, sizeof (outbuf), "RCPT TO: "); + r += smtp_upstream_write_list (session->rcpt->data, + outbuf + r, + sizeof (outbuf) - r); + session->cur_rcpt = NULL; + return rspamd_dispatcher_write ( + session->upstream_dispatcher, + outbuf, + r, + FALSE, + FALSE); } + session->state = SMTP_STATE_WAIT_UPSTREAM; + return TRUE; } else { - goto improper_sequence; + session->errors++; + return FALSE; } - break; - case SMTP_COMMAND_RSET: - session->from = NULL; - if (session->rcpt) { - g_list_free (session->rcpt); + } + else { + goto improper_sequence; + } + break; + case SMTP_COMMAND_RSET: + session->from = NULL; + if (session->rcpt) { + g_list_free (session->rcpt); + } + if (session->upstream) { + remove_normal_event (session->s, + smtp_upstream_finalize_connection, + session); + session->upstream = NULL; + } + session->state = SMTP_STATE_GREETING; + break; + case SMTP_COMMAND_DATA: + if (session->state == SMTP_STATE_RCPT) { + if (session->rcpt == NULL) { + session->error = SMTP_ERROR_RECIPIENTS; + session->errors++; + return FALSE; } - if (session->upstream) { - remove_normal_event (session->s, smtp_upstream_finalize_connection, session); - session->upstream = NULL; + if (!call_stage_filters (session, SMTP_STAGE_DATA)) { + return FALSE; } - session->state = SMTP_STATE_GREETING; - break; - case SMTP_COMMAND_DATA: - if (session->state == SMTP_STATE_RCPT) { - if (session->rcpt == NULL) { - session->error = SMTP_ERROR_RECIPIENTS; - session->errors ++; - return FALSE; - } - if (! call_stage_filters (session, SMTP_STAGE_DATA)) { - return FALSE; - } - if (session->upstream == NULL) { - session->error = SMTP_ERROR_UPSTREAM; - session->state = SMTP_STATE_CRITICAL_ERROR; - return FALSE; - } - else { - session->upstream_state = SMTP_STATE_DATA; - rspamd_dispatcher_restore (session->upstream_dispatcher); - r = rspamd_snprintf (outbuf, sizeof (outbuf), "DATA" CRLF); - session->state = SMTP_STATE_WAIT_UPSTREAM; - session->error = SMTP_ERROR_DATA_OK; - return rspamd_dispatcher_write (session->upstream_dispatcher, outbuf, r, FALSE, FALSE); - } + if (session->upstream == NULL) { + session->error = SMTP_ERROR_UPSTREAM; + session->state = SMTP_STATE_CRITICAL_ERROR; + return FALSE; } else { - goto improper_sequence; + session->upstream_state = SMTP_STATE_DATA; + rspamd_dispatcher_restore (session->upstream_dispatcher); + r = rspamd_snprintf (outbuf, sizeof (outbuf), "DATA" CRLF); + session->state = SMTP_STATE_WAIT_UPSTREAM; + session->error = SMTP_ERROR_DATA_OK; + return rspamd_dispatcher_write (session->upstream_dispatcher, + outbuf, + r, + FALSE, + FALSE); } - case SMTP_COMMAND_VRFY: - case SMTP_COMMAND_EXPN: - case SMTP_COMMAND_HELP: - session->error = SMTP_ERROR_UNIMPLIMENTED; - return FALSE; + } + else { + goto improper_sequence; + } + case SMTP_COMMAND_VRFY: + case SMTP_COMMAND_EXPN: + case SMTP_COMMAND_HELP: + session->error = SMTP_ERROR_UNIMPLIMENTED; + return FALSE; } - + session->error = SMTP_ERROR_OK; return TRUE; improper_sequence: - session->errors ++; + session->errors++; session->error = SMTP_ERROR_SEQUENCE; return FALSE; } @@ -230,11 +245,11 @@ improper_sequence: static gboolean process_smtp_data (struct smtp_session *session) { - struct stat st; - gint r; - GList *cur, *t; - f_str_t *f; - gchar *s; + struct stat st; + gint r; + GList *cur, *t; + f_str_t *f; + gchar *s; if (fstat (session->temp_fd, &st) == -1) { msg_err ("fstat failed: %s", strerror (errno)); @@ -242,17 +257,23 @@ process_smtp_data (struct smtp_session *session) } /* Now mmap temp file if it is small enough */ session->temp_size = st.st_size; - if (session->ctx->max_size == 0 || st.st_size < (off_t)session->ctx->max_size) { + if (session->ctx->max_size == 0 || st.st_size < + (off_t)session->ctx->max_size) { session->task = rspamd_task_new (session->worker); session->task->resolver = session->resolver; session->task->fin_callback = smtp_write_socket; session->task->fin_arg = session; - session->task->msg = rspamd_mempool_alloc (session->pool, sizeof (GString)); + session->task->msg = + rspamd_mempool_alloc (session->pool, sizeof (GString)); session->task->s = session->s; #ifdef HAVE_MMAP_NOCORE - if ((session->task->msg->str = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED | MAP_NOCORE, session->temp_fd, 0)) == MAP_FAILED) { + if ((session->task->msg->str = + mmap (NULL, st.st_size, PROT_READ, MAP_SHARED | MAP_NOCORE, + session->temp_fd, 0)) == MAP_FAILED) { #else - if ((session->task->msg->str = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, session->temp_fd, 0)) == MAP_FAILED) { + if ((session->task->msg->str = + mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, session->temp_fd, + 0)) == MAP_FAILED) { #endif msg_err ("mmap failed: %s", strerror (errno)); goto err; @@ -280,7 +301,8 @@ process_smtp_data (struct smtp_session *session) t = g_list_next (t); } - memcpy (&session->task->from_addr, &session->client_addr, sizeof (struct in_addr)); + memcpy (&session->task->from_addr, &session->client_addr, + sizeof (struct in_addr)); session->task->cmd = CMD_CHECK; if (process_message (session->task) == -1) { @@ -305,7 +327,9 @@ process_smtp_data (struct smtp_session *session) } } else { - msg_info ("not scan message as it is %z bytes and maximum is %z", st.st_size, session->ctx->max_size); + msg_info ("not scan message as it is %z bytes and maximum is %z", + st.st_size, + session->ctx->max_size); session->task = NULL; return smtp_send_upstream_message (session); } @@ -314,7 +338,8 @@ process_smtp_data (struct smtp_session *session) err: session->error = SMTP_ERROR_FILE; session->state = SMTP_STATE_CRITICAL_ERROR; - if (! rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, + TRUE)) { return FALSE; } destroy_session (session->s); @@ -324,65 +349,74 @@ err: /* * Callback that is called when there is data to read in buffer */ -static gboolean +static gboolean smtp_read_socket (f_str_t * in, void *arg) { - struct smtp_session *session = arg; + struct smtp_session *session = arg; switch (session->state) { - case SMTP_STATE_RESOLVE_REVERSE: - case SMTP_STATE_RESOLVE_NORMAL: - case SMTP_STATE_DELAY: - session->error = make_smtp_error (session->pool, 550, "%s Improper use of SMTP command pipelining", "5.5.0"); - session->state = SMTP_STATE_ERROR; - break; - case SMTP_STATE_GREETING: - case SMTP_STATE_HELO: - case SMTP_STATE_FROM: - case SMTP_STATE_RCPT: - case SMTP_STATE_DATA: - read_smtp_command (session, in); - if (session->state != SMTP_STATE_WAIT_UPSTREAM) { - if (session->errors > session->ctx->max_errors) { - session->error = SMTP_ERROR_LIMIT; - session->state = SMTP_STATE_CRITICAL_ERROR; - if (! rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { - return FALSE; - } - destroy_session (session->s); - return FALSE; - } - if (! smtp_write_socket (session)) { + case SMTP_STATE_RESOLVE_REVERSE: + case SMTP_STATE_RESOLVE_NORMAL: + case SMTP_STATE_DELAY: + session->error = make_smtp_error (session->pool, + 550, + "%s Improper use of SMTP command pipelining", + "5.5.0"); + session->state = SMTP_STATE_ERROR; + break; + case SMTP_STATE_GREETING: + case SMTP_STATE_HELO: + case SMTP_STATE_FROM: + case SMTP_STATE_RCPT: + case SMTP_STATE_DATA: + read_smtp_command (session, in); + if (session->state != SMTP_STATE_WAIT_UPSTREAM) { + if (session->errors > session->ctx->max_errors) { + session->error = SMTP_ERROR_LIMIT; + session->state = SMTP_STATE_CRITICAL_ERROR; + if (!rspamd_dispatcher_write (session->dispatcher, + session->error, 0, FALSE, TRUE)) { return FALSE; } + destroy_session (session->s); + return FALSE; } - break; - case SMTP_STATE_AFTER_DATA: - if (in->len == 0) { - return TRUE; - } - if (in->len == 3 && memcmp (in->begin, DATA_END_TRAILER, in->len) == 0) { - return process_smtp_data (session); + if (!smtp_write_socket (session)) { + return FALSE; } + } + break; + case SMTP_STATE_AFTER_DATA: + if (in->len == 0) { + return TRUE; + } + if (in->len == 3 && + memcmp (in->begin, DATA_END_TRAILER, in->len) == 0) { + return process_smtp_data (session); + } - if (write (session->temp_fd, in->begin, in->len) != (ssize_t)in->len) { - msg_err ("cannot write to temp file: %s", strerror (errno)); - session->error = SMTP_ERROR_FILE; - session->state = SMTP_STATE_CRITICAL_ERROR; - if (! rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { - return FALSE; - } - destroy_session (session->s); + if (write (session->temp_fd, in->begin, in->len) != (ssize_t)in->len) { + msg_err ("cannot write to temp file: %s", strerror (errno)); + session->error = SMTP_ERROR_FILE; + session->state = SMTP_STATE_CRITICAL_ERROR; + if (!rspamd_dispatcher_write (session->dispatcher, session->error, + 0, FALSE, TRUE)) { return FALSE; } - break; - case SMTP_STATE_WAIT_UPSTREAM: - rspamd_dispatcher_pause (session->dispatcher); - break; - default: - session->error = make_smtp_error (session->pool, 550, "%s Internal error", "5.5.0"); - session->state = SMTP_STATE_ERROR; - break; + destroy_session (session->s); + return FALSE; + } + break; + case SMTP_STATE_WAIT_UPSTREAM: + rspamd_dispatcher_pause (session->dispatcher); + break; + default: + session->error = make_smtp_error (session->pool, + 550, + "%s Internal error", + "5.5.0"); + session->state = SMTP_STATE_ERROR; + break; } if (session->state == SMTP_STATE_QUIT) { @@ -399,14 +433,15 @@ smtp_read_socket (f_str_t * in, void *arg) /* * Callback for socket writing */ -static gboolean +static gboolean smtp_write_socket (void *arg) { - struct smtp_session *session = arg; + struct smtp_session *session = arg; if (session->state == SMTP_STATE_CRITICAL_ERROR) { if (session->error != NULL) { - if (! rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, session->error, + 0, FALSE, TRUE)) { return FALSE; } } @@ -419,7 +454,8 @@ smtp_write_socket (void *arg) } else { if (session->error != NULL) { - if (! rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, + session->error, 0, FALSE, TRUE)) { return FALSE; } } @@ -427,12 +463,13 @@ smtp_write_socket (void *arg) } else { if (session->error != NULL) { - if (! rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, session->error, + 0, FALSE, TRUE)) { return FALSE; } } } - + return TRUE; } @@ -442,7 +479,7 @@ smtp_write_socket (void *arg) static void smtp_err_socket (GError * err, void *arg) { - struct smtp_session *session = arg; + struct smtp_session *session = arg; msg_info ("abnormally closing connection, error: %s", err->message); /* Free buffers */ @@ -456,7 +493,8 @@ static gboolean write_smtp_greeting (struct smtp_session *session) { if (session->ctx->smtp_banner) { - if (! rspamd_dispatcher_write (session->dispatcher, session->ctx->smtp_banner, 0, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, + session->ctx->smtp_banner, 0, FALSE, TRUE)) { return FALSE; } } @@ -470,9 +508,11 @@ write_smtp_greeting (struct smtp_session *session) static void smtp_delay_handler (gint fd, short what, void *arg) { - struct smtp_session *session = arg; - - remove_normal_event (session->s, (event_finalizer_t)event_del, session->delay_timer); + struct smtp_session *session = arg; + + remove_normal_event (session->s, + (event_finalizer_t)event_del, + session->delay_timer); if (session->state == SMTP_STATE_DELAY) { session->state = SMTP_STATE_GREETING; write_smtp_greeting (session); @@ -489,9 +529,9 @@ smtp_delay_handler (gint fd, short what, void *arg) static void smtp_make_delay (struct smtp_session *session) { - struct event *tev; - struct timeval *tv; - gint32 jitter; + struct event *tev; + struct timeval *tv; + gint32 jitter; if (session->ctx->smtp_delay != 0 && session->state == SMTP_STATE_DELAY) { tev = rspamd_mempool_alloc (session->pool, sizeof (struct event)); @@ -506,7 +546,10 @@ smtp_make_delay (struct smtp_session *session) evtimer_set (tev, smtp_delay_handler, session); evtimer_add (tev, tv); - register_async_event (session->s, (event_finalizer_t)event_del, tev, g_quark_from_static_string ("smtp proxy")); + register_async_event (session->s, + (event_finalizer_t)event_del, + tev, + g_quark_from_static_string ("smtp proxy")); session->delay_timer = tev; } else if (session->state == SMTP_STATE_DELAY) { @@ -521,83 +564,98 @@ smtp_make_delay (struct smtp_session *session) static void smtp_dns_cb (struct rspamd_dns_reply *reply, void *arg) { - struct smtp_session *session = arg; - gint res = 0; - union rspamd_reply_element *elt; - GList *cur; + struct smtp_session *session = arg; + gint res = 0; + union rspamd_reply_element *elt; + GList *cur; switch (session->state) { - case SMTP_STATE_RESOLVE_REVERSE: - /* Parse reverse reply and start resolve of this ip */ - if (reply->code != RDNS_RC_NOERROR) { - rspamd_conditional_debug(rspamd_main->logger, session->client_addr.s_addr, __FUNCTION__, - "DNS error: %s", dns_strerror (reply->code)); - - if (reply->code == RDNS_RC_NXDOMAIN) { - session->hostname = rspamd_mempool_strdup (session->pool, XCLIENT_HOST_UNAVAILABLE); - } - else { - session->hostname = rspamd_mempool_strdup (session->pool, XCLIENT_HOST_TEMPFAIL); - } - session->state = SMTP_STATE_DELAY; - smtp_make_delay (session); + case SMTP_STATE_RESOLVE_REVERSE: + /* Parse reverse reply and start resolve of this ip */ + if (reply->code != RDNS_RC_NOERROR) { + rspamd_conditional_debug (rspamd_main->logger, + session->client_addr.s_addr, + __FUNCTION__, + "DNS error: %s", + dns_strerror (reply->code)); + + if (reply->code == RDNS_RC_NXDOMAIN) { + session->hostname = rspamd_mempool_strdup (session->pool, + XCLIENT_HOST_UNAVAILABLE); } else { - if (reply->elements) { - elt = reply->elements->data; - session->hostname = rspamd_mempool_strdup (session->pool, elt->ptr.name); - session->state = SMTP_STATE_RESOLVE_NORMAL; - make_dns_request (session->resolver, session->s, session->pool, - smtp_dns_cb, session, RDNS_REQUEST_A, session->hostname); - - } + session->hostname = rspamd_mempool_strdup (session->pool, + XCLIENT_HOST_TEMPFAIL); } - break; - case SMTP_STATE_RESOLVE_NORMAL: - if (reply->code != RDNS_RC_NOERROR) { - rspamd_conditional_debug(rspamd_main->logger, session->client_addr.s_addr, __FUNCTION__, - "DNS error: %s", dns_strerror (reply->code)); + session->state = SMTP_STATE_DELAY; + smtp_make_delay (session); + } + else { + if (reply->elements) { + elt = reply->elements->data; + session->hostname = rspamd_mempool_strdup (session->pool, + elt->ptr.name); + session->state = SMTP_STATE_RESOLVE_NORMAL; + make_dns_request (session->resolver, session->s, session->pool, + smtp_dns_cb, session, RDNS_REQUEST_A, session->hostname); - if (reply->code == RDNS_RC_NXDOMAIN) { - session->hostname = rspamd_mempool_strdup (session->pool, XCLIENT_HOST_UNAVAILABLE); - } - else { - session->hostname = rspamd_mempool_strdup (session->pool, XCLIENT_HOST_TEMPFAIL); - } - session->state = SMTP_STATE_DELAY; - smtp_make_delay (session); + } + } + break; + case SMTP_STATE_RESOLVE_NORMAL: + if (reply->code != RDNS_RC_NOERROR) { + rspamd_conditional_debug (rspamd_main->logger, + session->client_addr.s_addr, + __FUNCTION__, + "DNS error: %s", + dns_strerror (reply->code)); + + if (reply->code == RDNS_RC_NXDOMAIN) { + session->hostname = rspamd_mempool_strdup (session->pool, + XCLIENT_HOST_UNAVAILABLE); } else { - res = 0; - cur = reply->elements; - while (cur) { - elt = cur->data; - if (memcmp (&session->client_addr, &elt->a.addr[0], sizeof (struct in_addr)) == 0) { - res = 1; - session->resolved = TRUE; - break; - } - cur = g_list_next (cur); + session->hostname = rspamd_mempool_strdup (session->pool, + XCLIENT_HOST_TEMPFAIL); + } + session->state = SMTP_STATE_DELAY; + smtp_make_delay (session); + } + else { + res = 0; + cur = reply->elements; + while (cur) { + elt = cur->data; + if (memcmp (&session->client_addr, &elt->a.addr[0], + sizeof (struct in_addr)) == 0) { + res = 1; + session->resolved = TRUE; + break; } + cur = g_list_next (cur); + } - if (res == 0) { - msg_info ("cannot find address for hostname: %s, ip: %s", session->hostname, inet_ntoa (session->client_addr)); - session->hostname = rspamd_mempool_strdup (session->pool, XCLIENT_HOST_UNAVAILABLE); - } - session->state = SMTP_STATE_DELAY; - smtp_make_delay (session); + if (res == 0) { + msg_info ("cannot find address for hostname: %s, ip: %s", + session->hostname, + inet_ntoa (session->client_addr)); + session->hostname = rspamd_mempool_strdup (session->pool, + XCLIENT_HOST_UNAVAILABLE); } - break; - case SMTP_STATE_ERROR: - session->state = SMTP_STATE_WRITE_ERROR; - smtp_write_socket (session); - break; - default: - /* - * This callback is called on unknown state, usually this indicates - * an error (invalid pipelining) - */ - break; + session->state = SMTP_STATE_DELAY; + smtp_make_delay (session); + } + break; + case SMTP_STATE_ERROR: + session->state = SMTP_STATE_WRITE_ERROR; + smtp_write_socket (session); + break; + default: + /* + * This callback is called on unknown state, usually this indicates + * an error (invalid pipelining) + */ + break; } } @@ -607,15 +665,16 @@ smtp_dns_cb (struct rspamd_dns_reply *reply, void *arg) static void accept_socket (gint fd, short what, void *arg) { - struct rspamd_worker *worker = (struct rspamd_worker *)arg; - union sa_union su; - struct smtp_session *session; - struct smtp_worker_ctx *ctx; + struct rspamd_worker *worker = (struct rspamd_worker *)arg; + union sa_union su; + struct smtp_session *session; + struct smtp_worker_ctx *ctx; - socklen_t addrlen = sizeof (su.ss); - gint nfd; + socklen_t addrlen = sizeof (su.ss); + gint nfd; - if ((nfd = accept_from_socket (fd, (struct sockaddr *)&su.ss, &addrlen)) == -1) { + if ((nfd = + accept_from_socket (fd, (struct sockaddr *)&su.ss, &addrlen)) == -1) { msg_warn ("accept failed: %s", strerror (errno)); return; } @@ -633,8 +692,10 @@ accept_socket (gint fd, short what, void *arg) session->client_addr.s_addr = INADDR_NONE; } else if (su.ss.ss_family == AF_INET) { - msg_info ("accepted connection from %s port %d", inet_ntoa (su.s4.sin_addr), ntohs (su.s4.sin_port)); - memcpy (&session->client_addr, &su.s4.sin_addr, sizeof (struct in_addr)); + msg_info ("accepted connection from %s port %d", + inet_ntoa (su.s4.sin_addr), ntohs (su.s4.sin_port)); + memcpy (&session->client_addr, &su.s4.sin_addr, + sizeof (struct in_addr)); } session->sock = nfd; @@ -649,18 +710,28 @@ accept_socket (gint fd, short what, void *arg) /* Resolve client's addr */ /* Set up async session */ - session->s = new_async_session (session->pool, NULL, NULL, free_smtp_session, session); + session->s = new_async_session (session->pool, + NULL, + NULL, + free_smtp_session, + session); session->state = SMTP_STATE_RESOLVE_REVERSE; - if (! make_dns_request (session->resolver, session->s, session->pool, - smtp_dns_cb, session, RDNS_REQUEST_PTR, &session->client_addr)) { + if (!make_dns_request (session->resolver, session->s, session->pool, + smtp_dns_cb, session, RDNS_REQUEST_PTR, &session->client_addr)) { msg_err ("cannot resolve %s", inet_ntoa (session->client_addr)); g_free (session); close (nfd); return; } else { - session->dispatcher = rspamd_create_dispatcher (session->ev_base, nfd, BUFFER_LINE, - smtp_read_socket, smtp_write_socket, smtp_err_socket, &session->ctx->smtp_timeout, session); + session->dispatcher = rspamd_create_dispatcher (session->ev_base, + nfd, + BUFFER_LINE, + smtp_read_socket, + smtp_write_socket, + smtp_err_socket, + &session->ctx->smtp_timeout, + session); session->dispatcher->peer_addr = session->client_addr.s_addr; } } @@ -668,41 +739,41 @@ accept_socket (gint fd, short what, void *arg) static void parse_smtp_banner (struct smtp_worker_ctx *ctx, const gchar *line) { - gint hostmax, banner_len = sizeof ("220 ") - 1; - gchar *p, *t, *hostbuf = NULL; - gboolean has_crlf = FALSE; + gint hostmax, banner_len = sizeof ("220 ") - 1; + gchar *p, *t, *hostbuf = NULL; + gboolean has_crlf = FALSE; p = (gchar *)line; while (*p) { if (*p == '%') { - p ++; + p++; switch (*p) { - case 'n': - /* Assume %n as CRLF */ - banner_len += sizeof (CRLF) - 1 + sizeof ("220 -") - 1; - has_crlf = TRUE; - break; - case 'h': - hostmax = sysconf (_SC_HOST_NAME_MAX) + 1; - hostbuf = alloca (hostmax); - gethostname (hostbuf, hostmax); - hostbuf[hostmax - 1] = '\0'; - banner_len += strlen (hostbuf); - break; - case '%': - banner_len += 1; - break; - default: - banner_len += 2; - break; + case 'n': + /* Assume %n as CRLF */ + banner_len += sizeof (CRLF) - 1 + sizeof ("220 -") - 1; + has_crlf = TRUE; + break; + case 'h': + hostmax = sysconf (_SC_HOST_NAME_MAX) + 1; + hostbuf = alloca (hostmax); + gethostname (hostbuf, hostmax); + hostbuf[hostmax - 1] = '\0'; + banner_len += strlen (hostbuf); + break; + case '%': + banner_len += 1; + break; + default: + banner_len += 2; + break; } } else { - banner_len ++; + banner_len++; } - p ++; + p++; } - + if (has_crlf) { banner_len += sizeof (CRLF "220 " CRLF); } @@ -723,30 +794,30 @@ parse_smtp_banner (struct smtp_worker_ctx *ctx, const gchar *line) while (*p) { if (*p == '%') { - p ++; + p++; switch (*p) { - case 'n': - /* Assume %n as CRLF */ - *t++ = CR; *t++ = LF; - t = g_stpcpy (t, "220-"); - p ++; - break; - case 'h': - t = g_stpcpy (t, hostbuf); - p ++; - break; - case '%': - *t++ = '%'; - p ++; - break; - default: - /* Copy all %<gchar> to dest */ - *t++ = *(p - 1); *t++ = *p; - break; + case 'n': + /* Assume %n as CRLF */ + *t++ = CR; *t++ = LF; + t = g_stpcpy (t, "220-"); + p++; + break; + case 'h': + t = g_stpcpy (t, hostbuf); + p++; + break; + case '%': + *t++ = '%'; + p++; + break; + default: + /* Copy all %<gchar> to dest */ + *t++ = *(p - 1); *t++ = *p; + break; } } else { - *t ++ = *p ++; + *t++ = *p++; } } if (has_crlf) { @@ -760,12 +831,12 @@ parse_smtp_banner (struct smtp_worker_ctx *ctx, const gchar *line) static void make_capabilities (struct smtp_worker_ctx *ctx, const gchar *line) { - gchar **strv, *p, *result, *hostbuf; - guint32 num, i, len, hostmax; + gchar **strv, *p, *result, *hostbuf; + guint32 num, i, len, hostmax; strv = g_strsplit_set (line, ",;", -1); num = g_strv_length (strv); - + hostmax = sysconf (_SC_HOST_NAME_MAX) + 1; hostbuf = alloca (hostmax); gethostname (hostbuf, hostmax); @@ -773,26 +844,32 @@ make_capabilities (struct smtp_worker_ctx *ctx, const gchar *line) len = sizeof ("250-") + strlen (hostbuf) + sizeof (CRLF) - 1; - for (i = 0; i < num; i ++) { + for (i = 0; i < num; i++) { p = strv[i]; len += sizeof ("250-") + sizeof (CRLF) + strlen (p) - 2; } result = rspamd_mempool_alloc (ctx->pool, len); ctx->smtp_capabilities = result; - + p = result; if (num == 0) { p += rspamd_snprintf (p, len - (p - result), "250 %s" CRLF, hostbuf); } else { p += rspamd_snprintf (p, len - (p - result), "250-%s" CRLF, hostbuf); - for (i = 0; i < num; i ++) { + for (i = 0; i < num; i++) { if (i != num - 1) { - p += rspamd_snprintf (p, len - (p - result), "250-%s" CRLF, strv[i]); + p += rspamd_snprintf (p, + len - (p - result), + "250-%s" CRLF, + strv[i]); } else { - p += rspamd_snprintf (p, len - (p - result), "250 %s" CRLF, strv[i]); + p += rspamd_snprintf (p, + len - (p - result), + "250 %s" CRLF, + strv[i]); } } } @@ -803,14 +880,14 @@ make_capabilities (struct smtp_worker_ctx *ctx, const gchar *line) gpointer init_smtp (struct rspamd_config *cfg) { - struct smtp_worker_ctx *ctx; - GQuark type; + struct smtp_worker_ctx *ctx; + GQuark type; type = g_quark_try_string ("smtp"); ctx = g_malloc0 (sizeof (struct smtp_worker_ctx)); ctx->pool = rspamd_mempool_new (rspamd_mempool_suggest_size ()); - + /* Set default values */ ctx->smtp_timeout_raw = 300000; ctx->smtp_delay = 0; @@ -820,44 +897,49 @@ init_smtp (struct rspamd_config *cfg) ctx->reject_message = DEFAULT_REJECT_MESSAGE; rspamd_rcl_register_worker_option (cfg, type, "upstreams", - rspamd_rcl_parse_struct_string, ctx, - G_STRUCT_OFFSET (struct smtp_worker_ctx, upstreams_str), 0); + rspamd_rcl_parse_struct_string, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, upstreams_str), 0); rspamd_rcl_register_worker_option (cfg, type, "banner", - rspamd_rcl_parse_struct_string, ctx, - G_STRUCT_OFFSET (struct smtp_worker_ctx, smtp_banner_str), 0); + rspamd_rcl_parse_struct_string, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, smtp_banner_str), 0); rspamd_rcl_register_worker_option (cfg, type, "timeout", - rspamd_rcl_parse_struct_time, ctx, - G_STRUCT_OFFSET (struct smtp_worker_ctx, smtp_timeout_raw), RSPAMD_CL_FLAG_TIME_UINT_32); + rspamd_rcl_parse_struct_time, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, + smtp_timeout_raw), RSPAMD_CL_FLAG_TIME_UINT_32); rspamd_rcl_register_worker_option (cfg, type, "delay", - rspamd_rcl_parse_struct_time, ctx, - G_STRUCT_OFFSET (struct smtp_worker_ctx, smtp_delay), RSPAMD_CL_FLAG_TIME_UINT_32); + rspamd_rcl_parse_struct_time, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, + smtp_delay), RSPAMD_CL_FLAG_TIME_UINT_32); rspamd_rcl_register_worker_option (cfg, type, "jitter", - rspamd_rcl_parse_struct_time, ctx, - G_STRUCT_OFFSET (struct smtp_worker_ctx, delay_jitter), RSPAMD_CL_FLAG_TIME_UINT_32); + rspamd_rcl_parse_struct_time, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, + delay_jitter), RSPAMD_CL_FLAG_TIME_UINT_32); rspamd_rcl_register_worker_option (cfg, type, "capabilities", - rspamd_rcl_parse_struct_string, ctx, - G_STRUCT_OFFSET (struct smtp_worker_ctx, smtp_capabilities_str), 0); + rspamd_rcl_parse_struct_string, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, smtp_capabilities_str), 0); rspamd_rcl_register_worker_option (cfg, type, "xclient", - rspamd_rcl_parse_struct_boolean, ctx, - G_STRUCT_OFFSET (struct smtp_worker_ctx, use_xclient), 0); + rspamd_rcl_parse_struct_boolean, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, use_xclient), 0); rspamd_rcl_register_worker_option (cfg, type, "reject_message", - rspamd_rcl_parse_struct_string, ctx, - G_STRUCT_OFFSET (struct smtp_worker_ctx, reject_message), 0); + rspamd_rcl_parse_struct_string, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, reject_message), 0); rspamd_rcl_register_worker_option (cfg, type, "max_errors", - rspamd_rcl_parse_struct_integer, ctx, - G_STRUCT_OFFSET (struct smtp_worker_ctx, max_errors), RSPAMD_CL_FLAG_INT_32); + rspamd_rcl_parse_struct_integer, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, + max_errors), RSPAMD_CL_FLAG_INT_32); rspamd_rcl_register_worker_option (cfg, type, "max_size", - rspamd_rcl_parse_struct_integer, ctx, - G_STRUCT_OFFSET (struct smtp_worker_ctx, max_size), RSPAMD_CL_FLAG_INT_SIZE); + rspamd_rcl_parse_struct_integer, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, + max_size), RSPAMD_CL_FLAG_INT_SIZE); return ctx; } @@ -866,15 +948,16 @@ init_smtp (struct rspamd_config *cfg) static gboolean config_smtp_worker (struct rspamd_worker *worker) { - struct smtp_worker_ctx *ctx = worker->ctx; - gchar *value; + struct smtp_worker_ctx *ctx = worker->ctx; + gchar *value; /* Init timeval */ msec_to_tv (ctx->smtp_timeout_raw, &ctx->smtp_timeout); /* Init upstreams */ if ((value = ctx->upstreams_str) != NULL) { - if (!parse_upstreams_line (ctx->pool, ctx->upstreams, value, &ctx->upstream_num)) { + if (!parse_upstreams_line (ctx->pool, ctx->upstreams, value, + &ctx->upstream_num)) { return FALSE; } } @@ -891,7 +974,7 @@ config_smtp_worker (struct rspamd_worker *worker) if ((value = ctx->smtp_capabilities_str) != NULL) { make_capabilities (ctx, value); } - + return TRUE; } @@ -902,7 +985,7 @@ config_smtp_worker (struct rspamd_worker *worker) void start_smtp (struct rspamd_worker *worker) { - struct smtp_worker_ctx *ctx = worker->ctx; + struct smtp_worker_ctx *ctx = worker->ctx; ctx->ev_base = rspamd_prepare_worker (worker, "smtp_worker", accept_socket); @@ -922,15 +1005,18 @@ start_smtp (struct rspamd_worker *worker) umask (S_IWGRP | S_IWOTH | S_IROTH | S_IRGRP); event_base_loop (ctx->ev_base, 0); - + close_log (rspamd_main->logger); exit (EXIT_SUCCESS); } -void -register_smtp_filter (struct smtp_worker_ctx *ctx, enum rspamd_smtp_stage stage, smtp_filter_t filter, gpointer filter_data) +void +register_smtp_filter (struct smtp_worker_ctx *ctx, + enum rspamd_smtp_stage stage, + smtp_filter_t filter, + gpointer filter_data) { - struct smtp_filter *new; + struct smtp_filter *new; new = rspamd_mempool_alloc (ctx->pool, sizeof (struct smtp_filter)); @@ -941,10 +1027,11 @@ register_smtp_filter (struct smtp_worker_ctx *ctx, enum rspamd_smtp_stage stage, msg_err ("invalid smtp stage: %d", stage); } else { - ctx->smtp_filters[stage] = g_list_prepend (ctx->smtp_filters[stage], new); + ctx->smtp_filters[stage] = + g_list_prepend (ctx->smtp_filters[stage], new); } } -/* - * vi:ts=4 +/* + * vi:ts=4 */ |