⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tracert.c

📁 Linux下面实现trace功能的网络程序例子
💻 C
字号:
/* * traceroute     * see unp1 chapter 25  * hushui 2002.6  * * Linux 2.2.14-5.0  * $ gcc -v * Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/specs * gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release) *  */#include "stdio.h"#include "errno.h"#include "signal.h"#include "sys/time.h"#include "sys/types.h"#include "sys/socket.h"#include "netinet/in.h"#include "netinet/ip.h"#include "netinet/udp.h"#include "netinet/ip_icmp.h"#include "netdb.h"#define BUFFSIZE  1500 /* max size ,set to MTU */#define MAX_TRACE_TTL 30 #define TIMEOUT      (-2)#define RECV_ERROR   (-3)#define ICMP_ERROR   (-4)  #define REACHDEST    (-5)#define INTER_ROUTER (-6)#pragma pack(1) struct rec{ /* outgoing UDP data */	unsigned short rec_seq;	unsigned short rec_ttl;	struct timeval rec_tv;};int traceloop();int recv_result(unsigned short seq,		struct sockaddr_in *precv_addr ,struct timeval * tv) ;void sig_alarm(int signal_num);void timeval_sub(struct timeval *recv, struct timeval *send) ;static int icmpfd , udpfd; /* icmp and udp socket fd */static struct sockaddr_in dest_addr; /* destnation host sockaddr struct */static struct sockaddr_in local;  /* local udp sockaddr struct */static int prob,maxprob; /* maxprob: max prob for each intermediate router */ static unsigned short ttl,maxttl; /* maxttl:max hop before get to destination */static pid_t pid ; static unsigned int dest_port=32768 + 666;  /* dest UDP port for probe */static unsigned int loca_port  ;           /* local UDP port */static char recvbuff[BUFFSIZE];static char sendbuff[BUFFSIZE];void  sig_alarm(int signal_num){	return; /* generate EINTR from recvfrom */}/*   *  Main */int main(int argc ,char * argv[]){	struct hostent *he; /* get destination  host information */	struct sigaction old,new ;	if(argc!=2) {		printf("useage : ping  dest_addrhost \n");		exit(0);	}	if((he=gethostbyname(argv[1]))==NULL) {		perror("gethostbyname");		exit(1);	}	dest_addr.sin_addr =*((struct in_addr*)(he->h_addr)); /* IP address */	dest_addr.sin_family=AF_INET;	bzero(&(dest_addr.sin_zero),8);		if((icmpfd=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP))<0){	/* raw socket for receiving ICMP error datagram*/		perror("socket");		exit(1);	}	/* Raw socket must be created as root user  */	setuid(getuid()); /* don't need root prividge any more */	new.sa_handler=sig_alarm;	sigemptyset(&new.sa_mask);	new.sa_flags=0;	new.sa_flags=SA_INTERRUPT;	sigaction(SIGALRM ,&new,&old); /* set up alram */	printf("tracert  %s\n", inet_ntoa(dest_addr.sin_addr));	setvbuf(stdout,NULL,_IONBF,0);	traceloop();	sigaction(SIGALRM ,&old,NULL); /* set up alram */	close(icmpfd);	return  1 ;}int traceloop(){	int n , recv_err;	struct rec * p_rec ; /* UDP sending data */	struct sockaddr_in recv_addr;	unsigned short seq;	int done,bsdopt ;	struct timeval tvrecv ;	float rtt ;	struct protoent * protoent; 	if((udpfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))<0){	/* UDP socket for probe */		perror("socket");		return -1 ;	}	local.sin_family=AF_INET;	loca_port=(getpid() & 0xffff) | 0x8000;  /* local udp port. */	local.sin_port=htons(loca_port);  /* local udp port. */	bzero(&(local.sin_zero),8);       	bsdopt=1 ;       	protoent =  getprotobyname("icmp");	if (!protoent) {		perror("getprotobyname");		return -1;       	}       	else {   		if (setsockopt(udpfd, protoent->p_proto, SO_BSDCOMPAT, (char*)&bsdopt, sizeof(bsdopt))			               == -1) {		     	perror("setsockopt");			return -1;			}	} 	if(bind(udpfd,(struct sockaddr*)(&local),sizeof(struct sockaddr))<0)	{		perror("bind");		return -1 ;	}		maxttl=MAX_TRACE_TTL; seq=0; maxprob=3; /* initialize */	seq=0; done=0;	for(ttl=1;ttl<=maxttl&&(done==0);ttl++) /* main loop */ 		{		if(setsockopt(udpfd,IPPROTO_IP,IP_TTL,&ttl,		/* attention ,ttl should not be zero */					sizeof(ttl))<0)		{			perror("setsockopt");			return  -1;		}		printf("TTL=%3d ",ttl);		for(prob=0;prob<maxprob;prob++){			p_rec=(struct rec*)sendbuff;			p_rec->rec_ttl=ttl;			p_rec->rec_seq=++seq;			dest_addr.sin_port=htons(dest_port+seq);			/* remote udp port for probe ,			 * be careful that it is not used by remote  host 			 */						gettimeofday((struct timeval*)(&p_rec->rec_tv),NULL) ;			/* OK ,let's send the UDP request */			if(sendto(udpfd,(char*)p_rec,				  	 sizeof(struct rec),0,					 (struct sockaddr*)(&dest_addr), 					 sizeof(struct sockaddr))==-1)			{       				perror("sendto");				return -1 ;			}			recv_err=recv_result(seq,&recv_addr,&tvrecv); 			timeval_sub(&tvrecv, &(p_rec->rec_tv)); 			rtt = tvrecv.tv_sec * 1000.0 + tvrecv.tv_usec/1000.0; 						switch(recv_err)			{			  case(TIMEOUT):   			           printf("\t\t  *  \t");				   break;			  case(RECV_ERROR):			  case(ICMP_ERROR):				   printf("recv error\n");				   return -1 ;			  case(INTER_ROUTER):   			           printf("  %s(%.3fms)  ",inet_ntoa(recv_addr.sin_addr),rtt);				   break;			  case(REACHDEST): /* reach destination */   			           printf("  %s(%.3f)ms  ",inet_ntoa(recv_addr.sin_addr),rtt);				   done++;				   break;			  default:				  /* printf("\tother ICMP error%d \n ",recv_err);*//* for debug */ 				   break;		    	}		fflush(stdout); 		alarm(0);		} /* end nested for loop (one intermediate router probe) */		printf("\n");	}/* end main loop*/		if(done)  printf("done  %d hops \n" , ttl-1);	close(udpfd);	return   1;}int recv_result(unsigned short seq,		struct sockaddr_in *precv_addr ,struct timeval * tv) {/* process recvbuff  * see which ICMP errnor message received  * * The packet should receive  * *  * *  * |-------------------------------------n--------------------------------------|  *                          |-----------------icmplen---------------------------|  * |--------len_iphead------|             |--------hlen_iphead-----|  * * | IPv4 header | IPv4 opt | ICMP header | IPv4 header | IPv4 opt | UDP header |  * * |-----20B-----|--0~40B---|-----8B------|-----20B-----|---0~40B--|-----8B-----|  * *  *  */	struct ip *ip ,*hip;	struct icmp *icmp;	int len_iphead ,hlen_iphead,icmplen ;	int n ;	double rrt ;	struct udphdr * udp;	unsigned int sock_len=sizeof(struct sockaddr);	alarm(2);	if((n=recvfrom(icmpfd,recvbuff,sizeof(recvbuff),0,			   (struct sockaddr*)precv_addr,&sock_len))<0)	{		if(errno==EINTR)			return TIMEOUT;		else			return RECV_ERROR;	}		gettimeofday(tv,NULL); /* save recv time */		ip=(struct ip*)recvbuff ;	len_iphead=ip->ip_hl<<2; /*  length of IP head */	icmp=(struct icmp*)(recvbuff+len_iphead);	if((icmplen=n-len_iphead)<8)			return RECV_ERROR;		if(icmp->icmp_type==ICMP_TIMXCEED&&		icmp->icmp_code==ICMP_TIMXCEED_INTRANS){		if(icmplen<(8+20+8))			return ICMP_ERROR;		hip=(struct ip*)(recvbuff+len_iphead+8);		hlen_iphead=hip->ip_hl<<2; /*  length of old IP head */		udp=(struct udphdr*)(recvbuff+len_iphead+8+hlen_iphead);		if(hip->ip_p==IPPROTO_UDP&&			udp->source==htons(loca_port)&&			udp->dest==htons(dest_port+seq))			return INTER_ROUTER; /* we meet a intermediate router */	}else if(icmp->icmp_type==ICMP_UNREACH)	{		if(icmplen<8+20+8)			return ICMP_ERROR;		hip=(struct ip*)(recvbuff+len_iphead+8);		hlen_iphead=hip->ip_hl<<2; /*  length of old IP head */		udp=(struct udphdr*)(recvbuff+len_iphead+8+hlen_iphead);		if(hip->ip_p==IPPROTO_UDP&&			udp->source==htons(loca_port)&&			udp->dest==htons(dest_port+seq))		{					if(icmp->icmp_code==ICMP_UNREACH_PORT)				return REACHDEST;			else{			       	return (icmp->icmp_code); /* 0,1,2...*/			}		}	}	/** some other ICMP error **/        return (icmp->icmp_code|icmp->icmp_type); /* >0 */}void timeval_sub(struct timeval *recv, struct timeval *send) { 	if((recv->tv_usec -= send->tv_usec) < 0) { 		recv->tv_sec--; 		recv->tv_usec += 1000000; 	} 	recv->tv_sec -= send->tv_sec; 	return; } 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -