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