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