astraceroute: use sizeof(*iph)
[netsniff-ng.git] / src / astraceroute.c
blob59ffe3fd0611cba970e3a56b86fdb74e36a31391
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2011 Daniel Borkmann.
5 * Subject to the GPL, version 2.
7 * An Autonomous System trace route utility based on TCP instead of ICMP for
8 * a better passing of firewalls. Supports IPv4 and IPv6. Based on the idea
9 * of tcptraceroute (http://michael.toren.net/code/tcptraceroute/), but hacked
10 * for Autonomous Systems tracing, thus you will know an approximate path of
11 * your curvetun tunneled packets, for instance. However, astraceroute was
12 * written from scratch and does not use any libraries. Special thanks to
13 * Team CYMRU!
15 * The road must be trod, but it will be very hard. And neither strength nor
16 * wisdom will carry us far upon it. This quest may be attempted by the weak
17 * with as much hope as the strong. Yet such is oft the course of deeds that
18 * move the wheels of the world: small hands do them because they must,
19 * while the eyes of the great are elsewhere.
21 * -- The Lord of the Rings, Elrond, Chapter 'The Council of Elrond'.
23 * astraceroute includes GeoLite data created by MaxMind, available from
24 * http://www.maxmind.com/. On Debian you need libgeoip-dev, libgeoip1 and
25 * geoip-database-contrib.
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <signal.h>
31 #include <getopt.h>
32 #include <ctype.h>
33 #include <stdint.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/socket.h>
37 #include <fcntl.h>
38 #include <string.h>
39 #include <asm/byteorder.h>
40 #include <linux/tcp.h>
41 #include <netinet/ip.h>
42 #include <netinet/ip6.h>
43 #include <netinet/in.h>
44 #include <errno.h>
45 #include <netdb.h>
46 #include <arpa/inet.h>
47 #include <linux/if_ether.h>
48 #include <linux/icmp.h>
49 #include <linux/icmpv6.h>
50 #include <GeoIP.h>
51 #include <GeoIPCity.h>
53 #include "bpf.h"
54 #include "die.h"
55 #include "tprintf.h"
56 #include "pkt_buff.h"
57 #include "proto.h"
58 #include "xmalloc.h"
59 #include "xio.h"
60 #include "aslookup.h"
61 #include "xutils.h"
62 #include "mtrand.h"
63 #include "ring_rx.h"
64 #include "built_in.h"
66 #define WHOIS_SERVER_SOURCE "/etc/netsniff-ng/whois.conf"
68 struct ash_cfg {
69 char *host;
70 char *port;
71 int init_ttl;
72 int max_ttl;
73 int dns_resolv;
74 char *dev;
75 int queries;
76 int timeout;
77 int syn, ack, ecn, fin, psh, rst, urg;
78 int tos, nofrag;
79 int totlen;
80 char *whois;
81 char *whois_port;
82 int ip;
83 char *payload;
86 volatile sig_atomic_t sigint = 0;
88 static int show_pkt = 0;
90 static GeoIP *gi_country = NULL;
91 static GeoIP *gi_city = NULL;
93 static const char *short_options = "H:p:nNf:m:i:d:q:x:SAEFPURt:Gl:w:W:hv46X:ZLK";
95 static struct option long_options[] = {
96 {"host", required_argument, 0, 'H'},
97 {"port", required_argument, 0, 'p'},
98 {"init-ttl", required_argument, 0, 'f'},
99 {"max-ttl", required_argument, 0, 'm'},
100 {"numeric", no_argument, 0, 'n'},
101 {"dns", no_argument, 0, 'N'},
102 {"ipv4", no_argument, 0, '4'},
103 {"ipv6", no_argument, 0, '6'},
104 {"dev", required_argument, 0, 'd'},
105 {"num-probes", required_argument, 0, 'q'},
106 {"timeout", required_argument, 0, 'x'},
107 {"syn", no_argument, 0, 'S'},
108 {"ack", no_argument, 0, 'A'},
109 {"urg", no_argument, 0, 'U'},
110 {"fin", no_argument, 0, 'F'},
111 {"psh", no_argument, 0, 'P'},
112 {"rst", no_argument, 0, 'R'},
113 {"ecn-syn", no_argument, 0, 'E'},
114 {"tos", required_argument, 0, 't'},
115 {"payload", required_argument, 0, 'X'},
116 {"show-packet", no_argument, 0, 'Z'},
117 {"nofrag", no_argument, 0, 'G'},
118 {"totlen", required_argument, 0, 'l'},
119 {"whois", required_argument, 0, 'w'},
120 {"wport", required_argument, 0, 'W'},
121 {"city-db", required_argument, 0, 'L'},
122 {"country-db", required_argument, 0, 'K'},
123 {"version", no_argument, 0, 'v'},
124 {"help", no_argument, 0, 'h'},
125 {0, 0, 0, 0}
128 static struct sock_filter ipv4_icmp_type_11[] = {
129 /* (000) ldh [12] */
130 { 0x28, 0, 0, 0x0000000c },
131 /* (001) jeq #0x800 jt 2 jf 10 */
132 { 0x15, 0, 8, 0x00000800 },
133 /* (002) ldb [23] */
134 { 0x30, 0, 0, 0x00000017 },
135 /* (003) jeq #0x1 jt 4 jf 10 */
136 { 0x15, 0, 6, 0x00000001 },
137 /* (004) ldh [20] */
138 { 0x28, 0, 0, 0x00000014 },
139 /* (005) jset #0x1fff jt 10 jf 6 */
140 { 0x45, 4, 0, 0x00001fff },
141 /* (006) ldxb 4*([14]&0xf) */
142 { 0xb1, 0, 0, 0x0000000e },
143 /* (007) ldb [x + 14] */
144 { 0x50, 0, 0, 0x0000000e },
145 /* (008) jeq #0xb jt 9 jf 10 */
146 { 0x15, 0, 1, 0x0000000b },
147 /* (009) ret #65535 */
148 { 0x06, 0, 0, 0xffffffff },
149 /* (010) ret #0 */
150 { 0x06, 0, 0, 0x00000000 },
153 static struct sock_filter ipv6_icmp6_type_3[] = {
154 /* (000) ldh [12] */
155 { 0x28, 0, 0, 0x0000000c },
156 /* (001) jeq #0x86dd jt 2 jf 7 */
157 { 0x15, 0, 5, 0x000086dd },
158 /* (002) ldb [20] */
159 { 0x30, 0, 0, 0x00000014 },
160 /* (003) jeq #0x3a jt 4 jf 7 */
161 { 0x15, 0, 3, 0x0000003a },
162 /* (004) ldb [54] */
163 { 0x30, 0, 0, 0x00000036 },
164 /* (005) jeq #0x3 jt 6 jf 7 */
165 { 0x15, 0, 1, 0x00000003 },
166 /* (006) ret #65535 */
167 { 0x06, 0, 0, 0xffffffff },
168 /* (007) ret #0 */
169 { 0x06, 0, 0, 0x00000000 },
172 #define PKT_NOT_FOR_US 0
173 #define PKT_GOOD 1
175 static inline const char *make_n_a(const char *p)
177 return p ? : "N/A";
180 static void signal_handler(int number)
182 switch (number) {
183 case SIGINT:
184 sigint = 1;
185 break;
186 default:
187 break;
191 static void header(void)
193 printf("%s%s%s\n", colorize_start(bold), "astraceroute "
194 VERSION_STRING, colorize_end());
197 static void help(void)
200 printf("\nastraceroute %s, Autonomous System (AS) trace route utility\n",
201 VERSION_STRING);
202 printf("http://www.netsniff-ng.org\n\n");
203 printf("Usage: astraceroute [options]\n");
204 printf("Options:\n");
205 printf(" -H|--host <host> Host/IPv4/IPv6 to lookup AS route to\n");
206 printf(" -p|--port <port> Hosts port to lookup AS route to\n");
207 printf(" -i|-d|--dev <device> Networking device, i.e. eth0\n");
208 printf(" -4|--ipv4 Use IPv4 requests (default)\n");
209 printf(" -6|--ipv6 Use IPv6 requests\n");
210 printf(" -n|--numeric Do not do reverse DNS lookup for hops\n");
211 printf(" -N|--dns Do a reverse DNS lookup for hops\n");
212 printf(" -f|--init-ttl <ttl> Set initial TTL\n");
213 printf(" -m|--max-ttl <ttl> Set maximum TTL (default: 30)\n");
214 printf(" -q|--num-probes <num> Number of max probes for each hop (default: 3)\n");
215 printf(" -x|--timeout <sec> Probe response timeout in sec (default: 3)\n");
216 printf(" -S|--syn Set TCP SYN flag in packets\n");
217 printf(" -A|--ack Set TCP ACK flag in packets\n");
218 printf(" -F|--fin Set TCP FIN flag in packets\n");
219 printf(" -P|--psh Set TCP PSH flag in packets\n");
220 printf(" -U|--urg Set TCP URG flag in packets\n");
221 printf(" -R|--rst Set TCP RST flag in packets\n");
222 printf(" -E|--ecn-syn Send ECN SYN packets (RFC3168)\n");
223 printf(" -t|--tos <tos> Set the IP TOS field\n");
224 printf(" -G|--nofrag Set do not fragment bit\n");
225 printf(" -X|--payload <string> Specify a payload string to test DPIs\n");
226 printf(" -Z|--show-packet Show returned packet on each hop\n");
227 printf(" -l|--totlen <len> Specify total packet len\n");
228 printf(" -w|--whois <server> Use a different AS whois DB server\n");
229 printf(" (default: /etc/netsniff-ng/whois.conf)\n");
230 printf(" -W|--wport <port> Use a different port to AS whois server\n");
231 printf(" (default: /etc/netsniff-ng/whois.conf)\n");
232 printf(" --city-db <path> Specifiy path for geoip city database\n");
233 printf(" --country-db <path> Specifiy path for geoip country database\n");
234 printf(" -v|--version Print version\n");
235 printf(" -h|--help Print this help\n");
236 printf("\n");
237 printf("Examples:\n");
238 printf(" IPv4 trace of AS with TCP SYN probe (this will most-likely pass):\n");
239 printf(" astraceroute -i eth0 -N -S -H netsniff-ng.org\n");
240 printf(" IPv4 trace of AS with TCP ECN SYN probe:\n");
241 printf(" astraceroute -i eth0 -N -E -H netsniff-ng.org\n");
242 printf(" IPv4 trace of AS with TCP FIN probe:\n");
243 printf(" astraceroute -i eth0 -N -F -H netsniff-ng.org\n");
244 printf(" IPv4 trace of AS with Xmas probe:\n");
245 printf(" astraceroute -i eth0 -N -FPU -H netsniff-ng.org\n");
246 printf(" IPv4 trace of AS with Null probe with ASCII payload:\n");
247 printf(" astraceroute -i eth0 -N -H netsniff-ng.org -X \"censor-me\" -Z\n");
248 printf(" IPv6 trace of AS up to www.6bone.net:\n");
249 printf(" astraceroute -6 -i eth0 -S -E -N -H www.6bone.net\n");
250 printf("\n");
251 printf("Note:\n");
252 printf(" If the TCP probe did not give any results, then astraceroute will\n");
253 printf(" automatically probe for classic ICMP packets! To gather more\n");
254 printf(" information about astraceroute's fetched AS numbers, see i.e.\n");
255 printf(" http://bgp.he.net/AS<number>!\n");
256 printf("\n");
257 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
258 printf("Copyright (C) 2011-2012 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
259 printf("Swiss federal institute of technology (ETH Zurich)\n");
260 printf("License: GNU GPL version 2\n");
261 printf("This is free software: you are free to change and redistribute it.\n");
262 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
263 die();
266 static void version(void)
268 printf("\nastraceroute %s, AS trace route utility\n",
269 VERSION_STRING);
270 printf("http://www.netsniff-ng.org\n\n");
271 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
272 printf("Copyright (C) 2011-2012 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
273 printf("Swiss federal institute of technology (ETH Zurich)\n");
274 printf("License: GNU GPL version 2\n");
275 printf("This is free software: you are free to change and redistribute it.\n");
276 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
277 die();
280 static inline unsigned short csum(unsigned short *buf, int nwords)
282 unsigned long sum;
284 for (sum = 0; nwords > 0; nwords--)
285 sum += *buf++;
286 sum = (sum >> 16) + (sum & 0xffff);
287 sum += (sum >> 16);
289 return ~sum;
292 static void assemble_data(uint8_t *packet, size_t len, const char *payload)
294 int i;
296 if (payload == NULL) {
297 for (i = 0; i < len; ++i)
298 packet[i] = (uint8_t) mt_rand_int32();
299 } else {
300 int lmin = min(len, strlen(payload));
301 for (i = 0; i < lmin; ++i)
302 packet[i] = (uint8_t) payload[i];
303 for (i = lmin; i < len; ++i)
304 packet[i] = (uint8_t) mt_rand_int32();
308 static void assemble_icmp4(uint8_t *packet, size_t len)
310 struct icmphdr *icmph = (struct icmphdr *) packet;
312 bug_on(len < sizeof(struct icmphdr));
314 icmph->type = ICMP_ECHO;
315 icmph->code = 0;
316 icmph->checksum = 0;
319 static void assemble_icmp6(uint8_t *packet, size_t len)
321 struct icmp6hdr *icmp6h = (struct icmp6hdr *) packet;
323 bug_on(len < sizeof(struct icmp6hdr));
325 icmp6h->icmp6_type = ICMPV6_ECHO_REQUEST;
326 icmp6h->icmp6_code = 0;
327 icmp6h->icmp6_cksum = 0;
330 static void assemble_tcp(uint8_t *packet, size_t len, int syn, int ack,
331 int urg, int fin, int rst, int psh, int ecn, int dport)
333 struct tcphdr *tcph = (struct tcphdr *) packet;
335 bug_on(len < sizeof(struct tcphdr));
337 tcph->source = htons((uint16_t) mt_rand_int32());
338 tcph->dest = htons((uint16_t) dport);
339 tcph->seq = htonl(mt_rand_int32());
340 tcph->ack_seq = (!!ack ? htonl(mt_rand_int32()) : 0);
341 tcph->doff = 5;
342 tcph->syn = !!syn;
343 tcph->ack = !!ack;
344 tcph->urg = !!urg;
345 tcph->fin = !!fin;
346 tcph->rst = !!rst;
347 tcph->psh = !!psh;
348 tcph->ece = !!ecn;
349 tcph->cwr = !!ecn;
350 tcph->window = htons((uint16_t) (100 + (mt_rand_int32() % 65435)));
351 tcph->check = 0;
352 tcph->urg_ptr = (!!urg ? htons((uint16_t) mt_rand_int32()) : 0);
355 static int assemble_ipv4_tcp(uint8_t *packet, size_t len, int ttl,
356 int tos, const struct sockaddr *dst,
357 const struct sockaddr *src, int syn, int ack,
358 int urg, int fin, int rst, int psh, int ecn,
359 int nofrag, int dport, const char *payload)
361 struct iphdr *iph = (struct iphdr *) packet;
362 uint8_t *data;
363 size_t data_len;
365 bug_on(!src || !dst);
366 bug_on(src->sa_family != PF_INET || dst->sa_family != PF_INET);
367 bug_on(len < sizeof(struct iphdr) + sizeof(struct tcphdr));
369 iph->ihl = 5;
370 iph->version = 4;
371 iph->tos = (uint8_t) tos;
372 iph->tot_len = htons((uint16_t) len);
373 iph->id = htons((uint16_t) mt_rand_int32());
374 iph->frag_off = nofrag ? IP_DF : 0;
375 iph->ttl = (uint8_t) ttl;
376 iph->protocol = 6; /* TCP */
377 iph->saddr = ((const struct sockaddr_in *) src)->sin_addr.s_addr;
378 iph->daddr = ((const struct sockaddr_in *) dst)->sin_addr.s_addr;
380 data = packet + sizeof(*iph);
381 data_len = len - sizeof(*iph);
382 assemble_tcp(data, data_len, syn, ack, urg, fin, rst, psh, ecn, dport);
384 data = packet + sizeof(*iph) + sizeof(struct tcphdr);
385 data_len = len - sizeof(*iph) - sizeof(struct tcphdr);
386 assemble_data(data, data_len, payload);
388 iph->check = csum((unsigned short *) packet, ntohs(iph->tot_len) >> 1);
390 return ntohs(iph->id);
393 static int assemble_ipv6_tcp(uint8_t *packet, size_t len, int ttl,
394 const struct sockaddr *dst,
395 const struct sockaddr *src, int syn, int ack,
396 int urg, int fin, int rst, int psh, int ecn,
397 int dport, const char *payload)
399 struct ip6_hdr *ip6h = (struct ip6_hdr *) packet;
400 uint8_t *data;
401 size_t data_len;
403 bug_on(!src || !dst);
404 bug_on(src->sa_family != PF_INET6 || dst->sa_family != PF_INET6);
405 bug_on(len < sizeof(*ip6h) + sizeof(struct tcphdr));
407 ip6h->ip6_flow = htonl(mt_rand_int32() & 0x000fffff);
408 ip6h->ip6_vfc = 0x60;
409 ip6h->ip6_plen = htons((uint16_t) len - sizeof(*ip6h));
410 ip6h->ip6_nxt = 6; /* TCP */
411 ip6h->ip6_hlim = (uint8_t) ttl;
412 memcpy(&ip6h->ip6_src, &(((const struct sockaddr_in6 *)
413 src)->sin6_addr), sizeof(ip6h->ip6_src));
414 memcpy(&ip6h->ip6_dst, &(((const struct sockaddr_in6 *)
415 dst)->sin6_addr), sizeof(ip6h->ip6_dst));
417 data = packet + sizeof(*ip6h);
418 data_len = len - sizeof(*ip6h);
419 assemble_tcp(data, data_len, syn, ack, urg, fin, rst, psh, ecn, dport);
421 data = packet + sizeof(*ip6h) + sizeof(struct tcphdr);
422 data_len = len - sizeof(*ip6h) - sizeof(struct tcphdr);
423 assemble_data(data, data_len, payload);
425 return ntohl(ip6h->ip6_flow) & 0x000fffff;
428 static int assemble_ipv6_icmp6(uint8_t *packet, size_t len, int ttl,
429 const struct sockaddr *dst,
430 const struct sockaddr *src,
431 const char *payload)
433 struct ip6_hdr *ip6h = (struct ip6_hdr *) packet;
434 uint8_t *data;
435 size_t data_len;
437 bug_on(!src || !dst);
438 bug_on(src->sa_family != PF_INET6 || dst->sa_family != PF_INET6);
439 bug_on(len < sizeof(*ip6h) + sizeof(struct icmp6hdr));
441 ip6h->ip6_flow = htonl(mt_rand_int32() & 0x000fffff);
442 ip6h->ip6_vfc = 0x60;
443 ip6h->ip6_plen = htons((uint16_t) len - sizeof(*ip6h));
444 ip6h->ip6_nxt = 0x3a; /* ICMP6 */
445 ip6h->ip6_hlim = (uint8_t) ttl;
446 memcpy(&ip6h->ip6_src, &(((const struct sockaddr_in6 *)
447 src)->sin6_addr), sizeof(ip6h->ip6_src));
448 memcpy(&ip6h->ip6_dst, &(((const struct sockaddr_in6 *)
449 dst)->sin6_addr), sizeof(ip6h->ip6_dst));
451 data = packet + sizeof(*ip6h);
452 data_len = len - sizeof(*ip6h);
453 assemble_icmp6(data, data_len);
455 data = packet + sizeof(*ip6h) + sizeof(struct icmp6hdr);
456 data_len = len - sizeof(*ip6h) - sizeof(struct icmp6hdr);
457 assemble_data(data, data_len, payload);
459 return ntohl(ip6h->ip6_flow) & 0x000fffff;
462 static int assemble_ipv4_icmp4(uint8_t *packet, size_t len, int ttl,
463 int tos, const struct sockaddr *dst,
464 const struct sockaddr *src, int nofrag,
465 const char *payload)
467 struct iphdr *iph = (struct iphdr *) packet;
468 uint8_t *data;
469 size_t data_len;
471 bug_on(!src || !dst);
472 bug_on(src->sa_family != PF_INET || dst->sa_family != PF_INET);
473 bug_on(len < sizeof(struct iphdr) + sizeof(struct icmphdr));
475 iph->ihl = 5;
476 iph->version = 4;
477 iph->tos = 0;
478 iph->tot_len = htons((uint16_t) len);
479 iph->id = htons((uint16_t) mt_rand_int32());
480 iph->frag_off = nofrag ? IP_DF : 0;
481 iph->ttl = (uint8_t) ttl;
482 iph->protocol = 1; /* ICMP4 */
483 iph->saddr = ((const struct sockaddr_in *) src)->sin_addr.s_addr;
484 iph->daddr = ((const struct sockaddr_in *) dst)->sin_addr.s_addr;
486 data = packet + sizeof(*iph);
487 data_len = len - sizeof(*iph);
488 assemble_icmp4(data, data_len);
490 data = packet + sizeof(*iph) + sizeof(struct icmphdr);
491 data_len = len - sizeof(*iph) - sizeof(struct icmphdr);
492 assemble_data(data, data_len, payload);
494 iph->check = csum((unsigned short *) packet, ntohs(iph->tot_len) >> 1);
496 return ntohs(iph->id);
499 static int assemble_packet_or_die(uint8_t *packet, size_t len,
500 int ttl, int icmp,
501 const struct ash_cfg *cfg,
502 const struct sockaddr *dst,
503 const struct sockaddr *src)
505 if (icmp) {
506 if (cfg->ip == 4) {
507 return assemble_ipv4_icmp4(packet, len, ttl, cfg->tos,
508 dst, src, cfg->nofrag,
509 cfg->payload);
510 } else {
511 return assemble_ipv6_icmp6(packet, len, ttl, dst, src,
512 cfg->payload);
514 } else {
515 if (cfg->ip == 4) {
516 return assemble_ipv4_tcp(packet, len, ttl, cfg->tos,
517 dst, src, cfg->syn, cfg->ack,
518 cfg->urg, cfg->fin, cfg->rst,
519 cfg->psh, cfg->ecn,
520 cfg->nofrag, atoi(cfg->port),
521 cfg->payload);
522 } else {
523 return assemble_ipv6_tcp(packet, len, ttl, dst, src,
524 cfg->syn, cfg->ack, cfg->urg,
525 cfg->fin, cfg->rst, cfg->psh,
526 cfg->ecn, atoi(cfg->port),
527 cfg->payload);
531 return -EIO;
534 static int handle_ipv4_icmp(uint8_t *packet, size_t len, int ttl, int id,
535 const struct sockaddr *own, int dns_resolv)
537 int ret;
538 struct iphdr *iph = (struct iphdr *) packet;
539 struct iphdr *iph_inner;
540 struct icmphdr *icmph;
541 char *hbuff;
542 struct sockaddr_in sa;
543 struct asrecord rec;
544 GeoIPRecord *gir;
546 if (iph->protocol != 1)
547 return PKT_NOT_FOR_US;
548 if (iph->daddr != ((const struct sockaddr_in *) own)->sin_addr.s_addr)
549 return PKT_NOT_FOR_US;
551 icmph = (struct icmphdr *) (packet + sizeof(struct iphdr));
552 if (icmph->type != ICMP_TIME_EXCEEDED)
553 return PKT_NOT_FOR_US;
554 if (icmph->code != ICMP_EXC_TTL)
555 return PKT_NOT_FOR_US;
557 iph_inner = (struct iphdr *) (packet + sizeof(struct iphdr) +
558 sizeof(struct icmphdr));
559 if (ntohs(iph_inner->id) != id)
560 return PKT_NOT_FOR_US;
562 hbuff = xzmalloc(NI_MAXHOST);
564 memset(&sa, 0, sizeof(sa));
565 sa.sin_family = PF_INET;
566 sa.sin_addr.s_addr = iph->saddr;
568 getnameinfo((struct sockaddr *) &sa, sizeof(sa), hbuff, NI_MAXHOST,
569 NULL, 0, NI_NUMERICHOST);
571 memset(&rec, 0, sizeof(rec));
572 ret = aslookup(hbuff, &rec);
573 if (ret < 0)
574 panic("AS lookup error %d!\n", ret);
576 gir = GeoIP_record_by_ipnum(gi_city, ntohl(iph->saddr));
577 if (!dns_resolv) {
578 if (strlen(rec.country) > 0 && gir) {
579 const char *city = make_n_a(gir->city);
581 printf("%s in AS%s (%s, %s, %s, %f, %f), %s %s (%s), %s", hbuff,
582 rec.number, rec.country,
583 GeoIP_country_name_by_ipnum(gi_country, ntohl(iph->saddr)),
584 city, gir->latitude, gir->longitude,
585 rec.prefix, rec.registry, rec.since, rec.name);
586 } else if (strlen(rec.country) > 0 && !gir) {
587 printf("%s in AS%s (%s, %s), %s %s (%s), %s", hbuff,
588 rec.number, rec.country,
589 GeoIP_country_name_by_ipnum(gi_country, ntohl(iph->saddr)),
590 rec.prefix, rec.registry, rec.since, rec.name);
591 } else {
592 printf("%s in unkown AS", hbuff);
594 } else {
595 struct hostent *hent = gethostbyaddr(&sa.sin_addr,
596 sizeof(sa.sin_addr),
597 PF_INET);
599 if (strlen(rec.country) > 0 && gir) {
600 const char *city = make_n_a(gir->city);
601 printf("%s (%s) in AS%s (%s, %s, %s, %f, %f), %s %s (%s), %s",
602 (hent ? hent->h_name : hbuff), hbuff,
603 rec.number, rec.country,
604 GeoIP_country_name_by_ipnum(gi_country, ntohl(iph->saddr)),
605 city, gir->latitude, gir->longitude,
606 rec.prefix, rec.registry,
607 rec.since, rec.name);
608 } else if (strlen(rec.country) > 0 && !gir) {
609 printf("%s (%s) in AS%s (%s, %s), %s %s (%s), %s",
610 (hent ? hent->h_name : hbuff), hbuff,
611 rec.number, rec.country,
612 GeoIP_country_name_by_ipnum(gi_country, ntohl(iph->saddr)),
613 rec.prefix, rec.registry,
614 rec.since, rec.name);
615 } else {
616 printf("%s (%s) in unkown AS",
617 (hent ? hent->h_name : hbuff), hbuff);
621 xfree(hbuff);
623 return PKT_GOOD;
626 static int handle_ipv6_icmp(uint8_t *packet, size_t len, int ttl, int id,
627 const struct sockaddr *own, int dns_resolv)
629 int ret;
630 struct ip6_hdr *ip6h = (struct ip6_hdr *) packet;
631 struct ip6_hdr *ip6h_inner;
632 struct icmp6hdr *icmp6h;
633 char *hbuff;
634 struct sockaddr_in6 sa;
635 struct asrecord rec;
636 GeoIPRecord *gir;
638 if (ip6h->ip6_nxt != 0x3a)
639 return PKT_NOT_FOR_US;
640 if (memcmp(&ip6h->ip6_dst, &(((const struct sockaddr_in6 *)
641 own)->sin6_addr), sizeof(ip6h->ip6_dst)))
642 return PKT_NOT_FOR_US;
644 icmp6h = (struct icmp6hdr *) (packet + sizeof(*ip6h));
645 if (icmp6h->icmp6_type != ICMPV6_TIME_EXCEED)
646 return PKT_NOT_FOR_US;
647 if (icmp6h->icmp6_code != ICMPV6_EXC_HOPLIMIT)
648 return PKT_NOT_FOR_US;
650 ip6h_inner = (struct ip6_hdr *) (packet + sizeof(*ip6h) + sizeof(*icmp6h));
651 if ((ntohl(ip6h_inner->ip6_flow) & 0x000fffff) != id)
652 return PKT_NOT_FOR_US;
654 hbuff = xzmalloc(NI_MAXHOST);
656 memset(&sa, 0, sizeof(sa));
657 sa.sin6_family = PF_INET6;
658 memcpy(&sa.sin6_addr, &ip6h->ip6_src, sizeof(ip6h->ip6_src));
660 getnameinfo((struct sockaddr *) &sa, sizeof(sa), hbuff, NI_MAXHOST,
661 NULL, 0, NI_NUMERICHOST);
663 memset(&rec, 0, sizeof(rec));
664 ret = aslookup(hbuff, &rec);
665 if (ret < 0)
666 panic("AS lookup error %d!\n", ret);
668 gir = GeoIP_record_by_ipnum_v6(gi_city, sa.sin6_addr);
669 if (!dns_resolv) {
670 if (strlen(rec.country) > 0 && gir) {
671 const char *city = make_n_a(gir->city);
673 printf("%s in AS%s (%s, %s, %s, %f, %f), %s %s (%s), %s", hbuff,
674 rec.number, rec.country,
675 GeoIP_country_name_by_ipnum_v6(gi_country, sa.sin6_addr),
676 city, gir->latitude, gir->longitude,
677 rec.prefix, rec.registry, rec.since, rec.name);
678 } else if (strlen(rec.country) > 0 && !gir) {
679 printf("%s in AS%s (%s, %s), %s %s (%s), %s", hbuff,
680 rec.number, rec.country,
681 GeoIP_country_name_by_ipnum_v6(gi_country, sa.sin6_addr),
682 rec.prefix, rec.registry, rec.since, rec.name);
683 } else {
684 printf("%s in unkown AS", hbuff);
686 } else {
687 struct hostent *hent = gethostbyaddr(&sa.sin6_addr,
688 sizeof(sa.sin6_addr),
689 PF_INET6);
691 if (strlen(rec.country) > 0 && gir) {
692 const char *city = make_n_a(gir->city);
693 printf("%s (%s) in AS%s (%s, %s, %s, %f, %f), %s %s (%s), %s",
694 (hent ? hent->h_name : hbuff), hbuff,
695 rec.number, rec.country,
696 GeoIP_country_name_by_ipnum_v6(gi_country, sa.sin6_addr),
697 city, gir->latitude, gir->longitude,
698 rec.prefix, rec.registry,
699 rec.since, rec.name);
700 } else if (strlen(rec.country) > 0 && !gir) {
701 printf("%s (%s) in AS%s (%s, %s), %s %s (%s), %s",
702 (hent ? hent->h_name : hbuff), hbuff,
703 rec.number, rec.country,
704 GeoIP_country_name_by_ipnum_v6(gi_country, sa.sin6_addr),
705 rec.prefix, rec.registry,
706 rec.since, rec.name);
707 } else {
708 printf("%s (%s) in unkown AS",
709 (hent ? hent->h_name : hbuff), hbuff);
713 xfree(hbuff);
715 return PKT_GOOD;
718 static int handle_packet(uint8_t *packet, size_t len, int ip, int ttl, int id,
719 struct sockaddr *own, int dns_resolv)
721 if (ip == 4)
722 return handle_ipv4_icmp(packet, len, ttl, id, own, dns_resolv);
723 else
724 return handle_ipv6_icmp(packet, len, ttl, id, own, dns_resolv);
727 static int do_trace(const struct ash_cfg *cfg)
729 int ttl, query, fd = -1, one = 1, ret, fd_cap, ifindex;
730 int is_okay = 0, id, timeout_poll;
731 uint8_t *packet, *packet_rcv;
732 ssize_t err, real_len, sd_len;
733 size_t len, len_rcv;
734 struct addrinfo hints, *ahead, *ai;
735 char *hbuff1, *hbuff2;
736 struct sockaddr_storage ss, sd;
737 struct sock_fprog bpf_ops;
738 struct ring dummy_ring;
739 struct pollfd pfd;
741 mt_init_by_random_device();
743 memset(&hints, 0, sizeof(hints));
744 hints.ai_family = PF_UNSPEC;
745 hints.ai_socktype = SOCK_STREAM;
746 hints.ai_protocol = IPPROTO_TCP;
747 hints.ai_flags = AI_NUMERICSERV;
749 ret = getaddrinfo(cfg->host, cfg->port, &hints, &ahead);
750 if (ret < 0) {
751 whine("Cannot get address info!\n");
752 return -EIO;
755 for (ai = ahead; ai != NULL && fd < 0; ai = ai->ai_next) {
756 if (!((ai->ai_family == PF_INET6 && cfg->ip == 6) ||
757 (ai->ai_family == PF_INET && cfg->ip == 4)))
758 continue;
759 fd = socket(ai->ai_family, SOCK_RAW, IPPROTO_RAW);
760 if (fd < 0)
761 continue;
762 fd_cap = pf_socket();
764 memset(&ss, 0, sizeof(ss));
765 ret = device_address(cfg->dev, ai->ai_family, &ss);
766 if (ret < 0)
767 panic("Cannot get own device address!\n");
769 ret = bind(fd, (struct sockaddr *) &ss, sizeof(ss));
770 if (ret < 0)
771 panic("Cannot bind socket!\n");
773 memset(&sd, 0, sizeof(sd));
774 memcpy(&sd, ai->ai_addr, ai->ai_addrlen);
775 if (ai->ai_family == PF_INET6) {
776 struct sockaddr_in6 *sd6 = (struct sockaddr_in6 *) &sd;
777 sd6->sin6_port = htons(0);
779 sd_len = ai->ai_addrlen;
781 break;
784 freeaddrinfo(ahead);
786 if (fd < 0) {
787 whine("Cannot create socket! Does remote support IPv%d?!\n",
788 cfg->ip);
789 return -EIO;
792 len = cfg->totlen;
793 if (cfg->ip == 4) {
794 if (len < sizeof(struct iphdr) + sizeof(struct tcphdr)) {
795 len = sizeof(struct iphdr) + sizeof(struct tcphdr);
796 if (cfg->payload)
797 len += strlen(cfg->payload);
799 } else {
800 if (len < sizeof(struct ip6_hdr) + sizeof(struct tcphdr)) {
801 len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
802 if (cfg->payload)
803 len += strlen(cfg->payload);
807 if (len >= device_mtu(cfg->dev))
808 panic("Packet len exceeds device MTU!\n");
810 packet = xmalloc(len);
811 len_rcv = device_mtu(cfg->dev);
812 packet_rcv = xmalloc(len_rcv);
814 hbuff1 = xzmalloc(256);
815 getnameinfo((struct sockaddr *) &sd, sizeof(sd), hbuff1, 256,
816 NULL, 0, NI_NUMERICHOST);
818 hbuff2 = xzmalloc(256);
819 getnameinfo((struct sockaddr *) &ss, sizeof(ss), hbuff2, 256,
820 NULL, 0, NI_NUMERICHOST);
822 ret = setsockopt(fd, cfg->ip == 4 ? IPPROTO_IP : IPPROTO_IPV6,
823 IP_HDRINCL, &one, sizeof(one));
824 if (ret < 0)
825 panic("Kernel does not support IP_HDRINCL!\n");
827 printf("AS path IPv%d TCP trace from %s to %s:%s (%s) with len %zu "
828 "Bytes, %u max hops\n", cfg->ip, hbuff2, hbuff1, cfg->port,
829 cfg->host, len, cfg->max_ttl);
831 printf("Using flags SYN:%d,ACK:%d,ECN:%d,FIN:%d,PSH:%d,RST:%d,URG:%d\n",
832 cfg->syn, cfg->ack, cfg->ecn, cfg->fin, cfg->psh, cfg->rst,
833 cfg->urg);
835 if (cfg->payload)
836 printf("With payload: \'%s\'\n", cfg->payload);
838 fflush(stdout);
840 xfree(hbuff1);
841 xfree(hbuff2);
843 hbuff1 = hbuff2 = NULL;
845 enable_kernel_bpf_jit_compiler();
847 memset(&bpf_ops, 0, sizeof(bpf_ops));
848 if (cfg->ip == 4) {
849 bpf_ops.filter = ipv4_icmp_type_11;
850 bpf_ops.len = (sizeof(ipv4_icmp_type_11) /
851 sizeof(ipv4_icmp_type_11[0]));
852 } else {
853 bpf_ops.filter = ipv6_icmp6_type_3;
854 bpf_ops.len = (sizeof(ipv6_icmp6_type_3) /
855 sizeof(ipv6_icmp6_type_3[0]));
858 bpf_attach_to_sock(fd_cap, &bpf_ops);
859 ifindex = device_ifindex(cfg->dev);
860 bind_rx_ring(fd_cap, &dummy_ring, ifindex);
861 prepare_polling(fd_cap, &pfd);
863 timeout_poll = (cfg->timeout > 0 ? cfg->timeout : 3) * 1000;
865 for (ttl = cfg->init_ttl; ttl <= cfg->max_ttl; ++ttl) {
866 int icmp = 0;
867 is_okay = 0;
869 if ((ttl == cfg->init_ttl && !show_pkt) ||
870 (ttl > cfg->init_ttl)) {
871 printf("%2d: ", ttl);
872 fflush(stdout);
874 retry:
875 for (query = 0; query < cfg->queries && !is_okay; ++query) {
876 id = assemble_packet_or_die(packet, len, ttl, icmp, cfg,
877 (struct sockaddr *) &sd,
878 (struct sockaddr *) &ss);
879 if (ttl == cfg->init_ttl && query == 0 && show_pkt) {
880 struct pkt_buff *pkt;
882 printf("Original packet:\n");
884 pkt = pkt_alloc(packet, len);
885 hex_ascii(pkt);
886 tprintf_flush();
887 pkt_free(pkt);
889 printf("\n%2d: ", ttl);
890 fflush(stdout);
893 err = sendto(fd, packet, len, 0, (struct sockaddr *) &sd,
894 sd_len);
895 if (err < 0)
896 panic("sendto failed: %s\n", strerror(errno));
898 err = poll(&pfd, 1, timeout_poll);
899 if (err > 0 && pfd.revents & POLLIN) {
900 real_len = recvfrom(fd_cap, packet_rcv, len_rcv,
901 0, NULL, NULL);
902 if (real_len < sizeof(struct ethhdr) +
903 (cfg->ip ? sizeof(struct iphdr) +
904 sizeof(struct icmphdr) :
905 sizeof(struct ip6_hdr) +
906 sizeof(struct icmp6hdr)))
907 continue;
909 is_okay = handle_packet(packet_rcv + sizeof(struct ethhdr),
910 real_len - sizeof(struct ethhdr),
911 cfg->ip, ttl, id,
912 (struct sockaddr *) &ss,
913 cfg->dns_resolv);
914 if (is_okay && show_pkt) {
915 struct pkt_buff *pkt;
917 printf("\n Received packet:\n");
919 pkt = pkt_alloc(packet_rcv, real_len);
920 hex_ascii(pkt);
921 tprintf_flush();
922 pkt_free(pkt);
924 } else {
925 printf("* ");
926 fflush(stdout);
927 is_okay = 0;
931 if (is_okay == 0 && icmp == 0) {
932 icmp = 1;
933 goto retry;
936 printf("\n");
937 fflush(stdout);
940 close(fd_cap);
941 close(fd);
943 xfree(packet);
944 xfree(packet_rcv);
946 return 0;
949 static void parse_whois_or_die(struct ash_cfg *cfg)
951 int fd;
952 ssize_t ret;
953 char tmp[512], *ptr, *ptr2;
955 fd = open_or_die(WHOIS_SERVER_SOURCE, O_RDONLY);
957 while ((ret = read(fd, tmp, sizeof(tmp))) > 0) {
958 tmp[sizeof(tmp) - 1] = 0;
959 ptr = skips(tmp);
960 ptr2 = ptr;
961 while (*ptr2 != ' ' && ptr2 < &tmp[sizeof(tmp) - 1])
962 ptr2++;
963 if (*ptr2 != ' ')
964 panic("Parser error!\n");
965 *ptr2 = 0;
966 cfg->whois = xstrdup(ptr);
967 ptr = ptr2 + 1;
968 if (ptr >= &tmp[sizeof(tmp) - 1])
969 panic("Parser error!\n");
970 ptr = skips(ptr);
971 ptr[strlen(ptr) - 1] = 0;
972 cfg->whois_port = xstrdup(ptr);
973 break;
976 close(fd);
979 int main(int argc, char **argv)
981 int c, opt_index, ret;
982 struct ash_cfg cfg;
983 char *path_city_db = NULL, *path_country_db = NULL;
985 check_for_root_maybe_die();
987 memset(&cfg, 0, sizeof(cfg));
988 cfg.init_ttl = 1;
989 cfg.max_ttl = 30;
990 cfg.queries = 3;
991 cfg.timeout = 3;
992 cfg.ip = 4;
993 cfg.payload = NULL;
994 cfg.dev = xstrdup("eth0");
995 cfg.port = xstrdup("80");
997 while ((c = getopt_long(argc, argv, short_options, long_options,
998 &opt_index)) != EOF) {
999 switch (c) {
1000 case 'h':
1001 help();
1002 break;
1003 case 'v':
1004 version();
1005 break;
1006 case 'H':
1007 cfg.host = xstrdup(optarg);
1008 break;
1009 case 'p':
1010 if (cfg.port)
1011 xfree(cfg.port);
1012 cfg.port = xstrdup(optarg);
1013 break;
1014 case 'n':
1015 cfg.dns_resolv = 0;
1016 break;
1017 case '4':
1018 cfg.ip = 4;
1019 break;
1020 case '6':
1021 cfg.ip = 6;
1022 break;
1023 case 'Z':
1024 show_pkt = 1;
1025 break;
1026 case 'N':
1027 cfg.dns_resolv = 1;
1028 break;
1029 case 'f':
1030 cfg.init_ttl = atoi(optarg);
1031 if (cfg.init_ttl <= 0)
1032 help();
1033 break;
1034 case 'm':
1035 cfg.max_ttl = atoi(optarg);
1036 if (cfg.max_ttl <= 0)
1037 help();
1038 break;
1039 case 'i':
1040 case 'd':
1041 if (cfg.dev)
1042 xfree(cfg.dev);
1043 cfg.dev = xstrdup(optarg);
1044 break;
1045 case 'q':
1046 cfg.queries = atoi(optarg);
1047 if (cfg.queries <= 0)
1048 help();
1049 break;
1050 case 'x':
1051 cfg.timeout = atoi(optarg);
1052 if (cfg.timeout <= 0)
1053 help();
1054 break;
1055 case 'S':
1056 cfg.syn = 1;
1057 break;
1058 case 'A':
1059 cfg.ack = 1;
1060 break;
1061 case 'F':
1062 cfg.fin = 1;
1063 break;
1064 case 'U':
1065 cfg.urg = 1;
1066 break;
1067 case 'P':
1068 cfg.psh = 1;
1069 break;
1070 case 'R':
1071 cfg.rst = 1;
1072 break;
1073 case 'E':
1074 cfg.syn = 1;
1075 cfg.ecn = 1;
1076 break;
1077 case 't':
1078 cfg.tos = atoi(optarg);
1079 if (cfg.tos < 0)
1080 help();
1081 break;
1082 case 'G':
1083 cfg.nofrag = 1;
1084 break;
1085 case 'X':
1086 cfg.payload = xstrdup(optarg);
1087 break;
1088 case 'l':
1089 cfg.totlen = atoi(optarg);
1090 if (cfg.totlen <= 0)
1091 help();
1092 break;
1093 case 'w':
1094 cfg.whois = xstrdup(optarg);
1095 break;
1096 case 'W':
1097 cfg.whois_port = xstrdup(optarg);
1098 break;
1099 case 'L':
1100 path_city_db = xstrdup(optarg);
1101 break;
1102 case 'K':
1103 path_country_db = xstrdup(optarg);
1104 break;
1105 case '?':
1106 switch (optopt) {
1107 case 'H':
1108 case 'p':
1109 case 'L':
1110 case 'K':
1111 case 'f':
1112 case 'm':
1113 case 'i':
1114 case 'd':
1115 case 'q':
1116 case 'x':
1117 case 'X':
1118 case 't':
1119 case 'l':
1120 case 'w':
1121 case 'W':
1122 panic("Option -%c requires an argument!\n",
1123 optopt);
1124 default:
1125 if (isprint(optopt))
1126 whine("Unknown option character "
1127 "`0x%X\'!\n", optopt);
1128 die();
1130 default:
1131 break;
1135 if (argc < 3 ||
1136 !cfg.host || !cfg.port ||
1137 cfg.init_ttl > cfg.max_ttl ||
1138 cfg.init_ttl > MAXTTL ||
1139 cfg.max_ttl > MAXTTL)
1140 help();
1142 if (!device_up_and_running(cfg.dev))
1143 panic("Networking device not up and running!\n");
1144 if (!cfg.whois || !cfg.whois_port)
1145 parse_whois_or_die(&cfg);
1146 if (device_mtu(cfg.dev) <= cfg.totlen)
1147 panic("Packet larger than device MTU!\n");
1149 register_signal(SIGHUP, signal_handler);
1151 header();
1153 tprintf_init();
1155 ret = aslookup_prepare(cfg.whois, cfg.whois_port);
1156 if (ret < 0)
1157 panic("Cannot resolve whois server!\n");
1159 if (path_country_db)
1160 gi_country = GeoIP_open(path_country_db, GEOIP_MMAP_CACHE);
1161 else
1162 gi_country = GeoIP_open_type(cfg.ip == 4 ?
1163 GEOIP_COUNTRY_EDITION :
1164 GEOIP_COUNTRY_EDITION_V6,
1165 GEOIP_MMAP_CACHE);
1167 if (path_city_db)
1168 gi_city = GeoIP_open(path_city_db, GEOIP_MMAP_CACHE);
1169 else
1170 gi_city = GeoIP_open_type(cfg.ip == 4 ?
1171 GEOIP_CITY_EDITION_REV1 :
1172 GEOIP_CITY_EDITION_REV1_V6,
1173 GEOIP_MMAP_CACHE);
1175 if (!gi_country || !gi_city)
1176 panic("Cannot open GeoIP database! Wrong path?!\n");
1178 GeoIP_set_charset(gi_country, GEOIP_CHARSET_UTF8);
1179 GeoIP_set_charset(gi_city, GEOIP_CHARSET_UTF8);
1181 ret = do_trace(&cfg);
1183 GeoIP_delete(gi_city);
1184 GeoIP_delete(gi_country);
1186 tprintf_cleanup();
1188 free(cfg.whois_port);
1189 free(cfg.whois);
1190 free(cfg.dev);
1191 free(cfg.host);
1192 free(cfg.port);
1193 free(cfg.payload);
1194 free(path_city_db);
1195 free(path_country_db);
1197 return ret;