built_in: add kernel u* types
[netsniff-ng-old.git] / src / ashunt.c
blobfa10d04c345b32e9388db5de3def8141f0964806
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, ashunt was written
12 * from scratch and does not use any libraries. Special thanks to Team CYMRU!
14 * The road must be trod, but it will be very hard. And neither strength nor
15 * wisdom will carry us far upon it. This quest may be attempted by the weak
16 * with as much hope as the strong. Yet such is oft the course of deeds that
17 * move the wheels of the world: small hands do them because they must,
18 * while the eyes of the great are elsewhere.
20 * -- The Lord of the Rings, Elrond, Chapter 'The Council of Elrond'.
22 * ashunt includes GeoLite data created by MaxMind, available from
23 * http://www.maxmind.com/. On Debian you need libgeoip-dev, libgeoip1 and
24 * geoip-database-contrib.
29 =head1 NAME
31 ashunt - Autonomous System (AS) trace route utility
33 =head1 SYNOPSIS
35 ashunt -H|--host <host> -i|-d|--dev <dev> [-6|--ipv6]
36 [-n|--numeric] [-N|--dns] [-f|--init-ttl <ttl>]
37 [-m|--max-ttl <ttl>] [-q|--num-probes] [-x|--timeout <sec>]
38 [-S|--syn] [-A|--ack] [-F|--fin] [-P|--psh] [-U|--urg]
39 [-R|--rst] [-E|--ecn-syn] [-t|--tos <tos>] [-G|--nofrag]
40 [-X|--payload <string>] [-Z|--show-packet] [-l|--totlen <len>]
41 [-w|--whois <server>] [-W|--wport <port>] [--city-db <path>]
42 [--country-db <path>] [-v|--version] [-h|--help]
44 =head1 DESCRIPTION
46 This program provides AS information on each hop between the client
47 and the target host.
49 =head1 OPTIONS
51 =over
53 =item ashunt -i eth0 -N -E -H netsniff-ng.org
55 IPv4 trace of AS with TCP ECN SYN probe
57 =item ashunt -i eth0 -N -S -H netsniff-ng.org
59 IPv4 trace of AS with TCP SYN probe
61 =item ashunt -i eth0 -N -F -H netsniff-ng.org
63 IPv4 trace of AS with TCP FIN probe
65 =item ashunt -i eth0 -N -FPU -H netsniff-ng.org
67 IPv4 trace of AS with Xmas probe
69 =item ashunt -i eth0 -N -H netsniff-ng.org -X "censor-me" -Z
71 IPv4 trace of AS with Null probe with ASCII payload
73 =item ashunt -6 -S -i eth0 -H netsniff-ng.org
75 IPv6 trace of AS up to netsniff-ng.org
77 =back
79 =head1 OPTIONS
81 =over
83 =item -h|--help
85 Print help text and lists all options.
87 =item -v|--version
89 Print version.
91 =item -H|--host <host>
93 Host/IPv4/IPv6 to lookup AS route to
95 =item i-|-d|--dev <netdev>
97 Networking device, i.e. eth0
99 =item -p|--port <port>
101 Hosts port to lookup AS route to
103 =item -4|--ipv4
105 Use IPv4 requests (default)
107 =item -6|--ipv6
109 Use IPv6 requests
111 =item -n|--numeric
113 Do not do reverse DNS lookup for hops
115 =item -N|--dns
117 Do a reverse DNS lookup for hops
119 =item -f|--init-ttl <ttl>
121 Set initial TTL
123 =item -m|--max-ttl <ttl>
125 Set maximum TTL (default: 30)
127 =item -q|--num-probes <num>
129 Number of max probes for each hop (default: 3)
131 =item -x|--timeout <sec>
133 Probe response timeout in sec (default: 3)
135 =item -S|--syn
137 Set TCP SYN flag in packets
139 =item -A|--ack
141 Set TCP ACK flag in packets
143 =item -F|--fin
145 Set TCP FIN flag in packets
147 =item -P|--psh
149 Set TCP PSH flag in packets
151 =item -U|--urg
153 Set TCP URG flag in packets
155 =item -R|--rst
157 Set TCP RST flag in packets
159 =item -E|--ecn-syn
161 Send ECN SYN packets (RFC3168)
163 =item -t|--tos <tos>
165 Set the IP TOS field
167 =item -w|--whois <server>
169 Use a different AS whois DB server
170 (default: /etc/netsniff-ng/whois.conf)
172 =item -W|--wport <port>
174 Use a different port to AS whois server
175 (default: /etc/netsniff-ng/whois.conf)
177 =item --city-db <path>
179 Specifiy path for geoip city database
181 =item --country-db <path>
183 Specifiy path for geoip country database
185 =back
187 =head1 AUTHOR
189 Written by Daniel Borkmann <daniel@netsniff-ng.org>
191 =head1 DOCUMENTATION
193 Documentation by Emmanuel Roullit <emmanuel@netsniff-ng.org>
195 =head1 BUGS
197 Please report bugs to <bugs@netsniff-ng.org>
199 =cut
203 #include <stdio.h>
204 #include <stdlib.h>
205 #include <signal.h>
206 #include <getopt.h>
207 #include <ctype.h>
208 #include <stdint.h>
209 #include <sys/types.h>
210 #include <sys/stat.h>
211 #include <sys/socket.h>
212 #include <fcntl.h>
213 #include <string.h>
214 #include <asm/byteorder.h>
215 #include <linux/tcp.h>
216 #include <netinet/ip.h>
217 #include <netinet/ip6.h>
218 #include <netinet/in.h>
219 #include <errno.h>
220 #include <netdb.h>
221 #include <arpa/inet.h>
222 #include <linux/if_ether.h>
223 #include <linux/icmp.h>
224 #include <linux/icmpv6.h>
225 #include <GeoIP.h>
226 #include <GeoIPCity.h>
228 #include "bpf.h"
229 #include "die.h"
230 #include "tprintf.h"
231 #include "pkt_buff.h"
232 #include "proto_struct.h"
233 #include "proto_none.h"
234 #include "xmalloc.h"
235 #include "xstring.h"
236 #include "xio.h"
237 #include "aslookup.h"
238 #include "xsys.h"
239 #include "mtrand.h"
240 #include "ring_rx.h"
241 #include "built_in.h"
243 #define WHOIS_SERVER_SOURCE "/etc/netsniff-ng/whois.conf"
245 static int assemble_ipv6_tcp(uint8_t *packet, size_t len, int ttl,
246 struct sockaddr_in *sin) __attribute__ ((unused));
248 struct ash_cfg {
249 char *host;
250 char *port;
251 int init_ttl;
252 int max_ttl;
253 int dns_resolv;
254 char *dev;
255 int queries;
256 int timeout;
257 int syn, ack, ecn, fin, psh, rst, urg;
258 int tos, nofrag;
259 int totlen;
260 char *whois;
261 char *whois_port;
262 int ip;
263 char *payload;
266 volatile sig_atomic_t sigint = 0;
268 static int show_pkt = 0;
270 static GeoIP *gi_country = NULL;
271 static GeoIP *gi_city = NULL;
273 static const char *short_options = "H:p:nNf:m:i:d:q:x:SAEFPURt:Gl:w:W:hv46X:ZLK";
275 static struct option long_options[] = {
276 {"host", required_argument, 0, 'H'},
277 {"port", required_argument, 0, 'p'},
278 {"init-ttl", required_argument, 0, 'f'},
279 {"max-ttl", required_argument, 0, 'm'},
280 {"numeric", no_argument, 0, 'n'},
281 {"dns", no_argument, 0, 'N'},
282 {"ipv4", no_argument, 0, '4'},
283 {"ipv6", no_argument, 0, '6'},
284 {"dev", required_argument, 0, 'd'},
285 {"num-probes", required_argument, 0, 'q'},
286 {"timeout", required_argument, 0, 'x'},
287 {"syn", no_argument, 0, 'S'},
288 {"ack", no_argument, 0, 'A'},
289 {"urg", no_argument, 0, 'U'},
290 {"fin", no_argument, 0, 'F'},
291 {"psh", no_argument, 0, 'P'},
292 {"rst", no_argument, 0, 'R'},
293 {"ecn-syn", no_argument, 0, 'E'},
294 {"tos", required_argument, 0, 't'},
295 {"payload", required_argument, 0, 'X'},
296 {"show-packet", no_argument, 0, 'Z'},
297 {"nofrag", no_argument, 0, 'G'},
298 {"totlen", required_argument, 0, 'l'},
299 {"whois", required_argument, 0, 'w'},
300 {"wport", required_argument, 0, 'W'},
301 {"city-db", required_argument, 0, 'L'},
302 {"country-db", required_argument, 0, 'K'},
303 {"version", no_argument, 0, 'v'},
304 {"help", no_argument, 0, 'h'},
305 {0, 0, 0, 0}
308 static struct sock_filter ipv4_icmp_type_11[] = {
309 /* (000) ldh [12] */
310 { 0x28, 0, 0, 0x0000000c },
311 /* (001) jeq #0x800 jt 2 jf 10 */
312 { 0x15, 0, 8, 0x00000800 },
313 /* (002) ldb [23] */
314 { 0x30, 0, 0, 0x00000017 },
315 /* (003) jeq #0x1 jt 4 jf 10 */
316 { 0x15, 0, 6, 0x00000001 },
317 /* (004) ldh [20] */
318 { 0x28, 0, 0, 0x00000014 },
319 /* (005) jset #0x1fff jt 10 jf 6 */
320 { 0x45, 4, 0, 0x00001fff },
321 /* (006) ldxb 4*([14]&0xf) */
322 { 0xb1, 0, 0, 0x0000000e },
323 /* (007) ldb [x + 14] */
324 { 0x50, 0, 0, 0x0000000e },
325 /* (008) jeq #0xb jt 9 jf 10 */
326 { 0x15, 0, 1, 0x0000000b },
327 /* (009) ret #65535 */
328 { 0x06, 0, 0, 0xffffffff },
329 /* (010) ret #0 */
330 { 0x06, 0, 0, 0x00000000 },
333 static struct sock_filter ipv6_icmp6_type_3[] = {
334 /* (000) ldh [12] */
335 { 0x28, 0, 0, 0x0000000c },
336 /* (001) jeq #0x86dd jt 2 jf 7 */
337 { 0x15, 0, 5, 0x000086dd },
338 /* (002) ldb [20] */
339 { 0x30, 0, 0, 0x00000014 },
340 /* (003) jeq #0x3a jt 4 jf 7 */
341 { 0x15, 0, 3, 0x0000003a },
342 /* (004) ldb [54] */
343 { 0x30, 0, 0, 0x00000036 },
344 /* (005) jeq #0x3 jt 6 jf 7 */
345 { 0x15, 0, 1, 0x00000003 },
346 /* (006) ret #65535 */
347 { 0x06, 0, 0, 0xffffffff },
348 /* (007) ret #0 */
349 { 0x06, 0, 0, 0x00000000 },
352 static void signal_handler(int number)
354 switch (number) {
355 case SIGINT:
356 sigint = 1;
357 break;
358 default:
359 break;
363 static void header(void)
365 printf("%s%s%s\n", colorize_start(bold), "ashunt "
366 VERSION_STRING, colorize_end());
369 static void help(void)
372 printf("\nashunt %s, Autonomous System (AS) trace route utility\n",
373 VERSION_STRING);
374 printf("http://www.netsniff-ng.org\n\n");
375 printf("Usage: ashunt [options]\n");
376 printf("Options:\n");
377 printf(" -H|--host <host> Host/IPv4/IPv6 to lookup AS route to\n");
378 printf(" -p|--port <port> Hosts port to lookup AS route to\n");
379 printf(" -i|-d|--dev <device> Networking device, i.e. eth0\n");
380 printf(" -4|--ipv4 Use IPv4 requests (default)\n");
381 printf(" -6|--ipv6 Use IPv6 requests\n");
382 printf(" -n|--numeric Do not do reverse DNS lookup for hops\n");
383 printf(" -N|--dns Do a reverse DNS lookup for hops\n");
384 printf(" -f|--init-ttl <ttl> Set initial TTL\n");
385 printf(" -m|--max-ttl <ttl> Set maximum TTL (default: 30)\n");
386 printf(" -q|--num-probes <num> Number of max probes for each hop (default: 3)\n");
387 printf(" -x|--timeout <sec> Probe response timeout in sec (default: 3)\n");
388 printf(" -S|--syn Set TCP SYN flag in packets\n");
389 printf(" -A|--ack Set TCP ACK flag in packets\n");
390 printf(" -F|--fin Set TCP FIN flag in packets\n");
391 printf(" -P|--psh Set TCP PSH flag in packets\n");
392 printf(" -U|--urg Set TCP URG flag in packets\n");
393 printf(" -R|--rst Set TCP RST flag in packets\n");
394 printf(" -E|--ecn-syn Send ECN SYN packets (RFC3168)\n");
395 printf(" -t|--tos <tos> Set the IP TOS field\n");
396 printf(" -G|--nofrag Set do not fragment bit\n");
397 printf(" -X|--payload <string> Specify a payload string to test DPIs\n");
398 printf(" -Z|--show-packet Show returned packet on each hop\n");
399 printf(" -l|--totlen <len> Specify total packet len\n");
400 printf(" -w|--whois <server> Use a different AS whois DB server\n");
401 printf(" (default: /etc/netsniff-ng/whois.conf)\n");
402 printf(" -W|--wport <port> Use a different port to AS whois server\n");
403 printf(" (default: /etc/netsniff-ng/whois.conf)\n");
404 printf(" --city-db <path> Specifiy path for geoip city database\n");
405 printf(" --country-db <path> Specifiy path for geoip country database\n");
406 printf(" -v|--version Print version\n");
407 printf(" -h|--help Print this help\n");
408 printf("\n");
409 printf("Examples:\n");
410 printf(" IPv4 trace of AS with TCP ECN SYN probe:\n");
411 printf(" ashunt -i eth0 -N -E -H netsniff-ng.org\n");
412 printf(" IPv4 trace of AS with TCP SYN probe (this will most-likely pass):\n");
413 printf(" ashunt -i eth0 -N -S -H netsniff-ng.org\n");
414 printf(" IPv4 trace of AS with TCP FIN probe:\n");
415 printf(" ashunt -i eth0 -N -F -H netsniff-ng.org\n");
416 printf(" IPv4 trace of AS with Xmas probe:\n");
417 printf(" ashunt -i eth0 -N -FPU -H netsniff-ng.org\n");
418 printf(" IPv4 trace of AS with Null probe with ASCII payload:\n");
419 printf(" ashunt -i eth0 -N -H netsniff-ng.org -X \"censor-me\" -Z\n");
420 printf(" IPv6 trace of AS up to netsniff-ng.org:\n");
421 printf(" ashunt -6 -S -i eth0 -H netsniff-ng.org\n");
422 printf("\n");
423 printf("Note:\n");
424 printf(" If the TCP probe did not give any results, then ashunt will\n");
425 printf(" automatically probe for classic ICMP packets! To gather more\n");
426 printf(" information about ashunt's fetched AS numbers, see i.e.\n");
427 printf(" http://bgp.he.net/AS<number>!\n");
428 printf("\n");
429 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
430 printf("Copyright (C) 2011-2012 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
431 printf("Swiss federal institute of technology (ETH Zurich)\n");
432 printf("License: GNU GPL version 2\n");
433 printf("This is free software: you are free to change and redistribute it.\n");
434 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
435 die();
438 static void version(void)
440 printf("\nashunt %s, AS trace route utility\n",
441 VERSION_STRING);
442 printf("http://www.netsniff-ng.org\n\n");
443 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
444 printf("Copyright (C) 2011-2012 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
445 printf("Swiss federal institute of technology (ETH Zurich)\n");
446 printf("License: GNU GPL version 2\n");
447 printf("This is free software: you are free to change and redistribute it.\n");
448 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
449 die();
452 static inline unsigned short csum(unsigned short *buf, int nwords)
454 unsigned long sum;
456 for (sum = 0; nwords > 0; nwords--)
457 sum += *buf++;
458 sum = (sum >> 16) + (sum & 0xffff);
459 sum += (sum >> 16);
461 return ~sum;
464 static void assemble_data(uint8_t *packet, size_t len, const char *payload)
466 int i;
468 if (payload == NULL) {
469 for (i = 0; i < len; ++i)
470 packet[i] = (uint8_t) mt_rand_int32();
471 } else {
472 int lmin = min(len, strlen(payload));
473 for (i = 0; i < lmin; ++i)
474 packet[i] = (uint8_t) payload[i];
475 for (i = lmin; i < len; ++i)
476 packet[i] = (uint8_t) mt_rand_int32();
480 static void assemble_tcp(uint8_t *packet, size_t len, int syn, int ack,
481 int urg, int fin, int rst, int psh, int ecn, int dport)
483 struct tcphdr *tcph = (struct tcphdr *) packet;
485 bug_on(len < sizeof(struct tcphdr));
487 tcph->source = htons((uint16_t) mt_rand_int32());
488 tcph->dest = htons((uint16_t) dport);
489 tcph->seq = htonl(mt_rand_int32());
490 tcph->ack_seq = (!!ack ? htonl(mt_rand_int32()) : 0);
491 tcph->doff = 5;
492 tcph->syn = !!syn;
493 tcph->ack = !!ack;
494 tcph->urg = !!urg;
495 tcph->fin = !!fin;
496 tcph->rst = !!rst;
497 tcph->psh = !!psh;
498 tcph->ece = !!ecn;
499 tcph->cwr = !!ecn;
500 tcph->window = htons((uint16_t) (100 + (mt_rand_int32() % 65435)));
501 tcph->check = 0;
502 tcph->urg_ptr = (!!urg ? htons((uint16_t) mt_rand_int32()) : 0);
505 /* returns: ipv4 id */
506 static int assemble_ipv4_tcp(uint8_t *packet, size_t len, int ttl,
507 int tos, const struct sockaddr *dst,
508 const struct sockaddr *src, int syn, int ack,
509 int urg, int fin, int rst, int psh, int ecn,
510 int nofrag, int dport, const char *payload)
512 struct iphdr *iph = (struct iphdr *) packet;
514 bug_on(!src || !dst);
515 bug_on(src->sa_family != PF_INET || dst->sa_family != PF_INET);
516 bug_on(len < sizeof(struct iphdr) + sizeof(struct tcphdr));
518 iph->ihl = 5;
519 iph->version = 4;
520 iph->tos = (uint8_t) tos;
521 iph->tot_len = htons((uint16_t) len);
522 iph->id = htons((uint16_t) mt_rand_int32());
523 iph->frag_off = nofrag ? IP_DF : 0;
524 iph->ttl = (uint8_t) ttl;
525 iph->protocol = 6; /* TCP */
526 iph->saddr = ((const struct sockaddr_in *) src)->sin_addr.s_addr;
527 iph->daddr = ((const struct sockaddr_in *) dst)->sin_addr.s_addr;
529 assemble_tcp(packet + sizeof(struct iphdr),
530 len - sizeof(struct iphdr), syn, ack, urg, fin, rst,
531 psh, ecn, dport);
533 assemble_data(packet + sizeof(struct iphdr) + sizeof(struct tcphdr),
534 len - sizeof(struct iphdr) - sizeof(struct tcphdr),
535 payload);
537 iph->check = csum((unsigned short *) packet,
538 ntohs(iph->tot_len) >> 1);
540 return ntohs(iph->id);
543 /* returns: ipv6 flow label */
544 static int assemble_ipv6_tcp(uint8_t *packet, size_t len, int ttl,
545 struct sockaddr_in *sin)
547 return 0;
550 static void assemble_icmp4(uint8_t *packet, size_t len)
552 struct icmphdr *icmph = (struct icmphdr *) packet;
554 bug_on(len < sizeof(struct icmphdr));
556 icmph->type = ICMP_ECHO;
557 icmph->code = 0;
558 icmph->checksum = 0;
561 /* returns: ipv4 id */
562 static int assemble_ipv4_icmp4(uint8_t *packet, size_t len, int ttl,
563 int tos, const struct sockaddr *dst,
564 const struct sockaddr *src, int nofrag,
565 const char *payload)
567 struct iphdr *iph = (struct iphdr *) packet;
569 bug_on(!src || !dst);
570 bug_on(src->sa_family != PF_INET || dst->sa_family != PF_INET);
571 bug_on(len < sizeof(struct iphdr) + sizeof(struct tcphdr));
573 iph->ihl = 5;
574 iph->version = 4;
575 iph->tos = 0;
576 iph->tot_len = htons((uint16_t) len);
577 iph->id = htons((uint16_t) mt_rand_int32());
578 iph->frag_off = nofrag ? IP_DF : 0;
579 iph->ttl = (uint8_t) ttl;
580 iph->protocol = 1; /* ICMP4 */
581 iph->saddr = ((const struct sockaddr_in *) src)->sin_addr.s_addr;
582 iph->daddr = ((const struct sockaddr_in *) dst)->sin_addr.s_addr;
584 assemble_icmp4(packet + sizeof(struct iphdr),
585 len - sizeof(struct iphdr));
587 assemble_data(packet + sizeof(struct iphdr) + sizeof(struct icmphdr),
588 len - sizeof(struct iphdr) - sizeof(struct icmphdr),
589 payload);
591 iph->check = csum((unsigned short *) packet,
592 ntohs(iph->tot_len) >> 1);
594 return ntohs(iph->id);
597 static int assemble_packet_or_die(uint8_t *packet, size_t len, int ttl, int icmp,
598 const struct ash_cfg *cfg,
599 const struct sockaddr *dst,
600 const struct sockaddr *src)
602 if (icmp)
603 return assemble_ipv4_icmp4(packet, len, ttl, cfg->tos, dst, src,
604 cfg->nofrag, cfg->payload);
605 else
606 return assemble_ipv4_tcp(packet, len, ttl, cfg->tos, dst, src,
607 cfg->syn, cfg->ack, cfg->urg, cfg->fin,
608 cfg->rst, cfg->psh, cfg->ecn,
609 cfg->nofrag, atoi(cfg->port),
610 cfg->payload);
613 #define PKT_NOT_FOR_US 0
614 #define PKT_GOOD 1
616 static inline const char *make_n_a(const char *p)
618 return p ? : "N/A";
621 static int handle_ipv4_icmp(uint8_t *packet, size_t len, int ttl, int id,
622 const struct sockaddr *own, int dns_resolv)
624 int ret;
625 struct iphdr *iph = (struct iphdr *) packet;
626 struct iphdr *iph_inner;
627 struct icmphdr *icmph;
628 char *hbuff;
629 struct sockaddr_in sa;
630 struct asrecord rec;
631 GeoIPRecord *gir;
633 if (iph->protocol != 1)
634 return PKT_NOT_FOR_US;
635 if (iph->daddr != ((const struct sockaddr_in *) own)->sin_addr.s_addr)
636 return PKT_NOT_FOR_US;
638 icmph = (struct icmphdr *) (packet + sizeof(struct iphdr));
639 if (icmph->type != ICMP_TIME_EXCEEDED)
640 return PKT_NOT_FOR_US;
641 if (icmph->code != ICMP_EXC_TTL)
642 return PKT_NOT_FOR_US;
644 iph_inner = (struct iphdr *) (packet + sizeof(struct iphdr) +
645 sizeof(struct icmphdr));
646 if (ntohs(iph_inner->id) != id)
647 return PKT_NOT_FOR_US;
649 hbuff = xzmalloc(NI_MAXHOST);
651 memset(&sa, 0, sizeof(sa));
652 sa.sin_family = PF_INET;
653 sa.sin_addr.s_addr = iph->saddr;
655 getnameinfo((struct sockaddr *) &sa, sizeof(sa), hbuff, NI_MAXHOST,
656 NULL, 0, NI_NUMERICHOST);
658 memset(&rec, 0, sizeof(rec));
659 ret = aslookup(hbuff, &rec);
660 if (ret < 0)
661 panic("AS lookup error %d!\n", ret);
663 gir = GeoIP_record_by_ipnum(gi_city, ntohl(iph->saddr));
664 if (!dns_resolv) {
665 if (strlen(rec.country) > 0 && gir) {
666 const char *city = make_n_a(gir->city);
668 printf("%s in AS%s (%s, %s, %s, %f, %f), %s %s (%s), %s", hbuff,
669 rec.number, rec.country,
670 GeoIP_country_name_by_ipnum(gi_country, ntohl(iph->saddr)),
671 city, gir->latitude, gir->longitude,
672 rec.prefix, rec.registry, rec.since, rec.name);
673 } else if (strlen(rec.country) > 0 && !gir) {
674 printf("%s in AS%s (%s, %s), %s %s (%s), %s", hbuff,
675 rec.number, rec.country,
676 GeoIP_country_name_by_ipnum(gi_country, ntohl(iph->saddr)),
677 rec.prefix, rec.registry, rec.since, rec.name);
678 } else {
679 printf("%s in unkown AS", hbuff);
681 } else {
682 struct hostent *hent = gethostbyaddr(&sa.sin_addr,
683 sizeof(sa.sin_addr),
684 PF_INET);
686 if (strlen(rec.country) > 0 && gir) {
687 const char *city = make_n_a(gir->city);
688 printf("%s (%s) in AS%s (%s, %s, %s, %f, %f), %s %s (%s), %s",
689 (hent ? hent->h_name : hbuff), hbuff,
690 rec.number, rec.country,
691 GeoIP_country_name_by_ipnum(gi_country, ntohl(iph->saddr)),
692 city, gir->latitude, gir->longitude,
693 rec.prefix, rec.registry,
694 rec.since, rec.name);
695 } else if (strlen(rec.country) > 0 && !gir) {
696 printf("%s (%s) in AS%s (%s, %s), %s %s (%s), %s",
697 (hent ? hent->h_name : hbuff), hbuff,
698 rec.number, rec.country,
699 GeoIP_country_name_by_ipnum(gi_country, ntohl(iph->saddr)),
700 rec.prefix, rec.registry,
701 rec.since, rec.name);
702 } else {
703 printf("%s (%s) in unkown AS",
704 (hent ? hent->h_name : hbuff), hbuff);
708 xfree(hbuff);
710 return PKT_GOOD;
713 static int handle_packet(uint8_t *packet, size_t len, int ip, int ttl, int id,
714 struct sockaddr *own, int dns_resolv)
716 return handle_ipv4_icmp(packet, len, ttl, id, own, dns_resolv);
719 static int do_trace(const struct ash_cfg *cfg)
721 int ttl, query, fd = -1, one = 1, ret, fd_cap, ifindex;
722 int is_okay = 0, id, timeout_poll;
723 uint8_t *packet, *packet_rcv;
724 ssize_t err, real_len;
725 size_t len, len_rcv;
726 struct addrinfo hints, *ahead, *ai;
727 char *hbuff1, *hbuff2;
728 struct sockaddr_storage ss, sd;
729 struct sock_fprog bpf_ops;
730 struct ring dummy_ring;
731 struct pollfd pfd;
733 mt_init_by_random_device();
735 memset(&hints, 0, sizeof(hints));
736 hints.ai_family = PF_UNSPEC;
737 hints.ai_socktype = SOCK_STREAM;
738 hints.ai_protocol = IPPROTO_TCP;
739 hints.ai_flags = AI_NUMERICSERV;
741 ret = getaddrinfo(cfg->host, cfg->port, &hints, &ahead);
742 if (ret < 0) {
743 whine("Cannot get address info!\n");
744 return -EIO;
747 for (ai = ahead; ai != NULL && fd < 0; ai = ai->ai_next) {
748 if (!((ai->ai_family == PF_INET6 && cfg->ip == 6) ||
749 (ai->ai_family == PF_INET && cfg->ip == 4)))
750 continue;
751 fd = socket(ai->ai_family, SOCK_RAW, ai->ai_protocol);
752 if (fd < 0)
753 continue;
755 fd_cap = pf_socket();
757 memset(&ss, 0, sizeof(ss));
758 ret = device_address(cfg->dev, ai->ai_family, &ss);
759 if (ret < 0)
760 panic("Cannot get own device address!\n");
762 ret = bind(fd, (struct sockaddr *) &ss, sizeof(ss));
763 if (ret < 0)
764 panic("Cannot bind socket!\n");
766 memset(&sd, 0, sizeof(sd));
767 memcpy(&sd, ai->ai_addr, ai->ai_addrlen);
769 break;
772 freeaddrinfo(ahead);
774 if (fd < 0) {
775 whine("Cannot create socket! Does remote support IPv%d?!\n",
776 cfg->ip);
777 return -EIO;
780 len = cfg->totlen;
781 if (cfg->ip == 4) {
782 if (len < sizeof(struct iphdr) + sizeof(struct tcphdr)) {
783 len = sizeof(struct iphdr) + sizeof(struct tcphdr);
784 if (cfg->payload)
785 len += strlen(cfg->payload);
787 } else {
788 if (len < sizeof(struct ip6_hdr) + sizeof(struct tcphdr)) {
789 len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
790 if (cfg->payload)
791 len += strlen(cfg->payload);
795 if (len >= device_mtu(cfg->dev))
796 panic("Packet len exceeds device MTU!\n");
798 packet = xmalloc(len);
799 len_rcv = device_mtu(cfg->dev);
800 packet_rcv = xmalloc(len_rcv);
802 hbuff1 = xzmalloc(256);
803 getnameinfo((struct sockaddr *) &sd, sizeof(sd), hbuff1, 256,
804 NULL, 0, NI_NUMERICHOST);
806 hbuff2 = xzmalloc(256);
807 getnameinfo((struct sockaddr *) &ss, sizeof(ss), hbuff2, 256,
808 NULL, 0, NI_NUMERICHOST);
810 ret = setsockopt(fd, cfg->ip == 4 ? IPPROTO_IP : IPPROTO_IPV6,
811 IP_HDRINCL, &one, sizeof(one));
812 if (ret < 0)
813 panic("Kernel does not support IP_HDRINCL!\n");
815 printf("AS path IPv%d TCP trace from %s to %s:%s (%s) with len %zu "
816 "Bytes, %u max hops\n", cfg->ip, hbuff2, hbuff1, cfg->port,
817 cfg->host, len, cfg->max_ttl);
819 printf("Using flags SYN:%d,ACK:%d,ECN:%d,FIN:%d,PSH:%d,RST:%d,URG:%d\n",
820 cfg->syn, cfg->ack, cfg->ecn, cfg->fin, cfg->psh, cfg->rst,
821 cfg->urg);
823 if (cfg->payload)
824 printf("With payload: \'%s\'\n", cfg->payload);
826 fflush(stdout);
828 xfree(hbuff1);
829 xfree(hbuff2);
831 hbuff1 = hbuff2 = NULL;
833 enable_kernel_bpf_jit_compiler();
835 memset(&bpf_ops, 0, sizeof(bpf_ops));
836 if (cfg->ip == 4) {
837 bpf_ops.filter = ipv4_icmp_type_11;
838 bpf_ops.len = (sizeof(ipv4_icmp_type_11) /
839 sizeof(ipv4_icmp_type_11[0]));
840 } else {
841 bpf_ops.filter = ipv6_icmp6_type_3;
842 bpf_ops.len = (sizeof(ipv6_icmp6_type_3) /
843 sizeof(ipv6_icmp6_type_3[0]));
846 bpf_attach_to_sock(fd_cap, &bpf_ops);
847 ifindex = device_ifindex(cfg->dev);
848 bind_rx_ring(fd_cap, &dummy_ring, ifindex);
849 prepare_polling(fd_cap, &pfd);
851 timeout_poll = (cfg->timeout > 0 ? cfg->timeout : 3) * 1000;
853 for (ttl = cfg->init_ttl; ttl <= cfg->max_ttl; ++ttl) {
854 int icmp = 0;
855 is_okay = 0;
857 if ((ttl == cfg->init_ttl && !show_pkt) ||
858 (ttl > cfg->init_ttl)) {
859 printf("%2d: ", ttl);
860 fflush(stdout);
862 retry:
863 for (query = 0; query < cfg->queries && !is_okay; ++query) {
864 id = assemble_packet_or_die(packet, len, ttl, icmp, cfg,
865 (struct sockaddr *) &sd,
866 (struct sockaddr *) &ss);
867 if (ttl == cfg->init_ttl && query == 0 && show_pkt) {
868 struct pkt_buff *pkt;
870 printf("Original packet:\n");
872 pkt = pkt_alloc(packet, len);
873 hex_ascii(pkt);
874 tprintf_flush();
875 pkt_free(pkt);
877 printf("\n%2d: ", ttl);
878 fflush(stdout);
881 err = sendto(fd, packet, len, 0, (struct sockaddr *) &sd,
882 sizeof(sd));
883 if (err < 0)
884 panic("sendto failed: %s\n", strerror(errno));
886 err = poll(&pfd, 1, timeout_poll);
887 if (err > 0 && pfd.revents & POLLIN) {
888 real_len = recvfrom(fd_cap, packet_rcv, len_rcv,
889 0, NULL, NULL);
890 if (real_len < sizeof(struct ethhdr) +
891 (cfg->ip ? sizeof(struct iphdr) +
892 sizeof(struct icmphdr) :
893 sizeof(struct ip6_hdr) +
894 sizeof(struct icmp6hdr)))
895 continue;
897 is_okay = handle_packet(packet_rcv + sizeof(struct ethhdr),
898 real_len - sizeof(struct ethhdr),
899 cfg->ip, ttl, id,
900 (struct sockaddr *) &ss,
901 cfg->dns_resolv);
902 if (is_okay && show_pkt) {
903 struct pkt_buff *pkt;
905 printf("\n Received packet:\n");
907 pkt = pkt_alloc(packet_rcv, real_len);
908 hex_ascii(pkt);
909 tprintf_flush();
910 pkt_free(pkt);
912 } else {
913 printf("* ");
914 fflush(stdout);
915 is_okay = 0;
919 if (is_okay == 0 && icmp == 0) {
920 icmp = 1;
921 goto retry;
924 printf("\n");
925 fflush(stdout);
928 close(fd_cap);
929 close(fd);
931 xfree(packet);
932 xfree(packet_rcv);
934 return 0;
937 static void parse_whois_or_die(struct ash_cfg *cfg)
939 int fd;
940 ssize_t ret;
941 char tmp[512], *ptr, *ptr2;
943 fd = open_or_die(WHOIS_SERVER_SOURCE, O_RDONLY);
945 while ((ret = read(fd, tmp, sizeof(tmp))) > 0) {
946 tmp[sizeof(tmp) - 1] = 0;
947 ptr = skips(tmp);
948 ptr2 = ptr;
949 while (*ptr2 != ' ' && ptr2 < &tmp[sizeof(tmp) - 1])
950 ptr2++;
951 if (*ptr2 != ' ')
952 panic("Parser error!\n");
953 *ptr2 = 0;
954 cfg->whois = xstrdup(ptr);
955 ptr = ptr2 + 1;
956 if (ptr >= &tmp[sizeof(tmp) - 1])
957 panic("Parser error!\n");
958 ptr = skips(ptr);
959 ptr[strlen(ptr) - 1] = 0;
960 cfg->whois_port = xstrdup(ptr);
961 break;
964 close(fd);
967 int main(int argc, char **argv)
969 int c, opt_index, ret;
970 struct ash_cfg cfg;
971 char *path_city_db = NULL, *path_country_db = NULL;
973 check_for_root_maybe_die();
975 memset(&cfg, 0, sizeof(cfg));
976 cfg.init_ttl = 1;
977 cfg.max_ttl = 30;
978 cfg.queries = 3;
979 cfg.timeout = 3;
980 cfg.ip = 4;
981 cfg.payload = NULL;
982 cfg.dev = xstrdup("eth0");
983 cfg.port = xstrdup("80");
985 while ((c = getopt_long(argc, argv, short_options, long_options,
986 &opt_index)) != EOF) {
987 switch (c) {
988 case 'h':
989 help();
990 break;
991 case 'v':
992 version();
993 break;
994 case 'H':
995 cfg.host = xstrdup(optarg);
996 break;
997 case 'p':
998 if (cfg.port)
999 xfree(cfg.port);
1000 cfg.port = xstrdup(optarg);
1001 break;
1002 case 'n':
1003 cfg.dns_resolv = 0;
1004 break;
1005 case '4':
1006 cfg.ip = 4;
1007 break;
1008 case '6':
1009 cfg.ip = 6;
1010 break;
1011 case 'Z':
1012 show_pkt = 1;
1013 break;
1014 case 'N':
1015 cfg.dns_resolv = 1;
1016 break;
1017 case 'f':
1018 cfg.init_ttl = atoi(optarg);
1019 if (cfg.init_ttl <= 0)
1020 help();
1021 break;
1022 case 'm':
1023 cfg.max_ttl = atoi(optarg);
1024 if (cfg.max_ttl <= 0)
1025 help();
1026 break;
1027 case 'i':
1028 case 'd':
1029 if (cfg.dev)
1030 xfree(cfg.dev);
1031 cfg.dev = xstrdup(optarg);
1032 break;
1033 case 'q':
1034 cfg.queries = atoi(optarg);
1035 if (cfg.queries <= 0)
1036 help();
1037 break;
1038 case 'x':
1039 cfg.timeout = atoi(optarg);
1040 if (cfg.timeout <= 0)
1041 help();
1042 break;
1043 case 'S':
1044 cfg.syn = 1;
1045 break;
1046 case 'A':
1047 cfg.ack = 1;
1048 break;
1049 case 'F':
1050 cfg.fin = 1;
1051 break;
1052 case 'U':
1053 cfg.urg = 1;
1054 break;
1055 case 'P':
1056 cfg.psh = 1;
1057 break;
1058 case 'R':
1059 cfg.rst = 1;
1060 break;
1061 case 'E':
1062 cfg.syn = 1;
1063 cfg.ecn = 1;
1064 break;
1065 case 't':
1066 cfg.tos = atoi(optarg);
1067 if (cfg.tos < 0)
1068 help();
1069 break;
1070 case 'G':
1071 cfg.nofrag = 1;
1072 break;
1073 case 'X':
1074 cfg.payload = xstrdup(optarg);
1075 break;
1076 case 'l':
1077 cfg.totlen = atoi(optarg);
1078 if (cfg.totlen <= 0)
1079 help();
1080 break;
1081 case 'w':
1082 cfg.whois = xstrdup(optarg);
1083 break;
1084 case 'W':
1085 cfg.whois_port = xstrdup(optarg);
1086 break;
1087 case 'L':
1088 path_city_db = xstrdup(optarg);
1089 break;
1090 case 'K':
1091 path_country_db = xstrdup(optarg);
1092 break;
1093 case '?':
1094 switch (optopt) {
1095 case 'H':
1096 case 'p':
1097 case 'L':
1098 case 'K':
1099 case 'f':
1100 case 'm':
1101 case 'i':
1102 case 'd':
1103 case 'q':
1104 case 'x':
1105 case 'X':
1106 case 't':
1107 case 'l':
1108 case 'w':
1109 case 'W':
1110 panic("Option -%c requires an argument!\n",
1111 optopt);
1112 default:
1113 if (isprint(optopt))
1114 whine("Unknown option character "
1115 "`0x%X\'!\n", optopt);
1116 die();
1118 default:
1119 break;
1123 if (argc < 3 ||
1124 !cfg.host || !cfg.port ||
1125 cfg.init_ttl > cfg.max_ttl ||
1126 cfg.init_ttl > MAXTTL ||
1127 cfg.max_ttl > MAXTTL)
1128 help();
1130 if (!device_up_and_running(cfg.dev))
1131 panic("Networking device not up and running!\n");
1132 if (!cfg.whois || !cfg.whois_port)
1133 parse_whois_or_die(&cfg);
1134 if (device_mtu(cfg.dev) <= cfg.totlen)
1135 panic("Packet larger than device MTU!\n");
1137 register_signal(SIGHUP, signal_handler);
1139 header();
1141 tprintf_init();
1143 ret = aslookup_prepare(cfg.whois, cfg.whois_port);
1144 if (ret < 0)
1145 panic("Cannot resolve whois server!\n");
1147 if (path_country_db)
1148 gi_country = GeoIP_open(path_country_db, GEOIP_MMAP_CACHE);
1149 else
1150 gi_country = GeoIP_open_type(GEOIP_COUNTRY_EDITION,
1151 GEOIP_MMAP_CACHE);
1153 if (path_city_db)
1154 gi_city = GeoIP_open(path_city_db, GEOIP_MMAP_CACHE);
1155 else
1156 gi_city = GeoIP_open_type(GEOIP_CITY_EDITION_REV1,
1157 GEOIP_MMAP_CACHE);
1159 if (!gi_country || !gi_city)
1160 panic("Cannot open GeoIP database! Wrong path?!\n");
1162 GeoIP_set_charset(gi_country, GEOIP_CHARSET_UTF8);
1163 GeoIP_set_charset(gi_city, GEOIP_CHARSET_UTF8);
1165 ret = do_trace(&cfg);
1167 GeoIP_delete(gi_city);
1168 GeoIP_delete(gi_country);
1170 tprintf_cleanup();
1172 if (cfg.whois_port)
1173 xfree(cfg.whois_port);
1174 if (cfg.whois)
1175 xfree(cfg.whois);
1176 if (cfg.dev)
1177 xfree(cfg.dev);
1178 if (cfg.host)
1179 xfree(cfg.host);
1180 if (cfg.port)
1181 xfree(cfg.port);
1182 if (cfg.payload)
1183 xfree(cfg.payload);
1184 if (path_city_db)
1185 xfree(path_city_db);
1186 if (path_country_db)
1187 xfree(path_country_db);
1189 return ret;