1 /*
2  * PROJECT:     ReactOS nslookup utility
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        base/applications/network/nslookup/utility.c
5  * PURPOSE:     Support functions for nslookup.c
6  * COPYRIGHT:   Copyright 2009 Lucas Suggs <lucas.suggs@gmail.com>
7  */
8 
9 #include "nslookup.h"
10 
11 BOOL SendRequest( PCHAR pInBuffer,
12                   ULONG InBufferLength,
13                   PCHAR pOutBuffer,
14                   PULONG pOutBufferLength )
15 {
16     int j;
17     USHORT RequestID, ResponseID;
18     BOOL bWait;
19     SOCKET s;
20     SOCKADDR_IN RecAddr, RecAddr2, SendAddr;
21     int SendAddrLen = sizeof(SendAddr);
22 
23     RtlZeroMemory( &RecAddr, sizeof(SOCKADDR_IN) );
24     RtlZeroMemory( &RecAddr2, sizeof(SOCKADDR_IN) );
25     RtlZeroMemory( &SendAddr, sizeof(SOCKADDR_IN) );
26 
27     /* Pull the request ID from the buffer. */
28     RequestID = ntohs( ((PSHORT)&pInBuffer[0])[0] );
29 
30     /* If D2 flags is enabled, then display D2 information. */
31     if( State.d2 ) PrintD2( pInBuffer, InBufferLength );
32 
33     /* Create the sockets for both send and receive. */
34     s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
35 
36     if (s == INVALID_SOCKET)
37         return FALSE;
38 
39     /* Set up the structure to tell it where we are going. */
40     RecAddr.sin_family = AF_INET;
41     RecAddr.sin_port = htons( State.port );
42     RecAddr.sin_addr.s_addr = inet_addr( State.DefaultServerAddress );
43 
44     /* Set up the structure to tell it what port to listen on. */
45     RecAddr2.sin_family = AF_INET;
46     RecAddr2.sin_port = htons( State.port );
47     RecAddr2.sin_addr.s_addr = htonl( INADDR_ANY );
48 
49     /* Bind the receive socket. */
50     bind( s, (SOCKADDR*)&RecAddr2, sizeof(RecAddr2) );
51 
52     /* Send the datagram to the DNS server. */
53     j = sendto( s,
54                 pInBuffer,
55                 InBufferLength,
56                 0,
57                 (SOCKADDR*)&RecAddr,
58                 sizeof(RecAddr) );
59     if( j == SOCKET_ERROR )
60     {
61         switch( WSAGetLastError() )
62         {
63         case WSANOTINITIALISED:
64             _tprintf( _T("sendto() failed with WSANOTINITIALIZED\n") );
65             break;
66         case WSAENETDOWN:
67             _tprintf( _T("sendto() failed with WSAENETDOWN\n") );
68             break;
69         case WSAEACCES:
70             _tprintf( _T("sendto() failed with WSAEACCES\n") );
71             break;
72         case WSAEINVAL:
73             _tprintf( _T("sendto() failed with WSAEINVAL\n") );
74             break;
75         case WSAEINTR:
76             _tprintf( _T("sendto() failed with WSAEINTR\n") );
77             break;
78         case WSAEINPROGRESS:
79             _tprintf( _T("sendto() failed with WSAEINPROGRESS\n") );
80             break;
81         case WSAEFAULT:
82             _tprintf( _T("sendto() failed with WSAEFAULT\n") );
83             break;
84         case WSAENETRESET:
85             _tprintf( _T("sendto() failed with WSAENETRESET\n") );
86             break;
87         case WSAENOBUFS:
88             _tprintf( _T("sendto() failed with WSAENOBUFS\n") );
89             break;
90         case WSAENOTCONN:
91             _tprintf( _T("sendto() failed with WSAENOTCONN\n") );
92             break;
93         case WSAENOTSOCK:
94             _tprintf( _T("sendto() failed with WSAENOTSOCK\n") );
95             break;
96         case WSAEOPNOTSUPP:
97             _tprintf( _T("sendto() failed with WSAEOPNOTSUPP\n") );
98             break;
99         case WSAESHUTDOWN:
100             _tprintf( _T("sendto() failed with WSAESHUTDOWN\n") );
101             break;
102         case WSAEWOULDBLOCK:
103             _tprintf( _T("sendto() failed with WSAEWOULDBLOCK\n") );
104             break;
105         case WSAEMSGSIZE:
106             _tprintf( _T("sendto() failed with WSAEMSGSIZE\n") );
107             break;
108         case WSAEHOSTUNREACH:
109             _tprintf( _T("sendto() failed with WSAEHOSTUNREACH\n") );
110             break;
111         case WSAECONNABORTED:
112             _tprintf( _T("sendto() failed with WSAECONNABORTED\n") );
113             break;
114         case WSAECONNRESET:
115             _tprintf( _T("sendto() failed with WSAECONNRESET\n") );
116             break;
117         case WSAEADDRNOTAVAIL:
118             _tprintf( _T("sendto() failed with WSAEADDRNOTAVAIL\n") );
119             break;
120         case WSAEAFNOSUPPORT:
121             _tprintf( _T("sendto() failed with WSAEAFNOSUPPORT\n") );
122             break;
123         case WSAEDESTADDRREQ:
124             _tprintf( _T("sendto() failed with WSAEDESTADDRREQ\n") );
125             break;
126         case WSAENETUNREACH:
127             _tprintf( _T("sendto() failed with WSAENETUNREACH\n") );
128             break;
129         case WSAETIMEDOUT:
130             _tprintf( _T("sendto() failed with WSAETIMEDOUT\n") );
131             break;
132         default:
133             _tprintf( _T("sendto() failed with unknown error\n") );
134         }
135 
136         closesocket( s );
137         return FALSE;
138     }
139 
140     bWait = TRUE;
141 
142     while( bWait )
143     {
144         /* Wait for the DNS reply. */
145         j = recvfrom( s,
146                       pOutBuffer,
147                       *pOutBufferLength,
148                       0,
149                       (SOCKADDR*)&SendAddr,
150                       &SendAddrLen );
151         if( j == SOCKET_ERROR )
152         {
153             switch( WSAGetLastError() )
154             {
155             case WSANOTINITIALISED:
156                 _tprintf( _T("recvfrom() failed with WSANOTINITIALIZED\n") );
157                 break;
158             case WSAENETDOWN:
159                 _tprintf( _T("recvfrom() failed with WSAENETDOWN\n") );
160                 break;
161             case WSAEACCES:
162                 _tprintf( _T("recvfrom() failed with WSAEACCES\n") );
163                 break;
164             case WSAEINVAL:
165                 _tprintf( _T("recvfrom() failed with WSAEINVAL\n") );
166                 break;
167             case WSAEINTR:
168                 _tprintf( _T("recvfrom() failed with WSAEINTR\n") );
169                 break;
170             case WSAEINPROGRESS:
171                 _tprintf( _T("recvfrom() failed with WSAEINPROGRESS\n") );
172                 break;
173             case WSAEFAULT:
174                 _tprintf( _T("recvfrom() failed with WSAEFAULT\n") );
175                 break;
176             case WSAENETRESET:
177                 _tprintf( _T("recvfrom() failed with WSAENETRESET\n") );
178                 break;
179             case WSAENOBUFS:
180                 _tprintf( _T("recvfrom() failed with WSAENOBUFS\n") );
181                 break;
182             case WSAENOTCONN:
183                 _tprintf( _T("recvfrom() failed with WSAENOTCONN\n") );
184                 break;
185             case WSAENOTSOCK:
186                 _tprintf( _T("recvfrom() failed with WSAENOTSOCK\n") );
187                 break;
188             case WSAEOPNOTSUPP:
189                 _tprintf( _T("recvfrom() failed with WSAEOPNOTSUPP\n") );
190                 break;
191             case WSAESHUTDOWN:
192                 _tprintf( _T("recvfrom() failed with WSAESHUTDOWN\n") );
193                 break;
194             case WSAEWOULDBLOCK:
195                 _tprintf( _T("recvfrom() failed with WSAEWOULDBLOCK\n") );
196                 break;
197             case WSAEMSGSIZE:
198                 _tprintf( _T("recvfrom() failed with WSAEMSGSIZE\n") );
199                 break;
200             case WSAEHOSTUNREACH:
201                 _tprintf( _T("recvfrom() failed with WSAEHOSTUNREACH\n") );
202                 break;
203             case WSAECONNABORTED:
204                 _tprintf( _T("recvfrom() failed with WSAECONNABORTED\n") );
205                 break;
206             case WSAECONNRESET:
207                 _tprintf( _T("recvfrom() failed with WSAECONNRESET\n") );
208                 break;
209             case WSAEADDRNOTAVAIL:
210                 _tprintf( _T("recvfrom() failed with WSAEADDRNOTAVAIL\n") );
211                 break;
212             case WSAEAFNOSUPPORT:
213                 _tprintf( _T("recvfrom() failed with WSAEAFNOSUPPORT\n") );
214                 break;
215             case WSAEDESTADDRREQ:
216                 _tprintf( _T("recvfrom() failed with WSAEDESTADDRREQ\n") );
217                 break;
218             case WSAENETUNREACH:
219                 _tprintf( _T("recvfrom() failed with WSAENETUNREACH\n") );
220                 break;
221             case WSAETIMEDOUT:
222                 _tprintf( _T("recvfrom() failed with WSAETIMEDOUT\n") );
223                 break;
224             default:
225                 _tprintf( _T("recvfrom() failed with unknown error\n") );
226             }
227 
228             closesocket( s );
229             return FALSE;
230         }
231 
232         ResponseID = ntohs( ((PSHORT)&pOutBuffer[0])[0] );
233 
234         if( ResponseID == RequestID ) bWait = FALSE;
235     }
236 
237     /* We don't need the sockets anymore. */
238     closesocket( s );
239 
240     /* If debug information then display debug information. */
241     if( State.debug ) PrintDebug( pOutBuffer, j );
242 
243     /* Return the real output buffer length. */
244     *pOutBufferLength = j;
245 
246     return TRUE;
247 }
248 
249 void ReverseIP( PCHAR pIP, PCHAR pReturn )
250 {
251     int i;
252     int j;
253     int k = 0;
254 
255     j = strlen( pIP ) - 1;
256     i = j;
257 
258     /* We have A.B.C.D
259        We will turn this into D.C.B.A and stick it in pReturn */
260 
261     /* A */
262     for( ; i > 0; i -= 1 ) if( '.' == pIP[i] ) break;
263 
264     strncpy( &pReturn[k], &pIP[i + 1], (j - i) );
265     k += (j - i);
266 
267     pReturn[k] = '.';
268     k += 1;
269 
270     i -= 1;
271     j = i;
272 
273     /* B */
274     for( ; i > 0; i -= 1 ) if( '.' == pIP[i] ) break;
275 
276     strncpy( &pReturn[k], &pIP[i + 1], (j - i) );
277     k += (j - i);
278 
279     pReturn[k] = '.';
280     k += 1;
281 
282     i -= 1;
283     j = i;
284 
285     /* C */
286     for( ; i > 0; i -= 1 ) if( '.' == pIP[i] ) break;
287 
288     strncpy( &pReturn[k], &pIP[i + 1], (j - i) );
289     k += (j - i);
290 
291     pReturn[k] = '.';
292     k += 1;
293 
294     i -= 1;
295     j = i;
296 
297     /* D */
298     for( ; i > 0; i -= 1 );
299 
300     strncpy( &pReturn[k], &pIP[i], (j - i) + 1 );
301     k += (j - i) + 1;
302 
303     pReturn[k] = '\0';
304 }
305 
306 BOOL IsValidIP( PCHAR pInput )
307 {
308     int i = 0, l = 0, b = 0, c = 1;
309 
310     /* Max length of an IP, e.g. 255.255.255.255, is 15 characters. */
311     l = strlen( pInput );
312     if( l > 15 ) return FALSE;
313 
314     /* 'b' is the count of the current segment. It gets reset after seeing a
315        '.'. */
316     for( ; i < l; i += 1 )
317     {
318         if( '.' == pInput[i] )
319         {
320             if( !b ) return FALSE;
321             if( b > 3 ) return FALSE;
322 
323             b = 0;
324             c += 1;
325         }
326         else
327         {
328             b += 1;
329 
330             if( (pInput[i] < '0') || (pInput[i] > '9') ) return FALSE;
331         }
332     }
333 
334     if( b > 3 ) return FALSE;
335 
336     /* 'c' is the number of segments seen. If it's less than 4, then it's not
337        a valid IP. */
338     if( c < 4 ) return FALSE;
339 
340     return TRUE;
341 }
342 
343 int ExtractName( PCHAR pBuffer, PCHAR pOutput, USHORT Offset, UCHAR Limit )
344 {
345     int c = 0, d = 0, i = 0, j = 0, k = 0, l = 0, m = 0;
346 
347     i = Offset;
348 
349     /* If Limit == 0, then we assume "no" limit. */
350     d = Limit;
351     if( 0 == Limit ) d = 255;
352 
353     while( d > 0 )
354     {
355         l = pBuffer[i] & 0xFF;
356         i += 1;
357         if( !m ) c += 1;
358 
359         if( 0xC0 == l )
360         {
361             if( !m ) c += 1;
362             m = 1;
363             d += (255 - Limit);
364             i = pBuffer[i];
365         }
366         else
367         {
368             for( j = 0; j < l; j += 1 )
369             {
370                 pOutput[k] = pBuffer[i];
371 
372                 i += 1;
373                 if( !m ) c += 1;
374                 k += 1;
375                 d -= 1;
376             }
377 
378             d -= 1;
379 
380             if( !pBuffer[i] || (d < 1) ) break;
381 
382             pOutput[k] = '.';
383             k += 1;
384         }
385     };
386 
387     if( !m )
388     {
389         if( !Limit ) c += 1;
390     }
391 
392     pOutput[k] = '\0';
393 
394     return c;
395 }
396 
397 int ExtractIP( PCHAR pBuffer, PCHAR pOutput, USHORT Offset )
398 {
399     int c = 0, l = 0, i = 0, v = 0;
400 
401     i = Offset;
402 
403     v = (UCHAR)pBuffer[i];
404     l += 1;
405     i += 1;
406 
407     sprintf( &pOutput[c], "%d.", v );
408     c += strlen( &pOutput[c] );
409 
410     v = (UCHAR)pBuffer[i];
411     l += 1;
412     i += 1;
413 
414     sprintf( &pOutput[c], "%d.", v );
415     c += strlen( &pOutput[c] );
416 
417     v = (UCHAR)pBuffer[i];
418     l += 1;
419     i += 1;
420 
421     sprintf( &pOutput[c], "%d.", v );
422     c += strlen( &pOutput[c] );
423 
424     v = (UCHAR)pBuffer[i];
425     l += 1;
426     i += 1;
427 
428     sprintf( &pOutput[c], "%d", v );
429     c += strlen( &pOutput[c] );
430 
431     pOutput[c] = '\0';
432 
433     return l;
434 }
435 
436 void PrintD2( PCHAR pBuffer, DWORD BufferLength )
437 {
438     USHORT RequestID;
439     UCHAR Header1, Header2;
440     USHORT NumQuestions, NumAnswers, NumAuthority, NumAdditional;
441     USHORT Type, Class;
442     CHAR pName[255];
443     int i = 0, k = 0;
444 
445     RequestID = ntohs( ((PUSHORT)&pBuffer[i])[0] );
446     i += 2;
447 
448     Header1 = pBuffer[i];
449     i += 1;
450 
451     Header2 = pBuffer[i];
452     i += 1;
453 
454     NumQuestions = ntohs( ((PSHORT)&pBuffer[i])[0] );
455     i += 2;
456 
457     NumAnswers = ntohs( ((PSHORT)&pBuffer[i])[0] );
458     i += 2;
459 
460     NumAuthority = ntohs( ((PUSHORT)&pBuffer[i])[0] );
461     i += 2;
462 
463     NumAdditional = ntohs( ((PUSHORT)&pBuffer[i])[0] );
464     i += 2;
465 
466     _tprintf( _T("------------\n") );
467     _tprintf( _T("SendRequest(), len %d\n"), (int)BufferLength );
468     _tprintf( _T("    HEADER:\n") );
469     _tprintf( _T("        opcode = %s, id = %d, rcode = %s\n"),
470                  OpcodeIDtoOpcodeName( (Header1 & 0x78) >> 3 ),
471                  (int)RequestID,
472                  RCodeIDtoRCodeName( Header2 & 0x0F ) );
473 
474     _tprintf( _T("        header flags:  query") );
475     if( Header1 & 0x01 ) _tprintf( _T(", want recursion") );
476     _tprintf( _T("\n") );
477 
478     _tprintf( _T("        questions = %d,  answers = %d,"
479                  "  authority records = %d,  additional = %d\n\n"),
480                  (int)NumQuestions,
481                  (int)NumAnswers,
482                  (int)NumAuthority,
483                  (int)NumAdditional );
484 
485     if( NumQuestions )
486     {
487         _tprintf( _T("    QUESTIONS:\n") );
488 
489         for( k = 0; k < NumQuestions; k += 1 )
490         {
491             i += ExtractName( pBuffer, pName, i, 0 );
492 
493             _tprintf( _T("        %s"), pName );
494 
495             Type = ntohs( ((PUSHORT)&pBuffer[i])[0] );
496             i += 2;
497 
498             Class = ntohs( ((PUSHORT)&pBuffer[i])[0] );
499             i += 2;
500 
501             _tprintf( _T(", type = %s, class = %s\n"),
502                       TypeIDtoTypeName( Type ),
503                       ClassIDtoClassName( Class ) );
504         }
505     }
506 
507     _tprintf( _T("\n------------\n") );
508 }
509 
510 void PrintDebug( PCHAR pBuffer, DWORD BufferLength )
511 {
512     USHORT ResponseID;
513     UCHAR Header1, Header2;
514     USHORT NumQuestions, NumAnswers, NumAuthority, NumAdditional;
515     USHORT Type, Class;
516     ULONG TTL;
517     CHAR pName[255];
518     int d = 0, i = 0, k = 0;
519 
520     ResponseID = ntohs( ((PUSHORT)&pBuffer[i])[0] );
521     i += 2;
522 
523     Header1 = pBuffer[i];
524     i += 1;
525 
526     Header2 = pBuffer[i];
527     i += 1;
528 
529     NumQuestions = ntohs( ((PSHORT)&pBuffer[i])[0] );
530     i += 2;
531 
532     NumAnswers = ntohs( ((PSHORT)&pBuffer[i])[0] );
533     i += 2;
534 
535     NumAuthority = ntohs( ((PUSHORT)&pBuffer[i])[0] );
536     i += 2;
537 
538     NumAdditional = ntohs( ((PUSHORT)&pBuffer[i])[0] );
539     i += 2;
540 
541     _tprintf( _T("------------\n") );
542     _tprintf( _T("Got answer (%d bytes):\n"), (int)BufferLength );
543     _tprintf( _T("    HEADER:\n") );
544     _tprintf( _T("        opcode = %s, id = %d, rcode = %s\n"),
545                  OpcodeIDtoOpcodeName( (Header1 & 0x78) >> 3 ),
546                  (int)ResponseID,
547                  RCodeIDtoRCodeName( Header2 & 0x0F ) );
548 
549     _tprintf( _T("        header flags:  response") );
550     if( Header1 & 0x01 ) _tprintf( _T(", want recursion") );
551     if( Header2 & 0x80 ) _tprintf( _T(", recursion avail.") );
552     _tprintf( _T("\n") );
553 
554     _tprintf( _T("        questions = %d,  answers = %d,  "
555                  "authority records = %d,  additional = %d\n\n"),
556                  (int)NumQuestions,
557                  (int)NumAnswers,
558                  (int)NumAuthority,
559                  (int)NumAdditional );
560 
561     if( NumQuestions )
562     {
563         _tprintf( _T("    QUESTIONS:\n") );
564 
565         for( k = 0; k < NumQuestions; k += 1 )
566         {
567             i += ExtractName( pBuffer, pName, i, 0 );
568 
569             _tprintf( _T("        %s"), pName );
570 
571             Type = ntohs( ((PUSHORT)&pBuffer[i])[0] );
572             i += 2;
573 
574             Class = ntohs( ((PUSHORT)&pBuffer[i])[0] );
575             i += 2;
576 
577             _tprintf( _T(", type = %s, class = %s\n"),
578                       TypeIDtoTypeName( Type ),
579                       ClassIDtoClassName( Class ) );
580         }
581     }
582 
583     if( NumAnswers )
584     {
585         _tprintf( _T("    ANSWERS:\n") );
586 
587         for( k = 0; k < NumAnswers; k += 1 )
588         {
589             _tprintf( _T("    ->  ") );
590 
591             /* Print out the name. */
592             i += ExtractName( pBuffer, pName, i, 0 );
593 
594             _tprintf( _T("%s\n"), pName );
595 
596             /* Print out the type, class and data length. */
597             Type = ntohs( ((PUSHORT)&pBuffer[i])[0] );
598             i += 2;
599 
600             Class = ntohs( ((PUSHORT)&pBuffer[i])[0] );
601             i += 2;
602 
603             TTL = ntohl( ((PULONG)&pBuffer[i])[0] );
604             i += 4;
605 
606             d = ntohs( ((PUSHORT)&pBuffer[i])[0] );
607             i += 2;
608 
609             _tprintf( _T("        type = %s, class = %s, dlen = %d\n"),
610                       TypeIDtoTypeName( Type ),
611                       ClassIDtoClassName( Class ),
612                       d );
613 
614             /* Print out the answer. */
615             if( TYPE_A == Type )
616             {
617                 i += ExtractIP( pBuffer, pName, i );
618 
619                 _tprintf( _T("        internet address = %s\n"), pName );
620             }
621             else
622             {
623                 i += ExtractName( pBuffer, pName, i, d );
624 
625                 _tprintf( _T("        name = %s\n"), pName );
626             }
627 
628             _tprintf( _T("        ttl = %d ()\n"), (int)TTL );
629         }
630     }
631 
632     if( NumAuthority )
633     {
634         _tprintf( _T("    AUTHORITY RECORDS:\n") );
635 
636         for( k = 0; k < NumAuthority; k += 1 )
637         {
638             /* Print out the zone name. */
639             i += ExtractName( pBuffer, pName, i, 0 );
640 
641             _tprintf( _T("    ->  %s\n"), pName );
642 
643             /* Print out the type, class, data length and TTL. */
644             Type = ntohs( ((PUSHORT)&pBuffer[i])[0] );
645             i += 2;
646 
647             Class = ntohs( ((PUSHORT)&pBuffer[i])[0] );
648             i += 2;
649 
650             TTL = ntohl( ((PULONG)&pBuffer[i])[0] );
651             i += 4;
652 
653             d = ntohs( ((PUSHORT)&pBuffer[i])[0] );
654             i += 2;
655 
656             _tprintf( _T("        type = %s, class = %s, dlen = %d\n"),
657                       TypeIDtoTypeName( Type ),
658                       ClassIDtoClassName( Class ),
659                       d );
660 
661             /* TODO: There might be more types? */
662             if( TYPE_NS == Type )
663             {
664                 /* Print out the NS. */
665                 i += ExtractName( pBuffer, pName, i, d );
666 
667                 _tprintf( _T("        nameserver = %s\n"), pName );
668 
669                 _tprintf( _T("        ttl = %d ()\n"), (int)TTL );
670             }
671             else if( TYPE_SOA == Type )
672             {
673                 _tprintf( _T("        ttl = %d ()\n"), (int)TTL );
674 
675                 /* Print out the primary NS. */
676                 i += ExtractName( pBuffer, pName, i, 0 );
677 
678                 _tprintf( _T("        primary name server = %s\n"), pName );
679 
680                 /* Print out the responsible mailbox. */
681                 i += ExtractName( pBuffer, pName, i, 0 );
682 
683                 _tprintf( _T("        responsible mail addr = %s\n"), pName );
684 
685                 /* Print out the serial, refresh, retry, expire and default TTL. */
686                 _tprintf( _T("        serial = ()\n") );
687                 _tprintf( _T("        refresh = ()\n") );
688                 _tprintf( _T("        retry = ()\n") );
689                 _tprintf( _T("        expire = ()\n") );
690                 _tprintf( _T("        default TTL = ()\n") );
691                 i += 20;
692             }
693         }
694     }
695 
696     if( NumAdditional )
697     {
698         _tprintf( _T("    ADDITIONAL:\n") );
699 
700         for( k = 0; k < NumAdditional; k += 1 )
701         {
702             /* Print the name. */
703             i += ExtractName( pBuffer, pName, i, 0 );
704 
705             _tprintf( _T("    ->  %s\n"), pName );
706 
707             /* Print out the type, class, data length and TTL. */
708             Type = ntohs( ((PUSHORT)&pBuffer[i])[0] );
709             i += 2;
710 
711             Class = ntohs( ((PUSHORT)&pBuffer[i])[0] );
712             i += 2;
713 
714             TTL = ntohl( ((PULONG)&pBuffer[i])[0] );
715             i += 4;
716 
717             d = ntohs( ((PUSHORT)&pBuffer[i])[0] );
718             i += 2;
719 
720             _tprintf( _T("        type = %s, class = %s, dlen = %d\n"),
721                       TypeIDtoTypeName( Type ),
722                       ClassIDtoClassName( Class ),
723                       d );
724 
725             /* TODO: There might be more types? */
726             if( TYPE_A == Type )
727             {
728                 /* Print out the NS. */
729                 i += ExtractIP( pBuffer, pName, i );
730 
731                 _tprintf( _T("        internet address = %s\n"), pName );
732 
733                 _tprintf( _T("        ttl = %d ()\n"), (int)TTL );
734             }
735         }
736     }
737 
738     _tprintf( _T("\n------------\n") );
739 }
740 
741 PCHAR OpcodeIDtoOpcodeName( UCHAR Opcode )
742 {
743     switch( Opcode & 0x0F )
744     {
745     case OPCODE_QUERY:
746         return OpcodeQuery;
747 
748     case OPCODE_IQUERY:
749         return OpcodeIQuery;
750 
751     case OPCODE_STATUS:
752         return OpcodeStatus;
753 
754     default:
755         return OpcodeReserved;
756     }
757 }
758 
759 PCHAR RCodeIDtoRCodeName( UCHAR RCode )
760 {
761     switch( RCode & 0x0F )
762     {
763     case RCODE_NOERROR:
764         return RCodeNOERROR;
765 
766     case RCODE_FORMERR:
767         return RCodeFORMERR;
768 
769     case RCODE_FAILURE:
770         return RCodeFAILURE;
771 
772     case RCODE_NXDOMAIN:
773         return RCodeNXDOMAIN;
774 
775     case RCODE_NOTIMP:
776         return RCodeNOTIMP;
777 
778     case RCODE_REFUSED:
779         return RCodeREFUSED;
780 
781     default:
782         return RCodeReserved;
783     }
784 }
785 
786 PCHAR TypeIDtoTypeName( USHORT TypeID )
787 {
788     switch( TypeID )
789     {
790     case TYPE_A:
791         return TypeA;
792 
793     case TYPE_NS:
794         return TypeNS;
795 
796     case TYPE_CNAME:
797         return TypeCNAME;
798 
799     case TYPE_SOA:
800         return TypeSOA;
801 
802     case TYPE_WKS:
803         return TypeSRV;
804 
805     case TYPE_PTR:
806         return TypePTR;
807 
808     case TYPE_MX:
809         return TypeMX;
810 
811     case TYPE_ANY:
812         return TypeAny;
813 
814     default:
815         return "Unknown";
816     }
817 }
818 
819 USHORT TypeNametoTypeID( PCHAR TypeName )
820 {
821     if( !strncmp( TypeName, TypeA, strlen( TypeA ) ) ) return TYPE_A;
822     if( !strncmp( TypeName, TypeNS, strlen( TypeNS ) ) ) return TYPE_NS;
823     if( !strncmp( TypeName, TypeCNAME, strlen( TypeCNAME ) ) ) return TYPE_CNAME;
824     if( !strncmp( TypeName, TypeSOA, strlen( TypeSOA ) ) ) return TYPE_SOA;
825     if( !strncmp( TypeName, TypeSRV, strlen( TypeSRV ) ) ) return TYPE_WKS;
826     if( !strncmp( TypeName, TypePTR, strlen( TypePTR ) ) ) return TYPE_PTR;
827     if( !strncmp( TypeName, TypeMX, strlen( TypeMX ) ) ) return TYPE_MX;
828     if( !strncmp( TypeName, TypeAny, strlen( TypeAny ) ) ) return TYPE_ANY;
829 
830     return 0;
831 }
832 
833 PCHAR ClassIDtoClassName( USHORT ClassID )
834 {
835     switch( ClassID )
836     {
837     case CLASS_IN:
838         return ClassIN;
839 
840     case CLASS_ANY:
841         return ClassAny;
842 
843     default:
844         return "Unknown";
845     }
846 }
847 
848 USHORT ClassNametoClassID( PCHAR ClassName )
849 {
850     if( !strncmp( ClassName, ClassIN, strlen( ClassIN ) ) ) return CLASS_IN;
851     if( !strncmp( ClassName, ClassAny, strlen( ClassAny ) ) ) return CLASS_ANY;
852 
853     return 0;
854 }
855