1 /*
2 Copyright (c) 1999 Rafal Wojtczuk <nergal@7bulls.com>. All rights reserved.
3 See the file COPYING for license details.
4 */
5
6 #include <config.h>
7 #include <sys/types.h>
8 #include <netinet/in.h>
9 #include <netinet/in_systm.h>
10 #include <netinet/ip.h>
11 #include <netinet/tcp.h>
12 #include <netinet/udp.h>
13 #include <arpa/inet.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <syslog.h>
17 #include <pcap.h>
18 #include <errno.h>
19 #include <config.h>
20 #if (HAVE_UNISTD_H)
21 #include <unistd.h>
22 #endif
23 #include <stdlib.h>
24 #include "checksum.h"
25 #include "ip_fragment.h"
26 #include "scan.h"
27 #include "tcp.h"
28 #include "util.h"
29 #include "nids.h"
30 #ifdef HAVE_LIBGTHREAD_2_0
31 #include <glib.h>
32 #endif
33
34 #ifdef __linux__
35 extern int set_all_promisc();
36 #endif
37
38 #define int_ntoa(x) inet_ntoa(*((struct in_addr *)&x))
39 extern int ip_options_compile(unsigned char *);
40 extern int raw_init();
41 static void nids_syslog(int, int, struct ip *, void *);
42 static int nids_ip_filter(struct ip *, int);
43
44 static struct proc_node *ip_frag_procs;
45 static struct proc_node *ip_procs;
46 static struct proc_node *udp_procs;
47
48 struct proc_node *tcp_procs;
49 static int linktype;
50 static pcap_t *desc = NULL;
51
52 #ifdef HAVE_LIBGTHREAD_2_0
53
54 /* async queue for multiprocessing - mcree */
55 static GAsyncQueue *cap_queue;
56
57 /* items in the queue */
58 struct cap_queue_item {
59 void *data;
60 bpf_u_int32 caplen;
61 };
62
63 /* marks end of queue */
64 static struct cap_queue_item EOF_item;
65
66 /* error buffer for glib calls */
67 static GError *gerror = NULL;
68
69 #endif
70
71 char nids_errbuf[PCAP_ERRBUF_SIZE];
72 struct pcap_pkthdr * nids_last_pcap_header = NULL;
73 u_char *nids_last_pcap_data = NULL;
74 u_int nids_linkoffset = 0;
75
76 char *nids_warnings[] = {
77 "Murphy - you never should see this message !",
78 "Oversized IP packet",
79 "Invalid IP fragment list: fragment over size",
80 "Overlapping IP fragments",
81 "Invalid IP header",
82 "Source routed IP frame",
83 "Max number of TCP streams reached",
84 "Invalid TCP header",
85 "Too much data in TCP receive queue",
86 "Invalid TCP flags"
87 };
88
89 struct nids_prm nids_params = {
90 1040, /* n_tcp_streams */
91 256, /* n_hosts */
92 NULL, /* device */
93 NULL, /* filename */
94 168, /* sk_buff_size */
95 -1, /* dev_addon */
96 nids_syslog, /* syslog() */
97 LOG_ALERT, /* syslog_level */
98 256, /* scan_num_hosts */
99 3000, /* scan_delay */
100 10, /* scan_num_ports */
101 nids_no_mem, /* no_mem() */
102 nids_ip_filter, /* ip_filter() */
103 NULL, /* pcap_filter */
104 1, /* promisc */
105 0, /* one_loop_less */
106 1024, /* pcap_timeout */
107 0, /* multiproc */
108 20000, /* queue_limit */
109 0, /* tcp_workarounds */
110 NULL /* pcap_desc */
111 };
112
nids_ip_filter(struct ip * x,int len)113 static int nids_ip_filter(struct ip *x, int len)
114 {
115 (void)x;
116 (void)len;
117 return 1;
118 }
119
nids_syslog(int type,int errnum,struct ip * iph,void * data)120 static void nids_syslog(int type, int errnum, struct ip *iph, void *data)
121 {
122 char saddr[20], daddr[20];
123 char buf[1024];
124 struct host *this_host;
125 unsigned char flagsand = 255, flagsor = 0;
126 int i;
127
128 switch (type) {
129
130 case NIDS_WARN_IP:
131 if (errnum != NIDS_WARN_IP_HDR) {
132 strcpy(saddr, int_ntoa(iph->ip_src.s_addr));
133 strcpy(daddr, int_ntoa(iph->ip_dst.s_addr));
134 syslog(nids_params.syslog_level,
135 "%s, packet (apparently) from %s to %s\n",
136 nids_warnings[errnum], saddr, daddr);
137 } else
138 syslog(nids_params.syslog_level, "%s\n",
139 nids_warnings[errnum]);
140 break;
141
142 case NIDS_WARN_TCP:
143 strcpy(saddr, int_ntoa(iph->ip_src.s_addr));
144 strcpy(daddr, int_ntoa(iph->ip_dst.s_addr));
145 if (errnum != NIDS_WARN_TCP_HDR)
146 syslog(nids_params.syslog_level,
147 "%s,from %s:%hu to %s:%hu\n", nids_warnings[errnum],
148 saddr, ntohs(((struct tcphdr *) data)->th_sport), daddr,
149 ntohs(((struct tcphdr *) data)->th_dport));
150 else
151 syslog(nids_params.syslog_level, "%s,from %s to %s\n",
152 nids_warnings[errnum], saddr, daddr);
153 break;
154
155 case NIDS_WARN_SCAN:
156 this_host = (struct host *) data;
157 sprintf(buf, "Scan from %s. Scanned ports: ",
158 int_ntoa(this_host->addr));
159 for (i = 0; i < this_host->n_packets; i++) {
160 strcat(buf, int_ntoa(this_host->packets[i].addr));
161 sprintf(buf + strlen(buf), ":%hu,",
162 this_host->packets[i].port);
163 flagsand &= this_host->packets[i].flags;
164 flagsor |= this_host->packets[i].flags;
165 }
166 if (flagsand == flagsor) {
167 i = flagsand;
168 switch (flagsand) {
169 case 2:
170 strcat(buf, "scan type: SYN");
171 break;
172 case 0:
173 strcat(buf, "scan type: NULL");
174 break;
175 case 1:
176 strcat(buf, "scan type: FIN");
177 break;
178 default:
179 sprintf(buf + strlen(buf), "flags=0x%x", i);
180 }
181 } else
182 strcat(buf, "various flags");
183 syslog(nids_params.syslog_level, "%s", buf);
184 break;
185
186 default:
187 syslog(nids_params.syslog_level, "Unknown warning number ?\n");
188 }
189 }
190
191 /* called either directly from pcap_hand() or from cap_queue_process_thread()
192 * depending on the value of nids_params.multiproc - mcree
193 */
call_ip_frag_procs(void * data,bpf_u_int32 caplen)194 static void call_ip_frag_procs(void *data,bpf_u_int32 caplen)
195 {
196 struct proc_node *i;
197 for (i = ip_frag_procs; i; i = i->next)
198 (i->item) (data, caplen);
199 }
200
201
202 /* wireless frame types, mostly from tcpdump (wam) */
203 #define FC_TYPE(fc) (((fc) >> 2) & 0x3)
204 #define FC_SUBTYPE(fc) (((fc) >> 4) & 0xF)
205 #define DATA_FRAME_IS_QOS(x) ((x) & 0x08)
206 #define FC_WEP(fc) ((fc) & 0x4000)
207 #define FC_TO_DS(fc) ((fc) & 0x0100)
208 #define FC_FROM_DS(fc) ((fc) & 0x0200)
209 #define T_MGMT 0x0 /* management */
210 #define T_CTRL 0x1 /* control */
211 #define T_DATA 0x2 /* data */
212 #define T_RESV 0x3 /* reserved */
213 #define EXTRACT_LE_16BITS(p) \
214 ((unsigned short)*((const unsigned char *)(p) + 1) << 8 | \
215 (unsigned short)*((const unsigned char *)(p) + 0))
216 #define EXTRACT_16BITS(p) ((unsigned short)ntohs(*(const unsigned short *)(p)))
217 #define LLC_FRAME_SIZE 8
218 #define LLC_OFFSET_TO_TYPE_FIELD 6
219 #define ETHERTYPE_IP 0x0800
220
nids_pcap_handler(u_char * par,struct pcap_pkthdr * hdr,u_char * data)221 void nids_pcap_handler(u_char * par, struct pcap_pkthdr *hdr, u_char * data)
222 {
223 u_char *data_aligned;
224 #ifdef HAVE_LIBGTHREAD_2_0
225 struct cap_queue_item *qitem;
226 #endif
227 #ifdef DLT_IEEE802_11
228 unsigned short fc;
229 int linkoffset_tweaked_by_prism_code = 0;
230 int linkoffset_tweaked_by_radio_code = 0;
231 #endif
232
233 /*
234 * Check for savagely closed TCP connections. Might
235 * happen only when nids_params.tcp_workarounds is non-zero;
236 * otherwise nids_tcp_timeouts is always NULL.
237 */
238 if (NULL != nids_tcp_timeouts)
239 tcp_check_timeouts(&hdr->ts);
240
241 nids_last_pcap_header = hdr;
242 nids_last_pcap_data = data;
243 (void)par; /* warnings... */
244 switch (linktype) {
245 case DLT_EN10MB:
246 if (hdr->caplen < 14)
247 return;
248 /* Only handle IP packets and 802.1Q VLAN tagged packets below. */
249 if (data[12] == 8 && data[13] == 0) {
250 /* Regular ethernet */
251 nids_linkoffset = 14;
252 } else if (data[12] == 0x81 && data[13] == 0) {
253 /* Skip 802.1Q VLAN and priority information */
254 nids_linkoffset = 18;
255 } else
256 /* non-ip frame */
257 return;
258 break;
259 #ifdef DLT_PRISM_HEADER
260 #ifndef DLT_IEEE802_11
261 #error DLT_PRISM_HEADER is defined, but DLT_IEEE802_11 is not ???
262 #endif
263 case DLT_PRISM_HEADER:
264 nids_linkoffset = 144; //sizeof(prism2_hdr);
265 linkoffset_tweaked_by_prism_code = 1;
266 //now let DLT_IEEE802_11 do the rest
267 #endif
268 #ifdef DLT_IEEE802_11_RADIO
269 case DLT_IEEE802_11_RADIO:
270 // just get rid of the radio tap header
271 if (!linkoffset_tweaked_by_prism_code) {
272 nids_linkoffset = EXTRACT_LE_16BITS(data + 2); // skip radiotap header
273 linkoffset_tweaked_by_radio_code = 1;
274 }
275 //now let DLT_IEEE802_11 do the rest
276 #endif
277 #ifdef DLT_IEEE802_11
278 case DLT_IEEE802_11:
279 /* I don't know why frame control is always little endian, but it
280 * works for tcpdump, so who am I to complain? (wam)
281 */
282 if (!linkoffset_tweaked_by_prism_code && !linkoffset_tweaked_by_radio_code)
283 nids_linkoffset = 0;
284 fc = EXTRACT_LE_16BITS(data + nids_linkoffset);
285 if (FC_TYPE(fc) != T_DATA || FC_WEP(fc)) {
286 return;
287 }
288 if (FC_TO_DS(fc) && FC_FROM_DS(fc)) {
289 /* a wireless distribution system packet will have another
290 * MAC addr in the frame
291 */
292 nids_linkoffset += 30;
293 } else {
294 nids_linkoffset += 24;
295 }
296 if (DATA_FRAME_IS_QOS(FC_SUBTYPE(fc)))
297 nids_linkoffset += 2;
298 if (hdr->len < nids_linkoffset + LLC_FRAME_SIZE)
299 return;
300 if (ETHERTYPE_IP !=
301 EXTRACT_16BITS(data + nids_linkoffset + LLC_OFFSET_TO_TYPE_FIELD)) {
302 /* EAP, LEAP, and other 802.11 enhancements can be
303 * encapsulated within a data packet too. Look only at
304 * encapsulated IP packets (Type field of the LLC frame).
305 */
306 return;
307 }
308 nids_linkoffset += LLC_FRAME_SIZE;
309 break;
310 #endif
311 default:;
312 }
313 if (hdr->caplen < nids_linkoffset)
314 return;
315
316 /*
317 * sure, memcpy costs. But many EXTRACT_{SHORT, LONG} macros cost, too.
318 * Anyway, libpcap tries to ensure proper layer 3 alignment (look for
319 * handle->offset in pcap sources), so memcpy should not be called.
320 */
321 #ifdef LBL_ALIGN
322 if ((unsigned long) (data + nids_linkoffset) & 0x3) {
323 data_aligned = alloca(hdr->caplen - nids_linkoffset + 4);
324 data_aligned -= (unsigned long) data_aligned % 4;
325 memcpy(data_aligned, data + nids_linkoffset, hdr->caplen - nids_linkoffset);
326 } else
327 #endif
328 data_aligned = data + nids_linkoffset;
329
330 #ifdef HAVE_LIBGTHREAD_2_0
331 if(nids_params.multiproc) {
332 /*
333 * Insert received fragment into the async capture queue.
334 * We hope that the overhead of memcpy
335 * will be saturated by the benefits of SMP - mcree
336 */
337 qitem=malloc(sizeof(struct cap_queue_item));
338 if (qitem && (qitem->data=malloc(hdr->caplen - nids_linkoffset))) {
339 qitem->caplen=hdr->caplen - nids_linkoffset;
340 memcpy(qitem->data,data_aligned,qitem->caplen);
341 g_async_queue_lock(cap_queue);
342 /* ensure queue does not overflow */
343 if(g_async_queue_length_unlocked(cap_queue) > nids_params.queue_limit) {
344 /* queue limit reached: drop packet - should we notify user via syslog? */
345 free(qitem->data);
346 free(qitem);
347 } else {
348 /* insert packet to queue */
349 g_async_queue_push_unlocked(cap_queue,qitem);
350 }
351 g_async_queue_unlock(cap_queue);
352 }
353 } else { /* user requested simple passthru - no threading */
354 call_ip_frag_procs(data_aligned,hdr->caplen - nids_linkoffset);
355 }
356 #else
357 call_ip_frag_procs(data_aligned,hdr->caplen - nids_linkoffset);
358 #endif
359 }
360
gen_ip_frag_proc(u_char * data,int len)361 static void gen_ip_frag_proc(u_char * data, int len)
362 {
363 struct proc_node *i;
364 struct ip *iph = (struct ip *) data;
365 int need_free = 0;
366 int skblen;
367 void (*glibc_syslog_h_workaround)(int, int, struct ip *, void*)=
368 nids_params.syslog;
369
370 if (!nids_params.ip_filter(iph, len))
371 return;
372
373 if (len < (int)sizeof(struct ip) || iph->ip_hl < 5 || iph->ip_v != 4 ||
374 ip_fast_csum((unsigned char *) iph, iph->ip_hl) != 0 ||
375 len < ntohs(iph->ip_len) || ntohs(iph->ip_len) < iph->ip_hl << 2) {
376 glibc_syslog_h_workaround(NIDS_WARN_IP, NIDS_WARN_IP_HDR, iph, 0);
377 return;
378 }
379 if (iph->ip_hl > 5 && ip_options_compile((unsigned char *)data)) {
380 glibc_syslog_h_workaround(NIDS_WARN_IP, NIDS_WARN_IP_SRR, iph, 0);
381 return;
382 }
383 switch (ip_defrag_stub((struct ip *) data, &iph)) {
384 case IPF_ISF:
385 return;
386 case IPF_NOTF:
387 need_free = 0;
388 iph = (struct ip *) data;
389 break;
390 case IPF_NEW:
391 need_free = 1;
392 break;
393 default:;
394 }
395 skblen = ntohs(iph->ip_len) + 16;
396 if (!need_free)
397 skblen += nids_params.dev_addon;
398 skblen = (skblen + 15) & ~15;
399 skblen += nids_params.sk_buff_size;
400
401 for (i = ip_procs; i; i = i->next)
402 (i->item) (iph, skblen);
403 if (need_free)
404 free(iph);
405 }
406
407 #if HAVE_BSD_UDPHDR
408 #define UH_ULEN uh_ulen
409 #define UH_SPORT uh_sport
410 #define UH_DPORT uh_dport
411 #else
412 #define UH_ULEN len
413 #define UH_SPORT source
414 #define UH_DPORT dest
415 #endif
416
process_udp(char * data)417 static void process_udp(char *data)
418 {
419 struct proc_node *ipp = udp_procs;
420 struct ip *iph = (struct ip *) data;
421 struct udphdr *udph;
422 struct tuple4 addr;
423 int hlen = iph->ip_hl << 2;
424 int len = ntohs(iph->ip_len);
425 int ulen;
426 if (len - hlen < (int)sizeof(struct udphdr))
427 return;
428 udph = (struct udphdr *) (data + hlen);
429 ulen = ntohs(udph->UH_ULEN);
430 if (len - hlen < ulen || ulen < (int)sizeof(struct udphdr))
431 return;
432 /* According to RFC768 a checksum of 0 is not an error (Sebastien Raveau) */
433 if (udph->uh_sum && my_udp_check
434 ((void *) udph, ulen, iph->ip_src.s_addr,
435 iph->ip_dst.s_addr)) return;
436 addr.source = ntohs(udph->UH_SPORT);
437 addr.dest = ntohs(udph->UH_DPORT);
438 addr.saddr = iph->ip_src.s_addr;
439 addr.daddr = iph->ip_dst.s_addr;
440 while (ipp) {
441 ipp->item(&addr, ((char *) udph) + sizeof(struct udphdr),
442 ulen - sizeof(struct udphdr), data);
443 ipp = ipp->next;
444 }
445 }
gen_ip_proc(u_char * data,int skblen)446 static void gen_ip_proc(u_char * data, int skblen)
447 {
448 switch (((struct ip *) data)->ip_p) {
449 case IPPROTO_TCP:
450 process_tcp(data, skblen);
451 break;
452 case IPPROTO_UDP:
453 process_udp((char *)data);
454 break;
455 case IPPROTO_ICMP:
456 if (nids_params.n_tcp_streams)
457 process_icmp(data);
458 break;
459 default:
460 break;
461 }
462 }
init_procs()463 static void init_procs()
464 {
465 ip_frag_procs = mknew(struct proc_node);
466 ip_frag_procs->item = gen_ip_frag_proc;
467 ip_frag_procs->next = 0;
468 ip_procs = mknew(struct proc_node);
469 ip_procs->item = gen_ip_proc;
470 ip_procs->next = 0;
471 tcp_procs = 0;
472 udp_procs = 0;
473 }
474
nids_register_udp(void (* x))475 void nids_register_udp(void (*x))
476 {
477 register_callback(&udp_procs, x);
478 }
479
nids_unregister_udp(void (* x))480 void nids_unregister_udp(void (*x))
481 {
482 unregister_callback(&udp_procs, x);
483 }
484
nids_register_ip(void (* x))485 void nids_register_ip(void (*x))
486 {
487 register_callback(&ip_procs, x);
488 }
489
nids_unregister_ip(void (* x))490 void nids_unregister_ip(void (*x))
491 {
492 unregister_callback(&ip_procs, x);
493 }
494
nids_register_ip_frag(void (* x))495 void nids_register_ip_frag(void (*x))
496 {
497 register_callback(&ip_frag_procs, x);
498 }
499
nids_unregister_ip_frag(void (* x))500 void nids_unregister_ip_frag(void (*x))
501 {
502 unregister_callback(&ip_frag_procs, x);
503 }
504
open_live()505 static int open_live()
506 {
507 char *device;
508 int promisc = 0;
509
510 if (nids_params.device == NULL)
511 nids_params.device = pcap_lookupdev(nids_errbuf);
512 if (nids_params.device == NULL)
513 return 0;
514
515 device = nids_params.device;
516 if (!strcmp(device, "all"))
517 device = "any";
518 else
519 promisc = (nids_params.promisc != 0);
520
521 if ((desc = pcap_open_live(device, 16384, promisc,
522 nids_params.pcap_timeout, nids_errbuf)) == NULL)
523 return 0;
524 #ifdef __linux__
525 if (!strcmp(device, "any") && nids_params.promisc
526 && !set_all_promisc()) {
527 nids_errbuf[0] = 0;
528 strncat(nids_errbuf, strerror(errno), sizeof(nids_errbuf) - 1);
529 return 0;
530 }
531 #endif
532 if (!raw_init()) {
533 nids_errbuf[0] = 0;
534 strncat(nids_errbuf, strerror(errno), sizeof(nids_errbuf) - 1);
535 return 0;
536 }
537 return 1;
538 }
539
540 #ifdef HAVE_LIBGTHREAD_2_0
541
542 #define START_CAP_QUEUE_PROCESS_THREAD() \
543 if(nids_params.multiproc) { /* threading... */ \
544 if(!(g_thread_create_full((GThreadFunc)cap_queue_process_thread,NULL,0,FALSE,TRUE,G_THREAD_PRIORITY_LOW,&gerror))) { \
545 strcpy(nids_errbuf, "thread: "); \
546 strncat(nids_errbuf, gerror->message, sizeof(nids_errbuf) - 8); \
547 return 0; \
548 }; \
549 }
550
551 #define STOP_CAP_QUEUE_PROCESS_THREAD() \
552 if(nids_params.multiproc) { /* stop the capture process thread */ \
553 g_async_queue_push(cap_queue,&EOF_item); \
554 }
555
556
557 /* thread entry point
558 * pops capture queue items and feeds them to
559 * the ip fragment processors - mcree
560 */
cap_queue_process_thread()561 static void cap_queue_process_thread()
562 {
563 struct cap_queue_item *qitem;
564
565 while(1) { /* loop "forever" */
566 qitem=g_async_queue_pop(cap_queue);
567 if (qitem==&EOF_item) break; /* EOF item received: we should exit */
568 call_ip_frag_procs(qitem->data,qitem->caplen);
569 free(qitem->data);
570 free(qitem);
571 }
572 g_thread_exit(NULL);
573 }
574
575 #else
576
577 #define START_CAP_QUEUE_PROCESS_THREAD()
578 #define STOP_CAP_QUEUE_PROCESS_THREAD()
579
580 #endif
581
nids_init()582 int nids_init()
583 {
584 /* free resources that previous usages might have allocated */
585 nids_exit();
586
587 if (nids_params.pcap_desc)
588 desc = nids_params.pcap_desc;
589 else if (nids_params.filename) {
590 if ((desc = pcap_open_offline(nids_params.filename,
591 nids_errbuf)) == NULL)
592 return 0;
593 } else if (!open_live())
594 return 0;
595
596 if (nids_params.pcap_filter != NULL) {
597 u_int mask = 0;
598 struct bpf_program fcode;
599
600 if (pcap_compile(desc, &fcode, nids_params.pcap_filter, 1, mask) <
601 0) return 0;
602 if (pcap_setfilter(desc, &fcode) == -1)
603 return 0;
604 }
605 switch ((linktype = pcap_datalink(desc))) {
606 #ifdef DLT_IEEE802_11
607 #ifdef DLT_PRISM_HEADER
608 case DLT_PRISM_HEADER:
609 #endif
610 #ifdef DLT_IEEE802_11_RADIO
611 case DLT_IEEE802_11_RADIO:
612 #endif
613 case DLT_IEEE802_11:
614 /* wireless, need to calculate offset per frame */
615 break;
616 #endif
617 #ifdef DLT_NULL
618 case DLT_NULL:
619 nids_linkoffset = 4;
620 break;
621 #endif
622 case DLT_EN10MB:
623 nids_linkoffset = 14;
624 break;
625 case DLT_PPP:
626 nids_linkoffset = 4;
627 break;
628 /* Token Ring Support by vacuum@technotronic.com, thanks dugsong! */
629 case DLT_IEEE802:
630 nids_linkoffset = 22;
631 break;
632
633 case DLT_RAW:
634 case DLT_SLIP:
635 nids_linkoffset = 0;
636 break;
637 #define DLT_LINUX_SLL 113
638 case DLT_LINUX_SLL:
639 nids_linkoffset = 16;
640 break;
641 #ifdef DLT_FDDI
642 case DLT_FDDI:
643 nids_linkoffset = 21;
644 break;
645 #endif
646 #ifdef DLT_PPP_SERIAL
647 case DLT_PPP_SERIAL:
648 nids_linkoffset = 4;
649 break;
650 #endif
651 default:
652 strcpy(nids_errbuf, "link type unknown");
653 return 0;
654 }
655 if (nids_params.dev_addon == -1) {
656 if (linktype == DLT_EN10MB)
657 nids_params.dev_addon = 16;
658 else
659 nids_params.dev_addon = 0;
660 }
661 if (nids_params.syslog == nids_syslog)
662 openlog("libnids", 0, LOG_LOCAL0);
663
664 init_procs();
665 tcp_init(nids_params.n_tcp_streams);
666 ip_frag_init(nids_params.n_hosts);
667 scan_init();
668
669 if(nids_params.multiproc) {
670 #ifdef HAVE_LIBGTHREAD_2_0
671 g_thread_init(NULL);
672 cap_queue=g_async_queue_new();
673 #else
674 strcpy(nids_errbuf, "libnids was compiled without threads support");
675 return 0;
676 #endif
677 }
678
679 return 1;
680 }
681
nids_run()682 int nids_run()
683 {
684 if (!desc) {
685 strcpy(nids_errbuf, "Libnids not initialized");
686 return 0;
687 }
688 START_CAP_QUEUE_PROCESS_THREAD(); /* threading... */
689 pcap_loop(desc, -1, (pcap_handler) nids_pcap_handler, 0);
690 /* FIXME: will this code ever be called? Don't think so - mcree */
691 STOP_CAP_QUEUE_PROCESS_THREAD();
692 nids_exit();
693 return 0;
694 }
695
nids_exit()696 void nids_exit()
697 {
698 if (!desc) {
699 strcpy(nids_errbuf, "Libnids not initialized");
700 return;
701 }
702 #ifdef HAVE_LIBGTHREAD_2_0
703 if (nids_params.multiproc) {
704 /* I have no portable sys_sched_yield,
705 and I don't want to add more synchronization...
706 */
707 while (g_async_queue_length(cap_queue)>0)
708 usleep(100000);
709 }
710 #endif
711 tcp_exit();
712 ip_frag_exit();
713 scan_exit();
714 strcpy(nids_errbuf, "loop: ");
715 strncat(nids_errbuf, pcap_geterr(desc), sizeof nids_errbuf - 7);
716 if (!nids_params.pcap_desc)
717 pcap_close(desc);
718 desc = NULL;
719
720 free(ip_procs);
721 free(ip_frag_procs);
722 }
723
nids_getfd()724 int nids_getfd()
725 {
726 if (!desc) {
727 strcpy(nids_errbuf, "Libnids not initialized");
728 return -1;
729 }
730 return pcap_get_selectable_fd(desc);
731 }
732
nids_next()733 int nids_next()
734 {
735 struct pcap_pkthdr h;
736 char *data;
737
738 if (!desc) {
739 strcpy(nids_errbuf, "Libnids not initialized");
740 return 0;
741 }
742 if (!(data = (char *) pcap_next(desc, &h))) {
743 strcpy(nids_errbuf, "next: ");
744 strncat(nids_errbuf, pcap_geterr(desc), sizeof(nids_errbuf) - 7);
745 return 0;
746 }
747 /* threading is quite useless (harmful) in this case - should we do an API change? */
748 START_CAP_QUEUE_PROCESS_THREAD();
749 nids_pcap_handler(0, &h, (u_char *)data);
750 STOP_CAP_QUEUE_PROCESS_THREAD();
751 return 1;
752 }
753
nids_dispatch(int cnt)754 int nids_dispatch(int cnt)
755 {
756 int r;
757
758 if (!desc) {
759 strcpy(nids_errbuf, "Libnids not initialized");
760 return -1;
761 }
762 START_CAP_QUEUE_PROCESS_THREAD(); /* threading... */
763 if ((r = pcap_dispatch(desc, cnt, (pcap_handler) nids_pcap_handler,
764 NULL)) == -1) {
765 strcpy(nids_errbuf, "dispatch: ");
766 strncat(nids_errbuf, pcap_geterr(desc), sizeof(nids_errbuf) - 11);
767 }
768 STOP_CAP_QUEUE_PROCESS_THREAD();
769 return r;
770 }
771