Esempio n. 1
0
/**
 * Push error of redis request to lua callback
 * @param code
 * @param ud
 */
static void
lua_redis_push_error (const gchar *err,
	struct lua_redis_userdata *ud,
	gboolean connected)
{
	struct rspamd_task **ptask;

	/* Push error */
	lua_rawgeti (ud->L, LUA_REGISTRYINDEX, ud->cbref);
	ptask = lua_newuserdata (ud->L, sizeof (struct rspamd_task *));
	rspamd_lua_setclass (ud->L, "rspamd{task}", -1);

	*ptask = ud->task;
	/* String of error */
	lua_pushstring (ud->L, err);
	/* Data is nil */
	lua_pushnil (ud->L);
	if (lua_pcall (ud->L, 3, 0, 0) != 0) {
		msg_info ("call to callback failed: %s", lua_tostring (ud->L, -1));
	}

	if (connected) {
		rspamd_session_remove_event (ud->task->s, lua_redis_fin, ud);
	}
}
Esempio n. 2
0
static void
rspamd_symbols_cache_tm (gint fd, short what, void *data)
{
	struct rspamd_task *task = data;

	rspamd_session_remove_event (task->s, rspamd_symbols_cache_continuation,
			data);
}
Esempio n. 3
0
static void
lua_tcp_maybe_free (struct lua_tcp_cbdata *cbd)
{
	if (cbd->session) {
		rspamd_session_remove_event (cbd->session, lua_tcp_fin, cbd);
	}
	else {
		lua_tcp_fin (cbd);
	}
}
Esempio n. 4
0
/* Called when we have checked the specified message id */
static void
rspamd_stat_cache_redis_get (redisAsyncContext *c, gpointer r, gpointer priv)
{
	struct rspamd_redis_cache_runtime *rt = priv;
	redisReply *reply = r;
	struct rspamd_task *task;
	glong val = 0;

	task = rt->task;

	if (c->err == 0) {
		if (reply) {
			if (G_LIKELY (reply->type == REDIS_REPLY_INTEGER)) {
				val = reply->integer;
			}
			else if (reply->type == REDIS_REPLY_STRING) {
				rspamd_strtol (reply->str, reply->len, &val);
			}
			else {
				if (reply->type != REDIS_REPLY_NIL) {
					msg_err_task ("bad learned type for %s: %d",
							rt->ctx->stcf->symbol, reply->type);
				}

				val = 0;
			}
		}

		if ((val > 0 && (task->flags & RSPAMD_TASK_FLAG_LEARN_SPAM)) ||
				(val < 0 && (task->flags & RSPAMD_TASK_FLAG_LEARN_HAM))) {
			/* Already learned */
			g_set_error (&task->err, rspamd_stat_quark (), 404,
					"<%s> has been already "
					"learned as %s, ignore it", task->message_id,
					(task->flags & RSPAMD_TASK_FLAG_LEARN_SPAM) ? "spam" : "ham");
			task->flags |= RSPAMD_TASK_FLAG_ALREADY_LEARNED;
		}
		else if (val != 0) {
			/* Unlearn flag */
			task->flags |= RSPAMD_TASK_FLAG_UNLEARN;
		}
		rspamd_upstream_ok (rt->selected);
	}
	else {
		rspamd_upstream_fail (rt->selected);
	}

	if (rt->has_event) {
		rspamd_session_remove_event (task->s, rspamd_redis_cache_fin, rt);
	}
}
Esempio n. 5
0
static void
rspamd_redis_cache_timeout (gint fd, short what, gpointer d)
{
	struct rspamd_redis_cache_runtime *rt = d;
	struct rspamd_task *task;

	task = rt->task;

	msg_err_task ("connection to redis server %s timed out",
			rspamd_upstream_name (rt->selected));
	rspamd_upstream_fail (rt->selected);

	if (rt->has_event) {
		rspamd_session_remove_event (task->s, rspamd_redis_cache_fin, d);
	}
}
Esempio n. 6
0
/* Called when we have learned the specified message id */
static void
rspamd_stat_cache_redis_set (redisAsyncContext *c, gpointer r, gpointer priv)
{
	struct rspamd_redis_cache_runtime *rt = priv;
	struct rspamd_task *task;

	task = rt->task;

	if (c->err == 0) {
		/* XXX: we ignore results here */
		rspamd_upstream_ok (rt->selected);
	}
	else {
		rspamd_upstream_fail (rt->selected);
	}

	if (rt->has_event) {
		rspamd_session_remove_event (task->s, rspamd_redis_cache_fin, rt);
	}
}
Esempio n. 7
0
/**
 * Push data of redis request to lua callback
 * @param r redis reply data
 * @param ud
 */
static void
lua_redis_push_data (const redisReply *r, struct lua_redis_userdata *ud)
{
	struct rspamd_task **ptask;

	/* Push error */
	lua_rawgeti (ud->L, LUA_REGISTRYINDEX, ud->cbref);
	ptask = lua_newuserdata (ud->L, sizeof (struct rspamd_task *));
	rspamd_lua_setclass (ud->L, "rspamd{task}", -1);

	*ptask = ud->task;
	/* Error is nil */
	lua_pushnil (ud->L);
	/* Data */
	lua_redis_push_reply (ud->L, r);

	if (lua_pcall (ud->L, 3, 0, 0) != 0) {
		msg_info ("call to callback failed: %s", lua_tostring (ud->L, -1));
	}

	rspamd_session_remove_event (ud->task->s, lua_redis_fin, ud);
}
Esempio n. 8
0
/* Called when we have set tokens during learning */
static void
rspamd_redis_learned (redisAsyncContext *c, gpointer r, gpointer priv)
{
	struct redis_stat_runtime *rt = REDIS_RUNTIME (priv);
	struct rspamd_task *task;

	task = rt->task;

	if (c->err == 0) {
		rspamd_upstream_ok (rt->selected);
	}
	else {
		msg_err_task_check ("error getting reply from redis server %s: %s",
				rspamd_upstream_name (rt->selected), c->errstr);

		if (rt->redis) {
			rspamd_upstream_fail (rt->selected);
		}
	}

	if (rt->has_event) {
		rspamd_session_remove_event (task->s, rspamd_redis_fin_learn, rt);
	}
}
Esempio n. 9
0
gboolean
smtp_upstream_read_socket (rspamd_ftok_t * in, void *arg)
{
	struct smtp_session *session = arg;
	gchar outbuf[BUFSIZ];
	gint r;

	msg_debug ("in: %T, state: %d", in, session->upstream_state);
	switch (session->upstream_state) {
	case SMTP_STATE_GREETING:
		r = check_smtp_ustream_reply (in, '2');
		if (r == -1) {
			session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
			rspamd_strlcpy (session->error, in->begin, in->len + 1);
			/* XXX: assume upstream errors as critical errors */
			session->state = SMTP_STATE_CRITICAL_ERROR;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				in->len, FALSE, TRUE)) {
				goto err;
			}
			if (!rspamd_dispatcher_write (session->dispatcher, CRLF,
				sizeof (CRLF) - 1, FALSE, TRUE)) {
				goto err;
			}
			rspamd_session_destroy (session->s);
			return FALSE;
		}
		else if (r == 1) {
			if (session->ctx->use_xclient) {
				r = rspamd_snprintf (outbuf,
						sizeof (outbuf),
						"XCLIENT NAME=%s ADDR=%s" CRLF,
						session->resolved ? session->hostname : "[UNDEFINED]",
						inet_ntoa (session->client_addr));
				session->upstream_state = SMTP_STATE_HELO;
				return rspamd_dispatcher_write (session->upstream_dispatcher,
						   outbuf,
						   r,
						   FALSE,
						   FALSE);
			}
			else {
				session->upstream_state = SMTP_STATE_FROM;
				if (session->helo) {
					r = rspamd_snprintf (outbuf, sizeof (outbuf), "%s %s" CRLF,
							session->esmtp ? "EHLO" : "HELO",
							session->helo);
				}
				else {
					return smtp_upstream_read_socket (in, arg);
				}
				return rspamd_dispatcher_write (session->upstream_dispatcher,
						   outbuf,
						   r,
						   FALSE,
						   FALSE);
			}
		}
		break;
	case SMTP_STATE_HELO:
		r = check_smtp_ustream_reply (in, '2');
		if (r == -1) {
			session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
			rspamd_strlcpy (session->error, in->begin, in->len + 1);
			/* XXX: assume upstream errors as critical errors */
			session->state = SMTP_STATE_CRITICAL_ERROR;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				in->len, FALSE, TRUE)) {
				goto err;
			}
			if (!rspamd_dispatcher_write (session->dispatcher, CRLF,
				sizeof (CRLF) - 1, FALSE, TRUE)) {
				goto err;
			}
			rspamd_session_destroy (session->s);
			return FALSE;
		}
		else if (r == 1) {
			session->upstream_state = SMTP_STATE_FROM;
			if (session->helo) {
				r = rspamd_snprintf (outbuf, sizeof (outbuf), "%s %s" CRLF,
						session->esmtp ? "EHLO" : "HELO",
						session->helo);
			}
			else {
				return smtp_upstream_read_socket (in, arg);
			}
			return rspamd_dispatcher_write (session->upstream_dispatcher,
					   outbuf,
					   r,
					   FALSE,
					   FALSE);
		}
		break;
	case SMTP_STATE_FROM:
		r = check_smtp_ustream_reply (in, '2');
		if (r == -1) {
			session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
			rspamd_strlcpy (session->error, in->begin, in->len + 1);
			/* XXX: assume upstream errors as critical errors */
			session->state = SMTP_STATE_CRITICAL_ERROR;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				in->len, FALSE, TRUE)) {
				goto err;
			}
			if (!rspamd_dispatcher_write (session->dispatcher, CRLF,
				sizeof (CRLF) - 1, FALSE, TRUE)) {
				goto err;
			}
			rspamd_session_destroy (session->s);
			return FALSE;
		}
		else if (r == 1) {
			r = rspamd_snprintf (outbuf, sizeof (outbuf), "MAIL FROM: ");
			r +=
				smtp_upstream_write_list (session->from,
					outbuf + r,
					sizeof (outbuf) - r);
			session->upstream_state = SMTP_STATE_RCPT;
			return rspamd_dispatcher_write (session->upstream_dispatcher,
					   outbuf,
					   r,
					   FALSE,
					   FALSE);
		}
		break;
	case SMTP_STATE_RCPT:
		r = check_smtp_ustream_reply (in, '2');
		if (r == -1) {
			session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
			rspamd_strlcpy (session->error, in->begin, in->len + 1);
			/* XXX: assume upstream errors as critical errors */
			session->state = SMTP_STATE_CRITICAL_ERROR;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				in->len, FALSE, TRUE)) {
				goto err;
			}
			if (!rspamd_dispatcher_write (session->dispatcher, CRLF,
				sizeof (CRLF) - 1, FALSE, TRUE)) {
				goto err;
			}
			rspamd_session_destroy (session->s);
			return FALSE;
		}
		else if (r == 1) {
			r = rspamd_snprintf (outbuf, sizeof (outbuf), "RCPT TO: ");
			session->cur_rcpt = g_list_first (session->rcpt);
			r += smtp_upstream_write_list (session->cur_rcpt->data,
					outbuf + r,
					sizeof (outbuf) - r);
			session->cur_rcpt = g_list_next (session->cur_rcpt);
			session->upstream_state = SMTP_STATE_BEFORE_DATA;
			return rspamd_dispatcher_write (session->upstream_dispatcher,
					   outbuf,
					   r,
					   FALSE,
					   FALSE);
		}
		break;
	case SMTP_STATE_BEFORE_DATA:
		r = check_smtp_ustream_reply (in, '2');
		if (r == -1) {
			session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
			rspamd_strlcpy (session->error, in->begin, in->len + 1);
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				in->len, FALSE, TRUE)) {
				goto err;
			}
			if (!rspamd_dispatcher_write (session->dispatcher, CRLF,
				sizeof (CRLF) - 1, FALSE, TRUE)) {
				goto err;
			}
			if (session->cur_rcpt) {
				session->rcpt = g_list_delete_link (session->rcpt,
						session->cur_rcpt);
			}
			else {
				session->rcpt =
					g_list_delete_link (session->rcpt, session->rcpt);
			}
			session->errors++;
			session->state = SMTP_STATE_RCPT;
			return TRUE;
		}
		else if (r == 1) {
			if (session->cur_rcpt != NULL) {
				r = rspamd_snprintf (outbuf, sizeof (outbuf), "RCPT TO: ");
				r += smtp_upstream_write_list (session->cur_rcpt,
						outbuf + r,
						sizeof (outbuf) - r);
				session->cur_rcpt = g_list_next (session->cur_rcpt);
				if (!rspamd_dispatcher_write (session->upstream_dispatcher,
					outbuf, r, FALSE, FALSE)) {
					goto err;
				}
			}
			else {
				session->upstream_state = SMTP_STATE_DATA;
				rspamd_dispatcher_pause (session->upstream_dispatcher);
			}
			session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
			rspamd_strlcpy (session->error, in->begin, in->len + 1);
			/* Write to client */
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				in->len, FALSE, TRUE)) {
				goto err;
			}
			if (!rspamd_dispatcher_write (session->dispatcher, CRLF,
				sizeof (CRLF) - 1, FALSE, TRUE)) {
				goto err;
			}
			if (session->state == SMTP_STATE_WAIT_UPSTREAM) {
				rspamd_dispatcher_restore (session->dispatcher);
				session->state = SMTP_STATE_RCPT;
			}
		}
		break;
	case SMTP_STATE_DATA:
		r = check_smtp_ustream_reply (in, '3');
		if (r == -1) {
			session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
			rspamd_strlcpy (session->error, in->begin, in->len + 1);
			/* XXX: assume upstream errors as critical errors */
			session->state = SMTP_STATE_CRITICAL_ERROR;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				0, FALSE, TRUE)) {
				goto err;
			}
			if (!rspamd_dispatcher_write (session->dispatcher, CRLF,
				sizeof (CRLF) - 1, FALSE, TRUE)) {
				goto err;
			}
			rspamd_session_destroy (session->s);
			return FALSE;
		}
		else if (r == 1) {
			if (!make_smtp_tempfile (session)) {
				session->error = SMTP_ERROR_FILE;
				session->state = SMTP_STATE_CRITICAL_ERROR;
				rspamd_dispatcher_restore (session->dispatcher);
				if (!rspamd_dispatcher_write (session->dispatcher,
					session->error, 0, FALSE, TRUE)) {
					goto err;
				}
				rspamd_session_destroy (session->s);
				return FALSE;
			}
			session->state = SMTP_STATE_AFTER_DATA;
			session->error = SMTP_ERROR_DATA_OK;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				0, FALSE, TRUE)) {
				goto err;
			}
			rspamd_dispatcher_pause (session->upstream_dispatcher);
			rspamd_set_dispatcher_policy (session->dispatcher, BUFFER_LINE, 0);
			session->dispatcher->strip_eol = FALSE;
			return TRUE;
		}
		break;
	case SMTP_STATE_AFTER_DATA:
		session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
		rspamd_strlcpy (session->error, in->begin, in->len + 1);
		session->state = SMTP_STATE_DATA;
		rspamd_dispatcher_restore (session->dispatcher);
		if (!rspamd_dispatcher_write (session->dispatcher, session->error, 0,
			FALSE, TRUE)) {
			goto err;
		}
		if (!rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) -
			1, FALSE, TRUE)) {
			goto err;
		}
		if (!rspamd_dispatcher_write (session->upstream_dispatcher, "QUIT" CRLF,
			sizeof ("QUIT" CRLF) - 1, FALSE, TRUE)) {
			goto err;
		}
		session->upstream_state = SMTP_STATE_END;
		return TRUE;
		break;
	case SMTP_STATE_END:
		r = check_smtp_ustream_reply (in, '5');
		if (r == -1) {
			session->error = rspamd_mempool_alloc (session->pool, in->len + 1);
			rspamd_strlcpy (session->error, in->begin, in->len + 1);
			/* XXX: assume upstream errors as critical errors */
			session->state = SMTP_STATE_CRITICAL_ERROR;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				0, FALSE, TRUE)) {
				goto err;
			}
			if (!rspamd_dispatcher_write (session->dispatcher, CRLF,
				sizeof (CRLF) - 1, FALSE, TRUE)) {
				goto err;
			}
			rspamd_session_destroy (session->s);
			return FALSE;
		}
		else {
			rspamd_session_remove_event (session->s,
				(event_finalizer_t)smtp_upstream_finalize_connection,
				session);
		}
		return FALSE;
		break;
	default:
		msg_err ("got upstream reply at unexpected state: %d, reply: %T",
			session->upstream_state,
			in);
		session->state = SMTP_STATE_CRITICAL_ERROR;
		rspamd_dispatcher_restore (session->dispatcher);
		if (!rspamd_dispatcher_write (session->dispatcher, session->error, 0,
			FALSE, TRUE)) {
			goto err;
		}
		if (!rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) -
			1, FALSE, TRUE)) {
			goto err;
		}
		rspamd_session_destroy (session->s);
		return FALSE;
	}

	return TRUE;
err:
	msg_warn ("write error occured");
	return FALSE;
}
Esempio n. 10
0
/* Called when we have received tokens values from redis */
static void
rspamd_redis_processed (redisAsyncContext *c, gpointer r, gpointer priv)
{
	struct redis_stat_runtime *rt = REDIS_RUNTIME (priv);
	redisReply *reply = r, *elt;
	struct rspamd_task *task;
	rspamd_token_t *tok;
	guint i, processed = 0, found = 0;
	gulong val;
	gdouble float_val;

	task = rt->task;

	if (c->err == 0) {
		if (r != NULL) {
			if (reply->type == REDIS_REPLY_ARRAY) {

				if (reply->elements == task->tokens->len) {
					for (i = 0; i < reply->elements; i ++) {
						tok = g_ptr_array_index (task->tokens, i);
						elt = reply->element[i];

						if (G_UNLIKELY (elt->type == REDIS_REPLY_INTEGER)) {
							tok->values[rt->id] = elt->integer;
							found ++;
						}
						else if (elt->type == REDIS_REPLY_STRING) {
							if (rt->stcf->clcf->flags &
									RSPAMD_FLAG_CLASSIFIER_INTEGER) {
								rspamd_strtoul (elt->str, elt->len, &val);
								tok->values[rt->id] = val;
							}
							else {
								float_val = strtod (elt->str, NULL);
								tok->values[rt->id] = float_val;
							}

							found ++;
						}
						else {
							tok->values[rt->id] = 0;
						}

						processed ++;
					}

					if (rt->stcf->is_spam) {
						task->flags |= RSPAMD_TASK_FLAG_HAS_SPAM_TOKENS;
					}
					else {
						task->flags |= RSPAMD_TASK_FLAG_HAS_HAM_TOKENS;
					}
				}
				else {
					msg_err_task_check ("got invalid length of reply vector from redis: "
							"%d, expected: %d",
							(gint)reply->elements,
							(gint)task->tokens->len);
				}
			}
			else {
				msg_err_task_check ("got invalid reply from redis: %d",
						reply->type);
			}

			msg_debug_task_check ("received tokens for %s: %d processed, %d found",
					rt->redis_object_expanded, processed, found);
			rspamd_upstream_ok (rt->selected);
		}
	}
	else {
		msg_err_task ("error getting reply from redis server %s: %s",
				rspamd_upstream_name (rt->selected), c->errstr);

		if (rt->redis) {
			rspamd_upstream_fail (rt->selected);
		}
	}

	if (rt->has_event) {
		rspamd_session_remove_event (task->s, rspamd_redis_fin, rt);
	}
}