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) 19 static 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 52 struct 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 62 static void sv_close(struct irs_sv *); 63 static struct servent * sv_byname(struct irs_sv *, 64 const char *, const char *); 65 static struct servent * sv_byport(struct irs_sv *, int, const char *); 66 static struct servent * sv_next(struct irs_sv *); 67 static void sv_rewind(struct irs_sv *); 68 static void sv_minimize(struct irs_sv *); 69 #ifdef SV_RES_SETGET 70 static struct __res_state * sv_res_get(struct irs_sv *); 71 static void sv_res_set(struct irs_sv *, 72 struct __res_state *, 73 void (*)(void *)); 74 #endif 75 76 static struct servent * parse_hes_list(struct irs_sv *, 77 char **, const char *); 78 79 /* Public */ 80 81 struct irs_sv * 82 irs_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 122 static void 123 sv_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 137 static struct servent * 138 sv_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 152 static struct servent * 153 sv_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 169 static struct servent * 170 sv_next(struct irs_sv *this) { 171 UNUSED(this); 172 errno = ENODEV; 173 return (NULL); 174 } 175 176 static void 177 sv_rewind(struct irs_sv *this) { 178 UNUSED(this); 179 /* NOOP */ 180 } 181 182 /* Private */ 183 184 static struct servent * 185 parse_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 275 static void 276 sv_minimize(struct irs_sv *this) { 277 UNUSED(this); 278 /* NOOP */ 279 } 280 281 #ifdef SV_RES_SETGET 282 static struct __res_state * 283 sv_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 290 static void 291 sv_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