def _limit_handler(self, args): """ Handles 'limit' command-line argument Limits bandwith of host to specified rate """ hosts = self._get_hosts_by_ids(args.id) rate = NetRate(args.rate) direction = self._parse_direction_args(args) if not rate.is_valid(): IO.error('limit rate is invalid.') return if hosts is not None and len(hosts) > 0: for host in hosts: if not host.spoofed: self.arp_spoofer.add(host) self.limiter.limit(host, direction, rate) IO.ok('{}{}{r} {} {}limited{r} to {}.'.format( IO.Fore.LIGHTYELLOW_EX, host.ip, Direction.pretty_direction(direction), IO.Fore.LIGHTRED_EX, rate, r=IO.Style.RESET_ALL))
def _add_handler(self, args): """ Handles 'add' command-line argument Adds custom host to host list """ ip = args.ip if not netutils.validate_ip_address(ip): IO.error('invalid ip address.') return if args.mac: mac = args.mac if not netutils.validate_mac_address(mac): IO.error('invalid mac address.') return else: mac = netutils.get_mac_by_ip(self.interface, ip) if mac is None: IO.error('unable to resolve mac address. specify manually (--mac).') return name = None try: host_info = socket.gethostbyaddr(ip) name = None if host_info is None else host_info[0] except socket.herror: pass host = Host(ip, mac, name) if host in self.hosts: IO.error('host does already exist.') return self.hosts.append(host) IO.ok('host added.')
def interrupt_handler(self): IO.spacer() IO.ok('cleaning up... stand by...') self.arp_spoofer.stop() for host in self.hosts: self._free_host(host)
def _block_handler(self, args): """ Handles 'block' command-line argument Blocks internet communication for host """ hosts = self._get_hosts_by_ids(args.id) direction = self._parse_direction_args(args) discordText = "```" if hosts is not None and len(hosts) > 0: for host in hosts: if not host.spoofed: self.arp_spoofer.add(host) self.limiter.block(host, direction) self.bandwidth_monitor.add(host) IO.ok('{}{}{r} {} {}blocked{r}.'.format( IO.Fore.LIGHTYELLOW_EX, host.ip, Direction.pretty_direction(direction), IO.Fore.RED, r=IO.Style.RESET_ALL)) discordText += '{} pada IP {} diblokir\n'.format( Direction.pretty_direction(direction), host.ip) discordText += '```' if hosts is not None and len(hosts) > 0: IO.discord(discordText)
def run(): """ Main entry point of the application """ version = get_version() args = parse_arguments() IO.initialize(args.colorless) IO.print(get_main_banner(version)) if not is_linux(): IO.error('run under linux.') return if not is_privileged(): IO.error('run as root.') return args = process_arguments(args) if args is None: return if initialize(args.interface): IO.spacer() menu = MainMenu(version, args.interface, args.gateway_ip, args.gateway_mac, args.netmask) menu.start() cleanup(args.interface)
def _limit_handler(self, args): """ Handles 'limit' command-line argument Limits bandwith of host to specified rate """ hosts = self._get_hosts_by_ids(args.id) if hosts is None or len(hosts) == 0: return try: rate = BitRate.from_rate_string(args.rate) except Exception: IO.error('limit rate is invalid.') return direction = self._parse_direction_args(args) for host in hosts: self.arp_spoofer.add(host) self.limiter.limit(host, direction, rate) self.bandwidth_monitor.add(host) IO.ok('{}{}{r} {} {}limited{r} to {}.'.format( IO.Fore.LIGHTYELLOW_EX, host.ip, Direction.pretty_direction(direction), IO.Fore.LIGHTRED_EX, rate, r=IO.Style.RESET_ALL))
def scan(self, iprange=None): self._resolve_names = True with ThreadPoolExecutor(max_workers=self.max_workers) as executor: hosts = [] iprange = [ str(x) for x in (self.iprange if iprange is None else iprange) ] iterator = tqdm( iterable=executor.map(self._sweep, iprange), total=len(iprange), ncols=45, bar_format='{percentage:3.0f}% |{bar}| {n_fmt}/{total_fmt}') try: for host in iterator: if host is not None: try: host_info = socket.gethostbyaddr(host.ip) name = '' if host_info is None else host_info[0] host.name = name except socket.herror: pass hosts.append(host) except KeyboardInterrupt: iterator.close() IO.ok('aborted. waiting for shutdown...') return hosts
def _free_host(self, host): """ Stops ARP spoofing and unlimits host """ if host.spoofed: self.arp_spoofer.remove(host) self.limiter.unlimit(host) IO.ok('{}{}{} freed.'.format(IO.Fore.LIGHTYELLOW_EX, host.ip, IO.Style.RESET_ALL))
def _clear_handler(self, args): """ Handler for the 'clear' command-line argument Clears the terminal window and re-prints the banner """ IO.clear() IO.print(get_main_banner(self.version)) self._print_help_reminder()
def _help_handler(self, args): """ Handles 'help' command-line argument Prints help message including commands and usage """ spaces = ' ' * 35 IO.print(""" {y}scan (--range [IP range]){r}{}scans for online hosts on your network. {s}required to find the hosts you want to limit. {b}{s}e.g.: scan {s} scan --range 192.168.178.1-192.168.178.50 {s} scan --range 192.168.178.1/24{r} {y}hosts (--force){r}{}lists all scanned hosts. {s}contains host information, including IDs. {y}limit [ID1,ID2,...] [rate]{r}{}limits bandwith of host(s) (uload/dload). {y} (--upload) (--download){r}{}{b}e.g.: limit 4 100kbit {s} limit 2,3,4 1gbit --download {s} limit all 200kbit --upload{r} {y}block [ID1,ID2,...]{r}{}blocks internet access of host(s). {y} (--upload) (--download){r}{}{b}e.g.: block 3,2 {s} block all --upload{r} {y}free [ID1,ID2,...]{r}{}unlimits/unblocks host(s). {b}{s}e.g.: free 3 {s} free all{r} {y}add [IP] (--mac [MAC]){r}{}adds custom host to host list. {s}mac resolved automatically. {b}{s}e.g.: add 192.168.178.24 {s} add 192.168.1.50 --mac 1c:fc:bc:2d:a6:37{r} {y}monitor (--interval [time in ms]){r}{}monitors bandwidth usage of limited hosts. {b}{s}e.g.: monitor --interval 600{r} {y}clear{r}{}clears the terminal window. {y}quit{r}{}quits the application. """.format(spaces[len('scan (--range [IP range])'):], spaces[len('hosts (--force)'):], spaces[len('limit [ID1,ID2,...] [rate]'):], spaces[len(' (--upload) (--download)'):], spaces[len('block [ID1,ID2,...]'):], spaces[len(' (--upload) (--download)'):], spaces[len('free [ID1,ID2,...]'):], spaces[len('add [IP] (--mac [MAC])'):], spaces[len('monitor (--interval [time in ms])'):], spaces[len('clear'):], spaces[len('quit'):], y=IO.Fore.LIGHTYELLOW_EX, r=IO.Style.RESET_ALL, b=IO.Style.BRIGHT, s=spaces))
def interrupt_handler(self, ctrl_c=True): if ctrl_c: IO.spacer() IO.ok('cleaning up... stand by...') self.arp_spoofer.stop() self.bandwidth_monitor.stop() for host in self.hosts: self._free_host(host)
def _remove_handler(self, args): hosts = self._get_hosts_by_ids(args.id) discordText = "```" if hosts is not None and len(hosts) > 0: for host in hosts: self._free_host(host) discordText += 'IP {} dihapus dari list\n'.format(host.ip) self.hosts = [host for host in self.hosts if host not in hosts] discordText += "```" if hosts is not None and len(hosts) > 0: IO.discord(discordText)
def _block_handler(self, args): """ Handles 'block' command-line argument Blocks internet communication for host """ host = self._get_host_by_id(args.id) if host is not None: if not host.spoofed: self.arp_spoofer.add(host) self.limiter.block(host) IO.ok('{}{}{} blocked{}.'.format(IO.Fore.LIGHTYELLOW_EX, host.ip, IO.Fore.RED, IO.Style.RESET_ALL))
def _scan_handler(self, args): """ Handles 'scan' command-line argument (Re)scans for hosts on the network """ if args.iprange: try: if '-' in args.iprange: iprange = list( netaddr.iter_iprange(*args.iprange.split('-'))) else: iprange = list(netaddr.IPNetwork(args.iprange)) except netaddr.core.AddrFormatError: IO.error('ip range invalid.') return else: iprange = None for host in self.hosts: self._free_host(host) IO.spacer() self.hosts = self.host_scanner.scan(iprange) IO.ok('{}{}{} hosts discovered.'.format(IO.Fore.LIGHTYELLOW_EX, len(self.hosts), IO.Style.RESET_ALL)) IO.spacer()
def _hosts_handler(self, args): """ Handles 'hosts' command-line argument Displays discovered hosts """ table_data = [[ '{}ID{}'.format(IO.Style.BRIGHT, IO.Style.RESET_ALL), '{}IP address{}'.format(IO.Style.BRIGHT, IO.Style.RESET_ALL), '{}MAC address{}'.format(IO.Style.BRIGHT, IO.Style.RESET_ALL), '{}Hostname{}'.format(IO.Style.BRIGHT, IO.Style.RESET_ALL), '{}Status{}'.format(IO.Style.BRIGHT, IO.Style.RESET_ALL) ]] with self.hosts_lock: for host in self.hosts: table_data.append([ '{}{}{}'.format(IO.Fore.LIGHTYELLOW_EX, self._get_host_id(host, lock=False), IO.Style.RESET_ALL), host.ip, host.mac, host.name, host.pretty_status() ]) table = SingleTable(table_data, 'Hosts') if not args.force and not table.ok: IO.error( 'table does not fit terminal. resize or decrease font size. you can also force the display (--force).' ) return IO.spacer() IO.print(table.table) IO.spacer()
def _scan_handler(self, args): """ Handles 'scan' command-line argument (Re)scans for hosts on the network """ if args.iprange: iprange = self._parse_iprange(args.iprange) if iprange is None: IO.error('invalid ip range.') return else: iprange = None with self.hosts_lock: for host in self.hosts: self._free_host(host) IO.spacer() hosts = self.host_scanner.scan(iprange) self.hosts_lock.acquire() self.hosts = hosts self.hosts_lock.release() IO.ok('{}{}{} hosts discovered.'.format(IO.Fore.LIGHTYELLOW_EX, len(hosts), IO.Style.RESET_ALL)) IO.spacer()
def _get_host_by_id(self, id_): try: identifier = int(id_) except ValueError: IO.error('identifier is not an integer.') return if len(self.hosts) == 0 or identifier not in range(len(self.hosts)): IO.error('no host with id {}{}{}.'.format(IO.Fore.LIGHTYELLOW_EX, identifier, IO.Style.RESET_ALL)) return return self.hosts[identifier]
def _hosts_handler(self, args): """ Handles 'hosts' command-line argument Displays discovered hosts """ table_data = [[ '{}ID{}'.format(IO.Style.BRIGHT, IO.Style.RESET_ALL), '{}IP-Address{}'.format(IO.Style.BRIGHT, IO.Style.RESET_ALL), '{}MAC-Address{}'.format(IO.Style.BRIGHT, IO.Style.RESET_ALL), '{}Hostname{}'.format(IO.Style.BRIGHT, IO.Style.RESET_ALL), '{}Status{}'.format(IO.Style.BRIGHT, IO.Style.RESET_ALL) ]] for i, host in enumerate(self.hosts): table_data.append([ '{}{}{}'.format(IO.Fore.LIGHTYELLOW_EX, i, IO.Style.RESET_ALL), host.ip, host.mac, host.name if host.name is not None else '', host.pretty_status() ]) table = SingleTable(table_data, 'Hosts') if not table.ok: IO.error( 'table does not fit terminal. resize or decrease font size.') return IO.spacer() IO.print(table.table) IO.spacer()
def _free_handler(self, args): """ Handles 'free' command-line argument Frees the host from all limitations """ hosts = self._get_hosts_by_ids(args.id) discordText = "```" if hosts is not None and len(hosts) > 0: for host in hosts: self._free_host(host) discordText += 'IP {} dibebaskan dari limitasi\n'.format( host.ip) discordText += "```" if hosts is not None and len(hosts) > 0: IO.discord(discordText)
def scan(self): with ThreadPoolExecutor(max_workers=self.max_workers) as executor: hosts = [] iterator = tqdm( iterable=executor.map(self._sweep, self.iprange), total=len(self.iprange), ncols=45, bar_format='{percentage:3.0f}% |{bar}| {n_fmt}/{total_fmt}') try: for host in iterator: if host is not None: hosts.append(host) except KeyboardInterrupt: iterator.close() IO.ok('aborted. waiting for shutdown...') return hosts
def _block_handler(self, args): """ Handles 'block' command-line argument Blocks internet communication for host """ hosts = self._get_hosts_by_ids(args.id) direction = self._parse_direction_args(args) if hosts is not None and len(hosts) > 0: for host in hosts: if not host.spoofed: self.arp_spoofer.add(host) self.limiter.block(host, direction) IO.ok('{}{}{r} {} {}blocked{r}.'.format( IO.Fore.LIGHTYELLOW_EX, host.ip, Direction.pretty_direction(direction), IO.Fore.RED, r=IO.Style.RESET_ALL))
def _limit_handler(self, args): """ Handles 'limit' command-line argument Limits bandwith of host to specified rate """ hosts = self._get_hosts_by_ids(args.id) rate = args.rate if hosts is not None and len(hosts) > 0: for host in hosts: if not host.spoofed: self.arp_spoofer.add(host) if netutils.validate_netrate_string(rate): self.limiter.limit(host, rate) else: IO.error('limit rate is invalid.') return IO.ok('{}{}{} limited{} to {}.'.format(IO.Fore.LIGHTYELLOW_EX, host.ip, IO.Fore.LIGHTRED_EX, IO.Style.RESET_ALL, rate))
def _get_hosts_by_ids(self, ids_string): if ids_string == 'all': return self.hosts.copy() try: ids = [int(x) for x in ids_string.split(',')] except ValueError: IO.error('\'{}\' are invalid IDs.'.format(ids_string)) return hosts = [] for id_ in ids: if len(self.hosts) == 0 or id_ not in range(len(self.hosts)): IO.error('no host with id {}{}{}.'.format( IO.Fore.LIGHTYELLOW_EX, id_, IO.Style.RESET_ALL)) return if self.hosts[id_] not in hosts: hosts.append(self.hosts[id_]) return hosts
def _get_hosts_by_ids(self, ids_string): if ids_string == 'all': return self.hosts.copy() ids = ids_string.split(',') hosts = set() for id_ in ids: is_mac = netutils.validate_mac_address(id_) is_ip = netutils.validate_ip_address(id_) is_id_ = id_.isdigit() if not is_mac and not is_ip and not is_id_: IO.error('invalid identifier(s): \'{}\'.'.format(ids_string)) return if is_mac or is_ip: found = False for host in self.hosts: if host.mac == id_.lower() or host.ip == id_: found = True hosts.add(host) break if not found: IO.error('no host matching {}{}{}.'.format(IO.Fore.LIGHTYELLOW_EX, id_, IO.Style.RESET_ALL)) return else: id_ = int(id_) if len(self.hosts) == 0 or id_ not in range(len(self.hosts)): IO.error('no host with id {}{}{}.'.format(IO.Fore.LIGHTYELLOW_EX, id_, IO.Style.RESET_ALL)) return hosts.add(self.hosts[id_]) return hosts
def initialize(interface): """ Sets up requirements, e.g. IP-Forwarding, 3rd party applications """ if not netutils.create_qdisc_root(interface): IO.spacer() IO.error('qdisc root handle could not be created. maybe flush network settings (--flush).') return False if not netutils.enable_ip_forwarding(): IO.spacer() IO.error('ip forwarding could not be enabled.') return False return True
def _help_handler(self, args): """ Handles 'help' command-line argument Prints help message including commands and usage """ spaces = ' ' * 20 IO.print(""" {y}scan{r}{}scans for online hosts on your network. {s}required to find the hosts you want to limit. {y}hosts{r}{}lists all scanned hosts. {s}contains host information, including IDs. {y}limit [ID] [rate]{r}{}limits bandwith of host (uload/dload). {b}{s}e.g.: limit 4 100kbit {s} limit 2 1gbit {s} limit 5 500tbit{r} {y}block [ID]{r}{}blocks internet access of host. {b}{s}e.g.: block 3{r} {y}free [ID]{r}{}unlimits/unblocks host. {b}{s}e.g.: free 3{r} {y}clear{r}{}clears the terminal window. """.format(spaces[len('scan'):], spaces[len('hosts'):], spaces[len('limit [ID] [rate]'):], spaces[len('block [ID]'):], spaces[len('free [ID]'):], spaces[len('clear'):], y=IO.Fore.LIGHTYELLOW_EX, r=IO.Style.RESET_ALL, b=IO.Style.BRIGHT, s=spaces))
def start(self): """ Starts the menu input loop. Commands will be processed and handled. """ self._active = True while self._active: try: command = IO.input(self.prompt) except KeyboardInterrupt: self.interrupt_handler() break # split command by spaces and parse the arguments parsed_args = self.parser.parse(command.split()) if parsed_args is not None: self.argument_handler(parsed_args)
def _scan_handler(self, args): """ Handles 'scan' command-line argument (Re)scans for hosts on the network """ for host in self.hosts: self._free_host(host) IO.spacer() self.hosts = self.host_scanner.scan() IO.ok('{}{}{} hosts discovered.'.format(IO.Fore.LIGHTYELLOW_EX, len(self.hosts), IO.Style.RESET_ALL)) IO.spacer()
def _watch_set_handler(self, args): """ Handles 'watch set' command-line argument Modifies settings of the reconnection reconnection watcher """ if args.attribute.lower() in ('range', 'iprange', 'ip_range'): iprange = self._parse_iprange(args.value) if iprange is not None: self.host_watcher.iprange = iprange else: IO.error('invalid ip range.') elif args.attribute.lower() in ('interval'): if args.value.isdigit(): self.host_watcher.interval = int(args.value) else: IO.error('invalid interval.') else: IO.error('{}{}{} is an invalid settings attribute.'.format( IO.Fore.LIGHTYELLOW_EX, args.attribute, IO.Style.RESET_ALL))
def _print_help_reminder(self): IO.print( 'type {Y}help{R} or {Y}?{R} to show command information.'.format( Y=IO.Fore.LIGHTYELLOW_EX, R=IO.Style.RESET_ALL))