/*
 * 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 "../include/packit.h" 
#include "../include/inject.h"
#include "../include/error.h"


libnet_t *packet_d;

void
injection_stats()
{
    struct libnet_stats ln_stats;

    libnet_stats(packet_d, &ln_stats);

    fprintf(stdout, "-| Packet Injection Statistics |-"
		    "---------------------"
		    "----------------------"
		    "\n");

    fprintf(stdout,
        "Packet(s) sent: %ld  "
        "Packet errors: %ld  "
        "Bytes written: %ld  ",
        ln_stats.packets_sent, ln_stats.packet_errors, ln_stats.bytes_written);

    fprintf(stdout, "\n");

    return;
}

void
enter_packet_foundry(short init_type, unsigned int count)
{
    unsigned int p_count;
    int port_range = 0;

#ifdef __DEBUG
    fprintf(stderr, "DEBUG: enter_packet_foundry() INIT_TYPE: %d  COUNT: %d\n", init_type, count);
#endif

    header_len = 0;
    
    signal(SIGTERM, injection_clean_exit);
    signal(SIGINT, injection_clean_exit);
    signal(SIGQUIT, injection_clean_exit);
    signal(SIGHUP, injection_clean_exit);

    fprintf(stdout, "Mode:  Packet Injection\n\n");

    if(burst > BURST_MAX)
    {
        fprintf(stderr, "\nError: Maximum burst rate is %d\n", BURST_MAX);
        exit(FAILURE);
    }

    if(payload != NULL)
        payload_len = strlen(payload); 

    if((packet_d = libnet_init(init_type, device, errbuf)) == NULL)
    {
        fprintf(stderr, "\nError: Unable to initialize packet injection\n");
        exit(FAILURE);
    }

    if(s_dport != NULL && strstr(s_dport, ":"))
    {
	count = parse_port_range(s_dport);

        if(count < 1)
	{
	    fprintf(stderr, "\nError: Invalid port range: %s\n", s_dport);
	    exit(FAILURE);
	}

	port_range = 1;
    }
    else
    {
        dport = (int)atoi(s_dport);
    }

    for(p_count = 1; p_count < count + 1; p_count++)
    {
        switch(injection_type)
        {
            case ETHERTYPE_IP:
#ifdef __DEBUG
    fprintf(stderr, "DEBUG: Injecting IP traffic\n");
#endif
	        switch(ip4hdr_o.ip_proto)
	        {
		    case IPPROTO_TCP:
                        packet_d = build_tcp_hdr(packet_d);
	 	        break;
 
 		    case IPPROTO_UDP:
                        packet_d = build_udp_hdr(packet_d);
		        break;

		    case IPPROTO_ICMP:
                        packet_d = build_icmpv4_hdr(packet_d);
		        break;
	        }

                packet_d = build_ipv4_hdr(packet_d);
	        break;

	    case ETHERTYPE_ARP: 
#ifdef __DEBUG
    fprintf(stderr, "DEBUG: Injecting ARP traffic\n");
#endif
		packet_d = build_arp_hdr(packet_d);
	        break;
        }

        if(ehdr_o.s_addr || ehdr_o.d_addr)
            packet_d = build_ethernet_hdr(packet_d);
	else if(injection_type == ETHERTYPE_ARP)
            packet_d = build_ethernet_hdr_auto(packet_d);

        if(p_count == 1)
            print_injection(init_type, count);

        if(libnet_write(packet_d) == -1)
        {
            fprintf(stderr, "\nError: Unable to write packet to network\n");
            exit(FAILURE); 
        }

        /* we shouldn't have to use this */
        libnet_clear_packet(packet_d);

        if(burst && count > 1 && (p_count % burst) == 0)
	{ 
            fprintf(stderr, ".");
            sleep(interval);
	}
        else if(!burst && count > 1 && count != p_count)
	{
	    fprintf(stderr, "."); 
            sleep(interval);
	}
	else if(count == 1)
	{
	    fprintf(stderr, ".");
        }

	if(port_range)
	    dport++;
    }

#ifdef __DEBUG
    fprintf(stderr, "DEBUG: Preparing to clean house and exit\n");
#endif

    injection_clean_exit(EXIT_SUCCESS);

    return;
}

void
injection_clean_exit(int sig)
{
    fprintf(stdout, "\n\n");

    injection_stats();
    libnet_destroy(packet_d);

    fprintf(stdout, "\n");

#ifdef __DEBUG
    fprintf(stderr, "DEBUG: Good-Bye\n");
#endif

    exit(FAILURE);

    return;
}
