/*
 ============================================================================
 Name        : fuzz.c
 Author      : Andrew Dunn, Sean Enck
 Version     : 1.0
 Copyright   : 2009
 Description : Generating random input for program continuity testing
 ============================================================================
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include <time.h>

// Function Prototypes
void parseInput(int , char **);
void execInput();
void printCharset(int , int , int , int );
void printUsage();
void printHelp();

// Defines
#define TRUE 1
#define FALSE 0
#define MAXOUTPUT 320000

// Global Variables
static int verboseInput;
int printable;
int allascii;
int lrand;
int number = 0;
int delay = 0;

/* * * * * * * * * * *
 * Method: main
 * Purpose: Verify arguments and call for input parsing and execution
 * Parameters:
 *	argc - number of arguments
 *	argv - arguments
 * * * * * * * * * * */
int main(int argc, char **argv) {
	if( argc < 2) {
		printUsage();
		return EXIT_SUCCESS;
	}
	//call to parse and then execute based on input
	parseInput(argc, argv);
	execInput();
	return EXIT_SUCCESS;
}

/* * * * * * * * * * *
 * Method: parseInput
 * Purpose: Use getopt to pull out the command line arguments for the fuzzer
 * Parameters:
 *	argc - number of arguments
 *	argv - arguments
 * * * * * * * * * * */
void parseInput(int argc, char **argv) {
	
	//argument struct
	static struct option longOptions[] =
    {
        {"verbose", 	no_argument,       	&verboseInput, 1},
        {"brief",   	no_argument,       	&verboseInput, 0},
        {"help",  		no_argument,	 	0, 'h'},
        {"printable",  	no_argument,       	0, 'p'},
        {"allascii",  	no_argument, 		0, 'a'},
        {"lrand",  		no_argument, 		0, 'l'},
        {"number",  	required_argument, 	0, 'n'},
        {"delay",    	required_argument, 	0, 'd'},
        {0, 0, 0, 0}
    };

	int optionIndex = 0;
	char opt_char = 0;

	// Parse Input
	while ((opt_char = getopt_long(argc, argv, "hpaln:d:", longOptions, &optionIndex)) != -1) {
		switch(opt_char) {
			case 0:
			   if (longOptions[optionIndex].flag != 0)
				 break;
			   printf ("option %s", longOptions[optionIndex].name);
			   if (optarg)
				 printf (" with arg %s", optarg);
			   printf ("\n");
			   break;
			case 'p':
				printable = TRUE;
				break;
			case 'a':
				allascii = TRUE;
				break;
			case 'n':
				number = atoi(optarg);
				break;
			case 'l':
				lrand = TRUE;
				break;
			case 'd':
				delay = atoi(optarg);
				break;
			case 'h':
				printHelp();
				exit(EXIT_SUCCESS);
				break;
			default:
				printHelp();
				exit(EXIT_SUCCESS);
				break;
		}
	}
}

/* * * * * * * * * * *
 * Method: execInput
 * Purpose: Execute the fuzzing based on the parsed input
 * Parameters: none
 * * * * * * * * * * */
void execInput() {
	//check for a valid input amount
	if(number <= 0) {
		printHelp();
		exit(EXIT_SUCCESS);
	}
	if(number > MAXOUTPUT) {
		printf("Usage: Cannot Print out more than 320000 characters");
		exit(EXIT_SUCCESS);
	}
	else if(printable) {
		printCharset((int)number, 32, 94, (int)delay);
		allascii = FALSE;
	}
	else if(allascii) {
		printCharset((int)number, 0, 255, (int)delay);
	}
}

/* * * * * * * * * * *
 * Method: printCharset
 * Purpose: Execute the fuzzing based on the parsed input
 * Parameters:
 *	length - the number of characters to print
 *	lowBound - the ascii low bound for characters
 *	highBound - the ascii high bound for characters
 *	waitTime - the amount of time to wait between characters
 * * * * * * * * * * */
void printCharset(int length, int lowBound, int highBound, int waitTime) {
	int iterator;
	
	//go through and make each of the characters
	for(iterator = 0; iterator < length; iterator++) {
	   srand((unsigned int)time(NULL) + rand());
	   int randVal = rand();
	   randVal = randVal % highBound;
	   randVal = randVal + lowBound;

		//is there a specified waiting period?
	   if(waitTime > 0) {
		   sleep(waitTime);
	   }

		//random newlines if specified
	   if(lrand == TRUE) {
		   if(randVal % 10 == FALSE) {
			   printf("\n");
		   }
	   }

		//print and flush character
	   printf("%c", (char)randVal);
	   fflush(stdout);
	}
}

/* * * * * * * * * * *
 * Method: printHelp
 * Purpose: Print the expanded help information
 * Parameters: none
 * * * * * * * * * * */
void printHelp() {
	printUsage();
	printf("\n\nFuzz is meant to generate random input for use in testing security");
	printf("\n\n Arguments:");
	printf("\n-n <n>, --number <n>\t\tThe length of output fuzz is to create");
	printf("\n-p, --printable\t\t\tCreate only printable ASCII characters");
	printf("\n-a, --allascii\t\t\tCreate all ASCII characters");
	printf("\n-l, --lrand\t\t\tCreate random length lines (\\n terminated strings)");
	printf("\n-d <n>, --delay <n>\t\tDelay <n> seconds following each character");
	printf("\n");
}

/* * * * * * * * * * *
 * Method: printUsage
 * Purpose: Print a generic usage statement
 * Parameters: none
 * * * * * * * * * * */
void printUsage() {
	printf("\nUsage: fuzz -n <FUZZLENGTH> -<ARGUMENTS>");
	printf("\nTry 'fuzz --help' for more information");
	printf("\n");
}

