You can use <linux/ip.h>
it contains structure to point to ip packet. also you can use socket.
here after an example. This example send an ICMP ECHO packet and wait for response
/* send icmp packet example */
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <linux/ip.h>
#include <linux/icmp.h>
int main(int argc, char* argv[])
{
struct iphdr *ip, *ip_reply;
struct icmphdr* icmp;
struct sockaddr_in connection;
char *dst_addr="192.168.1.33";
char *src_addr="192.168.1.34";
char *packet, *buffer;
int sockfd, optval, addrlen;
packet = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
buffer = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
ip = (struct iphdr*) packet;
icmp = (struct icmphdr*) (packet + sizeof(struct iphdr));
ip->ihl = 5;
ip->version = 4;
ip->tot_len = sizeof(struct iphdr) + sizeof(struct icmphdr);
ip->protocol = IPPROTO_ICMP;
ip->saddr = inet_addr(src_addr);
ip->daddr = inet_addr(dst_addr);
ip->check = in_cksum((unsigned short *)ip, sizeof(struct iphdr));
icmp->type = ICMP_ECHO;
icmp->checksum = in_cksum((unsigned short *)icmp, sizeof(struct icmphdr));
/* open ICMP socket */
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
/* IP_HDRINCL must be set on the socket so that the kernel does not attempt
* to automatically add a default ip header to the packet*/
setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int));
connection.sin_family = AF_INET;
connection.sin_addr.s_addr = ip->daddr;
sendto(sockfd, packet, ip->tot_len, 0, (struct sockaddr *)&connection, sizeof(struct sockaddr));
printf("Sent %d byte packet to %s\n", ip->tot_len, dst_addr);
addrlen = sizeof(connection);
if (recvfrom(sockfd, buffer, sizeof(struct iphdr) + sizeof(struct icmphdr), 0, (struct sockaddr *)&connection, &addrlen) == -1)
{
perror("recv");
}
else
{
char *cp;
ip_reply = (struct iphdr*) buffer;
cp = (char *)&ip_reply->saddr;
printf("Received %d byte reply from %u.%u.%u.%u:\n", ntohs(ip_reply->tot_len), cp[0]&0xff,cp[1]&0xff,cp[2]&0xff,cp[3]&0xff);
printf("ID: %d\n", ntohs(ip_reply->id));
printf("TTL: %d\n", ip_reply->ttl);
}
}
unsigned short in_cksum(unsigned short *addr, int len)
{
register int sum = 0;
u_short answer = 0;
register u_short *w = addr;
register int nleft = len;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum), we add
* sequential 16 bit words to it, and at the end, fold back all the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1)
{
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1)
{
*(u_char *) (&answer) = *(u_char *) w;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return (answer);
}