⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 query.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
字号:
/*
 * COPYRIGHT:   See COPYING in the top level directory
 * PROJECT:     ReactOS system libraries
 * FILE:        lib/dnsapi/dnsapi/query.c
 * PURPOSE:     DNSAPI functions built on the ADNS library.
 * PROGRAMER:   Art Yerkes
 * UPDATE HISTORY:
 *              12/15/03 -- Created
 */

#include "precomp.h"

#define NDEBUG
#include <debug.h>

/* DnsQuery ****************************
 * Begin a DNS query, and allow the result to be placed in the application
 * supplied result pointer.  The result can be manipulated with the record
 * functions.  
 *
 * Name                 -- The DNS object to be queried.
 * Type                 -- The type of records to be returned.  These are 
 *                          listed in windns.h
 * Options              -- Query options.  DNS_QUERY_STANDARD is the base
 *                          state, and every other option takes precedence.
 *                          multiple options can be combined.  Listed in
 *                          windns.h
 * Servers              -- List of alternate servers (optional)
 * QueryResultSet       -- Pointer to the result pointer that will be filled
 *                          when the response is available.
 * Reserved             -- Response as it appears on the wire.  Optional.
 */

char *xstrsave(const char *str) {
  char *p;
  
  p = RtlAllocateHeap( RtlGetProcessHeap(), 0, strlen(str)+1 );
  if ( NULL != p ) {
    strcpy(p,str);
  }
  return p;
}

DNS_STATUS WINAPI DnsQuery_A
( LPCSTR Name,
  WORD Type,
  DWORD Options,
  PIP4_ARRAY Servers,
  PDNS_RECORD *QueryResultSet,
  PVOID *Reserved ) {
  adns_state astate;
  int quflags = 0, i;
  int adns_error;
  adns_answer *answer;
  LPSTR CurrentName;
  unsigned CNameLoop;

  *QueryResultSet = 0;

  switch( Type ) {
  case DNS_TYPE_A:
    adns_error = adns_init( &astate,
			    adns_if_noenv |
			    adns_if_noerrprint |
			    adns_if_noserverwarn |
			    (Servers ? adns_if_noserver : 0),
			    0 );
    
    if( adns_error != adns_s_ok ) {
      return DnsIntTranslateAdnsToDNS_STATUS( adns_error );
    }

    if (Servers) {
      for( i = 0; i < Servers->AddrCount; i++ ) {
	adns_addserver( astate, *((struct in_addr *)&Servers->AddrArray[i]) );
      }
    }

    /*
     * adns doesn't resolve chained CNAME records (a CNAME which points to
     * another CNAME pointing to another... pointing to an A record), according
     * to a mailing list thread the authors believe that chained CNAME records
     * are invalid and the DNS entries should be fixed. That's a nice academic
     * standpoint, but there certainly are chained CNAME records out there,
     * even some fairly major ones (at the time of this writing
     * download.mozilla.org is a chained CNAME). Everyone else seems to resolve
     * these fine, so we should too. So we loop here to try to resolve CNAME
     * chains ourselves. Of course, there must be a limit to protect against
     * CNAME loops.
     */

#define CNAME_LOOP_MAX 16

    CurrentName = (LPSTR) Name;
    for ( CNameLoop = 0; CNameLoop < CNAME_LOOP_MAX; CNameLoop++ ) {
      adns_error = adns_synchronous( astate, 
                                     CurrentName, 
                                     adns_r_addr, 
                                     quflags, 
                                     &answer );
				   
      if( adns_error != adns_s_ok ) {
        adns_finish( astate );
        if ( CurrentName != Name ) {
          RtlFreeHeap( CurrentName, 0, GetProcessHeap() );
        }
        return DnsIntTranslateAdnsToDNS_STATUS( adns_error );
      }

      if( answer && answer->rrs.addr ) {
        if ( CurrentName != Name ) {
          RtlFreeHeap( CurrentName, 0, GetProcessHeap() );
        }
        *QueryResultSet = 
          (PDNS_RECORD)RtlAllocateHeap( RtlGetProcessHeap(), 0,
                                        sizeof( DNS_RECORD ) );
        if ( NULL == *QueryResultSet ) {
          adns_finish( astate );
          return ERROR_OUTOFMEMORY;
        }
        (*QueryResultSet)->pNext = NULL;
        (*QueryResultSet)->wType = Type;
        (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
        (*QueryResultSet)->Data.A.IpAddress = 
            answer->rrs.addr->addr.inet.sin_addr.s_addr;
        adns_finish( astate );
        (*QueryResultSet)->pName = xstrsave( Name );
        return NULL != (*QueryResultSet)->pName ? ERROR_SUCCESS :
                                                  ERROR_OUTOFMEMORY;
      }
      if ( NULL == answer || adns_s_prohibitedcname != answer->status ||
           NULL == answer->cname ) {
        adns_finish( astate );
        if ( CurrentName != Name ) {
          RtlFreeHeap( CurrentName, 0, GetProcessHeap() );
        }
        return ERROR_FILE_NOT_FOUND;
      }
      if ( CurrentName != Name ) {
        RtlFreeHeap( CurrentName, 0, GetProcessHeap() );
      }
      CurrentName = xstrsave( answer->cname );
      if ( NULL == CurrentName ) {
        adns_finish( astate );
        return ERROR_OUTOFMEMORY;
      }
    }
    adns_finish( astate );
    RtlFreeHeap( CurrentName, 0, GetProcessHeap() );
    return ERROR_FILE_NOT_FOUND;
  default:
    return ERROR_OUTOFMEMORY; /* XXX arty: find a better error code. */
  }
}

static PCHAR DnsWToC( const WCHAR *WideString ) {
  int chars = wcstombs( NULL, WideString, 0 );
  PCHAR out = RtlAllocateHeap( RtlGetProcessHeap(), 0, chars + 1 );
  wcstombs( out, WideString, chars + 1 );
  return out;
}

static PWCHAR DnsCToW( const CHAR *NarrowString ) {
  int chars = mbstowcs( NULL, NarrowString, 0 );
  PWCHAR out = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
				(chars + 1) * sizeof(WCHAR) );
  mbstowcs( out, NarrowString, chars + 1 );
  return out;
}

DNS_STATUS WINAPI DnsQuery_W
( LPCWSTR Name,
  WORD Type,
  DWORD Options,
  PIP4_ARRAY Servers,
  PDNS_RECORD *QueryResultSet,
  PVOID *Reserved ) {
  UINT i;
  PCHAR Buffer;
  DNS_STATUS Status;
  PDNS_RECORD QueryResultWide;
  PDNS_RECORD ConvertedRecord = 0, LastRecord = 0;

  Buffer = DnsWToC( Name );

  Status = DnsQuery_A( Buffer, Type, Options, Servers, &QueryResultWide,
		       Reserved );

  while( Status == ERROR_SUCCESS && QueryResultWide ) {
    switch( QueryResultWide->wType ) {
    case DNS_TYPE_A:
    case DNS_TYPE_WKS:
#ifndef __USE_W32API
    case DNS_TYPE_AAAA:
    case DNS_TYPE_KEY:
#endif
      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
					 sizeof(DNS_RECORD) );
      ConvertedRecord->pName = (PCHAR)DnsCToW( QueryResultWide->pName );
      ConvertedRecord->wType = QueryResultWide->wType;
      ConvertedRecord->wDataLength = QueryResultWide->wDataLength;
      memcpy( ConvertedRecord, QueryResultWide, 
	      QueryResultWide->wDataLength );
      break;

    case DNS_TYPE_CNAME:
    case DNS_TYPE_PTR:
    case DNS_TYPE_NS:
    case DNS_TYPE_MB:
    case DNS_TYPE_MD:
    case DNS_TYPE_MF:
    case DNS_TYPE_MG:
    case DNS_TYPE_MR:
      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
					 sizeof(DNS_RECORD) );
      ConvertedRecord->pName = (PCHAR)DnsCToW( QueryResultWide->pName );
      ConvertedRecord->wType = QueryResultWide->wType;
      ConvertedRecord->wDataLength = sizeof(DNS_PTR_DATA);
      ConvertedRecord->Data.PTR.pNameHost = 
	  (PCHAR)DnsCToW( QueryResultWide->Data.PTR.pNameHost );
      break;
    case DNS_TYPE_MINFO:
#ifndef __USE_W32API
    case DNS_TYPE_RP:
#endif
      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
					 sizeof(DNS_RECORD) );
      ConvertedRecord->pName = (PCHAR)DnsCToW( QueryResultWide->pName );
      ConvertedRecord->wType = QueryResultWide->wType;
      ConvertedRecord->wDataLength = sizeof(DNS_MINFO_DATA);
      ConvertedRecord->Data.MINFO.pNameMailbox =
	  (PCHAR)DnsCToW( QueryResultWide->Data.MINFO.pNameMailbox );
      ConvertedRecord->Data.MINFO.pNameErrorsMailbox =
	  (PCHAR)DnsCToW( QueryResultWide->Data.MINFO.pNameErrorsMailbox );
      break;

    case DNS_TYPE_MX:
#ifndef __USE_W32API
    case DNS_TYPE_AFSDB:
    case DNS_TYPE_RT:
#endif
      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
					 sizeof(DNS_RECORD) );
      ConvertedRecord->pName = (PCHAR)DnsCToW( QueryResultWide->pName );
      ConvertedRecord->wType = QueryResultWide->wType;
      ConvertedRecord->wDataLength = sizeof(DNS_MX_DATA);
      ConvertedRecord->Data.MX.pNameExchange = 
	  (PCHAR)DnsCToW( QueryResultWide->Data.MX.pNameExchange );
      ConvertedRecord->Data.MX.wPreference =
	  QueryResultWide->Data.MX.wPreference;
      break;

#ifndef __USE_W32API
    case DNS_TYPE_TXT:
    case DNS_TYPE_ISDN:
#endif
    case DNS_TYPE_HINFO:
      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
					 sizeof(DNS_TXT_DATA) + 
					 QueryResultWide->
					 Data.TXT.dwStringCount );
      ConvertedRecord->pName = (PCHAR)DnsCToW( QueryResultWide->pName );
      ConvertedRecord->wType = QueryResultWide->wType;
      ConvertedRecord->wDataLength = 
	sizeof(DNS_TXT_DATA) + 
	(sizeof(PWCHAR) * QueryResultWide->Data.TXT.dwStringCount);
      ConvertedRecord->Data.TXT.dwStringCount = 
	QueryResultWide->Data.TXT.dwStringCount;
      for( i = 0; i < ConvertedRecord->Data.TXT.dwStringCount; i++ ) {
	ConvertedRecord->Data.TXT.pStringArray[i] = 
	    (PCHAR)DnsCToW( QueryResultWide->Data.TXT.pStringArray[i] );
      }
      break;

    case DNS_TYPE_NULL:
      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
					 sizeof(DNS_NULL_DATA) + 
					 QueryResultWide->
					 Data.Null.dwByteCount );
      ConvertedRecord->pName = (PCHAR)DnsCToW( QueryResultWide->pName );
      ConvertedRecord->wType = QueryResultWide->wType;
      ConvertedRecord->wDataLength =
	sizeof(DNS_NULL_DATA) + QueryResultWide->Data.Null.dwByteCount;
      ConvertedRecord->Data.Null.dwByteCount = 
	QueryResultWide->Data.Null.dwByteCount;
      memcpy( &ConvertedRecord->Data.Null.Data, 
	      &QueryResultWide->Data.Null.Data,
	      QueryResultWide->Data.Null.dwByteCount );
      break;

#ifndef __USE_W32API
    case DNS_TYPE_SIG:
      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
					 sizeof(DNS_RECORDA) );
      ConvertedRecord->pName = DnsCToW( QueryResultWide->pName );
      ConvertedRecord->wType = QueryResultWide->wType;
      ConvertedRecord->wDataLength = sizeof(DNS_SIG_DATAA);
      memcpy( &ConvertedRecord->Data.SIG,
	      &QueryResultWide->Data.SIG,
	      sizeof(QueryResultWide->Data.SIG) );
      ConvertedRecord->Data.SIG.pNameSigner =
	DnsCToW( QueryResultWide->Data.SIG.pNameSigner );
      break;

    case DNS_TYPE_NXT:
      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
					 sizeof(DNS_RECORDA) );
      ConvertedRecord->pName = DnsCToW( QueryResultWide->pName );
      ConvertedRecord->wType = QueryResultWide->wType;
      ConvertedRecord->wDataLength = sizeof(DNS_NXT_DATAA);
      memcpy( &ConvertedRecord->Data.NXT,
	      &QueryResultWide->Data.NXT,
	      sizeof(QueryResultWide->Data.NXT) );
      ConvertedRecord->Data.NXT.pNameNext =
	DnsCToW( QueryResultWide->Data.NXT.pNameNext );
      break;

    case DNS_TYPE_SRV:
      ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0, 
					 sizeof(DNS_RECORDA) );
      ConvertedRecord->pName = DnsCToW( QueryResultWide->pName );
      ConvertedRecord->wType = QueryResultWide->wType;
      ConvertedRecord->wDataLength = sizeof(DNS_SRV_DATAA);
      memcpy( &ConvertedRecord->Data.SRV,
	      &QueryResultWide->Data.SRV,
	      sizeof(QueryResultWide->Data.SRV) );
      ConvertedRecord->Data.SRV.pNameTarget =
	DnsCToW( QueryResultWide->Data.SRV.pNameTarget );
      break;
#endif
    }

    if( LastRecord ) {
      LastRecord->pNext = ConvertedRecord;
      LastRecord = LastRecord->pNext;
    } else {
      LastRecord = *QueryResultSet = ConvertedRecord;
    }
  }

  LastRecord->pNext = 0;

  /* The name */
  RtlFreeHeap( RtlGetProcessHeap(), 0, Buffer );

  return Status;
}

DNS_STATUS WINAPI DnsQuery_UTF8
( LPCSTR Name,
  WORD Type,
  DWORD Options,
  PIP4_ARRAY Servers,
  PDNS_RECORD *QueryResultSet,
  PVOID *Reserved ) {
  return DnsQuery_UTF8( Name, Type, Options, Servers, QueryResultSet, 
			Reserved );
}

void DnsIntFreeRecordList( PDNS_RECORD ToDelete ) {
  UINT i;
  PDNS_RECORD next = 0;

  while( ToDelete ) {
      if( ToDelete->pName ) 
	  RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->pName );
      switch( ToDelete->wType ) {
      case DNS_TYPE_CNAME:
      case DNS_TYPE_PTR:
      case DNS_TYPE_NS:
      case DNS_TYPE_MB:
      case DNS_TYPE_MD:
      case DNS_TYPE_MF:
      case DNS_TYPE_MG:
      case DNS_TYPE_MR:
	  RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.PTR.pNameHost );
	  break;
      case DNS_TYPE_MINFO:
#ifndef __USE_W32API
      case DNS_TYPE_RP:
	  RtlFreeHeap( RtlGetProcessHeap(), 0, 
		       ToDelete->Data.MINFO.pNameMailbox );
	  RtlFreeHeap( RtlGetProcessHeap(), 0,
		       ToDelete->Data.MINFO.pNameErrorsMailbox );
	  break;
	  
      case DNS_TYPE_AFSDB:
      case DNS_TYPE_RT:
#endif
      case DNS_TYPE_MX:
	  RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.MX.pNameExchange );
	  break;
	  
#ifndef __USE_W32API
      case DNS_TYPE_TXT:
      case DNS_TYPE_ISDN:
#endif
      case DNS_TYPE_HINFO:
	  for( i = 0; i < ToDelete->Data.TXT.dwStringCount; i++ ) {
	      RtlFreeHeap( RtlGetProcessHeap(), 0, 
			   ToDelete->Data.TXT.pStringArray[i] );
	  }
	  RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.TXT.pStringArray );
	  break;
	  
#ifndef __USE_W32API
      case DNS_TYPE_SIG:
	  RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.SIG.pNameSigner );
	  break;
	  
      case DNS_TYPE_NXT:
	  RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.NXT.pNameNext );
	  break;
	  
      case DNS_TYPE_SRV:
	  RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.SRV.pNameTarget );
	  break;
#endif
      }
      
      next = ToDelete->pNext;
      RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete );
      ToDelete = next;
  }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -