• UNP1:Linux下实现traceroute程序


    这个程序敲得我快吐血了.....在敲代码和调试过程中遇到了N个纠结的问题.....我还差的远呢,继续努力~

    -------------------------以下为正文--------------------------

    traceroute程序,简单的说就是找到本地与目的地之间route节点。它的实现方法是通过不断发送ttl递增的请求包来实现。具体的原理可以参照TCP/IP详解,里面讲的很透彻~

    以下为实现代码(相比书中做了一些改动)

    trace.h

     1 #include<stdio.h>
    2 #include<sys/time.h>
    3 #include<errno.h>
    4 #include<signal.h>
    5 #include<time.h>
    6 #include<stdlib.h>
    7 #include<unistd.h>
    8 #include<netdb.h>
    9 #include<string.h>
    10 #include<strings.h>
    11 #include<sys/socket.h>
    12 #include<arpa/inet.h>
    13 #include<netinet/in_systm.h>
    14 #include<netinet/ip.h>
    15 #include<netinet/ip_icmp.h>
    16 #include<netinet/udp.h>
    17 #include<netinet/in_systm.h>
    18 #define BUFSIZE 1500
    19 struct rec{
    20 u_short rec_seq;
    21 u_short rec_ttl;
    22 struct timeval rec_tv;
    23 };
    24
    25 char recvbuf[BUFSIZE];
    26 char sendbuf[BUFSIZE];
    27
    28 int datalen;
    29 char *host;
    30 u_short sport,dport;
    31 int nsent;
    32 pid_t pid;
    33 int probe,nprobes;
    34 int sendfd,recvfd;
    35 int ttl,max_ttl;
    36 int verbose;
    37
    38 const char* icmpcode_v4(int);
    39 int recv_v4(int,struct timeval*);
    40 void sig_alrm(int);
    41 void traceloop(void);
    42 void tv_sub(struct timeval*,struct timeval*);
    43
    44 struct proto{
    45 const char*(*icmpcode)(int);
    46 int (*recv)(int,struct timeval*);
    47 struct sockaddr *sasend; //dest addr, the destination
    48 struct sockaddr *sarecv; //recv addr, store who send the message
    49 struct sockaddr *salast;
    50 struct sockaddr *sabind; //bind the source port
    51 socklen_t salen;
    52 int icmpproto;
    53 int ttllevel;
    54 int ttloptname;
    55 }*pr;

    main.c

     1 #include"trace.h"
    2 struct proto proto_v4={icmpcode_v4,recv_v4,NULL,NULL,NULL,NULL,0,IPPROTO_ICMP,IPPROTO_IP,IP_TTL};
    3
    4 int datalen=sizeof(struct rec);
    5 int max_ttl=30;
    6 int nprobes=3;
    7 u_short dport=32768+666;//hope the port of dest is not used
    8
    9 struct addrinfo *host_serv(const char *host,const char *serv,int family,int socktype){
    10 int n;
    11 struct addrinfo hints,*res;
    12 bzero(&hints,sizeof(hints));
    13 hints.ai_flags=AI_CANONNAME;
    14 hints.ai_family=family;
    15 hints.ai_socktype=socktype;
    16 if((n=getaddrinfo(host,serv,&hints,&res))!=0){
    17 return NULL;
    18 }
    19 return (res);
    20 }
    21 int main(int argc,char *argv[]){
    22 int c;
    23 struct addrinfo *ai;
    24 struct sigaction s_action;
    25 char h[20]={0};
    26 while((c=getopt(argc,argv,"m:v"))!=-1){
    27 switch(c){
    28 case 'm':
    29 if((max_ttl=atoi(optarg))<0){
    30 printf("invalid input\n");
    31 }
    32 break;
    33 case 'v':
    34 verbose++;
    35 break;
    36 case '?':
    37 printf("unrecognized\n");
    38 return -1;
    39 }
    40 }
    41 if(optind!=argc-1){
    42 printf("error input\n");
    43 return -1;
    44 }
    45 host=argv[optind];
    46
    47 pid=getpid();
    48
    49 bzero(&s_action,sizeof(s_action));
    50 s_action.sa_handler=sig_alrm;
    51 s_action.sa_flags=SA_INTERRUPT;
    52 sigaction(SIGALRM,&s_action,NULL);
    53
    54 // signal(SIGALRM,sig_alrm);
    55 ai=host_serv(host,NULL,0,0);
    56 inet_ntop(AF_INET,&((struct sockaddr_in*)(ai->ai_addr))->sin_addr,h,sizeof(h));
    57 printf("traceroute to %s (%s): %d hops max, %d data bytes\n",
    58 ai->ai_canonname?ai->ai_canonname:h,h,max_ttl,datalen);
    59
    60 if(ai->ai_family==AF_INET){
    61 pr=&proto_v4;
    62 }else{
    63 printf("UNKNOW address family\n");
    64 return -1;
    65 }
    66
    67 pr->sasend=ai->ai_addr;
    68 pr->sarecv=(struct sockaddr*)calloc(1,ai->ai_addrlen);
    69 pr->salast=(struct sockaddr*)calloc(1,ai->ai_addrlen);
    70 pr->sabind=(struct sockaddr*)calloc(1,ai->ai_addrlen);
    71 pr->salen=ai->ai_addrlen;
    72 traceloop();
    73 exit(0);
    74 }

    traceloop.c

    这里udp结构里的成员按照书上的写法会出现错误。linux里对udp的定义不一样。

      1 //#define __FAVOR_BSD
    2 #include"trace.h"
    3 int gotalarm;
    4 const char *icmpcode_v4(int code){
    5 static char errbuf[100];
    6 switch(code){
    7 case 0:return("network unreachable");
    8 case 1:return("host unreachable");
    9 case 2:return("protocol unreachable");
    10 case 3:return("port unreachable");
    11 case 4:return("fragmentation required but DF bit set");
    12 case 5:return("source route failed");
    13 case 6:return("destination network unknown");
    14 case 7:return("destination host unknown");
    15 case 8:return("source host isolated(obsolete)");
    16 case 9:return("destination network administartively prohibited");
    17 case 10:return("destination host administartively prohibited");
    18 case 11:return("network unreachable for TOS");
    19 case 12:return("host unreachable for TOS");
    20 case 13:return("communication error");
    21 case 14:return("host recedenc violation");
    22 case 15:return("precedence cutoff in effect");
    23 default:sprintf(errbuf,"unknown code %d",code);
    24 }
    25 return errbuf;
    26 }
    27 void sig_alrm(int signo){
    28 gotalarm=1;
    29 return;
    30 }
    31 void tv_sub(struct timeval *out,struct timeval *in){
    32 if((out->tv_usec-=in->tv_usec)<0){
    33 --out->tv_sec;
    34 out->tv_sec+=1000000;
    35 }
    36 out->tv_sec-=in->tv_sec;
    37 }
    38 void traceloop(void){
    39 int seq,code,done;
    40 double rtt;
    41 struct rec *rec;
    42 struct timeval tvrecv;
    43 if((recvfd=socket(pr->sasend->sa_family,SOCK_RAW,pr->icmpproto))<0){
    44 printf("recvfd:socket failed\n");
    45 return;
    46 }
    47 setuid(getuid());
    48 if((sendfd=socket(pr->sasend->sa_family,SOCK_DGRAM,0))<0){
    49 printf("sendfd:socket failed\n");
    50 return;
    51 }
    52
    53 pr->sabind->sa_family=pr->sasend->sa_family;
    54 sport=(getpid()&0xffff) | 0x8000;
    55 ((struct sockaddr_in*)pr->sabind)->sin_port=htons(sport);
    56
    57 if(bind(sendfd,pr->sabind,pr->salen)<0){
    58 printf("bind error\n");
    59 return;
    60 }
    61
    62 sig_alrm(SIGALRM);
    63 seq=0;
    64 done=0;
    65 for(ttl=1;ttl<=max_ttl&&done==0;ttl++){
    66 setsockopt(sendfd,pr->ttllevel,pr->ttloptname,&ttl,sizeof(int));//modify ttl
    67 bzero(pr->salast,pr->salen);
    68 printf("%2d ",ttl);
    69 fflush(stdout);
    70 for(probe=0;probe<nprobes;probe++){
    71 /*
    72 *these sendbuf is just
    73 *used to exam if the received data is sended by our program
    74 */
    75 rec=(struct rec*)sendbuf;
    76 rec->rec_seq=++seq;
    77 rec->rec_ttl=ttl;
    78
    79 gettimeofday(&rec->rec_tv,NULL);
    80 ((struct sockaddr_in*)pr->sasend)->sin_port=htons(dport+seq);
    81 if(sendto(sendfd,sendbuf,datalen,0,pr->sasend,pr->salen)<0){//send to dest with ttl added
    82 perror("bad sendto");
    83 continue;
    84 }
    85
    86 //if time_out print * else print info
    87 if((code=(*pr->recv)(seq,&tvrecv))==-3){
    88 printf(" *");
    89 }else{
    90 char str[NI_MAXHOST];
    91 if(memcmp(pr->sarecv,pr->salast,pr->salen)!=0){
    92 if(getnameinfo(pr->sarecv,pr->salen,str,sizeof(str),NULL,0,0)==0){
    93 printf(" %s (%s)",str,inet_ntoa(((struct sockaddr_in*)pr->sarecv)->sin_addr));
    94 }else{
    95 printf(" %s",inet_ntoa(((struct sockaddr_in*)pr->sarecv)->sin_addr));
    96 }
    97 memcpy(pr->salast,pr->sarecv,pr->salen);
    98 }
    99 tv_sub(&tvrecv,&rec->rec_tv);
    100 rtt=tvrecv.tv_sec*1000.0+tvrecv.tv_usec/1000;
    101 printf(" %.3f ms",rtt);
    102
    103 if(code==-1){ //reach the dest
    104 done++;
    105 }else if(code>0){
    106 printf(" (ICMP %s)",(*pr->icmpcode)(code));
    107 }
    108 }
    109 fflush(stdout);
    110 }
    111 printf("\n");
    112 }
    113 }
    114 int recv_v4(int seq,struct timeval *tv){
    115 int hlen1,hlen2,icmplen,ret;
    116 socklen_t len;
    117 ssize_t n;
    118 struct ip *ip,*hip;
    119 struct icmp *icmp;
    120 struct udphdr *udp;
    121
    122 gotalarm=0;
    123 for(;;){
    124 if(gotalarm){
    125 return -3;
    126 }
    127 len=pr->salen;
    128 alarm(3);
    129 n=recvfrom(recvfd,recvbuf,sizeof(recvbuf),0,pr->sarecv,&len);//data len
    130 if(n<0){
    131 if(errno==EINTR){
    132 continue;
    133 }else{
    134 printf("recvfrom error\n");
    135 return 0;
    136 }
    137 }else{
    138 //if recvfrom ok , close the alarm
    139 alarm(0);
    140 }
    141
    142 //read data
    143 ip=(struct ip*)recvbuf;
    144 hlen1=ip->ip_hl<<2;//ip len
    145 icmp=(struct icmp*)(recvbuf+hlen1);
    146 if((icmplen=n-hlen1)<8){
    147 continue;
    148 }
    149 if(icmp->icmp_type==ICMP_TIMXCEED&&
    150 icmp->icmp_code==ICMP_TIMXCEED_INTRANS){
    151 if(icmplen<8+sizeof(struct ip)){
    152 continue;
    153 }
    154 //get icmp data
    155 hip=(struct ip*)(recvbuf+hlen1+8);
    156 hlen2=hip->ip_hl<<2;
    157 if(icmplen<8+hlen2+4){
    158 continue;
    159 }
    160 udp=(struct udphdr *)(recvbuf+hlen1+8+hlen2);
    161 if(hip->ip_p==IPPROTO_UDP&&
    162 udp->source==htons(sport)&&
    163 udp->dest==htons(dport+seq)){
    164 ret=-2;
    165 break;
    166 }
    167 }else if(icmp->icmp_type==ICMP_UNREACH){
    168 if(icmplen<8+sizeof(struct ip))
    169 continue;
    170 hip=(struct ip*)(recvbuf+hlen1+8);
    171 hlen2=hip->ip_hl<<2;
    172 if(icmplen<8+hlen2+4)
    173 continue;
    174 udp=(struct udphdr*)(recvbuf+hlen1+8+hlen2);
    175 if(hip->ip_p==IPPROTO_UDP&&
    176 udp->source==htons(sport)&&
    177 udp->dest==htons(dport+seq)){
    178 if(icmp->icmp_code==ICMP_UNREACH_PORT)
    179 ret=-1; //reach the destination
    180 else
    181 ret=icmp->icmp_code;
    182 break;
    183 }
    184 }
    185 }
    186 gettimeofday(tv,NULL);
    187 return ret;
    188 }




  • 相关阅读:
    好利獲得(意大利电信集团)
    NFS CIFS SAMBA 的联系和区别
    Common Internet File System
    服务信息块协议 SMB(Server Message Block protocol)
    TF卡和SD卡的区别
    Robots协议(爬虫协议、机器人协议)
    语义后承(semantic consequence),句法后承(syntactic consequence),实质蕴含(material implication / material conditional)
    Word 页眉插入自动标题(页眉显示章节标题)
    Intel® Core™ i5-5300U Processor
    linux的chmod,chown命令详解
  • 原文地址:https://www.cnblogs.com/aLittleBitCool/p/2182760.html
Copyright © 2020-2023  润新知