PCAPExporterCfg::PCAPExporterCfg(XMLElement* elem) : CfgHelper<PCAPExporterModule, PCAPExporterCfg>(elem, "pcapExporter"), link_type(DLT_EN10MB) { if (!elem) return; XMLNode::XMLSet<XMLElement*> set = elem->getElementChildren(); for (XMLNode::XMLSet<XMLElement*>::iterator it = set.begin(); it != set.end(); it++) { XMLElement* e = *it; if (e->matches("filename")) { fileName = e->getFirstText(); } else if (e->matches("linkType")) { int tmp = pcap_datalink_name_to_val(e->getFirstText().c_str()); if (tmp == -1) { msg(MSG_ERROR, "Found illegal link type"); } else { link_type = tmp; } } else if (e->matches("snaplen")) { snaplen = getInt("snaplen", PCAP_MAX_CAPTURE_LENGTH, e); } } }
/* Setup filter resources */ static int pf_capture_setup(netio_desc_t *nio,void **opt, int argc,char *argv[]) { struct netio_filter_capture *c; int link_type; /* We must have a link type and a filename */ if (argc != 2) return(-1); /* Free resources if something has already been done */ pf_capture_free(nio,opt); /* Allocate structure to hold PCAP info */ if (!(c = malloc(sizeof(*c)))) return(-1); if (pthread_mutex_init(&c->lock,NULL)) { fprintf(stderr,"NIO %s: pthread_mutex_init failure (file %s)\n", nio->name,argv[0]); goto pcap_lock_err; } if ((link_type = pcap_datalink_name_to_val(argv[0])) == -1) { fprintf(stderr,"NIO %s: unknown link type %s, assuming Ethernet.\n", nio->name,argv[0]); link_type = DLT_EN10MB; } /* Open a dead pcap descriptor */ if (!(c->desc = pcap_open_dead(link_type,8192))) { fprintf(stderr,"NIO %s: pcap_open_dead failure\n",nio->name); goto pcap_open_err; } /* Open the output file */ if (!(c->dumper = pcap_dump_open(c->desc,argv[1]))) { fprintf(stderr,"NIO %s: pcap_dump_open failure (file %s)\n", nio->name,argv[0]); goto pcap_dump_err; } printf("NIO %s: capturing to file '%s'\n",nio->name,argv[1]); *opt = c; return(0); pcap_dump_err: pcap_close(c->desc); pcap_open_err: pthread_mutex_destroy(&c->lock); pcap_lock_err: free(c); return(-1); }
int main(int argc, char **argv) { char *cp; int op; int dflag; char *infile; int Oflag; long snaplen; int dlt; bpf_u_int32 netmask = PCAP_NETMASK_UNKNOWN; char *cmdbuf; pcap_t *pd; struct bpf_program fcode; #ifdef WIN32 if(wsockinit() != 0) return 1; #endif /* WIN32 */ dflag = 1; infile = NULL; Oflag = 1; snaplen = 68; if ((cp = strrchr(argv[0], '/')) != NULL) program_name = cp + 1; else program_name = argv[0]; opterr = 0; while ((op = getopt(argc, argv, "dF:m:Os:")) != -1) { switch (op) { case 'd': ++dflag; break; case 'F': infile = optarg; break; case 'O': Oflag = 0; break; case 'm': { in_addr_t addr; addr = inet_addr(optarg); if (addr == INADDR_NONE) error("invalid netmask %s", optarg); netmask = addr; break; } case 's': { char *end; snaplen = strtol(optarg, &end, 0); if (optarg == end || *end != '\0' || snaplen < 0 || snaplen > 65535) error("invalid snaplen %s", optarg); else if (snaplen == 0) snaplen = 65535; break; } default: usage(); /* NOTREACHED */ } } if (optind >= argc) { usage(); /* NOTREACHED */ } dlt = pcap_datalink_name_to_val(argv[optind]); if (dlt < 0) error("invalid data link type %s", argv[optind]); if (infile) cmdbuf = read_infile(infile); else cmdbuf = copy_argv(&argv[optind+1]); pd = pcap_open_dead(dlt, snaplen); if (pd == NULL) error("Can't open fake pcap_t"); if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) error("%s", pcap_geterr(pd)); if (!bpf_validate(fcode.bf_insns, fcode.bf_len)) warn("Filter doesn't pass validation"); bpf_dump(&fcode, dflag); pcap_close(pd); exit(0); }
int main(int argc, char **argv) { char *cp; int op; #ifndef BDEBUG int dflag; #endif char *infile; int Oflag; long snaplen; char *p; int dlt; int have_fcode = 0; bpf_u_int32 netmask = PCAP_NETMASK_UNKNOWN; char *cmdbuf; pcap_t *pd; struct bpf_program fcode; #ifdef _WIN32 if (pcap_wsockinit() != 0) return 1; #endif /* _WIN32 */ #ifndef BDEBUG dflag = 1; #else /* if optimizer debugging is enabled, output DOT graph * `dflag=4' is equivalent to -dddd to follow -d/-dd/-ddd * convention in tcpdump command line */ dflag = 4; #endif infile = NULL; Oflag = 1; snaplen = 68; if ((cp = strrchr(argv[0], '/')) != NULL) program_name = cp + 1; else program_name = argv[0]; opterr = 0; while ((op = getopt(argc, argv, "dF:m:Os:")) != -1) { switch (op) { case 'd': ++dflag; break; case 'F': infile = optarg; break; case 'O': Oflag = 0; break; case 'm': { bpf_u_int32 addr; switch (inet_pton(AF_INET, optarg, &addr)) { case 0: error("invalid netmask %s", optarg); break; case -1: error("invalid netmask %s: %s", optarg, pcap_strerror(errno)); break; case 1: netmask = addr; break; } break; } case 's': { char *end; snaplen = strtol(optarg, &end, 0); if (optarg == end || *end != '\0' || snaplen < 0 || snaplen > 65535) error("invalid snaplen %s", optarg); else if (snaplen == 0) snaplen = 65535; break; } default: usage(); /* NOTREACHED */ } } if (optind >= argc) { usage(); /* NOTREACHED */ } dlt = pcap_datalink_name_to_val(argv[optind]); if (dlt < 0) { dlt = (int)strtol(argv[optind], &p, 10); if (p == argv[optind] || *p != '\0') error("invalid data link type %s", argv[optind]); } if (infile) cmdbuf = read_infile(infile); else cmdbuf = copy_argv(&argv[optind+1]); pd = pcap_open_dead(dlt, snaplen); if (pd == NULL) error("Can't open fake pcap_t"); if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) error("%s", pcap_geterr(pd)); have_fcode = 1; if (!bpf_validate(fcode.bf_insns, fcode.bf_len)) warn("Filter doesn't pass validation"); #ifdef BDEBUG if (cmdbuf != NULL) { // replace line feed with space for (cp = cmdbuf; *cp != '\0'; ++cp) { if (*cp == '\r' || *cp == '\n') { *cp = ' '; } } // only show machine code if BDEBUG defined, since dflag > 3 printf("machine codes for filter: %s\n", cmdbuf); } else printf("machine codes for empty filter:\n"); #endif bpf_dump(&fcode, dflag); free(cmdbuf); if (have_fcode) pcap_freecode (&fcode); pcap_close(pd); exit(0); }
int CDECL wine_pcap_datalink_name_to_val(const char *name) { TRACE("(%s)\n", debugstr_a(name)); return pcap_datalink_name_to_val(name); }
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; }
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; }