/** * * flow.cpp: * * The flow class is used to track individual TCP/IP flows (2 per connection). * The class implements the methods that turn a flow into a filename. * * This file is part of tcpflow by Jeremy Elson * Initial Release: 7 April 1999. * * This source code is under the GNU Public License (GPL). See * LICENSE for details. * */ #include "tcpflow.h" #include "tcpip.h" #include "tcpdemux.h" #ifdef HAVE_ARPA_INET_H #include // inet_ntop #endif #include #include #include std::string flow::filename_template("%A.%a-%B.%b%V%v%C%c"); std::string flow::outdir("."); void flow::usage() { std::cout << "\n" "Filename template format for option -T:\n"; std::cout << " %A/%a - source IP address/port; %B/%b - dest IP address/port\n"; std::cout << " %E/%e - source/dest Ethernet Mac address\n"; std::cout << " %V/%v - VLAN number, '--' if no vlan/'' if no vlan\n"; std::cout << " %T/%t - Timestamp in ISO8601 format/unix time_t\n"; std::cout << " %c - connection_count for connections>0 / %# for all connections;"; std::cout << " %C - 'c' if connection_count >0\n"; std::cout << " %N - (connection_number ) % 1000\n"; std::cout << " %K - (connection_number / 1000) % 1000\n"; std::cout << " %M - (connection_number / 1000000) % 1000\n"; std::cout << " %G - (connection_number / 1000000000) % 1000\n"; std::cout << " %S - session ID\n"; std::cout << " %% - Output a '%'\n"; std::cout << "\n"; std::cout << "Default value is: '"<< flow::filename_template <<"'\n"; std::cout << "\n"; std::cout << "Note: Using the option -T will ignore options -Fk, -Fm and -Fg.\n"; std::cout << " Filename template format handles '/' to create sub-directories.\n"; } std::string flow::filename(uint32_t connection_count, bool is_pcap) { std::stringstream ss; /* Add the outdir */ if(flow::outdir!="." && flow::outdir!=""){ ss << flow::outdir; ss << '/'; } for(unsigned int i=0;i0 if(connection_count>0) ss << "c"; break; case 'c': // connection_count if connection_count >0 if(connection_count>0) ss << connection_count; break; case 'S': // session ID ss << std::setfill('0') << std::setw(20) << session_id; break; case '#': // always output connection count ss << connection_count; break; case '%': // Output a '%' ss << "%"; break; default: std::cerr << "Invalid filename_template: " << filename_template << "\n"; std::cerr << "unknown character: " << filename_template.at(i+1) << "\n"; exit(1); } if(buf[0]) ss << buf; } } if(is_pcap){ ss << ".pcap"; // file extension } return ss.str(); } /** * Find an unused filename for the flow and optionally open it. * This is called from tcpip::open_file(). */ std::string flow::new_filename(int *fd,int flags,int mode) { /* Loop connection count until we find a file that doesn't exist */ for(uint32_t connection_count=0;;connection_count++){ std::string nfn = filename(connection_count, false); if(nfn.find('/')!=std::string::npos) mkdirs_for_path(nfn.c_str()); int nfd = tcpdemux::getInstance()->retrying_open(nfn,flags,mode); if(nfd>=0){ *fd = nfd; return nfn; } if(errno!=EEXIST) die("Cannot open: %s",nfn.c_str()); } return std::string("<>"); // error; no file } std::string flow::new_pcap_filename() { /* Loop connection count until we find a file that doesn't exist */ for(uint32_t connection_count=0;;connection_count++){ std::string nfn = filename(connection_count, true); if(nfn.find('/')!=std::string::npos) mkdirs_for_path(nfn.c_str()); return nfn; } return std::string("<>"); // error; no file }