[NSLOOKUP]
[reactos.git] / reactos / base / applications / network / nslookup / nslookup.c
1 /*
2 * PROJECT: ReactOS nslookup utility
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: 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 }