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