1 |
|
|
/* $OpenBSD: worker.c,v 1.5 2017/08/03 17:36:06 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 |
|
|
#include <arpa/inet.h> |
66 |
|
|
#include <arpa/nameser.h> |
67 |
|
|
#include <endian.h> |
68 |
|
|
#include <err.h> |
69 |
|
|
#include <limits.h> |
70 |
|
|
#include <netdb.h> |
71 |
|
|
#include <netinet/icmp6.h> |
72 |
|
|
#include <netinet/in.h> |
73 |
|
|
#include <netinet/ip.h> |
74 |
|
|
#include <netinet/ip6.h> |
75 |
|
|
#include <netinet/ip_icmp.h> |
76 |
|
|
#include <netinet/udp.h> |
77 |
|
|
#include <poll.h> |
78 |
|
|
#include <stdio.h> |
79 |
|
|
#include <string.h> |
80 |
|
|
#include <sys/socket.h> |
81 |
|
|
#include <sys/time.h> |
82 |
|
|
#include <sys/types.h> |
83 |
|
|
#include <sys/uio.h> |
84 |
|
|
#include <time.h> |
85 |
|
|
#include <unistd.h> |
86 |
|
|
|
87 |
|
|
#include "traceroute.h" |
88 |
|
|
|
89 |
|
|
static u_int8_t icmp_type = ICMP_ECHO; /* default ICMP code/type */ |
90 |
|
|
|
91 |
|
|
void |
92 |
|
|
print_exthdr(u_char *buf, int cc) |
93 |
|
|
{ |
94 |
|
|
struct icmp_ext_hdr exthdr; |
95 |
|
|
struct icmp_ext_obj_hdr objhdr; |
96 |
|
|
struct ip *ip; |
97 |
|
|
struct icmp *icp; |
98 |
|
|
int hlen, first; |
99 |
|
|
u_int32_t label; |
100 |
|
|
u_int16_t off, olen; |
101 |
|
|
u_int8_t type; |
102 |
|
|
|
103 |
|
|
ip = (struct ip *)buf; |
104 |
|
|
hlen = ip->ip_hl << 2; |
105 |
|
|
if (cc < hlen + ICMP_MINLEN) |
106 |
|
|
return; |
107 |
|
|
icp = (struct icmp *)(buf + hlen); |
108 |
|
|
cc -= hlen + ICMP_MINLEN; |
109 |
|
|
buf += hlen + ICMP_MINLEN; |
110 |
|
|
|
111 |
|
|
type = icp->icmp_type; |
112 |
|
|
if (type != ICMP_TIMXCEED && type != ICMP_UNREACH && |
113 |
|
|
type != ICMP_PARAMPROB) |
114 |
|
|
/* Wrong ICMP type for extension */ |
115 |
|
|
return; |
116 |
|
|
|
117 |
|
|
off = icp->icmp_length * sizeof(u_int32_t); |
118 |
|
|
if (off == 0) |
119 |
|
|
/* |
120 |
|
|
* rfc 4884 Section 5.5: traceroute MUST try to parse |
121 |
|
|
* broken ext headers. Again IETF bent over to please |
122 |
|
|
* idotic corporations. |
123 |
|
|
*/ |
124 |
|
|
off = ICMP_EXT_OFFSET; |
125 |
|
|
else if (off < ICMP_EXT_OFFSET) |
126 |
|
|
/* rfc 4884 requires an offset of at least 128 bytes */ |
127 |
|
|
return; |
128 |
|
|
|
129 |
|
|
/* make sure that at least one extension is present */ |
130 |
|
|
if (cc < off + sizeof(exthdr) + sizeof(objhdr)) |
131 |
|
|
/* Not enough space for ICMP extensions */ |
132 |
|
|
return; |
133 |
|
|
|
134 |
|
|
cc -= off; |
135 |
|
|
buf += off; |
136 |
|
|
memcpy(&exthdr, buf, sizeof(exthdr)); |
137 |
|
|
|
138 |
|
|
/* verify version */ |
139 |
|
|
if ((exthdr.ieh_version & ICMP_EXT_HDR_VMASK) != ICMP_EXT_HDR_VERSION) |
140 |
|
|
return; |
141 |
|
|
|
142 |
|
|
/* verify checksum */ |
143 |
|
|
if (exthdr.ieh_cksum && in_cksum((u_short *)buf, cc)) |
144 |
|
|
return; |
145 |
|
|
|
146 |
|
|
buf += sizeof(exthdr); |
147 |
|
|
cc -= sizeof(exthdr); |
148 |
|
|
|
149 |
|
|
while (cc > sizeof(objhdr)) { |
150 |
|
|
memcpy(&objhdr, buf, sizeof(objhdr)); |
151 |
|
|
olen = ntohs(objhdr.ieo_length); |
152 |
|
|
|
153 |
|
|
/* Sanity check the length field */ |
154 |
|
|
if (olen < sizeof(objhdr) || olen > cc) |
155 |
|
|
return; |
156 |
|
|
|
157 |
|
|
cc -= olen; |
158 |
|
|
|
159 |
|
|
/* Move past the object header */ |
160 |
|
|
buf += sizeof(objhdr); |
161 |
|
|
olen -= sizeof(objhdr); |
162 |
|
|
|
163 |
|
|
switch (objhdr.ieo_cnum) { |
164 |
|
|
case ICMP_EXT_MPLS: |
165 |
|
|
/* RFC 4950: ICMP Extensions for MPLS */ |
166 |
|
|
switch (objhdr.ieo_ctype) { |
167 |
|
|
case 1: |
168 |
|
|
first = 0; |
169 |
|
|
while (olen >= sizeof(u_int32_t)) { |
170 |
|
|
memcpy(&label, buf, sizeof(u_int32_t)); |
171 |
|
|
label = htonl(label); |
172 |
|
|
buf += sizeof(u_int32_t); |
173 |
|
|
olen -= sizeof(u_int32_t); |
174 |
|
|
|
175 |
|
|
if (first == 0) { |
176 |
|
|
printf(" [MPLS Label "); |
177 |
|
|
first++; |
178 |
|
|
} else |
179 |
|
|
printf(", "); |
180 |
|
|
printf("%d", MPLS_LABEL(label)); |
181 |
|
|
if (MPLS_EXP(label)) |
182 |
|
|
printf(" (Exp %x)", |
183 |
|
|
MPLS_EXP(label)); |
184 |
|
|
} |
185 |
|
|
if (olen > 0) { |
186 |
|
|
printf("|]"); |
187 |
|
|
return; |
188 |
|
|
} |
189 |
|
|
if (first != 0) |
190 |
|
|
printf("]"); |
191 |
|
|
break; |
192 |
|
|
default: |
193 |
|
|
buf += olen; |
194 |
|
|
break; |
195 |
|
|
} |
196 |
|
|
break; |
197 |
|
|
case ICMP_EXT_IFINFO: |
198 |
|
|
default: |
199 |
|
|
buf += olen; |
200 |
|
|
break; |
201 |
|
|
} |
202 |
|
|
} |
203 |
|
|
} |
204 |
|
|
|
205 |
|
|
void |
206 |
|
|
check_tos(struct ip *ip, int *last_tos) |
207 |
|
|
{ |
208 |
|
|
struct icmp *icp; |
209 |
|
|
struct ip *inner_ip; |
210 |
|
|
|
211 |
|
|
icp = (struct icmp *) (((u_char *)ip)+(ip->ip_hl<<2)); |
212 |
|
|
inner_ip = (struct ip *) (((u_char *)icp)+8); |
213 |
|
|
|
214 |
|
|
if (inner_ip->ip_tos != *last_tos) |
215 |
|
|
printf (" (TOS=%d!)", inner_ip->ip_tos); |
216 |
|
|
|
217 |
|
|
*last_tos = inner_ip->ip_tos; |
218 |
|
|
} |
219 |
|
|
|
220 |
|
|
int |
221 |
|
|
wait_for_reply(int sock, struct msghdr *mhdr, int curwaittime) |
222 |
|
|
{ |
223 |
|
|
struct pollfd pfd[1]; |
224 |
|
|
int cc = 0; |
225 |
|
|
|
226 |
|
|
pfd[0].fd = sock; |
227 |
|
|
pfd[0].events = POLLIN; |
228 |
|
|
pfd[0].revents = 0; |
229 |
|
|
|
230 |
|
|
if (poll(pfd, 1, curwaittime) > 0) |
231 |
|
|
cc = recvmsg(rcvsock, mhdr, 0); |
232 |
|
|
|
233 |
|
|
return (cc); |
234 |
|
|
} |
235 |
|
|
|
236 |
|
|
void |
237 |
|
|
dump_packet(void) |
238 |
|
|
{ |
239 |
|
|
u_char *p; |
240 |
|
|
int i; |
241 |
|
|
|
242 |
|
|
fprintf(stderr, "packet data:"); |
243 |
|
|
for (p = outpacket, i = 0; i < datalen; i++) { |
244 |
|
|
if ((i % 24) == 0) |
245 |
|
|
fprintf(stderr, "\n "); |
246 |
|
|
fprintf(stderr, " %02x", *p++); |
247 |
|
|
} |
248 |
|
|
fprintf(stderr, "\n"); |
249 |
|
|
} |
250 |
|
|
|
251 |
|
|
void |
252 |
|
|
build_probe4(struct tr_conf *conf, int seq, u_int8_t ttl, int iflag) |
253 |
|
|
{ |
254 |
|
|
struct ip *ip = (struct ip *)outpacket; |
255 |
|
|
u_char *p = (u_char *)(ip + 1); |
256 |
|
|
struct udphdr *up = (struct udphdr *)(p + conf->lsrrlen); |
257 |
|
|
struct icmp *icmpp = (struct icmp *)(p + conf->lsrrlen); |
258 |
|
|
struct packetdata *op; |
259 |
|
|
struct timeval tv; |
260 |
|
|
|
261 |
|
|
ip->ip_len = htons(datalen); |
262 |
|
|
ip->ip_ttl = ttl; |
263 |
|
|
ip->ip_id = htons(conf->ident+seq); |
264 |
|
|
|
265 |
|
|
switch (conf->proto) { |
266 |
|
|
case IPPROTO_ICMP: |
267 |
|
|
icmpp->icmp_type = icmp_type; |
268 |
|
|
icmpp->icmp_code = ICMP_CODE; |
269 |
|
|
icmpp->icmp_seq = htons(seq); |
270 |
|
|
icmpp->icmp_id = htons(conf->ident); |
271 |
|
|
op = (struct packetdata *)(icmpp + 1); |
272 |
|
|
break; |
273 |
|
|
case IPPROTO_UDP: |
274 |
|
|
up->uh_sport = htons(conf->ident); |
275 |
|
|
if (iflag) |
276 |
|
|
up->uh_dport = htons(conf->port+seq); |
277 |
|
|
else |
278 |
|
|
up->uh_dport = htons(conf->port); |
279 |
|
|
up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip) - |
280 |
|
|
conf->lsrrlen)); |
281 |
|
|
up->uh_sum = 0; |
282 |
|
|
op = (struct packetdata *)(up + 1); |
283 |
|
|
break; |
284 |
|
|
default: |
285 |
|
|
op = (struct packetdata *)(ip + 1); |
286 |
|
|
break; |
287 |
|
|
} |
288 |
|
|
op->seq = seq; |
289 |
|
|
op->ttl = ttl; |
290 |
|
|
gettime(&tv); |
291 |
|
|
|
292 |
|
|
/* |
293 |
|
|
* We don't want hostiles snooping the net to get any useful |
294 |
|
|
* information about us. Send the timestamp in network byte order, |
295 |
|
|
* and perturb the timestamp enough that they won't know our |
296 |
|
|
* real clock ticker. We don't want to perturb the time by too |
297 |
|
|
* much: being off by a suspiciously large amount might indicate |
298 |
|
|
* OpenBSD. |
299 |
|
|
* |
300 |
|
|
* The timestamps in the packet are currently unused. If future |
301 |
|
|
* work wants to use them they will have to subtract out the |
302 |
|
|
* perturbation first. |
303 |
|
|
*/ |
304 |
|
|
gettime(&tv); |
305 |
|
|
op->sec = htonl(tv.tv_sec + sec_perturb); |
306 |
|
|
op->usec = htonl((tv.tv_usec + usec_perturb) % 1000000); |
307 |
|
|
|
308 |
|
|
if (conf->proto == IPPROTO_ICMP && icmp_type == ICMP_ECHO) { |
309 |
|
|
icmpp->icmp_cksum = 0; |
310 |
|
|
icmpp->icmp_cksum = in_cksum((u_short *)icmpp, |
311 |
|
|
datalen - sizeof(struct ip) - conf->lsrrlen); |
312 |
|
|
if (icmpp->icmp_cksum == 0) |
313 |
|
|
icmpp->icmp_cksum = 0xffff; |
314 |
|
|
} |
315 |
|
|
} |
316 |
|
|
|
317 |
|
|
void |
318 |
|
|
build_probe6(struct tr_conf *conf, int seq, u_int8_t hops, int iflag, |
319 |
|
|
struct sockaddr *to) |
320 |
|
|
{ |
321 |
|
|
struct timeval tv; |
322 |
|
|
struct packetdata *op; |
323 |
|
|
int i; |
324 |
|
|
|
325 |
|
|
i = hops; |
326 |
|
|
if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, |
327 |
|
|
(char *)&i, sizeof(i)) < 0) |
328 |
|
|
warn("setsockopt IPV6_UNICAST_HOPS"); |
329 |
|
|
|
330 |
|
|
if (iflag) |
331 |
|
|
((struct sockaddr_in6*)to)->sin6_port = htons(conf->port + seq); |
332 |
|
|
else |
333 |
|
|
((struct sockaddr_in6*)to)->sin6_port = htons(conf->port); |
334 |
|
|
gettime(&tv); |
335 |
|
|
|
336 |
|
|
if (conf->proto == IPPROTO_ICMP) { |
337 |
|
|
struct icmp6_hdr *icp = (struct icmp6_hdr *)outpacket; |
338 |
|
|
|
339 |
|
|
icp->icmp6_type = ICMP6_ECHO_REQUEST; |
340 |
|
|
icp->icmp6_code = 0; |
341 |
|
|
icp->icmp6_cksum = 0; |
342 |
|
|
icp->icmp6_id = conf->ident; |
343 |
|
|
icp->icmp6_seq = htons(seq); |
344 |
|
|
op = (struct packetdata *)(outpacket + |
345 |
|
|
sizeof(struct icmp6_hdr)); |
346 |
|
|
} else |
347 |
|
|
op = (struct packetdata *)outpacket; |
348 |
|
|
op->seq = seq; |
349 |
|
|
op->ttl = hops; |
350 |
|
|
op->sec = htonl(tv.tv_sec); |
351 |
|
|
op->usec = htonl(tv.tv_usec); |
352 |
|
|
} |
353 |
|
|
|
354 |
|
|
void |
355 |
|
|
send_probe(struct tr_conf *conf, int seq, u_int8_t ttl, int iflag, |
356 |
|
|
struct sockaddr *to) |
357 |
|
|
{ |
358 |
|
|
int i; |
359 |
|
|
|
360 |
|
|
switch (to->sa_family) { |
361 |
|
|
case AF_INET: |
362 |
|
|
build_probe4(conf, seq, ttl, iflag); |
363 |
|
|
break; |
364 |
|
|
case AF_INET6: |
365 |
|
|
build_probe6(conf, seq, ttl, iflag, to); |
366 |
|
|
break; |
367 |
|
|
default: |
368 |
|
|
errx(1, "unsupported AF: %d", to->sa_family); |
369 |
|
|
break; |
370 |
|
|
} |
371 |
|
|
|
372 |
|
|
if (conf->dump) |
373 |
|
|
dump_packet(); |
374 |
|
|
|
375 |
|
|
i = sendto(sndsock, outpacket, datalen, 0, to, to->sa_len); |
376 |
|
|
if (i < 0 || i != datalen) { |
377 |
|
|
if (i < 0) |
378 |
|
|
warn("sendto"); |
379 |
|
|
printf("%s: wrote %s %d chars, ret=%d\n", __progname, hostname, |
380 |
|
|
datalen, i); |
381 |
|
|
(void) fflush(stdout); |
382 |
|
|
} |
383 |
|
|
} |
384 |
|
|
|
385 |
|
|
double |
386 |
|
|
deltaT(struct timeval *t1p, struct timeval *t2p) |
387 |
|
|
{ |
388 |
|
|
double dt; |
389 |
|
|
|
390 |
|
|
dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + |
391 |
|
|
(double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; |
392 |
|
|
return (dt); |
393 |
|
|
} |
394 |
|
|
|
395 |
|
|
static char *ttab[] = { |
396 |
|
|
"Echo Reply", |
397 |
|
|
"ICMP 1", |
398 |
|
|
"ICMP 2", |
399 |
|
|
"Dest Unreachable", |
400 |
|
|
"Source Quench", |
401 |
|
|
"Redirect", |
402 |
|
|
"ICMP 6", |
403 |
|
|
"ICMP 7", |
404 |
|
|
"Echo", |
405 |
|
|
"Router Advert", |
406 |
|
|
"Router Solicit", |
407 |
|
|
"Time Exceeded", |
408 |
|
|
"Param Problem", |
409 |
|
|
"Timestamp", |
410 |
|
|
"Timestamp Reply", |
411 |
|
|
"Info Request", |
412 |
|
|
"Info Reply", |
413 |
|
|
"Mask Request", |
414 |
|
|
"Mask Reply" |
415 |
|
|
}; |
416 |
|
|
|
417 |
|
|
/* |
418 |
|
|
* Convert an ICMP "type" field to a printable string. |
419 |
|
|
*/ |
420 |
|
|
char * |
421 |
|
|
pr_type(u_int8_t t) |
422 |
|
|
{ |
423 |
|
|
if (t > 18) |
424 |
|
|
return ("OUT-OF-RANGE"); |
425 |
|
|
return (ttab[t]); |
426 |
|
|
} |
427 |
|
|
|
428 |
|
|
int |
429 |
|
|
packet_ok(struct tr_conf *conf, int af, struct msghdr *mhdr, int cc, int seq, |
430 |
|
|
int iflag) |
431 |
|
|
{ |
432 |
|
|
switch (af) { |
433 |
|
|
case AF_INET: |
434 |
|
|
return packet_ok4(conf, mhdr, cc, seq, iflag); |
435 |
|
|
break; |
436 |
|
|
case AF_INET6: |
437 |
|
|
return packet_ok6(conf, mhdr, cc, seq, iflag); |
438 |
|
|
break; |
439 |
|
|
default: |
440 |
|
|
errx(1, "unsupported AF: %d", af); |
441 |
|
|
break; |
442 |
|
|
} |
443 |
|
|
} |
444 |
|
|
|
445 |
|
|
int |
446 |
|
|
packet_ok4(struct tr_conf *conf, struct msghdr *mhdr, int cc,int seq, int iflag) |
447 |
|
|
{ |
448 |
|
|
struct sockaddr_in *from = (struct sockaddr_in *)mhdr->msg_name; |
449 |
|
|
struct icmp *icp; |
450 |
|
|
u_char code; |
451 |
|
|
char *buf = (char *)mhdr->msg_iov[0].iov_base; |
452 |
|
|
u_int8_t type; |
453 |
|
|
int hlen; |
454 |
|
|
struct ip *ip; |
455 |
|
|
|
456 |
|
|
ip = (struct ip *) buf; |
457 |
|
|
hlen = ip->ip_hl << 2; |
458 |
|
|
if (cc < hlen + ICMP_MINLEN) { |
459 |
|
|
if (conf->verbose) |
460 |
|
|
printf("packet too short (%d bytes) from %s\n", cc, |
461 |
|
|
inet_ntoa(from->sin_addr)); |
462 |
|
|
return (0); |
463 |
|
|
} |
464 |
|
|
cc -= hlen; |
465 |
|
|
icp = (struct icmp *)(buf + hlen); |
466 |
|
|
type = icp->icmp_type; |
467 |
|
|
code = icp->icmp_code; |
468 |
|
|
if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || |
469 |
|
|
type == ICMP_UNREACH || type == ICMP_ECHOREPLY) { |
470 |
|
|
struct ip *hip; |
471 |
|
|
struct udphdr *up; |
472 |
|
|
struct icmp *icmpp; |
473 |
|
|
|
474 |
|
|
hip = &icp->icmp_ip; |
475 |
|
|
hlen = hip->ip_hl << 2; |
476 |
|
|
|
477 |
|
|
switch (conf->proto) { |
478 |
|
|
case IPPROTO_ICMP: |
479 |
|
|
if (icmp_type == ICMP_ECHO && |
480 |
|
|
type == ICMP_ECHOREPLY && |
481 |
|
|
icp->icmp_id == htons(conf->ident) && |
482 |
|
|
icp->icmp_seq == htons(seq)) |
483 |
|
|
return (-2); /* we got there */ |
484 |
|
|
|
485 |
|
|
icmpp = (struct icmp *)((u_char *)hip + hlen); |
486 |
|
|
if (hlen + 8 <= cc && hip->ip_p == IPPROTO_ICMP && |
487 |
|
|
icmpp->icmp_id == htons(conf->ident) && |
488 |
|
|
icmpp->icmp_seq == htons(seq)) |
489 |
|
|
return (type == ICMP_TIMXCEED? -1 : code + 1); |
490 |
|
|
break; |
491 |
|
|
|
492 |
|
|
case IPPROTO_UDP: |
493 |
|
|
up = (struct udphdr *)((u_char *)hip + hlen); |
494 |
|
|
if (hlen + 12 <= cc && hip->ip_p == conf->proto && |
495 |
|
|
up->uh_sport == htons(conf->ident) && |
496 |
|
|
((iflag && up->uh_dport == htons(conf->port + |
497 |
|
|
seq)) || |
498 |
|
|
(!iflag && up->uh_dport == htons(conf->port)))) |
499 |
|
|
return (type == ICMP_TIMXCEED? -1 : code + 1); |
500 |
|
|
break; |
501 |
|
|
default: |
502 |
|
|
/* this is some odd, user specified proto, |
503 |
|
|
* how do we check it? |
504 |
|
|
*/ |
505 |
|
|
if (hip->ip_p == conf->proto) |
506 |
|
|
return (type == ICMP_TIMXCEED? -1 : code + 1); |
507 |
|
|
} |
508 |
|
|
} |
509 |
|
|
if (conf->verbose) { |
510 |
|
|
int i; |
511 |
|
|
in_addr_t *lp = (in_addr_t *)&icp->icmp_ip; |
512 |
|
|
|
513 |
|
|
printf("\n%d bytes from %s", cc, inet_ntoa(from->sin_addr)); |
514 |
|
|
printf(" to %s", inet_ntoa(ip->ip_dst)); |
515 |
|
|
printf(": icmp type %u (%s) code %d\n", type, pr_type(type), |
516 |
|
|
icp->icmp_code); |
517 |
|
|
for (i = 4; i < cc ; i += sizeof(in_addr_t)) |
518 |
|
|
printf("%2d: x%8.8lx\n", i, (unsigned long)*lp++); |
519 |
|
|
} |
520 |
|
|
return (0); |
521 |
|
|
} |
522 |
|
|
|
523 |
|
|
int |
524 |
|
|
packet_ok6(struct tr_conf *conf, struct msghdr *mhdr, int cc, int seq, |
525 |
|
|
int iflag) |
526 |
|
|
{ |
527 |
|
|
struct icmp6_hdr *icp; |
528 |
|
|
struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; |
529 |
|
|
u_char type, code; |
530 |
|
|
char *buf = (char *)mhdr->msg_iov[0].iov_base; |
531 |
|
|
struct cmsghdr *cm; |
532 |
|
|
int *hlimp; |
533 |
|
|
char hbuf[NI_MAXHOST]; |
534 |
|
|
int useicmp = (conf->proto == IPPROTO_ICMP); |
535 |
|
|
|
536 |
|
|
if (cc < sizeof(struct icmp6_hdr)) { |
537 |
|
|
if (conf->verbose) { |
538 |
|
|
if (getnameinfo((struct sockaddr *)from, from->sin6_len, |
539 |
|
|
hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) |
540 |
|
|
strlcpy(hbuf, "invalid", sizeof(hbuf)); |
541 |
|
|
printf("data too short (%d bytes) from %s\n", cc, hbuf); |
542 |
|
|
} |
543 |
|
|
return(0); |
544 |
|
|
} |
545 |
|
|
icp = (struct icmp6_hdr *)buf; |
546 |
|
|
/* get optional information via advanced API */ |
547 |
|
|
rcvpktinfo = NULL; |
548 |
|
|
hlimp = NULL; |
549 |
|
|
for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; |
550 |
|
|
cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { |
551 |
|
|
if (cm->cmsg_level == IPPROTO_IPV6 && |
552 |
|
|
cm->cmsg_type == IPV6_PKTINFO && |
553 |
|
|
cm->cmsg_len == |
554 |
|
|
CMSG_LEN(sizeof(struct in6_pktinfo))) |
555 |
|
|
rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm)); |
556 |
|
|
|
557 |
|
|
if (cm->cmsg_level == IPPROTO_IPV6 && |
558 |
|
|
cm->cmsg_type == IPV6_HOPLIMIT && |
559 |
|
|
cm->cmsg_len == CMSG_LEN(sizeof(int))) |
560 |
|
|
hlimp = (int *)CMSG_DATA(cm); |
561 |
|
|
} |
562 |
|
|
if (rcvpktinfo == NULL || hlimp == NULL) { |
563 |
|
|
warnx("failed to get received hop limit or packet info"); |
564 |
|
|
rcvhlim = 0; /*XXX*/ |
565 |
|
|
} else |
566 |
|
|
rcvhlim = *hlimp; |
567 |
|
|
|
568 |
|
|
type = icp->icmp6_type; |
569 |
|
|
code = icp->icmp6_code; |
570 |
|
|
if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) |
571 |
|
|
|| type == ICMP6_DST_UNREACH) { |
572 |
|
|
struct ip6_hdr *hip; |
573 |
|
|
struct udphdr *up; |
574 |
|
|
|
575 |
|
|
hip = (struct ip6_hdr *)(icp + 1); |
576 |
|
|
if ((up = get_udphdr(conf, hip, (u_char *)(buf + cc))) == |
577 |
|
|
NULL) { |
578 |
|
|
if (conf->verbose) |
579 |
|
|
warnx("failed to get upper layer header"); |
580 |
|
|
return(0); |
581 |
|
|
} |
582 |
|
|
if (useicmp && |
583 |
|
|
((struct icmp6_hdr *)up)->icmp6_id == conf->ident && |
584 |
|
|
((struct icmp6_hdr *)up)->icmp6_seq == htons(seq)) |
585 |
|
|
return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1); |
586 |
|
|
else if (!useicmp && |
587 |
|
|
up->uh_sport == htons(srcport) && |
588 |
|
|
((iflag && up->uh_dport == htons(conf->port + seq)) || |
589 |
|
|
(!iflag && up->uh_dport == htons(conf->port)))) |
590 |
|
|
return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1); |
591 |
|
|
} else if (useicmp && type == ICMP6_ECHO_REPLY) { |
592 |
|
|
if (icp->icmp6_id == conf->ident && |
593 |
|
|
icp->icmp6_seq == htons(seq)) |
594 |
|
|
return (ICMP6_DST_UNREACH_NOPORT + 1); |
595 |
|
|
} |
596 |
|
|
if (conf->verbose) { |
597 |
|
|
char sbuf[NI_MAXHOST], dbuf[INET6_ADDRSTRLEN]; |
598 |
|
|
u_int8_t *p; |
599 |
|
|
int i; |
600 |
|
|
|
601 |
|
|
if (getnameinfo((struct sockaddr *)from, from->sin6_len, |
602 |
|
|
sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0) |
603 |
|
|
strlcpy(sbuf, "invalid", sizeof(sbuf)); |
604 |
|
|
printf("\n%d bytes from %s to %s", cc, sbuf, |
605 |
|
|
rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, |
606 |
|
|
dbuf, sizeof(dbuf)) : "?"); |
607 |
|
|
printf(": icmp type %d (%s) code %d\n", type, pr_type(type), |
608 |
|
|
icp->icmp6_code); |
609 |
|
|
p = (u_int8_t *)(icp + 1); |
610 |
|
|
#define WIDTH 16 |
611 |
|
|
for (i = 0; i < cc; i++) { |
612 |
|
|
if (i % WIDTH == 0) |
613 |
|
|
printf("%04x:", i); |
614 |
|
|
if (i % 4 == 0) |
615 |
|
|
printf(" "); |
616 |
|
|
printf("%02x", p[i]); |
617 |
|
|
if (i % WIDTH == WIDTH - 1) |
618 |
|
|
printf("\n"); |
619 |
|
|
} |
620 |
|
|
if (cc % WIDTH != 0) |
621 |
|
|
printf("\n"); |
622 |
|
|
} |
623 |
|
|
return(0); |
624 |
|
|
} |
625 |
|
|
|
626 |
|
|
void |
627 |
|
|
print(struct tr_conf *conf, struct sockaddr *from, int cc, const char *to) |
628 |
|
|
{ |
629 |
|
|
char hbuf[NI_MAXHOST]; |
630 |
|
|
if (getnameinfo(from, from->sa_len, |
631 |
|
|
hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) |
632 |
|
|
strlcpy(hbuf, "invalid", sizeof(hbuf)); |
633 |
|
|
if (conf->nflag) |
634 |
|
|
printf(" %s", hbuf); |
635 |
|
|
else |
636 |
|
|
printf(" %s (%s)", inetname(from), hbuf); |
637 |
|
|
|
638 |
|
|
if (conf->Aflag) |
639 |
|
|
print_asn((struct sockaddr_storage *)from); |
640 |
|
|
|
641 |
|
|
if (conf->verbose) |
642 |
|
|
printf(" %d bytes to %s", cc, to); |
643 |
|
|
} |
644 |
|
|
|
645 |
|
|
/* |
646 |
|
|
* Increment pointer until find the UDP or ICMP header. |
647 |
|
|
*/ |
648 |
|
|
struct udphdr * |
649 |
|
|
get_udphdr(struct tr_conf *conf, struct ip6_hdr *ip6, u_char *lim) |
650 |
|
|
{ |
651 |
|
|
u_char *cp = (u_char *)ip6, nh; |
652 |
|
|
int hlen; |
653 |
|
|
int useicmp = (conf->proto == IPPROTO_ICMP); |
654 |
|
|
|
655 |
|
|
if (cp + sizeof(*ip6) >= lim) |
656 |
|
|
return(NULL); |
657 |
|
|
|
658 |
|
|
nh = ip6->ip6_nxt; |
659 |
|
|
cp += sizeof(struct ip6_hdr); |
660 |
|
|
|
661 |
|
|
while (lim - cp >= 8) { |
662 |
|
|
switch (nh) { |
663 |
|
|
case IPPROTO_ESP: |
664 |
|
|
case IPPROTO_TCP: |
665 |
|
|
return(NULL); |
666 |
|
|
case IPPROTO_ICMPV6: |
667 |
|
|
return(useicmp ? (struct udphdr *)cp : NULL); |
668 |
|
|
case IPPROTO_UDP: |
669 |
|
|
return(useicmp ? NULL : (struct udphdr *)cp); |
670 |
|
|
case IPPROTO_FRAGMENT: |
671 |
|
|
hlen = sizeof(struct ip6_frag); |
672 |
|
|
nh = ((struct ip6_frag *)cp)->ip6f_nxt; |
673 |
|
|
break; |
674 |
|
|
case IPPROTO_AH: |
675 |
|
|
hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2; |
676 |
|
|
nh = ((struct ip6_ext *)cp)->ip6e_nxt; |
677 |
|
|
break; |
678 |
|
|
default: |
679 |
|
|
hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3; |
680 |
|
|
nh = ((struct ip6_ext *)cp)->ip6e_nxt; |
681 |
|
|
break; |
682 |
|
|
} |
683 |
|
|
|
684 |
|
|
cp += hlen; |
685 |
|
|
} |
686 |
|
|
|
687 |
|
|
return(NULL); |
688 |
|
|
} |
689 |
|
|
|
690 |
|
|
void |
691 |
|
|
icmp_code(int af, int code, int *got_there, int *unreachable) |
692 |
|
|
{ |
693 |
|
|
switch (af) { |
694 |
|
|
case AF_INET: |
695 |
|
|
icmp4_code(code, got_there, unreachable); |
696 |
|
|
break; |
697 |
|
|
case AF_INET6: |
698 |
|
|
icmp6_code(code, got_there, unreachable); |
699 |
|
|
break; |
700 |
|
|
default: |
701 |
|
|
errx(1, "unsupported AF: %d", af); |
702 |
|
|
break; |
703 |
|
|
} |
704 |
|
|
} |
705 |
|
|
|
706 |
|
|
void |
707 |
|
|
icmp4_code(int code, int *got_there, int *unreachable) |
708 |
|
|
{ |
709 |
|
|
struct ip *ip = (struct ip *)packet; |
710 |
|
|
|
711 |
|
|
switch (code) { |
712 |
|
|
case ICMP_UNREACH_PORT: |
713 |
|
|
if (ip->ip_ttl <= 1) |
714 |
|
|
printf(" !"); |
715 |
|
|
++(*got_there); |
716 |
|
|
break; |
717 |
|
|
case ICMP_UNREACH_NET: |
718 |
|
|
++(*unreachable); |
719 |
|
|
printf(" !N"); |
720 |
|
|
break; |
721 |
|
|
case ICMP_UNREACH_HOST: |
722 |
|
|
++(*unreachable); |
723 |
|
|
printf(" !H"); |
724 |
|
|
break; |
725 |
|
|
case ICMP_UNREACH_PROTOCOL: |
726 |
|
|
++(*got_there); |
727 |
|
|
printf(" !P"); |
728 |
|
|
break; |
729 |
|
|
case ICMP_UNREACH_NEEDFRAG: |
730 |
|
|
++(*unreachable); |
731 |
|
|
printf(" !F"); |
732 |
|
|
break; |
733 |
|
|
case ICMP_UNREACH_SRCFAIL: |
734 |
|
|
++(*unreachable); |
735 |
|
|
printf(" !S"); |
736 |
|
|
break; |
737 |
|
|
case ICMP_UNREACH_FILTER_PROHIB: |
738 |
|
|
++(*unreachable); |
739 |
|
|
printf(" !X"); |
740 |
|
|
break; |
741 |
|
|
case ICMP_UNREACH_NET_PROHIB: /*misuse*/ |
742 |
|
|
++(*unreachable); |
743 |
|
|
printf(" !A"); |
744 |
|
|
break; |
745 |
|
|
case ICMP_UNREACH_HOST_PROHIB: |
746 |
|
|
++(*unreachable); |
747 |
|
|
printf(" !C"); |
748 |
|
|
break; |
749 |
|
|
case ICMP_UNREACH_NET_UNKNOWN: |
750 |
|
|
case ICMP_UNREACH_HOST_UNKNOWN: |
751 |
|
|
++(*unreachable); |
752 |
|
|
printf(" !U"); |
753 |
|
|
break; |
754 |
|
|
case ICMP_UNREACH_ISOLATED: |
755 |
|
|
++(*unreachable); |
756 |
|
|
printf(" !I"); |
757 |
|
|
break; |
758 |
|
|
case ICMP_UNREACH_TOSNET: |
759 |
|
|
case ICMP_UNREACH_TOSHOST: |
760 |
|
|
++(*unreachable); |
761 |
|
|
printf(" !T"); |
762 |
|
|
break; |
763 |
|
|
default: |
764 |
|
|
++(*unreachable); |
765 |
|
|
printf(" !<%d>", code); |
766 |
|
|
break; |
767 |
|
|
} |
768 |
|
|
} |
769 |
|
|
|
770 |
|
|
void |
771 |
|
|
icmp6_code(int code, int *got_there, int *unreachable) |
772 |
|
|
{ |
773 |
|
|
switch (code) { |
774 |
|
|
case ICMP6_DST_UNREACH_NOROUTE: |
775 |
|
|
++(*unreachable); |
776 |
|
|
printf(" !N"); |
777 |
|
|
break; |
778 |
|
|
case ICMP6_DST_UNREACH_ADMIN: |
779 |
|
|
++(*unreachable); |
780 |
|
|
printf(" !P"); |
781 |
|
|
break; |
782 |
|
|
case ICMP6_DST_UNREACH_BEYONDSCOPE: |
783 |
|
|
++(*unreachable); |
784 |
|
|
printf(" !S"); |
785 |
|
|
break; |
786 |
|
|
case ICMP6_DST_UNREACH_ADDR: |
787 |
|
|
++(*unreachable); |
788 |
|
|
printf(" !A"); |
789 |
|
|
break; |
790 |
|
|
case ICMP6_DST_UNREACH_NOPORT: |
791 |
|
|
if (rcvhlim >= 0 && rcvhlim <= 1) |
792 |
|
|
printf(" !"); |
793 |
|
|
++(*got_there); |
794 |
|
|
break; |
795 |
|
|
default: |
796 |
|
|
++(*unreachable); |
797 |
|
|
printf(" !<%d>", code); |
798 |
|
|
break; |
799 |
|
|
} |
800 |
|
|
} |
801 |
|
|
|
802 |
|
|
/* |
803 |
|
|
* Checksum routine for Internet Protocol family headers (C Version) |
804 |
|
|
*/ |
805 |
|
|
u_short |
806 |
|
|
in_cksum(u_short *addr, int len) |
807 |
|
|
{ |
808 |
|
|
u_short *w = addr, answer; |
809 |
|
|
int nleft = len, sum = 0; |
810 |
|
|
|
811 |
|
|
/* |
812 |
|
|
* Our algorithm is simple, using a 32 bit accumulator (sum), |
813 |
|
|
* we add sequential 16 bit words to it, and at the end, fold |
814 |
|
|
* back all the carry bits from the top 16 bits into the lower |
815 |
|
|
* 16 bits. |
816 |
|
|
*/ |
817 |
|
|
while (nleft > 1) { |
818 |
|
|
sum += *w++; |
819 |
|
|
nleft -= 2; |
820 |
|
|
} |
821 |
|
|
|
822 |
|
|
/* mop up an odd byte, if necessary */ |
823 |
|
|
if (nleft == 1) |
824 |
|
|
sum += *(u_char *)w; |
825 |
|
|
|
826 |
|
|
/* |
827 |
|
|
* add back carry outs from top 16 bits to low 16 bits |
828 |
|
|
*/ |
829 |
|
|
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ |
830 |
|
|
sum += (sum >> 16); /* add carry */ |
831 |
|
|
answer = ~sum; /* truncate to 16 bits */ |
832 |
|
|
return (answer); |
833 |
|
|
} |
834 |
|
|
|
835 |
|
|
/* |
836 |
|
|
* Construct an Internet address representation. |
837 |
|
|
*/ |
838 |
|
|
const char * |
839 |
|
|
inetname(struct sockaddr *sa) |
840 |
|
|
{ |
841 |
|
|
static char line[NI_MAXHOST], domain[HOST_NAME_MAX + 1]; |
842 |
|
|
static int first = 1; |
843 |
|
|
char *cp; |
844 |
|
|
|
845 |
|
|
if (first) { |
846 |
|
|
first = 0; |
847 |
|
|
if (gethostname(domain, sizeof(domain)) == 0 && |
848 |
|
|
(cp = strchr(domain, '.')) != NULL) |
849 |
|
|
memmove(domain, cp + 1, strlen(cp + 1) + 1); |
850 |
|
|
else |
851 |
|
|
domain[0] = 0; |
852 |
|
|
} |
853 |
|
|
if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, |
854 |
|
|
NI_NAMEREQD) == 0) { |
855 |
|
|
if ((cp = strchr(line, '.')) != NULL && strcmp(cp + 1, |
856 |
|
|
domain) == 0) |
857 |
|
|
*cp = '\0'; |
858 |
|
|
return (line); |
859 |
|
|
} |
860 |
|
|
|
861 |
|
|
if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, |
862 |
|
|
NI_NUMERICHOST) != 0) |
863 |
|
|
return ("invalid"); |
864 |
|
|
return (line); |
865 |
|
|
} |
866 |
|
|
|
867 |
|
|
void |
868 |
|
|
print_asn(struct sockaddr_storage *ss) |
869 |
|
|
{ |
870 |
|
|
struct rrsetinfo *answers = NULL; |
871 |
|
|
int counter; |
872 |
|
|
const u_char *uaddr; |
873 |
|
|
char qbuf[MAXDNAME]; |
874 |
|
|
|
875 |
|
|
switch (ss->ss_family) { |
876 |
|
|
case AF_INET: |
877 |
|
|
uaddr = (const u_char *)&((struct sockaddr_in *) ss)->sin_addr; |
878 |
|
|
if (snprintf(qbuf, sizeof qbuf, "%u.%u.%u.%u." |
879 |
|
|
"origin.asn.cymru.com", |
880 |
|
|
(uaddr[3] & 0xff), (uaddr[2] & 0xff), |
881 |
|
|
(uaddr[1] & 0xff), (uaddr[0] & 0xff)) >= sizeof (qbuf)) |
882 |
|
|
return; |
883 |
|
|
break; |
884 |
|
|
case AF_INET6: |
885 |
|
|
uaddr = (const u_char *)&((struct sockaddr_in6 *) ss)->sin6_addr; |
886 |
|
|
if (snprintf(qbuf, sizeof qbuf, |
887 |
|
|
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." |
888 |
|
|
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." |
889 |
|
|
"origin6.asn.cymru.com", |
890 |
|
|
(uaddr[15] & 0x0f), ((uaddr[15] >>4)& 0x0f), |
891 |
|
|
(uaddr[14] & 0x0f), ((uaddr[14] >>4)& 0x0f), |
892 |
|
|
(uaddr[13] & 0x0f), ((uaddr[13] >>4)& 0x0f), |
893 |
|
|
(uaddr[12] & 0x0f), ((uaddr[12] >>4)& 0x0f), |
894 |
|
|
(uaddr[11] & 0x0f), ((uaddr[11] >>4)& 0x0f), |
895 |
|
|
(uaddr[10] & 0x0f), ((uaddr[10] >>4)& 0x0f), |
896 |
|
|
(uaddr[9] & 0x0f), ((uaddr[9] >>4)& 0x0f), |
897 |
|
|
(uaddr[8] & 0x0f), ((uaddr[8] >>4)& 0x0f), |
898 |
|
|
(uaddr[7] & 0x0f), ((uaddr[7] >>4)& 0x0f), |
899 |
|
|
(uaddr[6] & 0x0f), ((uaddr[6] >>4)& 0x0f), |
900 |
|
|
(uaddr[5] & 0x0f), ((uaddr[5] >>4)& 0x0f), |
901 |
|
|
(uaddr[4] & 0x0f), ((uaddr[4] >>4)& 0x0f), |
902 |
|
|
(uaddr[3] & 0x0f), ((uaddr[3] >>4)& 0x0f), |
903 |
|
|
(uaddr[2] & 0x0f), ((uaddr[2] >>4)& 0x0f), |
904 |
|
|
(uaddr[1] & 0x0f), ((uaddr[1] >>4)& 0x0f), |
905 |
|
|
(uaddr[0] & 0x0f), ((uaddr[0] >>4)& 0x0f)) >= sizeof (qbuf)) |
906 |
|
|
return; |
907 |
|
|
break; |
908 |
|
|
default: |
909 |
|
|
return; |
910 |
|
|
} |
911 |
|
|
|
912 |
|
|
if (getrrsetbyname(qbuf, C_IN, T_TXT, 0, &answers) != 0) |
913 |
|
|
return; |
914 |
|
|
for (counter = 0; counter < answers->rri_nrdatas; counter++) { |
915 |
|
|
char *p, *as = answers->rri_rdatas[counter].rdi_data; |
916 |
|
|
as++; /* skip first byte, it contains length */ |
917 |
|
|
if ((p = strchr(as,'|'))) { |
918 |
|
|
printf(counter ? ", " : " ["); |
919 |
|
|
p[-1] = 0; |
920 |
|
|
printf("AS%s", as); |
921 |
|
|
} |
922 |
|
|
} |
923 |
|
|
if (counter) |
924 |
|
|
printf("]"); |
925 |
|
|
|
926 |
|
|
freerrset(answers); |
927 |
|
|
} |
928 |
|
|
|
929 |
|
|
int |
930 |
|
|
map_tos(char *s, int *val) |
931 |
|
|
{ |
932 |
|
|
/* DiffServ Codepoints and other TOS mappings */ |
933 |
|
|
const struct toskeywords { |
934 |
|
|
const char *keyword; |
935 |
|
|
int val; |
936 |
|
|
} *t, toskeywords[] = { |
937 |
|
|
{ "af11", IPTOS_DSCP_AF11 }, |
938 |
|
|
{ "af12", IPTOS_DSCP_AF12 }, |
939 |
|
|
{ "af13", IPTOS_DSCP_AF13 }, |
940 |
|
|
{ "af21", IPTOS_DSCP_AF21 }, |
941 |
|
|
{ "af22", IPTOS_DSCP_AF22 }, |
942 |
|
|
{ "af23", IPTOS_DSCP_AF23 }, |
943 |
|
|
{ "af31", IPTOS_DSCP_AF31 }, |
944 |
|
|
{ "af32", IPTOS_DSCP_AF32 }, |
945 |
|
|
{ "af33", IPTOS_DSCP_AF33 }, |
946 |
|
|
{ "af41", IPTOS_DSCP_AF41 }, |
947 |
|
|
{ "af42", IPTOS_DSCP_AF42 }, |
948 |
|
|
{ "af43", IPTOS_DSCP_AF43 }, |
949 |
|
|
{ "critical", IPTOS_PREC_CRITIC_ECP }, |
950 |
|
|
{ "cs0", IPTOS_DSCP_CS0 }, |
951 |
|
|
{ "cs1", IPTOS_DSCP_CS1 }, |
952 |
|
|
{ "cs2", IPTOS_DSCP_CS2 }, |
953 |
|
|
{ "cs3", IPTOS_DSCP_CS3 }, |
954 |
|
|
{ "cs4", IPTOS_DSCP_CS4 }, |
955 |
|
|
{ "cs5", IPTOS_DSCP_CS5 }, |
956 |
|
|
{ "cs6", IPTOS_DSCP_CS6 }, |
957 |
|
|
{ "cs7", IPTOS_DSCP_CS7 }, |
958 |
|
|
{ "ef", IPTOS_DSCP_EF }, |
959 |
|
|
{ "inetcontrol", IPTOS_PREC_INTERNETCONTROL }, |
960 |
|
|
{ "lowdelay", IPTOS_LOWDELAY }, |
961 |
|
|
{ "netcontrol", IPTOS_PREC_NETCONTROL }, |
962 |
|
|
{ "reliability", IPTOS_RELIABILITY }, |
963 |
|
|
{ "throughput", IPTOS_THROUGHPUT }, |
964 |
|
|
{ NULL, -1 }, |
965 |
|
|
}; |
966 |
|
|
|
967 |
|
|
for (t = toskeywords; t->keyword != NULL; t++) { |
968 |
|
|
if (strcmp(s, t->keyword) == 0) { |
969 |
|
|
*val = t->val; |
970 |
|
|
return (1); |
971 |
|
|
} |
972 |
|
|
} |
973 |
|
|
|
974 |
|
|
return (0); |
975 |
|
|
} |
976 |
|
|
|
977 |
|
|
void |
978 |
|
|
gettime(struct timeval *tv) |
979 |
|
|
{ |
980 |
|
|
struct timespec ts; |
981 |
|
|
|
982 |
|
|
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) |
983 |
|
|
err(1, "clock_gettime(CLOCK_MONOTONIC)"); |
984 |
|
|
|
985 |
|
|
TIMESPEC_TO_TIMEVAL(tv, &ts); |
986 |
|
|
} |