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 50static int srv_rr_order = 1; 51static int loop_integer = 1; 52static int version_flag = 0; 53static int help_flag = 0; 54 55static 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 67static void 68usage (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 79static 80int 81test_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 178int 179main(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