#!/usr/bin/env python3

#IMPORTING REQUIRED LIBRARIES
#from datetime import datetime
#from time import time
#from funcy import flatten
from numpy import array
from sys import argv, platform
from colorama import init, Fore
from os import popen, path, remove
from subprocess import call
import socket, getopt, logging as log

try:
	#SETTING UP A COLOR SCHEME FOR BETTER VISUALISATION
	init()
	BLUE = Fore.BLUE   		#FOR MARKING THE SUCCESSFUL STARTING AND COMPLETION OF THE PROGRAM
	RED = Fore.RED	   		#FOR MARKING STARTING/ENDING OF AN EVENT OR AN ERROR
	GREEN = Fore.GREEN 		#FOR MARKING A SUCCESSFUL HOST/PORT DISCOVERY AND HELP MENU
	RESET = Fore.RESET		#FOR RESETTING TO DEFAULT SHELL COLOR
	GRAY = Fore.LIGHTBLACK_EX	#FOR MARKING AN UNSUCCESSFUL HOST/PORT DISCOVERY IN VERBOSE MODE
	YELLOW = Fore.YELLOW		#FOR MARKING DEBUGGING STATEMENTS
	
	#SETTING UP A LOGGING SYSTEM
	log.basicConfig(level = log.INFO, format = '  %(message)s', handlers = [log.FileHandler('temp.log'), log.StreamHandler()])
	
	#SETTING UP OS-SPECIFIC COMMANDS
	if platform == 'win32': PRINT = 'type'
	else: PRINT = 'cat'
    
	#CHECKING WHETHER DEDMAP IS INSTALLED OR NOT
	INSTALLED = platform == 'win32' or path.exists('/usr/share/dedmap/') or path.exists('/data/data/com.termux/files/usr/share/dedmap/')
	print()
	
	#GRAPHICS/TEXT ART
	def graphics():
		if INSTALLED: call('pyfiglet -c RED dedmap -f Bloody', shell = True)
		else: call('figlet -f fonts/Bloody.flf dedmap', shell = True)
		
	#DARK-WEB SWITCH
	def dark(): print(f"\n{YELLOW}Dark-Web Mode Activated!{RESET}\n")
	
	#FUNCTION TO SAVE THE OUTPUT TO A FILE
	def out():
		if "--out" in options: 
			print(f'\n{GREEN}Writing the output to {options["--out"]}{RESET}\n')
			call(f'{PRINT} temp.log >> {options["--out"]}.dedmap', shell = True)
		try: remove('temp.log')
		except: print(f'\n{RED}Can\'t remove the temp.log file. Remove it manually before next use.{RESET}')

	#DEFINED A HELP FUNCTION TO OUTPUT USAGE INSTRUCTIONS
	def help(): print(GREEN + """
DEDMAP ( https://7Ragnarok7.github.io/DEDMAP )

Usage: dedmap [--option(s)] [target(s)]

By default, a tcp scan will be performed if no options are provided.
-t option must be exclusively provided if any other option is used like -p or -v or -n.
By default, the top 100 commonly used ports will be scanned if no ports are specified.
Long Options (--<options>) have more priority.

Options:
-h, --help              show this help message and exit
-s, --silent		run in silent mode (remove the dedmap banner)
-b, --black		turn on dark-web mode
-v, --verbose           run in verbose mode
-d, --dns               performs a dns lookup
-r, --rdns              performs a reverse dns lookup
-p, --port<port(s)>     only scan specified port(s)
                        Ex: -p 21; -p 21,22,23;
                        -p top10; (scan top 10 commonly used ports)
                        -p top100; (scan top 100 commonly used ports)
                        -p top1000; (scan top 1000 commonly used ports)
                        -p system; (scan system ports from 0 to 1023)
                        -p user; (scan user ports from 1024 to 49151)
                        -p private; (scan private ports from 49152 to 65535)
                        -p all; (scan all ports from 0 to 65535)
-t, --tcp               perform a tcp scan (default scan if NO OPTIONS are specified)
-u, --udp               perform a udp scan (Dosen't seems to work using socket in python)
-n, --net             	perform a network scan
-m, --mode<wan/lan>     select the mode for network scan (default = wan)
                        Select lan mode(turbo mode) for better scanning speeds (upto 5x)
                        It is recommended to use the turbo mode only on a lan network
                        as it might result in loss of accuracy in wan networks
                        Ex: -nm lan; -nm wan;
-o, --out<filename>   	save the output to a file
                        Ex: -o report

Examples:               dedmap 1.1.1.1
                        dedmap localhost
                        dedmap -d google.com yahoo.com facebook.com localhost
                        dedmap google.com
                        dedmap google.com yahoo.com
                        dedmap 1.1.1.1 2.2.2.2 3.3.3.3
                        dedmap 1.1.1.1-100 google.com (Perform a tcp scan on all the hosts without pinging to bypass firewall icmp block)
                        dedmap -p 20 1.1.1.1
                        dedmap -p top10 2.2.2.2
                        dedmap -p 20,21,22 1.1.1.1
                        dedmap -nm lan -p 21 192.168.1.1-255 (Perform a tcp port scan in lan mode on all the live hosts)
                        dedmap -n 1.1.1.1-255
                        dedmap -nr 1.1.1.1-255 (Perform a dns lookup on all the live targets in the network)
                        dedmap -nt 1.1.1.0-255 (To scan only the hosts which are alive in the network)
                        dedmap -o report 127.0.0.1
""" + RESET)


	#DEFINED A FUNCTION FOR DEBUGGING
	def debug():
		print(YELLOW, targets, RESET)
		print(YELLOW, TARGET_LEN, RESET)
		print(YELLOW, options, RESET)
		print(YELLOW, OPTION_LEN, RESET)
		print(YELLOW, live_targets, RESET)
	
	
	#DESIGNED A FUNTION TO GIVE PRIORITY TO LONG-FORMAT ARGUMENTS
	def priority():
		for item in POSSIBLE_OPTIONS:
			if item in options and POSSIBLE_OPTIONS[item] in options: del(options[item])
			elif item in options: options[POSSIBLE_OPTIONS[item]] = options.pop(item)
		
	
	#DESIGNED AN ALGORITHM TO CONVERT IP-RANGE TO A LIST OF IP'S
	def convert(seperated, index):
		new_targets = []
		octets = seperated[0].split(".")
		new = [i for i in range(int(octets[3]), int(seperated[1]) + 1)]
		for i in new: new_targets.append(".".join([octets[0], octets[1], octets[2], str(i)]))	 
		targets[index] = new_targets
		
	
	#TCP/UDP SCANNER
	def scanner(ip, p, mode):
		global port_count
		if mode == "tcp": sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		else: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
		sock.settimeout(0.2)
		result = sock.connect_ex((ip, p))
		
		if not result:
			port_count += 1
			log.info(f"{GREEN}  PORT {p} ({TOP_100_PORTS[p] if p in TOP_100_PORTS else 'unknown'}) -->   OPEN   {RESET}")
		elif result and ("--verbose" in options or "--port" in options): print(f"{GRAY}  PORT {p} ({TOP_100_PORTS[p] if p in TOP_100_PORTS else 'unknown'})  -->   CLOSED   {RESET}")
		sock.close()	
	
	#TCP/UDP SCAN SELECTOR ***************
	def tcp_udp(mode, port_range = range(0, 0)):
		log.info(f"\n{RED}Performing a {mode} scan.....{RESET}\n")
		global port_count
		
		if "--net" in options:
			log.info(f"\n{GREEN}Found {len(live_targets)} live targets!\nScanning only the live hosts as a network scan was performed before.{RESET}")
			scan_targets = live_targets
		else:
			log.info(f"\n{RED}Scanning all {len(targets)} targets as no network scan was performed.{RESET}\n")
			scan_targets = targets.values()
			
		for ip in scan_targets:
			log.info(f"\n{RED}---------------- Scanning {SWAP_TARGETS[ip]} ({ip}) ---------------{RESET}\n")
			port_count = 0
		
			if len(ports): port_range = ports
				
			for p in port_range:
				if mode == "tcp" or mode == "udp": scanner(ip, p, mode)
				else:
					out()
					exit(f"\n{RED}Invalid scan option specified!{RESET}\n")
			if port_count: log.info(f"\n{GREEN}Found {port_count} out of {len(port_range)} ports open for the host: {SWAP_TARGETS[ip]}{RESET}\n")
	
	#MAIN SCAN CALLING FUNCTION ********
	def scan():
		
		#DNS LOOKUP
		if "--dns" in options: log.info(f"\n{RED}Performing a DNS lookup.....{RESET}\n\n{GREEN}{targets}{RESET}\n")
		
		#NETWORK SCAN
		if "--net" in options:
			log.info(f"\n{RED}Performing a network scan.....{RESET}\n")
			for ip in targets.values():
				if "--verbose" in options: print(f"{RED}Scanning {SWAP_TARGETS[ip]} .....{RESET}")
				if "--mode" not in options or options["--mode"] == "wan": response = popen(f"ping -b -c 1 -W 1 {ip}")
				elif options["--mode"] == "lan": response = popen(f"ping -b -c 1 -W 0.2 {ip}")
				else: exit(f"\n{RED}Invalid network scan mode specified!{RESET}\n")
				if "ttl" in response.readlines()[1].lower():
					log.info(f"{GREEN}{ip} --> Live{RESET}")
					live_targets.append(ip) #STORING ALL THE LIVE TARGETS
			log.info(f"\n{GREEN}{len(live_targets)} hosts alive out of {TARGET_LEN}{RESET}\n")
		
		
		#REVERSE-DNS LOOKUP
		if "--rdns" in options:
			log.info(f"\n{RED}Performing a REVERSE-DNS lookup.....{RESET}\n")
			if "--net" in options: hostnames = list(map(socket.gethostbyaddr, live_targets))
			else: hostnames = list(map(socket.gethostbyaddr, targets.values()))
			log.info(array(list(zip(hostnames, live_targets))))
			
		
		#TCP/UDP SCAN
		if "--tcp" in options or OPTION_LEN == 0: #MUST SPECIFY -t OPTION IN ANY OTHER OPTION IS GIVEN (EVEN -v)
			if "--port" not in options or options["--port"] == "top100": tcp_udp("tcp", TOP_100_PORTS.keys())
			elif options["--port"] == "top10": tcp_udp("tcp", TOP_10_PORTS)
			elif options["--port"] == "top1000": tcp_udp("tcp", TOP_1000_PORTS)
			elif options["--port"] == "system": tcp_udp("tcp", range(0, 1024))
			elif options["--port"] == "user": tcp_udp("tcp", range(1024, 49152))
			elif options["--port"] == "private": tcp_udp("tcp", range(49152, 65536))
			elif options["--port"] == "all": tcp_udp("tcp", range(0, 65536))
			elif len(ports) and "".join([str(i) for i in ports]).isdigit(): tcp_udp("tcp")
			else: print(f"{RED}\nInvalid port option specified!{RESET}\n")
			
		if "--udp" in options:
			if "--port" not in options or options["--port"] == "top100": tcp_udp("udp", TOP_100_PORTS.keys())
			elif options["--port"] == "top10": tcp_udp("udp", TOP_10_PORTS)
			elif options["--port"] == "top1000": tcp_udp("udp", TOP_1000_PORTS)
			elif options["--port"] == "system": tcp_udp("udp", range(0, 1024))
			elif options["--port"] == "user": tcp_udp("udp", range(1024, 49152))
			elif options["--port"] == "private": tcp_udp("udp", range(49152, 65536))
			elif options["--port"] == "all": tcp_udp("udp", range(0, 65536))
			elif len(ports) and "".join([str(i) for i in ports]).isdigit(): tcp_udp("udp")
			else: print(f"\n{RED}Invalid port option specified!{RESET}\n")
			
		
	#GETTING HOSTNAMES, IPs AND SCANNING PARAMETERS FORM SHELL ARGUMENTS
	options, targets = getopt.getopt(argv[1:], 'sbndrtuhvp:o:m:', ['silent', 'black', 'net', 'dns', 'rdns', 'tcp', 'udp', 'help', 'verbose', 'port=', 'out=', 'mode='])
	

	#CHECKING WHETHER THERE IS AN IP-RANGE OR NOT 
	for item in targets:
		if "-" in item:
			new = item.split("-")
			if "".join(new[0].split(".")).isdigit(): convert(new, targets.index(item))

	
	#VARIABLES
	from funcy import flatten
	targets = list(flatten(targets)) #CONVERTING NESTED LISTS RETURNED FROM CONVERT() TO NORMAL LISTS
	targets = dict(zip(targets, list(map(socket.gethostbyname, targets)))) #CONVERTING THE TARGETS INTO A DICTIONARY WITH THEIR RESPECTIVE IPs FOR BETTER ADDRESSING
	options = dict(options) #CONVERTING THE OPTIONS INTO A DICTIONARY FOR BETTER ADDRESSING
	ports = []
	live_targets = []
	
	#CONSTANTS
	POSSIBLE_OPTIONS = {"-s":"--silent", "-b":"--black", "-n":"--net", "-m":"--mode", "-d":"--dns", "-r":"--rdns", "-t":"--tcp", "-u":"--udp", "-h":"--help", "-v":"--verbose", "-p":"--port", "-o":"--out"}
	TARGET_LEN = len(targets)
	OPTION_LEN = len(options)
	SWAP_TARGETS = dict(zip(targets.values(), targets.keys())) #Same targets dictionary with keys and values swapped with each other
	
	TOP_1000_PORTS = [1,3,4,6,7,9,13,17,19,20,21,22,23,24,25,26,30,32,33,37,42,43,49,53,70,79,80,81,82,83,84,85,88,89,90,99,100,106,109,110,111,113,119,125,135,139,143,144,146,161,163,179,199,211,212,222,254,255,256,259,264,280,301,306,311,340,366,389,406,407,416,417,425,427,443,444,445,458,464,465,481,497,500,512,513,514,515,524,541,543,544,545,548,554,555,563,587,593,616,617,625,631,636,646,648,666,667,668,683,687,691,700,705,711,714,720,722,726,749,765,777,783,787,800,801,808,843,873,880,888,898,900,901,902,903,911,912,981,987,990,992,993,995,999,1000,1001,1002,1007,1009,1010,1011,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1102,1104,1105,1106,1107,1108,1110,1111,1112,1113,1114,1117,1119,1121,1122,1123,1124,1126,1130,1131,1132,1137,1138,1141,1145,1147,1148,1149,1151,1152,1154,1163,1164,1165,1166,1169,1174,1175,1183,1185,1186,1187,1192,1198,1199,1201,1213,1216,1217,1218,1233,1234,1236,1244,1247,1248,1259,1271,1272,1277,1287,1296,1300,1301,1309,1310,1311,1322,1328,1334,1352,1417,1433,1434,1443,1455,1461,1494,1500,1501,1503,1521,1524,1533,1556,1580,1583,1594,1600,1641,1658,1666,1687,1688,1700,1717,1718,1719,1720,1721,1723,1755,1761,1782,1783,1801,1805,1812,1839,1840,1862,1863,1864,1875,1900,1914,1935,1947,1971,1972,1974,1984,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2013,2020,2021,2022,2030,2033,2034,2035,2038,2040,2041,2042,2043,2045,2046,2047,2048,2049,2065,2068,2099,2100,2103,2105,2106,2107,2111,2119,2121,2126,2135,2144,2160,2161,2170,2179,2190,2191,2196,2200,2222,2251,2260,2288,2301,2323,2366,2381,2382,2383,2393,2394,2399,2401,2492,2500,2522,2525,2557,2601,2602,2604,2605,2607,2608,2638,2701,2702,2710,2717,2718,2725,2800,2809,2811,2869,2875,2909,2910,2920,2967,2968,2998,3000,3001,3003,3005,3006,3007,3011,3013,3017,3030,3031,3052,3071,3077,3128,3168,3211,3221,3260,3261,3268,3269,3283,3300,3301,3306,3322,3323,3324,3325,3333,3351,3367,3369,3370,3371,3372,3389,3390,3404,3476,3493,3517,3527,3546,3551,3580,3659,3689,3690,3703,3737,3766,3784,3800,3801,3809,3814,3826,3827,3828,3851,3869,3871,3878,3880,3889,3905,3914,3918,3920,3945,3971,3986,3995,3998,4000,4001,4002,4003,4004,4005,4006,4045,4111,4125,4126,4129,4224,4242,4279,4321,4343,4443,4444,4445,4446,4449,4550,4567,4662,4848,4899,4900,4998,5000,5001,5002,5003,5004,5009,5030,5033,5050,5051,5054,5060,5061,5080,5087,5100,5101,5102,5120,5190,5200,5214,5221,5222,5225,5226,5269,5280,5298,5357,5405,5414,5431,5432,5440,5500,5510,5544,5550,5555,5560,5566,5631,5633,5666,5678,5679,5718,5730,5800,5801,5802,5810,5811,5815,5822,5825,5850,5859,5862,5877,5900,5901,5902,5903,5904,5906,5907,5910,5911,5915,5922,5925,5950,5952,5959,5960,5961,5962,5963,5987,5988,5989,5998,5999,6000,6001,6002,6003,6004,6005,6006,6007,6009,6025,6059,6100,6101,6106,6112,6123,6129,6156,6346,6389,6502,6510,6543,6547,6565,6566,6567,6580,6646,6666,6667,6668,6669,6689,6692,6699,6779,6788,6789,6792,6839,6881,6901,6969,7000,7001,7002,7004,7007,7019,7025,7070,7100,7103,7106,7200,7201,7402,7435,7443,7496,7512,7625,7627,7676,7741,7777,7778,7800,7911,7920,7921,7937,7938,7999,8000,8001,8002,8007,8008,8009,8010,8011,8021,8022,8031,8042,8045,8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8093,8099,8100,8180,8181,8192,8193,8194,8200,8222,8254,8290,8291,8292,8300,8333,8383,8400,8402,8443,8500,8600,8649,8651,8652,8654,8701,8800,8873,8888,8899,8994,9000,9001,9002,9003,9009,9010,9011,9040,9050,9071,9080,9081,9090,9091,9099,9100,9101,9102,9103,9110,9111,9200,9207,9220,9290,9415,9418,9485,9500,9502,9503,9535,9575,9593,9594,9595,9618,9666,9876,9877,9878,9898,9900,9917,9929,9943,9944,9968,9998,9999,10000,10001,10002,10003,10004,10009,10010,10012,10024,10025,10082,10180,10215,10243,10566,10616,10617,10621,10626,10628,10629,10778,11110,11111,11967,12000,12174,12265,12345,13456,13722,13782,13783,14000,14238,14441,14442,15000,15002,15003,15004,15660,15742,16000,16001,16012,16016,16018,16080,16113,16992,16993,17877,17988,18040,18101,18988,19101,19283,19315,19350,19780,19801,19842,20000,20005,20031,20221,20222,20828,21571,22939,23502,24444,24800,25734,25735,26214,27000,27352,27353,27355,27356,27715,28201,30000,30718,30951,31038,31337,32768,32769,32770,32771,32772,32773,32774,32775,32776,32777,32778,32779,32780,32781,32782,32783,32784,32785,33354,33899,34571,34572,34573,35500,38292,40193,40911,41511,42510,44176,44442,44443,44501,45100,48080,49152,49153,49154,49155,49156,49157,49158,49159,49160,49161,49163,49165,49167,49175,49176,49400,49999,50000,50001,50002,50003,50006,50300,50389,50500,50636,50800,51103,51493,52673,52822,52848,52869,54045,54328,55055,55056,55555,55600,56737,56738,57294,57797,58080,60020,60443,61532,61900,62078,63331,64623,64680,65000,65129,65389]
	
	TOP_100_PORTS = {7:'echo',9:'discard',13:'daytime',21:'ftp',22:'ssh',23:'telnet',25:'smtp',26:'rsftp',37:'time',53:'domain',79:'finger',80:'http',81:'hosts2-ns',88:'kerberos-sec',106:'pop3pw',110:'pop3',111:'rpcbind',113:'ident',119:'nntp',135:'msrpc',139:'netbios-ssn',143:'imap',144:'news',179:'bgp',199:'smux',389:'ldap',427:'svrloc',443:'https',444:'snpp',445:'microsoft-ds',465:'smtps',513:'login',514:'shell',515:'printer',543:'klogin',544:'kshell',548:'afp',554:'rtsp',587:'submission',631:'ipp',646:'ldp',873:'rsync',990:'ftps',993:'imaps',995:'pop3s',1025:'NFS-or-IIS',1026:'LSA-or-nterm',1027:'IIS',1028:'unknown',1029:'ms-lsa',1110:'nfsd-status',1433:'ms-sql-s',1720:'h323q931',1723:'pptp',1755:'wms',1900:'upnp',2000:'cisco-sccp',2001:'dc',2049:'nfs',2121:'ccproxy-ftp',2717:'pn-requester',3000:'ppp',3128:'squid-http',3306:'mysql',3389:'ms-wbt-server',3986:'mapper-ws_ethd',4899:'radmin',5000:'upnp',5009:'airport-admin',5051:'ida-agent',5060:'sip',5101:'admdog',5190:'aol',5357:'wsdapi',5432:'postgresql',5631:'pcanywheredata',5666:'nrpe',5800:'vnc-http',5900:'vnc',6000:'X11',6001:'X11:1',6646:'unknown',7070:'realserver',8000:'http-alt',8008:'http',8009:'',8080:'',8081:'',8443:'https-alt',8888:'ajp13',9100:'jetdirect',9999:'abyss',10000:'snet-sensor-mgmt',32768:'filenet-tms',49152:'unknown',49153:'unknown',49154:'unknown',49155:'unknown',49156:'unknown',49157:'unknown'}	
	
	TOP_10_PORTS = [21,22,23,25,80,110,139,443,445,3389]
	
	#DARK
	if "--black" in options:
		out()
		exit(dark())
	
	#HELP
	if "--help" in options:
		out()
		exit(help())
	
	#CHECKING FOR EMPTY HOSTS
	if not targets:
		out()
		exit(f"\n{RED}No targets specified!{RESET}\n\n{GREEN}Usage: dedmap [--option(s)] [target(s)]\n\n{array(list(zip(list(POSSIBLE_OPTIONS), list(POSSIBLE_OPTIONS.values()))))}\n\nUse dedmap -h or --help to get a detailed usage instruction.{RESET}\n")
	
	
	#GIVING PRIORITY TO LONG-FORMAT ARGUMENTS
	priority()
	
	#GETTING SPECIFIC PORTS
	if "--port" in options: 
		if "," in options["--port"] : ports = options["--port"].split(",")
		elif options["--port"].isdigit(): ports.append(options["--port"])
	ports = [int(i) for i in ports]

	
	################### MAIN ############################ *********
	
	if "--silent" not in options: graphics()
	
	#INITIAL MESSAGE
	from datetime import datetime
	log.info(f'\n{BLUE}Starting DEDMAP at {datetime.now().strftime("%B %d, %Y %H:%M:%S")} ( https://7Ragnarok7.github.io/DEDMAP ) .....{RESET}')
	with open("temp.log", "a") as file: file.write(f'\nCommand used: {" ".join(argv)}\n')

	#RECORDING THE STARTING TIME TO CALCULATE TOTAL SCANNING TIME
	from time import time
	STARTING_TIME = time()
	
	#STARTING THE SCAN *********
	scan()
	
	#TOTAL COMPLETION TIME
	log.info(f"\n{BLUE}Scan completed in: {round(time() - STARTING_TIME, 2)} seconds.{RESET}")
	
	#DEBUGGING ---- COMMENT OR UNCOMMENT TO TURN OFF OR ON. MOVE THIS PART OF CODE ABOVE OR BELOW SOME OTHER CODE TO PERFORM EXECUTION ORDER-SPECIFIC DEBUGGING
	#debug()

	#REPORTING
	log.info(f"\n{YELLOW}Report BUGS at ( https://github.com/7Ragnarok7/DEDMAP/issues ){RESET}\n")


#EXCEPTION HANDLING
except IndexError: exit(f"\n{RED}IP-RANGE only supported in last octet .i.e 1.1.1.1-100{RESET}\n")
except socket.gaierror: print(f"\n{RED}Unable to resolve hostname!{RESET}\n")
except socket.error: print(f"\n{RED}Couldn't connect to the server!{RESET}\n")
except KeyboardInterrupt:
	log.info(f"\n{RED}Quitting... Ctrl+C was pressed{RESET}\n")
	exit(out())
except getopt.GetoptError:
	if argv[1] == "-p" or argv[1] == "--port": exit(f"\n{RED}Option -p requires an argument{RESET}\n")
	elif argv[1] == "-o" or argv[1] == "--out": exit(f"\n{RED}Option -o requires an argument{RESET}\n")
	else: exit(f"\n{RED}Argument Value Missing/Option Not Valid!{RESET}\n")
else: out()
