/* EXCLUDED-TEAM [www.excluded.org]
   tping V 1.0     <--->   l0om

this is a tcp version of the common ping programm. this pings with tcp
packets (+ack). if the host is up well receive an tcp answer (+rst).
otherwise the host is down for us.


for usage see void help()...
./tping       # without any options

*/

#include <stdio.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/time.h>
#include <sys/select.h>
#include <stdlib.h>

#define   OKAY      0
#define   UP        2  
#define   DOWN      3
#define   ERROR    -1

unsigned short in_cksum(unsigned short *ptr, int);
int check_host(int *sock);
void help();

struct pseudohdr {
	        unsigned long saddr;
	        unsigned long daddr;
	        char useless;
	        unsigned char protocol;
	        unsigned short length;
                struct tcphdr tcp;
	};


struct pseudohdr pseudo;
struct tcphdr tcp;
struct sockaddr_in servaddr;
int maxwait = 5;   

int main(int argc, char **argv)
{
  int bytes = 0;
  int sockfd, loop = 3;
  int option = 0;
  int i, stats = 0;
  int value = 0; 
  int sport, dport, times;
  int wait = 0;
  unsigned int saddr;

  if(argc == 1) {
    help();
    return OKAY;
  }

  sport = 80; dport = 80;
  times=stats=servaddr.sin_addr.s_addr=0;

  for(i = 1; i < argc; i++) 
    {
      if(argv[i][0] == '-')
	{
	  switch(argv[i][1]) {
	  case 'f':{ saddr = inet_addr(argv[++i]);
	  break;}
	  case 't':{ servaddr.sin_addr.s_addr=inet_addr(argv[++i]);
	  break;}
	  case 's':{ sport=atoi(argv[++i]);
	  break;}
	  case 'd':{ dport=atoi(argv[++i]);
	  break;}
	  case 'c':{ loop=atoi(argv[++i]);
	  break;}
	  case 'i':{ wait=atoi(argv[++i]);
	  break;}
        case 'w':{ maxwait=atoi(argv[++i]);
        break;}
	  }
	
	}
    }
  
  if(servaddr.sin_addr.s_addr == 0 || saddr == 0) { 
    help();
    printf("error. specify dest or source address\n");
  }


  sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
  if(sockfd < 0) {
    printf("Error. cannot creat socket\n");
    return -1;
  }


  printf("TPING (%s)   (sp:%d)   (dp:%d)\n",inet_ntoa(servaddr.sin_addr.s_addr),sport,dport);
  printf("----------------------------\n");
  
  for(i = 1; i <= loop; i++) { 

  tcp.source = htons(sport);
  tcp.dest = htons(dport);
  tcp.seq = getpid();
  tcp.ack_seq = 0;
  tcp.res1 = 0;
  tcp.doff = 5;
  tcp.syn = 0;
  tcp.rst = 0;
  tcp.fin = 0;
  tcp.psh = 0;
  tcp.urg = 0;
  tcp.ack = 1;
  tcp.window = htons(1000);
  tcp.check = 0;
  tcp.urg_ptr = 0;
  
  pseudo.saddr = saddr;
  pseudo.daddr = servaddr.sin_addr.s_addr;
  pseudo.useless = 0;
  pseudo.protocol = IPPROTO_TCP;
  pseudo.length = htons(20);

  servaddr.sin_family = AF_INET;
  servaddr.sin_port = tcp.dest;

  pseudo.tcp.dest = tcp.dest;
  bcopy(&tcp,&pseudo.tcp,20);
  tcp.check = in_cksum((unsigned short *)&pseudo,32);

  sleep(wait);

    if(sendto(sockfd, &tcp, 20, 0,
		 (struct sockaddr *)&servaddr, sizeof(servaddr)) == 20) {
      times++;
   
      if( (value = check_host(&sockfd)) == UP) {  
      printf("received TCP answer from %s\n",inet_ntoa(pseudo.daddr));
      stats++;
      }
    else printf("recevied NO TCP answer...\n");
    }    
    else {
      printf("error. could not send packet\n");
      return ERROR;
    }
  }
  printf("------TPING STATISTICS------\n");
  printf("%d tcp +ack packets send, %d received, %d percent lost\n",times,
	 stats,((stats*100/times)-100));

  return OKAY;
}


int check_host(int *sock) 
{
  fd_set rset;
  int bytes = 0;
  struct iphdr *ip;
  struct tcphdr *tcp2;
  char recvbuff[1000];
  struct timeval tv;

  tv.tv_sec = maxwait;       /* the incomming packet could need this time */
  tv.tv_usec = 0;

  FD_ZERO(&rset);
  FD_SET(*sock,&rset);

  memset(recvbuff,0,sizeof(recvbuff));
     
    if(select(*sock+1, &rset, NULL, NULL, &tv) > 0)
	{
	 if(FD_ISSET(*sock, &rset))  /* socket readable */
	    {
	      ip = (struct iphdr *)recvbuff;
	      tcp2 = (struct tcphdr *) (recvbuff + sizeof(struct iphdr));
	      bytes = read(*sock,recvbuff,sizeof(recvbuff));
	      if(bytes <= 0) return ERROR;
	      if(ip->saddr == servaddr.sin_addr.s_addr) 
		return UP;
	    }
	}
    else return DOWN;
}


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);
}

void help() 
{
  puts("help\n");
  puts("tping [[-options]...]");
  puts("options:");
  puts("-f: ur source IP address");  
  puts("-t: dest IP address");
  puts("-s: source port");
  puts("-d: dest port");
  puts("-c: times to ping");
  puts("-i: seconds to wait after every send");
  puts("-w: seconds to wait for answer");
  puts("example:\n");
  puts("./tping -f 1.1.1.1 -t 2.2.2.2 -s 80 -d 80 -c 3 -i 1");
  puts("pings form 1.1.1.1 to 2.2.2.2 whith source port 80");
  puts("to destport 80 three times. wait one sec after every send\n");
  puts("l0om");
}


  


