/*
		                  LCRZO
                             Network library
             Copyright(c) 1999,2000,2001,2002 Laurent Constantin
                                  -----

  Main server    : http://www.laurentconstantin.com/
  Backup servers : http://go.to/laurentconstantin/
                   http://laurentconstantin.est-la.com/
                   http://laurentconstantin.free.fr/
                   http://lauconstantin.multimania.com/
  [my current email address is on the web servers]

                                  -----
  This file is part of Lcrzo.

  Lcrzo is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  Lcrzo is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details (http://www.gnu.org).

------------------------------------------------------------------------
*/

/* -- Note about comments and variable names --
   In versions 1.00 up to 2.08, lcrzo was only written in French (my
   mother tongue). Since version 3.00, lcrzo is written in English, but
   most of comments and variable names are still in French.
   In future versions, I'll try to translate everything into English,
   but as you may guess, that's a quite big work...
   So, for the moment, here are some word translation, if you want to
   be able to understand what's going on in the functions :
     afficher - print     ;  ajouter - add         ;  copie - copy
     dernier - last       ;  donnee - data         ;  ecrire - write
     entete - header      ;  envoye - sent         ;  ferme - close
     fichier - file       ;  lire - read           ;  masque - mask 
     nboct - byte number  ;  ouvre, ouvrir - open  ;  paq, paquet - packet
     plage - range        ;  premier - first       ;  recu - received
     reseau - network     ;  retour - return       ;  taille - size
     tunnel - pipe

*/

#include "lcrzo_incl.h"

#include "sysdep/lcrzo_priv_spoof_eth.c"
#include "sysdep/lcrzo_priv_spoof_ip.c"

/*-------------------------------------------------------------*/
int lcrzo_priv_spoofprint_eth(lcrzo_spoof *pspoof,
			      const lcrzo_device device, 
			      lcrzo_constdata packet,
			      lcrzo_int32 nboctpacket);
int lcrzo_priv_spoofprint_eth(lcrzo_spoof *pspoof,
			      const lcrzo_device device, 
			      lcrzo_constdata packet,
			      lcrzo_int32 nboctpacket)
{ if (pspoof->para_printbeforesending)
  { lcrzo_er(lcrzo_packet_print_eth(packet, nboctpacket, 
				   pspoof->para_printprofile));
  }
  return(lcrzo_priv_spoof_eth(pspoof, device, packet, nboctpacket));
} 

/*-------------------------------------------------------------*/
int lcrzo_priv_spoofprint_ip(lcrzo_spoof *pspoof,
			     lcrzo_constdata packet,
			     lcrzo_int32 nboctpacket);
int lcrzo_priv_spoofprint_ip(lcrzo_spoof *pspoof,
			     lcrzo_constdata packet,
			     lcrzo_int32 nboctpacket)
{ lcrzo_device device;
  lcrzo_etha srcetha, destetha;
  lcrzo_ipl destipl;
  lcrzo_hdrleth hdrleth;
  lcrzo_data data;
  lcrzo_int32 datasize;

  if ( ! pspoof->para_useethforip )
  { if (pspoof->para_printbeforesending)
    { lcrzo_er(lcrzo_packet_print_ip(packet, nboctpacket, 
				     pspoof->para_printprofile));
    }
    lcrzo_er(lcrzo_priv_spoof_ip(pspoof, packet, nboctpacket))
  }
  else
  { /* get the destination host */
    if (nboctpacket<20)
    { return(LCRZO_ERR_OKROUTENOTFOUND);
    }
    else
    { lcrzo_er(lcrzo_ipl_init_ipa(packet+16, &destipl));
    }
    /* get route to this host */
    lcrzo_er(lcrzo_conf_route_to_host(destipl,
				      device, srcetha, destetha,
				      NULL, NULL));
    /* initialize an Ethernet header */
    lcrzo_er(lcrzo_hdrleth_initdefault(&hdrleth));
    memcpy(hdrleth.src, srcetha, LCRZO_ETHA_MAXBYTES);
    memcpy(hdrleth.dst, destetha, LCRZO_ETHA_MAXBYTES);
    hdrleth.type=LCRZO_HDRLETH_TYPE_IP;
    lcrzo_er(lcrzo_packet_initm_ethdata(hdrleth, packet, (lcrzo_uint16)nboctpacket,
					&data, &datasize));

    /* send the Ethernet packet */
    lcrzo_efr(lcrzo_spoof_eth(pspoof, device, data, datasize), 
	      lcrzo_data_free(data));
    lcrzo_data_free(data);
  }

  return(LCRZO_ERR_OK);
} 

/*-------------------------------------------------------------*/
int lcrzo_spoof_init(lcrzo_spoof *pspoof)
{
  /*parameters verification*/
  if (pspoof==NULL) return(LCRZO_ERR_PANULLPTR);

  pspoof->spooftype=LCRZO_PRIV_SPOOF_TYPE_NONE;
  lcrzo_er(lcrzo_global_get_spoof_fragoctosize(&(pspoof->para_fragoctosize)));
  lcrzo_er(lcrzo_global_get_spoof_printbeforesending(&(pspoof->para_printbeforesending)));
  lcrzo_er(lcrzo_global_get_spoof_printprofile(&(pspoof->para_printprofile)));
  lcrzo_er(lcrzo_global_get_spoof_useethforip(&(pspoof->para_useethforip)));
  pspoof->fd=-1;

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_close(lcrzo_spoof *pspoof)
{
  /*parameters verification*/
  if (pspoof==NULL) return(LCRZO_ERR_PANULLPTR);

  switch(pspoof->spooftype)
  { case LCRZO_PRIV_SPOOF_TYPE_NONE:
      break;
    case LCRZO_PRIV_SPOOF_TYPE_ETH:
      lcrzo_er(lcrzo_priv_spoof_close_eth(pspoof));
      break;
    case LCRZO_PRIV_SPOOF_TYPE_IP:
      lcrzo_er(lcrzo_priv_spoof_close_ip(pspoof));
      break;
    default:
      return(lcrzo_ieuv("lcrzo_spoof_close", "pspoof->spooftype"));
  }
  pspoof->fd=-1;
  pspoof->spooftype=LCRZO_PRIV_SPOOF_TYPE_NONE;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_eth(lcrzo_spoof *pspoof,
		    const lcrzo_device device, 
		    lcrzo_constdata packet, 
		    lcrzo_int32 nboctpacket)
{ lcrzo_uint8 nboctipoptpremier, nboctipoptsuivants, nboctipopt;
  lcrzo_hdrlip hdrlipfrag, hdrlip;
  lcrzo_hdrleth hdrleth;
  lcrzo_uint16 i, nbfragments, nboctipdata, nbmaxoct, nboctdejaenvoyes;
  lcrzo_int32 nboctethdatatosend;
  lcrzo_data ipdata, ethdatatosend;
  lcrzo_ipopt ipopt;
  lcrzo_device dev;
  int ret;

  /*parameters verification*/
  if (pspoof==NULL) return(LCRZO_ERR_PANULLPTR);
  if (device==NULL) return(LCRZO_ERR_PANULLPTR);
  if (packet==NULL && nboctpacket) return(LCRZO_ERR_PANULLPTRSIZE);
  if (nboctpacket==0) return(LCRZO_ERR_OK);
  if (nboctpacket<0) return(LCRZO_ERR_PATOOLOW);
  lcrzo_er(lcrzo_device_init_noalias(device, dev));

  /*if spooftype is different than actual*/
  switch(pspoof->spooftype)
  { case LCRZO_PRIV_SPOOF_TYPE_NONE:
      lcrzo_er(lcrzo_priv_spoof_init_eth(pspoof, dev));
      pspoof->spooftype=LCRZO_PRIV_SPOOF_TYPE_ETH;
      break;
    case LCRZO_PRIV_SPOOF_TYPE_ETH:
      if (!lcrzo_device_equal(pspoof->device, dev))
      { lcrzo_er(lcrzo_priv_spoof_close_eth(pspoof));
        lcrzo_er(lcrzo_priv_spoof_init_eth(pspoof, dev));
        pspoof->spooftype=LCRZO_PRIV_SPOOF_TYPE_ETH;
      }
      break;
    case LCRZO_PRIV_SPOOF_TYPE_IP:
      lcrzo_er(lcrzo_priv_spoof_close_ip(pspoof));
      lcrzo_er(lcrzo_priv_spoof_init_eth(pspoof, dev));
      pspoof->spooftype=LCRZO_PRIV_SPOOF_TYPE_ETH;
      break;
    default:
      return(lcrzo_ieuv("lcrzo_spoof_eth", "pspoof->spooftype"));
  }

  /*call the private function*/
  if (pspoof->para_fragoctosize>=8192)
  { return(lcrzo_priv_spoofprint_eth(pspoof, dev, packet, nboctpacket));
    /*finish here*/
  }

  /*we decode*/
  ret=lcrzo_packet_decodem_ethipoptdata(packet, nboctpacket,
					&hdrleth, &hdrlip,
					ipopt, &nboctipopt,
					&ipdata, &nboctipdata);
  if (ret!=LCRZO_ERR_OK)
  { return(lcrzo_priv_spoofprint_eth(pspoof, dev, packet, nboctpacket));
    /*finish here*/
  }

  /*calcul du nombre de fragments*/
  nbmaxoct=(lcrzo_uint16)(pspoof->para_fragoctosize*8);
  nbfragments=(lcrzo_uint16)((nboctipdata+(nbmaxoct-1))/nbmaxoct);

  /*si il n'y a qu'un fragment, on l'envoie simplement*/
  if (nbfragments<=1)
  { lcrzo_data_free(ipdata);
    return(lcrzo_priv_spoofprint_eth(pspoof, dev, packet, nboctpacket));
    /*finish here*/
  }

  /*on "analyse" les options pour savoir si on les mets dans chaque
    fragment ou non. Selon la rfc 791 si le bit de poids fort vaut
    0, on ne les copie pas.*/
  if (nboctipopt==0)
  { nboctipoptpremier=0;
    nboctipoptsuivants=0;
  }
  else
  { nboctipoptpremier=nboctipopt;
    if ( ipopt[0]&0x80 )
      nboctipoptsuivants=nboctipopt;
    else
      nboctipoptsuivants=0; /*on ne met l'option que dans le premier frag*/
  }

  /*on coupe en fragments d'au plus nbmaxoctooct "octo-octets"*/
  /*arrive ici, on suppose que nbfragments>1, c'est a dire nbfragments-1!=0*/
  nboctdejaenvoyes=0;
  for ( i=0 ; i<nbfragments ; i++)
  { /*on cree le nouvel entete IP*/
    hdrlipfrag=hdrlip;
    hdrlipfrag.ihl=LCRZO_HDRLIP_IHL_DEFVAL; /*pour forcer le calcul*/
    hdrlipfrag.totlen=LCRZO_HDRLIP_TOTLEN_DEFVAL; /*forcer le calcul*/
    hdrlipfrag.check=LCRZO_HDRLIP_CHECK_DEFVAL; /*forcer le calcul*/
    if ( i==0 ) /*premier fragment*/
    { /*on cree le nouvel entete IP*/
      hdrlipfrag.morefrag = 1;
      hdrlipfrag.dontfrag = 0;
      hdrlipfrag.offsetfrag = 0;
      /*on envoie le fragment*/
      lcrzo_efr(lcrzo_packet_initm_ethipoptdata(hdrleth, hdrlipfrag, 
						ipopt, nboctipoptpremier,
						ipdata, nbmaxoct,
						&ethdatatosend,
						&nboctethdatatosend),
		lcrzo_data_free(ipdata));
      ret=lcrzo_priv_spoofprint_eth(pspoof, dev, ethdatatosend,
				    (lcrzo_uint16)nboctethdatatosend);
      lcrzo_data_free(ethdatatosend);
      lcrzo_efr(ret, lcrzo_data_free(ipdata));
    }
    else if (i==(nbfragments-1)) /*dernier fragment*/
    { /*on cree le nouvel entete IP*/
      hdrlipfrag.morefrag = 0;
      hdrlipfrag.dontfrag = 0;
      hdrlipfrag.offsetfrag = (lcrzo_uint16)(nboctdejaenvoyes/8);
      /*on envoie le fragment*/
      lcrzo_efr(lcrzo_packet_initm_ethipoptdata(hdrleth, hdrlipfrag, 
						ipopt, nboctipoptsuivants,
						ipdata+nboctdejaenvoyes, 
						(lcrzo_uint16)(nboctipdata-
       						      nboctdejaenvoyes),
						&ethdatatosend,
						&nboctethdatatosend),
		lcrzo_data_free(ipdata));
      ret=lcrzo_priv_spoofprint_eth(pspoof, dev, ethdatatosend,
				    nboctethdatatosend);
      lcrzo_data_free(ethdatatosend);
      lcrzo_efr(ret, lcrzo_data_free(ipdata));
    }
    else
    { /*on cree le nouvel entete IP*/
      hdrlipfrag.morefrag = 1;
      hdrlipfrag.dontfrag = 0;
      hdrlipfrag.offsetfrag = (lcrzo_uint16)(nboctdejaenvoyes/8);
      /*on envoie le fragment*/
      lcrzo_efr(lcrzo_packet_initm_ethipoptdata(hdrleth, hdrlipfrag, 
						ipopt, nboctipoptsuivants,
						ipdata+nboctdejaenvoyes,
						nbmaxoct, &ethdatatosend,
						&nboctethdatatosend),
		lcrzo_data_free(ipdata));
      ret=lcrzo_priv_spoofprint_eth(pspoof, dev, ethdatatosend,
				    nboctethdatatosend);
      lcrzo_data_free(ethdatatosend);
      lcrzo_efr(ret, lcrzo_data_free(ipdata));
    }
    /*on incremente le nombre d'octets envoyes*/
    nboctdejaenvoyes=(lcrzo_uint16)(nboctdejaenvoyes+nbmaxoct);
  }
  lcrzo_data_free(ipdata);
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_ip(lcrzo_spoof *pspoof,
		   lcrzo_constdata packet,
		   lcrzo_int32 nboctpacket)
{ lcrzo_uint8 nboctipoptpremier, nboctipoptsuivants, nboctipopt;
  lcrzo_hdrlip hdrlipfrag, hdrlip;
  lcrzo_uint16 i, nbfragments, nboctipdata;
  lcrzo_uint16 nbmaxoct, nboctdejaenvoyes;
  lcrzo_int32 nboctipdatatosend;
  lcrzo_data ipdata, ipdatatosend;
  lcrzo_ipopt ipopt;
  int ret;

  /*parameters verification*/
  if (pspoof==NULL) return(LCRZO_ERR_PANULLPTR);
  if (packet==NULL && nboctpacket) return(LCRZO_ERR_PANULLPTRSIZE);
  if (nboctpacket==0) return(LCRZO_ERR_OK);
  if (nboctpacket<0) return(LCRZO_ERR_PATOOLOW);

  /*if spooftype is different than actual*/
  switch(pspoof->spooftype)
  { case LCRZO_PRIV_SPOOF_TYPE_NONE:
      if ( pspoof->para_useethforip )
      { /* the spoof_init_eth is done by spoof_eth in lcrzo_priv_spoofprint_ip */
      }
      else
      { lcrzo_er(lcrzo_priv_spoof_init_ip(pspoof));
        pspoof->spooftype=LCRZO_PRIV_SPOOF_TYPE_IP;
      }
      break;
    case LCRZO_PRIV_SPOOF_TYPE_ETH:
      if ( pspoof->para_useethforip )
      { /* change nothing */
      }
      else
      { lcrzo_er(lcrzo_priv_spoof_close_eth(pspoof));
        lcrzo_er(lcrzo_priv_spoof_init_ip(pspoof));
        pspoof->spooftype=LCRZO_PRIV_SPOOF_TYPE_IP;
      }
      break;
    case LCRZO_PRIV_SPOOF_TYPE_IP:
      if ( pspoof->para_useethforip )
      { lcrzo_er(lcrzo_priv_spoof_close_ip(pspoof));
        pspoof->spooftype=LCRZO_PRIV_SPOOF_TYPE_NONE;
        /* the spoof_init_eth is done by spoof_eth in lcrzo_priv_spoofprint_ip */
      }
      else
      { /* change nothing */
      }
      break;
    default:
      return(lcrzo_ieuv("lcrzo_spoof_ip", "pspoof->spooftype"));
  }

  /*call the private function*/
  if (pspoof->para_fragoctosize>=8192)
  { return(lcrzo_priv_spoofprint_ip(pspoof, packet, nboctpacket));
    /*finish here*/
  }

  /*we decode*/
  ret=lcrzo_packet_decodem_ipoptdata(packet, nboctpacket,
				     &hdrlip, ipopt, &nboctipopt,
				     &ipdata, &nboctipdata);
  if (ret!=LCRZO_ERR_OK)
  { return(lcrzo_priv_spoofprint_ip(pspoof, packet, nboctpacket));
    /*finish here*/
  }

  /*calcul du nombre de fragments*/
  nbmaxoct=(lcrzo_uint16)(pspoof->para_fragoctosize*8);
  nbfragments=(lcrzo_uint16)((nboctipdata+(nbmaxoct-1))/nbmaxoct);

  /*si il n'y a qu'un fragment, on l'envoie simplement*/
  if (nbfragments<=1)
  { lcrzo_data_free(ipdata);
    return(lcrzo_priv_spoofprint_ip(pspoof, packet, nboctpacket));
    /*finish here*/
  }

  /*on "analyse" les options pour savoir si on les mets dans chaque
    fragment ou non. Selon la rfc 791 si le bit de poids fort vaut
    0, on ne les copie pas.*/
  if (nboctipopt==0)
  { nboctipoptpremier=0;
    nboctipoptsuivants=0;
  }
  else
  { nboctipoptpremier=nboctipopt;
    if ( ipopt[0]&0x80 )
      nboctipoptsuivants=nboctipopt;
    else
      nboctipoptsuivants=0; /*on ne met l'option que dans le premier frag*/
  }

  /*on coupe en fragments d'au plus nbmaxoctooct "octo-octets"*/
  /*arrive ici, on suppose que nbfragments>1, c'est a dire nbfragments-1!=0*/
  nboctdejaenvoyes=0;
  for ( i=0 ; i<nbfragments ; i++)
  { /*on cree le nouvel entete IP*/
    hdrlipfrag=hdrlip;
    hdrlipfrag.ihl=LCRZO_HDRLIP_IHL_DEFVAL; /*pour forcer le calcul*/
    hdrlipfrag.totlen=LCRZO_HDRLIP_TOTLEN_DEFVAL; /*forcer le calcul*/
    hdrlipfrag.check=LCRZO_HDRLIP_CHECK_DEFVAL; /*forcer le calcul*/
    if ( i==0 ) /*premier fragment*/
    { /*on cree le nouvel entete IP*/
      hdrlipfrag.morefrag = 1;
      hdrlipfrag.dontfrag = 0;
      hdrlipfrag.offsetfrag = 0;
      /*on envoie le fragment*/
      lcrzo_efr(lcrzo_packet_initm_ipoptdata(hdrlipfrag, 
					     ipopt, nboctipoptpremier,
					     ipdata, nbmaxoct,
					     &ipdatatosend,&nboctipdatatosend),
		lcrzo_data_free(ipdata));
      ret=lcrzo_priv_spoofprint_ip(pspoof, ipdatatosend,
				   nboctipdatatosend);
      lcrzo_data_free(ipdatatosend);
      lcrzo_efr(ret, lcrzo_data_free(ipdata));
   }
    else if (i==(nbfragments-1)) /*dernier fragment*/
    { /*on cree le nouvel entete IP*/
      hdrlipfrag.morefrag = 0;
      hdrlipfrag.dontfrag = 0;
      hdrlipfrag.offsetfrag = (lcrzo_uint16)(nboctdejaenvoyes/8);
      /*on envoie le fragment*/
      lcrzo_efr(lcrzo_packet_initm_ipoptdata(hdrlipfrag, 
					     ipopt, nboctipoptsuivants,
					     ipdata+nboctdejaenvoyes, 
					     (lcrzo_uint16)(nboctipdata-
							    nboctdejaenvoyes),
					     &ipdatatosend,&nboctipdatatosend),
		lcrzo_data_free(ipdata));
      ret=lcrzo_priv_spoofprint_ip(pspoof, ipdatatosend,
				   (lcrzo_uint16)nboctipdatatosend);
      lcrzo_data_free(ipdatatosend);
      lcrzo_efr(ret, lcrzo_data_free(ipdata));
    }
    else
    { /*on cree le nouvel entete IP*/
      hdrlipfrag.morefrag = 1;
      hdrlipfrag.dontfrag = 0;
      hdrlipfrag.offsetfrag = (lcrzo_uint16)(nboctdejaenvoyes/8);
      /*on envoie le fragment*/
      lcrzo_efr(lcrzo_packet_initm_ipoptdata(hdrlipfrag, 
					     ipopt, nboctipoptsuivants,
					     ipdata+nboctdejaenvoyes, nbmaxoct,
					     &ipdatatosend,&nboctipdatatosend),
		lcrzo_data_free(ipdata));
      ret=lcrzo_priv_spoofprint_ip(pspoof, ipdatatosend,
				   nboctipdatatosend);
      lcrzo_data_free(ipdatatosend);
      lcrzo_efr(ret, lcrzo_data_free(ipdata));
    }
    /*on incremente le nombre d'octets envoyes*/
    nboctdejaenvoyes=(lcrzo_uint16)(nboctdejaenvoyes+nbmaxoct);
  }
  lcrzo_data_free(ipdata);
 
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
int lcrzo_spoof_ipoptdata(lcrzo_spoof *pspoof,
			  lcrzo_hdrlip hdrlip,
			  const lcrzo_ipopt ipopt,
			  lcrzo_uint8 nboctipopt,
			  lcrzo_constdata data,
			  lcrzo_uint16 nboctdata)
{ lcrzo_data packet;
  lcrzo_int32 nboctpacket;
  int ret;

  lcrzo_er(lcrzo_packet_initm_ipoptdata(hdrlip, ipopt, nboctipopt,
					data, nboctdata,
					&packet, &nboctpacket));
  ret=lcrzo_spoof_ip(pspoof, packet, nboctpacket);
  lcrzo_data_free(packet);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_ipoptudpdata(lcrzo_spoof *pspoof,
			     lcrzo_hdrlip hdrlip,
			     const lcrzo_ipopt ipopt,
			     lcrzo_uint8 nboctipopt,
			     lcrzo_hdrludp hdrludp,
			     lcrzo_constdata data,
			     lcrzo_uint16 nboctdata)
{ lcrzo_data packet;
  lcrzo_int32 nboctpacket;
  int ret;

  lcrzo_er(lcrzo_packet_initm_ipoptudpdata(hdrlip, ipopt, nboctipopt,
					   hdrludp, data, nboctdata,
					&packet, &nboctpacket));
  ret=lcrzo_spoof_ip(pspoof, packet, nboctpacket);
  lcrzo_data_free(packet);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_ipopttcpoptdata(lcrzo_spoof *pspoof,
				lcrzo_hdrlip hdrlip,
				const lcrzo_ipopt ipopt,
				lcrzo_uint8 nboctipopt,
				lcrzo_hdrltcp hdrltcp,
				const lcrzo_tcpopt tcpopt,
				lcrzo_uint8 nbocttcpopt,
				lcrzo_constdata data,
				lcrzo_uint16 nboctdata)
{ lcrzo_data packet;
  lcrzo_int32 nboctpacket;
  int ret;

  lcrzo_er(lcrzo_packet_initm_ipopttcpoptdata(hdrlip, ipopt, nboctipopt,
					      hdrltcp, tcpopt, nbocttcpopt,
					      data, nboctdata,
					      &packet, &nboctpacket));
  ret=lcrzo_spoof_ip(pspoof, packet, nboctpacket);
  lcrzo_data_free(packet);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_ipopticmpdata(lcrzo_spoof *pspoof,
			      lcrzo_hdrlip hdrlip,
			      const lcrzo_ipopt ipopt,
			      lcrzo_uint8 nboctipopt,
			      lcrzo_hdrlicmp hdrlicmp,
			      lcrzo_constdata data,
			      lcrzo_uint16 nboctdata)
{ lcrzo_data packet;
  lcrzo_int32 nboctpacket;
  int ret;

  lcrzo_er(lcrzo_packet_initm_ipopticmpdata(hdrlip, ipopt, nboctipopt,
					    hdrlicmp, data, nboctdata,
					    &packet, &nboctpacket));
  ret=lcrzo_spoof_ip(pspoof, packet, nboctpacket);
  lcrzo_data_free(packet);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_ethdata(lcrzo_spoof *pspoof,
			const lcrzo_device device, 
			lcrzo_hdrleth hdrleth,
			lcrzo_constdata data,
			lcrzo_uint16 nboctdata)
{ lcrzo_data packet;
  lcrzo_int32 nboctpacket;
  int ret;

  lcrzo_er(lcrzo_packet_initm_ethdata(hdrleth, data, nboctdata,
				      &packet, &nboctpacket));
  ret=lcrzo_spoof_eth(pspoof, device, packet, nboctpacket);
  lcrzo_data_free(packet);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_ethipoptdata(lcrzo_spoof *pspoof,
			     const lcrzo_device device, 
			     lcrzo_hdrleth hdrleth,
			     lcrzo_hdrlip hdrlip,
			     const lcrzo_ipopt ipopt,
			     lcrzo_uint8 nboctipopt,
			     lcrzo_constdata data,
			     lcrzo_uint16 nboctdata)
{ lcrzo_data packet;
  lcrzo_int32 nboctpacket;
  int ret;

  lcrzo_er(lcrzo_packet_initm_ethipoptdata(hdrleth, hdrlip, ipopt, nboctipopt,
					   data, nboctdata,
					   &packet, &nboctpacket));
  ret=lcrzo_spoof_eth(pspoof, device, packet, nboctpacket);
  lcrzo_data_free(packet);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_ethipoptudpdata(lcrzo_spoof *pspoof,
				const lcrzo_device device,
				lcrzo_hdrleth hdrleth,
				lcrzo_hdrlip hdrlip,
				const lcrzo_ipopt ipopt,
				lcrzo_uint8 nboctipopt,
				lcrzo_hdrludp hdrludp,
				lcrzo_constdata data,
				lcrzo_uint16 nboctdata)
{ lcrzo_data packet;
  lcrzo_int32 nboctpacket;
  int ret;

  lcrzo_er(lcrzo_packet_initm_ethipoptudpdata(hdrleth, hdrlip,
					      ipopt, nboctipopt,
					      hdrludp, data, nboctdata,
					      &packet, &nboctpacket));
  ret=lcrzo_spoof_eth(pspoof, device, packet, nboctpacket);
  lcrzo_data_free(packet);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_ethipopttcpoptdata(lcrzo_spoof *pspoof,
				   const lcrzo_device device,
				   lcrzo_hdrleth hdrleth,
				   lcrzo_hdrlip hdrlip,
				   const lcrzo_ipopt ipopt,
				   lcrzo_uint8 nboctipopt,
				   lcrzo_hdrltcp hdrltcp,
				   const lcrzo_tcpopt tcpopt,
				   lcrzo_uint8 nbocttcpopt,
				   lcrzo_constdata data,
				   lcrzo_uint16 nboctdata)
{ lcrzo_data packet;
  lcrzo_int32 nboctpacket;
  int ret;

  lcrzo_er(lcrzo_packet_initm_ethipopttcpoptdata(hdrleth, 
						 hdrlip, ipopt, nboctipopt,
						 hdrltcp, tcpopt, nbocttcpopt,
						 data, nboctdata,
						 &packet, &nboctpacket));
  ret=lcrzo_spoof_eth(pspoof, device, packet, nboctpacket);
  lcrzo_data_free(packet);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_ethipopticmpdata(lcrzo_spoof *pspoof,
				 const lcrzo_device device,
				 lcrzo_hdrleth hdrleth,
				 lcrzo_hdrlip hdrlip,
				 const lcrzo_ipopt ipopt,
				 lcrzo_uint8 nboctipopt,
				 lcrzo_hdrlicmp hdrlicmp,
				 lcrzo_constdata data,
				 lcrzo_uint16 nboctdata)
{ lcrzo_data packet;
  lcrzo_int32 nboctpacket;
  int ret;

  lcrzo_er(lcrzo_packet_initm_ethipopticmpdata(hdrleth, hdrlip,
					       ipopt, nboctipopt,
					       hdrlicmp, data, nboctdata,
					       &packet, &nboctpacket));
  ret=lcrzo_spoof_eth(pspoof, device, packet, nboctpacket);
  lcrzo_data_free(packet);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_etharp(lcrzo_spoof *pspoof,
		       const lcrzo_device device, 
		       lcrzo_hdrleth hdrleth,
		       lcrzo_hdrlarp hdrlarp)
{ lcrzo_data packet;
  lcrzo_int32 nboctpacket;
  int ret;

  lcrzo_er(lcrzo_packet_initm_etharp(hdrleth, hdrlarp, &packet, &nboctpacket));
  ret=lcrzo_spoof_eth(pspoof, device, packet, nboctpacket);
  lcrzo_data_free(packet);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_get_fd(lcrzo_spoof *pspoof, 
		       int *pwritefd)
{
  /*parameters verification*/
  if (pspoof==NULL) return(LCRZO_ERR_PANULLPTR);

  if ( pwritefd!=NULL ) *pwritefd=pspoof->fd;

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_spoofeasy_ipudp(lcrzo_ipl iplsrc,
			      lcrzo_ipl ipldst,
			      lcrzo_uint16 portsrc,
			      lcrzo_uint16 portdst,
			      lcrzo_constdata dataudp, 
			      lcrzo_uint16 nboctdataudp)
{ lcrzo_hdrlip  hdrlip;
  lcrzo_hdrludp hdrludp;
  lcrzo_spoof spoof;

  /*parameters verification*/
  if (dataudp==NULL && nboctdataudp) return(LCRZO_ERR_PANULLPTRSIZE);

  /*initialisation de l'entete IP*/
  lcrzo_er(lcrzo_hdrlip_initdefault(&hdrlip));
  hdrlip.saddr=iplsrc;
  hdrlip.daddr=ipldst;
  /*initialisation de l'entete UDP*/
  lcrzo_er(lcrzo_hdrludp_initdefault(&hdrludp));
  hdrludp.sport=portsrc;
  hdrludp.dport=portdst;

  /*envoi d'un packet avec donnees*/
  lcrzo_er(lcrzo_spoof_init(&spoof));
  lcrzo_er(lcrzo_spoof_ipoptudpdata(&spoof, hdrlip, NULL, 0,
				    hdrludp, dataudp, nboctdataudp));
  lcrzo_er(lcrzo_spoof_close(&spoof));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_spoofeasy_iptcp(lcrzo_ipl iplsrc,
			  lcrzo_ipl ipldst,
			  lcrzo_uint16 portsrc,
			  lcrzo_uint16 portdst,
			  lcrzo_uint32 seqnum,
			  lcrzo_uint32 acknum,
			  lcrzo_bool bitsyn, 
			  lcrzo_bool bitack, 
			  lcrzo_bool bitfin,
			  lcrzo_bool bitrst,
			  lcrzo_constdata datatcp, 
			  lcrzo_uint16 nboctdatatcp)
{ lcrzo_hdrlip  hdrlip;
  lcrzo_hdrltcp hdrltcp;
  lcrzo_spoof spoof;

  /*parameters verification*/
  if (datatcp==NULL && nboctdatatcp) return(LCRZO_ERR_PANULLPTRSIZE);
  lcrzo_bool_verifbof(bitsyn);
  lcrzo_bool_verifbof(bitack);
  lcrzo_bool_verifbof(bitrst);

  /*initialisation de l'entete IP*/
  lcrzo_er(lcrzo_hdrlip_initdefault(&hdrlip));
  hdrlip.saddr=iplsrc;
  hdrlip.daddr=ipldst;
  /*initialisation de l'entete TCP*/
  lcrzo_er(lcrzo_hdrltcp_initdefault(&hdrltcp));
  hdrltcp.sport=portsrc;
  hdrltcp.dport=portdst;
  hdrltcp.seqnum=seqnum;
  hdrltcp.acknum=acknum;
  hdrltcp.syn=(lcrzo_int8)bitsyn;
  hdrltcp.ack=(lcrzo_int8)bitack;
  hdrltcp.fin=(lcrzo_int8)bitfin;
  hdrltcp.rst=(lcrzo_int8)bitrst;

  /*envoi d'un packet avec donnees*/
  lcrzo_er(lcrzo_spoof_init(&spoof));
  lcrzo_er(lcrzo_spoof_ipopttcpoptdata(&spoof, hdrlip, NULL, 0,
				       hdrltcp, NULL, 0,
				       datatcp, nboctdatatcp));
  lcrzo_er(lcrzo_spoof_close(&spoof));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_spoofeasy_ipicmp(lcrzo_ipl iplsrc,
			       lcrzo_ipl ipldst,
			       lcrzo_uint8 type,
			       lcrzo_uint8 code,
			       lcrzo_constdata dataicmp, 
			       lcrzo_uint16 nboctdataicmp)
{ lcrzo_hdrlip  hdrlip;
  lcrzo_hdrlicmp hdrlicmp;
  lcrzo_spoof spoof;

  /*parameters verification*/
  if (dataicmp==NULL && nboctdataicmp) return(LCRZO_ERR_PANULLPTRSIZE);

  /*initialisation de l'entete IP*/
  lcrzo_er(lcrzo_hdrlip_initdefault(&hdrlip));
  hdrlip.saddr=iplsrc;
  hdrlip.daddr=ipldst;
  /*initialisation de l'entete ICMP*/
  lcrzo_er(lcrzo_hdrlicmp_initdefault(&hdrlicmp));
  hdrlicmp.type=type;
  hdrlicmp.code=code;

  /*envoi d'un packet avec donnees*/
  lcrzo_er(lcrzo_spoof_init(&spoof));
  lcrzo_er(lcrzo_spoof_ipopticmpdata(&spoof, hdrlip, NULL, 0,
				     hdrlicmp,
				     dataicmp, nboctdataicmp));
  lcrzo_er(lcrzo_spoof_close(&spoof));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_spoofeasy_ethipudp(const lcrzo_device device,
				 const lcrzo_etha ethasrc,
				 const lcrzo_etha ethadst,
				 lcrzo_ipl iplsrc,
				 lcrzo_ipl ipldst,
				 lcrzo_uint16 portsrc,
				 lcrzo_uint16 portdst,
				 lcrzo_constdata dataudp, 
				 lcrzo_uint16 nboctdataudp)
{ lcrzo_hdrleth hdrleth;
  lcrzo_hdrlip  hdrlip;
  lcrzo_hdrludp hdrludp;
  lcrzo_spoof spoof;

  /*parameters verification*/
  if (device==NULL) return(LCRZO_ERR_PANULLPTR);
  if (ethasrc==NULL) return(LCRZO_ERR_PANULLPTR);
  if (ethadst==NULL) return(LCRZO_ERR_PANULLPTR);
  if (dataudp==NULL && nboctdataudp) return(LCRZO_ERR_PANULLPTRSIZE);

  /*initialisation de l'entete ETH*/
  lcrzo_er(lcrzo_hdrleth_initdefault(&hdrleth));
  memcpy(hdrleth.src, ethasrc, LCRZO_ETHA_MAXBYTES);
  memcpy(hdrleth.dst, ethadst, LCRZO_ETHA_MAXBYTES);
  /*initialisation de l'entete IP*/
  lcrzo_er(lcrzo_hdrlip_initdefault(&hdrlip));
  hdrlip.saddr=iplsrc;
  hdrlip.daddr=ipldst;
  /*initialisation de l'entete UDP*/
  lcrzo_er(lcrzo_hdrludp_initdefault(&hdrludp));
  hdrludp.sport=portsrc;
  hdrludp.dport=portdst;

  /*envoi d'un packet avec donnees*/
  lcrzo_er(lcrzo_spoof_init(&spoof));
  lcrzo_er(lcrzo_spoof_ethipoptudpdata(&spoof, device, 
				       hdrleth, hdrlip, NULL, 0,
				       hdrludp, dataudp, nboctdataudp));
  lcrzo_er(lcrzo_spoof_close(&spoof));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_spoofeasy_ethiptcp(const lcrzo_device device,
			     const lcrzo_etha ethasrc,
			     const lcrzo_etha ethadst,
			     lcrzo_ipl iplsrc,
			     lcrzo_ipl ipldst,
			     lcrzo_uint16 portsrc,
			     lcrzo_uint16 portdst,
			     lcrzo_uint32 seqnum,
			     lcrzo_uint32 acknum,
			     lcrzo_bool bitsyn,
			     lcrzo_bool bitack, 
			     lcrzo_bool bitfin,
			     lcrzo_bool bitrst,
			     lcrzo_constdata datatcp, 
			     lcrzo_uint16 nboctdatatcp)
{ lcrzo_hdrleth hdrleth;
  lcrzo_hdrlip  hdrlip;
  lcrzo_hdrltcp hdrltcp;
  lcrzo_spoof spoof;

  /*parameters verification*/
  if (device==NULL) return(LCRZO_ERR_PANULLPTR);
  if (ethasrc==NULL) return(LCRZO_ERR_PANULLPTR);
  if (ethadst==NULL) return(LCRZO_ERR_PANULLPTR);
  if (datatcp==NULL && nboctdatatcp) return(LCRZO_ERR_PANULLPTRSIZE);
  lcrzo_bool_verifbof(bitsyn);
  lcrzo_bool_verifbof(bitack);
  lcrzo_bool_verifbof(bitrst);

  /*initialisation de l'entete ETH*/
  lcrzo_er(lcrzo_hdrleth_initdefault(&hdrleth));
  memcpy(hdrleth.src, ethasrc, LCRZO_ETHA_MAXBYTES);
  memcpy(hdrleth.dst, ethadst, LCRZO_ETHA_MAXBYTES);
  /*initialisation de l'entete IP*/
  lcrzo_er(lcrzo_hdrlip_initdefault(&hdrlip));
  hdrlip.saddr=iplsrc;
  hdrlip.daddr=ipldst;
  /*initialisation de l'entete TCP*/
  lcrzo_er(lcrzo_hdrltcp_initdefault(&hdrltcp));
  hdrltcp.sport=portsrc;
  hdrltcp.dport=portdst;
  hdrltcp.seqnum=seqnum;
  hdrltcp.acknum=acknum;
  hdrltcp.syn=(lcrzo_int8)bitsyn;
  hdrltcp.ack=(lcrzo_int8)bitack;
  hdrltcp.fin=(lcrzo_int8)bitfin;
  hdrltcp.rst=(lcrzo_int8)bitrst;

  /*envoi d'un packet avec donnees*/
  lcrzo_er(lcrzo_spoof_init(&spoof));
  lcrzo_er(lcrzo_spoof_ethipopttcpoptdata(&spoof, device, hdrleth,
					  hdrlip, NULL, 0,
					  hdrltcp, NULL, 0,
					  datatcp, nboctdatatcp));
  lcrzo_er(lcrzo_spoof_close(&spoof));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_spoofeasy_ethipicmp(const lcrzo_device device,
				  const lcrzo_etha ethasrc,
				  const lcrzo_etha ethadst,
				  lcrzo_ipl iplsrc,
				  lcrzo_ipl ipldst,
				  lcrzo_uint8 type,
				  lcrzo_uint8 code,
				 lcrzo_constdata dataicmp, 
				  lcrzo_uint16 nboctdataicmp)
{ lcrzo_hdrleth hdrleth;
  lcrzo_hdrlip  hdrlip;
  lcrzo_hdrlicmp hdrlicmp;
  lcrzo_spoof spoof;

  /*parameters verification*/
  if (device==NULL) return(LCRZO_ERR_PANULLPTR);
  if (ethasrc==NULL) return(LCRZO_ERR_PANULLPTR);
  if (ethadst==NULL) return(LCRZO_ERR_PANULLPTR);
  if (dataicmp==NULL && nboctdataicmp) return(LCRZO_ERR_PANULLPTRSIZE);

  /*initialisation de l'entete ETH*/
  lcrzo_er(lcrzo_hdrleth_initdefault(&hdrleth));
  memcpy(hdrleth.src, ethasrc, LCRZO_ETHA_MAXBYTES);
  memcpy(hdrleth.dst, ethadst, LCRZO_ETHA_MAXBYTES);
  /*initialisation de l'entete IP*/
  lcrzo_er(lcrzo_hdrlip_initdefault(&hdrlip));
  hdrlip.saddr=iplsrc;
  hdrlip.daddr=ipldst;
  /*initialisation de l'entete ICMP*/
  lcrzo_er(lcrzo_hdrlicmp_initdefault(&hdrlicmp));
  hdrlicmp.type=type;
  hdrlicmp.code=code;

  /*envoi d'un packet avec donnees*/
  lcrzo_er(lcrzo_spoof_init(&spoof));
  lcrzo_er(lcrzo_spoof_ethipopticmpdata(&spoof, device, hdrleth,
					hdrlip, NULL, 0,
					hdrlicmp,
					dataicmp, nboctdataicmp));
  lcrzo_er(lcrzo_spoof_close(&spoof));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_set_fragoctosize(lcrzo_spoof *pspoof,
				 lcrzo_uint16 fragoctosize)
{ if (pspoof==NULL) return(LCRZO_ERR_PANULLPTR);
  if (fragoctosize==0) return(LCRZO_ERR_PATOOLOW);
  if (fragoctosize>8192) return(LCRZO_ERR_PATOOBIG);

  pspoof->para_fragoctosize=fragoctosize;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_set_printbeforesending(lcrzo_spoof *pspoof,
				       lcrzo_bool printbeforesending)
{ if (pspoof==NULL) return(LCRZO_ERR_PANULLPTR);
  lcrzo_bool_verifbof(printbeforesending);
  pspoof->para_printbeforesending=printbeforesending;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_spoof_set_useethforip.c"

/*-------------------------------------------------------------*/
int lcrzo_spoof_set_printprofile(lcrzo_spoof *pspoof,
				 lcrzo_printprofile printprofile)
{ if (pspoof==NULL) return(LCRZO_ERR_PANULLPTR);
  pspoof->para_printprofile=printprofile;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_get_fragoctosize(lcrzo_spoof *pspoof,
				 lcrzo_uint16 *pfragoctosize)
{ if (pspoof==NULL) return(LCRZO_ERR_PANULLPTR);
  if (pfragoctosize!=NULL) *pfragoctosize=pspoof->para_fragoctosize;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_get_printbeforesending(lcrzo_spoof *pspoof,
				       lcrzo_bool *pprintbeforesending)
{ if (pspoof==NULL) return(LCRZO_ERR_PANULLPTR);
  if (pprintbeforesending!=NULL)
  { *pprintbeforesending=pspoof->para_printbeforesending;
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_get_printprofile(lcrzo_spoof *pspoof,
				 lcrzo_printprofile *pprintprofile)
{ if (pspoof==NULL) return(LCRZO_ERR_PANULLPTR);
  if (pprintprofile!=NULL) *pprintprofile=pspoof->para_printprofile;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_spoof_get_useethforip(lcrzo_spoof *pspoof,
				lcrzo_bool *puseethforip)
{ if (pspoof==NULL) return(LCRZO_ERR_PANULLPTR);
  if (puseethforip!=NULL)
  { *puseethforip=pspoof->para_useethforip;
  }
  return(LCRZO_ERR_OK);
}

