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