noit_boolean noit_apply_filterset(const char *filterset, noit_check_t *check, metric_t *metric) { /* We pass in filterset here just in case someone wants to apply * a filterset other than check->filterset.. You never know. */ void *vfs; if(!filterset) return noit_true; /* No filter */ if(!filtersets) return noit_false; /* Couldn't possibly match */ LOCKFS(); if(noit_hash_retrieve(filtersets, filterset, strlen(filterset), &vfs)) { filterset_t *fs = (filterset_t *)vfs; filterrule_t *r; noit_atomic_inc32(&fs->ref_cnt); UNLOCKFS(); #define MATCHES(rname, value) noit_apply_filterrule(r->rname, r->rname##_e, value) for(r = fs->rules; r; r = r->next) { if(MATCHES(target, check->target) && MATCHES(module, check->module) && MATCHES(name, check->name) && MATCHES(metric, metric->metric_name)) return (r->type == NOIT_FILTER_ACCEPT) ? noit_true : noit_false; } filterset_free(fs); return noit_false; } UNLOCKFS(); return noit_false; }
int noit_filter_exists(const char *name) { int exists; void *v; LOCKFS(); exists = noit_hash_retrieve(filtersets, name, strlen(name), &v); UNLOCKFS(); return exists; }
int noit_filter_remove(noit_conf_section_t vnode) { int removed; char *name = (char *)xmlGetProp(vnode, (xmlChar *)"name"); if(!name) return 0; LOCKFS(); removed = noit_hash_delete(filtersets, name, strlen(name), NULL, filterset_free); UNLOCKFS(); return removed; }
void noit_filter_compile_add(noit_conf_section_t setinfo) { noit_conf_section_t *rules; int j, fcnt; char filterset_name[256]; filterset_t *set; if(!noit_conf_get_stringbuf(setinfo, "@name", filterset_name, sizeof(filterset_name))) { noitL(noit_error, "filterset with no name, skipping as it cannot be referenced.\n"); return; } set = calloc(1, sizeof(*set)); set->ref_cnt = 1; set->name = strdup(filterset_name); rules = noit_conf_get_sections(setinfo, "rule", &fcnt); /* Here we will work through the list backwards pushing the rules on * the front of the list. That way we can simply walk them in order * for the application process. */ noitL(noit_debug, "Compiling filterset '%s'\n", set->name); for(j=fcnt-1; j>=0; j--) { filterrule_t *rule; char buffer[256]; if(!noit_conf_get_stringbuf(rules[j], "@type", buffer, sizeof(buffer)) || (strcmp(buffer, "accept") && strcmp(buffer, "allow") && strcmp(buffer, "deny"))) { noitL(noit_error, "rule must have type 'accept' or 'allow' or 'deny'\n"); continue; } noitL(noit_debug, "Prepending %s into %s\n", buffer, set->name); rule = calloc(1, sizeof(*rule)); rule->type = (!strcmp(buffer, "accept") || !strcmp(buffer, "allow")) ? NOIT_FILTER_ACCEPT : NOIT_FILTER_DENY; /* Compile our rules */ #define RULE_COMPILE(rname) do { \ char *longre = NULL; \ if(noit_conf_get_string(rules[j], "@" #rname, &longre)) { \ const char *error; \ int erroffset; \ rule->rname = pcre_compile(longre, 0, &error, &erroffset, NULL); \ if(!rule->rname) { \ noitL(noit_error, "set '%s' rule '%s: %s' compile failed: %s\n", \ set->name, #rname, longre, error ? error : "???"); \ } \ else { \ rule->rname##_e = pcre_study(rule->rname, 0, &error); \ } \ free(longre); \ } \ } while(0) RULE_COMPILE(target); RULE_COMPILE(module); RULE_COMPILE(name); RULE_COMPILE(metric); rule->next = set->rules; set->rules = rule; } free(rules); LOCKFS(); noit_hash_replace(filtersets, set->name, strlen(set->name), (void *)set, NULL, filterset_free); UNLOCKFS(); }
static int noit_console_filter_configure(noit_console_closure_t ncct, int argc, char **argv, noit_console_state_t *state, void *closure) { xmlNodePtr parent, fsnode = NULL; int rv = -1; noit_conf_t_userdata_t *info; char xpath[1024]; info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA); if(!info) { nc_printf(ncct, "internal error\n"); goto cleanup; } if(strncmp(info->path, "/filtersets/", strlen("/filtersets/")) && strcmp(info->path, "/filtersets")) { nc_printf(ncct, "filterset only allows inside /filtersets (not %s)\n", info->path); goto cleanup; } if(argc != 1) { nc_printf(ncct, "filterset requires one argument\n"); goto cleanup; } snprintf(xpath, sizeof(xpath), "/%s", info->path); parent = noit_conf_get_section(NULL, xpath); if(!parent) { nc_printf(ncct, "internal error, can't final current working path\n"); goto cleanup; } snprintf(xpath, sizeof(xpath), "filterset[@name=\"%s\"]", argv[0]); fsnode = noit_conf_get_section(parent, xpath); if(closure) { int removed; removed = noit_filter_remove(fsnode); nc_printf(ncct, "%sremoved filterset '%s'\n", removed ? "" : "failed to ", argv[0]); if(removed) { xmlUnlinkNode(fsnode); xmlFreeNode(fsnode); } rv = !removed; goto cleanup; } if(!fsnode) { void *vfs; nc_printf(ncct, "Cannot find filterset '%s'\n", argv[0]); LOCKFS(); if(noit_hash_retrieve(filtersets, argv[0], strlen(argv[0]), &vfs)) { UNLOCKFS(); nc_printf(ncct, "filter of the same name already exists\n"); goto cleanup; } UNLOCKFS(); /* Fine the parent path */ fsnode = xmlNewNode(NULL, (xmlChar *)"filterset"); xmlSetProp(fsnode, (xmlChar *)"name", (xmlChar *)argv[0]); xmlAddChild(parent, fsnode); nc_printf(ncct, "created new filterset\n"); } if(info) { char *xmlpath = NULL; if(info->path) free(info->path); xmlpath = (char *)xmlGetNodePath(fsnode); info->path = strdup(xmlpath + strlen("/noit")); free(xmlpath); strlcpy(info->filter_name, argv[0], sizeof(info->filter_name)); if(state) { noit_console_state_push_state(ncct, state); noit_console_state_init(ncct); } } cleanup: return rv; }
mtev_boolean noit_apply_filterset(const char *filterset, noit_check_t *check, metric_t *metric) { /* We pass in filterset here just in case someone wants to apply * a filterset other than check->filterset.. You never know. */ void *vfs; if(!filterset) return mtev_true; /* No filter */ if(!filtersets) return mtev_false; /* Couldn't possibly match */ LOCKFS(); if(mtev_hash_retrieve(filtersets, filterset, strlen(filterset), &vfs)) { filterset_t *fs = (filterset_t *)vfs; filterrule_t *r, *skipto_rule = NULL; int idx = 0; mtev_atomic_inc32(&fs->ref_cnt); UNLOCKFS(); #define MATCHES(rname, value) noit_apply_filterrule(r->rname##_ht, r->rname ? r->rname : r->rname##_override, r->rname ? r->rname##_e : NULL, value) for(r = fs->rules; r; r = r->next) { int need_target, need_module, need_name, need_metric; /* If we're targeting a skipto rule, match or continue */ idx++; if(skipto_rule && skipto_rule != r) continue; skipto_rule = NULL; need_target = !MATCHES(target, check->target); need_module = !MATCHES(module, check->module); need_name = !MATCHES(name, check->name); need_metric = !MATCHES(metric, metric->metric_name); if(!need_target && !need_module && !need_name && !need_metric) { if(r->type == NOIT_FILTER_SKIPTO) { skipto_rule = r->skipto_rule; continue; } return (r->type == NOIT_FILTER_ACCEPT) ? mtev_true : mtev_false; } /* If we need some of these and we have an auto setting that isn't fulfilled for each of them, we can add and succeed */ #define CHECK_ADD(rname) (!need_##rname || (r->rname##_auto_hash_max > 0 && r->rname##_ht && mtev_hash_size(r->rname##_ht) < r->rname##_auto_hash_max)) if(CHECK_ADD(target) && CHECK_ADD(module) && CHECK_ADD(name) && CHECK_ADD(metric)) { #define UPDATE_FILTER_RULE(rnum, rname, value) do { \ mtev_hash_replace(r->rname##_ht, strdup(value), strlen(value), NULL, free, NULL); \ if(noit_filter_update_conf_rule(fs->name, rnum, #rname, value) < 0) { \ mtevL(noit_error, "Error updating configuration for new filter auto_add on %s=%s\n", #rname, value); \ } \ } while(0) if(need_target) UPDATE_FILTER_RULE(idx, target, check->target); if(need_module) UPDATE_FILTER_RULE(idx, module, check->module); if(need_name) UPDATE_FILTER_RULE(idx, name, check->name); if(need_metric) UPDATE_FILTER_RULE(idx, metric, metric->metric_name); noit_filterset_log_auto_add(fs->name, check, metric, r->type == NOIT_FILTER_ACCEPT); if(r->type == NOIT_FILTER_SKIPTO) { skipto_rule = r->skipto_rule; continue; } return (r->type == NOIT_FILTER_ACCEPT) ? mtev_true : mtev_false; } } filterset_free(fs); return mtev_false; } UNLOCKFS(); return mtev_false; }
void noit_filter_compile_add(mtev_conf_section_t setinfo) { mtev_conf_section_t *rules; int j, fcnt; char filterset_name[256]; filterset_t *set; if(!mtev_conf_get_stringbuf(setinfo, "@name", filterset_name, sizeof(filterset_name))) { mtevL(noit_error, "filterset with no name, skipping as it cannot be referenced.\n"); return; } set = calloc(1, sizeof(*set)); set->ref_cnt = 1; set->name = strdup(filterset_name); rules = mtev_conf_get_sections(setinfo, "rule", &fcnt); /* Here we will work through the list backwards pushing the rules on * the front of the list. That way we can simply walk them in order * for the application process. */ mtevL(noit_debug, "Compiling filterset '%s'\n", set->name); for(j=fcnt-1; j>=0; j--) { filterrule_t *rule; char buffer[256]; if(!mtev_conf_get_stringbuf(rules[j], "@type", buffer, sizeof(buffer)) || (strcmp(buffer, "accept") && strcmp(buffer, "allow") && strcmp(buffer, "deny") && strncmp(buffer, "skipto:", strlen("skipto:")))) { mtevL(noit_error, "rule must have type 'accept' or 'allow' or 'deny' or 'skipto:'\n"); continue; } mtevL(noit_debug, "Prepending %s into %s\n", buffer, set->name); rule = calloc(1, sizeof(*rule)); if(!strncasecmp(buffer, "skipto:", strlen("skipto:"))) { rule->type = NOIT_FILTER_SKIPTO; rule->skipto = strdup(buffer+strlen("skipto:")); } else { rule->type = (!strcmp(buffer, "accept") || !strcmp(buffer, "allow")) ? NOIT_FILTER_ACCEPT : NOIT_FILTER_DENY; } if(mtev_conf_get_stringbuf(rules[j], "@id", buffer, sizeof(buffer))) { rule->ruleid = strdup(buffer); } /* Compile any hash tables, should they exist */ #define HT_COMPILE(rname) do { \ mtev_conf_section_t *htentries; \ int hte_cnt, hti, tablesize = 2, auto_max = 0; \ char *htstr; \ htentries = mtev_conf_get_sections(rules[j], #rname, &hte_cnt); \ mtev_conf_get_int(rules[j], "@" #rname "_auto_add", &auto_max); \ if(hte_cnt || auto_max > 0) { \ rule->rname##_auto_hash_max = auto_max; \ rule->rname##_ht = calloc(1, sizeof(*(rule->rname##_ht))); \ while(tablesize < hte_cnt) tablesize <<= 1; \ mtev_hash_init_size(rule->rname##_ht, tablesize); \ for(hti=0; hti<hte_cnt; hti++) { \ if(!mtev_conf_get_string(htentries[hti], "self::node()", &htstr)) \ mtevL(noit_error, "Error fetching text content from filter match.\n"); \ else \ mtev_hash_replace(rule->rname##_ht, htstr, strlen(htstr), NULL, free, NULL); \ } \ } \ free(htentries); \ } while(0); HT_COMPILE(target); HT_COMPILE(module); HT_COMPILE(name); HT_COMPILE(metric); /* Compile our rules */ #define RULE_COMPILE(rname) do { \ char *longre = NULL; \ if(mtev_conf_get_string(rules[j], "@" #rname, &longre)) { \ const char *error; \ int erroffset; \ rule->rname = pcre_compile(longre, 0, &error, &erroffset, NULL); \ if(!rule->rname) { \ mtevL(noit_debug, "set '%s' rule '%s: %s' compile failed: %s\n", \ set->name, #rname, longre, error ? error : "???"); \ rule->rname##_override = fallback_no_match; \ } \ else { \ rule->rname##_e = pcre_study(rule->rname, 0, &error); \ } \ free(longre); \ } \ } while(0) if(rule->target_ht == NULL) RULE_COMPILE(target); if(rule->module_ht == NULL) RULE_COMPILE(module); if(rule->name_ht == NULL) RULE_COMPILE(name); if(rule->metric_ht == NULL) RULE_COMPILE(metric); rule->next = set->rules; set->rules = rule; } filterrule_t *cursor; for(cursor = set->rules; cursor->next; cursor = cursor->next) { if(cursor->skipto) { filterrule_t *target; for(target = cursor->next; target; target = target->next) { if(target->ruleid && !strcmp(cursor->skipto, target->ruleid)) { cursor->skipto_rule = target; break; } } if(!cursor->skipto_rule) mtevL(noit_error, "filterset %s skipto:%s not found\n", set->name, cursor->skipto); } } free(rules); LOCKFS(); mtev_hash_replace(filtersets, set->name, strlen(set->name), (void *)set, NULL, filterset_free); UNLOCKFS(); }