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