| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 | # SPDX-License-Identifier: AGPL-3.0-or-later""".. _botdetection.ip_lists:Method ``ip_lists``-------------------The ``ip_lists`` method implements IP :py:obj:`block- <block_ip>` and:py:obj:`pass-lists <pass_ip>`... code:: toml   [botdetection.ip_lists]   pass_ip = [    '167.235.158.251', # IPv4 of check.searx.space    '192.168.0.0/16',  # IPv4 private network    'fe80::/10'        # IPv6 linklocal   ]   block_ip = [      '93.184.216.34', # IPv4 of example.org      '257.1.1.1',     # invalid IP --> will be ignored, logged in ERROR class   ]"""# pylint: disable=unused-argumentfrom __future__ import annotationsfrom typing import Tuplefrom ipaddress import (    ip_network,    IPv4Address,    IPv6Address,)from . import configfrom ._helpers import loggerlogger = logger.getChild('ip_limit')SEARXNG_ORG = [    # https://github.com/searxng/searxng/pull/2484#issuecomment-1576639195    '167.235.158.251',  # IPv4 check.searx.space    '2a01:04f8:1c1c:8fc2::/64',  # IPv6 check.searx.space]"""Passlist of IPs from the SearXNG organization, e.g. `check.searx.space`."""def pass_ip(real_ip: IPv4Address | IPv6Address, cfg: config.Config) -> Tuple[bool, str]:    """Checks if the IP on the subnet is in one of the members of the    ``botdetection.ip_lists.pass_ip`` list.    """    if cfg.get('botdetection.ip_lists.pass_searxng_org', default=True):        for net in SEARXNG_ORG:            net = ip_network(net, strict=False)            if real_ip.version == net.version and real_ip in net:                return True, f"IP matches {net.compressed} in SEARXNG_ORG list."    return ip_is_subnet_of_member_in_list(real_ip, 'botdetection.ip_lists.pass_ip', cfg)def block_ip(real_ip: IPv4Address | IPv6Address, cfg: config.Config) -> Tuple[bool, str]:    """Checks if the IP on the subnet is in one of the members of the    ``botdetection.ip_lists.block_ip`` list.    """    block, msg = ip_is_subnet_of_member_in_list(real_ip, 'botdetection.ip_lists.block_ip', cfg)    if block:        msg += " To remove IP from list, please contact the maintainer of the service."    return block, msgdef ip_is_subnet_of_member_in_list(    real_ip: IPv4Address | IPv6Address, list_name: str, cfg: config.Config) -> Tuple[bool, str]:    for net in cfg.get(list_name, default=[]):        try:            net = ip_network(net, strict=False)        except ValueError:            logger.error("invalid IP %s in %s", net, list_name)            continue        if real_ip.version == net.version and real_ip in net:            return True, f"IP matches {net.compressed} in {list_name}."    return False, f"IP is not a member of an item in the f{list_name} list"
 |