📄 tracert.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 + -