.module 'regexp' {
SYMBOL = "regexp_expression";
};
+header_filters = "regexp";
+
+Обратите внимание, что модуль regexp надо регистрировать как header filter, так как иначе он не будет работать.
+Эту проблему надо исправлять, но это не первоочередная задача.
Формат регэкспов такой:
/pattern/flags
Флаги регэскпов:
i, m, s, x, u, o - такие же, как у perl/pcre
H - ищет по заголовкам
-M - ищет по всему сообщению
+M - ищет по всему сообщению (в "сыром" виде)
P - ищет по всем mime частям
U - ищет по url
+X - ищет по "сырым" хедерам (тут нужно учитывать фолдинг и ставить, где надо, /m для multiline матчинга)
+
Выражение регэкспов может содержать сложные выражения из нескольких регэкспов, операторов логики и скобок:
SOME_SYMBOL = "To=/blah@blah/H & !(From=/blah@blah/H | Subject=/blah/H)"
+
Также можно использовать переменные:
$to_blah = "To=/blah@blah/H";
$from_blah = "From=/blah@blah/H";
$subject_blah = "Subject=/blah/H";
+
тогда предыдущее выражение будет таким
+
SOME_SYMBOL = "${to_blah} & !(${from_blah} | ${subject_blah})"
};
/**
- * Regexp type: /H - header, /M - mime, /U - url
+ * Regexp type: /H - header, /M - mime, /U - url /X - raw header
*/
enum rspamd_regexp_type {
REGEXP_NONE = 0,
REGEXP_MIME,
REGEXP_MESSAGE,
REGEXP_URL,
+ REGEXP_RAW_HEADER,
};
/**
}
p ++;
break;
+ case 'X':
+ if (result->type == REGEXP_NONE || result->type == REGEXP_HEADER) {
+ result->type = REGEXP_RAW_HEADER;
+ }
+ p ++;
+ break;
/* Stop flags parsing */
default:
p = NULL;
int parts_count; /**< mime parts count */
GMimeMessage *message; /**< message, parsed with GMime */
GList *parts; /**< list of parsed parts */
+ char *raw_headers; /**< list of raw headers */
TAILQ_HEAD (uriq, uri) urls; /**< list of parsed urls */
GHashTable *results; /**< hash table of metric_result indexed by
* metric's name */
task->message_id = "undef";
}
+#ifdef GMIME24
+ task->raw_headers = g_mime_object_get_headers (GMIME_OBJECT (task->message));
+#else
+ task->raw_headers = g_mime_message_get_headers (task->message);
+#endif
+
+ if (task->raw_headers) {
+ memory_pool_add_destructor (task->task_pool, (pool_destruct_func)g_free, task->raw_headers);
+ }
+
task->worker->srv->stat->messages_scanned ++;
/* free the parser (and the stream) */
static gsize
process_regexp (struct rspamd_regexp *re, struct worker_task *task)
{
- char *headerv;
+ char *headerv, *c, t;
struct mime_part *part;
GList *cur;
struct uri *url;
}
return 0;
case REGEXP_MESSAGE:
- msg_debug ("process_message: checking message regexp: /%s/", re->regexp_text);
+ msg_debug ("process_regexp: checking message regexp: /%s/", re->regexp_text);
if (g_regex_match_full (re->regexp, task->msg->begin, task->msg->len, 0, 0, NULL, NULL) == TRUE) {
return 1;
}
return 0;
case REGEXP_URL:
- msg_debug ("process_url: checking url regexp: /%s/", re->regexp_text);
+ msg_debug ("process_regexp: checking url regexp: /%s/", re->regexp_text);
TAILQ_FOREACH (url, &task->urls, next) {
if (g_regex_match (re->regexp, struri (url), 0, NULL) == TRUE) {
return 1;
}
}
return 0;
+ case REGEXP_RAW_HEADER:
+ msg_debug ("process_regexp: checking for raw header: %s with regexp: /%s/", re->header, re->regexp_text);
+ if (task->raw_headers == NULL) {
+ msg_debug ("process_regexp: cannot check for raw header in message, no headers found");
+ return 0;
+ }
+ if ((headerv = strstr (task->raw_headers, re->header)) == NULL) {
+ /* No header was found */
+ return 0;
+ }
+ /* Skip header name and start matching after regexp */
+ headerv += strlen (re->header) + 1;
+ /* Now the main problem is to find position of end of raw header */
+ c = headerv;
+ while (*c) {
+ /* We need to handle all types of line end */
+ if ((*c == '\r' && *(c + 1) == '\n')) {
+ c ++;
+ /* Check for folding */
+ if (!g_ascii_isspace (*(c + 1))) {
+ c ++;
+ break;
+ }
+ }
+ else if (*c == '\r' || *c == '\n') {
+ if (!g_ascii_isspace (*(c + 1))) {
+ c ++;
+ break;
+ }
+ }
+ c ++;
+ }
+ /* Temporary null terminate this part of string */
+ t = *c;
+ *c = '\0';
+ if (g_regex_match (re->regexp, headerv, 0, NULL) == TRUE) {
+ *c = t;
+ return 1;
+ }
+ *c = t;
+ return 0;
}
/* Not reached */