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