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(); }
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(); }