1 /*
2     rate  --  statistic traffic analyzer
3     Copyright (C) 2003 Mateusz 'mteg' Golicz
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 #ifdef HAVE_REGEX
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #ifdef OPEN_BSD
27 #include <netinet/in_systm.h>
28 #endif
29 #include <netinet/in.h>
30 #include <netinet/ip.h>
31 #include <netinet/tcp.h>
32 #include <sys/timeb.h>
33 #include <signal.h>
34 #include <time.h>
35 #include <pcap.h>
36 #include "lib.h"
37 #ifdef HAVE_REGEX
38 #include <regex.h>
39 #endif
40 #include "iphash.h"
41 
42 static regex_t global_regex_c;
43 static char * regex_checking_buffer = NULL;
44 extern int opt_caplen;
45 
46 
unescape(char * string,int * length,unsigned char terminator)47 char* unescape(char *string, int *length, unsigned char terminator)
48 {
49 	char *out;
50 	char c, d, e;
51 	int i, k;
52 
53 	out = (char*) malloc(strlen(string)); k=0; /* in the worst case we'll need so much */
54 	for(i = 0; string[i] != 0; i++) /* foreach character in string */
55 	{
56 		if(string[i] == '\\') /* is it '\' ? */
57 		{
58 			c = string[i + 1]; /* get next character .. */
59 			if(!c) continue; /* if it's end of string, forget that */
60 			if(c == 'x') /* x - means hexadecimal code of character */
61 			{
62 				if((d = string[i + 2])) /* get first hex digit */
63 				{
64 					if((e = string[i + 3])) /* get second hex digit */
65 					{
66 						if(d >= 'a' && d <= 'f') d = d - 'a' + 10; else d -= '0';
67 						if(e >= 'a' && e <= 'f') e = e - 'a' + 10; else e -= '0';
68 						out[k++] = d << 4 | e; /* calculate character code and write into final string */
69 						i += 3; /* x<hex_digit><hex_digit> */
70 						continue;
71 					}
72 				}
73 			}
74 			if(c == 'n')
75 			{
76 				out[k++] = '\n';
77 				i += 1;
78 				continue;
79 			}
80 			if(c == 'r')
81 			{
82 				out[k++] = '\r';
83 				i += 1;
84 				continue;
85 			}
86 			if(c == 't')
87 			{
88 				out[k++] = '\t';
89 				i += 1;
90 				continue;
91 			}
92 			if(c == '\\')
93 			{
94 				out[k++] = c;
95 				i += 1;
96 				continue;
97 			}
98 			out[k++] = string[i];
99 			out[k++] = c;
100 			i += 1;
101 		}
102 		else
103 		{
104 			if(string[i] == terminator) break; /* we reached end of string */
105 			out[k++] = string[i]; /* add that end marker to final string */
106 		}
107 	}
108 	out[k] = 0;
109 	if(length) *length = i;
110 	return(out);
111 }
112 
113 
prepare_buffer(const char * data,int len,char nul_char)114 void prepare_buffer(const char * data, int len, char nul_char)
115 {
116 	int safe_len = (len > opt_caplen) ? opt_caplen : len;
117 	int i;
118 	for(i = 0; i<safe_len; i++)
119 	{
120 		char c;
121 		c = data[i];
122 		if(c == 0) c = nul_char;
123 		regex_checking_buffer[i] = c;
124 	}
125 	regex_checking_buffer[i] = 0;
126 }
127 
check_regex(const char * data,int len,char nul_char)128 int check_regex(const char * data, int len, char nul_char)
129 {
130 	prepare_buffer(data, len, nul_char);
131 	if(regexec(&global_regex_c, regex_checking_buffer, 0, NULL, 0) == 0)
132 		return(1);
133 	else
134 		return(0);
135 
136 }
prepare_regex(char * regex,int caplen)137 void prepare_regex(char *regex, int caplen)
138 {
139 	if(regex)
140 	{
141 		int rc;
142 
143 		regex = unescape(regex, NULL, 0);
144 		rc = regcomp(&global_regex_c, regex, REG_EXTENDED | REG_NOSUB);
145 		if(rc)
146 		{
147 			char errbuff[100];
148 			regerror(rc, &global_regex_c, errbuff, 100);
149 			fprintf(stderr, "regcomp('%s'): %s\n", regex, errbuff);
150 			exit(1);
151 		}
152 		regex_checking_buffer = (char*) malloc(caplen + 1);
153 		if(!regex_checking_buffer)
154 		{
155 			fprintf(stderr, "Unable to allocate regex checking buffer, out of memory?\n");
156 			exit(1);
157 		}
158 	}
159 }
160 
161 
162 
163 
164 static regex_t *global_extractor_c = NULL;
165 static char ** stringtab = NULL;
166 static int *lentab = NULL;
167 static int ext_count = 0;
168 
169 static char ** formattab = NULL;
170 static int * ordertab = NULL;
171 int ordercount = 0;
172 
173 
prepare_extractor(char * regex,char * order,int caplen)174 void prepare_extractor(char *regex, char * order, int caplen)
175 {
176 	int state = '(';
177 	char * pos, * nx;
178 
179 	nx = pos = regex = unescape(regex, NULL, 0);
180 
181 	for(; nx;)
182 	{
183 		char * part;
184 		int rc;
185 
186 		for(nx = index(pos, state); nx; nx = index(nx + 1, state))
187 			if(nx != regex)
188 			{
189 				if((nx - 1) != regex)
190 					if(*(nx - 2) == '\\') continue;
191 
192 				if(*(nx - 1) == '\\')
193 					break;
194 			}
195 
196 		if(nx)
197 		{
198 			*(nx - 1) = 0;
199 			*(nx++) = 0;
200 		}
201 
202 		if(state == '(')
203 			state = ')';
204 		else
205 			state = '(';
206 
207 		part = strdup(pos);
208 		global_extractor_c = (regex_t*) realloc(global_extractor_c, sizeof(regex_t) * (ext_count + 1));
209 		{
210 			rc = regcomp(&global_extractor_c[ext_count], part, REG_EXTENDED);
211 			if(rc)
212 			{
213 				char errbuff[100];
214 				regerror(rc, &global_extractor_c[ext_count], errbuff, 100);
215 				fprintf(stderr, "regcomp('%s'): %s\n", part, errbuff);
216 				exit(1);
217 			}
218 			ext_count++;
219 		}
220 		pos = nx;
221 	}
222 
223 	if(ext_count % 2 == 0)
224 	{
225 		fprintf(stderr, "Unmatched '(' or ')' (%d sub-expressions)\n", ext_count);
226 		exit(1);
227 	}
228 	if(!ext_count)
229 	{
230 		fprintf(stderr, "Empty extractor match regex.\n");
231 		exit(1);
232 	}
233 
234 	regex_checking_buffer = (char*) malloc(caplen + 1);
235 
236 	if(!regex_checking_buffer)
237 	{
238 		fprintf(stderr, "Unable to allocate regex checking buffer, out of memory?\n");
239 		exit(1);
240 	}
241 	stringtab = (char**) malloc(sizeof(char*) * ext_count);
242 	lentab = (int*) malloc(sizeof(int) * ext_count);
243 
244 	if(order)
245 	{
246 		nx = pos = order;
247 
248 		for(; nx;)
249 		{
250 			char * part;
251 
252 			nx = index(pos, '\\');
253 
254 			if(nx)
255 				*(nx++) = 0;
256 
257 			formattab = (char**) realloc(formattab, (ordercount + 1) * sizeof(char*));
258 			ordertab = (int*) realloc(ordertab, (ordercount + 1) * sizeof(int));
259 
260 			formattab[ordercount] = strdup(pos);
261 			if(nx)
262 			{
263 				if(*nx)
264 				{
265 					ordertab[ordercount] = *(nx) - '1';
266 					if(ordertab[ordercount] >= (ext_count / 2))
267 					{
268 						fprintf(stderr, "Reference %c in format string is invalid.\n", *nx);
269 						exit(1);
270 					}
271 					nx++;
272 					ordercount++;
273 				}
274 			}
275 			pos = nx;
276 		}
277 	}
278 }
279 
280 #define MAX_STRSIZE 512
281 
extractor(const char * data,int len,char nul_char,int showips)282 int extractor(const char * data, int len, char nul_char, int showips)
283 {
284 	regmatch_t match;
285 	int lastchar = -1;
286 	int i, j = 0;
287 	unsigned char strout[MAX_STRSIZE];
288 
289 
290 	prepare_buffer(data, len, nul_char);
291 	for(i = 0; i < ext_count; i++)
292 	{
293 		if(regexec(&global_extractor_c[i], regex_checking_buffer + ((lastchar > 0) ? (lastchar) : 0), 1, &match, 0) != 0) break;
294 
295 		if(i % 2 == 1)
296 		{
297 			stringtab[j] = regex_checking_buffer + lastchar + match.rm_so;
298 			lentab[j++] = match.rm_eo - match.rm_so + 1;
299 		}
300 
301 		if(lastchar < 0)
302 			lastchar = match.rm_eo;
303 		else
304 		{
305 			if(match.rm_so != 0) break;
306 			lastchar += match.rm_eo;
307 		}
308 	}
309 
310 	if(i == ext_count)
311 	{
312 		if(showips)
313 		{
314 			struct in_addr in;
315 			if(len >= sizeof(struct ip))
316 			{
317 				in = ((struct ip*) data)->ip_src;
318 				printf("%s => ", inet_ntoa(in));
319 				in = ((struct ip*) data)->ip_dst;
320 				printf("%s ", inet_ntoa(in));
321 			}
322 		}
323 		if(ordertab)
324 		{
325 			int oc;
326 			for(oc = 0; oc<ordercount; oc++)
327 			{
328 				int l, o;
329 				printf("%s", formattab[oc]);
330 				o = ordertab[oc];
331 
332 				l = lentab[o];
333 				if(l > (MAX_STRSIZE - 1)) l = MAX_STRSIZE - 1;
334 				snprintf(strout, l, "%s", stringtab[o]);
335 				printf("%s", strout);
336 			}
337 			printf("%s\n", formattab[oc]);
338 		}
339 		else
340 		{
341 			for(i = 0; i < j; i++)
342 			{
343 				int l = lentab[i];
344 				if(l > (MAX_STRSIZE - 1)) l = MAX_STRSIZE - 1;
345 				snprintf(strout, l, "%s", stringtab[i]);
346 				printf("%s ", strout);
347 			}
348 			printf("\n");
349 		}
350 	}
351 }
352 
353 #endif
354