trafgen: lexer/parser: fix cpu() selection and whitespacing
[netsniff-ng.git] / astraceroute.c
blob76b0818811d90f4dbec317e2b24cb6ba4cc2ff24
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * Copyright 2011 - 2013 Daniel Borkmann.
4 * Subject to the GPL, version 2.
5 */
7 #define _BSD_SOURCE
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <signal.h>
11 #include <getopt.h>
12 #include <ctype.h>
13 #include <stdint.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <sys/socket.h>
17 #include <sys/fsuid.h>
18 #include <fcntl.h>
19 #include <time.h>
20 #include <string.h>
21 #include <asm/byteorder.h>
22 #include <linux/tcp.h>
23 #include <netinet/ip.h>
24 #include <netinet/ip6.h>
25 #include <netinet/in.h>
26 #include <errno.h>
27 #include <netdb.h>
28 #include <sys/time.h>
29 #include <arpa/inet.h>
30 #include <linux/if_ether.h>
31 #include <linux/icmp.h>
32 #include <linux/icmpv6.h>
34 #include "bpf.h"
35 #include "die.h"
36 #include "tprintf.h"
37 #include "pkt_buff.h"
38 #include "proto.h"
39 #include "xmalloc.h"
40 #include "xio.h"
41 #include "csum.h"
42 #include "geoip.h"
43 #include "xutils.h"
44 #include "ring_rx.h"
45 #include "built_in.h"
47 struct ctx {
48 char *host, *port, *dev, *payload;
49 int init_ttl, max_ttl, dns_resolv, queries, timeout, totlen, rcvlen;
50 int syn, ack, ecn, fin, psh, rst, urg, tos, nofrag, proto, show;
51 int sd_len, dport, latitude;
54 struct proto_ops {
55 int (*assembler)(uint8_t *packet, size_t len, int ttl, int proto,
56 const struct ctx *ctx, const struct sockaddr *dst,
57 const struct sockaddr *src);
58 const struct sock_filter *filter;
59 unsigned int flen;
60 unsigned int min_len_tcp, min_len_icmp;
61 int (*check)(uint8_t *packet, size_t len, int ttl, int id,
62 const struct sockaddr *src);
63 void (*handler)(uint8_t *packet, size_t len, int dns_resolv,
64 int latitude);
67 sig_atomic_t sigint = 0;
69 static int assemble_ipv4(uint8_t *packet, size_t len, int ttl, int proto,
70 const struct ctx *ctx, const struct sockaddr *dst,
71 const struct sockaddr *src);
72 static int assemble_ipv6(uint8_t *packet, size_t len, int ttl, int proto,
73 const struct ctx *ctx, const struct sockaddr *dst,
74 const struct sockaddr *src);
75 static int check_ipv4(uint8_t *packet, size_t len, int ttl, int id,
76 const struct sockaddr *ss);
77 static void handle_ipv4(uint8_t *packet, size_t len, int dns_resolv,
78 int latitude);
79 static int check_ipv6(uint8_t *packet, size_t len, int ttl, int id,
80 const struct sockaddr *ss);
81 static void handle_ipv6(uint8_t *packet, size_t len, int dns_resolv,
82 int latitude);
84 static const char *short_options = "H:p:nNf:m:i:d:q:x:SAEFPURt:Gl:hv46X:ZuL";
85 static const struct option long_options[] = {
86 {"host", required_argument, NULL, 'H'},
87 {"port", required_argument, NULL, 'p'},
88 {"init-ttl", required_argument, NULL, 'f'},
89 {"max-ttl", required_argument, NULL, 'm'},
90 {"dev", required_argument, NULL, 'd'},
91 {"num-probes", required_argument, NULL, 'q'},
92 {"timeout", required_argument, NULL, 'x'},
93 {"tos", required_argument, NULL, 't'},
94 {"payload", required_argument, NULL, 'X'},
95 {"totlen", required_argument, NULL, 'l'},
96 {"numeric", no_argument, NULL, 'n'},
97 {"latitude", no_argument, NULL, 'L'},
98 {"update", no_argument, NULL, 'u'},
99 {"dns", no_argument, NULL, 'N'},
100 {"ipv4", no_argument, NULL, '4'},
101 {"ipv6", no_argument, NULL, '6'},
102 {"syn", no_argument, NULL, 'S'},
103 {"ack", no_argument, NULL, 'A'},
104 {"urg", no_argument, NULL, 'U'},
105 {"fin", no_argument, NULL, 'F'},
106 {"psh", no_argument, NULL, 'P'},
107 {"rst", no_argument, NULL, 'R'},
108 {"ecn-syn", no_argument, NULL, 'E'},
109 {"show-packet", no_argument, NULL, 'Z'},
110 {"nofrag", no_argument, NULL, 'G'},
111 {"version", no_argument, NULL, 'v'},
112 {"help", no_argument, NULL, 'h'},
113 {NULL, 0, NULL, 0}
116 static const struct sock_filter ipv4_icmp_type_11[] = {
117 { 0x28, 0, 0, 0x0000000c }, /* ldh [12] */
118 { 0x15, 0, 8, 0x00000800 }, /* jneq #0x800, drop */
119 { 0x30, 0, 0, 0x00000017 }, /* ldb [23] */
120 { 0x15, 0, 6, 0x00000001 }, /* jneq #0x1, drop */
121 { 0x28, 0, 0, 0x00000014 }, /* ldh [20] */
122 { 0x45, 4, 0, 0x00001fff }, /* jset #0x1fff, drop */
123 { 0xb1, 0, 0, 0x0000000e }, /* ldxb 4*([14]&0xf) */
124 { 0x50, 0, 0, 0x0000000e }, /* ldb [x + 14] */
125 { 0x15, 0, 1, 0x0000000b }, /* jneq #0xb, drop */
126 { 0x06, 0, 0, 0xffffffff }, /* ret #-1 */
127 { 0x06, 0, 0, 0x00000000 }, /* drop: ret #0 */
130 static const struct sock_filter ipv6_icmp6_type_3[] = {
131 { 0x28, 0, 0, 0x0000000c }, /* ldh [12] */
132 { 0x15, 0, 5, 0x000086dd }, /* jneq #0x86dd, drop */
133 { 0x30, 0, 0, 0x00000014 }, /* ldb [20] */
134 { 0x15, 0, 3, 0x0000003a }, /* jneq #0x3a, drop */
135 { 0x30, 0, 0, 0x00000036 }, /* ldb [54] */
136 { 0x15, 0, 1, 0x00000003 }, /* jneq #0x3, drop */
137 { 0x06, 0, 0, 0xffffffff }, /* ret #-1 */
138 { 0x06, 0, 0, 0x00000000 }, /* drop: ret #0 */
141 static const struct proto_ops af_ops[] = {
142 [IPPROTO_IP] = {
143 .assembler = assemble_ipv4,
144 .handler = handle_ipv4,
145 .check = check_ipv4,
146 .filter = ipv4_icmp_type_11,
147 .flen = array_size(ipv4_icmp_type_11),
148 .min_len_tcp = sizeof(struct iphdr) + sizeof(struct tcphdr),
149 .min_len_icmp = sizeof(struct iphdr) + sizeof(struct icmphdr),
151 [IPPROTO_IPV6] = {
152 .assembler = assemble_ipv6,
153 .handler = handle_ipv6,
154 .check = check_ipv6,
155 .filter = ipv6_icmp6_type_3,
156 .flen = array_size(ipv6_icmp6_type_3),
157 .min_len_tcp = sizeof(struct ip6_hdr) + sizeof(struct tcphdr),
158 .min_len_icmp = sizeof(struct ip6_hdr) + sizeof(struct icmp6hdr),
162 static void signal_handler(int number)
164 switch (number) {
165 case SIGINT:
166 sigint = 1;
167 default:
168 break;
172 static void help(void)
174 printf("\nastraceroute %s, autonomous system trace route utility\n", VERSION_STRING);
175 puts("http://www.netsniff-ng.org\n\n"
176 "Usage: astraceroute [options]\n"
177 "Options:\n"
178 " -H|--host <host> Host/IPv4/IPv6 to lookup AS route to\n"
179 " -p|--port <port> Hosts port to lookup AS route to\n"
180 " -i|-d|--dev <device> Networking device, e.g. eth0\n"
181 " -f|--init-ttl <ttl> Set initial TTL\n"
182 " -m|--max-ttl <ttl> Set maximum TTL (def: 30)\n"
183 " -q|--num-probes <num> Number of max probes for each hop (def: 2)\n"
184 " -x|--timeout <sec> Probe response timeout in sec (def: 3)\n"
185 " -X|--payload <string> Specify a payload string to test DPIs\n"
186 " -l|--totlen <len> Specify total packet len\n"
187 " -4|--ipv4 Use IPv4-only requests\n"
188 " -6|--ipv6 Use IPv6-only requests\n"
189 " -n|--numeric Do not do reverse DNS lookup for hops\n"
190 " -u|--update Update GeoIP databases\n"
191 " -L|--latitude Show latitude and longtitude\n"
192 " -N|--dns Do a reverse DNS lookup for hops\n"
193 " -S|--syn Set TCP SYN flag\n"
194 " -A|--ack Set TCP ACK flag\n"
195 " -F|--fin Set TCP FIN flag\n"
196 " -P|--psh Set TCP PSH flag\n"
197 " -U|--urg Set TCP URG flag\n"
198 " -R|--rst Set TCP RST flag\n"
199 " -E|--ecn-syn Send ECN SYN packets (RFC3168)\n"
200 " -t|--tos <tos> Set the IP TOS field\n"
201 " -G|--nofrag Set do not fragment bit\n"
202 " -Z|--show-packet Show returned packet on each hop\n"
203 " -v|--version Print version\n"
204 " -h|--help Print this help\n\n"
205 "Examples:\n"
206 " IPv4 trace of AS with TCP SYN probe (this will most-likely pass):\n"
207 " astraceroute -i eth0 -N -S -H netsniff-ng.org\n"
208 " IPv4 trace of AS with TCP ECN SYN probe:\n"
209 " astraceroute -i eth0 -N -E -H netsniff-ng.org\n"
210 " IPv4 trace of AS with TCP FIN probe:\n"
211 " astraceroute -i eth0 -N -F -H netsniff-ng.org\n"
212 " IPv4 trace of AS with Xmas probe:\n"
213 " astraceroute -i eth0 -N -FPU -H netsniff-ng.org\n"
214 " IPv4 trace of AS with Null probe with ASCII payload:\n"
215 " astraceroute -i eth0 -N -H netsniff-ng.org -X \"censor-me\" -Z\n"
216 " IPv6 trace of AS up to www.6bone.net:\n"
217 " astraceroute -6 -i eth0 -S -E -N -H www.6bone.net\n\n"
218 "Note:\n"
219 " If the TCP probe did not give any results, then astraceroute will\n"
220 " automatically probe for classic ICMP packets! To gather more\n"
221 " information about astraceroute's fetched AS numbers, see e.g.\n"
222 " http://bgp.he.net/AS<number>!\n\n"
223 "Please report bugs to <bugs@netsniff-ng.org>\n"
224 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>\n"
225 "Swiss federal institute of technology (ETH Zurich)\n"
226 "License: GNU GPL version 2.0\n"
227 "This is free software: you are free to change and redistribute it.\n"
228 "There is NO WARRANTY, to the extent permitted by law.\n");
229 die();
232 static void version(void)
234 printf("\nastraceroute %s, autonomous system trace route utility\n", VERSION_STRING);
235 puts("http://www.netsniff-ng.org\n\n"
236 "Please report bugs to <bugs@netsniff-ng.org>\n"
237 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>\n"
238 "Swiss federal institute of technology (ETH Zurich)\n"
239 "License: GNU GPL version 2.0\n"
240 "This is free software: you are free to change and redistribute it.\n"
241 "There is NO WARRANTY, to the extent permitted by law.\n");
242 die();
245 static void __assemble_data(uint8_t *packet, size_t len, const char *payload)
247 int i;
249 if (payload == NULL) {
250 for (i = 0; i < len; ++i)
251 packet[i] = (uint8_t) rand();
252 } else {
253 int lmin = min(len, strlen(payload));
255 for (i = 0; i < lmin; ++i)
256 packet[i] = (uint8_t) payload[i];
257 for (i = lmin; i < len; ++i)
258 packet[i] = (uint8_t) rand();
262 static void __assemble_icmp4(uint8_t *packet, size_t len)
264 struct icmphdr *icmph = (struct icmphdr *) packet;
266 bug_on(len < sizeof(struct icmphdr));
268 icmph->type = ICMP_ECHO;
269 icmph->code = 0;
270 icmph->checksum = 0;
273 static void __assemble_icmp6(uint8_t *packet, size_t len)
275 struct icmp6hdr *icmp6h = (struct icmp6hdr *) packet;
277 bug_on(len < sizeof(struct icmp6hdr));
279 icmp6h->icmp6_type = ICMPV6_ECHO_REQUEST;
280 icmp6h->icmp6_code = 0;
281 icmp6h->icmp6_cksum = 0;
284 static void __assemble_tcp(uint8_t *packet, size_t len, int syn, int ack,
285 int urg, int fin, int rst, int psh, int ecn,
286 int dport)
288 struct tcphdr *tcph = (struct tcphdr *) packet;
290 bug_on(len < sizeof(struct tcphdr));
292 tcph->source = htons((uint16_t) rand());
293 tcph->dest = htons((uint16_t) dport);
295 tcph->seq = htonl(rand());
296 tcph->ack_seq = (!!ack ? htonl(rand()) : 0);
298 tcph->doff = 5;
300 tcph->syn = !!syn;
301 tcph->ack = !!ack;
302 tcph->urg = !!urg;
303 tcph->fin = !!fin;
304 tcph->rst = !!rst;
305 tcph->psh = !!psh;
306 tcph->ece = !!ecn;
307 tcph->cwr = !!ecn;
309 tcph->window = htons((uint16_t) (100 + (rand() % 65435)));
310 tcph->urg_ptr = (!!urg ? htons((uint16_t) rand()) : 0);
311 tcph->check = 0;
314 static int assemble_ipv4(uint8_t *packet, size_t len, int ttl, int proto,
315 const struct ctx *ctx, const struct sockaddr *dst,
316 const struct sockaddr *src)
318 uint8_t *data;
319 size_t data_len, off_next = 0;
320 struct iphdr *iph = (struct iphdr *) packet;
322 bug_on(!src || !dst);
323 bug_on(src->sa_family != PF_INET || dst->sa_family != PF_INET);
324 bug_on(len < sizeof(*iph) + min(sizeof(struct tcphdr),
325 sizeof(struct icmphdr)));
327 iph->ihl = 5;
328 iph->version = 4;
329 iph->tos = (uint8_t) ctx->tos;
331 iph->tot_len = htons((uint16_t) len);
332 iph->id = htons((uint16_t) rand());
334 iph->frag_off = ctx->nofrag ? IP_DF : 0;
335 iph->ttl = (uint8_t) ttl;
337 iph->saddr = ((const struct sockaddr_in *) src)->sin_addr.s_addr;
338 iph->daddr = ((const struct sockaddr_in *) dst)->sin_addr.s_addr;
340 iph->protocol = (uint8_t) proto;
342 data = packet + sizeof(*iph);
343 data_len = len - sizeof(*iph);
345 switch (proto) {
346 case IPPROTO_TCP:
347 __assemble_tcp(data, data_len, ctx->syn, ctx->ack, ctx->urg,
348 ctx->fin, ctx->rst, ctx->psh, ctx->ecn, ctx->dport);
349 off_next = sizeof(struct tcphdr);
350 break;
351 case IPPROTO_ICMP:
352 __assemble_icmp4(data, data_len);
353 off_next = sizeof(struct icmphdr);
354 break;
355 default:
356 bug();
359 data = packet + sizeof(*iph) + off_next;
360 data_len = len - sizeof(*iph) - off_next;
362 __assemble_data(data, data_len, ctx->payload);
364 iph->check = csum((unsigned short *) packet, ntohs(iph->tot_len) >> 1);
366 return ntohs(iph->id);
369 static int assemble_ipv6(uint8_t *packet, size_t len, int ttl, int proto,
370 const struct ctx *ctx, const struct sockaddr *dst,
371 const struct sockaddr *src)
373 uint8_t *data;
374 size_t data_len, off_next = 0;
375 struct ip6_hdr *ip6h = (struct ip6_hdr *) packet;
377 bug_on(!src || !dst);
378 bug_on(src->sa_family != PF_INET6 || dst->sa_family != PF_INET6);
379 bug_on(len < sizeof(*ip6h) + min(sizeof(struct tcphdr),
380 sizeof(struct icmp6hdr)));
382 ip6h->ip6_flow = htonl(rand() & 0x000fffff);
383 ip6h->ip6_vfc = 0x60;
385 ip6h->ip6_plen = htons((uint16_t) len - sizeof(*ip6h));
386 ip6h->ip6_nxt = (uint8_t) proto;
387 ip6h->ip6_hlim = (uint8_t) ttl;
389 memcpy(&ip6h->ip6_src, &(((const struct sockaddr_in6 *)
390 src)->sin6_addr), sizeof(ip6h->ip6_src));
391 memcpy(&ip6h->ip6_dst, &(((const struct sockaddr_in6 *)
392 dst)->sin6_addr), sizeof(ip6h->ip6_dst));
394 data = packet + sizeof(*ip6h);
395 data_len = len - sizeof(*ip6h);
397 switch (proto) {
398 case IPPROTO_TCP:
399 __assemble_tcp(data, data_len, ctx->syn, ctx->ack, ctx->urg,
400 ctx->fin, ctx->rst, ctx->psh, ctx->ecn, ctx->dport);
401 off_next = sizeof(struct tcphdr);
402 break;
403 case IPPROTO_ICMP:
404 case IPPROTO_ICMPV6:
405 __assemble_icmp6(data, data_len);
406 off_next = sizeof(struct icmp6hdr);
407 break;
408 default:
409 bug();
412 data = packet + sizeof(*ip6h) + off_next;
413 data_len = len - sizeof(*ip6h) - off_next;
415 __assemble_data(data, data_len, ctx->payload);
417 return ntohl(ip6h->ip6_flow) & 0x000fffff;
420 static int check_ipv4(uint8_t *packet, size_t len, int ttl, int id,
421 const struct sockaddr *ss)
423 struct iphdr *iph = (struct iphdr *) packet;
424 struct iphdr *iph_inner;
425 struct icmphdr *icmph;
427 if (iph->protocol != IPPROTO_ICMP)
428 return -EINVAL;
429 if (iph->daddr != ((const struct sockaddr_in *) ss)->sin_addr.s_addr)
430 return -EINVAL;
432 icmph = (struct icmphdr *) (packet + sizeof(struct iphdr));
433 if (icmph->type != ICMP_TIME_EXCEEDED)
434 return -EINVAL;
435 if (icmph->code != ICMP_EXC_TTL)
436 return -EINVAL;
438 iph_inner = (struct iphdr *) (packet + sizeof(struct iphdr) +
439 sizeof(struct icmphdr));
440 if (ntohs(iph_inner->id) != id)
441 return -EINVAL;
443 return len;
446 static void handle_ipv4(uint8_t *packet, size_t len, int dns_resolv, int latitude)
448 char hbuff[NI_MAXHOST];
449 struct iphdr *iph = (struct iphdr *) packet;
450 struct sockaddr_in sd;
451 struct hostent *hent;
452 const char *as, *country, *city;
454 memset(hbuff, 0, sizeof(hbuff));
455 memset(&sd, 0, sizeof(sd));
456 sd.sin_family = PF_INET;
457 sd.sin_addr.s_addr = iph->saddr;
459 getnameinfo((struct sockaddr *) &sd, sizeof(sd),
460 hbuff, sizeof(hbuff), NULL, 0, NI_NUMERICHOST);
462 as = geoip4_as_name(sd);
463 country = geoip4_country_name(sd);
464 city = geoip4_city_name(sd);
466 if (dns_resolv) {
467 hent = gethostbyaddr(&sd.sin_addr, sizeof(sd.sin_addr), PF_INET);
468 if (hent)
469 printf(" %s (%s)", hent->h_name, hbuff);
470 else
471 printf(" %s", hbuff);
472 } else {
473 printf(" %s", hbuff);
475 if (as)
476 printf(" in %s", as);
477 if (country) {
478 printf(" in %s", country);
479 if (city)
480 printf(", %s", city);
482 if (latitude)
483 printf(" (%f/%f)", geoip4_latitude(sd), geoip4_longitude(sd));
486 static int check_ipv6(uint8_t *packet, size_t len, int ttl, int id,
487 const struct sockaddr *ss)
489 struct ip6_hdr *ip6h = (struct ip6_hdr *) packet;
490 struct ip6_hdr *ip6h_inner;
491 struct icmp6hdr *icmp6h;
493 if (ip6h->ip6_nxt != 0x3a)
494 return -EINVAL;
495 if (memcmp(&ip6h->ip6_dst, &(((const struct sockaddr_in6 *)
496 ss)->sin6_addr), sizeof(ip6h->ip6_dst)))
497 return -EINVAL;
499 icmp6h = (struct icmp6hdr *) (packet + sizeof(*ip6h));
500 if (icmp6h->icmp6_type != ICMPV6_TIME_EXCEED)
501 return -EINVAL;
502 if (icmp6h->icmp6_code != ICMPV6_EXC_HOPLIMIT)
503 return -EINVAL;
505 ip6h_inner = (struct ip6_hdr *) (packet + sizeof(*ip6h) + sizeof(*icmp6h));
506 if ((ntohl(ip6h_inner->ip6_flow) & 0x000fffff) != id)
507 return -EINVAL;
509 return len;
512 static void handle_ipv6(uint8_t *packet, size_t len, int dns_resolv, int latitude)
514 char hbuff[NI_MAXHOST];
515 struct ip6_hdr *ip6h = (struct ip6_hdr *) packet;
516 struct sockaddr_in6 sd;
517 struct hostent *hent;
518 const char *as, *country, *city;
520 memset(hbuff, 0, sizeof(hbuff));
521 memset(&sd, 0, sizeof(sd));
522 sd.sin6_family = PF_INET6;
523 memcpy(&sd.sin6_addr, &ip6h->ip6_src, sizeof(ip6h->ip6_src));
525 getnameinfo((struct sockaddr *) &sd, sizeof(sd),
526 hbuff, sizeof(hbuff), NULL, 0, NI_NUMERICHOST);
528 as = geoip6_as_name(sd);
529 country = geoip6_country_name(sd);
530 city = geoip6_city_name(sd);
532 if (dns_resolv) {
533 hent = gethostbyaddr(&sd.sin6_addr, sizeof(sd.sin6_addr), PF_INET6);
534 if (hent)
535 printf(" %s (%s)", hent->h_name, hbuff);
536 else
537 printf(" %s", hbuff);
538 } else {
539 printf(" %s", hbuff);
541 if (as)
542 printf(" in %s", as);
543 if (country) {
544 printf(" in %s", country);
545 if (city)
546 printf(", %s", city);
548 if (latitude)
549 printf(" (%f/%f)", geoip6_latitude(sd), geoip6_longitude(sd));
552 static void show_trace_info(struct ctx *ctx, const struct sockaddr_storage *ss,
553 const struct sockaddr_storage *sd)
555 char hbuffs[256], hbuffd[256];
557 memset(hbuffd, 0, sizeof(hbuffd));
558 getnameinfo((struct sockaddr *) sd, sizeof(*sd),
559 hbuffd, sizeof(hbuffd), NULL, 0, NI_NUMERICHOST);
561 memset(hbuffs, 0, sizeof(hbuffs));
562 getnameinfo((struct sockaddr *) ss, sizeof(*ss),
563 hbuffs, sizeof(hbuffs), NULL, 0, NI_NUMERICHOST);
565 printf("AS path IPv%d TCP trace from %s to %s:%s (%s) with len %d "
566 "Bytes, %u max hops\n", ctx->proto == IPPROTO_IP ? 4 : 6,
567 hbuffs, hbuffd, ctx->port, ctx->host, ctx->totlen, ctx->max_ttl);
569 printf("Using flags SYN:%d,ACK:%d,ECN:%d,FIN:%d,PSH:%d,RST:%d,URG:%d\n",
570 ctx->syn, ctx->ack, ctx->ecn, ctx->fin, ctx->psh, ctx->rst, ctx->urg);
572 if (ctx->payload)
573 printf("With payload: \'%s\'\n", ctx->payload);
576 static int get_remote_fd(struct ctx *ctx, struct sockaddr_storage *ss,
577 struct sockaddr_storage *sd)
579 int fd = -1, ret, one = 1;
580 struct addrinfo hints, *ahead, *ai;
582 memset(&hints, 0, sizeof(hints));
583 hints.ai_family = PF_UNSPEC;
584 hints.ai_socktype = SOCK_STREAM;
585 hints.ai_protocol = IPPROTO_TCP;
586 hints.ai_flags = AI_NUMERICSERV;
588 ret = getaddrinfo(ctx->host, ctx->port, &hints, &ahead);
589 if (ret < 0)
590 panic("Cannot get address info!\n");
592 for (ai = ahead; ai != NULL && fd < 0; ai = ai->ai_next) {
593 if (!((ai->ai_family == PF_INET6 && ctx->proto == IPPROTO_IPV6) ||
594 (ai->ai_family == PF_INET && ctx->proto == IPPROTO_IP)))
595 continue;
597 fd = socket(ai->ai_family, SOCK_RAW, IPPROTO_RAW);
598 if (fd < 0)
599 continue;
601 memset(ss, 0, sizeof(*ss));
602 ret = device_address(ctx->dev, ai->ai_family, ss);
603 if (ret < 0)
604 panic("Cannot get own device address!\n");
606 ret = bind(fd, (struct sockaddr *) ss, sizeof(*ss));
607 if (ret < 0)
608 panic("Cannot bind socket!\n");
610 memset(sd, 0, sizeof(*sd));
611 memcpy(sd, ai->ai_addr, ai->ai_addrlen);
613 ctx->sd_len = ai->ai_addrlen;
614 ctx->dport = strtoul(ctx->port, NULL, 10);
616 ret = setsockopt(fd, ctx->proto, IP_HDRINCL, &one, sizeof(one));
617 if (ret < 0)
618 panic("Kernel does not support IP_HDRINCL!\n");
620 if (ai->ai_family == PF_INET6) {
621 struct sockaddr_in6 *sd6 = (struct sockaddr_in6 *) sd;
623 sd6->sin6_port = 0;
626 break;
629 freeaddrinfo(ahead);
631 if (fd < 0)
632 panic("Cannot create socket! Does remote "
633 "support IPv%d?!\n",
634 ctx->proto == IPPROTO_IP ? 4 : 6);
636 return fd;
639 static void inject_filter(struct ctx *ctx, int fd)
641 struct sock_fprog bpf_ops;
643 enable_kernel_bpf_jit_compiler();
645 memset(&bpf_ops, 0, sizeof(bpf_ops));
646 bpf_ops.filter = (struct sock_filter *) af_ops[ctx->proto].filter;
647 bpf_ops.len = af_ops[ctx->proto].flen;
649 bpf_attach_to_sock(fd, &bpf_ops);
652 static int __process_node(struct ctx *ctx, int fd, int fd_cap, int ttl,
653 int inner_proto, uint8_t *pkt_snd, uint8_t *pkt_rcv,
654 const struct sockaddr_storage *ss,
655 const struct sockaddr_storage *sd, struct timeval *diff)
657 int pkt_id, ret, timeout;
658 struct pollfd pfd;
659 struct timeval start, end;
661 prepare_polling(fd_cap, &pfd);
663 memset(pkt_snd, 0, ctx->totlen);
664 pkt_id = af_ops[ctx->proto].assembler(pkt_snd, ctx->totlen, ttl,
665 inner_proto, ctx,
666 (const struct sockaddr *) sd,
667 (const struct sockaddr *) ss);
669 ret = sendto(fd, pkt_snd, ctx->totlen, 0, (struct sockaddr *) sd,
670 ctx->sd_len);
671 if (ret < 0)
672 panic("sendto failed: %s\n", strerror(errno));
674 bug_on(gettimeofday(&start, NULL));
676 timeout = (ctx->timeout > 0 ? ctx->timeout : 2) * 1000;
678 ret = poll(&pfd, 1, timeout);
679 if (ret > 0 && pfd.revents & POLLIN && sigint == 0) {
680 bug_on(gettimeofday(&end, NULL));
681 if (diff)
682 timersub(&end, &start, diff);
684 ret = recvfrom(fd_cap, pkt_rcv, ctx->rcvlen, 0, NULL, NULL);
685 if (ret < sizeof(struct ethhdr) + af_ops[ctx->proto].min_len_icmp)
686 return -EIO;
688 return af_ops[ctx->proto].check(pkt_rcv + sizeof(struct ethhdr),
689 ret - sizeof(struct ethhdr), ttl,
690 pkt_id, (const struct sockaddr *) ss);
691 } else {
692 return -EIO;
695 return 0;
698 static void timerdiv(const unsigned long divisor, const struct timeval *tv,
699 struct timeval *result)
701 uint64_t x = ((uint64_t) tv->tv_sec * 1000 * 1000 + tv->tv_usec) / divisor;
703 result->tv_sec = x / 1000 / 1000;
704 result->tv_usec = x % (1000 * 1000);
707 static int timevalcmp(const void *t1, const void *t2)
709 if (timercmp((struct timeval *) t1, (struct timeval *) t2, <))
710 return -1;
711 if (timercmp((struct timeval *) t1, (struct timeval *) t2, >))
712 return 1;
714 return 0;
717 static int __process_time(struct ctx *ctx, int fd, int fd_cap, int ttl,
718 int inner_proto, uint8_t *pkt_snd, uint8_t *pkt_rcv,
719 const struct sockaddr_storage *ss,
720 const struct sockaddr_storage *sd)
722 int good = 0, i, j = 0, ret = -EIO, idx, ret_good = -EIO;
723 struct timeval probes[9], *tmp, sum, res;
724 uint8_t *trash = xmalloc(ctx->rcvlen);
725 char *cwait[] = { "-", "\\", "|", "/" };
726 const char *proto_short[] = {
727 [IPPROTO_TCP] = "t",
728 [IPPROTO_ICMP] = "i",
729 [IPPROTO_ICMPV6] = "i",
732 memset(probes, 0, sizeof(probes));
733 for (i = 0; i < array_size(probes) && sigint == 0; ++i) {
734 ret = __process_node(ctx, fd, fd_cap, ttl, inner_proto,
735 pkt_snd, good == 0 ? pkt_rcv : trash,
736 ss, sd, &probes[i]);
737 if (ret > 0) {
738 if (good == 0)
739 ret_good = ret;
740 good++;
743 if (good == 0 && ctx->queries == i)
744 break;
746 usleep(50000);
748 printf("\r%2d: %s", ttl, cwait[j++]);
749 fflush(stdout);
750 if (j >= array_size(cwait))
751 j = 0;
754 if (good == 0) {
755 xfree(trash);
756 return -EIO;
759 tmp = xmalloc(sizeof(struct timeval) * good);
760 for (i = j = 0; i < array_size(probes); ++i) {
761 if (probes[i].tv_sec == 0 && probes[i].tv_usec == 0)
762 continue;
763 tmp[j].tv_sec = probes[i].tv_sec;
764 tmp[j].tv_usec = probes[i].tv_usec;
765 j++;
768 qsort(tmp, j, sizeof(struct timeval), timevalcmp);
770 printf("\r%2d: %s[", ttl, proto_short[inner_proto]);
771 idx = j / 2;
772 switch (j % 2) {
773 case 0:
774 timeradd(&tmp[idx], &tmp[idx - 1], &sum);
775 timerdiv(2, &sum, &res);
776 if (res.tv_sec > 0)
777 printf("%lu sec ", res.tv_sec);
778 printf("%7lu us", res.tv_usec);
779 break;
780 case 1:
781 if (tmp[idx].tv_sec > 0)
782 printf("%lu sec ", tmp[idx].tv_sec);
783 printf("%7lu us", tmp[idx].tv_usec);
784 break;
786 printf("]");
788 xfree(tmp);
789 xfree(trash);
791 return ret_good;
794 static int __probe_remote(struct ctx *ctx, int fd, int fd_cap, int ttl,
795 uint8_t *pkt_snd, uint8_t *pkt_rcv,
796 const struct sockaddr_storage *ss,
797 const struct sockaddr_storage *sd,
798 int inner_proto)
800 int ret = -EIO, tries = ctx->queries;
802 while (tries-- > 0 && sigint == 0) {
803 ret = __process_time(ctx, fd, fd_cap, ttl, inner_proto,
804 pkt_snd, pkt_rcv, ss, sd);
805 if (ret < 0)
806 continue;
808 af_ops[ctx->proto].handler(pkt_rcv + sizeof(struct ethhdr),
809 ret - sizeof(struct ethhdr),
810 ctx->dns_resolv, ctx->latitude);
811 if (ctx->show) {
812 struct pkt_buff *pkt;
814 printf("\n");
815 pkt = pkt_alloc(pkt_rcv, ret);
816 hex_ascii(pkt);
817 tprintf_flush();
818 pkt_free(pkt);
821 break;
824 return ret;
827 static int __process_ttl(struct ctx *ctx, int fd, int fd_cap, int ttl,
828 uint8_t *pkt_snd, uint8_t *pkt_rcv,
829 const struct sockaddr_storage *ss,
830 const struct sockaddr_storage *sd)
832 int ret = -EIO, i;
833 const int inner_protos[] = {
834 IPPROTO_TCP,
835 IPPROTO_ICMP,
838 printf("%2d: ", ttl);
839 fflush(stdout);
841 for (i = 0; i < array_size(inner_protos) && sigint == 0; ++i) {
842 ret = __probe_remote(ctx, fd, fd_cap, ttl, pkt_snd, pkt_rcv, ss, sd,
843 inner_protos[i]);
844 if (ret > 0)
845 break;
848 if (ret <= 0)
849 printf("\r%2d: ?[ no answer]", ttl);
850 if (ctx->show == 0)
851 printf("\n");
852 if (ctx->show && ret <= 0)
853 printf("\n\n");
855 fflush(stdout);
856 return 0;
859 static int main_trace(struct ctx *ctx)
861 int fd, fd_cap, ifindex, ttl;
862 struct ring dummy_ring;
863 struct sockaddr_storage ss, sd;
864 uint8_t *pkt_snd, *pkt_rcv;
866 fd = get_remote_fd(ctx, &ss, &sd);
867 fd_cap = pf_socket();
869 inject_filter(ctx, fd_cap);
871 ifindex = device_ifindex(ctx->dev);
872 bind_rx_ring(fd_cap, &dummy_ring, ifindex);
874 if (ctx->totlen < af_ops[ctx->proto].min_len_tcp) {
875 ctx->totlen = af_ops[ctx->proto].min_len_tcp;
876 if (ctx->payload)
877 ctx->totlen += strlen(ctx->payload);
880 ctx->rcvlen = device_mtu(ctx->dev) - sizeof(struct ethhdr);
881 if (ctx->totlen >= ctx->rcvlen)
882 panic("Packet len exceeds device MTU!\n");
884 pkt_snd = xmalloc(ctx->totlen);
885 pkt_rcv = xmalloc(ctx->rcvlen);
887 show_trace_info(ctx, &ss, &sd);
889 for (ttl = ctx->init_ttl; ttl <= ctx->max_ttl && sigint == 0; ++ttl)
890 __process_ttl(ctx, fd, fd_cap, ttl, pkt_snd, pkt_rcv,
891 &ss, &sd);
893 xfree(pkt_snd);
894 xfree(pkt_rcv);
896 close(fd_cap);
897 close(fd);
899 return 0;
902 int main(int argc, char **argv)
904 int c, opt_index, ret;
905 struct ctx ctx;
907 setfsuid(getuid());
908 setfsgid(getgid());
910 srand(time(NULL));
912 memset(&ctx, 0, sizeof(ctx));
913 ctx.init_ttl = 1;
914 ctx.max_ttl = 30;
915 ctx.queries = 2;
916 ctx.timeout = 2;
917 ctx.proto = IPPROTO_IP;
918 ctx.payload = NULL;
919 ctx.dev = xstrdup("eth0");
920 ctx.port = xstrdup("80");
922 while ((c = getopt_long(argc, argv, short_options, long_options,
923 &opt_index)) != EOF) {
924 switch (c) {
925 case 'h':
926 help();
927 break;
928 case 'v':
929 version();
930 break;
931 case 'u':
932 update_geoip();
933 die();
934 break;
935 case 'H':
936 ctx.host = xstrdup(optarg);
937 break;
938 case 'p':
939 if (ctx.port)
940 xfree(ctx.port);
941 ctx.port = xstrdup(optarg);
942 break;
943 case 'n':
944 ctx.dns_resolv = 0;
945 break;
946 case '4':
947 ctx.proto = IPPROTO_IP;
948 break;
949 case '6':
950 ctx.proto = IPPROTO_IPV6;
951 break;
952 case 'Z':
953 ctx.show = 1;
954 break;
955 case 'N':
956 ctx.dns_resolv = 1;
957 break;
958 case 'f':
959 ctx.init_ttl = atoi(optarg);
960 if (ctx.init_ttl <= 0)
961 help();
962 break;
963 case 'm':
964 ctx.max_ttl = atoi(optarg);
965 if (ctx.max_ttl <= 0)
966 help();
967 break;
968 case 'i':
969 case 'd':
970 free(ctx.dev);
971 ctx.dev = xstrdup(optarg);
972 break;
973 case 'q':
974 ctx.queries = atoi(optarg);
975 if (ctx.queries <= 0)
976 help();
977 break;
978 case 'x':
979 ctx.timeout = atoi(optarg);
980 if (ctx.timeout <= 0)
981 help();
982 break;
983 case 'L':
984 ctx.latitude = 1;
985 break;
986 case 'S':
987 ctx.syn = 1;
988 break;
989 case 'A':
990 ctx.ack = 1;
991 break;
992 case 'F':
993 ctx.fin = 1;
994 break;
995 case 'U':
996 ctx.urg = 1;
997 break;
998 case 'P':
999 ctx.psh = 1;
1000 break;
1001 case 'R':
1002 ctx.rst = 1;
1003 break;
1004 case 'E':
1005 ctx.syn = 1;
1006 ctx.ecn = 1;
1007 break;
1008 case 't':
1009 ctx.tos = atoi(optarg);
1010 if (ctx.tos < 0)
1011 help();
1012 break;
1013 case 'G':
1014 ctx.nofrag = 1;
1015 break;
1016 case 'X':
1017 ctx.payload = xstrdup(optarg);
1018 break;
1019 case 'l':
1020 ctx.totlen = atoi(optarg);
1021 if (ctx.totlen <= 0)
1022 help();
1023 break;
1024 case '?':
1025 switch (optopt) {
1026 case 'H':
1027 case 'p':
1028 case 'f':
1029 case 'm':
1030 case 'i':
1031 case 'd':
1032 case 'q':
1033 case 'x':
1034 case 'X':
1035 case 't':
1036 case 'l':
1037 panic("Option -%c requires an argument!\n",
1038 optopt);
1039 default:
1040 if (isprint(optopt))
1041 printf("Unknown option character `0x%X\'!\n", optopt);
1042 die();
1044 default:
1045 break;
1049 if (argc < 3 || !ctx.host || !ctx.port || ctx.init_ttl > ctx.max_ttl ||
1050 ctx.init_ttl > MAXTTL || ctx.max_ttl > MAXTTL)
1051 help();
1053 if (!device_up_and_running(ctx.dev))
1054 panic("Networking device not up and running!\n");
1055 if (device_mtu(ctx.dev) <= ctx.totlen)
1056 panic("Packet larger than device MTU!\n");
1058 register_signal(SIGHUP, signal_handler);
1059 register_signal(SIGINT, signal_handler);
1061 tprintf_init();
1062 init_geoip(1);
1064 ret = main_trace(&ctx);
1066 destroy_geoip();
1067 tprintf_cleanup();
1069 free(ctx.dev);
1070 free(ctx.host);
1071 free(ctx.port);
1072 free(ctx.payload);
1074 return ret;