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