📄 traceroute.c
字号:
/* Copyright (c) 2006, 2007 Dmitry Butskoy <buc@citadel.stu.neva.ru> License: GPL v2 or any later See COPYING for the status of this software.*/#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <unistd.h>#include <fcntl.h>#include <sys/socket.h>#include <sys/poll.h>#include <netinet/icmp6.h>#include <netinet/ip_icmp.h>#include <netinet/in.h>#include <netinet/ip6.h>#include <netdb.h>#include <errno.h>#include <locale.h>#include <sys/utsname.h>#include <linux/types.h>#include <linux/errqueue.h>/* XXX: Remove this when things will be defined properly in netinet/ ... */#include "flowlabel.h"#include <clif.h>#include "version.h"#include "traceroute.h"#ifndef ICMP6_DST_UNREACH_BEYONDSCOPE#ifdef ICMP6_DST_UNREACH_NOTNEIGHBOR#define ICMP6_DST_UNREACH_BEYONDSCOPE ICMP6_DST_UNREACH_NOTNEIGHBOR#else#define ICMP6_DST_UNREACH_BEYONDSCOPE 2#endif#endif#ifndef IPV6_RECVHOPLIMIT#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT#endif#ifndef IP_PMTUDISC_PROBE#define IP_PMTUDISC_PROBE 3#endif#ifndef IPV6_PMTUDISC_PROBE#define IPV6_PMTUDISC_PROBE 3#endif#define MAX_HOPS 255#define MAX_PROBES 10#define MAX_GATEWAYS_4 8#define MAX_GATEWAYS_6 127#define DEF_HOPS 30#define DEF_SIM_PROBES 16 /* including several hops */#define DEF_NUM_PROBES 3#define DEF_WAIT_SECS 5.0#define DEF_SEND_SECS 0#define DEF_DATA_LEN 40 /* all but IP header... */#define MAX_PACKET_LEN 65000#ifndef DEF_AF#define DEF_AF AF_INET#endif#define ttl2hops(X) (((X) <= 64 ? 65 : ((X) <= 128 ? 129 : 256)) - (X))static char version_string[] = "Modern traceroute for Linux, " "version " _TEXT(VERSION) ", " __DATE__ "\nCopyright (c) 2008 Dmitry Butskoy, " " License: GPL v2 or any later";static int debug = 0;static unsigned int first_hop = 1;static unsigned int max_hops = DEF_HOPS;static unsigned int sim_probes = DEF_SIM_PROBES;static unsigned int probes_per_hop = DEF_NUM_PROBES;static char **gateways = NULL;static int num_gateways = 0;static unsigned char *rtbuf = NULL;static size_t rtbuf_len = 0;static size_t header_len = 0;static size_t data_len = 0;static int dontfrag = 0;static int noresolve = 0;static int extension = 0;static int as_lookups = 0;static unsigned int dst_port_seq = 0;static unsigned int tos = 0;static unsigned int flow_label = 0;static int noroute = 0;static int packet_len = -1;static double wait_secs = DEF_WAIT_SECS;static double send_secs = DEF_SEND_SECS;static int mtudisc = 0;static int backward = 0;static sockaddr_any dst_addr = {{ 0, }, };static char *dst_name = NULL;static char *device = NULL;static sockaddr_any src_addr = {{ 0, }, };static unsigned int src_port = 0;static const char *module = "default";static const tr_module *ops = NULL;static char *opts[16] = { NULL, }; /* assume enough */static unsigned int opts_idx = 1; /* first one reserved... */static int af = 0;static probe *probes = NULL;static unsigned int num_probes = 0;static void ex_error (const char *format, ...) { va_list ap; va_start (ap, format); vfprintf (stderr, format, ap); va_end (ap); fprintf (stderr, "\n"); exit (2);}void error (const char *str) { fprintf (stderr, "\n"); perror (str); exit (1);}/* Set initial parameters according to how we was called */static void check_progname (const char *name) { const char *p; int l; p = strrchr (name, '/'); if (p) p++; else p = name; l = strlen (p); if (l <= 0) return; l--; if (p[l] == '6') af = AF_INET6; else if (p[l] == '4') af = AF_INET; if (!strncmp (p, "tcp", 3)) module = "tcp"; if (!strncmp (p, "tracert", 7)) module = "icmp"; return;}static int getaddr (const char *name, sockaddr_any *addr) { int ret; struct addrinfo hints, *ai, *res = NULL; memset (&hints, 0, sizeof (hints)); //清0? hints.ai_family = af; hints.ai_flags = AI_IDN; ret = getaddrinfo (name, NULL, &hints, &res); if (ret) { fprintf (stderr, "%s: %s\n", name, gai_strerror (ret)); return -1; } for (ai = res; ai; ai = ai->ai_next) { if (ai->ai_family == af) break; /* when af not specified, choose DEF_AF if present */ if (!af && ai->ai_family == DEF_AF) break; } if (!ai) ai = res; /* anything... */ if (ai->ai_addrlen > sizeof (*addr)) return -1; /* paranoia */ memcpy (addr, ai->ai_addr, ai->ai_addrlen); freeaddrinfo (res); return 0;}static void make_fd_used (int fd) { int nfd; if (fcntl (fd, F_GETFL) != -1) return; if (errno != EBADF) error ("fcntl F_GETFL"); nfd = open ("/dev/null", O_RDONLY); if (nfd < 0) error ("open /dev/null"); if (nfd != fd) { dup2 (nfd, fd); close (nfd); } return;}static char addr2str_buf[INET6_ADDRSTRLEN];static const char *addr2str (const sockaddr_any *addr) { getnameinfo (&addr->sa, sizeof (*addr), addr2str_buf, sizeof (addr2str_buf), 0, 0, NI_NUMERICHOST); return addr2str_buf;}/* IP options stuff */static void init_ip_options (void) { sockaddr_any *gates; int i, max; if (!num_gateways) return; max = af == AF_INET ? MAX_GATEWAYS_4 : MAX_GATEWAYS_6; if (num_gateways > max) ex_error ("Too many gateways specified. No more than %d", max); gates = alloca (num_gateways * sizeof (*gates)); for (i = 0; i < num_gateways; i++) { if (!gateways[i]) error ("strdup"); if (getaddr (gateways[i], &gates[i]) < 0) ex_error (""); /* already reported */ if (gates[i].sa.sa_family != af) ex_error ("IP versions mismatch in gateway addresses"); free (gateways[i]); } free (gateways); gateways = NULL; if (af == AF_INET) { struct in_addr *in; rtbuf_len = 4 + (num_gateways + 1) * sizeof (*in); rtbuf = malloc (rtbuf_len); if (!rtbuf) error ("malloc"); in = (struct in_addr *) &rtbuf[4]; for (i = 0; i < num_gateways; i++) memcpy (&in[i], &gates[i].sin.sin_addr, sizeof (*in)); /* final hop */ memcpy (&in[i], &dst_addr.sin.sin_addr, sizeof (*in)); i++; rtbuf[0] = IPOPT_NOP; rtbuf[1] = IPOPT_LSRR; rtbuf[2] = (i * sizeof (*in)) + 3; rtbuf[3] = IPOPT_MINOFF; } else if (af == AF_INET6) { struct in6_addr *in6; struct ip6_rthdr *rth; /* IPV6_RTHDR_TYPE_0 length is 8 */ rtbuf_len = 8 + num_gateways * sizeof (*in6); rtbuf = malloc (rtbuf_len); if (!rtbuf) error ("malloc"); rth = (struct ip6_rthdr *) rtbuf; rth->ip6r_nxt = 0; rth->ip6r_len = 2 * num_gateways; rth->ip6r_type = IPV6_RTHDR_TYPE_0; rth->ip6r_segleft = num_gateways; *((u_int32_t *) (rth + 1)) = 0; in6 = (struct in6_addr *) (rtbuf + 8); for (i = 0; i < num_gateways; i++) memcpy (&in6[i], &gates[i].sin6.sin6_addr, sizeof (*in6)); } return;}/* Command line stuff */static int set_af (CLIF_option *optn, char *arg) { int vers = (int) optn->data; if (vers == 4) af = AF_INET; else if (vers == 6) af = AF_INET6; else return -1; return 0;}static int add_gateway (CLIF_option *optn, char *arg) { if (num_gateways >= MAX_GATEWAYS_6) { /* 127 > 8 ... :) */ fprintf (stderr, "Too many gateways specified."); return -1; } gateways = realloc (gateways, (num_gateways + 1) * sizeof (*gateways)); if (!gateways) error ("malloc"); gateways[num_gateways++] = strdup (arg); return 0;}static int set_source (CLIF_option *optn, char *arg) { return getaddr (arg, &src_addr);}static int set_port (CLIF_option *optn, char *arg) { unsigned int *up = (unsigned int *) optn->data; char *q; *up = strtoul (arg, &q, 0); if (q == arg) { struct servent *s = getservbyname (arg, NULL); if (!s) return -1; *up = ntohs (s->s_port); } return 0;}static int set_module (CLIF_option *optn, char *arg) { module = (char *) optn->data; return 0;}static int set_mod_option (CLIF_option *optn, char *arg) { if (!strcmp (arg, "help")) { const tr_module *mod = tr_get_module (module); if (mod && mod->options) { /* just to set common keyword flag... */ CLIF_parse (1, &arg, 0, 0, CLIF_KEYWORD); CLIF_print_options (NULL, mod->options); } else fprintf (stderr, "No options for module `%s'\n", module); exit (0); } if (opts_idx >= sizeof (opts) / sizeof (*opts)) { fprintf (stderr, "Too many module options\n"); return -1; } opts[opts_idx] = strdup (arg); if (!opts[opts_idx]) error ("strdup"); opts_idx++; return 0;}static int set_raw (CLIF_option *optn, char *arg) { char buf[1024]; module = "raw"; snprintf (buf, sizeof (buf), "protocol=%s", arg); return set_mod_option (optn, buf);}static int set_host (CLIF_argument *argm, char *arg, int index) { if (getaddr (arg, &dst_addr) < 0) return -1; dst_name = arg; /* i.e., guess it by the addr in cmdline... */ if (!af) af = dst_addr.sa.sa_family; return 0;}static CLIF_option option_list[] = { { "4", 0, 0, "Use IPv4", set_af, (void *) 4, 0, CLIF_EXTRA }, { "6", 0, 0, "Use IPv6", set_af, (void *) 6, 0, 0 }, { "d", "debug", 0, "Enable socket level debugging", CLIF_set_flag, &debug, 0, 0 }, { "F", "dont-fragment", 0, "Do not fragment packets", CLIF_set_flag, &dontfrag, 0, CLIF_ABBREV }, { "f", "first", "first_ttl", "Start from the %s hop (instead from 1)", CLIF_set_uint, &first_hop, 0, 0 }, { "g", "gateway", "gate", "Route packets throw the specified gateway " "(maximum " _TEXT(MAX_GATEWAYS_4) " for IPv4 and " _TEXT(MAX_GATEWAYS_6) " for IPv6)", add_gateway, 0, 0, CLIF_SEVERAL }, { "I", "icmp", 0, "Use ICMP ECHO for tracerouting", set_module, "icmp", 0, 0 }, { "T", "tcp", 0, "Use TCP SYN for tracerouting", set_module, "tcp", 0, 0 }, { "i", "interface", "device", "Specify a network interface " "to operate with", CLIF_set_string, &device, 0, 0 }, { "m", "max-hops", "max_ttl", "Set the max number of hops (max TTL " "to be reached). Default is " _TEXT(DEF_HOPS) , CLIF_set_uint, &max_hops, 0, 0 }, { "N", "sim-queries", "squeries", "Set the number of probes " "to be tried simultaneously (default is " _TEXT(DEF_SIM_PROBES) ")", CLIF_set_uint, &sim_probes, 0, 0 }, { "n", 0, 0, "Do not resolve IP addresses to their domain names", CLIF_set_flag, &noresolve, 0, 0 }, { "p", "port", "port", "Set the destination port to use. " "It is either initial udp port value for " "\"default\" method (incremented by each probe, " "default is " _TEXT(DEF_START_PORT) "), " "or initial seq for \"icmp\" (incremented as well, " "default from 1), or some constant destination port" " for other methods (with default of " _TEXT(DEF_TCP_PORT) " for \"tcp\", " _TEXT(DEF_UDP_PORT) " for \"udp\", etc.)", set_port, &dst_port_seq, 0, 0 }, { "t", "tos", "tos", "Set the TOS (IPv4 type of service) or TC " "(IPv6 traffic class) value for outgoing packets", CLIF_set_uint, &tos, 0, 0 }, { "l", "flowlabel", "flow_label", "Use specified %s for IPv6 packets", CLIF_set_uint, &flow_label, 0, 0 }, { "w", "wait", "waittime", "Set the number of seconds to wait for " "response to a probe (default is " _TEXT(DEF_WAIT_SECS) "). Non-integer (float point) " "values allowed too", CLIF_set_double, &wait_secs, 0, 0 }, { "q", "queries", "nqueries", "Set the number of probes per each hop. " "Default is " _TEXT(DEF_NUM_PROBES), CLIF_set_uint, &probes_per_hop, 0, 0 }, { "r", 0, 0, "Bypass the normal routing and send directly to a host " "on an attached network", CLIF_set_flag, &noroute, 0, 0 }, { "s", "source", "src_addr", "Use source %s for outgoing packets", set_source, 0, 0, 0 }, { "z", "sendwait", "sendwait", "Minimal time interval between probes " "(default " _TEXT(DEF_SEND_SECS) "). If the value " "is more than 10, then it specifies a number " "in milliseconds, else it is a number of seconds " "(float point values allowed too)", CLIF_set_double, &send_secs, 0, 0 }, { "e", "extensions", 0, "Show ICMP extensions (if present), " "including MPLS", CLIF_set_flag, &extension, 0, CLIF_ABBREV }, { "A", "as-path-lookups", 0, "Perform AS path lookups in routing " "registries and print results directly after " "the corresponding addresses", CLIF_set_flag, &as_lookups, 0, 0 }, { "M", "module", "name", "Use specified module (either builtin or " "external) for traceroute operations. Most methods " "have their shortcuts (`-I' means `-M icmp' etc.)", CLIF_set_string, &module, 0, CLIF_EXTRA }, { "O", "options", "OPTS", "Use module-specific option %s for the " "traceroute module. Several %s allowed, separated " "by comma. If %s is \"help\", print info about " "available options", set_mod_option, 0, 0, CLIF_SEVERAL | CLIF_EXTRA }, { 0, "sport", "num", "Use source port %s for outgoing packets. " "Implies `-N 1'",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -