"Fossies" - the Fresh Open Source Software Archive

Member "tcpflow-1.6.1/src/flow.cpp" (19 Feb 2021, 6524 Bytes) of package /linux/misc/tcpflow-1.6.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "flow.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.5.0_vs_1.6.1.

    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 
   31 void flow::usage()
   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",
  107                          mac_saddr[0],mac_saddr[1],mac_saddr[2],mac_saddr[3],mac_saddr[4],mac_saddr[5]);
  108                 break;
  109             case 'e':
  110                 snprintf(buf,sizeof(buf),"%02x:%02x:%02x:%02x:%02x:%02x",
  111                          mac_daddr[0],mac_daddr[1],mac_daddr[2],mac_daddr[3],mac_daddr[4],mac_daddr[5]);
  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
  131         if(vlan!=be13::packet_info::NO_VLAN) ss << vlan;
  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 
  183 std::string flow::new_pcap_filename()
  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 }