Raw сокеты WinSocket C++. В данной статье – примере мне хотелось бы показать работу с простыми(raw) сокетами. Данные сокеты позволяют получить доступ к базовому протоколу передачи данных, это дает нам большие возможности создания таких сетевых утилит как Ping, Traceroute, а также для организации IP Spoofing, DDoS, ICMP-flood, и многого еще =) Рассматривать будем только протокол IP, так как большинство других протоколов вообще не поддерживают простые сокеты, разве только ATM.
Поддержка данного типа сокетов начинается только в Windows Sockets 2-ой версии. Первое, что необходимо сделать для использования данного типа сокета – это его создание. Для этого запускаем Visual C++, далее создаем новый проект(«CTRL+N» или File->New), тип проекта «Win32 Console Application», и пишем следующий код:
#include <Winsock2.h>//Ws2_32.lib #include <Windows.h> #include <iostream.h> void ShowError() { LPVOID lpMsgBuf = NULL; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,NULL,WSAGetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR)&lpMsgBuf,0,NULL); cout<<(LPCTSTR)lpMsgBuf<<endl; LocalFree(lpMsgBuf); } int main() { WSADATA wsaData; if(WSAStartup(0x0202,&wsaData)){ShowError();} else { cout<<"WSAStartup - OK"<<endl; SOCKET sckt; sckt = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP); if(sckt == INVALID_SOCKET){ShowError();} { cout<<"Raw scoket is created"<<endl; if(closesocket(sckt)== SOCKET_ERROR){ShowError();} } if(WSACleanup()){ShowError();} else{cout<<"WSACleanup - OK"<<endl;} } return 0; }
Как видно из приведенного кода, для создания простого сокета достаточно указать вторым аргументом функции socket, протокол SOCK_RAW, но самое интересное представляет третий аргумент, в приведенной выше коде мы использовали IPPROTO_ICMP, но так же можно использовать IPPROTO_IGMP, IPPROTO_IP, IPPROTO_UDP, IPPROTO_RAW, IPPROTO_TCP, все эти параметры позволяют нам манипулировать заголовками представленных протоколов. При самостоятельном заполнение IP заголовка, необходимо добавить в код следующие строки:
BOOL opt = TRUE; if(setsockopt (sckt,IPPROTO_IP,IP_HDRINCL,(char*)&opt,sizeof(opt))==SOCKET_ERROR) {ShowError();}
Это позволит функции отправки(send, sendto) отправить заголовок IP перед посылаемыми данными, а функция приема вернет этот заголовок вместе с данными. На рисунке представленном ниже показан заголовок IP.
Теперь нам надо определить структуру, которая будет представлять IP заголовок:
typedef struct ip_hdr { unsigned char ip_verlen; unsigned char ip_tos; unsigned short ip_total_len; unsigned short ip_id; unsigned short ip_offset; unsigned char ip_ttl; unsigned char ip_protocol; unsigned short ip_checksum; unsigned int sourceIP; unsigned int destIP; }IP_HDR;
Для начальных опытов мы попробуем создать простой UDP сокет, так как он проще, его величина всего 8 байт, содержит 4 поля, более наглядно показано на рисунке ниже.
Определение структуры UDP заголовка.
typedef struct udp_hdr { unsigned short source_port; unsigned short dest_port; unsigned short udp_len; unsigned short udp_sum; }UDP_HDR;
Как Вы знаете протокол UDP ненадежный и не гарантирует доставку данных, значит вычисление контрольной суммы не обязательно, хотя и можно это сделать. Для этого используется псевдозаголовок представленный на рисунке:
Контрольная сумма UDP рассчитывается точно так же, как контрольная сумма IP заголовка, сумма 16-битных слов с переполнением. Если UDP датаграмма состоит из нечетного количества байт то необходимо в конце датаграммы добавить нулевые байты заполнения(который не передаются). Для расчета контрольной суммы в коде программы мы будем использовать следующею функцию, которая одинаковая для всех протоколов TCP/IP:
USHORT checksum(USHORT *buffer, int size) { unsigned long cksum=0; while (size > 1){ cksum += *buffer++; size -= sizeof(USHORT); } if (size){ cksum += *(UCHAR*)buffer; } cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >>16); return (USHORT)(~cksum); }
Вот полный вариант программы:
#include <Winsock2.h>//Ws2_32.lib #include <ws2tcpip.h> //#include <Windows.h> #include <iostream.h> #include <stdio.h> #include <stdlib.h> /*****************************************************************/ void ShowError() { LPVOID lpMsgBuf = NULL; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,NULL,WSAGetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR)&lpMsgBuf,0,NULL); CharToOem((char*)lpMsgBuf,(char*)lpMsgBuf); cout<<(LPCTSTR)lpMsgBuf<<endl; LocalFree(lpMsgBuf); } USHORT checksum(USHORT *buffer, int size) { unsigned long cksum=0; while (size > 1){ cksum += *buffer++; size -= sizeof(USHORT); } if (size){ cksum += *(UCHAR*)buffer; } cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >>16); return (USHORT)(~cksum); } /*****************************************************************/ typedef struct ip_hdr { unsigned char ip_verlen; unsigned char ip_tos; unsigned short ip_total_len; unsigned short ip_id; unsigned short ip_offset; unsigned char ip_ttl; unsigned char ip_protocol; unsigned short ip_checksum; unsigned int sourceIP; unsigned int destIP; }IP_HDR; typedef struct udp_hdr { unsigned short source_port; unsigned short dest_port; unsigned short udp_len; unsigned short udp_sum; }UDP_HDR; /*****************************************************************/ int main() { WSADATA wsaData; struct sockaddr_in remote; IP_HDR ipHdr; UDP_HDR udpHdr; unsigned short iTotalSize,iIPSize,iUdpSize, iUdpChecksumSize,ver; char buf[4096],*ptr,szMessage[4068]; strcpy(szMessage,"Code by Lazy_elf"); if(WSAStartup(0x0202,&wsaData)){ShowError();} else { cout<<"WSAStartup - OK"<<endl; SOCKET sckt; sckt = WSASocket (AF_INET,SOCK_RAW,IPPROTO_UDP,NULL,0,0); if(sckt == INVALID_SOCKET){ShowError();} { cout<<"Raw scoket is created"<<endl; BOOL opt = TRUE; if(setsockopt (sckt,IPPROTO_IP,IP_HDRINCL,(char*)&opt,sizeof(opt))==SOCKET_ERROR) {ShowError();} else { cout<<"setsockopt - OK"<<endl; iTotalSize = sizeof(ipHdr)+sizeof(udpHdr)+strlen(szMessage); iIPSize = sizeof(ipHdr)/sizeof(unsigned long); ver = 4; ipHdr.ip_verlen = (ver<<4) | iIPSize; ipHdr.ip_tos = 0; ipHdr.ip_total_len = htons(iTotalSize); ipHdr.ip_id = 0; ipHdr.ip_offset = 0; ipHdr.ip_ttl = 128; ipHdr.ip_protocol = IPPROTO_UDP; ipHdr.ip_checksum = 0; ipHdr.sourceIP = inet_addr("10.10.10.1"); ipHdr.destIP = inet_addr("10.10.10.2"); //-------------------------------------------// iUdpSize = sizeof(udpHdr)+strlen(szMessage); udpHdr.source_port = htons(3004); udpHdr.dest_port = htons(4004); udpHdr.udp_len = htons(iUdpSize); udpHdr.udp_sum = 0; //-------------------------------------------// iUdpChecksumSize = 0; ptr = buf;ZeroMemory(buf,4096); memcpy(ptr,&ipHdr.sourceIP, sizeof(ipHdr.sourceIP)); ptr += sizeof(ipHdr.sourceIP); iUdpChecksumSize += sizeof(ipHdr.sourceIP); memcpy(ptr,&ipHdr.destIP,sizeof(ipHdr.destIP)); ptr += sizeof(ipHdr.destIP); iUdpChecksumSize += sizeof(ipHdr.destIP); ptr++;iUdpChecksumSize += 1; memcpy(ptr,&ipHdr.ip_protocol,sizeof(ipHdr.ip_protocol)); ptr += sizeof(ipHdr.ip_protocol); iUdpChecksumSize += sizeof(ipHdr.ip_protocol); memcpy(ptr,&udpHdr.udp_len,sizeof(udpHdr.udp_len)); ptr += sizeof(udpHdr.udp_len); iUdpChecksumSize += sizeof(udpHdr.udp_len); memcpy(ptr,&udpHdr,sizeof(udpHdr)); ptr += sizeof(udpHdr); iUdpChecksumSize += sizeof(udpHdr); for(unsigned int i = 0; i < strlen(szMessage); i++, ptr++) *ptr = szMessage[i]; iUdpChecksumSize += strlen(szMessage); udpHdr.udp_sum = checksum((USHORT *)buf, iUdpChecksumSize); ZeroMemory(buf,4096);ptr = buf; memcpy(ptr,&ipHdr, sizeof(ipHdr)); ptr += sizeof(ipHdr); memcpy(ptr,&udpHdr,sizeof(udpHdr));ptr += sizeof(udpHdr); memcpy(ptr,szMessage,strlen(szMessage)); remote.sin_family = AF_INET; remote.sin_port = htons(4004); remote.sin_addr.s_addr = inet_addr("10.10.10.2"); if(sendto(sckt,buf,iTotalSize,0,(SOCKADDR *)&remote,sizeof(remote))==SOCKET_ERROR){ShowError();} else{cout<<"sendto - OK"<<endl;} } if(closesocket(sckt)== SOCKET_ERROR){ShowError();} else{cout<<"closesocket - OK"<<endl;} } if(WSACleanup()){ShowError();} else{cout<<"WSACleanup - OK"<<endl;} } return 0; }
WireShark не детектирует отсылку этих пакетов
Вероятно данный метод уже устарел, статья писалась очень давно.
А можно похожий пример только вместо udp вставить icmp?
if(setsockopt (sckt,IPPROTO_IP,IP_HDRINCL,(char*)&opt,sizeof(opt))==SOCKET_ERROR)
у меня вылетает по 10049
Обсуждение закрыто.