2
votes

I'm writing a program that should convert strongSwan log to WireShark packets. So, for instance, we have a sequence like this one in a text file.

Feb 14 14:53:22 dubu12 charon: 13[IKE] sending cert request for "C=RU, ST=NW, O=Company, CN=StronSwanSERV"
Feb 14 14:53:22 dubu12 charon: 13[IKE] shared Diffie Hellman secret => 128 bytes @ 0x7f36e8001ed0
Feb 14 14:53:22 dubu12 charon: 13[IKE] 0: 23 D9 25 9F F1 78 9F C4 83 89 2F 06 E3 DB C2 69 #.%..x..../....i
Feb 14 14:53:22 dubu12 charon: 13[IKE] 16: 24 06 49 01 75 2E 6A 4F AF E6 07 9C F9 77 07 A1 $.I.u.jO.....w..
Feb 14 14:53:22 dubu12 charon: 13[IKE] 32: 02 D8 52 0C F0 27 10 14 19 69 B8 B7 CB 0F 41 40 ..R..'...i....A@
Feb 14 14:53:22 dubu12 charon: 13[IKE] 48: 72 AA 50 8C 90 FF 4D C8 66 88 6C F8 44 B3 2E A2 r.P...M.f.l.D...
Feb 14 14:53:22 dubu12 charon: 13[IKE] 64: 62 F4 C8 4B 31 3C A9 DF DE C8 DF 85 6D 3E E7 56 b..K1<......m>.V
Feb 14 14:53:22 dubu12 charon: 13[IKE] 80: 9D 32 6B 29 C9 7E 9F 41 9C C2 EB D8 8D 3F 51 68 .2k).~.A.....?Qh
Feb 14 14:53:22 dubu12 charon: 13[IKE] 96: 75 74 3A 96 D6 09 B6 34 38 D8 28 5E 6F 7D 20 44 ut:....48.(^o} D
Feb 14 14:53:22 dubu12 charon: 13[IKE] 112: E3 3F 72 1E DD A5 73 B0 CC E0 92 8C 7A 54 3B 34 .?r...s.....zT;4

I have my own class that performs all the actions via Libpcap.

int TgrReader::dump(std::deque<TgrPacket> deqTgrPacket, char* fileName)
{
  pcap_t* pHandle = pcap_open_dead(DLT_RAW, 65535);
  pcap_dumper_t* pDumper = pcap_dump_open(pHandle, fileName);
  std::deque<TgrPacket>::iterator iter=deqTgrPacket.begin();
  while(iter != deqTgrPacket.end())
  {
    pcap_dump(reinterpret_cast<u_char*>(pDumper), &(iter->header), reinterpret_cast<u_char*>(iter->data.toLocal8Bit().data()));
    iter++;
  }
  pcap_dump_close(pDumper);
  pcap_close(pHandle);
  return 0;
}

So, we have that packet. We have the header for packet made, data (strings from 0: to 112:) is being stored in char* variable. I'm trying to dump a packet like this, but it messes up positions somehow

.enter image description here I tried to google a proper way of dumping in a situation like this, but can't seem to find a solution. Anyone knows what I'm doing wrong?

============================================

UPD: The deque with data contains elements of this:

struct TgrPacket
{
  pcap_pkthdr header;
  QString data;
  TgrPacket(pcap_pkthdr pHeader, QString pData);
};

So the data is stored in a single QString. While scanning the text file, I'm looking for the first string of data (that looks like "... 0: 23 D9 25...") and cut everything from ": " and append it to the QString data. Then I get data from next strings until I reach the last line of this packet, then I start looking for new packets again. After I finished appending my QString, I get the time of the packet, convert it to time_val and create a structure with time_val field and QString with data. The function is like this if you want to have a look:

std::deque<TgrPacket> TgrReader::readFile(std::deque<TgrPacket>& deqTgrPacket)
{
    //1) read to "dataString"
    //2) parse it
    //3) loop add data from "dataString" to "qDataString" if data was found
    //4) eject time from "dataString" and add it to "vTm", which is struct tm type
    //5) create packet and add to deque
    char* dataString = new char [ 255 ];
    char* dataBlock = new char [40];
    QString* qTimeString = new QString;
    QString* qTempDataString = new QString;
    time_t vTime_t = 0;
    struct tm* vTm = new tm;
    while(!feof(srcFile))
    {
        fgets(dataString, 65535, srcFile);
        switch(parse(dataString, stringState))
        {
        case BLANK: //skip blank lines
            stringState = BLANK;
            break;
        case LINE: //read data lines until last one is read
            stringState = LINE;
            qTimeString = new QString;            
            qTempDataString = new QString;
            vTime_t = 0;
            vTm = new tm;
            while(stringState != END && !feof(srcFile))
            {
                sscanf(dataString, "%*s %*s %*s %s", dataBlock);
                for(int j = 39 + strlen(dataBlock); j < strlen(dataString) - 17; j++)
                {
                    qTempDataString->append(dataString[j]);
                }
                fgets(dataString, 65535, srcFile);                
                qTimeString->append(dataString);
                stringState = parse(dataString, stringState);
            }
            stringState = END;
            qTimeString->truncate(15);
            vTm->tm_year = 114;
            strptime(qTimeString->toLatin1().data(),"%h  %d %H:%M:%S",vTm);
            vTime_t = mktime(vTm);
            deqTgrPacket.push_back(createPacket(&vTime_t, qTempDataString, qTempDataString->length()));
            break;
        }
    }
    return deqTgrPacket;
}
1
The problem is probably how you read the source log file and how you store your data in the structure(s) you have. Please show the involved structures and how you read/parse the actual data from the log file. - Some programmer dude
Added some more info for you, hope this will help us to find a solution - Leonid Bor
To start with, you have undefined behavior in your code: You allocate 255 characters for dataString but then allow up to 65535 bytes to be read into it. Also you should never to while (!feof(...)), as the EOF flag is not set until after you try to read from beyond the file. In this case do while (fgets(...) != NULL). And why are you using C file I/O instead of C++ streams? And why pointers for the QString objects (which you allocate twice and never free). And you never free the vTm object either (no pointer needed here too). - Some programmer dude
Even if some functions require a pointer, you don't actually have to use pointers and new. Take for example your mktime call, it wants you to provide a pointer to a struct tm, so you make a pointer and allocate memory for it. Instead you can just declare a non-pointer variable and use the address-of operator to make a pointer of it, like tm vTm; ...; vTime_t = mktime(&vTm); No pointer, no allocation, no memory leak. - Some programmer dude
Thx for all the advises, I'll work on it in the future for sure. But still, the main problem at the moment is incorrert data writing. Any thoughts about that? - Leonid Bor

1 Answers

0
votes

While I don't know PCAP really, I will make an educated guess: The pcap_dump function expects the data (passed as the last argument) to be the actual binary data of the packet. Since you read and stored the data as a string then pcap_dump will dump the ASCII values.

You should probably parse the data into bytes of binary data instead of as a string. Using the standard library (as I don't know Qt well enough) you could probably do something like this:

std::istringstream istr(qTempDataString->toStdString());
std::string value;
std::string data;
while (istr >> value)
    data += static_cast<char>(std::stoi(value, nullptr, 16));

*qTempDataString = QString::fromStdString(data);

The important bits here are the istr >> value which extracts a whitespace delimited "word" from the stream and puts it into the string value, and std::stoi(value, nullptr, 16) which takes the string and converts it to a number (the 16 is the base, which is hexadecimal).