4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (c) 1996-1999 by Internet Software Consortium.
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.
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.
20 #if defined(LIBC_SCCS) && !defined(lint)
21 static const char rcsid
[] = "Id: dns_nw.c,v 1.12 2005/04/27 04:56:22 sra Exp";
22 #endif /* LIBC_SCCS and not lint */
26 #include "port_before.h"
28 #include <sys/param.h>
29 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <arpa/nameser.h>
43 #include <isc/memcluster.h>
46 #include "port_after.h"
52 # define SPRINTF(x) strlen(sprintf/**/x)
54 # define SPRINTF(x) sprintf x
61 #define MAXPACKET (64*1024)
65 char * ali
[MAXALIASES
];
67 struct __res_state
* res
;
68 void (*free_res
)(void *);
76 enum by_what
{ by_addr
, by_name
};
80 static void nw_close(struct irs_nw
*);
81 static struct nwent
* nw_byname(struct irs_nw
*, const char *, int);
82 static struct nwent
* nw_byaddr(struct irs_nw
*, void *, int, int);
83 static struct nwent
* nw_next(struct irs_nw
*);
84 static void nw_rewind(struct irs_nw
*);
85 static void nw_minimize(struct irs_nw
*);
86 static struct __res_state
* nw_res_get(struct irs_nw
*this);
87 static void nw_res_set(struct irs_nw
*this,
88 struct __res_state
*res
,
89 void (*free_res
)(void *));
91 static struct nwent
* get1101byaddr(struct irs_nw
*, u_char
*, int);
92 static struct nwent
* get1101byname(struct irs_nw
*, const char *);
93 static struct nwent
* get1101answer(struct irs_nw
*,
94 u_char
*ansbuf
, int anslen
,
96 int af
, const char *name
,
97 const u_char
*addr
, int addrlen
);
98 static struct nwent
* get1101mask(struct irs_nw
*this, struct nwent
*);
99 static int make1101inaddr(const u_char
*, int, char *, int);
100 static void normalize_name(char *name
);
101 static int init(struct irs_nw
*this);
106 irs_dns_nw(struct irs_acc
*this) {
112 if (!(pvt
= memget(sizeof *pvt
))) {
116 memset(pvt
, 0, sizeof *pvt
);
117 if (!(nw
= memget(sizeof *nw
))) {
118 memput(pvt
, sizeof *pvt
);
122 memset(nw
, 0x5e, sizeof *nw
);
124 nw
->close
= nw_close
;
125 nw
->byname
= nw_byname
;
126 nw
->byaddr
= nw_byaddr
;
128 nw
->rewind
= nw_rewind
;
129 nw
->minimize
= nw_minimize
;
130 nw
->res_get
= nw_res_get
;
131 nw
->res_set
= nw_res_set
;
138 nw_close(struct irs_nw
*this) {
139 struct pvt
*pvt
= (struct pvt
*)this->private;
143 if (pvt
->res
&& pvt
->free_res
)
144 (*pvt
->free_res
)(pvt
->res
);
146 memput(pvt
, sizeof *pvt
);
147 memput(this, sizeof *this);
150 static struct nwent
*
151 nw_byname(struct irs_nw
*this, const char *name
, int af
) {
152 struct pvt
*pvt
= (struct pvt
*)this->private;
154 if (init(this) == -1)
159 return (get1101byname(this, name
));
163 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
164 errno
= EAFNOSUPPORT
;
168 static struct nwent
*
169 nw_byaddr(struct irs_nw
*this, void *net
, int len
, int af
) {
170 struct pvt
*pvt
= (struct pvt
*)this->private;
172 if (init(this) == -1)
177 return (get1101byaddr(this, net
, len
));
181 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
182 errno
= EAFNOSUPPORT
;
186 static struct nwent
*
187 nw_next(struct irs_nw
*this) {
195 nw_rewind(struct irs_nw
*this) {
201 nw_minimize(struct irs_nw
*this) {
202 struct pvt
*pvt
= (struct pvt
*)this->private;
205 res_nclose(pvt
->res
);
208 static struct __res_state
*
209 nw_res_get(struct irs_nw
*this) {
210 struct pvt
*pvt
= (struct pvt
*)this->private;
213 struct __res_state
*res
;
214 res
= (struct __res_state
*)malloc(sizeof *res
);
219 memset(res
, 0, sizeof *res
);
220 nw_res_set(this, res
, free
);
227 nw_res_set(struct irs_nw
*this, struct __res_state
*res
,
228 void (*free_res
)(void *)) {
229 struct pvt
*pvt
= (struct pvt
*)this->private;
231 if (pvt
->res
&& pvt
->free_res
) {
232 res_nclose(pvt
->res
);
233 (*pvt
->free_res
)(pvt
->res
);
237 pvt
->free_res
= free_res
;
242 static struct nwent
*
243 get1101byname(struct irs_nw
*this, const char *name
) {
244 struct pvt
*pvt
= (struct pvt
*)this->private;
247 struct nwent
*result
;
249 ansbuf
= memget(MAXPACKET
);
250 if (ansbuf
== NULL
) {
252 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
255 anslen
= res_nsearch(pvt
->res
, name
, C_IN
, T_PTR
, ansbuf
, MAXPACKET
);
257 memput(ansbuf
, MAXPACKET
);
260 result
= get1101mask(this, get1101answer(this, ansbuf
, anslen
, by_name
,
261 AF_INET
, name
, NULL
, 0));
262 memput(ansbuf
, MAXPACKET
);
266 static struct nwent
*
267 get1101byaddr(struct irs_nw
*this, u_char
*net
, int len
) {
268 struct pvt
*pvt
= (struct pvt
*)this->private;
269 char qbuf
[sizeof "255.255.255.255.in-addr.arpa"];
270 struct nwent
*result
;
274 if (len
< 1 || len
> 32) {
276 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
279 if (make1101inaddr(net
, len
, qbuf
, sizeof qbuf
) < 0)
281 ansbuf
= memget(MAXPACKET
);
282 if (ansbuf
== NULL
) {
284 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
287 anslen
= res_nquery(pvt
->res
, qbuf
, C_IN
, T_PTR
, ansbuf
, MAXPACKET
);
289 memput(ansbuf
, MAXPACKET
);
292 result
= get1101mask(this, get1101answer(this, ansbuf
, anslen
, by_addr
,
293 AF_INET
, NULL
, net
, len
));
294 memput(ansbuf
, MAXPACKET
);
298 static struct nwent
*
299 get1101answer(struct irs_nw
*this,
300 u_char
*ansbuf
, int anslen
, enum by_what by_what
,
301 int af
, const char *name
, const u_char
*addr
, int addrlen
)
303 struct pvt
*pvt
= (struct pvt
*)this->private;
304 int type
, class, ancount
, qdcount
, haveanswer
;
309 /* Initialize, and parse header. */
310 eom
= ansbuf
+ anslen
;
311 if (ansbuf
+ HFIXEDSZ
> eom
) {
312 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
315 hp
= (HEADER
*)ansbuf
;
316 cp
= ansbuf
+ HFIXEDSZ
;
317 qdcount
= ntohs(hp
->qdcount
);
318 while (qdcount
-- > 0) {
319 int n
= dn_skipname(cp
, eom
);
321 if (n
< 0 || cp
> eom
) {
322 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
326 ancount
= ntohs(hp
->ancount
);
329 RES_SET_H_ERRNO(pvt
->res
, HOST_NOT_FOUND
);
331 RES_SET_H_ERRNO(pvt
->res
, TRY_AGAIN
);
335 /* Prepare a return structure. */
337 ep
= pvt
->buf
+ sizeof(pvt
->buf
);
338 pvt
->net
.n_name
= NULL
;
339 pvt
->net
.n_aliases
= pvt
->ali
;
340 pvt
->net
.n_addrtype
= af
;
341 pvt
->net
.n_addr
= NULL
;
342 pvt
->net
.n_length
= addrlen
;
344 /* Save input key if given. */
348 int n
= strlen(name
) + 1;
351 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
354 pvt
->net
.n_name
= strcpy(bp
, name
); /* (checked) */
359 if (addr
!= NULL
&& addrlen
!= 0) {
360 int n
= addrlen
/ 8 + ((addrlen
% 8) != 0);
362 if (INADDRSZ
> (ep
- bp
)) {
363 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
366 memset(bp
, 0, INADDRSZ
);
368 pvt
->net
.n_addr
= bp
;
376 /* Parse the answer, collect aliases. */
379 while (--ancount
>= 0 && cp
< eom
) {
380 int n
= dn_expand(ansbuf
, eom
, cp
, bp
, ep
- bp
);
382 cp
+= n
; /*%< Owner */
383 if (n
< 0 || !maybe_dnok(pvt
->res
, bp
) ||
384 cp
+ 3 * INT16SZ
+ INT32SZ
> eom
) {
385 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
388 GETSHORT(type
, cp
); /*%< Type */
389 GETSHORT(class, cp
); /*%< Class */
390 cp
+= INT32SZ
; /*%< TTL */
391 GETSHORT(n
, cp
); /*%< RDLENGTH */
392 if (class == C_IN
&& type
== T_PTR
) {
395 nn
= dn_expand(ansbuf
, eom
, cp
, bp
, ep
- bp
);
396 if (nn
< 0 || !maybe_hnok(pvt
->res
, bp
) || nn
!= n
) {
397 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
403 if (pvt
->net
.n_name
== NULL
)
404 pvt
->net
.n_name
= bp
;
405 else if (ns_samename(pvt
->net
.n_name
, bp
) == 1)
415 u_int b1
, b2
, b3
, b4
;
417 if (pvt
->net
.n_addr
!= NULL
||
418 sscanf(bp
, "%u.%u.%u.%u.in-addr.arpa",
419 &b1
, &b2
, &b3
, &b4
) != 4)
421 if ((ep
- bp
) < INADDRSZ
) {
422 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
425 pvt
->net
.n_addr
= bp
;
430 pvt
->net
.n_length
= INADDRSZ
* 8;
435 cp
+= n
; /*%< RDATA */
438 RES_SET_H_ERRNO(pvt
->res
, TRY_AGAIN
);
446 static struct nwent
*
447 get1101mask(struct irs_nw
*this, struct nwent
*nwent
) {
448 struct pvt
*pvt
= (struct pvt
*)this->private;
449 char qbuf
[sizeof "255.255.255.255.in-addr.arpa"], owner
[MAXDNAME
];
450 int anslen
, type
, class, ancount
, qdcount
;
451 u_char
*ansbuf
, *cp
, *eom
;
456 if (make1101inaddr(nwent
->n_addr
, nwent
->n_length
, qbuf
, sizeof qbuf
)
458 /* "First, do no harm." */
462 ansbuf
= memget(MAXPACKET
);
463 if (ansbuf
== NULL
) {
465 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
468 /* Query for the A RR that would hold this network's mask. */
469 anslen
= res_nquery(pvt
->res
, qbuf
, C_IN
, T_A
, ansbuf
, MAXPACKET
);
470 if (anslen
< HFIXEDSZ
) {
471 memput(ansbuf
, MAXPACKET
);
475 /* Initialize, and parse header. */
476 hp
= (HEADER
*)ansbuf
;
477 cp
= ansbuf
+ HFIXEDSZ
;
478 eom
= ansbuf
+ anslen
;
479 qdcount
= ntohs(hp
->qdcount
);
480 while (qdcount
-- > 0) {
481 int n
= dn_skipname(cp
, eom
);
483 if (n
< 0 || cp
> eom
) {
484 memput(ansbuf
, MAXPACKET
);
488 ancount
= ntohs(hp
->ancount
);
490 /* Parse the answer, collect aliases. */
491 while (--ancount
>= 0 && cp
< eom
) {
492 int n
= dn_expand(ansbuf
, eom
, cp
, owner
, sizeof owner
);
494 if (n
< 0 || !maybe_dnok(pvt
->res
, owner
))
496 cp
+= n
; /*%< Owner */
497 if (cp
+ 3 * INT16SZ
+ INT32SZ
> eom
)
499 GETSHORT(type
, cp
); /*%< Type */
500 GETSHORT(class, cp
); /*%< Class */
501 cp
+= INT32SZ
; /*%< TTL */
502 GETSHORT(n
, cp
); /*%< RDLENGTH */
505 if (n
== INADDRSZ
&& class == C_IN
&& type
== T_A
&&
506 ns_samename(qbuf
, owner
) == 1) {
507 /* This A RR indicates the actual netmask. */
511 for (nn
= 0; nn
< INADDRSZ
; nn
++)
512 for (mm
= 7; mm
>= 0; mm
--)
513 if (cp
[nn
] & (1 << mm
))
518 cp
+= n
; /*%< RDATA */
520 memput(ansbuf
, MAXPACKET
);
525 make1101inaddr(const u_char
*net
, int bits
, char *name
, int size
) {
531 /* Zero fill any whole bytes left out of the prefix. */
532 for (n
= (32 - bits
) / 8; n
> 0; n
--) {
533 if (ep
- name
< (int)(sizeof "0."))
535 m
= SPRINTF((name
, "0."));
539 /* Format the partial byte, if any, within the prefix. */
540 if ((n
= bits
% 8) != 0) {
541 if (ep
- name
< (int)(sizeof "255."))
543 m
= SPRINTF((name
, "%u.",
544 net
[bits
/ 8] & ~((1 << (8 - n
)) - 1)));
548 /* Format the whole bytes within the prefix. */
549 for (n
= bits
/ 8; n
> 0; n
--) {
550 if (ep
- name
< (int)(sizeof "255."))
552 m
= SPRINTF((name
, "%u.", net
[n
- 1]));
556 /* Add the static text. */
557 if (ep
- name
< (int)(sizeof "in-addr.arpa"))
559 (void) SPRINTF((name
, "in-addr.arpa"));
568 normalize_name(char *name
) {
571 /* Make lower case. */
572 for (t
= name
; *t
; t
++)
573 if (isascii((unsigned char)*t
) && isupper((unsigned char)*t
))
574 *t
= tolower((*t
)&0xff);
576 /* Remove trailing dots. */
577 while (t
> name
&& t
[-1] == '.')
582 init(struct irs_nw
*this) {
583 struct pvt
*pvt
= (struct pvt
*)this->private;
585 if (!pvt
->res
&& !nw_res_get(this))
587 if (((pvt
->res
->options
& RES_INIT
) == 0U) &&
588 res_ninit(pvt
->res
) == -1)