Home | History | Annotate | Line # | Download | only in dns
      1 /*	$NetBSD: dns_rr_test.c,v 1.2 2025/02/25 19:15:44 christos Exp $	*/
      2 
      3  /*
      4   * System library.
      5   */
      6 #include <sys_defs.h>
      7 #include <stdlib.h>
      8 
      9  /*
     10   * Utility library.
     11   */
     12 #include <msg.h>
     13 #include <msg_vstream.h>
     14 #include <mymalloc.h>
     15 #include <stringops.h>
     16 #include <vstring.h>
     17 
     18  /*
     19   * DNS library.
     20   */
     21 #include <dns.h>
     22 
     23 #define STR(x)	vstring_str(x)
     24 
     25  /*
     26   * Test helpers. TODO: move eq_dns_rr() to testing/dns_rr_testers.c; need to
     27   * verify that the expected difference is reported, or use a GTEST matcher.
     28   */
     29 
     30 /* print_dns_rr - format as { qname, reply, flags } */
     31 
     32 static char *print_dns_rr(VSTRING *buf, DNS_RR *rr)
     33 {
     34     static VSTRING *tmp;
     35 
     36     if (tmp == 0)
     37 	tmp = vstring_alloc(100);
     38     vstring_sprintf(buf, "{qname=%s, reply='%s', flags=0x%x}",
     39 		    rr->qname, dns_strrecord(tmp, rr), rr->flags);
     40     return (STR(buf));
     41 }
     42 
     43 /* eq_dns_rr - predicate that two lists are equivalent */
     44 
     45 static int eq_dns_rr(DNS_RR *got, DNS_RR *want)
     46 {
     47     VSTRING *got_buf = 0;
     48     VSTRING *want_buf = 0;
     49 
     50 #define EQ_DNS_RR_RETURN(val) do { \
     51 	if (got_buf) \
     52 	    vstring_free(got_buf); \
     53 	if (want_buf) \
     54 	    vstring_free(want_buf); \
     55 	return (val); \
     56     } while (0)
     57 
     58     /* Same length. */
     59     if (got == 0 && want == 0)
     60 	EQ_DNS_RR_RETURN(1);
     61     if (want == 0) {
     62 	msg_warn("got %s, want null",
     63 		 print_dns_rr(got_buf = vstring_alloc(100), got));
     64     }
     65     if (got == 0) {
     66 	msg_warn("got null, want %s",
     67 		 print_dns_rr(want_buf = vstring_alloc(100), want));
     68 	EQ_DNS_RR_RETURN(0);
     69     }
     70     /* Same query name, resource record, flags. */
     71     if (strcmp(print_dns_rr(got_buf = vstring_alloc(100), got),
     72 	       print_dns_rr(want_buf = vstring_alloc(100), want)) != 0) {
     73 	msg_warn("got %s, want %s", STR(want_buf), STR(got_buf));
     74 	EQ_DNS_RR_RETURN(0);
     75     }
     76     /* Same children. */
     77     EQ_DNS_RR_RETURN(eq_dns_rr(got->next, want->next));
     78 }
     79 
     80 static int eq_dns_rr_free(DNS_RR *got, DNS_RR *want)
     81 {
     82     int     res = eq_dns_rr(got, want);
     83 
     84     dns_rr_free(got);
     85     dns_rr_free(want);
     86     return (res);
     87 }
     88 
     89  /*
     90   * Tests and test cases.
     91   */
     92 typedef struct TEST_CASE {
     93     const char *label;			/* identifies test case */
     94     int     (*fn) (void);
     95 } TEST_CASE;
     96 
     97 #define PASS    (0)
     98 #define FAIL    (1)
     99 
    100  /*
    101   * Begin helper tests. TODO: move these to testing/dns_rr_testers_test.c.
    102   */
    103 
    104 static int eq_dns_rr_qname_differ(void)
    105 {
    106     DNS_RR *got = dns_rr_create("qa", "ra", T_SRV, C_IN, 3600, 1, 25, 1, "mxa", 4);
    107     DNS_RR *want = dns_rr_copy(got);
    108 
    109     myfree(want->qname);
    110     want->qname = mystrdup("qb");
    111     return (!eq_dns_rr_free(got, want));
    112 }
    113 
    114 static int eq_dns_rr_reply_differ(void)
    115 {
    116     DNS_RR *got = dns_rr_create("qa", "ra", T_SRV, C_IN, 3600, 1, 25, 1, "mxa", 4);
    117     DNS_RR *want = dns_rr_copy(got);
    118 
    119     want->port += 1;
    120     return (!eq_dns_rr_free(got, want));
    121 }
    122 
    123  /*
    124   * End helper tests.
    125   */
    126 
    127  /*
    128   * Begin DNS_RR tests.
    129   */
    130 
    131 static int eq_dns_rr_flags_differ(void)
    132 {
    133     DNS_RR *got = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    134     DNS_RR *want = dns_rr_copy(got);
    135 
    136     want->flags |= DNS_RR_FLAG_TRUNCATED;
    137     return (!eq_dns_rr_free(got, want));
    138 }
    139 
    140 static int append_to_null_from_null(void)
    141 {
    142     DNS_RR *got = dns_rr_append((DNS_RR *) 0, (DNS_RR *) 0);
    143     DNS_RR *want = 0;
    144 
    145     return (eq_dns_rr_free(got, want));
    146 }
    147 
    148 static int append_to_elem_from_null(void)
    149 {
    150     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    151     DNS_RR *got, *want;
    152 
    153     got = dns_rr_append(dns_rr_copy(a), (DNS_RR *) 0);
    154 
    155     want = a;
    156 
    157     return (eq_dns_rr_free(got, want));
    158 }
    159 
    160 static int appent_to_null_from_elem(void)
    161 {
    162     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    163     DNS_RR *got, *want;
    164 
    165     got = dns_rr_append((DNS_RR *) 0, dns_rr_copy(a));
    166 
    167     want = a;
    168 
    169     return (eq_dns_rr_free(got, want));
    170 }
    171 
    172 static int append_to_elem_from_elem(void)
    173 {
    174     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    175     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    176     DNS_RR *got, *want;
    177 
    178     got = dns_rr_append(dns_rr_copy(a), dns_rr_copy(b));
    179 
    180     (want = a)->next = b;
    181 
    182     return (eq_dns_rr_free(got, want));
    183 }
    184 
    185 static int append_to_elem_from_list(void)
    186 {
    187     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    188     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    189     DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
    190     DNS_RR *got, *want;
    191 
    192     got = dns_rr_append(dns_rr_copy(a),
    193 			dns_rr_append(dns_rr_copy(b),
    194 				      dns_rr_copy(c)));
    195 
    196     ((want = a)->next = b)->next = c;
    197 
    198     return (eq_dns_rr_free(got, want));
    199 }
    200 
    201 static int append_to_list_from_elem(void)
    202 {
    203     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    204     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    205     DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
    206     DNS_RR *got, *want;
    207 
    208     got = dns_rr_append(dns_rr_append(dns_rr_copy(a),
    209 				      dns_rr_copy(b)),
    210 			dns_rr_copy(c));
    211 
    212     ((want = a)->next = b)->next = c;
    213 
    214     return (eq_dns_rr_free(got, want));
    215 }
    216 
    217 static int append_to_list_from_list(void)
    218 {
    219     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    220     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    221     DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
    222     DNS_RR *d = dns_rr_create_noport("qd", "rd", T_MX, C_IN, 3600, 1, "mxd", 4);
    223     DNS_RR *got, *want;
    224 
    225     got = dns_rr_append(dns_rr_append(dns_rr_copy(a),
    226 				      dns_rr_copy(b)),
    227 			dns_rr_append(dns_rr_copy(c),
    228 				      dns_rr_copy(d)));
    229 
    230     (((want = a)->next = b)->next = c)->next = d;
    231 
    232     return (eq_dns_rr_free(got, want));
    233 }
    234 
    235 static int append_propagates_flags(void)
    236 {
    237     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    238     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    239     DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
    240     DNS_RR *d = dns_rr_create_noport("qd", "rd", T_MX, C_IN, 3600, 1, "mxd", 4);
    241     DNS_RR *left = dns_rr_append(dns_rr_copy(a), dns_rr_copy(b));
    242     DNS_RR *rite = dns_rr_append(dns_rr_copy(c), dns_rr_copy(d));
    243     DNS_RR *got, *want, *rr;
    244 
    245     for (rr = rite; rr; rr = rr->next)
    246 	rr->flags |= DNS_RR_FLAG_TRUNCATED;
    247 
    248     got = dns_rr_append(left, rite);
    249 
    250     (((want = a)->next = b)->next = c)->next = d;
    251     for (rr = want; rr; rr = rr->next)
    252 	rr->flags |= DNS_RR_FLAG_TRUNCATED;
    253 
    254     return (eq_dns_rr_free(got, want));
    255 }
    256 
    257 static int append_to_list_from_list_truncate(void)
    258 {
    259     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    260     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    261     DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
    262     DNS_RR *d = dns_rr_create_noport("qd", "rd", T_MX, C_IN, 3600, 1, "mxd", 4);
    263     DNS_RR *got, *want, *rr;
    264 
    265     var_dns_rr_list_limit = 3;
    266 
    267     ((want = dns_rr_copy(a))->next = dns_rr_copy(b))->next = dns_rr_copy(c);
    268     for (rr = want; rr; rr = rr->next)
    269 	rr->flags |= DNS_RR_FLAG_TRUNCATED;
    270 
    271     got = dns_rr_append(dns_rr_append(a, b),
    272 			dns_rr_append(c, d));
    273 
    274     return (eq_dns_rr_free(got, want));
    275 }
    276 
    277 static int append_to_list_from_elem_elem_truncate(void)
    278 {
    279     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    280     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    281     DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
    282     DNS_RR *d = dns_rr_create_noport("qd", "rd", T_MX, C_IN, 3600, 1, "mxd", 4);
    283     DNS_RR *got, *want, *rr;
    284 
    285     var_dns_rr_list_limit = 2;
    286 
    287     (want = dns_rr_copy(a))->next = dns_rr_copy(b);
    288     for (rr = want; rr; rr = rr->next)
    289 	rr->flags |= DNS_RR_FLAG_TRUNCATED;
    290 
    291     got = dns_rr_append(a, b);
    292     got = dns_rr_append(got, c);		/* should be logged  */
    293     got = dns_rr_append(got, d);		/* should be silent */
    294 
    295     return (eq_dns_rr_free(got, want));
    296 }
    297 
    298 static int append_to_list_from_elem_truncate(void)
    299 {
    300     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    301     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    302     DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
    303     DNS_RR *got, *want, *rr;
    304 
    305     var_dns_rr_list_limit = 2;
    306 
    307     (want = dns_rr_copy(a))->next = dns_rr_copy(b);
    308     for (rr = want; rr; rr = rr->next)
    309 	rr->flags |= DNS_RR_FLAG_TRUNCATED;
    310 
    311     got = dns_rr_append(dns_rr_append(a, b), c);
    312 
    313     return (eq_dns_rr_free(got, want));
    314 }
    315 
    316 static int append_to_elem_from_list_truncate(void)
    317 {
    318     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    319     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    320     DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
    321     DNS_RR *got, *want, *rr;
    322 
    323     var_dns_rr_list_limit = 2;
    324 
    325     (want = dns_rr_copy(a))->next = dns_rr_copy(b);
    326     for (rr = want; rr; rr = rr->next)
    327 	rr->flags |= DNS_RR_FLAG_TRUNCATED;
    328 
    329     got = dns_rr_append(a, dns_rr_append(b, c));
    330 
    331     return (eq_dns_rr_free(got, want));
    332 }
    333 
    334 static int append_to_list_from_elem_exact_fit(void)
    335 {
    336     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    337     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    338     DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
    339     DNS_RR *got, *want;
    340 
    341     var_dns_rr_list_limit = 3;
    342 
    343     ((want = dns_rr_copy(a))->next = dns_rr_copy(b))->next = dns_rr_copy(c);
    344 
    345     got = dns_rr_append(dns_rr_append(a, b), c);
    346 
    347     return (eq_dns_rr_free(got, want));
    348 }
    349 
    350 static int append_to_elem_from_list_exact_fit(void)
    351 {
    352     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    353     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    354     DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
    355     DNS_RR *got, *want;
    356 
    357     var_dns_rr_list_limit = 3;
    358 
    359     ((want = dns_rr_copy(a))->next = dns_rr_copy(b))->next = dns_rr_copy(c);
    360 
    361     got = dns_rr_append(a, dns_rr_append(b, c));
    362 
    363     return (eq_dns_rr_free(got, want));
    364 }
    365 
    366 static int delete_middle_element(void)
    367 {
    368     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    369     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    370     DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
    371     DNS_RR *got, *want, *list;
    372 
    373     ((list = a)->next = b)->next = c;
    374     (want = dns_rr_copy(a))->next = dns_rr_copy(c);
    375     got = dns_rr_remove(list, b);
    376 
    377     return (eq_dns_rr_free(got, want));
    378 }
    379 
    380 static int delete_first_element(void)
    381 {
    382     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    383     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    384     DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
    385     DNS_RR *got, *want, *list;
    386 
    387     ((list = a)->next = b)->next = c;
    388     (want = dns_rr_copy(b))->next = dns_rr_copy(c);
    389     got = dns_rr_remove(list, a);
    390 
    391     return (eq_dns_rr_free(got, want));
    392 }
    393 
    394 static int delete_last_element(void)
    395 {
    396     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    397     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    398     DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
    399     DNS_RR *got, *want, *list;
    400 
    401     ((list = a)->next = b)->next = c;
    402     (want = dns_rr_copy(a))->next = dns_rr_copy(b);
    403     got = dns_rr_remove(list, c);
    404 
    405     return (eq_dns_rr_free(got, want));
    406 }
    407 
    408 static int detach_middle_element(void)
    409 {
    410     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    411     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    412     DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
    413     DNS_RR *got, *want, *list;
    414 
    415     ((list = a)->next = b)->next = c;
    416     (want = dns_rr_copy(a))->next = dns_rr_copy(c);
    417     got = dns_rr_detach(list, b);
    418     dns_rr_free(b);
    419 
    420     return (eq_dns_rr_free(got, want));
    421 }
    422 
    423 static int detach_first_element(void)
    424 {
    425     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    426     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    427     DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
    428     DNS_RR *got, *want, *list;
    429 
    430     ((list = a)->next = b)->next = c;
    431     (want = dns_rr_copy(b))->next = dns_rr_copy(c);
    432     got = dns_rr_detach(list, a);
    433     dns_rr_free(a);
    434 
    435     return (eq_dns_rr_free(got, want));
    436 }
    437 
    438 static int detach_last_element(void)
    439 {
    440     DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
    441     DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
    442     DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
    443     DNS_RR *got, *want, *list;
    444 
    445     ((list = a)->next = b)->next = c;
    446     (want = dns_rr_copy(a))->next = dns_rr_copy(b);
    447     got = dns_rr_detach(list, c);
    448     dns_rr_free(c);
    449 
    450     return (eq_dns_rr_free(got, want));
    451 }
    452 
    453  /*
    454   * The test cases.
    455   */
    456 static const TEST_CASE test_cases[] = {
    457 
    458     /*
    459      * Test eq_dns_rr; TODO: move to testing/dns_rr_testers_test.c
    460      */
    461     "eq_dns_rr qname differ", eq_dns_rr_qname_differ,
    462     "eq_dns_rr reply differ", eq_dns_rr_reply_differ,
    463     "eq_dns_rr flags differ", eq_dns_rr_flags_differ,
    464 
    465     /*
    466      * Test dns_rr_append() without truncation.
    467      */
    468     "append to null from null", append_to_null_from_null,
    469     "append to null from element", appent_to_null_from_elem,
    470     "append to element from null", append_to_elem_from_null,
    471     "append to element from element", append_to_elem_from_elem,
    472     "append to element from list", append_to_elem_from_list,
    473     "append to list from element", append_to_list_from_elem,
    474     "append to list from list", append_to_list_from_list,
    475 
    476     /*
    477      * Test dns_rr_append() flag propagation.
    478      */
    479     "append propagates flags", append_propagates_flags,
    480 
    481     /*
    482      * Test dns_rr_append() with truncation.
    483      */
    484     "append to list from list truncate", append_to_list_from_list_truncate,
    485     "append to list from element element truncate", append_to_list_from_elem_elem_truncate,
    486     "append to list from element truncate", append_to_list_from_elem_truncate,
    487     "append to element from list truncate", append_to_elem_from_list_truncate,
    488     "append to list from element exact fit", append_to_list_from_elem_exact_fit,
    489     "append to element from list exact fit", append_to_elem_from_list_exact_fit,
    490 
    491     /*
    492      * TODO: tests for dns_rr_sort(), dns_rr_srv_sort(), dns_rr_shuffle(),
    493      * etc.
    494      */
    495     "delete element from list (middle)", delete_middle_element,
    496     "delete element from list (first)", delete_first_element,
    497     "delete element from list (last)", delete_last_element,
    498     "detach element from list (middle)", detach_middle_element,
    499     "detach element from list (first)", detach_first_element,
    500     "detach element from list (last)", detach_last_element,
    501     0,
    502 };
    503 
    504 int     main(int argc, char **argv)
    505 {
    506     const TEST_CASE *tp;
    507     int     pass = 0;
    508     int     fail = 0;
    509     VSTRING *res_buf = vstring_alloc(100);
    510     int     saved_limit = var_dns_rr_list_limit;
    511 
    512     msg_vstream_init(sane_basename((VSTRING *) 0, argv[0]), VSTREAM_ERR);
    513 
    514     for (tp = test_cases; tp->label != 0; tp++) {
    515 	msg_info("RUN  %s", tp->label);
    516 	if (tp->fn() == 0) {
    517 	    fail++;
    518 	    msg_info("FAIL %s", tp->label);
    519 	} else {
    520 	    msg_info("PASS %s", tp->label);
    521 	    pass++;
    522 	}
    523 	var_dns_rr_list_limit = saved_limit;
    524     }
    525     msg_info("PASS=%d FAIL=%d", pass, fail);
    526     vstring_free(res_buf);
    527     exit(fail != 0);
    528 }
    529