1 /* $NetBSD: resolve-test.c,v 1.2 2017/01/28 21:31:50 christos Exp $ */
2
3 /*
4 * Copyright (c) 1995 - 2016 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36
37 #include <config.h>
38
39 #include <krb5/roken.h>
40 #include <krb5/getarg.h>
41 #include <assert.h>
42 #ifdef HAVE_ARPA_NAMESER_H
43 #include <arpa/nameser.h>
44 #endif
45 #ifdef HAVE_RESOLV_H
46 #include <resolv.h>
47 #endif
48 #include <krb5/resolve.h>
49
50 static int srv_rr_order = 1;
51 static int loop_integer = 1;
52 static int version_flag = 0;
53 static int help_flag = 0;
54
55 static struct getargs args[] = {
56 {"srv-rr-order", 0,
57 arg_negative_flag, &srv_rr_order,
58 "do not test SRV RR ordering", NULL },
59 {"loop", 0, arg_integer, &loop_integer,
60 "loop resolving", NULL },
61 {"version", 0, arg_flag, &version_flag,
62 "print version", NULL },
63 {"help", 0, arg_flag, &help_flag,
64 NULL, NULL }
65 };
66
67 static void
usage(int ret)68 usage (int ret)
69 {
70 arg_printusage (args,
71 sizeof(args)/sizeof(*args),
72 NULL,
73 "dns-record resource-record-type");
74 exit (ret);
75 }
76
77 #define NUMRRS 16
78
79 static
80 int
test_rk_dns_srv_order(size_t run)81 test_rk_dns_srv_order(size_t run)
82 {
83 struct rk_dns_reply reply;
84 struct rk_resource_record rrs[NUMRRS];
85 struct rk_resource_record *rr;
86 struct rk_srv_record srvs[NUMRRS];
87 size_t i, prio0;
88 int fail = 0;
89
90 (void) memset(&reply, 0, sizeof(reply));
91 (void) memset(srvs, 0, sizeof(srvs));
92 (void) memset(rrs, 0, sizeof(rrs));
93
94 /* Test with two equal weight zero SRV records */
95 rrs[0].type = rk_ns_t_srv;
96 rrs[0].u.srv = &srvs[0];
97 rrs[0].next = &rrs[1];
98 srvs[0].priority = 10;
99 srvs[0].weight = 0;
100
101 rrs[1].type = rk_ns_t_srv;
102 rrs[1].u.srv = &srvs[1];
103 rrs[1].next = NULL;
104 srvs[1].priority = 10;
105 srvs[1].weight = 0;
106 reply.head = &rrs[0];
107
108 rk_dns_srv_order(&reply);
109 assert(reply.head != NULL);
110 printf("%p %p\n", &rrs[0], rrs[0].next);
111
112 /*
113 * Test four priority groups with priority 1--5 and weigths 0--3 in the
114 * first two groups, and 1--4 in the last two groups. Test multiple zero
115 * weights, by further coercing the weight to zero if <= run/2.
116 */
117 for (i = 0; i < NUMRRS; i++) {
118 rrs[i].type = rk_ns_t_srv;
119 rrs[i].u.srv = &srvs[i];
120 srvs[i].priority = 1 + i / 4;
121 srvs[i].weight = i % 4 + i / 8;
122 if (srvs[i].weight <= run/2)
123 srvs[i].weight = 0;
124 }
125 /* Shuffle the RRs */
126 for (i = 0; i < NUMRRS - 1; i++) {
127 struct rk_resource_record tmp;
128 size_t j = rk_random() % (NUMRRS - i);
129
130 if (j > 0) {
131 tmp = rrs[i+j];
132 rrs[i+j] = rrs[i];
133 rrs[i] = tmp;
134 }
135 }
136 for (i = 0; i < NUMRRS; i++)
137 rrs[i].next = &rrs[i + 1];
138 rrs[i - 1].next = NULL;
139 reply.head = &rrs[0];
140
141 for (i = 0, rr = reply.head; i < NUMRRS; i++) {
142 if (rr == NULL)
143 break;
144 printf("SRV RR order run %lu input: prio %lu weight %lu\n",
145 (unsigned long)run, (unsigned long)rr->u.srv->priority,
146 (unsigned long)rr->u.srv->weight);
147 rr = rr->next;
148 }
149
150 rk_dns_srv_order(&reply);
151 assert(reply.head != NULL);
152
153 /*
154 * After sorting, ensure monotone priority ordering with jumps by 1 at
155 * group boundaries.
156 */
157 prio0 = 0;
158 for (i = 0, rr = reply.head; i < NUMRRS; i++) {
159 if (rr == NULL)
160 break;
161 if (rr->u.srv->priority < prio0 ||
162 (rr->u.srv->priority != prio0 &&
163 (i % 4 != 0 || rr->u.srv->priority > prio0 + 1))) {
164 printf("SRV RR order run %lu failed\n", run);
165 fail = 1;
166 }
167 prio0 = rr->u.srv->priority;
168 printf("SRV RR order run %lu output: prio %lu weight %lu\n",
169 (unsigned long)run, (unsigned long)rr->u.srv->priority,
170 (unsigned long)rr->u.srv->weight);
171 rr = rr->next;
172 }
173 assert(i == NUMRRS);
174
175 return fail;
176 }
177
178 int
main(int argc,char ** argv)179 main(int argc, char **argv)
180 {
181 struct rk_dns_reply *r;
182 struct rk_resource_record *rr;
183 int optidx = 0, i, exit_code = 0;
184
185 setprogname (argv[0]);
186 rk_random_init();
187
188 if (getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
189 usage(1);
190
191 if (help_flag)
192 usage (0);
193
194 if (version_flag) {
195 printf("some version\n");
196 exit(0);
197 }
198
199 argc -= optidx;
200 argv += optidx;
201
202 if (argc != 2 && argc != 0 && !srv_rr_order)
203 usage(1);
204
205 if (srv_rr_order) {
206 exit_code += test_rk_dns_srv_order(0);
207 exit_code += test_rk_dns_srv_order(1);
208 exit_code += test_rk_dns_srv_order(2);
209 exit_code += test_rk_dns_srv_order(3);
210 exit_code += test_rk_dns_srv_order(4);
211 exit_code += test_rk_dns_srv_order(5);
212 }
213
214 if (srv_rr_order && argc == 0)
215 exit(exit_code ? 1 : 0);
216
217 if (argc != 2)
218 usage(1);
219
220 for (i = 0; i < loop_integer; i++) {
221
222 r = rk_dns_lookup(argv[0], argv[1]);
223 if (r == NULL) {
224 printf("No reply.\n");
225 exit_code = 1;
226 break;
227 }
228 if (r->q.type == rk_ns_t_srv)
229 rk_dns_srv_order(r);
230
231 for (rr = r->head; rr;rr=rr->next) {
232 printf("%-30s %-5s %-6d ", rr->domain, rk_dns_type_to_string(rr->type), rr->ttl);
233 switch (rr->type) {
234 case rk_ns_t_ns:
235 case rk_ns_t_cname:
236 case rk_ns_t_ptr:
237 printf("%s\n", (char*)rr->u.data);
238 break;
239 case rk_ns_t_a:
240 printf("%s\n", inet_ntoa(*rr->u.a));
241 break;
242 case rk_ns_t_mx:
243 case rk_ns_t_afsdb: {
244 printf("%d %s\n", rr->u.mx->preference, rr->u.mx->domain);
245 break;
246 }
247 case rk_ns_t_srv: {
248 struct rk_srv_record *srv = rr->u.srv;
249 printf("%d %d %d %s\n", srv->priority, srv->weight,
250 srv->port, srv->target);
251 break;
252 }
253 case rk_ns_t_txt: {
254 printf("%s\n", rr->u.txt);
255 break;
256 }
257 case rk_ns_t_sig: {
258 struct rk_sig_record *sig = rr->u.sig;
259 const char *type_string = rk_dns_type_to_string (sig->type);
260
261 printf("type %u (%s), algorithm %u, labels %u, orig_ttl %u, "
262 "sig_expiration %u, sig_inception %u, key_tag %u, "
263 "signer %s\n",
264 sig->type, type_string ? type_string : "",
265 sig->algorithm, sig->labels, sig->orig_ttl,
266 sig->sig_expiration, sig->sig_inception, sig->key_tag,
267 sig->signer);
268 break;
269 }
270 case rk_ns_t_key: {
271 struct rk_key_record *key = rr->u.key;
272
273 printf("flags %u, protocol %u, algorithm %u\n",
274 key->flags, key->protocol, key->algorithm);
275 break;
276 }
277 case rk_ns_t_sshfp: {
278 struct rk_sshfp_record *sshfp = rr->u.sshfp;
279 size_t j;
280
281 printf ("alg %u type %u length %lu data ", sshfp->algorithm,
282 sshfp->type, (unsigned long)sshfp->sshfp_len);
283 for (j = 0; j < sshfp->sshfp_len; j++)
284 printf("%02X", sshfp->sshfp_data[j]);
285 printf("\n");
286
287 break;
288 }
289 case rk_ns_t_ds: {
290 struct rk_ds_record *ds = rr->u.ds;
291 size_t j;
292
293 printf("key tag %u alg %u type %u length %lu data ",
294 ds->key_tag, ds->algorithm, ds->digest_type,
295 (unsigned long)ds->digest_len);
296 for (j = 0; j < ds->digest_len; j++)
297 printf("%02X", ds->digest_data[j]);
298 printf("\n");
299
300 break;
301 }
302 default:
303 printf("\n");
304 break;
305 }
306 }
307 rk_dns_free_data(r);
308 }
309
310 return exit_code ? 1 : 0;
311 }
312