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(®ex, 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, ®ex, 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