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.
31 ashunt - Autonomous System (AS) trace route utility
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]
46 This program provides AS information on each hop between the client
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
85 Print help text and lists all options.
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
105 Use IPv4 requests (default)
113 Do not do reverse DNS lookup for hops
117 Do a reverse DNS lookup for hops
119 =item -f|--init-ttl <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)
137 Set TCP SYN flag in packets
141 Set TCP ACK flag in packets
145 Set TCP FIN flag in packets
149 Set TCP PSH flag in packets
153 Set TCP URG flag in packets
157 Set TCP RST flag in packets
161 Send ECN SYN packets (RFC3168)
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
189 Written by Daniel Borkmann <daniel@netsniff-ng.org>
193 Documentation by Emmanuel Roullit <emmanuel@netsniff-ng.org>
197 Please report bugs to <bugs@netsniff-ng.org>
210 #include <sys/types.h>
211 #include <sys/stat.h>
212 #include <sys/socket.h>
215 #include <asm/byteorder.h>
216 #include <linux/tcp.h>
217 #include <netinet/ip.h>
218 #include <netinet/ip6.h>
219 #include <netinet/in.h>
222 #include <arpa/inet.h>
223 #include <linux/if_ether.h>
224 #include <linux/icmp.h>
225 #include <linux/icmpv6.h>
227 #include <GeoIPCity.h>
232 #include "proto_hex.h"
236 #include "aslookup.h"
241 #define WHOIS_SERVER_SOURCE "/etc/netsniff-ng/whois.conf"
243 static int assemble_ipv6_tcp(uint8_t *packet
, size_t len
, int ttl
,
244 struct sockaddr_in
*sin
) __attribute__ ((unused
));
255 int syn
, ack
, ecn
, fin
, psh
, rst
, urg
;
264 volatile sig_atomic_t sigint
= 0;
266 static int show_pkt
= 0;
268 static GeoIP
*gi_country
= NULL
;
269 static GeoIP
*gi_city
= NULL
;
271 static const char *short_options
= "H:p:nNf:m:i:d:q:x:SAEFPURt:Gl:w:W:hv46X:ZLK";
273 static struct option long_options
[] = {
274 {"host", required_argument
, 0, 'H'},
275 {"port", required_argument
, 0, 'p'},
276 {"init-ttl", required_argument
, 0, 'f'},
277 {"max-ttl", required_argument
, 0, 'm'},
278 {"numeric", no_argument
, 0, 'n'},
279 {"dns", no_argument
, 0, 'N'},
280 {"ipv4", no_argument
, 0, '4'},
281 {"ipv6", no_argument
, 0, '6'},
282 {"dev", required_argument
, 0, 'd'},
283 {"num-probes", required_argument
, 0, 'q'},
284 {"timeout", required_argument
, 0, 'x'},
285 {"syn", no_argument
, 0, 'S'},
286 {"ack", no_argument
, 0, 'A'},
287 {"urg", no_argument
, 0, 'U'},
288 {"fin", no_argument
, 0, 'F'},
289 {"psh", no_argument
, 0, 'P'},
290 {"rst", no_argument
, 0, 'R'},
291 {"ecn-syn", no_argument
, 0, 'E'},
292 {"tos", required_argument
, 0, 't'},
293 {"payload", required_argument
, 0, 'X'},
294 {"show-packet", no_argument
, 0, 'Z'},
295 {"nofrag", no_argument
, 0, 'G'},
296 {"totlen", required_argument
, 0, 'l'},
297 {"whois", required_argument
, 0, 'w'},
298 {"wport", required_argument
, 0, 'W'},
299 {"city-db", required_argument
, 0, 'L'},
300 {"country-db", required_argument
, 0, 'K'},
301 {"version", no_argument
, 0, 'v'},
302 {"help", no_argument
, 0, 'h'},
306 static struct sock_filter ipv4_icmp_type_11
[] = {
308 { 0x28, 0, 0, 0x0000000c },
309 /* (001) jeq #0x800 jt 2 jf 10 */
310 { 0x15, 0, 8, 0x00000800 },
312 { 0x30, 0, 0, 0x00000017 },
313 /* (003) jeq #0x1 jt 4 jf 10 */
314 { 0x15, 0, 6, 0x00000001 },
316 { 0x28, 0, 0, 0x00000014 },
317 /* (005) jset #0x1fff jt 10 jf 6 */
318 { 0x45, 4, 0, 0x00001fff },
319 /* (006) ldxb 4*([14]&0xf) */
320 { 0xb1, 0, 0, 0x0000000e },
321 /* (007) ldb [x + 14] */
322 { 0x50, 0, 0, 0x0000000e },
323 /* (008) jeq #0xb jt 9 jf 10 */
324 { 0x15, 0, 1, 0x0000000b },
325 /* (009) ret #65535 */
326 { 0x06, 0, 0, 0xffffffff },
328 { 0x06, 0, 0, 0x00000000 },
331 static struct sock_filter ipv6_icmp6_type_3
[] = {
333 { 0x28, 0, 0, 0x0000000c },
334 /* (001) jeq #0x86dd jt 2 jf 7 */
335 { 0x15, 0, 5, 0x000086dd },
337 { 0x30, 0, 0, 0x00000014 },
338 /* (003) jeq #0x3a jt 4 jf 7 */
339 { 0x15, 0, 3, 0x0000003a },
341 { 0x30, 0, 0, 0x00000036 },
342 /* (005) jeq #0x3 jt 6 jf 7 */
343 { 0x15, 0, 1, 0x00000003 },
344 /* (006) ret #65535 */
345 { 0x06, 0, 0, 0xffffffff },
347 { 0x06, 0, 0, 0x00000000 },
350 static void signal_handler(int number
)
361 static void header(void)
363 printf("%s%s%s\n", colorize_start(bold
), "ashunt "
364 VERSION_STRING
, colorize_end());
367 static void help(void)
370 printf("\nashunt %s, Autonomous System (AS) trace route utility\n",
372 printf("http://www.netsniff-ng.org\n\n");
373 printf("Usage: ashunt [options]\n");
374 printf("Options:\n");
375 printf(" -H|--host <host> Host/IPv4/IPv6 to lookup AS route to\n");
376 printf(" -p|--port <port> Hosts port to lookup AS route to\n");
377 printf(" -i|-d|--dev <device> Networking device, i.e. eth0\n");
378 printf(" -4|--ipv4 Use IPv4 requests (default)\n");
379 printf(" -6|--ipv6 Use IPv6 requests\n");
380 printf(" -n|--numeric Do not do reverse DNS lookup for hops\n");
381 printf(" -N|--dns Do a reverse DNS lookup for hops\n");
382 printf(" -f|--init-ttl <ttl> Set initial TTL\n");
383 printf(" -m|--max-ttl <ttl> Set maximum TTL (default: 30)\n");
384 printf(" -q|--num-probes <num> Number of max probes for each hop (default: 3)\n");
385 printf(" -x|--timeout <sec> Probe response timeout in sec (default: 3)\n");
386 printf(" -S|--syn Set TCP SYN flag in packets\n");
387 printf(" -A|--ack Set TCP ACK flag in packets\n");
388 printf(" -F|--fin Set TCP FIN flag in packets\n");
389 printf(" -P|--psh Set TCP PSH flag in packets\n");
390 printf(" -U|--urg Set TCP URG flag in packets\n");
391 printf(" -R|--rst Set TCP RST flag in packets\n");
392 printf(" -E|--ecn-syn Send ECN SYN packets (RFC3168)\n");
393 printf(" -t|--tos <tos> Set the IP TOS field\n");
394 printf(" -G|--nofrag Set do not fragment bit\n");
395 printf(" -X|--payload <string> Specify a payload string to test DPIs\n");
396 printf(" -Z|--show-packet Show returned packet on each hop\n");
397 printf(" -l|--totlen <len> Specify total packet len\n");
398 printf(" -w|--whois <server> Use a different AS whois DB server\n");
399 printf(" (default: /etc/netsniff-ng/whois.conf)\n");
400 printf(" -W|--wport <port> Use a different port to AS whois server\n");
401 printf(" (default: /etc/netsniff-ng/whois.conf)\n");
402 printf(" --city-db <path> Specifiy path for geoip city database\n");
403 printf(" --country-db <path> Specifiy path for geoip country database\n");
404 printf(" -v|--version Print version\n");
405 printf(" -h|--help Print this help\n");
407 printf("Examples:\n");
408 printf(" IPv4 trace of AS with TCP ECN SYN probe:\n");
409 printf(" ashunt -i eth0 -N -E -H netsniff-ng.org\n");
410 printf(" IPv4 trace of AS with TCP SYN probe (this will most-likely pass):\n");
411 printf(" ashunt -i eth0 -N -S -H netsniff-ng.org\n");
412 printf(" IPv4 trace of AS with TCP FIN probe:\n");
413 printf(" ashunt -i eth0 -N -F -H netsniff-ng.org\n");
414 printf(" IPv4 trace of AS with Xmas probe:\n");
415 printf(" ashunt -i eth0 -N -FPU -H netsniff-ng.org\n");
416 printf(" IPv4 trace of AS with Null probe with ASCII payload:\n");
417 printf(" ashunt -i eth0 -N -H netsniff-ng.org -X \"censor-me\" -Z\n");
418 printf(" IPv6 trace of AS up to netsniff-ng.org:\n");
419 printf(" ashunt -6 -S -i eth0 -H netsniff-ng.org\n");
422 printf(" If the TCP probe did not give any results, then ashunt will\n");
423 printf(" automatically probe for classic ICMP packets! To gather more\n");
424 printf(" information about ashunt's fetched AS numbers, see i.e.\n");
425 printf(" http://bgp.he.net/AS<number>!\n");
427 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
428 printf("Copyright (C) 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
429 printf("Swiss federal institute of technology (ETH Zurich)\n");
430 printf("License: GNU GPL version 2\n");
431 printf("This is free software: you are free to change and redistribute it.\n");
432 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
437 static void version(void)
439 printf("\nashunt %s, AS trace route utility\n",
441 printf("http://www.netsniff-ng.org\n\n");
442 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
443 printf("Copyright (C) 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
444 printf("Swiss federal institute of technology (ETH Zurich)\n");
445 printf("License: GNU GPL version 2\n");
446 printf("This is free software: you are free to change and redistribute it.\n");
447 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
452 static inline unsigned short csum(unsigned short *buf
, int nwords
)
455 for (sum
= 0; nwords
> 0; nwords
--)
457 sum
= (sum
>> 16) + (sum
& 0xffff);
462 static void assemble_data(uint8_t *packet
, size_t len
, const char *payload
)
465 if (payload
== NULL
) {
466 for (i
= 0; i
< len
; ++i
)
467 packet
[i
] = (uint8_t) mt_rand_int32();
469 int lmin
= min(len
, strlen(payload
));
470 for (i
= 0; i
< lmin
; ++i
)
471 packet
[i
] = (uint8_t) payload
[i
];
472 for (i
= lmin
; i
< len
; ++i
)
473 packet
[i
] = (uint8_t) mt_rand_int32();
477 static void assemble_tcp(uint8_t *packet
, size_t len
, int syn
, int ack
,
478 int urg
, int fin
, int rst
, int psh
, int ecn
, int dport
)
480 struct tcphdr
*tcph
= (struct tcphdr
*) packet
;
481 assert(len
>= sizeof(struct tcphdr
));
482 tcph
->source
= htons((uint16_t) mt_rand_int32());
483 tcph
->dest
= htons((uint16_t) dport
);
484 tcph
->seq
= htonl(mt_rand_int32());
485 tcph
->ack_seq
= (!!ack
? htonl(mt_rand_int32()) : 0);
495 tcph
->window
= htons((uint16_t) (100 + (mt_rand_int32() % 65435)));
497 tcph
->urg_ptr
= (!!urg
? htons((uint16_t) mt_rand_int32()) : 0);
500 /* returns: ipv4 id */
501 static int assemble_ipv4_tcp(uint8_t *packet
, size_t len
, int ttl
,
502 int tos
, const struct sockaddr
*dst
,
503 const struct sockaddr
*src
, int syn
, int ack
,
504 int urg
, int fin
, int rst
, int psh
, int ecn
,
505 int nofrag
, int dport
, const char *payload
)
507 struct iphdr
*iph
= (struct iphdr
*) packet
;
509 assert(src
->sa_family
== PF_INET
&& dst
->sa_family
== PF_INET
);
510 assert(len
>= sizeof(struct iphdr
) + sizeof(struct tcphdr
));
513 iph
->tos
= (uint8_t) tos
;
514 iph
->tot_len
= htons((uint16_t) len
);
515 iph
->id
= htons((uint16_t) mt_rand_int32());
516 iph
->frag_off
= nofrag
? IP_DF
: 0;
517 iph
->ttl
= (uint8_t) ttl
;
518 iph
->protocol
= 6; /* TCP */
519 iph
->saddr
= ((const struct sockaddr_in
*) src
)->sin_addr
.s_addr
;
520 iph
->daddr
= ((const struct sockaddr_in
*) dst
)->sin_addr
.s_addr
;
521 assemble_tcp(packet
+ sizeof(struct iphdr
),
522 len
- sizeof(struct iphdr
), syn
, ack
, urg
, fin
, rst
,
524 assemble_data(packet
+ sizeof(struct iphdr
) + sizeof(struct tcphdr
),
525 len
- sizeof(struct iphdr
) - sizeof(struct tcphdr
),
527 iph
->check
= csum((unsigned short *) packet
,
528 ntohs(iph
->tot_len
) >> 1);
529 return ntohs(iph
->id
);
532 /* returns: ipv6 flow label */
533 static int assemble_ipv6_tcp(uint8_t *packet
, size_t len
, int ttl
,
534 struct sockaddr_in
*sin
)
539 static void assemble_icmp4(uint8_t *packet
, size_t len
)
541 struct icmphdr
*icmph
= (struct icmphdr
*) packet
;
542 assert(len
>= sizeof(struct icmphdr
));
543 icmph
->type
= ICMP_ECHO
;
548 /* returns: ipv4 id */
549 static int assemble_ipv4_icmp4(uint8_t *packet
, size_t len
, int ttl
,
550 int tos
, const struct sockaddr
*dst
,
551 const struct sockaddr
*src
, int nofrag
,
554 struct iphdr
*iph
= (struct iphdr
*) packet
;
556 assert(src
->sa_family
== PF_INET
&& dst
->sa_family
== PF_INET
);
557 assert(len
>= sizeof(struct iphdr
) + sizeof(struct tcphdr
));
561 iph
->tot_len
= htons((uint16_t) len
);
562 iph
->id
= htons((uint16_t) mt_rand_int32());
563 iph
->frag_off
= nofrag
? IP_DF
: 0;
564 iph
->ttl
= (uint8_t) ttl
;
565 iph
->protocol
= 1; /* ICMP4 */
566 iph
->saddr
= ((const struct sockaddr_in
*) src
)->sin_addr
.s_addr
;
567 iph
->daddr
= ((const struct sockaddr_in
*) dst
)->sin_addr
.s_addr
;
568 assemble_icmp4(packet
+ sizeof(struct iphdr
),
569 len
- sizeof(struct iphdr
));
570 assemble_data(packet
+ sizeof(struct iphdr
) + sizeof(struct icmphdr
),
571 len
- sizeof(struct iphdr
) - sizeof(struct icmphdr
),
573 iph
->check
= csum((unsigned short *) packet
,
574 ntohs(iph
->tot_len
) >> 1);
575 return ntohs(iph
->id
);
578 static int assemble_packet_or_die(uint8_t *packet
, size_t len
, int ttl
, int icmp
,
579 const struct ash_cfg
*cfg
,
580 const struct sockaddr
*dst
,
581 const struct sockaddr
*src
)
584 return assemble_ipv4_icmp4(packet
, len
, ttl
, cfg
->tos
, dst
, src
,
585 cfg
->nofrag
, cfg
->payload
);
587 return assemble_ipv4_tcp(packet
, len
, ttl
, cfg
->tos
, dst
, src
,
588 cfg
->syn
, cfg
->ack
, cfg
->urg
, cfg
->fin
,
589 cfg
->rst
, cfg
->psh
, cfg
->ecn
,
590 cfg
->nofrag
, atoi(cfg
->port
),
594 #define PKT_NOT_FOR_US 0
597 static inline const char *make_n_a(const char *p
)
602 static int handle_ipv4_icmp(uint8_t *packet
, size_t len
, int ttl
, int id
,
603 const struct sockaddr
*own
, int dns_resolv
)
606 struct iphdr
*iph
= (struct iphdr
*) packet
;
607 struct iphdr
*iph_inner
;
608 struct icmphdr
*icmph
;
610 struct sockaddr_in sa
;
613 if (iph
->protocol
!= 1)
614 return PKT_NOT_FOR_US
;
615 if (iph
->daddr
!= ((const struct sockaddr_in
*) own
)->sin_addr
.s_addr
)
616 return PKT_NOT_FOR_US
;
617 icmph
= (struct icmphdr
*) (packet
+ sizeof(struct iphdr
));
618 if (icmph
->type
!= ICMP_TIME_EXCEEDED
)
619 return PKT_NOT_FOR_US
;
620 if (icmph
->code
!= ICMP_EXC_TTL
)
621 return PKT_NOT_FOR_US
;
622 iph_inner
= (struct iphdr
*) (packet
+ sizeof(struct iphdr
) +
623 sizeof(struct icmphdr
));
624 if (ntohs(iph_inner
->id
) != id
)
625 return PKT_NOT_FOR_US
;
626 hbuff
= xzmalloc(NI_MAXHOST
);
627 memset(&sa
, 0, sizeof(sa
));
628 sa
.sin_family
= PF_INET
;
629 sa
.sin_addr
.s_addr
= iph
->saddr
;
630 getnameinfo((struct sockaddr
*) &sa
, sizeof(sa
), hbuff
, NI_MAXHOST
,
631 NULL
, 0, NI_NUMERICHOST
);
632 memset(&rec
, 0, sizeof(rec
));
633 ret
= aslookup(hbuff
, &rec
);
635 panic("AS lookup error %d!\n", ret
);
636 gir
= GeoIP_record_by_ipnum(gi_city
, ntohl(iph
->saddr
));
638 if (strlen(rec
.country
) > 0 && gir
) {
639 const char *city
= make_n_a(gir
->city
);
640 printf("%s in AS%s (%s, %s, %s, %f, %f), %s %s (%s), %s", hbuff
,
641 rec
.number
, rec
.country
,
642 GeoIP_country_name_by_ipnum(gi_country
, ntohl(iph
->saddr
)),
643 city
, gir
->latitude
, gir
->longitude
,
644 rec
.prefix
, rec
.registry
, rec
.since
, rec
.name
);
645 } else if (strlen(rec
.country
) > 0 && !gir
) {
646 printf("%s in AS%s (%s, %s), %s %s (%s), %s", hbuff
,
647 rec
.number
, rec
.country
,
648 GeoIP_country_name_by_ipnum(gi_country
, ntohl(iph
->saddr
)),
649 rec
.prefix
, rec
.registry
, rec
.since
, rec
.name
);
651 printf("%s in unkown AS", hbuff
);
654 struct hostent
*hent
= gethostbyaddr(&sa
.sin_addr
,
657 if (strlen(rec
.country
) > 0 && gir
) {
658 const char *city
= make_n_a(gir
->city
);
659 printf("%s (%s) in AS%s (%s, %s, %s, %f, %f), %s %s (%s), %s",
660 (hent
? hent
->h_name
: hbuff
), hbuff
,
661 rec
.number
, rec
.country
,
662 GeoIP_country_name_by_ipnum(gi_country
, ntohl(iph
->saddr
)),
663 city
, gir
->latitude
, gir
->longitude
,
664 rec
.prefix
, rec
.registry
,
665 rec
.since
, rec
.name
);
666 } else if (strlen(rec
.country
) > 0 && !gir
) {
667 printf("%s (%s) in AS%s (%s, %s), %s %s (%s), %s",
668 (hent
? hent
->h_name
: hbuff
), hbuff
,
669 rec
.number
, rec
.country
,
670 GeoIP_country_name_by_ipnum(gi_country
, ntohl(iph
->saddr
)),
671 rec
.prefix
, rec
.registry
,
672 rec
.since
, rec
.name
);
674 printf("%s (%s) in unkown AS",
675 (hent
? hent
->h_name
: hbuff
), hbuff
);
682 static int handle_packet(uint8_t *packet
, size_t len
, int ip
, int ttl
, int id
,
683 struct sockaddr
*own
, int dns_resolv
)
685 return handle_ipv4_icmp(packet
, len
, ttl
, id
, own
, dns_resolv
);
688 static int do_trace(const struct ash_cfg
*cfg
)
690 int ttl
, query
, fd
= -1, one
= 1, ret
, fd_cap
, ifindex
;
691 int is_okay
= 0, id
, timeout_poll
;
692 uint8_t *packet
, *packet_rcv
;
693 ssize_t err
, real_len
;
695 struct addrinfo hints
, *ahead
, *ai
;
696 char *hbuff1
, *hbuff2
;
697 struct sockaddr_storage ss
, sd
;
698 struct sock_fprog bpf_ops
;
699 struct ring dummy_ring
;
702 mt_init_by_random_device();
704 memset(&hints
, 0, sizeof(hints
));
705 hints
.ai_family
= PF_UNSPEC
;
706 hints
.ai_socktype
= SOCK_STREAM
;
707 hints
.ai_protocol
= IPPROTO_TCP
;
708 hints
.ai_flags
= AI_NUMERICSERV
;
710 ret
= getaddrinfo(cfg
->host
, cfg
->port
, &hints
, &ahead
);
712 whine("Cannot get address info!\n");
716 for (ai
= ahead
; ai
!= NULL
&& fd
< 0; ai
= ai
->ai_next
) {
717 if (!((ai
->ai_family
== PF_INET6
&& cfg
->ip
== 6) ||
718 (ai
->ai_family
== PF_INET
&& cfg
->ip
== 4)))
720 fd
= socket(ai
->ai_family
, SOCK_RAW
, ai
->ai_protocol
);
723 fd_cap
= pf_socket();
724 memset(&ss
, 0, sizeof(ss
));
725 ret
= device_address(cfg
->dev
, ai
->ai_family
, &ss
);
727 panic("Cannot get own device address!\n");
728 ret
= bind(fd
, (struct sockaddr
*) &ss
, sizeof(ss
));
730 panic("Cannot bind socket!\n");
731 memset(&sd
, 0, sizeof(sd
));
732 memcpy(&sd
, ai
->ai_addr
, ai
->ai_addrlen
);
738 whine("Cannot create socket! Does remote support IPv%d?!\n",
745 if (len
< sizeof(struct iphdr
) + sizeof(struct tcphdr
)) {
746 len
= sizeof(struct iphdr
) + sizeof(struct tcphdr
);
748 len
+= strlen(cfg
->payload
);
751 if (len
< sizeof(struct ip6_hdr
) + sizeof(struct tcphdr
)) {
752 len
= sizeof(struct ip6_hdr
) + sizeof(struct tcphdr
);
754 len
+= strlen(cfg
->payload
);
757 if (len
>= device_mtu(cfg
->dev
))
758 panic("Packet len exceeds device MTU!\n");
760 packet
= xmalloc(len
);
761 len_rcv
= device_mtu(cfg
->dev
);
762 packet_rcv
= xmalloc(len_rcv
);
764 hbuff1
= xzmalloc(256);
765 getnameinfo((struct sockaddr
*) &sd
, sizeof(sd
), hbuff1
, 256,
766 NULL
, 0, NI_NUMERICHOST
);
768 hbuff2
= xzmalloc(256);
769 getnameinfo((struct sockaddr
*) &ss
, sizeof(ss
), hbuff2
, 256,
770 NULL
, 0, NI_NUMERICHOST
);
772 ret
= setsockopt(fd
, cfg
->ip
== 4 ? IPPROTO_IP
: IPPROTO_IPV6
,
773 IP_HDRINCL
, &one
, sizeof(one
));
775 panic("Kernel does not support IP_HDRINCL!\n");
777 info("AS path IPv%d TCP trace from %s to %s:%s (%s) with len %u "
778 "Bytes, %u max hops\n", cfg
->ip
, hbuff2
, hbuff1
, cfg
->port
,
779 cfg
->host
, len
, cfg
->max_ttl
);
780 info("Using flags SYN:%d,ACK:%d,ECN:%d,FIN:%d,PSH:%d,RST:%d,URG:%d\n",
781 cfg
->syn
, cfg
->ack
, cfg
->ecn
, cfg
->fin
, cfg
->psh
, cfg
->rst
,
784 info("With payload: \'%s\'\n", cfg
->payload
);
790 hbuff1
= hbuff2
= NULL
;
792 enable_kernel_bpf_jit_compiler();
793 memset(&bpf_ops
, 0, sizeof(bpf_ops
));
795 bpf_ops
.filter
= ipv4_icmp_type_11
;
796 bpf_ops
.len
= (sizeof(ipv4_icmp_type_11
) /
797 sizeof(ipv4_icmp_type_11
[0]));
799 bpf_ops
.filter
= ipv6_icmp6_type_3
;
800 bpf_ops
.len
= (sizeof(ipv6_icmp6_type_3
) /
801 sizeof(ipv6_icmp6_type_3
[0]));
803 bpf_attach_to_sock(fd_cap
, &bpf_ops
);
804 ifindex
= device_ifindex(cfg
->dev
);
805 bind_rx_ring(fd_cap
, &dummy_ring
, ifindex
);
806 prepare_polling(fd_cap
, &pfd
);
807 timeout_poll
= (cfg
->timeout
> 0 ? cfg
->timeout
: 3) * 1000;
809 for (ttl
= cfg
->init_ttl
; ttl
<= cfg
->max_ttl
; ++ttl
) {
813 if ((ttl
== cfg
->init_ttl
&& !show_pkt
) ||
814 (ttl
> cfg
->init_ttl
)) {
819 for (query
= 0; query
< cfg
->queries
&& !is_okay
; ++query
) {
820 id
= assemble_packet_or_die(packet
, len
, ttl
, icmp
, cfg
,
821 (struct sockaddr
*) &sd
,
822 (struct sockaddr
*) &ss
);
823 if (ttl
== cfg
->init_ttl
&& query
== 0 && show_pkt
) {
824 info("Original packet:\n");
827 info("\n%2d: ", ttl
);
831 err
= sendto(fd
, packet
, len
, 0, (struct sockaddr
*) &sd
,
834 panic("sendto failed: %s\n", strerror(errno
));
836 err
= poll(&pfd
, 1, timeout_poll
);
837 if (err
> 0 && pfd
.revents
& POLLIN
) {
838 real_len
= recvfrom(fd_cap
, packet_rcv
, len_rcv
,
840 if (real_len
< sizeof(struct ethhdr
) +
841 (cfg
->ip
? sizeof(struct iphdr
) +
842 sizeof(struct icmphdr
) :
843 sizeof(struct ip6_hdr
) +
844 sizeof(struct icmp6hdr
)))
847 is_okay
= handle_packet(packet_rcv
+ sizeof(struct ethhdr
),
848 real_len
- sizeof(struct ethhdr
),
850 (struct sockaddr
*) &ss
,
852 if (is_okay
&& show_pkt
) {
853 info("\n Received packet:\n");
854 hex(packet_rcv
, real_len
);
864 if (is_okay
== 0 && icmp
== 0) {
880 static void parse_whois_or_die(struct ash_cfg
*cfg
)
884 char tmp
[512], *ptr
, *ptr2
;
886 fd
= open_or_die(WHOIS_SERVER_SOURCE
, O_RDONLY
);
887 while ((ret
= read(fd
, tmp
, sizeof(tmp
))) > 0) {
888 tmp
[sizeof(tmp
) - 1] = 0;
891 while (*ptr2
!= ' ' && ptr2
< &tmp
[sizeof(tmp
) - 1])
894 panic("Parser error!\n");
896 cfg
->whois
= xstrdup(ptr
);
898 if (ptr
>= &tmp
[sizeof(tmp
) - 1])
899 panic("Parser error!\n");
901 ptr
[strlen(ptr
) - 1] = 0;
902 cfg
->whois_port
= xstrdup(ptr
);
908 int main(int argc
, char **argv
)
910 int c
, opt_index
, ret
;
912 char *path_city_db
= NULL
, *path_country_db
= NULL
;
914 check_for_root_maybe_die();
916 memset(&cfg
, 0, sizeof(cfg
));
923 cfg
.dev
= xstrdup("eth0");
924 cfg
.port
= xstrdup("80");
926 while ((c
= getopt_long(argc
, argv
, short_options
, long_options
,
927 &opt_index
)) != EOF
) {
936 cfg
.host
= xstrdup(optarg
);
941 cfg
.port
= xstrdup(optarg
);
959 cfg
.init_ttl
= atoi(optarg
);
960 if (cfg
.init_ttl
<= 0)
964 cfg
.max_ttl
= atoi(optarg
);
965 if (cfg
.max_ttl
<= 0)
972 cfg
.dev
= xstrdup(optarg
);
975 cfg
.queries
= atoi(optarg
);
976 if (cfg
.queries
<= 0)
980 cfg
.timeout
= atoi(optarg
);
981 if (cfg
.timeout
<= 0)
1007 cfg
.tos
= atoi(optarg
);
1015 cfg
.payload
= xstrdup(optarg
);
1018 cfg
.totlen
= atoi(optarg
);
1019 if (cfg
.totlen
<= 0)
1023 cfg
.whois
= xstrdup(optarg
);
1026 cfg
.whois_port
= xstrdup(optarg
);
1029 path_city_db
= xstrdup(optarg
);
1032 path_country_db
= xstrdup(optarg
);
1051 panic("Option -%c requires an argument!\n",
1054 if (isprint(optopt
))
1055 whine("Unknown option character "
1056 "`0x%X\'!\n", optopt
);
1065 !cfg
.host
|| !cfg
.port
||
1066 cfg
.init_ttl
> cfg
.max_ttl
||
1067 cfg
.init_ttl
> MAXTTL
||
1068 cfg
.max_ttl
> MAXTTL
)
1070 if (!device_up_and_running(cfg
.dev
))
1071 panic("Networking device not up and running!\n");
1072 if (!cfg
.whois
|| !cfg
.whois_port
)
1073 parse_whois_or_die(&cfg
);
1074 if (device_mtu(cfg
.dev
) <= cfg
.totlen
)
1075 panic("Packet larger than device MTU!\n");
1076 register_signal(SIGHUP
, signal_handler
);
1079 ret
= aslookup_prepare(cfg
.whois
, cfg
.whois_port
);
1081 panic("Cannot resolve whois server!\n");
1082 if (path_country_db
)
1083 gi_country
= GeoIP_open(path_country_db
, GEOIP_MMAP_CACHE
);
1085 gi_country
= GeoIP_open_type(GEOIP_COUNTRY_EDITION
,
1088 gi_city
= GeoIP_open(path_city_db
, GEOIP_MMAP_CACHE
);
1090 gi_city
= GeoIP_open_type(GEOIP_CITY_EDITION_REV1
,
1092 if (!gi_country
|| !gi_city
)
1093 panic("Cannot open GeoIP database! Wrong path?!\n");
1094 GeoIP_set_charset(gi_country
, GEOIP_CHARSET_UTF8
);
1095 GeoIP_set_charset(gi_city
, GEOIP_CHARSET_UTF8
);
1096 ret
= do_trace(&cfg
);
1097 GeoIP_delete(gi_city
);
1098 GeoIP_delete(gi_country
);
1101 xfree(cfg
.whois_port
);
1113 xfree(path_city_db
);
1114 if (path_country_db
)
1115 xfree(path_country_db
);