Fragmented ICMP packet generator.
ff8302c76379341492e7d4b5c00d34c04aaceee1802459aaf36d4bd83c34b98f
/*
* frag
* by: Fryxar
* e-mail: fryxar@yahoo.com.ar
*
* Fragment ICMP packet generator
*/
#include<stdio.h>
#include<netdb.h>
#include<stdlib.h>
#include<errno.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/ip.h>
#include<netinet/ip_icmp.h>
#define ERROR(msg) {perror(msg); exit -1;}
#define FRAGS_ALL 0
#define FRAGS_ODD 1
#define FRAGS_EVEN 2
int open_packet() {
int s, on = 1;
if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
ERROR("socket");
if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0)
ERROR("setsockopt");
return s;
}
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);
}
int send_packet(int s, struct sockaddr_in saddr, struct sockaddr_in daddr, int protocol, char frags, int id, int frag_len, int tot_len) {
unsigned char packet[IP_MAXPACKET];
struct iphdr *iphdr;
struct icmphdr *icmphdr;
int offset, length;
int start, step;
switch(frags) {
case FRAGS_ALL:
start = 0;
step = (frag_len<<3);
break;
case FRAGS_EVEN:
start = 0;
step = 2*(frag_len<<3);
break;
case FRAGS_ODD:
start = (frag_len<<3);
step = 2*(frag_len<<3);
break;
}
memset(packet, 0, IP_MAXPACKET);
length = sizeof(struct iphdr) + (frag_len<<3);
iphdr = (struct iphdr *)packet;
icmphdr = (struct icmphdr *)(packet + sizeof(struct iphdr));
iphdr->ihl = 5;
iphdr->version = IPVERSION;
iphdr->tot_len = htons(length);
iphdr->id = htons(id);
iphdr->ttl = IPDEFTTL;
iphdr->protocol = protocol;
iphdr->saddr = saddr.sin_addr.s_addr;
iphdr->daddr = daddr.sin_addr.s_addr;
for(offset = start; offset < tot_len; offset += step) {
if(offset) {
// Not first fragment
iphdr->frag_off = htons(offset>>3);
bzero(packet + sizeof(struct iphdr), IP_MAXPACKET
- sizeof(struct iphdr));
} else {
// First fragment
iphdr->frag_off = 0;
if(protocol == IPPROTO_ICMP) {
icmphdr->type = ICMP_ECHO;
icmphdr->code = 0;
icmphdr->un.echo.id = 0;
icmphdr->un.echo.sequence = 0;
icmphdr->checksum = (unsigned short)in_cksum((unsigned short *)icmphdr, tot_len);
}
}
if(offset + (frag_len<<3) < tot_len) {
iphdr->frag_off |= htons(IP_MF);
} else {
length = sizeof(struct iphdr) + tot_len - offset;
iphdr->tot_len = htons(length);
}
iphdr->check = (unsigned short)in_cksum((unsigned short *)iphdr, sizeof(struct iphdr));
if(sendto(s, packet, length, 0x0, (struct sockaddr *)&daddr, sizeof(struct sockaddr)) != length)
ERROR("sendto");
}
}
void usage(char *program) {
fprintf(stderr, "frag v"VERSION"\n"
"usage: %s [options] <source_host> <destination_host>\n\n"
"options:\n"
" -i <id> Starting session id (range: 1-65535)\n"
" -s <fragmentsize> Fragments size (x 8)\n"
" -l <packetsize> Total packet size\n"
" -t <type> Set send policity (odd|even|all)\n"
" -p <protocol> Set protocol (tcp|udp|icmp...)\n"
" -a <n> Amount of packet to send\n"
"\ndefault:\n"
"%s -i 1 -t all -s 7 -p icmp -l 64000 -a 1 my_host.com your_host.com\n"
"\n", program, program);
exit(-1);
}
int main(int argc, char *argv[]) {
char *shost, *dhost;
struct hostent *hostentry;
struct sockaddr_in saddr, daddr;
struct protoent *protoent;
int s, i;
int id = 1, size = 7, len = 64000, amount = 1;
int protocol = IPPROTO_ICMP, type = FRAGS_ALL;
if(argc < 3) usage(argv[0]);
while((i = getopt(argc, argv, "a:i:s:l:t:p:")) != -1) {
switch(i) {
case 'i':
if(strlen(optarg) == 0) usage(argv[0]);
id = atoi(optarg);
break;
case 's':
if(strlen(optarg) == 0) usage(argv[0]);
size = atoi(optarg);
break;
case 'a':
if(strlen(optarg) == 0) usage(argv[0]);
amount = atoi(optarg);
break;
case 'l':
if(strlen(optarg) == 0) usage(argv[0]);
len = atoi(optarg);
break;
case 't':
if(!memcmp(optarg, "odd", 4)) type = FRAGS_ODD;
else if(!memcmp(optarg, "even", 5)) type = FRAGS_EVEN;
else if(!memcmp(optarg, "all", 4)) type = FRAGS_ALL;
else usage(argv[0]);
break;
case 'p':
if((protoent=getprotobyname(optarg)) == NULL) usage(argv[0]);
protocol = protoent->p_proto;
break;
default:
usage(argv[0]);
break;
}
}
shost = argv[argc-2];
dhost = argv[argc-1];
// Source address
if((hostentry = gethostbyname(shost)) == NULL) ERROR("gethostbyname source address");
memset(&saddr, 0, sizeof(struct sockaddr));
saddr.sin_family = AF_INET;
saddr.sin_addr = *((struct in_addr *)hostentry->h_addr);
// Destination address
if((hostentry = gethostbyname(dhost)) == NULL) ERROR("gethostbyname destination address");
memset(&daddr, 0, sizeof(struct sockaddr));
daddr.sin_family = AF_INET;
daddr.sin_addr = *((struct in_addr *)hostentry->h_addr);
// MAIN
s = open_packet();
for(i = 0; i < amount; i++) {
printf("Sending packets with ID %d (frags length=%d, total length=%d)\n",
(id + i)%65535, (size<<3), len);
send_packet(s, saddr, daddr, protocol, type, (id + i)%65535, size, len);
}
close(s);
return(0);
}