diff --git a/src/DosAtk.cpp b/src/DosAtk.cpp index 41825a6..5ff6357 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) { @@ -222,42 +242,38 @@ bool is_numeric(const std::string& s) { 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 +283,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 +301,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 +382,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 +}