⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 traceroute.c

📁 linux下traceroute的实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/*    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 + -