利用原始套接字实现对流经本机IP包的捕获

来源:互联网 发布:2011年nba总决赛数据 编辑:程序博客网 时间:2024/06/05 10:41

经过上一篇博客的总结,我知道到了原始套接字接收到的字符串的开始字段是IP数据报的首部,所以我想除了之前利用win_pcap可以捕获数据包以外,理论上来说原始套接字也可以实现对IP数据报的捕获。思路也很简单,捕获到字符串以后转换成指向IP首部结构体的指针,再打印相关信息就可以了。

当然由于网卡会默认丢掉不属于本机的数据包,所以需要将套接字设置为接收所有数据。win_pcap是直接对网卡进行设置。ioctlsocket( )函数用于控制套接字上的I/O行为,同时获取与那个套接字上挂起的网络I/O操作的有关信息。

int ioctlsocket(SOCKET s,//套接字long cmd,//对s的命令u_long* argp//命令参数指针)//如果成功的话返回0,如果失败的话返回错误代码
函数的示例(让socket接收所有数据包):

u_long flag=1;ioctlsocket(s,SIO_RCVALL,&flag);

于是有了以下一段代码:

#include "stdafx.h"#include <winsock2.h>#include <ws2tcpip.h> #include "mstcpip.h"     //自定义#include <stdio.h>#pragma comment(lib, "ws2_32.lib")struct IPHEADER{unsigned char h_verlen; //4位首部长度,4位IP版本号 unsigned char tos; //8位服务类型TOS unsigned short total_len; //16位总长度(字节) unsigned short ident; //16位标识 unsigned short frag_and_flags; //3位标志位 unsigned char ttl; //8位生存时间 TTL unsigned char proto; //8位协议 (TCP, UDP 或其他) unsigned short checksum; //16位IP首部校验和 in_addr sourceIP; //32位源IP地址 in_addr destIP; //32位目的IP地址 };#define BUFSIZE 256#define RECVBUF 1520int analyzeIP(IPHEADER *pip, int buflen){if (buflen < 20){printf("此包不完整!\n");}printf("版本号:%d\n", pip->h_verlen >> 4);printf("首部长度(字节):%d\n", (pip->h_verlen & 0x0f)*4);printf("总长度:%d\n", pip->total_len);printf("协议类型:%d\n", pip->proto);printf("源地址:%s\n", inet_ntoa(pip->sourceIP));printf("目的地址:%s\n", inet_ntoa(pip->destIP));return 0;}int main(){SOCKET s;WSADATA wsa;int retval;retval = WSAStartup(MAKEWORD(2, 2), &wsa);if (retval == SOCKET_ERROR){printf("startup failed\n");WSACleanup();return 0;}s = socket(AF_INET, SOCK_RAW, IPPROTO_IP);if (s == INVALID_SOCKET){printf("socket error\n");WSACleanup();return 0;}sockaddr_in addr;char hostname[BUFSIZE] = { 0 };int namelen;namelen = gethostname(hostname, BUFSIZE);//取得本机名,存放在hostname里面hostent *ph = gethostbyname(hostname);if (ph == NULL){printf("gethostbyname failed\n");WSACleanup();closesocket(s);return 0;}addr.sin_family = AF_INET;addr.sin_port = htons(0);memcpy(&(addr.sin_addr), ph->h_addr, ph->h_length);retval = bind(s, (sockaddr*)&addr, sizeof(sockaddr_in));if (retval == SOCKET_ERROR){printf("bind error\n");closesocket(s);WSACleanup();return 0;}unsigned long flag = 1;retval = ioctlsocket(s, SIO_RCVALL, &flag);//将网卡设置为混杂if (retval != 0){printf("ioctlsocket error\n");closesocket(s);WSACleanup();return 0;}char recvbuf[RECVBUF];size_t size;IPHEADER *p_ipheader;int cnt = 0;while (1){size = recv(s, recvbuf, RECVBUF, 0);if (size == 0 || size == SOCKET_ERROR){printf("recv error\n");closesocket(s);WSACleanup();continue;}cnt++;printf("第 %d 个包\n", cnt);p_ipheader = (IPHEADER*)recvbuf;analyzeIP(p_ipheader, size);memset(recvbuf, 0, sizeof(recvbuf));}WSACleanup();closesocket(s);return 0;}


但当我把这个程序和win_pcap的程序一起运行的时候,发现这个程序捕获的包没有win_pcap的程序捕获得多,而且这个程序捕获的包部分信息也很奇怪,比如源地址,目的地址等,于是我猜想这可能是windows处于安全原因对原始套接字的使用也做出了限制。

0 0
原创粉丝点击