1 /* 2 * Copyright 1997-2002 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 1996,1999 by Internet Software Consortium. 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 14 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 16 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 17 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 18 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 19 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20 * SOFTWARE. 21 */ 22 23 #pragma ident "%Z%%M% %I% %E% SMI" 24 25 #if defined(LIBC_SCCS) && !defined(lint) 26 static const char rcsid[] = "$Id: dns_sv.c,v 1.20 2001/05/29 05:48:33 marka Exp $"; 27 #endif 28 29 /* Imports */ 30 31 #include "port_before.h" 32 33 #include <sys/types.h> 34 #include <netinet/in.h> 35 36 #include <stdio.h> 37 #include <string.h> 38 #include <netdb.h> 39 #include <ctype.h> 40 #include <stdlib.h> 41 #include <errno.h> 42 43 #include <sys/types.h> 44 #include <netinet/in.h> 45 #include <arpa/nameser.h> 46 #include <resolv.h> 47 48 #include <isc/memcluster.h> 49 #include <irs.h> 50 51 #include "port_after.h" 52 53 #include "irs_p.h" 54 #include "hesiod.h" 55 #include "dns_p.h" 56 57 /* Definitions */ 58 59 struct pvt { 60 struct dns_p * dns; 61 struct servent serv; 62 char * svbuf; 63 struct __res_state * res; 64 void (*free_res)(void *); 65 }; 66 67 /* Forward. */ 68 69 static void sv_close(struct irs_sv *); 70 static struct servent * sv_byname(struct irs_sv *, 71 const char *, const char *); 72 static struct servent * sv_byport(struct irs_sv *, int, const char *); 73 static struct servent * sv_next(struct irs_sv *); 74 static void sv_rewind(struct irs_sv *); 75 static void sv_minimize(struct irs_sv *); 76 #ifdef SV_RES_SETGET 77 static struct __res_state * sv_res_get(struct irs_sv *); 78 static void sv_res_set(struct irs_sv *, 79 struct __res_state *, 80 void (*)(void *)); 81 #endif 82 83 static struct servent * parse_hes_list(struct irs_sv *, 84 char **, const char *); 85 86 /* Public */ 87 88 struct irs_sv * 89 irs_dns_sv(struct irs_acc *this) { 90 struct dns_p *dns = (struct dns_p *)this->private; 91 struct irs_sv *sv; 92 struct pvt *pvt; 93 94 if (!dns || !dns->hes_ctx) { 95 errno = ENODEV; 96 return (NULL); 97 } 98 if (!(pvt = memget(sizeof *pvt))) { 99 errno = ENOMEM; 100 return (NULL); 101 } 102 memset(pvt, 0, sizeof *pvt); 103 pvt->dns = dns; 104 if (!(sv = memget(sizeof *sv))) { 105 memput(pvt, sizeof *pvt); 106 errno = ENOMEM; 107 return (NULL); 108 } 109 memset(sv, 0x5e, sizeof *sv); 110 sv->private = pvt; 111 sv->byname = sv_byname; 112 sv->byport = sv_byport; 113 sv->next = sv_next; 114 sv->rewind = sv_rewind; 115 sv->close = sv_close; 116 sv->minimize = sv_minimize; 117 #ifdef SV_RES_SETGET 118 sv->res_get = sv_res_get; 119 sv->res_set = sv_res_set; 120 #else 121 sv->res_get = NULL; /* sv_res_get; */ 122 sv->res_set = NULL; /* sv_res_set; */ 123 #endif 124 return (sv); 125 } 126 127 /* Methods */ 128 129 static void 130 sv_close(struct irs_sv *this) { 131 struct pvt *pvt = (struct pvt *)this->private; 132 133 if (pvt->serv.s_aliases) 134 free(pvt->serv.s_aliases); 135 if (pvt->svbuf) 136 free(pvt->svbuf); 137 138 if (pvt->res && pvt->free_res) 139 (*pvt->free_res)(pvt->res); 140 memput(pvt, sizeof *pvt); 141 memput(this, sizeof *this); 142 } 143 144 static struct servent * 145 sv_byname(struct irs_sv *this, const char *name, const char *proto) { 146 struct pvt *pvt = (struct pvt *)this->private; 147 struct dns_p *dns = pvt->dns; 148 struct servent *s; 149 char **hes_list; 150 151 if (!(hes_list = hesiod_resolve(dns->hes_ctx, name, "service"))) 152 return (NULL); 153 154 s = parse_hes_list(this, hes_list, proto); 155 hesiod_free_list(dns->hes_ctx, hes_list); 156 return (s); 157 } 158 159 static struct servent * 160 sv_byport(struct irs_sv *this, int port, const char *proto) { 161 struct pvt *pvt = (struct pvt *)this->private; 162 struct dns_p *dns = pvt->dns; 163 struct servent *s; 164 char portstr[16]; 165 char **hes_list; 166 167 sprintf(portstr, "%d", ntohs(port)); 168 if (!(hes_list = hesiod_resolve(dns->hes_ctx, portstr, "port"))) 169 return (NULL); 170 171 s = parse_hes_list(this, hes_list, proto); 172 hesiod_free_list(dns->hes_ctx, hes_list); 173 return (s); 174 } 175 176 static struct servent * 177 sv_next(struct irs_sv *this) { 178 UNUSED(this); 179 errno = ENODEV; 180 return (NULL); 181 } 182 183 static void 184 sv_rewind(struct irs_sv *this) { 185 UNUSED(this); 186 /* NOOP */ 187 } 188 189 /* Private */ 190 191 static struct servent * 192 parse_hes_list(struct irs_sv *this, char **hes_list, const char *proto) { 193 struct pvt *pvt = (struct pvt *)this->private; 194 char *p, *cp, **cpp, **new; 195 int proto_len; 196 int num = 0; 197 int max = 0; 198 199 for (cpp = hes_list; *cpp; cpp++) { 200 cp = *cpp; 201 202 /* Strip away comments, if any. */ 203 if ((p = strchr(cp, '#'))) 204 *p = 0; 205 206 /* Check to make sure the protocol matches. */ 207 p = cp; 208 while (*p && !isspace((unsigned char)*p)) 209 p++; 210 if (!*p) 211 continue; 212 if (proto) { 213 proto_len = strlen(proto); 214 if (strncasecmp(++p, proto, proto_len) != 0) 215 continue; 216 if (p[proto_len] && !isspace(p[proto_len]&0xff)) 217 continue; 218 } 219 /* OK, we've got a live one. Let's parse it for real. */ 220 if (pvt->svbuf) 221 free(pvt->svbuf); 222 pvt->svbuf = strdup(cp); 223 224 p = pvt->svbuf; 225 pvt->serv.s_name = p; 226 while (*p && !isspace(*p&0xff)) 227 p++; 228 if (!*p) 229 continue; 230 *p++ = '\0'; 231 232 pvt->serv.s_proto = p; 233 while (*p && !isspace(*p&0xff)) 234 p++; 235 if (!*p) 236 continue; 237 *p++ = '\0'; 238 239 pvt->serv.s_port = htons((u_short) atoi(p)); 240 while (*p && !isspace(*p&0xff)) 241 p++; 242 if (*p) 243 *p++ = '\0'; 244 245 while (*p) { 246 if ((num + 1) >= max || !pvt->serv.s_aliases) { 247 max += 10; 248 new = realloc(pvt->serv.s_aliases, 249 max * sizeof(char *)); 250 if (!new) { 251 errno = ENOMEM; 252 goto cleanup; 253 } 254 pvt->serv.s_aliases = new; 255 } 256 pvt->serv.s_aliases[num++] = p; 257 while (*p && !isspace(*p&0xff)) 258 p++; 259 if (*p) 260 *p++ = '\0'; 261 } 262 if (!pvt->serv.s_aliases) 263 pvt->serv.s_aliases = malloc(sizeof(char *)); 264 if (!pvt->serv.s_aliases) 265 goto cleanup; 266 pvt->serv.s_aliases[num] = NULL; 267 return (&pvt->serv); 268 } 269 270 cleanup: 271 if (pvt->serv.s_aliases) { 272 free(pvt->serv.s_aliases); 273 pvt->serv.s_aliases = NULL; 274 } 275 if (pvt->svbuf) { 276 free(pvt->svbuf); 277 pvt->svbuf = NULL; 278 } 279 return (NULL); 280 } 281 282 static void 283 sv_minimize(struct irs_sv *this) { 284 UNUSED(this); 285 /* NOOP */ 286 } 287 288 #ifdef SV_RES_SETGET 289 static struct __res_state * 290 sv_res_get(struct irs_sv *this) { 291 struct pvt *pvt = (struct pvt *)this->private; 292 struct dns_p *dns = pvt->dns; 293 294 return (__hesiod_res_get(dns->hes_ctx)); 295 } 296 297 static void 298 sv_res_set(struct irs_sv *this, struct __res_state * res, 299 void (*free_res)(void *)) { 300 struct pvt *pvt = (struct pvt *)this->private; 301 struct dns_p *dns = pvt->dns; 302 303 __hesiod_res_set(dns->hes_ctx, res, free_res); 304 } 305 #endif 306