Ejemplo n.º 1
0
static void do_expire(char *datadir) {
bookkeeper_t 	*books;
dirstat_t 		*dirstat, oldstat;
int				ret, bookkeeper_stat, do_rescan;

	syslog(LOG_INFO, "Run expire on '%s'", datadir);

	do_rescan = 0;
	ret = ReadStatInfo(datadir, &dirstat, CREATE_AND_LOCK);
	switch (ret) {
		case STATFILE_OK:
			break;
		case ERR_NOSTATFILE:
			dirstat->low_water = 95;
		case FORCE_REBUILD:
			syslog(LOG_INFO, "Force rebuild stat record");
			do_rescan = 1;
			break;
		case ERR_FAIL:
			syslog(LOG_ERR, "expire failed: can't read stat record");
			return;
			/* not reached */
			break;
		default:
			syslog(LOG_ERR, "expire failed: unexpected return code %i reading stat record", ret);
			return;
			/* not reached */
	}

	bookkeeper_stat = AccessBookkeeper(&books, datadir);
	if ( do_rescan ) {
		RescanDir(datadir, dirstat);
		if ( bookkeeper_stat == BOOKKEEPER_OK ) {
			ClearBooks(books, NULL);
			// release the books below
		}
	}

	if ( bookkeeper_stat == BOOKKEEPER_OK ) {
		bookkeeper_t	tmp_books;
		ClearBooks(books, &tmp_books);
		UpdateBookStat(dirstat, &tmp_books);
		ReleaseBookkeeper(books, DETACH_ONLY);
	} else {
		syslog(LOG_ERR, "Error %i: can't access book keeping records", ret);
	}

	syslog(LOG_INFO, "Limits: Filesize %s, Lifetime %s, Watermark: %llu%%\n", 
		dirstat->max_size     ? ScaleValue(dirstat->max_size)    : "<none>", 
		dirstat->max_lifetime ? ScaleTime(dirstat->max_lifetime) : "<none>",
		(unsigned long long)dirstat->low_water);
		
	syslog(LOG_INFO, "Current size: %s, Current lifetime: %s, Number of files: %llu",
		ScaleValue(dirstat->filesize),
		ScaleTime(dirstat->last - dirstat->first),
		(unsigned long long)dirstat->numfiles);

	oldstat = *dirstat;
	if ( dirstat->max_size || dirstat->max_lifetime ) 
		ExpireDir(datadir, dirstat, dirstat->max_size, dirstat->max_lifetime, 0);
	WriteStatInfo(dirstat);

	if ( (oldstat.numfiles - dirstat->numfiles) > 0 ) {
		syslog(LOG_INFO, "expire completed");
		syslog(LOG_INFO, "   expired files: %llu", (unsigned long long)(oldstat.numfiles - dirstat->numfiles));
		syslog(LOG_INFO, "   expired time slot: %s", ScaleTime(dirstat->first - oldstat.first));
		syslog(LOG_INFO, "   expired file size: %s", ScaleValue(oldstat.filesize - dirstat->filesize));
		syslog(LOG_INFO, "New size: %s, New lifetime: %s, Number of files: %llu",
			ScaleValue(dirstat->filesize),
		ScaleTime(dirstat->last - dirstat->first),
			(unsigned long long)dirstat->numfiles);
	} else {
		syslog(LOG_INFO, "expire completed - nothing to expire.");
	}
	ReleaseStatInfo(dirstat);

} // End of do_expire
Ejemplo n.º 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 */
Ejemplo n.º 3
0
int main(int argc, char **argv) {
 
char	*bindhost, *filter, *datadir, pidstr[32], *launch_process;
char	*userid, *groupid, *checkptr, *listenport, *mcastgroup, *extension_tags;
char	*Ident, *dynsrcdir, pidfile[MAXPATHLEN];
struct stat fstat;
packet_function_t receive_packet;
send_peer_t  peer;
FlowSource_t *fs;
struct sigaction act;
int		family, bufflen;
time_t 	twin, t_start;
int		sock, synctime, do_daemonize, expire, report_sequence, do_xstat;
int		subdir_index, sampling_rate, compress;
int		c;
#ifdef PCAP
char	*pcap_file;
 
	pcap_file		= NULL;
#endif

	receive_packet 	= recvfrom;
	verbose = synctime = do_daemonize = 0;
	bufflen  		= 0;
	family			= AF_UNSPEC;
	launcher_pid	= 0;
	launcher_alive	= 0;
	report_sequence	= 0;
	listenport		= DEFAULTCISCOPORT;
	bindhost 		= NULL;
	mcastgroup		= NULL;
	pidfile[0]		= 0;
	filter   		= NULL;
	launch_process	= NULL;
	userid 			= groupid = NULL;
	twin	 		= TIME_WINDOW;
	datadir	 		= NULL;
	subdir_index	= 0;
	expire			= 0;
	sampling_rate	= 1;
	compress		= 0;
	do_xstat		= 0;
	memset((void *)&peer, 0, sizeof(send_peer_t));
	peer.family		= AF_UNSPEC;
	Ident			= "none";
	FlowSource		= NULL;
	extension_tags	= DefaultExtensions;
	dynsrcdir		= NULL;

	while ((c = getopt(argc, argv, "46ef:whEVI:DB:b:j:l:M:n:p:P:R:S:s:T:t:x:Xru:g:z")) != EOF) {
		switch (c) {
			case 'h':
				usage(argv[0]);
				exit(0);
				break;
			case 'u':
				userid  = optarg;
				break;
			case 'g':
				groupid  = optarg;
				break;
			case 'e':
				expire = 1;
				break;
			case 'f': {
#ifdef PCAP
				struct stat	fstat;
				pcap_file = optarg;
				stat(pcap_file, &fstat);
				if ( !S_ISREG(fstat.st_mode) ) {
					fprintf(stderr, "Not a regular file: %s\n", pcap_file);
					exit(254);
				}
#else
				fprintf(stderr, "PCAP reader not compiled! Option ignored!\n");
#endif
				} break;
			case 'E':
				verbose = 1;
				Setv6Mode(1);
				break;
			case 'V':
				printf("%s: Version: %s\n",argv[0], nfdump_version);
				exit(0);
				break;
			case 'X':
				do_xstat = 1;
				break;
			case 'D':
				do_daemonize = 1;
				break;
			case 'I':
				Ident = strdup(optarg);
				break;
			case 'M':
				dynsrcdir = strdup(optarg);
				if ( strlen(dynsrcdir) > MAXPATHLEN ) {
					fprintf(stderr, "ERROR: Path too long!\n");
					exit(255);
				}
				if ( stat(dynsrcdir, &fstat) < 0 ) {
					fprintf(stderr, "stat() failed on %s: %s\n", dynsrcdir, strerror(errno));
					exit(255);
				}
				if ( !(fstat.st_mode & S_IFDIR) ) {
					fprintf(stderr, "No such directory: %s\n", dynsrcdir);
					break;
				}
				if ( !SetDynamicSourcesDir(&FlowSource, dynsrcdir) ) {
					fprintf(stderr, "-l, -M and -n are mutually exclusive\n");
					break;
				}
				break;
			case 'n':
				if ( AddFlowSource(&FlowSource, optarg) != 1 ) 
					exit(255);
				break;
			case 'w':
				synctime = 1;
				break;
			case 'B':
				bufflen = strtol(optarg, &checkptr, 10);
				if ( (checkptr != NULL && *checkptr == 0) && bufflen > 0 )
					break;
				fprintf(stderr,"Argument error for -B\n");
				exit(255);
			case 'b':
				bindhost = optarg;
				break;
			case 'j':
				mcastgroup = optarg;
				break;
			case 'p':
				listenport = optarg;
				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 'R': {
				char *p = strchr(optarg, '/');
				if ( p ) { 
					*p++ = '\0';
					peer.port = strdup(p);
				} else {
					peer.port = DEFAULTCISCOPORT;
				}
				peer.hostname = strdup(optarg);

				break; }
			case 'r':
				report_sequence = 1;
				break;
			case 's':
				// a negative sampling rate is set as the overwrite sampling rate
				sampling_rate = (int)strtol(optarg, (char **)NULL, 10);
				if ( (sampling_rate == 0 ) ||
					 (sampling_rate < 0 && sampling_rate < -10000000) ||
					 (sampling_rate > 0 && sampling_rate > 10000000) ) {
					fprintf(stderr, "Invalid sampling rate: %s\n", optarg);
					exit(255);
				} 
				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 'l':
				datadir = optarg;
				if ( strlen(datadir) > MAXPATHLEN ) {
					fprintf(stderr, "ERROR: Path too long!\n");
					exit(255);
				}
				if ( stat(datadir, &fstat) < 0 ) {
					fprintf(stderr, "stat() failed on %s: %s\n", datadir, strerror(errno));
					exit(255);
				}
				if ( !(fstat.st_mode & S_IFDIR) ) {
					fprintf(stderr, "No such directory: %s\n", datadir);
					break;
				}
				break;
			case 'S':
				subdir_index = atoi(optarg);
				break;
			case 't':
				twin = atoi(optarg);
				if ( twin <= 0 ) {
					fprintf(stderr, "ERROR: time frame <= 0\n");
					exit(255);
				}
				if (twin < 10) {
					fprintf(stderr, "WARNING, Very small time frame - < 10s!\n");
				}
				break;
			case 'x':
				launch_process = optarg;
				break;
			case 'z':
				compress = 1;
				break;
			case '4':
				if ( family == AF_UNSPEC )
					family = AF_INET;
				else {
					fprintf(stderr, "ERROR, Accepts only one protocol IPv4 or IPv6!\n");
					exit(255);
				}
				break;
			case '6':
				if ( family == AF_UNSPEC )
					family = AF_INET6;
				else {
					fprintf(stderr, "ERROR, Accepts only one protocol IPv4 or IPv6!\n");
					exit(255);
				}
				break;
			default:
				usage(argv[0]);
				exit(255);
		}
	}
	
	if ( FlowSource == NULL && datadir == NULL && dynsrcdir == NULL ) {
		fprintf(stderr, "ERROR, Missing -n (-l/-I) or -M source definitions\n");
		exit(255);
	}
	if ( FlowSource == NULL && datadir != NULL && !AddDefaultFlowSource(&FlowSource, Ident, datadir) ) {
		fprintf(stderr, "Failed to add default data collector directory\n");
		exit(255);
	}

	if ( bindhost && mcastgroup ) {
		fprintf(stderr, "ERROR, -b and -j are mutually exclusive!!\n");
		exit(255);
	}

	if ( do_daemonize && !InitLog(argv[0], SYSLOG_FACILITY)) {
		exit(255);
	}

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

	// Debug code to read from pcap file
#ifdef PCAP
	sock = 0;
	if ( pcap_file ) {
		printf("Setup pcap reader\n");
		setup_packethandler(pcap_file, NULL);
		receive_packet 	= NextPacket;
	} else 
#endif
	if ( mcastgroup ) 
		sock = Multicast_receive_socket (mcastgroup, listenport, family, bufflen);
	else 
		sock = Unicast_receive_socket(bindhost, listenport, family, bufflen );

	if ( sock == -1 ) {
		fprintf(stderr,"Terminated due to errors.\n");
		exit(255);
	}

	if ( peer.hostname ) {
		peer.sockfd = Unicast_send_socket (peer.hostname, peer.port, peer.family, bufflen, 
											&peer.addr, &peer.addrlen );
		if ( peer.sockfd <= 0 )
			exit(255);
		LogInfo("Replay flows to host: %s port: %s", peer.hostname, peer.port);
	}

	if ( sampling_rate < 0 ) {
		default_sampling = -sampling_rate;
		overwrite_sampling = default_sampling;
	} else {
		default_sampling = sampling_rate;
	}

	SetPriv(userid, groupid);

	if ( subdir_index && !InitHierPath(subdir_index) ) {
		close(sock);
		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));
				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));
						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));
				exit(255);
			} // else errno == ENOENT - no file - this is fine
		}
	}

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


	t_start = time(NULL);
	if ( synctime )
		t_start = t_start - ( t_start % twin);

	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));
			close(sock);
			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);
	}

	done = 0;
	if ( launch_process || expire ) {
		// for efficiency reason, the process collecting the data
		// and the process launching processes, when a new file becomes
		// available are separated. Communication is done using signals
		// as well as shared memory
		// prepare shared memory
		shmem = mmap(0, sizeof(srecord_t), PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
		if ( shmem == (caddr_t)-1 ) {
			LogError("mmap() error: %s", strerror(errno));
			close(sock);
			exit(255);
		}

		launcher_pid = fork();
		switch (launcher_pid) {
			case 0:
				// child
				close(sock);
				launcher((char *)shmem, FlowSource, launch_process, expire);
				_exit(0);
				break;
			case -1:
				LogError("fork() error: %s", strerror(errno));
				if ( strlen(pidfile) )
					unlink(pidfile);
				exit(255);
				break;
			default:
				// parent
			launcher_alive = 1;
			LogInfo("Launcher[%i] forked", launcher_pid);
		}
	}

	fs = FlowSource;
	while ( fs ) {
		if ( InitBookkeeper(&fs->bookkeeper, fs->datadir, getpid(), launcher_pid) != BOOKKEEPER_OK ) {
			LogError("initialize bookkeeper failed.");

			// release all already allocated bookkeepers
			fs = FlowSource;
			while ( fs && fs->bookkeeper ) {
				ReleaseBookkeeper(fs->bookkeeper, DESTROY_BOOKKEEPER);
				fs = fs->next;
			}
			close(sock);
			if ( launcher_pid )
				kill_launcher(launcher_pid);
			if ( strlen(pidfile) )
				unlink(pidfile);
			exit(255);
		}

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

		fs = fs->next;
	}

	/* Signal handling */
	memset((void *)&act,0,sizeof(struct sigaction));
	act.sa_handler = IntHandler;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	sigaction(SIGTERM, &act, NULL);
	sigaction(SIGINT, &act, NULL);
	sigaction(SIGHUP, &act, NULL);
	sigaction(SIGALRM, &act, NULL);
	sigaction(SIGCHLD, &act, NULL);

	LogInfo("Startup.");
	run(receive_packet, sock, peer, twin, t_start, report_sequence, subdir_index, compress, do_xstat);
	close(sock);
	kill_launcher(launcher_pid);

	fs = FlowSource;
	while ( fs && fs->bookkeeper ) {
		dirstat_t 	*dirstat;
		// if we do not auto expire and there is a stat file, update the stats before we leave
		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);
		fs = fs->next;
	}

	LogInfo("Terminating nfcapd.");
	EndLog();

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

	return 0;

} /* End of main */
Ejemplo n.º 4
0
int main( int argc, char **argv ) {
    struct stat fstat;
    int 		c, err, maxsize_set, maxlife_set;
    int			do_rescan, do_expire, do_list, print_stat, do_update_param, print_books, is_profile, nfsen_format;
    char		*maxsize_string, *lifetime_string, *datadir;
    uint64_t	maxsize, lifetime, low_water;
    uint32_t	runtime;
    channel_t	*channel, *current_channel;

    maxsize_string = lifetime_string = NULL;
    datadir = NULL;
    maxsize = lifetime = 0;
    do_rescan  		= 0;
    do_expire  		= 0;
    do_list	   		= 0;
    do_update_param = 0;
    is_profile		= 0;
    print_stat		= 0;
    print_books		= 0;
    maxsize_set 	= 0;
    maxlife_set 	= 0;
    low_water		= 0;
    nfsen_format	= 0;
    runtime			= 0;

    while ((c = getopt(argc, argv, "e:hl:L:T:Ypr:s:t:u:w:")) != EOF) {
        switch (c) {
        case 'h':
            usage(argv[0]);
            exit(0);
            break;
        case 'l':
            CheckDataDir(datadir);
            datadir = optarg;
            do_list = 1;
            print_stat = 1;
            break;
        case 'L':
            CheckDataDir(datadir);
            datadir = optarg;
            print_stat  = 1;
            print_books = 1;
            break;
        case 'p':
            is_profile = 1;
            break;
        case 'r':
            CheckDataDir(datadir);
            do_rescan = 1;
            print_stat = 1;
            datadir = optarg;
            break;
        case 'e':
            CheckDataDir(datadir);
            datadir = optarg;
            do_expire = 1;
            print_stat = 1;
            break;
        case 's':
            if ( ParseSizeDef(optarg, &maxsize ) == 0 )
                exit(250);
            maxsize_set = 1;
            break;
        case 't':
            if ( ParseTimeDef(optarg, &lifetime ) == 0 )
                exit(250);
            maxlife_set = 1;
            break;
        case 'u':
            CheckDataDir(datadir);
            datadir = optarg;
            do_update_param = 1;
            break;
        case 'w':
            low_water = strtoll(optarg, NULL, 10);
            if ( low_water > 100 ) {
                fprintf(stderr, "Water mark > 100%%\n");
                exit(250);
            }
            if ( low_water == 0 )
                low_water = 100;
            break;
        case 'T':
            runtime = strtoll(optarg, NULL, 10);
            if ( runtime > 3600 ) {
                fprintf(stderr, "Runtime > 3600 (1h)\n");
                exit(250);
            }
            break;
        case 'Y':
            nfsen_format = 1;
            break;
        default:
            usage(argv[0]);
            exit(250);
        }

    }

    datadir = AbsolutePath(datadir);

    if ( !datadir ) {
        fprintf(stderr, "Missing data directory\n");
        usage(argv[0]);
        exit(250);
    }

    err  = stat(datadir, &fstat);
    if ( !(fstat.st_mode & S_IFDIR) ) {
        fprintf(stderr, "No such directory: %s\n", datadir);
        exit(250);
    }

    channel = GetChannelList(datadir, is_profile, do_rescan);
    // GetChannelList(datadir, is_profile, do_rescan);
    if ( !channel ) {
        exit(250);
    }

// printf("Size: %llu, time: %llu\n", maxsize, lifetime);

    // update water mark only, when not listing
    if ( !is_profile && !do_list && low_water )
        channel->dirstat->low_water = low_water;

    /* process do_list first: if the UpdateBookStat results in a FORCE_REBUILD,
     * this will immediately done afterwards
     * do_expire will need accurate books as well, so update the books here as well
     */
    if ( do_list || do_expire ) {
        current_channel = channel;
        while ( current_channel ) {
            if ( current_channel->books_stat == BOOKKEEPER_OK ) {
                bookkeeper_t	tmp_books;
                printf("Include nfcapd bookeeping record in %s\n", current_channel->datadir);
                ClearBooks(current_channel->books, &tmp_books);
                UpdateBookStat(current_channel->dirstat, &tmp_books);
                if ( current_channel->dirstat->status == FORCE_REBUILD )
                    current_channel->do_rescan = 1;
            }
            current_channel = current_channel->next;
        }
    }

    // process do_rescan: make sure stats are up to date, if required
    current_channel = channel;
    while ( current_channel ) {
        if ( current_channel->do_rescan ) {
            int	 i;
            uint64_t last_sequence;

            /* detect new files: If nfcapd adds a new file while we are rescanning the directory
            * this results in inconsistent data for the rescan. Therefore check at the begin and end
            * of the rescan for the sequence number, which reflects the accesss/change to the bookkeeping record
            * It's assumed, that such an event does not occure more than once. However, loop 3 times max
            */
            for ( i=0; i<3; i++ ) {
                last_sequence = BookSequence(current_channel->books);
                printf("Scanning files in %s .. ", current_channel->datadir);
                RescanDir(current_channel->datadir, current_channel->dirstat);
                if ( current_channel->dirstat->numfiles == 0 ) { //nothing found
                    current_channel->status = NOFILES;
                }
                if ( BookSequence(current_channel->books) == last_sequence )
                    break;
                printf("Rescan again, due to file changes in directory!\n");
            }
            if ( BookSequence(current_channel->books) != last_sequence ) {
                fprintf(stderr, "Could not savely rescan the directory. Data is not consistent.\n");
                ReleaseBookkeeper(current_channel->books, DETACH_ONLY);
                if ( current_channel->status == OK )
                    WriteStatInfo(current_channel->dirstat);
                exit(250);
            }
            printf("done.\n");
            if ( current_channel->books_stat == BOOKKEEPER_OK ) {
                printf("Updating nfcapd bookeeping records\n");
                ClearBooks(channel->books, NULL);
            }
        }
        current_channel = current_channel->next;
    }

    // now process do_expire if required
    if ( do_expire ) {
        dirstat_t	old_stat, current_stat;

        if ( is_profile ) {
            current_stat.status = 0;
            current_stat.max_lifetime 	= lifetime;
            current_stat.max_size  		= maxsize;
            current_stat.low_water 		= low_water ? low_water : 98;

            // sum up all channels in the profile
            current_channel = channel;
            current_stat.numfiles = current_channel->dirstat->numfiles;
            current_stat.filesize = current_channel->dirstat->filesize;
            current_stat.first 	  = current_channel->dirstat->first;
            current_stat.last 	  = current_channel->dirstat->last;
            current_channel = current_channel->next;
            while ( current_channel ) {
                current_stat.numfiles += current_channel->dirstat->numfiles;
                current_stat.filesize += current_channel->dirstat->filesize;
                if ( current_channel->dirstat->first && (current_channel->dirstat->first < current_stat.first) )
                    current_stat.first = current_channel->dirstat->first;
                if ( current_channel->dirstat->last > current_stat.last )
                    current_stat.last = current_channel->dirstat->last;

                current_channel = current_channel->next;
            }
            old_stat = current_stat;
            ExpireProfile(channel, &current_stat, maxsize, lifetime, runtime);

        } else {
            // cmd args override dirstat values
            if ( maxsize_set )
                channel->dirstat->max_size     = maxsize;
            else
                maxsize = channel->dirstat->max_size;
            if ( maxlife_set )
                channel->dirstat->max_lifetime = lifetime;
            else
                lifetime = channel->dirstat->max_lifetime;


            old_stat = *(channel->dirstat);
            ExpireDir(channel->datadir, channel->dirstat, maxsize, lifetime, runtime);
            current_stat = *(channel->dirstat);

        }
        // Report, what we have done
        printf("Expired files:      %llu\n", (unsigned long long)(old_stat.numfiles - current_stat.numfiles));
        printf("Expired file size:  %s\n", ScaleValue(old_stat.filesize - current_stat.filesize));
        printf("Expired time range: %s\n\n", ScaleTime(current_stat.first - old_stat.first));
    }

    if ( !is_profile && do_update_param ) {
        switch (channel->books_stat) {
        case BOOKKEEPER_OK:
            if ( maxsize_set )
                channel->dirstat->max_size = maxsize;
            else
                maxsize = channel->dirstat->max_size;
            if ( maxlife_set )
                channel->dirstat->max_lifetime = lifetime;
            else
                lifetime = channel->dirstat->max_lifetime;
            printf("Update collector process running for directory: '%s'\n", datadir);
            UpdateBooksParam(channel->books, (time_t)lifetime, maxsize);
            print_stat = 1;
            break;
        case ERR_NOTEXISTS:
            if ( maxsize_set )
                channel->dirstat->max_size = maxsize;
            if ( maxlife_set )
                channel->dirstat->max_lifetime = lifetime;
            print_stat = 1;
            break;
        default:
            // should never be reached as already cought earlier
            printf("Error %i while connecting to collector\n", channel->books_stat);
        }
        if ( channel->status == OK || channel->status == NOFILES  )
            WriteStatInfo(channel->dirstat);
    }

    if ( !is_profile && print_books ) {
        switch (channel->books_stat) {
        case BOOKKEEPER_OK:
            PrintBooks(channel->books);
            break;
        case ERR_NOTEXISTS:
            printf("No collector process running for directory: '%s'\n", channel->datadir);
            break;
        default:
            // should never be reached as already cought earlier
            printf("Error %i while connecting to collector\n", channel->books_stat);
        }

    }

    if ( print_stat ) {
        if ( is_profile ) {
            dirstat_t	current_stat;

            current_stat.status = 0;
            current_stat.max_lifetime 	= lifetime;
            current_stat.max_size  		= maxsize;
            current_stat.low_water 		= low_water ? low_water : 98;

            // sum up all channels in the profile
            current_channel = channel;
            current_stat.numfiles = current_channel->dirstat->numfiles;
            current_stat.filesize = current_channel->dirstat->filesize;
            current_stat.first 	  = current_channel->dirstat->first;
            current_stat.last 	  = current_channel->dirstat->last;
            current_channel = current_channel->next;
            while ( current_channel ) {
                current_stat.numfiles += current_channel->dirstat->numfiles;
                current_stat.filesize += current_channel->dirstat->filesize;
                if ( current_channel->dirstat->first && (current_channel->dirstat->first < current_stat.first) )
                    current_stat.first = current_channel->dirstat->first;
                if ( current_channel->dirstat->last > current_stat.last )
                    current_stat.last = current_channel->dirstat->last;

                current_channel = current_channel->next;
            }
            if ( nfsen_format ) {
                printf("Stat|%llu|%llu|%llu\n",
                       (unsigned long long)current_stat.filesize,
                       (unsigned long long)current_stat.first, (unsigned long long)current_stat.last);
            } else
                PrintDirStat(&current_stat);
        } else if ( nfsen_format )
            printf("Stat|%llu|%llu|%llu\n",
                   (unsigned long long)channel->dirstat->filesize,
                   (unsigned long long)channel->dirstat->first, (unsigned long long)channel->dirstat->last );
        else
            PrintDirStat(channel->dirstat);

    }

    current_channel = channel;
    while ( current_channel ) {
        ReleaseBookkeeper(current_channel->books, DETACH_ONLY);
        if ( current_channel->status == OK )
            WriteStatInfo(current_channel->dirstat);

        current_channel = current_channel->next;
    }

    return 0;
}