1*5bbd2a12Schristos /* $NetBSD: dns_nw.c,v 1.1.1.2 2012/09/09 16:07:52 christos Exp $ */
2b5677b36Schristos
3b5677b36Schristos /*
4b5677b36Schristos * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5b5677b36Schristos * Copyright (c) 1996-1999 by Internet Software Consortium.
6b5677b36Schristos *
7b5677b36Schristos * Permission to use, copy, modify, and distribute this software for any
8b5677b36Schristos * purpose with or without fee is hereby granted, provided that the above
9b5677b36Schristos * copyright notice and this permission notice appear in all copies.
10b5677b36Schristos *
11b5677b36Schristos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12b5677b36Schristos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13b5677b36Schristos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
14b5677b36Schristos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15b5677b36Schristos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16b5677b36Schristos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17b5677b36Schristos * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18b5677b36Schristos */
19b5677b36Schristos
20b5677b36Schristos #if defined(LIBC_SCCS) && !defined(lint)
21b5677b36Schristos static const char rcsid[] = "Id: dns_nw.c,v 1.12 2005/04/27 04:56:22 sra Exp ";
22b5677b36Schristos #endif /* LIBC_SCCS and not lint */
23b5677b36Schristos
24b5677b36Schristos /* Imports. */
25b5677b36Schristos
26b5677b36Schristos #include "port_before.h"
27b5677b36Schristos
28b5677b36Schristos #include <sys/param.h>
29b5677b36Schristos #include <sys/socket.h>
30b5677b36Schristos
31b5677b36Schristos #include <netinet/in.h>
32b5677b36Schristos #include <arpa/inet.h>
33b5677b36Schristos #include <arpa/nameser.h>
34b5677b36Schristos
35b5677b36Schristos #include <ctype.h>
36b5677b36Schristos #include <errno.h>
37b5677b36Schristos #include <netdb.h>
38b5677b36Schristos #include <resolv.h>
39b5677b36Schristos #include <stdio.h>
40b5677b36Schristos #include <stdlib.h>
41b5677b36Schristos #include <string.h>
42b5677b36Schristos
43b5677b36Schristos #include <isc/memcluster.h>
44b5677b36Schristos #include <irs.h>
45b5677b36Schristos
46b5677b36Schristos #include "port_after.h"
47b5677b36Schristos
48b5677b36Schristos #include "irs_p.h"
49b5677b36Schristos #include "dns_p.h"
50b5677b36Schristos
51b5677b36Schristos #ifdef SPRINTF_CHAR
52b5677b36Schristos # define SPRINTF(x) strlen(sprintf/**/x)
53b5677b36Schristos #else
54b5677b36Schristos # define SPRINTF(x) sprintf x
55b5677b36Schristos #endif
56b5677b36Schristos
57b5677b36Schristos /* Definitions. */
58b5677b36Schristos
59b5677b36Schristos #define MAXALIASES 35
60b5677b36Schristos
61b5677b36Schristos #define MAXPACKET (64*1024)
62b5677b36Schristos
63b5677b36Schristos struct pvt {
64b5677b36Schristos struct nwent net;
65b5677b36Schristos char * ali[MAXALIASES];
66b5677b36Schristos char buf[BUFSIZ+1];
67b5677b36Schristos struct __res_state * res;
68b5677b36Schristos void (*free_res)(void *);
69b5677b36Schristos };
70b5677b36Schristos
71b5677b36Schristos typedef union {
72b5677b36Schristos long al;
73b5677b36Schristos char ac;
74b5677b36Schristos } align;
75b5677b36Schristos
76b5677b36Schristos enum by_what { by_addr, by_name };
77b5677b36Schristos
78b5677b36Schristos /* Forwards. */
79b5677b36Schristos
80b5677b36Schristos static void nw_close(struct irs_nw *);
81b5677b36Schristos static struct nwent * nw_byname(struct irs_nw *, const char *, int);
82b5677b36Schristos static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int);
83b5677b36Schristos static struct nwent * nw_next(struct irs_nw *);
84b5677b36Schristos static void nw_rewind(struct irs_nw *);
85b5677b36Schristos static void nw_minimize(struct irs_nw *);
86b5677b36Schristos static struct __res_state * nw_res_get(struct irs_nw *this);
87b5677b36Schristos static void nw_res_set(struct irs_nw *this,
88b5677b36Schristos struct __res_state *res,
89b5677b36Schristos void (*free_res)(void *));
90b5677b36Schristos
91b5677b36Schristos static struct nwent * get1101byaddr(struct irs_nw *, u_char *, int);
92b5677b36Schristos static struct nwent * get1101byname(struct irs_nw *, const char *);
93b5677b36Schristos static struct nwent * get1101answer(struct irs_nw *,
94b5677b36Schristos u_char *ansbuf, int anslen,
95b5677b36Schristos enum by_what by_what,
96b5677b36Schristos int af, const char *name,
97b5677b36Schristos const u_char *addr, int addrlen);
98b5677b36Schristos static struct nwent * get1101mask(struct irs_nw *this, struct nwent *);
99b5677b36Schristos static int make1101inaddr(const u_char *, int, char *, int);
100b5677b36Schristos static void normalize_name(char *name);
101b5677b36Schristos static int init(struct irs_nw *this);
102b5677b36Schristos
103b5677b36Schristos /* Exports. */
104b5677b36Schristos
105b5677b36Schristos struct irs_nw *
irs_dns_nw(struct irs_acc * this)106b5677b36Schristos irs_dns_nw(struct irs_acc *this) {
107b5677b36Schristos struct irs_nw *nw;
108b5677b36Schristos struct pvt *pvt;
109b5677b36Schristos
110b5677b36Schristos UNUSED(this);
111b5677b36Schristos
112b5677b36Schristos if (!(pvt = memget(sizeof *pvt))) {
113b5677b36Schristos errno = ENOMEM;
114b5677b36Schristos return (NULL);
115b5677b36Schristos }
116b5677b36Schristos memset(pvt, 0, sizeof *pvt);
117b5677b36Schristos if (!(nw = memget(sizeof *nw))) {
118b5677b36Schristos memput(pvt, sizeof *pvt);
119b5677b36Schristos errno = ENOMEM;
120b5677b36Schristos return (NULL);
121b5677b36Schristos }
122b5677b36Schristos memset(nw, 0x5e, sizeof *nw);
123b5677b36Schristos nw->private = pvt;
124b5677b36Schristos nw->close = nw_close;
125b5677b36Schristos nw->byname = nw_byname;
126b5677b36Schristos nw->byaddr = nw_byaddr;
127b5677b36Schristos nw->next = nw_next;
128b5677b36Schristos nw->rewind = nw_rewind;
129b5677b36Schristos nw->minimize = nw_minimize;
130b5677b36Schristos nw->res_get = nw_res_get;
131b5677b36Schristos nw->res_set = nw_res_set;
132b5677b36Schristos return (nw);
133b5677b36Schristos }
134b5677b36Schristos
135b5677b36Schristos /* Methods. */
136b5677b36Schristos
137b5677b36Schristos static void
nw_close(struct irs_nw * this)138b5677b36Schristos nw_close(struct irs_nw *this) {
139b5677b36Schristos struct pvt *pvt = (struct pvt *)this->private;
140b5677b36Schristos
141b5677b36Schristos nw_minimize(this);
142b5677b36Schristos
143b5677b36Schristos if (pvt->res && pvt->free_res)
144b5677b36Schristos (*pvt->free_res)(pvt->res);
145b5677b36Schristos
146b5677b36Schristos memput(pvt, sizeof *pvt);
147b5677b36Schristos memput(this, sizeof *this);
148b5677b36Schristos }
149b5677b36Schristos
150b5677b36Schristos static struct nwent *
nw_byname(struct irs_nw * this,const char * name,int af)151b5677b36Schristos nw_byname(struct irs_nw *this, const char *name, int af) {
152b5677b36Schristos struct pvt *pvt = (struct pvt *)this->private;
153b5677b36Schristos
154b5677b36Schristos if (init(this) == -1)
155b5677b36Schristos return (NULL);
156b5677b36Schristos
157b5677b36Schristos switch (af) {
158b5677b36Schristos case AF_INET:
159b5677b36Schristos return (get1101byname(this, name));
160b5677b36Schristos default:
161b5677b36Schristos (void)NULL;
162b5677b36Schristos }
163b5677b36Schristos RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
164b5677b36Schristos errno = EAFNOSUPPORT;
165b5677b36Schristos return (NULL);
166b5677b36Schristos }
167b5677b36Schristos
168b5677b36Schristos static struct nwent *
nw_byaddr(struct irs_nw * this,void * net,int len,int af)169b5677b36Schristos nw_byaddr(struct irs_nw *this, void *net, int len, int af) {
170b5677b36Schristos struct pvt *pvt = (struct pvt *)this->private;
171b5677b36Schristos
172b5677b36Schristos if (init(this) == -1)
173b5677b36Schristos return (NULL);
174b5677b36Schristos
175b5677b36Schristos switch (af) {
176b5677b36Schristos case AF_INET:
177b5677b36Schristos return (get1101byaddr(this, net, len));
178b5677b36Schristos default:
179b5677b36Schristos (void)NULL;
180b5677b36Schristos }
181b5677b36Schristos RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
182b5677b36Schristos errno = EAFNOSUPPORT;
183b5677b36Schristos return (NULL);
184b5677b36Schristos }
185b5677b36Schristos
186b5677b36Schristos static struct nwent *
nw_next(struct irs_nw * this)187b5677b36Schristos nw_next(struct irs_nw *this) {
188b5677b36Schristos
189b5677b36Schristos UNUSED(this);
190b5677b36Schristos
191b5677b36Schristos return (NULL);
192b5677b36Schristos }
193b5677b36Schristos
194b5677b36Schristos static void
nw_rewind(struct irs_nw * this)195b5677b36Schristos nw_rewind(struct irs_nw *this) {
196b5677b36Schristos UNUSED(this);
197b5677b36Schristos /* NOOP */
198b5677b36Schristos }
199b5677b36Schristos
200b5677b36Schristos static void
nw_minimize(struct irs_nw * this)201b5677b36Schristos nw_minimize(struct irs_nw *this) {
202b5677b36Schristos struct pvt *pvt = (struct pvt *)this->private;
203b5677b36Schristos
204b5677b36Schristos if (pvt->res)
205b5677b36Schristos res_nclose(pvt->res);
206b5677b36Schristos }
207b5677b36Schristos
208b5677b36Schristos static struct __res_state *
nw_res_get(struct irs_nw * this)209b5677b36Schristos nw_res_get(struct irs_nw *this) {
210b5677b36Schristos struct pvt *pvt = (struct pvt *)this->private;
211b5677b36Schristos
212b5677b36Schristos if (!pvt->res) {
213b5677b36Schristos struct __res_state *res;
214b5677b36Schristos res = (struct __res_state *)malloc(sizeof *res);
215b5677b36Schristos if (!res) {
216b5677b36Schristos errno = ENOMEM;
217b5677b36Schristos return (NULL);
218b5677b36Schristos }
219b5677b36Schristos memset(res, 0, sizeof *res);
220b5677b36Schristos nw_res_set(this, res, free);
221b5677b36Schristos }
222b5677b36Schristos
223b5677b36Schristos return (pvt->res);
224b5677b36Schristos }
225b5677b36Schristos
226b5677b36Schristos static void
nw_res_set(struct irs_nw * this,struct __res_state * res,void (* free_res)(void *))227b5677b36Schristos nw_res_set(struct irs_nw *this, struct __res_state *res,
228b5677b36Schristos void (*free_res)(void *)) {
229b5677b36Schristos struct pvt *pvt = (struct pvt *)this->private;
230b5677b36Schristos
231b5677b36Schristos if (pvt->res && pvt->free_res) {
232b5677b36Schristos res_nclose(pvt->res);
233b5677b36Schristos (*pvt->free_res)(pvt->res);
234b5677b36Schristos }
235b5677b36Schristos
236b5677b36Schristos pvt->res = res;
237b5677b36Schristos pvt->free_res = free_res;
238b5677b36Schristos }
239b5677b36Schristos
240b5677b36Schristos /* Private. */
241b5677b36Schristos
242b5677b36Schristos static struct nwent *
get1101byname(struct irs_nw * this,const char * name)243b5677b36Schristos get1101byname(struct irs_nw *this, const char *name) {
244b5677b36Schristos struct pvt *pvt = (struct pvt *)this->private;
245b5677b36Schristos u_char *ansbuf;
246b5677b36Schristos int anslen;
247b5677b36Schristos struct nwent *result;
248b5677b36Schristos
249b5677b36Schristos ansbuf = memget(MAXPACKET);
250b5677b36Schristos if (ansbuf == NULL) {
251b5677b36Schristos errno = ENOMEM;
252b5677b36Schristos RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
253b5677b36Schristos return (NULL);
254b5677b36Schristos }
255b5677b36Schristos anslen = res_nsearch(pvt->res, name, C_IN, T_PTR, ansbuf, MAXPACKET);
256b5677b36Schristos if (anslen < 0) {
257b5677b36Schristos memput(ansbuf, MAXPACKET);
258b5677b36Schristos return (NULL);
259b5677b36Schristos }
260b5677b36Schristos result = get1101mask(this, get1101answer(this, ansbuf, anslen, by_name,
261b5677b36Schristos AF_INET, name, NULL, 0));
262b5677b36Schristos memput(ansbuf, MAXPACKET);
263b5677b36Schristos return (result);
264b5677b36Schristos }
265b5677b36Schristos
266b5677b36Schristos static struct nwent *
get1101byaddr(struct irs_nw * this,u_char * net,int len)267b5677b36Schristos get1101byaddr(struct irs_nw *this, u_char *net, int len) {
268b5677b36Schristos struct pvt *pvt = (struct pvt *)this->private;
269b5677b36Schristos char qbuf[sizeof "255.255.255.255.in-addr.arpa"];
270b5677b36Schristos struct nwent *result;
271b5677b36Schristos u_char *ansbuf;
272b5677b36Schristos int anslen;
273b5677b36Schristos
274b5677b36Schristos if (len < 1 || len > 32) {
275b5677b36Schristos errno = EINVAL;
276b5677b36Schristos RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
277b5677b36Schristos return (NULL);
278b5677b36Schristos }
279b5677b36Schristos if (make1101inaddr(net, len, qbuf, sizeof qbuf) < 0)
280b5677b36Schristos return (NULL);
281b5677b36Schristos ansbuf = memget(MAXPACKET);
282b5677b36Schristos if (ansbuf == NULL) {
283b5677b36Schristos errno = ENOMEM;
284b5677b36Schristos RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
285b5677b36Schristos return (NULL);
286b5677b36Schristos }
287b5677b36Schristos anslen = res_nquery(pvt->res, qbuf, C_IN, T_PTR, ansbuf, MAXPACKET);
288b5677b36Schristos if (anslen < 0) {
289b5677b36Schristos memput(ansbuf, MAXPACKET);
290b5677b36Schristos return (NULL);
291b5677b36Schristos }
292b5677b36Schristos result = get1101mask(this, get1101answer(this, ansbuf, anslen, by_addr,
293b5677b36Schristos AF_INET, NULL, net, len));
294b5677b36Schristos memput(ansbuf, MAXPACKET);
295b5677b36Schristos return (result);
296b5677b36Schristos }
297b5677b36Schristos
298b5677b36Schristos static struct nwent *
get1101answer(struct irs_nw * this,u_char * ansbuf,int anslen,enum by_what by_what,int af,const char * name,const u_char * addr,int addrlen)299b5677b36Schristos get1101answer(struct irs_nw *this,
300b5677b36Schristos u_char *ansbuf, int anslen, enum by_what by_what,
301b5677b36Schristos int af, const char *name, const u_char *addr, int addrlen)
302b5677b36Schristos {
303b5677b36Schristos struct pvt *pvt = (struct pvt *)this->private;
304b5677b36Schristos int type, class, ancount, qdcount, haveanswer;
305b5677b36Schristos char *bp, *ep, **ap;
306b5677b36Schristos u_char *cp, *eom;
307b5677b36Schristos HEADER *hp;
308b5677b36Schristos
309b5677b36Schristos /* Initialize, and parse header. */
310b5677b36Schristos eom = ansbuf + anslen;
311b5677b36Schristos if (ansbuf + HFIXEDSZ > eom) {
312b5677b36Schristos RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
313b5677b36Schristos return (NULL);
314b5677b36Schristos }
315b5677b36Schristos hp = (HEADER *)ansbuf;
316b5677b36Schristos cp = ansbuf + HFIXEDSZ;
317b5677b36Schristos qdcount = ntohs(hp->qdcount);
318b5677b36Schristos while (qdcount-- > 0) {
319b5677b36Schristos int n = dn_skipname(cp, eom);
320b5677b36Schristos cp += n + QFIXEDSZ;
321b5677b36Schristos if (n < 0 || cp > eom) {
322b5677b36Schristos RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
323b5677b36Schristos return (NULL);
324b5677b36Schristos }
325b5677b36Schristos }
326b5677b36Schristos ancount = ntohs(hp->ancount);
327b5677b36Schristos if (!ancount) {
328b5677b36Schristos if (hp->aa)
329b5677b36Schristos RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
330b5677b36Schristos else
331b5677b36Schristos RES_SET_H_ERRNO(pvt->res, TRY_AGAIN);
332b5677b36Schristos return (NULL);
333b5677b36Schristos }
334b5677b36Schristos
335b5677b36Schristos /* Prepare a return structure. */
336b5677b36Schristos bp = pvt->buf;
337b5677b36Schristos ep = pvt->buf + sizeof(pvt->buf);
338b5677b36Schristos pvt->net.n_name = NULL;
339b5677b36Schristos pvt->net.n_aliases = pvt->ali;
340b5677b36Schristos pvt->net.n_addrtype = af;
341b5677b36Schristos pvt->net.n_addr = NULL;
342b5677b36Schristos pvt->net.n_length = addrlen;
343b5677b36Schristos
344b5677b36Schristos /* Save input key if given. */
345b5677b36Schristos switch (by_what) {
346b5677b36Schristos case by_name:
347b5677b36Schristos if (name != NULL) {
348b5677b36Schristos int n = strlen(name) + 1;
349b5677b36Schristos
350b5677b36Schristos if (n > (ep - bp)) {
351b5677b36Schristos RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
352b5677b36Schristos return (NULL);
353b5677b36Schristos }
354b5677b36Schristos pvt->net.n_name = strcpy(bp, name); /* (checked) */
355b5677b36Schristos bp += n;
356b5677b36Schristos }
357b5677b36Schristos break;
358b5677b36Schristos case by_addr:
359b5677b36Schristos if (addr != NULL && addrlen != 0) {
360b5677b36Schristos int n = addrlen / 8 + ((addrlen % 8) != 0);
361b5677b36Schristos
362b5677b36Schristos if (INADDRSZ > (ep - bp)) {
363b5677b36Schristos RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
364b5677b36Schristos return (NULL);
365b5677b36Schristos }
366b5677b36Schristos memset(bp, 0, INADDRSZ);
367b5677b36Schristos memcpy(bp, addr, n);
368b5677b36Schristos pvt->net.n_addr = bp;
369b5677b36Schristos bp += INADDRSZ;
370b5677b36Schristos }
371b5677b36Schristos break;
372b5677b36Schristos default:
373b5677b36Schristos abort();
374b5677b36Schristos }
375b5677b36Schristos
376b5677b36Schristos /* Parse the answer, collect aliases. */
377b5677b36Schristos ap = pvt->ali;
378b5677b36Schristos haveanswer = 0;
379b5677b36Schristos while (--ancount >= 0 && cp < eom) {
380b5677b36Schristos int n = dn_expand(ansbuf, eom, cp, bp, ep - bp);
381b5677b36Schristos
382b5677b36Schristos cp += n; /*%< Owner */
383b5677b36Schristos if (n < 0 || !maybe_dnok(pvt->res, bp) ||
384b5677b36Schristos cp + 3 * INT16SZ + INT32SZ > eom) {
385b5677b36Schristos RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
386b5677b36Schristos return (NULL);
387b5677b36Schristos }
388b5677b36Schristos GETSHORT(type, cp); /*%< Type */
389b5677b36Schristos GETSHORT(class, cp); /*%< Class */
390b5677b36Schristos cp += INT32SZ; /*%< TTL */
391b5677b36Schristos GETSHORT(n, cp); /*%< RDLENGTH */
392b5677b36Schristos if (class == C_IN && type == T_PTR) {
393b5677b36Schristos int nn;
394b5677b36Schristos
395b5677b36Schristos nn = dn_expand(ansbuf, eom, cp, bp, ep - bp);
396b5677b36Schristos if (nn < 0 || !maybe_hnok(pvt->res, bp) || nn != n) {
397b5677b36Schristos RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
398b5677b36Schristos return (NULL);
399b5677b36Schristos }
400b5677b36Schristos normalize_name(bp);
401b5677b36Schristos switch (by_what) {
402b5677b36Schristos case by_addr: {
403b5677b36Schristos if (pvt->net.n_name == NULL)
404b5677b36Schristos pvt->net.n_name = bp;
405b5677b36Schristos else if (ns_samename(pvt->net.n_name, bp) == 1)
406b5677b36Schristos break;
407b5677b36Schristos else
408b5677b36Schristos *ap++ = bp;
409b5677b36Schristos nn = strlen(bp) + 1;
410b5677b36Schristos bp += nn;
411b5677b36Schristos haveanswer++;
412b5677b36Schristos break;
413b5677b36Schristos }
414b5677b36Schristos case by_name: {
415b5677b36Schristos u_int b1, b2, b3, b4;
416b5677b36Schristos
417b5677b36Schristos if (pvt->net.n_addr != NULL ||
418b5677b36Schristos sscanf(bp, "%u.%u.%u.%u.in-addr.arpa",
419b5677b36Schristos &b1, &b2, &b3, &b4) != 4)
420b5677b36Schristos break;
421b5677b36Schristos if ((ep - bp) < INADDRSZ) {
422b5677b36Schristos RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
423b5677b36Schristos return (NULL);
424b5677b36Schristos }
425b5677b36Schristos pvt->net.n_addr = bp;
426b5677b36Schristos *bp++ = b4;
427b5677b36Schristos *bp++ = b3;
428b5677b36Schristos *bp++ = b2;
429b5677b36Schristos *bp++ = b1;
430b5677b36Schristos pvt->net.n_length = INADDRSZ * 8;
431b5677b36Schristos haveanswer++;
432b5677b36Schristos }
433b5677b36Schristos }
434b5677b36Schristos }
435b5677b36Schristos cp += n; /*%< RDATA */
436b5677b36Schristos }
437b5677b36Schristos if (!haveanswer) {
438b5677b36Schristos RES_SET_H_ERRNO(pvt->res, TRY_AGAIN);
439b5677b36Schristos return (NULL);
440b5677b36Schristos }
441b5677b36Schristos *ap = NULL;
442b5677b36Schristos
443b5677b36Schristos return (&pvt->net);
444b5677b36Schristos }
445b5677b36Schristos
446b5677b36Schristos static struct nwent *
get1101mask(struct irs_nw * this,struct nwent * nwent)447b5677b36Schristos get1101mask(struct irs_nw *this, struct nwent *nwent) {
448b5677b36Schristos struct pvt *pvt = (struct pvt *)this->private;
449b5677b36Schristos char qbuf[sizeof "255.255.255.255.in-addr.arpa"], owner[MAXDNAME];
450b5677b36Schristos int anslen, type, class, ancount, qdcount;
451b5677b36Schristos u_char *ansbuf, *cp, *eom;
452b5677b36Schristos HEADER *hp;
453b5677b36Schristos
454b5677b36Schristos if (!nwent)
455b5677b36Schristos return (NULL);
456b5677b36Schristos if (make1101inaddr(nwent->n_addr, nwent->n_length, qbuf, sizeof qbuf)
457b5677b36Schristos < 0) {
458b5677b36Schristos /* "First, do no harm." */
459b5677b36Schristos return (nwent);
460b5677b36Schristos }
461b5677b36Schristos
462b5677b36Schristos ansbuf = memget(MAXPACKET);
463b5677b36Schristos if (ansbuf == NULL) {
464b5677b36Schristos errno = ENOMEM;
465b5677b36Schristos RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
466b5677b36Schristos return (NULL);
467b5677b36Schristos }
468b5677b36Schristos /* Query for the A RR that would hold this network's mask. */
469b5677b36Schristos anslen = res_nquery(pvt->res, qbuf, C_IN, T_A, ansbuf, MAXPACKET);
470b5677b36Schristos if (anslen < HFIXEDSZ) {
471b5677b36Schristos memput(ansbuf, MAXPACKET);
472b5677b36Schristos return (nwent);
473b5677b36Schristos }
474b5677b36Schristos
475b5677b36Schristos /* Initialize, and parse header. */
476b5677b36Schristos hp = (HEADER *)ansbuf;
477b5677b36Schristos cp = ansbuf + HFIXEDSZ;
478b5677b36Schristos eom = ansbuf + anslen;
479b5677b36Schristos qdcount = ntohs(hp->qdcount);
480b5677b36Schristos while (qdcount-- > 0) {
481b5677b36Schristos int n = dn_skipname(cp, eom);
482b5677b36Schristos cp += n + QFIXEDSZ;
483b5677b36Schristos if (n < 0 || cp > eom) {
484b5677b36Schristos memput(ansbuf, MAXPACKET);
485b5677b36Schristos return (nwent);
486b5677b36Schristos }
487b5677b36Schristos }
488b5677b36Schristos ancount = ntohs(hp->ancount);
489b5677b36Schristos
490b5677b36Schristos /* Parse the answer, collect aliases. */
491b5677b36Schristos while (--ancount >= 0 && cp < eom) {
492b5677b36Schristos int n = dn_expand(ansbuf, eom, cp, owner, sizeof owner);
493b5677b36Schristos
494b5677b36Schristos if (n < 0 || !maybe_dnok(pvt->res, owner))
495b5677b36Schristos break;
496b5677b36Schristos cp += n; /*%< Owner */
497b5677b36Schristos if (cp + 3 * INT16SZ + INT32SZ > eom)
498b5677b36Schristos break;
499b5677b36Schristos GETSHORT(type, cp); /*%< Type */
500b5677b36Schristos GETSHORT(class, cp); /*%< Class */
501b5677b36Schristos cp += INT32SZ; /*%< TTL */
502b5677b36Schristos GETSHORT(n, cp); /*%< RDLENGTH */
503b5677b36Schristos if (cp + n > eom)
504b5677b36Schristos break;
505b5677b36Schristos if (n == INADDRSZ && class == C_IN && type == T_A &&
506b5677b36Schristos ns_samename(qbuf, owner) == 1) {
507b5677b36Schristos /* This A RR indicates the actual netmask. */
508b5677b36Schristos int nn, mm;
509b5677b36Schristos
510b5677b36Schristos nwent->n_length = 0;
511b5677b36Schristos for (nn = 0; nn < INADDRSZ; nn++)
512b5677b36Schristos for (mm = 7; mm >= 0; mm--)
513b5677b36Schristos if (cp[nn] & (1 << mm))
514b5677b36Schristos nwent->n_length++;
515b5677b36Schristos else
516b5677b36Schristos break;
517b5677b36Schristos }
518b5677b36Schristos cp += n; /*%< RDATA */
519b5677b36Schristos }
520b5677b36Schristos memput(ansbuf, MAXPACKET);
521b5677b36Schristos return (nwent);
522b5677b36Schristos }
523b5677b36Schristos
524b5677b36Schristos static int
make1101inaddr(const u_char * net,int bits,char * name,int size)525b5677b36Schristos make1101inaddr(const u_char *net, int bits, char *name, int size) {
526b5677b36Schristos int n, m;
527b5677b36Schristos char *ep;
528b5677b36Schristos
529b5677b36Schristos ep = name + size;
530b5677b36Schristos
531b5677b36Schristos /* Zero fill any whole bytes left out of the prefix. */
532b5677b36Schristos for (n = (32 - bits) / 8; n > 0; n--) {
533b5677b36Schristos if (ep - name < (int)(sizeof "0."))
534b5677b36Schristos goto emsgsize;
535b5677b36Schristos m = SPRINTF((name, "0."));
536b5677b36Schristos name += m;
537b5677b36Schristos }
538b5677b36Schristos
539b5677b36Schristos /* Format the partial byte, if any, within the prefix. */
540b5677b36Schristos if ((n = bits % 8) != 0) {
541b5677b36Schristos if (ep - name < (int)(sizeof "255."))
542b5677b36Schristos goto emsgsize;
543b5677b36Schristos m = SPRINTF((name, "%u.",
544b5677b36Schristos net[bits / 8] & ~((1 << (8 - n)) - 1)));
545b5677b36Schristos name += m;
546b5677b36Schristos }
547b5677b36Schristos
548b5677b36Schristos /* Format the whole bytes within the prefix. */
549b5677b36Schristos for (n = bits / 8; n > 0; n--) {
550b5677b36Schristos if (ep - name < (int)(sizeof "255."))
551b5677b36Schristos goto emsgsize;
552b5677b36Schristos m = SPRINTF((name, "%u.", net[n - 1]));
553b5677b36Schristos name += m;
554b5677b36Schristos }
555b5677b36Schristos
556b5677b36Schristos /* Add the static text. */
557b5677b36Schristos if (ep - name < (int)(sizeof "in-addr.arpa"))
558b5677b36Schristos goto emsgsize;
559b5677b36Schristos (void) SPRINTF((name, "in-addr.arpa"));
560b5677b36Schristos return (0);
561b5677b36Schristos
562b5677b36Schristos emsgsize:
563b5677b36Schristos errno = EMSGSIZE;
564b5677b36Schristos return (-1);
565b5677b36Schristos }
566b5677b36Schristos
567b5677b36Schristos static void
normalize_name(char * name)568b5677b36Schristos normalize_name(char *name) {
569b5677b36Schristos char *t;
570b5677b36Schristos
571b5677b36Schristos /* Make lower case. */
572b5677b36Schristos for (t = name; *t; t++)
573b5677b36Schristos if (isascii((unsigned char)*t) && isupper((unsigned char)*t))
574b5677b36Schristos *t = tolower((*t)&0xff);
575b5677b36Schristos
576b5677b36Schristos /* Remove trailing dots. */
577b5677b36Schristos while (t > name && t[-1] == '.')
578b5677b36Schristos *--t = '\0';
579b5677b36Schristos }
580b5677b36Schristos
581b5677b36Schristos static int
init(struct irs_nw * this)582b5677b36Schristos init(struct irs_nw *this) {
583b5677b36Schristos struct pvt *pvt = (struct pvt *)this->private;
584b5677b36Schristos
585b5677b36Schristos if (!pvt->res && !nw_res_get(this))
586b5677b36Schristos return (-1);
587b5677b36Schristos if (((pvt->res->options & RES_INIT) == 0U) &&
588b5677b36Schristos res_ninit(pvt->res) == -1)
589b5677b36Schristos return (-1);
590b5677b36Schristos return (0);
591b5677b36Schristos }
592b5677b36Schristos
593b5677b36Schristos /*! \file */
594