Merge pull request #2167 from guardicore/2109-refactor-ip-addresses-resource

Refactor IPAddresses resource
This commit is contained in:
Shreya Malviya 2022-08-05 13:54:33 +05:30 committed by GitHub
commit 89b194d0ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 65 additions and 39 deletions

View File

@ -35,13 +35,14 @@ class DIContainer:
if not inspect.isclass(concrete_type): if not inspect.isclass(concrete_type):
raise TypeError( raise TypeError(
"Expected a class, but received an instance of type " "Expected a class, but received an instance of type "
f'"{concrete_type.__class__.__name__}"; Pass a class, not an instance, to ' f'"{DIContainer._format_type_name(concrete_type.__class__)}"; Pass a class, not an '
"register(), or use register_instance() instead" "instance, to register(), or use register_instance() instead"
) )
if not issubclass(concrete_type, interface): if not issubclass(concrete_type, interface):
raise TypeError( 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 self._type_registry[interface] = concrete_type
@ -56,8 +57,9 @@ class DIContainer:
""" """
if not isinstance(instance, interface): if not isinstance(instance, interface):
raise TypeError( raise TypeError(
f'The provided instance of type "{instance.__class__.__name__}" ' "The provided instance of type "
f"is not an instance of {interface.__name__}" f'"{DIContainer._format_type_name(instance.__class__)}" '
f"is not an instance of {DIContainer._format_type_name(interface)}"
) )
self._instance_registry[interface] = instance self._instance_registry[interface] = instance
@ -151,7 +153,9 @@ class DIContainer:
elif type_ in self._instance_registry: elif type_ in self._instance_registry:
return self._retrieve_registered_instance(type_) 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: def _construct_new_instance(self, arg_type: Type[T]) -> T:
try: try:
@ -182,3 +186,13 @@ class DIContainer:
""" """
convention_identifier = (type_, name) convention_identifier = (type_, name)
del_key(self._convention_registry, convention_identifier) 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_)

View File

@ -13,6 +13,7 @@ from monkey_island.cc.database import database, mongo
from monkey_island.cc.resources import ( from monkey_island.cc.resources import (
AgentBinaries, AgentBinaries,
ClearSimulationData, ClearSimulationData,
IPAddresses,
IslandLog, IslandLog,
PropagationCredentials, PropagationCredentials,
RemoteRun, 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.edge import Edge
from monkey_island.cc.resources.exploitations.manual_exploitation import ManualExploitation 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.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.island_mode import IslandMode
from monkey_island.cc.resources.local_run import LocalRun from monkey_island.cc.resources.local_run import LocalRun
from monkey_island.cc.resources.log import Log 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(TelemetryFeed)
api.add_resource(Log) api.add_resource(Log)
api.add_resource(IslandLog) 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 Spec: These two should be the same resource, GET for download and POST for upload
api.add_resource(PBAFileDownload) api.add_resource(PBAFileDownload)

View File

@ -19,7 +19,7 @@ from mongoengine import (
from monkey_island.cc.models.command_control_channel import CommandControlChannel 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.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.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): class ParentNotFoundError(Exception):
@ -123,7 +123,7 @@ class Monkey(Document):
def get_label_by_id(object_id): def get_label_by_id(object_id):
current_monkey = Monkey.get_single_monkey_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] 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 label = "MonkeyIsland - " + label
return label return label

View File

@ -4,3 +4,4 @@ from .clear_simulation_data import ClearSimulationData
from .island_log import IslandLog from .island_log import IslandLog
from .reset_agent_configuration import ResetAgentConfiguration from .reset_agent_configuration import ResetAgentConfiguration
from .propagation_credentials import PropagationCredentials from .propagation_credentials import PropagationCredentials
from .ip_addresses import IPAddresses

View File

@ -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.AbstractResource import AbstractResource
from monkey_island.cc.resources.request_authentication import jwt_required 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"] urls = ["/api/island/ip-addresses"]
def __init__(self, ip_addresses: Sequence[str]):
self._ips = ip_addresses
@jwt_required @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

View File

@ -6,7 +6,6 @@ from monkey_island.cc.database import mongo
from monkey_island.cc.resources.AbstractResource import AbstractResource from monkey_island.cc.resources.AbstractResource import AbstractResource
from monkey_island.cc.resources.request_authentication import jwt_required 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.infection_lifecycle import get_completed_steps
from monkey_island.cc.services.utils.network_utils import local_ip_addresses
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -29,7 +28,6 @@ class Root(AbstractResource):
@jwt_required @jwt_required
def get_server_info(self): def get_server_info(self):
return jsonify( return jsonify(
ip_addresses=local_ip_addresses(),
mongo=str(mongo.db), mongo=str(mongo.db),
completed_steps=get_completed_steps(), completed_steps=get_completed_steps(),
) )

View File

@ -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.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.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 PyWSGILoggingFilter # noqa: E402
from monkey_island.cc.setup import island_config_options_validator # 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 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(): 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( logger.info(
"To access the web interface, navigate to one of the the following URLs using your " "To access the web interface, navigate to one of the the following URLs using your "
f"browser: {web_interface_urls}" f"browser: {web_interface_urls}"

View File

@ -1,6 +1,7 @@
import json import json
import logging import logging
from pathlib import Path from pathlib import Path
from typing import Sequence
from pymongo import MongoClient 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 ( from monkey_island.cc.services.telemetry.processing.processing import (
TELEMETRY_CATEGORY_TO_PROCESSING_FUNC, 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 monkey_island.cc.setup.mongo.mongo_setup import MONGO_URL
from . import AuthenticationService 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(Path, "island_log_file_path", get_log_file_path(data_dir))
container.register_convention(str, "version_number", get_version()) 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): def _register_repositories(container: DIContainer, data_dir: Path):

View File

@ -9,7 +9,7 @@ from monkey_island.cc.database import mongo
from monkey_island.cc.models import Monkey from monkey_island.cc.models import Monkey
from monkey_island.cc.services.edge.displayed_edge import DisplayedEdgeService from monkey_island.cc.services.edge.displayed_edge import DisplayedEdgeService
from monkey_island.cc.services.edge.edge import EdgeService 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 from monkey_island.cc.services.utils.node_states import NodeStates
@ -110,7 +110,7 @@ class NodeService:
def get_monkey_label(monkey): def get_monkey_label(monkey):
# todo # todo
label = monkey["hostname"] + " : " + monkey["ip_addresses"][0] 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: if len(set(monkey["ip_addresses"]).intersection(ip_addresses)) > 0:
label = "MonkeyIsland - " + label label = "MonkeyIsland - " + label
return label return label
@ -118,7 +118,7 @@ class NodeService:
@staticmethod @staticmethod
def get_monkey_group(monkey): def get_monkey_group(monkey):
keywords = [] 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"]) keywords.extend(["island", "monkey"])
else: else:
monkey_type = "manual" if NodeService.get_monkey_manual_run(monkey) else "monkey" 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 # It's better to just initialize the island machine on reset I think
@staticmethod @staticmethod
def get_monkey_island_monkey(): def get_monkey_island_monkey():
ip_addresses = local_ip_addresses() ip_addresses = get_ip_addresses()
for ip_address in ip_addresses: for ip_address in ip_addresses:
monkey = NodeService.get_monkey_by_ip(ip_address) monkey = NodeService.get_monkey_by_ip(ip_address)
if monkey is not None: if monkey is not None:
@ -297,7 +297,7 @@ class NodeService:
@staticmethod @staticmethod
def get_monkey_island_node(): def get_monkey_island_node():
island_node = NodeService.get_monkey_island_pseudo_net_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() island_node["domain_name"] = socket.gethostname()
return island_node return island_node

View File

@ -19,7 +19,7 @@ from monkey_island.cc.services.reporting.pth_report import PTHReportService
from monkey_island.cc.services.reporting.report_generation_synchronisation import ( from monkey_island.cc.services.reporting.report_generation_synchronisation import (
safe_generate_regular_report, 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 AWSService
from . import aws_exporter from . import aws_exporter
@ -175,7 +175,7 @@ class ReportService:
@staticmethod @staticmethod
def get_island_cross_segment_issues(): def get_island_cross_segment_issues():
issues = [] issues = []
island_ips = local_ip_addresses() island_ips = get_ip_addresses()
for monkey in mongo.db.monkey.find( for monkey in mongo.db.monkey.find(
{"tunnel": {"$exists": False}}, {"tunnel": 1, "guid": 1, "hostname": 1} {"tunnel": {"$exists": False}}, {"tunnel": 1, "guid": 1, "hostname": 1}
): ):

View File

@ -4,10 +4,10 @@ import stat
import subprocess import subprocess
from pathlib import Path from pathlib import Path
from shutil import copyfileobj from shutil import copyfileobj
from typing import Sequence
from monkey_island.cc.repository import IAgentBinaryRepository, RetrievalError from monkey_island.cc.repository import IAgentBinaryRepository, RetrievalError
from monkey_island.cc.server_utils.consts import ISLAND_PORT 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__) logger = logging.getLogger(__name__)
@ -15,9 +15,15 @@ AGENT_NAMES = {"linux": "monkey-linux-64", "windows": "monkey-windows-64.exe"}
class LocalMonkeyRunService: 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._data_dir = data_dir
self._agent_binary_repository = agent_binary_repository self._agent_binary_repository = agent_binary_repository
self._ips = ip_addresses
def run_local_monkey(self): def run_local_monkey(self):
# get the monkey executable suitable to run on the server # get the monkey executable suitable to run on the server
@ -59,7 +65,7 @@ class LocalMonkeyRunService:
# run the monkey # run the monkey
try: try:
ip = local_ip_addresses()[0] ip = self._ips[0]
port = ISLAND_PORT port = ISLAND_PORT
args = [str(dest_path), "m0nk3y", "-s", f"{ip}:{port}"] args = [str(dest_path), "m0nk3y", "-s", f"{ip}:{port}"]

View File

@ -58,7 +58,7 @@ else:
# lot of times during the report generation. This means that if the interfaces of the Island machine # 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. # change, the Island process needs to be restarted.
@lru(maxsize=1) @lru(maxsize=1)
def local_ip_addresses() -> Sequence[str]: def get_ip_addresses() -> Sequence[str]:
ip_list = [] ip_list = []
for interface in interfaces(): for interface in interfaces():
addresses = ifaddresses(interface).get(AF_INET, []) addresses = ifaddresses(interface).get(AF_INET, [])

View File

@ -32,11 +32,11 @@ const getContents = (props) => {
}, []); }, []);
function getIps() { function getIps() {
authComponent.authFetch('/api') authComponent.authFetch('/api/island/ip-addresses')
.then(res => res.json()) .then(res => res.json())
.then(res => { .then(ip_addresses => {
setAllIPs(res['ip_addresses']); setAllIPs(ip_addresses);
setSelectedIp(res['ip_addresses'][0]); setSelectedIp(ip_addresses[0]);
}); });
} }

View File

@ -23,8 +23,7 @@ function RunOptions(props) {
if (initialized === false) { if (initialized === false) {
authComponent.authFetch(IP_ADDRESSES_URL) authComponent.authFetch(IP_ADDRESSES_URL)
.then(res => res.json()) .then(res => res.json())
.then(res => { .then(ipAddresses => {
let ipAddresses = res.ip_addresses;
setIps(ipAddresses); setIps(ipAddresses);
setInitialized(true); setInitialized(true);
}); });