1313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/*
2313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * tracepath.c
3313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *
4313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *		This program is free software; you can redistribute it and/or
5313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *		modify it under the terms of the GNU General Public License
6313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *		as published by the Free Software Foundation; either version
7313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *		2 of the License, or (at your option) any later version.
8313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *
9313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */
11313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
12313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <stdio.h>
13313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <stdlib.h>
14313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <unistd.h>
15313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <sys/socket.h>
16313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <linux/types.h>
17313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <linux/errqueue.h>
18313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <errno.h>
19313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <string.h>
20313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <netdb.h>
21313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <netinet/in.h>
22313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <resolv.h>
23313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <sys/time.h>
24313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <sys/uio.h>
25313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <arpa/inet.h>
26313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifdef USE_IDN
27313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <idna.h>
28313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <locale.h>
29313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
30313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
31313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifndef IP_PMTUDISC_PROBE
32313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#define IP_PMTUDISC_PROBE	3
33313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
34313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
35313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#define MAX_HOPS_LIMIT		255
36313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#define MAX_HOPS_DEFAULT	30
37313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
38313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistruct hhistory
39313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
40313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int	hops;
41313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct timeval sendtime;
42313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti};
43313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
44313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistruct hhistory his[64];
45313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint hisptr;
46313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
47313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistruct sockaddr_in target;
48313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti__u16 base_port;
49313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint max_hops = MAX_HOPS_DEFAULT;
50313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
51313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitticonst int overhead = 28;
52313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint mtu = 65535;
53313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid *pktbuf;
54313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint hops_to = -1;
55313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint hops_from = -1;
56313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint no_resolve = 0;
57313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint show_both = 0;
58313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
59313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#define HOST_COLUMN_SIZE	52
60313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
61313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistruct probehdr
62313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
63313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	__u32 ttl;
64313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct timeval tv;
65313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti};
66313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
67313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid data_wait(int fd)
68313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
69313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	fd_set fds;
70313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct timeval tv;
71313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	FD_ZERO(&fds);
72313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	FD_SET(fd, &fds);
73313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	tv.tv_sec = 1;
74313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	tv.tv_usec = 0;
75313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	select(fd+1, &fds, NULL, NULL, &tv);
76313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
77313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
78313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid print_host(const char *a, const char *b, int both)
79313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
80313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int plen;
81313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	plen = printf("%s", a);
82313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (both)
83313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		plen += printf(" (%s)", b);
84313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (plen >= HOST_COLUMN_SIZE)
85313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		plen = HOST_COLUMN_SIZE - 1;
86313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	printf("%*s", HOST_COLUMN_SIZE - plen, "");
87313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
88313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
89313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint recverr(int fd, int ttl)
90313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
91313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int res;
92313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct probehdr rcvbuf;
93313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	char cbuf[512];
94313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct iovec  iov;
95313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct msghdr msg;
96313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct cmsghdr *cmsg;
97313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct sock_extended_err *e;
98313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct sockaddr_in addr;
99313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct timeval tv;
100313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct timeval *rettv;
101313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int slot;
102313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int rethops;
103313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int sndhops;
104313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int progress = -1;
105313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int broken_router;
106313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
107313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittirestart:
108313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	memset(&rcvbuf, -1, sizeof(rcvbuf));
109313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	iov.iov_base = &rcvbuf;
110313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	iov.iov_len = sizeof(rcvbuf);
111313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	msg.msg_name = (__u8*)&addr;
112313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	msg.msg_namelen = sizeof(addr);
113313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	msg.msg_iov = &iov;
114313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	msg.msg_iovlen = 1;
115313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	msg.msg_flags = 0;
116313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	msg.msg_control = cbuf;
117313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	msg.msg_controllen = sizeof(cbuf);
118313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
119313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	gettimeofday(&tv, NULL);
120313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	res = recvmsg(fd, &msg, MSG_ERRQUEUE);
121313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (res < 0) {
122313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (errno == EAGAIN)
123313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			return progress;
124313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		goto restart;
125313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
126313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
127313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	progress = mtu;
128313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
129313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	rethops = -1;
130313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	sndhops = -1;
131313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	e = NULL;
132313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	rettv = NULL;
133313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	slot = ntohs(addr.sin_port) - base_port;
134313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (slot>=0 && slot < 63 && his[slot].hops) {
135313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		sndhops = his[slot].hops;
136313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		rettv = &his[slot].sendtime;
137313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		his[slot].hops = 0;
138313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
139313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	broken_router = 0;
140313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (res == sizeof(rcvbuf)) {
141313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (rcvbuf.ttl == 0 || rcvbuf.tv.tv_sec == 0) {
142313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			broken_router = 1;
143313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		} else {
144313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			sndhops = rcvbuf.ttl;
145313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			rettv = &rcvbuf.tv;
146313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
147313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
148313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
149313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
150313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (cmsg->cmsg_level == SOL_IP) {
151313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (cmsg->cmsg_type == IP_RECVERR) {
152313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				e = (struct sock_extended_err *) CMSG_DATA(cmsg);
153313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			} else if (cmsg->cmsg_type == IP_TTL) {
154313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				memcpy(&rethops, CMSG_DATA(cmsg), sizeof(rethops));
155313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			} else {
156313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				printf("cmsg:%d\n ", cmsg->cmsg_type);
157313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
158313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
159313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
160313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (e == NULL) {
161313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("no info\n");
162313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		return 0;
163313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
164313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (e->ee_origin == SO_EE_ORIGIN_LOCAL) {
165313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("%2d?: %*s ", ttl, -(HOST_COLUMN_SIZE - 1), "[LOCALHOST]");
166313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	} else if (e->ee_origin == SO_EE_ORIGIN_ICMP) {
167313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		char abuf[128];
168313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		struct sockaddr_in *sin = (struct sockaddr_in*)(e+1);
169313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		struct hostent *h = NULL;
170313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		char *idn = NULL;
171313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
172313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		inet_ntop(AF_INET, &sin->sin_addr, abuf, sizeof(abuf));
173313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
174313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (sndhops>0)
175313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("%2d:  ", sndhops);
176313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		else
177313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("%2d?: ", ttl);
178313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
179313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (!no_resolve || show_both) {
180313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			fflush(stdout);
181313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			h = gethostbyaddr((char *) &sin->sin_addr, sizeof(sin->sin_addr), AF_INET);
182313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
183313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
184313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifdef USE_IDN
185313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (h && idna_to_unicode_lzlz(h->h_name, &idn, 0) != IDNA_SUCCESS)
186313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			idn = NULL;
187313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
188313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (no_resolve)
189313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			print_host(abuf, h ? (idn ? idn : h->h_name) : abuf, show_both);
190313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		else
191313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			print_host(h ? (idn ? idn : h->h_name) : abuf, abuf, show_both);
192313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
193313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifdef USE_IDN
194313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		free(idn);
195313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
196313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
197313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
198313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (rettv) {
199313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		int diff = (tv.tv_sec-rettv->tv_sec)*1000000+(tv.tv_usec-rettv->tv_usec);
200313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("%3d.%03dms ", diff/1000, diff%1000);
201313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (broken_router)
202313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("(This broken router returned corrupted payload) ");
203313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
204313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
205313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	switch (e->ee_errno) {
206313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case ETIMEDOUT:
207313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("\n");
208313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		break;
209313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case EMSGSIZE:
210313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("pmtu %d\n", e->ee_info);
211313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		mtu = e->ee_info;
212313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		progress = mtu;
213313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		break;
214313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case ECONNREFUSED:
215313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("reached\n");
216313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		hops_to = sndhops<0 ? ttl : sndhops;
217313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		hops_from = rethops;
218313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		return 0;
219313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case EPROTO:
220313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("!P\n");
221313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		return 0;
222313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case EHOSTUNREACH:
223313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (e->ee_origin == SO_EE_ORIGIN_ICMP &&
224313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		    e->ee_type == 11 &&
225313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		    e->ee_code == 0) {
226313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (rethops>=0) {
227313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (rethops<=64)
228313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					rethops = 65-rethops;
229313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				else if (rethops<=128)
230313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					rethops = 129-rethops;
231313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				else
232313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					rethops = 256-rethops;
233313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (sndhops>=0 && rethops != sndhops)
234313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					printf("asymm %2d ", rethops);
235313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				else if (sndhops<0 && rethops != ttl)
236313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					printf("asymm %2d ", rethops);
237313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
238313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("\n");
239313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
240313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
241313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("!H\n");
242313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		return 0;
243313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case ENETUNREACH:
244313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("!N\n");
245313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		return 0;
246313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case EACCES:
247313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("!A\n");
248313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		return 0;
249313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	default:
250313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("\n");
251313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		errno = e->ee_errno;
252313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		perror("NET ERROR");
253313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		return 0;
254313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
255313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	goto restart;
256313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
257313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
258313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint probe_ttl(int fd, int ttl)
259313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
260313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int i;
261313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct probehdr *hdr = pktbuf;
262313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
263313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	memset(pktbuf, 0, mtu);
264313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittirestart:
265313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	for (i=0; i<10; i++) {
266313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		int res;
267313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
268313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		hdr->ttl = ttl;
269313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		target.sin_port = htons(base_port + hisptr);
270313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		gettimeofday(&hdr->tv, NULL);
271313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		his[hisptr].hops = ttl;
272313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		his[hisptr].sendtime = hdr->tv;
273313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (sendto(fd, pktbuf, mtu-overhead, 0, (struct sockaddr*)&target, sizeof(target)) > 0)
274313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
275313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		res = recverr(fd, ttl);
276313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		his[hisptr].hops = 0;
277313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (res==0)
278313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			return 0;
279313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (res > 0)
280313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			goto restart;
281313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
282313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	hisptr = (hisptr + 1)&63;
283313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
284313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (i<10) {
285313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		data_wait(fd);
286313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (recv(fd, pktbuf, mtu, MSG_DONTWAIT) > 0) {
287313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("%2d?: reply received 8)\n", ttl);
288313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			return 0;
289313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
290313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		return recverr(fd, ttl);
291313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
292313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
293313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	printf("%2d:  send failed\n", ttl);
294313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	return 0;
295313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
296313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
297313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistatic void usage(void) __attribute((noreturn));
298313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
299313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistatic void usage(void)
300313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
301313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	fprintf(stderr, "Usage: tracepath [-n] [-b] [-l <len>] [-p port] <destination>\n");
302313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	exit(-1);
303313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
304313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
305313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint
306313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittimain(int argc, char **argv)
307313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
308313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct hostent *he;
309313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int fd;
310313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int on;
311313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int ttl;
312313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	char *p;
313313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int ch;
314313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifdef USE_IDN
315313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int rc;
316313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	setlocale(LC_ALL, "");
317313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
318313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
319313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	while ((ch = getopt(argc, argv, "nbh?l:m:p:")) != EOF) {
320313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		switch(ch) {
321313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case 'n':
322313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			no_resolve = 1;
323313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
324313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case 'b':
325313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			show_both = 1;
326313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
327313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case 'l':
328313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if ((mtu = atoi(optarg)) <= overhead) {
329313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				fprintf(stderr, "Error: pktlen must be > %d and <= %d.\n",
330313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					overhead, INT_MAX);
331313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				exit(1);
332313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
333313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
334313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case 'm':
335313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			max_hops = atoi(optarg);
336313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (max_hops < 0 || max_hops > MAX_HOPS_LIMIT) {
337313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				fprintf(stderr,
338313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					"Error: max hops must be 0 .. %d (inclusive).\n",
339313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					MAX_HOPS_LIMIT);
340313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
341313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
342313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case 'p':
343313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			base_port = atoi(optarg);
344313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
345313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		default:
346313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			usage();
347313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
348313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
349313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
350313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	argc -= optind;
351313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	argv += optind;
352313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
353313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (argc != 1)
354313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		usage();
355313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
356313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	fd = socket(AF_INET, SOCK_DGRAM, 0);
357313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (fd < 0) {
358313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		perror("socket");
359313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		exit(1);
360313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
361313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	target.sin_family = AF_INET;
362313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
363313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	/* Backward compatiblity */
364313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (!base_port) {
365313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		p = strchr(argv[0], '/');
366313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (p) {
367313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			*p = 0;
368313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			base_port = atoi(p+1);
369313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		} else
370313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			base_port = 44444;
371313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
372313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
373313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	p = argv[0];
374313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifdef USE_IDN
375313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	rc = idna_to_ascii_lz(argv[0], &p, 0);
376313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (rc != IDNA_SUCCESS) {
377313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		fprintf(stderr, "IDNA encoding failed: %s\n", idna_strerror(rc));
378313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		exit(2);
379313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
380313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
381313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
382313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	he = gethostbyname(p);
383313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (he == NULL) {
384313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		herror("gethostbyname");
385313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		exit(1);
386313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
387313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
388313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifdef USE_IDN
389313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	free(p);
390313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
391313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
392313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	memcpy(&target.sin_addr, he->h_addr, 4);
393313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
394313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	on = IP_PMTUDISC_PROBE;
395313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &on, sizeof(on)) &&
396313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	    (on = IP_PMTUDISC_DO,
397313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	     setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &on, sizeof(on)))) {
398313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		perror("IP_MTU_DISCOVER");
399313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		exit(1);
400313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
401313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	on = 1;
402313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (setsockopt(fd, SOL_IP, IP_RECVERR, &on, sizeof(on))) {
403313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		perror("IP_RECVERR");
404313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		exit(1);
405313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
406313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (setsockopt(fd, SOL_IP, IP_RECVTTL, &on, sizeof(on))) {
407313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		perror("IP_RECVTTL");
408313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		exit(1);
409313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
410313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
411313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	pktbuf = malloc(mtu);
412313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (!pktbuf) {
413313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		perror("malloc");
414313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		exit(1);
415313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
416313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
417313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	for (ttl = 1; ttl <= max_hops; ttl++) {
418313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		int res;
419313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		int i;
420313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
421313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		on = ttl;
422313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (setsockopt(fd, SOL_IP, IP_TTL, &on, sizeof(on))) {
423313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			perror("IP_TTL");
424313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			exit(1);
425313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
426313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
427313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittirestart:
428313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		for (i=0; i<3; i++) {
429313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			int old_mtu;
430313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
431313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			old_mtu = mtu;
432313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			res = probe_ttl(fd, ttl);
433313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (mtu != old_mtu)
434313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				goto restart;
435313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (res == 0)
436313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				goto done;
437313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (res > 0)
438313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				break;
439313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
440313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
441313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (res < 0)
442313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("%2d:  no reply\n", ttl);
443313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
444313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	printf("     Too many hops: pmtu %d\n", mtu);
445313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittidone:
446313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	printf("     Resume: pmtu %d ", mtu);
447313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (hops_to>=0)
448313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("hops %d ", hops_to);
449313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (hops_from>=0)
450313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("back %d ", hops_from);
451313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	printf("\n");
452313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	exit(0);
453313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
454