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>
209 #include <sys/types.h>
210 #include <sys/stat.h>
211 #include <sys/socket.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>
221 #include <arpa/inet.h>
222 #include <linux/if_ether.h>
223 #include <linux/icmp.h>
224 #include <linux/icmpv6.h>
226 #include <GeoIPCity.h>
231 #include "pkt_buff.h"
236 #include "aslookup.h"
240 #include "built_in.h"
242 #define WHOIS_SERVER_SOURCE "/etc/netsniff-ng/whois.conf"
244 static int assemble_ipv6_tcp(uint8_t *packet
, size_t len
, int ttl
,
245 struct sockaddr_in
*sin
) __attribute__ ((unused
));
256 int syn
, ack
, ecn
, fin
, psh
, rst
, urg
;
265 volatile sig_atomic_t sigint
= 0;
267 static int show_pkt
= 0;
269 static GeoIP
*gi_country
= NULL
;
270 static GeoIP
*gi_city
= NULL
;
272 static const char *short_options
= "H:p:nNf:m:i:d:q:x:SAEFPURt:Gl:w:W:hv46X:ZLK";
274 static struct option long_options
[] = {
275 {"host", required_argument
, 0, 'H'},
276 {"port", required_argument
, 0, 'p'},
277 {"init-ttl", required_argument
, 0, 'f'},
278 {"max-ttl", required_argument
, 0, 'm'},
279 {"numeric", no_argument
, 0, 'n'},
280 {"dns", no_argument
, 0, 'N'},
281 {"ipv4", no_argument
, 0, '4'},
282 {"ipv6", no_argument
, 0, '6'},
283 {"dev", required_argument
, 0, 'd'},
284 {"num-probes", required_argument
, 0, 'q'},
285 {"timeout", required_argument
, 0, 'x'},
286 {"syn", no_argument
, 0, 'S'},
287 {"ack", no_argument
, 0, 'A'},
288 {"urg", no_argument
, 0, 'U'},
289 {"fin", no_argument
, 0, 'F'},
290 {"psh", no_argument
, 0, 'P'},
291 {"rst", no_argument
, 0, 'R'},
292 {"ecn-syn", no_argument
, 0, 'E'},
293 {"tos", required_argument
, 0, 't'},
294 {"payload", required_argument
, 0, 'X'},
295 {"show-packet", no_argument
, 0, 'Z'},
296 {"nofrag", no_argument
, 0, 'G'},
297 {"totlen", required_argument
, 0, 'l'},
298 {"whois", required_argument
, 0, 'w'},
299 {"wport", required_argument
, 0, 'W'},
300 {"city-db", required_argument
, 0, 'L'},
301 {"country-db", required_argument
, 0, 'K'},
302 {"version", no_argument
, 0, 'v'},
303 {"help", no_argument
, 0, 'h'},
307 static struct sock_filter ipv4_icmp_type_11
[] = {
309 { 0x28, 0, 0, 0x0000000c },
310 /* (001) jeq #0x800 jt 2 jf 10 */
311 { 0x15, 0, 8, 0x00000800 },
313 { 0x30, 0, 0, 0x00000017 },
314 /* (003) jeq #0x1 jt 4 jf 10 */
315 { 0x15, 0, 6, 0x00000001 },
317 { 0x28, 0, 0, 0x00000014 },
318 /* (005) jset #0x1fff jt 10 jf 6 */
319 { 0x45, 4, 0, 0x00001fff },
320 /* (006) ldxb 4*([14]&0xf) */
321 { 0xb1, 0, 0, 0x0000000e },
322 /* (007) ldb [x + 14] */
323 { 0x50, 0, 0, 0x0000000e },
324 /* (008) jeq #0xb jt 9 jf 10 */
325 { 0x15, 0, 1, 0x0000000b },
326 /* (009) ret #65535 */
327 { 0x06, 0, 0, 0xffffffff },
329 { 0x06, 0, 0, 0x00000000 },
332 static struct sock_filter ipv6_icmp6_type_3
[] = {
334 { 0x28, 0, 0, 0x0000000c },
335 /* (001) jeq #0x86dd jt 2 jf 7 */
336 { 0x15, 0, 5, 0x000086dd },
338 { 0x30, 0, 0, 0x00000014 },
339 /* (003) jeq #0x3a jt 4 jf 7 */
340 { 0x15, 0, 3, 0x0000003a },
342 { 0x30, 0, 0, 0x00000036 },
343 /* (005) jeq #0x3 jt 6 jf 7 */
344 { 0x15, 0, 1, 0x00000003 },
345 /* (006) ret #65535 */
346 { 0x06, 0, 0, 0xffffffff },
348 { 0x06, 0, 0, 0x00000000 },
351 static void signal_handler(int number
)
362 static void header(void)
364 printf("%s%s%s\n", colorize_start(bold
), "ashunt "
365 VERSION_STRING
, colorize_end());
368 static void help(void)
371 printf("\nashunt %s, Autonomous System (AS) trace route utility\n",
373 printf("http://www.netsniff-ng.org\n\n");
374 printf("Usage: ashunt [options]\n");
375 printf("Options:\n");
376 printf(" -H|--host <host> Host/IPv4/IPv6 to lookup AS route to\n");
377 printf(" -p|--port <port> Hosts port to lookup AS route to\n");
378 printf(" -i|-d|--dev <device> Networking device, i.e. eth0\n");
379 printf(" -4|--ipv4 Use IPv4 requests (default)\n");
380 printf(" -6|--ipv6 Use IPv6 requests\n");
381 printf(" -n|--numeric Do not do reverse DNS lookup for hops\n");
382 printf(" -N|--dns Do a reverse DNS lookup for hops\n");
383 printf(" -f|--init-ttl <ttl> Set initial TTL\n");
384 printf(" -m|--max-ttl <ttl> Set maximum TTL (default: 30)\n");
385 printf(" -q|--num-probes <num> Number of max probes for each hop (default: 3)\n");
386 printf(" -x|--timeout <sec> Probe response timeout in sec (default: 3)\n");
387 printf(" -S|--syn Set TCP SYN flag in packets\n");
388 printf(" -A|--ack Set TCP ACK flag in packets\n");
389 printf(" -F|--fin Set TCP FIN flag in packets\n");
390 printf(" -P|--psh Set TCP PSH flag in packets\n");
391 printf(" -U|--urg Set TCP URG flag in packets\n");
392 printf(" -R|--rst Set TCP RST flag in packets\n");
393 printf(" -E|--ecn-syn Send ECN SYN packets (RFC3168)\n");
394 printf(" -t|--tos <tos> Set the IP TOS field\n");
395 printf(" -G|--nofrag Set do not fragment bit\n");
396 printf(" -X|--payload <string> Specify a payload string to test DPIs\n");
397 printf(" -Z|--show-packet Show returned packet on each hop\n");
398 printf(" -l|--totlen <len> Specify total packet len\n");
399 printf(" -w|--whois <server> Use a different AS whois DB server\n");
400 printf(" (default: /etc/netsniff-ng/whois.conf)\n");
401 printf(" -W|--wport <port> Use a different port to AS whois server\n");
402 printf(" (default: /etc/netsniff-ng/whois.conf)\n");
403 printf(" --city-db <path> Specifiy path for geoip city database\n");
404 printf(" --country-db <path> Specifiy path for geoip country database\n");
405 printf(" -v|--version Print version\n");
406 printf(" -h|--help Print this help\n");
408 printf("Examples:\n");
409 printf(" IPv4 trace of AS with TCP ECN SYN probe:\n");
410 printf(" ashunt -i eth0 -N -E -H netsniff-ng.org\n");
411 printf(" IPv4 trace of AS with TCP SYN probe (this will most-likely pass):\n");
412 printf(" ashunt -i eth0 -N -S -H netsniff-ng.org\n");
413 printf(" IPv4 trace of AS with TCP FIN probe:\n");
414 printf(" ashunt -i eth0 -N -F -H netsniff-ng.org\n");
415 printf(" IPv4 trace of AS with Xmas probe:\n");
416 printf(" ashunt -i eth0 -N -FPU -H netsniff-ng.org\n");
417 printf(" IPv4 trace of AS with Null probe with ASCII payload:\n");
418 printf(" ashunt -i eth0 -N -H netsniff-ng.org -X \"censor-me\" -Z\n");
419 printf(" IPv6 trace of AS up to netsniff-ng.org:\n");
420 printf(" ashunt -6 -S -i eth0 -H netsniff-ng.org\n");
423 printf(" If the TCP probe did not give any results, then ashunt will\n");
424 printf(" automatically probe for classic ICMP packets! To gather more\n");
425 printf(" information about ashunt's fetched AS numbers, see i.e.\n");
426 printf(" http://bgp.he.net/AS<number>!\n");
428 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
429 printf("Copyright (C) 2011-2012 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
430 printf("Swiss federal institute of technology (ETH Zurich)\n");
431 printf("License: GNU GPL version 2\n");
432 printf("This is free software: you are free to change and redistribute it.\n");
433 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-2012 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");
451 static inline unsigned short csum(unsigned short *buf
, int nwords
)
455 for (sum
= 0; nwords
> 0; nwords
--)
457 sum
= (sum
>> 16) + (sum
& 0xffff);
463 static void assemble_data(uint8_t *packet
, size_t len
, const char *payload
)
467 if (payload
== NULL
) {
468 for (i
= 0; i
< len
; ++i
)
469 packet
[i
] = (uint8_t) mt_rand_int32();
471 int lmin
= min(len
, strlen(payload
));
472 for (i
= 0; i
< lmin
; ++i
)
473 packet
[i
] = (uint8_t) payload
[i
];
474 for (i
= lmin
; i
< len
; ++i
)
475 packet
[i
] = (uint8_t) mt_rand_int32();
479 static void assemble_tcp(uint8_t *packet
, size_t len
, int syn
, int ack
,
480 int urg
, int fin
, int rst
, int psh
, int ecn
, int dport
)
482 struct tcphdr
*tcph
= (struct tcphdr
*) packet
;
484 bug_on(len
< sizeof(struct tcphdr
));
486 tcph
->source
= htons((uint16_t) mt_rand_int32());
487 tcph
->dest
= htons((uint16_t) dport
);
488 tcph
->seq
= htonl(mt_rand_int32());
489 tcph
->ack_seq
= (!!ack
? htonl(mt_rand_int32()) : 0);
499 tcph
->window
= htons((uint16_t) (100 + (mt_rand_int32() % 65435)));
501 tcph
->urg_ptr
= (!!urg
? htons((uint16_t) mt_rand_int32()) : 0);
504 /* returns: ipv4 id */
505 static int assemble_ipv4_tcp(uint8_t *packet
, size_t len
, int ttl
,
506 int tos
, const struct sockaddr
*dst
,
507 const struct sockaddr
*src
, int syn
, int ack
,
508 int urg
, int fin
, int rst
, int psh
, int ecn
,
509 int nofrag
, int dport
, const char *payload
)
511 struct iphdr
*iph
= (struct iphdr
*) packet
;
513 bug_on(!src
|| !dst
);
514 bug_on(src
->sa_family
!= PF_INET
|| dst
->sa_family
!= PF_INET
);
515 bug_on(len
< sizeof(struct iphdr
) + sizeof(struct tcphdr
));
519 iph
->tos
= (uint8_t) tos
;
520 iph
->tot_len
= htons((uint16_t) len
);
521 iph
->id
= htons((uint16_t) mt_rand_int32());
522 iph
->frag_off
= nofrag
? IP_DF
: 0;
523 iph
->ttl
= (uint8_t) ttl
;
524 iph
->protocol
= 6; /* TCP */
525 iph
->saddr
= ((const struct sockaddr_in
*) src
)->sin_addr
.s_addr
;
526 iph
->daddr
= ((const struct sockaddr_in
*) dst
)->sin_addr
.s_addr
;
528 assemble_tcp(packet
+ sizeof(struct iphdr
),
529 len
- sizeof(struct iphdr
), syn
, ack
, urg
, fin
, rst
,
532 assemble_data(packet
+ sizeof(struct iphdr
) + sizeof(struct tcphdr
),
533 len
- sizeof(struct iphdr
) - sizeof(struct tcphdr
),
536 iph
->check
= csum((unsigned short *) packet
,
537 ntohs(iph
->tot_len
) >> 1);
539 return ntohs(iph
->id
);
542 /* returns: ipv6 flow label */
543 static int assemble_ipv6_tcp(uint8_t *packet
, size_t len
, int ttl
,
544 struct sockaddr_in
*sin
)
549 static void assemble_icmp4(uint8_t *packet
, size_t len
)
551 struct icmphdr
*icmph
= (struct icmphdr
*) packet
;
553 bug_on(len
< sizeof(struct icmphdr
));
555 icmph
->type
= ICMP_ECHO
;
560 /* returns: ipv4 id */
561 static int assemble_ipv4_icmp4(uint8_t *packet
, size_t len
, int ttl
,
562 int tos
, const struct sockaddr
*dst
,
563 const struct sockaddr
*src
, int nofrag
,
566 struct iphdr
*iph
= (struct iphdr
*) packet
;
568 bug_on(!src
|| !dst
);
569 bug_on(src
->sa_family
!= PF_INET
|| dst
->sa_family
!= PF_INET
);
570 bug_on(len
< sizeof(struct iphdr
) + sizeof(struct tcphdr
));
575 iph
->tot_len
= htons((uint16_t) len
);
576 iph
->id
= htons((uint16_t) mt_rand_int32());
577 iph
->frag_off
= nofrag
? IP_DF
: 0;
578 iph
->ttl
= (uint8_t) ttl
;
579 iph
->protocol
= 1; /* ICMP4 */
580 iph
->saddr
= ((const struct sockaddr_in
*) src
)->sin_addr
.s_addr
;
581 iph
->daddr
= ((const struct sockaddr_in
*) dst
)->sin_addr
.s_addr
;
583 assemble_icmp4(packet
+ sizeof(struct iphdr
),
584 len
- sizeof(struct iphdr
));
586 assemble_data(packet
+ sizeof(struct iphdr
) + sizeof(struct icmphdr
),
587 len
- sizeof(struct iphdr
) - sizeof(struct icmphdr
),
590 iph
->check
= csum((unsigned short *) packet
,
591 ntohs(iph
->tot_len
) >> 1);
593 return ntohs(iph
->id
);
596 static int assemble_packet_or_die(uint8_t *packet
, size_t len
, int ttl
, int icmp
,
597 const struct ash_cfg
*cfg
,
598 const struct sockaddr
*dst
,
599 const struct sockaddr
*src
)
602 return assemble_ipv4_icmp4(packet
, len
, ttl
, cfg
->tos
, dst
, src
,
603 cfg
->nofrag
, cfg
->payload
);
605 return assemble_ipv4_tcp(packet
, len
, ttl
, cfg
->tos
, dst
, src
,
606 cfg
->syn
, cfg
->ack
, cfg
->urg
, cfg
->fin
,
607 cfg
->rst
, cfg
->psh
, cfg
->ecn
,
608 cfg
->nofrag
, atoi(cfg
->port
),
612 #define PKT_NOT_FOR_US 0
615 static inline const char *make_n_a(const char *p
)
620 static int handle_ipv4_icmp(uint8_t *packet
, size_t len
, int ttl
, int id
,
621 const struct sockaddr
*own
, int dns_resolv
)
624 struct iphdr
*iph
= (struct iphdr
*) packet
;
625 struct iphdr
*iph_inner
;
626 struct icmphdr
*icmph
;
628 struct sockaddr_in sa
;
632 if (iph
->protocol
!= 1)
633 return PKT_NOT_FOR_US
;
634 if (iph
->daddr
!= ((const struct sockaddr_in
*) own
)->sin_addr
.s_addr
)
635 return PKT_NOT_FOR_US
;
637 icmph
= (struct icmphdr
*) (packet
+ sizeof(struct iphdr
));
638 if (icmph
->type
!= ICMP_TIME_EXCEEDED
)
639 return PKT_NOT_FOR_US
;
640 if (icmph
->code
!= ICMP_EXC_TTL
)
641 return PKT_NOT_FOR_US
;
643 iph_inner
= (struct iphdr
*) (packet
+ sizeof(struct iphdr
) +
644 sizeof(struct icmphdr
));
645 if (ntohs(iph_inner
->id
) != id
)
646 return PKT_NOT_FOR_US
;
648 hbuff
= xzmalloc(NI_MAXHOST
);
650 memset(&sa
, 0, sizeof(sa
));
651 sa
.sin_family
= PF_INET
;
652 sa
.sin_addr
.s_addr
= iph
->saddr
;
654 getnameinfo((struct sockaddr
*) &sa
, sizeof(sa
), hbuff
, NI_MAXHOST
,
655 NULL
, 0, NI_NUMERICHOST
);
657 memset(&rec
, 0, sizeof(rec
));
658 ret
= aslookup(hbuff
, &rec
);
660 panic("AS lookup error %d!\n", ret
);
662 gir
= GeoIP_record_by_ipnum(gi_city
, ntohl(iph
->saddr
));
664 if (strlen(rec
.country
) > 0 && gir
) {
665 const char *city
= make_n_a(gir
->city
);
667 printf("%s in AS%s (%s, %s, %s, %f, %f), %s %s (%s), %s", hbuff
,
668 rec
.number
, rec
.country
,
669 GeoIP_country_name_by_ipnum(gi_country
, ntohl(iph
->saddr
)),
670 city
, gir
->latitude
, gir
->longitude
,
671 rec
.prefix
, rec
.registry
, rec
.since
, rec
.name
);
672 } else if (strlen(rec
.country
) > 0 && !gir
) {
673 printf("%s in AS%s (%s, %s), %s %s (%s), %s", hbuff
,
674 rec
.number
, rec
.country
,
675 GeoIP_country_name_by_ipnum(gi_country
, ntohl(iph
->saddr
)),
676 rec
.prefix
, rec
.registry
, rec
.since
, rec
.name
);
678 printf("%s in unkown AS", hbuff
);
681 struct hostent
*hent
= gethostbyaddr(&sa
.sin_addr
,
685 if (strlen(rec
.country
) > 0 && gir
) {
686 const char *city
= make_n_a(gir
->city
);
687 printf("%s (%s) in AS%s (%s, %s, %s, %f, %f), %s %s (%s), %s",
688 (hent
? hent
->h_name
: hbuff
), hbuff
,
689 rec
.number
, rec
.country
,
690 GeoIP_country_name_by_ipnum(gi_country
, ntohl(iph
->saddr
)),
691 city
, gir
->latitude
, gir
->longitude
,
692 rec
.prefix
, rec
.registry
,
693 rec
.since
, rec
.name
);
694 } else if (strlen(rec
.country
) > 0 && !gir
) {
695 printf("%s (%s) in AS%s (%s, %s), %s %s (%s), %s",
696 (hent
? hent
->h_name
: hbuff
), hbuff
,
697 rec
.number
, rec
.country
,
698 GeoIP_country_name_by_ipnum(gi_country
, ntohl(iph
->saddr
)),
699 rec
.prefix
, rec
.registry
,
700 rec
.since
, rec
.name
);
702 printf("%s (%s) in unkown AS",
703 (hent
? hent
->h_name
: hbuff
), hbuff
);
712 static int handle_packet(uint8_t *packet
, size_t len
, int ip
, int ttl
, int id
,
713 struct sockaddr
*own
, int dns_resolv
)
715 return handle_ipv4_icmp(packet
, len
, ttl
, id
, own
, dns_resolv
);
718 static int do_trace(const struct ash_cfg
*cfg
)
720 int ttl
, query
, fd
= -1, one
= 1, ret
, fd_cap
, ifindex
;
721 int is_okay
= 0, id
, timeout_poll
;
722 uint8_t *packet
, *packet_rcv
;
723 ssize_t err
, real_len
;
725 struct addrinfo hints
, *ahead
, *ai
;
726 char *hbuff1
, *hbuff2
;
727 struct sockaddr_storage ss
, sd
;
728 struct sock_fprog bpf_ops
;
729 struct ring dummy_ring
;
732 mt_init_by_random_device();
734 memset(&hints
, 0, sizeof(hints
));
735 hints
.ai_family
= PF_UNSPEC
;
736 hints
.ai_socktype
= SOCK_STREAM
;
737 hints
.ai_protocol
= IPPROTO_TCP
;
738 hints
.ai_flags
= AI_NUMERICSERV
;
740 ret
= getaddrinfo(cfg
->host
, cfg
->port
, &hints
, &ahead
);
742 whine("Cannot get address info!\n");
746 for (ai
= ahead
; ai
!= NULL
&& fd
< 0; ai
= ai
->ai_next
) {
747 if (!((ai
->ai_family
== PF_INET6
&& cfg
->ip
== 6) ||
748 (ai
->ai_family
== PF_INET
&& cfg
->ip
== 4)))
750 fd
= socket(ai
->ai_family
, SOCK_RAW
, ai
->ai_protocol
);
754 fd_cap
= pf_socket();
756 memset(&ss
, 0, sizeof(ss
));
757 ret
= device_address(cfg
->dev
, ai
->ai_family
, &ss
);
759 panic("Cannot get own device address!\n");
761 ret
= bind(fd
, (struct sockaddr
*) &ss
, sizeof(ss
));
763 panic("Cannot bind socket!\n");
765 memset(&sd
, 0, sizeof(sd
));
766 memcpy(&sd
, ai
->ai_addr
, ai
->ai_addrlen
);
774 whine("Cannot create socket! Does remote support IPv%d?!\n",
781 if (len
< sizeof(struct iphdr
) + sizeof(struct tcphdr
)) {
782 len
= sizeof(struct iphdr
) + sizeof(struct tcphdr
);
784 len
+= strlen(cfg
->payload
);
787 if (len
< sizeof(struct ip6_hdr
) + sizeof(struct tcphdr
)) {
788 len
= sizeof(struct ip6_hdr
) + sizeof(struct tcphdr
);
790 len
+= strlen(cfg
->payload
);
794 if (len
>= device_mtu(cfg
->dev
))
795 panic("Packet len exceeds device MTU!\n");
797 packet
= xmalloc(len
);
798 len_rcv
= device_mtu(cfg
->dev
);
799 packet_rcv
= xmalloc(len_rcv
);
801 hbuff1
= xzmalloc(256);
802 getnameinfo((struct sockaddr
*) &sd
, sizeof(sd
), hbuff1
, 256,
803 NULL
, 0, NI_NUMERICHOST
);
805 hbuff2
= xzmalloc(256);
806 getnameinfo((struct sockaddr
*) &ss
, sizeof(ss
), hbuff2
, 256,
807 NULL
, 0, NI_NUMERICHOST
);
809 ret
= setsockopt(fd
, cfg
->ip
== 4 ? IPPROTO_IP
: IPPROTO_IPV6
,
810 IP_HDRINCL
, &one
, sizeof(one
));
812 panic("Kernel does not support IP_HDRINCL!\n");
814 printf("AS path IPv%d TCP trace from %s to %s:%s (%s) with len %zu "
815 "Bytes, %u max hops\n", cfg
->ip
, hbuff2
, hbuff1
, cfg
->port
,
816 cfg
->host
, len
, cfg
->max_ttl
);
818 printf("Using flags SYN:%d,ACK:%d,ECN:%d,FIN:%d,PSH:%d,RST:%d,URG:%d\n",
819 cfg
->syn
, cfg
->ack
, cfg
->ecn
, cfg
->fin
, cfg
->psh
, cfg
->rst
,
823 printf("With payload: \'%s\'\n", cfg
->payload
);
830 hbuff1
= hbuff2
= NULL
;
832 enable_kernel_bpf_jit_compiler();
834 memset(&bpf_ops
, 0, sizeof(bpf_ops
));
836 bpf_ops
.filter
= ipv4_icmp_type_11
;
837 bpf_ops
.len
= (sizeof(ipv4_icmp_type_11
) /
838 sizeof(ipv4_icmp_type_11
[0]));
840 bpf_ops
.filter
= ipv6_icmp6_type_3
;
841 bpf_ops
.len
= (sizeof(ipv6_icmp6_type_3
) /
842 sizeof(ipv6_icmp6_type_3
[0]));
845 bpf_attach_to_sock(fd_cap
, &bpf_ops
);
846 ifindex
= device_ifindex(cfg
->dev
);
847 bind_rx_ring(fd_cap
, &dummy_ring
, ifindex
);
848 prepare_polling(fd_cap
, &pfd
);
850 timeout_poll
= (cfg
->timeout
> 0 ? cfg
->timeout
: 3) * 1000;
852 for (ttl
= cfg
->init_ttl
; ttl
<= cfg
->max_ttl
; ++ttl
) {
856 if ((ttl
== cfg
->init_ttl
&& !show_pkt
) ||
857 (ttl
> cfg
->init_ttl
)) {
858 printf("%2d: ", ttl
);
862 for (query
= 0; query
< cfg
->queries
&& !is_okay
; ++query
) {
863 id
= assemble_packet_or_die(packet
, len
, ttl
, icmp
, cfg
,
864 (struct sockaddr
*) &sd
,
865 (struct sockaddr
*) &ss
);
866 if (ttl
== cfg
->init_ttl
&& query
== 0 && show_pkt
) {
867 struct pkt_buff
*pkt
;
869 printf("Original packet:\n");
871 pkt
= pkt_alloc(packet
, len
);
876 printf("\n%2d: ", ttl
);
880 err
= sendto(fd
, packet
, len
, 0, (struct sockaddr
*) &sd
,
883 panic("sendto failed: %s\n", strerror(errno
));
885 err
= poll(&pfd
, 1, timeout_poll
);
886 if (err
> 0 && pfd
.revents
& POLLIN
) {
887 real_len
= recvfrom(fd_cap
, packet_rcv
, len_rcv
,
889 if (real_len
< sizeof(struct ethhdr
) +
890 (cfg
->ip
? sizeof(struct iphdr
) +
891 sizeof(struct icmphdr
) :
892 sizeof(struct ip6_hdr
) +
893 sizeof(struct icmp6hdr
)))
896 is_okay
= handle_packet(packet_rcv
+ sizeof(struct ethhdr
),
897 real_len
- sizeof(struct ethhdr
),
899 (struct sockaddr
*) &ss
,
901 if (is_okay
&& show_pkt
) {
902 struct pkt_buff
*pkt
;
904 printf("\n Received packet:\n");
906 pkt
= pkt_alloc(packet_rcv
, real_len
);
918 if (is_okay
== 0 && icmp
== 0) {
936 static void parse_whois_or_die(struct ash_cfg
*cfg
)
940 char tmp
[512], *ptr
, *ptr2
;
942 fd
= open_or_die(WHOIS_SERVER_SOURCE
, O_RDONLY
);
944 while ((ret
= read(fd
, tmp
, sizeof(tmp
))) > 0) {
945 tmp
[sizeof(tmp
) - 1] = 0;
948 while (*ptr2
!= ' ' && ptr2
< &tmp
[sizeof(tmp
) - 1])
951 panic("Parser error!\n");
953 cfg
->whois
= xstrdup(ptr
);
955 if (ptr
>= &tmp
[sizeof(tmp
) - 1])
956 panic("Parser error!\n");
958 ptr
[strlen(ptr
) - 1] = 0;
959 cfg
->whois_port
= xstrdup(ptr
);
966 int main(int argc
, char **argv
)
968 int c
, opt_index
, ret
;
970 char *path_city_db
= NULL
, *path_country_db
= NULL
;
972 check_for_root_maybe_die();
974 memset(&cfg
, 0, sizeof(cfg
));
981 cfg
.dev
= xstrdup("eth0");
982 cfg
.port
= xstrdup("80");
984 while ((c
= getopt_long(argc
, argv
, short_options
, long_options
,
985 &opt_index
)) != EOF
) {
994 cfg
.host
= xstrdup(optarg
);
999 cfg
.port
= xstrdup(optarg
);
1017 cfg
.init_ttl
= atoi(optarg
);
1018 if (cfg
.init_ttl
<= 0)
1022 cfg
.max_ttl
= atoi(optarg
);
1023 if (cfg
.max_ttl
<= 0)
1030 cfg
.dev
= xstrdup(optarg
);
1033 cfg
.queries
= atoi(optarg
);
1034 if (cfg
.queries
<= 0)
1038 cfg
.timeout
= atoi(optarg
);
1039 if (cfg
.timeout
<= 0)
1065 cfg
.tos
= atoi(optarg
);
1073 cfg
.payload
= xstrdup(optarg
);
1076 cfg
.totlen
= atoi(optarg
);
1077 if (cfg
.totlen
<= 0)
1081 cfg
.whois
= xstrdup(optarg
);
1084 cfg
.whois_port
= xstrdup(optarg
);
1087 path_city_db
= xstrdup(optarg
);
1090 path_country_db
= xstrdup(optarg
);
1109 panic("Option -%c requires an argument!\n",
1112 if (isprint(optopt
))
1113 whine("Unknown option character "
1114 "`0x%X\'!\n", optopt
);
1123 !cfg
.host
|| !cfg
.port
||
1124 cfg
.init_ttl
> cfg
.max_ttl
||
1125 cfg
.init_ttl
> MAXTTL
||
1126 cfg
.max_ttl
> MAXTTL
)
1129 if (!device_up_and_running(cfg
.dev
))
1130 panic("Networking device not up and running!\n");
1131 if (!cfg
.whois
|| !cfg
.whois_port
)
1132 parse_whois_or_die(&cfg
);
1133 if (device_mtu(cfg
.dev
) <= cfg
.totlen
)
1134 panic("Packet larger than device MTU!\n");
1136 register_signal(SIGHUP
, signal_handler
);
1142 ret
= aslookup_prepare(cfg
.whois
, cfg
.whois_port
);
1144 panic("Cannot resolve whois server!\n");
1146 if (path_country_db
)
1147 gi_country
= GeoIP_open(path_country_db
, GEOIP_MMAP_CACHE
);
1149 gi_country
= GeoIP_open_type(GEOIP_COUNTRY_EDITION
,
1153 gi_city
= GeoIP_open(path_city_db
, GEOIP_MMAP_CACHE
);
1155 gi_city
= GeoIP_open_type(GEOIP_CITY_EDITION_REV1
,
1158 if (!gi_country
|| !gi_city
)
1159 panic("Cannot open GeoIP database! Wrong path?!\n");
1161 GeoIP_set_charset(gi_country
, GEOIP_CHARSET_UTF8
);
1162 GeoIP_set_charset(gi_city
, GEOIP_CHARSET_UTF8
);
1164 ret
= do_trace(&cfg
);
1166 GeoIP_delete(gi_city
);
1167 GeoIP_delete(gi_country
);
1172 xfree(cfg
.whois_port
);
1184 xfree(path_city_db
);
1185 if (path_country_db
)
1186 xfree(path_country_db
);