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