hackedteam/vector-ipa

View on GitHub
src/match_users_dhcp.c

Summary

Maintainability
Test Coverage
/*
    MODULE -- Module to match an user based on radius packets

    Copyright (C) Alberto Ornaghi

    $Id: match_users_dhcp.c 2653 2010-07-06 07:31:19Z alor $
*/

#include <main.h>
#include <hook.h>
#include <packet.h>

#include <match.h>
#include <match_users.h>
#include <dhcp.h>

/* global vars */

struct dhcp_node {
   char tag[MAX_TAG_LEN];
   char mac[ETH_ASCII_ADDR_LEN];
   LIST_ENTRY (dhcp_node) next;
};

static LIST_HEAD(, dhcp_node) dhcp_root;
static pthread_mutex_t dhcp_mutex = PTHREAD_MUTEX_INITIALIZER;

/* proto */

void match_user_dhcp_add(char *value, char *tag);
void match_user_dhcp_clear(void);
struct dhcp_node * find_dhcp_user(char *mac);
void dissector_dhcp(struct packet_object *po);

/*******************************************/

void match_user_dhcp_add(char *value, char *tag)
{
   struct dhcp_node *e;

   /*
    * remove the hook. we must do this because we are called on every reload list.
    * otherwise the hook will be setup multiple time
    */
   hook_del(HOOK_PACKET_UDP, dissector_dhcp);

   /* add the hook on UDP packet, this will pass us all the DHCP packets to look into */
   hook_add(HOOK_PACKET_UDP, dissector_dhcp);

   /* create the element for the list */
   SAFE_CALLOC(e, 1, sizeof(struct dhcp_node));

   snprintf(e->tag, MAX_TAG_LEN-1, "%s", tag);
   snprintf(e->mac, ETH_ASCII_ADDR_LEN-1, "%s", value);

   pthread_mutex_lock(&dhcp_mutex);
   LIST_INSERT_HEAD(&dhcp_root, e, next);
   pthread_mutex_unlock(&dhcp_mutex);
}


void match_user_dhcp_clear(void)
{
   struct dhcp_node *e, *tmp;

   pthread_mutex_lock(&dhcp_mutex);

   /* remove all the elements */
   LIST_FOREACH_SAFE(e, &dhcp_root, next, tmp) {
      LIST_REMOVE(e, next);
      SAFE_FREE(e);
   }

   pthread_mutex_unlock(&dhcp_mutex);
}


struct dhcp_node * find_dhcp_user(char *mac)
{
   struct dhcp_node *e;

   pthread_mutex_lock(&dhcp_mutex);

   /* search into the list */
   LIST_FOREACH(e, &dhcp_root, next) {
      if (match_pattern(mac, e->mac)) {
         pthread_mutex_unlock(&dhcp_mutex);
         return e;
      }
   }

   pthread_mutex_unlock(&dhcp_mutex);

   return NULL;
}


void dissector_dhcp(struct packet_object *po)
{
   struct dhcp_header *dhcp;
   struct ip_addr ip;
   struct dhcp_node *e;
   struct timeval tv;
   u_char *data = po->DATA.data;
   u_char *end = po->DATA.data + po->DATA.len;
   u_char *options, *opt;
   char tmp[MAX_ASCII_ADDR_LEN];
   char mac[ETH_ASCII_ADDR_LEN];

   /* packet is not dhcp */
   if (ntohs(po->L4.dst) != 68)
      return;

   /* sanity check */
   if (po->DATA.len < sizeof(struct dhcp_header))
      return;

   DEBUG_MSG(D_VERBOSE, "dissector_dhcp");

   /* cast the header and options */
   dhcp = (struct dhcp_header *)data;
   options = (u_char *)(dhcp + 1);

   /* check for the magic cookie */
   if (dhcp->magic != htonl(DHCP_MAGIC_COOKIE))
      return;

   /* servers only send replies */
   if (dhcp->op != BOOTREPLY)
      return;

   /* search the "message type" option */
   if ((opt = dhcp_get_option(DHCP_OPT_MSG_TYPE, options, end)) == NULL)
      return;

   /*
    * we are interested only in DHCP ACK replies from the server.
    * we take this and parse the address release to the client
    */
   if (*(opt + 1) != DHCP_ACK)
      return;

   /* get the client mac address */
   mac_addr_ntoa(dhcp->chaddr, mac);

   DEBUG_MSG(D_EXCESSIVE, "DHCP mac: [%s]", mac);

   /* search if the mac address belongs to our targets */
   if ((e = find_dhcp_user(mac)) == NULL)
      return;

   /* get the assigned ip */
   ip_addr_init(&ip, AF_INET, (u_char *)&dhcp->yiaddr);

   DEBUG_MSG(D_INFO, "DHCP TARGET DISCOVERED [%s] [%s] [%s]", e->tag, mac, ip_addr_ntoa(&ip, tmp));

   gettimeofday(&tv, NULL);
   active_user_add(&ip, NULL, e->tag, tv);
}

/* EOF */

// vim:ts=3:expandtab