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

📄 traceroute.c

📁 Linux网络编程教程适合初学者入门学习
💻 C
字号:
#include <signal.h>

#include <netinet/in.h>

#include <netdb.h>

#include <sys/socket.h>

#include  <sys/types.h> 

#include  <sys/times.h> 

#include <sys/time.h>

#include  <sys/select.h> 

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h> 

#include <fcntl.h>

#include <errno.h>



struct ip

{

#if __BYTE_ORDER == __LITTLE_ENDIAN

    unsigned int ip_hl:4;                /* little-endian IP头长度(单位为32位)4位 */

    unsigned int ip_v:4;                 /* 版本号4 IP4用4 */

#endif

#if __BYTE_ORDER == __BIG_ENDIAN

    unsigned int ip_v:4;                /*  version */

    unsigned int ip_hl:4;               /*  header length */

#endif

    u_int8_t ip_tos;                    /* 服务类型  一般为0 */

    u_short ip_len;                     /* 数据总长度 (单位为32位) */

    u_short ip_id;                      /* 标识16 */

    u_short ip_off;                     /* 分段偏移*/

#define IP_RF 0x8000                    /*  reserved fragment标志 */

#define IP_DF 0x4000                    /*  dont fragment flag */

#define IP_MF 0x2000                    /*  more fragments flag */

#define IP_OFFMASK 0x1fff               /*  mask for fragmenting bits */

    u_int8_t ip_ttl;                     /* 生存时间 */

    u_int8_t ip_p;                      /* 传输协议 tcp是6 */

    u_short ip_sum;                     /* 头校验和 */

    struct in_addr ip_src, ip_dst;      /*  源地址 目标地址 */

};



struct icmp             

{

u_int8_t  type;		/* 消息类型 */

  	u_int8_t  code;		/* 代码类型 */

  	u_int16_t checksum;	/* 校验位 */

  	union

  	{

    		u_char ih_pptr;			/* ICMP_PARAMPROB */

    		struct in_addr ih_gwaddr;	/* 网关地址 */

    		struct 					/* echo 数据包 */

{

      		u_int16_t id;

      		u_int16_t sequence;

    		} echo;



    u_int32_t ih_void;



    struct ih_pmtu

    {

     	u_int16_t ipm_void;

     	u_int16_t ipm_nextmtu;

} ih_pmtu;



    struct ih_rtradv

    {

u_int8_t irt_num_addrs;

u_int8_t irt_wpa;

u_int16_t irt_lifetime;

    } ih_rtradv;

  } un;

#define	icmp_pptr	un.ih_pptr

#define	icmp_gwaddr	un.ih_gwaddr

#define	icmp_id		un.echo.id

#define	icmp_seq	un.echo.sequence

#define	icmp_void	un.ih_void

#define	icmp_pmvoid	un.ih_pmtu.ipm_void

#define	icmp_nextmtu	un.ih_pmtu.ipm_nextmtu

#define	icmp_num_addrs	un.ih_rtradv.irt_num_addrs

#define	icmp_wpa	un.ih_rtradv.irt_wpa

#define	icmp_lifetime	un.ih_rtradv.irt_lifetime

  

union

{

    struct

    {

    		u_int32_t its_otime;

u_int32_t its_rtime;

      	u_int32_t its_ttime;

    } id_ts;

    struct

    {

    		struct ip idi_ip;

	  /* 属性阿和紧跟它的64位数据 */

    } id_ip;



  } icmp_dun;

#define	icmp_otime	icmp_dun.id_ts.its_otime

#define	icmp_rtime	icmp_dun.id_ts.its_rtime

#define	icmp_ttime	icmp_dun.id_ts.its_ttime

#define	icmp_ip		icmp_dun.id_ip.idi_ip

#define	icmp_radv	icmp_dun.id_radv

#define	icmp_mask	icmp_dun.id_mask

#define	icmp_data	icmp_dun.id_data

};





struct ip_and_icmp

{

struct  ip iph;

struct  icmp icmph;

};



/* 公共信息 */ 

char dstip[]="202.115.57.24"; 	/* 目标IP */

int	errno;

int	sends,waits;				/* 发送的socket 接收用的socket */

char info[500]; 				/* 收到的icmp信息 */

struct icmp *eicmp; 			/* TTL超时的icmp信息 */

struct ip_and_icmp *ip_icmp;		/* 收到的icmp原始信息 */

struct sockaddr_in toaddr,from;  	/* 目标地址  来信息地址 */



unsigned short csum (unsigned short *packet, int packlen)  /* 校验和计算 */

{

	register unsigned long sum = 0;



	while (packlen > 1) {

		sum+= *(packet++);

		packlen-=2;

	}



	if (packlen > 0)

		sum += *(unsigned char *)packet;



	/* 这些将取决于位顺序 */

	while (sum >> 16)

		sum = (sum & 0xffff) + (sum >> 16);



	return (unsigned short) ~sum;

}



long int send_echo(struct sockaddr_in toaddr,int id,int sq,int size,int ttlset)

/* 发送icmp ECHO信息可定目标IP,ID号,SQ号和 IP的TTL大小, */

/* 出现返回-1,否则返回发送时的时间 */

void sendicmp()

{

 int lenth;

 long int nowtime;

 char icmpbuffer[200];

 struct  icmp  *icmph;

 memset(icmpbuffer,'a', 200);

 icmph=(struct  icmp *)icmpbuffer;

 sen=socket(AF_INET,SOCK_RAW,1);

 inet_aton(toip,&toaddr.sin_addr);   /* 字符串转入地址 */

 toaddr.sin_family = AF_INET; 

 icmph->type=8;

 icmph->code=0;

 icmph->un.echo.id=htons(id);

 icmph->un.echo.sequence=htons(sq);

 icmph->checksum=htons(0);

 icmph->checksum=csum((unsigned short *)icmpbuffer,8+size);

 /* 发送的没有IP头信息 */

 setsockopt(sends, IPPROTO_IP, IP_TTL, &ttlset, sizeof(ttlset));  /* 设定TTL的大小 */

 lenth=sendto(sends,icmpbuffer,8+size,0,(struct sockaddr *)&toaddr,sizeof(toaddr));

 if (lenth>0)

 {

  	nowtime=clock();

printf("send ICMO size %d at clock %d to %s  id=%d sq=%d  \n",

size,nowtime,inet_ntoa(toaddr.sin_addr),id,sq);

  }

  else

  {

  	return -1;

  }

 return nowtime;

}



/* 等对应的ICMP REPLY信息 指定IP,ID,SQ和等待时间。*/

/* 出现ttl超时或收到返回接收到时的时间,否则为-1 */

int wait_icmp(struct sockaddr_in toaddr,int id,int sq,clock_t timesize)

{

int length,fromlength;

clock_t endclock,recvclock;

inet_aton(toip,&toaddr.sin_addr);

memset(info,'A',500);

endclock=clock()+timesize;

while(clock()<endclock)

     {

fromlength=sizeof(from);

		length=recvfrom(waits,info,sizeof(info),0,

(struct sockaddr *)&from,&fromlength);

   	   

	   if ( length>0 && (from.sin_addr.s_addr==toaddr.sin_addr.s_addr) 

&& (ip_icmp->icmph.type==0) )

   	   { 

recvclock=clock();

if ((ntohs(ip_icmp->icmph.un.echo.id)==id) 

&& (ntohs(ip_icmp->icmph.un.echo.sequence)==sq) )

		  	{

viewinfo(info,length);

		  	return recvclock;

          	}

		} /* end length>0

		if (length>0 && (ip_icmp->icmph.type==11)&&(ntohs(eicmp->icmp_id)==id) 

&& (ntohs(eicmp->icmp_seq)==sq) )   /* 11为ttl超时 */

		{

recvclock=clock();

   	 		return recvclock;

		}

    } /* end while */



return -1;  /* 超时 */

}



int main(int argc, char *argv[])

{

int rec,fromlen,n,sq,id,mstime,on=1,route=1,timeout=0,ttl;

long int iplong;

struct protoent *proto;

struct hostent *hp,*fromname; 

clock_t start,sendtime,waittime;

start = clock();

ip_icmp=(struct ip_and_icmp *)info;

eicmp=(struct icmp *)(&ip_icmp->icmph.icmp_ip+1);

id=999;

mstime=2000;

if (argc<2)

{

printf("usage: %s ip_addrs time-out(millisecond)  \n",argv[0]);

printf("       %s testping 192.168.11.38 1000  \n",argv[0]);

printf("or     %s testping 192.168.11.38   \n",argv[0]);

return 0;

}

if (argc>2)

{

mstime=atoi(argv[2]);

if (mstime<1)

    		{

printf("time-out(millisecond) is error \n");

exit (0);

}

printf("timo-out %d ms \n",mstime);

}

if ((hp = gethostbyname(argv[1])) == NULL)    /* 进入名字的分析 */

{

if ( (toaddr.sin_addr.s_addr=inet_addr(argv[1])) == -1) 

{ 

	    		fprintf(stderr, "%s: unknown host\n", argv[1]);

exit (0);

		}

		if (htonl(toaddr.sin_addr.s_addr)<0x1000001)

        	{

         		printf("error ip %s \n",inet_ntoa(toaddr.sin_addr));

         		exit (0);

        	}

     } 

else 

{

bcopy(hp->h_addr_list[0], &toaddr.sin_addr.s_addr, hp->h_length);

} 

icmph=(struct  icmphdr *)icmpbuffer;

/* 初化接收和发送用的sends */

sends=socket(AF_INET,SOCK_RAW,1);

if(setsockopt(sends, IPPROTO_IP, IP_TTL, &on, sizeof(on)) < 0)

{

perror("This is sytem can't set TTL \n"); 

exit(1); 

     }

waits=socket(AF_INET,SOCK_RAW,1);

fcntl(waits,F_SETFL,O_NDELAY); 

proto = getprotobyname("icmp");  

rec=socket(AF_INET,SOCK_RAW, proto->p_proto);

fcntl(rec,F_SETFL,O_NDELAY); 

printf("%s \n",sys_errlist[errno]);

if (rec<0)

{

exit(0);

}

printf("now to wait... at %d \n",start);

/* waiting for packets */

inet_aton(dstip,&toaddr.sin_addr);

printf("send ICMO  to %s  \n",inet_ntoa(toaddr.sin_addr));

   	id=999;  		/* 初始化ID */

sq=0;   		/* 初始化sq */

timeout=0;  	/* time out次数 */

ttl=1;    /* ttl 值 */

while (1)

{

sq++;

sendtime=send_echo(toaddr,id,sq*100,20,ttl);	/* 发送ICMP ECHO */

/* 目标IP  编号  长度 ttl */

if (sendtime==-1)

{

printf("end error \n");

exit (0);

}

waittime=wait_icmp(toaddr,id,sq*100,mstime*1000); /* 接收ICMP ECHO */



if (waittime==-1)

{

if (timeout==4)  /* 连续4次time out退出 */

{

printf("time out >3 end \n");

exit (1);

}

printf("time out \n");

timeout++;

}

     else 

{

if (ip_icmp->icmph.type==0)

{

printf("%02d ",route);

printf(" %04d ms ",(waittime-sendtime)/1000);

printf("  %s ",inet_ntoa(ip_icmp->iph.ip_src));

printf("\n");

printf("\n");

printf("Trace complete \n");

break;

}

if (ip_icmp->icmph.type==11)

{

timeout=0;

ttl++;   			/* 接收到一个ttl超时信息TTL值加1 */

printf("%02d ",route);

printf(" %04d ms ",(waittime-sendtime)/1000);

printf("  %s ",inet_ntoa(ip_icmp->iph.ip_src));

printf("\n");

route++;

}

} /* end else waittime==-1 */

} /* end for */

}

⌨️ 快捷键说明

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