Resolve chained CNAME records
[reactos.git] / reactos / lib / dnsapi / dnsapi / query.c
index 2def104..d8b7fae 100644 (file)
@@ -8,13 +8,10 @@
  *              12/15/03 -- Created
  */
 
-#include <windows.h>
-#include <winerror.h>
-#include <windns.h>
-#include <internal/windns.h>
-#include <string.h>
-#define NTOS_MODE_USER
-#include <ntos.h>
+#include "precomp.h"
+
+#define NDEBUG
+#include <debug.h>
 
 /* DnsQuery ****************************
  * Begin a DNS query, and allow the result to be placed in the application
 char *xstrsave(const char *str) {
   char *p;
   
-  p= RtlAllocateHeap( RtlGetProcessHeap(), 0, strlen(str)+1 );
-  strcpy(p,str);
+  p = RtlAllocateHeap( RtlGetProcessHeap(), 0, strlen(str)+1 );
+  if ( NULL != p ) {
+    strcpy(p,str);
+  }
   return p;
 }
 
@@ -53,6 +52,8 @@ DNS_STATUS WINAPI DnsQuery_A
   int quflags = 0;
   int adns_error;
   adns_answer *answer;
+  LPSTR CurrentName;
+  unsigned CNameLoop;
 
   *QueryResultSet = 0;
 
@@ -67,31 +68,78 @@ DNS_STATUS WINAPI DnsQuery_A
       return DnsIntTranslateAdnsToDNS_STATUS( adns_error );
     }
 
-    adns_error = adns_synchronous( astate, 
-                                  Name, 
-                                  adns_r_addr, 
-                                  quflags, 
-                                  &answer );
+    /*
+     * 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 );
-      return DnsIntTranslateAdnsToDNS_STATUS( adns_error );
-    }
+      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 ) {
-       *QueryResultSet = 
-           (PDNS_RECORD)RtlAllocateHeap( RtlGetProcessHeap(), 0,
-                                         sizeof( DNS_RECORD ) );
-       (*QueryResultSet)->pNext = NULL;
-       (*QueryResultSet)->wType = Type;
-       (*QueryResultSet)->pName = xstrsave( Name );
-       (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
-       (*QueryResultSet)->Data.A.IpAddress = 
-           answer->rrs.addr->addr.inet.sin_addr.s_addr;
-       adns_finish( astate );
-       return ERROR_SUCCESS;
-    } else
-       return ERROR_FILE_NOT_FOUND;
+      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. */
   }
@@ -119,7 +167,7 @@ DNS_STATUS WINAPI DnsQuery_W
   PIP4_ARRAY Servers,
   PDNS_RECORD *QueryResultSet,
   PVOID *Reserved ) {
-  int i;
+  UINT i;
   PCHAR Buffer;
   DNS_STATUS Status;
   PDNS_RECORD QueryResultWide;
@@ -302,7 +350,7 @@ DNS_STATUS WINAPI DnsQuery_UTF8
 }
 
 void DnsIntFreeRecordList( PDNS_RECORD ToDelete ) {
-  int i;
+  UINT i;
   PDNS_RECORD next = 0;
 
   while( ToDelete ) {