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"
235 #include "aslookup.h"
239 #include "built_in.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-2012 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");
436 static void version(void)
438 printf("\nashunt %s, AS trace route utility\n",
440 printf("http://www.netsniff-ng.org\n\n");
441 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
442 printf("Copyright (C) 2011-2012 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
443 printf("Swiss federal institute of technology (ETH Zurich)\n");
444 printf("License: GNU GPL version 2\n");
445 printf("This is free software: you are free to change and redistribute it.\n");
446 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
450 static inline unsigned short csum(unsigned short *buf
, int nwords
)
454 for (sum
= 0; nwords
> 0; nwords
--)
456 sum
= (sum
>> 16) + (sum
& 0xffff);
462 static void assemble_data(uint8_t *packet
, size_t len
, const char *payload
)
466 if (payload
== NULL
) {
467 for (i
= 0; i
< len
; ++i
)
468 packet
[i
] = (uint8_t) mt_rand_int32();
470 int lmin
= min(len
, strlen(payload
));
471 for (i
= 0; i
< lmin
; ++i
)
472 packet
[i
] = (uint8_t) payload
[i
];
473 for (i
= lmin
; i
< len
; ++i
)
474 packet
[i
] = (uint8_t) mt_rand_int32();
478 static void assemble_tcp(uint8_t *packet
, size_t len
, int syn
, int ack
,
479 int urg
, int fin
, int rst
, int psh
, int ecn
, int dport
)
481 struct tcphdr
*tcph
= (struct tcphdr
*) packet
;
483 bug_on(len
< sizeof(struct tcphdr
));
485 tcph
->source
= htons((uint16_t) mt_rand_int32());
486 tcph
->dest
= htons((uint16_t) dport
);
487 tcph
->seq
= htonl(mt_rand_int32());
488 tcph
->ack_seq
= (!!ack
? htonl(mt_rand_int32()) : 0);
498 tcph
->window
= htons((uint16_t) (100 + (mt_rand_int32() % 65435)));
500 tcph
->urg_ptr
= (!!urg
? htons((uint16_t) mt_rand_int32()) : 0);
503 /* returns: ipv4 id */
504 static int assemble_ipv4_tcp(uint8_t *packet
, size_t len
, int ttl
,
505 int tos
, const struct sockaddr
*dst
,
506 const struct sockaddr
*src
, int syn
, int ack
,
507 int urg
, int fin
, int rst
, int psh
, int ecn
,
508 int nofrag
, int dport
, const char *payload
)
510 struct iphdr
*iph
= (struct iphdr
*) packet
;
512 bug_on(!src
|| !dst
);
513 bug_on(src
->sa_family
!= PF_INET
|| dst
->sa_family
!= PF_INET
);
514 bug_on(len
< sizeof(struct iphdr
) + sizeof(struct tcphdr
));
518 iph
->tos
= (uint8_t) tos
;
519 iph
->tot_len
= htons((uint16_t) len
);
520 iph
->id
= htons((uint16_t) mt_rand_int32());
521 iph
->frag_off
= nofrag
? IP_DF
: 0;
522 iph
->ttl
= (uint8_t) ttl
;
523 iph
->protocol
= 6; /* TCP */
524 iph
->saddr
= ((const struct sockaddr_in
*) src
)->sin_addr
.s_addr
;
525 iph
->daddr
= ((const struct sockaddr_in
*) dst
)->sin_addr
.s_addr
;
527 assemble_tcp(packet
+ sizeof(struct iphdr
),
528 len
- sizeof(struct iphdr
), syn
, ack
, urg
, fin
, rst
,
531 assemble_data(packet
+ sizeof(struct iphdr
) + sizeof(struct tcphdr
),
532 len
- sizeof(struct iphdr
) - sizeof(struct tcphdr
),
535 iph
->check
= csum((unsigned short *) packet
,
536 ntohs(iph
->tot_len
) >> 1);
538 return ntohs(iph
->id
);
541 /* returns: ipv6 flow label */
542 static int assemble_ipv6_tcp(uint8_t *packet
, size_t len
, int ttl
,
543 struct sockaddr_in
*sin
)
548 static void assemble_icmp4(uint8_t *packet
, size_t len
)
550 struct icmphdr
*icmph
= (struct icmphdr
*) packet
;
552 bug_on(len
< sizeof(struct icmphdr
));
554 icmph
->type
= ICMP_ECHO
;
559 /* returns: ipv4 id */
560 static int assemble_ipv4_icmp4(uint8_t *packet
, size_t len
, int ttl
,
561 int tos
, const struct sockaddr
*dst
,
562 const struct sockaddr
*src
, int nofrag
,
565 struct iphdr
*iph
= (struct iphdr
*) packet
;
567 bug_on(!src
|| !dst
);
568 bug_on(src
->sa_family
!= PF_INET
|| dst
->sa_family
!= PF_INET
);
569 bug_on(len
< sizeof(struct iphdr
) + sizeof(struct tcphdr
));
574 iph
->tot_len
= htons((uint16_t) len
);
575 iph
->id
= htons((uint16_t) mt_rand_int32());
576 iph
->frag_off
= nofrag
? IP_DF
: 0;
577 iph
->ttl
= (uint8_t) ttl
;
578 iph
->protocol
= 1; /* ICMP4 */
579 iph
->saddr
= ((const struct sockaddr_in
*) src
)->sin_addr
.s_addr
;
580 iph
->daddr
= ((const struct sockaddr_in
*) dst
)->sin_addr
.s_addr
;
582 assemble_icmp4(packet
+ sizeof(struct iphdr
),
583 len
- sizeof(struct iphdr
));
585 assemble_data(packet
+ sizeof(struct iphdr
) + sizeof(struct icmphdr
),
586 len
- sizeof(struct iphdr
) - sizeof(struct icmphdr
),
589 iph
->check
= csum((unsigned short *) packet
,
590 ntohs(iph
->tot_len
) >> 1);
592 return ntohs(iph
->id
);
595 static int assemble_packet_or_die(uint8_t *packet
, size_t len
, int ttl
, int icmp
,
596 const struct ash_cfg
*cfg
,
597 const struct sockaddr
*dst
,
598 const struct sockaddr
*src
)
601 return assemble_ipv4_icmp4(packet
, len
, ttl
, cfg
->tos
, dst
, src
,
602 cfg
->nofrag
, cfg
->payload
);
604 return assemble_ipv4_tcp(packet
, len
, ttl
, cfg
->tos
, dst
, src
,
605 cfg
->syn
, cfg
->ack
, cfg
->urg
, cfg
->fin
,
606 cfg
->rst
, cfg
->psh
, cfg
->ecn
,
607 cfg
->nofrag
, atoi(cfg
->port
),
611 #define PKT_NOT_FOR_US 0
614 static inline const char *make_n_a(const char *p
)
619 static int handle_ipv4_icmp(uint8_t *packet
, size_t len
, int ttl
, int id
,
620 const struct sockaddr
*own
, int dns_resolv
)
623 struct iphdr
*iph
= (struct iphdr
*) packet
;
624 struct iphdr
*iph_inner
;
625 struct icmphdr
*icmph
;
627 struct sockaddr_in sa
;
631 if (iph
->protocol
!= 1)
632 return PKT_NOT_FOR_US
;
633 if (iph
->daddr
!= ((const struct sockaddr_in
*) own
)->sin_addr
.s_addr
)
634 return PKT_NOT_FOR_US
;
636 icmph
= (struct icmphdr
*) (packet
+ sizeof(struct iphdr
));
637 if (icmph
->type
!= ICMP_TIME_EXCEEDED
)
638 return PKT_NOT_FOR_US
;
639 if (icmph
->code
!= ICMP_EXC_TTL
)
640 return PKT_NOT_FOR_US
;
642 iph_inner
= (struct iphdr
*) (packet
+ sizeof(struct iphdr
) +
643 sizeof(struct icmphdr
));
644 if (ntohs(iph_inner
->id
) != id
)
645 return PKT_NOT_FOR_US
;
647 hbuff
= xzmalloc(NI_MAXHOST
);
649 memset(&sa
, 0, sizeof(sa
));
650 sa
.sin_family
= PF_INET
;
651 sa
.sin_addr
.s_addr
= iph
->saddr
;
653 getnameinfo((struct sockaddr
*) &sa
, sizeof(sa
), hbuff
, NI_MAXHOST
,
654 NULL
, 0, NI_NUMERICHOST
);
656 memset(&rec
, 0, sizeof(rec
));
657 ret
= aslookup(hbuff
, &rec
);
659 panic("AS lookup error %d!\n", ret
);
661 gir
= GeoIP_record_by_ipnum(gi_city
, ntohl(iph
->saddr
));
663 if (strlen(rec
.country
) > 0 && gir
) {
664 const char *city
= make_n_a(gir
->city
);
666 printf("%s in AS%s (%s, %s, %s, %f, %f), %s %s (%s), %s", hbuff
,
667 rec
.number
, rec
.country
,
668 GeoIP_country_name_by_ipnum(gi_country
, ntohl(iph
->saddr
)),
669 city
, gir
->latitude
, gir
->longitude
,
670 rec
.prefix
, rec
.registry
, rec
.since
, rec
.name
);
671 } else if (strlen(rec
.country
) > 0 && !gir
) {
672 printf("%s in AS%s (%s, %s), %s %s (%s), %s", hbuff
,
673 rec
.number
, rec
.country
,
674 GeoIP_country_name_by_ipnum(gi_country
, ntohl(iph
->saddr
)),
675 rec
.prefix
, rec
.registry
, rec
.since
, rec
.name
);
677 printf("%s in unkown AS", hbuff
);
680 struct hostent
*hent
= gethostbyaddr(&sa
.sin_addr
,
684 if (strlen(rec
.country
) > 0 && gir
) {
685 const char *city
= make_n_a(gir
->city
);
686 printf("%s (%s) in AS%s (%s, %s, %s, %f, %f), %s %s (%s), %s",
687 (hent
? hent
->h_name
: hbuff
), hbuff
,
688 rec
.number
, rec
.country
,
689 GeoIP_country_name_by_ipnum(gi_country
, ntohl(iph
->saddr
)),
690 city
, gir
->latitude
, gir
->longitude
,
691 rec
.prefix
, rec
.registry
,
692 rec
.since
, rec
.name
);
693 } else if (strlen(rec
.country
) > 0 && !gir
) {
694 printf("%s (%s) in AS%s (%s, %s), %s %s (%s), %s",
695 (hent
? hent
->h_name
: hbuff
), hbuff
,
696 rec
.number
, rec
.country
,
697 GeoIP_country_name_by_ipnum(gi_country
, ntohl(iph
->saddr
)),
698 rec
.prefix
, rec
.registry
,
699 rec
.since
, rec
.name
);
701 printf("%s (%s) in unkown AS",
702 (hent
? hent
->h_name
: hbuff
), hbuff
);
711 static int handle_packet(uint8_t *packet
, size_t len
, int ip
, int ttl
, int id
,
712 struct sockaddr
*own
, int dns_resolv
)
714 return handle_ipv4_icmp(packet
, len
, ttl
, id
, own
, dns_resolv
);
717 static int do_trace(const struct ash_cfg
*cfg
)
719 int ttl
, query
, fd
= -1, one
= 1, ret
, fd_cap
, ifindex
;
720 int is_okay
= 0, id
, timeout_poll
;
721 uint8_t *packet
, *packet_rcv
;
722 ssize_t err
, real_len
;
724 struct addrinfo hints
, *ahead
, *ai
;
725 char *hbuff1
, *hbuff2
;
726 struct sockaddr_storage ss
, sd
;
727 struct sock_fprog bpf_ops
;
728 struct ring dummy_ring
;
731 mt_init_by_random_device();
733 memset(&hints
, 0, sizeof(hints
));
734 hints
.ai_family
= PF_UNSPEC
;
735 hints
.ai_socktype
= SOCK_STREAM
;
736 hints
.ai_protocol
= IPPROTO_TCP
;
737 hints
.ai_flags
= AI_NUMERICSERV
;
739 ret
= getaddrinfo(cfg
->host
, cfg
->port
, &hints
, &ahead
);
741 whine("Cannot get address info!\n");
745 for (ai
= ahead
; ai
!= NULL
&& fd
< 0; ai
= ai
->ai_next
) {
746 if (!((ai
->ai_family
== PF_INET6
&& cfg
->ip
== 6) ||
747 (ai
->ai_family
== PF_INET
&& cfg
->ip
== 4)))
749 fd
= socket(ai
->ai_family
, SOCK_RAW
, ai
->ai_protocol
);
753 fd_cap
= pf_socket();
755 memset(&ss
, 0, sizeof(ss
));
756 ret
= device_address(cfg
->dev
, ai
->ai_family
, &ss
);
758 panic("Cannot get own device address!\n");
760 ret
= bind(fd
, (struct sockaddr
*) &ss
, sizeof(ss
));
762 panic("Cannot bind socket!\n");
764 memset(&sd
, 0, sizeof(sd
));
765 memcpy(&sd
, ai
->ai_addr
, ai
->ai_addrlen
);
773 whine("Cannot create socket! Does remote support IPv%d?!\n",
780 if (len
< sizeof(struct iphdr
) + sizeof(struct tcphdr
)) {
781 len
= sizeof(struct iphdr
) + sizeof(struct tcphdr
);
783 len
+= strlen(cfg
->payload
);
786 if (len
< sizeof(struct ip6_hdr
) + sizeof(struct tcphdr
)) {
787 len
= sizeof(struct ip6_hdr
) + sizeof(struct tcphdr
);
789 len
+= strlen(cfg
->payload
);
793 if (len
>= device_mtu(cfg
->dev
))
794 panic("Packet len exceeds device MTU!\n");
796 packet
= xmalloc(len
);
797 len_rcv
= device_mtu(cfg
->dev
);
798 packet_rcv
= xmalloc(len_rcv
);
800 hbuff1
= xzmalloc(256);
801 getnameinfo((struct sockaddr
*) &sd
, sizeof(sd
), hbuff1
, 256,
802 NULL
, 0, NI_NUMERICHOST
);
804 hbuff2
= xzmalloc(256);
805 getnameinfo((struct sockaddr
*) &ss
, sizeof(ss
), hbuff2
, 256,
806 NULL
, 0, NI_NUMERICHOST
);
808 ret
= setsockopt(fd
, cfg
->ip
== 4 ? IPPROTO_IP
: IPPROTO_IPV6
,
809 IP_HDRINCL
, &one
, sizeof(one
));
811 panic("Kernel does not support IP_HDRINCL!\n");
813 printf("AS path IPv%d TCP trace from %s to %s:%s (%s) with len %zu "
814 "Bytes, %u max hops\n", cfg
->ip
, hbuff2
, hbuff1
, cfg
->port
,
815 cfg
->host
, len
, cfg
->max_ttl
);
817 printf("Using flags SYN:%d,ACK:%d,ECN:%d,FIN:%d,PSH:%d,RST:%d,URG:%d\n",
818 cfg
->syn
, cfg
->ack
, cfg
->ecn
, cfg
->fin
, cfg
->psh
, cfg
->rst
,
822 printf("With payload: \'%s\'\n", cfg
->payload
);
829 hbuff1
= hbuff2
= NULL
;
831 enable_kernel_bpf_jit_compiler();
833 memset(&bpf_ops
, 0, sizeof(bpf_ops
));
835 bpf_ops
.filter
= ipv4_icmp_type_11
;
836 bpf_ops
.len
= (sizeof(ipv4_icmp_type_11
) /
837 sizeof(ipv4_icmp_type_11
[0]));
839 bpf_ops
.filter
= ipv6_icmp6_type_3
;
840 bpf_ops
.len
= (sizeof(ipv6_icmp6_type_3
) /
841 sizeof(ipv6_icmp6_type_3
[0]));
844 bpf_attach_to_sock(fd_cap
, &bpf_ops
);
845 ifindex
= device_ifindex(cfg
->dev
);
846 bind_rx_ring(fd_cap
, &dummy_ring
, ifindex
);
847 prepare_polling(fd_cap
, &pfd
);
849 timeout_poll
= (cfg
->timeout
> 0 ? cfg
->timeout
: 3) * 1000;
851 for (ttl
= cfg
->init_ttl
; ttl
<= cfg
->max_ttl
; ++ttl
) {
855 if ((ttl
== cfg
->init_ttl
&& !show_pkt
) ||
856 (ttl
> cfg
->init_ttl
)) {
857 printf("%2d: ", ttl
);
861 for (query
= 0; query
< cfg
->queries
&& !is_okay
; ++query
) {
862 id
= assemble_packet_or_die(packet
, len
, ttl
, icmp
, cfg
,
863 (struct sockaddr
*) &sd
,
864 (struct sockaddr
*) &ss
);
865 if (ttl
== cfg
->init_ttl
&& query
== 0 && show_pkt
) {
866 struct pkt_buff
*pkt
;
868 printf("Original packet:\n");
870 pkt
= pkt_alloc(packet
, len
);
875 printf("\n%2d: ", ttl
);
879 err
= sendto(fd
, packet
, len
, 0, (struct sockaddr
*) &sd
,
882 panic("sendto failed: %s\n", strerror(errno
));
884 err
= poll(&pfd
, 1, timeout_poll
);
885 if (err
> 0 && pfd
.revents
& POLLIN
) {
886 real_len
= recvfrom(fd_cap
, packet_rcv
, len_rcv
,
888 if (real_len
< sizeof(struct ethhdr
) +
889 (cfg
->ip
? sizeof(struct iphdr
) +
890 sizeof(struct icmphdr
) :
891 sizeof(struct ip6_hdr
) +
892 sizeof(struct icmp6hdr
)))
895 is_okay
= handle_packet(packet_rcv
+ sizeof(struct ethhdr
),
896 real_len
- sizeof(struct ethhdr
),
898 (struct sockaddr
*) &ss
,
900 if (is_okay
&& show_pkt
) {
901 struct pkt_buff
*pkt
;
903 printf("\n Received packet:\n");
905 pkt
= pkt_alloc(packet_rcv
, real_len
);
917 if (is_okay
== 0 && icmp
== 0) {
935 static void parse_whois_or_die(struct ash_cfg
*cfg
)
939 char tmp
[512], *ptr
, *ptr2
;
941 fd
= open_or_die(WHOIS_SERVER_SOURCE
, O_RDONLY
);
943 while ((ret
= read(fd
, tmp
, sizeof(tmp
))) > 0) {
944 tmp
[sizeof(tmp
) - 1] = 0;
947 while (*ptr2
!= ' ' && ptr2
< &tmp
[sizeof(tmp
) - 1])
950 panic("Parser error!\n");
952 cfg
->whois
= xstrdup(ptr
);
954 if (ptr
>= &tmp
[sizeof(tmp
) - 1])
955 panic("Parser error!\n");
957 ptr
[strlen(ptr
) - 1] = 0;
958 cfg
->whois_port
= xstrdup(ptr
);
965 int main(int argc
, char **argv
)
967 int c
, opt_index
, ret
;
969 char *path_city_db
= NULL
, *path_country_db
= NULL
;
971 check_for_root_maybe_die();
973 memset(&cfg
, 0, sizeof(cfg
));
980 cfg
.dev
= xstrdup("eth0");
981 cfg
.port
= xstrdup("80");
983 while ((c
= getopt_long(argc
, argv
, short_options
, long_options
,
984 &opt_index
)) != EOF
) {
993 cfg
.host
= xstrdup(optarg
);
998 cfg
.port
= xstrdup(optarg
);
1016 cfg
.init_ttl
= atoi(optarg
);
1017 if (cfg
.init_ttl
<= 0)
1021 cfg
.max_ttl
= atoi(optarg
);
1022 if (cfg
.max_ttl
<= 0)
1029 cfg
.dev
= xstrdup(optarg
);
1032 cfg
.queries
= atoi(optarg
);
1033 if (cfg
.queries
<= 0)
1037 cfg
.timeout
= atoi(optarg
);
1038 if (cfg
.timeout
<= 0)
1064 cfg
.tos
= atoi(optarg
);
1072 cfg
.payload
= xstrdup(optarg
);
1075 cfg
.totlen
= atoi(optarg
);
1076 if (cfg
.totlen
<= 0)
1080 cfg
.whois
= xstrdup(optarg
);
1083 cfg
.whois_port
= xstrdup(optarg
);
1086 path_city_db
= xstrdup(optarg
);
1089 path_country_db
= xstrdup(optarg
);
1108 panic("Option -%c requires an argument!\n",
1111 if (isprint(optopt
))
1112 whine("Unknown option character "
1113 "`0x%X\'!\n", optopt
);
1122 !cfg
.host
|| !cfg
.port
||
1123 cfg
.init_ttl
> cfg
.max_ttl
||
1124 cfg
.init_ttl
> MAXTTL
||
1125 cfg
.max_ttl
> MAXTTL
)
1128 if (!device_up_and_running(cfg
.dev
))
1129 panic("Networking device not up and running!\n");
1130 if (!cfg
.whois
|| !cfg
.whois_port
)
1131 parse_whois_or_die(&cfg
);
1132 if (device_mtu(cfg
.dev
) <= cfg
.totlen
)
1133 panic("Packet larger than device MTU!\n");
1135 register_signal(SIGHUP
, signal_handler
);
1141 ret
= aslookup_prepare(cfg
.whois
, cfg
.whois_port
);
1143 panic("Cannot resolve whois server!\n");
1145 if (path_country_db
)
1146 gi_country
= GeoIP_open(path_country_db
, GEOIP_MMAP_CACHE
);
1148 gi_country
= GeoIP_open_type(GEOIP_COUNTRY_EDITION
,
1152 gi_city
= GeoIP_open(path_city_db
, GEOIP_MMAP_CACHE
);
1154 gi_city
= GeoIP_open_type(GEOIP_CITY_EDITION_REV1
,
1157 if (!gi_country
|| !gi_city
)
1158 panic("Cannot open GeoIP database! Wrong path?!\n");
1160 GeoIP_set_charset(gi_country
, GEOIP_CHARSET_UTF8
);
1161 GeoIP_set_charset(gi_city
, GEOIP_CHARSET_UTF8
);
1163 ret
= do_trace(&cfg
);
1165 GeoIP_delete(gi_city
);
1166 GeoIP_delete(gi_country
);
1171 xfree(cfg
.whois_port
);
1183 xfree(path_city_db
);
1184 if (path_country_db
)
1185 xfree(path_country_db
);