1/*	$NetBSD: srv_33.c,v 1.1 2024/02/18 20:57:46 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/* RFC2782 */
17
18#ifndef RDATA_IN_1_SRV_33_C
19#define RDATA_IN_1_SRV_33_C
20
21#define RRTYPE_SRV_ATTRIBUTES (DNS_RDATATYPEATTR_FOLLOWADDITIONAL)
22
23static isc_result_t
24fromtext_in_srv(ARGS_FROMTEXT) {
25	isc_token_t token;
26	dns_name_t name;
27	isc_buffer_t buffer;
28	bool ok;
29
30	REQUIRE(type == dns_rdatatype_srv);
31	REQUIRE(rdclass == dns_rdataclass_in);
32
33	UNUSED(type);
34	UNUSED(rdclass);
35	UNUSED(callbacks);
36
37	/*
38	 * Priority.
39	 */
40	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
41				      false));
42	if (token.value.as_ulong > 0xffffU) {
43		RETTOK(ISC_R_RANGE);
44	}
45	RETERR(uint16_tobuffer(token.value.as_ulong, target));
46
47	/*
48	 * Weight.
49	 */
50	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
51				      false));
52	if (token.value.as_ulong > 0xffffU) {
53		RETTOK(ISC_R_RANGE);
54	}
55	RETERR(uint16_tobuffer(token.value.as_ulong, target));
56
57	/*
58	 * Port.
59	 */
60	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
61				      false));
62	if (token.value.as_ulong > 0xffffU) {
63		RETTOK(ISC_R_RANGE);
64	}
65	RETERR(uint16_tobuffer(token.value.as_ulong, target));
66
67	/*
68	 * Target.
69	 */
70	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
71				      false));
72	dns_name_init(&name, NULL);
73	buffer_fromregion(&buffer, &token.value.as_region);
74	if (origin == NULL) {
75		origin = dns_rootname;
76	}
77	RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
78	ok = true;
79	if ((options & DNS_RDATA_CHECKNAMES) != 0) {
80		ok = dns_name_ishostname(&name, false);
81	}
82	if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0) {
83		RETTOK(DNS_R_BADNAME);
84	}
85	if (!ok && callbacks != NULL) {
86		warn_badname(&name, lexer, callbacks);
87	}
88	return (ISC_R_SUCCESS);
89}
90
91static isc_result_t
92totext_in_srv(ARGS_TOTEXT) {
93	isc_region_t region;
94	dns_name_t name;
95	dns_name_t prefix;
96	bool sub;
97	char buf[sizeof("64000")];
98	unsigned short num;
99
100	REQUIRE(rdata->type == dns_rdatatype_srv);
101	REQUIRE(rdata->rdclass == dns_rdataclass_in);
102	REQUIRE(rdata->length != 0);
103
104	dns_name_init(&name, NULL);
105	dns_name_init(&prefix, NULL);
106
107	/*
108	 * Priority.
109	 */
110	dns_rdata_toregion(rdata, &region);
111	num = uint16_fromregion(&region);
112	isc_region_consume(&region, 2);
113	snprintf(buf, sizeof(buf), "%u", num);
114	RETERR(str_totext(buf, target));
115	RETERR(str_totext(" ", target));
116
117	/*
118	 * Weight.
119	 */
120	num = uint16_fromregion(&region);
121	isc_region_consume(&region, 2);
122	snprintf(buf, sizeof(buf), "%u", num);
123	RETERR(str_totext(buf, target));
124	RETERR(str_totext(" ", target));
125
126	/*
127	 * Port.
128	 */
129	num = uint16_fromregion(&region);
130	isc_region_consume(&region, 2);
131	snprintf(buf, sizeof(buf), "%u", num);
132	RETERR(str_totext(buf, target));
133	RETERR(str_totext(" ", target));
134
135	/*
136	 * Target.
137	 */
138	dns_name_fromregion(&name, &region);
139	sub = name_prefix(&name, tctx->origin, &prefix);
140	return (dns_name_totext(&prefix, sub, target));
141}
142
143static isc_result_t
144fromwire_in_srv(ARGS_FROMWIRE) {
145	dns_name_t name;
146	isc_region_t sr;
147
148	REQUIRE(type == dns_rdatatype_srv);
149	REQUIRE(rdclass == dns_rdataclass_in);
150
151	UNUSED(type);
152	UNUSED(rdclass);
153
154	dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
155
156	dns_name_init(&name, NULL);
157
158	/*
159	 * Priority, weight, port.
160	 */
161	isc_buffer_activeregion(source, &sr);
162	if (sr.length < 6) {
163		return (ISC_R_UNEXPECTEDEND);
164	}
165	RETERR(mem_tobuffer(target, sr.base, 6));
166	isc_buffer_forward(source, 6);
167
168	/*
169	 * Target.
170	 */
171	return (dns_name_fromwire(&name, source, dctx, options, target));
172}
173
174static isc_result_t
175towire_in_srv(ARGS_TOWIRE) {
176	dns_name_t name;
177	dns_offsets_t offsets;
178	isc_region_t sr;
179
180	REQUIRE(rdata->type == dns_rdatatype_srv);
181	REQUIRE(rdata->length != 0);
182
183	dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
184	/*
185	 * Priority, weight, port.
186	 */
187	dns_rdata_toregion(rdata, &sr);
188	RETERR(mem_tobuffer(target, sr.base, 6));
189	isc_region_consume(&sr, 6);
190
191	/*
192	 * Target.
193	 */
194	dns_name_init(&name, offsets);
195	dns_name_fromregion(&name, &sr);
196	return (dns_name_towire(&name, cctx, target));
197}
198
199static int
200compare_in_srv(ARGS_COMPARE) {
201	dns_name_t name1;
202	dns_name_t name2;
203	isc_region_t region1;
204	isc_region_t region2;
205	int order;
206
207	REQUIRE(rdata1->type == rdata2->type);
208	REQUIRE(rdata1->rdclass == rdata2->rdclass);
209	REQUIRE(rdata1->type == dns_rdatatype_srv);
210	REQUIRE(rdata1->rdclass == dns_rdataclass_in);
211	REQUIRE(rdata1->length != 0);
212	REQUIRE(rdata2->length != 0);
213
214	/*
215	 * Priority, weight, port.
216	 */
217	order = memcmp(rdata1->data, rdata2->data, 6);
218	if (order != 0) {
219		return (order < 0 ? -1 : 1);
220	}
221
222	/*
223	 * Target.
224	 */
225	dns_name_init(&name1, NULL);
226	dns_name_init(&name2, NULL);
227
228	dns_rdata_toregion(rdata1, &region1);
229	dns_rdata_toregion(rdata2, &region2);
230
231	isc_region_consume(&region1, 6);
232	isc_region_consume(&region2, 6);
233
234	dns_name_fromregion(&name1, &region1);
235	dns_name_fromregion(&name2, &region2);
236
237	return (dns_name_rdatacompare(&name1, &name2));
238}
239
240static isc_result_t
241fromstruct_in_srv(ARGS_FROMSTRUCT) {
242	dns_rdata_in_srv_t *srv = source;
243	isc_region_t region;
244
245	REQUIRE(type == dns_rdatatype_srv);
246	REQUIRE(rdclass == dns_rdataclass_in);
247	REQUIRE(srv != NULL);
248	REQUIRE(srv->common.rdtype == type);
249	REQUIRE(srv->common.rdclass == rdclass);
250
251	UNUSED(type);
252	UNUSED(rdclass);
253
254	RETERR(uint16_tobuffer(srv->priority, target));
255	RETERR(uint16_tobuffer(srv->weight, target));
256	RETERR(uint16_tobuffer(srv->port, target));
257	dns_name_toregion(&srv->target, &region);
258	return (isc_buffer_copyregion(target, &region));
259}
260
261static isc_result_t
262tostruct_in_srv(ARGS_TOSTRUCT) {
263	isc_region_t region;
264	dns_rdata_in_srv_t *srv = target;
265	dns_name_t name;
266
267	REQUIRE(rdata->rdclass == dns_rdataclass_in);
268	REQUIRE(rdata->type == dns_rdatatype_srv);
269	REQUIRE(srv != NULL);
270	REQUIRE(rdata->length != 0);
271
272	srv->common.rdclass = rdata->rdclass;
273	srv->common.rdtype = rdata->type;
274	ISC_LINK_INIT(&srv->common, link);
275
276	dns_name_init(&name, NULL);
277	dns_rdata_toregion(rdata, &region);
278	srv->priority = uint16_fromregion(&region);
279	isc_region_consume(&region, 2);
280	srv->weight = uint16_fromregion(&region);
281	isc_region_consume(&region, 2);
282	srv->port = uint16_fromregion(&region);
283	isc_region_consume(&region, 2);
284	dns_name_fromregion(&name, &region);
285	dns_name_init(&srv->target, NULL);
286	RETERR(name_duporclone(&name, mctx, &srv->target));
287	srv->mctx = mctx;
288	return (ISC_R_SUCCESS);
289}
290
291static void
292freestruct_in_srv(ARGS_FREESTRUCT) {
293	dns_rdata_in_srv_t *srv = source;
294
295	REQUIRE(srv != NULL);
296	REQUIRE(srv->common.rdclass == dns_rdataclass_in);
297	REQUIRE(srv->common.rdtype == dns_rdatatype_srv);
298
299	if (srv->mctx == NULL) {
300		return;
301	}
302
303	dns_name_free(&srv->target, srv->mctx);
304	srv->mctx = NULL;
305}
306
307static isc_result_t
308additionaldata_in_srv(ARGS_ADDLDATA) {
309	char buf[sizeof("_65000._tcp")];
310	dns_fixedname_t fixed;
311	dns_name_t name;
312	dns_offsets_t offsets;
313	isc_region_t region;
314	uint16_t port;
315	isc_result_t result;
316
317	REQUIRE(rdata->type == dns_rdatatype_srv);
318	REQUIRE(rdata->rdclass == dns_rdataclass_in);
319
320	dns_name_init(&name, offsets);
321	dns_rdata_toregion(rdata, &region);
322	isc_region_consume(&region, 4);
323	port = uint16_fromregion(&region);
324	isc_region_consume(&region, 2);
325	dns_name_fromregion(&name, &region);
326
327	if (dns_name_equal(&name, dns_rootname)) {
328		return (ISC_R_SUCCESS);
329	}
330
331	result = (add)(arg, &name, dns_rdatatype_a);
332	if (result != ISC_R_SUCCESS) {
333		return (result);
334	}
335
336	dns_fixedname_init(&fixed);
337	snprintf(buf, sizeof(buf), "_%u._tcp", port);
338	result = dns_name_fromstring2(dns_fixedname_name(&fixed), buf, NULL, 0,
339				      NULL);
340	if (result != ISC_R_SUCCESS) {
341		return (ISC_R_SUCCESS);
342	}
343
344	result = dns_name_concatenate(dns_fixedname_name(&fixed), &name,
345				      dns_fixedname_name(&fixed), NULL);
346	if (result != ISC_R_SUCCESS) {
347		return (ISC_R_SUCCESS);
348	}
349
350	return ((add)(arg, dns_fixedname_name(&fixed), dns_rdatatype_tlsa));
351}
352
353static isc_result_t
354digest_in_srv(ARGS_DIGEST) {
355	isc_region_t r1, r2;
356	dns_name_t name;
357
358	REQUIRE(rdata->type == dns_rdatatype_srv);
359	REQUIRE(rdata->rdclass == dns_rdataclass_in);
360
361	dns_rdata_toregion(rdata, &r1);
362	r2 = r1;
363	isc_region_consume(&r2, 6);
364	r1.length = 6;
365	RETERR((digest)(arg, &r1));
366	dns_name_init(&name, NULL);
367	dns_name_fromregion(&name, &r2);
368	return (dns_name_digest(&name, digest, arg));
369}
370
371static bool
372checkowner_in_srv(ARGS_CHECKOWNER) {
373	REQUIRE(type == dns_rdatatype_srv);
374	REQUIRE(rdclass == dns_rdataclass_in);
375
376	UNUSED(name);
377	UNUSED(type);
378	UNUSED(rdclass);
379	UNUSED(wildcard);
380
381	return (true);
382}
383
384static bool
385checknames_in_srv(ARGS_CHECKNAMES) {
386	isc_region_t region;
387	dns_name_t name;
388
389	REQUIRE(rdata->type == dns_rdatatype_srv);
390	REQUIRE(rdata->rdclass == dns_rdataclass_in);
391
392	UNUSED(owner);
393
394	dns_rdata_toregion(rdata, &region);
395	isc_region_consume(&region, 6);
396	dns_name_init(&name, NULL);
397	dns_name_fromregion(&name, &region);
398	if (!dns_name_ishostname(&name, false)) {
399		if (bad != NULL) {
400			dns_name_clone(&name, bad);
401		}
402		return (false);
403	}
404	return (true);
405}
406
407static int
408casecompare_in_srv(ARGS_COMPARE) {
409	return (compare_in_srv(rdata1, rdata2));
410}
411
412#endif /* RDATA_IN_1_SRV_33_C */
413