Ejemplo n.º 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()
Ejemplo n.º 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)
Ejemplo n.º 3
0
def main():
    setup_logging('ddns2.log')
    config = get_config('router', 'ddns')

    logging.info("starting ddns")

    ddns_config = config['DDNS_CONFIG']
    resource4 = ddns_config['resource4']
    resource6 = ddns_config['resource6']
    domain = ddns_config['domain']
    pppoe_interface = ddns_config['pppoe_interface']
    ipv6_pool_name = ddns_config['ipv6_pool_name']

    logging.info("loaded config, connecting to router")

    router_api = RouterOsApiPool(**(config['ROUTER_CONFIG'])).get_api()

    while True:
        try:
            for local_ip, resource in ((get_local_ipv4(router_api,
                                                       pppoe_interface),
                                        resource4),
                                       (get_local_ipv6(router_api,
                                                       ipv6_pool_name),
                                        resource6)):
                current_ip, record_name = get_current_record_ip(
                    domain, resource)
                if local_ip is not None and current_ip != local_ip:
                    logging.info(
                        f"updating record {record_name} from {current_ip} to {local_ip}"
                    )
                    update_record_ip(domain, resource, local_ip)
            heartbeat()
        except RouterOsApiConnectionError:
            logging.warning('resetting router api')
            router_api = RouterOsApiPool(
                **(get_config('router')['ROUTER_CONFIG'])).get_api()
        except JSONDecodeError:
            logging.exception('linode JSONDecodeError')
        except (requests.exceptions.RequestException, OSError):
            logging.exception('RequestException issues')
        except:
            logging.exception("error")
            raise
        finally:
            sleep(30)
Ejemplo n.º 4
0
def main():
    set_routes = set()
    add_routes = set()
    setup_logging('routes.log')
    config = get_config('router')
    router_key = config['ROUTER_CONFIG']
    router_api = RouterOsApiPool(**router_key).get_api()
    route = router_api.get_resource('/ip/route')
    load_existing_routes(route, set_routes)
    connections = router_api.get_resource('/ip/firewall/connection')
    while True:
        heartbeat()
        add_routes.clear()
        add_fast_routes(add_routes, connections)
        new_routes, remove_routes = load_address_list(router_api, set_routes,
                                                      add_routes)
        if new_routes:
            add_new_routes(route, new_routes, remove_routes)
            set_routes -= remove_routes
            set_routes = set_routes.union(new_routes)
        sleep(30)
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
def main_loop(session_key, session):
    res = session.get('http://192.168.100.1/reseau-pa3-frequencecable.html')
    res.raise_for_status()

    if 'document.write(AccessMemberLimit);' in res.text:
        logging.warning(
            "Permission denied, another user is already logged; sleeping 20 seconds"
        )
        sleep(20)
        return session_key

    if '>location.href="/login.html"<' in res.text:
        logging.info("logging in to session")
        # login
        res = session.get('http://192.168.100.1/login.html')
        res.raise_for_status()
        session_key = session_key_matcher.match(res.text).group(1)
        logging.info("session key is {}".format(session_key))
        res = session.post(
            f'http://192.168.100.1/postlogin.cgi?sessionKey={session_key}',
            data={
                'sessionKey': session_key,
                'loginUsername': MODEM_USER,
                'loginPassword': MODEM_PASSWORD,
            })
        if 'var RefreshPage = ' not in res.text:
            logging.warning("failed to login")
            return session_key
        logging.info(f"cookie is {session.cookies}")
        return session_key

    if not session.cookies:
        logging.warning(
            f"need to force logout and log back in for reboot to work")
        session.get('http://192.168.100.1/logout.html').raise_for_status()
        return ''

    new_session_key = session_key_matcher.match(res.text).group(1)
    if new_session_key and new_session_key != session_key:
        session_key = new_session_key

    m = error_counters_matcher.match(res.text)
    correctable = int(m.group(1))
    uncorrectable = int(m.group(2))

    if uncorrectable > 1:
        logging.warning(
            "found {} correctable and {} uncorrectable errors".format(
                correctable, uncorrectable))
        logging.warning("disabling cable modem route")
        router_api = RouterOsApiPool(**ROUTER_KEY).get_api()
        route = router_api.get_resource('/ip/route')
        route_id = route.get(distance='15')[0]['id']
        route.set(id=route_id, disabled='no')

        logging.warning(
            "restarting cable modem; session key is {}, cookies {}".format(
                session_key, session.cookies))

        res = session.post(
            f'http://192.168.100.1/reseau-pa3-frequencecable.cgi?sessionKey={session_key}',
            data={
                'sessionKey': session_key,
                'CmStartupDsFreq': '999999',
                'action': '1',
            })
        res.raise_for_status()
        if 'Invalid Session Key' in res.text:
            logging.warning(
                'Invalid Session Key error, logging out and retrying')
            session.get('http://192.168.100.1/logout.html').raise_for_status()
            return ''

        logging.warning("disabling eth interface on router")
        eth = router_api.get_resource('/interface')
        eth_id = eth.get(name='wan-hot')[0]['id']
        eth.set(id=eth_id, disabled='yes')

        logging.warning("waiting 125 seconds")
        sleep(120)

        eth.set(id=eth_id, disabled='no')
        logging.warning("reenabling cable modem interface")
        sleep(5)

        logging.warning("reenabling cable modem route")
        route.set(id=route_id, disabled='yes')

    return session_key
Ejemplo n.º 7
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}'
            )
    def connect(self):

        self.connection = RouterOsApiPool(host=self.hostname, username=self.username, password=self.password,
                                     plaintext_login=True)
        return self.connection
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)