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, astraceroute was
12 * written from scratch and does not use any libraries. Special thanks to
15 * The road must be trod, but it will be very hard. And neither strength nor
16 * wisdom will carry us far upon it. This quest may be attempted by the weak
17 * with as much hope as the strong. Yet such is oft the course of deeds that
18 * move the wheels of the world: small hands do them because they must,
19 * while the eyes of the great are elsewhere.
21 * -- The Lord of the Rings, Elrond, Chapter 'The Council of Elrond'.
23 * astraceroute includes GeoLite data created by MaxMind, available from
24 * http://www.maxmind.com/. On Debian you need libgeoip-dev, libgeoip1 and
25 * geoip-database-contrib.
34 #include <sys/types.h>
36 #include <sys/socket.h>
39 #include <asm/byteorder.h>
40 #include <linux/tcp.h>
41 #include <netinet/ip.h>
42 #include <netinet/ip6.h>
43 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <linux/if_ether.h>
48 #include <linux/icmp.h>
49 #include <linux/icmpv6.h>
51 #include <GeoIPCity.h>
66 #define WHOIS_SERVER_SOURCE "/etc/netsniff-ng/whois.conf"
77 int syn
, ack
, ecn
, fin
, psh
, rst
, urg
;
86 volatile sig_atomic_t sigint
= 0;
88 static int show_pkt
= 0;
90 static GeoIP
*gi_country
= NULL
;
91 static GeoIP
*gi_city
= NULL
;
93 static const char *short_options
= "H:p:nNf:m:i:d:q:x:SAEFPURt:Gl:w:W:hv46X:ZLK";
95 static struct option long_options
[] = {
96 {"host", required_argument
, 0, 'H'},
97 {"port", required_argument
, 0, 'p'},
98 {"init-ttl", required_argument
, 0, 'f'},
99 {"max-ttl", required_argument
, 0, 'm'},
100 {"numeric", no_argument
, 0, 'n'},
101 {"dns", no_argument
, 0, 'N'},
102 {"ipv4", no_argument
, 0, '4'},
103 {"ipv6", no_argument
, 0, '6'},
104 {"dev", required_argument
, 0, 'd'},
105 {"num-probes", required_argument
, 0, 'q'},
106 {"timeout", required_argument
, 0, 'x'},
107 {"syn", no_argument
, 0, 'S'},
108 {"ack", no_argument
, 0, 'A'},
109 {"urg", no_argument
, 0, 'U'},
110 {"fin", no_argument
, 0, 'F'},
111 {"psh", no_argument
, 0, 'P'},
112 {"rst", no_argument
, 0, 'R'},
113 {"ecn-syn", no_argument
, 0, 'E'},
114 {"tos", required_argument
, 0, 't'},
115 {"payload", required_argument
, 0, 'X'},
116 {"show-packet", no_argument
, 0, 'Z'},
117 {"nofrag", no_argument
, 0, 'G'},
118 {"totlen", required_argument
, 0, 'l'},
119 {"whois", required_argument
, 0, 'w'},
120 {"wport", required_argument
, 0, 'W'},
121 {"city-db", required_argument
, 0, 'L'},
122 {"country-db", required_argument
, 0, 'K'},
123 {"version", no_argument
, 0, 'v'},
124 {"help", no_argument
, 0, 'h'},
128 static struct sock_filter ipv4_icmp_type_11
[] = {
130 { 0x28, 0, 0, 0x0000000c },
131 /* (001) jeq #0x800 jt 2 jf 10 */
132 { 0x15, 0, 8, 0x00000800 },
134 { 0x30, 0, 0, 0x00000017 },
135 /* (003) jeq #0x1 jt 4 jf 10 */
136 { 0x15, 0, 6, 0x00000001 },
138 { 0x28, 0, 0, 0x00000014 },
139 /* (005) jset #0x1fff jt 10 jf 6 */
140 { 0x45, 4, 0, 0x00001fff },
141 /* (006) ldxb 4*([14]&0xf) */
142 { 0xb1, 0, 0, 0x0000000e },
143 /* (007) ldb [x + 14] */
144 { 0x50, 0, 0, 0x0000000e },
145 /* (008) jeq #0xb jt 9 jf 10 */
146 { 0x15, 0, 1, 0x0000000b },
147 /* (009) ret #65535 */
148 { 0x06, 0, 0, 0xffffffff },
150 { 0x06, 0, 0, 0x00000000 },
153 static struct sock_filter ipv6_icmp6_type_3
[] = {
155 { 0x28, 0, 0, 0x0000000c },
156 /* (001) jeq #0x86dd jt 2 jf 7 */
157 { 0x15, 0, 5, 0x000086dd },
159 { 0x30, 0, 0, 0x00000014 },
160 /* (003) jeq #0x3a jt 4 jf 7 */
161 { 0x15, 0, 3, 0x0000003a },
163 { 0x30, 0, 0, 0x00000036 },
164 /* (005) jeq #0x3 jt 6 jf 7 */
165 { 0x15, 0, 1, 0x00000003 },
166 /* (006) ret #65535 */
167 { 0x06, 0, 0, 0xffffffff },
169 { 0x06, 0, 0, 0x00000000 },
172 #define PKT_NOT_FOR_US 0
175 static inline const char *make_n_a(const char *p
)
180 static void signal_handler(int number
)
191 static void header(void)
193 printf("%s%s%s\n", colorize_start(bold
), "astraceroute "
194 VERSION_STRING
, colorize_end());
197 static void help(void)
200 printf("\nastraceroute %s, Autonomous System (AS) trace route utility\n",
202 printf("http://www.netsniff-ng.org\n\n");
203 printf("Usage: astraceroute [options]\n");
204 printf("Options:\n");
205 printf(" -H|--host <host> Host/IPv4/IPv6 to lookup AS route to\n");
206 printf(" -p|--port <port> Hosts port to lookup AS route to\n");
207 printf(" -i|-d|--dev <device> Networking device, i.e. eth0\n");
208 printf(" -4|--ipv4 Use IPv4 requests (default)\n");
209 printf(" -6|--ipv6 Use IPv6 requests\n");
210 printf(" -n|--numeric Do not do reverse DNS lookup for hops\n");
211 printf(" -N|--dns Do a reverse DNS lookup for hops\n");
212 printf(" -f|--init-ttl <ttl> Set initial TTL\n");
213 printf(" -m|--max-ttl <ttl> Set maximum TTL (default: 30)\n");
214 printf(" -q|--num-probes <num> Number of max probes for each hop (default: 3)\n");
215 printf(" -x|--timeout <sec> Probe response timeout in sec (default: 3)\n");
216 printf(" -S|--syn Set TCP SYN flag in packets\n");
217 printf(" -A|--ack Set TCP ACK flag in packets\n");
218 printf(" -F|--fin Set TCP FIN flag in packets\n");
219 printf(" -P|--psh Set TCP PSH flag in packets\n");
220 printf(" -U|--urg Set TCP URG flag in packets\n");
221 printf(" -R|--rst Set TCP RST flag in packets\n");
222 printf(" -E|--ecn-syn Send ECN SYN packets (RFC3168)\n");
223 printf(" -t|--tos <tos> Set the IP TOS field\n");
224 printf(" -G|--nofrag Set do not fragment bit\n");
225 printf(" -X|--payload <string> Specify a payload string to test DPIs\n");
226 printf(" -Z|--show-packet Show returned packet on each hop\n");
227 printf(" -l|--totlen <len> Specify total packet len\n");
228 printf(" -w|--whois <server> Use a different AS whois DB server\n");
229 printf(" (default: /etc/netsniff-ng/whois.conf)\n");
230 printf(" -W|--wport <port> Use a different port to AS whois server\n");
231 printf(" (default: /etc/netsniff-ng/whois.conf)\n");
232 printf(" --city-db <path> Specifiy path for geoip city database\n");
233 printf(" --country-db <path> Specifiy path for geoip country database\n");
234 printf(" -v|--version Print version\n");
235 printf(" -h|--help Print this help\n");
237 printf("Examples:\n");
238 printf(" IPv4 trace of AS with TCP SYN probe (this will most-likely pass):\n");
239 printf(" astraceroute -i eth0 -N -S -H netsniff-ng.org\n");
240 printf(" IPv4 trace of AS with TCP ECN SYN probe:\n");
241 printf(" astraceroute -i eth0 -N -E -H netsniff-ng.org\n");
242 printf(" IPv4 trace of AS with TCP FIN probe:\n");
243 printf(" astraceroute -i eth0 -N -F -H netsniff-ng.org\n");
244 printf(" IPv4 trace of AS with Xmas probe:\n");
245 printf(" astraceroute -i eth0 -N -FPU -H netsniff-ng.org\n");
246 printf(" IPv4 trace of AS with Null probe with ASCII payload:\n");
247 printf(" astraceroute -i eth0 -N -H netsniff-ng.org -X \"censor-me\" -Z\n");
248 printf(" IPv6 trace of AS up to www.6bone.net:\n");
249 printf(" astraceroute -6 -i eth0 -S -E -N -H www.6bone.net\n");
252 printf(" If the TCP probe did not give any results, then astraceroute will\n");
253 printf(" automatically probe for classic ICMP packets! To gather more\n");
254 printf(" information about astraceroute's fetched AS numbers, see i.e.\n");
255 printf(" http://bgp.he.net/AS<number>!\n");
257 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
258 printf("Copyright (C) 2011-2012 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
259 printf("Swiss federal institute of technology (ETH Zurich)\n");
260 printf("License: GNU GPL version 2\n");
261 printf("This is free software: you are free to change and redistribute it.\n");
262 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
266 static void version(void)
268 printf("\nastraceroute %s, AS trace route utility\n",
270 printf("http://www.netsniff-ng.org\n\n");
271 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
272 printf("Copyright (C) 2011-2012 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
273 printf("Swiss federal institute of technology (ETH Zurich)\n");
274 printf("License: GNU GPL version 2\n");
275 printf("This is free software: you are free to change and redistribute it.\n");
276 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
280 static inline unsigned short csum(unsigned short *buf
, int nwords
)
284 for (sum
= 0; nwords
> 0; nwords
--)
286 sum
= (sum
>> 16) + (sum
& 0xffff);
292 static void assemble_data(uint8_t *packet
, size_t len
, const char *payload
)
296 if (payload
== NULL
) {
297 for (i
= 0; i
< len
; ++i
)
298 packet
[i
] = (uint8_t) mt_rand_int32();
300 int lmin
= min(len
, strlen(payload
));
301 for (i
= 0; i
< lmin
; ++i
)
302 packet
[i
] = (uint8_t) payload
[i
];
303 for (i
= lmin
; i
< len
; ++i
)
304 packet
[i
] = (uint8_t) mt_rand_int32();
308 static void assemble_icmp4(uint8_t *packet
, size_t len
)
310 struct icmphdr
*icmph
= (struct icmphdr
*) packet
;
312 bug_on(len
< sizeof(struct icmphdr
));
314 icmph
->type
= ICMP_ECHO
;
319 static void assemble_icmp6(uint8_t *packet
, size_t len
)
321 struct icmp6hdr
*icmp6h
= (struct icmp6hdr
*) packet
;
323 bug_on(len
< sizeof(struct icmp6hdr
));
325 icmp6h
->icmp6_type
= ICMPV6_ECHO_REQUEST
;
326 icmp6h
->icmp6_code
= 0;
327 icmp6h
->icmp6_cksum
= 0;
330 static void assemble_tcp(uint8_t *packet
, size_t len
, int syn
, int ack
,
331 int urg
, int fin
, int rst
, int psh
, int ecn
, int dport
)
333 struct tcphdr
*tcph
= (struct tcphdr
*) packet
;
335 bug_on(len
< sizeof(struct tcphdr
));
337 tcph
->source
= htons((uint16_t) mt_rand_int32());
338 tcph
->dest
= htons((uint16_t) dport
);
339 tcph
->seq
= htonl(mt_rand_int32());
340 tcph
->ack_seq
= (!!ack
? htonl(mt_rand_int32()) : 0);
350 tcph
->window
= htons((uint16_t) (100 + (mt_rand_int32() % 65435)));
352 tcph
->urg_ptr
= (!!urg
? htons((uint16_t) mt_rand_int32()) : 0);
355 static int assemble_ipv4_tcp(uint8_t *packet
, size_t len
, int ttl
,
356 int tos
, const struct sockaddr
*dst
,
357 const struct sockaddr
*src
, int syn
, int ack
,
358 int urg
, int fin
, int rst
, int psh
, int ecn
,
359 int nofrag
, int dport
, const char *payload
)
361 struct iphdr
*iph
= (struct iphdr
*) packet
;
365 bug_on(!src
|| !dst
);
366 bug_on(src
->sa_family
!= PF_INET
|| dst
->sa_family
!= PF_INET
);
367 bug_on(len
< sizeof(*iph
) + sizeof(struct tcphdr
));
371 iph
->tos
= (uint8_t) tos
;
372 iph
->tot_len
= htons((uint16_t) len
);
373 iph
->id
= htons((uint16_t) mt_rand_int32());
374 iph
->frag_off
= nofrag
? IP_DF
: 0;
375 iph
->ttl
= (uint8_t) ttl
;
376 iph
->protocol
= 6; /* TCP */
377 iph
->saddr
= ((const struct sockaddr_in
*) src
)->sin_addr
.s_addr
;
378 iph
->daddr
= ((const struct sockaddr_in
*) dst
)->sin_addr
.s_addr
;
380 data
= packet
+ sizeof(*iph
);
381 data_len
= len
- sizeof(*iph
);
382 assemble_tcp(data
, data_len
, syn
, ack
, urg
, fin
, rst
, psh
, ecn
, dport
);
384 data
= packet
+ sizeof(*iph
) + sizeof(struct tcphdr
);
385 data_len
= len
- sizeof(*iph
) - sizeof(struct tcphdr
);
386 assemble_data(data
, data_len
, payload
);
388 iph
->check
= csum((unsigned short *) packet
, ntohs(iph
->tot_len
) >> 1);
390 return ntohs(iph
->id
);
393 static int assemble_ipv6_tcp(uint8_t *packet
, size_t len
, int ttl
,
394 const struct sockaddr
*dst
,
395 const struct sockaddr
*src
, int syn
, int ack
,
396 int urg
, int fin
, int rst
, int psh
, int ecn
,
397 int dport
, const char *payload
)
399 struct ip6_hdr
*ip6h
= (struct ip6_hdr
*) packet
;
403 bug_on(!src
|| !dst
);
404 bug_on(src
->sa_family
!= PF_INET6
|| dst
->sa_family
!= PF_INET6
);
405 bug_on(len
< sizeof(*ip6h
) + sizeof(struct tcphdr
));
407 ip6h
->ip6_flow
= htonl(mt_rand_int32() & 0x000fffff);
408 ip6h
->ip6_vfc
= 0x60;
409 ip6h
->ip6_plen
= htons((uint16_t) len
- sizeof(*ip6h
));
410 ip6h
->ip6_nxt
= 6; /* TCP */
411 ip6h
->ip6_hlim
= (uint8_t) ttl
;
412 memcpy(&ip6h
->ip6_src
, &(((const struct sockaddr_in6
*)
413 src
)->sin6_addr
), sizeof(ip6h
->ip6_src
));
414 memcpy(&ip6h
->ip6_dst
, &(((const struct sockaddr_in6
*)
415 dst
)->sin6_addr
), sizeof(ip6h
->ip6_dst
));
417 data
= packet
+ sizeof(*ip6h
);
418 data_len
= len
- sizeof(*ip6h
);
419 assemble_tcp(data
, data_len
, syn
, ack
, urg
, fin
, rst
, psh
, ecn
, dport
);
421 data
= packet
+ sizeof(*ip6h
) + sizeof(struct tcphdr
);
422 data_len
= len
- sizeof(*ip6h
) - sizeof(struct tcphdr
);
423 assemble_data(data
, data_len
, payload
);
425 return ntohl(ip6h
->ip6_flow
) & 0x000fffff;
428 static int assemble_ipv6_icmp6(uint8_t *packet
, size_t len
, int ttl
,
429 const struct sockaddr
*dst
,
430 const struct sockaddr
*src
,
433 struct ip6_hdr
*ip6h
= (struct ip6_hdr
*) packet
;
437 bug_on(!src
|| !dst
);
438 bug_on(src
->sa_family
!= PF_INET6
|| dst
->sa_family
!= PF_INET6
);
439 bug_on(len
< sizeof(*ip6h
) + sizeof(struct icmp6hdr
));
441 ip6h
->ip6_flow
= htonl(mt_rand_int32() & 0x000fffff);
442 ip6h
->ip6_vfc
= 0x60;
443 ip6h
->ip6_plen
= htons((uint16_t) len
- sizeof(*ip6h
));
444 ip6h
->ip6_nxt
= 0x3a; /* ICMP6 */
445 ip6h
->ip6_hlim
= (uint8_t) ttl
;
446 memcpy(&ip6h
->ip6_src
, &(((const struct sockaddr_in6
*)
447 src
)->sin6_addr
), sizeof(ip6h
->ip6_src
));
448 memcpy(&ip6h
->ip6_dst
, &(((const struct sockaddr_in6
*)
449 dst
)->sin6_addr
), sizeof(ip6h
->ip6_dst
));
451 data
= packet
+ sizeof(*ip6h
);
452 data_len
= len
- sizeof(*ip6h
);
453 assemble_icmp6(data
, data_len
);
455 data
= packet
+ sizeof(*ip6h
) + sizeof(struct icmp6hdr
);
456 data_len
= len
- sizeof(*ip6h
) - sizeof(struct icmp6hdr
);
457 assemble_data(data
, data_len
, payload
);
459 return ntohl(ip6h
->ip6_flow
) & 0x000fffff;
462 static int assemble_ipv4_icmp4(uint8_t *packet
, size_t len
, int ttl
,
463 int tos
, const struct sockaddr
*dst
,
464 const struct sockaddr
*src
, int nofrag
,
467 struct iphdr
*iph
= (struct iphdr
*) packet
;
471 bug_on(!src
|| !dst
);
472 bug_on(src
->sa_family
!= PF_INET
|| dst
->sa_family
!= PF_INET
);
473 bug_on(len
< sizeof(struct iphdr
) + sizeof(struct icmphdr
));
478 iph
->tot_len
= htons((uint16_t) len
);
479 iph
->id
= htons((uint16_t) mt_rand_int32());
480 iph
->frag_off
= nofrag
? IP_DF
: 0;
481 iph
->ttl
= (uint8_t) ttl
;
482 iph
->protocol
= 1; /* ICMP4 */
483 iph
->saddr
= ((const struct sockaddr_in
*) src
)->sin_addr
.s_addr
;
484 iph
->daddr
= ((const struct sockaddr_in
*) dst
)->sin_addr
.s_addr
;
486 data
= packet
+ sizeof(*iph
);
487 data_len
= len
- sizeof(*iph
);
488 assemble_icmp4(data
, data_len
);
490 data
= packet
+ sizeof(*iph
) + sizeof(struct icmphdr
);
491 data_len
= len
- sizeof(*iph
) - sizeof(struct icmphdr
);
492 assemble_data(data
, data_len
, payload
);
494 iph
->check
= csum((unsigned short *) packet
, ntohs(iph
->tot_len
) >> 1);
496 return ntohs(iph
->id
);
499 static int assemble_packet_or_die(uint8_t *packet
, size_t len
,
501 const struct ash_cfg
*cfg
,
502 const struct sockaddr
*dst
,
503 const struct sockaddr
*src
)
507 return assemble_ipv4_icmp4(packet
, len
, ttl
, cfg
->tos
,
508 dst
, src
, cfg
->nofrag
,
511 return assemble_ipv6_icmp6(packet
, len
, ttl
, dst
, src
,
516 return assemble_ipv4_tcp(packet
, len
, ttl
, cfg
->tos
,
517 dst
, src
, cfg
->syn
, cfg
->ack
,
518 cfg
->urg
, cfg
->fin
, cfg
->rst
,
520 cfg
->nofrag
, atoi(cfg
->port
),
523 return assemble_ipv6_tcp(packet
, len
, ttl
, dst
, src
,
524 cfg
->syn
, cfg
->ack
, cfg
->urg
,
525 cfg
->fin
, cfg
->rst
, cfg
->psh
,
526 cfg
->ecn
, atoi(cfg
->port
),
534 static int handle_ipv4_icmp(uint8_t *packet
, size_t len
, int ttl
, int id
,
535 const struct sockaddr
*own
, int dns_resolv
)
538 struct iphdr
*iph
= (struct iphdr
*) packet
;
539 struct iphdr
*iph_inner
;
540 struct icmphdr
*icmph
;
542 struct sockaddr_in sa
;
546 if (iph
->protocol
!= 1)
547 return PKT_NOT_FOR_US
;
548 if (iph
->daddr
!= ((const struct sockaddr_in
*) own
)->sin_addr
.s_addr
)
549 return PKT_NOT_FOR_US
;
551 icmph
= (struct icmphdr
*) (packet
+ sizeof(struct iphdr
));
552 if (icmph
->type
!= ICMP_TIME_EXCEEDED
)
553 return PKT_NOT_FOR_US
;
554 if (icmph
->code
!= ICMP_EXC_TTL
)
555 return PKT_NOT_FOR_US
;
557 iph_inner
= (struct iphdr
*) (packet
+ sizeof(struct iphdr
) +
558 sizeof(struct icmphdr
));
559 if (ntohs(iph_inner
->id
) != id
)
560 return PKT_NOT_FOR_US
;
562 hbuff
= xzmalloc(NI_MAXHOST
);
564 memset(&sa
, 0, sizeof(sa
));
565 sa
.sin_family
= PF_INET
;
566 sa
.sin_addr
.s_addr
= iph
->saddr
;
568 getnameinfo((struct sockaddr
*) &sa
, sizeof(sa
), hbuff
, NI_MAXHOST
,
569 NULL
, 0, NI_NUMERICHOST
);
571 memset(&rec
, 0, sizeof(rec
));
572 ret
= aslookup(hbuff
, &rec
);
574 panic("AS lookup error %d!\n", ret
);
576 gir
= GeoIP_record_by_ipnum(gi_city
, ntohl(iph
->saddr
));
578 if (strlen(rec
.country
) > 0 && gir
) {
579 const char *city
= make_n_a(gir
->city
);
581 printf("%s in AS%s (%s, %s, %s, %f, %f), %s %s (%s), %s", hbuff
,
582 rec
.number
, rec
.country
,
583 GeoIP_country_name_by_ipnum(gi_country
, ntohl(iph
->saddr
)),
584 city
, gir
->latitude
, gir
->longitude
,
585 rec
.prefix
, rec
.registry
, rec
.since
, rec
.name
);
586 } else if (strlen(rec
.country
) > 0 && !gir
) {
587 printf("%s in AS%s (%s, %s), %s %s (%s), %s", hbuff
,
588 rec
.number
, rec
.country
,
589 GeoIP_country_name_by_ipnum(gi_country
, ntohl(iph
->saddr
)),
590 rec
.prefix
, rec
.registry
, rec
.since
, rec
.name
);
592 printf("%s in unkown AS", hbuff
);
595 struct hostent
*hent
= gethostbyaddr(&sa
.sin_addr
,
599 if (strlen(rec
.country
) > 0 && gir
) {
600 const char *city
= make_n_a(gir
->city
);
601 printf("%s (%s) in AS%s (%s, %s, %s, %f, %f), %s %s (%s), %s",
602 (hent
? hent
->h_name
: hbuff
), hbuff
,
603 rec
.number
, rec
.country
,
604 GeoIP_country_name_by_ipnum(gi_country
, ntohl(iph
->saddr
)),
605 city
, gir
->latitude
, gir
->longitude
,
606 rec
.prefix
, rec
.registry
,
607 rec
.since
, rec
.name
);
608 } else if (strlen(rec
.country
) > 0 && !gir
) {
609 printf("%s (%s) in AS%s (%s, %s), %s %s (%s), %s",
610 (hent
? hent
->h_name
: hbuff
), hbuff
,
611 rec
.number
, rec
.country
,
612 GeoIP_country_name_by_ipnum(gi_country
, ntohl(iph
->saddr
)),
613 rec
.prefix
, rec
.registry
,
614 rec
.since
, rec
.name
);
616 printf("%s (%s) in unkown AS",
617 (hent
? hent
->h_name
: hbuff
), hbuff
);
626 static int handle_ipv6_icmp(uint8_t *packet
, size_t len
, int ttl
, int id
,
627 const struct sockaddr
*own
, int dns_resolv
)
630 struct ip6_hdr
*ip6h
= (struct ip6_hdr
*) packet
;
631 struct ip6_hdr
*ip6h_inner
;
632 struct icmp6hdr
*icmp6h
;
634 struct sockaddr_in6 sa
;
638 if (ip6h
->ip6_nxt
!= 0x3a)
639 return PKT_NOT_FOR_US
;
640 if (memcmp(&ip6h
->ip6_dst
, &(((const struct sockaddr_in6
*)
641 own
)->sin6_addr
), sizeof(ip6h
->ip6_dst
)))
642 return PKT_NOT_FOR_US
;
644 icmp6h
= (struct icmp6hdr
*) (packet
+ sizeof(*ip6h
));
645 if (icmp6h
->icmp6_type
!= ICMPV6_TIME_EXCEED
)
646 return PKT_NOT_FOR_US
;
647 if (icmp6h
->icmp6_code
!= ICMPV6_EXC_HOPLIMIT
)
648 return PKT_NOT_FOR_US
;
650 ip6h_inner
= (struct ip6_hdr
*) (packet
+ sizeof(*ip6h
) + sizeof(*icmp6h
));
651 if ((ntohl(ip6h_inner
->ip6_flow
) & 0x000fffff) != id
)
652 return PKT_NOT_FOR_US
;
654 hbuff
= xzmalloc(NI_MAXHOST
);
656 memset(&sa
, 0, sizeof(sa
));
657 sa
.sin6_family
= PF_INET6
;
658 memcpy(&sa
.sin6_addr
, &ip6h
->ip6_src
, sizeof(ip6h
->ip6_src
));
660 getnameinfo((struct sockaddr
*) &sa
, sizeof(sa
), hbuff
, NI_MAXHOST
,
661 NULL
, 0, NI_NUMERICHOST
);
663 memset(&rec
, 0, sizeof(rec
));
664 ret
= aslookup(hbuff
, &rec
);
666 panic("AS lookup error %d!\n", ret
);
668 gir
= GeoIP_record_by_ipnum_v6(gi_city
, sa
.sin6_addr
);
670 if (strlen(rec
.country
) > 0 && gir
) {
671 const char *city
= make_n_a(gir
->city
);
673 printf("%s in AS%s (%s, %s, %s, %f, %f), %s %s (%s), %s", hbuff
,
674 rec
.number
, rec
.country
,
675 GeoIP_country_name_by_ipnum_v6(gi_country
, sa
.sin6_addr
),
676 city
, gir
->latitude
, gir
->longitude
,
677 rec
.prefix
, rec
.registry
, rec
.since
, rec
.name
);
678 } else if (strlen(rec
.country
) > 0 && !gir
) {
679 printf("%s in AS%s (%s, %s), %s %s (%s), %s", hbuff
,
680 rec
.number
, rec
.country
,
681 GeoIP_country_name_by_ipnum_v6(gi_country
, sa
.sin6_addr
),
682 rec
.prefix
, rec
.registry
, rec
.since
, rec
.name
);
684 printf("%s in unkown AS", hbuff
);
687 struct hostent
*hent
= gethostbyaddr(&sa
.sin6_addr
,
688 sizeof(sa
.sin6_addr
),
691 if (strlen(rec
.country
) > 0 && gir
) {
692 const char *city
= make_n_a(gir
->city
);
693 printf("%s (%s) in AS%s (%s, %s, %s, %f, %f), %s %s (%s), %s",
694 (hent
? hent
->h_name
: hbuff
), hbuff
,
695 rec
.number
, rec
.country
,
696 GeoIP_country_name_by_ipnum_v6(gi_country
, sa
.sin6_addr
),
697 city
, gir
->latitude
, gir
->longitude
,
698 rec
.prefix
, rec
.registry
,
699 rec
.since
, rec
.name
);
700 } else if (strlen(rec
.country
) > 0 && !gir
) {
701 printf("%s (%s) in AS%s (%s, %s), %s %s (%s), %s",
702 (hent
? hent
->h_name
: hbuff
), hbuff
,
703 rec
.number
, rec
.country
,
704 GeoIP_country_name_by_ipnum_v6(gi_country
, sa
.sin6_addr
),
705 rec
.prefix
, rec
.registry
,
706 rec
.since
, rec
.name
);
708 printf("%s (%s) in unkown AS",
709 (hent
? hent
->h_name
: hbuff
), hbuff
);
718 static int handle_packet(uint8_t *packet
, size_t len
, int ip
, int ttl
, int id
,
719 struct sockaddr
*own
, int dns_resolv
)
722 return handle_ipv4_icmp(packet
, len
, ttl
, id
, own
, dns_resolv
);
724 return handle_ipv6_icmp(packet
, len
, ttl
, id
, own
, dns_resolv
);
727 static int do_trace(const struct ash_cfg
*cfg
)
729 int ttl
, query
, fd
= -1, one
= 1, ret
, fd_cap
, ifindex
;
730 int is_okay
= 0, id
, timeout_poll
;
731 uint8_t *packet
, *packet_rcv
;
732 ssize_t err
, real_len
, sd_len
;
734 struct addrinfo hints
, *ahead
, *ai
;
735 char *hbuff1
, *hbuff2
;
736 struct sockaddr_storage ss
, sd
;
737 struct sock_fprog bpf_ops
;
738 struct ring dummy_ring
;
741 mt_init_by_random_device();
743 memset(&hints
, 0, sizeof(hints
));
744 hints
.ai_family
= PF_UNSPEC
;
745 hints
.ai_socktype
= SOCK_STREAM
;
746 hints
.ai_protocol
= IPPROTO_TCP
;
747 hints
.ai_flags
= AI_NUMERICSERV
;
749 ret
= getaddrinfo(cfg
->host
, cfg
->port
, &hints
, &ahead
);
751 whine("Cannot get address info!\n");
755 for (ai
= ahead
; ai
!= NULL
&& fd
< 0; ai
= ai
->ai_next
) {
756 if (!((ai
->ai_family
== PF_INET6
&& cfg
->ip
== 6) ||
757 (ai
->ai_family
== PF_INET
&& cfg
->ip
== 4)))
759 fd
= socket(ai
->ai_family
, SOCK_RAW
, IPPROTO_RAW
);
762 fd_cap
= pf_socket();
764 memset(&ss
, 0, sizeof(ss
));
765 ret
= device_address(cfg
->dev
, ai
->ai_family
, &ss
);
767 panic("Cannot get own device address!\n");
769 ret
= bind(fd
, (struct sockaddr
*) &ss
, sizeof(ss
));
771 panic("Cannot bind socket!\n");
773 memset(&sd
, 0, sizeof(sd
));
774 memcpy(&sd
, ai
->ai_addr
, ai
->ai_addrlen
);
775 if (ai
->ai_family
== PF_INET6
) {
776 struct sockaddr_in6
*sd6
= (struct sockaddr_in6
*) &sd
;
777 sd6
->sin6_port
= htons(0);
779 sd_len
= ai
->ai_addrlen
;
787 whine("Cannot create socket! Does remote support IPv%d?!\n",
794 if (len
< sizeof(struct iphdr
) + sizeof(struct tcphdr
)) {
795 len
= sizeof(struct iphdr
) + sizeof(struct tcphdr
);
797 len
+= strlen(cfg
->payload
);
800 if (len
< sizeof(struct ip6_hdr
) + sizeof(struct tcphdr
)) {
801 len
= sizeof(struct ip6_hdr
) + sizeof(struct tcphdr
);
803 len
+= strlen(cfg
->payload
);
807 if (len
>= device_mtu(cfg
->dev
))
808 panic("Packet len exceeds device MTU!\n");
810 packet
= xmalloc(len
);
811 len_rcv
= device_mtu(cfg
->dev
);
812 packet_rcv
= xmalloc(len_rcv
);
814 hbuff1
= xzmalloc(256);
815 getnameinfo((struct sockaddr
*) &sd
, sizeof(sd
), hbuff1
, 256,
816 NULL
, 0, NI_NUMERICHOST
);
818 hbuff2
= xzmalloc(256);
819 getnameinfo((struct sockaddr
*) &ss
, sizeof(ss
), hbuff2
, 256,
820 NULL
, 0, NI_NUMERICHOST
);
822 ret
= setsockopt(fd
, cfg
->ip
== 4 ? IPPROTO_IP
: IPPROTO_IPV6
,
823 IP_HDRINCL
, &one
, sizeof(one
));
825 panic("Kernel does not support IP_HDRINCL!\n");
827 printf("AS path IPv%d TCP trace from %s to %s:%s (%s) with len %zu "
828 "Bytes, %u max hops\n", cfg
->ip
, hbuff2
, hbuff1
, cfg
->port
,
829 cfg
->host
, len
, cfg
->max_ttl
);
831 printf("Using flags SYN:%d,ACK:%d,ECN:%d,FIN:%d,PSH:%d,RST:%d,URG:%d\n",
832 cfg
->syn
, cfg
->ack
, cfg
->ecn
, cfg
->fin
, cfg
->psh
, cfg
->rst
,
836 printf("With payload: \'%s\'\n", cfg
->payload
);
843 hbuff1
= hbuff2
= NULL
;
845 enable_kernel_bpf_jit_compiler();
847 memset(&bpf_ops
, 0, sizeof(bpf_ops
));
849 bpf_ops
.filter
= ipv4_icmp_type_11
;
850 bpf_ops
.len
= (sizeof(ipv4_icmp_type_11
) /
851 sizeof(ipv4_icmp_type_11
[0]));
853 bpf_ops
.filter
= ipv6_icmp6_type_3
;
854 bpf_ops
.len
= (sizeof(ipv6_icmp6_type_3
) /
855 sizeof(ipv6_icmp6_type_3
[0]));
858 bpf_attach_to_sock(fd_cap
, &bpf_ops
);
859 ifindex
= device_ifindex(cfg
->dev
);
860 bind_rx_ring(fd_cap
, &dummy_ring
, ifindex
);
861 prepare_polling(fd_cap
, &pfd
);
863 timeout_poll
= (cfg
->timeout
> 0 ? cfg
->timeout
: 3) * 1000;
865 for (ttl
= cfg
->init_ttl
; ttl
<= cfg
->max_ttl
; ++ttl
) {
869 if ((ttl
== cfg
->init_ttl
&& !show_pkt
) ||
870 (ttl
> cfg
->init_ttl
)) {
871 printf("%2d: ", ttl
);
875 for (query
= 0; query
< cfg
->queries
&& !is_okay
; ++query
) {
876 id
= assemble_packet_or_die(packet
, len
, ttl
, icmp
, cfg
,
877 (struct sockaddr
*) &sd
,
878 (struct sockaddr
*) &ss
);
879 if (ttl
== cfg
->init_ttl
&& query
== 0 && show_pkt
) {
880 struct pkt_buff
*pkt
;
882 printf("Original packet:\n");
884 pkt
= pkt_alloc(packet
, len
);
889 printf("\n%2d: ", ttl
);
893 err
= sendto(fd
, packet
, len
, 0, (struct sockaddr
*) &sd
,
896 panic("sendto failed: %s\n", strerror(errno
));
898 err
= poll(&pfd
, 1, timeout_poll
);
899 if (err
> 0 && pfd
.revents
& POLLIN
) {
900 real_len
= recvfrom(fd_cap
, packet_rcv
, len_rcv
,
902 if (real_len
< sizeof(struct ethhdr
) +
903 (cfg
->ip
? sizeof(struct iphdr
) +
904 sizeof(struct icmphdr
) :
905 sizeof(struct ip6_hdr
) +
906 sizeof(struct icmp6hdr
)))
909 is_okay
= handle_packet(packet_rcv
+ sizeof(struct ethhdr
),
910 real_len
- sizeof(struct ethhdr
),
912 (struct sockaddr
*) &ss
,
914 if (is_okay
&& show_pkt
) {
915 struct pkt_buff
*pkt
;
917 printf("\n Received packet:\n");
919 pkt
= pkt_alloc(packet_rcv
, real_len
);
931 if (is_okay
== 0 && icmp
== 0) {
949 static void parse_whois_or_die(struct ash_cfg
*cfg
)
953 char tmp
[512], *ptr
, *ptr2
;
955 fd
= open_or_die(WHOIS_SERVER_SOURCE
, O_RDONLY
);
957 while ((ret
= read(fd
, tmp
, sizeof(tmp
))) > 0) {
958 tmp
[sizeof(tmp
) - 1] = 0;
961 while (*ptr2
!= ' ' && ptr2
< &tmp
[sizeof(tmp
) - 1])
964 panic("Parser error!\n");
966 cfg
->whois
= xstrdup(ptr
);
968 if (ptr
>= &tmp
[sizeof(tmp
) - 1])
969 panic("Parser error!\n");
971 ptr
[strlen(ptr
) - 1] = 0;
972 cfg
->whois_port
= xstrdup(ptr
);
979 int main(int argc
, char **argv
)
981 int c
, opt_index
, ret
;
983 char *path_city_db
= NULL
, *path_country_db
= NULL
;
985 check_for_root_maybe_die();
987 memset(&cfg
, 0, sizeof(cfg
));
994 cfg
.dev
= xstrdup("eth0");
995 cfg
.port
= xstrdup("80");
997 while ((c
= getopt_long(argc
, argv
, short_options
, long_options
,
998 &opt_index
)) != EOF
) {
1007 cfg
.host
= xstrdup(optarg
);
1012 cfg
.port
= xstrdup(optarg
);
1030 cfg
.init_ttl
= atoi(optarg
);
1031 if (cfg
.init_ttl
<= 0)
1035 cfg
.max_ttl
= atoi(optarg
);
1036 if (cfg
.max_ttl
<= 0)
1043 cfg
.dev
= xstrdup(optarg
);
1046 cfg
.queries
= atoi(optarg
);
1047 if (cfg
.queries
<= 0)
1051 cfg
.timeout
= atoi(optarg
);
1052 if (cfg
.timeout
<= 0)
1078 cfg
.tos
= atoi(optarg
);
1086 cfg
.payload
= xstrdup(optarg
);
1089 cfg
.totlen
= atoi(optarg
);
1090 if (cfg
.totlen
<= 0)
1094 cfg
.whois
= xstrdup(optarg
);
1097 cfg
.whois_port
= xstrdup(optarg
);
1100 path_city_db
= xstrdup(optarg
);
1103 path_country_db
= xstrdup(optarg
);
1122 panic("Option -%c requires an argument!\n",
1125 if (isprint(optopt
))
1126 whine("Unknown option character "
1127 "`0x%X\'!\n", optopt
);
1136 !cfg
.host
|| !cfg
.port
||
1137 cfg
.init_ttl
> cfg
.max_ttl
||
1138 cfg
.init_ttl
> MAXTTL
||
1139 cfg
.max_ttl
> MAXTTL
)
1142 if (!device_up_and_running(cfg
.dev
))
1143 panic("Networking device not up and running!\n");
1144 if (!cfg
.whois
|| !cfg
.whois_port
)
1145 parse_whois_or_die(&cfg
);
1146 if (device_mtu(cfg
.dev
) <= cfg
.totlen
)
1147 panic("Packet larger than device MTU!\n");
1149 register_signal(SIGHUP
, signal_handler
);
1155 ret
= aslookup_prepare(cfg
.whois
, cfg
.whois_port
);
1157 panic("Cannot resolve whois server!\n");
1159 if (path_country_db
)
1160 gi_country
= GeoIP_open(path_country_db
, GEOIP_MMAP_CACHE
);
1162 gi_country
= GeoIP_open_type(cfg
.ip
== 4 ?
1163 GEOIP_COUNTRY_EDITION
:
1164 GEOIP_COUNTRY_EDITION_V6
,
1168 gi_city
= GeoIP_open(path_city_db
, GEOIP_MMAP_CACHE
);
1170 gi_city
= GeoIP_open_type(cfg
.ip
== 4 ?
1171 GEOIP_CITY_EDITION_REV1
:
1172 GEOIP_CITY_EDITION_REV1_V6
,
1175 if (!gi_country
|| !gi_city
)
1176 panic("Cannot open GeoIP database! Wrong path?!\n");
1178 GeoIP_set_charset(gi_country
, GEOIP_CHARSET_UTF8
);
1179 GeoIP_set_charset(gi_city
, GEOIP_CHARSET_UTF8
);
1181 ret
= do_trace(&cfg
);
1183 GeoIP_delete(gi_city
);
1184 GeoIP_delete(gi_country
);
1188 free(cfg
.whois_port
);
1195 free(path_country_db
);