Raw Sockets – Packets with Winpcap
A previous post mentions how to send raw packets using winsock api on windows xp. 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
Each header has its own job to do in the whole transmission process.
Code :
u_char packet[65536]; char *dump = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
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.
1. Ethernet header looks like
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Ethernet destination address (first 32 bits) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Ethernet dest (last 16 bits) |Ethernet source (first 16 bits)| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Ethernet source address (last 32 bits) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type code | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
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.
now 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(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” ;simple!
The above demonstration is mostly self-explaining. We got the mac-address of the network interface we want to use. 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());
}
So by now the source-ip , its mac-address , primary-gateway-mac should be into their respective variables. So now we have enough information to build our ethernet header.
Enjoy!
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
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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
and our 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;
and then the 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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
and our structure for this 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;
Now the headers can be build easily :
// ******************* 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;
almost done
data = (char*)(packet + sizeof(ETHER_HDR) + sizeof(IPV4_HDR) + sizeof(TCP_HDR)); strcpy(data,dump); 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.
Source Code :
Download
Popularity: 9% [?]
















what does the eth_hdr struct look like?
typedef struct ethernet_header
{
UCHAR dest[6];
UCHAR source[6];
USHORT type;
} ETHER_HDR , *PETHER_HDR , FAR * LPETHER_HDR , ETHERHeader;
I can’t believe how easy you made this look. You should write some networking tutorials. Thanks heaps for this guide it’s amazing.
Hmm maybe I can use this to make a nice winpcap class. Thanks again.
thanks alot
i’ve been looking for something like this for a long time
It says its sending, but nothing is picked up by wireshark…
Hi, I try to get your full source code, but I can’t open the link that you gave