Bug Summary

File:src/usr.sbin/traceroute/traceroute.c
Warning:line 357, column 13
Although the value stored to 'rcvsock6' is used in the enclosing expression, the value is never actually read from 'rcvsock6'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name traceroute.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/traceroute/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/traceroute -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/traceroute/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/traceroute/traceroute.c
1/* $OpenBSD: traceroute.c,v 1.168 2021/09/03 09:13:00 florian Exp $ */
2/* $NetBSD: traceroute.c,v 1.10 1995/05/21 15:50:45 mycroft Exp $ */
3
4/*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/*-
34 * Copyright (c) 1990, 1993
35 * The Regents of the University of California. All rights reserved.
36 *
37 * This code is derived from software contributed to Berkeley by
38 * Van Jacobson.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 */
64
65/*
66 * traceroute host - trace the route ip packets follow going to "host".
67 *
68 * Attempt to trace the route an ip packet would follow to some
69 * internet host. We find out intermediate hops by launching probe
70 * packets with a small ttl (time to live) then listening for an
71 * icmp "time exceeded" reply from a gateway. We start our probes
72 * with a ttl of one and increase by one until we get an icmp "port
73 * unreachable" (which means we got to "host") or hit a max (which
74 * defaults to 64 hops & can be changed with the -m flag). Three
75 * probes (change with -q flag) are sent at each ttl setting and a
76 * line is printed showing the ttl, address of the gateway and
77 * round trip time of each probe. If the probe answers come from
78 * different gateways, the address of each responding system will
79 * be printed. If there is no response within a 5 sec. timeout
80 * interval (changed with the -w flag), a "*" is printed for that
81 * probe.
82 *
83 * Probe packets are UDP format. We don't want the destination
84 * host to process them so the destination port is set to an
85 * unlikely value (if some clod on the destination is using that
86 * value, it can be changed with the -p flag).
87 *
88 * A sample use might be:
89 *
90 * [yak 71]% traceroute nis.nsf.net.
91 * traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 56 byte packet
92 * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
93 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
94 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
95 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
96 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
97 * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
98 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
99 * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
100 * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
101 * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
102 * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
103 *
104 * Note that lines 2 & 3 are the same. This is due to a buggy
105 * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
106 * packets with a zero ttl.
107 *
108 * A more interesting example is:
109 *
110 * [yak 72]% traceroute allspice.lcs.mit.edu.
111 * traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max
112 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
113 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
114 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
115 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
116 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
117 * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
118 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
119 * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
120 * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
121 * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
122 * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
123 * 12 * * *
124 * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
125 * 14 * * *
126 * 15 * * *
127 * 16 * * *
128 * 17 * * *
129 * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
130 *
131 * (I start to see why I'm having so much trouble with mail to
132 * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away
133 * either don't send ICMP "time exceeded" messages or send them
134 * with a ttl too small to reach us. 14 - 17 are running the
135 * MIT C Gateway code that doesn't send "time exceeded"s. God
136 * only knows what's going on with 12.
137 *
138 * The silent gateway 12 in the above may be the result of a bug in
139 * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3)
140 * sends an unreachable message using whatever ttl remains in the
141 * original datagram. Since, for gateways, the remaining ttl is
142 * zero, the icmp "time exceeded" is guaranteed to not make it back
143 * to us. The behavior of this bug is slightly more interesting
144 * when it appears on the destination system:
145 *
146 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
147 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
148 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
149 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
150 * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
151 * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
152 * 7 * * *
153 * 8 * * *
154 * 9 * * *
155 * 10 * * *
156 * 11 * * *
157 * 12 * * *
158 * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
159 *
160 * Notice that there are 12 "gateways" (13 is the final
161 * destination) and exactly the last half of them are "missing".
162 * What's really happening is that rip (a Sun-3 running Sun OS3.5)
163 * is using the ttl from our arriving datagram as the ttl in its
164 * icmp reply. So, the reply will time out on the return path
165 * (with no notice sent to anyone since icmp's aren't sent for
166 * icmp's) until we probe with a ttl that's at least twice the path
167 * length. I.e., rip is really only 7 hops away. A reply that
168 * returns with a ttl of 1 is a clue this problem exists.
169 * Traceroute prints a "!" after the time if the ttl is <= 1.
170 * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
171 * non-standard (HPUX) software, expect to see this problem
172 * frequently and/or take care picking the target host of your
173 * probes.
174 *
175 * Other possible annotations after the time are !H, !N, !P (got a host,
176 * network or protocol unreachable, respectively), !S or !F (source
177 * route failed or fragmentation needed -- neither of these should
178 * ever occur and the associated gateway is busted if you see one). If
179 * almost all the probes result in some kind of unreachable, traceroute
180 * will give up and exit.
181 *
182 * Notes
183 * -----
184 * This program must be run by root or be setuid. (I suggest that
185 * you *don't* make it setuid -- casual use could result in a lot
186 * of unnecessary traffic on our poor, congested nets.)
187 *
188 * This program requires a kernel mod that does not appear in any
189 * system available from Berkeley: A raw ip socket using proto
190 * IPPROTO_RAW must interpret the data sent as an ip datagram (as
191 * opposed to data to be wrapped in a ip datagram). See the README
192 * file that came with the source to this program for a description
193 * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may
194 * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
195 * MODIFIED TO RUN THIS PROGRAM.
196 *
197 * The udp port usage may appear bizarre (well, ok, it is bizarre).
198 * The problem is that an icmp message only contains 8 bytes of
199 * data from the original datagram. 8 bytes is the size of a udp
200 * header so, if we want to associate replies with the original
201 * datagram, the necessary information must be encoded into the
202 * udp header (the ip id could be used but there's no way to
203 * interlock with the kernel's assignment of ip id's and, anyway,
204 * it would have taken a lot more kernel hacking to allow this
205 * code to set the ip id). So, to allow two or more users to
206 * use traceroute simultaneously, we use this task's pid as the
207 * source port (the high bit is set to move the port number out
208 * of the "likely" range). To keep track of which probe is being
209 * replied to (so times and/or hop counts don't get confused by a
210 * reply that was delayed in transit), we increment the destination
211 * port number before each probe.
212 *
213 * Don't use this as a coding example. I was trying to find a
214 * routing problem and this code sort-of popped out after 48 hours
215 * without sleep. I was amazed it ever compiled, much less ran.
216 *
217 * I stole the idea for this program from Steve Deering. Since
218 * the first release, I've learned that had I attended the right
219 * IETF working group meetings, I also could have stolen it from Guy
220 * Almes or Matt Mathis. I don't know (or care) who came up with
221 * the idea first. I envy the originators' perspicacity and I'm
222 * glad they didn't keep the idea a secret.
223 *
224 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
225 * enhancements to the original distribution.
226 *
227 * I've hacked up a round-trip-route version of this that works by
228 * sending a loose-source-routed udp datagram through the destination
229 * back to yourself. Unfortunately, SO many gateways botch source
230 * routing, the thing is almost worthless. Maybe one day...
231 *
232 * -- Van Jacobson (van@helios.ee.lbl.gov)
233 * Tue Dec 20 03:50:13 PST 1988
234 */
235
236#include <sys/socket.h>
237#include <sys/sysctl.h>
238#include <sys/time.h>
239#include <sys/uio.h>
240
241#include <netinet/in.h>
242#include <netinet/ip.h>
243#include <netinet/ip6.h>
244#include <netinet/ip_icmp.h>
245#include <netinet/icmp6.h>
246#include <netinet/udp.h>
247
248#include <arpa/inet.h>
249
250#include <err.h>
251#include <errno(*__errno()).h>
252#include <event.h>
253#include <limits.h>
254#include <netdb.h>
255#include <pwd.h>
256#include <stdio.h>
257#include <stdlib.h>
258#include <string.h>
259#include <unistd.h>
260
261#include "traceroute.h"
262
263int32_t sec_perturb;
264int32_t usec_perturb;
265
266u_char packet[512];
267u_char *outpacket; /* last inbound (icmp) packet */
268
269int rcvsock; /* receive (icmp) socket file descriptor */
270int sndsock; /* send (udp) socket file descriptor */
271
272int rcvhlim;
273struct in6_pktinfo *rcvpktinfo;
274
275int datalen; /* How much data */
276
277char *hostname;
278
279u_int16_t srcport;
280
281void usage(void);
282
283#define TRACEROUTE_USER"_traceroute" "_traceroute"
284
285void sock_read(int, short, void *);
286void send_timer(int, short, void *);
287
288struct tr_conf *conf; /* configuration defaults */
289struct tr_result *tr_results;
290struct sockaddr_in from4, to4;
291struct sockaddr_in6 from6, to6;
292struct sockaddr *from, *to;
293struct msghdr rcvmhdr;
294struct event timer_ev;
295int v6flag;
296int *waiting_ttls;
297int last_tos = 0;
298
299int
300main(int argc, char *argv[])
301{
302 int mib[4] = { CTL_NET4, PF_INET2, IPPROTO_IP0, IPCTL_DEFTTL3 };
303 char hbuf[NI_MAXHOST256];
304
305 struct addrinfo hints, *res;
306 struct hostent *hp;
307 struct ip *ip = NULL((void *)0);
308 struct iovec rcviov[2];
309 static u_char *rcvcmsgbuf;
310 struct passwd *pw;
311 struct event sock_ev;
312 struct timeval tv = {0, 0};
313
314 long l;
315 socklen_t len;
316 size_t size;
317
318 int ch;
319 int on = 1;
320 int error;
321 int headerlen; /* How long packet's header is */
322 int i;
323 int packetlen;
324 int rcvcmsglen;
325 int rcvsock4, rcvsock6;
326 int sndsock4, sndsock6;
327 u_int32_t tmprnd;
328 int v4sock_errno, v6sock_errno;
329
330 char *dest;
331 const char *errstr;
332
333 uid_t ouid, uid;
334 gid_t gid;
335
336 /* Cannot pledge due to special setsockopt()s below */
337 if (unveil("/", "r") == -1)
338 err(1, "unveil /");
339 if (unveil(NULL((void *)0), NULL((void *)0)) == -1)
340 err(1, "unveil");
341
342 if ((conf = calloc(1, sizeof(*conf))) == NULL((void *)0))
343 err(1,NULL((void *)0));
344
345 conf->first_ttl = 1;
346 conf->proto = IPPROTO_UDP17;
347 conf->max_ttl = IPDEFTTL64;
348 conf->nprobes = 3;
349 conf->expected_responses = 2; /* icmp + DNS */
350
351 /* start udp dest port # for probe packets */
352 conf->port = 32768+666;
353
354 memset(&rcvmhdr, 0, sizeof(rcvmhdr));
355 memset(&rcviov, 0, sizeof(rcviov));
356
357 rcvsock4 = rcvsock6 = sndsock4 = sndsock6 = -1;
Although the value stored to 'rcvsock6' is used in the enclosing expression, the value is never actually read from 'rcvsock6'
358 v4sock_errno = v6sock_errno = 0;
359
360 conf->waittime = 3 * 1000;
361
362 if ((rcvsock6 = socket(AF_INET624, SOCK_RAW3, IPPROTO_ICMPV658)) == -1)
363 v6sock_errno = errno(*__errno());
364 else if ((sndsock6 = socket(AF_INET624, SOCK_DGRAM2, 0)) == -1)
365 v6sock_errno = errno(*__errno());
366
367 if ((rcvsock4 = socket(AF_INET2, SOCK_RAW3, IPPROTO_ICMP1)) == -1)
368 v4sock_errno = errno(*__errno());
369 else if ((sndsock4 = socket(AF_INET2, SOCK_RAW3, IPPROTO_RAW255)) == -1)
370 v4sock_errno = errno(*__errno());
371
372 /* revoke privs */
373 ouid = getuid();
374 if (ouid == 0 && (pw = getpwnam(TRACEROUTE_USER"_traceroute")) != NULL((void *)0)) {
375 uid = pw->pw_uid;
376 gid = pw->pw_gid;
377 } else {
378 uid = getuid();
379 gid = getgid();
380 }
381 if (ouid && (setgroups(1, &gid) ||
382 setresgid(gid, gid, gid) ||
383 setresuid(uid, uid, uid)))
384 err(1, "unable to revoke privs");
385
386 if (strcmp("traceroute6", __progname) == 0) {
387 v6flag = 1;
388 if (v6sock_errno != 0)
389 errc(5, v6sock_errno, rcvsock6 < 0 ? "socket(ICMPv6)" :
390 "socket(SOCK_DGRAM)");
391 rcvsock = rcvsock6;
392 sndsock = sndsock6;
393 if (rcvsock4 >= 0)
394 close(rcvsock4);
395 if (sndsock4 >= 0)
396 close(sndsock4);
397 } else {
398 if (v4sock_errno != 0)
399 errc(5, v4sock_errno, rcvsock4 < 0 ? "icmp socket" :
400 "raw socket");
401 rcvsock = rcvsock4;
402 sndsock = sndsock4;
403 if (rcvsock6 >= 0)
404 close(rcvsock6);
405 if (sndsock6 >= 0)
406 close(sndsock6);
407 }
408
409 if (v6flag) {
410 mib[1] = PF_INET624;
411 mib[2] = IPPROTO_IPV641;
412 mib[3] = IPV6CTL_DEFHLIM3;
413 /* specify to tell receiving interface */
414 if (setsockopt(rcvsock, IPPROTO_IPV641, IPV6_RECVPKTINFO36, &on,
415 sizeof(on)) == -1)
416 err(1, "setsockopt(IPV6_RECVPKTINFO)");
417
418 /* specify to tell hoplimit field of received IP6 hdr */
419 if (setsockopt(rcvsock, IPPROTO_IPV641, IPV6_RECVHOPLIMIT37, &on,
420 sizeof(on)) == -1)
421 err(1, "setsockopt(IPV6_RECVHOPLIMIT)");
422 }
423
424 size = sizeof(i);
425 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &i, &size, NULL((void *)0), 0) == -1)
426 err(1, "sysctl");
427 conf->max_ttl = i;
428
429 while ((ch = getopt(argc, argv, v6flag ? "ADdf:Ilm:np:q:Ss:t:w:vV:" :
430 "ADdf:g:Ilm:nP:p:q:Ss:t:V:vw:x")) != -1)
431 switch (ch) {
432 case 'A':
433 conf->Aflag = 1;
434 conf->expected_responses++;
435 break;
436 case 'd':
437 conf->dflag = 1;
438 break;
439 case 'D':
440 conf->dump = 1;
441 break;
442 case 'f':
443 conf->first_ttl = strtonum(optarg, 1, conf->max_ttl,
444 &errstr);
445 if (errstr)
446 errx(1, "min ttl must be 1 to %u.",
447 conf->max_ttl);
448 break;
449 case 'g':
450 if (conf->lsrr >= MAX_LSRR((40 - 4) / 4))
451 errx(1, "too many gateways; max %d", MAX_LSRR((40 - 4) / 4));
452 if (inet_aton(optarg, &conf->gateway[conf->lsrr]) ==
453 0) {
454 hp = gethostbyname(optarg);
455 if (hp == 0)
456 errx(1, "unknown host %s", optarg);
457 memcpy(&conf->gateway[conf->lsrr], hp->h_addrh_addr_list[0],
458 hp->h_length);
459 }
460 if (++conf->lsrr == 1)
461 conf->lsrrlen = 4;
462 conf->lsrrlen += 4;
463 break;
464 case 'I':
465 if (conf->protoset)
466 errx(1, "protocol already set with -P");
467 conf->protoset = 1;
468 conf->proto = IPPROTO_ICMP1;
469 break;
470 case 'l':
471 conf->ttl_flag = 1;
472 break;
473 case 'm':
474 conf->max_ttl = strtonum(optarg, conf->first_ttl,
475 MAXTTL255, &errstr);
476 if (errstr)
477 errx(1, "max ttl must be %u to %u.",
478 conf->first_ttl, MAXTTL255);
479 break;
480 case 'n':
481 conf->nflag = 1;
482 conf->expected_responses--;
483 break;
484 case 'p':
485 conf->port = strtonum(optarg, 1, 65535, &errstr);
486 if (errstr)
487 errx(1, "port must be >0, <65536.");
488 break;
489 case 'P':
490 if (conf->protoset)
491 errx(1, "protocol already set with -I");
492 conf->protoset = 1;
493 conf->proto = strtonum(optarg, 1, IPPROTO_MAX256 - 1,
494 &errstr);
495 if (errstr) {
496 struct protoent *pent;
497
498 pent = getprotobyname(optarg);
499 if (pent)
500 conf->proto = pent->p_proto;
501 else
502 errx(1, "proto must be >=1, or a "
503 "name.");
504 }
505 break;
506 case 'q':
507 conf->nprobes = strtonum(optarg, 1, 1024, &errstr);
508 if (errstr)
509 errx(1, "nprobes must be >0.");
510 break;
511 case 's':
512 /*
513 * set the ip source address of the outbound
514 * probe (e.g., on a multi-homed host).
515 */
516 conf->source = optarg;
517 break;
518 case 'S':
519 conf->sump = 1;
520 break;
521 case 't':
522 if (!map_tos(optarg, &conf->tos)) {
523 if (strlen(optarg) > 1 && optarg[0] == '0' &&
524 optarg[1] == 'x') {
525 char *ep;
526 errno(*__errno()) = 0;
527 ep = NULL((void *)0);
528 l = strtol(optarg, &ep, 16);
529 if (errno(*__errno()) || !*optarg || *ep ||
530 l < 0 || l > 255)
531 errx(1, "illegal tos value %s",
532 optarg);
533 conf->tos = (int)l;
534 } else {
535 conf->tos = strtonum(optarg, 0, 255,
536 &errstr);
537 if (errstr)
538 errx(1, "illegal tos value %s",
539 optarg);
540 }
541 }
542 conf->tflag = 1;
543 last_tos = conf->tos;
544 break;
545 case 'v':
546 conf->verbose = 1;
547 break;
548 case 'V':
549 conf->rtableid = (unsigned int)strtonum(optarg, 0,
550 RT_TABLEID_MAX255, &errstr);
551 if (errstr)
552 errx(1, "rtable value is %s: %s",
553 errstr, optarg);
554 if (setsockopt(sndsock, SOL_SOCKET0xffff, SO_RTABLE0x1021,
555 &conf->rtableid, sizeof(conf->rtableid)) == -1)
556 err(1, "setsockopt SO_RTABLE");
557 if (setsockopt(rcvsock, SOL_SOCKET0xffff, SO_RTABLE0x1021,
558 &conf->rtableid, sizeof(conf->rtableid)) == -1)
559 err(1, "setsockopt SO_RTABLE");
560 break;
561 case 'w':
562 conf->waittime = strtonum(optarg, 1, INT_MAX2147483647, &errstr);
563 if (errstr)
564 errx(1, "wait must be >=1 sec.");
565 conf->waittime *= 1000;
566 break;
567 case 'x':
568 conf->xflag = 1;
569 break;
570 default:
571 usage();
572 }
573
574 if (ouid == 0 && (setgroups(1, &gid) ||
575 setresgid(gid, gid, gid) ||
576 setresuid(uid, uid, uid)))
577 err(1, "unable to revoke privs");
578
579 argc -= optind;
580 argv += optind;
581
582 if (argc < 1 || argc > 2)
583 usage();
584
585 tr_results = calloc(sizeof(struct tr_result), conf->max_ttl *
586 conf->nprobes);
587 if (tr_results == NULL((void *)0))
588 err(1, NULL((void *)0));
589
590 waiting_ttls = calloc(sizeof(int), conf->max_ttl);
591 for (i = 0; i < conf->max_ttl; i++)
592 waiting_ttls[i] = conf->nprobes * conf->expected_responses;
593
594 setvbuf(stdout(&__sF[1]), NULL((void *)0), _IOLBF1, 0);
595
596 conf->ident = (getpid() & 0xffff) | 0x8000;
597 tmprnd = arc4random();
598 sec_perturb = (tmprnd & 0x80000000) ? -(tmprnd & 0x7ff) :
599 (tmprnd & 0x7ff);
600 usec_perturb = arc4random();
601
602 memset(&to4, 0, sizeof(to4));
603 memset(&to6, 0, sizeof(to6));
604
605 dest = *argv;
606
607 memset(&hints, 0, sizeof(hints));
608 hints.ai_family = v6flag ? PF_INET624 : PF_INET2;
609 hints.ai_socktype = SOCK_RAW3;
610 hints.ai_protocol = 0;
611 hints.ai_flags = AI_CANONNAME2;
612 if ((error = getaddrinfo(dest, NULL((void *)0), &hints, &res)))
613 errx(1, "%s", gai_strerror(error));
614
615 switch (res->ai_family) {
616 case AF_INET2:
617 to = (struct sockaddr *)&to4;
618 from = (struct sockaddr *)&from4;
619 break;
620 case AF_INET624:
621 to = (struct sockaddr *)&to6;
622 from = (struct sockaddr *)&from6;
623 break;
624 default:
625 errx(1, "unsupported AF: %d", res->ai_family);
626 break;
627 }
628
629 memcpy(to, res->ai_addr, res->ai_addrlen);
630
631 if (!hostname) {
632 hostname = res->ai_canonname ? strdup(res->ai_canonname) : dest;
633 if (!hostname)
634 errx(1, "malloc");
635 }
636
637 if (res->ai_next) {
638 if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf,
639 sizeof(hbuf), NULL((void *)0), 0, NI_NUMERICHOST1) != 0)
640 strlcpy(hbuf, "?", sizeof(hbuf));
641 warnx("Warning: %s has multiple "
642 "addresses; using %s", hostname, hbuf);
643 }
644 freeaddrinfo(res);
645
646 if (*++argv) {
647 datalen = strtonum(*argv, 0, INT_MAX2147483647, &errstr);
648 if (errstr)
649 errx(1, "datalen out of range");
650 }
651
652 switch (to->sa_family) {
653 case AF_INET2:
654 switch (conf->proto) {
655 case IPPROTO_UDP17:
656 headerlen = (sizeof(struct ip) + conf->lsrrlen +
657 sizeof(struct udphdr) + sizeof(struct packetdata));
658 break;
659 case IPPROTO_ICMP1:
660 headerlen = (sizeof(struct ip) + conf->lsrrlen +
661 sizeof(struct icmp) + sizeof(struct packetdata));
662 break;
663 default:
664 headerlen = (sizeof(struct ip) + conf->lsrrlen +
665 sizeof(struct packetdata));
666 }
667
668 if (datalen < 0 || datalen > IP_MAXPACKET65535 - headerlen)
669 errx(1, "packet size must be 0 to %d.",
670 IP_MAXPACKET65535 - headerlen);
671
672 datalen += headerlen;
673
674 if ((outpacket = calloc(1, datalen)) == NULL((void *)0))
675 err(1, "calloc");
676
677 rcviov[0].iov_base = (caddr_t)packet;
678 rcviov[0].iov_len = sizeof(packet);
679 rcvmhdr.msg_name = (caddr_t)&from4;
680 rcvmhdr.msg_namelen = sizeof(from4);
681 rcvmhdr.msg_iov = rcviov;
682 rcvmhdr.msg_iovlen = 1;
683 rcvmhdr.msg_control = NULL((void *)0);
684 rcvmhdr.msg_controllen = 0;
685
686 ip = (struct ip *)outpacket;
687 if (conf->lsrr != 0) {
688 u_char *p = (u_char *)(ip + 1);
689
690 *p++ = IPOPT_NOP1;
691 *p++ = IPOPT_LSRR131;
692 *p++ = conf->lsrrlen - 1;
693 *p++ = IPOPT_MINOFF4;
694 conf->gateway[conf->lsrr] = to4.sin_addr;
695 for (i = 1; i <= conf->lsrr; i++) {
696 memcpy(p, &conf->gateway[i],
697 sizeof(struct in_addr));
698 p += sizeof(struct in_addr);
699 }
700 ip->ip_dst = conf->gateway[0];
701 } else
702 ip->ip_dst = to4.sin_addr;
703 ip->ip_off = htons(0)(__uint16_t)(__builtin_constant_p(0) ? (__uint16_t)(((__uint16_t
)(0) & 0xffU) << 8 | ((__uint16_t)(0) & 0xff00U
) >> 8) : __swap16md(0))
;
704 ip->ip_hl = (sizeof(struct ip) + conf->lsrrlen) >> 2;
705 ip->ip_p = conf->proto;
706 ip->ip_v = IPVERSION4;
707 ip->ip_tos = conf->tos;
708
709 if (setsockopt(sndsock, IPPROTO_IP0, IP_HDRINCL2,
710 &on, sizeof(on)) == -1)
711 err(6, "IP_HDRINCL");
712
713 if (conf->source) {
714 memset(&from4, 0, sizeof(from4));
715 from4.sin_family = AF_INET2;
716 if (inet_aton(conf->source, &from4.sin_addr) == 0)
717 errx(1, "unknown host %s", conf->source);
718 ip->ip_src = from4.sin_addr;
719 if (ouid != 0 &&
720 (ntohl(from4.sin_addr.s_addr)(__uint32_t)(__builtin_constant_p(from4.sin_addr.s_addr) ? (__uint32_t
)(((__uint32_t)(from4.sin_addr.s_addr) & 0xff) << 24
| ((__uint32_t)(from4.sin_addr.s_addr) & 0xff00) <<
8 | ((__uint32_t)(from4.sin_addr.s_addr) & 0xff0000) >>
8 | ((__uint32_t)(from4.sin_addr.s_addr) & 0xff000000) >>
24) : __swap32md(from4.sin_addr.s_addr))
& 0xff000000U) ==
721 0x7f000000U && (ntohl(to4.sin_addr.s_addr)(__uint32_t)(__builtin_constant_p(to4.sin_addr.s_addr) ? (__uint32_t
)(((__uint32_t)(to4.sin_addr.s_addr) & 0xff) << 24 |
((__uint32_t)(to4.sin_addr.s_addr) & 0xff00) << 8 |
((__uint32_t)(to4.sin_addr.s_addr) & 0xff0000) >> 8
| ((__uint32_t)(to4.sin_addr.s_addr) & 0xff000000) >>
24) : __swap32md(to4.sin_addr.s_addr))
&
722 0xff000000U) != 0x7f000000U)
723 errx(1, "source is on 127/8, destination is"
724 " not");
725 if (ouid && bind(sndsock, (struct sockaddr *)&from4,
726 sizeof(from4)) == -1)
727 err(1, "bind");
728 }
729 packetlen = datalen;
730 break;
731 case AF_INET624:
732 /*
733 * packetlen is the size of the complete IP packet sent and
734 * reported in the first line of output.
735 * For IPv4 this is equal to datalen since we are constructing
736 * a raw packet.
737 * For IPv6 we need to always add the size of the IP6 header
738 * and for UDP packets the size of the UDP header since they
739 * are prepended to the packet by the kernel
740 */
741 packetlen = sizeof(struct ip6_hdr);
742 switch (conf->proto) {
743 case IPPROTO_UDP17:
744 headerlen = sizeof(struct packetdata);
745 packetlen += sizeof(struct udphdr);
746 break;
747 case IPPROTO_ICMP1:
748 headerlen = sizeof(struct icmp6_hdr) +
749 sizeof(struct packetdata);
750 break;
751 default:
752 errx(1, "Unsupported proto: %hhu", conf->proto);
753 break;
754 }
755
756 if (datalen < 0 || datalen > IP_MAXPACKET65535 - headerlen)
757 errx(1, "packet size must be 0 to %d.",
758 IP_MAXPACKET65535 - headerlen);
759
760 datalen += headerlen;
761 packetlen += datalen;
762
763 if ((outpacket = calloc(1, datalen)) == NULL((void *)0))
764 err(1, "calloc");
765
766 /* initialize msghdr for receiving packets */
767 rcviov[0].iov_base = (caddr_t)packet;
768 rcviov[0].iov_len = sizeof(packet);
769 rcvmhdr.msg_name = (caddr_t)&from6;
770 rcvmhdr.msg_namelen = sizeof(from6);
771 rcvmhdr.msg_iov = rcviov;
772 rcvmhdr.msg_iovlen = 1;
773 rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof(struct
in6_pktinfo)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)
))
+
774 CMSG_SPACE(sizeof(int))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof(int))
+ (sizeof(long) - 1)) &~(sizeof(long) - 1)))
;
775
776 if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL((void *)0))
777 errx(1, "malloc");
778 rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
779 rcvmhdr.msg_controllen = rcvcmsglen;
780
781 /*
782 * Send UDP or ICMP
783 */
784 if (conf->proto == IPPROTO_ICMP1) {
785 close(sndsock);
786 sndsock = rcvsock;
787 }
788
789 /*
790 * Source selection
791 */
792 memset(&from6, 0, sizeof(from6));
793 if (conf->source) {
794 memset(&hints, 0, sizeof(hints));
795 hints.ai_family = AF_INET624;
796 hints.ai_socktype = SOCK_DGRAM2; /*dummy*/
797 hints.ai_flags = AI_NUMERICHOST4;
798 if ((error = getaddrinfo(conf->source, "0", &hints,
799 &res)))
800 errx(1, "%s: %s", conf->source,
801 gai_strerror(error));
802 memcpy(&from6, res->ai_addr, res->ai_addrlen);
803 freeaddrinfo(res);
804 } else {
805 struct sockaddr_in6 nxt;
806 int dummy;
807
808 nxt = to6;
809 nxt.sin6_port = htons(DUMMY_PORT)(__uint16_t)(__builtin_constant_p(10010) ? (__uint16_t)(((__uint16_t
)(10010) & 0xffU) << 8 | ((__uint16_t)(10010) &
0xff00U) >> 8) : __swap16md(10010))
;
810 if ((dummy = socket(AF_INET624, SOCK_DGRAM2, 0)) == -1)
811 err(1, "socket");
812 if (conf->rtableid > 0 &&
813 setsockopt(dummy, SOL_SOCKET0xffff, SO_RTABLE0x1021,
814 &conf->rtableid, sizeof(conf->rtableid)) == -1)
815 err(1, "setsockopt(SO_RTABLE)");
816 if (connect(dummy, (struct sockaddr *)&nxt,
817 nxt.sin6_len) == -1)
818 err(1, "connect");
819 len = sizeof(from6);
820 if (getsockname(dummy, (struct sockaddr *)&from6,
821 &len) == -1)
822 err(1, "getsockname");
823 close(dummy);
824 }
825
826 from6.sin6_port = htons(0)(__uint16_t)(__builtin_constant_p(0) ? (__uint16_t)(((__uint16_t
)(0) & 0xffU) << 8 | ((__uint16_t)(0) & 0xff00U
) >> 8) : __swap16md(0))
;
827 if (bind(sndsock, (struct sockaddr *)&from6, from6.sin6_len) == -1)
828 err(1, "bind sndsock");
829
830 if (conf->tflag) {
831 if (setsockopt(sndsock, IPPROTO_IPV641, IPV6_TCLASS61,
832 &conf->tos, sizeof(conf->tos)) == -1)
833 err(6, "IPV6_TCLASS");
834 }
835
836 len = sizeof(from6);
837 if (getsockname(sndsock, (struct sockaddr *)&from6, &len) == -1)
838 err(1, "getsockname");
839 srcport = ntohs(from6.sin6_port)(__uint16_t)(__builtin_constant_p(from6.sin6_port) ? (__uint16_t
)(((__uint16_t)(from6.sin6_port) & 0xffU) << 8 | ((
__uint16_t)(from6.sin6_port) & 0xff00U) >> 8) : __swap16md
(from6.sin6_port))
;
840 break;
841 default:
842 errx(1, "unsupported AF: %d", to->sa_family);
843 break;
844 }
845
846 if (conf->dflag) {
847 (void) setsockopt(rcvsock, SOL_SOCKET0xffff, SO_DEBUG0x0001,
848 &on, sizeof(on));
849 (void) setsockopt(sndsock, SOL_SOCKET0xffff, SO_DEBUG0x0001,
850 &on, sizeof(on));
851 }
852
853 if (setsockopt(sndsock, SOL_SOCKET0xffff, SO_SNDBUF0x1001,
854 &datalen, sizeof(datalen)) == -1)
855 err(6, "SO_SNDBUF");
856
857 if (conf->nflag && !conf->Aflag) {
858 if (pledge("stdio inet", NULL((void *)0)) == -1)
859 err(1, "pledge");
860 } else {
861 if (pledge("stdio inet dns", NULL((void *)0)) == -1)
862 err(1, "pledge");
863 }
864
865 if (getnameinfo(to, to->sa_len, hbuf,
866 sizeof(hbuf), NULL((void *)0), 0, NI_NUMERICHOST1))
867 strlcpy(hbuf, "(invalid)", sizeof(hbuf));
868 fprintf(stderr(&__sF[2]), "%s to %s (%s)", __progname, hostname, hbuf);
869 if (conf->source)
870 fprintf(stderr(&__sF[2]), " from %s", conf->source);
871 fprintf(stderr(&__sF[2]), ", %u hops max, %d byte packets\n", conf->max_ttl,
872 packetlen);
873 (void) fflush(stderr(&__sF[2]));
874
875 if (conf->first_ttl > 1)
876 printf("Skipping %u intermediate hops\n", conf->first_ttl - 1);
877
878 event_init();
879
880 event_set(&sock_ev, rcvsock, EV_READ0x02 | EV_PERSIST0x10, sock_read, NULL((void *)0));
881 event_add(&sock_ev, NULL((void *)0));
882 evtimer_set(&timer_ev, send_timer, &timer_ev)event_set(&timer_ev, -1, 0, send_timer, &timer_ev);
883 evtimer_add(&timer_ev, &tv)event_add(&timer_ev, &tv);
884 event_dispatch();
885}
886
887void
888usage(void)
889{
890 if (v6flag) {
891 fprintf(stderr(&__sF[2]), "usage: %s "
892 "[-ADdIlnSv] [-f first_hop] [-m max_hop] [-p port]\n"
893 "\t[-q nqueries] [-s sourceaddr] [-t toskeyword] [-V rtable] "
894 "[-w waittime]\n\thost [datalen]\n", __progname);
895 } else {
896 fprintf(stderr(&__sF[2]),
897 "usage: %s [-ADdIlnSvx] [-f first_ttl] [-g gateway_addr] "
898 "[-m max_ttl]\n"
899 "\t[-P proto] [-p port] [-q nqueries] [-s sourceaddr]\n"
900 "\t[-t toskeyword] "
901 "[-V rtable] [-w waittime] host [datalen]\n",
902 __progname);
903 }
904 exit(1);
905}
906
907void
908sock_read(int fd, short events, void *arg)
909{
910 struct ip *ip;
911 struct timeval t2, tv = {0, 0};
912 int pkg_ok, cc, recv_seq, recv_seq_row;
913 char hbuf[NI_MAXHOST256];
914
915 cc = recvmsg(rcvsock, &rcvmhdr, 0);
916
917 if (cc == 0)
918 return;
919
920 evtimer_add(&timer_ev, &tv)event_add(&timer_ev, &tv);
921
922 gettime(&t2);
923
924 pkg_ok = packet_ok(conf, to->sa_family, &rcvmhdr, cc, &recv_seq);
925
926 /* Skip wrong packet */
927 if (pkg_ok == 0)
928 goto out;
929
930 /* skip corrupt sequence number */
931 if (recv_seq < 0 || recv_seq >= conf->max_ttl * conf->nprobes)
932 goto out;
933
934 recv_seq_row = recv_seq / conf->nprobes;
935
936 /* skipping dup */
937 if (tr_results[recv_seq].dup++)
938 goto out;
939
940 switch (to->sa_family) {
941 case AF_INET2:
942 ip = (struct ip *)packet;
943
944 print(conf, from, cc - (ip->ip_hl << 2), inet_ntop(AF_INET2,
945 &ip->ip_dst, hbuf, sizeof(hbuf)), &tr_results[recv_seq]);
946 break;
947 case AF_INET624:
948 print(conf, from, cc, rcvpktinfo ? inet_ntop(AF_INET624,
949 &rcvpktinfo->ipi6_addr, hbuf, sizeof(hbuf)) : "?",
950 &tr_results[recv_seq]);
951 break;
952 default:
953 errx(1, "unsupported AF: %d", to->sa_family);
954 }
955
956 tr_results[recv_seq].t2 = t2;
957 tr_results[recv_seq].resp_ttl = v6flag ? rcvhlim : ip->ip_ttl;
958
959 waiting_ttls[recv_seq_row]--;
960
961 if (pkg_ok == -2) {
962 if ((v6flag && rcvhlim <= 1) ||
963 (!v6flag && ip->ip_ttl <=1))
964 snprintf(tr_results[recv_seq].icmp_code,
965 sizeof(tr_results[recv_seq].icmp_code), "%s", " !");
966 tr_results[recv_seq].got_there++;
967 } else {
968 if (to->sa_family == AF_INET2 && conf->tflag)
969 check_tos(ip, &last_tos, &tr_results[recv_seq]);
970 if (pkg_ok != -1) {
971 icmp_code(to->sa_family, pkg_ok - 1,
972 &tr_results[recv_seq].got_there,
973 &tr_results[recv_seq].unreachable,
974 &tr_results[recv_seq]);
975 }
976 }
977
978 if (cc && ((recv_seq + 1) % conf->nprobes) == 0 &&
979 (conf->xflag || conf->verbose))
980 print_exthdr(packet, cc, &tr_results[recv_seq]);
981 out:
982 catchup_result_rows(tr_results, conf);
983}
984
985void
986send_timer(int fd, short events, void *arg)
987{
988 static int seq;
989 struct timeval tv = {0, 30000}, t1;
990 struct event *ev = arg;
991 int ttl;
992
993 evtimer_add(ev, &tv)event_add(ev, &tv);
994
995 ttl = conf->first_ttl + seq / conf->nprobes;
996 if (ttl <= conf->max_ttl) {
997 gettime(&t1);
998 tr_results[seq].seq = seq;
999 tr_results[seq].row = seq / conf->nprobes;
1000 tr_results[seq].ttl = ttl;
1001 tr_results[seq].t1 = t1;
1002 send_probe(conf, seq, ttl, to);
1003 seq++;
1004 }
1005
1006 catchup_result_rows(tr_results, conf);
1007
1008}