/*
 * author: Darren Bounds <dbounds@intrusense.com>
 * copyright: Copyright (C) 2002 by Darren Bounds
 * license: This software is under GPL version 2 of license
 *
 * 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
 *
 * packit official page at http://packit.sourceforge.net
 */

#include <time.h>

#include "../include/packit.h" 
#include "../include/inject.h"
#include "../include/error.h"


unsigned char *
retrieve_rand_ethernet_addr()
{
    int oct, oct_count;
    static int seed;
    unsigned char *eaddr;

#ifdef __DEBUG
    fprintf(stderr, "DEBUG: retrieve_rand_ethernet_addr()\n");
#endif

    eaddr = malloc(sizeof(unsigned char) * 18);

   for(oct_count = 1; oct_count < 7; oct_count++)
   {
       seed++;
       srand(time(0) ^ getpid() * seed);
       oct = rand() % 255;

       if(oct_count != 1)
           sprintf(eaddr, "%s:%0x", eaddr, oct);
       else
           sprintf(eaddr, "%0x", oct);
   }

    return eaddr;
}


libnet_t *
build_ethernet_hdr(libnet_t *packet_d)
{
    int i;
    unsigned char us_addr[6];
    unsigned char ud_addr[6];
	
    struct libnet_ether_addr *hw_addr;

#ifdef __DEBUG
    fprintf(stderr, "DEBUG: build_ethernet_hdr()\n");
#endif

    if(ehdr_o.eh_rand_saddr)
        ehdr_o.s_addr = retrieve_rand_ethernet_addr();

    if(ehdr_o.eh_rand_daddr)
        ehdr_o.d_addr = retrieve_rand_ethernet_addr();

    if(ehdr_o.s_addr == NULL)
    {
        if((hw_addr = libnet_get_hwaddr(packet_d)) == NULL)
        {
            fprintf(stderr, "\nError: Unable to determine ethernet address: %s\n", libnet_geterror(packet_d));
            exit(FAILURE);
        }

	for(i = 0; i < 6; i++)
	    us_addr[i] = hw_addr->ether_addr_octet[i];
    }
    else
    {
        if(format_ethernet_addr(ehdr_o.s_addr, us_addr) == 0)
        {
            fprintf(stderr, "\nError: Invalid source ethernet address\n");
            exit(FAILURE);
        }
    }
    
    snprintf(ehdr_o.shw_addr, 18, "%0X:%0X:%0X:%0X:%0X:%0X",
        us_addr[0], us_addr[1], us_addr[2], us_addr[3], us_addr[4], us_addr[5]);

    if(ehdr_o.d_addr == NULL && injection_type == ETHERTYPE_ARP)
	ehdr_o.d_addr = ETH_BROADCAST; 
    else if(ehdr_o.d_addr == NULL)
	ehdr_o.d_addr = ETH_DEFAULT;

    if(format_ethernet_addr(ehdr_o.d_addr, ud_addr) == 0)
    {
        fprintf(stderr, "\nError: Invalid destination ethernet address\n");
        exit(FAILURE);
    }

    snprintf(ehdr_o.dhw_addr, 18, "%0X:%0X:%0X:%0X:%0X:%0X",
        ud_addr[0], ud_addr[1], ud_addr[2], ud_addr[3], ud_addr[4], ud_addr[5]);

    if(libnet_build_ethernet(
        ud_addr,
        us_addr,
        injection_type,
        NULL,
        0,
        packet_d,
        0) == -1)
    {
        fprintf(stderr, "\nError: Unable to build Ethernet header: %s\n", libnet_geterror(packet_d));
        exit(FAILURE);
    }

    return packet_d;
}

libnet_t *
build_ethernet_hdr_auto(libnet_t *packet_d)
{
    unsigned char d_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

#ifdef __DEBUG
    fprintf(stderr, "DEBUG: build_ethernet_hdr_auto()\n");
#endif

    if(libnet_autobuild_ethernet(
        d_addr,                 
        ETHERTYPE_ARP, 
        packet_d) == -1)
    {
	fprintf(stderr, "\nError: Unable to auto build Ethernet header: %s\n", libnet_geterror(packet_d));
	exit(FAILURE);
    }
		
    return packet_d;
}

int
format_ethernet_addr(char *ethstr, unsigned char u_eaddr[6])
{
    int i = 0;
    long base16;
    char *eptr, *delim = ":";
    char o_ethstr[18] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; 
   
#ifdef __DEBUG
    fprintf(stderr, "DEBUG: format_ethernet_addr()\n");
#endif

    if(ethstr)
    {
	strncpy(o_ethstr, ethstr, 18);
    }
    else
    {
	u_eaddr = o_ethstr;
        return 1;
    }

    for(eptr = strtok(o_ethstr, delim);
         eptr;
         eptr = strtok(NULL, delim))
    {
        if((base16 = strtol(eptr, 0, 16)) > 0xff)
	    return 0;	

        u_eaddr[i] = base16;
        i++;
    }

    if(i != 6)
        return 0;    

    ethstr = o_ethstr;

    return 1; 
}
