1 /* Copyright 2000, International Business Machines Corporation and others.
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
11 #include <afs/param.h>
13 #include <afs/cellconfig.h>
18 #include "cm_dns_private.h"
21 #include <afs/afsint.h>
22 #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500)
27 /*extern void afsi_log(char *pattern, ...);*/
30 static char dns_addr[30];
32 extern char cm_confDir[];
34 static int cm_dnsEnabled = -1;
36 void DNSlowerCase(char *str)
40 for (i=0; i<strlen(str); i++)
41 /*str[i] = tolower(str[i]);*/
42 if (str[i] >= 'A' && str[i] <= 'Z')
46 int cm_InitDNS(int enabled)
54 if (!enabled) { fprintf(stderr, "DNS support disabled\n"); cm_dnsEnabled = 0; return 0; }
56 /* First try AFS_NS environment var. */
57 addr = getenv("AFS_NS");
58 if (addr && inet_addr(addr) != -1) {
59 strcpy(dns_addr, addr);
61 /* Now check for the AFSDNS.INI file */
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");
69 code = GetWindowsDirectory(configpath, sizeof(configpath));
70 if (code == 0 || code > sizeof(configpath)) return -1;
72 strcat(configpath, "\\afsdns.ini");
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),
80 if (len == 0 || inet_addr(dns_addr) == -1) {
81 fprintf(stderr, "No valid name server addresses found, DNS lookup is "
83 cm_dnsEnabled = 0; /* failed */
84 return -1; /* No name servers defined */
86 else fprintf(stderr, "Found DNS server %s\n", dns_addr);
88 #endif /* DNSAPI_ENV */
94 SOCKADDR_IN setSockAddr(char *server, int port)
97 int addrLen = sizeof(SOCKADDR_IN);
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);*/
110 int getRRCount(PDNS_HDR ptr)
112 return(ntohs(ptr->rr_count));
116 int send_DNS_Addr_Query(char* query,
117 SOCKET commSock, SOCKADDR_IN sockAddr, char *buffer)
120 PDNS_QTAIL pDNS_qtail;
125 #ifndef WIN32_LEAN_AND_MEAN
126 bzero(buffer,BUFSIZE);
127 #endif /*WIN32_LEAN_AND_MEAN*/
129 /*********************************
130 * Build DNS Query Message *
132 * hard-coded Adrress (A) query *
133 *********************************/
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 */
143 queryLen = putQName( query, &(buffer[ DNS_HDR_LEN ] ) );
144 queryLen += DNS_HDR_LEN; /* query Length is just after the query name and header */
146 fprintf(stderr, "send_DNS_Addr: query=%s, queryLen=%d\n", query, queryLen);
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;
155 /**************************
156 * Send DNS Query Message *
157 **************************/
160 res = sendto( commSock,
164 (struct sockaddr *) &sockAddr,
165 sizeof( SOCKADDR_IN ) );
167 /*dumpSbuffer(buffer,queryLen);*/
172 fprintf(stderr, "send_DNS_Addr_Query: error %d, errno %d\n", res, errno);
173 fprintf(stderr, "sendto() failed \n");
179 /*printf( "sendto() succeeded\n");*/
187 int send_DNS_AFSDB_Query(char* query,
188 SOCKET commSock, SOCKADDR_IN sockAddr, char *buffer)
190 /*static char buffer[BUFSIZE];*/
193 PDNS_QTAIL pDNS_qtail;
198 #ifndef WIN32_LEAN_AND_MEAN
199 bzero(buffer,BUFSIZE);
200 #endif /*WIN32_LEAN_AND_MEAN*/
202 /***************************
203 * Build DNS Query Message *
205 * hard-coded AFSDB query *
206 ***************************/
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 */
216 queryLen = putQName( query, &(buffer[ DNS_HDR_LEN ] ) );
217 queryLen += DNS_HDR_LEN; /* query Length is just after the query name and header */
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;
225 /**************************
226 * Send DNS Query Message *
227 **************************/
229 res = sendto( commSock,
233 (struct sockaddr *) &sockAddr,
234 sizeof( SOCKADDR_IN ) );
236 /*dumpSbuffer(buffer,queryLen);*/
241 fprintf(stderr, "send_DNS_AFSDB_Query: error %d, errno %d\n", res, errno);
242 fprintf(stderr, "sendto() failed \n");
248 /*printf( "sendto() succeeded\n");*/
256 PDNS_HDR get_DNS_Response(SOCKET commSock, SOCKADDR_IN sockAddr, char *buffer)
258 /*static char buffer[BUFSIZE];*/
260 int addrLen = sizeof(SOCKADDR_IN);
263 #ifndef WIN32_LEAN_AND_MEAN
264 bzero(buffer,BUFSIZE);
265 #endif /*WIN32_LEAN_AND_MEAN*/
267 /*****************************
268 * Receive DNS Reply Message *
269 *****************************/
271 /*printf( "calling recvfrom() on connected UDP socket\n" );*/
273 size = recvfrom( commSock,
277 (struct sockaddr *) &sockAddr,
279 if (size < 0) { fprintf(stderr, "recvfrom error %d\n", errno); return NULL; }
281 /*dumpRbuffer(buffer,res);*/
284 fprintf(stderr, "recvfrom returned %d bytes from %s: \n",
285 size, inet_ntoa( sockAddr.sin_addr ) );
288 return((PDNS_HDR)&( buffer[ 0 ] ));
293 int putQName( char *pHostName, char *pQName )
300 DNSlowerCase(pHostName);
301 /*printf( "Hostname: [%s]\n", pHostName );*/
303 for ( i = 0; *( pHostName + i ); i++ )
305 c = *( pHostName + i ); /* get next character */
310 /* dot encountered, fill in previous length */
311 if (k!=0){ /*don't process repeated dots*/
312 /*printf( "%c", c );*/
314 j = j+k+1; /* set index to next counter */
315 k = 0; /* reset segment length */
320 /*printf( "%c", c );*/
321 *( pQName + j + k + 1 ) = c; /* assign to QName */
322 k++; /* inc count of seg chars */
326 *(pQName + j ) = k; /* count for final segment */
328 *(pQName + j + k + 1 ) = 0; /* count for trailing NULL segment is 0 */
333 return ( j + k + 1 ); /* return total length of QName */
335 return ( j + k + 2 );
336 } /* end putQName() */
339 u_char * skipRRQName(u_char *pQName)
348 /* skip the 'compression' pointer */
352 /* skip a normal qname segment */
359 /* ptr now pointing at terminating zero of query QName,
360 or the pointer for the previous occurrence
366 } /* end skipRRQName() */
370 u_char * printRRQName( u_char *pQName, PDNS_HDR buffer )
373 u_char *buffPtr = (u_char *) buffer;
382 for ( i = 0; i < BUFSIZE; i++ )
393 for ( k = 1; k <= c; k++ )
395 fprintf(stderr, "%c", *( namePtr + k ) );
401 fprintf(stderr,"\n");
402 namePtr++; /* skip terminating zero */
409 } /* end printRRQName() */
412 u_char * sPrintRRQName( u_char *pQName, PDNS_HDR buffer, char *str )
415 u_char *buffPtr = (u_char *) buffer;
426 for ( i = 0; i < BUFSIZE; i++ )
437 for ( k = 1; k <= c; k++ )
439 sprintf(section,"%c", *( namePtr + k ) );
446 namePtr++; /* skip terminating zero */
453 } /* end sPrintRRQName() */
456 void printReplyBuffer_AFSDB(PDNS_HDR replyBuff)
458 u_char *ptr = (u_char *) replyBuff;
459 int answerCount = ntohs((replyBuff)->rr_count);
466 /* ptr now pointing at start of QName in query field */
467 ptr = skipRRQName(ptr);
470 /* skip the query type and class fields */
473 /* ptr should now be at the start of the answer RR sections */
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); }
484 ptr = skipRRQName(ptr);
486 fprintf(stderr,"---------------------------------\n");
491 void processReplyBuffer_AFSDB(SOCKET commSock, PDNS_HDR replyBuff, int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS], int *numServers, int *ttl)
492 /*PAFS_SRV_LIST (srvList)*/
494 u_char *ptr = (u_char *) replyBuff;
495 int answerCount = ntohs((replyBuff)->rr_count);
506 /* ptr now pointing at start of QName in query field */
507 ptr = skipRRQName(ptr);
510 /* skip the query type and class fields */
513 /* ptr should now be at the start of the answer RR sections */
515 answerCount = MIN(answerCount, AFSMAXCELLHOSTS);
517 fprintf(stderr, "processRep_AFSDB: answerCount=%d\n", answerCount);
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);
532 fprintf(stderr, "resolving name %s\n", hostName);
534 /* resolve name from DNS query */
535 rc = DNSgetAddr(commSock, hostName, &addr);
537 continue; /* skip this entry */
539 fprintf(stderr, "processRep_AFSDB: resolved name %s to addr %x\n", hostName, addr);
541 memcpy(&cellHostAddrs[srvCount], &addr.s_addr, sizeof(addr.s_addr));
542 strncpy(cellHostNames[srvCount], hostName, MAXCELLCHARS);
543 cellHostNames[srvCount][MAXCELLCHARS-1] = '\0';
547 ptr = skipRRQName(ptr);
551 *numServers = srvCount;
556 u_char * processReplyBuffer_Addr(PDNS_HDR replyBuff)
558 u_char *ptr = (u_char *) replyBuff;
559 int answerCount = ntohs((replyBuff)->rr_count);
564 fprintf(stderr, "processReplyBuffer_Addr: answerCount=%d\n", answerCount);
566 if (answerCount == 0) return 0;
570 /* ptr now pointing at start of QName in query field */
571 ptr = skipRRQName(ptr);
574 /* skip the query type and class fields */
577 /* ptr should now be at the start of the answer RR sections */
578 ptr = skipRRQName(ptr);
579 rrPtr = (PDNS_A_RR_HDR) ptr;
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);
588 ptr += DNS_A_RR_HDR_LEN;
594 int DNSgetAddr(SOCKET commSock, char *hostName, struct in_addr *iNet)
596 /* Variables for DNS message parsing and creation */
599 SOCKADDR_IN sockAddr;
600 char buffer[BUFSIZE];
605 /**********************
606 * Get a DGRAM socket *
607 **********************/
609 sockAddr = setSockAddr(dns_addr, DNS_PORT);
611 rc = send_DNS_Addr_Query(hostName,commSock,sockAddr, buffer);
612 if (rc < 0) return rc;
613 pDNShdr = get_DNS_Response(commSock,sockAddr, buffer);
617 addr = processReplyBuffer_Addr(pDNShdr);
621 aPtr = (u_long *) addr;
623 iNet->s_addr = *aPtr;
627 #endif /* DNSAPI_ENV */
629 int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS],
630 int *numServers, int *ttl)
633 /*static AFS_SRV_LIST srvList;
634 static int ans = 0;*/
636 SOCKADDR_IN sockAddr;
638 char buffer[BUFSIZE];
643 fprintf(stderr, "getAFSServer: cell %s, cm_dnsEnabled=%d\n", cellName, cm_dnsEnabled);
646 #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
647 if (cm_dnsEnabled == -1) { /* not yet initialized, eg when called by klog */
648 cm_InitDNS(1); /* assume enabled */
651 if (cm_dnsEnabled == 0) { /* possibly we failed in cm_InitDNS above */
652 fprintf(stderr, "DNS initialization failed, disabled\n");
657 sockAddr = setSockAddr(dns_addr, DNS_PORT);
659 commSock = socket( AF_INET, SOCK_DGRAM, 0 );
662 /*afsi_log("socket() failed\n");*/
663 fprintf(stderr, "getAFSServer: socket() failed, errno=%d\n", errno);
669 /* the win95 sock.vxd will not allow sendto for unbound sockets,
670 * so just bind to nothing and it works */
672 __djgpp_set_socket_blocking_mode(commSock, 0);
673 bind(commSock,0,sizeof( SOCKADDR_IN ) );
676 strncpy(query, cellName, 1024);
678 if (query[strlen(query)-1] != '.') {
679 strncat(query,".",1024);
683 rc = send_DNS_AFSDB_Query(cellName,commSock,sockAddr, buffer);
685 fprintf(stderr,"getAFSServer: send_DNS_AFSDB_Query failed\n");
690 pDNShdr = get_DNS_Response(commSock,sockAddr, buffer);
692 /*printReplyBuffer_AFSDB(pDNShdr);*/
694 processReplyBuffer_AFSDB(commSock, pDNShdr, cellHostAddrs, cellHostNames, numServers, ttl);
698 closesocket(commSock);
699 if (*numServers == 0)
704 #else /* DNSAPI_ENV */
705 PDNS_RECORD pDnsCell, pDnsIter, pDnsVol,pDnsVolIter, pDnsCIter;
707 struct sockaddr_in vlSockAddr;
713 /* query the AFSDB records of cell */
714 strncpy(query, cellName, 1024);
716 if (query[strlen(query)-1] != '.') {
717 strncat(query,".",1024);
721 if (DnsQuery_A(query, DNS_TYPE_AFSDB, DNS_QUERY_STANDARD, NULL, &pDnsCell, NULL) == ERROR_SUCCESS) {
722 memset((void*) &vlSockAddr, 0, sizeof(vlSockAddr));
724 /* go through the returned records */
725 for (pDnsIter = pDnsCell;pDnsIter; pDnsIter = pDnsIter->pNext) {
726 /* if we find an AFSDB record with Preference set to 1, we found a volserver */
727 if (pDnsIter->wType == DNS_TYPE_AFSDB && pDnsIter->Data.Afsdb.wPreference == 1) {
728 strncpy(cellHostNames[*numServers], pDnsIter->Data.Afsdb.pNameExchange, MAXHOSTCHARS);
729 cellHostNames[*numServers][MAXHOSTCHARS-1]='\0';
733 *ttl = pDnsIter->dwTtl;
734 if (*numServers == AFSMAXCELLHOSTS)
739 for (i=0;i<*numServers;i++)
740 cellHostAddrs[i] = 0;
742 /* now check if there are any A records in the results */
743 for (pDnsIter = pDnsCell; pDnsIter; pDnsIter = pDnsIter->pNext) {
744 if(pDnsIter->wType == DNS_TYPE_A)
745 /* check if its for one of the volservers */
746 for (i=0;i<*numServers;i++)
747 if(stricmp(pDnsIter->pName, cellHostNames[i]) == 0)
748 cellHostAddrs[i] = pDnsIter->Data.A.IpAddress;
751 for (i=0;i<*numServers;i++) {
752 /* if we don't have an IP yet, then we should try resolving the volserver hostname
753 in a separate query. */
754 if (!cellHostAddrs[i]) {
755 if (DnsQuery_A(cellHostNames[i], DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &pDnsVol, NULL) == ERROR_SUCCESS) {
756 for (pDnsVolIter = pDnsVol; pDnsVolIter; pDnsVolIter=pDnsVolIter->pNext) {
757 /* if we get an A record, keep it */
758 if (pDnsVolIter->wType == DNS_TYPE_A && stricmp(cellHostNames[i], pDnsVolIter->pName)==0) {
759 cellHostAddrs[i] = pDnsVolIter->Data.A.IpAddress;
762 /* if we get a CNAME, look for a corresponding A record */
763 if (pDnsVolIter->wType == DNS_TYPE_CNAME && stricmp(cellHostNames[i], pDnsVolIter->pName)==0) {
764 for (pDnsCIter=pDnsVolIter; pDnsCIter; pDnsCIter=pDnsCIter->pNext) {
765 if (pDnsCIter->wType == DNS_TYPE_A && stricmp(pDnsVolIter->Data.CNAME.pNameHost, pDnsCIter->pName)==0) {
766 cellHostAddrs[i] = pDnsCIter->Data.A.IpAddress;
770 if (cellHostAddrs[i])
772 /* TODO: if the additional section is missing, then do another lookup for the CNAME */
775 /* we are done with the volserver lookup */
776 DnsRecordListFree(pDnsVol, DnsFreeRecordListDeep);
780 DnsRecordListFree(pDnsCell, DnsFreeRecordListDeep);
783 if ( *numServers > 0 )
787 #endif /* DNSAPI_ENV */
789 #endif /* AFS_AFSDB_ENV */