#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pscan.h"

extern char *outfilename;
extern short outfiletype;
extern unsigned long wait_time;
extern unsigned long num_instances;
extern unsigned long IP;
extern char *targethostname;
extern unsigned short total_open;
extern unsigned short total_scanned;
extern int options;
extern FILE *pfo;
static FILE *out = NULL;	// general outpout file descriptor, expected to assume values stdout or pfo

// tags for html output
char TR[10];
char ENDTR[10];
char TD[10];
char ENDTD[10];
char BR[10];

void print_config_core(FILE *);
void print_general_html();
void print_general_xml();
void print_config_xml();
void print_config_html();
void print_port_core(unsigned short, char *, port_response, FILE *);
void print_port_xml(unsigned short, char *, port_response, FILE *);
void print_port_html(unsigned short, char *, port_response, FILE *);
void print_totals_core(unsigned long, FILE *);
void print_totals_xml(unsigned long, FILE *);
void print_totals_html(unsigned long, FILE *);
void print_mac_xml(char *);
void print_end_xml();
void print_end_html();

void output_init()
{
	if(outfilename)
	{
		if((pfo = fopen(outfilename, "w")) == NULL)
		{
			fprintf(stderr, "Unable to open file \"%s\" for output\n", outfilename);
			exit(0);
		}
		out = pfo;
	}
	else
		out = stdout;


	if( (outfilename  &&  ((outfiletype == TEXTFILE) ||  (outfiletype == XMLFILE)))
		||  (!outfilename))
	{
		strcpy(TR, "");
		strcpy(ENDTR, "");
		strcpy(TD, "");
		strcpy(ENDTD, "");
		strcpy(BR, "\n");
	}
	else if(outfiletype == HTMLFILE)
	{
		strcpy(TR, "<tr>");
		strcpy(ENDTR, "</tr>");
		strcpy(TD, "<td>");
		strcpy(ENDTD, "</td>");
		strcpy(BR, "<br>\n");
	}
}


// this one goes to stdout only
void print_help()
{	
	fprintf(stdout, "Usage: portscanner <IP> or <hostname> [options]\n");
	fprintf(stdout, "Options:\n");
	fprintf(stdout, "\t-p <start>-<end>\tStarting and ending port\n\t\t\t(default: only frequent ports - check readme)\n");
	fprintf(stdout, "\tOR -p <port_list>\tPorts list with commas\n\t\t\t(list can contain start-end, like -p 25,80,132-139,144)\n");
	fprintf(stdout, "\t-s \t\tPerform a SYN scan. Default is Connect scan\n");
	fprintf(stdout, "\t-n <inst>\tNumber of simultaneous TCP port scan instances\n\t\t\t(default: 10)\n"); 
	fprintf(stdout, "\t-w <time>\tMax waiting time for each port in milliseconds, only\n\t\t\tfor Connect scans (default: 1000)\n");
	fprintf(stdout, "\t-a\t\tReport all ports (OPEN, CLOSED and TIMEDOUT)\n");
	fprintf(stdout, "\t-r\t\tDon't resolve ports to known services. Default: resolve\n");
	fprintf(stdout, "\t-M\t\tMAC lookup of remote IP\n");
	fprintf(stdout, "\t-h\t\tHide on-fly port displaying. Ignored with all -o options\n");
	fprintf(stdout, "\t-o <filename>\tRedirect standard ASCII output to filename\n");
	fprintf(stdout, "\t-oh <filename>\tRedirect output to filename in HTML format\n");
	fprintf(stdout, "\t-ox <filename>\tRedirect output to filename in XML format\n");
	fprintf(stdout, "\nCommand line examples:\n");

	fprintf(stdout, "\t1- scans hostname.com in syn mode using default ports\n");
	fprintf(stdout, "\t./portscanner hostname.com -s\n\n");

	fprintf(stdout, "\t2- scans hostname.com in connect mode using default ports and wait\n\ttime 300 ms.\n");
	fprintf(stdout, "\t./portscanner hostname.com -w 300\n\n");

	fprintf(stdout, "\t3- scans all ports of hostname.com in syn mode\n");
	fprintf(stdout, "\t./portscanner hostname.com -p 1-65535 -s\n\n");

	fprintf(stdout, "\t4- scans ports from 1250 to 3500 of hostname.com in syn mode; output\n\tto html file\n");
	fprintf(stdout, "\t./portscanner hostname.com -p 1250-3500 -s -oh outfile.html\n\n");

	fprintf(stdout, "\t5- scans default ports of the ip address in connect mode; uses 20\n\tinstances, wait time 300 ms., does MAC lookup, prints results at end\n");
	fprintf(stdout, "\t./portscanner 192.168.1.1 -n 20 -w 300 -M -h\n\n");

	fprintf(stdout, "\t6- scans all ports of the ip address in connect mode; uses 20\n\tinstances, wait time 300 ms., MAC lookup, outputs results for all ports\n\tto a txt file\n");
	fprintf(stdout, "\t./portscanner 192.168.1.1 -p 1-65535 -n 20 -w 300 -M -a -o outfile.txt\n\n");
}



void print_general(FILE *out)
{
	fprintf(out, "#\n");
	fprintf(out, "SecPoint Port scanner   (c) www.SecPoint.com\nv. %s\n", PSCAN_VERSION);
	fprintf(out, "The Portable Penetrator - Wifi Recovery - Vulnerability Scanner\n");
	fprintf(out, "http://www.secpoint.com/portable-penetrator.html \n\n");
}

// this one goes to output file only
void print_general_to_file()
{
	if(outfiletype == TEXTFILE)
		print_general(pfo);
	else if(outfiletype == XMLFILE)
		print_general_xml();
	else	// HTMLFILE
		print_general_html();
}

void print_general_xml()
{
	fprintf(out, "<?xml version=\"1.0\"?>\n");
	fprintf(out, "<!-- SecPoint Port scanner   (c) www.SecPoint.com\n");
	fprintf(out, "     v. %s\n", PSCAN_VERSION);
	fprintf(out, "     The Portable Penetrator - Wifi Recovery - Vulnerability Scanner\n");
  	fprintf(out, "     http://www.secpoint.com/portable-penetrator.html -->\n");
	fprintf(out, "<portscanner>\n");
}
void print_general_html()
{
	fprintf(out, "<html> <head>  \n");
	fprintf(out, "<title>SecPoint Port scanner (c)</title>  \n");
	fprintf(out, "</head>  \n");
	fprintf(out, "<body>  \n");
	fprintf(out, "<p><b><font face=\"Verdana\" size=\"2\">SecPoint Port scanner   (c)  \n");
	fprintf(out, "<a href=\"http://www.SecPoint.com\">www.SecPoint.com</a><br>v %s</b><br><br>  \n", PSCAN_VERSION);
	fprintf(out, "The Portable Penetrator - Wifi Recovery - Vulnerability Scanner<br>  \n");
	fprintf(out, "<a href=\"http://www.secpoint.com/portable-penetrator.html\">http://www.secpoint.com/portable-penetrator.html</a>  \n");
	fprintf(out, "<br><br>  \n");
}


void print_config()
{
	if( (outfilename  &&  outfiletype == TEXTFILE)  ||  (!outfilename))
		print_config_core(out);
	else if(outfiletype == XMLFILE)
		print_config_xml();
	else	// HTMLFILE
		print_config_html();
}	


void print_config_core(FILE *out)
{
	char *yes = "YES", *no = "NO";
	fprintf(out, "%sScanning IP: %s", BR, net_get_aip(IP));
	if(targethostname)	// we were given a hostname to resolve, not an IP, so we print it out
		fprintf(out, " (%s)", targethostname);
	fprintf(out, "%s", BR);
	if (!(options & OPTIONS_SYN_SCAN))
		fprintf(out, "Instances: %u, waiting time: %u%s", (unsigned int)num_instances, (unsigned int)wait_time, BR);
	fprintf(out, "Syn scan: %s%sReport all ports: %s, Resolve ports: %s%sMAC lookup: %s, Hide on-fly port displaying: %s%s%s", 
		options & OPTIONS_SYN_SCAN ? yes : no, BR,
		options & OPTIONS_ALL_PORTS ? yes : no, 
		options & OPTIONS_DONT_RESOLVE_PORTS ? no : yes, BR,
		options & OPTIONS_RESOLVE_MAC ? yes : no,
		options & OPTIONS_ONFLY_HIDE ? yes : no, BR, BR);
}

void print_config_xml()
{
	char *yes = "YES", *no = "NO";
 	fprintf(out, " <host>\n");
	fprintf(out, "  <address addr=\"%s\" addrtype=\"ipv4\"/>\n", net_get_aip(IP));
	if(targethostname)		// same as before
		fprintf(out, "  <hostname name=\"%s\"/>\n", targethostname);
	fprintf(out, "  <scaninfo\n");
	if (!(options & OPTIONS_SYN_SCAN))
	 	fprintf(out, "            instances=\"%u\" waitingtime=\"%u\" synscan=\"%s\"\n",
					(unsigned int)num_instances, (unsigned int)wait_time, (options & OPTIONS_SYN_SCAN ? yes : no) );
 	fprintf(out, "            reportallports=\"%s\" resolveports=\"%s\" maclookup=\"%s\" hideonfly=\"%s\"/>\n",
					options & OPTIONS_ALL_PORTS ? yes : no,
					options & OPTIONS_DONT_RESOLVE_PORTS ? no : yes,
					options & OPTIONS_RESOLVE_MAC ? yes : no,
					options & OPTIONS_ONFLY_HIDE ? yes : no);

	fprintf(out, "  <ports>\n");
}
void print_config_html()
{
	print_config_core(out);
	fprintf(out, "</font>\n");
	fprintf(out, "<table border=\"1\" width=\"100%%\" cellspacing=\"0\" cellpadding=\"2\">   \n");
	fprintf(out, "<tr style=\"font-family: Verdana; color: #FFFFFF; font-weight: bold; font-size: 10pt; background-color: #000080\">     \n");
	fprintf(out, "<td>Port</td>  \n<td>Status</td>  \n<td>Service</td>  \n</tr>\n");
}


void print_port(unsigned short port, char *service_str, port_response status)
{
	if( (outfilename  &&  outfiletype == TEXTFILE)  ||  (!outfilename))
		print_port_core(port, service_str, status, out);
	else if(outfiletype == XMLFILE)
		print_port_xml(port, service_str, status, out);
	else	// HTMLFILE
		print_port_html(port, service_str, status, out);

}

void print_port_core(unsigned short port, char *service_str, port_response status, FILE *out)
{
	char *srvstr = (service_str ? service_str : "");
	fprintf(out, "%s%u/tcp%s %s%s%s  %s%s%s%s\n", 
			TD, port, ENDTD, TD, (status==OPEN ? "open" : (status==CLOSED ? "closed" : "timeout" )),
			ENDTD, TD, srvstr, ENDTD, ENDTR);
}

void print_port_xml(unsigned short port, char *service_str, port_response status, FILE *out)
{
	fprintf(out, "   <port protocol=\"tcp\" portid=\"%u\">\n", port);
	fprintf(out, "    <state state=\"%s\"/>\n", (status==OPEN ? "open" : (status==CLOSED ? "closed" : "timeout" )));
	fprintf(out, "    <service name=\"%s\"/>\n", service_str);
	fprintf(out, "   </port>\n");
}

void print_port_html(unsigned short port, char *service_str, port_response status, FILE *out)
{
	fprintf(out, "<tr style=\"font-family: Verdana; font-size: 10pt; \">  \n");
	print_port_core(port, service_str, status, out);
}

void print_totals(unsigned long time)
{
	if( (outfilename  &&  outfiletype == TEXTFILE)  ||  (!outfilename))
		print_totals_core(time, out);
	else if(outfiletype == XMLFILE)
		print_totals_xml(time, out);
	else	// HTMLFILE
		print_totals_html(time, out);
}


void print_totals_core(unsigned long time, FILE *out)
{
	fprintf(out, "%sTotal ports scanned: %d%sTotal ports open: %d%s", BR, total_scanned, BR, total_open, BR);

	if(time/1000 <= 60)
		fprintf(out, "Scan time: %u.%03u seconds%s%s", (unsigned int)(time / 1000), (unsigned int)(time % 1000), BR, BR);
	else
		fprintf(out, "Scan time: %u minutes, %u seconds%s%s", 
			(unsigned int)(time / 60000), (unsigned int)((time % 60000)/1000), BR, BR);
}

void print_totals_xml(unsigned long time, FILE *out)
{
	fprintf(out, "  </ports>\n");
	fprintf(out, " </host>\n");
	fprintf(out, " <runstats>\n");
	fprintf(out, "  <finished nscanned=\"%d\" nopen=\"%d\" elapsed=\"%u.%03u\" exit=\"success\"/>\n",  
		total_scanned, total_open, (unsigned int)(time / 1000), (unsigned int)(time % 1000));
	fprintf(out, " </runstats>\n");
}

void print_totals_html(unsigned long time, FILE *out)
{
	fprintf(out, "</table>\n\n");
	fprintf(out, "<font face=\"Verdana\" size=\"2\">");
	print_totals_core(time, out);
}

void print_mac(char *string)
{
	if( (outfilename  &&  ((outfiletype == TEXTFILE) ||  (outfiletype == HTMLFILE)))
		||  (!outfilename))
	fprintf(out, string);
	else	// XMLFILE
		print_mac_xml(string);
}

void print_mac_xml(char *string)
{
	fprintf(out, "  <macdata>\n");
	fprintf(out, "    <macinfo summary=\"%s\"\n", string);
	fprintf(out, "/>\n");
	fprintf(out, "  </macdata>\n");
}

void output_end()
{
	if(outfilename  &&  outfiletype == XMLFILE)
		print_end_xml();
	else if(outfilename  &&  outfiletype == HTMLFILE)
		print_end_html();

	if(outfilename  && pfo)
		fclose(pfo);
}

void print_end_xml()
{
	fprintf(out, "</portscanner>\n");
}

void print_end_html()
{
	fprintf(out, "</font>\n</body>\n</html>\n");
}
