#!/usr/bin/python

#
# This is a draft of script that is testing nmap's functions coverage.
# I tried to create as many tests as possible to cover as many function
# as possible.
#
# I assume that you have computer with ethernet connection :)
#
#
# Most of my test are against localhost.
#
# You should also run something like this:
#  ### for i in `seq 2 255`; do ip addr add 127.0.0.$i/8 dev lo; done
# to create many localhost ip's to test whole network scanning.
#
# I run nmap by typing "sudo ./nmap", but you should change this to fit
# your needs.
#
#
# Oh, and you should also have your nmap compiled with options "-g -pg -ftest-coverage -fprofile-arcs"
# on newer nmap after "./configure" you can just type "make debug"
#
#
#



import sys
import string
import time
import os
import socket
import struct
import signal
import re

# Some host that you have direct connection
eth_host = "192.168.1.1"
eth_network = "192.168.1.1/24"
# Your ethernet interface
ethlo_iface = "eth0"


# This computer's ethernet ip
ethlo_host = "192.168.1.4"

#
test_dir = "/home/majek/n/aa/src"
tmp_file = "/tmp/trash"

#
out1 = "/tmp/nmap-out1"
out2 = "/tmp/nmap-out2"

#
sudo = "sudo "

home = os.environ["HOME"]
user = os.environ["USER"]
nmap = "./nmap"
prefix = "localhost -T5 -vvv -d22 --datadir=" + home + "/.nmap"


nmap_tests = [
	"-sS -e lo -S 127.1.1.1 -p22",
	"-sS --stylesheet http://www.insecure.org/nmap/data/nmap.xsl -oS " + tmp_file,
	"-min-parallelism 100 --max-parallelism 900 -sS --host-timeout 900000 --max-retries 2 --min_rtt_timeout 10 --max-rtt-timeout 100 --initial-rtt-timeout 20 --min-hostgroup 300 --max-hostgroup 301 -n 127.0.0.1/24 --osscan-guess -p21,22",
	"--scan-delay 30 --max-scan-delay 22 -sS --host-timeout 1501 --max-retries 2 --min_rtt_timeout 10 --max-rtt-timeout 100 --initial-rtt-timeout 20 --min-hostgroup 300 --max-hostgroup 301 -n 127.0.0.1/24 --osscan-guess -p21,22",
	"2>/dev/null; echo -e 'n -sS -T5 localhost'|"+sudo+" "+nmap+" --interactive 2>/dev/null;echo 1",
	"-sS -p0,1,22,80,443 -A scanme.insecure.org",
	"-sI "+ethlo_host+" "+eth_host+" -p 0,1,2,22,25,443 -PR",
	"-sS -e "+ethlo_iface+" -S "+ethlo_host+" "+eth_host,
	"-sS -O -sR",
	"-sT -g 9999",
	"-sU -g 9999",
	"-sO -F",
	"-sO",
	"--scanflags URGACKPSHRSTSYNFI -p1,2,22,80,443",
	"-sS -n localhost/24 -iR 6 --exclude 127.0.0.1,127.0.0.2 --excludefile "+test_dir+"/test-inputhostname -p1,2,3,4,55,33,22",
	"-sP -n localhost/24 --exclude 127.0.0.1/26 --randomize-hosts",
	"-h",
	"-sS -PS80,22,1,2,3,4,5,443 -p 22,1,2,3,4,5,443,80",
	"-sS -O -sR -sV -pT:1,22,80 -C",
	"--iflist",
	"-sS -F",
	"-sS -f",
	"-sS -e lo",
	"-sS --spoof-mac 00:01:02:03:04:05",
	"-sS -oN " + tmp_file,
	"-sS -p 1,22,80 -send-eth " + ethlo_iface + " " + eth_host,
	"-R -sP -PR 127.0.0.1/27",
	"127.0.0.2 127.0.0.1 --scan_delay 1 --max_scan_delay 2 -P0 -sS -p1,22 -O",
	"2>/dev/null;"+sudo+" "+nmap+" -T5 -sS -p 80 "+eth_network,
	"2>/dev/null;"+sudo+" "+nmap+" -T5 -sS -p 80 195.136.32.1",
	]

def unused_funs(printfuns):
	
	os.popen(sudo +"chown "+user+" *.gcda "+out1+" "+out2+" "+tmp_file+"* ")
	for filename in os.listdir("."):
		if filename.endswith(".cc"):
			os.popen("gcov -lfb "+filename+" >/dev/null")
	
	grp = os.popen("grep -n \"^function \" *.cc.gcov","r")

	## utils.cc.gcov:537:function _Z10gcd_n_uintiPj called 4 returned 100% blocks executed 91%
	pat = re.compile(r'^(.*).gcov:([0-9]+):function (.*) called ([0-9]+) ')
	lfilename = ""
	llineno   = 0
	lfunction = ""
	lcalledno = 0
	allno = 0
	allyes = 0
	for line in grp:
		a = pat.findall(line)
		for b in a:
			filename = b[0]
			lineno   = int(b[1])
			function = b[2]
			calledno = int(b[3])

			if filename == lfilename and (lineno-1) == llineno:
				lcalledno += calledno
				calledno = lcalledno
			if lcalledno == 0:
				fu=os.popen("c++filt \""+lfunction+"\"|tr \" \" \"_\"")
				fun = fu.read()[:-1]
				if printfuns==True:
					print lfilename+"\t"+fun
				allno+=1
			allyes += 1


			lfilename = filename
			llineno   = lineno
			lfunction = function
			lcalledno = calledno

	print "NR:"+`allno` +"/"+ `allyes`



def do_nmap_test(nmap, options, prefix):
	print "****** Testing:  ", nmap + " " + options
	cmd = "sh -c \""+sudo + nmap + " " + prefix + " "  + options + " >"+out1+" 2>"+out2+" \""
	run = os.popen(cmd, "r")
	run.read()
	ret = run.close()
	if ret != None:
		print "Command failed, watch exit files "+out1+" and "+out2
		print "CMD: " +cmd
		os.abort()


all = True
if len(sys.argv) > 1:
	param = int(sys.argv[1])
	all = False

if all or param == 1:
	os.popen("rm -f *.gcda ")

	for test in nmap_tests:
		do_nmap_test(nmap, test, prefix)
		unused_funs(False)

if all or param == 2:
	unused_funs(True)




#	os.popen("rm -f *.gcda "+out1+" "+out2+" "+tmp_file+"* ")
