Reverse DNS lookup now works with option -N on ashunt
[netsniff-ng.git] / src / ashunt.c
blob9914a6cb39661e4257bf37efae63c222dc982dd7
1 /*
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.
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.
13 * The road must be trod, but it will be very hard. And neither strength nor
14 * wisdom will carry us far upon it. This quest may be attempted by the weak
15 * with as much hope as the strong. Yet such is oft the course of deeds that
16 * move the wheels of the world: small hands do them because they must,
17 * while the eyes of the great are elsewhere.
19 * -- The Lord of the Rings, Elrond, Chapter 'The Council of Elrond'.
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <signal.h>
25 #include <getopt.h>
26 #include <ctype.h>
27 #include <stdint.h>
28 #include <assert.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/socket.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <asm/byteorder.h>
35 #include <linux/tcp.h>
36 #include <netinet/ip.h>
37 #include <netinet/ip6.h>
38 #include <netinet/in.h>
39 #include <errno.h>
40 #include <netdb.h>
41 #include <arpa/inet.h>
42 #include <linux/if_ether.h>
43 #include <linux/icmp.h>
44 #include <linux/icmpv6.h>
46 #include "misc.h"
47 #include "bpf.h"
48 #include "die.h"
49 #include "xmalloc.h"
50 #include "write_or_die.h"
51 #include "aslookup.h"
52 #include "version.h"
53 #include "signals.h"
54 #include "netdev.h"
55 #include "mtrand.h"
56 #include "parser.h"
57 #include "rx_ring.h"
58 #include "poll.h"
60 #define WHOIS_SERVER_SOURCE "/etc/netsniff-ng/whois.conf"
62 struct ash_cfg {
63 char *host;
64 char *port;
65 int init_ttl;
66 int max_ttl;
67 int dns_resolv;
68 char *dev;
69 int queries;
70 int timeout;
71 int syn, ack, ecn, fin, psh, rst, urg;
72 int tos, nofrag;
73 int totlen;
74 char *whois;
75 char *whois_port;
76 int ip;
79 sig_atomic_t sigint = 0;
81 static const char *short_options = "H:p:nNf:m:i:d:q:x:SAEFPURt:Gl:w:W:hv46";
83 static struct option long_options[] = {
84 {"host", required_argument, 0, 'H'},
85 {"port", required_argument, 0, 'p'},
86 {"init-ttl", required_argument, 0, 'f'},
87 {"max-ttl", required_argument, 0, 'm'},
88 {"numeric", no_argument, 0, 'n'},
89 {"dns", no_argument, 0, 'N'},
90 {"ipv4", no_argument, 0, '4'},
91 {"ipv6", no_argument, 0, '6'},
92 {"dev", required_argument, 0, 'd'},
93 {"num-probes", required_argument, 0, 'q'},
94 {"timeout", required_argument, 0, 'x'},
95 {"syn", no_argument, 0, 'S'},
96 {"ack", no_argument, 0, 'A'},
97 {"urg", no_argument, 0, 'U'},
98 {"fin", no_argument, 0, 'F'},
99 {"psh", no_argument, 0, 'P'},
100 {"rst", no_argument, 0, 'R'},
101 {"ecn-syn", no_argument, 0, 'E'},
102 {"tos", required_argument, 0, 't'},
103 {"nofrag", no_argument, 0, 'G'},
104 {"totlen", required_argument, 0, 'l'},
105 {"whois", required_argument, 0, 'w'},
106 {"wport", required_argument, 0, 'W'},
107 {"version", no_argument, 0, 'v'},
108 {"help", no_argument, 0, 'h'},
109 {0, 0, 0, 0}
112 static struct sock_filter ipv4_icmp_type_11[] = {
113 /* (000) ldh [12] */
114 { 0x28, 0, 0, 0x0000000c },
115 /* (001) jeq #0x800 jt 2 jf 10 */
116 { 0x15, 0, 8, 0x00000800 },
117 /* (002) ldb [23] */
118 { 0x30, 0, 0, 0x00000017 },
119 /* (003) jeq #0x1 jt 4 jf 10 */
120 { 0x15, 0, 6, 0x00000001 },
121 /* (004) ldh [20] */
122 { 0x28, 0, 0, 0x00000014 },
123 /* (005) jset #0x1fff jt 10 jf 6 */
124 { 0x45, 4, 0, 0x00001fff },
125 /* (006) ldxb 4*([14]&0xf) */
126 { 0xb1, 0, 0, 0x0000000e },
127 /* (007) ldb [x + 14] */
128 { 0x50, 0, 0, 0x0000000e },
129 /* (008) jeq #0xb jt 9 jf 10 */
130 { 0x15, 0, 1, 0x0000000b },
131 /* (009) ret #65535 */
132 { 0x06, 0, 0, 0xffffffff },
133 /* (010) ret #0 */
134 { 0x06, 0, 0, 0x00000000 },
137 static struct sock_filter ipv6_icmp6_type_3[] = {
138 /* (000) ldh [12] */
139 { 0x28, 0, 0, 0x0000000c },
140 /* (001) jeq #0x86dd jt 2 jf 7 */
141 { 0x15, 0, 5, 0x000086dd },
142 /* (002) ldb [20] */
143 { 0x30, 0, 0, 0x00000014 },
144 /* (003) jeq #0x3a jt 4 jf 7 */
145 { 0x15, 0, 3, 0x0000003a },
146 /* (004) ldb [54] */
147 { 0x30, 0, 0, 0x00000036 },
148 /* (005) jeq #0x3 jt 6 jf 7 */
149 { 0x15, 0, 1, 0x00000003 },
150 /* (006) ret #65535 */
151 { 0x06, 0, 0, 0xffffffff },
152 /* (007) ret #0 */
153 { 0x06, 0, 0, 0x00000000 },
156 static void signal_handler(int number)
158 switch (number) {
159 case SIGINT:
160 sigint = 1;
161 break;
162 default:
163 break;
167 static void header(void)
169 printf("%s%s%s\n", colorize_start(bold), "ashunt "
170 VERSION_STRING, colorize_end());
173 static void help(void)
176 printf("\nashunt %s, AS trace route utility\n",
177 VERSION_STRING);
178 printf("http://www.netsniff-ng.org\n\n");
179 printf("Usage: ashunt [options]\n");
180 printf("Options:\n");
181 printf(" -H|--host <host> Host/IPv4/IPv6 to lookup AS route to\n");
182 printf(" -p|--port <port> Hosts port to lookup AS route to\n");
183 printf(" -i|-d|--dev <device> Networking device, i.e. eth0\n");
184 printf(" -4|--ipv4 Use IPv4 requests (default)\n");
185 printf(" -6|--ipv6 Use IPv6 requests\n");
186 printf(" -n|--numeric Do not do reverse DNS lookup for hops\n");
187 printf(" -N|--dns Do a reverse DNS lookup for hops\n");
188 printf(" -f|--init-ttl <ttl> Set initial TTL\n");
189 printf(" -m|--max-ttl <ttl> Set maximum TTL (default: 30)\n");
190 printf(" -q|--num-probes <num> Number of max probes for each hop (default: 3)\n");
191 printf(" -x|--timeout <sec> Probe response timeout in sec (default: 3)\n");
192 printf(" -S|--syn Set TCP SYN flag in packets\n");
193 printf(" -A|--ack Set TCP ACK flag in packets\n");
194 printf(" -F|--fin Set TCP FIN flag in packets\n");
195 printf(" -P|--psh Set TCP PSH flag in packets\n");
196 printf(" -U|--urg Set TCP URG flag in packets\n");
197 printf(" -R|--rst Set TCP RST flag in packets\n");
198 printf(" -E|--ecn-syn Send ECN SYN packets (RFC3168)\n");
199 printf(" -t|--tos <tos> Set the IP TOS field\n");
200 printf(" -G|--nofrag Set do not fragment bit\n");
201 printf(" -l|--totlen <len> Specify total packet len\n");
202 printf(" -w|--whois <server> Use a different AS whois DB server\n");
203 printf(" (default: /etc/netsniff-ng/whois.conf)\n");
204 printf(" -W|--wport <port> Use a different port to AS whois server\n");
205 printf(" (default: /etc/netsniff-ng/whois.conf)\n");
206 printf(" -v|--version Print version\n");
207 printf(" -h|--help Print this help\n");
208 printf("\n");
209 printf("Examples:\n");
210 printf(" IPv4 trace of AS up to netsniff-ng.org:\n");
211 printf(" ashunt -i eth0 -N -E -H netsniff-ng.org\n");
212 printf(" IPv6 trace of AS up to netsniff-ng.org:\n");
213 printf(" ashunt -6 -i eth0 -H netsniff-ng.org\n");
214 printf("\n");
215 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
216 printf("Copyright (C) 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
217 printf("Swiss federal institute of technology (ETH Zurich)\n");
218 printf("License: GNU GPL version 2\n");
219 printf("This is free software: you are free to change and redistribute it.\n");
220 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
222 die();
225 static void version(void)
227 printf("\nashunt %s, AS trace route utility\n",
228 VERSION_STRING);
229 printf("http://www.netsniff-ng.org\n\n");
230 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
231 printf("Copyright (C) 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
232 printf("Swiss federal institute of technology (ETH Zurich)\n");
233 printf("License: GNU GPL version 2\n");
234 printf("This is free software: you are free to change and redistribute it.\n");
235 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
237 die();
240 static inline unsigned short csum(unsigned short *buf, int nwords)
242 unsigned long sum;
243 for (sum = 0; nwords > 0; nwords--)
244 sum += *buf++;
245 sum = (sum >> 16) + (sum & 0xffff);
246 sum += (sum >> 16);
247 return ~sum;
250 static void assemble_data(uint8_t *packet, size_t len)
252 int i;
253 for (i = 0; i < len; ++i)
254 packet[i] = (uint8_t) mt_rand_int32();
257 static void assemble_tcp(uint8_t *packet, size_t len, int syn, int ack,
258 int urg, int fin, int rst, int psh, int ecn, int dport)
260 struct tcphdr *tcph = (struct tcphdr *) packet;
261 assert(len >= sizeof(struct tcphdr));
262 tcph->source = htons((uint16_t) mt_rand_int32());
263 tcph->dest = htons((uint16_t) dport);
264 tcph->seq = htonl(mt_rand_int32());
265 tcph->ack_seq = (!!ack ? htonl(mt_rand_int32()) : 0);
266 tcph->doff = 5;
267 tcph->syn = !!syn;
268 tcph->ack = !!ack;
269 tcph->urg = !!urg;
270 tcph->fin = !!fin;
271 tcph->rst = !!rst;
272 tcph->psh = !!psh;
273 tcph->ece = !!ecn;
274 tcph->cwr = !!ecn;
275 tcph->window = htons((uint16_t) (100 + (mt_rand_int32() % 65435)));
276 tcph->check = 0;
277 tcph->urg_ptr = (!!urg ? htons((uint16_t) mt_rand_int32()) : 0);
280 /* returns: ipv4 id */
281 static int assemble_ipv4_tcp(uint8_t *packet, size_t len, int ttl,
282 int tos, const struct sockaddr *dst,
283 const struct sockaddr *src, int syn, int ack,
284 int urg, int fin, int rst, int psh, int ecn,
285 int nofrag, int dport)
287 struct iphdr *iph = (struct iphdr *) packet;
288 assert(src && dst);
289 assert(src->sa_family == PF_INET && dst->sa_family == PF_INET);
290 assert(len >= sizeof(struct iphdr) + sizeof(struct tcphdr));
291 iph->ihl = 5;
292 iph->version = 4;
293 iph->tos = (uint8_t) tos;
294 iph->tot_len = htons((uint16_t) len);
295 iph->id = htons((uint16_t) mt_rand_int32());
296 iph->frag_off = nofrag ? IP_DF : 0;
297 iph->ttl = (uint8_t) ttl;
298 iph->protocol = 6; /* TCP */
299 iph->saddr = ((struct sockaddr_in *) src)->sin_addr.s_addr;
300 iph->daddr = ((struct sockaddr_in *) dst)->sin_addr.s_addr;
301 assemble_tcp(packet + sizeof(struct iphdr),
302 len - sizeof(struct iphdr), syn, ack, urg, fin, rst,
303 psh, ecn, dport);
304 assemble_data(packet + sizeof(struct iphdr) + sizeof(struct tcphdr),
305 len - sizeof(struct iphdr) - sizeof(struct tcphdr));
306 iph->check = csum((unsigned short *) packet,
307 ntohs(iph->tot_len) >> 1);
308 return ntohs(iph->id);
311 /* returns: ipv6 flow label */
312 static int assemble_ipv6_tcp(uint8_t *packet, size_t len, int ttl,
313 struct sockaddr_in *sin)
315 return 0;
318 static int assemble_packet_or_die(uint8_t *packet, size_t len, int ttl,
319 const struct ash_cfg *cfg,
320 const struct sockaddr *dst,
321 const struct sockaddr *src)
323 return assemble_ipv4_tcp(packet, len, ttl, cfg->tos, dst, src, cfg->syn,
324 cfg->ack, cfg->urg, cfg->fin, cfg->rst,
325 cfg->psh, cfg->ecn, cfg->nofrag, atoi(cfg->port));
328 #define PKT_NOT_FOR_US 0
329 #define PKT_GOOD 1
331 static int handle_ipv4_icmp(uint8_t *packet, size_t len, int ttl, int id,
332 const struct sockaddr *own, int dns_resolv)
334 int ret;
335 struct iphdr *iph = (struct iphdr *) packet;
336 struct iphdr *iph_inner;
337 struct icmphdr *icmph;
338 char *hbuff;
339 struct sockaddr_in sa;
340 struct asrecord rec;
342 if (iph->protocol != 1)
343 return PKT_NOT_FOR_US;
344 if (iph->daddr != ((struct sockaddr_in *) own)->sin_addr.s_addr)
345 return PKT_NOT_FOR_US;
346 icmph = (struct icmphdr *) (packet + sizeof(struct iphdr));
347 if (icmph->type != ICMP_TIME_EXCEEDED)
348 return PKT_NOT_FOR_US;
349 if (icmph->code != ICMP_EXC_TTL)
350 return PKT_NOT_FOR_US;
351 iph_inner = (struct iphdr *) (packet + sizeof(struct iphdr) +
352 sizeof(struct icmphdr));
353 if (ntohs(iph_inner->id) != id)
354 return PKT_NOT_FOR_US;
356 hbuff = xzmalloc(NI_MAXHOST);
357 memset(&sa, 0, sizeof(sa));
359 sa.sin_family = PF_INET;
360 sa.sin_addr.s_addr = iph->saddr;
361 getnameinfo((struct sockaddr *) &sa, sizeof(sa), hbuff, NI_MAXHOST,
362 NULL, 0, NI_NUMERICHOST);
364 memset(&rec, 0, sizeof(rec));
365 ret = aslookup(hbuff, &rec);
366 if (ret < 0)
367 panic("AS lookup error %d!\n", ret);
369 if (!dns_resolv) {
370 if (strlen(rec.country) > 0) {
371 printf("%s in AS%s (%s), %s %s (%s), %s", hbuff,
372 rec.number, rec.country, rec.prefix,
373 rec.registry, rec.since, rec.name);
374 } else {
375 printf("%s in unkown AS", hbuff);
377 } else {
378 struct hostent *hent = gethostbyaddr(&sa.sin_addr,
379 sizeof(sa.sin_addr),
380 PF_INET);
381 if (hent != NULL && strlen(rec.country) > 0) {
382 printf("%s (%s) in AS%s (%s), %s %s (%s), %s",
383 hent->h_name, hbuff, rec.number, rec.country,
384 rec.prefix, rec.registry, rec.since, rec.name);
385 } else {
386 printf("%s in unkown AS", hbuff);
390 xfree(hbuff);
391 return PKT_GOOD;
394 static int handle_packet(uint8_t *packet, size_t len, int ip, int ttl, int id,
395 struct sockaddr *own, int dns_resolv)
397 return handle_ipv4_icmp(packet, len, ttl, id, own, dns_resolv);
400 static int do_trace(const struct ash_cfg *cfg)
402 int ttl, query, fd = -1, one = 1, ret, fd_cap, ifindex;
403 int is_okay = 0, id, timeout_poll;
404 uint8_t *packet, *packet_rcv;
405 ssize_t err, real_len;
406 size_t len, len_rcv;
407 struct addrinfo hints, *ahead, *ai;
408 char *hbuff1, *hbuff2;
409 struct sockaddr_storage ss, sd;
410 struct sock_fprog bpf_ops;
411 struct ring dummy_ring;
412 struct pollfd pfd;
414 mt_init_by_random_device();
416 memset(&hints, 0, sizeof(hints));
417 hints.ai_family = PF_UNSPEC;
418 hints.ai_socktype = SOCK_STREAM;
419 hints.ai_protocol = IPPROTO_TCP;
420 hints.ai_flags = AI_NUMERICSERV;
422 ret = getaddrinfo(cfg->host, cfg->port, &hints, &ahead);
423 if (ret < 0) {
424 whine("Cannot get address info!\n");
425 return -EIO;
428 for (ai = ahead; ai != NULL && fd < 0; ai = ai->ai_next) {
429 if (!((ai->ai_family == PF_INET6 && cfg->ip == 6) ||
430 (ai->ai_family == PF_INET && cfg->ip == 4)))
431 continue;
432 fd = socket(ai->ai_family, SOCK_RAW, ai->ai_protocol);
433 if (fd < 0)
434 continue;
435 fd_cap = pf_socket();
436 memset(&ss, 0, sizeof(ss));
437 ret = device_address(cfg->dev, ai->ai_family, &ss);
438 if (ret < 0)
439 panic("Cannot get own device address!\n");
440 ret = bind(fd, (struct sockaddr *) &ss, sizeof(ss));
441 if (ret < 0)
442 panic("Cannot bind socket!\n");
443 memset(&sd, 0, sizeof(sd));
444 memcpy(&sd, ai->ai_addr, ai->ai_addrlen);
445 break;
448 freeaddrinfo(ahead);
449 if (fd < 0) {
450 whine("Cannot create socket! Does remote support IPv%d?!\n",
451 cfg->ip);
452 return -EIO;
455 len = cfg->totlen;
456 if (cfg->ip == 4) {
457 if (len < sizeof(struct iphdr) + sizeof(struct tcphdr))
458 len = sizeof(struct iphdr) + sizeof(struct tcphdr);
459 } else {
460 if (len < sizeof(struct ip6_hdr) + sizeof(struct tcphdr))
461 len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
463 if (len >= device_mtu(cfg->dev))
464 panic("Packet len exceeds device MTU!\n");
466 packet = xmalloc(len);
467 len_rcv = device_mtu(cfg->dev);
468 packet_rcv = xmalloc(len_rcv);
470 hbuff1 = xzmalloc(256);
471 getnameinfo((struct sockaddr *) &sd, sizeof(sd), hbuff1, 256,
472 NULL, 0, NI_NUMERICHOST);
474 hbuff2 = xzmalloc(256);
475 getnameinfo((struct sockaddr *) &ss, sizeof(ss), hbuff2, 256,
476 NULL, 0, NI_NUMERICHOST);
478 ret = setsockopt(fd, cfg->ip == 4 ? IPPROTO_IP : IPPROTO_IPV6,
479 IP_HDRINCL, &one, sizeof(one));
480 if (ret < 0)
481 panic("Kernel does not support IP_HDRINCL!\n");
483 info("AS path IPv%d TCP trace from %s to %s:%s (%s) with len %u "
484 "Bytes, %u max hops\n", cfg->ip, hbuff2, hbuff1, cfg->port,
485 cfg->host, len, cfg->max_ttl);
486 info("Using flags SYN:%d,ACK:%d,ECN:%d,FIN:%d,PSH:%d,RST:%d,URG:%d\n",
487 cfg->syn, cfg->ack, cfg->ecn, cfg->fin, cfg->psh, cfg->rst,
488 cfg->urg);
489 fflush(stdout);
491 xfree(hbuff1);
492 xfree(hbuff2);
493 hbuff1 = hbuff2 = NULL;
495 memset(&bpf_ops, 0, sizeof(bpf_ops));
496 if (cfg->ip == 4) {
497 bpf_ops.filter = ipv4_icmp_type_11;
498 bpf_ops.len = (sizeof(ipv4_icmp_type_11) /
499 sizeof(ipv4_icmp_type_11[0]));
500 } else {
501 bpf_ops.filter = ipv6_icmp6_type_3;
502 bpf_ops.len = (sizeof(ipv6_icmp6_type_3) /
503 sizeof(ipv6_icmp6_type_3[0]));
505 bpf_attach_to_sock(fd_cap, &bpf_ops);
506 enable_kernel_bpf_jit_compiler();
507 ifindex = device_ifindex(cfg->dev);
508 bind_rx_ring(fd_cap, &dummy_ring, ifindex);
509 prepare_polling(fd_cap, &pfd);
510 timeout_poll = (cfg->timeout > 0 ? cfg->timeout : 3) * 1000;
512 for (ttl = cfg->init_ttl; ttl <= cfg->max_ttl; ++ttl) {
513 is_okay = 0;
514 info("%2d: ", ttl);
515 fflush(stdout);
516 for (query = 0; query < cfg->queries && !is_okay; ++query) {
517 id = assemble_packet_or_die(packet, len, ttl, cfg,
518 (struct sockaddr *) &sd,
519 (struct sockaddr *) &ss);
521 err = sendto(fd, packet, len, 0, (struct sockaddr *) &sd,
522 sizeof(sd));
523 if (err < 0)
524 panic("sendto failed: %s\n", strerror(errno));
526 err = poll(&pfd, 1, timeout_poll);
527 if (err > 0 && pfd.revents & POLLIN) {
528 real_len = recvfrom(fd_cap, packet_rcv, len_rcv,
529 0, NULL, NULL);
530 if (real_len < sizeof(struct ethhdr) +
531 (cfg->ip ? sizeof(struct iphdr) +
532 sizeof(struct icmphdr) :
533 sizeof(struct ip6_hdr) +
534 sizeof(struct icmp6hdr)))
535 continue;
537 is_okay = handle_packet(packet_rcv + sizeof(struct ethhdr),
538 real_len - sizeof(struct ethhdr),
539 cfg->ip, ttl, id,
540 (struct sockaddr *) &ss,
541 cfg->dns_resolv);
542 } else {
543 info("* ");
544 fflush(stdout);
545 is_okay = 0;
548 info("\n");
549 fflush(stdout);
552 close(fd_cap);
553 close(fd);
554 xfree(packet);
555 xfree(packet_rcv);
556 return 0;
559 void parse_whois_or_die(struct ash_cfg *cfg)
561 int fd;
562 ssize_t ret;
563 char tmp[512], *ptr, *ptr2;
565 fd = open_or_die(WHOIS_SERVER_SOURCE, O_RDONLY);
566 while ((ret = read(fd, tmp, sizeof(tmp))) > 0) {
567 tmp[sizeof(tmp) - 1] = 0;
568 ptr = skips(tmp);
569 ptr2 = ptr;
570 while (*ptr2 != ' ' && ptr2 < &tmp[sizeof(tmp) - 1])
571 ptr2++;
572 if (*ptr2 != ' ')
573 panic("Parser error!\n");
574 *ptr2 = 0;
575 cfg->whois = xstrdup(ptr);
576 ptr = ptr2 + 1;
577 if (ptr >= &tmp[sizeof(tmp) - 1])
578 panic("Parser error!\n");
579 ptr = skips(ptr);
580 ptr[strlen(ptr) - 1] = 0;
581 cfg->whois_port = xstrdup(ptr);
582 break;
584 close(fd);
587 int main(int argc, char **argv)
589 int c, opt_index, ret;
590 struct ash_cfg cfg;
592 check_for_root_maybe_die();
594 memset(&cfg, 0, sizeof(cfg));
595 cfg.init_ttl = 1;
596 cfg.max_ttl = 30;
597 cfg.queries = 3;
598 cfg.timeout = 3;
599 cfg.ip = 4;
600 cfg.dev = xstrdup("eth0");
601 cfg.port = xstrdup("80");
603 while ((c = getopt_long(argc, argv, short_options, long_options,
604 &opt_index)) != EOF) {
605 switch (c) {
606 case 'h':
607 help();
608 break;
609 case 'v':
610 version();
611 break;
612 case 'H':
613 cfg.host = xstrdup(optarg);
614 break;
615 case 'p':
616 if (cfg.port)
617 xfree(cfg.port);
618 cfg.port = xstrdup(optarg);
619 break;
620 case 'n':
621 cfg.dns_resolv = 0;
622 break;
623 case '4':
624 cfg.ip = 4;
625 break;
626 case '6':
627 cfg.ip = 6;
628 break;
629 case 'N':
630 cfg.dns_resolv = 1;
631 break;
632 case 'f':
633 cfg.init_ttl = atoi(optarg);
634 if (cfg.init_ttl <= 0)
635 help();
636 break;
637 case 'm':
638 cfg.max_ttl = atoi(optarg);
639 if (cfg.max_ttl <= 0)
640 help();
641 break;
642 case 'i':
643 case 'd':
644 if (cfg.dev)
645 xfree(cfg.dev);
646 cfg.dev = xstrdup(optarg);
647 break;
648 case 'q':
649 cfg.queries = atoi(optarg);
650 if (cfg.queries <= 0)
651 help();
652 break;
653 case 'x':
654 cfg.timeout = atoi(optarg);
655 if (cfg.timeout <= 0)
656 help();
657 break;
658 case 'S':
659 cfg.syn = 1;
660 break;
661 case 'A':
662 cfg.ack = 1;
663 break;
664 case 'F':
665 cfg.fin = 1;
666 break;
667 case 'U':
668 cfg.urg = 1;
669 break;
670 case 'P':
671 cfg.psh = 1;
672 break;
673 case 'R':
674 cfg.rst = 1;
675 break;
676 case 'E':
677 cfg.syn = 1;
678 cfg.ecn = 1;
679 break;
680 case 't':
681 cfg.tos = atoi(optarg);
682 if (cfg.tos < 0)
683 help();
684 break;
685 case 'G':
686 cfg.nofrag = 1;
687 break;
688 case 'l':
689 cfg.totlen = atoi(optarg);
690 if (cfg.totlen <= 0)
691 help();
692 break;
693 case 'w':
694 cfg.whois = xstrdup(optarg);
695 break;
696 case 'W':
697 cfg.whois_port = xstrdup(optarg);
698 break;
699 case '?':
700 switch (optopt) {
701 case 'H':
702 case 'p':
703 case 'f':
704 case 'm':
705 case 'i':
706 case 'd':
707 case 'q':
708 case 'x':
709 case 't':
710 case 'l':
711 case 'w':
712 case 'W':
713 panic("Option -%c requires an argument!\n",
714 optopt);
715 default:
716 if (isprint(optopt))
717 whine("Unknown option character "
718 "`0x%X\'!\n", optopt);
719 die();
721 default:
722 break;
726 if (argc < 3 ||
727 !cfg.host || !cfg.port ||
728 cfg.init_ttl > cfg.max_ttl ||
729 cfg.init_ttl > MAXTTL ||
730 cfg.max_ttl > MAXTTL)
731 help();
732 if (!device_up_and_running(cfg.dev))
733 panic("Networking device not up and running!\n");
734 if (!cfg.whois || !cfg.whois_port)
735 parse_whois_or_die(&cfg);
736 if (device_mtu(cfg.dev) <= cfg.totlen)
737 panic("Packet larger than device MTU!\n");
738 if (!cfg.syn && !cfg.ack && !cfg.fin && !cfg.urg && !cfg.psh &&
739 !cfg.ecn && !cfg.rst)
740 cfg.syn = 1;
741 register_signal(SIGHUP, signal_handler);
743 header();
744 ret = aslookup_prepare(cfg.whois, cfg.whois_port);
745 if (ret < 0)
746 panic("Cannot resolve whois server!\n");
747 ret = do_trace(&cfg);
749 if (cfg.whois_port)
750 xfree(cfg.whois_port);
751 if (cfg.whois)
752 xfree(cfg.whois);
753 if (cfg.dev)
754 xfree(cfg.dev);
755 if (cfg.host)
756 xfree(cfg.host);
757 if (cfg.port)
758 xfree(cfg.port);
759 return ret;