Initial revision
[kopensolaris-gnu/glibc.git] / resolv / gethnamaddr.c
1 /*
2  * ++Copyright++ 1985, 1988, 1993
3  * -
4  * Copyright (c) 1985, 1988, 1993
5  *    The Regents of the University of California.  All rights reserved.
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by the University of
18  *      California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  * 
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  * -
35  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
36  * 
37  * Permission to use, copy, modify, and distribute this software for any
38  * purpose with or without fee is hereby granted, provided that the above
39  * copyright notice and this permission notice appear in all copies, and that
40  * the name of Digital Equipment Corporation not be used in advertising or
41  * publicity pertaining to distribution of the document or software without
42  * specific, written prior permission.
43  * 
44  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
47  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51  * SOFTWARE.
52  * -
53  * --Copyright--
54  */
55
56 #if defined(LIBC_SCCS) && !defined(lint)
57 static char sccsid[] = "@(#)gethostnamadr.c     8.1 (Berkeley) 6/4/93";
58 static char rcsid[] = "$Id$";
59 #endif /* LIBC_SCCS and not lint */
60
61 #include <sys/param.h>
62 #include <sys/socket.h>
63 #include <netinet/in.h>
64 #include <arpa/inet.h>
65 #include <arpa/nameser.h>
66
67 #include <stdio.h>
68 #include <netdb.h>
69 #include <resolv.h>
70 #include <ctype.h>
71 #include <errno.h>
72 #include <syslog.h>
73
74 #ifndef LOG_AUTH
75 # define LOG_AUTH 0
76 #endif
77
78 #define MULTI_PTRS_ARE_ALIASES 1        /* XXX - experimental */
79
80 #if defined(BSD) && (BSD >= 199103)
81 # include <string.h>
82 #else
83 # include "../conf/portability.h"
84 #endif
85 #if defined(USE_OPTIONS_H)
86 # include <../conf/options.h>
87 #endif
88
89 #define MAXALIASES      35
90 #define MAXADDRS        35
91
92 static const char AskedForGot[] =
93                           "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
94
95 static char *h_addr_ptrs[MAXADDRS + 1];
96
97 static struct hostent host;
98 static char *host_aliases[MAXALIASES];
99 static char hostbuf[8*1024];
100 static struct in_addr host_addr;
101 static FILE *hostf = NULL;
102 static int stayopen = 0;
103
104 #ifdef RESOLVSORT
105 static void addrsort __P((char **, int));
106 #endif
107
108 #if PACKETSZ > 1024
109 #define MAXPACKET       PACKETSZ
110 #else
111 #define MAXPACKET       1024
112 #endif
113
114 typedef union {
115     HEADER hdr;
116     u_char buf[MAXPACKET];
117 } querybuf;
118
119 typedef union {
120     int32_t al;
121     char ac;
122 } align;
123
124 extern int h_errno;
125
126 static struct hostent *
127 getanswer(answer, anslen, qname, qclass, qtype)
128         const querybuf *answer;
129         int anslen;
130         const char *qname;
131         int qclass, qtype;
132 {
133         register const HEADER *hp;
134         register const u_char *cp;
135         register int n;
136         const u_char *eom;
137         char *bp, **ap, **hap;
138         int type, class, buflen, ancount, qdcount;
139         int haveanswer, had_error;
140         int toobig = 0;
141         char tbuf[MAXDNAME+1];
142
143         host.h_name = NULL;
144         eom = answer->buf + anslen;
145         /*
146          * find first satisfactory answer
147          */
148         hp = &answer->hdr;
149         ancount = ntohs(hp->ancount);
150         qdcount = ntohs(hp->qdcount);
151         bp = hostbuf;
152         buflen = sizeof hostbuf;
153         cp = answer->buf + HFIXEDSZ;
154         if (qdcount != 1) {
155                 h_errno = NO_RECOVERY;
156                 return (NULL);
157         }
158         if ((n = dn_expand(answer->buf, eom, cp, bp, buflen)) < 0) {
159                 h_errno = NO_RECOVERY;
160                 return (NULL);
161         }
162         cp += n + QFIXEDSZ;
163         if (qtype == T_A) {
164                 /* res_send() has already verified that the query name is the
165                  * same as the one we sent; this just gets the expanded name
166                  * (i.e., with the succeeding search-domain tacked on).
167                  */
168                 n = strlen(bp) + 1;             /* for the \0 */
169                 host.h_name = bp;
170                 bp += n;
171                 buflen -= n;
172                 /* The qname can be abbreviated, but h_name is now absolute. */
173                 qname = host.h_name;
174         }
175         ap = host_aliases;
176         *ap = NULL;
177         host.h_aliases = host_aliases;
178         hap = h_addr_ptrs;
179         *hap = NULL;
180 #if BSD >= 43 || defined(h_addr)        /* new-style hostent structure */
181         host.h_addr_list = h_addr_ptrs;
182 #endif
183         haveanswer = 0;
184         had_error = 0;
185         while (ancount-- > 0 && cp < eom && !had_error) {
186                 n = dn_expand(answer->buf, eom, cp, bp, buflen);
187                 if (n < 0) {
188                         had_error++;
189                         continue;
190                 }
191                 cp += n;                        /* name */
192                 type = _getshort(cp);
193                 cp += INT16SZ;                  /* type */
194                 class = _getshort(cp);
195                 cp += INT16SZ + INT32SZ;        /* class, TTL */
196                 n = _getshort(cp);
197                 cp += INT16SZ;                  /* len */
198                 if (class != qclass) {
199                         /* XXX - debug? syslog? */
200                         cp += n;
201                         continue;               /* XXX - had_error++ ? */
202                 }
203                 if (qtype == T_A && type == T_CNAME) {
204                         if (ap >= &host_aliases[MAXALIASES-1])
205                                 continue;
206                         n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
207                         if (n < 0) {
208                                 had_error++;
209                                 continue;
210                         }
211                         cp += n;
212                         if (host.h_name && strcasecmp(host.h_name, bp) != 0) {
213                                 syslog(LOG_NOTICE|LOG_AUTH,
214                 "gethostby*.getanswer: asked for \"%s\", got CNAME for \"%s\"",
215                                        host.h_name, bp);
216                                 continue;       /* XXX - had_error++ ? */
217                         }
218                         /* Store alias. */
219                         *ap++ = bp;
220                         n = strlen(bp) + 1;     /* for the \0 */
221                         bp += n;
222                         buflen -= n;
223                         /* Get canonical name. */
224                         n = strlen(tbuf) + 1;   /* for the \0 */
225                         if (n > buflen) {
226                                 had_error++;
227                                 continue;
228                         }
229                         strcpy(bp, tbuf);
230                         host.h_name = bp;
231                         bp += n;
232                         buflen -= n;
233                         continue;
234                 }
235                 if (type != qtype) {
236                         syslog(LOG_NOTICE|LOG_AUTH,
237                      "gethostby*.getanswer: asked for type %d(%s), got %d(%s)",
238                                qtype, qname, type, bp);
239                         cp += n;
240                         continue;               /* XXX - had_error++ ? */
241                 }
242                 switch (type) {
243                 case T_PTR:
244                         if (strcasecmp(qname, bp) != 0) {
245                                 syslog(LOG_NOTICE|LOG_AUTH,
246                                        AskedForGot, qname, bp);
247                                 cp += n;
248                                 continue;       /* XXX - had_error++ ? */
249                         }
250                         n = dn_expand(answer->buf, eom, cp, bp, buflen);
251                         if (n < 0) {
252                                 had_error++;
253                                 break;
254                         }
255 #if MULTI_PTRS_ARE_ALIASES
256                         cp += n;
257                         if (!haveanswer)
258                                 host.h_name = bp;
259                         else if (ap < &host_aliases[MAXALIASES-1])
260                                 *ap++ = bp;
261                         else
262                                 n = -1;
263                         if (n != -1) {
264                                 n = strlen(bp) + 1;     /* for the \0 */
265                                 bp += n;
266                                 buflen -= n;
267                         }
268                         break;
269 #else
270                         host.h_name = bp;
271                         return (&host);
272 #endif
273                 case T_A:
274                         if (strcasecmp(host.h_name, bp) != 0) {
275                                 syslog(LOG_NOTICE|LOG_AUTH,
276                                        AskedForGot, host.h_name, bp);
277                                 cp += n;
278                                 continue;       /* XXX - had_error++ ? */
279                         }
280                         if (haveanswer) {
281                                 if (n != host.h_length) {
282                                         cp += n;
283                                         continue;
284                                 }
285                         } else {
286                                 register int nn;
287
288                                 host.h_length = n;
289                                 host.h_addrtype = (class == C_IN)
290                                                   ? AF_INET
291                                                   : AF_UNSPEC;
292                                 host.h_name = bp;
293                                 nn = strlen(bp) + 1;    /* for the \0 */
294                                 bp += nn;
295                                 buflen -= nn;
296                         }
297
298                         bp += sizeof(align) - ((u_long)bp % sizeof(align));
299
300                         if (bp + n >= &hostbuf[sizeof hostbuf]) {
301 #ifdef DEBUG
302                                 if (_res.options & RES_DEBUG)
303                                         printf("size (%d) too big\n", n);
304 #endif
305                                 had_error++;
306                                 continue;
307                         }
308                         if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
309                                 if (_res.options & RES_DEBUG && !toobig++)
310                                         printf("Too many addresses (%d)\n",
311                                                MAXADDRS);
312                                 cp += n;
313                                 continue;
314                         }
315                         bcopy(cp, *hap++ = bp, n);
316                         bp += n;
317                         cp += n;
318                         break;
319                 default:
320                         abort();
321                 } /*switch*/
322                 if (!had_error)
323                         haveanswer++;
324         } /*while*/
325         if (haveanswer) {
326                 *ap = NULL;
327                 *hap = NULL;
328 # if defined(RESOLVSORT)
329                 /*
330                  * Note: we sort even if host can take only one address
331                  * in its return structures - should give it the "best"
332                  * address in that case, not some random one
333                  */
334                 if (_res.nsort && haveanswer > 1 &&
335                     qclass == C_IN && qtype == T_A)
336                         addrsort(h_addr_ptrs, haveanswer);
337 # endif /*RESOLVSORT*/
338 #if BSD >= 43 || defined(h_addr)        /* new-style hostent structure */
339                 /* nothing */
340 #else
341                 host.h_addr = h_addr_ptrs[0];
342 #endif /*BSD*/
343                 if (!host.h_name) {
344                         n = strlen(qname) + 1;  /* for the \0 */
345                         strcpy(bp, qname);
346                         host.h_name = bp;
347                 }
348                 return (&host);
349         } else {
350                 h_errno = TRY_AGAIN;
351                 return (NULL);
352         }
353 }
354
355 struct hostent *
356 gethostbyname(name)
357         const char *name;
358 {
359         querybuf buf;
360         register const char *cp;
361         int n;
362         extern struct hostent *_gethtbyname();
363
364         /*
365          * disallow names consisting only of digits/dots, unless
366          * they end in a dot.
367          */
368         if (isdigit(name[0]))
369                 for (cp = name;; ++cp) {
370                         if (!*cp) {
371                                 if (*--cp == '.')
372                                         break;
373                                 /*
374                                  * All-numeric, no dot at the end.
375                                  * Fake up a hostent as if we'd actually
376                                  * done a lookup.
377                                  */
378                                 if (!inet_aton(name, &host_addr)) {
379                                         h_errno = HOST_NOT_FOUND;
380                                         return (NULL);
381                                 }
382                                 host.h_name = (char *)name;
383                                 host.h_aliases = host_aliases;
384                                 host_aliases[0] = NULL;
385                                 host.h_addrtype = AF_INET;
386                                 host.h_length = INT32SZ;
387                                 h_addr_ptrs[0] = (char *)&host_addr;
388                                 h_addr_ptrs[1] = NULL;
389 #if BSD >= 43 || defined(h_addr)        /* new-style hostent structure */
390                                 host.h_addr_list = h_addr_ptrs;
391 #else
392                                 host.h_addr = h_addr_ptrs[0];
393 #endif
394                                 return (&host);
395                         }
396                         if (!isdigit(*cp) && *cp != '.') 
397                                 break;
398                 }
399
400         if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof(buf))) < 0) {
401 #ifdef DEBUG
402                 if (_res.options & RES_DEBUG)
403                         printf("res_search failed\n");
404 #endif
405                 if (errno == ECONNREFUSED)
406                         return (_gethtbyname(name));
407                 else
408                         return (NULL);
409         }
410         return (getanswer(&buf, n, name, C_IN, T_A));
411 }
412
413 struct hostent *
414 gethostbyaddr(addr, len, type)
415         const char *addr;
416         int len, type;
417 {
418         int n;
419         querybuf buf;
420         register struct hostent *hp;
421         char qbuf[MAXDNAME+1];
422 #ifdef SUNSECURITY
423         register struct hostent *rhp;
424         char **haddr;
425         u_long old_options;
426 #endif /*SUNSECURITY*/
427         extern struct hostent *_gethtbyaddr();
428         
429         if (type != AF_INET)
430                 return (NULL);
431         (void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
432                 ((unsigned)addr[3] & 0xff),
433                 ((unsigned)addr[2] & 0xff),
434                 ((unsigned)addr[1] & 0xff),
435                 ((unsigned)addr[0] & 0xff));
436         n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
437         if (n < 0) {
438 #ifdef DEBUG
439                 if (_res.options & RES_DEBUG)
440                         printf("res_query failed\n");
441 #endif
442                 if (errno == ECONNREFUSED)
443                         return (_gethtbyaddr(addr, len, type));
444                 return (NULL);
445         }
446         if (!(hp = getanswer(&buf, n, qbuf, C_IN, T_PTR)))
447                 return (NULL);
448 #ifdef SUNSECURITY
449         /*
450          * turn off search as the name should be absolute,
451          * 'localhost' should be matched by defnames
452          */
453         old_options = _res.options;
454         _res.options &= ~RES_DNSRCH;
455         _res.options |= RES_DEFNAMES;
456         if (!(rhp = gethostbyname(hp->h_name))) {
457                 syslog(LOG_NOTICE|LOG_AUTH,
458                        "gethostbyaddr: No A record for %s (verifying [%s])",
459                        hp->h_name, inet_ntoa(*((struct in_addr *)addr)));
460                 _res.options = old_options;
461                 return (NULL);
462         }
463         _res.options = old_options;
464         for (haddr = rhp->h_addr_list; *haddr; haddr++)
465                 if (!memcmp(*haddr, addr, INADDRSZ))
466                         break;
467         if (!*haddr) {
468                 syslog(LOG_NOTICE|LOG_AUTH,
469                        "gethostbyaddr: A record of %s != PTR record [%s]",
470                        hp->h_name, inet_ntoa(*((struct in_addr *)addr)));
471                 h_errno = HOST_NOT_FOUND;
472                 return (NULL);
473         }
474 #endif /*SUNSECURITY*/
475         hp->h_addrtype = type;
476         hp->h_length = len;
477         h_addr_ptrs[0] = (char *)&host_addr;
478         h_addr_ptrs[1] = NULL;
479         host_addr = *(struct in_addr *)addr;
480 #if BSD < 43 && !defined(h_addr)        /* new-style hostent structure */
481         hp->h_addr = h_addr_ptrs[0];
482 #endif
483         return (hp);
484 }
485
486 void
487 _sethtent(f)
488         int f;
489 {
490         if (!hostf)
491                 hostf = fopen(_PATH_HOSTS, "r" );
492         else
493                 rewind(hostf);
494         stayopen = f;
495 }
496
497 void
498 _endhtent()
499 {
500         if (hostf && !stayopen) {
501                 (void) fclose(hostf);
502                 hostf = NULL;
503         }
504 }
505
506 struct hostent *
507 _gethtent()
508 {
509         char *p;
510         register char *cp, **q;
511
512         if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" )))
513                 return (NULL);
514 again:
515         if (!(p = fgets(hostbuf, sizeof hostbuf, hostf)))
516                 return (NULL);
517         if (*p == '#')
518                 goto again;
519         if (!(cp = strpbrk(p, "#\n")))
520                 goto again;
521         *cp = '\0';
522         if (!(cp = strpbrk(p, " \t")))
523                 goto again;
524         *cp++ = '\0';
525         /* THIS STUFF IS INTERNET SPECIFIC */
526         if (!inet_aton(p, &host_addr))
527                 goto again;
528         h_addr_ptrs[0] = (char *)&host_addr;
529         h_addr_ptrs[1] = NULL;
530 #if BSD >= 43 || defined(h_addr)        /* new-style hostent structure */
531         host.h_addr_list = h_addr_ptrs;
532 #else
533         host.h_addr = h_addr_ptrs[0];
534 #endif
535         host.h_length = INT32SZ;
536         host.h_addrtype = AF_INET;
537         while (*cp == ' ' || *cp == '\t')
538                 cp++;
539         host.h_name = cp;
540         q = host.h_aliases = host_aliases;
541         if (cp = strpbrk(cp, " \t"))
542                 *cp++ = '\0';
543         while (cp && *cp) {
544                 if (*cp == ' ' || *cp == '\t') {
545                         cp++;
546                         continue;
547                 }
548                 if (q < &host_aliases[MAXALIASES - 1])
549                         *q++ = cp;
550                 if (cp = strpbrk(cp, " \t"))
551                         *cp++ = '\0';
552         }
553         *q = NULL;
554         return (&host);
555 }
556
557 struct hostent *
558 _gethtbyname(name)
559         char *name;
560 {
561         register struct hostent *p;
562         register char **cp;
563         
564         _sethtent(0);
565         while (p = _gethtent()) {
566                 if (strcasecmp(p->h_name, name) == 0)
567                         break;
568                 for (cp = p->h_aliases; *cp != 0; cp++)
569                         if (strcasecmp(*cp, name) == 0)
570                                 goto found;
571         }
572 found:
573         _endhtent();
574         return (p);
575 }
576
577 struct hostent *
578 _gethtbyaddr(addr, len, type)
579         const char *addr;
580         int len, type;
581 {
582         register struct hostent *p;
583
584         _sethtent(0);
585         while (p = _gethtent())
586                 if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len))
587                         break;
588         _endhtent();
589         return (p);
590 }
591
592 #ifdef RESOLVSORT
593 static void
594 addrsort(ap, num)
595         char **ap;
596         int num;
597 {
598         int i, j;
599         char **p;
600         short aval[MAXADDRS];
601         int needsort = 0;
602
603         p = ap;
604         for (i = 0; i < num; i++, p++) {
605             for (j = 0 ; j < _res.nsort; j++)
606                 if (_res.sort_list[j].addr.s_addr == 
607                     (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
608                         break;
609             aval[i] = j;
610             if (needsort == 0 && i > 0 && j < aval[i-1])
611                 needsort = i;
612         }
613         if (!needsort)
614             return;
615
616         while (needsort < num) {
617             for (j = needsort - 1; j >= 0; j--) {
618                 if (aval[j] > aval[j+1]) {
619                     char *hp;
620
621                     i = aval[j];
622                     aval[j] = aval[j+1];
623                     aval[j+1] = i;
624
625                     hp = ap[j];
626                     ap[j] = ap[j+1];
627                     ap[j+1] = hp;
628
629                 } else
630                     break;
631             }
632             needsort++;
633         }
634 }
635 #endif
636
637 #if defined(BSD43_BSD43_NFS) || defined(sun)
638 /* some libc's out there are bound internally to these names (UMIPS) */
639 void
640 ht_sethostent(stayopen)
641         int stayopen;
642 {
643         _sethtent(stayopen);
644 }
645
646 void
647 ht_endhostent()
648 {
649         _endhtent();
650 }
651
652 struct hostent *
653 ht_gethostbyname(name)
654         char *name;
655 {
656         return (_gethtbyname(name));
657 }
658
659 struct hostent *
660 ht_gethostbyaddr(addr, len, type)
661         const char *addr;
662         int len, type;
663 {
664         return (_gethtbyaddr(addr, len, type));
665 }
666
667 struct hostent *
668 gethostent()
669 {
670         return (_gethtent());
671 }
672
673 void
674 dns_service()
675 {
676         return;
677 }
678
679 #undef dn_skipname
680 dn_skipname(comp_dn, eom)
681         const u_char *comp_dn, *eom;
682 {
683         return (__dn_skipname(comp_dn, eom));
684 }
685 #endif /*old-style libc with yp junk in it*/
686
687 #ifdef ultrix
688 /* more icky libc packaging in ultrix */
689 int
690 local_hostname_length(hostname)
691         const char *hostname;
692 {
693         int len_host, len_domain;
694
695         if (!*_res.defdname)
696                 res_init();
697         len_host = strlen(hostname);
698         len_domain = strlen(_res.defdname);
699         if (len_host > len_domain &&
700             !strcasecmp(hostname + len_host - len_domain, _res.defdname) &&
701             hostname[len_host - len_domain - 1] == '.')
702                 return (len_host - len_domain - 1);
703         return (0);
704 }
705 #endif