cardif_linux.c

来自「linux 下通过802.1认证的安装包」· C语言 代码 · 共 1,995 行 · 第 1/4 页

C
1,995
字号
/**
 * Linux card interface implementation.
 *
 * Licensed under a dual GPL/BSD license.  (See LICENSE file for more info.)
 *
 * File: cardif_linux.c
 *
 * Authors: Chris.Hessing@utah.edu
 *
 * $Id: cardif_linux.c,v 1.140.2.30 2007/07/21 11:39:12 cgrohmann Exp $
 * $Date: 2007/07/21 11:39:12 $
 *
 **/

#ifdef LINUX_FRAMER

#define _GNU_SOURCE

#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/compiler.h>
#include <iwlib.h>
#include <linux/if_packet.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <linux/rtnetlink.h>
#include <string.h>

#include "wireless_copy.h"
#include "xsupconfig.h"
#include "context.h"
#include "config_ssid.h"
#include "cardif/linux/cardif_linux_wext.h"
#include "cardif/cardif.h"
#include "xsup_common.h"
#include "xsup_debug.h"
#include "xsup_err.h"
#include "snmp.h"
#include "statemachine.h"
#include "wireless_sm.h"
#include "cardif/linux/cardif_linux.h"
#include "cardif/linux/cardif_linux_rtnetlink.h"
#include "ipc_events.h"
#include "ipc_events_index.h"
#include "timer.h"
#include "event_core.h"
#include "eapol.h"
#include "interfaces.h"

#ifdef USE_EFENCE
#include <efence.h>
#endif

#ifndef ETH_P_EAPOL
#define ETH_P_EAPOL 0x888e
#endif

// Define this, so the compiler doesn't complain.
extern unsigned int if_nametoindex(const char *);

// This contains a pointer to the functions needed for wireless.  
struct cardif_funcs *wireless;

// Store values about what state our interface was in before we start messing
// with it.
struct int_starting_data *startup;

/**
 * \brief Get the MAC address of an interface based on it's name.
 *
 * @param[in] intname   A string that contains the interface name that we
 *                      want to get the MAC address for.
 *
 * @param[out] intmac   The interface MAC address of the interface named by
 *                      intname.
 *
 * \retval XEGENERROR on general error
 * \retval XENONE on success
 **/
int get_mac_by_name(char *intname, char *intmac)
{
  struct ifreq ifr;
  struct lin_sock_data *sockData = NULL;
  int retval = XENONE;
  context *ctx = NULL;
 
  if (!xsup_assert((ctx != NULL), "ctx != NULL", FALSE))
    return XEMALLOC;

  ctx = event_core_get_active_ctx();

  sockData = ctx->sockData;

  memset(&ifr, 0x00, sizeof(ifr));

  if (strlen(intname) == 0)
    {
      debug_printf(DEBUG_NORMAL, "Invalid interface name in %s():%d\n",
		   __FUNCTION__, __LINE__);
      return XEGENERROR;
    }

  ifr.ifr_ifindex = if_nametoindex(intname);

  // Tell the ifreq struct which interface we want to use.
  Strncpy((char *)&ifr.ifr_name, sizeof(ifr.ifr_name), intname, strlen(intname)+1);

  // Get our MAC address.
  retval = ioctl(sockData->sockInt, SIOCGIFHWADDR, &ifr);
  if (retval < 0)
    {
      debug_printf(DEBUG_NORMAL, "Error getting hardware (MAC) address for "
		   "interface %s!\n", intname);
      debug_printf(DEBUG_NORMAL, "Error was (%d) : %s\n", errno, strerror(errno));
    }

  memcpy(intmac, (char *)&ifr.ifr_hwaddr.sa_data[0], 6);

  return XENONE;
}

/**
 * Clear all keys, and accept unencrypted traffic again.
 *
 * @param[in] ctx   The context that contains the interface that we want
 *                  to allow unencrypted traffic on again.
 **/
void cardif_linux_clear_keys(context *ctx)
{
  int i;

  if (!xsup_assert((ctx != NULL), "ctx != NULL", FALSE))
    return;

  debug_printf(DEBUG_INT, "Clearing keys!\n");

  debug_printf(DEBUG_INT, "Allowing unencrypted frames again.\n");
  cardif_drop_unencrypted(ctx, 0);
  
  // Clear the PTK.
  debug_printf(DEBUG_INT, "Clearing PTK.\n");
  cardif_delete_key(ctx, 0, 1);

  for (i=0;i<4;i++)
    {
      debug_printf(DEBUG_INT, "Clearing key index %d.\n", i);
      cardif_delete_key(ctx, i, 0);
    }

  cardif_linux_wext_enc_disable(ctx);
}

/**
 * \brief Determine if we are currently associated. 
 *
 * @param[in] ctx   The context that contains the interface that we want to
 *                  check the association status on.
 *
 * \retval XEMALLOC on error
 * \retval IS_UNASSOCIATED when the interface isn't associated
 * \retval IS_ASSOCIATED when the interface is associated
 **/
int cardif_check_associated(context *ctx)
{
  char newmac[6], curbssid[6];

  if (!xsup_assert((ctx != NULL), "ctx != NULL", FALSE))
    return XEMALLOC;

  // If we are wired, this function doesn't do anything useful.
  if (ctx->intType != ETH_802_11_INT) return XENONE;

  cardif_GetBSSID(ctx, curbssid);

  memset(newmac, 0x00, 6);
  if (memcmp(newmac, curbssid, 6) == 0)
    {
      return IS_UNASSOCIATED;
    }

  memset(newmac, 0x44, 6);
  if (memcmp(newmac, curbssid, 6) == 0)
    {
      return IS_UNASSOCIATED;
    }

  memset(newmac, 0xFF, 6);
  if (memcmp(newmac, curbssid, 6) == 0)
    {
      return IS_UNASSOCIATED;
    }

  //Otherwise, we are associated.
  return IS_ASSOCIATED;
}

/**
 * \brief Set up the wireless cardif_funcs structure to the driver that the 
 *        user has requested.
 *
 * @param[in] driver   A number that identifies the driver that we want to use.
 **/
void cardif_set_driver(char driver)
{
  switch (driver)
    {
    case DRIVER_NONE:
      wireless = NULL;
      break;

    default:
    case DRIVER_WEXT:
      wireless = &cardif_linux_wext_driver;
      break;
    }
}

/**
 * \breif Initialize an interface.
 *
 * Do whatever is needed to get the interface in to a state that we can send
 * and recieve frames on the network.  Any information that we need to later
 * use should be stored in the context structure.
 *
 * @param[in] ctx   The context that contains enough information for us to
 *                  init the interface.
 * @param[in] driver   A number that identifies the driver that this card is
 *                     using.
 *
 * \retval XEMALLOC on memory allocation error
 * \retval XEGENERROR on general error
 * \retval XENONE on success
 **/
int cardif_init(context *ctx, char driver)
{
  struct ifreq ifr;
  struct lin_sock_data *sockData;
  int retval;
  struct config_globals *globals;

  if (!xsup_assert((ctx != NULL), "ctx != NULL", FALSE))
    return XEMALLOC;

  // Get the information about the global settings from the config file.
  globals = config_get_globals();

  if (!xsup_assert((globals != NULL), "globals != NULL", FALSE))
    return XEGENERROR;

  debug_printf(DEBUG_INT, "Initializing socket for interface %s..\n",
	       ctx->intName);

  // Keep track of which driver we were assigned.
#warning The below needs to be moved to the wireless context init function!
  //  ctx->driver_in_use = driver;

  // Allocate memory for the things we need.
  ctx->sockData = (void *)Malloc(sizeof(struct lin_sock_data));
  if (ctx->sockData == NULL)
    {
      debug_printf(DEBUG_NORMAL, "Error allocating memory!\n");
      return XEMALLOC;
    }

  sockData = ctx->sockData;

  // Establish a socket handle.
  sockData->sockInt = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_EAPOL));
  if (sockData->sockInt < 0)
    {
      debug_printf(DEBUG_NORMAL, 
		   "Couldn't initialize raw socket for interface %s!\n",
		   ctx->intName);
      return XENOSOCK;
    }        

  // Build our link layer socket struct, so we can bind it to a specific
  // interface.
  sockData->sll.sll_family = PF_PACKET;
  sockData->sll.sll_ifindex = if_nametoindex(ctx->intName);
  sockData->sll.sll_protocol = htons(ETH_P_EAPOL);

  // Bind to the interface.
  retval = bind(sockData->sockInt, (const struct sockaddr *)&sockData->sll, 
		sizeof(struct sockaddr_ll));
  if (retval < 0)
    {
      debug_printf(DEBUG_NORMAL, "Error binding raw socket to interface %s!\n",
		   ctx->intName);
      return XESOCKOP;
    }

  memset(&ifr, 0x00, sizeof(ifr));

  if (strlen(ctx->intName) == 0)
    {
      debug_printf(DEBUG_NORMAL, "Invalid interface name in %s():%d\n",
                   __FUNCTION__, __LINE__);
      return XEGENERROR;
    }

  ifr.ifr_ifindex = if_nametoindex(ctx->intName);

  // Tell the ifreq struct which interface we want to use.
  Strncpy((char *)&ifr.ifr_name, sizeof(ifr.ifr_name), ctx->intName, 
	  strlen(ctx->intName)+1);

  // Get our MAC address.  (Needed for sending frames out correctly.)
  retval = ioctl(sockData->sockInt, SIOCGIFHWADDR, &ifr);
  if (retval < 0)
    {
      debug_printf(DEBUG_NORMAL, "Error getting hardware (MAC) address for interface %s!\n",
		   ctx->intName);
      debug_printf(DEBUG_NORMAL, "Error was (%d) : %s\n", errno, strerror(errno)); 
      return XENOTINT;
    }

  // Store a copy of our source MAC for later use.
  memcpy((char *)&ctx->source_mac[0], (char *)&ifr.ifr_hwaddr.sa_data[0], 6);

  // Check if we want ALLMULTI mode, and enable it.
  if (TEST_FLAG(globals->flags, CONFIG_GLOBALS_ALLMULTI))
    {
      if (strlen(ctx->intName) == 0)
        {
          debug_printf(DEBUG_NORMAL, "Invalid interface name in %s():%d\n",
                       __FUNCTION__, __LINE__);
          return XEGENERROR;
        }

      // Tell the ifreq struct which interface we want to use.
      Strncpy((char *)&ifr.ifr_name, sizeof(ifr.ifr_name), ctx->intName, 
	      strlen(ctx->intName)+1);

      if (ioctl(sockData->sockInt, SIOCGIFFLAGS, &ifr) < 0)
	{
	  debug_printf(DEBUG_NORMAL, "Couldn't determine if ALLMULTI is enabled!\n");
	} else {
	  if (ifr.ifr_flags & IFF_ALLMULTI)
	    {
	      debug_printf(DEBUG_INT, "Allmulti mode is already enabled on this device!\n");
	      ctx->flags |= ALLMULTI;
	    } else {
	      debug_printf(DEBUG_INT, "Allmulti is currently disabled on this device!\n");
	      ctx->flags &= ~ALLMULTI;
	    }
	}

      debug_printf(DEBUG_INT, "Turning on ALLMULTI mode.\n");
      ifr.ifr_flags |= IFF_ALLMULTI;
      if (ioctl(sockData->sockInt, SIOCSIFFLAGS, &ifr) < 0)
	{
	  debug_printf(DEBUG_NORMAL, "Couldn't set ALLMULTI mode on this interface!  We will continue anyway!\n");
	}
    }

  // Set up wireless card drivers.
  cardif_set_driver(driver);

  if (cardif_int_is_wireless(ctx) == TRUE)
    {
      debug_printf(DEBUG_INT, "Interface is wireless.\n");
      ctx->intType = ETH_802_11_INT;

      if (context_create_wireless_ctx((wireless_ctx **)&ctx->intTypeData, 0) != XENONE)
	{
	  debug_printf(DEBUG_NORMAL, "Couldn't create wireless context for "
		       "interface!\n");
	  ipc_events_error(ctx, IPC_EVENT_ERROR_CANT_CREATE_WIRELESS_CTX, ctx->desc);
	  return -1;
	}

      // If we have our destination set to AUTO, then preset our destination
      // address.
      if (globals->destination == DEST_AUTO)
	{
	  cardif_GetBSSID(ctx, ctx->dest_mac);
	}
      ctx->intType = ETH_802_11_INT;
    }

  ctx->sendframe = Malloc(FRAMESIZE);
  if (ctx->sendframe == NULL)
    {
      debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to store frames "
		   "to be sent.\n");
      return XEMALLOC;
    }

  // Initialize our rtnetlink event handler.
  cardif_linux_rtnetlink_init(ctx);

  event_core_register(cardif_get_socket(ctx), ctx, eapol_withframe,
                      LOW_PRIORITY, "frame handler");
	  
  return XENONE;
}

/**
 * \brief Tell the wireless card to start scanning for wireless networks.
 *
 * @param[in] ctx   The context that contains the interface that we want to
 *                  start scanning for networks.
 * @param[in] passive  TRUE if we want to do a passive scan.
 *
 * \retval XEMALLOC on memory allocation error
 * \retval XENONE on success (or nothing to do)
 **/
int cardif_do_wireless_scan(context *ctx, char passive)
{
  wireless_ctx *wctx = NULL;

  if (!xsup_assert((ctx != NULL), "ctx != NULL", FALSE))
    return XEMALLOC;

  if (!xsup_assert((ctx->intTypeData != NULL), "ctx->intTypeData != NULL",
		   FALSE))
    return XEMALLOC;

  if (wireless == NULL) 
    {
      debug_printf(DEBUG_INT, "No valid wireless calls struct! (%s:%d)\n",
		   __FUNCTION__, __LINE__);
      return XEMALLOC;
    }

  if (wireless->scan == NULL)
    {
      debug_printf(DEBUG_NORMAL, "No scan function defined!\n");
      return XEMALLOC;
    }

  wctx = (wireless_ctx *)ctx->intTypeData;

  // If we are already scanning, then we shouldn't get here, but go ahead 
  // and ignore it anyway.
  if (TEST_FLAG(wctx->flags, WIRELESS_SCANNING) )
    {
      debug_printf(DEBUG_INT, "Got a request to start a new scan when one is"
		   " already in progress!  Ignoring!\n");
      return XENONE;
    }

  SET_FLAG(wctx->flags, WIRELESS_SCANNING);
  config_ssid_clear(wctx);

  return wireless->scan(ctx, passive);
}

/**
 * \brief Send a disassociate message.
 *
 * @param[in] ctx   The context that contains the interface that we want
 *                  to send a disassociate message with.
 * @param[in] reason_code   The reason for the disassociation. (Reason codes
 *                          are specified in the 802.11 standards.)
 *
 * \retval XEMALLOC on memory allocation error
 * \retval XENONE on success
 **/
int cardif_disassociate(context *ctx, int reason_code)
{
  if (!xsup_assert((ctx != NULL), "ctx != NULL", FALSE))
    return XEMALLOC;

  if (wireless == NULL) return XEMALLOC;

  if (wireless->disassociate == NULL) return XEMALLOC;

  debug_printf(DEBUG_INT, "Called %s\n", __FUNCTION__);
  return wireless->disassociate(ctx, reason_code);
}

/**
 * \brief Return the socket number for functions that need it.
 *
 * @param[in] ctx   The context that contains the socket number we are
 *                  looking for.
 *
 * \retval XEMALLOC on memory allocation error
 * \retval XENONE on success
 **/
int cardif_get_socket(context *ctx)
{
  struct lin_sock_data *sockData;

  if (!xsup_assert((ctx != NULL), "ctx != NULL", FALSE))
    return XEMALLOC;

  sockData = ctx->sockData;

  return sockData->sockInt;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?