aboutsummaryrefslogblamecommitdiffstats
path: root/bin/nfextract.c
blob: 038c889940b74105d51f5466117f7b311d0579c7 (plain) (tree)
1
2
3
4


                        
                                   



















                                                                                
                                     



                                        
                    



                 
                   





                    
                   
                     
                      
                 


                        



                                                   
                                            




                                
                                                        

                                                              
                                                                              
                                                      
                                                                             
                                                      

         


                                             

 

                                                              
 
                                                         
 
              
                                                                 

            

                       
                                                                    














                                                                            
            
     
 
 




                                                                      

 


                                                                     

                         
 



                                                                                




                             

                                                                                

              



                                                                    


                                                        
                                  
                         
                                                        
                         
 
                                                                               

                                                                        




                                                                    
                                                                               









                                           


                                                         

                  

                                                                     


                                            

                                                                     
                                            

                  
                                                  



                       
                           

                                                                

                                        
 

                                               
 
                                                                     

                         
 

                                      
 

             

// The MIT License (MIT)

// Copyright (c) 2018 Yun-Chih Chen

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#define _XOPEN_SOURCE 700 // strptime
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200809 // strdup
#endif

#include "extract.h"
#include "main.h"
#include "sql.h"
#include "util.h"

#include <dirent.h>
#include <fcntl.h>
#include <getopt.h>
#include <pthread.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

#define PROG "nfextract"
#define DATE_FORMAT_HUMAN "YYYY-MM-DD [HH:MM][:SS]"
#define DATE_FORMAT "%Y-%m-%d"
#define DATE_FORMAT_FULL DATE_FORMAT " %H:%M"
#define DATE_FORMAT_FULL2 DATE_FORMAT " %H:%M:%S"
#define DATE_FORMAT_OUTPUT DATE_FORMAT_FULL2

const char *help_text =
    "Usage: " PROG " [OPTION]\n"
    "\n"
    "Options:\n"
    "  -d --storage=<dirname>     sqlite storage file\n"
    "  -h --help                  print this help\n"
    "  -v --version               print version information\n"
    "  -s --since=<date>          start showing entries on or newer than the "
    "specified date (format: " DATE_FORMAT_HUMAN ")\n"
    "  -u --until=<date>          stop showing entries on or older than the "
    "specified date (format: " DATE_FORMAT_HUMAN ")\n"
    "\n";

void sig_handler(int signo) {
    if (signo == SIGHUP)
        puts("Terminated due to SIGHUP ...");
}

static void callback(const State *s, const Timerange *range) {
    int nr_entries = s->header->nr_entries;

    DEBUG("callback: extracting %d entries", nr_entries);

    int i = 0;
    while (i < nr_entries && s->store[i].timestamp < range->from)
        i++;

    time_t last_t = 0;
    char timestamp[20];
    while (i < nr_entries && s->store[i].timestamp < range->until) {
        if (last_t != s->store[i].timestamp || !last_t) {
            last_t = s->store[i].timestamp;
            strftime(timestamp, 20, DATE_FORMAT_OUTPUT, localtime(&last_t));
        }

        printf("  "
               "%-18s:\t"
               "daddr=%-16s\t"
               "proto=%s\t"
               "uid=%d\t"
               "sport=%d\t"
               "dport=%d\n",
               timestamp, inet_ntoa(s->store[i].daddr),
               s->store[i].protocol == IPPROTO_TCP ? "TCP" : "UDP",
               s->store[i].uid, s->store[i].sport, s->store[i].dport);
        ++i;
    }
}

static void extract_all(const char *storage, const Timerange *range) {
    sqlite3 *db = NULL;
    db_open(&db, storage);
    db_read_data_by_timerange(db, range, callback);
    db_close(db);
}

static time_t parse_date_string(time_t default_t, const char *date) {
    struct tm parsed;
    char *ret;
    if (!date)
        return default_t;

#define PARSE(FORMAT)                                                          \
    ret = strptime(date, FORMAT, &parsed);                                     \
    if (ret && !*ret)                                                          \
        return mktime(&parsed);

    PARSE(DATE_FORMAT);
    PARSE(DATE_FORMAT_FULL);
    PARSE(DATE_FORMAT_FULL2);

    FATAL("Wrong date format: expected: \"" DATE_FORMAT_HUMAN "\", got: \"%s\"",
          date);
    return -1;
}

static void populate_date_range(Timerange *range, const char *since,
                                const char *until) {
    range->from = parse_date_string(0, since);
    range->until = parse_date_string(time(NULL), until);
}

int main(int argc, char *argv[]) {
    char *storage = NULL;
    char *date_since_str = NULL, *date_until_str = NULL;
    Timerange date_range;

    struct option longopts[] = {{"storage_file", required_argument, NULL, 'd'},
                                {"since", optional_argument, NULL, 's'},
                                {"until", optional_argument, NULL, 'u'},
                                {"help", no_argument, NULL, 'h'},
                                {"version", no_argument, NULL, 'v'},
                                {0, 0, 0, 0}};

    int opt;
    while ((opt = getopt_long(argc, argv, "d:s:u:hv", longopts, NULL)) != -1) {
        switch (opt) {
        case 'h':
            printf("%s", help_text);
            exit(0);
            break;
        case 'v':
            printf("%s %s", PROG, VERSION);
            exit(0);
            break;
        case 'd':
            if (!optarg)
                FATAL("Expected: --storage_file=[PATH]");
            storage = strdup(optarg);
            break;
        case 's':
            if (!optarg)
                FATAL("Expected: --since=\"" DATE_FORMAT_HUMAN "\"");
            date_since_str = strdup(optarg);
            break;
        case 'u':
            if (!optarg)
                FATAL("Expected: --until=\"" DATE_FORMAT_HUMAN "\"");
            date_until_str = strdup(optarg);
            break;
        case '?':
            FATAL("Unknown argument, see --help");
        }
    }

    // verify arguments
    ASSERT(storage != NULL,
           "You must provide a storage directory (see --help)");

    if (check_file_exist(storage) < 0)
        ERROR("storage file not exist");

    if (signal(SIGHUP, sig_handler) == SIG_ERR)
        ERROR("Could not set SIGHUP handler");

    populate_date_range(&date_range, date_since_str, date_until_str);
    free(date_since_str);
    free(date_until_str);

    extract_all(storage, &date_range);
    free(storage);

    return 0;
}