Added ARP to packet.c
[netsniff-ng.git] / src / netsniff-ng.c
blobf46fa419f1d092ef9a38f5130998f973e12724d8
1 /* XXX: Coding Style - use the tool indent with the following (Linux kernel
2 * code indents)
4 * indent -nbad -bap -nbc -bbo -hnl -br -brs -c33 -cd33 -ncdb -ce -ci4 \
5 * -cli0 -d0 -di1 -nfc1 -i8 -ip0 -l120 -lp -npcs -nprs -npsl -sai \
6 * -saf -saw -ncs -nsc -sob -nfca -cp33 -ss -ts8 -il1
9 * netsniff-ng
11 * High performance network sniffer for packet inspection
13 * Copyright (C) 2009, 2010 Daniel Borkmann <danborkmann@googlemail.com> and
14 * Emmanuel Roullit <emmanuel.roullit@googlemail.com>
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or (at
19 * your option) any later version.
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 * for more details.
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
30 * Note: Your kernel has to be compiled with CONFIG_PACKET_MMAP=y option in
31 * order to use this.
34 #define _GNU_SOURCE
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdint.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <unistd.h>
42 #include <signal.h>
43 #include <fcntl.h>
44 #include <errno.h>
45 #include <assert.h>
46 #include <ctype.h>
47 #include <pthread.h>
48 #include <getopt.h>
49 #include <netsniff-ng.h>
51 #include <net/if.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
55 #include <sys/ioctl.h>
56 #include <sys/un.h>
57 #include <sys/types.h>
58 #include <sys/poll.h>
60 #include <netsniff-ng/misc.h>
61 #include <netsniff-ng/system.h>
62 #include <netsniff-ng/rx_ring.h>
63 #include <netsniff-ng/signal.h>
64 #include <netsniff-ng/macros.h>
65 #include <netsniff-ng/types.h>
66 #include <netsniff-ng/print.h>
67 #include <netsniff-ng/dump.h>
68 #include <netsniff-ng/netdev.h>
69 #include <netsniff-ng/bpf.h>
72 * Global vars
75 volatile sig_atomic_t sigint = 0;
76 volatile sig_atomic_t sigusr2 = 0;
78 ring_buff_stat_t netstat;
79 pthread_mutex_t gs_loc_mutex;
81 print_packet_buff_t print_packet_buffer = versatile_print;
84 * Functions
87 /**
88 * refresh_counters - Refreshes global packet counters
90 static inline void refresh_counters(void)
92 float curr_weight = 0.68f;
94 netstat.per_min.frames += netstat.per_sec.frames;
95 netstat.per_min.bytes += netstat.per_sec.bytes;
97 netstat.t_elapsed++;
99 if (unlikely(netstat.t_elapsed % 60 == 0)) {
100 netstat.s_per_min.frames =
101 curr_weight * netstat.per_min.frames + (1.f - curr_weight) * netstat.s_per_min.frames;
102 netstat.s_per_min.bytes =
103 curr_weight * netstat.per_min.bytes + (1.f - curr_weight) * netstat.s_per_min.bytes;
105 netstat.per_min.frames = netstat.per_min.bytes = 0;
108 netstat.s_per_sec.frames =
109 curr_weight * netstat.per_sec.frames + (1.f - curr_weight) * netstat.s_per_sec.frames;
110 netstat.s_per_sec.bytes = curr_weight * netstat.per_sec.bytes + (1.f - curr_weight) * netstat.s_per_sec.bytes;
112 netstat.per_sec.frames = netstat.per_sec.bytes = 0;
116 * print_counters - Prints global counters to terminal
118 static inline void print_counters(void)
120 uint64_t d_day, d_h, d_min, d_sec, d_nsec;
122 struct timespec t_curr, diff;
124 clock_gettime(CLOCK_REALTIME, &t_curr);
126 timespec_subtract(&diff, &t_curr, &netstat.m_start);
128 d_day = DIV_S2DAYS(diff.tv_sec);
129 diff.tv_sec = MOD_DAYS2S(diff.tv_sec);
130 d_h = DIV_S2HOURS(diff.tv_sec);
131 diff.tv_sec = MOD_HOURS2S(diff.tv_sec);
132 d_min = DIV_S2MINUT(diff.tv_sec);
133 diff.tv_sec = MOD_MINUT2S(diff.tv_sec);
134 d_sec = diff.tv_sec;
135 d_nsec = diff.tv_nsec;
138 * FIXME Find a way to print a uint64_t
139 * on 32 and 64 bit arch w/o gcc warnings
141 info("stats summary:\n");
142 info("--------------------------------------------------------------------------------------------\n");
143 info("elapsed time: %llu d, %llu h, %llu min, %llu s, %llu ns\n", d_day, d_h, d_min, d_sec, d_nsec);
144 info("-----------+--------------------------+--------------------------+--------------------------\n");
145 info(" | per sec | per min | total \n");
146 info("-----------+--------------------------+--------------------------+--------------------------\n");
147 info(" frames | %24llu | %24llu | %24llu \n",
148 netstat.s_per_sec.frames, netstat.s_per_min.frames, netstat.total.frames);
149 info("-----------+--------------------------+--------------------------+--------------------------\n");
150 info(" in B | %24llu | %24llu | %24llu \n",
151 netstat.s_per_sec.bytes, netstat.s_per_min.bytes, netstat.total.bytes);
152 info(" in KB | %24llu | %24llu | %24llu \n",
153 DIV_KBYTES(netstat.s_per_sec.bytes), DIV_KBYTES(netstat.s_per_min.bytes), DIV_KBYTES(netstat.total.bytes));
154 info(" in MB | %24llu | %24llu | %24llu \n",
155 DIV_MBYTES(netstat.s_per_sec.bytes), DIV_MBYTES(netstat.s_per_min.bytes), DIV_MBYTES(netstat.total.bytes));
156 info(" in GB | %24llu | %24llu | %24llu \n",
157 DIV_GBYTES(netstat.s_per_sec.bytes), DIV_GBYTES(netstat.s_per_min.bytes), DIV_GBYTES(netstat.total.bytes));
158 info("-----------+--------------------------+--------------------------+--------------------------\n");
162 * uds_thread - Unix Domain Socket thread for sending internal counter states
163 * @psock: socket pointer
165 static void *uds_thread(void *psock)
167 int ret;
168 int sock;
170 assert(psock);
172 /* Signalmask is per thread. we don't want to interrupt the
173 send-syscall */
174 hold_softirq_pthread(2, SIGUSR1, SIGALRM);
176 info("unix domain socket server: entering thread\n");
177 sock = *((int *)psock);
179 pthread_mutex_lock(&gs_loc_mutex);
181 ret = send(sock, &netstat, sizeof(netstat), 0);
182 if (ret < 0) {
183 perr("cannot send ring buffer stats - ");
186 pthread_mutex_unlock(&gs_loc_mutex);
188 close(sock);
190 info("unix domain socket server: quitting thread\n");
191 pthread_exit(0);
195 * start_uds_server - Unix Domain Socket server main
196 * @psockfile: path to UDS inode
198 void *start_uds_server(void *psockfile)
200 int ret;
201 int sock, sock2;
203 char *sockfile = (char *)psockfile;
205 pthread_t tid;
207 struct sockaddr_un local;
208 struct sockaddr_un remote;
210 assert(psockfile);
212 sock = socket(AF_UNIX, SOCK_STREAM, 0);
213 if (sock < 0) {
214 perr("cannot create uds socket %d - ", errno);
215 pthread_exit(0);
218 local.sun_family = AF_UNIX;
219 strncpy(local.sun_path, sockfile, sizeof(local.sun_path));
221 if (unlink(local.sun_path) != 0) {
222 perr("cannot unlink %s\n", local.sun_path);
223 pthread_exit(0);
226 info("bind socket to %s\n", local.sun_path);
228 ret = bind(sock, (struct sockaddr *)&local, sizeof(local));
229 if (ret < 0) {
230 perr("cannot bind uds socket %d - ", errno);
231 pthread_exit(0);
234 ret = listen(sock, INTERNAL_UDS_QUEUE_LEN);
235 if (ret < 0) {
236 perr("cannot set up uds listening queue %d - ", errno);
237 pthread_exit(0);
240 while (1) {
241 size_t t = sizeof(remote);
242 info("unix domain socket server: waiting for a connection\n");
244 sock2 = accept(sock, (struct sockaddr *)&remote, (socklen_t *) & t);
245 if (sock2 < 0) {
246 perr("cannot do accept on uds socket %d - ", errno);
247 pthread_exit(0);
250 info("unix domain socket server: connected to client\n");
252 /* We're not interested in joining...
253 so a single thread id is sufficient */
254 ret = pthread_create(&tid, NULL, uds_thread, &sock2);
255 if (ret < 0) {
256 perr("uds server: error creating thread - ");
257 pthread_exit(0);
260 pthread_detach(tid);
263 info("unix domain socket server: quit\n");
264 pthread_exit(0);
268 * softirq_handler - Signal handling multiplexer
269 * @number: signal number
271 void softirq_handler(int number)
273 switch (number) {
274 case SIGALRM:
276 refresh_counters();
277 break;
279 case SIGUSR1:
281 print_counters();
282 break;
284 case SIGUSR2:
286 switch (++sigusr2 % 2) {
287 case 0:
289 print_packet_buffer = versatile_print;
290 break;
292 case 1:
294 print_packet_buffer = NULL;
295 break;
297 default:
299 print_packet_buffer = versatile_print;
300 break;
303 break;
305 case SIGINT:
307 sigint = 1;
308 info("caught SIGINT! ... bye bye\n");
309 break;
311 case SIGHUP:
313 info("caught SIGHUP! ... ignoring\n");
314 break;
316 default:
318 break;
324 * fetch_packets_and_print - Traverses RX_RING and prints content
325 * @rb: ring buffer
326 * @pfd: file descriptor for polling
328 void fetch_packets(ring_buff_t * rb, struct pollfd *pfd, int timeout, FILE * pcap, int packet_type, int sock)
330 int ret, foo, i = 0;
332 assert(rb);
333 assert(pfd);
335 /* This is our critical path ... */
336 while (likely(!sigint)) {
337 while (mem_notify_user_for_rx(rb->frames[i]) && likely(!sigint)) {
338 struct frame_map *fm = rb->frames[i].iov_base;
339 ring_buff_bytes_t *rbb =
340 (ring_buff_bytes_t *) (rb->frames[i].iov_base + sizeof(*fm) + sizeof(short));
342 /* Check if the user wants to have a specific
343 packet type */
344 if (packet_type != PACKET_DONT_CARE) {
345 if (fm->s_ll.sll_pkttype != packet_type) {
346 goto __out_notify_kernel;
350 if (pcap != NULL) {
351 pcap_dump(pcap, &fm->tp_h, (struct ethhdr *)rbb);
354 if (print_packet_buffer) {
355 /* This path here slows us down ... well, but
356 the user wants to see what's going on */
357 print_packet_buffer(rbb, &fm->tp_h);
360 /* Pending singals will be delivered after netstat
361 manipulation */
362 hold_softirq(2, SIGUSR1, SIGALRM);
363 pthread_mutex_lock(&gs_loc_mutex);
365 netstat.per_sec.frames++;
366 netstat.per_sec.bytes += fm->tp_h.tp_len;
368 netstat.total.frames++;
369 netstat.total.bytes += fm->tp_h.tp_len;
371 pthread_mutex_unlock(&gs_loc_mutex);
372 restore_softirq(2, SIGUSR1, SIGALRM);
374 /* Next frame */
375 i = (i + 1) % rb->layout.tp_frame_nr;
377 __out_notify_kernel:
378 /* This is very important, otherwise kernel starts
379 to drop packages */
380 mem_notify_kernel_for_rx(&(fm->tp_h));
383 while ((ret = poll(pfd, 1, timeout)) <= 0)
384 /* NOP */ ;
386 if (ret > 0 && (pfd->revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL))) {
387 if (pfd->revents & (POLLHUP | POLLRDHUP)) {
388 err("Hangup on socket occured.\n\n");
389 return;
390 } else if (pfd->revents & POLLERR) {
391 /* recv is more specififc on the error */
392 errno = 0;
393 if (recv(sock, &foo, sizeof(foo), MSG_PEEK) != -1)
394 goto __out_grab_frame; /* Hmm... no error */
395 if (errno == ENETDOWN) {
396 err("Interface went down\n\n");
397 } else {
398 err("%s\n\n", strerror(errno));
400 return;
401 } else if (pfd->revents & POLLNVAL) {
402 err("Invalid polling request on socket.\n\n");
403 return;
407 __out_grab_frame:
408 /* Look-ahead if current frame is status kernel, otherwise we have
409 have incoming frames and poll spins / hangs all the time :( */
410 for (; ((struct tpacket_hdr *)rb->frames[i].iov_base)->tp_status
411 != TP_STATUS_USER; i = (i + 1) % rb->layout.tp_frame_nr)
412 /* NOP */ ;
413 /* Why this should be okay:
414 1) Current frame[i] is TP_STATUS_USER:
415 This is our original case that occurs without
416 the for loop.
417 2) Current frame[i] is not TP_STATUS_USER:
418 poll returns correctly with return value 1 (number of
419 file descriptors), so an event has occured which has
420 to be POLLIN since all error conditions have been
421 caught previously. Furthermore, during ring traversal
422 a frame that has been set to TP_STATUS_USER will be
423 given back to kernel on finish with TP_STATUS_KERNEL.
424 So, if we look ahead all skipped frames are not ready
425 for user access. Since the kernel decides to put
426 frames, which are 'behind' our pointer, into
427 TP_STATUS_USER we do one loop and return at the
428 correct position after passing the for loop again. If
429 we grab frame which are 'in front of' our pointer
430 we'll fetch them within the first for loop.
436 * init_system - Initializes netsniff-ng main
437 * @sd: system configuration data
438 * @sock: socket
439 * @rb: ring buffer
440 * @pfd: file descriptor for polling
442 static int init_system(system_data_t * sd, int *sock, ring_buff_t ** rb, struct pollfd *pfd)
444 int stmp, i, ret, bpf_len = 0;
445 char dev_buff[1024];
447 struct sock_filter *bpf = NULL;
448 struct ifconf ifc;
449 struct ifreq *ifr = NULL;
450 struct ifreq *ifr_elem = NULL;
451 struct itimerval val_r;
453 assert(sd);
454 assert(sock);
455 assert(rb);
456 assert(pfd);
458 /* We are only allowed to do these nasty things as root ;) */
459 check_for_root();
461 /* Scheduler timeslice & prio tuning */
462 if (!sd->no_prioritization) {
463 set_proc_prio(DEFAULT_PROCESS_PRIO);
464 set_sched_status(DEFAULT_SCHED_POLICY, DEFAULT_SCHED_PRIO);
467 register_softirq(SIGINT, &softirq_handler);
468 register_softirq(SIGALRM, &softirq_handler);
469 register_softirq(SIGUSR1, &softirq_handler);
470 register_softirq(SIGUSR2, &softirq_handler);
471 register_softirq(SIGHUP, &softirq_handler);
473 if (sd->sysdaemon) {
474 ret = daemonize(sd->pidfile, sd->logfile, sd->sockfile, start_uds_server);
475 if (ret != 0) {
476 err("daemonize failed");
477 exit(EXIT_FAILURE);
481 /* Print program header */
482 header();
484 (*rb) = (ring_buff_t *) malloc(sizeof(**rb));
485 if ((*rb) == NULL) {
486 perr("Cannot allocate ring buffer\n");
487 exit(EXIT_FAILURE);
490 memset((*rb), 0, sizeof(**rb));
492 /* User didn't specify a device, so we switch to the default running
493 dev. This is the first running dev found (except lo). If we find
494 nothing, we switch to lo. */
495 if (!sd->dev) {
496 sd->dev = strdup("lo");
497 if (!sd->dev) {
498 perror("Cannot allocate mem");
499 exit(EXIT_FAILURE);
502 stmp = socket(AF_INET, SOCK_DGRAM, 0);
503 if (stmp < 0) {
504 perror("socket");
505 exit(EXIT_FAILURE);
508 ifc.ifc_len = sizeof(dev_buff);
509 ifc.ifc_buf = dev_buff;
511 if (ioctl(stmp, SIOCGIFCONF, &ifc) < 0) {
512 perror("ioctl(SIOCGIFCONF)");
513 exit(EXIT_FAILURE);
516 ifr = ifc.ifc_req;
518 for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); ++i) {
519 ifr_elem = &ifr[i];
521 if (ioctl(stmp, SIOCGIFFLAGS, ifr_elem) < 0) {
522 perror("ioctl(SIOCGIFFLAGS)");
523 exit(EXIT_FAILURE);
526 if ((ifr_elem->ifr_flags & IFF_UP) &&
527 (ifr_elem->ifr_flags & IFF_RUNNING) && strncmp(ifr_elem->ifr_name, "lo", IFNAMSIZ)) {
528 sd->dev = strdup(ifr_elem->ifr_name);
529 if (!sd->dev) {
530 perror("Cannot allocate mem");
531 exit(EXIT_FAILURE);
533 break;
537 close(stmp);
539 info("No device specified, using `%s`.\n\n", sd->dev);
542 (*sock) = alloc_pf_sock();
543 put_dev_into_promisc_mode((*sock), ethdev_to_ifindex((*sock), sd->dev));
545 if (sd->bypass_bpf == BPF_NO_BYPASS) {
546 /* XXX: If you try to create custom filters with tcpdump, you
547 have to edit the ret opcode, otherwise your payload
548 will be cut off at 96 Byte:
550 { 0x6, 0, 0, 0xFFFFFFFF },
552 The kernel now takes skb->len instead of 0xFFFFFFFF ;)
555 /* Berkeley Packet Filter stuff */
556 parse_rules(sd->rulefile, &bpf, &bpf_len);
557 inject_kernel_bpf((*sock), bpf, bpf_len * sizeof(*bpf));
559 /* Print info for the user */
560 bpf_dump_all(bpf, bpf_len);
561 } else {
562 info("No filter applied. Sniffing all traffic.\n\n");
565 /* RX_RING stuff */
566 create_virt_rx_ring((*sock), (*rb), sd->dev);
567 bind_dev_to_rx_ring((*sock), ethdev_to_ifindex((*sock), sd->dev), (*rb));
568 mmap_virt_rx_ring((*sock), (*rb));
570 alloc_frame_buffer((*rb));
571 prepare_polling((*sock), pfd);
573 memset(&netstat, 0, sizeof(netstat));
575 /* Timer settings for counter update */
576 val_r.it_value.tv_sec = (INTERVAL_COUNTER_REFR / 1000);
577 val_r.it_value.tv_usec = (INTERVAL_COUNTER_REFR * 1000) % 1000000;
578 val_r.it_interval = val_r.it_value;
580 ret = setitimer(ITIMER_REAL, &val_r, NULL);
581 if (ret < 0) {
582 perr("cannot set itimer - ");
583 exit(EXIT_FAILURE);
586 clock_gettime(CLOCK_REALTIME, &netstat.m_start);
588 info("--- Listening ---\n\n");
590 free(bpf);
591 return 0;
595 * cleanup_system - Cleans up netsniff-ng main
596 * @sd: system configuration data
597 * @sock: socket
598 * @rb: ring buffer
600 static void cleanup_system(system_data_t * sd, int *sock, ring_buff_t ** rb)
602 assert(sd);
603 assert(sock);
604 assert(rb);
605 assert(*rb);
607 net_stat((*sock));
608 destroy_virt_rx_ring((*sock), (*rb));
610 free((*rb));
611 close((*sock));
614 * FIXME Find a way to print a uint64_t
615 * on 32 and 64 bit arch w/o gcc warnings
618 info("captured frames: %llu, "
619 "captured bytes: %llu [%llu KiB, %llu MiB, %llu GiB]\n",
620 netstat.total.frames, netstat.total.bytes,
621 netstat.total.bytes / 1024,
622 netstat.total.bytes / (1024 * 1024), netstat.total.bytes / (1024 * 1024 * 1024));
624 free(sd->dev);
626 if (sd->sysdaemon) {
627 undaemonize(sd->pidfile);
632 * main - Main routine
633 * @argc: number of args
634 * @argv: arguments passed from tty
636 int main(int argc, char **argv)
638 FILE *dump_pcap = NULL;
639 int i, c, opt_idx;
640 int sock;
642 system_data_t *sd;
643 ring_buff_t *rb;
644 struct pollfd pfd;
646 static struct option long_options[] = {
647 {"dev", required_argument, 0, 'd'},
648 {"dump", required_argument, 0, 'p'},
649 {"replay", required_argument, 0, 'r'},
650 {"quit-after", required_argument, 0, 'q'},
651 {"generate", required_argument, 0, 'g'},
652 {"type", required_argument, 0, 't'},
653 {"filter", required_argument, 0, 'f'},
654 {"bind-cpu", required_argument, 0, 'b'},
655 {"unbind-cpu", required_argument, 0, 'B'},
656 {"prio-norm", no_argument, 0, 'H'},
657 {"non-block", no_argument, 0, 'n'},
658 {"no-color", no_argument, 0, 'N'},
659 {"silent", no_argument, 0, 's'},
660 {"daemonize", no_argument, 0, 'D'},
661 {"pidfile", required_argument, 0, 'P'},
662 {"logfile", required_argument, 0, 'L'},
663 {"sockfile", required_argument, 0, 'S'},
664 {"version", no_argument, 0, 'v'},
665 {"help", no_argument, 0, 'h'},
666 {0, 0, 0, 0}
669 sd = malloc(sizeof(*sd));
670 if (!sd) {
671 err("No mem left!\n");
672 exit(EXIT_FAILURE);
675 memset(sd, 0, sizeof(*sd));
676 memset(&pfd, 0, sizeof(pfd));
678 /* Some default sys configuration */
679 sd->blocking_mode = POLL_WAIT_INF;
680 sd->bypass_bpf = BPF_BYPASS;
681 sd->packet_type = PACKET_DONT_CARE;
683 while ((c = getopt_long(argc, argv, "vhd:p:P:L:Df:sS:b:B:Hnt:", long_options, &opt_idx)) != EOF) {
684 switch (c) {
685 case 'h':
687 help();
688 break;
690 case 'v':
692 version();
693 break;
695 case 'd':
697 sd->dev = strdup(optarg);
698 if (!sd->dev) {
699 perror("Cannot allocate mem");
700 exit(EXIT_FAILURE);
702 break;
704 case 'n':
706 sd->blocking_mode = POLL_WAIT_NONE;
707 break;
709 case 'H':
711 sd->no_prioritization = PROC_NO_HIGHPRIO;
712 break;
714 case 't':
716 if (!strncmp(optarg, "host", strlen("host"))) {
717 sd->packet_type = PACKET_HOST;
718 } else if (!strncmp(optarg, "broadcast", strlen("broadcast"))) {
719 sd->packet_type = PACKET_BROADCAST;
720 } else if (!strncmp(optarg, "multicast", strlen("multicast"))) {
721 sd->packet_type = PACKET_MULTICAST;
722 } else if (!strncmp(optarg, "others", strlen("others"))) {
723 sd->packet_type = PACKET_OTHERHOST;
724 } else if (!strncmp(optarg, "outgoing", strlen("outgoing"))) {
725 sd->packet_type = PACKET_OUTGOING;
726 } else {
727 sd->packet_type = PACKET_DONT_CARE;
729 break;
731 case 'f':
733 sd->bypass_bpf = BPF_NO_BYPASS;
734 sd->rulefile = optarg;
735 break;
737 case 's':
739 /* Switch to silent mode */
740 print_packet_buffer = NULL;
741 break;
743 case 'D':
745 sd->sysdaemon = SYSD_ENABLE;
746 break;
748 case 'P':
750 sd->pidfile = optarg;
751 break;
753 case 'L':
755 sd->logfile = optarg;
756 break;
758 case 'S':
760 sd->sockfile = optarg;
761 break;
763 case 'b':
765 set_cpu_affinity(optarg);
766 break;
768 case 'B':
770 set_cpu_affinity_inv(optarg);
771 break;
773 case 'p':
775 if ((dump_pcap = fopen(optarg, "w+")) == NULL) {
776 perr("Can't open file: ");
777 exit(EXIT_FAILURE);
780 sf_write_header(dump_pcap, LINKTYPE_EN10MB, 0, PCAP_DEFAULT_SNAPSHOT_LEN);
781 break;
784 case '?':
786 switch (optopt) {
787 case 'd':
788 case 'f':
789 case 'p':
790 case 'P':
791 case 'L':
792 case 'S':
793 case 'b':
794 case 'B':
796 fprintf(stderr, "Option -%c requires an argument!\n", optopt);
797 break;
799 default:
801 if (isprint(optopt)) {
802 fprintf(stderr, "Unknown option character `0x%X\'!\n", optopt);
804 break;
808 return 1;
810 default:
812 abort();
817 if (sd->sysdaemon && (!sd->pidfile || !sd->logfile || !sd->sockfile)) {
818 help();
819 exit(EXIT_FAILURE);
822 for (i = optind; i < argc; ++i) {
823 err("Non-option argument %s!\n", argv[i]);
826 if (optind < argc) {
827 exit(EXIT_FAILURE);
831 * Main stuff
834 init_system(sd, &sock, &rb, &pfd);
835 fetch_packets(rb, &pfd, sd->blocking_mode, dump_pcap, sd->packet_type, sock);
836 cleanup_system(sd, &sock, &rb);
838 if (dump_pcap != NULL) {
839 fclose(dump_pcap);
842 free(sd);
843 return 0;