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