root/src/noit_filters.c

Revision 6210da7ee0e2ed143d71a8e00b709f16e71059f8, 4.9 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

various changes to avoid dereferencing type-punned pointers and breaking strict-aliasing rules, refs #34

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  */
5
6 #include "noit_defines.h"
7
8 #include "utils/noit_hash.h"
9 #include "noit_conf.h"
10 #include "noit_check.h"
11 #include "noit_filters.h"
12
13 #include <pcre.h>
14
15 static noit_hash_table *filtersets = NULL;
16
17 typedef enum { NOIT_FILTER_ACCEPT, NOIT_FILTER_DENY } noit_ruletype_t;
18 typedef struct _filterrule {
19   noit_ruletype_t type;
20   pcre *target;
21   pcre_extra *target_e;
22   pcre *module;
23   pcre_extra *module_e;
24   pcre *name;
25   pcre_extra *name_e;
26   pcre *metric;
27   pcre_extra *metric_e;
28   struct _filterrule *next;
29 } filterrule_t;
30
31 typedef struct {
32   char *name;
33   filterrule_t *rules;
34 } filterset_t;
35
36 void
37 noit_refresh_filtersets(noit_console_closure_t ncct,
38                         noit_conf_t_userdata_t *info) {
39   noit_filters_init();
40   nc_printf(ncct, "Reloaded %d filtersets.\n",
41             filtersets ? filtersets->size : 0);
42 }
43
44 #define FRF(r,a) do { \
45   if(r->a) pcre_free(r->a); \
46   if(r->a##_e) pcre_free(r->a##_e); \
47 } while(0)
48
49 static void
50 filterrule_free(void *vp) {
51   filterrule_t *r = vp;
52   FRF(r,target);
53   FRF(r,module);
54   FRF(r,name);
55   FRF(r,metric);
56   free(r);
57 }
58 static void
59 filterset_free(void *vp) {
60   filterset_t *fs = vp;
61   filterrule_t *r;
62   while(fs->rules) {
63     r = fs->rules->next;
64     filterrule_free(fs->rules);
65     fs->rules = r;
66   }
67   if(fs->name) free(fs->name);
68   free(fs);
69 }
70 void
71 noit_filters_init() {
72   noit_hash_table *newsets = NULL, *cleanup;
73   noit_conf_section_t *sets;
74   int i, cnt;
75
76   sets = noit_conf_get_sections(NULL, "/noit/filtersets//filterset", &cnt);
77   newsets = calloc(1, sizeof(noit_hash_table));
78   for(i=0; i<cnt; i++) {
79     noit_conf_section_t *rules;
80     int j, fcnt;
81     char filterset_name[256];
82     filterset_t *set;
83     if(!noit_conf_get_stringbuf(sets[i], "@name",
84                                 filterset_name, sizeof(filterset_name))) {
85       noitL(noit_error,
86             "filterset with no name, skipping as it cannot be referenced.\n");
87       continue;
88     }
89     set = calloc(1, sizeof(*set));
90     set->name = strdup(filterset_name);
91
92     rules = noit_conf_get_sections(sets[i], "rule", &fcnt);
93     /* Here we will work through the list backwards pushing the rules on
94      * the front of the list.  That way we can simply walk them in order
95      * for the application process.
96      */
97     noitL(noit_debug, "Compiling filterset '%s'\n", set->name);
98     for(j=fcnt-1; j>=0; j--) {
99       filterrule_t *rule;
100       char buffer[256];
101       if(!noit_conf_get_stringbuf(rules[j], "@type", buffer, sizeof(buffer)) ||
102          (strcmp(buffer, "accept") && strcmp(buffer, "deny"))) {
103         noitL(noit_error, "rule must have type 'accept' or 'deny'\n");
104         continue;
105       }
106       noitL(noit_debug, "Prepending %s into %s\n", buffer, set->name);
107       rule = calloc(1, sizeof(*rule));
108       rule->type = (!strcmp(buffer, "accept")) ?
109                      NOIT_FILTER_ACCEPT : NOIT_FILTER_DENY;
110
111       /* Compile our rules */
112 #define RULE_COMPILE(rname) do { \
113   if(noit_conf_get_stringbuf(rules[j], "@" #rname, buffer, sizeof(buffer))) { \
114     const char *error; \
115     int erroffset; \
116     rule->rname = pcre_compile(buffer, 0, &error, &erroffset, NULL); \
117     if(!rule->rname) { \
118       noitL(noit_error, "set '%s' rule '%s: %s' compile failed: %s\n", \
119             set->name, #rname, buffer, error ? error : "???"); \
120     } \
121     else { \
122       rule->rname##_e = pcre_study(rule->rname, 0, &error); \
123     } \
124   } \
125 } while(0)
126
127       RULE_COMPILE(target);
128       RULE_COMPILE(module);
129       RULE_COMPILE(name);
130       RULE_COMPILE(metric);
131       rule->next = set->rules;
132       set->rules = rule;
133     }
134     free(rules);
135     noit_hash_replace(newsets, set->name, strlen(set->name), (void *)set,
136                       NULL, filterset_free);
137   }
138   free(sets);
139   cleanup = filtersets;
140   filtersets = newsets;
141   if(cleanup) noit_hash_destroy(cleanup, NULL, filterset_free);
142 }
143
144 static noit_boolean
145 noit_apply_filterrule(pcre *p, pcre_extra *pe, const char *subj) {
146   int rc, ovector[30];
147   if(!p) return noit_true;
148   rc = pcre_exec(p, pe, subj, strlen(subj), 0, 0, ovector, 30);
149   if(rc >= 0) return noit_true;
150   return noit_false;
151 }
152 noit_boolean
153 noit_apply_filterset(const char *filterset,
154                      noit_check_t *check,
155                      metric_t *metric) {
156   /* We pass in filterset here just in case someone wants to apply
157    * a filterset other than check->filterset.. You never know.
158    */
159   void *vfs;
160   if(!filtersets || !filterset) return noit_true;
161
162   if(noit_hash_retrieve(filtersets, filterset, strlen(filterset), &vfs)) {
163     filterset_t *fs = (filterset_t *)vfs;
164     filterrule_t *r;
165 #define MATCHES(rname, value) noit_apply_filterrule(r->rname, r->rname##_e, value)
166     for(r = fs->rules; r; r = r->next) {
167       if(MATCHES(target, check->target) &&
168          MATCHES(module, check->module) &&
169          MATCHES(name, check->name) &&
170          MATCHES(metric, metric->metric_name))
171         return (r->type == NOIT_FILTER_ACCEPT) ? noit_true : noit_false;
172     }
173   }
174   return noit_true;
175 }
176
177
Note: See TracBrowser for help on using the browser.