diff --git a/monkey/common/di_container.py b/monkey/common/di_container.py index c1c740e39..9220864c3 100644 --- a/monkey/common/di_container.py +++ b/monkey/common/di_container.py @@ -35,13 +35,14 @@ class DIContainer: if not inspect.isclass(concrete_type): raise TypeError( "Expected a class, but received an instance of type " - f'"{concrete_type.__class__.__name__}"; Pass a class, not an instance, to ' - "register(), or use register_instance() instead" + f'"{DIContainer._format_type_name(concrete_type.__class__)}"; Pass a class, not an ' + "instance, to register(), or use register_instance() instead" ) if not issubclass(concrete_type, interface): raise TypeError( - f'Class "{concrete_type.__name__}" is not a subclass of {interface.__name__}' + f'Class "{DIContainer._format_type_name(concrete_type)}" is not a subclass of ' + f"{DIContainer._format_type_name(interface)}" ) self._type_registry[interface] = concrete_type @@ -56,8 +57,9 @@ class DIContainer: """ if not isinstance(instance, interface): raise TypeError( - f'The provided instance of type "{instance.__class__.__name__}" ' - f"is not an instance of {interface.__name__}" + "The provided instance of type " + f'"{DIContainer._format_type_name(instance.__class__)}" ' + f"is not an instance of {DIContainer._format_type_name(interface)}" ) self._instance_registry[interface] = instance @@ -151,7 +153,9 @@ class DIContainer: elif type_ in self._instance_registry: return self._retrieve_registered_instance(type_) - raise UnregisteredTypeError(f'Failed to resolve unregistered type "{type_.__name__}"') + raise UnregisteredTypeError( + f'Failed to resolve unregistered type "{DIContainer._format_type_name(type)}"' + ) def _construct_new_instance(self, arg_type: Type[T]) -> T: try: @@ -182,3 +186,13 @@ class DIContainer: """ convention_identifier = (type_, name) del_key(self._convention_registry, convention_identifier) + + @staticmethod + def _format_type_name(type_: Type) -> str: + try: + return type_.__name__ + except AttributeError: + # Some Types, like typing.Sequence, don't have a __name__ attribute in python3.7. When + # we upgrade to a later version of Python, this exception handler may no longer be + # necessary. + return str(type_) diff --git a/monkey/monkey_island/cc/app.py b/monkey/monkey_island/cc/app.py index cd7d46018..570d1bee8 100644 --- a/monkey/monkey_island/cc/app.py +++ b/monkey/monkey_island/cc/app.py @@ -13,6 +13,7 @@ from monkey_island.cc.database import database, mongo from monkey_island.cc.resources import ( AgentBinaries, ClearSimulationData, + IPAddresses, IslandLog, PropagationCredentials, RemoteRun, @@ -33,7 +34,6 @@ from monkey_island.cc.resources.blackbox.telemetry_blackbox_endpoint import ( from monkey_island.cc.resources.edge import Edge from monkey_island.cc.resources.exploitations.manual_exploitation import ManualExploitation from monkey_island.cc.resources.exploitations.monkey_exploitation import MonkeyExploitation -from monkey_island.cc.resources.ip_addresses import IpAddresses from monkey_island.cc.resources.island_mode import IslandMode from monkey_island.cc.resources.local_run import LocalRun from monkey_island.cc.resources.log import Log @@ -179,7 +179,7 @@ def init_restful_endpoints(api: FlaskDIWrapper): api.add_resource(TelemetryFeed) api.add_resource(Log) api.add_resource(IslandLog) - api.add_resource(IpAddresses) + api.add_resource(IPAddresses) # API Spec: These two should be the same resource, GET for download and POST for upload api.add_resource(PBAFileDownload) diff --git a/monkey/monkey_island/cc/models/monkey.py b/monkey/monkey_island/cc/models/monkey.py index a106f9965..003e14509 100644 --- a/monkey/monkey_island/cc/models/monkey.py +++ b/monkey/monkey_island/cc/models/monkey.py @@ -19,7 +19,7 @@ from mongoengine import ( from monkey_island.cc.models.command_control_channel import CommandControlChannel from monkey_island.cc.models.monkey_ttl import MonkeyTtl, create_monkey_ttl_document from monkey_island.cc.server_utils.consts import DEFAULT_MONKEY_TTL_EXPIRY_DURATION_IN_SECONDS -from monkey_island.cc.services.utils.network_utils import local_ip_addresses +from monkey_island.cc.services.utils.network_utils import get_ip_addresses class ParentNotFoundError(Exception): @@ -123,7 +123,7 @@ class Monkey(Document): def get_label_by_id(object_id): current_monkey = Monkey.get_single_monkey_by_id(object_id) label = Monkey.get_hostname_by_id(object_id) + " : " + current_monkey.ip_addresses[0] - if len(set(current_monkey.ip_addresses).intersection(local_ip_addresses())) > 0: + if len(set(current_monkey.ip_addresses).intersection(get_ip_addresses())) > 0: label = "MonkeyIsland - " + label return label diff --git a/monkey/monkey_island/cc/resources/__init__.py b/monkey/monkey_island/cc/resources/__init__.py index 28a55cd09..91024a6e3 100644 --- a/monkey/monkey_island/cc/resources/__init__.py +++ b/monkey/monkey_island/cc/resources/__init__.py @@ -4,3 +4,4 @@ from .clear_simulation_data import ClearSimulationData from .island_log import IslandLog from .reset_agent_configuration import ResetAgentConfiguration from .propagation_credentials import PropagationCredentials +from .ip_addresses import IPAddresses diff --git a/monkey/monkey_island/cc/resources/ip_addresses.py b/monkey/monkey_island/cc/resources/ip_addresses.py index ef0e0fa4b..3ba7d6123 100644 --- a/monkey/monkey_island/cc/resources/ip_addresses.py +++ b/monkey/monkey_island/cc/resources/ip_addresses.py @@ -1,20 +1,25 @@ -from typing import Mapping, Sequence +from typing import Sequence from monkey_island.cc.resources.AbstractResource import AbstractResource from monkey_island.cc.resources.request_authentication import jwt_required -from monkey_island.cc.services.utils.network_utils import local_ip_addresses -class IpAddresses(AbstractResource): +class IPAddresses(AbstractResource): + """ + Endpoint for the Monkey Island's IP addresses + """ + urls = ["/api/island/ip-addresses"] + def __init__(self, ip_addresses: Sequence[str]): + self._ips = ip_addresses + @jwt_required - def get(self) -> Mapping[str, Sequence[str]]: + def get(self) -> Sequence[str]: """ - Gets the IP addresses of the Island network interfaces + Sends the IP addresses of the Island - :return: a dictionary with "ip_addresses" key that points to a list of IP's + :return: IP addresses """ - local_ips = local_ip_addresses() - return {"ip_addresses": local_ips} + return self._ips diff --git a/monkey/monkey_island/cc/resources/root.py b/monkey/monkey_island/cc/resources/root.py index ef53ff788..4200029a4 100644 --- a/monkey/monkey_island/cc/resources/root.py +++ b/monkey/monkey_island/cc/resources/root.py @@ -6,7 +6,6 @@ from monkey_island.cc.database import mongo from monkey_island.cc.resources.AbstractResource import AbstractResource from monkey_island.cc.resources.request_authentication import jwt_required from monkey_island.cc.services.infection_lifecycle import get_completed_steps -from monkey_island.cc.services.utils.network_utils import local_ip_addresses logger = logging.getLogger(__name__) @@ -29,7 +28,6 @@ class Root(AbstractResource): @jwt_required def get_server_info(self): return jsonify( - ip_addresses=local_ip_addresses(), mongo=str(mongo.db), completed_steps=get_completed_steps(), ) diff --git a/monkey/monkey_island/cc/server_setup.py b/monkey/monkey_island/cc/server_setup.py index 3b08cd2f2..eed949a02 100644 --- a/monkey/monkey_island/cc/server_setup.py +++ b/monkey/monkey_island/cc/server_setup.py @@ -27,7 +27,7 @@ from monkey_island.cc.server_utils.consts import ( # noqa: E402 ) from monkey_island.cc.server_utils.island_logger import reset_logger, setup_logging # noqa: E402 from monkey_island.cc.services.initialize import initialize_services # noqa: E402 -from monkey_island.cc.services.utils.network_utils import local_ip_addresses # noqa: E402 +from monkey_island.cc.services.utils.network_utils import get_ip_addresses # noqa: E402 from monkey_island.cc.setup import PyWSGILoggingFilter # noqa: E402 from monkey_island.cc.setup import island_config_options_validator # noqa: E402 from monkey_island.cc.setup.data_dir import IncompatibleDataDirectory, setup_data_dir # noqa: E402 @@ -168,7 +168,7 @@ def _log_init_info(): def _log_web_interface_access_urls(): - web_interface_urls = ", ".join([f"https://{ip}:{ISLAND_PORT}" for ip in local_ip_addresses()]) + web_interface_urls = ", ".join([f"https://{ip}:{ISLAND_PORT}" for ip in get_ip_addresses()]) logger.info( "To access the web interface, navigate to one of the the following URLs using your " f"browser: {web_interface_urls}" diff --git a/monkey/monkey_island/cc/services/initialize.py b/monkey/monkey_island/cc/services/initialize.py index a280c4705..f6ff6d309 100644 --- a/monkey/monkey_island/cc/services/initialize.py +++ b/monkey/monkey_island/cc/services/initialize.py @@ -1,6 +1,7 @@ import json import logging from pathlib import Path +from typing import Sequence from pymongo import MongoClient @@ -46,6 +47,7 @@ from monkey_island.cc.services.telemetry.processing.credentials.credentials_pars from monkey_island.cc.services.telemetry.processing.processing import ( TELEMETRY_CATEGORY_TO_PROCESSING_FUNC, ) +from monkey_island.cc.services.utils.network_utils import get_ip_addresses from monkey_island.cc.setup.mongo.mongo_setup import MONGO_URL from . import AuthenticationService @@ -96,6 +98,7 @@ def _register_conventions(container: DIContainer, data_dir: Path): ) container.register_convention(Path, "island_log_file_path", get_log_file_path(data_dir)) container.register_convention(str, "version_number", get_version()) + container.register_convention(Sequence[str], "ip_addresses", get_ip_addresses()) def _register_repositories(container: DIContainer, data_dir: Path): diff --git a/monkey/monkey_island/cc/services/node.py b/monkey/monkey_island/cc/services/node.py index 4ffb3935d..faac42539 100644 --- a/monkey/monkey_island/cc/services/node.py +++ b/monkey/monkey_island/cc/services/node.py @@ -9,7 +9,7 @@ from monkey_island.cc.database import mongo from monkey_island.cc.models import Monkey from monkey_island.cc.services.edge.displayed_edge import DisplayedEdgeService from monkey_island.cc.services.edge.edge import EdgeService -from monkey_island.cc.services.utils.network_utils import local_ip_addresses +from monkey_island.cc.services.utils.network_utils import get_ip_addresses from monkey_island.cc.services.utils.node_states import NodeStates @@ -110,7 +110,7 @@ class NodeService: def get_monkey_label(monkey): # todo label = monkey["hostname"] + " : " + monkey["ip_addresses"][0] - ip_addresses = local_ip_addresses() + ip_addresses = get_ip_addresses() if len(set(monkey["ip_addresses"]).intersection(ip_addresses)) > 0: label = "MonkeyIsland - " + label return label @@ -118,7 +118,7 @@ class NodeService: @staticmethod def get_monkey_group(monkey): keywords = [] - if len(set(monkey["ip_addresses"]).intersection(local_ip_addresses())) != 0: + if len(set(monkey["ip_addresses"]).intersection(get_ip_addresses())) != 0: keywords.extend(["island", "monkey"]) else: monkey_type = "manual" if NodeService.get_monkey_manual_run(monkey) else "monkey" @@ -275,7 +275,7 @@ class NodeService: # It's better to just initialize the island machine on reset I think @staticmethod def get_monkey_island_monkey(): - ip_addresses = local_ip_addresses() + ip_addresses = get_ip_addresses() for ip_address in ip_addresses: monkey = NodeService.get_monkey_by_ip(ip_address) if monkey is not None: @@ -297,7 +297,7 @@ class NodeService: @staticmethod def get_monkey_island_node(): island_node = NodeService.get_monkey_island_pseudo_net_node() - island_node["ip_addresses"] = local_ip_addresses() + island_node["ip_addresses"] = get_ip_addresses() island_node["domain_name"] = socket.gethostname() return island_node diff --git a/monkey/monkey_island/cc/services/reporting/report.py b/monkey/monkey_island/cc/services/reporting/report.py index 89c6d2a78..32761c7a6 100644 --- a/monkey/monkey_island/cc/services/reporting/report.py +++ b/monkey/monkey_island/cc/services/reporting/report.py @@ -19,7 +19,7 @@ from monkey_island.cc.services.reporting.pth_report import PTHReportService from monkey_island.cc.services.reporting.report_generation_synchronisation import ( safe_generate_regular_report, ) -from monkey_island.cc.services.utils.network_utils import get_subnets, local_ip_addresses +from monkey_island.cc.services.utils.network_utils import get_ip_addresses, get_subnets from .. import AWSService from . import aws_exporter @@ -175,7 +175,7 @@ class ReportService: @staticmethod def get_island_cross_segment_issues(): issues = [] - island_ips = local_ip_addresses() + island_ips = get_ip_addresses() for monkey in mongo.db.monkey.find( {"tunnel": {"$exists": False}}, {"tunnel": 1, "guid": 1, "hostname": 1} ): diff --git a/monkey/monkey_island/cc/services/run_local_monkey.py b/monkey/monkey_island/cc/services/run_local_monkey.py index a56642e2c..36c348b85 100644 --- a/monkey/monkey_island/cc/services/run_local_monkey.py +++ b/monkey/monkey_island/cc/services/run_local_monkey.py @@ -4,10 +4,10 @@ import stat import subprocess from pathlib import Path from shutil import copyfileobj +from typing import Sequence from monkey_island.cc.repository import IAgentBinaryRepository, RetrievalError from monkey_island.cc.server_utils.consts import ISLAND_PORT -from monkey_island.cc.services.utils.network_utils import local_ip_addresses logger = logging.getLogger(__name__) @@ -15,9 +15,15 @@ AGENT_NAMES = {"linux": "monkey-linux-64", "windows": "monkey-windows-64.exe"} class LocalMonkeyRunService: - def __init__(self, data_dir: Path, agent_binary_repository: IAgentBinaryRepository): + def __init__( + self, + data_dir: Path, + agent_binary_repository: IAgentBinaryRepository, + ip_addresses: Sequence[str], + ): self._data_dir = data_dir self._agent_binary_repository = agent_binary_repository + self._ips = ip_addresses def run_local_monkey(self): # get the monkey executable suitable to run on the server @@ -59,7 +65,7 @@ class LocalMonkeyRunService: # run the monkey try: - ip = local_ip_addresses()[0] + ip = self._ips[0] port = ISLAND_PORT args = [str(dest_path), "m0nk3y", "-s", f"{ip}:{port}"] diff --git a/monkey/monkey_island/cc/services/utils/network_utils.py b/monkey/monkey_island/cc/services/utils/network_utils.py index e68a68748..8af255ee0 100644 --- a/monkey/monkey_island/cc/services/utils/network_utils.py +++ b/monkey/monkey_island/cc/services/utils/network_utils.py @@ -58,7 +58,7 @@ else: # lot of times during the report generation. This means that if the interfaces of the Island machine # change, the Island process needs to be restarted. @lru(maxsize=1) -def local_ip_addresses() -> Sequence[str]: +def get_ip_addresses() -> Sequence[str]: ip_list = [] for interface in interfaces(): addresses = ifaddresses(interface).get(AF_INET, []) diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOnAWS/AWSRunOptions.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOnAWS/AWSRunOptions.js index e6c2290b2..a91da1c36 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOnAWS/AWSRunOptions.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOnAWS/AWSRunOptions.js @@ -32,11 +32,11 @@ const getContents = (props) => { }, []); function getIps() { - authComponent.authFetch('/api') + authComponent.authFetch('/api/island/ip-addresses') .then(res => res.json()) - .then(res => { - setAllIPs(res['ip_addresses']); - setSelectedIp(res['ip_addresses'][0]); + .then(ip_addresses => { + setAllIPs(ip_addresses); + setSelectedIp(ip_addresses[0]); }); } diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js index 99f7f92b7..87a872c5f 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js @@ -23,8 +23,7 @@ function RunOptions(props) { if (initialized === false) { authComponent.authFetch(IP_ADDRESSES_URL) .then(res => res.json()) - .then(res => { - let ipAddresses = res.ip_addresses; + .then(ipAddresses => { setIps(ipAddresses); setInitialized(true); });