void add_iface(char *iface) { char errbuf[PCAP_ERRBUF_SIZE]; char const *filter; struct iface_config *ifc; int rc; if (cfg.v4_flag) filter = ip4_filter; else if (cfg.v6_flag) filter = ip6_filter; else filter = def_filter; ifc = (struct iface_config *) calloc(1, sizeof(struct iface_config)); ifc->name = iface; ifc->pcap_handle = pcap_open_live(iface, SNAP_LEN, cfg.promisc_flag, 1000, errbuf); if (ifc->pcap_handle == NULL) { log_msg(LOG_WARNING, "Skipping interface %s, %s", iface, errbuf); goto error; } rc = pcap_datalink(ifc->pcap_handle); if (rc != DLT_EN10MB) { log_msg(LOG_WARNING, "Skipping interface %s, invalid data link layer %s (%s).", iface, pcap_datalink_val_to_name(rc), pcap_datalink_val_to_description(rc)); goto error_pcap; } rc = pcap_compile(ifc->pcap_handle, &ifc->pcap_filter, filter, 0, 0); if (rc == -1) { log_msg(LOG_WARNING, "Skipping interface %s, %s", iface, pcap_geterr(ifc->pcap_handle)); goto error_pcap; } rc = pcap_setfilter(ifc->pcap_handle, &ifc->pcap_filter); if (rc == -1) { log_msg(LOG_WARNING, "Skipping iface %s, %s", iface, pcap_geterr(ifc->pcap_handle)); goto error_filter; } rc = pcap_fileno(ifc->pcap_handle); #if HAVE_LIBEVENT2 ifc->event = event_new(cfg.eb, rc, EV_READ|EV_PERSIST, read_cb, ifc); if(!ifc->event) log_msg(LOG_ERR, "%s: event_new(...)", __FUNCTION__); event_add(ifc->event, NULL); #else event_set(&ifc->event, rc, EV_READ|EV_PERSIST, read_cb, ifc); event_add(&ifc->event, NULL); #endif if (cfg.hashsize < 1 || cfg.hashsize > 65536) log_msg(LOG_ERR, "%s: hash size (%d) must be >= 1 and <= 65536", __FUNCTION__, cfg.hashsize); if (cfg.ratelimit) { ifc->cache = calloc(cfg.hashsize, sizeof(*ifc->cache)); if (!ifc->cache) log_msg(LOG_ERR, "%s: unable to allocate memory for hash cache", __FUNCTION__); } ifc->next = cfg.interfaces; cfg.interfaces = ifc; log_msg(LOG_DEBUG, "Opened interface %s (%s)", iface, pcap_datalink_val_to_description(pcap_datalink(ifc->pcap_handle))); return; error_filter: pcap_freecode(&ifc->pcap_filter); error_pcap: pcap_close(ifc->pcap_handle); error: free(ifc); }
int zizzania_start(struct zizzania *z) { struct sigaction sa; sigset_t set; struct bpf_program fp; const uint8_t *packet; struct pcap_pkthdr *packet_header; int dlt; uint8_t retval; int error = 0; /* get pcap handle live */ if (z->setup.live) { int snaplen; *z->error_buffer = '\0'; snaplen = *(z->setup.output) ? MAX_SNAPLEN : MIN_SNAPLEN; z->handler = pcap_open_live(z->setup.input, snaplen, 1, READ_TIMEOUT, z->error_buffer); /* warning */ if (*z->error_buffer) { PRINT(z->error_buffer); } } /* from file */ else { z->handler = pcap_open_offline(z->setup.input, z->error_buffer); z->setup.passive = 1; } if (!z->handler) { return 0; } /* drop root privileges */ zizzania_drop_root(); /* check datalink type */ dlt = pcap_datalink(z->handler); PRINTF("datalink type %s", pcap_datalink_val_to_name(dlt)); if (pcap_datalink(z->handler) != DLT_IEEE802_11_RADIO) { const char *expected_dlt; expected_dlt = pcap_datalink_val_to_name (DLT_IEEE802_11_RADIO); zizzania_set_error_messagef(z, "wrong device type/mode %s; %s expected", pcap_datalink_val_to_name(dlt), expected_dlt); return 0; } /* set capture filter */ pcap_compile(z->handler, &fp, BPF, 1, -1); pcap_setfilter(z->handler, &fp); pcap_freecode(&fp); /* open dumper */ if (*(z->setup.output)) { PRINTF("dumping packets to %s", z->setup.output); z->dumper = pcap_dump_open(z->handler, z->setup.output); if (!z->dumper) { zizzania_set_error_messagef(z, pcap_geterr(z->handler)); return 0; } } /* ignore signals */ memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = SIG_IGN; if (sigaction(SIGINT, &sa, NULL) || sigaction(SIGTERM, &sa, NULL)) { zizzania_set_error_messagef(z, "unable to set signal action"); return 0; } /* mask all signals (so everything is sent to the dispatcher, blocked on the sigtimedwait) */ sigfillset(&set); if (pthread_sigmask(SIG_SETMASK, &set, NULL)) { zizzania_set_error_messagef(z, "unable to set signal mask"); return 0; } /* start dispatcher */ if (pthread_create(&z->dispatcher, NULL, zizzania_dispatcher, z)) { zizzania_set_error_messagef(z, "unable to start dispatcher thread"); return 0; } /* packet loop */ while (!z->stop) { switch (pcap_next_ex(z->handler, &packet_header, &packet)) { case 0: /* timeout */ break; /* recheck flag and eventually start over */ case 1: /* no problem */ error = !zizzania_process_packet(z, packet_header, packet); break; case -1: /* error */ PRINT(pcap_geterr(z->handler)); zizzania_set_error_messagef(z, pcap_geterr(z->handler)); error = z->stop = 1; break; case -2: /* end of file */ PRINT("eof"); z->stop = 1; break; } } PRINT("shuting down the dispatcher"); /* force dispatcher wakeup on errors on this thread */ pthread_kill(z->dispatcher, SIGTERM); /* join dispatcher thread */ if (pthread_join(z->dispatcher, (void *)&retval)) { PRINT("cannot join the dispatcher"); return 0; } return !error && retval; }