// NetSniffer.cpp : 定义控制台应用程序的入口点。 // /* 简单说明一下什么是网络嗅探器,网络嗅探器是一个抓取所有经过网卡数据的软件,在一般使用电脑时,网卡 只接受到发送至本机的数据,那是因为这是网卡是非混杂模式的,挡一个目的地址非本机地址的数据包经过网 卡时,网卡在数据链路层(mac地址)检测到是非本机数据,则直接丢弃,当设置为混杂模式时,所有经过网卡 的数据包均可被读取出来。 */ #include "stdafx.h" #include <WinSock2.h> #include <ws2tcpip.h> #include <mstcpip.h> #include "datastruct.h" #include "procdata.h" #pragma comment(lib, "Ws2_32.lib") #define BUF 256 #define RECVBUF 1500 int _tmain(int argc, _TCHAR* argv[]) { // Declare some variables WSADATA wsaData; int iResult = 0; iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iResult != NO_ERROR) { wprintf(L"Error at WSAStartup()\n"); return 1; } SOCKET sock = INVALID_SOCKET; // 理论上在socket 第三个参数设定为制定协议类型(如0x0800或0x0806或多个等等),则可以获取 // 数据链路层的数据,即包括了以太网帧的首部在数据部分,但window 封闭了这一层,所以获取 // 数据只能去到ip层。若想获取以太网帧可以使用winpcap 开发库,linux下是libpcap。(注意: // Linux下可用socket套接字获取数据链路层) if ((sock = socket(AF_INET, SOCK_RAW, /*htons(0x0800)*/IPPROTO_IP)) == INVALID_SOCKET) { printf("socket error:%d\n", GetLastError()); WSACleanup(); return 1; } // hostent 结构体包含了所有能抓取到的网卡对应的地址 struct sockaddr_in addr; char hostname[BUF] = {0}; int namelen = gethostname(hostname, BUF); struct hostent *phost = gethostbyname(hostname); if (phost != NULL) { addr.sin_family = AF_INET; addr.sin_port = htons(0); char *paddr; int i = 0; for (paddr = *phost->h_addr_list; paddr != NULL; ++i, paddr = *(phost->h_addr_list + i)) { memcpy(&(addr.sin_addr), paddr, phost->h_length); printf("[%d] %s\n", i, inet_ntoa(addr.sin_addr)); } printf("Please chose a device for Sniffer:"); int index; reenter: scanf("%d", &index); if (index < 0 || index >= i) goto reenter; paddr = *(phost->h_addr_list + index); memcpy(&(addr.sin_addr), paddr, phost->h_length); } else { closesocket(sock); WSACleanup(); return 1; } if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { closesocket(sock); WSACleanup(); return 1; } // 设置网卡为混杂模式 unsigned long flag = 1; if (ioctlsocket(sock, SIO_RCVALL, &flag) != 0) { closesocket(sock); WSACleanup(); return 1; } char recvbuf[RECVBUF]; size_t size = 0; pip_header pip; int count = 0; while (1) { // 接受到IP数据包 size = recv(sock, recvbuf, RECVBUF, 0); if (size == 0 || size == SOCKET_ERROR) { if (size == SOCKET_ERROR) { closesocket(sock); WSACleanup(); return 1; } continue; } count++; // printf("[%0.4d]\t", count); pip = (pip_header)recvbuf; switch (pip->proto) { case IPPROTO_TCP: procTcpPack(recvbuf); break; case IPPROTO_UDP: procUdpPack(recvbuf); break; case IPPROTO_ICMP: procIcmpPack(recvbuf); break; case IPPROTO_IGMP: printf("Catch a IGMP, len : %d.\n", ntohs(pip->tlen)); break; case IPPROTO_EGP: printf("Catch a EGP, len : %d.\n", ntohs(pip->tlen)); break; case IPPROTO_IGP: printf("Catch a IGP, len : %d.\n", ntohs(pip->tlen)); break; case IPPROTO_ESP: printf("Catch a ESP, len : %d.\n", ntohs(pip->tlen)); break; case MIB_IPPROTO_OSPF: printf("Catch a OSPF, len : %d.\n", ntohs(pip->tlen)); break; default: printf("Unknow proto.\n"); break; }; memset(recvbuf, 0, sizeof(recvbuf)); } return 0; }
datastruct.h
#ifndef _DATASTRUCT_H_ #define _DATASTRUCT_H_ typedef struct mac_header { char destaddr[6]; char souraddr[6]; unsigned short frametype; }mac_header, *pmac_header; #pragma pack(push, 1) typedef struct ip_header { unsigned char ver4_hlen4; // 版本 和 首部长度 unsigned char diffserv; // 区分服务 unsigned short tlen; // 总长度 unsigned short flag; // 标识 unsigned short flag4_fraoff12; // 标志 和 片偏移 unsigned char ttl; // 生存时间 unsigned char proto; // 协议 unsigned short crc; // 首部检验和 unsigned long souraddr; // 源地址 unsigned long destaddr; // 目的地址 }ip_header, *pip_header; typedef struct udp_header { unsigned short sourport; unsigned short destport; unsigned short tlen; unsigned short crc; }udp_header, *pudp_header; typedef struct tcp_header { unsigned short sourport; unsigned short destport; unsigned long snum; unsigned long acknum; unsigned short off4_reser6_flag6; unsigned short window; unsigned short crc; unsigned short emerp; }tcp_header, *ptcp_header; typedef struct iph_pack { unsigned short hlen; unsigned short tlen; unsigned long souraddr; unsigned long destaddr; }iph_pack; #pragma pack(pop) #endifprocdata.h
#ifndef _PROCDATA_H #define _PROCDATA_H #define _WINSOCK_DEPRECATED_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #include "datastruct.h" #include <memory.h> #include <stdio.h> #include <WinSock2.h> #include <ws2tcpip.h> #include <mstcpip.h> struct iph_pack procIpHeader(char *ipdata); // udp,tcp,icmp 和 http,ftp... 均是被封装在ip数据包中 void procUdpPack(char *ipdata); void procTcpPack(char *ipdata); void procIcmpPack(char *ipdata); void procIgmpPack(char *ipdata); #endif
#include "procdata.h" // 处理ip首部 struct iph_pack procIpHeader(char *ipdata) { struct iph_pack len; memset(&len, 0, sizeof(len)); if (!ipdata) return len; struct ip_header *iph = (struct ip_header *)ipdata; len.hlen = (iph->ver4_hlen4 & 0xf) * 4; //printf("header len : %d ", len.hlen); len.tlen = iph->tlen; len.souraddr = iph->souraddr; len.destaddr = iph->destaddr; return len; } void procUdpPack(char *ipdata) { struct iph_pack hPack = procIpHeader(ipdata); // 随便找一个变量作判断 if (hPack.hlen == 0) return; struct udp_header *uh = (struct udp_header *)(ipdata + hPack.hlen); struct in_addr addr1,addr2; printf("total_len(%-4d)\t", ntohs(hPack.tlen)); char buf[16]; memset(buf, 0, 16); switch (ntohs(uh->destport)) { // DNS case 53: strncpy(buf, "DNS", 3); break; // TFTP case 69: strncpy(buf, "TFTP", 4); break; // SNMP case 161: strncpy(buf, "SNMP", 4); break; case 520: strncpy(buf, "RIP", 3); break; // 非常用的熟知端口号 default: strncpy(buf, "UDP", 3); break; } printf("%-6s\t", buf); addr1.s_addr = hPack.souraddr; addr2.s_addr = hPack.destaddr; printf("%-15s:%5d -> ", inet_ntoa(addr1), ntohs(uh->sourport) ); printf("%-15s:%5d\n", inet_ntoa(addr2), ntohs(uh->destport)); } void procTcpPack(char *ipdata) { struct iph_pack hPack = procIpHeader(ipdata); // 随便找一个变量作判断 if (hPack.hlen == 0) return; struct tcp_header *th = (struct tcp_header *)(ipdata + hPack.hlen); struct in_addr addr1, addr2; printf("total_len(%-4d)\t", ntohs(hPack.tlen)); char buf[16]; memset(buf, 0, 16); switch (ntohs(th->destport)) { // FTP case 21: strncpy(buf, "FTP", 3); break; // TELNET case 23: strncpy(buf, "TELNET", 6); break; // SMTP case 161: strncpy(buf, "SMTP", 4); break; // HTTP case 80: strncpy(buf, "HTTP", 4); break; // 非常用的熟知端口号 default: strncpy(buf, "TCP", 3); break; } printf("%-6s\t", buf); addr1.s_addr = hPack.souraddr; addr2.s_addr = hPack.destaddr; printf("%-15s:%5d -> ", inet_ntoa(addr1), ntohs(th->sourport) ); printf("%-15s:%5d\n", inet_ntoa(addr2), ntohs(th->destport)); } void procIcmpPack(char *ipdata) { struct iph_pack hPack = procIpHeader(ipdata); struct in_addr addr1, addr2; char buf[16] = "ICMP"; printf("total_len(%-4d)\t%-6s\t%-22s -> ", ntohs(hPack.tlen), buf, inet_ntoa((addr1.s_addr = hPack.souraddr, addr1)) ); printf("%-22s\n", inet_ntoa((addr2.s_addr = hPack.destaddr, addr2))); }