xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rdata/in_1/wks_11.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: wks_11.c,v 1.11 2025/01/26 16:25:35 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_IN_1_WKS_11_C
17 #define RDATA_IN_1_WKS_11_C
18 
19 #include <limits.h>
20 #include <netdb.h>
21 
22 #include <isc/ascii.h>
23 #include <isc/net.h>
24 #include <isc/once.h>
25 
26 #define RRTYPE_WKS_ATTRIBUTES (0)
27 
28 static isc_mutex_t wks_lock;
29 
30 static void
31 init_lock(void) {
32 	isc_mutex_init(&wks_lock);
33 }
34 
35 static bool
36 mygetprotobyname(const char *name, long *proto) {
37 	struct protoent *pe;
38 
39 	LOCK(&wks_lock);
40 	pe = getprotobyname(name);
41 	if (pe != NULL) {
42 		*proto = pe->p_proto;
43 	}
44 	UNLOCK(&wks_lock);
45 	return pe != NULL;
46 }
47 
48 static bool
49 mygetservbyname(const char *name, const char *proto, long *port) {
50 	struct servent *se;
51 
52 	LOCK(&wks_lock);
53 	se = getservbyname(name, proto);
54 	if (se != NULL) {
55 		*port = ntohs(se->s_port);
56 	}
57 	UNLOCK(&wks_lock);
58 	return se != NULL;
59 }
60 
61 static isc_result_t
62 fromtext_in_wks(ARGS_FROMTEXT) {
63 	static isc_once_t once = ISC_ONCE_INIT;
64 	isc_token_t token;
65 	isc_region_t region;
66 	struct in_addr addr;
67 	char *e = NULL;
68 	long proto;
69 	unsigned char bm[8 * 1024]; /* 64k bits */
70 	long port;
71 	long maxport = -1;
72 	const char *ps = NULL;
73 	unsigned int n;
74 	char service[32];
75 	isc_result_t result;
76 
77 	REQUIRE(type == dns_rdatatype_wks);
78 	REQUIRE(rdclass == dns_rdataclass_in);
79 
80 	UNUSED(type);
81 	UNUSED(origin);
82 	UNUSED(options);
83 	UNUSED(rdclass);
84 	UNUSED(callbacks);
85 
86 	isc_once_do(&once, init_lock);
87 
88 	/*
89 	 * IPv4 dotted quad.
90 	 */
91 	CHECK(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
92 				     false));
93 
94 	isc_buffer_availableregion(target, &region);
95 	if (inet_pton(AF_INET, DNS_AS_STR(token), &addr) != 1) {
96 		CHECKTOK(DNS_R_BADDOTTEDQUAD);
97 	}
98 	if (region.length < 4) {
99 		return ISC_R_NOSPACE;
100 	}
101 	memmove(region.base, &addr, 4);
102 	isc_buffer_add(target, 4);
103 
104 	/*
105 	 * Protocol.
106 	 */
107 	CHECK(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
108 				     false));
109 
110 	proto = strtol(DNS_AS_STR(token), &e, 10);
111 	if (*e != '\0' && !mygetprotobyname(DNS_AS_STR(token), &proto)) {
112 		CHECKTOK(DNS_R_UNKNOWNPROTO);
113 	}
114 
115 	if (proto < 0 || proto > 0xff) {
116 		CHECKTOK(ISC_R_RANGE);
117 	}
118 
119 	if (proto == IPPROTO_TCP) {
120 		ps = "tcp";
121 	} else if (proto == IPPROTO_UDP) {
122 		ps = "udp";
123 	}
124 
125 	CHECK(uint8_tobuffer(proto, target));
126 
127 	memset(bm, 0, sizeof(bm));
128 	do {
129 		CHECK(isc_lex_getmastertoken(lexer, &token,
130 					     isc_tokentype_string, true));
131 		if (token.type != isc_tokentype_string) {
132 			break;
133 		}
134 
135 		/*
136 		 * Lowercase the service string as some getservbyname() are
137 		 * case sensitive and the database is usually in lowercase.
138 		 */
139 		strlcpy(service, DNS_AS_STR(token), sizeof(service));
140 		isc_ascii_strtolower(service);
141 
142 		port = strtol(DNS_AS_STR(token), &e, 10);
143 		if (*e != 0 && !mygetservbyname(service, ps, &port) &&
144 		    !mygetservbyname(DNS_AS_STR(token), ps, &port))
145 		{
146 			CHECKTOK(DNS_R_UNKNOWNSERVICE);
147 		}
148 		if (port < 0 || port > 0xffff) {
149 			CHECKTOK(ISC_R_RANGE);
150 		}
151 		if (port > maxport) {
152 			maxport = port;
153 		}
154 		bm[port / 8] |= (0x80 >> (port % 8));
155 	} while (1);
156 
157 	/*
158 	 * Let upper layer handle eol/eof.
159 	 */
160 	isc_lex_ungettoken(lexer, &token);
161 
162 	n = (maxport + 8) / 8;
163 	result = mem_tobuffer(target, bm, n);
164 
165 cleanup:
166 	return result;
167 }
168 
169 static isc_result_t
170 totext_in_wks(ARGS_TOTEXT) {
171 	isc_region_t sr;
172 	unsigned short proto;
173 	char buf[sizeof("65535")];
174 	unsigned int i, j;
175 
176 	UNUSED(tctx);
177 
178 	REQUIRE(rdata->type == dns_rdatatype_wks);
179 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
180 	REQUIRE(rdata->length >= 5);
181 
182 	dns_rdata_toregion(rdata, &sr);
183 	RETERR(inet_totext(AF_INET, tctx->flags, &sr, target));
184 	isc_region_consume(&sr, 4);
185 
186 	proto = uint8_fromregion(&sr);
187 	snprintf(buf, sizeof(buf), "%u", proto);
188 	RETERR(str_totext(" ", target));
189 	RETERR(str_totext(buf, target));
190 	isc_region_consume(&sr, 1);
191 
192 	INSIST(sr.length <= 8 * 1024);
193 	for (i = 0; i < sr.length; i++) {
194 		if (sr.base[i] != 0) {
195 			for (j = 0; j < 8; j++) {
196 				if ((sr.base[i] & (0x80 >> j)) != 0) {
197 					{
198 						snprintf(buf, sizeof(buf), "%u",
199 							 i * 8 + j);
200 						RETERR(str_totext(" ", target));
201 						RETERR(str_totext(buf, target));
202 					}
203 				}
204 			}
205 		}
206 	}
207 
208 	return ISC_R_SUCCESS;
209 }
210 
211 static isc_result_t
212 fromwire_in_wks(ARGS_FROMWIRE) {
213 	isc_region_t sr;
214 	isc_region_t tr;
215 
216 	REQUIRE(type == dns_rdatatype_wks);
217 	REQUIRE(rdclass == dns_rdataclass_in);
218 
219 	UNUSED(type);
220 	UNUSED(dctx);
221 	UNUSED(rdclass);
222 
223 	isc_buffer_activeregion(source, &sr);
224 	isc_buffer_availableregion(target, &tr);
225 
226 	if (sr.length < 5) {
227 		return ISC_R_UNEXPECTEDEND;
228 	}
229 	if (sr.length > 8 * 1024 + 5) {
230 		return DNS_R_EXTRADATA;
231 	}
232 	if (sr.length > 5 && sr.base[sr.length - 1] == 0) {
233 		return DNS_R_FORMERR;
234 	}
235 	if (tr.length < sr.length) {
236 		return ISC_R_NOSPACE;
237 	}
238 
239 	memmove(tr.base, sr.base, sr.length);
240 	isc_buffer_add(target, sr.length);
241 	isc_buffer_forward(source, sr.length);
242 
243 	return ISC_R_SUCCESS;
244 }
245 
246 static isc_result_t
247 towire_in_wks(ARGS_TOWIRE) {
248 	isc_region_t sr;
249 
250 	UNUSED(cctx);
251 
252 	REQUIRE(rdata->type == dns_rdatatype_wks);
253 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
254 	REQUIRE(rdata->length != 0);
255 
256 	dns_rdata_toregion(rdata, &sr);
257 	return mem_tobuffer(target, sr.base, sr.length);
258 }
259 
260 static int
261 compare_in_wks(ARGS_COMPARE) {
262 	isc_region_t r1;
263 	isc_region_t r2;
264 
265 	REQUIRE(rdata1->type == rdata2->type);
266 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
267 	REQUIRE(rdata1->type == dns_rdatatype_wks);
268 	REQUIRE(rdata1->rdclass == dns_rdataclass_in);
269 	REQUIRE(rdata1->length != 0);
270 	REQUIRE(rdata2->length != 0);
271 
272 	dns_rdata_toregion(rdata1, &r1);
273 	dns_rdata_toregion(rdata2, &r2);
274 	return isc_region_compare(&r1, &r2);
275 }
276 
277 static isc_result_t
278 fromstruct_in_wks(ARGS_FROMSTRUCT) {
279 	dns_rdata_in_wks_t *wks = source;
280 	uint32_t a;
281 
282 	REQUIRE(type == dns_rdatatype_wks);
283 	REQUIRE(rdclass == dns_rdataclass_in);
284 	REQUIRE(wks != NULL);
285 	REQUIRE(wks->common.rdtype == type);
286 	REQUIRE(wks->common.rdclass == rdclass);
287 	REQUIRE((wks->map != NULL && wks->map_len <= 8 * 1024) ||
288 		wks->map_len == 0);
289 
290 	UNUSED(type);
291 	UNUSED(rdclass);
292 
293 	a = ntohl(wks->in_addr.s_addr);
294 	RETERR(uint32_tobuffer(a, target));
295 	RETERR(uint8_tobuffer(wks->protocol, target));
296 	return mem_tobuffer(target, wks->map, wks->map_len);
297 }
298 
299 static isc_result_t
300 tostruct_in_wks(ARGS_TOSTRUCT) {
301 	dns_rdata_in_wks_t *wks = target;
302 	uint32_t n;
303 	isc_region_t region;
304 
305 	REQUIRE(wks != NULL);
306 	REQUIRE(rdata->type == dns_rdatatype_wks);
307 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
308 	REQUIRE(rdata->length != 0);
309 
310 	wks->common.rdclass = rdata->rdclass;
311 	wks->common.rdtype = rdata->type;
312 	ISC_LINK_INIT(&wks->common, link);
313 
314 	dns_rdata_toregion(rdata, &region);
315 	n = uint32_fromregion(&region);
316 	wks->in_addr.s_addr = htonl(n);
317 	isc_region_consume(&region, 4);
318 	wks->protocol = uint8_fromregion(&region);
319 	isc_region_consume(&region, 1);
320 	wks->map_len = region.length;
321 	wks->map = mem_maybedup(mctx, region.base, region.length);
322 	wks->mctx = mctx;
323 	return ISC_R_SUCCESS;
324 }
325 
326 static void
327 freestruct_in_wks(ARGS_FREESTRUCT) {
328 	dns_rdata_in_wks_t *wks = source;
329 
330 	REQUIRE(wks != NULL);
331 	REQUIRE(wks->common.rdtype == dns_rdatatype_wks);
332 	REQUIRE(wks->common.rdclass == dns_rdataclass_in);
333 
334 	if (wks->mctx == NULL) {
335 		return;
336 	}
337 
338 	if (wks->map != NULL) {
339 		isc_mem_free(wks->mctx, wks->map);
340 	}
341 	wks->mctx = NULL;
342 }
343 
344 static isc_result_t
345 additionaldata_in_wks(ARGS_ADDLDATA) {
346 	REQUIRE(rdata->type == dns_rdatatype_wks);
347 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
348 
349 	UNUSED(rdata);
350 	UNUSED(owner);
351 	UNUSED(add);
352 	UNUSED(arg);
353 
354 	return ISC_R_SUCCESS;
355 }
356 
357 static isc_result_t
358 digest_in_wks(ARGS_DIGEST) {
359 	isc_region_t r;
360 
361 	REQUIRE(rdata->type == dns_rdatatype_wks);
362 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
363 
364 	dns_rdata_toregion(rdata, &r);
365 
366 	return (digest)(arg, &r);
367 }
368 
369 static bool
370 checkowner_in_wks(ARGS_CHECKOWNER) {
371 	REQUIRE(type == dns_rdatatype_wks);
372 	REQUIRE(rdclass == dns_rdataclass_in);
373 
374 	UNUSED(type);
375 	UNUSED(rdclass);
376 
377 	return dns_name_ishostname(name, wildcard);
378 }
379 
380 static bool
381 checknames_in_wks(ARGS_CHECKNAMES) {
382 	REQUIRE(rdata->type == dns_rdatatype_wks);
383 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
384 
385 	UNUSED(rdata);
386 	UNUSED(owner);
387 	UNUSED(bad);
388 
389 	return true;
390 }
391 
392 static int
393 casecompare_in_wks(ARGS_COMPARE) {
394 	return compare_in_wks(rdata1, rdata2);
395 }
396 
397 #endif /* RDATA_IN_1_WKS_11_C */
398