tcpflow  1.6.1
About: tcpflow is a TCP/IP packet demultiplexer that captures data transmitted as part of TCP connections (flows), and stores the data in a way that is convenient for protocol analysis and debugging.
  Fossies Dox: tcpflow-1.6.1.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

flow.cpp
Go to the documentation of this file.
1 /**
2  *
3  * flow.cpp:
4  *
5  * The flow class is used to track individual TCP/IP flows (2 per connection).
6  * The class implements the methods that turn a flow into a filename.
7  *
8  * This file is part of tcpflow by Jeremy Elson <jelson@circlemud.org>
9  * Initial Release: 7 April 1999.
10  *
11  * This source code is under the GNU Public License (GPL). See
12  * LICENSE for details.
13  *
14  */
15 
16 #include "tcpflow.h"
17 #include "tcpip.h"
18 #include "tcpdemux.h"
19 
20 #ifdef HAVE_ARPA_INET_H
21 #include <arpa/inet.h> // inet_ntop
22 #endif
23 
24 #include <assert.h>
25 #include <iostream>
26 #include <sstream>
27 
28 std::string flow::filename_template("%A.%a-%B.%b%V%v%C%c");
29 std::string flow::outdir(".");
30 
32 {
33  std::cout << "\n"
34  "Filename template format for option -T:\n";
35  std::cout << " %A/%a - source IP address/port; %B/%b - dest IP address/port\n";
36  std::cout << " %E/%e - source/dest Ethernet Mac address\n";
37  std::cout << " %V/%v - VLAN number, '--' if no vlan/'' if no vlan\n";
38  std::cout << " %T/%t - Timestamp in ISO8601 format/unix time_t\n";
39  std::cout << " %c - connection_count for connections>0 / %# for all connections;";
40  std::cout << " %C - 'c' if connection_count >0\n";
41  std::cout << " %N - (connection_number ) % 1000\n";
42  std::cout << " %K - (connection_number / 1000) % 1000\n";
43  std::cout << " %M - (connection_number / 1000000) % 1000\n";
44  std::cout << " %G - (connection_number / 1000000000) % 1000\n";
45  std::cout << " %S - session ID\n";
46  std::cout << " %% - Output a '%'\n";
47  std::cout << "\n";
48  std::cout << "Default value is: '"<< flow::filename_template <<"'\n";
49  std::cout << "\n";
50  std::cout << "Note: Using the option -T will ignore options -Fk, -Fm and -Fg.\n";
51  std::cout << " Filename template format handles '/' to create sub-directories.\n";
52 }
53 
54 std::string flow::filename(uint32_t connection_count, bool is_pcap)
55 {
56  std::stringstream ss;
57 
58  /* Add the outdir */
59  if(flow::outdir!="." && flow::outdir!=""){
60  ss << flow::outdir;
61  ss << '/';
62  }
63 
64  for(unsigned int i=0;i<filename_template.size();i++){
65  switch(filename_template.at(i)){
66  default:
67  ss << filename_template.at(i);
68  break;
69  case '%':
70  if(i==filename_template.size()-1){
71  std::cerr << "Invalid filename_template: " << filename_template << " cannot end with a %\n";
72  exit(1);
73  }
74  /* put the substitute in ss or buf */
75  char buf[1024];
76  buf[0] = 0;
77  switch(filename_template.at(++i)){
78  case 'A': // source IP address
79  switch(family){
80  case AF_INET:
81  snprintf(buf,sizeof(buf),"%03d.%03d.%03d.%03d",
82  src.addr[0], src.addr[1], src.addr[2], src.addr[3]);
83  break;
84  case AF_INET6:
85  inet_ntop(family, src.addr, buf,sizeof(buf));
86  }
87  break;
88  case 'a': // source IP port
89  snprintf(buf,sizeof(buf),"%05d",sport);
90  break;
91  case 'B': // dest IP address
92  switch(family){
93  case AF_INET:
94  snprintf(buf,sizeof(buf),"%03d.%03d.%03d.%03d",
95  dst.addr[0], dst.addr[1], dst.addr[2], dst.addr[3]);
96  break;
97  case AF_INET6:
98  inet_ntop(family, dst.addr, buf,sizeof(buf));
99  }
100  break;
101  case 'b': // dest IP port
102  snprintf(buf,sizeof(buf),"%05d",dport);
103  break;
104  /* binning by connection number */
105  case 'E':
106  snprintf(buf,sizeof(buf),"%02x:%02x:%02x:%02x:%02x:%02x",
108  break;
109  case 'e':
110  snprintf(buf,sizeof(buf),"%02x:%02x:%02x:%02x:%02x:%02x",
112  break;
113  case 'N': snprintf(buf,sizeof(buf),"%03d",(int)(id) % 1000);break;
114  case 'K': snprintf(buf,sizeof(buf),"%03d",(int)(id /1000 ) % 1000);break;
115  case 'M': snprintf(buf,sizeof(buf),"%03d",(int)(id /1000000) % 1000);break;
116  case 'G': snprintf(buf,sizeof(buf),"%03d",(int)(id /1000000000) % 1000);break;
117 
118  case 'T': // Timestamp in ISO8601 format
119  {
120  time_t t = tstart.tv_sec;
121  strftime(buf,sizeof(buf),"%Y-%m-%dT%H:%M:%SZ",gmtime(&t));
122  break;
123  }
124  case 't': // Unix time_t
125  ss << tstart.tv_sec;
126  break;
127  case 'V': // '--' if VLAN is present
128  if(vlan!=be13::packet_info::NO_VLAN) ss << "--";
129  break;
130  case 'v': // VLAN number if VLAN is present
132  break;
133  case 'C': // 'c' if connection_count >0
134  if(connection_count>0) ss << "c";
135  break;
136  case 'c': // connection_count if connection_count >0
137  if(connection_count>0) ss << connection_count;
138  break;
139  case 'S': // session ID
140  ss << std::setfill('0') << std::setw(20) << session_id;
141  break;
142  case '#': // always output connection count
143  ss << connection_count;
144  break;
145  case '%': // Output a '%'
146  ss << "%";
147  break;
148  default:
149  std::cerr << "Invalid filename_template: " << filename_template << "\n";
150  std::cerr << "unknown character: " << filename_template.at(i+1) << "\n";
151  exit(1);
152  }
153  if(buf[0]) ss << buf;
154  }
155  }
156  if(is_pcap){
157  ss << ".pcap"; // file extension
158  }
159  return ss.str();
160 }
161 
162 /**
163  * Find an unused filename for the flow and optionally open it.
164  * This is called from tcpip::open_file().
165  */
166 
167 std::string flow::new_filename(int *fd,int flags,int mode)
168 {
169  /* Loop connection count until we find a file that doesn't exist */
170  for(uint32_t connection_count=0;;connection_count++){
171  std::string nfn = filename(connection_count, false);
172  if(nfn.find('/')!=std::string::npos) mkdirs_for_path(nfn.c_str());
173  int nfd = tcpdemux::getInstance()->retrying_open(nfn,flags,mode);
174  if(nfd>=0){
175  *fd = nfd;
176  return nfn;
177  }
178  if(errno!=EEXIST) die("Cannot open: %s",nfn.c_str());
179  }
180  return std::string("<<CANNOT CREATE FILE>>"); // error; no file
181 }
182 
184 {
185  /* Loop connection count until we find a file that doesn't exist */
186  for(uint32_t connection_count=0;;connection_count++){
187  std::string nfn = filename(connection_count, true);
188  if(nfn.find('/')!=std::string::npos) mkdirs_for_path(nfn.c_str());
189  return nfn;
190  }
191  return std::string("<<CANNOT CREATE FILE>>"); // error; no file
192 }
ipaddr dst
Definition: tcpip.h:98
ipaddr src
Definition: tcpip.h:96
sa_family_t family
Definition: tcpip.h:101
uint16_t dport
Definition: tcpip.h:100
uint16_t sport
Definition: tcpip.h:99
int32_t vlan
Definition: tcpip.h:178
uint8_t mac_saddr[6]
Definition: tcpip.h:180
std::string new_pcap_filename()
Definition: flow.cpp:183
std::string new_filename(int *fd, int flags, int mode)
Definition: flow.cpp:167
static std::string outdir
Definition: tcpip.h:160
uint64_t session_id
Definition: tcpip.h:186
static void usage()
Definition: flow.cpp:31
struct timeval tstart
Definition: tcpip.h:181
uint8_t mac_daddr[6]
Definition: tcpip.h:179
static std::string filename_template
Definition: tcpip.h:159
std::string filename(uint32_t connection_count, bool)
Definition: flow.cpp:54
uint8_t addr[16]
Definition: tcpip.h:41
int retrying_open(const std::string &filename, int oflag, int mask)
Definition: tcpdemux.cpp:121
static tcpdemux * getInstance()
Definition: tcpdemux.cpp:103
flags
Definition: http_parser.h:216
const char * inet_ntop(int af, const void *addr, char *buf, socklen_t len)
Definition: inet_ntop.c:41
unsigned int uint32_t
Definition: core.h:40
void die(const char *fmt,...)
Definition: util.cpp:175
void mkdirs_for_path(std::string path)
Definition: util.cpp:112