/* Initializes pcap capture settings and returns a pcap handle on success, NULL on error */ pcap_t *capture_init(char *capture_source) { pcap_t *handle = NULL; char errbuf[PCAP_ERRBUF_SIZE] = {0}; #ifdef __APPLE__ // must disassociate from any current AP. This is the only way. pid_t pid = fork(); if (!pid) { char* argv[] = {"/System/Library/PrivateFrameworks/Apple80211.framework/Resources/airport", "-z", NULL}; execve("/System/Library/PrivateFrameworks/Apple80211.framework/Resources/airport", argv, NULL); } int status; waitpid(pid, &status, 0); handle = pcap_create(capture_source, errbuf); if (handle) { pcap_set_snaplen(handle, BUFSIZ); pcap_set_timeout(handle, 50); pcap_set_rfmon(handle, 1); pcap_set_promisc(handle, 1); int status = pcap_activate(handle); if (status) cprintf(CRITICAL, "pcap_activate status %d\n", status); } #else handle = pcap_open_live(capture_source, BUFSIZ, 1, 0, errbuf); #endif if (!handle) { handle = pcap_open_offline(capture_source, errbuf); } return handle; }
pcap_t * pcap_open_live_extended(const char *source, int snaplen, int promisc, int to_ms, int rfmon, char *errbuf) { pcap_t *p; int status; p = pcap_create(source, errbuf); if (p == NULL) return (NULL); status = pcap_set_snaplen(p, snaplen); if (status < 0) goto fail; status = pcap_set_promisc(p, promisc); if (status < 0) goto fail; status = pcap_set_timeout(p, to_ms); if (status < 0) goto fail; if(pcap_can_set_rfmon(p) == 1) { status = pcap_set_rfmon(p, rfmon); if (status < 0) goto fail; } status = pcap_activate(p); if (status < 0) goto fail; return (p); fail: snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", source, pcap_geterr(p)); pcap_close(p); return (NULL); }
void capture(char *dev) { pcap_t *pcap; char errbuf[PCAP_ERRBUF_SIZE]; struct pcap_pkthdr header; /* The header that pcap gives us */ const u_char *packet; /* The actual packet */ if(NULL == dev) { dev = pcap_lookupdev(errbuf); if (dev == NULL) { fprintf(stderr, "Couldn't find default device: %s\n", errbuf); exit(1); } } pcap = pcap_create(dev, errbuf); pcap_set_rfmon(pcap, 1); pcap_set_promisc(pcap, 1); pcap_set_buffer_size(pcap, 1 * 1024 * 1024); pcap_set_timeout(pcap, 1); pcap_set_snaplen(pcap, 16384); pcap_activate(pcap); if(DLT_IEEE802_11_RADIO == pcap_datalink(pcap)) { pcap_loop(pcap, 0, got_packet, 0); } else { fprintf(stderr, "Could not initialize a IEEE802_11_RADIO packet capture for interface %s\n", dev); } }
/* * Class: disy_jnipcap_Pcap * Method: setRfmon * Signature: (JI)I */ JNIEXPORT jint JNICALL Java_disy_jnipcap_Pcap_setRfmon (JNIEnv *env, jclass jcls, jlong jptr, jint jmon) { pcap_t *p = (pcap_t *) jptr; if (p == NULL) return -1; return (jint) pcap_set_rfmon (p, (int) jmon); }
void Sniffer::set_rfmon(bool rfmon_enabled) { #ifndef _WIN32 if (pcap_can_set_rfmon(get_pcap_handle()) == 1) { if (pcap_set_rfmon(get_pcap_handle(), rfmon_enabled)) { throw pcap_error(pcap_geterr(get_pcap_handle())); } } #endif }
int myPcapCatchAndAnaly() { int status=0; int header_type; char errbuf[PCAP_ERRBUF_SIZE]; /* openwrt && linux */ char *dev=(char *)"wlan0"; /* mac os */ //test // char* dev=(char *)"en0"; handle=pcap_create(dev,errbuf); //为抓取器打开一个句柄 if (handle == NULL) { fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf); return 0; } // 由于在该路由器测试时,发现在该openwrt系统上不支持libpcap设置monitor模式,在激活的时候会产生错误 // 将采用手动设置并检测网卡是否为monitor模式 // if(pcap_can_set_rfmon(handle)) { // //查看是否能设置为监控模式 // printf("Device %s can be opened in monitor mode\n",dev); // } // else { // printf("Device %s can't be opened in monitor mode!!!\n",dev); // } // 若是mac os系统,则可以支持 // test if(pcap_set_rfmon(handle,1)!=0) { fprintf(stderr, "Device %s couldn't be opened in monitor mode\n", dev); return 0; } else { printf("Device %s has been opened in monitor mode\n", dev); } pcap_set_promisc(handle,0); //不设置混杂模式 pcap_set_snaplen(handle,65535); //设置最大捕获包的长度 status=pcap_activate(handle); //激活 if(status!=0) { pcap_perror(handle,(char*)"pcap error: "); return 0; } header_type=pcap_datalink(handle); //返回链路层的类型 if(header_type!=DLT_IEEE802_11_RADIO) { printf("Error: incorrect header type - %d\n",header_type); return 0; } int id = 0; pcap_loop(handle, -1, getPacket, (u_char*)&id); return 1; }
static void prep_pcap_handle(pcap_t *handle) { int err; err = pcap_set_rfmon(handle, options.rfmon); if(err) die(0, "DEBUG: pcap handle should not be activated at %s:%d", __FILE__, __LINE__); err = pcap_set_promisc(handle, options.promisc); if(err) die(0, "DEBUG: pcap handle should not be activated at %s:%d", __FILE__, __LINE__); err = pcap_set_snaplen(handle, options.snaplen); if(err) die(0, "DEBUG: pcap handle should not be activated at %s:%d", __FILE__, __LINE__); err = pcap_set_timeout(handle, options.read_timeout); if(err) die(0, "DEBUG: pcap handle should not be activated at %s:%d", __FILE__, __LINE__); if(options.buffer_size > 0) { err = pcap_set_buffer_size(handle, options.buffer_size); if(err) die(0, "DEBUG: pcap handle should not be activated at %s:%d", __FILE__, __LINE__); } if(options.tstamp_type != PCAP_ERROR) { err = pcap_set_tstamp_type(handle, options.tstamp_type); if(err == PCAP_ERROR_ACTIVATED) die(0, "DEBUG: pcap handle should not be activated at %s:%d", __FILE__, __LINE__); else if(err == PCAP_ERROR_CANTSET_TSTAMP_TYPE) die(0, "pcap_set_tstamp_type(): Device does not support setting the timestamp"); else if(err == PCAP_WARNING_TSTAMP_TYPE_NOTSUP) plog(0, "pcap_set_tstamp_type(): Device does not support specified tstamp type"); } if(options.tstamp_nano) { err = pcap_set_tstamp_precision(handle, PCAP_TSTAMP_PRECISION_NANO); if(err == PCAP_ERROR_ACTIVATED) die(0, "DEBUG: pcap handle should not be activated at %s:%d", __FILE__, __LINE__); else if(err == PCAP_ERROR_TSTAMP_PRECISION_NOTSUP) die(0, "pcap_set_tstamp_precision(): Device does not support nanosecond precision"); } if(options.linktype != PCAP_ERROR) { err = pcap_set_datalink(handle, options.linktype); if(err) die(0, "pcap_set_datalink(): %s", pcap_geterr(handle)); } }
static int epcap_open(EPCAP_STATE *ep) { char errbuf[PCAP_ERRBUF_SIZE]; if (ep->file) { PCAP_ERRBUF(ep->p = pcap_open_offline(ep->file, errbuf)); } else { if (ep->dev == NULL) PCAP_ERRBUF(ep->dev = pcap_lookupdev(errbuf)); #ifdef HAVE_PCAP_CREATE PCAP_ERRBUF(ep->p = pcap_create(ep->dev, errbuf)); (void)pcap_set_snaplen(ep->p, ep->snaplen); (void)pcap_set_promisc(ep->p, ep->opt & EPCAP_OPT_PROMISC); (void)pcap_set_timeout(ep->p, ep->timeout); if (ep->bufsz > 0) (void)pcap_set_buffer_size(ep->p, ep->bufsz); switch (pcap_activate(ep->p)) { case 0: break; case PCAP_WARNING: case PCAP_ERROR: case PCAP_WARNING_PROMISC_NOTSUP: case PCAP_ERROR_NO_SUCH_DEVICE: case PCAP_ERROR_PERM_DENIED: pcap_perror(ep->p, "pcap_activate: "); exit(EXIT_FAILURE); default: exit(EXIT_FAILURE); } #else PCAP_ERRBUF(ep->p = pcap_open_live(ep->dev, ep->snaplen, ep->opt & EPCAP_OPT_PROMISC, ep->timeout, errbuf)); #endif /* monitor mode */ #ifdef PCAP_ERROR_RFMON_NOTSUP if (pcap_can_set_rfmon(ep->p) == 1) (void)pcap_set_rfmon(ep->p, ep->opt & EPCAP_OPT_RFMON); #endif } ep->datalink = pcap_datalink(ep->p); return 0; }
int epcap_open(EPCAP_STATE *ep) { char errbuf[PCAP_ERRBUF_SIZE]; if (ep->file) { PCAP_ERRBUF(ep->p = pcap_open_offline(ep->file, errbuf)); } else { if (ep->dev == NULL) PCAP_ERRBUF(ep->dev = pcap_lookupdev(errbuf)); PCAP_ERRBUF(ep->p = pcap_open_live(ep->dev, ep->snaplen, ep->promisc, ep->timeout, errbuf)); /* monitor mode */ if (pcap_can_set_rfmon(ep->p) == 1) (void)pcap_set_rfmon(ep->p, ep->rfmon); } return (0); }
/** * Set up pcap listener for the given interfaces and protocols. * @return a properly configured pcap_t* object for listening for the given protocols - NULL on error * @see pcap_protocols */ pcap_t* create_pcap_listener(const char * dev ///<[in] Device name to listen on , gboolean blocking ///<[in] TRUE if this is a blocking connection , unsigned listenmask ///<[in] Bit mask of protocols to listen for ///< (see @ref pcap_protocols "list of valid bits") , struct bpf_program*prog) ///<[out] Compiled PCAP program { pcap_t* pcdescr = NULL; bpf_u_int32 maskp = 0; bpf_u_int32 netp = 0; char errbuf[PCAP_ERRBUF_SIZE]; char * expr = NULL; int filterlen = 1; unsigned j; int cnt=0; int rc; const char ORWORD [] = " or "; gboolean need_promisc = FALSE; BINDDEBUG(pcap_t); // setbuf(stdout, NULL); setvbuf(stdout, NULL, _IONBF, 0); errbuf[0] = '\0'; // Search the list of valid bits so we can construct the libpcap filter // for the given set of protocols on the fly... // On this pass we just compute the amount of memory we'll need... for (j = 0, cnt = 0; j < DIMOF(filterinfo); ++j) { if (listenmask & filterinfo[j].filterbit) { ++cnt; if (cnt > 1) { filterlen += sizeof(ORWORD); } filterlen += strlen(filterinfo[j].filter); } } if (filterlen < 2) { g_warning("Constructed filter is too short - invalid mask argument."); return NULL; } if (NULL == (expr = malloc(filterlen))) { g_error("Out of memory!"); return NULL; } // Same song, different verse... // This time around, we construct the filter expr[0] = '\0'; for (j = 0, cnt = 0; j < DIMOF(filterinfo); ++j) { if (listenmask & filterinfo[j].filterbit) { ++cnt; if (cnt > 1) { g_strlcat(expr, ORWORD, filterlen); } g_strlcat(expr, filterinfo[j].filter, filterlen); } } if (pcap_lookupnet(dev, &netp, &maskp, errbuf) != 0) { // This is not a problem for non-IPv4 protocols... // It just looks up the ipv4 address - which we mostly don't care about. g_info("%s.%d: pcap_lookupnet(\"%s\") failed: [%s]" , __FUNCTION__, __LINE__, dev, errbuf); } if (NULL == (pcdescr = pcap_create(dev, errbuf))) { g_warning("pcap_create failed: [%s]", errbuf); goto oopsie; } //pcap_set_promisc(pcdescr, FALSE); for (j = 0; j < DIMOF(filterinfo); ++j) { if (listenmask & filterinfo[j].filterbit) { const char * addrstring = filterinfo[j].mcastaddr; if (addrstring && !_enable_mcast_address(addrstring, dev, TRUE)) { need_promisc = TRUE; } } } pcap_set_promisc(pcdescr, need_promisc); #ifdef HAVE_PCAP_SET_RFMON pcap_set_rfmon(pcdescr, FALSE); #endif pcap_setdirection(pcdescr, PCAP_D_IN); // Weird bug - returns -3 and doesn't show an error message... // And pcap_getnonblock also returns -3... Neither should happen AFAIK... errbuf[0] = '\0'; if ((rc = pcap_setnonblock(pcdescr, !blocking, errbuf)) < 0 && errbuf[0] != '\0') { g_warning("pcap_setnonblock(%d) failed: [%s] [rc=%d]", !blocking, errbuf, rc); g_warning("Have no idea why this happens - current blocking state is: %d." , pcap_getnonblock(pcdescr, errbuf)); } pcap_set_snaplen(pcdescr, 1500); /// @todo deal with pcap_set_timeout() call here. if (blocking) { pcap_set_timeout(pcdescr, 240*1000); } else { pcap_set_timeout(pcdescr, 1); } //pcap_set_buffer_size(pcdescr, 1500); if (pcap_activate(pcdescr) != 0) { g_warning("pcap_activate failed: [%s]", pcap_geterr(pcdescr)); goto oopsie; } if (pcap_compile(pcdescr, prog, expr, FALSE, maskp) < 0) { g_warning("pcap_compile of [%s] failed: [%s]", expr, pcap_geterr(pcdescr)); goto oopsie; } if (pcap_setfilter(pcdescr, prog) < 0) { g_warning("pcap_setfilter on [%s] failed: [%s]", expr, pcap_geterr(pcdescr)); goto oopsie; } DEBUGMSG1("Compile of [%s] worked!", expr); free(expr); expr = NULL; return(pcdescr); oopsie: // Some kind of failure - free things up and return NULL g_warning("%s.%d: Could not set up PCAP on %s" , __FUNCTION__, __LINE__, dev); if (expr) { free(expr); expr = NULL; } if (pcdescr) { close_pcap_listener(pcdescr, dev, listenmask); pcdescr = NULL; } return NULL; }
int main(int argc, char **argv) { register int op; register char *cp, *device; int dorfmon, dopromisc, snaplen, useactivate, bufsize; char ebuf[PCAP_ERRBUF_SIZE]; pcap_t *pd; int status = 0; device = NULL; dorfmon = 0; dopromisc = 0; snaplen = MAXIMUM_SNAPLEN; bufsize = 0; useactivate = 0; if ((cp = strrchr(argv[0], '/')) != NULL) program_name = cp + 1; else program_name = argv[0]; opterr = 0; while ((op = getopt(argc, argv, "i:Ips:aB:")) != -1) { switch (op) { case 'i': device = optarg; break; case 'I': dorfmon = 1; useactivate = 1; /* required for rfmon */ break; case 'p': dopromisc = 1; break; case 's': { char *end; snaplen = strtol(optarg, &end, 0); if (optarg == end || *end != '\0' || snaplen < 0 || snaplen > MAXIMUM_SNAPLEN) error("invalid snaplen %s", optarg); else if (snaplen == 0) snaplen = MAXIMUM_SNAPLEN; break; } case 'B': bufsize = atoi(optarg)*1024; if (bufsize <= 0) error("invalid packet buffer size %s", optarg); useactivate = 1; /* required for bufsize */ break; case 'a': useactivate = 1; break; default: usage(); /* NOTREACHED */ } } if (useactivate) { pd = pcap_create(device, ebuf); if (pd == NULL) error("%s", ebuf); status = pcap_set_snaplen(pd, snaplen); if (status != 0) error("%s: pcap_set_snaplen failed: %s", device, pcap_statustostr(status)); if (dopromisc) { status = pcap_set_promisc(pd, 1); if (status != 0) error("%s: pcap_set_promisc failed: %s", device, pcap_statustostr(status)); } if (dorfmon) { status = pcap_set_rfmon(pd, 1); if (status != 0) error("%s: pcap_set_rfmon failed: %s", device, pcap_statustostr(status)); } status = pcap_set_timeout(pd, 1000); if (status != 0) error("%s: pcap_set_timeout failed: %s", device, pcap_statustostr(status)); if (bufsize != 0) { status = pcap_set_buffer_size(pd, bufsize); if (status != 0) error("%s: pcap_set_buffer_size failed: %s", device, pcap_statustostr(status)); } status = pcap_activate(pd); if (status < 0) { /* * pcap_activate() failed. */ error("%s: %s\n(%s)", device, pcap_statustostr(status), pcap_geterr(pd)); } else if (status > 0) { /* * pcap_activate() succeeded, but it's warning us * of a problem it had. */ warning("%s: %s\n(%s)", device, pcap_statustostr(status), pcap_geterr(pd)); } } else { *ebuf = '\0'; pd = pcap_open_live(device, 65535, 0, 1000, ebuf); if (pd == NULL) error("%s", ebuf); else if (*ebuf) warning("%s", ebuf); } pcap_close(pd); exit(status < 0 ? 1 : 0); }
int main (int argc, char *argv[]) { char *iface; pcap_t *pcap_res; int exitno, isrfmon; char errbuf[PCAP_ERRBUF_SIZE]; exitno = EXIT_SUCCESS; pcap_res = NULL; if ( argc < 2 ){ fprintf (stdout, "Usage: %s <INTERFACE>\n\nCheck if an INTERFACE supports a monitor mode (rfmon).\n", argv[0]); exitno = 2; goto cleanup; } iface = argv[1]; pcap_res = pcap_create (iface, errbuf); if ( pcap_res == NULL ){ fprintf (stderr, "%s: cannot open interface for a packet capture: %s\n", argv[0], errbuf); exitno = 2; goto cleanup; } isrfmon = pcap_can_set_rfmon (pcap_res); if ( isrfmon == 0 ){ fprintf (stderr, "not supported\n"); exitno = 1; goto cleanup; } else if ( isrfmon == 1 ){ // Attempt to activate a packet capture // ... } else { fprintf (stderr, "%s: cannot obtain information about rfmon support: %s\n", argv[0], pcap_geterr (pcap_res)); exitno = 2; goto cleanup; } isrfmon = pcap_set_rfmon (pcap_res, 1); if ( isrfmon != 0 ){ fprintf (stderr, "%s: cannot set an interface to monitor mode: %s\n", argv[0], pcap_geterr (pcap_res)); exitno = 2; goto cleanup; } isrfmon = pcap_activate (pcap_res); if ( isrfmon == PCAP_ERROR_RFMON_NOTSUP ){ fprintf (stderr, "not supported\n"); exitno = 1; } else if ( isrfmon == 0 ){ fprintf (stderr, "supported\n"); exitno = 0; } else { fprintf (stderr, "%s: cannot activate a packet capture: %s\n", argv[0], pcap_geterr (pcap_res)); exitno = 2; } cleanup: if ( pcap_res != NULL ) pcap_close (pcap_res); return exitno; }
static ERL_NIF_TERM nif_pcap_open_live(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary device = {0}; int snaplen = 0; int promisc = 0; int to_ms = 0; int buffer_size = 0; int rfmon = 0; char errbuf[PCAP_ERRBUF_SIZE] = {0}; EWPCAP_STATE *ep = NULL; ERL_NIF_TERM res = {0}; ERL_NIF_TERM ref = {0}; if (!enif_inspect_iolist_as_binary(env, argv[0], &device)) return enif_make_badarg(env); if (!enif_get_int(env, argv[1], &snaplen)) return enif_make_badarg(env); if (!enif_get_int(env, argv[2], &promisc)) return enif_make_badarg(env); if (!enif_get_int(env, argv[3], &to_ms)) return enif_make_badarg(env); if (!enif_get_int(env, argv[4], &buffer_size)) return enif_make_badarg(env); if (!enif_get_int(env, argv[5], &rfmon)) return enif_make_badarg(env); /* NULL terminate the device name */ if (device.size > 0) { if (!enif_realloc_binary(&device, device.size+1)) return enif_make_tuple2(env, atom_error, atom_enomem); device.data[device.size-1] = '\0'; } ep = enif_alloc_resource(EWPCAP_RESOURCE, sizeof(EWPCAP_STATE)); if (ep == NULL) return enif_make_tuple2(env, atom_error, atom_enomem); /* "any" is a Linux only virtual dev */ ep->p = pcap_create((device.size == 0 ? "any" : (char *)device.data), errbuf); if (ep->p == NULL) return enif_make_tuple2(env, atom_error, enif_make_string(env, errbuf, ERL_NIF_LATIN1)); /* Set the snaplen */ (void)pcap_set_snaplen(ep->p, snaplen); /* Set promiscuous mode */ (void)pcap_set_promisc(ep->p, promisc); /* Set timeout */ (void)pcap_set_timeout(ep->p, to_ms); /* Set buffer size */ if (buffer_size > 0) (void)pcap_set_buffer_size(ep->p, buffer_size); /* Set monitor mode */ if (pcap_can_set_rfmon(ep->p) == 1) (void)pcap_set_rfmon(ep->p, rfmon); /* Return failure on error and warnings */ if (pcap_activate(ep->p) != 0) { pcap_close(ep->p); return enif_make_tuple2(env, atom_error, enif_make_string(env, pcap_geterr(ep->p), ERL_NIF_LATIN1)); } ep->datalink = pcap_datalink(ep->p); (void)enif_self(env, &ep->pid); ep->term_env = enif_alloc_env(); if (ep->term_env == NULL) { pcap_close(ep->p); return enif_make_tuple2(env, atom_error, atom_enomem); } ep->ref = enif_make_ref(ep->term_env); ref = enif_make_copy(env, ep->ref); res = enif_make_resource(env, ep); enif_release_resource(ep); return enif_make_tuple2(env, atom_ok, enif_make_tuple3(env, atom_ewpcap_resource, ref, res)); }
static ulink_recv_t *ulink_recv_open(const char *netdev) { int err; ulink_recv_t *t = NULL; if (getenv("debug") != NULL) { debug = 1; } t = (ulink_recv_t *)malloc(sizeof(ulink_recv_t)); memset(t, 0, sizeof(ulink_recv_t)); /* init the pcap */ { char errbuf[PCAP_ERRBUF_SIZE]; t->pcap_handle = pcap_create(netdev, errbuf); if (NULL == t->pcap_handle) { LOG_("pcap_open_live failed. %s", errbuf); free(t); return NULL; } err = pcap_set_snaplen(t->pcap_handle, 128); if (err) { LOG_("pcap_set_snaplen failed: %s", pcap_statustostr(err)); pcap_close(t->pcap_handle); free(t); return NULL; } err = pcap_set_rfmon(t->pcap_handle, 1); if (err) { LOG_("pcap_set_rfmon failed: %s", pcap_statustostr(err)); pcap_close(t->pcap_handle); free(t); return NULL; } err = pcap_set_timeout(t->pcap_handle, CHANNEL_SCAN_TIME); if (err) { LOG_("pcap_set_timeout failed: %s", pcap_statustostr(err)); pcap_close(t->pcap_handle); free(t); return NULL; } err = pcap_activate(t->pcap_handle); if (err) { LOG_("pcap_activate failed: %s", pcap_statustostr(err)); pcap_close(t->pcap_handle); free(t); return NULL; } /* filter */ err = pcap_compile(t->pcap_handle, &t->bpf, "ether multicast and type data subtype qos-data or subtype data", 1, 0); if (err) { LOG_("pcap_compile failed: %s", pcap_geterr(t->pcap_handle)); pcap_close(t->pcap_handle); free(t); return NULL; } err = pcap_setfilter(t->pcap_handle, &t->bpf); if (err) { LOG_("pcap_setfilter failed: %s", pcap_statustostr(err)); pcap_freecode(&t->bpf); pcap_close(t->pcap_handle); free(t); return NULL; } } return t; }
int main (int argc, char *argv[]) { struct pollfd *poll_fd; struct config etherpoke_conf; struct config_filter *filter_iter; struct session_data *pcap_session; struct option_data opt; char conf_errbuff[CONF_ERRBUF_SIZE]; char pcap_errbuff[PCAP_ERRBUF_SIZE]; struct pathname path_config; struct sigaction sa; #ifdef DBG_AVG_LOOP_SPEED clock_t clock_start; double clock_avg; #endif pid_t pid; int i, c, j, rval, syslog_flags, opt_index, filter_cnt, sock, poll_len; struct option opt_long[] = { { "", no_argument, NULL, '4' }, { "", no_argument, NULL, '6' }, { "hostname", required_argument, NULL, 't' }, { "daemon", no_argument, NULL, 'd' }, { "accept-max", required_argument, NULL, 'm' }, { "verbose", no_argument, NULL, 'V' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0 } }; sock = -1; poll_fd = NULL; pcap_session = NULL; exitno = EXIT_SUCCESS; syslog_flags = LOG_PID | LOG_PERROR; #ifdef DBG_AVG_LOOP_SPEED clock_avg = 0; #endif memset (&opt, 0, sizeof (struct option_data)); opt.accept_max = ACCEPT_MAX; opt.ip_version = AF_UNSPEC; memset (&path_config, 0, sizeof (struct pathname)); memset (ðerpoke_conf, 0, sizeof (struct config)); while ( (c = getopt_long (argc, argv, "46t:dm:Vhv", opt_long, &opt_index)) != -1 ){ switch ( c ){ case 'd': opt.daemon = 1; break; case 't': rval = hostformat_parse (optarg, opt.hostname, opt.port); if ( rval == -1 || strlen (opt.hostname) == 0 || strlen (opt.port) == 0 ){ fprintf (stderr, "%s: invalid hostname format (expects HOSTNAME:PORT)\n", argv[0]); exitno = EXIT_FAILURE; goto cleanup; } opt.tcp_event = 1; break; case '4': opt.ip_version = AF_INET; break; case '6': opt.ip_version = AF_INET6; break; case 'm': rval = sscanf (optarg, "%u", &(opt.accept_max)); if ( rval < 1 || opt.accept_max == 0 ){ fprintf (stderr, "%s: invalid number for maximum connections\n", argv[0]); exitno = EXIT_FAILURE; goto cleanup; } break; case 'V': opt.verbose = 1; break; case 'h': etherpoke_help (argv[0]); exitno = EXIT_SUCCESS; goto cleanup; case 'v': etherpoke_version (argv[0]); exitno = EXIT_SUCCESS; goto cleanup; default: etherpoke_help (argv[0]); exitno = EXIT_FAILURE; goto cleanup; } } // Check if there are some non-option arguments, these are treated as paths // to configuration files. if ( (argc - optind) == 0 ){ fprintf (stderr, "%s: configuration file not specified. Use '--help' to see usage information.\n", argv[0]); exitno = EXIT_FAILURE; goto cleanup; } // Change working directory to match the dirname of the config file. rval = path_split (argv[optind], &path_config); if ( rval != 0 ){ fprintf (stderr, "%s: cannot split path to configuration file.\n", argv[0]); exitno = EXIT_FAILURE; goto cleanup; } rval = chdir (path_config.dir); if ( rval == -1 ){ fprintf (stderr, "%s: cannot set working directory to '%s': %s\n", argv[0], path_config.dir, strerror (errno)); exitno = EXIT_FAILURE; goto cleanup; } // // Load configuration file // filter_cnt = config_load (ðerpoke_conf, path_config.base, conf_errbuff); if ( filter_cnt == -1 ){ fprintf (stderr, "%s: cannot load configuration file '%s': %s\n", argv[0], argv[optind], conf_errbuff); exitno = EXIT_FAILURE; goto cleanup; } else if ( filter_cnt == 0 ){ fprintf (stderr, "%s: nothing to do, no filters defined.\n", argv[0]); exitno = EXIT_FAILURE; goto cleanup; } // Allocate enough memory for filters (+1 means that we are also allocating // space for listening socket). // NOTE: always allocate space for listening socket here, to move this // allocation inside the block below (where listening socket is actually // allocated) is not a good idea as more complex condition would have to be // used inside the main loop. poll_len = filter_cnt + 1; if ( opt.tcp_event ){ struct addrinfo *host_addr, addr_hint; int opt_val; // Increase poll size to accommodate socket descriptors for clients. poll_len += opt.accept_max; host_addr = NULL; memset (&addr_hint, 0, sizeof (struct addrinfo)); // Setup addrinfo hints addr_hint.ai_family = opt.ip_version; addr_hint.ai_socktype = SOCK_STREAM; addr_hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; rval = getaddrinfo (opt.hostname, opt.port, &addr_hint, &host_addr); if ( rval != 0 ){ fprintf (stderr, "%s: hostname resolve failed: %s\n", argv[0], gai_strerror (rval)); exitno = EXIT_FAILURE; goto cleanup; } sock = socket (host_addr->ai_family, host_addr->ai_socktype | SOCK_NONBLOCK, host_addr->ai_protocol); if ( sock == -1 ){ freeaddrinfo (host_addr); fprintf (stderr, "%s: cannot create socket: %s\n", argv[0], strerror (errno)); exitno = EXIT_FAILURE; goto cleanup; } opt_val = 1; if ( setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof (opt_val)) == -1 ){ freeaddrinfo (host_addr); fprintf (stderr, "%s: cannot set socket options: %s\n", argv[0], strerror (errno)); exitno = EXIT_FAILURE; goto cleanup; } rval = bind (sock, (struct sockaddr*) host_addr->ai_addr, host_addr->ai_addrlen); if ( rval == -1 ){ freeaddrinfo (host_addr); fprintf (stderr, "%s: cannot bind to address: %s\n", argv[0], strerror (errno)); exitno = EXIT_FAILURE; goto cleanup; } rval = listen (sock, LISTEN_QUEUE_LEN); if ( rval == -1 ){ freeaddrinfo (host_addr); fprintf (stderr, "%s: %s\n", argv[0], strerror (errno)); exitno = EXIT_FAILURE; goto cleanup; } freeaddrinfo (host_addr); } pcap_session = (struct session_data*) calloc (filter_cnt, sizeof (struct session_data)); if ( pcap_session == NULL ){ fprintf (stderr, "%s: cannot allocate memory: %s\n", argv[0], strerror (errno)); exitno = EXIT_FAILURE; goto cleanup; } for ( i = 0, filter_iter = etherpoke_conf.head; filter_iter != NULL; i++, filter_iter = filter_iter->next ){ int link_type; session_data_init (&(pcap_session[i])); pcap_session[i].timeout = filter_iter->session_timeout; pcap_session[i].evt_mask = filter_iter->notify; pcap_session[i].filter_name = strdup (filter_iter->name); if ( pcap_session[i].filter_name == NULL ){ fprintf (stderr, "%s: cannot allocate memory: %s\n", argv[0], strerror (errno)); exitno = EXIT_FAILURE; goto cleanup; } if ( filter_iter->notify & NOTIFY_EXEC ){ if ( filter_iter->session_begin != NULL ){ rval = wordexp (filter_iter->session_begin, &(pcap_session[i].evt_cmd_beg), WORDEXP_FLAGS); if ( rval != 0 ) goto filter_error; } if ( filter_iter->session_error != NULL ){ rval = wordexp (filter_iter->session_error, &(pcap_session[i].evt_cmd_err), WORDEXP_FLAGS); if ( rval != 0 ) goto filter_error; } if ( filter_iter->session_end != NULL ){ rval = wordexp (filter_iter->session_end, &(pcap_session[i].evt_cmd_end), WORDEXP_FLAGS); if ( rval != 0 ) goto filter_error; } filter_error: switch ( rval ){ case WRDE_SYNTAX: fprintf (stderr, "%s: invalid event hook in '%s': syntax error\n", argv[0], filter_iter->name); exitno = EXIT_FAILURE; goto cleanup; case WRDE_BADCHAR: fprintf (stderr, "%s: invalid event hook in '%s': bad character\n", argv[0], filter_iter->name); exitno = EXIT_FAILURE; goto cleanup; case WRDE_BADVAL: fprintf (stderr, "%s: invalid event hook in '%s': referencing undefined variable\n", argv[0], filter_iter->name); exitno = EXIT_FAILURE; goto cleanup; case WRDE_NOSPACE: fprintf (stderr, "%s: cannot expand event hook string in '%s': out of memory\n", argv[0], filter_iter->name); exitno = EXIT_FAILURE; goto cleanup; } } pcap_session[i].handle = pcap_create (filter_iter->interface, pcap_errbuff); if ( pcap_session[i].handle == NULL ){ fprintf (stderr, "%s: cannot start packet capture: %s\n", argv[0], pcap_errbuff); exitno = EXIT_FAILURE; goto cleanup; } rval = pcap_set_rfmon (pcap_session[i].handle, filter_iter->rfmon); if ( rval != 0 ){ fprintf (stderr, "%s: cannot enable monitor mode on interface '%s': %s\n", argv[0], filter_iter->interface, pcap_geterr (pcap_session[i].handle)); exitno = EXIT_FAILURE; goto cleanup; } rval = pcap_set_promisc (pcap_session[i].handle, !(filter_iter->rfmon)); if ( rval != 0 ){ fprintf (stderr, "%s: cannot enable promiscuous mode on interface '%s'\n", argv[0], filter_iter->interface); exitno = EXIT_FAILURE; goto cleanup; } rval = pcap_set_timeout (pcap_session[i].handle, SELECT_TIMEOUT_MS); if ( rval != 0 ){ fprintf (stderr, "%s: cannot set read timeout on interface '%s': %s\n", argv[0], filter_iter->interface, pcap_geterr (pcap_session[i].handle)); exitno = EXIT_FAILURE; goto cleanup; } rval = pcap_setnonblock (pcap_session[i].handle, 1, pcap_errbuff); if ( rval == -1 ){ fprintf (stderr, "%s: cannot set nonblock mode on packet capture resource: %s\n", argv[0], pcap_errbuff); exitno = EXIT_FAILURE; goto cleanup; } rval = pcap_activate (pcap_session[i].handle); if ( rval != 0 ){ fprintf (stderr, "%s: cannot activate packet capture on interface '%s': %s\n", argv[0], filter_iter->interface, pcap_geterr (pcap_session[i].handle)); exitno = EXIT_FAILURE; goto cleanup; } // Set link-layer type from configuration file. if ( filter_iter->link_type != NULL ){ link_type = pcap_datalink_name_to_val (filter_iter->link_type); if ( link_type == -1 ){ fprintf (stderr, "%s: cannot convert link-layer type '%s': unknown link-layer type name\n", argv[0], filter_iter->link_type); exitno = EXIT_FAILURE; goto cleanup; } } else { // If no link-layer type is specified in the configuration file, // use default value. At this point I am sticking with DLTs used by // wireshark on hardware I have available. Different values may // apply to different hardware/driver, therefore more research time // should be put into finding 'best' values. // More information: http://www.tcpdump.org/linktypes.html if ( filter_iter->rfmon ){ link_type = DLT_IEEE802_11_RADIO; } else { link_type = DLT_EN10MB; } } rval = pcap_set_datalink (pcap_session[i].handle, link_type); if ( rval == -1 ){ fprintf (stderr, "%s: cannot set data-link type: %s\n", argv[0], pcap_geterr (pcap_session[i].handle)); exitno = EXIT_FAILURE; goto cleanup; } if ( filter_iter->match != NULL ){ struct bpf_program bpf_prog; rval = pcap_compile (pcap_session[i].handle, &bpf_prog, filter_iter->match, 0, PCAP_NETMASK_UNKNOWN); if ( rval == -1 ){ fprintf (stderr, "%s: cannot compile the filter '%s' match rule: %s\n", argv[0], filter_iter->name, pcap_geterr (pcap_session[i].handle)); exitno = EXIT_FAILURE; goto cleanup; } rval = pcap_setfilter (pcap_session[i].handle, &bpf_prog); if ( rval == -1 ){ fprintf (stderr, "%s: cannot apply the filter '%s' on interface '%s': %s\n", argv[0], filter_iter->name, filter_iter->interface, pcap_geterr (pcap_session[i].handle)); exitno = EXIT_FAILURE; goto cleanup; } pcap_freecode (&bpf_prog); } pcap_session[i].fd = pcap_get_selectable_fd (pcap_session[i].handle); if ( pcap_session[i].fd == -1 ){ fprintf (stderr, "%s: cannot obtain file descriptor for packet capture interface '%s'\n", argv[0], filter_iter->interface); exitno = EXIT_FAILURE; goto cleanup; } } // We no longer need data stored in config structure. All neccessary data // were moved into session_data structure. config_unload (ðerpoke_conf); poll_fd = (struct pollfd*) malloc (sizeof (struct pollfd) * poll_len); if ( poll_fd == NULL ){ fprintf (stderr, "%s: cannot allocate memory: %s\n", argv[0], strerror (errno)); exitno = EXIT_FAILURE; goto cleanup; } // Populate poll structure... for ( i = 0; i < poll_len; i++ ){ // ... with pcap file descriptors... if ( i < filter_cnt ) poll_fd[i].fd = pcap_session[i].fd; // ... listening socket... else if ( i == filter_cnt ) poll_fd[i].fd = sock; // ... invalid file descriptors (will be ignored by poll(2)), in space reserved for client sockets... else poll_fd[i].fd = -1; poll_fd[i].events = POLLIN | POLLERR; poll_fd[i].revents = 0; } // // Setup signal handler // sa.sa_handler = etherpoke_sigdie; sigemptyset (&(sa.sa_mask)); sa.sa_flags = 0; rval = 0; rval &= sigaction (SIGINT, &sa, NULL); rval &= sigaction (SIGQUIT, &sa, NULL); rval &= sigaction (SIGTERM, &sa, NULL); sa.sa_handler = SIG_IGN; sigemptyset (&(sa.sa_mask)); sa.sa_flags = 0; rval &= sigaction (SIGCHLD, &sa, NULL); if ( rval != 0 ){ fprintf (stderr, "%s: cannot setup signal handler: %s\n", argv[0], strerror (errno)); exitno = EXIT_FAILURE; goto cleanup; } // // Daemonize the process if the flag was set // if ( opt.daemon == 1 ){ pid = fork (); if ( pid > 0 ){ exitno = EXIT_SUCCESS; goto cleanup; } else if ( pid == -1 ){ fprintf (stderr, "%s: cannot daemonize the process (fork failed).\n", argv[0]); exitno = EXIT_FAILURE; goto cleanup; } if ( setsid () == -1 ){ fprintf (stderr, "%s: cannot daemonize the process (setsid failed).\n", argv[0]); exitno = EXIT_FAILURE; goto cleanup; } umask (0); freopen ("/dev/null", "r", stdin); freopen ("/dev/null", "w", stdout); freopen ("/dev/null", "w", stderr); syslog_flags = LOG_PID; } openlog ("etherpoke", syslog_flags, LOG_DAEMON); syslog (LOG_INFO, "Etherpoke started (loaded filters: %u)", filter_cnt); if ( opt.tcp_event ) syslog (LOG_INFO, "Event notifications available via %s:%s (ACCEPT_MAX: %u)", opt.hostname, opt.port, opt.accept_max); // // Main loop // main_loop = 1; while ( main_loop ){ const u_char *pkt_data; struct pcap_pkthdr *pkt_header; time_t current_time; errno = 0; rval = poll (poll_fd, poll_len, SELECT_TIMEOUT_MS); if ( rval == -1 ){ if ( errno == EINTR ) continue; syslog (LOG_ERR, "poll(2) failed: %s", strerror (errno)); exitno = EXIT_FAILURE; goto cleanup; } #ifdef DBG_AVG_LOOP_SPEED clock_start = clock (); #endif // Accept incoming connection if ( poll_fd[filter_cnt].revents & POLLIN ){ int sock_new; sock_new = accept (sock, NULL, NULL); if ( sock_new == -1 ){ syslog (LOG_ERR, "cannot accept new connection: %s", strerror (errno)); exitno = EXIT_FAILURE; goto cleanup; } // Find unused place in the poll array for ( j = (filter_cnt + 1); j < poll_len; j++ ){ if ( poll_fd[j].fd == -1 ){ poll_fd[j].fd = sock_new; sock_new = -1; break; } } if ( sock_new != -1 ){ if ( opt.verbose ) syslog (LOG_INFO, "Client refused: too many concurrent connections"); close (sock_new); } else { if ( opt.verbose ) syslog (LOG_INFO, "Client connected..."); } } // Take care of incoming client data. At this point only shutdown and // close is handled, no other input is expected from the clients. for ( i = (filter_cnt + 1); i < poll_len; i++ ){ if ( poll_fd[i].revents & POLLIN ){ char nok[128]; errno = 0; rval = recv (poll_fd[i].fd, nok, sizeof (nok), MSG_DONTWAIT); if ( rval <= 0 && (errno != EAGAIN && errno != EWOULDBLOCK) ){ if ( opt.verbose ) syslog (LOG_INFO, "Client disconnected..."); close (poll_fd[i].fd); poll_fd[i].fd = -1; } } } time (¤t_time); // Handle changes on pcap file descriptors for ( i = 0; i < filter_cnt; i++ ){ wordexp_t *cmd_exp; const char *evt_str; // Handle incoming packet if ( (poll_fd[i].revents & POLLIN) || (poll_fd[i].revents & POLLERR) ){ rval = pcap_next_ex (pcap_session[i].handle, &pkt_header, &pkt_data); if ( rval == 1 ){ if ( pcap_session[i].evt.ts == 0 ) pcap_session[i].evt.type = SE_BEG; pcap_session[i].evt.ts = pkt_header->ts.tv_sec; } else if ( rval < 0 ){ pcap_session[i].evt.type = SE_ERR; } } if ( (pcap_session[i].evt.ts > 0) && (difftime (current_time, pcap_session[i].evt.ts) >= pcap_session[i].timeout) ){ pcap_session[i].evt.type = SE_END; } switch ( pcap_session[i].evt.type ){ case SE_NUL: // There was no change on this file descriptor, skip to // another one. 'continue' may seem a bit confusing here, // but it applies to a loop above. Not sure how other // compilers will behave (other than gcc). continue; case SE_BEG: evt_str = "BEG"; cmd_exp = &(pcap_session[i].evt_cmd_beg); pcap_session[i].evt.type = SE_NUL; break; case SE_END: cmd_exp = &(pcap_session[i].evt_cmd_end); evt_str = "END"; pcap_session[i].evt.type = SE_NUL; pcap_session[i].evt.ts = 0; break; case SE_ERR: evt_str = "ERR"; cmd_exp = &(pcap_session[i].evt_cmd_err); pcap_session[i].evt.type = SE_NUL; pcap_session[i].evt.ts = 0; break; default: // Undefined state... What to do, other than die? syslog (LOG_ERR, "undefined event type"); exitno = EXIT_FAILURE; goto cleanup; } if ( opt.verbose ) syslog (LOG_INFO, "%s:%s", pcap_session[i].filter_name, evt_str); // Send socket notification if ( pcap_session[i].evt_mask & NOTIFY_SOCK ){ char msg[CONF_FILTER_NAME_MAXLEN + 5]; snprintf (msg, sizeof (msg), "%s:%s", pcap_session[i].filter_name, evt_str); for ( j = (filter_cnt + 1); j < poll_len; j++ ){ if ( poll_fd[j].fd == -1 ) continue; errno = 0; rval = send (poll_fd[j].fd, msg, strlen (msg) + 1, MSG_NOSIGNAL | MSG_DONTWAIT); if ( rval == -1 && (errno != EAGAIN && errno != EWOULDBLOCK) ){ syslog (LOG_WARNING, "failed to send notification: %s", strerror (errno)); close (poll_fd[j].fd); poll_fd[j].fd = -1; } } } // Execute an event hook if ( pcap_session[i].evt_mask & NOTIFY_EXEC ){ // Expansion was not made... if ( cmd_exp->we_wordc == 0 ) continue; pid = fork (); if ( pid == -1 ){ syslog (LOG_ERR, "cannot fork the process: %s", strerror (errno)); exitno = EXIT_FAILURE; goto cleanup; } // Parent process, carry on... if ( pid > 0 ) continue; errno = 0; execv (cmd_exp->we_wordv[0], cmd_exp->we_wordv); // This code gets executed only if execv(3) fails. Wrapping // this code in a condition is unneccessary. syslog (LOG_WARNING, "cannot execute event hook in '%s': %s", pcap_session[i].filter_name, strerror (errno)); exitno = EXIT_FAILURE; goto cleanup; } } #ifdef DBG_AVG_LOOP_SPEED clock_avg = (clock_avg + (clock () - clock_start)) / 2; syslog (LOG_DEBUG, "Average loop speed: %lf", (double) (clock_avg / CLOCKS_PER_SEC)); #endif } syslog (LOG_INFO, "Etherpoke shutdown (signal %u)", exitno); cleanup: closelog (); if ( pcap_session != NULL ){ for ( i = 0; i < filter_cnt; i++ ) session_data_free (&(pcap_session[i])); free (pcap_session); } if ( poll_fd != NULL ) free (poll_fd); if ( sock != -1 ) close (sock); config_unload (ðerpoke_conf); path_free (&path_config); return exitno; }
inline void set_monitor_mode(pcap_t *source, const bool flag) { if (pcap_set_rfmon(source, flag) != 0) { throw already_activated_error{source}; } }
int main(int argc, char **argv) { char *cp, *device; int op; int dorfmon, useactivate; char ebuf[PCAP_ERRBUF_SIZE]; char *infile; char *cmdbuf; pcap_t *pd; int status = 0; int pcap_fd; #if defined(USE_BPF) struct bpf_program bad_fcode; struct bpf_insn uninitialized[INSN_COUNT]; #elif defined(USE_SOCKET_FILTERS) struct sock_fprog bad_fcode; struct sock_filter uninitialized[INSN_COUNT]; #endif struct bpf_program fcode; device = NULL; dorfmon = 0; useactivate = 0; infile = NULL; if ((cp = strrchr(argv[0], '/')) != NULL) program_name = cp + 1; else program_name = argv[0]; opterr = 0; while ((op = getopt(argc, argv, "aF:i:I")) != -1) { switch (op) { case 'a': useactivate = 1; break; case 'F': infile = optarg; break; case 'i': device = optarg; break; case 'I': dorfmon = 1; useactivate = 1; /* required for rfmon */ break; default: usage(); /* NOTREACHED */ } } if (device == NULL) { /* * No interface specified; get whatever pcap_lookupdev() * finds. */ device = pcap_lookupdev(ebuf); if (device == NULL) { error("couldn't find interface to use: %s", ebuf); } } if (infile != NULL) { /* * Filter specified with "-F" and a file containing * a filter. */ cmdbuf = read_infile(infile); } else { if (optind < argc) { /* * Filter specified with arguments on the * command line. */ cmdbuf = copy_argv(&argv[optind+1]); } else { /* * No filter specified; use an empty string, which * compiles to an "accept all" filter. */ cmdbuf = ""; } } if (useactivate) { pd = pcap_create(device, ebuf); if (pd == NULL) error("%s: pcap_create() failed: %s", device, ebuf); status = pcap_set_snaplen(pd, 65535); if (status != 0) error("%s: pcap_set_snaplen failed: %s", device, pcap_statustostr(status)); status = pcap_set_promisc(pd, 1); if (status != 0) error("%s: pcap_set_promisc failed: %s", device, pcap_statustostr(status)); if (dorfmon) { status = pcap_set_rfmon(pd, 1); if (status != 0) error("%s: pcap_set_rfmon failed: %s", device, pcap_statustostr(status)); } status = pcap_set_timeout(pd, 1000); if (status != 0) error("%s: pcap_set_timeout failed: %s", device, pcap_statustostr(status)); status = pcap_activate(pd); if (status < 0) { /* * pcap_activate() failed. */ error("%s: %s\n(%s)", device, pcap_statustostr(status), pcap_geterr(pd)); } else if (status > 0) { /* * pcap_activate() succeeded, but it's warning us * of a problem it had. */ warning("%s: %s\n(%s)", device, pcap_statustostr(status), pcap_geterr(pd)); } } else { *ebuf = '\0'; pd = pcap_open_live(device, 65535, 1, 1000, ebuf); if (pd == NULL) error("%s", ebuf); else if (*ebuf) warning("%s", ebuf); } pcap_fd = pcap_fileno(pd); /* * Try setting a filter with an uninitialized bpf_program * structure. This should cause valgrind to report a * problem. * * We don't check for errors, because it could get an * error due to a bad pointer or count. */ #if defined(USE_BPF) ioctl(pcap_fd, BIOCSETF, &bad_fcode); #elif defined(USE_SOCKET_FILTERS) setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, sizeof(bad_fcode)); #endif /* * Try setting a filter with an initialized bpf_program * structure that points to an uninitialized program. * That should also cause valgrind to report a problem. * * We don't check for errors, because it could get an * error due to a bad pointer or count. */ #if defined(USE_BPF) bad_fcode.bf_len = INSN_COUNT; bad_fcode.bf_insns = uninitialized; ioctl(pcap_fd, BIOCSETF, &bad_fcode); #elif defined(USE_SOCKET_FILTERS) bad_fcode.len = INSN_COUNT; bad_fcode.filter = uninitialized; setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, sizeof(bad_fcode)); #endif /* * Now compile a filter and set the filter with that. * That should *not* cause valgrind to report a * problem. */ if (pcap_compile(pd, &fcode, cmdbuf, 1, 0) < 0) error("can't compile filter: %s", pcap_geterr(pd)); if (pcap_setfilter(pd, &fcode) < 0) error("can't set filter: %s", pcap_geterr(pd)); pcap_close(pd); exit(status < 0 ? 1 : 0); }
int main(int argc, char **argv) { /* default values for command line arguments (see also static variables) */ const char *if_name = PCAPPRINT_DEF_IFNAME; int snaplen = PCAPPRINT_DEF_SNAPLEN; const char *dlt_name = PCAPPRINT_DEF_DLTNAME; int num_pkts = -1; const char *pcap_filename = NULL; const char *bpf_expr = NULL; int rfmon = 0; /* process command line options */ const char *usage = "usage: pcap-print [options]\n"; int c; while ((c = getopt(argc, argv, ":1234ab:c:dfhi:mNqr:s:tVy:")) != -1) { switch (c) { case '1': case '2': case '3': case '4': enabled_layers[c-'0'-1]++; break; case 'a': /* arbitrary "big" number */ enabled_layers[0] = 100; enabled_layers[1] = 100; enabled_layers[2] = 100; enabled_layers[3] = 100; break; case 'b': bpf_expr = optarg; break; case 'c': num_pkts = atoi(optarg); break; case 'd': tsfmt = TS_CTIME; break; case 'f': print_fcs = 1; break; case 'h': printf(usage); printf( " -1 print data-link header (e.g. Ethernet)\n" " -2 print network header (e.g. IP)\n" " -3 print transport header (e.g. TCP)\n" " -4 print application header (e.g. HTTP)\n" " -a print ALL headers, with maximum verbosity\n" " -b specify a BPF filter\n" " -c print only first N packets\n" " -d print absolute timestamp in date format\n" " -f print FCS for MAC headers\n" " -h print usage information and quit\n" " -i network interface on which to capture packets" " (default: %s)\n" " -m set rfmon mode on interface\n" " -N number packets as they are printed\n" " -q suppress printing of packet-parsing errors\n" " -r read from pcap file instead of live capture\n" " -s capture size in bytes (default: %d)\n" " -t print absolute timestamp\n" " -V print pcap version and quit\n" " -y datalink type for capturing interface (default: %s)\n", PCAPPRINT_DEF_IFNAME, PCAPPRINT_DEF_SNAPLEN, PCAPPRINT_DEF_DLTNAME); exit(0); break; case 'i': if_name = optarg; break; case 'm': rfmon = 1; break; case 'N': use_numbering = 1; break; case 'q': quiet = 1; break; case 'r': pcap_filename = optarg; break; case 's': snaplen = (int)strtol(optarg, (char **)NULL, 10); break; case 't': tsfmt = TS_ABS; break; case 'V': printf("%s\n", pcap_lib_version()); exit(0); break; case 'y': dlt_name = optarg; break; case ':': errx(1, "option -%c requires an operand", optopt); break; case '?': errx(1, "unrecognized option: -%c", optopt); break; default: /* unhandled option indicates programming error */ assert(0); } } /* if no layers we specified, use defaults (hard-coded) */ if (! (enabled_layers[0] || enabled_layers[1] || enabled_layers[2] || enabled_layers[3])) { enabled_layers[1] = 1; enabled_layers[2] = 1; } /* create pcap handle (either from file or from live capture) */ char ebuf[PCAP_ERRBUF_SIZE]; *ebuf = '\0'; /* used only if a BPF program (filter) is specified */ bpf_u_int32 netnum = 0, netmask = 0; if (pcap_filename != NULL) { /* "capture" from file */ if (strcmp(if_name, PCAPPRINT_DEF_IFNAME) != 0) warnx("warning: -i option ignored when -f option is present"); if (snaplen != PCAPPRINT_DEF_SNAPLEN) warnx("warning: -s option ignored when -f option is present"); if (strcmp(dlt_name, PCAPPRINT_DEF_DLTNAME) != 0) warnx("warning: -y option ignored when -f option is present"); pcap_h = pcap_open_offline(pcap_filename, ebuf); if (pcap_h == NULL) errx(1, "pcap_open_offline: %s", ebuf); else if (*ebuf) warnx("pcap_open_offline: %s", ebuf); /* read dlt from file */ dlt = pcap_datalink(pcap_h); } else { /* live capture */ dlt = pcap_datalink_name_to_val(dlt_name); if (dlt < 0) err(1, "invalid data link type %s", dlt_name); pcap_h = pcap_create(if_name, ebuf); if (pcap_h == NULL) errx(1, "pcap_create: %s", ebuf); if (pcap_set_snaplen(pcap_h, snaplen) != 0) errx(1, "pcap_set_snaplen: %s", pcap_geterr(pcap_h)); if (pcap_set_promisc(pcap_h, 1) != 0) errx(1, "pcap_set_promisc: %s", pcap_geterr(pcap_h)); if (rfmon) { if (pcap_can_set_rfmon(pcap_h) == 0) errx(1, "cannot set rfmon mode on device %s", if_name); if (pcap_set_rfmon(pcap_h, 1) != 0) errx(1, "pcap_set_rfmon: %s", pcap_geterr(pcap_h)); } if (pcap_set_buffer_size(pcap_h, PCAPPRINT_BPF_BUFSIZE) != 0) errx(1, "pcap_set_buffer_size: %s", pcap_geterr(pcap_h)); if (pcap_set_timeout(pcap_h, PCAPPRINT_READ_TIMEOUT) != 0) errx(1, "pcap_set_timeout: %s", pcap_geterr(pcap_h)); if (pcap_lookupnet(if_name, &netnum, &netmask, ebuf) == -1) errx(1, "pcap_lookupnet: %s", ebuf); if (pcap_activate(pcap_h) != 0) errx(1, "pcap_activate: %s", pcap_geterr(pcap_h)); /* * the following calls must be done AFTER pcap_activate(): * pcap_setfilter * pcap_setdirection * pcap_set_datalink * pcap_getnonblock * pcap_setnonblock * pcap_stats * all reads/writes */ if (pcap_set_datalink(pcap_h, dlt) == -1) errx(1, "pcap_set_datalink: %s", pcap_geterr(pcap_h)); int r, yes = 1; int pcap_fd = pcap_get_selectable_fd(pcap_h); if ((r = ioctl(pcap_fd, BIOCIMMEDIATE, &yes)) == -1) err(1, "BIOCIMMEDIATE"); else if (r != 0) warnx("BIOCIMMEDIATE returned %d", r); /* set up signal handlers */ if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, signal_handler); if (signal(SIGTERM, SIG_IGN) != SIG_IGN) signal(SIGTERM, signal_handler); } /* apply BPF filter (if one was specified) */ if (bpf_expr != NULL) { struct bpf_program bpf; if (pcap_compile(pcap_h, &bpf, bpf_expr, 1 /*optimize*/, netmask) == -1) errx(1, "pcap_compile: %s", pcap_geterr(pcap_h)); if (pcap_setfilter(pcap_h, &bpf) == -1) errx(1, "pcap_setfilter: %s", pcap_geterr(pcap_h)); } /* start reading packets */ if (pcap_loop(pcap_h, num_pkts, handle_packet, NULL) == -1) errx(1, "pcap_loop: %s", pcap_geterr(pcap_h)); if (pcap_filename == NULL) { /* if live capture.. */ printf("%u packets captured\n", pkt_count); struct pcap_stat stats; if (pcap_stats(pcap_h, &stats) != 0) { warnx("pcap_stats: %s", pcap_geterr(pcap_h)); } else { printf("%u packets received by filter\n" "%u packets dropped by kernel\n", stats.ps_recv, stats.ps_drop); } } pcap_close(pcap_h); return 0; }