2005-05-23 Ulrich Drepper <drepper@redhat.com>
[glibc.git] / resolv / nss_dns / dns-canon.c
blob91708df51f11a1b21a7a2458b69bb31a56ab495d
1 /* Copyright (C) 2004 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #include <errno.h>
21 #include <netdb.h>
22 #include <resolv.h>
23 #include <stdlib.h>
24 #include <arpa/nameser.h>
25 #include <nsswitch.h>
28 #if PACKETSZ > 65536
29 # define MAXPACKET PACKETSZ
30 #else
31 # define MAXPACKET 65536
32 #endif
35 /* We need this time later. */
36 typedef union querybuf
38 HEADER hdr;
39 unsigned char buf[MAXPACKET];
40 } querybuf;
43 enum nss_status
44 _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen,
45 char **result,int *errnop, int *h_errnop)
47 /* Just an alibi buffer, res_nquery will allocate a real buffer for
48 us. */
49 unsigned char buf[20];
50 union
52 querybuf *buf;
53 unsigned char *ptr;
54 } ansp = { .ptr = buf };
55 enum nss_status status = NSS_STATUS_UNAVAIL;
56 int qtypes[] = { ns_t_a, ns_t_aaaa };
57 #define nqtypes (sizeof (qtypes) / sizeof (qtypes[0]))
59 for (int i = 0; i < nqtypes; ++i)
61 int r = __libc_res_nquery (&_res, name, ns_c_in, qtypes[i],
62 buf, sizeof (buf), &ansp.ptr);
63 if (r > 0)
65 /* We need to decode the response. Just one question record.
66 And if we got no answers we bail out, too. */
67 if (ansp.buf->hdr.qdcount != htons (1))
68 continue;
70 /* Number of answers. */
71 unsigned int ancount = ntohs (ansp.buf->hdr.ancount);
73 /* Beginning and end of the buffer with query, answer, and the
74 rest. */
75 unsigned char *ptr = &ansp.buf->buf[sizeof (HEADER)];
76 unsigned char *endptr = ansp.ptr + r;
78 /* Skip over the query. This is the name, type, and class. */
79 int s = __dn_skipname (ptr, endptr);
80 if (s < 0)
82 unavail:
83 status = NSS_STATUS_UNAVAIL;
84 break;
87 /* Skip over the name and the two 16-bit values containing type
88 and class. */
89 ptr += s + 2 * sizeof (uint16_t);
91 while (ancount-- > 0)
93 /* Now the reply. First again the name from the query,
94 then type, class, TTL, and the length of the RDATA.
95 We remember the name start. */
96 unsigned char *namestart = ptr;
97 s = __dn_skipname (ptr, endptr);
98 if (s < 0)
99 goto unavail;
101 ptr += s;
103 /* Check whether type and class match. */
104 unsigned int type = ntohs (*(uint16_t *) ptr);
105 if (type == qtypes[i])
107 /* We found the record. */
108 s = __dn_expand (ansp.buf->buf, endptr, namestart,
109 buffer, buflen);
110 if (s < 0)
112 if (errno != EMSGSIZE)
113 goto unavail;
115 /* The buffer is too small. */
116 *errnop = ERANGE;
117 status = NSS_STATUS_TRYAGAIN;
118 h_errno = NETDB_INTERNAL;
120 else
122 /* Success. */
123 *result = buffer;
124 status = NSS_STATUS_SUCCESS;
127 goto out;
130 if (type != ns_t_cname)
131 goto unavail;
133 ptr += sizeof (uint16_t);
134 if (*(uint16_t *) ptr != htons (ns_c_in))
135 goto unavail;
137 /* Also skip over the TTL. */
138 ptr += sizeof (uint16_t) + sizeof (uint32_t);
140 /* Skip over the data length and data. */
141 ptr += sizeof (uint16_t) + ntohs (*(uint16_t *) ptr);
146 out:
147 *h_errnop = h_errno;
149 if (ansp.ptr != buf)
150 free (ansp.ptr);
152 return status;