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: dns_sv.c,v 1.5 2005/04/27 04:56:23 sra Exp $"; 20#endif 21 22/* Imports */ 23 24#include "port_before.h" 25 26#include <sys/types.h> 27#include <netinet/in.h> 28 29#include <stdio.h> 30#include <string.h> 31#include <netdb.h> 32#include <ctype.h> 33#include <stdlib.h> 34#include <errno.h> 35 36#include <sys/types.h> 37#include <netinet/in.h> 38#include <arpa/nameser.h> 39#include <resolv.h> 40 41#include <isc/memcluster.h> 42#include <irs.h> 43 44#include "port_after.h" 45 46#include "irs_p.h" 47#include "hesiod.h" 48#include "dns_p.h" 49 50/* Definitions */ 51 52struct pvt { 53 struct dns_p * dns; 54 struct servent serv; 55 char * svbuf; 56 struct __res_state * res; 57 void (*free_res)(void *); 58}; 59 60/* Forward. */ 61 62static void sv_close(struct irs_sv *); 63static struct servent * sv_byname(struct irs_sv *, 64 const char *, const char *); 65static struct servent * sv_byport(struct irs_sv *, int, const char *); 66static struct servent * sv_next(struct irs_sv *); 67static void sv_rewind(struct irs_sv *); 68static void sv_minimize(struct irs_sv *); 69#ifdef SV_RES_SETGET 70static struct __res_state * sv_res_get(struct irs_sv *); 71static void sv_res_set(struct irs_sv *, 72 struct __res_state *, 73 void (*)(void *)); 74#endif 75 76static struct servent * parse_hes_list(struct irs_sv *, 77 char **, const char *); 78 79/* Public */ 80 81struct irs_sv * 82irs_dns_sv(struct irs_acc *this) { 83 struct dns_p *dns = (struct dns_p *)this->private; 84 struct irs_sv *sv; 85 struct pvt *pvt; 86 87 if (!dns || !dns->hes_ctx) { 88 errno = ENODEV; 89 return (NULL); 90 } 91 if (!(pvt = memget(sizeof *pvt))) { 92 errno = ENOMEM; 93 return (NULL); 94 } 95 memset(pvt, 0, sizeof *pvt); 96 pvt->dns = dns; 97 if (!(sv = memget(sizeof *sv))) { 98 memput(pvt, sizeof *pvt); 99 errno = ENOMEM; 100 return (NULL); 101 } 102 memset(sv, 0x5e, sizeof *sv); 103 sv->private = pvt; 104 sv->byname = sv_byname; 105 sv->byport = sv_byport; 106 sv->next = sv_next; 107 sv->rewind = sv_rewind; 108 sv->close = sv_close; 109 sv->minimize = sv_minimize; 110#ifdef SV_RES_SETGET 111 sv->res_get = sv_res_get; 112 sv->res_set = sv_res_set; 113#else 114 sv->res_get = NULL; /*%< sv_res_get; */ 115 sv->res_set = NULL; /*%< sv_res_set; */ 116#endif 117 return (sv); 118} 119 120/* Methods */ 121 122static void 123sv_close(struct irs_sv *this) { 124 struct pvt *pvt = (struct pvt *)this->private; 125 126 if (pvt->serv.s_aliases) 127 free(pvt->serv.s_aliases); 128 if (pvt->svbuf) 129 free(pvt->svbuf); 130 131 if (pvt->res && pvt->free_res) 132 (*pvt->free_res)(pvt->res); 133 memput(pvt, sizeof *pvt); 134 memput(this, sizeof *this); 135} 136 137static struct servent * 138sv_byname(struct irs_sv *this, const char *name, const char *proto) { 139 struct pvt *pvt = (struct pvt *)this->private; 140 struct dns_p *dns = pvt->dns; 141 struct servent *s; 142 char **hes_list; 143 144 if (!(hes_list = hesiod_resolve(dns->hes_ctx, name, "service"))) 145 return (NULL); 146 147 s = parse_hes_list(this, hes_list, proto); 148 hesiod_free_list(dns->hes_ctx, hes_list); 149 return (s); 150} 151 152static struct servent * 153sv_byport(struct irs_sv *this, int port, const char *proto) { 154 struct pvt *pvt = (struct pvt *)this->private; 155 struct dns_p *dns = pvt->dns; 156 struct servent *s; 157 char portstr[16]; 158 char **hes_list; 159 160 sprintf(portstr, "%d", ntohs(port)); 161 if (!(hes_list = hesiod_resolve(dns->hes_ctx, portstr, "port"))) 162 return (NULL); 163 164 s = parse_hes_list(this, hes_list, proto); 165 hesiod_free_list(dns->hes_ctx, hes_list); 166 return (s); 167} 168 169static struct servent * 170sv_next(struct irs_sv *this) { 171 UNUSED(this); 172 errno = ENODEV; 173 return (NULL); 174} 175 176static void 177sv_rewind(struct irs_sv *this) { 178 UNUSED(this); 179 /* NOOP */ 180} 181 182/* Private */ 183 184static struct servent * 185parse_hes_list(struct irs_sv *this, char **hes_list, const char *proto) { 186 struct pvt *pvt = (struct pvt *)this->private; 187 char *p, *cp, **cpp, **new; 188 int proto_len; 189 int num = 0; 190 int max = 0; 191 192 for (cpp = hes_list; *cpp; cpp++) { 193 cp = *cpp; 194 195 /* Strip away comments, if any. */ 196 if ((p = strchr(cp, '#'))) 197 *p = 0; 198 199 /* Check to make sure the protocol matches. */ 200 p = cp; 201 while (*p && !isspace((unsigned char)*p)) 202 p++; 203 if (!*p) 204 continue; 205 if (proto) { 206 proto_len = strlen(proto); 207 if (strncasecmp(++p, proto, proto_len) != 0) 208 continue; 209 if (p[proto_len] && !isspace(p[proto_len]&0xff)) 210 continue; 211 } 212 /* OK, we've got a live one. Let's parse it for real. */ 213 if (pvt->svbuf) 214 free(pvt->svbuf); 215 pvt->svbuf = strdup(cp); 216 217 p = pvt->svbuf; 218 pvt->serv.s_name = p; 219 while (*p && !isspace(*p&0xff)) 220 p++; 221 if (!*p) 222 continue; 223 *p++ = '\0'; 224 225 pvt->serv.s_proto = p; 226 while (*p && !isspace(*p&0xff)) 227 p++; 228 if (!*p) 229 continue; 230 *p++ = '\0'; 231 232 pvt->serv.s_port = htons((u_short) atoi(p)); 233 while (*p && !isspace(*p&0xff)) 234 p++; 235 if (*p) 236 *p++ = '\0'; 237 238 while (*p) { 239 if ((num + 1) >= max || !pvt->serv.s_aliases) { 240 max += 10; 241 new = realloc(pvt->serv.s_aliases, 242 max * sizeof(char *)); 243 if (!new) { 244 errno = ENOMEM; 245 goto cleanup; 246 } 247 pvt->serv.s_aliases = new; 248 } 249 pvt->serv.s_aliases[num++] = p; 250 while (*p && !isspace(*p&0xff)) 251 p++; 252 if (*p) 253 *p++ = '\0'; 254 } 255 if (!pvt->serv.s_aliases) 256 pvt->serv.s_aliases = malloc(sizeof(char *)); 257 if (!pvt->serv.s_aliases) 258 goto cleanup; 259 pvt->serv.s_aliases[num] = NULL; 260 return (&pvt->serv); 261 } 262 263 cleanup: 264 if (pvt->serv.s_aliases) { 265 free(pvt->serv.s_aliases); 266 pvt->serv.s_aliases = NULL; 267 } 268 if (pvt->svbuf) { 269 free(pvt->svbuf); 270 pvt->svbuf = NULL; 271 } 272 return (NULL); 273} 274 275static void 276sv_minimize(struct irs_sv *this) { 277 UNUSED(this); 278 /* NOOP */ 279} 280 281#ifdef SV_RES_SETGET 282static struct __res_state * 283sv_res_get(struct irs_sv *this) { 284 struct pvt *pvt = (struct pvt *)this->private; 285 struct dns_p *dns = pvt->dns; 286 287 return (__hesiod_res_get(dns->hes_ctx)); 288} 289 290static void 291sv_res_set(struct irs_sv *this, struct __res_state * res, 292 void (*free_res)(void *)) { 293 struct pvt *pvt = (struct pvt *)this->private; 294 struct dns_p *dns = pvt->dns; 295 296 __hesiod_res_set(dns->hes_ctx, res, free_res); 297} 298#endif 299 300/*! \file */ 301