]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - lib/libc/net/getnetbydns.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / lib / libc / net / getnetbydns.c
1 /*-
2  * Copyright (c) 1985, 1988, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  * -
29  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
30  *
31  * Permission to use, copy, modify, and distribute this software for any
32  * purpose with or without fee is hereby granted, provided that the above
33  * copyright notice and this permission notice appear in all copies, and that
34  * the name of Digital Equipment Corporation not be used in advertising or
35  * publicity pertaining to distribution of the document or software without
36  * specific, written prior permission.
37  *
38  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
39  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
40  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
41  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
42  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
43  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
44  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45  * SOFTWARE.
46  * -
47  * --Copyright--
48  */
49 /* Portions Copyright (c) 1993 Carlos Leandro and Rui Salgueiro
50  *      Dep. Matematica Universidade de Coimbra, Portugal, Europe
51  *
52  * Permission to use, copy, modify, and distribute this software for any
53  * purpose with or without fee is hereby granted, provided that the above
54  * copyright notice and this permission notice appear in all copies.
55  */
56
57 #if defined(LIBC_SCCS) && !defined(lint)
58 static char sccsid[] = "@(#)gethostnamadr.c     8.1 (Berkeley) 6/4/93";
59 #endif /* LIBC_SCCS and not lint */
60 #include <sys/cdefs.h>
61 __FBSDID("$FreeBSD$");
62
63 #include <sys/param.h>
64 #include <sys/socket.h>
65 #include <netinet/in.h>
66 #include <arpa/inet.h>
67 #include <arpa/nameser.h>
68
69 #include <errno.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <netdb.h>
73 #include <resolv.h>
74 #include <ctype.h>
75 #include <string.h>
76 #include <unistd.h>
77 #include <syslog.h>
78 #include <stdarg.h>
79 #include <nsswitch.h>
80
81 #include "netdb_private.h"
82 #include "res_config.h"
83
84 #define BYADDR 0
85 #define BYNAME 1
86
87 #define MAXPACKET       (64*1024)
88
89 typedef union {
90         HEADER  hdr;
91         u_char  buf[MAXPACKET];
92 } querybuf;
93
94 typedef union {
95         long    al;
96         char    ac;
97 } align;
98
99 /*
100  * Reverse the order of first four dotted entries of in.
101  * Out must contain space for at least strlen(in) characters.
102  * The result does not include any leading 0s of in.
103  */
104 static void
105 ipreverse(char *in, char *out)
106 {
107         char *pos[4];
108         int len[4];
109         char *p, *start;
110         int i = 0;
111         int leading = 1;
112
113         /* Fill-in element positions and lengths: pos[], len[]. */
114         start = p = in;
115         for (;;) {
116                 if (*p == '.' || *p == '\0') {
117                         /* Leading 0? */
118                         if (leading && p - start == 1 && *start == '0')
119                                 len[i] = 0;
120                         else {
121                                 len[i] = p - start;
122                                 leading = 0;
123                         }
124                         pos[i] = start;
125                         start = p + 1;
126                         i++;
127                 }
128                 if (i == 4)
129                         break;
130                 if (*p == 0) {
131                         for (; i < 4; i++) {
132                                 pos[i] = p;
133                                 len[i] = 0;
134                         }
135                         break;
136                 }
137                 p++;
138         }
139
140         /* Copy the entries in reverse order */
141         p = out;
142         leading = 1;
143         for (i = 3; i >= 0; i--) {
144                 memcpy(p, pos[i], len[i]);
145                 if (len[i])
146                         leading = 0;
147                 p += len[i];
148                 /* Need a . separator? */
149                 if (!leading && i > 0 && len[i - 1])
150                         *p++ = '.';
151         }
152         *p = '\0';
153 }
154
155 static int
156 getnetanswer(querybuf *answer, int anslen, int net_i, struct netent *ne,
157     struct netent_data *ned, res_state statp)
158 {
159
160         HEADER *hp;
161         u_char *cp;
162         int n;
163         u_char *eom;
164         int type, class, ancount, qdcount, haveanswer;
165         char aux[MAXHOSTNAMELEN];
166         char ans[MAXHOSTNAMELEN];
167         char *in, *bp, *ep, **ap;
168
169         /*
170          * find first satisfactory answer
171          *
172          *      answer --> +------------+  ( MESSAGE )
173          *                 |   Header   |
174          *                 +------------+
175          *                 |  Question  | the question for the name server
176          *                 +------------+
177          *                 |   Answer   | RRs answering the question
178          *                 +------------+
179          *                 | Authority  | RRs pointing toward an authority
180          *                 | Additional | RRs holding additional information
181          *                 +------------+
182          */
183         eom = answer->buf + anslen;
184         hp = &answer->hdr;
185         ancount = ntohs(hp->ancount); /* #/records in the answer section */
186         qdcount = ntohs(hp->qdcount); /* #/entries in the question section */
187         bp = ned->netbuf;
188         ep = ned->netbuf + sizeof(ned->netbuf);
189         cp = answer->buf + HFIXEDSZ;
190         if (!qdcount) {
191                 if (hp->aa)
192                         RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
193                 else
194                         RES_SET_H_ERRNO(statp, TRY_AGAIN);
195                 return (-1);
196         }
197         while (qdcount-- > 0)
198                 cp += __dn_skipname(cp, eom) + QFIXEDSZ;
199         ap = ned->net_aliases;
200         *ap = NULL;
201         ne->n_aliases = ned->net_aliases;
202         haveanswer = 0;
203         while (--ancount >= 0 && cp < eom) {
204                 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
205                 if ((n < 0) || !res_dnok(bp))
206                         break;
207                 cp += n;
208                 ans[0] = '\0';
209                 (void)strncpy(&ans[0], bp, sizeof(ans) - 1);
210                 ans[sizeof(ans) - 1] = '\0';
211                 GETSHORT(type, cp);
212                 GETSHORT(class, cp);
213                 cp += INT32SZ;          /* TTL */
214                 GETSHORT(n, cp);
215                 if (class == C_IN && type == T_PTR) {
216                         n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
217                         if ((n < 0) || !res_hnok(bp)) {
218                                 cp += n;
219                                 return (-1);
220                         }
221                         cp += n;
222                         *ap++ = bp;
223                         n = strlen(bp) + 1;
224                         bp += n;
225                         ne->n_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
226                         haveanswer++;
227                 }
228         }
229         if (haveanswer) {
230                 *ap = NULL;
231                 switch (net_i) {
232                 case BYADDR:
233                         ne->n_name = *ne->n_aliases;
234                         ne->n_net = 0L;
235                         break;
236                 case BYNAME:
237                         in = *ne->n_aliases;
238                         n = strlen(ans) + 1;
239                         if (ep - bp < n) {
240                                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
241                                 errno = ENOBUFS;
242                                 return (-1);
243                         }
244                         strlcpy(bp, ans, ep - bp);
245                         ne->n_name = bp;
246                         if (strlen(in) + 1 > sizeof(aux)) {
247                                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
248                                 errno = ENOBUFS;
249                                 return (-1);
250                         }
251                         ipreverse(in, aux);
252                         ne->n_net = inet_network(aux);
253                         break;
254                 }
255                 ne->n_aliases++;
256                 return (0);
257         }
258         RES_SET_H_ERRNO(statp, TRY_AGAIN);
259         return (-1);
260 }
261
262 int
263 _dns_getnetbyaddr(void *rval, void *cb_data, va_list ap)
264 {
265         uint32_t net;
266         int net_type;
267         char *buffer;
268         size_t buflen;
269         int *errnop, *h_errnop;
270         struct netent *nptr, ne;
271         struct netent_data *ned;
272         unsigned int netbr[4];
273         int nn, anslen, error;
274         querybuf *buf;
275         char qbuf[MAXDNAME];
276         uint32_t net2;
277         res_state statp;
278
279         net = va_arg(ap, uint32_t);
280         net_type = va_arg(ap, int);
281         nptr = va_arg(ap, struct netent *);
282         buffer = va_arg(ap, char *);
283         buflen = va_arg(ap, size_t);
284         errnop = va_arg(ap, int *);
285         h_errnop = va_arg(ap, int *);
286
287         statp = __res_state();
288         if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
289                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
290                 *h_errnop = statp->res_h_errno;
291                 return (NS_UNAVAIL);
292         }
293
294         if ((ned = __netent_data_init()) == NULL) {
295                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
296                 *h_errnop = statp->res_h_errno;
297                 return (NS_UNAVAIL);
298         }
299
300         *((struct netent **)rval) = NULL;
301
302         if (net_type != AF_INET) {
303                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
304                 *h_errnop = statp->res_h_errno;
305                 return (NS_UNAVAIL);
306         }
307
308         for (nn = 4, net2 = net; net2; net2 >>= 8)
309                 netbr[--nn] = net2 & 0xff;
310         switch (nn) {
311         case 3:         /* Class A */
312                 sprintf(qbuf, "0.0.0.%u.in-addr.arpa", netbr[3]);
313                 break;
314         case 2:         /* Class B */
315                 sprintf(qbuf, "0.0.%u.%u.in-addr.arpa", netbr[3], netbr[2]);
316                 break;
317         case 1:         /* Class C */
318                 sprintf(qbuf, "0.%u.%u.%u.in-addr.arpa", netbr[3], netbr[2],
319                     netbr[1]);
320                 break;
321         case 0:         /* Class D - E */
322                 sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa", netbr[3], netbr[2],
323                     netbr[1], netbr[0]);
324                 break;
325         }
326         if ((buf = malloc(sizeof(*buf))) == NULL) {
327                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
328                 *h_errnop = statp->res_h_errno;
329                 return (NS_NOTFOUND);
330         }
331         anslen = res_nquery(statp, qbuf, C_IN, T_PTR, (u_char *)buf,
332             sizeof(*buf));
333         if (anslen < 0) {
334                 free(buf);
335 #ifdef DEBUG
336                 if (statp->options & RES_DEBUG)
337                         printf("res_nsearch failed\n");
338 #endif
339                 *h_errnop = statp->res_h_errno;
340                 return (NS_UNAVAIL);
341         } else if (anslen > sizeof(*buf)) {
342                 free(buf);
343 #ifdef DEBUG
344                 if (statp->options & RES_DEBUG)
345                         printf("res_nsearch static buffer too small\n");
346 #endif
347                 *h_errnop = statp->res_h_errno;
348                 return (NS_UNAVAIL);
349         }
350         error = getnetanswer(buf, anslen, BYADDR, &ne, ned, statp);
351         free(buf);
352         if (error == 0) {
353                 /* Strip trailing zeros */
354                 while ((net & 0xff) == 0 && net != 0)
355                         net >>= 8;
356                 ne.n_net = net;
357                 if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
358                         *errnop = errno;
359                         RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
360                         *h_errnop = statp->res_h_errno;
361                         return (NS_RETURN);
362                 }
363                 *((struct netent **)rval) = nptr;
364                 return (NS_SUCCESS);
365         }
366         *h_errnop = statp->res_h_errno;
367         return (NS_NOTFOUND);
368 }
369
370 int
371 _dns_getnetbyname(void *rval, void *cb_data, va_list ap)
372 {
373         const char *net;
374         char *buffer;
375         size_t buflen;
376         int *errnop, *h_errnop;
377         struct netent *nptr, ne;
378         struct netent_data *ned;
379         int anslen, error;
380         querybuf *buf;
381         char qbuf[MAXDNAME];
382         res_state statp;
383
384         net = va_arg(ap, const char *);
385         nptr = va_arg(ap, struct netent *);
386         buffer = va_arg(ap, char *);
387         buflen = va_arg(ap, size_t);
388         errnop = va_arg(ap, int *);
389         h_errnop = va_arg(ap, int *);
390
391         statp = __res_state();
392         if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
393                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
394                 *h_errnop = statp->res_h_errno;
395                 return (NS_UNAVAIL);
396         }
397         if ((ned = __netent_data_init()) == NULL) {
398                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
399                 *h_errnop = statp->res_h_errno;
400                 return (NS_UNAVAIL);
401         }
402         if ((buf = malloc(sizeof(*buf))) == NULL) {
403                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
404                 *h_errnop = statp->res_h_errno;
405                 return (NS_NOTFOUND);
406         }
407
408         *((struct netent **)rval) = NULL;
409
410         strncpy(qbuf, net, sizeof(qbuf) - 1);
411         qbuf[sizeof(qbuf) - 1] = '\0';
412         anslen = res_nsearch(statp, qbuf, C_IN, T_PTR, (u_char *)buf,
413             sizeof(*buf));
414         if (anslen < 0) {
415                 free(buf);
416 #ifdef DEBUG
417                 if (statp->options & RES_DEBUG)
418                         printf("res_nsearch failed\n");
419 #endif
420                 return (NS_UNAVAIL);
421         } else if (anslen > sizeof(*buf)) {
422                 free(buf);
423 #ifdef DEBUG
424                 if (statp->options & RES_DEBUG)
425                         printf("res_search static buffer too small\n");
426 #endif
427                 return (NS_UNAVAIL);
428         }
429         error = getnetanswer(buf, anslen, BYNAME, &ne, ned, statp);
430         free(buf);
431         if (error != 0) {
432                 *h_errnop = statp->res_h_errno;
433                 return (NS_NOTFOUND);
434         }
435         if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
436                 *errnop = errno;
437                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
438                 *h_errnop = statp->res_h_errno;
439                 return (NS_RETURN);
440         }
441         *((struct netent **)rval) = nptr;
442         return (NS_SUCCESS);
443 }
444
445 void
446 _setnetdnsent(int stayopen)
447 {
448         res_state statp;
449
450         statp = __res_state();
451         if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1)
452                 return;
453         if (stayopen)
454                 statp->options |= RES_STAYOPEN | RES_USEVC;
455 }
456
457 void
458 _endnetdnsent()
459 {
460         res_state statp;
461
462         statp = __res_state();
463         statp->options &= ~(RES_STAYOPEN | RES_USEVC);
464         res_nclose(statp);
465 }