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