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"
232 #include "proto_struct.h"
233 #include "proto_none.h"
237 #include "aslookup.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
));
257 int syn
, ack
, ecn
, fin
, psh
, rst
, urg
;
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'},
308 static struct sock_filter ipv4_icmp_type_11
[] = {
310 { 0x28, 0, 0, 0x0000000c },
311 /* (001) jeq #0x800 jt 2 jf 10 */
312 { 0x15, 0, 8, 0x00000800 },
314 { 0x30, 0, 0, 0x00000017 },
315 /* (003) jeq #0x1 jt 4 jf 10 */
316 { 0x15, 0, 6, 0x00000001 },
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 },
330 { 0x06, 0, 0, 0x00000000 },
333 static struct sock_filter ipv6_icmp6_type_3
[] = {
335 { 0x28, 0, 0, 0x0000000c },
336 /* (001) jeq #0x86dd jt 2 jf 7 */
337 { 0x15, 0, 5, 0x000086dd },
339 { 0x30, 0, 0, 0x00000014 },
340 /* (003) jeq #0x3a jt 4 jf 7 */
341 { 0x15, 0, 3, 0x0000003a },
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 },
349 { 0x06, 0, 0, 0x00000000 },
352 static void signal_handler(int number
)
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",
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");
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");
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");
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");
438 static void version(void)
440 printf("\nashunt %s, AS trace route utility\n",
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");
452 static inline unsigned short csum(unsigned short *buf
, int nwords
)
456 for (sum
= 0; nwords
> 0; nwords
--)
458 sum
= (sum
>> 16) + (sum
& 0xffff);
464 static void assemble_data(uint8_t *packet
, size_t len
, const char *payload
)
468 if (payload
== NULL
) {
469 for (i
= 0; i
< len
; ++i
)
470 packet
[i
] = (uint8_t) mt_rand_int32();
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);
500 tcph
->window
= htons((uint16_t) (100 + (mt_rand_int32() % 65435)));
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
));
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
,
533 assemble_data(packet
+ sizeof(struct iphdr
) + sizeof(struct tcphdr
),
534 len
- sizeof(struct iphdr
) - sizeof(struct tcphdr
),
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
)
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
;
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
,
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
));
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
),
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
)
603 return assemble_ipv4_icmp4(packet
, len
, ttl
, cfg
->tos
, dst
, src
,
604 cfg
->nofrag
, cfg
->payload
);
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
),
613 #define PKT_NOT_FOR_US 0
616 static inline const char *make_n_a(const char *p
)
621 static int handle_ipv4_icmp(uint8_t *packet
, size_t len
, int ttl
, int id
,
622 const struct sockaddr
*own
, int dns_resolv
)
625 struct iphdr
*iph
= (struct iphdr
*) packet
;
626 struct iphdr
*iph_inner
;
627 struct icmphdr
*icmph
;
629 struct sockaddr_in sa
;
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
);
661 panic("AS lookup error %d!\n", ret
);
663 gir
= GeoIP_record_by_ipnum(gi_city
, ntohl(iph
->saddr
));
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
);
679 printf("%s in unkown AS", hbuff
);
682 struct hostent
*hent
= gethostbyaddr(&sa
.sin_addr
,
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
);
703 printf("%s (%s) in unkown AS",
704 (hent
? hent
->h_name
: hbuff
), hbuff
);
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
;
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
;
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
);
743 whine("Cannot get address info!\n");
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)))
751 fd
= socket(ai
->ai_family
, SOCK_RAW
, ai
->ai_protocol
);
755 fd_cap
= pf_socket();
757 memset(&ss
, 0, sizeof(ss
));
758 ret
= device_address(cfg
->dev
, ai
->ai_family
, &ss
);
760 panic("Cannot get own device address!\n");
762 ret
= bind(fd
, (struct sockaddr
*) &ss
, sizeof(ss
));
764 panic("Cannot bind socket!\n");
766 memset(&sd
, 0, sizeof(sd
));
767 memcpy(&sd
, ai
->ai_addr
, ai
->ai_addrlen
);
775 whine("Cannot create socket! Does remote support IPv%d?!\n",
782 if (len
< sizeof(struct iphdr
) + sizeof(struct tcphdr
)) {
783 len
= sizeof(struct iphdr
) + sizeof(struct tcphdr
);
785 len
+= strlen(cfg
->payload
);
788 if (len
< sizeof(struct ip6_hdr
) + sizeof(struct tcphdr
)) {
789 len
= sizeof(struct ip6_hdr
) + sizeof(struct tcphdr
);
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
));
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
,
824 printf("With payload: \'%s\'\n", cfg
->payload
);
831 hbuff1
= hbuff2
= NULL
;
833 enable_kernel_bpf_jit_compiler();
835 memset(&bpf_ops
, 0, sizeof(bpf_ops
));
837 bpf_ops
.filter
= ipv4_icmp_type_11
;
838 bpf_ops
.len
= (sizeof(ipv4_icmp_type_11
) /
839 sizeof(ipv4_icmp_type_11
[0]));
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
) {
857 if ((ttl
== cfg
->init_ttl
&& !show_pkt
) ||
858 (ttl
> cfg
->init_ttl
)) {
859 printf("%2d: ", ttl
);
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
);
877 printf("\n%2d: ", ttl
);
881 err
= sendto(fd
, packet
, len
, 0, (struct sockaddr
*) &sd
,
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
,
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
)))
897 is_okay
= handle_packet(packet_rcv
+ sizeof(struct ethhdr
),
898 real_len
- sizeof(struct ethhdr
),
900 (struct sockaddr
*) &ss
,
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
);
919 if (is_okay
== 0 && icmp
== 0) {
937 static void parse_whois_or_die(struct ash_cfg
*cfg
)
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;
949 while (*ptr2
!= ' ' && ptr2
< &tmp
[sizeof(tmp
) - 1])
952 panic("Parser error!\n");
954 cfg
->whois
= xstrdup(ptr
);
956 if (ptr
>= &tmp
[sizeof(tmp
) - 1])
957 panic("Parser error!\n");
959 ptr
[strlen(ptr
) - 1] = 0;
960 cfg
->whois_port
= xstrdup(ptr
);
967 int main(int argc
, char **argv
)
969 int c
, opt_index
, ret
;
971 char *path_city_db
= NULL
, *path_country_db
= NULL
;
973 check_for_root_maybe_die();
975 memset(&cfg
, 0, sizeof(cfg
));
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
) {
995 cfg
.host
= xstrdup(optarg
);
1000 cfg
.port
= xstrdup(optarg
);
1018 cfg
.init_ttl
= atoi(optarg
);
1019 if (cfg
.init_ttl
<= 0)
1023 cfg
.max_ttl
= atoi(optarg
);
1024 if (cfg
.max_ttl
<= 0)
1031 cfg
.dev
= xstrdup(optarg
);
1034 cfg
.queries
= atoi(optarg
);
1035 if (cfg
.queries
<= 0)
1039 cfg
.timeout
= atoi(optarg
);
1040 if (cfg
.timeout
<= 0)
1066 cfg
.tos
= atoi(optarg
);
1074 cfg
.payload
= xstrdup(optarg
);
1077 cfg
.totlen
= atoi(optarg
);
1078 if (cfg
.totlen
<= 0)
1082 cfg
.whois
= xstrdup(optarg
);
1085 cfg
.whois_port
= xstrdup(optarg
);
1088 path_city_db
= xstrdup(optarg
);
1091 path_country_db
= xstrdup(optarg
);
1110 panic("Option -%c requires an argument!\n",
1113 if (isprint(optopt
))
1114 whine("Unknown option character "
1115 "`0x%X\'!\n", optopt
);
1124 !cfg
.host
|| !cfg
.port
||
1125 cfg
.init_ttl
> cfg
.max_ttl
||
1126 cfg
.init_ttl
> MAXTTL
||
1127 cfg
.max_ttl
> MAXTTL
)
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
);
1143 ret
= aslookup_prepare(cfg
.whois
, cfg
.whois_port
);
1145 panic("Cannot resolve whois server!\n");
1147 if (path_country_db
)
1148 gi_country
= GeoIP_open(path_country_db
, GEOIP_MMAP_CACHE
);
1150 gi_country
= GeoIP_open_type(GEOIP_COUNTRY_EDITION
,
1154 gi_city
= GeoIP_open(path_city_db
, GEOIP_MMAP_CACHE
);
1156 gi_city
= GeoIP_open_type(GEOIP_CITY_EDITION_REV1
,
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
);
1173 xfree(cfg
.whois_port
);
1185 xfree(path_city_db
);
1186 if (path_country_db
)
1187 xfree(path_country_db
);