mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-06-29 21:56:37 +02:00
Add spamfilter::rule (preconditions), add context to crule parser,
and add the first functions: online_time() and reputation(). The more interesting stuff will follow later...
This commit is contained in:
+6
-5
@@ -534,7 +534,7 @@ extern void init_CommandHash(void);
|
||||
/* CRULE */
|
||||
extern struct CRuleNode* crule_parse(const char*);
|
||||
extern void crule_free(struct CRuleNode**);
|
||||
extern int crule_eval(struct CRuleNode* rule);
|
||||
extern int crule_eval(crule_context *context, CRuleNode *rule);
|
||||
extern int crule_test(const char *rule);
|
||||
extern const char *crule_errstring(int errcode);
|
||||
|
||||
@@ -818,10 +818,11 @@ extern MODVAR TKL *(*tkl_add_banexception)(int type, const char *usermask, const
|
||||
time_t expire_at, time_t set_at, int soft, const char *bantypes, int flags);
|
||||
extern MODVAR TKL *(*tkl_add_nameban)(int type, const char *name, int hold, const char *reason, const char *setby,
|
||||
time_t expire_at, time_t set_at, int flags);
|
||||
extern MODVAR TKL *(*tkl_add_spamfilter)(int type, unsigned short target, BanAction *action, Match *match, const char *setby,
|
||||
time_t expire_at, time_t set_at,
|
||||
time_t spamf_tkl_duration, const char *spamf_tkl_reason,
|
||||
int flags);
|
||||
extern MODVAR TKL *(*tkl_add_spamfilter)(int type, unsigned short target, BanAction *action,
|
||||
Match *match, const char *rule, const char *setby,
|
||||
time_t expire_at, time_t set_at,
|
||||
time_t spamf_tkl_duration, const char *spamf_tkl_reason,
|
||||
int flags);
|
||||
extern MODVAR TKL *(*find_tkl_serverban)(int type, const char *usermask, const char *hostmask, int softban);
|
||||
extern MODVAR TKL *(*find_tkl_banexception)(int type, const char *usermask, const char *hostmask, int softban);
|
||||
extern MODVAR TKL *(*find_tkl_nameban)(int type, const char *name, int hold);
|
||||
|
||||
+34
-26
@@ -855,6 +855,7 @@ struct LoopStruct {
|
||||
typedef enum {
|
||||
MATCH_SIMPLE=1, /**< Simple pattern with * and ? */
|
||||
MATCH_PCRE_REGEX=2, /**< PCRE2 Perl-like regex (new) */
|
||||
MATCH_NONE=3, /**< No matching at all (rule-based) */
|
||||
} MatchType;
|
||||
|
||||
/** Match struct, which allows various matching styles, see MATCH_* */
|
||||
@@ -1063,6 +1064,37 @@ struct Secret {
|
||||
SecretCache *cache;
|
||||
};
|
||||
|
||||
/* CRULE stuff */
|
||||
|
||||
#define CRULE_ALL 0
|
||||
#define CRULE_AUTO 1
|
||||
|
||||
/* some constants and shared data types */
|
||||
#define CR_MAXARGLEN 80 /**< Maximum arg length (must be > HOSTLEN) */
|
||||
#define CR_MAXARGS 3 /**< Maximum number of args for a rule */
|
||||
|
||||
/* context when running a crule */
|
||||
typedef struct crule_context crule_context;
|
||||
struct crule_context
|
||||
{
|
||||
Client *client;
|
||||
};
|
||||
|
||||
/** Evaluation function for a connection rule. */
|
||||
typedef int (*crule_funcptr) (crule_context *context, int, void **);
|
||||
|
||||
/** CRULE - Node in a connection rule tree. */
|
||||
struct CRuleNode {
|
||||
crule_funcptr funcptr; /**< Evaluation function for this node. */
|
||||
int numargs; /**< Number of arguments. */
|
||||
void *arg[CR_MAXARGS]; /**< Array of arguments. For operators, each arg
|
||||
is a tree element; for functions, each arg is
|
||||
a string. */
|
||||
int func_test_type; /* for >, < and == */
|
||||
int func_test_value; /* integer value to compare against */
|
||||
};
|
||||
typedef struct CRuleNode CRuleNode;
|
||||
typedef struct CRuleNode* CRuleNodePtr;
|
||||
|
||||
/* tkl:
|
||||
* TKL_KILL|TKL_GLOBAL = Global K-Line (GLINE)
|
||||
@@ -1176,6 +1208,8 @@ struct Spamfilter {
|
||||
unsigned short target;
|
||||
BanAction *action; /**< Ban action */
|
||||
Match *match; /**< Spamfilter matcher */
|
||||
CRuleNode *rule; /**< parsed crule */
|
||||
char *prettyrule; /**< human printable version */
|
||||
char *tkl_reason; /**< Reason to use for bans placed by this spamfilter, escaped by unreal_encodespace(). */
|
||||
time_t tkl_duration; /**< Duration of bans placed by this spamfilter */
|
||||
};
|
||||
@@ -1529,32 +1563,6 @@ struct AuthConfig {
|
||||
#define crypt DES_crypt
|
||||
#endif
|
||||
|
||||
/* CRULE stuff */
|
||||
|
||||
#define CRULE_ALL 0
|
||||
#define CRULE_AUTO 1
|
||||
|
||||
/* some constants and shared data types */
|
||||
#define CR_MAXARGLEN 80 /**< Maximum arg length (must be > HOSTLEN) */
|
||||
#define CR_MAXARGS 3 /**< Maximum number of args for a rule */
|
||||
|
||||
/** Evaluation function for a connection rule. */
|
||||
typedef int (*crule_funcptr) (int, void **);
|
||||
|
||||
/** CRULE - Node in a connection rule tree. */
|
||||
struct CRuleNode {
|
||||
crule_funcptr funcptr; /**< Evaluation function for this node. */
|
||||
int numargs; /**< Number of arguments. */
|
||||
void *arg[CR_MAXARGS]; /**< Array of arguments. For operators, each arg
|
||||
is a tree element; for functions, each arg is
|
||||
a string. */
|
||||
int func_test_type; /* for >, < and == */
|
||||
int func_test_value; /* integer value to compare against */
|
||||
};
|
||||
typedef struct CRuleNode CRuleNode;
|
||||
typedef struct CRuleNode* CRuleNodePtr;
|
||||
|
||||
|
||||
/*
|
||||
* conf2 stuff -stskeeps
|
||||
*/
|
||||
|
||||
@@ -55,10 +55,11 @@ TKL *(*tkl_add_serverban)(int type, const char *usermask, const char *hostmask,
|
||||
time_t expire_at, time_t set_at, int soft, int flags);
|
||||
TKL *(*tkl_add_nameban)(int type, const char *name, int hold, const char *reason, const char *setby,
|
||||
time_t expire_at, time_t set_at, int flags);
|
||||
TKL *(*tkl_add_spamfilter)(int type, unsigned short target, BanAction *action, Match *match, const char *setby,
|
||||
time_t expire_at, time_t set_at,
|
||||
time_t spamf_tkl_duration, const char *spamf_tkl_reason,
|
||||
int flags);
|
||||
TKL *(*tkl_add_spamfilter)(int type, unsigned short target, BanAction *action,
|
||||
Match *match, const char *rule, const char *setby,
|
||||
time_t expire_at, time_t set_at,
|
||||
time_t spamf_tkl_duration, const char *spamf_tkl_reason,
|
||||
int flags);
|
||||
TKL *(*tkl_add_banexception)(int type, const char *usermask, const char *hostmask, SecurityGroup *match,
|
||||
const char *reason, const char *set_by,
|
||||
time_t expire_at, time_t set_at, int soft, const char *bantypes, int flags);
|
||||
|
||||
+40
-20
@@ -132,12 +132,15 @@ enum crule_errcode {
|
||||
*/
|
||||
|
||||
/* rule function prototypes - local! */
|
||||
static int crule_connected(int, void **);
|
||||
static int crule_directcon(int, void **);
|
||||
static int crule_via(int, void **);
|
||||
static int crule_directop(int, void **);
|
||||
static int crule__andor(int, void **);
|
||||
static int crule__not(int, void **);
|
||||
static int crule_connected(crule_context *, int, void **);
|
||||
static int crule_directcon(crule_context *, int, void **);
|
||||
static int crule_via(crule_context *, int, void **);
|
||||
static int crule_directop(crule_context *, int, void **);
|
||||
static int crule__andor(crule_context *, int, void **);
|
||||
static int crule__not(crule_context *, int, void **);
|
||||
// newstyle
|
||||
static int crule_online_time(crule_context *, int, void **);
|
||||
static int crule_reputation(crule_context *, int, void **);
|
||||
|
||||
/* parsing function prototypes - local! */
|
||||
static int crule_gettoken(crule_token *next_tokp, const char** str);
|
||||
@@ -185,13 +188,15 @@ struct crule_funclistent {
|
||||
struct crule_funclistent crule_funclist[] = {
|
||||
/* maximum function name length is 14 chars */
|
||||
{"connected", 1, crule_connected},
|
||||
{"online_time", 0, crule_online_time},
|
||||
{"reputation", 0, crule_reputation},
|
||||
{"directcon", 1, crule_directcon},
|
||||
{"via", 2, crule_via},
|
||||
{"directop", 0, crule_directop},
|
||||
{"", 0, NULL} /* this must be here to mark end of list */
|
||||
};
|
||||
|
||||
static int crule_connected(int numargs, void *crulearg[])
|
||||
static int crule_connected(crule_context *context, int numargs, void *crulearg[])
|
||||
{
|
||||
#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
|
||||
Client *client;
|
||||
@@ -208,7 +213,7 @@ static int crule_connected(int numargs, void *crulearg[])
|
||||
#endif
|
||||
}
|
||||
|
||||
static int crule_directcon(int numargs, void *crulearg[])
|
||||
static int crule_directcon(crule_context *context, int numargs, void *crulearg[])
|
||||
{
|
||||
#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
|
||||
Client *client;
|
||||
@@ -227,7 +232,7 @@ static int crule_directcon(int numargs, void *crulearg[])
|
||||
#endif
|
||||
}
|
||||
|
||||
static int crule_via(int numargs, void *crulearg[])
|
||||
static int crule_via(crule_context *context, int numargs, void *crulearg[])
|
||||
{
|
||||
#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
|
||||
Client *client;
|
||||
@@ -246,7 +251,7 @@ static int crule_via(int numargs, void *crulearg[])
|
||||
#endif
|
||||
}
|
||||
|
||||
static int crule_directop(int numargs, void *crulearg[])
|
||||
static int crule_directop(crule_context *context, int numargs, void *crulearg[])
|
||||
{
|
||||
#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
|
||||
Client *client;
|
||||
@@ -264,13 +269,27 @@ static int crule_directop(int numargs, void *crulearg[])
|
||||
#endif
|
||||
}
|
||||
|
||||
static int crule_online_time(crule_context *context, int numargs, void *crulearg[])
|
||||
{
|
||||
if (context && context->client)
|
||||
return get_connected_time(context->client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crule_reputation(crule_context *context, int numargs, void *crulearg[])
|
||||
{
|
||||
if (context && context->client)
|
||||
return GetReputation(context->client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Evaluate a connection rule.
|
||||
* @param[in] rule Rule to evalute.
|
||||
* @return Non-zero if the rule allows the connection, zero otherwise.
|
||||
*/
|
||||
int crule_eval(struct CRuleNode* rule)
|
||||
int crule_eval(crule_context *context, struct CRuleNode* rule)
|
||||
{
|
||||
int ret = rule->funcptr(rule->numargs, rule->arg);
|
||||
int ret = rule->funcptr(context, rule->numargs, rule->arg);
|
||||
switch (rule->func_test_type)
|
||||
{
|
||||
case CR_EQUAL:
|
||||
@@ -300,15 +319,15 @@ int crule_eval(struct CRuleNode* rule)
|
||||
* @param[in] crulearg Argument array.
|
||||
* @return Non-zero if the condition is true, zero if not.
|
||||
*/
|
||||
static int crule__andor(int numargs, void *crulearg[])
|
||||
static int crule__andor(crule_context *context, int numargs, void *crulearg[])
|
||||
{
|
||||
int result1;
|
||||
|
||||
result1 = crule_eval(crulearg[0]);
|
||||
result1 = crule_eval(context, crulearg[0]);
|
||||
if (crulearg[2]) /* or */
|
||||
return (result1 || crule_eval(crulearg[1]));
|
||||
return (result1 || crule_eval(context, crulearg[1]));
|
||||
else
|
||||
return (result1 && crule_eval(crulearg[1]));
|
||||
return (result1 && crule_eval(context, crulearg[1]));
|
||||
}
|
||||
|
||||
/** Logically invert the result of crulearg[0].
|
||||
@@ -316,9 +335,9 @@ static int crule__andor(int numargs, void *crulearg[])
|
||||
* @param[in] crulearg Argument array.
|
||||
* @return Non-zero if the condition is true, zero if not.
|
||||
*/
|
||||
static int crule__not(int numargs, void *crulearg[])
|
||||
static int crule__not(crule_context *context, int numargs, void *crulearg[])
|
||||
{
|
||||
return (!crule_eval(crulearg[0]));
|
||||
return (!crule_eval(context, crulearg[0]));
|
||||
}
|
||||
|
||||
/** Scan an input token from \a ruleptr.
|
||||
@@ -388,7 +407,7 @@ static int crule_gettoken(crule_token *next_tokp, const char** ruleptr)
|
||||
break;
|
||||
default:
|
||||
if ((isalnum(*(--(*ruleptr)))) || (**ruleptr == '*') ||
|
||||
(**ruleptr == '?') || (**ruleptr == '.') || (**ruleptr == '-'))
|
||||
(**ruleptr == '?') || (**ruleptr == '.') || (**ruleptr == '-') || (**ruleptr == '_'))
|
||||
*next_tokp = CR_WORD;
|
||||
else
|
||||
return (CR_UNKNWTOK);
|
||||
@@ -411,7 +430,8 @@ static void crule_getword(char* word, int* wordlenp, size_t maxlen, const char**
|
||||
while ((size_t)(word_ptr - word) < maxlen
|
||||
&& (isalnum(**ruleptr)
|
||||
|| **ruleptr == '*' || **ruleptr == '?'
|
||||
|| **ruleptr == '.' || **ruleptr == '-'))
|
||||
|| **ruleptr == '.' || **ruleptr == '-'
|
||||
|| **ruleptr == '_'))
|
||||
*word_ptr++ = *(*ruleptr)++;
|
||||
*word_ptr = '\0';
|
||||
*wordlenp = word_ptr - word;
|
||||
|
||||
+7
-2
@@ -569,8 +569,13 @@ void json_expand_tkl(json_t *root, const char *key, TKL *tkl, int detail)
|
||||
} else
|
||||
if (TKLIsSpamfilter(tkl))
|
||||
{
|
||||
json_object_set_new(j, "name", json_string_unreal(tkl->ptr.spamfilter->match->str));
|
||||
json_object_set_new(j, "match_type", json_string_unreal(unreal_match_method_valtostr(tkl->ptr.spamfilter->match->type)));
|
||||
if (tkl->ptr.spamfilter->match->str)
|
||||
{
|
||||
json_object_set_new(j, "name", json_string_unreal(tkl->ptr.spamfilter->match->str));
|
||||
json_object_set_new(j, "match_type", json_string_unreal(unreal_match_method_valtostr(tkl->ptr.spamfilter->match->type)));
|
||||
}
|
||||
if (tkl->ptr.spamfilter->prettyrule)
|
||||
json_object_set_new(j, "rule", json_string_unreal(tkl->ptr.spamfilter->prettyrule));
|
||||
json_object_set_new(j, "ban_action", json_string_unreal(ban_actions_to_string(tkl->ptr.spamfilter->action)));
|
||||
json_object_set_new(j, "ban_duration", json_integer(tkl->ptr.spamfilter->tkl_duration));
|
||||
json_object_set_new(j, "ban_duration_string", json_string_unreal(pretty_time_val_r(buf, sizeof(buf), tkl->ptr.spamfilter->tkl_duration)));
|
||||
|
||||
+11
-1
@@ -428,6 +428,9 @@ Match *unreal_create_match(MatchType type, const char *str, char **error)
|
||||
}
|
||||
pcre2_jit_compile(m->ext.pcre2_expr, PCRE2_JIT_COMPLETE);
|
||||
return m;
|
||||
} else if (m->type == MATCH_NONE)
|
||||
{
|
||||
/* Nothing to do */
|
||||
}
|
||||
else {
|
||||
/* Unknown type, how did that happen ? */
|
||||
@@ -463,6 +466,9 @@ int unreal_match(Match *m, const char *str)
|
||||
return 0; /* NO MATCH */
|
||||
}
|
||||
|
||||
if (m->type == MATCH_NONE)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -472,6 +478,8 @@ int unreal_match_method_strtoval(const char *str)
|
||||
return MATCH_PCRE_REGEX;
|
||||
if (!strcmp(str, "simple") || !strcmp(str, "glob"))
|
||||
return MATCH_SIMPLE;
|
||||
if (!strcmp(str, "none"))
|
||||
return MATCH_NONE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -481,7 +489,9 @@ char *unreal_match_method_valtostr(int val)
|
||||
return "regex";
|
||||
if (val == MATCH_SIMPLE)
|
||||
return "simple";
|
||||
|
||||
if (val == MATCH_NONE)
|
||||
return "none";
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -971,7 +971,7 @@ char *spamfilter_target_inttostring(int v)
|
||||
if (v & e->value)
|
||||
*p++ = e->character;
|
||||
*p = '\0';
|
||||
return buf;
|
||||
return *buf ? buf : "-";
|
||||
}
|
||||
|
||||
/** Replace underscores back to the space character.
|
||||
|
||||
@@ -247,7 +247,7 @@ RPC_CALL_FUNC(rpc_spamfilter_add)
|
||||
return;
|
||||
}
|
||||
|
||||
tkl = tkl_add_spamfilter(type, targets, banact_value_to_struct(action), m, set_by, 0, TStime(),
|
||||
tkl = tkl_add_spamfilter(type, targets, banact_value_to_struct(action), m, NULL, set_by, 0, TStime(),
|
||||
ban_duration, reason, 0);
|
||||
|
||||
if (!tkl)
|
||||
|
||||
@@ -2204,13 +2204,14 @@ int _is_services_but_not_ulined(Client *client)
|
||||
const char *_check_deny_link(ConfigItem_link *link, int auto_connect)
|
||||
{
|
||||
ConfigItem_deny_link *d;
|
||||
crule_context context;
|
||||
|
||||
for (d = conf_deny_link; d; d = d->next)
|
||||
{
|
||||
if ((auto_connect == 0) && (d->flag.type == CRULE_AUTO))
|
||||
continue;
|
||||
if (unreal_mask_match_string(link->servername, d->mask) &&
|
||||
crule_eval(d->rule))
|
||||
crule_eval(NULL, d->rule))
|
||||
{
|
||||
return d->reason;
|
||||
}
|
||||
|
||||
+118
-48
@@ -68,10 +68,11 @@ TKL *_tkl_add_banexception(int type, char *usermask, char *hostmask, SecurityGro
|
||||
time_t expire_at, time_t set_at, int soft, char *bantypes, int flags);
|
||||
TKL *_tkl_add_nameban(int type, char *name, int hold, char *reason, char *set_by,
|
||||
time_t expire_at, time_t set_at, int flags);
|
||||
TKL *_tkl_add_spamfilter(int type, unsigned short target, BanAction *action, Match *match, char *set_by,
|
||||
time_t expire_at, time_t set_at,
|
||||
time_t spamf_tkl_duration, char *spamf_tkl_reason,
|
||||
int flags);
|
||||
TKL *_tkl_add_spamfilter(int type, unsigned short target, BanAction *action, Match *match,
|
||||
const char *rule, const char *set_by,
|
||||
time_t expire_at, time_t set_at,
|
||||
time_t spamf_tkl_duration, const char *spamf_tkl_reason,
|
||||
int flags);
|
||||
void _sendnotice_tkl_del(char *removed_by, TKL *tkl);
|
||||
void _sendnotice_tkl_add(TKL *tkl);
|
||||
void _free_tkl(TKL *tkl);
|
||||
@@ -269,7 +270,7 @@ int tkl_config_test_spamfilter(ConfigFile *cf, ConfigEntry *ce, int type, int *e
|
||||
ConfigEntry *cep, *cepp;
|
||||
int errors = 0;
|
||||
char *match = NULL, *reason = NULL;
|
||||
char has_target = 0, has_match = 0, has_action = 0, has_reason = 0, has_bantime = 0, has_match_type = 0;
|
||||
char has_target = 0, has_match = 0, has_rule = 0, has_action = 0, has_reason = 0, has_bantime = 0, has_match_type = 0;
|
||||
int match_type = 0;
|
||||
|
||||
/* We are only interested in spamfilter { } blocks */
|
||||
@@ -357,6 +358,25 @@ int tkl_config_test_spamfilter(ConfigFile *cf, ConfigEntry *ce, int type, int *e
|
||||
has_match = 1;
|
||||
match = cep->value;
|
||||
}
|
||||
else if (!strcmp(cep->name, "rule"))
|
||||
{
|
||||
int val;
|
||||
if (has_rule)
|
||||
{
|
||||
config_warn_duplicate(cep->file->filename,
|
||||
cep->line_number, "spamfilter::rule");
|
||||
continue;
|
||||
}
|
||||
has_rule = 1;
|
||||
if ((val = crule_test(cep->value)))
|
||||
{
|
||||
config_error("%s:%i: spamfilter::rule contains an invalid expression: %s",
|
||||
cep->file->filename,
|
||||
cep->line_number,
|
||||
crule_errstring(val));
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(cep->name, "ban-time"))
|
||||
{
|
||||
if (has_bantime)
|
||||
@@ -425,13 +445,19 @@ int tkl_config_test_spamfilter(ConfigFile *cf, ConfigEntry *ce, int type, int *e
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_match)
|
||||
if (!has_match && !has_rule)
|
||||
{
|
||||
config_error_missing(ce->file->filename, ce->line_number,
|
||||
"spamfilter::match");
|
||||
"spamfilter::match or spamfilter::rule");
|
||||
errors++;
|
||||
}
|
||||
if (!has_target)
|
||||
if (!has_match && has_match_type && has_rule)
|
||||
{
|
||||
config_error("%s:%i: spamfilter::match-type makes no sense if you only have a spamfilter::rule. Remove the match-type.",
|
||||
ce->file->filename, ce->line_number);
|
||||
errors++;
|
||||
}
|
||||
if (!has_target && match)
|
||||
{
|
||||
config_error_missing(ce->file->filename, ce->line_number,
|
||||
"spamfilter::target");
|
||||
@@ -450,7 +476,7 @@ int tkl_config_test_spamfilter(ConfigFile *cf, ConfigEntry *ce, int type, int *e
|
||||
ce->file->filename, ce->line_number);
|
||||
errors++;
|
||||
}
|
||||
if (!has_match_type)
|
||||
if (!has_match_type && match)
|
||||
{
|
||||
config_error_missing(ce->file->filename, ce->line_number,
|
||||
"spamfilter::match-type");
|
||||
@@ -474,13 +500,14 @@ int tkl_config_run_spamfilter(ConfigFile *cf, ConfigEntry *ce, int type)
|
||||
{
|
||||
ConfigEntry *cep;
|
||||
ConfigEntry *cepp;
|
||||
char *word = NULL;
|
||||
char *match = NULL;
|
||||
char *rule = NULL;
|
||||
time_t bantime = tempiConf.spamfilter_ban_time;
|
||||
char *banreason = tempiConf.spamfilter_ban_reason;
|
||||
BanAction *action;
|
||||
int target = 0;
|
||||
int match_type = 0;
|
||||
Match *m;
|
||||
Match *m = NULL;
|
||||
|
||||
/* We are only interested in spamfilter { } blocks */
|
||||
if ((type != CONFIG_MAIN) || strcmp(ce->name, "spamfilter"))
|
||||
@@ -490,7 +517,11 @@ int tkl_config_run_spamfilter(ConfigFile *cf, ConfigEntry *ce, int type)
|
||||
{
|
||||
if (!strcmp(cep->name, "match"))
|
||||
{
|
||||
word = cep->value;
|
||||
match = cep->value;
|
||||
}
|
||||
else if (!strcmp(cep->name, "rule"))
|
||||
{
|
||||
rule = cep->value;
|
||||
}
|
||||
else if (!strcmp(cep->name, "target"))
|
||||
{
|
||||
@@ -520,11 +551,16 @@ int tkl_config_run_spamfilter(ConfigFile *cf, ConfigEntry *ce, int type)
|
||||
}
|
||||
}
|
||||
|
||||
m = unreal_create_match(match_type, word, NULL);
|
||||
if (!match && rule)
|
||||
match_type = MATCH_NONE;
|
||||
|
||||
if (match)
|
||||
m = unreal_create_match(match_type, match, NULL);
|
||||
tkl_add_spamfilter(TKL_SPAMF,
|
||||
target,
|
||||
action,
|
||||
m,
|
||||
rule,
|
||||
"-config-",
|
||||
0,
|
||||
TStime(),
|
||||
@@ -2585,9 +2621,10 @@ TKL *tkl_find_head(char type, char *hostmask, TKL *def)
|
||||
* @returns The TKL entry, or NULL in case of a problem,
|
||||
* such as a regex failing to compile, memory problem, ..
|
||||
*/
|
||||
TKL *_tkl_add_spamfilter(int type, unsigned short target, BanAction *action, Match *match, char *set_by,
|
||||
TKL *_tkl_add_spamfilter(int type, unsigned short target, BanAction *action,
|
||||
Match *match, const char *rule, const char *set_by,
|
||||
time_t expire_at, time_t set_at,
|
||||
time_t tkl_duration, char *tkl_reason,
|
||||
time_t tkl_duration, const char *tkl_reason,
|
||||
int flags)
|
||||
{
|
||||
TKL *tkl;
|
||||
@@ -2597,14 +2634,26 @@ TKL *_tkl_add_spamfilter(int type, unsigned short target, BanAction *action, Mat
|
||||
abort();
|
||||
|
||||
tkl = safe_alloc(sizeof(TKL));
|
||||
/* First the common fields */
|
||||
tkl->type = type;
|
||||
tkl->flags = flags;
|
||||
tkl->set_at = set_at;
|
||||
safe_strdup(tkl->set_by, set_by);
|
||||
tkl->expire_at = expire_at;
|
||||
/* Then the spamfilter fields */
|
||||
tkl->ptr.spamfilter = safe_alloc(sizeof(Spamfilter));
|
||||
if (rule)
|
||||
{
|
||||
tkl->ptr.spamfilter->rule = crule_parse(rule);
|
||||
safe_strdup(tkl->ptr.spamfilter->prettyrule, rule);
|
||||
}
|
||||
if (rule && !match)
|
||||
{
|
||||
/* When no spamfilter::match, name it $RULE:xxx */
|
||||
char buf[512];
|
||||
snprintf(buf, sizeof(buf), "$RULE:%s", rule);
|
||||
match = safe_alloc(sizeof(Match));
|
||||
match->type = MATCH_NONE;
|
||||
safe_strdup(match->str, buf);
|
||||
}
|
||||
tkl->ptr.spamfilter->target = target;
|
||||
tkl->ptr.spamfilter->action = action;
|
||||
tkl->ptr.spamfilter->match = match;
|
||||
@@ -2826,6 +2875,9 @@ void _free_tkl(TKL *tkl)
|
||||
safe_free(tkl->ptr.spamfilter->tkl_reason);
|
||||
if (tkl->ptr.spamfilter->match)
|
||||
unreal_delete_match(tkl->ptr.spamfilter->match);
|
||||
if (tkl->ptr.spamfilter->rule)
|
||||
crule_free(&tkl->ptr.spamfilter->rule);
|
||||
safe_free(tkl->ptr.spamfilter->prettyrule);
|
||||
safe_free(tkl->ptr.spamfilter);
|
||||
} else
|
||||
if (TKLIsBanException(tkl) && tkl->ptr.banexception)
|
||||
@@ -4344,7 +4396,7 @@ CMD_FUNC(cmd_tkl_add)
|
||||
log_data_string("spamfilter_regex_error", err));
|
||||
return;
|
||||
}
|
||||
tkl = tkl_add_spamfilter(type, target, banact_value_to_struct(action), m, set_by, expire_at, set_at,
|
||||
tkl = tkl_add_spamfilter(type, target, banact_value_to_struct(action), m, NULL, set_by, expire_at, set_at,
|
||||
tkl_duration, tkl_reason, 0);
|
||||
}
|
||||
} else
|
||||
@@ -4931,40 +4983,58 @@ int _match_spamfilter(Client *client, const char *str_in, int target, const char
|
||||
if (IsLoggedIn(client) && only_soft_actions(tkl->ptr.spamfilter->action))
|
||||
continue;
|
||||
|
||||
#ifdef SPAMFILTER_DETECTSLOW
|
||||
memset(&rnow, 0, sizeof(rnow));
|
||||
memset(&rprev, 0, sizeof(rnow));
|
||||
|
||||
getrusage(RUSAGE_SELF, &rprev);
|
||||
#endif
|
||||
|
||||
ret = unreal_match(tkl->ptr.spamfilter->match, str);
|
||||
|
||||
#ifdef SPAMFILTER_DETECTSLOW
|
||||
getrusage(RUSAGE_SELF, &rnow);
|
||||
|
||||
ms_past = ((rnow.ru_utime.tv_sec - rprev.ru_utime.tv_sec) * 1000) +
|
||||
((rnow.ru_utime.tv_usec - rprev.ru_utime.tv_usec) / 1000);
|
||||
|
||||
if ((SPAMFILTER_DETECTSLOW_FATAL > 0) && (ms_past > SPAMFILTER_DETECTSLOW_FATAL))
|
||||
/* Run any pre 'rule' if there is any */
|
||||
if (tkl->ptr.spamfilter->rule)
|
||||
{
|
||||
unreal_log(ULOG_ERROR, "tkl", "SPAMFILTER_SLOW_FATAL", NULL,
|
||||
"[Spamfilter] WARNING: Too slow spamfilter detected (took $msec_time msec to execute) "
|
||||
"-- spamfilter will be \002REMOVED!\002: $tkl",
|
||||
log_data_tkl("tkl", tkl),
|
||||
log_data_integer("msec_time", ms_past));
|
||||
tkl_del_line(tkl);
|
||||
return 0; /* Act as if it didn't match, even if it did.. it's gone now anyway.. */
|
||||
} else
|
||||
if ((SPAMFILTER_DETECTSLOW_WARN > 0) && (ms_past > SPAMFILTER_DETECTSLOW_WARN))
|
||||
{
|
||||
unreal_log(ULOG_WARNING, "tkl", "SPAMFILTER_SLOW_WARN", NULL,
|
||||
"[Spamfilter] WARNING: Slow spamfilter detected (took $msec_time msec to execute): $tkl",
|
||||
log_data_tkl("tkl", tkl),
|
||||
log_data_integer("msec_time", ms_past));
|
||||
crule_context context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
context.client = client;
|
||||
if (!crule_eval(&context, tkl->ptr.spamfilter->rule))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tkl->ptr.spamfilter->match && (tkl->ptr.spamfilter->match->type != MATCH_NONE))
|
||||
{
|
||||
// TODO: wait, why are we running slow spamfilter detection for simple (non-regex) too ?
|
||||
#ifdef SPAMFILTER_DETECTSLOW
|
||||
memset(&rnow, 0, sizeof(rnow));
|
||||
memset(&rprev, 0, sizeof(rnow));
|
||||
|
||||
getrusage(RUSAGE_SELF, &rprev);
|
||||
#endif
|
||||
|
||||
ret = unreal_match(tkl->ptr.spamfilter->match, str);
|
||||
|
||||
#ifdef SPAMFILTER_DETECTSLOW
|
||||
getrusage(RUSAGE_SELF, &rnow);
|
||||
|
||||
ms_past = ((rnow.ru_utime.tv_sec - rprev.ru_utime.tv_sec) * 1000) +
|
||||
((rnow.ru_utime.tv_usec - rprev.ru_utime.tv_usec) / 1000);
|
||||
|
||||
if ((SPAMFILTER_DETECTSLOW_FATAL > 0) && (ms_past > SPAMFILTER_DETECTSLOW_FATAL))
|
||||
{
|
||||
unreal_log(ULOG_ERROR, "tkl", "SPAMFILTER_SLOW_FATAL", NULL,
|
||||
"[Spamfilter] WARNING: Too slow spamfilter detected (took $msec_time msec to execute) "
|
||||
"-- spamfilter will be \002REMOVED!\002: $tkl",
|
||||
log_data_tkl("tkl", tkl),
|
||||
log_data_integer("msec_time", ms_past));
|
||||
tkl_del_line(tkl);
|
||||
return 0; /* Act as if it didn't match, even if it did.. it's gone now anyway.. */
|
||||
} else
|
||||
if ((SPAMFILTER_DETECTSLOW_WARN > 0) && (ms_past > SPAMFILTER_DETECTSLOW_WARN))
|
||||
{
|
||||
unreal_log(ULOG_WARNING, "tkl", "SPAMFILTER_SLOW_WARN", NULL,
|
||||
"[Spamfilter] WARNING: Slow spamfilter detected (took $msec_time msec to execute): $tkl",
|
||||
log_data_tkl("tkl", tkl),
|
||||
log_data_integer("msec_time", ms_past));
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
/* There is no ::match but there was a ::rule, and that is enough for a match.. */
|
||||
if (tkl->ptr.spamfilter->rule)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
{
|
||||
/* We have a match! But.. perhaps it's on the exceptions list? */
|
||||
|
||||
@@ -723,6 +723,7 @@ int read_tkldb(void)
|
||||
tkl_add_spamfilter(tkl->type, tkl->ptr.spamfilter->target,
|
||||
tkl->ptr.spamfilter->action,
|
||||
tkl->ptr.spamfilter->match,
|
||||
NULL,
|
||||
tkl->set_by, tkl->expire_at, tkl->set_at,
|
||||
tkl->ptr.spamfilter->tkl_duration,
|
||||
tkl->ptr.spamfilter->tkl_reason,
|
||||
|
||||
Reference in New Issue
Block a user