/*
 * 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 *
build_icmpv4_hdr(libnet_t *packet_d)
{
    unsigned char ih_payload[8];
    unsigned int ih_payload_len = 8;
    unsigned int ihn_gw, ihn_mask, ihn_saddr, ihn_daddr;
    unsigned int orig_hlen = PACKIT_IPV4_H + PACKIT_ICMPV4_H;

#ifdef __DEBUG
    fprintf(stderr, "DEBUG: build_icmpv4_hdr(): TYPE: %d  CODE: %d\n", i4hdr_o.ih_type, i4hdr_o.ih_code);
#endif

    switch(i4hdr_o.ih_type)
    {
        case ICMP_ECHOREPLY: case ICMP_ECHO: default:
#ifdef __DEBUG
            fprintf(stderr, "DEBUG: Building ICMP echo header\n");
#endif

            header_len = PACKIT_ICMPV4_ECHO_H;

            if(libnet_build_icmpv4_echo(
	        i4hdr_o.ih_type,
	        i4hdr_o.ih_code,
	        0,
	        i4hdr_o.ih_id,
	        i4hdr_o.ih_seq,
	        payload,
	        payload_len,
	        packet_d,
	        0) == -1)
	    {
	        fprintf(stderr, "\nError: Unable to build ICMPv4 echo header: %s\n", libnet_geterror(packet_d));
	        exit(FAILURE);
	    }

            break;

	case ICMP_UNREACH: case ICMP_REDIRECT: case ICMP_TIMXCEED:
            if(i4hdr_o.ih_proto == IPPROTO_TCP)
	        orig_hlen = PACKIT_IPV4_H + PACKIT_TCP_H;
	    else if(i4hdr_o.ih_proto == IPPROTO_UDP)
                orig_hlen = PACKIT_IPV4_H + PACKIT_UDP_H;
            else if(i4hdr_o.ih_proto == IPPROTO_ICMP)
	        orig_hlen = PACKIT_IPV4_H + PACKIT_ICMPV4_H;

	    if(i4hdr_o.ih_rand_saddr)
                i4hdr_o.ih_saddr = retrieve_rand_ipv4_addr();

            if(i4hdr_o.ih_rand_daddr)
		i4hdr_o.ih_daddr = retrieve_rand_ipv4_addr();

            if(i4hdr_o.ih_saddr == NULL)
	    {
	        fprintf(stderr, "\nError: No original source IP address defined\n");
	        exit(FAILURE);
	    }

	    if((ihn_saddr = libnet_name2addr4(packet_d, i4hdr_o.ih_saddr, 1)) == -1)
            {
	        fprintf(stderr, "\nError: Invalid original source IP address: %s\n", i4hdr_o.ih_saddr);
		exit(FAILURE);
            }

	    if(i4hdr_o.ih_daddr == NULL)
	    {
	        fprintf(stderr, "\nError: No original destination IP address defined\n");
	        exit(FAILURE);
	    }

	    if((ihn_daddr = libnet_name2addr4(packet_d, i4hdr_o.ih_daddr, 1)) == -1)
	    {
	        fprintf(stderr, "\nError: Invalid original destination IP address: %s\n", i4hdr_o.ih_daddr);
	        exit(FAILURE);
	    }

            ih_payload[0] = (i4hdr_o.ih_sport >> 8) & 0xff;
	    ih_payload[1] = i4hdr_o.ih_sport & 0xff;
	    ih_payload[2] = (i4hdr_o.ih_dport >> 8) & 0xff;
	    ih_payload[3] = i4hdr_o.ih_dport & 0xff;
	    ih_payload[4] = 0;
	    ih_payload[5] = 32;
	    ih_payload[6] = 0;
	    ih_payload[7] = 0; 

            ih_payload_len = 8;

	    if(i4hdr_o.ih_type == ICMP_UNREACH)
	    {
#ifdef __DEBUG
                fprintf(stderr, "DEBUG: Building ICMP unreachable header\n");
#endif

                header_len = PACKIT_ICMPV4_UNREACH_H;

                if(libnet_build_icmpv4_unreach(
                    i4hdr_o.ih_type,
                    i4hdr_o.ih_code,
                    0,
	            orig_hlen,
	            i4hdr_o.ih_tos,	
                    i4hdr_o.ih_id,
                    0,
                    i4hdr_o.ih_ttl,
                    i4hdr_o.ih_proto,
                    i4hdr_o.ih_sum,
                    ihn_saddr,
                    ihn_daddr,
                    ih_payload,
                    ih_payload_len,
                    packet_d,
                    0) == -1)
                {
                    fprintf(stderr, "\nError: Unable to build ICMPv4 unreach header: %s\n", libnet_geterror(packet_d));
	            exit(FAILURE);
	        }
            }
	    else if(i4hdr_o.ih_type == ICMP_REDIRECT)
	    { 
#ifdef __DEBUG
                fprintf(stderr, "DEBUG: Building ICMP redirect header\n");
#endif

		header_len = PACKIT_ICMPV4_REDIRECT_H;

                if(i4hdr_o.ih_rand_gw)
	            i4hdr_o.ih_gw = retrieve_rand_ipv4_addr();

                if(i4hdr_o.ih_gw == NULL)
	        {
	            fprintf(stderr, "\nError: No gateway IP address defined\n");
	            exit(FAILURE);
	        }

                if((ihn_gw = libnet_name2addr4(packet_d, i4hdr_o.ih_gw, 1)) == -1)
	        {
	            fprintf(stderr, "\nError: Invalid gateway IP address: %s\n", i4hdr_o.ih_gw);
		    exit(FAILURE);
                }

 	        if(libnet_build_icmpv4_redirect(
	            i4hdr_o.ih_type,
	            i4hdr_o.ih_code,
	            0,
	            ihn_gw,
	            orig_hlen, 
	            i4hdr_o.ih_tos,
	            i4hdr_o.ih_id,
	            0,
	            i4hdr_o.ih_ttl,
	            i4hdr_o.ih_proto,
	            i4hdr_o.ih_sum,
                    ihn_saddr,
	            ihn_daddr,
	            ih_payload,
	            ih_payload_len,
	            packet_d,
	            0) == -1)
 	        {
	            fprintf(stderr, "\nError: Unable to build ICMPv4 redirect header: %s\n", libnet_geterror(packet_d));
	            exit(FAILURE);
	        }
	    }
            else if(i4hdr_o.ih_type == ICMP_TIMXCEED)
	    {
#ifdef __DEBUG
                fprintf(stderr, "DEBUG: Building ICMP timelimit exceeded header\n");
#endif

                header_len = PACKIT_ICMPV4_TIMXCEED_H;

                if(libnet_build_icmpv4_timeexceed(
                    i4hdr_o.ih_type,
	            i4hdr_o.ih_code,
                    0,
	            orig_hlen,
	            i4hdr_o.ih_tos,
	            i4hdr_o.ih_id,
	            0,
                    i4hdr_o.ih_ttl,
	            i4hdr_o.ih_proto, 
	            i4hdr_o.ih_sum,
	            ihn_saddr,
	            ihn_daddr,
	            ih_payload,
	            ih_payload_len,
	            packet_d,
	            0) == -1)
	        {
	            fprintf(stderr, "\nError: Unable to build ICMPv4 timeexceed header: %s\n", libnet_geterror(packet_d));
	            exit(FAILURE);
	        }
	    }

            break;

        case ICMP_TSTAMP: case ICMP_TSTAMPREPLY:
#ifdef __DEBUG
            fprintf(stderr, "DEBUG: Building ICMP timestamp header\n");
#endif

            header_len = PACKIT_ICMPV4_TS_H;

            if(libnet_build_icmpv4_timestamp(
                i4hdr_o.ih_type,
                i4hdr_o.ih_code,
                0,
		i4hdr_o.ih_id,
		i4hdr_o.ih_seq,
		i4hdr_o.ih_otime,
		i4hdr_o.ih_rtime,
		i4hdr_o.ih_ttime,
		payload,
		payload_len,
		packet_d,
		0) == -1)
	    {
		fprintf(stderr, "\nError: Unable to build ICMPv4 timestamp header: %s\n", libnet_geterror(packet_d));
		exit(FAILURE);
	    }
				   
            break;

        case ICMP_MASKREQ: case ICMP_MASKREPLY:
#ifdef __DEBUG
            fprintf(stderr, "DEBUG: Building ICMP mask header\n");
#endif

	    if((ihn_mask = libnet_name2addr4(packet_d, i4hdr_o.ih_mask, 1)) == -1)
	    {
	        fprintf(stderr, "\nError: Invalid mask address: %s\n", i4hdr_o.ih_mask);
	        exit(FAILURE);
	    }

            header_len = PACKIT_ICMPV4_MASK_H;

	    if(libnet_build_icmpv4_mask(
	        i4hdr_o.ih_type,
	        i4hdr_o.ih_code,
	        0,
	        i4hdr_o.ih_id,
	        i4hdr_o.ih_seq,
		ihn_mask, 
	        payload,
	        payload_len,
	        packet_d,
	        0) == -1)
	    {
	        fprintf(stderr, "\nError: Unable to build ICMPv4 mask header: %s\n", libnet_geterror(packet_d));
	        exit(FAILURE);
	    }

            break;
    }

    return packet_d; 
}

