xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rdata/generic/mx_15.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: mx_15.c,v 1.9 2025/01/26 16:25:32 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 #ifndef RDATA_GENERIC_MX_15_C
17 #define RDATA_GENERIC_MX_15_C
18 
19 #include <string.h>
20 
21 #include <isc/net.h>
22 
23 #include <dns/fixedname.h>
24 
25 #define RRTYPE_MX_ATTRIBUTES (0)
26 
27 static bool
28 check_mx(isc_token_t *token) {
29 	char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")];
30 	struct in_addr addr;
31 	struct in6_addr addr6;
32 
33 	if (strlcpy(tmp, DNS_AS_STR(*token), sizeof(tmp)) >= sizeof(tmp)) {
34 		return true;
35 	}
36 
37 	if (tmp[strlen(tmp) - 1] == '.') {
38 		tmp[strlen(tmp) - 1] = '\0';
39 	}
40 	if (inet_pton(AF_INET, tmp, &addr) == 1 ||
41 	    inet_pton(AF_INET6, tmp, &addr6) == 1)
42 	{
43 		return false;
44 	}
45 
46 	return true;
47 }
48 
49 static isc_result_t
50 fromtext_mx(ARGS_FROMTEXT) {
51 	isc_token_t token;
52 	dns_name_t name;
53 	isc_buffer_t buffer;
54 	bool ok;
55 
56 	REQUIRE(type == dns_rdatatype_mx);
57 
58 	UNUSED(type);
59 	UNUSED(rdclass);
60 
61 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
62 				      false));
63 	if (token.value.as_ulong > 0xffffU) {
64 		RETTOK(ISC_R_RANGE);
65 	}
66 	RETERR(uint16_tobuffer(token.value.as_ulong, target));
67 
68 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
69 				      false));
70 
71 	ok = true;
72 	if ((options & DNS_RDATA_CHECKMX) != 0) {
73 		ok = check_mx(&token);
74 	}
75 	if (!ok && (options & DNS_RDATA_CHECKMXFAIL) != 0) {
76 		RETTOK(DNS_R_MXISADDRESS);
77 	}
78 	if (!ok && callbacks != NULL) {
79 		warn_badmx(&token, lexer, callbacks);
80 	}
81 
82 	dns_name_init(&name, NULL);
83 	buffer_fromregion(&buffer, &token.value.as_region);
84 	if (origin == NULL) {
85 		origin = dns_rootname;
86 	}
87 	RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
88 	ok = true;
89 	if ((options & DNS_RDATA_CHECKNAMES) != 0) {
90 		ok = dns_name_ishostname(&name, false);
91 	}
92 	if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0) {
93 		RETTOK(DNS_R_BADNAME);
94 	}
95 	if (!ok && callbacks != NULL) {
96 		warn_badname(&name, lexer, callbacks);
97 	}
98 	return ISC_R_SUCCESS;
99 }
100 
101 static isc_result_t
102 totext_mx(ARGS_TOTEXT) {
103 	isc_region_t region;
104 	dns_name_t name;
105 	dns_name_t prefix;
106 	unsigned int opts;
107 	char buf[sizeof("64000")];
108 	unsigned short num;
109 
110 	REQUIRE(rdata->type == dns_rdatatype_mx);
111 	REQUIRE(rdata->length != 0);
112 
113 	dns_name_init(&name, NULL);
114 	dns_name_init(&prefix, NULL);
115 
116 	dns_rdata_toregion(rdata, &region);
117 	num = uint16_fromregion(&region);
118 	isc_region_consume(&region, 2);
119 	snprintf(buf, sizeof(buf), "%u", num);
120 	RETERR(str_totext(buf, target));
121 
122 	RETERR(str_totext(" ", target));
123 
124 	dns_name_fromregion(&name, &region);
125 	opts = name_prefix(&name, tctx->origin, &prefix) ? DNS_NAME_OMITFINALDOT
126 							 : 0;
127 	return dns_name_totext(&prefix, opts, target);
128 }
129 
130 static isc_result_t
131 fromwire_mx(ARGS_FROMWIRE) {
132 	dns_name_t name;
133 	isc_region_t sregion;
134 
135 	REQUIRE(type == dns_rdatatype_mx);
136 
137 	UNUSED(type);
138 	UNUSED(rdclass);
139 
140 	dctx = dns_decompress_setpermitted(dctx, true);
141 
142 	dns_name_init(&name, NULL);
143 
144 	isc_buffer_activeregion(source, &sregion);
145 	if (sregion.length < 2) {
146 		return ISC_R_UNEXPECTEDEND;
147 	}
148 	RETERR(mem_tobuffer(target, sregion.base, 2));
149 	isc_buffer_forward(source, 2);
150 	return dns_name_fromwire(&name, source, dctx, target);
151 }
152 
153 static isc_result_t
154 towire_mx(ARGS_TOWIRE) {
155 	dns_name_t name;
156 	dns_offsets_t offsets;
157 	isc_region_t region;
158 
159 	REQUIRE(rdata->type == dns_rdatatype_mx);
160 	REQUIRE(rdata->length != 0);
161 
162 	dns_compress_setpermitted(cctx, true);
163 
164 	dns_rdata_toregion(rdata, &region);
165 	RETERR(mem_tobuffer(target, region.base, 2));
166 	isc_region_consume(&region, 2);
167 
168 	dns_name_init(&name, offsets);
169 	dns_name_fromregion(&name, &region);
170 
171 	return dns_name_towire(&name, cctx, target, NULL);
172 }
173 
174 static int
175 compare_mx(ARGS_COMPARE) {
176 	dns_name_t name1;
177 	dns_name_t name2;
178 	isc_region_t region1;
179 	isc_region_t region2;
180 	int order;
181 
182 	REQUIRE(rdata1->type == rdata2->type);
183 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
184 	REQUIRE(rdata1->type == dns_rdatatype_mx);
185 	REQUIRE(rdata1->length != 0);
186 	REQUIRE(rdata2->length != 0);
187 
188 	order = memcmp(rdata1->data, rdata2->data, 2);
189 	if (order != 0) {
190 		return order < 0 ? -1 : 1;
191 	}
192 
193 	dns_name_init(&name1, NULL);
194 	dns_name_init(&name2, NULL);
195 
196 	dns_rdata_toregion(rdata1, &region1);
197 	dns_rdata_toregion(rdata2, &region2);
198 
199 	isc_region_consume(&region1, 2);
200 	isc_region_consume(&region2, 2);
201 
202 	dns_name_fromregion(&name1, &region1);
203 	dns_name_fromregion(&name2, &region2);
204 
205 	return dns_name_rdatacompare(&name1, &name2);
206 }
207 
208 static isc_result_t
209 fromstruct_mx(ARGS_FROMSTRUCT) {
210 	dns_rdata_mx_t *mx = source;
211 	isc_region_t region;
212 
213 	REQUIRE(type == dns_rdatatype_mx);
214 	REQUIRE(mx != NULL);
215 	REQUIRE(mx->common.rdtype == type);
216 	REQUIRE(mx->common.rdclass == rdclass);
217 
218 	UNUSED(type);
219 	UNUSED(rdclass);
220 
221 	RETERR(uint16_tobuffer(mx->pref, target));
222 	dns_name_toregion(&mx->mx, &region);
223 	return isc_buffer_copyregion(target, &region);
224 }
225 
226 static isc_result_t
227 tostruct_mx(ARGS_TOSTRUCT) {
228 	isc_region_t region;
229 	dns_rdata_mx_t *mx = target;
230 	dns_name_t name;
231 
232 	REQUIRE(rdata->type == dns_rdatatype_mx);
233 	REQUIRE(mx != NULL);
234 	REQUIRE(rdata->length != 0);
235 
236 	mx->common.rdclass = rdata->rdclass;
237 	mx->common.rdtype = rdata->type;
238 	ISC_LINK_INIT(&mx->common, link);
239 
240 	dns_name_init(&name, NULL);
241 	dns_rdata_toregion(rdata, &region);
242 	mx->pref = uint16_fromregion(&region);
243 	isc_region_consume(&region, 2);
244 	dns_name_fromregion(&name, &region);
245 	dns_name_init(&mx->mx, NULL);
246 	name_duporclone(&name, mctx, &mx->mx);
247 	mx->mctx = mctx;
248 	return ISC_R_SUCCESS;
249 }
250 
251 static void
252 freestruct_mx(ARGS_FREESTRUCT) {
253 	dns_rdata_mx_t *mx = source;
254 
255 	REQUIRE(mx != NULL);
256 	REQUIRE(mx->common.rdtype == dns_rdatatype_mx);
257 
258 	if (mx->mctx == NULL) {
259 		return;
260 	}
261 
262 	dns_name_free(&mx->mx, mx->mctx);
263 	mx->mctx = NULL;
264 }
265 
266 static unsigned char port25_offset[] = { 0, 3 };
267 static unsigned char port25_ndata[] = "\003_25\004_tcp";
268 static dns_name_t port25 = DNS_NAME_INITNONABSOLUTE(port25_ndata,
269 						    port25_offset);
270 
271 static isc_result_t
272 additionaldata_mx(ARGS_ADDLDATA) {
273 	isc_result_t result;
274 	dns_fixedname_t fixed;
275 	dns_name_t name;
276 	dns_offsets_t offsets;
277 	isc_region_t region;
278 
279 	REQUIRE(rdata->type == dns_rdatatype_mx);
280 
281 	UNUSED(owner);
282 
283 	dns_name_init(&name, offsets);
284 	dns_rdata_toregion(rdata, &region);
285 	isc_region_consume(&region, 2);
286 	dns_name_fromregion(&name, &region);
287 
288 	if (dns_name_equal(&name, dns_rootname)) {
289 		return ISC_R_SUCCESS;
290 	}
291 
292 	result = (add)(arg, &name, dns_rdatatype_a, NULL DNS__DB_FILELINE);
293 	if (result != ISC_R_SUCCESS) {
294 		return result;
295 	}
296 
297 	dns_fixedname_init(&fixed);
298 	result = dns_name_concatenate(&port25, &name,
299 				      dns_fixedname_name(&fixed), NULL);
300 	if (result != ISC_R_SUCCESS) {
301 		return ISC_R_SUCCESS;
302 	}
303 
304 	return (add)(arg, dns_fixedname_name(&fixed), dns_rdatatype_tlsa,
305 		     NULL DNS__DB_FILELINE);
306 }
307 
308 static isc_result_t
309 digest_mx(ARGS_DIGEST) {
310 	isc_region_t r1, r2;
311 	dns_name_t name;
312 
313 	REQUIRE(rdata->type == dns_rdatatype_mx);
314 
315 	dns_rdata_toregion(rdata, &r1);
316 	r2 = r1;
317 	isc_region_consume(&r2, 2);
318 	r1.length = 2;
319 	RETERR((digest)(arg, &r1));
320 	dns_name_init(&name, NULL);
321 	dns_name_fromregion(&name, &r2);
322 	return dns_name_digest(&name, digest, arg);
323 }
324 
325 static bool
326 checkowner_mx(ARGS_CHECKOWNER) {
327 	REQUIRE(type == dns_rdatatype_mx);
328 
329 	UNUSED(type);
330 	UNUSED(rdclass);
331 
332 	return dns_name_ishostname(name, wildcard);
333 }
334 
335 static bool
336 checknames_mx(ARGS_CHECKNAMES) {
337 	isc_region_t region;
338 	dns_name_t name;
339 
340 	REQUIRE(rdata->type == dns_rdatatype_mx);
341 
342 	UNUSED(owner);
343 
344 	dns_rdata_toregion(rdata, &region);
345 	isc_region_consume(&region, 2);
346 	dns_name_init(&name, NULL);
347 	dns_name_fromregion(&name, &region);
348 	if (!dns_name_ishostname(&name, false)) {
349 		if (bad != NULL) {
350 			dns_name_clone(&name, bad);
351 		}
352 		return false;
353 	}
354 	return true;
355 }
356 
357 static int
358 casecompare_mx(ARGS_COMPARE) {
359 	return compare_mx(rdata1, rdata2);
360 }
361 
362 #endif /* RDATA_GENERIC_MX_15_C */
363