/**************************************************************************
                          ipmagic.c  -  The Magic of IP
                             -------------------
    begin                : Tue Jul 31 2001
    copyright            : (C) 2001 by Josiah Zayner
    email                : phric@legions.org
 ***************************************************************************/

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



#include "wand.h"


/*
   We need to get rid of these globals I guess we will just
   have to make a big struct!
*/

/* For number of spells and labels and such */
GtkWidget *num_sp, *numsp_lbl;

/* IP widget text boxes */
GtkWidget *hl_te, *vers_te, *tos_te, *tlen_te, *id_te, *frag_te;
GtkWidget *ttl_te, *fragoff_te, *sadd_te, *dadd_te, *proto, *frag;

GtkWidget *payload;
GtkWidget *gtksnoop;

GtkWidget *make_misc_meat(void)
{

  GtkWidget *tab_lbl, *fixed_pos_misc;


  tab_lbl = fixed_pos_misc = NULL;


  tab_lbl = gtk_label_new(" Snoop ");
  fixed_pos_misc = gtk_fixed_new();
  gtk_notebook_insert_page(GTK_NOTEBOOK(tab),
                           fixed_pos_misc,
                           tab_lbl,
		           2);
  gtk_widget_show(fixed_pos_misc);
  gtk_widget_show(tab_lbl);

  gtksnoop = make_tex(fixed_pos_misc, gtksnoop, 520, 300, 40, 100);
  return gtksnoop;

/*
  hwd_lbl = make_label(fixed_pos_misc,
                       hwd_lbl, "Hardware Address:", 65, 80);
  hwd1 = make_text(fixed_pos_misc, hwd1, 30, 22, 175, 78);
  hwd2 = make_text(fixed_pos_misc, hwd2, 30, 22, 215, 78);
  hwd3 = make_text(fixed_pos_misc, hwd3, 30, 22, 255, 78);
  hwd4 = make_text(fixed_pos_misc, hwd4, 30, 22, 295, 78);
  hwd5 = make_text(fixed_pos_misc, hwd5, 30, 22, 335, 78);
  hwd6 = make_text(fixed_pos_misc, hwd6, 30, 22, 375, 78);
*/
}


/* hide the widgets of the protocol last chosen */
void clear_last(int which)
{
  switch(which)
  {

     case 1:
       clear_tcp();
     break;

     case 2:
       clear_udp();
     break;

     case 3:
       clear_icmp();
     break;

     case 4:
       clear_igmp();
     break;
  }
}


/* function to choose which protocols widgets to display
   and which to hide!
*/
void cast_spell(GtkEntry *entry)
{
  const char *item;
  /*
     we need these otherwise gtk_widget_hide will cause a core
     because the widgets pointing to a NULL
  */
  static int last = 0;

  item = gtk_entry_get_text(entry);

  if(strstr(item, "TCP"))
  {

    clear_last(last);
    tcp_spell();
    last = 1;
  }

  else if(strstr(item, "UDP"))
  {
    clear_last(last);
    udp_spell();
    last = 2;
  }

  else if(strstr(item, "ICMP"))
  {
    clear_last(last);
    last = 3;
    icmp_spell();
  }

  else if(strstr(item, "IGMP"))
  {
    clear_last(last);
    last = 4;
    igmp_spell();
  }

  else
  {
    clear_last(last);
    last = 0;

  }
}



void ip_cauldron()
{
  /* widget labels for IP header */
  GtkWidget *IP_lbl, *hl_lbl, *vers_lbl, *tos_lbl, *tlen_lbl, *id_lbl, *frag_lbl;
  GtkWidget *ttl_lbl, *proto_lbl, *sadd_lbl, *dadd_lbl, *fragoff_lbl;


  GList *frags = NULL;
  GList *protos = NULL;
  const char *protoc;

  /* initially assign these as NULL */
  IP_lbl = hl_lbl = vers_lbl = tos_lbl = tlen_lbl = id_lbl = frag_lbl = NULL;
  ttl_lbl = proto_lbl = sadd_lbl = dadd_lbl = ttl_te = fragoff_lbl = NULL;
  hl_te = vers_te = tos_te = tlen_te = id_te = frag_te = NULL;
  ttl_te = fragoff_te = sadd_te = dadd_te = proto = frag = NULL;
  num_sp = numsp_lbl = NULL;

  /* display all our IP widgets
     and text box and label for each yikes! thats alot
  */
  IP_lbl = make_label(fixed_pos, IP_lbl, "IP Header Options", 225, 50);
  hl_lbl = make_label(fixed_pos, hl_lbl, "Header Length(32bits x):", 30, 80);
  hl_te = make_text(fixed_pos, hl_te, 30, 22, 175, 78);
  vers_lbl = make_label(fixed_pos, vers_lbl, "IP Version:", 240, 80);
  vers_te = make_text(fixed_pos, vers_te, 40, 22, 310, 78);
  tos_lbl = make_label(fixed_pos, tos_lbl, "Type-Of-Service:", 370, 80);
  tos_te = make_text(fixed_pos, tos_te, 40, 22, 480, 78);

  tlen_lbl = make_label(fixed_pos, tlen_lbl, "Total Length(8bits x):", 30, 120);
  /*
  tlen_te = make_text(fixed_pos, tlen_te, 30, 22, 175, 118);
  */
  id_lbl = make_label(fixed_pos, id_lbl, "Packet ID:", 240, 120);
  id_te = make_text(fixed_pos, id_te, 40, 22, 310, 118);
  ttl_lbl = make_label(fixed_pos, ttl_lbl, "Time-To-Live:", 370, 120);
  ttl_te = make_text(fixed_pos, ttl_te, 40, 22, 480, 118);

  numsp_lbl = make_label(fixed_pos, numsp_lbl, "Number of Packets:", 30, 160);
  num_sp = make_text(fixed_pos, num_sp, 30, 22, 160, 158);
  /* our fragmentation combo box */
  frag_lbl = make_label(fixed_pos, frag_lbl, "Fragmentaion:", 235, 160);
  frag = make_combo(fixed_pos, frag, 120, 10, 325, 160);
  frags = g_list_append(frags, (void *)"None");
  frags = g_list_append(frags, (void *)"Don't Fragment");
  frags = g_list_append(frags, (void *)"Fragment");
  frags = g_list_append(frags, (void *)"More Fragments");
  gtk_combo_set_popdown_strings(GTK_COMBO(frag), frags);
  g_list_free(frags);
  gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(frag)->entry), FALSE);

  /*
  fragoff_lbl = make_label(fixed_pos, fragoff_lbl, "Fragmentation Offset:", 320, 160);
  fragoff_te = make_text(fixed_pos, fragoff_te, 40, 22, 430, 158);
  */
  /* our protocol combo box, TCP, UDP, and ICMP */
  proto_lbl = make_label(fixed_pos, proto_lbl, "Protocol:", 220, 250);
  proto = make_combo(fixed_pos, proto, 60, 10, 280, 250);
  protos = g_list_append(protos, (void *)"IP");
  protos = g_list_append(protos, (void *)"TCP");
  protos = g_list_append(protos, (void *)"UDP");
  protos = g_list_append(protos, (void *)"ICMP");

  gtk_combo_set_popdown_strings(GTK_COMBO(proto), protos);
  g_list_free(protos);
  gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(proto)->entry), FALSE);

  /* if we choose a protocol clear all widgets and show the new ones */
  gtk_signal_connect(GTK_OBJECT(GTK_COMBO(proto)->entry),
                     "changed",
                     GTK_SIGNAL_FUNC(cast_spell),
                     GTK_ENTRY(GTK_COMBO(proto)->entry)
                    );

  sadd_lbl = make_label(fixed_pos, sadd_lbl, "Source Host:", 40, 200);
  sadd_te = make_text(fixed_pos, sadd_te, 150, 22, 120, 200);
  dadd_lbl = make_label(fixed_pos, dadd_lbl, "Destination Host:", 310, 200);
  dadd_te = make_text(fixed_pos, dadd_te, 150, 22, 410, 200);
  protoc = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(proto)->entry));
  payload = make_tex(fixed_pos, payload, 520, 80, 40, 300);

  /* whatever proto is picked intialize that packet type */

  /* for our NEW MISCellaneous(sp?) tab blah MISC tab */
  make_misc_meat();

  ip_defaults((GtkWidget *)NULL);
}

/* set default values to make it easier on the user!
   YAY, for user!
*/
void ip_defaults(GtkWidget *oldbutton)
{
  const char *protoc;

  gtk_entry_set_text(GTK_ENTRY(num_sp), "1");
  gtk_entry_set_text(GTK_ENTRY(hl_te), "5");
  gtk_entry_set_text(GTK_ENTRY(vers_te), "4");
  gtk_entry_set_text(GTK_ENTRY(tos_te), "0");
 /* gtk_entry_set_text(GTK_ENTRY(tlen_te), "40");  */
  gtk_entry_set_text(GTK_ENTRY(id_te), "0");
  gtk_entry_set_text(GTK_ENTRY(ttl_te), "64");

  /* gtk_entry_set_text(GTK_ENTRY(fragoff_te), "0"); */
  gtk_entry_set_text(GTK_ENTRY(sadd_te), "127.0.0.1");
  gtk_entry_set_text(GTK_ENTRY(dadd_te), "127.0.0.1");
  protoc = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(proto)->entry));

}

/* begining to start to implement IGMP woohoo! */
void igmp_spell(void) { }

void igmp_defaults(void) { }

void clear_igmp(void) { }

/* Nice and easy, the only argument is the maximum data size
   then we allocate memory after we have the real data size
   so we only allocate for the memory we need
*/
char *get_payload(int size_d)
{
  int x;
  char *data = NULL;


  /* check datalength and store data */
  if(size_d > gtk_text_get_length(GTK_TEXT(payload)))
  {
    data = clalloc(size_d);
    memset(data, '\0', size_d);

    for(x = 0; x < gtk_text_get_length(GTK_TEXT(payload)); x++)
    { data[x] = GTK_TEXT_INDEX(GTK_TEXT(payload), x); }

  }
  else
    prterr("Data length to long for one packet!!");

  return data;
}

/* have this so we can return :P ,
   gtk_signal_connect needs a void function!
*/
void send_packet(GtkWidget *oldbutton)
{ packet_send(); }
 

/* this function allows me to control errors 
   that send_packet cannot because it has no return 
   value or rather can't have one, due to Gtk signal
   handling thing-o-mobobbers!
*/

int packet_send(void)
{
  int s, yes = 1, one = 1, SNOOP_ONF = 0;
  struct sockaddr_in endup;
  struct in_addr ip_srce, ip_dstn;
  struct protoent *ourproto;
  struct packmack *tcpips = clalloc(sizeof(struct packmack));
  char *envelope = NULL;
  char *data = NULL;
  static int x;

  /* get our source and dest addresses */
  ip_srce = wherefromto(gtk_entry_get_text(GTK_ENTRY(sadd_te)));
  /* do we need this?
   if(ip_srce.s_addr == 0) { prterr("No source address"); }
  */
  ip_dstn = wherefromto(gtk_entry_get_text(GTK_ENTRY(dadd_te)));
  if(ip_dstn.s_addr == 0) { return 1; }
  tcpips->d_port = 0;
  tcpips->packsz = S_IP;

  /* get proto */
  if((ourproto = getprotobyname(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(proto)->entry)))) == NULL)
  {
    prterr("Getprotobyname: invalid protocol");
    
  }

  /* allocate memory for packet and get data */
  if(ourproto->p_proto == 6)
  {
    envelope = clalloc(65535);
    tcpips = tcp_gather(envelope, get_payload(65535 - S_TCPIP),
                        ip_srce, ip_dstn);
  }
  else if(ourproto->p_proto == 17)
  {
    envelope = clalloc(65535);
    tcpips = udp_gather(envelope, get_payload(65535 - (S_IP + S_UDP)),
                        ip_srce, ip_dstn);
  }
  else if(ourproto->p_proto == 1)
  {
    envelope = clalloc(65535);
    tcpips = icmp_gather(envelope, get_payload(65535 - (S_IP + S_ICMP)));
  }
  else if(ourproto->p_proto == 0){ envelope = clalloc(65535);  }

  gather_info(envelope, ourproto->p_proto, tcpips->packsz);

  /* open a raw socket */
  if((s = socket(PF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
  {
    perror("socket");
    exit(s);
  }

  /* set socket options at IP level, so we can create our own IP header */
  if((setsockopt(s, SOL_IP, IP_HDRINCL, &yes, sizeof(yes))) == -1)
  {
    prterr("setsockopt");
    exit(1);
  }

  /* we need to set this socket option to send and recv broadcasts
     It is supposed to only be datagram broadcast but should I
     enforce this? and even so I need to figure a way to extract
     the header values from the memory segment
  */
  if(ip_srce.s_addr & 0xff000000 || ip_dstn.s_addr & 0xff000000)
    {
      if((setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one))) == -1)
        {
          perror("setsockopt");
          exit(-1);
        }
    }

  /* file in sockaddr struct BLAH! */
  memset(&endup, '\0', sizeof(struct sockaddr_in));
  endup.sin_family = PF_INET;
  endup.sin_port = tcpips->d_port;
  endup.sin_addr = ip_dstn;
  
  if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(snoop_check)))
  { SNOOP_ONF = 2; }

  /* send num_sp number of packets */
  for(x = 0; x < atoi(gtk_entry_get_text(GTK_ENTRY(num_sp))); x++)
  {
    /* yes and finally send packet */
    if((sendto(s, envelope,
               tcpips->packsz,
               0,
               (struct sockaddr *)&endup,
               sizeof(struct sockaddr))) == -1)
    {

      prterr("sendto: cannot send");
      return 1;
    }
    if(ourproto->p_proto == 6 && SNOOP_ONF)
      pooper_snooper(SNOOP_ONF, ip_dstn, tcpips->d_port, (void *)gtksnoop);
  }


  /* free memory and close socket */
  free(envelope);
  if(data)
    free(data);
  free(tcpips);
  close(s);
  return 0;
}

/* get ip header info from boxes
   then get ip_magic->protocol header info
*/
void gather_info(char *envelope, int proto, int pasize)
{
  struct ip *ip_magic = clalloc(S_IP);
  const char *iteme;

  ip_magic->ip_hl = atoi(gtk_entry_get_text(GTK_ENTRY(hl_te))); /* header length */
  ip_magic->ip_v = atoi(gtk_entry_get_text(GTK_ENTRY(vers_te))); /* version */
  ip_magic->ip_tos = atoi(gtk_entry_get_text(GTK_ENTRY(tos_te))); /* type-of-service */
  ip_magic->ip_len = pasize; /* packet length */

  ip_magic->ip_id = htons(atoi(gtk_entry_get_text(GTK_ENTRY(id_te)))); /* ID */
 /* ip_magic->ip_off = atoi(gtk_entry_get_text(GTK_ENTRY(fragoff_te))); */
  ip_magic->ip_ttl = atoi(gtk_entry_get_text(GTK_ENTRY(ttl_te))); /* time to live */
  ip_magic->ip_p = proto; /* protocol */

  /* fragmentation */
  iteme = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(frag)->entry));
  if(strstr(iteme, "Fragment") && !strstr(iteme, "Don't") && !strstr(iteme, "More"))
  {  ip_magic->ip_off = 16; }
  else if(strstr(iteme, "Don't"))
  { ip_magic->ip_off = 64; }
  else if (strstr(iteme, "More"))
  { ip_magic->ip_off = 32; }
  else if(strstr(iteme, "None"))
  { ip_magic->ip_off = 0; }


  ip_magic->ip_src = wherefromto(gtk_entry_get_text(GTK_ENTRY(sadd_te))); /* source address */
  ip_magic->ip_dst = wherefromto(gtk_entry_get_text(GTK_ENTRY(dadd_te))); /* destination address */
  memcpy(envelope, ip_magic, S_IP); /* copy IP header to packet */

}




