1 /*
2     ettercap -- content filtering engine module
3 
4     Copyright (C) ALoR & NaGA
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 
20 */
21 
22 #include <ec.h>
23 #include <ec_filter.h>
24 #include <ec_version.h>
25 #include <ec_threads.h>
26 #include <ec_send.h>
27 
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 
32 #include <regex.h>
33 #ifdef HAVE_PCRE
34    #include <pcre.h>
35 #endif
36 
37 
38 #define JIT_FAULT(x, ...) do { USER_MSG("JIT FILTER FAULT: " x "\n", ## __VA_ARGS__); return -E_FATAL; } while(0)
39 
40 /* since we need a recursive mutex, we cannot initialize it here statically */
41 static pthread_mutex_t filters_mutex;
42 #define FILTERS_LOCK     do{ pthread_mutex_lock(&filters_mutex); }while(0)
43 #define FILTERS_UNLOCK   do{ pthread_mutex_unlock(&filters_mutex); }while(0)
44 
45 /* protos */
46 
47 static void reconstruct_strings(struct filter_env *fenv, struct filter_header *fh);
48 static int compile_regex(struct filter_env *fenv);
49 
50 static int filter_engine(struct filter_op *fop, struct packet_object *po);
51 static int execute_test(struct filter_op *fop, struct packet_object *po);
52 static int execute_assign(struct filter_op *fop, struct packet_object *po);
53 static int execute_incdec(struct filter_op *fop, struct packet_object *po);
54 static int execute_func(struct filter_op *fop, struct packet_object *po);
55 
56 static int func_search(struct filter_op *fop, struct packet_object *po);
57 static int func_regex(struct filter_op *fop, struct packet_object *po);
58 static int func_pcre(struct filter_op *fop, struct packet_object *po);
59 static int func_replace(struct filter_op *fop, struct packet_object *po);
60 static int func_inject(struct filter_op *fop, struct packet_object *po);
61 static int func_execinject(struct filter_op *fop, struct packet_object *po);
62 static int func_execreplace(struct filter_op *fop, struct packet_object *po);
63 static int func_log(struct filter_op *fop, struct packet_object *po);
64 static int func_drop(struct packet_object *po);
65 static int func_kill(struct packet_object *po);
66 static int func_exec(struct filter_op *fop);
67 
68 static int cmp_eq(u_int32 a, u_int32 b);
69 static int cmp_neq(u_int32 a, u_int32 b);
70 static int cmp_lt(u_int32 a, u_int32 b);
71 static int cmp_gt(u_int32 a, u_int32 b);
72 static int cmp_leq(u_int32 a, u_int32 b);
73 static int cmp_geq(u_int32 a, u_int32 b);
74 /*******************************************/
75 
76 /* initialize the filter mutex */
filter_init_mutex(void)77 void filter_init_mutex(void) {
78    pthread_mutexattr_t at;
79    pthread_mutexattr_init(&at);
80    /* we want an recursive mutex, so we can re-acquire it in the same thread */
81    pthread_mutexattr_settype(&at, PTHREAD_MUTEX_RECURSIVE_NP);
82    pthread_mutex_init(&filters_mutex, &at);
83 }
84 
85 /*
86  * JIT interpreter for binary filters.
87  * it process the filter_ops and apply the instructions
88  * on the given packet object
89  */
filter_engine(struct filter_op * fop,struct packet_object * po)90 static int filter_engine(struct filter_op *fop, struct packet_object *po)
91 {
92    u_int32 eip = 0;
93    u_int32 flags = 0;
94       #define FLAG_FALSE   0
95       #define FLAG_TRUE    1
96 
97    /* sanity check */
98    BUG_IF(fop == NULL);
99 
100    FILTERS_LOCK;
101 
102    /* loop until EXIT */
103    while (fop[eip].opcode != FOP_EXIT) {
104 
105       switch (fop[eip].opcode) {
106          case FOP_TEST:
107             if (execute_test(&fop[eip], po) == FLAG_TRUE)
108                flags |= FLAG_TRUE;
109             else
110                flags &= ~(FLAG_TRUE);
111 
112             break;
113 
114          case FOP_ASSIGN:
115             execute_assign(&fop[eip], po);
116             /* assignment always returns true */
117             flags |= FLAG_TRUE;
118 
119             break;
120 
121          case FOP_INC:
122          case FOP_DEC:
123             execute_incdec(&fop[eip], po);
124             /* inc/dec always return true */
125             flags |= FLAG_TRUE;
126 
127             break;
128 
129          case FOP_FUNC:
130             if (execute_func(&fop[eip], po) == FLAG_TRUE)
131                flags |= FLAG_TRUE;
132             else
133                flags &= ~(FLAG_TRUE);
134 
135             break;
136 
137          case FOP_JMP:
138             /* jump the the next eip */
139             eip = fop[eip].op.jmp;
140             continue;
141 
142             break;
143 
144          case FOP_JTRUE:
145             /* jump the the next eip if the TRUE FLAG is set*/
146             if (flags & FLAG_TRUE) {
147                eip = fop[eip].op.jmp;
148                continue;
149             }
150             break;
151 
152          case FOP_JFALSE:
153             /* jump the the next eip if the TRUE FLAG is NOT set */
154             if (!(flags & FLAG_TRUE)) {
155                eip = fop[eip].op.jmp;
156                continue;
157             }
158             break;
159 
160          default:
161             FILTERS_UNLOCK;
162             JIT_FAULT("unsupported opcode [%d] (execution interrupted)", fop[eip].opcode);
163             break;
164       }
165 
166       /* autoincrement the instruction pointer */
167       eip++;
168    }
169 
170    FILTERS_UNLOCK;
171 
172    return 0;
173 }
174 
175 /*
176  * pass a packet through every (enabled) filter loaded
177  */
filter_packet(struct packet_object * po)178 void filter_packet(struct packet_object *po) {
179    struct filter_list **l;
180    for (l = EC_GBL_FILTERS; *l != NULL; l = &(*l)->next) {
181       /* if a script drops the packet, do not present it to following scripts */
182       if ( po->flags & PO_DROPPED )
183          break;
184       /* check whether the filter script is enabled */
185       if ((*l)->enabled)
186          filter_engine((*l)->env.chain, po);
187    }
188 }
189 
190 /*
191  * execute a function.
192  * return FLAG_TRUE if the function was successful
193  */
execute_func(struct filter_op * fop,struct packet_object * po)194 static int execute_func(struct filter_op *fop, struct packet_object *po)
195 {
196    switch (fop->op.func.op) {
197       case FFUNC_SEARCH:
198          /* search the string */
199          if (func_search(fop, po) == E_SUCCESS)
200             return FLAG_TRUE;
201          break;
202 
203       case FFUNC_REGEX:
204          /* search the string with a regex */
205          if (func_regex(fop, po) == E_SUCCESS)
206             return FLAG_TRUE;
207          break;
208 
209       case FFUNC_PCRE:
210          /* evaluate a perl regex */
211          if (func_pcre(fop, po) == E_SUCCESS)
212             return FLAG_TRUE;
213          break;
214 
215       case FFUNC_REPLACE:
216          /* replace the string */
217          if (func_replace(fop, po) == E_SUCCESS)
218             return FLAG_TRUE;
219          break;
220 
221       case FFUNC_INJECT:
222          /* replace the string */
223          if (func_inject(fop, po) == E_SUCCESS)
224             return FLAG_TRUE;
225          break;
226 
227       case FFUNC_EXECINJECT:
228          /* replace the string through output of a executable */
229          if (func_execinject(fop, po) == E_SUCCESS)
230             return FLAG_TRUE;
231          break;
232 
233       case FFUNC_EXECREPLACE:
234          /* replace the string through output of a executable */
235          if (func_execreplace(fop, po) == E_SUCCESS)
236             return FLAG_TRUE;
237          break;
238 
239       case FFUNC_LOG:
240          /* log the packet */
241          if (func_log(fop, po) == E_SUCCESS)
242             return FLAG_TRUE;
243          break;
244 
245       case FFUNC_DROP:
246          /* drop the packet */
247          func_drop(po);
248          return FLAG_TRUE;
249          break;
250 
251       case FFUNC_KILL:
252          /* kill the connection */
253          func_kill(po);
254          return FLAG_TRUE;
255          break;
256 
257       case FFUNC_MSG:
258          /* display the message to the user */
259          USER_MSG("%s\n", fop->op.func.string);
260          return FLAG_TRUE;
261          break;
262 
263       case FFUNC_EXEC:
264          /* execute the command */
265          if (func_exec(fop) == E_SUCCESS)
266             return FLAG_TRUE;
267          break;
268 
269       default:
270          JIT_FAULT("unsupported function [%d]", fop->op.func.op);
271          break;
272    }
273 
274    return FLAG_FALSE;
275 }
276 
277 /*
278  * execute a test.
279  * return FLAG_TRUE if the test was successful
280  */
execute_test(struct filter_op * fop,struct packet_object * po)281 static int execute_test(struct filter_op *fop, struct packet_object *po)
282 {
283    /* initialize to the beginning of the packet */
284    u_char *base = po->L2.header;
285    int (*cmp_func)(u_int32, u_int32) = &cmp_eq;
286 
287    /*
288     * point to the right base.
289     * if the test is L3.ttl, we have to start from
290     * L3.header to count for offset.
291     */
292    switch (fop->op.test.level) {
293       case 2:
294          base = po->L2.header;
295          break;
296       case 3:
297          base = po->L3.header;
298          break;
299       case 4:
300          base = po->L4.header;
301          break;
302       case 5:
303          base = po->DATA.data;
304          break;
305       case 6:
306          base = po->DATA.disp_data;
307          break;
308       default:
309          JIT_FAULT("unsupported test level [%d]", fop->op.test.level);
310          break;
311    }
312 
313    /* set the pointer to the comparison function */
314    switch(fop->op.test.op) {
315       case FTEST_EQ:
316          cmp_func = &cmp_eq;
317          break;
318       case FTEST_NEQ:
319          cmp_func = &cmp_neq;
320          break;
321       case FTEST_LT:
322          cmp_func = &cmp_lt;
323          break;
324       case FTEST_GT:
325          cmp_func = &cmp_gt;
326          break;
327       case FTEST_LEQ:
328          cmp_func = &cmp_leq;
329          break;
330       case FTEST_GEQ:
331          cmp_func = &cmp_geq;
332          break;
333       default:
334          JIT_FAULT("unsupported test operation");
335          break;
336 
337    }
338 
339    /*
340     * get the value with the proper size.
341     * 0 is a special case for strings (even binary)
342     */
343    switch (fop->op.test.size) {
344       case 0:
345          /* string comparison */
346          if (cmp_func(memcmp(base + fop->op.test.offset, fop->op.test.string, fop->op.test.slen), 0) )
347             return FLAG_TRUE;
348          break;
349       case 1:
350          /* char comparison */
351          if (cmp_func(*(u_int8 *)(base + fop->op.test.offset), (fop->op.test.value & 0xff)) )
352             return FLAG_TRUE;
353          break;
354       case 2:
355          /* short int comparison */
356          if (cmp_func(htons(*(u_int16 *)(base + fop->op.test.offset)), (fop->op.test.value & 0xffff)) )
357             return FLAG_TRUE;
358          break;
359       case 4:
360          /* int comparison */
361          if (cmp_func(htonl(*(u_int32 *)(base + fop->op.test.offset)), (fop->op.test.value & 0xffffffff)) )
362             return FLAG_TRUE;
363          break;
364       case 16: /* well IPv6 addresses should be handled as 16-byte pointer */
365          if (cmp_func(memcmp(base + fop->op.test.offset, fop->op.test.ipaddr, fop->op.test.size), 0) )
366             return FLAG_TRUE;
367          break;
368       default:
369          JIT_FAULT("unsupported test size [%d]", fop->op.test.size);
370          break;
371    }
372 
373    return FLAG_FALSE;
374 }
375 
376 /*
377  * make an assignment.
378  */
execute_assign(struct filter_op * fop,struct packet_object * po)379 static int execute_assign(struct filter_op *fop, struct packet_object *po)
380 {
381    /* initialize to the beginning of the packet */
382    u_char *base = po->L2.header;
383 
384    /* check the offensiveness */
385    if (EC_GBL_OPTIONS->unoffensive)
386       JIT_FAULT("Cannot modify packets in unoffensive mode");
387 
388    DEBUG_MSG("filter engine: execute_assign: L%d O%d S%d", fop->op.assign.level, fop->op.assign.offset, fop->op.assign.size);
389 
390    /*
391     * point to the right base.
392     */
393    switch (fop->op.assign.level) {
394       case 2:
395          base = po->L2.header;
396          break;
397       case 3:
398          base = po->L3.header;
399          break;
400       case 4:
401          base = po->L4.header;
402          break;
403       case 5:
404          base = po->DATA.data;
405          break;
406       default:
407          JIT_FAULT("unsupported assignment level [%d]", fop->op.assign.level);
408          break;
409    }
410 
411    /*
412     * get the value with the proper size.
413     * 0 is a special case for strings (even binary)
414     */
415    switch (fop->op.assign.size) {
416       case 0:
417          memcpy(base + fop->op.assign.offset, fop->op.assign.string, fop->op.assign.slen);
418          break;
419       case 1:
420          *(u_int8 *)(base + fop->op.assign.offset) = (fop->op.assign.value & 0xff);
421          break;
422       case 2:
423          *(u_int16 *)(base + fop->op.assign.offset) = ntohs(fop->op.assign.value & 0xffff);
424          break;
425       case 4:
426          *(u_int32 *)(base + fop->op.assign.offset) = ntohl(fop->op.assign.value & 0xffffffff);
427          break;
428       default:
429          JIT_FAULT("unsupported assign size [%d]", fop->op.assign.size);
430          break;
431    }
432 
433    /* mark the packet as modified */
434    po->flags |= PO_MODIFIED;
435 
436    return FLAG_TRUE;
437 }
438 
439 /*
440  * make an increment or decrement.
441  */
execute_incdec(struct filter_op * fop,struct packet_object * po)442 static int execute_incdec(struct filter_op *fop, struct packet_object *po)
443 {
444    /* initialize to the beginning of the packet */
445    u_char *base = po->L2.header;
446 
447    /* check the offensiveness */
448    if (EC_GBL_OPTIONS->unoffensive)
449       JIT_FAULT("Cannot modify packets in unoffensive mode");
450 
451    DEBUG_MSG("filter engine: execute_incdec: L%d O%d S%d", fop->op.assign.level, fop->op.assign.offset, fop->op.assign.size);
452 
453    /*
454     * point to the right base.
455     */
456    switch (fop->op.assign.level) {
457       case 2:
458          base = po->L2.header;
459          break;
460       case 3:
461          base = po->L3.header;
462          break;
463       case 4:
464          base = po->L4.header;
465          break;
466       case 5:
467          base = po->DATA.data;
468          break;
469       default:
470          JIT_FAULT("unsupported inc/dec level [%d]", fop->op.assign.level);
471          break;
472    }
473 
474    /*
475     * inc/dec the value with the proper size.
476     */
477    switch (fop->op.assign.size) {
478       case 1:
479          if (fop->opcode == FOP_INC)
480             *(u_int8 *)(base + fop->op.assign.offset) += (fop->op.assign.value & 0xff);
481          else
482             *(u_int8 *)(base + fop->op.assign.offset) -= (fop->op.assign.value & 0xff);
483          break;
484       case 2:
485          if (fop->opcode == FOP_INC)
486             *(u_int16 *)(base + fop->op.assign.offset) += ntohs(fop->op.assign.value & 0xffff);
487          else
488             *(u_int16 *)(base + fop->op.assign.offset) -= ntohs(fop->op.assign.value & 0xffff);
489          break;
490       case 4:
491          if (fop->opcode == FOP_INC)
492             *(u_int32 *)(base + fop->op.assign.offset) += ntohl(fop->op.assign.value & 0xffffffff);
493          else
494             *(u_int32 *)(base + fop->op.assign.offset) -= ntohl(fop->op.assign.value & 0xffffffff);
495          break;
496       default:
497          JIT_FAULT("unsupported inc/dec size [%d]", fop->op.assign.size);
498          break;
499    }
500 
501    /* mark the packet as modified */
502    po->flags |= PO_MODIFIED;
503 
504    return FLAG_TRUE;
505 }
506 
507 
508 /*
509  * search a string and return TRUE if found
510  */
func_search(struct filter_op * fop,struct packet_object * po)511 static int func_search(struct filter_op *fop, struct packet_object *po)
512 {
513    switch (fop->op.func.level) {
514       case 5:
515          /* search in the real packet */
516          if (memmem(po->DATA.data, po->DATA.len, fop->op.func.string, fop->op.func.slen))
517             return E_SUCCESS;
518          break;
519       case 6:
520          /* search in the decoded/decrypted packet */
521          if (memmem(po->DATA.disp_data, po->DATA.disp_len, fop->op.func.string, fop->op.func.slen))
522             return E_SUCCESS;
523          break;
524       default:
525          JIT_FAULT("unsupported search level [%d]", fop->op.func.level);
526          break;
527    }
528 
529    return -E_NOTFOUND;
530 }
531 
532 /*
533  * search a string with a regex and return TRUE if found
534  */
func_regex(struct filter_op * fop,struct packet_object * po)535 static int func_regex(struct filter_op *fop, struct packet_object *po)
536 {
537    switch (fop->op.func.level) {
538       case 5:
539          /* search in the real packet */
540          if (regexec(fop->op.func.ropt->regex, (const char*)po->DATA.data, 0, NULL, 0) == 0)
541             return E_SUCCESS;
542          break;
543       case 6:
544          /* search in the decoded/decrypted packet */
545          if (regexec(fop->op.func.ropt->regex, (const char*)po->DATA.disp_data, 0, NULL, 0) == 0)
546             return E_SUCCESS;
547          break;
548       default:
549          JIT_FAULT("unsupported regex level [%d]", fop->op.func.level);
550          break;
551    }
552 
553    return -E_NOTFOUND;
554 }
555 
556 
557 /*
558  * evaluate a perl regex and return TRUE if found
559  */
func_pcre(struct filter_op * fop,struct packet_object * po)560 static int func_pcre(struct filter_op *fop, struct packet_object *po)
561 {
562 #ifndef HAVE_PCRE
563    (void) fop;
564    (void) po;
565    JIT_FAULT("pcre_regex support not compiled in ettercap");
566    return -E_NOTFOUND;
567 #else
568    int ovec[PCRE_OVEC_SIZE];
569    int ret;
570 
571    DEBUG_MSG("filter engine: func_pcre");
572 
573    memset(&ovec, 0, sizeof(ovec));
574 
575    switch (fop->op.func.level) {
576       case 5:
577 
578          /* search in the real packet */
579          if ( (ret = pcre_exec(fop->op.func.ropt->pregex, fop->op.func.ropt->preg_extra, po->DATA.data, po->DATA.len, 0, 0, ovec, sizeof(ovec) / sizeof(*ovec))) < 0)
580             return -E_NOTFOUND;
581 
582          /* the pcre wants to modify the packet */
583          if (fop->op.func.replace) {
584             u_char *replaced;
585             u_char *q = fop->op.func.replace;
586             size_t i;
587             int slen = 0;
588 
589             /* don't modify if in unoffensive mode */
590             if (EC_GBL_OPTIONS->unoffensive)
591                JIT_FAULT("Cannot modify packets in unoffensive mode");
592 
593             /*
594              * worst case: the resulting string will need:
595              *   (n * |input|) + |subst| bytes
596              * where
597              *   |input| is the length of the matched input string (not the regex!)
598              *   |subst| is the length of the substition string
599              *   n       is the number of replacement markers in subst
600              *
601              * therefore, we need to count the number of $ characters first
602              * to get an upper limit of the buffer space needed
603              */
604             int markers = 0;
605             for (i=0; q[i]; i++) {
606                if (q[i] == '$') markers++;
607             }
608             /* now: i = strlen(q) */
609 
610             SAFE_CALLOC(replaced, markers*(ovec[1]-ovec[0]) + i + 1, sizeof(char));
611 
612             po->flags |= PO_MODIFIED;
613 
614             /* make the replacement */
615             uint8_t escaped = 0;
616             for (i = 0; i < fop->op.func.rlen; i++) {
617                /* we encounter an escape character (\), so the next character is to be taken literally */
618                if (!escaped && q[i] == '\\') {
619                   escaped = 1;
620                }
621                /* there is an unescaped position marker */
622                else if (!escaped && q[i] == '$') {
623                   /* a marker is succeeded by an integer, make sure it is there */
624                   if (q[i+1] == '\0')
625                      JIT_FAULT("Incomplete marker at end of substitution string");
626 
627                   /* so now we can safely move on to the next character, our digit */
628                   i++;
629                   /* we only support up to 9 markers since we only parse a single digit */
630                   if (q[i] < '0' || q[i] > '9')
631                      JIT_FAULT("Incomplete marker without integer in substitution string");
632 
633                   int marker = q[i]-'0';
634 
635                   /* check if the requested marker was found in the pce */
636                   if (marker > ret - 1 || marker == 0)
637                      JIT_FAULT("Too many marker for this pcre expression");
638 
639                   int t = ovec[marker * 2];
640                   int r = ovec[marker * 2 + 1];
641 
642                   /* copy the sub-string in place of the marker */
643                   for ( ; t < r; t++)
644                      replaced[slen++] = po->DATA.data[t];
645 
646                }
647                /* anything else either has no special meaning or is escaped,
648                 * so we just copy it
649                 */
650                else {
651                   replaced[slen++] = q[i];
652                   escaped = 0;
653                }
654             }
655 
656             /* calculate the delta */
657             int delta = (ovec[0]-ovec[1])+slen;
658 
659             /* check if we are overflowing pcap buffer */
660             BUG_IF(po->DATA.data < po->packet);
661             BUG_IF((u_int16)(EC_GBL_PCAP->snaplen - (po->DATA.data - po->packet)) <= po->DATA.len+delta);
662 
663             /* if the substitution string has a different length than the
664              * matched original string, we have to move around some data
665              */
666             int size_left = po->DATA.len - ovec[0] - slen;
667             int data_left = po->DATA.len - ovec[1];
668             DEBUG_MSG("func_pcre: match from %d to %d, substitution length is %d\n", ovec[0], ovec[1], slen);
669             DEBUG_MSG("func_pcre: packet size changed by %d bytes\n", delta);
670             if (delta != 0) {
671                /* copy everything behind the matched string to the new position */
672                memcpy(po->DATA.data+ovec[0]+slen, po->DATA.data + ovec[1], size_left < data_left ? size_left : data_left);
673             }
674 
675             /* copy the modified buffer on the original packet */
676             memcpy(po->DATA.data+ovec[0], replaced, slen);
677 
678             po->DATA.delta += delta;
679             po->DATA.len += delta;
680 
681             SAFE_FREE(replaced);
682          }
683 
684          break;
685       case 6:
686          /* search in the decoded one */
687          if ( pcre_exec(fop->op.func.ropt->pregex, fop->op.func.ropt->preg_extra, po->DATA.disp_data, po->DATA.disp_len, 0, 0, NULL, 0) < 0)
688             return -E_NOTFOUND;
689          break;
690       default:
691          JIT_FAULT("unsupported pcre_regex level [%d]", fop->op.func.level);
692          break;
693    }
694 
695    return E_SUCCESS;
696 #endif
697 }
698 
699 
700 /*
701  * replace a string in the packet object DATA.data
702  */
func_replace(struct filter_op * fop,struct packet_object * po)703 static int func_replace(struct filter_op *fop, struct packet_object *po)
704 {
705    u_int8 *ptr;
706    u_int8 *end;
707    size_t len;
708    size_t slen = fop->op.func.slen;
709    size_t rlen = fop->op.func.rlen;
710 
711    /* check the offensiveness */
712    if (EC_GBL_OPTIONS->unoffensive)
713       JIT_FAULT("Cannot modify packets in unoffensive mode");
714 
715    /* check if it exist at least one */
716    if (!memmem(po->DATA.data, po->DATA.len, fop->op.func.string, fop->op.func.slen) )
717       return -E_NOTFOUND;
718 
719    DEBUG_MSG("filter engine: func_replace");
720 
721    /*
722     * XXX BIG WARNING:
723     * maxlen is EC_GBL_PCAP->snaplen, but we can't
724     * rely on this forever...
725     */
726 
727    /* take the beginning and the end of the data */
728    ptr = po->DATA.data;
729    end = ptr + po->DATA.len;
730 
731    /* do the replacement */
732    do {
733       /* the len of the buffer to be analized */
734       len = end - ptr;
735 
736       /* search the string */
737       ptr = memmem(ptr, len, fop->op.func.string, slen);
738 
739       /* string no found, exit */
740       if (ptr == NULL)
741          break;
742 
743       /* update the len */
744       len = end - ptr - slen;
745 
746       /* set the delta */
747       po->DATA.delta += rlen - slen;
748       po->DATA.len += rlen - slen;
749 
750       /* check if we are overflowing pcap buffer */
751       BUG_IF(po->DATA.data < po->packet);
752       BUG_IF((u_int16)(EC_GBL_PCAP->snaplen - (po->DATA.data - po->packet)) <=  po->DATA.len);
753 
754       /* move the buffer to make room for the replacement string */
755       memmove(ptr + rlen, ptr + slen, len);
756       /* copy the replacemente string */
757       memcpy(ptr, fop->op.func.replace, rlen);
758       /* move the ptr after the replaced string */
759       ptr += rlen;
760       /* adjust the new buffer end */
761       end += rlen - slen;
762 
763       /* mark the packet as modified */
764       po->flags |= PO_MODIFIED;
765 
766    } while(ptr != NULL && ptr < end);
767 
768    return E_SUCCESS;
769 }
770 
771 /*
772  * inject a file into the communication
773  */
func_inject(struct filter_op * fop,struct packet_object * po)774 static int func_inject(struct filter_op *fop, struct packet_object *po)
775 {
776    int fd;
777    void *file;
778    size_t size, ret;
779 
780    /* check the offensiveness */
781    if (EC_GBL_OPTIONS->unoffensive)
782       JIT_FAULT("Cannot inject packets in unoffensive mode");
783 
784 
785    DEBUG_MSG("filter engine: func_inject %s", fop->op.func.string);
786 
787    /* open the file */
788    if ((fd = open((const char*)fop->op.func.string, O_RDONLY | O_BINARY)) == -1) {
789       USER_MSG("filter engine: inject(): File not found (%s)\n", fop->op.func.string);
790       return -E_FATAL;
791    }
792 
793    /* get the size */
794    size = lseek(fd, 0, SEEK_END);
795 
796    /* load the file in memory */
797    SAFE_CALLOC(file, size, sizeof(char));
798 
799    /* rewind the pointer */
800    lseek(fd, 0, SEEK_SET);
801 
802    ret = read(fd, file, size);
803 
804    close(fd);
805 
806    if (ret != size)
807       FATAL_MSG("Cannot read the file into memory");
808 
809    /* check if we are overflowing pcap buffer */
810    if(EC_GBL_PCAP->snaplen - (po->L4.header - (po->packet + po->L2.len) + po->L4.len) <= po->DATA.len + (unsigned)size)
811       JIT_FAULT("injected file too long");
812 
813    /* copy the file into the buffer */
814    memcpy(po->DATA.data + po->DATA.len, file, size);
815 
816    /* Adjust packet len and delta */
817    po->DATA.delta += size;
818    po->DATA.len += size;
819 
820    /* mark the packet as modified */
821    po->flags |= PO_MODIFIED;
822 
823    /* unset the flag to be dropped */
824    if (po->flags & PO_DROPPED)
825       po->flags ^= PO_DROPPED;
826 
827    /* close and unmap the file */
828    SAFE_FREE(file);
829 
830    return E_SUCCESS;
831 }
832 
833 /*
834  * inject output of a executable into the communication
835  */
func_execinject(struct filter_op * fop,struct packet_object * po)836 static int func_execinject(struct filter_op *fop, struct packet_object *po)
837 {
838    FILE *pstream = NULL;
839    unsigned char *output = NULL;
840    size_t n = 0, offset = 0, size = 128;
841    unsigned char buf[size];
842 
843    /* check the offensiveness */
844    if (EC_GBL_OPTIONS->unoffensive)
845       JIT_FAULT("Cannot inject packets in unoffensive mode");
846 
847 
848    DEBUG_MSG("filter engine: func_execinject %s", fop->op.func.string);
849 
850    /* open the pipe */
851    if ((pstream = popen((const char*)fop->op.func.string, "r")) == NULL) {
852       USER_MSG("filter engine: execinject(): Command not found (%s)\n", fop->op.func.string);
853       return -E_FATAL;
854    }
855 
856    while ((n = read(fileno(pstream), buf, size)) != 0) {
857       if (output == NULL) {
858          SAFE_CALLOC(output, offset+n, sizeof(unsigned char));
859       }
860       else {
861          SAFE_REALLOC(output, sizeof(unsigned char)*(offset+n));
862       }
863 
864       memcpy(output+offset, buf, n);
865       offset += n;
866    }
867 
868    /* close pipe stream */
869    pclose(pstream);
870 
871    /* check if we are overflowing pcap buffer */
872    if(EC_GBL_PCAP->snaplen - (po->L4.header - (po->packet + po->L2.len) + po->L4.len) <= po->DATA.len + (unsigned)offset)
873       JIT_FAULT("injected output too long");
874 
875    /* copy the output into the buffer */
876    memcpy(po->DATA.data + po->DATA.len, output, offset);
877 
878    /* Adjust packet len and delta */
879    po->DATA.delta += offset;
880    po->DATA.len += offset;
881 
882    /* mark the packet as modified */
883    po->flags |= PO_MODIFIED;
884 
885    /* unset the flag to be dropped */
886    if (po->flags & PO_DROPPED)
887       po->flags ^= PO_DROPPED;
888 
889    /* free memory */
890    SAFE_FREE(output);
891 
892    return E_SUCCESS;
893 }
894 
895 /*
896  * replace output of a executable into the communication
897  * executable takes communication before any change in input
898  */
func_execreplace(struct filter_op * fop,struct packet_object * po)899 static int func_execreplace(struct filter_op *fop, struct packet_object *po)
900 {
901    int child_stdout[2], child_stdin[2];
902    pid_t child_pid;
903    unsigned char *output = NULL;
904    size_t n = 0, offset = 0, size = 128;
905    unsigned char buf[size];
906 
907    /* check the offensiveness */
908    if (EC_GBL_OPTIONS->unoffensive)
909       JIT_FAULT("Cannot replace packets in unoffensive mode");
910 
911 
912    DEBUG_MSG("filter engine: func_execreplace %s", fop->op.func.string);
913 
914    /* open the pipe */
915    if (pipe(child_stdin) != 0 || pipe(child_stdout) != 0) {
916       USER_MSG("filter engine: execreplace(): failed to create pipes\n");
917       return -E_FATAL;
918    }
919    if ((child_pid = fork()) < 0) {
920       USER_MSG("filter engine: execreplace(): failed to fork\n");
921       return -E_FATAL;
922    }
923    if (child_pid == 0) {
924        char *const argv[] = { "/bin/sh", "-c", fop->op.func.string, NULL };
925        if (dup2(child_stdin[0], STDIN_FILENO) == -1 || dup2(child_stdout[1], STDOUT_FILENO) == -1) {
926            exit(EXIT_FAILURE);
927        }
928        close(child_stdin[1]);
929        close(child_stdout[0]);
930 
931        execv(argv[0], argv);
932        exit(EXIT_FAILURE);
933    }
934 
935    close(child_stdin[0]);
936    close(child_stdout[1]);
937    /* fill child STDIN with DATA */
938    while (offset < po->DATA.len) {
939        n = write(child_stdin[1], po->DATA.data + offset, po->DATA.len - offset);
940        if (n == (size_t)-1) {
941            break;
942        }
943        offset += n;
944    }
945    close(child_stdin[1]);
946 
947    /* Fill child STDIN with DATA */
948    offset = 0;
949    while ((n = read(child_stdout[0], buf, size)) != 0) {
950       if (output == NULL) {
951          SAFE_CALLOC(output, offset+n, sizeof(unsigned char));
952       }
953       else {
954          SAFE_REALLOC(output, sizeof(unsigned char)*(offset+n));
955       }
956 
957       memcpy(output+offset, buf, n);
958       offset += n;
959    }
960    /* close pipe stream */
961    close(child_stdout[0]);
962 
963    /* check if we are overflowing pcap buffer */
964    if(EC_GBL_PCAP->snaplen - (po->L4.header - (po->packet + po->L2.len) + po->L4.len) <= po->DATA.len + (unsigned)offset)
965       JIT_FAULT("replaced output too long");
966 
967    /* copy the output into the buffer */
968    memcpy(po->DATA.data, output, offset);
969 
970    /* Adjust packet len and delta */
971    if ((u_int)offset > po->DATA.len) {
972       po->DATA.delta += (int)((u_int)offset - po->DATA.len);
973    } else {
974       po->DATA.delta -= (int)(po->DATA.len - (u_int)offset);
975    }
976    po->DATA.len = offset;
977 
978    /* mark the packet as modified */
979    po->flags |= PO_MODIFIED;
980 
981    /* unset the flag to be dropped */
982    if (po->flags & PO_DROPPED)
983       po->flags ^= PO_DROPPED;
984 
985    /* free memory */
986    SAFE_FREE(output);
987 
988    return E_SUCCESS;
989 }
990 
991 
992 /*
993  * log the packet to a file
994  */
func_log(struct filter_op * fop,struct packet_object * po)995 static int func_log(struct filter_op *fop, struct packet_object *po)
996 {
997    int fd;
998 
999    DEBUG_MSG("filter engine: func_log");
1000 
1001    /* open the file */
1002    fd = open((const char*)fop->op.func.string, O_CREAT | O_APPEND | O_RDWR | O_BINARY, 0600);
1003    if (fd == -1) {
1004       USER_MSG("filter engine: Cannot open file %s\n", fop->op.func.string);
1005       return -E_FATAL;
1006    }
1007 
1008    /* which data should I have to log ? */
1009    switch(fop->op.func.level) {
1010       case 5:
1011          if (write(fd, po->DATA.data, po->DATA.len) < 0)
1012             USER_MSG("filter engine: Cannot write to file...%d\n", errno);
1013          break;
1014       case 6:
1015          if (write(fd, po->DATA.disp_data, po->DATA.disp_len) < 0)
1016             USER_MSG("filter engine: Cannot write to file...\n");
1017          break;
1018       default:
1019          JIT_FAULT("unsupported log level [%d]", fop->op.func.level);
1020          break;
1021    }
1022 
1023    /* close the file */
1024    close(fd);
1025 
1026    return E_SUCCESS;
1027 }
1028 
1029 /*
1030  * drop the packet
1031  */
func_drop(struct packet_object * po)1032 static int func_drop(struct packet_object *po)
1033 {
1034    DEBUG_MSG("filter engine: func_drop");
1035 
1036    /* se the flag to be dropped */
1037    po->flags |= PO_DROPPED;
1038 
1039    /* the delta is all the payload */
1040    po->DATA.delta -= po->DATA.len;
1041    po->DATA.len = 0;
1042 
1043    return E_SUCCESS;
1044 }
1045 
1046 /*
1047  * kill the connection:
1048  *    TCP:  reset
1049  *    UDP:  icmp port unreachable
1050  */
func_kill(struct packet_object * po)1051 static int func_kill(struct packet_object *po)
1052 {
1053    DEBUG_MSG("filter engine: func_kill");
1054 
1055    if (po->L4.proto == NL_TYPE_TCP) {
1056       /* reset both sides */
1057       /*
1058        * we can trust the ack number.
1059        * at least one side will be reset. the other is automatically reset
1060        */
1061       send_tcp(&po->L3.src, &po->L3.dst, po->L4.src, po->L4.dst, po->L4.seq, 0, TH_RST, NULL, 0);
1062       send_tcp(&po->L3.dst, &po->L3.src, po->L4.dst, po->L4.src, po->L4.ack, 0, TH_RST, NULL, 0);
1063    } else if (po->L4.proto == NL_TYPE_UDP) {
1064       send_L3_icmp_unreach(po);
1065    }
1066 
1067    return E_SUCCESS;
1068 }
1069 
1070 /*
1071  * execute the given command
1072  */
func_exec(struct filter_op * fop)1073 static int func_exec(struct filter_op *fop)
1074 {
1075    pid_t pid;
1076 
1077    DEBUG_MSG("filter engine: func_exec: %s", fop->op.func.string);
1078 
1079    /*
1080     * the command must be executed by a child.
1081     * we are forwding packets, and we cannot wait
1082     * for the execution of the command
1083     */
1084    pid = fork();
1085 
1086    /* check if the fork was successful */
1087    if (pid == -1)
1088       SEMIFATAL_ERROR("filter engine: fork() failed, cannot execute %s", fop->op.func.string);
1089 
1090    /* differentiate between the parent and the child */
1091    if (!pid) {
1092       int k, param_length;
1093       char **param = NULL;
1094       char *q = (char*)fop->op.func.string;
1095       char *p;
1096       int i = 0;
1097 
1098       /* split the string */
1099       for (p = strsep(&q, " "); p != NULL; p = strsep(&q, " ")) {
1100          /* allocate the array */
1101          SAFE_REALLOC(param, (i + 1) * sizeof(char *));
1102 
1103          /* copy the tokens in the array */
1104          param[i++] = strdup(p);
1105       }
1106 
1107       /* NULL terminate the array */
1108       SAFE_REALLOC(param, (i + 1) * sizeof(char *));
1109 
1110       param[i] = NULL;
1111       param_length= i + 1; //because there is a SAFE_REALLOC after the for.
1112 
1113       /*
1114        * close input, output and error.
1115        * we don't want to clobber the interface
1116        * with output from the child
1117        */
1118       close(fileno(stdin));
1119       close(fileno(stdout));
1120       close(fileno(stderr));
1121 
1122       /* execute the command */
1123       execve(param[0], param, NULL);
1124 
1125       /* reached on errors */
1126 	   for(k= 0; k < param_length; ++k)
1127 		   SAFE_FREE(param[k]);
1128 	   SAFE_FREE(param);
1129       _exit(-1);
1130    }
1131 
1132    return E_SUCCESS;
1133 }
1134 
1135 /*
1136  * functions for comparisons
1137  */
cmp_eq(u_int32 a,u_int32 b)1138 static int cmp_eq(u_int32 a, u_int32 b)
1139 {
1140    return (a == b);
1141 }
1142 
cmp_neq(u_int32 a,u_int32 b)1143 static int cmp_neq(u_int32 a, u_int32 b)
1144 {
1145    return (a != b);
1146 }
1147 
cmp_lt(u_int32 a,u_int32 b)1148 static int cmp_lt(u_int32 a, u_int32 b)
1149 {
1150    return (a < b);
1151 }
1152 
cmp_gt(u_int32 a,u_int32 b)1153 static int cmp_gt(u_int32 a, u_int32 b)
1154 {
1155    return (a > b);
1156 }
1157 
cmp_leq(u_int32 a,u_int32 b)1158 static int cmp_leq(u_int32 a, u_int32 b)
1159 {
1160    return (a <= b);
1161 }
1162 
cmp_geq(u_int32 a,u_int32 b)1163 static int cmp_geq(u_int32 a, u_int32 b)
1164 {
1165    return (a >= b);
1166 }
1167 
1168 /*
1169  * load the filter from a file
1170  */
filter_load_file(const char * filename,struct filter_list ** list,uint8_t enabled)1171 int filter_load_file(const char *filename, struct filter_list **list, uint8_t enabled)
1172 {
1173    int fd;
1174    void *file;
1175    size_t size, ret;
1176    struct filter_env *fenv;
1177    struct filter_header fh;
1178 
1179    DEBUG_MSG("filter_load_file (%s)", filename);
1180 
1181   /* open the file */
1182    if ((fd = open(filename, O_RDONLY | O_BINARY)) == -1)
1183       FATAL_MSG("File not found or permission denied");
1184 
1185    /* read the header */
1186    if (read(fd, &fh, sizeof(struct filter_header)) != sizeof(struct filter_header))
1187       FATAL_MSG("The file is corrupted");
1188 
1189    /* sanity checks */
1190    if (fh.magic != htons(EC_FILTER_MAGIC))
1191       FATAL_MSG("Bad magic in filter file\n"
1192             "Make sure to compile the filter with a current version of etterfilter");
1193 
1194    /* check pointer alignment */
1195    if (fh.code % 8)
1196       FATAL_MSG("Bad instruction pointer alignment\n"
1197             "Make sure to compile the filter with a current version of etterfilter");
1198 
1199    /* which version has compiled the filter ? */
1200    if (strcmp(fh.version, EC_VERSION))
1201       FATAL_MSG("Filter compiled for a different version");
1202 
1203    /* get the size */
1204    size = lseek(fd, 0, SEEK_END);
1205 
1206    /* load the file in memory */
1207    SAFE_CALLOC(file, size, sizeof(char));
1208 
1209    /* rewind the pointer */
1210    lseek(fd, 0, SEEK_SET);
1211 
1212    ret = read(fd, file, size);
1213 
1214    close(fd);
1215 
1216    if (ret != size)
1217       FATAL_MSG("Cannot read the file into memory");
1218 
1219    FILTERS_LOCK;
1220 
1221    /* advance to the end of the filter list */
1222    while (*list) list = &(*list)->next;
1223 
1224    /* allocate memory for the list entry */
1225    SAFE_CALLOC(*list, 1, sizeof(struct filter_list));
1226    fenv = &(*list)->env;
1227 
1228    /* set the global variables */
1229    fenv->map = file;
1230    fenv->chain = (struct filter_op *)(file + fh.code);
1231    fenv->len = size - sizeof(struct filter_header) - fh.code;
1232 
1233    /*
1234     * adjust all the string pointers
1235     * they must point to the data segment
1236     */
1237    reconstruct_strings(fenv, &fh);
1238 
1239    /* save the name of the loaded filter */
1240    (*list)->name = strdup(filename);
1241 
1242    /* enable the filter if requested */
1243    (*list)->enabled = enabled;
1244 
1245    FILTERS_UNLOCK;
1246 
1247    /* compile the regex to speed up the matching */
1248    if (compile_regex(fenv) != E_SUCCESS)
1249       return -E_FATAL;
1250 
1251    USER_MSG("Content filters loaded from %s...\n", filename);
1252 
1253    return E_SUCCESS;
1254 }
1255 
1256 /*
1257  * unload a filter list entry
1258  */
filter_unload(struct filter_list ** list)1259 void filter_unload(struct filter_list **list)
1260 {
1261    if (*list == NULL) return;
1262 
1263    FILTERS_LOCK;
1264 
1265    struct filter_env *fenv= &(*list)->env;
1266    size_t i = 0;
1267    struct filter_op *fop = fenv->chain;
1268 
1269    DEBUG_MSG("filter_unload");
1270 
1271    /* free the memory alloc'd for regex */
1272    while (fop != NULL && i < (fenv->len / sizeof(struct filter_op)) ) {
1273       /* search for func regex and pcre */
1274       if(fop[i].opcode == FOP_FUNC) {
1275          switch(fop[i].op.func.op) {
1276             case FFUNC_REGEX:
1277                regfree(fop[i].op.func.ropt->regex);
1278                SAFE_FREE(fop[i].op.func.ropt);
1279                break;
1280 
1281             case FFUNC_PCRE:
1282                #ifdef HAVE_PCRE
1283                pcre_free(fop[i].op.func.ropt->pregex);
1284                pcre_free(fop[i].op.func.ropt->preg_extra);
1285                SAFE_FREE(fop[i].op.func.ropt);
1286                #endif
1287                break;
1288          }
1289       }
1290       i++;
1291    }
1292 
1293    /* free the memory region containing the file */
1294    SAFE_FREE(fenv->map);
1295 
1296    /* wipe the pointer */
1297    fenv->map = NULL;
1298    fenv->chain = NULL;
1299    fenv->len = 0;
1300 
1301    SAFE_FREE((*list)->name);
1302 
1303    /* reclose the filter list */
1304    struct filter_list **ptr = list;
1305    struct filter_list *succ = (*list)->next;
1306    *ptr = succ;
1307    SAFE_FREE(*list);
1308 
1309    FILTERS_UNLOCK;
1310 }
1311 
filter_clear(void)1312 void filter_clear(void) {
1313    FILTERS_LOCK;
1314    struct filter_list **l = EC_GBL_FILTERS;
1315    while (*l) {
1316       filter_unload(l);
1317    }
1318    FILTERS_UNLOCK;
1319 }
1320 
1321 
1322 /*
1323  * replace relative offset to real address in the strings fields
1324  */
reconstruct_strings(struct filter_env * fenv,struct filter_header * fh)1325 static void reconstruct_strings(struct filter_env *fenv, struct filter_header *fh)
1326 {
1327    size_t i = 0;
1328    struct filter_op *fop = fenv->chain;
1329 
1330    /* parse all the instruction */
1331    while (i < (fenv->len / sizeof(struct filter_op)) ) {
1332 
1333       /*
1334        * the real address for a string is the base of the mmap'd file
1335        * plus the base of the data segment plus the offset in the field
1336        */
1337       switch(fop[i].opcode) {
1338          case FOP_FUNC:
1339             if (fop[i].op.func.slen)
1340                fop[i].op.func.string = (fenv->map + fh->data + (size_t)fop[i].op.func.string);
1341             if (fop[i].op.func.rlen)
1342                fop[i].op.func.replace = (fenv->map + fh->data + (size_t)fop[i].op.func.replace);
1343             break;
1344 
1345          case FOP_TEST:
1346             if (fop[i].op.test.slen)
1347                fop[i].op.test.string = (fenv->map + fh->data + (size_t)fop[i].op.test.string);
1348             break;
1349 
1350          case FOP_ASSIGN:
1351             if (fop[i].op.assign.slen)
1352                fop[i].op.assign.string = (fenv->map + fh->data + (size_t)fop[i].op.assign.string);
1353             break;
1354       }
1355 
1356       i++;
1357    }
1358 
1359 }
1360 
1361 /*
1362  * compile the regex of a filter_op
1363  */
compile_regex(struct filter_env * fenv)1364 static int compile_regex(struct filter_env *fenv)
1365 {
1366    size_t i = 0;
1367    struct filter_op *fop = fenv->chain;
1368    char errbuf[100];
1369    int err;
1370 #ifdef HAVE_PCRE
1371    const char *perrbuf = NULL;
1372 #endif
1373 
1374    /* parse all the instruction */
1375    while (i < (fenv->len / sizeof(struct filter_op)) ) {
1376 
1377       /* search for func regex and pcre */
1378       if(fop[i].opcode == FOP_FUNC) {
1379          switch(fop[i].op.func.op) {
1380             case FFUNC_REGEX:
1381 
1382                /* alloc the structures */
1383                SAFE_CALLOC(fop[i].op.func.ropt, 1, sizeof(struct regex_opt));
1384                SAFE_CALLOC(fop[i].op.func.ropt->regex, 1, sizeof(regex_t));
1385 
1386                /* prepare the regex */
1387                err = regcomp(fop[i].op.func.ropt->regex, (const char*)fop[i].op.func.string, REG_EXTENDED | REG_NOSUB | REG_ICASE );
1388                if (err) {
1389                   regerror(err, fop[i].op.func.ropt->regex, errbuf, sizeof(errbuf));
1390                   FATAL_MSG("filter engine: %s", errbuf);
1391                }
1392                break;
1393 
1394             case FFUNC_PCRE:
1395                #ifdef HAVE_PCRE
1396 
1397                /* alloc the structure */
1398                SAFE_CALLOC(fop[i].op.func.ropt, 1, sizeof(struct regex_opt));
1399 
1400                /* prepare the regex (with default option) */
1401                fop[i].op.func.ropt->pregex = pcre_compile(fop[i].op.func.string, 0, &perrbuf, &err, NULL );
1402                if (fop[i].op.func.ropt->pregex == NULL)
1403                   FATAL_MSG("filter engine: %s\n", perrbuf);
1404 
1405                /* optimize the pcre */
1406                fop[i].op.func.ropt->preg_extra = pcre_study(fop[i].op.func.ropt->pregex, 0, &perrbuf);
1407                if (perrbuf != NULL)
1408                   FATAL_MSG("filter engine: %s\n", perrbuf);
1409 
1410                #endif
1411                break;
1412          }
1413       }
1414       i++;
1415    }
1416 
1417    return E_SUCCESS;
1418 }
1419 
1420 /*
1421  * Walk the list of loaded filters and call the callback function
1422  * for every single list item along with the argument passed.
1423  * The callback function can stop the list from being traversed
1424  * any further by returning a false value.
1425  */
filter_walk_list(int (* cb)(struct filter_list *,void *),void * arg)1426 void filter_walk_list( int(*cb)(struct filter_list*, void*), void *arg) {
1427    struct filter_list **l;
1428    FILTERS_LOCK;
1429    for (l = EC_GBL_FILTERS; *l != NULL; l = &(*l)->next) {
1430       /* do not traverse the list any further if the callback tells us so */
1431       if (!cb(*l, arg))
1432          break;
1433    }
1434    FILTERS_UNLOCK;
1435 }
1436 
1437 /* EOF */
1438 
1439 // vim:ts=3:expandtab
1440 
1441