ICMP 검사

6969 단어 scan
icmp(Internet control message protocol)는 네트워크에서 오류 메시지를 전달하는 프로토콜로 유형과 코드에 따라 여러 종류로 나눌 수 있습니다. icmp 스캔을 실현하기 위해 저희는 요청 리셋(type=8,code=0)과 리셋 응답(type=0,code=0)만 사용할 수 있습니다. 구체적인 상황은 icmp, 메시지 형식을 보십시오.
원리는 스캔이 필요한 ip처럼 icmp로 리셋을 요청하고 icmp 리셋 응답을 받으면 이 ip는 활동 상태에 있다. 그렇지 않으면 아니다. 여기서 내가 개발한 환경은 win7+vs2013이다. 구축된 일반 컨트롤 게이지 프로그램은 socket을 사용하면 된다.
1. 헤드를 정의합니다.h 헤더 파일, 필요한 헤더 정의에 사용
#include"winsock2.h"
#pragma comment(lib,"ws2_32")
#include"WS2TCPIP.H"
#include "mstcpip.h"
//ip  ,         ip    ,              ,    ,  http://blog.csdn.net/u012198947/article/details/51078214     
typedef struct _iphdr
{
	unsigned char h_lenver;
	unsigned char tos;
	unsigned short total_len;
	unsigned short ident;
	unsigned short frag_and_flags;
	unsigned char ttl;
	unsigned char proto;
	unsigned short checksum;
	unsigned int sourceIP;
	unsigned int destIP;
}IPHEADER;
//icmp  
typedef struct _icmphdr
{
	BYTE i_type;
	BYTE i_code;
	USHORT i_cksum;
	USHORT i_id;
	USHORT i_seq;
	ULONG timestamp;
}ICMPHEADER;

//    
typedef struct
{
	USHORT usSeqNo;		  //    
	DWORD dwRoundTripTime; //    
	in_addr dwIPaddr;	  //  IP  
} DECODE_RESULT;//ip    ,    ,  ip    

2. 패킷을 보내는 함수
//       ,    icmp   
//        ,  0,  -1
//             ,          
int SendEchoRequest(SOCKET s, LPSOCKADDR_IN lpstToAddr)
{
	int nRet; //
	char IcmpSendBuf[sizeof(ICMPHEADER)];//       

	//     
	memset(IcmpSendBuf, 0, sizeof(IcmpSendBuf));
	ICMPHEADER *pIcmpHeader = (ICMPHEADER*)IcmpSendBuf;
	pIcmpHeader->i_type = 8; //      
	pIcmpHeader->i_code = 0;
	pIcmpHeader->i_id = (USHORT)GetCurrentProcessId();//     ,             
	pIcmpHeader->i_seq = 0x0;//
	pIcmpHeader->i_cksum = 0;
	pIcmpHeader->timestamp = 0x01020304;//  ,  ,      ,      4B
	pIcmpHeader->i_cksum = CheckSum((USHORT*)pIcmpHeader, sizeof(ICMPHEADER));//     ,    :

	nRet = sendto(s, IcmpSendBuf, sizeof(IcmpSendBuf),0, (LPSOCKADDR)lpstToAddr, sizeof(SOCKADDR_IN));//  

	if (nRet == SOCKET_ERROR)
	{
		cout << "sento Error" << endl;
		return -1;
	}
	return 0;
}
//       
USHORT CheckSum(USHORT *buffer, int size)
{
	unsigned long cksum = 0;
	while (size > 1)
	{
		cksum += *buffer++;
		size -= sizeof(USHORT);
	}
	if (size)
	{
		cksum += *(UCHAR*)buffer;
	}
	while (cksum >> 16)
		cksum = (cksum >> 16) + (cksum & 0xffff);
	return (USHORT)(~cksum);
}

3. 수신된 패키지를 분석하는 함수
/********************************************************
   :DecodeIcmpResponse
    :char* pBuf:         (  IP  )
int iPacketSize:       
DECODE_RESULT *stDecodeResult:      
    :       ,true:  ,false:  
  :          ,    ICMP             
*********************************************************/
BOOL DecodeIcmpResponse(char* pBuf, int iPacketSize, DECODE_RESULT& stDecodeResult)
{
	IPHEADER* pIpHdr = (IPHEADER*)pBuf;
	int iIpHdrLen = 20;//ip  ,  20  
	
	//ip    20  ,   icmp  
	ICMPHEADER* pIcmpHdr = (ICMPHEADER*)(pBuf + iIpHdrLen);
	USHORT usID, usSquNo;
	if (pIcmpHdr->i_type == 0)//    
	{
		usID = pIcmpHdr->i_id;
		usSquNo = pIcmpHdr->i_seq;
	}
	else
		return FALSE;
	//       ICMP   ,  type=0 icmp      ,      code
	if (pIcmpHdr->i_type == 0 )
	{
		//      
		stDecodeResult.dwIPaddr.s_addr = pIpHdr->sourceIP;
		stDecodeResult.dwRoundTripTime = GetTickCount() - stDecodeResult.dwRoundTripTime;
		return TRUE;
	}
	return FALSE;
}

4. 수신 패킷 함수
/********************************************************
   :RecvEchoReply
    :SOCKET s:     
SOCKADDR_IN *saFrom:        
SOCKADDR_IN *saDest:        
DECODE_RESULT *stDecodeResult:      
    :       ,true:  ,false:  
  :    ,   DecodeIcmpResponse     ICMP      
*********************************************************/
DWORD RecvEchoReply(SOCKET s, SOCKADDR_IN *saFrom, SOCKADDR_IN *saDest, DECODE_RESULT *stDecodeResult)
{
	int nRet;
	int nAddrLen = sizeof(struct sockaddr_in);

	//  ICMP      
	char IcmpRecvBuf[1024];
	memset(IcmpRecvBuf, 0, sizeof(IcmpRecvBuf));

	//   	
	nRet = recvfrom(s,					// socket
		(LPSTR)&IcmpRecvBuf,	// buffer
		1024,	// size of buffer
		0,					// flags
		(LPSOCKADDR)saFrom,	// From address
		&nAddrLen);			// pointer to address len


	//    
	if (nRet != SOCKET_ERROR) //      
	{
		//        ,                  EchoRequest 
		if (DecodeIcmpResponse(IcmpRecvBuf, nRet, *stDecodeResult))
		{
			if (stDecodeResult->dwIPaddr.s_addr == saDest->sin_addr.s_addr)
			{
				printf("         
"); return 1; } } else return -1; } else if (WSAGetLastError() == WSAETIMEDOUT) // , , icmp , ip , // icmp , arp ip , ip , icmp , , , { printf("
"); } else { printf("recvfrom , : %d
", WSAGetLastError()); return -1; } return 0; }

5. 다음은 주 함수
int main()
{
int iResult;
SOCKET sockRaw;
sockaddr_in addrDest, addrSrc;
DECODE_RESULT stDecodeResult;
USHORT usSeqNo = 0;
WSADATA wsaData;
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) 
{
//사용 가능한 Winsock DLL을 찾을 수 없음 알림
printf("WSAstartup 함수 호출 오류, 오류 번호:%d", WSAGetLastError();
return -1;
}
//원래 소켓 작성
sockRaw= socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
//수신 제한 시간 설정
int iTimeout = 1000;
iResult = setsockopt(sockRaw, SOL_SOCKET, SO_RCVTIMEO, (char*)&iTimeout, sizeof(iTimeout));
memset(&stDecodeResult, 0, sizeof(DECODE_RESULT));
//스캔이 필요한 IP는 필요에 따라 값을 매겨라
addrDest.sin_addr.S_un.S_addr = inet_addr("192.168.218.18");
addrDest.sin_family = AF_INET;
//ICMP Echo 요청 보내기
iResult = SendEchoRequest(sockRaw, &addrDest);
if (iResult == SOCKET_ERROR)
{
if (WSAGetLastError() == WSAEHOSTUNREACH){
printf ("목적 호스트가 도달할 수 없음,traceroute 탐지 종료!");
return -1;
}
}
//ICMP의 EchoReply 데이터 보고서 수신
iResult = RecvEchoReply(sockRaw, &addrSrc, &addrDest, &stDecodeResult);
return 0;
}
자, 이렇게 하면 ok 이다

좋은 웹페이지 즐겨찾기