原始套接字 运行在网络层IP,而一般套接字运行在传输层UDP或TCP。
创建原始套接字需要管理员权限,否则即使创建成功也可能在bind()时失败。
XP:
可以在注册表创建HKEY_LOCAL_MACHINESystemCurrentControlSetServiceAfdParametersDisaleRaw-Security,类型DWORD,值1
Win7:
以管理员权限运行编译器即可
#include
#include
#pragma comment(lib,"ws2_32")
#define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
//TCP头部结构体
typedef struct _TCPHeader
{
USHORT sourcePort;
USHORT destinationPort;
ULONG sequenceNumber;
ULONG acknowledgeNumber;
UCHAR dataoffset;
UCHAR flags;
USHORT windows;
USHORT checksum;
USHORT urgentPointer;
}TCPHeader, *PTCPHeader;
//UDP头部结构体
typedef struct _UDPHeader
{
USHORT sourcePort;
USHORT destinationPort;
USHORT len;
USHORT checksum;
}UDPHeader, *PUDPHeader;
//IP头部结构体
typedef struct _IPHeader
{
UCHAR iphVerLen;
UCHAR ipTOS;
USHORT ipLength;
USHORT ipID;
USHORT ipFlags;
UCHAR ipTTL;
UCHAR ipProtocol;
USHORT ipChecksum;
ULONG ipSource;
ULONG ipDestination;
}IPHeader, *PIPHeader;
void DecodeTCPPacket(char *pData);
void DecodeUDPPacket(char *pData);
void DecodeIPPacket(char *pData);
void main()
{
WSAData ws;
char szHostName[56];
//存放主机名
SOCKADDR_IN addr_in;
//SOCKADDR_IN 地址结构体
struct hostent *pHost;
DWORD dwValue = 1;
char buffer[255];
int nRet;
WSAStartup(MAKEWORD(2,2),&ws);
SOCKET sRaw = socket(AF_INET,SOCK_RAW,IPPROTO_IP);
//创建原始套接字
gethostname(szHostName,56);
//取主机名
if((pHost = gethostbyname((char *)szHostName)) == NULL)
//根据主机名返回一个struct hostent的地址信息结构体
return;
//初始化地址结构体 SOCKADDR_IN
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("bind to interface:%s
",::inet_ntoa(addr_in.sin_addr));
if(bind(sRaw,(SOCKADDR *)&addr_in,sizeof(addr_in)) == SOCKET_ERROR)
//绑定bind
{
return;
}
if(ioctlsocket(sRaw,SIO_RCVALL,&dwValue) != 0)
//获取套接字操作参数
{
return;
}
while(1)
{
nRet = recv(sRaw,buffer,1024,0);
//接受套接字
if(nRet > 0)
{
DecodeIPPacket(buffer);
//解码IP数据包
}
}
closesocket(sRaw);
}
//解码TCP
void DecodeTCPPacket(char *pData)
{
TCPHeader *pTcpHdr = (TCPHeader *)pData;
printf("TCP Port:%d -> %d
",ntohs(pTcpHdr->sourcePort),ntohs(pTcpHdr->destinationPort));
//输出TCP端口号
}
void DecodeUDPPacket(char *pData)
{
UDPHeader *pUdpHdr = (UDPHeader *)pData;
printf("UDP Port:%d -> %d
",ntohs(pUdpHdr->sourcePort),ntohs(pUdpHdr->destinationPort));
//输出UDP端口号
}
void DecodeIPPacket(char *pData)
{
IPHeader *pIpHdr = (IPHeader *)pData;
//IP首部结构体
in_addr source,destination;
//地址结构体 记录 源、目的地址
char szSourceIp[32],szDestinationIp[32];
int nHeaderLen;
//计算IP头部长度使用的变量
source.S_un.S_addr = pIpHdr->ipSource;
//获得源IP地址
destination.S_un.S_addr = pIpHdr->ipDestination;
//获得目的IP地址
strcpy(szSourceIp,::inet_ntoa(source));
//转换后记录下源IP
strcpy(szDestinationIp,::inet_ntoa(destination));
//转换后记录下目的IP
nHeaderLen = (pIpHdr->iphVerLen & 0xF)* sizeof(ULONG);
//计算头部长度
//根据类型使用相应的解码程序
switch(pIpHdr->ipProtocol)
{
case IPPROTO_TCP:
{
DecodeTCPPacket(pData + nHeaderLen);
//解码IP头部以后的部分(即TCP包)
break;
}
case IPPROTO_UDP:
{
DecodeUDPPacket(pData + nHeaderLen);
//解码IP头部以后的部分(即UDP包)
break;
}
case IPPROTO_ICMP:
{
break;
}
default:
break;
}
}