zoukankan      html  css  js  c++  java
  • 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 }




  • 相关阅读:
    LeetCode 32. 最长有效括号(Longest Valid Parentheses)
    LeetCode 141. 环形链表(Linked List Cycle)
    LeetCode 160. 相交链表(Intersection of Two Linked Lists)
    LeetCode 112. 路径总和(Path Sum)
    LeetCode 124. 二叉树中的最大路径和(Binary Tree Maximum Path Sum)
    LightGBM新特性总结
    sql service 事务与锁
    C#泛型实例详解
    C# 中的委托和事件(详解)
    C# DateTime日期格式化
  • 原文地址:https://www.cnblogs.com/aLittleBitCool/p/2182760.html
Copyright © 2011-2022 走看看