]> git.ipfire.org Git - thirdparty/glibc.git/blame - resolv/nss_dns/dns-canon.c
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / resolv / nss_dns / dns-canon.c
CommitLineData
2b778ceb 1/* Copyright (C) 2004-2021 Free Software Foundation, Inc.
28977c2c
UD
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
4
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.
9
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.
14
15 You should have received a copy of the GNU Lesser General Public
59ba27a6 16 License along with the GNU C Library; if not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
28977c2c
UD
18
19#include <errno.h>
20#include <netdb.h>
21#include <resolv.h>
22#include <stdlib.h>
e054f494 23#include <stdint.h>
28977c2c
UD
24#include <arpa/nameser.h>
25#include <nsswitch.h>
352f4ff9
FW
26#include <resolv/resolv_context.h>
27#include <resolv/resolv-internal.h>
28977c2c 28
bd65a52a
FW
29NSS_DECLARE_MODULE_FUNCTIONS (dns)
30
28977c2c
UD
31#if PACKETSZ > 65536
32# define MAXPACKET PACKETSZ
33#else
34# define MAXPACKET 65536
35#endif
36
37
38/* We need this time later. */
39typedef union querybuf
40{
41 HEADER hdr;
42 unsigned char buf[MAXPACKET];
43} querybuf;
44
45
acb98cb5
UD
46static const short int qtypes[] = { ns_t_a, ns_t_aaaa };
47#define nqtypes (sizeof (qtypes) / sizeof (qtypes[0]))
48
49
28977c2c
UD
50enum nss_status
51_nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen,
52 char **result,int *errnop, int *h_errnop)
53{
54 /* Just an alibi buffer, res_nquery will allocate a real buffer for
55 us. */
56 unsigned char buf[20];
57 union
58 {
59 querybuf *buf;
60 unsigned char *ptr;
61 } ansp = { .ptr = buf };
10b71c3d 62 enum nss_status status = NSS_STATUS_UNAVAIL;
28977c2c 63
352f4ff9
FW
64 struct resolv_context *ctx = __resolv_context_get ();
65 if (ctx == NULL)
66 {
67 *errnop = errno;
68 *h_errnop = NETDB_INTERNAL;
69 return NSS_STATUS_UNAVAIL;
70 }
71
3207d436 72 for (int i = 0; i < nqtypes; ++i)
28977c2c 73 {
352f4ff9
FW
74 int r = __res_context_query (ctx, name, ns_c_in, qtypes[i],
75 buf, sizeof (buf), &ansp.ptr, NULL, NULL,
76 NULL, NULL);
3207d436 77 if (r > 0)
28977c2c 78 {
3207d436
UD
79 /* We need to decode the response. Just one question record.
80 And if we got no answers we bail out, too. */
81 if (ansp.buf->hdr.qdcount != htons (1))
82 continue;
83
84 /* Number of answers. */
85 unsigned int ancount = ntohs (ansp.buf->hdr.ancount);
86
87 /* Beginning and end of the buffer with query, answer, and the
88 rest. */
89 unsigned char *ptr = &ansp.buf->buf[sizeof (HEADER)];
90 unsigned char *endptr = ansp.ptr + r;
91
92 /* Skip over the query. This is the name, type, and class. */
93 int s = __dn_skipname (ptr, endptr);
94 if (s < 0)
95 {
96 unavail:
97 status = NSS_STATUS_UNAVAIL;
98 break;
99 }
100
101 /* Skip over the name and the two 16-bit values containing type
102 and class. */
103 ptr += s + 2 * sizeof (uint16_t);
104
105 while (ancount-- > 0)
106 {
107 /* Now the reply. First again the name from the query,
108 then type, class, TTL, and the length of the RDATA.
109 We remember the name start. */
110 unsigned char *namestart = ptr;
111 s = __dn_skipname (ptr, endptr);
112 if (s < 0)
113 goto unavail;
114
115 ptr += s;
116
f749498f
FW
117 /* Check that there are enough bytes for the RR
118 metadata. */
119 if (endptr - ptr < 10)
120 goto unavail;
121
3207d436 122 /* Check whether type and class match. */
acb98cb5
UD
123 uint_fast16_t type;
124 NS_GET16 (type, ptr);
3207d436
UD
125 if (type == qtypes[i])
126 {
127 /* We found the record. */
128 s = __dn_expand (ansp.buf->buf, endptr, namestart,
129 buffer, buflen);
130 if (s < 0)
131 {
132 if (errno != EMSGSIZE)
133 goto unavail;
134
135 /* The buffer is too small. */
136 *errnop = ERANGE;
137 status = NSS_STATUS_TRYAGAIN;
138 h_errno = NETDB_INTERNAL;
139 }
140 else
141 {
142 /* Success. */
143 *result = buffer;
144 status = NSS_STATUS_SUCCESS;
145 }
146
147 goto out;
148 }
149
150 if (type != ns_t_cname)
151 goto unavail;
152
cd5743fd 153 if (__ns_get16 (ptr) != ns_c_in)
3207d436
UD
154 goto unavail;
155
f749498f 156 /* Also skip over class and TTL. */
3207d436
UD
157 ptr += sizeof (uint16_t) + sizeof (uint32_t);
158
f749498f
FW
159 /* Skip over RDATA length and RDATA itself. */
160 uint16_t rdatalen = __ns_get16 (ptr);
161 ptr += sizeof (uint16_t);
162 /* Not enough room for RDATA. */
163 if (endptr - ptr < rdatalen)
164 goto unavail;
165 ptr += rdatalen;
3207d436 166 }
28977c2c 167 }
d29fb41f
FW
168
169 /* Restore original buffer before retry. */
170 if (ansp.ptr != buf)
171 {
172 free (ansp.ptr);
173 ansp.ptr = buf;
174 }
28977c2c 175 }
3207d436
UD
176
177 out:
28977c2c
UD
178 *h_errnop = h_errno;
179
180 if (ansp.ptr != buf)
181 free (ansp.ptr);
352f4ff9 182 __resolv_context_put (ctx);
28977c2c
UD
183 return status;
184}