trafgen: parser: Add syntax for VLAN header creating
[netsniff-ng.git] / astraceroute.c
blobae40ff62408d16919fb2415c8c9336c0ddcc09b2
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 "dev.h"
37 #include "sig.h"
38 #include "config.h"
39 #include "tprintf.h"
40 #include "pkt_buff.h"
41 #include "proto.h"
42 #include "xmalloc.h"
43 #include "csum.h"
44 #include "sock.h"
45 #include "geoip.h"
46 #include "ring.h"
47 #include "built_in.h"
49 struct ctx {
50 char *host, *port, *dev, *payload, *bind_addr;
51 size_t totlen, rcvlen;
52 socklen_t sd_len;
53 int init_ttl, max_ttl, dns_resolv, queries, timeout;
54 int syn, ack, ecn, fin, psh, rst, urg, tos, nofrag, proto, show;
55 int dport, latitude;
58 struct proto_ops {
59 int (*assembler)(uint8_t *packet, size_t len, int ttl, int proto,
60 const struct ctx *ctx, const struct sockaddr *dst,
61 const struct sockaddr *src);
62 const struct sock_filter *filter;
63 unsigned int flen;
64 size_t min_len_tcp, min_len_icmp;
65 int (*check)(uint8_t *packet, size_t len, int ttl, int id,
66 const struct sockaddr *src);
67 void (*handler)(uint8_t *packet, size_t len, int dns_resolv,
68 int latitude);
71 static sig_atomic_t sigint = 0;
73 static int assemble_ipv4(uint8_t *packet, size_t len, int ttl, int proto,
74 const struct ctx *ctx, const struct sockaddr *dst,
75 const struct sockaddr *src);
76 static int assemble_ipv6(uint8_t *packet, size_t len, int ttl, int proto,
77 const struct ctx *ctx, const struct sockaddr *dst,
78 const struct sockaddr *src);
79 static int check_ipv4(uint8_t *packet, size_t len, int ttl, int id,
80 const struct sockaddr *ss);
81 static void handle_ipv4(uint8_t *packet, size_t len, int dns_resolv,
82 int latitude);
83 static int check_ipv6(uint8_t *packet, size_t len, int ttl, int id,
84 const struct sockaddr *ss);
85 static void handle_ipv6(uint8_t *packet, size_t len, int dns_resolv,
86 int latitude);
88 static const char *short_options = "H:p:nNf:m:b:i:d:q:x:SAEFPURt:Gl:hv46X:ZuL";
89 static const struct option long_options[] = {
90 {"host", required_argument, NULL, 'H'},
91 {"port", required_argument, NULL, 'p'},
92 {"init-ttl", required_argument, NULL, 'f'},
93 {"max-ttl", required_argument, NULL, 'm'},
94 {"bind", required_argument, NULL, 'b'},
95 {"dev", required_argument, NULL, 'd'},
96 {"num-probes", required_argument, NULL, 'q'},
97 {"timeout", required_argument, NULL, 'x'},
98 {"tos", required_argument, NULL, 't'},
99 {"payload", required_argument, NULL, 'X'},
100 {"totlen", required_argument, NULL, 'l'},
101 {"numeric", no_argument, NULL, 'n'},
102 {"latitude", no_argument, NULL, 'L'},
103 {"update", no_argument, NULL, 'u'},
104 {"dns", no_argument, NULL, 'N'},
105 {"ipv4", no_argument, NULL, '4'},
106 {"ipv6", no_argument, NULL, '6'},
107 {"syn", no_argument, NULL, 'S'},
108 {"ack", no_argument, NULL, 'A'},
109 {"urg", no_argument, NULL, 'U'},
110 {"fin", no_argument, NULL, 'F'},
111 {"psh", no_argument, NULL, 'P'},
112 {"rst", no_argument, NULL, 'R'},
113 {"ecn-syn", no_argument, NULL, 'E'},
114 {"show-packet", no_argument, NULL, 'Z'},
115 {"nofrag", no_argument, NULL, 'G'},
116 {"version", no_argument, NULL, 'v'},
117 {"help", no_argument, NULL, 'h'},
118 {NULL, 0, NULL, 0}
121 static const char *copyright = "Please report bugs to <netsniff-ng@googlegroups.com>\n"
122 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>\n"
123 "Swiss federal institute of technology (ETH Zurich)\n"
124 "License: GNU GPL version 2.0\n"
125 "This is free software: you are free to change and redistribute it.\n"
126 "There is NO WARRANTY, to the extent permitted by law.";
128 static const struct sock_filter ipv4_icmp_type_11[] = {
129 { 0x28, 0, 0, 0x0000000c }, /* ldh [12] */
130 { 0x15, 0, 8, 0x00000800 }, /* jneq #0x800, drop */
131 { 0x30, 0, 0, 0x00000017 }, /* ldb [23] */
132 { 0x15, 0, 6, 0x00000001 }, /* jneq #0x1, drop */
133 { 0x28, 0, 0, 0x00000014 }, /* ldh [20] */
134 { 0x45, 4, 0, 0x00001fff }, /* jset #0x1fff, drop */
135 { 0xb1, 0, 0, 0x0000000e }, /* ldxb 4*([14]&0xf) */
136 { 0x50, 0, 0, 0x0000000e }, /* ldb [x + 14] */
137 { 0x15, 0, 1, 0x0000000b }, /* jneq #0xb, drop */
138 { 0x06, 0, 0, 0xffffffff }, /* ret #-1 */
139 { 0x06, 0, 0, 0x00000000 }, /* drop: ret #0 */
142 static const struct sock_filter ipv6_icmp6_type_3[] = {
143 { 0x28, 0, 0, 0x0000000c }, /* ldh [12] */
144 { 0x15, 0, 5, 0x000086dd }, /* jneq #0x86dd, drop */
145 { 0x30, 0, 0, 0x00000014 }, /* ldb [20] */
146 { 0x15, 0, 3, 0x0000003a }, /* jneq #0x3a, drop */
147 { 0x30, 0, 0, 0x00000036 }, /* ldb [54] */
148 { 0x15, 0, 1, 0x00000003 }, /* jneq #0x3, drop */
149 { 0x06, 0, 0, 0xffffffff }, /* ret #-1 */
150 { 0x06, 0, 0, 0x00000000 }, /* drop: ret #0 */
153 static const struct proto_ops af_ops[] = {
154 [IPPROTO_IP] = {
155 .assembler = assemble_ipv4,
156 .handler = handle_ipv4,
157 .check = check_ipv4,
158 .filter = ipv4_icmp_type_11,
159 .flen = array_size(ipv4_icmp_type_11),
160 .min_len_tcp = sizeof(struct iphdr) + sizeof(struct tcphdr),
161 .min_len_icmp = sizeof(struct iphdr) + sizeof(struct icmphdr),
163 [IPPROTO_IPV6] = {
164 .assembler = assemble_ipv6,
165 .handler = handle_ipv6,
166 .check = check_ipv6,
167 .filter = ipv6_icmp6_type_3,
168 .flen = array_size(ipv6_icmp6_type_3),
169 .min_len_tcp = sizeof(struct ip6_hdr) + sizeof(struct tcphdr),
170 .min_len_icmp = sizeof(struct ip6_hdr) + sizeof(struct icmp6hdr),
174 static void signal_handler(int number)
176 switch (number) {
177 case SIGINT:
178 case SIGQUIT:
179 case SIGTERM:
180 sigint = 1;
181 default:
182 break;
186 static void __noreturn help(void)
188 printf("astraceroute %s, autonomous system trace route utility\n", VERSION_STRING);
189 puts("http://www.netsniff-ng.org\n\n"
190 "Usage: astraceroute [options]\n"
191 "Options:\n"
192 " -H|--host <host> Host/IPv4/IPv6 to lookup AS route to\n"
193 " -p|--port <port> Hosts port to lookup AS route to\n"
194 " -i|-d|--dev <device> Networking device, e.g. eth0\n"
195 " -b|--bind <IP> IP address to bind to, Must specify -6 for an IPv6 address\n"
196 " -f|--init-ttl <ttl> Set initial TTL\n"
197 " -m|--max-ttl <ttl> Set maximum TTL (def: 30)\n"
198 " -q|--num-probes <num> Number of max probes for each hop (def: 2)\n"
199 " -x|--timeout <sec> Probe response timeout in sec (def: 3)\n"
200 " -X|--payload <string> Specify a payload string to test DPIs\n"
201 " -l|--totlen <len> Specify total packet len\n"
202 " -4|--ipv4 Use IPv4-only requests\n"
203 " -6|--ipv6 Use IPv6-only requests\n"
204 " -n|--numeric Do not do reverse DNS lookup for hops\n"
205 " -u|--update Update GeoIP databases\n"
206 " -L|--latitude Show latitude and longitude\n"
207 " -N|--dns Do a reverse DNS lookup for hops\n"
208 " -S|--syn Set TCP SYN flag\n"
209 " -A|--ack Set TCP ACK flag\n"
210 " -F|--fin Set TCP FIN flag\n"
211 " -P|--psh Set TCP PSH flag\n"
212 " -U|--urg Set TCP URG flag\n"
213 " -R|--rst Set TCP RST flag\n"
214 " -E|--ecn-syn Send ECN SYN packets (RFC3168)\n"
215 " -t|--tos <tos> Set the IP TOS field\n"
216 " -G|--nofrag Set do not fragment bit\n"
217 " -Z|--show-packet Show returned packet on each hop\n"
218 " -v|--version Print version and exit\n"
219 " -h|--help Print this help and exit\n\n"
220 "Examples:\n"
221 " IPv4 trace of AS with TCP SYN probe (this will most-likely pass):\n"
222 " astraceroute -i eth0 -N -S -H netsniff-ng.org\n"
223 " IPv4 trace of AS with TCP ECN SYN probe:\n"
224 " astraceroute -i eth0 -N -E -H netsniff-ng.org\n"
225 " IPv4 trace of AS with TCP FIN probe:\n"
226 " astraceroute -i eth0 -N -F -H netsniff-ng.org\n"
227 " IPv4 trace of AS with Xmas probe:\n"
228 " astraceroute -i eth0 -N -FPU -H netsniff-ng.org\n"
229 " IPv4 trace of AS with Null probe with ASCII payload:\n"
230 " astraceroute -i eth0 -N -H netsniff-ng.org -X \"censor-me\" -Z\n"
231 " IPv6 trace of AS up to www.6bone.net:\n"
232 " astraceroute -6 -i eth0 -S -E -N -H www.6bone.net\n\n"
233 "Note:\n"
234 " If the TCP probe did not give any results, then astraceroute will\n"
235 " automatically probe for classic ICMP packets! To gather more\n"
236 " information about astraceroute's fetched AS numbers, see e.g.\n"
237 " http://bgp.he.net/AS<number>!\n");
238 puts(copyright);
239 die();
242 static void __noreturn version(void)
244 printf("astraceroute %s, Git id: %s\n", VERSION_LONG, GITVERSION);
245 puts("autonomous system trace route utility\n"
246 "http://www.netsniff-ng.org\n");
247 puts(copyright);
248 die();
251 static void __assemble_data(uint8_t *packet, size_t len, const char *payload)
253 size_t i;
255 if (payload == NULL) {
256 for (i = 0; i < len; ++i)
257 packet[i] = (uint8_t) rand();
258 } else {
259 size_t lmin = min(len, strlen(payload));
261 for (i = 0; i < lmin; ++i)
262 packet[i] = (uint8_t) payload[i];
263 for (i = lmin; i < len; ++i)
264 packet[i] = (uint8_t) rand();
268 static void __assemble_icmp4(uint8_t *packet, size_t len)
270 struct icmphdr *icmph = (struct icmphdr *) packet;
272 bug_on(len < sizeof(struct icmphdr));
274 icmph->type = ICMP_ECHO;
275 icmph->code = 0;
276 icmph->checksum = 0;
279 static void __assemble_icmp6(uint8_t *packet, size_t len)
281 struct icmp6hdr *icmp6h = (struct icmp6hdr *) packet;
283 bug_on(len < sizeof(struct icmp6hdr));
285 icmp6h->icmp6_type = ICMPV6_ECHO_REQUEST;
286 icmp6h->icmp6_code = 0;
287 icmp6h->icmp6_cksum = 0;
290 static void __assemble_tcp(uint8_t *packet, size_t len, int syn, int ack,
291 int urg, int fin, int rst, int psh, int ecn,
292 int dport)
294 struct tcphdr *tcph = (struct tcphdr *) packet;
296 bug_on(len < sizeof(struct tcphdr));
298 tcph->source = htons((uint16_t) rand());
299 tcph->dest = htons((uint16_t) dport);
301 tcph->seq = htonl(rand());
302 tcph->ack_seq = (!!ack ? htonl(rand()) : 0);
304 tcph->doff = 5;
306 tcph->syn = !!syn;
307 tcph->ack = !!ack;
308 tcph->urg = !!urg;
309 tcph->fin = !!fin;
310 tcph->rst = !!rst;
311 tcph->psh = !!psh;
312 tcph->ece = !!ecn;
313 tcph->cwr = !!ecn;
315 tcph->window = htons((uint16_t) (100 + (rand() % 65435)));
316 tcph->urg_ptr = (!!urg ? htons((uint16_t) rand()) : 0);
317 tcph->check = 0;
320 static int assemble_ipv4(uint8_t *packet, size_t len, int ttl, int proto,
321 const struct ctx *ctx, const struct sockaddr *dst,
322 const struct sockaddr *src)
324 uint8_t *data;
325 size_t data_len, off_next = 0;
326 struct iphdr *iph = (struct iphdr *) packet;
328 bug_on(!src || !dst);
329 bug_on(src->sa_family != PF_INET || dst->sa_family != PF_INET);
330 bug_on(len < sizeof(*iph) + min(sizeof(struct tcphdr),
331 sizeof(struct icmphdr)));
333 iph->ihl = 5;
334 iph->version = 4;
335 iph->tos = (uint8_t) ctx->tos;
337 iph->tot_len = htons((uint16_t) len);
338 iph->id = htons((uint16_t) rand());
340 iph->frag_off = ctx->nofrag ? IP_DF : 0;
341 iph->ttl = (uint8_t) ttl;
343 iph->saddr = ((const struct sockaddr_in *) src)->sin_addr.s_addr;
344 iph->daddr = ((const struct sockaddr_in *) dst)->sin_addr.s_addr;
346 iph->protocol = (uint8_t) proto;
348 data = packet + sizeof(*iph);
349 data_len = len - sizeof(*iph);
351 switch (proto) {
352 case IPPROTO_TCP:
353 __assemble_tcp(data, data_len, ctx->syn, ctx->ack, ctx->urg,
354 ctx->fin, ctx->rst, ctx->psh, ctx->ecn, ctx->dport);
355 off_next = sizeof(struct tcphdr);
356 break;
357 case IPPROTO_ICMP:
358 __assemble_icmp4(data, data_len);
359 off_next = sizeof(struct icmphdr);
360 break;
361 default:
362 bug();
365 data = packet + sizeof(*iph) + off_next;
366 data_len = len - sizeof(*iph) - off_next;
368 __assemble_data(data, data_len, ctx->payload);
370 iph->check = csum((unsigned short *) packet, ntohs(iph->tot_len) >> 1);
372 return ntohs(iph->id);
375 static int assemble_ipv6(uint8_t *packet, size_t len, int ttl, int proto,
376 const struct ctx *ctx, const struct sockaddr *dst,
377 const struct sockaddr *src)
379 uint8_t *data;
380 size_t data_len, off_next = 0;
381 struct ip6_hdr *ip6h = (struct ip6_hdr *) packet;
383 bug_on(!src || !dst);
384 bug_on(src->sa_family != PF_INET6 || dst->sa_family != PF_INET6);
385 bug_on(len < sizeof(*ip6h) + min(sizeof(struct tcphdr),
386 sizeof(struct icmp6hdr)));
388 ip6h->ip6_flow = htonl(rand() & 0x000fffff);
389 ip6h->ip6_vfc = 0x60;
391 ip6h->ip6_plen = htons((uint16_t) len - sizeof(*ip6h));
392 ip6h->ip6_nxt = (uint8_t) proto;
393 ip6h->ip6_hlim = (uint8_t) ttl;
395 memcpy(&ip6h->ip6_src, &(((const struct sockaddr_in6 *)
396 src)->sin6_addr), sizeof(ip6h->ip6_src));
397 memcpy(&ip6h->ip6_dst, &(((const struct sockaddr_in6 *)
398 dst)->sin6_addr), sizeof(ip6h->ip6_dst));
400 data = packet + sizeof(*ip6h);
401 data_len = len - sizeof(*ip6h);
403 switch (proto) {
404 case IPPROTO_TCP:
405 __assemble_tcp(data, data_len, ctx->syn, ctx->ack, ctx->urg,
406 ctx->fin, ctx->rst, ctx->psh, ctx->ecn, ctx->dport);
407 off_next = sizeof(struct tcphdr);
408 break;
409 case IPPROTO_ICMP:
410 case IPPROTO_ICMPV6:
411 __assemble_icmp6(data, data_len);
412 off_next = sizeof(struct icmp6hdr);
413 break;
414 default:
415 bug();
418 data = packet + sizeof(*ip6h) + off_next;
419 data_len = len - sizeof(*ip6h) - off_next;
421 __assemble_data(data, data_len, ctx->payload);
423 return ntohl(ip6h->ip6_flow) & 0x000fffff;
426 static int check_ipv4(uint8_t *packet, size_t len, int ttl __maybe_unused,
427 int id, const struct sockaddr *ss)
429 struct iphdr *iph = (struct iphdr *) packet;
430 struct iphdr *iph_inner;
431 struct icmphdr *icmph;
433 if (iph->protocol != IPPROTO_ICMP)
434 return -EINVAL;
435 if (iph->daddr != ((const struct sockaddr_in *) ss)->sin_addr.s_addr)
436 return -EINVAL;
438 icmph = (struct icmphdr *) (packet + sizeof(struct iphdr));
439 if (icmph->type != ICMP_TIME_EXCEEDED)
440 return -EINVAL;
441 if (icmph->code != ICMP_EXC_TTL)
442 return -EINVAL;
444 iph_inner = (struct iphdr *) (packet + sizeof(struct iphdr) +
445 sizeof(struct icmphdr));
446 if (ntohs(iph_inner->id) != id)
447 return -EINVAL;
449 return len;
452 static void handle_ipv4(uint8_t *packet, size_t len __maybe_unused,
453 int dns_resolv, int latitude)
455 char hbuff[NI_MAXHOST];
456 struct iphdr *iph = (struct iphdr *) packet;
457 struct sockaddr_in sd;
458 struct hostent *hent;
459 const char *as, *country, *city;
461 memset(hbuff, 0, sizeof(hbuff));
462 memset(&sd, 0, sizeof(sd));
463 sd.sin_family = PF_INET;
464 sd.sin_addr.s_addr = iph->saddr;
466 getnameinfo((struct sockaddr *) &sd, sizeof(sd),
467 hbuff, sizeof(hbuff), NULL, 0, NI_NUMERICHOST);
469 as = geoip4_as_name(&sd);
470 country = geoip4_country_name(&sd);
471 city = geoip4_city_name(&sd);
473 if (dns_resolv) {
474 hent = gethostbyaddr(&sd.sin_addr, sizeof(sd.sin_addr), PF_INET);
475 if (hent)
476 printf(" %s (%s)", hent->h_name, hbuff);
477 else
478 printf(" %s", hbuff);
479 } else {
480 printf(" %s", hbuff);
482 if (as)
483 printf(" in %s", as);
484 if (country) {
485 printf(" in %s", country);
486 if (city)
487 printf(", %s", city);
489 if (latitude)
490 printf(" (%f/%f)", geoip4_latitude(&sd), geoip4_longitude(&sd));
493 static int check_ipv6(uint8_t *packet, size_t len, int ttl __maybe_unused,
494 int id, const struct sockaddr *ss)
496 struct ip6_hdr *ip6h = (struct ip6_hdr *) packet;
497 struct ip6_hdr *ip6h_inner;
498 struct icmp6hdr *icmp6h;
500 if (ip6h->ip6_nxt != 0x3a)
501 return -EINVAL;
502 if (memcmp(&ip6h->ip6_dst, &(((const struct sockaddr_in6 *)
503 ss)->sin6_addr), sizeof(ip6h->ip6_dst)))
504 return -EINVAL;
506 icmp6h = (struct icmp6hdr *) (packet + sizeof(*ip6h));
507 if (icmp6h->icmp6_type != ICMPV6_TIME_EXCEED)
508 return -EINVAL;
509 if (icmp6h->icmp6_code != ICMPV6_EXC_HOPLIMIT)
510 return -EINVAL;
512 ip6h_inner = (struct ip6_hdr *) (packet + sizeof(*ip6h) + sizeof(*icmp6h));
513 if ((ntohl(ip6h_inner->ip6_flow) & 0x000fffff) != (uint32_t) id)
514 return -EINVAL;
516 return len;
519 static void handle_ipv6(uint8_t *packet, size_t len __maybe_unused,
520 int dns_resolv, int latitude)
522 char hbuff[NI_MAXHOST];
523 struct ip6_hdr *ip6h = (struct ip6_hdr *) packet;
524 struct sockaddr_in6 sd;
525 struct hostent *hent;
526 const char *as, *country, *city;
528 memset(hbuff, 0, sizeof(hbuff));
529 memset(&sd, 0, sizeof(sd));
530 sd.sin6_family = PF_INET6;
531 memcpy(&sd.sin6_addr, &ip6h->ip6_src, sizeof(ip6h->ip6_src));
533 getnameinfo((struct sockaddr *) &sd, sizeof(sd),
534 hbuff, sizeof(hbuff), NULL, 0, NI_NUMERICHOST);
536 as = geoip6_as_name(&sd);
537 country = geoip6_country_name(&sd);
538 city = geoip6_city_name(&sd);
540 if (dns_resolv) {
541 hent = gethostbyaddr(&sd.sin6_addr, sizeof(sd.sin6_addr), PF_INET6);
542 if (hent)
543 printf(" %s (%s)", hent->h_name, hbuff);
544 else
545 printf(" %s", hbuff);
546 } else {
547 printf(" %s", hbuff);
549 if (as)
550 printf(" in %s", as);
551 if (country) {
552 printf(" in %s", country);
553 if (city)
554 printf(", %s", city);
556 if (latitude)
557 printf(" (%f/%f)", geoip6_latitude(&sd), geoip6_longitude(&sd));
560 static void show_trace_info(struct ctx *ctx, const struct sockaddr_storage *ss,
561 const struct sockaddr_storage *sd)
563 char hbuffs[256], hbuffd[256];
565 memset(hbuffd, 0, sizeof(hbuffd));
566 getnameinfo((struct sockaddr *) sd, sizeof(*sd),
567 hbuffd, sizeof(hbuffd), NULL, 0, NI_NUMERICHOST);
569 memset(hbuffs, 0, sizeof(hbuffs));
570 getnameinfo((struct sockaddr *) ss, sizeof(*ss),
571 hbuffs, sizeof(hbuffs), NULL, 0, NI_NUMERICHOST);
573 printf("AS path IPv%d TCP trace from %s to %s:%s (%s) with len %zu "
574 "Bytes, %u max hops\n", ctx->proto == IPPROTO_IP ? 4 : 6,
575 hbuffs, hbuffd, ctx->port, ctx->host, ctx->totlen, ctx->max_ttl);
577 printf("Using flags SYN:%d,ACK:%d,ECN:%d,FIN:%d,PSH:%d,RST:%d,URG:%d\n",
578 ctx->syn, ctx->ack, ctx->ecn, ctx->fin, ctx->psh, ctx->rst, ctx->urg);
580 if (ctx->payload)
581 printf("With payload: \'%s\'\n", ctx->payload);
584 static int get_remote_fd(struct ctx *ctx, struct sockaddr_storage *ss,
585 struct sockaddr_storage *sd)
587 int fd = -1, ret, one = 1, af = AF_INET;
588 struct addrinfo hints, *ahead, *ai;
589 unsigned char bind_ip[sizeof(struct in6_addr)];
591 memset(&hints, 0, sizeof(hints));
592 hints.ai_family = PF_UNSPEC;
593 hints.ai_socktype = SOCK_STREAM;
594 hints.ai_protocol = IPPROTO_TCP;
595 hints.ai_flags = AI_NUMERICSERV;
597 ret = getaddrinfo(ctx->host, ctx->port, &hints, &ahead);
598 if (ret < 0)
599 panic("Cannot get address info!\n");
601 for (ai = ahead; ai != NULL && fd < 0; ai = ai->ai_next) {
602 if (!((ai->ai_family == PF_INET6 && ctx->proto == IPPROTO_IPV6) ||
603 (ai->ai_family == PF_INET && ctx->proto == IPPROTO_IP)))
604 continue;
606 fd = socket(ai->ai_family, SOCK_RAW, IPPROTO_RAW);
607 if (fd < 0)
608 continue;
610 memset(ss, 0, sizeof(*ss));
611 ret = device_address(ctx->dev, ai->ai_family, ss);
612 if (ret < 0 && !ctx->bind_addr)
613 panic("Cannot get own device address!\n");
615 if (ctx->bind_addr) {
616 if (ctx->proto == IPPROTO_IPV6)
617 af = AF_INET6;
619 if (inet_pton(af, ctx->bind_addr, &bind_ip) != 1)
620 panic("Address is invalid!\n");
622 if (af == AF_INET6) {
623 struct sockaddr_in6 *ss6 = (struct sockaddr_in6 *) ss;
624 memcpy(&ss6->sin6_addr.s6_addr, &bind_ip, sizeof(struct in6_addr));
625 } else {
626 struct sockaddr_in *ss4 = (struct sockaddr_in *) ss;
627 memcpy(&ss4->sin_addr.s_addr, &bind_ip, sizeof(struct in_addr));
631 ret = bind(fd, (struct sockaddr *) ss, sizeof(*ss));
632 if (ret < 0)
633 panic("Cannot bind socket!\n");
635 memset(sd, 0, sizeof(*sd));
636 memcpy(sd, ai->ai_addr, ai->ai_addrlen);
638 ctx->sd_len = ai->ai_addrlen;
639 ctx->dport = strtoul(ctx->port, NULL, 10);
641 ret = setsockopt(fd, ctx->proto, IP_HDRINCL, &one, sizeof(one));
642 if (ret < 0)
643 panic("Kernel does not support IP_HDRINCL!\n");
645 if (ai->ai_family == PF_INET6) {
646 struct sockaddr_in6 *sd6 = (struct sockaddr_in6 *) sd;
648 sd6->sin6_port = 0;
651 break;
654 freeaddrinfo(ahead);
656 if (fd < 0)
657 panic("Cannot create socket! Does remote "
658 "support IPv%d?!\n",
659 ctx->proto == IPPROTO_IP ? 4 : 6);
661 return fd;
664 static void inject_filter(struct ctx *ctx, int fd)
666 struct sock_fprog bpf_ops;
668 enable_kernel_bpf_jit_compiler();
670 memset(&bpf_ops, 0, sizeof(bpf_ops));
671 bpf_ops.filter = (struct sock_filter *) af_ops[ctx->proto].filter;
672 bpf_ops.len = af_ops[ctx->proto].flen;
674 bpf_attach_to_sock(fd, &bpf_ops);
677 static int __process_node(struct ctx *ctx, int fd, int fd_cap, int ttl,
678 int inner_proto, uint8_t *pkt_snd, uint8_t *pkt_rcv,
679 const struct sockaddr_storage *ss,
680 const struct sockaddr_storage *sd, struct timeval *diff)
682 int pkt_id, ret, timeout;
683 struct pollfd pfd;
684 struct timeval start, end;
686 prepare_polling(fd_cap, &pfd);
688 memset(pkt_snd, 0, ctx->totlen);
689 pkt_id = af_ops[ctx->proto].assembler(pkt_snd, ctx->totlen, ttl,
690 inner_proto, ctx,
691 (const struct sockaddr *) sd,
692 (const struct sockaddr *) ss);
694 ret = sendto(fd, pkt_snd, ctx->totlen, 0, (struct sockaddr *) sd,
695 ctx->sd_len);
696 if (ret < 0)
697 panic("sendto failed: %s\n", strerror(errno));
699 bug_on(gettimeofday(&start, NULL));
701 timeout = (ctx->timeout > 0 ? ctx->timeout : 2) * 1000;
703 ret = poll(&pfd, 1, timeout);
704 if (ret > 0 && pfd.revents & POLLIN && sigint == 0) {
705 bug_on(gettimeofday(&end, NULL));
706 if (diff)
707 timersub(&end, &start, diff);
709 ret = recvfrom(fd_cap, pkt_rcv, ctx->rcvlen, 0, NULL, NULL);
710 if (ret < (int) (sizeof(struct ethhdr) + af_ops[ctx->proto].min_len_icmp))
711 return -EIO;
713 return af_ops[ctx->proto].check(pkt_rcv + sizeof(struct ethhdr),
714 ret - sizeof(struct ethhdr), ttl,
715 pkt_id, (const struct sockaddr *) ss);
716 } else {
717 return -EIO;
720 return 0;
723 static void timerdiv(const unsigned long divisor, const struct timeval *tv,
724 struct timeval *result)
726 uint64_t x = ((uint64_t) tv->tv_sec * 1000 * 1000 + tv->tv_usec) / divisor;
728 result->tv_sec = x / 1000 / 1000;
729 result->tv_usec = x % (1000 * 1000);
732 static int timevalcmp(const void *t1, const void *t2)
734 if (timercmp((struct timeval *) t1, (struct timeval *) t2, <))
735 return -1;
736 if (timercmp((struct timeval *) t1, (struct timeval *) t2, >))
737 return 1;
739 return 0;
742 static int __process_time(struct ctx *ctx, int fd, int fd_cap, int ttl,
743 int inner_proto, uint8_t *pkt_snd, uint8_t *pkt_rcv,
744 const struct sockaddr_storage *ss,
745 const struct sockaddr_storage *sd)
747 size_t i, j = 0;
748 int good = 0, ret = -EIO, idx, ret_good = -EIO;
749 struct timeval probes[9], *tmp, sum, res;
750 uint8_t *trash = xmalloc(ctx->rcvlen);
751 char *cwait[] = { "-", "\\", "|", "/" };
752 const char *proto_short[] = {
753 [IPPROTO_TCP] = "t",
754 [IPPROTO_ICMP] = "i",
755 [IPPROTO_ICMPV6] = "i",
758 memset(probes, 0, sizeof(probes));
759 for (i = 0; i < array_size(probes) && sigint == 0; ++i) {
760 ret = __process_node(ctx, fd, fd_cap, ttl, inner_proto,
761 pkt_snd, good == 0 ? pkt_rcv : trash,
762 ss, sd, &probes[i]);
763 if (ret > 0) {
764 if (good == 0)
765 ret_good = ret;
766 good++;
769 if (good == 0 && ctx->queries == (int) i)
770 break;
772 usleep(50000);
774 printf("\r%2d: %s", ttl, cwait[j++]);
775 fflush(stdout);
776 if (j >= array_size(cwait))
777 j = 0;
780 if (good == 0) {
781 xfree(trash);
782 return -EIO;
785 tmp = xcalloc(good, sizeof(struct timeval));
786 for (i = j = 0; i < array_size(probes); ++i) {
787 if (probes[i].tv_sec == 0 && probes[i].tv_usec == 0)
788 continue;
789 tmp[j].tv_sec = probes[i].tv_sec;
790 tmp[j].tv_usec = probes[i].tv_usec;
791 j++;
794 qsort(tmp, j, sizeof(struct timeval), timevalcmp);
796 printf("\r%2d: %s[", ttl, proto_short[inner_proto]);
797 idx = j / 2;
798 switch (j % 2) {
799 case 0:
800 timeradd(&tmp[idx], &tmp[idx - 1], &sum);
801 timerdiv(2, &sum, &res);
802 if (res.tv_sec > 0)
803 printf("%lu sec ", res.tv_sec);
804 printf("%7lu us", res.tv_usec);
805 break;
806 case 1:
807 if (tmp[idx].tv_sec > 0)
808 printf("%lu sec ", tmp[idx].tv_sec);
809 printf("%7lu us", tmp[idx].tv_usec);
810 break;
812 printf("]");
814 xfree(tmp);
815 xfree(trash);
817 return ret_good;
820 static int __probe_remote(struct ctx *ctx, int fd, int fd_cap, int ttl,
821 uint8_t *pkt_snd, uint8_t *pkt_rcv,
822 const struct sockaddr_storage *ss,
823 const struct sockaddr_storage *sd,
824 int inner_proto)
826 int ret = -EIO, tries = ctx->queries;
828 while (tries-- > 0 && sigint == 0) {
829 ret = __process_time(ctx, fd, fd_cap, ttl, inner_proto,
830 pkt_snd, pkt_rcv, ss, sd);
831 if (ret < 0)
832 continue;
834 af_ops[ctx->proto].handler(pkt_rcv + sizeof(struct ethhdr),
835 ret - sizeof(struct ethhdr),
836 ctx->dns_resolv, ctx->latitude);
837 if (ctx->show) {
838 struct pkt_buff *pkt;
840 printf("\n");
841 pkt = pkt_alloc(pkt_rcv, ret);
842 hex_ascii(pkt);
843 tprintf_flush();
844 pkt_free(pkt);
847 break;
850 return ret;
853 static int __process_ttl(struct ctx *ctx, int fd, int fd_cap, int ttl,
854 uint8_t *pkt_snd, uint8_t *pkt_rcv,
855 const struct sockaddr_storage *ss,
856 const struct sockaddr_storage *sd)
858 int ret = -EIO;
859 size_t i;
860 const int inner_protos[] = {
861 IPPROTO_TCP,
862 IPPROTO_ICMP,
865 printf("%2d: ", ttl);
866 fflush(stdout);
868 for (i = 0; i < array_size(inner_protos) && sigint == 0; ++i) {
869 ret = __probe_remote(ctx, fd, fd_cap, ttl, pkt_snd, pkt_rcv, ss, sd,
870 inner_protos[i]);
871 if (ret > 0)
872 break;
875 if (ret <= 0)
876 printf("\r%2d: ?[ no answer]", ttl);
877 if (ctx->show == 0)
878 printf("\n");
879 if (ctx->show && ret <= 0)
880 printf("\n\n");
882 fflush(stdout);
883 return 0;
886 static int main_trace(struct ctx *ctx)
888 int fd, fd_cap, ifindex, ttl;
889 struct ring dummy_ring;
890 struct sockaddr_storage ss, sd;
891 uint8_t *pkt_snd, *pkt_rcv;
893 fd = get_remote_fd(ctx, &ss, &sd);
894 fd_cap = pf_socket();
896 inject_filter(ctx, fd_cap);
898 ifindex = device_ifindex(ctx->dev);
899 bind_ring_generic(fd_cap, &dummy_ring, ifindex, false);
901 if (ctx->totlen < af_ops[ctx->proto].min_len_tcp) {
902 ctx->totlen = af_ops[ctx->proto].min_len_tcp;
903 if (ctx->payload)
904 ctx->totlen += strlen(ctx->payload);
907 ctx->rcvlen = device_mtu(ctx->dev) - sizeof(struct ethhdr);
908 if (ctx->totlen >= ctx->rcvlen)
909 panic("Packet len exceeds device MTU!\n");
911 pkt_snd = xmalloc(ctx->totlen);
912 pkt_rcv = xmalloc(ctx->rcvlen);
914 show_trace_info(ctx, &ss, &sd);
916 for (ttl = ctx->init_ttl; ttl <= ctx->max_ttl && sigint == 0; ++ttl)
917 __process_ttl(ctx, fd, fd_cap, ttl, pkt_snd, pkt_rcv,
918 &ss, &sd);
920 xfree(pkt_snd);
921 xfree(pkt_rcv);
923 close(fd_cap);
924 close(fd);
926 return 0;
929 int main(int argc, char **argv)
931 int c, opt_index, ret;
932 struct ctx ctx;
934 setfsuid(getuid());
935 setfsgid(getgid());
937 srand(time(NULL));
939 memset(&ctx, 0, sizeof(ctx));
940 ctx.init_ttl = 1;
941 ctx.max_ttl = 30;
942 ctx.queries = 2;
943 ctx.timeout = 2;
944 ctx.proto = IPPROTO_IP;
945 ctx.payload = NULL;
946 ctx.dev = xstrdup("eth0");
947 ctx.port = xstrdup("80");
948 ctx.bind_addr = NULL;
950 while ((c = getopt_long(argc, argv, short_options, long_options,
951 &opt_index)) != EOF) {
952 switch (c) {
953 case 'h':
954 help();
955 break;
956 case 'v':
957 version();
958 break;
959 case 'u':
960 update_geoip();
961 die();
962 break;
963 case 'H':
964 ctx.host = xstrdup(optarg);
965 break;
966 case 'p':
967 if (ctx.port)
968 xfree(ctx.port);
969 ctx.port = xstrdup(optarg);
970 break;
971 case 'n':
972 ctx.dns_resolv = 0;
973 break;
974 case '4':
975 ctx.proto = IPPROTO_IP;
976 break;
977 case '6':
978 ctx.proto = IPPROTO_IPV6;
979 break;
980 case 'Z':
981 ctx.show = 1;
982 break;
983 case 'N':
984 ctx.dns_resolv = 1;
985 break;
986 case 'f':
987 ctx.init_ttl = atoi(optarg);
988 if (ctx.init_ttl <= 0)
989 help();
990 break;
991 case 'm':
992 ctx.max_ttl = atoi(optarg);
993 if (ctx.max_ttl <= 0)
994 help();
995 break;
996 case 'b':
997 ctx.bind_addr = xstrdup(optarg);
998 break;
999 case 'i':
1000 case 'd':
1001 free(ctx.dev);
1002 ctx.dev = xstrdup(optarg);
1003 break;
1004 case 'q':
1005 ctx.queries = atoi(optarg);
1006 if (ctx.queries <= 0)
1007 help();
1008 break;
1009 case 'x':
1010 ctx.timeout = atoi(optarg);
1011 if (ctx.timeout <= 0)
1012 help();
1013 break;
1014 case 'L':
1015 ctx.latitude = 1;
1016 break;
1017 case 'S':
1018 ctx.syn = 1;
1019 break;
1020 case 'A':
1021 ctx.ack = 1;
1022 break;
1023 case 'F':
1024 ctx.fin = 1;
1025 break;
1026 case 'U':
1027 ctx.urg = 1;
1028 break;
1029 case 'P':
1030 ctx.psh = 1;
1031 break;
1032 case 'R':
1033 ctx.rst = 1;
1034 break;
1035 case 'E':
1036 ctx.syn = 1;
1037 ctx.ecn = 1;
1038 break;
1039 case 't':
1040 ctx.tos = atoi(optarg);
1041 if (ctx.tos < 0)
1042 help();
1043 break;
1044 case 'G':
1045 ctx.nofrag = 1;
1046 break;
1047 case 'X':
1048 ctx.payload = xstrdup(optarg);
1049 break;
1050 case 'l':
1051 ctx.totlen = strtoul(optarg, NULL, 10);
1052 if (ctx.totlen == 0)
1053 help();
1054 break;
1055 case '?':
1056 switch (optopt) {
1057 case 'H':
1058 case 'p':
1059 case 'f':
1060 case 'm':
1061 case 'i':
1062 case 'd':
1063 case 'q':
1064 case 'x':
1065 case 'X':
1066 case 't':
1067 case 'l':
1068 panic("Option -%c requires an argument!\n",
1069 optopt);
1070 default:
1071 if (isprint(optopt))
1072 printf("Unknown option character `0x%X\'!\n", optopt);
1073 die();
1075 default:
1076 break;
1080 if (argc < 3 || !ctx.host || !ctx.port || ctx.init_ttl > ctx.max_ttl ||
1081 ctx.init_ttl > MAXTTL || ctx.max_ttl > MAXTTL)
1082 help();
1084 if (!device_up_and_running(ctx.dev))
1085 panic("Networking device not up and running!\n");
1086 if (device_mtu(ctx.dev) <= ctx.totlen)
1087 panic("Packet larger than device MTU!\n");
1089 register_signal(SIGHUP, signal_handler);
1090 register_signal(SIGINT, signal_handler);
1091 register_signal(SIGQUIT, signal_handler);
1092 register_signal(SIGTERM, signal_handler);
1094 tprintf_init();
1095 init_geoip(1);
1097 ret = main_trace(&ctx);
1099 destroy_geoip();
1100 tprintf_cleanup();
1102 free(ctx.dev);
1103 free(ctx.host);
1104 free(ctx.port);
1105 free(ctx.bind_addr);
1106 free(ctx.payload);
1108 return ret;