1 /**************************************************************************
2  **
3  ** sngrep - SIP Messages flow viewer
4  **
5  ** Copyright (C) 2013-2018 Ivan Alonso (Kaian)
6  ** Copyright (C) 2013-2018 Irontec SL. All rights reserved.
7  **
8  ** This program is free software: you can redistribute it and/or modify
9  ** it under the terms of the GNU General Public License as published by
10  ** the Free Software Foundation, either version 3 of the License, or
11  ** (at your option) any later version.
12  **
13  ** This program is distributed in the hope that it will be useful,
14  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  ** GNU General Public License for more details.
17  **
18  ** You should have received a copy of the GNU General Public License
19  ** along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  **
21  ****************************************************************************/
22 /**
23  * @file filter.c
24  * @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
25  *
26  * @brief Source code of functions defined in filter.h
27  *
28  */
29 #include <stdlib.h>
30 #include <string.h>
31 #include "sip.h"
32 #include "curses/ui_call_list.h"
33 #include "filter.h"
34 
35 //! Storage of filter information
36 filter_t filters[FILTER_COUNT] = { };
37 
38 int
filter_set(int type,const char * expr)39 filter_set(int type, const char *expr)
40 {
41 #ifdef WITH_PCRE
42     pcre *regex = NULL;
43 
44     // If we have an expression, check if compiles before changing the filter
45     if (expr) {
46         const char *re_err = NULL;
47         int32_t err_offset;
48         int32_t pcre_options = PCRE_UNGREEDY | PCRE_CASELESS;
49 
50         // Check if we have a valid expression
51         if (!(regex = pcre_compile(expr, pcre_options, &re_err, &err_offset, 0)))
52             return 1;
53     }
54 
55     // Remove previous value
56     if (filters[type].expr) {
57         sng_free(filters[type].expr);
58         pcre_free(filters[type].regex);
59     }
60 
61     // Set new expresion values
62     filters[type].expr = (expr) ? strdup(expr) : NULL;
63     filters[type].regex = regex;
64 
65 #else
66     regex_t regex;
67     // If we have an expression, check if compiles before changing the filter
68     if (expr) {
69         // Check if we have a valid expression
70         if (regcomp(&regex, expr, REG_EXTENDED | REG_ICASE) != 0)
71             return 1;
72     }
73 
74     // Remove previous value
75     if (filters[type].expr) {
76         sng_free(filters[type].expr);
77         regfree(&filters[type].regex);
78     }
79 
80     // Set new expresion values
81     filters[type].expr = (expr) ? strdup(expr) : NULL;
82     memcpy(&filters[type].regex, &regex, sizeof(regex));
83 #endif
84 
85     return 0;
86 }
87 
88 const char *
filter_get(int type)89 filter_get(int type)
90 {
91     return filters[type].expr;
92 }
93 
94 int
filter_check_call(void * item)95 filter_check_call(void *item)
96 {
97     int i;
98     char data[MAX_SIP_PAYLOAD];
99     sip_call_t *call = (sip_call_t*) item;
100     sip_msg_t *msg;
101     vector_iter_t it;
102 
103     // Dont filter calls without messages
104     if (call_msg_count(call) == 0)
105         return 0;
106 
107     // Filter for this call has already be processed
108     if (call->filtered != -1)
109         return (call->filtered == 0);
110 
111     // By default, call matches all filters
112     call->filtered = 0;
113 
114     // Check all filter types
115     for (i=0; i < FILTER_COUNT; i++) {
116         // If filter is not enabled, go to the next
117         if (!filters[i].expr)
118             continue;
119 
120         // Initialize
121         memset(data, 0, sizeof(data));
122 
123         // Get filtered field
124         switch(i) {
125             case FILTER_SIPFROM:
126                 call_get_attribute(call, SIP_ATTR_SIPFROM, data);
127                 break;
128             case FILTER_SIPTO:
129                 call_get_attribute(call, SIP_ATTR_SIPTO, data);
130                 break;
131             case FILTER_SOURCE:
132                 call_get_attribute(call, SIP_ATTR_SRC, data);
133                 break;
134             case FILTER_DESTINATION:
135                 call_get_attribute(call, SIP_ATTR_DST, data);
136                 break;
137             case FILTER_METHOD:
138                 call_get_attribute(call, SIP_ATTR_METHOD, data);
139                 break;
140             case FILTER_PAYLOAD:
141                 break;
142             case FILTER_CALL_LIST:
143                 // FIXME Maybe call should know hot to calculate this line
144                 call_list_line_text(ui_find_by_type(PANEL_CALL_LIST), call, data);
145                 break;
146             default:
147                 // Unknown filter id
148                 return 0;
149         }
150 
151         // For payload filtering, check all messages payload
152         if (i == FILTER_PAYLOAD) {
153             // Assume this call doesn't match the filter
154             call->filtered = 1;
155             // Create an iterator for the call messages
156             it = vector_iterator(call->msgs);
157             while ((msg = vector_iterator_next(&it))) {
158                 // Copy message payload
159                 strcpy(data, msg_get_payload(msg));
160                 // Check if this payload matches the filter
161                 if (filter_check_expr(filters[i], data) == 0) {
162                     call->filtered = 0;
163                     break;
164                 }
165             }
166             if (call->filtered == 1)
167                 break;
168         } else {
169             // Check the filter against given data
170             if (filter_check_expr(filters[i], data) != 0) {
171                 // The data didn't matched the filter
172                 call->filtered = 1;
173                 break;
174             }
175         }
176     }
177 
178     // Return the final filter status
179     return (call->filtered == 0);
180 }
181 
182 int
filter_check_expr(filter_t filter,const char * data)183 filter_check_expr(filter_t filter, const char *data)
184 {
185 #ifdef WITH_PCRE
186         return pcre_exec(filter.regex, 0, data, strlen(data), 0, 0, 0, 0);
187 #else
188         // Call doesn't match this filter
189         return regexec(&filter.regex, data, 0, NULL, 0);
190 #endif
191 }
192 
193 void
filter_reset_calls()194 filter_reset_calls()
195 {
196     sip_call_t *call;
197     vector_iter_t calls = sip_calls_iterator();
198 
199     // Force filter evaluation
200     while ((call = vector_iterator_next(&calls)))
201         call->filtered = -1;
202 }
203