e03c8a6992cf141e10e72317158a87fdab3d0f63
[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
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <roken.h>
13
14 #include <afs/stds.h>
15 #include <afs/cellconfig.h>
16 #include <windows.h>
17 #include <winsock2.h>
18 #include "cm_dns_private.h"
19 #include "cm_nls.h"
20 #include "cm_dns.h"
21 #include <lwp.h>
22 #include <afs/afsint.h>
23 #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500)
24 #include <windns.h>
25 #define DNSAPI_ENV
26 #endif
27 #include <errno.h>
28 #include <strsafe.h>
29
30 /*extern void afsi_log(char *pattern, ...);*/
31
32 static char dns_addr[30];
33 static int cm_dnsEnabled = -1;
34
35 void DNSlowerCase(char *str)
36 {
37     unsigned int i;
38
39     for (i=0; i<strlen(str); i++)
40         /*str[i] = tolower(str[i]);*/
41         if (str[i] >= 'A' && str[i] <= 'Z')
42             str[i] += 'a' - 'A';
43 }
44
45 int cm_InitDNS(int enabled)
46 {
47 #ifndef DNSAPI_ENV
48     char configpath[100];
49     int len;
50     int code;
51     char *addr;
52
53     if (!enabled) {
54         fprintf(stderr, "DNS support disabled\n");
55         cm_dnsEnabled = 0;
56         return 0;
57     }
58
59     /* First try AFS_NS environment var. */
60     addr = getenv("AFS_NS");
61     if (addr && inet_addr(addr) != -1) {
62         strcpy(dns_addr, addr);
63     } else {
64         /* Now check for the AFSDNS.INI file */
65         code = GetWindowsDirectory(configpath, sizeof(configpath));
66         if (code == 0 || code > sizeof(configpath)) return -1;
67         strcat(configpath, "\\afsdns.ini");
68
69         /* Currently we only get (and query) the first nameserver.  Getting
70         list of mult. nameservers should be easy to do. */
71         len = GetPrivateProfileString("AFS Domain Name Servers", "ns1", NULL,
72                                        dns_addr, sizeof(dns_addr),
73                                        configpath);
74
75         if (len == 0 || inet_addr(dns_addr) == -1) {
76             fprintf(stderr, "No valid name server addresses found, DNS lookup is "
77                      "disabled\n");
78             cm_dnsEnabled = 0;  /* failed */
79             return -1;     /* No name servers defined */
80         }
81         else
82             fprintf(stderr, "Found DNS server %s\n", dns_addr);
83     }
84 #endif /* DNSAPI_ENV */
85     cm_dnsEnabled = 1;
86     return 0;
87 }
88
89 #ifndef DNSAPI_ENV
90 SOCKADDR_IN setSockAddr(char *server, int port)
91 {
92   SOCKADDR_IN sockAddr;
93   int         addrLen = sizeof(SOCKADDR_IN);
94
95 #ifndef WIN32_LEAN_AND_MEAN
96   bzero(&sockAddr,addrLen);
97 #endif /*WIN32_LEAN_AND_MEAN*/
98   sockAddr.sin_family   = AF_INET;
99   sockAddr.sin_port     = htons( port );
100   sockAddr.sin_addr.s_addr = inet_addr( server );
101   /*inet_aton(server, &sockAddr.sin_addr.s_addr);*/
102
103   return (sockAddr);
104 }
105
106 int getRRCount(PDNS_HDR ptr)
107 {
108   return(ntohs(ptr->rr_count));
109 }
110
111
112 int send_DNS_Addr_Query(char* query,
113                          SOCKET commSock, SOCKADDR_IN sockAddr, char *buffer)
114 {
115   PDNS_HDR    pDNShdr;
116   PDNS_QTAIL  pDNS_qtail;
117
118   int     queryLen = 0;
119   int     res;
120
121 #ifndef WIN32_LEAN_AND_MEAN
122   bzero(buffer,BUFSIZE);
123 #endif /*WIN32_LEAN_AND_MEAN*/
124
125   /*********************************
126    * Build DNS Query Message       *
127    *                               *
128    * hard-coded Adrress (A) query  *
129    *********************************/
130
131   pDNShdr = (PDNS_HDR)&( buffer[ 0 ] );
132   pDNShdr->id         = htons( 0xDADE );
133   pDNShdr->flags      = htons( DNS_FLAG_RD ); /* do recurse */
134   pDNShdr->q_count    = htons( 1 );           /* one query */
135   pDNShdr->rr_count   = 0;                    /* none in query */
136   pDNShdr->auth_count = 0;                    /* none in query */
137   pDNShdr->add_count  = 0;                    /* none in query */
138
139   queryLen = putQName( query, &(buffer[ DNS_HDR_LEN ] ) );
140   queryLen += DNS_HDR_LEN; /* query Length is just after the query name and header */
141 #ifdef DEBUG
142   fprintf(stderr, "send_DNS_Addr: query=%s, queryLen=%d\n", query, queryLen);
143 #endif
144
145
146   pDNS_qtail = (PDNS_QTAIL) &(buffer[ queryLen ]);
147   pDNS_qtail->qtype = htons(255);/*htons(DNS_RRTYPE_A); */
148   pDNS_qtail->qclass = htons(DNS_RRCLASS_IN);
149   queryLen +=  DNS_QTAIL_LEN;
150
151   /**************************
152    * Send DNS Query Message *
153    **************************/
154
155
156   res = sendto( commSock,
157                 buffer,
158                 queryLen,
159                 0,
160                 (struct sockaddr *) &sockAddr,
161                 sizeof( SOCKADDR_IN ) );
162
163   /*dumpSbuffer(buffer,queryLen);*/
164
165   if ( res < 0 )
166     {
167 #ifdef DEBUG
168       fprintf(stderr, "send_DNS_Addr_Query: error %d, errno %d\n", res, errno);
169       fprintf(stderr, "sendto() failed \n");
170 #endif
171       return ( -1 );
172     }
173   else
174     {
175     /*printf( "sendto() succeeded\n");*/
176     ;
177     } /* end if */
178
179   return(0);
180 }
181
182
183 int send_DNS_AFSDB_Query(char* query,
184                          SOCKET commSock, SOCKADDR_IN sockAddr, char *buffer)
185 {
186   /*static char buffer[BUFSIZE];*/
187
188   PDNS_HDR    pDNShdr;
189   PDNS_QTAIL  pDNS_qtail;
190
191   int     queryLen = 0;
192   int     res;
193
194 #ifndef WIN32_LEAN_AND_MEAN
195   bzero(buffer,BUFSIZE);
196 #endif /*WIN32_LEAN_AND_MEAN*/
197
198   /***************************
199    * Build DNS Query Message *
200    *                         *
201    * hard-coded AFSDB query  *
202    ***************************/
203
204   pDNShdr = (PDNS_HDR)&( buffer[ 0 ] );
205   pDNShdr->id         = htons( 0xDEAD );
206   pDNShdr->flags      = htons( DNS_FLAG_RD ); /* do recurse */
207   pDNShdr->q_count    = htons( 1 );           /* one query */
208   pDNShdr->rr_count   = 0;                    /* none in query */
209   pDNShdr->auth_count = 0;                    /* none in query */
210   pDNShdr->add_count  = 0;                    /* none in query */
211
212   queryLen = putQName( query, &(buffer[ DNS_HDR_LEN ] ) );
213   queryLen += DNS_HDR_LEN; /* query Length is just after the query name and header */
214
215
216   pDNS_qtail = (PDNS_QTAIL) &(buffer[ queryLen ]);
217   pDNS_qtail->qtype = htons(DNS_RRTYPE_AFSDB);
218   pDNS_qtail->qclass = htons(DNS_RRCLASS_IN);
219   queryLen +=  DNS_QTAIL_LEN;
220
221   /**************************
222    * Send DNS Query Message *
223    **************************/
224
225   res = sendto( commSock,
226                 buffer,
227                 queryLen,
228                 0,
229                 (struct sockaddr *) &sockAddr,
230                 sizeof( SOCKADDR_IN ) );
231
232   /*dumpSbuffer(buffer,queryLen);*/
233
234   if ( res < 0 )
235     {
236 #ifdef DEBUG
237       fprintf(stderr, "send_DNS_AFSDB_Query: error %d, errno %d\n", res, errno);
238       fprintf(stderr,  "sendto() failed \n");
239 #endif /* DEBUG */
240       return ( -1 );
241     }
242   else
243     {
244     /*printf( "sendto() succeeded\n");*/
245     ;
246     } /* end if */
247
248   return(0);
249 }
250
251
252 PDNS_HDR get_DNS_Response(SOCKET commSock, SOCKADDR_IN sockAddr, char *buffer)
253 {
254   /*static char buffer[BUFSIZE];*/
255
256   int         addrLen = sizeof(SOCKADDR_IN);
257   int size;
258
259 #ifndef WIN32_LEAN_AND_MEAN
260   bzero(buffer,BUFSIZE);
261 #endif /*WIN32_LEAN_AND_MEAN*/
262
263   /*****************************
264    * Receive DNS Reply Message *
265    *****************************/
266
267   /*printf( "calling recvfrom() on connected UDP socket\n" );*/
268
269   size = recvfrom( commSock,
270                   buffer,
271                   BUFSIZE,
272                   0,
273                   (struct sockaddr *) &sockAddr,
274                   &addrLen );
275   if (size < 0) { fprintf(stderr, "recvfrom error %d\n", errno); return NULL; }
276
277   /*dumpRbuffer(buffer,res);*/
278
279 #ifdef DEBUG
280   fprintf(stderr, "recvfrom returned %d bytes from %s: \n",
281           size, inet_ntoa( sockAddr.sin_addr ) );
282 #endif /* DEBUG */
283
284   return((PDNS_HDR)&( buffer[ 0 ] ));
285
286 }
287
288
289 int putQName( char *pHostName, char *pQName )
290 {
291   int     i;
292   char    c;
293   int     j = 0;
294   int     k = 0;
295
296   DNSlowerCase(pHostName);
297   /*printf( "Hostname: [%s]\n", pHostName );*/
298
299   for ( i = 0; *( pHostName + i ); i++ )
300     {
301       c = *( pHostName + i );   /* get next character */
302
303
304       if ( c == '.' )
305         {
306           /* dot encountered, fill in previous length */
307           if (k!=0){ /*don't process repeated dots*/
308           /*printf( "%c", c );*/
309             *( pQName + j ) = k;
310             j = j+k+1;  /* set index to next counter */
311             k = 0;      /* reset segment length */
312           }
313         }
314       else
315         {
316         /*printf( "%c", c );*/
317           *( pQName + j + k + 1 ) = c;  /* assign to QName */
318           k++;                /* inc count of seg chars */
319         } /* end if */
320     } /* end for loop */
321
322   *(pQName + j )                  = k;   /* count for final segment */
323
324   *(pQName + j + k + 1 )      = 0;   /* count for trailing NULL segment is 0 */
325
326   /*printf( "\n" ); */
327
328   if (c == '.')
329     return ( j + k + 1 );        /* return total length of QName */
330   else
331     return ( j + k + 2 );
332 } /* end putQName() */
333
334
335 u_char * skipRRQName(u_char *pQName)
336 {
337   u_char *ptr;
338   u_char c;
339
340   ptr = pQName;
341   c = *ptr;
342   while (c) {
343     if ( c >= 0xC0 ) {
344     /* skip the 'compression' pointer */
345       ptr = ptr+1;
346       c = '\0';
347     } else {
348       /* skip a normal qname segment */
349       ptr += *ptr;
350       ptr++;
351       c = *ptr;
352     };
353   };
354
355   /* ptr now pointing at terminating zero of query QName,
356      or the pointer for the previous occurrence
357      (compression)
358    */
359   ptr++;
360
361   return (ptr);
362 } /* end skipRRQName() */
363
364
365
366 u_char * printRRQName( u_char *pQName, PDNS_HDR buffer )
367 {
368   u_short i, k;
369   u_char *buffPtr = (u_char *) buffer;
370   u_char *namePtr;
371   u_char *retPtr;
372   u_char c;
373
374
375   namePtr = pQName;
376   retPtr = 0;
377
378   for ( i = 0; i < BUFSIZE; i++ )
379     {
380       c = *namePtr;
381       if ( c >= 0xC0 ) {
382         c = *(namePtr + 1);
383         retPtr = namePtr+2;
384         namePtr = buffPtr+c;
385       } else {
386         if ( c == 0 )
387           break;
388
389         for ( k = 1; k <= c; k++ )
390           {
391             fprintf(stderr, "%c", *( namePtr + k ) );
392           } /* end for loop */
393         fprintf(stderr,".");
394         namePtr += k;
395       }
396     } /* end for loop */
397   fprintf(stderr,"\n");
398   namePtr++; /* skip terminating zero */
399
400   if (retPtr)
401     return(retPtr);
402   else
403     return(namePtr);
404
405 } /* end printRRQName() */
406
407
408 u_char * sPrintRRQName( u_char *pQName, PDNS_HDR buffer, char *str )
409 {
410   u_short i, k;
411   u_char *buffPtr = (u_char *) buffer;
412   u_char *namePtr;
413   u_char *retPtr;
414   u_char c;
415
416   char   section[64];
417
418   strcpy(str,"");
419   namePtr = pQName;
420   retPtr = 0;
421
422   for ( i = 0; i < BUFSIZE; i++ )
423     {
424       c = *namePtr;
425       if ( c >= 0xC0 ) {
426         c = *(namePtr + 1);
427         retPtr = namePtr+2;
428         namePtr = buffPtr+c;
429       } else {
430         if ( c == 0 )
431           break;
432
433         for ( k = 1; k <= c; k++ )
434           {
435             sprintf(section,"%c", *( namePtr + k ) );
436             strcat(str,section);
437           } /* end for loop */
438         strcat(str,".");
439         namePtr += k;
440       }
441     } /* end for loop */
442   namePtr++; /* skip terminating zero */
443
444   if (retPtr)
445     return(retPtr);
446   else
447     return(namePtr);
448
449 } /* end sPrintRRQName() */
450
451
452 void printReplyBuffer_AFSDB(PDNS_HDR replyBuff)
453 {
454   u_char *ptr = (u_char *) replyBuff;
455   int    answerCount = ntohs((replyBuff)->rr_count);
456   u_char i;
457   PDNS_AFSDB_RR_HDR
458          rrPtr;
459
460   ptr += DNS_HDR_LEN;
461
462   /* ptr now pointing at start of QName in query field */
463   ptr = skipRRQName(ptr);
464
465
466   /* skip the query type and class fields */
467   ptr+= DNS_QTAIL_LEN;
468
469   /* ptr should now be at the start of the answer RR sections */
470
471   fprintf(stderr,"---------------------------------\n");
472   for (i=0; i<answerCount ; i++){
473     ptr = skipRRQName(ptr);
474     rrPtr = (PDNS_AFSDB_RR_HDR) ptr;
475     ptr+= DNS_AFSDB_RR_HDR_LEN;
476     if ( ntohs(rrPtr->rr_afsdb_class) == 1) {
477       fprintf(stderr,"AFDB class %d ->  ",ntohs(rrPtr->rr_afsdb_class));
478       ptr = printRRQName(ptr,replyBuff); }
479     else
480       ptr = skipRRQName(ptr);
481   };
482   fprintf(stderr,"---------------------------------\n");
483
484
485 };
486
487 void processReplyBuffer_AFSDB(SOCKET commSock, PDNS_HDR replyBuff, int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS],
488                               unsigned short ports[], unsigned short ipRanks[], int *numServers, int *ttl)
489   /*PAFS_SRV_LIST (srvList)*/
490 {
491   u_char *ptr = (u_char *) replyBuff;
492   int    answerCount = ntohs((replyBuff)->rr_count);
493   u_char i;
494   PDNS_AFSDB_RR_HDR
495          rrPtr;
496   int srvCount = 0;
497   char hostName[256];
498   struct in_addr addr;
499   int rc;
500
501   ptr += DNS_HDR_LEN;
502
503   /* ptr now pointing at start of QName in query field */
504   ptr = skipRRQName(ptr);
505
506
507   /* skip the query type and class fields */
508   ptr+= DNS_QTAIL_LEN;
509
510   /* ptr should now be at the start of the answer RR sections */
511
512   answerCount = min(answerCount, AFSMAXCELLHOSTS);
513 #ifdef DEBUG
514   fprintf(stderr, "processRep_AFSDB: answerCount=%d\n", answerCount);
515 #endif /* DEBUG */
516
517   for (i=0; i<answerCount ; i++){
518     ptr = skipRRQName(ptr);
519     rrPtr = (PDNS_AFSDB_RR_HDR) ptr;
520     ptr+= DNS_AFSDB_RR_HDR_LEN;
521     if ((ntohs(rrPtr->rr_afsdb_class) == 1) &&
522         (srvCount < MAX_AFS_SRVS)) {
523       /*ptr = sPrintRRQName(ptr,replyBuff,srvList->host[srvList->count]);*/
524       ptr = sPrintRRQName(ptr,replyBuff,hostName);
525       /*ptr = printRRQName(ptr,replyBuff);*/
526       *ttl = ntohl(rrPtr->rr_ttl);
527
528 #ifdef DEBUG
529       fprintf(stderr, "resolving name %s\n", hostName);
530 #endif
531       /* resolve name from DNS query */
532       rc = DNSgetAddr(commSock, hostName, &addr);
533       if (rc < 0)
534         continue;  /* skip this entry */
535 #ifdef DEBUG
536       fprintf(stderr, "processRep_AFSDB: resolved name %s to addr %x\n", hostName, addr);
537 #endif /* DEBUG */
538       memcpy(&cellHostAddrs[srvCount], &addr.s_addr, sizeof(addr.s_addr));
539           strncpy(cellHostNames[srvCount], hostName, CELL_MAXNAMELEN);
540           cellHostNames[srvCount][CELL_MAXNAMELEN-1] = '\0';
541       ipRanks[srvCount] = 0;
542       ports[srvCount] = htons(7003);
543       srvCount++;
544     }
545     else {
546       ptr = skipRRQName(ptr);
547     }
548   }
549
550   *numServers = srvCount;
551
552 }
553
554
555 u_char * processReplyBuffer_Addr(PDNS_HDR replyBuff)
556 {
557   u_char *ptr = (u_char *) replyBuff;
558   int    answerCount = ntohs((replyBuff)->rr_count);
559   PDNS_A_RR_HDR
560          rrPtr;
561
562 #ifdef DEBUG
563   fprintf(stderr, "processReplyBuffer_Addr: answerCount=%d\n", answerCount);
564 #endif /* DEBUG */
565   if (answerCount == 0) return 0;
566
567   ptr += DNS_HDR_LEN;
568
569   /* ptr now pointing at start of QName in query field */
570   ptr = skipRRQName(ptr);
571
572
573   /* skip the query type and class fields */
574   ptr+= DNS_QTAIL_LEN;
575
576   /* ptr should now be at the start of the answer RR sections */
577   ptr = skipRRQName(ptr);
578   rrPtr = (PDNS_A_RR_HDR) ptr;
579
580 #ifdef DEBUG
581   fprintf(stderr, "type:%d, class:%d, ttl:%d, rdlength:%d\n",
582          ntohs(rrPtr->rr_type),ntohs(rrPtr->rr_class),
583          ntohl(rrPtr->rr_ttl),ntohs(rrPtr->rr_rdlength));
584   fprintf(stderr, "Count %d\tand Answer %8x\n",answerCount,rrPtr->rr_addr);
585 #endif /* DEBUG */
586
587   ptr += DNS_A_RR_HDR_LEN;
588
589   return (ptr);
590
591 };
592
593 int DNSgetAddr(SOCKET commSock, char *hostName, struct in_addr *iNet)
594 {
595   /* Variables for DNS message parsing and creation */
596   PDNS_HDR  pDNShdr;
597
598   SOCKADDR_IN sockAddr;
599   char buffer[BUFSIZE];
600   u_char *addr;
601   u_long *aPtr;
602   int rc;
603
604   /**********************
605    * Get a DGRAM socket *
606    **********************/
607
608   sockAddr = setSockAddr(dns_addr, DNS_PORT);
609
610   rc = send_DNS_Addr_Query(hostName,commSock,sockAddr, buffer);
611   if (rc < 0) return rc;
612   pDNShdr = get_DNS_Response(commSock,sockAddr, buffer);
613   if (pDNShdr == NULL)
614     return -1;
615
616   addr = processReplyBuffer_Addr(pDNShdr);
617   if (addr == 0)
618     return -1;
619
620   aPtr = (u_long *) addr;
621
622   iNet->s_addr = *aPtr;
623
624   return(0);
625 }
626 #endif /* DNSAPI_ENV */
627
628 int getAFSServer(const char *service, const char *protocol, const char *cellName,
629                  unsigned short afsdbPort,  /* network byte order */
630                  int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS],
631                  unsigned short ports[],    /* network byte order */
632                  unsigned short ipRanks[],
633                  int *numServers, int *ttl)
634 {
635 #ifndef DNSAPI_ENV
636     SOCKET commSock;
637     SOCKADDR_IN sockAddr;
638     PDNS_HDR  pDNShdr;
639     char buffer[BUFSIZE];
640     char query[1024];
641     int rc;
642
643 #ifdef DEBUG
644     fprintf(stderr, "getAFSServer: cell %s, cm_dnsEnabled=%d\n", cellName, cm_dnsEnabled);
645 #endif
646
647     *numServers = 0;
648     *ttl = 0;
649
650 #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
651     if (cm_dnsEnabled == -1) { /* not yet initialized, eg when called by klog */
652         cm_InitDNS(1);         /* assume enabled */
653     }
654 #endif
655     if (cm_dnsEnabled == 0) {  /* possibly we failed in cm_InitDNS above */
656         fprintf(stderr, "DNS initialization failed, disabled\n");
657         return -1;
658     }
659
660     if (service == NULL || protocol == NULL || cellName == NULL) {
661         fprintf(stderr, "invalid input\n");
662         return -1;
663     }
664
665     sockAddr = setSockAddr(dns_addr, DNS_PORT);
666
667     commSock = socket( AF_INET, SOCK_DGRAM, 0 );
668     if ( commSock < 0 )
669     {
670         /*afsi_log("socket() failed\n");*/
671         fprintf(stderr, "getAFSServer: socket() failed, errno=%d\n", errno);
672         return (-1);
673     }
674
675     StringCbCopyA(query, sizeof(query), cellName);
676     if (query[strlen(query)-1] != '.') {
677         StringCbCatA(query, sizeof(query), ".");
678     }
679
680     rc = send_DNS_AFSDB_Query(query,commSock,sockAddr, buffer);
681     if (rc < 0) {
682         closesocket(commSock);
683         fprintf(stderr,"getAFSServer: send_DNS_AFSDB_Query failed\n");
684         return -1;
685     }
686
687     pDNShdr = get_DNS_Response(commSock,sockAddr, buffer);
688
689     /*printReplyBuffer_AFSDB(pDNShdr);*/
690     if (pDNShdr)
691         processReplyBuffer_AFSDB(commSock, pDNShdr, cellHostAddrs, cellHostNames, ports, ipRanks, numServers, ttl);
692
693     closesocket(commSock);
694     if (*numServers == 0)
695         return(-1);
696     else
697         return 0;
698 #else /* DNSAPI_ENV */
699     PDNS_RECORD pDnsCell, pDnsIter, pDnsVol, pDnsVolIter, pDnsCIter;
700     int i;
701     char query[1024];
702
703     *numServers = 0;
704     *ttl = 0;
705
706     if (service == NULL || protocol == NULL || cellName == NULL)
707         return -1;
708
709 #ifdef AFS_FREELANCE_CLIENT
710     if ( cm_stricmp_utf8N(cellName, "Freelance.Local.Root") == 0 )
711         return -1;
712 #endif /* AFS_FREELANCE_CLIENT */
713
714     /* query the SRV _afs3-vlserver._udp records of cell */
715     StringCbPrintf(query, sizeof(query), "_%s._%s.%s", service, protocol, cellName);
716     if (query[strlen(query)-1] != '.') {
717         StringCbCatA(query, sizeof(query), ".");
718     }
719
720     if (DnsQuery_A(query, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &pDnsCell, NULL) == ERROR_SUCCESS) {
721         /* go through the returned records */
722         for (pDnsIter = pDnsCell;pDnsIter; pDnsIter = pDnsIter->pNext) {
723             /* if we find an SRV record, we found the service */
724             if (pDnsIter->wType == DNS_TYPE_SRV) {
725                 StringCbCopyA(cellHostNames[*numServers], sizeof(cellHostNames[*numServers]),
726                               pDnsIter->Data.SRV.pNameTarget);
727                 ipRanks[*numServers] = pDnsIter->Data.SRV.wPriority;
728                 ports[*numServers] = htons(pDnsIter->Data.SRV.wPort);
729                 (*numServers)++;
730
731                 if (!*ttl)
732                     *ttl = pDnsIter->dwTtl;
733                 if (*numServers == AFSMAXCELLHOSTS)
734                     break;
735             }
736         }
737
738         for (i=0;i<*numServers;i++)
739             cellHostAddrs[i] = 0;
740
741         /* now check if there are any A records in the results */
742         for (pDnsIter = pDnsCell; pDnsIter; pDnsIter = pDnsIter->pNext) {
743             if(pDnsIter->wType == DNS_TYPE_A)
744                 /* check if its for one of the service */
745                 for (i=0;i<*numServers;i++)
746                     if(cm_stricmp_utf8(pDnsIter->pName, cellHostNames[i]) == 0)
747                         cellHostAddrs[i] = pDnsIter->Data.A.IpAddress;
748         }
749
750         for (i=0;i<*numServers;i++) {
751             /* if we don't have an IP yet, then we should try resolving the afs3-vlserver hostname
752             in a separate query. */
753             if (!cellHostAddrs[i]) {
754                 if (DnsQuery_A(cellHostNames[i], DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &pDnsVol, NULL) == ERROR_SUCCESS) {
755                     for (pDnsVolIter = pDnsVol; pDnsVolIter; pDnsVolIter=pDnsVolIter->pNext) {
756                         /* if we get an A record, keep it */
757                         if (pDnsVolIter->wType == DNS_TYPE_A && cm_stricmp_utf8(cellHostNames[i], pDnsVolIter->pName)==0) {
758                             cellHostAddrs[i] = pDnsVolIter->Data.A.IpAddress;
759                             break;
760                         }
761                         /* if we get a CNAME, look for a corresponding A record */
762                         if (pDnsVolIter->wType == DNS_TYPE_CNAME && cm_stricmp_utf8(cellHostNames[i], pDnsVolIter->pName)==0) {
763                             for (pDnsCIter=pDnsVolIter; pDnsCIter; pDnsCIter=pDnsCIter->pNext) {
764                                 if (pDnsCIter->wType == DNS_TYPE_A && cm_stricmp_utf8(pDnsVolIter->Data.CNAME.pNameHost, pDnsCIter->pName)==0) {
765                                     cellHostAddrs[i] = pDnsCIter->Data.A.IpAddress;
766                                     break;
767                                 }
768                             }
769                             if (cellHostAddrs[i])
770                                 break;
771                             /* TODO: if the additional section is missing, then do another lookup for the CNAME */
772                         }
773                     }
774                     /* we are done with the service lookup */
775                     DnsRecordListFree(pDnsVol, DnsFreeRecordListDeep);
776                 }
777             }
778         }
779         DnsRecordListFree(pDnsCell, DnsFreeRecordListDeep);
780     }
781     else {
782         /* query the AFSDB records of cell */
783         StringCbCopyA(query, sizeof(query), cellName);
784         if (query[strlen(query)-1] != '.') {
785             StringCbCatA(query, sizeof(query), ".");
786         }
787
788         if (DnsQuery_A(query, DNS_TYPE_AFSDB, DNS_QUERY_STANDARD, NULL, &pDnsCell, NULL) == ERROR_SUCCESS) {
789             /* go through the returned records */
790             for (pDnsIter = pDnsCell;pDnsIter; pDnsIter = pDnsIter->pNext) {
791                 /* if we find an AFSDB record with Preference set to 1, we found a service instance */
792                 if (pDnsIter->wType == DNS_TYPE_AFSDB && pDnsIter->Data.Afsdb.wPreference == 1) {
793                     StringCbCopyA(cellHostNames[*numServers], sizeof(cellHostNames[*numServers]),
794                                    pDnsIter->Data.Afsdb.pNameExchange);
795                     ipRanks[*numServers] = 0;
796                     ports[*numServers] = afsdbPort;
797                     (*numServers)++;
798
799                     if (!*ttl)
800                         *ttl = pDnsIter->dwTtl;
801                     if (*numServers == AFSMAXCELLHOSTS)
802                         break;
803                 }
804             }
805
806             for (i=0;i<*numServers;i++)
807                 cellHostAddrs[i] = 0;
808
809             /* now check if there are any A records in the results */
810             for (pDnsIter = pDnsCell; pDnsIter; pDnsIter = pDnsIter->pNext) {
811                 if(pDnsIter->wType == DNS_TYPE_A)
812                     /* check if its for one of the service */
813                     for (i=0;i<*numServers;i++)
814                         if(cm_stricmp_utf8(pDnsIter->pName, cellHostNames[i]) == 0)
815                             cellHostAddrs[i] = pDnsIter->Data.A.IpAddress;
816             }
817
818             for (i=0;i<*numServers;i++) {
819                 /* if we don't have an IP yet, then we should try resolving the service hostname
820                 in a separate query. */
821                 if (!cellHostAddrs[i]) {
822                     if (DnsQuery_A(cellHostNames[i], DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &pDnsVol, NULL) == ERROR_SUCCESS) {
823                         for (pDnsVolIter = pDnsVol; pDnsVolIter; pDnsVolIter=pDnsVolIter->pNext) {
824                             /* if we get an A record, keep it */
825                             if (pDnsVolIter->wType == DNS_TYPE_A && cm_stricmp_utf8(cellHostNames[i], pDnsVolIter->pName)==0) {
826                                 cellHostAddrs[i] = pDnsVolIter->Data.A.IpAddress;
827                                 break;
828                             }
829                             /* if we get a CNAME, look for a corresponding A record */
830                             if (pDnsVolIter->wType == DNS_TYPE_CNAME && cm_stricmp_utf8(cellHostNames[i], pDnsVolIter->pName)==0) {
831                                 for (pDnsCIter=pDnsVolIter; pDnsCIter; pDnsCIter=pDnsCIter->pNext) {
832                                     if (pDnsCIter->wType == DNS_TYPE_A && cm_stricmp_utf8(pDnsVolIter->Data.CNAME.pNameHost, pDnsCIter->pName)==0) {
833                                         cellHostAddrs[i] = pDnsCIter->Data.A.IpAddress;
834                                         break;
835                                     }
836                                 }
837                                 if (cellHostAddrs[i])
838                                     break;
839                                 /* TODO: if the additional section is missing, then do another lookup for the CNAME */
840                             }
841                         }
842                         /* we are done with the service lookup */
843                         DnsRecordListFree(pDnsVol, DnsFreeRecordListDeep);
844                     }
845                 }
846             }
847             DnsRecordListFree(pDnsCell, DnsFreeRecordListDeep);
848         }
849     }
850
851     if ( *numServers > 0 )
852         return 0;
853     else
854         return -1;
855 #endif /* DNSAPI_ENV */
856 }
857
858 int getAFSServerW(const cm_unichar_t *service, const cm_unichar_t *protocol, const cm_unichar_t *cellName,
859                   unsigned short afsdbPort, /* network byte order */
860                   int *cellHostAddrs,
861                   cm_unichar_t cellHostNames[][MAXHOSTCHARS],
862                   unsigned short ports[],   /* network byte order */
863                   unsigned short ipRanks[],
864                   int *numServers, int *ttl)
865 {
866 #ifdef DNSAPI_ENV
867     PDNS_RECORDW pDnsCell, pDnsIter, pDnsVol,pDnsVolIter, pDnsCIter;
868     int i;
869     cm_unichar_t query[1024];
870
871     *numServers = 0;
872     *ttl = 0;
873
874     if (service == NULL || protocol == NULL || cellName == NULL)
875         return -1;
876
877 #ifdef AFS_FREELANCE_CLIENT
878     if ( cm_stricmp_utf16(cellName, L"Freelance.Local.Root") == 0 )
879         return -1;
880 #endif /* AFS_FREELANCE_CLIENT */
881
882     /* query the SRV _afs3-vlserver._udp records of cell */
883     StringCbPrintfW(query, sizeof(query), L"_%S._%S.%S", service, protocol, cellName);
884     if (query[wcslen(query)-1] != L'.') {
885         StringCbCatW(query, sizeof(query), L".");
886     }
887
888     if (DnsQuery_W(query, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, (PDNS_RECORD *) &pDnsCell,
889                    NULL) == ERROR_SUCCESS) {
890         /* go through the returned records */
891         for (pDnsIter = pDnsCell; pDnsIter; pDnsIter = pDnsIter->pNext) {
892             /* if we find an SRV record, we found a service instance */
893             if (pDnsIter->wType == DNS_TYPE_SRV) {
894                 StringCbCopyW(cellHostNames[*numServers], sizeof(cellHostNames[*numServers]),
895                               pDnsIter->Data.SRV.pNameTarget);
896                 ipRanks[*numServers] = pDnsIter->Data.SRV.wPriority;
897                 ports[*numServers] = htons(pDnsIter->Data.SRV.wPort);
898                 (*numServers)++;
899
900                 if (!*ttl)
901                     *ttl = pDnsIter->dwTtl;
902                 if (*numServers == AFSMAXCELLHOSTS)
903                     break;
904             }
905         }
906
907         for (i=0;i<*numServers;i++)
908             cellHostAddrs[i] = 0;
909
910         /* now check if there are any A records in the results */
911         for (pDnsIter = pDnsCell; pDnsIter; pDnsIter = pDnsIter->pNext) {
912             if(pDnsIter->wType == DNS_TYPE_A)
913                 /* check if its for one of the service instances */
914                 for (i=0;i<*numServers;i++)
915                     if(cm_stricmp_utf16(pDnsIter->pName, cellHostNames[i]) == 0)
916                         cellHostAddrs[i] = pDnsIter->Data.A.IpAddress;
917         }
918
919         for (i=0;i<*numServers;i++) {
920             /* if we don't have an IP yet, then we should try resolving the service hostname
921             in a separate query. */
922             if (!cellHostAddrs[i]) {
923                 if (DnsQuery_W(cellHostNames[i], DNS_TYPE_A, DNS_QUERY_STANDARD, NULL,
924                                (PDNS_RECORD *) &pDnsVol, NULL) == ERROR_SUCCESS) {
925                     for (pDnsVolIter = pDnsVol; pDnsVolIter; pDnsVolIter=pDnsVolIter->pNext) {
926                         /* if we get an A record, keep it */
927                         if (pDnsVolIter->wType == DNS_TYPE_A && cm_stricmp_utf16(cellHostNames[i], pDnsVolIter->pName)==0) {
928                             cellHostAddrs[i] = pDnsVolIter->Data.A.IpAddress;
929                             break;
930                         }
931                         /* if we get a CNAME, look for a corresponding A record */
932                         if (pDnsVolIter->wType == DNS_TYPE_CNAME && cm_stricmp_utf16(cellHostNames[i], pDnsVolIter->pName)==0) {
933                             for (pDnsCIter=pDnsVolIter; pDnsCIter; pDnsCIter=pDnsCIter->pNext) {
934                                 if (pDnsCIter->wType == DNS_TYPE_A && cm_stricmp_utf16(pDnsVolIter->Data.CNAME.pNameHost, pDnsCIter->pName)==0) {
935                                     cellHostAddrs[i] = pDnsCIter->Data.A.IpAddress;
936                                     break;
937                                 }
938                             }
939                             if (cellHostAddrs[i])
940                                 break;
941                             /* TODO: if the additional section is missing, then do another lookup for the CNAME */
942                         }
943                     }
944                     /* we are done with the service lookup */
945                     DnsRecordListFree((PDNS_RECORD) pDnsVol, DnsFreeRecordListDeep);
946                 }
947             }
948         }
949         DnsRecordListFree((PDNS_RECORD) pDnsCell, DnsFreeRecordListDeep);
950     }
951     else {
952         /* query the AFSDB records of cell */
953         StringCbCopyW(query, sizeof(query), cellName);
954         if (query[wcslen(query)-1] != L'.') {
955             StringCbCatW(query, sizeof(query), L".");
956         }
957
958         if (DnsQuery_W(query, DNS_TYPE_AFSDB, DNS_QUERY_STANDARD, NULL, (PDNS_RECORD *) &pDnsCell,
959                        NULL) == ERROR_SUCCESS) {
960             /* go through the returned records */
961             for (pDnsIter = pDnsCell;pDnsIter; pDnsIter = pDnsIter->pNext) {
962                 /* if we find an AFSDB record with Preference set to 1, we found a service instance */
963                 if (pDnsIter->wType == DNS_TYPE_AFSDB && pDnsIter->Data.Afsdb.wPreference == 1) {
964                     StringCbCopyW(cellHostNames[*numServers], sizeof(cellHostNames[*numServers]),
965                                   pDnsIter->Data.Afsdb.pNameExchange);
966                     ipRanks[*numServers] = 0;
967                     ports[*numServers] = afsdbPort;
968                     (*numServers)++;
969
970                     if (!*ttl)
971                         *ttl = pDnsIter->dwTtl;
972                     if (*numServers == AFSMAXCELLHOSTS)
973                         break;
974                 }
975             }
976
977             for (i=0;i<*numServers;i++)
978                 cellHostAddrs[i] = 0;
979
980             /* now check if there are any A records in the results */
981             for (pDnsIter = pDnsCell; pDnsIter; pDnsIter = pDnsIter->pNext) {
982                 if(pDnsIter->wType == DNS_TYPE_A)
983                     /* check if its for one of the service instances */
984                     for (i=0;i<*numServers;i++)
985                         if(cm_stricmp_utf16(pDnsIter->pName, cellHostNames[i]) == 0)
986                             cellHostAddrs[i] = pDnsIter->Data.A.IpAddress;
987             }
988
989             for (i=0;i<*numServers;i++) {
990                 /* if we don't have an IP yet, then we should try resolving the service hostname
991                 in a separate query. */
992                 if (!cellHostAddrs[i]) {
993                     if (DnsQuery_W(cellHostNames[i], DNS_TYPE_A, DNS_QUERY_STANDARD, NULL,
994                                    (PDNS_RECORD *) &pDnsVol, NULL) == ERROR_SUCCESS) {
995                         for (pDnsVolIter = pDnsVol; pDnsVolIter; pDnsVolIter=pDnsVolIter->pNext) {
996                             /* if we get an A record, keep it */
997                             if (pDnsVolIter->wType == DNS_TYPE_A && cm_stricmp_utf16(cellHostNames[i], pDnsVolIter->pName)==0) {
998                                 cellHostAddrs[i] = pDnsVolIter->Data.A.IpAddress;
999                                 break;
1000                             }
1001                             /* if we get a CNAME, look for a corresponding A record */
1002                             if (pDnsVolIter->wType == DNS_TYPE_CNAME && cm_stricmp_utf16(cellHostNames[i], pDnsVolIter->pName)==0) {
1003                                 for (pDnsCIter=pDnsVolIter; pDnsCIter; pDnsCIter=pDnsCIter->pNext) {
1004                                     if (pDnsCIter->wType == DNS_TYPE_A && cm_stricmp_utf16(pDnsVolIter->Data.CNAME.pNameHost, pDnsCIter->pName)==0) {
1005                                         cellHostAddrs[i] = pDnsCIter->Data.A.IpAddress;
1006                                         break;
1007                                     }
1008                                 }
1009                                 if (cellHostAddrs[i])
1010                                     break;
1011                                 /* TODO: if the additional section is missing, then do another lookup for the CNAME */
1012                             }
1013                         }
1014                         /* we are done with the service lookup */
1015                         DnsRecordListFree((PDNS_RECORD) pDnsVol, DnsFreeRecordListDeep);
1016                     }
1017                 }
1018             }
1019             DnsRecordListFree((PDNS_RECORD) pDnsCell, DnsFreeRecordListDeep);
1020         }
1021     }
1022
1023     if ( *numServers > 0 )
1024         return 0;
1025     else
1026 #endif  /* DNSAPI_ENV */
1027         return -1;
1028 }
1029