1135446Strhodes/*
2262706Serwin * Copyright (C) 2004, 2007, 2009, 2011-2014  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 1999-2002  Internet Software Consortium.
4135446Strhodes *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18234010Sdougb/* $Id$ */
19135446Strhodes
20135446Strhodes/* Reviewed: Fri Mar 17 15:01:49 PST 2000 by explorer */
21135446Strhodes
22135446Strhodes#ifndef RDATA_IN_1_WKS_11_C
23135446Strhodes#define RDATA_IN_1_WKS_11_C
24135446Strhodes
25135446Strhodes#include <limits.h>
26135446Strhodes#include <stdlib.h>
27135446Strhodes
28135446Strhodes#include <isc/net.h>
29135446Strhodes#include <isc/netdb.h>
30234010Sdougb#include <isc/once.h>
31135446Strhodes
32135446Strhodes#define RRTYPE_WKS_ATTRIBUTES (0)
33135446Strhodes
34234010Sdougbstatic isc_mutex_t wks_lock;
35234010Sdougb
36234010Sdougbstatic void init_lock(void) {
37234010Sdougb	RUNTIME_CHECK(isc_mutex_init(&wks_lock) == ISC_R_SUCCESS);
38234010Sdougb}
39234010Sdougb
40234010Sdougbstatic isc_boolean_t
41234010Sdougbmygetprotobyname(const char *name, long *proto) {
42234010Sdougb	struct protoent *pe;
43234010Sdougb
44234010Sdougb	LOCK(&wks_lock);
45234010Sdougb	pe = getprotobyname(name);
46234010Sdougb	if (pe != NULL)
47234010Sdougb		*proto = pe->p_proto;
48234010Sdougb	UNLOCK(&wks_lock);
49234010Sdougb	return (ISC_TF(pe != NULL));
50234010Sdougb}
51234010Sdougb
52234010Sdougbstatic isc_boolean_t
53234010Sdougbmygetservbyname(const char *name, const char *proto, long *port) {
54234010Sdougb	struct servent *se;
55234010Sdougb
56234010Sdougb	LOCK(&wks_lock);
57234010Sdougb	se = getservbyname(name, proto);
58234010Sdougb	if (se != NULL)
59234010Sdougb		*port = ntohs(se->s_port);
60234010Sdougb	UNLOCK(&wks_lock);
61234010Sdougb	return (ISC_TF(se != NULL));
62234010Sdougb}
63234010Sdougb
64135446Strhodesstatic inline isc_result_t
65135446Strhodesfromtext_in_wks(ARGS_FROMTEXT) {
66234010Sdougb	static isc_once_t once = ISC_ONCE_INIT;
67135446Strhodes	isc_token_t token;
68135446Strhodes	isc_region_t region;
69135446Strhodes	struct in_addr addr;
70135446Strhodes	char *e;
71135446Strhodes	long proto;
72135446Strhodes	unsigned char bm[8*1024]; /* 64k bits */
73135446Strhodes	long port;
74135446Strhodes	long maxport = -1;
75135446Strhodes	const char *ps = NULL;
76135446Strhodes	unsigned int n;
77135446Strhodes	char service[32];
78135446Strhodes	int i;
79135446Strhodes
80135446Strhodes	REQUIRE(type == 11);
81135446Strhodes	REQUIRE(rdclass == 1);
82135446Strhodes
83135446Strhodes	UNUSED(type);
84135446Strhodes	UNUSED(origin);
85135446Strhodes	UNUSED(options);
86135446Strhodes	UNUSED(rdclass);
87135446Strhodes
88234010Sdougb	RUNTIME_CHECK(isc_once_do(&once, init_lock) == ISC_R_SUCCESS);
89234010Sdougb
90135446Strhodes	/*
91135446Strhodes	 * IPv4 dotted quad.
92135446Strhodes	 */
93135446Strhodes	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
94135446Strhodes				      ISC_FALSE));
95135446Strhodes
96135446Strhodes	isc_buffer_availableregion(target, &region);
97135446Strhodes	if (getquad(DNS_AS_STR(token), &addr, lexer, callbacks) != 1)
98135446Strhodes		RETTOK(DNS_R_BADDOTTEDQUAD);
99135446Strhodes	if (region.length < 4)
100135446Strhodes		return (ISC_R_NOSPACE);
101262706Serwin	memmove(region.base, &addr, 4);
102135446Strhodes	isc_buffer_add(target, 4);
103135446Strhodes
104135446Strhodes	/*
105135446Strhodes	 * Protocol.
106135446Strhodes	 */
107135446Strhodes	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
108135446Strhodes				      ISC_FALSE));
109135446Strhodes
110135446Strhodes	proto = strtol(DNS_AS_STR(token), &e, 10);
111135446Strhodes	if (*e == 0)
112135446Strhodes		;
113234010Sdougb	else if (!mygetprotobyname(DNS_AS_STR(token), &proto))
114135446Strhodes		RETTOK(DNS_R_UNKNOWNPROTO);
115234010Sdougb
116135446Strhodes	if (proto < 0 || proto > 0xff)
117135446Strhodes		RETTOK(ISC_R_RANGE);
118135446Strhodes
119135446Strhodes	if (proto == IPPROTO_TCP)
120135446Strhodes		ps = "tcp";
121135446Strhodes	else if (proto == IPPROTO_UDP)
122135446Strhodes		ps = "udp";
123135446Strhodes
124135446Strhodes	RETERR(uint8_tobuffer(proto, target));
125135446Strhodes
126135446Strhodes	memset(bm, 0, sizeof(bm));
127135446Strhodes	do {
128135446Strhodes		RETERR(isc_lex_getmastertoken(lexer, &token,
129135446Strhodes					      isc_tokentype_string, ISC_TRUE));
130135446Strhodes		if (token.type != isc_tokentype_string)
131135446Strhodes			break;
132135446Strhodes
133135446Strhodes		/*
134135446Strhodes		 * Lowercase the service string as some getservbyname() are
135135446Strhodes		 * case sensitive and the database is usually in lowercase.
136135446Strhodes		 */
137135446Strhodes		strncpy(service, DNS_AS_STR(token), sizeof(service));
138135446Strhodes		service[sizeof(service)-1] = '\0';
139135446Strhodes		for (i = strlen(service) - 1; i >= 0; i--)
140135446Strhodes			if (isupper(service[i]&0xff))
141143731Sdougb				service[i] = tolower(service[i]&0xff);
142135446Strhodes
143135446Strhodes		port = strtol(DNS_AS_STR(token), &e, 10);
144135446Strhodes		if (*e == 0)
145135446Strhodes			;
146234010Sdougb		else if (!mygetservbyname(service, ps, &port) &&
147234010Sdougb			 !mygetservbyname(DNS_AS_STR(token), ps, &port))
148135446Strhodes			RETTOK(DNS_R_UNKNOWNSERVICE);
149135446Strhodes		if (port < 0 || port > 0xffff)
150135446Strhodes			RETTOK(ISC_R_RANGE);
151135446Strhodes		if (port > maxport)
152135446Strhodes			maxport = port;
153135446Strhodes		bm[port / 8] |= (0x80 >> (port % 8));
154135446Strhodes	} while (1);
155135446Strhodes
156135446Strhodes	/*
157135446Strhodes	 * Let upper layer handle eol/eof.
158135446Strhodes	 */
159135446Strhodes	isc_lex_ungettoken(lexer, &token);
160135446Strhodes
161135446Strhodes	n = (maxport + 8) / 8;
162135446Strhodes	return (mem_tobuffer(target, bm, n));
163135446Strhodes}
164135446Strhodes
165135446Strhodesstatic inline isc_result_t
166135446Strhodestotext_in_wks(ARGS_TOTEXT) {
167135446Strhodes	isc_region_t sr;
168135446Strhodes	unsigned short proto;
169135446Strhodes	char buf[sizeof("65535")];
170135446Strhodes	unsigned int i, j;
171135446Strhodes
172135446Strhodes	UNUSED(tctx);
173135446Strhodes
174135446Strhodes	REQUIRE(rdata->type == 11);
175135446Strhodes	REQUIRE(rdata->rdclass == 1);
176135446Strhodes	REQUIRE(rdata->length >= 5);
177135446Strhodes
178135446Strhodes	dns_rdata_toregion(rdata, &sr);
179135446Strhodes	RETERR(inet_totext(AF_INET, &sr, target));
180135446Strhodes	isc_region_consume(&sr, 4);
181135446Strhodes
182135446Strhodes	proto = uint8_fromregion(&sr);
183135446Strhodes	sprintf(buf, "%u", proto);
184135446Strhodes	RETERR(str_totext(" ", target));
185135446Strhodes	RETERR(str_totext(buf, target));
186135446Strhodes	isc_region_consume(&sr, 1);
187135446Strhodes
188193149Sdougb	INSIST(sr.length <= 8*1024);
189135446Strhodes	for (i = 0; i < sr.length; i++) {
190135446Strhodes		if (sr.base[i] != 0)
191135446Strhodes			for (j = 0; j < 8; j++)
192135446Strhodes				if ((sr.base[i] & (0x80 >> j)) != 0) {
193135446Strhodes					sprintf(buf, "%u", i * 8 + j);
194135446Strhodes					RETERR(str_totext(" ", target));
195135446Strhodes					RETERR(str_totext(buf, target));
196135446Strhodes				}
197135446Strhodes	}
198135446Strhodes
199135446Strhodes	return (ISC_R_SUCCESS);
200135446Strhodes}
201135446Strhodes
202135446Strhodesstatic inline isc_result_t
203135446Strhodesfromwire_in_wks(ARGS_FROMWIRE) {
204135446Strhodes	isc_region_t sr;
205135446Strhodes	isc_region_t tr;
206135446Strhodes
207135446Strhodes	REQUIRE(type == 11);
208135446Strhodes	REQUIRE(rdclass == 1);
209135446Strhodes
210135446Strhodes	UNUSED(type);
211135446Strhodes	UNUSED(dctx);
212135446Strhodes	UNUSED(options);
213135446Strhodes	UNUSED(rdclass);
214135446Strhodes
215135446Strhodes	isc_buffer_activeregion(source, &sr);
216135446Strhodes	isc_buffer_availableregion(target, &tr);
217135446Strhodes
218135446Strhodes	if (sr.length < 5)
219135446Strhodes		return (ISC_R_UNEXPECTEDEND);
220135446Strhodes	if (sr.length > 8 * 1024 + 5)
221135446Strhodes		return (DNS_R_EXTRADATA);
222135446Strhodes	if (tr.length < sr.length)
223135446Strhodes		return (ISC_R_NOSPACE);
224135446Strhodes
225262706Serwin	memmove(tr.base, sr.base, sr.length);
226135446Strhodes	isc_buffer_add(target, sr.length);
227135446Strhodes	isc_buffer_forward(source, sr.length);
228135446Strhodes
229135446Strhodes	return (ISC_R_SUCCESS);
230135446Strhodes}
231135446Strhodes
232135446Strhodesstatic inline isc_result_t
233135446Strhodestowire_in_wks(ARGS_TOWIRE) {
234135446Strhodes	isc_region_t sr;
235135446Strhodes
236135446Strhodes	UNUSED(cctx);
237135446Strhodes
238135446Strhodes	REQUIRE(rdata->type == 11);
239135446Strhodes	REQUIRE(rdata->rdclass == 1);
240135446Strhodes	REQUIRE(rdata->length != 0);
241135446Strhodes
242135446Strhodes	dns_rdata_toregion(rdata, &sr);
243135446Strhodes	return (mem_tobuffer(target, sr.base, sr.length));
244135446Strhodes}
245135446Strhodes
246135446Strhodesstatic inline int
247135446Strhodescompare_in_wks(ARGS_COMPARE) {
248135446Strhodes	isc_region_t r1;
249135446Strhodes	isc_region_t r2;
250135446Strhodes
251135446Strhodes	REQUIRE(rdata1->type == rdata2->type);
252135446Strhodes	REQUIRE(rdata1->rdclass == rdata2->rdclass);
253135446Strhodes	REQUIRE(rdata1->type == 11);
254135446Strhodes	REQUIRE(rdata1->rdclass == 1);
255135446Strhodes	REQUIRE(rdata1->length != 0);
256135446Strhodes	REQUIRE(rdata2->length != 0);
257135446Strhodes
258135446Strhodes	dns_rdata_toregion(rdata1, &r1);
259135446Strhodes	dns_rdata_toregion(rdata2, &r2);
260135446Strhodes	return (isc_region_compare(&r1, &r2));
261135446Strhodes}
262135446Strhodes
263135446Strhodesstatic inline isc_result_t
264135446Strhodesfromstruct_in_wks(ARGS_FROMSTRUCT) {
265135446Strhodes	dns_rdata_in_wks_t *wks = source;
266135446Strhodes	isc_uint32_t a;
267135446Strhodes
268135446Strhodes	REQUIRE(type == 11);
269135446Strhodes	REQUIRE(rdclass == 1);
270135446Strhodes	REQUIRE(source != NULL);
271135446Strhodes	REQUIRE(wks->common.rdtype == type);
272135446Strhodes	REQUIRE(wks->common.rdclass == rdclass);
273193149Sdougb	REQUIRE((wks->map != NULL && wks->map_len <= 8*1024) ||
274193149Sdougb		 wks->map_len == 0);
275135446Strhodes
276135446Strhodes	UNUSED(type);
277135446Strhodes	UNUSED(rdclass);
278135446Strhodes
279135446Strhodes	a = ntohl(wks->in_addr.s_addr);
280135446Strhodes	RETERR(uint32_tobuffer(a, target));
281262706Serwin	RETERR(uint8_tobuffer(wks->protocol, target));
282135446Strhodes	return (mem_tobuffer(target, wks->map, wks->map_len));
283135446Strhodes}
284135446Strhodes
285135446Strhodesstatic inline isc_result_t
286135446Strhodestostruct_in_wks(ARGS_TOSTRUCT) {
287135446Strhodes	dns_rdata_in_wks_t *wks = target;
288135446Strhodes	isc_uint32_t n;
289135446Strhodes	isc_region_t region;
290135446Strhodes
291135446Strhodes	REQUIRE(rdata->type == 11);
292135446Strhodes	REQUIRE(rdata->rdclass == 1);
293135446Strhodes	REQUIRE(rdata->length != 0);
294135446Strhodes
295135446Strhodes	wks->common.rdclass = rdata->rdclass;
296135446Strhodes	wks->common.rdtype = rdata->type;
297135446Strhodes	ISC_LINK_INIT(&wks->common, link);
298135446Strhodes
299135446Strhodes	dns_rdata_toregion(rdata, &region);
300135446Strhodes	n = uint32_fromregion(&region);
301135446Strhodes	wks->in_addr.s_addr = htonl(n);
302135446Strhodes	isc_region_consume(&region, 4);
303262706Serwin	wks->protocol = uint8_fromregion(&region);
304262706Serwin	isc_region_consume(&region, 1);
305135446Strhodes	wks->map_len = region.length;
306135446Strhodes	wks->map = mem_maybedup(mctx, region.base, region.length);
307135446Strhodes	if (wks->map == NULL)
308135446Strhodes		return (ISC_R_NOMEMORY);
309135446Strhodes	wks->mctx = mctx;
310135446Strhodes	return (ISC_R_SUCCESS);
311135446Strhodes}
312135446Strhodes
313135446Strhodesstatic inline void
314135446Strhodesfreestruct_in_wks(ARGS_FREESTRUCT) {
315135446Strhodes	dns_rdata_in_wks_t *wks = source;
316135446Strhodes
317135446Strhodes	REQUIRE(source != NULL);
318135446Strhodes	REQUIRE(wks->common.rdtype == 11);
319135446Strhodes	REQUIRE(wks->common.rdclass == 1);
320135446Strhodes
321135446Strhodes	if (wks->mctx == NULL)
322135446Strhodes		return;
323135446Strhodes
324135446Strhodes	if (wks->map != NULL)
325135446Strhodes		isc_mem_free(wks->mctx, wks->map);
326135446Strhodes	wks->mctx = NULL;
327135446Strhodes}
328135446Strhodes
329135446Strhodesstatic inline isc_result_t
330135446Strhodesadditionaldata_in_wks(ARGS_ADDLDATA) {
331135446Strhodes	UNUSED(rdata);
332135446Strhodes	UNUSED(add);
333135446Strhodes	UNUSED(arg);
334135446Strhodes
335135446Strhodes	REQUIRE(rdata->type == 11);
336135446Strhodes	REQUIRE(rdata->rdclass == 1);
337135446Strhodes
338135446Strhodes	return (ISC_R_SUCCESS);
339135446Strhodes}
340135446Strhodes
341135446Strhodesstatic inline isc_result_t
342135446Strhodesdigest_in_wks(ARGS_DIGEST) {
343135446Strhodes	isc_region_t r;
344135446Strhodes
345135446Strhodes	REQUIRE(rdata->type == 11);
346135446Strhodes	REQUIRE(rdata->rdclass == 1);
347135446Strhodes
348135446Strhodes	dns_rdata_toregion(rdata, &r);
349135446Strhodes
350135446Strhodes	return ((digest)(arg, &r));
351135446Strhodes}
352135446Strhodes
353135446Strhodesstatic inline isc_boolean_t
354135446Strhodescheckowner_in_wks(ARGS_CHECKOWNER) {
355135446Strhodes
356135446Strhodes	REQUIRE(type == 11);
357135446Strhodes	REQUIRE(rdclass == 1);
358135446Strhodes
359135446Strhodes	UNUSED(type);
360135446Strhodes	UNUSED(rdclass);
361135446Strhodes
362135446Strhodes	return (dns_name_ishostname(name, wildcard));
363135446Strhodes}
364135446Strhodes
365135446Strhodesstatic inline isc_boolean_t
366135446Strhodeschecknames_in_wks(ARGS_CHECKNAMES) {
367135446Strhodes
368135446Strhodes	REQUIRE(rdata->type == 11);
369135446Strhodes	REQUIRE(rdata->rdclass == 1);
370135446Strhodes
371135446Strhodes	UNUSED(rdata);
372135446Strhodes	UNUSED(owner);
373135446Strhodes	UNUSED(bad);
374135446Strhodes
375135446Strhodes	return (ISC_TRUE);
376135446Strhodes}
377135446Strhodes
378224092Sdougbstatic inline int
379224092Sdougbcasecompare_in_wks(ARGS_COMPARE) {
380224092Sdougb	return (compare_in_wks(rdata1, rdata2));
381224092Sdougb}
382224092Sdougb
383135446Strhodes#endif	/* RDATA_IN_1_WKS_11_C */
384