2 * Copyright (c) 1996, 1998 by Internet Software Consortium.
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
18 #if defined(LIBC_SCCS) && !defined(lint)
19 static const char rcsid[] = "$Id: dns_nw.c,v 1.13 1998/02/13 01:10:40 halley Exp $";
20 #endif /* LIBC_SCCS and not lint */
24 #include "port_before.h"
26 #include <sys/param.h>
27 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <arpa/nameser.h>
43 #include "port_after.h"
49 # define SPRINTF(x) strlen(sprintf/**/x)
51 # define SPRINTF(x) sprintf x
61 #define MAXPACKET PACKETSZ
63 #define MAXPACKET 1024
68 char * ali[MAXALIASES];
77 enum by_what { by_addr, by_name };
81 static void nw_close(struct irs_nw *);
82 static struct nwent * nw_byname(struct irs_nw *, const char *, int);
83 static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int);
84 static struct nwent * nw_next(struct irs_nw *);
85 static void nw_rewind(struct irs_nw *);
86 static void nw_minimize(struct irs_nw *);
88 static struct nwent * get1101byaddr(struct irs_nw *, u_char *, int);
89 static struct nwent * get1101byname(struct irs_nw *, const char *);
90 static struct nwent * get1101answer(struct irs_nw *,
91 u_char *ansbuf, int anslen,
93 int af, const char *name,
94 const u_char *addr, int addrlen);
95 static struct nwent * get1101mask(struct nwent *);
96 static int make1101inaddr(const u_char *, int, char *, int);
97 static void normalize_name(char *name);
102 irs_dns_nw(struct irs_acc *this) {
106 if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) {
110 memset(pvt, 0, sizeof *pvt);
111 if (!(nw = (struct irs_nw *)malloc(sizeof *nw))) {
116 memset(nw, 0x5e, sizeof *nw);
118 nw->close = nw_close;
119 nw->byname = nw_byname;
120 nw->byaddr = nw_byaddr;
122 nw->rewind = nw_rewind;
123 nw->minimize = nw_minimize;
130 nw_close(struct irs_nw *this) {
131 struct pvt *pvt = (struct pvt *)this->private;
137 static struct nwent *
138 nw_byname(struct irs_nw *this, const char *name, int af) {
141 return (get1101byname(this, name));
145 h_errno = NETDB_INTERNAL;
146 errno = EAFNOSUPPORT;
150 static struct nwent *
151 nw_byaddr(struct irs_nw *this, void *net, int len, int af) {
154 return (get1101byaddr(this, net, len));
158 h_errno = NETDB_INTERNAL;
159 errno = EAFNOSUPPORT;
163 static struct nwent *
164 nw_next(struct irs_nw *this) {
169 nw_rewind(struct irs_nw *this) {
174 nw_minimize(struct irs_nw *this) {
180 static struct nwent *
181 get1101byname(struct irs_nw *this, const char *name) {
182 u_char ansbuf[MAXPACKET];
185 if ((_res.options & RES_INIT) == 0 && res_init() == -1)
187 anslen = res_search(name, C_IN, T_PTR, ansbuf, sizeof ansbuf);
190 return (get1101mask(get1101answer(this, ansbuf, anslen, by_name,
191 AF_INET, name, NULL, 0)));
194 static struct nwent *
195 get1101byaddr(struct irs_nw *this, u_char *net, int len) {
196 u_char ansbuf[MAXPACKET];
197 char qbuf[sizeof "255.255.255.255.in-addr.arpa"];
200 if (len < 1 || len > 32) {
202 h_errno = NETDB_INTERNAL;
205 if (make1101inaddr(net, len, qbuf, sizeof qbuf) < 0)
207 anslen = res_query(qbuf, C_IN, T_PTR, ansbuf, sizeof ansbuf);
210 return (get1101mask(get1101answer(this, ansbuf, anslen, by_addr,
211 AF_INET, NULL, net, len)));
214 static struct nwent *
215 get1101answer(struct irs_nw *this,
216 u_char *ansbuf, int anslen, enum by_what by_what,
217 int af, const char *name, const u_char *addr, int addrlen)
219 struct pvt *pvt = (struct pvt *)this->private;
220 int type, class, buflen, ancount, qdcount, haveanswer;
225 /* Initialize, and parse header. */
226 eom = ansbuf + anslen;
227 if (ansbuf + HFIXEDSZ > eom) {
228 h_errno = NO_RECOVERY;
231 hp = (HEADER *)ansbuf;
232 cp = ansbuf + HFIXEDSZ;
233 qdcount = ntohs(hp->qdcount);
234 while (qdcount-- > 0) {
235 int n = dn_skipname(cp, eom);
237 if (n < 0 || cp > eom) {
238 h_errno = NO_RECOVERY;
242 ancount = ntohs(hp->ancount);
245 h_errno = HOST_NOT_FOUND;
251 /* Prepare a return structure. */
253 buflen = sizeof pvt->buf;
254 pvt->net.n_name = NULL;
255 pvt->net.n_aliases = pvt->ali;
256 pvt->net.n_addrtype = af;
257 pvt->net.n_addr = NULL;
258 pvt->net.n_length = addrlen;
260 /* Save input key if given. */
264 int n = strlen(name) + 1;
267 h_errno = NO_RECOVERY;
270 pvt->net.n_name = strcpy(bp, name);
276 if (addr != NULL && addrlen != 0) {
277 int n = addrlen / 8 + ((addrlen % 8) != 0);
279 if (INADDRSZ > buflen) {
280 h_errno = NO_RECOVERY;
283 memset(bp, 0, INADDRSZ);
285 pvt->net.n_addr = bp;
294 /* Parse the answer, collect aliases. */
297 while (--ancount >= 0 && cp < eom) {
298 int n = dn_expand(ansbuf, eom, cp, bp, buflen);
301 if (n < 0 || !res_dnok(bp) ||
302 cp + 3 * INT16SZ + INT32SZ > eom) {
303 h_errno = NO_RECOVERY;
306 GETSHORT(type, cp); /* Type */
307 GETSHORT(class, cp); /* Class */
308 cp += INT32SZ; /* TTL */
309 GETSHORT(n, cp); /* RDLENGTH */
310 if (class == C_IN && type == T_PTR) {
313 nn = dn_expand(ansbuf, eom, cp, bp, buflen);
314 if (nn < 0 || !res_hnok(bp) || nn != n) {
315 h_errno = NO_RECOVERY;
321 if (pvt->net.n_name == NULL)
322 pvt->net.n_name = bp;
323 else if (strcasecmp(pvt->net.n_name, bp) == 0)
334 u_int b1, b2, b3, b4;
336 if (pvt->net.n_addr != NULL ||
337 sscanf(bp, "%u.%u.%u.%u.in-addr.arpa",
338 &b1, &b2, &b3, &b4) != 4)
340 if (buflen < INADDRSZ) {
341 h_errno = NO_RECOVERY;
344 pvt->net.n_addr = bp;
350 pvt->net.n_length = INADDRSZ * 8;
366 static struct nwent *
367 get1101mask(struct nwent *nwent) {
368 char qbuf[sizeof "255.255.255.255.in-addr.arpa"], owner[MAXDNAME];
369 int anslen, type, class, ancount, qdcount;
370 u_char ansbuf[MAXPACKET], *cp, *eom;
375 if (make1101inaddr(nwent->n_addr, nwent->n_length, qbuf, sizeof qbuf)
377 /* "First, do no harm." */
381 /* Query for the A RR that would hold this network's mask. */
382 anslen = res_query(qbuf, C_IN, T_A, ansbuf, sizeof ansbuf);
383 if (anslen < HFIXEDSZ)
386 /* Initialize, and parse header. */
387 hp = (HEADER *)ansbuf;
388 cp = ansbuf + HFIXEDSZ;
389 eom = ansbuf + anslen;
390 qdcount = ntohs(hp->qdcount);
391 while (qdcount-- > 0) {
392 int n = dn_skipname(cp, eom);
394 if (n < 0 || cp > eom)
397 ancount = ntohs(hp->ancount);
399 /* Parse the answer, collect aliases. */
400 while (--ancount >= 0 && cp < eom) {
401 int n = dn_expand(ansbuf, eom, cp, owner, sizeof owner);
403 if (n < 0 || !res_dnok(owner))
406 if (cp + 3 * INT16SZ + INT32SZ > eom)
408 GETSHORT(type, cp); /* Type */
409 GETSHORT(class, cp); /* Class */
410 cp += INT32SZ; /* TTL */
411 GETSHORT(n, cp); /* RDLENGTH */
414 if (n == INADDRSZ && class == C_IN && type == T_A &&
415 !strcasecmp(qbuf, owner)) {
416 /* This A RR indicates the actual netmask. */
420 for (nn = 0; nn < INADDRSZ; nn++)
421 for (mm = 7; mm >= 0; mm--)
422 if (cp[nn] & (1 << mm))
433 make1101inaddr(const u_char *net, int bits, char *name, int size) {
436 /* Zero fill any whole bytes left out of the prefix. */
437 for (n = (32 - bits) / 8; n > 0; n--) {
438 if (size < (int)(sizeof "0."))
440 m = SPRINTF((name, "0."));
445 /* Format the partial byte, if any, within the prefix. */
446 if ((n = bits % 8) != 0) {
447 if (size < (int)(sizeof "255."))
449 m = SPRINTF((name, "%u.",
450 net[bits / 8] & ~((1 << (8 - n)) - 1)));
455 /* Format the whole bytes within the prefix. */
456 for (n = bits / 8; n > 0; n--) {
457 if (size < (int)(sizeof "255."))
459 m = SPRINTF((name, "%u.", net[n - 1]));
464 /* Add the static text. */
465 if (size < (int)(sizeof "in-addr.arpa"))
467 (void) SPRINTF((name, "in-addr.arpa"));
476 normalize_name(char *name) {
479 /* Make lower case. */
480 for (t = name; *t; t++)
481 if (isascii(*t) && isupper(*t))
484 /* Remove trailing dots. */
485 while (t > name && t[-1] == '.')