diff --git a/reactos/base/applications/network/network.rbuild b/reactos/base/applications/network/network.rbuild index bdf9d883d7c..61109ec8bd7 100644 --- a/reactos/base/applications/network/network.rbuild +++ b/reactos/base/applications/network/network.rbuild @@ -22,6 +22,9 @@ + + + diff --git a/reactos/base/applications/network/nslookup/nslookup.c b/reactos/base/applications/network/nslookup/nslookup.c new file mode 100644 index 00000000000..993ab04a650 --- /dev/null +++ b/reactos/base/applications/network/nslookup/nslookup.c @@ -0,0 +1,858 @@ +/* + * PROJECT: ReactOS nslookup utility + * LICENSE: GPL - See COPYING in the top level directory + * FILE: applications/network/nslookup/nslookup.c + * PURPOSE: Perform DNS lookups + * COPYRIGHT: Copyright 2009 Lucas Suggs + */ + +#include +#include +#include +#include +#include +#include +#include +#include "nslookup.h" + +STATE State; +HANDLE ProcessHeap; +ULONG RequestID; + +void PrintState() +{ + _tprintf( _T("Default Server: (null)\n\n") ); + _tprintf( _T("Set options:\n") ); + + _tprintf( _T(" ") ); + if( !State.debug ) _tprintf( _T("no") ); + _tprintf( _T("debug\n") ); + + _tprintf( _T(" ") ); + if( !State.defname ) _tprintf( _T("no") ); + _tprintf( _T("defname\n") ); + + _tprintf( _T(" ") ); + if( !State.search ) _tprintf( _T("no") ); + _tprintf( _T("search\n") ); + + _tprintf( _T(" ") ); + if( !State.recurse ) _tprintf( _T("no") ); + _tprintf( _T("recurse\n") ); + + _tprintf( _T(" ") ); + if( !State.d2 ) _tprintf( _T("no") ); + _tprintf( _T("d2\n") ); + + _tprintf( _T(" ") ); + if( !State.vc ) _tprintf( _T("no") ); + _tprintf( _T("vc\n") ); + + _tprintf( _T(" ") ); + if( !State.ignoretc ) _tprintf( _T("no") ); + _tprintf( _T("ignoretc\n") ); + + _tprintf( _T(" port=%d\n"), State.port ); + _tprintf( _T(" type=%s\n"), State.type ); + _tprintf( _T(" class=%s\n"), State.Class ); + _tprintf( _T(" timeout=%d\n"), (int)State.timeout ); + _tprintf( _T(" retry=%d\n"), (int)State.retry ); + _tprintf( _T(" root=%s\n"), State.root ); + _tprintf( _T(" domain=%s\n"), State.domain ); + + _tprintf( _T(" ") ); + if( !State.MSxfr ) _tprintf( _T("no") ); + _tprintf( _T("MSxfr\n") ); + + _tprintf( _T(" IXFRversion=%d\n"), (int)State.ixfrver ); + + _tprintf( _T(" srchlist=%s\n\n"), State.srchlist[0] ); +} + +void PrintUsage() +{ + _tprintf( _T("Usage:\n" + " nslookup [-opt ...] # interactive mode using" + " default server\n nslookup [-opt ...] - server #" + " interactive mode using 'server'\n nslookup [-opt ...]" + " host # just look up 'host' using default server\n" + " nslookup [-opt ...] host server # just look up 'host'" + " using 'server'\n") ); +} + +BOOL PerformInternalLookup( PCHAR pAddr, PCHAR pResult ) +{ + /* Needed to issue DNS packets and parse them. */ + PCHAR Buffer = NULL, RecBuffer = NULL; + CHAR pResolve[256]; + ULONG BufferLength = 0, RecBufferLength = 512; + int i = 0, j = 0, k = 0, d = 0; + BOOL bOk = FALSE; + + /* Makes things easier when parsing the response packet. */ + UCHAR Header1, Header2; + USHORT NumQuestions; + USHORT NumAnswers; + USHORT NumAuthority; + USHORT NumAdditional; + USHORT Type; + + if( (strlen( pAddr ) + 1) > 255 ) return FALSE; + + Type = TYPE_A; + if( IsValidIP( pAddr ) ) Type = TYPE_PTR; + + /* If it's a PTR lookup then append the ARPA sig to the end. */ + if( Type == TYPE_PTR ) + { + ReverseIP( pAddr, pResolve ); + strcat( pResolve, ARPA_SIG ); + } + else + { + strcpy( pResolve, pAddr ); + } + + /* Base header length + length of QNAME + length of QTYPE and QCLASS */ + BufferLength = 12 + (strlen( pResolve ) + 2) + 4; + + /* Allocate memory for the buffer. */ + Buffer = HeapAlloc( ProcessHeap, 0, BufferLength ); + if( !Buffer ) + { + _tprintf( _T("ERROR: Out of memory\n") ); + goto cleanup; + } + + /* Allocate the receiving buffer. */ + RecBuffer = HeapAlloc( ProcessHeap, 0, RecBufferLength ); + if( !RecBuffer ) + { + _tprintf( _T("ERROR: Out of memory\n") ); + goto cleanup; + } + + /* Insert the ID field. */ + ((PSHORT)&Buffer[i])[0] = htons( RequestID ); + i += 2; + + /* Bits 0-7 of the second 16 are all 0, except for when recursion is + desired. */ + Buffer[i] = 0x00; + if( State.recurse) Buffer[i] |= 0x01; + i += 1; + + /* Bits 8-15 of the second 16 are 0 for a query. */ + Buffer[i] = 0x00; + i += 1; + + /* Only 1 question. */ + ((PSHORT)&Buffer[i])[0] = htons( 1 ); + i += 2; + + /* We aren't sending a response, so 0 out the rest of the header. */ + Buffer[i] = 0x00; + Buffer[i + 1] = 0x00; + Buffer[i + 2] = 0x00; + Buffer[i + 3] = 0x00; + Buffer[i + 4] = 0x00; + Buffer[i + 5] = 0x00; + i += 6; + + /* Walk through the query address. Split each section delimited by '.'. + Format of the QNAME section is length|data, etc. Last one is null */ + j = i; + i += 1; + + for( k = 0; k < strlen( pResolve ); k += 1 ) + { + if( pResolve[k] != '.' ) + { + Buffer[i] = pResolve[k]; + i += 1; + } + else + { + Buffer[j] = (i - j) - 1; + j = i; + i += 1; + } + } + + Buffer[j] = (i - j) - 1; + Buffer[i] = 0x00; + i += 1; + + /* QTYPE */ + ((PSHORT)&Buffer[i])[0] = htons( Type ); + i += 2; + + /* QCLASS */ + ((PSHORT)&Buffer[i])[0] = htons( CLASS_IN ); + + /* Ship the request off to the DNS server. */ + bOk = SendRequest( Buffer, + BufferLength, + RecBuffer, + &RecBufferLength ); + if( !bOk ) goto cleanup; + + /* Start parsing the received packet. */ + Header1 = RecBuffer[2]; + Header2 = RecBuffer[3]; + NumQuestions = ntohs( ((PSHORT)&RecBuffer[4])[0] ); + NumAnswers = ntohs( ((PSHORT)&RecBuffer[6])[0] ); + NumAuthority = ntohs( ((PUSHORT)&RecBuffer[8])[0] ); + NumAdditional = ntohs( ((PUSHORT)&RecBuffer[10])[0] ); + + k = 12; + + /* We don't care about the questions section, blow through it. */ + if( NumQuestions ) + { + for( i = 0; i < NumQuestions; i += 1 ) + { + /* Quick way to skip the domain name section. */ + k += ExtractName( RecBuffer, pResult, k, 0 ); + k += 4; + } + } + + /* Skip the answer name. */ + k += ExtractName( RecBuffer, pResult, k, 0 ); + + Type = ntohs( ((PUSHORT)&RecBuffer[k])[0] ); + k += 8; + + d = ntohs( ((PUSHORT)&RecBuffer[k])[0] ); + k += 2; + + if( TYPE_PTR == Type ) + { + k += ExtractName( RecBuffer, pResult, k, d ); + } + else if( TYPE_A == Type ) + { + k += ExtractIP( RecBuffer, pResult, k ); + } + +cleanup: + /* Free memory. */ + if( Buffer ) HeapFree( ProcessHeap, 0, Buffer ); + if( RecBuffer ) HeapFree( ProcessHeap, 0, RecBuffer ); + + RequestID += 1; + + return bOk; +} + +void PerformLookup( PCHAR pAddr ) +{ + /* Needed to issue DNS packets and parse them. */ + PCHAR Buffer = NULL, RecBuffer = NULL; + CHAR pResolve[256]; + CHAR pResult[256]; + ULONG BufferLength = 0, RecBufferLength = 512; + int i = 0, j = 0, k = 0, d = 0; + BOOL bOk = FALSE; + + /* Makes things easier when parsing the response packet. */ + UCHAR Header1, Header2; + USHORT NumQuestions; + USHORT NumAnswers; + USHORT NumAuthority; + USHORT NumAdditional; + USHORT Type; + + if( (strlen( pAddr ) + 1) > 255 ) return; + + _tprintf( _T("Server: %s\n"), State.DefaultServer ); + _tprintf( _T("Address: %s\n\n"), State.DefaultServerAddress ); + + if( !strcmp( TypeA, State.type ) + || !strcmp( TypeAAAA, State.type ) + || !strcmp( TypeBoth, State.type ) ) + { + Type = TYPE_A; + if( IsValidIP( pAddr ) ) Type = TYPE_PTR; + } + else + Type = TypeNametoTypeID( State.type ); + + /* If it's a PTR lookup then append the ARPA sig to the end. */ + if( (Type == TYPE_PTR) && IsValidIP( pAddr ) ) + { + ReverseIP( pAddr, pResolve ); + strcat( pResolve, ARPA_SIG ); + } + else + { + strcpy( pResolve, pAddr ); + } + + /* Base header length + length of QNAME + length of QTYPE and QCLASS */ + BufferLength = 12 + (strlen( pResolve ) + 2) + 4; + + /* Allocate memory for the buffer. */ + Buffer = HeapAlloc( ProcessHeap, 0, BufferLength ); + if( !Buffer ) + { + _tprintf( _T("ERROR: Out of memory\n") ); + goto cleanup; + } + + /* Allocate memory for the return buffer. */ + RecBuffer = HeapAlloc( ProcessHeap, 0, RecBufferLength ); + if( !RecBuffer ) + { + _tprintf( _T("ERROR: Out of memory\n") ); + goto cleanup; + } + + /* Insert the ID field. */ + ((PSHORT)&Buffer[i])[0] = htons( RequestID ); + i += 2; + + /* Bits 0-7 of the second 16 are all 0, except for when recursion is + desired. */ + Buffer[i] = 0x00; + if( State.recurse) Buffer[i] |= 0x01; + i += 1; + + /* Bits 8-15 of the second 16 are 0 for a query. */ + Buffer[i] = 0x00; + i += 1; + + /* Only 1 question. */ + ((PSHORT)&Buffer[i])[0] = htons( 1 ); + i += 2; + + /* We aren't sending a response, so 0 out the rest of the header. */ + Buffer[i] = 0x00; + Buffer[i + 1] = 0x00; + Buffer[i + 2] = 0x00; + Buffer[i + 3] = 0x00; + Buffer[i + 4] = 0x00; + Buffer[i + 5] = 0x00; + i += 6; + + /* Walk through the query address. Split each section delimited by '.'. + Format of the QNAME section is length|data, etc. Last one is null */ + j = i; + i += 1; + + for( k = 0; k < strlen( pResolve ); k += 1 ) + { + if( pResolve[k] != '.' ) + { + Buffer[i] = pResolve[k]; + i += 1; + } + else + { + Buffer[j] = (i - j) - 1; + j = i; + i += 1; + } + } + + Buffer[j] = (i - j) - 1; + Buffer[i] = 0x00; + i += 1; + + /* QTYPE */ + ((PSHORT)&Buffer[i])[0] = htons( Type ); + i += 2; + + /* QCLASS */ + ((PSHORT)&Buffer[i])[0] = htons( ClassNametoClassID( State.Class ) ); + + /* Ship off the request to the DNS server. */ + bOk = SendRequest( Buffer, + BufferLength, + RecBuffer, + &RecBufferLength ); + if( !bOk ) goto cleanup; + + /* Start parsing the received packet. */ + Header1 = RecBuffer[2]; + Header2 = RecBuffer[3]; + NumQuestions = ntohs( ((PSHORT)&RecBuffer[4])[0] ); + NumAnswers = ntohs( ((PSHORT)&RecBuffer[6])[0] ); + NumAuthority = ntohs( ((PUSHORT)&RecBuffer[8])[0] ); + NumAdditional = ntohs( ((PUSHORT)&RecBuffer[10])[0] ); + Type = 0; + + /* Check the RCODE for failure. */ + d = Header2 & 0x0F; + if( d != RCODE_NOERROR ) + { + switch( d ) + { + case RCODE_NXDOMAIN: + _tprintf( _T("*** %s can't find %s: Non-existant domain\n"), State.DefaultServer, pAddr ); + break; + + case RCODE_REFUSED: + _tprintf( _T("*** %s can't find %s: Query refused\n"), State.DefaultServer, pAddr ); + break; + + default: + _tprintf( _T("*** %s can't find %s: Unknown RCODE\n"), State.DefaultServer, pAddr ); + } + + goto cleanup; + } + + k = 12; + + if( NumQuestions ) + { + /* Blow through the questions section since we don't care about it. */ + for( i = 0; i < NumQuestions; i += 1 ) + { + k += ExtractName( RecBuffer, pResult, k, 0 ); + k += 4; + } + } + + if( NumAnswers ) + { + /* Skip the name. */ + k += ExtractName( RecBuffer, pResult, k, 0 ); + + Type = ntohs( ((PUSHORT)&RecBuffer[k])[0] ); + k += 8; + + d = ntohs( ((PUSHORT)&RecBuffer[k])[0] ); + k += 2; + + if( TYPE_PTR == Type ) + { + k += ExtractName( RecBuffer, pResult, k, d ); + } + else if( TYPE_A == Type ) + { + k += ExtractIP( RecBuffer, pResult, k ); + } + } + + /* FIXME: This'll need to support more than PTR and A at some point. */ + if( !strcmp( State.type, TypePTR ) ) + { + if( TYPE_PTR == Type ) + { + _tprintf( _T("%s name = %s\n"), pResolve, pResult ); + } + else + { + } + } + else if( !strcmp( State.type, TypeA ) + || !strcmp( State.type, TypeAAAA ) + || !strcmp( State.type, TypeBoth ) ) + { + if( (TYPE_A == Type) /*|| (TYPE_AAAA == Type)*/ ) + { + if( 0 == NumAuthority ) + _tprintf( _T("Non-authoritative answer:\n") ); + + _tprintf( _T("Name: %s\n"), pAddr ); + _tprintf( _T("Address: %s\n\n"), pResult ); + } + else + { + _tprintf( _T("Name: %s\n"), pResult ); + _tprintf( _T("Address: %s\n\n"), pAddr ); + } + } + +cleanup: + /* Free memory. */ + if( Buffer ) HeapFree( ProcessHeap, 0, Buffer ); + if( RecBuffer ) HeapFree( ProcessHeap, 0, RecBuffer ); + + RequestID += 1; +} + +BOOL ParseCommandLine( int argc, char* argv[] ) +{ + int i; + BOOL NoMoreOptions = FALSE; + BOOL Interactive = FALSE; + CHAR AddrToResolve[256]; + CHAR Server[256]; + + RtlZeroMemory( AddrToResolve, 256 ); + RtlZeroMemory( Server, 256 ); + + if( 2 == argc ) + { + /* In the Windows nslookup, usage is only displayed if /? is the only + option specified on the command line. */ + if( !strncmp( "/?", argv[1], 2 ) ) + { + PrintUsage(); + return 0; + } + } + + if( argc > 1 ) + { + for( i = 1; i < argc; i += 1 ) + { + if( NoMoreOptions ) + { + strncpy( Server, argv[i], 255 ); + + /* Determine which one to resolve. This is based on whether the + DNS server provided was an IP or an FQDN. */ + if( IsValidIP( Server ) ) + { + strncpy( State.DefaultServerAddress, Server, 16 ); + + PerformInternalLookup( State.DefaultServerAddress, + State.DefaultServer ); + } + else + { + strncpy( State.DefaultServer, Server, 255 ); + + PerformInternalLookup( State.DefaultServer, + State.DefaultServerAddress ); + } + + if( Interactive ) return 1; + + PerformLookup( AddrToResolve ); + + return 0; + } + else + { + if( !strncmp( "-all", argv[i], 4 ) ) + { + PrintState(); + } + else if( !strncmp( "-type=", argv[i], 6 ) ) + { + if( !strncmp( TypeA, &argv[i][6], strlen( TypeA ) ) ) + { + State.type = TypeA; + } + else if( !strncmp( TypeAAAA, &argv[i][6], strlen( TypeAAAA ) ) ) + { + State.type = TypeAAAA; + } + else if( !strncmp( TypeBoth, &argv[i][6], strlen( TypeBoth ) ) ) + { + State.type = TypeBoth; + } + else if( !strncmp( TypeAny, &argv[i][6], strlen( TypeAny ) ) ) + { + State.type = TypeAny; + } + else if( !strncmp( TypeCNAME, &argv[i][6], strlen( TypeCNAME ) ) ) + { + State.type = TypeCNAME; + } + else if( !strncmp( TypeMX, &argv[i][6], strlen( TypeMX ) ) ) + { + State.type = TypeMX; + } + else if( !strncmp( TypeNS, &argv[i][6], strlen( TypeNS ) ) ) + { + State.type = TypeNS; + } + else if( !strncmp( TypePTR, &argv[i][6], strlen( TypePTR ) ) ) + { + State.type = TypePTR; + } + else if( !strncmp( TypeSOA, &argv[i][6], strlen( TypeSOA ) ) ) + { + State.type = TypeSOA; + } + else if( !strncmp( TypeSRV, &argv[i][6], strlen( TypeSRV ) ) ) + { + State.type = TypeSRV; + } + else + { + _tprintf( _T("unknown query type: %s"), &argv[i][6] ); + } + } + else if( !strncmp( "-domain=", argv[i], 8 ) ) + { + strcpy( State.domain, &argv[i][8] ); + } + else if( !strncmp( "-srchlist=", argv[i], 10 ) ) + { + } + else if( !strncmp( "-root=", argv[i], 6 ) ) + { + strcpy( State.root, &argv[i][6] ); + } + else if( !strncmp( "-retry=", argv[i], 7 ) ) + { + } + else if( !strncmp( "-timeout=", argv[i], 9 ) ) + { + } + else if( !strncmp( "-querytype=", argv[i], 11 ) ) + { + if( !strncmp( TypeA, &argv[i][11], strlen( TypeA ) ) ) + { + State.type = TypeA; + } + else if( !strncmp( TypeAAAA, &argv[i][11], strlen( TypeAAAA ) ) ) + { + State.type = TypeAAAA; + } + else if( !strncmp( TypeBoth, &argv[i][11], strlen( TypeBoth ) ) ) + { + State.type = TypeBoth; + } + else if( !strncmp( TypeAny, &argv[i][11], strlen( TypeAny ) ) ) + { + State.type = TypeAny; + } + else if( !strncmp( TypeCNAME, &argv[i][11], strlen( TypeCNAME ) ) ) + { + State.type = TypeCNAME; + } + else if( !strncmp( TypeMX, &argv[i][11], strlen( TypeMX ) ) ) + { + State.type = TypeMX; + } + else if( !strncmp( TypeNS, &argv[i][11], strlen( TypeNS ) ) ) + { + State.type = TypeNS; + } + else if( !strncmp( TypePTR, &argv[i][11], strlen( TypePTR ) ) ) + { + State.type = TypePTR; + } + else if( !strncmp( TypeSOA, &argv[i][11], strlen( TypeSOA ) ) ) + { + State.type = TypeSOA; + } + else if( !strncmp( TypeSRV, &argv[i][11], strlen( TypeSRV ) ) ) + { + State.type = TypeSRV; + } + else + { + _tprintf( _T("unknown query type: %s"), &argv[i][6] ); + } + } + else if( !strncmp( "-class=", argv[i], 7 ) ) + { + if( !strncmp( ClassIN, &argv[i][7], strlen( ClassIN ) ) ) + { + State.Class = ClassIN; + } + else if( !strncmp( ClassAny, &argv[i][7], strlen( ClassAny ) ) ) + { + State.Class = ClassAny; + } + else + { + _tprintf( _T("unknown query class: %s"), &argv[i][7] ); + } + } + else if( !strncmp( "-ixfrver=", argv[i], 9 ) ) + { + } + else if( !strncmp( "-debug", argv[i], 6 ) ) + { + State.debug = TRUE; + } + else if( !strncmp( "-nodebug", argv[i], 8 ) ) + { + State.debug = FALSE; + State.d2 = FALSE; + } + else if( !strncmp( "-d2", argv[i], 3 ) ) + { + State.d2 = TRUE; + State.debug = TRUE; + } + else if( !strncmp( "-nod2", argv[i], 5 ) ) + { + if( State.debug ) _tprintf( _T("d2 mode disabled; still in debug mode\n") ); + + State.d2 = FALSE; + } + else if( !strncmp( "-defname", argv[i], 8 ) ) + { + State.defname = TRUE; + } + else if( !strncmp( "-noddefname", argv[i], 10 ) ) + { + State.defname = FALSE; + } + else if( !strncmp( "-recurse", argv[i], 8 ) ) + { + State.recurse = TRUE; + } + else if( !strncmp( "-norecurse", argv[i], 10 ) ) + { + State.recurse = FALSE; + } + else if( !strncmp( "-search", argv[i], 7 ) ) + { + State.search = TRUE; + } + else if( !strncmp( "-nosearch", argv[i], 9 ) ) + { + State.search = FALSE; + } + else if( !strncmp( "-vc", argv[i], 3 ) ) + { + State.vc = TRUE; + } + else if( !strncmp( "-novc", argv[i], 5 ) ) + { + State.vc = FALSE; + } + else if( !strncmp( "-msxfr", argv[i], 6 ) ) + { + State.MSxfr = TRUE; + } + else if( !strncmp( "-nomsxfr", argv[i], 8 ) ) + { + State.MSxfr = FALSE; + } + else if( !strncmp( "-", argv[i], 1 ) && (strlen( argv[i] ) == 1) ) + { + /* Since we received just the plain - switch, we are going + to be entering interactive mode. We also will not be + parsing any more options. */ + NoMoreOptions = TRUE; + Interactive = TRUE; + } + else + { + /* Grab the address to resolve. No more options accepted + past this point. */ + strncpy( AddrToResolve, argv[i], 255 ); + NoMoreOptions = TRUE; + } + } + } + + if( NoMoreOptions && !Interactive ) + { + /* Get the FQDN of the DNS server. */ + PerformInternalLookup( State.DefaultServerAddress, + State.DefaultServer ); + + PerformLookup( AddrToResolve ); + + return 0; + } + } + + /* Get the FQDN of the DNS server. */ + PerformInternalLookup( State.DefaultServerAddress, + State.DefaultServer ); + + return 1; +} + +void InteractiveMode() +{ + _tprintf( _T("Default Server: %s\n"), State.DefaultServer ); + _tprintf( _T("Address: %s\n\n"), State.DefaultServerAddress ); + + /* TODO: Implement interactive mode. */ + + _tprintf( _T("ERROR: Feature not implemented.\n") ); +} + +int main( int argc, char* argv[] ) +{ + int i; + ULONG Status; + PFIXED_INFO pNetInfo = NULL; + ULONG NetBufLen = 0; + WSADATA wsaData; + + ProcessHeap = GetProcessHeap(); + RequestID = 1; + + /* Set up the initial state. */ + State.debug = FALSE; + State.defname = TRUE; + State.search = TRUE; + State.recurse = TRUE; + State.d2 = FALSE; + State.vc = FALSE; + State.ignoretc = FALSE; + State.port = 53; + State.type = TypeBoth; + State.Class = ClassIN; + State.timeout = 2; + State.retry = 1; + State.MSxfr = TRUE; + State.ixfrver = 1; + + RtlZeroMemory( State.root, 256 ); + RtlZeroMemory( State.domain, 256 ); + for( i = 0; i < 6; i += 1 ) RtlZeroMemory( State.srchlist[i], 256 ); + RtlZeroMemory( State.DefaultServer, 256 ); + RtlZeroMemory( State.DefaultServerAddress, 16 ); + + strncpy( State.root, DEFAULT_ROOT, strlen( DEFAULT_ROOT ) ); + + /* We don't know how long of a buffer it will want to return. So we'll + pass an empty one now and let it fail only once, instead of guessing. */ + Status = GetNetworkParams( pNetInfo, &NetBufLen ); + if( Status == ERROR_BUFFER_OVERFLOW ) + { + pNetInfo = (PFIXED_INFO)HeapAlloc( ProcessHeap, 0, NetBufLen ); + if( pNetInfo == NULL ) + { + _tprintf( _T("ERROR: Out of memory\n") ); + + return -1; + } + + /* For real this time. */ + Status = GetNetworkParams( pNetInfo, &NetBufLen ); + if( Status != NO_ERROR ) + { + _tprintf( _T("Error in GetNetworkParams call\n") ); + + HeapFree( ProcessHeap, 0, pNetInfo ); + + return -2; + } + } + + strncpy( State.domain, pNetInfo->DomainName, 255 ); + strncpy( State.srchlist[0], pNetInfo->DomainName, 255 ); + strncpy( State.DefaultServerAddress, + pNetInfo->DnsServerList.IpAddress.String, + 15 ); + + HeapFree( ProcessHeap, 0, pNetInfo ); + + WSAStartup( MAKEWORD(2,2), &wsaData ); + + switch( ParseCommandLine( argc, argv ) ) + { + case 0: + /* This means that it was a /? parameter. */ + break; + + default: + /* Anything else means we enter interactive mode. The only exception + to this is when the host to resolve was provided on the command + line. */ + InteractiveMode(); + } + + WSACleanup(); + return 0; +} diff --git a/reactos/base/applications/network/nslookup/nslookup.h b/reactos/base/applications/network/nslookup/nslookup.h new file mode 100644 index 00000000000..51ff023001b --- /dev/null +++ b/reactos/base/applications/network/nslookup/nslookup.h @@ -0,0 +1,104 @@ +#define TypeA "A" +#define TypeAAAA "AAAA" +#define TypeBoth "A+AAAA" +#define TypeAny "ANY" +#define TypeCNAME "CNAME" +#define TypeMX "MX" +#define TypeNS "NS" +#define TypePTR "PTR" +#define TypeSOA "SOA" +#define TypeSRV "SRV" + +#define TYPE_A 0x01 +#define TYPE_NS 0x02 +#define TYPE_CNAME 0x05 +#define TYPE_SOA 0x06 +#define TYPE_WKS 0x0B +#define TYPE_PTR 0x0C +#define TYPE_MX 0x0F +#define TYPE_ANY 0xFF + +#define ClassIN "IN" +#define ClassAny "ANY" + +#define CLASS_IN 0x01 +#define CLASS_ANY 0xFF + +#define OPCODE_QUERY 0x00 +#define OPCODE_IQUERY 0x01 +#define OPCODE_STATUS 0x02 + +#define OpcodeQuery "QUERY" +#define OpcodeIQuery "IQUERY" +#define OpcodeStatus "STATUS" +#define OpcodeReserved "RESERVED" + +#define RCODE_NOERROR 0x00 +#define RCODE_FORMERR 0x01 +#define RCODE_FAILURE 0x02 +#define RCODE_NXDOMAIN 0x03 +#define RCODE_NOTIMP 0x04 +#define RCODE_REFUSED 0x05 + +#define RCodeNOERROR "NOERROR" +#define RCodeFORMERR "FORMERR" +#define RCodeFAILURE "FAILURE" +#define RCodeNXDOMAIN "NXDOMAIN" +#define RCodeNOTIMP "NOTIMP" +#define RCodeREFUSED "REFUSED" +#define RCodeReserved "RESERVED" + +#define DEFAULT_ROOT "A.ROOT-SERVERS.NET." +#define ARPA_SIG ".in-addr.arpa" + +typedef struct _STATE +{ + BOOL debug; + BOOL defname; + BOOL d2; + BOOL recurse; + BOOL search; + BOOL vc; + BOOL ignoretc; + BOOL MSxfr; + CHAR domain[256]; + CHAR srchlist[6][256]; + CHAR root[256]; + DWORD retry; + DWORD timeout; + DWORD ixfrver; + PCHAR type; + PCHAR Class; + USHORT port; + CHAR DefaultServer[256]; + CHAR DefaultServerAddress[16]; +} STATE, *PSTATE; + +/* nslookup.c */ + +extern STATE State; +extern HANDLE ProcessHeap; + +/* utility.c */ + +BOOL SendRequest( PCHAR pInBuffer, + ULONG InBufferLength, + PCHAR pOutBuffer, + PULONG pOutBufferLength ); + +int ExtractName( PCHAR pBuffer, + PCHAR pOutput, + USHORT Offset, + UCHAR Limit ); + +void ReverseIP( PCHAR pIP, PCHAR pReturn ); +BOOL IsValidIP( PCHAR pInput ); +int ExtractIP( PCHAR pBuffer, PCHAR pOutput, USHORT Offset ); +void PrintD2( PCHAR pBuffer, DWORD BufferLength ); +void PrintDebug( PCHAR pBuffer, DWORD BufferLength ); +PCHAR OpcodeIDtoOpcodeName( UCHAR Opcode ); +PCHAR RCodeIDtoRCodeName( UCHAR RCode ); +PCHAR TypeIDtoTypeName( USHORT TypeID ); +USHORT TypeNametoTypeID( PCHAR TypeName ); +PCHAR ClassIDtoClassName( USHORT ClassID ); +USHORT ClassNametoClassID( PCHAR ClassName ); diff --git a/reactos/base/applications/network/nslookup/nslookup.rbuild b/reactos/base/applications/network/nslookup/nslookup.rbuild new file mode 100644 index 00000000000..b4d02f9f563 --- /dev/null +++ b/reactos/base/applications/network/nslookup/nslookup.rbuild @@ -0,0 +1,13 @@ + + + + . + kernel32 + user32 + ws2_32 + snmpapi + iphlpapi + nslookup.c + utility.c + nslookup.rc + diff --git a/reactos/base/applications/network/nslookup/nslookup.rc b/reactos/base/applications/network/nslookup/nslookup.rc new file mode 100644 index 00000000000..0bc0c0f76e3 --- /dev/null +++ b/reactos/base/applications/network/nslookup/nslookup.rc @@ -0,0 +1,5 @@ +#define REACTOS_STR_FILE_DESCRIPTION "ReactOS TCP/IPv4 Win32 nslookup\0" +#define REACTOS_STR_INTERNAL_NAME "nslookup\0" +#define REACTOS_STR_ORIGINAL_FILENAME "nslookup.exe\0" +#define REACTOS_STR_ORIGINAL_COPYRIGHT "Lucas Suggs (lucas.suggs@gmail.com)\0" +#include diff --git a/reactos/base/applications/network/nslookup/utility.c b/reactos/base/applications/network/nslookup/utility.c new file mode 100644 index 00000000000..50e8cc12d29 --- /dev/null +++ b/reactos/base/applications/network/nslookup/utility.c @@ -0,0 +1,852 @@ +/* + * PROJECT: ReactOS nslookup utility + * LICENSE: GPL - See COPYING in the top level directory + * FILE: applications/network/nslookup/utility.c + * PURPOSE: Support functions for nslookup.c + * COPYRIGHT: Copyright 2009 Lucas Suggs + */ + +#include +#include +#include +#include "nslookup.h" + +BOOL SendRequest( PCHAR pInBuffer, + ULONG InBufferLength, + PCHAR pOutBuffer, + PULONG pOutBufferLength ) +{ + int j; + USHORT RequestID, ResponseID; + BOOL bWait; + SOCKET s; + SOCKADDR_IN RecAddr, RecAddr2, SendAddr; + int SendAddrLen = sizeof(SendAddr); + + RtlZeroMemory( &RecAddr, sizeof(SOCKADDR_IN) ); + RtlZeroMemory( &RecAddr2, sizeof(SOCKADDR_IN) ); + RtlZeroMemory( &SendAddr, sizeof(SOCKADDR_IN) ); + + /* Pull the request ID from the buffer. */ + RequestID = ntohs( ((PSHORT)&pInBuffer[0])[0] ); + + /* If D2 flags is enabled, then display D2 information. */ + if( State.d2 ) PrintD2( pInBuffer, InBufferLength ); + + /* Create the sockets for both send and receive. */ + s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); + + /* Set up the structure to tell it where we are going. */ + RecAddr.sin_family = AF_INET; + RecAddr.sin_port = htons( State.port ); + RecAddr.sin_addr.s_addr = inet_addr( State.DefaultServerAddress ); + + /* Set up the structure to tell it what port to listen on. */ + RecAddr2.sin_family = AF_INET; + RecAddr2.sin_port = htons( State.port ); + RecAddr2.sin_addr.s_addr = htonl( INADDR_ANY ); + + /* Bind the receive socket. */ + bind( s, (SOCKADDR*)&RecAddr2, sizeof(RecAddr2) ); + + /* Send the datagram to the DNS server. */ + j = sendto( s, + pInBuffer, + InBufferLength, + 0, + (SOCKADDR*)&RecAddr, + sizeof(RecAddr) ); + if( j == SOCKET_ERROR ) + { + switch( WSAGetLastError() ) + { + case WSANOTINITIALISED: + _tprintf( _T("sendto() failed with WSANOTINITIALIZED\n") ); + break; + case WSAENETDOWN: + _tprintf( _T("sendto() failed with WSAENETDOWN\n") ); + break; + case WSAEACCES: + _tprintf( _T("sendto() failed with WSAEACCES\n") ); + break; + case WSAEINVAL: + _tprintf( _T("sendto() failed with WSAEINVAL\n") ); + break; + case WSAEINTR: + _tprintf( _T("sendto() failed with WSAEINTR\n") ); + break; + case WSAEINPROGRESS: + _tprintf( _T("sendto() failed with WSAEINPROGRESS\n") ); + break; + case WSAEFAULT: + _tprintf( _T("sendto() failed with WSAEFAULT\n") ); + break; + case WSAENETRESET: + _tprintf( _T("sendto() failed with WSAENETRESET\n") ); + break; + case WSAENOBUFS: + _tprintf( _T("sendto() failed with WSAENOBUFS\n") ); + break; + case WSAENOTCONN: + _tprintf( _T("sendto() failed with WSAENOTCONN\n") ); + break; + case WSAENOTSOCK: + _tprintf( _T("sendto() failed with WSAENOTSOCK\n") ); + break; + case WSAEOPNOTSUPP: + _tprintf( _T("sendto() failed with WSAEOPNOTSUPP\n") ); + break; + case WSAESHUTDOWN: + _tprintf( _T("sendto() failed with WSAESHUTDOWN\n") ); + break; + case WSAEWOULDBLOCK: + _tprintf( _T("sendto() failed with WSAEWOULDBLOCK\n") ); + break; + case WSAEMSGSIZE: + _tprintf( _T("sendto() failed with WSAEMSGSIZE\n") ); + break; + case WSAEHOSTUNREACH: + _tprintf( _T("sendto() failed with WSAEHOSTUNREACH\n") ); + break; + case WSAECONNABORTED: + _tprintf( _T("sendto() failed with WSAECONNABORTED\n") ); + break; + case WSAECONNRESET: + _tprintf( _T("sendto() failed with WSAECONNRESET\n") ); + break; + case WSAEADDRNOTAVAIL: + _tprintf( _T("sendto() failed with WSAEADDRNOTAVAIL\n") ); + break; + case WSAEAFNOSUPPORT: + _tprintf( _T("sendto() failed with WSAEAFNOSUPPORT\n") ); + break; + case WSAEDESTADDRREQ: + _tprintf( _T("sendto() failed with WSAEDESTADDRREQ\n") ); + break; + case WSAENETUNREACH: + _tprintf( _T("sendto() failed with WSAENETUNREACH\n") ); + break; + case WSAETIMEDOUT: + _tprintf( _T("sendto() failed with WSAETIMEDOUT\n") ); + break; + default: + _tprintf( _T("sendto() failed with unknown error\n") ); + } + + return FALSE; + } + + bWait = TRUE; + + while( bWait ) + { + /* Wait for the DNS reply. */ + j = recvfrom( s, + pOutBuffer, + *pOutBufferLength, + 0, + (SOCKADDR*)&SendAddr, + &SendAddrLen ); + if( j == SOCKET_ERROR ) + { + switch( WSAGetLastError() ) + { + case WSANOTINITIALISED: + _tprintf( _T("recvfrom() failed with WSANOTINITIALIZED\n") ); + break; + case WSAENETDOWN: + _tprintf( _T("recvfrom() failed with WSAENETDOWN\n") ); + break; + case WSAEACCES: + _tprintf( _T("recvfrom() failed with WSAEACCES\n") ); + break; + case WSAEINVAL: + _tprintf( _T("recvfrom() failed with WSAEINVAL\n") ); + break; + case WSAEINTR: + _tprintf( _T("recvfrom() failed with WSAEINTR\n") ); + break; + case WSAEINPROGRESS: + _tprintf( _T("recvfrom() failed with WSAEINPROGRESS\n") ); + break; + case WSAEFAULT: + _tprintf( _T("recvfrom() failed with WSAEFAULT\n") ); + break; + case WSAENETRESET: + _tprintf( _T("recvfrom() failed with WSAENETRESET\n") ); + break; + case WSAENOBUFS: + _tprintf( _T("recvfrom() failed with WSAENOBUFS\n") ); + break; + case WSAENOTCONN: + _tprintf( _T("recvfrom() failed with WSAENOTCONN\n") ); + break; + case WSAENOTSOCK: + _tprintf( _T("recvfrom() failed with WSAENOTSOCK\n") ); + break; + case WSAEOPNOTSUPP: + _tprintf( _T("recvfrom() failed with WSAEOPNOTSUPP\n") ); + break; + case WSAESHUTDOWN: + _tprintf( _T("recvfrom() failed with WSAESHUTDOWN\n") ); + break; + case WSAEWOULDBLOCK: + _tprintf( _T("recvfrom() failed with WSAEWOULDBLOCK\n") ); + break; + case WSAEMSGSIZE: + _tprintf( _T("recvfrom() failed with WSAEMSGSIZE\n") ); + break; + case WSAEHOSTUNREACH: + _tprintf( _T("recvfrom() failed with WSAEHOSTUNREACH\n") ); + break; + case WSAECONNABORTED: + _tprintf( _T("recvfrom() failed with WSAECONNABORTED\n") ); + break; + case WSAECONNRESET: + _tprintf( _T("recvfrom() failed with WSAECONNRESET\n") ); + break; + case WSAEADDRNOTAVAIL: + _tprintf( _T("recvfrom() failed with WSAEADDRNOTAVAIL\n") ); + break; + case WSAEAFNOSUPPORT: + _tprintf( _T("recvfrom() failed with WSAEAFNOSUPPORT\n") ); + break; + case WSAEDESTADDRREQ: + _tprintf( _T("recvfrom() failed with WSAEDESTADDRREQ\n") ); + break; + case WSAENETUNREACH: + _tprintf( _T("recvfrom() failed with WSAENETUNREACH\n") ); + break; + case WSAETIMEDOUT: + _tprintf( _T("recvfrom() failed with WSAETIMEDOUT\n") ); + break; + default: + _tprintf( _T("recvfrom() failed with unknown error\n") ); + } + + return FALSE; + } + + ResponseID = ntohs( ((PSHORT)&pOutBuffer[0])[0] ); + + if( ResponseID == RequestID ) bWait = FALSE; + } + + /* We don't need the sockets anymore. */ + closesocket( s ); + + /* If debug information then display debug information. */ + if( State.debug ) PrintDebug( pOutBuffer, j ); + + /* Return the real output buffer length. */ + *pOutBufferLength = j; + + return TRUE; +} + +void ReverseIP( PCHAR pIP, PCHAR pReturn ) +{ + int i; + int j; + int k = 0; + + j = strlen( pIP ) - 1; + i = j; + + /* We have A.B.C.D + We will turn this into D.C.B.A and stick it in pReturn */ + + /* A */ + for( ; i > 0; i -= 1 ) if( '.' == pIP[i] ) break; + + strncpy( &pReturn[k], &pIP[i + 1], (j - i) ); + k += (j - i); + + pReturn[k] = '.'; + k += 1; + + i -= 1; + j = i; + + /* B */ + for( ; i > 0; i -= 1 ) if( '.' == pIP[i] ) break; + + strncpy( &pReturn[k], &pIP[i + 1], (j - i) ); + k += (j - i); + + pReturn[k] = '.'; + k += 1; + + i -= 1; + j = i; + + /* C */ + for( ; i > 0; i -= 1 ) if( '.' == pIP[i] ) break; + + strncpy( &pReturn[k], &pIP[i + 1], (j - i) ); + k += (j - i); + + pReturn[k] = '.'; + k += 1; + + i -= 1; + j = i; + + /* D */ + for( ; i > 0; i -= 1 ); + + strncpy( &pReturn[k], &pIP[i], (j - i) + 1 ); + k += (j - i) + 1; + + pReturn[k] = '\0'; +} + +BOOL IsValidIP( PCHAR pInput ) +{ + int i = 0, l = 0, b = 0, c = 1; + + /* Max length of an IP, e.g. 255.255.255.255, is 15 characters. */ + l = strlen( pInput ); + if( l > 15 ) return FALSE; + + /* 'b' is the count of the current segment. It gets reset after seeing a + '.'. */ + for( ; i < l; i += 1 ) + { + if( '.' == pInput[i] ) + { + if( !b ) return FALSE; + if( b > 3 ) return FALSE; + + b = 0; + c += 1; + } + else + { + b += 1; + + if( (pInput[i] < '0') || (pInput[i] > '9') ) return FALSE; + } + } + + if( b > 3 ) return FALSE; + + /* 'c' is the number of segments seen. If it's less than 4, then it's not + a valid IP. */ + if( c < 4 ) return FALSE; + + return TRUE; +} + +int ExtractName( PCHAR pBuffer, PCHAR pOutput, USHORT Offset, UCHAR Limit ) +{ + int c = 0, d = 0, i = 0, j = 0, k = 0, l = 0, m = 0; + + i = Offset; + + /* If Limit == 0, then we assume "no" limit. */ + d = Limit; + if( 0 == Limit ) d = 255; + + while( d > 0 ) + { + l = pBuffer[i] & 0xFF; + i += 1; + if( !m ) c += 1; + + if( 0xC0 == l ) + { + if( !m ) c += 1; + m = 1; + d += (255 - Limit); + i = pBuffer[i]; + } + else + { + for( j = 0; j < l; j += 1 ) + { + pOutput[k] = pBuffer[i]; + + i += 1; + if( !m ) c += 1; + k += 1; + d -= 1; + } + + d -= 1; + + if( !pBuffer[i] || (d < 1) ) break; + + pOutput[k] = '.'; + k += 1; + } + }; + + if( !m ) + { + if( !Limit ) c += 1; + } + + pOutput[k] = '\0'; + + return c; +} + +int ExtractIP( PCHAR pBuffer, PCHAR pOutput, USHORT Offset ) +{ + int c = 0, l = 0, i = 0, v = 0; + + i = Offset; + + v = (UCHAR)pBuffer[i]; + l += 1; + i += 1; + + sprintf( &pOutput[c], "%d.", v ); + c += strlen( &pOutput[c] ); + + v = (UCHAR)pBuffer[i]; + l += 1; + i += 1; + + sprintf( &pOutput[c], "%d.", v ); + c += strlen( &pOutput[c] ); + + v = (UCHAR)pBuffer[i]; + l += 1; + i += 1; + + sprintf( &pOutput[c], "%d.", v ); + c += strlen( &pOutput[c] ); + + v = (UCHAR)pBuffer[i]; + l += 1; + i += 1; + + sprintf( &pOutput[c], "%d", v ); + c += strlen( &pOutput[c] ); + + pOutput[c] = '\0'; + + return l; +} + +void PrintD2( PCHAR pBuffer, DWORD BufferLength ) +{ + USHORT RequestID; + UCHAR Header1, Header2; + USHORT NumQuestions, NumAnswers, NumAuthority, NumAdditional; + USHORT Type, Class; + CHAR pName[255]; + int i = 0, k = 0; + + RequestID = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + Header1 = pBuffer[i]; + i += 1; + + Header2 = pBuffer[i]; + i += 1; + + NumQuestions = ntohs( ((PSHORT)&pBuffer[i])[0] ); + i += 2; + + NumAnswers = ntohs( ((PSHORT)&pBuffer[i])[0] ); + i += 2; + + NumAuthority = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + NumAdditional = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + _tprintf( _T("------------\n") ); + _tprintf( _T("SendRequest(), len %d\n"), (int)BufferLength ); + _tprintf( _T(" HEADER:\n") ); + _tprintf( _T(" opcode = %s, id = %d, rcode = %s\n"), + OpcodeIDtoOpcodeName( (Header1 & 0x78) >> 3 ), + (int)RequestID, + RCodeIDtoRCodeName( Header2 & 0x0F ) ); + + _tprintf( _T(" header flags: query") ); + if( Header1 & 0x01 ) _tprintf( _T(", want recursion") ); + _tprintf( _T("\n") ); + + _tprintf( _T(" questions = %d, answers = %d," + " authority records = %d, additional = %d\n\n"), + (int)NumQuestions, + (int)NumAnswers, + (int)NumAuthority, + (int)NumAdditional ); + + if( NumQuestions ) + { + _tprintf( _T(" QUESTIONS:\n") ); + + for( k = 0; k < NumQuestions; k += 1 ) + { + i += ExtractName( pBuffer, pName, i, 0 ); + + _tprintf( _T(" %s"), pName ); + + Type = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + Class = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + _tprintf( _T(", type = %s, class = %s\n"), + TypeIDtoTypeName( Type ), + ClassIDtoClassName( Class ) ); + } + } + + _tprintf( _T("\n------------\n") ); +} + +void PrintDebug( PCHAR pBuffer, DWORD BufferLength ) +{ + USHORT ResponseID; + UCHAR Header1, Header2; + USHORT NumQuestions, NumAnswers, NumAuthority, NumAdditional; + USHORT Type, Class; + ULONG TTL; + CHAR pName[255]; + int d = 0, i = 0, k = 0; + + ResponseID = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + Header1 = pBuffer[i]; + i += 1; + + Header2 = pBuffer[i]; + i += 1; + + NumQuestions = ntohs( ((PSHORT)&pBuffer[i])[0] ); + i += 2; + + NumAnswers = ntohs( ((PSHORT)&pBuffer[i])[0] ); + i += 2; + + NumAuthority = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + NumAdditional = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + _tprintf( _T("------------\n") ); + _tprintf( _T("Got answer (%d bytes):\n"), (int)BufferLength ); + _tprintf( _T(" HEADER:\n") ); + _tprintf( _T(" opcode = %s, id = %d, rcode = %s\n"), + OpcodeIDtoOpcodeName( (Header1 & 0x78) >> 3 ), + (int)ResponseID, + RCodeIDtoRCodeName( Header2 & 0x0F ) ); + + _tprintf( _T(" header flags: response") ); + if( Header1 & 0x01 ) _tprintf( _T(", want recursion") ); + if( Header2 & 0x80 ) _tprintf( _T(", recursion avail.") ); + _tprintf( _T("\n") ); + + _tprintf( _T(" questions = %d, answers = %d, " + "authority records = %d, additional = %d\n\n"), + (int)NumQuestions, + (int)NumAnswers, + (int)NumAuthority, + (int)NumAdditional ); + + if( NumQuestions ) + { + _tprintf( _T(" QUESTIONS:\n") ); + + for( k = 0; k < NumQuestions; k += 1 ) + { + i += ExtractName( pBuffer, pName, i, 0 ); + + _tprintf( _T(" %s"), pName ); + + Type = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + Class = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + _tprintf( _T(", type = %s, class = %s\n"), + TypeIDtoTypeName( Type ), + ClassIDtoClassName( Class ) ); + } + } + + if( NumAnswers ) + { + _tprintf( _T(" ANSWERS:\n") ); + + for( k = 0; k < NumAnswers; k += 1 ) + { + _tprintf( _T(" -> ") ); + + /* Print out the name. */ + i += ExtractName( pBuffer, pName, i, 0 ); + + _tprintf( _T("%s\n"), pName ); + + /* Print out the type, class and data length. */ + Type = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + Class = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + TTL = ntohl( ((PULONG)&pBuffer[i])[0] ); + i += 4; + + d = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + _tprintf( _T(" type = %s, class = %s, dlen = %d\n"), + TypeIDtoTypeName( Type ), + ClassIDtoClassName( Class ), + d ); + + /* Print out the answer. */ + if( TYPE_A == Type ) + { + i += ExtractIP( pBuffer, pName, i ); + + _tprintf( _T(" internet address = %s\n"), pName ); + } + else + { + i += ExtractName( pBuffer, pName, i, d ); + + _tprintf( _T(" name = %s\n"), pName ); + } + + _tprintf( _T(" ttl = %d ()\n"), (int)TTL ); + } + } + + if( NumAuthority ) + { + _tprintf( _T(" AUTHORITY RECORDS:\n") ); + + for( k = 0; k < NumAuthority; k += 1 ) + { + /* Print out the zone name. */ + i += ExtractName( pBuffer, pName, i, 0 ); + + _tprintf( _T(" -> %s\n"), pName ); + + /* Print out the type, class, data length and TTL. */ + Type = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + Class = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + TTL = ntohl( ((PULONG)&pBuffer[i])[0] ); + i += 4; + + d = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + _tprintf( _T(" type = %s, class = %s, dlen = %d\n"), + TypeIDtoTypeName( Type ), + ClassIDtoClassName( Class ), + d ); + + /* TODO: There might be more types? */ + if( TYPE_NS == Type ) + { + /* Print out the NS. */ + i += ExtractName( pBuffer, pName, i, d ); + + _tprintf( _T(" nameserver = %s\n"), pName ); + + _tprintf( _T(" ttl = %d ()\n"), (int)TTL ); + } + else if( TYPE_SOA == Type ) + { + _tprintf( _T(" ttl = %d ()\n"), (int)TTL ); + + /* Print out the primary NS. */ + i += ExtractName( pBuffer, pName, i, 0 ); + + _tprintf( _T(" primary name server = %s\n"), pName ); + + /* Print out the responsible mailbox. */ + i += ExtractName( pBuffer, pName, i, 0 ); + + _tprintf( _T(" responsible mail addr = %s\n"), pName ); + + /* Print out the serial, refresh, retry, expire and default TTL. */ + _tprintf( _T(" serial = ()\n") ); + _tprintf( _T(" refresh = ()\n") ); + _tprintf( _T(" retry = ()\n") ); + _tprintf( _T(" expire = ()\n") ); + _tprintf( _T(" default TTL = ()\n") ); + i += 20; + } + } + } + + if( NumAdditional ) + { + _tprintf( _T(" ADDITIONAL:\n") ); + + for( k = 0; k < NumAdditional; k += 1 ) + { + /* Print the name. */ + i += ExtractName( pBuffer, pName, i, 0 ); + + _tprintf( _T(" -> %s\n"), pName ); + + /* Print out the type, class, data length and TTL. */ + Type = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + Class = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + TTL = ntohl( ((PULONG)&pBuffer[i])[0] ); + i += 4; + + d = ntohs( ((PUSHORT)&pBuffer[i])[0] ); + i += 2; + + _tprintf( _T(" type = %s, class = %s, dlen = %d\n"), + TypeIDtoTypeName( Type ), + ClassIDtoClassName( Class ), + d ); + + /* TODO: There might be more types? */ + if( TYPE_A == Type ) + { + /* Print out the NS. */ + i += ExtractIP( pBuffer, pName, i ); + + _tprintf( _T(" internet address = %s\n"), pName ); + + _tprintf( _T(" ttl = %d ()\n"), (int)TTL ); + } + } + } + + _tprintf( _T("\n------------\n") ); +} + +PCHAR OpcodeIDtoOpcodeName( UCHAR Opcode ) +{ + switch( Opcode & 0x0F ) + { + case OPCODE_QUERY: + return OpcodeQuery; + + case OPCODE_IQUERY: + return OpcodeIQuery; + + case OPCODE_STATUS: + return OpcodeStatus; + + default: + return OpcodeReserved; + } +} + +PCHAR RCodeIDtoRCodeName( UCHAR RCode ) +{ + switch( RCode & 0x0F ) + { + case RCODE_NOERROR: + return RCodeNOERROR; + + case RCODE_FORMERR: + return RCodeFORMERR; + + case RCODE_FAILURE: + return RCodeFAILURE; + + case RCODE_NXDOMAIN: + return RCodeNXDOMAIN; + + case RCODE_NOTIMP: + return RCodeNOTIMP; + + case RCODE_REFUSED: + return RCodeREFUSED; + + default: + return RCodeReserved; + } +} + +PCHAR TypeIDtoTypeName( USHORT TypeID ) +{ + switch( TypeID ) + { + case TYPE_A: + return TypeA; + + case TYPE_NS: + return TypeNS; + + case TYPE_CNAME: + return TypeCNAME; + + case TYPE_SOA: + return TypeSOA; + + case TYPE_WKS: + return TypeSRV; + + case TYPE_PTR: + return TypePTR; + + case TYPE_MX: + return TypeMX; + + case TYPE_ANY: + return TypeAny; + + default: + return "Unknown"; + } +} + +USHORT TypeNametoTypeID( PCHAR TypeName ) +{ + if( !strncmp( TypeName, TypeA, strlen( TypeA ) ) ) return TYPE_A; + if( !strncmp( TypeName, TypeNS, strlen( TypeNS ) ) ) return TYPE_NS; + if( !strncmp( TypeName, TypeCNAME, strlen( TypeCNAME ) ) ) return TYPE_CNAME; + if( !strncmp( TypeName, TypeSOA, strlen( TypeSOA ) ) ) return TYPE_SOA; + if( !strncmp( TypeName, TypeSRV, strlen( TypeSRV ) ) ) return TYPE_WKS; + if( !strncmp( TypeName, TypePTR, strlen( TypePTR ) ) ) return TYPE_PTR; + if( !strncmp( TypeName, TypeMX, strlen( TypeMX ) ) ) return TYPE_MX; + if( !strncmp( TypeName, TypeAny, strlen( TypeAny ) ) ) return TYPE_ANY; + + return 0; +} + +PCHAR ClassIDtoClassName( USHORT ClassID ) +{ + switch( ClassID ) + { + case CLASS_IN: + return ClassIN; + + case CLASS_ANY: + return ClassAny; + + default: + return "Unknown"; + } +} + +USHORT ClassNametoClassID( PCHAR ClassName ) +{ + if( !strncmp( ClassName, ClassIN, strlen( ClassIN ) ) ) return CLASS_IN; + if( !strncmp( ClassName, ClassAny, strlen( ClassAny ) ) ) return CLASS_ANY; + + return 0; +} diff --git a/reactos/boot/bootdata/packages/reactos.dff b/reactos/boot/bootdata/packages/reactos.dff index 6cec800b26b..f3bd12ddfde 100644 --- a/reactos/boot/bootdata/packages/reactos.dff +++ b/reactos/boot/bootdata/packages/reactos.dff @@ -64,6 +64,7 @@ base\applications\network\finger\finger.exe 1 base\applications\network\ftp\ftp.exe 1 base\applications\network\ipconfig\ipconfig.exe 1 base\applications\network\netstat\netstat.exe 1 +base\applications\network\nslookup\nslookup.exe 1 base\applications\network\ping\ping.exe 1 base\applications\network\telnet\telnet.exe 1 base\applications\network\tracert\tracert.exe 1