1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * SPDX-License-Identifier: MPL-2.0
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0.  If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 #include <stdbool.h>
15 #include <stdlib.h>
16 
17 #include <isc/commandline.h>
18 #include <isc/print.h>
19 #include <isc/string.h>
20 #include <isc/util.h>
21 
22 #include <dns/fixedname.h>
23 #include <dns/result.h>
24 
25 static void
print_wirename(isc_region_t * name)26 print_wirename(isc_region_t *name) {
27 	unsigned char *ccurr, *cend;
28 
29 	if (name->length == 0) {
30 		printf("<empty wire name>\n");
31 		return;
32 	}
33 	ccurr = name->base;
34 	cend = ccurr + name->length;
35 	while (ccurr != cend) {
36 		printf("%02x ", *ccurr++);
37 	}
38 	printf("\n");
39 }
40 
41 static void
print_name(dns_name_t * name)42 print_name(dns_name_t *name) {
43 	isc_result_t result;
44 	isc_buffer_t source;
45 	isc_region_t r;
46 	char s[1000];
47 
48 	isc_buffer_init(&source, s, sizeof(s));
49 	if (dns_name_countlabels(name) > 0) {
50 		result = dns_name_totext(name, false, &source);
51 	} else {
52 		result = ISC_R_SUCCESS;
53 	}
54 	if (result == ISC_R_SUCCESS) {
55 		isc_buffer_usedregion(&source, &r);
56 		if (r.length > 0) {
57 			printf("%.*s\n", (int)r.length, r.base);
58 		} else {
59 			printf("<empty text name>\n");
60 		}
61 	} else {
62 		printf("error: %s\n", dns_result_totext(result));
63 	}
64 }
65 
66 int
main(int argc,char * argv[])67 main(int argc, char *argv[]) {
68 	char s[1000];
69 	isc_result_t result;
70 	dns_fixedname_t wname, wname2, oname, compname, downname;
71 	isc_buffer_t source;
72 	isc_region_t r;
73 	dns_name_t *name, *comp, *down;
74 	const dns_name_t *origin;
75 	unsigned int downcase = 0;
76 	size_t len;
77 	bool quiet = false;
78 	bool concatenate = false;
79 	bool got_name = false;
80 	bool check_absolute = false;
81 	bool check_wildcard = false;
82 	bool test_downcase = false;
83 	bool inplace = false;
84 	bool want_split = false;
85 	unsigned int labels, split_label = 0;
86 	dns_fixedname_t fprefix, fsuffix;
87 	dns_name_t *prefix, *suffix;
88 	int ch;
89 
90 	while ((ch = isc_commandline_parse(argc, argv, "acdiqs:w")) != -1) {
91 		switch (ch) {
92 		case 'a':
93 			check_absolute = true;
94 			break;
95 		case 'c':
96 			concatenate = true;
97 			break;
98 		case 'd':
99 			test_downcase = true;
100 			break;
101 		case 'i':
102 			inplace = true;
103 			break;
104 		case 'q':
105 			quiet = true;
106 			break;
107 		case 's':
108 			want_split = true;
109 			split_label = atoi(isc_commandline_argument);
110 			break;
111 		case 'w':
112 			check_wildcard = true;
113 			break;
114 		}
115 	}
116 
117 	argc -= isc_commandline_index;
118 	argv += isc_commandline_index;
119 
120 	if (argc > 0) {
121 		if (strcasecmp("none", argv[0]) == 0) {
122 			origin = NULL;
123 		} else {
124 			len = strlen(argv[0]);
125 			isc_buffer_init(&source, argv[0], len);
126 			isc_buffer_add(&source, len);
127 			dns_fixedname_init(&oname);
128 			result = dns_name_fromtext(dns_fixedname_name(&oname),
129 						   &source, dns_rootname, 0,
130 						   NULL);
131 			if (result != 0) {
132 				fprintf(stderr,
133 					"dns_name_fromtext() failed: %s\n",
134 					dns_result_totext(result));
135 				exit(1);
136 			}
137 			origin = dns_fixedname_name(&oname);
138 		}
139 	} else if (concatenate) {
140 		origin = NULL;
141 	} else {
142 		origin = dns_rootname;
143 	}
144 
145 	if (argc >= 1) {
146 		if (strcasecmp("none", argv[1]) == 0) {
147 			comp = NULL;
148 		} else {
149 			len = strlen(argv[1]);
150 			isc_buffer_init(&source, argv[1], len);
151 			isc_buffer_add(&source, len);
152 			comp = dns_fixedname_initname(&compname);
153 			result = dns_name_fromtext(comp, &source, origin, 0,
154 						   NULL);
155 			if (result != 0) {
156 				fprintf(stderr,
157 					"dns_name_fromtext() failed: %s\n",
158 					dns_result_totext(result));
159 				exit(1);
160 			}
161 		}
162 	} else {
163 		comp = NULL;
164 	}
165 
166 	name = dns_fixedname_initname(&wname);
167 	dns_fixedname_init(&wname2);
168 	while (fgets(s, sizeof(s), stdin) != NULL) {
169 		len = strlen(s);
170 		if (len > 0U && s[len - 1] == '\n') {
171 			s[len - 1] = '\0';
172 			len--;
173 		}
174 		isc_buffer_init(&source, s, len);
175 		isc_buffer_add(&source, len);
176 
177 		if (len > 0U) {
178 			result = dns_name_fromtext(name, &source, origin,
179 						   downcase, NULL);
180 		} else {
181 			if (name == dns_fixedname_name(&wname)) {
182 				dns_fixedname_init(&wname);
183 			} else {
184 				dns_fixedname_init(&wname2);
185 			}
186 			result = ISC_R_SUCCESS;
187 		}
188 
189 		if (result != ISC_R_SUCCESS) {
190 			printf("%s\n", dns_result_totext(result));
191 			if (name == dns_fixedname_name(&wname)) {
192 				dns_fixedname_init(&wname);
193 			} else {
194 				dns_fixedname_init(&wname2);
195 			}
196 			continue;
197 		}
198 
199 		if (check_absolute && dns_name_countlabels(name) > 0) {
200 			if (dns_name_isabsolute(name)) {
201 				printf("absolute\n");
202 			} else {
203 				printf("relative\n");
204 			}
205 		}
206 		if (check_wildcard && dns_name_countlabels(name) > 0) {
207 			if (dns_name_iswildcard(name)) {
208 				printf("wildcard\n");
209 			} else {
210 				printf("not wildcard\n");
211 			}
212 		}
213 		dns_name_toregion(name, &r);
214 		if (!quiet) {
215 			print_wirename(&r);
216 			printf("%u labels, %u bytes.\n",
217 			       dns_name_countlabels(name), r.length);
218 		}
219 
220 		if (concatenate) {
221 			if (got_name) {
222 				printf("Concatenating.\n");
223 				result = dns_name_concatenate(
224 					dns_fixedname_name(&wname),
225 					dns_fixedname_name(&wname2),
226 					dns_fixedname_name(&wname2), NULL);
227 				name = dns_fixedname_name(&wname2);
228 				if (result == ISC_R_SUCCESS) {
229 					if (check_absolute &&
230 					    dns_name_countlabels(name) > 0) {
231 						if (dns_name_isabsolute(name)) {
232 							printf("absolute\n");
233 						} else {
234 							printf("relative\n");
235 						}
236 					}
237 					if (check_wildcard &&
238 					    dns_name_countlabels(name) > 0) {
239 						if (dns_name_iswildcard(name)) {
240 							printf("wildcard\n");
241 						} else {
242 							printf("not "
243 							       "wildcard\n");
244 						}
245 					}
246 					dns_name_toregion(name, &r);
247 					if (!quiet) {
248 						print_wirename(&r);
249 						printf("%u labels, "
250 						       "%u bytes.\n",
251 						       dns_name_countlabels(
252 							       name),
253 						       r.length);
254 					}
255 				} else {
256 					printf("%s\n",
257 					       dns_result_totext(result));
258 				}
259 				got_name = false;
260 			} else {
261 				got_name = true;
262 			}
263 		}
264 		isc_buffer_init(&source, s, sizeof(s));
265 		if (dns_name_countlabels(name) > 0) {
266 			result = dns_name_totext(name, false, &source);
267 		} else {
268 			result = ISC_R_SUCCESS;
269 		}
270 		if (result == ISC_R_SUCCESS) {
271 			isc_buffer_usedregion(&source, &r);
272 			if (r.length > 0) {
273 				printf("%.*s\n", (int)r.length, r.base);
274 			} else {
275 				printf("<empty text name>\n");
276 			}
277 			if (!quiet) {
278 				printf("%u bytes.\n", source.used);
279 			}
280 		} else {
281 			printf("%s\n", dns_result_totext(result));
282 		}
283 
284 		if (test_downcase) {
285 			if (inplace) {
286 				down = name;
287 			} else {
288 				down = dns_fixedname_initname(&downname);
289 			}
290 			result = dns_name_downcase(name, down, NULL);
291 			INSIST(result == ISC_R_SUCCESS);
292 			if (!quiet) {
293 				dns_name_toregion(down, &r);
294 				print_wirename(&r);
295 				printf("%u labels, %u bytes.\n",
296 				       dns_name_countlabels(down), r.length);
297 			}
298 			isc_buffer_init(&source, s, sizeof(s));
299 			print_name(down);
300 		}
301 
302 		if (comp != NULL && dns_name_countlabels(name) > 0) {
303 			int order;
304 			unsigned int nlabels;
305 			dns_namereln_t namereln;
306 
307 			namereln = dns_name_fullcompare(name, comp, &order,
308 							&nlabels);
309 			if (!quiet) {
310 				if (order < 0) {
311 					printf("<");
312 				} else if (order > 0) {
313 					printf(">");
314 				} else {
315 					printf("=");
316 				}
317 				switch (namereln) {
318 				case dns_namereln_contains:
319 					printf(", contains");
320 					break;
321 				case dns_namereln_subdomain:
322 					printf(", subdomain");
323 					break;
324 				case dns_namereln_commonancestor:
325 					printf(", common ancestor");
326 					break;
327 				default:
328 					break;
329 				}
330 				if (namereln != dns_namereln_none &&
331 				    namereln != dns_namereln_equal) {
332 					printf(", nlabels = %u", nlabels);
333 				}
334 				printf("\n");
335 			}
336 			printf("dns_name_equal() returns %s\n",
337 			       dns_name_equal(name, comp) ? "TRUE" : "FALSE");
338 		}
339 
340 		labels = dns_name_countlabels(name);
341 		if (want_split && split_label < labels) {
342 			prefix = dns_fixedname_initname(&fprefix);
343 			suffix = dns_fixedname_initname(&fsuffix);
344 			printf("splitting at label %u: ", split_label);
345 			dns_name_split(name, split_label, prefix, suffix);
346 			printf("\n    prefix = ");
347 			print_name(prefix);
348 			printf("    suffix = ");
349 			print_name(suffix);
350 		}
351 
352 		if (concatenate) {
353 			if (got_name) {
354 				name = dns_fixedname_name(&wname2);
355 			} else {
356 				name = dns_fixedname_name(&wname);
357 			}
358 		}
359 	}
360 
361 	return (0);
362 }
363