raw sockets, pcap files & wireshark quirks?

So this is one of those things that you don’t stumble upon until you are playing with it. When writing sniffers you can use libpcap or it’s win32 version winpcap. Now that doesn’t really do the job in all circumstances, since sometimes you don’t want to install an additional library. Lucky for us you can also sniff traffic by using raw sockets(I’m assuming win32, for the rest of the blog entry). Usually when sniffing with raw sockets you are looking for something specific in the stream of data and can just output it to a good old plain text file…however sometimes you’d just like to capture everything that comes through the network interface. That’s when it becomes interesting to save packets in the PCAP format, so I decided to write my own quick & dirty implementation.

Now here comes the fun part, when sniffing the packets you get everything above the Physical Layer. This means that the Ethernet header is lost and you directly receive the IP header. I did not realize this until I had written the packets into a PCAP file. When trying to open the file with Wireshark, it tries to interpret the first bytes as a Ethernet header which fails horribly. So I came up with two possible solutions:

  • Understand / Configure wireshark to start directly with the IP interpretation
    • Tried this for a while, then decided to go for the second option just for fun.
  • Add a fake Ethernet header to each packet.
    • As previously stated this was the final choice

Well it worked like a charm, Wireshark correctly interpreted the packets and dissected the rest of the contents just as I was used to with normal captures. If anyone knows how to correct the problem WITHOUT writing the fake Ethernet header, by just configuring wireshark correctly DO share.

Here is one last and small warning/readme, before I post the src, for those wanting to play with raw sockets…I’ve noticed some weird behavior myself when testing the sniffer on Win7.

http://www.nirsoft.net/utils/smsniff.html#problems

Under Windows 2000/XP (or greater), SmartSniff also allows you to capture TCP/IP packets without installing any capture driver, by using ‘Raw Sockets’ method. However, this capture method has some limitations and problems:

  • Outgoing UDP and ICMP packets are not captured.
  • On Windows XP SP1 outgoing packets are not captured at all – Thanks to Microsoft’s bug that appeared in SP1 update…
    This bug was fixed on SP2 update, but under Vista, Microsoft returned back the outgoing packets bug of XP/SP1.
  • On Windows Vista with SP1, only UDP packets are captured. TCP packets are not captured at all.
  • On Windows 7, it seems that ‘Raw Sockets’ method works properly again, at least for now…

The header file:


/*

DiabloHorn, fun with pcap and raw sockets

*/

#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#include <time.h>

typedef struct pcap_hdr_s {
 unsigned int magic_number;   /* magic number */
 unsigned short version_major;  /* major version number */
 unsigned short version_minor;  /* minor version number */
 int  thiszone;       /* GMT to local correction */
 unsigned int sigfigs;        /* accuracy of timestamps */
 unsigned int snaplen;        /* max length of captured packets, in octets */
 unsigned int network;        /* data link type */
} pcap_hdr;

typedef struct pcaprec_hdr_s {
 unsigned int ts_sec;         /* timestamp seconds */
 unsigned int ts_usec;        /* timestamp microseconds */
 unsigned int incl_len;       /* number of octets of packet saved in file */
 unsigned int orig_len;       /* actual length of packet */
} pcaprec_hdr;

HANDLE openpcap(LPCWSTR);
void writepcaprec(HANDLE,void *,int);
void closepcap(HANDLE);

The C file


/*

 DiabloHorn, fun with pcap and raw sockets

 */
#include "pcap.h"

/*
 Opens a pcap file for appending, file is set to +S +H.
 Writes the general header.
*/
HANDLE openpcap(LPCWSTR filename){
 HANDLE hFile = NULL;
 pcap_hdr *genHeader;
 DWORD numWritten;
 //create file with shared read access and set it's attrib to +S +H
 hFile = CreateFile(filename,FILE_APPEND_DATA,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,NULL);
 if(hFile == INVALID_HANDLE_VALUE){
 return hFile;
 }else if(GetLastError() == ERROR_ALREADY_EXISTS){
 printf("Appending to existing pcap file\n");
 return hFile;
 }
 printf("Created empty pcap file\n");
 genHeader = (pcap_hdr *)malloc(sizeof(pcap_hdr));
 memset(genHeader,0,sizeof(pcap_hdr));
 genHeader->magic_number = 0xa1b2c3d4;
 genHeader->network = 1;//ethernet
 genHeader->sigfigs = 0;
 genHeader->snaplen = 65535;
 genHeader->thiszone = 0;
 genHeader->version_major = 2;
 genHeader->version_minor = 4;
 printf("Writing general pcap header\n");

 if(WriteFile(hFile,genHeader,sizeof(pcap_hdr),&numWritten,NULL) == 0){
 //need something more sexy here
 return INVALID_HANDLE_VALUE;
 }
 free(genHeader);
 return hFile;
}

/*
 Write the record of the pcap file
 Write record header (does not take into account the time stuff)
 Write fake eth header
 Write actual ip load data
 NOTE: supplied data must be max size 65521, due to specs in general header
 reason cause of fakeeth and me liking 65535 as a number :-)
*/
void writepcaprec(HANDLE hFile,void *data,int datalen){
 pcaprec_hdr *recHeader;
 DWORD numWritten;
 time_t seconds;
 //fake eth header
 byte fakeeth[14] = {0xde,0xde,0xde,0xde,0xde,0xad,0xbe,0xbe,0xbe,0xbe,0xbe,0xef,0x08,0x00};
 seconds = time(NULL);
 //write pcap record header stuff
 recHeader = (pcaprec_hdr *)malloc(sizeof(pcaprec_hdr));
 memset(recHeader,0,sizeof(pcaprec_hdr));
 recHeader->incl_len = datalen+sizeof(fakeeth);
 recHeader->orig_len = datalen+sizeof(fakeeth);
 recHeader->ts_sec = (unsigned int)seconds;
 recHeader->ts_usec = 0;
 printf("Writing record pcap header\n");
 WriteFile(hFile,recHeader,sizeof(pcaprec_hdr),&numWritten,NULL);
 free(recHeader);
 printf("Writing fake eth header\n");
 //write fake eth header, to fix wireshark
 WriteFile(hFile,fakeeth,sizeof(fakeeth),&numWritten,NULL);
 printf("Writing record data\n");
 //write pcap data stuff
 WriteFile(hFile,data,datalen,&numWritten,NULL);
}

/*
 Prolly hardly used but ohwell...
*/
void closepcap(HANDLE hFile){
 CloseHandle(hFile);
}

3 thoughts on “raw sockets, pcap files & wireshark quirks?”

  1. In Windows (post SP2) you can’t really gain access to the lower level protocol information without using WinPcap because WinPcap implements a custom networking driver that gains access to the lower level (unfiltered) networking data. This was done in Windows for supposed security reasons because implementing raw socket captures was never intended for general use, only for those who are involved with prototyping new protocols or revising old ones.

    WinPcap is the reason why Wireshark is capable of capturing all levels of the incoming packets. As well as capturing, winpcap is also capable of filtering the types of packets that are captured and dumping them directly to the hard drive. Wireshark provides convenient GUI for implementing WinPcap (filtering, dumping to files, etc) as well as adding the capability to do post capture processing. If you want to do this programaticallly and you’re using anything other than C you’ll need to find a wrapper library for your specific language.

    Welcome to the world of low-level networking.

  2. if your still looking for a way to tell wireshark to interpret packets as IP…
    setting linktype value in pcap file header to DLT_RAW (maybe LINKTYPE_RAW) should do the trick
    line 28, c file
    genHeader->network = 1; change to genHeader->network = 101;
    (LINKTYPE_RAW == 101)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: