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