Пример #1
0
 /**
  * Same as WaitDone(), but automatically lock and unlock the mutex.
  *
  * Caller must not lock the mutex.
  */
 void LockWaitDone() {
     ScopeLock protect(mutex);
     WaitDone();
 }
Пример #2
0
int main(int argc, char *argv[]) {
sigset_t			signal_set;
struct sigaction	sa;
int c, snaplen, err, do_daemonize;
int subdir_index, compress, expire, cache_size;
FlowSource_t	*fs;
dirstat_t 		*dirstat;
time_t 			t_win;
char 			*device, *pcapfile, *filter, *datadir, *pcap_datadir, *extension_tags, pidfile[MAXPATHLEN], pidstr[32];
char			*Ident, *userid, *groupid;
pcap_dev_t 		*pcap_dev;
p_packet_thread_args_t *p_packet_thread_args;
p_flow_thread_args_t *p_flow_thread_args;

	snaplen			= 100;
	do_daemonize	= 0;
	launcher_pid	= 0;
	device			= NULL;
	pcapfile		= NULL;
	filter			= NULL;
	pidfile[0]		= '\0';
	t_win			= TIME_WINDOW;
	datadir			= DEFAULT_DIR;
	pcap_datadir	= NULL;
	userid			= groupid = NULL;
	Ident			= "none";
	fs				= NULL;
	extension_tags	= DefaultExtensions;
	subdir_index	= 0;
	compress		= NOT_COMPRESSED;
	verbose			= 0;
	expire			= 0;
	cache_size		= 0;
	while ((c = getopt(argc, argv, "B:DEI:g:hi:j:r:s:l:p:P:t:u:S:T:e:Vz")) != EOF) {
		switch (c) {
			struct stat fstat;
			case 'h':
				usage(argv[0]);
				exit(0);
				break;
			case 'u':
				userid  = optarg;
				break;
			case 'g':
				groupid  = optarg;
				break;
			case 'D':
				do_daemonize = 1;
				break;
			case 'B':
				cache_size = atoi(optarg);
				if (cache_size <= 0) {
					LogError("ERROR: Cache size must not be < 0");
					exit(EXIT_FAILURE);
				}
				break;
			case 'I':
				Ident = strdup(optarg);
				break;
			case 'i':
				device = optarg;
				break;
			case 'l':
				datadir = optarg;
				err  = stat(datadir, &fstat);
				if (!(fstat.st_mode & S_IFDIR)) {
					LogError("No such directory: " "'%s'", datadir);
					break;
				}
				break;
			case 'p':
				pcap_datadir = optarg;
				err  = stat(pcap_datadir, &fstat);
				if (!(fstat.st_mode & S_IFDIR)) {
					LogError("No such directory: " "'%s'", pcap_datadir);
					break;
				}
				break;
			case 'r': {
				struct stat stat_buf;
				pcapfile = optarg;
				if ( stat(pcapfile, &stat_buf) ) {
					LogError("Can't stat '%s': %s", pcapfile, strerror(errno));
					exit(EXIT_FAILURE);
				}
				if (!S_ISREG(stat_buf.st_mode) ) {
					LogError("'%s' is not a file", pcapfile);
					exit(EXIT_FAILURE);
				}
				} break;
			case 's':
				snaplen = atoi(optarg);
				if (snaplen < 14 + 20 + 20) { // ethernet, IP , TCP, no payload
					LogError("ERROR:, snaplen < sizeof IPv4 - Need 54 bytes for TCP/IPv4");
					exit(EXIT_FAILURE);
				}
				break;
			case 't':
				t_win = atoi(optarg);
				if (t_win < 60) {
					LogError("WARNING, very small time frame (< 60)!");
				}
				if (t_win <= 0) {
					LogError("ERROR: time frame too small (<= 0)");
					exit(EXIT_FAILURE);
				}
				break;
			case 'j':
				if ( compress ) {
					LogError("Use either -z for LZO or -j for BZ2 compression, but not both\n");
					exit(255);
				}
				compress = BZ2_COMPRESSED;
				break;
			case 'z':
				if ( compress ) {
					LogError("Use either -z for LZO or -j for BZ2 compression, but not both\n");
					exit(255);
				}
				compress = LZO_COMPRESSED;
				break;
			case 'P':
				if ( optarg[0] == '/' ) { 	// absolute path given
					strncpy(pidfile, optarg, MAXPATHLEN-1);
				} else {					// path relative to current working directory
					char tmp[MAXPATHLEN];
					if ( !getcwd(tmp, MAXPATHLEN-1) ) {
						fprintf(stderr, "Failed to get current working directory: %s\n", strerror(errno));
						exit(255);
					}
					tmp[MAXPATHLEN-1] = 0;
					snprintf(pidfile, MAXPATHLEN - 1 - strlen(tmp), "%s/%s", tmp, optarg);
				}
				// pidfile now absolute path
				pidfile[MAXPATHLEN-1] = 0;
				break;
			case 'S':
				subdir_index = atoi(optarg);
				break;
			case 'T': {
				size_t len = strlen(optarg);
				extension_tags = optarg;
				if ( len == 0 || len > 128 ) {
					fprintf(stderr, "Extension length error. Unexpected option '%s'\n", extension_tags);
					exit(255);
				}
				break; }
			case 'E':
				verbose = 1;
				Setv6Mode(1);
				break;
			case 'V':
				printf("%s: Version: %s\n",argv[0], nfdump_version);
				exit(0);
				break;
			default:
				usage(argv[0]);
				exit(EXIT_FAILURE);
		}
	}

	if (argc - optind > 1) {
		usage(argv[0]);
		exit(EXIT_FAILURE);
	} else {
		/* user specified a pcap filter */
		filter = argv[optind];
	}

	if ( fs == NULL && datadir != NULL && !AddDefaultFlowSource(&fs, Ident, datadir) ) {
		fprintf(stderr, "Failed to add default data collector directory\n");
		exit(255);
	}

	if ( device && pcapfile ) {
		LogError("Specify either a device or a pcapfile, but not both");
		exit(EXIT_FAILURE);
	}

	if ( !device && !pcapfile ) {
		LogError("Specify either a device or a pcapfile to read packets from");
		exit(EXIT_FAILURE);
	}

	
	if ( !Init_FlowTree(cache_size)) {
		LogError("Init_FlowTree() failed.");
		exit(EXIT_FAILURE);
	}

	InitExtensionMaps(NO_EXTENSION_LIST);
	SetupExtensionDescriptors(strdup(extension_tags));

	if ( pcapfile ) {
		pcap_dev = setup_pcap_file(pcapfile, filter, snaplen);
	} else {
		pcap_dev = setup_pcap_live(device, filter, snaplen);
	}
	if (!pcap_dev) {
		exit(EXIT_FAILURE);
	}

	SetPriv(userid, groupid);

	if ( subdir_index && !InitHierPath(subdir_index) ) {
		pcap_close(pcap_dev->handle);
		exit(255);
	}

	if ( do_daemonize && !InitLog(argv[0], SYSLOG_FACILITY)) {
		pcap_close(pcap_dev->handle);
		exit(255);
	}

	// check if pid file exists and if so, if a process with registered pid is running
	if ( strlen(pidfile) ) {
		int pidf;
		pidf = open(pidfile, O_RDONLY, 0);
		if ( pidf > 0 ) {
			// pid file exists
			char s[32];
			ssize_t len;
			len = read(pidf, (void *)s, 31);
			close(pidf);
			s[31] = '\0';
			if ( len < 0 ) {
				fprintf(stderr, "read() error existing pid file: %s\n", strerror(errno));
				pcap_close(pcap_dev->handle);
				exit(255);
			} else {
				unsigned long pid = atol(s);
				if ( pid == 0 ) {
					// garbage - use this file
					unlink(pidfile);
				} else {
					if ( kill(pid, 0) == 0 ) {
						// process exists
						fprintf(stderr, "A process with pid %lu registered in pidfile %s is already running!\n", 
							pid, strerror(errno));
						pcap_close(pcap_dev->handle);
						exit(255);
					} else {
						// no such process - use this file
						unlink(pidfile);
					}
				}
			}
		} else {
			if ( errno != ENOENT ) {
				fprintf(stderr, "open() error existing pid file: %s\n", strerror(errno));
				pcap_close(pcap_dev->handle);
				exit(255);
			} // else errno == ENOENT - no file - this is fine
		}
	}

	if ( do_daemonize ) {
		verbose = 0;
		daemonize();
	}

	if (strlen(pidfile)) {
		pid_t pid = getpid();
		int pidf  = open(pidfile, O_RDWR|O_TRUNC|O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
		if ( pidf == -1 ) {
			LogError("Error opening pid file: '%s' %s", pidfile, strerror(errno));
			pcap_close(pcap_dev->handle);
			exit(255);
		}
		snprintf(pidstr,31,"%lu\n", (unsigned long)pid);
		if ( write(pidf, pidstr, strlen(pidstr)) <= 0 ) {
			LogError("Error write pid file: '%s' %s", pidfile, strerror(errno));
		}
		close(pidf);
	}

	if ( InitBookkeeper(&fs->bookkeeper, fs->datadir, getpid(), launcher_pid) != BOOKKEEPER_OK ) {
			LogError("initialize bookkeeper failed.");
			pcap_close(pcap_dev->handle);
			exit(255);
	}

	// Init the extension map list
	if ( !InitExtensionMapList(fs) ) {
		// error message goes to syslog
		pcap_close(pcap_dev->handle);
		exit(255);
	}

	IPFragTree_init();

	LogInfo("Startup.");
	// prepare signal mask for all threads
	// block signals, as they are handled by the main thread
	// mask is inherited by all threads
	sigemptyset(&signal_set);
	sigaddset(&signal_set, SIGINT);
	sigaddset(&signal_set, SIGHUP);
	sigaddset(&signal_set, SIGTERM);
	sigaddset(&signal_set, SIGUSR1);
	sigaddset(&signal_set, SIGPIPE);
	pthread_sigmask(SIG_BLOCK, &signal_set, NULL);

	// for USR2 set a signal handler, which interrupts blocking
	// system calls - and signals done event
	// handler applies for all threads in a process
	sa.sa_handler = Interrupt_handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sigaction(SIGPIPE, &sa, NULL);
	sigaction(SIGUSR2, &sa, NULL);

	// key for each thread
	err = pthread_key_create(&buffer_key, NULL);
	if ( err ) {
		LogError("pthread_key() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
		exit(255);
	}

	// prepare flow thread args
	p_flow_thread_args = (p_flow_thread_args_t *)malloc(sizeof(p_flow_thread_args_t));
	if ( !p_flow_thread_args ) {
		LogError("malloc() error in %s line %d: %s\n", 
			__FILE__, __LINE__, strerror(errno) );
		exit(255);
	}	
	p_flow_thread_args->fs 	   	   = fs;
	p_flow_thread_args->t_win 	   = t_win;
	p_flow_thread_args->compress   = compress;
	p_flow_thread_args->subdir_index = subdir_index;
	p_flow_thread_args->parent	   = pthread_self();
	p_flow_thread_args->NodeList   = NewNodeList();

	err = 0;
	err = pthread_create(&p_flow_thread_args->tid, NULL, p_flow_thread, (void *)p_flow_thread_args);
	if ( err ) {
		LogError("pthread_create() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
		exit(255);
	}
	dbg_printf("Started flow thread[%lu]\n", (long unsigned)p_flow_thread_args->tid);

	// prepare packet thread args
	p_packet_thread_args = (p_packet_thread_args_t *)malloc(sizeof(p_packet_thread_args_t));
	if ( !p_packet_thread_args ) {
		LogError("malloc() error in %s line %d: %s\n", 
			__FILE__, __LINE__, strerror(errno) );
		exit(255);
	}	
	p_packet_thread_args->pcap_dev 	   = pcap_dev;
	p_packet_thread_args->t_win 	   = t_win;
	p_packet_thread_args->subdir_index = subdir_index;
	p_packet_thread_args->pcap_datadir = pcap_datadir;
	p_packet_thread_args->live 	   	   = device != NULL;
	p_packet_thread_args->parent	   = pthread_self();
	p_packet_thread_args->NodeList	   = p_flow_thread_args->NodeList;

	err = pthread_create(&p_packet_thread_args->tid, NULL, p_packet_thread, (void *)p_packet_thread_args);
	if ( err ) {
		LogError("pthread_create() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
		exit(255);
	}
	dbg_printf("Started packet thread[%lu]\n", (long unsigned)p_packet_thread_args->tid);

	// Wait till done
	WaitDone();

	dbg_printf("Signal packet thread to terminate\n");
	SignalThreadTerminate((thread_info_t *)p_packet_thread_args, NULL);

	dbg_printf("Signal flow thread to terminate\n");
	SignalThreadTerminate((thread_info_t *)p_flow_thread_args, &p_packet_thread_args->NodeList->c_list);

	// free arg list
	free((void *)p_packet_thread_args);
	free((void *)p_flow_thread_args);

	LogInfo("Terminating nfpcapd.");

	if ( expire == 0 && ReadStatInfo(fs->datadir, &dirstat, LOCK_IF_EXISTS) == STATFILE_OK ) {
		UpdateBookStat(dirstat, fs->bookkeeper);
		WriteStatInfo(dirstat);
		LogInfo("Updating statinfo in directory '%s'", datadir);
	}

	ReleaseBookkeeper(fs->bookkeeper, DESTROY_BOOKKEEPER);
	pcap_close(pcap_dev->handle);

	if ( strlen(pidfile) )
		unlink(pidfile);

	EndLog();

	exit(EXIT_SUCCESS);
} /* End of main */