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