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