1 /* $NetBSD: dns_sv.c,v 1.1.1.1 2009/04/12 15:33:42 christos Exp $ */ 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) 21 static 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 54 struct 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 64 static void sv_close(struct irs_sv *); 65 static struct servent * sv_byname(struct irs_sv *, 66 const char *, const char *); 67 static struct servent * sv_byport(struct irs_sv *, int, const char *); 68 static struct servent * sv_next(struct irs_sv *); 69 static void sv_rewind(struct irs_sv *); 70 static void sv_minimize(struct irs_sv *); 71 #ifdef SV_RES_SETGET 72 static struct __res_state * sv_res_get(struct irs_sv *); 73 static void sv_res_set(struct irs_sv *, 74 struct __res_state *, 75 void (*)(void *)); 76 #endif 77 78 static struct servent * parse_hes_list(struct irs_sv *, 79 char **, const char *); 80 81 /* Public */ 82 83 struct irs_sv * 84 irs_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 124 static void 125 sv_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 139 static struct servent * 140 sv_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 154 static struct servent * 155 sv_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 171 static struct servent * 172 sv_next(struct irs_sv *this) { 173 UNUSED(this); 174 errno = ENODEV; 175 return (NULL); 176 } 177 178 static void 179 sv_rewind(struct irs_sv *this) { 180 UNUSED(this); 181 /* NOOP */ 182 } 183 184 /* Private */ 185 186 static struct servent * 187 parse_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 277 static void 278 sv_minimize(struct irs_sv *this) { 279 UNUSED(this); 280 /* NOOP */ 281 } 282 283 #ifdef SV_RES_SETGET 284 static struct __res_state * 285 sv_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 292 static void 293 sv_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