2 * netsniff-ng - the packet sniffing beast
3 * Copyright 2011 - 2013 Daniel Borkmann.
4 * Subject to the GPL, version 2.
8 #define _DEFAULT_SOURCE
15 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <sys/fsuid.h>
22 #include <asm/byteorder.h>
23 #include <linux/tcp.h>
24 #include <netinet/if_ether.h>
25 #include <netinet/ip.h>
26 #include <netinet/ip6.h>
27 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <linux/icmp.h>
33 #include <linux/icmpv6.h>
51 char *host
, *port
, *dev
, *payload
, *bind_addr
;
52 size_t totlen
, rcvlen
;
54 int init_ttl
, max_ttl
, dport
, queries
, timeout
;
55 int syn
, ack
, ecn
, fin
, psh
, rst
, urg
, tos
, nofrag
, proto
;
56 bool do_geo_lookup
, do_dns_resolution
, do_show_packet
;
60 int (*assembler
)(uint8_t *packet
, size_t len
, int ttl
, int proto
,
61 const struct ctx
*ctx
, const struct sockaddr
*dst
,
62 const struct sockaddr
*src
);
63 const struct sock_filter
*filter
;
65 size_t min_len_tcp
, min_len_icmp
;
66 int (*check
)(uint8_t *packet
, size_t len
, int ttl
, int id
,
67 const struct sockaddr
*src
);
68 void (*handler
)(uint8_t *packet
, size_t len
, bool do_dns_resolution
,
72 static sig_atomic_t sigint
= 0;
74 static int assemble_ipv4(uint8_t *packet
, size_t len
, int ttl
, int proto
,
75 const struct ctx
*ctx
, const struct sockaddr
*dst
,
76 const struct sockaddr
*src
);
77 static int check_ipv4(uint8_t *packet
, size_t len
, int ttl
, int id
,
78 const struct sockaddr
*ss
);
79 static void handle_ipv4(uint8_t *packet
, size_t len
, bool do_dns_resolution
,
81 static int assemble_ipv6(uint8_t *packet
, size_t len
, int ttl
, int proto
,
82 const struct ctx
*ctx
, const struct sockaddr
*dst
,
83 const struct sockaddr
*src
);
84 static int check_ipv6(uint8_t *packet
, size_t len
, int ttl
, int id
,
85 const struct sockaddr
*ss
);
86 static void handle_ipv6(uint8_t *packet
, size_t len
, bool do_dns_resolution
,
89 static const char *short_options
= "H:p:nNf:m:b:i:d:q:x:SAEFPURt:Gl:hv46X:ZuL";
90 static const struct option long_options
[] = {
91 {"host", required_argument
, NULL
, 'H'},
92 {"port", required_argument
, NULL
, 'p'},
93 {"init-ttl", required_argument
, NULL
, 'f'},
94 {"max-ttl", required_argument
, NULL
, 'm'},
95 {"bind", required_argument
, NULL
, 'b'},
96 {"dev", required_argument
, NULL
, 'd'},
97 {"num-probes", required_argument
, NULL
, 'q'},
98 {"timeout", required_argument
, NULL
, 'x'},
99 {"tos", required_argument
, NULL
, 't'},
100 {"payload", required_argument
, NULL
, 'X'},
101 {"totlen", required_argument
, NULL
, 'l'},
102 {"numeric", no_argument
, NULL
, 'n'},
103 {"latitude", no_argument
, NULL
, 'L'},
104 {"update", no_argument
, NULL
, 'u'},
105 {"dns", no_argument
, NULL
, 'N'},
106 {"ipv4", no_argument
, NULL
, '4'},
107 {"ipv6", no_argument
, NULL
, '6'},
108 {"syn", no_argument
, NULL
, 'S'},
109 {"ack", no_argument
, NULL
, 'A'},
110 {"urg", no_argument
, NULL
, 'U'},
111 {"fin", no_argument
, NULL
, 'F'},
112 {"psh", no_argument
, NULL
, 'P'},
113 {"rst", no_argument
, NULL
, 'R'},
114 {"ecn-syn", no_argument
, NULL
, 'E'},
115 {"show-packet", no_argument
, NULL
, 'Z'},
116 {"nofrag", no_argument
, NULL
, 'G'},
117 {"version", no_argument
, NULL
, 'v'},
118 {"help", no_argument
, NULL
, 'h'},
122 static const char *copyright
=
123 "Please report bugs at https://github.com/netsniff-ng/netsniff-ng/issues\n"
124 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>\n"
125 "Swiss federal institute of technology (ETH Zurich)\n"
126 "License: GNU GPL version 2.0\n"
127 "This is free software: you are free to change and redistribute it.\n"
128 "There is NO WARRANTY, to the extent permitted by law.";
130 static const struct sock_filter ipv4_icmp_type_11
[] = {
131 { 0x28, 0, 0, 0x0000000c }, /* ldh [12] */
132 { 0x15, 0, 8, 0x00000800 }, /* jneq #0x800, drop */
133 { 0x30, 0, 0, 0x00000017 }, /* ldb [23] */
134 { 0x15, 0, 6, 0x00000001 }, /* jneq #0x1, drop */
135 { 0x28, 0, 0, 0x00000014 }, /* ldh [20] */
136 { 0x45, 4, 0, 0x00001fff }, /* jset #0x1fff, drop */
137 { 0xb1, 0, 0, 0x0000000e }, /* ldxb 4*([14]&0xf) */
138 { 0x50, 0, 0, 0x0000000e }, /* ldb [x + 14] */
139 { 0x15, 0, 1, 0x0000000b }, /* jneq #0xb, drop */
140 { 0x06, 0, 0, 0xffffffff }, /* ret #-1 */
141 { 0x06, 0, 0, 0x00000000 }, /* drop: ret #0 */
144 static const struct sock_filter ipv6_icmp6_type_3
[] = {
145 { 0x28, 0, 0, 0x0000000c }, /* ldh [12] */
146 { 0x15, 0, 5, 0x000086dd }, /* jneq #0x86dd, drop */
147 { 0x30, 0, 0, 0x00000014 }, /* ldb [20] */
148 { 0x15, 0, 3, 0x0000003a }, /* jneq #0x3a, drop */
149 { 0x30, 0, 0, 0x00000036 }, /* ldb [54] */
150 { 0x15, 0, 1, 0x00000003 }, /* jneq #0x3, drop */
151 { 0x06, 0, 0, 0xffffffff }, /* ret #-1 */
152 { 0x06, 0, 0, 0x00000000 }, /* drop: ret #0 */
155 static const struct proto_ops af_ops
[] = {
157 .assembler
= assemble_ipv4
,
158 .handler
= handle_ipv4
,
160 .filter
= ipv4_icmp_type_11
,
161 .flen
= array_size(ipv4_icmp_type_11
),
162 .min_len_tcp
= sizeof(struct iphdr
) + sizeof(struct tcphdr
),
163 .min_len_icmp
= sizeof(struct iphdr
) + sizeof(struct icmphdr
),
166 .assembler
= assemble_ipv6
,
167 .handler
= handle_ipv6
,
169 .filter
= ipv6_icmp6_type_3
,
170 .flen
= array_size(ipv6_icmp6_type_3
),
171 .min_len_tcp
= sizeof(struct ip6_hdr
) + sizeof(struct tcphdr
),
172 .min_len_icmp
= sizeof(struct ip6_hdr
) + sizeof(struct icmp6hdr
),
176 static void signal_handler(int number
)
188 static void __noreturn
help(void)
190 printf("astraceroute %s, autonomous system trace route utility\n", VERSION_STRING
);
191 puts("http://www.netsniff-ng.org\n\n"
192 "Usage: astraceroute [options]\n"
194 " -H|--host <host> Host/IPv4/IPv6 to lookup AS route to\n"
195 " -p|--port <port> Hosts port to lookup AS route to\n"
196 " -i|-d|--dev <device> Networking device, e.g. eth0\n"
197 " -b|--bind <IP> IP address to bind to, Must specify -6 for an IPv6 address\n"
198 " -f|--init-ttl <ttl> Set initial TTL\n"
199 " -m|--max-ttl <ttl> Set maximum TTL (def: 30)\n"
200 " -q|--num-probes <num> Number of max probes for each hop (def: 2)\n"
201 " -x|--timeout <sec> Probe response timeout in sec (def: 3)\n"
202 " -X|--payload <string> Specify a payload string to test DPIs\n"
203 " -l|--totlen <len> Specify total packet len\n"
204 " -4|--ipv4 Use IPv4-only requests\n"
205 " -6|--ipv6 Use IPv6-only requests\n"
206 " -n|--numeric Do not do reverse DNS lookup for hops\n"
207 " -u|--update Update GeoIP databases\n"
208 " -L|--latitude Show latitude and longitude\n"
209 " -N|--dns Do a reverse DNS lookup for hops\n"
210 " -S|--syn Set TCP SYN flag\n"
211 " -A|--ack Set TCP ACK flag\n"
212 " -F|--fin Set TCP FIN flag\n"
213 " -P|--psh Set TCP PSH flag\n"
214 " -U|--urg Set TCP URG flag\n"
215 " -R|--rst Set TCP RST flag\n"
216 " -E|--ecn-syn Send ECN SYN packets (RFC3168)\n"
217 " -t|--tos <tos> Set the IP TOS field\n"
218 " -G|--nofrag Set do not fragment bit\n"
219 " -Z|--show-packet Show returned packet on each hop\n"
220 " -v|--version Print version and exit\n"
221 " -h|--help Print this help and exit\n\n"
223 " IPv4 trace of AS with TCP SYN probe (this will most-likely pass):\n"
224 " astraceroute -i eth0 -N -S -H netsniff-ng.org\n"
225 " IPv4 trace of AS with TCP ECN SYN probe:\n"
226 " astraceroute -i eth0 -N -E -H netsniff-ng.org\n"
227 " IPv4 trace of AS with TCP FIN probe:\n"
228 " astraceroute -i eth0 -N -F -H netsniff-ng.org\n"
229 " IPv4 trace of AS with Xmas probe:\n"
230 " astraceroute -i eth0 -N -FPU -H netsniff-ng.org\n"
231 " IPv4 trace of AS with Null probe with ASCII payload:\n"
232 " astraceroute -i eth0 -N -H netsniff-ng.org -X \"censor-me\" -Z\n"
233 " IPv6 trace of AS up to www.6bone.net:\n"
234 " astraceroute -6 -i eth0 -S -E -N -H www.6bone.net\n\n"
236 " If the TCP probe did not give any results, then astraceroute will\n"
237 " automatically probe for classic ICMP packets! To gather more\n"
238 " information about astraceroute's fetched AS numbers, see e.g.\n"
239 " http://bgp.he.net/AS<number>!\n");
244 static void __noreturn
version(void)
246 printf("astraceroute %s, Git id: %s\n", VERSION_LONG
, GITVERSION
);
247 puts("autonomous system trace route utility\n"
248 "http://www.netsniff-ng.org\n");
253 static void __assemble_data(uint8_t *packet
, size_t len
, const char *payload
)
257 if (payload
== NULL
) {
258 for (i
= 0; i
< len
; ++i
)
259 packet
[i
] = (uint8_t) rand();
261 size_t lmin
= min(len
, strlen(payload
));
263 for (i
= 0; i
< lmin
; ++i
)
264 packet
[i
] = (uint8_t) payload
[i
];
265 for (i
= lmin
; i
< len
; ++i
)
266 packet
[i
] = (uint8_t) rand();
270 static void __assemble_icmp4(uint8_t *packet
, size_t len
, const struct ctx
*ctx
)
274 struct icmphdr
*icmph
= (struct icmphdr
*) packet
;
276 bug_on(len
< sizeof(*icmph
));
278 icmph
->type
= ICMP_ECHO
;
282 data
= packet
+ sizeof(*icmph
);
283 data_len
= len
- sizeof(*icmph
);
285 __assemble_data(data
, data_len
, ctx
->payload
);
287 icmph
->checksum
= csum((unsigned short *)packet
, len
/ 2);
290 static void __assemble_icmp6(uint8_t *packet
, size_t len
, const struct ctx
*ctx
,
291 const struct sockaddr
*dst
, const struct sockaddr
*src
)
295 struct ip6_hdr ip6hdr
;
296 struct icmp6hdr
*icmp6h
= (struct icmp6hdr
*) packet
;
298 bug_on(len
< sizeof(*icmp6h
));
300 icmp6h
->icmp6_type
= ICMPV6_ECHO_REQUEST
;
301 icmp6h
->icmp6_code
= 0;
302 icmp6h
->icmp6_cksum
= 0;
304 data
= packet
+ sizeof(*icmp6h
);
305 data_len
= len
- sizeof(*icmp6h
);
307 __assemble_data(data
, data_len
, ctx
->payload
);
309 memcpy(&ip6hdr
.ip6_src
, &((const struct sockaddr_in6
*) src
)->sin6_addr
,
310 sizeof(ip6hdr
.ip6_src
));
311 memcpy(&ip6hdr
.ip6_dst
, &((const struct sockaddr_in6
*) dst
)->sin6_addr
,
312 sizeof(ip6hdr
.ip6_dst
));
314 icmp6h
->icmp6_cksum
= p6_csum(&ip6hdr
, packet
, sizeof(*icmp6h
) + data_len
, IPPROTO_ICMPV6
);
317 static size_t __assemble_tcp_header(struct tcphdr
*tcph
, const struct ctx
*ctx
)
319 tcph
->source
= htons((uint16_t) rand());
320 tcph
->dest
= htons((uint16_t) ctx
->dport
);
322 tcph
->seq
= htonl(rand());
323 tcph
->ack_seq
= (!!ctx
->ack
? htonl(rand()) : 0);
327 tcph
->syn
= !!ctx
->syn
;
328 tcph
->ack
= !!ctx
->ack
;
329 tcph
->urg
= !!ctx
->urg
;
330 tcph
->fin
= !!ctx
->fin
;
331 tcph
->rst
= !!ctx
->rst
;
332 tcph
->psh
= !!ctx
->psh
;
333 tcph
->ece
= !!ctx
->ecn
;
334 tcph
->cwr
= !!ctx
->ecn
;
336 tcph
->window
= htons((uint16_t) (100 + (rand() % 65435)));
338 tcph
->urg_ptr
= (!!ctx
->urg
? htons((uint16_t) rand()) : 0);
340 return tcph
->doff
* 4;
343 static void __assemble_tcp(uint8_t *packet
, size_t len
, const struct ctx
*ctx
,
344 const struct sockaddr
*dst
, const struct sockaddr
*src
)
348 size_t tcp_len
, data_len
;
350 struct tcphdr
*tcph
= (struct tcphdr
*) packet
;
352 bug_on(len
< sizeof(*tcph
));
354 tcp_len
= __assemble_tcp_header(tcph
, ctx
);
356 data
= packet
+ tcp_len
;
357 data_len
= len
- tcp_len
;
359 __assemble_data(data
, data_len
, ctx
->payload
);
361 memcpy(&iphdr
.ip_src
, &((const struct sockaddr_in
*) src
)->sin_addr
.s_addr
,
362 sizeof(iphdr
.ip_src
));
363 memcpy(&iphdr
.ip_dst
, &((const struct sockaddr_in
*) dst
)->sin_addr
.s_addr
,
364 sizeof(iphdr
.ip_dst
));
366 tcph
->check
= p4_csum(&iphdr
, packet
, tcp_len
+ data_len
, IPPROTO_TCP
);
369 static void __assemble_tcp6(uint8_t *packet
, size_t len
, const struct ctx
*ctx
,
370 const struct sockaddr
*dst
, const struct sockaddr
*src
)
373 size_t tcp_len
, data_len
;
374 struct ip6_hdr ip6hdr
;
375 struct tcphdr
*tcph
= (struct tcphdr
*) packet
;
377 bug_on(len
< sizeof(*tcph
));
379 tcp_len
= __assemble_tcp_header(tcph
, ctx
);
381 data
= packet
+ tcp_len
;
382 data_len
= len
- tcp_len
;
384 __assemble_data(data
, data_len
, ctx
->payload
);
386 memcpy(&ip6hdr
.ip6_src
, &((const struct sockaddr_in6
*) src
)->sin6_addr
,
387 sizeof(ip6hdr
.ip6_src
));
388 memcpy(&ip6hdr
.ip6_dst
, &((const struct sockaddr_in6
*) dst
)->sin6_addr
,
389 sizeof(ip6hdr
.ip6_dst
));
391 tcph
->check
= p6_csum(&ip6hdr
, packet
, tcp_len
+ data_len
, IPPROTO_TCP
);
394 static int assemble_ipv4(uint8_t *packet
, size_t len
, int ttl
, int proto
,
395 const struct ctx
*ctx
, const struct sockaddr
*dst
,
396 const struct sockaddr
*src
)
400 struct iphdr
*iph
= (struct iphdr
*) packet
;
402 bug_on(!src
|| !dst
);
403 bug_on(src
->sa_family
!= PF_INET
|| dst
->sa_family
!= PF_INET
);
404 bug_on(len
< sizeof(*iph
) + min(sizeof(struct tcphdr
),
405 sizeof(struct icmphdr
)));
409 iph
->tos
= (uint8_t) ctx
->tos
;
411 iph
->tot_len
= htons((uint16_t) len
);
412 iph
->id
= htons((uint16_t) rand());
414 iph
->frag_off
= ctx
->nofrag
? IP_DF
: 0;
415 iph
->ttl
= (uint8_t) ttl
;
417 iph
->saddr
= ((const struct sockaddr_in
*) src
)->sin_addr
.s_addr
;
418 iph
->daddr
= ((const struct sockaddr_in
*) dst
)->sin_addr
.s_addr
;
420 iph
->protocol
= (uint8_t) proto
;
423 data
= packet
+ sizeof(*iph
);
424 data_len
= len
- sizeof(*iph
);
428 __assemble_tcp(data
, data_len
, ctx
, dst
, src
);
432 __assemble_icmp4(data
, data_len
, ctx
);
440 iph
->check
= csum((unsigned short *) packet
, ntohs(iph
->tot_len
) >> 1);
442 return ntohs(iph
->id
);
445 static int assemble_ipv6(uint8_t *packet
, size_t len
, int ttl
, int proto
,
446 const struct ctx
*ctx
, const struct sockaddr
*dst
,
447 const struct sockaddr
*src
)
451 struct ip6_hdr
*ip6h
= (struct ip6_hdr
*) packet
;
453 bug_on(!src
|| !dst
);
454 bug_on(src
->sa_family
!= PF_INET6
|| dst
->sa_family
!= PF_INET6
);
455 bug_on(len
< sizeof(*ip6h
) + min(sizeof(struct tcphdr
),
456 sizeof(struct icmp6hdr
)));
458 ip6h
->ip6_flow
= htonl(rand() & 0x000fffff);
459 ip6h
->ip6_vfc
= 0x60;
461 ip6h
->ip6_plen
= htons((uint16_t) len
- sizeof(*ip6h
));
462 ip6h
->ip6_nxt
= (uint8_t) proto
;
463 ip6h
->ip6_hlim
= (uint8_t) ttl
;
465 memcpy(&ip6h
->ip6_src
, &(((const struct sockaddr_in6
*)
466 src
)->sin6_addr
), sizeof(ip6h
->ip6_src
));
467 memcpy(&ip6h
->ip6_dst
, &(((const struct sockaddr_in6
*)
468 dst
)->sin6_addr
), sizeof(ip6h
->ip6_dst
));
470 data
= packet
+ sizeof(*ip6h
);
471 data_len
= len
- sizeof(*ip6h
);
475 __assemble_tcp6(data
, data_len
, ctx
, dst
, src
);
480 __assemble_icmp6(data
, data_len
, ctx
, dst
, src
);
487 return ntohl(ip6h
->ip6_flow
) & 0x000fffff;
490 static int check_ipv4(uint8_t *packet
, size_t len
, int ttl __maybe_unused
,
491 int id
, const struct sockaddr
*ss
)
493 struct iphdr
*iph
= (struct iphdr
*) packet
;
494 struct iphdr
*iph_inner
;
495 struct icmphdr
*icmph
;
497 if (iph
->protocol
!= IPPROTO_ICMP
)
499 if (iph
->daddr
!= ((const struct sockaddr_in
*) ss
)->sin_addr
.s_addr
)
502 icmph
= (struct icmphdr
*) (packet
+ sizeof(struct iphdr
));
503 if (icmph
->type
!= ICMP_TIME_EXCEEDED
)
505 if (icmph
->code
!= ICMP_EXC_TTL
)
508 iph_inner
= (struct iphdr
*) (packet
+ sizeof(struct iphdr
) +
509 sizeof(struct icmphdr
));
510 if (ntohs(iph_inner
->id
) != id
)
516 static void handle_ipv4(uint8_t *packet
, size_t len __maybe_unused
,
517 bool do_dns_resolution
, bool do_geo_lookup
)
519 char hbuff
[NI_MAXHOST
];
520 struct iphdr
*iph
= (struct iphdr
*) packet
;
521 struct sockaddr_in sd
;
522 struct hostent
*hent
;
523 const char *as
, *country
;
526 memset(hbuff
, 0, sizeof(hbuff
));
527 memset(&sd
, 0, sizeof(sd
));
528 sd
.sin_family
= PF_INET
;
529 sd
.sin_addr
.s_addr
= iph
->saddr
;
531 getnameinfo((struct sockaddr
*) &sd
, sizeof(sd
),
532 hbuff
, sizeof(hbuff
), NULL
, 0, NI_NUMERICHOST
);
534 as
= geoip4_as_name(&sd
);
535 country
= geoip4_country_name(&sd
);
536 city
= geoip4_city_name(&sd
);
538 if (do_dns_resolution
) {
539 hent
= gethostbyaddr(&sd
.sin_addr
, sizeof(sd
.sin_addr
), PF_INET
);
541 printf(" %s (%s)", hent
->h_name
, hbuff
);
543 printf(" %s", hbuff
);
545 printf(" %s", hbuff
);
548 printf(" in %s", as
);
550 printf(" in %s", country
);
552 printf(", %s", city
);
555 printf(" (%f/%f)", geoip4_latitude(&sd
), geoip4_longitude(&sd
));
560 static int check_ipv6(uint8_t *packet
, size_t len
, int ttl __maybe_unused
,
561 int id
, const struct sockaddr
*ss
)
563 struct ip6_hdr
*ip6h
= (struct ip6_hdr
*) packet
;
564 struct ip6_hdr
*ip6h_inner
;
565 struct icmp6hdr
*icmp6h
;
567 if (ip6h
->ip6_nxt
!= IPPROTO_ICMPV6
)
569 if (memcmp(&ip6h
->ip6_dst
, &(((const struct sockaddr_in6
*)
570 ss
)->sin6_addr
), sizeof(ip6h
->ip6_dst
)))
573 icmp6h
= (struct icmp6hdr
*) (packet
+ sizeof(*ip6h
));
574 if (icmp6h
->icmp6_type
!= ICMPV6_TIME_EXCEED
)
576 if (icmp6h
->icmp6_code
!= ICMPV6_EXC_HOPLIMIT
)
579 ip6h_inner
= (struct ip6_hdr
*) (packet
+ sizeof(*ip6h
) + sizeof(*icmp6h
));
580 if ((ntohl(ip6h_inner
->ip6_flow
) & 0x000fffff) != (uint32_t) id
)
586 static void handle_ipv6(uint8_t *packet
, size_t len __maybe_unused
,
587 bool do_dns_resolution
, bool do_geo_lookup
)
589 char hbuff
[NI_MAXHOST
];
590 struct ip6_hdr
*ip6h
= (struct ip6_hdr
*) packet
;
591 struct sockaddr_in6 sd
;
592 struct hostent
*hent
;
593 const char *as
, *country
;
596 memset(hbuff
, 0, sizeof(hbuff
));
597 memset(&sd
, 0, sizeof(sd
));
598 sd
.sin6_family
= PF_INET6
;
599 memcpy(&sd
.sin6_addr
, &ip6h
->ip6_src
, sizeof(ip6h
->ip6_src
));
601 getnameinfo((struct sockaddr
*) &sd
, sizeof(sd
),
602 hbuff
, sizeof(hbuff
), NULL
, 0, NI_NUMERICHOST
);
604 as
= geoip6_as_name(&sd
);
605 country
= geoip6_country_name(&sd
);
606 city
= geoip6_city_name(&sd
);
608 if (do_dns_resolution
) {
609 hent
= gethostbyaddr(&sd
.sin6_addr
, sizeof(sd
.sin6_addr
), PF_INET6
);
611 printf(" %s (%s)", hent
->h_name
, hbuff
);
613 printf(" %s", hbuff
);
615 printf(" %s", hbuff
);
618 printf(" in %s", as
);
620 printf(" in %s", country
);
622 printf(", %s", city
);
625 printf(" (%f/%f)", geoip6_latitude(&sd
), geoip6_longitude(&sd
));
630 static void show_trace_info(struct ctx
*ctx
, const struct sockaddr_storage
*ss
,
631 const struct sockaddr_storage
*sd
)
633 char hbuffs
[256], hbuffd
[256];
635 memset(hbuffd
, 0, sizeof(hbuffd
));
636 getnameinfo((struct sockaddr
*) sd
, sizeof(*sd
),
637 hbuffd
, sizeof(hbuffd
), NULL
, 0, NI_NUMERICHOST
);
639 memset(hbuffs
, 0, sizeof(hbuffs
));
640 getnameinfo((struct sockaddr
*) ss
, sizeof(*ss
),
641 hbuffs
, sizeof(hbuffs
), NULL
, 0, NI_NUMERICHOST
);
643 printf("AS path IPv%d TCP trace from %s to %s:%s (%s) with len %zu "
644 "Bytes, %u max hops\n", ctx
->proto
== IPPROTO_IP
? 4 : 6,
645 hbuffs
, hbuffd
, ctx
->port
, ctx
->host
, ctx
->totlen
, ctx
->max_ttl
);
647 printf("Using flags SYN:%d,ACK:%d,ECN:%d,FIN:%d,PSH:%d,RST:%d,URG:%d\n",
648 ctx
->syn
, ctx
->ack
, ctx
->ecn
, ctx
->fin
, ctx
->psh
, ctx
->rst
, ctx
->urg
);
651 printf("With payload: \'%s\'\n", ctx
->payload
);
654 static int get_remote_fd(struct ctx
*ctx
, struct sockaddr_storage
*ss
,
655 struct sockaddr_storage
*sd
)
657 int fd
= -1, ret
, one
= 1, af
= AF_INET
;
658 struct addrinfo hints
, *ahead
, *ai
;
659 unsigned char bind_ip
[sizeof(struct in6_addr
)];
661 memset(&hints
, 0, sizeof(hints
));
662 hints
.ai_family
= PF_UNSPEC
;
663 hints
.ai_socktype
= SOCK_STREAM
;
664 hints
.ai_protocol
= IPPROTO_TCP
;
665 hints
.ai_flags
= AI_NUMERICSERV
;
667 ret
= getaddrinfo(ctx
->host
, ctx
->port
, &hints
, &ahead
);
669 panic("Cannot get address info!\n");
671 for (ai
= ahead
; ai
!= NULL
&& fd
< 0; ai
= ai
->ai_next
) {
672 if (!((ai
->ai_family
== PF_INET6
&& ctx
->proto
== IPPROTO_IPV6
) ||
673 (ai
->ai_family
== PF_INET
&& ctx
->proto
== IPPROTO_IP
)))
676 fd
= socket(ai
->ai_family
, SOCK_RAW
, IPPROTO_RAW
);
680 memset(ss
, 0, sizeof(*ss
));
681 ret
= device_address(ctx
->dev
, ai
->ai_family
, ss
);
682 if (ret
< 0 && !ctx
->bind_addr
)
683 panic("Cannot get own device address!\n");
685 if (ctx
->bind_addr
) {
686 if (ctx
->proto
== IPPROTO_IPV6
)
689 if (inet_pton(af
, ctx
->bind_addr
, &bind_ip
) != 1)
690 panic("Address is invalid!\n");
692 if (af
== AF_INET6
) {
693 struct sockaddr_in6
*ss6
= (struct sockaddr_in6
*) ss
;
694 memcpy(&ss6
->sin6_addr
.s6_addr
, &bind_ip
, sizeof(struct in6_addr
));
696 struct sockaddr_in
*ss4
= (struct sockaddr_in
*) ss
;
697 memcpy(&ss4
->sin_addr
.s_addr
, &bind_ip
, sizeof(struct in_addr
));
701 ret
= bind(fd
, (struct sockaddr
*) ss
, sizeof(*ss
));
703 panic("Cannot bind socket!\n");
705 memset(sd
, 0, sizeof(*sd
));
706 memcpy(sd
, ai
->ai_addr
, ai
->ai_addrlen
);
708 ctx
->sd_len
= ai
->ai_addrlen
;
709 ctx
->dport
= strtoul(ctx
->port
, NULL
, 10);
711 ret
= setsockopt(fd
, ctx
->proto
, IP_HDRINCL
, &one
, sizeof(one
));
713 panic("Kernel does not support IP_HDRINCL!\n");
715 if (ai
->ai_family
== PF_INET6
) {
716 struct sockaddr_in6
*sd6
= (struct sockaddr_in6
*) sd
;
727 panic("Cannot create socket! Does remote "
729 ctx
->proto
== IPPROTO_IP
? 4 : 6);
734 static void inject_filter(struct ctx
*ctx
, int fd
)
736 struct sock_fprog bpf_ops
;
738 enable_kernel_bpf_jit_compiler();
740 memset(&bpf_ops
, 0, sizeof(bpf_ops
));
741 bpf_ops
.filter
= (struct sock_filter
*) af_ops
[ctx
->proto
].filter
;
742 bpf_ops
.len
= af_ops
[ctx
->proto
].flen
;
744 bpf_attach_to_sock(fd
, &bpf_ops
);
747 static int __process_node(struct ctx
*ctx
, int fd
, int fd_cap
, int ttl
,
748 int inner_proto
, uint8_t *pkt_snd
, uint8_t *pkt_rcv
,
749 const struct sockaddr_storage
*ss
,
750 const struct sockaddr_storage
*sd
, struct timeval
*diff
)
752 int pkt_id
, ret
, timeout
;
754 struct timeval start
, end
;
756 prepare_polling(fd_cap
, &pfd
);
758 memset(pkt_snd
, 0, ctx
->totlen
);
759 pkt_id
= af_ops
[ctx
->proto
].assembler(pkt_snd
, ctx
->totlen
, ttl
,
761 (const struct sockaddr
*) sd
,
762 (const struct sockaddr
*) ss
);
764 ret
= sendto(fd
, pkt_snd
, ctx
->totlen
, 0, (struct sockaddr
*) sd
,
767 panic("sendto failed: %s\n", strerror(errno
));
769 bug_on(gettimeofday(&start
, NULL
));
771 timeout
= (ctx
->timeout
> 0 ? ctx
->timeout
: 2) * 1000;
773 ret
= poll(&pfd
, 1, timeout
);
774 if (ret
> 0 && pfd
.revents
& POLLIN
&& sigint
== 0) {
775 bug_on(gettimeofday(&end
, NULL
));
777 timersub(&end
, &start
, diff
);
779 ret
= recvfrom(fd_cap
, pkt_rcv
, ctx
->rcvlen
, 0, NULL
, NULL
);
780 if (ret
< (int) (sizeof(struct ethhdr
) + af_ops
[ctx
->proto
].min_len_icmp
))
783 return af_ops
[ctx
->proto
].check(pkt_rcv
+ sizeof(struct ethhdr
),
784 ret
- sizeof(struct ethhdr
), ttl
,
785 pkt_id
, (const struct sockaddr
*) ss
);
793 static void timerdiv(const unsigned long divisor
, const struct timeval
*tv
,
794 struct timeval
*result
)
796 uint64_t x
= ((uint64_t) tv
->tv_sec
* 1000 * 1000 + tv
->tv_usec
) / divisor
;
798 result
->tv_sec
= x
/ 1000 / 1000;
799 result
->tv_usec
= x
% (1000 * 1000);
802 static int timevalcmp(const void *t1
, const void *t2
)
804 if (timercmp((struct timeval
*) t1
, (struct timeval
*) t2
, <))
806 if (timercmp((struct timeval
*) t1
, (struct timeval
*) t2
, >))
812 static const char *proto_short(int proto
)
825 static int __process_time(struct ctx
*ctx
, int fd
, int fd_cap
, int ttl
,
826 int inner_proto
, uint8_t *pkt_snd
, uint8_t *pkt_rcv
,
827 const struct sockaddr_storage
*ss
,
828 const struct sockaddr_storage
*sd
)
831 int good
= 0, ret
= -EIO
, idx
, ret_good
= -EIO
;
832 struct timeval probes
[9], *tmp
, sum
, res
;
833 uint8_t *trash
= xmalloc(ctx
->rcvlen
);
834 char *cwait
[] = { "-", "\\", "|", "/" };
836 memset(probes
, 0, sizeof(probes
));
837 for (i
= 0; i
< array_size(probes
) && sigint
== 0; ++i
) {
838 ret
= __process_node(ctx
, fd
, fd_cap
, ttl
, inner_proto
,
839 pkt_snd
, good
== 0 ? pkt_rcv
: trash
,
847 if (good
== 0 && ctx
->queries
== (int) i
)
852 printf("\r%2d: %s", ttl
, cwait
[j
++]);
854 if (j
>= array_size(cwait
))
863 tmp
= xcalloc(good
, sizeof(struct timeval
));
864 for (i
= j
= 0; i
< array_size(probes
); ++i
) {
865 if (probes
[i
].tv_sec
== 0 && probes
[i
].tv_usec
== 0)
867 tmp
[j
].tv_sec
= probes
[i
].tv_sec
;
868 tmp
[j
].tv_usec
= probes
[i
].tv_usec
;
872 qsort(tmp
, j
, sizeof(struct timeval
), timevalcmp
);
874 printf("\r%2d: %s[", ttl
, proto_short(inner_proto
));
878 timeradd(&tmp
[idx
], &tmp
[idx
- 1], &sum
);
879 timerdiv(2, &sum
, &res
);
881 printf("%lu sec ", res
.tv_sec
);
882 printf("%7lu us", res
.tv_usec
);
885 if (tmp
[idx
].tv_sec
> 0)
886 printf("%lu sec ", tmp
[idx
].tv_sec
);
887 printf("%7lu us", tmp
[idx
].tv_usec
);
898 static int __probe_remote(struct ctx
*ctx
, int fd
, int fd_cap
, int ttl
,
899 uint8_t *pkt_snd
, uint8_t *pkt_rcv
,
900 const struct sockaddr_storage
*ss
,
901 const struct sockaddr_storage
*sd
,
904 int ret
= -EIO
, tries
= ctx
->queries
;
906 while (tries
-- > 0 && sigint
== 0) {
907 ret
= __process_time(ctx
, fd
, fd_cap
, ttl
, inner_proto
,
908 pkt_snd
, pkt_rcv
, ss
, sd
);
912 af_ops
[ctx
->proto
].handler(pkt_rcv
+ sizeof(struct ethhdr
),
913 ret
- sizeof(struct ethhdr
),
914 ctx
->do_dns_resolution
, ctx
->do_geo_lookup
);
915 if (ctx
->do_show_packet
) {
916 struct pkt_buff
*pkt
;
919 pkt
= pkt_alloc(pkt_rcv
, ret
);
931 static int __process_ttl(struct ctx
*ctx
, int fd
, int fd_cap
, int ttl
,
932 uint8_t *pkt_snd
, uint8_t *pkt_rcv
,
933 const struct sockaddr_storage
*ss
,
934 const struct sockaddr_storage
*sd
)
938 const int inner_protos
[] = {
943 printf("%2d: ", ttl
);
946 for (i
= 0; i
< array_size(inner_protos
) && sigint
== 0; ++i
) {
947 ret
= __probe_remote(ctx
, fd
, fd_cap
, ttl
, pkt_snd
, pkt_rcv
, ss
, sd
,
954 printf("\r%2d: ?[ no answer]", ttl
);
955 if (!ctx
->do_show_packet
)
957 if (ctx
->do_show_packet
&& ret
<= 0)
964 static int main_trace(struct ctx
*ctx
)
966 int fd
, fd_cap
, ifindex
, ttl
;
967 struct ring dummy_ring
;
968 struct sockaddr_storage ss
, sd
;
969 uint8_t *pkt_snd
, *pkt_rcv
;
971 fd
= get_remote_fd(ctx
, &ss
, &sd
);
972 fd_cap
= pf_socket();
974 inject_filter(ctx
, fd_cap
);
976 ifindex
= device_ifindex(ctx
->dev
);
977 bind_ring_generic(fd_cap
, &dummy_ring
, ifindex
, false);
979 if (ctx
->totlen
< af_ops
[ctx
->proto
].min_len_tcp
) {
980 ctx
->totlen
= af_ops
[ctx
->proto
].min_len_tcp
;
982 ctx
->totlen
+= strlen(ctx
->payload
);
985 ctx
->rcvlen
= device_mtu(ctx
->dev
) - sizeof(struct ethhdr
);
986 if (ctx
->totlen
>= ctx
->rcvlen
)
987 panic("packet length (%zu) exceeds device MTU (%zu)\n", ctx
->totlen
, ctx
->rcvlen
);
989 pkt_snd
= xmalloc(ctx
->totlen
);
990 pkt_rcv
= xmalloc(ctx
->rcvlen
);
992 show_trace_info(ctx
, &ss
, &sd
);
994 for (ttl
= ctx
->init_ttl
; ttl
<= ctx
->max_ttl
&& sigint
== 0; ++ttl
)
995 __process_ttl(ctx
, fd
, fd_cap
, ttl
, pkt_snd
, pkt_rcv
,
1007 int main(int argc
, char **argv
)
1017 memset(&ctx
, 0, sizeof(ctx
));
1022 ctx
.proto
= IPPROTO_IP
;
1024 ctx
.dev
= xstrdup("eth0");
1025 ctx
.port
= xstrdup("80");
1026 ctx
.bind_addr
= NULL
;
1028 while ((c
= getopt_long(argc
, argv
, short_options
, long_options
,
1042 ctx
.host
= xstrdup(optarg
);
1047 ctx
.port
= xstrdup(optarg
);
1050 ctx
.do_dns_resolution
= false;
1053 ctx
.proto
= IPPROTO_IP
;
1056 ctx
.proto
= IPPROTO_IPV6
;
1059 ctx
.do_show_packet
= true;
1062 ctx
.do_dns_resolution
= true;
1065 ctx
.init_ttl
= atoi(optarg
);
1066 if (ctx
.init_ttl
<= 0)
1070 ctx
.max_ttl
= atoi(optarg
);
1071 if (ctx
.max_ttl
<= 0)
1075 ctx
.bind_addr
= xstrdup(optarg
);
1080 ctx
.dev
= xstrdup(optarg
);
1083 ctx
.queries
= atoi(optarg
);
1084 if (ctx
.queries
<= 0)
1088 ctx
.timeout
= atoi(optarg
);
1089 if (ctx
.timeout
<= 0)
1093 ctx
.do_geo_lookup
= true;
1118 ctx
.tos
= atoi(optarg
);
1126 ctx
.payload
= xstrdup(optarg
);
1129 ctx
.totlen
= strtoul(optarg
, NULL
, 10);
1130 if (ctx
.totlen
== 0)
1146 panic("option -%c requires an argument!\n",
1149 if (isprint(optopt
))
1150 printf("unknown option character '0x%X'!\n", optopt
);
1158 if (argc
< 3 || !ctx
.host
|| !ctx
.port
|| ctx
.init_ttl
> ctx
.max_ttl
||
1159 ctx
.init_ttl
> MAXTTL
|| ctx
.max_ttl
> MAXTTL
)
1162 if (!device_up_and_running(ctx
.dev
))
1163 panic("networking device %s is not up and running\n", ctx
.dev
);
1164 if (device_mtu(ctx
.dev
) <= ctx
.totlen
)
1165 panic("packet length (%zu) exceeds device MTU (%zu)\n", ctx
.totlen
, device_mtu(ctx
.dev
));
1167 register_signal(SIGHUP
, signal_handler
);
1168 register_signal(SIGINT
, signal_handler
);
1169 register_signal(SIGQUIT
, signal_handler
);
1170 register_signal(SIGTERM
, signal_handler
);
1175 ret
= main_trace(&ctx
);
1183 free(ctx
.bind_addr
);