Fixed issue 52

This commit is contained in:
Joshua Ogunyinka
2019-08-14 20:28:35 +01:00
parent d85cd7a3b0
commit ee47cac4ab
4 changed files with 213 additions and 149 deletions

View File

@@ -2,15 +2,24 @@
import sys import sys
from Interlace.lib.core.input import InputParser, InputHelper from Interlace.lib.core.input import InputParser, InputHelper
from Interlace.lib.core.output import OutputHelper, Level from Interlace.lib.core.output import OutputHelper, Level
from Interlace.lib.threader import Pool from Interlace.lib.threader import Pool, TaskBlock
def print_command(level, command, message, output):
if isinstance(command, TaskBlock):
for c in command:
print_command(level, c, message, output)
else:
output.terminal(Level.THREAD, command.name(), "Added to Queue")
def build_queue(arguments, output): def build_queue(arguments, output):
queue = list() task_queue = InputHelper.process_commands(arguments)
for command in InputHelper.process_commands(arguments): task_list = []
output.terminal(Level.THREAD, command, "Added to Queue") for task in task_queue:
queue.append(command) print_command(Level.THREAD, task, "Added to Queue", output)
return queue task_list.append(task)
return task_list
def main(): def main():

View File

@@ -1,12 +1,12 @@
from argparse import ArgumentParser
from netaddr import IPNetwork, IPRange, IPGlob
from Interlace.lib.core.output import OutputHelper, Level
import os.path import os.path
from os import access, W_OK
import sys import sys
from re import compile from argparse import ArgumentParser
from random import sample
from math import ceil from math import ceil
from os import access, W_OK
from random import sample
from netaddr import IPNetwork, IPRange, IPGlob
from Interlace.lib.threader import TaskBlock, Task
class InputHelper(object): class InputHelper(object):
@@ -62,35 +62,83 @@ class InputHelper(object):
return ips return ips
@staticmethod @staticmethod
def _replace_variable_for_commands(commands, variable, replacements): def _process_port(port_type):
tmp_commands = set() if "," in port_type:
return port_type.split(",")
elif "-" in port_type:
tmp = port_type.split("-")
begin_range = int(tmp[0])
end_range = int(tmp[1])
if begin_range >= end_range:
raise Exception("Invalid range provided")
return list(range(begin_range, end_range + 1))
return [port_type]
test = list() @staticmethod
def _pre_process_commands(command_list, task_name):
task_block = TaskBlock(task_name)
parent_task = None
for command in command_list:
command = str(command).strip()
if not command:
continue
if command.startswith('_block:') and command.endswith('_'):
new_task_name = command.split('_block:')[1][:-1].strip()
if task_name == new_task_name:
return task_block
task = InputHelper._pre_process_commands(command_list, new_task_name)
else:
task = Task(command)
if command == '_blocker_':
parent_task = task_block.last()
parent_task.set_lock()
continue
if parent_task:
task.wait_for(parent_task.get_lock())
task_block.add_task(task)
return task_block
@staticmethod
def _pre_process_hosts(host_ranges, destination_set, arguments):
for host in host_ranges:
host = host.replace(" ", "")
for ips in host.split(","):
# check if it is a domain name
if ips.split(".")[-1][0].isalpha():
destination_set.add(ips)
continue
# checking for CIDR
if not arguments.nocidr and "/" in ips:
destination_set.update(InputHelper._get_cidr_to_ips(ips))
# checking for IPs in a range
elif "-" in ips:
destination_set.update(InputHelper._get_ips_from_range(ips))
# checking for glob ranges
elif "*" in ips:
destination_set.update(InputHelper._get_ips_from_glob(ips))
else:
destination_set.add(ips)
@staticmethod
def _replace_variable_with_commands(commands, variable, replacements):
for replacement in replacements: for replacement in replacements:
for command in commands: for command in commands:
test.append(str(command).replace(variable, str(replacement))) if isinstance(command, TaskBlock):
InputHelper._replace_variable_with_commands(command, variable, replacements)
else:
command.replace(variable, str(replacement))
tmp_commands.update(test)
return tmp_commands
@staticmethod @staticmethod
def _replace_variable_array(commands, variable, replacement): def _replace_variable_array(commands, variable, replacement):
tmp_commands = set() # TODO
counter = 0 if variable not in sample(commands, 1)[0]:
return
test = list()
if not variable in sample(commands, 1)[0]:
return commands
for command in commands:
test.append(str(command).replace(variable, str(replacement[counter])))
counter += 1
tmp_commands.update(test)
return tmp_commands
for counter, command in enumerate(commands):
if isinstance(command, TaskBlock):
InputHelper._replace_variable_array(command, variable, replacement)
else:
command.replace(variable, str(replacement[counter]))
@staticmethod @staticmethod
def process_commands(arguments): def process_commands(arguments):
@@ -99,98 +147,37 @@ class InputHelper(object):
targets = set() targets = set()
exclusions_ranges = set() exclusions_ranges = set()
exclusions = set() exclusions = set()
final_commands = set()
output = OutputHelper(arguments)
# checking for whether output is writable and whether it exists # checking if output is writable and exists
if arguments.output: if arguments.output:
if not access(arguments.output, W_OK): if not access(arguments.output, W_OK):
raise Exception("Directory provided isn't writable") raise Exception("Directory provided isn't writable")
if arguments.port: if arguments.port:
if "," in arguments.port: ports = InputHelper._process_port(arguments.port)
ports = arguments.port.split(",")
elif "-" in arguments.port:
tmp_ports = arguments.port.split("-")
if int(tmp_ports[0]) >= int(tmp_ports[1]):
raise Exception("Invalid range provided")
ports = list(range(int(tmp_ports[0]), int(tmp_ports[1]) + 1))
else:
ports = [arguments.port]
if arguments.realport: if arguments.realport:
if "," in arguments.realport: real_ports = InputHelper._process_port(arguments.realport)
real_ports = arguments.realport.split(",")
elif "-" in arguments.realport:
tmp_ports = arguments.realport.split("-")
if int(tmp_ports[0]) >= int(tmp_ports[1]):
raise Exception("Invalid range provided")
real_ports = list(range(int(tmp_ports[0]), int(tmp_ports[1]) + 1))
else:
real_ports = [arguments.realport]
# process targets first # process targets first
if arguments.target: if arguments.target:
ranges.add(arguments.target) ranges.add(arguments.target)
else: else:
targetFile = arguments.target_list target_file = arguments.target_list
if not sys.stdin.isatty(): if not sys.stdin.isatty():
targetFile = sys.stdin target_file = sys.stdin
for target in targetFile: ranges.update([target for target in target_file if target.strip()])
if target.strip():
ranges.add(target.strip())
# process exclusions first # process exclusions first
if arguments.exclusions: if arguments.exclusions:
exclusions_ranges.add(arguments.exclusions) exclusions_ranges.add(arguments.exclusions)
else: else:
if arguments.exclusions_list: if arguments.exclusions_list:
for exclusion in arguments.exclusions_list: exclusions_ranges.update([exclusion for exclusion in arguments.exclusions_list if exclusion.strip()])
exclusions_ranges.add(target.strip())
# removing elements that may have spaces (helpful for easily processing comma notation) # removing elements that may have spaces (helpful for easily processing comma notation)
for target in ranges: InputHelper._pre_process_hosts(ranges, targets, arguments)
target = target.replace(" ", "") InputHelper._pre_process_hosts(exclusions_ranges, exclusions, arguments)
for ips in target.split(","):
# check if it is a domain name
if ips.split(".")[-1][0].isalpha():
targets.add(ips)
continue
# checking for CIDR
if not arguments.nocidr and "/" in ips:
targets.update(InputHelper._get_cidr_to_ips(ips))
# checking for IPs in a range
elif "-" in ips:
targets.update(InputHelper._get_ips_from_range(ips))
# checking for glob ranges
elif "*" in ips:
targets.update(InputHelper._get_ips_from_glob(ips))
else:
targets.add(ips)
# removing elements that may have spaces (helpful for easily processing comma notation)
for exclusion in exclusions_ranges:
exclusion = exclusion.replace(" ", "")
for ips in exclusion.split(","):
# check if it is a domain name
if ips.split(".")[-1][0].isalpha():
targets.add(ips)
continue
# checking for CIDR
if not arguments.nocidr and "/" in ips:
exclusions.update(InputHelper._get_cidr_to_ips(ips))
# checking for IPs in a range
elif "-" in ips:
exclusions.update(InputHelper._get_ips_from_range(ips))
# checking for glob ranges
elif "*" in ips:
exclusions.update(InputHelper._get_ips_from_glob(ips))
else:
exclusions.add(ips)
# difference operation # difference operation
targets -= exclusions targets -= exclusions
@@ -201,41 +188,36 @@ class InputHelper(object):
if arguments.command: if arguments.command:
commands.add(arguments.command.rstrip('\n')) commands.add(arguments.command.rstrip('\n'))
else: else:
for command in arguments.command_list: tasks = InputHelper._pre_process_commands(arguments.command_list, '')
commands.add(command.rstrip('\n')) commands.update(tasks.get_tasks())
final_commands = InputHelper._replace_variable_for_commands(commands, "_target_", targets) InputHelper._replace_variable_with_commands(commands, "_target_", targets)
final_commands = InputHelper._replace_variable_for_commands(final_commands, "_host_", targets) InputHelper._replace_variable_with_commands(commands, "_host_", targets)
if arguments.port: if arguments.port:
final_commands = InputHelper._replace_variable_for_commands(final_commands, "_port_", ports) InputHelper._replace_variable_with_commands(commands, "_port_", ports)
if arguments.realport: if arguments.realport:
final_commands = InputHelper._replace_variable_for_commands(final_commands, "_realport_", real_ports) InputHelper._replace_variable_with_commands(commands, "_realport_", real_ports)
if arguments.output: if arguments.output:
final_commands = InputHelper._replace_variable_for_commands(final_commands, "_output_", [arguments.output]) InputHelper._replace_variable_with_commands(commands, "_output_", [arguments.output])
if arguments.proto: if arguments.proto:
if "," in arguments.proto: if "," in arguments.proto:
protocols = arguments.proto.split(",") protocols = arguments.proto.split(",")
else: else:
protocols = arguments.proto protocols = arguments.proto
final_commands = InputHelper._replace_variable_for_commands(final_commands, "_proto_", protocols) InputHelper._replace_variable_with_commands(commands, "_proto_", protocols)
# process proxies # process proxies
if arguments.proxy_list: if arguments.proxy_list:
proxy_list = list() proxy_list = [proxy for proxy in arguments.proxy_list if proxy.strip()]
for proxy in arguments.proxy_list: if len(proxy_list) < len(commands):
if proxy.strip(): proxy_list = ceil(len(commands) / len(proxy_list)) * proxy_list
proxy_list.append(proxy.strip())
if len(proxy_list) < len(final_commands): InputHelper._replace_variable_array(commands, "_proxy_", proxy_list)
proxy_list = ceil(len(final_commands) / len(proxy_list)) * proxy_list return commands
final_commands = InputHelper._replace_variable_array(final_commands, "_proxy_", proxy_list)
return final_commands
class InputParser(object): class InputParser(object):

View File

@@ -1,7 +1,9 @@
from colorclass import Color
from colorclass import disable_all_colors, enable_all_colors, is_enabled
from time import localtime, strftime
from enum import IntEnum from enum import IntEnum
from time import localtime, strftime
from colorclass import Color
from colorclass import disable_all_colors
from Interlace.lib.core.__version__ import __version__ from Interlace.lib.core.__version__ import __version__
@@ -40,7 +42,7 @@ class OutputHelper(object):
'target': target, 'target': target,
'command': command, 'command': command,
'message': message, 'message': message,
'leader':leader 'leader': leader
} }
if not self.silent: if not self.silent:

View File

@@ -1,12 +1,92 @@
import threading
import subprocess import subprocess
import os from multiprocessing import Event
from threading import Thread
from tqdm import tqdm from tqdm import tqdm
class Task(object):
def __init__(self, command):
self.task = command
self._lock = None
self._waiting_for_task = False
def __hash__(self):
return self.task.__hash__()
def replace(self, old, new):
self.task = self.task.replace(old, new)
def run(self, t=False):
if not self._waiting_for_task:
self._run_task(t)
if self._lock:
self._lock.set()
else:
self._lock.wait()
self._run_task(t)
def wait_for(self, lock):
self._lock = lock
self._waiting_for_task = True
def set_lock(self):
if not self._lock:
self._lock = Event()
self._lock.clear()
def name(self):
return self.task
def get_lock(self):
return self._lock
def _run_task(self, t=False):
if t:
s = subprocess.Popen(self.task, shell=True, stdout=subprocess.PIPE)
t.write(s.stdout.readline().decode("utf-8"))
else:
subprocess.Popen(self.task, shell=True)
class TaskBlock(Task):
def __init__(self, name):
super().__init__('')
self._name = name
self.tasks = []
def name(self):
return self._name
def add_task(self, task):
self.tasks.append(task)
def __len__(self):
return len(self.tasks)
def __hash__(self):
hash_value = 0
for t in self.tasks:
hash_value ^= t.__hash__()
return hash_value
def __iter__(self):
return self.tasks.__iter__()
def last(self):
return self.tasks[-1]
def _run_task(self, t=False):
for task in self.tasks:
task._run_task(t)
def get_tasks(self):
return self.tasks
class Worker(object): class Worker(object):
def __init__(self, queue, timeout, output, tqdm): def __init__(self, task_queue, timeout, output, tqdm):
self.queue = queue self.queue = task_queue
self.timeout = timeout self.timeout = timeout
self.output = output self.output = output
self.tqdm = tqdm self.tqdm = tqdm
@@ -19,24 +99,16 @@ class Worker(object):
if isinstance(self.tqdm, tqdm): if isinstance(self.tqdm, tqdm):
self.tqdm.update(1) self.tqdm.update(1)
# run task # run task
self.run_task(task, self.tqdm) task.run(self.tqdm)
else: else:
self.run_task(task) task.run()
except IndexError: except IndexError:
break break
@staticmethod
def run_task(task, t=False):
if t:
s = subprocess.Popen(task, shell=True, stdout=subprocess.PIPE)
t.write(s.stdout.readline().decode("utf-8"))
else:
subprocess.Popen(task, shell=True)
class Pool(object): class Pool(object):
def __init__(self, max_workers, queue, timeout, output, progress_bar): def __init__(self, max_workers, task_queue, timeout, output, progress_bar):
# convert stdin input to integer # convert stdin input to integer
max_workers = int(max_workers) max_workers = int(max_workers)
@@ -45,28 +117,26 @@ class Pool(object):
raise ValueError("Workers must be >= 1") raise ValueError("Workers must be >= 1")
# check if the queue is empty # check if the queue is empty
if not queue: if not task_queue:
raise ValueError("The queue is empty") raise ValueError("The queue is empty")
self.queue = queue self.queue = task_queue
self.timeout = timeout self.timeout = timeout
self.output = output self.output = output
self.max_workers = max_workers self.max_workers = min(len(task_queue), max_workers)
if not progress_bar: if not progress_bar:
self.tqdm = tqdm(total=len(queue)) self.tqdm = tqdm(total=len(task_queue))
else: else:
self.tqdm = True self.tqdm = True
def run(self): def run(self):
workers = [Worker(self.queue, self.timeout, self.output, self.tqdm) for w in range(self.max_workers)] workers = [Worker(self.queue, self.timeout, self.output, self.tqdm) for w in range(self.max_workers)]
threads = [] threads = []
# run # run
for worker in workers: for worker in workers:
thread = threading.Thread(target=worker) thread = Thread(target=worker)
thread.start() thread.start()
threads.append(thread) threads.append(thread)
@@ -74,6 +144,7 @@ class Pool(object):
for thread in threads: for thread in threads:
thread.join() thread.join()
# test harness # test harness
if __name__ == "__main__": if __name__ == "__main__":
tasks = ["sleep 1", tasks = ["sleep 1",