unix网络编程里面的ping命令的源代码挺长的,为了加深理解,比照书上的内容,自己写了一个简化版,代码比较粗糙,没有怎么修饰,而且只能ping IPV4的,但是可以ping网站的名字和地址。
环境是ubuntu12.04+codelite
执行时需要超级用户权限,如果以后想直接只用这个,可以设置一个suid位。
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <stdlib.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <netdb.h>
- #include <netinet/ip_icmp.h>
- #include <sys/time.h>
- int sockfd;
- int size;
- struct addrinfo *addr_info;
- int send_msg(int sockfd, struct addrinfo *addr);
- void sig_alarm(int signo){
- if(send_msg(sockfd, addr_info)<0){
- puts("send_msg error");
- }
- alarm(1);
- }
- uint16_t in_cksum(uint16_t *addr, int len);
- int nsend = 0;
- int datalen = 56;
- #define BUFSIZE 1500
- char sendbuf[BUFSIZE];
- char recvbuf[BUFSIZE];
- int main(int argc ,char *argv[]){
- if((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1){
- perror("socket");
- exit(1);
- }
-
- if(signal(SIGALRM, sig_alarm) < 0){
- perror("sigalrm");
- exit(1);
- }
-
- //获取ip地址
- struct sockaddr_in sock_addr;
- if(getaddrinfo(argv[1], NULL, NULL, &addr_info) != 0){
- perror("getaddrinfo");
- exit(1);
- }
- setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));//把套接口缓存设置为61440,防止多个ping产生溢出
-
- //输出一些ping的信息
- char hostname[20];//主机名字
- printf("ping %s (%s): %d data bytes\n", addr_info->ai_canonname?addr_info->ai_canonname:argv[1],\
- inet_ntop(AF_INET, &((struct sockaddr_in *)(addr_info->ai_addr))->sin_addr, hostname, sizeof(hostname)), \
- datalen);
- //发送icmp消息
- sig_alarm(SIGALRM);
- if(setuid(getuid())<0){
- perror("setuid(getuid())");
- return 0;
- }
-
- int hlen1;
- char controlbuf[BUFSIZE];
- struct msghdr msg;
- struct iovec iov;
- ssize_t n;
- struct timeval tval;
- size = 61440;
-
-
- iov.iov_base = recvbuf;
- iov.iov_len = sizeof(recvbuf);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_name = calloc(1,addr_info->ai_addrlen);
- msg.msg_namelen = addr_info->ai_addrlen;
- msg.msg_control = controlbuf;
- for(;;){
- if(recvmsg(sockfd, &msg, 0) < 0){
- perror("recvmsg");
- return 0;
- }
- //解析icmp消息
- if(gettimeofday(&tval, NULL) < 0){
- perror("gettimeofday");
- return 0;
- }
- int icmplen;
- double rtt;
- struct ip *ip_pkag = NULL;
- struct icmp *icmp_pkg;
- struct timeval *tvsend;
- ip_pkag = (struct ip *)recvbuf;
- hlen1 = ip_pkag->ip_hl<<2;
- if(ip_pkag->ip_p != IPPROTO_ICMP){
- printf("get addr not icmp");
- return 0;
- }
- icmp_pkg = (struct icmp *)(recvbuf + hlen1);
- if(icmp_pkg->icmp_type != ICMP_ECHOREPLY){
- printf("not icmp reply");
- return 0;
- }
- //计算时间差
- tvsend = (struct timeval *)(icmp_pkg->icmp_data);
- if((tval.tv_usec -= tvsend->tv_usec) < 0){
- tval.tv_sec;
- tval.tv_usec += 1000000;
- }
- tval.tv_sec -= tvsend->tv_sec;
- rtt = tval.tv_sec*1000.0 + tval.tv_usec/1000.0;
-
- 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);
- }
- return 0;
- }
- int send_msg(int sockfd, struct addrinfo *addr_info){
- struct icmp *icmp_pkg = (struct icmp *)sendbuf;
- icmp_pkg->icmp_type = ICMP_ECHO;
- icmp_pkg->icmp_code = 0;
- icmp_pkg->icmp_id = getpid()&0xffff;
- icmp_pkg->icmp_seq = nsend++;
- memset(icmp_pkg->icmp_data, 0xa5, datalen);
- if(gettimeofday((struct timeval *)icmp_pkg->icmp_data, NULL) < 0){
- perror("gettimeofday");
- return 1;
- }
- int len;
- len = 8 + datalen;
- icmp_pkg->icmp_cksum = 0;
- icmp_pkg->icmp_cksum = in_cksum((u_short *)icmp_pkg, len);
-
- if(sendto(sockfd, sendbuf, len, 0, addr_info->ai_addr, addr_info->ai_addrlen ) < 0){
- perror("sendto");
- return 2;
- }
- return 0;
- }
- 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); //add hi 16 to low 16
- sum += (sum>>16); //add carry
- answer = ~sum; //truncate to 16 bits
- return answer;
- }
阅读(1962) | 评论(0) | 转发(0) |