Logo Search packages:      
Sourcecode: wackamole version File versions  Download package

spoofmanager.c

/*
 * The Wackamole Program.
 *     
 * The contents of this file are subject to the CNDS Open Source
 * License, Version 1.0 (the ``License''); you may not use
 * this file except in compliance with the License.  You may obtain a
 * copy of the License at:
 *
 * http://www.backhand.org/wackamole/license/
 *
 * or in the file ``license.txt'' found in this distribution.
 *
 * Software distributed under the License is distributed on an AS IS basis, 
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
 * for the specific language governing rights and limitations under the 
 * License.
 *
 * The Creators of Wackamole are:
 *  Yair Amir, Ryan Caudy, Aashima Munjal and Theo Schlossnagle.
 *
 *  Copyright (C) 2000-2001 The Johns Hopkins University
 *  All Rights Reserved.
 *
 *  This product uses the Spread toolkit, developed by Spread Concepts LLC.
 *  For more information about Spread see http://www.spread.org
 *
 *  Wackamole development was partially funded by a grant from the Defense
 *  Advanced Research Projects Agency (DARPA) to Johns Hopkins University. The 
 *  U.S. Government retains certain rights in this software.
 *
 */
#include "config.h"
#include "alarm.h"
#include "ife.h"
#include "arpcache.h"

extern int Num_notifications;
extern struct notification Notification_table[MAX_NOTIF];

/* RWC: NEED A VERSION THAT TAKES CODE AND DATA. */
#if 0
void *arp_spoof_notifier(void *);
#endif
void arp_spoof_notifier( int, void * );
/* end RWC */
int send_arp_spoof_arp_cache(struct interface *i, struct notification *n,
                       address *ac, int *count);
int send_arp_spoof_netblock(struct interface *i, struct notification *n,
                      int *count);

void cancel_spoofer(entry *VE) {
  /* RWC: ELIMINATE THREAD CODE */
#if 0
  /* You should have the lock when you enter this function */
#ifndef DONT_USE_THREADS
  if(VE->notifier) {
    Alarm(PRINT, "canceled unfinished notification thread");
    pthread_cancel(VE->notifier);
  }
#endif
#endif
  /* RWC: Here's the code that replaces the previous. */
  E_dequeue( arp_spoof_notifier, 0, VE );
  Alarm( PRINT, "Dequeued arp spoof notifier." );
  /* end RWC */
}
void invoke_spoofer(entry *VE) {
  /* RWC: ELIMINATE THREAD CODE
   * note: There appears to be a memory leak in the version that would have
   *       been used previously if DONT_USE_THREADS was defined.  Also, there
   *       is a locking error in the threaded version, caused by incorrect code
   *       in defines.h:  _ve_wait(*VE) is UNLOCKING the mutex, while
   *       _ve_post(*VE) LOCKS the mutex. */
  sp_time zero_time = { 0, 0 };
#if 0
#ifndef DONT_USE_THREADS
  pthread_attr_t attr;
  /*  Spawn a pthread to do notifications for all VIPs in the VIF.
      We iterate across each notification and spoofs each VIP
      for that notification */
  _ve_wait(*VE);
  cancel_spoofer(VE);
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  if(VE->thread_data) free(VE->thread_data);
  VE->thread_data = (void *)fetch_shared_arp_cache();
  if(pthread_create(&(VE->notifier), &attr, arp_spoof_notifier, (void *)VE)) {
    Alarm(PRINT, "could not create wackamole notification thread.");
  } else {
    Alarm(PRINT, "created notification thread for virtual entry");
  }
  _ve_post(*VE);
  pthread_attr_destroy(&attr);
#else
  VE->thread_data = (void *)fetch_shared_arp_cache();
  arp_spoof_notifier(VE);
#endif
#endif
  /* RWC: Here's the code that replaces the previous. */
  cancel_spoofer(VE);
  if(VE->arp_spoof_data.arpcache) free(VE->arp_spoof_data.arpcache);
  VE->arp_spoof_data.arpcache = fetch_shared_arp_cache();
  E_queue( arp_spoof_notifier, 0, VE, zero_time ); 
  Alarm( PRINT, "Queued arp spoof notifier for virtual entry." );
  /* end RWC */
}

  /* RWC: ELIMINATE THREAD CODE */
#if 0
void *arp_spoof_notifier(void *arg) {
  int i, j, old, ifcount = 0;
  entry *VE = (entry *)arg;
  struct interface lVIF[MAX_PSEUDO+1];
  int left_todo[MAX_NOTIF];
  address *arpcache;

#ifndef DONT_USE_THREADS
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old);
#endif
  /* how many VIPs we got? */
  if(_pif_ip_s(*VE)) {
    memcpy(&lVIF[ifcount], &(VE->pseudo_if), sizeof(struct interface));
    ifcount++;
  }
  for(i=0;(i<MAX_PSEUDO) && _eif_ip_s(*VE, i);i++) {
    memcpy(&lVIF[ifcount], &(VE->extra_ifs[i]), sizeof(struct interface));
    ifcount++;
  }

  arpcache = (address *)VE->thread_data;

  for(i=0;i<Num_notifications;i++) left_todo[i]=-1;

  old = -1;
  while(old) {
    old=0;
    for(j=0;j<ifcount;j++) {
      for(i=0;i<Num_notifications;i++) {
        struct notification *ni = &Notification_table[i];
        if(_is_arp_cache(*ni)) {
        /* fetch arp cache and do that */
        old+=send_arp_spoof_arp_cache(&lVIF[j], ni, arpcache, &left_todo[i]);
        } else {
        old+=send_arp_spoof_netblock(&lVIF[j], ni, &left_todo[i]);
        }
      }
    }
    usleep(1000000); /* 1 second */
  }
  Alarm(PRINT, "finished notification thread for virtual entry");
#ifndef DONT_USE_THREADS
  _ve_wait(*VE);
  VE->notifier = 0;
  _ve_post(*VE);
  pthread_exit(0);
#endif
  return (void *)0;
}
#endif

/* RWC: new version of arp_spoof_notifier, to work with events.
 * Treat code as a boolean representing whether or not this is the first time
 * the function has been called since the spoofer was invoked, and data as a
 * virtual entry. */
void arp_spoof_notifier( int code, void *data ) {
  int i, j, old;
  entry *VE = (entry *)data;
  sp_time sleep_time = { 1, 0 }; /* One second. */

  if( !code ) {
    /* how many VIPs we got? */
    if(_pif_ip_s(*VE)) {
      memcpy(&(VE->arp_spoof_data.lVIF[VE->arp_spoof_data.ifcount]),
             &(VE->pseudo_if), sizeof(struct interface) );
      VE->arp_spoof_data.ifcount++;
    }
    for(i=0;(i<MAX_PSEUDO) && _eif_ip_s(*VE, i);i++) {
      memcpy(&(VE->arp_spoof_data.lVIF[VE->arp_spoof_data.ifcount]), 
             &(VE->extra_ifs[i]), sizeof(struct interface) );
      VE->arp_spoof_data.ifcount++;
    }

    for(i=0;i<Num_notifications;i++) VE->arp_spoof_data.left_todo[i]=-1;
  }

  old = 0;
  for( j = 0; j < VE->arp_spoof_data.ifcount; j++ ) {
    for( i = 0; i < Num_notifications; i++ ) {
      struct notification *ni = &Notification_table[i];
      if(_is_arp_cache(*ni)) {
        /* fetch arp cache and do that */
        old+=send_arp_spoof_arp_cache( &(VE->arp_spoof_data.lVIF[j]), ni,
                                       VE->arp_spoof_data.arpcache,
                                       &(VE->arp_spoof_data.left_todo[i]) );
      } else {
        old+=send_arp_spoof_netblock( &(VE->arp_spoof_data.lVIF[j]), ni,
                                      &(VE->arp_spoof_data.left_todo[i]) );
      }
    }
  }

  if( old ) {
    E_queue( arp_spoof_notifier, 1, VE, sleep_time );
    Alarm( PRINT, "Re-queued arp spoof notifier for virtual entry." );
  } else {
    Alarm( PRINT, "Finished arp spoof notification for virtual entry." );
  }
}
/* end RWC */

#define cidrsize(a) (0xffffffff - ((a).netmask.s_addr) + 1)

unsigned int calc_new_cidr(struct interface *i1, struct interface *i2,
               struct interface *out) {
  unsigned int s1, s2, e1, e2;
  s1 = _if_ip_s(*i1) & _if_nm_s(*i1);
  e1 = _if_ip_s(*i1) | (~(_if_nm_s(*i1)));
  s2 = _if_ip_s(*i2) & _if_nm_s(*i2);
  e2 = _if_ip_s(*i2) | (~(_if_nm_s(*i2)));
  s1 = MAX(s1,s2);
  e1 = MIN(e1,e2);
  if(e1<s1) {
    return 0;
  }
  _if_ip_s(*out) = s1;
  strcpy(out->ifname, i1->ifname);
  return e1-s1+1;
}
int send_arp_spoof_arp_cache(struct interface *i, struct notification *n,
                       address *ac, int *count) {
  /* Send notification about i to n */
  int s, c;
  struct interface arpi, dest;
  address *acp = ac;
Alarm(ARPING, "Count: %d", *count);
  if(*count == -1) {
    *count = 0;
    while(*acp) { acp++; (*count)++; }
  }
Alarm(ARPING, "Count: %d", *count);
  if(*count == 0) return 0;
  arpi.ifname[0]='\0';
  arpi.netmask.s_addr = ~0;
  for(s=0,c=0;s<*count && (!n->throttle || (c<n->throttle));s++) {
    if(ac[s] == 0) continue;
    arpi.ipaddr.s_addr = ac[s];
    if(calc_new_cidr(i, &arpi, &dest)) {
      /* This arp entry can be delivered for this vip */
Alarm(ARPING, "Spoofing (from arp): %s:%s", i->ifname, inet_ntoa(dest.ipaddr));
      if_send_spoof_request(i->ifname,
                      htonl(_if_ip_s(*i)), htonl(_if_ip_s(dest)),
                      2);
      /* Zero out this entry so we ignore it if there is another round */
      /* this is a _copy_ of the shared arp cache.. so, we can mutilate it */
      ac[s] = 0;
      c++;
    }
  }
  return c;
}
int send_arp_spoof_netblock(struct interface *i, struct notification *n,
                      int *count) {
  /* Send notification about i to n */
  struct interface newcidr;
  unsigned int csize, c, s;

  if(*count == 0) return 0;
  csize = calc_new_cidr(i, &(n->destination), &newcidr);
  if(strcmp(i->ifname, n->destination.ifname)) {
    return 0;
  }
  if(newcidr.ifname[0] == '\0') return 0;
  if(*count == -1) *count = csize;
  _if_ip_s(newcidr)+=(csize-*count);
  for(s=0,c=(csize-*count);(c<csize) && (!n->throttle || (s<n->throttle));c++) {
    if_send_spoof_request(i->ifname,
                    htonl(_if_ip_s(*i)), htonl(_if_ip_s(newcidr)),
                    2);
    _if_ip_s(newcidr)++;
    s++;
    (*count)--;
  }
  return s;
}

Generated by  Doxygen 1.6.0   Back to index