1 /* 2 * PROJECT: ReactOS nslookup utility 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: base/applications/network/nslookup/nslookup.c 5 * PURPOSE: Perform DNS lookups 6 * COPYRIGHT: Copyright 2009 Lucas Suggs <lucas.suggs@gmail.com> 7 */ 8 9 #include "nslookup.h" 10 11 #include <winbase.h> 12 #include <iphlpapi.h> 13 14 STATE State; 15 HANDLE ProcessHeap; 16 ULONG RequestID; 17 18 void PrintState() 19 { 20 _tprintf( _T("Default Server: (null)\n\n") ); 21 _tprintf( _T("Set options:\n") ); 22 23 _tprintf( _T(" ") ); 24 if( !State.debug ) _tprintf( _T("no") ); 25 _tprintf( _T("debug\n") ); 26 27 _tprintf( _T(" ") ); 28 if( !State.defname ) _tprintf( _T("no") ); 29 _tprintf( _T("defname\n") ); 30 31 _tprintf( _T(" ") ); 32 if( !State.search ) _tprintf( _T("no") ); 33 _tprintf( _T("search\n") ); 34 35 _tprintf( _T(" ") ); 36 if( !State.recurse ) _tprintf( _T("no") ); 37 _tprintf( _T("recurse\n") ); 38 39 _tprintf( _T(" ") ); 40 if( !State.d2 ) _tprintf( _T("no") ); 41 _tprintf( _T("d2\n") ); 42 43 _tprintf( _T(" ") ); 44 if( !State.vc ) _tprintf( _T("no") ); 45 _tprintf( _T("vc\n") ); 46 47 _tprintf( _T(" ") ); 48 if( !State.ignoretc ) _tprintf( _T("no") ); 49 _tprintf( _T("ignoretc\n") ); 50 51 _tprintf( _T(" port=%d\n"), State.port ); 52 _tprintf( _T(" type=%s\n"), State.type ); 53 _tprintf( _T(" class=%s\n"), State.Class ); 54 _tprintf( _T(" timeout=%d\n"), (int)State.timeout ); 55 _tprintf( _T(" retry=%d\n"), (int)State.retry ); 56 _tprintf( _T(" root=%s\n"), State.root ); 57 _tprintf( _T(" domain=%s\n"), State.domain ); 58 59 _tprintf( _T(" ") ); 60 if( !State.MSxfr ) _tprintf( _T("no") ); 61 _tprintf( _T("MSxfr\n") ); 62 63 _tprintf( _T(" IXFRversion=%d\n"), (int)State.ixfrver ); 64 65 _tprintf( _T(" srchlist=%s\n\n"), State.srchlist[0] ); 66 } 67 68 void PrintUsage() 69 { 70 _tprintf( _T("Usage:\n" 71 " nslookup [-opt ...] # interactive mode using" 72 " default server\n nslookup [-opt ...] - server #" 73 " interactive mode using 'server'\n nslookup [-opt ...]" 74 " host # just look up 'host' using default server\n" 75 " nslookup [-opt ...] host server # just look up 'host'" 76 " using 'server'\n") ); 77 } 78 79 BOOL PerformInternalLookup( PCHAR pAddr, PCHAR pResult ) 80 { 81 /* Needed to issue DNS packets and parse them. */ 82 PCHAR Buffer = NULL, RecBuffer = NULL; 83 CHAR pResolve[256]; 84 ULONG BufferLength = 0, RecBufferLength = 512; 85 int i = 0, j = 0, k = 0, d = 0; 86 BOOL bOk = FALSE; 87 88 /* Makes things easier when parsing the response packet. */ 89 USHORT NumQuestions; 90 USHORT Type; 91 92 if( (strlen( pAddr ) + 1) > 255 ) return FALSE; 93 94 Type = TYPE_A; 95 if( IsValidIP( pAddr ) ) Type = TYPE_PTR; 96 97 /* If it's a PTR lookup then append the ARPA sig to the end. */ 98 if( Type == TYPE_PTR ) 99 { 100 ReverseIP( pAddr, pResolve ); 101 strcat( pResolve, ARPA_SIG ); 102 } 103 else 104 { 105 strcpy( pResolve, pAddr ); 106 } 107 108 /* Base header length + length of QNAME + length of QTYPE and QCLASS */ 109 BufferLength = 12 + (strlen( pResolve ) + 2) + 4; 110 111 /* Allocate memory for the buffer. */ 112 Buffer = HeapAlloc( ProcessHeap, 0, BufferLength ); 113 if( !Buffer ) 114 { 115 _tprintf( _T("ERROR: Out of memory\n") ); 116 goto cleanup; 117 } 118 119 /* Allocate the receiving buffer. */ 120 RecBuffer = HeapAlloc( ProcessHeap, 0, RecBufferLength ); 121 if( !RecBuffer ) 122 { 123 _tprintf( _T("ERROR: Out of memory\n") ); 124 goto cleanup; 125 } 126 127 /* Insert the ID field. */ 128 ((PSHORT)&Buffer[i])[0] = htons( RequestID ); 129 i += 2; 130 131 /* Bits 0-7 of the second 16 are all 0, except for when recursion is 132 desired. */ 133 Buffer[i] = 0x00; 134 if( State.recurse) Buffer[i] |= 0x01; 135 i += 1; 136 137 /* Bits 8-15 of the second 16 are 0 for a query. */ 138 Buffer[i] = 0x00; 139 i += 1; 140 141 /* Only 1 question. */ 142 ((PSHORT)&Buffer[i])[0] = htons( 1 ); 143 i += 2; 144 145 /* We aren't sending a response, so 0 out the rest of the header. */ 146 Buffer[i] = 0x00; 147 Buffer[i + 1] = 0x00; 148 Buffer[i + 2] = 0x00; 149 Buffer[i + 3] = 0x00; 150 Buffer[i + 4] = 0x00; 151 Buffer[i + 5] = 0x00; 152 i += 6; 153 154 /* Walk through the query address. Split each section delimited by '.'. 155 Format of the QNAME section is length|data, etc. Last one is null */ 156 j = i; 157 i += 1; 158 159 for( k = 0; k < strlen( pResolve ); k += 1 ) 160 { 161 if( pResolve[k] != '.' ) 162 { 163 Buffer[i] = pResolve[k]; 164 i += 1; 165 } 166 else 167 { 168 Buffer[j] = (i - j) - 1; 169 j = i; 170 i += 1; 171 } 172 } 173 174 Buffer[j] = (i - j) - 1; 175 Buffer[i] = 0x00; 176 i += 1; 177 178 /* QTYPE */ 179 ((PSHORT)&Buffer[i])[0] = htons( Type ); 180 i += 2; 181 182 /* QCLASS */ 183 ((PSHORT)&Buffer[i])[0] = htons( CLASS_IN ); 184 185 /* Ship the request off to the DNS server. */ 186 bOk = SendRequest( Buffer, 187 BufferLength, 188 RecBuffer, 189 &RecBufferLength ); 190 if( !bOk ) goto cleanup; 191 192 /* Start parsing the received packet. */ 193 NumQuestions = ntohs( ((PSHORT)&RecBuffer[4])[0] ); 194 195 k = 12; 196 197 /* We don't care about the questions section, blow through it. */ 198 if( NumQuestions ) 199 { 200 for( i = 0; i < NumQuestions; i += 1 ) 201 { 202 /* Quick way to skip the domain name section. */ 203 k += ExtractName( RecBuffer, pResult, k, 0 ); 204 k += 4; 205 } 206 } 207 208 /* Skip the answer name. */ 209 k += ExtractName( RecBuffer, pResult, k, 0 ); 210 211 Type = ntohs( ((PUSHORT)&RecBuffer[k])[0] ); 212 k += 8; 213 214 d = ntohs( ((PUSHORT)&RecBuffer[k])[0] ); 215 k += 2; 216 217 if( TYPE_PTR == Type ) 218 { 219 k += ExtractName( RecBuffer, pResult, k, d ); 220 } 221 else if( TYPE_A == Type ) 222 { 223 k += ExtractIP( RecBuffer, pResult, k ); 224 } 225 226 cleanup: 227 /* Free memory. */ 228 if( Buffer ) HeapFree( ProcessHeap, 0, Buffer ); 229 if( RecBuffer ) HeapFree( ProcessHeap, 0, RecBuffer ); 230 231 RequestID += 1; 232 233 return bOk; 234 } 235 236 void PerformLookup( PCHAR pAddr ) 237 { 238 /* Needed to issue DNS packets and parse them. */ 239 PCHAR Buffer = NULL, RecBuffer = NULL; 240 CHAR pResolve[256]; 241 CHAR pResult[256]; 242 ULONG BufferLength = 0, RecBufferLength = 512; 243 int i = 0, j = 0, k = 0, d = 0; 244 BOOL bOk = FALSE; 245 246 /* Makes things easier when parsing the response packet. */ 247 UCHAR Header2; 248 USHORT NumQuestions; 249 USHORT NumAnswers; 250 USHORT NumAuthority; 251 USHORT Type; 252 253 if( (strlen( pAddr ) + 1) > 255 ) return; 254 255 _tprintf( _T("Server: %s\n"), State.DefaultServer ); 256 _tprintf( _T("Address: %s\n\n"), State.DefaultServerAddress ); 257 258 if( !strcmp( TypeA, State.type ) 259 || !strcmp( TypeAAAA, State.type ) 260 || !strcmp( TypeBoth, State.type ) ) 261 { 262 Type = TYPE_A; 263 if( IsValidIP( pAddr ) ) Type = TYPE_PTR; 264 } 265 else 266 Type = TypeNametoTypeID( State.type ); 267 268 /* If it's a PTR lookup then append the ARPA sig to the end. */ 269 if( (Type == TYPE_PTR) && IsValidIP( pAddr ) ) 270 { 271 ReverseIP( pAddr, pResolve ); 272 strcat( pResolve, ARPA_SIG ); 273 } 274 else 275 { 276 strcpy( pResolve, pAddr ); 277 } 278 279 /* Base header length + length of QNAME + length of QTYPE and QCLASS */ 280 BufferLength = 12 + (strlen( pResolve ) + 2) + 4; 281 282 /* Allocate memory for the buffer. */ 283 Buffer = HeapAlloc( ProcessHeap, 0, BufferLength ); 284 if( !Buffer ) 285 { 286 _tprintf( _T("ERROR: Out of memory\n") ); 287 goto cleanup; 288 } 289 290 /* Allocate memory for the return buffer. */ 291 RecBuffer = HeapAlloc( ProcessHeap, 0, RecBufferLength ); 292 if( !RecBuffer ) 293 { 294 _tprintf( _T("ERROR: Out of memory\n") ); 295 goto cleanup; 296 } 297 298 /* Insert the ID field. */ 299 ((PSHORT)&Buffer[i])[0] = htons( RequestID ); 300 i += 2; 301 302 /* Bits 0-7 of the second 16 are all 0, except for when recursion is 303 desired. */ 304 Buffer[i] = 0x00; 305 if( State.recurse) Buffer[i] |= 0x01; 306 i += 1; 307 308 /* Bits 8-15 of the second 16 are 0 for a query. */ 309 Buffer[i] = 0x00; 310 i += 1; 311 312 /* Only 1 question. */ 313 ((PSHORT)&Buffer[i])[0] = htons( 1 ); 314 i += 2; 315 316 /* We aren't sending a response, so 0 out the rest of the header. */ 317 Buffer[i] = 0x00; 318 Buffer[i + 1] = 0x00; 319 Buffer[i + 2] = 0x00; 320 Buffer[i + 3] = 0x00; 321 Buffer[i + 4] = 0x00; 322 Buffer[i + 5] = 0x00; 323 i += 6; 324 325 /* Walk through the query address. Split each section delimited by '.'. 326 Format of the QNAME section is length|data, etc. Last one is null */ 327 j = i; 328 i += 1; 329 330 for( k = 0; k < strlen( pResolve ); k += 1 ) 331 { 332 if( pResolve[k] != '.' ) 333 { 334 Buffer[i] = pResolve[k]; 335 i += 1; 336 } 337 else 338 { 339 Buffer[j] = (i - j) - 1; 340 j = i; 341 i += 1; 342 } 343 } 344 345 Buffer[j] = (i - j) - 1; 346 Buffer[i] = 0x00; 347 i += 1; 348 349 /* QTYPE */ 350 ((PSHORT)&Buffer[i])[0] = htons( Type ); 351 i += 2; 352 353 /* QCLASS */ 354 ((PSHORT)&Buffer[i])[0] = htons( ClassNametoClassID( State.Class ) ); 355 356 /* Ship off the request to the DNS server. */ 357 bOk = SendRequest( Buffer, 358 BufferLength, 359 RecBuffer, 360 &RecBufferLength ); 361 if( !bOk ) goto cleanup; 362 363 /* Start parsing the received packet. */ 364 Header2 = RecBuffer[3]; 365 NumQuestions = ntohs( ((PSHORT)&RecBuffer[4])[0] ); 366 NumAnswers = ntohs( ((PSHORT)&RecBuffer[6])[0] ); 367 NumAuthority = ntohs( ((PUSHORT)&RecBuffer[8])[0] ); 368 Type = 0; 369 370 /* Check the RCODE for failure. */ 371 d = Header2 & 0x0F; 372 if( d != RCODE_NOERROR ) 373 { 374 switch( d ) 375 { 376 case RCODE_NXDOMAIN: 377 _tprintf( _T("*** %s can't find %s: Non-existant domain\n"), State.DefaultServer, pAddr ); 378 break; 379 380 case RCODE_REFUSED: 381 _tprintf( _T("*** %s can't find %s: Query refused\n"), State.DefaultServer, pAddr ); 382 break; 383 384 default: 385 _tprintf( _T("*** %s can't find %s: Unknown RCODE\n"), State.DefaultServer, pAddr ); 386 } 387 388 goto cleanup; 389 } 390 391 k = 12; 392 393 if( NumQuestions ) 394 { 395 /* Blow through the questions section since we don't care about it. */ 396 for( i = 0; i < NumQuestions; i += 1 ) 397 { 398 k += ExtractName( RecBuffer, pResult, k, 0 ); 399 k += 4; 400 } 401 } 402 403 if( NumAnswers ) 404 { 405 /* Skip the name. */ 406 k += ExtractName( RecBuffer, pResult, k, 0 ); 407 408 Type = ntohs( ((PUSHORT)&RecBuffer[k])[0] ); 409 k += 8; 410 411 d = ntohs( ((PUSHORT)&RecBuffer[k])[0] ); 412 k += 2; 413 414 if( TYPE_PTR == Type ) 415 { 416 k += ExtractName( RecBuffer, pResult, k, d ); 417 } 418 else if( TYPE_A == Type ) 419 { 420 k += ExtractIP( RecBuffer, pResult, k ); 421 } 422 } 423 424 /* FIXME: This'll need to support more than PTR and A at some point. */ 425 if( !strcmp( State.type, TypePTR ) ) 426 { 427 if( TYPE_PTR == Type ) 428 { 429 _tprintf( _T("%s name = %s\n"), pResolve, pResult ); 430 } 431 else 432 { 433 } 434 } 435 else if( !strcmp( State.type, TypeA ) 436 || !strcmp( State.type, TypeAAAA ) 437 || !strcmp( State.type, TypeBoth ) ) 438 { 439 if( (TYPE_A == Type) /*|| (TYPE_AAAA == Type)*/ ) 440 { 441 if( 0 == NumAuthority ) 442 _tprintf( _T("Non-authoritative answer:\n") ); 443 444 _tprintf( _T("Name: %s\n"), pAddr ); 445 _tprintf( _T("Address: %s\n\n"), pResult ); 446 } 447 else 448 { 449 _tprintf( _T("Name: %s\n"), pResult ); 450 _tprintf( _T("Address: %s\n\n"), pAddr ); 451 } 452 } 453 454 cleanup: 455 /* Free memory. */ 456 if( Buffer ) HeapFree( ProcessHeap, 0, Buffer ); 457 if( RecBuffer ) HeapFree( ProcessHeap, 0, RecBuffer ); 458 459 RequestID += 1; 460 } 461 462 BOOL ParseCommandLine( int argc, char* argv[] ) 463 { 464 int i; 465 BOOL NoMoreOptions = FALSE; 466 BOOL Interactive = FALSE; 467 CHAR AddrToResolve[256]; 468 CHAR Server[256]; 469 470 RtlZeroMemory( AddrToResolve, 256 ); 471 RtlZeroMemory( Server, 256 ); 472 473 if( 2 == argc ) 474 { 475 /* In the Windows nslookup, usage is only displayed if /? is the only 476 option specified on the command line. */ 477 if( !strncmp( "/?", argv[1], 2 ) ) 478 { 479 PrintUsage(); 480 return 0; 481 } 482 } 483 484 if( argc > 1 ) 485 { 486 for( i = 1; i < argc; i += 1 ) 487 { 488 if( NoMoreOptions ) 489 { 490 strncpy( Server, argv[i], 255 ); 491 492 /* Determine which one to resolve. This is based on whether the 493 DNS server provided was an IP or an FQDN. */ 494 if( IsValidIP( Server ) ) 495 { 496 strncpy( State.DefaultServerAddress, Server, 16 ); 497 498 PerformInternalLookup( State.DefaultServerAddress, 499 State.DefaultServer ); 500 } 501 else 502 { 503 strncpy( State.DefaultServer, Server, 255 ); 504 505 PerformInternalLookup( State.DefaultServer, 506 State.DefaultServerAddress ); 507 } 508 509 if( Interactive ) return 1; 510 511 PerformLookup( AddrToResolve ); 512 513 return 0; 514 } 515 else 516 { 517 if( !strncmp( "-all", argv[i], 4 ) ) 518 { 519 PrintState(); 520 } 521 else if( !strncmp( "-type=", argv[i], 6 ) ) 522 { 523 if( !strncmp( TypeA, &argv[i][6], strlen( TypeA ) ) ) 524 { 525 State.type = TypeA; 526 } 527 else if( !strncmp( TypeAAAA, &argv[i][6], strlen( TypeAAAA ) ) ) 528 { 529 State.type = TypeAAAA; 530 } 531 else if( !strncmp( TypeBoth, &argv[i][6], strlen( TypeBoth ) ) ) 532 { 533 State.type = TypeBoth; 534 } 535 else if( !strncmp( TypeAny, &argv[i][6], strlen( TypeAny ) ) ) 536 { 537 State.type = TypeAny; 538 } 539 else if( !strncmp( TypeCNAME, &argv[i][6], strlen( TypeCNAME ) ) ) 540 { 541 State.type = TypeCNAME; 542 } 543 else if( !strncmp( TypeMX, &argv[i][6], strlen( TypeMX ) ) ) 544 { 545 State.type = TypeMX; 546 } 547 else if( !strncmp( TypeNS, &argv[i][6], strlen( TypeNS ) ) ) 548 { 549 State.type = TypeNS; 550 } 551 else if( !strncmp( TypePTR, &argv[i][6], strlen( TypePTR ) ) ) 552 { 553 State.type = TypePTR; 554 } 555 else if( !strncmp( TypeSOA, &argv[i][6], strlen( TypeSOA ) ) ) 556 { 557 State.type = TypeSOA; 558 } 559 else if( !strncmp( TypeSRV, &argv[i][6], strlen( TypeSRV ) ) ) 560 { 561 State.type = TypeSRV; 562 } 563 else 564 { 565 _tprintf( _T("unknown query type: %s"), &argv[i][6] ); 566 } 567 } 568 else if( !strncmp( "-domain=", argv[i], 8 ) ) 569 { 570 strcpy( State.domain, &argv[i][8] ); 571 } 572 else if( !strncmp( "-srchlist=", argv[i], 10 ) ) 573 { 574 } 575 else if( !strncmp( "-root=", argv[i], 6 ) ) 576 { 577 strcpy( State.root, &argv[i][6] ); 578 } 579 else if( !strncmp( "-retry=", argv[i], 7 ) ) 580 { 581 } 582 else if( !strncmp( "-timeout=", argv[i], 9 ) ) 583 { 584 } 585 else if( !strncmp( "-querytype=", argv[i], 11 ) ) 586 { 587 if( !strncmp( TypeA, &argv[i][11], strlen( TypeA ) ) ) 588 { 589 State.type = TypeA; 590 } 591 else if( !strncmp( TypeAAAA, &argv[i][11], strlen( TypeAAAA ) ) ) 592 { 593 State.type = TypeAAAA; 594 } 595 else if( !strncmp( TypeBoth, &argv[i][11], strlen( TypeBoth ) ) ) 596 { 597 State.type = TypeBoth; 598 } 599 else if( !strncmp( TypeAny, &argv[i][11], strlen( TypeAny ) ) ) 600 { 601 State.type = TypeAny; 602 } 603 else if( !strncmp( TypeCNAME, &argv[i][11], strlen( TypeCNAME ) ) ) 604 { 605 State.type = TypeCNAME; 606 } 607 else if( !strncmp( TypeMX, &argv[i][11], strlen( TypeMX ) ) ) 608 { 609 State.type = TypeMX; 610 } 611 else if( !strncmp( TypeNS, &argv[i][11], strlen( TypeNS ) ) ) 612 { 613 State.type = TypeNS; 614 } 615 else if( !strncmp( TypePTR, &argv[i][11], strlen( TypePTR ) ) ) 616 { 617 State.type = TypePTR; 618 } 619 else if( !strncmp( TypeSOA, &argv[i][11], strlen( TypeSOA ) ) ) 620 { 621 State.type = TypeSOA; 622 } 623 else if( !strncmp( TypeSRV, &argv[i][11], strlen( TypeSRV ) ) ) 624 { 625 State.type = TypeSRV; 626 } 627 else 628 { 629 _tprintf( _T("unknown query type: %s"), &argv[i][6] ); 630 } 631 } 632 else if( !strncmp( "-class=", argv[i], 7 ) ) 633 { 634 if( !strncmp( ClassIN, &argv[i][7], strlen( ClassIN ) ) ) 635 { 636 State.Class = ClassIN; 637 } 638 else if( !strncmp( ClassAny, &argv[i][7], strlen( ClassAny ) ) ) 639 { 640 State.Class = ClassAny; 641 } 642 else 643 { 644 _tprintf( _T("unknown query class: %s"), &argv[i][7] ); 645 } 646 } 647 else if( !strncmp( "-ixfrver=", argv[i], 9 ) ) 648 { 649 } 650 else if( !strncmp( "-debug", argv[i], 6 ) ) 651 { 652 State.debug = TRUE; 653 } 654 else if( !strncmp( "-nodebug", argv[i], 8 ) ) 655 { 656 State.debug = FALSE; 657 State.d2 = FALSE; 658 } 659 else if( !strncmp( "-d2", argv[i], 3 ) ) 660 { 661 State.d2 = TRUE; 662 State.debug = TRUE; 663 } 664 else if( !strncmp( "-nod2", argv[i], 5 ) ) 665 { 666 if( State.debug ) _tprintf( _T("d2 mode disabled; still in debug mode\n") ); 667 668 State.d2 = FALSE; 669 } 670 else if( !strncmp( "-defname", argv[i], 8 ) ) 671 { 672 State.defname = TRUE; 673 } 674 else if( !strncmp( "-noddefname", argv[i], 10 ) ) 675 { 676 State.defname = FALSE; 677 } 678 else if( !strncmp( "-recurse", argv[i], 8 ) ) 679 { 680 State.recurse = TRUE; 681 } 682 else if( !strncmp( "-norecurse", argv[i], 10 ) ) 683 { 684 State.recurse = FALSE; 685 } 686 else if( !strncmp( "-search", argv[i], 7 ) ) 687 { 688 State.search = TRUE; 689 } 690 else if( !strncmp( "-nosearch", argv[i], 9 ) ) 691 { 692 State.search = FALSE; 693 } 694 else if( !strncmp( "-vc", argv[i], 3 ) ) 695 { 696 State.vc = TRUE; 697 } 698 else if( !strncmp( "-novc", argv[i], 5 ) ) 699 { 700 State.vc = FALSE; 701 } 702 else if( !strncmp( "-msxfr", argv[i], 6 ) ) 703 { 704 State.MSxfr = TRUE; 705 } 706 else if( !strncmp( "-nomsxfr", argv[i], 8 ) ) 707 { 708 State.MSxfr = FALSE; 709 } 710 else if( !strncmp( "-", argv[i], 1 ) && (strlen( argv[i] ) == 1) ) 711 { 712 /* Since we received just the plain - switch, we are going 713 to be entering interactive mode. We also will not be 714 parsing any more options. */ 715 NoMoreOptions = TRUE; 716 Interactive = TRUE; 717 } 718 else 719 { 720 /* Grab the address to resolve. No more options accepted 721 past this point. */ 722 strncpy( AddrToResolve, argv[i], 255 ); 723 NoMoreOptions = TRUE; 724 } 725 } 726 } 727 728 if( NoMoreOptions && !Interactive ) 729 { 730 /* Get the FQDN of the DNS server. */ 731 PerformInternalLookup( State.DefaultServerAddress, 732 State.DefaultServer ); 733 734 PerformLookup( AddrToResolve ); 735 736 return 0; 737 } 738 } 739 740 /* Get the FQDN of the DNS server. */ 741 PerformInternalLookup( State.DefaultServerAddress, 742 State.DefaultServer ); 743 744 return 1; 745 } 746 747 void InteractiveMode() 748 { 749 _tprintf( _T("Default Server: %s\n"), State.DefaultServer ); 750 _tprintf( _T("Address: %s\n\n"), State.DefaultServerAddress ); 751 752 /* TODO: Implement interactive mode. */ 753 754 _tprintf( _T("ERROR: Feature not implemented.\n") ); 755 } 756 757 int main( int argc, char* argv[] ) 758 { 759 int i; 760 ULONG Status; 761 PFIXED_INFO pNetInfo = NULL; 762 ULONG NetBufLen = 0; 763 WSADATA wsaData; 764 765 ProcessHeap = GetProcessHeap(); 766 RequestID = 1; 767 768 /* Set up the initial state. */ 769 State.debug = FALSE; 770 State.defname = TRUE; 771 State.search = TRUE; 772 State.recurse = TRUE; 773 State.d2 = FALSE; 774 State.vc = FALSE; 775 State.ignoretc = FALSE; 776 State.port = 53; 777 State.type = TypeBoth; 778 State.Class = ClassIN; 779 State.timeout = 2; 780 State.retry = 1; 781 State.MSxfr = TRUE; 782 State.ixfrver = 1; 783 784 RtlZeroMemory( State.root, 256 ); 785 RtlZeroMemory( State.domain, 256 ); 786 for( i = 0; i < 6; i += 1 ) RtlZeroMemory( State.srchlist[i], 256 ); 787 RtlZeroMemory( State.DefaultServer, 256 ); 788 RtlZeroMemory( State.DefaultServerAddress, 16 ); 789 790 memcpy( State.root, DEFAULT_ROOT, sizeof(DEFAULT_ROOT) ); 791 792 /* We don't know how long of a buffer it will want to return. So we'll 793 pass an empty one now and let it fail only once, instead of guessing. */ 794 Status = GetNetworkParams( pNetInfo, &NetBufLen ); 795 if( Status == ERROR_BUFFER_OVERFLOW ) 796 { 797 pNetInfo = (PFIXED_INFO)HeapAlloc( ProcessHeap, 0, NetBufLen ); 798 if( pNetInfo == NULL ) 799 { 800 _tprintf( _T("ERROR: Out of memory\n") ); 801 802 return -1; 803 } 804 805 /* For real this time. */ 806 Status = GetNetworkParams( pNetInfo, &NetBufLen ); 807 if( Status != NO_ERROR ) 808 { 809 _tprintf( _T("Error in GetNetworkParams call\n") ); 810 811 HeapFree( ProcessHeap, 0, pNetInfo ); 812 813 return -2; 814 } 815 } 816 817 strncpy( State.domain, pNetInfo->DomainName, 255 ); 818 strncpy( State.srchlist[0], pNetInfo->DomainName, 255 ); 819 strncpy( State.DefaultServerAddress, 820 pNetInfo->DnsServerList.IpAddress.String, 821 15 ); 822 823 HeapFree( ProcessHeap, 0, pNetInfo ); 824 825 WSAStartup( MAKEWORD(2,2), &wsaData ); 826 827 switch( ParseCommandLine( argc, argv ) ) 828 { 829 case 0: 830 /* This means that it was a /? parameter. */ 831 break; 832 833 default: 834 /* Anything else means we enter interactive mode. The only exception 835 to this is when the host to resolve was provided on the command 836 line. */ 837 InteractiveMode(); 838 } 839 840 WSACleanup(); 841 return 0; 842 } 843