/**********************************************************************
** This is a real simple half opened connection scanner I
** put together. It scans ports 0 to 1024 for listening
** processes, and writes to stdout the ports that are 
** listening.
**
** halflife@saturn.net
**
** Modified for Network Explorer by Mark Spencer
**
** NOTE: You have to define MY_IP as your ip. If you have
** a dynamic ip, this is gonna bite :-).
*********************************************************************/

/* define the following as your ip address */

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>

#include <gtk/gtk.h>
#include "cheops.h"
#include "tcpip-mod.h"

static int tcp_socket = -1;


int init_halfscan()
{
   tcp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
   if((tcp_socket < 0))
   {
      fprintf(stderr, "couldnt open raw socket\n");
      exit(1);
   }
   return 0;
}

int scan_ports(unsigned int src_addr, unsigned int dst_addr, struct port *list, int timeout)
{
   struct recv_tcp
   {
      struct iphdr ip;
      struct tcphdr tcp;
      unsigned char blah[65535];
   }recv_tcp;

   int blah = 0;
   int total=0;
   int cnt=0;
   struct port *p;
   struct timeval tv;
   fd_set fds;
   int res=1;
   int res2;
   spoofrec s;
   
   /* Quickly, flush anything that is in the queue already. */
   while(res > 0)
   {
      /* Count on Linux's uniqiue in-place timeval modification to make this work... */
      FD_ZERO(&fds);
      FD_SET(tcp_socket, &fds);
      tv.tv_sec = 0;
      tv.tv_usec = 0;
      res = select(tcp_socket + 1, &fds, NULL, NULL, &tv);
      if (res > 0) 
      	res2=recv(tcp_socket, (struct recv_tcp *)&recv_tcp, 65535, 0);
   }
   res=1;
   
   p = list;
   while(p) {
   	/* Send out the requests */
   	blah++;
	total++;

   	s.sport =  ((getpid() + blah) & 0xFFF) + 3000;
	s.seq = rand() & 0xffff;
	s.ack = 0;
	s.retries=0;
	s.next=NULL;
	s.from.sin_addr.s_addr = src_addr;
	s.dest.sin_addr.s_addr = dst_addr;
	s.dport = p->dport;
	s.dest.sin_port = htons(s.dport);
	s.dest.sin_family = AF_INET;
	s.data=NULL;
	sendtcp(&s, SYN, 1);
	p=p->next;
   }
   tv.tv_sec = timeout;
   tv.tv_usec = 0;
   while(res > 0)
   {
      /* Count on Linux's uniqiue in-place timeval modification to make this work... */
      FD_ZERO(&fds);
      FD_SET(tcp_socket, &fds);
      res = select(tcp_socket + 1, &fds, NULL, NULL, &tv);
      if (res > 0) {
      	res2=recv(tcp_socket, (struct recv_tcp *)&recv_tcp, 65535, 0);
      	p = list;
		if (recv_tcp.ip.saddr == dst_addr) {
			while(p) {
				/* Check for duplicates */
				if (p->avail > 0) {
					p=p->next;
					continue;
				}
#if (__GLIBC__ < 2)
      	  			if(ntohs(recv_tcp.tcp.th_sport) == p->dport) {
	  				cnt++;
          				if(recv_tcp.tcp.th_flags &  TH_RST) 
#else
      	  			if(ntohs(recv_tcp.tcp.source) == p->dport) {
	  				cnt++;
          				if(recv_tcp.tcp.rst == 1) 
#endif
						p->avail = 0;
         	 			else 
						p->avail=1;
					
	  			}
	  			p=p->next;
        		}
		}
		if (cnt >= total) break;
      }
   }
   return cnt;
}

