From bee2853ded06f7346f78997bdd57c866783dc99f Mon Sep 17 00:00:00 2001 From: Bram Matthys Date: Sat, 8 Jul 2023 18:13:14 +0200 Subject: [PATCH] Add spamreport::type dronebl, actually reports to unrealircd.org atm for testing --- src/modules/spamreport.c | 131 +++++++++++++++++++++++++++++++-------- 1 file changed, 104 insertions(+), 27 deletions(-) diff --git a/src/modules/spamreport.c b/src/modules/spamreport.c index ae6134802..072ff52cd 100644 --- a/src/modules/spamreport.c +++ b/src/modules/spamreport.c @@ -13,14 +13,20 @@ ModuleHeader MOD_HEADER "unrealircd-6", }; -/* Structs */ +/* Enums and structs */ +typedef enum SpamreportType { + SPAMREPORT_TYPE_SIMPLE = 1, + SPAMREPORT_TYPE_DRONEBL = 2, +} SpamReportType; + typedef struct Spamreport Spamreport; struct Spamreport { Spamreport *prev, *next; char *name; /**< Name of the block, spamreport { } */ char *url; /**< URL to use */ - int type; + SpamReportType type; HttpMethod http_method; + NameValuePrioList *parameters; SecurityGroup *except; int rate_limit_num; int rate_limit_per; @@ -66,9 +72,10 @@ MOD_UNLOAD() /** Test a spamreport { } block in the configuration file */ int tkl_config_test_spamreport(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) { - ConfigEntry *cep; + ConfigEntry *cep, *cepp; int errors = 0; - char has_url=0, has_type=0, has_http_method=0; + char has_url=0, has_type=0, has_type_dronebl=0, has_http_method=0; + char has_dronebl_type=0, has_dronebl_rpckey=0; /* We are only interested in spamreport { } blocks */ if ((type != CONFIG_MAIN) || strcmp(ce->name, "spamreport")) @@ -86,6 +93,22 @@ int tkl_config_test_spamreport(ConfigFile *cf, ConfigEntry *ce, int type, int *e if (!strcmp(cep->name, "except")) { test_match_block(cf, cep, &errors); + } else + if (!strcmp(cep->name, "parameters")) + { + for (cepp = cep->items; cepp; cepp = cepp->next) + { + if (!cepp->value) + { + config_error_empty(cepp->file->filename, cepp->line_number, + "spamreport::parameters", cepp->name); + errors++; + } + else if (!strcmp(cepp->name, "rpckey")) + has_dronebl_rpckey = 1; + else if (!strcmp(cepp->name, "type")) + has_dronebl_type = 1; + } } else if (!cep->value) { @@ -113,7 +136,11 @@ int tkl_config_test_spamreport(ConfigFile *cf, ConfigEntry *ce, int type, int *e continue; } has_type = 1; - if (strcmp(cep->value, "simple")) + if (!strcmp(cep->value, "simple")) + ; + else if (!strcmp(cep->value, "dronebl")) + has_type_dronebl = 1; + else { config_error("%s:%i: spamreport::type: only 'simple' is supported at the moment", cep->file->filename, cep->line_number); @@ -151,22 +178,33 @@ int tkl_config_test_spamreport(ConfigFile *cf, ConfigEntry *ce, int type, int *e } } - if (!has_url) - { - config_error_missing(ce->file->filename, ce->line_number, "spamreport::url"); - errors++; - } - if (!has_type) { config_error_missing(ce->file->filename, ce->line_number, "spamreport::type"); errors++; } - if (!has_http_method) + if (has_type_dronebl) { - config_error_missing(ce->file->filename, ce->line_number, "spamreport::http-method"); - errors++; + if (!has_dronebl_rpckey || !has_dronebl_type) + { + config_error("%s:%i: spamreport: type dronebl used, missing spamreport::parameters: rpckey and/or type", + ce->file->filename, ce->line_number); + errors++; + } + } else + { + if (!has_url) + { + config_error_missing(ce->file->filename, ce->line_number, "spamreport::url"); + errors++; + } + + if (!has_http_method) + { + config_error_missing(ce->file->filename, ce->line_number, "spamreport::http-method"); + errors++; + } } *errs = errors; @@ -194,7 +232,12 @@ int tkl_config_run_spamreport(ConfigFile *cf, ConfigEntry *ce, int type) } else if (!strcmp(cep->name, "type")) { - // TODO + if (!strcmp(cep->value, "simple")) + s->type = SPAMREPORT_TYPE_SIMPLE; + else if (!strcmp(cep->value, "dronebl")) + s->type = SPAMREPORT_TYPE_DRONEBL; + else + abort(); } else if (!strcmp(cep->name, "http-method")) { @@ -207,12 +250,20 @@ int tkl_config_run_spamreport(ConfigFile *cf, ConfigEntry *ce, int type) { // TODO } + else if (!strcmp(cep->name, "parameters")) + { + for (cepp = cep->items; cepp; cepp = cepp->next) + add_nvplist(&s->parameters, 0, cepp->name, cepp->value); + } else if (!strcmp(cep->name, "except")) { conf_match_block(cf, cep, &s->except); } } + if (s->type == SPAMREPORT_TYPE_DRONEBL) + s->http_method = HTTP_METHOD_POST; + AddListItem(s, spamreports); return 1; } @@ -222,6 +273,8 @@ void free_spamreport_block(Spamreport *s) DelListItem(s, spamreports); safe_free(s->name); safe_free(s->url); + safe_free_nvplist(s->parameters); + free_security_group(s->except); safe_free(s); } @@ -249,8 +302,9 @@ Spamreport *find_spamreport_block(const char *name) int report_spam(Client *client, const char *ip, NameValuePrioList *details, Spamreport *s) { - NameValuePrioList *list; - char url[512]; + char urlbuf[512]; + char bodybuf[512]; + char *url = NULL; char *body = NULL; if (s == NULL) @@ -265,18 +319,41 @@ int report_spam(Client *client, const char *ip, NameValuePrioList *details, Spam return 0; // NOTE: 'except' is bypassed for manual SPAMREPORT with an ip and no client. - list = duplicate_nvplist(details); - add_nvplist(&list, -1, "ip", ip); - buildvarstring_nvp(s->url, url, sizeof(url), list); - safe_free_nvplist(list); - - if (s->http_method == HTTP_METHOD_POST) + if (s->type == SPAMREPORT_TYPE_SIMPLE) { - body = strchr(url, '?'); - if (body) - *body++ = '\0'; - } + NameValuePrioList *list = NULL; + list = duplicate_nvplist(details); + add_nvplist(&list, -1, "ip", ip); + buildvarstring_nvp(s->url, urlbuf, sizeof(urlbuf), list, BUILDVARSTRING_URLENCODE); + url = urlbuf; + safe_free_nvplist(list); + if (s->http_method == HTTP_METHOD_POST) + { + body = strchr(url, '?'); + if (body) + *body++ = '\0'; + } + } else + if (s->type == SPAMREPORT_TYPE_DRONEBL) + { + NameValuePrioList *list = NULL; + NameValuePrioList *list2 = NULL; + url = "https://www.unrealircd.org/spamreport.php"; + list = duplicate_nvplist(details); + duplicate_nvplist_append(s->parameters, &list); + add_nvplist(&list, -1, "ip", ip); + buildvarstring_nvp("rpckey=$rpckey&action=add&ip=$ip&type=$type", bodybuf, sizeof(bodybuf), list, BUILDVARSTRING_URLENCODE); + body = bodybuf; + safe_free_nvplist(list); // frees all the duplicated lists + } else + abort(); +#ifdef DEBUGMODE + unreal_log(ULOG_DEBUG, "spamreport", "SPAMREPORT_SEND_REQUEST", NULL, + "Calling url '$url' with body '$body'", + log_data_string("url", url), + log_data_string("body", (body ? body : ""))); +#endif url_start_async(url, s->http_method, body, 0, 0, download_complete_dontcare, NULL, url, 3); return 1; }