Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

БСТ1802 PING-LINUX Код 13.05.21

.docx
Скачиваний:
14
Добавлен:
18.05.2021
Размер:
36.5 Кб
Скачать

// ======================================== ДЕКЛАРАЦИИ ПЕРЕМЕННЫХ, МАКРОСОВ И БИБЛИОТЕК ========================================

#include <arpa/inet.h> //definitions for internet operations

#include <sys/types.h> //The data types

#include <sys/param.h> //Сдесь хранятся константы

#include <sys/socket.h> //Fot Internet Protocol

#include <sys/stat.h> //data returned

#include <sys/time.h> //The time types

#include <netinet/in_systm.h> //The Internet address family in sys

#include <netinet/in.h> //The Internet address family

#include <netinet/ip_icmp.h> //For ICMP

#include <netdb.h> //for network database operations

#include <unistd.h> //standard symbolic constants and types

#include <stdio.h> //standard input/output header

#include <ctype.h> //Character handling functions

#include <ctime> //Getting the date and time

#include <cstring> //for string

#include <fcntl.h> //Creating or overwriting a file

#include <string.h> //for string

#include <sstream> //providing string stream classes

#include <fstream> // To write to a file

#include <errno.h> // To work with error numbers

#include <stdlib.h> //for memory allocation routines

#include <stdint.h> //header defines integer types

#include <iostream> //standard input/output header

#define DEBUG(MS) printf(MS) //debug

#define MAX_PACKET 1024 //Размер буфера для приходящего пакета

#define ICMP_SIZE 64 //Размер посылаемого пакета

#define MaxSize 2000000 // Размер файла лога после которого он будет считаться переполненным

//Функции программы

int createLogF(); //Создание лог файла

int checkArgs(int); //Проверка колличестов входных аргументов

int dnsCheck(char **argv); //DNS or IP (DNStoIP)

int assembling(); //Сборка пакета

int request(); //Отправка пакета

int response(); //Прием пакета

int finish (); //Завершение

//Функции лога

int isLogExist(); //Для проверки существования или переполненности лога

int createLog(); //Создание лога

int ErrorOutput(int TypeError); //Вывод ошибок возникших в работе программы

int AddMessageToLog(std::string ); //Запись сообщения в лог

void LogfileDiag(int); //Диагностика ошибок лога

struct sockaddr_in saServer, from; //Информация о сокете

std::string hostname; //Имя сервера

struct hostent *hp; //Информация о хосте

u_char *packet [MAX_PACKET], *recvbuf = NULL; //Для ICMP пакета один для отправки, другой для примема

struct icmp *icp; //Структура для icmp пакета

int sock; //переменная для сокета

struct timeval start, end; //Для фиксации времени

fd_set rfds; //добавляют заданный описатель к набору

struct timeval tv; //для select

struct ip *ip; //Структра ip

int no_data; //Для счета количество провалов

int req; // Переменная для цикла

char* username; // Переменная под имя пользователя

char log_buff[128]; //Переменная под сборку пути к логу

bool Overflow; // Переменная показывающая не переполнен ли лог

int Errornum; // Переменная под хранение номера ошибки

struct stat logStat; // Создание структуры информации о файле

char buff; // Буфер для формирования записи в лог

char *date; // Переменная для получения текущей даты

time_t now; // Структура для получения времени

// ======================================== КОНЕЦ ДЕКЛАРАЦИИ ПЕРЕМЕННЫХ, МАКРОСОВ И БИБЛИОТЕК ========================================

// ======================================== ДЕКЛАРАЦИИ ФУНКЦИЙ ========================================

int createLogF(){

DEBUG ("Create log\n");

if (isLogExist() == 1)

{

int i = createLog();

if (i == 1){

return 1;

}

return 0;

}

return 0;

}

int checkArgs(int argc){ //Проверка количества входных аргументов

DEBUG ("Check enter arg\n");

if (argc != 2) {

printf("usage: ip/dns address\n");

ErrorOutput(20);

return 1;

}

return 0;

}

int dnsCheck(char * argv[]){

DEBUG ("Check dns or ip\n");

std::string target = argv[1]; //Меняем аргумент из char in str

std::stringstream ss; //Для преоброзавние строки

std::string strOut; //Для хранения преобразованной строки

char hnamebuf[MAXHOSTNAMELEN]; //буфер для hostname

saServer.sin_family = AF_INET; //Назначаем принадлежность к ipv4

saServer.sin_addr.s_addr = inet_addr(target.c_str()); //Назначаем адрес

if (saServer.sin_addr.s_addr != (u_int)-1) //Проверяем тип адреса

hostname = target; //Если адрес ip то не меняем адрес

else //Если адрес DNS

{

hp = gethostbyname(target.c_str()); //Ищем в базе ip входящего DNS

if (!hp)

{

printf ("Unkown host");

ErrorOutput(30);

return 1;

}

//Переопределяем тип и имя

saServer.sin_family = hp->h_addrtype;

bcopy(hp->h_addr, (caddr_t)&saServer.sin_addr, hp->h_length);

strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);

hostname = hnamebuf;

}

ss << "Host IP: " << inet_ntoa (saServer.sin_addr) << std::endl;

strOut = ss.str();

printf(strOut.c_str());

AddMessageToLog(strOut);

return 0;

}

int assembling(){ //Собираем пакет

DEBUG ("Assembling packet\n");

if ( (recvbuf = (u_char *)malloc((u_int)MAX_PACKET)) == NULL) //Создаем буфер для входящих пакетов

{

printf ("malloc error\n");

ErrorOutput(40);

ErrorOutput(41);

return 1;

}

if ( (sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) //Создаем сокет

{

printf ("Needs to run as superuser!!\n ");

ErrorOutput(40);

ErrorOutput(42);

return 1; /* Needs to run as superuser!! */

}

//Определям заголовок пакета

icp = (struct icmp *)packet;

icp->icmp_type = ICMP_ECHO; // Тип пакета

icp->icmp_code = 0;

icp->icmp_cksum = 0; //сумма пакета (изменется дальше)

icp->icmp_seq = 12345; //последоваетльность

icp->icmp_id = getpid(); //id пакета

icp->icmp_cksum = in_cksum((unsigned short *)icp,ICMP_SIZE); //сума пакета

FD_ZERO(&rfds);

FD_SET(sock, &rfds);

tv.tv_sec = 1;

tv.tv_usec = 0;

return 0;

}

int request(){

DEBUG ("Request\n");

sleep(1);

gettimeofday(&start, NULL); //фиксация времени отправки

//отправляем пакет и проверяем получилось ли

int i = sendto(sock, (char *)packet, ICMP_SIZE, 0, (struct sockaddr*)&saServer, (socklen_t)sizeof(struct sockaddr_in));

if (i < 0){

printf("sendto error");

ErrorOutput(50);

return 1;

}

return 0;

}

int response(){

DEBUG ("Response\n");

int fromlen, ret, hlen, end_t;

std::stringstream ss; //Для преоброзавние строки

std::string strOut; //Для хранения преобразованной строки

// блокируемся пока не получим данные или не истечет время

int retval = select(sock+1, &rfds, NULL, NULL, &tv);

if (retval == -1)

{

perror("select()");

ErrorOutput(60);

ErrorOutput(61);

return 1;

}

else if (retval)

{

fromlen = sizeof(sockaddr_in);

if ( (ret = recvfrom(sock, (char *)recvbuf, MAX_PACKET , 0,(struct sockaddr *)&from, (socklen_t*)&fromlen)) < 0)

{

perror("recvfrom error");

ErrorOutput(60);

return 1;

}

// Check the IP header

ip = (struct ip *)((char*)recvbuf);

hlen = sizeof( struct ip );

if (ret < (hlen + ICMP_MINLEN)) //Не соответсвие разменра пакета

{

std::cout << "packet too short ( " << ret <<" bytes) from "<< hostname <<" hostname" << std::endl;

ErrorOutput(60);

ErrorOutput(62);

return 1;

}

icp = (struct icmp *)(recvbuf + hlen);

if (icp->icmp_type == ICMP_ECHOREPLY)

{

if (icp->icmp_seq != 12345) //не соответсвие последовательности

printf ("received sequence # %c \n", icp->icmp_seq);

if (icp->icmp_id != getpid()) //не правильный id пакета

printf ("received id %c \n", icp->icmp_id);

}

else{

printf ("Recv: not an echo reply \n");

ErrorOutput(60);

return 1;

}

gettimeofday(&end, NULL); //фиксация время получения пакета

end_t = 1000000*(end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec);

if(end_t < 1)

end_t = 1;

ss << "Ping host: " << inet_ntoa(from.sin_addr)

<< " time = " << end_t << "usec " << std::endl;

strOut = ss.str();

printf(strOut.c_str());

AddMessageToLog(strOut);

return 0;

}

else

{

if (no_data == 5){

printf ("No data about node.\n");

ErrorOutput(60);

ErrorOutput(63);

return 1;

}

else{

printf ("No data within one seconds.\n");

AddMessageToLog("No data within one seconds.\n");

return 0;

}

}

}

static uint16_t in_cksum(uint16_t *addr, unsigned len)

{

DEBUG ("Chek Summa\n");

uint16_t answer = 0;

/*

* Algorithm is simple, using a 32 bit accumulator (sum), add

* sequential 16 bit words to it, and at the end, fold back all the

* carry bits from the t 16 bits into the lower 16 bits.

*/

uint32_t sum = 0;

while (len > 1) {

sum += *addr++;

len -= 2;

}

if (len == 1) {

*(unsigned char *)&answer = *(unsigned char *)addr ;

sum += answer;

}

sum = (sum >> 16) + (sum & 0xffff);

sum += (sum >> 16);

answer = ~sum;

return answer;

}

int isLogExist() // Функция проверки наличия и переполнения лога

{

username = getenv("USER"); // Получение имени пользователя

// Сборка пути

sprintf(log_buff, "%s%s%s", "/home/",username, "/Desktop/Ping/Ping_log.txt" );

if ( stat((char *)log_buff, &logStat) == -1 ) // Заполнение структуры информации о файле

{

return 1; // Возвращаем 1 говоря что файла не существует

}

else if (logStat.st_size > MaxSize)

{

std::cout << "Файл лога переполнился и будет перезаписан";

Overflow = true;

return 1;

}

return 0; //Возвращаем 0 говоря что файла существует

}

int createLog() // Функция создания папки и лога

{

char path_buff[128]; //Переменная под сборку команды

int result; // Переменная под результат создания папки

// Сборка команды создания директории

sprintf(path_buff, "%s%s%s","mkdir -p /home/", username, "/Desktop/Ping" );

result = system(path_buff); // Создание директории

if (result == -1) // Обработка ошибки

{

ErrorOutput(10);

return 1;

}

if (Overflow)

{

result = open((char*)log_buff, O_RDWR | O_TRUNC); // Перезапись файла лога

}

else

{

// Создание файла

result = open((char*)log_buff, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

}

if (result == -1) // Обработка ошибки

{

Errornum = errno;

LogfileDiag(Errornum);

ErrorOutput(11);

return 1;

}

close(result);

return 0;

}

int ErrorOutput(int TypeError) // Функция записи ошибки в лог

{

switch(TypeError)

{

case 10:

{

std::cout <<"Ошибка создания директории для лога"<<std::endl;

break;

}

case 11:

{

std::cout <<"Ошибка создания файла лога"<<std::endl;

break;

}

case 12:

{

std::cout <<"Ошибка записи в лог"<<std::endl;

break;

}

case 20:

{

AddMessageToLog("ERROR Неверное количество входных аргументов");

break;

}

case 30:

{

AddMessageToLog("ERROR Доменное имя не соответствует никакому IP");

break;

}

case 40:

{

AddMessageToLog("ERROR Пакет не собран");

break;

}

case 41:

{

AddMessageToLog("ERROR malloc");

break;

}

case 42:

{

AddMessageToLog("ERROR Недостаточно прав");

break;

}

case 50:

{

AddMessageToLog("ERROR При отправке возникла ошибка");

break;

}

case 60:

{

AddMessageToLog("ERROR Пакет не получен");

break;

}

case 61:

{

AddMessageToLog("ERROR select()");

break;

}

case 62:

{

AddMessageToLog("ERROR Не соответсвие разменра пакета ");

break;

}

case 63:

{

AddMessageToLog("ERROR Нет данных о ноде");

break;

}

}

return 0;

}

void LogfileDiag(int TypeError)

{

switch(TypeError) // Вывод сообщения в зависимости от значения errno

{

case 1:

{

std::cout <<"Операция не разрешена";

break;

}

case 12:

{

std::cout <<"Не достаточно памяти";

break;

}

case 13:

{

std::cout <<"Доступ запрещен";

break;

}

case 26:

{

std::cout <<"Текстовый файл занят";

break;

}

default:

{

std::cout <<"Неопознанная ошибка код errno = " << TypeError;

break;

}

}

}

int AddMessageToLog(std::string Message) // Функция добавления записи в лог

{

char *Mess = new char[Message.length() + 1]; // Создание массива под содержимое сообщения

strcpy(Mess, Message.c_str()); // Копирование сообщения в массив

time(&now); // Заполняем структуру

date = ctime(&now);

date[strlen(date)-1] = '\0';

sprintf(buff, "[%s] %s", date, Mess); // Формирование записи в лог

std::fstream fs;

fs.open(log_buff, std::fstream::app); // Открытие файла

if (!fs.is_open())

{

Errornum = errno;

LogfileDiag(Errornum);

ErrorOutput(12);

return 1;

}

fs << buff << std::endl;

fs.close();

delete [] Mess; // Удаление массива

return 0;

}

// ======================================== КОНЕЦ ДЕКЛАРАЦИИ ФУНКЦИЙ ========================================

// ======================================== ТЕЛО ПРОГРАММЫ ========================================

int main(int argc, char *argv[])

{

setlocale(LC_ALL, "Russian");

saServer = { 0 }; //Информация о сокете

from = { 0 }; //Информация о сервере

hostname = «»; //Имя сервера

hp = NULL; //Информация о хосте

packet = NULL; //Для ICMP пакета один для отправки, другой для примема

recvbuf = NULL; //Для ICMP пакета один для отправки, другой для примема

icp = { 0 }; //Структура для icmp пакета

sock = 0; //переменная для сокета

start = { 0 }; //Для фиксации времени

end = { 0 }; //Для фиксации времени

rfds = 0; //добавляют заданный описатель к набору

tv = { 0 }; //для select

ip = { 0 }; //Структра ip

no_data = 0; //Для счета количество провалов

req = 0; // Переменная для цикла

username = «»; // Переменная под имя пользователя

log_buff = «»; //Переменная под сборку пути к логу

Overflow = False; // Переменная показывающая не переполнен ли лог

Errornum = 0; // Переменная под хранение номера ошибки

buff = «»; // Буфер для формирования записи в лог

now = 0; // Структура для получения времени

logStat = {}; // Для получения информации о файе

date = NULL; // Переменная для получения текущей даты

switch (createLogF()) //Создание лог файла

{

case 0:

switch (checkArgs(argc)) //Проверка колличестов входных аргументов

{

case 0:

switch (dnsCheck(argv)) //DNS or IP (DNStoIP)

{

case 0:

switch (assembling()) //Сборка пакета

{

case 0:

while (req <= 30)

{

req ++;

switch (request()) //Отправка пакета

{

case 0:

switch (response()) //Прием пакета

{

case 0:

continue;

case 1:

printf ("Error code = 60\n");

return 60;

break;

}

case 1:

printf ("Error code = 50\n");

return 50;

break;

}

}

break;

case 1:

printf ("Error code = 40\n");

return 40;

break;

}

break;

case 1:

printf ("Error code = 30\n");

return 30;

break;

}

break;

case 1:

printf ("Error code = 20\n");

return 20;

break;

}

break;

case 1:

printf ("Error code = 10\n");

return 10;

break;

}

finish(); //Завершение

return 0;

}

// ======================================== КОНЕЦ ТЕЛА ПРОГРАММЫ ========================================