/* * PROJECT: ReactOS nslookup utility * LICENSE: GPL - See COPYING in the top level directory * FILE: base/applications/network/nslookup/utility.c * PURPOSE: Support functions for nslookup.c * COPYRIGHT: Copyright 2009 Lucas Suggs */ #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 ); if (s == INVALID_SOCKET) return FALSE; /* 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") ); } closesocket( s ); 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") ); } closesocket( s ); 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; }