Raw socket programming on windows with Winpcap

1 Flares Filament.io 1 Flares ×

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

Packet

IP Header

Next comes the 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 this 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

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

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

Send Packet

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

Thats should send the packet. Use Ethereal 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

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.

Download
Download Source Code

Last Updated On : 27th November 2012

Subscribe to get updates delivered to your inbox

About Silver Moon

Php developer, blogger and Linux enthusiast. He can be reached at m00n.silv3r@gmail.com. Or find him on Google+

  • 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…

    • http://www.binarytides.com/ Silver Moon

      verify the syn packet sent out using wireshark.
      ensure that the ip and tcp checksum of the packet is correct as reported by wireshark.

      • anonym

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

        • http://www.binarytides.com/ 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.

          • 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.)

  • 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?

  • http://community-info.org 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.

  • Alexander The Great

    Thanks!

  • AlexIzeld

    Still usefull after all this time …. thanks alot

  • moeloek

    Hi, I try to get your full source code, but I can’t open the link that you gave

    • Binary Tides

      source code link is now working.

  • Anonymous

    It says its sending, but nothing is picked up by wireshark…

    • Binary Tides

      Is there any firewall like zonealarm running ? Firewalls will tend to block such packets.

  • Anonymous

    thanks alot :D i’ve been looking for something like this for a long time :P :)

  • Anonymous

    Hmm maybe I can use this to make a nice winpcap class. Thanks again.

  • 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.

  • Its me

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

  • Anonymous

    what does the eth_hdr struct look like?

1 Flares Twitter 0 Facebook 1 Google+ 0 LinkedIn 0 StumbleUpon 0 Filament.io 1 Flares ×