|
@@ -53,6 +53,9 @@
|
|
|
#include "ipfix.h"
|
|
|
#include "psamp.h"
|
|
|
#include <pcap.h>
|
|
|
+#ifdef LINUX
|
|
|
+#include <net/if.h>
|
|
|
+#endif /* LINUX */
|
|
|
|
|
|
#define IPFIX_PORT 4739
|
|
|
|
|
@@ -158,7 +161,7 @@ sighand_other (int signum) {
|
|
|
static int
|
|
|
flow_compare (struct FLOW *a, struct FLOW *b) {
|
|
|
/* Be careful to avoid signed vs unsigned issues here */
|
|
|
- int r;
|
|
|
+ int r, i;
|
|
|
if (track_level == TRACK_FULL_VLAN || track_level == TRACK_FULL_VLAN_ETHER) {
|
|
|
if (a->vlanid[0] != b->vlanid[0])
|
|
|
return (a->vlanid[0] > b->vlanid[0] ? 1 : -1);
|
|
@@ -203,6 +206,13 @@ flow_compare (struct FLOW *a, struct FLOW *b) {
|
|
|
if (a->port[1] != b->port[1])
|
|
|
return (ntohs (a->port[1]) > ntohs (b->port[1]) ? 1 : -1);
|
|
|
|
|
|
+ if (a->mplsLabelStackDepth != b->mplsLabelStackDepth)
|
|
|
+ return (a->mplsLabelStackDepth > b->mplsLabelStackDepth ? 1 : -1);
|
|
|
+ for (i = 0; i < a->mplsLabelStackDepth; i++) {
|
|
|
+ if (a->mplsLabels[i] != b->mplsLabels[i])
|
|
|
+ return (a->mplsLabels[i] > b->mplsLabels[i] ? 1 : -1);
|
|
|
+ }
|
|
|
+
|
|
|
return (0);
|
|
|
}
|
|
|
|
|
@@ -293,7 +303,7 @@ format_ethermac (uint8_t ethermac[6]) {
|
|
|
static const char *
|
|
|
format_flow (struct FLOW *flow) {
|
|
|
char addr1[64], addr2[64], start_time[32], fin_time[32];
|
|
|
- static char buf[1024];
|
|
|
+ static char buf[4096];
|
|
|
|
|
|
inet_ntop (flow->af, &flow->addr[0], addr1, sizeof (addr1));
|
|
|
inet_ntop (flow->af, &flow->addr[1], addr2, sizeof (addr2));
|
|
@@ -326,7 +336,7 @@ format_flow (struct FLOW *flow) {
|
|
|
static const char *
|
|
|
format_flow_brief (struct FLOW *flow) {
|
|
|
char addr1[64], addr2[64];
|
|
|
- static char buf[1024];
|
|
|
+ static char buf[4096];
|
|
|
|
|
|
inet_ntop (flow->af, &flow->addr[0], addr1, sizeof (addr1));
|
|
|
inet_ntop (flow->af, &flow->addr[1], addr2, sizeof (addr2));
|
|
@@ -524,6 +534,7 @@ flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) {
|
|
|
if (flow->octets[0] > (1U << 31) || flow->octets[1] > (1U << 31)) {
|
|
|
flow->expiry->expires_at = 0;
|
|
|
flow->expiry->reason = R_OVERBYTES;
|
|
|
+ flow->flowEndReason = IPFIX_flowEndReason_lackOfResource;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
@@ -533,6 +544,7 @@ flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) {
|
|
|
ft->param.maximum_lifetime) {
|
|
|
flow->expiry->expires_at = 0;
|
|
|
flow->expiry->reason = R_MAXLIFE;
|
|
|
+ flow->flowEndReason = IPFIX_flowEndReason_activeTimeout;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
@@ -543,6 +555,7 @@ flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) {
|
|
|
flow->expiry->expires_at = flow->flow_last.tv_sec +
|
|
|
ft->param.tcp_rst_timeout;
|
|
|
flow->expiry->reason = R_TCP_RST;
|
|
|
+ flow->flowEndReason = IPFIX_flowEndReason_endOfFlow;
|
|
|
goto out;
|
|
|
}
|
|
|
/* Finished TCP flows */
|
|
@@ -551,6 +564,7 @@ flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) {
|
|
|
flow->expiry->expires_at = flow->flow_last.tv_sec +
|
|
|
ft->param.tcp_fin_timeout;
|
|
|
flow->expiry->reason = R_TCP_FIN;
|
|
|
+ flow->flowEndReason = IPFIX_flowEndReason_endOfFlow;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
@@ -559,6 +573,7 @@ flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) {
|
|
|
flow->expiry->expires_at = flow->flow_last.tv_sec +
|
|
|
ft->param.tcp_timeout;
|
|
|
flow->expiry->reason = R_TCP;
|
|
|
+ flow->flowEndReason = IPFIX_flowEndReason_idleTimeout;
|
|
|
goto out;
|
|
|
}
|
|
|
}
|
|
@@ -567,6 +582,7 @@ flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) {
|
|
|
/* UDP flows */
|
|
|
flow->expiry->expires_at = flow->flow_last.tv_sec + ft->param.udp_timeout;
|
|
|
flow->expiry->reason = R_UDP;
|
|
|
+ flow->flowEndReason = IPFIX_flowEndReason_idleTimeout;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
@@ -577,6 +593,7 @@ flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) {
|
|
|
flow->expiry->expires_at = flow->flow_last.tv_sec +
|
|
|
ft->param.icmp_timeout;
|
|
|
flow->expiry->reason = R_ICMP;
|
|
|
+ flow->flowEndReason = IPFIX_flowEndReason_idleTimeout;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
@@ -584,6 +601,7 @@ flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) {
|
|
|
flow->expiry->expires_at = flow->flow_last.tv_sec +
|
|
|
ft->param.general_timeout;
|
|
|
flow->expiry->reason = R_GENERAL;
|
|
|
+ flow->flowEndReason = IPFIX_flowEndReason_idleTimeout;
|
|
|
|
|
|
out:
|
|
|
if (ft->param.maximum_lifetime != 0 && flow->expiry->expires_at != 0) {
|
|
@@ -610,13 +628,13 @@ out:
|
|
|
* (the actual expiry is performed elsewhere)
|
|
|
*/
|
|
|
static int
|
|
|
-process_packet (struct FLOWTRACK *ft, const u_int8_t * pkt, int af,
|
|
|
+process_packet (struct FLOWTRACK *ft, const u_int8_t * frame_data, int af,
|
|
|
const u_int32_t caplen, const u_int32_t len,
|
|
|
struct ether_header *ether, u_int16_t vlanid,
|
|
|
- const struct timeval *received_time) {
|
|
|
+ const struct timeval *received_time, u_int8_t num_label) {
|
|
|
struct FLOW tmp, *flow;
|
|
|
- int frag, ndx;
|
|
|
-
|
|
|
+ int frag, ndx, i;
|
|
|
+ const u_int8_t *pkt = frame_data + num_label * 4;
|
|
|
/* Convert the IP packet to a flow identity */
|
|
|
memset (&tmp, 0, sizeof (tmp));
|
|
|
switch (af) {
|
|
@@ -659,6 +677,11 @@ process_packet (struct FLOWTRACK *ft, const u_int8_t * pkt, int af,
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ tmp.mplsLabelStackDepth = num_label;
|
|
|
+ for (i = 0; i < num_label && i < 10; i++) {
|
|
|
+ tmp.mplsLabels[i] = *(((u_int32_t *) frame_data) + i);
|
|
|
+ }
|
|
|
+
|
|
|
/* If a matching flow does not exist, create and insert one */
|
|
|
if ((flow = FLOW_FIND (FLOWS, &ft->flows, &tmp)) == NULL) {
|
|
|
/* Allocate and fill in the flow */
|
|
@@ -681,6 +704,7 @@ process_packet (struct FLOWTRACK *ft, const u_int8_t * pkt, int af,
|
|
|
/* Must be non-zero (0 means expire immediately) */
|
|
|
flow->expiry->expires_at = 1;
|
|
|
flow->expiry->reason = R_GENERAL;
|
|
|
+ flow->flowEndReason = IPFIX_flowEndReason_idleTimeout;
|
|
|
EXPIRY_INSERT (EXPIRIES, &ft->expiries, flow->expiry);
|
|
|
|
|
|
ft->param.num_flows++;
|
|
@@ -708,7 +732,7 @@ process_packet (struct FLOWTRACK *ft, const u_int8_t * pkt, int af,
|
|
|
* Subtract two timevals. Returns (t1 - t2) in milliseconds.
|
|
|
*/
|
|
|
u_int32_t
|
|
|
-timeval_sub_ms (const struct timeval * t1, const struct timeval * t2) {
|
|
|
+timeval_sub_ms (const struct timeval *t1, const struct timeval *t2) {
|
|
|
struct timeval res;
|
|
|
|
|
|
res.tv_sec = t1->tv_sec - t2->tv_sec;
|
|
@@ -1187,7 +1211,8 @@ dump_flows (struct FLOWTRACK *ft, FILE * out) {
|
|
|
*/
|
|
|
static int
|
|
|
datalink_check (int linktype, const u_int8_t * pkt, u_int32_t caplen, int *af,
|
|
|
- struct ether_header **ether, u_int16_t * vlanid) {
|
|
|
+ struct ether_header **ether, u_int16_t * vlanid,
|
|
|
+ u_int8_t * num_label) {
|
|
|
int i, j;
|
|
|
u_int32_t frametype;
|
|
|
int vlan_size = 0;
|
|
@@ -1221,6 +1246,11 @@ datalink_check (int linktype, const u_int8_t * pkt, u_int32_t caplen, int *af,
|
|
|
*vlanid <<= 8;
|
|
|
*vlanid |= pkt[j + dl->skiplen];
|
|
|
}
|
|
|
+ /*
|
|
|
+ * Mask out the PCP and DEI values,
|
|
|
+ * leaving just the VID.
|
|
|
+ */
|
|
|
+ *vlanid &= 0xFFF;
|
|
|
vlan_size = 4;
|
|
|
}
|
|
|
}
|
|
@@ -1243,7 +1273,21 @@ datalink_check (int linktype, const u_int8_t * pkt, u_int32_t caplen, int *af,
|
|
|
*af = AF_INET;
|
|
|
else if (frametype == dl->ft_v6)
|
|
|
*af = AF_INET6;
|
|
|
- else
|
|
|
+ else if (frametype == ETH_P_MPLS_UC && num_label != NULL) {
|
|
|
+ u_int32_t shim = 0;
|
|
|
+ u_int8_t ip_version = 0;
|
|
|
+ do {
|
|
|
+ shim = *((u_int32_t *) (pkt + dl->skiplen + vlan_size) + *num_label);
|
|
|
+ *num_label += 1;
|
|
|
+ } while (!((ntohl (shim) & MPLS_LS_S_MASK) >> MPLS_LS_S_SHIFT));
|
|
|
+ ip_version = (pkt[dl->skiplen + vlan_size + *num_label * 4] & 0xf0) >> 4;
|
|
|
+ if (ip_version == 4)
|
|
|
+ *af = AF_INET;
|
|
|
+ else if (ip_version == 6)
|
|
|
+ *af = AF_INET6;
|
|
|
+ else
|
|
|
+ return (-1);
|
|
|
+ } else
|
|
|
return (-1);
|
|
|
|
|
|
return (dl->skiplen + vlan_size);
|
|
@@ -1261,6 +1305,8 @@ flow_cb (u_char * user_data, const struct pcap_pkthdr *phdr,
|
|
|
struct timeval tv;
|
|
|
u_int16_t vlanid = 0;
|
|
|
struct ether_header *ether = NULL;
|
|
|
+ u_char *mpls_hdr = NULL;
|
|
|
+ u_int8_t num_label = 0;
|
|
|
|
|
|
if (cb_ctxt->ft->param.total_packets == 0) {
|
|
|
if (cb_ctxt->ft->param.adjust_time) {
|
|
@@ -1283,7 +1329,7 @@ flow_cb (u_char * user_data, const struct pcap_pkthdr *phdr,
|
|
|
}
|
|
|
|
|
|
s = datalink_check (cb_ctxt->linktype, pkt, phdr->caplen, &af, ðer,
|
|
|
- &vlanid);
|
|
|
+ &vlanid, &num_label);
|
|
|
if (s < 0 || (!cb_ctxt->want_v6 && af == AF_INET6)) {
|
|
|
cb_ctxt->ft->param.non_ip_packets++;
|
|
|
cb_ctxt->ft->param.total_packets--;
|
|
@@ -1291,7 +1337,8 @@ flow_cb (u_char * user_data, const struct pcap_pkthdr *phdr,
|
|
|
tv.tv_sec = phdr->ts.tv_sec;
|
|
|
tv.tv_usec = phdr->ts.tv_usec;
|
|
|
if (process_packet (cb_ctxt->ft, pkt + s, af, phdr->caplen - s,
|
|
|
- phdr->len - s, ether, vlanid, &tv) == PP_MALLOC_FAIL)
|
|
|
+ phdr->len - s, ether, vlanid, &tv,
|
|
|
+ num_label) == PP_MALLOC_FAIL)
|
|
|
cb_ctxt->fatal = 1;
|
|
|
}
|
|
|
if (cb_ctxt->ft->param.adjust_time)
|
|
@@ -1471,6 +1518,19 @@ recvsock (uint16_t portnumber) {
|
|
|
return rsock;
|
|
|
}
|
|
|
|
|
|
+#ifdef LINUX
|
|
|
+static void
|
|
|
+bind_device (int sock, char *ifname) {
|
|
|
+ struct ifreq ifr;
|
|
|
+ memset (&ifr, 0, sizeof (ifr));
|
|
|
+ strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
|
|
|
+ if (setsockopt
|
|
|
+ (sock, SOL_SOCKET, SO_BINDTODEVICE, (void *) &ifr, sizeof (ifr)) < 0) {
|
|
|
+ perror ("SO_BINDTODEVICE failed");
|
|
|
+ }
|
|
|
+}
|
|
|
+#endif /* LINUX */
|
|
|
+
|
|
|
static int
|
|
|
connsock (struct sockaddr_storage *addr, socklen_t len, int hoplimit,
|
|
|
int protocol) {
|
|
@@ -1566,21 +1626,44 @@ unix_listener (const char *path) {
|
|
|
|
|
|
static void
|
|
|
setup_packet_capture (struct pcap **pcap, int *linktype,
|
|
|
- char *dev, char *capfile, char *bpf_prog, int need_v6) {
|
|
|
+ char *dev, char *capfile, char *bpf_prog, int need_v6,
|
|
|
+ int promisc, int buffer_size_override) {
|
|
|
char ebuf[PCAP_ERRBUF_SIZE];
|
|
|
struct bpf_program prog_c;
|
|
|
u_int32_t bpf_mask, bpf_net;
|
|
|
+ int res;
|
|
|
|
|
|
/* Open pcap */
|
|
|
if (dev != NULL) {
|
|
|
if (!snaplen)
|
|
|
snaplen = need_v6 ? LIBPCAP_SNAPLEN_V6 : LIBPCAP_SNAPLEN_V4;
|
|
|
- if ((*pcap = pcap_open_live (dev, snaplen, 1, 0, ebuf)) == NULL) {
|
|
|
- fprintf (stderr, "pcap_open_live: %s\n", ebuf);
|
|
|
+ if ((*pcap = pcap_create (dev, ebuf)) == NULL) {
|
|
|
+ fprintf (stderr, "pcap_create: %s\n", ebuf);
|
|
|
+ exit (1);
|
|
|
+ }
|
|
|
+ if ((res = pcap_set_snaplen (*pcap, snaplen)) != 0) {
|
|
|
+ fprintf (stderr, "pcap_set_snaplen: %s\n", pcap_geterr (*pcap));
|
|
|
exit (1);
|
|
|
}
|
|
|
+ if ((res = pcap_set_promisc (*pcap, promisc)) != 0) {
|
|
|
+ fprintf (stderr, "pcap_set_promisc: %s\n", pcap_geterr (*pcap));
|
|
|
+ exit (1);
|
|
|
+ }
|
|
|
+ if ((res = pcap_set_timeout (*pcap, 0)) != 0) {
|
|
|
+ fprintf (stderr, "pcap_set_timeout: %s\n", pcap_geterr (*pcap));
|
|
|
+ exit (1);
|
|
|
+ }
|
|
|
+ if (buffer_size_override > 0)
|
|
|
+ if ((res = pcap_set_buffer_size (*pcap, buffer_size_override)) != 0) {
|
|
|
+ fprintf (stderr, "pcap_set_buffer_size: %s\n", pcap_geterr (*pcap));
|
|
|
+ exit (1);
|
|
|
+ }
|
|
|
if (pcap_lookupnet (dev, &bpf_net, &bpf_mask, ebuf) == -1)
|
|
|
bpf_net = bpf_mask = 0;
|
|
|
+ if ((res = pcap_activate (*pcap)) != 0) {
|
|
|
+ fprintf (stderr, "pcap_activate: %s\n", pcap_geterr (*pcap));
|
|
|
+ exit (1);
|
|
|
+ }
|
|
|
} else {
|
|
|
if ((*pcap = pcap_open_offline (capfile, ebuf)) == NULL) {
|
|
|
fprintf (stderr, "pcap_open_offline(%s): %s\n", capfile, ebuf);
|
|
@@ -1589,7 +1672,7 @@ setup_packet_capture (struct pcap **pcap, int *linktype,
|
|
|
bpf_net = bpf_mask = 0;
|
|
|
}
|
|
|
*linktype = pcap_datalink (*pcap);
|
|
|
- if (datalink_check (*linktype, NULL, 0, NULL, NULL, NULL) == -1) {
|
|
|
+ if (datalink_check (*linktype, NULL, 0, NULL, NULL, NULL, NULL) == -1) {
|
|
|
fprintf (stderr, "Unsupported datalink type %d\n", *linktype);
|
|
|
exit (1);
|
|
|
}
|
|
@@ -1701,6 +1784,7 @@ usage (void) {
|
|
|
" -P udp|tcp|sctp Specify transport layer protocol for exporting packets\n"
|
|
|
" -A sec|milli|micro|nano Specify absolute time format form exporting records\n"
|
|
|
" -s sampling_rate Specify periodical sampling rate (denominator)\n"
|
|
|
+ " -B bytes Libpcap buffer size in bytes\n"
|
|
|
" -b Bidirectional mode in IPFIX (-b work with -v 10)\n"
|
|
|
" -a Adjusting time for reading pcap file (-a work with -r)\n"
|
|
|
" -C capture_length Specify length for packet capture (snaplen)\n"
|
|
@@ -1709,6 +1793,11 @@ usage (void) {
|
|
|
#ifdef ENABLE_PTHREAD
|
|
|
" -M Enable multithread\n"
|
|
|
#endif /* ENABLE_PTHREAD */
|
|
|
+ " -N Disable promiscuous mode\n"
|
|
|
+#ifdef LINUX
|
|
|
+ " -S send_interface_name Specify send interface name\n"
|
|
|
+#endif /* LINUX */
|
|
|
+ " -x Specify number of MPLS labels\n"
|
|
|
" -h Display this help\n"
|
|
|
"\n"
|
|
|
"Valid timeout names and default values:\n"
|
|
@@ -1870,23 +1959,25 @@ drop_privs (void) {
|
|
|
exit (1);
|
|
|
}
|
|
|
#if defined(HAVE_SETRESGID)
|
|
|
- if (setresgid (pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1) {
|
|
|
+ if (setresgid (pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1)
|
|
|
#elif defined(HAVE_SETREGID)
|
|
|
- if (setregid (pw->pw_gid, pw->pw_gid) == -1) {
|
|
|
+ if (setregid (pw->pw_gid, pw->pw_gid) == -1)
|
|
|
#else
|
|
|
- if (setegid (pw->pw_gid) == -1 || setgid (pw->pw_gid) == -1) {
|
|
|
+ if (setegid (pw->pw_gid) == -1 || setgid (pw->pw_gid) == -1)
|
|
|
#endif
|
|
|
+ {
|
|
|
logit (LOG_ERR, "Couldn't set gid (%u): %s",
|
|
|
(unsigned int) pw->pw_gid, strerror (errno));
|
|
|
exit (1);
|
|
|
}
|
|
|
#if defined(HAVE_SETRESUID)
|
|
|
- if (setresuid (pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) {
|
|
|
+ if (setresuid (pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
|
|
|
#elif defined(HAVE_SETREUID)
|
|
|
- if (setreuid (pw->pw_uid, pw->pw_uid) == -1) {
|
|
|
+ if (setreuid (pw->pw_uid, pw->pw_uid) == -1)
|
|
|
#else
|
|
|
- if (seteuid (pw->pw_uid) == -1 || setuid (pw->pw_uid) == -1) {
|
|
|
+ if (seteuid (pw->pw_uid) == -1 || setuid (pw->pw_uid) == -1)
|
|
|
#endif
|
|
|
+ {
|
|
|
logit (LOG_ERR, "Couldn't set uid (%u): %s",
|
|
|
(unsigned int) pw->pw_uid, strerror (errno));
|
|
|
exit (1);
|
|
@@ -1907,9 +1998,13 @@ main (int argc, char **argv) {
|
|
|
struct CB_CTXT cb_ctxt;
|
|
|
struct pollfd pl[2];
|
|
|
struct DESTINATION *dest;
|
|
|
+ int pcap_override_buffer_size = 0;
|
|
|
int protocol = IPPROTO_UDP;
|
|
|
int version = 0;
|
|
|
int rsock = 0, recvport = IPFIX_PORT, recvloop = 0;
|
|
|
+#ifdef LINUX
|
|
|
+ char *send_ifname;
|
|
|
+#endif /* LINUX */
|
|
|
#ifdef ENABLE_PTHREAD
|
|
|
int use_thread = 0;
|
|
|
pthread_t read_thread = 0;
|
|
@@ -1917,6 +2012,7 @@ main (int argc, char **argv) {
|
|
|
pthread_mutex_init (&read_mutex, NULL);
|
|
|
pthread_cond_init (&read_cond, NULL);
|
|
|
#endif /* ENABLE_PTHREAD */
|
|
|
+ int use_promisc = 1;
|
|
|
|
|
|
closefrom (STDERR_FILENO + 1);
|
|
|
|
|
@@ -1935,7 +2031,7 @@ main (int argc, char **argv) {
|
|
|
|
|
|
while ((ch =
|
|
|
getopt (argc, argv,
|
|
|
- "6hdDL:T:i:r:f:t:n:m:p:c:v:s:P:A:baC:lR:M")) != -1) {
|
|
|
+ "6hdDL:T:i:r:f:t:n:m:p:c:v:s:P:A:B:baC:lR:MNS:x:")) != -1) {
|
|
|
switch (ch) {
|
|
|
case '6':
|
|
|
always_v6 = 1;
|
|
@@ -1974,6 +2070,10 @@ main (int argc, char **argv) {
|
|
|
}
|
|
|
if (verbose_flag)
|
|
|
fprintf (stderr, "Using %s (idx: %d)\n", dev, if_index);
|
|
|
+ strncpy (flowtrack.param.option.interfaceName, dev,
|
|
|
+ strlen (dev) <
|
|
|
+ sizeof (flowtrack.param.option.interfaceName) ?
|
|
|
+ strlen (dev) : sizeof (flowtrack.param.option.interfaceName));
|
|
|
break;
|
|
|
case 'r':
|
|
|
if (capfile != NULL || dev != NULL) {
|
|
@@ -1984,6 +2084,11 @@ main (int argc, char **argv) {
|
|
|
capfile = optarg;
|
|
|
dontfork_flag = 1;
|
|
|
ctlsock_path = NULL;
|
|
|
+ strncpy (flowtrack.param.option.interfaceName, capfile,
|
|
|
+ strlen (capfile) <
|
|
|
+ sizeof (flowtrack.param.option.interfaceName) ?
|
|
|
+ strlen (capfile) :
|
|
|
+ sizeof (flowtrack.param.option.interfaceName));
|
|
|
break;
|
|
|
case 't':
|
|
|
/* Will exit on failure */
|
|
@@ -2064,6 +2169,9 @@ main (int argc, char **argv) {
|
|
|
flowtrack.param.option.sample = 0;
|
|
|
}
|
|
|
break;
|
|
|
+ case 'B':
|
|
|
+ pcap_override_buffer_size = atoi (optarg);
|
|
|
+ break;
|
|
|
case 'P':
|
|
|
if (strcasecmp (optarg, "udp") == 0)
|
|
|
protocol = IPPROTO_UDP;
|
|
@@ -2117,6 +2225,23 @@ main (int argc, char **argv) {
|
|
|
use_thread = 1;
|
|
|
#endif /* ENABLE_PTHREAD */
|
|
|
break;
|
|
|
+ case 'N':
|
|
|
+ use_promisc = 0;
|
|
|
+ break;
|
|
|
+#ifdef LINUX
|
|
|
+ case 'S':
|
|
|
+ send_ifname = optarg;
|
|
|
+ break;
|
|
|
+#endif /* LINUX */
|
|
|
+ case 'x':
|
|
|
+ flowtrack.param.max_num_label = atoi (optarg);
|
|
|
+ if (flowtrack.param.max_num_label < 0
|
|
|
+ || flowtrack.param.max_num_label > 10) {
|
|
|
+ fprintf (stderr, "Invalid number of MPLS label\n\n");
|
|
|
+ usage ();
|
|
|
+ exit (1);
|
|
|
+ }
|
|
|
+ break;
|
|
|
default:
|
|
|
fprintf (stderr, "Invalid commandline option.\n");
|
|
|
usage ();
|
|
@@ -2136,7 +2261,8 @@ main (int argc, char **argv) {
|
|
|
/* Will exit on failure */
|
|
|
if (capfile != NULL || dev != NULL)
|
|
|
setup_packet_capture (&pcap, &linktype, dev, capfile, bpf_prog,
|
|
|
- target.dialect->v6_capable || always_v6);
|
|
|
+ target.dialect->v6_capable || always_v6,
|
|
|
+ use_promisc, pcap_override_buffer_size);
|
|
|
else if (rsock > 0)
|
|
|
linktype = 1; //LINKTYPE_ETHERNET
|
|
|
|
|
@@ -2164,6 +2290,11 @@ main (int argc, char **argv) {
|
|
|
} else
|
|
|
#endif
|
|
|
dest->sock = connsock (&dest->ss, dest->sslen, hoplimit, protocol);
|
|
|
+#ifdef LINUX
|
|
|
+ if (dest->sock > 0 && send_ifname != NULL) {
|
|
|
+ bind_device (dest->sock, send_ifname);
|
|
|
+ }
|
|
|
+#endif /* LINUX */
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2216,8 +2347,9 @@ main (int argc, char **argv) {
|
|
|
for (dest_idx = 0; dest_idx < target.num_destinations; dest_idx++) {
|
|
|
dest = &target.destinations[dest_idx];
|
|
|
if (dest->ss.ss_family != 0) {
|
|
|
- logit (LOG_NOTICE, "Exporting flows to [%s]:%s", dest->hostname,
|
|
|
- dest->servname);
|
|
|
+ logit (LOG_NOTICE, "Exporting flows from %s to [%s]:%s",
|
|
|
+ flowtrack.param.option.interfaceName,
|
|
|
+ dest->hostname, dest->servname);
|
|
|
}
|
|
|
}
|
|
|
flowtrack.param.option.meteringProcessId = getpid ();
|