Raw socket programming on windows with Winpcap

By | August 1, 2020

Raw sockets with winpcap

A previous post explains how to send raw packets using winsock api on windows xp.

However the winsock api has limited raw socket support in windows versions greater than windows xp+sp1.

Therefore winpcap has to be used to send raw packets on higher windows versions.

Winpcap is a packet driver useful for packet capturing and sending raw packets on the windows platform.

Raw means we have to cook the whole packet ourselves.

A TCP packet for example consists of:

1. Ethernet header
2. IP header
3. TCP header
4. The data supposed to be send
PACKET = ETHERNET_HEADER + IP_HEADER + TCP_HEADER + DATA

Each header has its own job to do in the whole transmission process.

Code :

u_char packet[65536];

Winpcap gives us one function called pcap_sendpacket() to throw the packet on the network adapter which forwards it. We have to responsibly construct the ethernet , ip and tcp headers and attach the data.

Ethernet Header

Structure

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|       Ethernet destination address (first 32 bits)            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Ethernet dest (last 16 bits)  |Ethernet source (first 16 bits)|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|       Ethernet source address (last 32 bits)                  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|        Type code              |                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

C structure for ethernet header :

//Ethernet Header
typedef struct ethernet_header
{
	UCHAR dest[6]; //Total 48 bits
	UCHAR source[6]; //Total 48 bits
	USHORT type; //16 bits
}   ETHER_HDR , *PETHER_HDR , FAR * LPETHER_HDR , ETHERHeader;

Ethernet destination address is the mac-address of the primary gateway of the network interface being used.
Ethernet source is the mac-address of the network interface itself.
Type field determines the type of the packet e.g. IP , ARP etc.

Now our first task is to get the source and destination mac address.
Winpcap gives the ip-addresses of all available network interfaces that can be used.

Get Mac address
If srcip has the source ip in in_addr or long format then we can get the mac-address of this ip address using the function GetMacAddress. This function is codes in the source code.

GetMacAddress(s_mac , srcip);
printf("Selected device has mac address : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X",s_mac[0],s_mac[1],s_mac[2],s_mac[3],s_mac[4],s_mac[5]);

GetMacAddress is like :

void GetMacAddress(unsigned char *mac , in_addr destip) 
{
    DWORD ret;
    in_addr srcip;
    ULONG MacAddr[2];
    ULONG PhyAddrLen = 6;  /* default to length of six bytes */
 
    srcip.s_addr=0;

    //Now print the Mac address also
    ret = SendArp(destip , srcip , MacAddr , &PhyAddrLen);
    if(PhyAddrLen) {
        BYTE *bMacAddr = (BYTE *) & MacAddr;
        for (int i = 0; i < (int) PhyAddrLen; i++) 
            mac[i] = (char)bMacAddr[i];
    }
}

SendArp is the method that is used to retrieve the "mac-address of a IP". It is defined in iphlpapi.dll

The above demonstration is mostly self-explaining. We got the mac-address of the network interface or IP we want to use. This method shall be used to get the mac address of local computer and the gateway.

Next task is to get the ip address of the primary gateway of a certain interface.

Get the Gateway IP

Next we need the IP address of the primary gateway of this interface and then it mac-address.

GetGateway gets the gateway :

void GetGateway(struct in_addr ip , char *sgatewayip , int *gatewayip) {
    char pAdapterInfo[5000];
    PIP_ADAPTER_INFO  AdapterInfo;
    ULONG OutBufLen = sizeof(pAdapterInfo) ;
 
    GetAdaptersInfo((PIP_ADAPTER_INFO) pAdapterInfo, &OutBufLen); 
    for(AdapterInfo = (PIP_ADAPTER_INFO)pAdapterInfo; AdapterInfo ; AdapterInfo = AdapterInfo->Next) {
        if(ip.s_addr == inet_addr(AdapterInfo->IpAddressList.IpAddress.String))
     strcpy(sgatewayip , AdapterInfo->GatewayList.IpAddress.String);
    }
    *gatewayip = inet_addr(sgatewayip);
}

GetAdaptersInfo is the function that retrieves a lot of information about a adapter.
This and SendArp are inside iphlpapi.dll ; IP helper api which we shall load and get the function pointers inside!

Buzz!

void loadiphlpapi() {
    HINSTANCE hDll = LoadLibrary("iphlpapi.dll");
  
    GetAdaptersInfo = (pgetadaptersinfo)GetProcAddress(hDll,"GetAdaptersInfo");
    if(GetAdaptersInfo==NULL)
        printf("Error in iphlpapi.dll%d",GetLastError());
    SendArp = (psendarp)GetProcAddress(hDll,"SendARP");
    if(SendArp==NULL)
 printf("Error in iphlpapi.dll%d",GetLastError());
}

By now we have the following information available :

1. Source IP address - IP of local computer.
2. Mac address of local computer.
3. Primary gateway of local computer.
4. Mac address of primary gateway.

The above 4 things are enough to build the ethernet header. Enjoy!

It is simple as :

ETHER_HDR *ehdr;
memcpy(ehdr->source , s_mac , 6); //Source Mac address
memcpy(ehdr->dest,d_mac,6); //Destination MAC address
ehdr->type = htons(0x0800); //IP Frames

TCP Packet Structure

The tcp packet structure has 2 parts. The IP header and the TCP header. First we shall take a look at the structures as defined in the RFC and then code them in C.

IP Header

RFC 791 gives the structure of an IP header as:

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          Total Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Identification        |Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Time to Live |    Protocol   |         Header Checksum       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Source Address                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Destination Address                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

C structure for IP header:

typedef struct ip_hdr
{
    unsigned char  ip_header_len:4;  // 4-bit header length (in 32-bit words) normally=5 (Means 20 Bytes may be 24 also)
    unsigned char  ip_version   :4;  // 4-bit IPv4 version
    unsigned char  ip_tos;           // IP type of service
    unsigned short ip_total_length;  // Total length
    unsigned short ip_id;            // Unique identifier 

    unsigned char  ip_frag_offset   :5;        // Fragment offset field
 
    unsigned char  ip_more_fragment :1;
    unsigned char  ip_dont_fragment :1;
    unsigned char  ip_reserved_zero :1;
 
    unsigned char  ip_frag_offset1;    //fragment offset
 
    unsigned char  ip_ttl;           // Time to live
    unsigned char  ip_protocol;      // Protocol(TCP,UDP etc)
    unsigned short ip_checksum;      // IP checksum
    unsigned int   ip_srcaddr;       // Source address
    unsigned int   ip_destaddr;      // Source address
}   IPV4_HDR, *PIPV4_HDR, FAR * LPIPV4_HDR , IPHeader;

TCP Header

The following is the structure of a TCP header.

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Sequence Number                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Acknowledgment Number                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Data |           |U|A|P|R|S|F|                               |
| Offset| Reserved  |R|C|S|S|Y|I|            Window             |
|       |           |G|K|H|T|N|N|                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Checksum            |         Urgent Pointer        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             data                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

C structure for TCP header:

// TCP header
typedef struct tcp_header
{
 unsigned short source_port;   // source port
 unsigned short dest_port;     // destination port
 unsigned int sequence;        // sequence number - 32 bits
 unsigned int acknowledge;     // acknowledgement number - 32 bits

 unsigned char ns :1;          //Nonce Sum Flag Added in RFC 3540.
 unsigned char reserved_part1:3; //according to rfc
 unsigned char data_offset:4;    /*The number of 32-bit words
                                   in the TCP header.
                                   This indicates where the data begins.
                                   The length of the TCP header
                                   is always a multiple
                                   of 32 bits.*/

 unsigned char fin :1; //Finish Flag
 unsigned char syn :1; //Synchronise Flag
 unsigned char rst :1; //Reset Flag
 unsigned char psh :1; //Push Flag
 unsigned char ack :1; //Acknowledgement Flag
 unsigned char urg :1; //Urgent Flag

 unsigned char ecn :1; //ECN-Echo Flag
 unsigned char cwr :1; //Congestion Window Reduced Flag

 ////////////////////////////////

 unsigned short window; // window
 unsigned short checksum; // checksum
 unsigned short urgent_pointer; // urgent pointer
} TCP_HDR , *PTCP_HDR , FAR * LPTCP_HDR , TCPHeader , TCP_HEADER;

Build the IP and TCP Headers

// *******************  IP Header *****************
    iphdr = (PIPV4_HDR)(packet + sizeof(ETHER_HDR));
 
    iphdr->ip_version = 4;
    iphdr->ip_header_len = 5; //In double words thats 4 bytes
    iphdr->ip_tos = 0;
    iphdr->ip_total_length = htons (sizeof(IPV4_HDR) + sizeof(TCP_HDR) + strlen(dump));
    iphdr->ip_id = htons(2);
    iphdr->ip_frag_offset = 0;
    iphdr->ip_reserved_zero=0;
    iphdr->ip_dont_fragment=1;
    iphdr->ip_more_fragment=0;
    iphdr->ip_frag_offset1 = 0;
    iphdr->ip_ttl    = 3;
    iphdr->ip_protocol = IPPROTO_TCP;
    iphdr->ip_srcaddr  = inet_addr("1.2.3.4");   //srcip.s_addr;
    iphdr->ip_destaddr = inet_addr("1.2.3.5");
    iphdr->ip_checksum =0;
    iphdr->ip_checksum = in_checksum((unsigned short*)iphdr, sizeof(IPV4_HDR));

    // *******************  TCP Header *****************
    tcphdr = (PTCP_HDR)(packet + sizeof(ETHER_HDR) + sizeof(IPV4_HDR));
 
    tcphdr->source_port = htons(SOURCE_PORT);
    tcphdr->dest_port = htons(80);
    tcphdr->sequence=0;
    tcphdr->acknowledge=0;
    tcphdr->reserved_part1=0;
    tcphdr->data_offset=5;
    tcphdr->fin=0;
    tcphdr->syn=1;
    tcphdr->rst=0;
    tcphdr->psh=0;
    tcphdr->ack=0;
    tcphdr->urg=0;
    tcphdr->ecn=0;
    tcphdr->cwr=0;
    tcphdr->window = htons(64240);
    tcphdr->checksum=0;
    tcphdr->urgent_pointer = 0;

Add some Data

After preparing the IP and TCP headers we can add application data to the packet.

char *dump = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
data = (char*)(packet + sizeof(ETHER_HDR) + sizeof(IPV4_HDR) + sizeof(TCP_HDR));
strcpy(data,dump);

Send Packet

The pcap_sendpacket function is used to send the raw packet on the network. The call to the function looks as follows:

pcap_sendpacket(fp , packet , sizeof(ETHER_HDR) + sizeof(IPV4_HDR) + sizeof(TCP_HDR) + strlen(dump));

Thats should send the packet. Use Wireshark to check whether the packet was successfully transmitted.

The above was an example of a TCP packet. Similarly UDP ICMP or any other packet can be build.

Compile and Run

The download link for the source code is given below. It is a VC++ 6.0 project. Open then and compile and run.
This program needs Winpcap.

Download and install winpcap. Also download the winpcap developer files which include the necessary headers (pcap.h and others) and the library files (wpcap.lib) to be linked.

Place the winpcap header and library files somewhere in your project workspace. Then in Vc++ go to Tools > Options > Directories and add the directory path of include and library files.

When compiling you might get a Winpcap error related to _W64 macro. Follow this article to solve it.

Output

Username : abc
Retrieving the available devices...Retrieved.
The following devices found :

1)
rpcap://\Device\NPF_{EA7C1F00-CD10-4288-8B0D-EBD63C22F468}
Description: Network adapter 'Intel(R) 82566DC Gigabit Network Connection (Micro
soft's Packet Scheduler) ' on local host
Loopback: No
Address Family: #2
Address Family Name: AF_INET
Address: 192.168.0.101
Netmask: 255.255.255.0
Broadcast Address: 255.255.255.255

Enter the device number you want to use : 1
Selected device has mac address : 00-1C-C0-F8-79-EE
Selected device has gateway : 192.168.0.1 (Mac : 00-1E-58-B8-D4-69)
Opening the selected device...Opened
Sending Packet...Send
Press any key to continue

Download Full Source Code

The full source code for the above program can be downloaded here:

Download Source Code

Conclusion

The program by default sends 1 packet. If you want to flood the destination then uncomment the while loop.
If any firewall like Zonealarm is running then packets might not be send.

So switch them off when experimenting with this code.

If you have any questions or feedback, let us know in the comments below.

About Silver Moon

A Tech Enthusiast, Blogger, Linux Fan and a Software Developer. Writes about Computer hardware, Linux and Open Source software and coding in Python, Php and Javascript. He can be reached at [email protected].

22 Comments

Raw socket programming on windows with Winpcap
  1. paul

    nice code thank you for share your knowledge!
    exists a coding error on line 170 main.cpp

    seudo = new unsigned char(sizeof P_HDR + strlen(dump));

    correct:
    seudo = new unsigned char[sizeof P_HDR + strlen(dump)];

    thank you!!!

  2. kenhero

    Hi,
    i’m building on MSVS 2013 on Win10 and i have some run time errors:
    the first is in adatper.cpp

    HINSTANCE hDll = LoadLibrary((LPCWSTR)”iphlpapi.dll”);

    hDll == NULL and then
    GetAdaptersInfo = (pgetadaptersinfo)GetProcAddress(hDll,”GetAdaptersInfo”);

    GetAdaptersInfo = NULL too!!!

    Suggestions?Thanks

  3. anonym

    Thank you for the excellent code!

    I run it. it send syn flood to my server. But server does not send back any SYN/ACK. Any idea? Please…

      1. anonym

        the syn packet is sent and ip and tcp checksums are correct. here is the output and the wireshark report on this packet:

        1. Silver Moon

          the packet is being sent to destination port 8000
          check if port 8000 is open on the remote server. this can be done using telnet
          telnet server_name 8000

          If the remote port is not open, no syn+ack reply would come.

          1. anonym

            the port 8000 is not open. i check it with open ports 139 and 445. but again don’t receive SYN/ACK. i check wireshark report on both client and server. (also firewall and anti virus is disabled on both.)

  4. anon

    I have downloaded the source code, but it gives an fault message on the following lines (especially: P_HDR: Unexpected type)

    unsigned char *seudo;
    seudo = new unsigned char(sizeof P_HDR + strlen(dump));
    memcpy(seudo, &pseudo_header, sizeof P_HDR);
    memcpy(seudo + sizeof P_HDR , data , strlen(dump));

    I hope somebody can help me out?

    1. paul

      line error:
      seudo = new unsigned char(sizeof P_HDR + strlen(dump));

      correct:

      seudo = new unsigned char[sizeof P_HDR + strlen(dump)]; // type *p = new type[ size ];

  5. Dave Marshall Katelansky

    Somebody (Anonymous) posted that they aren’t getting anything in Wireshark. I modified the example code for basic_dump, an example program that comes with the WinPcap developer package. I have basic_dump producing all the info I need to know if this program or any network program can send packets or not. I didn’t get anything from a Linux system (using a raw socket program) or Windows XP (using this program). I tried this this program on Windows 2000 and it worked. Try running on Windows 2000 or earlier.

  6. Anonymous

    I can’t believe how easy you made this look. You should write some networking tutorials. Thanks heaps for this guide it’s amazing.

  7. Its me

    typedef struct ethernet_header
    {
    UCHAR dest[6];
    UCHAR source[6];
    USHORT type;
    } ETHER_HDR , *PETHER_HDR , FAR * LPETHER_HDR , ETHERHeader;

Leave a Reply

Your email address will not be published. Required fields are marked *