利用TTL值探测远程主机操作系统类型

来源:互联网 发布:淘宝是cs还是bs 编辑:程序博客网 时间:2024/05/29 04:17

帮别人做的毕业设计。也不复杂,但是确实实现了如题的功能。

代码:

#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>

#pragma pack(1)

#define ICMP_ECHOREPLY 0
#define ICMP_ECHOREQ   8

//IP Header--RFC 791
typedef struct tagIPHDR
{
 u_char  VHDL;        //Version and IHL
 u_char  TOS ;        //Type of server
 short  TotLen;       //Total length
 short   ID;          //Identification
 short   FlagOff;       //Flags  and Fragment Offset
 u_char TTL;           //Time To Live
 u_char Protocol;      //protocol
 u_short checksum;    //Checksum
 struct in_addr iaSrc;      //Internet Address-Source
 struct in_addr iaDst;      //internet address-destination
}IPHDR, *PIPHDR;

//ICMP Header -RFC 792
typedef struct tagICMPHDR
{
 u_char Type;     //type
 u_char Code;     //Code
 u_short Checksum;   //checksum
 u_short ID;    //identification
 u_short Seq;    //sequence
 char Data;   //data
}ICMPHDR,*PICMPHDR;

#define REQ_DATASIZE 32    //Echo request data size
//ICMP eCHO Request
typedef struct tagECHOREQUEST
{
 ICMPHDR icmpHdr;
 DWORD  dwTime;
 CHAR cData[REQ_DATASIZE];
}ECHOREQUEST,*PECHOREQUEST;

//ICMP Echo Reply
typedef struct tagECHOREPLY
{
 IPHDR ipHdr;
 ECHOREQUEST  echoRequest;
 char cFiller[256];
}ECHOREPLY,*PCHOREPLY;

#pragma pack()
//internal functions
void  Ping(LPCSTR pstrHost);
void ReportError(LPCSTR  pstrForm);
int WaitForEchoReply(SOCKET s);
u_short in_cksum(u_short *addr,int len);

//ICMP Echo Request/Reply functions
int   SendEchoRequest(SOCKET,LPSOCKADDR_IN);
DWORD   RecvEchoReply(SOCKET,LPSOCKADDR_IN,u_char*);

//main()
void main(int argc,char **argv)
{
 WSADATA wsaData;
 WORD wVersionRequested=MAKEWORD(1,1);
 int nRet;

 //Checksum arguments
 if(argc!=2)
 {
  fprintf(stderr,"/nUsage:ping hostname/n");
  return;
 }


 //init WinSock
 nRet=WSAStartup(wVersionRequested,&wsaData);
 if(nRet)
 {
  fprintf(stderr,"/nError initializing WinSock/n");
  return;
 }


 //checksum version
 if (wsaData.wVersion!=wVersionRequested)
 {
  fprintf(stderr,"/nWinSock version not supported/n");
  return;
 }


 //go do the ping
 Ping(argv[1]);
 //Free Winsock
 WSACleanup();
}
//Ping()
//calls sendechorequest() and
//recvechoreply() and prints results
void Ping(LPCSTR pstrHost)
{
 SOCKET rawSocket;
 LPHOSTENT lpHost;
 struct sockaddr_in saDest;
 struct sockaddr_in saSrc;
 DWORD dwTimeSent;
    DWORD dwElapsed;
 u_char cTTL;
 int nLoop;
 int nRet;
 //create a Raw socket
 rawSocket=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
 if(rawSocket==SOCKET_ERROR)
 {
  ReportError("socket()");
  return;
 }
//Lookback host
    lpHost = gethostbyname(pstrHost);
 if (lpHost == NULL)
 {
  fprintf(stderr,"/nHost not found: %/n,pstrHost");
     return;
 }
 //Stetup destination socket address
 saDest.sin_addr.s_addr=*((u_long FAR *) (lpHost->h_addr));
 saDest.sin_family = AF_INET;
 saDest.sin_port =0;

 //Tell the user what we're doing
 printf("/nping %s [%s] with %d bytes of data/n",
           pstrHost,
     inet_ntoa(saDest.sin_addr),
     REQ_DATASIZE);

 //Ping multiple times
 for (nLoop =0; nLoop<4; nLoop++)
 {
  //Send ICMP echo request
  SendEchoRequest(rawSocket, &saDest);

  //Use select() to wait for data to be received
  nRet =WaitForEchoReply(rawSocket);
  if (nRet == SOCKET_ERROR)
  {
   ReportError("select()");
            break;
  }
  if (!nRet)
  {
   printf("/nTimeout");
   break;
  }

  //Receive reply
  dwTimeSent = RecvEchoReply(rawSocket,&saSrc,&cTTL);

  //Calculate elapsed time
  dwElapsed = GetTickCount() - dwTimeSent;
 }
 printf("/n");
 int iTTL=(int)cTTL;

    printf("所探测操作系统类别:");
 switch(iTTL){
 case 64:
  printf("LINUX/n");
  break;
 case 128:
  printf("WIN2K/NT/XP/n");
  break;
 case 32:
  printf("WINDOWS 早期系列:Windows 95/98/98SE Windows ME /n");
  break;
 case 255:
  printf("UNIX 系列/n");
  break;
 default:
  printf("未知!无法监测!/n");
 }

 nRet =closesocket(rawSocket);
 if (nRet == SOCKET_ERROR)
  ReportError("closesocket()");
 }

 //SendEchoRequest()
 //Fill in echo request header
 //and send to destination
 int SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr)
 {
  static ECHOREQUEST echoReq;
  static nId = 1;
  static nSeq = 1;
  int nRet;

  //Fill in echo request
  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));

  //Send the echo request
  nRet = sendto(s,             /*socket*/
             (LPSTR)&echoReq,       /*buffer*/
             sizeof(ECHOREQUEST),
       0,                         /*flags*/
       (LPSOCKADDR)lpstToAddr,   /*destination*/
       sizeof(SOCKADDR_IN));       /*address length*/
  if (nRet == SOCKET_ERROR)
   ReportError("sendto()");
  return (nRet);
 }

 //RecvEchoReply()
 //Receive incoming data
 //and parse out fields
 DWORD RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom,u_char *pTTL)
 {
  ECHOREPLY echoReply;
  int nRet;
  int nAddrLen = sizeof(struct sockaddr_in);

  //Receive the echo reply
  nRet = recvfrom(s,              //socket
                 (LPSTR)&echoReply,      //buffer
        sizeof(ECHOREPLY),      //size of buffer
        0,                      //flges
        (LPSOCKADDR)lpsaFrom,    //From  address
        &nAddrLen);              //pointer to address len

  //Check return value
  if(nRet == SOCKET_ERROR)
   ReportError("recvfrom()");

  //return time sent and IP TTL
  *pTTL = echoReply.ipHdr.TTL;
  return(echoReply.echoRequest.dwTime);
 }

 //What happend?
 void ReportError(LPCSTR pWhere)
 {
  fprintf(stderr,"/n%s error: %d/n",
   WSAGetLastError());
 }

 //WaitForEchoReply()
 //Use select() to determine when
 //data is waiting to be read
 int WaitForEchoReply(SOCKET s)
 {
  struct timeval Timeout;
  fd_set readfds;

  readfds.fd_count = 1;
  readfds.fd_array[0] =s;
  Timeout.tv_sec =5;
  Timeout.tv_usec =0;

  return(select(1,&readfds,NULL,NULL,&Timeout));
 }

 //
 //Mike Muuss' in_cksum(0 function
 //and his comments from the original
 //ping program
 /*
  *              IN_CKSUM
  *
  *CheckSum routine for Internet Protocol family headers (C Version)
  */
u_short in_cksum(u_short *addr,int len)
{
 register int nleft=len;
 register u_short *w=addr;
 register u_short answer;
 register int sum=0;
 /*
  *The algorithm is simple,using a 32 bit accumulator (sum),
  *we add sequential 16bit words to it,and at the end,fold
  *back all the carry bits from the top 16 bits into the lower
  *16 bits.
  *
  */
 while(nleft>1){
  sum+=*w++;
  nleft-=2;
 }
 /*mop up an odd byte,if necessary */
 if(nleft==1){
  u_short u=0;
  *(u_char *)(&u)=*(u_char*)w;
  sum+=u;
 }
 /*
  *add back carry outs from toop0 16bits to low 16 bits
  */
 sum=(sum>>16)+(sum&0xffff);/*add hi 16 to low 16 */
 sum+=(sum>>16);            /*add carry */
 answer=~sum;               /*trumcate to 16 bits */
 return (answer);
}