我最近要写一个程序,用到要写一个自己的ping程序,而且要改变发出去的数据报的原地址,参看的csdn里不少文章,但由于我水品有限,现在实现起来还是有困难,第一次写文章求救,希望大家帮忙!谢谢!在我不自己填写ip头时,程序还能正常ping通,但是我尝试着自己填充ip头后,就ping不了了!ip头的数据结构typedef struct ip_hdr
{
unsigned char ip_verlen;
unsigned char ip_tos;
unsigned short ip_totallength;
unsigned short ip_id;
unsigned short ip_offset;
unsigned char ip_ttl;
unsigned char ip_protocol;
unsigned short ip_checksum;
unsigned int ip_srcaddr;
unsigned int ip_destaddr;
}IPHDR, *PIPHDR;icmp数据结构typedef struct tagICMPHDR
{
unsigned char Type; // Type
unsigned char Code; // Code
u_short Checksum; // Checksum
u_short ID; // Identification
u_short Seq; // Sequence
unsigned char Data; // Data
}ICMPHDR, *PICMPHDR;
#define REQ_DATASIZE 32 // Echo Request Data size// ICMP Echo Request
typedef struct tagECHOREQUEST
{
ICMPHDR icmpHdr;
DWORD dwTime;
unsigned char cData[REQ_DATASIZE];
}ECHOREQUEST, *PECHOREQUEST;
// ICMP Echo Reply
typedef struct tagECHOREPLY
{
IPHDR ipHdr;
ECHOREQUEST echoRequest;
unsigned char cFiller[256];
}ECHOREPLY, *PECHOREPLY;我就不全放上程序了,选重要的。bool bOpt=true;
setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL, (char*)bOpt, sizeof(bOpt));//选择自己填充ip头我这样填充 IPHDR myIPHead;
myIPHead.ip_totallength=htons(sizeof(IPHDR)+sizeof(ECHOREQUEST));
int ipsize=sizeof(IPHDR)/sizeof(unsigned long);
int iIPVersion=4;
myIPHead.ip_verlen=(iIPVersion<<4)|ipsize;
myIPHead.ip_tos=0;
myIPHead.ip_id=0;
myIPHead.ip_offset=0;
myIPHead.ip_ttl=128;
myIPHead.ip_protocol=IPPROTO_ICMP;
myIPHead.ip_checksum=0;
myIPHead.ip_srcaddr=inet_addr("127.0.0.1");//这里发现只有写自己的ip才行,不然sendto报错
myIPHead.ip_destaddr=inet_addr("211.65.86.255");
然后计算ip的校验和myIPHead.ip_checksum=in_cksum((u_short *)&myIPHead, sizeof(myIPHead));icmp部分是用了一个现成的,不会有问题的echoReq.icmpHdr.Type = ICMP_ECHOREQ;
echoReq.icmpHdr.Code = 0;
echoReq.icmpHdr.Checksum = 0;
echoReq.icmpHdr.ID = nId++;
echoReq.icmpHdr.Seq = nSeq++;
// Fill in some data to send
for (nRet = 0; nRet < REQ_DATASIZE; nRet++)
echoReq.cData[nRet] = ' '+nRet; // Save tick count when sent
echoReq.dwTime = GetTickCount();
// Put data in packet and compute checksum
echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq, sizeof(ECHOREQUEST));填充一个buffer,准备发送。
memcpy(szSendBuf,&myIPHead,sizeof(myIPHead));
memcpy(szSendBuf+sizeof(myIPHead),&echoReq,sizeof(ECHOREQUEST));
sendSize=sizeof(myIPHead)+sizeof(echoReq);nRet = sendto(s, /* socket */
(LPSTR)szSendBuf, /* buffer */
sendSize,
0, /* flags */
(LPSOCKADDR)lpstToAddr, /* destination */
sizeof(SOCKADDR_IN)); /* address length */现在可以发送icmp报文了,但是我发现我自己填充的ip头得原地址好像必须是我自己机器的地址,否则在发送的时候会报一个套接字的错,查看后是WSAEINTR 10004这个错误,如果用自己得ip填ip头,就不会有这个错误,到底还能不能实现用别的机子的ip填写ip数据报发送数据啊?
急等着用这个程序!不然老板要骂了!
{
unsigned char ip_verlen;
unsigned char ip_tos;
unsigned short ip_totallength;
unsigned short ip_id;
unsigned short ip_offset;
unsigned char ip_ttl;
unsigned char ip_protocol;
unsigned short ip_checksum;
unsigned int ip_srcaddr;
unsigned int ip_destaddr;
}IPHDR, *PIPHDR;icmp数据结构typedef struct tagICMPHDR
{
unsigned char Type; // Type
unsigned char Code; // Code
u_short Checksum; // Checksum
u_short ID; // Identification
u_short Seq; // Sequence
unsigned char Data; // Data
}ICMPHDR, *PICMPHDR;
#define REQ_DATASIZE 32 // Echo Request Data size// ICMP Echo Request
typedef struct tagECHOREQUEST
{
ICMPHDR icmpHdr;
DWORD dwTime;
unsigned char cData[REQ_DATASIZE];
}ECHOREQUEST, *PECHOREQUEST;
// ICMP Echo Reply
typedef struct tagECHOREPLY
{
IPHDR ipHdr;
ECHOREQUEST echoRequest;
unsigned char cFiller[256];
}ECHOREPLY, *PECHOREPLY;我就不全放上程序了,选重要的。bool bOpt=true;
setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL, (char*)bOpt, sizeof(bOpt));//选择自己填充ip头我这样填充 IPHDR myIPHead;
myIPHead.ip_totallength=htons(sizeof(IPHDR)+sizeof(ECHOREQUEST));
int ipsize=sizeof(IPHDR)/sizeof(unsigned long);
int iIPVersion=4;
myIPHead.ip_verlen=(iIPVersion<<4)|ipsize;
myIPHead.ip_tos=0;
myIPHead.ip_id=0;
myIPHead.ip_offset=0;
myIPHead.ip_ttl=128;
myIPHead.ip_protocol=IPPROTO_ICMP;
myIPHead.ip_checksum=0;
myIPHead.ip_srcaddr=inet_addr("127.0.0.1");//这里发现只有写自己的ip才行,不然sendto报错
myIPHead.ip_destaddr=inet_addr("211.65.86.255");
然后计算ip的校验和myIPHead.ip_checksum=in_cksum((u_short *)&myIPHead, sizeof(myIPHead));icmp部分是用了一个现成的,不会有问题的echoReq.icmpHdr.Type = ICMP_ECHOREQ;
echoReq.icmpHdr.Code = 0;
echoReq.icmpHdr.Checksum = 0;
echoReq.icmpHdr.ID = nId++;
echoReq.icmpHdr.Seq = nSeq++;
// Fill in some data to send
for (nRet = 0; nRet < REQ_DATASIZE; nRet++)
echoReq.cData[nRet] = ' '+nRet; // Save tick count when sent
echoReq.dwTime = GetTickCount();
// Put data in packet and compute checksum
echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq, sizeof(ECHOREQUEST));填充一个buffer,准备发送。
memcpy(szSendBuf,&myIPHead,sizeof(myIPHead));
memcpy(szSendBuf+sizeof(myIPHead),&echoReq,sizeof(ECHOREQUEST));
sendSize=sizeof(myIPHead)+sizeof(echoReq);nRet = sendto(s, /* socket */
(LPSTR)szSendBuf, /* buffer */
sendSize,
0, /* flags */
(LPSOCKADDR)lpstToAddr, /* destination */
sizeof(SOCKADDR_IN)); /* address length */现在可以发送icmp报文了,但是我发现我自己填充的ip头得原地址好像必须是我自己机器的地址,否则在发送的时候会报一个套接字的错,查看后是WSAEINTR 10004这个错误,如果用自己得ip填ip头,就不会有这个错误,到底还能不能实现用别的机子的ip填写ip数据报发送数据啊?
急等着用这个程序!不然老板要骂了!
急等着用这个程序!不然老板要骂了!
不过你是不是改了原地址,实现过ping?我现在不该原地址都正常了,但是改了就发不出去了,在sendto函数报错,查看后是WSAEINTR 10004这个错误。现在不是收不到对方回复,而是发送不成功!
路由器或者交换机实际上是根据mac地址进行通讯的,而数据包离开跨路由的话他的mac地址是改变的,
然后设置网卡成混杂模式,接受反馈回来的数据,因为数据不会发给你这个虚拟出来的地址的。
多谢指教,不胜感激!我未来两天不能上网,可能不能及时给反馈! :)
哎,我该看看我错在哪了,对了,怎么给你分?
不过我有基于winpcap实现ICMP发送的部分代码
你要是想要,可以给你
我也写过类似程序
我按照你的改了改,可以正常发送icmp报文了,但是对方机子没有响应,我说的响应的意思不一定非要我的程序能收到icmp响应报文,而是对方机子最起码在arp表里面要有我的或者是我ip和mac信息吧,可是现在没有,codekey,这是为什么啊?
其实我写这个程序的用意就是要在对方机子的arp表里面有我指定的机子的ip mac信息。
再次打扰真不好意思
我按照你的改了改,可以正常发送icmp报文了,但是对方机子没有响应,我说的响应的意思不一定非要我的程序能收到icmp响应报文,而是对方机子最起码在arp表里面要有我的或者是我伪造发送icmp的机器(真实存在的)ip和mac信息吧,可是现在没有,codekey,这是为什么啊?
其实我写这个程序的用意就是要在对方机子的arp表里面有我指定的机子的ip mac信息。
再次打扰真不好意思
他们还真实厉害!
[email protected]