PageRenderTime 30ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/traceroute-2.0.18/traceroute/traceroute.c

#
C | 1556 lines | 1076 code | 403 blank | 77 comment | 328 complexity | 7f606b86260d842b98684696d138c0a7 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. /*
  2. Copyright (c) 2006, 2007 Dmitry Butskoy
  3. <buc@citadel.stu.neva.ru>
  4. License: GPL v2 or any later
  5. See COPYING for the status of this software.
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <stdarg.h>
  10. #include <unistd.h>
  11. #include <fcntl.h>
  12. #include <sys/socket.h>
  13. #include <sys/poll.h>
  14. #include <netinet/icmp6.h>
  15. #include <netinet/ip_icmp.h>
  16. #include <netinet/in.h>
  17. #include <netinet/ip6.h>
  18. #include <netdb.h>
  19. #include <errno.h>
  20. #include <locale.h>
  21. #include <sys/utsname.h>
  22. #include <linux/types.h>
  23. #include <linux/errqueue.h>
  24. /* XXX: Remove this when things will be defined properly in netinet/ ... */
  25. #include "flowlabel.h"
  26. #include <clif.h>
  27. #include "version.h"
  28. #include "traceroute.h"
  29. #ifndef ICMP6_DST_UNREACH_BEYONDSCOPE
  30. #ifdef ICMP6_DST_UNREACH_NOTNEIGHBOR
  31. #define ICMP6_DST_UNREACH_BEYONDSCOPE ICMP6_DST_UNREACH_NOTNEIGHBOR
  32. #else
  33. #define ICMP6_DST_UNREACH_BEYONDSCOPE 2
  34. #endif
  35. #endif
  36. #ifndef IPV6_RECVHOPLIMIT
  37. #define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
  38. #endif
  39. #ifndef IP_PMTUDISC_PROBE
  40. #define IP_PMTUDISC_PROBE 3
  41. #endif
  42. #ifndef IPV6_PMTUDISC_PROBE
  43. #define IPV6_PMTUDISC_PROBE 3
  44. #endif
  45. #define MAX_HOPS 255
  46. #define MAX_PROBES 10
  47. #define MAX_GATEWAYS_4 8
  48. #define MAX_GATEWAYS_6 127
  49. #define DEF_HOPS 30
  50. #define DEF_SIM_PROBES 16 /* including several hops */
  51. #define DEF_NUM_PROBES 3
  52. #define DEF_WAIT_SECS 5.0
  53. #define DEF_SEND_SECS 0
  54. #define DEF_DATA_LEN 40 /* all but IP header... */
  55. #define MAX_PACKET_LEN 65000
  56. #ifndef DEF_AF
  57. #define DEF_AF AF_INET
  58. #endif
  59. #define ttl2hops(X) (((X) <= 64 ? 65 : ((X) <= 128 ? 129 : 256)) - (X))
  60. static char version_string[] = "Modern traceroute for Linux, "
  61. "version " _TEXT(VERSION) ", " __DATE__
  62. "\nCopyright (c) 2008 Dmitry Butskoy, "
  63. " License: GPL v2 or any later";
  64. static int debug = 0;
  65. static unsigned int first_hop = 1;
  66. static unsigned int max_hops = DEF_HOPS;
  67. static unsigned int sim_probes = DEF_SIM_PROBES;
  68. static unsigned int probes_per_hop = DEF_NUM_PROBES;
  69. static char **gateways = NULL;
  70. static int num_gateways = 0;
  71. static unsigned char *rtbuf = NULL;
  72. static size_t rtbuf_len = 0;
  73. static unsigned int ipv6_rthdr_type = 2; /* IPV6_RTHDR_TYPE_2 */
  74. static size_t header_len = 0;
  75. static size_t data_len = 0;
  76. static int dontfrag = 0;
  77. static int noresolve = 0;
  78. static int extension = 0;
  79. static int as_lookups = 0;
  80. static unsigned int dst_port_seq = 0;
  81. static unsigned int tos = 0;
  82. static unsigned int flow_label = 0;
  83. static int noroute = 0;
  84. static unsigned int fwmark = 0;
  85. static int packet_len = -1;
  86. static double wait_secs = DEF_WAIT_SECS;
  87. static double send_secs = DEF_SEND_SECS;
  88. static int mtudisc = 0;
  89. static int backward = 0;
  90. static sockaddr_any dst_addr = {{ 0, }, };
  91. static char *dst_name = NULL;
  92. static char *device = NULL;
  93. static sockaddr_any src_addr = {{ 0, }, };
  94. static unsigned int src_port = 0;
  95. static const char *module = "default";
  96. static const tr_module *ops = NULL;
  97. static char *opts[16] = { NULL, }; /* assume enough */
  98. static unsigned int opts_idx = 1; /* first one reserved... */
  99. static int af = 0;
  100. static probe *probes = NULL;
  101. static unsigned int num_probes = 0;
  102. static void ex_error (const char *format, ...) {
  103. va_list ap;
  104. va_start (ap, format);
  105. vfprintf (stderr, format, ap);
  106. va_end (ap);
  107. fprintf (stderr, "\n");
  108. exit (2);
  109. }
  110. void error (const char *str) {
  111. fprintf (stderr, "\n");
  112. perror (str);
  113. exit (1);
  114. }
  115. void error_or_perm (const char *str) {
  116. if (errno == EPERM)
  117. fprintf (stderr, "You have no enough privileges to use "
  118. "this traceroute method.");
  119. error (str);
  120. }
  121. /* Set initial parameters according to how we was called */
  122. static void check_progname (const char *name) {
  123. const char *p;
  124. int l;
  125. p = strrchr (name, '/');
  126. if (p) p++;
  127. else p = name;
  128. l = strlen (p);
  129. if (l <= 0) return;
  130. l--;
  131. if (p[l] == '6') af = AF_INET6;
  132. else if (p[l] == '4') af = AF_INET;
  133. if (!strncmp (p, "tcp", 3))
  134. module = "tcp";
  135. if (!strncmp (p, "tracert", 7))
  136. module = "icmp";
  137. return;
  138. }
  139. static int getaddr (const char *name, sockaddr_any *addr) {
  140. int ret;
  141. struct addrinfo hints, *ai, *res = NULL;
  142. memset (&hints, 0, sizeof (hints));
  143. hints.ai_family = af;
  144. hints.ai_flags = AI_IDN;
  145. ret = getaddrinfo (name, NULL, &hints, &res);
  146. if (ret) {
  147. fprintf (stderr, "%s: %s\n", name, gai_strerror (ret));
  148. return -1;
  149. }
  150. for (ai = res; ai; ai = ai->ai_next) {
  151. if (ai->ai_family == af) break;
  152. /* when af not specified, choose DEF_AF if present */
  153. if (!af && ai->ai_family == DEF_AF)
  154. break;
  155. }
  156. if (!ai) ai = res; /* anything... */
  157. if (ai->ai_addrlen > sizeof (*addr))
  158. return -1; /* paranoia */
  159. memcpy (addr, ai->ai_addr, ai->ai_addrlen);
  160. freeaddrinfo (res);
  161. return 0;
  162. }
  163. static void make_fd_used (int fd) {
  164. int nfd;
  165. if (fcntl (fd, F_GETFL) != -1)
  166. return;
  167. if (errno != EBADF)
  168. error ("fcntl F_GETFL");
  169. nfd = open ("/dev/null", O_RDONLY);
  170. if (nfd < 0) error ("open /dev/null");
  171. if (nfd != fd) {
  172. dup2 (nfd, fd);
  173. close (nfd);
  174. }
  175. return;
  176. }
  177. static char addr2str_buf[INET6_ADDRSTRLEN];
  178. static const char *addr2str (const sockaddr_any *addr) {
  179. getnameinfo (&addr->sa, sizeof (*addr),
  180. addr2str_buf, sizeof (addr2str_buf), 0, 0, NI_NUMERICHOST);
  181. return addr2str_buf;
  182. }
  183. /* IP options stuff */
  184. static void init_ip_options (void) {
  185. sockaddr_any *gates;
  186. int i, max;
  187. if (!num_gateways)
  188. return;
  189. /* check for TYPE,ADDR,ADDR... form */
  190. if (af == AF_INET6 && num_gateways > 1 && gateways[0]) {
  191. char *q;
  192. unsigned int value = strtoul (gateways[0], &q, 0);
  193. if (!*q) {
  194. ipv6_rthdr_type = value;
  195. num_gateways--;
  196. for (i = 0; i < num_gateways; i++)
  197. gateways[i] = gateways[i + 1];
  198. }
  199. }
  200. max = af == AF_INET ? MAX_GATEWAYS_4 : MAX_GATEWAYS_6;
  201. if (num_gateways > max)
  202. ex_error ("Too many gateways specified. No more than %d", max);
  203. gates = alloca (num_gateways * sizeof (*gates));
  204. for (i = 0; i < num_gateways; i++) {
  205. if (!gateways[i]) error ("strdup");
  206. if (getaddr (gateways[i], &gates[i]) < 0)
  207. ex_error (""); /* already reported */
  208. if (gates[i].sa.sa_family != af)
  209. ex_error ("IP versions mismatch in gateway addresses");
  210. free (gateways[i]);
  211. }
  212. free (gateways);
  213. gateways = NULL;
  214. if (af == AF_INET) {
  215. struct in_addr *in;
  216. rtbuf_len = 4 + (num_gateways + 1) * sizeof (*in);
  217. rtbuf = malloc (rtbuf_len);
  218. if (!rtbuf) error ("malloc");
  219. in = (struct in_addr *) &rtbuf[4];
  220. for (i = 0; i < num_gateways; i++)
  221. memcpy (&in[i], &gates[i].sin.sin_addr, sizeof (*in));
  222. /* final hop */
  223. memcpy (&in[i], &dst_addr.sin.sin_addr, sizeof (*in));
  224. i++;
  225. rtbuf[0] = IPOPT_NOP;
  226. rtbuf[1] = IPOPT_LSRR;
  227. rtbuf[2] = (i * sizeof (*in)) + 3;
  228. rtbuf[3] = IPOPT_MINOFF;
  229. }
  230. else if (af == AF_INET6) {
  231. struct in6_addr *in6;
  232. struct ip6_rthdr *rth;
  233. /* IPV6_RTHDR_TYPE_0 length is 8 */
  234. rtbuf_len = 8 + num_gateways * sizeof (*in6);
  235. rtbuf = malloc (rtbuf_len);
  236. if (!rtbuf) error ("malloc");
  237. rth = (struct ip6_rthdr *) rtbuf;
  238. rth->ip6r_nxt = 0;
  239. rth->ip6r_len = 2 * num_gateways;
  240. rth->ip6r_type = ipv6_rthdr_type;
  241. rth->ip6r_segleft = num_gateways;
  242. *((u_int32_t *) (rth + 1)) = 0;
  243. in6 = (struct in6_addr *) (rtbuf + 8);
  244. for (i = 0; i < num_gateways; i++)
  245. memcpy (&in6[i], &gates[i].sin6.sin6_addr, sizeof (*in6));
  246. }
  247. return;
  248. }
  249. /* Command line stuff */
  250. static int set_af (CLIF_option *optn, char *arg) {
  251. int vers = (int) optn->data;
  252. if (vers == 4) af = AF_INET;
  253. else if (vers == 6) af = AF_INET6;
  254. else
  255. return -1;
  256. return 0;
  257. }
  258. static int add_gateway (CLIF_option *optn, char *arg) {
  259. if (num_gateways >= MAX_GATEWAYS_6) { /* 127 > 8 ... :) */
  260. fprintf (stderr, "Too many gateways specified.");
  261. return -1;
  262. }
  263. gateways = realloc (gateways, (num_gateways + 1) * sizeof (*gateways));
  264. if (!gateways) error ("malloc");
  265. gateways[num_gateways++] = strdup (arg);
  266. return 0;
  267. }
  268. static int set_source (CLIF_option *optn, char *arg) {
  269. return getaddr (arg, &src_addr);
  270. }
  271. static int set_port (CLIF_option *optn, char *arg) {
  272. unsigned int *up = (unsigned int *) optn->data;
  273. char *q;
  274. *up = strtoul (arg, &q, 0);
  275. if (q == arg) {
  276. struct servent *s = getservbyname (arg, NULL);
  277. if (!s) return -1;
  278. *up = ntohs (s->s_port);
  279. }
  280. return 0;
  281. }
  282. static int set_module (CLIF_option *optn, char *arg) {
  283. module = (char *) optn->data;
  284. return 0;
  285. }
  286. static int set_mod_option (CLIF_option *optn, char *arg) {
  287. if (!strcmp (arg, "help")) {
  288. const tr_module *mod = tr_get_module (module);
  289. if (mod && mod->options) {
  290. /* just to set common keyword flag... */
  291. CLIF_parse (1, &arg, 0, 0, CLIF_KEYWORD);
  292. CLIF_print_options (NULL, mod->options);
  293. } else
  294. fprintf (stderr, "No options for module `%s'\n", module);
  295. exit (0);
  296. }
  297. if (opts_idx >= sizeof (opts) / sizeof (*opts)) {
  298. fprintf (stderr, "Too many module options\n");
  299. return -1;
  300. }
  301. opts[opts_idx] = strdup (arg);
  302. if (!opts[opts_idx]) error ("strdup");
  303. opts_idx++;
  304. return 0;
  305. }
  306. static int set_raw (CLIF_option *optn, char *arg) {
  307. char buf[1024];
  308. module = "raw";
  309. snprintf (buf, sizeof (buf), "protocol=%s", arg);
  310. return set_mod_option (optn, buf);
  311. }
  312. static int set_host (CLIF_argument *argm, char *arg, int index) {
  313. if (getaddr (arg, &dst_addr) < 0)
  314. return -1;
  315. dst_name = arg;
  316. /* i.e., guess it by the addr in cmdline... */
  317. if (!af) af = dst_addr.sa.sa_family;
  318. return 0;
  319. }
  320. static CLIF_option option_list[] = {
  321. { "4", 0, 0, "Use IPv4", set_af, (void *) 4, 0, CLIF_EXTRA },
  322. { "6", 0, 0, "Use IPv6", set_af, (void *) 6, 0, 0 },
  323. { "d", "debug", 0, "Enable socket level debugging",
  324. CLIF_set_flag, &debug, 0, 0 },
  325. { "F", "dont-fragment", 0, "Do not fragment packets",
  326. CLIF_set_flag, &dontfrag, 0, CLIF_ABBREV },
  327. { "f", "first", "first_ttl", "Start from the %s hop (instead from 1)",
  328. CLIF_set_uint, &first_hop, 0, 0 },
  329. { "g", "gateway", "gate", "Route packets through the specified gateway "
  330. "(maximum " _TEXT(MAX_GATEWAYS_4) " for IPv4 and "
  331. _TEXT(MAX_GATEWAYS_6) " for IPv6)",
  332. add_gateway, 0, 0, CLIF_SEVERAL },
  333. { "I", "icmp", 0, "Use ICMP ECHO for tracerouting",
  334. set_module, "icmp", 0, 0 },
  335. { "T", "tcp", 0, "Use TCP SYN for tracerouting (default "
  336. "port is " _TEXT(DEF_TCP_PORT) ")",
  337. set_module, "tcp", 0, 0 },
  338. { "i", "interface", "device", "Specify a network interface "
  339. "to operate with",
  340. CLIF_set_string, &device, 0, 0 },
  341. { "m", "max-hops", "max_ttl", "Set the max number of hops (max TTL "
  342. "to be reached). Default is " _TEXT(DEF_HOPS) ,
  343. CLIF_set_uint, &max_hops, 0, 0 },
  344. { "N", "sim-queries", "squeries", "Set the number of probes "
  345. "to be tried simultaneously (default is "
  346. _TEXT(DEF_SIM_PROBES) ")",
  347. CLIF_set_uint, &sim_probes, 0, 0 },
  348. { "n", 0, 0, "Do not resolve IP addresses to their domain names",
  349. CLIF_set_flag, &noresolve, 0, 0 },
  350. { "p", "port", "port", "Set the destination port to use. "
  351. "It is either initial udp port value for "
  352. "\"default\" method (incremented by each probe, "
  353. "default is " _TEXT(DEF_START_PORT) "), "
  354. "or initial seq for \"icmp\" (incremented as well, "
  355. "default from 1), or some constant destination port"
  356. " for other methods (with default of "
  357. _TEXT(DEF_TCP_PORT) " for \"tcp\", "
  358. _TEXT(DEF_UDP_PORT) " for \"udp\", etc.)",
  359. set_port, &dst_port_seq, 0, 0 },
  360. { "t", "tos", "tos", "Set the TOS (IPv4 type of service) or TC "
  361. "(IPv6 traffic class) value for outgoing packets",
  362. CLIF_set_uint, &tos, 0, 0 },
  363. { "l", "flowlabel", "flow_label", "Use specified %s for IPv6 packets",
  364. CLIF_set_uint, &flow_label, 0, 0 },
  365. { "w", "wait", "waittime", "Set the number of seconds to wait for "
  366. "response to a probe (default is "
  367. _TEXT(DEF_WAIT_SECS) "). Non-integer (float point) "
  368. "values allowed too",
  369. CLIF_set_double, &wait_secs, 0, 0 },
  370. { "q", "queries", "nqueries", "Set the number of probes per each hop. "
  371. "Default is " _TEXT(DEF_NUM_PROBES),
  372. CLIF_set_uint, &probes_per_hop, 0, 0 },
  373. { "r", 0, 0, "Bypass the normal routing and send directly to a host "
  374. "on an attached network",
  375. CLIF_set_flag, &noroute, 0, 0 },
  376. { "s", "source", "src_addr", "Use source %s for outgoing packets",
  377. set_source, 0, 0, 0 },
  378. { "z", "sendwait", "sendwait", "Minimal time interval between probes "
  379. "(default " _TEXT(DEF_SEND_SECS) "). If the value "
  380. "is more than 10, then it specifies a number "
  381. "in milliseconds, else it is a number of seconds "
  382. "(float point values allowed too)",
  383. CLIF_set_double, &send_secs, 0, 0 },
  384. { "e", "extensions", 0, "Show ICMP extensions (if present), "
  385. "including MPLS",
  386. CLIF_set_flag, &extension, 0, CLIF_ABBREV },
  387. { "A", "as-path-lookups", 0, "Perform AS path lookups in routing "
  388. "registries and print results directly after "
  389. "the corresponding addresses",
  390. CLIF_set_flag, &as_lookups, 0, 0 },
  391. { "M", "module", "name", "Use specified module (either builtin or "
  392. "external) for traceroute operations. Most methods "
  393. "have their shortcuts (`-I' means `-M icmp' etc.)",
  394. CLIF_set_string, &module, 0, CLIF_EXTRA },
  395. { "O", "options", "OPTS", "Use module-specific option %s for the "
  396. "traceroute module. Several %s allowed, separated "
  397. "by comma. If %s is \"help\", print info about "
  398. "available options",
  399. set_mod_option, 0, 0, CLIF_SEVERAL | CLIF_EXTRA },
  400. { 0, "sport", "num", "Use source port %s for outgoing packets. "
  401. "Implies `-N 1'",
  402. set_port, &src_port, 0, CLIF_EXTRA },
  403. #ifdef SO_MARK
  404. { 0, "fwmark", "num", "Set firewall mark for outgoing packets",
  405. CLIF_set_uint, &fwmark, 0, 0 },
  406. #endif
  407. { "U", "udp", 0, "Use UDP to particular port for tracerouting "
  408. "(instead of increasing the port per each probe), "
  409. "default port is " _TEXT(DEF_UDP_PORT),
  410. set_module, "udp", 0, CLIF_EXTRA },
  411. { 0, "UL", 0, "Use UDPLITE for tracerouting (default dest port is "
  412. _TEXT(DEF_UDP_PORT) ")",
  413. set_module, "udplite", 0, CLIF_ONEDASH|CLIF_EXTRA },
  414. { "P", "protocol", "prot", "Use raw packet of protocol %s "
  415. "for tracerouting",
  416. set_raw, 0, 0, CLIF_EXTRA },
  417. { 0, "mtu", 0, "Discover MTU along the path being traced. "
  418. "Implies `-F -N 1'",
  419. CLIF_set_flag, &mtudisc, 0, CLIF_EXTRA },
  420. { 0, "back", 0, "Guess the number of hops in the backward path "
  421. "and print if it differs",
  422. CLIF_set_flag, &backward, 0, CLIF_EXTRA },
  423. CLIF_VERSION_OPTION (version_string),
  424. CLIF_HELP_OPTION,
  425. CLIF_END_OPTION
  426. };
  427. static CLIF_argument arg_list[] = {
  428. { "host", "The host to traceroute to",
  429. set_host, 0, CLIF_STRICT },
  430. { "packetlen", "The full packet length (default is the length of "
  431. "an IP header plus " _TEXT(DEF_DATA_LEN) "). Can be "
  432. "ignored or increased to a minimal allowed value",
  433. CLIF_arg_int, &packet_len, 0 },
  434. CLIF_END_ARGUMENT
  435. };
  436. static void do_it (void);
  437. int main (int argc, char *argv[]) {
  438. setlocale (LC_ALL, "");
  439. setlocale (LC_NUMERIC, "C"); /* avoid commas in msec printed */
  440. check_progname (argv[0]);
  441. if (CLIF_parse (argc, argv, option_list, arg_list,
  442. CLIF_MAY_JOIN_ARG | CLIF_HELP_EMPTY) < 0
  443. ) exit (2);
  444. ops = tr_get_module (module);
  445. if (!ops) ex_error ("Unknown traceroute module %s", module);
  446. if (!first_hop || first_hop > max_hops)
  447. ex_error ("first hop out of range");
  448. if (max_hops > MAX_HOPS)
  449. ex_error ("max hops cannot be more than " _TEXT(MAX_HOPS));
  450. if (!probes_per_hop || probes_per_hop > MAX_PROBES)
  451. ex_error ("no more than " _TEXT(MAX_PROBES) " probes per hop");
  452. if (wait_secs < 0)
  453. ex_error ("bad wait seconds `%g' specified", wait_secs);
  454. if (packet_len > MAX_PACKET_LEN)
  455. ex_error ("too big packetlen %d specified", packet_len);
  456. if (src_addr.sa.sa_family && src_addr.sa.sa_family != af)
  457. ex_error ("IP version mismatch in addresses specified");
  458. if (send_secs < 0)
  459. ex_error ("bad sendtime `%g' specified", send_secs);
  460. if (send_secs >= 10) /* it is milliseconds */
  461. send_secs /= 1000;
  462. if (af == AF_INET6 && (tos || flow_label))
  463. dst_addr.sin6.sin6_flowinfo =
  464. htonl (((tos & 0xff) << 20) | (flow_label & 0x000fffff));
  465. if (src_port) {
  466. src_addr.sin.sin_port = htons ((u_int16_t) src_port);
  467. src_addr.sa.sa_family = af;
  468. }
  469. if (src_port || ops->one_per_time)
  470. sim_probes = 1;
  471. /* make sure we don't std{in,out,err} to open sockets */
  472. make_fd_used (0);
  473. make_fd_used (1);
  474. make_fd_used (2);
  475. init_ip_options ();
  476. header_len = (af == AF_INET ? sizeof (struct iphdr)
  477. : sizeof (struct ip6_hdr)) +
  478. rtbuf_len + ops->header_len;
  479. if (mtudisc) {
  480. dontfrag = 1;
  481. sim_probes = 1;
  482. if (packet_len < 0)
  483. packet_len = MAX_PACKET_LEN;
  484. }
  485. if (packet_len < 0) {
  486. if (DEF_DATA_LEN >= ops->header_len)
  487. data_len = DEF_DATA_LEN - ops->header_len;
  488. } else {
  489. if (packet_len >= header_len)
  490. data_len = packet_len - header_len;
  491. }
  492. num_probes = max_hops * probes_per_hop;
  493. probes = calloc (num_probes, sizeof (*probes));
  494. if (!probes) error ("calloc");
  495. if (ops->options && opts_idx > 1) {
  496. opts[0] = strdup (module); /* aka argv[0] ... */
  497. if (CLIF_parse (opts_idx, opts, ops->options, 0, CLIF_KEYWORD) < 0)
  498. exit (2);
  499. }
  500. if (ops->init (&dst_addr, dst_port_seq, &data_len) < 0)
  501. ex_error ("trace method's init failed");
  502. do_it ();
  503. return 0;
  504. }
  505. /* PRINT STUFF */
  506. static void print_header (void) {
  507. /* Note, without ending new-line! */
  508. printf ("traceroute to %s (%s), %u hops max, %zu byte packets",
  509. dst_name, addr2str (&dst_addr), max_hops,
  510. header_len + data_len);
  511. fflush (stdout);
  512. }
  513. static void print_addr (sockaddr_any *res) {
  514. const char *str;
  515. if (!res->sa.sa_family)
  516. return;
  517. str = addr2str (res);
  518. if (noresolve)
  519. printf (" %s", str);
  520. else {
  521. char buf[1024];
  522. buf[0] = '\0';
  523. getnameinfo (&res->sa, sizeof (*res), buf, sizeof (buf),
  524. 0, 0, NI_IDN);
  525. printf (" %s (%s)", buf[0] ? buf : str, str);
  526. }
  527. if (as_lookups)
  528. printf (" [%s]", get_as_path (str));
  529. }
  530. static void print_probe (probe *pb) {
  531. unsigned int idx = (pb - probes);
  532. unsigned int ttl = idx / probes_per_hop + 1;
  533. unsigned int np = idx % probes_per_hop;
  534. if (np == 0)
  535. printf ("\n%2u ", ttl);
  536. if (!pb->res.sa.sa_family)
  537. printf (" *");
  538. else {
  539. int prn = !np; /* print if the first... */
  540. if (np) { /* ...and if differs with previous */
  541. probe *p;
  542. /* skip expired */
  543. for (p = pb - 1; np && !p->res.sa.sa_family; p--, np--) ;
  544. if (!np ||
  545. !equal_addr (&p->res, &pb->res) ||
  546. (p->ext != pb->ext &&
  547. !(p->ext && pb->ext && !strcmp (p->ext, pb->ext))) ||
  548. (backward && p->recv_ttl != pb->recv_ttl)
  549. ) prn = 1;
  550. }
  551. if (prn) {
  552. print_addr (&pb->res);
  553. if (pb->ext) printf (" <%s>", pb->ext);
  554. if (backward && pb->recv_ttl) {
  555. int hops = ttl2hops (pb->recv_ttl);
  556. if (hops != ttl) printf (" '-%d'", hops);
  557. }
  558. }
  559. }
  560. if (pb->recv_time) {
  561. double diff = pb->recv_time - pb->send_time;
  562. printf (" %.3f ms", diff * 1000);
  563. }
  564. if (pb->err_str[0])
  565. printf (" %s", pb->err_str);
  566. fflush (stdout);
  567. return;
  568. }
  569. static void print_end (void) {
  570. printf ("\n");
  571. }
  572. /* Check expiration stuff */
  573. static void check_expired (probe *pb) {
  574. int idx = (pb - probes);
  575. probe *p, *endp = probes + num_probes;
  576. probe *fp = NULL, *pfp = NULL;
  577. if (!pb->done) /* an ops method still not release it */
  578. return;
  579. /* check all the previous in the same hop */
  580. for (p = &probes[idx - (idx % probes_per_hop)]; p < pb; p++) {
  581. if (!p->done || /* too early to decide something */
  582. !p->final /* already ttl-exceeded in the same hop */
  583. ) return;
  584. pfp = p; /* some of the previous probes is final */
  585. }
  586. /* check forward all the sent probes */
  587. for (p = pb + 1; p < endp && p->send_time; p++) {
  588. if (p->done) { /* some next probe already done... */
  589. if (!p->final) /* ...was ttl-exceeded. OK, we are expired. */
  590. return;
  591. else {
  592. fp = p;
  593. break;
  594. }
  595. }
  596. }
  597. if (!fp) /* no any final probe found. Assume expired. */
  598. return;
  599. /* Well. There is a situation "*(this) * * * * ... * * final"
  600. We cannot guarantee that "final" is in its right place.
  601. We've sent "sim_probes" simultaneously, and the final hop
  602. can drop some of them and answer only for latest ones.
  603. If we can detect/assume that it so, then just put "final"
  604. to the (pseudo-expired) "this" place.
  605. */
  606. if (pfp ||
  607. (idx % probes_per_hop) + (fp - pb) < probes_per_hop
  608. ) {
  609. /* Either some previous (pfp) or some next probe
  610. in this hop is final. It means that the whole hop is final.
  611. Do the replace (it also causes further "final"s to be shifted
  612. here too).
  613. */
  614. goto replace_by_final;
  615. }
  616. /* If the final probe is an icmp_unreachable report
  617. (either in a case of some error, like "!H", or just port_unreach),
  618. it could follow the "time-exceed" report from the *same* hop.
  619. */
  620. for (p = pb - 1; p >= probes; p--) {
  621. if (equal_addr (&p->res, &fp->res)) {
  622. /* ...Yes. Put "final" to the "this" place. */
  623. goto replace_by_final;
  624. }
  625. }
  626. if (fp->recv_ttl) {
  627. /* Consider the ttl value of the report packet and guess where
  628. the "final" should be. If it seems that it should be
  629. in the same hop as "this", then do replace.
  630. */
  631. int back_hops, ttl;
  632. /* We assume that the reporting one has an initial ttl value
  633. of either 64, or 128, or 255. It is most widely used
  634. in the modern routers and computers.
  635. The idea comes from tracepath(1) routine.
  636. */
  637. back_hops = ttl2hops (fp->recv_ttl);
  638. /* It is possible that the back path differs from the forward
  639. and therefore has different number of hops. To minimize
  640. such an influence, get the nearest previous time-exceeded
  641. probe and compare with it.
  642. */
  643. for (p = pb - 1; p >= probes; p--) {
  644. if (p->done && !p->final && p->recv_ttl) {
  645. int hops = ttl2hops (p->recv_ttl);
  646. if (hops < back_hops) {
  647. ttl = (p - probes) / probes_per_hop + 1;
  648. back_hops = (back_hops - hops) + ttl;
  649. break;
  650. }
  651. }
  652. }
  653. ttl = idx / probes_per_hop + 1;
  654. if (back_hops == ttl)
  655. /* Yes! It seems that "final" should be at "this" place */
  656. goto replace_by_final;
  657. else if (back_hops < ttl)
  658. /* Hmmm... Assume better to replace here too... */
  659. goto replace_by_final;
  660. }
  661. /* No idea what to do. Assume expired. */
  662. return;
  663. replace_by_final:
  664. *pb = *fp;
  665. memset (fp, 0, sizeof (*fp));
  666. /* block extra re-send */
  667. fp->send_time = 1.;
  668. return;
  669. }
  670. probe *probe_by_seq (int seq) {
  671. int n;
  672. if (seq <= 0) return NULL;
  673. for (n = 0; n < num_probes; n++) {
  674. if (probes[n].seq == seq)
  675. return &probes[n];
  676. }
  677. return NULL;
  678. }
  679. probe *probe_by_sk (int sk) {
  680. int n;
  681. if (sk <= 0) return NULL;
  682. for (n = 0; n < num_probes; n++) {
  683. if (probes[n].sk == sk)
  684. return &probes[n];
  685. }
  686. return NULL;
  687. }
  688. static void poll_callback (int fd, int revents) {
  689. ops->recv_probe (fd, revents);
  690. }
  691. static void do_it (void) {
  692. int start = (first_hop - 1) * probes_per_hop;
  693. int end = num_probes;
  694. double last_send = 0;
  695. print_header ();
  696. while (start < end) {
  697. int n, num = 0;
  698. double max_time = 0;
  699. double now_time = get_time ();
  700. for (n = start; n < end; n++) {
  701. probe *pb = &probes[n];
  702. if (!pb->done &&
  703. pb->send_time &&
  704. now_time - pb->send_time >= wait_secs
  705. ) {
  706. ops->expire_probe (pb);
  707. check_expired (pb);
  708. }
  709. if (pb->done) {
  710. if (n == start) { /* can print it now */
  711. print_probe (pb);
  712. start++;
  713. }
  714. if (pb->final)
  715. end = (n / probes_per_hop + 1) * probes_per_hop;
  716. continue;
  717. }
  718. if (!pb->send_time) {
  719. int ttl;
  720. if (send_secs && (now_time - last_send) < send_secs) {
  721. max_time = (last_send + send_secs) - wait_secs;
  722. break;
  723. }
  724. ttl = n / probes_per_hop + 1;
  725. ops->send_probe (pb, ttl);
  726. if (!pb->send_time) {
  727. if (max_time) break; /* have chances later */
  728. else error ("send probe");
  729. }
  730. last_send = pb->send_time;
  731. }
  732. if (pb->send_time > max_time)
  733. max_time = pb->send_time;
  734. num++;
  735. if (num >= sim_probes) break;
  736. }
  737. if (max_time) {
  738. double timeout = (max_time + wait_secs) - now_time;
  739. if (timeout < 0) timeout = 0;
  740. do_poll (timeout, poll_callback);
  741. }
  742. }
  743. print_end ();
  744. return;
  745. }
  746. void tune_socket (int sk) {
  747. int i = 0;
  748. if (debug) {
  749. i = 1;
  750. if (setsockopt (sk, SOL_SOCKET, SO_DEBUG, &i, sizeof (i)) < 0)
  751. error ("setsockopt SO_DEBUG");
  752. }
  753. #ifdef SO_MARK
  754. if (fwmark) {
  755. if (setsockopt (sk, SOL_SOCKET, SO_MARK,
  756. &fwmark, sizeof (fwmark)) < 0
  757. ) error ("setsockopt SO_MARK");
  758. }
  759. #endif
  760. if (rtbuf && rtbuf_len) {
  761. if (af == AF_INET) {
  762. if (setsockopt (sk, IPPROTO_IP, IP_OPTIONS,
  763. rtbuf, rtbuf_len) < 0
  764. ) error ("setsockopt IP_OPTIONS");
  765. }
  766. else if (af == AF_INET6) {
  767. if (setsockopt (sk, IPPROTO_IPV6, IPV6_RTHDR,
  768. rtbuf, rtbuf_len) < 0
  769. ) error ("setsockopt IPV6_RTHDR");
  770. }
  771. }
  772. bind_socket (sk);
  773. if (af == AF_INET) {
  774. i = dontfrag ? IP_PMTUDISC_PROBE : IP_PMTUDISC_DONT;
  775. if (setsockopt (sk, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0 &&
  776. (!dontfrag || (i = IP_PMTUDISC_DO,
  777. setsockopt (sk, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0))
  778. ) error ("setsockopt IP_MTU_DISCOVER");
  779. if (tos) {
  780. i = tos;
  781. if (setsockopt (sk, SOL_IP, IP_TOS, &i, sizeof (i)) < 0)
  782. error ("setsockopt IP_TOS");
  783. }
  784. }
  785. else if (af == AF_INET6) {
  786. i = dontfrag ? IPV6_PMTUDISC_PROBE : IPV6_PMTUDISC_DONT;
  787. if (setsockopt (sk, SOL_IPV6, IPV6_MTU_DISCOVER,&i,sizeof(i)) < 0 &&
  788. (!dontfrag || (i = IPV6_PMTUDISC_DO,
  789. setsockopt (sk, SOL_IPV6, IPV6_MTU_DISCOVER,&i,sizeof(i)) < 0))
  790. ) error ("setsockopt IPV6_MTU_DISCOVER");
  791. if (flow_label) {
  792. struct in6_flowlabel_req flr;
  793. memset (&flr, 0, sizeof (flr));
  794. flr.flr_label = htonl (flow_label & 0x000fffff);
  795. flr.flr_action = IPV6_FL_A_GET;
  796. flr.flr_flags = IPV6_FL_F_CREATE;
  797. flr.flr_share = IPV6_FL_S_ANY;
  798. memcpy (&flr.flr_dst, &dst_addr.sin6.sin6_addr,
  799. sizeof (flr.flr_dst));
  800. if (setsockopt (sk, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR,
  801. &flr, sizeof (flr)) < 0
  802. ) error ("setsockopt IPV6_FLOWLABEL_MGR");
  803. }
  804. if (tos) {
  805. i = tos;
  806. if (setsockopt (sk, IPPROTO_IPV6, IPV6_TCLASS,
  807. &i, sizeof (i)) < 0
  808. ) error ("setsockopt IPV6_TCLASS");
  809. }
  810. if (tos || flow_label) {
  811. i = 1;
  812. if (setsockopt (sk, IPPROTO_IPV6, IPV6_FLOWINFO_SEND,
  813. &i, sizeof (i)) < 0
  814. ) error ("setsockopt IPV6_FLOWINFO_SEND");
  815. }
  816. }
  817. if (noroute) {
  818. i = noroute;
  819. if (setsockopt (sk, SOL_SOCKET, SO_DONTROUTE, &i, sizeof (i)) < 0)
  820. error ("setsockopt SO_DONTROUTE");
  821. }
  822. use_timestamp (sk);
  823. use_recv_ttl (sk);
  824. fcntl (sk, F_SETFL, O_NONBLOCK);
  825. return;
  826. }
  827. void parse_icmp_res (probe *pb, int type, int code, int info) {
  828. char *str = NULL;
  829. char buf[sizeof (pb->err_str)];
  830. if (af == AF_INET) {
  831. if (type == ICMP_TIME_EXCEEDED) {
  832. if (code == ICMP_EXC_TTL)
  833. return;
  834. }
  835. else if (type == ICMP_DEST_UNREACH) {
  836. switch (code) {
  837. case ICMP_UNREACH_NET:
  838. case ICMP_UNREACH_NET_UNKNOWN:
  839. case ICMP_UNREACH_ISOLATED:
  840. case ICMP_UNREACH_TOSNET:
  841. str = "!N";
  842. break;
  843. case ICMP_UNREACH_HOST:
  844. case ICMP_UNREACH_HOST_UNKNOWN:
  845. case ICMP_UNREACH_TOSHOST:
  846. str = "!H";
  847. break;
  848. case ICMP_UNREACH_NET_PROHIB:
  849. case ICMP_UNREACH_HOST_PROHIB:
  850. case ICMP_UNREACH_FILTER_PROHIB:
  851. str = "!X";
  852. break;
  853. case ICMP_UNREACH_PORT:
  854. /* dest host is reached */
  855. str = "";
  856. break;
  857. case ICMP_UNREACH_PROTOCOL:
  858. str = "!P";
  859. break;
  860. case ICMP_UNREACH_NEEDFRAG:
  861. snprintf (buf, sizeof (buf), "!F-%d", info);
  862. str = buf;
  863. break;
  864. case ICMP_UNREACH_SRCFAIL:
  865. str = "!S";
  866. break;
  867. case ICMP_UNREACH_HOST_PRECEDENCE:
  868. str = "!V";
  869. break;
  870. case ICMP_UNREACH_PRECEDENCE_CUTOFF:
  871. str = "!C";
  872. break;
  873. default:
  874. snprintf (buf, sizeof (buf), "!<%u>", code);
  875. str = buf;
  876. break;
  877. }
  878. }
  879. }
  880. else if (af == AF_INET6) {
  881. if (type == ICMP6_TIME_EXCEEDED) {
  882. if (code == ICMP6_TIME_EXCEED_TRANSIT)
  883. return;
  884. }
  885. else if (type == ICMP6_DST_UNREACH) {
  886. switch (code) {
  887. case ICMP6_DST_UNREACH_NOROUTE:
  888. str = "!N";
  889. break;
  890. case ICMP6_DST_UNREACH_BEYONDSCOPE:
  891. case ICMP6_DST_UNREACH_ADDR:
  892. str = "!H";
  893. break;
  894. case ICMP6_DST_UNREACH_ADMIN:
  895. str = "!X";
  896. break;
  897. case ICMP6_DST_UNREACH_NOPORT:
  898. /* dest host is reached */
  899. str = "";
  900. break;
  901. default:
  902. snprintf (buf, sizeof (buf), "!<%u>", code);
  903. str = buf;
  904. break;
  905. }
  906. }
  907. else if (type == ICMP6_PACKET_TOO_BIG) {
  908. snprintf (buf, sizeof (buf), "!F-%d", info);
  909. str = buf;
  910. }
  911. }
  912. if (!str) {
  913. snprintf (buf, sizeof (buf), "!<%u-%u>", type, code);
  914. str = buf;
  915. }
  916. if (*str) {
  917. strncpy (pb->err_str, str, sizeof (pb->err_str));
  918. pb->err_str[sizeof (pb->err_str) - 1] = '\0';
  919. }
  920. pb->final = 1;
  921. return;
  922. }
  923. void probe_done (probe *pb) {
  924. if (pb->sk) {
  925. del_poll (pb->sk);
  926. close (pb->sk);
  927. pb->sk = 0;
  928. }
  929. pb->seq = 0;
  930. pb->done = 1;
  931. }
  932. void recv_reply (int sk, int err, check_reply_t check_reply) {
  933. struct msghdr msg;
  934. sockaddr_any from;
  935. struct iovec iov;
  936. int n;
  937. probe *pb;
  938. char buf[1280]; /* min mtu for ipv6 ( >= 576 for ipv4) */
  939. char *bufp = buf;
  940. char control[1024];
  941. struct cmsghdr *cm;
  942. double recv_time = 0;
  943. int recv_ttl = 0;
  944. struct sock_extended_err *ee = NULL;
  945. memset (&msg, 0, sizeof (msg));
  946. msg.msg_name = &from;
  947. msg.msg_namelen = sizeof (from);
  948. msg.msg_control = control;
  949. msg.msg_controllen = sizeof (control);
  950. iov.iov_base = buf;
  951. iov.iov_len = sizeof (buf);
  952. msg.msg_iov = &iov;
  953. msg.msg_iovlen = 1;
  954. n = recvmsg (sk, &msg, err ? MSG_ERRQUEUE : 0);
  955. if (n < 0) return;
  956. /* when not MSG_ERRQUEUE, AF_INET returns full ipv4 header
  957. on raw sockets...
  958. */
  959. if (!err &&
  960. af == AF_INET &&
  961. /* XXX: Assume that the presence of an extra header means
  962. that it is not a raw socket...
  963. */
  964. ops->header_len == 0
  965. ) {
  966. struct iphdr *ip = (struct iphdr *) bufp;
  967. int hlen;
  968. if (n < sizeof (struct iphdr)) return;
  969. hlen = ip->ihl << 2;
  970. if (n < hlen) return;
  971. bufp += hlen;
  972. n -= hlen;
  973. }
  974. pb = check_reply (sk, err, &from, bufp, n);
  975. if (!pb) return;
  976. /* Parse CMSG stuff */
  977. for (cm = CMSG_FIRSTHDR (&msg); cm; cm = CMSG_NXTHDR (&msg, cm)) {
  978. void *ptr = CMSG_DATA (cm);
  979. if (cm->cmsg_level == SOL_SOCKET) {
  980. if (cm->cmsg_type == SO_TIMESTAMP) {
  981. struct timeval *tv = (struct timeval *) ptr;
  982. recv_time = tv->tv_sec + tv->tv_usec / 1000000.;
  983. }
  984. }
  985. else if (cm->cmsg_level == SOL_IP) {
  986. if (cm->cmsg_type == IP_TTL)
  987. recv_ttl = *((int *) ptr);
  988. else if (cm->cmsg_type == IP_RECVERR) {
  989. ee = (struct sock_extended_err *) ptr;
  990. if (ee->ee_origin != SO_EE_ORIGIN_ICMP)
  991. ee = NULL;
  992. /* dgram icmp sockets might return extra things... */
  993. if (ee->ee_type == ICMP_SOURCE_QUENCH ||
  994. ee->ee_type == ICMP_REDIRECT
  995. ) return;
  996. }
  997. }
  998. else if (cm->cmsg_level == SOL_IPV6) {
  999. if (cm->cmsg_type == IPV6_HOPLIMIT)
  1000. recv_ttl = *((int *) ptr);
  1001. else if (cm->cmsg_type == IPV6_RECVERR) {
  1002. ee = (struct sock_extended_err *) ptr;
  1003. if (ee->ee_origin != SO_EE_ORIGIN_ICMP6)
  1004. ee = NULL;
  1005. }
  1006. }
  1007. }
  1008. if (!recv_time)
  1009. recv_time = get_time ();
  1010. if (!err)
  1011. memcpy (&pb->res, &from, sizeof (pb->res));
  1012. pb->recv_time = recv_time;
  1013. pb->recv_ttl = recv_ttl;
  1014. if (ee) {
  1015. memcpy (&pb->res, SO_EE_OFFENDER (ee), sizeof(pb->res));
  1016. parse_icmp_res (pb, ee->ee_type, ee->ee_code, ee->ee_info);
  1017. }
  1018. if (ee &&
  1019. mtudisc &&
  1020. ee->ee_info >= header_len &&
  1021. ee->ee_info < header_len + data_len
  1022. ) {
  1023. data_len = ee->ee_info - header_len;
  1024. probe_done (pb);
  1025. /* clear this probe (as actually the previous hop answers here)
  1026. but fill its `err_str' by the info obtained. Ugly, but easy...
  1027. */
  1028. memset (pb, 0, sizeof (*pb));
  1029. snprintf (pb->err_str, sizeof(pb->err_str)-1, "F=%d", ee->ee_info);
  1030. return;
  1031. }
  1032. if (ee &&
  1033. extension &&
  1034. header_len + n >= (128 + 8) && /* at least... (rfc4884) */
  1035. header_len <= 128 && /* paranoia */
  1036. ((af == AF_INET && (ee->ee_type == ICMP_TIME_EXCEEDED ||
  1037. ee->ee_type == ICMP_DEST_UNREACH ||
  1038. ee->ee_type == ICMP_PARAMETERPROB)) ||
  1039. (af == AF_INET6 && (ee->ee_type == ICMP6_TIME_EXCEEDED ||
  1040. ee->ee_type == ICMP6_DST_UNREACH))
  1041. )
  1042. ) {
  1043. int step;
  1044. int offs = 128 - header_len;
  1045. if (n > data_len) step = 0; /* guaranteed at 128 ... */
  1046. else
  1047. step = af == AF_INET ? 4 : 8;
  1048. handle_extensions (pb, bufp + offs, n - offs, step);
  1049. }
  1050. probe_done (pb);
  1051. }
  1052. int equal_addr (const sockaddr_any *a, const sockaddr_any *b) {
  1053. if (!a->sa.sa_family)
  1054. return 0;
  1055. if (a->sa.sa_family != b->sa.sa_family)
  1056. return 0;
  1057. if (a->sa.sa_family == AF_INET6)
  1058. return !memcmp (&a->sin6.sin6_addr, &b->sin6.sin6_addr,
  1059. sizeof (a->sin6.sin6_addr));
  1060. else
  1061. return !memcmp (&a->sin.sin_addr, &b->sin.sin_addr,
  1062. sizeof (a->sin.sin_addr));
  1063. return 0; /* not reached */
  1064. }
  1065. void bind_socket (int sk) {
  1066. sockaddr_any *addr, tmp;
  1067. if (device) {
  1068. if (setsockopt (sk, SOL_SOCKET, SO_BINDTODEVICE,
  1069. device, strlen (device) + 1) < 0
  1070. ) error ("setsockopt SO_BINDTODEVICE");
  1071. }
  1072. if (!src_addr.sa.sa_family) {
  1073. memset (&tmp, 0, sizeof (tmp));
  1074. tmp.sa.sa_family = af;
  1075. addr = &tmp;
  1076. } else
  1077. addr = &src_addr;
  1078. if (bind (sk, &addr->sa, sizeof (*addr)) < 0)
  1079. error ("bind");
  1080. return;
  1081. }
  1082. void use_timestamp (int sk) {
  1083. int n = 1;
  1084. setsockopt (sk, SOL_SOCKET, SO_TIMESTAMP, &n, sizeof (n));
  1085. /* foo on errors... */
  1086. }
  1087. void use_recv_ttl (int sk) {
  1088. int n = 1;
  1089. if (af == AF_INET)
  1090. setsockopt (sk, SOL_IP, IP_RECVTTL, &n, sizeof (n));
  1091. else if (af == AF_INET6)
  1092. setsockopt (sk, SOL_IPV6, IPV6_RECVHOPLIMIT, &n, sizeof (n));
  1093. /* foo on errors */
  1094. }
  1095. void use_recverr (int sk) {
  1096. int val = 1;
  1097. if (af == AF_INET) {
  1098. if (setsockopt (sk, SOL_IP, IP_RECVERR, &val, sizeof (val)) < 0)
  1099. error ("setsockopt IP_RECVERR");
  1100. }
  1101. else if (af == AF_INET6) {
  1102. if (setsockopt (sk, SOL_IPV6, IPV6_RECVERR, &val, sizeof (val)) < 0)
  1103. error ("setsockopt IPV6_RECVERR");
  1104. }
  1105. }
  1106. void set_ttl (int sk, int ttl) {
  1107. if (af == AF_INET) {
  1108. if (setsockopt (sk, SOL_IP, IP_TTL, &ttl, sizeof (ttl)) < 0)
  1109. error ("setsockopt IP_TTL");
  1110. }
  1111. else if (af == AF_INET6) {
  1112. if (setsockopt (sk, SOL_IPV6, IPV6_UNICAST_HOPS,
  1113. &ttl, sizeof (ttl)) < 0
  1114. ) error ("setsockopt IPV6_UNICAST_HOPS");
  1115. }
  1116. }
  1117. int do_send (int sk, const void *data, size_t len, const sockaddr_any *addr) {
  1118. int res;
  1119. if (!addr || raw_can_connect ())
  1120. res = send (sk, data, len, 0);
  1121. else
  1122. res = sendto (sk, data, len, 0, &addr->sa, sizeof (*addr));
  1123. if (res < 0) {
  1124. if (errno == ENOBUFS || errno == EAGAIN)
  1125. return res;
  1126. if (errno == EMSGSIZE)
  1127. return 0; /* icmp will say more... */
  1128. error ("send"); /* not recoverable */
  1129. }
  1130. return res;
  1131. }
  1132. /* There is a bug in the kernel before 2.6.25, which prevents icmp errors
  1133. to be obtained by MSG_ERRQUEUE for ipv6 connected raw sockets.
  1134. */
  1135. static int can_connect = -1;
  1136. #define VER(A,B,C,D) (((((((A) << 8) | (B)) << 8) | (C)) << 8) | (D))
  1137. int raw_can_connect (void) {
  1138. if (can_connect < 0) {
  1139. if (af == AF_INET)
  1140. can_connect = 1;
  1141. else { /* AF_INET6 */
  1142. struct utsname uts;
  1143. int n;
  1144. unsigned int a, b, c, d = 0;
  1145. if (uname (&uts) < 0)
  1146. return 0;
  1147. n = sscanf (uts.release, "%u.%u.%u.%u", &a, &b, &c, &d);
  1148. can_connect = (n >= 3 && VER (a, b, c, d) >= VER (2, 6, 25, 0));
  1149. }
  1150. }
  1151. return can_connect;
  1152. }