icmp的程序(ping的实现)
code来源于《网络编程与分层协议设计》 chap7 ICMP协议程序设计
----没有理解,没有编译,只是敲了出来
ping.h
#define ICMP_ECHOREPLY 0
#define ICMP_ECHO       8
#define BUFSIZE   1500
#define DEFAULT_LEN  56
typedef unsigned char  u8;
typedef unsigned short u16;
typedef unsigned int   u32;
struct icmphdr{
	u8  type;
	u8  code;
	u16 checksum;
	union{
		struct  {
			u16 id;
			u16 sequence;
		}echo;
		u32 gateway;
		struct  
		{
			u16 unused;
			u16 mtu;
		}frag;
	}un;
	u8 data[0];
#define icmp_id un.echo.id
#define icmp_seq un.echo.sequence
};
#define ICMP_HSIZE sizeof(struct icmphdr)
struct iphdr{
	u8  hlen:4, ver:4;
	u8  tos;
	u16 tot_len;
	u16 id;
	u16 frag_off;
	u8  ttl;
	u8  protocol;
	u16 check;
	u32 saddr;
	u32 daddr;
};
char *hostname; 
int  datalen = DEFAULT_LEN;
char sendbuf[BUFSIZE];
char recvbuf[BUFSIZE];
int  nsent;
int  nrecv;
pid_t pid;
struct timeval recvtime;
int   sockfd;
struct sockaddr_in dest;
struct sockaddr_in from;
struct sigaction act_alarm;
struct sigaction act_int;
void alarm_handler(int);
void int_handler(int);
void set_sighandler();
void send_ping();
void recv_reply();
u16 checksum(u8 *buf, int len);
int handle_pkt();
void get_statistics(int, int);
void bail(const char *)
ping.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <errno.h>
#include <arpa/inet.h>
#include <signal.h>
#include <netinet/in.h>
#include "ping.h"
struct itimerval val_alarm={.it_interval.tv_sec = 1,
	                        .it_interval.tv_usec = 0,
							.it_value.tv_sec = 0,
							.it_value.tv_usec = 1
                           };
int main(int argc, char **argv)
{
	struct hostent *host;
	if (argc < 2){
		printf("Usuage: %s hostname\n", argv[0]);
		exit(1);
	}
	if (host = gethostbyname(argv[1]) == NULL){
		perror("can not understand the host name");
		exit(1);
	}
hostname = argv[1];
	memset(&dest, 0, sizeof(dest));
	dest.sin_family = PF_INET;
	dest.sin_port = ntohs(0);
	dest.sin_addr = *(struct in_addr *)host->h_addr_list[0];
	if ((sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0){
		perror("raw socket created error");
		exit(1);
	}
	setuid(getuid());
	pid = getpid();
	set_sighandler();
	printf("Ping %s(%s): %d bytes data in ICMP packets.\n\n",
		   argv[1], inet_ntoa(dest.sin_addr), datalen);
	if ((setitimer(ITIMER_REAL, &val_alarm, NULL)) == -1)
		bail("setitimer fails.");
	recv_reply();
	return 0;
}
void send_ping(void)
{
	struct icmphdr *icmp_hdr;
	int len;
	icmp_hdr = (struct icmphdr *)sendbuf;
	icmp_hdr->type = ICMP_ECHO;
	icmp_hdr->code = 0;
	icmp_hdr->icmp_id = pid;
	icmp_hdr->icmp_seq = nsent++;
	memset(icmp_hdr->data, 0xff, datalen);
gettimeofday((struct timeval *)icmp_hdr->data, NULL);
	len = ICMP_HSIZE + datalen;
	icmp_hdr->checksum = 0;
	icmp_hdr->checksum = checksum((u8 *)icmp_hdr, len);
	sendto(sockfd, sendbuf, len, 0, (struct sockaddr *)&dest, sizeof(dest));
}
void recv_reply()
{
	int n, len;
	int errno;
	n = nrecv = 0;
	len = sizeof(from);
	while (nrecv < 3){
		if ((n = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&from, &len)) < 0){
				   if (errno == EINTR)
					   continue;
				   bail("recvfrom error");
		}
gettimeofday(&recvtime, NULL);
if (handle_pkt())
			continue;
		nrecv++;
	}
	get_statistics(nsent, nrecv);
}
u16 checksum(u8 *buf, int len)
{
	u32 sum = 0;
	u16 *cbuf;
cbuf = (u16 *)buf;
	while (len > 1){
		sum += *cbuf++;
		len -= 2;
	}
	if(len)
		sum += *(u8 *)cbuf;
	sum = (sum >> 16) + (sum & 0xffff);
	sum += (sum >> 16);
	return -sum;
}
int handle_pkt()
{
	struct iphdr *ip;
	struct icmphdr *icmp;
	int ip_hlen;
	u16 ip_datalen;
	double rtt;
	struct timeval *sendtime;
ip = (struct iphdr *)recvbuf;
	ip_hlen = ip->hlen << 2;
	ip_datalen = ntohs(ip->tot_len) - ip_hlen;
icmp = (struct icmphdr *)(recvbuf + ip_hlen);
	if (checksum(u8 *)icmp, ip_datalen)
		return -1;
	if(icmp->icmp_id != pid)
		return -1;
	sendtime = (struct timeval *)icmp->data;
	rtt = ((&recvtime)->tv_sec - sendtime->tv_sec)*1000 + ((&recvtime)->tv_usec - sendtime->tv_usec)/1000.0;
	printf("%d bytes from %s: icmp_seq = %u ttl=%d rtt=%.3f ms\n", 
		ip_datalen, 
		inet_ntoa(from.sin_addr), 
		icmp->icmp_seq, 
		ip->ttl, 
		rtt);
	return 0;
}
void set_sighandler()
{
	act_alarm.sa_handler = alarm_handler;
	if (sigaction(SIGALRM, &act_alarm, NULL) == -1)
		bail("SIGALRM handler setting fails.");
	act_int.sa_handler = int_handler;
	if (sigaction(SIGINT, &act_int, NULL) == -1)
		bail("SIGINT handler setting fails.");
}
void get_statistics(int nsent, int nrecv)
{
	printf("---%s ping statistics ---\n", inet_ntoa(dest.sin_addr));
	printf("%d packets transmitted, %d received, %0.0f%%" "packet loss\n",
		nsent, nrecv, 1.0*(nsent - nrecv)/nsent*100);
}
void bail(const char *on_what)
{
	fputs(strerror(errno), stderr);
	fputs(":", stderr);
	fputs(on_what, stderr);
	fputc('\n', stderr);
	exit(1);
}
void int_handler(int sig)
{
	get_statistics(nsent, nrecv);
	close(sockfd);
	exit(1);
}
void alarm_handler(int signo)
{
	send_ping();
}
 
                    
                     
                    
                 
                    
                 
                
            
         
 
         浙公网安备 33010602011771号
浙公网安备 33010602011771号