ring_tx: handle EINTR from sendto
[netsniff-ng-new.git] / astraceroute.c
blobd5711fb1360f2ecf6d74ea3980bb366bfba39f2a
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 #define _DEFAULT_SOURCE
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <signal.h>
12 #include <getopt.h>
13 #include <ctype.h>
14 #include <stdint.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <sys/socket.h>
18 #include <sys/fsuid.h>
19 #include <fcntl.h>
20 #include <time.h>
21 #include <string.h>
22 #include <asm/byteorder.h>
23 #include <linux/tcp.h>
24 #include <netinet/if_ether.h>
25 #include <netinet/ip.h>
26 #include <netinet/ip6.h>
27 #include <netinet/in.h>
28 #include <errno.h>
29 #include <netdb.h>
30 #include <sys/time.h>
31 #include <arpa/inet.h>
32 #include <linux/icmp.h>
33 #include <linux/icmpv6.h>
35 #include "bpf.h"
36 #include "die.h"
37 #include "dev.h"
38 #include "sig.h"
39 #include "config.h"
40 #include "tprintf.h"
41 #include "pkt_buff.h"
42 #include "proto.h"
43 #include "xmalloc.h"
44 #include "csum.h"
45 #include "sock.h"
46 #include "geoip.h"
47 #include "ring.h"
48 #include "built_in.h"
50 struct ctx {
51 char *host, *port, *dev, *payload, *bind_addr;
52 size_t totlen, rcvlen;
53 socklen_t sd_len;
54 int init_ttl, max_ttl, dport, queries, timeout;
55 int syn, ack, ecn, fin, psh, rst, urg, tos, nofrag, proto;
56 bool do_geo_lookup, do_dns_resolution, do_show_packet;
59 struct proto_ops {
60 int (*assembler)(uint8_t *packet, size_t len, int ttl, int proto,
61 const struct ctx *ctx, const struct sockaddr *dst,
62 const struct sockaddr *src);
63 const struct sock_filter *filter;
64 unsigned int flen;
65 size_t min_len_tcp, min_len_icmp;
66 int (*check)(uint8_t *packet, size_t len, int ttl, int id,
67 const struct sockaddr *src);
68 void (*handler)(uint8_t *packet, size_t len, bool do_dns_resolution,
69 bool do_geo_lookup);
72 static sig_atomic_t sigint = 0;
74 static int assemble_ipv4(uint8_t *packet, size_t len, int ttl, int proto,
75 const struct ctx *ctx, const struct sockaddr *dst,
76 const struct sockaddr *src);
77 static int check_ipv4(uint8_t *packet, size_t len, int ttl, int id,
78 const struct sockaddr *ss);
79 static void handle_ipv4(uint8_t *packet, size_t len, bool do_dns_resolution,
80 bool do_geo_lookup);
81 static int assemble_ipv6(uint8_t *packet, size_t len, int ttl, int proto,
82 const struct ctx *ctx, const struct sockaddr *dst,
83 const struct sockaddr *src);
84 static int check_ipv6(uint8_t *packet, size_t len, int ttl, int id,
85 const struct sockaddr *ss);
86 static void handle_ipv6(uint8_t *packet, size_t len, bool do_dns_resolution,
87 bool do_geo_lookup);
89 static const char *short_options = "H:p:nNf:m:b:i:d:q:x:SAEFPURt:Gl:hv46X:ZuL";
90 static const struct option long_options[] = {
91 {"host", required_argument, NULL, 'H'},
92 {"port", required_argument, NULL, 'p'},
93 {"init-ttl", required_argument, NULL, 'f'},
94 {"max-ttl", required_argument, NULL, 'm'},
95 {"bind", required_argument, NULL, 'b'},
96 {"dev", required_argument, NULL, 'd'},
97 {"num-probes", required_argument, NULL, 'q'},
98 {"timeout", required_argument, NULL, 'x'},
99 {"tos", required_argument, NULL, 't'},
100 {"payload", required_argument, NULL, 'X'},
101 {"totlen", required_argument, NULL, 'l'},
102 {"numeric", no_argument, NULL, 'n'},
103 {"latitude", no_argument, NULL, 'L'},
104 {"update", no_argument, NULL, 'u'},
105 {"dns", no_argument, NULL, 'N'},
106 {"ipv4", no_argument, NULL, '4'},
107 {"ipv6", no_argument, NULL, '6'},
108 {"syn", no_argument, NULL, 'S'},
109 {"ack", no_argument, NULL, 'A'},
110 {"urg", no_argument, NULL, 'U'},
111 {"fin", no_argument, NULL, 'F'},
112 {"psh", no_argument, NULL, 'P'},
113 {"rst", no_argument, NULL, 'R'},
114 {"ecn-syn", no_argument, NULL, 'E'},
115 {"show-packet", no_argument, NULL, 'Z'},
116 {"nofrag", no_argument, NULL, 'G'},
117 {"version", no_argument, NULL, 'v'},
118 {"help", no_argument, NULL, 'h'},
119 {NULL, 0, NULL, 0}
122 static const char *copyright =
123 "Please report bugs at https://github.com/netsniff-ng/netsniff-ng/issues\n"
124 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>\n"
125 "Swiss federal institute of technology (ETH Zurich)\n"
126 "License: GNU GPL version 2.0\n"
127 "This is free software: you are free to change and redistribute it.\n"
128 "There is NO WARRANTY, to the extent permitted by law.";
130 static const struct sock_filter ipv4_icmp_type_11[] = {
131 { 0x28, 0, 0, 0x0000000c }, /* ldh [12] */
132 { 0x15, 0, 8, 0x00000800 }, /* jneq #0x800, drop */
133 { 0x30, 0, 0, 0x00000017 }, /* ldb [23] */
134 { 0x15, 0, 6, 0x00000001 }, /* jneq #0x1, drop */
135 { 0x28, 0, 0, 0x00000014 }, /* ldh [20] */
136 { 0x45, 4, 0, 0x00001fff }, /* jset #0x1fff, drop */
137 { 0xb1, 0, 0, 0x0000000e }, /* ldxb 4*([14]&0xf) */
138 { 0x50, 0, 0, 0x0000000e }, /* ldb [x + 14] */
139 { 0x15, 0, 1, 0x0000000b }, /* jneq #0xb, drop */
140 { 0x06, 0, 0, 0xffffffff }, /* ret #-1 */
141 { 0x06, 0, 0, 0x00000000 }, /* drop: ret #0 */
144 static const struct sock_filter ipv6_icmp6_type_3[] = {
145 { 0x28, 0, 0, 0x0000000c }, /* ldh [12] */
146 { 0x15, 0, 5, 0x000086dd }, /* jneq #0x86dd, drop */
147 { 0x30, 0, 0, 0x00000014 }, /* ldb [20] */
148 { 0x15, 0, 3, 0x0000003a }, /* jneq #0x3a, drop */
149 { 0x30, 0, 0, 0x00000036 }, /* ldb [54] */
150 { 0x15, 0, 1, 0x00000003 }, /* jneq #0x3, drop */
151 { 0x06, 0, 0, 0xffffffff }, /* ret #-1 */
152 { 0x06, 0, 0, 0x00000000 }, /* drop: ret #0 */
155 static const struct proto_ops af_ops[] = {
156 [IPPROTO_IP] = {
157 .assembler = assemble_ipv4,
158 .handler = handle_ipv4,
159 .check = check_ipv4,
160 .filter = ipv4_icmp_type_11,
161 .flen = array_size(ipv4_icmp_type_11),
162 .min_len_tcp = sizeof(struct iphdr) + sizeof(struct tcphdr),
163 .min_len_icmp = sizeof(struct iphdr) + sizeof(struct icmphdr),
165 [IPPROTO_IPV6] = {
166 .assembler = assemble_ipv6,
167 .handler = handle_ipv6,
168 .check = check_ipv6,
169 .filter = ipv6_icmp6_type_3,
170 .flen = array_size(ipv6_icmp6_type_3),
171 .min_len_tcp = sizeof(struct ip6_hdr) + sizeof(struct tcphdr),
172 .min_len_icmp = sizeof(struct ip6_hdr) + sizeof(struct icmp6hdr),
176 static void signal_handler(int number)
178 switch (number) {
179 case SIGINT:
180 case SIGQUIT:
181 case SIGTERM:
182 sigint = 1;
183 default:
184 break;
188 static void __noreturn help(void)
190 printf("astraceroute %s, autonomous system trace route utility\n", VERSION_STRING);
191 puts("http://www.netsniff-ng.org\n\n"
192 "Usage: astraceroute [options]\n"
193 "Options:\n"
194 " -H|--host <host> Host/IPv4/IPv6 to lookup AS route to\n"
195 " -p|--port <port> Hosts port to lookup AS route to\n"
196 " -i|-d|--dev <device> Networking device, e.g. eth0\n"
197 " -b|--bind <IP> IP address to bind to, Must specify -6 for an IPv6 address\n"
198 " -f|--init-ttl <ttl> Set initial TTL\n"
199 " -m|--max-ttl <ttl> Set maximum TTL (def: 30)\n"
200 " -q|--num-probes <num> Number of max probes for each hop (def: 2)\n"
201 " -x|--timeout <sec> Probe response timeout in sec (def: 3)\n"
202 " -X|--payload <string> Specify a payload string to test DPIs\n"
203 " -l|--totlen <len> Specify total packet len\n"
204 " -4|--ipv4 Use IPv4-only requests\n"
205 " -6|--ipv6 Use IPv6-only requests\n"
206 " -n|--numeric Do not do reverse DNS lookup for hops\n"
207 " -u|--update Update GeoIP databases\n"
208 " -L|--latitude Show latitude and longitude\n"
209 " -N|--dns Do a reverse DNS lookup for hops\n"
210 " -S|--syn Set TCP SYN flag\n"
211 " -A|--ack Set TCP ACK flag\n"
212 " -F|--fin Set TCP FIN flag\n"
213 " -P|--psh Set TCP PSH flag\n"
214 " -U|--urg Set TCP URG flag\n"
215 " -R|--rst Set TCP RST flag\n"
216 " -E|--ecn-syn Send ECN SYN packets (RFC3168)\n"
217 " -t|--tos <tos> Set the IP TOS field\n"
218 " -G|--nofrag Set do not fragment bit\n"
219 " -Z|--show-packet Show returned packet on each hop\n"
220 " -v|--version Print version and exit\n"
221 " -h|--help Print this help and exit\n\n"
222 "Examples:\n"
223 " IPv4 trace of AS with TCP SYN probe (this will most-likely pass):\n"
224 " astraceroute -i eth0 -N -S -H netsniff-ng.org\n"
225 " IPv4 trace of AS with TCP ECN SYN probe:\n"
226 " astraceroute -i eth0 -N -E -H netsniff-ng.org\n"
227 " IPv4 trace of AS with TCP FIN probe:\n"
228 " astraceroute -i eth0 -N -F -H netsniff-ng.org\n"
229 " IPv4 trace of AS with Xmas probe:\n"
230 " astraceroute -i eth0 -N -FPU -H netsniff-ng.org\n"
231 " IPv4 trace of AS with Null probe with ASCII payload:\n"
232 " astraceroute -i eth0 -N -H netsniff-ng.org -X \"censor-me\" -Z\n"
233 " IPv6 trace of AS up to www.6bone.net:\n"
234 " astraceroute -6 -i eth0 -S -E -N -H www.6bone.net\n\n"
235 "Note:\n"
236 " If the TCP probe did not give any results, then astraceroute will\n"
237 " automatically probe for classic ICMP packets! To gather more\n"
238 " information about astraceroute's fetched AS numbers, see e.g.\n"
239 " http://bgp.he.net/AS<number>!\n");
240 puts(copyright);
241 die();
244 static void __noreturn version(void)
246 printf("astraceroute %s, Git id: %s\n", VERSION_LONG, GITVERSION);
247 puts("autonomous system trace route utility\n"
248 "http://www.netsniff-ng.org\n");
249 puts(copyright);
250 die();
253 static void __assemble_data(uint8_t *packet, size_t len, const char *payload)
255 size_t i;
257 if (payload == NULL) {
258 for (i = 0; i < len; ++i)
259 packet[i] = (uint8_t) rand();
260 } else {
261 size_t lmin = min(len, strlen(payload));
263 for (i = 0; i < lmin; ++i)
264 packet[i] = (uint8_t) payload[i];
265 for (i = lmin; i < len; ++i)
266 packet[i] = (uint8_t) rand();
270 static void __assemble_icmp4(uint8_t *packet, size_t len, const struct ctx *ctx)
272 uint8_t *data;
273 size_t data_len;
274 struct icmphdr *icmph = (struct icmphdr *) packet;
276 bug_on(len < sizeof(*icmph));
278 icmph->type = ICMP_ECHO;
279 icmph->code = 0;
280 icmph->checksum = 0;
282 data = packet + sizeof(*icmph);
283 data_len = len - sizeof(*icmph);
285 __assemble_data(data, data_len, ctx->payload);
287 icmph->checksum = csum((unsigned short *)packet, len / 2);
290 static void __assemble_icmp6(uint8_t *packet, size_t len, const struct ctx *ctx,
291 const struct sockaddr *dst, const struct sockaddr *src)
293 uint8_t *data;
294 size_t data_len;
295 struct ip6_hdr ip6hdr;
296 struct icmp6hdr *icmp6h = (struct icmp6hdr *) packet;
298 bug_on(len < sizeof(*icmp6h));
300 icmp6h->icmp6_type = ICMPV6_ECHO_REQUEST;
301 icmp6h->icmp6_code = 0;
302 icmp6h->icmp6_cksum = 0;
304 data = packet + sizeof(*icmp6h);
305 data_len = len - sizeof(*icmp6h);
307 __assemble_data(data, data_len, ctx->payload);
309 memcpy(&ip6hdr.ip6_src, &((const struct sockaddr_in6 *) src)->sin6_addr,
310 sizeof(ip6hdr.ip6_src));
311 memcpy(&ip6hdr.ip6_dst, &((const struct sockaddr_in6 *) dst)->sin6_addr,
312 sizeof(ip6hdr.ip6_dst));
314 icmp6h->icmp6_cksum = p6_csum(&ip6hdr, packet, sizeof(*icmp6h) + data_len, IPPROTO_ICMPV6);
317 static size_t __assemble_tcp_header(struct tcphdr *tcph, const struct ctx *ctx)
319 tcph->source = htons((uint16_t) rand());
320 tcph->dest = htons((uint16_t) ctx->dport);
322 tcph->seq = htonl(rand());
323 tcph->ack_seq = (!!ctx->ack ? htonl(rand()) : 0);
325 tcph->doff = 5;
327 tcph->syn = !!ctx->syn;
328 tcph->ack = !!ctx->ack;
329 tcph->urg = !!ctx->urg;
330 tcph->fin = !!ctx->fin;
331 tcph->rst = !!ctx->rst;
332 tcph->psh = !!ctx->psh;
333 tcph->ece = !!ctx->ecn;
334 tcph->cwr = !!ctx->ecn;
336 tcph->window = htons((uint16_t) (100 + (rand() % 65435)));
337 tcph->check = 0;
338 tcph->urg_ptr = (!!ctx->urg ? htons((uint16_t) rand()) : 0);
340 return tcph->doff * 4;
343 static void __assemble_tcp(uint8_t *packet, size_t len, const struct ctx *ctx,
344 const struct sockaddr *dst, const struct sockaddr *src)
347 uint8_t *data;
348 size_t tcp_len, data_len;
349 struct ip iphdr;
350 struct tcphdr *tcph = (struct tcphdr *) packet;
352 bug_on(len < sizeof(*tcph));
354 tcp_len = __assemble_tcp_header(tcph, ctx);
356 data = packet + tcp_len;
357 data_len = len - tcp_len;
359 __assemble_data(data, data_len, ctx->payload);
361 memcpy(&iphdr.ip_src, &((const struct sockaddr_in *) src)->sin_addr.s_addr,
362 sizeof(iphdr.ip_src));
363 memcpy(&iphdr.ip_dst, &((const struct sockaddr_in *) dst)->sin_addr.s_addr,
364 sizeof(iphdr.ip_dst));
366 tcph->check = p4_csum(&iphdr, packet, tcp_len + data_len, IPPROTO_TCP);
369 static void __assemble_tcp6(uint8_t *packet, size_t len, const struct ctx *ctx,
370 const struct sockaddr *dst, const struct sockaddr *src)
372 uint8_t *data;
373 size_t tcp_len, data_len;
374 struct ip6_hdr ip6hdr;
375 struct tcphdr *tcph = (struct tcphdr *) packet;
377 bug_on(len < sizeof(*tcph));
379 tcp_len = __assemble_tcp_header(tcph, ctx);
381 data = packet + tcp_len;
382 data_len = len - tcp_len;
384 __assemble_data(data, data_len, ctx->payload);
386 memcpy(&ip6hdr.ip6_src, &((const struct sockaddr_in6 *) src)->sin6_addr,
387 sizeof(ip6hdr.ip6_src));
388 memcpy(&ip6hdr.ip6_dst, &((const struct sockaddr_in6 *) dst)->sin6_addr,
389 sizeof(ip6hdr.ip6_dst));
391 tcph->check = p6_csum(&ip6hdr, packet, tcp_len + data_len, IPPROTO_TCP);
394 static int assemble_ipv4(uint8_t *packet, size_t len, int ttl, int proto,
395 const struct ctx *ctx, const struct sockaddr *dst,
396 const struct sockaddr *src)
398 uint8_t *data;
399 size_t data_len;
400 struct iphdr *iph = (struct iphdr *) packet;
402 bug_on(!src || !dst);
403 bug_on(src->sa_family != PF_INET || dst->sa_family != PF_INET);
404 bug_on(len < sizeof(*iph) + min(sizeof(struct tcphdr),
405 sizeof(struct icmphdr)));
407 iph->ihl = 5;
408 iph->version = 4;
409 iph->tos = (uint8_t) ctx->tos;
411 iph->tot_len = htons((uint16_t) len);
412 iph->id = htons((uint16_t) rand());
414 iph->frag_off = ctx->nofrag ? IP_DF : 0;
415 iph->ttl = (uint8_t) ttl;
417 iph->saddr = ((const struct sockaddr_in *) src)->sin_addr.s_addr;
418 iph->daddr = ((const struct sockaddr_in *) dst)->sin_addr.s_addr;
420 iph->protocol = (uint8_t) proto;
421 iph->check = 0;
423 data = packet + sizeof(*iph);
424 data_len = len - sizeof(*iph);
426 switch (proto) {
427 case IPPROTO_TCP:
428 __assemble_tcp(data, data_len, ctx, dst, src);
429 break;
431 case IPPROTO_ICMP:
432 __assemble_icmp4(data, data_len, ctx);
433 break;
435 default:
436 bug();
440 iph->check = csum((unsigned short *) packet, ntohs(iph->tot_len) >> 1);
442 return ntohs(iph->id);
445 static int assemble_ipv6(uint8_t *packet, size_t len, int ttl, int proto,
446 const struct ctx *ctx, const struct sockaddr *dst,
447 const struct sockaddr *src)
449 uint8_t *data;
450 size_t data_len;
451 struct ip6_hdr *ip6h = (struct ip6_hdr *) packet;
453 bug_on(!src || !dst);
454 bug_on(src->sa_family != PF_INET6 || dst->sa_family != PF_INET6);
455 bug_on(len < sizeof(*ip6h) + min(sizeof(struct tcphdr),
456 sizeof(struct icmp6hdr)));
458 ip6h->ip6_flow = htonl(rand() & 0x000fffff);
459 ip6h->ip6_vfc = 0x60;
461 ip6h->ip6_plen = htons((uint16_t) len - sizeof(*ip6h));
462 ip6h->ip6_nxt = (uint8_t) proto;
463 ip6h->ip6_hlim = (uint8_t) ttl;
465 memcpy(&ip6h->ip6_src, &(((const struct sockaddr_in6 *)
466 src)->sin6_addr), sizeof(ip6h->ip6_src));
467 memcpy(&ip6h->ip6_dst, &(((const struct sockaddr_in6 *)
468 dst)->sin6_addr), sizeof(ip6h->ip6_dst));
470 data = packet + sizeof(*ip6h);
471 data_len = len - sizeof(*ip6h);
473 switch (proto) {
474 case IPPROTO_TCP:
475 __assemble_tcp6(data, data_len, ctx, dst, src);
476 break;
478 case IPPROTO_ICMP:
479 case IPPROTO_ICMPV6:
480 __assemble_icmp6(data, data_len, ctx, dst, src);
481 break;
483 default:
484 bug();
487 return ntohl(ip6h->ip6_flow) & 0x000fffff;
490 static int check_ipv4(uint8_t *packet, size_t len, int ttl __maybe_unused,
491 int id, const struct sockaddr *ss)
493 struct iphdr *iph = (struct iphdr *) packet;
494 struct iphdr *iph_inner;
495 struct icmphdr *icmph;
497 if (iph->protocol != IPPROTO_ICMP)
498 return -EINVAL;
499 if (iph->daddr != ((const struct sockaddr_in *) ss)->sin_addr.s_addr)
500 return -EINVAL;
502 icmph = (struct icmphdr *) (packet + sizeof(struct iphdr));
503 if (icmph->type != ICMP_TIME_EXCEEDED)
504 return -EINVAL;
505 if (icmph->code != ICMP_EXC_TTL)
506 return -EINVAL;
508 iph_inner = (struct iphdr *) (packet + sizeof(struct iphdr) +
509 sizeof(struct icmphdr));
510 if (ntohs(iph_inner->id) != id)
511 return -EINVAL;
513 return len;
516 static void handle_ipv4(uint8_t *packet, size_t len __maybe_unused,
517 bool do_dns_resolution, bool do_geo_lookup)
519 char hbuff[NI_MAXHOST];
520 struct iphdr *iph = (struct iphdr *) packet;
521 struct sockaddr_in sd;
522 struct hostent *hent;
523 const char *as, *country;
524 char *city;
526 memset(hbuff, 0, sizeof(hbuff));
527 memset(&sd, 0, sizeof(sd));
528 sd.sin_family = PF_INET;
529 sd.sin_addr.s_addr = iph->saddr;
531 getnameinfo((struct sockaddr *) &sd, sizeof(sd),
532 hbuff, sizeof(hbuff), NULL, 0, NI_NUMERICHOST);
534 as = geoip4_as_name(&sd);
535 country = geoip4_country_name(&sd);
536 city = geoip4_city_name(&sd);
538 if (do_dns_resolution) {
539 hent = gethostbyaddr(&sd.sin_addr, sizeof(sd.sin_addr), PF_INET);
540 if (hent)
541 printf(" %s (%s)", hent->h_name, hbuff);
542 else
543 printf(" %s", hbuff);
544 } else {
545 printf(" %s", hbuff);
547 if (as)
548 printf(" in %s", as);
549 if (country) {
550 printf(" in %s", country);
551 if (city)
552 printf(", %s", city);
554 if (do_geo_lookup)
555 printf(" (%f/%f)", geoip4_latitude(&sd), geoip4_longitude(&sd));
557 free(city);
560 static int check_ipv6(uint8_t *packet, size_t len, int ttl __maybe_unused,
561 int id, const struct sockaddr *ss)
563 struct ip6_hdr *ip6h = (struct ip6_hdr *) packet;
564 struct ip6_hdr *ip6h_inner;
565 struct icmp6hdr *icmp6h;
567 if (ip6h->ip6_nxt != IPPROTO_ICMPV6)
568 return -EINVAL;
569 if (memcmp(&ip6h->ip6_dst, &(((const struct sockaddr_in6 *)
570 ss)->sin6_addr), sizeof(ip6h->ip6_dst)))
571 return -EINVAL;
573 icmp6h = (struct icmp6hdr *) (packet + sizeof(*ip6h));
574 if (icmp6h->icmp6_type != ICMPV6_TIME_EXCEED)
575 return -EINVAL;
576 if (icmp6h->icmp6_code != ICMPV6_EXC_HOPLIMIT)
577 return -EINVAL;
579 ip6h_inner = (struct ip6_hdr *) (packet + sizeof(*ip6h) + sizeof(*icmp6h));
580 if ((ntohl(ip6h_inner->ip6_flow) & 0x000fffff) != (uint32_t) id)
581 return -EINVAL;
583 return len;
586 static void handle_ipv6(uint8_t *packet, size_t len __maybe_unused,
587 bool do_dns_resolution, bool do_geo_lookup)
589 char hbuff[NI_MAXHOST];
590 struct ip6_hdr *ip6h = (struct ip6_hdr *) packet;
591 struct sockaddr_in6 sd;
592 struct hostent *hent;
593 const char *as, *country;
594 char *city;
596 memset(hbuff, 0, sizeof(hbuff));
597 memset(&sd, 0, sizeof(sd));
598 sd.sin6_family = PF_INET6;
599 memcpy(&sd.sin6_addr, &ip6h->ip6_src, sizeof(ip6h->ip6_src));
601 getnameinfo((struct sockaddr *) &sd, sizeof(sd),
602 hbuff, sizeof(hbuff), NULL, 0, NI_NUMERICHOST);
604 as = geoip6_as_name(&sd);
605 country = geoip6_country_name(&sd);
606 city = geoip6_city_name(&sd);
608 if (do_dns_resolution) {
609 hent = gethostbyaddr(&sd.sin6_addr, sizeof(sd.sin6_addr), PF_INET6);
610 if (hent)
611 printf(" %s (%s)", hent->h_name, hbuff);
612 else
613 printf(" %s", hbuff);
614 } else {
615 printf(" %s", hbuff);
617 if (as)
618 printf(" in %s", as);
619 if (country) {
620 printf(" in %s", country);
621 if (city)
622 printf(", %s", city);
624 if (do_geo_lookup)
625 printf(" (%f/%f)", geoip6_latitude(&sd), geoip6_longitude(&sd));
627 free(city);
630 static void show_trace_info(struct ctx *ctx, const struct sockaddr_storage *ss,
631 const struct sockaddr_storage *sd)
633 char hbuffs[256], hbuffd[256];
635 memset(hbuffd, 0, sizeof(hbuffd));
636 getnameinfo((struct sockaddr *) sd, sizeof(*sd),
637 hbuffd, sizeof(hbuffd), NULL, 0, NI_NUMERICHOST);
639 memset(hbuffs, 0, sizeof(hbuffs));
640 getnameinfo((struct sockaddr *) ss, sizeof(*ss),
641 hbuffs, sizeof(hbuffs), NULL, 0, NI_NUMERICHOST);
643 printf("AS path IPv%d TCP trace from %s to %s:%s (%s) with len %zu "
644 "Bytes, %u max hops\n", ctx->proto == IPPROTO_IP ? 4 : 6,
645 hbuffs, hbuffd, ctx->port, ctx->host, ctx->totlen, ctx->max_ttl);
647 printf("Using flags SYN:%d,ACK:%d,ECN:%d,FIN:%d,PSH:%d,RST:%d,URG:%d\n",
648 ctx->syn, ctx->ack, ctx->ecn, ctx->fin, ctx->psh, ctx->rst, ctx->urg);
650 if (ctx->payload)
651 printf("With payload: \'%s\'\n", ctx->payload);
654 static int get_remote_fd(struct ctx *ctx, struct sockaddr_storage *ss,
655 struct sockaddr_storage *sd)
657 int fd = -1, ret, one = 1, af = AF_INET;
658 struct addrinfo hints, *ahead, *ai;
659 unsigned char bind_ip[sizeof(struct in6_addr)];
661 memset(&hints, 0, sizeof(hints));
662 hints.ai_family = PF_UNSPEC;
663 hints.ai_socktype = SOCK_STREAM;
664 hints.ai_protocol = IPPROTO_TCP;
665 hints.ai_flags = AI_NUMERICSERV;
667 ret = getaddrinfo(ctx->host, ctx->port, &hints, &ahead);
668 if (ret < 0)
669 panic("Cannot get address info!\n");
671 for (ai = ahead; ai != NULL && fd < 0; ai = ai->ai_next) {
672 if (!((ai->ai_family == PF_INET6 && ctx->proto == IPPROTO_IPV6) ||
673 (ai->ai_family == PF_INET && ctx->proto == IPPROTO_IP)))
674 continue;
676 fd = socket(ai->ai_family, SOCK_RAW, IPPROTO_RAW);
677 if (fd < 0)
678 continue;
680 memset(ss, 0, sizeof(*ss));
681 ret = device_address(ctx->dev, ai->ai_family, ss);
682 if (ret < 0 && !ctx->bind_addr)
683 panic("Cannot get own device address!\n");
685 if (ctx->bind_addr) {
686 if (ctx->proto == IPPROTO_IPV6)
687 af = AF_INET6;
689 if (inet_pton(af, ctx->bind_addr, &bind_ip) != 1)
690 panic("Address is invalid!\n");
692 if (af == AF_INET6) {
693 struct sockaddr_in6 *ss6 = (struct sockaddr_in6 *) ss;
694 memcpy(&ss6->sin6_addr.s6_addr, &bind_ip, sizeof(struct in6_addr));
695 } else {
696 struct sockaddr_in *ss4 = (struct sockaddr_in *) ss;
697 memcpy(&ss4->sin_addr.s_addr, &bind_ip, sizeof(struct in_addr));
701 ret = bind(fd, (struct sockaddr *) ss, sizeof(*ss));
702 if (ret < 0)
703 panic("Cannot bind socket!\n");
705 memset(sd, 0, sizeof(*sd));
706 memcpy(sd, ai->ai_addr, ai->ai_addrlen);
708 ctx->sd_len = ai->ai_addrlen;
709 ctx->dport = strtoul(ctx->port, NULL, 10);
711 ret = setsockopt(fd, ctx->proto, IP_HDRINCL, &one, sizeof(one));
712 if (ret < 0)
713 panic("Kernel does not support IP_HDRINCL!\n");
715 if (ai->ai_family == PF_INET6) {
716 struct sockaddr_in6 *sd6 = (struct sockaddr_in6 *) sd;
718 sd6->sin6_port = 0;
721 break;
724 freeaddrinfo(ahead);
726 if (fd < 0)
727 panic("Cannot create socket! Does remote "
728 "support IPv%d?!\n",
729 ctx->proto == IPPROTO_IP ? 4 : 6);
731 return fd;
734 static void inject_filter(struct ctx *ctx, int fd)
736 struct sock_fprog bpf_ops;
738 enable_kernel_bpf_jit_compiler();
740 memset(&bpf_ops, 0, sizeof(bpf_ops));
741 bpf_ops.filter = (struct sock_filter *) af_ops[ctx->proto].filter;
742 bpf_ops.len = af_ops[ctx->proto].flen;
744 bpf_attach_to_sock(fd, &bpf_ops);
747 static int __process_node(struct ctx *ctx, int fd, int fd_cap, int ttl,
748 int inner_proto, uint8_t *pkt_snd, uint8_t *pkt_rcv,
749 const struct sockaddr_storage *ss,
750 const struct sockaddr_storage *sd, struct timeval *diff)
752 int pkt_id, ret, timeout;
753 struct pollfd pfd;
754 struct timeval start, end;
756 prepare_polling(fd_cap, &pfd);
758 memset(pkt_snd, 0, ctx->totlen);
759 pkt_id = af_ops[ctx->proto].assembler(pkt_snd, ctx->totlen, ttl,
760 inner_proto, ctx,
761 (const struct sockaddr *) sd,
762 (const struct sockaddr *) ss);
764 ret = sendto(fd, pkt_snd, ctx->totlen, 0, (struct sockaddr *) sd,
765 ctx->sd_len);
766 if (ret < 0)
767 panic("sendto failed: %s\n", strerror(errno));
769 bug_on(gettimeofday(&start, NULL));
771 timeout = (ctx->timeout > 0 ? ctx->timeout : 2) * 1000;
773 ret = poll(&pfd, 1, timeout);
774 if (ret > 0 && pfd.revents & POLLIN && sigint == 0) {
775 bug_on(gettimeofday(&end, NULL));
776 if (diff)
777 timersub(&end, &start, diff);
779 ret = recvfrom(fd_cap, pkt_rcv, ctx->rcvlen, 0, NULL, NULL);
780 if (ret < (int) (sizeof(struct ethhdr) + af_ops[ctx->proto].min_len_icmp))
781 return -EIO;
783 return af_ops[ctx->proto].check(pkt_rcv + sizeof(struct ethhdr),
784 ret - sizeof(struct ethhdr), ttl,
785 pkt_id, (const struct sockaddr *) ss);
786 } else {
787 return -EIO;
790 return 0;
793 static void timerdiv(const unsigned long divisor, const struct timeval *tv,
794 struct timeval *result)
796 uint64_t x = ((uint64_t) tv->tv_sec * 1000 * 1000 + tv->tv_usec) / divisor;
798 result->tv_sec = x / 1000 / 1000;
799 result->tv_usec = x % (1000 * 1000);
802 static int timevalcmp(const void *t1, const void *t2)
804 if (timercmp((struct timeval *) t1, (struct timeval *) t2, <))
805 return -1;
806 if (timercmp((struct timeval *) t1, (struct timeval *) t2, >))
807 return 1;
809 return 0;
812 static const char *proto_short(int proto)
814 switch (proto) {
815 case IPPROTO_TCP:
816 return "t";
817 case IPPROTO_ICMP:
818 case IPPROTO_ICMPV6:
819 return "i";
820 default:
821 return "?";
825 static int __process_time(struct ctx *ctx, int fd, int fd_cap, int ttl,
826 int inner_proto, uint8_t *pkt_snd, uint8_t *pkt_rcv,
827 const struct sockaddr_storage *ss,
828 const struct sockaddr_storage *sd)
830 size_t i, j = 0;
831 int good = 0, ret = -EIO, idx, ret_good = -EIO;
832 struct timeval probes[9], *tmp, sum, res;
833 uint8_t *trash = xmalloc(ctx->rcvlen);
834 char *cwait[] = { "-", "\\", "|", "/" };
836 memset(probes, 0, sizeof(probes));
837 for (i = 0; i < array_size(probes) && sigint == 0; ++i) {
838 ret = __process_node(ctx, fd, fd_cap, ttl, inner_proto,
839 pkt_snd, good == 0 ? pkt_rcv : trash,
840 ss, sd, &probes[i]);
841 if (ret > 0) {
842 if (good == 0)
843 ret_good = ret;
844 good++;
847 if (good == 0 && ctx->queries == (int) i)
848 break;
850 usleep(50000);
852 printf("\r%2d: %s", ttl, cwait[j++]);
853 fflush(stdout);
854 if (j >= array_size(cwait))
855 j = 0;
858 if (good == 0) {
859 xfree(trash);
860 return -EIO;
863 tmp = xcalloc(good, sizeof(struct timeval));
864 for (i = j = 0; i < array_size(probes); ++i) {
865 if (probes[i].tv_sec == 0 && probes[i].tv_usec == 0)
866 continue;
867 tmp[j].tv_sec = probes[i].tv_sec;
868 tmp[j].tv_usec = probes[i].tv_usec;
869 j++;
872 qsort(tmp, j, sizeof(struct timeval), timevalcmp);
874 printf("\r%2d: %s[", ttl, proto_short(inner_proto));
875 idx = j / 2;
876 switch (j % 2) {
877 case 0:
878 timeradd(&tmp[idx], &tmp[idx - 1], &sum);
879 timerdiv(2, &sum, &res);
880 if (res.tv_sec > 0)
881 printf("%lu sec ", res.tv_sec);
882 printf("%7lu us", res.tv_usec);
883 break;
884 case 1:
885 if (tmp[idx].tv_sec > 0)
886 printf("%lu sec ", tmp[idx].tv_sec);
887 printf("%7lu us", tmp[idx].tv_usec);
888 break;
890 printf("]");
892 xfree(tmp);
893 xfree(trash);
895 return ret_good;
898 static int __probe_remote(struct ctx *ctx, int fd, int fd_cap, int ttl,
899 uint8_t *pkt_snd, uint8_t *pkt_rcv,
900 const struct sockaddr_storage *ss,
901 const struct sockaddr_storage *sd,
902 int inner_proto)
904 int ret = -EIO, tries = ctx->queries;
906 while (tries-- > 0 && sigint == 0) {
907 ret = __process_time(ctx, fd, fd_cap, ttl, inner_proto,
908 pkt_snd, pkt_rcv, ss, sd);
909 if (ret < 0)
910 continue;
912 af_ops[ctx->proto].handler(pkt_rcv + sizeof(struct ethhdr),
913 ret - sizeof(struct ethhdr),
914 ctx->do_dns_resolution, ctx->do_geo_lookup);
915 if (ctx->do_show_packet) {
916 struct pkt_buff *pkt;
918 printf("\n");
919 pkt = pkt_alloc(pkt_rcv, ret);
920 hex_ascii(pkt);
921 tprintf_flush();
922 pkt_free(pkt);
925 break;
928 return ret;
931 static int __process_ttl(struct ctx *ctx, int fd, int fd_cap, int ttl,
932 uint8_t *pkt_snd, uint8_t *pkt_rcv,
933 const struct sockaddr_storage *ss,
934 const struct sockaddr_storage *sd)
936 int ret = -EIO;
937 size_t i;
938 const int inner_protos[] = {
939 IPPROTO_TCP,
940 IPPROTO_ICMP,
943 printf("%2d: ", ttl);
944 fflush(stdout);
946 for (i = 0; i < array_size(inner_protos) && sigint == 0; ++i) {
947 ret = __probe_remote(ctx, fd, fd_cap, ttl, pkt_snd, pkt_rcv, ss, sd,
948 inner_protos[i]);
949 if (ret > 0)
950 break;
953 if (ret <= 0)
954 printf("\r%2d: ?[ no answer]", ttl);
955 if (!ctx->do_show_packet)
956 printf("\n");
957 if (ctx->do_show_packet && ret <= 0)
958 printf("\n\n");
960 fflush(stdout);
961 return 0;
964 static int main_trace(struct ctx *ctx)
966 int fd, fd_cap, ifindex, ttl;
967 struct ring dummy_ring;
968 struct sockaddr_storage ss, sd;
969 uint8_t *pkt_snd, *pkt_rcv;
971 fd = get_remote_fd(ctx, &ss, &sd);
972 fd_cap = pf_socket();
974 inject_filter(ctx, fd_cap);
976 ifindex = device_ifindex(ctx->dev);
977 bind_ring_generic(fd_cap, &dummy_ring, ifindex, false);
979 if (ctx->totlen < af_ops[ctx->proto].min_len_tcp) {
980 ctx->totlen = af_ops[ctx->proto].min_len_tcp;
981 if (ctx->payload)
982 ctx->totlen += strlen(ctx->payload);
985 ctx->rcvlen = device_mtu(ctx->dev) - sizeof(struct ethhdr);
986 if (ctx->totlen >= ctx->rcvlen)
987 panic("packet length (%zu) exceeds device MTU (%zu)\n", ctx->totlen, ctx->rcvlen);
989 pkt_snd = xmalloc(ctx->totlen);
990 pkt_rcv = xmalloc(ctx->rcvlen);
992 show_trace_info(ctx, &ss, &sd);
994 for (ttl = ctx->init_ttl; ttl <= ctx->max_ttl && sigint == 0; ++ttl)
995 __process_ttl(ctx, fd, fd_cap, ttl, pkt_snd, pkt_rcv,
996 &ss, &sd);
998 xfree(pkt_snd);
999 xfree(pkt_rcv);
1001 close(fd_cap);
1002 close(fd);
1004 return 0;
1007 int main(int argc, char **argv)
1009 int c, ret;
1010 struct ctx ctx;
1012 setfsuid(getuid());
1013 setfsgid(getgid());
1015 srand(time(NULL));
1017 memset(&ctx, 0, sizeof(ctx));
1018 ctx.init_ttl = 1;
1019 ctx.max_ttl = 30;
1020 ctx.queries = 2;
1021 ctx.timeout = 2;
1022 ctx.proto = IPPROTO_IP;
1023 ctx.payload = NULL;
1024 ctx.dev = xstrdup("eth0");
1025 ctx.port = xstrdup("80");
1026 ctx.bind_addr = NULL;
1028 while ((c = getopt_long(argc, argv, short_options, long_options,
1029 NULL)) != EOF) {
1030 switch (c) {
1031 case 'h':
1032 help();
1033 break;
1034 case 'v':
1035 version();
1036 break;
1037 case 'u':
1038 update_geoip();
1039 die();
1040 break;
1041 case 'H':
1042 ctx.host = xstrdup(optarg);
1043 break;
1044 case 'p':
1045 if (ctx.port)
1046 xfree(ctx.port);
1047 ctx.port = xstrdup(optarg);
1048 break;
1049 case 'n':
1050 ctx.do_dns_resolution = false;
1051 break;
1052 case '4':
1053 ctx.proto = IPPROTO_IP;
1054 break;
1055 case '6':
1056 ctx.proto = IPPROTO_IPV6;
1057 break;
1058 case 'Z':
1059 ctx.do_show_packet = true;
1060 break;
1061 case 'N':
1062 ctx.do_dns_resolution = true;
1063 break;
1064 case 'f':
1065 ctx.init_ttl = atoi(optarg);
1066 if (ctx.init_ttl <= 0)
1067 help();
1068 break;
1069 case 'm':
1070 ctx.max_ttl = atoi(optarg);
1071 if (ctx.max_ttl <= 0)
1072 help();
1073 break;
1074 case 'b':
1075 ctx.bind_addr = xstrdup(optarg);
1076 break;
1077 case 'i':
1078 case 'd':
1079 free(ctx.dev);
1080 ctx.dev = xstrdup(optarg);
1081 break;
1082 case 'q':
1083 ctx.queries = atoi(optarg);
1084 if (ctx.queries <= 0)
1085 help();
1086 break;
1087 case 'x':
1088 ctx.timeout = atoi(optarg);
1089 if (ctx.timeout <= 0)
1090 help();
1091 break;
1092 case 'L':
1093 ctx.do_geo_lookup = true;
1094 break;
1095 case 'S':
1096 ctx.syn = 1;
1097 break;
1098 case 'A':
1099 ctx.ack = 1;
1100 break;
1101 case 'F':
1102 ctx.fin = 1;
1103 break;
1104 case 'U':
1105 ctx.urg = 1;
1106 break;
1107 case 'P':
1108 ctx.psh = 1;
1109 break;
1110 case 'R':
1111 ctx.rst = 1;
1112 break;
1113 case 'E':
1114 ctx.syn = 1;
1115 ctx.ecn = 1;
1116 break;
1117 case 't':
1118 ctx.tos = atoi(optarg);
1119 if (ctx.tos < 0)
1120 help();
1121 break;
1122 case 'G':
1123 ctx.nofrag = 1;
1124 break;
1125 case 'X':
1126 ctx.payload = xstrdup(optarg);
1127 break;
1128 case 'l':
1129 ctx.totlen = strtoul(optarg, NULL, 10);
1130 if (ctx.totlen == 0)
1131 help();
1132 break;
1133 case '?':
1134 switch (optopt) {
1135 case 'H':
1136 case 'p':
1137 case 'f':
1138 case 'm':
1139 case 'i':
1140 case 'd':
1141 case 'q':
1142 case 'x':
1143 case 'X':
1144 case 't':
1145 case 'l':
1146 panic("option -%c requires an argument!\n",
1147 optopt);
1148 default:
1149 if (isprint(optopt))
1150 printf("unknown option character '0x%X'!\n", optopt);
1151 die();
1153 default:
1154 break;
1158 if (argc < 3 || !ctx.host || !ctx.port || ctx.init_ttl > ctx.max_ttl ||
1159 ctx.init_ttl > MAXTTL || ctx.max_ttl > MAXTTL)
1160 help();
1162 if (!device_up_and_running(ctx.dev))
1163 panic("networking device %s is not up and running\n", ctx.dev);
1164 if (device_mtu(ctx.dev) <= ctx.totlen)
1165 panic("packet length (%zu) exceeds device MTU (%zu)\n", ctx.totlen, device_mtu(ctx.dev));
1167 register_signal(SIGHUP, signal_handler);
1168 register_signal(SIGINT, signal_handler);
1169 register_signal(SIGQUIT, signal_handler);
1170 register_signal(SIGTERM, signal_handler);
1172 tprintf_init();
1173 init_geoip(1);
1175 ret = main_trace(&ctx);
1177 destroy_geoip();
1178 tprintf_cleanup();
1180 free(ctx.dev);
1181 free(ctx.host);
1182 free(ctx.port);
1183 free(ctx.bind_addr);
1184 free(ctx.payload);
1186 return ret;