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