1 /* 2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (c) 1996,1999 by Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #if defined(LIBC_SCCS) && !defined(lint) 19 static const char rcsid[] = "$Id: gen_ho.c,v 1.5 2006/03/09 23:57:56 marka Exp $"; 20 #endif /* LIBC_SCCS and not lint */ 21 22 /* Imports */ 23 24 #include "port_before.h" 25 26 #include <sys/types.h> 27 28 #include <netinet/in.h> 29 #include <arpa/nameser.h> 30 31 #include <errno.h> 32 #include <stdlib.h> 33 #include <netdb.h> 34 #include <resolv.h> 35 #include <stdio.h> 36 #include <string.h> 37 38 #include <isc/memcluster.h> 39 #include <irs.h> 40 41 #include "port_after.h" 42 43 #include "irs_p.h" 44 #include "gen_p.h" 45 46 /* Definitions */ 47 48 struct pvt { 49 struct irs_rule * rules; 50 struct irs_rule * rule; 51 struct irs_ho * ho; 52 struct __res_state * res; 53 void (*free_res)(void *); 54 }; 55 56 /* Forwards */ 57 58 static void ho_close(struct irs_ho *this); 59 static struct hostent * ho_byname(struct irs_ho *this, const char *name); 60 static struct hostent * ho_byname2(struct irs_ho *this, const char *name, 61 int af); 62 static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr, 63 int len, int af); 64 static struct hostent * ho_next(struct irs_ho *this); 65 static void ho_rewind(struct irs_ho *this); 66 static void ho_minimize(struct irs_ho *this); 67 static struct __res_state * ho_res_get(struct irs_ho *this); 68 static void ho_res_set(struct irs_ho *this, 69 struct __res_state *res, 70 void (*free_res)(void *)); 71 static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name, 72 const struct addrinfo *pai); 73 74 static int init(struct irs_ho *this); 75 76 /* Exports */ 77 78 struct irs_ho * 79 irs_gen_ho(struct irs_acc *this) { 80 struct gen_p *accpvt = (struct gen_p *)this->private; 81 struct irs_ho *ho; 82 struct pvt *pvt; 83 84 if (!(pvt = memget(sizeof *pvt))) { 85 errno = ENOMEM; 86 return (NULL); 87 } 88 memset(pvt, 0, sizeof *pvt); 89 if (!(ho = memget(sizeof *ho))) { 90 memput(pvt, sizeof *pvt); 91 errno = ENOMEM; 92 return (NULL); 93 } 94 memset(ho, 0x5e, sizeof *ho); 95 pvt->rules = accpvt->map_rules[irs_ho]; 96 pvt->rule = pvt->rules; 97 ho->private = pvt; 98 ho->close = ho_close; 99 ho->byname = ho_byname; 100 ho->byname2 = ho_byname2; 101 ho->byaddr = ho_byaddr; 102 ho->next = ho_next; 103 ho->rewind = ho_rewind; 104 ho->minimize = ho_minimize; 105 ho->res_get = ho_res_get; 106 ho->res_set = ho_res_set; 107 ho->addrinfo = ho_addrinfo; 108 return (ho); 109 } 110 111 /* Methods. */ 112 113 static void 114 ho_close(struct irs_ho *this) { 115 struct pvt *pvt = (struct pvt *)this->private; 116 117 ho_minimize(this); 118 if (pvt->res && pvt->free_res) 119 (*pvt->free_res)(pvt->res); 120 memput(pvt, sizeof *pvt); 121 memput(this, sizeof *this); 122 } 123 124 static struct hostent * 125 ho_byname(struct irs_ho *this, const char *name) { 126 struct pvt *pvt = (struct pvt *)this->private; 127 struct irs_rule *rule; 128 struct hostent *rval; 129 struct irs_ho *ho; 130 int therrno = NETDB_INTERNAL; 131 int softerror = 0; 132 133 if (init(this) == -1) 134 return (NULL); 135 136 for (rule = pvt->rules; rule; rule = rule->next) { 137 ho = rule->inst->ho; 138 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 139 errno = 0; 140 rval = (*ho->byname)(ho, name); 141 if (rval != NULL) 142 return (rval); 143 if (softerror == 0 && 144 pvt->res->res_h_errno != HOST_NOT_FOUND && 145 pvt->res->res_h_errno != NETDB_INTERNAL) { 146 softerror = 1; 147 therrno = pvt->res->res_h_errno; 148 } 149 if (rule->flags & IRS_CONTINUE) 150 continue; 151 /* 152 * The value TRY_AGAIN can mean that the service 153 * is not available, or just that this particular name 154 * cannot be resolved now. We use the errno ECONNREFUSED 155 * to distinguish. If a lookup sets that errno when 156 * H_ERRNO is TRY_AGAIN, we continue to try other lookup 157 * functions, otherwise we return the TRY_AGAIN error. 158 */ 159 if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED) 160 break; 161 } 162 if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND) 163 RES_SET_H_ERRNO(pvt->res, therrno); 164 return (NULL); 165 } 166 167 static struct hostent * 168 ho_byname2(struct irs_ho *this, const char *name, int af) { 169 struct pvt *pvt = (struct pvt *)this->private; 170 struct irs_rule *rule; 171 struct hostent *rval; 172 struct irs_ho *ho; 173 int therrno = NETDB_INTERNAL; 174 int softerror = 0; 175 176 if (init(this) == -1) 177 return (NULL); 178 179 for (rule = pvt->rules; rule; rule = rule->next) { 180 ho = rule->inst->ho; 181 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 182 errno = 0; 183 rval = (*ho->byname2)(ho, name, af); 184 if (rval != NULL) 185 return (rval); 186 if (softerror == 0 && 187 pvt->res->res_h_errno != HOST_NOT_FOUND && 188 pvt->res->res_h_errno != NETDB_INTERNAL) { 189 softerror = 1; 190 therrno = pvt->res->res_h_errno; 191 } 192 if (rule->flags & IRS_CONTINUE) 193 continue; 194 /* 195 * See the comments in ho_byname() explaining 196 * the interpretation of TRY_AGAIN and ECONNREFUSED. 197 */ 198 if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED) 199 break; 200 } 201 if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND) 202 RES_SET_H_ERRNO(pvt->res, therrno); 203 return (NULL); 204 } 205 206 static struct hostent * 207 ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) { 208 struct pvt *pvt = (struct pvt *)this->private; 209 struct irs_rule *rule; 210 struct hostent *rval; 211 struct irs_ho *ho; 212 int therrno = NETDB_INTERNAL; 213 int softerror = 0; 214 215 216 if (init(this) == -1) 217 return (NULL); 218 219 for (rule = pvt->rules; rule; rule = rule->next) { 220 ho = rule->inst->ho; 221 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 222 errno = 0; 223 rval = (*ho->byaddr)(ho, addr, len, af); 224 if (rval != NULL) 225 return (rval); 226 if (softerror == 0 && 227 pvt->res->res_h_errno != HOST_NOT_FOUND && 228 pvt->res->res_h_errno != NETDB_INTERNAL) { 229 softerror = 1; 230 therrno = pvt->res->res_h_errno; 231 } 232 233 if (rule->flags & IRS_CONTINUE) 234 continue; 235 /* 236 * See the comments in ho_byname() explaining 237 * the interpretation of TRY_AGAIN and ECONNREFUSED. 238 */ 239 if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED) 240 break; 241 } 242 if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND) 243 RES_SET_H_ERRNO(pvt->res, therrno); 244 return (NULL); 245 } 246 247 static struct hostent * 248 ho_next(struct irs_ho *this) { 249 struct pvt *pvt = (struct pvt *)this->private; 250 struct hostent *rval; 251 struct irs_ho *ho; 252 253 while (pvt->rule) { 254 ho = pvt->rule->inst->ho; 255 rval = (*ho->next)(ho); 256 if (rval) 257 return (rval); 258 if (!(pvt->rule->flags & IRS_CONTINUE)) 259 break; 260 pvt->rule = pvt->rule->next; 261 if (pvt->rule) { 262 ho = pvt->rule->inst->ho; 263 (*ho->rewind)(ho); 264 } 265 } 266 return (NULL); 267 } 268 269 static void 270 ho_rewind(struct irs_ho *this) { 271 struct pvt *pvt = (struct pvt *)this->private; 272 struct irs_ho *ho; 273 274 pvt->rule = pvt->rules; 275 if (pvt->rule) { 276 ho = pvt->rule->inst->ho; 277 (*ho->rewind)(ho); 278 } 279 } 280 281 static void 282 ho_minimize(struct irs_ho *this) { 283 struct pvt *pvt = (struct pvt *)this->private; 284 struct irs_rule *rule; 285 286 if (pvt->res) 287 res_nclose(pvt->res); 288 for (rule = pvt->rules; rule != NULL; rule = rule->next) { 289 struct irs_ho *ho = rule->inst->ho; 290 291 (*ho->minimize)(ho); 292 } 293 } 294 295 static struct __res_state * 296 ho_res_get(struct irs_ho *this) { 297 struct pvt *pvt = (struct pvt *)this->private; 298 299 if (!pvt->res) { 300 struct __res_state *res; 301 res = (struct __res_state *)malloc(sizeof *res); 302 if (!res) { 303 errno = ENOMEM; 304 return (NULL); 305 } 306 memset(res, 0, sizeof *res); 307 ho_res_set(this, res, free); 308 } 309 310 return (pvt->res); 311 } 312 313 static void 314 ho_res_set(struct irs_ho *this, struct __res_state *res, 315 void (*free_res)(void *)) { 316 struct pvt *pvt = (struct pvt *)this->private; 317 struct irs_rule *rule; 318 319 if (pvt->res && pvt->free_res) { 320 res_nclose(pvt->res); 321 (*pvt->free_res)(pvt->res); 322 } 323 324 pvt->res = res; 325 pvt->free_res = free_res; 326 327 for (rule = pvt->rules; rule != NULL; rule = rule->next) { 328 struct irs_ho *ho = rule->inst->ho; 329 330 (*ho->res_set)(ho, pvt->res, NULL); 331 } 332 } 333 334 static struct addrinfo * 335 ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai) 336 { 337 struct pvt *pvt = (struct pvt *)this->private; 338 struct irs_rule *rule; 339 struct addrinfo *rval = NULL; 340 struct irs_ho *ho; 341 int therrno = NETDB_INTERNAL; 342 int softerror = 0; 343 344 if (init(this) == -1) 345 return (NULL); 346 347 for (rule = pvt->rules; rule; rule = rule->next) { 348 ho = rule->inst->ho; 349 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 350 errno = 0; 351 if (ho->addrinfo == NULL) /*%< for safety */ 352 continue; 353 rval = (*ho->addrinfo)(ho, name, pai); 354 if (rval != NULL) 355 return (rval); 356 if (softerror == 0 && 357 pvt->res->res_h_errno != HOST_NOT_FOUND && 358 pvt->res->res_h_errno != NETDB_INTERNAL) { 359 softerror = 1; 360 therrno = pvt->res->res_h_errno; 361 } 362 if (rule->flags & IRS_CONTINUE) 363 continue; 364 /* 365 * See the comments in ho_byname() explaining 366 * the interpretation of TRY_AGAIN and ECONNREFUSED. 367 */ 368 if (pvt->res->res_h_errno != TRY_AGAIN || 369 errno != ECONNREFUSED) 370 break; 371 } 372 if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND) 373 RES_SET_H_ERRNO(pvt->res, therrno); 374 return (NULL); 375 } 376 377 static int 378 init(struct irs_ho *this) { 379 struct pvt *pvt = (struct pvt *)this->private; 380 381 if (!pvt->res && !ho_res_get(this)) 382 return (-1); 383 384 if (((pvt->res->options & RES_INIT) == 0U) && 385 (res_ninit(pvt->res) == -1)) 386 return (-1); 387 388 return (0); 389 } 390 391 /*! \file */ 392