|  | @@ -22,24 +22,25 @@
 | 
												
													
														
															|  |   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 |  |   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
												
													
														
															|  |   */
 |  |   */
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  | -/* $Id: softflowd.c,v 1.93 2006/11/02 06:23:29 djm Exp $ */
 |  | 
 | 
												
													
														
															|  | 
 |  | +/* $Id$ */
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  /*
 |  |  /*
 | 
												
													
														
															|  | - * This is software implementation of Cisco's NetFlow(tm) traffic 
 |  | 
 | 
												
													
														
															|  | - * reporting system. It operates by listening (via libpcap) on a 
 |  | 
 | 
												
													
														
															|  | - * promiscuous interface and tracking traffic flows. 
 |  | 
 | 
												
													
														
															|  | 
 |  | + * This is software implementation of Cisco's NetFlow(tm) traffic       
 | 
												
													
														
															|  | 
 |  | + * reporting system. It operates by listening (via libpcap) on a        
 | 
												
													
														
															|  | 
 |  | + * promiscuous interface and tracking traffic flows.                    
 | 
												
													
														
															|  |   *
 |  |   *
 | 
												
													
														
															|  | - * Traffic flows are recorded by source/destination/protocol IP address or, in the
 |  | 
 | 
												
													
														
															|  | - * case of TCP and UDP, by src_addr:src_port/dest_addr:dest_port/protocol
 |  | 
 | 
												
													
														
															|  | 
 |  | + * Traffic flows are recorded by source/destination/protocol
 | 
												
													
														
															|  | 
 |  | + * IP address or, in the case of TCP and UDP, by
 | 
												
													
														
															|  | 
 |  | + * src_addr:src_port/dest_addr:dest_port/protocol
 | 
												
													
														
															|  |   *
 |  |   *
 | 
												
													
														
															|  | - * Flows expire automatically after a period of inactivity (default: 1 hour)
 |  | 
 | 
												
													
														
															|  | - * They may also be evicted (in order of age) in situations where there are 
 |  | 
 | 
												
													
														
															|  | - * more flows than slots available.
 |  | 
 | 
												
													
														
															|  | 
 |  | + * Flows expire automatically after a period of inactivity (default: 1
 | 
												
													
														
															|  | 
 |  | + * hour) They may also be evicted (in order of age) in situations where
 | 
												
													
														
															|  | 
 |  | + * there are more flows than slots available.
 | 
												
													
														
															|  |   *
 |  |   *
 | 
												
													
														
															|  | - * Netflow version 1 compatible packets are sent to a specified target 
 |  | 
 | 
												
													
														
															|  | - * host upon flow expiry.
 |  | 
 | 
												
													
														
															|  | 
 |  | + * Netflow compatible packets are sent to a specified target host upon
 | 
												
													
														
															|  | 
 |  | + * flow expiry.
 | 
												
													
														
															|  |   *
 |  |   *
 | 
												
													
														
															|  | - * As this implementation watches traffic promiscuously, it is likely to 
 |  | 
 | 
												
													
														
															|  | 
 |  | + * As this implementation watches traffic promiscuously, it is likely to
 | 
												
													
														
															|  |   * place significant load on hosts or gateways on which it is installed.
 |  |   * place significant load on hosts or gateways on which it is installed.
 | 
												
													
														
															|  |   */
 |  |   */
 | 
												
													
														
															|  |  
 |  |  
 | 
												
											
												
													
														
															|  | @@ -48,16 +49,18 @@
 | 
												
													
														
															|  |  #include "convtime.h"
 |  |  #include "convtime.h"
 | 
												
													
														
															|  |  #include "softflowd.h"
 |  |  #include "softflowd.h"
 | 
												
													
														
															|  |  #include "treetype.h"
 |  |  #include "treetype.h"
 | 
												
													
														
															|  | 
 |  | +#include "freelist.h"
 | 
												
													
														
															|  |  #include "log.h"
 |  |  #include "log.h"
 | 
												
													
														
															|  |  #include <pcap.h>
 |  |  #include <pcap.h>
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  | -RCSID("$Id: softflowd.c,v 1.93 2006/11/02 06:23:29 djm Exp $");
 |  | 
 | 
												
													
														
															|  | 
 |  | +RCSID("$Id$");
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  /* Global variables */
 |  |  /* Global variables */
 | 
												
													
														
															|  |  static int verbose_flag = 0;		/* Debugging flag */
 |  |  static int verbose_flag = 0;		/* Debugging flag */
 | 
												
													
														
															|  | 
 |  | +static u_int16_t if_index = 0;		/* "manual" interface index */
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  /* Signal handler flags */
 |  |  /* Signal handler flags */
 | 
												
													
														
															|  | -static volatile int graceful_shutdown_request = 0;	
 |  | 
 | 
												
													
														
															|  | 
 |  | +static volatile sig_atomic_t graceful_shutdown_request = 0;	
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  /* Context for libpcap callback functions */
 |  |  /* Context for libpcap callback functions */
 | 
												
													
														
															|  |  struct CB_CTXT {
 |  |  struct CB_CTXT {
 | 
												
											
												
													
														
															|  | @@ -95,8 +98,8 @@ static const struct DATALINK lt[] = {
 | 
												
													
														
															|  |  };
 |  |  };
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  /* Netflow send functions */
 |  |  /* Netflow send functions */
 | 
												
													
														
															|  | -typedef int (netflow_send_func_t)(struct FLOW **, int, int, u_int64_t *,
 |  | 
 | 
												
													
														
															|  | -    struct timeval *, int);
 |  | 
 | 
												
													
														
															|  | 
 |  | +typedef int (netflow_send_func_t)(struct FLOW **, int, int, u_int16_t,
 | 
												
													
														
															|  | 
 |  | +	u_int64_t *, struct timeval *, int);
 | 
												
													
														
															|  |  struct NETFLOW_SENDER {
 |  |  struct NETFLOW_SENDER {
 | 
												
													
														
															|  |  	int version;
 |  |  	int version;
 | 
												
													
														
															|  |  	netflow_send_func_t *func;
 |  |  	netflow_send_func_t *func;
 | 
												
											
												
													
														
															|  | @@ -126,7 +129,8 @@ static void sighand_graceful_shutdown(int signum)
 | 
												
													
														
															|  |  static void sighand_other(int signum)
 |  |  static void sighand_other(int signum)
 | 
												
													
														
															|  |  {
 |  |  {
 | 
												
													
														
															|  |  	/* XXX: this may not be completely safe */
 |  |  	/* XXX: this may not be completely safe */
 | 
												
													
														
															|  | -	logit(LOG_WARNING, "Exiting immediately on unexpected signal %d", signum);
 |  | 
 | 
												
													
														
															|  | 
 |  | +	logit(LOG_WARNING, "Exiting immediately on unexpected signal %d",
 | 
												
													
														
															|  | 
 |  | +	    signum);
 | 
												
													
														
															|  |  	_exit(0);
 |  |  	_exit(0);
 | 
												
													
														
															|  |  }
 |  |  }
 | 
												
													
														
															|  |  
 |  |  
 | 
												
											
												
													
														
															|  | @@ -194,6 +198,30 @@ expiry_compare(struct EXPIRY *a, struct EXPIRY *b)
 | 
												
													
														
															|  |  EXPIRY_PROTOTYPE(EXPIRIES, EXPIRY, trp, expiry_compare);
 |  |  EXPIRY_PROTOTYPE(EXPIRIES, EXPIRY, trp, expiry_compare);
 | 
												
													
														
															|  |  EXPIRY_GENERATE(EXPIRIES, EXPIRY, trp, expiry_compare);
 |  |  EXPIRY_GENERATE(EXPIRIES, EXPIRY, trp, expiry_compare);
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  | 
 |  | +static struct FLOW *
 | 
												
													
														
															|  | 
 |  | +flow_get(struct FLOWTRACK *ft)
 | 
												
													
														
															|  | 
 |  | +{
 | 
												
													
														
															|  | 
 |  | +	return freelist_get(&ft->flow_freelist);
 | 
												
													
														
															|  | 
 |  | +}
 | 
												
													
														
															|  | 
 |  | +
 | 
												
													
														
															|  | 
 |  | +static void
 | 
												
													
														
															|  | 
 |  | +flow_put(struct FLOWTRACK *ft, struct FLOW *flow)
 | 
												
													
														
															|  | 
 |  | +{
 | 
												
													
														
															|  | 
 |  | +	return freelist_put(&ft->flow_freelist, flow);
 | 
												
													
														
															|  | 
 |  | +}
 | 
												
													
														
															|  | 
 |  | +
 | 
												
													
														
															|  | 
 |  | +static struct EXPIRY *
 | 
												
													
														
															|  | 
 |  | +expiry_get(struct FLOWTRACK *ft)
 | 
												
													
														
															|  | 
 |  | +{
 | 
												
													
														
															|  | 
 |  | +	return freelist_get(&ft->expiry_freelist);
 | 
												
													
														
															|  | 
 |  | +}
 | 
												
													
														
															|  | 
 |  | +
 | 
												
													
														
															|  | 
 |  | +static void
 | 
												
													
														
															|  | 
 |  | +expiry_put(struct FLOWTRACK *ft, struct EXPIRY *expiry)
 | 
												
													
														
															|  | 
 |  | +{
 | 
												
													
														
															|  | 
 |  | +	return freelist_put(&ft->expiry_freelist, expiry);
 | 
												
													
														
															|  | 
 |  | +}
 | 
												
													
														
															|  | 
 |  | +
 | 
												
													
														
															|  |  #if 0
 |  |  #if 0
 | 
												
													
														
															|  |  /* Dump a packet */
 |  |  /* Dump a packet */
 | 
												
													
														
															|  |  static void
 |  |  static void
 | 
												
											
												
													
														
															|  | @@ -218,9 +246,9 @@ static const char *
 | 
												
													
														
															|  |  format_time(time_t t)
 |  |  format_time(time_t t)
 | 
												
													
														
															|  |  {
 |  |  {
 | 
												
													
														
															|  |  	struct tm *tm;
 |  |  	struct tm *tm;
 | 
												
													
														
															|  | -	static char buf[20];
 |  | 
 | 
												
													
														
															|  | 
 |  | +	static char buf[32];
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  | -	tm = localtime(&t);
 |  | 
 | 
												
													
														
															|  | 
 |  | +	tm = gmtime(&t);
 | 
												
													
														
															|  |  	strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", tm);
 |  |  	strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", tm);
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  	return (buf);
 |  |  	return (buf);
 | 
												
											
												
													
														
															|  | @@ -231,7 +259,7 @@ format_time(time_t t)
 | 
												
													
														
															|  |  static const char *
 |  |  static const char *
 | 
												
													
														
															|  |  format_flow(struct FLOW *flow)
 |  |  format_flow(struct FLOW *flow)
 | 
												
													
														
															|  |  {
 |  |  {
 | 
												
													
														
															|  | -	char addr1[64], addr2[64], stime[20], ftime[20];
 |  | 
 | 
												
													
														
															|  | 
 |  | +	char addr1[64], addr2[64], stime[32], ftime[32];
 | 
												
													
														
															|  |  	static char buf[1024];
 |  |  	static char buf[1024];
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  	inet_ntop(flow->af, &flow->addr[0], addr1, sizeof(addr1));
 |  |  	inet_ntop(flow->af, &flow->addr[0], addr1, sizeof(addr1));
 | 
												
											
												
													
														
															|  | @@ -288,9 +316,9 @@ transport_to_flowrec(struct FLOW *flow, const u_int8_t *pkt,
 | 
												
													
														
															|  |  	const struct icmp *icmp = (const struct icmp *)pkt;
 |  |  	const struct icmp *icmp = (const struct icmp *)pkt;
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  	/*
 |  |  	/*
 | 
												
													
														
															|  | -	 * XXX to keep flow in proper canonical format, it may be necessary
 |  | 
 | 
												
													
														
															|  | -	 * to swap the array slots based on the order of the port numbers
 |  | 
 | 
												
													
														
															|  | -	 * does this matter in practice??? I don't think so - return flows will
 |  | 
 | 
												
													
														
															|  | 
 |  | +	 * XXX to keep flow in proper canonical format, it may be necessary to
 | 
												
													
														
															|  | 
 |  | +	 * swap the array slots based on the order of the port numbers does
 | 
												
													
														
															|  | 
 |  | +	 * this matter in practice??? I don't think so - return flows will
 | 
												
													
														
															|  |  	 * always match, because of their symmetrical addr/ports
 |  |  	 * always match, because of their symmetrical addr/ports
 | 
												
													
														
															|  |  	 */
 |  |  	 */
 | 
												
													
														
															|  |  
 |  |  
 | 
												
											
												
													
														
															|  | @@ -427,7 +455,7 @@ flow_update_expiry(struct FLOWTRACK *ft, struct FLOW *flow)
 | 
												
													
														
															|  |  {
 |  |  {
 | 
												
													
														
															|  |  	EXPIRY_REMOVE(EXPIRIES, &ft->expiries, flow->expiry);
 |  |  	EXPIRY_REMOVE(EXPIRIES, &ft->expiries, flow->expiry);
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  | -	/* Flows over 2Gb traffic */
 |  | 
 | 
												
													
														
															|  | 
 |  | +	/* Flows over 2 GiB traffic */
 | 
												
													
														
															|  |  	if (flow->octets[0] > (1U << 31) || flow->octets[1] > (1U << 31)) {
 |  |  	if (flow->octets[0] > (1U << 31) || flow->octets[1] > (1U << 31)) {
 | 
												
													
														
															|  |  		flow->expiry->expires_at = 0;
 |  |  		flow->expiry->expires_at = 0;
 | 
												
													
														
															|  |  		flow->expiry->reason = R_OVERBYTES;
 |  |  		flow->expiry->reason = R_OVERBYTES;
 | 
												
											
												
													
														
															|  | @@ -564,8 +592,8 @@ process_packet(struct FLOWTRACK *ft, const u_int8_t *pkt, int af,
 | 
												
													
														
															|  |  	/* If a matching flow does not exist, create and insert one */
 |  |  	/* If a matching flow does not exist, create and insert one */
 | 
												
													
														
															|  |  	if ((flow = FLOW_FIND(FLOWS, &ft->flows, &tmp)) == NULL) {
 |  |  	if ((flow = FLOW_FIND(FLOWS, &ft->flows, &tmp)) == NULL) {
 | 
												
													
														
															|  |  		/* Allocate and fill in the flow */
 |  |  		/* Allocate and fill in the flow */
 | 
												
													
														
															|  | -		if ((flow = malloc(sizeof(*flow))) == NULL) {
 |  | 
 | 
												
													
														
															|  | -			logit(LOG_ERR, "process_packet: flow malloc(%u) fail",
 |  | 
 | 
												
													
														
															|  | 
 |  | +		if ((flow = flow_get(ft)) == NULL) {
 | 
												
													
														
															|  | 
 |  | +			logit(LOG_ERR, "process_packet: flow_get failed",
 | 
												
													
														
															|  |  			    sizeof(*flow));
 |  |  			    sizeof(*flow));
 | 
												
													
														
															|  |  			return (PP_MALLOC_FAIL);
 |  |  			return (PP_MALLOC_FAIL);
 | 
												
													
														
															|  |  		}
 |  |  		}
 | 
												
											
												
													
														
															|  | @@ -576,8 +604,8 @@ process_packet(struct FLOWTRACK *ft, const u_int8_t *pkt, int af,
 | 
												
													
														
															|  |  		FLOW_INSERT(FLOWS, &ft->flows, flow);
 |  |  		FLOW_INSERT(FLOWS, &ft->flows, flow);
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  		/* Allocate and fill in the associated expiry event */
 |  |  		/* Allocate and fill in the associated expiry event */
 | 
												
													
														
															|  | -		if ((flow->expiry = malloc(sizeof(*flow->expiry))) == NULL) {
 |  | 
 | 
												
													
														
															|  | -			logit(LOG_ERR, "process_packet: expiry malloc(%u) fail",
 |  | 
 | 
												
													
														
															|  | 
 |  | +		if ((flow->expiry = expiry_get(ft)) == NULL) {
 | 
												
													
														
															|  | 
 |  | +			logit(LOG_ERR, "process_packet: expiry_get failed",
 | 
												
													
														
															|  |  			    sizeof(*flow->expiry));
 |  |  			    sizeof(*flow->expiry));
 | 
												
													
														
															|  |  			return (PP_MALLOC_FAIL);
 |  |  			return (PP_MALLOC_FAIL);
 | 
												
													
														
															|  |  		}
 |  |  		}
 | 
												
											
												
													
														
															|  | @@ -589,7 +617,8 @@ process_packet(struct FLOWTRACK *ft, const u_int8_t *pkt, int af,
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  		ft->num_flows++;
 |  |  		ft->num_flows++;
 | 
												
													
														
															|  |  		if (verbose_flag)
 |  |  		if (verbose_flag)
 | 
												
													
														
															|  | -			logit(LOG_DEBUG, "ADD FLOW %s", format_flow_brief(flow));
 |  | 
 | 
												
													
														
															|  | 
 |  | +			logit(LOG_DEBUG, "ADD FLOW %s",
 | 
												
													
														
															|  | 
 |  | +			    format_flow_brief(flow));
 | 
												
													
														
															|  |  	} else {
 |  |  	} else {
 | 
												
													
														
															|  |  		/* Update flow statistics */
 |  |  		/* Update flow statistics */
 | 
												
													
														
															|  |  		flow->packets[0] += tmp.packets[0];
 |  |  		flow->packets[0] += tmp.packets[0];
 | 
												
											
												
													
														
															|  | @@ -807,20 +836,21 @@ check_expired(struct FLOWTRACK *ft, struct NETFLOW_TARGET *target, int ex)
 | 
												
													
														
															|  |  			FLOW_REMOVE(FLOWS, &ft->flows, expiry->flow);
 |  |  			FLOW_REMOVE(FLOWS, &ft->flows, expiry->flow);
 | 
												
													
														
															|  |  			EXPIRY_REMOVE(EXPIRIES, &ft->expiries, expiry);
 |  |  			EXPIRY_REMOVE(EXPIRIES, &ft->expiries, expiry);
 | 
												
													
														
															|  |  			expiry->flow->expiry = NULL;
 |  |  			expiry->flow->expiry = NULL;
 | 
												
													
														
															|  | -			free(expiry);
 |  | 
 | 
												
													
														
															|  | 
 |  | +			expiry_put(ft, expiry);
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  			ft->num_flows--;
 |  |  			ft->num_flows--;
 | 
												
													
														
															|  |  		}
 |  |  		}
 | 
												
													
														
															|  |  	}
 |  |  	}
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  	if (verbose_flag)
 |  |  	if (verbose_flag)
 | 
												
													
														
															|  | -		logit(LOG_DEBUG, "Finished scan %d flow(s) to be evicted", num_expired);
 |  | 
 | 
												
													
														
															|  | 
 |  | +		logit(LOG_DEBUG, "Finished scan %d flow(s) to be evicted",
 | 
												
													
														
															|  | 
 |  | +		    num_expired);
 | 
												
													
														
															|  |  	
 |  |  	
 | 
												
													
														
															|  |  	/* Processing for expired flows */
 |  |  	/* Processing for expired flows */
 | 
												
													
														
															|  |  	if (num_expired > 0) {
 |  |  	if (num_expired > 0) {
 | 
												
													
														
															|  |  		if (target != NULL && target->fd != -1) {
 |  |  		if (target != NULL && target->fd != -1) {
 | 
												
													
														
															|  |  			r = target->dialect->func(expired_flows, num_expired, 
 |  |  			r = target->dialect->func(expired_flows, num_expired, 
 | 
												
													
														
															|  | -			    target->fd, &ft->flows_exported, 
 |  | 
 | 
												
													
														
															|  | 
 |  | +			    target->fd, if_index, &ft->flows_exported, 
 | 
												
													
														
															|  |  			    &ft->system_boot_time,  verbose_flag);
 |  |  			    &ft->system_boot_time,  verbose_flag);
 | 
												
													
														
															|  |  			if (verbose_flag)
 |  |  			if (verbose_flag)
 | 
												
													
														
															|  |  				logit(LOG_DEBUG, "sent %d netflow packets", r);
 |  |  				logit(LOG_DEBUG, "sent %d netflow packets", r);
 | 
												
											
												
													
														
															|  | @@ -838,8 +868,7 @@ check_expired(struct FLOWTRACK *ft, struct NETFLOW_TARGET *target, int ex)
 | 
												
													
														
															|  |  				    expired_flows[i]);
 |  |  				    expired_flows[i]);
 | 
												
													
														
															|  |  			}
 |  |  			}
 | 
												
													
														
															|  |  			update_statistics(ft, expired_flows[i]);
 |  |  			update_statistics(ft, expired_flows[i]);
 | 
												
													
														
															|  | -
 |  | 
 | 
												
													
														
															|  | -			free(expired_flows[i]);
 |  | 
 | 
												
													
														
															|  | 
 |  | +			flow_put(ft, expired_flows[i]);
 | 
												
													
														
															|  |  		}
 |  |  		}
 | 
												
													
														
															|  |  	
 |  |  	
 | 
												
													
														
															|  |  		free(expired_flows);
 |  |  		free(expired_flows);
 | 
												
											
												
													
														
															|  | @@ -923,10 +952,10 @@ delete_all_flows(struct FLOWTRACK *ft)
 | 
												
													
														
															|  |  		FLOW_REMOVE(FLOWS, &ft->flows, flow);
 |  |  		FLOW_REMOVE(FLOWS, &ft->flows, flow);
 | 
												
													
														
															|  |  		
 |  |  		
 | 
												
													
														
															|  |  		EXPIRY_REMOVE(EXPIRIES, &ft->expiries, flow->expiry);
 |  |  		EXPIRY_REMOVE(EXPIRIES, &ft->expiries, flow->expiry);
 | 
												
													
														
															|  | -		free(flow->expiry);
 |  | 
 | 
												
													
														
															|  | 
 |  | +		expiry_put(ft, flow->expiry);
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  		ft->num_flows--;
 |  |  		ft->num_flows--;
 | 
												
													
														
															|  | -		free(flow);
 |  | 
 | 
												
													
														
															|  | 
 |  | +		flow_put(ft, flow);
 | 
												
													
														
															|  |  		i++;
 |  |  		i++;
 | 
												
													
														
															|  |  	}
 |  |  	}
 | 
												
													
														
															|  |  	
 |  |  	
 | 
												
											
												
													
														
															|  | @@ -978,26 +1007,28 @@ statistics(struct FLOWTRACK *ft, FILE *out, pcap_t *pcap)
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  		fprintf(out, "\n");
 |  |  		fprintf(out, "\n");
 | 
												
													
														
															|  |  		fprintf(out, "Expired flow reasons:\n");
 |  |  		fprintf(out, "Expired flow reasons:\n");
 | 
												
													
														
															|  | -		fprintf(out, "       tcp = %9llu   tcp.rst = %9llu   tcp.fin = %9llu\n", 
 |  | 
 | 
												
													
														
															|  | -		    ft->expired_tcp, ft->expired_tcp_rst, ft->expired_tcp_fin);
 |  | 
 | 
												
													
														
															|  | -		fprintf(out, "       udp = %9llu      icmp = %9llu   general = %9llu\n",
 |  | 
 | 
												
													
														
															|  | -		    ft->expired_udp, ft->expired_icmp, ft->expired_general);
 |  | 
 | 
												
													
														
															|  | 
 |  | +		fprintf(out, "       tcp = %9llu   tcp.rst = %9llu   "
 | 
												
													
														
															|  | 
 |  | +		    "tcp.fin = %9llu\n", ft->expired_tcp, ft->expired_tcp_rst,
 | 
												
													
														
															|  | 
 |  | +		    ft->expired_tcp_fin);
 | 
												
													
														
															|  | 
 |  | +		fprintf(out, "       udp = %9llu      icmp = %9llu   "
 | 
												
													
														
															|  | 
 |  | +		    "general = %9llu\n", ft->expired_udp, ft->expired_icmp,
 | 
												
													
														
															|  | 
 |  | +		    ft->expired_general);
 | 
												
													
														
															|  |  		fprintf(out, "   maxlife = %9llu\n", ft->expired_maxlife);
 |  |  		fprintf(out, "   maxlife = %9llu\n", ft->expired_maxlife);
 | 
												
													
														
															|  | -		fprintf(out, "  over 2Gb = %9llu\n", ft->expired_overbytes);
 |  | 
 | 
												
													
														
															|  | 
 |  | +		fprintf(out, "over 2 GiB = %9llu\n", ft->expired_overbytes);
 | 
												
													
														
															|  |  		fprintf(out, "  maxflows = %9llu\n", ft->expired_maxflows);
 |  |  		fprintf(out, "  maxflows = %9llu\n", ft->expired_maxflows);
 | 
												
													
														
															|  |  		fprintf(out, "   flushed = %9llu\n", ft->expired_flush);
 |  |  		fprintf(out, "   flushed = %9llu\n", ft->expired_flush);
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  		fprintf(out, "\n");
 |  |  		fprintf(out, "\n");
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  | -		fprintf(out, "Per-protocol statistics:     Octets      Packets   Avg Life    Max Life\n");
 |  | 
 | 
												
													
														
															|  | 
 |  | +		fprintf(out, "Per-protocol statistics:     Octets      "
 | 
												
													
														
															|  | 
 |  | +		    "Packets   Avg Life    Max Life\n");
 | 
												
													
														
															|  |  		for(i = 0; i < 256; i++) {
 |  |  		for(i = 0; i < 256; i++) {
 | 
												
													
														
															|  |  			if (ft->packets_pp[i]) {
 |  |  			if (ft->packets_pp[i]) {
 | 
												
													
														
															|  |  				pe = getprotobynumber(i);
 |  |  				pe = getprotobynumber(i);
 | 
												
													
														
															|  |  				snprintf(proto, sizeof(proto), "%s (%d)", 
 |  |  				snprintf(proto, sizeof(proto), "%s (%d)", 
 | 
												
													
														
															|  |  				    pe != NULL ? pe->p_name : "Unknown", i);
 |  |  				    pe != NULL ? pe->p_name : "Unknown", i);
 | 
												
													
														
															|  | -				fprintf(out, 
 |  | 
 | 
												
													
														
															|  | -				    "  %17s: %14llu %12llu   %8.2fs %10.2fs\n",
 |  | 
 | 
												
													
														
															|  | -				    proto,
 |  | 
 | 
												
													
														
															|  | 
 |  | +				fprintf(out, "  %17s: %14llu %12llu   %8.2fs "
 | 
												
													
														
															|  | 
 |  | +				    "%10.2fs\n", proto,
 | 
												
													
														
															|  |  				    ft->octets_pp[i], 
 |  |  				    ft->octets_pp[i], 
 | 
												
													
														
															|  |  				    ft->packets_pp[i],
 |  |  				    ft->packets_pp[i],
 | 
												
													
														
															|  |  				    ft->duration_pp[i].mean,
 |  |  				    ft->duration_pp[i].mean,
 | 
												
											
												
													
														
															|  | @@ -1164,7 +1195,8 @@ accept_control(int lsock, struct NETFLOW_TARGET *target, struct FLOWTRACK *ft,
 | 
												
													
														
															|  |  		fprintf(ctlf, "\tsend-template\n");
 |  |  		fprintf(ctlf, "\tsend-template\n");
 | 
												
													
														
															|  |  		ret = 0;
 |  |  		ret = 0;
 | 
												
													
														
															|  |  	} else if (strcmp(buf, "shutdown") == 0) {
 |  |  	} else if (strcmp(buf, "shutdown") == 0) {
 | 
												
													
														
															|  | -		fprintf(ctlf, "softflowd[%u]: Shutting down gracefully...\n", getpid());
 |  | 
 | 
												
													
														
															|  | 
 |  | +		fprintf(ctlf, "softflowd[%u]: Shutting down gracefully...\n", 
 | 
												
													
														
															|  | 
 |  | +		    getpid());
 | 
												
													
														
															|  |  		graceful_shutdown_request = 1;
 |  |  		graceful_shutdown_request = 1;
 | 
												
													
														
															|  |  		ret = 1;
 |  |  		ret = 1;
 | 
												
													
														
															|  |  	} else if (strcmp(buf, "exit") == 0) {
 |  |  	} else if (strcmp(buf, "exit") == 0) {
 | 
												
											
												
													
														
															|  | @@ -1186,8 +1218,9 @@ accept_control(int lsock, struct NETFLOW_TARGET *target, struct FLOWTRACK *ft,
 | 
												
													
														
															|  |  		    delete_all_flows(ft));
 |  |  		    delete_all_flows(ft));
 | 
												
													
														
															|  |  		ret = 0;
 |  |  		ret = 0;
 | 
												
													
														
															|  |  	} else if (strcmp(buf, "statistics") == 0) {
 |  |  	} else if (strcmp(buf, "statistics") == 0) {
 | 
												
													
														
															|  | -		fprintf(ctlf, "softflowd[%u]: Accumulated statistics:\n", 
 |  | 
 | 
												
													
														
															|  | -		    getpid());
 |  | 
 | 
												
													
														
															|  | 
 |  | +		fprintf(ctlf, "softflowd[%u]: Accumulated statistics "
 | 
												
													
														
															|  | 
 |  | +		    "since %s UTC:\n", getpid(),
 | 
												
													
														
															|  | 
 |  | +		    format_time(ft->system_boot_time.tv_sec));
 | 
												
													
														
															|  |  		statistics(ft, ctlf, pcap);
 |  |  		statistics(ft, ctlf, pcap);
 | 
												
													
														
															|  |  		ret = 0;
 |  |  		ret = 0;
 | 
												
													
														
															|  |  	} else if (strcmp(buf, "debug+") == 0) {
 |  |  	} else if (strcmp(buf, "debug+") == 0) {
 | 
												
											
												
													
														
															|  | @@ -1395,6 +1428,11 @@ init_flowtrack(struct FLOWTRACK *ft)
 | 
												
													
														
															|  |  	FLOW_INIT(&ft->flows);
 |  |  	FLOW_INIT(&ft->flows);
 | 
												
													
														
															|  |  	EXPIRY_INIT(&ft->expiries);
 |  |  	EXPIRY_INIT(&ft->expiries);
 | 
												
													
														
															|  |  	
 |  |  	
 | 
												
													
														
															|  | 
 |  | +	freelist_init(&ft->flow_freelist, sizeof(struct FLOW));
 | 
												
													
														
															|  | 
 |  | +	freelist_init(&ft->expiry_freelist, sizeof(struct EXPIRY));
 | 
												
													
														
															|  | 
 |  | +
 | 
												
													
														
															|  | 
 |  | +	ft->max_flows = DEFAULT_MAX_FLOWS;
 | 
												
													
														
															|  | 
 |  | +
 | 
												
													
														
															|  |  	ft->track_level = TRACK_FULL;
 |  |  	ft->track_level = TRACK_FULL;
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  	ft->tcp_timeout = DEFAULT_TCP_TIMEOUT;
 |  |  	ft->tcp_timeout = DEFAULT_TCP_TIMEOUT;
 | 
												
											
												
													
														
															|  | @@ -1439,34 +1477,42 @@ argv_join(int argc, char **argv)
 | 
												
													
														
															|  |  static void
 |  |  static void
 | 
												
													
														
															|  |  usage(void)
 |  |  usage(void)
 | 
												
													
														
															|  |  {
 |  |  {
 | 
												
													
														
															|  | -	fprintf(stderr, "Usage: %s [options] [bpf_program]\n", PROGNAME);
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "This is %s version %s. Valid commandline options:\n", PROGNAME, PROGVER);
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  -i interface     Specify interface to listen on\n");
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  -r pcap_file     Specify packet capture file to read\n");
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  -t timeout=time  Specify named timeout\n");
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  -m max_flows     Specify maximum number of flows to track (default %d)\n", DEFAULT_MAX_FLOWS);
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  -n host:port     Send Cisco NetFlow(tm)-compatible packets to host:port\n");
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  -p pidfile       Record pid in specified file (default: %s)\n", DEFAULT_PIDFILE);
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  -c pidfile       Location of control socket (default: %s)\n", DEFAULT_CTLSOCK);
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  -v 1|5|9         NetFlow export packet version\n");
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  -L hoplimit      Set TTL/hoplimit for export datagrams\n");
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  -T full|proto|ip Set flow tracking level (default: full)\n");
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  -6               Track IPv6 flows, regardless of whether selected \n"
 |  | 
 | 
												
													
														
															|  | -	                "                   NetFlow export protocol supports it\n");
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  -d               Don't daemonise\n");
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  -D               Debug mode: don't daemonise + verbosity + track v6 flows\n");
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  -h               Display this help\n");
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "\n");
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "Valid timeout names and default values:\n");
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  tcp     (default %6d)", DEFAULT_TCP_TIMEOUT);
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  tcp.rst (default %6d)", DEFAULT_TCP_RST_TIMEOUT);
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  tcp.fin (default %6d)\n", DEFAULT_TCP_FIN_TIMEOUT);
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  udp     (default %6d)", DEFAULT_UDP_TIMEOUT);
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  icmp    (default %6d)", DEFAULT_ICMP_TIMEOUT);
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  general (default %6d)\n", DEFAULT_GENERAL_TIMEOUT);
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  maxlife (default %6d)", DEFAULT_MAXIMUM_LIFETIME);
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "  expint  (default %6d)\n", DEFAULT_EXPIRY_INTERVAL);
 |  | 
 | 
												
													
														
															|  | -	fprintf(stderr, "\n");
 |  | 
 | 
												
													
														
															|  | 
 |  | +	fprintf(stderr, 
 | 
												
													
														
															|  | 
 |  | +"Usage: %s [options] [bpf_program]\n"
 | 
												
													
														
															|  | 
 |  | +"This is %s version %s. Valid commandline options:\n"
 | 
												
													
														
															|  | 
 |  | +"  -i [idx:]interface Specify interface to listen on\n"
 | 
												
													
														
															|  | 
 |  | +"  -r pcap_file       Specify packet capture file to read\n"
 | 
												
													
														
															|  | 
 |  | +"  -t timeout=time    Specify named timeout\n"
 | 
												
													
														
															|  | 
 |  | +"  -m max_flows       Specify maximum number of flows to track (default %d)\n"
 | 
												
													
														
															|  | 
 |  | +"  -n host:port       Send Cisco NetFlow(tm)-compatible packets to host:port\n"
 | 
												
													
														
															|  | 
 |  | +"  -p pidfile         Record pid in specified file\n"
 | 
												
													
														
															|  | 
 |  | +"                     (default: %s)\n"
 | 
												
													
														
															|  | 
 |  | +"  -c pidfile         Location of control socket\n"
 | 
												
													
														
															|  | 
 |  | +"                     (default: %s)\n"
 | 
												
													
														
															|  | 
 |  | +"  -v 1|5|9           NetFlow export packet version\n"
 | 
												
													
														
															|  | 
 |  | +"  -L hoplimit        Set TTL/hoplimit for export datagrams\n"
 | 
												
													
														
															|  | 
 |  | +"  -T full|proto|ip   Set flow tracking level (default: full)\n"
 | 
												
													
														
															|  | 
 |  | +"  -6                 Track IPv6 flows, regardless of whether selected \n"
 | 
												
													
														
															|  | 
 |  | +"                     NetFlow export protocol supports it\n"
 | 
												
													
														
															|  | 
 |  | +"  -d                 Don't daemonise (run in foreground)\n"
 | 
												
													
														
															|  | 
 |  | +"  -D                 Debug mode: foreground + verbosity + track v6 flows\n"
 | 
												
													
														
															|  | 
 |  | +"  -h                 Display this help\n"
 | 
												
													
														
															|  | 
 |  | +"\n"
 | 
												
													
														
															|  | 
 |  | +"Valid timeout names and default values:\n"
 | 
												
													
														
															|  | 
 |  | +"  tcp     (default %6d)"
 | 
												
													
														
															|  | 
 |  | +"  tcp.rst (default %6d)"
 | 
												
													
														
															|  | 
 |  | +"  tcp.fin (default %6d)\n"
 | 
												
													
														
															|  | 
 |  | +"  udp     (default %6d)"
 | 
												
													
														
															|  | 
 |  | +"  icmp    (default %6d)"
 | 
												
													
														
															|  | 
 |  | +"  general (default %6d)\n"
 | 
												
													
														
															|  | 
 |  | +"  maxlife (default %6d)"
 | 
												
													
														
															|  | 
 |  | +"  expint  (default %6d)\n"
 | 
												
													
														
															|  | 
 |  | +"\n" ,
 | 
												
													
														
															|  | 
 |  | +	    PROGNAME, PROGNAME, PROGVER, DEFAULT_MAX_FLOWS, DEFAULT_PIDFILE,
 | 
												
													
														
															|  | 
 |  | +	    DEFAULT_CTLSOCK, DEFAULT_TCP_TIMEOUT, DEFAULT_TCP_RST_TIMEOUT,
 | 
												
													
														
															|  | 
 |  | +	    DEFAULT_TCP_FIN_TIMEOUT, DEFAULT_UDP_TIMEOUT, DEFAULT_ICMP_TIMEOUT,
 | 
												
													
														
															|  | 
 |  | +	    DEFAULT_GENERAL_TIMEOUT, DEFAULT_MAXIMUM_LIFETIME,
 | 
												
													
														
															|  | 
 |  | +	    DEFAULT_EXPIRY_INTERVAL);
 | 
												
													
														
															|  |  }
 |  |  }
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  static void
 |  |  static void
 | 
												
											
												
													
														
															|  | @@ -1633,8 +1679,8 @@ main(int argc, char **argv)
 | 
												
													
														
															|  |  	const char *pidfile_path, *ctlsock_path;
 |  |  	const char *pidfile_path, *ctlsock_path;
 | 
												
													
														
															|  |  	extern char *optarg;
 |  |  	extern char *optarg;
 | 
												
													
														
															|  |  	extern int optind;
 |  |  	extern int optind;
 | 
												
													
														
															|  | -	int ch, dontfork_flag, linktype, ctlsock, i, r, err, always_v6;
 |  | 
 | 
												
													
														
															|  | -	int max_flows, stop_collection_flag, exit_request, hoplimit;
 |  | 
 | 
												
													
														
															|  | 
 |  | +	int ch, dontfork_flag, linktype, ctlsock, i, err, always_v6, r;
 | 
												
													
														
															|  | 
 |  | +	int stop_collection_flag, exit_request, hoplimit;
 | 
												
													
														
															|  |  	pcap_t *pcap = NULL;
 |  |  	pcap_t *pcap = NULL;
 | 
												
													
														
															|  |  	struct sockaddr_storage dest;
 |  |  	struct sockaddr_storage dest;
 | 
												
													
														
															|  |  	struct FLOWTRACK flowtrack;
 |  |  	struct FLOWTRACK flowtrack;
 | 
												
											
												
													
														
															|  | @@ -1648,6 +1694,7 @@ main(int argc, char **argv)
 | 
												
													
														
															|  |  	init_flowtrack(&flowtrack);
 |  |  	init_flowtrack(&flowtrack);
 | 
												
													
														
															|  |  
 |  |  
 | 
												
													
														
															|  |  	memset(&dest, '\0', sizeof(dest));
 |  |  	memset(&dest, '\0', sizeof(dest));
 | 
												
													
														
															|  | 
 |  | +	dest_len = 0;
 | 
												
													
														
															|  |  	memset(&target, '\0', sizeof(target));
 |  |  	memset(&target, '\0', sizeof(target));
 | 
												
													
														
															|  |  	target.fd = -1;
 |  |  	target.fd = -1;
 | 
												
													
														
															|  |  	target.dialect = &nf[0];
 |  |  	target.dialect = &nf[0];
 | 
												
											
												
													
														
															|  | @@ -1655,11 +1702,11 @@ main(int argc, char **argv)
 | 
												
													
														
															|  |  	bpf_prog = NULL;
 |  |  	bpf_prog = NULL;
 | 
												
													
														
															|  |  	ctlsock = -1;
 |  |  	ctlsock = -1;
 | 
												
													
														
															|  |  	dev = capfile = NULL;
 |  |  	dev = capfile = NULL;
 | 
												
													
														
															|  | -	max_flows = DEFAULT_MAX_FLOWS;
 |  | 
 | 
												
													
														
															|  |  	pidfile_path = DEFAULT_PIDFILE;
 |  |  	pidfile_path = DEFAULT_PIDFILE;
 | 
												
													
														
															|  |  	ctlsock_path = DEFAULT_CTLSOCK;
 |  |  	ctlsock_path = DEFAULT_CTLSOCK;
 | 
												
													
														
															|  |  	dontfork_flag = 0;
 |  |  	dontfork_flag = 0;
 | 
												
													
														
															|  |  	always_v6 = 0;
 |  |  	always_v6 = 0;
 | 
												
													
														
															|  | 
 |  | +
 | 
												
													
														
															|  |  	while ((ch = getopt(argc, argv, "6hdDL:T:i:r:f:t:n:m:p:c:v:")) != -1) {
 |  |  	while ((ch = getopt(argc, argv, "6hdDL:T:i:r:f:t:n:m:p:c:v:")) != -1) {
 | 
												
													
														
															|  |  		switch (ch) {
 |  |  		switch (ch) {
 | 
												
													
														
															|  |  		case '6':
 |  |  		case '6':
 | 
												
											
												
													
														
															|  | @@ -1677,15 +1724,23 @@ main(int argc, char **argv)
 | 
												
													
														
															|  |  			break;
 |  |  			break;
 | 
												
													
														
															|  |  		case 'i':
 |  |  		case 'i':
 | 
												
													
														
															|  |  			if (capfile != NULL || dev != NULL) {
 |  |  			if (capfile != NULL || dev != NULL) {
 | 
												
													
														
															|  | -				fprintf(stderr, "Packet source already specified.\n\n");
 |  | 
 | 
												
													
														
															|  | 
 |  | +				fprintf(stderr, "Packet source already "
 | 
												
													
														
															|  | 
 |  | +				    "specified.\n\n");
 | 
												
													
														
															|  |  				usage();
 |  |  				usage();
 | 
												
													
														
															|  |  				exit(1);
 |  |  				exit(1);
 | 
												
													
														
															|  |  			}
 |  |  			}
 | 
												
													
														
															|  | -			dev = optarg;
 |  | 
 | 
												
													
														
															|  | 
 |  | +			dev = strsep(&optarg, ":");
 | 
												
													
														
															|  | 
 |  | +			if (optarg != NULL) {
 | 
												
													
														
															|  | 
 |  | +				if_index = (u_int16_t) atoi(dev);
 | 
												
													
														
															|  | 
 |  | +				dev = optarg;
 | 
												
													
														
															|  | 
 |  | +			}
 | 
												
													
														
															|  | 
 |  | +			if (verbose_flag)
 | 
												
													
														
															|  | 
 |  | +				fprintf(stderr, "Using %s (idx: %d)\n", dev, if_index);
 | 
												
													
														
															|  |  			break;
 |  |  			break;
 | 
												
													
														
															|  |  		case 'r':
 |  |  		case 'r':
 | 
												
													
														
															|  |  			if (capfile != NULL || dev != NULL) {
 |  |  			if (capfile != NULL || dev != NULL) {
 | 
												
													
														
															|  | -				fprintf(stderr, "Packet source already specified.\n\n");
 |  | 
 | 
												
													
														
															|  | 
 |  | +				fprintf(stderr, "Packet source already "
 | 
												
													
														
															|  | 
 |  | +				    "specified.\n\n");
 | 
												
													
														
															|  |  				usage();
 |  |  				usage();
 | 
												
													
														
															|  |  				exit(1);
 |  |  				exit(1);
 | 
												
													
														
															|  |  			}
 |  |  			}
 | 
												
											
												
													
														
															|  | @@ -1705,7 +1760,8 @@ main(int argc, char **argv)
 | 
												
													
														
															|  |  			else if (strcasecmp(optarg, "ip") == 0)
 |  |  			else if (strcasecmp(optarg, "ip") == 0)
 | 
												
													
														
															|  |  				flowtrack.track_level = TRACK_IP_ONLY;
 |  |  				flowtrack.track_level = TRACK_IP_ONLY;
 | 
												
													
														
															|  |  			else {
 |  |  			else {
 | 
												
													
														
															|  | -				fprintf(stderr, "Unknown flow tracking level\n");
 |  | 
 | 
												
													
														
															|  | 
 |  | +				fprintf(stderr, "Unknown flow tracking "
 | 
												
													
														
															|  | 
 |  | +				    "level\n");
 | 
												
													
														
															|  |  				usage();
 |  |  				usage();
 | 
												
													
														
															|  |  				exit(1);
 |  |  				exit(1);
 | 
												
													
														
															|  |  			}
 |  |  			}
 | 
												
											
												
													
														
															|  | @@ -1719,7 +1775,7 @@ main(int argc, char **argv)
 | 
												
													
														
															|  |  			}
 |  |  			}
 | 
												
													
														
															|  |  			break;
 |  |  			break;
 | 
												
													
														
															|  |  		case 'm':
 |  |  		case 'm':
 | 
												
													
														
															|  | -			if ((max_flows = atoi(optarg)) < 0) {
 |  | 
 | 
												
													
														
															|  | 
 |  | +			if ((flowtrack.max_flows = atoi(optarg)) < 0) {
 | 
												
													
														
															|  |  				fprintf(stderr, "Invalid maximum flows\n\n");
 |  |  				fprintf(stderr, "Invalid maximum flows\n\n");
 | 
												
													
														
															|  |  				usage();
 |  |  				usage();
 | 
												
													
														
															|  |  				exit(1);
 |  |  				exit(1);
 | 
												
											
												
													
														
															|  | @@ -1824,12 +1880,12 @@ main(int argc, char **argv)
 | 
												
													
														
															|  |  	cb_ctxt.ft = &flowtrack;
 |  |  	cb_ctxt.ft = &flowtrack;
 | 
												
													
														
															|  |  	cb_ctxt.linktype = linktype;
 |  |  	cb_ctxt.linktype = linktype;
 | 
												
													
														
															|  |  	cb_ctxt.want_v6 = target.dialect->v6_capable || always_v6;
 |  |  	cb_ctxt.want_v6 = target.dialect->v6_capable || always_v6;
 | 
												
													
														
															|  | -	while (!graceful_shutdown_request) {
 |  | 
 | 
												
													
														
															|  | 
 |  | +
 | 
												
													
														
															|  | 
 |  | +	for (r = 0; graceful_shutdown_request == 0; r = 0) {
 | 
												
													
														
															|  |  		/*
 |  |  		/*
 | 
												
													
														
															|  |  		 * Silly libpcap's timeout function doesn't work, so we
 |  |  		 * Silly libpcap's timeout function doesn't work, so we
 | 
												
													
														
															|  |  		 * do it here (only if we are reading live)
 |  |  		 * do it here (only if we are reading live)
 | 
												
													
														
															|  |  		 */
 |  |  		 */
 | 
												
													
														
															|  | -		r = 0;
 |  | 
 | 
												
													
														
															|  |  		if (capfile == NULL) {
 |  |  		if (capfile == NULL) {
 | 
												
													
														
															|  |  			memset(pl, '\0', sizeof(pl));
 |  |  			memset(pl, '\0', sizeof(pl));
 | 
												
													
														
															|  |  
 |  |  
 | 
												
											
												
													
														
															|  | @@ -1862,13 +1918,15 @@ main(int argc, char **argv)
 | 
												
													
														
															|  |  		/* If we have data, run it through libpcap */
 |  |  		/* If we have data, run it through libpcap */
 | 
												
													
														
															|  |  		if (!stop_collection_flag && 
 |  |  		if (!stop_collection_flag && 
 | 
												
													
														
															|  |  		    (capfile != NULL || pl[0].revents != 0)) {
 |  |  		    (capfile != NULL || pl[0].revents != 0)) {
 | 
												
													
														
															|  | -			r = pcap_dispatch(pcap, max_flows, flow_cb, (void*)&cb_ctxt);
 |  | 
 | 
												
													
														
															|  | 
 |  | +			r = pcap_dispatch(pcap, flowtrack.max_flows, flow_cb,
 | 
												
													
														
															|  | 
 |  | +			    (void*)&cb_ctxt);
 | 
												
													
														
															|  |  			if (r == -1) {
 |  |  			if (r == -1) {
 | 
												
													
														
															|  |  				logit(LOG_ERR, "Exiting on pcap_dispatch: %s", 
 |  |  				logit(LOG_ERR, "Exiting on pcap_dispatch: %s", 
 | 
												
													
														
															|  |  				    pcap_geterr(pcap));
 |  |  				    pcap_geterr(pcap));
 | 
												
													
														
															|  |  				break;
 |  |  				break;
 | 
												
													
														
															|  |  			} else if (r == 0) {
 |  |  			} else if (r == 0) {
 | 
												
													
														
															|  | -				logit(LOG_NOTICE, "Shutting down after pcap EOF");
 |  | 
 | 
												
													
														
															|  | 
 |  | +				logit(LOG_NOTICE, "Shutting down after "
 | 
												
													
														
															|  | 
 |  | +				    "pcap EOF");
 | 
												
													
														
															|  |  				graceful_shutdown_request = 1;
 |  |  				graceful_shutdown_request = 1;
 | 
												
													
														
															|  |  				break;
 |  |  				break;
 | 
												
													
														
															|  |  			}
 |  |  			}
 | 
												
											
												
													
														
															|  | @@ -1886,7 +1944,7 @@ main(int argc, char **argv)
 | 
												
													
														
															|  |  		 * or whenever we have exceeded the maximum number of active 
 |  |  		 * or whenever we have exceeded the maximum number of active 
 | 
												
													
														
															|  |  		 * flows
 |  |  		 * flows
 | 
												
													
														
															|  |  		 */
 |  |  		 */
 | 
												
													
														
															|  | -		if (flowtrack.num_flows > max_flows || 
 |  | 
 | 
												
													
														
															|  | 
 |  | +		if (flowtrack.num_flows > flowtrack.max_flows || 
 | 
												
													
														
															|  |  		    next_expire(&flowtrack) == 0) {
 |  |  		    next_expire(&flowtrack) == 0) {
 | 
												
													
														
															|  |  expiry_check:
 |  |  expiry_check:
 | 
												
													
														
															|  |  			/*
 |  |  			/*
 | 
												
											
												
													
														
															|  | @@ -1895,15 +1953,17 @@ expiry_check:
 | 
												
													
														
															|  |  			 * expire flows when the flow table is full. 
 |  |  			 * expire flows when the flow table is full. 
 | 
												
													
														
															|  |  			 */
 |  |  			 */
 | 
												
													
														
															|  |  			if (check_expired(&flowtrack, &target, 
 |  |  			if (check_expired(&flowtrack, &target, 
 | 
												
													
														
															|  | -			    capfile == NULL ? CE_EXPIRE_NORMAL : CE_EXPIRE_FORCED) < 0)
 |  | 
 | 
												
													
														
															|  | 
 |  | +			    capfile == NULL ? CE_EXPIRE_NORMAL :
 | 
												
													
														
															|  | 
 |  | +			    CE_EXPIRE_FORCED) < 0)
 | 
												
													
														
															|  |  				logit(LOG_WARNING, "Unable to export flows");
 |  |  				logit(LOG_WARNING, "Unable to export flows");
 | 
												
													
														
															|  |  	
 |  |  	
 | 
												
													
														
															|  |  			/*
 |  |  			/*
 | 
												
													
														
															|  |  			 * If we are over max_flows, force-expire the oldest 
 |  |  			 * If we are over max_flows, force-expire the oldest 
 | 
												
													
														
															|  |  			 * out first and immediately reprocess to evict them
 |  |  			 * out first and immediately reprocess to evict them
 | 
												
													
														
															|  |  			 */
 |  |  			 */
 | 
												
													
														
															|  | -			if (flowtrack.num_flows > max_flows) {
 |  | 
 | 
												
													
														
															|  | -				force_expire(&flowtrack, flowtrack.num_flows - max_flows);
 |  | 
 | 
												
													
														
															|  | 
 |  | +			if (flowtrack.num_flows > flowtrack.max_flows) {
 | 
												
													
														
															|  | 
 |  | +				force_expire(&flowtrack,
 | 
												
													
														
															|  | 
 |  | +				    flowtrack.num_flows - flowtrack.max_flows);
 | 
												
													
														
															|  |  				goto expiry_check;
 |  |  				goto expiry_check;
 | 
												
													
														
															|  |  			}
 |  |  			}
 | 
												
													
														
															|  |  		}
 |  |  		}
 |