1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 /* $Id: naptr_35.c,v 1.14 2022/12/26 19:24:11 jmc Exp $ */
18
19 /* Reviewed: Thu Mar 16 16:52:50 PST 2000 by bwelling */
20
21 /* RFC2915 */
22
23 #ifndef RDATA_GENERIC_NAPTR_35_C
24 #define RDATA_GENERIC_NAPTR_35_C
25
26 #include <isc/regex.h>
27
28 /*
29 * Check the wire format of the Regexp field.
30 * Don't allow embedded NUL's.
31 */
32 static inline isc_result_t
txt_valid_regex(const unsigned char * txt)33 txt_valid_regex(const unsigned char *txt) {
34 unsigned int nsub = 0;
35 char regex[256];
36 char *cp;
37 int flags = 0;
38 int replace = 0;
39 unsigned char c;
40 unsigned char delim;
41 unsigned int len;
42 int n;
43
44 len = *txt++;
45 if (len == 0U)
46 return (ISC_R_SUCCESS);
47
48 delim = *txt++;
49 len--;
50
51 /*
52 * Digits, backslash and flags can't be delimiters.
53 */
54 switch (delim) {
55 case '0': case '1': case '2': case '3': case '4':
56 case '5': case '6': case '7': case '8': case '9':
57 case '\\': case 'i': case 0:
58 return (DNS_R_SYNTAX);
59 }
60
61 cp = regex;
62 while (len-- > 0) {
63 c = *txt++;
64 if (c == 0)
65 return (DNS_R_SYNTAX);
66 if (c == delim && !replace) {
67 replace = 1;
68 continue;
69 } else if (c == delim && !flags) {
70 flags = 1;
71 continue;
72 } else if (c == delim)
73 return (DNS_R_SYNTAX);
74 /*
75 * Flags are not escaped.
76 */
77 if (flags) {
78 switch (c) {
79 case 'i':
80 continue;
81 default:
82 return (DNS_R_SYNTAX);
83 }
84 }
85 if (!replace)
86 *cp++ = c;
87 if (c == '\\') {
88 if (len == 0)
89 return (DNS_R_SYNTAX);
90 c = *txt++;
91 if (c == 0)
92 return (DNS_R_SYNTAX);
93 len--;
94 if (replace)
95 switch (c) {
96 case '0': return (DNS_R_SYNTAX);
97 case '1': if (nsub < 1) nsub = 1; break;
98 case '2': if (nsub < 2) nsub = 2; break;
99 case '3': if (nsub < 3) nsub = 3; break;
100 case '4': if (nsub < 4) nsub = 4; break;
101 case '5': if (nsub < 5) nsub = 5; break;
102 case '6': if (nsub < 6) nsub = 6; break;
103 case '7': if (nsub < 7) nsub = 7; break;
104 case '8': if (nsub < 8) nsub = 8; break;
105 case '9': if (nsub < 9) nsub = 9; break;
106 }
107 if (!replace)
108 *cp++ = c;
109 }
110 }
111 if (!flags)
112 return (DNS_R_SYNTAX);
113 *cp = '\0';
114 n = isc_regex_validate(regex);
115 if (n < 0 || nsub > (unsigned int)n)
116 return (DNS_R_SYNTAX);
117 return (ISC_R_SUCCESS);
118 }
119
120 static inline isc_result_t
totext_naptr(ARGS_TOTEXT)121 totext_naptr(ARGS_TOTEXT) {
122 isc_region_t region;
123 dns_name_t name;
124 dns_name_t prefix;
125 int sub;
126 char buf[sizeof("64000")];
127 unsigned short num;
128
129 REQUIRE(rdata->type == dns_rdatatype_naptr);
130 REQUIRE(rdata->length != 0);
131
132 dns_name_init(&name, NULL);
133 dns_name_init(&prefix, NULL);
134
135 dns_rdata_toregion(rdata, ®ion);
136
137 /*
138 * Order.
139 */
140 num = uint16_fromregion(®ion);
141 isc_region_consume(®ion, 2);
142 snprintf(buf, sizeof(buf), "%u", num);
143 RETERR(isc_str_tobuffer(buf, target));
144 RETERR(isc_str_tobuffer(" ", target));
145
146 /*
147 * Preference.
148 */
149 num = uint16_fromregion(®ion);
150 isc_region_consume(®ion, 2);
151 snprintf(buf, sizeof(buf), "%u", num);
152 RETERR(isc_str_tobuffer(buf, target));
153 RETERR(isc_str_tobuffer(" ", target));
154
155 /*
156 * Flags.
157 */
158 RETERR(txt_totext(®ion, 1, target));
159 RETERR(isc_str_tobuffer(" ", target));
160
161 /*
162 * Service.
163 */
164 RETERR(txt_totext(®ion, 1, target));
165 RETERR(isc_str_tobuffer(" ", target));
166
167 /*
168 * Regexp.
169 */
170 RETERR(txt_totext(®ion, 1, target));
171 RETERR(isc_str_tobuffer(" ", target));
172
173 /*
174 * Replacement.
175 */
176 dns_name_fromregion(&name, ®ion);
177 sub = name_prefix(&name, tctx->origin, &prefix);
178 return (dns_name_totext(&prefix, sub, target));
179 }
180
181 static inline isc_result_t
fromwire_naptr(ARGS_FROMWIRE)182 fromwire_naptr(ARGS_FROMWIRE) {
183 dns_name_t name;
184 isc_region_t sr;
185 unsigned char *regex;
186
187 REQUIRE(type == dns_rdatatype_naptr);
188
189 UNUSED(type);
190 UNUSED(rdclass);
191
192 dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
193
194 dns_name_init(&name, NULL);
195
196 /*
197 * Order, preference.
198 */
199 isc_buffer_activeregion(source, &sr);
200 if (sr.length < 4)
201 return (ISC_R_UNEXPECTEDEND);
202 RETERR(isc_mem_tobuffer(target, sr.base, 4));
203 isc_buffer_forward(source, 4);
204
205 /*
206 * Flags.
207 */
208 RETERR(txt_fromwire(source, target));
209
210 /*
211 * Service.
212 */
213 RETERR(txt_fromwire(source, target));
214
215 /*
216 * Regexp.
217 */
218 regex = isc_buffer_used(target);
219 RETERR(txt_fromwire(source, target));
220 RETERR(txt_valid_regex(regex));
221
222 /*
223 * Replacement.
224 */
225 return (dns_name_fromwire(&name, source, dctx, options, target));
226 }
227
228 static inline isc_result_t
towire_naptr(ARGS_TOWIRE)229 towire_naptr(ARGS_TOWIRE) {
230 dns_name_t name;
231 dns_offsets_t offsets;
232 isc_region_t sr;
233
234 REQUIRE(rdata->type == dns_rdatatype_naptr);
235 REQUIRE(rdata->length != 0);
236
237 dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
238 /*
239 * Order, preference.
240 */
241 dns_rdata_toregion(rdata, &sr);
242 RETERR(isc_mem_tobuffer(target, sr.base, 4));
243 isc_region_consume(&sr, 4);
244
245 /*
246 * Flags.
247 */
248 RETERR(isc_mem_tobuffer(target, sr.base, sr.base[0] + 1));
249 isc_region_consume(&sr, sr.base[0] + 1);
250
251 /*
252 * Service.
253 */
254 RETERR(isc_mem_tobuffer(target, sr.base, sr.base[0] + 1));
255 isc_region_consume(&sr, sr.base[0] + 1);
256
257 /*
258 * Regexp.
259 */
260 RETERR(isc_mem_tobuffer(target, sr.base, sr.base[0] + 1));
261 isc_region_consume(&sr, sr.base[0] + 1);
262
263 /*
264 * Replacement.
265 */
266 dns_name_init(&name, offsets);
267 dns_name_fromregion(&name, &sr);
268 return (dns_name_towire(&name, cctx, target));
269 }
270
271 #endif /* RDATA_GENERIC_NAPTR_35_C */
272