diff --git a/chaos_monkey/control.py b/chaos_monkey/control.py index c2939ec95..d02306bb7 100644 --- a/chaos_monkey/control.py +++ b/chaos_monkey/control.py @@ -120,7 +120,7 @@ class ControlClient(object): return try: - WormConfiguration.from_dict(reply.json().get('config')) + WormConfiguration.from_dict(reply.json()["objects"][0].get('config')) LOG.info("New configuration was loaded from server: %r" % (WormConfiguration.as_dict(),)) except Exception, exc: # we don't continue with default conf here because it might be dangerous @@ -128,6 +128,11 @@ class ControlClient(object): WormConfiguration.current_server, reply._content, exc) raise Exception("Couldn't load from from server's configuration, aborting. %s" % exc) + @staticmethod + def check_for_stop(): + ControlClient.load_control_config() + return not WormConfiguration.alive + @staticmethod def download_monkey_exe(host): if not WormConfiguration.current_server: diff --git a/chaos_monkey/monkey.py b/chaos_monkey/monkey.py index c4f2a6f09..365198fee 100644 --- a/chaos_monkey/monkey.py +++ b/chaos_monkey/monkey.py @@ -46,7 +46,7 @@ class ChaosMonkey(object): arg_parser.add_argument('-s', '--server') arg_parser.add_argument('-d', '--depth') opts, self._args = arg_parser.parse_known_args(self._args) - + self._parent = opts.parent self._default_tunnel = opts.tunnel self._default_server = opts.server @@ -69,10 +69,18 @@ class ChaosMonkey(object): if firewall.is_enabled(): firewall.add_firewall_rule() ControlClient.wakeup(parent=self._parent, default_tunnel=self._default_tunnel) + ControlClient.load_control_config() + + if not WormConfiguration.alive: + LOG.info("Marked not alive from configuration") + return + monkey_tunnel = ControlClient.create_control_tunnel() if monkey_tunnel: monkey_tunnel.start() + ControlClient.send_telemetry("state", {'done': False}) + self._default_server = WormConfiguration.current_server LOG.debug("default server: %s" % self._default_server) ControlClient.send_telemetry("tunnel", ControlClient.proxies.get('https')) @@ -103,12 +111,16 @@ class ChaosMonkey(object): break machines = self._network.get_victim_machines(WormConfiguration.scanner_class, - max_find=WormConfiguration.victims_max_find) + max_find=WormConfiguration.victims_max_find, + stop_callback=ControlClient.check_for_stop) is_empty = True for machine in machines: + if ControlClient.check_for_stop(): + break + is_empty = False for finger in self._fingerprint: - LOG.info("Trying to get OS fingerprint from %r with module %s", + LOG.info("Trying to get OS fingerprint from %r with module %s", machine, finger.__class__.__name__) finger.get_host_fingerprint(machine) @@ -156,8 +168,8 @@ class ChaosMonkey(object): if successful_exploiter: self._exploited_machines.add(machine) - ControlClient.send_telemetry('exploit', {'machine': machine.__dict__, - 'exploiter': successful_exploiter.__class__.__name__}) + ControlClient.send_telemetry('exploit', {'machine': machine.__dict__, + 'exploiter': successful_exploiter.__class__.__name__}) LOG.info("Successfully propagated to %s using %s", machine, successful_exploiter.__class__.__name__) @@ -202,13 +214,14 @@ class ChaosMonkey(object): from _subprocess import SW_HIDE, STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags = CREATE_NEW_CONSOLE | STARTF_USESHOWWINDOW - startupinfo.wShowWindow = SW_HIDE + startupinfo.wShowWindow = SW_HIDE subprocess.Popen(DELAY_DELETE_CMD % {'file_path': sys.executable}, - stdin=None, stdout=None, stderr=None, + stdin=None, stdout=None, stderr=None, close_fds=True, startupinfo=startupinfo) else: os.remove(sys.executable) except Exception, exc: LOG.error("Exception in self delete: %s", exc) - LOG.info("Monkey is shutting down") + ControlClient.send_telemetry("state", {'done': True}) + LOG.info("Monkey is shutting down") \ No newline at end of file diff --git a/chaos_monkey/network/network_scanner.py b/chaos_monkey/network/network_scanner.py index bef094429..430c4f68a 100644 --- a/chaos_monkey/network/network_scanner.py +++ b/chaos_monkey/network/network_scanner.py @@ -33,7 +33,7 @@ class NetworkScanner(object): for ip_address in self._ip_addresses] LOG.info("Base local networks to scan are: %r", self._ranges) - def get_victim_machines(self, scan_type, max_find=5): + def get_victim_machines(self, scan_type, max_find=5, stop_callback=None): assert issubclass(scan_type, HostScanner) scanner = scan_type() @@ -42,6 +42,10 @@ class NetworkScanner(object): for range in self._ranges: LOG.debug("Scanning for potential victims in the network %r", range) for victim in range: + if stop_callback and stop_callback(): + LOG.debug("Got stop signal") + break + # skip self IP address if victim.ip_addr in self._ip_addresses: continue diff --git a/monkey_island/cc/admin/ui/index.html b/monkey_island/cc/admin/ui/index.html index 5b1be9e53..aadd2c871 100644 --- a/monkey_island/cc/admin/ui/index.html +++ b/monkey_island/cc/admin/ui/index.html @@ -123,6 +123,34 @@