efknockr

- internet relay chat beacon
git clone git://git.acid.vegas/efknockr.git
Log | Files | Refs | Archive | README | LICENSE

efknockr.py (24595B)

      1 #!/usr/bin/env python
      2 # efknockr (internet relay chat drive-by tool) - developed by acidvegas in python (https://git.acid.vegas/efknockr)
      3 
      4 '''
      5 WARNING: This script is riddled with purposely made mistakes to prevent abuse LOL.
      6 '''
      7 
      8 import asyncio
      9 import ipaddress
     10 import os
     11 import random
     12 import re
     13 import ssl
     14 import sys
     15 import time
     16 import urllib.request
     17 
     18 class settings:
     19 	chan_first           = False          # Finish knocking channels before sending private messages
     20 	confuse              = True           # Use unicode confusables in messages to avoid spamfilters
     21 	daemon               = False          # Run in daemon mode (24/7 throttled knocking)
     22 	errors               = True           # Show errors in console
     23 	errors_conn          = False          # Show connection errors in console
     24 	exploits             = False          # Use a exploit payloads
     25 	mass_hl              = True           # Hilite all the users in a channel before parting
     26 	part_msg             = 'Smell ya l8r' # Send a custom part message when leaving channels
     27 	proxies              = False          # Connect with proxies
     28 	proxies_only         = False          # Only connect with proxies
     29 	proxies_scan         = False          # Scan for new proxies
     30 	proxies_local        = False          # Use proxies from proxies.txt
     31 	register             = True           # Register with NickServ before joining channels
     32 	register_chan        = '#EFKnockr'    # Set to None to disable channel registrations
     33 	register_chan_topic = 'EFK'           # Topic to set for the registered channel
     34 
     35 class throttle:
     36 	channels  = 3   if not settings.daemon else 2   # Maximum number of channels to knock at once
     37 	connect   = 15  if not settings.daemon else 60  # Delay between each connection attempt on a diffferent port
     38 	delay     = 300 if not settings.daemon else 600 # Delay before registering nick (if enabled) & sending /LIST
     39 	jdelay    = 3   if not settings.daemon else 10  # Delay before messaging a channel
     40 	join      = 10  if not settings.daemon else 30  # Delay between channel JOINs
     41 	message   = 1.5 if not settings.daemon else 3   # Delay between each message sent
     42 	nick      = 300 if not settings.daemon else 600 # Delay between every random NICK change
     43 	nicks     = 5   if not settings.daemon else 15  # Delay between each nick private messaged
     44 	private   = 5   if not settings.daemon else 15  # Delay between private messages
     45 	pthreads  = 500 if not settings.daemon else 300 # Maximum number of threads for proxy checking
     46 	ptimeout  = 15  if not settings.daemon else 30  # Timeout for all sockets
     47 	seconds   = 300 if not settings.daemon else 600 # Maximum seconds to wait when throttled for JOIN or PM
     48 	users     = 10  if not settings.daemon else 5   # Minimum number of users in a channel to knock
     49 	threads   = 500 if not settings.daemon else 50  # Maximum number of threads running
     50 	timeout   = 30  if not settings.daemon else 60  # Timeout for all sockets
     51 	ztimeout  = 200 if not settings.daemon else 300 # Timeout for zero data from server ;) ;) ;)
     52 
     53 messages = (
     54 	'This message has been brought to you by EFknockr!',
     55 	'WHAT IS UP PORT 6667!?',
     56 	['multi','lined','message','example'],
     57 	['cant','    stop','        me','cause','    im a','        pumper'],
     58 	'b i g   a c i d v e g a s   h a s   u'
     59 )
     60 
     61 class bad:
     62 	donotscan = (
     63 		'irc.terahertz.net',     '165.254.255.25',        '2001:728:1808::25',
     64 		'irc.dronebl.org',       'irc.alphachat.net',
     65 		'5.9.164.48',            '45.32.74.177',          '104.238.146.46',               '149.248.55.130',
     66 		'2001:19f0:6001:1dc::1', '2001:19f0:b001:ce3::1', '2a01:4f8:160:2501:48:164:9:5', '2001:19f0:6401:17c::1'
     67 	)
     68 	chan = {
     69 		'403' : 'ERR_NOSUCHCHANNEL',    '405' : 'ERR_TOOMANYCHANNELS',
     70 		'435' : 'ERR_BANONCHAN',        '442' : 'ERR_NOTONCHANNEL',
     71 		'448' : 'ERR_FORBIDDENCHANNEL', '470' : 'ERR_LINKCHANNEL',
     72 		'471' : 'ERR_CHANNELISFULL',    '473' : 'ERR_INVITEONLYCHAN',
     73 		'474' : 'ERR_BANNEDFROMCHAN',   '475' : 'ERR_BADCHANNELKEY',
     74 		'476' : 'ERR_BADCHANMASK',      '477' : 'ERR_NEEDREGGEDNICK',
     75 		'479' : 'ERR_BADCHANNAME',      '480' : 'ERR_THROTTLE',
     76 		'485' : 'ERR_CHANBANREASON',    '488' : 'ERR_NOSSL',
     77 		'489' : 'ERR_SECUREONLYCHAN',   '519' : 'ERR_TOOMANYUSERS',
     78 		'520' : 'ERR_OPERONLY',         '926' : 'ERR_BADCHANNEL'
     79 	}
     80 	error = {
     81 		'install identd'                 : 'Identd required',
     82 		'trying to reconnect too fast'   : 'Throttled',
     83 		'trying to (re)connect too fast' : 'Throttled',
     84 		'reconnecting too fast'          : 'Throttled',
     85 		'access denied'                  : 'Access denied',
     86 		'not authorized to'              : 'Not authorized',
     87 		'not authorised to'              : 'Not authorized',
     88 		'password mismatch'              : 'Password mismatch',
     89 		'dronebl'                        : 'DroneBL',
     90 		'dnsbl'                          : 'DNSBL',
     91 		'g:lined'                        : 'G:Lined',
     92 		'z:lined'                        : 'Z:Lined',
     93 		'timeout'                        : 'Timeout',
     94 		'closing link'                   : 'Banned',
     95 		'banned'                         : 'Banned',
     96 		'client exited'                  : 'QUIT',
     97 		'quit'                           : 'QUIT'
     98 	}
     99 
    100 # Globals
    101 all_proxies  = list()
    102 good_proxies = list()
    103 
    104 def confuse(data):
    105 	if settings.confuse:
    106 		chars = ''
    107 		for char in data:
    108 			if random.choice((True,False,False)):
    109 				if char == ' ':
    110 					chars += '\u00A0'
    111 				elif char.lower() in ('abcdefghijklmnopqrstvwyz'):
    112 					chars += char + random.choice(('\u200B','\u2060','\x0f','\x03\x0f'))
    113 				else:
    114 					chars += char
    115 			else:
    116 				chars += char
    117 		return ''.join(chars)
    118 	else:
    119 		return data
    120 
    121 def debug(data):
    122 	print('{0} \033[1;30m|\033[0m [\033[35m~\033[0m] {1}'.format(time.strftime('%I:%M:%S'), data))
    123 
    124 def error(data, reason=None):
    125 	if settings.errors:
    126 		print('{0} \033[1;30m|\033[0m [\033[31m!\033[0m] {1} \033[1;30m({2})\033[0m'.format(time.strftime('%I:%M:%S'), data, str(reason))) if reason else print('{0} \033[1;30m|\033[0m [\033[31m!\033[0m] {1}'.format(time.strftime('%I:%M:%S'), data))
    127 
    128 def get_proxies():
    129 	urls = (
    130 		'https://find-your-own-proxies.com/socks5.txt',
    131 		'https://find-your-own-proxies.com/socks5.txt',
    132 		'https://find-your-own-proxies.com/socks5.txt'
    133 	)
    134 	proxies = list()
    135 	for url in urls:
    136 		try:
    137 			req = urllib.request.Request(url)
    138 			req.add_header('User-Agent', 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)')
    139 			source  = urllib.request.urlopen(req, timeout=10).read().decode()
    140 			proxies+= list(set([proxy for proxy in re.findall('[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+', source, re.MULTILINE) if proxy not in proxies]))
    141 		except Exception as ex:
    142 			error('failed to grab new proxies!', ex)
    143 	return proxies if proxies else False
    144 
    145 async def check_proxy(semaphore, proxy):
    146 	async with semaphore:
    147 		ip, port = proxy.split(':')
    148 		options = {
    149 			'proxy'      : aiosocks.Socks5Addr(proxy.split(':')[0], int(proxy.split(':')[1])),
    150 			'proxy_auth' : None,
    151 			'dst'        : ('www.google.com',80),
    152 			'limit'      : 1024,
    153 			'ssl'        : None,
    154 			'family'     : 2
    155 		}
    156 		try:
    157 			await asyncio.wait_for(aiosocks.open_connection(**options), throttle.ptimeout)
    158 		except:
    159 			pass
    160 		else:
    161 			debug('\033[1;32mGOOD\033[0m \033[1;30m|\033[0m ' + proxy)
    162 			if ip not in all_proxies:
    163 				all_proxies.append(ip)
    164 				good_proxies.append(proxy)
    165 
    166 def rndnick():
    167 	prefix = random.choice(['st','sn','cr','pl','pr','fr','fl','qu','br','gr','sh','sk','tr','kl','wr','bl']+list('bcdfgklmnprstvwz'))
    168 	midfix = random.choice(('aeiou'))+random.choice(('aeiou'))+random.choice(('bcdfgklmnprstvwz'))
    169 	suffix = random.choice(['ed','est','er','le','ly','y','ies','iest','ian','ion','est','ing','led','inger']+list('abcdfgklmnprstvwz'))
    170 	return prefix+midfix+suffix
    171 
    172 def ssl_ctx():
    173 	ctx = ssl.create_default_context()
    174 	ctx.check_hostname = False
    175 	ctx.verify_mode = ssl.CERT_NONE
    176 	return ctx
    177 
    178 class probe:
    179 	def __init__(self, semaphore, server, proxy=None):
    180 		self.semaphore = semaphore
    181 		self.server    = server
    182 		self.proxy     = proxy
    183 		self.display   = server.ljust(18)+' \033[1;30m|\033[0m unknown network           \033[1;30m|\033[0m '
    184 		self.nickname  = rndnick()
    185 		self.channels  = {'all':list(), 'current':list(), 'users':dict(), 'bad':list()}
    186 		self.nicks     = {'all':list(), 'chan':dict(),    'check':list(), 'bad':list()}
    187 		self.loops     = {'init':None, 'chan':None, 'nick':None, 'pm':None}
    188 		self.jthrottle = throttle.join
    189 		self.nthrottle = throttle.private
    190 		self.reader    = None
    191 		self.write     = None
    192 
    193 	async def sendmsg(self, target, msg):
    194 		await self.raw(f'PRIVMSG {target} :{msg}')
    195 
    196 	async def run(self):
    197 		async with self.semaphore:
    198 			try:
    199 				await self.connect() # 6697
    200 			except Exception as ex:
    201 				if settings.errors_conn:
    202 					error(self.display + '\033[1;31mdisconnected\033[0m - failed to connect using SSL/TLS!', ex)
    203 				await asyncio.sleep(throttle.connect)
    204 				try:
    205 					await self.connect(True) # 6667
    206 				except Exception as ex:
    207 					if settings.errors_conn:
    208 						error(self.display + '\033[1;31mdisconnected\033[0m - failed to connect!', ex)
    209 
    210 	async def raw(self, data):
    211 		self.writer.write(data[:510].encode('utf-8') + b'\r\n')
    212 		await self.writer.drain()
    213 
    214 	async def connect(self, fallback=False):
    215 		if self.proxy:
    216 			auth = self.proxy.split('@')[0].split(':') if '@' in self.proxy else None
    217 			proxy_ip, proxy_port = self.proxy.split('@')[1].split(':') if '@' in self.proxy else self.proxy.split(':')
    218 			options = {
    219 				'proxy'      : aiosocks.Socks5Addr(proxy_ip, proxy_port),
    220 				'proxy_auth' : aiosocks.Socks5Auth(*auth) if auth else None,
    221 				'dst'        : (self.server,6667) if fallback else (self.server,6697),
    222 				'limit'      : 1024,
    223 				'ssl'        : None if fallback else ssl_ctx(),
    224 				'family'     : 2
    225 			}
    226 			self.reader, self.writer = await asyncio.wait_for(aiosocks.open_connection(**options), throttle.timeout)
    227 		else:
    228 			options = {
    229 				'host'   : self.server,
    230 				'port'   : 6667 if fallback else 6697,
    231 				'limit'  : 1024,
    232 				'ssl'    : None if fallback else ssl_ctx(),
    233 				'family' : 2
    234 			}
    235 			self.reader, self.writer = await asyncio.wait_for(asyncio.open_connection(**options), throttle.timeout)
    236 		del options
    237 		await self.raw('USER {0} 0 * :{1}'.format(rndnick(), rndnick()))
    238 		await self.raw('NICK ' + self.nickname)
    239 		await self.listen()
    240 		for item in self.loops:
    241 			if self.loops[item]:
    242 				self.loops[item].cancel()
    243 		debug(self.display + 'finished knocking')
    244 
    245 	async def loop_initial(self):
    246 		try:
    247 			await asyncio.sleep(throttle.delay)
    248 			mail = rndnick() + '@' + random.choice(('gmail.com','hotmail.com','yahoo.com','outlook.com','protonmail.com','mail.com',rndnick()+random.choice(('com','org','net'))))
    249 			cmds = [f'PRIVMSG NickServ :REGISTER {rndnick()} {mail}', 'LIST']
    250 			for command in cmds:
    251 				try:
    252 					await self.raw(command)
    253 				except:
    254 					break
    255 				else:
    256 					await asyncio.sleep(3)
    257 			if not self.channels['all']:
    258 				error(self.display + '\033[31merror\033[0m - no channels found')
    259 				await self.raw('QUIT')
    260 		except asyncio.CancelledError:
    261 			pass
    262 		except Exception as ex:
    263 			error(self.display + '\033[31merror\033[0m - loop_initial', ex)
    264 
    265 	async def loop_channels(self):
    266 		try:
    267 			while self.channels['all']:
    268 				while len(self.channels['current']) >= throttle.channels:
    269 					await asyncio.sleep(1)
    270 				await asyncio.sleep(self.jthrottle)
    271 				chan = random.choice(self.channels['all'])
    272 				self.channels['all'].remove(chan)
    273 				try:
    274 					await self.raw('JOIN ' + chan)
    275 				except:
    276 					break
    277 			if settings.chan_first:
    278 				self.loops['pm'] = asyncio.create_task(self.loop_private())
    279 			while self.nicks['check']:
    280 				await asyncio.sleep(1)
    281 			self.loops['nick'].cancel()
    282 			self.loops['pm'].cancel()
    283 			await self.raw('QUIT')
    284 		except asyncio.CancelledError:
    285 			pass
    286 		except Exception as ex:
    287 			error(self.display + '\033[31merror\033[0m - loop_channels', ex)
    288 
    289 	async def loop_nick(self):
    290 		try:
    291 			while True:
    292 				await asyncio.sleep(throttle.nick)
    293 				self.nickname = rndnick()
    294 				await self.raw('NICK ' + self.nickname)
    295 		except asyncio.CancelledError:
    296 			pass
    297 		except Exception as ex:
    298 			error(self.display + '\033[31merror\033[0m - loop_nick', ex)
    299 
    300 	async def loop_private(self):
    301 		try:
    302 			while True:
    303 				if self.nicks['check']:
    304 					nick = random.choice(self.nicks['check'])
    305 					self.nicks['check'].remove(nick)
    306 					try:
    307 						msg = random.choice(messages)
    308 						if type(msg) == list:
    309 							for i in msg:
    310 								if nick in self.nicks['bad']:
    311 									self.nicks['bad'].remove(nick)
    312 									break
    313 								else:
    314 									await self.sendmsg(nick, confuse(i))
    315 									await asyncio.sleep(throttle.message)
    316 						else:
    317 							await self.sendmsg(nick, confuse(msg))
    318 					except:
    319 						break
    320 					else:
    321 						del nick
    322 						await asyncio.sleep(throttle.nicks)
    323 				else:
    324 					await asyncio.sleep(1)
    325 		except asyncio.CancelledError:
    326 			pass
    327 		except Exception as ex:
    328 			error(self.display + '\033[31merror\033[0m - loop_private', ex)
    329 
    330 	async def listen(self):
    331 		while True:
    332 			try:
    333 				if self.reader.at_eof():
    334 					break
    335 				data  = await asyncio.wait_for(self.reader.readuntil(b'\r\n'), throttle.ztimeout)
    336 				line  = data.decode('utf-8').strip()
    337 				args  = line.split()
    338 				event = args[1].upper()
    339 				if event in bad.chan and len(args) >= 4:
    340 					chan = args[3]
    341 					if chan in self.channels['users']:
    342 						del self.channels['users'][chan]
    343 					if chan in self.nicks['chan']:
    344 						del self.nicks['chan'][chan]
    345 					error(f'{self.display}\033[31merror\033[0m - {chan}', bad.chan[event])
    346 				elif line.startswith('ERROR :'):
    347 					check = [check for check in bad.error if check in line.lower()]
    348 					if check:
    349 						raise Exception(bad.error[check[0]])
    350 				elif args[0] == 'PING':
    351 					await self.raw('PONG ' + args[1][1:])
    352 				elif event == '001': #RPL_WELCOME
    353 					host = args[0][1:]
    354 					if len(host) > 25:
    355 						self.display = f'{self.server.ljust(18)} \033[1;30m|\033[0m {host[:22]}... \033[1;30m|\033[0m '
    356 					else:
    357 						self.display = f'{self.server.ljust(18)} \033[1;30m|\033[0m {host.ljust(25)} \033[1;30m|\033[0m '
    358 					debug(self.display + f'\033[1;32mconnected\033[0m')
    359 					self.loops['init'] = asyncio.create_task(self.loop_initial())
    360 				elif event == '315' and len(args) >= 3: #RPL_ENDOFWHO
    361 					chan = args[3]
    362 					await asyncio.sleep(throttle.jdelay)
    363 					msg = random.choice(messages)
    364 					if type(msg) == list:
    365 						for i in msg:
    366 							if chan in self.channels['bad']:
    367 								self.channels['bad'].remove(chan)
    368 								break
    369 							else:
    370 								await self.sendmsg(chan, confuse(i))
    371 								await asyncio.sleep(throttle.message)
    372 					else:
    373 						await self.sendmsg(chan, confuse(msg))
    374 					if settings.exploits:
    375 						pass # TODO: add exploits
    376 					if settings.mass_hl:
    377 						self.nicks['chan'][chan] = ' '.join(self.nicks['chan'][chan])
    378 						if len(self.nicks['chan'][chan]) <= 400:
    379 							await self.sendmsg(chan, self.nicks['chan'][chan])
    380 						else:
    381 							while len(self.nicks['chan'][chan]) > 400:
    382 								if chan in self.channels['bad']:
    383 									self.channels['bad'].remove(chan)
    384 									break
    385 								else:
    386 									segment = self.nicks['chan'][chan][:400]
    387 									segment = segment[:-len(segment.split()[len(segment.split())-1])]
    388 									await self.sendmsg(chan, segment)
    389 									self.nicks['chan'][chan] = self.nicks['chan'][chan][len(segment):]
    390 									await asyncio.sleep(throttle.message)
    391 					await self.raw(f'PART {chan} :{settings.part_msg}')
    392 					self.channels['current'].remove(chan)
    393 					del self.nicks['chan'][chan]
    394 					if chan in self.channels['bad']:
    395 						self.channels['bad'].remove(chan)
    396 				elif event == '322' and len(args) >= 4: # RPL_LIST
    397 					chan  = args[3]
    398 					users = args[4]
    399 					if len(self.channels['all']) >= 20000:
    400 						error(self.display + 'LIST tarpit detected!') # Make it     wuddup
    401 						error(self.display + 'LIST tarpit detected!') # stand out           pi55
    402 						error(self.display + 'LIST tarpit detected!') # more                       n3t
    403 						self.snapshot['TARPIT'] = True
    404 						await self.raw('QUIT')
    405 					if users != '0': # no need to JOIN empty channels...
    406 						if chan not in ('#dronebl','#help','#opers'): # lets avoid the channels that are going to get use banned/blacklisted
    407 							self.channels['all'].append(chan)
    408 							self.channels['users'][chan] = users
    409 				elif event == '323': # RPL_LISTEND
    410 					if self.channels['all']:
    411 						debug(self.display + '\033[36mLIST\033[0m found \033[93m{0}\033[0m channel(s)'.format(str(len(self.channels['all']))))
    412 						self.loops['chan'] = asyncio.create_task(self.loop_channels())
    413 						self.loops['nick'] = asyncio.create_task(self.loop_nick())
    414 						if not settings.chan_first:
    415 							self.loops['pm']   = asyncio.create_task(self.loop_private())
    416 				elif event == '352' and len(args) >= 8: # RPL_WHORPL
    417 					chan = args[3]
    418 					nick = args[7]
    419 					self.nicks['chan'][chan].append(nick)
    420 					if nick not in self.nicks['all']+[self.nickname,]:
    421 						self.nicks['all'].append(nick)
    422 						self.nicks['check'].append(nick)
    423 				elif event == '366' and len(args) >= 4: # RPL_ENDOFNAMES
    424 					chan = args[3]
    425 					self.nicks['chan'][chan] = list()
    426 					self.channels['current'].append(chan)
    427 					if chan in self.channels['users']:
    428 						debug('{0}\033[32mJOIN\033[0m {1} \033[1;30m(found \033[93m{2}\033[0m users)\033[0m'.format(self.display, chan, self.channels['users'][chan]))
    429 						del self.channels['users'][chan]
    430 					await self.raw('WHO ' + chan)
    431 					# MADE YOU LOOK LOL GET FUCKED XD
    432 				elif event == '404' and len(args) >= 5: # ERR_CANNOTSENDTOCHAN
    433 					chan = args[3]
    434 					msg  = ' '.join(args[4:])[1:]
    435 					error(self.display + '\033[31merror\033[0m - failed to knock ' + chan, msg)
    436 					if chan not in self.channels['bad']:
    437 						self.channels['bad'].append(chan)
    438 				elif event == '421' and len(args) >= 3: # ERR_UNKNOWNCOMMAND
    439 					msg = ' '.join(args[2:])
    440 					if 'You must be connected for' in msg:
    441 						error(self.display + '\033[31merror\033[0m - delay found', msg)
    442 				elif event == '433': # ERR_NICKINUSE
    443 					self.nickname = rndnick()
    444 					await self.raw('NICK ' + self.nickname)
    445 				elif event == '439' and len(args) >= 11: # ERR_TARGETTOOFAST
    446 					target = args[3]
    447 					msg    = ' '.join(args[4:])[1:]
    448 					seconds = args[10]
    449 					if target[:1] in ('#','&'):
    450 						self.channels['all'].append(target)
    451 						if seconds.isdigit():
    452 							self.jthrottle = throttle.seconds if int(seconds) > throttle.seconds else int(seconds)
    453 					else:
    454 						self.nicks['check'].append(target)
    455 						if seconds.isdigit():
    456 							self.nthrottle = throttle.seconds if int(seconds) > throttle.seconds else int(seconds)
    457 					error(self.display + '\033[31merror\033[0m - delay found for ' + target, msg)
    458 				elif event == '465': # ERR_YOUREBANNEDCREEP
    459 					check = [check for check in bad.error if check in line.lower()]
    460 					if check:
    461 						raise Exception(bad.error[check[0]])
    462 				elif event == '464': # ERR_PASSWDMISMATCH
    463 					raise Exception('Network has a password')
    464 				elif event == '487': # ERR_MSGSERVICES
    465 					if '"/msg NickServ" is no longer supported' in line: # TODO: need to do this for ChanServ aswell
    466 						await self.raw('/NickServ REGISTER {0} {1}'.format(rndnick(), f'{rndnick()}@{rndnick()}.com'))
    467 				elif args[1] in ('716','717'): # RPL_TARGUMODEG / RPL_TARGNOTIFY
    468 					nick = args[2] #TODO: verify this is the correct arguement
    469 					if nick not in self.nicks['bad']:
    470 						self.nicks['bad'].append(nick)
    471 				elif event == 'KICK' and len(args) >= 4:
    472 					chan   = args[2]
    473 					kicked = args[3]
    474 					if kicked == self.nickname:
    475 						if chan in self.channels['current']:
    476 							self.channels['current'].remove(chan)
    477 				elif event == 'KILL':
    478 					nick = args[2]
    479 					if nick == self.nickname:
    480 						raise Exception('KILL')
    481 				elif event == 'MODE' and len(args) == 4:
    482 					nick = args[2]
    483 					if nick == self.nickname:
    484 						mode = args[3][1:]
    485 						if mode == '+r':
    486 							chan = settings.register_chan + '_' + str(random.randint(10,99))
    487 							await self.raw('JOIN ' + chan)
    488 							await self.raw(f'TOPIC {chan} :' + settings.register_chan_topic)
    489 							await self.sendmsg('ChanServ', 'REGISTER ' + chan)
    490 							await self.sendmsg('ChanServ', f'SET {chan} KEEPTOPIC ON')
    491 							await self.sendmsg('ChanServ', f'SET {chan} NOEXPIRE ON')
    492 							await self.sendmsg('ChanServ', f'SET {chan} PERSIST ON')
    493 							await self.sendmsg('ChanServ', f'SET {chan} DESCRIPTION ' + settings.register_chan_topic)
    494 							await self.raw('PART ' + chan)
    495 				elif event in ('NOTICE','PRIVMSG') and len(args) >= 4:
    496 					nick   = args[0].split('!')[1:]
    497 					target = args[2]
    498 					msg    = ' '.join(args[3:])[1:]
    499 					if target == self.nickname:
    500 						for i in ('proxy','proxys','proxies'):
    501 							if i in msg.lower():
    502 								check = [x for x in ('bopm','hopm') if x in line]
    503 								if check:
    504 									error(f'{self.display}\033[93m{check[0].upper()} detected\033[0m')
    505 								else:
    506 									error(self.display + '\033[93mProxy Monitor detected\033[0m')
    507 						for i in ('You must have been using this nick for','You must be connected for','not connected long enough','Please wait', 'You cannot list within the first'):
    508 							if i in msg:
    509 								error(self.display + '\033[31merror\033[0m - delay found', msg)
    510 								break
    511 						if msg[:8] == '\001VERSION':
    512 							version = random.choice(('http://www.mibbit.com ajax IRC Client','mIRC v6.35 Khaled Mardam-Bey','xchat 0.24.1 Linux 2.6.27-8-eeepc i686','rZNC Version 1.0 [02/01/11] - Built from ZNC','thelounge v3.0.0 -- https://thelounge.chat/'))
    513 							await self.raw(f'NOTICE {nick} \001VERSION {version}\001')
    514 						elif '!' not in args[0]:
    515 							if 'dronebl.org/lookup' in msg:
    516 								error(self.display + '\033[93mDroneBL detected\033[0m')
    517 								raise Exception('DroneBL')
    518 							else:
    519 								if [i for i in ('You\'re banned','You are permanently banned','You are banned','You are not welcome','Temporary K-line') if i in msg]:
    520 									raise Exception('K-Lined')
    521 			except (UnicodeDecodeError, UnicodeEncodeError):
    522 				pass
    523 			except Exception as ex:
    524 				error(self.display + '\033[1;31mdisconnected\033[0m', ex)
    525 				break
    526 
    527 async def main_b(targets):
    528 	sema = asyncio.BoundedSemaphore(throttle.pthreads) # B O U N D E D   S E M A P H O R E   G A N G
    529 	jobs = list()
    530 	for target in targets:
    531 		jobs.append(asyncio.ensure_future(check_proxy(sema, target)))
    532 	await asyncio.gather(*jobs)
    533 
    534 async def main_a(targets):
    535 	sema = asyncio.BoundedSemaphore(throttle.threads) # B O U N D E D   S E M A P H O R E   G A N G
    536 	jobs = list()
    537 	if settings.proxies:
    538 		if settings.proxies_scan:
    539 			proxies = None
    540 			del all_proxies[:len(all_proxies)]
    541 			del good_proxies[:len(good_proxies)]
    542 			while not good_proxies:
    543 				debug('scanning for fresh Socks5 proxies...')
    544 				proxies = get_proxies()
    545 				if proxies:
    546 					debug(f'testing {len(proxies):,} proxies...')
    547 					await main_b(proxies)
    548 					if not good_proxies:
    549 						await asyncio.sleep(300)
    550 				else:
    551 					await asyncio.sleep(300)
    552 			debug(f'found {len(good_proxies):,} proxies')
    553 		elif settings.proxies_local:
    554 			with open('proxies.txt', 'r') as f:
    555 				good_proxies = [line.rstrip() for line in f.readlines() if line]
    556 		else:
    557 			raise SystemExit('error: invalid proxy mode (must use either proxy scanning or local proxies)')
    558 	for target in targets:
    559 		try:
    560 			ipaddress.IPv4Address(target)
    561 		except:
    562 			error('invalid ip address', target)
    563 		else:
    564 			if settings.proxies:
    565 				for proxy in good_proxies: # Todo: we should check if this is empty before running
    566 					jobs.append(asyncio.ensure_future(probe(sema, target, proxy).run()))
    567 			if not settings.proxies_only:
    568 				jobs.append(asyncio.ensure_future(probe(sema, target).run()))
    569 	random.shuffle(jobs)
    570 	await asyncio.gather(*jobs)
    571 
    572 # Main
    573 print('#'*56)
    574 print('#{:^54}#'.format(''))
    575 print('#{:^54}#'.format('EFknockr (internet relay chat beacon)'))
    576 print('#{:^54}#'.format('Developed by acidvegas in Python'))
    577 print('#{:^54}#'.format('https://git.acid.vegas/efknockr'))
    578 print('#{:^54}#'.format(''))
    579 print('#'*56)
    580 if True:
    581 	raise SystemExit('those who are not skids may figure out how to use this...') # ;) by removing this you agree to only test this on your own server(s) LOLOLOOL
    582 if settings.proxies:
    583 	try:
    584 		import aiosocks
    585 	except ImportError:
    586 		raise SystemExit('missing required library \'aiosocks\' (https://pypi.org/project/aiosocks/)')
    587 if len(sys.argv) != 2:
    588 	raise SystemExit('error: invalid arguments')
    589 targets_file = sys.argv[1]
    590 if not os.path.isfile(targets_file):
    591 	raise SystemExit('error: invalid file path')
    592 targets = [line.rstrip() for line in open(targets_file).readlines() if line and line not in bad.donotscan]
    593 del targets_file
    594 debug(f'loaded {len(targets):,} targets')
    595 while True:
    596 	asyncio.run(main_a(targets))
    597 	debug('EFknockr has finished knocking!!')
    598 	if not settings.daemon:
    599 		break