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 *)∈
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 *)∈
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