6c09e05fd4c874acf7d12408bbe32a530ebf9541
[openafs.git] / src / WINNT / afsd / cm_dns.c
1 /* Copyright 2000, International Business Machines Corporation and others.
2  * All Rights Reserved.
3  *
4  * This software has been released under the terms of the IBM Public
5  * License.  For details, see the LICENSE file in the top-level source
6  * directory or online at http://www.openafs.org/dl/license10.html
7  */
8
9 #ifdef AFS_AFSDB_ENV
10
11 #include <afs/param.h>
12 #include <afs/stds.h>
13 #include <afs/cellconfig.h>
14 #include <windows.h>
15 #include <winsock2.h>
16 #include "cm_dns_private.h"
17 #include "cm_dns.h"
18 #include <lwp.h>
19 #include <afs/afsint.h>
20 #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500)
21 #include <windns.h>
22 #define DNSAPI_ENV
23 #endif
24 #include <errno.h>
25
26 /*extern void afsi_log(char *pattern, ...);*/
27
28 static char dns_addr[30];
29 static int cm_dnsEnabled = -1;
30
31 void DNSlowerCase(char *str)
32 {
33   int i;
34
35   for (i=0; i<strlen(str); i++)
36     /*str[i] = tolower(str[i]);*/
37     if (str[i] >= 'A' && str[i] <= 'Z')
38       str[i] += 'a' - 'A';
39 }
40
41 int cm_InitDNS(int enabled)
42 {
43 #ifndef DNSAPI_ENV
44   char configpath[100];
45   int len;
46   int code;
47   char *addr;
48   
49   if (!enabled) { fprintf(stderr, "DNS support disabled\n"); cm_dnsEnabled = 0; return 0; }
50
51   /* First try AFS_NS environment var. */
52   addr = getenv("AFS_NS");
53   if (addr && inet_addr(addr) != -1) {
54     strcpy(dns_addr, addr);
55   } else {
56     /* Now check for the AFSDNS.INI file */
57     code = GetWindowsDirectory(configpath, sizeof(configpath));
58     if (code == 0 || code > sizeof(configpath)) return -1;
59     strcat(configpath, "\\afsdns.ini");
60
61     /* Currently we only get (and query) the first nameserver.  Getting
62        list of mult. nameservers should be easy to do. */
63     len = GetPrivateProfileString("AFS Domain Name Servers", "ns1", NULL,
64                             dns_addr, sizeof(dns_addr),
65                             configpath);
66   
67     if (len == 0 || inet_addr(dns_addr) == -1) {
68       fprintf(stderr, "No valid name server addresses found, DNS lookup is "
69                       "disabled\n");
70       cm_dnsEnabled = 0;  /* failed */
71       return -1;     /* No name servers defined */
72     }
73     else fprintf(stderr, "Found DNS server %s\n", dns_addr);
74   }
75 #endif /* DNSAPI_ENV */
76   cm_dnsEnabled = 1;
77   return 0;
78 }
79
80 #ifndef DNSAPI_ENV
81 SOCKADDR_IN setSockAddr(char *server, int port)
82 {
83   SOCKADDR_IN sockAddr;                     
84   int         addrLen = sizeof(SOCKADDR_IN);
85
86 #ifndef WIN32_LEAN_AND_MEAN
87   bzero(&sockAddr,addrLen);
88 #endif /*WIN32_LEAN_AND_MEAN*/
89   sockAddr.sin_family   = AF_INET;
90   sockAddr.sin_port     = htons( port );
91   sockAddr.sin_addr.s_addr = inet_addr( server );
92   /*inet_aton(server, &sockAddr.sin_addr.s_addr);*/
93
94   return (sockAddr);
95 }
96
97 int getRRCount(PDNS_HDR ptr)
98 {
99   return(ntohs(ptr->rr_count));
100 }
101
102
103 int send_DNS_Addr_Query(char* query, 
104                          SOCKET commSock, SOCKADDR_IN sockAddr, char *buffer)
105 {
106   PDNS_HDR    pDNShdr;
107   PDNS_QTAIL  pDNS_qtail;
108
109   int     queryLen = 0;
110   int     res;
111
112 #ifndef WIN32_LEAN_AND_MEAN
113   bzero(buffer,BUFSIZE);
114 #endif /*WIN32_LEAN_AND_MEAN*/
115
116   /*********************************
117    * Build DNS Query Message       *
118    *                               *
119    * hard-coded Adrress (A) query  *
120    *********************************/
121   
122   pDNShdr = (PDNS_HDR)&( buffer[ 0 ] );
123   pDNShdr->id         = htons( 0xDADE );
124   pDNShdr->flags      = htons( DNS_FLAG_RD ); /* do recurse */
125   pDNShdr->q_count    = htons( 1 );           /* one query */
126   pDNShdr->rr_count   = 0;                    /* none in query */
127   pDNShdr->auth_count = 0;                    /* none in query */
128   pDNShdr->add_count  = 0;                    /* none in query */
129   
130   queryLen = putQName( query, &(buffer[ DNS_HDR_LEN ] ) );
131   queryLen += DNS_HDR_LEN; /* query Length is just after the query name and header */
132 #ifdef DEBUG
133   fprintf(stderr, "send_DNS_Addr: query=%s, queryLen=%d\n", query, queryLen);
134 #endif
135   
136   
137   pDNS_qtail = (PDNS_QTAIL) &(buffer[ queryLen ]);
138   pDNS_qtail->qtype = htons(255);/*htons(DNS_RRTYPE_A); */
139   pDNS_qtail->qclass = htons(DNS_RRCLASS_IN); 
140   queryLen +=  DNS_QTAIL_LEN;
141   
142   /**************************
143    * Send DNS Query Message *
144    **************************/
145   
146
147   res = sendto( commSock,
148                 buffer,
149                 queryLen,
150                 0,
151                 (struct sockaddr *) &sockAddr,
152                 sizeof( SOCKADDR_IN ) );
153   
154   /*dumpSbuffer(buffer,queryLen);*/
155
156   if ( res < 0 )
157     {
158 #ifdef DEBUG
159       fprintf(stderr, "send_DNS_Addr_Query: error %d, errno %d\n", res, errno);
160       fprintf(stderr, "sendto() failed \n");
161 #endif
162       return ( -1 );
163     }
164   else
165     {
166     /*printf( "sendto() succeeded\n");*/
167     ;
168     } /* end if */
169   
170   return(0);
171 }
172
173
174 int send_DNS_AFSDB_Query(char* query, 
175                          SOCKET commSock, SOCKADDR_IN sockAddr, char *buffer)
176 {
177   /*static char buffer[BUFSIZE];*/
178
179   PDNS_HDR    pDNShdr;
180   PDNS_QTAIL  pDNS_qtail;
181
182   int     queryLen = 0;
183   int     res;
184
185 #ifndef WIN32_LEAN_AND_MEAN
186   bzero(buffer,BUFSIZE);
187 #endif /*WIN32_LEAN_AND_MEAN*/
188
189   /***************************
190    * Build DNS Query Message *
191    *                         *
192    * hard-coded AFSDB query  *
193    ***************************/
194   
195   pDNShdr = (PDNS_HDR)&( buffer[ 0 ] );
196   pDNShdr->id         = htons( 0xDEAD );
197   pDNShdr->flags      = htons( DNS_FLAG_RD ); /* do recurse */
198   pDNShdr->q_count    = htons( 1 );           /* one query */
199   pDNShdr->rr_count   = 0;                    /* none in query */
200   pDNShdr->auth_count = 0;                    /* none in query */
201   pDNShdr->add_count  = 0;                    /* none in query */
202   
203   queryLen = putQName( query, &(buffer[ DNS_HDR_LEN ] ) );
204   queryLen += DNS_HDR_LEN; /* query Length is just after the query name and header */
205   
206   
207   pDNS_qtail = (PDNS_QTAIL) &(buffer[ queryLen ]);
208   pDNS_qtail->qtype = htons(DNS_RRTYPE_AFSDB); 
209   pDNS_qtail->qclass = htons(DNS_RRCLASS_IN); 
210   queryLen +=  DNS_QTAIL_LEN;
211   
212   /**************************
213    * Send DNS Query Message *
214    **************************/
215   
216   res = sendto( commSock,
217                 buffer,
218                 queryLen,
219                 0,
220                 (struct sockaddr *) &sockAddr,
221                 sizeof( SOCKADDR_IN ) );
222   
223   /*dumpSbuffer(buffer,queryLen);*/
224
225   if ( res < 0 )
226     {
227 #ifdef DEBUG
228       fprintf(stderr, "send_DNS_AFSDB_Query: error %d, errno %d\n", res, errno);
229       fprintf(stderr,  "sendto() failed \n");
230 #endif /* DEBUG */
231       return ( -1 );
232     }
233   else
234     {
235     /*printf( "sendto() succeeded\n");*/
236     ;
237     } /* end if */
238   
239   return(0);
240 }
241
242
243 PDNS_HDR get_DNS_Response(SOCKET commSock, SOCKADDR_IN sockAddr, char *buffer)
244 {
245   /*static char buffer[BUFSIZE];*/
246
247   int         addrLen = sizeof(SOCKADDR_IN);
248   int size;
249
250 #ifndef WIN32_LEAN_AND_MEAN
251   bzero(buffer,BUFSIZE);
252 #endif /*WIN32_LEAN_AND_MEAN*/
253
254   /*****************************
255    * Receive DNS Reply Message *
256    *****************************/
257   
258   /*printf( "calling recvfrom() on connected UDP socket\n" );*/
259   
260   size = recvfrom( commSock,
261                   buffer,
262                   BUFSIZE,
263                   0,
264                   (struct sockaddr *) &sockAddr,
265                   &addrLen );
266   if (size < 0) { fprintf(stderr, "recvfrom error %d\n", errno); return NULL; }
267
268   /*dumpRbuffer(buffer,res);*/
269
270 #ifdef DEBUG
271   fprintf(stderr, "recvfrom returned %d bytes from %s: \n", 
272           size, inet_ntoa( sockAddr.sin_addr ) );
273 #endif /* DEBUG */
274   
275   return((PDNS_HDR)&( buffer[ 0 ] ));
276
277 }
278
279
280 int putQName( char *pHostName, char *pQName )
281 {
282   int     i;
283   char    c;
284   int     j = 0;
285   int     k = 0;
286   
287   DNSlowerCase(pHostName);
288   /*printf( "Hostname: [%s]\n", pHostName );*/
289   
290   for ( i = 0; *( pHostName + i ); i++ )
291     {
292       c = *( pHostName + i );   /* get next character */
293       
294       
295       if ( c == '.' )
296         {
297           /* dot encountered, fill in previous length */
298           if (k!=0){ /*don't process repeated dots*/
299           /*printf( "%c", c );*/
300             *( pQName + j ) = k;
301             j = j+k+1;  /* set index to next counter */
302             k = 0;      /* reset segment length */
303           }
304         }
305       else
306         {
307         /*printf( "%c", c );*/
308           *( pQName + j + k + 1 ) = c;  /* assign to QName */
309           k++;                /* inc count of seg chars */
310         } /* end if */
311     } /* end for loop */
312   
313   *(pQName + j )                  = k;   /* count for final segment */
314
315   *(pQName + j + k + 1 )      = 0;   /* count for trailing NULL segment is 0 */
316   
317   /*printf( "\n" ); */
318   
319   if (c == '.')
320     return ( j + k + 1 );        /* return total length of QName */
321   else
322     return ( j + k + 2 );
323 } /* end putQName() */
324
325
326 u_char * skipRRQName(u_char *pQName)
327 {
328   u_char *ptr;
329   u_char c;
330
331   ptr = pQName;
332   c = *ptr;
333   while (c) {
334     if ( c >= 0xC0 ) {
335     /* skip the 'compression' pointer */
336       ptr = ptr+1;
337       c = '\0';
338     } else {
339       /* skip a normal qname segment */
340       ptr += *ptr;
341       ptr++;
342       c = *ptr;
343     };
344   };
345
346   /* ptr now pointing at terminating zero of query QName,
347      or the pointer for the previous occurrence 
348      (compression)
349    */
350   ptr++;
351
352   return (ptr);
353 } /* end skipRRQName() */
354
355
356
357 u_char * printRRQName( u_char *pQName, PDNS_HDR buffer )
358 {
359   u_short i, k;
360   u_char *buffPtr = (u_char *) buffer;
361   u_char *namePtr;
362   u_char *retPtr;
363   u_char c;
364
365
366   namePtr = pQName;
367   retPtr = 0;
368
369   for ( i = 0; i < BUFSIZE; i++ )
370     {
371       c = *namePtr;
372       if ( c >= 0xC0 ) {
373         c = *(namePtr + 1);
374         retPtr = namePtr+2;
375         namePtr = buffPtr+c; 
376       } else {
377         if ( c == 0 )
378           break;
379         
380         for ( k = 1; k <= c; k++ )
381           {
382             fprintf(stderr, "%c", *( namePtr + k ) );
383           } /* end for loop */
384         fprintf(stderr,".");
385         namePtr += k;
386       }
387     } /* end for loop */
388   fprintf(stderr,"\n");
389   namePtr++; /* skip terminating zero */
390
391   if (retPtr)
392     return(retPtr);
393   else
394     return(namePtr);
395
396 } /* end printRRQName() */
397
398
399 u_char * sPrintRRQName( u_char *pQName, PDNS_HDR buffer, char *str )
400 {
401   u_short i, k;
402   u_char *buffPtr = (u_char *) buffer;
403   u_char *namePtr;
404   u_char *retPtr;
405   u_char c;
406
407   char   section[64];
408
409   strcpy(str,"");
410   namePtr = pQName;
411   retPtr = 0;
412
413   for ( i = 0; i < BUFSIZE; i++ )
414     {
415       c = *namePtr;
416       if ( c >= 0xC0 ) {
417         c = *(namePtr + 1);
418         retPtr = namePtr+2;
419         namePtr = buffPtr+c; 
420       } else {
421         if ( c == 0 )
422           break;
423         
424         for ( k = 1; k <= c; k++ )
425           {
426             sprintf(section,"%c", *( namePtr + k ) );
427             strcat(str,section);
428           } /* end for loop */
429         strcat(str,".");
430         namePtr += k;
431       }
432     } /* end for loop */
433   namePtr++; /* skip terminating zero */
434
435   if (retPtr)
436     return(retPtr);
437   else
438     return(namePtr);
439
440 } /* end sPrintRRQName() */
441
442
443 void printReplyBuffer_AFSDB(PDNS_HDR replyBuff)
444 {
445   u_char *ptr = (u_char *) replyBuff;
446   int    answerCount = ntohs((replyBuff)->rr_count);
447   u_char i;
448   PDNS_AFSDB_RR_HDR 
449          rrPtr;
450
451   ptr += DNS_HDR_LEN;
452
453   /* ptr now pointing at start of QName in query field */
454   ptr = skipRRQName(ptr);
455
456
457   /* skip the query type and class fields */
458   ptr+= DNS_QTAIL_LEN;
459
460   /* ptr should now be at the start of the answer RR sections */
461
462   fprintf(stderr,"---------------------------------\n");
463   for (i=0; i<answerCount ; i++){
464     ptr = skipRRQName(ptr);
465     rrPtr = (PDNS_AFSDB_RR_HDR) ptr;
466     ptr+= DNS_AFSDB_RR_HDR_LEN;
467     if ( ntohs(rrPtr->rr_afsdb_class) == 1) {
468       fprintf(stderr,"AFDB class %d ->  ",ntohs(rrPtr->rr_afsdb_class)); 
469       ptr = printRRQName(ptr,replyBuff); }
470     else
471       ptr = skipRRQName(ptr);
472   };
473   fprintf(stderr,"---------------------------------\n");
474
475
476 };
477
478 void processReplyBuffer_AFSDB(SOCKET commSock, PDNS_HDR replyBuff, int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS], int *numServers, int *ttl)
479   /*PAFS_SRV_LIST (srvList)*/
480 {
481   u_char *ptr = (u_char *) replyBuff;
482   int    answerCount = ntohs((replyBuff)->rr_count);
483   u_char i;
484   PDNS_AFSDB_RR_HDR 
485          rrPtr;
486   int srvCount = 0;
487   char hostName[256];
488   struct in_addr addr;
489   int rc;
490
491   ptr += DNS_HDR_LEN;
492
493   /* ptr now pointing at start of QName in query field */
494   ptr = skipRRQName(ptr);
495
496
497   /* skip the query type and class fields */
498   ptr+= DNS_QTAIL_LEN;
499
500   /* ptr should now be at the start of the answer RR sections */
501
502   answerCount = MIN(answerCount, AFSMAXCELLHOSTS);
503 #ifdef DEBUG
504   fprintf(stderr, "processRep_AFSDB: answerCount=%d\n", answerCount);
505 #endif /* DEBUG */
506
507   for (i=0; i<answerCount ; i++){
508     ptr = skipRRQName(ptr);
509     rrPtr = (PDNS_AFSDB_RR_HDR) ptr;
510     ptr+= DNS_AFSDB_RR_HDR_LEN;
511     if ((ntohs(rrPtr->rr_afsdb_class) == 1) && 
512         (srvCount < MAX_AFS_SRVS)) {
513       /*ptr = sPrintRRQName(ptr,replyBuff,srvList->host[srvList->count]);*/
514       ptr = sPrintRRQName(ptr,replyBuff,hostName);
515       /*ptr = printRRQName(ptr,replyBuff);*/
516       *ttl = ntohl(rrPtr->rr_ttl);
517
518 #ifdef DEBUG
519       fprintf(stderr, "resolving name %s\n", hostName);
520 #endif
521       /* resolve name from DNS query */
522       rc = DNSgetAddr(commSock, hostName, &addr);
523       if (rc < 0)
524         continue;  /* skip this entry */
525 #ifdef DEBUG
526       fprintf(stderr, "processRep_AFSDB: resolved name %s to addr %x\n", hostName, addr);
527 #endif /* DEBUG */
528       memcpy(&cellHostAddrs[srvCount], &addr.s_addr, sizeof(addr.s_addr));
529           strncpy(cellHostNames[srvCount], hostName, MAXCELLCHARS);
530           cellHostNames[srvCount][MAXCELLCHARS-1] = '\0';
531       srvCount++;
532     }
533     else {
534       ptr = skipRRQName(ptr);
535     }
536   }
537
538   *numServers = srvCount;
539
540 }
541
542
543 u_char * processReplyBuffer_Addr(PDNS_HDR replyBuff)
544 {
545   u_char *ptr = (u_char *) replyBuff;
546   int    answerCount = ntohs((replyBuff)->rr_count);
547   PDNS_A_RR_HDR 
548          rrPtr;
549
550 #ifdef DEBUG
551   fprintf(stderr, "processReplyBuffer_Addr: answerCount=%d\n", answerCount);
552 #endif /* DEBUG */
553   if (answerCount == 0) return 0;
554   
555   ptr += DNS_HDR_LEN;
556
557   /* ptr now pointing at start of QName in query field */
558   ptr = skipRRQName(ptr);
559
560
561   /* skip the query type and class fields */
562   ptr+= DNS_QTAIL_LEN;
563
564   /* ptr should now be at the start of the answer RR sections */
565   ptr = skipRRQName(ptr);
566   rrPtr = (PDNS_A_RR_HDR) ptr;
567
568 #ifdef DEBUG
569   fprintf(stderr, "type:%d, class:%d, ttl:%d, rdlength:%d\n",
570          ntohs(rrPtr->rr_type),ntohs(rrPtr->rr_class),
571          ntohl(rrPtr->rr_ttl),ntohs(rrPtr->rr_rdlength));
572   fprintf(stderr, "Count %d\tand Answer %8x\n",answerCount,rrPtr->rr_addr);
573 #endif /* DEBUG */
574
575   ptr += DNS_A_RR_HDR_LEN;
576
577   return (ptr);
578
579 };
580
581 int DNSgetAddr(SOCKET commSock, char *hostName, struct in_addr *iNet)
582 {
583   /* Variables for DNS message parsing and creation */
584   PDNS_HDR  pDNShdr;
585
586   SOCKADDR_IN sockAddr;
587   char buffer[BUFSIZE];
588   u_char *addr;
589   u_long *aPtr;
590   int rc;
591
592   /**********************
593    * Get a DGRAM socket *
594    **********************/
595   
596   sockAddr = setSockAddr(dns_addr, DNS_PORT);
597   
598   rc = send_DNS_Addr_Query(hostName,commSock,sockAddr, buffer);
599   if (rc < 0) return rc;
600   pDNShdr = get_DNS_Response(commSock,sockAddr, buffer);
601   if (pDNShdr == NULL)
602     return -1;
603   
604   addr = processReplyBuffer_Addr(pDNShdr);
605   if (addr == 0)
606     return -1;
607
608   aPtr = (u_long *) addr;
609
610   iNet->s_addr = *aPtr;
611
612   return(0);
613 }
614 #endif /* DNSAPI_ENV */
615
616 int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS], 
617                  int *numServers, int *ttl)
618 {
619 #ifndef DNSAPI_ENV
620    /*static AFS_SRV_LIST srvList;
621     static int ans = 0;*/
622   SOCKET commSock;
623   SOCKADDR_IN sockAddr;
624   PDNS_HDR  pDNShdr;
625   char buffer[BUFSIZE];
626   char query[1024];
627   int rc;
628
629 #ifdef DEBUG
630   fprintf(stderr, "getAFSServer: cell %s, cm_dnsEnabled=%d\n", cellName, cm_dnsEnabled);
631 #endif
632
633 #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
634   if (cm_dnsEnabled == -1) { /* not yet initialized, eg when called by klog */
635     cm_InitDNS(1);    /* assume enabled */
636   }
637 #endif
638   if (cm_dnsEnabled == 0) {  /* possibly we failed in cm_InitDNS above */
639     fprintf(stderr, "DNS initialization failed, disabled\n");
640     *numServers = 0;
641     return -1;
642   }
643   
644   sockAddr = setSockAddr(dns_addr, DNS_PORT);
645   
646   commSock = socket( AF_INET, SOCK_DGRAM, 0 );
647   if ( commSock < 0 )
648     {
649       /*afsi_log("socket() failed\n");*/
650       fprintf(stderr, "getAFSServer: socket() failed, errno=%d\n", errno);
651       *numServers = 0;
652       return (-1);
653     } 
654   
655   strncpy(query, cellName, 1024);
656   query[1023] = 0;
657   if (query[strlen(query)-1] != '.') {
658     strncat(query,".",1024);
659     query[1023] = 0;
660   }
661
662   rc = send_DNS_AFSDB_Query(cellName,commSock,sockAddr, buffer);
663   if (rc < 0) {
664     fprintf(stderr,"getAFSServer: send_DNS_AFSDB_Query failed\n");
665     *numServers = 0;
666     return -1;
667   }
668     
669   pDNShdr = get_DNS_Response(commSock,sockAddr, buffer);
670   
671   /*printReplyBuffer_AFSDB(pDNShdr);*/
672   if (pDNShdr)
673     processReplyBuffer_AFSDB(commSock, pDNShdr, cellHostAddrs, cellHostNames, numServers, ttl);
674   else
675     *numServers = 0;
676   
677   closesocket(commSock);
678   if (*numServers == 0)
679     return(-1);
680
681   else
682     return 0;
683 #else /* DNSAPI_ENV */
684     PDNS_RECORD pDnsCell, pDnsIter, pDnsVol,pDnsVolIter, pDnsCIter;
685     DWORD i;
686     struct sockaddr_in vlSockAddr;
687     char query[1024];
688
689     *numServers = 0; 
690     *ttl = 0;
691
692     /* query the AFSDB records of cell */
693     strncpy(query, cellName, 1024);
694     query[1023] = 0;
695     if (query[strlen(query)-1] != '.') {
696         strncat(query,".",1024);
697         query[1023] = 0;
698     }
699
700     if (DnsQuery_A(query, DNS_TYPE_AFSDB, DNS_QUERY_STANDARD, NULL, &pDnsCell, NULL) == ERROR_SUCCESS) {
701         memset((void*) &vlSockAddr, 0, sizeof(vlSockAddr));
702                 
703         /* go through the returned records */
704         for (pDnsIter = pDnsCell;pDnsIter; pDnsIter = pDnsIter->pNext) {
705             /* if we find an AFSDB record with Preference set to 1, we found a volserver */
706             if (pDnsIter->wType == DNS_TYPE_AFSDB && pDnsIter->Data.Afsdb.wPreference == 1) {
707                 strncpy(cellHostNames[*numServers], pDnsIter->Data.Afsdb.pNameExchange, MAXHOSTCHARS);
708                 cellHostNames[*numServers][MAXHOSTCHARS-1]='\0';
709                 (*numServers)++;
710                 
711                 if (!*ttl) 
712                     *ttl = pDnsIter->dwTtl;
713                 if (*numServers == AFSMAXCELLHOSTS) 
714                     break;
715             }
716         }
717
718         for (i=0;i<*numServers;i++) 
719             cellHostAddrs[i] = 0;
720
721         /* now check if there are any A records in the results */
722         for (pDnsIter = pDnsCell; pDnsIter; pDnsIter = pDnsIter->pNext) {
723             if(pDnsIter->wType == DNS_TYPE_A)
724                 /* check if its for one of the volservers */
725                 for (i=0;i<*numServers;i++)
726                     if(stricmp(pDnsIter->pName, cellHostNames[i]) == 0)
727                         cellHostAddrs[i] = pDnsIter->Data.A.IpAddress;
728         }       
729
730         for (i=0;i<*numServers;i++) {
731             /* if we don't have an IP yet, then we should try resolving the volserver hostname
732             in a separate query. */
733             if (!cellHostAddrs[i]) {
734                 if (DnsQuery_A(cellHostNames[i], DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &pDnsVol, NULL) == ERROR_SUCCESS) {
735                     for (pDnsVolIter = pDnsVol; pDnsVolIter; pDnsVolIter=pDnsVolIter->pNext) {
736                         /* if we get an A record, keep it */
737                         if (pDnsVolIter->wType == DNS_TYPE_A && stricmp(cellHostNames[i], pDnsVolIter->pName)==0) {
738                             cellHostAddrs[i] = pDnsVolIter->Data.A.IpAddress;
739                             break;
740                         }
741                         /* if we get a CNAME, look for a corresponding A record */
742                         if (pDnsVolIter->wType == DNS_TYPE_CNAME && stricmp(cellHostNames[i], pDnsVolIter->pName)==0) {
743                             for (pDnsCIter=pDnsVolIter; pDnsCIter; pDnsCIter=pDnsCIter->pNext) {
744                                 if (pDnsCIter->wType == DNS_TYPE_A && stricmp(pDnsVolIter->Data.CNAME.pNameHost, pDnsCIter->pName)==0) {
745                                     cellHostAddrs[i] = pDnsCIter->Data.A.IpAddress;
746                                     break;
747                                 }
748                             }
749                             if (cellHostAddrs[i]) 
750                                 break;
751                             /* TODO: if the additional section is missing, then do another lookup for the CNAME */
752                         }
753                     }
754                     /* we are done with the volserver lookup */
755                     DnsRecordListFree(pDnsVol, DnsFreeRecordListDeep);
756                 }
757             }
758         }
759         DnsRecordListFree(pDnsCell, DnsFreeRecordListDeep);
760     }
761
762     if ( *numServers > 0 )
763         return 0;
764     else        
765         return -1;
766 #endif /* DNSAPI_ENV */
767 }
768 #endif /* AFS_AFSDB_ENV */