注意,应以管理员身份运行,否则会无效创建原始套接字!
代码
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#define DestPort 65432 //目的UDP端口
#define SourcePort 65433 //源UDP端口
#include "iostream"
#include "winsock2.h"
#include "string.h"
#include "ws2tcpip.h"
#pragma comment(lib,"ws2_32.lib")
using namespace std;
typedef struct _IPHeader { //定义IP首部结构
unsigned char iphVerLen; //版本号和头部长度
unsigned char ipTOS; //服务类型
unsigned short ipLength; //分组总长度
unsigned short ipID; //分组标识
unsigned short ipFlags; //标志
unsigned char ipTTL; //生存时间
unsigned char ipProtocol; //协议
unsigned short ipChecksum; //校验和
unsigned long ipSource; //源IP地址
unsigned long ipDestination; //目的IP地址
}IPHeader;
typedef struct _UDPHeader { //定义IP首部结构
unsigned short sourcePort; //源端口号
unsigned short destinationPort;//目的端口号
unsigned short len; //包长度
unsigned short checksum; //校验和
}UDPHeader;
typedef struct tsd_hdr { //定义UDP伪首部结构
unsigned long saddr; //源IP地址
unsigned long daddr; //目的IP地址
char mbz; //填充
char ptcl; //协议型
unsigned short udpl; //TCP长度
}PSDHEADER;
unsigned short checksum(unsigned short * buff, int size) {
unsigned long cksum = 0;
while (size > 1) {
cksum += *buff++;
size -= sizeof(unsigned short);
}
if (size)cksum += *(char *)buff;
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16);
return (unsigned short)(~cksum);
}
int main(int argc, char **argv) {
//加载winsock2.2
WSADATA wsaData;
int ret;
if ((ret = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) {
cout << "初始化WinSock2.2出错!";
return -1;
}
//输入目的IP地址或域名
char szDestIp[256] = { 0 };
cout << "请输入目的地址:" << endl;
cin.getline(szDestIp, sizeof(szDestIp));
char szSourceIp[] = "192.168.0.108"; //源IP地址(本机IP地址)
char szMsg[] = "give you a UDP package!\n";
int nMsgLen = strlen(szMsg);
SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (sRaw == INVALID_SOCKET) {
cout << WSAGetLastError()<<endl;
return -1;
}
//绑定本地IP地址
sockaddr_in addr;
memset((void *)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(SourcePort);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sRaw, (sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) {
cout << "bind failed" << endl;
WSACleanup();
return 0;
}
int bIncl = 1;
setsockopt(sRaw,IPPROTO_IP, IP_HDRINCL, (char *)&bIncl, sizeof(bIncl));
//创建并填充IP首部
char buff[1024] = { 0 };
IPHeader *pIphdr = (IPHeader *)buff;
pIphdr->iphVerLen = (4 << 4 | (sizeof(IPHeader) / sizeof(unsigned long)));
pIphdr->ipLength = htons(sizeof(IPHeader) + sizeof(UDPHeader) + sizeof(UDPHeader) + nMsgLen);
pIphdr->ipTTL = 128;
pIphdr->ipProtocol = IPPROTO_UDP;
pIphdr->ipSource = inet_addr(szSourceIp);
pIphdr->ipDestination = inet_addr(szDestIp);
pIphdr->ipChecksum = checksum((unsigned short *)pIphdr, sizeof(IPHeader));
//填充UDP首部
UDPHeader *pUdphdr = (UDPHeader *)&buff[sizeof(IPHeader)];
pUdphdr->sourcePort = htons(SourcePort);
pUdphdr->destinationPort = htons(DestPort);
pUdphdr->len = htons(sizeof(UDPHeader) + nMsgLen);
pUdphdr->checksum = 0;
//填充UDP数据
char *pData = &buff[sizeof(IPHeader) + sizeof(UDPHeader)];
memcpy(pData, szMsg, nMsgLen);
//填充伪首部
PSDHEADER psdHeader;
psdHeader.saddr = pIphdr->ipSource;
psdHeader.daddr = pIphdr->ipDestination;
psdHeader.mbz = 0;
psdHeader.ptcl = IPPROTO_UDP;
psdHeader.udpl = htons(sizeof(UDPHeader) + nMsgLen);
char szBuff[1024];
memcpy(szBuff, &psdHeader, sizeof(psdHeader));
memcpy(szBuff + sizeof(psdHeader), pUdphdr, sizeof(UDPHeader));
memcpy(szBuff + sizeof(psdHeader) + sizeof(UDPHeader), pData, nMsgLen);
pUdphdr->checksum = checksum((unsigned short *)szBuff, sizeof(psdHeader) + sizeof(UDPHeader) + nMsgLen);
//填充发送目的地址
sockaddr_in destAddr = { 0 };
destAddr.sin_family = AF_INET;
destAddr.sin_port = htons(DestPort);
destAddr.sin_addr.S_un.S_addr = inet_addr(szDestIp);
//发送5个原始UDP数据报
int nRet;
for (int i = 0; i < 5; i++) {
nRet = sendto(sRaw, buff, sizeof(IPHeader) + sizeof(UDPHeader) + nMsgLen, 0, (sockaddr *)&destAddr, sizeof(destAddr));
if (nRet == SOCKET_ERROR) {
cout << "send failed! 错误代码: " <<GetLastError()<< endl;
break;
}
else
cout << "发送字节数: " << nRet << endl;
Sleep(1000);
}
closesocket(sRaw);
WSACleanup();
return 0;
}