1 /* Implement suppression of AAAA queries.
2 Copyright (C) 2022-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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, see
17 <https://www.gnu.org/licenses/>. */
21 #include <resolv-internal.h>
22 #include <resolv_context.h>
23 #include <arpa/nameser.h>
25 /* Returns true if the question type at P matches EXPECTED, and the
28 qtype_matches (const unsigned char *p
, int expected
)
30 /* This assumes that T_A/C_IN constants are less than 256, which
32 return p
[0] == 0 && p
[1] == expected
&& p
[2] == 0 && p
[3] == C_IN
;
35 /* Handle RES_NOAAAA translation of AAAA queries. To produce a Name
36 Error (NXDOMAIN) response for domain names that do not exist, it is
37 still necessary to send a query. Using question type A is a
38 conservative choice. In the returned answer, it is necessary to
39 switch back the question type to AAAA. */
41 __res_handle_no_aaaa (struct resolv_context
*ctx
,
42 const unsigned char *buf
, int buflen
,
43 unsigned char *ans
, int anssiz
, int *result
)
45 /* AAAA mode is not active, or the query looks invalid (will not be
46 able to be parsed). */
47 if ((ctx
->resp
->options
& RES_NOAAAA
) == 0
48 || buflen
<= sizeof (HEADER
))
51 /* The replacement A query is produced here. */
55 unsigned char question
[NS_MAXCDNAME
+ 4];
57 memcpy (&replacement
.header
, buf
, sizeof (replacement
.header
));
59 if (replacement
.header
.qr
60 || replacement
.header
.opcode
!= 0
61 || replacement
.header
.rcode
!= 0
62 || ntohs (replacement
.header
.qdcount
) != 1
63 || ntohs (replacement
.header
.ancount
) != 0
64 || ntohs (replacement
.header
.nscount
) != 0)
65 /* Not a well-formed question. Let the core resolver code produce
70 replacement
.header
.arcount
= htons (0);
72 /* Extract the QNAME. */
73 int ret
= __ns_name_unpack (buf
, buf
+ buflen
, buf
+ sizeof (HEADER
),
74 replacement
.question
, NS_MAXCDNAME
);
79 /* Compute the end of the question name. */
80 const unsigned char *after_question
= buf
+ sizeof (HEADER
) + ret
;
82 /* Check that we are dealing with an AAAA query. */
83 if (buf
+ buflen
- after_question
< 4
84 || !qtype_matches (after_question
, T_AAAA
))
87 /* Find the place to store the type/class data in the replacement
89 after_question
= replacement
.question
;
90 /* This cannot fail because __ns_name_unpack above produced a valid
92 (void) __ns_name_skip (&after_question
, &replacement
.question
[NS_MAXCDNAME
]);
93 unsigned char *start_of_query
= (unsigned char *) &replacement
;
94 const unsigned char *end_of_query
= after_question
+ 4;
96 /* Produce an A/IN query. */
98 unsigned char *p
= (unsigned char *) after_question
;
105 /* Clear the output buffer, to avoid reading undefined data when
106 rewriting the result from A to AAAA. */
107 memset (ans
, 0, anssiz
);
109 /* Always perform the message translation, independent of the error
111 ret
= __res_context_send (ctx
,
112 start_of_query
, end_of_query
- start_of_query
,
113 NULL
, 0, ans
, anssiz
,
114 NULL
, NULL
, NULL
, NULL
, NULL
);
116 /* Patch in the AAAA question type if there is room and the A query
117 type was received. */
118 after_question
= ans
+ sizeof (HEADER
);
119 if (__ns_name_skip (&after_question
, ans
+ anssiz
) == 0
120 && ans
+ anssiz
- after_question
>= 4
121 && qtype_matches (after_question
, T_A
))
123 ((unsigned char *) after_question
)[1] = T_AAAA
;
125 /* Create an aligned copy of the header. Hide all data except
126 the question from the response. Put back the header. There is
127 no need to change the response code. The zero answer count turns
128 a positive response with data into a no-data response. */
129 memcpy (&replacement
.header
, ans
, sizeof (replacement
.header
));
130 replacement
.header
.ancount
= htons (0);
131 replacement
.header
.nscount
= htons (0);
132 replacement
.header
.arcount
= htons (0);
133 memcpy (ans
, &replacement
.header
, sizeof (replacement
.header
));
135 /* Truncate the reply. */
139 *result
= after_question
- ans
+ 4;