recvfrom 10014:系统检测到在一个调用中尝试使用指针参数时的无效指针地址。
记Android 发送PDU相关问题

ICMP构建报文,实现Ping

ckfan posted @ 2012年11月05日 19:47 in 技术blog , 2015 阅读

 

首先要了解下ICMP,先前用IcmpSendEcho实现了Ping功能,见 http://ckfan.is-programmer.com/posts/36168.html

    ICMP:是Internet 控制信息协议(ICMP)是 IP 组的一个整合部分,通过 IP 包传送的 ICMP 信息主要用于涉及网络
操作或错误操作的不可达信息。
    ICMP 的报文类型:

    这里再说说下,我原先一些误区: 1.ICMP没有端口,它并不像TCP/UDP那样有发到特定的接收端口,它是控制协议,服务于IP层。当某个网关发现传输错误时,立即向信源主机发 送 ICMP报文,报告出错信息,让信源主机采取相应处理措施,它是一种差错和控制报文协议,不仅用于传输差错报文,还传输控制报文。 2.ICMP 包发送是不可靠的。

 

code:

.h

#pragma once
#include <winsock2.h> 
#include <ws2tcpip.h> 
#pragma comment(lib, "ws2_32.lib")

#pragma pack(1)
// ICMP 头部
typedef struct _ihdr
{
	BYTE i_type;		// 8位类型
	BYTE i_code;		// 8位代码
	USHORT i_cksum;		// 16位校验和
	USHORT i_id;		// 识别号
	USHORT i_seq;		// 报文序列号
	ULONG timestamp;	// 时间戳
}ICMP_HEADER;

typedef struct _iphdr{
	unsigned char  h_lenver;		// 4 位IP版本号+4位首部长度
	unsigned char  tos;			// 8位服务类型TOS
	unsigned short total_len;		// 16位IP包总长度(字节)
	unsigned short ident;			// 16位标识, 用于辅助IP包的拆装,本实验不用,置零
	unsigned short frag_and_flags;	// 3位标志位+13位偏移位, 也是用于IP包的拆装,本实验不用,置零
	unsigned char  ttl;			// 8位IP包生存时间 TTL
	unsigned char  proto;			// 8位协议 (TCP, UDP 或其他), 本实验置ICMP,置为1
	unsigned short checksum;		// 16位IP首部校验和,最初置零,等
							// 所有包头都填写正确后,计算并替换.
	unsigned int   sourceIP;		// 32位源IP地址
	unsigned int   destIP;			// 32位目的IP地址
}IP_HEADER;
#pragma pack()

class CIPing
{
public:
	CIPing();
	~CIPing();
	// PING X.X.X.X
	BOOL Ping(LPCTSTR ip, int timeout);
private:
	SOCKET s;
};

.cpp
#include "stdafx.h"
#include "IPing.h"

// 校验和
unsigned short CheckSum(unsigned short *addr, int count)
{
       /* Compute Internet Checksum for "count" bytes
        * beginning at location "addr".
       */
       register long sum = 0;

       while( count > 1 )
       {
           /* This is the inner loop */
           sum += *addr++;
           count -= sizeof(USHORT);
        }

       /* Add left-over byte, if any */
       if( count > 0 )
           sum += * (unsigned char *) addr;

       /* Fold 32-bit sum to 16 bits */
       while (sum>>16)
           sum = (sum & 0xffff) + (sum >> 16);

       return (USHORT)~sum;
}
CIPing::CIPing()
{

}

CIPing::~CIPing()
{

}

// PING X.X.X.X
BOOL CIPing::Ping(LPCTSTR ip, int timeout)
{
	struct sockaddr_in addrSrc;
	struct sockaddr_in addrDest;
	ICMP_HEADER head;
	UCHAR ucSendBuf[1024];
	UCHAR ucRecBuf[1024];
	int recFromLen;
	IP_HEADER   *pIpHdr = NULL;
	unsigned short len;

	// create
	if((s = WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET)
	{
		return FALSE;
	}

	// 发送时限
	setsockopt( s, SOL_SOCKET, SO_SNDTIMEO, ( char * )&timeout, sizeof( int ) );
	
	// 接收时限
	setsockopt( s, SOL_SOCKET, SO_RCVTIMEO, ( char * )&timeout, sizeof( int ) );

	memset(&addrSrc, 0, sizeof(sockaddr_in));

	// addr
	addrSrc.sin_family = AF_INET;
	addrSrc.sin_addr.s_addr = inet_addr(ip);

	// 填充ICMP首部
	memset(&head, 0, sizeof(ICMP_HEADER));
	// 回显应答
	head.i_type = 0;
	head.i_code = 0;	
	// 校验和置0
	head.i_cksum = 0; 
	head.i_id = 2;
	// 时间戳
	head.timestamp = GetTickCount(); 
	head.i_seq = 999;

	memset(ucSendBuf, 0, 1024);
	memcpy(ucSendBuf, &head, sizeof(ICMP_HEADER));
	memset(ucSendBuf + sizeof(ICMP_HEADER), '1', 32);
	head.i_cksum = CheckSum((USHORT*)ucSendBuf, sizeof(ICMP_HEADER) + 32);
	memcpy(ucSendBuf, &head, sizeof(ICMP_HEADER));

	// 发送
	if(sendto(s, (char*)ucSendBuf, sizeof(ICMP_HEADER) + 32, 0, (struct sockaddr*)&addrSrc,sizeof(addrSrc)) ==	SOCKET_ERROR)
	{
		closesocket(s);
		s = NULL;
		return FALSE;
	}

	memset(ucRecBuf, 0, 1024);
	memset(&addrDest, 0, sizeof(struct sockaddr));
	recFromLen = sizeof(sockaddr);
	addrDest.sin_family = AF_INET;
	if (recvfrom(s, (char*)ucRecBuf, 1023, 0, (struct sockaddr*)&addrDest, &recFromLen) == SOCKET_ERROR)
	{
		if(WSAGetLastError() == WSAETIMEDOUT)
		{
			OutputDebugString("Time out...\n");
		}
		closesocket(s);
		s = NULL;
		return FALSE;
	}
	closesocket(s);
	s = NULL;
	
	// 判断包的正确性
	pIpHdr = (IP_HEADER *)ucRecBuf;
	// Number of 32-bit words * 4 = bytes
	// 计算ip包头长度
	len = sizeof(unsigned long) * (pIpHdr->h_lenver & 0xf);  
	memcpy(&head,& ucRecBuf[len], sizeof(ICMP_HEADER));
	// 标识
	if (head.i_id != 2)
	{
		return FALSE;
	}
	return TRUE;
}
seo service UK 说:
2024年1月16日 15:22

The the next occasion I read a blog, Hopefully it doesnt disappoint me around this blog. What i’m saying is, I know it was my substitute for read, but I really thought youd have something interesting to express. All I hear is often a number of whining about something you could fix in the event you werent too busy in search of attention


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter