69,369
社区成员
发帖
与我相关
我的任务
分享
#include "Winsock2.h"
#include "stdio.h"
#include "Ws2tcpip.h"
#pragma comment(lib,"ws2_32.lib")
typedef struct //定义IP报头
{
unsigned short ip_verlen; //4位首部长度+4位版本号
unsigned short ip_tos; //8位服务类型
unsigned short ip_totallength;///16位总长度(字节)
unsigned short ip_id; //16位标识
unsigned short ip_offset; //3位标志位
unsigned short ip_ttl; //8位生存时间 TTL
unsigned short ip_protocol; //8位协议 (TCP, UDP 或其他)
unsigned short ip_checksum; //16位IP首部校验和
unsigned long ip_srcaddr; //32位源IP地址
unsigned long ip_destaddr; //32位目的IP地址
}IP_HDR;
typedef struct //定义UDP报头
{
unsigned short src_portno;//16位源端口
unsigned short dst_portno;//16位目的端口
unsigned short udp_length;//16位长度
unsigned short udp_checksum;//16位校验和
}UDP_HDR;
int main()
{
WSADATA wsd;
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
{
printf("WSAStartup() failed: %d ", GetLastError());
return -1;
}
SOCKET s = WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, NULL, 0,WSA_FLAG_OVERLAPPED); // Create a raw socket
if (s == INVALID_SOCKET)
{
printf("WSASocket() failed: %d ", WSAGetLastError());
return -1;
}
DWORD bOpt = TRUE;
int ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char*) &bOpt, sizeof(bOpt)); // 使用IP_HDRINCL
if (ret == SOCKET_ERROR)
{
printf("setsockopt(IP_HDRINCL) failed: %d ", WSAGetLastError());
return -1;
}
const int BUFFER_SIZE = 80;
char buffer[BUFFER_SIZE];
const char *strMessage = "treat demo"; // Message to send
// Set IP header
const u_short uToPort = 8000;
udpHdr.dst_portno = htons(uToPort); // 接收方端口
const u_short uFromPort = 1000;
udpHdr.src_portno = htons(uFromPort); // 发送伪造的端口
const unsigned short iUdpSize = sizeof(udpHdr) + strlen(strMessage);
udpHdr.udp_length = htons(iUdpSize);
udpHdr.udp_checksum = 0;
// 组建待发送的UDP报文
ZeroMemory(buffer, BUFFER_SIZE);
char *ptr = buffer;
memcpy(ptr, &ipHdr, sizeof(ipHdr));
ptr += sizeof(ipHdr);
memcpy(ptr, &udpHdr, sizeof(udpHdr));
ptr += sizeof(udpHdr);
memcpy(ptr, strMessage, strlen(strMessage));
// Apparently, this SOCKADDR_IN structure makes no difference.
// Whatever we put as the destination IP addr in the IP header is what goes.
// Specifying a different destination in remote will be ignored.
sockaddr_in remote;
remote.sin_family = AF_INET;
remote.sin_port = htons(8000);
remote.sin_addr.s_addr = inet_addr("192.168.0.6");
printf("TO %s:%d ", target_ip_address, uToPort);
ret = sendto(s, buffer, iTotalSize, 0, (SOCKADDR*) &remote, sizeof(remote)); // 发送伪造的报文
if (ret == SOCKET_ERROR)
{
printf("sendto() failed: %d ", WSAGetLastError());
}
else
printf("sent %d bytes ", ret);
closesocket(s);
WSACleanup();
return 1;
}
#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
#include <mmsystem.h>
#pragma comment(lib, "ws2_32")
#pragma comment(lib, "winmm")
#define ICMP_ECHOREPLY 0 //ICMP回应答复
#define ICMP_ECHOREQ 8 //ICMP回应请求
#define REQ_DATASIZE 32 //请求数据报大小
#include <iostream>
using namespace std;
//定义IP首部格式
typedef struct _IPHeader {
u_char VIHL; //版本和首部长度
u_char ToS; //服务类型
u_short TotalLen; //总长度
u_short ID; //标识号
u_short Frag_Flags; //片偏移量
u_char TTL; //生存时间
u_char Protocol; //协议
u_short Checksum; //首部校验和
struct in_addr SrcIP; //源IP地址
struct in_addr DestIP; //目的地址
}
IPHDR, *PIPHDR;
//定义ICMP首部格式
typedef struct _ICMPHeader {
u_char Type; //类型
u_char Code; //代码
u_short Checksum; //首部校验和
u_short ID; //标识
u_short Seq; //序列号
char Data; //数据
}
ICMPHDR, *PICMPHDR;
//定义ICMP回应请求
typedef struct _ECHOREQUEST {
ICMPHDR icmpHdr;
DWORD dwTime;
char cData[REQ_DATASIZE];
}
ECHOREQUEST, *PECHOREQUEST;
//定义ICMP回应答复
typedef struct _ECHOREPLY {
IPHDR ipHdr;
ECHOREQUEST echoRequest;
char cFiller[256];
}
ECHOREPLY, *PECHOREPLY;
//计算校验和
u_short checksum(u_short *buffer, int len) {
register int nleft = len;
register u_short *w = buffer;
register u_short answer;
register int sum = 0;
//使用32位累加器,进行16位的反馈计算
while ( nleft > 1 ) {
sum += *w++;
nleft -= 2;
}
//补全奇数位
if ( nleft == 1 ) {
u_short u = 0;
*(u_char *)(&u) = *(u_char*)w;
sum += u;
}
//将反馈的16位从高位移到低位
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
//发送回应请求函数
int SendEchoRequest(SOCKET s, struct sockaddr_in *lpstToAddr) {
static ECHOREQUEST echoReq;
static int nId = 1;
static int nSeq = 1;
int nRet;
//填充回应请求消息
echoReq.icmpHdr.Type = ICMP_ECHOREQ;
echoReq.icmpHdr.Code = 0;
echoReq.icmpHdr.Checksum = 0;
echoReq.icmpHdr.ID = nId++;
echoReq.icmpHdr.Seq = nSeq++;
//填充要发送的数据
for (nRet = 0; nRet < REQ_DATASIZE; nRet++) {
echoReq.cData[nRet] = '1' + nRet;
}
//存储发送的时间
echoReq.dwTime = timeGetTime();
//计算回应请求的校验和
echoReq.icmpHdr.Checksum = checksum((u_short*)&echoReq, sizeof(ECHOREQUEST));
//发送回应请求
nRet = sendto(s,(LPSTR)&echoReq,sizeof(ECHOREQUEST),
0,(struct sockaddr*)lpstToAddr,sizeof(SOCKADDR_IN));
if (nRet == SOCKET_ERROR) {
printf("send to() error:%d\n", WSAGetLastError());
}
return (nRet);
}
//接收应答回复并进行解析
DWORD RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL) {
ECHOREPLY echoReply;
int nRet;
int nAddrLen = sizeof(struct sockaddr_in);
//接收应答回复
nRet = recvfrom(s,(LPSTR)&echoReply,sizeof(ECHOREPLY),
0,(LPSOCKADDR)lpsaFrom,&nAddrLen);
//检验接收结果
if (nRet == SOCKET_ERROR) {
printf("recvfrom() error:%d\n",WSAGetLastError());
}
//记录返回的TTL
*pTTL = echoReply.ipHdr.TTL;
//返回应答时间
return(echoReply.echoRequest.dwTime);
}
//等待回应答复,使用select模型
int WaitForEchoReply(SOCKET s) {
struct timeval timeout;
fd_set readfds;
readfds.fd_count = 1;
readfds.fd_array[0] = s;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
return(select(1, &readfds, NULL, NULL, &timeout));
}
//PING功能实现
void Ping(char *pstrHost,bool logic) {
SOCKET rawSocket;
LPHOSTENT lpHost;
struct sockaddr_in destIP;
struct sockaddr_in srcIP;
DWORD dwTimeSent;
DWORD dwElapsed;
u_char cTTL;
int nLoop,k=4;
int nRet,minimum=100000,maximum=0,average=0;
int sent=4,reveived=0,lost=0;
//创建原始套接字,ICMP类型
rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (rawSocket == SOCKET_ERROR) {
printf("socket() error:%d\n", WSAGetLastError());
return;
}
//检测目标主机
lpHost = gethostbyname(pstrHost);
if (lpHost==NULL) {
printf("Host not found:%s\n", pstrHost);
return;
}
//设置目标机地址
destIP.sin_addr.s_addr = *((u_long FAR*)(lpHost->h_addr)); //设置目标IP
destIP.sin_family = AF_INET; //地址规格
destIP.sin_port = 0;
//提示开始进行PING
printf("\nPinging %s [%s] with %d bytes of data:\n",pstrHost,inet_ntoa(destIP.sin_addr),REQ_DATASIZE);
//发起多次PING测试
for (nLoop=0; nLoop<k; nLoop++) {
if (logic)k=k+1;
//发送ICMP回应请求
SendEchoRequest(rawSocket, &destIP);
//等待回复的数据
nRet = WaitForEchoReply(rawSocket);
if (nRet == SOCKET_ERROR) {
printf("select() error:%d\n", WSAGetLastError());
break;
}
if (!nRet) {
lost++;
printf("\nRequest time out.");
continue;
}
//接收回复
dwTimeSent = RecvEchoReply(rawSocket, &srcIP, &cTTL);
reveived++;
//计算花费的时间
dwElapsed = timeGetTime() - dwTimeSent;
if(dwElapsed>maximum)maximum=dwElapsed;
if(dwElapsed<minimum)minimum=dwElapsed;
average+=dwElapsed;
printf("\nReply from %s: bytes = %d time = %ldms TTL = %d",
inet_ntoa(srcIP.sin_addr),REQ_DATASIZE,dwElapsed,cTTL);
}
printf("\n\n");
printf("Ping statistics for %s:\n",inet_ntoa(srcIP.sin_addr));
printf(" Packets: Sent = %d, Received = %d, Lost = %d (%.f%% loss),\n",
sent,reveived,lost,(float)(lost*1.0/sent)*100);
if(lost==0) {
printf("Approximate round trip times in milli-seconds:\n");
printf(" Minimum = %dms, Maximum = %dms, Average = %dms\n",minimum,maximum,average/sent);
}
printf("\n\n");
nRet = closesocket(rawSocket);
if (nRet == SOCKET_ERROR) {
printf("closesocket() error:%d\n", WSAGetLastError());
}
}
void main() {
printf("Welcome to the Ping Test\n");
while(1) {
WSADATA wsd;//检测输入的参数
//初始化Winsock
if (WSAStartup(MAKEWORD(1, 1), &wsd) != 0) {
printf("加载 Winsock 失败!\n");
}
char opt1[100];
char *ptr=opt1;
bool log=false;
printf("Ping ");
cin.getline(opt1,100,'\n');
if ((opt1[0]=='-')&&(opt1[1]=='t')&&(opt1[2]==' ')) {
log=true;
ptr=opt1+3;
}
//开始PING
Ping(ptr,log);
//程序释放 Winsock 资源
WSACleanup();
}
}
[/quot]
赵4老师啊,我最近在用多线程做一个局域网ip嗅探器。按照你的思路,我发现只要sock变为可读,select就会返回,那其他非局域网的ip发送的回应ping也会激发select的返回,在调用select之前有什么办法可以过滤掉这些多余的icmp回应么??#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
#include <mmsystem.h>
#pragma comment(lib, "ws2_32")
#pragma comment(lib, "winmm")
#define ICMP_ECHOREPLY 0 //ICMP回应答复
#define ICMP_ECHOREQ 8 //ICMP回应请求
#define REQ_DATASIZE 32 //请求数据报大小
#include <iostream>
using namespace std;
//定义IP首部格式
typedef struct _IPHeader {
u_char VIHL; //版本和首部长度
u_char ToS; //服务类型
u_short TotalLen; //总长度
u_short ID; //标识号
u_short Frag_Flags; //片偏移量
u_char TTL; //生存时间
u_char Protocol; //协议
u_short Checksum; //首部校验和
struct in_addr SrcIP; //源IP地址
struct in_addr DestIP; //目的地址
}
IPHDR, *PIPHDR;
//定义ICMP首部格式
typedef struct _ICMPHeader {
u_char Type; //类型
u_char Code; //代码
u_short Checksum; //首部校验和
u_short ID; //标识
u_short Seq; //序列号
char Data; //数据
}
ICMPHDR, *PICMPHDR;
//定义ICMP回应请求
typedef struct _ECHOREQUEST {
ICMPHDR icmpHdr;
DWORD dwTime;
char cData[REQ_DATASIZE];
}
ECHOREQUEST, *PECHOREQUEST;
//定义ICMP回应答复
typedef struct _ECHOREPLY {
IPHDR ipHdr;
ECHOREQUEST echoRequest;
char cFiller[256];
}
ECHOREPLY, *PECHOREPLY;
//计算校验和
u_short checksum(u_short *buffer, int len) {
register int nleft = len;
register u_short *w = buffer;
register u_short answer;
register int sum = 0;
//使用32位累加器,进行16位的反馈计算
while ( nleft > 1 ) {
sum += *w++;
nleft -= 2;
}
//补全奇数位
if ( nleft == 1 ) {
u_short u = 0;
*(u_char *)(&u) = *(u_char*)w;
sum += u;
}
//将反馈的16位从高位移到低位
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
//发送回应请求函数
int SendEchoRequest(SOCKET s, struct sockaddr_in *lpstToAddr) {
static ECHOREQUEST echoReq;
static int nId = 1;
static int nSeq = 1;
int nRet;
//填充回应请求消息
echoReq.icmpHdr.Type = ICMP_ECHOREQ;
echoReq.icmpHdr.Code = 0;
echoReq.icmpHdr.Checksum = 0;
echoReq.icmpHdr.ID = nId++;
echoReq.icmpHdr.Seq = nSeq++;
//填充要发送的数据
for (nRet = 0; nRet < REQ_DATASIZE; nRet++) {
echoReq.cData[nRet] = '1' + nRet;
}
//存储发送的时间
echoReq.dwTime = timeGetTime();
//计算回应请求的校验和
echoReq.icmpHdr.Checksum = checksum((u_short*)&echoReq, sizeof(ECHOREQUEST));
//发送回应请求
nRet = sendto(s,(LPSTR)&echoReq,sizeof(ECHOREQUEST),
0,(struct sockaddr*)lpstToAddr,sizeof(SOCKADDR_IN));
if (nRet == SOCKET_ERROR) {
printf("send to() error:%d\n", WSAGetLastError());
}
return (nRet);
}
//接收应答回复并进行解析
DWORD RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL) {
ECHOREPLY echoReply;
int nRet;
int nAddrLen = sizeof(struct sockaddr_in);
//接收应答回复
nRet = recvfrom(s,(LPSTR)&echoReply,sizeof(ECHOREPLY),
0,(LPSOCKADDR)lpsaFrom,&nAddrLen);
//检验接收结果
if (nRet == SOCKET_ERROR) {
printf("recvfrom() error:%d\n",WSAGetLastError());
}
//记录返回的TTL
*pTTL = echoReply.ipHdr.TTL;
//返回应答时间
return(echoReply.echoRequest.dwTime);
}
//等待回应答复,使用select模型
int WaitForEchoReply(SOCKET s) {
struct timeval timeout;
fd_set readfds;
readfds.fd_count = 1;
readfds.fd_array[0] = s;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
return(select(1, &readfds, NULL, NULL, &timeout));
}
//PING功能实现
void Ping(char *pstrHost,bool logic) {
SOCKET rawSocket;
LPHOSTENT lpHost;
struct sockaddr_in destIP;
struct sockaddr_in srcIP;
DWORD dwTimeSent;
DWORD dwElapsed;
u_char cTTL;
int nLoop,k=4;
int nRet,minimum=100000,maximum=0,average=0;
int sent=4,reveived=0,lost=0;
//创建原始套接字,ICMP类型
rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (rawSocket == SOCKET_ERROR) {
printf("socket() error:%d\n", WSAGetLastError());
return;
}
//检测目标主机
lpHost = gethostbyname(pstrHost);
if (lpHost==NULL) {
printf("Host not found:%s\n", pstrHost);
return;
}
//设置目标机地址
destIP.sin_addr.s_addr = *((u_long FAR*)(lpHost->h_addr)); //设置目标IP
destIP.sin_family = AF_INET; //地址规格
destIP.sin_port = 0;
//提示开始进行PING
printf("\nPinging %s [%s] with %d bytes of data:\n",pstrHost,inet_ntoa(destIP.sin_addr),REQ_DATASIZE);
//发起多次PING测试
for (nLoop=0; nLoop<k; nLoop++) {
if (logic)k=k+1;
//发送ICMP回应请求
SendEchoRequest(rawSocket, &destIP);
//等待回复的数据
nRet = WaitForEchoReply(rawSocket);
if (nRet == SOCKET_ERROR) {
printf("select() error:%d\n", WSAGetLastError());
break;
}
if (!nRet) {
lost++;
printf("\nRequest time out.");
continue;
}
//接收回复
dwTimeSent = RecvEchoReply(rawSocket, &srcIP, &cTTL);
reveived++;
//计算花费的时间
dwElapsed = timeGetTime() - dwTimeSent;
if(dwElapsed>maximum)maximum=dwElapsed;
if(dwElapsed<minimum)minimum=dwElapsed;
average+=dwElapsed;
printf("\nReply from %s: bytes = %d time = %ldms TTL = %d",
inet_ntoa(srcIP.sin_addr),REQ_DATASIZE,dwElapsed,cTTL);
}
printf("\n\n");
printf("Ping statistics for %s:\n",inet_ntoa(srcIP.sin_addr));
printf(" Packets: Sent = %d, Received = %d, Lost = %d (%.f%% loss),\n",
sent,reveived,lost,(float)(lost*1.0/sent)*100);
if(lost==0) {
printf("Approximate round trip times in milli-seconds:\n");
printf(" Minimum = %dms, Maximum = %dms, Average = %dms\n",minimum,maximum,average/sent);
}
printf("\n\n");
nRet = closesocket(rawSocket);
if (nRet == SOCKET_ERROR) {
printf("closesocket() error:%d\n", WSAGetLastError());
}
}
void main() {
printf("Welcome to the Ping Test\n");
while(1) {
WSADATA wsd;//检测输入的参数
//初始化Winsock
if (WSAStartup(MAKEWORD(1, 1), &wsd) != 0) {
printf("加载 Winsock 失败!\n");
}
char opt1[100];
char *ptr=opt1;
bool log=false;
printf("Ping ");
cin.getline(opt1,100,'\n');
if ((opt1[0]=='-')&&(opt1[1]=='t')&&(opt1[2]==' ')) {
log=true;
ptr=opt1+3;
}
//开始PING
Ping(ptr,log);
//程序释放 Winsock 资源
WSACleanup();
}
}