/*
 *   yet another pointless and retarded proggie brought to you by
 *                       reflector
 *   thx to halflife for psuedo header and timer shit from halfscan.c
 */
#include <sys/types.h> 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <signal.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

#define MAXHOSTNAME   128

int timeout = 0;
int lazy_refl = 0;

unsigned short checkzum(unsigned short *, int);
void dumpsyns(int, unsigned, unsigned, int, unsigned, unsigned, int);
void getdemsyns(unsigned, unsigned, int, int, char *);
void sort_ports(int *, int, FILE *, int);
void alarm_handler(int);
void refl_handler(int);
int compar(const void *, const void *);

main (argc, argv)
int argc;
char *argv[];

{

   int r,e,f,l,dirty_sock;
   pid_t dapid;
   char *filename;
   char *localhost;
   unsigned max_port;
   unsigned dest;
   unsigned source;
   struct hostent *he;
   f=0;
   l=0;
   
   
   /* check usage */
   
   if ((argc < 4) || (argc > 6))
   {
      printf("usage: %s source target max-port-to-scan [-f filename]\n", argv[0]);
      printf("       source must be YOUR ip address as a dotted quad.\n");
      exit(1);
   }

   for (r=0; r < argc; r++)
   {
      if(!strcmp("-f", argv[r]))
      {
         f=1;
         filename = argv[++r];
      }
   }
	 
   max_port = atoi(argv[3]);
   if ((max_port < 1) || (max_port > 32767))
   {
      printf("max port to scan should really be between 1 and 32,767.\n");
      exit(1);
   }

   dest = inet_addr(argv[2]);
   if (dest == -1);
   {
      if((he = gethostbyname(argv[2])) == NULL)
      {
         printf("doh.  %s duz not exist.  cunt.\n", argv[2]);
	 exit(1);
      }
      bcopy ((char *)he->h_addr,  (char *)&dest, he->h_length);
   }
   

   source = inet_addr(argv[1]);
   if (source == -1)
   {
      printf("check that source address you fucking dork.\n");
      exit(1);
   }


   /* open raw sockets */

   if ((dirty_sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0)
   {
      printf("could not open socket. are you even root, cunt?\n");
      exit(1);

   }
   
   printf("checking out ports 1 thru %d on %s.\n", max_port, argv[2]);

   /* fork - parent sends syns, child listens, rsts half open connections. */

   dapid = fork();
   if (dapid < 0)
   {
      printf("could not fork.\n");
      exit(1);
   }
   if (dapid > 0)
   {
      signal(SIGALRM, alarm_handler);
      sleep(3);
      for (r=1; r <= max_port; r++)
         dumpsyns(r, source, dest, dirty_sock, 0, 0, 0);
      kill(dapid, 10);      
      while (1)
      {
         if (timeout == 1)
	 {
	    sleep(2);
	    exit(1);
	 }
      }
   }
   if (dapid == 0)
   {
     getdemsyns(source, dest, dirty_sock, f, filename); 
   }
}

void dumpsyns(int port, unsigned source, unsigned dest, int dirty_sock, unsigned seqnum, unsigned acknum, int testrst)
{
   int r,e,f,doh;
   struct sockaddr_in sin;
   struct tcphdr teeseepee;
   struct fux_psuedo_heder
   {
      unsigned source;
      unsigned dest;
      unsigned pad     :  8,
               proto   :  8,
	       tcp_len : 16;
      struct tcphdr tcp;
   }psuedo_hed;


   sin.sin_family      = AF_INET;
   sin.sin_port        = htons(port);
   sin.sin_addr.s_addr = dest;
   
   /* fill in tcp header, checking if we want this to be a rst segment. */

   teeseepee.source    = getpid();
   teeseepee.dest      = htons(port);

   /* if this is to be a rst */

   if (testrst == 1)
   {
      teeseepee.seq       = acknum;
      teeseepee.ack_seq   = seqnum + 1;
      teeseepee.rst       = 1;
      teeseepee.syn       = 0;
      teeseepee.ack       = 1;
      teeseepee.window    = 0;
   }

   /* if not */

   if (testrst == 0)
   {
      teeseepee.seq       = getpid() + port;
      teeseepee.ack_seq   = 0;
      teeseepee.rst       = 0;
      teeseepee.syn       = 1;
      teeseepee.ack       = 0;
      teeseepee.window    = htons(512);
   }

   /* these don't care if we are rsting or not */

   teeseepee.doff      = 5;
   teeseepee.res1      = 0;
   teeseepee.res2      = 0;
   teeseepee.urg       = 0;
   teeseepee.psh       = 0;
   teeseepee.fin       = 0;
   teeseepee.check     = 0;
   teeseepee.urg_ptr   = 0;

   /* fill in psuedo-header.  ugh. */

   psuedo_hed.source   = source;
   psuedo_hed.dest     = dest;
   psuedo_hed.pad      = 0;
   psuedo_hed.proto    = 6;
   psuedo_hed.tcp_len  = htons(20);

   bcopy (&teeseepee, (char *)&psuedo_hed.tcp, 20);
   teeseepee.check = checkzum((unsigned short *)&psuedo_hed, 32);

   /* bewm! */

   doh = sendto(dirty_sock, &teeseepee, sizeof(teeseepee), 0, (struct sockaddr *)&sin, sizeof(sin));
   if (doh != sizeof(teeseepee))
   {
      printf("error sending syn.\n");
      exit(1);
   }
   
}

void getdemsyns(source, dest, stiff_sock, f, filename)
unsigned source,dest;
int stiff_sock, f;
char *filename;
{
 
   int rst_sock;
   int doh, r, e=0, i=1;
   int array[150];
   FILE *fp;
   struct servent *sp;
   struct sockaddr_in sin, duhsin;
   struct in_addr ina;
   struct in_tcp
   {
      struct iphdr   ip;
      struct tcphdr tcp;
      char dataz[65495];
   }intcp;

   ina.s_addr = dest;

   if (f == 1)
   {
      if ((fp = fopen(filename, "a")) == NULL)
      {
         printf("could not open file, cunt.\n");
         exit(1);
      }
      fprintf(fp, "            --- results for %s ---\n", inet_ntoa(ina));
   }

   duhsin.sin_family      = AF_INET;
   duhsin.sin_port        = htons(getppid());
   duhsin.sin_addr.s_addr = source;
 
   if ((bind(stiff_sock, (struct sockaddr *)&duhsin, sizeof(duhsin))) < 0)
   {
      printf("could not bind socket.\n");
      exit(1);
   }   
 
   sin.sin_family      = AF_INET;
   sin.sin_port        = htons(getppid());
   sin.sin_addr.s_addr = dest;
  
   
   if ((rst_sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0)
   {
      printf("error opening rst_sock.\n");
      exit(1);
   }

   
   signal(SIGUSR1, refl_handler);
   signal(SIGALRM, alarm_handler);
   alarm(30);
   printf("        SYNs received [");
   fflush(stdout);
   while(1)
   {
      if ((timeout == 1) && (lazy_refl == 1))
      {
         printf("]\n");
         sort_ports(array, f, fp, i);
      }
      doh = read(stiff_sock, (char *)&intcp, 65535);  
      if (intcp.tcp.dest == getppid())
      {
         if (intcp.tcp.syn == 1)
         {
	    alarm(35);
	     
	    /* reset connection */

	    dumpsyns(intcp.tcp.source, source, dest, rst_sock, intcp.tcp.ack_seq, intcp.tcp.ack, 1); 

            /* stuff port in array */

            e = 0;

            for(r=0; r <= i; r++)
	    {
	       if(ntohs(intcp.tcp.source) == array[r])
	          e = 1;
	    }

            if (e == 0)
            {
               printf(".");
               fflush(stdout);
               array[i] = ntohs(intcp.tcp.source); 
               i++;
            }                 
         }             
      }        
   }        
}   

void sort_ports(int *array, int f, FILE *fp, int i)
{
   pid_t pidz;
   int r,e;
   struct servent *sp;
   
   setservent(1);
   pidz = getppid();
   fflush(stdout);
   qsort(array, i, sizeof(array[0]), compar);
   for(e = 1; e < i; e++)
   {
      if ((sp = getservbyport(array[e], "tcp")) == NULL)
      {
         if (f == 1)
            fprintf(fp, "received syn from port %d.\n", array[e]);
         else
            printf("received syn from port %d.\n", array[e]);
      }
      else
      {
         if (f == 1)
            fprintf(fp, "%s found on port %d.\n", sp->s_name, array[e]);
         else
            printf("%s found on port %d.\n", (char *)sp->s_name, array[e]);
      }
      fflush(stdout);
   }
   kill(pidz, 14);
   endservent();
   exit(1);
}

int compar(const void *intone, const void *inttwo)
{
   if (*(int *)intone == *(int *)inttwo)
      return 0;
   if (*(int *)intone < *(int *)inttwo)
      return -1;
   if (*(int *)intone > *(int *)inttwo)
      return 1;
}

void alarm_handler(int s)
{
   alarm(0);
   timeout = 1;
}

void refl_handler(int s)
{
   lazy_refl = 1;
}

/*
 * I didn't steal this from ping.c.  really.  I wrote it.  really.
 */						    
unsigned short checkzum(addr, len)
    u_short *addr;
    int len;
{
    register int nleft = len;
    register u_short *w = addr;
    register int sum = 0;
    u_short answer = 0;

    /*
     * 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);
}

