diff --git a/GITEA_INSTRUCTIONS.md b/GITEA_INSTRUCTIONS.md new file mode 100644 index 0000000..a6a9919 --- /dev/null +++ b/GITEA_INSTRUCTIONS.md @@ -0,0 +1,73 @@ +# Инструкция: Удаленный запуск анализатора IP через Gitea Actions + +Эта инструкция поможет вам настроить автоматический или ручной запуск скрипта `ip_analyzer.py` на удаленном сервере с использованием встроенного CI/CD Gitea (Gitea Actions). + +## Шаг 1: Подготовка репозитория в Gitea + +1. Создайте новый репозиторий в вашем инстансе Gitea (или используйте существующий). +2. Загрузите в корень репозитория файл `ip_analyzer.py`. + +## Шаг 2: Включение Gitea Actions + +1. Перейдите в настройки вашего репозитория в Gitea (`Настройки` -> `Общие`). +2. Найдите раздел **Репозиторий (Repository)** -> **Дополнительные возможности (Advanced Settings)**. +3. Поставьте галочку **Включить действия репозитория (Enable Repository Actions)**. +4. Нажмите `Сохранить`. + +*(Примечание: Убедитесь, что администратор Gitea настроил и подключил Gitea Runner для вашего сервера. Без активного раннера (Runner) сценарии выполняться не будут).* + +## Шаг 3: Создание Workflow (сценария CI/CD) + +Мы создадим сценарий, который позволит запускать скрипт вручную прямо из веб-интерфейса Gitea, передавая нужный IP-адрес как параметр перед запуском. + +1. В корне вашего репозитория создайте директорию `.gitea/workflows/` (именно `.gitea`, а не `.github`, хотя Gitea Actions совместимы с синтаксисом GitHub). +2. Внутри этой директории создайте файл `analyze-ip.yaml` (полный путь: `.gitea/workflows/analyze-ip.yaml`). +3. Вставьте в этот файл следующий код: + +```yaml +name: IP Analyzer + +# Разрешаем ручной запуск (workflow_dispatch) с вводом параметров +on: + workflow_dispatch: + inputs: + ip_address: + description: 'IP-адрес для анализа' + required: true + default: '8.8.8.8' + +jobs: + analyze: + runs-on: ubuntu-latest # Укажите здесь метку вашего Gitea Runner (например, ubuntu-latest, debian и т.д.) + steps: + - name: Checkout кода + uses: actions/checkout@v3 + + - name: Установка Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - name: Запуск анализатора + run: | + echo "Запуск скрипта для IP: ${{ github.event.inputs.ip_address }}" + python ip_analyzer.py ${{ github.event.inputs.ip_address }} +``` + +4. Закоммитьте и отправьте (push) этот файл в Gitea-репозиторий. + +## Шаг 4: Запуск проверки через веб-интерфейс Gitea + +1. Откройте ваш репозиторий в Gitea. +2. В верхнем меню перейдите на вкладку **Действия (Actions)**. +3. В левом боковом меню выберите ваш workflow: `IP Analyzer`. +4. В правой части экрана (вверху списка запусков) нажмите кнопку **Запустить процесс (Run Workflow)**. +5. Появится выпадающее меню. В поле `ip_address` введите IP-адрес сервера, который вы хотите проверить (например, `1.1.1.1` или IP нужного сервера). +6. Нажмите зеленую кнопку запуска. + +## Шаг 5: Просмотр результатов + +1. После запуска появится новая задача в списке с желтым значком "В процессе". Кликните на неё. +2. Нажмите на блок `analyze` (название задачи). +3. Перед вами откроется консоль Gitea Runner'а. +4. Раскройте шаг **Запуск анализатора**. В нем вы увидите подробный текстовый вывод работы вашего скрипта `ip_analyzer.py` со всей собранной информацией об IP-адресе. \ No newline at end of file diff --git a/ip_analyzer.py b/ip_analyzer.py new file mode 100644 index 0000000..2b874d2 --- /dev/null +++ b/ip_analyzer.py @@ -0,0 +1,139 @@ +import argparse +import socket +import subprocess +import platform +import json +import urllib.request +import urllib.error +import concurrent.futures + + +def get_ip_info(ip): + """Получает общую информацию об IP через ip-api.com""" + url = f"http://ip-api.com/json/{ip}?fields=status,message,country,countryCode,region,regionName,city,zip,lat,lon,timezone,isp,org,as,query" + try: + # Притворяемся браузером, чтобы избежать блокировок + req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'}) + with urllib.request.urlopen(req, timeout=10) as response: + data = json.loads(response.read().decode()) + return data + except Exception as e: + return {"error": str(e)} + + +def check_ping(ip, count=4): + """Измеряет средний пинг до сервера с помощью системной утилиты ping""" + # Выбираем правильный параметр в зависимости от ОС: Windows использует -n, Linux/Mac -c + param = '-n' if platform.system().lower() == 'windows' else '-c' + command = ['ping', param, str(count), ip] + + try: + output = subprocess.check_output(command, stderr=subprocess.STDOUT, universal_newlines=True) + return output + except subprocess.CalledProcessError as e: + return e.output + except Exception as e: + return str(e) + + +def check_port(ip, port, timeout=2): + """Проверяет доступность определенного TCP-порта""" + try: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.settimeout(timeout) + result = sock.connect_ex((ip, port)) + return result == 0 + except Exception: + return False + + +def check_dnsbl(ip): + """Проверяет IP в популярных базах DNSBL (спам-базы и черные списки)""" + dnsbl_lists = [ + "zen.spamhaus.org", + "b.barracudacentral.org", + "bl.spamcop.net", + "cbl.abuseat.org", + "dnsbl.sorbs.net" + ] + + # Разворачиваем IP для DNS-запроса (например: 1.2.3.4 -> 4.3.2.1) + try: + reversed_ip = ".".join(reversed(ip.split("."))) + except Exception: + return {"error": "Неверный формат IP-адреса для проверки в DNSBL"} + + results = {} + for dnsbl in dnsbl_lists: + query = f"{reversed_ip}.{dnsbl}" + try: + # Если IP в базе, DNS вернет loopback адрес (обычно 127.0.0.x) + answers = socket.gethostbyname(query) + results[dnsbl] = f"В ЧЕРНОМ СПИСКЕ (ответ: {answers})" + except socket.gaierror: + # Имя не разрешено, значит IP нет в базе, он чист + results[dnsbl] = "Чисто" + except Exception as e: + results[dnsbl] = f"Ошибка проверки: {e}" + + return results + + +def main(): + parser = argparse.ArgumentParser(description="Скрипт для подробного анализа IP-адреса сервера.") + parser.add_argument("ip", help="IP-адрес для анализа") + args = parser.parse_args() + ip = args.ip + + print(f"{'=' * 50}") + print(f"Анализ IP-адреса: {ip}") + print(f"{'=' * 50}\n") + + # 1. Информация о локации и провайдере + print("[*] 1. Получение общей информации и геолокации...") + info = get_ip_info(ip) + if info.get('status') == 'success': + print(f" Страна: {info.get('country')} ({info.get('countryCode')})") + print(f" Регион: {info.get('regionName')}, {info.get('city')} {info.get('zip', '')}") + print(f" Временная: {info.get('timezone')}") + print(f" Координаты: Lat: {info.get('lat')}, Lon: {info.get('lon')}") + print(f" Провайдер: {info.get('isp')}") + print(f" Организация: {info.get('org')}") + print(f" AS: {info.get('as')}") + else: + print(f" Не удалось получить информацию. Ответ: {info}") + + # 2. Проверка популярных портов + print("\n[*] 2. Проверка доступности портов (Сервисы)...") + ports_to_check = {'HTTP (80)': 80, 'HTTPS (443)': 443, 'SSH (22)': 22, 'RDP (3389)': 3389, 'FTP (21)': 21} + with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: + future_to_port = {executor.submit(check_port, ip, port): name for name, port in ports_to_check.items()} + for future in concurrent.futures.as_completed(future_to_port): + port_name = future_to_port[future] + try: + is_open = future.result() + status = "Открыт" if is_open else "Закрыт / Заблокирован Firewall" + print(f" Порт {port_name:12}: {status}") + except Exception as e: + print(f" Порт {port_name:12}: Ошибка проверки ({e})") + + # 3. Базы блокировок + print("\n[*] 3. Проверка по базам блокировок (DNSBL / Spamhaus)...") + dnsbl_results = check_dnsbl(ip) + if "error" in dnsbl_results: + print(f" {dnsbl_results['error']}") + else: + for db, res in dnsbl_results.items(): + print(f" {db:25}: {res}") + + # 4. Проверка пинга + print("\n[*] 4. Измерение пинга до локации (ICMP)...") + ping_result = check_ping(ip) + # Выводим результат пинга с небольшим отступом для красоты + for line in ping_result.splitlines(): + if line.strip(): + print(f" {line}") + + +if __name__ == "__main__": + main() \ No newline at end of file