/*
 *   yet another pointless and retarded proggie brought to you by
 *                       reflector
 * 
 *   thanks tew ^ao for dual sendsyn, listensyn idea and              
 *   to halflife for psuedo header shit from halfscan.c
 */
 
#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>

unsigned short checkzum(unsigned short *, int);
void dumpsyns(int, unsigned, unsigned, int);
void getdemsyns(unsigned, unsigned, int, int, char *);

main (argc, argv)
int argc;
char *argv[];

{

   int r,e,f,l,dirty_sock,stiff_sock;
   pid_t dapid;
   char *filename;
   unsigned dest;
   unsigned source;
   unsigned max_port;
   struct hostent *he;
   f=0;
   l=0;
   
   
   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 > 7000))
   {
      printf("max port to scan should really be between 1 and 7000.\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);
   }
   
   if ((dirty_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
   {
      printf("could not open socket. are you even root, cunt?\n");
      exit(1);

   }
   
   if ((stiff_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 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]);


   dapid = fork();
   if (dapid < 0)
   {
      printf("could not fork.\n");
      exit(1);
   }
   if (dapid > 0);
   {
      for (r=1; r <= max_port; r++)
         dumpsyns(r, source, dest, dirty_sock);
      close(dirty_sock);   
   }
   if (dapid == 0)
   {
      getdemsyns(source, dest, stiff_sock, f, filename);
   }
}

void dumpsyns(int port, unsigned source, unsigned dest, int dirty_sock)
{
   int r,e,f,doh;
   struct sockaddr_in sin;
   struct iphdr eyepee;
   struct tcphdr teeseepee;
   struct fux_psuedo_heder
   {
      unsigned source;
      unsigned dest;
      unsigned pad     :  8,
               proto   :  8,
	       tcp_len : 16;
      struct tcphdr tcp;
   }psuedo_hed;

   struct sendme
   {
      struct iphdr  ip;
      struct tcphdr tcp;
   }send_me;


   sin.sin_family      = AF_INET;
   sin.sin_port        = htons(port);
   sin.sin_addr.s_addr = dest;
   
   eyepee.version      = 4;
   eyepee.ihl          = 5;
   eyepee.tos          = 0;
   eyepee.tot_len      = htons(40);
   eyepee.id           = getpid();
   eyepee.frag_off     = 0;
   eyepee.ttl          = 255;
   eyepee.protocol     = 6;
   eyepee.check        = 0;
   eyepee.saddr        = source;
   eyepee.daddr        = dest;
   eyepee.check        = checkzum((unsigned short *)&eyepee, 20);

   teeseepee.source    = getpid();
   teeseepee.dest      = htons(port);
   teeseepee.seq       = getpid() + port;
   teeseepee.ack_seq   = 0;
   teeseepee.doff      = 5;
   teeseepee.res1      = 0;
   teeseepee.res2      = 0;
   teeseepee.urg       = 0;
   teeseepee.ack       = 0;
   teeseepee.psh       = 0;
   teeseepee.rst       = 0;
   teeseepee.syn       = 1;
   teeseepee.fin       = 0;
   teeseepee.window    = htons(128);
   teeseepee.check     = 0;
   teeseepee.urg_ptr   = 0;

   psuedo_hed.source   = source;
   psuedo_hed.dest     = dest;
   psuedo_hed.pad      = 0;
   psuedo_hed.proto    = htons(6);
   psuedo_hed.tcp_len  = htons(20);

   bcopy (&teeseepee, (char *)&psuedo_hed.tcp, 20);
   teeseepee.check = checkzum((unsigned short *)&psuedo_hed, 32);

   bcopy(&eyepee, (char *)&send_me.ip, 20);
   bcopy(&teeseepee, (char *)&send_me.tcp, 20);

   
   doh = sendto(dirty_sock, &send_me, sizeof(send_me), 0, (struct sockaddr *)&sin, sizeof(sin));
   if (doh != sizeof(send_me))
   {
      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 doh;
   FILE *fp;
   struct servent *sp;
   struct sockaddr_in sin, duhsin;
   struct in_tcp
   {
      struct iphdr   ip;
      struct tcphdr tcp;
      char dataz[65495];
   }intcp;

   if (f == 1)
   {
      if ((fp = fopen(filename, "w")) == NULL)
      {
         printf("could not open file, cunt.\n");
         exit(1);
      }
   }

   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;

   while(1)
   {
      doh = recvfrom(stiff_sock, &intcp, sizeof(intcp), 0, (struct sockaddr *)&sin, (int *)sizeof(sin));
      if (doh < 0)
      {
         printf("error receiving.\n");
	 exit(1);
      }
      else printf("%d bytes received.\n", doh);
      if (intcp.tcp.dest == getppid())
      {
         if (intcp.tcp.syn == 1)
         {
            if ((sp = getservbyport(intcp.tcp.source, "tcp")) == NULL)
            {
	       if (f == 1)
	          fprintf(fp, "received syn from port %d.\n", intcp.tcp.source);
	       else
	          printf("received syn from port %d.\n", intcp.tcp.source);
	    }
	    else
	    {
	       if (f == 1)
	          fprintf(fp, "%s found on port %d.\n", sp->s_name, intcp.tcp.source);
	       else
	          printf("%s found on port %d.\n", sp->s_name, intcp.tcp.source);
	    }
	 }
      }
   }
}


/*
 * 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);
}

