1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 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. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * - 31 * Portions Copyright (c) 1993 by Digital Equipment Corporation. 32 * 33 * Permission to use, copy, modify, and distribute this software for any 34 * purpose with or without fee is hereby granted, provided that the above 35 * copyright notice and this permission notice appear in all copies, and that 36 * the name of Digital Equipment Corporation not be used in advertising or 37 * publicity pertaining to distribution of the document or software without 38 * specific, written prior permission. 39 * 40 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 41 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 42 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 43 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 44 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 45 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 46 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 47 * SOFTWARE. 48 * - 49 * --Copyright-- 50 */ 51 /* Portions Copyright (c) 1993 Carlos Leandro and Rui Salgueiro 52 * Dep. Matematica Universidade de Coimbra, Portugal, Europe 53 * 54 * Permission to use, copy, modify, and distribute this software for any 55 * purpose with or without fee is hereby granted, provided that the above 56 * copyright notice and this permission notice appear in all copies. 57 */ 58 59 #include <sys/param.h> 60 #include <sys/socket.h> 61 #include <netinet/in.h> 62 #include <arpa/inet.h> 63 #include <arpa/nameser.h> 64 65 #include <errno.h> 66 #include <stdio.h> 67 #include <stdlib.h> 68 #include <netdb.h> 69 #include <resolv.h> 70 #include <ctype.h> 71 #include <string.h> 72 #include <unistd.h> 73 #include <syslog.h> 74 #include <stdarg.h> 75 #include <nsswitch.h> 76 77 #include "netdb_private.h" 78 #include "res_config.h" 79 80 #define BYADDR 0 81 #define BYNAME 1 82 83 #define MAXPACKET (64*1024) 84 85 typedef union { 86 HEADER hdr; 87 u_char buf[MAXPACKET]; 88 } querybuf; 89 90 typedef union { 91 long al; 92 char ac; 93 } align; 94 95 /* 96 * Reverse the order of first four dotted entries of in. 97 * Out must contain space for at least strlen(in) characters. 98 * The result does not include any leading 0s of in. 99 */ 100 static void 101 ipreverse(char *in, char *out) 102 { 103 char *pos[4]; 104 int len[4]; 105 char *p, *start; 106 int i = 0; 107 int leading = 1; 108 109 /* Fill-in element positions and lengths: pos[], len[]. */ 110 start = p = in; 111 for (;;) { 112 if (*p == '.' || *p == '\0') { 113 /* Leading 0? */ 114 if (leading && p - start == 1 && *start == '0') 115 len[i] = 0; 116 else { 117 len[i] = p - start; 118 leading = 0; 119 } 120 pos[i] = start; 121 start = p + 1; 122 i++; 123 } 124 if (i == 4) 125 break; 126 if (*p == 0) { 127 for (; i < 4; i++) { 128 pos[i] = p; 129 len[i] = 0; 130 } 131 break; 132 } 133 p++; 134 } 135 136 /* Copy the entries in reverse order */ 137 p = out; 138 leading = 1; 139 for (i = 3; i >= 0; i--) { 140 memcpy(p, pos[i], len[i]); 141 if (len[i]) 142 leading = 0; 143 p += len[i]; 144 /* Need a . separator? */ 145 if (!leading && i > 0 && len[i - 1]) 146 *p++ = '.'; 147 } 148 *p = '\0'; 149 } 150 151 static int 152 getnetanswer(querybuf *answer, int anslen, int net_i, struct netent *ne, 153 struct netent_data *ned, res_state statp) 154 { 155 156 HEADER *hp; 157 u_char *cp; 158 int n; 159 u_char *eom; 160 int type, class, ancount, qdcount, haveanswer; 161 char aux[MAXHOSTNAMELEN]; 162 char ans[MAXHOSTNAMELEN]; 163 char *in, *bp, *ep, **ap; 164 165 /* 166 * find first satisfactory answer 167 * 168 * answer --> +------------+ ( MESSAGE ) 169 * | Header | 170 * +------------+ 171 * | Question | the question for the name server 172 * +------------+ 173 * | Answer | RRs answering the question 174 * +------------+ 175 * | Authority | RRs pointing toward an authority 176 * | Additional | RRs holding additional information 177 * +------------+ 178 */ 179 eom = answer->buf + anslen; 180 hp = &answer->hdr; 181 ancount = ntohs(hp->ancount); /* #/records in the answer section */ 182 qdcount = ntohs(hp->qdcount); /* #/entries in the question section */ 183 bp = ned->netbuf; 184 ep = ned->netbuf + sizeof(ned->netbuf); 185 cp = answer->buf + HFIXEDSZ; 186 if (!qdcount) { 187 if (hp->aa) 188 RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); 189 else 190 RES_SET_H_ERRNO(statp, TRY_AGAIN); 191 return (-1); 192 } 193 while (qdcount-- > 0) 194 cp += __dn_skipname(cp, eom) + QFIXEDSZ; 195 ap = ned->net_aliases; 196 *ap = NULL; 197 ne->n_aliases = ned->net_aliases; 198 haveanswer = 0; 199 while (--ancount >= 0 && cp < eom) { 200 n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 201 if ((n < 0) || !res_dnok(bp)) 202 break; 203 cp += n; 204 ans[0] = '\0'; 205 (void)strncpy(&ans[0], bp, sizeof(ans) - 1); 206 ans[sizeof(ans) - 1] = '\0'; 207 GETSHORT(type, cp); 208 GETSHORT(class, cp); 209 cp += INT32SZ; /* TTL */ 210 GETSHORT(n, cp); 211 if (class == C_IN && type == T_PTR) { 212 n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 213 if ((n < 0) || !res_hnok(bp)) { 214 cp += n; 215 return (-1); 216 } 217 cp += n; 218 *ap++ = bp; 219 n = strlen(bp) + 1; 220 bp += n; 221 ne->n_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC; 222 haveanswer++; 223 } 224 } 225 if (haveanswer) { 226 *ap = NULL; 227 switch (net_i) { 228 case BYADDR: 229 ne->n_name = *ne->n_aliases; 230 ne->n_net = 0L; 231 break; 232 case BYNAME: 233 in = *ne->n_aliases; 234 n = strlen(ans) + 1; 235 if (ep - bp < n) { 236 RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 237 errno = ENOBUFS; 238 return (-1); 239 } 240 strlcpy(bp, ans, ep - bp); 241 ne->n_name = bp; 242 if (strlen(in) + 1 > sizeof(aux)) { 243 RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 244 errno = ENOBUFS; 245 return (-1); 246 } 247 ipreverse(in, aux); 248 ne->n_net = inet_network(aux); 249 break; 250 } 251 ne->n_aliases++; 252 return (0); 253 } 254 RES_SET_H_ERRNO(statp, TRY_AGAIN); 255 return (-1); 256 } 257 258 int 259 _dns_getnetbyaddr(void *rval, void *cb_data, va_list ap) 260 { 261 uint32_t net; 262 int net_type; 263 char *buffer; 264 size_t buflen; 265 int *errnop, *h_errnop; 266 struct netent *nptr, ne; 267 struct netent_data *ned; 268 unsigned int netbr[4]; 269 int nn, anslen, error; 270 querybuf *buf; 271 char qbuf[MAXDNAME]; 272 uint32_t net2; 273 res_state statp; 274 275 net = va_arg(ap, uint32_t); 276 net_type = va_arg(ap, int); 277 nptr = va_arg(ap, struct netent *); 278 buffer = va_arg(ap, char *); 279 buflen = va_arg(ap, size_t); 280 errnop = va_arg(ap, int *); 281 h_errnop = va_arg(ap, int *); 282 283 statp = __res_state(); 284 if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) { 285 RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 286 *h_errnop = statp->res_h_errno; 287 return (NS_UNAVAIL); 288 } 289 290 if ((ned = __netent_data_init()) == NULL) { 291 RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 292 *h_errnop = statp->res_h_errno; 293 return (NS_UNAVAIL); 294 } 295 296 *((struct netent **)rval) = NULL; 297 298 if (net_type != AF_INET) { 299 RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 300 *h_errnop = statp->res_h_errno; 301 return (NS_UNAVAIL); 302 } 303 304 for (nn = 4, net2 = net; net2; net2 >>= 8) 305 netbr[--nn] = net2 & 0xff; 306 switch (nn) { 307 case 3: /* Class A */ 308 sprintf(qbuf, "0.0.0.%u.in-addr.arpa", netbr[3]); 309 break; 310 case 2: /* Class B */ 311 sprintf(qbuf, "0.0.%u.%u.in-addr.arpa", netbr[3], netbr[2]); 312 break; 313 case 1: /* Class C */ 314 sprintf(qbuf, "0.%u.%u.%u.in-addr.arpa", netbr[3], netbr[2], 315 netbr[1]); 316 break; 317 case 0: /* Class D - E */ 318 sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa", netbr[3], netbr[2], 319 netbr[1], netbr[0]); 320 break; 321 } 322 if ((buf = malloc(sizeof(*buf))) == NULL) { 323 RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 324 *h_errnop = statp->res_h_errno; 325 return (NS_NOTFOUND); 326 } 327 anslen = res_nquery(statp, qbuf, C_IN, T_PTR, (u_char *)buf, 328 sizeof(*buf)); 329 if (anslen < 0) { 330 free(buf); 331 #ifdef DEBUG 332 if (statp->options & RES_DEBUG) 333 printf("res_nsearch failed\n"); 334 #endif 335 *h_errnop = statp->res_h_errno; 336 return (NS_UNAVAIL); 337 } else if (anslen > sizeof(*buf)) { 338 free(buf); 339 #ifdef DEBUG 340 if (statp->options & RES_DEBUG) 341 printf("res_nsearch static buffer too small\n"); 342 #endif 343 *h_errnop = statp->res_h_errno; 344 return (NS_UNAVAIL); 345 } 346 error = getnetanswer(buf, anslen, BYADDR, &ne, ned, statp); 347 free(buf); 348 if (error == 0) { 349 /* Strip trailing zeros */ 350 while ((net & 0xff) == 0 && net != 0) 351 net >>= 8; 352 ne.n_net = net; 353 if (__copy_netent(&ne, nptr, buffer, buflen) != 0) { 354 *errnop = errno; 355 RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 356 *h_errnop = statp->res_h_errno; 357 return (NS_RETURN); 358 } 359 *((struct netent **)rval) = nptr; 360 return (NS_SUCCESS); 361 } 362 *h_errnop = statp->res_h_errno; 363 return (NS_NOTFOUND); 364 } 365 366 int 367 _dns_getnetbyname(void *rval, void *cb_data, va_list ap) 368 { 369 const char *net; 370 char *buffer; 371 size_t buflen; 372 int *errnop, *h_errnop; 373 struct netent *nptr, ne; 374 struct netent_data *ned; 375 int anslen, error; 376 querybuf *buf; 377 char qbuf[MAXDNAME]; 378 res_state statp; 379 380 net = va_arg(ap, const char *); 381 nptr = va_arg(ap, struct netent *); 382 buffer = va_arg(ap, char *); 383 buflen = va_arg(ap, size_t); 384 errnop = va_arg(ap, int *); 385 h_errnop = va_arg(ap, int *); 386 387 statp = __res_state(); 388 if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) { 389 RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 390 *h_errnop = statp->res_h_errno; 391 return (NS_UNAVAIL); 392 } 393 if ((ned = __netent_data_init()) == NULL) { 394 RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 395 *h_errnop = statp->res_h_errno; 396 return (NS_UNAVAIL); 397 } 398 if ((buf = malloc(sizeof(*buf))) == NULL) { 399 RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 400 *h_errnop = statp->res_h_errno; 401 return (NS_NOTFOUND); 402 } 403 404 *((struct netent **)rval) = NULL; 405 406 strncpy(qbuf, net, sizeof(qbuf) - 1); 407 qbuf[sizeof(qbuf) - 1] = '\0'; 408 anslen = res_nsearch(statp, qbuf, C_IN, T_PTR, (u_char *)buf, 409 sizeof(*buf)); 410 if (anslen < 0) { 411 free(buf); 412 #ifdef DEBUG 413 if (statp->options & RES_DEBUG) 414 printf("res_nsearch failed\n"); 415 #endif 416 return (NS_UNAVAIL); 417 } else if (anslen > sizeof(*buf)) { 418 free(buf); 419 #ifdef DEBUG 420 if (statp->options & RES_DEBUG) 421 printf("res_search static buffer too small\n"); 422 #endif 423 return (NS_UNAVAIL); 424 } 425 error = getnetanswer(buf, anslen, BYNAME, &ne, ned, statp); 426 free(buf); 427 if (error != 0) { 428 *h_errnop = statp->res_h_errno; 429 return (NS_NOTFOUND); 430 } 431 if (__copy_netent(&ne, nptr, buffer, buflen) != 0) { 432 *errnop = errno; 433 RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 434 *h_errnop = statp->res_h_errno; 435 return (NS_RETURN); 436 } 437 *((struct netent **)rval) = nptr; 438 return (NS_SUCCESS); 439 } 440 441 void 442 _setnetdnsent(int stayopen) 443 { 444 res_state statp; 445 446 statp = __res_state(); 447 if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) 448 return; 449 if (stayopen) 450 statp->options |= RES_STAYOPEN | RES_USEVC; 451 } 452 453 void 454 _endnetdnsent(void) 455 { 456 res_state statp; 457 458 statp = __res_state(); 459 statp->options &= ~(RES_STAYOPEN | RES_USEVC); 460 res_nclose(statp); 461 } 462