/*
 * pcap_helpers.cpp
 *
 * Author: Francesco Montorsi
 * Website: https://github.com/f18m/large-pcap-analyzer
 *
 *
 * LICENSE:
        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation; either version 2 of the License, or
        (at your option) any later version.

        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.

        You should have received a copy of the GNU General Public License
        along with this program; if not, write to the Free Software
        Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
        MA 02110-1301, USA.

 */

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------

#include "pcap_helpers.h"
#include "printf_helpers.h"

// adapted from
// http://sourcecodebrowser.com/libpcapnav/0.8/pcapnav__append_8c.html#a918994d1d2d679e4aaad41f7724360ea

pcap_dumper_t* pcap_dump_append(pcap_t* pcap, const char* filename)
{
    char pcap_errbuf[PCAP_ERRBUF_SIZE];
    pcap_t* pn = NULL;
    FILE* result = NULL;

    pn = pcap_open_offline(filename, pcap_errbuf);
    if (pn == NULL) {

        result = (FILE*)pcap_dump_open(pcap, filename);
        if (result) {
            // file does not exit... create it with the regular PCAP API function
            return (pcap_dumper_t*)result;
        } else {
            printf_error("Cannot open file: %s\n", pcap_errbuf);
            return NULL;
        }
    }

    /* Check whether the linklayer protocols are compatible -- if not,
   * then we cannot append (at least not without linklayer adaptors).
   *
   * Note that we do NOT check against pn->trace.filehdr.linktype
   * directly. Pcap's internal mapping mechanism may cause a different
   * value to be stored in the header structure than reported through
   * pcap_datalink(), so we must make sure we use pcap_datalink() in
   * both cases to ensure comparability.
   */
    if (pcap_datalink(pn) != pcap_datalink(pcap)) {
        printf_error("linklayer protocols incompatible (%i/%i)", pcap_datalink(pn),
            pcap_datalink(pcap));
        pcap_close(pn);
        return NULL;
    }

    if (!(result = fopen(filename, "r+"))) {
        printf_error("Error opening '%s' in r+ mode.\n", filename);
        goto error_return;
    }

#if 0
    /* Check whether the snaplen will need to be updated: */
    if (pcap_snapshot(pn) < pcap_snapshot(pcap))
    {
        //struct pcap_file_header filehdr;

        printf_error( "snaplen needs updating from %d to %d.\n",
                pcap_snapshot(pn), pcap_snapshot(pcap));

/*
        filehdr = pn->trace.filehdr;
        filehdr.snaplen = pcap_snapshot(pcap);

        if (fwrite(&filehdr, sizeof(struct pcap_file_header), 1, result) != 1)
        {
            D(("Cannot write corrected file header.\n"));
            goto error_return;
        }*/
        goto error_return;
    }
#endif

    if (fseek(result, 0, SEEK_END) < 0) {
        printf_error("Error seeking to end of file.\n");
        goto error_return;
    }

#if 0
    if (mode == PCAPNAV_DUMP_APPEND_SAFE)
    {
      if (! append_fix_trunc_packet(pn, result))
       {
         D(("Fixing truncated packet failed.\n"));
         goto error_return;
       }
    }
#endif

    pcap_close(pn);
    return (pcap_dumper_t*)result;

error_return:
    pcap_close(pn);
    return NULL;
}

int pcap_compile_bpf(struct bpf_program* program, const char* buf)
{
    pcap_t* p;
    int ret;

    p = pcap_open_dead(DLT_EN10MB, MAX_SNAPLEN);
    if (p == NULL) {
        return -1;
    }

    ret = pcap_compile(p, program, buf, 0 /* optimize */, PCAP_NETMASK_UNKNOWN /* process packet from any network */);
    pcap_close(p);
    return ret;
}
