1 /* -*- Mode: c; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4; -*- */
2 /* vim:set ts=4 sw=4 ai nobackup nocindent sm: */
3 
4 /*
5  * tcptraceroute -- A traceroute implementation using TCP packets
6  * Copyright (c) 2001-2006  Michael C. Toren <mct@toren.net>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License, version 2, as published
10  * by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * for more details.
16  *
17  * A copy of the GNU GPL is available as /usr/doc/copyright/GPL on Debian
18  * systems, or on the World Wide Web at http://www.gnu.org/copyleft/gpl.html
19  * You can also obtain it by writing to the Free Software Foundation, Inc.,
20  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21  */
22 
23 #include "tcptraceroute.h"
24 #include <stdarg.h>
25 
26 /*
27  * fatal() and pfatal() are useful stdarg functions from
28  * namp.  debug() and warn() are based on them.
29  */
30 
fatal(char * fmt,...)31 void fatal(char *fmt, ...)
32 {
33 	va_list ap;
34 	fflush(stdout);
35 	va_start(ap, fmt);
36 	vfprintf(stderr, fmt, ap);
37 	va_end(ap);
38 	exit(1);
39 }
40 
debug(char * fmt,...)41 void debug(char *fmt, ...)
42 {
43 	va_list ap;
44 	if (! o_debug) return;
45 	fflush(stdout);
46 	fprintf(stderr, "debug: ");
47 	va_start(ap, fmt);
48 	vfprintf(stderr, fmt, ap);
49 	va_end(ap);
50 	fflush(stderr);
51 }
52 
warn(char * fmt,...)53 void warn(char *fmt, ...)
54 {
55 	va_list ap;
56 	fflush(stdout);
57 	fprintf(stderr, "Warning: ");
58 	va_start(ap, fmt);
59 	vfprintf(stderr, fmt, ap);
60 	va_end(ap);
61 	fflush(stderr);
62 }
63 
pfatal(char * err)64 void pfatal(char *err)
65 {
66 	debug("errno == %d\n", errno);
67 	fflush(stdout);
68 	perror(err);
69 	exit(1);
70 }
71 
usage(void)72 void usage(void)
73 {
74 	printf("\n%s %s\n%s\n", PACKAGE, VERSION, BANNER);
75     fatal("\
76 Usage: %s [-nNFSAE] [-i <interface>] [-f <first ttl>]\n\
77        [-l <packet length>] [-q <number of queries>] [-t <tos>]\n\
78        [-m <max ttl>] [-pP] <source port>] [-s <source address>]\n\
79        [-w <wait time>] <host> [destination port] [packet length]\n\n", name);
80 }
81 
about(void)82 void about(void)
83 {
84 	printf("\n%s %s\n%s\n", PACKAGE, VERSION, BANNER);
85 	exit(0);
86 }
87 
88 /*
89  * realloc(3) or bust!
90  */
91 
xrealloc(void * oldp,int size)92 void *xrealloc(void *oldp, int size)
93 {
94 	void *p;
95 
96 	if (!oldp)
97 		p = malloc(size);
98 	else
99 		p = realloc(oldp, size);
100 
101 	if (!p)
102 		fatal("Out of memory!  Could not reallocate %d bytes!\n", size);
103 
104 	memset(p, 0, size);
105 	return p;
106 }
107 
108 /*
109  * Same as strncpy and snprintf, but always be sure the result is terminated.
110  */
111 
safe_strncpy(char * dst,char * src,int size)112 char *safe_strncpy(char *dst, char *src, int size)
113 {
114 	dst[size-1] = '\0';
115 	return strncpy(dst, src, size-1);
116 }
117 
safe_snprintf(char * s,int size,char * fmt,...)118 int safe_snprintf(char *s, int size, char *fmt, ...)
119 {
120 	va_list ap;
121 	int ret;
122 
123 	va_start(ap, fmt);
124 	ret = vsnprintf(s, size, fmt, ap);
125 	s[size-1] = '\0';
126 	va_end(ap);
127 
128 	return ret;
129 }
130 
131 /*
132  * return a pointer to a string containing only the
133  * printable characters of the string passed to it.
134  */
135 
sprintable(char * s)136 char *sprintable(char *s)
137 {
138 	static char buf[TEXTSIZE];
139 	int i;
140 
141 	if (s && s[0])
142 		safe_strncpy(buf, s, TEXTSIZE);
143 	else
144 		safe_strncpy(buf, "(empty)", TEXTSIZE);
145 
146 	for (i = 0; buf[i]; i++)
147 		if (! isprint((u_char) buf[i]))
148 			buf[i] = '?';
149 
150 	return buf;
151 }
152 
153 /*
154  * isdigit() across an entire string.
155  */
156 
isnumeric(char * s)157 int isnumeric(char *s)
158 {
159 	int i;
160 
161 	if (!s || !s[0])
162 		return 0;
163 
164 	for (i = 0; s[i]; i++)
165 		if (! isdigit((u_char) s[i]))
166 			return 0;
167 
168 	return 1;
169 }
170 
171 /*
172  * Compute the difference between two timeval structures.
173  */
174 
tvdiff(struct timeval * tv1,struct timeval * tv2)175 struct timeval tvdiff(struct timeval *tv1, struct timeval *tv2)
176 {
177 	struct timeval tvdiff;
178 
179 	tvdiff.tv_sec = tv1->tv_sec - tv2->tv_sec;
180 	tvdiff.tv_usec = tv1->tv_usec - tv2->tv_usec;
181 
182 	if ((tvdiff.tv_sec > 0) && (tvdiff.tv_usec < 0))
183 	{
184 		tvdiff.tv_usec += 1000000L;
185 		tvdiff.tv_sec--;
186 	}
187 
188 	else if ((tvdiff.tv_sec < 0) && (tvdiff.tv_usec > 0))
189 	{
190 		tvdiff.tv_usec -= 1000000L;
191 		tvdiff.tv_sec++;
192 	}
193 
194 	return tvdiff;
195 }
196 
197 /*
198  * Is the timeval less than, equal to, or greater than zero?
199  */
200 
tvsign(struct timeval * tv)201 int tvsign(struct timeval *tv)
202 {
203 	if (tv->tv_sec < 0) return -1;
204 
205 	if (tv->tv_sec == 0)
206 	{
207 		if (tv->tv_usec < 0) return -1;
208 		if (tv->tv_usec == 0) return 0;
209 		if (tv->tv_usec > 0) return 1;
210 	}
211 
212 	if (tv->tv_sec > 0) return 1;
213 
214 	return -1;
215 }
216 
217 /*
218  * Inspired by libnet_host_lookup(), but I needed more than 2 buffers while
219  * I was debugging.  I really could get by with only 2 now, but *shrug*.
220  */
221 
iptos(u_long in)222 char *iptos(u_long in)
223 {
224 	static char output[IPTOSBUFFERS][IPTOSBUFSIZ];
225 	static short which;
226 	u_char *p;
227 
228 	p = (u_char *)&in;
229 	which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
230 	safe_snprintf(output[which], IPTOSBUFSIZ, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
231 	return output[which];
232 }
233 
234 /*
235  * A wrapper for libnet_addr2name4(), with the option not to resolve
236  * RFC1918 space.
237  */
238 
iptohost(u_long in)239 char *iptohost(u_long in)
240 {
241 	u_char *p = (u_char *)&in;
242 
243 	if ((o_numeric > -1) &&
244 		((p[0] == 10) ||
245 		(p[0] == 192 && p[1] == 168) ||
246 		(p[0] == 172 && p[1] >= 16 && p[1] <= 31)))
247 	{
248 		debug("Not attempting to resolve RFC1918 address %s\n", iptos(in));
249 		return iptos(in);
250 	}
251 
252 	return (char *)libnet_addr2name4(in,
253 		o_numeric > 0 ? LIBNET_DONT_RESOLVE : LIBNET_RESOLVE);
254 }
255 
256 /*
257  * Useful for debugging; dump #define's and command line options.
258  */
259 
debugoptions(void)260 void debugoptions(void)
261 {
262 	if (! o_debug)
263 		return;
264 
265 	debug("debugoptions():\n");
266 
267 	debug("%16s: %-2d %14s: %-2d %16s: %-2d\n",
268 		"TEXTSIZE", TEXTSIZE,
269 		"SNAPLEN", SNAPLEN,
270 		"IPTOSBUFFERS", IPTOSBUFFERS);
271 
272 	debug("%16s: %-3d %15s: %-2d %16s: %-2d\n",
273 		"ALLOCATEID_CACHE", ALLOCATEID_CACHE_SIZE,
274 		"datalink", datalink,
275 		"datalinkoffset", datalinkoffset(datalink));
276 
277 	debug("%16s: %-2d %16s: %-2d %16s: %-2d\n",
278 		"o_minttl", o_minttl,
279 		"o_maxttl", o_maxttl,
280 		"o_timeout", o_timeout);
281 
282 	debug("%16s: %-2d %16s: %-2d %16s: %-2d\n",
283 		"o_debug", o_debug,
284 		"o_numeric", o_numeric,
285 		"o_pktlen", o_pktlen);
286 
287 	debug("%16s: %-2d %16s: %-2d %16s: %-2d\n",
288 		"o_nqueries", o_nqueries,
289 		"o_dontfrag", o_dontfrag,
290 		"o_tos", o_tos);
291 
292 	debug("%16s: %-2d %16s: %-2d %16s: %-2d\n",
293 		"o_forceport", o_forceport,
294 		"o_syn", o_syn,
295 		"o_ack", o_ack);
296 
297 	debug("%16s: %-2d %16s: %d %16s: %-2d\n",
298 		"o_ecn", o_ecn,
299 		"o_nofilter", o_nofilter,
300 		"o_nogetinterfaces", o_nogetinterfaces);
301 
302 	debug("%16s: %-2d %16s: %-12s %s: %s\n",
303 		"o_trackport", o_trackport,
304 		"datalinkname", datalinkname(datalink),
305 		"device", device);
306 
307 	debug("%16s: %-2d %16s: %-2d %16s: %-10ld\n",
308 		"o_noselect", o_noselect,
309 		"o_dnat", o_dnat,
310 		"isn", isn);
311 }
312