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 #include <arpa/nameser.h> 25 #include <resolv.h> 26 27 #include <stdio.h> 28 #include <string.h> 29 #include <netdb.h> 30 #include <ctype.h> 31 #include <stdlib.h> 32 #include <errno.h> 33 34 #include <isc/memcluster.h> 35 #include <irs.h> 36 37 #include "port_after.h" 38 39 #include "irs_p.h" 40 #include "hesiod.h" 41 #include "dns_p.h" 42 43 /* Types. */ 44 45 struct pvt { 46 struct dns_p * dns; 47 struct protoent proto; 48 char * prbuf; 49 }; 50 51 /* Forward. */ 52 53 static void pr_close(struct irs_pr *); 54 static struct protoent * pr_byname(struct irs_pr *, const char *); 55 static struct protoent * pr_bynumber(struct irs_pr *, int); 56 static struct protoent * pr_next(struct irs_pr *); 57 static void pr_rewind(struct irs_pr *); 58 static void pr_minimize(struct irs_pr *); 59 static struct __res_state * pr_res_get(struct irs_pr *); 60 static void pr_res_set(struct irs_pr *, 61 struct __res_state *, 62 void (*)(void *)); 63 64 static struct protoent * parse_hes_list(struct irs_pr *, char **); 65 66 /* Public. */ 67 68 struct irs_pr * 69 irs_dns_pr(struct irs_acc *this) { 70 struct dns_p *dns = (struct dns_p *)this->private; 71 struct pvt *pvt; 72 struct irs_pr *pr; 73 74 if (!dns->hes_ctx) { 75 errno = ENODEV; 76 return (NULL); 77 } 78 if (!(pvt = memget(sizeof *pvt))) { 79 errno = ENOMEM; 80 return (NULL); 81 } 82 memset(pvt, 0, sizeof *pvt); 83 if (!(pr = memget(sizeof *pr))) { 84 memput(pvt, sizeof *pvt); 85 errno = ENOMEM; 86 return (NULL); 87 } 88 memset(pr, 0x5e, sizeof *pr); 89 pvt->dns = dns; 90 pr->private = pvt; 91 pr->byname = pr_byname; 92 pr->bynumber = pr_bynumber; 93 pr->next = pr_next; 94 pr->rewind = pr_rewind; 95 pr->close = pr_close; 96 pr->minimize = pr_minimize; 97 pr->res_get = pr_res_get; 98 pr->res_set = pr_res_set; 99 return (pr); 100 } 101 102 /* Methods. */ 103 104 static void 105 pr_close(struct irs_pr *this) { 106 struct pvt *pvt = (struct pvt *)this->private; 107 108 if (pvt->proto.p_aliases) 109 free(pvt->proto.p_aliases); 110 if (pvt->prbuf) 111 free(pvt->prbuf); 112 113 memput(pvt, sizeof *pvt); 114 memput(this, sizeof *this); 115 } 116 117 static struct protoent * 118 pr_byname(struct irs_pr *this, const char *name) { 119 struct pvt *pvt = (struct pvt *)this->private; 120 struct dns_p *dns = pvt->dns; 121 struct protoent *proto; 122 char **hes_list; 123 124 if (!(hes_list = hesiod_resolve(dns->hes_ctx, name, "protocol"))) 125 return (NULL); 126 127 proto = parse_hes_list(this, hes_list); 128 hesiod_free_list(dns->hes_ctx, hes_list); 129 return (proto); 130 } 131 132 static struct protoent * 133 pr_bynumber(struct irs_pr *this, int num) { 134 struct pvt *pvt = (struct pvt *)this->private; 135 struct dns_p *dns = pvt->dns; 136 struct protoent *proto; 137 char numstr[16]; 138 char **hes_list; 139 140 sprintf(numstr, "%d", num); 141 if (!(hes_list = hesiod_resolve(dns->hes_ctx, numstr, "protonum"))) 142 return (NULL); 143 144 proto = parse_hes_list(this, hes_list); 145 hesiod_free_list(dns->hes_ctx, hes_list); 146 return (proto); 147 } 148 149 static struct protoent * 150 pr_next(struct irs_pr *this) { 151 UNUSED(this); 152 errno = ENODEV; 153 return (NULL); 154 } 155 156 static void 157 pr_rewind(struct irs_pr *this) { 158 UNUSED(this); 159 /* NOOP */ 160 } 161 162 static void 163 pr_minimize(struct irs_pr *this) { 164 UNUSED(this); 165 /* NOOP */ 166 } 167 168 static struct __res_state * 169 pr_res_get(struct irs_pr *this) { 170 struct pvt *pvt = (struct pvt *)this->private; 171 struct dns_p *dns = pvt->dns; 172 173 return (__hesiod_res_get(dns->hes_ctx)); 174 } 175 176 static void 177 pr_res_set(struct irs_pr *this, struct __res_state * res, 178 void (*free_res)(void *)) { 179 struct pvt *pvt = (struct pvt *)this->private; 180 struct dns_p *dns = pvt->dns; 181 182 __hesiod_res_set(dns->hes_ctx, res, free_res); 183 } 184 185 /* Private. */ 186 187 static struct protoent * 188 parse_hes_list(struct irs_pr *this, char **hes_list) { 189 struct pvt *pvt = (struct pvt *)this->private; 190 char *p, *cp, **cpp, **new; 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 /* Skip blank lines. */ 202 p = cp; 203 while (*p && !isspace((unsigned char)*p)) 204 p++; 205 if (!*p) 206 continue; 207 208 /* OK, we've got a live one. Let's parse it for real. */ 209 if (pvt->prbuf) 210 free(pvt->prbuf); 211 pvt->prbuf = strdup(cp); 212 213 p = pvt->prbuf; 214 pvt->proto.p_name = p; 215 while (*p && !isspace((unsigned char)*p)) 216 p++; 217 if (!*p) 218 continue; 219 *p++ = '\0'; 220 221 pvt->proto.p_proto = atoi(p); 222 while (*p && !isspace((unsigned char)*p)) 223 p++; 224 if (*p) 225 *p++ = '\0'; 226 227 while (*p) { 228 if ((num + 1) >= max || !pvt->proto.p_aliases) { 229 max += 10; 230 new = realloc(pvt->proto.p_aliases, 231 max * sizeof(char *)); 232 if (!new) { 233 errno = ENOMEM; 234 goto cleanup; 235 } 236 pvt->proto.p_aliases = new; 237 } 238 pvt->proto.p_aliases[num++] = p; 239 while (*p && !isspace((unsigned char)*p)) 240 p++; 241 if (*p) 242 *p++ = '\0'; 243 } 244 if (!pvt->proto.p_aliases) 245 pvt->proto.p_aliases = malloc(sizeof(char *)); 246 if (!pvt->proto.p_aliases) 247 goto cleanup; 248 pvt->proto.p_aliases[num] = NULL; 249 return (&pvt->proto); 250 } 251 252 cleanup: 253 if (pvt->proto.p_aliases) { 254 free(pvt->proto.p_aliases); 255 pvt->proto.p_aliases = NULL; 256 } 257 if (pvt->prbuf) { 258 free(pvt->prbuf); 259 pvt->prbuf = NULL; 260 } 261 return (NULL); 262 } 263 264 /*! \file */ 265