Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.97.9.175] |
|
Сообщ.
#1
,
|
|
|
Хочу научиться работать с RAW сокетами, а именно - хотелось бы написать сниффер пакетов (ну, для начала, хотя бы примитивный)...
Так вот. Задача: я хочу получать на сокет ВСЕ IP пакеты. Как мне для этого создавать сокет? Как делать bind()? Получать UDP пакеты с порта 27015 я научился... //create socket SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_UDP); if(s==INVALID_SOCKET) return -1; //bind sockaddr_in local_addr; local_addr.sin_family = AF_INET; local_addr.sin_port = htons(27015); local_addr.sin_addr.S_un.S_addr = INADDR_ANY; if(bind(s, (const struct sockaddr *)&local_addr, sizeof(local_addr)) == SOCKET_ERROR) return -2; //recv sockaddr addr_from; int from_len = sizeof(addr_from); res = recvfrom(s, buf, buf_size-1, 0, &addr_from, &from_len); //buf - буфер, buf_size - его длина if(res>0) { Log("NT: INFO: recvfrom() success"); buf[res] = 0; Log(buf); // в общем - вывод на экран } else { //ошибка.... } Я пробовал создавать сокет: SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_IP); Сокет создаётся. Без bind() recvfrom() вылетает с ошибкой WSAEINVAL, что говорит о том, что Цитата MSDN The socket has not been bound with bind... А к какому адресу биндиться-то RAW-сокету с IPPROTO_IP? Использовать ли sockaddr_in или просто sockaddr?.. Код: //bind sockaddr local_addr; local_addr.sa_family = AF_INET; memset(local_addr.sa_data, 0, 14); Как быть? как "схватить" все IP пакеты, которые машина получает? |
Сообщ.
#3
,
|
|
|
Цитата Oleg2004 @ Поиск по форуму дает это Там всё на тему "как отправить", "как послать" итп... ПОиск я уже смотрел... не особо мне он помог.... Мне бы как ПОЛУЧИТЬ пакет... причём не UDP, как в той ссылке, а любой IP-пакет.... |
Сообщ.
#5
,
|
|
|
Посмотри это
Цитата Ниже приведён полный код программы. Данный код не претендует на звание крутого снифера, однако при желании его можно доработать, чтобы можно было просматривать содержимое пакетов. Так же на его основе можно легко сделать простой анализатор трафика. А главное - не надо делать всяких драйверов; всё просто и понятно. Суть этого сниффера заключается в том, что используются соке Сокеты второй версии и созданный сокет переводится в режим promiscuous (прослушивания). #include <conio.h> #include <stdio.h> #include <winsock2.h> #define MAX_PACKET_SIZE 0x10000 #define SIO_RCVALL 0x98000001 // Буфер для приёма данных char Buffer[MAX_PACKET_SIZE]; // 64 Kb //Структура заголовка IP-пакета 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; char src[10]; char dest[10]; char ds[15]; unsigned short lowbyte; unsigned short hibyte; void main() { WSADATA wsadata; // Инициализация WinSock. SOCKET s; // Cлущающий сокет. char name[128]; // Имя хоста (компьютера). HOSTENT* phe; // Информация о хосте. SOCKADDR_IN sa; // Адрес хоста IN_ADDR sa1; // unsigned long flag = 1; // Флаг PROMISC Вкл/выкл. // инициализация WSAStartup(MAKEWORD(2,2), &wsadata); s = socket( AF_INET, SOCK_RAW, IPPROTO_IP ); gethostname(name, sizeof(name)); phe = gethostbyname( name ); ZeroMemory( &sa, sizeof(sa) ); sa.sin_family = AF_INET; sa.sin_addr.s_addr = ((struct in_addr *)phe->h_addr_list[0])->s_addr; bind(s, (SOCKADDR *)&sa, sizeof(SOCKADDR)); // Включение promiscuous mode. ioctlsocket(s, SIO_RCVALL, &flag); // Бесконечный цикл приёма IP-пакетов. while( !_kbhit() ) { int count; count = recv( s, Buffer, sizeof(Buffer), 0 ); // обработка IP-пакета if( count >= sizeof(IPHeader) ) { IPHeader* hdr = (IPHeader *)Buffer; //Начинаем разбор пакета... strcpy(src,"Пакет: "); CharToOem(src,dest); printf(dest); // Преобразуем в понятный вид адрес отправителя. printf("From "); sa1.s_addr = hdr->iph_src; printf(inet_ntoa(sa1)); // Преобразуем в понятный вид адрес получателя. printf(" To "); sa1.s_addr = hdr->iph_dest; printf(inet_ntoa(sa1)); // Вычисляем протокол. Полный список этих констант // содержится в файле winsock2.h printf(" Prot: "); if(hdr->iph_protocol == IPPROTO_TCP) printf("TCP "); if(hdr->iph_protocol == IPPROTO_UDP) printf("UDP "); // Вычисляем размер. Так как в сети принят прямой порядок // байтов, а не обратный, то прийдётся поменять байты местами. printf("Size: "); lowbyte = hdr->iph_length>>8; hibyte = hdr->iph_length<<8; hibyte = hibyte + lowbyte; printf("%s",itoa(hibyte,"",10)); // Вычисляем время жизни пакета. printf(" TTL:%s",itoa(hdr->iph_ttl,"",10)); printf("\n"); } } closesocket( s ); WSACleanup(); } |
Сообщ.
#6
,
|
|
|
MinLexx
вот САМЫЙ простой пример сниффера на сокетах #include <iostream> #include <winsock2.h> #include <ws2tcpip.h> #include <conio.h> #define SIO_RCVALL 0x98000001 #pragma comment(lib,"ws2_32.lib") void main(void){ WSADATA wsa; WSAStartup(MAKEWORD(2,2),&wsa); SOCKET s = socket(AF_INET,SOCK_RAW,IPPROTO_IP); sockaddr_in adr; memset(&adr,0,sizeof(sockaddr_in)); adr.sin_addr.s_addr = INADDR_ANY; adr.sin_family = AF_INET; bind(s,(sockaddr*)&adr,sizeof(sockaddr_in)); DWORD d =1; ioctlsocket(s,SIO_RCVALL,&d); char buff[2000]={0}; while (recv(s,buff,2000,0)!=SOCKET_ERROR){ in_addr ip1 , ip2; ip1.S_un.S_addr = *((int*)(buff+12)); ip2.S_un.S_addr = *((int*)(buff+16)); std::cout << "user " << inet_ntoa(ip1); std::cout <<" shlot chtoto user-u " <<inet_ntoa(ip2) <<"\n"; } std::cout <<"Error N:" << WSAGetLastError(); _getch(); } Добавлено во , убрал еще 1 строчку))) ну что , кто короче?? |
Сообщ.
#7
,
|
|
|
Видимо быстрый у Вас инет) Шустро тыкаете по кнопочке "Поиск".
ФФсем спасип... буду копать..... |
Сообщ.
#8
,
|
|
|
Цитата MinLexx @ Видимо быстрый у Вас инет) Шустро тыкаете по кнопочке "Поиск". Э. Не нада. Я сам писал.. я уже спортом решил заняться.. в еще меньшее число строк это написал ))) #include <iostream> #include <winsock2.h> #include <ws2tcpip.h> #define SIO_RCVALL 0x98000001 #pragma comment(lib,"ws2_32.lib") void main(void){ WSADATA wsa; WSAStartup(MAKEWORD(2,2),&wsa); SOCKET s = socket(AF_INET,SOCK_RAW,IPPROTO_IP); sockaddr_in adr = {AF_INET , INADDR_ANY , 0 , 0}; bind(s,(sockaddr*)&adr,sizeof(sockaddr_in)); DWORD d =1; ioctlsocket(s,SIO_RCVALL,&d); char buff[2000]={0}; while (recv(s,buff,2000,0)!=SOCKET_ERROR){ in_addr ip1 , ip2; ip1.S_un.S_addr = *((int*)(buff+12)); ip2.S_un.S_addr = *((int*)(buff+16)); std::cout << "user " << inet_ntoa(ip1); std::cout <<" shlot chtoto user-u " <<inet_ntoa(ip2) <<"\n"; } std::cout <<"Error N:" << WSAGetLastError(); } |
Сообщ.
#9
,
|
|
|
Цитата MSDN Return Values Upon successful completion, the ioctlsocket returns zero. Otherwise, a value of SOCKET_ERROR is returned. Так вот, вызов //SIO_RCVALL DWORD d = 1; if(ioctlsocket(s, SIO_RCVALL, &d) == SOCKET_ERROR) { Log("NT: ERROR: ioctlsocket(... SIO_RCVALL ...) set failed."); } выводит на экран это сообщение. Хотя последующий вызов recvfrom() успешен... Твой код, конечно, короткий, но он не проверяет ни одно возвращаемое значение... |
Сообщ.
#10
,
|
|
|
MinLexx
Специфика SIO_RCVALL в том , что он срабатывает , но ioctlsocket возвращает ошибку. |
Сообщ.
#11
,
|
|
|
Интересно где это про такие вот мелочи жизни литературу почитать можно? И почему константа SIO_RCVALL не определена стандартно? Почему в MSDN ничего нет толкового на эту тему?
|
Сообщ.
#12
,
|
|
|
cozy
Цитата Посмотри это В данном коде содержится нехилая ошибка: printf("%s",itoa(hibyte,"",10)); ^^ - как такое можно было написать ? |
Сообщ.
#13
,
|
|
|
Извиняюсь, код не мой.
Copy'n'paste. В принципе, код свою работу делает, а исправить эту ошибку надеюсь труда не составит? |
Сообщ.
#14
,
|
|
|
cozy
Цитата Извиняюсь, код не мой. Знаю. Цитата В принципе, код свою работу делает, У меня TTL не печатал, так я эту ошибку и обнаружил |
Сообщ.
#15
,
|
|
|
Не хочу плодить темы.....
Короче понял я, толковый сниффер на Винапи/Винсок не напишешь, тут нужен WinPcap. Ну, покопал я WinPcap, посмотрел примерчики - прикольно, этот WinPcap ловит пакеты на уровне Ethernet!!! Я даже смог разобрать заголовки Ethernet, IP, UDP, ... Короче, новая задача есть. В некоторой сети между сегментами не проходят UDP-пакеты (фильтруются на роутере). А надо сделать так, чтобы UDP-пакеты могли перемещаться от компа к компу за пределы сегментов. Однако, протокол TCP разрешён... Вариант решения таков: создать TCP туннель для связи нескольких компьютеров... На одном из компов запущен сервер, соединяющий клиентов. На компах, которые хотят связаться через UDP, запущены клиенты - клиенты соединяются с сервером по TCP. Клиент представляет из себя сниффер UDP-пакетов... Когда комп отправляет UDP пакет, клиент его прослушивает, записывает и запихивает в TCP-пакет, отсылает серверу. Далее, сервер, получая от клиента пакет, персылает его всем остальным клиентам. Клиенты, получившие такие пакеты, должны отправить их в свою подсеть.... Так, как будто они пришли из другой подсети (можно туннелировать ВЕСЬ IP-пакет, не проблема ), не изменяя адреса отправителя/получателя, вообще не изменяя пакет... Внимание ВОПРОС Можно ли отправить пакет в сеть так, чтобы он вернулся из сети на свою же машину, будто посланный из сети? Допустим, комп из одной подсети шлёт UDP-пакет 10.70.24.60:6111 -> 255.255.255.255:6111 Сниффер-клиент на нём запущенный, перехватывает этот пакет, шлёт по TCP серверу, сервер пересылает пакет компьютеру в другой сети, напиример, 10.70.18.4. Клиент на 2м компе, 10.70.18.4, Получает от сервера этот пакет в TCP-пакете. Далее, задача: послать этот UDP-пакет, взятый из TCP-пакета, самому себе, так, как будто он пришёл из сети извне. ТАКОЕ ВОЗМОЖНО???? Т.е. в данном примере, комп 10.70.18.4 должен получить броадкаст-UDP пакет от 10.70.24.60:6111... Как это сделать? |