adig.c (48111B)
1 /* MIT License 2 * 3 * Copyright (c) 1998 Massachusetts Institute of Technology 4 * Copyright (c) The c-ares project and its contributors 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 * 25 * SPDX-License-Identifier: MIT 26 */ 27 #include "ares_setup.h" 28 29 #ifdef HAVE_NETINET_IN_H 30 # include <netinet/in.h> 31 #endif 32 #ifdef HAVE_ARPA_INET_H 33 # include <arpa/inet.h> 34 #endif 35 #ifdef HAVE_NETDB_H 36 # include <netdb.h> 37 #endif 38 39 #include "ares_nameser.h" 40 41 #ifdef HAVE_STRINGS_H 42 # include <strings.h> 43 #endif 44 45 #include "ares.h" 46 #include "ares_array.h" 47 #include "ares_buf.h" 48 #include "ares_dns.h" 49 #include "ares_getopt.h" 50 #include "ares_mem.h" 51 #include "ares_str.h" 52 53 #include "limits.h" 54 55 #ifndef PATH_MAX 56 # define PATH_MAX 1024 57 #endif 58 59 typedef struct { 60 unsigned short port; 61 size_t tries; 62 size_t ndots; 63 ares_bool_t tcp; 64 ares_bool_t ignore_tc; 65 char *search; 66 ares_bool_t do_search; 67 ares_bool_t aa_flag; 68 ares_bool_t ad_flag; 69 ares_bool_t cd_flag; 70 ares_bool_t rd_flag; 71 /* ares_bool_t do_flag; */ 72 ares_bool_t edns; 73 size_t udp_size; 74 ares_bool_t primary; 75 ares_bool_t aliases; 76 ares_bool_t stayopen; 77 ares_bool_t dns0x20; 78 ares_bool_t display_class; 79 ares_bool_t display_ttl; 80 ares_bool_t display_command; 81 ares_bool_t display_stats; 82 ares_bool_t display_query; 83 ares_bool_t display_question; 84 ares_bool_t display_answer; 85 ares_bool_t display_authority; 86 ares_bool_t display_additional; 87 ares_bool_t display_comments; 88 } dns_options_t; 89 90 typedef struct { 91 dns_options_t opts; 92 ares_bool_t is_help; 93 ares_bool_t no_rcfile; 94 struct ares_options options; 95 int optmask; 96 ares_dns_class_t qclass; 97 ares_dns_rec_type_t qtype; 98 char *name; 99 char *servers; 100 char error[256]; 101 } adig_config_t; 102 103 static adig_config_t global_config; 104 105 106 static const char *helpstr[] = { 107 "usage: adig [@server] [-c class] [-p port#] [-q name] [-t type] [-x addr]", 108 " [name] [type] [class] [queryopt...]", 109 "", 110 "@server: server ip address. May specify multiple in comma delimited " 111 "format.", 112 " may be specified in URI format", 113 "name: name of the resource record that is to be looked up", 114 "type: what type of query is required. e.g. - A, AAAA, MX, TXT, etc. If", 115 " no specified, A will be used.", 116 "class: Sets the query class, defaults to IN. May also be HS or CH.", 117 "", 118 "FLAGS", 119 "-c class: Sets the query class, defaults to IN. May also be HS or CH.", 120 "-h: Prints this help.", 121 "-p port: Sends query to a port other than 53. Often recommended to set", 122 " the port using @server instead.", 123 "-q name: Specifies the domain name to query. Useful to distinguish name", 124 " from other arguments", 125 "-r: Skip adigrc processing", 126 "-s: Server (alias for @server syntax), compatibility with old cmdline", 127 "-t type: Indicates resource record type to query. Useful to distinguish", 128 " type from other arguments", 129 "-x addr: Simplified reverse lookups. Sets the type to PTR and forms a", 130 " valid in-arpa query string", 131 "", 132 "QUERY OPTIONS", 133 "+[no]aaonly: Sets the aa flag in the query. Default is off.", 134 "+[no]aaflag: Alias for +[no]aaonly", 135 "+[no]additional: Toggles printing the additional section. On by default.", 136 "+[no]adflag: Sets the ad (authentic data) bit in the query. Default is", 137 " off.", 138 "+[no]aliases: Whether or not to honor the HOSTALIASES file. Default is", 139 " on.", 140 "+[no]all: Toggles all of +[no]cmd, +[no]stats, +[no]question,", 141 " +[no]answer, +[no]authority, +[no]additional, " 142 "+[no]comments", 143 "+[no]answer: Toggles printing the answer. On by default.", 144 "+[no]authority: Toggles printing the authority. On by default.", 145 "+bufsize=#: UDP EDNS 0 packet size allowed. Defaults to 1232.", 146 "+[no]cdflag: Sets the CD (checking disabled) bit in the query. Default", 147 " is off.", 148 "+[no]class: Display the class when printing the record. On by " 149 "default.", 150 "+[no]cmd: Toggles printing the command requested. On by default.", 151 "+[no]comments: Toggles printing the comments. On by default", 152 "+[no]defname: Alias for +[no]search", 153 "+domain=somename: Sets the search list to a single domain.", 154 "+[no]dns0x20: Whether or not to use DNS 0x20 case randomization when", 155 " sending queries. Default is off.", 156 "+[no]edns[=#]: Enable or disable EDNS. Only allows a value of 0 if", 157 " specified. Default is to enable EDNS.", 158 "+[no]ignore: Ignore truncation on UDP, by default retried on TCP.", 159 "+[no]keepopen: Whether or not the server connection should be " 160 "persistent.", 161 " Default is off.", 162 "+ndots=#: Sets the number of dots that must appear before being", 163 " considered absolute. Defaults to 1.", 164 "+[no]primary: Whether or not to only use a single server if more than " 165 "one", 166 " server is available. Defaults to using all servers.", 167 "+[no]qr: Toggles printing the request query. Off by default.", 168 "+[no]question: Toggles printing the question. On by default.", 169 "+[no]recurse: Toggles the RD (Recursion Desired) bit. On by default.", 170 "+retry=#: Same as +tries but does not include the initial attempt.", 171 "+[no]search: To use or not use the search list. Search list is not " 172 "used", 173 " by default.", 174 "+[no]stats: Toggles printing the statistics. On by default.", 175 "+[no]tcp: Whether to use TCP when querying name servers. Default is", 176 " UDP.", 177 "+tries=#: Number of query tries. Defaults to 3.", 178 "+[no]ttlid: Display the TTL when printing the record. On by default.", 179 "+[no]vc: Alias for +[no]tcp", 180 "", 181 NULL 182 }; 183 184 static void free_config(void) 185 { 186 free(global_config.servers); 187 free(global_config.name); 188 free(global_config.opts.search); 189 memset(&global_config, 0, sizeof(global_config)); 190 } 191 192 static void print_help(void) 193 { 194 size_t i; 195 printf("adig version %s\n\n", ares_version(NULL)); 196 for (i = 0; helpstr[i] != NULL; i++) { 197 printf("%s\n", helpstr[i]); 198 } 199 } 200 201 static void print_flags(ares_dns_flags_t flags) 202 { 203 if (flags & ARES_FLAG_QR) { 204 printf(" qr"); 205 } 206 if (flags & ARES_FLAG_AA) { 207 printf(" aa"); 208 } 209 if (flags & ARES_FLAG_TC) { 210 printf(" tc"); 211 } 212 if (flags & ARES_FLAG_RD) { 213 printf(" rd"); 214 } 215 if (flags & ARES_FLAG_RA) { 216 printf(" ra"); 217 } 218 if (flags & ARES_FLAG_AD) { 219 printf(" ad"); 220 } 221 if (flags & ARES_FLAG_CD) { 222 printf(" cd"); 223 } 224 } 225 226 static void print_header(const ares_dns_record_t *dnsrec) 227 { 228 printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n", 229 ares_dns_opcode_tostr(ares_dns_record_get_opcode(dnsrec)), 230 ares_dns_rcode_tostr(ares_dns_record_get_rcode(dnsrec)), 231 ares_dns_record_get_id(dnsrec)); 232 printf(";; flags:"); 233 print_flags(ares_dns_record_get_flags(dnsrec)); 234 printf("; QUERY: %u, ANSWER: %u, AUTHORITY: %u, ADDITIONAL: %u\n\n", 235 (unsigned int)ares_dns_record_query_cnt(dnsrec), 236 (unsigned int)ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER), 237 (unsigned int)ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_AUTHORITY), 238 (unsigned int)ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ADDITIONAL)); 239 } 240 241 static void print_question(const ares_dns_record_t *dnsrec) 242 { 243 size_t i; 244 245 if (global_config.opts.display_comments) { 246 printf(";; QUESTION SECTION:\n"); 247 } 248 249 for (i = 0; i < ares_dns_record_query_cnt(dnsrec); i++) { 250 const char *name; 251 ares_dns_rec_type_t qtype; 252 ares_dns_class_t qclass; 253 size_t len; 254 if (ares_dns_record_query_get(dnsrec, i, &name, &qtype, &qclass) != 255 ARES_SUCCESS) { 256 return; 257 } 258 if (name == NULL) { 259 return; 260 } 261 len = strlen(name); 262 printf(";%s.\t", name); 263 if (len + 1 < 24) { 264 printf("\t"); 265 } 266 if (len + 1 < 16) { 267 printf("\t"); 268 } 269 270 if (global_config.opts.display_class) { 271 printf("%s\t", ares_dns_class_tostr(qclass)); 272 } 273 274 printf("%s\n", ares_dns_rec_type_tostr(qtype)); 275 } 276 277 if (global_config.opts.display_comments) { 278 printf("\n"); 279 } 280 } 281 282 static void print_opt_none(const unsigned char *val, size_t val_len) 283 { 284 (void)val; 285 if (val_len != 0) { 286 printf("INVALID!"); 287 } 288 } 289 290 static void print_opt_addr_list(const unsigned char *val, size_t val_len) 291 { 292 size_t i; 293 if (val_len % 4 != 0) { 294 printf("INVALID!"); 295 return; 296 } 297 for (i = 0; i < val_len; i += 4) { 298 char buf[256] = ""; 299 ares_inet_ntop(AF_INET, val + i, buf, sizeof(buf)); 300 if (i != 0) { 301 printf(","); 302 } 303 printf("%s", buf); 304 } 305 } 306 307 static void print_opt_addr6_list(const unsigned char *val, size_t val_len) 308 { 309 size_t i; 310 if (val_len % 16 != 0) { 311 printf("INVALID!"); 312 return; 313 } 314 for (i = 0; i < val_len; i += 16) { 315 char buf[256] = ""; 316 317 ares_inet_ntop(AF_INET6, val + i, buf, sizeof(buf)); 318 if (i != 0) { 319 printf(","); 320 } 321 printf("%s", buf); 322 } 323 } 324 325 static void print_opt_u8_list(const unsigned char *val, size_t val_len) 326 { 327 size_t i; 328 329 for (i = 0; i < val_len; i++) { 330 if (i != 0) { 331 printf(","); 332 } 333 printf("%u", (unsigned int)val[i]); 334 } 335 } 336 337 static void print_opt_u16_list(const unsigned char *val, size_t val_len) 338 { 339 size_t i; 340 if (val_len < 2 || val_len % 2 != 0) { 341 printf("INVALID!"); 342 return; 343 } 344 for (i = 0; i < val_len; i += 2) { 345 unsigned short u16 = 0; 346 unsigned short c; 347 /* Jumping over backwards to try to avoid odd compiler warnings */ 348 c = (unsigned short)val[i]; 349 u16 |= (unsigned short)((c << 8) & 0xFFFF); 350 c = (unsigned short)val[i + 1]; 351 u16 |= c; 352 if (i != 0) { 353 printf(","); 354 } 355 printf("%u", (unsigned int)u16); 356 } 357 } 358 359 static void print_opt_u32_list(const unsigned char *val, size_t val_len) 360 { 361 size_t i; 362 if (val_len < 4 || val_len % 4 != 0) { 363 printf("INVALID!"); 364 return; 365 } 366 for (i = 0; i < val_len; i += 4) { 367 unsigned int u32 = 0; 368 369 u32 |= (unsigned int)(val[i] << 24); 370 u32 |= (unsigned int)(val[i + 1] << 16); 371 u32 |= (unsigned int)(val[i + 2] << 8); 372 u32 |= (unsigned int)(val[i + 3]); 373 if (i != 0) { 374 printf(","); 375 } 376 printf("%u", u32); 377 } 378 } 379 380 static void print_opt_str_list(const unsigned char *val, size_t val_len) 381 { 382 size_t cnt = 0; 383 384 printf("\""); 385 while (val_len) { 386 long read_len = 0; 387 unsigned char *str = NULL; 388 ares_status_t status; 389 390 if (cnt) { 391 printf(","); 392 } 393 394 status = (ares_status_t)ares_expand_string(val, val, (int)val_len, &str, 395 &read_len); 396 if (status != ARES_SUCCESS) { 397 printf("INVALID"); 398 break; 399 } 400 printf("%s", str); 401 ares_free_string(str); 402 val_len -= (size_t)read_len; 403 val += read_len; 404 cnt++; 405 } 406 printf("\""); 407 } 408 409 static void print_opt_name(const unsigned char *val, size_t val_len) 410 { 411 char *str = NULL; 412 long read_len = 0; 413 414 if (ares_expand_name(val, val, (int)val_len, &str, &read_len) != 415 ARES_SUCCESS) { 416 printf("INVALID!"); 417 return; 418 } 419 420 printf("%s.", str); 421 ares_free_string(str); 422 } 423 424 static void print_opt_bin(const unsigned char *val, size_t val_len) 425 { 426 size_t i; 427 428 for (i = 0; i < val_len; i++) { 429 printf("%02x", (unsigned int)val[i]); 430 } 431 } 432 433 static ares_bool_t adig_isprint(int ch) 434 { 435 if (ch >= 0x20 && ch <= 0x7E) { 436 return ARES_TRUE; 437 } 438 return ARES_FALSE; 439 } 440 441 static void print_opt_binp(const unsigned char *val, size_t val_len) 442 { 443 size_t i; 444 printf("\""); 445 for (i = 0; i < val_len; i++) { 446 if (adig_isprint(val[i])) { 447 printf("%c", val[i]); 448 } else { 449 printf("\\%03d", val[i]); 450 } 451 } 452 printf("\""); 453 } 454 455 static void print_opts(const ares_dns_rr_t *rr, ares_dns_rr_key_t key) 456 { 457 size_t i; 458 459 for (i = 0; i < ares_dns_rr_get_opt_cnt(rr, key); i++) { 460 size_t val_len = 0; 461 const unsigned char *val = NULL; 462 unsigned short opt; 463 const char *name; 464 465 if (i != 0) { 466 printf(" "); 467 } 468 469 opt = ares_dns_rr_get_opt(rr, key, i, &val, &val_len); 470 name = ares_dns_opt_get_name(key, opt); 471 if (name == NULL) { 472 printf("key%u", (unsigned int)opt); 473 } else { 474 printf("%s", name); 475 } 476 if (val_len == 0) { 477 return; 478 } 479 480 printf("="); 481 482 switch (ares_dns_opt_get_datatype(key, opt)) { 483 case ARES_OPT_DATATYPE_NONE: 484 print_opt_none(val, val_len); 485 break; 486 case ARES_OPT_DATATYPE_U8_LIST: 487 print_opt_u8_list(val, val_len); 488 break; 489 case ARES_OPT_DATATYPE_INADDR4_LIST: 490 print_opt_addr_list(val, val_len); 491 break; 492 case ARES_OPT_DATATYPE_INADDR6_LIST: 493 print_opt_addr6_list(val, val_len); 494 break; 495 case ARES_OPT_DATATYPE_U16: 496 case ARES_OPT_DATATYPE_U16_LIST: 497 print_opt_u16_list(val, val_len); 498 break; 499 case ARES_OPT_DATATYPE_U32: 500 case ARES_OPT_DATATYPE_U32_LIST: 501 print_opt_u32_list(val, val_len); 502 break; 503 case ARES_OPT_DATATYPE_STR_LIST: 504 print_opt_str_list(val, val_len); 505 break; 506 case ARES_OPT_DATATYPE_BIN: 507 print_opt_bin(val, val_len); 508 break; 509 case ARES_OPT_DATATYPE_NAME: 510 print_opt_name(val, val_len); 511 break; 512 } 513 } 514 } 515 516 static void print_addr(const ares_dns_rr_t *rr, ares_dns_rr_key_t key) 517 { 518 const struct in_addr *addr = ares_dns_rr_get_addr(rr, key); 519 char buf[256] = ""; 520 521 ares_inet_ntop(AF_INET, addr, buf, sizeof(buf)); 522 printf("%s", buf); 523 } 524 525 static void print_addr6(const ares_dns_rr_t *rr, ares_dns_rr_key_t key) 526 { 527 const struct ares_in6_addr *addr = ares_dns_rr_get_addr6(rr, key); 528 char buf[256] = ""; 529 530 ares_inet_ntop(AF_INET6, addr, buf, sizeof(buf)); 531 printf("%s", buf); 532 } 533 534 static void print_u8(const ares_dns_rr_t *rr, ares_dns_rr_key_t key) 535 { 536 unsigned char u8 = ares_dns_rr_get_u8(rr, key); 537 printf("%u", (unsigned int)u8); 538 } 539 540 static void print_u16(const ares_dns_rr_t *rr, ares_dns_rr_key_t key) 541 { 542 unsigned short u16 = ares_dns_rr_get_u16(rr, key); 543 printf("%u", (unsigned int)u16); 544 } 545 546 static void print_u32(const ares_dns_rr_t *rr, ares_dns_rr_key_t key) 547 { 548 unsigned int u32 = ares_dns_rr_get_u32(rr, key); 549 printf("%u", u32); 550 } 551 552 static void print_name(const ares_dns_rr_t *rr, ares_dns_rr_key_t key) 553 { 554 const char *str = ares_dns_rr_get_str(rr, key); 555 printf("%s.", str); 556 } 557 558 static void print_str(const ares_dns_rr_t *rr, ares_dns_rr_key_t key) 559 { 560 const char *str = ares_dns_rr_get_str(rr, key); 561 printf("\"%s\"", str); 562 } 563 564 static void print_bin(const ares_dns_rr_t *rr, ares_dns_rr_key_t key) 565 { 566 size_t len = 0; 567 const unsigned char *binp = ares_dns_rr_get_bin(rr, key, &len); 568 print_opt_bin(binp, len); 569 } 570 571 static void print_binp(const ares_dns_rr_t *rr, ares_dns_rr_key_t key) 572 { 573 size_t len; 574 const unsigned char *binp = ares_dns_rr_get_bin(rr, key, &len); 575 576 print_opt_binp(binp, len); 577 } 578 579 static void print_abinp(const ares_dns_rr_t *rr, ares_dns_rr_key_t key) 580 { 581 size_t i; 582 size_t cnt = ares_dns_rr_get_abin_cnt(rr, key); 583 584 for (i = 0; i < cnt; i++) { 585 size_t len; 586 const unsigned char *binp = ares_dns_rr_get_abin(rr, key, i, &len); 587 if (i != 0) { 588 printf(" "); 589 } 590 print_opt_binp(binp, len); 591 } 592 } 593 594 static void print_rr(const ares_dns_rr_t *rr) 595 { 596 const char *name = ares_dns_rr_get_name(rr); 597 size_t len = 0; 598 size_t keys_cnt = 0; 599 ares_dns_rec_type_t rtype = ares_dns_rr_get_type(rr); 600 const ares_dns_rr_key_t *keys = ares_dns_rr_get_keys(rtype, &keys_cnt); 601 size_t i; 602 603 if (name == NULL) { 604 return; 605 } 606 607 len = strlen(name); 608 609 printf("%s.\t", name); 610 if (len < 24) { 611 printf("\t"); 612 } 613 614 if (global_config.opts.display_ttl) { 615 printf("%u\t", ares_dns_rr_get_ttl(rr)); 616 } 617 618 if (global_config.opts.display_class) { 619 printf("%s\t", ares_dns_class_tostr(ares_dns_rr_get_class(rr))); 620 } 621 622 printf("%s\t", ares_dns_rec_type_tostr(rtype)); 623 624 /* Output params here */ 625 for (i = 0; i < keys_cnt; i++) { 626 ares_dns_datatype_t datatype = ares_dns_rr_key_datatype(keys[i]); 627 if (i != 0) { 628 printf(" "); 629 } 630 631 switch (datatype) { 632 case ARES_DATATYPE_INADDR: 633 print_addr(rr, keys[i]); 634 break; 635 case ARES_DATATYPE_INADDR6: 636 print_addr6(rr, keys[i]); 637 break; 638 case ARES_DATATYPE_U8: 639 print_u8(rr, keys[i]); 640 break; 641 case ARES_DATATYPE_U16: 642 print_u16(rr, keys[i]); 643 break; 644 case ARES_DATATYPE_U32: 645 print_u32(rr, keys[i]); 646 break; 647 case ARES_DATATYPE_NAME: 648 print_name(rr, keys[i]); 649 break; 650 case ARES_DATATYPE_STR: 651 print_str(rr, keys[i]); 652 break; 653 case ARES_DATATYPE_BIN: 654 print_bin(rr, keys[i]); 655 break; 656 case ARES_DATATYPE_BINP: 657 print_binp(rr, keys[i]); 658 break; 659 case ARES_DATATYPE_ABINP: 660 print_abinp(rr, keys[i]); 661 break; 662 case ARES_DATATYPE_OPT: 663 print_opts(rr, keys[i]); 664 break; 665 } 666 } 667 668 printf("\n"); 669 } 670 671 static const ares_dns_rr_t *has_opt(const ares_dns_record_t *dnsrec, 672 ares_dns_section_t section) 673 { 674 size_t i; 675 for (i = 0; i < ares_dns_record_rr_cnt(dnsrec, section); i++) { 676 const ares_dns_rr_t *rr = ares_dns_record_rr_get_const(dnsrec, section, i); 677 if (ares_dns_rr_get_type(rr) == ARES_REC_TYPE_OPT) { 678 return rr; 679 } 680 } 681 return NULL; 682 } 683 684 static void print_section(const ares_dns_record_t *dnsrec, 685 ares_dns_section_t section) 686 { 687 size_t i; 688 689 if (ares_dns_record_rr_cnt(dnsrec, section) == 0 || 690 (ares_dns_record_rr_cnt(dnsrec, section) == 1 && 691 has_opt(dnsrec, section) != NULL)) { 692 return; 693 } 694 695 if (global_config.opts.display_comments) { 696 printf(";; %s SECTION:\n", ares_dns_section_tostr(section)); 697 } 698 for (i = 0; i < ares_dns_record_rr_cnt(dnsrec, section); i++) { 699 const ares_dns_rr_t *rr = ares_dns_record_rr_get_const(dnsrec, section, i); 700 if (ares_dns_rr_get_type(rr) == ARES_REC_TYPE_OPT) { 701 continue; 702 } 703 print_rr(rr); 704 } 705 if (global_config.opts.display_comments) { 706 printf("\n"); 707 } 708 } 709 710 static void print_opt_psuedosection(const ares_dns_record_t *dnsrec) 711 { 712 const ares_dns_rr_t *rr = has_opt(dnsrec, ARES_SECTION_ADDITIONAL); 713 const unsigned char *cookie = NULL; 714 size_t cookie_len = 0; 715 716 if (rr == NULL) { 717 return; 718 } 719 720 if (!ares_dns_rr_get_opt_byid(rr, ARES_RR_OPT_OPTIONS, ARES_OPT_PARAM_COOKIE, 721 &cookie, &cookie_len)) { 722 cookie = NULL; 723 } 724 725 printf(";; OPT PSEUDOSECTION:\n"); 726 printf("; EDNS: version: %u, flags: %u; udp: %u\n", 727 (unsigned int)ares_dns_rr_get_u8(rr, ARES_RR_OPT_VERSION), 728 (unsigned int)ares_dns_rr_get_u16(rr, ARES_RR_OPT_FLAGS), 729 (unsigned int)ares_dns_rr_get_u16(rr, ARES_RR_OPT_UDP_SIZE)); 730 731 if (cookie) { 732 printf("; COOKIE: "); 733 print_opt_bin(cookie, cookie_len); 734 printf(" (good)\n"); 735 } 736 } 737 738 static void print_record(const ares_dns_record_t *dnsrec) 739 { 740 if (global_config.opts.display_comments) { 741 print_header(dnsrec); 742 print_opt_psuedosection(dnsrec); 743 } 744 745 if (global_config.opts.display_question) { 746 print_question(dnsrec); 747 } 748 749 if (global_config.opts.display_answer) { 750 print_section(dnsrec, ARES_SECTION_ANSWER); 751 } 752 753 if (global_config.opts.display_additional) { 754 print_section(dnsrec, ARES_SECTION_ADDITIONAL); 755 } 756 757 if (global_config.opts.display_authority) { 758 print_section(dnsrec, ARES_SECTION_AUTHORITY); 759 } 760 761 if (global_config.opts.display_stats) { 762 unsigned char *abuf = NULL; 763 size_t alen = 0; 764 ares_dns_write(dnsrec, &abuf, &alen); 765 printf(";; MSG SIZE rcvd: %d\n\n", (int)alen); 766 ares_free_string(abuf); 767 } 768 } 769 770 static void callback(void *arg, ares_status_t status, size_t timeouts, 771 const ares_dns_record_t *dnsrec) 772 { 773 (void)arg; 774 (void)timeouts; 775 776 if (global_config.opts.display_comments) { 777 /* We got a "Server status" */ 778 if (status >= ARES_SUCCESS && status <= ARES_EREFUSED) { 779 printf(";; Got answer:"); 780 } else { 781 printf(";;"); 782 } 783 if (status != ARES_SUCCESS) { 784 printf(" %s", ares_strerror((int)status)); 785 } 786 printf("\n"); 787 } 788 789 print_record(dnsrec); 790 } 791 792 static ares_status_t enqueue_query(ares_channel_t *channel) 793 { 794 ares_dns_record_t *dnsrec = NULL; 795 ares_dns_rr_t *rr = NULL; 796 ares_status_t status; 797 unsigned short flags = 0; 798 char *nametemp = NULL; 799 const char *name = global_config.name; 800 801 if (global_config.opts.aa_flag) { 802 flags |= ARES_FLAG_AA; 803 } 804 805 if (global_config.opts.ad_flag) { 806 flags |= ARES_FLAG_AD; 807 } 808 809 if (global_config.opts.cd_flag) { 810 flags |= ARES_FLAG_CD; 811 } 812 813 if (global_config.opts.rd_flag) { 814 flags |= ARES_FLAG_RD; 815 } 816 817 status = ares_dns_record_create(&dnsrec, 0, flags, ARES_OPCODE_QUERY, 818 ARES_RCODE_NOERROR); 819 if (status != ARES_SUCCESS) { 820 goto done; 821 } 822 823 /* If it is a PTR record, convert from ip address into in-arpa form 824 * automatically */ 825 if (global_config.qtype == ARES_REC_TYPE_PTR) { 826 struct ares_addr addr; 827 size_t len; 828 addr.family = AF_UNSPEC; 829 830 if (ares_dns_pton(name, &addr, &len) != NULL) { 831 nametemp = ares_dns_addr_to_ptr(&addr); 832 name = nametemp; 833 } 834 } 835 836 status = ares_dns_record_query_add(dnsrec, name, global_config.qtype, 837 global_config.qclass); 838 if (status != ARES_SUCCESS) { 839 goto done; 840 } 841 842 if (global_config.opts.edns) { 843 status = ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "", 844 ARES_REC_TYPE_OPT, ARES_CLASS_IN, 0); 845 if (status != ARES_SUCCESS) { 846 goto done; 847 } 848 ares_dns_rr_set_u16(rr, ARES_RR_OPT_UDP_SIZE, 849 (unsigned short)global_config.opts.udp_size); 850 ares_dns_rr_set_u8(rr, ARES_RR_OPT_VERSION, 0); 851 } 852 853 if (global_config.opts.display_query) { 854 printf(";; Sending:\n"); 855 print_record(dnsrec); 856 } 857 858 if (global_config.opts.do_search) { 859 status = ares_search_dnsrec(channel, dnsrec, callback, NULL); 860 } else { 861 status = ares_send_dnsrec(channel, dnsrec, callback, NULL, NULL); 862 } 863 864 done: 865 ares_free_string(nametemp); 866 ares_dns_record_destroy(dnsrec); 867 return status; 868 } 869 870 static int event_loop(ares_channel_t *channel) 871 { 872 while (1) { 873 fd_set read_fds; 874 fd_set write_fds; 875 int nfds; 876 struct timeval tv; 877 struct timeval *tvp; 878 int count; 879 880 FD_ZERO(&read_fds); 881 FD_ZERO(&write_fds); 882 memset(&tv, 0, sizeof(tv)); 883 884 nfds = ares_fds(channel, &read_fds, &write_fds); 885 if (nfds == 0) { 886 break; 887 } 888 tvp = ares_timeout(channel, NULL, &tv); 889 if (tvp == NULL) { 890 break; 891 } 892 count = select(nfds, &read_fds, &write_fds, NULL, tvp); 893 if (count < 0) { 894 #ifdef USE_WINSOCK 895 int err = WSAGetLastError(); 896 #else 897 int err = errno; 898 #endif 899 if (err != EAGAIN && err != EINTR) { 900 fprintf(stderr, "select fail: %d", err); 901 return 1; 902 } 903 } 904 ares_process(channel, &read_fds, &write_fds); 905 } 906 return 0; 907 } 908 909 typedef enum { 910 OPT_TYPE_BOOL, 911 OPT_TYPE_STRING, 912 OPT_TYPE_SIZE_T, 913 OPT_TYPE_U16, 914 OPT_TYPE_FUNC 915 } opt_type_t; 916 917 /* Callback called with OPT_TYPE_FUNC when processing options. 918 * \param[in] prefix prefix character for option 919 * \param[in] name name for option 920 * \param[in] is_true ARES_TRUE unless option was prefixed with 'no' 921 * \param[in] value value for option 922 * \return ARES_TRUE on success, ARES_FALSE on failure. Should fill in 923 * global_config.error on error */ 924 typedef ares_bool_t (*dig_opt_cb_t)(char prefix, const char *name, 925 ares_bool_t is_true, const char *value); 926 927 static ares_bool_t opt_class_cb(char prefix, const char *name, 928 ares_bool_t is_true, const char *value) 929 { 930 (void)prefix; 931 (void)name; 932 (void)is_true; 933 934 if (!ares_dns_class_fromstr(&global_config.qclass, value)) { 935 snprintf(global_config.error, sizeof(global_config.error), 936 "unrecognized class %s", value); 937 return ARES_FALSE; 938 } 939 940 return ARES_TRUE; 941 } 942 943 static ares_bool_t opt_type_cb(char prefix, const char *name, 944 ares_bool_t is_true, const char *value) 945 { 946 (void)prefix; 947 (void)name; 948 (void)is_true; 949 950 if (!ares_dns_rec_type_fromstr(&global_config.qtype, value)) { 951 snprintf(global_config.error, sizeof(global_config.error), 952 "unrecognized record type %s", value); 953 return ARES_FALSE; 954 } 955 return ARES_TRUE; 956 } 957 958 static ares_bool_t opt_ptr_cb(char prefix, const char *name, 959 ares_bool_t is_true, const char *value) 960 { 961 (void)prefix; 962 (void)name; 963 (void)is_true; 964 global_config.qtype = ARES_REC_TYPE_PTR; 965 ares_free(global_config.name); 966 global_config.name = strdup(value); 967 return ARES_TRUE; 968 } 969 970 static ares_bool_t opt_all_cb(char prefix, const char *name, 971 ares_bool_t is_true, const char *value) 972 { 973 (void)prefix; 974 (void)name; 975 (void)value; 976 977 global_config.opts.display_command = is_true; 978 global_config.opts.display_stats = is_true; 979 global_config.opts.display_question = is_true; 980 global_config.opts.display_answer = is_true; 981 global_config.opts.display_authority = is_true; 982 global_config.opts.display_additional = is_true; 983 global_config.opts.display_comments = is_true; 984 return ARES_TRUE; 985 } 986 987 static ares_bool_t opt_edns_cb(char prefix, const char *name, 988 ares_bool_t is_true, const char *value) 989 { 990 (void)prefix; 991 (void)name; 992 993 global_config.opts.edns = is_true; 994 if (is_true && value != NULL && atoi(value) > 0) { 995 snprintf(global_config.error, sizeof(global_config.error), 996 "edns 0 only supported"); 997 return ARES_FALSE; 998 } 999 return ARES_TRUE; 1000 } 1001 1002 static ares_bool_t opt_retry_cb(char prefix, const char *name, 1003 ares_bool_t is_true, const char *value) 1004 { 1005 (void)prefix; 1006 (void)name; 1007 (void)is_true; 1008 1009 if (!ares_str_isnum(value)) { 1010 snprintf(global_config.error, sizeof(global_config.error), 1011 "value not numeric"); 1012 return ARES_FALSE; 1013 } 1014 1015 global_config.opts.tries = strtoul(value, NULL, 10) + 1; 1016 return ARES_TRUE; 1017 } 1018 1019 static ares_bool_t opt_dig_bare_cb(char prefix, const char *name, 1020 ares_bool_t is_true, const char *value) 1021 { 1022 (void)prefix; 1023 (void)name; 1024 (void)is_true; 1025 1026 /* Handle @servers */ 1027 if (*value == '@') { 1028 free(global_config.servers); 1029 global_config.servers = strdup(value + 1); 1030 return ARES_TRUE; 1031 } 1032 1033 /* Make sure we don't pass options */ 1034 if (*value == '-' || *value == '+') { 1035 snprintf(global_config.error, sizeof(global_config.error), 1036 "unrecognized argument %s", value); 1037 return ARES_FALSE; 1038 } 1039 1040 /* See if it is a DNS class */ 1041 if (ares_dns_class_fromstr(&global_config.qclass, value)) { 1042 return ARES_TRUE; 1043 } 1044 1045 /* See if it is a DNS record type */ 1046 if (ares_dns_rec_type_fromstr(&global_config.qtype, value)) { 1047 return ARES_TRUE; 1048 } 1049 1050 /* See if it is a domain name */ 1051 if (ares_is_hostname(value)) { 1052 free(global_config.name); 1053 global_config.name = strdup(value); 1054 return ARES_TRUE; 1055 } 1056 1057 snprintf(global_config.error, sizeof(global_config.error), 1058 "unrecognized argument %s", value); 1059 return ARES_FALSE; 1060 } 1061 1062 static const struct { 1063 /* Prefix for option. If 0 then this param is a non-option and type must be 1064 * OPT_TYPE_FUNC where the entire value for the param will be passed */ 1065 char prefix; 1066 /* Name of option. If null, there is none and the value is expected to be 1067 * immediately after the prefix character */ 1068 const char *name; 1069 /* Separator between key and value. If 0 then uses the next argument as the 1070 * value, otherwise splits on the separator. BOOL types won't ever use a 1071 * separator and is ignored.*/ 1072 char separator; 1073 /* Type of parameter passed in. If it is OPT_TYPE_FUNC, then it calls the 1074 * dig_opt_cb_t callback */ 1075 opt_type_t type; 1076 /* Pointer to argument to fill in */ 1077 void *opt; 1078 /* Callback if OPT_TYPE_FUNC */ 1079 dig_opt_cb_t cb; 1080 } dig_options[] = { 1081 /* -4 (ipv4 only) */ 1082 /* -6 (ipv6 only) */ 1083 /* { '-', "b", 0, OPT_TYPE_FUNC, NULL, opt_bind_address_cb }, 1084 */ 1085 { '-', "c", 0, OPT_TYPE_FUNC, NULL, opt_class_cb }, 1086 /* -f file */ 1087 { '-', "h", 0, OPT_TYPE_BOOL, &global_config.is_help, NULL }, 1088 /* -k keyfile */ 1089 /* -m (memory usage debugging) */ 1090 { '-', "p", 0, OPT_TYPE_U16, &global_config.opts.port, NULL }, 1091 { '-', "q", 0, OPT_TYPE_STRING, &global_config.name, NULL }, 1092 { '-', "r", 0, OPT_TYPE_BOOL, &global_config.no_rcfile, NULL }, 1093 { '-', "s", 0, OPT_TYPE_STRING, &global_config.servers, NULL }, 1094 { '-', "t", 0, OPT_TYPE_FUNC, NULL, opt_type_cb }, 1095 /* -u (print microseconds instead of milliseconds) */ 1096 { '-', "x", 0, OPT_TYPE_FUNC, NULL, opt_ptr_cb }, 1097 /* -y [hmac:]keynam:secret */ 1098 { '+', "aaflag", 0, OPT_TYPE_BOOL, &global_config.opts.aa_flag, NULL }, 1099 { '+', "aaonly", 0, OPT_TYPE_BOOL, &global_config.opts.aa_flag, NULL }, 1100 { '+', "additional", 0, OPT_TYPE_BOOL, &global_config.opts.display_additional, 1101 NULL }, 1102 { '+', "adflag", 0, OPT_TYPE_BOOL, &global_config.opts.ad_flag, NULL }, 1103 { '+', "aliases", 0, OPT_TYPE_BOOL, &global_config.opts.aliases, NULL }, 1104 { '+', "all", '=', OPT_TYPE_FUNC, NULL, opt_all_cb }, 1105 { '+', "answer", 0, OPT_TYPE_BOOL, &global_config.opts.display_answer, NULL }, 1106 { '+', "authority", 0, OPT_TYPE_BOOL, &global_config.opts.display_authority, 1107 NULL }, 1108 { '+', "bufsize", '=', OPT_TYPE_SIZE_T, &global_config.opts.udp_size, NULL }, 1109 { '+', "cdflag", 0, OPT_TYPE_BOOL, &global_config.opts.cd_flag, NULL }, 1110 { '+', "class", 0, OPT_TYPE_BOOL, &global_config.opts.display_class, NULL }, 1111 { '+', "cmd", 0, OPT_TYPE_BOOL, &global_config.opts.display_command, NULL }, 1112 { '+', "comments", 0, OPT_TYPE_BOOL, &global_config.opts.display_comments, 1113 NULL }, 1114 { '+', "defname", 0, OPT_TYPE_BOOL, &global_config.opts.do_search, NULL }, 1115 { '+', "dns0x20", 0, OPT_TYPE_BOOL, &global_config.opts.dns0x20, NULL }, 1116 { '+', "domain", '=', OPT_TYPE_STRING, &global_config.opts.search, NULL }, 1117 { '+', "edns", '=', OPT_TYPE_FUNC, NULL, opt_edns_cb }, 1118 { '+', "keepopen", 0, OPT_TYPE_BOOL, &global_config.opts.stayopen, NULL }, 1119 { '+', "ignore", 0, OPT_TYPE_BOOL, &global_config.opts.ignore_tc, NULL }, 1120 { '+', "ndots", '=', OPT_TYPE_SIZE_T, &global_config.opts.ndots, NULL }, 1121 { '+', "primary", 0, OPT_TYPE_BOOL, &global_config.opts.primary, NULL }, 1122 { '+', "qr", 0, OPT_TYPE_BOOL, &global_config.opts.display_query, NULL }, 1123 { '+', "question", 0, OPT_TYPE_BOOL, &global_config.opts.display_question, 1124 NULL }, 1125 { '+', "recurse", 0, OPT_TYPE_BOOL, &global_config.opts.rd_flag, NULL }, 1126 { '+', "retry", '=', OPT_TYPE_FUNC, NULL, opt_retry_cb }, 1127 { '+', "search", 0, OPT_TYPE_BOOL, &global_config.opts.do_search, NULL }, 1128 { '+', "stats", 0, OPT_TYPE_BOOL, &global_config.opts.display_stats, NULL }, 1129 { '+', "tcp", 0, OPT_TYPE_BOOL, &global_config.opts.tcp, NULL }, 1130 { '+', "tries", '=', OPT_TYPE_SIZE_T, &global_config.opts.tries, NULL }, 1131 { '+', "ttlid", 0, OPT_TYPE_BOOL, &global_config.opts.display_ttl, NULL }, 1132 { '+', "vc", 0, OPT_TYPE_BOOL, &global_config.opts.tcp, NULL }, 1133 { 0, NULL, 0, OPT_TYPE_FUNC, NULL, opt_dig_bare_cb }, 1134 { 0, NULL, 0, 0, NULL, NULL } 1135 }; 1136 1137 static ares_bool_t read_cmdline(int argc, const char * const *argv, 1138 int start_idx) 1139 { 1140 int arg; 1141 size_t opt; 1142 1143 for (arg = start_idx; arg < argc; arg++) { 1144 ares_bool_t option_handled = ARES_FALSE; 1145 1146 for (opt = 0; !option_handled && 1147 (dig_options[opt].opt != NULL || dig_options[opt].cb != NULL); 1148 opt++) { 1149 ares_bool_t is_true = ARES_TRUE; 1150 const char *value = NULL; 1151 const char *nameptr = NULL; 1152 size_t namelen; 1153 1154 /* Match prefix character */ 1155 if (dig_options[opt].prefix != 0 && 1156 dig_options[opt].prefix != *(argv[arg])) { 1157 continue; 1158 } 1159 1160 nameptr = argv[arg]; 1161 1162 /* skip prefix */ 1163 if (dig_options[opt].prefix != 0) { 1164 nameptr++; 1165 } 1166 1167 /* Negated option if it has a 'no' prefix */ 1168 if (ares_streq_max(nameptr, "no", 2)) { 1169 is_true = ARES_FALSE; 1170 nameptr += 2; 1171 } 1172 1173 if (dig_options[opt].separator != 0) { 1174 const char *ptr = strchr(nameptr, dig_options[opt].separator); 1175 if (ptr == NULL) { 1176 namelen = ares_strlen(nameptr); 1177 } else { 1178 namelen = (size_t)(ptr - nameptr); 1179 value = ptr + 1; 1180 } 1181 } else { 1182 namelen = ares_strlen(nameptr); 1183 } 1184 1185 /* Match name */ 1186 if (dig_options[opt].name != NULL && 1187 !ares_streq_max(nameptr, dig_options[opt].name, namelen)) { 1188 continue; 1189 } 1190 1191 if (dig_options[opt].name == NULL) { 1192 value = nameptr; 1193 } 1194 1195 /* We need another argument for the value */ 1196 if (dig_options[opt].type != OPT_TYPE_BOOL && 1197 dig_options[opt].prefix != 0 && dig_options[opt].separator == 0) { 1198 if (arg == argc - 1) { 1199 snprintf(global_config.error, sizeof(global_config.error), 1200 "insufficient arguments for %c%s", dig_options[opt].prefix, 1201 dig_options[opt].name); 1202 return ARES_FALSE; 1203 } 1204 arg++; 1205 value = argv[arg]; 1206 } 1207 1208 switch (dig_options[opt].type) { 1209 case OPT_TYPE_BOOL: 1210 { 1211 ares_bool_t *b = dig_options[opt].opt; 1212 if (b == NULL) { 1213 snprintf(global_config.error, sizeof(global_config.error), 1214 "invalid use for %c%s", dig_options[opt].prefix, 1215 dig_options[opt].name); 1216 return ARES_FALSE; 1217 } 1218 *b = is_true; 1219 } 1220 break; 1221 case OPT_TYPE_STRING: 1222 { 1223 char **str = dig_options[opt].opt; 1224 if (str == NULL) { 1225 snprintf(global_config.error, sizeof(global_config.error), 1226 "invalid use for %c%s", dig_options[opt].prefix, 1227 dig_options[opt].name); 1228 return ARES_FALSE; 1229 } 1230 if (value == NULL) { 1231 snprintf(global_config.error, sizeof(global_config.error), 1232 "missing value for %c%s", dig_options[opt].prefix, 1233 dig_options[opt].name); 1234 return ARES_FALSE; 1235 } 1236 if (*str != NULL) { 1237 free(*str); 1238 } 1239 *str = strdup(value); 1240 break; 1241 } 1242 case OPT_TYPE_SIZE_T: 1243 { 1244 size_t *s = dig_options[opt].opt; 1245 if (s == NULL) { 1246 snprintf(global_config.error, sizeof(global_config.error), 1247 "invalid use for %c%s", dig_options[opt].prefix, 1248 dig_options[opt].name); 1249 return ARES_FALSE; 1250 } 1251 if (value == NULL) { 1252 snprintf(global_config.error, sizeof(global_config.error), 1253 "missing value for %c%s", dig_options[opt].prefix, 1254 dig_options[opt].name); 1255 return ARES_FALSE; 1256 } 1257 if (!ares_str_isnum(value)) { 1258 snprintf(global_config.error, sizeof(global_config.error), 1259 "%c%s is not a numeric value", dig_options[opt].prefix, 1260 dig_options[opt].name); 1261 return ARES_FALSE; 1262 } 1263 *s = strtoul(value, NULL, 10); 1264 break; 1265 } 1266 case OPT_TYPE_U16: 1267 { 1268 unsigned short *s = dig_options[opt].opt; 1269 if (s == NULL) { 1270 snprintf(global_config.error, sizeof(global_config.error), 1271 "invalid use for %c%s", dig_options[opt].prefix, 1272 dig_options[opt].name); 1273 return ARES_FALSE; 1274 } 1275 if (value == NULL) { 1276 snprintf(global_config.error, sizeof(global_config.error), 1277 "missing value for %c%s", dig_options[opt].prefix, 1278 dig_options[opt].name); 1279 return ARES_FALSE; 1280 } 1281 if (!ares_str_isnum(value)) { 1282 snprintf(global_config.error, sizeof(global_config.error), 1283 "%c%s is not a numeric value", dig_options[opt].prefix, 1284 dig_options[opt].name); 1285 return ARES_FALSE; 1286 } 1287 *s = (unsigned short)strtoul(value, NULL, 10); 1288 break; 1289 } 1290 case OPT_TYPE_FUNC: 1291 if (dig_options[opt].cb == NULL) { 1292 snprintf(global_config.error, sizeof(global_config.error), 1293 "missing callback"); 1294 return ARES_FALSE; 1295 } 1296 if (!dig_options[opt].cb(dig_options[opt].prefix, 1297 dig_options[opt].name, is_true, value)) { 1298 return ARES_FALSE; 1299 } 1300 break; 1301 } 1302 option_handled = ARES_TRUE; 1303 } 1304 1305 if (!option_handled) { 1306 snprintf(global_config.error, sizeof(global_config.error), 1307 "unrecognized option %s", argv[arg]); 1308 return ARES_FALSE; 1309 } 1310 } 1311 1312 return ARES_TRUE; 1313 } 1314 1315 static ares_bool_t read_rcfile(void) 1316 { 1317 char configdir[PATH_MAX]; 1318 unsigned int cdlen = 0; 1319 1320 #if !defined(WIN32) 1321 # if !defined(__APPLE__) 1322 char *configdir_xdg; 1323 # endif 1324 char *homedir; 1325 #endif 1326 1327 char rcfile[PATH_MAX]; 1328 unsigned int rclen; 1329 1330 size_t rcargc; 1331 char **rcargv; 1332 ares_buf_t *rcbuf; 1333 ares_status_t rcstatus; 1334 1335 #if defined(WIN32) 1336 cdlen = (unsigned int)snprintf(configdir, sizeof(configdir), "%s/%s", 1337 getenv("APPDATA"), "c-ares"); 1338 1339 #elif defined(__APPLE__) 1340 homedir = getenv("HOME"); 1341 if (homedir != NULL) { 1342 cdlen = (unsigned int)snprintf(configdir, sizeof(configdir), "%s/%s/%s/%s", 1343 homedir, "Library", "Application Support", 1344 "c-ares"); 1345 } 1346 1347 #else 1348 configdir_xdg = getenv("XDG_CONFIG_HOME"); 1349 1350 if (configdir_xdg == NULL) { 1351 homedir = getenv("HOME"); 1352 if (homedir != NULL) { 1353 cdlen = (unsigned int)snprintf(configdir, sizeof(configdir), "%s/%s", 1354 homedir, ".config"); 1355 } 1356 } else { 1357 cdlen = 1358 (unsigned int)snprintf(configdir, sizeof(configdir), "%s", configdir_xdg); 1359 } 1360 1361 #endif 1362 1363 DEBUGF(fprintf(stderr, "read_cmdline() configdir: %s\n", configdir)); 1364 1365 if (cdlen == 0 || cdlen > sizeof(configdir)) { 1366 DEBUGF( 1367 fprintf(stderr, "read_cmdline() skipping rcfile parsing on directory\n")); 1368 return ARES_TRUE; 1369 } 1370 1371 rclen = 1372 (unsigned int)snprintf(rcfile, sizeof(rcfile), "%s/adigrc", configdir); 1373 1374 if (rclen > sizeof(rcfile)) { 1375 DEBUGF(fprintf(stderr, "read_cmdline() skipping rcfile parsing on file\n")); 1376 return ARES_TRUE; 1377 } 1378 1379 rcbuf = ares_buf_create(); 1380 if (ares_buf_load_file(rcfile, rcbuf) == ARES_SUCCESS) { 1381 rcstatus = ares_buf_split_str(rcbuf, (const unsigned char *)"\n ", 2, 1382 ARES_BUF_SPLIT_TRIM, 0, &rcargv, &rcargc); 1383 1384 if (rcstatus == ARES_SUCCESS) { 1385 read_cmdline((int)rcargc, (const char * const *)rcargv, 0); 1386 1387 } else { 1388 snprintf(global_config.error, sizeof(global_config.error), 1389 "rcfile is invalid: %s", ares_strerror((int)rcstatus)); 1390 } 1391 1392 ares_free_array(rcargv, rcargc, ares_free); 1393 1394 if (rcstatus != ARES_SUCCESS) { 1395 ares_buf_destroy(rcbuf); 1396 return ARES_FALSE; 1397 } 1398 1399 } else { 1400 DEBUGF(fprintf(stderr, "read_cmdline() failed to load rcfile")); 1401 } 1402 ares_buf_destroy(rcbuf); 1403 1404 return ARES_TRUE; 1405 } 1406 1407 static void config_defaults(void) 1408 { 1409 memset(&global_config, 0, sizeof(global_config)); 1410 1411 global_config.opts.tries = 3; 1412 global_config.opts.ndots = 1; 1413 global_config.opts.rd_flag = ARES_TRUE; 1414 global_config.opts.edns = ARES_TRUE; 1415 global_config.opts.udp_size = 1232; 1416 global_config.opts.aliases = ARES_TRUE; 1417 global_config.opts.display_class = ARES_TRUE; 1418 global_config.opts.display_ttl = ARES_TRUE; 1419 global_config.opts.display_command = ARES_TRUE; 1420 global_config.opts.display_stats = ARES_TRUE; 1421 global_config.opts.display_question = ARES_TRUE; 1422 global_config.opts.display_answer = ARES_TRUE; 1423 global_config.opts.display_authority = ARES_TRUE; 1424 global_config.opts.display_additional = ARES_TRUE; 1425 global_config.opts.display_comments = ARES_TRUE; 1426 global_config.qclass = ARES_CLASS_IN; 1427 global_config.qtype = ARES_REC_TYPE_A; 1428 } 1429 1430 static void config_opts(void) 1431 { 1432 global_config.optmask = ARES_OPT_FLAGS; 1433 if (global_config.opts.tcp) { 1434 global_config.options.flags |= ARES_FLAG_USEVC; 1435 } 1436 if (global_config.opts.primary) { 1437 global_config.options.flags |= ARES_FLAG_PRIMARY; 1438 } 1439 if (global_config.opts.edns) { 1440 global_config.options.flags |= ARES_FLAG_EDNS; 1441 } 1442 if (global_config.opts.stayopen) { 1443 global_config.options.flags |= ARES_FLAG_STAYOPEN; 1444 } 1445 if (global_config.opts.dns0x20) { 1446 global_config.options.flags |= ARES_FLAG_DNS0x20; 1447 } 1448 if (!global_config.opts.aliases) { 1449 global_config.options.flags |= ARES_FLAG_NOALIASES; 1450 } 1451 if (!global_config.opts.rd_flag) { 1452 global_config.options.flags |= ARES_FLAG_NORECURSE; 1453 } 1454 if (!global_config.opts.do_search) { 1455 global_config.options.flags |= ARES_FLAG_NOSEARCH; 1456 } 1457 if (global_config.opts.ignore_tc) { 1458 global_config.options.flags |= ARES_FLAG_IGNTC; 1459 } 1460 if (global_config.opts.port) { 1461 global_config.optmask |= ARES_OPT_UDP_PORT; 1462 global_config.optmask |= ARES_OPT_TCP_PORT; 1463 global_config.options.udp_port = global_config.opts.port; 1464 global_config.options.tcp_port = global_config.opts.port; 1465 } 1466 1467 global_config.optmask |= ARES_OPT_TRIES; 1468 global_config.options.tries = (int)global_config.opts.tries; 1469 1470 global_config.optmask |= ARES_OPT_NDOTS; 1471 global_config.options.ndots = (int)global_config.opts.ndots; 1472 1473 global_config.optmask |= ARES_OPT_EDNSPSZ; 1474 global_config.options.ednspsz = (int)global_config.opts.udp_size; 1475 1476 if (global_config.opts.search != NULL) { 1477 global_config.optmask |= ARES_OPT_DOMAINS; 1478 global_config.options.domains = &global_config.opts.search; 1479 global_config.options.ndomains = 1; 1480 } 1481 } 1482 1483 int main(int argc, char **argv) 1484 { 1485 ares_channel_t *channel = NULL; 1486 ares_status_t status; 1487 int rv = 0; 1488 1489 #ifdef USE_WINSOCK 1490 WORD wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK); 1491 WSADATA wsaData; 1492 WSAStartup(wVersionRequested, &wsaData); 1493 #endif 1494 1495 status = (ares_status_t)ares_library_init(ARES_LIB_INIT_ALL); 1496 if (status != ARES_SUCCESS) { 1497 fprintf(stderr, "ares_library_init: %s\n", ares_strerror((int)status)); 1498 return 1; 1499 } 1500 1501 config_defaults(); 1502 1503 if (!read_cmdline(argc, (const char * const *)argv, 1)) { 1504 printf("\n** ERROR: %s\n\n", global_config.error); 1505 print_help(); 1506 rv = 1; 1507 goto done; 1508 } 1509 1510 if (global_config.no_rcfile && !read_rcfile()) { 1511 fprintf(stderr, "\n** ERROR: %s\n", global_config.error); 1512 } 1513 1514 if (global_config.is_help) { 1515 print_help(); 1516 goto done; 1517 } 1518 1519 if (global_config.name == NULL) { 1520 printf("missing query name\n"); 1521 print_help(); 1522 rv = 1; 1523 goto done; 1524 } 1525 1526 config_opts(); 1527 1528 status = (ares_status_t)ares_init_options(&channel, &global_config.options, 1529 global_config.optmask); 1530 if (status != ARES_SUCCESS) { 1531 fprintf(stderr, "ares_init_options: %s\n", ares_strerror((int)status)); 1532 rv = 1; 1533 goto done; 1534 } 1535 1536 if (global_config.servers) { 1537 status = 1538 (ares_status_t)ares_set_servers_ports_csv(channel, global_config.servers); 1539 if (status != ARES_SUCCESS) { 1540 fprintf(stderr, "ares_set_servers_ports_csv: %s: %s\n", 1541 ares_strerror((int)status), global_config.servers); 1542 rv = 1; 1543 goto done; 1544 } 1545 } 1546 1547 /* Debug */ 1548 if (global_config.opts.display_command) { 1549 printf("\n; <<>> c-ares DiG %s <<>>", ares_version(NULL)); 1550 printf(" %s", global_config.name); 1551 printf("\n"); 1552 } 1553 1554 /* Enqueue a query for each separate name */ 1555 status = enqueue_query(channel); 1556 if (status != ARES_SUCCESS) { 1557 fprintf(stderr, "Failed to create query for %s: %s\n", global_config.name, 1558 ares_strerror((int)status)); 1559 rv = 1; 1560 goto done; 1561 } 1562 1563 /* Process events */ 1564 rv = event_loop(channel); 1565 1566 done: 1567 free_config(); 1568 ares_destroy(channel); 1569 ares_library_cleanup(); 1570 1571 #ifdef USE_WINSOCK 1572 WSACleanup(); 1573 #endif 1574 return rv; 1575 }