Пример #1
0
class RouterOsApi:
    """
    Connects to the RouterOS device using the RouterOS API (with SSL by default).
    """
    def open(
        self,
        hostname: Optional[str],
        username: Optional[str],
        password: Optional[str],
        port: Optional[int],
        platform: Optional[str],
        extras: Optional[Dict[str, Any]] = None,
        configuration: Optional[Config] = None,
    ) -> None:
        """
        Connect to the device and populate the attribute :attr:`connection` with
        the underlying connection.

        Args:
            extras: Extra arguments for :class:`RouterOsApiPool`.
        """
        params = {
            "host": hostname,
            "username": username,
            "password": password,
            "port": port,
            "plaintext_login": True,
            "use_ssl": True
        }

        if extras is not None and extras.get("use_ssl", True):
            ssl_ctx = ssl.create_default_context()
            ssl_ctx.verify_mode = ssl.CERT_REQUIRED if extras.get(
                "ssl_verify", True) else ssl.CERT_NONE
            ssl_ctx.check_hostname = extras.get("ssl_verify_hostname", False)
            if "ssl_ca_file" in extras:
                ssl_ctx.load_verify_locations(extras.pop("ssl_ca_file"))
            params["ssl_context"] = ssl_ctx

        extras = extras or {}
        params.update(extras)
        self._pool = RouterOsApiPool(**params)
        self.connection = self._pool.get_api()

    def close(self) -> None:
        """Close the connection with the device"""
        self._pool.disconnect()
Пример #2
0
    def __init__(self, config):
        """Initialize the scanner."""
        self.last_results = None
        self.host = config[CONF_HOST]
        self.interface = config[CONF_INTERFACE]
        self.address_range = config[CONF_ADDRESS_RANGE]
        self.port = config[CONF_PORT]
        self.username = config[CONF_USERNAME]
        self.password = config[CONF_PASSWORD]
        self.scan_interval = config[CONF_SCAN_INTERVAL]
        self.success_init = True

        from routeros_api import RouterOsApiPool

        # Establish a connection to the Mikrotik router.
        connection = RouterOsApiPool(self.host,
                                     username=self.username,
                                     password=self.password,
                                     port=self.port)
        self.client = connection.get_api()
        self.leases = self.client.get_resource('/ip/dhcp-server/lease').get()
        _LOGGER.debug('Got leases %s', str(self.leases))

        # At this point it is difficult to tell if a connection is established.
        # So just check for null objects.
        if not connection.connected:
            self.success_init = False

        if self.success_init:
            _LOGGER.info('Successfully connected to Mikrotik device')

            # Reserve 2 seconds for API communication.
            self.ip_scan_args = {
                "duration": str(max(self.scan_interval.seconds - 2, 1))
            }
            if self.address_range:
                self.ip_scan_args["address-range"] = self.address_range
            if self.interface:
                self.ip_scan_args["interface"] = self.interface
            _LOGGER.debug('ip_scan_args %s', str(self.ip_scan_args))

            self._update_info()
        else:
            _LOGGER.error(
                'Failed to establish connection to Mikrotik device with IP: %s',
                self.host)
Пример #3
0
class RouterAPIConnection:
    ''' Base wrapper interface for the routeros_api library
    '''
    def __init__(self, router_name, config_entry):
        self.router_name = router_name
        self.config_entry = config_entry
        self.last_failure_timestamp = self.successive_failure_count = 0

        ctx = None
        if self.config_entry.use_ssl and self.config_entry.no_ssl_certificate:
            ctx = ssl.create_default_context()
            ctx.set_ciphers('ADH:@SECLEVEL=0')

        self.connection = RouterOsApiPool(
            host=self.config_entry.hostname,
            username=self.config_entry.username,
            password=self.config_entry.password,
            port=self.config_entry.port,
            plaintext_login=True,
            use_ssl=self.config_entry.use_ssl,
            ssl_verify=self.config_entry.ssl_certificate_verify,
            ssl_context=ctx)

        self.connection.socket_timeout = config_handler.system_entry(
        ).socket_timeout
        self.api = None

    def is_connected(self):
        if not (self.connection and self.connection.connected and self.api):
            return False
        try:
            self.api.get_resource('/system/identity').get()
            return True
        except (socket.error, socket.timeout, Exception) as exc:
            self._set_connect_state(success=False, exc=exc)
            return False

    def connect(self):
        connect_time = datetime.now()
        if self.is_connected() or self._in_connect_timeout(
                connect_time.timestamp()):
            return
        try:
            print(
                f'Connecting to router {self.router_name}@{self.config_entry.hostname}'
            )
            self.api = self.connection.get_api()
            self._set_connect_state(success=True, connect_time=connect_time)
        except (socket.error, socket.timeout, Exception) as exc:
            self._set_connect_state(success=False,
                                    connect_time=connect_time,
                                    exc=exc)
            #raise RouterAPIConnectionError

    def router_api(self):
        if not self.is_connected():
            self.connect()
        return self.api

    def _in_connect_timeout(self, connect_timestamp, quiet=True):
        connect_delay = self._connect_delay()
        if (connect_timestamp - self.last_failure_timestamp) < connect_delay:
            if not quiet:
                print(
                    f'{self.router_name}@{self.config_entry.hostname}: in connect timeout, {int(connect_delay - (connect_timestamp - self.last_failure_timestamp))}secs remaining'
                )
                print(
                    f'Successive failure count: {self.successive_failure_count}'
                )
            return True
        if not quiet:
            print(
                f'{self.router_name}@{self.config_entry.hostname}: OK to connect'
            )
            if self.last_failure_timestamp > 0:
                print(
                    f'Seconds since last failure: {connect_timestamp - self.last_failure_timestamp}'
                )
                print(
                    f'Prior successive failure count: {self.successive_failure_count}'
                )
        return False

    def _connect_delay(self):
        mktxp_entry = config_handler.system_entry()
        connect_delay = (
            1 + self.successive_failure_count /
            mktxp_entry.delay_inc_div) * mktxp_entry.initial_delay_on_failure
        return connect_delay if connect_delay < mktxp_entry.max_delay_on_failure else mktxp_entry.max_delay_on_failure

    def _set_connect_state(self,
                           success=False,
                           connect_time=datetime.now(),
                           exc=None):
        if success:
            self.last_failure_timestamp = 0
            self.successive_failure_count = 0
            print(
                f'{connect_time.strftime("%Y-%m-%d %H:%M:%S")} Connection to router {self.router_name}@{self.config_entry.hostname} has been established'
            )
        else:
            self.api = None
            self.successive_failure_count += 1
            self.last_failure_timestamp = connect_time.timestamp()
            print(
                f'{connect_time.strftime("%Y-%m-%d %H:%M:%S")} Connection to router {self.router_name}@{self.config_entry.hostname} has failed: {exc}'
            )
class API:
    def __init__(self, hostname, username, password):

        # Router Credentials
        self.hostname = hostname
        self.username = username
        self.password = password

        self.connection = None

        self.api = None

    ########################################################################################################################

    def connect(self):

        self.connection = RouterOsApiPool(host=self.hostname, username=self.username, password=self.password,
                                     plaintext_login=True)
        return self.connection

    ########################################################################################################################

    def get_api(self):
        try:
            self.api = self.connection.get_api()
            return self.api
        except RouterOsApiConnectionError:
            self.api = None

    ########################################################################################################################

    def check_api(self):
        if self.api:
            try:
                self.api.get_resource('log').get()
                return self.api

            except RouterOsApiConnectionError:
                self.api = None
                return self.api

    ########################################################################################################################

    def add_ips(self, address, list):

        if not self.check_api():
            return None

        prefix = self.api.get_resource('ip/firewall/address-list')
        prefix.add(address=address, list=list, timeout='35d')



    ########################################################################################################################

    def check_log(self):

        if not self.check_api():
            print("Failed attemtps could not create API instance, finnishing up script")
            return None

        logged_attempts = list()
        saved_attempts = list()
        log = self.api.get_resource('log').get()

        for entry in log:
            if "denied winbox/dude connect from" in entry["message"]:
                ip = re.findall(r"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b", entry["message"])[0]

                logged_attempt = dict()
                logged_attempt["id"], logged_attempt["ip"] = entry["id"], ip
                regex_string = "Modify your IP specifications Here"
                white_list = re.findall(regex_string, ip)

                if not white_list:
                    logged_attempts.append(logged_attempt)

        if len(saved_attempts) > 0:
            for saved_attempt in saved_attempts:
                if len(logged_attempts) > 0:
                    for logged_attempt in logged_attempts:
                        if saved_attempt["id"] != logged_attempt["id"]:
                            saved_attempts.append(logged_attempt)

        else:
            for logged_attempt in logged_attempts:
                saved_attempts.append(logged_attempt)

        return saved_attempts

    ########################################################################################################################

    def attempt_counter(self, attempts):

        if attempts:
            ip_counter = list()
            tested_ips = list()

            for attempt in attempts:
                attempt_ip = attempt["ip"]
                if len(ip_counter) > 0:
                    if attempt_ip not in tested_ips:
                        new_counter = dict()
                        new_counter["ip"], new_counter["counter"] = attempt_ip, 1

                        ip_counter.append(new_counter)
                        tested_ips.append(new_counter["ip"])

                    else:
                        for ip_counter_entry in ip_counter:
                            if attempt_ip == ip_counter_entry["ip"]:
                                ip_counter_entry["counter"] += 1
                else:
                    new_ip = dict()
                    new_ip["ip"] = attempt_ip
                    new_ip["counter"] = 1
                    ip_counter.append(new_ip)
                    tested_ips.append(new_ip["ip"])

            return ip_counter

        ip_counter = None
        return ip_counter

########################################################################################################################
########################################################################################################################

    def create_address_list(self, attempts):

        COMMAND_PATH = '/sys/script/'
        COMMAND_ID = 'ip_block'


        exsisting_ips = list()

        if not self.check_api():
            print("Error connecting to API while creating starting address list")
            return None

        if not attempts:
            return None

        blocked_subnet = self.api.get_resource('/ip/firewall/address-list').get()
        for subnet in blocked_subnet:
            if subnet["list"] == "BLOCKED_SUBNETS":
                exsisting_ips.append(subnet["address"])

        if attempts:
            for attempt in attempts:
                ip = attempt["ip"]
                if ip not in exsisting_ips:
                    print(ip)
                    self.add_ips(address=ip, list="BLOCKED_SUBNETS")

                    ip_inst = BlockedIP(ip, datetime.datetime.now())
                    IPs.insert_IP(ip_address=ip_inst.IP, date_time=ip_inst.date_time)

        self.connection.disconnect()

########################################################################################################################

    def full_sequence(self):
        self.connect()

        self.get_api()
        print(self.api)

        if not self.check_api():
            return None

        log = self.check_log()
        attempt_counter = self.attempt_counter(log)
        self.create_address_list(attempt_counter)