15090768aa7d50b0474502d4b6c9fc03e7167825
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>
11 BOOL
SendRequest( PCHAR pInBuffer
,
14 PULONG pOutBufferLength
)
17 USHORT RequestID
, ResponseID
;
20 SOCKADDR_IN RecAddr
, RecAddr2
, SendAddr
;
21 int SendAddrLen
= sizeof(SendAddr
);
23 RtlZeroMemory( &RecAddr
, sizeof(SOCKADDR_IN
) );
24 RtlZeroMemory( &RecAddr2
, sizeof(SOCKADDR_IN
) );
25 RtlZeroMemory( &SendAddr
, sizeof(SOCKADDR_IN
) );
27 /* Pull the request ID from the buffer. */
28 RequestID
= ntohs( ((PSHORT
)&pInBuffer
[0])[0] );
30 /* If D2 flags is enabled, then display D2 information. */
31 if( State
.d2
) PrintD2( pInBuffer
, InBufferLength
);
33 /* Create the sockets for both send and receive. */
34 s
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
36 if (s
== INVALID_SOCKET
)
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
);
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
);
49 /* Bind the receive socket. */
50 bind( s
, (SOCKADDR
*)&RecAddr2
, sizeof(RecAddr2
) );
52 /* Send the datagram to the DNS server. */
59 if( j
== SOCKET_ERROR
)
61 switch( WSAGetLastError() )
63 case WSANOTINITIALISED
:
64 _tprintf( _T("sendto() failed with WSANOTINITIALIZED\n") );
67 _tprintf( _T("sendto() failed with WSAENETDOWN\n") );
70 _tprintf( _T("sendto() failed with WSAEACCES\n") );
73 _tprintf( _T("sendto() failed with WSAEINVAL\n") );
76 _tprintf( _T("sendto() failed with WSAEINTR\n") );
79 _tprintf( _T("sendto() failed with WSAEINPROGRESS\n") );
82 _tprintf( _T("sendto() failed with WSAEFAULT\n") );
85 _tprintf( _T("sendto() failed with WSAENETRESET\n") );
88 _tprintf( _T("sendto() failed with WSAENOBUFS\n") );
91 _tprintf( _T("sendto() failed with WSAENOTCONN\n") );
94 _tprintf( _T("sendto() failed with WSAENOTSOCK\n") );
97 _tprintf( _T("sendto() failed with WSAEOPNOTSUPP\n") );
100 _tprintf( _T("sendto() failed with WSAESHUTDOWN\n") );
103 _tprintf( _T("sendto() failed with WSAEWOULDBLOCK\n") );
106 _tprintf( _T("sendto() failed with WSAEMSGSIZE\n") );
108 case WSAEHOSTUNREACH
:
109 _tprintf( _T("sendto() failed with WSAEHOSTUNREACH\n") );
111 case WSAECONNABORTED
:
112 _tprintf( _T("sendto() failed with WSAECONNABORTED\n") );
115 _tprintf( _T("sendto() failed with WSAECONNRESET\n") );
117 case WSAEADDRNOTAVAIL
:
118 _tprintf( _T("sendto() failed with WSAEADDRNOTAVAIL\n") );
120 case WSAEAFNOSUPPORT
:
121 _tprintf( _T("sendto() failed with WSAEAFNOSUPPORT\n") );
123 case WSAEDESTADDRREQ
:
124 _tprintf( _T("sendto() failed with WSAEDESTADDRREQ\n") );
127 _tprintf( _T("sendto() failed with WSAENETUNREACH\n") );
130 _tprintf( _T("sendto() failed with WSAETIMEDOUT\n") );
133 _tprintf( _T("sendto() failed with unknown error\n") );
144 /* Wait for the DNS reply. */
149 (SOCKADDR
*)&SendAddr
,
151 if( j
== SOCKET_ERROR
)
153 switch( WSAGetLastError() )
155 case WSANOTINITIALISED
:
156 _tprintf( _T("recvfrom() failed with WSANOTINITIALIZED\n") );
159 _tprintf( _T("recvfrom() failed with WSAENETDOWN\n") );
162 _tprintf( _T("recvfrom() failed with WSAEACCES\n") );
165 _tprintf( _T("recvfrom() failed with WSAEINVAL\n") );
168 _tprintf( _T("recvfrom() failed with WSAEINTR\n") );
171 _tprintf( _T("recvfrom() failed with WSAEINPROGRESS\n") );
174 _tprintf( _T("recvfrom() failed with WSAEFAULT\n") );
177 _tprintf( _T("recvfrom() failed with WSAENETRESET\n") );
180 _tprintf( _T("recvfrom() failed with WSAENOBUFS\n") );
183 _tprintf( _T("recvfrom() failed with WSAENOTCONN\n") );
186 _tprintf( _T("recvfrom() failed with WSAENOTSOCK\n") );
189 _tprintf( _T("recvfrom() failed with WSAEOPNOTSUPP\n") );
192 _tprintf( _T("recvfrom() failed with WSAESHUTDOWN\n") );
195 _tprintf( _T("recvfrom() failed with WSAEWOULDBLOCK\n") );
198 _tprintf( _T("recvfrom() failed with WSAEMSGSIZE\n") );
200 case WSAEHOSTUNREACH
:
201 _tprintf( _T("recvfrom() failed with WSAEHOSTUNREACH\n") );
203 case WSAECONNABORTED
:
204 _tprintf( _T("recvfrom() failed with WSAECONNABORTED\n") );
207 _tprintf( _T("recvfrom() failed with WSAECONNRESET\n") );
209 case WSAEADDRNOTAVAIL
:
210 _tprintf( _T("recvfrom() failed with WSAEADDRNOTAVAIL\n") );
212 case WSAEAFNOSUPPORT
:
213 _tprintf( _T("recvfrom() failed with WSAEAFNOSUPPORT\n") );
215 case WSAEDESTADDRREQ
:
216 _tprintf( _T("recvfrom() failed with WSAEDESTADDRREQ\n") );
219 _tprintf( _T("recvfrom() failed with WSAENETUNREACH\n") );
222 _tprintf( _T("recvfrom() failed with WSAETIMEDOUT\n") );
225 _tprintf( _T("recvfrom() failed with unknown error\n") );
232 ResponseID
= ntohs( ((PSHORT
)&pOutBuffer
[0])[0] );
234 if( ResponseID
== RequestID
) bWait
= FALSE
;
237 /* We don't need the sockets anymore. */
240 /* If debug information then display debug information. */
241 if( State
.debug
) PrintDebug( pOutBuffer
, j
);
243 /* Return the real output buffer length. */
244 *pOutBufferLength
= j
;
249 void ReverseIP( PCHAR pIP
, PCHAR pReturn
)
255 j
= strlen( pIP
) - 1;
259 We will turn this into D.C.B.A and stick it in pReturn */
262 for( ; i
> 0; i
-= 1 ) if( '.' == pIP
[i
] ) break;
264 strncpy( &pReturn
[k
], &pIP
[i
+ 1], (j
- i
) );
274 for( ; i
> 0; i
-= 1 ) if( '.' == pIP
[i
] ) break;
276 strncpy( &pReturn
[k
], &pIP
[i
+ 1], (j
- i
) );
286 for( ; i
> 0; i
-= 1 ) if( '.' == pIP
[i
] ) break;
288 strncpy( &pReturn
[k
], &pIP
[i
+ 1], (j
- i
) );
298 for( ; i
> 0; i
-= 1 );
300 strncpy( &pReturn
[k
], &pIP
[i
], (j
- i
) + 1 );
306 BOOL
IsValidIP( PCHAR pInput
)
308 int i
= 0, l
= 0, b
= 0, c
= 1;
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
;
314 /* 'b' is the count of the current segment. It gets reset after seeing a
316 for( ; i
< l
; i
+= 1 )
318 if( '.' == pInput
[i
] )
320 if( !b
) return FALSE
;
321 if( b
> 3 ) return FALSE
;
330 if( (pInput
[i
] < '0') || (pInput
[i
] > '9') ) return FALSE
;
334 if( b
> 3 ) return FALSE
;
336 /* 'c' is the number of segments seen. If it's less than 4, then it's not
338 if( c
< 4 ) return FALSE
;
343 int ExtractName( PCHAR pBuffer
, PCHAR pOutput
, USHORT Offset
, UCHAR Limit
)
345 int c
= 0, d
= 0, i
= 0, j
= 0, k
= 0, l
= 0, m
= 0;
349 /* If Limit == 0, then we assume "no" limit. */
351 if( 0 == Limit
) d
= 255;
355 l
= pBuffer
[i
] & 0xFF;
368 for( j
= 0; j
< l
; j
+= 1 )
370 pOutput
[k
] = pBuffer
[i
];
380 if( !pBuffer
[i
] || (d
< 1) ) break;
397 int ExtractIP( PCHAR pBuffer
, PCHAR pOutput
, USHORT Offset
)
399 int c
= 0, l
= 0, i
= 0, v
= 0;
403 v
= (UCHAR
)pBuffer
[i
];
407 sprintf( &pOutput
[c
], "%d.", v
);
408 c
+= strlen( &pOutput
[c
] );
410 v
= (UCHAR
)pBuffer
[i
];
414 sprintf( &pOutput
[c
], "%d.", v
);
415 c
+= strlen( &pOutput
[c
] );
417 v
= (UCHAR
)pBuffer
[i
];
421 sprintf( &pOutput
[c
], "%d.", v
);
422 c
+= strlen( &pOutput
[c
] );
424 v
= (UCHAR
)pBuffer
[i
];
428 sprintf( &pOutput
[c
], "%d", v
);
429 c
+= strlen( &pOutput
[c
] );
436 void PrintD2( PCHAR pBuffer
, DWORD BufferLength
)
439 UCHAR Header1
, Header2
;
440 USHORT NumQuestions
, NumAnswers
, NumAuthority
, NumAdditional
;
445 RequestID
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
448 Header1
= pBuffer
[i
];
451 Header2
= pBuffer
[i
];
454 NumQuestions
= ntohs( ((PSHORT
)&pBuffer
[i
])[0] );
457 NumAnswers
= ntohs( ((PSHORT
)&pBuffer
[i
])[0] );
460 NumAuthority
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
463 NumAdditional
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
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 ),
472 RCodeIDtoRCodeName( Header2
& 0x0F ) );
474 _tprintf( _T(" header flags: query") );
475 if( Header1
& 0x01 ) _tprintf( _T(", want recursion") );
476 _tprintf( _T("\n") );
478 _tprintf( _T(" questions = %d, answers = %d,"
479 " authority records = %d, additional = %d\n\n"),
483 (int)NumAdditional
);
487 _tprintf( _T(" QUESTIONS:\n") );
489 for( k
= 0; k
< NumQuestions
; k
+= 1 )
491 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
493 _tprintf( _T(" %s"), pName
);
495 Type
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
498 Class
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
501 _tprintf( _T(", type = %s, class = %s\n"),
502 TypeIDtoTypeName( Type
),
503 ClassIDtoClassName( Class
) );
507 _tprintf( _T("\n------------\n") );
510 void PrintDebug( PCHAR pBuffer
, DWORD BufferLength
)
513 UCHAR Header1
, Header2
;
514 USHORT NumQuestions
, NumAnswers
, NumAuthority
, NumAdditional
;
518 int d
= 0, i
= 0, k
= 0;
520 ResponseID
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
523 Header1
= pBuffer
[i
];
526 Header2
= pBuffer
[i
];
529 NumQuestions
= ntohs( ((PSHORT
)&pBuffer
[i
])[0] );
532 NumAnswers
= ntohs( ((PSHORT
)&pBuffer
[i
])[0] );
535 NumAuthority
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
538 NumAdditional
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
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 ),
547 RCodeIDtoRCodeName( Header2
& 0x0F ) );
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") );
554 _tprintf( _T(" questions = %d, answers = %d, "
555 "authority records = %d, additional = %d\n\n"),
559 (int)NumAdditional
);
563 _tprintf( _T(" QUESTIONS:\n") );
565 for( k
= 0; k
< NumQuestions
; k
+= 1 )
567 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
569 _tprintf( _T(" %s"), pName
);
571 Type
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
574 Class
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
577 _tprintf( _T(", type = %s, class = %s\n"),
578 TypeIDtoTypeName( Type
),
579 ClassIDtoClassName( Class
) );
585 _tprintf( _T(" ANSWERS:\n") );
587 for( k
= 0; k
< NumAnswers
; k
+= 1 )
589 _tprintf( _T(" -> ") );
591 /* Print out the name. */
592 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
594 _tprintf( _T("%s\n"), pName
);
596 /* Print out the type, class and data length. */
597 Type
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
600 Class
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
603 TTL
= ntohl( ((PULONG
)&pBuffer
[i
])[0] );
606 d
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
609 _tprintf( _T(" type = %s, class = %s, dlen = %d\n"),
610 TypeIDtoTypeName( Type
),
611 ClassIDtoClassName( Class
),
614 /* Print out the answer. */
617 i
+= ExtractIP( pBuffer
, pName
, i
);
619 _tprintf( _T(" internet address = %s\n"), pName
);
623 i
+= ExtractName( pBuffer
, pName
, i
, d
);
625 _tprintf( _T(" name = %s\n"), pName
);
628 _tprintf( _T(" ttl = %d ()\n"), (int)TTL
);
634 _tprintf( _T(" AUTHORITY RECORDS:\n") );
636 for( k
= 0; k
< NumAuthority
; k
+= 1 )
638 /* Print out the zone name. */
639 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
641 _tprintf( _T(" -> %s\n"), pName
);
643 /* Print out the type, class, data length and TTL. */
644 Type
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
647 Class
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
650 TTL
= ntohl( ((PULONG
)&pBuffer
[i
])[0] );
653 d
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
656 _tprintf( _T(" type = %s, class = %s, dlen = %d\n"),
657 TypeIDtoTypeName( Type
),
658 ClassIDtoClassName( Class
),
661 /* TODO: There might be more types? */
662 if( TYPE_NS
== Type
)
664 /* Print out the NS. */
665 i
+= ExtractName( pBuffer
, pName
, i
, d
);
667 _tprintf( _T(" nameserver = %s\n"), pName
);
669 _tprintf( _T(" ttl = %d ()\n"), (int)TTL
);
671 else if( TYPE_SOA
== Type
)
673 _tprintf( _T(" ttl = %d ()\n"), (int)TTL
);
675 /* Print out the primary NS. */
676 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
678 _tprintf( _T(" primary name server = %s\n"), pName
);
680 /* Print out the responsible mailbox. */
681 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
683 _tprintf( _T(" responsible mail addr = %s\n"), pName
);
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") );
698 _tprintf( _T(" ADDITIONAL:\n") );
700 for( k
= 0; k
< NumAdditional
; k
+= 1 )
702 /* Print the name. */
703 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
705 _tprintf( _T(" -> %s\n"), pName
);
707 /* Print out the type, class, data length and TTL. */
708 Type
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
711 Class
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
714 TTL
= ntohl( ((PULONG
)&pBuffer
[i
])[0] );
717 d
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
720 _tprintf( _T(" type = %s, class = %s, dlen = %d\n"),
721 TypeIDtoTypeName( Type
),
722 ClassIDtoClassName( Class
),
725 /* TODO: There might be more types? */
728 /* Print out the NS. */
729 i
+= ExtractIP( pBuffer
, pName
, i
);
731 _tprintf( _T(" internet address = %s\n"), pName
);
733 _tprintf( _T(" ttl = %d ()\n"), (int)TTL
);
738 _tprintf( _T("\n------------\n") );
741 PCHAR
OpcodeIDtoOpcodeName( UCHAR Opcode
)
743 switch( Opcode
& 0x0F )
755 return OpcodeReserved
;
759 PCHAR
RCodeIDtoRCodeName( UCHAR RCode
)
761 switch( RCode
& 0x0F )
773 return RCodeNXDOMAIN
;
782 return RCodeReserved
;
786 PCHAR
TypeIDtoTypeName( USHORT TypeID
)
819 USHORT
TypeNametoTypeID( PCHAR TypeName
)
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
;
833 PCHAR
ClassIDtoClassName( USHORT ClassID
)
848 USHORT
ClassNametoClassID( PCHAR ClassName
)
850 if( !strncmp( ClassName
, ClassIN
, strlen( ClassIN
) ) ) return CLASS_IN
;
851 if( !strncmp( ClassName
, ClassAny
, strlen( ClassAny
) ) ) return CLASS_ANY
;