Merge from trunk:
Resolve chained CNAME records
Modified: branches/ros-branch-0_2_9/reactos/lib/dnsapi/dnsapi/query.c

Modified: branches/ros-branch-0_2_9/reactos/lib/dnsapi/dnsapi/query.c
--- branches/ros-branch-0_2_9/reactos/lib/dnsapi/dnsapi/query.c	2005-12-11 21:17:58 UTC (rev 20082)
+++ branches/ros-branch-0_2_9/reactos/lib/dnsapi/dnsapi/query.c	2005-12-11 21:18:32 UTC (rev 20083)
@@ -34,8 +34,10 @@
 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;
 }
 
@@ -50,6 +52,8 @@
   int quflags = 0;
   int adns_error;
   adns_answer *answer;
+  LPSTR CurrentName;
+  unsigned CNameLoop;
 
   *QueryResultSet = 0;
 
@@ -64,31 +68,78 @@
       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 ) {
+        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;
+      }
     }
-
-    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;
+    adns_finish( astate );
+    RtlFreeHeap( CurrentName, 0, GetProcessHeap() );
+    return ERROR_FILE_NOT_FOUND;
   default:
     return ERROR_OUTOFMEMORY; /* XXX arty: find a better error code. */
   }