4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
15 #include <sys/socket.h>
16 #include <linux/types.h>
17 #include <linux/errqueue.h>
21 #include <netinet/in.h>
25 #include <arpa/inet.h>
30 struct timeval sendtime;
33 struct hhistory his[64];
36 struct sockaddr_in target;
39 const int overhead = 28;
51 void data_wait(int fd)
59 select(fd+1, &fds, NULL, NULL, &tv);
62 int recverr(int fd, int ttl)
65 struct probehdr rcvbuf;
70 struct sock_extended_err *e;
71 struct sockaddr_in addr;
73 struct timeval *rettv;
81 memset(&rcvbuf, -1, sizeof(rcvbuf));
82 iov.iov_base = &rcvbuf;
83 iov.iov_len = sizeof(rcvbuf);
84 msg.msg_name = (__u8*)&addr;
85 msg.msg_namelen = sizeof(addr);
89 msg.msg_control = cbuf;
90 msg.msg_controllen = sizeof(cbuf);
92 gettimeofday(&tv, NULL);
93 res = recvmsg(fd, &msg, MSG_ERRQUEUE);
106 slot = ntohs(addr.sin_port) - base_port;
107 if (slot>=0 && slot < 63 && his[slot].hops) {
108 sndhops = his[slot].hops;
109 rettv = &his[slot].sendtime;
113 if (res == sizeof(rcvbuf)) {
114 if (rcvbuf.ttl == 0 || rcvbuf.tv.tv_sec == 0) {
117 sndhops = rcvbuf.ttl;
122 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
123 if (cmsg->cmsg_level == SOL_IP) {
124 if (cmsg->cmsg_type == IP_RECVERR) {
125 e = (struct sock_extended_err *) CMSG_DATA(cmsg);
126 } else if (cmsg->cmsg_type == IP_TTL) {
127 rethops = *(int*)CMSG_DATA(cmsg);
129 printf("cmsg:%d\n ", cmsg->cmsg_type);
137 if (e->ee_origin == SO_EE_ORIGIN_LOCAL) {
138 printf("%2d?: %-15s ", ttl, "[LOCALHOST]");
139 } else if (e->ee_origin == SO_EE_ORIGIN_ICMP) {
141 struct sockaddr_in *sin = (struct sockaddr_in*)(e+1);
143 inet_ntop(AF_INET, &sin->sin_addr, abuf, sizeof(abuf));
146 printf("%2d: ", sndhops);
148 printf("%2d?: ", ttl);
154 h = gethostbyaddr((char *) &sin->sin_addr, sizeof(sin->sin_addr), AF_INET);
155 snprintf(fabuf, sizeof(fabuf), "%s (%s)", h ? h->h_name : abuf, abuf);
156 printf("%-52s ", fabuf);
158 printf("%-15s ", abuf);
164 rethops = 65-rethops;
165 else if (rethops<=128)
166 rethops = 129-rethops;
168 rethops = 256-rethops;
169 if (sndhops>=0 && rethops != sndhops)
170 printf("asymm %2d ", rethops);
171 else if (sndhops<0 && rethops != ttl)
172 printf("asymm %2d ", rethops);
176 int diff = (tv.tv_sec-rettv->tv_sec)*1000000+(tv.tv_usec-rettv->tv_usec);
177 printf("%3d.%03dms ", diff/1000, diff%1000);
179 printf("(This broken router returned corrupted payload) ");
182 switch (e->ee_errno) {
187 printf("pmtu %d\n", e->ee_info);
193 hops_to = sndhops<0 ? ttl : sndhops;
200 if (e->ee_origin == SO_EE_ORIGIN_ICMP &&
223 int probe_ttl(int fd, int ttl)
227 struct probehdr *hdr = (struct probehdr*)sndbuf;
229 memset(sndbuf,0,mtu);
232 for (i=0; i<10; i++) {
236 target.sin_port = htons(base_port + hisptr);
237 gettimeofday(&hdr->tv, NULL);
238 his[hisptr].hops = ttl;
239 his[hisptr].sendtime = hdr->tv;
240 if (sendto(fd, sndbuf, mtu-overhead, 0, (struct sockaddr*)&target, sizeof(target)) > 0)
242 res = recverr(fd, ttl);
243 his[hisptr].hops = 0;
249 hisptr = (hisptr + 1)&63;
253 if (recv(fd, sndbuf, sizeof(sndbuf), MSG_DONTWAIT) > 0) {
254 printf("%2d?: reply received 8)\n", ttl);
257 return recverr(fd, ttl);
260 printf("%2d: send failed\n", ttl);
264 static void usage(void) __attribute((noreturn));
266 static void usage(void)
268 fprintf(stderr, "Usage: tracepath [-n] <destination>[/<port>]\n");
273 main(int argc, char **argv)
282 while ((ch = getopt(argc, argv, "nh?")) != EOF) {
299 fd = socket(AF_INET, SOCK_DGRAM, 0);
304 target.sin_family = AF_INET;
306 p = strchr(argv[0], '/');
309 base_port = atoi(p+1);
312 he = gethostbyname(argv[0]);
314 herror("gethostbyname");
317 memcpy(&target.sin_addr, he->h_addr, 4);
320 if (setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &on, sizeof(on))) {
321 perror("IP_MTU_DISCOVER");
325 if (setsockopt(fd, SOL_IP, IP_RECVERR, &on, sizeof(on))) {
326 perror("IP_RECVERR");
329 if (setsockopt(fd, SOL_IP, IP_RECVTTL, &on, sizeof(on))) {
330 perror("IP_RECVTTL");
334 for (ttl=1; ttl<32; ttl++) {
339 if (setsockopt(fd, SOL_IP, IP_TTL, &on, sizeof(on))) {
344 for (i=0; i<3; i++) {
345 res = probe_ttl(fd, ttl);
353 printf("%2d: no reply\n", ttl);
355 printf(" Too many hops: pmtu %d\n", mtu);
357 printf(" Resume: pmtu %d ", mtu);
359 printf("hops %d ", hops_to);
361 printf("back %d ", hops_from);