2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (c) 1996-1999 by Internet Software Consortium.
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.
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.
18 #if defined(LIBC_SCCS) && !defined(lint)
19 static const char rcsid
[] = "$Id: dns_nw.c,v 1.3.2.7 2004/05/17 07:46:42 marka 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>
41 #include <isc/memcluster.h>
44 #include "port_after.h"
50 # define SPRINTF(x) strlen(sprintf/**/x)
52 # define SPRINTF(x) sprintf x
59 #define MAXPACKET (64*1024)
63 char * ali
[MAXALIASES
];
65 struct __res_state
* res
;
66 void (*free_res
)(void *);
74 enum by_what
{ by_addr
, by_name
};
78 static void nw_close(struct irs_nw
*);
79 static struct nwent
* nw_byname(struct irs_nw
*, const char *, int);
80 static struct nwent
* nw_byaddr(struct irs_nw
*, void *, int, int);
81 static struct nwent
* nw_next(struct irs_nw
*);
82 static void nw_rewind(struct irs_nw
*);
83 static void nw_minimize(struct irs_nw
*);
84 static struct __res_state
* nw_res_get(struct irs_nw
*this);
85 static void nw_res_set(struct irs_nw
*this,
86 struct __res_state
*res
,
87 void (*free_res
)(void *));
89 static struct nwent
* get1101byaddr(struct irs_nw
*, u_char
*, int);
90 static struct nwent
* get1101byname(struct irs_nw
*, const char *);
91 static struct nwent
* get1101answer(struct irs_nw
*,
92 u_char
*ansbuf
, int anslen
,
94 int af
, const char *name
,
95 const u_char
*addr
, int addrlen
);
96 static struct nwent
* get1101mask(struct irs_nw
*this, struct nwent
*);
97 static int make1101inaddr(const u_char
*, int, char *, int);
98 static void normalize_name(char *name
);
99 static int init(struct irs_nw
*this);
104 irs_dns_nw(struct irs_acc
*this) {
110 if (!(pvt
= memget(sizeof *pvt
))) {
114 memset(pvt
, 0, sizeof *pvt
);
115 if (!(nw
= memget(sizeof *nw
))) {
116 memput(pvt
, sizeof *pvt
);
120 memset(nw
, 0x5e, sizeof *nw
);
122 nw
->close
= nw_close
;
123 nw
->byname
= nw_byname
;
124 nw
->byaddr
= nw_byaddr
;
126 nw
->rewind
= nw_rewind
;
127 nw
->minimize
= nw_minimize
;
128 nw
->res_get
= nw_res_get
;
129 nw
->res_set
= nw_res_set
;
136 nw_close(struct irs_nw
*this) {
137 struct pvt
*pvt
= (struct pvt
*)this->private;
141 if (pvt
->res
&& pvt
->free_res
)
142 (*pvt
->free_res
)(pvt
->res
);
144 memput(pvt
, sizeof *pvt
);
145 memput(this, sizeof *this);
148 static struct nwent
*
149 nw_byname(struct irs_nw
*this, const char *name
, int af
) {
150 struct pvt
*pvt
= (struct pvt
*)this->private;
152 if (init(this) == -1)
157 return (get1101byname(this, name
));
161 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
162 errno
= EAFNOSUPPORT
;
166 static struct nwent
*
167 nw_byaddr(struct irs_nw
*this, void *net
, int len
, int af
) {
168 struct pvt
*pvt
= (struct pvt
*)this->private;
170 if (init(this) == -1)
175 return (get1101byaddr(this, net
, len
));
179 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
180 errno
= EAFNOSUPPORT
;
184 static struct nwent
*
185 nw_next(struct irs_nw
*this) {
193 nw_rewind(struct irs_nw
*this) {
199 nw_minimize(struct irs_nw
*this) {
200 struct pvt
*pvt
= (struct pvt
*)this->private;
203 res_nclose(pvt
->res
);
206 static struct __res_state
*
207 nw_res_get(struct irs_nw
*this) {
208 struct pvt
*pvt
= (struct pvt
*)this->private;
211 struct __res_state
*res
;
212 res
= (struct __res_state
*)malloc(sizeof *res
);
217 memset(res
, 0, sizeof *res
);
218 nw_res_set(this, res
, free
);
225 nw_res_set(struct irs_nw
*this, struct __res_state
*res
,
226 void (*free_res
)(void *)) {
227 struct pvt
*pvt
= (struct pvt
*)this->private;
229 if (pvt
->res
&& pvt
->free_res
) {
230 res_nclose(pvt
->res
);
231 (*pvt
->free_res
)(pvt
->res
);
235 pvt
->free_res
= free_res
;
240 static struct nwent
*
241 get1101byname(struct irs_nw
*this, const char *name
) {
242 struct pvt
*pvt
= (struct pvt
*)this->private;
245 struct nwent
*result
;
247 ansbuf
= memget(MAXPACKET
);
248 if (ansbuf
== NULL
) {
250 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
253 anslen
= res_nsearch(pvt
->res
, name
, C_IN
, T_PTR
, ansbuf
, MAXPACKET
);
255 memput(ansbuf
, MAXPACKET
);
258 result
= get1101mask(this, get1101answer(this, ansbuf
, anslen
, by_name
,
259 AF_INET
, name
, NULL
, 0));
260 memput(ansbuf
, MAXPACKET
);
264 static struct nwent
*
265 get1101byaddr(struct irs_nw
*this, u_char
*net
, int len
) {
266 struct pvt
*pvt
= (struct pvt
*)this->private;
267 char qbuf
[sizeof "255.255.255.255.in-addr.arpa"];
268 struct nwent
*result
;
272 if (len
< 1 || len
> 32) {
274 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
277 if (make1101inaddr(net
, len
, qbuf
, sizeof qbuf
) < 0)
279 ansbuf
= memget(MAXPACKET
);
280 if (ansbuf
== NULL
) {
282 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
285 anslen
= res_nquery(pvt
->res
, qbuf
, C_IN
, T_PTR
, ansbuf
, MAXPACKET
);
287 memput(ansbuf
, MAXPACKET
);
290 result
= get1101mask(this, get1101answer(this, ansbuf
, anslen
, by_addr
,
291 AF_INET
, NULL
, net
, len
));
292 memput(ansbuf
, MAXPACKET
);
296 static struct nwent
*
297 get1101answer(struct irs_nw
*this,
298 u_char
*ansbuf
, int anslen
, enum by_what by_what
,
299 int af
, const char *name
, const u_char
*addr
, int addrlen
)
301 struct pvt
*pvt
= (struct pvt
*)this->private;
302 int type
, class, ancount
, qdcount
, haveanswer
;
307 /* Initialize, and parse header. */
308 eom
= ansbuf
+ anslen
;
309 if (ansbuf
+ HFIXEDSZ
> eom
) {
310 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
313 hp
= (HEADER
*)ansbuf
;
314 cp
= ansbuf
+ HFIXEDSZ
;
315 qdcount
= ntohs(hp
->qdcount
);
316 while (qdcount
-- > 0) {
317 int n
= dn_skipname(cp
, eom
);
319 if (n
< 0 || cp
> eom
) {
320 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
324 ancount
= ntohs(hp
->ancount
);
327 RES_SET_H_ERRNO(pvt
->res
, HOST_NOT_FOUND
);
329 RES_SET_H_ERRNO(pvt
->res
, TRY_AGAIN
);
333 /* Prepare a return structure. */
335 ep
= pvt
->buf
+ sizeof(pvt
->buf
);
336 pvt
->net
.n_name
= NULL
;
337 pvt
->net
.n_aliases
= pvt
->ali
;
338 pvt
->net
.n_addrtype
= af
;
339 pvt
->net
.n_addr
= NULL
;
340 pvt
->net
.n_length
= addrlen
;
342 /* Save input key if given. */
346 int n
= strlen(name
) + 1;
349 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
352 pvt
->net
.n_name
= strcpy(bp
, name
); /* (checked) */
357 if (addr
!= NULL
&& addrlen
!= 0) {
358 int n
= addrlen
/ 8 + ((addrlen
% 8) != 0);
360 if (INADDRSZ
> (ep
- bp
)) {
361 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
364 memset(bp
, 0, INADDRSZ
);
366 pvt
->net
.n_addr
= bp
;
374 /* Parse the answer, collect aliases. */
377 while (--ancount
>= 0 && cp
< eom
) {
378 int n
= dn_expand(ansbuf
, eom
, cp
, bp
, ep
- bp
);
381 if (n
< 0 || !maybe_dnok(pvt
->res
, bp
) ||
382 cp
+ 3 * INT16SZ
+ INT32SZ
> eom
) {
383 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
386 GETSHORT(type
, cp
); /* Type */
387 GETSHORT(class, cp
); /* Class */
388 cp
+= INT32SZ
; /* TTL */
389 GETSHORT(n
, cp
); /* RDLENGTH */
390 if (class == C_IN
&& type
== T_PTR
) {
393 nn
= dn_expand(ansbuf
, eom
, cp
, bp
, ep
- bp
);
394 if (nn
< 0 || !maybe_hnok(pvt
->res
, bp
) || nn
!= n
) {
395 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
401 if (pvt
->net
.n_name
== NULL
)
402 pvt
->net
.n_name
= bp
;
403 else if (ns_samename(pvt
->net
.n_name
, bp
) == 1)
413 u_int b1
, b2
, b3
, b4
;
415 if (pvt
->net
.n_addr
!= NULL
||
416 sscanf(bp
, "%u.%u.%u.%u.in-addr.arpa",
417 &b1
, &b2
, &b3
, &b4
) != 4)
419 if ((ep
- bp
) < INADDRSZ
) {
420 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
423 pvt
->net
.n_addr
= bp
;
428 pvt
->net
.n_length
= INADDRSZ
* 8;
436 RES_SET_H_ERRNO(pvt
->res
, TRY_AGAIN
);
444 static struct nwent
*
445 get1101mask(struct irs_nw
*this, struct nwent
*nwent
) {
446 struct pvt
*pvt
= (struct pvt
*)this->private;
447 char qbuf
[sizeof "255.255.255.255.in-addr.arpa"], owner
[MAXDNAME
];
448 int anslen
, type
, class, ancount
, qdcount
;
449 u_char
*ansbuf
, *cp
, *eom
;
454 if (make1101inaddr(nwent
->n_addr
, nwent
->n_length
, qbuf
, sizeof qbuf
)
456 /* "First, do no harm." */
460 ansbuf
= memget(MAXPACKET
);
461 if (ansbuf
== NULL
) {
463 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
466 /* Query for the A RR that would hold this network's mask. */
467 anslen
= res_nquery(pvt
->res
, qbuf
, C_IN
, T_A
, ansbuf
, MAXPACKET
);
468 if (anslen
< HFIXEDSZ
) {
469 memput(ansbuf
, MAXPACKET
);
473 /* Initialize, and parse header. */
474 hp
= (HEADER
*)ansbuf
;
475 cp
= ansbuf
+ HFIXEDSZ
;
476 eom
= ansbuf
+ anslen
;
477 qdcount
= ntohs(hp
->qdcount
);
478 while (qdcount
-- > 0) {
479 int n
= dn_skipname(cp
, eom
);
481 if (n
< 0 || cp
> eom
) {
482 memput(ansbuf
, MAXPACKET
);
486 ancount
= ntohs(hp
->ancount
);
488 /* Parse the answer, collect aliases. */
489 while (--ancount
>= 0 && cp
< eom
) {
490 int n
= dn_expand(ansbuf
, eom
, cp
, owner
, sizeof owner
);
492 if (n
< 0 || !maybe_dnok(pvt
->res
, owner
))
495 if (cp
+ 3 * INT16SZ
+ INT32SZ
> eom
)
497 GETSHORT(type
, cp
); /* Type */
498 GETSHORT(class, cp
); /* Class */
499 cp
+= INT32SZ
; /* TTL */
500 GETSHORT(n
, cp
); /* RDLENGTH */
503 if (n
== INADDRSZ
&& class == C_IN
&& type
== T_A
&&
504 ns_samename(qbuf
, owner
) == 1) {
505 /* This A RR indicates the actual netmask. */
509 for (nn
= 0; nn
< INADDRSZ
; nn
++)
510 for (mm
= 7; mm
>= 0; mm
--)
511 if (cp
[nn
] & (1 << mm
))
518 memput(ansbuf
, MAXPACKET
);
523 make1101inaddr(const u_char
*net
, int bits
, char *name
, int size
) {
529 /* Zero fill any whole bytes left out of the prefix. */
530 for (n
= (32 - bits
) / 8; n
> 0; n
--) {
531 if (ep
- name
< (int)(sizeof "0."))
533 m
= SPRINTF((name
, "0."));
537 /* Format the partial byte, if any, within the prefix. */
538 if ((n
= bits
% 8) != 0) {
539 if (ep
- name
< (int)(sizeof "255."))
541 m
= SPRINTF((name
, "%u.",
542 net
[bits
/ 8] & ~((1 << (8 - n
)) - 1)));
546 /* Format the whole bytes within the prefix. */
547 for (n
= bits
/ 8; n
> 0; n
--) {
548 if (ep
- name
< (int)(sizeof "255."))
550 m
= SPRINTF((name
, "%u.", net
[n
- 1]));
554 /* Add the static text. */
555 if (ep
- name
< (int)(sizeof "in-addr.arpa"))
557 (void) SPRINTF((name
, "in-addr.arpa"));
566 normalize_name(char *name
) {
569 /* Make lower case. */
570 for (t
= name
; *t
; t
++)
571 if (isascii((unsigned char)*t
) && isupper((unsigned char)*t
))
574 /* Remove trailing dots. */
575 while (t
> name
&& t
[-1] == '.')
580 init(struct irs_nw
*this) {
581 struct pvt
*pvt
= (struct pvt
*)this->private;
583 if (!pvt
->res
&& !nw_res_get(this))
585 if (((pvt
->res
->options
& RES_INIT
) == 0U) &&
586 res_ninit(pvt
->res
) == -1)