Код:
/***************************************************************************
"Впервые исходный текст такого сниффера был опубликован в шестом номере журнала #29A,
затем его передрал Z0mnie, переложивший ассемблерный код на интернациональный программистский язык Си++ (странно, а почему не Си?)
и унаследовавший все ляпы оригинала.
Ниже приведен его ключевой фрагмент с моими комментариями,
а полный исходный текст содержится в файле sniffer.с.
Другой источник вдохновления - демонстрационный пример IPHDRINC, входящий в состав Platform SDK 2000. Рекомендую."
(c)Крис Касперски
changed by Gar|k 2010 GNU GPL
***************************************************************************/
#pragma optimize("gsy",on)
#pragma comment(linker, "/MERGE:.data=.text")
#pragma comment(linker, "/MERGE:.rdata=.text")
#pragma comment(linker, "/SECTION:.text,EWR")
#include <stdio.h>
#include <winsock2.h> // Wincosk2.h должен быть раньше windows!
#pragma comment(lib,"Ws2_32.lib")
#include <windows.h>
//#define SIO_ADDRESS_LIST_QUERY _WSAIOR(IOC_WS2,22)
/* во избежании ошибки переполнения 10014 SIO_ADDRESS_LIST_QUERY -- Gar|k
Windows* Sockets 2 / Application Programming Interface / August 7, 1997
"If output buffer is not large enough to contain the address list,
SOCKET_ERROR is returned as the result of this IOCTL and WSAGetLastError() returns WSAEFAULT."
*/
struct SSOCKET_ADDRESS_LIST {
int iAddressCount;
SOCKET_ADDRESS Address[50];
};
#define MAX_PACKET_SIZE 0x10000
struct SIPHEADER {
unsigned char VerLen;
unsigned char ServiceType;
unsigned short PacketLength;
unsigned short Id;
unsigned short Offset;
unsigned char TTL;
unsigned char Protocol;
unsigned short XSum;
unsigned char SrcIP[4];
unsigned char DestIP[4];
};
typedef struct SIPHEADER IPHEADER;
struct SIPPACKET {
unsigned char Header[sizeof(IPHEADER)];
unsigned char Data[MAX_PACKET_SIZE];
};
typedef struct SIPPACKET IPPACKET;
int main(void){
char buf[512];
SOCKET raw_socket;
SSOCKET_ADDRESS_LIST addrlist;
SSOCKET_ADDRESS_LIST *llist=&addrlist;
SOCKADDR_IN addr;
unsigned long N,rcv_all_enabled=1;
int n_addr=0,a,len;
IPPACKET IPPacket;
IPHEADER *IPHeader;
if (WSAStartup(0x202, (WSADATA *)buf))
return printf("-ERR:WSAStart error %d\n", WSAGetLastError());
// создаем сырой сокет
//------------------------------------------------------------------------
if ((raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IP)) == INVALID_SOCKET)
return printf("-ERR:socket(,SOCK_RAW,) -> %d\n", WSAGetLastError());
// (не)устанавиваем атрибут IP_HDRINCL (ибо он на фиг не нужен)
// ------------------------------------------------------------------------
// if (setsockopt(raw_socket,IPPROTO_IP,IP_HDRINCL,(char*)&rcv_all_enabled,
// sizeof(optval)) == SOCKET_ERROR) return printf("-ERR:setsockopt(,,IP_"\
// "HDRINCL) -> %d\n", WSAGetLastError());
// перечисляем все интерфейсы
// -----------------------------------------------------------------------
if (WSAIoctl(raw_socket, SIO_ADDRESS_LIST_QUERY, 0, 0, (LPVOID)&addrlist, sizeof(addrlist), &N, 0, 0) == SOCKET_ERROR)
return printf("-ERR:WSAIoctl(SIO_ADDRESS_LIST_QUERY) error %d\n", WSAGetLastError());
// найден хоть один интерфейс?
if (!(n_addr = llist->iAddressCount)) return printf("-ERR:list is empty\n");
// распечатываем список имеющихся интерфейсов
// ------------------------------------------------------------------------
for (a = 0; a < n_addr; a++)
printf("IP - %s\n", inet_ntoa(((struct sockaddr_in*)llist->Address[a].lpSockaddr)->sin_addr));
// биндим последний интерфейс (последний - для простоты понимания)
addr.sin_family = AF_INET;
addr.sin_addr = ((struct sockaddr_in*)llist->Address[a - 1].lpSockaddr)->sin_addr;
if (bind(raw_socket, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
return printf("-ERR:bind\n");
#define SIO_RCVALL 0x98000001
// сообщаем системе, что мы хотим получать все IP-пакеты, проходящие мимо
// ------------------------------------------------------------------------
if (WSAIoctl(raw_socket, SIO_RCVALL, &rcv_all_enabled, sizeof(rcv_all_enabled), \
0, 0, &N, 0, 0) == SOCKET_ERROR)
return printf("-ERR:WSAIoctl(SIO_RCVALL)-->%d\n", WSAGetLastError());
// получаем все пакеты, приходящие на данный интерфейс
while(1)
{
if ((len = recv(raw_socket, (char *)&IPPacket,sizeof(IPPacket),0)) < 1)
return printf("-ERR:recv()->%d,WSAErr=%i\n", len, WSAGetLastError());
if(len>=sizeof(IPHEADER))
{
IPHeader=(IPHEADER *)&IPPacket.Header;
printf("%d.%d.%d.%d -> %d.%d.%d.%d %d %d\n",IPHeader->SrcIP[0],IPHeader->SrcIP[1],IPHeader->SrcIP[2],IPHeader->SrcIP[3],IPHeader->DestIP[0],IPHeader->DestIP[1],IPHeader->DestIP[2],IPHeader->DestIP[3],IPHeader->Protocol,len);
}
}
WSACleanup();
return 0;
}
как бы вариант на блокирующих сокетах.
|