• 原始套接字--traceroute


     traceroute, 也就是 trace route,跟踪路由。这个程序最早是Van Jacobson实现的。源码在网上可以找到,不过我还没有去找。是IP路由过程中对数据包TTL(Time to Live,存活时间)的处理。当路由器收到一个IP包时,会修改IP包的TTL(及由此造成的头部检验和checksum变化)。每收到一个包,检查这个 的TTL是否是0或1。如果是,表明这个包还没有到达目的地,而且剩余时间不多了,肯定是到不了目的地了。这样路由器就简单地丢弃这个包,并给源主机发送 ICMP通知,说这个包已经超时了。ICMP的通知信息里包含当前路由器发送时所用的IP。
      这样就可以通过构造数据包,来间接检查到 达一个主机时经过了哪些路由。一开始发送一个TTL为1的包,这样到达第一个路由器的时候就已经超时了,第一个路由器就发通知说包超时,这样就可以记录下 所经过的第一个路由器的IP。然后TTL加1,安全通过第一个路由器,而第二个路由器的的处理与第一个相同,丢包,发通知说包超时了,这样记录下第二个路 由器IP,由此可以一直进行下去,直到这个数据包到达目标主机,由此打印出所有经过的路由器。
    #include<stdio.h>
    #include<sys/time.h>
    #include<errno.h>
    #include<signal.h>
    #include<time.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<netdb.h>
    #include<string.h>
    #include<strings.h>
    #include<sys/socket.h>
    #include<arpa/inet.h>
    #include<netinet/in_systm.h>
    #include<netinet/ip.h>
    #include<netinet/ip_icmp.h>
    #include<netinet/udp.h>
    #include<netinet/in_systm.h>
    #define BUFSIZE 1500
    struct rec{
        u_short rec_seq;
        u_short rec_ttl;
        struct timeval rec_tv;
    };
    
    char recvbuf[BUFSIZE];
    char sendbuf[BUFSIZE];
    
    int datalen;
    char *host;
    u_short sport,dport;
    int nsent;
    pid_t pid;
    int probe,nprobes;
    int sendfd,recvfd;
    int ttl,max_ttl;
    int verbose;
    
    struct proto{
        const char*(*icmpcode)(int);
        int (*recv)(int,struct timeval*);
        struct sockaddr *sasend;    //dest addr, the destination
        struct sockaddr *sarecv;    //recv addr, store who send the message
        struct sockaddr *salast;
        struct sockaddr *sabind;    //bind the source port
        socklen_t salen;
        int icmpproto;
        int ttllevel;
        int ttloptname;
    }*pr;
    int gotalarm;
    const char *icmpcode_v4(int code){
        static char errbuf[100];
        switch(code){
            case 0:return("network unreachable");   
            case 1:return("host unreachable");
            case 2:return("protocol unreachable");
            case 3:return("port unreachable");  
            case 4:return("fragmentation required but DF bit set"); 
            case 5:return("source route failed");   
            case 6:return("destination network unknown");   
            case 7:return("destination host unknown");  
            case 8:return("source host isolated(obsolete)");    
            case 9:return("destination network administartively prohibited");
            case 10:return("destination host administartively prohibited"); 
            case 11:return("network unreachable for TOS");  
            case 12:return("host unreachable for TOS"); 
            case 13:return("communication error");  
            case 14:return("host recedenc violation");  
            case 15:return("precedence cutoff in effect");  
            default:sprintf(errbuf,"unknown code %d",code);
        }   
        return errbuf;  
    }
    void sig_alrm(int signo){
        gotalarm=1;
        return;
    }
    void tv_sub(struct timeval *out,struct timeval *in){
        if((out->tv_usec-=in->tv_usec)<0){
            --out->tv_sec;
            out->tv_sec+=1000000;
        }   
        out->tv_sec-=in->tv_sec;
    }
    void traceloop(void){
        int seq,code,done;
        double rtt;
        struct rec *rec;
        struct timeval tvrecv;
        if((recvfd=socket(pr->sasend->sa_family,SOCK_RAW,pr->icmpproto))<0){
            printf("recvfd:socket failed
    ");
            return;
        }
        setuid(getuid());
        if((sendfd=socket(pr->sasend->sa_family,SOCK_DGRAM,0))<0){
            printf("sendfd:socket failed
    ");
            return;
        }
    
        pr->sabind->sa_family=pr->sasend->sa_family;
        sport=(getpid()&0xffff) | 0x8000;
        ((struct sockaddr_in*)pr->sabind)->sin_port=htons(sport);
    
        if(bind(sendfd,pr->sabind,pr->salen)<0){
            printf("bind error
    ");
            return;
        }
    
        sig_alrm(SIGALRM);
        seq=0;
        done=0;
        for(ttl=1;ttl<=max_ttl&&done==0;ttl++){
            setsockopt(sendfd,pr->ttllevel,pr->ttloptname,&ttl,sizeof(int));//modify ttl
            bzero(pr->salast,pr->salen);
            printf("%2d ",ttl);
            fflush(stdout);
            for(probe=0;probe<nprobes;probe++){
                /*
                 *             *these sendbuf is just
                 *                         *used to exam if the received data is sended by our program 
                 *                                     */
                rec=(struct rec*)sendbuf;
                rec->rec_seq=++seq;
                rec->rec_ttl=ttl;
    
                gettimeofday(&rec->rec_tv,NULL);
                ((struct sockaddr_in*)pr->sasend)->sin_port=htons(dport+seq);
                if(sendto(sendfd,sendbuf,datalen,0,pr->sasend,pr->salen)<0){//send to dest with ttl added
                    perror("bad sendto");
                    continue;
                }
    
                //if time_out print * else print info
                if((code=(*pr->recv)(seq,&tvrecv))==-3){
                    printf(" *");
                }else{
                    char str[NI_MAXHOST];
                    if(memcmp(pr->sarecv,pr->salast,pr->salen)!=0){
                        if(getnameinfo(pr->sarecv,pr->salen,str,sizeof(str),NULL,0,0)==0){
                            printf(" %s (%s)",str,inet_ntoa(((struct sockaddr_in*)pr->sarecv)->sin_addr));
                        }else{
                            printf(" %s",inet_ntoa(((struct sockaddr_in*)pr->sarecv)->sin_addr));
                        }
                        memcpy(pr->salast,pr->sarecv,pr->salen);
                    }
                    tv_sub(&tvrecv,&rec->rec_tv);
                    rtt=tvrecv.tv_sec*1000.0+tvrecv.tv_usec/1000;
                    printf("  %.3f ms",rtt);
    
                    if(code==-1){   //reach the dest
                        done++;
                    }else if(code>0){
                        printf(" (ICMP %s)",(*pr->icmpcode)(code));
                    }
                }
                fflush(stdout);
            }
            printf("
    ");
        }
    }
    int recv_v4(int seq,struct timeval *tv){
        int hlen1,hlen2,icmplen,ret;
        socklen_t len;
        ssize_t n;
        struct ip *ip,*hip;
        struct icmp *icmp;
        struct udphdr *udp;
    
        gotalarm=0;
        for(;;){
            if(gotalarm){
                return -3;
            }
            len=pr->salen;
            alarm(3);
            n=recvfrom(recvfd,recvbuf,sizeof(recvbuf),0,pr->sarecv,&len);//data len
            if(n<0){
                if(errno==EINTR){
                    continue;
                }else{
                    printf("recvfrom error
    ");
                    return 0;
                }
            }else{
                //if recvfrom ok , close the alarm
                alarm(0);
            }
    
            //read data
            ip=(struct ip*)recvbuf;
            hlen1=ip->ip_hl<<2;//ip len
            icmp=(struct icmp*)(recvbuf+hlen1);
            if((icmplen=n-hlen1)<8){
                continue;
            }
            if(icmp->icmp_type==ICMP_TIMXCEED&&
                    icmp->icmp_code==ICMP_TIMXCEED_INTRANS){
                if(icmplen<8+sizeof(struct ip)){
                    continue;
                }
                //get icmp data
                hip=(struct ip*)(recvbuf+hlen1+8);
                hlen2=hip->ip_hl<<2;
                if(icmplen<8+hlen2+4){
                    continue;
                }
                udp=(struct udphdr *)(recvbuf+hlen1+8+hlen2);
                if(hip->ip_p==IPPROTO_UDP&&
                        udp->source==htons(sport)&&
                        udp->dest==htons(dport+seq)){
                    ret=-2;
                    break;
                }
            }else if(icmp->icmp_type==ICMP_UNREACH){
                if(icmplen<8+sizeof(struct ip))
                    continue;
                hip=(struct ip*)(recvbuf+hlen1+8);
                hlen2=hip->ip_hl<<2;
                if(icmplen<8+hlen2+4)
                    continue;
                udp=(struct udphdr*)(recvbuf+hlen1+8+hlen2);
                if(hip->ip_p==IPPROTO_UDP&&
                        udp->source==htons(sport)&&
                        udp->dest==htons(dport+seq)){
                    if(icmp->icmp_code==ICMP_UNREACH_PORT)
                        ret=-1;     //reach the destination
                    else
                        ret=icmp->icmp_code;
                    break;
                }
            }
        }
        gettimeofday(tv,NULL);
        return ret;
    }
    
    struct proto proto_v4={icmpcode_v4,recv_v4,NULL,NULL,NULL,NULL,0,IPPROTO_ICMP,IPPROTO_IP,IP_TTL};
    
    int datalen=sizeof(struct rec);
    int max_ttl=30;
    int nprobes=3;
    u_short dport=32768+666;//hope the port of dest is not used
    
    struct addrinfo *host_serv(const char *host,const char *serv,int family,int socktype){
        int n;
        struct addrinfo hints,*res;
        bzero(&hints,sizeof(hints));
        hints.ai_flags=AI_CANONNAME;
        hints.ai_family=family;
        hints.ai_socktype=socktype;
        if((n=getaddrinfo(host,serv,&hints,&res))!=0){
            return NULL;
        }
        return (res);
    }
    int main(int argc,char *argv[]){
        int c;
        struct addrinfo *ai;
        struct sigaction s_action;
        char h[20]={0};
        while((c=getopt(argc,argv,"m:v"))!=-1){
            switch(c){
                case 'm':
                    if((max_ttl=atoi(optarg))<0){
                        printf("invalid input
    ");
                    }   
                    break;
                case 'v':
                    verbose++;
                    break;
                case '?':
                    printf("unrecognized
    ");
                    return -1; 
            }   
        }   
        if(optind!=argc-1){
            printf("error input
    ");    
            return -1; 
        }  
        host=argv[optind];
    
        pid=getpid();
    
        bzero(&s_action,sizeof(s_action));
        s_action.sa_handler=sig_alrm;
        s_action.sa_flags=SA_INTERRUPT;
        sigaction(SIGALRM,&s_action,NULL);
    
    //    signal(SIGALRM,sig_alrm); 
        ai=host_serv(host,NULL,0,0);
        inet_ntop(AF_INET,&((struct sockaddr_in*)(ai->ai_addr))->sin_addr,h,sizeof(h));
        printf("traceroute to %s (%s): %d hops max, %d data bytes
    ",
                ai->ai_canonname?ai->ai_canonname:h,h,max_ttl,datalen);
    
        if(ai->ai_family==AF_INET){
            pr=&proto_v4;
        }else{
            printf("UNKNOW address family
    ");
            return -1;
        }
    
        pr->sasend=ai->ai_addr;
        pr->sarecv=(struct sockaddr*)calloc(1,ai->ai_addrlen);
        pr->salast=(struct sockaddr*)calloc(1,ai->ai_addrlen);
        pr->sabind=(struct sockaddr*)calloc(1,ai->ai_addrlen);
        pr->salen=ai->ai_addrlen;
        traceloop();
        exit(0);
    }
  • 相关阅读:
    rzc generate exited with code -2147450730.
    c#WebService动态调用
    c#BarTender打印,打印微调
    记一次ios下h5页面图片显示问题
    FID
    RSA密钥对生成,并解析公钥指数和模数
    angularjs-6
    angularjs-5
    angularjs-4
    angularjs-4
  • 原文地址:https://www.cnblogs.com/tla001/p/6592438.html
Copyright © 2020-2023  润新知