#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#pragma comment(lib,"WS2_32")
#include "Ws2tcpip.h"
//#include <mstcpip.h>
//#include <Wtsapi32.h>
//IP数据报头部
typedef struct _IPHeader //20个字节
{
UCHAR iphVerLen; //版本号和头长度(各占4位)
UCHAR ipTOS; //服务类型
USHORT ipLength; //封包总长度,即整个IP报的长度
USHORT ipID; //封包的标识,惟一标识发送的每一个数据报
USHORT ipFlags; //标志
UCHAR ipTTL; //生存时间,就是TTL
UCHAR ipProtocol; //协议,可能是TCP、UDP、ICMP等
USHORT ipChecksum; //校验和
ULONG ipSource; //源IP地址
ULONG ipDestination; //目标IP地址
}IPHeader,*PIPHeader;
//UDP数据报头
typedef struct _UDPHeader
{
USHORT sourcePort; //源端口号
USHORT destinationPort; //目的端口号
USHORT len; //封包长度
USHORT checksum; //校验和
}UDPHeader,*PUDPHeader;
//TCP数据报头
typedef struct _TCPHeader
{
USHORT sourcePort; //16位源端口号
USHORT destinationPort; //16位目的端口号
ULONG sequenceNumber; //32位序列号
ULONG acknowledgeNumber;//32位确认号
UCHAR dataoffset; //4位首部长度/6位保留字
UCHAR flags; //6位标志位
USHORT windows; //16位窗口大小
USHORT checksum; //16位校验和
USHORT urgentPointer; //16位紧急数据偏移量
}TCPHeader,*PTCPHeader;
//程序运行之后,首先创建原始套接字,将它绑定到一个明确的本地地址(不能为ADDR_ANY),
//然后设置SIO_RCVALL控制代码,最后进入无限循环,不断调用recv函数接收经过本地网卡
//的IP封包。
//解析协议的两个函数
void DecodeTCPPacket(char *pData)
{
TCPHeader *pTCPHdr =(TCPHeader *)pData;
printf("Port :%d->%d\n",ntohs(pTCPHdr->sourcePort),ntohs(pTCPHdr->destinationPort));
//下面还可以根据目的端口号进一步解析应用层协议
switch(ntohs(pTCPHdr->destinationPort))
{
case 21:
break;
case 80:
case 8080:
break;
}
}
void DecodeIPPacket(char *pData)
{
IPHeader *pIPHdr =(IPHeader *)pData;
in_addr source,dest;
char szSourceIp[32],szDestIp[32];
printf("\n\n-------------------\n");
//从IP头中取出源IP地址和目的IP地址
source.S_un.S_addr=pIPHdr->ipSource;
dest.S_un.S_addr=pIPHdr->ipDestination;
strcpy(szSourceIp,inet_ntoa(source));
strcpy(szDestIp,inet_ntoa(dest));
printf("%s->%s\n",szSourceIp,szDestIp);
//IP头长度
int nHeaderLen =(pIPHdr->iphVerLen&0xf)*sizeof(ULONG);
switch(pIPHdr->ipProtocol)
{
case IPPROTO_TCP:
DecodeTCPPacket(pData+nHeaderLen);
break;
case IPPROTO_UDP:
break;
case IPPROTO_IP:
break;
}
}
void main()
{
//创建原始套接字
SOCKET sRaw =socket(AF_INET,SOCK_RAW,IPPROTO_IP);
//获取本地IP地址
char szHostName[56];
SOCKADDR_IN addr_in;
struct hostent *pHost;
gethostname(szHostName,56);
if((pHost=gethostbyname((char *)szHostName))==NULL)
{
return ;
}
//在调用ioctl之前,套接字必须绑定
addr_in.sin_family=AF_INET;
addr_in.sin_port=htons(0);
memcpy(&addr_in.sin_addr.S_un.S_addr,pHost->h_addr_list[0],pHost->h_length);
printf("Binding to interface :%s\n",inet_ntoa(addr_in.sin_addr));
if(bind(sRaw,(PSOCKADDR)&addr_in,sizeof(addr_in))==SOCKET_ERROR)
{
return;
}
//设置SIO_RCVALL控制代码,以便接收所有的IP包
DWORD dwValue =1;
if(ioctlsocket(sRaw,SIO_RCVALL,&dwValue)!=0)
{
return ;
}
//开始接收封包
char buff[1024];
int nRet;
while(TRUE)
{
nRet =recv(sRaw,buff,1024,0);
if(nRet>0)
{
DecodeIPPacket(buff);
}
}
closesocket(sRaw);
}