2 * PROJECT: ReactOS nslookup utility
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: applications/network/nslookup/utility.c
5 * PURPOSE: Support functions for nslookup.c
6 * COPYRIGHT: Copyright 2009 Lucas Suggs <lucas.suggs@gmail.com>
14 BOOL
SendRequest( PCHAR pInBuffer
,
17 PULONG pOutBufferLength
)
20 USHORT RequestID
, ResponseID
;
23 SOCKADDR_IN RecAddr
, RecAddr2
, SendAddr
;
24 int SendAddrLen
= sizeof(SendAddr
);
26 RtlZeroMemory( &RecAddr
, sizeof(SOCKADDR_IN
) );
27 RtlZeroMemory( &RecAddr2
, sizeof(SOCKADDR_IN
) );
28 RtlZeroMemory( &SendAddr
, sizeof(SOCKADDR_IN
) );
30 /* Pull the request ID from the buffer. */
31 RequestID
= ntohs( ((PSHORT
)&pInBuffer
[0])[0] );
33 /* If D2 flags is enabled, then display D2 information. */
34 if( State
.d2
) PrintD2( pInBuffer
, InBufferLength
);
36 /* Create the sockets for both send and receive. */
37 s
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
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") );
143 /* Wait for the DNS reply. */
148 (SOCKADDR
*)&SendAddr
,
150 if( j
== SOCKET_ERROR
)
152 switch( WSAGetLastError() )
154 case WSANOTINITIALISED
:
155 _tprintf( _T("recvfrom() failed with WSANOTINITIALIZED\n") );
158 _tprintf( _T("recvfrom() failed with WSAENETDOWN\n") );
161 _tprintf( _T("recvfrom() failed with WSAEACCES\n") );
164 _tprintf( _T("recvfrom() failed with WSAEINVAL\n") );
167 _tprintf( _T("recvfrom() failed with WSAEINTR\n") );
170 _tprintf( _T("recvfrom() failed with WSAEINPROGRESS\n") );
173 _tprintf( _T("recvfrom() failed with WSAEFAULT\n") );
176 _tprintf( _T("recvfrom() failed with WSAENETRESET\n") );
179 _tprintf( _T("recvfrom() failed with WSAENOBUFS\n") );
182 _tprintf( _T("recvfrom() failed with WSAENOTCONN\n") );
185 _tprintf( _T("recvfrom() failed with WSAENOTSOCK\n") );
188 _tprintf( _T("recvfrom() failed with WSAEOPNOTSUPP\n") );
191 _tprintf( _T("recvfrom() failed with WSAESHUTDOWN\n") );
194 _tprintf( _T("recvfrom() failed with WSAEWOULDBLOCK\n") );
197 _tprintf( _T("recvfrom() failed with WSAEMSGSIZE\n") );
199 case WSAEHOSTUNREACH
:
200 _tprintf( _T("recvfrom() failed with WSAEHOSTUNREACH\n") );
202 case WSAECONNABORTED
:
203 _tprintf( _T("recvfrom() failed with WSAECONNABORTED\n") );
206 _tprintf( _T("recvfrom() failed with WSAECONNRESET\n") );
208 case WSAEADDRNOTAVAIL
:
209 _tprintf( _T("recvfrom() failed with WSAEADDRNOTAVAIL\n") );
211 case WSAEAFNOSUPPORT
:
212 _tprintf( _T("recvfrom() failed with WSAEAFNOSUPPORT\n") );
214 case WSAEDESTADDRREQ
:
215 _tprintf( _T("recvfrom() failed with WSAEDESTADDRREQ\n") );
218 _tprintf( _T("recvfrom() failed with WSAENETUNREACH\n") );
221 _tprintf( _T("recvfrom() failed with WSAETIMEDOUT\n") );
224 _tprintf( _T("recvfrom() failed with unknown error\n") );
230 ResponseID
= ntohs( ((PSHORT
)&pOutBuffer
[0])[0] );
232 if( ResponseID
== RequestID
) bWait
= FALSE
;
235 /* We don't need the sockets anymore. */
238 /* If debug information then display debug information. */
239 if( State
.debug
) PrintDebug( pOutBuffer
, j
);
241 /* Return the real output buffer length. */
242 *pOutBufferLength
= j
;
247 void ReverseIP( PCHAR pIP
, PCHAR pReturn
)
253 j
= strlen( pIP
) - 1;
257 We will turn this into D.C.B.A and stick it in pReturn */
260 for( ; i
> 0; i
-= 1 ) if( '.' == pIP
[i
] ) break;
262 strncpy( &pReturn
[k
], &pIP
[i
+ 1], (j
- i
) );
272 for( ; i
> 0; i
-= 1 ) if( '.' == pIP
[i
] ) break;
274 strncpy( &pReturn
[k
], &pIP
[i
+ 1], (j
- i
) );
284 for( ; i
> 0; i
-= 1 ) if( '.' == pIP
[i
] ) break;
286 strncpy( &pReturn
[k
], &pIP
[i
+ 1], (j
- i
) );
296 for( ; i
> 0; i
-= 1 );
298 strncpy( &pReturn
[k
], &pIP
[i
], (j
- i
) + 1 );
304 BOOL
IsValidIP( PCHAR pInput
)
306 int i
= 0, l
= 0, b
= 0, c
= 1;
308 /* Max length of an IP, e.g. 255.255.255.255, is 15 characters. */
309 l
= strlen( pInput
);
310 if( l
> 15 ) return FALSE
;
312 /* 'b' is the count of the current segment. It gets reset after seeing a
314 for( ; i
< l
; i
+= 1 )
316 if( '.' == pInput
[i
] )
318 if( !b
) return FALSE
;
319 if( b
> 3 ) return FALSE
;
328 if( (pInput
[i
] < '0') || (pInput
[i
] > '9') ) return FALSE
;
332 if( b
> 3 ) return FALSE
;
334 /* 'c' is the number of segments seen. If it's less than 4, then it's not
336 if( c
< 4 ) return FALSE
;
341 int ExtractName( PCHAR pBuffer
, PCHAR pOutput
, USHORT Offset
, UCHAR Limit
)
343 int c
= 0, d
= 0, i
= 0, j
= 0, k
= 0, l
= 0, m
= 0;
347 /* If Limit == 0, then we assume "no" limit. */
349 if( 0 == Limit
) d
= 255;
353 l
= pBuffer
[i
] & 0xFF;
366 for( j
= 0; j
< l
; j
+= 1 )
368 pOutput
[k
] = pBuffer
[i
];
378 if( !pBuffer
[i
] || (d
< 1) ) break;
395 int ExtractIP( PCHAR pBuffer
, PCHAR pOutput
, USHORT Offset
)
397 int c
= 0, l
= 0, i
= 0, v
= 0;
401 v
= (UCHAR
)pBuffer
[i
];
405 sprintf( &pOutput
[c
], "%d.", v
);
406 c
+= strlen( &pOutput
[c
] );
408 v
= (UCHAR
)pBuffer
[i
];
412 sprintf( &pOutput
[c
], "%d.", v
);
413 c
+= strlen( &pOutput
[c
] );
415 v
= (UCHAR
)pBuffer
[i
];
419 sprintf( &pOutput
[c
], "%d.", v
);
420 c
+= strlen( &pOutput
[c
] );
422 v
= (UCHAR
)pBuffer
[i
];
426 sprintf( &pOutput
[c
], "%d", v
);
427 c
+= strlen( &pOutput
[c
] );
434 void PrintD2( PCHAR pBuffer
, DWORD BufferLength
)
437 UCHAR Header1
, Header2
;
438 USHORT NumQuestions
, NumAnswers
, NumAuthority
, NumAdditional
;
443 RequestID
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
446 Header1
= pBuffer
[i
];
449 Header2
= pBuffer
[i
];
452 NumQuestions
= ntohs( ((PSHORT
)&pBuffer
[i
])[0] );
455 NumAnswers
= ntohs( ((PSHORT
)&pBuffer
[i
])[0] );
458 NumAuthority
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
461 NumAdditional
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
464 _tprintf( _T("------------\n") );
465 _tprintf( _T("SendRequest(), len %d\n"), (int)BufferLength
);
466 _tprintf( _T(" HEADER:\n") );
467 _tprintf( _T(" opcode = %s, id = %d, rcode = %s\n"),
468 OpcodeIDtoOpcodeName( (Header1
& 0x78) >> 3 ),
470 RCodeIDtoRCodeName( Header2
& 0x0F ) );
472 _tprintf( _T(" header flags: query") );
473 if( Header1
& 0x01 ) _tprintf( _T(", want recursion") );
474 _tprintf( _T("\n") );
476 _tprintf( _T(" questions = %d, answers = %d,"
477 " authority records = %d, additional = %d\n\n"),
481 (int)NumAdditional
);
485 _tprintf( _T(" QUESTIONS:\n") );
487 for( k
= 0; k
< NumQuestions
; k
+= 1 )
489 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
491 _tprintf( _T(" %s"), pName
);
493 Type
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
496 Class
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
499 _tprintf( _T(", type = %s, class = %s\n"),
500 TypeIDtoTypeName( Type
),
501 ClassIDtoClassName( Class
) );
505 _tprintf( _T("\n------------\n") );
508 void PrintDebug( PCHAR pBuffer
, DWORD BufferLength
)
511 UCHAR Header1
, Header2
;
512 USHORT NumQuestions
, NumAnswers
, NumAuthority
, NumAdditional
;
516 int d
= 0, i
= 0, k
= 0;
518 ResponseID
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
521 Header1
= pBuffer
[i
];
524 Header2
= pBuffer
[i
];
527 NumQuestions
= ntohs( ((PSHORT
)&pBuffer
[i
])[0] );
530 NumAnswers
= ntohs( ((PSHORT
)&pBuffer
[i
])[0] );
533 NumAuthority
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
536 NumAdditional
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
539 _tprintf( _T("------------\n") );
540 _tprintf( _T("Got answer (%d bytes):\n"), (int)BufferLength
);
541 _tprintf( _T(" HEADER:\n") );
542 _tprintf( _T(" opcode = %s, id = %d, rcode = %s\n"),
543 OpcodeIDtoOpcodeName( (Header1
& 0x78) >> 3 ),
545 RCodeIDtoRCodeName( Header2
& 0x0F ) );
547 _tprintf( _T(" header flags: response") );
548 if( Header1
& 0x01 ) _tprintf( _T(", want recursion") );
549 if( Header2
& 0x80 ) _tprintf( _T(", recursion avail.") );
550 _tprintf( _T("\n") );
552 _tprintf( _T(" questions = %d, answers = %d, "
553 "authority records = %d, additional = %d\n\n"),
557 (int)NumAdditional
);
561 _tprintf( _T(" QUESTIONS:\n") );
563 for( k
= 0; k
< NumQuestions
; k
+= 1 )
565 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
567 _tprintf( _T(" %s"), pName
);
569 Type
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
572 Class
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
575 _tprintf( _T(", type = %s, class = %s\n"),
576 TypeIDtoTypeName( Type
),
577 ClassIDtoClassName( Class
) );
583 _tprintf( _T(" ANSWERS:\n") );
585 for( k
= 0; k
< NumAnswers
; k
+= 1 )
587 _tprintf( _T(" -> ") );
589 /* Print out the name. */
590 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
592 _tprintf( _T("%s\n"), pName
);
594 /* Print out the type, class and data length. */
595 Type
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
598 Class
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
601 TTL
= ntohl( ((PULONG
)&pBuffer
[i
])[0] );
604 d
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
607 _tprintf( _T(" type = %s, class = %s, dlen = %d\n"),
608 TypeIDtoTypeName( Type
),
609 ClassIDtoClassName( Class
),
612 /* Print out the answer. */
615 i
+= ExtractIP( pBuffer
, pName
, i
);
617 _tprintf( _T(" internet address = %s\n"), pName
);
621 i
+= ExtractName( pBuffer
, pName
, i
, d
);
623 _tprintf( _T(" name = %s\n"), pName
);
626 _tprintf( _T(" ttl = %d ()\n"), (int)TTL
);
632 _tprintf( _T(" AUTHORITY RECORDS:\n") );
634 for( k
= 0; k
< NumAuthority
; k
+= 1 )
636 /* Print out the zone name. */
637 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
639 _tprintf( _T(" -> %s\n"), pName
);
641 /* Print out the type, class, data length and TTL. */
642 Type
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
645 Class
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
648 TTL
= ntohl( ((PULONG
)&pBuffer
[i
])[0] );
651 d
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
654 _tprintf( _T(" type = %s, class = %s, dlen = %d\n"),
655 TypeIDtoTypeName( Type
),
656 ClassIDtoClassName( Class
),
659 /* TODO: There might be more types? */
660 if( TYPE_NS
== Type
)
662 /* Print out the NS. */
663 i
+= ExtractName( pBuffer
, pName
, i
, d
);
665 _tprintf( _T(" nameserver = %s\n"), pName
);
667 _tprintf( _T(" ttl = %d ()\n"), (int)TTL
);
669 else if( TYPE_SOA
== Type
)
671 _tprintf( _T(" ttl = %d ()\n"), (int)TTL
);
673 /* Print out the primary NS. */
674 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
676 _tprintf( _T(" primary name server = %s\n"), pName
);
678 /* Print out the responsible mailbox. */
679 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
681 _tprintf( _T(" responsible mail addr = %s\n"), pName
);
683 /* Print out the serial, refresh, retry, expire and default TTL. */
684 _tprintf( _T(" serial = ()\n") );
685 _tprintf( _T(" refresh = ()\n") );
686 _tprintf( _T(" retry = ()\n") );
687 _tprintf( _T(" expire = ()\n") );
688 _tprintf( _T(" default TTL = ()\n") );
696 _tprintf( _T(" ADDITIONAL:\n") );
698 for( k
= 0; k
< NumAdditional
; k
+= 1 )
700 /* Print the name. */
701 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
703 _tprintf( _T(" -> %s\n"), pName
);
705 /* Print out the type, class, data length and TTL. */
706 Type
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
709 Class
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
712 TTL
= ntohl( ((PULONG
)&pBuffer
[i
])[0] );
715 d
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
718 _tprintf( _T(" type = %s, class = %s, dlen = %d\n"),
719 TypeIDtoTypeName( Type
),
720 ClassIDtoClassName( Class
),
723 /* TODO: There might be more types? */
726 /* Print out the NS. */
727 i
+= ExtractIP( pBuffer
, pName
, i
);
729 _tprintf( _T(" internet address = %s\n"), pName
);
731 _tprintf( _T(" ttl = %d ()\n"), (int)TTL
);
736 _tprintf( _T("\n------------\n") );
739 PCHAR
OpcodeIDtoOpcodeName( UCHAR Opcode
)
741 switch( Opcode
& 0x0F )
753 return OpcodeReserved
;
757 PCHAR
RCodeIDtoRCodeName( UCHAR RCode
)
759 switch( RCode
& 0x0F )
771 return RCodeNXDOMAIN
;
780 return RCodeReserved
;
784 PCHAR
TypeIDtoTypeName( USHORT TypeID
)
817 USHORT
TypeNametoTypeID( PCHAR TypeName
)
819 if( !strncmp( TypeName
, TypeA
, strlen( TypeA
) ) ) return TYPE_A
;
820 if( !strncmp( TypeName
, TypeNS
, strlen( TypeNS
) ) ) return TYPE_NS
;
821 if( !strncmp( TypeName
, TypeCNAME
, strlen( TypeCNAME
) ) ) return TYPE_CNAME
;
822 if( !strncmp( TypeName
, TypeSOA
, strlen( TypeSOA
) ) ) return TYPE_SOA
;
823 if( !strncmp( TypeName
, TypeSRV
, strlen( TypeSRV
) ) ) return TYPE_WKS
;
824 if( !strncmp( TypeName
, TypePTR
, strlen( TypePTR
) ) ) return TYPE_PTR
;
825 if( !strncmp( TypeName
, TypeMX
, strlen( TypeMX
) ) ) return TYPE_MX
;
826 if( !strncmp( TypeName
, TypeAny
, strlen( TypeAny
) ) ) return TYPE_ANY
;
831 PCHAR
ClassIDtoClassName( USHORT ClassID
)
846 USHORT
ClassNametoClassID( PCHAR ClassName
)
848 if( !strncmp( ClassName
, ClassIN
, strlen( ClassIN
) ) ) return CLASS_IN
;
849 if( !strncmp( ClassName
, ClassAny
, strlen( ClassAny
) ) ) return CLASS_ANY
;