1 /*
   2  * Copyright 2015 Gary Mills
   3  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
   4  * Use is subject to license terms.
   5  */
   6 
   7 /*
   8  * Copyright (c) 1985, 1988 Regents of the University of California.
   9  * All rights reserved.
  10  *
  11  * Redistribution and use in source and binary forms are permitted
  12  * provided that this notice is preserved and that due credit is given
  13  * to the University of California at Berkeley. The name of the University
  14  * may not be used to endorse or promote products derived from this
  15  * software without specific prior written permission. This software
  16  * is provided ``as is'' without express or implied warranty.
  17  *
  18  */
  19 
  20 #include <sys/param.h>
  21 #include <sys/socket.h>
  22 #include <netinet/in.h>
  23 #include <ctype.h>
  24 #include <netdb.h>
  25 #include <stdio.h>
  26 #include <errno.h>
  27 #include <string.h>
  28 #include <arpa/inet.h>
  29 #include <arpa/nameser.h>
  30 #include <resolv.h>
  31 #include <syslog.h>
  32 #include "crossl.h"
  33 
  34 /*
  35  * When the name service switch calls libresolv, it doesn't want fallback
  36  * to /etc/hosts, so we provide a method to turn it off.
  37  */
  38 static int      no_hosts_fallback = 0;
  39 
  40 void
  41 __res_set_no_hosts_fallback(void) {
  42         no_hosts_fallback = 1;
  43 }
  44 
  45 static int
  46 __res_no_hosts_fallback(void) {
  47         return(no_hosts_fallback);
  48 }
  49 
  50 static char *h_addr_ptrs[MAXADDRS + 1];
  51 
  52 static struct hostent host;
  53 static char *host_aliases[MAXALIASES];
  54 static char hostbuf[BUFSIZ+1];
  55 static struct in_addr host_addr;
  56 static char HOSTDB[] = "/etc/hosts";
  57 static FILE *hostf = NULL;
  58 static char hostaddr[MAXADDRS];
  59 static char *host_addrs[2];
  60 static int stayopen = 0;
  61 static char *any();
  62 
  63 #if PACKETSZ > 1024
  64 #define MAXPACKET       PACKETSZ
  65 #else
  66 #define MAXPACKET       1024
  67 #endif
  68 
  69 typedef union {
  70         HEADER hdr;
  71         u_char buf[MAXPACKET];
  72 } querybuf;
  73 
  74 static union {
  75         long al;
  76         char ac;
  77 } align;
  78 
  79 
  80 int h_errno;
  81 
  82 static struct hostent *
  83 getanswer(answer, anslen, iquery)
  84         querybuf *answer;
  85         int anslen;
  86         int iquery;
  87 {
  88         register HEADER *hp;
  89         register u_char *cp;
  90         register int n;
  91         u_char *eom;
  92         char *bp, **ap;
  93         int type, class, buflen, ancount, qdcount;
  94         int haveanswer, getclass = C_ANY;
  95         char **hap;
  96 
  97         eom = answer->buf + anslen;
  98         /*
  99          * find first satisfactory answer
 100          */
 101         hp = &answer->hdr;
 102         ancount = ntohs(hp->ancount);
 103         qdcount = ntohs(hp->qdcount);
 104         bp = hostbuf;
 105         buflen = sizeof (hostbuf);
 106         cp = answer->buf + sizeof (HEADER);
 107         if (qdcount) {
 108                 if (iquery) {
 109                         if ((n = dn_expand(answer->buf, eom,
 110                             cp, (u_char *)bp, buflen)) < 0) {
 111                                 h_errno = NO_RECOVERY;
 112                                 return ((struct hostent *) NULL);
 113                         }
 114                         cp += n + QFIXEDSZ;
 115                         host.h_name = bp;
 116                         n = strlen(bp) + 1;
 117                         bp += n;
 118                         buflen -= n;
 119                 } else
 120                         cp += dn_skipname(cp, eom) + QFIXEDSZ;
 121                 while (--qdcount > 0)
 122                         cp += dn_skipname(cp, eom) + QFIXEDSZ;
 123         } else if (iquery) {
 124                 if (hp->aa)
 125                         h_errno = HOST_NOT_FOUND;
 126                 else
 127                         h_errno = TRY_AGAIN;
 128                 return ((struct hostent *) NULL);
 129         }
 130         ap = host_aliases;
 131         host.h_aliases = host_aliases;
 132         hap = h_addr_ptrs;
 133 #if BSD >= 43 || defined(h_addr)     /* new-style hostent structure */
 134         host.h_addr_list = h_addr_ptrs;
 135 #endif
 136         haveanswer = 0;
 137         while (--ancount >= 0 && cp < eom && haveanswer < MAXADDRS) {
 138                 if ((n = dn_expand(answer->buf, eom,
 139                     cp, (u_char *)bp, buflen)) < 0)
 140                         break;
 141                 cp += n;
 142                 type = _getshort(cp);
 143                 cp += sizeof (u_short);
 144                 class = _getshort(cp);
 145                 cp += sizeof (u_short) + sizeof (u_long);
 146                 n = _getshort(cp);
 147                 cp += sizeof (u_short);
 148                 if (type == T_CNAME) {
 149                         cp += n;
 150                         if (ap >= &host_aliases[MAXALIASES-1])
 151                                 continue;
 152                         *ap++ = bp;
 153                         n = strlen(bp) + 1;
 154                         bp += n;
 155                         buflen -= n;
 156                         continue;
 157                 }
 158                 if (iquery && type == T_PTR) {
 159                         if ((n = dn_expand(answer->buf, eom,
 160                             cp, (u_char *)bp, buflen)) < 0) {
 161                                 cp += n;
 162                                 continue;
 163                         }
 164                         cp += n;
 165                         host.h_name = bp;
 166                         return (&host);
 167                 }
 168                 if (iquery || type != T_A) {
 169 #ifdef DEBUG
 170                         if (_res.options & RES_DEBUG)
 171                                 printf("unexpected answer type %d, size %d\n",
 172                                         type, n);
 173 #endif
 174                         cp += n;
 175                         continue;
 176                 }
 177                 if (haveanswer) {
 178                         if (n != host.h_length) {
 179                                 cp += n;
 180                                 continue;
 181                         }
 182                         if (class != getclass) {
 183                                 cp += n;
 184                                 continue;
 185                         }
 186                 } else {
 187                         host.h_length = n;
 188                         getclass = class;
 189                         host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
 190                         if (!iquery) {
 191                                 host.h_name = bp;
 192                                 bp += strlen(bp) + 1;
 193                         }
 194                 }
 195 
 196                 bp += sizeof (align) - ((u_long)bp % sizeof (align));
 197 
 198                 if (bp + n >= &hostbuf[sizeof (hostbuf)]) {
 199 #ifdef DEBUG
 200                         if (_res.options & RES_DEBUG)
 201                                 printf("size (%d) too big\n", n);
 202 #endif
 203                         break;
 204                 }
 205 #ifdef SYSV
 206                 memcpy((void *)(*hap++ = bp), (void *)cp, n);
 207 #else
 208                 bcopy(cp, *hap++ = bp, n);
 209 #endif
 210                 bp += n;
 211                 cp += n;
 212                 haveanswer++;
 213         }
 214         if (haveanswer) {
 215                 *ap = NULL;
 216 #if BSD >= 43 || defined(h_addr)     /* new-style hostent structure */
 217                 *hap = NULL;
 218 #else
 219                 host.h_addr = h_addr_ptrs[0];
 220 #endif
 221                 return (&host);
 222         } else {
 223                 h_errno = TRY_AGAIN;
 224                 return ((struct hostent *) NULL);
 225         }
 226 }
 227 
 228 static struct hostent *_gethtbyname();
 229 
 230 struct hostent *
 231 res_gethostbyname(name)
 232         char *name;
 233 {
 234         querybuf buf;
 235         register char *cp;
 236         int n;
 237 
 238         /*
 239          * disallow names consisting only of digits/dots, unless
 240          * they end in a dot.
 241          */
 242         if (isdigit(name[0]))
 243                 for (cp = name; /*EMPTY*/; ++cp) {
 244                         if (!*cp) {
 245                                 if (*--cp == '.')
 246                                         break;
 247                                 h_errno = HOST_NOT_FOUND;
 248                                 return ((struct hostent *) NULL);
 249                         }
 250                         if (!isdigit(*cp) && *cp != '.')
 251                                 break;
 252                 }
 253 
 254         if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof (buf))) < 0) {
 255 #ifdef DEBUG
 256                 if (_res.options & RES_DEBUG)
 257                         printf("res_search failed\n");
 258 #endif
 259                 if (errno == ECONNREFUSED)
 260                         return (_gethtbyname(name));
 261                 else
 262                         return ((struct hostent *) NULL);
 263         }
 264         return (getanswer(&buf, n, 0));
 265 }
 266 
 267 static struct hostent *_gethtbyaddr();
 268 
 269 static struct hostent *
 270 _getrhbyaddr(addr, len, type)
 271         char *addr;
 272         int len, type;
 273 {
 274         int n;
 275         querybuf buf;
 276         register struct hostent *hp;
 277         char qbuf[MAXDNAME];
 278 
 279         if (type != AF_INET)
 280                 return ((struct hostent *) NULL);
 281         (void) sprintf(qbuf, "%d.%d.%d.%d.in-addr.arpa",
 282                 ((unsigned)addr[3] & 0xff),
 283                 ((unsigned)addr[2] & 0xff),
 284                 ((unsigned)addr[1] & 0xff),
 285                 ((unsigned)addr[0] & 0xff));
 286         n = res_query(qbuf, C_IN, T_PTR, (u_char *)&buf, sizeof (buf));
 287         if (n < 0) {
 288 #ifdef DEBUG
 289                 if (_res.options & RES_DEBUG)
 290                         printf("res_query failed\n");
 291 #endif
 292                 if (errno == ECONNREFUSED)
 293                         return (_gethtbyaddr(addr, len, type));
 294                 return ((struct hostent *) NULL);
 295         }
 296         hp = getanswer(&buf, n, 1);
 297         if (hp == NULL)
 298                 return ((struct hostent *) NULL);
 299         hp->h_addrtype = type;
 300         hp->h_length = len;
 301         h_addr_ptrs[0] = (char *)&host_addr;
 302         h_addr_ptrs[1] = (char *)0;
 303         host_addr = *(struct in_addr *)addr;
 304         return (hp);
 305 }
 306 
 307 /*
 308  * First we get what the PTR record says, but do an extra call
 309  * to gethostbyname() to make sure that someone is not trying to
 310  * spoof us.  Hopefully this is not done that often, so good
 311  * performance is not really an issue.
 312  */
 313 struct hostent *
 314 res_gethostbyaddr(addr, len, type)
 315         char    *addr;
 316         int     len;
 317         int     type;
 318 {
 319         char            **a, hbuf[MAXHOSTNAMELEN];
 320         struct hostent  *hp, *hp2;
 321 
 322         if ((hp = _getrhbyaddr(addr, len, type)) == (struct hostent *)NULL)
 323                 return ((struct hostent *)NULL);
 324 
 325         /* hang on to what we got as an answer */
 326         (void) strcpy(hbuf, hp->h_name);
 327 
 328         /* check to make sure by doing a forward query */
 329         if ((hp2 = res_gethostbyname(hbuf)) != (struct hostent *)NULL)
 330                 for (a = hp2->h_addr_list; *a; a++)
 331 #ifdef SYSV
 332                         if (memcmp(*a, addr, hp2->h_length) == 0)
 333 #else
 334                         if (bcmp(*a, addr, hp2->h_length) == 0)
 335 #endif
 336                                 return (hp2);
 337 
 338         /*
 339          * we've been spoofed, make sure to log it.
 340          * XXX - syslog needs a security priority level.
 341          */
 342         syslog(LOG_NOTICE, "gethostbyaddr: %s != %s", hbuf,
 343                 inet_ntoa(*(struct in_addr *)addr));
 344         return ((struct hostent *)NULL);
 345 }
 346 
 347 static void
 348 _sethtent(int f)
 349 {
 350         if (__res_no_hosts_fallback()) return;
 351 
 352         if (hostf == NULL)
 353                 hostf = fopen(HOSTDB, "r");
 354         else
 355                 rewind(hostf);
 356         stayopen |= f;
 357 }
 358 
 359 static void
 360 _endhtent(void)
 361 {
 362         if (__res_no_hosts_fallback()) return;
 363 
 364         if (hostf && !stayopen) {
 365                 (void) fclose(hostf);
 366                 hostf = NULL;
 367         }
 368 }
 369 
 370 static struct hostent *
 371 _gethtent()
 372 {
 373         char *p;
 374         register char *cp, **q;
 375 
 376         if (__res_no_hosts_fallback()) return(NULL);
 377 
 378         if (hostf == NULL && (hostf = fopen(HOSTDB, "r")) == NULL)
 379                 return (NULL);
 380 again:
 381         if ((p = fgets(hostbuf, BUFSIZ, hostf)) == NULL)
 382                 return (NULL);
 383         if (*p == '#')
 384                 goto again;
 385         cp = any(p, "#\n");
 386         if (cp == NULL)
 387                 goto again;
 388         *cp = '\0';
 389         cp = any(p, " \t");
 390         if (cp == NULL)
 391                 goto again;
 392         *cp++ = '\0';
 393         /* THIS STUFF IS INTERNET SPECIFIC */
 394 #if BSD >= 43 || defined(h_addr)     /* new-style hostent structure */
 395         host.h_addr_list = host_addrs;
 396 #endif
 397         host.h_addr = hostaddr;
 398         *((u_long *)host.h_addr) = inet_addr(p);
 399         host.h_length = sizeof (u_long);
 400         host.h_addrtype = AF_INET;
 401         while (*cp == ' ' || *cp == '\t')
 402                 cp++;
 403         host.h_name = cp;
 404         q = host.h_aliases = host_aliases;
 405         cp = any(cp, " \t");
 406         if (cp != NULL)
 407                 *cp++ = '\0';
 408         while (cp && *cp) {
 409                 if (*cp == ' ' || *cp == '\t') {
 410                         cp++;
 411                         continue;
 412                 }
 413                 if (q < &host_aliases[MAXALIASES - 1])
 414                         *q++ = cp;
 415                 cp = any(cp, " \t");
 416                 if (cp != NULL)
 417                         *cp++ = '\0';
 418         }
 419         *q = NULL;
 420         return (&host);
 421 }
 422 
 423 static char *
 424 any(cp, match)
 425         register char *cp;
 426         char *match;
 427 {
 428         register char *mp, c;
 429 
 430         while (c = *cp) {
 431                 for (mp = match; *mp; mp++)
 432                         if (*mp == c)
 433                                 return (cp);
 434                 cp++;
 435         }
 436         return ((char *)0);
 437 }
 438 
 439 static struct hostent *
 440 _gethtbyname(name)
 441         char *name;
 442 {
 443         register struct hostent *p;
 444         register char **cp;
 445 
 446         _sethtent(0);
 447         while (p = _gethtent()) {
 448                 if (strcasecmp(p->h_name, name) == 0)
 449                         break;
 450                 for (cp = p->h_aliases; *cp != 0; cp++)
 451                         if (strcasecmp(*cp, name) == 0)
 452                                 goto found;
 453         }
 454 found:
 455         _endhtent();
 456         return (p);
 457 }
 458 
 459 static struct hostent *
 460 _gethtbyaddr(addr, len, type)
 461         char *addr;
 462         int len, type;
 463 {
 464         register struct hostent *p;
 465 
 466         _sethtent(0);
 467         while (p = _gethtent())
 468 #ifdef SYSV
 469                 if (p->h_addrtype == type && !memcmp(p->h_addr, addr, len))
 470 #else
 471                 if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len))
 472 #endif
 473                         break;
 474         _endhtent();
 475         return (p);
 476 }