diff options
Diffstat (limited to 'testcode/unitmain.c')
| -rw-r--r-- | testcode/unitmain.c | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/testcode/unitmain.c b/testcode/unitmain.c index b6dac5507faf..647cbca3b05b 100644 --- a/testcode/unitmain.c +++ b/testcode/unitmain.c @@ -530,6 +530,207 @@ infra_test(void) config_delete(cfg); } +#include "util/edns.h" +/* Complete version-invalid client cookie; needs a new one. + * Based on edns_cookie_rfc9018_a2 */ +static void +edns_cookie_invalid_version(void) +{ + uint32_t timestamp = 1559734385; + uint8_t client_cookie[] = { + 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57, + 0x99, 0x00, 0x00, 0x00, + 0x5c, 0xf7, 0x9f, 0x11, + 0x1f, 0x81, 0x30, 0xc3, 0xee, 0xe2, 0x94, 0x80 }; + uint8_t server_cookie[] = { + 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57, + 0x01, 0x00, 0x00, 0x00, + 0x5c, 0xf7, 0xa8, 0x71, + 0xd4, 0xa5, 0x64, 0xa1, 0x44, 0x2a, 0xca, 0x77 }; + uint8_t server_secret[] = { + 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f, + 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf }; + uint8_t buf[32]; + /* copy client cookie|version|reserved|timestamp */ + memcpy(buf, client_cookie, 8 + 4 + 4); + /* copy ip 198.51.100.100 */ + memcpy(buf + 16, "\306\063\144\144", 4); + unit_assert(edns_cookie_server_validate(client_cookie, + sizeof(client_cookie), server_secret, sizeof(server_secret), 1, + buf, timestamp) == COOKIE_STATUS_INVALID); + edns_cookie_server_write(buf, server_secret, 1, timestamp); + unit_assert(memcmp(server_cookie, buf, 24) == 0); +} + +/* Complete hash-invalid client cookie; needs a new one. */ +static void +edns_cookie_invalid_hash(void) +{ + uint32_t timestamp = 0; + uint8_t client_cookie[] = { + 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86, + 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x32, 0xF2, 0x43, 0xB9, 0xBC, 0xFE, 0xC4, 0x06 }; + uint8_t server_cookie[] = { + 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86, + 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xBA, 0x0D, 0x82, 0x90, 0x8F, 0xAA, 0xEB, 0xBD }; + uint8_t server_secret[] = { + 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f, + 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf }; + uint8_t buf[32]; + /* copy client cookie|version|reserved|timestamp */ + memcpy(buf, client_cookie, 8 + 4 + 4); + /* copy ip 203.0.113.203 */ + memcpy(buf + 16, "\313\000\161\313", 4); + unit_assert(edns_cookie_server_validate(client_cookie, + sizeof(client_cookie), server_secret, sizeof(server_secret), 1, + buf, timestamp) == COOKIE_STATUS_INVALID); + edns_cookie_server_write(buf, server_secret, 1, timestamp); + unit_assert(memcmp(server_cookie, buf, 24) == 0); +} + +/* Complete hash-valid client cookie; more than 30 minutes old; needs a + * refreshed server cookie. + * A slightly better variation of edns_cookie_rfc9018_a3 for Unbound to check + * that RESERVED bits do not influence cookie validation. */ +static void +edns_cookie_rfc9018_a3_better(void) +{ + uint32_t timestamp = 1800 + 1; + uint8_t client_cookie[] = { + 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86, + 0x01, 0xab, 0xcd, 0xef, + 0x00, 0x00, 0x00, 0x00, + 0x32, 0xF2, 0x43, 0xB9, 0xBC, 0xFE, 0xC4, 0x06 }; + uint8_t server_cookie[] = { + 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86, + 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x09, + 0x62, 0xD5, 0x93, 0x09, 0x14, 0x5C, 0x23, 0x9D }; + uint8_t server_secret[] = { + 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f, + 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf }; + uint8_t buf[32]; + /* copy client cookie|version|reserved|timestamp */ + memcpy(buf, client_cookie, 8 + 4 + 4); + /* copy ip 203.0.113.203 */ + memcpy(buf + 16, "\313\000\161\313", 4); + unit_assert(edns_cookie_server_validate(client_cookie, + sizeof(client_cookie), server_secret, sizeof(server_secret), 1, + buf, timestamp) == COOKIE_STATUS_VALID_RENEW); + edns_cookie_server_write(buf, server_secret, 1, timestamp); + unit_assert(memcmp(server_cookie, buf, 24) == 0); +} + +/* Complete hash-valid client cookie; more than 60 minutes old (expired); + * needs a refreshed server cookie. */ +static void +edns_cookie_rfc9018_a3(void) +{ + uint32_t timestamp = 1559734700; + uint8_t client_cookie[] = { + 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86, + 0x01, 0xab, 0xcd, 0xef, + 0x5c, 0xf7, 0x8f, 0x71, + 0xa3, 0x14, 0x22, 0x7b, 0x66, 0x79, 0xeb, 0xf5 }; + uint8_t server_cookie[] = { + 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86, + 0x01, 0x00, 0x00, 0x00, + 0x5c, 0xf7, 0xa9, 0xac, + 0xf7, 0x3a, 0x78, 0x10, 0xac, 0xa2, 0x38, 0x1e }; + uint8_t server_secret[] = { + 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f, + 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf }; + uint8_t buf[32]; + /* copy client cookie|version|reserved|timestamp */ + memcpy(buf, client_cookie, 8 + 4 + 4); + /* copy ip 203.0.113.203 */ + memcpy(buf + 16, "\313\000\161\313", 4); + unit_assert(edns_cookie_server_validate(client_cookie, + sizeof(client_cookie), server_secret, sizeof(server_secret), 1, + buf, timestamp) == COOKIE_STATUS_EXPIRED); + edns_cookie_server_write(buf, server_secret, 1, timestamp); + unit_assert(memcmp(server_cookie, buf, 24) == 0); +} + +/* Complete hash-valid client cookie; more than 30 minutes old; needs a + * refreshed server cookie. */ +static void +edns_cookie_rfc9018_a2(void) +{ + uint32_t timestamp = 1559734385; + uint8_t client_cookie[] = { + 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57, + 0x01, 0x00, 0x00, 0x00, + 0x5c, 0xf7, 0x9f, 0x11, + 0x1f, 0x81, 0x30, 0xc3, 0xee, 0xe2, 0x94, 0x80 }; + uint8_t server_cookie[] = { + 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57, + 0x01, 0x00, 0x00, 0x00, + 0x5c, 0xf7, 0xa8, 0x71, + 0xd4, 0xa5, 0x64, 0xa1, 0x44, 0x2a, 0xca, 0x77 }; + uint8_t server_secret[] = { + 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f, + 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf }; + uint8_t buf[32]; + /* copy client cookie|version|reserved|timestamp */ + memcpy(buf, client_cookie, 8 + 4 + 4); + /* copy ip 198.51.100.100 */ + memcpy(buf + 16, "\306\063\144\144", 4); + unit_assert(edns_cookie_server_validate(client_cookie, + sizeof(client_cookie), server_secret, sizeof(server_secret), 1, + buf, timestamp) == COOKIE_STATUS_VALID_RENEW); + edns_cookie_server_write(buf, server_secret, 1, timestamp); + unit_assert(memcmp(server_cookie, buf, 24) == 0); +} + +/* Only client cookie; needs a complete server cookie. */ +static void +edns_cookie_rfc9018_a1(void) +{ + uint32_t timestamp = 1559731985; + uint8_t client_cookie[] = { + 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57 }; + uint8_t server_cookie[] = { + 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57, + 0x01, 0x00, 0x00, 0x00, + 0x5c, 0xf7, 0x9f, 0x11, + 0x1f, 0x81, 0x30, 0xc3, 0xee, 0xe2, 0x94, 0x80 }; + uint8_t server_secret[] = { + 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f, + 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf }; + uint8_t buf[32]; + /* copy client cookie|version|reserved|timestamp */ + memcpy(buf, server_cookie, 8 + 4 + 4); + /* copy ip 198.51.100.100 */ + memcpy(buf + 16, "\306\063\144\144", 4); + unit_assert(edns_cookie_server_validate(client_cookie, + sizeof(client_cookie), + /* these will not be used; it will return invalid + * because of the size. */ + NULL, 0, 1, NULL, 0) == COOKIE_STATUS_CLIENT_ONLY); + edns_cookie_server_write(buf, server_secret, 1, timestamp); + unit_assert(memcmp(server_cookie, buf, 24) == 0); +} + +/** test interoperable DNS cookies (RFC9018) */ +static void +edns_cookie_test(void) +{ + unit_show_feature("interoperable dns cookies"); + /* Check RFC9018 appendix test vectors */ + edns_cookie_rfc9018_a1(); + edns_cookie_rfc9018_a2(); + edns_cookie_rfc9018_a3(); + /* More tests */ + edns_cookie_rfc9018_a3_better(); + edns_cookie_invalid_hash(); + edns_cookie_invalid_version(); +} + #include "util/random.h" /** test randomness */ static void @@ -839,6 +1040,218 @@ static void respip_test(void) respip_conf_actions_test(); } +#include "util/regional.h" +#include "sldns/sbuffer.h" +#include "util/data/dname.h" +#include "util/data/msgreply.h" +#include "util/data/msgencode.h" +#include "sldns/str2wire.h" + +static void edns_ede_encode_setup(struct edns_data* edns, + struct regional* region) +{ + memset(edns, 0, sizeof(*edns)); + edns->edns_present = 1; + edns->edns_version = EDNS_ADVERTISED_VERSION; + edns->udp_size = EDNS_ADVERTISED_SIZE; + edns->bits &= EDNS_DO; + /* Fill up opt_list_out with EDEs */ + unit_assert( + edns_opt_list_append_ede(&edns->opt_list_out, region, + LDNS_EDE_OTHER, "Too long other text")); + unit_assert( + edns_opt_list_append_ede(&edns->opt_list_out, region, + LDNS_EDE_OTHER, "Too long other text")); + unit_assert( + edns_opt_list_append_ede(&edns->opt_list_out, region, + LDNS_EDE_BLOCKED, "Too long blocked text")); + unit_assert( + edns_opt_list_append_ede(&edns->opt_list_out, region, + LDNS_EDE_OTHER, "Too long other text")); + unit_assert( + edns_opt_list_append_ede(&edns->opt_list_out, region, + LDNS_EDE_BLOCKED, "Too long blocked text")); + /* Fill up opt_list_inplace_cb_out with EDEs */ + unit_assert( + edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region, + LDNS_EDE_OTHER, "Too long other text")); + unit_assert( + edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region, + LDNS_EDE_OTHER, "Too long other text")); + unit_assert( + edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region, + LDNS_EDE_BLOCKED, "Too long blocked text")); + unit_assert( + edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region, + LDNS_EDE_OTHER, "Too long other text")); + unit_assert( + edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region, + LDNS_EDE_BLOCKED, "Too long blocked text")); + /* append another EDNS option to both lists */ + unit_assert( + edns_opt_list_append(&edns->opt_list_out, + LDNS_EDNS_UNBOUND_CACHEDB_TESTFRAME_TEST, 0, NULL, region)); + unit_assert( + edns_opt_list_append(&edns->opt_list_inplace_cb_out, + LDNS_EDNS_UNBOUND_CACHEDB_TESTFRAME_TEST, 0, NULL, region)); + /* append LDNS_EDE_OTHER at the end of both lists */ + unit_assert( + edns_opt_list_append_ede(&edns->opt_list_out, region, + LDNS_EDE_OTHER, "Too long other text")); + unit_assert( + edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region, + LDNS_EDE_OTHER, "Too long other text")); +} + +static void edns_ede_encode_encodedecode(struct query_info* qinfo, + struct reply_info* rep, struct regional* region, + struct edns_data* edns, sldns_buffer* pkt) +{ + /* encode */ + unit_assert( + reply_info_answer_encode(qinfo, rep, 1, rep->flags, pkt, + 0, 0, region, 65535, edns, 0, 0)); + /* buffer ready for reading; skip after the question section */ + sldns_buffer_skip(pkt, LDNS_HEADER_SIZE); + (void)query_dname_len(pkt); + sldns_buffer_skip(pkt, 2 + 2); + /* decode */ + unit_assert(parse_edns_from_query_pkt(pkt, edns, NULL, NULL, NULL, 0, + region) == 0); +} + +static void edns_ede_encode_check(struct edns_data* edns, int* found_ede, + int* found_ede_other, int* found_ede_txt, int* found_other_edns) +{ + struct edns_option* opt; + for(opt = edns->opt_list_in; opt; opt = opt->next) { + if(opt->opt_code == LDNS_EDNS_EDE) { + (*found_ede)++; + if(opt->opt_len > 2) + (*found_ede_txt)++; + if(opt->opt_len >= 2 && sldns_read_uint16( + opt->opt_data) == LDNS_EDE_OTHER) + (*found_ede_other)++; + } else { + (*found_other_edns)++; + } + } + +} + +static void edns_ede_encode_fit_test(struct query_info* qinfo, + struct reply_info* rep, struct regional* region) +{ + struct edns_data edns; + int found_ede = 0, found_ede_other = 0, found_ede_txt = 0; + int found_other_edns = 0; + sldns_buffer* pkt = sldns_buffer_new(65535); + unit_assert(pkt); + edns_ede_encode_setup(&edns, region); + /* leave the pkt buffer as is; everything should fit */ + edns_ede_encode_encodedecode(qinfo, rep, region, &edns, pkt); + edns_ede_encode_check(&edns, &found_ede, &found_ede_other, + &found_ede_txt, &found_other_edns); + unit_assert(found_ede == 12); + unit_assert(found_ede_other == 8); + unit_assert(found_ede_txt == 12); + unit_assert(found_other_edns == 2); + /* cleanup */ + sldns_buffer_free(pkt); +} + +static void edns_ede_encode_notxt_fit_test( struct query_info* qinfo, + struct reply_info* rep, struct regional* region) +{ + struct edns_data edns; + sldns_buffer* pkt; + uint16_t edns_field_size, ede_txt_size; + int found_ede = 0, found_ede_other = 0, found_ede_txt = 0; + int found_other_edns = 0; + edns_ede_encode_setup(&edns, region); + /* pkt buffer should fit everything if the ede txt is cropped. + * OTHER EDE should not be there since it is useless without text. */ + edns_field_size = calc_edns_field_size(&edns); + (void)calc_ede_option_size(&edns, &ede_txt_size); + pkt = sldns_buffer_new(LDNS_HEADER_SIZE + + qinfo->qname_len + + 2 + 2 /* qtype + qclass */ + + 11 /* opt record */ + + edns_field_size + - ede_txt_size); + unit_assert(pkt); + edns_ede_encode_encodedecode(qinfo, rep, region, &edns, pkt); + edns_ede_encode_check(&edns, &found_ede, &found_ede_other, + &found_ede_txt, &found_other_edns); + unit_assert(found_ede == 4); + unit_assert(found_ede_other == 0); + unit_assert(found_ede_txt == 0); + unit_assert(found_other_edns == 2); + /* cleanup */ + sldns_buffer_free(pkt); +} + +static void edns_ede_encode_no_fit_test( struct query_info* qinfo, + struct reply_info* rep, struct regional* region) +{ + struct edns_data edns; + sldns_buffer* pkt; + uint16_t edns_field_size, ede_size, ede_txt_size; + int found_ede = 0, found_ede_other = 0, found_ede_txt = 0; + int found_other_edns = 0; + edns_ede_encode_setup(&edns, region); + /* pkt buffer should fit only non-EDE options. */ + edns_field_size = calc_edns_field_size(&edns); + ede_size = calc_ede_option_size(&edns, &ede_txt_size); + pkt = sldns_buffer_new(LDNS_HEADER_SIZE + + qinfo->qname_len + + 2 + 2 /* qtype + qclass */ + + 11 /* opt record */ + + edns_field_size + - ede_size); + unit_assert(pkt); + edns_ede_encode_encodedecode(qinfo, rep, region, &edns, pkt); + edns_ede_encode_check(&edns, &found_ede, &found_ede_other, + &found_ede_txt, &found_other_edns); + unit_assert(found_ede == 0); + unit_assert(found_ede_other == 0); + unit_assert(found_ede_txt == 0); + unit_assert(found_other_edns == 2); + /* cleanup */ + sldns_buffer_free(pkt); +} + +/** test optional EDE encoding with various buffer + * available sizes */ +static void edns_ede_answer_encode_test(void) +{ + struct regional* region = regional_create(); + struct reply_info* rep; + struct query_info qinfo; + unit_show_feature("edns ede optional encoding"); + unit_assert(region); + rep = construct_reply_info_base(region, + LDNS_RCODE_NOERROR | BIT_QR, 1, + 3600, 3600, 3600, + 0, 0, 0, 0, + sec_status_unchecked, LDNS_EDE_NONE); + unit_assert(rep); + memset(&qinfo, 0, sizeof(qinfo)); + qinfo.qname = sldns_str2wire_dname("encode.ede.", &qinfo.qname_len); + unit_assert(qinfo.qname); + qinfo.qtype = LDNS_RR_TYPE_TXT; + qinfo.qclass = LDNS_RR_CLASS_IN; + + edns_ede_encode_fit_test(&qinfo, rep, region); + edns_ede_encode_notxt_fit_test(&qinfo, rep, region); + edns_ede_encode_no_fit_test(&qinfo, rep, region); + + /* cleanup */ + free(qinfo.qname); + regional_free_all(region); + regional_destroy(region); +} + void unit_show_func(const char* file, const char* func) { printf("test %s:%s\n", file, func); @@ -852,6 +1265,7 @@ void unit_show_feature(const char* feature) #ifdef USE_ECDSA_EVP_WORKAROUND void ecdsa_evp_workaround_init(void); #endif + /** * Main unit test program. Setup, teardown and report errors. * @param argc: arg count. @@ -906,9 +1320,11 @@ main(int argc, char* argv[]) slabhash_test(); infra_test(); ldns_test(); + edns_cookie_test(); zonemd_test(); tcpreuse_test(); msgparse_test(); + edns_ede_answer_encode_test(); #ifdef CLIENT_SUBNET ecs_test(); #endif /* CLIENT_SUBNET */ |
