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:
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.
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!!!
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
Excellent tutorial ! Thank you
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…
verify the syn packet sent out using wireshark.
ensure that the ip and tcp checksum of the packet is correct as reported by wireshark.
the syn packet is sent and ip and tcp checksums are correct. here is the output and the wireshark report on this packet:
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.
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.)
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?
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 ];
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.
Thanks!
Still usefull after all this time …. thanks alot
Hi, I try to get your full source code, but I can’t open the link that you gave
source code link is now working.
It says its sending, but nothing is picked up by wireshark…
Is there any firewall like zonealarm running ? Firewalls will tend to block such packets.
thanks alot :D i’ve been looking for something like this for a long time :P :)
Hmm maybe I can use this to make a nice winpcap class. Thanks again.
I can’t believe how easy you made this look. You should write some networking tutorials. Thanks heaps for this guide it’s amazing.
typedef struct ethernet_header
{
UCHAR dest[6];
UCHAR source[6];
USHORT type;
} ETHER_HDR , *PETHER_HDR , FAR * LPETHER_HDR , ETHERHeader;
what does the eth_hdr struct look like?