From a96165b7fa4535274eed91c7a850b406f04b2ca2 Mon Sep 17 00:00:00 2001 From: AleksanovED Date: Tue, 25 Mar 2025 11:09:18 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B8=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/DosAtk.cpp | 368 ++++++++++++++++++++++++++++--------------------- 1 file changed, 211 insertions(+), 157 deletions(-) diff --git a/src/DosAtk.cpp b/src/DosAtk.cpp index e4ea23f..9ca946f 100644 --- a/src/DosAtk.cpp +++ b/src/DosAtk.cpp @@ -1,15 +1,14 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include // Для работы с вводом-выводом (cout, cin и др.) +#include // Стандартная библиотека C (функции работы с памятью, преобразования типов и др.) +#include // Для работы со строками string +#include // Для работы с временем и таймерами +#include // Функции работы со временем C (time_t, localtime и др.) +#include // Для форматированного вывода (setw, setprecision и др.) +#include // Для разбора аргументов командной строки +#include // Функции для работы с символами (isdigit, isalpha и др.) +#include // Библиотека libcurl для HTTP-запросов (отправка в Telegram) +// Глобальные переменные std::string attack_type; // Тип атаки: scan или syn std::string domain; // Доменное Имя std::string ip; // Ip жертвы @@ -63,63 +62,73 @@ int my_check_params(int argc, char **argv) debug_msg += argv[i]; debug_msg += " "; } - printf("begin my_check_params (argc: %i, argv: %s)\n", argc, debug_msg.c_str()); + printf("begin my_check_params (argc: %i, argv: %s)\n", argc, debug_msg.c_str()); // debug + // Обрабатываем аргументы командной строки с помощью getopt_long + // Цикл продолжается, пока getopt_long возвращает валидные опции (-1 означает конец опций) while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { switch (opt) { - case 'a': - attack_type = optarg; + case 'a': // Обработка опции -a (--attack) + attack_type = optarg; // Сохраняем тип атаки (scan/flood) break; - case 'd': - domain = optarg; + case 'd': // Обработка опции -d (--domain) + domain = optarg; // Сохраняем доменное имя цели break; - case 'i': - ip = optarg; + case 'i': // Обработка опции -i (--ip) + ip = optarg; // Сохраняем IP-адрес цели break; - case 'p': - port = optarg; + case 'p': // Обработка опции -p (--port) + port = optarg; // Сохраняем номер порта break; - case 'l': - log_file = optarg; + case 'l': // Обработка опции -l (--log) + log_file = optarg; // Сохраняем путь к лог-файлу break; - case 't': - telegram_id = optarg; + case 't': // Обработка опции -t (--telegram) + telegram_id = optarg; // Сохраняем Telegram ID break; - case 'b': - telegram_token = optarg; + case 'b': // Обработка опции -b (--token) + telegram_token = optarg; // Сохраняем токен бота Telegram break; - case 'h': - status = 0; + case 'h': // Обработка опции -h (--help) + status = 0; // Устанавливаем статус "показать справку" break; - case '?': - status = -101; + case '?': // Обработка неизвестной опции + status = -101; // Устанавливаем статус "неизвестная опция" break; } } + // Проверяем корректность введенных параметров if (status != 0 && status != -101) { - if (attack_type != "flood" && attack_type != "scan") { - status = -1; - } - else if (attack_type == "scan" && domain.empty() && ip.empty()) { - status = -10; - } - else if (attack_type == "flood" && domain.empty() && ip.empty()) { - status = -20; - } - else if ((!telegram_id.empty() && telegram_token.empty()) || (telegram_id.empty() && !telegram_token.empty())) { - status = -600; - } - else if (attack_type == "scan") { - status = 1; - } - else if (attack_type == "flood") { - status = 2; - } + // Проверяем валидность типа атаки + if (attack_type != "flood" && attack_type != "scan") { + status = -1; // Некорректный тип атаки + } + // Для сканирования портов должна быть указана цель (домен или IP) + else if (attack_type == "scan" && domain.empty() && ip.empty()) { + status = -10; // Не указана цель для сканирования + } + // Для флуд-атаки должна быть указана цель (домен или IP) + else if (attack_type == "flood" && domain.empty() && ip.empty()) { + status = -20; // Не указана цель для флуда + } + // Проверяем, что если указан Telegram ID или токен, то должны быть указаны оба + else if ((!telegram_id.empty() && telegram_token.empty()) || + (telegram_id.empty() && !telegram_token.empty())) { + status = -600; // Неполные данные для Telegram + } + // Если все проверки пройдены и тип атаки - сканирование + else if (attack_type == "scan") { + status = 1; // Валидные параметры для сканирования + } + // Если все проверки пройдены и тип атаки - флуд + else if (attack_type == "flood") { + status = 2; // Валидные параметры для флуда + } } - printf("end my_check_params status: %i\n", status); + printf("end my_check_params status: %i\n", status); // debug return status; } @@ -127,10 +136,12 @@ int my_check_params(int argc, char **argv) // формирует сообщение с описанием произошедшей ошибки void my_diag(int status) { - printf("begin my_diag (status: %i)\n", status); + // Отладочный вывод - начало работы функции (можно отключить в релизной версии) + printf("begin my_diag (status: %i)\n", status); // debug + // Выбор сообщения в зависимости от кода ошибки switch (status) { - case 0: + case 0: // Специальный случай - вывод справки по использованию printf("Usage: ./DosAtk [options]\n" "Required:\n" " -a, --attack TYPE Type of attack (scan|flood)\n" @@ -142,125 +153,142 @@ void my_diag(int status) " -t, --telegram ID Telegram ID\n" " -b, --token TOKEN Telegram bot token\n"); break; - case -1: + case -1: // Некорректный тип атаки printf("Error: Invalid attack type!\n--help for more info\n"); break; - case -10: + case -10: // Отсутствуют обязательные параметры для сканирования портов printf("Error: Missing required parameters for port scanning!\n--help for more info\n"); break; - case -20: + case -20: // Отсутствуют обязательные параметры для SYN flood атаки printf("Error: Missing required parameters for tcp syn dos attack!\n--help for more info\n"); break; - case -101: + case -101: // Встречена неизвестная опция командной строки printf("Error: Unknown option!\n.--help for info\n"); break; - case -600: + case -600: // Неполные данные для Telegram-уведомлений printf("Error: To use telegram integration both telegram_id and telegram_token have to be provided!\n.--help for info\n"); break; } - printf("end my_diag\n"); + + // Отладочный вывод - завершение работы функции + printf("end my_diag\n"); // debug } -// Функция для экранирования спецсимволов в JSON +// Функция для экранирования специальных символов в строке перед использованием в JSON +// Принимает: const std::string& s - исходная строка для обработки +// Возвращает: std::string - строка с экранированными спецсимволами std::string escape_json(const std::string& s) { - std::string result; + std::string result; // Результирующая строка с экранированными символами + // Проходим по каждому символу входной строки for (char c : s) { + // Обрабатываем специальные символы JSON switch (c) { - case '"': result += "\\\""; break; - case '\\': result += "\\\\"; break; - case '\b': result += "\\b"; break; - case '\f': result += "\\f"; break; - case '\n': result += "\\n"; break; - case '\r': result += "\\r"; break; - case '\t': result += "\\t"; break; - default: result += c; break; + case '"': result += "\\\""; break; // Экранирование двойных кавычек + case '\\': result += "\\\\"; break; // Экранирование обратного слеша + case '\b': result += "\\b"; break; // Экранирование backspace + case '\f': result += "\\f"; break; // Экранирование formfeed + case '\n': result += "\\n"; break; // Экранирование новой строки + case '\r': result += "\\r"; break; // Экранирование возврата каретки + case '\t': result += "\\t"; break; // Экранирование табуляции + default: result += c; break; // Все остальные символы добавляем как есть } } - return result; + return result; // Возвращаем обработанную строку } // Проверка, является ли строка числом (включая отрицательные) bool is_numeric(const std::string& s) { - size_t start; - if (s.empty()) return false; + size_t start; // Индекс, с которого начинать проверку цифр + if (s.empty()) return false; // Пустая строка не может быть числом + // Проверяем наличие знака минус в начале start = 0; if (s[0] == '-') { + // Строка из одного минуса не является числом if (s.size() == 1) return false; + // Если минус есть, начинаем проверку с следующего символа start = 1; } - + // Проверяем все оставшиеся символы на цифры for (size_t i = start; i < s.size(); ++i) { + // Найден нецифровой символ - строка не число if (!isdigit(s[i])) return false; } + // Все проверки пройдены - строка является числом return true; } int my_msg() { - CURL* curl; - std::string escaped_msg; - std::cout << msg << std::endl; - std::string chat_id_field; - std::string json_data; - struct curl_slist* headers; - headers = nullptr; - long http_code; - CURLcode res; + // Инициализация переменных для работы с CURL + CURL* curl; // Указатель на CURL-объект + std::string escaped_msg; // Экранированное сообщение для JSON + std::cout << msg << std::endl; // Вывод сообщения в консоль (для отладки) + std::string chat_id_field; // Поле chat_id для JSON + std::string json_data; // Итоговый JSON для отправки + struct curl_slist* headers; // Заголовки HTTP-запроса + headers = nullptr; // Инициализация заголовков + long http_code; // HTTP-код ответа + CURLcode res; // Код результата CURL-операции + // Проверка наличия обязательных параметров Telegram if (telegram_token.empty() || telegram_id.empty()) { - return 0; // Интеграция не настроена + return 0; // Интеграция с Telegram не настроена (отсутствует токен или ID) } + // Инициализация CURL curl = curl_easy_init(); if (!curl) return 6; // Ошибка инициализации CURL - // Экранируем сообщение + // Экранирование спецсимволов в сообщении для JSON escaped_msg = escape_json(msg); - // Формируем поле chat_id + // Формирование поля chat_id в зависимости от типа ID (число или строка) if (is_numeric(telegram_id)) { - chat_id_field = "\"chat_id\": " + telegram_id; + chat_id_field = "\"chat_id\": " + telegram_id; // Числовой ID } else { - chat_id_field = "\"chat_id\": \"" + telegram_id + "\""; + chat_id_field = "\"chat_id\": \"" + telegram_id + "\""; // Строковый ID } - // Формируем JSON + // Сборка JSON-запроса json_data = "{" + chat_id_field + ", \"text\": \"" + escaped_msg + "\"}"; - // Настраиваем заголовоки + // Установка заголовка Content-Type headers = curl_slist_append(headers, "Content-Type: application/json"); - // Настраиваем параметры CURL - curl_easy_setopt(curl, CURLOPT_URL, ("https://api.telegram.org/bot" + telegram_token + "/sendMessage").c_str()); - curl_easy_setopt(curl, CURLOPT_POST, 1L); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data.c_str()); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl/7.68.0"); + // Настройка параметров CURL-запроса + curl_easy_setopt(curl, CURLOPT_URL, ("https://api.telegram.org/bot" + telegram_token + "/sendMessage").c_str()); // URL API Telegram + curl_easy_setopt(curl, CURLOPT_POST, 1L); // Использовать POST-метод + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data.c_str()); // Тело запроса (JSON) + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); // Заголовки запроса + curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl/7.68.0"); // User-Agent - // Игнорируем вывод ответа + // Игнорирование вывода ответа (пустая функция обратного вызова) curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, [](void*, size_t size, size_t nmemb, void*) -> size_t { return size * nmemb; }); - // Выполняем запрос + // Выполнение HTTP-запроса res = curl_easy_perform(curl); + // Получение HTTP-кода ответа http_code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); - // Освобождаем ресурсы - curl_slist_free_all(headers); - curl_easy_cleanup(curl); + // Освобождение ресурсов + curl_slist_free_all(headers); // Очистка заголовков + curl_easy_cleanup(curl); // Завершение работы CURL - if (res != CURLE_OK) return 5; + // Обработка ошибок CURL + if (res != CURLE_OK) return 5; // Ошибка выполнения запроса + // Обработка HTTP-кодов ответа switch (http_code) { - case 200: return 0; - case 401: return 1; - case 400: return 2; - case 404: return 3; + case 200: return 0; // Успешный запрос + case 401: return 1; // Ошибка авторизации (неверный токен) + case 400: return 2; // Неверный запрос + case 404: return 3; // Ресурс не найден default: - if (http_code >= 500) return 4; - return 4; + if (http_code >= 500) return 4; // Ошибка сервера + return 4; // Прочие ошибки } } // Данная функция записывает в файл лога сообщение @@ -272,33 +300,43 @@ int my_log() // Данная функция завершает программу и рассчитывает итоговое время выполнения программы void my_fin() { + // Фиксируем время окончания работы программы auto end_timestamp = std::chrono::system_clock::now(); + // Преобразуем время окончания в time_t и миллисекунды auto end_time_t = std::chrono::system_clock::to_time_t(end_timestamp); auto end_ms = std::chrono::duration_cast(end_timestamp.time_since_epoch()) % 1000; + // Вычисляем продолжительность работы программы auto duration = end_timestamp - start_timestamp; + // Разбиваем продолжительность на компоненты auto hours = std::chrono::duration_cast(duration); auto minutes = std::chrono::duration_cast(duration % std::chrono::hours(1)); auto seconds = std::chrono::duration_cast(duration % std::chrono::minutes(1)); auto milliseconds = std::chrono::duration_cast(duration % std::chrono::seconds(1)); + // Выводим информацию о времени работы std::cout << "Worked for "; + // Для коротких периодов (<2 минут) выводим в секундах с дробной частью if (duration < std::chrono::minutes(2)) { double total_seconds = std::chrono::duration(duration).count(); std::cout << std::fixed << std::setprecision(3) << total_seconds << " seconds"; } else { + // Для длительных периодов выводим в формате ЧЧ:ММ:СС.мс if (hours.count() > 0) std::cout << hours.count() << "h "; if (minutes.count() > 0) std::cout << minutes.count() << "m "; std::cout << seconds.count() << "s " << milliseconds.count() << "ms"; } std::cout << std::endl; + // Выводим статистику по запросам std::cout << "Sent " << (n_ok_requests + n_fail_requests) << " requests (" << n_ok_requests << " ok, " << n_fail_requests << " failed)" << std::endl; + // Выводим точное время завершения работы std::cout << "DosAtk stopped at " << std::put_time(std::localtime(&end_time_t), "%Y-%m-%d %H:%M:%S") << "." << std::setfill('0') << std::setw(3) << end_ms.count() << std::endl; + // Завершаем программу с кодом 0 (успешное завершение) std::exit(0); } @@ -320,78 +358,91 @@ int my_udp() return 2; } -// Тело программы +// Главная функция программы - точка входа int main(int argc, char **argv) { - int check_params_status; - int log_status; - int dns_status; - int udp_status; - int tcp_syn_status; + // Объявление переменных для хранения статусов операций + int check_params_status; // Статус проверки параметров + int log_status; // Статус записи в лог + int dns_status; // Статус DNS-разрешения + int udp_status; // Статус UDP-атаки + int tcp_syn_status; // Статус TCP SYN-атаки - // ====== Тело программы ====== // - n_ok_requests = 0; - n_fail_requests = 0; - start_timestamp = std::chrono::system_clock::now(); + // ====== Инициализация программы ====== // + n_ok_requests = 0; // Счетчик успешных запросов + n_fail_requests = 0; // Счетчик неудачных запросов + start_timestamp = std::chrono::system_clock::now(); // Засекаем время начала - time_t now_time_t; - now_time_t = std::chrono::system_clock::to_time_t(start_timestamp); - - std::chrono::milliseconds ms; - ms = std::chrono::duration_cast(start_timestamp.time_since_epoch()) % 1000; + // Получаем текущее время в различных форматах + time_t now_time_t = std::chrono::system_clock::to_time_t(start_timestamp); + auto ms = std::chrono::duration_cast( + start_timestamp.time_since_epoch()) % 1000; + // Выводим информацию о времени запуска программы printf("Starting DosAtk at %04d-%02d-%02d %02d:%02d:%02d.%03ld\n", - std::localtime(&now_time_t)->tm_year + 1900, - std::localtime(&now_time_t)->tm_mon + 1, - std::localtime(&now_time_t)->tm_mday, - std::localtime(&now_time_t)->tm_hour, - std::localtime(&now_time_t)->tm_min, - std::localtime(&now_time_t)->tm_sec, - ms.count()); + std::localtime(&now_time_t)->tm_year + 1900, // Год (с 1900) + std::localtime(&now_time_t)->tm_mon + 1, // Месяц (0-11) + std::localtime(&now_time_t)->tm_mday, // День месяца + std::localtime(&now_time_t)->tm_hour, // Часы + std::localtime(&now_time_t)->tm_min, // Минуты + std::localtime(&now_time_t)->tm_sec, // Секунды + ms.count()); // Миллисекунды + // ====== Основная логика программы ====== // + // 1. Проверяем параметры командной строки check_params_status = my_check_params(argc, argv); + + // Обрабатываем результат проверки параметров switch (check_params_status) { - case 1: + case 1: // Режим сканирования портов (UDP) + // Пытаемся разрешить DNS (если указано доменное имя) dns_status = my_dns(); - if (dns_status == 0) + + if (dns_status == 0) // Если DNS разрешен успешно { + // Запускаем цикл UDP-атаки while (udp_status = my_udp()) { - if (udp_status == 2) + if (udp_status == 2) // Код завершения атаки { break; } - else if (udp_status < 0) + else if (udp_status < 0) // Обработка ошибок { - my_diag(udp_status); - log_status = my_log(); - if (log_status == 1) + my_diag(udp_status); // Выводим диагностику + log_status = my_log(); // Пытаемся записать в лог + if (log_status == 1) // Если требуется уведомление { - my_msg(); + my_msg(); // Отправляем сообщение } } } - log_status = my_log(); - my_msg(); - my_fin(); + // Завершающие действия после атаки + log_status = my_log(); // Логируем завершение + my_msg(); // Отправляем финальное сообщение + my_fin(); // Корректно завершаем программу } - else if (dns_status == 1) + else if (dns_status == 1) // Ошибка DNS-разрешения { - my_diag(check_params_status); - log_status = my_log(); - if (log_status == 0){ - my_fin(); + my_diag(check_params_status); // Выводим ошибку + log_status = my_log(); // Логируем ошибку + + if (log_status == 0) { // Если не требуется уведомление + my_fin(); // Просто завершаем программу } - else if (log_status == 1) + else if (log_status == 1) // Если требуется уведомление { - my_msg(); - my_fin(); + my_msg(); // Отправляем сообщение + my_fin(); // Завершаем программу } } break; - case 2: + + case 2: // Режим SYN-флуда (TCP) + // Аналогичная логика как для UDP-режима dns_status = my_dns(); + if (dns_status == 0) { while (tcp_syn_status = my_tcp_syn()) @@ -429,19 +480,22 @@ int main(int argc, char **argv) } } break; - default: - my_diag(check_params_status); - log_status = my_log(); - if (log_status == 0) + + default: // Некорректные параметры или запрос справки + my_diag(check_params_status); // Выводим диагностику + log_status = my_log(); // Логируем событие + + if (log_status == 0) // Без уведомления { - my_fin(); + my_fin(); // Завершаем программу } - else if (log_status == 1) + else if (log_status == 1) // С уведомлением { - my_msg(); - my_fin(); + my_msg(); // Отправляем сообщение + my_fin(); // Завершаем программу } break; } - return 0; -} + + return 0; // Возвращаем код успешного завершения +} \ No newline at end of file