⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 icmpping.c

📁 Allows sending and receiving of multicast datagrams and experimentation with the multicast APIs
💻 C
字号:
/*---------------------------------------------------------------------
 *
 * Program: MULTITST.EXE  Optional WinSock features test program
 *
 * filename: icmpping.c
 *
 * copyright by Bob Quinn, 1995
 *
 * Description: This module does ICMP ping on WinSock implementations
 *  that support the *optional* IPPROTO_ICMP SOCK_RAW socket type.
 *  It also has the potential for traceroute capability over (much
 *  less common) setsockopt() IP_TTL capable WinSock implementations.
 * .
 *  This software is not subject to any  export  provision  of
 *  the  United  States  Department  of  Commerce,  and may be
 *  exported to any country or planet.
 *
 *  Permission is granted to anyone to use this  software  for any  
 *  purpose  on  any computer system, and to alter it and redistribute 
 *  it freely, subject to the following  restrictions:
 *
 *  1. The author is not responsible for the consequences of
 *     use of this software, no matter how awful, even if they
 *     arise from flaws in it.
 *
 *  2. The origin of this software must not be misrepresented,
 *     either by explicit claim or by omission.  Since few users
 *     ever read sources, credits must appear in the documentation.
 *
 *  3. Altered versions must be plainly marked as such, and
 *     must not be misrepresented as being the original software.
 *     Since few users ever read sources, credits must appear in
 *     the documentation.
 *
 *  4. This notice may not be removed or altered.
 *	 
 ---------------------------------------------------------------------*/
#include <windows.h>
#include <windowsx.h>
#include <winsock.h>
#include <stdlib.h>
#include <memory.h>

#include "..\wsa_xtra.h"

#define PNGBUFSIZE 8192+ICMP_HDR_LEN+IP_HDR_LEN

/* external functions */
extern void  WSAErrMsg(LPSTR);

/* internal public functions */
SOCKET icmp_open(void);
u_short cksum (u_short FAR*, int);
int icmp_close(SOCKET);
int set_ttl (SOCKET, int);
int icmp_sendto (SOCKET, HWND, LPSOCKADDR_IN, int, int, int);
u_long icmp_recvfrom(SOCKET,LPINT,LPINT,LPSOCKADDR_IN);

/* private data */
static ICMP_HDR FAR *lpIcmpHdr;	/* pointers into our I/O buffer */
static IP_HDR 	FAR *lpIpHdr;
static char achIOBuf[PNGBUFSIZE];
static SOCKADDR_IN stFromAddr;
static DWORD lCurrentTime, lRoundTripTime;

/*-----------------------------------------------------------
 * Function icmp_open()
 *
 * Description: opens an ICMP "raw" socket,
 *  - does error check
 *  - displays error message if failed,
 *  - else returns socket handle
 */
SOCKET icmp_open(void) {
  SOCKET s;
  s = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
  if (s == SOCKET_ERROR) {
    WSAErrMsg("socket(type=SOCK_RAW, protocol=IPROTO_ICMP)");		
    return (INVALID_SOCKET);
  }
  return (s);
} /* end icmp_open() */

/*-----------------------------------------------------------
 * Function icmp_close()
 *
 * Description: closes a socket (generic for any socket, though
 *  we happen to use it for ICMP "raw" sockets here.
 *  - does error check
 *  - displays error message if failed (which is very unlikely)
 */
int icmp_close(SOCKET s) { 
  int nRet; 
  nRet = closesocket (s);
  if (nRet == SOCKET_ERROR)	/* very unlikely */
    WSAErrMsg("closesocket()");
  return (nRet);
} /* end icmp_close() */

/*-----------------------------------------------------------
 * Function set_IP_TTL()
 *
 * Description: Attempts to set the IP Time to live value using the
 *  IP_TTL socket option (which is rarely supported).  This is necessary
 *  to implement a traceroute application/
 */
int set_ttl (SOCKET s, int nTimeToLive) {
  int nRet;
  nRet = setsockopt (s, IPPROTO_IP, IP_TTL,(LPSTR)&nTimeToLive, sizeof(int));
  if (nRet==SOCKET_ERROR) {
    WSAErrMsg("setsockopt(lewel=IPPROTO_IP, option=IP_TTL)");
  }
  return (nRet);
} /* end set_IP_TTL() */

/*-----------------------------------------------------------
 * Function: icmp_ping()
 *
 * Description: sends an ICMP Echo Request to destination address
 *  provided, then reads the ICMP Echo Reply back.  It records the
 *  round trip time.  This requires a WinSock that can provide a
 *  socket of type=SOCK_RAW and protocol=IPPROTO_ICMP.  Since "raw
 *  socket" support is optional in WinSock version 1.1, this will
 *  not work over all WinSock implementations.
 *
 */
int icmp_sendto (SOCKET s,
    HWND hwnd,
    LPSOCKADDR_IN lpstToAddr,
    int nIcmpId,
    int nIcmpSeq,
    int nEchoDataLen) {
  int nAddrLen = sizeof(SOCKADDR_IN);
  int nRet;
  u_short i;
  char c;
 
  /*--------------------- init ICMP header -----------------------*/
  lpIcmpHdr = (ICMP_HDR FAR *)achIOBuf;
  lpIcmpHdr->icmp_type  = ICMP_ECHOREQ;
  lpIcmpHdr->icmp_code  = 0;
  lpIcmpHdr->icmp_cksum = 0;
  lpIcmpHdr->icmp_id	  = nIcmpId++;
  lpIcmpHdr->icmp_seq   = nIcmpSeq++;
  /*--------------------put data into packet------------------------
   * insert the current time, so we can calculate round-trip time
   *  upon receipt of echo reply (which will echo data we sent) */
  lCurrentTime = GetCurrentTime();			
  _fmemcpy (&(achIOBuf[ICMP_HDR_LEN]),&lCurrentTime,sizeof(long));
	 		  
  /* data length includes the time (but not icmp header) */
  c=' ';   /* first char: space, right after the time */
  for (i=ICMP_HDR_LEN+sizeof(long);
       ((i < (nEchoDataLen+ICMP_HDR_LEN)) && (i < PNGBUFSIZE)); 
       i++) {
    achIOBuf[i] = c;
    c++;
    if (c > '~')	/* go up to ASCII 126, then back to 32 */
      c= ' ';
  }
  /*----------------------assign ICMP checksum ----------------------
   * ICMP checksum includes ICMP header and data, and assumes current
   *  checksum value of zero in header */
  lpIcmpHdr->icmp_cksum = cksum((u_short FAR *)lpIcmpHdr, 
	  nEchoDataLen+ICMP_HDR_LEN);
  								  
  /*--------------------- send ICMP echo request -------------------*/
  nRet = sendto (s,         /* socket */
    (LPSTR)lpIcmpHdr,       /* buffer */
    nEchoDataLen+ICMP_HDR_LEN+sizeof(long),	/* length */
    0,                      /* flags */
    (LPSOCKADDR)lpstToAddr, /* destination */
    sizeof(SOCKADDR_IN));   /* address length */

  if (nRet == SOCKET_ERROR) {
    WSAErrMsg("sendto()");
  }
	
  return (nRet);
} /* end icmp_sendto() */

/*-----------------------------------------------------------
 * Function: icmp_recvfrom()
 *
 * Description:
 *   receive icmp echo reply, parse the reply packet to get round trip
 *   time, and calculate it.
 */
u_long icmp_recvfrom(SOCKET s,
    LPINT lpnIcmpId,
    LPINT lpnIcmpSeq, 
    LPSOCKADDR_IN lpstFromAddr) {
  u_long lSendTime;	
  int nAddrLen = sizeof(struct sockaddr_in);
  int nRet, i;
		
  /*-------------------- receive ICMP echo reply ------------------*/
  stFromAddr.sin_family = AF_INET;
  stFromAddr.sin_addr.s_addr = INADDR_ANY;  /* not used on input anyway */
  stFromAddr.sin_port = 0;   /* port not used in ICMP */
  nRet = recvfrom (s,             /* socket */
      (LPSTR)achIOBuf,            /* buffer */
      PNGBUFSIZE+ICMP_HDR_LEN+sizeof(long)+IP_HDR_LEN,  /* length */
      0,                          /* flags */
      (LPSOCKADDR)lpstFromAddr,   /* source */
      &nAddrLen);                 /* addrlen*/

  if (nRet == SOCKET_ERROR) {
    WSAErrMsg("recvfrom()");
  }
  /*------------------------- parse data ---------------------------
   * remove the time from data and display with current time.
   *  NOTE: the data received and sent are asymmetric: we receive 
   *  the IP header, although we didn抰 send it. This subtlety is
   *  often missed by WinSocks so we do a quick check of the data
   *  received to see if it includes the IP header (we look for 0x45
   *  value in first byte of buffer to check if IP header present).
   */
  /* figure out the offset to data */
  if (achIOBuf[0] == 0x45) {  /* IP header present? */
    i = IP_HDR_LEN + ICMP_HDR_LEN;
    lpIcmpHdr = (LPICMPHDR) &(achIOBuf[IP_HDR_LEN]);
  } else {
    i = ICMP_HDR_LEN;	
    lpIcmpHdr = (LPICMPHDR) achIOBuf;
  }
  
  /* pull out the ICMP ID and Sequence numbers */
  *lpnIcmpId  = lpIcmpHdr->icmp_id;
  *lpnIcmpSeq = lpIcmpHdr->icmp_seq;
   		
  /* remove the send time from the ICMP data */
  _fmemcpy (&lSendTime, (&achIOBuf[i]), sizeof(u_long));
   		
  return (lSendTime);
} /* end icmp_recvfrom() */

/*-----------------------------------------------------------
 * Function: cksum()
 *
 * Description:
 *  Calculate Internet checksum for data buffer and length (one抯 
 *  complement sum of 16-bit words).  Used in IP, ICMP, UDP, IGMP.
 */
u_short cksum (u_short FAR*lpBuf, int nLen) {	
  register long lSum = 0L;	/* work variables */
		
  /* note: to handle odd number of bytes, last (even) byte in 
   *  buffer have a value of 0 (we assume that it does) */
  while (nLen > 0) {
    lSum += *(lpBuf++);	/* add word value to sum */
    nLen -= 2;          /* decrement byte count by 2 */
  }
  /* put 32-bit sum into 16-bits */
  lSum = (lSum & 0xffff) + (lSum>>16);
  lSum += (lSum >> 16);

  /* return Internet checksum.  Note:integral type
   * conversion warning is expected here. It's ok. */
  return (~lSum); 
}  /* end cksum() */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -