Chinaunix首页 | 论坛 | 博客
  • 博客访问: 474340
  • 博文数量: 120
  • 博客积分: 1853
  • 博客等级: 上尉
  • 技术积分: 1177
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-22 22:40
文章分类

全部博文(120)

文章存档

2013年(16)

2012年(104)

分类: 网络与安全

2012-08-07 11:29:07

    unix网络编程里面的ping命令的源代码挺长的,为了加深理解,比照书上的内容,自己写了一个简化版,代码比较粗糙,没有怎么修饰,而且只能ping IPV4的,但是可以ping网站的名字和地址。
    环境是ubuntu12.04+codelite
    执行时需要超级用户权限,如果以后想直接只用这个,可以设置一个suid位。

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/socket.h>
  6. #include <stdlib.h>
  7. #include <signal.h>
  8. #include <sys/types.h>
  9. #include <netdb.h>
  10. #include <netinet/ip_icmp.h>
  11. #include <sys/time.h>

  12. int sockfd;
  13. int size;
  14. struct addrinfo *addr_info;
  15. int send_msg(int sockfd, struct addrinfo *addr);
  16. void sig_alarm(int signo){
  17.     if(send_msg(sockfd, addr_info)<0){
  18.         puts("send_msg error");
  19.     }
  20.     alarm(1);
  21. }

  22. uint16_t in_cksum(uint16_t *addr, int len);

  23. int nsend = 0;
  24. int datalen = 56;
  25. #define BUFSIZE 1500
  26. char sendbuf[BUFSIZE];
  27. char recvbuf[BUFSIZE];



  28. int main(int argc ,char *argv[]){

  29.     if((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1){
  30.             perror("socket");
  31.             exit(1);
  32.     }
  33.         
  34.     if(signal(SIGALRM, sig_alarm) < 0){
  35.             perror("sigalrm");
  36.             exit(1);
  37.     }
  38.     
  39.     //获取ip地址
  40.     struct sockaddr_in sock_addr;
  41.     if(getaddrinfo(argv[1], NULL, NULL, &addr_info) != 0){
  42.             perror("getaddrinfo");
  43.             exit(1);
  44.     }
  45.     setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));//把套接口缓存设置为61440,防止多个ping产生溢出
  46.     
  47.     //输出一些ping的信息    
  48.     char hostname[20];//主机名字
  49.     printf("ping %s (%s): %d data bytes\n", addr_info->ai_canonname?addr_info->ai_canonname:argv[1],\
  50.      inet_ntop(AF_INET, &((struct sockaddr_in *)(addr_info->ai_addr))->sin_addr, hostname, sizeof(hostname)), \
  51.                                             datalen);


  52.     //发送icmp消息
  53.     sig_alarm(SIGALRM);
  54.     if(setuid(getuid())<0){
  55.             perror("setuid(getuid())");
  56.             return 0;
  57.     }
  58.     
  59.     int          hlen1;
  60.     char controlbuf[BUFSIZE];
  61.     struct msghdr msg;
  62.     struct iovec iov;
  63.     ssize_t      n;
  64.     struct timeval tval;
  65.     size = 61440;
  66.     
  67.     
  68.     iov.iov_base = recvbuf;
  69.     iov.iov_len    = sizeof(recvbuf);
  70.     msg.msg_iov    = &iov;
  71.     msg.msg_iovlen    = 1;
  72.     msg.msg_name    = calloc(1,addr_info->ai_addrlen);
  73.     msg.msg_namelen    = addr_info->ai_addrlen;
  74.     msg.msg_control    = controlbuf;
  75.     for(;;){
  76.         if(recvmsg(sockfd, &msg, 0) < 0){
  77.             perror("recvmsg");
  78.             return 0;
  79.         }
  80.         //解析icmp消息
  81.         if(gettimeofday(&tval, NULL) < 0){
  82.                 perror("gettimeofday");
  83.                 return 0;
  84.         }

  85.         int icmplen;
  86.         double rtt;
  87.         struct ip *ip_pkag = NULL;
  88.         struct icmp *icmp_pkg;
  89.         struct timeval *tvsend;
  90.         ip_pkag = (struct ip *)recvbuf;
  91.         hlen1 = ip_pkag->ip_hl<<2;
  92.         if(ip_pkag->ip_p != IPPROTO_ICMP){
  93.                 printf("get addr not icmp");
  94.                 return 0;
  95.         }
  96.         icmp_pkg = (struct icmp *)(recvbuf + hlen1);
  97.         if(icmp_pkg->icmp_type != ICMP_ECHOREPLY){
  98.                 printf("not icmp reply");
  99.                 return 0;
  100.         }
  101.         //计算时间差    
  102.         tvsend = (struct timeval *)(icmp_pkg->icmp_data);
  103.         if((tval.tv_usec -= tvsend->tv_usec) < 0){
  104.             tval.tv_sec;
  105.             tval.tv_usec += 1000000;
  106.         }
  107.         tval.tv_sec -= tvsend->tv_sec;
  108.         rtt = tval.tv_sec*1000.0 + tval.tv_usec/1000.0;
  109.     
  110.         printf("%d bytes from %s: seq= %u, ttl=%d, rtt=%.3fms\n",icmplen, inet_ntop(AF_INET, &((struct sockaddr_in *)(addr_info->ai_addr))->sin_addr,hostname, sizeof(hostname)), icmp_pkg->icmp_seq, ip_pkag->ip_ttl, rtt);
  111.     }
  112.     return 0;
  113. }

  114. int send_msg(int sockfd, struct addrinfo *addr_info){
  115.     struct icmp *icmp_pkg = (struct icmp *)sendbuf;
  116.     icmp_pkg->icmp_type = ICMP_ECHO;
  117.     icmp_pkg->icmp_code = 0;
  118.     icmp_pkg->icmp_id = getpid()&0xffff;
  119.     icmp_pkg->icmp_seq = nsend++;
  120.     memset(icmp_pkg->icmp_data, 0xa5, datalen);
  121.     if(gettimeofday((struct timeval *)icmp_pkg->icmp_data, NULL) < 0){
  122.             perror("gettimeofday");
  123.             return 1;
  124.     }

  125.     int len;
  126.     len = 8 + datalen;
  127.     icmp_pkg->icmp_cksum = 0;
  128.      icmp_pkg->icmp_cksum = in_cksum((u_short *)icmp_pkg, len);
  129.     
  130.     if(sendto(sockfd, sendbuf, len, 0, addr_info->ai_addr, addr_info->ai_addrlen ) < 0){
  131.         perror("sendto");
  132.         return 2;
  133.     }
  134.     return 0;
  135. }

  136. uint16_t in_cksum(uint16_t *addr, int len){
  137.     int nleft=len;
  138.     uint32_t sum = 0;
  139.     uint16_t *w = addr;
  140.     uint16_t answer = 0;
  141.     
  142.     while(nleft > 1){
  143.         sum += *w++;
  144.         nleft -= 2;
  145.     }
  146.     
  147.     if(nleft = 1){
  148.         *(unsigned char *)(&answer) = *(unsigned char *)w ;
  149.         sum += answer;
  150.     }
  151.     
  152.     sum = (sum >> 16) + (sum & 0xffff); //add hi 16 to low 16
  153.     sum += (sum>>16); //add carry
  154.     answer = ~sum; //truncate to 16 bits
  155.     return answer;
  156. }

阅读(1891) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~