Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Низкоуровневое программирование > Win Api
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 27.11.2016, 15:55   #1
Aoizora
Заблокирован
 
Регистрация: 11.11.2016
Сообщений: 261
По умолчанию Не получается забиндить сокет

Мне нужно написать простой анализатор пакетов, который снифает трафик, слегка анализирует пакеты и решает, отбрасывать пакет или нет. Написал такую программу:

Код:
#include <Winsock2.h>
#include <Windows.h>
#include <iostream>

#pragma comment(lib, "Ws2_32.lib")

#define SIO_RCVALL 0x98000001
#define MAX_PACKET_SIZE 0x10000

typedef struct tagIPHeader
{
  unsigned char  ver_len;		// версия и длина заголовка
  unsigned char  tos;			// тип сервиса 
  unsigned short length;		// длина всего пакета 
  unsigned short id;			// Id 
  unsigned short flgs_offset;		// флаги и смещение
  unsigned char  ttl;			// время жизни 
  unsigned char  protocol;		// протокол 
  unsigned short xsum;			// контрольная сумма 
  unsigned long  src;			// IP-адрес отправителя 
  unsigned long  dest;			// IP-адрес назначения 
  unsigned short *params;		// параметры (до 320 бит)
  unsigned char  *data;			// данные (до 65535 октетов)
} IPHeader;

void ShowError()
{
        LPVOID lpMsgBuf = NULL;
		int error = WSAGetLastError();
		printf("error = %d\n", error);
        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
			NULL,
			error,
			MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
			(LPTSTR)&lpMsgBuf,0,NULL);
        std::cout << (LPCTSTR)lpMsgBuf << std::endl;
        LocalFree(lpMsgBuf);
}

IPHeader* sniff(SOCKET sock)
{
	IPHeader *hdr;
	char buffer[MAX_PACKET_SIZE];
	int count = 0;

	count = recv(sock, buffer, sizeof(buffer), 0);
	if (count >= (int)sizeof(IPHeader))
	{
		hdr = (IPHeader *)malloc(MAX_PACKET_SIZE);
		memcpy(hdr, buffer, MAX_PACKET_SIZE);
		return hdr;
	}
	else
		return 0;
}

int main()
{
		WSADATA wsaData;
		char hostname[128];
		HOSTENT* hostinfo;
		SOCKADDR_IN sa;
		sockaddr_in local_addr;
		unsigned long flag = 1;

        if(WSAStartup(0x0202, &wsaData)){ ShowError(); }
        else
        {
                std::cout << "WSAStartup - OK" << std::endl;
                SOCKET sock;
                sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP);	// Create raw socket
                if(sock == INVALID_SOCKET){ ShowError(); }
                {
                        std::cout << "Raw scoket is created" << std::endl;
                        //if(closesocket(sock) == SOCKET_ERROR) { ShowError(); }
                }


				gethostname(hostname, sizeof(hostname));
				hostinfo = gethostbyname(hostname);

				ZeroMemory(&sa, sizeof(sockaddr));
				sa.sin_family = AF_INET;
				sa.sin_addr.s_addr = ((struct in_addr *)hostinfo->h_addr_list[0])->s_addr;

				ZeroMemory(&local_addr, sizeof(local_addr));
				local_addr.sin_family=AF_INET;
				local_addr.sin_addr.s_addr=((struct in_addr *)hostinfo->h_addr_list[0])->s_addr;
				if (bind(sock, (sockaddr *)&local_addr, sizeof(sockaddr) == SOCKET_ERROR))
				{
					ShowError();
				}

				ioctlsocket(sock, SIO_RCVALL, &flag);

				// Analyze packets
				while (true)
				{
						IPHeader* hdr = sniff(sock);
						// обработка IP-пакета
						if (hdr)
						{ 
								unsigned char *byte_iterator = (unsigned char *)hdr;
								for (int i = 0; i < sizeof(IPHeader); i++)
								{
										printf("%02x", *byte_iterator);
										++byte_iterator;
								}
						}
						free(hdr);
				}
                
                if(WSACleanup()) { ShowError(); }
                else
				{ std::cout << "WSACleanup - OK" << std::endl;}
        }
        
        return 0;
}
При бинде сокета возвращается ошибка 10014: Bad address. The system detected an invalid pointer address in attempting to use a pointer argument of a call. This error occurs if an application passes an invalid pointer value, or if the length of the buffer is too small. For instance, if the length of an argument, which is a sockaddr structure, is smaller than the sizeof(sockaddr).

Я так понимаю, проблема в размере структур, которые я использую в вызове bind? Как решить проблему?
Aoizora вне форума Ответить с цитированием
Старый 27.11.2016, 16:14   #2
Aoizora
Заблокирован
 
Регистрация: 11.11.2016
Сообщений: 261
По умолчанию

Проблему с биндом решил. Не хватало закрывающей скобки.

Остались две задачи:
1. Добраться до данных в пакете и анализировать их
2. Переделать под IPv6

Чтобы получить данные, надо просто перейти по указателю, а размер этих данных равен IPHeader.length - sizeof(tagIPHeader)? Или нет?
Aoizora вне форума Ответить с цитированием
Старый 27.11.2016, 16:14   #3
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,695
По умолчанию

Цитата:
Я так понимаю, проблема в размере структур, которые я использую в вызове bind?
Нет
Цитата:
Как решить проблему?
Расставить скобки правильно. Смотите внимательно как вы вызываете:
Код:
bind(sock, (sockaddr *)&local_addr, sizeof(sockaddr) == SOCKET_ERROR)
Сколько ( sizeof(sockaddr) == SOCKET_ERROR ) вы передаетье как размер?
p51x на форуме Ответить с цитированием
Старый 27.11.2016, 16:30   #4
Aoizora
Заблокирован
 
Регистрация: 11.11.2016
Сообщений: 261
По умолчанию

Это решил.

Дописал такую процедуру:

Код:
void AnalyzePacket(IPHeader *hdr)
{
	int SizeOfData = hdr->length - sizeof(IPHeader);
	unsigned char *DataPtr = hdr->data;

	for (int i = 0; i < SizeOfData; i++)
	{
		printf("%c ", *DataPtr);
	}
	printf("\n\n");
}
То есть просто хочу вывести данные на экран. В DataPtr оказывается инвалидный указатель. Как вытащить данные из IP-пакета?

Еще хочу понять, какова структура данных, которые лежат в буфере после вызова recv. Там сырые данные, то есть IP-заголовок и прочая ботва, или что-то другое?
Aoizora вне форума Ответить с цитированием
Старый 27.11.2016, 16:46   #5
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,493
По умолчанию

А что, это работает?! В документации прямым текстом написано, что нельзя передавать IPPROTO_IP...

Ref:
https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx
waleri вне форума Ответить с цитированием
Старый 27.11.2016, 17:01   #6
Aoizora
Заблокирован
 
Регистрация: 11.11.2016
Сообщений: 261
По умолчанию

Цитата:
Сообщение от waleri Посмотреть сообщение
А что, это работает?! В документации прямым текстом написано, что нельзя передавать IPPROTO_IP...

Ref:
https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx
Черт знает, но src/dest-адреса в консоли похожи на настоящие, то есть сниффер работает правильно (или я не заметил где-то ошибку).

Остается вопрос, как добраться до данных.
Aoizora вне форума Ответить с цитированием
Старый 27.11.2016, 17:04   #7
Aoizora
Заблокирован
 
Регистрация: 11.11.2016
Сообщений: 261
По умолчанию

У меня в строке printf("data = %s\n", *hdr->data); или printf("data = %s\n", hdr->data); обращение к неверной памяти.
Aoizora вне форума Ответить с цитированием
Старый 29.11.2016, 12:18   #8
Ethereal2
Пользователь
 
Регистрация: 17.02.2013
Сообщений: 26
По умолчанию

Цитата:
Сообщение от Aoizora Посмотреть сообщение
unsigned char *DataPtr = hdr->data;
Тебе нужен не указатель, взятый из поля данных, а указатель на поле данных. У тебя лишняя косвенность. Хотя, Си не моя тема, но вроде бы так.
Ethereal2 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Что то не дает забиндить порты Abuhamed Windows 2 03.10.2013 00:14
Забиндить ImageBrush ImageSource coNsept Общие вопросы .NET 1 28.11.2012 05:00
Сокет останавливает другой сокет. batand C/C++ Сетевое программирование 2 09.10.2012 11:58
Вопрос по WinSock: "сокет=сокет." Ksardas13 C/C++ Сетевое программирование 2 27.11.2011 16:12
Как забиндить все ПОРТЫ? KaneKRY Работа с сетью в Delphi 0 02.04.2010 14:45