Linux下使用原始套接字实现ping 功能

    技术2026-01-06  7

    //获得某个网卡的IP地址

    char*   GetIpAddress(const char* interfaceName)

    {

      register int fd, intrface;   struct ifreq buf[MAXINTERFACES];   //#define MAXINTERFACES    12   struct ifconf ifc;   if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) >= 0)   {     ifc.ifc_len = sizeof buf;     ifc.ifc_buf = (caddr_t) buf;     if (!ioctl (fd, SIOCGIFCONF, (char *) &ifc))     {       intrface = ifc.ifc_len / sizeof (struct ifreq);       while (intrface-- > 0)       {         if (0 != strcmp(buf[intrface].ifr_name, interfaceName))           continue;            //get the ip address of this net device         if (!(ioctl (fd, SIOCGIFADDR, (char *) &buf[intrface])))         {           ::close(fd);           return (inet_ntoa(((struct sockaddr_in*)(&buf[intrface].ifr_addr))->sin_addr));         }         else         {           char str[256];           sprintf (str, "cpm: ioctl device %s", buf[intrface].ifr_name);           perror (str);         }       }     }     ::close(fd);   } return "";

    }

     

    bool   IsValidIpAddress(const char* ipAddress)

    {

       struct sockaddr_in sin;   sin.sin_family = AF_INET;   memset(&sin, 0, sizeof(sin));   if (inet_pton(AF_INET, ipAddress, &sin.sin_addr) <= 0)   {     return false;   }   else   {     char strConvertedIP[MAX_IP_LENGTH];    //#define MAX_IP_LENGTH     30     if (NULL != inet_ntop(AF_INET, &sin.sin_addr, strConvertedIP, MAX_IP_LENGTH) )     {              if(0 != strcmp(strConvertedIP, "0.0.0.0"))       {         return true;       }     }     return false;   }

    }

     bool    send_echo_req(int sock_fd,struct sockaddr_in *dstaddr)

    {

       char buf[100];   size_t len = sizeof(struct icmp);   struct icmp *icmp;   socklen_t dstlen = sizeof(struct sockaddr_in);   bzero(buf, sizeof(buf));   icmp = (struct icmp *)buf;   icmp->icmp_type = ICMP_ECHO;   icmp->icmp_code = 0;   icmp->icmp_id = getpid();   icmp->icmp_seq = 1;   icmp->icmp_cksum = in_cksum((uint16_t *) icmp, sizeof(struct icmp));   if (sendto(sockfd, buf, len, 0, (struct sockaddr*)dstaddr, dstlen) == -1)   {     err_sys("sendto");     return false;   }   return true; }

    bool     recv_echo_reply(int sock_fd)

    {

       char buf[100];   ssize_t n;   struct ip *ip;   struct icmp *icmp;     fd_set rfds;   struct timeval tv;   int retval;   FD_ZERO(&rfds);   FD_SET(sockfd, &rfds);   tv.tv_sec = 5;   tv.tv_usec = 0;   retval = select(sockfd+1, &rfds, NULL, NULL, &tv);   if (retval == -1)   {     perror("select()");     return false;   }   else if (retval)   {     /* FD_ISSET(0, &rfds) will be true. */     if ((n = read(sockfd, buf, sizeof(buf))) == -1)     {       err_sys("read");       return false;     }     ip = (struct ip *)buf;     if (ip->ip_p != IPPROTO_ICMP) {       fprintf(stderr, "protocol error./r/n");       return false;     }     icmp = (struct icmp *)(buf + sizeof(struct ip));     if (icmp->icmp_type == ICMP_ECHOREPLY) {       if (icmp->icmp_id != getpid()) {         fprintf(stderr, "not this process./r/n");         return false;       } else {         //printf("destination host is alive./r/n");         return true;       }     }   }   //printf("ping timeout./n");   return false;

    }

    uint16_t   in_cksum(uint16_t*  addr, int len)

    {

       int nleft = len;   uint32_t sum = 0;   uint16_t *w = addr;   uint16_t answer = 0;   while (nleft > 1) {     sum += *w++;     nleft -= 2;   }   if (nleft == 1) {     *(unsigned char *)(&answer) = *(unsigned char *)w ;     sum += answer;   }   sum = (sum >> 16) + (sum & 0xffff);   sum += (sum >> 16);   answer = ~sum;   return(answer);

    }

    bool    Ping (char* dest)

    {

       int sockfd;   struct sockaddr_in dstaddr;   bool ret;     char*  ipAddr;   ipAddr = GetIPAddress(m_wirelessNetworkDevice);   if(!IsValidIPAddress(ipAddr.toUtf8().constData()))     return false;   if ((sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)   //ICMP协议,原始套接字类型   {     err_sys("socket");     return false;   }   bzero(&dstaddr, sizeof(dstaddr));   dstaddr.sin_family = AF_INET;   dstaddr.sin_port = htons(0);   //printf("dest is %s/n",dest);   if (inet_pton(AF_INET, dest, &dstaddr.sin_addr) <= 0)   {     err_sys("inet_pton");     ::close(sockfd);     return false;   }   ret = send_echo_req(sockfd, &dstaddr);   if (!ret)   {     ::close(sockfd);     return false;   }   ret = recv_echo_reply(sockfd);   if (ret)   {     ::close(sockfd);     return true;   }   else   {     ::close(sockfd);     return false;   }

    }

     以上是Linux下的代码。

    最新回复(0)