#include <sys/socket.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netdb.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#define IP_HEAD_LEN 20
#define ICMP_LEN 8
#define BUFFER_SIZE 50 * 1024
int ip_fd;
int p_id;
int packet_len;
struct sockaddr_in send_addr;
char send_buf[1024];
int sequence;
struct hostent *host;
int flag;
int main(int argc, char **argv)
{
if(argc != 2){
fprintf(stderr, "usage: ping <host|ip_address>./n");
exit(1);
}
ip_fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if(ip_fd < 0){
fprintf(stderr, "raw socket error./n");
exit(1);
}
setuid(getpid());
ping(argv[1]);
}
void handle_alarm(int signo)
{
send_ip();
alarm(1);
}
ping(char *argv)
{
struct sigaction act;
act.sa_handler = handle_alarm;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGALRM, &act, NULL);
p_id = getpid();
/*只须填写地址信息,不需要指定端口信息,因为原始套接字在传输层之下*/
send_addr.sin_family = AF_INET;
/*判断是主机名还是ip地址*/
if(inet_addr(argv) == INADDR_NONE){
/*是主机名*/
if((host = gethostbyname(argv)) == NULL){
/*主机名错误*/
perror("get host by name error: unknow host.");
exit(1);
}
memcpy(&send_addr.sin_addr, host->h_addr, host->h_length);
}
else{
/*是ip地址*/
inet_aton(argv, &send_addr.sin_addr);
}
printf("ping %s(%s) %d(%d) bytes of data/n", argv,inet_ntoa(send_addr.sin_addr), sizeof(struct timeval),sizeof(struct timeval) + IP_HEAD_LEN + ICMP_LEN);
flag = 0;
/*触发一个SIGALRM信号*/
raise(SIGALRM);
recv_ip();
}
unsigned short ip_checksum(unsigned short *pcheck, int check_len)
{
int nleft = check_len;
int sum = 0;
unsigned short *p = pcheck;
unsigned short result = 0;
while(nleft > 1){
sum = sum + *p ++;
nleft -= 2;
}
if(nleft == 1){
*(unsigned char *)(&result) = *(unsigned char *)p;
sum += result;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = sum;
return result;
}
int sequence = 0;
int packet_len = IP_HEAD_LEN + ICMP_LEN;
send_ip(void)
{
if(sequence != 0 && !flag){
printf("Destination Host Unreachable/n");
}
int len;
struct icmphdr *icmp_p;
icmp_p = (struct icmphdr *)send_buf;
/*填写ICMP报文类型*/
icmp_p->type = ICMP_ECHO;
/*填写ICMP报文的代码*/
icmp_p->code = 0;
/*填写ICMP报文的标识符*/
(icmp_p->un).echo.id = p_id;
/*填写ICMP报文的序号,并增加ICMP的序号*/
(icmp_p->un).echo.sequence = sequence;
/*记录发送时间*/
gettimeofday((struct timeval*)(icmp_p + 1), NULL);
/*报文的长度等于IP包长度加上ICMP报文长度和数据长度*/
len = sizeof(struct timeval) + packet_len;
/*计算ICMP的校验和*/
icmp_p->checksum = 0;
icmp_p->checksum = ip_checksum((u_short *)icmp_p, len);
/*发送ICMP数据包*/
if(sendto(ip_fd, send_buf, len, 0, (struct sockaddr*)&send_addr, sizeof(send_addr)) < 0){
fprintf(stderr, "send to error./n");
}
}
recv_ip(void)
{
char recv_buf[1024];
int len;
int n;
struct ip *ip_p;
struct timeval *time_now, *time_send;
struct timeval now;
int iphead_len;
int icmp_len;
struct icmphdr *icmp_p;
float delay;
while(1){
n = recvfrom(ip_fd,recv_buf,sizeof(recv_buf),0,NULL,NULL);
printf("%d,flag:%d,sequence:%d/n",n,flag,sequence);
if(n < 0){
if(errno = EINTR)
continue;
else{
printf("recvfrom error./n");
continue;
}
}
ip_p = (struct ip*)recv_buf;
/*获取IP包头长度*/
iphead_len = ip_p->ip_hl<<2;
/*获取IP数据包中包含的ICMP报文*/
icmp_p = (struct icmphdr *)(recv_buf + iphead_len);
/*计算ICMP报文长度,它等于接受到的长度减去IP包头的长度*/
icmp_len = n - iphead_len;
if(icmp_len < 8){
fprintf(stderr, "error icmp len = %d./n", icmp_len);
}
/*如果ICMP类型相同则输出显示*/
if(icmp_p->type == ICMP_ECHOREPLY){
if((icmp_p->un).echo.id != p_id)
return;
if(icmp_len < 16)
printf("icmplen = %d./n", icmp_len);
flag = 1;//表示已经接收到回文;
sequence++;
gettimeofday(&now, NULL);
time_now = &now;
time_send = (struct timeval*)(icmp_p + 1);
if((time_now->tv_usec -= time_send->tv_usec) < 0){
time_now->tv_sec --;
time_now->tv_usec += 1000000;
}
time_now->tv_sec -= time_send->tv_sec;
/*计算延时*/
delay = time_now->tv_sec * 1000.0 + time_now->tv_usec / 1000.0;
/*打印接收到的报文相关信息*/
printf("%d(%d) bytes from %s: icmp_seq=%d ttl=%d time=%.3fms/n",
icmp_len, n, inet_ntoa(send_addr.sin_addr), (icmp_p->un).echo.sequence,
ip_p->ip_ttl, delay);
}
}
}
那位高手帮忙看看这段代码有什么问题?怎么总出现下面的情况?
10.129.73.25是本机的网关;
[root@localhost6 123]# ./ping 10.129.73.25
ping 10.129.73.25(10.129.73.25) 8(36) bytes of data
-1,flag:0,sequence:0
-1,flag:0,sequence:0
-1,flag:0,sequence:0
-1,flag:0,sequence:0
-1,flag:0,sequence:0
-1,flag:0,sequence:0
10.129.73.100是本机的IP
[root@localhost6 123]# ./ping 10.129.73.100
ping 10.129.73.100(10.129.73.100) 8(36) bytes of data
56,flag:0,sequence:0
56,flag:0,sequence:0
36(56) bytes from 10.129.73.100: icmp_seq=0 ttl=64 time=0.308ms
-1,flag:1,sequence:1
56,flag:1,sequence:1
56,flag:1,sequence:1
36(56) bytes from 10.129.73.100: icmp_seq=1 ttl=64 time=0.213ms
-1,flag:1,sequence:2
56,flag:1,sequence:2
56,flag:1,sequence:2
36(56) bytes from 10.129.73.100: icmp_seq=2 ttl=64 time=0.163ms
-1,flag:1,sequence:3
56,flag:1,sequence:3
56,flag:1,sequence:3
36(56) bytes from 10.129.73.100: icmp_seq=3 ttl=64 time=0.147ms
-1,flag:1,sequence:4
56,flag:1,sequence:4
56,flag:1,sequence:4
36(56) bytes from 10.129.73.100: icmp_seq=4 ttl=64 time=0.156ms
-1,flag:1,sequence:5
56,flag:1,sequence:5
56,flag:1,sequence:5
36(56) bytes from 10.129.73.100: icmp_seq=5 ttl=64 time=0.146ms
-1,flag:1,sequence:6
56,flag:1,sequence:6
56,flag:1,sequence:6
36(56) bytes from 10.129.73.100: icmp_seq=6 ttl=64 time=0.145ms