Чтение данных с IP-пакетов

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by LostCoast, 22 Nov 2012.

  1. LostCoast

    LostCoast New Member

    Joined:
    13 Nov 2012
    Messages:
    2
    Likes Received:
    0
    Reputations:
    -1
    Всем привет!
    Я пишу сниффер трафика на с++, возникли трудности с получением передаваемых данных в IP-пакетах. У меня получается читать информацию из IP-сегмента, tcp-сегмента. Дальше, по идеи, хранятся передаваемые данные. Я их вытаскиваю, но они непонятно в каком виде хранятся, при простом отображении я получаю смайлики и кракозябры. Не подскажите как получить эти данные в нормальном виде?

    Если что, вот исходники.
    Code:
    #include "ws2tcpip.h"
    #include <conio.h>
    
    typedef struct IPHeader {
    	UCHAR iph_verlen; // версия и длина заголовка
    	UCHAR iph_tos; // тип сервиса
    	USHORT iph_length; // длина всего пакета
    	USHORT iph_id; // Идентификация
    	USHORT iph_offset; // флаги и смещения
    	UCHAR iph_ttl; // время жизни пакета
    	UCHAR iph_protocol; // протокол
    	USHORT iph_xsum; // контрольная сумма
    	ULONG iph_src; // IP-адрес отправителя
    	ULONG iph_dest; // IP-адрес назначения
    } IPHeader;
    
    typedef struct {
    	unsigned short int th_sport;
    	unsigned short int th_dport;
    	unsigned int th_seq;
    	unsigned int th_ack;
    	unsigned char th_x2:4, th_off:4;
    	unsigned char th_flags;
    	unsigned short int th_win;
    	unsigned short int th_sum;
    	unsigned short int th_urp;
    } TCPHDR; // 20 bytes
    
    #define SIO_RCVALL 0x98000001


    Code:
    #include <WinSock2.h>
    #include <Windows.h>
    #include <iostream>
    #include <cstdlib>
    #include "ws2tcpip.h"
    #include "TCP_IP.h"
    #include <conio.h>
    using namespace std;
    #pragma comment(lib, "ws2_32.lib")
    
    const char* SOURCE_IP = "192.168.51.54";
    
    struct udpheader {
    	unsigned short int uh_sport;
    	unsigned short int uh_dport;
    	unsigned short int uh_len;
    	unsigned short int uh_check;
    };
    
    int main()
    {
    	WSADATA wsaData;
    	struct sockaddr_in sin;
    	SOCKET s;
    	char host[20];
    	hostent *phe;
    	ULONG flag = 1;
    	if (WSAStartup(MAKEWORD(2, 2), &wsaData))
    	{
    		cout << "Error on startup WSA" << endl;
    		return 1;
    	}
    
    	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_IP)) == SOCKET_ERROR)
    	{
    		cout << "Error on create socket" << endl;
    		return 1;
    	}
    
    	ZeroMemory(&sin, sizeof(sin));
    	gethostname(host, sizeof(host));
    	phe = gethostbyname(host);
    
    	sin.sin_family = AF_INET;
    	sin.sin_addr.s_addr = ((struct in_addr*)phe->h_addr_list[0])->s_addr;
    
    	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)))
    	{
    		cout << "Error on binding socket" << endl;
    		return 1;
    	}
    
    	if (ioctlsocket(s, SIO_RCVALL, &flag))
    	{
    		cout << "Error on set SIO_RCVALL" << endl;
    		return 1;
    	}
    
    	char buffer[65536];
    	int count;
    	while (true)
    	{
    		if ((count = recv(s, buffer, sizeof(buffer), 0)))
    		{
    		
    			
    			IPHeader* iph = (IPHeader* )buffer;
    			char str[INET_ADDRSTRLEN];
    			in_addr sa;
    			sa.s_addr = iph->iph_src;
    			WORD size = (iph->iph_length << 8) + (iph->iph_length >> 8);
    			//вывод информации от кого, кому, и какой протокол
    			cout << "From: " << inet_ntoa(sa);
    			sa.s_addr = iph->iph_dest;
    			cout << " To: " << inet_ntoa(sa);
    			switch(iph->iph_protocol)
    			{
    			case IPPROTO_TCP :
    				cout << " TCP" << endl;
    				break;
    			case IPPROTO_UDP :
    				cout << " UDP" << endl;
    				break;
    			}
    			//начинаем разбирать пакеты
    			struct TCPHDR *tcp_hdr = NULL; //тсп - сегмент
    			struct udpheader *udp_hdr; //удп - сегмент
    			size_t  headers_len, data_len; //длмна сегмента и длина данных после сегментов
    			u_char *data; //тут будем хранить данные о пакете
    
    			if(iph->iph_protocol == IPPROTO_TCP) 
    			{
    				 tcp_hdr = (struct TCPHDR *)(buffer+sizeof(*iph)); //получаем тсп сегмент учитывая длину айпи - сегмента
    				 data = (u_char *)(buffer + (headers_len = sizeof(*iph) + sizeof(tcp_hdr))); // вычисляем длину данных в пакете
    				 data_len = count - headers_len;
    				 //cout << "TCP Receive: " << count <<  " Data_len" << data_len << " Header len: " << sizeof(tcp_hdr) << endl;
    				 // в принципе дальше можно делать что укогдо с данными
    			}
    
    			if(iph->iph_protocol == IPPROTO_UDP) 
    			{
    				//тут все тоже самое только с удп пакетом
    				 udp_hdr = (struct udpheader *)(buffer+sizeof(*iph));
    				 data = (u_char *)(buffer+(headers_len = sizeof(*iph)+sizeof(*udp_hdr)));
    				 data_len = count - headers_len;
    				 //cout << "UDP Receive: " << count <<  " Data_len" << data_len << endl;
    				 //cout << data << endl;
    				 // в принципе дальше можно делать что укогдо с данными
    			}
    		}
    		Sleep(100);
    	}
    
    	return 0;
    }
     
  2. Gar|k

    Gar|k Moderator

    Joined:
    20 Mar 2009
    Messages:
    1,166
    Likes Received:
    266
    Reputations:
    82
    То что ты взял откуда-то код это понятно, потому что обработки получения данных нет вовсе.

    По хорошему сначала нужно получить заголовок IP разобрать его - получить длину пакета из структуры. уже потом получить его полностью... далее уже разбирать TCP заголовок и уже проверять там размер окна...

    while(true)
    {
    recvall ipheaer siteof(ipheader)
    recvall tcpbuf ipheader->iph_length

    // работа с TCP пакетом

    }
    Если тебе важна целостность перехватываемых данных нужно учитывать что TCP разбивает пакеты на сегменты.

    По поводу вывода - в курсе что такое 16 ричная кодировка и HEX редактор? Знаешь о существовании функции sprintf %02h ?
     
    _________________________
  3. LostCoast

    LostCoast New Member

    Joined:
    13 Nov 2012
    Messages:
    2
    Likes Received:
    0
    Reputations:
    -1
    Делал по примерам, не спорю, коменты сам ставил если что.
    Теперь по делу: IPHeader* iph = (IPHeader* )buffer; здесь я заполняю структуру, и выводя данные структуры, вижу от кого куда он посылается. Получается я уже получил ip заголовок, верно?

    Далее вот этой строчкой получаю tcp заголовок: tcp_hdr = (struct TCPHDR *)(buffer+sizeof(*iph)); и так же могу спокойно смотреть что внутри, верно?

    С HEX редактором знаком, знаю как в нем выглядят данные, т.е. я могу сохранить в файл принятые данные, а потом разобрать их редактором?, точнее там я их и увижу?

    sprintf %02h как то не сталкивался с такой функцией, работал с printf, fprintf

    На сколько я помню эти сегменты могут придти в любом порядке, в этом заключается загвоздка?