1 /* $NetBSD: res_data.c,v 1.8 2004/06/09 18:07:03 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.1.206.2 2004/03/16 12:34:18 marka Exp"; 24 #else 25 __RCSID("$NetBSD: res_data.c,v 1.8 2004/06/09 18:07:03 christos Exp $"); 26 #endif 27 #endif /* LIBC_SCCS and not lint */ 28 29 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_private.h" 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 48 49 __LIBC_HIDDEN__ 50 const char * const _res_opcodes[] = { 51 "QUERY", 52 "IQUERY", 53 "CQUERYM", 54 "CQUERYU", /* experimental */ 55 "NOTIFY", /* experimental */ 56 "UPDATE", 57 "6", 58 "7", 59 "8", 60 "9", 61 "10", 62 "11", 63 "12", 64 "13", 65 "ZONEINIT", 66 "ZONEREF", 67 }; 68 69 #ifdef BIND_UPDATE 70 const char * const _res_sectioncodes[] = { 71 "ZONE", 72 "PREREQUISITES", 73 "UPDATE", 74 "ADDITIONAL", 75 }; 76 #endif 77 78 #ifndef __BIND_NOSTATIC 79 extern struct __res_state _nres; 80 81 /* Proto. */ 82 83 int res_ourserver_p(const res_state, const struct sockaddr *); 84 85 #ifdef ANDROID_CHANGES 86 static int res_need_init() { 87 return ((_nres.options & RES_INIT) == 0U) || res_get_dns_changed(); 88 } 89 #else 90 #define res_need_init() ((_nres.options & RES_INIT) == 0U) 91 #endif 92 93 int 94 res_init(void) { 95 int rv; 96 extern int __res_vinit(res_state, int); 97 #ifdef COMPAT__RES 98 /* 99 * Compatibility with program that were accessing _res directly 100 * to set options. We keep another struct res that is the same 101 * size as the original res structure, and then copy fields to 102 * it so that we achieve the same initialization 103 */ 104 extern void *__res_get_old_state(void); 105 extern void __res_put_old_state(void *); 106 res_state ores = __res_get_old_state(); 107 108 if (ores->options != 0) 109 _nres.options = ores->options; 110 if (ores->retrans != 0) 111 _nres.retrans = ores->retrans; 112 if (ores->retry != 0) 113 _nres.retry = ores->retry; 114 #endif 115 116 /* 117 * These three fields used to be statically initialized. This made 118 * it hard to use this code in a shared library. It is necessary, 119 * now that we're doing dynamic initialization here, that we preserve 120 * the old semantics: if an application modifies one of these three 121 * fields of _res before res_init() is called, res_init() will not 122 * alter them. Of course, if an application is setting them to 123 * _zero_ before calling res_init(), hoping to override what used 124 * to be the static default, we can't detect it and unexpected results 125 * will follow. Zero for any of these fields would make no sense, 126 * so one can safely assume that the applications were already getting 127 * unexpected results. 128 * 129 * _nres.options is tricky since some apps were known to diddle the bits 130 * before res_init() was first called. We can't replicate that semantic 131 * with dynamic initialization (they may have turned bits off that are 132 * set in RES_DEFAULT). Our solution is to declare such applications 133 * "broken". They could fool us by setting RES_INIT but none do (yet). 134 */ 135 if (!_nres.retrans) 136 _nres.retrans = RES_TIMEOUT; 137 if (!_nres.retry) 138 _nres.retry = 4; 139 if (!(_nres.options & RES_INIT)) 140 _nres.options = RES_DEFAULT; 141 142 /* 143 * This one used to initialize implicitly to zero, so unless the app 144 * has set it to something in particular, we can randomize it now. 145 */ 146 if (!_nres.id) 147 _nres.id = res_randomid(); 148 149 rv = __res_vinit(&_nres, 1); 150 #ifdef COMPAT__RES 151 __res_put_old_state(&_nres); 152 #endif 153 return rv; 154 } 155 156 void 157 p_query(const u_char *msg) { 158 fp_query(msg, stdout); 159 } 160 161 void 162 fp_query(const u_char *msg, FILE *file) { 163 fp_nquery(msg, PACKETSZ, file); 164 } 165 166 void 167 fp_nquery(const u_char *msg, int len, FILE *file) { 168 if (res_need_init() && res_init() == -1) 169 return; 170 171 res_pquery(&_nres, msg, len, file); 172 } 173 174 int 175 res_mkquery(int op, /* opcode of query */ 176 const char *dname, /* domain name */ 177 int class, int type, /* class and type of query */ 178 const u_char *data, /* resource record data */ 179 int datalen, /* length of data */ 180 const u_char *newrr_in, /* new rr for modify or append */ 181 u_char *buf, /* buffer to put query */ 182 int buflen) /* size of buffer */ 183 { 184 if (res_need_init() && res_init() == -1) { 185 RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); 186 return (-1); 187 } 188 return (res_nmkquery(&_nres, op, dname, class, type, 189 data, datalen, 190 newrr_in, buf, buflen)); 191 } 192 193 #ifdef _LIBRESOLV 194 int 195 res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { 196 if (res_need_init() && res_init() == -1) { 197 RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); 198 return (-1); 199 } 200 201 return (res_nmkupdate(&_nres, rrecp_in, buf, buflen)); 202 } 203 #endif 204 205 int 206 res_query(const char *name, /* domain name */ 207 int class, int type, /* class and type of query */ 208 u_char *answer, /* buffer to put answer */ 209 int anslen) /* size of answer buffer */ 210 { 211 if (res_need_init() && res_init() == -1) { 212 RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); 213 return (-1); 214 } 215 return (res_nquery(&_nres, name, class, type, answer, anslen)); 216 } 217 218 void 219 res_send_setqhook(res_send_qhook hook) { 220 _nres.qhook = hook; 221 } 222 223 void 224 res_send_setrhook(res_send_rhook hook) { 225 _nres.rhook = hook; 226 } 227 228 int 229 res_isourserver(const struct sockaddr_in *inp) { 230 return (res_ourserver_p(&_nres, (const struct sockaddr *)(const void *)inp)); 231 } 232 233 int 234 res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { 235 if (res_need_init() && res_init() == -1) { 236 /* errno should have been set by res_init() in this case. */ 237 return (-1); 238 } 239 240 return (res_nsend(&_nres, buf, buflen, ans, anssiz)); 241 } 242 243 #ifdef _LIBRESOLV 244 int 245 res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key, 246 u_char *ans, int anssiz) 247 { 248 if (res_need_init() && res_init() == -1) { 249 /* errno should have been set by res_init() in this case. */ 250 return (-1); 251 } 252 253 return (res_nsendsigned(&_nres, buf, buflen, key, ans, anssiz)); 254 } 255 #endif 256 257 void 258 res_close(void) { 259 res_nclose(&_nres); 260 } 261 262 #ifdef _LIBRESOLV 263 int 264 res_update(ns_updrec *rrecp_in) { 265 if (res_need_init() && res_init() == -1) { 266 RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); 267 return (-1); 268 } 269 270 return (res_nupdate(&_nres, rrecp_in, NULL)); 271 } 272 #endif 273 274 int 275 res_search(const char *name, /* domain name */ 276 int class, int type, /* class and type of query */ 277 u_char *answer, /* buffer to put answer */ 278 int anslen) /* size of answer */ 279 { 280 if (res_need_init() && res_init() == -1) { 281 RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); 282 return (-1); 283 } 284 285 return (res_nsearch(&_nres, name, class, type, answer, anslen)); 286 } 287 288 int 289 res_querydomain(const char *name, 290 const char *domain, 291 int class, int type, /* class and type of query */ 292 u_char *answer, /* buffer to put answer */ 293 int anslen) /* size of answer */ 294 { 295 if (res_need_init() && res_init() == -1) { 296 RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); 297 return (-1); 298 } 299 300 return (res_nquerydomain(&_nres, name, domain, 301 class, type, 302 answer, anslen)); 303 } 304 305 int 306 res_opt(int a, u_char *b, int c, int d) 307 { 308 return res_nopt(&_nres, a, b, c, d); 309 } 310 311 const char * 312 hostalias(const char *name) { 313 return NULL; 314 } 315 316 #ifdef ultrix 317 int 318 local_hostname_length(const char *hostname) { 319 int len_host, len_domain; 320 321 if (!*_nres.defdname) 322 res_init(); 323 len_host = strlen(hostname); 324 len_domain = strlen(_nres.defdname); 325 if (len_host > len_domain && 326 !strcasecmp(hostname + len_host - len_domain, _nres.defdname) && 327 hostname[len_host - len_domain - 1] == '.') 328 return (len_host - len_domain - 1); 329 return (0); 330 } 331 #endif /*ultrix*/ 332 333 #endif 334