gnutella.c 10.1 KB
Newer Older
1
2
3
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
's avatar
committed
4
5
6
7
8
#include <stdlib.h>
#include <stdio.h>
#include <sys/shm.h>
#include <string.h>
#include <errno.h>
's avatar
committed
9

's avatar
committed
10
11
12
13
14
15
16
17
#include "mapidflib.h"
#include "mapidlib.h"
#include "mapidevices.h"
#include "mapid.h"
#include "fhelp.h"
#include "debug.h"
#include "mapiipc.h"
#include "mstring.h"
18
19
20
#include "acsmx2.h"
#include "mapi_errors.h"

's avatar
committed
21
#include <pcap.h>
's avatar
committed
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <netinet/in.h>
#include <net/ethernet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>

#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <time.h>

's avatar
committed
42
#include "log.h"
43
#include "trackflib.h"
's avatar
committed
44

's avatar
committed
45
46
47
48
49
50
struct filters {
	int protocol;
	unsigned int saddr;
	unsigned int daddr;
	uint16_t sp;
	uint16_t dp;
's avatar
committed
51
	struct timeval ts;
's avatar
committed
52
53
54
55
56
57
58
59
	struct filters *next;
};

struct list{
	struct filters *head;
	struct filters *tail;
};

60
#define GNUTELLA_STRING_NO 4
's avatar
committed
61

62
char *gnutella_strings[GNUTELLA_STRING_NO]={"GET /uri-res/N2R?urn:sha1:","GNUTELLA CONNECT/","GNUTELLA/", "Server: LimeWire/"};//,"GET /get/"};
's avatar
committed
63

64
struct mapid_gnutella {
65
#ifndef __WITH_AHO__
66
67
	int *shift[GNUTELLA_STRING_NO];
	int *skip[GNUTELLA_STRING_NO];
68
69
70
#else
	ACSM_STRUCT2 *acsm;
#endif 
's avatar
committed
71
	struct list **gnulist;
's avatar
committed
72
73
};

's avatar
committed
74
int isGnutella(mapidflib_function_instance_t *,  unsigned char *, unsigned int );
75

76
static int gnutella_init(mapidflib_function_instance_t *instance, MAPI_UNUSED int fd)
's avatar
committed
77
{
78
	int i=0;
79
80
81
#ifdef __WITH_AHO__
	char *p;
#endif
's avatar
committed
82

's avatar
committed
83
	instance->internal_data = malloc(sizeof(struct mapid_gnutella));
's avatar
committed
84
85
86
87
88
89
90
	((struct mapid_gnutella*)instance->internal_data)->gnulist = (struct list**)malloc(sizeof(struct list *)*HASHTABLESIZE);
	memset(((struct mapid_gnutella*)instance->internal_data)->gnulist, 0, (sizeof(struct list*)*HASHTABLESIZE));
	for(i = 0; i < HASHTABLESIZE; i ++) {
		((struct mapid_gnutella*)instance->internal_data)->gnulist[i] = (struct list*)malloc(sizeof(struct list));
		((struct mapid_gnutella*)instance->internal_data)->gnulist[i]->head = NULL;
		((struct mapid_gnutella*)instance->internal_data)->gnulist[i]->tail = NULL;
	}
91
#ifndef __WITH_AHO__
92
	for(i=0;i<GNUTELLA_STRING_NO;i++) {
93
94
95
		((struct mapid_gnutella*)instance->internal_data)->shift[i] = make_shift(gnutella_strings[i],strlen(gnutella_strings[i]));
		((struct mapid_gnutella*)instance->internal_data)->skip[i] = make_skip(gnutella_strings[i], strlen(gnutella_strings[i]));
	}
96
97
98
99
100
101
102
103
104
105
106
#else 
	((struct mapid_gnutella*)instance->internal_data)->acsm = acsmNew2();

	if(!(((struct mapid_gnutella*)instance->internal_data)->acsm)) {
		return MAPID_MEM_ALLOCATION_ERROR;
	}
	for(i = 0; i < GNUTELLA_STRING_NO; i++) {
		p = gnutella_strings[i];

		acsmAddPattern2(((struct mapid_gnutella*)instance->internal_data)->acsm, p, strlen(p), 1, 0, 100,(void*)p, i);
	}
's avatar
committed
107

108
109
	acsmCompile2(((struct mapid_gnutella*)instance->internal_data)->acsm);
#endif
's avatar
committed
110
111
112
	return 0;
}	

113
114
115
116
117
118
119
120
121
122
123
124
125
126
#ifdef __WITH_AHO__

static int global_index = -1;
static char *found = NULL;

	int gnutella_matchFound(void* id, int my_index, MAPI_UNUSED void *data) 
	{
  		global_index = my_index;
		found = (char *)id;

		return my_index;
	}
#endif

's avatar
committed
127
int isGnutella(mapidflib_function_instance_t *instance, unsigned char *pkt, unsigned int len)
's avatar
committed
128
{
129
#ifndef __WITH_AHO__
130
	int i=0;
131

132
	for(i=0;i<GNUTELLA_STRING_NO;i++) {
's avatar
committed
133
134
		if(len < strlen(gnutella_strings[i]))
				continue;
's avatar
committed
135

's avatar
committed
136
137
		if(len < 100) {
			if(mSearch((char *)(pkt), len, gnutella_strings[i], strlen(gnutella_strings[i]),
138
				((struct mapid_gnutella *)instance->internal_data)->skip[i],
's avatar
committed
139
140
141
142
143
144
145
146
147
148
				((struct mapid_gnutella *)instance->internal_data)->shift[i])) {
				return i;
			}
		}
		else {
			if(mSearch((char *)(pkt), 100, gnutella_strings[i], strlen(gnutella_strings[i]),
				((struct mapid_gnutella *)instance->internal_data)->skip[i],
				((struct mapid_gnutella *)instance->internal_data)->shift[i])){
				return i;
			}
149
150
		}
	}
151
152
153
154
155
156
157
158
159
160
161

#else
	global_index = -1;
	found = NULL;

	acsmSearch2(((struct mapid_gnutella*)instance->internal_data)->acsm, pkt, len, gnutella_matchFound, (void *)0);
	
	return global_index;

#endif
	
's avatar
committed
162
	return -1;
's avatar
committed
163
164
165
166

}

static int gnutella_process(mapidflib_function_instance_t *instance,
's avatar
committed
167
168
			MAPI_UNUSED  unsigned char* dev_pkt,
			 unsigned char* pkt,
's avatar
committed
169
170
171
172
			mapid_pkthdr_t* pkt_head)
{
	struct filters *temp = NULL, *prev = NULL, *new = NULL;
	int len = pkt_head->caplen;
's avatar
committed
173
	 unsigned char *p = NULL;
's avatar
committed
174
175
	struct timeval ts;

's avatar
committed
176
	struct list **gnulist = ((struct mapid_gnutella*)instance->internal_data)->gnulist;
's avatar
committed
177
178
	uint16_t ethertype;
	struct ether_header *ep = NULL;
's avatar
committed
179
180
181
182
	struct pos_header {
		uint16_t af;
		uint16_t cf;
	}	*pp = NULL;
's avatar
committed
183
184
185
186
	struct iphdr *iph = NULL;
	struct tcphdr *tcph = NULL;
	struct udphdr *udph = NULL;
	
's avatar
committed
187
188
	struct vlan_802q_header *vlan_header;

's avatar
committed
189
	unsigned int saddr, daddr;
's avatar
committed
190
191
	struct in_addr source, dest;

's avatar
committed
192
193
	uint16_t sp, dp;

's avatar
committed
194
	unsigned int hashval = 0;
's avatar
committed
195
	int i = 0;
196
197
198
199

	int pkt_color = pkt_head->color;

	if(pkt_color != 0 && pkt_color != GNUTELLA_COLOR) {
200
201
202
		return 0;
	}

's avatar
committed
203
204
	p = pkt;

's avatar
committed
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
	switch(instance->hwinfo->link_type) {
		case DLT_EN10MB:
				// lay the Ethernet header struct over the packet data
				ep = (struct ether_header *)p;

				// skip ethernet header
				p += sizeof(struct ether_header);
				len -= sizeof(struct ether_header);

				ethertype = ntohs(ep->ether_type);

				if(ethertype  == ETHERTYPE_8021Q) {
					vlan_header = (struct vlan_802q_header*)p;
					ethertype = ntohs(vlan_header->ether_type);
					p += sizeof(struct vlan_802q_header);
				}
				
				if(ethertype == MPLS_MASK) {
					p += 4;			
				}
				else if(ethertype != ETHERTYPE_IP) {
					return 0;
				}
			break;
		case DLT_CHDLC:
				pp = (struct pos_header *)p;

				p += sizeof(struct pos_header);
				len -= sizeof(struct pos_header);

				ethertype = ntohs(pp->cf);

				if (ethertype != ETHERTYPE_IP) {
					return 0;
				}
			break;
		default:
			//DEBUG_CMD(Debug_Message("Link layer not supported"));
			return 0;
's avatar
committed
244
245
246
247
248
249
250
	}
	
	// IP header struct over the packet data;
	iph = (struct iphdr*)p;

	saddr = *((unsigned int *)&(iph->saddr));
	daddr = *((unsigned int *)&(iph->daddr));
's avatar
committed
251
252
253
254
255

	source.s_addr = (unsigned long int)iph->saddr;
	dest.s_addr = (unsigned long int)iph->daddr;

	hashval = (saddr + daddr) % HASHTABLESIZE;
's avatar
committed
256

's avatar
committed
257
	p += iph->ihl * 4;
's avatar
committed
258
259
	len -= iph->ihl * 4;

's avatar
committed
260
261
262
263
264
265
	if(iph->protocol == 6)	// TCP
	{
		tcph = (struct tcphdr *)p;
		
		sp = ntohs(tcph->source);
		dp = ntohs(tcph->dest);
's avatar
committed
266
267
268

		p += tcph->doff * 4;

's avatar
committed
269
		if((unsigned int)(p - pkt) == pkt_head->caplen) {
's avatar
committed
270
271
272
			return 0;
		}
		len -= tcph->doff * 4;
's avatar
committed
273
274
275
276
277
278
279
	}
	else if(iph->protocol == 17)	// UDP
	{
		udph = (struct udphdr *)p;

		sp = ntohs(udph->source);
		dp = ntohs(udph->dest);
's avatar
committed
280
281
282

		p += sizeof(struct udphdr);
		
's avatar
committed
283
		if((unsigned int)(p -pkt) == pkt_head->caplen) {
's avatar
committed
284
285
286
			return 0;
		}
		len -= sizeof(struct udphdr);
's avatar
committed
287
288
289
290
291
292
	}
	else
	{
		return 0;
	}

's avatar
committed
293
294
	gettimeofday(&ts, NULL);

's avatar
committed
295
	for(temp = gnulist[hashval]->head, prev = gnulist[hashval]->head; temp != NULL; prev = temp, temp = temp->next)
296
297
298
299
300
301
302
303
	{
		if(temp->protocol == iph->protocol &&
				(
				 (temp->saddr == saddr && temp->daddr == daddr && temp->sp == sp && temp->dp == dp)
				 ||
				 (temp->saddr == daddr && temp->daddr == saddr && temp->sp == dp && temp->dp == sp))
				)
		{
's avatar
committed
304
305
				gettimeofday(&(temp->ts), NULL);

's avatar
committed
306
				if(iph->protocol == 6 && tcph->fin)	{
's avatar
committed
307
308
					if(temp == gnulist[hashval]->head) {
						gnulist[hashval]->head = temp->next;
's avatar
committed
309
310
311
312
					}
					else {
						prev->next = temp->next;
					}
313
314
315
					temp->next = NULL;
					free(temp);
				}
's avatar
committed
316
					
317
			pkt_head->color = GNUTELLA_COLOR;
318
319
			return 1;
		}
's avatar
committed
320
321
		
		if(ts.tv_sec - temp->ts.tv_sec > 60) {
's avatar
committed
322
323
			if(temp == gnulist[hashval]->head) {
				gnulist[hashval]->head = temp->next;
's avatar
committed
324
325
326
327
328
329
330
			}
			else {
				prev->next = temp->next;
			}
			temp->next = NULL;
			free(temp);
		}
331
332
	}

's avatar
committed
333
	if((i = isGnutella(instance,pkt,len)) >= 0)
's avatar
committed
334
	{
335
336
		new = (struct filters*)malloc(sizeof(struct filters));
		if(new == NULL)
337
			DEBUG_CMD(Debug_Message("new = NULL (malloc failed)"));
338
		
's avatar
committed
339
340
341
342
343
344
		new->protocol = iph->protocol;
		new->saddr = saddr;
		new->daddr = daddr;
		new->sp = sp;
		new->dp = dp;

345
#ifdef __TRACKFLIB_LOGGING__
346
	#ifndef __WITH_AHO__
's avatar
committed
347
		write_to_log("GNUTELLA", gnutella_strings[i], iph->protocol, source, sp, dest, dp, pkt, len); 
348
349
350
	#else
		write_to_log("GNUTELLA", found, iph->protocol, source, sp, dest, dp, pkt, len); 
	#endif
351
#endif
's avatar
committed
352
		for(temp = gnulist[hashval]->head; temp != NULL; temp = temp->next)
's avatar
committed
353
354
355
356
357
358
359
360
		{
			if(new->protocol == temp->protocol && (
					(new->saddr == temp->saddr && new->daddr == temp->daddr && new->sp == temp->sp && new->dp == temp->dp) 
					||
					(new->daddr == temp->saddr && new->saddr == temp->daddr && new->dp == temp->sp && new->sp == temp->dp)
					)
				)
			{
361
				pkt_head->color = GNUTELLA_COLOR;
's avatar
committed
362
363
364
365
				return 1;
			}
		}

's avatar
committed
366
367
		gettimeofday(&(new->ts), NULL);

's avatar
committed
368
369
		new->next = gnulist[hashval]->head;
		gnulist[hashval]->head = new;
370
371
	
		pkt_head->color = GNUTELLA_COLOR;
's avatar
committed
372
373
374
375
376
377
378
379
380
		return 1;
	}

	return 0;
}

static int gnutella_cleanup(mapidflib_function_instance_t *instance) 
{
	struct filters *temp = NULL, *tmp = NULL;
's avatar
committed
381
382
	int i = 0;

's avatar
committed
383
384
  if(instance->internal_data != NULL){

's avatar
committed
385
386
387
388
389
390
391
392
	  for(i = 0; i < HASHTABLESIZE; i++) {
		  temp = ((struct mapid_gnutella*)instance->internal_data)->gnulist[i]->head;
		  
		  while(temp != NULL) {
			  tmp = temp;
			  temp = temp->next;
			  free(tmp);
		  }
393
		  free(((struct mapid_gnutella*)instance->internal_data)->gnulist[i]);
's avatar
committed
394
	  }
395
396
397
398
399
400
401
402
#ifndef __WITH_AHO__
        for(i=0;i<GNUTELLA_STRING_NO;i++) {
                free(((struct mapid_gnutella*)instance->internal_data)->shift[i]);
                free(((struct mapid_gnutella*)instance->internal_data)->skip[i]);
        }
#else
        acsmFree2(((struct mapid_gnutella*)instance->internal_data)->acsm);
#endif
's avatar
committed
403

's avatar
committed
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
	free(((struct mapid_gnutella*)instance->internal_data)->gnulist);
	free(instance->internal_data);
  }
  return 0;
}

static mapidflib_function_def_t finfo={
  "",
  "TRACK_GNUTELLA",
  "Searches for Gnutella packets\n",
  "",
  MAPI_DEVICE_ALL,
  MAPIRES_NONE,
  0, //shm size
  0, //modifies_pkts
419
420
  1, //filters packets
  MAPIOPT_NONE,
's avatar
committed
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
  NULL,
  gnutella_init,
  gnutella_process,
  NULL, //get_result
  NULL, //reset
  gnutella_cleanup,
  NULL, //client_init
  NULL, //client_read_result
  NULL  //client_cleanup
};

mapidflib_function_def_t* gnutella_get_funct_info();
mapidflib_function_def_t* gnutella_get_funct_info() {
  return &finfo;
};