生成RAW Socket
SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_IP); if(INVALID_SOCKET == s) { printf("socket(AF_INET, SOCK_RAW, IPPROTO_IP) == INVALID_SOCKET, ErrorCode=%d", GetLastError()); return false; }
RAW Socket接收到的数据包保留原始的IP包头。
SOCK_RAW能操作底层传输,所以它们能用于造成安全威胁的恶意目的,故在Windows2000及以后操作系统中只有Administrator组成员可以创建RAW socket。
RAW Socket发送和接收的所有包一概视为无连接的数据报。
绑定本地地址
sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("192.168.4.111"); addr.sin_port = htons(4445); if(SOCKET_ERROR == bind(s, (sockaddr*)&addr, sizeof(addr))) { printf("bind == SOCKET_ERROR, ErrorCode=%d ", GetLastError()); return 0; }
必须进行地址绑定否则设置SIO_RCVALL时出10022错误。
socket绑定IP后将仅接收通过该网卡的IP数据包。它不会接收到流经其他网卡的IP数据包。
有多个网卡,则需循环处理,一次绑定一个,不能使用htonl(INADDR_ANY),否则失败。
设置SIO_RCVALL控制码
RCVALL_VALUE emRcvallValue = RCVALL_IPLEVEL; DWORD dwBytesReturned = 0; if(SOCKET_ERROR == WSAIoctl(s, SIO_RCVALL, &emRcvallValue, sizeof(emRcvallValue), NULL, 0, &dwBytesReturned, NULL, NULL)) { printf("WSAIoctl == SOCKET_ERROR, ErrorCode=%d", GetLastError()); return 0; }SIO_RCVALL控制码将使一个socket能够接收经过该网卡的所有IP数据包。
RCVALL_IPLEVEL为SIO_RCVALL控制码的选项值,类型为RCVALL_VALUE
typedef enum { RCVALL_OFF = 0, RCVALL_ON = 1, RCVALL_SOCKETLEVELONLY = 2, RCVALL_IPLEVEL = 3, } RCVALL_VALUE, *PRCVALL_VALUE;
RCVALL_IPLEVEL在IP层抓包,不会设置网卡为杂乱模式避免了可能的错误,网卡仍旧仅接收发给自己的数据包或广播数据包。该选项仅影响IP层对数据包的处理过程。
不允许先将该控制码作用于一个网卡而后作用于另一个网卡。在把该控制码用于其他网卡前必选先关闭现有socket的SIO_RCVALL控制码。(因电脑只有一个网卡故未得到验证)
抓包
char cBuffer[100*1024] = {0}; int iLenRecv = recv(s, cBuffer, 100*1024, 0); if(SOCKET_ERROR == iLenRecv) { printf("recv == SOCKET_ERROR, ErrorCode=%d", GetLastError()); return false; } if(0 == iLenRecv) { printf("recv == SOCKET_ERROR, Connection Closed"); break; } cBuffer[iLenRecv] = ' ';
妥善关闭
/*关闭SIO_RCVALL*/ emRcvallValue = RCVALL_OFF; if(SOCKET_ERROR == WSAIoctl(s, SIO_RCVALL, &emRcvallValue, sizeof(emRcvallValue), NULL, 0, &dwBytesReturned, NULL, NULL)) { printf("WSAIoctl == SOCKET_ERROR, ErrorCode=%d ", GetLastError()); return false; } /*关闭socket*/ closesocket(s);
完整代码
/*生成RAW socket*/ SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_IP); if(INVALID_SOCKET == s) { WriteToLog("LogicModule::GetProcNetworkFlow: socket == INVALID_SOCKET, ErrorCode=%d", GetLastError()); return false; } /*初始化sockaddr*/ sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("192.168.4.111"); addr.sin_port = htons(4444); /*绑定网卡地址*/ if(SOCKET_ERROR == bind(s, (sockaddr*)&addr, sizeof(addr))) { printf("bind == SOCKET_ERROR, ErrorCode=%d", GetLastError()); return false; } /*设置socket模式*/ RCVALL_VALUE emRcvallValue = RCVALL_IPLEVEL; DWORD dwBytesReturned = 0; if(SOCKET_ERROR == WSAIoctl(s, SIO_RCVALL, &emRcvallValue, sizeof(emRcvallValue), NULL, 0, &dwBytesReturned, NULL, NULL)) { printf("WSAIoctl == SOCKET_ERROR, ErrorCode=%d", GetLastError()); return false; } /*抓包*/ char cBuffer[100*1024] = {0}; int iLenRecv = recv(s, cBuffer, 100*1024, 0); if(SOCKET_ERROR == iLenRecv) { printf("recv == SOCKET_ERROR, ErrorCode=%d", GetLastError()); return false; } if(0 == iLenRecv) { printf("recv == SOCKET_ERROR, Connection Closed"); break; } cBuffer[iLenRecv] = ' '; /*关闭SIO_RCVALL*/ emRcvallValue = RCVALL_OFF; if(SOCKET_ERROR == WSAIoctl(s, SIO_RCVALL, &emRcvallValue, sizeof(emRcvallValue), NULL, 0, &dwBytesReturned, NULL, NULL)) { printf("WSAIoctl == SOCKET_ERROR, ErrorCode=%d ", GetLastError()); return false; } /*关闭socket*/ closesocket(s);