]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bind/lib/irs/dns_nw.c
This commit was generated by cvs2svn to compensate for changes in r52894,
[FreeBSD/FreeBSD.git] / contrib / bind / lib / irs / dns_nw.c
1 /*
2  * Copyright (c) 1996, 1998 by Internet Software Consortium.
3  *
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.
7  *
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
15  * SOFTWARE.
16  */
17
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 */
21
22 /* Imports. */
23
24 #include "port_before.h"
25
26 #include <sys/param.h>
27 #include <sys/socket.h>
28
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <arpa/nameser.h>
32
33 #include <ctype.h>
34 #include <errno.h>
35 #include <netdb.h>
36 #include <resolv.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include <irs.h>
42
43 #include "port_after.h"
44
45 #include "irs_p.h"
46 #include "dns_p.h"
47
48 #ifdef SPRINTF_CHAR
49 # define SPRINTF(x) strlen(sprintf/**/x)
50 #else
51 # define SPRINTF(x) sprintf x
52 #endif
53
54 extern int h_errno;
55
56 /* Definitions. */
57
58 #define MAXALIASES      35
59
60 #if PACKETSZ > 1024
61 #define MAXPACKET       PACKETSZ
62 #else
63 #define MAXPACKET       1024
64 #endif
65
66 struct pvt {
67         struct nwent    net;
68         char *          ali[MAXALIASES];
69         char            buf[BUFSIZ+1];
70 };
71
72 typedef union {
73         long    al;
74         char    ac;
75 } align;
76
77 enum by_what { by_addr, by_name };
78
79 /* Forwards. */
80
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 *);
87
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,
92                                       enum by_what by_what,
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);
98
99 /* Exports. */
100
101 struct irs_nw *
102 irs_dns_nw(struct irs_acc *this) {
103         struct irs_nw *nw;
104         struct pvt *pvt;
105
106         if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) {
107                 errno = ENOMEM;
108                 return (NULL);
109         }
110         memset(pvt, 0, sizeof *pvt);
111         if (!(nw = (struct irs_nw *)malloc(sizeof *nw))) {
112                 free(pvt);
113                 errno = ENOMEM;
114                 return (NULL);
115         }
116         memset(nw, 0x5e, sizeof *nw);
117         nw->private = pvt;
118         nw->close = nw_close;
119         nw->byname = nw_byname;
120         nw->byaddr = nw_byaddr;
121         nw->next = nw_next;
122         nw->rewind = nw_rewind;
123         nw->minimize = nw_minimize;
124         return (nw);
125 }
126
127 /* Methods. */
128
129 static void
130 nw_close(struct irs_nw *this) {
131         struct pvt *pvt = (struct pvt *)this->private;
132
133         free(pvt);
134         free(this);
135 }
136
137 static struct nwent *
138 nw_byname(struct irs_nw *this, const char *name, int af) {
139         switch (af) {
140         case AF_INET:
141                 return (get1101byname(this, name));
142         default:
143                 (void)NULL;
144         }
145         h_errno = NETDB_INTERNAL;
146         errno = EAFNOSUPPORT;
147         return (NULL);
148 }
149
150 static struct nwent *
151 nw_byaddr(struct irs_nw *this, void *net, int len, int af) {
152         switch (af) {
153         case AF_INET:
154                 return (get1101byaddr(this, net, len));
155         default:
156                 (void)NULL;
157         }
158         h_errno = NETDB_INTERNAL;
159         errno = EAFNOSUPPORT;
160         return (NULL);
161 }
162
163 static struct nwent *
164 nw_next(struct irs_nw *this) {
165         return (NULL);
166 }
167
168 static void
169 nw_rewind(struct irs_nw *this) {
170         /* NOOP */
171 }
172
173 static void
174 nw_minimize(struct irs_nw *this) {
175         /* NOOP */
176 }
177
178 /* Private. */
179
180 static struct nwent *
181 get1101byname(struct irs_nw *this, const char *name) {
182         u_char ansbuf[MAXPACKET];
183         int anslen;
184
185         if ((_res.options & RES_INIT) == 0 && res_init() == -1)
186                 return (NULL);
187         anslen = res_search(name, C_IN, T_PTR, ansbuf, sizeof ansbuf);
188         if (anslen < 0)
189                 return (NULL);
190         return (get1101mask(get1101answer(this, ansbuf, anslen, by_name,
191                                           AF_INET, name, NULL, 0)));
192 }
193
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"];
198         int anslen;
199
200         if (len < 1 || len > 32) {
201                 errno = EINVAL;
202                 h_errno = NETDB_INTERNAL;
203                 return (NULL);
204         }
205         if (make1101inaddr(net, len, qbuf, sizeof qbuf) < 0)
206                 return (NULL);
207         anslen = res_query(qbuf, C_IN, T_PTR, ansbuf, sizeof ansbuf);
208         if (anslen < 0)
209                 return (NULL);
210         return (get1101mask(get1101answer(this, ansbuf, anslen, by_addr,
211                                           AF_INET, NULL, net, len)));
212 }
213
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)
218 {
219         struct pvt *pvt = (struct pvt *)this->private;
220         int type, class, buflen, ancount, qdcount, haveanswer;
221         char *bp, **ap;
222         u_char *cp, *eom;
223         HEADER *hp;
224
225         /* Initialize, and parse header. */
226         eom = ansbuf + anslen;
227         if (ansbuf + HFIXEDSZ > eom) {
228                 h_errno = NO_RECOVERY;
229                 return (NULL);
230         }
231         hp = (HEADER *)ansbuf;
232         cp = ansbuf + HFIXEDSZ;
233         qdcount = ntohs(hp->qdcount);
234         while (qdcount-- > 0) {
235                 int n = dn_skipname(cp, eom);
236                 cp += n + QFIXEDSZ;
237                 if (n < 0 || cp > eom) {
238                         h_errno = NO_RECOVERY;
239                         return (NULL);
240                 }
241         }
242         ancount = ntohs(hp->ancount);
243         if (!ancount) {
244                 if (hp->aa)
245                         h_errno = HOST_NOT_FOUND;
246                 else
247                         h_errno = TRY_AGAIN;
248                 return (NULL);
249         }
250
251         /* Prepare a return structure. */
252         bp = pvt->buf;
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;
259
260         /* Save input key if given. */
261         switch (by_what) {
262         case by_name:
263                 if (name != NULL) {
264                         int n = strlen(name) + 1;
265
266                         if (n > buflen) {
267                                 h_errno = NO_RECOVERY;
268                                 return (NULL);
269                         }
270                         pvt->net.n_name = strcpy(bp, name);
271                         bp += n;
272                         buflen -= n;
273                 }
274                 break;
275         case by_addr:
276                 if (addr != NULL && addrlen != 0) {
277                         int n = addrlen / 8 + ((addrlen % 8) != 0);
278
279                         if (INADDRSZ > buflen) {
280                                 h_errno = NO_RECOVERY;
281                                 return (NULL);
282                         }
283                         memset(bp, 0, INADDRSZ);
284                         memcpy(bp, addr, n);
285                         pvt->net.n_addr = bp;
286                         bp += INADDRSZ;
287                         buflen -= INADDRSZ;
288                 }
289                 break;
290         default:
291                 abort();
292         }
293
294         /* Parse the answer, collect aliases. */
295         ap = pvt->ali;
296         haveanswer = 0;
297         while (--ancount >= 0 && cp < eom) {
298                 int n = dn_expand(ansbuf, eom, cp, bp, buflen);
299
300                 cp += n;                /* Owner */
301                 if (n < 0 || !res_dnok(bp) ||
302                     cp + 3 * INT16SZ + INT32SZ > eom) {
303                         h_errno = NO_RECOVERY;
304                         return (NULL);
305                 }
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) {
311                         int nn;
312
313                         nn = dn_expand(ansbuf, eom, cp, bp, buflen);
314                         if (nn < 0 || !res_hnok(bp) || nn != n) {
315                                 h_errno = NO_RECOVERY;
316                                 return (NULL);
317                         }
318                         normalize_name(bp);
319                         switch (by_what) {
320                         case by_addr: {
321                                 if (pvt->net.n_name == NULL)
322                                         pvt->net.n_name = bp;
323                                 else if (strcasecmp(pvt->net.n_name, bp) == 0)
324                                         break;
325                                 else
326                                         *ap++ = bp;
327                                 nn = strlen(bp) + 1;
328                                 bp += nn;
329                                 buflen -= nn;
330                                 haveanswer++;
331                                 break;
332                             }
333                         case by_name: {
334                                 u_int b1, b2, b3, b4;
335
336                                 if (pvt->net.n_addr != NULL ||
337                                     sscanf(bp, "%u.%u.%u.%u.in-addr.arpa",
338                                            &b1, &b2, &b3, &b4) != 4)
339                                         break;
340                                 if (buflen < INADDRSZ) {
341                                         h_errno = NO_RECOVERY;
342                                         return (NULL);
343                                 }
344                                 pvt->net.n_addr = bp;
345                                 *bp++ = b4;
346                                 *bp++ = b3;
347                                 *bp++ = b2;
348                                 *bp++ = b1;
349                                 buflen -= INADDRSZ;
350                                 pvt->net.n_length = INADDRSZ * 8;
351                                 haveanswer++;
352                             }
353                         }
354                 }
355                 cp += n;                /* RDATA */
356         }
357         if (!haveanswer) {
358                 h_errno = TRY_AGAIN;
359                 return (NULL);
360         }
361         *ap = NULL;
362
363         return (&pvt->net);
364 }
365
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;
371         HEADER *hp;
372
373         if (!nwent)
374                 return (NULL);
375         if (make1101inaddr(nwent->n_addr, nwent->n_length, qbuf, sizeof qbuf)
376             < 0) {
377                 /* "First, do no harm." */
378                 return (nwent);
379         }
380
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)
384                 return (nwent);
385
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);
393                 cp += n + QFIXEDSZ;
394                 if (n < 0 || cp > eom)
395                         return (nwent);
396         }
397         ancount = ntohs(hp->ancount);
398
399         /* Parse the answer, collect aliases. */
400         while (--ancount >= 0 && cp < eom) {
401                 int n = dn_expand(ansbuf, eom, cp, owner, sizeof owner);
402
403                 if (n < 0 || !res_dnok(owner))
404                         break;
405                 cp += n;                /* Owner */
406                 if (cp + 3 * INT16SZ + INT32SZ > eom)
407                         break;
408                 GETSHORT(type, cp);     /* Type */
409                 GETSHORT(class, cp);    /* Class */
410                 cp += INT32SZ;          /* TTL */
411                 GETSHORT(n, cp);        /* RDLENGTH */
412                 if (cp + n > eom)
413                         break;
414                 if (n == INADDRSZ && class == C_IN && type == T_A &&
415                     !strcasecmp(qbuf, owner)) {
416                         /* This A RR indicates the actual netmask. */
417                         int nn, mm;
418
419                         nwent->n_length = 0;
420                         for (nn = 0; nn < INADDRSZ; nn++)
421                                 for (mm = 7; mm >= 0; mm--)
422                                         if (cp[nn] & (1 << mm))
423                                                 nwent->n_length++;
424                                         else
425                                                 break;
426                 }
427                 cp += n;                /* RDATA */
428         }
429         return (nwent);
430 }
431
432 static int
433 make1101inaddr(const u_char *net, int bits, char *name, int size) {
434         int n, m;
435
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."))
439                         goto emsgsize;
440                 m = SPRINTF((name, "0."));
441                 name += m;
442                 size -= m;
443         }
444
445         /* Format the partial byte, if any, within the prefix. */
446         if ((n = bits % 8) != 0) {
447                 if (size < (int)(sizeof "255."))
448                         goto emsgsize;
449                 m = SPRINTF((name, "%u.",
450                              net[bits / 8] & ~((1 << (8 - n)) - 1)));
451                 name += m;
452                 size -= m;
453         }
454
455         /* Format the whole bytes within the prefix. */
456         for (n = bits / 8; n > 0; n--) {
457                 if (size < (int)(sizeof "255."))
458                         goto emsgsize;
459                 m = SPRINTF((name, "%u.", net[n - 1]));
460                 name += m;
461                 size -= m;
462         }
463
464         /* Add the static text. */
465         if (size < (int)(sizeof "in-addr.arpa"))
466                 goto emsgsize;
467         (void) SPRINTF((name, "in-addr.arpa"));
468         return (0);
469
470  emsgsize:
471         errno = EMSGSIZE;
472         return (-1);
473 }
474
475 static void
476 normalize_name(char *name) {
477         char *t;
478
479         /* Make lower case. */
480         for (t = name; *t; t++)
481                 if (isascii(*t) && isupper(*t))
482                         *t = tolower(*t);
483
484         /* Remove trailing dots. */
485         while (t > name && t[-1] == '.')
486                 *--t = '\0';
487 }