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