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) 19static 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 48struct 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 58static void ho_close(struct irs_ho *this); 59static struct hostent * ho_byname(struct irs_ho *this, const char *name); 60static struct hostent * ho_byname2(struct irs_ho *this, const char *name, 61 int af); 62static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr, 63 int len, int af); 64static struct hostent * ho_next(struct irs_ho *this); 65static void ho_rewind(struct irs_ho *this); 66static void ho_minimize(struct irs_ho *this); 67static struct __res_state * ho_res_get(struct irs_ho *this); 68static void ho_res_set(struct irs_ho *this, 69 struct __res_state *res, 70 void (*free_res)(void *)); 71static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name, 72 const struct addrinfo *pai); 73 74static int init(struct irs_ho *this); 75 76/* Exports */ 77 78struct irs_ho * 79irs_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 113static void 114ho_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 124static struct hostent * 125ho_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 167static struct hostent * 168ho_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 206static struct hostent * 207ho_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 247static struct hostent * 248ho_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 269static void 270ho_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 281static void 282ho_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 295static struct __res_state * 296ho_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 313static void 314ho_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 334static struct addrinfo * 335ho_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 377static int 378init(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