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