1 /* $NetBSD: res_data.c,v 1.14 2009/10/24 05:35:37 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 23 static 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.14 2009/10/24 05:35:37 christos Exp $"); 26 #endif 27 #endif /* LIBC_SCCS and not lint */ 28 29 #include "port_before.h" 30 31 #include <sys/types.h> 32 #include <sys/param.h> 33 #include <sys/socket.h> 34 #include <sys/time.h> 35 36 #include <netinet/in.h> 37 #include <arpa/inet.h> 38 #include <arpa/nameser.h> 39 40 #include <ctype.h> 41 #include <netdb.h> 42 #include <resolv.h> 43 #include <res_update.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 49 #include "port_after.h" 50 51 #include "res_private.h" 52 53 #ifdef __weak_alias 54 __weak_alias(res_init,_res_init) 55 __weak_alias(res_mkquery,_res_mkquery) 56 __weak_alias(res_query,_res_query) 57 __weak_alias(res_search,_res_search) 58 __weak_alias(res_send,__res_send) 59 __weak_alias(res_close,__res_close) 60 /* XXX: these leaked in the old bind8 libc */ 61 __weak_alias(res_querydomain,__res_querydomain) 62 __weak_alias(res_send_setqhook,__res_send_setqhook) 63 __weak_alias(res_send_setrhook,__res_send_setrhook) 64 #if 0 65 __weak_alias(p_query,__p_query) 66 __weak_alias(fp_query,__fp_query) 67 __weak_alias(fp_nquery,__fp_nquery) 68 __weak_alias(res_isourserver,__res_isourserver) 69 __weak_alias(hostalias,__hostalias) 70 #endif 71 #endif 72 73 const char *_res_opcodes[] = { 74 "QUERY", 75 "IQUERY", 76 "CQUERYM", 77 "CQUERYU", /*%< experimental */ 78 "NOTIFY", /*%< experimental */ 79 "UPDATE", 80 "6", 81 "7", 82 "8", 83 "9", 84 "10", 85 "11", 86 "12", 87 "13", 88 "ZONEINIT", 89 "ZONEREF", 90 }; 91 92 #ifdef BIND_UPDATE 93 const char *_res_sectioncodes[] = { 94 "ZONE", 95 "PREREQUISITES", 96 "UPDATE", 97 "ADDITIONAL", 98 }; 99 #endif 100 101 #ifndef __BIND_NOSTATIC 102 extern struct __res_state _nres; 103 104 /* Proto. */ 105 106 int res_ourserver_p(const res_state, const struct sockaddr *); 107 108 int 109 res_init(void) { 110 int rv; 111 #ifdef COMPAT__RES 112 /* 113 * Compatibility with program that were accessing _res directly 114 * to set options. We keep another struct res that is the same 115 * size as the original res structure, and then copy fields to 116 * it so that we achieve the same initialization 117 */ 118 extern void *__res_get_old_state(void); 119 extern void __res_put_old_state(void *); 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 170 void 171 p_query(const u_char *msg) { 172 fp_query(msg, stdout); 173 } 174 175 void 176 fp_query(const u_char *msg, FILE *file) { 177 fp_nquery(msg, PACKETSZ, file); 178 } 179 180 void 181 fp_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 188 int 189 res_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 208 int 209 res_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 219 int 220 res_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 232 void 233 res_send_setqhook(res_send_qhook hook) { 234 _nres.qhook = hook; 235 } 236 237 void 238 res_send_setrhook(res_send_rhook hook) { 239 _nres.rhook = hook; 240 } 241 242 int 243 res_isourserver(const struct sockaddr_in *inp) { 244 return (res_ourserver_p(&_nres, (const struct sockaddr *)(const void *)inp)); 245 } 246 247 int 248 res_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 258 int 259 res_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 271 void 272 res_close(void) { 273 res_nclose(&_nres); 274 } 275 276 #ifdef _LIBRESOLV 277 int 278 res_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 288 int 289 res_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 302 int 303 res_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 319 u_int 320 res_randomid(void) { 321 if ((_nres.options & RES_INIT) == 0U && res_init() == -1) { 322 RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); 323 return (u_int)-1; 324 } 325 326 return (res_nrandomid(&_nres)); 327 } 328 329 const char * 330 hostalias(const char *name) { 331 static char abuf[MAXDNAME]; 332 333 return (res_hostalias(&_nres, name, abuf, sizeof abuf)); 334 } 335 336 #ifdef ultrix 337 int 338 local_hostname_length(const char *hostname) { 339 int len_host, len_domain; 340 341 if (!*_nres.defdname) 342 res_init(); 343 len_host = strlen(hostname); 344 len_domain = strlen(_nres.defdname); 345 if (len_host > len_domain && 346 !strcasecmp(hostname + len_host - len_domain, _nres.defdname) && 347 hostname[len_host - len_domain - 1] == '.') 348 return (len_host - len_domain - 1); 349 return (0); 350 } 351 #endif /*ultrix*/ 352 353 #endif 354 355 /*! \file */ 356