root/src/noit_filters.c

Revision 88a71780101cbf23034aa0cb840f9f0368fda2dd, 6.5 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

fixes #126

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
16  *       of its contributors may be used to endorse or promote products
17  *       derived from this software without specific prior written
18  *       permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "noit_defines.h"
34
35 #include "utils/noit_hash.h"
36 #include "noit_conf.h"
37 #include "noit_check.h"
38 #include "noit_filters.h"
39
40 #include <pcre.h>
41
42 static noit_hash_table *filtersets = NULL;
43
44 typedef enum { NOIT_FILTER_ACCEPT, NOIT_FILTER_DENY } noit_ruletype_t;
45 typedef struct _filterrule {
46   noit_ruletype_t type;
47   pcre *target;
48   pcre_extra *target_e;
49   pcre *module;
50   pcre_extra *module_e;
51   pcre *name;
52   pcre_extra *name_e;
53   pcre *metric;
54   pcre_extra *metric_e;
55   struct _filterrule *next;
56 } filterrule_t;
57
58 typedef struct {
59   char *name;
60   filterrule_t *rules;
61 } filterset_t;
62
63 void
64 noit_refresh_filtersets(noit_console_closure_t ncct,
65                         noit_conf_t_userdata_t *info) {
66   noit_filters_init();
67   nc_printf(ncct, "Reloaded %d filtersets.\n",
68             filtersets ? filtersets->size : 0);
69 }
70
71 #define FRF(r,a) do { \
72   if(r->a) pcre_free(r->a); \
73   if(r->a##_e) pcre_free(r->a##_e); \
74 } while(0)
75
76 static void
77 filterrule_free(void *vp) {
78   filterrule_t *r = vp;
79   FRF(r,target);
80   FRF(r,module);
81   FRF(r,name);
82   FRF(r,metric);
83   free(r);
84 }
85 static void
86 filterset_free(void *vp) {
87   filterset_t *fs = vp;
88   filterrule_t *r;
89   while(fs->rules) {
90     r = fs->rules->next;
91     filterrule_free(fs->rules);
92     fs->rules = r;
93   }
94   if(fs->name) free(fs->name);
95   free(fs);
96 }
97 void
98 noit_filters_init() {
99   noit_hash_table *newsets = NULL, *cleanup;
100   noit_conf_section_t *sets;
101   int i, cnt;
102
103   sets = noit_conf_get_sections(NULL, "/noit/filtersets//filterset", &cnt);
104   newsets = calloc(1, sizeof(noit_hash_table));
105   for(i=0; i<cnt; i++) {
106     noit_conf_section_t *rules;
107     int j, fcnt;
108     char filterset_name[256];
109     filterset_t *set;
110     if(!noit_conf_get_stringbuf(sets[i], "@name",
111                                 filterset_name, sizeof(filterset_name))) {
112       noitL(noit_error,
113             "filterset with no name, skipping as it cannot be referenced.\n");
114       continue;
115     }
116     set = calloc(1, sizeof(*set));
117     set->name = strdup(filterset_name);
118
119     rules = noit_conf_get_sections(sets[i], "rule", &fcnt);
120     /* Here we will work through the list backwards pushing the rules on
121      * the front of the list.  That way we can simply walk them in order
122      * for the application process.
123      */
124     noitL(noit_debug, "Compiling filterset '%s'\n", set->name);
125     for(j=fcnt-1; j>=0; j--) {
126       filterrule_t *rule;
127       char buffer[256];
128       if(!noit_conf_get_stringbuf(rules[j], "@type", buffer, sizeof(buffer)) ||
129          (strcmp(buffer, "accept") && strcmp(buffer, "deny"))) {
130         noitL(noit_error, "rule must have type 'accept' or 'deny'\n");
131         continue;
132       }
133       noitL(noit_debug, "Prepending %s into %s\n", buffer, set->name);
134       rule = calloc(1, sizeof(*rule));
135       rule->type = (!strcmp(buffer, "accept")) ?
136                      NOIT_FILTER_ACCEPT : NOIT_FILTER_DENY;
137
138       /* Compile our rules */
139 #define RULE_COMPILE(rname) do { \
140   if(noit_conf_get_stringbuf(rules[j], "@" #rname, buffer, sizeof(buffer))) { \
141     const char *error; \
142     int erroffset; \
143     rule->rname = pcre_compile(buffer, 0, &error, &erroffset, NULL); \
144     if(!rule->rname) { \
145       noitL(noit_error, "set '%s' rule '%s: %s' compile failed: %s\n", \
146             set->name, #rname, buffer, error ? error : "???"); \
147     } \
148     else { \
149       rule->rname##_e = pcre_study(rule->rname, 0, &error); \
150     } \
151   } \
152 } while(0)
153
154       RULE_COMPILE(target);
155       RULE_COMPILE(module);
156       RULE_COMPILE(name);
157       RULE_COMPILE(metric);
158       rule->next = set->rules;
159       set->rules = rule;
160     }
161     free(rules);
162     noit_hash_replace(newsets, set->name, strlen(set->name), (void *)set,
163                       NULL, filterset_free);
164   }
165   free(sets);
166   cleanup = filtersets;
167   filtersets = newsets;
168   if(cleanup) noit_hash_destroy(cleanup, NULL, filterset_free);
169 }
170
171 static noit_boolean
172 noit_apply_filterrule(pcre *p, pcre_extra *pe, const char *subj) {
173   int rc, ovector[30];
174   if(!p) return noit_true;
175   rc = pcre_exec(p, pe, subj, strlen(subj), 0, 0, ovector, 30);
176   if(rc >= 0) return noit_true;
177   return noit_false;
178 }
179 noit_boolean
180 noit_apply_filterset(const char *filterset,
181                      noit_check_t *check,
182                      metric_t *metric) {
183   /* We pass in filterset here just in case someone wants to apply
184    * a filterset other than check->filterset.. You never know.
185    */
186   void *vfs;
187   if(!filtersets || !filterset) return noit_true;
188
189   if(noit_hash_retrieve(filtersets, filterset, strlen(filterset), &vfs)) {
190     filterset_t *fs = (filterset_t *)vfs;
191     filterrule_t *r;
192 #define MATCHES(rname, value) noit_apply_filterrule(r->rname, r->rname##_e, value)
193     for(r = fs->rules; r; r = r->next) {
194       if(MATCHES(target, check->target) &&
195          MATCHES(module, check->module) &&
196          MATCHES(name, check->name) &&
197          MATCHES(metric, metric->metric_name))
198         return (r->type == NOIT_FILTER_ACCEPT) ? noit_true : noit_false;
199     }
200   }
201   return noit_true;
202 }
203
204
Note: See TracBrowser for help on using the browser.