1/* $NetBSD: res_data.c,v 1.15 2024/01/23 17:24:38 christos Exp $ */ 2 3/* 4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (c) 1995-1999 by Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20#include <sys/cdefs.h> 21#if defined(LIBC_SCCS) && !defined(lint) 22#ifdef notdef 23static const char rcsid[] = "Id: res_data.c,v 1.7 2008/12/11 09:59:00 marka Exp"; 24#else 25__RCSID("$NetBSD: res_data.c,v 1.15 2024/01/23 17:24:38 christos Exp $"); 26#endif 27#endif /* LIBC_SCCS and not lint */ 28 29#include "port_before.h" 30 31#include "namespace.h" 32#include <sys/types.h> 33#include <sys/param.h> 34#include <sys/socket.h> 35#include <sys/time.h> 36 37#include <netinet/in.h> 38#include <arpa/inet.h> 39#include <arpa/nameser.h> 40 41#include <ctype.h> 42#include <netdb.h> 43#include <resolv.h> 44#include <res_update.h> 45#include <stdio.h> 46#include <stdlib.h> 47#include <string.h> 48#include <unistd.h> 49 50#include "port_after.h" 51 52#include "res_private.h" 53 54#ifdef __weak_alias 55__weak_alias(res_init,_res_init) 56__weak_alias(res_mkquery,_res_mkquery) 57__weak_alias(res_query,_res_query) 58__weak_alias(res_search,_res_search) 59__weak_alias(res_send,__res_send) 60__weak_alias(res_close,__res_close) 61/* XXX: these leaked in the old bind8 libc */ 62__weak_alias(res_querydomain,__res_querydomain) 63__weak_alias(res_send_setqhook,__res_send_setqhook) 64__weak_alias(res_send_setrhook,__res_send_setrhook) 65#if 0 66__weak_alias(p_query,__p_query) 67__weak_alias(fp_query,__fp_query) 68__weak_alias(fp_nquery,__fp_nquery) 69__weak_alias(res_isourserver,__res_isourserver) 70__weak_alias(res_opt,_res_opt) 71__weak_alias(hostalias,__hostalias) 72#endif 73#endif 74 75const char *_res_opcodes[] = { 76 "QUERY", 77 "IQUERY", 78 "CQUERYM", 79 "CQUERYU", /*%< experimental */ 80 "NOTIFY", /*%< experimental */ 81 "UPDATE", 82 "6", 83 "7", 84 "8", 85 "9", 86 "10", 87 "11", 88 "12", 89 "13", 90 "ZONEINIT", 91 "ZONEREF", 92}; 93 94#ifdef BIND_UPDATE 95const char *_res_sectioncodes[] = { 96 "ZONE", 97 "PREREQUISITES", 98 "UPDATE", 99 "ADDITIONAL", 100}; 101#endif 102 103#ifndef __BIND_NOSTATIC 104extern struct __res_state _nres; 105 106/* Proto. */ 107 108int res_ourserver_p(const res_state, const struct sockaddr *); 109 110int 111res_init(void) { 112 int rv; 113#ifdef COMPAT__RES 114 /* 115 * Compatibility with program that were accessing _res directly 116 * to set options. We keep another struct res that is the same 117 * size as the original res structure, and then copy fields to 118 * it so that we achieve the same initialization 119 */ 120 res_state ores = __res_get_old_state(); 121 122 if (ores->options != 0) 123 _nres.options = ores->options; 124 if (ores->retrans != 0) 125 _nres.retrans = ores->retrans; 126 if (ores->retry != 0) 127 _nres.retry = ores->retry; 128#endif 129 130 /* 131 * These three fields used to be statically initialized. This made 132 * it hard to use this code in a shared library. It is necessary, 133 * now that we're doing dynamic initialization here, that we preserve 134 * the old semantics: if an application modifies one of these three 135 * fields of _res before res_init() is called, res_init() will not 136 * alter them. Of course, if an application is setting them to 137 * _zero_ before calling res_init(), hoping to override what used 138 * to be the static default, we can't detect it and unexpected results 139 * will follow. Zero for any of these fields would make no sense, 140 * so one can safely assume that the applications were already getting 141 * unexpected results. 142 * 143 * _nres.options is tricky since some apps were known to diddle the bits 144 * before res_init() was first called. We can't replicate that semantic 145 * with dynamic initialization (they may have turned bits off that are 146 * set in RES_DEFAULT). Our solution is to declare such applications 147 * "broken". They could fool us by setting RES_INIT but none do (yet). 148 */ 149 if (!_nres.retrans) 150 _nres.retrans = RES_TIMEOUT; 151 if (!_nres.retry) 152 _nres.retry = 4; 153 if (!(_nres.options & RES_INIT)) 154 _nres.options = RES_DEFAULT; 155 156 /* 157 * This one used to initialize implicitly to zero, so unless the app 158 * has set it to something in particular, we can randomize it now. 159 */ 160 if (!_nres.id) 161 _nres.id = res_nrandomid(&_nres); 162 163 rv = __res_vinit(&_nres, 1); 164#ifdef COMPAT__RES 165 __res_put_old_state(&_nres); 166#endif 167 return rv; 168} 169 170void 171p_query(const u_char *msg) { 172 fp_query(msg, stdout); 173} 174 175void 176fp_query(const u_char *msg, FILE *file) { 177 fp_nquery(msg, PACKETSZ, file); 178} 179 180void 181fp_nquery(const u_char *msg, int len, FILE *file) { 182 if ((_nres.options & RES_INIT) == 0U && res_init() == -1) 183 return; 184 185 res_pquery(&_nres, msg, len, file); 186} 187 188int 189res_mkquery(int op, /*!< opcode of query */ 190 const char *dname, /*!< domain name */ 191 int class, int type, /*!< class and type of query */ 192 const u_char *data, /*!< resource record data */ 193 int datalen, /*!< length of data */ 194 const u_char *newrr_in, /*!< new rr for modify or append */ 195 u_char *buf, /*!< buffer to put query */ 196 int buflen) /*!< size of buffer */ 197{ 198 if ((_nres.options & RES_INIT) == 0U && res_init() == -1) { 199 RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); 200 return (-1); 201 } 202 return (res_nmkquery(&_nres, op, dname, class, type, 203 data, datalen, 204 newrr_in, buf, buflen)); 205} 206 207#ifdef _LIBRESOLV 208int 209res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { 210 if ((_nres.options & RES_INIT) == 0U && res_init() == -1) { 211 RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); 212 return (-1); 213 } 214 215 return (res_nmkupdate(&_nres, rrecp_in, buf, buflen)); 216} 217#endif 218 219int 220res_query(const char *name, /*!< domain name */ 221 int class, int type, /*!< class and type of query */ 222 u_char *answer, /*!< buffer to put answer */ 223 int anslen) /*!< size of answer buffer */ 224{ 225 if ((_nres.options & RES_INIT) == 0U && res_init() == -1) { 226 RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); 227 return (-1); 228 } 229 return (res_nquery(&_nres, name, class, type, answer, anslen)); 230} 231 232void 233res_send_setqhook(res_send_qhook hook) { 234 _nres.qhook = hook; 235} 236 237void 238res_send_setrhook(res_send_rhook hook) { 239 _nres.rhook = hook; 240} 241 242int 243res_isourserver(const struct sockaddr_in *inp) { 244 return (res_ourserver_p(&_nres, (const struct sockaddr *)(const void *)inp)); 245} 246 247int 248res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { 249 if ((_nres.options & RES_INIT) == 0U && res_init() == -1) { 250 /* errno should have been set by res_init() in this case. */ 251 return (-1); 252 } 253 254 return (res_nsend(&_nres, buf, buflen, ans, anssiz)); 255} 256 257#ifdef _LIBRESOLV 258int 259res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key, 260 u_char *ans, int anssiz) 261{ 262 if ((_nres.options & RES_INIT) == 0U && res_init() == -1) { 263 /* errno should have been set by res_init() in this case. */ 264 return (-1); 265 } 266 267 return (res_nsendsigned(&_nres, buf, buflen, key, ans, anssiz)); 268} 269#endif 270 271void 272res_close(void) { 273 res_nclose(&_nres); 274} 275 276#ifdef _LIBRESOLV 277int 278res_update(ns_updrec *rrecp_in) { 279 if ((_nres.options & RES_INIT) == 0U && res_init() == -1) { 280 RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); 281 return (-1); 282 } 283 284 return (res_nupdate(&_nres, rrecp_in, NULL)); 285} 286#endif 287 288int 289res_search(const char *name, /*!< domain name */ 290 int class, int type, /*!< class and type of query */ 291 u_char *answer, /*!< buffer to put answer */ 292 int anslen) /*!< size of answer */ 293{ 294 if ((_nres.options & RES_INIT) == 0U && res_init() == -1) { 295 RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); 296 return (-1); 297 } 298 299 return (res_nsearch(&_nres, name, class, type, answer, anslen)); 300} 301 302int 303res_querydomain(const char *name, 304 const char *domain, 305 int class, int type, /*!< class and type of query */ 306 u_char *answer, /*!< buffer to put answer */ 307 int anslen) /*!< size of answer */ 308{ 309 if ((_nres.options & RES_INIT) == 0U && res_init() == -1) { 310 RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); 311 return (-1); 312 } 313 314 return (res_nquerydomain(&_nres, name, domain, 315 class, type, 316 answer, anslen)); 317} 318 319int 320res_opt(int a, u_char *b, int c, int d) 321{ 322 return res_nopt(&_nres, a, b, c, d); 323} 324 325u_int 326res_randomid(void) { 327 if ((_nres.options & RES_INIT) == 0U && res_init() == -1) { 328 RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); 329 return (u_int)-1; 330 } 331 332 return (res_nrandomid(&_nres)); 333} 334 335const char * 336hostalias(const char *name) { 337 static char abuf[MAXDNAME]; 338 339 return (res_hostalias(&_nres, name, abuf, sizeof abuf)); 340} 341 342#ifdef ultrix 343int 344local_hostname_length(const char *hostname) { 345 int len_host, len_domain; 346 347 if (!*_nres.defdname) 348 res_init(); 349 len_host = strlen(hostname); 350 len_domain = strlen(_nres.defdname); 351 if (len_host > len_domain && 352 !strcasecmp(hostname + len_host - len_domain, _nres.defdname) && 353 hostname[len_host - len_domain - 1] == '.') 354 return (len_host - len_domain - 1); 355 return (0); 356} 357#endif /*ultrix*/ 358 359#endif 360 361/*! \file */ 362