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>
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 /* Set up the structure to tell it where we are going. */
37 RecAddr
.sin_family
= AF_INET
;
38 RecAddr
.sin_port
= htons( State
.port
);
39 RecAddr
.sin_addr
.s_addr
= inet_addr( State
.DefaultServerAddress
);
41 /* Set up the structure to tell it what port to listen on. */
42 RecAddr2
.sin_family
= AF_INET
;
43 RecAddr2
.sin_port
= htons( State
.port
);
44 RecAddr2
.sin_addr
.s_addr
= htonl( INADDR_ANY
);
46 /* Bind the receive socket. */
47 bind( s
, (SOCKADDR
*)&RecAddr2
, sizeof(RecAddr2
) );
49 /* Send the datagram to the DNS server. */
56 if( j
== SOCKET_ERROR
)
58 switch( WSAGetLastError() )
60 case WSANOTINITIALISED
:
61 _tprintf( _T("sendto() failed with WSANOTINITIALIZED\n") );
64 _tprintf( _T("sendto() failed with WSAENETDOWN\n") );
67 _tprintf( _T("sendto() failed with WSAEACCES\n") );
70 _tprintf( _T("sendto() failed with WSAEINVAL\n") );
73 _tprintf( _T("sendto() failed with WSAEINTR\n") );
76 _tprintf( _T("sendto() failed with WSAEINPROGRESS\n") );
79 _tprintf( _T("sendto() failed with WSAEFAULT\n") );
82 _tprintf( _T("sendto() failed with WSAENETRESET\n") );
85 _tprintf( _T("sendto() failed with WSAENOBUFS\n") );
88 _tprintf( _T("sendto() failed with WSAENOTCONN\n") );
91 _tprintf( _T("sendto() failed with WSAENOTSOCK\n") );
94 _tprintf( _T("sendto() failed with WSAEOPNOTSUPP\n") );
97 _tprintf( _T("sendto() failed with WSAESHUTDOWN\n") );
100 _tprintf( _T("sendto() failed with WSAEWOULDBLOCK\n") );
103 _tprintf( _T("sendto() failed with WSAEMSGSIZE\n") );
105 case WSAEHOSTUNREACH
:
106 _tprintf( _T("sendto() failed with WSAEHOSTUNREACH\n") );
108 case WSAECONNABORTED
:
109 _tprintf( _T("sendto() failed with WSAECONNABORTED\n") );
112 _tprintf( _T("sendto() failed with WSAECONNRESET\n") );
114 case WSAEADDRNOTAVAIL
:
115 _tprintf( _T("sendto() failed with WSAEADDRNOTAVAIL\n") );
117 case WSAEAFNOSUPPORT
:
118 _tprintf( _T("sendto() failed with WSAEAFNOSUPPORT\n") );
120 case WSAEDESTADDRREQ
:
121 _tprintf( _T("sendto() failed with WSAEDESTADDRREQ\n") );
124 _tprintf( _T("sendto() failed with WSAENETUNREACH\n") );
127 _tprintf( _T("sendto() failed with WSAETIMEDOUT\n") );
130 _tprintf( _T("sendto() failed with unknown error\n") );
140 /* Wait for the DNS reply. */
145 (SOCKADDR
*)&SendAddr
,
147 if( j
== SOCKET_ERROR
)
149 switch( WSAGetLastError() )
151 case WSANOTINITIALISED
:
152 _tprintf( _T("recvfrom() failed with WSANOTINITIALIZED\n") );
155 _tprintf( _T("recvfrom() failed with WSAENETDOWN\n") );
158 _tprintf( _T("recvfrom() failed with WSAEACCES\n") );
161 _tprintf( _T("recvfrom() failed with WSAEINVAL\n") );
164 _tprintf( _T("recvfrom() failed with WSAEINTR\n") );
167 _tprintf( _T("recvfrom() failed with WSAEINPROGRESS\n") );
170 _tprintf( _T("recvfrom() failed with WSAEFAULT\n") );
173 _tprintf( _T("recvfrom() failed with WSAENETRESET\n") );
176 _tprintf( _T("recvfrom() failed with WSAENOBUFS\n") );
179 _tprintf( _T("recvfrom() failed with WSAENOTCONN\n") );
182 _tprintf( _T("recvfrom() failed with WSAENOTSOCK\n") );
185 _tprintf( _T("recvfrom() failed with WSAEOPNOTSUPP\n") );
188 _tprintf( _T("recvfrom() failed with WSAESHUTDOWN\n") );
191 _tprintf( _T("recvfrom() failed with WSAEWOULDBLOCK\n") );
194 _tprintf( _T("recvfrom() failed with WSAEMSGSIZE\n") );
196 case WSAEHOSTUNREACH
:
197 _tprintf( _T("recvfrom() failed with WSAEHOSTUNREACH\n") );
199 case WSAECONNABORTED
:
200 _tprintf( _T("recvfrom() failed with WSAECONNABORTED\n") );
203 _tprintf( _T("recvfrom() failed with WSAECONNRESET\n") );
205 case WSAEADDRNOTAVAIL
:
206 _tprintf( _T("recvfrom() failed with WSAEADDRNOTAVAIL\n") );
208 case WSAEAFNOSUPPORT
:
209 _tprintf( _T("recvfrom() failed with WSAEAFNOSUPPORT\n") );
211 case WSAEDESTADDRREQ
:
212 _tprintf( _T("recvfrom() failed with WSAEDESTADDRREQ\n") );
215 _tprintf( _T("recvfrom() failed with WSAENETUNREACH\n") );
218 _tprintf( _T("recvfrom() failed with WSAETIMEDOUT\n") );
221 _tprintf( _T("recvfrom() failed with unknown error\n") );
227 ResponseID
= ntohs( ((PSHORT
)&pOutBuffer
[0])[0] );
229 if( ResponseID
== RequestID
) bWait
= FALSE
;
232 /* We don't need the sockets anymore. */
235 /* If debug information then display debug information. */
236 if( State
.debug
) PrintDebug( pOutBuffer
, j
);
238 /* Return the real output buffer length. */
239 *pOutBufferLength
= j
;
244 void ReverseIP( PCHAR pIP
, PCHAR pReturn
)
250 j
= strlen( pIP
) - 1;
254 We will turn this into D.C.B.A and stick it in pReturn */
257 for( ; i
> 0; i
-= 1 ) if( '.' == pIP
[i
] ) break;
259 strncpy( &pReturn
[k
], &pIP
[i
+ 1], (j
- i
) );
269 for( ; i
> 0; i
-= 1 ) if( '.' == pIP
[i
] ) break;
271 strncpy( &pReturn
[k
], &pIP
[i
+ 1], (j
- i
) );
281 for( ; i
> 0; i
-= 1 ) if( '.' == pIP
[i
] ) break;
283 strncpy( &pReturn
[k
], &pIP
[i
+ 1], (j
- i
) );
293 for( ; i
> 0; i
-= 1 );
295 strncpy( &pReturn
[k
], &pIP
[i
], (j
- i
) + 1 );
301 BOOL
IsValidIP( PCHAR pInput
)
303 int i
= 0, l
= 0, b
= 0, c
= 1;
305 /* Max length of an IP, e.g. 255.255.255.255, is 15 characters. */
306 l
= strlen( pInput
);
307 if( l
> 15 ) return FALSE
;
309 /* 'b' is the count of the current segment. It gets reset after seeing a
311 for( ; i
< l
; i
+= 1 )
313 if( '.' == pInput
[i
] )
315 if( !b
) return FALSE
;
316 if( b
> 3 ) return FALSE
;
325 if( (pInput
[i
] < '0') || (pInput
[i
] > '9') ) return FALSE
;
329 if( b
> 3 ) return FALSE
;
331 /* 'c' is the number of segments seen. If it's less than 4, then it's not
333 if( c
< 4 ) return FALSE
;
338 int ExtractName( PCHAR pBuffer
, PCHAR pOutput
, USHORT Offset
, UCHAR Limit
)
340 int c
= 0, d
= 0, i
= 0, j
= 0, k
= 0, l
= 0, m
= 0;
344 /* If Limit == 0, then we assume "no" limit. */
346 if( 0 == Limit
) d
= 255;
350 l
= pBuffer
[i
] & 0xFF;
363 for( j
= 0; j
< l
; j
+= 1 )
365 pOutput
[k
] = pBuffer
[i
];
375 if( !pBuffer
[i
] || (d
< 1) ) break;
392 int ExtractIP( PCHAR pBuffer
, PCHAR pOutput
, USHORT Offset
)
394 int c
= 0, l
= 0, i
= 0, v
= 0;
398 v
= (UCHAR
)pBuffer
[i
];
402 sprintf( &pOutput
[c
], "%d.", v
);
403 c
+= strlen( &pOutput
[c
] );
405 v
= (UCHAR
)pBuffer
[i
];
409 sprintf( &pOutput
[c
], "%d.", v
);
410 c
+= strlen( &pOutput
[c
] );
412 v
= (UCHAR
)pBuffer
[i
];
416 sprintf( &pOutput
[c
], "%d.", v
);
417 c
+= strlen( &pOutput
[c
] );
419 v
= (UCHAR
)pBuffer
[i
];
423 sprintf( &pOutput
[c
], "%d", v
);
424 c
+= strlen( &pOutput
[c
] );
431 void PrintD2( PCHAR pBuffer
, DWORD BufferLength
)
434 UCHAR Header1
, Header2
;
435 USHORT NumQuestions
, NumAnswers
, NumAuthority
, NumAdditional
;
440 RequestID
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
443 Header1
= pBuffer
[i
];
446 Header2
= pBuffer
[i
];
449 NumQuestions
= ntohs( ((PSHORT
)&pBuffer
[i
])[0] );
452 NumAnswers
= ntohs( ((PSHORT
)&pBuffer
[i
])[0] );
455 NumAuthority
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
458 NumAdditional
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
461 _tprintf( _T("------------\n") );
462 _tprintf( _T("SendRequest(), len %d\n"), (int)BufferLength
);
463 _tprintf( _T(" HEADER:\n") );
464 _tprintf( _T(" opcode = %s, id = %d, rcode = %s\n"),
465 OpcodeIDtoOpcodeName( (Header1
& 0x78) >> 3 ),
467 RCodeIDtoRCodeName( Header2
& 0x0F ) );
469 _tprintf( _T(" header flags: query") );
470 if( Header1
& 0x01 ) _tprintf( _T(", want recursion") );
471 _tprintf( _T("\n") );
473 _tprintf( _T(" questions = %d, answers = %d,"
474 " authority records = %d, additional = %d\n\n"),
478 (int)NumAdditional
);
482 _tprintf( _T(" QUESTIONS:\n") );
484 for( k
= 0; k
< NumQuestions
; k
+= 1 )
486 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
488 _tprintf( _T(" %s"), pName
);
490 Type
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
493 Class
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
496 _tprintf( _T(", type = %s, class = %s\n"),
497 TypeIDtoTypeName( Type
),
498 ClassIDtoClassName( Class
) );
502 _tprintf( _T("\n------------\n") );
505 void PrintDebug( PCHAR pBuffer
, DWORD BufferLength
)
508 UCHAR Header1
, Header2
;
509 USHORT NumQuestions
, NumAnswers
, NumAuthority
, NumAdditional
;
513 int d
= 0, i
= 0, k
= 0;
515 ResponseID
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
518 Header1
= pBuffer
[i
];
521 Header2
= pBuffer
[i
];
524 NumQuestions
= ntohs( ((PSHORT
)&pBuffer
[i
])[0] );
527 NumAnswers
= ntohs( ((PSHORT
)&pBuffer
[i
])[0] );
530 NumAuthority
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
533 NumAdditional
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
536 _tprintf( _T("------------\n") );
537 _tprintf( _T("Got answer (%d bytes):\n"), (int)BufferLength
);
538 _tprintf( _T(" HEADER:\n") );
539 _tprintf( _T(" opcode = %s, id = %d, rcode = %s\n"),
540 OpcodeIDtoOpcodeName( (Header1
& 0x78) >> 3 ),
542 RCodeIDtoRCodeName( Header2
& 0x0F ) );
544 _tprintf( _T(" header flags: response") );
545 if( Header1
& 0x01 ) _tprintf( _T(", want recursion") );
546 if( Header2
& 0x80 ) _tprintf( _T(", recursion avail.") );
547 _tprintf( _T("\n") );
549 _tprintf( _T(" questions = %d, answers = %d, "
550 "authority records = %d, additional = %d\n\n"),
554 (int)NumAdditional
);
558 _tprintf( _T(" QUESTIONS:\n") );
560 for( k
= 0; k
< NumQuestions
; k
+= 1 )
562 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
564 _tprintf( _T(" %s"), pName
);
566 Type
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
569 Class
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
572 _tprintf( _T(", type = %s, class = %s\n"),
573 TypeIDtoTypeName( Type
),
574 ClassIDtoClassName( Class
) );
580 _tprintf( _T(" ANSWERS:\n") );
582 for( k
= 0; k
< NumAnswers
; k
+= 1 )
584 _tprintf( _T(" -> ") );
586 /* Print out the name. */
587 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
589 _tprintf( _T("%s\n"), pName
);
591 /* Print out the type, class and data length. */
592 Type
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
595 Class
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
598 TTL
= ntohl( ((PULONG
)&pBuffer
[i
])[0] );
601 d
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
604 _tprintf( _T(" type = %s, class = %s, dlen = %d\n"),
605 TypeIDtoTypeName( Type
),
606 ClassIDtoClassName( Class
),
609 /* Print out the answer. */
612 i
+= ExtractIP( pBuffer
, pName
, i
);
614 _tprintf( _T(" internet address = %s\n"), pName
);
618 i
+= ExtractName( pBuffer
, pName
, i
, d
);
620 _tprintf( _T(" name = %s\n"), pName
);
623 _tprintf( _T(" ttl = %d ()\n"), (int)TTL
);
629 _tprintf( _T(" AUTHORITY RECORDS:\n") );
631 for( k
= 0; k
< NumAuthority
; k
+= 1 )
633 /* Print out the zone name. */
634 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
636 _tprintf( _T(" -> %s\n"), pName
);
638 /* Print out the type, class, data length and TTL. */
639 Type
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
642 Class
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
645 TTL
= ntohl( ((PULONG
)&pBuffer
[i
])[0] );
648 d
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
651 _tprintf( _T(" type = %s, class = %s, dlen = %d\n"),
652 TypeIDtoTypeName( Type
),
653 ClassIDtoClassName( Class
),
656 /* TODO: There might be more types? */
657 if( TYPE_NS
== Type
)
659 /* Print out the NS. */
660 i
+= ExtractName( pBuffer
, pName
, i
, d
);
662 _tprintf( _T(" nameserver = %s\n"), pName
);
664 _tprintf( _T(" ttl = %d ()\n"), (int)TTL
);
666 else if( TYPE_SOA
== Type
)
668 _tprintf( _T(" ttl = %d ()\n"), (int)TTL
);
670 /* Print out the primary NS. */
671 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
673 _tprintf( _T(" primary name server = %s\n"), pName
);
675 /* Print out the responsible mailbox. */
676 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
678 _tprintf( _T(" responsible mail addr = %s\n"), pName
);
680 /* Print out the serial, refresh, retry, expire and default TTL. */
681 _tprintf( _T(" serial = ()\n") );
682 _tprintf( _T(" refresh = ()\n") );
683 _tprintf( _T(" retry = ()\n") );
684 _tprintf( _T(" expire = ()\n") );
685 _tprintf( _T(" default TTL = ()\n") );
693 _tprintf( _T(" ADDITIONAL:\n") );
695 for( k
= 0; k
< NumAdditional
; k
+= 1 )
697 /* Print the name. */
698 i
+= ExtractName( pBuffer
, pName
, i
, 0 );
700 _tprintf( _T(" -> %s\n"), pName
);
702 /* Print out the type, class, data length and TTL. */
703 Type
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
706 Class
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
709 TTL
= ntohl( ((PULONG
)&pBuffer
[i
])[0] );
712 d
= ntohs( ((PUSHORT
)&pBuffer
[i
])[0] );
715 _tprintf( _T(" type = %s, class = %s, dlen = %d\n"),
716 TypeIDtoTypeName( Type
),
717 ClassIDtoClassName( Class
),
720 /* TODO: There might be more types? */
723 /* Print out the NS. */
724 i
+= ExtractIP( pBuffer
, pName
, i
);
726 _tprintf( _T(" internet address = %s\n"), pName
);
728 _tprintf( _T(" ttl = %d ()\n"), (int)TTL
);
733 _tprintf( _T("\n------------\n") );
736 PCHAR
OpcodeIDtoOpcodeName( UCHAR Opcode
)
738 switch( Opcode
& 0x0F )
750 return OpcodeReserved
;
754 PCHAR
RCodeIDtoRCodeName( UCHAR RCode
)
756 switch( RCode
& 0x0F )
768 return RCodeNXDOMAIN
;
777 return RCodeReserved
;
781 PCHAR
TypeIDtoTypeName( USHORT TypeID
)
814 USHORT
TypeNametoTypeID( PCHAR TypeName
)
816 if( !strncmp( TypeName
, TypeA
, strlen( TypeA
) ) ) return TYPE_A
;
817 if( !strncmp( TypeName
, TypeNS
, strlen( TypeNS
) ) ) return TYPE_NS
;
818 if( !strncmp( TypeName
, TypeCNAME
, strlen( TypeCNAME
) ) ) return TYPE_CNAME
;
819 if( !strncmp( TypeName
, TypeSOA
, strlen( TypeSOA
) ) ) return TYPE_SOA
;
820 if( !strncmp( TypeName
, TypeSRV
, strlen( TypeSRV
) ) ) return TYPE_WKS
;
821 if( !strncmp( TypeName
, TypePTR
, strlen( TypePTR
) ) ) return TYPE_PTR
;
822 if( !strncmp( TypeName
, TypeMX
, strlen( TypeMX
) ) ) return TYPE_MX
;
823 if( !strncmp( TypeName
, TypeAny
, strlen( TypeAny
) ) ) return TYPE_ANY
;
828 PCHAR
ClassIDtoClassName( USHORT ClassID
)
843 USHORT
ClassNametoClassID( PCHAR ClassName
)
845 if( !strncmp( ClassName
, ClassIN
, strlen( ClassIN
) ) ) return CLASS_IN
;
846 if( !strncmp( ClassName
, ClassAny
, strlen( ClassAny
) ) ) return CLASS_ANY
;