Raw socket programming on windows with Winpcap
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
Related Posts
-
http://community-info.org Dave Marshall Katelansky
-
Alexander The Great
-
AlexIzeld
-
moeloek
-
Anonymous
-
Anonymous
-
Anonymous
-
Anonymous
-
Its me
-
Anonymous