Monday, December 14, 2009

Sending ICMP request using C program

/**********************************************************************************
* AUTHOR : Chaitanya bhargav M
* Date : 14/10/2009
* description : To send an icmp request to specified host via specified
* Interface.
* License : Never mind to do any thing with this code.But, it might be unreliable
* *********************************************************************************
* CopyLeft(c) Chaitanya bhargav M 2009
***********************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

typedef unsigned long int uint32;
typedef unsigned short int uint16;
typedef unsigned char uint8;

#define ETHER_TYPE_FOR_IP 0x0800
#define PROTOCOL_ICMP 0x01

// For proper memory allocation for each packet
#pragma pack(1)
// Ethernet header
typedef struct eth_hdr
{
uint8 dest_mac[6];
uint8 src_mac[6];
uint16 ether_type;
}ETH_HDR;
// 802.1Q Header
typedef struct vlan_hdr
{
uint16 type;
uint16 vlanID;
}VLAN_HDR;
// IP Header without options
typedef struct ip_hdr
{
uint8 version_headerlen;
uint8 diffserv;
uint16 total_len;
uint16 ident;
uint8 flags;
uint8 frag_offset;
uint8 ttl;
uint8 protocol;
uint16 checksum;
uint32 src_addr;
uint32 dest_addr;
}IP_HDR;
// ICMP Header
typedef struct icmp_hdr
{
uint8 type;
uint8 code;
uint16 checksum;
uint16 ident;
uint16 seq_no;
}ICMP_HDR;
// My own ICMP packet
typedef struct icmp_packet
{
ETH_HDR eth;
IP_HDR ip;
ICMP_HDR icmp;
uint8 data[32];
}ICMP_PKT;

// Function prototypes to calculate checksum and to print packet
unsigned short int header_checksum(char *, unsigned short int );
int print_pkt( char *, unsigned short int );

int main(int argc, char *argv[])
{
struct sockaddr_in *sin;
struct ifreq ifr;
struct sockaddr_ll sa;
int if_fd,icmp_fd,retVal,arp_flagg = 1;
unsigned long int ipAddr,IfIndex;
unsigned char IfMac[6];
ICMP_PKT pkt;
// It's my gateway. So, i am hardcoding
unsigned char gateway[7] = { 0x00,0x1A,0x6D,0x2B,0x89,0x29 };

if(argc != 3)
{
printf("Usage:\n ./icmp_req \n");
exit(1);
}

if(getuid() && geteuid())
{
printf("Oops!\n No Super user right\n");
exit(1);
}

// Check for default gateway
if(!strcmp(argv[1],"eth0"))
{
arp_flagg = 0;
}

if_fd = socket(AF_INET, SOCK_DGRAM, 0);
if( if_fd < 0 )
{
perror("If Socket");
exit(1);
}

//==============================Interface related data======================
// provide Interface name
strcpy(ifr.ifr_name,argv[1]);

// IP address
retVal = ioctl( if_fd, SIOCGIFADDR, &ifr, sizeof(ifr));
if( retVal < 0 )
{
perror("IFADDR IOCTL");
close(if_fd);
exit(1);
}
sin = (struct sockaddr_in *)&ifr.ifr_addr;
ipAddr = ntohl(sin->sin_addr.s_addr);

#ifdef DBG_ICMP
printf("IpAddr = %s\n",inet_ntoa(sin->sin_addr));
#endif

// MAC address
retVal = ioctl(if_fd, SIOCGIFHWADDR, &ifr, sizeof(ifr));
if( retVal < 0)
{
perror("IFHWADDR IOCTL");
close(if_fd);
exit(1);
}
memcpy(IfMac, ifr.ifr_hwaddr.sa_data, 6 * sizeof(unsigned char));

#ifdef DBG_ICMP
printf("MAC = %02x:%02x:%02x:%02x:%02x:%02x\n", IfMac[0],IfMac[1],IfMac[2],IfMac[3],IfMac[4],IfMac[5]);
#endif

// Interface index
retVal = ioctl(if_fd, SIOCGIFINDEX, &ifr, sizeof(ifr));
if( retVal < 0)
{
perror("IFINDEX");
close(if_fd);
exit(1);
}

#ifdef DBG_ICMP
printf("IfIndex = %d\n",ifr.ifr_ifindex);
#endif

IfIndex = ifr.ifr_ifindex;
//==============================Interface related data=====================

//==============================Packet socket==============================

icmp_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
if(icmp_fd < 0 )
{
perror("ICMP Socket");
close(if_fd);
exit(1);
}

//=============================Frame the packet============================
// Ethernet header
if(!arp_flagg) // If sending via gateway
{
memcpy(pkt.eth.dest_mac, gateway, 6 * sizeof(unsigned char));
}
else // If sending via private interface
{
memset(pkt.eth.dest_mac, 0xFF, 6 * sizeof(unsigned char));
}
memcpy(pkt.eth.src_mac, IfMac, 6 * sizeof(unsigned char));
pkt.eth.ether_type = htons(ETHER_TYPE_FOR_IP);

// IP header
pkt.ip.version_headerlen = 0x45; // version = IPv4, len = 5 (x 32 = 160)
pkt.ip.diffserv = 0x00; // Best effort
pkt.ip.total_len = htons(0x003C); // 20 IP header + 8 UDP header + 32 data
pkt.ip.ident = htons(0xa9b1); // just to identify reply
pkt.ip.flags = 0x00; // no fragmentation
pkt.ip.frag_offset = htons(0x0000); // no fragmentaion
pkt.ip.ttl = 0x80; // let's give 128
pkt.ip.protocol = PROTOCOL_ICMP; // ICMP protocol inside IP
pkt.ip.checksum = htons(0x0000); // Will be found out after framing full header
pkt.ip.src_addr = htonl(ipAddr); // inet address of given Interface
pkt.ip.dest_addr = inet_addr(argv[2]);// to whom shall we send

pkt.ip.checksum = htons(header_checksum( (char *)&pkt.ip.version_headerlen, 20));

// ICMP header
pkt.icmp.type = 0x08; // ICMP request
pkt.icmp.code = 0x00; // Code for ICMP request
pkt.icmp.checksum = htons(0x0000); // Will be filled after framing full header
pkt.icmp.ident = htons(0x0300); // anything
pkt.icmp.seq_no = htons(0xC000); // anything

pkt.icmp.checksum = htons(header_checksum( (char *)&pkt.icmp.type, 8));

// Data padding
memset(pkt.data, 0, 32 * sizeof(unsigned char));// Windows(R) Style

#ifndef DBG_ICMP
print_pkt((char *)&pkt, sizeof(pkt));
#endif

//======================Ok, Now send it!================

// We need this to send the packet
sa.sll_family = AF_PACKET; // AF_PACKET is a must
sa.sll_ifindex = ifr.ifr_ifindex; // chosen if. index number
sa.sll_protocol = htons(ETH_P_IP); // protocol of interest

// Now send it!
retVal = sendto(icmp_fd, &pkt, sizeof(pkt), 0, (struct sockaddr *)&sa, sizeof(sa));
if(retVal < 0 )
{
perror("send to");
close(icmp_fd);
close(if_fd);
exit(1);
}

return 0;
}

/***********************************************************
* To find the checksum of any header
* Description:
* - add two bytes at a time till the end
* - add the overflow till you come up with a 2-byte result
* - take a 1's compliment
***********************************************************/
unsigned short int header_checksum(char *buf, unsigned short int len)
{
unsigned char *header;

unsigned short int low16 = 0,i = 0;
unsigned long int checksum_32 =0;

// add 2 bytes at a time
for(i = 0; i < len; i+=2 )
{
low16 = (buf[i] << 8)&0xFF00 | buf[i+1]&0xFF ;
checksum_32 = checksum_32 + low16;
}

// Append the overflow -- 2 times for safety
if(checksum_32 >> 16)
{
checksum_32 = (checksum_32 & 0xFFFF) + (checksum_32 >> 16);
}
if(checksum_32 >> 16)
{
checksum_32 = (checksum_32 & 0xFFFF) + (checksum_32 >> 16);
}
// One's compliment
checksum_32 = ~checksum_32;

return (checksum_32&0xFFFF);
}

/**********************************************
* To Print the packet *
**********************************************/
int print_pkt( char *buf, unsigned short int len)
{
int i = 0;

printf("Size of packet = %d\n",len);
for( i = 0; i < len ; i++)
{
if(i%16 == 0)
printf("\n");

printf("%02x ",buf[i]&0xff);
}
printf("\n");
return 0;
}

No comments:

Post a Comment