summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--src/bin/dhcp6/dhcp6_lexer.cc12
-rw-r--r--src/lib/asiodns/io_fetch.cc6
-rw-r--r--src/lib/cryptolink/crypto_rng.cc7
-rw-r--r--src/lib/cryptolink/crypto_rng.h5
-rw-r--r--src/lib/cryptolink/openssl_hash.cc3
-rw-r--r--src/lib/d2srv/nc_trans.cc4
-rw-r--r--src/lib/dns/.gitignore2
-rw-r--r--src/lib/dns/Makefile.am67
-rw-r--r--src/lib/dns/char_string.cc265
-rw-r--r--src/lib/dns/char_string.h136
-rw-r--r--src/lib/dns/dns_fwd.h21
-rw-r--r--src/lib/dns/edns.cc21
-rw-r--r--src/lib/dns/edns.h8
-rw-r--r--src/lib/dns/gen-rdatacode.py.in382
-rw-r--r--src/lib/dns/message.cc29
-rw-r--r--src/lib/dns/messagerenderer.cc6
-rw-r--r--src/lib/dns/messagerenderer.h1
-rw-r--r--src/lib/dns/name.cc15
-rw-r--r--src/lib/dns/qid_gen.cc41
-rw-r--r--src/lib/dns/qid_gen.h54
-rw-r--r--src/lib/dns/question.cc15
-rw-r--r--src/lib/dns/question.h5
-rw-r--r--src/lib/dns/rdata.cc19
-rw-r--r--src/lib/dns/rdata/any_255/tsig_250.cc562
-rw-r--r--src/lib/dns/rdata/any_255/tsig_250.h146
-rw-r--r--src/lib/dns/rdata/generic/detail/.gitignore1
-rw-r--r--src/lib/dns/rdata/generic/detail/lexer_util.h58
-rw-r--r--src/lib/dns/rdata/generic/opt_41.cc207
-rw-r--r--src/lib/dns/rdata/generic/opt_41.h90
-rw-r--r--src/lib/dns/rdata/generic/ptr_12.cc120
-rw-r--r--src/lib/dns/rdata/generic/ptr_12.h41
-rw-r--r--src/lib/dns/rdata/generic/rrsig_46.cc329
-rw-r--r--src/lib/dns/rdata/generic/rrsig_46.h51
-rw-r--r--src/lib/dns/rdata/generic/soa_6.cc205
-rw-r--r--src/lib/dns/rdata/generic/soa_6.h48
-rw-r--r--src/lib/dns/rdata/generic/tkey_249.cc608
-rw-r--r--src/lib/dns/rdata/generic/tkey_249.h139
-rw-r--r--src/lib/dns/rdata/in_1/a_1.cc173
-rw-r--r--src/lib/dns/rdata/in_1/a_1.h34
-rw-r--r--src/lib/dns/rdata/in_1/aaaa_28.cc152
-rw-r--r--src/lib/dns/rdata/in_1/aaaa_28.h34
-rw-r--r--src/lib/dns/rdata/in_1/dhcid_49.cc161
-rw-r--r--src/lib/dns/rdata/in_1/dhcid_49.h49
-rw-r--r--src/lib/dns/rdata/template.cc1
-rw-r--r--src/lib/dns/rdata/template.h1
-rw-r--r--src/lib/dns/rdataclass.cc481
-rw-r--r--src/lib/dns/rdataclass.h425
-rw-r--r--src/lib/dns/rrclass-placeholder.h315
-rw-r--r--src/lib/dns/rrclass.cc13
-rw-r--r--src/lib/dns/rrclass.h16
-rw-r--r--src/lib/dns/rrparamregistry-placeholder.cc538
-rw-r--r--src/lib/dns/rrparamregistry.cc39
-rw-r--r--src/lib/dns/rrparamregistry.h3
-rw-r--r--src/lib/dns/rrset.cc52
-rw-r--r--src/lib/dns/rrset.h27
-rw-r--r--src/lib/dns/rrttl.cc13
-rw-r--r--src/lib/dns/rrtype-placeholder.h153
-rw-r--r--src/lib/dns/rrtype.cc15
-rw-r--r--src/lib/dns/rrtype.h61
-rw-r--r--src/lib/dns/tests/Makefile.am37
-rw-r--r--src/lib/dns/tests/dns_exceptions_unittest.cc64
-rw-r--r--src/lib/dns/tests/edns_unittest.cc257
-rw-r--r--src/lib/dns/tests/labelsequence_unittest.cc1242
-rw-r--r--src/lib/dns/tests/master_lexer_inputsource_unittest.cc367
-rw-r--r--src/lib/dns/tests/master_lexer_state_unittest.cc606
-rw-r--r--src/lib/dns/tests/master_lexer_token_unittest.cc161
-rw-r--r--src/lib/dns/tests/master_lexer_unittest.cc520
-rw-r--r--src/lib/dns/tests/master_loader_callbacks_test.cc78
-rw-r--r--src/lib/dns/tests/master_loader_unittest.cc1425
-rw-r--r--src/lib/dns/tests/masterload_unittest.cc1
-rw-r--r--src/lib/dns/tests/message_unittest.cc1156
-rw-r--r--src/lib/dns/tests/messagerenderer_unittest.cc291
-rw-r--r--src/lib/dns/tests/name_unittest.cc793
-rw-r--r--src/lib/dns/tests/nsec3hash_unittest.cc1
-rw-r--r--src/lib/dns/tests/opcode_unittest.cc99
-rw-r--r--src/lib/dns/tests/qid_gen_unittest.cc1
-rw-r--r--src/lib/dns/tests/question_unittest.cc197
-rw-r--r--src/lib/dns/tests/rcode_unittest.cc125
-rw-r--r--src/lib/dns/tests/rdata_afsdb_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_caa_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_char_string_data_unittest.cc180
-rw-r--r--src/lib/dns/tests/rdata_char_string_unittest.cc245
-rw-r--r--src/lib/dns/tests/rdata_cname_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_dhcid_unittest.cc164
-rw-r--r--src/lib/dns/tests/rdata_dname_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_dnskey_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_ds_like_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_hinfo_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_in_a_unittest.cc158
-rw-r--r--src/lib/dns/tests/rdata_in_aaaa_unittest.cc150
-rw-r--r--src/lib/dns/tests/rdata_minfo_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_mx_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_naptr_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_ns_unittest.cc144
-rw-r--r--src/lib/dns/tests/rdata_nsec3_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_nsec3param_like_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_nsec3param_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_nsec_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_nsecbitmap_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_opt_unittest.cc197
-rw-r--r--src/lib/dns/tests/rdata_pimpl_holder_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_ptr_unittest.cc144
-rw-r--r--src/lib/dns/tests/rdata_rp_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_rrsig_unittest.cc368
-rw-r--r--src/lib/dns/tests/rdata_soa_unittest.cc248
-rw-r--r--src/lib/dns/tests/rdata_srv_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_sshfp_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_tkey_unittest.cc449
-rw-r--r--src/lib/dns/tests/rdata_tlsa_unittest.cc1
-rw-r--r--src/lib/dns/tests/rdata_tsig_unittest.cc422
-rw-r--r--src/lib/dns/tests/rdata_txt_like_unittest.cc393
-rw-r--r--src/lib/dns/tests/rdata_unittest.cc470
-rw-r--r--src/lib/dns/tests/rdata_unittest.h86
-rw-r--r--src/lib/dns/tests/rdatafields_unittest.cc1
-rw-r--r--src/lib/dns/tests/rrclass_unittest.cc173
-rw-r--r--src/lib/dns/tests/rrcollator_unittest.cc1
-rw-r--r--src/lib/dns/tests/rrparamregistry_unittest.cc14
-rw-r--r--src/lib/dns/tests/rrset_collection_unittest.cc1
-rw-r--r--src/lib/dns/tests/rrset_unittest.cc440
-rw-r--r--src/lib/dns/tests/rrttl_unittest.cc278
-rw-r--r--src/lib/dns/tests/rrtype_unittest.cc169
-rw-r--r--src/lib/dns/tests/serial_unittest.cc172
-rw-r--r--src/lib/dns/tests/testdata/Makefile.am101
-rw-r--r--src/lib/dns/tests/testdata/rdata_afsdb_fromWire1.spec3
-rw-r--r--src/lib/dns/tests/testdata/rdata_afsdb_fromWire1.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_afsdb_fromWire2.spec6
-rw-r--r--src/lib/dns/tests/testdata/rdata_afsdb_fromWire2.wire11
-rw-r--r--src/lib/dns/tests/testdata/rdata_afsdb_fromWire3.spec4
-rw-r--r--src/lib/dns/tests/testdata/rdata_afsdb_fromWire3.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_afsdb_fromWire4.spec4
-rw-r--r--src/lib/dns/tests/testdata/rdata_afsdb_fromWire4.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_afsdb_fromWire5.spec4
-rw-r--r--src/lib/dns/tests/testdata/rdata_afsdb_fromWire5.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_afsdb_toWire1.spec4
-rw-r--r--src/lib/dns/tests/testdata/rdata_afsdb_toWire1.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_afsdb_toWire2.spec8
-rw-r--r--src/lib/dns/tests/testdata/rdata_afsdb_toWire2.wire11
-rw-r--r--src/lib/dns/tests/testdata/rdata_caa_fromWire1.spec6
-rw-r--r--src/lib/dns/tests/testdata/rdata_caa_fromWire1.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_caa_fromWire2.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_caa_fromWire2.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_caa_fromWire3.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_caa_fromWire3.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_caa_fromWire4.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_caa_fromWire4.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_caa_fromWire56
-rw-r--r--src/lib/dns/tests/testdata/rdata_caa_fromWire64
-rw-r--r--src/lib/dns/tests/testdata/rdata_cname_fromWire44
-rw-r--r--src/lib/dns/tests/testdata/rdata_dname_fromWire44
-rw-r--r--src/lib/dns/tests/testdata/rdata_dnskey_empty_keydata_fromWire.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_dnskey_empty_keydata_fromWire.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_dnskey_fromWire.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_dnskey_fromWire.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_ds_fromWire6
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_fromWire1.spec3
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_fromWire1.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_fromWire2.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_fromWire2.wire11
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_fromWire3.spec6
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_fromWire3.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_fromWire4.spec6
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_fromWire4.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_fromWire5.spec5
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_fromWire5.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_fromWire6.spec5
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_fromWire6.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_toWire1.spec5
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_toWire1.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_toWire2.spec6
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_toWire2.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_toWireUncompressed1.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_toWireUncompressed1.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_toWireUncompressed2.spec8
-rw-r--r--src/lib/dns/tests/testdata/rdata_minfo_toWireUncompressed2.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_mx_fromWire15
-rw-r--r--src/lib/dns/tests/testdata/rdata_mx_toWire112
-rw-r--r--src/lib/dns/tests/testdata/rdata_mx_toWire212
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire17
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire1.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire10.spec8
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire10.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire11.spec8
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire11.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire12.spec9
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire12.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire13.spec9
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire13.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire14.spec9
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire14.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire15.spec10
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire15.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire16.spec8
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire16.wire12
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire17.spec8
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire17.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire2.spec9
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire2.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire36
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire4.spec9
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire4.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire5.spec13
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire5.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire6.spec11
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire6.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire7.spec9
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire7.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire8.spec9
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire8.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire9.spec10
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3_fromWire9.wire16
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3param_fromWire15
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3param_fromWire11.spec8
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3param_fromWire11.wire10
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3param_fromWire13.spec9
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3param_fromWire13.wire10
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3param_fromWire2.spec9
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec3param_fromWire2.wire10
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire16
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire10.spec8
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire10.wire10
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire16.spec8
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire16.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire210
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire310
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire4.spec9
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire4.wire10
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire5.spec13
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire5.wire10
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire6.spec11
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire6.wire10
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire7.spec9
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire7.wire10
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire8.spec9
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire8.wire10
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire9.spec10
-rw-r--r--src/lib/dns/tests/testdata/rdata_nsec_fromWire9.wire12
-rw-r--r--src/lib/dns/tests/testdata/rdata_rp_fromWire1.spec6
-rw-r--r--src/lib/dns/tests/testdata/rdata_rp_fromWire1.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_rp_fromWire2.spec12
-rw-r--r--src/lib/dns/tests/testdata/rdata_rp_fromWire2.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_rp_fromWire3.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_rp_fromWire3.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_rp_fromWire4.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_rp_fromWire4.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_rp_fromWire5.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_rp_fromWire5.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_rp_fromWire6.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_rp_fromWire6.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_rp_toWire1.spec8
-rw-r--r--src/lib/dns/tests/testdata/rdata_rp_toWire1.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_rp_toWire2.spec14
-rw-r--r--src/lib/dns/tests/testdata/rdata_rp_toWire2.wire14
-rw-r--r--src/lib/dns/tests/testdata/rdata_srv_fromWire36
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire4
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire1.spec6
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire1.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire106
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire114
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire124
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire24
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire2.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire2.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire3.spec8
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire3.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire4.spec8
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire4.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire5.spec8
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire5.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire6.spec8
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire6.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire7.spec8
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire7.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire8.spec9
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire8.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_sshfp_fromWire96
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire4
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire106
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire114
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire124
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire24
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire3.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire3.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire4.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire4.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire5.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire5.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire6.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire6.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire7.spec9
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire7.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire8.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire8.wire8
-rw-r--r--src/lib/dns/tests/testdata/rdata_tlsa_fromWire97
-rw-r--r--src/lib/dns/tests/testdata/rdatafields1.spec10
-rw-r--r--src/lib/dns/tests/testdata/rdatafields1.wire9
-rw-r--r--src/lib/dns/tests/testdata/rdatafields2.spec11
-rw-r--r--src/lib/dns/tests/testdata/rdatafields2.wire9
-rw-r--r--src/lib/dns/tests/testdata/rdatafields3.spec11
-rw-r--r--src/lib/dns/tests/testdata/rdatafields3.wire12
-rw-r--r--src/lib/dns/tests/testdata/rdatafields4.spec7
-rw-r--r--src/lib/dns/tests/testdata/rdatafields4.wire12
-rw-r--r--src/lib/dns/tests/testdata/rdatafields5.spec12
-rw-r--r--src/lib/dns/tests/testdata/rdatafields5.wire18
-rw-r--r--src/lib/dns/tests/testdata/rdatafields6.spec13
-rw-r--r--src/lib/dns/tests/testdata/rdatafields6.wire18
-rw-r--r--src/lib/dns/tests/tsig_unittest.cc1180
-rw-r--r--src/lib/dns/tests/tsigerror_unittest.cc125
-rw-r--r--src/lib/dns/tests/tsigkey_unittest.cc349
-rw-r--r--src/lib/dns/tests/tsigrecord_unittest.cc157
-rw-r--r--src/lib/dns/tests/unittest_util.cc19
-rw-r--r--src/lib/dns/tests/unittest_util.h12
-rw-r--r--src/lib/dns/tests/zone_checker_unittest.cc1
-rw-r--r--src/lib/dns/tsig.cc37
-rw-r--r--src/lib/dns/tsigrecord.cc13
-rw-r--r--src/lib/dns/tsigrecord.h4
-rw-r--r--src/lib/dns/txt_like.h237
-rw-r--r--src/lib/util/unittests/wiredata.cc4
318 files changed, 15426 insertions, 7498 deletions
diff --git a/configure.ac b/configure.ac
index 94198c8cc1..cf289880f4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1618,8 +1618,6 @@ AC_CONFIG_FILES([src/lib/dhcpsrv/tests/Makefile])
AC_CONFIG_FILES([src/lib/dhcpsrv/tests/test_libraries.h])
AC_CONFIG_FILES([src/lib/dhcpsrv/testutils/Makefile])
AC_CONFIG_FILES([src/lib/dns/Makefile])
-AC_CONFIG_FILES([src/lib/dns/gen-rdatacode.py],
- [chmod +x src/lib/dns/gen-rdatacode.py])
AC_CONFIG_FILES([src/lib/dns/tests/Makefile])
AC_CONFIG_FILES([src/lib/dns/tests/testdata/Makefile])
AC_CONFIG_FILES([src/lib/eval/Makefile])
diff --git a/src/bin/dhcp6/dhcp6_lexer.cc b/src/bin/dhcp6/dhcp6_lexer.cc
index 5c433f0ab3..7e427df457 100644
--- a/src/bin/dhcp6/dhcp6_lexer.cc
+++ b/src/bin/dhcp6/dhcp6_lexer.cc
@@ -1,6 +1,6 @@
-#line 2 "dhcp6_lexer.cc"
+#line 1 "dhcp6_lexer.cc"
-#line 4 "dhcp6_lexer.cc"
+#line 3 "dhcp6_lexer.cc"
#define YY_INT_ALIGNED short int
@@ -2245,7 +2245,7 @@ using namespace isc::dhcp;
/* To avoid the call to exit... oops! */
#define YY_FATAL_ERROR(msg) isc::dhcp::Parser6Context::fatal(msg)
-#line 2249 "dhcp6_lexer.cc"
+#line 2248 "dhcp6_lexer.cc"
/* noyywrap disables automatic rewinding for the next file to parse. Since we
always parse only a single string, there's no need to do any wraps. And
using yywrap requires linking with -lfl, which provides the default yywrap
@@ -2271,8 +2271,8 @@ using namespace isc::dhcp;
by moving it ahead by yyleng bytes. yyleng specifies the length of the
currently matched token. */
#define YY_USER_ACTION driver.loc_.columns(yyleng);
+#line 2274 "dhcp6_lexer.cc"
#line 2275 "dhcp6_lexer.cc"
-#line 2276 "dhcp6_lexer.cc"
#define INITIAL 0
#define COMMENT 1
@@ -2602,7 +2602,7 @@ YY_DECL
}
-#line 2606 "dhcp6_lexer.cc"
+#line 2605 "dhcp6_lexer.cc"
while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
{
@@ -5774,7 +5774,7 @@ YY_RULE_SETUP
#line 2512 "dhcp6_lexer.ll"
ECHO;
YY_BREAK
-#line 5778 "dhcp6_lexer.cc"
+#line 5777 "dhcp6_lexer.cc"
case YY_END_OF_BUFFER:
{
diff --git a/src/lib/asiodns/io_fetch.cc b/src/lib/asiodns/io_fetch.cc
index b0c3b46d1b..8256fa2de6 100644
--- a/src/lib/asiodns/io_fetch.cc
+++ b/src/lib/asiodns/io_fetch.cc
@@ -18,7 +18,7 @@
#include <asiodns/logger.h>
#include <dns/messagerenderer.h>
#include <dns/opcode.h>
-#include <dns/qid_gen.h>
+#include <cryptolink/crypto_rng.h>
#include <dns/rcode.h>
#include <util/buffer.h>
@@ -83,7 +83,7 @@ struct IOFetchData : boost::noncopyable {
isc::log::MessageID origin; ///< Origin of last asynchronous I/O
uint8_t staging[IOFetch::STAGING_LENGTH];
///< Temporary array for received data
- isc::dns::qid_t qid; ///< The QID set in the query
+ isc::dns::qid_t qid; ///< The QID set in the query
/// \brief Constructor
///
@@ -132,7 +132,7 @@ struct IOFetchData : boost::noncopyable {
packet(false),
origin(ASIODNS_UNKNOWN_ORIGIN),
staging(),
- qid(QidGenerator::getInstance().generateQid()) {
+ qid(cryptolink::generateQid()) {
}
/// \brief Destructor
diff --git a/src/lib/cryptolink/crypto_rng.cc b/src/lib/cryptolink/crypto_rng.cc
index e6b4ee0f29..13155fbcbb 100644
--- a/src/lib/cryptolink/crypto_rng.cc
+++ b/src/lib/cryptolink/crypto_rng.cc
@@ -28,5 +28,12 @@ random(size_t len) {
return (rng->random(len));
}
+uint16_t generateQid() {
+ uint16_t val;
+ std::vector<uint8_t> rnd = random(sizeof(uint16_t));
+ memmove(&val, &rnd[0], sizeof(uint16_t));
+ return (val);
+}
+
} // namespace cryptolink
} // namespace isc
diff --git a/src/lib/cryptolink/crypto_rng.h b/src/lib/cryptolink/crypto_rng.h
index cfada09a96..1a2c96bd9f 100644
--- a/src/lib/cryptolink/crypto_rng.h
+++ b/src/lib/cryptolink/crypto_rng.h
@@ -57,6 +57,11 @@ private:
/// \param len The length of the data
std::vector<uint8_t> random(size_t len);
+/// \brief Generate a Qid
+///
+/// \return A random Qid
+uint16_t generateQid();
+
} // namespace cryptolink
} // namespace isc
diff --git a/src/lib/cryptolink/openssl_hash.cc b/src/lib/cryptolink/openssl_hash.cc
index 68f2285e15..1dd935c85b 100644
--- a/src/lib/cryptolink/openssl_hash.cc
+++ b/src/lib/cryptolink/openssl_hash.cc
@@ -145,8 +145,7 @@ private:
EVP_MD_CTX* md_;
};
-Hash::Hash(const HashAlgorithm hash_algorithm)
-{
+Hash::Hash(const HashAlgorithm hash_algorithm) {
impl_ = new HashImpl(hash_algorithm);
}
diff --git a/src/lib/d2srv/nc_trans.cc b/src/lib/d2srv/nc_trans.cc
index 4b2baaf2aa..43e71cb098 100644
--- a/src/lib/d2srv/nc_trans.cc
+++ b/src/lib/d2srv/nc_trans.cc
@@ -8,7 +8,7 @@
#include <d2srv/d2_log.h>
#include <d2srv/nc_trans.h>
-#include <dns/qid_gen.h>
+#include <cryptolink/crypto_rng.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <hooks/hooks.h>
@@ -352,7 +352,7 @@ NameChangeTransaction::prepNewRequest(DdnsDomainPtr domain) {
D2UpdateMessagePtr request(new D2UpdateMessage(D2UpdateMessage::
OUTBOUND));
// Set the query id
- request->setId(dns::QidGenerator::getInstance().generateQid());
+ request->setId(cryptolink::generateQid());
// Construct the Zone Section.
dns::Name zone_name(domain->getName());
request->setZone(zone_name, dns::RRClass::IN());
diff --git a/src/lib/dns/.gitignore b/src/lib/dns/.gitignore
index fa14fe18b4..e69de29bb2 100644
--- a/src/lib/dns/.gitignore
+++ b/src/lib/dns/.gitignore
@@ -1,2 +0,0 @@
-/gen-rdatacode.py
-/s-rdatacode
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index feac9e3c22..9dd841065a 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -7,45 +7,7 @@ AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CXXFLAGS = $(KEA_CXXFLAGS)
CLEANFILES = *.gcno *.gcda
-CLEANFILES += s-rdatacode
-# These two are created with rrtype/class.h, so not explicitly listed in
-# BUILT_SOURCES.
-CLEANFILES += python/rrtype_constants_inc.cc
-CLEANFILES += python/rrclass_constants_inc.cc
-DISTCLEANFILES = gen-rdatacode.py
-
-EXTRA_DIST = rrclass-placeholder.h
-EXTRA_DIST += rrparamregistry-placeholder.cc
-EXTRA_DIST += rrtype-placeholder.h
-
-# TODO: double-check that this is the only way
-# NOTE: when an rdata file is added, please also add to this list:
-EXTRA_DIST += rdata/any_255/tsig_250.cc
-EXTRA_DIST += rdata/any_255/tsig_250.h
-EXTRA_DIST += rdata/generic/detail/lexer_util.h
-EXTRA_DIST += rdata/generic/opt_41.cc
-EXTRA_DIST += rdata/generic/opt_41.h
-EXTRA_DIST += rdata/generic/ptr_12.cc
-EXTRA_DIST += rdata/generic/ptr_12.h
-EXTRA_DIST += rdata/generic/rrsig_46.cc
-EXTRA_DIST += rdata/generic/rrsig_46.h
-EXTRA_DIST += rdata/generic/soa_6.cc
-EXTRA_DIST += rdata/generic/soa_6.h
-EXTRA_DIST += rdata/generic/tkey_249.cc
-EXTRA_DIST += rdata/generic/tkey_249.h
-EXTRA_DIST += rdata/in_1/a_1.cc
-EXTRA_DIST += rdata/in_1/a_1.h
-EXTRA_DIST += rdata/in_1/aaaa_28.cc
-EXTRA_DIST += rdata/in_1/aaaa_28.h
-EXTRA_DIST += rdata/in_1/dhcid_49.cc
-EXTRA_DIST += rdata/in_1/dhcid_49.h
-EXTRA_DIST += rdata/template.cc
-EXTRA_DIST += rdata/template.h
-
-noinst_SCRIPTS = gen-rdatacode.py
-
-# auto-generate by gen-rdatacode.py:
BUILT_SOURCES = rrclass.h rrtype.h rrparamregistry.cc
BUILT_SOURCES += rdataclass.h rdataclass.cc
@@ -55,7 +17,6 @@ libkea_dns___la_LDFLAGS = -no-undefined -version-info 54:0:0
libkea_dns___la_LDFLAGS += $(AM_LDFLAGS) $(CRYPTO_LDFLAGS)
libkea_dns___la_SOURCES =
-libkea_dns___la_SOURCES += dns_fwd.h
libkea_dns___la_SOURCES += edns.h edns.cc
libkea_dns___la_SOURCES += exceptions.h exceptions.cc
libkea_dns___la_SOURCES += master_lexer_inputsource.h master_lexer_inputsource.cc
@@ -75,7 +36,6 @@ libkea_dns___la_SOURCES += rrparamregistry.h
libkea_dns___la_SOURCES += rrset.h rrset.cc
libkea_dns___la_SOURCES += rrttl.h rrttl.cc
libkea_dns___la_SOURCES += rrtype.cc
-libkea_dns___la_SOURCES += qid_gen.h qid_gen.cc
libkea_dns___la_SOURCES += question.h question.cc
libkea_dns___la_SOURCES += serial.h serial.cc
libkea_dns___la_SOURCES += tsig.h tsig.cc
@@ -84,6 +44,9 @@ libkea_dns___la_SOURCES += tsigkey.h tsigkey.cc
libkea_dns___la_SOURCES += tsigrecord.h tsigrecord.cc
libkea_dns___la_SOURCES += master_loader_callbacks.h
libkea_dns___la_SOURCES += master_loader.h
+libkea_dns___la_SOURCES += txt_like.h
+libkea_dns___la_SOURCES += char_string.h char_string.cc
+
libkea_dns___la_CPPFLAGS = $(AM_CPPFLAGS)
libkea_dns___la_LIBADD = $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la
@@ -96,24 +59,9 @@ libkea_dns___la_LIBADD += $(CRYPTO_LIBS)
libkea_dns___la_SOURCES += rdataclass.h rrclass.h rrtype.h
libkea_dns___la_SOURCES += rdataclass.cc rrparamregistry.cc
-rrclass.h: rrclass-placeholder.h
-rrtype.h: rrtype-placeholder.h
-rrparamregistry.cc: rrparamregistry-placeholder.cc
-
-s-rdatacode: Makefile $(EXTRA_DIST)
- $(PYTHON) ./gen-rdatacode.py
- touch $@
-
-# In ticket #3413 we removed the whole BIND10/Bundy framework. We also want
-# to not require Python3, hence instead of generating the code every time,
-# we added the generated files to our repo. It is still possible to regenerate
-# those files, but that step is no longer required for successful compilation.
-
-#rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc: s-rdatacode
-
libdns___includedir = $(pkgincludedir)/dns
libdns___include_HEADERS = \
- dns_fwd.h \
+ char_string.h \
edns.h \
exceptions.h \
labelsequence.h \
@@ -126,7 +74,6 @@ libdns___include_HEADERS = \
messagerenderer.h \
name.h \
opcode.h \
- qid_gen.h \
question.h \
rcode.h \
rdata.h \
@@ -140,9 +87,7 @@ libdns___include_HEADERS = \
tsig.h \
tsigerror.h \
tsigkey.h \
- tsigrecord.h
+ tsigrecord.h \
+ txt_like.h
# Purposely not installing these headers:
# name_internal.h: used only internally, and not actually DNS specific
-# rdata/*/detail/*.h: these are internal use only
-# rrclass-placeholder.h
-# rrtype-placeholder.h
diff --git a/src/lib/dns/char_string.cc b/src/lib/dns/char_string.cc
new file mode 100644
index 0000000000..c28d2047c5
--- /dev/null
+++ b/src/lib/dns/char_string.cc
@@ -0,0 +1,265 @@
+// Copyright (C) 2012-2024 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/exceptions.h>
+#include <dns/rdata.h>
+#include <dns/master_lexer.h>
+#include <dns/char_string.h>
+#include <util/buffer.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include <cassert>
+#include <cctype>
+#include <cstring>
+#include <vector>
+
+#include <stdint.h>
+
+namespace isc {
+namespace dns {
+namespace rdata {
+namespace generic {
+namespace detail {
+
+namespace {
+// Convert a DDD form to the corresponding integer
+int
+decimalToNumber(const char* s, const char* s_end) {
+ if (s_end - s < 3) {
+ isc_throw(InvalidRdataText, "Escaped digits too short");
+ }
+
+ const std::string num_str(s, s + 3);
+ try {
+ const int i = boost::lexical_cast<int>(num_str);
+ if (i > 255) {
+ isc_throw(InvalidRdataText, "Escaped digits too large: "
+ << num_str);
+ }
+ return (i);
+ } catch (const boost::bad_lexical_cast&) {
+ isc_throw(InvalidRdataText,
+ "Invalid form for escaped digits: " << num_str);
+ }
+}
+}
+
+void
+stringToCharString(const MasterToken::StringRegion& str_region,
+ CharString& result) {
+ // make a space for the 1-byte length field; filled in at the end
+ result.push_back(0);
+
+ bool escape = false;
+ const char* s = str_region.beg;
+ const char* const s_end = str_region.beg + str_region.len;
+
+ for (size_t n = str_region.len; n != 0; --n, ++s) {
+ int c = (*s & 0xff);
+ if (escape && std::isdigit(c) != 0) {
+ c = decimalToNumber(s, s_end);
+ assert(n >= 3);
+ n -= 2;
+ s += 2;
+ } else if (!escape && c == '\\') {
+ escape = true;
+ continue;
+ }
+ escape = false;
+ result.push_back(c);
+ }
+ if (escape) { // terminated by non-escaped '\'
+ isc_throw(InvalidRdataText, "character-string ends with '\\'");
+ }
+ if (result.size() > MAX_CHARSTRING_LEN + 1) { // '+ 1' due to the len field
+ isc_throw(CharStringTooLong, "character-string is too long: " <<
+ (result.size() - 1) << "(+1) characters");
+ }
+ result[0] = result.size() - 1;
+}
+
+void
+stringToCharStringData(const MasterToken::StringRegion& str_region,
+ CharStringData& result) {
+ bool escape = false;
+ const char* s = str_region.beg;
+ const char* const s_end = str_region.beg + str_region.len;
+
+ for (size_t n = str_region.len; n != 0; --n, ++s) {
+ int c = (*s & 0xff);
+ if (escape && std::isdigit(c) != 0) {
+ c = decimalToNumber(s, s_end);
+ // decimalToNumber() already throws if (s_end - s) is less
+ // than 3, so the following assertion is unnecessary. But we
+ // assert it anyway. 'n' is an unsigned type (size_t) and
+ // can underflow.
+ assert(n >= 3);
+ // 'n' and 's' are also updated by 1 in the for statement's
+ // expression, so we update them by 2 instead of 3 here.
+ n -= 2;
+ s += 2;
+ } else if (!escape && c == '\\') {
+ escape = true;
+ continue;
+ }
+ escape = false;
+ result.push_back(c);
+ }
+ if (escape) { // terminated by non-escaped '\'
+ isc_throw(InvalidRdataText, "character-string ends with '\\'");
+ }
+}
+
+std::string
+charStringToString(const CharString& char_string) {
+ std::string s;
+ bool first = true;
+ for (auto const& it : char_string) {
+ if (first) {
+ first = false;
+ continue;
+ }
+ const uint8_t ch = it;
+ if ((ch < 0x20) || (ch >= 0x7f)) {
+ // convert to escaped \xxx (decimal) format
+ s.push_back('\\');
+ s.push_back('0' + ((ch / 100) % 10));
+ s.push_back('0' + ((ch / 10) % 10));
+ s.push_back('0' + (ch % 10));
+ continue;
+ }
+ if ((ch == '"') || (ch == ';') || (ch == '\\')) {
+ s.push_back('\\');
+ }
+ s.push_back(ch);
+ }
+
+ return (s);
+}
+
+std::string
+charStringDataToString(const CharStringData& char_string) {
+ std::string s;
+ for (auto const& it : char_string) {
+ const uint8_t ch = it;
+ if ((ch < 0x20) || (ch >= 0x7f)) {
+ // convert to escaped \xxx (decimal) format
+ s.push_back('\\');
+ s.push_back('0' + ((ch / 100) % 10));
+ s.push_back('0' + ((ch / 10) % 10));
+ s.push_back('0' + (ch % 10));
+ continue;
+ }
+ if ((ch == '"') || (ch == ';') || (ch == '\\')) {
+ s.push_back('\\');
+ }
+ s.push_back(ch);
+ }
+
+ return (s);
+}
+
+int compareCharStrings(const detail::CharString& self,
+ const detail::CharString& other) {
+ if (self.size() == 0 && other.size() == 0) {
+ return (0);
+ }
+ if (self.size() == 0) {
+ return (-1);
+ }
+ if (other.size() == 0) {
+ return (1);
+ }
+ const size_t self_len = self[0];
+ const size_t other_len = other[0];
+ const size_t cmp_len = std::min(self_len, other_len);
+ if (cmp_len == 0) {
+ if (self_len < other_len) {
+ return (-1);
+ } else if (self_len > other_len) {
+ return (1);
+ } else {
+ return (0);
+ }
+ }
+ const int cmp = std::memcmp(&self[1], &other[1], cmp_len);
+ if (cmp < 0) {
+ return (-1);
+ } else if (cmp > 0) {
+ return (1);
+ } else if (self_len < other_len) {
+ return (-1);
+ } else if (self_len > other_len) {
+ return (1);
+ } else {
+ return (0);
+ }
+}
+
+int compareCharStringDatas(const detail::CharStringData& self,
+ const detail::CharStringData& other) {
+ if (self.size() == 0 && other.size() == 0) {
+ return (0);
+ }
+ if (self.size() == 0) {
+ return (-1);
+ }
+ if (other.size() == 0) {
+ return (1);
+ }
+ const size_t self_len = self.size();
+ const size_t other_len = other.size();
+ const size_t cmp_len = std::min(self_len, other_len);
+ const int cmp = std::memcmp(&self[0], &other[0], cmp_len);
+ if (cmp < 0) {
+ return (-1);
+ } else if (cmp > 0) {
+ return (1);
+ } else if (self_len < other_len) {
+ return (-1);
+ } else if (self_len > other_len) {
+ return (1);
+ } else {
+ return (0);
+ }
+}
+
+size_t
+bufferToCharString(isc::util::InputBuffer& buffer, size_t rdata_len,
+ CharString& target) {
+ if (rdata_len < 1 || buffer.getLength() - buffer.getPosition() < 1) {
+ isc_throw(isc::dns::DNSMessageFORMERR,
+ "insufficient data to read character-string length");
+ }
+ const uint8_t len = buffer.readUint8();
+ if (rdata_len < len + 1) {
+ isc_throw(isc::dns::DNSMessageFORMERR,
+ "character string length is too large: " <<
+ static_cast<int>(len));
+ }
+ if (buffer.getLength() - buffer.getPosition() < len) {
+ isc_throw(isc::dns::DNSMessageFORMERR,
+ "not enough data in buffer to read character-string of len"
+ << static_cast<int>(len));
+ }
+
+ target.resize(len + 1);
+ target[0] = len;
+ buffer.readData(&target[0] + 1, len);
+
+ return (len + 1);
+}
+
+} // end of detail
+} // end of generic
+} // end of rdata
+} // end of dns
+} // end of isc
diff --git a/src/lib/dns/char_string.h b/src/lib/dns/char_string.h
new file mode 100644
index 0000000000..adfcab1db4
--- /dev/null
+++ b/src/lib/dns/char_string.h
@@ -0,0 +1,136 @@
+// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef DNS_RDATA_CHARSTRING_H
+#define DNS_RDATA_CHARSTRING_H 1
+
+#include <dns/master_lexer.h>
+
+#include <string>
+#include <vector>
+#include <algorithm>
+#include <stdint.h>
+
+namespace isc {
+namespace dns {
+namespace rdata {
+namespace generic {
+namespace detail {
+
+/// \brief Type for DNS character string.
+///
+/// A character string can contain any unsigned 8-bit value, so this cannot
+/// be the bare char basis.
+typedef std::vector<uint8_t> CharString;
+
+/// \brief Type for DNS character string without the length prefix.
+typedef std::vector<uint8_t> CharStringData;
+
+/// \brief Convert a DNS character-string into corresponding binary data.
+///
+/// This helper function takes a string object that is expected to be a
+/// textual representation of a valid DNS character-string, and dumps
+/// the corresponding binary sequence in the given placeholder (passed
+/// via the \c result parameter). It handles escape notations of
+/// character-strings with a backslash ('\'), and checks the length
+/// restriction.
+///
+/// \throw CharStringTooLong The resulting binary data are too large for a
+/// valid character-string.
+/// \throw InvalidRdataText Other syntax errors.
+///
+/// \brief str_region A string that represents a character-string.
+/// \brief result A placeholder vector where the resulting data are to be
+/// stored. Expected to be empty, but it's not checked.
+void stringToCharString(const MasterToken::StringRegion& str_region,
+ CharString& result);
+
+/// \brief Convert a DNS character-string into corresponding binary data.
+///
+/// This method functions similar to \c stringToCharString() except it
+/// does not include the 1-octet length prefix in the \c result, and the
+/// result is not limited to MAX_CHARSTRING_LEN octets.
+///
+/// \throw InvalidRdataText Upon syntax errors.
+///
+/// \brief str_region A string that represents a character-string.
+/// \brief result A placeholder vector where the resulting data are to be
+/// stored. Expected to be empty, but it's not checked.
+void stringToCharStringData(const MasterToken::StringRegion& str_region,
+ CharStringData& result);
+
+/// \brief Convert a CharString into a textual DNS character-string.
+///
+/// This method converts a binary 8-bit representation of a DNS
+/// character string into a textual string representation, escaping any
+/// special characters in the process. For example, characters like
+/// double-quotes, semi-colon and backspace are prefixed with backspace
+/// character, and characters not in the printable range of [0x20, 0x7e]
+/// (inclusive) are converted to the \xxx 3-digit decimal
+/// representation.
+///
+/// \param char_string The \c CharString to convert.
+/// \return A string representation of \c char_string.
+std::string charStringToString(const CharString& char_string);
+
+/// \brief Convert a CharStringData into a textual DNS character-string.
+///
+/// Reverse of \c stringToCharStringData(). See \c stringToCharString()
+/// vs. \c stringToCharStringData().
+///
+/// \param char_string The \c CharStringData to convert.
+/// \return A string representation of \c char_string.
+std::string charStringDataToString(const CharStringData& char_string);
+
+/// \brief Compare two CharString objects
+///
+/// \param self The CharString field to compare
+/// \param other The CharString field to compare to
+///
+/// \return -1 if \c self would be sorted before \c other
+/// 1 if \c self would be sorted after \c other
+/// 0 if \c self and \c other are equal
+int compareCharStrings(const CharString& self, const CharString& other);
+
+/// \brief Compare two CharStringData objects
+///
+/// \param self The CharStringData field to compare
+/// \param other The CharStringData field to compare to
+///
+/// \return -1 if \c self would be sorted before \c other
+/// 1 if \c self would be sorted after \c other
+/// 0 if \c self and \c other are equal
+int compareCharStringDatas(const CharStringData& self,
+ const CharStringData& other);
+
+/// \brief Convert a buffer containing a character-string to CharString
+///
+/// This method reads one character-string from the given buffer (in wire
+/// format) and places the result in the given \c CharString object.
+/// Since this is expected to be used in message parsing, the exception it
+/// raises is of that type.
+///
+/// On success, the buffer position is advanced to the end of the char-string,
+/// and the number of bytes read is returned.
+///
+/// \param buffer The buffer to read from.
+/// \param rdata_len The total size of the rr's rdata currently being read
+/// (used for integrity checks in the wire data)
+/// \param target The \c CharString where the result will be stored. Any
+/// existing data in the target will be overwritten.
+/// \throw DNSMessageFORMERR If the available data is not enough to read
+/// the character-string, or if the character-string length is out of bounds
+/// \return The number of bytes read
+size_t bufferToCharString(isc::util::InputBuffer& buffer, size_t rdata_len,
+ CharString& target);
+
+
+} // namespace detail
+} // namespace generic
+} // namespace rdata
+} // namespace dns
+} // namespace isc
+#endif // DNS_RDATA_CHARSTRING_H
diff --git a/src/lib/dns/dns_fwd.h b/src/lib/dns/dns_fwd.h
deleted file mode 100644
index 5ba2802a7f..0000000000
--- a/src/lib/dns/dns_fwd.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef DNS_FWD_H
-#define DNS_FWD_H
-
-/// \file dns_fwd.h
-/// \brief Forward declarations for definitions of libdns++
-///
-/// This file provides a set of forward declarations for definitions commonly
-/// used in libdns++ to help minimize dependency when actual the definition
-/// is not necessary.
-
-namespace isc {
-namespace dns {
-} // namespace dns
-} // namespace isc
-#endif // DNS_FWD_H
diff --git a/src/lib/dns/edns.cc b/src/lib/dns/edns.cc
index 3d9c21ac45..35ad58733f 100644
--- a/src/lib/dns/edns.cc
+++ b/src/lib/dns/edns.cc
@@ -6,14 +6,7 @@
#include <config.h>
-#include <stdint.h>
-
-#include <cassert>
-
-#include <boost/lexical_cast.hpp>
-
#include <exceptions/exceptions.h>
-
#include <dns/edns.h>
#include <dns/exceptions.h>
#include <dns/message.h>
@@ -25,10 +18,14 @@
#include <dns/rrttl.h>
#include <dns/rrtype.h>
+#include <stdint.h>
+#include <boost/lexical_cast.hpp>
+
+using namespace isc::util;
+using namespace isc::dns::rdata;
+
using namespace std;
using boost::lexical_cast;
-using namespace isc::dns::rdata;
-using namespace isc::util;
namespace isc {
namespace dns {
@@ -104,7 +101,7 @@ namespace {
/// Helper function to define unified implementation for the public versions
/// of toWire().
template <typename Output>
-int
+uint32_t
toWireCommon(Output& output, const uint8_t version,
const uint16_t udp_size, const bool dnssec_aware,
const uint8_t extended_rcode) {
@@ -127,7 +124,7 @@ toWireCommon(Output& output, const uint8_t version,
}
}
-unsigned int
+uint32_t
EDNS::toWire(AbstractMessageRenderer& renderer,
const uint8_t extended_rcode) const {
// If adding the OPT RR would exceed the size limit, don't do it.
@@ -141,7 +138,7 @@ EDNS::toWire(AbstractMessageRenderer& renderer,
extended_rcode));
}
-unsigned int
+uint32_t
EDNS::toWire(isc::util::OutputBuffer& buffer,
const uint8_t extended_rcode) const {
return (toWireCommon(buffer, version_, udp_size_, dnssec_aware_,
diff --git a/src/lib/dns/edns.h b/src/lib/dns/edns.h
index 2415a52724..362f7bdc75 100644
--- a/src/lib/dns/edns.h
+++ b/src/lib/dns/edns.h
@@ -304,8 +304,8 @@ public:
/// \param extended_rcode Upper 8 bits of extended RCODE to be rendered as
/// part of the EDNS OPT RR.
/// \return 1 if the OPT RR fits in the message size limit; otherwise 0.
- unsigned int toWire(AbstractMessageRenderer& renderer,
- const uint8_t extended_rcode) const;
+ uint32_t toWire(AbstractMessageRenderer& renderer,
+ const uint8_t extended_rcode) const;
/// \brief Render the \c EDNS in the wire format.
///
@@ -313,8 +313,8 @@ public:
/// except it renders the OPT RR in an \c OutputBuffer and therefore
/// does not care about message size limit.
/// As a consequence it always returns 1.
- unsigned int toWire(isc::util::OutputBuffer& buffer,
- const uint8_t extended_rcode) const;
+ uint32_t toWire(isc::util::OutputBuffer& buffer,
+ const uint8_t extended_rcode) const;
/// \brief Convert the EDNS to a string.
///
diff --git a/src/lib/dns/gen-rdatacode.py.in b/src/lib/dns/gen-rdatacode.py.in
deleted file mode 100644
index e5284a3459..0000000000
--- a/src/lib/dns/gen-rdatacode.py.in
+++ /dev/null
@@ -1,382 +0,0 @@
-#!@PYTHON@
-
-# Copyright (C) 2010-2021 Internet Systems Consortium, Inc. ("ISC")
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-"""\
-This is a supplemental script to (half) auto-generate DNS Rdata related
-classes and constants.
-"""
-
-# This script should be used every time existing RR data changes or when new
-# RR types are added or existing are removed. Since DHCP uses only four
-# (A,AAAA,PTR,DHCID) RR types, its usage is expected to be an uncommon event.
-# The only envisaged use case is if/when we decide to trim down libdns++.
-
-import os
-from os.path import getmtime
-import re
-import sys
-
-re_typecode = re.compile('([\da-z\-]+)_(\d+)')
-classcode2txt = {}
-typecode2txt = {}
-# For meta types and types well-known but not implemented. This is a dict from
-# type code values (as string) to textual mnemonic.
-meta_types = {
- # Real meta types. We won't have Rdata implement for them, but we need
- # RRType constants.
- '251': 'ixfr', '252': 'axfr', '255': 'any',
- # Obsolete types. We probably won't implement Rdata for them, but it's
- # better to have RRType constants.
- '3': 'md', '4': 'mf', '7': 'mb', '8': 'mg', '9': 'mr', '30': 'nxt',
- '38': 'a6', '254': 'maila',
- # Types officially assigned but not yet supported in our implementation.
- '10': 'null', '11': 'wks', '19': 'x25', '21': 'rt', '22': 'nsap',
- '23': 'nsap-ptr', '24': 'sig', '20': 'isdn', '25': 'key', '26': 'px',
- '27': 'gpos', '29': 'loc', '36': 'kx', '37': 'cert', '42': 'apl',
- '45': 'ipseckey', '55': 'hip', '103': 'unspec',
- '104': 'nid', '105': 'l32', '106': 'l64', '107': 'lp',
- '253': 'mailb', '256': 'uri'
- }
-# Classes that don't have any known types. This is a dict from type code
-# values (as string) to textual mnemonic.
-meta_classes = {'254': 'none'}
-typeandclass = []
-generic_code = 65536 # something larger than any code value
-rdata_declarations = ''
-class_definitions = ''
-classdir_mtime = 0
-rdatadef_mtime = 0
-rdatahdr_mtime = 0
-heading_txt = '''///////////////
-///////////////
-/////////////// THIS FILE IS AUTOMATICALLY GENERATED BY gen-rdatacode.py.
-/////////////// DO NOT EDIT!
-///////////////
-///////////////
-
-'''
-
-def import_classdef(class_txt, file):
- content = ''
- rdata_source = open(file, 'r')
- for line in rdata_source.readlines():
- if re.match('// BEGIN_ISC_NAMESPACE', line):
- content += 'namespace isc {\n'
- content += 'namespace dns {\n'
- continue
- if re.match('// BEGIN_RDATA_NAMESPACE', line):
- content += 'namespace rdata {\n'
- content += 'namespace ' + class_txt + ' {\n'
- continue
- if re.match('// END_ISC_NAMESPACE', line):
- content += '} // end of namespace "dns"\n'
- content += '} // end of namespace "isc"\n'
- continue
- if re.match('// END_RDATA_NAMESPACE', line):
- content += '} // end of namespace "' + class_txt +'"\n'
- content += '} // end of namespace "rdata"\n'
- continue
- content += line
- rdata_source.close()
- return content
-
-def import_classheader(class_txt, type_txt, type_code, file):
- type_utxt = type_txt.upper()
- class_utxt = class_txt.upper()
-
- # for each CLASS_n/TYPE_m.h
- rdata_header = open(file, 'r')
- content = ''
- guard_macro = class_txt.upper() + '_' + type_txt.upper()
- guard_macro += '_' + type_code + '_H'
- for line in rdata_header.readlines():
- if re.match('// BEGIN_HEADER_GUARD', line):
- content += '#ifndef ' + guard_macro + '\n'
- content += '#define ' + guard_macro + ' 1\n'
- continue
- if re.match('// END_HEADER_GUARD', line):
- content += '#endif // ' + guard_macro + '\n'
- continue
- if re.match('// BEGIN_ISC_NAMESPACE', line):
- content += 'namespace isc {\n'
- content += 'namespace dns {\n'
- continue
- if re.match('// BEGIN_RDATA_NAMESPACE', line):
- content += 'namespace rdata {\n'
- content += 'namespace ' + class_txt + ' {\n'
- continue
- if re.match('// END_ISC_NAMESPACE', line):
- content += '} // end of namespace "dns"\n'
- content += '} // end of namespace "isc"\n'
- continue
- if re.match('// END_RDATA_NAMESPACE', line):
- content += '} // end of namespace "' + class_txt +'"\n'
- content += '} // end of namespace "rdata"\n'
- continue
- if re.match('// Local Variables:', line):
- break
- content += line
- if re.match('// BEGIN_COMMON_DECLARATIONS', line):
- content += '''
-class AbstractMessageRenderer;\n\n'''
- if re.match('\s+// BEGIN_COMMON_MEMBERS$', line):
- content += '''
- explicit ''' + type_utxt + '''(const std::string& type_str);
- ''' + type_utxt + '''(isc::util::InputBuffer& buffer, size_t rdata_len);
- ''' + type_utxt + '''(const ''' + type_utxt + '''& other);
- ''' + type_utxt + '''(
- MasterLexer& lexer, const Name* name,
- MasterLoader::Options options, MasterLoaderCallbacks& callbacks);
- virtual std::string toText() const;
- virtual void toWire(isc::util::OutputBuffer& buffer) const;
- virtual void toWire(AbstractMessageRenderer& renderer) const;
- virtual int compare(const Rdata& other) const;\n\n'''
- rdata_header.close()
- return content
-
-def import_definitions(classcode2txt, typecode2txt, typeandclass):
- global rdata_declarations
- global class_definitions
- global classdir_mtime
- global rdatadef_mtime
- global rdatahdr_mtime
-
- if classdir_mtime < getmtime('@srcdir@/rdata'):
- classdir_mtime = getmtime('@srcdir@/rdata')
-
- # Sort directories before iterating through them so that the directory
- # list is processed in the same order on all systems. The resulting
- # files should compile regardless of the order in which the components
- # are included but... Having a fixed order for the directories should
- # eliminate system-dependent problems. (Note that the directory names
- # in BIND 10 are ASCII, so the order should be locale-independent.)
- dirlist = os.listdir('@srcdir@/rdata')
- dirlist.sort()
- for dir in dirlist:
- classdir = '@srcdir@/rdata' + os.sep + dir
- m = re_typecode.match(dir)
- if os.path.isdir(classdir) and (m != None or dir == 'generic'):
- if dir == 'generic':
- class_txt = 'generic'
- class_code = generic_code
- else:
- class_txt = m.group(1)
- class_code = m.group(2)
- if not class_code in classcode2txt:
- classcode2txt[class_code] = class_txt
-
- # Same considerations as directories regarding sorted order
- # also apply to files.
- filelist = os.listdir(classdir)
- filelist.sort()
- for file in filelist:
- file = classdir + os.sep + file
- m = re_typecode.match(os.path.split(file)[1])
- if m != None:
- type_txt = m.group(1)
- type_code = m.group(2)
- if not type_code in typecode2txt:
- typecode2txt[type_code] = type_txt
- if re.search('\.cc$', file):
- if rdatadef_mtime < getmtime(file):
- rdatadef_mtime = getmtime(file)
- class_definitions += import_classdef(class_txt, file)
- elif re.search('\.h$', file):
- if rdatahdr_mtime < getmtime(file):
- rdatahdr_mtime = getmtime(file)
- rdata_declarations += import_classheader(class_txt,
- type_txt,
- type_code,
- file)
- typeandclass.append((type_txt, int(type_code),
- (class_txt, class_txt),
- int(class_code)))
- if class_txt == 'generic':
- typeandclass.append((type_txt, int(type_code),
- (class_txt, 'in'), 1))
-
-def need_generate(file, mtime):
- '''Check if we need to generate the specified file.
-
- To avoid unnecessary compilation, we skip (re)generating the file when
- the file already exists and newer than the base file.
- '''
- if os.path.exists(file) and getmtime(file) > mtime:
- return False
- return True
-
-def generate_rdatadef(file, basemtime):
- if not need_generate(file, basemtime):
- print('skip generating ' + file);
- return
- rdata_deffile = open(file, 'w')
- rdata_deffile.write(heading_txt)
- rdata_deffile.write(class_definitions)
- rdata_deffile.close()
-
-def generate_rdatahdr(file, heading, declarations, basemtime):
- if not need_generate(file, basemtime):
- print('skip generating ' + file);
- return
- heading += '''
-#ifndef DNS_RDATACLASS_H
-#define DNS_RDATACLASS_H
-
-#include <dns/master_loader.h>
-
-namespace isc {
-namespace dns {
-class Name;
-class MasterLexer;
-class MasterLoaderCallbacks;
-}
-}
-'''
- declarations += '''
-#endif // DNS_RDATACLASS_H
-'''
- rdata_header = open(file, 'w')
- rdata_header.write(heading)
- rdata_header.write(declarations)
- rdata_header.close()
-
-def generate_typeclasscode(fileprefix, basemtime, code2txt, type_or_class):
- placeholder = '@srcdir@/' + fileprefix + '-placeholder.h'
- outputfile = '@builddir@/' + fileprefix + '.h'
- py_outputfile = '@builddir@/python/' + fileprefix + '_constants_inc.cc'
- upper_key = type_or_class.upper() # TYPE or CLASS
- lower_key = 'rr' + type_or_class.lower() # rrtype or rrclass
- cap_key = type_or_class # Type or Class
-
- # We only decide whether to generate files for libdns++ files; Python
- # files are generated if and only if libdns++ files are generated.
- # In practice it should be sufficient.
- if (not need_generate(outputfile, basemtime) and
- getmtime(outputfile) > getmtime(placeholder)):
- print('skip generating ' + outputfile)
- return
-
- # Create a list of (code, code-text) pairs, where code-text is generally
- # upper-cased, with applying special filters when necessary.
- def convert(code_txt):
- # Workaround by heuristics: there's a "NULL" RR type, but it would
- # cause conflict with the C/C++ macro. We use Null as a special case.
- if code_txt == 'null':
- return 'Null'
- # Likewise, convert "nsap-ptr" to "NSAP_PTR" as a dash cannot be part
- # of a C/C++ variable.
- if code_txt == 'nsap-ptr':
- return 'NSAP_PTR'
- return code_txt.upper()
- codes = [ (code, convert(txt)) for code, txt in code2txt.items() ]
-
- # Dump source code for libdns++
- with open(placeholder, 'r') as header_temp:
- with open(outputfile, 'w') as header_out:
- header_out.write(heading_txt)
- for line in header_temp:
- header_out.write(line)
- if re.match('\s+// BEGIN_WELL_KNOWN_' + upper_key +
- '_DECLARATIONS$', line):
- for code in codes:
- header_out.write(' ' * 4 + 'static const RR' +
- cap_key + '& ' + code[1] + '();\n')
- if re.match('// BEGIN_WELL_KNOWN_' + upper_key +
- '_DEFINITIONS$', line):
- for code in codes:
- header_out.write('''inline const RR''' + cap_key +
- '''&
-RR''' + cap_key + '''::''' + code[1] + '''() {
- static RR''' + cap_key + ''' ''' + lower_key + '''(''' + code[0] + ''');
- return (''' + lower_key + ''');
-}\n
-''')
-
- # Dump source code snippet for isc.dns Python module
- with open(py_outputfile, 'w') as py_out:
- py_out.write(" // auto-generated by ../gen-rdatacode.py."
- " Don't edit this file.\n")
- py_out.write("\n")
- for code in codes:
- py_out.write('''\
- installClassVariable(''' + lower_key + '''_type, "''' + code[1] + '''",
- createRR''' + cap_key + '''Object(RR''' + \
- cap_key + '''::''' + code[1] + '''()));
-''')
-
-def generate_rrparam(fileprefix, basemtime):
- placeholder = '@srcdir@/' + fileprefix + '-placeholder.cc'
- outputfile = '@builddir@/' + fileprefix + '.cc'
- if not need_generate(outputfile, basemtime) and getmtime(outputfile) > getmtime(placeholder):
- print('skip generating ' + outputfile)
- return
-
- # sort by class, then by type
- typeandclassparams = ''
- typeandclass.sort(key = lambda x: (x[3], x[1]))
- for param in typeandclass:
- # for rrparamregistry.cc
- # each param is a tuple of (type_txt, type_code, class_tuple,
- # class_code)
- (type_txt, type_code, class_tuple, class_code) = param
- type_utxt = type_txt.upper()
- class_txt = class_tuple[0]
- class_utxt = class_tuple[1].upper()
- indent = ' ' * 8
- typeandclassparams += indent
-
- if class_tuple[1] != 'generic':
- typeandclassparams += 'add("' + type_utxt + '", '
- typeandclassparams += str(type_code) + ', "' + class_utxt
- typeandclassparams += '", ' + str(class_code)
- typeandclassparams += ', RdataFactoryPtr(new ' + 'RdataFactory' + '<'
- typeandclassparams += class_txt + '::' + type_utxt + '>()));\n'
- else:
- typeandclassparams += 'add("' + type_utxt + '", ' + str(type_code)
- typeandclassparams += ', RdataFactoryPtr(new ' + 'RdataFactory' + '<'
- typeandclassparams += class_txt + '::' + type_utxt + '>()));\n'
-
- typeandclassparams += indent + '// Meta and non-implemented RR types\n'
- for type_code, type_txt in meta_types.items():
- typeandclassparams += indent + \
- 'addType("' + type_txt.upper() + '", ' + type_code + ');\n'
-
- typeandclassparams += indent + '// Meta classes\n'
- for cls_code, cls_txt in meta_classes.items():
- typeandclassparams += indent + \
- 'addClass("' + cls_txt.upper() + '", ' + cls_code + ');\n'
-
- rrparam_temp = open(placeholder, 'r')
- rrparam_out = open(outputfile, 'w')
- rrparam_out.write(heading_txt)
- for line in rrparam_temp.readlines():
- rrparam_out.write(line)
- if re.match('\s+// BEGIN_WELL_KNOWN_PARAMS', line):
- rrparam_out.write(typeandclassparams)
- rrparam_temp.close()
- rrparam_out.close()
-
-if __name__ == "__main__":
- try:
- import_definitions(classcode2txt, typecode2txt, typeandclass)
- generate_rdatadef('@builddir@/rdataclass.cc', rdatadef_mtime)
- generate_rdatahdr('@builddir@/rdataclass.h', heading_txt,
- rdata_declarations, rdatahdr_mtime)
-
- # merge auto-generated types/classes with meta maps and generate the
- # corresponding code.
- generate_typeclasscode('rrtype', rdatahdr_mtime,
- dict(typecode2txt, **meta_types), 'Type')
- generate_typeclasscode('rrclass', classdir_mtime,
- dict(classcode2txt, **meta_classes), 'Class')
-
- generate_rrparam('rrparamregistry', rdatahdr_mtime)
- except:
- sys.stderr.write('Code generation failed due to exception: %s\n' %
- sys.exc_info()[1])
- exit(1)
diff --git a/src/lib/dns/message.cc b/src/lib/dns/message.cc
index f2b52816fe..d855f4d90d 100644
--- a/src/lib/dns/message.cc
+++ b/src/lib/dns/message.cc
@@ -6,21 +6,7 @@
#include <config.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <cassert>
-#include <string>
-#include <sstream>
-#include <vector>
-
-#include <boost/lexical_cast.hpp>
-#include <boost/shared_ptr.hpp>
-
#include <exceptions/exceptions.h>
-
-#include <util/buffer.h>
-
#include <dns/edns.h>
#include <dns/exceptions.h>
#include <dns/message.h>
@@ -35,12 +21,23 @@
#include <dns/rrttl.h>
#include <dns/rrset.h>
#include <dns/tsig.h>
+#include <util/buffer.h>
+
+#include <stdint.h>
+#include <algorithm>
+#include <cassert>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <boost/lexical_cast.hpp>
+#include <boost/shared_ptr.hpp>
-using namespace std;
-using boost::lexical_cast;
using namespace isc::dns::rdata;
using namespace isc::util;
+using namespace std;
+using boost::lexical_cast;
+
namespace isc {
namespace dns {
diff --git a/src/lib/dns/messagerenderer.cc b/src/lib/dns/messagerenderer.cc
index fcef95c9aa..bc59e16d63 100644
--- a/src/lib/dns/messagerenderer.cc
+++ b/src/lib/dns/messagerenderer.cc
@@ -7,23 +7,23 @@
#include <config.h>
#include <exceptions/exceptions.h>
-#include <util/buffer.h>
#include <dns/name.h>
#include <dns/name_internal.h>
#include <dns/labelsequence.h>
#include <dns/messagerenderer.h>
+#include <util/buffer.h>
#include <boost/array.hpp>
#include <boost/static_assert.hpp>
-
#include <limits>
#include <cassert>
#include <vector>
-using namespace std;
using namespace isc::util;
using isc::dns::name::internal::maptolower;
+using namespace std;
+
namespace isc {
namespace dns {
diff --git a/src/lib/dns/messagerenderer.h b/src/lib/dns/messagerenderer.h
index d63bbd7ea5..ec47132a4b 100644
--- a/src/lib/dns/messagerenderer.h
+++ b/src/lib/dns/messagerenderer.h
@@ -13,7 +13,6 @@
#include <boost/noncopyable.hpp>
namespace isc {
-
namespace dns {
// forward declarations
class Name;
diff --git a/src/lib/dns/name.cc b/src/lib/dns/name.cc
index addac4fa8e..efdea0e10d 100644
--- a/src/lib/dns/name.cc
+++ b/src/lib/dns/name.cc
@@ -6,6 +6,12 @@
#include <config.h>
+#include <exceptions/isc_assert.h>
+#include <dns/name.h>
+#include <dns/name_internal.h>
+#include <dns/messagerenderer.h>
+#include <dns/labelsequence.h>
+
#include <cctype>
#include <iterator>
#include <functional>
@@ -13,16 +19,11 @@
#include <iostream>
#include <algorithm>
-#include <exceptions/isc_assert.h>
-#include <dns/name.h>
-#include <dns/name_internal.h>
-#include <dns/messagerenderer.h>
-#include <dns/labelsequence.h>
-
-using namespace std;
using namespace isc::util;
using namespace isc::dns::name::internal;
+using namespace std;
+
namespace isc {
namespace dns {
diff --git a/src/lib/dns/qid_gen.cc b/src/lib/dns/qid_gen.cc
deleted file mode 100644
index 207eeadb3e..0000000000
--- a/src/lib/dns/qid_gen.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (C) 2011-2021 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-// qid_gen defines a generator for query id's
-//
-// We probably want to merge this with the weighted random in the nsas
-// (and other parts where we need randomness, perhaps another thing
-// for a general libutil?)
-
-#include <config.h>
-
-#include <cryptolink/crypto_rng.h>
-#include <dns/qid_gen.h>
-#include <cstring>
-
-namespace isc {
-namespace dns {
-
-QidGenerator qid_generator_instance;
-
-QidGenerator&
-QidGenerator::getInstance() {
- return (qid_generator_instance);
-}
-
-QidGenerator::QidGenerator() {
-}
-
-uint16_t
-QidGenerator::generateQid() {
- uint16_t val;
- std::vector<uint8_t> rnd = isc::cryptolink::random(sizeof(uint16_t));
- memmove(&val, &rnd[0], sizeof(uint16_t));
- return (val);
-}
-
-} // namespace dns
-} // namespace isc
diff --git a/src/lib/dns/qid_gen.h b/src/lib/dns/qid_gen.h
deleted file mode 100644
index 732dd9a3bc..0000000000
--- a/src/lib/dns/qid_gen.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (C) 2011-2021 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-// qid_gen defines a generator for query id's
-//
-// We probably want to merge this with the weighted random in the nsas
-// (and other parts where we need randomness, perhaps another thing
-// for a general libutil?)
-
-#ifndef QID_GEN_H
-#define QID_GEN_H
-
-#include <cryptolink/crypto_rng.h>
-#include <stdint.h>
-
-namespace isc {
-namespace dns {
-
-/// This class generates Qids for outgoing queries
-///
-/// It is implemented as a singleton; the public way to access it
-/// is to call getInstance()->generateQid().
-///
-/// It automatically seeds it with the current time when it is first
-/// used.
-class QidGenerator {
-public:
- /// \brief Returns the singleton instance of the QidGenerator
- ///
- /// Returns a reference to the singleton instance of the generator
- static QidGenerator& getInstance();
-
- /// \brief Default constructor
- ///
- /// It is recommended that getInstance is used rather than creating
- /// separate instances of this class.
- ///
- /// The constructor automatically seeds the generator with the
- /// current time.
- QidGenerator();
-
- /// Generate a Qid
- ///
- /// \return A random Qid
- uint16_t generateQid();
-};
-
-} // namespace dns
-} // namespace isc
-
-#endif // QID_GEN_H
diff --git a/src/lib/dns/question.cc b/src/lib/dns/question.cc
index 72499f2355..7659f34ae3 100644
--- a/src/lib/dns/question.cc
+++ b/src/lib/dns/question.cc
@@ -6,19 +6,20 @@
#include <config.h>
-#include <iostream>
-#include <string>
-
-#include <util/buffer.h>
#include <dns/messagerenderer.h>
#include <dns/name.h>
#include <dns/question.h>
#include <dns/rrclass.h>
#include <dns/rrtype.h>
+#include <util/buffer.h>
+
+#include <iostream>
+#include <string>
-using namespace std;
using namespace isc::util;
+using namespace std;
+
namespace isc {
namespace dns {
Question::Question(InputBuffer& buffer) :
@@ -44,7 +45,7 @@ Question::toText(bool newline) const {
return (r);
}
-unsigned int
+uint32_t
Question::toWire(OutputBuffer& buffer) const {
name_.toWire(buffer);
rrtype_.toWire(buffer);
@@ -53,7 +54,7 @@ Question::toWire(OutputBuffer& buffer) const {
return (1);
}
-unsigned int
+uint32_t
Question::toWire(AbstractMessageRenderer& renderer) const {
const size_t pos0 = renderer.getLength();
diff --git a/src/lib/dns/question.h b/src/lib/dns/question.h
index 055907a315..21a8a9b4e7 100644
--- a/src/lib/dns/question.h
+++ b/src/lib/dns/question.h
@@ -17,7 +17,6 @@
#include <dns/rrtype.h>
namespace isc {
-
namespace dns {
class Question;
@@ -214,7 +213,7 @@ public:
/// output buffer and name compression information.
///
/// \return 1 on success; 0 if it causes truncation
- unsigned int toWire(AbstractMessageRenderer& renderer) const;
+ uint32_t toWire(AbstractMessageRenderer& renderer) const;
/// \brief Render the Question in the wire format without name compression.
///
@@ -224,7 +223,7 @@ public:
///
/// \param buffer An output buffer to store the wire data.
/// \return 1
- unsigned int toWire(isc::util::OutputBuffer& buffer) const;
+ uint32_t toWire(isc::util::OutputBuffer& buffer) const;
//@}
///
diff --git a/src/lib/dns/rdata.cc b/src/lib/dns/rdata.cc
index 25829c8d2e..dd778a9c17 100644
--- a/src/lib/dns/rdata.cc
+++ b/src/lib/dns/rdata.cc
@@ -7,20 +7,17 @@
#include <config.h>
#include <exceptions/exceptions.h>
-
-#include <util/buffer.h>
-#include <util/encode/encode.h>
-
#include <dns/name.h>
#include <dns/messagerenderer.h>
#include <dns/master_lexer.h>
#include <dns/rdata.h>
#include <dns/rrparamregistry.h>
#include <dns/rrtype.h>
+#include <util/buffer.h>
+#include <util/encode/encode.h>
#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp>
-
#include <algorithm>
#include <cctype>
#include <string>
@@ -29,13 +26,13 @@
#include <ios>
#include <ostream>
#include <vector>
-
#include <stdint.h>
#include <string.h>
+using namespace isc::util;
+
using namespace std;
using boost::lexical_cast;
-using namespace isc::util;
namespace isc {
namespace dns {
@@ -61,7 +58,7 @@ createRdata(const RRType& rrtype, const RRClass& rrclass,
RdataPtr
createRdata(const RRType& rrtype, const RRClass& rrclass,
- isc::util::InputBuffer& buffer, size_t len) {
+ InputBuffer& buffer, size_t len) {
if (len > MAX_RDLENGTH) {
isc_throw(InvalidRdataLength, "RDLENGTH too large");
}
@@ -197,7 +194,7 @@ struct GenericImpl {
vector<uint8_t> data_;
};
-Generic::Generic(isc::util::InputBuffer& buffer, size_t rdata_len) {
+Generic::Generic(InputBuffer& buffer, size_t rdata_len) {
if (rdata_len > MAX_RDLENGTH) {
isc_throw(InvalidRdataLength, "RDLENGTH too large");
}
@@ -256,7 +253,7 @@ Generic::constructFromLexer(MasterLexer& lexer) {
}
try {
- isc::util::encode::decodeHex(hex_txt, data);
+ encode::decodeHex(hex_txt, data);
} catch (const isc::BadValue& ex) {
isc_throw(InvalidRdataText,
"Invalid hex encoding of generic RDATA: " << ex.what());
@@ -351,7 +348,7 @@ Generic::toText() const {
}
void
-Generic::toWire(isc::util::OutputBuffer& buffer) const {
+Generic::toWire(OutputBuffer& buffer) const {
buffer.writeData(&impl_->data_[0], impl_->data_.size());
}
diff --git a/src/lib/dns/rdata/any_255/tsig_250.cc b/src/lib/dns/rdata/any_255/tsig_250.cc
deleted file mode 100644
index b5469d2bcd..0000000000
--- a/src/lib/dns/rdata/any_255/tsig_250.cc
+++ /dev/null
@@ -1,562 +0,0 @@
-// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <string>
-#include <sstream>
-#include <vector>
-
-#include <boost/lexical_cast.hpp>
-
-#include <util/buffer.h>
-#include <util/encode/encode.h>
-
-#include <dns/messagerenderer.h>
-#include <dns/name.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rcode.h>
-#include <dns/tsigkey.h>
-#include <dns/tsigerror.h>
-#include <dns/rdata/generic/detail/lexer_util.h>
-
-using namespace std;
-using boost::lexical_cast;
-using namespace isc::util;
-using namespace isc::util::encode;
-using namespace isc::dns;
-using isc::dns::rdata::generic::detail::createNameFromLexer;
-
-// BEGIN_ISC_NAMESPACE
-// BEGIN_RDATA_NAMESPACE
-
-// straightforward representation of TSIG RDATA fields
-struct TSIGImpl {
- TSIGImpl(const Name& algorithm, uint64_t time_signed, uint16_t fudge,
- vector<uint8_t>& mac, uint16_t original_id, uint16_t error,
- vector<uint8_t>& other_data) :
- algorithm_(algorithm), time_signed_(time_signed), fudge_(fudge),
- mac_(mac), original_id_(original_id), error_(error),
- other_data_(other_data) {
- }
- TSIGImpl(const Name& algorithm, uint64_t time_signed, uint16_t fudge,
- size_t macsize, const void* mac, uint16_t original_id,
- uint16_t error, size_t other_len, const void* other_data) :
- algorithm_(algorithm), time_signed_(time_signed), fudge_(fudge),
- mac_(static_cast<const uint8_t*>(mac),
- static_cast<const uint8_t*>(mac) + macsize),
- original_id_(original_id), error_(error),
- other_data_(static_cast<const uint8_t*>(other_data),
- static_cast<const uint8_t*>(other_data) + other_len) {
- }
- template <typename Output>
- void toWireCommon(Output& output) const;
-
- const Name algorithm_;
- const uint64_t time_signed_;
- const uint16_t fudge_;
- const vector<uint8_t> mac_;
- const uint16_t original_id_;
- const uint16_t error_;
- const vector<uint8_t> other_data_;
-};
-
-// helper function for string and lexer constructors
-boost::shared_ptr<TSIGImpl>
-TSIG::constructFromLexer(MasterLexer& lexer, const Name* origin) {
- const Name& algorithm =
- createNameFromLexer(lexer, origin ? origin : &Name::ROOT_NAME());
- const Name& canonical_algorithm_name =
- (algorithm == TSIGKey::HMACMD5_SHORT_NAME()) ?
- TSIGKey::HMACMD5_NAME() : algorithm;
-
- const string& time_txt =
- lexer.getNextToken(MasterToken::STRING).getString();
- uint64_t time_signed;
- try {
- time_signed = boost::lexical_cast<uint64_t>(time_txt);
- } catch (const boost::bad_lexical_cast&) {
- isc_throw(InvalidRdataText, "Invalid TSIG Time");
- }
- if ((time_signed >> 48) != 0) {
- isc_throw(InvalidRdataText, "TSIG Time out of range");
- }
-
- const uint32_t fudge = lexer.getNextToken(MasterToken::NUMBER).getNumber();
- if (fudge > 0xffff) {
- isc_throw(InvalidRdataText, "TSIG Fudge out of range");
- }
- const uint32_t macsize =
- lexer.getNextToken(MasterToken::NUMBER).getNumber();
- if (macsize > 0xffff) {
- isc_throw(InvalidRdataText, "TSIG MAC Size out of range");
- }
-
- const string& mac_txt = (macsize > 0) ?
- lexer.getNextToken(MasterToken::STRING).getString() : "";
- vector<uint8_t> mac;
- decodeBase64(mac_txt, mac);
- if (mac.size() != macsize) {
- isc_throw(InvalidRdataText, "TSIG MAC Size and data are inconsistent");
- }
-
- const uint32_t orig_id =
- lexer.getNextToken(MasterToken::NUMBER).getNumber();
- if (orig_id > 0xffff) {
- isc_throw(InvalidRdataText, "TSIG Original ID out of range");
- }
-
- const string& error_txt =
- lexer.getNextToken(MasterToken::STRING).getString();
- uint32_t error = 0;
- // XXX: In the initial implementation we hardcode the mnemonics.
- // We'll soon generalize this.
- if (error_txt == "NOERROR") {
- error = Rcode::NOERROR_CODE;
- } else if (error_txt == "BADSIG") {
- error = TSIGError::BAD_SIG_CODE;
- } else if (error_txt == "BADKEY") {
- error = TSIGError::BAD_KEY_CODE;
- } else if (error_txt == "BADTIME") {
- error = TSIGError::BAD_TIME_CODE;
- } else if (error_txt == "BADMODE") {
- error = TSIGError::BAD_MODE_CODE;
- } else if (error_txt == "BADNAME") {
- error = TSIGError::BAD_NAME_CODE;
- } else if (error_txt == "BADALG") {
- error = TSIGError::BAD_ALG_CODE;
- } else if (error_txt == "BADTRUNC") {
- error = TSIGError::BAD_TRUNC_CODE;
- } else {
- /// we cast to uint32_t and range-check, because casting directly to
- /// uint16_t will convert negative numbers to large positive numbers
- try {
- error = boost::lexical_cast<uint32_t>(error_txt);
- } catch (const boost::bad_lexical_cast&) {
- isc_throw(InvalidRdataText, "Invalid TSIG Error");
- }
- if (error > 0xffff) {
- isc_throw(InvalidRdataText, "TSIG Error out of range");
- }
- }
-
- const uint32_t otherlen =
- lexer.getNextToken(MasterToken::NUMBER).getNumber();
- if (otherlen > 0xffff) {
- isc_throw(InvalidRdataText, "TSIG Other Len out of range");
- }
- const string otherdata_txt = (otherlen > 0) ?
- lexer.getNextToken(MasterToken::STRING).getString() : "";
- vector<uint8_t> other_data;
- decodeBase64(otherdata_txt, other_data);
- if (other_data.size() != otherlen) {
- isc_throw(InvalidRdataText,
- "TSIG Other Data length does not match Other Len");
- }
- // RFC2845 says Other Data is "empty unless Error == BADTIME".
- // However, we don't enforce that.
-
- return (boost::shared_ptr<TSIGImpl>(new TSIGImpl(canonical_algorithm_name,
- time_signed, fudge, mac,
- orig_id, error, other_data)));
-}
-
-/// \brief Constructor from string.
-///
-/// The given string must represent a valid TSIG RDATA. There can be extra
-/// space characters at the beginning or end of the text (which are simply
-/// ignored), but other extra text, including a new line, will make the
-/// construction fail with an exception.
-///
-/// \c tsig_str must be formatted as follows:
-/// \code <Algorithm Name> <Time Signed> <Fudge> <MAC Size> [<MAC>]
-/// <Original ID> <Error> <Other Len> [<Other Data>]
-/// \endcode
-///
-/// Note that, since the Algorithm Name field is defined to be "in domain name
-/// syntax", but it is not actually a domain name, it does not have to be
-/// fully qualified.
-///
-/// The Error field is an unsigned 16-bit decimal integer or a valid mnemonic
-/// as specified in RFC2845. Currently, "NOERROR", "BADSIG", "BADKEY", and
-/// "BADTIME" are supported (case sensitive). In future versions other
-/// representations that are compatible with the DNS RCODE may be supported.
-///
-/// The MAC and Other Data fields are base-64 encoded strings that do not
-/// contain space characters.
-/// If the MAC Size field is 0, the MAC field must not appear in \c tsig_str.
-/// If the Other Len field is 0, the Other Data field must not appear in
-/// \c tsig_str.
-/// The decoded data of the MAC field is MAC Size bytes of binary stream.
-/// The decoded data of the Other Data field is Other Len bytes of binary
-/// stream.
-///
-/// An example of valid string is:
-/// \code "hmac-sha256. 853804800 300 3 AAAA 2845 0 0" \endcode
-/// In this example Other Data is missing because Other Len is 0.
-///
-/// Note that RFC2845 does not define the standard presentation format
-/// of %TSIG RR, so the above syntax is implementation specific.
-/// This is, however, compatible with the format acceptable to BIND 9's
-/// RDATA parser.
-///
-/// \throw Others Exception from the Name constructors.
-/// \throw InvalidRdataText if any fields are out of their valid range,
-/// or are incorrect.
-/// \throw BadValue if MAC or Other Data is not validly encoded in base-64.
-///
-/// \param tsig_str A string containing the RDATA to be created
-TSIG::TSIG(const std::string& tsig_str) : impl_(NULL) {
- // We use unique_ptr here because if there is an exception in this
- // constructor, the destructor is not called and there could be a
- // leak of the TSIGImpl that constructFromLexer() returns.
- boost::shared_ptr<TSIGImpl> impl_ptr;
-
- try {
- std::istringstream ss(tsig_str);
- MasterLexer lexer;
- lexer.pushSource(ss);
-
- impl_ptr.reset(constructFromLexer(lexer, NULL));
-
- if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
- isc_throw(InvalidRdataText,
- "Extra input text for TSIG: " << tsig_str);
- }
- } catch (const MasterLexer::LexerError& ex) {
- isc_throw(InvalidRdataText,
- "Failed to construct TSIG from '" << tsig_str << "': "
- << ex.what());
- }
-
- impl_ = impl_ptr;
-}
-
-/// \brief Constructor with a context of MasterLexer.
-///
-/// The \c lexer should point to the beginning of valid textual
-/// representation of an TSIG RDATA.
-///
-/// See \c TSIG::TSIG(const std::string&) for description of the
-/// expected RDATA fields.
-///
-/// \throw MasterLexer::LexerError General parsing error such as
-/// missing field.
-/// \throw InvalidRdataText if any fields are out of their valid range,
-/// or are incorrect.
-///
-/// \param lexer A \c MasterLexer object parsing a master file for the
-/// RDATA to be created
-TSIG::TSIG(MasterLexer& lexer, const Name* origin,
- MasterLoader::Options, MasterLoaderCallbacks&) :
- impl_(constructFromLexer(lexer, origin)) {
-}
-
-/// \brief Constructor from wire-format data.
-///
-/// When a read operation on \c buffer fails (e.g., due to a corrupted
-/// message) a corresponding exception from the \c InputBuffer class will
-/// be thrown.
-/// If the wire-format data does not begin with a valid domain name,
-/// a corresponding exception from the \c Name class will be thrown.
-/// In addition, this constructor internally involves resource allocation,
-/// and if it fails a corresponding standard exception will be thrown.
-///
-/// According to RFC3597, the Algorithm field must be a non compressed form
-/// of domain name. But this implementation accepts a %TSIG RR even if that
-/// field is compressed.
-///
-/// \param buffer A buffer storing the wire format data.
-/// \param rdata_len The length of the RDATA in bytes, normally expected
-/// to be the value of the RDLENGTH field of the corresponding RR.
-/// But this constructor does not use this parameter; if necessary, the caller
-/// must check consistency between the length parameter and the actual
-/// RDATA length.
-TSIG::TSIG(InputBuffer& buffer, size_t) :
- impl_(NULL) {
- Name algorithm(buffer);
-
- uint8_t time_signed_buf[6];
- buffer.readData(time_signed_buf, sizeof(time_signed_buf));
- const uint64_t time_signed =
- (static_cast<uint64_t>(time_signed_buf[0]) << 40 |
- static_cast<uint64_t>(time_signed_buf[1]) << 32 |
- static_cast<uint64_t>(time_signed_buf[2]) << 24 |
- static_cast<uint64_t>(time_signed_buf[3]) << 16 |
- static_cast<uint64_t>(time_signed_buf[4]) << 8 |
- static_cast<uint64_t>(time_signed_buf[5]));
-
- const uint16_t fudge = buffer.readUint16();
-
- const uint16_t mac_size = buffer.readUint16();
- vector<uint8_t> mac(mac_size);
- if (mac_size > 0) {
- buffer.readData(&mac[0], mac_size);
- }
-
- const uint16_t original_id = buffer.readUint16();
- const uint16_t error = buffer.readUint16();
-
- const uint16_t other_len = buffer.readUint16();
- vector<uint8_t> other_data(other_len);
- if (other_len > 0) {
- buffer.readData(&other_data[0], other_len);
- }
-
- const Name& canonical_algorithm_name =
- (algorithm == TSIGKey::HMACMD5_SHORT_NAME()) ?
- TSIGKey::HMACMD5_NAME() : algorithm;
- impl_.reset(new TSIGImpl(canonical_algorithm_name, time_signed, fudge, mac,
- original_id, error, other_data));
-}
-
-TSIG::TSIG(const Name& algorithm, uint64_t time_signed, uint16_t fudge,
- uint16_t mac_size, const void* mac, uint16_t original_id,
- uint16_t error, uint16_t other_len, const void* other_data) :
- impl_(NULL) {
- // Time Signed is a 48-bit value.
- if ((time_signed >> 48) != 0) {
- isc_throw(OutOfRange, "TSIG Time Signed is too large: " <<
- time_signed);
- }
- if ((mac_size == 0 && mac != NULL) || (mac_size > 0 && mac == NULL)) {
- isc_throw(InvalidParameter, "TSIG MAC size and data inconsistent");
- }
- if ((other_len == 0 && other_data != NULL) ||
- (other_len > 0 && other_data == NULL)) {
- isc_throw(InvalidParameter,
- "TSIG Other data length and data inconsistent");
- }
- const Name& canonical_algorithm_name =
- (algorithm == TSIGKey::HMACMD5_SHORT_NAME()) ?
- TSIGKey::HMACMD5_NAME() : algorithm;
- impl_.reset(new TSIGImpl(canonical_algorithm_name, time_signed, fudge, mac_size,
- mac, original_id, error, other_len, other_data));
-}
-
-/// \brief The copy constructor.
-///
-/// It internally allocates a resource, and if it fails a corresponding
-/// standard exception will be thrown.
-/// This constructor never throws an exception otherwise.
-TSIG::TSIG(const TSIG& source) : Rdata(), impl_(new TSIGImpl(*source.impl_)) {
-}
-
-TSIG&
-TSIG::operator=(const TSIG& source) {
- if (this == &source) {
- return (*this);
- }
-
- impl_.reset(new TSIGImpl(*source.impl_));
-
- return (*this);
-}
-
-TSIG::~TSIG() {
-}
-
-/// \brief Convert the \c TSIG to a string.
-///
-/// The output of this method is formatted as described in the "from string"
-/// constructor (\c TSIG(const std::string&))).
-///
-/// If internal resource allocation fails, a corresponding
-/// standard exception will be thrown.
-///
-/// \return A \c string object that represents the \c TSIG object.
-std::string
-TSIG::toText() const {
- string result;
-
- result += impl_->algorithm_.toText() + " " +
- lexical_cast<string>(impl_->time_signed_) + " " +
- lexical_cast<string>(impl_->fudge_) + " " +
- lexical_cast<string>(impl_->mac_.size()) + " ";
- if (!impl_->mac_.empty()) {
- result += encodeBase64(impl_->mac_) + " ";
- }
- result += lexical_cast<string>(impl_->original_id_) + " ";
- result += TSIGError(impl_->error_).toText() + " ";
- result += lexical_cast<string>(impl_->other_data_.size());
- if (!impl_->other_data_.empty()) {
- result += " " + encodeBase64(impl_->other_data_);
- }
-
- return (result);
-}
-
-// Common sequence of toWire() operations used for the two versions of
-// toWire().
-template <typename Output>
-void
-TSIGImpl::toWireCommon(Output& output) const {
- output.writeUint16(time_signed_ >> 32);
- output.writeUint32(time_signed_ & 0xffffffff);
- output.writeUint16(fudge_);
- const uint16_t mac_size = mac_.size();
- output.writeUint16(mac_size);
- if (mac_size > 0) {
- output.writeData(&mac_[0], mac_size);
- }
- output.writeUint16(original_id_);
- output.writeUint16(error_);
- const uint16_t other_len = other_data_.size();
- output.writeUint16(other_len);
- if (other_len > 0) {
- output.writeData(&other_data_[0], other_len);
- }
-}
-
-/// \brief Render the \c TSIG in the wire format without name compression.
-///
-/// If internal resource allocation fails, a corresponding
-/// standard exception will be thrown.
-/// This method never throws an exception otherwise.
-///
-/// \param buffer An output buffer to store the wire data.
-void
-TSIG::toWire(OutputBuffer& buffer) const {
- impl_->algorithm_.toWire(buffer);
- impl_->toWireCommon<OutputBuffer>(buffer);
-}
-
-/// \brief Render the \c TSIG in the wire format with taking into account
-/// compression.
-///
-/// As specified in RFC3597, the Algorithm field (a domain name) will not
-/// be compressed. However, the domain name could be a target of compression
-/// of other compressible names (though pretty unlikely), the offset
-/// information of the algorithm name may be recorded in \c renderer.
-///
-/// If internal resource allocation fails, a corresponding
-/// standard exception will be thrown.
-/// This method never throws an exception otherwise.
-///
-/// \param renderer DNS message rendering context that encapsulates the
-/// output buffer and name compression information.
-void
-TSIG::toWire(AbstractMessageRenderer& renderer) const {
- renderer.writeName(impl_->algorithm_, false);
- impl_->toWireCommon<AbstractMessageRenderer>(renderer);
-}
-
-// A helper function commonly used for TSIG::compare().
-int
-vectorComp(const vector<uint8_t>& v1, const vector<uint8_t>& v2) {
- const size_t this_size = v1.size();
- const size_t other_size = v2.size();
- if (this_size != other_size) {
- return (this_size < other_size ? -1 : 1);
- }
- if (this_size > 0) {
- return (memcmp(&v1[0], &v2[0], this_size));
- }
- return (0);
-}
-
-/// \brief Compare two instances of \c TSIG RDATA.
-///
-/// This method compares \c this and the \c other \c TSIG objects
-/// in terms of the DNSSEC sorting order as defined in RFC4034, and returns
-/// the result as an integer.
-///
-/// This method is expected to be used in a polymorphic way, and the
-/// parameter to compare against is therefore of the abstract \c Rdata class.
-/// However, comparing two \c Rdata objects of different RR types
-/// is meaningless, and \c other must point to a \c TSIG object;
-/// otherwise, the standard \c bad_cast exception will be thrown.
-/// This method never throws an exception otherwise.
-///
-/// \param other the right-hand operand to compare against.
-/// \return < 0 if \c this would be sorted before \c other.
-/// \return 0 if \c this is identical to \c other in terms of sorting order.
-/// \return > 0 if \c this would be sorted after \c other.
-int
-TSIG::compare(const Rdata& other) const {
- const TSIG& other_tsig = dynamic_cast<const TSIG&>(other);
-
- const int ncmp = compareNames(impl_->algorithm_,
- other_tsig.impl_->algorithm_);
- if (ncmp != 0) {
- return (ncmp);
- }
-
- if (impl_->time_signed_ != other_tsig.impl_->time_signed_) {
- return (impl_->time_signed_ < other_tsig.impl_->time_signed_ ? -1 : 1);
- }
- if (impl_->fudge_ != other_tsig.impl_->fudge_) {
- return (impl_->fudge_ < other_tsig.impl_->fudge_ ? -1 : 1);
- }
- const int vcmp = vectorComp(impl_->mac_, other_tsig.impl_->mac_);
- if (vcmp != 0) {
- return (vcmp);
- }
- if (impl_->original_id_ != other_tsig.impl_->original_id_) {
- return (impl_->original_id_ < other_tsig.impl_->original_id_ ? -1 : 1);
- }
- if (impl_->error_ != other_tsig.impl_->error_) {
- return (impl_->error_ < other_tsig.impl_->error_ ? -1 : 1);
- }
- return (vectorComp(impl_->other_data_, other_tsig.impl_->other_data_));
-}
-
-const Name&
-TSIG::getAlgorithm() const {
- return (impl_->algorithm_);
-}
-
-uint64_t
-TSIG::getTimeSigned() const {
- return (impl_->time_signed_);
-}
-
-uint16_t
-TSIG::getFudge() const {
- return (impl_->fudge_);
-}
-
-uint16_t
-TSIG::getMACSize() const {
- return (impl_->mac_.size());
-}
-
-const void*
-TSIG::getMAC() const {
- if (!impl_->mac_.empty()) {
- return (&impl_->mac_[0]);
- } else {
- return (NULL);
- }
-}
-
-uint16_t
-TSIG::getOriginalID() const {
- return (impl_->original_id_);
-}
-
-uint16_t
-TSIG::getError() const {
- return (impl_->error_);
-}
-
-uint16_t
-TSIG::getOtherLen() const {
- return (impl_->other_data_.size());
-}
-
-const void*
-TSIG::getOtherData() const {
- if (!impl_->other_data_.empty()) {
- return (&impl_->other_data_[0]);
- } else {
- return (NULL);
- }
-}
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/any_255/tsig_250.h b/src/lib/dns/rdata/any_255/tsig_250.h
deleted file mode 100644
index 826cdbca54..0000000000
--- a/src/lib/dns/rdata/any_255/tsig_250.h
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-// BEGIN_HEADER_GUARD
-
-#include <stdint.h>
-
-#include <string>
-
-#include <util/buffer.h>
-#include <dns/name.h>
-#include <dns/rdata.h>
-#include <boost/shared_ptr.hpp>
-
-// BEGIN_ISC_NAMESPACE
-
-// BEGIN_COMMON_DECLARATIONS
-// END_COMMON_DECLARATIONS
-
-// BEGIN_RDATA_NAMESPACE
-
-struct TSIGImpl;
-
-/// \brief \c rdata::TSIG class represents the TSIG RDATA as defined %in
-/// RFC2845.
-///
-/// This class implements the basic interfaces inherited from the abstract
-/// \c rdata::Rdata class, and provides trivial accessors specific to the
-/// TSIG RDATA.
-class TSIG : public Rdata {
-public:
- // BEGIN_COMMON_MEMBERS
- // END_COMMON_MEMBERS
-
- /// \brief Constructor from RDATA field parameters.
- ///
- /// The parameters are a straightforward mapping of %TSIG RDATA
- /// fields as defined %in RFC2845, but there are some implementation
- /// specific notes as follows.
- ///
- /// \c algorithm is a \c Name object that specifies the algorithm.
- /// For example, if the algorithm is HMAC-SHA256, \c algorithm would be
- /// \c Name("hmac-sha256").
- ///
- /// \c time_signed corresponds to the Time Signed field, which is of
- /// 48-bit unsigned integer type, and therefore cannot exceed 2^48-1;
- /// otherwise, an exception of type \c OutOfRange will be thrown.
- ///
- /// \c mac_size and \c mac correspond to the MAC Size and MAC fields,
- /// respectively. When the MAC field is empty, \c mac must be NULL.
- /// \c mac_size and \c mac must be consistent %in that \c mac_size is 0 if
- /// and only if \c mac is NULL; otherwise an exception of type
- /// InvalidParameter will be thrown.
- ///
- /// The same restriction applies to \c other_len and \c other_data,
- /// which correspond to the Other Len and Other Data fields, respectively.
- ///
- /// This constructor internally involves resource allocation, and if
- /// it fails, a corresponding standard exception will be thrown.
- TSIG(const Name& algorithm, uint64_t time_signed, uint16_t fudge,
- uint16_t mac_size, const void* mac, uint16_t original_id,
- uint16_t error, uint16_t other_len, const void* other_data);
-
- /// \brief Assignment operator.
- ///
- /// It internally allocates a resource, and if it fails a corresponding
- /// standard exception will be thrown.
- /// This operator never throws an exception otherwise.
- ///
- /// This operator provides the strong exception guarantee: When an
- /// exception is thrown the content of the assignment target will be
- /// intact.
- TSIG& operator=(const TSIG& source);
-
- /// \brief The destructor.
- ~TSIG();
-
- /// \brief Return the algorithm name.
- ///
- /// This method never throws an exception.
- const Name& getAlgorithm() const;
-
- /// \brief Return the value of the Time Signed field.
- ///
- /// The returned value does not exceed 2^48-1.
- ///
- /// This method never throws an exception.
- uint64_t getTimeSigned() const;
-
- /// \brief Return the value of the Fudge field.
- ///
- /// This method never throws an exception.
- uint16_t getFudge() const;
-
- /// \brief Return the value of the MAC Size field.
- ///
- /// This method never throws an exception.
- uint16_t getMACSize() const;
-
- /// \brief Return the value of the MAC field.
- ///
- /// If the MAC field is empty, it returns NULL.
- /// Otherwise, the memory region beginning at the address returned by
- /// this method is valid up to the bytes specified by the return value
- /// of \c getMACSize().
- /// The memory region is only valid while the corresponding \c TSIG
- /// object is valid. The caller must hold the \c TSIG object while
- /// it needs to refer to the region or it must make a local copy of the
- /// region.
- ///
- /// This method never throws an exception.
- const void* getMAC() const;
-
- /// \brief Return the value of the Original ID field.
- ///
- /// This method never throws an exception.
- uint16_t getOriginalID() const;
-
- /// \brief Return the value of the Error field.
- ///
- /// This method never throws an exception.
- uint16_t getError() const;
-
- /// \brief Return the value of the Other Len field.
- ///
- /// This method never throws an exception.
- uint16_t getOtherLen() const;
-
- /// \brief Return the value of the Other Data field.
- ///
- /// The same note as \c getMAC() applies.
- ///
- /// This method never throws an exception.
- const void* getOtherData() const;
-private:
- boost::shared_ptr<TSIGImpl> constructFromLexer(MasterLexer& lexer, const Name* origin);
-
- boost::shared_ptr<TSIGImpl> impl_;
-};
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
-// END_HEADER_GUARD
diff --git a/src/lib/dns/rdata/generic/detail/.gitignore b/src/lib/dns/rdata/generic/detail/.gitignore
deleted file mode 100644
index c83c0130e8..0000000000
--- a/src/lib/dns/rdata/generic/detail/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/.dirstamp
diff --git a/src/lib/dns/rdata/generic/detail/lexer_util.h b/src/lib/dns/rdata/generic/detail/lexer_util.h
deleted file mode 100644
index 4e3d120c2a..0000000000
--- a/src/lib/dns/rdata/generic/detail/lexer_util.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef DNS_RDATA_LEXER_UTIL_H
-#define DNS_RDATA_LEXER_UTIL_H
-
-#include <dns/name.h>
-#include <dns/master_lexer.h>
-
-/// \file lexer_util.h
-/// \brief Utilities for extracting RDATA fields from lexer.
-///
-/// This file intends to define convenient small routines that can be
-/// commonly used in the RDATA implementation to build RDATA fields from
-/// a \c MasterLexer.
-
-namespace isc {
-namespace dns {
-namespace rdata {
-namespace generic {
-namespace detail {
-
-/// \brief Construct a Name object using a master lexer and optional origin.
-///
-/// This is a convenient shortcut of commonly used code pattern that would
-/// be used to build RDATA that contain a domain name field.
-///
-/// Note that this function throws an exception against invalid input.
-/// The (direct or indirect) caller's responsibility needs to expect and
-/// handle exceptions appropriately.
-///
-/// \throw MasterLexer::LexerError The next token from lexer is not string.
-/// \throw Other Exceptions from the \c Name class constructor if the next
-/// string token from the lexer does not represent a valid name.
-///
-/// \param lexer A \c MasterLexer object. Its next token is expected to be
-/// a string that represent a domain name.
-/// \param origin If non NULL, specifies the origin of the name to be
-/// constructed.
-///
-/// \return A new Name object that corresponds to the next string token of
-/// the \c lexer.
-inline Name
-createNameFromLexer(MasterLexer& lexer, const Name* origin) {
- const MasterToken::StringRegion& str_region =
- lexer.getNextToken(MasterToken::STRING).getStringRegion();
- return (Name(str_region.beg, str_region.len, origin));
-}
-
-} // namespace detail
-} // namespace generic
-} // namespace rdata
-} // namespace dns
-} // namespace isc
-#endif // DNS_RDATA_LEXER_UTIL_H
diff --git a/src/lib/dns/rdata/generic/opt_41.cc b/src/lib/dns/rdata/generic/opt_41.cc
deleted file mode 100644
index c382955904..0000000000
--- a/src/lib/dns/rdata/generic/opt_41.cc
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <util/buffer.h>
-#include <dns/messagerenderer.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-
-#include <string>
-#include <string.h>
-
-using namespace std;
-using namespace isc::util;
-
-// BEGIN_ISC_NAMESPACE
-// BEGIN_RDATA_NAMESPACE
-
-/// \brief Constructor.
-OPT::PseudoRR::PseudoRR(uint16_t code,
- boost::shared_ptr<std::vector<uint8_t> >& data) :
- code_(code),
- data_(data) {
-}
-
-uint16_t
-OPT::PseudoRR::getCode() const {
- return (code_);
-}
-
-const uint8_t*
-OPT::PseudoRR::getData() const {
- return (&(*data_)[0]);
-}
-
-uint16_t
-OPT::PseudoRR::getLength() const {
- return (data_->size());
-}
-
-struct OPTImpl {
- OPTImpl() :
- rdlength_(0) {
- }
-
- uint16_t rdlength_;
- std::vector<OPT::PseudoRR> pseudo_rrs_;
-};
-
-/// \brief Default constructor.
-OPT::OPT() :
- impl_(new OPTImpl()) {
-}
-
-/// \brief Constructor from string.
-///
-/// This constructor cannot be used, and always throws an exception.
-///
-/// \throw InvalidRdataText OPT RR cannot be constructed from text.
-OPT::OPT(const std::string&) :
- impl_(NULL) {
- isc_throw(InvalidRdataText, "OPT RR cannot be constructed from text");
-}
-
-/// \brief Constructor with a context of MasterLexer.
-///
-/// This constructor cannot be used, and always throws an exception.
-///
-/// \throw InvalidRdataText OPT RR cannot be constructed from text.
-OPT::OPT(MasterLexer&, const Name*,
- MasterLoader::Options, MasterLoaderCallbacks&) :
- impl_(NULL) {
- isc_throw(InvalidRdataText, "OPT RR cannot be constructed from text");
-}
-
-OPT::OPT(InputBuffer& buffer, size_t rdata_len) :
- impl_(NULL) {
- boost::shared_ptr<OPTImpl> impl_ptr(new OPTImpl());
-
- while (true) {
- if (rdata_len == 0) {
- break;
- }
-
- if (rdata_len < 4) {
- isc_throw(InvalidRdataLength,
- "Pseudo OPT RR record too short: "
- << rdata_len << " bytes");
- }
-
- const uint16_t option_code = buffer.readUint16();
- const uint16_t option_length = buffer.readUint16();
- rdata_len -= 4;
-
- if (static_cast<uint16_t>(impl_ptr->rdlength_ + option_length) <
- impl_ptr->rdlength_) {
- isc_throw(InvalidRdataText,
- "Option length " << option_length
- << " would overflow OPT RR RDLEN (currently "
- << impl_ptr->rdlength_ << ").");
- }
-
- if (rdata_len < option_length) {
- isc_throw(InvalidRdataLength, "Corrupt pseudo OPT RR record");
- }
-
- boost::shared_ptr<std::vector<uint8_t> >
- option_data(new std::vector<uint8_t>(option_length));
- buffer.readData(&(*option_data)[0], option_length);
- impl_ptr->pseudo_rrs_.push_back(PseudoRR(option_code, option_data));
- impl_ptr->rdlength_ += option_length;
- rdata_len -= option_length;
- }
-
- impl_ = impl_ptr;
-}
-
-OPT::OPT(const OPT& other) :
- Rdata(), impl_(new OPTImpl(*other.impl_)) {
-}
-
-OPT&
-OPT::operator=(const OPT& source) {
- if (this == &source) {
- return (*this);
- }
-
- OPTImpl* newimpl = new OPTImpl(*source.impl_);
- impl_ = newimpl;
-
- return (*this);
-}
-
-OPT::~OPT() {
-}
-
-std::string
-OPT::toText() const {
- isc_throw(isc::InvalidOperation,
- "OPT RRs do not have a presentation format");
-}
-
-void
-OPT::toWire(OutputBuffer& buffer) const {
- for (auto const& pseudo_rr : impl_->pseudo_rrs_) {
- buffer.writeUint16(pseudo_rr.getCode());
- const uint16_t length = pseudo_rr.getLength();
- buffer.writeUint16(length);
- if (length > 0) {
- buffer.writeData(pseudo_rr.getData(), length);
- }
- }
-}
-
-void
-OPT::toWire(AbstractMessageRenderer& renderer) const {
- for (auto const& pseudo_rr : impl_->pseudo_rrs_) {
- renderer.writeUint16(pseudo_rr.getCode());
- const uint16_t length = pseudo_rr.getLength();
- renderer.writeUint16(length);
- if (length > 0) {
- renderer.writeData(pseudo_rr.getData(), length);
- }
- }
-}
-
-int
-OPT::compare(const Rdata&) const {
- isc_throw(isc::InvalidOperation,
- "It is meaningless to compare a set of OPT pseudo RRs; "
- "they have unspecified order");
- return (0);
-}
-
-void
-OPT::appendPseudoRR(uint16_t code, const uint8_t* data, uint16_t length) {
- // See if it overflows 16-bit length field. We only worry about the
- // pseudo-RR length here, not the whole message length (which should
- // be checked and enforced elsewhere).
- if (static_cast<uint16_t>(impl_->rdlength_ + length) <
- impl_->rdlength_) {
- isc_throw(isc::InvalidParameter,
- "Option length " << length
- << " would overflow OPT RR RDLEN (currently "
- << impl_->rdlength_ << ").");
- }
-
- boost::shared_ptr<std::vector<uint8_t> >
- option_data(new std::vector<uint8_t>(length));
- if (length != 0) {
- std::memcpy(&(*option_data)[0], data, length);
- }
- impl_->pseudo_rrs_.push_back(PseudoRR(code, option_data));
- impl_->rdlength_ += length;
-}
-
-const std::vector<OPT::PseudoRR>&
-OPT::getPseudoRRs() const {
- return (impl_->pseudo_rrs_);
-}
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/opt_41.h b/src/lib/dns/rdata/generic/opt_41.h
deleted file mode 100644
index e2d3ccb516..0000000000
--- a/src/lib/dns/rdata/generic/opt_41.h
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-// BEGIN_HEADER_GUARD
-
-#include <string>
-
-#include <dns/rdata.h>
-
-#include <boost/shared_ptr.hpp>
-
-#include <vector>
-
-// BEGIN_ISC_NAMESPACE
-
-// BEGIN_COMMON_DECLARATIONS
-// END_COMMON_DECLARATIONS
-
-// BEGIN_RDATA_NAMESPACE
-
-struct OPTImpl;
-
-class OPT : public Rdata {
-public:
- // BEGIN_COMMON_MEMBERS
- // END_COMMON_MEMBERS
-
- // The default constructor makes sense for OPT as it can be empty.
- OPT();
- OPT& operator=(const OPT& source);
- ~OPT();
-
- /// \brief A class representing a pseudo RR (or option) within an
- /// OPT RR (see RFC 6891).
- class PseudoRR {
- public:
- /// \brief Constructor.
- /// \param code The OPTION-CODE field of the pseudo RR.
- /// \param data The OPTION-DATA field of the pseudo
- /// RR. OPTION-LENGTH is set to the length of this vector.
- PseudoRR(uint16_t code,
- boost::shared_ptr<std::vector<uint8_t> >& data);
-
- /// \brief Return the option code of this pseudo RR.
- uint16_t getCode() const;
-
- /// \brief Return the option data of this pseudo RR.
- const uint8_t* getData() const;
-
- /// \brief Return the length of the option data of this
- /// pseudo RR.
- uint16_t getLength() const;
-
- private:
- uint16_t code_;
- boost::shared_ptr<std::vector<uint8_t> > data_;
- };
-
- /// \brief Append a pseudo RR (option) in this OPT RR.
- ///
- /// \param code The OPTION-CODE field of the pseudo RR.
- /// \param data The OPTION-DATA field of the pseudo RR.
- /// \param length The size of the \c data argument. OPTION-LENGTH is
- /// set to this size.
- /// \throw isc::InvalidParameter if this pseudo RR would cause
- /// the OPT RDATA to overflow its RDLENGTH.
- void appendPseudoRR(uint16_t code, const uint8_t* data, uint16_t length);
-
- /// \brief Return a vector of the pseudo RRs (options) in this
- /// OPT RR.
- ///
- /// Note: The returned reference is only valid during the lifetime
- /// of this \c generic::OPT object. It should not be used
- /// afterwards.
- const std::vector<PseudoRR>& getPseudoRRs() const;
-
-private:
- boost::shared_ptr<OPTImpl> impl_;
-};
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
-// END_HEADER_GUARD
-
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/lib/dns/rdata/generic/ptr_12.cc b/src/lib/dns/rdata/generic/ptr_12.cc
deleted file mode 100644
index d33a6d8a45..0000000000
--- a/src/lib/dns/rdata/generic/ptr_12.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <string>
-
-#include <util/buffer.h>
-#include <dns/name.h>
-#include <dns/messagerenderer.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-
-#include <dns/rdata/generic/detail/lexer_util.h>
-
-using namespace std;
-using namespace isc::util;
-using isc::dns::rdata::generic::detail::createNameFromLexer;
-
-// BEGIN_ISC_NAMESPACE
-// BEGIN_RDATA_NAMESPACE
-
-/// \brief Constructor from string.
-///
-/// The given string must represent a valid PTR RDATA. There can be
-/// extra space characters at the beginning or end of the text (which
-/// are simply ignored), but other extra text, including a new line,
-/// will make the construction fail with an exception.
-///
-/// The PTRDNAME must be absolute since there's no parameter that
-/// specifies the origin name; if it is not absolute, \c
-/// MissingNameOrigin exception will be thrown. These must not be
-/// represented as a quoted string.
-///
-/// \throw Others Exception from the Name and RRTTL constructors.
-/// \throw InvalidRdataText Other general syntax errors.
-PTR::PTR(const std::string& type_str) :
- // Fill in dummy name and replace them soon below.
- ptr_name_(Name::ROOT_NAME()) {
- try {
- std::istringstream ss(type_str);
- MasterLexer lexer;
- lexer.pushSource(ss);
-
- ptr_name_ = createNameFromLexer(lexer, NULL);
-
- if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
- isc_throw(InvalidRdataText, "extra input text for PTR: "
- << type_str);
- }
- } catch (const MasterLexer::LexerError& ex) {
- isc_throw(InvalidRdataText, "Failed to construct PTR from '" <<
- type_str << "': " << ex.what());
- }
-}
-
-PTR::PTR(InputBuffer& buffer, size_t) :
- ptr_name_(buffer) {
- // we don't need rdata_len for parsing. if necessary, the caller will
- // check consistency.
-}
-
-/// \brief Constructor with a context of MasterLexer.
-///
-/// The \c lexer should point to the beginning of valid textual
-/// representation of a PTR RDATA. The PTRDNAME field can be
-/// non-absolute if \c origin is non-NULL, in which case \c origin is
-/// used to make it absolute. It must not be represented as a quoted
-/// string.
-///
-/// \throw MasterLexer::LexerError General parsing error such as missing field.
-/// \throw Other Exceptions from the Name and RRTTL constructors if
-/// construction of textual fields as these objects fail.
-///
-/// \param lexer A \c MasterLexer object parsing a master file for the
-/// RDATA to be created
-/// \param origin If non NULL, specifies the origin of PTRDNAME when it
-/// is non-absolute.
-PTR::PTR(MasterLexer& lexer, const Name* origin,
- MasterLoader::Options, MasterLoaderCallbacks&) :
- ptr_name_(createNameFromLexer(lexer, origin)) {
-}
-
-PTR::PTR(const PTR& source) :
- Rdata(), ptr_name_(source.ptr_name_) {
-}
-
-std::string
-PTR::toText() const {
- return (ptr_name_.toText());
-}
-
-void
-PTR::toWire(OutputBuffer& buffer) const {
- ptr_name_.toWire(buffer);
-}
-
-void
-PTR::toWire(AbstractMessageRenderer& renderer) const {
- renderer.writeName(ptr_name_);
-}
-
-int
-PTR::compare(const Rdata& other) const {
- // The compare method normally begins with this dynamic cast.
- const PTR& other_ptr = dynamic_cast<const PTR&>(other);
-
- return (compareNames(ptr_name_, other_ptr.ptr_name_));
-}
-
-const Name&
-PTR::getPTRName() const {
- return (ptr_name_);
-}
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/ptr_12.h b/src/lib/dns/rdata/generic/ptr_12.h
deleted file mode 100644
index 101d60c263..0000000000
--- a/src/lib/dns/rdata/generic/ptr_12.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-// BEGIN_HEADER_GUARD
-
-#include <string>
-
-#include <dns/name.h>
-#include <dns/rdata.h>
-
-// BEGIN_ISC_NAMESPACE
-
-// BEGIN_COMMON_DECLARATIONS
-// END_COMMON_DECLARATIONS
-
-// BEGIN_RDATA_NAMESPACE
-
-class PTR : public Rdata {
-public:
- // BEGIN_COMMON_MEMBERS
- // END_COMMON_MEMBERS
-
- ///
- /// Specialized constructor
- ///
- explicit PTR(const Name& ptr_name) : ptr_name_(ptr_name) {
- }
- ///
- /// Specialized methods
- ///
- const Name& getPTRName() const;
-private:
- Name ptr_name_;
-};
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
-// END_HEADER_GUARD
diff --git a/src/lib/dns/rdata/generic/rrsig_46.cc b/src/lib/dns/rdata/generic/rrsig_46.cc
deleted file mode 100644
index 94d62f5e16..0000000000
--- a/src/lib/dns/rdata/generic/rrsig_46.cc
+++ /dev/null
@@ -1,329 +0,0 @@
-// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <string>
-#include <iomanip>
-#include <iostream>
-#include <sstream>
-#include <vector>
-
-#include <boost/lexical_cast.hpp>
-
-#include <util/encode/encode.h>
-#include <util/buffer.h>
-#include <util/time_utilities.h>
-#include <dns/messagerenderer.h>
-#include <dns/name.h>
-#include <dns/rrtype.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rdata/generic/detail/lexer_util.h>
-
-#include <stdio.h>
-#include <time.h>
-
-using namespace std;
-using namespace isc::util;
-using namespace isc::util::encode;
-using isc::dns::rdata::generic::detail::createNameFromLexer;
-
-// BEGIN_ISC_NAMESPACE
-// BEGIN_RDATA_NAMESPACE
-
-namespace {
-// This is the minimum necessary length of all wire-format RRSIG RDATA:
-// - two 8-bit fields (algorithm and labels)
-// - two 16-bit fields (covered and tag)
-// - three 32-bit fields (original TTL, expire and inception)
-const size_t RRSIG_MINIMUM_LEN = 2 * sizeof(uint8_t) + 2 * sizeof(uint16_t) +
- 3 * sizeof(uint32_t);
-}
-
-struct RRSIGImpl {
- // straightforward representation of RRSIG RDATA fields
- RRSIGImpl(const RRType& covered, uint8_t algorithm, uint8_t labels,
- uint32_t originalttl, uint32_t timeexpire,
- uint32_t timeinception, uint16_t tag, const Name& signer,
- const vector<uint8_t>& signature) :
- covered_(covered), algorithm_(algorithm), labels_(labels),
- originalttl_(originalttl), timeexpire_(timeexpire),
- timeinception_(timeinception), tag_(tag), signer_(signer),
- signature_(signature) {
- }
-
- const RRType covered_;
- uint8_t algorithm_;
- uint8_t labels_;
- uint32_t originalttl_;
- uint32_t timeexpire_;
- uint32_t timeinception_;
- uint16_t tag_;
- const Name signer_;
- const vector<uint8_t> signature_;
-};
-
-// helper function for string and lexer constructors
-boost::shared_ptr<RRSIGImpl>
-RRSIG::constructFromLexer(MasterLexer& lexer, const Name* origin) {
- const RRType covered(lexer.getNextToken(MasterToken::STRING).getString());
- const uint32_t algorithm =
- lexer.getNextToken(MasterToken::NUMBER).getNumber();
- if (algorithm > 0xff) {
- isc_throw(InvalidRdataText, "RRSIG algorithm out of range");
- }
- const uint32_t labels =
- lexer.getNextToken(MasterToken::NUMBER).getNumber();
- if (labels > 0xff) {
- isc_throw(InvalidRdataText, "RRSIG labels out of range");
- }
- const uint32_t originalttl =
- lexer.getNextToken(MasterToken::NUMBER).getNumber();
- const uint32_t timeexpire =
- timeFromText32(lexer.getNextToken(MasterToken::STRING).getString());
- const uint32_t timeinception =
- timeFromText32(lexer.getNextToken(MasterToken::STRING).getString());
- const uint32_t tag =
- lexer.getNextToken(MasterToken::NUMBER).getNumber();
- if (tag > 0xffff) {
- isc_throw(InvalidRdataText, "RRSIG key tag out of range");
- }
- const Name& signer = createNameFromLexer(lexer, origin);
-
- string signature_txt;
- string signature_part;
- // Whitespace is allowed within base64 text, so read to the end of input.
- while (true) {
- const MasterToken& token =
- lexer.getNextToken(MasterToken::STRING, true);
- if ((token.getType() == MasterToken::END_OF_FILE) ||
- (token.getType() == MasterToken::END_OF_LINE)) {
- break;
- }
- token.getString(signature_part);
- signature_txt.append(signature_part);
- }
- lexer.ungetToken();
-
- vector<uint8_t> signature;
- // missing signature is okay
- if (signature_txt.size() > 0) {
- decodeBase64(signature_txt, signature);
- }
-
- return (boost::shared_ptr<RRSIGImpl>(new RRSIGImpl(covered, algorithm, labels,
- originalttl, timeexpire, timeinception,
- static_cast<uint16_t>(tag), signer, signature)));
-}
-
-/// \brief Constructor from string.
-///
-/// The given string must represent a valid RRSIG RDATA. There can be extra
-/// space characters at the beginning or end of the text (which are simply
-/// ignored), but other extra text, including a new line, will make the
-/// construction fail with an exception.
-///
-/// The Signer's Name must be absolute since there's no parameter that
-/// specifies the origin name; if this is not absolute, \c MissingNameOrigin
-/// exception will be thrown. This must not be represented as a quoted
-/// string.
-///
-/// See the construction that takes \c MasterLexer for other fields.
-///
-/// \throw Others Exception from the Name constructor.
-/// \throw InvalidRdataText Other general syntax errors.
-RRSIG::RRSIG(const std::string& rrsig_str) :
- impl_(NULL) {
- // We use unique_ptr here because if there is an exception in this
- // constructor, the destructor is not called and there could be a
- // leak of the RRSIGImpl that constructFromLexer() returns.
- boost::shared_ptr<RRSIGImpl> impl_ptr;
-
- try {
- std::istringstream iss(rrsig_str);
- MasterLexer lexer;
- lexer.pushSource(iss);
-
- impl_ptr.reset(constructFromLexer(lexer, NULL));
-
- if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
- isc_throw(InvalidRdataText, "extra input text for RRSIG: "
- << rrsig_str);
- }
- } catch (const MasterLexer::LexerError& ex) {
- isc_throw(InvalidRdataText, "Failed to construct RRSIG from '" <<
- rrsig_str << "': " << ex.what());
- }
-
- impl_ = impl_ptr;
-}
-
-/// \brief Constructor with a context of MasterLexer.
-///
-/// The \c lexer should point to the beginning of valid textual representation
-/// of an RRSIG RDATA. The Signer's Name fields can be non absolute if \c
-/// origin is non NULL, in which case \c origin is used to make it absolute.
-/// This must not be represented as a quoted string.
-///
-/// The Original TTL field is a valid decimal representation of an unsigned
-/// 32-bit integer. Note that alternate textual representations of \c RRTTL,
-/// such as "1H" for 3600 seconds, are not allowed here.
-///
-/// \throw MasterLexer::LexerError General parsing error such as missing field.
-/// \throw Other Exceptions from the Name constructor if
-/// construction of textual fields as these objects fail.
-///
-/// \param lexer A \c MasterLexer object parsing a master file for the
-/// RDATA to be created
-/// \param origin If non NULL, specifies the origin of Signer's Name when
-/// it is non absolute.
-RRSIG::RRSIG(MasterLexer& lexer, const Name* origin,
- MasterLoader::Options, MasterLoaderCallbacks&) :
- impl_(constructFromLexer(lexer, origin)) {
-}
-
-RRSIG::RRSIG(InputBuffer& buffer, size_t rdata_len) {
- size_t pos = buffer.getPosition();
-
- if (rdata_len < RRSIG_MINIMUM_LEN) {
- isc_throw(InvalidRdataLength, "RRSIG too short");
- }
-
- RRType covered(buffer);
- uint8_t algorithm = buffer.readUint8();
- uint8_t labels = buffer.readUint8();
- uint32_t originalttl = buffer.readUint32();
- uint32_t timeexpire = buffer.readUint32();
- uint32_t timeinception = buffer.readUint32();
- uint16_t tag = buffer.readUint16();
- Name signer(buffer);
-
- // rdata_len must be sufficiently large to hold non empty signature data.
- if (rdata_len <= buffer.getPosition() - pos) {
- isc_throw(InvalidRdataLength, "RRSIG too short");
- }
- rdata_len -= (buffer.getPosition() - pos);
-
- vector<uint8_t> signature(rdata_len);
- buffer.readData(&signature[0], rdata_len);
-
- impl_.reset(new RRSIGImpl(covered, algorithm, labels,
- originalttl, timeexpire, timeinception, tag,
- signer, signature));
-}
-
-RRSIG::RRSIG(const RRSIG& source) :
- Rdata(), impl_(new RRSIGImpl(*source.impl_)) {
-}
-
-RRSIG&
-RRSIG::operator=(const RRSIG& source) {
- if (this == &source) {
- return (*this);
- }
-
- impl_.reset(new RRSIGImpl(*source.impl_));
-
- return (*this);
-}
-
-RRSIG::~RRSIG() {
-}
-
-string
-RRSIG::toText() const {
- return (impl_->covered_.toText() +
- " " + boost::lexical_cast<string>(static_cast<int>(impl_->algorithm_))
- + " " + boost::lexical_cast<string>(static_cast<int>(impl_->labels_))
- + " " + boost::lexical_cast<string>(impl_->originalttl_)
- + " " + timeToText32(impl_->timeexpire_)
- + " " + timeToText32(impl_->timeinception_)
- + " " + boost::lexical_cast<string>(impl_->tag_)
- + " " + impl_->signer_.toText()
- + " " + encodeBase64(impl_->signature_));
-}
-
-void
-RRSIG::toWire(OutputBuffer& buffer) const {
- impl_->covered_.toWire(buffer);
- buffer.writeUint8(impl_->algorithm_);
- buffer.writeUint8(impl_->labels_);
- buffer.writeUint32(impl_->originalttl_);
- buffer.writeUint32(impl_->timeexpire_);
- buffer.writeUint32(impl_->timeinception_);
- buffer.writeUint16(impl_->tag_);
- impl_->signer_.toWire(buffer);
- buffer.writeData(&impl_->signature_[0], impl_->signature_.size());
-}
-
-void
-RRSIG::toWire(AbstractMessageRenderer& renderer) const {
- impl_->covered_.toWire(renderer);
- renderer.writeUint8(impl_->algorithm_);
- renderer.writeUint8(impl_->labels_);
- renderer.writeUint32(impl_->originalttl_);
- renderer.writeUint32(impl_->timeexpire_);
- renderer.writeUint32(impl_->timeinception_);
- renderer.writeUint16(impl_->tag_);
- renderer.writeName(impl_->signer_, false);
- renderer.writeData(&impl_->signature_[0], impl_->signature_.size());
-}
-
-int
-RRSIG::compare(const Rdata& other) const {
- const RRSIG& other_rrsig = dynamic_cast<const RRSIG&>(other);
-
- if (impl_->covered_.getCode() != other_rrsig.impl_->covered_.getCode()) {
- return (impl_->covered_.getCode() <
- other_rrsig.impl_->covered_.getCode() ? -1 : 1);
- }
- if (impl_->algorithm_ != other_rrsig.impl_->algorithm_) {
- return (impl_->algorithm_ < other_rrsig.impl_->algorithm_ ? -1 : 1);
- }
- if (impl_->labels_ != other_rrsig.impl_->labels_) {
- return (impl_->labels_ < other_rrsig.impl_->labels_ ? -1 : 1);
- }
- if (impl_->originalttl_ != other_rrsig.impl_->originalttl_) {
- return (impl_->originalttl_ < other_rrsig.impl_->originalttl_ ?
- -1 : 1);
- }
- if (impl_->timeexpire_ != other_rrsig.impl_->timeexpire_) {
- return (impl_->timeexpire_ < other_rrsig.impl_->timeexpire_ ?
- -1 : 1);
- }
- if (impl_->timeinception_ != other_rrsig.impl_->timeinception_) {
- return (impl_->timeinception_ < other_rrsig.impl_->timeinception_ ?
- -1 : 1);
- }
- if (impl_->tag_ != other_rrsig.impl_->tag_) {
- return (impl_->tag_ < other_rrsig.impl_->tag_ ? -1 : 1);
- }
-
- int cmp = compareNames(impl_->signer_, other_rrsig.impl_->signer_);
- if (cmp != 0) {
- return (cmp);
- }
-
- size_t this_len = impl_->signature_.size();
- size_t other_len = other_rrsig.impl_->signature_.size();
- size_t cmplen = min(this_len, other_len);
- cmp = memcmp(&impl_->signature_[0], &other_rrsig.impl_->signature_[0],
- cmplen);
- if (cmp != 0) {
- return (cmp);
- } else {
- return ((this_len == other_len) ? 0 : (this_len < other_len) ? -1 : 1);
- }
-}
-
-const RRType&
-RRSIG::typeCovered() const {
- return (impl_->covered_);
-}
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/rrsig_46.h b/src/lib/dns/rdata/generic/rrsig_46.h
deleted file mode 100644
index 8443ad79e8..0000000000
--- a/src/lib/dns/rdata/generic/rrsig_46.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <stdint.h>
-
-#include <string>
-
-#include <dns/name.h>
-#include <dns/rrtype.h>
-#include <dns/rdata.h>
-#include <boost/shared_ptr.hpp>
-
-// BEGIN_HEADER_GUARD
-
-// BEGIN_ISC_NAMESPACE
-
-// BEGIN_COMMON_DECLARATIONS
-// END_COMMON_DECLARATIONS
-
-// BEGIN_RDATA_NAMESPACE
-
-struct RRSIGImpl;
-
-/// \brief \c rdata::RRSIG class represents the RRSIG RDATA as defined %in
-/// RFC4034.
-///
-/// This class implements the basic interfaces inherited from the abstract
-/// \c rdata::Rdata class, and provides trivial accessors specific to the
-/// RRSIG RDATA.
-class RRSIG : public Rdata {
-public:
- // BEGIN_COMMON_MEMBERS
- // END_COMMON_MEMBERS
- RRSIG& operator=(const RRSIG& source);
- ~RRSIG();
-
- // specialized methods
- const RRType& typeCovered() const;
-private:
- // helper function for string and lexer constructors
- boost::shared_ptr<RRSIGImpl> constructFromLexer(MasterLexer& lexer, const Name* origin);
-
- boost::shared_ptr<RRSIGImpl> impl_;
-};
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
-// END_HEADER_GUARD
diff --git a/src/lib/dns/rdata/generic/soa_6.cc b/src/lib/dns/rdata/generic/soa_6.cc
deleted file mode 100644
index 945d4b99cd..0000000000
--- a/src/lib/dns/rdata/generic/soa_6.cc
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <exceptions/exceptions.h>
-
-#include <util/buffer.h>
-#include <dns/name.h>
-#include <dns/master_lexer.h>
-#include <dns/master_loader.h>
-#include <dns/master_loader_callbacks.h>
-#include <dns/messagerenderer.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-
-#include <dns/rdata/generic/detail/lexer_util.h>
-
-#include <boost/static_assert.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include <string>
-#include <sstream>
-
-using namespace std;
-using boost::lexical_cast;
-using namespace isc::util;
-using isc::dns::rdata::generic::detail::createNameFromLexer;
-
-// BEGIN_ISC_NAMESPACE
-// BEGIN_RDATA_NAMESPACE
-
-SOA::SOA(InputBuffer& buffer, size_t) :
- mname_(buffer), rname_(buffer) {
- // we don't need rdata_len for parsing. if necessary, the caller will
- // check consistency.
- buffer.readData(numdata_, sizeof(numdata_));
-}
-
-namespace {
-void
-fillParameters(MasterLexer& lexer, uint8_t numdata[20]) {
- // Copy serial, refresh, retry, expire, minimum. We accept the extended
- // TTL-compatible style for the latter four.
- OutputBuffer buffer(20);
- buffer.writeUint32(lexer.getNextToken(MasterToken::NUMBER).getNumber());
- for (int i = 0; i < 4; ++i) {
- buffer.writeUint32(RRTTL(lexer.getNextToken(MasterToken::STRING).
- getString()).getValue());
- }
- memcpy(numdata, buffer.getData(), buffer.getLength());
-}
-}
-
-/// \brief Constructor from string.
-///
-/// The given string must represent a valid SOA RDATA. There can be extra
-/// space characters at the beginning or end of the text (which are simply
-/// ignored), but other extra text, including a new line, will make the
-/// construction fail with an exception.
-///
-/// The MNAME and RNAME must be absolute since there's no parameter that
-/// specifies the origin name; if these are not absolute, \c MissingNameOrigin
-/// exception will be thrown. These must not be represented as a quoted
-/// string.
-///
-/// See the construction that takes \c MasterLexer for other fields.
-///
-/// \throw Others Exception from the Name and RRTTL constructors.
-/// \throw InvalidRdataText Other general syntax errors.
-SOA::SOA(const std::string& soastr) :
- // Fill in dummy name and replace them soon below.
- mname_(Name::ROOT_NAME()), rname_(Name::ROOT_NAME()) {
- try {
- std::istringstream ss(soastr);
- MasterLexer lexer;
- lexer.pushSource(ss);
-
- mname_ = createNameFromLexer(lexer, NULL);
- rname_ = createNameFromLexer(lexer, NULL);
- fillParameters(lexer, numdata_);
-
- if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
- isc_throw(InvalidRdataText, "extra input text for SOA: "
- << soastr);
- }
- } catch (const MasterLexer::LexerError& ex) {
- isc_throw(InvalidRdataText, "Failed to construct SOA from '" <<
- soastr << "': " << ex.what());
- }
-}
-
-/// \brief Constructor with a context of MasterLexer.
-///
-/// The \c lexer should point to the beginning of valid textual representation
-/// of an SOA RDATA. The MNAME and RNAME fields can be non absolute if
-/// \c origin is non NULL, in which case \c origin is used to make them
-/// absolute. These must not be represented as a quoted string.
-///
-/// The REFRESH, RETRY, EXPIRE, and MINIMUM fields can be either a valid
-/// decimal representation of an unsigned 32-bit integer or other
-/// valid textual representation of \c RRTTL such as "1H" (which means 3600).
-///
-/// \throw MasterLexer::LexerError General parsing error such as missing field.
-/// \throw Other Exceptions from the Name and RRTTL constructors if
-/// construction of textual fields as these objects fail.
-///
-/// \param lexer A \c MasterLexer object parsing a master file for the
-/// RDATA to be created
-/// \param origin If non NULL, specifies the origin of MNAME and RNAME when
-/// they are non absolute.
-SOA::SOA(MasterLexer& lexer, const Name* origin,
- MasterLoader::Options, MasterLoaderCallbacks&) :
- mname_(createNameFromLexer(lexer, origin)),
- rname_(createNameFromLexer(lexer, origin)) {
- fillParameters(lexer, numdata_);
-}
-
-SOA::SOA(const Name& mname, const Name& rname, uint32_t serial,
- uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum) :
- mname_(mname), rname_(rname) {
- OutputBuffer b(20);
- b.writeUint32(serial);
- b.writeUint32(refresh);
- b.writeUint32(retry);
- b.writeUint32(expire);
- b.writeUint32(minimum);
- assert(b.getLength() == sizeof(numdata_));
- memcpy(numdata_, b.getData(), sizeof(numdata_));
-}
-
-SOA::SOA(const SOA& other) :
- Rdata(), mname_(other.mname_), rname_(other.rname_) {
- memcpy(numdata_, other.numdata_, sizeof(numdata_));
-}
-
-void
-SOA::toWire(OutputBuffer& buffer) const {
- mname_.toWire(buffer);
- rname_.toWire(buffer);
- buffer.writeData(numdata_, sizeof(numdata_));
-}
-
-void
-SOA::toWire(AbstractMessageRenderer& renderer) const {
- renderer.writeName(mname_);
- renderer.writeName(rname_);
- renderer.writeData(numdata_, sizeof(numdata_));
-}
-
-Serial
-SOA::getSerial() const {
- InputBuffer b(numdata_, sizeof(numdata_));
- return (Serial(b.readUint32()));
-}
-
-uint32_t
-SOA::getMinimum() const {
- // Make sure the buffer access is safe.
- BOOST_STATIC_ASSERT(sizeof(numdata_) ==
- sizeof(uint32_t) * 4 + sizeof(uint32_t));
-
- InputBuffer b(&numdata_[sizeof(uint32_t) * 4], sizeof(uint32_t));
- return (b.readUint32());
-}
-
-string
-SOA::toText() const {
- InputBuffer b(numdata_, sizeof(numdata_));
- uint32_t serial = b.readUint32();
- uint32_t refresh = b.readUint32();
- uint32_t retry = b.readUint32();
- uint32_t expire = b.readUint32();
- uint32_t minimum = b.readUint32();
-
- return (mname_.toText() + " " + rname_.toText() + " " +
- lexical_cast<string>(serial) + " " +
- lexical_cast<string>(refresh) + " " +
- lexical_cast<string>(retry) + " " +
- lexical_cast<string>(expire) + " " +
- lexical_cast<string>(minimum));
-}
-
-int
-SOA::compare(const Rdata& other) const {
- const SOA& other_soa = dynamic_cast<const SOA&>(other);
-
- int order = compareNames(mname_, other_soa.mname_);
- if (order != 0) {
- return (order);
- }
-
- order = compareNames(rname_, other_soa.rname_);
- if (order != 0) {
- return (order);
- }
-
- return (memcmp(numdata_, other_soa.numdata_, sizeof(numdata_)));
-}
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/soa_6.h b/src/lib/dns/rdata/generic/soa_6.h
deleted file mode 100644
index 509663311f..0000000000
--- a/src/lib/dns/rdata/generic/soa_6.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-// BEGIN_HEADER_GUARD
-
-#include <string>
-
-#include <dns/name.h>
-#include <dns/rdata.h>
-#include <dns/rrttl.h>
-#include <dns/serial.h>
-
-// BEGIN_ISC_NAMESPACE
-
-// BEGIN_COMMON_DECLARATIONS
-// END_COMMON_DECLARATIONS
-
-// BEGIN_RDATA_NAMESPACE
-
-class SOA : public Rdata {
-public:
- // BEGIN_COMMON_MEMBERS
- // END_COMMON_MEMBERS
-
- SOA(const Name& mname, const Name& rname, uint32_t serial,
- uint32_t refresh, uint32_t retry, uint32_t expire,
- uint32_t minimum);
-
- /// \brief Returns the serial stored in the SOA.
- Serial getSerial() const;
-
- /// brief Returns the minimum TTL field value of the SOA.
- uint32_t getMinimum() const;
-private:
- /// Note: this is a prototype version; we may reconsider
- /// this representation later.
- Name mname_;
- Name rname_;
- /// serial, refresh, retry, expire, minimum, stored in network byte order
- uint8_t numdata_[20];
-};
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
-// END_HEADER_GUARD
diff --git a/src/lib/dns/rdata/generic/tkey_249.cc b/src/lib/dns/rdata/generic/tkey_249.cc
deleted file mode 100644
index d12e2c6295..0000000000
--- a/src/lib/dns/rdata/generic/tkey_249.cc
+++ /dev/null
@@ -1,608 +0,0 @@
-// Copyright (C) 2021-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <string>
-#include <sstream>
-#include <vector>
-
-#include <boost/lexical_cast.hpp>
-
-#include <util/buffer.h>
-#include <util/encode/encode.h>
-#include <util/time_utilities.h>
-
-#include <dns/tsigerror.h>
-#include <dns/messagerenderer.h>
-#include <dns/name.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rcode.h>
-#include <dns/rdata/generic/detail/lexer_util.h>
-
-using namespace std;
-using boost::lexical_cast;
-using namespace isc::util;
-using namespace isc::util::encode;
-using namespace isc::dns;
-using isc::dns::rdata::generic::detail::createNameFromLexer;
-
-// BEGIN_ISC_NAMESPACE
-// BEGIN_RDATA_NAMESPACE
-
-const uint16_t TKEY::GSS_API_MODE = 3;
-
-// straightforward representation of TKEY RDATA fields
-struct TKEYImpl {
- /// \brief Constructor from RDATA field parameters.
- ///
- /// \param algorithm The DNS name of the algorithm e.g. gss-tsig.
- /// \param inception The inception time (in seconds since 1970).
- /// \param expire The expire time (in seconds since 1970).
- /// \param mode The mode e.g. Diffie-Hellman (2) or GSS-API (3).
- /// \param error The error code (extended error space shared with TSIG).
- /// \param key The key (can be empty).
- /// \param other_data The other data (can be and usually is empty).
- TKEYImpl(const Name& algorithm, uint32_t inception, uint32_t expire,
- uint16_t mode, uint16_t error, vector<uint8_t>& key,
- vector<uint8_t>& other_data) :
- algorithm_(algorithm), inception_(inception), expire_(expire),
- mode_(mode), error_(error), key_(key), other_data_(other_data) {
- }
-
- /// \brief Constructor from RDATA field parameters.
- ///
- /// \param algorithm The DNS name of the algorithm e.g. gss-tsig.
- /// \param inception The inception time (in seconds since 1970).
- /// \param expire The expire time (in seconds since 1970).
- /// \param mode The mode e.g. Diffie-Hellman (2) or GSS-API (3).
- /// \param error The error code (extended error space shared with TSIG).
- /// \param key_len The key length (0 means no key).
- /// \param key The key (can be 0).
- /// \param other_len The other data length (0 means no other data).
- /// \param other_data The other data (can be and usually is 0).
- TKEYImpl(const Name& algorithm, uint32_t inception, uint32_t expire,
- uint16_t mode, uint16_t error, size_t key_len,
- const void* key, size_t other_len, const void* other_data) :
- algorithm_(algorithm), inception_(inception), expire_(expire),
- mode_(mode), error_(error),
- key_(key_len > 0 ?
- vector<uint8_t>(static_cast<const uint8_t*>(key),
- static_cast<const uint8_t*>(key) + key_len) :
- vector<uint8_t>(key_len)),
- other_data_(other_len > 0 ?
- vector<uint8_t>(static_cast<const uint8_t*>(other_data),
- static_cast<const uint8_t*>(other_data) +
- other_len) :
- vector<uint8_t>(other_len)) {
- }
-
- /// \brief Common part of toWire methods.
- /// \tparam Output \c OutputBuffer or \c AbstractMessageRenderer.
- template <typename Output>
- void toWireCommon(Output& output) const;
-
- /// \brief The DNS name of the algorithm e.g. gss-tsig.
- const Name algorithm_;
-
- /// \brief The inception time (in seconds since 1970).
- const uint32_t inception_;
-
- /// \brief The expire time (in seconds since 1970).
- const uint32_t expire_;
-
- /// \brief The mode e.g. Diffie-Hellman (2) or GSS-API (3).
- const uint16_t mode_;
-
- /// \brief The error code (extended error space shared with TSIG).
- const uint16_t error_;
-
- /// \brief The key (can be empty).
- const vector<uint8_t> key_;
-
- /// \brief The other data (can be and usually is empty).
- const vector<uint8_t> other_data_;
-};
-
-// helper function for string and lexer constructors
-boost::shared_ptr<TKEYImpl>
-TKEY::constructFromLexer(MasterLexer& lexer, const Name* origin) {
- const Name& algorithm =
- createNameFromLexer(lexer, origin ? origin : &Name::ROOT_NAME());
-
- const uint32_t inception =
- timeFromText32(lexer.getNextToken(MasterToken::STRING).getString());
-
- const uint32_t expire =
- timeFromText32(lexer.getNextToken(MasterToken::STRING).getString());
-
- /// The mode is either a mnemonic (only one is defined: GSS-API) or
- /// a number.
- const string& mode_txt =
- lexer.getNextToken(MasterToken::STRING).getString();
- uint32_t mode = 0;
- if (mode_txt == "GSS-API") {
- mode = GSS_API_MODE;
- } else {
- /// we cast to uint32_t and range-check, because casting directly to
- /// uint16_t will convert negative numbers to large positive numbers
- try {
- mode = boost::lexical_cast<uint32_t>(mode_txt);
- } catch (const boost::bad_lexical_cast&) {
- isc_throw(InvalidRdataText, "Invalid TKEY Mode");
- }
- if (mode > 0xffff) {
- isc_throw(InvalidRdataText, "TKEY Mode out of range");
- }
- }
-
- const string& error_txt =
- lexer.getNextToken(MasterToken::STRING).getString();
- uint32_t error = 0;
- // XXX: In the initial implementation we hardcode the mnemonics.
- // We'll soon generalize this.
- if (error_txt == "NOERROR") {
- error = Rcode::NOERROR_CODE;
- } else if (error_txt == "BADSIG") {
- error = TSIGError::BAD_SIG_CODE;
- } else if (error_txt == "BADKEY") {
- error = TSIGError::BAD_KEY_CODE;
- } else if (error_txt == "BADTIME") {
- error = TSIGError::BAD_TIME_CODE;
- } else if (error_txt == "BADMODE") {
- error = TSIGError::BAD_MODE_CODE;
- } else if (error_txt == "BADNAME") {
- error = TSIGError::BAD_NAME_CODE;
- } else if (error_txt == "BADALG") {
- error = TSIGError::BAD_ALG_CODE;
- } else if (error_txt == "BADTRUNC") {
- error = TSIGError::BAD_TRUNC_CODE;
- } else {
- /// we cast to uint32_t and range-check, because casting directly to
- /// uint16_t will convert negative numbers to large positive numbers
- try {
- error = boost::lexical_cast<uint32_t>(error_txt);
- } catch (const boost::bad_lexical_cast&) {
- isc_throw(InvalidRdataText, "Invalid TKEY Error");
- }
- if (error > 0xffff) {
- isc_throw(InvalidRdataText, "TKEY Error out of range");
- }
- }
-
- const uint32_t keylen =
- lexer.getNextToken(MasterToken::NUMBER).getNumber();
- if (keylen > 0xffff) {
- isc_throw(InvalidRdataText, "TKEY Key Len out of range");
- }
- const string keydata_txt = (keylen > 0) ?
- lexer.getNextToken(MasterToken::STRING).getString() : "";
- vector<uint8_t> key_data;
- decodeBase64(keydata_txt, key_data);
- if (key_data.size() != keylen) {
- isc_throw(InvalidRdataText,
- "TKEY Key Data length does not match Other Len");
- }
-
- const uint32_t otherlen =
- lexer.getNextToken(MasterToken::NUMBER).getNumber();
- if (otherlen > 0xffff) {
- isc_throw(InvalidRdataText, "TKEY Other Len out of range");
- }
- const string otherdata_txt = (otherlen > 0) ?
- lexer.getNextToken(MasterToken::STRING).getString() : "";
- vector<uint8_t> other_data;
- decodeBase64(otherdata_txt, other_data);
- if (other_data.size() != otherlen) {
- isc_throw(InvalidRdataText,
- "TKEY Other Data length does not match Other Len");
- }
- // RFC2845 says Other Data is "empty unless Error == BADTIME".
- // However, we don't enforce that.
-
- return (new boost::shared_ptr<TKEYImpl>(algorithm, inception, expire, mode, error,
- key_data, other_data));
-}
-
-/// \brief Constructor from string.
-///
-/// The given string must represent a valid TKEY RDATA. There can be extra
-/// space characters at the beginning or end of the text (which are simply
-/// ignored), but other extra text, including a new line, will make the
-/// construction fail with an exception.
-///
-/// \c tkey_str must be formatted as follows:
-/// \code <Algorithm Name> <Inception> <Expire> <Mode> <Error>
-/// <Key Len> [<Key Data>] <Other Len> [<Other Data>]
-/// \endcode
-///
-/// Note that, since the Algorithm Name field is defined to be "in domain name
-/// syntax", but it is not actually a domain name, it does not have to be
-/// fully qualified.
-///
-/// The Mode field is an unsigned 16-bit decimal integer as specified
-/// in RFC2930 or a common mnemonic. Currently only "GSS-API" (case sensitive)
-/// is supported ("Diffie-Hellman" is not).
-///
-/// The Error field is an unsigned 16-bit decimal integer or a valid mnemonic
-/// as specified in RFC2845. Currently, "NOERROR", "BADSIG", "BADKEY",
-/// "BADTIME", "BADMODE", "BADNAME", and "BADALG" are supported
-/// (case sensitive). In future versions other representations that
-/// are compatible with the DNS RCODE may be supported.
-///
-/// The Key Data and Other Data fields are base-64 encoded strings that do not
-/// contain space characters.
-/// If the Key Len field is 0, the Key Data field must not appear in
-/// \c tkey_str.
-/// If the Other Len field is 0, the Other Data field must not appear in
-/// \c tkey_str.
-/// The decoded data of the Key Data field is Key Len bytes of binary stream.
-/// The decoded data of the Other Data field is Other Len bytes of binary
-/// stream.
-///
-/// An example of valid string is:
-/// \code "gss-tsig. 20210501120000 20210501130000 0 3 aabbcc 0" \endcode
-/// In this example Other Data is missing because Other Len is 0.
-///
-/// Note that RFC2930 does not define the standard presentation format
-/// of %TKEY RR, so the above syntax is implementation specific.
-/// This is, however, compatible with the format acceptable to BIND 9's
-/// RDATA parser.
-///
-/// \throw Others Exception from the Name constructors.
-/// \throw InvalidRdataText if any fields are out of their valid range,
-/// or are incorrect.
-/// \throw BadValue if Key Data or Other Data is not validly encoded
-/// in base-64.
-///
-/// \param tkey_str A string containing the RDATA to be created
-TKEY::TKEY(const std::string& tkey_str) : impl_(0) {
- // We use unique_ptr here because if there is an exception in this
- // constructor, the destructor is not called and there could be a
- // leak of the TKEYImpl that constructFromLexer() returns.
- boost::shared_ptr<TKEYImpl> impl_ptr;
-
- try {
- std::istringstream ss(tkey_str);
- MasterLexer lexer;
- lexer.pushSource(ss);
-
- impl_ptr.reset(constructFromLexer(lexer, 0));
-
- if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
- isc_throw(InvalidRdataText,
- "Extra input text for TKEY: " << tkey_str);
- }
- } catch (const MasterLexer::LexerError& ex) {
- isc_throw(InvalidRdataText,
- "Failed to construct TKEY from '" << tkey_str << "': "
- << ex.what());
- }
-
- impl_ = impl_ptr;
-}
-
-/// \brief Constructor with a context of MasterLexer.
-///
-/// The \c lexer should point to the beginning of valid textual
-/// representation of an TKEY RDATA.
-///
-/// See \c TKEY::TKEY(const std::string&) for description of the
-/// expected RDATA fields.
-///
-/// \throw MasterLexer::LexerError General parsing error such as
-/// missing field.
-/// \throw InvalidRdataText if any fields are out of their valid range,
-/// or are incorrect.
-///
-/// \param lexer A \c MasterLexer object parsing a master file for the
-/// RDATA to be created
-TKEY::TKEY(MasterLexer& lexer, const Name* origin,
- MasterLoader::Options, MasterLoaderCallbacks&) :
- impl_(constructFromLexer(lexer, origin)) {
-}
-
-/// \brief Constructor from wire-format data.
-///
-/// When a read operation on \c buffer fails (e.g., due to a corrupted
-/// message) a corresponding exception from the \c InputBuffer class will
-/// be thrown.
-/// If the wire-format data does not begin with a valid domain name,
-/// a corresponding exception from the \c Name class will be thrown.
-/// In addition, this constructor internally involves resource allocation,
-/// and if it fails a corresponding standard exception will be thrown.
-///
-/// According to RFC3597, the Algorithm field must be a non compressed form
-/// of domain name. But this implementation accepts a %TKEY RR even if that
-/// field is compressed.
-///
-/// \param buffer A buffer storing the wire format data.
-/// \param rdata_len The length of the RDATA in bytes, normally expected
-/// to be the value of the RDLENGTH field of the corresponding RR.
-/// But this constructor does not use this parameter; if necessary, the caller
-/// must check consistency between the length parameter and the actual
-/// RDATA length.
-TKEY::TKEY(InputBuffer& buffer, size_t) :
- impl_(0) {
- Name algorithm(buffer);
-
- const uint32_t inception = buffer.readUint32();
-
- const uint32_t expire = buffer.readUint32();
-
- const uint16_t mode = buffer.readUint16();
-
- const uint16_t error = buffer.readUint16();
-
- const uint16_t key_len = buffer.readUint16();
- vector<uint8_t> key(key_len);
- if (key_len > 0) {
- buffer.readData(&key[0], key_len);
- }
-
- const uint16_t other_len = buffer.readUint16();
- vector<uint8_t> other_data(other_len);
- if (other_len > 0) {
- buffer.readData(&other_data[0], other_len);
- }
-
- impl_.reset(new TKEYImpl(algorithm, inception, expire, mode, error,
- key, other_data));
-}
-
-TKEY::TKEY(const Name& algorithm, uint32_t inception, uint32_t expire,
- uint16_t mode, uint16_t error, uint16_t key_len,
- const void* key, uint16_t other_len, const void* other_data) :
- impl_(0) {
- if ((key_len == 0 && key != 0) || (key_len > 0 && key == 0)) {
- isc_throw(InvalidParameter, "TKEY Key length and data inconsistent");
- }
- if ((other_len == 0 && other_data != 0) ||
- (other_len > 0 && other_data == 0)) {
- isc_throw(InvalidParameter,
- "TKEY Other data length and data inconsistent");
- }
- impl_.reset(new TKEYImpl(algorithm, inception, expire, mode, error,
- key_len, key, other_len, other_data));
-}
-
-/// \brief The copy constructor.
-///
-/// It internally allocates a resource, and if it fails a corresponding
-/// standard exception will be thrown.
-/// This constructor never throws an exception otherwise.
-TKEY::TKEY(const TKEY& source) : Rdata(), impl_(new TKEYImpl(*source.impl_)) {
-}
-
-TKEY&
-TKEY::operator=(const TKEY& source) {
- if (this == &source) {
- return (*this);
- }
-
- impl_.reset(new TKEYImpl(*source.impl_));
-
- return (*this);
-}
-
-TKEY::~TKEY() {
-}
-
-/// \brief Convert the \c TKEY to a string.
-///
-/// The output of this method is formatted as described in the "from string"
-/// constructor (\c TKEY(const std::string&))).
-///
-/// If internal resource allocation fails, a corresponding
-/// standard exception will be thrown.
-///
-/// \return A \c string object that represents the \c TKEY object.
-std::string
-TKEY::toText() const {
- string result;
-
- result += impl_->algorithm_.toText() + " " +
- timeToText32(impl_->inception_) + " " +
- timeToText32(impl_->expire_) + " ";
- if (impl_->mode_ == GSS_API_MODE) {
- result += "GSS-API ";
- } else {
- result += lexical_cast<string>(impl_->mode_) + " ";
- }
- result += TSIGError(impl_->error_).toText() + " " +
- lexical_cast<string>(impl_->key_.size()) + " ";
- if (!impl_->key_.empty()) {
- result += encodeBase64(impl_->key_) + " ";
- }
- result += lexical_cast<string>(impl_->other_data_.size());
- if (!impl_->other_data_.empty()) {
- result += " " + encodeBase64(impl_->other_data_);
- }
-
- return (result);
-}
-
-// Common sequence of toWire() operations used for the two versions of
-// toWire().
-template <typename Output>
-void
-TKEYImpl::toWireCommon(Output& output) const {
- output.writeUint32(inception_);
- output.writeUint32(expire_);
- output.writeUint16(mode_);
- output.writeUint16(error_);
- const uint16_t key_len = key_.size();
- output.writeUint16(key_len);
- if (key_len > 0) {
- output.writeData(&key_[0], key_len);
- }
- const uint16_t other_len = other_data_.size();
- output.writeUint16(other_len);
- if (other_len > 0) {
- output.writeData(&other_data_[0], other_len);
- }
-}
-
-/// \brief Render the \c TKEY in the wire format without name compression.
-///
-/// If internal resource allocation fails, a corresponding
-/// standard exception will be thrown.
-/// This method never throws an exception otherwise.
-///
-/// \param buffer An output buffer to store the wire data.
-void
-TKEY::toWire(OutputBuffer& buffer) const {
- impl_->algorithm_.toWire(buffer);
- impl_->toWireCommon<OutputBuffer>(buffer);
-}
-
-/// \brief Render the \c TKEY in the wire format with taking into account
-/// compression.
-///
-/// As specified in RFC3597, the Algorithm field (a domain name) will not
-/// be compressed. However, the domain name could be a target of compression
-/// of other compressible names (though pretty unlikely), the offset
-/// information of the algorithm name may be recorded in \c renderer.
-///
-/// If internal resource allocation fails, a corresponding
-/// standard exception will be thrown.
-/// This method never throws an exception otherwise.
-///
-/// \param renderer DNS message rendering context that encapsulates the
-/// output buffer and name compression information.
-void
-TKEY::toWire(AbstractMessageRenderer& renderer) const {
- renderer.writeName(impl_->algorithm_, false);
- impl_->toWireCommon<AbstractMessageRenderer>(renderer);
-}
-
-// A helper function commonly used for TKEY::compare().
-int
-vectorComp(const vector<uint8_t>& v1, const vector<uint8_t>& v2) {
- const size_t this_size = v1.size();
- const size_t other_size = v2.size();
- if (this_size != other_size) {
- return (this_size < other_size ? -1 : 1);
- }
- if (this_size > 0) {
- return (memcmp(&v1[0], &v2[0], this_size));
- }
- return (0);
-}
-
-/// \brief Compare two instances of \c TKEY RDATA.
-///
-/// This method compares \c this and the \c other \c TKEY objects
-/// in terms of the DNSSEC sorting order as defined in RFC4034, and returns
-/// the result as an integer.
-///
-/// This method is expected to be used in a polymorphic way, and the
-/// parameter to compare against is therefore of the abstract \c Rdata class.
-/// However, comparing two \c Rdata objects of different RR types
-/// is meaningless, and \c other must point to a \c TKEY object;
-/// otherwise, the standard \c bad_cast exception will be thrown.
-/// This method never throws an exception otherwise.
-///
-/// \param other the right-hand operand to compare against.
-/// \return < 0 if \c this would be sorted before \c other.
-/// \return 0 if \c this is identical to \c other in terms of sorting order.
-/// \return > 0 if \c this would be sorted after \c other.
-int
-TKEY::compare(const Rdata& other) const {
- const TKEY& other_tkey = dynamic_cast<const TKEY&>(other);
-
- const int ncmp = compareNames(impl_->algorithm_,
- other_tkey.impl_->algorithm_);
- if (ncmp != 0) {
- return (ncmp);
- }
-
- if (impl_->inception_ != other_tkey.impl_->inception_) {
- return (impl_->inception_ < other_tkey.impl_->inception_ ? -1 : 1);
- }
- if (impl_->expire_ != other_tkey.impl_->expire_) {
- return (impl_->expire_ < other_tkey.impl_->expire_ ? -1 : 1);
- }
- if (impl_->mode_ != other_tkey.impl_->mode_) {
- return (impl_->mode_ < other_tkey.impl_->mode_ ? -1 : 1);
- }
- if (impl_->error_ != other_tkey.impl_->error_) {
- return (impl_->error_ < other_tkey.impl_->error_ ? -1 : 1);
- }
-
- const int vcmp = vectorComp(impl_->key_, other_tkey.impl_->key_);
- if (vcmp != 0) {
- return (vcmp);
- }
- return (vectorComp(impl_->other_data_, other_tkey.impl_->other_data_));
-}
-
-const Name&
-TKEY::getAlgorithm() const {
- return (impl_->algorithm_);
-}
-
-uint32_t
-TKEY::getInception() const {
- return (impl_->inception_);
-}
-
-string
-TKEY::getInceptionDate() const {
- return (timeToText32(impl_->inception_));
-}
-
-uint32_t
-TKEY::getExpire() const {
- return (impl_->expire_);
-}
-
-string
-TKEY::getExpireDate() const {
- return (timeToText32(impl_->expire_));
-}
-
-uint16_t
-TKEY::getMode() const {
- return (impl_->mode_);
-}
-
-uint16_t
-TKEY::getError() const {
- return (impl_->error_);
-}
-
-uint16_t
-TKEY::getKeyLen() const {
- return (impl_->key_.size());
-}
-
-const void*
-TKEY::getKey() const {
- if (!impl_->key_.empty()) {
- return (&impl_->key_[0]);
- } else {
- return (0);
- }
-}
-
-uint16_t
-TKEY::getOtherLen() const {
- return (impl_->other_data_.size());
-}
-
-const void*
-TKEY::getOtherData() const {
- if (!impl_->other_data_.empty()) {
- return (&impl_->other_data_[0]);
- } else {
- return (0);
- }
-}
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/tkey_249.h b/src/lib/dns/rdata/generic/tkey_249.h
deleted file mode 100644
index cd7278d374..0000000000
--- a/src/lib/dns/rdata/generic/tkey_249.h
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-// BEGIN_HEADER_GUARD
-
-#include <stdint.h>
-
-#include <string>
-
-#include <dns/name.h>
-#include <dns/rdata.h>
-#include <boost/shared_ptr.hpp>
-
-// BEGIN_ISC_NAMESPACE
-
-// BEGIN_COMMON_DECLARATIONS
-// END_COMMON_DECLARATIONS
-
-// BEGIN_RDATA_NAMESPACE
-
-struct TKEYImpl;
-
-/// \brief \c rdata::TKEY class represents the TKEY RDATA as defined %in
-/// RFC2930.
-///
-/// This class implements the basic interfaces inherited from the abstract
-/// \c rdata::Rdata class, and provides trivial accessors specific to the
-/// TKEY RDATA.
-class TKEY : public Rdata {
-public:
- // BEGIN_COMMON_MEMBERS
- // END_COMMON_MEMBERS
-
- /// \brief Constructor from RDATA field parameters.
- ///
- /// The parameters are a straightforward mapping of %TKEY RDATA
- /// fields as defined %in RFC2930.
- ///
- /// This RR is pretty close to the TSIG RR with 32 bit timestamps,
- /// or the RRSIG RR with a second "other" data field.
- ///
- /// This constructor internally involves resource allocation, and if
- /// it fails, a corresponding standard exception will be thrown.
- ///
- /// \param algorithm The DNS name of the algorithm e.g. gss-tsig.
- /// \param inception The inception time (in seconds since 1970).
- /// \param expire The expire time (in seconds since 1970).
- /// \param mode The mode e.g. Diffie-Hellman (2) or GSS-API (3).
- /// \param error The error code (extended error space shared with TSIG).
- /// \param key_len The key length (0 means no key).
- /// \param key The key (can be 0).
- /// \param other_len The other data length (0 means no other data).
- /// \param other_data The other data (can be and usually is 0).
- TKEY(const Name& algorithm, uint32_t inception, uint32_t expire,
- uint16_t mode, uint16_t error, uint16_t key_len,
- const void* key, uint16_t other_len, const void* other_data);
-
- /// \brief Assignment operator.
- ///
- /// It internally allocates a resource, and if it fails a corresponding
- /// standard exception will be thrown.
- /// This operator never throws an exception otherwise.
- ///
- /// This operator provides the strong exception guarantee: When an
- /// exception is thrown the content of the assignment target will be
- /// intact.
- TKEY& operator=(const TKEY& source);
-
- /// \brief The destructor.
- ~TKEY();
-
- /// \brief Return the algorithm name.
- ///
- /// This method never throws an exception.
- const Name& getAlgorithm() const;
-
- /// \brief Return the value of the Inception field as a number.
- ///
- /// This method never throws an exception.
- uint32_t getInception() const;
-
- /// \brief Return the value of the Inception field as a string.
- std::string getInceptionDate() const;
-
- /// \brief Return the value of the Expire field as a number.
- ///
- /// This method never throws an exception.
- uint32_t getExpire() const;
-
- /// \brief Return the value of the Expire field as a string.
- std::string getExpireDate() const;
-
- /// \brief Return the value of the Mode field.
- ///
- /// This method never throws an exception.
- uint16_t getMode() const;
-
- /// \brief Return the value of the Error field.
- ///
- /// This method never throws an exception.
- uint16_t getError() const;
-
- /// \brief Return the value of the Key Len field.
- ///
- /// This method never throws an exception.
- uint16_t getKeyLen() const;
-
- /// \brief Return the value of the Key field.
- ///
- /// This method never throws an exception.
- const void* getKey() const;
-
- /// \brief Return the value of the Other Len field.
- ///
- /// This method never throws an exception.
- uint16_t getOtherLen() const;
-
- /// \brief Return the value of the Other Data field.
- ///
- /// The same note as \c getMAC() applies.
- ///
- /// This method never throws an exception.
- const void* getOtherData() const;
-
- /// \brief The GSS_API constant for the Mode field.
- static const uint16_t GSS_API_MODE;
-
-private:
- boost::shared_ptr<TKEYImpl> constructFromLexer(MasterLexer& lexer, const Name* origin);
-
- boost::shared_ptr<TKEYImpl> impl_;
-};
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
-// END_HEADER_GUARD
diff --git a/src/lib/dns/rdata/in_1/a_1.cc b/src/lib/dns/rdata/in_1/a_1.cc
deleted file mode 100644
index 2a7b3efbb8..0000000000
--- a/src/lib/dns/rdata/in_1/a_1.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <stdint.h>
-#include <string.h>
-
-#include <cerrno>
-#include <cstring>
-#include <string>
-
-#include <arpa/inet.h> // XXX: for inet_pton/ntop(), not exist in C++ standards
-#include <sys/socket.h> // for AF_INET/AF_INET6
-
-#include <exceptions/exceptions.h>
-
-#include <util/buffer.h>
-
-#include <dns/exceptions.h>
-#include <dns/messagerenderer.h>
-#include <dns/master_lexer.h>
-#include <dns/master_loader_callbacks.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-
-using namespace std;
-using namespace isc::util;
-
-// BEGIN_ISC_NAMESPACE
-// BEGIN_RDATA_NAMESPACE
-
-namespace {
-void
-convertToIPv4Addr(const char* src, size_t src_len, uint32_t* dst) {
- // This check specifically rejects invalid input that begins with valid
- // address text followed by a nul character (and possibly followed by
- // further garbage). It cannot be detected by inet_pton().
- //
- // Note that this is private subroutine of the in::A constructors, which
- // pass std::string.size() or StringRegion::len as src_len, so it should
- // be equal to strlen() unless there's an intermediate nul character.
- if (src_len != strlen(src)) {
- isc_throw(InvalidRdataText,
- "Bad IN/A RDATA text: unexpected nul in string: '"
- << src << "'");
- }
- const int result = inet_pton(AF_INET, src, dst);
- if (result == 0) {
- isc_throw(InvalidRdataText, "Bad IN/A RDATA text: '" << src << "'");
- } else if (result < 0) {
- isc_throw(isc::Unexpected,
- "Unexpected failure in parsing IN/A RDATA text: '"
- << src << "': " << std::strerror(errno));
- }
-}
-}
-
-/// \brief Constructor from string.
-///
-/// The given string must be a valid textual representation of an IPv4
-/// address as specified in RFC1035, that is, four decimal numbers separated
-/// by dots without any embedded spaces. Note that it excludes abbreviated
-/// forms such as "10.1" to mean "10.0.0.1".
-///
-/// Internally, this implementation uses the standard inet_pton() library
-/// function for the AF_INET family to parse and convert the textual
-/// representation. While standard compliant implementations of this function
-/// should accept exactly what this constructor expects, specific
-/// implementation may behave differently, in which case this constructor
-/// will simply accept the result of inet_pton(). In any case, the user of
-/// the class shouldn't assume such specific implementation behavior of
-/// inet_pton().
-///
-/// No extra character should be contained in \c addrstr other than the
-/// textual address. These include spaces and the nul character.
-///
-/// \throw InvalidRdata The text extracted by the lexer isn't recognized as
-/// a valid IPv4 address.
-/// \throw Unexpected Unexpected system error in conversion (this should be
-/// very rare).
-///
-/// \param addrstr Textual representation of IPv4 address to be used as the
-/// RDATA.
-A::A(const std::string& addrstr) {
- convertToIPv4Addr(addrstr.c_str(), addrstr.size(), &addr_);
-}
-
-/// \brief Constructor with a context of MasterLexer.
-///
-/// The \c lexer should point to the beginning of valid textual representation
-/// of a class IN A RDATA.
-///
-/// The acceptable form of the textual address is generally the same as the
-/// string version of the constructor, but this version accepts beginning
-/// spaces and trailing spaces or other characters. Trailing non space
-/// characters would be considered an invalid form in an RR representation,
-/// but handling such errors is not the responsibility of this constructor.
-/// It also accepts other unusual syntax that would be considered valid
-/// in the context of DNS master file; for example, it accepts an IPv4
-/// address surrounded by parentheses, such as "(192.0.2.1)", although it's
-/// very unlikely to be used for this type of RDATA.
-///
-/// \throw MasterLexer::LexerError General parsing error such as missing field.
-/// \throw InvalidRdata The text extracted by the lexer isn't recognized as
-/// a valid IPv4 address.
-/// \throw Unexpected Unexpected system error in conversion (this should be
-/// very rare).
-///
-/// \param lexer A \c MasterLexer object parsing a master file for the
-/// RDATA to be created
-A::A(MasterLexer& lexer, const Name*,
- MasterLoader::Options, MasterLoaderCallbacks&) {
- const MasterToken& token = lexer.getNextToken(MasterToken::STRING);
- convertToIPv4Addr(token.getStringRegion().beg, token.getStringRegion().len,
- &addr_);
-}
-
-A::A(InputBuffer& buffer, size_t rdata_len) {
- if (rdata_len != sizeof(addr_)) {
- isc_throw(DNSMessageFORMERR,
- "IN/A RDATA construction from wire failed: Invalid length: "
- << rdata_len);
- }
- if (buffer.getLength() - buffer.getPosition() < sizeof(addr_)) {
- isc_throw(DNSMessageFORMERR,
- "IN/A RDATA construction from wire failed: "
- "insufficient buffer length: "
- << buffer.getLength() - buffer.getPosition());
- }
- buffer.readData(&addr_, sizeof(addr_));
-}
-
-/// \brief Copy constructor.
-A::A(const A& other) : Rdata(), addr_(other.addr_) {
-}
-
-void
-A::toWire(OutputBuffer& buffer) const {
- buffer.writeData(&addr_, sizeof(addr_));
-}
-
-void
-A::toWire(AbstractMessageRenderer& renderer) const {
- renderer.writeData(&addr_, sizeof(addr_));
-}
-
-/// \brief Return a textual form of the underlying IPv4 address of the RDATA.
-string
-A::toText() const {
- char addr_string[sizeof("255.255.255.255")];
-
- if (inet_ntop(AF_INET, &addr_, addr_string, sizeof(addr_string)) == NULL) {
- isc_throw(Unexpected,
- "Failed to convert IN/A RDATA to textual IPv4 address");
- }
-
- return (addr_string);
-}
-
-/// \brief Compare two in::A RDATAs.
-///
-/// In effect, it compares the two RDATA as an unsigned 32-bit integer.
-int
-A::compare(const Rdata& other) const {
- const A& other_a = dynamic_cast<const A&>(other);
- return (memcmp(&addr_, &other_a.addr_, sizeof(addr_)));
-}
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/in_1/a_1.h b/src/lib/dns/rdata/in_1/a_1.h
deleted file mode 100644
index f8061d7d22..0000000000
--- a/src/lib/dns/rdata/in_1/a_1.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-// BEGIN_HEADER_GUARD
-
-#include <string>
-
-#include <dns/rdata.h>
-
-// BEGIN_ISC_NAMESPACE
-
-// BEGIN_COMMON_DECLARATIONS
-// END_COMMON_DECLARATIONS
-
-// BEGIN_RDATA_NAMESPACE
-
-class A : public Rdata {
-public:
- // BEGIN_COMMON_MEMBERS
- // END_COMMON_MEMBERS
-
- //We can use the default destructor.
- //virtual ~A() {}
- // notyet:
- //const struct in_addr& getAddress() const { return (addr_); }
-private:
- uint32_t addr_; // raw IPv4 address (network byte order)
-};
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
-// END_HEADER_GUARD
diff --git a/src/lib/dns/rdata/in_1/aaaa_28.cc b/src/lib/dns/rdata/in_1/aaaa_28.cc
deleted file mode 100644
index 51243f48e8..0000000000
--- a/src/lib/dns/rdata/in_1/aaaa_28.cc
+++ /dev/null
@@ -1,152 +0,0 @@
-// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <exceptions/exceptions.h>
-#include <util/buffer.h>
-#include <dns/exceptions.h>
-#include <dns/messagerenderer.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/master_lexer.h>
-#include <dns/master_loader.h>
-
-#include <stdint.h>
-#include <string.h>
-
-#include <cerrno>
-#include <cstring>
-#include <string>
-
-#include <arpa/inet.h> // XXX: for inet_pton/ntop(), not exist in C++ standards
-#include <sys/socket.h> // for AF_INET/AF_INET6
-
-using namespace std;
-using namespace isc::util;
-
-// BEGIN_ISC_NAMESPACE
-// BEGIN_RDATA_NAMESPACE
-
-namespace {
-void
-convertToIPv6Addr(const char* src, size_t src_len, void* dst) {
- // See a_1.cc for this check.
- if (src_len != strlen(src)) {
- isc_throw(InvalidRdataText,
- "Bad IN/AAAA RDATA text: unexpected nul in string: '"
- << src << "'");
- }
- const int result = inet_pton(AF_INET6, src, dst);
- if (result == 0) {
- isc_throw(InvalidRdataText, "Bad IN/AAAA RDATA text: '" << src << "'");
- } else if (result < 0) {
- isc_throw(isc::Unexpected,
- "Unexpected failure in parsing IN/AAAA RDATA text: '"
- << src << "': " << std::strerror(errno));
- }
-}
-}
-
-/// \brief Constructor from string.
-///
-/// The given string must be a valid textual representation of an IPv6
-/// address as specified in RFC1886.
-///
-/// No extra character should be contained in \c addrstr other than the
-/// textual address. These include spaces and the nul character.
-///
-/// \throw InvalidRdata The text extracted by the lexer isn't recognized as
-/// a valid IPv6 address.
-/// \throw Unexpected Unexpected system error in conversion (this should be
-/// very rare).
-///
-/// \param addrstr Textual representation of IPv6 address to be used as the
-/// RDATA.
-AAAA::AAAA(const std::string& addrstr) {
- convertToIPv6Addr(addrstr.c_str(), addrstr.size(), addr_);
-}
-
-/// \brief Constructor with a context of MasterLexer.
-///
-/// The \c lexer should point to the beginning of valid textual representation
-/// of a class IN AAAA RDATA.
-///
-/// The acceptable form of the textual address is generally the same as the
-/// string version of the constructor, but this version is slightly more
-/// flexible. See the similar constructor of \c in::A class; the same
-/// notes apply here.
-///
-/// \throw MasterLexer::LexerError General parsing error such as missing field.
-/// \throw InvalidRdata The text extracted by the lexer isn't recognized as
-/// a valid IPv6 address.
-/// \throw Unexpected Unexpected system error in conversion (this should be
-/// very rare).
-///
-/// \param lexer A \c MasterLexer object parsing a master file for the
-/// RDATA to be created
-AAAA::AAAA(MasterLexer& lexer, const Name*,
- MasterLoader::Options, MasterLoaderCallbacks&) {
- const MasterToken& token = lexer.getNextToken(MasterToken::STRING);
- convertToIPv6Addr(token.getStringRegion().beg, token.getStringRegion().len,
- addr_);
-}
-
-/// \brief Copy constructor.
-AAAA::AAAA(InputBuffer& buffer, size_t rdata_len) {
- if (rdata_len != sizeof(addr_)) {
- isc_throw(DNSMessageFORMERR,
- "IN/AAAA RDATA construction from wire failed: "
- "Invalid length: " << rdata_len);
- }
- if (buffer.getLength() - buffer.getPosition() < sizeof(addr_)) {
- isc_throw(DNSMessageFORMERR,
- "IN/AAAA RDATA construction from wire failed: "
- "insufficient buffer length: "
- << buffer.getLength() - buffer.getPosition());
- }
- buffer.readData(&addr_, sizeof(addr_));
-}
-
-AAAA::AAAA(const AAAA& other) : Rdata() {
- memcpy(addr_, other.addr_, sizeof(addr_));
-}
-
-/// \brief Return a textual form of the underlying IPv6 address of the RDATA.
-void
-AAAA::toWire(OutputBuffer& buffer) const {
- buffer.writeData(&addr_, sizeof(addr_));
-}
-
-void
-AAAA::toWire(AbstractMessageRenderer& renderer) const {
- renderer.writeData(&addr_, sizeof(addr_));
-}
-
-string
-AAAA::toText() const {
- char addr_string[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
-
- if (inet_ntop(AF_INET6, &addr_, addr_string, sizeof(addr_string))
- == NULL) {
- isc_throw(Unexpected,
- "Failed to convert IN/AAAA RDATA to textual IPv6 address");
- }
-
- return (string(addr_string));
-}
-
-/// \brief Compare two in::AAAA RDATAs.
-///
-/// In effect, it compares the two RDATA as an unsigned 128-bit integer.
-int
-AAAA::compare(const Rdata& other) const {
- const AAAA& other_a = dynamic_cast<const AAAA&>(other);
- return (memcmp(&addr_, &other_a.addr_, sizeof(addr_)));
-}
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/in_1/aaaa_28.h b/src/lib/dns/rdata/in_1/aaaa_28.h
deleted file mode 100644
index c8829344b4..0000000000
--- a/src/lib/dns/rdata/in_1/aaaa_28.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-// BEGIN_HEADER_GUARD
-
-#include <stdint.h>
-
-#include <string>
-
-#include <dns/rdata.h>
-
-// BEGIN_ISC_NAMESPACE
-
-// BEGIN_COMMON_DECLARATIONS
-// END_COMMON_DECLARATIONS
-
-// BEGIN_RDATA_NAMESPACE
-
-class AAAA : public Rdata {
-public:
- // BEGIN_COMMON_MEMBERS
- // END_COMMON_MEMBERS
- // notyet:
- //const struct in6_addr& getAddress() const { return (addr_); }
-private:
- uint8_t addr_[16]; // raw IPv6 address (network byte order)
-};
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
-// END_HEADER_GUARD
diff --git a/src/lib/dns/rdata/in_1/dhcid_49.cc b/src/lib/dns/rdata/in_1/dhcid_49.cc
deleted file mode 100644
index 89c3f89360..0000000000
--- a/src/lib/dns/rdata/in_1/dhcid_49.cc
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright (C) 2011-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <stdint.h>
-#include <string.h>
-
-#include <exceptions/exceptions.h>
-
-#include <util/buffer.h>
-#include <util/encode/encode.h>
-#include <dns/exceptions.h>
-#include <dns/messagerenderer.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-
-using namespace std;
-using namespace isc::util;
-using namespace isc::util::encode;
-
-// BEGIN_ISC_NAMESPACE
-// BEGIN_RDATA_NAMESPACE
-
-void
-DHCID::constructFromLexer(MasterLexer& lexer) {
- string digest_txt = lexer.getNextToken(MasterToken::STRING).getString();
-
- // Whitespace is allowed within base64 text, so read to the end of input.
- string digest_part;
- while (true) {
- const MasterToken& token =
- lexer.getNextToken(MasterToken::STRING, true);
- if ((token.getType() == MasterToken::END_OF_FILE) ||
- (token.getType() == MasterToken::END_OF_LINE)) {
- break;
- }
- token.getString(digest_part);
- digest_txt.append(digest_part);
- }
- lexer.ungetToken();
-
- decodeBase64(digest_txt, digest_);
-}
-
-/// \brief Constructor from string.
-///
-/// \param dhcid_str A base-64 representation of the DHCID binary data.
-///
-/// \throw InvalidRdataText if the string could not be parsed correctly.
-DHCID::DHCID(const std::string& dhcid_str) {
- try {
- std::istringstream iss(dhcid_str);
- MasterLexer lexer;
- lexer.pushSource(iss);
-
- constructFromLexer(lexer);
-
- if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
- isc_throw(InvalidRdataText, "extra input text for DHCID: "
- << dhcid_str);
- }
- } catch (const MasterLexer::LexerError& ex) {
- isc_throw(InvalidRdataText, "Failed to construct DHCID from '" <<
- dhcid_str << "': " << ex.what());
- }
-}
-
-/// \brief Constructor with a context of MasterLexer.
-///
-/// The \c lexer should point to the beginning of valid textual representation
-/// of a DHCID RDATA.
-///
-/// \throw BadValue if the text is not valid base-64.
-/// \throw MasterLexer::LexerError General parsing error such as missing field.
-///
-/// \param lexer A \c MasterLexer object parsing a master file for the
-/// RDATA to be created
-DHCID::DHCID(MasterLexer& lexer, const Name*,
- MasterLoader::Options, MasterLoaderCallbacks&) {
- constructFromLexer(lexer);
-}
-
-/// \brief Constructor from wire-format data.
-///
-/// \param buffer A buffer storing the wire format data.
-/// \param rdata_len The length of the RDATA in bytes
-DHCID::DHCID(InputBuffer& buffer, size_t rdata_len) {
- if (rdata_len == 0) {
- isc_throw(InvalidRdataLength, "Missing DHCID rdata");
- }
-
- digest_.resize(rdata_len);
- buffer.readData(&digest_[0], rdata_len);
-}
-
-/// \brief The copy constructor.
-///
-/// This trivial copy constructor never throws an exception.
-DHCID::DHCID(const DHCID& other) : Rdata(), digest_(other.digest_) {
-}
-
-/// \brief Render the \c DHCID in the wire format.
-///
-/// \param buffer An output buffer to store the wire data.
-void
-DHCID::toWire(OutputBuffer& buffer) const {
- buffer.writeData(&digest_[0], digest_.size());
-}
-
-/// \brief Render the \c DHCID in the wire format into a
-/// \c MessageRenderer object.
-///
-/// \param renderer DNS message rendering context that encapsulates the
-/// output buffer in which the \c DHCID is to be stored.
-void
-DHCID::toWire(AbstractMessageRenderer& renderer) const {
- renderer.writeData(&digest_[0], digest_.size());
-}
-
-/// \brief Convert the \c DHCID to a string.
-///
-/// This method returns a \c std::string object representing the \c DHCID.
-///
-/// \return A string representation of \c DHCID.
-string
-DHCID::toText() const {
- return (encodeBase64(digest_));
-}
-
-/// \brief Compare two instances of \c DHCID RDATA.
-///
-/// See documentation in \c Rdata.
-int
-DHCID::compare(const Rdata& other) const {
- const DHCID& other_dhcid = dynamic_cast<const DHCID&>(other);
-
- size_t this_len = digest_.size();
- size_t other_len = other_dhcid.digest_.size();
- size_t cmplen = min(this_len, other_len);
- int cmp = memcmp(&digest_[0], &other_dhcid.digest_[0], cmplen);
- if (cmp != 0) {
- return (cmp);
- } else {
- return ((this_len == other_len) ? 0 : (this_len < other_len) ? -1 : 1);
- }
-}
-
-/// \brief Accessor method to get the DHCID digest
-///
-/// \return A reference to the binary DHCID data
-const std::vector<uint8_t>&
-DHCID::getDigest() const {
- return (digest_);
-}
-
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/in_1/dhcid_49.h b/src/lib/dns/rdata/in_1/dhcid_49.h
deleted file mode 100644
index e5602c1cce..0000000000
--- a/src/lib/dns/rdata/in_1/dhcid_49.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-// BEGIN_HEADER_GUARD
-
-#include <string>
-#include <vector>
-
-#include <dns/rdata.h>
-
-// BEGIN_ISC_NAMESPACE
-
-// BEGIN_COMMON_DECLARATIONS
-// END_COMMON_DECLARATIONS
-
-// BEGIN_RDATA_NAMESPACE
-
-/// \brief \c rdata::DHCID class represents the DHCID RDATA as defined %in
-/// RFC4701.
-///
-/// This class implements the basic interfaces inherited from the abstract
-/// \c rdata::Rdata class, and provides trivial accessors specific to the
-/// DHCID RDATA.
-class DHCID : public Rdata {
-public:
- // BEGIN_COMMON_MEMBERS
- // END_COMMON_MEMBERS
-
- /// \brief Return the digest.
- ///
- /// This method never throws an exception.
- const std::vector<uint8_t>& getDigest() const;
-
-private:
- // helper for string and lexer constructors
- void constructFromLexer(MasterLexer& lexer);
-
- /// \brief Private data representation
- ///
- /// Opaque data at least 3 octets long as per RFC4701.
- ///
- std::vector<uint8_t> digest_;
-};
-// END_RDATA_NAMESPACE
-// END_ISC_NAMESPACE
-// END_HEADER_GUARD
diff --git a/src/lib/dns/rdata/template.cc b/src/lib/dns/rdata/template.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/rdata/template.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/rdata/template.h b/src/lib/dns/rdata/template.h
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/rdata/template.h
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/rdataclass.cc b/src/lib/dns/rdataclass.cc
index 699f6aaaa4..43c26c5936 100644
--- a/src/lib/dns/rdataclass.cc
+++ b/src/lib/dns/rdataclass.cc
@@ -1,10 +1,3 @@
-///////////////
-///////////////
-/////////////// THIS FILE IS AUTOMATICALLY GENERATED BY gen-rdatacode.py.
-/////////////// DO NOT EDIT!
-///////////////
-///////////////
-
// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
@@ -13,32 +6,50 @@
#include <config.h>
-#include <string>
-#include <sstream>
-#include <vector>
-
-#include <boost/lexical_cast.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include <util/buffer.h>
-#include <util/encode/encode.h>
-
+#include <exceptions/exceptions.h>
+#include <dns/exceptions.h>
+#include <dns/master_lexer.h>
+#include <dns/master_loader.h>
+#include <dns/master_loader_callbacks.h>
#include <dns/messagerenderer.h>
#include <dns/name.h>
+#include <dns/rcode.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
-#include <dns/rcode.h>
+#include <dns/rrtype.h>
#include <dns/tsigkey.h>
#include <dns/tsigerror.h>
-#include <dns/rdata/generic/detail/lexer_util.h>
+#include <dns/txt_like.h>
+#include <util/buffer.h>
+#include <util/encode/encode.h>
+#include <util/buffer.h>
+#include <util/time_utilities.h>
+
+#include <cerrno>
+#include <cstring>
+#include <iomanip>
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+
+#include <arpa/inet.h> // XXX: for inet_pton/ntop(), not exist in C++ standards
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/socket.h> // for AF_INET/AF_INET6
+#include <time.h>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/shared_ptr.hpp>
-using namespace std;
-using boost::lexical_cast;
using namespace isc::util;
using namespace isc::util::encode;
using namespace isc::dns;
using isc::dns::rdata::generic::detail::createNameFromLexer;
+using namespace std;
+using boost::lexical_cast;
+
namespace isc {
namespace dns {
namespace rdata {
@@ -568,32 +579,100 @@ TSIG::getOtherData() const {
}
} // end of namespace "any"
-} // end of namespace "rdata"
-} // end of namespace "dns"
-} // end of namespace "isc"
-// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#include <config.h>
+namespace generic {
-#include <util/buffer.h>
-#include <dns/messagerenderer.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
+/// \brief Constructor from string.
+///
+/// The given string must represent a valid NS RDATA. There can be extra
+/// space characters at the beginning or end of the text (which are simply
+/// ignored), but other extra text, including a new line, will make the
+/// construction fail with an exception.
+///
+/// The NSDNAME must be absolute since there's no parameter that
+/// specifies the origin name; if it is not absolute, \c
+/// MissingNameOrigin exception will be thrown. These must not be
+/// represented as a quoted string.
+///
+/// \throw Others Exception from the Name and RRTTL constructors.
+/// \throw InvalidRdataText Other general syntax errors.
+NS::NS(const std::string& namestr) :
+ // Fill in dummy name and replace them soon below.
+ nsname_(Name::ROOT_NAME()) {
+ try {
+ std::istringstream ss(namestr);
+ MasterLexer lexer;
+ lexer.pushSource(ss);
-#include <string>
-#include <string.h>
+ nsname_ = createNameFromLexer(lexer, NULL);
-using namespace std;
-using namespace isc::util;
+ if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+ isc_throw(InvalidRdataText, "extra input text for NS: "
+ << namestr);
+ }
+ } catch (const MasterLexer::LexerError& ex) {
+ isc_throw(InvalidRdataText, "Failed to construct NS from '" <<
+ namestr << "': " << ex.what());
+ }
+}
-namespace isc {
-namespace dns {
-namespace rdata {
-namespace generic {
+NS::NS(InputBuffer& buffer, size_t) :
+ nsname_(buffer) {
+ // we don't need rdata_len for parsing. if necessary, the caller will
+ // check consistency.
+}
+
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual
+/// representation of an NS RDATA. The NSDNAME field can be
+/// non-absolute if \c origin is non-NULL, in which case \c origin is
+/// used to make it absolute. It must not be represented as a quoted
+/// string.
+///
+/// \throw MasterLexer::LexerError General parsing error such as missing field.
+/// \throw Other Exceptions from the Name and RRTTL constructors if
+/// construction of textual fields as these objects fail.
+///
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+/// \param origin If non NULL, specifies the origin of NSDNAME when it
+/// is non-absolute.
+NS::NS(MasterLexer& lexer, const Name* origin,
+ MasterLoader::Options, MasterLoaderCallbacks&) :
+ nsname_(createNameFromLexer(lexer, origin)) {
+}
+
+NS::NS(const NS& other) :
+ Rdata(), nsname_(other.nsname_) {
+}
+
+void
+NS::toWire(OutputBuffer& buffer) const {
+ nsname_.toWire(buffer);
+}
+
+void
+NS::toWire(AbstractMessageRenderer& renderer) const {
+ renderer.writeName(nsname_);
+}
+
+string
+NS::toText() const {
+ return (nsname_.toText());
+}
+
+int
+NS::compare(const Rdata& other) const {
+ const NS& other_ns = dynamic_cast<const NS&>(other);
+
+ return (compareNames(nsname_, other_ns.nsname_));
+}
+
+const Name&
+NS::getNSName() const {
+ return (nsname_);
+}
/// \brief Constructor.
OPT::PseudoRR::PseudoRR(uint16_t code,
@@ -777,38 +856,6 @@ OPT::getPseudoRRs() const {
return (impl_->pseudo_rrs_);
}
-} // end of namespace "generic"
-} // end of namespace "rdata"
-} // end of namespace "dns"
-} // end of namespace "isc"
-
-// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <string>
-
-#include <util/buffer.h>
-#include <dns/name.h>
-#include <dns/messagerenderer.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-
-#include <dns/rdata/generic/detail/lexer_util.h>
-
-using namespace std;
-using namespace isc::util;
-using isc::dns::rdata::generic::detail::createNameFromLexer;
-
-namespace isc {
-namespace dns {
-namespace rdata {
-namespace generic {
-
/// \brief Constructor from string.
///
/// The given string must represent a valid PTR RDATA. There can be
@@ -903,50 +950,6 @@ PTR::getPTRName() const {
return (ptr_name_);
}
-} // end of namespace "generic"
-} // end of namespace "rdata"
-} // end of namespace "dns"
-} // end of namespace "isc"
-
-// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <string>
-#include <iomanip>
-#include <iostream>
-#include <sstream>
-#include <vector>
-
-#include <boost/lexical_cast.hpp>
-
-#include <util/encode/encode.h>
-#include <util/buffer.h>
-#include <util/time_utilities.h>
-#include <dns/messagerenderer.h>
-#include <dns/name.h>
-#include <dns/rrtype.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rdata/generic/detail/lexer_util.h>
-
-#include <stdio.h>
-#include <time.h>
-
-using namespace std;
-using namespace isc::util;
-using namespace isc::util::encode;
-using isc::dns::rdata::generic::detail::createNameFromLexer;
-
-namespace isc {
-namespace dns {
-namespace rdata {
-namespace generic {
-
namespace {
// This is the minimum necessary length of all wire-format RRSIG RDATA:
// - two 8-bit fields (algorithm and labels)
@@ -1237,48 +1240,6 @@ RRSIG::typeCovered() const {
return (impl_->covered_);
}
-} // end of namespace "generic"
-} // end of namespace "rdata"
-} // end of namespace "dns"
-} // end of namespace "isc"
-
-// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <exceptions/exceptions.h>
-
-#include <util/buffer.h>
-#include <dns/name.h>
-#include <dns/master_lexer.h>
-#include <dns/master_loader.h>
-#include <dns/master_loader_callbacks.h>
-#include <dns/messagerenderer.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-
-#include <dns/rdata/generic/detail/lexer_util.h>
-
-#include <boost/static_assert.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include <string>
-#include <sstream>
-
-using namespace std;
-using boost::lexical_cast;
-using namespace isc::util;
-using isc::dns::rdata::generic::detail::createNameFromLexer;
-
-namespace isc {
-namespace dns {
-namespace rdata {
-namespace generic {
-
SOA::SOA(InputBuffer& buffer, size_t) :
mname_(buffer), rname_(buffer) {
// we don't need rdata_len for parsing. if necessary, the caller will
@@ -1447,49 +1408,6 @@ SOA::compare(const Rdata& other) const {
return (memcmp(numdata_, other_soa.numdata_, sizeof(numdata_)));
}
-} // end of namespace "generic"
-} // end of namespace "rdata"
-} // end of namespace "dns"
-} // end of namespace "isc"
-
-// Copyright (C) 2021-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <string>
-#include <sstream>
-#include <vector>
-
-#include <boost/lexical_cast.hpp>
-
-#include <util/buffer.h>
-#include <util/encode/encode.h>
-#include <util/time_utilities.h>
-
-#include <dns/tsigerror.h>
-#include <dns/messagerenderer.h>
-#include <dns/name.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rcode.h>
-#include <dns/rdata/generic/detail/lexer_util.h>
-
-using namespace std;
-using boost::lexical_cast;
-using namespace isc::util;
-using namespace isc::util::encode;
-using namespace isc::dns;
-using isc::dns::rdata::generic::detail::createNameFromLexer;
-
-namespace isc {
-namespace dns {
-namespace rdata {
-namespace generic {
-
const uint16_t TKEY::GSS_API_MODE = 3;
// straightforward representation of TKEY RDATA fields
@@ -2061,46 +1979,72 @@ TKEY::getOtherData() const {
}
}
-} // end of namespace "generic"
-} // end of namespace "rdata"
-} // end of namespace "dns"
-} // end of namespace "isc"
-// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+TXT&
+TXT::operator=(const TXT& source) {
+ if (this == &source) {
+ return (*this);
+ }
-#include <config.h>
+ impl_.reset(new TXTImpl(*source.impl_));
-#include <stdint.h>
-#include <string.h>
+ return (*this);
+}
-#include <cerrno>
-#include <cstring>
-#include <string>
+TXT::~TXT() {
+}
-#include <arpa/inet.h> // XXX: for inet_pton/ntop(), not exist in C++ standards
-#include <sys/socket.h> // for AF_INET/AF_INET6
+TXT::TXT(InputBuffer& buffer, size_t rdata_len) :
+ impl_(new TXTImpl(buffer, rdata_len)) {
+}
-#include <exceptions/exceptions.h>
+/// \brief Constructor using the master lexer.
+///
+/// This implementation only uses the \c lexer parameters; others are
+/// ignored.
+///
+/// \throw CharStringTooLong the parameter string length exceeds maximum.
+/// \throw InvalidRdataText the method cannot process the parameter data
+///
+/// \param lexer A \c MasterLexer object parsing a master file for this
+/// RDATA.
+TXT::TXT(MasterLexer& lexer, const Name*, MasterLoader::Options,
+ MasterLoaderCallbacks&) :
+ impl_(new TXTImpl(lexer)) {
+}
-#include <util/buffer.h>
+TXT::TXT(const std::string& txtstr) :
+ impl_(new TXTImpl(txtstr)) {
+}
-#include <dns/exceptions.h>
-#include <dns/messagerenderer.h>
-#include <dns/master_lexer.h>
-#include <dns/master_loader_callbacks.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
+TXT::TXT(const TXT& other) :
+ Rdata(), impl_(new TXTImpl(*other.impl_)) {
+}
-using namespace std;
-using namespace isc::util;
+void
+TXT::toWire(OutputBuffer& buffer) const {
+ impl_->toWire(buffer);
+}
+
+void
+TXT::toWire(AbstractMessageRenderer& renderer) const {
+ impl_->toWire(renderer);
+}
+
+string
+TXT::toText() const {
+ return (impl_->toText());
+}
+
+int
+TXT::compare(const Rdata& other) const {
+ const TXT& other_txt = dynamic_cast<const TXT&>(other);
+
+ return (impl_->compare(*other_txt.impl_));
+}
+
+} // end of namespace "generic"
-namespace isc {
-namespace dns {
-namespace rdata {
namespace in {
namespace {
@@ -2239,44 +2183,6 @@ A::compare(const Rdata& other) const {
const A& other_a = dynamic_cast<const A&>(other);
return (memcmp(&addr_, &other_a.addr_, sizeof(addr_)));
}
-} // end of namespace "in"
-} // end of namespace "rdata"
-} // end of namespace "dns"
-} // end of namespace "isc"
-// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <exceptions/exceptions.h>
-#include <util/buffer.h>
-#include <dns/exceptions.h>
-#include <dns/messagerenderer.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/master_lexer.h>
-#include <dns/master_loader.h>
-
-#include <stdint.h>
-#include <string.h>
-
-#include <cerrno>
-#include <cstring>
-#include <string>
-
-#include <arpa/inet.h> // XXX: for inet_pton/ntop(), not exist in C++ standards
-#include <sys/socket.h> // for AF_INET/AF_INET6
-
-using namespace std;
-using namespace isc::util;
-
-namespace isc {
-namespace dns {
-namespace rdata {
-namespace in {
namespace {
void
@@ -2395,39 +2301,6 @@ AAAA::compare(const Rdata& other) const {
return (memcmp(&addr_, &other_a.addr_, sizeof(addr_)));
}
-} // end of namespace "in"
-} // end of namespace "rdata"
-} // end of namespace "dns"
-} // end of namespace "isc"
-// Copyright (C) 2011-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <stdint.h>
-#include <string.h>
-
-#include <exceptions/exceptions.h>
-
-#include <util/buffer.h>
-#include <util/encode/encode.h>
-#include <dns/exceptions.h>
-#include <dns/messagerenderer.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-
-using namespace std;
-using namespace isc::util;
-using namespace isc::util::encode;
-
-namespace isc {
-namespace dns {
-namespace rdata {
-namespace in {
-
void
DHCID::constructFromLexer(MasterLexer& lexer) {
string digest_txt = lexer.getNextToken(MasterToken::STRING).getString();
diff --git a/src/lib/dns/rdataclass.h b/src/lib/dns/rdataclass.h
index da60839f0d..25eaab8bc0 100644
--- a/src/lib/dns/rdataclass.h
+++ b/src/lib/dns/rdataclass.h
@@ -1,49 +1,33 @@
-///////////////
-///////////////
-/////////////// THIS FILE IS AUTOMATICALLY GENERATED BY gen-rdatacode.py.
-/////////////// DO NOT EDIT!
-///////////////
-///////////////
-
-#ifndef DNS_RDATACLASS_H
-#define DNS_RDATACLASS_H
-
-#include <dns/master_loader.h>
-
-namespace isc {
-namespace dns {
-class Name;
-class MasterLexer;
-class MasterLoaderCallbacks;
-}
-}
-// Copyright (C) 2010-2021 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#ifndef ANY_TSIG_250_H
-#define ANY_TSIG_250_H
-
-#include <stdint.h>
-
-#include <string>
+#ifndef DNS_RDATACLASS_H
+#define DNS_RDATACLASS_H
-#include <util/buffer.h>
+#include <dns/master_loader.h>
#include <dns/name.h>
#include <dns/rdata.h>
+#include <dns/rrttl.h>
+#include <dns/rrtype.h>
+#include <dns/serial.h>
+#include <util/buffer.h>
+
+#include <stdint.h>
+#include <string>
+#include <vector>
#include <boost/shared_ptr.hpp>
namespace isc {
namespace dns {
-// BEGIN_COMMON_DECLARATIONS
-
+class Name;
+class MasterLexer;
+class MasterLoaderCallbacks;
class AbstractMessageRenderer;
-// END_COMMON_DECLARATIONS
-
namespace rdata {
namespace any {
@@ -57,8 +41,6 @@ struct TSIGImpl;
/// TSIG RDATA.
class TSIG : public Rdata {
public:
- // BEGIN_COMMON_MEMBERS
-
explicit TSIG(const std::string& type_str);
TSIG(isc::util::InputBuffer& buffer, size_t rdata_len);
TSIG(const TSIG& other);
@@ -70,8 +52,6 @@ public:
virtual void toWire(AbstractMessageRenderer& renderer) const;
virtual int compare(const Rdata& other) const;
- // END_COMMON_MEMBERS
-
/// \brief Constructor from RDATA field parameters.
///
/// The parameters are a straightforward mapping of %TSIG RDATA
@@ -179,47 +159,71 @@ private:
};
} // end of namespace "any"
-} // end of namespace "rdata"
-} // end of namespace "dns"
-} // end of namespace "isc"
-#endif // ANY_TSIG_250_H
-
-// Copyright (C) 2010-2021 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef GENERIC_OPT_41_H
-#define GENERIC_OPT_41_H
-
-#include <string>
-#include <util/buffer.h>
-#include <dns/rdata.h>
-
-#include <boost/shared_ptr.hpp>
-
-#include <vector>
+namespace generic {
+namespace detail {
-namespace isc {
-namespace dns {
+/// \brief Construct a Name object using a master lexer and optional origin.
+///
+/// This is a convenient shortcut of commonly used code pattern that would
+/// be used to build RDATA that contain a domain name field.
+///
+/// Note that this function throws an exception against invalid input.
+/// The (direct or indirect) caller's responsibility needs to expect and
+/// handle exceptions appropriately.
+///
+/// \throw MasterLexer::LexerError The next token from lexer is not string.
+/// \throw Other Exceptions from the \c Name class constructor if the next
+/// string token from the lexer does not represent a valid name.
+///
+/// \param lexer A \c MasterLexer object. Its next token is expected to be
+/// a string that represent a domain name.
+/// \param origin If non NULL, specifies the origin of the name to be
+/// constructed.
+///
+/// \return A new Name object that corresponds to the next string token of
+/// the \c lexer.
+inline Name
+createNameFromLexer(MasterLexer& lexer, const Name* origin) {
+ const MasterToken::StringRegion& str_region =
+ lexer.getNextToken(MasterToken::STRING).getStringRegion();
+ return (Name(str_region.beg, str_region.len, origin));
+}
-// BEGIN_COMMON_DECLARATIONS
+template<class Type, uint16_t typeCode>
+class TXTLikeImpl;
-class AbstractMessageRenderer;
+} // namespace detail
-// END_COMMON_DECLARATIONS
+class NS : public Rdata {
+public:
+ explicit NS(const std::string& type_str);
+ NS(isc::util::InputBuffer& buffer, size_t rdata_len);
+ NS(const NS& other);
+ NS(
+ MasterLexer& lexer, const Name* name,
+ MasterLoader::Options options, MasterLoaderCallbacks& callbacks);
+ virtual std::string toText() const;
+ virtual void toWire(isc::util::OutputBuffer& buffer) const;
+ virtual void toWire(AbstractMessageRenderer& renderer) const;
+ virtual int compare(const Rdata& other) const;
-namespace rdata {
-namespace generic {
+ /// Specialized constructor
+ ///
+ explicit NS(const Name& nsname) : nsname_(nsname) {
+ }
+ ///
+ /// Specialized methods
+ ///
+ const Name& getNSName() const;
+private:
+ Name nsname_;
+};
struct OPTImpl;
class OPT : public Rdata {
public:
- // BEGIN_COMMON_MEMBERS
-
explicit OPT(const std::string& type_str);
OPT(isc::util::InputBuffer& buffer, size_t rdata_len);
OPT(const OPT& other);
@@ -231,8 +235,6 @@ public:
virtual void toWire(AbstractMessageRenderer& renderer) const;
virtual int compare(const Rdata& other) const;
- // END_COMMON_MEMBERS
-
// The default constructor makes sense for OPT as it can be empty.
OPT();
OPT& operator=(const OPT& source);
@@ -286,43 +288,8 @@ private:
boost::shared_ptr<OPTImpl> impl_;
};
-} // end of namespace "generic"
-} // end of namespace "rdata"
-} // end of namespace "dns"
-} // end of namespace "isc"
-#endif // GENERIC_OPT_41_H
-
-// Copyright (C) 2010-2021 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef GENERIC_PTR_12_H
-#define GENERIC_PTR_12_H
-
-#include <string>
-
-#include <util/buffer.h>
-#include <dns/name.h>
-#include <dns/rdata.h>
-
-namespace isc {
-namespace dns {
-
-// BEGIN_COMMON_DECLARATIONS
-
-class AbstractMessageRenderer;
-
-// END_COMMON_DECLARATIONS
-
-namespace rdata {
-namespace generic {
-
class PTR : public Rdata {
public:
- // BEGIN_COMMON_MEMBERS
-
explicit PTR(const std::string& type_str);
PTR(isc::util::InputBuffer& buffer, size_t rdata_len);
PTR(const PTR& other);
@@ -334,8 +301,6 @@ public:
virtual void toWire(AbstractMessageRenderer& renderer) const;
virtual int compare(const Rdata& other) const;
- // END_COMMON_MEMBERS
-
///
/// Specialized constructor
///
@@ -349,42 +314,6 @@ private:
Name ptr_name_;
};
-} // end of namespace "generic"
-} // end of namespace "rdata"
-} // end of namespace "dns"
-} // end of namespace "isc"
-#endif // GENERIC_PTR_12_H
-
-// Copyright (C) 2010-2021 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <stdint.h>
-
-#include <string>
-
-#include <dns/name.h>
-#include <dns/rrtype.h>
-#include <dns/rdata.h>
-#include <boost/shared_ptr.hpp>
-
-#ifndef GENERIC_RRSIG_46_H
-#define GENERIC_RRSIG_46_H
-
-namespace isc {
-namespace dns {
-
-// BEGIN_COMMON_DECLARATIONS
-
-class AbstractMessageRenderer;
-
-// END_COMMON_DECLARATIONS
-
-namespace rdata {
-namespace generic {
-
struct RRSIGImpl;
/// \brief \c rdata::RRSIG class represents the RRSIG RDATA as defined %in
@@ -395,8 +324,6 @@ struct RRSIGImpl;
/// RRSIG RDATA.
class RRSIG : public Rdata {
public:
- // BEGIN_COMMON_MEMBERS
-
explicit RRSIG(const std::string& type_str);
RRSIG(isc::util::InputBuffer& buffer, size_t rdata_len);
RRSIG(const RRSIG& other);
@@ -408,7 +335,6 @@ public:
virtual void toWire(AbstractMessageRenderer& renderer) const;
virtual int compare(const Rdata& other) const;
- // END_COMMON_MEMBERS
RRSIG& operator=(const RRSIG& source);
~RRSIG();
@@ -421,45 +347,8 @@ private:
boost::shared_ptr<RRSIGImpl> impl_;
};
-} // end of namespace "generic"
-} // end of namespace "rdata"
-} // end of namespace "dns"
-} // end of namespace "isc"
-#endif // GENERIC_RRSIG_46_H
-
-// Copyright (C) 2010-2021 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef GENERIC_SOA_6_H
-#define GENERIC_SOA_6_H
-
-#include <string>
-
-#include <dns/name.h>
-#include <dns/rdata.h>
-#include <dns/rrttl.h>
-#include <dns/serial.h>
-#include <util/buffer.h>
-
-namespace isc {
-namespace dns {
-
-// BEGIN_COMMON_DECLARATIONS
-
-class AbstractMessageRenderer;
-
-// END_COMMON_DECLARATIONS
-
-namespace rdata {
-namespace generic {
-
class SOA : public Rdata {
public:
- // BEGIN_COMMON_MEMBERS
-
explicit SOA(const std::string& type_str);
SOA(isc::util::InputBuffer& buffer, size_t rdata_len);
SOA(const SOA& other);
@@ -471,8 +360,6 @@ public:
virtual void toWire(AbstractMessageRenderer& renderer) const;
virtual int compare(const Rdata& other) const;
- // END_COMMON_MEMBERS
-
SOA(const Name& mname, const Name& rname, uint32_t serial,
uint32_t refresh, uint32_t retry, uint32_t expire,
uint32_t minimum);
@@ -491,43 +378,6 @@ private:
uint8_t numdata_[20];
};
-} // end of namespace "generic"
-} // end of namespace "rdata"
-} // end of namespace "dns"
-} // end of namespace "isc"
-#endif // GENERIC_SOA_6_H
-#endif // DNS_RDATACLASS_H
-
-// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef GENERIC_TKEY_249_H
-#define GENERIC_TKEY_249_H
-
-#include <stdint.h>
-
-#include <string>
-
-#include <util/buffer.h>
-#include <dns/name.h>
-#include <dns/rdata.h>
-#include <boost/shared_ptr.hpp>
-
-namespace isc {
-namespace dns {
-
-// BEGIN_COMMON_DECLARATIONS
-
-class AbstractMessageRenderer;
-
-// END_COMMON_DECLARATIONS
-
-namespace rdata {
-namespace generic {
-
struct TKEYImpl;
/// \brief \c rdata::TKEY class represents the TKEY RDATA as defined %in
@@ -538,8 +388,6 @@ struct TKEYImpl;
/// TKEY RDATA.
class TKEY : public Rdata {
public:
- // BEGIN_COMMON_MEMBERS
-
explicit TKEY(const std::string& type_str);
TKEY(isc::util::InputBuffer& buffer, size_t rdata_len);
TKEY(const TKEY& other);
@@ -551,8 +399,6 @@ public:
virtual void toWire(AbstractMessageRenderer& renderer) const;
virtual int compare(const Rdata& other) const;
- // END_COMMON_MEMBERS
-
/// \brief Constructor from RDATA field parameters.
///
/// The parameters are a straightforward mapping of %TKEY RDATA
@@ -653,42 +499,33 @@ private:
boost::shared_ptr<TKEYImpl> impl_;
};
-} // end of namespace "generic"
-} // end of namespace "rdata"
-} // end of namespace "dns"
-} // end of namespace "isc"
-#endif // GENERIC_TKEY_249_H
-
-// Copyright (C) 2010-2021 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef IN_A_1_H
-#define IN_A_1_H
-
-#include <string>
-
-#include <util/buffer.h>
-#include <dns/rdata.h>
-
-namespace isc {
-namespace dns {
+class TXT : public Rdata {
+public:
+ explicit TXT(const std::string& type_str);
+ TXT(isc::util::InputBuffer& buffer, size_t rdata_len);
+ TXT(const TXT& other);
+ TXT(
+ MasterLexer& lexer, const Name* name,
+ MasterLoader::Options options, MasterLoaderCallbacks& callbacks);
+ virtual std::string toText() const;
+ virtual void toWire(isc::util::OutputBuffer& buffer) const;
+ virtual void toWire(AbstractMessageRenderer& renderer) const;
+ virtual int compare(const Rdata& other) const;
-// BEGIN_COMMON_DECLARATIONS
+ TXT& operator=(const TXT& source);
+ ~TXT();
-class AbstractMessageRenderer;
+private:
+ typedef isc::dns::rdata::generic::detail::TXTLikeImpl<TXT, 16> TXTImpl;
+ boost::shared_ptr<TXTImpl> impl_;
+};
+} // namespace generic
-// END_COMMON_DECLARATIONS
-namespace rdata {
namespace in {
class A : public Rdata {
public:
- // BEGIN_COMMON_MEMBERS
-
explicit A(const std::string& type_str);
A(isc::util::InputBuffer& buffer, size_t rdata_len);
A(const A& other);
@@ -699,54 +536,12 @@ public:
virtual void toWire(isc::util::OutputBuffer& buffer) const;
virtual void toWire(AbstractMessageRenderer& renderer) const;
virtual int compare(const Rdata& other) const;
-
- // END_COMMON_MEMBERS
-
- //We can use the default destructor.
- //virtual ~A() {}
- // notyet:
- //const struct in_addr& getAddress() const { return (addr_); }
private:
uint32_t addr_; // raw IPv4 address (network byte order)
};
-} // end of namespace "in"
-} // end of namespace "rdata"
-} // end of namespace "dns"
-} // end of namespace "isc"
-#endif // IN_A_1_H
-
-// Copyright (C) 2010-2021 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef IN_AAAA_28_H
-#define IN_AAAA_28_H
-
-#include <stdint.h>
-
-#include <string>
-
-#include <util/buffer.h>
-#include <dns/rdata.h>
-
-namespace isc {
-namespace dns {
-
-// BEGIN_COMMON_DECLARATIONS
-
-class AbstractMessageRenderer;
-
-// END_COMMON_DECLARATIONS
-
-namespace rdata {
-namespace in {
class AAAA : public Rdata {
public:
- // BEGIN_COMMON_MEMBERS
-
explicit AAAA(const std::string& type_str);
AAAA(isc::util::InputBuffer& buffer, size_t rdata_len);
AAAA(const AAAA& other);
@@ -757,47 +552,10 @@ public:
virtual void toWire(isc::util::OutputBuffer& buffer) const;
virtual void toWire(AbstractMessageRenderer& renderer) const;
virtual int compare(const Rdata& other) const;
-
- // END_COMMON_MEMBERS
- // notyet:
- //const struct in6_addr& getAddress() const { return (addr_); }
private:
uint8_t addr_[16]; // raw IPv6 address (network byte order)
};
-} // end of namespace "in"
-} // end of namespace "rdata"
-} // end of namespace "dns"
-} // end of namespace "isc"
-#endif // IN_AAAA_28_H
-
-// Copyright (C) 2011-2021 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef IN_DHCID_49_H
-#define IN_DHCID_49_H
-
-#include <string>
-#include <vector>
-
-#include <util/buffer.h>
-#include <dns/rdata.h>
-
-namespace isc {
-namespace dns {
-
-// BEGIN_COMMON_DECLARATIONS
-
-class AbstractMessageRenderer;
-
-// END_COMMON_DECLARATIONS
-
-namespace rdata {
-namespace in {
-
/// \brief \c rdata::DHCID class represents the DHCID RDATA as defined %in
/// RFC4701.
///
@@ -806,8 +564,6 @@ namespace in {
/// DHCID RDATA.
class DHCID : public Rdata {
public:
- // BEGIN_COMMON_MEMBERS
-
explicit DHCID(const std::string& type_str);
DHCID(isc::util::InputBuffer& buffer, size_t rdata_len);
DHCID(const DHCID& other);
@@ -819,8 +575,6 @@ public:
virtual void toWire(AbstractMessageRenderer& renderer) const;
virtual int compare(const Rdata& other) const;
- // END_COMMON_MEMBERS
-
/// \brief Return the digest.
///
/// This method never throws an exception.
@@ -836,8 +590,9 @@ private:
///
std::vector<uint8_t> digest_;
};
+
} // end of namespace "in"
} // end of namespace "rdata"
} // end of namespace "dns"
} // end of namespace "isc"
-#endif // IN_DHCID_49_H
+#endif // DNS_RDATACLASS_H
diff --git a/src/lib/dns/rrclass-placeholder.h b/src/lib/dns/rrclass-placeholder.h
deleted file mode 100644
index a9c4ebda0b..0000000000
--- a/src/lib/dns/rrclass-placeholder.h
+++ /dev/null
@@ -1,315 +0,0 @@
-// Copyright (C) 2010-2017 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef RRCLASS_H
-#define RRCLASS_H
-
-#include <util/buffer.h>
-
-#include <stdint.h>
-
-#include <string>
-#include <ostream>
-
-#include <dns/exceptions.h>
-
-#include <boost/optional.hpp>
-
-// Undefine the macro IN which is defined in some operating systems
-// but conflicts the IN RR class.
-
-#ifdef IN
-#undef IN
-#endif
-
-namespace isc {
-
-namespace dns {
-
-// forward declarations
-class AbstractMessageRenderer;
-
-///
-/// \brief A standard DNS module exception that is thrown if an RRClass object
-/// is being constructed from an unrecognized string.
-///
-class InvalidRRClass : public DNSTextError {
-public:
- InvalidRRClass(const char* file, size_t line, const char* what) :
- DNSTextError(file, line, what) {}
-};
-
-///
-/// \brief A standard DNS module exception that is thrown if an RRClass object
-/// is being constructed from a incomplete (too short) wire-format data.
-///
-class IncompleteRRClass : public isc::dns::Exception {
-public:
- IncompleteRRClass(const char* file, size_t line, const char* what) :
- isc::dns::Exception(file, line, what) {}
-};
-
-///
-/// The \c RRClass class encapsulates DNS resource record classes.
-///
-/// This class manages the 16-bit integer class codes in quite a straightforward
-/// way. The only non trivial task is to handle textual representations of
-/// RR classes, such as "IN", "CH", or "CLASS65534".
-///
-/// This class consults a helper \c RRParamRegistry class, which is a registry
-/// of RR related parameters and has the singleton object. This registry
-/// provides a mapping between RR class codes and their "well-known" textual
-/// representations.
-/// Parameters of RR classes defined by DNS protocol standards are automatically
-/// registered at initialization time and are ensured to be always available for
-/// applications unless the application explicitly modifies the registry.
-///
-/// For convenience, this class defines constant class objects corresponding to
-/// standard RR classes. These are generally referred to as the form of
-/// <code>RRClass::{class-text}()</code>.
-/// For example, \c RRClass::IN() is an \c RRClass object corresponding to the
-/// IN class (class code 1).
-/// Note that these constants are used through a "proxy" function.
-/// This is because they may be used to initialize another non-local (e.g.
-/// global or namespace-scope) static object as follows:
-///
-/// \code
-/// namespace foo {
-/// const RRClass default_class = RRClass::IN();
-/// } \endcode
-///
-/// In order to ensure that the constant RRClass object has been initialized
-/// before the initialization for \c default_class, we need help from
-/// the proxy function.
-///
-/// Note to developers: same note as \c RRType applies.
-class RRClass {
-public:
- ///
- /// \name Constructors and Destructor
- ///
- //@{
- /// Constructor from an integer class code.
- ///
- /// This constructor never throws an exception.
- ///
- /// \param classcode An 16-bit integer code corresponding to the RRClass.
- explicit RRClass(uint16_t classcode) : classcode_(classcode) {}
- ///
- /// A valid string is one of "well-known" textual class representations
- /// such as "IN" or "CH", or in the standard format for "unknown"
- /// classes as defined in RFC3597, i.e., "CLASSnnnn".
- ///
- /// More precisely, the "well-known" representations are the ones stored
- /// in the \c RRParamRegistry registry (see the class description).
- ///
- /// As for the format of "CLASSnnnn", "nnnn" must represent a valid 16-bit
- /// unsigned integer, which may contain leading 0's as long as it consists
- /// of at most 5 characters (inclusive).
- /// For example, "CLASS1" and "CLASS0001" are valid and represent the same
- /// class, but "CLASS65536" and "CLASS000001" are invalid.
- /// A "CLASSnnnn" representation is valid even if the corresponding class
- /// code is registered in the \c RRParamRegistry object. For example, both
- /// "IN" and "CLASS1" are valid and represent the same class.
- ///
- /// All of these representations are case insensitive; "IN" and "in", and
- /// "CLASS1" and "class1" are all valid and represent the same classes,
- /// respectively.
- ///
- /// If the given string is not recognized as a valid representation of
- /// an RR class, an exception of class \c InvalidRRClass will be thrown.
- ///
- /// \param class_str A string representation of the \c RRClass
- explicit RRClass(const std::string& class_str);
- /// Constructor from wire-format data.
- ///
- /// The \c buffer parameter normally stores a complete DNS message
- /// containing the RRClass to be constructed. The current read position of
- /// the buffer points to the head of the class.
- ///
- /// If the given data does not large enough to contain a 16-bit integer,
- /// an exception of class \c IncompleteRRClass will be thrown.
- ///
- /// \param buffer A buffer storing the wire format data.
- explicit RRClass(isc::util::InputBuffer& buffer);
-
- /// A separate factory of RRClass from text.
- ///
- /// This static method is similar to the constructor that takes a
- /// string object, but works as a factory and reports parsing
- /// failure in the form of the return value. Normally the
- /// constructor version should suffice, but in some cases the caller
- /// may have to expect mixture of valid and invalid input, and may
- /// want to minimize the overhead of possible exception handling.
- /// This version is provided for such purpose.
- ///
- /// For the format of the \c class_str argument, see the
- /// <code>RRClass(const std::string&)</code> constructor.
- ///
- /// If the given text represents a valid RRClass, it returns a
- /// pointer to a new \c RRClass object. If the given text does not
- /// represent a valid RRClass, it returns \c NULL.
- ///
- /// One main purpose of this function is to minimize the overhead
- /// when the given text does not represent a valid RR class. For
- /// this reason this function intentionally omits the capability of
- /// delivering a detailed reason for the parse failure, such as in the
- /// \c want() string when exception is thrown from the constructor
- /// (it will internally require a creation of string object, which
- /// is relatively expensive). If such detailed information is
- /// necessary, the constructor version should be used to catch the
- /// resulting exception.
- ///
- /// This function never throws the \c InvalidRRClass exception.
- ///
- /// \param class_str A string representation of the \c RRClass.
- /// \return A new RRClass object for the given text or a \c NULL
- /// value.
- static RRClass* createFromText(const std::string& class_str);
-
- ///
- /// We use the default copy constructor intentionally.
- //@}
- /// We use the default copy assignment operator intentionally.
- ///
-
- ///
- /// \name Converter methods
- ///
- //@{
- /// \brief Convert the \c RRClass to a string.
- ///
- /// If a "well known" textual representation for the class code is
- /// registered in the RR parameter registry (see the class description),
- /// that will be used as the return value of this method. Otherwise, this
- /// method creates a new string for an "unknown" class in the format defined
- /// in RFC3597, i.e., "CLASSnnnn", and returns it.
- ///
- /// If resource allocation for the string fails, a corresponding standard
- /// exception will be thrown.
- ///
- /// \return A string representation of the \c RRClass.
- const std::string toText() const;
- /// \brief Render the \c RRClass in the wire format.
- ///
- /// This method renders the class code in network byte order via
- /// \c renderer, which encapsulates output buffer and other rendering
- /// contexts.
- ///
- /// If resource allocation in rendering process fails, a corresponding
- /// standard exception will be thrown.
- ///
- /// \param renderer DNS message rendering context that encapsulates the
- /// output buffer in which the RRClass is to be stored.
- void toWire(AbstractMessageRenderer& renderer) const;
- /// \brief Render the \c RRClass in the wire format.
- ///
- /// This method renders the class code in network byte order into the
- /// \c buffer.
- ///
- /// If resource allocation in rendering process fails, a corresponding
- /// standard exception will be thrown.
- ///
- /// \param buffer An output buffer to store the wire data.
- void toWire(isc::util::OutputBuffer& buffer) const;
- //@}
-
- ///
- /// \name Getter Methods
- ///
- //@{
- /// \brief Returns the RR class code as a 16-bit unsigned integer.
- ///
- /// This method never throws an exception.
- ///
- /// \return An 16-bit integer code corresponding to the RRClass.
- uint16_t getCode() const {
- return (classcode_);
- }
- //@}
-
- ///
- /// \name Comparison methods
- ///
- //@{
- /// \brief Return true iff two RRClasses are equal.
- ///
- /// Two RRClasses are equal iff their class codes are equal.
- ///
- /// This method never throws an exception.
- ///
- /// \param other the \c RRClass object to compare against.
- /// \return true if the two RRClasses are equal; otherwise false.
- bool equals(const RRClass& other) const {
- return (classcode_ == other.classcode_);
- }
- /// \brief Same as \c equals().
- bool operator==(const RRClass& other) const {
- return (equals(other));
- }
-
- /// \brief Return true iff two RRClasses are not equal.
- ///
- /// This method never throws an exception.
- ///
- /// \param other the \c RRClass object to compare against.
- /// \return true if the two RRClasses are not equal; otherwise false.
- bool nequals(const RRClass& other) const {
- return (classcode_ != other.classcode_);
- }
- /// \brief Same as \c nequals().
- bool operator!=(const RRClass& other) const {
- return (nequals(other));
- }
-
- /// \brief Less-than comparison for RRClass against \c other
- ///
- /// We define the less-than relationship based on their class codes;
- /// one RRClass is less than the other iff the code of the former is less
- /// than that of the other as unsigned integers.
- /// The relationship is meaningless in terms of DNS protocol; the only
- /// reason we define this method is that RRClass objects can be stored in
- /// STL containers without requiring user-defined less-than relationship.
- /// We therefore don't define other comparison operators.
- ///
- /// This method never throws an exception.
- ///
- /// \param other the \c RRClass object to compare against.
- /// \return true if \c this RRClass is less than the \c other; otherwise
- /// false.
- bool operator<(const RRClass& other) const {
- return (classcode_ < other.classcode_);
- }
-
- // BEGIN_WELL_KNOWN_CLASS_DECLARATIONS
- // END_WELL_KNOWN_CLASS_DECLARATIONS
-
-private:
- uint16_t classcode_;
-};
-
-// BEGIN_WELL_KNOWN_CLASS_DEFINITIONS
-// END_WELL_KNOWN_CLASS_DEFINITIONS
-
-///
-/// \brief Insert the \c RRClass as a string into stream.
-///
-/// This method convert the \c rrclass into a string and inserts it into the
-/// output stream \c os.
-///
-/// This function overloads the global operator<< to behave as described in
-/// ostream::operator<< but applied to \c RRClass objects.
-///
-/// \param os A \c std::ostream object on which the insertion operation is
-/// performed.
-/// \param rrclass The \c RRClass object output by the operation.
-/// \return A reference to the same \c std::ostream object referenced by
-/// parameter \c os after the insertion operation.
-std::ostream&
-operator<<(std::ostream& os, const RRClass& rrclass);
-}
-}
-#endif // RRCLASS_H
diff --git a/src/lib/dns/rrclass.cc b/src/lib/dns/rrclass.cc
index 4617a3e16a..b01f86ede1 100644
--- a/src/lib/dns/rrclass.cc
+++ b/src/lib/dns/rrclass.cc
@@ -6,21 +6,20 @@
#include <config.h>
-#include <stdint.h>
-
-#include <string>
-
#include <exceptions/exceptions.h>
-
-#include <util/buffer.h>
#include <dns/messagerenderer.h>
#include <dns/rrparamregistry.h>
#include <dns/rrclass.h>
+#include <util/buffer.h>
+
+#include <stdint.h>
+#include <string>
-using namespace std;
using namespace isc::dns;
using namespace isc::util;
+using namespace std;
+
namespace isc {
namespace dns {
diff --git a/src/lib/dns/rrclass.h b/src/lib/dns/rrclass.h
index b730971454..12d94f2ef3 100644
--- a/src/lib/dns/rrclass.h
+++ b/src/lib/dns/rrclass.h
@@ -1,11 +1,4 @@
-///////////////
-///////////////
-/////////////// THIS FILE IS AUTOMATICALLY GENERATED BY gen-rdatacode.py.
-/////////////// DO NOT EDIT!
-///////////////
-///////////////
-
-// Copyright (C) 2010-2021 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -295,6 +288,7 @@ public:
// BEGIN_WELL_KNOWN_CLASS_DECLARATIONS
static const RRClass& ANY();
static const RRClass& IN();
+ static const RRClass& CH();
static const RRClass& NONE();
// END_WELL_KNOWN_CLASS_DECLARATIONS
@@ -316,6 +310,12 @@ RRClass::IN() {
}
inline const RRClass&
+RRClass::CH() {
+ static RRClass rrclass(3);
+ return (rrclass);
+}
+
+inline const RRClass&
RRClass::NONE() {
static RRClass rrclass(254);
return (rrclass);
diff --git a/src/lib/dns/rrparamregistry-placeholder.cc b/src/lib/dns/rrparamregistry-placeholder.cc
deleted file mode 100644
index da46d12b70..0000000000
--- a/src/lib/dns/rrparamregistry-placeholder.cc
+++ /dev/null
@@ -1,538 +0,0 @@
-// Copyright (C) 2010-2022 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <cassert>
-#include <algorithm>
-#include <cctype>
-#include <functional>
-#include <map>
-#include <string>
-#include <sstream>
-#include <utility>
-
-#include <stdint.h>
-
-#include <boost/shared_ptr.hpp>
-
-#include <exceptions/exceptions.h>
-
-#include <dns/rrparamregistry.h>
-#include <dns/rrclass.h>
-#include <dns/rrtype.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-
-using namespace std;
-
-using namespace isc::util;
-using namespace isc::dns::rdata;
-
-namespace isc {
-namespace dns {
-
-namespace {
-///
-/// The following function and class are a helper to define case-insensitive
-/// equivalence relationship on strings. They are used in the mapping
-/// containers below.
-///
-bool
-CICharLess(char c1, char c2) {
- return (tolower(static_cast<unsigned char>(c1)) <
- tolower(static_cast<unsigned char>(c2)));
-}
-
-struct CIStringLess {
- bool operator()(const string& s1, const string& s2) const
- {
- return (lexicographical_compare(s1.begin(), s1.end(),
- s2.begin(), s2.end(), CICharLess));
- }
-};
-
-struct RRTypeParam {
- RRTypeParam(const string& code_string, uint16_t code) :
- code_string_(code_string), code_(code) {}
- string code_string_;
- uint16_t code_;
-
- /// magic constants
- static const unsigned int MAX_CODE = 0xffff;
- static const string& UNKNOWN_PREFIX();
- static size_t UNKNOWN_PREFIXLEN();
- static const string& UNKNOWN_MAX();
- static size_t UNKNOWN_MAXLEN();
-};
-
-typedef boost::shared_ptr<RRTypeParam> RRTypeParamPtr;
-typedef map<string, RRTypeParamPtr, CIStringLess> StrRRTypeMap;
-typedef map<uint16_t, RRTypeParamPtr> CodeRRTypeMap;
-
-inline const string&
-RRTypeParam::UNKNOWN_PREFIX() {
- static const string p("TYPE");
- return (p);
-}
-
-inline size_t
-RRTypeParam::UNKNOWN_PREFIXLEN() {
- static size_t plen = UNKNOWN_PREFIX().size();
- return (plen);
-}
-
-inline const string&
-RRTypeParam::UNKNOWN_MAX() {
- static const string p("TYPE65535");
- return (p);
-}
-
-inline size_t
-RRTypeParam::UNKNOWN_MAXLEN() {
- static size_t plen = UNKNOWN_MAX().size();
- return (plen);
-}
-
-struct RRClassParam {
- RRClassParam(const string& code_string, uint16_t code) :
- code_string_(code_string), code_(code) {}
- string code_string_;
- uint16_t code_;
-
- /// magic constants
- static const unsigned int MAX_CODE = 0xffff;
- static const string& UNKNOWN_PREFIX();
- static size_t UNKNOWN_PREFIXLEN();
- static const string& UNKNOWN_MAX();
- static size_t UNKNOWN_MAXLEN();
-};
-
-typedef boost::shared_ptr<RRClassParam> RRClassParamPtr;
-typedef map<string, RRClassParamPtr, CIStringLess> StrRRClassMap;
-typedef map<uint16_t, RRClassParamPtr> CodeRRClassMap;
-
-inline const string&
-RRClassParam::UNKNOWN_PREFIX() {
- static const string p("CLASS");
- return (p);
-}
-
-inline size_t
-RRClassParam::UNKNOWN_PREFIXLEN() {
- static size_t plen = UNKNOWN_PREFIX().size();
- return (plen);
-}
-
-inline const string&
-RRClassParam::UNKNOWN_MAX() {
- static const string p("CLASS65535");
- return (p);
-}
-
-inline size_t
-RRClassParam::UNKNOWN_MAXLEN() {
- static size_t plen = UNKNOWN_MAX().size();
- return (plen);
-}
-} // end of anonymous namespace
-
-/// Note: the element ordering in the type/class pair is intentional.
-/// The standard library will perform inequality comparison (i.e, '<')
-/// in the way that the second elements (RRClass) are compared only when
-/// the first elements are equivalent.
-/// In practice, when we compare two pairs of RRType and RRClass, RRClass
-/// would be the same (and, in particular, be class IN) in the majority of
-/// cases. So this comparison ordering should be more efficient in common
-/// cases.
-typedef pair<RRType, RRClass> RRTypeClass;
-typedef map<RRTypeClass, RdataFactoryPtr> RdataFactoryMap;
-typedef map<RRType, RdataFactoryPtr> GenericRdataFactoryMap;
-
-template <typename T>
-class RdataFactory : public AbstractRdataFactory {
-public:
- virtual RdataPtr create(const string& rdata_str) const {
- return (RdataPtr(new T(rdata_str)));
- }
-
- virtual RdataPtr create(InputBuffer& buffer, size_t rdata_len) const {
- return (RdataPtr(new T(buffer, rdata_len)));
- }
-
- virtual RdataPtr create(const Rdata& source) const {
- return (RdataPtr(new T(dynamic_cast<const T&>(source))));
- }
-
- virtual RdataPtr create(MasterLexer& lexer, const Name* origin,
- MasterLoader::Options options,
- MasterLoaderCallbacks& callbacks) const {
- return (RdataPtr(new T(lexer, origin, options, callbacks)));
- }
-};
-
-///
-/// \brief The \c RRParamRegistryImpl class is the actual implementation of
-/// \c RRParamRegistry.
-///
-/// The implementation is hidden from applications. We can refer to specific
-/// members of this class only within the implementation source file.
-///
-struct RRParamRegistryImpl {
- /// Mappings from RR type codes to textual representations.
- StrRRTypeMap str2typemap;
- /// Mappings from textual representations of RR types to integer codes.
- CodeRRTypeMap code2typemap;
- /// Mappings from RR class codes to textual representations.
- StrRRClassMap str2classmap;
- /// Mappings from textual representations of RR classes to integer codes.
- CodeRRClassMap code2classmap;
- RdataFactoryMap rdata_factories;
- GenericRdataFactoryMap genericrdata_factories;
-};
-
-RRParamRegistry::RRParamRegistry() : impl_(new RRParamRegistryImpl()) { // set up parameters for well-known RRs
- try {
- // BEGIN_WELL_KNOWN_PARAMS
- // END_WELL_KNOWN_PARAMS
- } catch (...) {
- throw;
- }
-}
-
-RRParamRegistry::~RRParamRegistry() {
-}
-
-RRParamRegistry&
-RRParamRegistry::getRegistry() {
- static RRParamRegistry registry;
-
- return (registry);
-}
-
-void
-RRParamRegistry::add(const std::string& typecode_string, uint16_t typecode,
- RdataFactoryPtr rdata_factory)
-{
- bool type_added = false;
- try {
- type_added = addType(typecode_string, typecode);
- impl_->genericrdata_factories.insert(pair<RRType, RdataFactoryPtr>(
- RRType(typecode),
- rdata_factory));
- } catch (...) {
- if (type_added) {
- removeType(typecode);
- }
- throw;
- }
-}
-
-void
-RRParamRegistry::add(const std::string& typecode_string, uint16_t typecode,
- const std::string& classcode_string, uint16_t classcode,
- RdataFactoryPtr rdata_factory)
-{
- // Rollback logic on failure is complicated. If adding the new type or
- // class fails, we should revert to the original state, cleaning up
- // intermediate state. But we need to make sure that we don't remove
- // existing data. addType()/addClass() will simply ignore an attempt to
- // add the same data, so the cleanup should be performed only when we add
- // something new but we fail in other part of the process.
- bool type_added = false;
- bool class_added = false;
-
- try {
- type_added = addType(typecode_string, typecode);
- class_added = addClass(classcode_string, classcode);
- impl_->rdata_factories.insert(pair<RRTypeClass, RdataFactoryPtr>(
- RRTypeClass(RRType(typecode),
- RRClass(classcode)),
- rdata_factory));
- } catch (...) {
- if (type_added) {
- removeType(typecode);
- }
- if (class_added) {
- removeClass(classcode);
- }
- throw;
- }
-}
-
-bool
-RRParamRegistry::removeRdataFactory(const RRType& rrtype,
- const RRClass& rrclass) {
- RdataFactoryMap::iterator found =
- impl_->rdata_factories.find(RRTypeClass(rrtype, rrclass));
- if (found != impl_->rdata_factories.end()) {
- impl_->rdata_factories.erase(found);
- return (true);
- }
-
- return (false);
-}
-
-bool
-RRParamRegistry::removeRdataFactory(const RRType& rrtype) {
- GenericRdataFactoryMap::iterator found =
- impl_->genericrdata_factories.find(rrtype);
- if (found != impl_->genericrdata_factories.end()) {
- impl_->genericrdata_factories.erase(found);
- return (true);
- }
-
- return (false);
-}
-
-namespace {
-///
-/// These are helper functions to implement case-insensitive string comparison.
-/// This could be simplified using strncasecmp(), but unfortunately it's not
-/// included in <cstring>. To be as much as portable within the C++ standard
-/// we take the "in house" approach here.
-///
-bool CICharEqual(char c1, char c2) {
- return (tolower(static_cast<unsigned char>(c1)) ==
- tolower(static_cast<unsigned char>(c2)));
-}
-
-bool
-caseStringEqual(const string& s1, const string& s2, size_t n) {
- assert(s1.size() >= n && s2.size() >= n);
-
- return (mismatch(s1.begin(), s1.begin() + n, s2.begin(), CICharEqual).first
- == s1.begin() + n);
-}
-
-/// Code logic for RRTypes and RRClasses is mostly common except (C++) type and
-/// member names. So we define type-independent templates to describe the
-/// common logic and let concrete classes use it to avoid code duplicates.
-/// The following summarize template parameters used in the set of template
-/// functions:
-/// PT: parameter type, either RRTypeParam or RRClassParam
-/// MC: type of mapping class from code: either CodeRRTypeMap or CodeRRClassMap
-/// MS: type of mapping class from string: either StrRRTypeMap or StrRRClassMap
-/// ET: exception type for error handling: either InvalidRRType or
-/// InvalidRRClass
-template <typename PT, typename MC, typename MS, typename ET>
-inline bool
-addParam(const string& code_string, uint16_t code, MC& codemap, MS& stringmap) {
- // Duplicate type check
- typename MC::const_iterator found = codemap.find(code);
- if (found != codemap.end()) {
- if (found->second->code_string_ != code_string) {
- isc_throw(ET, "Duplicate RR parameter registration");
- }
- return (false);
- }
-
- typedef boost::shared_ptr<PT> ParamPtr;
- typedef pair<string, ParamPtr> StrParamPair;
- typedef pair<uint16_t, ParamPtr> CodeParamPair;
- ParamPtr param = ParamPtr(new PT(code_string, code));
- try {
- stringmap.insert(StrParamPair(code_string, param));
- codemap.insert(CodeParamPair(code, param));
- } catch (...) {
- // Rollback to the previous state: not all of the erase operations will
- // find the entry, but we don't care.
- stringmap.erase(code_string);
- codemap.erase(code);
- throw;
- }
-
- return (true);
-}
-
-template <typename MC, typename MS>
-inline bool
-removeParam(uint16_t code, MC& codemap, MS& stringmap) {
- typename MC::iterator found = codemap.find(code);
-
- if (found != codemap.end()) {
- size_t erased = stringmap.erase(found->second->code_string_);
- // We must have a corresponding entry of the str2 map exists
- assert(erased == 1);
-
- codemap.erase(found);
-
- return (true);
- }
-
- return (false);
-}
-
-template <typename PT, typename MS>
-inline bool
-textToCode(const string& code_str, MS& stringmap, uint16_t& ret_code) {
- typename MS::const_iterator found;
-
- found = stringmap.find(code_str);
- if (found != stringmap.end()) {
- ret_code = found->second->code_;
- return (true);
- }
-
- size_t l = code_str.size();
- if (l > PT::UNKNOWN_PREFIXLEN() &&
- l <= PT::UNKNOWN_MAXLEN() &&
- caseStringEqual(code_str, PT::UNKNOWN_PREFIX(),
- PT::UNKNOWN_PREFIXLEN())) {
- unsigned int code;
- istringstream iss(code_str.substr(PT::UNKNOWN_PREFIXLEN(),
- l - PT::UNKNOWN_PREFIXLEN()));
- iss >> dec >> code;
- if (iss.rdstate() == ios::eofbit && code <= PT::MAX_CODE) {
- ret_code = code;
- return (true);
- }
- }
-
- return (false);
-}
-
-template <typename PT, typename MC>
-inline string
-codeToText(uint16_t code, MC& codemap) {
- typename MC::const_iterator found;
-
- found = codemap.find(code);
- if (found != codemap.end()) {
- return (found->second->code_string_);
- }
-
- ostringstream ss;
- ss << code;
- return (PT::UNKNOWN_PREFIX() + ss.str());
-}
-}
-
-bool
-RRParamRegistry::addType(const string& type_string, uint16_t code) {
- return (addParam<RRTypeParam, CodeRRTypeMap, StrRRTypeMap, RRTypeExists>
- (type_string, code, impl_->code2typemap, impl_->str2typemap));
-}
-
-bool
-RRParamRegistry::removeType(uint16_t code) {
- return (removeParam<CodeRRTypeMap, StrRRTypeMap>(code, impl_->code2typemap,
- impl_->str2typemap));
-}
-
-bool
-RRParamRegistry::textToTypeCode(const string& type_string,
- uint16_t& type_code) const {
- return (textToCode<RRTypeParam, StrRRTypeMap>
- (type_string, impl_->str2typemap, type_code));
-}
-
-string
-RRParamRegistry::codeToTypeText(uint16_t code) const {
- return (codeToText<RRTypeParam, CodeRRTypeMap>(code, impl_->code2typemap));
-}
-
-bool
-RRParamRegistry::addClass(const string& class_string, uint16_t code) {
- return (addParam<RRClassParam, CodeRRClassMap, StrRRClassMap, RRClassExists>
- (class_string, code, impl_->code2classmap, impl_->str2classmap));
-}
-
-bool
-RRParamRegistry::removeClass(uint16_t code) {
- return (removeParam<CodeRRClassMap, StrRRClassMap>(code,
- impl_->code2classmap,
- impl_->str2classmap));
-}
-
-bool
-RRParamRegistry::textToClassCode(const string& class_string,
- uint16_t& class_code) const {
- return (textToCode<RRClassParam, StrRRClassMap>
- (class_string, impl_->str2classmap, class_code));
-}
-
-string
-RRParamRegistry::codeToClassText(uint16_t code) const {
- return (codeToText<RRClassParam, CodeRRClassMap>(code,
- impl_->code2classmap));
-}
-
-namespace {
-inline const AbstractRdataFactory*
-findRdataFactory(RRParamRegistryImpl* reg_impl,
- const RRType& rrtype, const RRClass& rrclass) {
- RdataFactoryMap::const_iterator found;
- found = reg_impl->rdata_factories.find(RRTypeClass(rrtype, rrclass));
- if (found != reg_impl->rdata_factories.end()) {
- return (found->second.get());
- }
-
- GenericRdataFactoryMap::const_iterator genfound =
- reg_impl->genericrdata_factories.find(rrtype);
- if (genfound != reg_impl->genericrdata_factories.end()) {
- return (genfound->second.get());
- }
-
- return (NULL);
-}
-}
-
-RdataPtr
-RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
- const std::string& rdata_string) {
- // If the text indicates that it's rdata of an "unknown" type (beginning
- // with '\# n'), parse it that way. (TBD)
-
- const AbstractRdataFactory* factory =
- findRdataFactory(impl_, rrtype, rrclass);
- if (factory != NULL) {
- return (factory->create(rdata_string));
- }
-
- return (RdataPtr(new generic::Generic(rdata_string)));
-}
-
-RdataPtr
-RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
- InputBuffer& buffer, size_t rdata_len) {
- const AbstractRdataFactory* factory =
- findRdataFactory(impl_, rrtype, rrclass);
- if (factory != NULL) {
- return (factory->create(buffer, rdata_len));
- }
-
- return (RdataPtr(new generic::Generic(buffer, rdata_len)));
-}
-
-RdataPtr
-RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
- const Rdata& source) {
- const AbstractRdataFactory* factory =
- findRdataFactory(impl_, rrtype, rrclass);
- if (factory != NULL) {
- return (factory->create(source));
- }
-
- return (RdataPtr(new rdata::generic::Generic(
- dynamic_cast<const generic::Generic&>(source))));
-}
-
-RdataPtr
-RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
- MasterLexer& lexer, const Name* name,
- MasterLoader::Options options,
- MasterLoaderCallbacks& callbacks) {
- const AbstractRdataFactory* factory =
- findRdataFactory(impl_, rrtype, rrclass);
- if (factory != NULL) {
- return (factory->create(lexer, name, options, callbacks));
- }
-
- return (RdataPtr(new generic::Generic(lexer, name, options, callbacks)));
-}
-}
-}
diff --git a/src/lib/dns/rrparamregistry.cc b/src/lib/dns/rrparamregistry.cc
index 91a0e5420c..612878b522 100644
--- a/src/lib/dns/rrparamregistry.cc
+++ b/src/lib/dns/rrparamregistry.cc
@@ -1,46 +1,34 @@
-// Copyright (C) 2010-2022 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-/// @file rrparamregistry.cc
-///
-/// THIS FILE USED TO BE AUTOMATICALLY GENERATED BY gen-rdatacode.py.
-/// Once this library was taken over by Kea project, we do not develop
-/// the DNS capabilities anymore, as Kea focuses on DHCP, not DNS.
-/// As such, we stopped adding new RR types as those we have are
-/// sufficient. Therefore it's unlikely this file will ever be
-/// regenerated.
-
#include <config.h>
+#include <exceptions/exceptions.h>
+#include <dns/rrparamregistry.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+
#include <cassert>
#include <algorithm>
#include <cctype>
#include <functional>
#include <map>
+#include <stdint.h>
#include <string>
#include <sstream>
#include <utility>
-
-#include <stdint.h>
-
#include <boost/shared_ptr.hpp>
-#include <exceptions/exceptions.h>
-
-#include <dns/rrparamregistry.h>
-#include <dns/rrclass.h>
-#include <dns/rrtype.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-
-using namespace std;
-
using namespace isc::util;
using namespace isc::dns::rdata;
+using namespace std;
+
namespace isc {
namespace dns {
@@ -208,21 +196,26 @@ RRParamRegistry::RRParamRegistry() : impl_(new RRParamRegistryImpl()) {
try {
// BEGIN_WELL_KNOWN_PARAMS
add("A", 1, "IN", 1, RdataFactoryPtr(new RdataFactory<in::A>()));
+ add("NS", 2, "IN", 1, RdataFactoryPtr(new RdataFactory<generic::NS>()));
add("SOA", 6, "IN", 1, RdataFactoryPtr(new RdataFactory<generic::SOA>()));
add("PTR", 12, "IN", 1, RdataFactoryPtr(new RdataFactory<generic::PTR>()));
+ add("TXT", 16, "IN", 1, RdataFactoryPtr(new RdataFactory<generic::TXT>()));
add("AAAA", 28, "IN", 1, RdataFactoryPtr(new RdataFactory<in::AAAA>()));
add("OPT", 41, "IN", 1, RdataFactoryPtr(new RdataFactory<generic::OPT>()));
add("RRSIG", 46, "IN", 1, RdataFactoryPtr(new RdataFactory<generic::RRSIG>()));
add("DHCID", 49, "IN", 1, RdataFactoryPtr(new RdataFactory<in::DHCID>()));
add("TKEY", 249, "IN", 1, RdataFactoryPtr(new RdataFactory<generic::TKEY>()));
add("TSIG", 250, "ANY", 255, RdataFactoryPtr(new RdataFactory<any::TSIG>()));
+ add("NS", 2, RdataFactoryPtr(new RdataFactory<generic::NS>()));
add("SOA", 6, RdataFactoryPtr(new RdataFactory<generic::SOA>()));
add("PTR", 12, RdataFactoryPtr(new RdataFactory<generic::PTR>()));
+ add("TXT", 16, RdataFactoryPtr(new RdataFactory<generic::TXT>()));
add("OPT", 41, RdataFactoryPtr(new RdataFactory<generic::OPT>()));
add("RRSIG", 46, RdataFactoryPtr(new RdataFactory<generic::RRSIG>()));
add("TKEY", 249, RdataFactoryPtr(new RdataFactory<generic::TKEY>()));
addType("ANY", 255);
// Meta classes
+ addClass("CH", 3);
addClass("NONE", 254);
// END_WELL_KNOWN_PARAMS
} catch (...) {
diff --git a/src/lib/dns/rrparamregistry.h b/src/lib/dns/rrparamregistry.h
index 36aa1e6b45..578b5ab3e9 100644
--- a/src/lib/dns/rrparamregistry.h
+++ b/src/lib/dns/rrparamregistry.h
@@ -94,7 +94,8 @@ public:
/// \c Rdata to parse.
/// \param rdata_len The length in buffer of the \c Rdata. In bytes.
/// \return An \c RdataPtr object pointing to the created \c Rdata object.
- virtual RdataPtr create(isc::util::InputBuffer& buffer, size_t rdata_len) const = 0;
+ virtual RdataPtr create(isc::util::InputBuffer& buffer,
+ size_t rdata_len) const = 0;
/// \brief Create RDATA from another \c Rdata object of the same type.
///
diff --git a/src/lib/dns/rrset.cc b/src/lib/dns/rrset.cc
index 5458279197..1ab3bde031 100644
--- a/src/lib/dns/rrset.cc
+++ b/src/lib/dns/rrset.cc
@@ -6,25 +6,25 @@
#include <config.h>
-#include <algorithm>
-#include <string>
-#include <vector>
-
-#include <boost/shared_ptr.hpp>
-
-#include <util/buffer.h>
#include <dns/messagerenderer.h>
#include <dns/name.h>
#include <dns/rrclass.h>
#include <dns/rrtype.h>
#include <dns/rrttl.h>
#include <dns/rrset.h>
+#include <util/buffer.h>
+
+#include <algorithm>
+#include <string>
+#include <vector>
+#include <boost/shared_ptr.hpp>
-using namespace std;
using namespace isc::dns;
using namespace isc::util;
using namespace isc::dns::rdata;
+using namespace std;
+
namespace isc {
namespace dns {
void
@@ -70,9 +70,9 @@ namespace { // unnamed namespace
// FIXME: This method's code should somehow be unified with
// BasicRRsetImpl::toWire() below to avoid duplication.
template <typename T>
-inline unsigned int
+inline uint32_t
rrsetToWire(const AbstractRRset& rrset, T& output, const size_t limit) {
- unsigned int n = 0;
+ uint32_t n = 0;
RdataIteratorPtr it = rrset.getRdataIterator();
if (it->isLast()) {
@@ -124,14 +124,14 @@ rrsetToWire(const AbstractRRset& rrset, T& output, const size_t limit) {
} // end of unnamed namespace
-unsigned int
+uint32_t
AbstractRRset::toWire(OutputBuffer& buffer) const {
return (rrsetToWire<OutputBuffer>(*this, buffer, 0));
}
-unsigned int
+uint32_t
AbstractRRset::toWire(AbstractMessageRenderer& renderer) const {
- const unsigned int rrs_written = rrsetToWire<AbstractMessageRenderer>(
+ const uint32_t rrs_written = rrsetToWire<AbstractMessageRenderer>(
*this, renderer, renderer.getLengthLimit());
if (getRdataCount() > rrs_written) {
renderer.setTruncated();
@@ -163,7 +163,7 @@ public:
const RRType& rrtype, const RRTTL& ttl) :
name_(name), rrclass_(rrclass), rrtype_(rrtype), ttl_(ttl) {}
- unsigned int toWire(AbstractMessageRenderer& renderer, size_t limit) const;
+ uint32_t toWire(AbstractMessageRenderer& renderer, size_t limit) const;
Name name_;
RRClass rrclass_;
@@ -177,7 +177,7 @@ public:
// FIXME: This method's code should somehow be unified with
// rrsetToWire() above to avoid duplication.
-unsigned int
+uint32_t
BasicRRsetImpl::toWire(AbstractMessageRenderer& renderer, size_t limit) const {
if (rdatalist_.empty()) {
// empty rrsets are only allowed for classes ANY and NONE
@@ -197,7 +197,7 @@ BasicRRsetImpl::toWire(AbstractMessageRenderer& renderer, size_t limit) const {
return (1);
}
- unsigned int n = 0;
+ uint32_t n = 0;
// sort the set of Rdata based on rrset-order and sortlist, and possible
// other options. Details to be considered.
@@ -250,7 +250,7 @@ BasicRRset::addRdata(const std::string& rdata_str) {
addRdata(createRdata(getType(), getClass(), rdata_str));
}
-unsigned int
+uint32_t
BasicRRset::getRdataCount() const {
return (impl_->rdatalist_.size());
}
@@ -329,14 +329,14 @@ BasicRRset::getLength() const {
return (length);
}
-unsigned int
+uint32_t
BasicRRset::toWire(OutputBuffer& buffer) const {
return (AbstractRRset::toWire(buffer));
}
-unsigned int
+uint32_t
BasicRRset::toWire(AbstractMessageRenderer& renderer) const {
- const unsigned int rrs_written = impl_->toWire(renderer,
+ const uint32_t rrs_written = impl_->toWire(renderer,
renderer.getLengthLimit());
if (impl_->rdatalist_.size() > rrs_written) {
renderer.setTruncated();
@@ -345,14 +345,14 @@ BasicRRset::toWire(AbstractMessageRenderer& renderer) const {
}
RRset::RRset(const Name& name, const RRClass& rrclass,
- const RRType& rrtype, const RRTTL& ttl) :
+ const RRType& rrtype, const RRTTL& ttl) :
BasicRRset(name, rrclass, rrtype, ttl) {
}
RRset::~RRset() {
}
-unsigned int
+uint32_t
RRset::getRRsigDataCount() const {
if (rrsig_) {
return (rrsig_->getRdataCount());
@@ -376,9 +376,9 @@ RRset::getLength() const {
return (length);
}
-unsigned int
+uint32_t
RRset::toWire(OutputBuffer& buffer) const {
- unsigned int rrs_written = BasicRRset::toWire(buffer);
+ uint32_t rrs_written = BasicRRset::toWire(buffer);
if (getRdataCount() > rrs_written) {
return (rrs_written);
}
@@ -390,9 +390,9 @@ RRset::toWire(OutputBuffer& buffer) const {
return (rrs_written);
}
-unsigned int
+uint32_t
RRset::toWire(AbstractMessageRenderer& renderer) const {
- unsigned int rrs_written = BasicRRset::toWire(renderer);
+ uint32_t rrs_written = BasicRRset::toWire(renderer);
if (getRdataCount() > rrs_written) {
return (rrs_written);
}
diff --git a/src/lib/dns/rrset.h b/src/lib/dns/rrset.h
index ece89697ad..26b92eec23 100644
--- a/src/lib/dns/rrset.h
+++ b/src/lib/dns/rrset.h
@@ -16,12 +16,9 @@
#include <dns/rdata.h>
#include <dns/rrtype.h>
+#include <util/buffer.h>
namespace isc {
-namespace util {
-class OututBuffer;
-}
-
namespace dns {
///
@@ -196,7 +193,7 @@ public:
/// this method may return 0.
///
/// \return The number of \c Rdata objects contained.
- virtual unsigned int getRdataCount() const = 0;
+ virtual uint32_t getRdataCount() const = 0;
/// \brief Get the wire format length of the \c AbstractRRset.
///
@@ -316,7 +313,7 @@ public:
/// \return The number of RRs rendered. If the truncation is necessary
/// this value may be different from the number of RDATA objects contained
/// in the RRset.
- virtual unsigned int toWire(AbstractMessageRenderer& renderer) const = 0;
+ virtual uint32_t toWire(AbstractMessageRenderer& renderer) const = 0;
/// \brief Render the RRset in the wire format without any compression.
///
@@ -324,7 +321,7 @@ public:
///
/// \param buffer An output buffer to store the wire data.
/// \return The number of RRs rendered.
- virtual unsigned int toWire(isc::util::OutputBuffer& buffer) const = 0;
+ virtual uint32_t toWire(isc::util::OutputBuffer& buffer) const = 0;
//@}
///
@@ -450,7 +447,7 @@ public:
/// method may return 0.
///
/// \return The number of \c RRSIG records associated.
- virtual unsigned int getRRsigDataCount() const = 0;
+ virtual uint32_t getRRsigDataCount() const = 0;
/// \brief Adds RRSIG RRset RRs to the associated RRSIG RRset
///
@@ -664,7 +661,7 @@ public:
/// This method never throws an exception.
///
/// \return The number of \c Rdata objects contained.
- virtual unsigned int getRdataCount() const;
+ virtual uint32_t getRdataCount() const;
/// \brief Get the wire format length of the \c BasicRRset.
///
@@ -729,13 +726,13 @@ public:
///
/// This method simply uses the default implementation.
/// See \c AbstractRRset::toWire(MessageRenderer&)const.
- virtual unsigned int toWire(AbstractMessageRenderer& renderer) const;
+ virtual uint32_t toWire(AbstractMessageRenderer& renderer) const;
/// \brief Render the RRset in the wire format without any compression.
///
/// This method simply uses the default implementation.
/// See \c AbstractRRset::toWire(OutputBuffer&)const.
- virtual unsigned int toWire(isc::util::OutputBuffer& buffer) const;
+ virtual uint32_t toWire(isc::util::OutputBuffer& buffer) const;
//@}
///
@@ -801,7 +798,7 @@ public:
///
/// \return Always returns 0. Associated RRSIG RRsets are not
/// supported in this class.
- virtual unsigned int getRRsigDataCount() const {
+ virtual uint32_t getRRsigDataCount() const {
return (0);
}
@@ -862,12 +859,12 @@ public:
/// truncation handling.
///
/// See \c AbstractRRset::toWire(MessageRenderer&)const.
- virtual unsigned int toWire(AbstractMessageRenderer& renderer) const;
+ virtual uint32_t toWire(AbstractMessageRenderer& renderer) const;
/// \brief Render the RRset in the wire format without any compression.
///
/// See \c AbstractRRset::toWire(OutputBuffer&)const.
- virtual unsigned int toWire(isc::util::OutputBuffer& buffer) const;
+ virtual uint32_t toWire(isc::util::OutputBuffer& buffer) const;
/// \brief Updates the owner name of the \c RRset, including RRSIGs if any
virtual void setTTL(const RRTTL& ttl) {
@@ -927,7 +924,7 @@ public:
/// method may return 0.
///
/// \return The number of \c RRSIG records associated.
- virtual unsigned int getRRsigDataCount() const;
+ virtual uint32_t getRRsigDataCount() const;
private:
RRsetPtr rrsig_;
diff --git a/src/lib/dns/rrttl.cc b/src/lib/dns/rrttl.cc
index 83877c74ed..8d9a7112d0 100644
--- a/src/lib/dns/rrttl.cc
+++ b/src/lib/dns/rrttl.cc
@@ -6,18 +6,17 @@
#include <config.h>
-#include <stdint.h>
-
-#include <sstream>
-#include <ostream>
-
-#include <util/buffer.h>
#include <dns/messagerenderer.h>
#include <dns/rrttl.h>
+#include <util/buffer.h>
-#include <boost/lexical_cast.hpp>
#include <algorithm>
#include <cctype>
+#include <stdint.h>
+#include <sstream>
+#include <ostream>
+
+#include <boost/lexical_cast.hpp>
using namespace std;
using namespace isc::dns;
diff --git a/src/lib/dns/rrtype-placeholder.h b/src/lib/dns/rrtype-placeholder.h
deleted file mode 100644
index 4e9c99acce..0000000000
--- a/src/lib/dns/rrtype-placeholder.h
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef RRTYPE_H
-#define RRTYPE_H
-
-#include <stdint.h>
-
-#include <string>
-#include <ostream>
-
-#include <dns/exceptions.h>'
-#include <util/buffer.h>
-
-// Solaris x86 defines DS in <sys/regset.h>, which gets pulled in by Boost
-#if defined(__sun) && defined(DS)
-# undef DS
-#endif
-
-namespace isc {
-namespace dns {
-
-// forward declarations
-class AbstractMessageRenderer;
-///
-/// The \c RRType class encapsulates DNS resource record types.
-///
-/// This class manages the 16-bit integer type codes in quite a straightforward
-/// way. The only non trivial task is to handle textual representations of
-/// RR types, such as "A", "AAAA", or "TYPE65534".
-///
-/// This class consults a helper \c RRParamRegistry class, which is a registry
-/// of RR related parameters and has the singleton object. This registry
-/// provides a mapping between RR type codes and their "well-known" textual
-/// representations.
-/// Parameters of RR types defined by DNS protocol standards are automatically
-/// registered at initialization time and are ensured to be always available for
-/// applications unless the application explicitly modifies the registry.
-///
-/// For convenience, this class defines constant class objects corresponding to
-/// standard RR types. These are generally referred to as the form of
-/// <code>RRType::{type-text}()</code>.
-/// For example, \c RRType::NS() is an \c RRType object corresponding to the NS
-/// resource record (type code 2).
-/// Note that these constants are used through a "proxy" function.
-/// This is because they may be used to initialize another non-local (e.g.
-/// global or namespace-scope) static object as follows:
-///
-/// \code
-/// namespace foo {
-/// const RRType default_type = RRType::A();
-/// } \endcode
-///
-/// In order to ensure that the constant RRType object has been initialized
-/// before the initialization for \c default_type, we need help from
-/// the proxy function.
-///
-/// In the current implementation, the initialization of the well-known
-/// static objects is not thread safe. The same consideration as the
-/// \c RRParamRegistry class applies. We may extend the implementation so
-/// that the initialization is ensured to be thread safe in a future version.
-///
-/// Note to developers: since it's expected that some of these constant
-/// \c RRType objects are frequently used in a performance sensitive path,
-/// we define these proxy functions as inline. This makes sense only when
-/// the corresponding static objects are defined only once even if they used
-/// in different source files. Sufficiently modern compilers should meet
-/// this assumption, but if we encounter memory bloat due to this problem with
-/// particular compilers we need to revisit the design or think about
-/// workaround.
-class RRType {
-public:
- ///
- /// \name Constructors and Destructor
- ///
- //@{
- /// Constructor from an integer type code.
- ///
- /// This constructor never throws an exception.
- ///
- /// \param typecode An 16-bit integer code corresponding to the RRType.
- explicit RRType(uint16_t typecode) : typecode_(typecode) {}
- /// Constructor from a string.
- ///
- /// A valid string is one of "well-known" textual type representations
- /// such as "A", "AAAA", or "NS", or in the standard format for "unknown"
- /// RR types as defined in RFC3597, i.e., "TYPEnnnn".
- ///
- /// More precisely, the "well-known" representations are the ones stored
- /// in the \c RRParamRegistry registry (see the class description).
- ///
- /// As for the format of "TYPEnnnn", "nnnn" must represent a valid 16-bit
- /// unsigned integer, which may contain leading 0's as long as it consists
- /// of at most 5 characters (inclusive).
- /// For example, "TYPE1" and "TYPE001" are valid and represent the same
- /// RR type, but "TYPE65536" and "TYPE000001" are invalid.
- /// A "TYPEnnnn" representation is valid even if the corresponding type code
- /// is registered in the \c RRParamRegistry object. For example, both
- /// "A" and "TYPE1" are valid and represent the same RR type.
- ///
- /// All of these representations are case insensitive; "NS" and "ns", and
- /// "TYPE1" and "type1" are all valid and represent the same RR types,
- /// respectively.
- ///
- /// If the given string is not recognized as a valid representation of
- /// an RR type, an exception of class \c InvalidRRType will be thrown.
- ///
- /// \param typestr A string representation of the \c RRType
- explicit RRType(const std::string& typestr);
- /// Constructor from wire-format data.
- ///
- /// The \c buffer parameter normally stores a complete DNS message
- /// containing the RRType to be constructed. The current read position of
- /// the buffer points to the head of the type.
- ///
- /// If the given data does not large enough to contain a 16-bit integer,
- /// an exception of class \c IncompleteRRType will be thrown.
- ///
- /// \param buffer A buffer storing the wire format data.
- explicit RRType(isc::util::InputBuffer& buffer);
- ///
- /// We use the default copy constructor intentionally.
- //@}
- /// We use the default copy assignment operator intentionally.
- ///
- ///
- /// \name Getter Methods
- ///
- //@{
- /// \brief Returns the RR type code as a 16-bit unsigned integer.
- ///
- /// This method never throws an exception.
- ///
- /// \return An 16-bit integer code corresponding to the RRType.
- uint16_t getCode() const {
- return (typecode_);
- }
- //@}
- // BEGIN_WELL_KNOWN_TYPE_DECLARATIONS
- // END_WELL_KNOWN_TYPE_DECLARATIONS
-
-private:
- uint16_t typecode_;
-};
-
-// BEGIN_WELL_KNOWN_TYPE_DEFINITIONS
-// END_WELL_KNOWN_TYPE_DEFINITIONS
-}
-}
-#endif // RRTYPE_H
diff --git a/src/lib/dns/rrtype.cc b/src/lib/dns/rrtype.cc
index 242af518ba..2944cb6bdd 100644
--- a/src/lib/dns/rrtype.cc
+++ b/src/lib/dns/rrtype.cc
@@ -6,22 +6,21 @@
#include <config.h>
-#include <stdint.h>
-
-#include <string>
-#include <ostream>
-
#include <exceptions/exceptions.h>
-
-#include <util/buffer.h>
#include <dns/messagerenderer.h>
#include <dns/rrparamregistry.h>
#include <dns/rrtype.h>
+#include <util/buffer.h>
+
+#include <stdint.h>
+#include <string>
+#include <ostream>
-using namespace std;
using namespace isc::util;
using isc::dns::RRType;
+using namespace std;
+
namespace isc {
namespace dns {
diff --git a/src/lib/dns/rrtype.h b/src/lib/dns/rrtype.h
index 6f2c583323..63d8e5282e 100644
--- a/src/lib/dns/rrtype.h
+++ b/src/lib/dns/rrtype.h
@@ -1,11 +1,4 @@
-///////////////
-///////////////
-/////////////// THIS FILE IS AUTOMATICALLY GENERATED BY gen-rdatacode.py.
-/////////////// DO NOT EDIT!
-///////////////
-///////////////
-
-// Copyright (C) 2010-2021 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -265,15 +258,17 @@ public:
//@}
// BEGIN_WELL_KNOWN_TYPE_DECLARATIONS
- static const RRType& TSIG();
+ static const RRType& A();
+ static const RRType& NS();
+ static const RRType& SOA();
static const RRType& OPT();
static const RRType& PTR();
- static const RRType& RRSIG();
- static const RRType& SOA();
- static const RRType& TKEY();
- static const RRType& A();
+ static const RRType& TXT();
static const RRType& AAAA();
+ static const RRType& RRSIG();
static const RRType& DHCID();
+ static const RRType& TKEY();
+ static const RRType& TSIG();
static const RRType& ANY();
// END_WELL_KNOWN_TYPE_DECLARATIONS
@@ -284,14 +279,20 @@ private:
// BEGIN_WELL_KNOWN_TYPE_DEFINITIONS
inline const RRType&
-RRType::TSIG() {
- static RRType rrtype(250);
+RRType::A() {
+ static RRType rrtype(1);
return (rrtype);
}
inline const RRType&
-RRType::A() {
- static RRType rrtype(1);
+RRType::NS() {
+ static RRType rrtype(2);
+ return (rrtype);
+}
+
+inline const RRType&
+RRType::SOA() {
+ static RRType rrtype(6);
return (rrtype);
}
@@ -308,32 +309,38 @@ RRType::PTR() {
}
inline const RRType&
-RRType::RRSIG() {
- static RRType rrtype(46);
+RRType::TXT() {
+ static RRType rrtype(16);
return (rrtype);
}
inline const RRType&
-RRType::SOA() {
- static RRType rrtype(6);
+RRType::AAAA() {
+ static RRType rrtype(28);
return (rrtype);
}
inline const RRType&
-RRType::TKEY() {
- static RRType rrtype(249);
+RRType::RRSIG() {
+ static RRType rrtype(46);
return (rrtype);
}
inline const RRType&
-RRType::AAAA() {
- static RRType rrtype(28);
+RRType::DHCID() {
+ static RRType rrtype(49);
return (rrtype);
}
inline const RRType&
-RRType::DHCID() {
- static RRType rrtype(49);
+RRType::TKEY() {
+ static RRType rrtype(249);
+ return (rrtype);
+}
+
+inline const RRType&
+RRType::TSIG() {
+ static RRType rrtype(250);
return (rrtype);
}
diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am
index c89c3db48b..113bf4a9e6 100644
--- a/src/lib/dns/tests/Makefile.am
+++ b/src/lib/dns/tests/Makefile.am
@@ -28,49 +28,28 @@ run_unittests_SOURCES += master_lexer_unittest.cc
run_unittests_SOURCES += master_loader_unittest.cc
run_unittests_SOURCES += master_lexer_state_unittest.cc
run_unittests_SOURCES += name_unittest.cc
-run_unittests_SOURCES += nsec3hash_unittest.cc
-run_unittests_SOURCES += rrclass_unittest.cc rrtype_unittest.cc
run_unittests_SOURCES += rrttl_unittest.cc
-run_unittests_SOURCES += rrcollator_unittest.cc
+run_unittests_SOURCES += rrclass_unittest.cc
+run_unittests_SOURCES += rrtype_unittest.cc
run_unittests_SOURCES += opcode_unittest.cc
run_unittests_SOURCES += rcode_unittest.cc
run_unittests_SOURCES += rdata_unittest.h rdata_unittest.cc
-run_unittests_SOURCES += rdatafields_unittest.cc
-run_unittests_SOURCES += rdata_pimpl_holder_unittest.cc
run_unittests_SOURCES += rdata_char_string_unittest.cc
run_unittests_SOURCES += rdata_char_string_data_unittest.cc
-run_unittests_SOURCES += rdata_in_a_unittest.cc rdata_in_aaaa_unittest.cc
-run_unittests_SOURCES += rdata_ns_unittest.cc rdata_soa_unittest.cc
+run_unittests_SOURCES += rdata_in_a_unittest.cc
+run_unittests_SOURCES += rdata_in_aaaa_unittest.cc
+run_unittests_SOURCES += rdata_ns_unittest.cc
+run_unittests_SOURCES += rdata_soa_unittest.cc
run_unittests_SOURCES += rdata_txt_like_unittest.cc
-run_unittests_SOURCES += rdata_mx_unittest.cc
-run_unittests_SOURCES += rdata_sshfp_unittest.cc
-run_unittests_SOURCES += rdata_ptr_unittest.cc rdata_cname_unittest.cc
-run_unittests_SOURCES += rdata_dname_unittest.cc
-run_unittests_SOURCES += rdata_afsdb_unittest.cc
+run_unittests_SOURCES += rdata_ptr_unittest.cc
run_unittests_SOURCES += rdata_opt_unittest.cc
run_unittests_SOURCES += rdata_dhcid_unittest.cc
-run_unittests_SOURCES += rdata_dnskey_unittest.cc
-run_unittests_SOURCES += rdata_ds_like_unittest.cc
-run_unittests_SOURCES += rdata_nsec_unittest.cc
-run_unittests_SOURCES += rdata_nsec3_unittest.cc
-run_unittests_SOURCES += rdata_nsecbitmap_unittest.cc
-run_unittests_SOURCES += rdata_nsec3param_unittest.cc
-run_unittests_SOURCES += rdata_nsec3param_like_unittest.cc
run_unittests_SOURCES += rdata_rrsig_unittest.cc
-run_unittests_SOURCES += rdata_rp_unittest.cc
-run_unittests_SOURCES += rdata_srv_unittest.cc
-run_unittests_SOURCES += rdata_tlsa_unittest.cc
-run_unittests_SOURCES += rdata_minfo_unittest.cc
run_unittests_SOURCES += rdata_tsig_unittest.cc
-run_unittests_SOURCES += rdata_naptr_unittest.cc
-run_unittests_SOURCES += rdata_hinfo_unittest.cc
-run_unittests_SOURCES += rdata_caa_unittest.cc
run_unittests_SOURCES += rdata_tkey_unittest.cc
run_unittests_SOURCES += rrset_unittest.cc
-run_unittests_SOURCES += qid_gen_unittest.cc
run_unittests_SOURCES += question_unittest.cc
run_unittests_SOURCES += rrparamregistry_unittest.cc
-run_unittests_SOURCES += masterload_unittest.cc
run_unittests_SOURCES += message_unittest.cc
run_unittests_SOURCES += serial_unittest.cc
run_unittests_SOURCES += tsig_unittest.cc
@@ -78,8 +57,6 @@ run_unittests_SOURCES += tsigerror_unittest.cc
run_unittests_SOURCES += tsigkey_unittest.cc
run_unittests_SOURCES += tsigrecord_unittest.cc
run_unittests_SOURCES += master_loader_callbacks_test.cc
-run_unittests_SOURCES += rrset_collection_unittest.cc
-run_unittests_SOURCES += zone_checker_unittest.cc
run_unittests_SOURCES += run_unittests.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS)
diff --git a/src/lib/dns/tests/dns_exceptions_unittest.cc b/src/lib/dns/tests/dns_exceptions_unittest.cc
index 8b13789179..a8d25907c7 100644
--- a/src/lib/dns/tests/dns_exceptions_unittest.cc
+++ b/src/lib/dns/tests/dns_exceptions_unittest.cc
@@ -1 +1,65 @@
+// Copyright (C) 2014-2015,2017 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <dns/exceptions.h>
+
+#include <gtest/gtest.h>
+
+namespace { // begin unnamed namespace
+
+TEST(DNSExceptionsTest, checkExceptionsHierarchy) {
+ EXPECT_NO_THROW({
+ const isc::dns::Exception exception("", 0, "");
+ const isc::Exception& exception_cast =
+ dynamic_cast<const isc::Exception&>(exception);
+ // to avoid compiler warning
+ exception_cast.what();
+ });
+
+ EXPECT_NO_THROW({
+ const isc::dns::DNSTextError exception("", 0, "");
+ const isc::dns::Exception& exception_cast =
+ dynamic_cast<const isc::dns::Exception&>(exception);
+ // to avoid compiler warning
+ exception_cast.what();
+ });
+
+ EXPECT_NO_THROW({
+ const isc::dns::NameParserException exception("", 0, "");
+ const isc::dns::DNSTextError& exception_cast =
+ dynamic_cast<const isc::dns::DNSTextError&>(exception);
+ // to avoid compiler warning
+ exception_cast.what();
+ });
+
+ EXPECT_NO_THROW({
+ const isc::dns::DNSMessageFORMERR exception("", 0, "");
+ const isc::dns::DNSProtocolError& exception_cast =
+ dynamic_cast<const isc::dns::DNSProtocolError&>(exception);
+ const isc::dns::Exception& exception_cast2 =
+ dynamic_cast<const isc::dns::Exception&>(exception);
+ // to avoid compiler warning
+ exception_cast.getRcode();
+ exception_cast.what();
+ exception_cast2.what();
+ });
+
+ EXPECT_NO_THROW({
+ const isc::dns::DNSMessageBADVERS exception("", 0, "");
+ const isc::dns::DNSProtocolError& exception_cast =
+ dynamic_cast<const isc::dns::DNSProtocolError&>(exception);
+ const isc::dns::Exception& exception_cast2 =
+ dynamic_cast<const isc::dns::Exception&>(exception);
+ // to avoid compiler warning
+ exception_cast.getRcode();
+ exception_cast.what();
+ exception_cast2.what();
+ });
+}
+
+} // end unnamed namespace
diff --git a/src/lib/dns/tests/edns_unittest.cc b/src/lib/dns/tests/edns_unittest.cc
index 8b13789179..dfc68cc67e 100644
--- a/src/lib/dns/tests/edns_unittest.cc
+++ b/src/lib/dns/tests/edns_unittest.cc
@@ -1 +1,258 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <sstream>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <dns/edns.h>
+#include <dns/exceptions.h>
+#include <dns/message.h>
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/rcode.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrttl.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+#include <util/unittests/wiredata.h>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+const uint8_t EDNS::SUPPORTED_VERSION;
+
+namespace {
+class EDNSTest : public ::testing::Test {
+protected:
+ EDNSTest() : rrtype(RRType::OPT()), buffer(NULL, 0), obuffer(0), rcode(0) {
+ opt_rdata = ConstRdataPtr(new generic::OPT());
+ edns_base.setUDPSize(4096);
+ }
+ RRType rrtype;
+ EDNS edns_base;
+ ConstEDNSPtr edns;
+ InputBuffer buffer;
+ OutputBuffer obuffer;
+ MessageRenderer renderer;
+ ConstRdataPtr opt_rdata;
+ Rcode rcode;
+ vector<unsigned char> wiredata;
+};
+
+// RRClass of EDNS OPT means UDP buffer size
+const RRClass rrclass(4096);
+// RRTTL of EDNS OPT encodes extended-rcode, version, and DO bit
+const RRTTL rrttl_do_on(0x00008000); // DO=on
+const RRTTL rrttl_do_off(0); // DO=off
+const RRTTL rrttl_badver(0x00018000); // version=1, DO=on
+
+TEST_F(EDNSTest, badVerConstruct) {
+ EXPECT_THROW(EDNS(1), isc::InvalidParameter);
+}
+
+TEST_F(EDNSTest, DNSSECDOBit) {
+ // tests for EDNS from RR
+
+ // DO bit is on, so DNSSEC should be considered to be supported.
+ EXPECT_TRUE(EDNS(Name::ROOT_NAME(), rrclass, rrtype,
+ rrttl_do_on, *opt_rdata).getDNSSECAwareness());
+
+ // DO bit is off. DNSSEC should be considered to be unsupported.
+ EXPECT_FALSE(EDNS(Name::ROOT_NAME(), rrclass, rrtype,
+ rrttl_do_off, *opt_rdata).getDNSSECAwareness());
+
+ // tests for EDNS constructed by hand
+ EXPECT_FALSE(edns_base.getDNSSECAwareness()); // false by default
+ edns_base.setDNSSECAwareness(true); // enable by hand
+ EXPECT_TRUE(edns_base.getDNSSECAwareness());
+ edns_base.setDNSSECAwareness(false); // disable by hand
+ EXPECT_FALSE(edns_base.getDNSSECAwareness());
+}
+
+TEST_F(EDNSTest, UDPSize) {
+ EXPECT_EQ(4096, EDNS(Name::ROOT_NAME(), rrclass, rrtype, rrttl_do_on,
+ *opt_rdata).getUDPSize());
+
+ // EDNS UDP size smaller than the traditional max, 512. Unusual, but
+ // not prohibited.
+ edns_base.setUDPSize(511);
+ EXPECT_EQ(511, edns_base.getUDPSize());
+
+ // Even 0 is okay.
+ edns_base.setUDPSize(0);
+ EXPECT_EQ(0, edns_base.getUDPSize());
+
+ // Possible max value is also okay, although the higher layer app may
+ // adjust it to a reasonably lower value
+ edns_base.setUDPSize(65535);
+ EXPECT_EQ(65535, edns_base.getUDPSize());
+}
+
+TEST_F(EDNSTest, getVersion) {
+ // Constructed by hand
+ EXPECT_EQ(EDNS::SUPPORTED_VERSION, EDNS().getVersion());
+
+ // From RR
+ EXPECT_EQ(EDNS::SUPPORTED_VERSION,
+ EDNS(Name::ROOT_NAME(), rrclass, rrtype, rrttl_do_on,
+ *opt_rdata).getVersion());
+}
+
+TEST_F(EDNSTest, BadWireData) {
+ // Incompatible RR type
+ EXPECT_THROW(EDNS(Name::ROOT_NAME(), rrclass, RRType::A(),
+ rrttl_do_on, *opt_rdata), isc::InvalidParameter);
+
+ // OPT RR of a non root name
+ EXPECT_THROW(EDNS(Name("example.com"), rrclass, rrtype,
+ rrttl_do_on, *opt_rdata), DNSMessageFORMERR);
+
+ // Unsupported Version
+ EXPECT_THROW(EDNS(Name::ROOT_NAME(), rrclass, rrtype,
+ rrttl_badver, *opt_rdata), DNSMessageBADVERS);
+}
+
+TEST_F(EDNSTest, toText) {
+ // Typical case, disabling DNSSEC
+ EXPECT_EQ("; EDNS: version: 0, flags:; udp: 4096\n",
+ EDNS(Name::ROOT_NAME(), rrclass, rrtype, rrttl_do_off,
+ *opt_rdata).toText());
+
+ // Typical case, enabling DNSSEC
+ EXPECT_EQ("; EDNS: version: 0, flags: do; udp: 4096\n",
+ EDNS(Name::ROOT_NAME(), rrclass, rrtype, rrttl_do_on,
+ *opt_rdata).toText());
+
+ // Non-0 extended Rcode: ignored in the toText() output.
+ EXPECT_EQ("; EDNS: version: 0, flags: do; udp: 4096\n",
+ EDNS(Name::ROOT_NAME(), rrclass, rrtype,
+ RRTTL(0x01008000), *opt_rdata).toText());
+
+ // Unknown flag: ignored in the toText() output.
+ EXPECT_EQ("; EDNS: version: 0, flags: do; udp: 4096\n",
+ EDNS(Name::ROOT_NAME(), rrclass, rrtype,
+ RRTTL(0x00008001), *opt_rdata).toText());
+}
+
+TEST_F(EDNSTest, toWireRenderer) {
+ // Typical case, (explicitly) disabling DNSSEC
+ edns_base.setDNSSECAwareness(false);
+ EXPECT_EQ(1, edns_base.toWire(renderer,
+ Rcode::NOERROR().getExtendedCode()));
+ UnitTestUtil::readWireData("edns_toWire1.wire", wiredata);
+ matchWireData(&wiredata[0], wiredata.size(),
+ renderer.getData(), renderer.getLength());
+
+ // Typical case, enabling DNSSEC
+ renderer.clear();
+ wiredata.clear();
+ edns_base.setDNSSECAwareness(true);
+ EXPECT_EQ(1, edns_base.toWire(renderer,
+ Rcode::NOERROR().getExtendedCode()));
+ UnitTestUtil::readWireData("edns_toWire2.wire", wiredata);
+ matchWireData(&wiredata[0], wiredata.size(),
+ renderer.getData(), renderer.getLength());
+
+ // Non-0 extended Rcode
+ renderer.clear();
+ wiredata.clear();
+ edns_base.setDNSSECAwareness(true);
+ EXPECT_EQ(1, edns_base.toWire(renderer,
+ Rcode::BADVERS().getExtendedCode()));
+ UnitTestUtil::readWireData("edns_toWire3.wire", wiredata);
+ matchWireData(&wiredata[0], wiredata.size(),
+ renderer.getData(), renderer.getLength());
+
+ // Uncommon UDP buffer size
+ renderer.clear();
+ wiredata.clear();
+ edns_base.setDNSSECAwareness(true);
+ edns_base.setUDPSize(511);
+ EXPECT_EQ(1, edns_base.toWire(renderer,
+ Rcode::NOERROR().getExtendedCode()));
+ UnitTestUtil::readWireData("edns_toWire4.wire", wiredata);
+ matchWireData(&wiredata[0], wiredata.size(),
+ renderer.getData(), renderer.getLength());
+
+ // From RR with unknown flag. If used for toWire(), the unknown flag
+ // should disappear.
+ renderer.clear();
+ wiredata.clear();
+ EXPECT_EQ(1, EDNS(Name::ROOT_NAME(), rrclass, rrtype, RRTTL(0x00008001),
+ *opt_rdata).toWire(renderer,
+ Rcode::NOERROR().getExtendedCode()));
+ UnitTestUtil::readWireData("edns_toWire2.wire", wiredata);
+ matchWireData(&wiredata[0], wiredata.size(),
+ renderer.getData(), renderer.getLength());
+
+ // If the available length in the renderer is not sufficient for the OPT
+ // RR, it shouldn't be inserted.
+ renderer.clear();
+ renderer.setLengthLimit(10); // 10 = minimum length of OPT RR - 1
+ edns_base.setDNSSECAwareness(true);
+ edns_base.setUDPSize(4096);
+ EXPECT_EQ(0, edns_base.toWire(renderer,
+ Rcode::NOERROR().getExtendedCode()));
+ // renderer should be intact
+ EXPECT_EQ(0, renderer.getLength());
+}
+
+TEST_F(EDNSTest, toWireBuffer) {
+ // "to renderer" and "to buffer" should generally produce the same result.
+ // for simplicity we only check one typical case to confirm that.
+ EXPECT_EQ(1, edns_base.toWire(obuffer,
+ Rcode::NOERROR().getExtendedCode()));
+ UnitTestUtil::readWireData("edns_toWire1.wire", wiredata);
+ matchWireData(&wiredata[0], wiredata.size(),
+ obuffer.getData(), obuffer.getLength());
+}
+
+TEST_F(EDNSTest, createFromRR) {
+ uint8_t extended_rcode;
+
+ // normal case
+ edns = ConstEDNSPtr(createEDNSFromRR(Name::ROOT_NAME(), rrclass, rrtype,
+ rrttl_do_on, *opt_rdata,
+ extended_rcode));
+ EXPECT_EQ(EDNS::SUPPORTED_VERSION, edns->getVersion());
+ EXPECT_TRUE(edns->getDNSSECAwareness());
+ EXPECT_EQ(4096, edns->getUDPSize());
+ EXPECT_EQ(0, static_cast<int>(extended_rcode));
+
+ // non-0 extended rcode
+ extended_rcode = 0;
+ ConstEDNSPtr(createEDNSFromRR(Name::ROOT_NAME(), rrclass, rrtype,
+ RRTTL(0x01008000), *opt_rdata,
+ extended_rcode));
+ EXPECT_EQ(1, static_cast<int>(extended_rcode));
+
+ // creation triggers an exception. extended_rcode must be intact.
+ extended_rcode = 0;
+ EXPECT_THROW(createEDNSFromRR(Name::ROOT_NAME(), rrclass, rrtype,
+ rrttl_badver, *opt_rdata, extended_rcode),
+ DNSMessageBADVERS);
+ EXPECT_EQ(0, static_cast<int>(extended_rcode));
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST_F(EDNSTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << edns_base;
+ EXPECT_EQ(edns_base.toText(), oss.str());
+}
+}
diff --git a/src/lib/dns/tests/labelsequence_unittest.cc b/src/lib/dns/tests/labelsequence_unittest.cc
index 8b13789179..15650fac07 100644
--- a/src/lib/dns/tests/labelsequence_unittest.cc
+++ b/src/lib/dns/tests/labelsequence_unittest.cc
@@ -1 +1,1243 @@
+// Copyright (C) 2012-2020 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <util/buffer.h>
+
+#include <dns/labelsequence.h>
+#include <dns/name.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <boost/functional/hash.hpp>
+
+#include <string>
+#include <vector>
+#include <utility>
+#include <set>
+
+using namespace isc::dns;
+using namespace std;
+
+// XXX: this is defined as class static constants, but some compilers
+// seemingly cannot find the symbols when used in the EXPECT_xxx macros.
+const size_t LabelSequence::MAX_SERIALIZED_LENGTH;
+
+namespace {
+
+// Common check that two labelsequences are equal
+void check_equal(const LabelSequence& ls1, const LabelSequence& ls2) {
+ NameComparisonResult result = ls1.compare(ls2);
+ EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+ result.getRelation()) << ls1.toText() << " != " << ls2.toText();
+ EXPECT_EQ(0, result.getOrder()) << ls1.toText() << " != " << ls2.toText();
+ EXPECT_EQ(ls1.getLabelCount(), result.getCommonLabels());
+}
+
+// Common check for general comparison of two labelsequences
+void check_compare(const LabelSequence& ls1, const LabelSequence& ls2,
+ isc::dns::NameComparisonResult::NameRelation relation,
+ size_t common_labels, bool check_order, int order=0) {
+ NameComparisonResult result = ls1.compare(ls2);
+ EXPECT_EQ(relation, result.getRelation());
+ EXPECT_EQ(common_labels, result.getCommonLabels());
+ if (check_order) {
+ EXPECT_EQ(order, result.getOrder());
+ }
+}
+
+class LabelSequenceTest : public ::testing::Test {
+public:
+ LabelSequenceTest() : n1("example.org"), n2("example.com"),
+ n3("example.org"), n4("foo.bar.test.example"),
+ n5("example.ORG"), n6("ExAmPlE.org"),
+ n7("."), n8("foo.example.org.bar"),
+ n9("\\000xample.org"),
+ n10("\\000xample.org"),
+ n11("\\000xample.com"),
+ n12("\\000xamplE.com"),
+ n_maxlabel("0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6"),
+ ls1(n1), ls2(n2), ls3(n3), ls4(n4), ls5(n5),
+ ls6(n6), ls7(n7), ls8(n8),
+ ls9(n9), ls10(n10), ls11(n11), ls12(n12)
+ {};
+ // Need to keep names in scope for at least the lifetime of
+ // the labelsequences
+ Name n1, n2, n3, n4, n5, n6, n7, n8;
+ Name n9, n10, n11, n12;
+ const Name n_maxlabel;
+
+ LabelSequence ls1, ls2, ls3, ls4, ls5, ls6, ls7, ls8;
+ LabelSequence ls9, ls10, ls11, ls12;
+};
+
+// Check the assignment operator.
+TEST_F(LabelSequenceTest, assign) {
+ // Create the label sequence with example.org (n1 name).
+ LabelSequence ls(n1);
+ EXPECT_TRUE(ls == ls1);
+
+ // Assign the label sequence to example.com (n2 name).
+ ls = ls2;
+ EXPECT_FALSE(ls == ls1);
+ EXPECT_TRUE(ls == ls2);
+}
+
+// Basic equality tests
+TEST_F(LabelSequenceTest, equals_sensitive) {
+ EXPECT_TRUE(ls1.equals(ls1, true));
+ EXPECT_FALSE(ls1.equals(ls2, true));
+ EXPECT_TRUE(ls1.equals(ls3, true));
+ EXPECT_FALSE(ls1.equals(ls4, true));
+ EXPECT_FALSE(ls1.equals(ls5, true));
+ EXPECT_FALSE(ls1.equals(ls6, true));
+ EXPECT_FALSE(ls1.equals(ls7, true));
+ EXPECT_FALSE(ls1.equals(ls8, true));
+
+ EXPECT_FALSE(ls2.equals(ls1, true));
+ EXPECT_TRUE(ls2.equals(ls2, true));
+ EXPECT_FALSE(ls2.equals(ls3, true));
+ EXPECT_FALSE(ls2.equals(ls4, true));
+ EXPECT_FALSE(ls2.equals(ls5, true));
+ EXPECT_FALSE(ls2.equals(ls6, true));
+ EXPECT_FALSE(ls2.equals(ls7, true));
+ EXPECT_FALSE(ls2.equals(ls8, true));
+
+ EXPECT_FALSE(ls4.equals(ls1, true));
+ EXPECT_FALSE(ls4.equals(ls2, true));
+ EXPECT_FALSE(ls4.equals(ls3, true));
+ EXPECT_TRUE(ls4.equals(ls4, true));
+ EXPECT_FALSE(ls4.equals(ls5, true));
+ EXPECT_FALSE(ls4.equals(ls6, true));
+ EXPECT_FALSE(ls4.equals(ls7, true));
+ EXPECT_FALSE(ls4.equals(ls8, true));
+
+ EXPECT_FALSE(ls5.equals(ls1, true));
+ EXPECT_FALSE(ls5.equals(ls2, true));
+ EXPECT_FALSE(ls5.equals(ls3, true));
+ EXPECT_FALSE(ls5.equals(ls4, true));
+ EXPECT_TRUE(ls5.equals(ls5, true));
+ EXPECT_FALSE(ls5.equals(ls6, true));
+ EXPECT_FALSE(ls5.equals(ls7, true));
+ EXPECT_FALSE(ls5.equals(ls8, true));
+
+ EXPECT_TRUE(ls9.equals(ls10, true));
+ EXPECT_FALSE(ls9.equals(ls11, true));
+ EXPECT_FALSE(ls9.equals(ls12, true));
+ EXPECT_FALSE(ls11.equals(ls12, true));
+}
+
+TEST_F(LabelSequenceTest, equals_insensitive) {
+ EXPECT_TRUE(ls1.equals(ls1));
+ EXPECT_FALSE(ls1.equals(ls2));
+ EXPECT_TRUE(ls1.equals(ls3));
+ EXPECT_FALSE(ls1.equals(ls4));
+ EXPECT_TRUE(ls1.equals(ls5));
+ EXPECT_TRUE(ls1.equals(ls6));
+ EXPECT_FALSE(ls1.equals(ls7));
+
+ EXPECT_FALSE(ls2.equals(ls1));
+ EXPECT_TRUE(ls2.equals(ls2));
+ EXPECT_FALSE(ls2.equals(ls3));
+ EXPECT_FALSE(ls2.equals(ls4));
+ EXPECT_FALSE(ls2.equals(ls5));
+ EXPECT_FALSE(ls2.equals(ls6));
+ EXPECT_FALSE(ls2.equals(ls7));
+
+ EXPECT_TRUE(ls3.equals(ls1));
+ EXPECT_FALSE(ls3.equals(ls2));
+ EXPECT_TRUE(ls3.equals(ls3));
+ EXPECT_FALSE(ls3.equals(ls4));
+ EXPECT_TRUE(ls3.equals(ls5));
+ EXPECT_TRUE(ls3.equals(ls6));
+ EXPECT_FALSE(ls3.equals(ls7));
+
+ EXPECT_FALSE(ls4.equals(ls1));
+ EXPECT_FALSE(ls4.equals(ls2));
+ EXPECT_FALSE(ls4.equals(ls3));
+ EXPECT_TRUE(ls4.equals(ls4));
+ EXPECT_FALSE(ls4.equals(ls5));
+ EXPECT_FALSE(ls4.equals(ls6));
+ EXPECT_FALSE(ls4.equals(ls7));
+
+ EXPECT_TRUE(ls5.equals(ls1));
+ EXPECT_FALSE(ls5.equals(ls2));
+ EXPECT_TRUE(ls5.equals(ls3));
+ EXPECT_FALSE(ls5.equals(ls4));
+ EXPECT_TRUE(ls5.equals(ls5));
+ EXPECT_TRUE(ls5.equals(ls6));
+ EXPECT_FALSE(ls5.equals(ls7));
+
+ EXPECT_TRUE(ls9.equals(ls10));
+ EXPECT_FALSE(ls9.equals(ls11));
+ EXPECT_FALSE(ls9.equals(ls12));
+ EXPECT_TRUE(ls11.equals(ls12));
+}
+
+// operator==(). This is mostly trivial wrapper, so it should suffice to
+// check some basic cases.
+TEST_F(LabelSequenceTest, operatorEqual) {
+ // cppcheck-suppress duplicateExpression
+ EXPECT_TRUE(ls1 == ls1); // self equivalence
+ EXPECT_TRUE(ls1 == LabelSequence(n1)); // equivalent two different objects
+ EXPECT_FALSE(ls1 == ls2); // non equivalent objects
+ EXPECT_TRUE(ls1 == ls5); // it's always case insensitive
+}
+
+// Compare tests
+TEST_F(LabelSequenceTest, compare) {
+ // "example.org." and "example.org.", case sensitive
+ NameComparisonResult result = ls1.compare(ls3, true);
+ EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+ result.getRelation());
+ EXPECT_EQ(0, result.getOrder());
+ EXPECT_EQ(3, result.getCommonLabels());
+
+ // "example.org." and "example.ORG.", case sensitive
+ result = ls3.compare(ls5, true);
+ EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+ result.getRelation());
+ EXPECT_LT(0, result.getOrder());
+ EXPECT_EQ(1, result.getCommonLabels());
+
+ // "example.org." and "example.ORG.", case in-sensitive
+ result = ls3.compare(ls5);
+ EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+ result.getRelation());
+ EXPECT_EQ(0, result.getOrder());
+ EXPECT_EQ(3, result.getCommonLabels());
+
+ Name na("a.example.org");
+ Name nb("b.example.org");
+ LabelSequence lsa(na);
+ LabelSequence lsb(nb);
+
+ // "a.example.org." and "b.example.org.", case in-sensitive
+ result = lsa.compare(lsb);
+ EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+ result.getRelation());
+ EXPECT_GT(0, result.getOrder());
+ EXPECT_EQ(3, result.getCommonLabels());
+
+ // "example.org." and "b.example.org.", case in-sensitive
+ lsa.stripLeft(1);
+ result = lsa.compare(lsb);
+ EXPECT_EQ(isc::dns::NameComparisonResult::SUPERDOMAIN,
+ result.getRelation());
+ EXPECT_GT(0, result.getOrder());
+ EXPECT_EQ(3, result.getCommonLabels());
+
+ Name nc("g.f.e.d.c.example.org");
+ LabelSequence lsc(nc);
+
+ // "g.f.e.d.c.example.org." and "b.example.org" (not absolute), case
+ // in-sensitive; the absolute one is always smaller.
+ lsb.stripRight(1);
+ result = lsc.compare(lsb);
+ EXPECT_EQ(isc::dns::NameComparisonResult::NONE, result.getRelation());
+ EXPECT_GT(0, result.getOrder());
+ EXPECT_EQ(0, result.getCommonLabels());
+
+ // "g.f.e.d.c.example.org." and "example.org.", case in-sensitive
+ result = lsc.compare(ls1);
+ EXPECT_EQ(isc::dns::NameComparisonResult::SUBDOMAIN,
+ result.getRelation());
+ EXPECT_LT(0, result.getOrder());
+ EXPECT_EQ(3, result.getCommonLabels());
+
+ // "e.d.c.example.org." and "example.org.", case in-sensitive
+ lsc.stripLeft(2);
+ result = lsc.compare(ls1);
+ EXPECT_EQ(isc::dns::NameComparisonResult::SUBDOMAIN,
+ result.getRelation());
+ EXPECT_LT(0, result.getOrder());
+ EXPECT_EQ(3, result.getCommonLabels());
+
+ // "example.org." and "example.org.", case in-sensitive
+ lsc.stripLeft(3);
+ result = lsc.compare(ls1);
+ EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+ result.getRelation());
+ EXPECT_EQ(0, result.getOrder());
+ EXPECT_EQ(3, result.getCommonLabels());
+
+ // "." and "example.org.", case in-sensitive
+ lsc.stripLeft(2);
+ result = lsc.compare(ls1);
+ EXPECT_EQ(isc::dns::NameComparisonResult::SUPERDOMAIN,
+ result.getRelation());
+ EXPECT_GT(0, result.getOrder());
+ EXPECT_EQ(1, result.getCommonLabels());
+
+ Name nd("a.b.c.isc.example.org");
+ LabelSequence lsd(nd);
+ Name ne("w.x.y.isc.EXAMPLE.org");
+ LabelSequence lse(ne);
+
+ // "a.b.c.isc.example.org." and "w.x.y.isc.EXAMPLE.org.",
+ // case sensitive
+ result = lsd.compare(lse, true);
+ EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+ result.getRelation());
+ EXPECT_LT(0, result.getOrder());
+ EXPECT_EQ(2, result.getCommonLabels());
+
+ // "a.b.c.isc.example.org." and "w.x.y.isc.EXAMPLE.org.",
+ // case in-sensitive
+ result = lsd.compare(lse);
+ EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+ result.getRelation());
+ EXPECT_GT(0, result.getOrder());
+ EXPECT_EQ(4, result.getCommonLabels());
+
+ // "isc.example.org." and "isc.EXAMPLE.org.", case sensitive
+ lsd.stripLeft(3);
+ lse.stripLeft(3);
+ result = lsd.compare(lse, true);
+ EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+ result.getRelation());
+ EXPECT_LT(0, result.getOrder());
+ EXPECT_EQ(2, result.getCommonLabels());
+
+ // "isc.example.org." and "isc.EXAMPLE.org.", case in-sensitive
+ result = lsd.compare(lse);
+ EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+ result.getRelation());
+ EXPECT_EQ(0, result.getOrder());
+ EXPECT_EQ(4, result.getCommonLabels());
+
+ Name nf("a.b.c.isc.example.org");
+ LabelSequence lsf(nf);
+ Name ng("w.x.y.isc.EXAMPLE.org");
+ LabelSequence lsg(ng);
+
+ // lsf: "a.b.c.isc.example.org."
+ // lsg: "w.x.y.isc.EXAMPLE.org" (not absolute), case in-sensitive.
+ // the absolute one is always smaller.
+ lsg.stripRight(1);
+ result = lsg.compare(lsf); // lsg > lsf
+ EXPECT_EQ(isc::dns::NameComparisonResult::NONE, result.getRelation());
+ EXPECT_LT(0, result.getOrder());
+ EXPECT_EQ(0, result.getCommonLabels());
+
+ // "a.b.c.isc.example.org" (not absolute) and
+ // "w.x.y.isc.EXAMPLE.org" (not absolute), case in-sensitive
+ lsf.stripRight(1);
+ result = lsg.compare(lsf);
+ EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+ result.getRelation());
+ EXPECT_LT(0, result.getOrder());
+ EXPECT_EQ(3, result.getCommonLabels());
+
+ // "a.b.c.isc.example" (not absolute) and
+ // "w.x.y.isc.EXAMPLE" (not absolute), case in-sensitive
+ lsf.stripRight(1);
+ lsg.stripRight(1);
+ result = lsg.compare(lsf);
+ EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+ result.getRelation());
+ EXPECT_LT(0, result.getOrder());
+ EXPECT_EQ(2, result.getCommonLabels());
+
+ // lsf: "a.b.c" (not absolute) and
+ // lsg: "w.x.y" (not absolute), case in-sensitive; a.b.c < w.x.y;
+ // no common labels.
+ lsf.stripRight(2);
+ lsg.stripRight(2);
+ result = lsf.compare(lsg);
+ EXPECT_EQ(isc::dns::NameComparisonResult::NONE, result.getRelation());
+ EXPECT_GT(0, result.getOrder());
+ EXPECT_EQ(0, result.getCommonLabels());
+
+ // lsf2: a.b.cc (not absolute); a.b.c < a.b.cc, no common labels.
+ const Name nf2("a.b.cc");
+ LabelSequence lsf2(nf2);
+ lsf2.stripRight(1);
+ result = lsf.compare(lsf2);
+ EXPECT_EQ(isc::dns::NameComparisonResult::NONE, result.getRelation());
+ EXPECT_GT(0, result.getOrder());
+ EXPECT_EQ(0, result.getCommonLabels());
+
+ Name nh("aexample.org");
+ LabelSequence lsh(nh);
+ Name ni("bexample.org");
+ LabelSequence lsi(ni);
+
+ // "aexample.org" (not absolute) and
+ // "bexample.org" (not absolute), case in-sensitive
+ lsh.stripRight(1);
+ lsi.stripRight(1);
+ result = lsh.compare(lsi);
+ EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+ result.getRelation());
+ EXPECT_GT(0, result.getOrder());
+ EXPECT_EQ(1, result.getCommonLabels());
+
+ // "aexample" (not absolute) and
+ // "bexample" (not absolute), case in-sensitive;
+ // aexample < bexample; no common labels.
+ lsh.stripRight(1);
+ lsi.stripRight(1);
+ result = lsh.compare(lsi);
+ EXPECT_EQ(isc::dns::NameComparisonResult::NONE, result.getRelation());
+ EXPECT_GT(0, result.getOrder());
+ EXPECT_EQ(0, result.getCommonLabels());
+
+ Name nj("example.org");
+ LabelSequence lsj(nj);
+ Name nk("example.org");
+ LabelSequence lsk(nk);
+
+ // "example.org" (not absolute) and
+ // "example.org" (not absolute), case in-sensitive
+ lsj.stripRight(1);
+ lsk.stripRight(1);
+ result = lsj.compare(lsk);
+ EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+ result.getRelation());
+ EXPECT_EQ(0, result.getOrder());
+ EXPECT_EQ(2, result.getCommonLabels());
+
+ // "example" (not absolute) and
+ // "example" (not absolute), case in-sensitive
+ lsj.stripRight(1);
+ lsk.stripRight(1);
+ result = lsj.compare(lsk);
+ EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+ result.getRelation());
+ EXPECT_EQ(0, result.getOrder());
+ EXPECT_EQ(1, result.getCommonLabels());
+}
+
+void
+getDataCheck(const uint8_t* expected_data, size_t expected_len,
+ const LabelSequence& ls)
+{
+ size_t len;
+ const uint8_t* data = ls.getData(&len);
+ ASSERT_EQ(expected_len, len) << "Expected data: " << expected_data <<
+ ", label sequence: " << ls;
+ EXPECT_EQ(expected_len, ls.getDataLength()) <<
+ "Expected data: " << expected_data <<
+ ", label sequence: " << ls;
+ for (size_t i = 0; i < len; ++i) {
+ EXPECT_EQ(expected_data[i], data[i]) <<
+ "Difference at pos " << i << ": Expected data: " << expected_data <<
+ ", label sequence: " << ls;
+ }
+}
+
+// Convenient data converter for expected data. Label data must be of
+// uint8_t*, while it's convenient if we can specify some test data in
+// plain string (which is of char*). This wrapper converts the latter to
+// the former in a safer way.
+void
+getDataCheck(const char* expected_char_data, size_t expected_len,
+ const LabelSequence& ls)
+{
+ const vector<uint8_t> expected_data(expected_char_data,
+ expected_char_data + expected_len);
+ getDataCheck(&expected_data[0], expected_len, ls);
+}
+
+TEST_F(LabelSequenceTest, getData) {
+ getDataCheck("\007example\003org\000", 13, ls1);
+ getDataCheck("\007example\003com\000", 13, ls2);
+ getDataCheck("\007example\003org\000", 13, ls3);
+ getDataCheck("\003foo\003bar\004test\007example\000", 22, ls4);
+ getDataCheck("\007example\003ORG\000", 13, ls5);
+ getDataCheck("\007ExAmPlE\003org\000", 13, ls6);
+ getDataCheck("\000", 1, ls7);
+};
+
+TEST_F(LabelSequenceTest, stripLeft) {
+ EXPECT_TRUE(ls1.equals(ls3));
+ ls1.stripLeft(0);
+ getDataCheck("\007example\003org\000", 13, ls1);
+ EXPECT_TRUE(ls1.equals(ls3));
+ ls1.stripLeft(1);
+ getDataCheck("\003org\000", 5, ls1);
+ EXPECT_FALSE(ls1.equals(ls3));
+ ls1.stripLeft(1);
+ getDataCheck("\000", 1, ls1);
+ EXPECT_TRUE(ls1.equals(ls7));
+
+ ls2.stripLeft(2);
+ getDataCheck("\000", 1, ls2);
+ EXPECT_TRUE(ls2.equals(ls7));
+}
+
+TEST_F(LabelSequenceTest, stripRight) {
+ EXPECT_TRUE(ls1.equals(ls3));
+ ls1.stripRight(1);
+ getDataCheck("\007example\003org", 12, ls1);
+ EXPECT_FALSE(ls1.equals(ls3));
+ ls1.stripRight(1);
+ getDataCheck("\007example", 8, ls1);
+ EXPECT_FALSE(ls1.equals(ls3));
+
+ ASSERT_FALSE(ls1.equals(ls2));
+ ls2.stripRight(2);
+ getDataCheck("\007example", 8, ls2);
+ EXPECT_TRUE(ls1.equals(ls2));
+}
+
+TEST_F(LabelSequenceTest, stripOutOfRange) {
+ EXPECT_THROW(ls1.stripLeft(100), isc::OutOfRange);
+ EXPECT_THROW(ls1.stripLeft(5), isc::OutOfRange);
+ EXPECT_THROW(ls1.stripLeft(4), isc::OutOfRange);
+ EXPECT_THROW(ls1.stripLeft(3), isc::OutOfRange);
+ getDataCheck("\007example\003org\000", 13, ls1);
+
+ EXPECT_THROW(ls1.stripRight(100), isc::OutOfRange);
+ EXPECT_THROW(ls1.stripRight(5), isc::OutOfRange);
+ EXPECT_THROW(ls1.stripRight(4), isc::OutOfRange);
+ EXPECT_THROW(ls1.stripRight(3), isc::OutOfRange);
+ getDataCheck("\007example\003org\000", 13, ls1);
+}
+
+TEST_F(LabelSequenceTest, getLabelCount) {
+ EXPECT_EQ(3, ls1.getLabelCount());
+ ls1.stripLeft(0);
+ EXPECT_EQ(3, ls1.getLabelCount());
+ ls1.stripLeft(1);
+ EXPECT_EQ(2, ls1.getLabelCount());
+ ls1.stripLeft(1);
+ EXPECT_EQ(1, ls1.getLabelCount());
+
+ EXPECT_EQ(3, ls2.getLabelCount());
+ ls2.stripRight(1);
+ EXPECT_EQ(2, ls2.getLabelCount());
+ ls2.stripRight(1);
+ EXPECT_EQ(1, ls2.getLabelCount());
+
+ EXPECT_EQ(3, ls3.getLabelCount());
+ ls3.stripRight(2);
+ EXPECT_EQ(1, ls3.getLabelCount());
+
+ EXPECT_EQ(5, ls4.getLabelCount());
+ ls4.stripRight(3);
+ EXPECT_EQ(2, ls4.getLabelCount());
+
+ EXPECT_EQ(3, ls5.getLabelCount());
+ ls5.stripLeft(2);
+ EXPECT_EQ(1, ls5.getLabelCount());
+}
+
+TEST_F(LabelSequenceTest, comparePart) {
+ EXPECT_FALSE(ls1.equals(ls8));
+
+ // strip root label from example.org.
+ ls1.stripRight(1);
+ // strip foo from foo.example.org.bar.
+ ls8.stripLeft(1);
+ // strip bar. (i.e. bar and root) too
+ ls8.stripRight(2);
+
+ EXPECT_TRUE(ls1.equals(ls8));
+
+ // Data comparison
+ size_t len;
+ const uint8_t* data = ls1.getData(&len);
+ getDataCheck(data, len, ls8);
+}
+
+TEST_F(LabelSequenceTest, isAbsolute) {
+ ASSERT_TRUE(ls1.isAbsolute());
+
+ ls1.stripLeft(1);
+ ASSERT_TRUE(ls1.isAbsolute());
+ ls1.stripRight(1);
+ ASSERT_FALSE(ls1.isAbsolute());
+
+ ASSERT_TRUE(ls2.isAbsolute());
+ ls2.stripRight(1);
+ ASSERT_FALSE(ls2.isAbsolute());
+
+ ASSERT_TRUE(ls3.isAbsolute());
+ ls3.stripLeft(2);
+ ASSERT_TRUE(ls3.isAbsolute());
+}
+
+TEST_F(LabelSequenceTest, toText) {
+ EXPECT_EQ(".", ls7.toText());
+
+ EXPECT_EQ("example.org.", ls1.toText());
+ ls1.stripLeft(1);
+ EXPECT_EQ("org.", ls1.toText());
+ ls1.stripLeft(1);
+ EXPECT_EQ(".", ls1.toText());
+
+ EXPECT_EQ("example.com.", ls2.toText());
+ ls2.stripRight(1);
+ EXPECT_EQ("example.com", ls2.toText());
+ ls2.stripRight(1);
+ EXPECT_EQ("example", ls2.toText());
+
+ EXPECT_EQ("foo.example.org.bar.", ls8.toText());
+ ls8.stripRight(2);
+ EXPECT_EQ("foo.example.org", ls8.toText());
+
+ EXPECT_EQ(".", ls7.toText());
+ EXPECT_THROW(ls7.stripLeft(1), isc::OutOfRange);
+
+ Name n_long1("012345678901234567890123456789"
+ "012345678901234567890123456789012."
+ "012345678901234567890123456789"
+ "012345678901234567890123456789012."
+ "012345678901234567890123456789"
+ "012345678901234567890123456789012."
+ "012345678901234567890123456789"
+ "0123456789012345678901234567890");
+ LabelSequence ls_long1(n_long1);
+
+ EXPECT_EQ("012345678901234567890123456789"
+ "012345678901234567890123456789012."
+ "012345678901234567890123456789"
+ "012345678901234567890123456789012."
+ "012345678901234567890123456789"
+ "012345678901234567890123456789012."
+ "012345678901234567890123456789"
+ "0123456789012345678901234567890.", ls_long1.toText());
+ ls_long1.stripRight(1);
+ EXPECT_EQ("012345678901234567890123456789"
+ "012345678901234567890123456789012."
+ "012345678901234567890123456789"
+ "012345678901234567890123456789012."
+ "012345678901234567890123456789"
+ "012345678901234567890123456789012."
+ "012345678901234567890123456789"
+ "0123456789012345678901234567890", ls_long1.toText());
+
+ LabelSequence ls_long2(n_maxlabel);
+
+ EXPECT_EQ("0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6.", ls_long2.toText());
+ ls_long2.stripRight(1);
+ EXPECT_EQ("0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+ "0.1.2.3.4.5.6", ls_long2.toText());
+ ls_long2.stripRight(125);
+ EXPECT_EQ("0.1", ls_long2.toText());
+}
+
+// The following verifies that toRawText() returns a string
+// actual characters in place of escape sequences. We do not
+// bother with an exhaustive set of tests here as this is
+// not a primary use case.
+TEST_F(LabelSequenceTest, toRawText) {
+ Name n("a bc.$exa(m)ple.@org");
+ LabelSequence l(n);
+ EXPECT_EQ("a bc.$exa(m)ple.@org", l.toRawText(true));
+ EXPECT_EQ("a bc.$exa(m)ple.@org.", l.toRawText(false));
+
+ // toRawText is not supposed to do any sanity checks.
+ // Let's try with a very weird name.
+ Name n2("xtra\tchars\n.in.name");
+ LabelSequence l2(n2);
+ EXPECT_EQ("xtra\tchars\n.in.name.", l2.toRawText(false));
+}
+
+// The following are test data used in the getHash test below. Normally
+// we use example/documentation domain names for testing, but in this case
+// we'd specifically like to use more realistic data, and are intentionally
+// using real-world samples: They are the NS names of root and some top level
+// domains as of this test.
+const char* const root_servers[] = {
+ "a.root-servers.net", "b.root-servers.net", "c.root-servers.net",
+ "d.root-servers.net", "e.root-servers.net", "f.root-servers.net",
+ "g.root-servers.net", "h.root-servers.net", "i.root-servers.net",
+ "j.root-servers.net", "k.root-servers.net", "l.root-servers.net",
+ "m.root-servers.net", NULL
+};
+
+const char* const jp_servers[] = {
+ "a.dns.jp", "b.dns.jp", "c.dns.jp", "d.dns.jp", "e.dns.jp",
+ "f.dns.jp", "g.dns.jp", NULL
+};
+const char* const cn_servers[] = {
+ "a.dns.cn", "b.dns.cn", "c.dns.cn", "d.dns.cn", "e.dns.cn",
+ "ns.cernet.net", NULL
+};
+const char* const ca_servers[] = {
+ "k.ca-servers.ca", "e.ca-servers.ca", "a.ca-servers.ca", "z.ca-servers.ca",
+ "tld.isc-sns.net", "c.ca-servers.ca", "j.ca-servers.ca", "l.ca-servers.ca",
+ "sns-pb.isc.org", "f.ca-servers.ca", NULL
+};
+
+// A helper function used in the getHash test below.
+void
+hashDistributionCheck(const char* const* servers) {
+ const size_t BUCKETS = 64; // constant used in the MessageRenderer
+ set<Name> names;
+ vector<size_t> hash_counts(BUCKETS);
+
+ // Store all test names and their super domain names (excluding the
+ // "root" label) in the set, calculates their hash values, and increments
+ // the counter for the corresponding hash "bucket".
+ for (size_t i = 0; servers[i] != NULL; ++i) {
+ const Name name(servers[i]);
+ for (size_t l = 0; l < name.getLabelCount() - 1; ++l) {
+ pair<set<Name>::const_iterator, bool> ret =
+ names.insert(name.split(l));
+ if (ret.second) {
+ hash_counts[LabelSequence((*ret.first)).getHash(false) %
+ BUCKETS]++;
+ }
+ }
+ }
+
+ // See how many conflicts we have in the buckets. For the testing purpose
+ // we expect there's at most 2 conflicts in each set, which is an
+ // arbitrary choice (it should happen to succeed with the hash function
+ // and data we are using; if it's not the case, maybe with an update to
+ // the hash implementation, we should revise the test).
+ for (size_t i = 0; i < BUCKETS; ++i) {
+ EXPECT_GE(3, hash_counts[i]);
+ }
+}
+
+TEST_F(LabelSequenceTest, getHash) {
+ // Trivial case. The same sequence should have the same hash.
+ EXPECT_EQ(ls1.getHash(true), ls1.getHash(true));
+
+ // Check the case-insensitive mode behavior.
+ EXPECT_EQ(ls1.getHash(false), ls5.getHash(false));
+
+ // Check that the distribution of hash values is "not too bad" (such as
+ // everything has the same hash value due to a stupid bug). It's
+ // difficult to check such things reliably. We do some ad hoc tests here.
+ hashDistributionCheck(root_servers);
+ hashDistributionCheck(jp_servers);
+ hashDistributionCheck(cn_servers);
+ hashDistributionCheck(ca_servers);
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST_F(LabelSequenceTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << ls1;
+ EXPECT_EQ(ls1.toText(), oss.str());
+}
+
+TEST_F(LabelSequenceTest, serialize) {
+ // placeholder for serialized data. We use a sufficiently large space
+ // for testing the overwrapping cases below.
+ uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH * 3];
+
+ // vector to store expected and actual data
+ vector<LabelSequence> actual_labelseqs;
+ typedef pair<size_t, const uint8_t*> DataPair;
+ vector<DataPair> expected;
+
+ // An absolute sequence directly constructed from a valid name.
+ // labels = 3, offset sequence = 0, 8, 12, data = "example.com."
+ actual_labelseqs.push_back(ls1);
+ const uint8_t expected_data1[] = {
+ 3, 0, 8, 12, 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e',
+ 3, 'o', 'r', 'g', 0 };
+ expected.push_back(DataPair(sizeof(expected_data1), expected_data1));
+
+ // Strip the original one from right.
+ // labels = 2, offset sequence = 0, 8, data = "example.com" (non absolute)
+ LabelSequence ls_rstripped = ls1;
+ ls_rstripped.stripRight(1);
+ actual_labelseqs.push_back(ls_rstripped);
+ const uint8_t expected_data2[] = {
+ 2, 0, 8, 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e',
+ 3, 'o', 'r', 'g'};
+ expected.push_back(DataPair(sizeof(expected_data2), expected_data2));
+
+ // Strip the original one from left.
+ // labels = 2, offset sequence = 0, 4, data = "com."
+ // Note that offsets are adjusted so that they begin with 0.
+ LabelSequence ls_lstripped = ls1;
+ ls_lstripped.stripLeft(1);
+ actual_labelseqs.push_back(ls_lstripped);
+ const uint8_t expected_data3[] = { 2, 0, 4, 3, 'o', 'r', 'g', 0 };
+ expected.push_back(DataPair(sizeof(expected_data3), expected_data3));
+
+ // Root label.
+ LabelSequence ls_root(Name::ROOT_NAME());
+ actual_labelseqs.push_back(ls_root);
+ const uint8_t expected_data4[] = { 1, 0, 0 };
+ expected.push_back(DataPair(sizeof(expected_data4), expected_data4));
+
+ // Non absolute single-label.
+ LabelSequence ls_single = ls_rstripped;
+ ls_single.stripRight(1);
+ actual_labelseqs.push_back(ls_single);
+ const uint8_t expected_data5[] = {
+ 1, 0, 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e' };
+ expected.push_back(DataPair(sizeof(expected_data5), expected_data5));
+
+ // Labels containing a longest possible label
+ const Name name_longlabel(std::string(63, 'x')); // 63 'x's
+ LabelSequence ls_longlabel(name_longlabel);
+ actual_labelseqs.push_back(ls_longlabel);
+ vector<uint8_t> expected_data6;
+ expected_data6.push_back(2); // 2 labels
+ expected_data6.push_back(0); // 1st offset
+ expected_data6.push_back(64); // 2nd offset
+ expected_data6.push_back(63); // 1st label length
+ expected_data6.insert(expected_data6.end(), 63, 'x'); // 1st label: 63 'x's
+ expected_data6.push_back(0); // 2nd label: trailing 0
+ expected.push_back(DataPair(expected_data6.size(), &expected_data6[0]));
+
+ // Max number of labels and longest possible name
+ EXPECT_EQ(Name::MAX_WIRE, n_maxlabel.getLength());
+ LabelSequence ls_maxlabel(n_maxlabel);
+ actual_labelseqs.push_back(ls_maxlabel);
+ vector<uint8_t> expected_data7;
+ expected_data7.push_back(Name::MAX_LABELS); // number of labels
+ for (size_t i = 0; i < Name::MAX_LABELS; ++i) {
+ expected_data7.push_back(i * 2); // each label has length and 1 byte
+ }
+ // Copy wire data of the name
+ isc::util::OutputBuffer ob(0);
+ n_maxlabel.toWire(ob);
+ expected_data7.insert(expected_data7.end(),
+ static_cast<const uint8_t*>(ob.getData()),
+ static_cast<const uint8_t*>(ob.getData()) +
+ ob.getLength());
+ expected.push_back(DataPair(expected_data7.size(), &expected_data7[0]));
+
+ // For each data set, serialize the labels and compare the data to the
+ // expected one.
+ vector<DataPair>::const_iterator it = expected.begin();
+ vector<LabelSequence>::const_iterator itl = actual_labelseqs.begin();
+ for (; it != expected.end(); ++it, ++itl) {
+ SCOPED_TRACE(itl->toText());
+
+ const size_t serialized_len = itl->getSerializedLength();
+
+ ASSERT_GE(LabelSequence::MAX_SERIALIZED_LENGTH, serialized_len);
+ itl->serialize(labels_buf, serialized_len);
+ EXPECT_EQ(it->first, serialized_len);
+ EXPECT_EQ(0, memcmp(it->second, labels_buf, serialized_len));
+
+ EXPECT_EQ(NameComparisonResult::EQUAL,
+ LabelSequence(labels_buf).compare(*itl).getRelation());
+
+ // Shift the data to the middle of the buffer for overwrap check
+ uint8_t* const bp = labels_buf;
+ std::memcpy(bp + serialized_len, bp, serialized_len);
+ // Memory layout is now as follows:
+ // <- ser_len -> <- ser_len ------>
+ // bp bp+ser_len bp+(ser_len*2)
+ // olen,odata,ndata
+
+ // end of buffer would be the first byte of offsets: invalid.
+ EXPECT_THROW(LabelSequence(bp + serialized_len).
+ serialize(bp + 2, serialized_len),
+ isc::BadValue);
+ // begin of buffer would be the last byte of ndata: invalid.
+ EXPECT_THROW(LabelSequence(bp + serialized_len).
+ serialize(bp + (2 * serialized_len) - 1, serialized_len),
+ isc::BadValue);
+ // A boundary safe case: buffer is placed after the sequence data.
+ // should cause no disruption.
+ LabelSequence(bp + serialized_len).
+ serialize(bp + 2 * serialized_len, serialized_len);
+ // A boundary safe case: buffer is placed before the sequence data
+ // should cause no disruption. (but the original serialized data will
+ // be overridden, so it can't be used any more)
+ LabelSequence(bp + serialized_len).
+ serialize(bp + 1, serialized_len);
+ }
+
+ EXPECT_THROW(ls1.serialize(labels_buf, ls1.getSerializedLength() - 1),
+ isc::BadValue);
+}
+
+#ifdef ENABLE_DEBUG
+
+// These checks are enabled only in debug mode in the LabelSequence
+// class.
+TEST_F(LabelSequenceTest, badDeserialize) {
+ EXPECT_THROW(LabelSequence(NULL), isc::BadValue);
+ const uint8_t zero_offsets[] = { 0 };
+ EXPECT_THROW(LabelSequence ls(zero_offsets), isc::BadValue);
+ const uint8_t toomany_offsets[] = { Name::MAX_LABELS + 1 };
+ EXPECT_THROW(LabelSequence ls(toomany_offsets), isc::BadValue);
+
+ // (second) offset does not match actual label length
+ const uint8_t offsets_wrongoffset[] = { 2, 0, 64, 1 };
+ EXPECT_THROW(LabelSequence ls(offsets_wrongoffset), isc::BadValue);
+
+ // offset matches, but exceeds MAX_LABEL_LEN
+ const uint8_t offsets_toolonglabel[] = { 2, 0, 64, 64 };
+ EXPECT_THROW(LabelSequence ls(offsets_toolonglabel), isc::BadValue);
+
+ // Inconsistent data: an offset is lower than the previous offset
+ const uint8_t offsets_lower[] = { 3, // # of offsets
+ 0, 2, 1, // offsets
+ 1, 'a', 1, 'b', 0};
+ EXPECT_THROW(LabelSequence ls(offsets_lower), isc::BadValue);
+
+ // Inconsistent data: an offset is equal to the previous offset
+ const uint8_t offsets_noincrease[] = { 2, 0, 0, 0, 0 };
+ EXPECT_THROW(LabelSequence ls(offsets_noincrease), isc::BadValue);
+}
+
+#endif
+
+namespace {
+
+// Helper function; repeatedly calls
+// - Initially, all three labelsequences should be the same
+// - repeatedly performs:
+// - checks all three are equal
+// - stripLeft on ls1
+// - checks ls1 and ls2 are different, and ls2 and ls3 are equal
+// - stripLeft on ls2
+// - checks ls1 and ls2 are equal, and ls2 and ls3 are different
+// - stripLeft on ls3
+//
+// (this test makes sure the stripLeft of one has no effect on the other
+// two, and that the strip properties hold regardless of how they were
+// constructed)
+//
+void stripLeftCheck(LabelSequence ls1, LabelSequence ls2, LabelSequence ls3) {
+ ASSERT_LT(1, ls1.getLabelCount());
+ while (ls1.getLabelCount() > 1) {
+ check_equal(ls1, ls2);
+ check_equal(ls2, ls3);
+
+ ls1.stripLeft(1);
+ check_compare(ls1, ls2, isc::dns::NameComparisonResult::SUPERDOMAIN,
+ ls1.getLabelCount(), true, -1);
+ check_equal(ls2, ls3);
+
+ ls2.stripLeft(1);
+ check_equal(ls1, ls2);
+ check_compare(ls2, ls3, isc::dns::NameComparisonResult::SUPERDOMAIN,
+ ls1.getLabelCount(), true, -1);
+
+ ls3.stripLeft(1);
+ }
+}
+
+// Similar to stripLeftCheck, but using stripRight()
+void stripRightCheck(LabelSequence ls1, LabelSequence ls2, LabelSequence ls3) {
+ ASSERT_LT(1, ls1.getLabelCount());
+ while (ls1.getLabelCount() > 1) {
+ check_equal(ls1, ls2);
+ check_equal(ls2, ls3);
+
+ ls1.stripRight(1);
+ check_compare(ls1, ls2, isc::dns::NameComparisonResult::NONE, 0,
+ false);
+ check_equal(ls2, ls3);
+
+ ls2.stripRight(1);
+ check_equal(ls1, ls2);
+ check_compare(ls2, ls3, isc::dns::NameComparisonResult::NONE, 0,
+ false);
+
+ ls3.stripRight(1);
+ }
+}
+
+} // end anonymous namespace
+
+class ExtendableLabelSequenceTest : public ::testing::Test {
+public:
+ ExtendableLabelSequenceTest() : bar("bar."),
+ example_org("example.org"),
+ foo("foo."),
+ foo_bar("foo.bar."),
+ foo_bar_example_org("foo.bar.example.org."),
+ foo_bar_foo_bar("foo.bar.foo.bar."),
+ foo_example("foo.example."),
+ org("org")
+ {
+ // explicitly set to non-zero data, to make sure
+ // we don't try to use data we don't set
+ memset(buf, 0xff, LabelSequence::MAX_SERIALIZED_LENGTH);
+ }
+
+ Name bar;
+ Name example_org;
+ Name foo;
+ Name foo_bar;
+ Name foo_bar_example_org;
+ Name foo_bar_foo_bar;
+ Name foo_example;
+ Name org;
+
+ uint8_t buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+};
+
+// Test that 'extendable' labelsequences behave correctly when using
+// stripLeft() and stripRight()
+TEST_F(ExtendableLabelSequenceTest, extendableLabelSequence) {
+ LabelSequence ls1(example_org);
+ LabelSequence ls2(example_org);
+
+ LabelSequence els(ls1, buf);
+ // ls1 is absolute, so els should be too
+ EXPECT_TRUE(els.isAbsolute());
+ check_equal(ls1, els);
+
+ ASSERT_EQ(ls1.getDataLength(), els.getDataLength());
+ stripLeftCheck(ls1, els, ls2);
+ stripRightCheck(ls1, els, ls2);
+
+ // Creating an extendable labelsequence from a non-absolute
+ // label sequence should result in a non-absolute label sequence
+ ls1.stripRight(1);
+ els = LabelSequence(ls1, buf);
+ EXPECT_FALSE(els.isAbsolute());
+ check_equal(ls1, els);
+
+ // and extending with the root label should make it absolute again
+ els.extend(LabelSequence(Name(".")), buf);
+ EXPECT_TRUE(els.isAbsolute());
+ check_equal(ls2, els);
+}
+
+// Test that 'extendable' LabelSequences behave correctly when initialized
+// with a stripped source LabelSequence
+TEST_F(ExtendableLabelSequenceTest, extendableLabelSequenceLeftStrippedSource) {
+ LabelSequence ls1(foo_bar_example_org);
+ LabelSequence ls2(foo_bar_example_org);
+
+ while (ls1.getLabelCount() > 2) {
+ ls1.stripLeft(1);
+ ls2.stripLeft(1);
+
+ LabelSequence els(ls1, buf);
+
+ ASSERT_EQ(ls1.getDataLength(), els.getDataLength());
+ stripLeftCheck(ls1, els, ls2);
+ stripRightCheck(ls1, els, ls2);
+ }
+}
+
+TEST_F(ExtendableLabelSequenceTest, extendableLabelSequenceRightStrippedSource) {
+ LabelSequence ls1(foo_bar_example_org);
+ LabelSequence ls2(foo_bar_example_org);
+
+ while (ls1.getLabelCount() > 2) {
+ ls1.stripRight(1);
+ ls2.stripRight(1);
+
+ LabelSequence els(ls1, buf);
+
+ ASSERT_EQ(ls1.getDataLength(), els.getDataLength());
+ stripLeftCheck(ls1, els, ls2);
+ stripRightCheck(ls1, els, ls2);
+ }
+}
+
+// Check some basic 'extend' functionality
+TEST_F(ExtendableLabelSequenceTest, extend) {
+ LabelSequence ls1(foo_bar);
+ LabelSequence ls2(foo);
+ LabelSequence ls3(bar);
+ LabelSequence ls4(foo_bar);
+
+ LabelSequence els(ls2, buf);
+
+ check_compare(ls1, els, isc::dns::NameComparisonResult::COMMONANCESTOR, 1,
+ true, -4);
+ els.extend(ls3, buf);
+ EXPECT_TRUE(els.isAbsolute());
+
+ check_equal(ls1, els);
+ stripLeftCheck(ls1, els, ls4);
+ stripRightCheck(ls1, els, ls4);
+
+ // strip, then extend again
+ els.stripRight(2); // (2, 1 for root label, 1 for last label)
+ els.extend(ls3, buf);
+ EXPECT_TRUE(els.isAbsolute());
+ check_equal(ls1, els);
+
+ // Extending again should make it different
+ els.extend(ls3, buf);
+ EXPECT_TRUE(els.isAbsolute());
+ check_compare(ls1, els, isc::dns::NameComparisonResult::COMMONANCESTOR, 2,
+ true, 4);
+
+ // Extending with a non-absolute name should make it non-absolute as well
+ ls3.stripRight(1);
+ els.extend(ls3, buf);
+ EXPECT_FALSE(els.isAbsolute());
+
+ Name check_name("foo.bar.bar.bar");
+ LabelSequence check_ls(check_name);
+ check_ls.stripRight(1);
+ check_equal(check_ls, els);
+
+ // And try extending when both are not absolute
+ els.stripRight(3);
+ ls1.stripRight(1);
+ EXPECT_FALSE(els.isAbsolute());
+ els.extend(ls3, buf);
+ EXPECT_FALSE(els.isAbsolute());
+ check_equal(ls1, els);
+
+ // Extending non-absolute with absolute should make it absolute again
+ EXPECT_FALSE(els.isAbsolute());
+ els.extend(LabelSequence(Name("absolute.")), buf);
+ EXPECT_TRUE(els.isAbsolute());
+ check_equal(LabelSequence(Name("foo.bar.absolute")), els);
+}
+
+TEST_F(ExtendableLabelSequenceTest, extendLeftStripped) {
+ LabelSequence ls1(foo_example);
+ LabelSequence ls2(example_org);
+ LabelSequence ls3(org);
+
+ LabelSequence els(ls1, buf);
+
+ els.stripLeft(1);
+ els.extend(ls3, buf);
+ EXPECT_TRUE(els.isAbsolute());
+ check_equal(ls2, els);
+}
+
+// Check that when extending with itself, it does not cause horrible failures
+TEST_F(ExtendableLabelSequenceTest, extendWithItself) {
+ LabelSequence ls1(foo_bar);
+ LabelSequence ls2(foo_bar_foo_bar);
+
+ LabelSequence els(ls1, buf);
+
+ els.extend(els, buf);
+ EXPECT_TRUE(els.isAbsolute());
+ check_equal(ls2, els);
+
+ // Also try for non-absolute names
+ ls2.stripRight(1);
+ els = LabelSequence(ls1, buf);
+ els.stripRight(1);
+ els.extend(els, buf);
+ EXPECT_FALSE(els.isAbsolute());
+ check_equal(ls2, els);
+
+ // Once more, now start out with non-absolute labelsequence
+ ls1.stripRight(1);
+ els = LabelSequence(ls1, buf);
+ els.extend(els, buf);
+ EXPECT_FALSE(els.isAbsolute());
+ check_equal(ls2, els);
+}
+
+// Test that 'extending' with just a root label is a no-op, iff the original
+// was already absolute
+TEST_F(ExtendableLabelSequenceTest, extendWithRoot) {
+ LabelSequence ls1(example_org);
+
+ LabelSequence els(LabelSequence(ls1, buf));
+ check_equal(ls1, els);
+ els.extend(LabelSequence(Name(".")), buf);
+ EXPECT_TRUE(els.isAbsolute());
+ check_equal(ls1, els);
+
+ // but not if the original was not absolute (it will be equal to
+ // the original labelsequence used above, but not the one it was based
+ // on).
+ LabelSequence ls2(example_org);
+ ls2.stripRight(1);
+ els = LabelSequence(ls2, buf);
+ EXPECT_FALSE(els.isAbsolute());
+ els.extend(LabelSequence(Name(".")), buf);
+ EXPECT_TRUE(els.isAbsolute());
+ check_equal(ls1, els);
+ check_compare(ls2, els, isc::dns::NameComparisonResult::NONE, 0, true, 3);
+}
+
+// Check possible failure modes of extend()
+TEST_F(ExtendableLabelSequenceTest, extendBadData) {
+ LabelSequence ls1(example_org);
+
+ LabelSequence els(ls1, buf);
+
+ // try use with unrelated labelsequence
+ EXPECT_THROW(ls1.extend(ls1, buf), isc::BadValue);
+
+ // Create a long name, but so that we can still extend once
+ Name longlabel("1234567890123456789012345678901234567890"
+ "12345678901234567890");
+ LabelSequence long_ls(longlabel);
+ els = LabelSequence(long_ls, buf);
+ els.extend(els, buf);
+ els.extend(long_ls, buf);
+ els.extend(long_ls, buf);
+ ASSERT_EQ(245, els.getDataLength());
+ // Extending once more with 10 bytes should still work
+ els.extend(LabelSequence(Name("123456789")), buf);
+ EXPECT_TRUE(els.isAbsolute());
+
+ // Extended label sequence should now look like
+ const Name full_name(
+ "123456789012345678901234567890123456789012345678901234567890."
+ "123456789012345678901234567890123456789012345678901234567890."
+ "123456789012345678901234567890123456789012345678901234567890."
+ "123456789012345678901234567890123456789012345678901234567890."
+ "123456789.");
+ const LabelSequence full_ls(full_name);
+ check_equal(full_ls, els);
+
+ // But now, even the shortest extension should fail
+ EXPECT_THROW(els.extend(LabelSequence(Name("1")), buf), isc::BadValue);
+
+ // Check it hasn't been changed
+ EXPECT_TRUE(els.isAbsolute());
+ check_equal(full_ls, els);
+
+ // Also check that extending past MAX_LABELS is not possible
+ Name shortname("1.");
+ LabelSequence short_ls(shortname);
+ els = LabelSequence(short_ls, buf);
+ for (size_t i=0; i < 126; ++i) {
+ els.extend(short_ls, buf);
+ }
+
+ // Should now look like this
+ const Name full_name2(
+ "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1."
+ "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1."
+ "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1."
+ "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1."
+ "1.1.1.1.1.1.1.");
+ const LabelSequence full_ls2(full_name2);
+ EXPECT_TRUE(els.isAbsolute());
+ check_equal(full_ls2, els);
+
+ EXPECT_THROW(els.extend(short_ls, buf), isc::BadValue);
+
+ EXPECT_TRUE(els.isAbsolute());
+ check_equal(full_ls2, els);
+}
+
+// Check the static fixed 'wildcard' LabelSequence
+TEST(WildCardLabelSequence, wildcard) {
+ ASSERT_FALSE(LabelSequence::WILDCARD().isAbsolute());
+ ASSERT_EQ("*", LabelSequence::WILDCARD().toText());
+}
+
+}
diff --git a/src/lib/dns/tests/master_lexer_inputsource_unittest.cc b/src/lib/dns/tests/master_lexer_inputsource_unittest.cc
index 8b13789179..c5f618af06 100644
--- a/src/lib/dns/tests/master_lexer_inputsource_unittest.cc
+++ b/src/lib/dns/tests/master_lexer_inputsource_unittest.cc
@@ -1 +1,368 @@
+// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <dns/master_lexer_inputsource.h>
+#include <dns/master_lexer.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <string.h>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::master_lexer_internal;
+
+namespace {
+
+const char* const test_input =
+ "Line1 to scan.\nLine2 to scan.\nLine3 to scan.\n";
+
+class InputSourceTest : public ::testing::Test {
+protected:
+ InputSourceTest() :
+ str_(test_input),
+ str_length_(strlen(str_)),
+ iss_(str_),
+ source_(iss_)
+ {}
+
+ const char* str_;
+ const size_t str_length_;
+ stringstream iss_;
+ InputSource source_;
+};
+
+// Test the default return values set during InputSource construction.
+TEST_F(InputSourceTest, defaults) {
+ EXPECT_EQ(1, source_.getCurrentLine());
+ EXPECT_FALSE(source_.atEOF());
+}
+
+// getName() on file and stream sources
+TEST_F(InputSourceTest, getName) {
+ EXPECT_EQ(0, source_.getName().find("stream-"));
+
+ // Use some file; doesn't really matter what.
+ InputSource source2(TEST_DATA_SRCDIR "/masterload.txt");
+ EXPECT_EQ(TEST_DATA_SRCDIR "/masterload.txt", source2.getName());
+}
+
+TEST_F(InputSourceTest, nonExistentFile) {
+ EXPECT_THROW({
+ InputSource source(TEST_DATA_SRCDIR "/does-not-exist");
+ }, InputSource::OpenError);
+}
+
+// getChar() should return characters from the input stream in
+// sequence. ungetChar() should skip backwards.
+void
+checkGetAndUngetChar(InputSource& source,
+ const char* str, const size_t str_length)
+{
+ for (size_t i = 0; i < str_length; ++i) {
+ EXPECT_EQ(str[i], source.getChar());
+ EXPECT_EQ(i + 1, source.getPosition());
+ EXPECT_FALSE(source.atEOF());
+ }
+
+ // At this point, we still have not reached EOF.
+ EXPECT_FALSE(source.atEOF());
+
+ // This should cause EOF to be set.
+ EXPECT_EQ(InputSource::END_OF_STREAM, source.getChar());
+
+ // Now, EOF should be set.
+ EXPECT_TRUE(source.atEOF());
+
+ // It doesn't increase the position count.
+ EXPECT_EQ(str_length, source.getPosition());
+ EXPECT_EQ(str_length, source.getSize()); // this should be == getSize().
+
+ // Now, let's go backwards. This should cause the EOF to be set to
+ // false.
+ source.ungetChar();
+
+ // Now, EOF should be false.
+ EXPECT_FALSE(source.atEOF());
+
+ // But the position shouldn't change.
+ EXPECT_EQ(str_length, source.getPosition());
+
+ // This should cause EOF to be set again.
+ EXPECT_EQ(InputSource::END_OF_STREAM, source.getChar());
+
+ // Now, EOF should be set.
+ EXPECT_TRUE(source.atEOF());
+
+ // Now, let's go backwards in a loop. Start by skipping the EOF.
+ source.ungetChar();
+
+ for (size_t i = 0; i < str_length; ++i) {
+ const size_t index = str_length - 1 - i;
+ // Skip one character.
+ source.ungetChar();
+ EXPECT_EQ(str[index], source.getChar());
+ EXPECT_EQ(index + 1, source.getPosition());
+ // Skip the character we received again.
+ source.ungetChar();
+ }
+
+ // Skipping past the start of buffer should throw.
+ EXPECT_THROW(source.ungetChar(), InputSource::UngetBeforeBeginning);
+}
+
+TEST_F(InputSourceTest, stream) {
+ checkGetAndUngetChar(source_, str_, str_length_);
+}
+
+TEST_F(InputSourceTest, file) {
+ std::ifstream fs(TEST_DATA_SRCDIR "/masterload.txt");
+ const std::string str((std::istreambuf_iterator<char>(fs)),
+ std::istreambuf_iterator<char>());
+ fs.close();
+
+ InputSource source(TEST_DATA_SRCDIR "/masterload.txt");
+ checkGetAndUngetChar(source, str.c_str(), str.size());
+}
+
+// ungetAll() should skip back to the place where the InputSource
+// started at construction, or the last saved start of line.
+TEST_F(InputSourceTest, ungetAll) {
+ while (!source_.atEOF()) {
+ source_.getChar();
+ }
+
+ // Now, we are at EOF.
+ EXPECT_TRUE(source_.atEOF());
+ EXPECT_EQ(4, source_.getCurrentLine());
+
+ source_.ungetAll();
+
+ // Now we are back to where we started.
+ EXPECT_EQ(1, source_.getCurrentLine());
+ EXPECT_FALSE(source_.atEOF());
+ EXPECT_EQ(0, source_.getPosition());
+}
+
+TEST_F(InputSourceTest, compact) {
+ // Compact at the start
+ source_.compact();
+
+ // Ungetting here must throw.
+ EXPECT_THROW(source_.ungetChar(), InputSource::UngetBeforeBeginning);
+
+ for (size_t i = 0; i < str_length_; ++i) {
+ EXPECT_EQ(str_[i], source_.getChar());
+ EXPECT_FALSE(source_.atEOF());
+ }
+
+ // At this point, we still have not reached EOF.
+ EXPECT_FALSE(source_.atEOF());
+
+ // This should cause EOF to be set.
+ EXPECT_EQ(InputSource::END_OF_STREAM, source_.getChar());
+
+ // Now, EOF should be set.
+ EXPECT_TRUE(source_.atEOF());
+ EXPECT_EQ(4, source_.getCurrentLine());
+
+ // Compact again
+ source_.compact();
+
+ // We are still at EOF.
+ EXPECT_TRUE(source_.atEOF());
+ EXPECT_EQ(4, source_.getCurrentLine());
+
+ // compact shouldn't change the position count.
+ EXPECT_EQ(source_.getSize(), source_.getPosition());
+
+ // Skip the EOF.
+ source_.ungetChar();
+
+ // Ungetting here must throw.
+ EXPECT_THROW(source_.ungetChar(), InputSource::UngetBeforeBeginning);
+
+ EXPECT_EQ(InputSource::END_OF_STREAM, source_.getChar());
+ EXPECT_TRUE(source_.atEOF());
+}
+
+TEST_F(InputSourceTest, markDuring) {
+ // First, skip to line 2.
+ while (!source_.atEOF() &&
+ (source_.getCurrentLine() != 2)) {
+ source_.getChar();
+ }
+ EXPECT_FALSE(source_.atEOF());
+ EXPECT_EQ(2, source_.getCurrentLine());
+
+ // Now, unget a couple of characters. This should cause the
+ // buffer_pos_ to be not equal to the size of the buffer.
+ source_.ungetChar();
+ source_.ungetChar();
+
+ // Now "mark" the source, meaning that we save line number and also
+ // compact the internal buffer at this stage.
+ source_.mark();
+
+ // Ungetting here must throw.
+ EXPECT_THROW(source_.ungetChar(), InputSource::UngetBeforeBeginning);
+
+ for (size_t i = 13; i < str_length_; ++i) {
+ EXPECT_EQ(str_[i], source_.getChar());
+ EXPECT_FALSE(source_.atEOF());
+ }
+
+ // At this point, we still have not reached EOF.
+ EXPECT_FALSE(source_.atEOF());
+
+ // This should cause EOF to be set.
+ EXPECT_EQ(InputSource::END_OF_STREAM, source_.getChar());
+
+ // Now, EOF should be set.
+ EXPECT_TRUE(source_.atEOF());
+
+ // Now, ungetAll() and check where it goes back.
+ source_.ungetAll();
+
+ // Ungetting here must throw.
+ EXPECT_THROW(source_.ungetChar(), InputSource::UngetBeforeBeginning);
+
+ for (size_t i = 13; i < str_length_; ++i) {
+ EXPECT_EQ(str_[i], source_.getChar());
+ EXPECT_FALSE(source_.atEOF());
+ }
+
+ // At this point, we still have not reached EOF.
+ EXPECT_FALSE(source_.atEOF());
+
+ // This should cause EOF to be set.
+ EXPECT_EQ(InputSource::END_OF_STREAM, source_.getChar());
+
+ // Now, EOF should be set.
+ EXPECT_TRUE(source_.atEOF());
+}
+
+// Test line counters.
+TEST_F(InputSourceTest, lines) {
+ size_t line = 1;
+ while (!source_.atEOF()) {
+ if (source_.getChar() == '\n') {
+ ++line;
+ }
+ EXPECT_EQ(line, source_.getCurrentLine());
+ }
+
+ // Now, we are at EOF.
+ EXPECT_TRUE(source_.atEOF());
+ EXPECT_EQ(4, source_.getCurrentLine());
+
+ // Go backwards 2 characters, skipping the last EOF and '\n'.
+ source_.ungetChar();
+ source_.ungetChar();
+
+ EXPECT_FALSE(source_.atEOF());
+ EXPECT_EQ(3, source_.getCurrentLine());
+
+ source_.ungetAll();
+
+ // Now we are back to where we started.
+ EXPECT_EQ(1, source_.getCurrentLine());
+ EXPECT_FALSE(source_.atEOF());
+
+ // Now check that line numbers are decremented properly (as much as
+ // possible using the available API).
+ while (!source_.atEOF()) {
+ source_.getChar();
+ }
+ line = source_.getCurrentLine();
+
+ // Now, we are at EOF.
+ EXPECT_TRUE(source_.atEOF());
+ EXPECT_EQ(4, line);
+
+ EXPECT_THROW({
+ while (true) {
+ source_.ungetChar();
+ EXPECT_TRUE(((line == source_.getCurrentLine()) ||
+ ((line - 1) == source_.getCurrentLine())));
+ line = source_.getCurrentLine();
+ }
+ }, InputSource::UngetBeforeBeginning);
+
+ // Now we are back to where we started.
+ EXPECT_EQ(1, source_.getCurrentLine());
+}
+
+// ungetAll() after saveLine() should skip back to the last-saved place.
+TEST_F(InputSourceTest, saveLine) {
+ // First, skip to line 2.
+ while (!source_.atEOF() &&
+ (source_.getCurrentLine() != 2)) {
+ source_.getChar();
+ }
+ EXPECT_FALSE(source_.atEOF());
+ EXPECT_EQ(2, source_.getCurrentLine());
+
+ // Now, save the line.
+ source_.saveLine();
+
+ // Now, go to EOF
+ while (!source_.atEOF()) {
+ source_.getChar();
+ }
+
+ // Now, we are at EOF.
+ EXPECT_TRUE(source_.atEOF());
+ EXPECT_EQ(4, source_.getCurrentLine());
+
+ // Now, ungetAll() and check where it goes back.
+ source_.ungetAll();
+
+ // Now we are back to where we last-saved.
+ EXPECT_EQ(2, source_.getCurrentLine());
+ EXPECT_FALSE(source_.atEOF());
+}
+
+TEST_F(InputSourceTest, getSize) {
+ // A simple case using string stream
+ EXPECT_EQ(strlen(test_input), source_.getSize());
+
+ // Check it works with an empty input
+ istringstream iss("");
+ EXPECT_EQ(0, InputSource(iss).getSize());
+
+ // Pretend there's an error in seeking in the stream. It will be
+ // considered a seek specific error, and getSize() returns "unknown".
+ iss.setstate(std::ios_base::failbit);
+ EXPECT_EQ(MasterLexer::SOURCE_SIZE_UNKNOWN, InputSource(iss).getSize());
+ // The fail bit should have been cleared.
+ EXPECT_FALSE(iss.fail());
+
+ // Pretend there's a *critical* error in the stream. The constructor will
+ // throw in the attempt of getting the input size.
+ iss.setstate(std::ios_base::badbit);
+ EXPECT_THROW(InputSource isrc(iss), InputSource::OpenError);
+
+ // Check with input source from file name. We hardcode the file size
+ // for simplicity. It won't change too often.
+ EXPECT_EQ(143, InputSource(TEST_DATA_SRCDIR "/masterload.txt").getSize());
+}
+
+TEST_F(InputSourceTest, getPosition) {
+ // Initially the position is set to 0. Other cases are tested in tests
+ // for get and unget.
+ EXPECT_EQ(0, source_.getPosition());
+ EXPECT_EQ(0, InputSource(TEST_DATA_SRCDIR "/masterload.txt").getPosition());
+}
+
+} // end namespace
diff --git a/src/lib/dns/tests/master_lexer_state_unittest.cc b/src/lib/dns/tests/master_lexer_state_unittest.cc
index 8b13789179..e810136068 100644
--- a/src/lib/dns/tests/master_lexer_state_unittest.cc
+++ b/src/lib/dns/tests/master_lexer_state_unittest.cc
@@ -1 +1,607 @@
+// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <dns/master_lexer.h>
+#include <dns/master_lexer_inputsource.h>
+#include <dns/master_lexer_state.h>
+
+#include <gtest/gtest.h>
+
+#include <sstream>
+
+using namespace isc::dns;
+using namespace master_lexer_internal;
+
+namespace {
+typedef MasterToken Token; // shortcut
+
+class MasterLexerStateTest : public ::testing::Test {
+protected:
+ MasterLexerStateTest() : common_options(MasterLexer::INITIAL_WS),
+ s_null(NULL),
+ s_crlf(State::getInstance(State::CRLF)),
+ s_string(State::getInstance(State::String)),
+ s_qstring(State::getInstance(State::QString)),
+ s_number(State::getInstance(State::Number)),
+ options(MasterLexer::NONE),
+ orig_options(options)
+ {}
+
+ // Specify INITIAL_WS as common initial options.
+ const MasterLexer::Options common_options;
+ MasterLexer lexer;
+ const State* const s_null;
+ const State& s_crlf;
+ const State& s_string;
+ const State& s_qstring;
+ const State& s_number;
+ std::stringstream ss;
+ MasterLexer::Options options, orig_options;
+};
+
+// Common check for the end-of-file condition.
+// Token is set to END_OF_FILE, and the lexer was NOT last eol state.
+// Passed state can be any valid one; they are stateless, just providing the
+// interface for inspection.
+void
+eofCheck(const State& state, MasterLexer& lexer) {
+ EXPECT_EQ(Token::END_OF_FILE, state.getToken(lexer).getType());
+ EXPECT_FALSE(state.wasLastEOL(lexer));
+}
+
+TEST_F(MasterLexerStateTest, startAndEnd) {
+ // A simple case: the input is empty, so we begin with start and
+ // are immediately done.
+ lexer.pushSource(ss);
+ EXPECT_EQ(s_null, State::start(lexer, common_options));
+ eofCheck(s_crlf, lexer);
+}
+
+TEST_F(MasterLexerStateTest, startToEOL) {
+ ss << "\n";
+ lexer.pushSource(ss);
+
+ EXPECT_EQ(s_null, State::start(lexer, common_options));
+ EXPECT_TRUE(s_crlf.wasLastEOL(lexer));
+ EXPECT_EQ(Token::END_OF_LINE, s_crlf.getToken(lexer).getType());
+
+ // The next lexer session will reach EOF. Same eof check should pass.
+ EXPECT_EQ(s_null, State::start(lexer, common_options));
+ eofCheck(s_crlf, lexer);
+}
+
+TEST_F(MasterLexerStateTest, space) {
+ // repeat '\t\n' twice (see below), then space after EOL
+ ss << " \t\n\t\n ";
+ lexer.pushSource(ss);
+
+ // by default space characters and tabs will be ignored. We check this
+ // twice; at the second iteration, it's a white space at the beginning
+ // of line, but since we don't specify INITIAL_WS option, it's treated as
+ // normal space and ignored.
+ for (size_t i = 0; i < 2; ++i) {
+ EXPECT_EQ(s_null, State::start(lexer, MasterLexer::NONE));
+ EXPECT_TRUE(s_crlf.wasLastEOL(lexer));
+ EXPECT_EQ(Token::END_OF_LINE, s_crlf.getToken(lexer).getType());
+ }
+
+ // Now we specify the INITIAL_WS option. It will be recognized and the
+ // corresponding token will be returned.
+ EXPECT_EQ(s_null, State::start(lexer, MasterLexer::INITIAL_WS));
+ EXPECT_FALSE(s_crlf.wasLastEOL(lexer));
+ EXPECT_EQ(Token::INITIAL_WS, s_crlf.getToken(lexer).getType());
+}
+
+TEST_F(MasterLexerStateTest, parentheses) {
+ ss << "\n(\na\n )\n "; // 1st \n is to check if 'was EOL' is set to false
+ lexer.pushSource(ss);
+
+ EXPECT_EQ(s_null, State::start(lexer, common_options)); // handle \n
+
+ // Now handle '('. It skips \n and recognize 'a' as string
+ EXPECT_EQ(0, s_crlf.getParenCount(lexer)); // check pre condition
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ EXPECT_EQ(1, s_crlf.getParenCount(lexer)); // check post condition
+ EXPECT_FALSE(s_crlf.wasLastEOL(lexer));
+
+ // skip 'a'
+ s_string.handle(lexer);
+
+ // Then handle ')'. '\n' before ')' isn't recognized because
+ // it's canceled due to the '('. Likewise, the space after the '\n'
+ // shouldn't be recognized but should be just ignored.
+ EXPECT_EQ(s_null, State::start(lexer, common_options));
+ EXPECT_EQ(0, s_crlf.getParenCount(lexer));
+
+ // Now, temporarily disabled options are restored: Both EOL and the
+ // initial WS are recognized
+ EXPECT_EQ(Token::END_OF_LINE, s_crlf.getToken(lexer).getType());
+ EXPECT_EQ(s_null, State::start(lexer, common_options));
+ EXPECT_EQ(Token::INITIAL_WS, s_crlf.getToken(lexer).getType());
+}
+
+TEST_F(MasterLexerStateTest, nestedParentheses) {
+ // This is an unusual, but allowed (in this implementation) case.
+ ss << "(a(b)\n c)\n ";
+ lexer.pushSource(ss);
+
+ EXPECT_EQ(&s_string, State::start(lexer, common_options)); // consume '('
+ s_string.handle(lexer); // consume 'a'
+ EXPECT_EQ(&s_string, State::start(lexer, common_options)); // consume '('
+ s_string.handle(lexer); // consume 'b'
+ EXPECT_EQ(2, s_crlf.getParenCount(lexer)); // now the count is 2
+
+ // Close the inner most parentheses. count will be decreased, but option
+ // shouldn't be restored yet, so the intermediate EOL or initial WS won't
+ // be recognized.
+ EXPECT_EQ(&s_string, State::start(lexer, common_options)); // consume ')'
+ s_string.handle(lexer); // consume 'c'
+ EXPECT_EQ(1, s_crlf.getParenCount(lexer));
+
+ // Close the outermost parentheses. count will be reset to 0, and original
+ // options are restored.
+ EXPECT_EQ(s_null, State::start(lexer, common_options));
+
+ // Now, temporarily disabled options are restored: Both EOL and the
+ // initial WS are recognized
+ EXPECT_EQ(Token::END_OF_LINE, s_crlf.getToken(lexer).getType());
+ EXPECT_EQ(s_null, State::start(lexer, common_options));
+ EXPECT_EQ(Token::INITIAL_WS, s_crlf.getToken(lexer).getType());
+}
+
+TEST_F(MasterLexerStateTest, unbalancedParentheses) {
+ // Only closing paren is provided. We prepend a \n to check if it's
+ // correctly canceled after detecting the error.
+ ss << "\n)";
+ ss << "(a";
+ lexer.pushSource(ss);
+
+ EXPECT_EQ(s_null, State::start(lexer, common_options)); // consume '\n'
+ EXPECT_TRUE(s_crlf.wasLastEOL(lexer)); // this \n was remembered
+
+ // Now checking ')'. The result should be error, count shouldn't be
+ // changed. "last EOL" should be canceled.
+ EXPECT_EQ(0, s_crlf.getParenCount(lexer));
+ EXPECT_EQ(s_null, State::start(lexer, common_options));
+ EXPECT_EQ(0, s_crlf.getParenCount(lexer));
+ ASSERT_EQ(Token::ERROR, s_crlf.getToken(lexer).getType());
+ EXPECT_EQ(Token::UNBALANCED_PAREN, s_crlf.getToken(lexer).getErrorCode());
+ EXPECT_FALSE(s_crlf.wasLastEOL(lexer));
+
+ // Reach EOF with a dangling open parenthesis.
+ EXPECT_EQ(&s_string, State::start(lexer, common_options)); // consume '('
+ s_string.handle(lexer); // consume 'a'
+ EXPECT_EQ(1, s_crlf.getParenCount(lexer));
+ EXPECT_EQ(s_null, State::start(lexer, common_options)); // reach EOF
+ ASSERT_EQ(Token::ERROR, s_crlf.getToken(lexer).getType());
+ EXPECT_EQ(Token::UNBALANCED_PAREN, s_crlf.getToken(lexer).getErrorCode());
+ EXPECT_EQ(0, s_crlf.getParenCount(lexer)); // should be reset to 0
+}
+
+TEST_F(MasterLexerStateTest, startToComment) {
+ // Begin with 'start', detect space, then encounter a comment. Skip
+ // the rest of the line, and recognize the new line. Note that the
+ // second ';' is simply ignored.
+ ss << " ;a;\n";
+ ss << ";a;"; // Likewise, but the comment ends with EOF.
+ lexer.pushSource(ss);
+
+ // Initial whitespace (asked for in common_options)
+ EXPECT_EQ(s_null, State::start(lexer, common_options));
+ EXPECT_EQ(Token::INITIAL_WS, s_crlf.getToken(lexer).getType());
+ // Comment ending with EOL
+ EXPECT_EQ(s_null, State::start(lexer, common_options));
+ EXPECT_EQ(Token::END_OF_LINE, s_crlf.getToken(lexer).getType());
+
+ // Comment ending with EOF
+ EXPECT_EQ(s_null, State::start(lexer, common_options));
+ EXPECT_EQ(Token::END_OF_FILE, s_crlf.getToken(lexer).getType());
+}
+
+TEST_F(MasterLexerStateTest, commentAfterParen) {
+ // comment after an opening parenthesis. The code that is tested by
+ // other tests should also ensure that it works correctly, but we
+ // check it explicitly.
+ ss << "( ;this is a comment\na)\n";
+ lexer.pushSource(ss);
+
+ // consume '(', skip comments, consume 'a', then consume ')'
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer);
+ EXPECT_EQ(s_null, State::start(lexer, common_options));
+ EXPECT_EQ(Token::END_OF_LINE, s_crlf.getToken(lexer).getType());
+}
+
+TEST_F(MasterLexerStateTest, crlf) {
+ ss << "\r\n"; // case 1
+ ss << "\r "; // case 2
+ ss << "\r;comment\na"; // case 3
+ ss << "\r"; // case 4
+ lexer.pushSource(ss);
+
+ // 1. A sequence of \r, \n is recognized as a single 'end-of-line'
+ EXPECT_EQ(&s_crlf, State::start(lexer, common_options)); // recognize '\r'
+ s_crlf.handle(lexer); // recognize '\n'
+ EXPECT_EQ(Token::END_OF_LINE, s_crlf.getToken(lexer).getType());
+ EXPECT_TRUE(s_crlf.wasLastEOL(lexer));
+
+ // 2. Single '\r' (not followed by \n) is recognized as a single
+ // 'end-of-line'. then there will be "initial WS"
+ EXPECT_EQ(&s_crlf, State::start(lexer, common_options)); // recognize '\r'
+ // see ' ', "unget" it
+ s_crlf.handle(lexer);
+ EXPECT_EQ(s_null, State::start(lexer, common_options)); // recognize ' '
+ EXPECT_EQ(Token::INITIAL_WS, s_crlf.getToken(lexer).getType());
+
+ // 3. comment between \r and \n
+ EXPECT_EQ(&s_crlf, State::start(lexer, common_options)); // recognize '\r'
+ // skip comments, recognize '\n'
+ s_crlf.handle(lexer);
+ EXPECT_EQ(Token::END_OF_LINE, s_crlf.getToken(lexer).getType());
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer); // skip 'a'
+
+ // 4. \r then EOF
+ EXPECT_EQ(&s_crlf, State::start(lexer, common_options)); // recognize '\r'
+ // see EOF, then "unget" it
+ s_crlf.handle(lexer);
+ EXPECT_EQ(s_null, State::start(lexer, common_options)); // recognize EOF
+ EXPECT_EQ(Token::END_OF_FILE, s_crlf.getToken(lexer).getType());
+}
+
+// Commonly used check for string related test cases, checking if the given
+// token has expected values.
+void
+stringTokenCheck(const std::string& expected, const MasterToken& token,
+ bool quoted = false)
+{
+ EXPECT_EQ(quoted ? Token::QSTRING : Token::STRING, token.getType());
+ EXPECT_EQ(expected, token.getString());
+ const std::string actual(token.getStringRegion().beg,
+ token.getStringRegion().beg +
+ token.getStringRegion().len);
+ EXPECT_EQ(expected, actual);
+
+ // There should be "hidden" nul-terminator after the string data.
+ ASSERT_NE(static_cast<const char*>(NULL), token.getStringRegion().beg);
+ EXPECT_EQ(0, *(token.getStringRegion().beg + token.getStringRegion().len));
+}
+
+TEST_F(MasterLexerStateTest, string) {
+ // Check with simple strings followed by separate characters
+ ss << "followed-by-EOL\n";
+ ss << "followed-by-CR\r";
+ ss << "followed-by-space ";
+ ss << "followed-by-tab\t";
+ ss << "followed-by-comment;this is comment and ignored\n";
+ ss << "followed-by-paren(closing)";
+ ss << "followed-by-EOF";
+ lexer.pushSource(ss);
+
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer); // recognize str, see \n
+ EXPECT_FALSE(s_string.wasLastEOL(lexer));
+ stringTokenCheck("followed-by-EOL", s_string.getToken(lexer));
+ EXPECT_EQ(s_null, State::start(lexer, common_options)); // skip \n
+
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer); // recognize str, see \r
+ stringTokenCheck("followed-by-CR", s_string.getToken(lexer));
+ EXPECT_EQ(&s_crlf, State::start(lexer, common_options)); // handle \r...
+ s_crlf.handle(lexer); // ...and skip it
+
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer); // recognize str, see ' '
+ stringTokenCheck("followed-by-space", s_string.getToken(lexer));
+
+ // skip ' ', then recognize the next string
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer); // recognize str, see \t
+ stringTokenCheck("followed-by-tab", s_string.getToken(lexer));
+
+ // skip \t, then recognize the next string
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer); // recognize str, see comment
+ stringTokenCheck("followed-by-comment", s_string.getToken(lexer));
+ EXPECT_EQ(s_null, State::start(lexer, common_options)); // skip \n after it
+
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer); // recognize str, see '('
+ stringTokenCheck("followed-by-paren", s_string.getToken(lexer));
+ EXPECT_EQ(&s_string, State::start(lexer, common_options)); // str in ()
+ s_string.handle(lexer); // recognize the str, see ')'
+ stringTokenCheck("closing", s_string.getToken(lexer));
+
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer); // recognize str, see EOF
+ stringTokenCheck("followed-by-EOF", s_string.getToken(lexer));
+}
+
+TEST_F(MasterLexerStateTest, stringEscape) {
+ // some of the separate characters should be considered part of the
+ // string if escaped.
+ ss << "escaped\\ space ";
+ ss << "escaped\\\ttab ";
+ ss << "escaped\\(paren ";
+ ss << "escaped\\)close ";
+ ss << "escaped\\;comment ";
+ ss << "escaped\\\\ backslash "; // second '\' shouldn't escape ' '
+ lexer.pushSource(ss);
+
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer); // recognize str, see ' ' at end
+ stringTokenCheck("escaped\\ space", s_string.getToken(lexer));
+
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer); // recognize str, see ' ' at end
+ stringTokenCheck("escaped\\\ttab", s_string.getToken(lexer));
+
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer); // recognize str, see ' ' at end
+ stringTokenCheck("escaped\\(paren", s_string.getToken(lexer));
+
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer); // recognize str, see ' ' at end
+ stringTokenCheck("escaped\\)close", s_string.getToken(lexer));
+
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer); // recognize str, see ' ' at end
+ stringTokenCheck("escaped\\;comment", s_string.getToken(lexer));
+
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer); // recognize str, see ' ' in mid
+ stringTokenCheck("escaped\\\\", s_string.getToken(lexer));
+
+ // Confirm the word that follows the escaped '\' is correctly recognized.
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer); // recognize str, see ' ' at end
+ stringTokenCheck("backslash", s_string.getToken(lexer));
+}
+
+TEST_F(MasterLexerStateTest, quotedString) {
+ ss << "\"ignore-quotes\"\n";
+ ss << "\"quoted string\" "; // space is part of the qstring
+ ss << "\"\" "; // empty quoted string
+ // also check other separator characters. note that \r doesn't cause
+ // UNBALANCED_QUOTES. Not sure if it's intentional, but that's how the
+ // BIND 9 version works, so we follow it (it should be too minor to matter
+ // in practice anyway)
+ ss << "\"quoted()\t\rstring\" ";
+ ss << "\"escape\\ in quote\" ";
+ ss << "\"escaped\\\"\" ";
+ ss << "\"escaped backslash\\\\\" ";
+ ss << "\"no;comment\"";
+ lexer.pushSource(ss);
+
+ // by default, '"' is unexpected (when QSTRING is not specified),
+ // and it returns MasterToken::UNEXPECTED_QUOTES.
+ EXPECT_EQ(s_null, State::start(lexer, common_options));
+ EXPECT_EQ(Token::UNEXPECTED_QUOTES, s_string.getToken(lexer).getErrorCode());
+ // Read it as a QSTRING.
+ s_qstring.handle(lexer); // recognize quoted str, see \n
+ stringTokenCheck("ignore-quotes", s_qstring.getToken(lexer), true);
+ EXPECT_EQ(s_null, State::start(lexer, common_options)); // skip \n after it
+ EXPECT_TRUE(s_string.wasLastEOL(lexer));
+
+ // If QSTRING is specified in option, '"' is regarded as a beginning of
+ // a quoted string.
+ const MasterLexer::Options options = common_options | MasterLexer::QSTRING;
+ EXPECT_EQ(&s_qstring, State::start(lexer, options));
+ EXPECT_FALSE(s_string.wasLastEOL(lexer)); // EOL is canceled due to '"'
+ s_qstring.handle(lexer);
+ stringTokenCheck("quoted string", s_string.getToken(lexer), true);
+
+ // Empty string is okay as qstring
+ EXPECT_EQ(&s_qstring, State::start(lexer, options));
+ s_qstring.handle(lexer);
+ stringTokenCheck("", s_string.getToken(lexer), true);
+
+ // Also checks other separator characters within a qstring
+ EXPECT_EQ(&s_qstring, State::start(lexer, options));
+ s_qstring.handle(lexer);
+ stringTokenCheck("quoted()\t\rstring", s_string.getToken(lexer), true);
+
+ // escape character mostly doesn't have any effect in the qstring
+ // processing
+ EXPECT_EQ(&s_qstring, State::start(lexer, options));
+ s_qstring.handle(lexer);
+ stringTokenCheck("escape\\ in quote", s_string.getToken(lexer), true);
+
+ // The only exception is the quotation mark itself. Note that the escape
+ // only works on the quotation mark immediately after it.
+ EXPECT_EQ(&s_qstring, State::start(lexer, options));
+ s_qstring.handle(lexer);
+ stringTokenCheck("escaped\"", s_string.getToken(lexer), true);
+
+ // quoted '\' then '"'. Unlike the previous case '"' shouldn't be
+ // escaped.
+ EXPECT_EQ(&s_qstring, State::start(lexer, options));
+ s_qstring.handle(lexer);
+ stringTokenCheck("escaped backslash\\\\", s_string.getToken(lexer), true);
+
+ // ';' has no meaning in a quoted string (not indicating a comment)
+ EXPECT_EQ(&s_qstring, State::start(lexer, options));
+ s_qstring.handle(lexer);
+ stringTokenCheck("no;comment", s_string.getToken(lexer), true);
+}
+
+TEST_F(MasterLexerStateTest, brokenQuotedString) {
+ ss << "\"unbalanced-quote\n";
+ ss << "\"quoted\\\n\" ";
+ ss << "\"unclosed quote and EOF";
+ lexer.pushSource(ss);
+
+ // EOL is encountered without closing the quote
+ const MasterLexer::Options options = common_options | MasterLexer::QSTRING;
+ EXPECT_EQ(&s_qstring, State::start(lexer, options));
+ s_qstring.handle(lexer);
+ ASSERT_EQ(Token::ERROR, s_qstring.getToken(lexer).getType());
+ EXPECT_EQ(Token::UNBALANCED_QUOTES,
+ s_qstring.getToken(lexer).getErrorCode());
+ // We can resume after the error from the '\n'
+ EXPECT_EQ(s_null, State::start(lexer, options));
+ EXPECT_EQ(Token::END_OF_LINE, s_crlf.getToken(lexer).getType());
+
+ // \n is okay in a quoted string if escaped
+ EXPECT_EQ(&s_qstring, State::start(lexer, options));
+ s_qstring.handle(lexer);
+ stringTokenCheck("quoted\\\n", s_string.getToken(lexer), true);
+
+ // EOF is encountered without closing the quote
+ EXPECT_EQ(&s_qstring, State::start(lexer, options));
+ s_qstring.handle(lexer);
+ ASSERT_EQ(Token::ERROR, s_qstring.getToken(lexer).getType());
+ EXPECT_EQ(Token::UNEXPECTED_END, s_qstring.getToken(lexer).getErrorCode());
+ // If we continue we'll simply see the EOF
+ EXPECT_EQ(s_null, State::start(lexer, options));
+ EXPECT_EQ(Token::END_OF_FILE, s_crlf.getToken(lexer).getType());
+}
+
+TEST_F(MasterLexerStateTest, basicNumbers) {
+ ss << "0 ";
+ ss << "1 ";
+ ss << "12345 ";
+ ss << "4294967295 "; // 2^32-1
+ ss << "4294967296 "; // Out of range
+ ss << "340282366920938463463374607431768211456 ";
+ // Very much out of range (2^128)
+ ss << "005 "; // Leading zeroes are ignored
+ ss << "42;asdf\n"; // Number with comment
+ ss << "37"; // Simple number again, here to make
+ // sure none of the above messed up
+ // the tokenizer
+ lexer.pushSource(ss);
+
+ // Ask the lexer to recognize numbers as well
+ const MasterLexer::Options options = common_options | MasterLexer::NUMBER;
+
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer);
+ EXPECT_EQ(0, s_number.getToken(lexer).getNumber());
+
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer);
+ EXPECT_EQ(1, s_number.getToken(lexer).getNumber());
+
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer);
+ EXPECT_EQ(12345, s_number.getToken(lexer).getNumber());
+
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer);
+ EXPECT_EQ(4294967295u, s_number.getToken(lexer).getNumber());
+
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer);
+ EXPECT_EQ(Token::NUMBER_OUT_OF_RANGE,
+ s_number.getToken(lexer).getErrorCode());
+
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer);
+ EXPECT_EQ(Token::NUMBER_OUT_OF_RANGE,
+ s_number.getToken(lexer).getErrorCode());
+
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer);
+ EXPECT_EQ(5, s_number.getToken(lexer).getNumber());
+
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer);
+ EXPECT_EQ(42, s_number.getToken(lexer).getNumber());
+
+ EXPECT_EQ(s_null, State::start(lexer, options));
+ EXPECT_TRUE(s_crlf.wasLastEOL(lexer));
+ EXPECT_EQ(Token::END_OF_LINE, s_crlf.getToken(lexer).getType());
+
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer);
+ EXPECT_EQ(37, s_number.getToken(lexer).getNumber());
+
+ // If we continue we'll simply see the EOF
+ EXPECT_EQ(s_null, State::start(lexer, options));
+ EXPECT_EQ(Token::END_OF_FILE, s_crlf.getToken(lexer).getType());
+}
+
+// Test tokens that look like (or start out as) numbers,
+// but turn out to be strings. Tests include escaped characters.
+TEST_F(MasterLexerStateTest, stringNumbers) {
+ ss << "123 "; // Should be read as a string if the
+ // NUMBER option is not given
+ ss << "-1 "; // Negative numbers are interpreted
+ // as strings (unsigned integers only)
+ ss << "123abc456 "; // 'Numbers' containing non-digits should
+ // be interpreted as strings
+ ss << "123\\456 "; // Numbers containing escaped digits are
+ // interpreted as strings
+ ss << "3scaped\\ space ";
+ ss << "3scaped\\\ttab ";
+ ss << "3scaped\\(paren ";
+ ss << "3scaped\\)close ";
+ ss << "3scaped\\;comment ";
+ ss << "3scaped\\\\ 8ackslash "; // second '\' shouldn't escape ' '
+
+ lexer.pushSource(ss);
+
+ // Note that common_options does not include MasterLexer::NUMBER,
+ // so the token should be recognized as a string
+ EXPECT_EQ(&s_string, State::start(lexer, common_options));
+ s_string.handle(lexer);
+ stringTokenCheck("123", s_string.getToken(lexer), false);
+
+ // Ask the lexer to recognize numbers as well
+ const MasterLexer::Options options = common_options | MasterLexer::NUMBER;
+
+ EXPECT_EQ(&s_string, State::start(lexer, options));
+ s_string.handle(lexer);
+ stringTokenCheck("-1", s_string.getToken(lexer), false);
+
+ // Starts out as a number, but ends up being a string
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer);
+ stringTokenCheck("123abc456", s_number.getToken(lexer), false);
+
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer);
+ stringTokenCheck("123\\456", s_number.getToken(lexer), false);
+
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer); // recognize str, see ' ' at end
+ stringTokenCheck("3scaped\\ space", s_number.getToken(lexer));
+
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer); // recognize str, see ' ' at end
+ stringTokenCheck("3scaped\\\ttab", s_number.getToken(lexer));
+
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer); // recognize str, see ' ' at end
+ stringTokenCheck("3scaped\\(paren", s_number.getToken(lexer));
+
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer); // recognize str, see ' ' at end
+ stringTokenCheck("3scaped\\)close", s_number.getToken(lexer));
+
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer); // recognize str, see ' ' at end
+ stringTokenCheck("3scaped\\;comment", s_number.getToken(lexer));
+
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer); // recognize str, see ' ' in mid
+ stringTokenCheck("3scaped\\\\", s_number.getToken(lexer));
+
+ // Confirm the word that follows the escaped '\' is correctly recognized.
+ EXPECT_EQ(&s_number, State::start(lexer, options));
+ s_number.handle(lexer); // recognize str, see ' ' at end
+ stringTokenCheck("8ackslash", s_number.getToken(lexer));
+
+ // If we continue we'll simply see the EOF
+ EXPECT_EQ(s_null, State::start(lexer, options));
+ EXPECT_EQ(Token::END_OF_FILE, s_crlf.getToken(lexer).getType());
+}
+
+} // end anonymous namespace
diff --git a/src/lib/dns/tests/master_lexer_token_unittest.cc b/src/lib/dns/tests/master_lexer_token_unittest.cc
index 8b13789179..2167a9f5e6 100644
--- a/src/lib/dns/tests/master_lexer_token_unittest.cc
+++ b/src/lib/dns/tests/master_lexer_token_unittest.cc
@@ -1 +1,162 @@
+// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/master_lexer.h>
+
+#include <gtest/gtest.h>
+
+#include <string>
+
+using namespace isc::dns;
+
+namespace {
+
+const char TEST_STRING[] = "string token";
+// This excludes the ending \0 character
+const size_t TEST_STRING_LEN = sizeof(TEST_STRING) - 1;
+
+class MasterLexerTokenTest : public ::testing::Test {
+protected:
+ MasterLexerTokenTest() :
+ token_eof(MasterToken::END_OF_FILE),
+ token_str(TEST_STRING, TEST_STRING_LEN),
+ token_num(42),
+ token_err(MasterToken::UNEXPECTED_END)
+ {}
+
+ const MasterToken token_eof; // an example of non-value type token
+ const MasterToken token_str;
+ const MasterToken token_num;
+ const MasterToken token_err;
+};
+
+
+TEST_F(MasterLexerTokenTest, strings) {
+ // basic construction and getter checks
+ EXPECT_EQ(MasterToken::STRING, token_str.getType());
+ EXPECT_EQ(std::string("string token"), token_str.getString());
+ std::string strval = "dummy"; // this should be replaced
+ token_str.getString(strval);
+ EXPECT_EQ(std::string("string token"), strval);
+ const MasterToken::StringRegion str_region =
+ token_str.getStringRegion();
+ EXPECT_EQ(TEST_STRING, str_region.beg);
+ EXPECT_EQ(TEST_STRING_LEN, str_region.len);
+
+ // Even if the stored string contains a nul character (in this case,
+ // it happens to be at the end of the string, but could be in the middle),
+ // getString() should return a string object containing the nul.
+ std::string expected_str("string token");
+ expected_str.push_back('\0');
+ EXPECT_EQ(expected_str,
+ MasterToken(TEST_STRING, TEST_STRING_LEN + 1).getString());
+ MasterToken(TEST_STRING, TEST_STRING_LEN + 1).getString(strval);
+ EXPECT_EQ(expected_str, strval);
+
+ // Construct type of qstring
+ EXPECT_EQ(MasterToken::QSTRING,
+ MasterToken(TEST_STRING, sizeof(TEST_STRING), true).
+ getType());
+ // if we explicitly set 'quoted' to false, it should be normal string
+ EXPECT_EQ(MasterToken::STRING,
+ MasterToken(TEST_STRING, sizeof(TEST_STRING), false).
+ getType());
+
+ // getString/StringRegion() aren't allowed for non string(-variant) types
+ EXPECT_THROW(token_eof.getString(), isc::InvalidOperation);
+ EXPECT_THROW(token_eof.getString(strval), isc::InvalidOperation);
+ EXPECT_THROW(token_num.getString(), isc::InvalidOperation);
+ EXPECT_THROW(token_num.getString(strval), isc::InvalidOperation);
+ EXPECT_THROW(token_eof.getStringRegion(), isc::InvalidOperation);
+ EXPECT_THROW(token_num.getStringRegion(), isc::InvalidOperation);
+}
+
+TEST_F(MasterLexerTokenTest, numbers) {
+ EXPECT_EQ(42, token_num.getNumber());
+ EXPECT_EQ(MasterToken::NUMBER, token_num.getType());
+
+ // It's copyable and assignable.
+ MasterToken token(token_num);
+ EXPECT_EQ(42, token.getNumber());
+ EXPECT_EQ(MasterToken::NUMBER, token.getType());
+
+ token = token_num;
+ EXPECT_EQ(42, token.getNumber());
+ EXPECT_EQ(MasterToken::NUMBER, token.getType());
+
+ // it's okay to replace it with a different type of token
+ token = token_eof;
+ EXPECT_EQ(MasterToken::END_OF_FILE, token.getType());
+
+ // Possible max value
+ token = MasterToken(0xffffffff);
+ EXPECT_EQ(4294967295u, token.getNumber());
+
+ // getNumber() isn't allowed for non number types
+ EXPECT_THROW(token_eof.getNumber(), isc::InvalidOperation);
+ EXPECT_THROW(token_str.getNumber(), isc::InvalidOperation);
+}
+
+TEST_F(MasterLexerTokenTest, novalues) {
+ // Just checking we can construct them and getType() returns correct value.
+ EXPECT_EQ(MasterToken::END_OF_FILE, token_eof.getType());
+ EXPECT_EQ(MasterToken::END_OF_LINE,
+ MasterToken(MasterToken::END_OF_LINE).getType());
+ EXPECT_EQ(MasterToken::INITIAL_WS,
+ MasterToken(MasterToken::INITIAL_WS).getType());
+
+ // Special types of tokens cannot have value-based types
+ EXPECT_THROW(MasterToken t(MasterToken::STRING), isc::InvalidParameter);
+ EXPECT_THROW(MasterToken t(MasterToken::QSTRING), isc::InvalidParameter);
+ EXPECT_THROW(MasterToken t(MasterToken::NUMBER), isc::InvalidParameter);
+ EXPECT_THROW(MasterToken t(MasterToken::ERROR), isc::InvalidParameter);
+}
+
+TEST_F(MasterLexerTokenTest, errors) {
+ EXPECT_EQ(MasterToken::ERROR, token_err.getType());
+ EXPECT_EQ(MasterToken::UNEXPECTED_END, token_err.getErrorCode());
+ EXPECT_EQ("unexpected end of input", token_err.getErrorText());
+ EXPECT_EQ("lexer not started", MasterToken(MasterToken::NOT_STARTED).
+ getErrorText());
+ EXPECT_EQ("unbalanced parentheses",
+ MasterToken(MasterToken::UNBALANCED_PAREN).
+ getErrorText());
+ EXPECT_EQ("unbalanced quotes", MasterToken(MasterToken::UNBALANCED_QUOTES).
+ getErrorText());
+ EXPECT_EQ("no token produced", MasterToken(MasterToken::NO_TOKEN_PRODUCED).
+ getErrorText());
+ EXPECT_EQ("number out of range",
+ MasterToken(MasterToken::NUMBER_OUT_OF_RANGE).
+ getErrorText());
+ EXPECT_EQ("not a valid number",
+ MasterToken(MasterToken::BAD_NUMBER).getErrorText());
+ EXPECT_EQ("unexpected quotes",
+ MasterToken(MasterToken::UNEXPECTED_QUOTES).getErrorText());
+
+ // getErrorCode/Text() isn't allowed for non number types
+ EXPECT_THROW(token_num.getErrorCode(), isc::InvalidOperation);
+ EXPECT_THROW(token_num.getErrorText(), isc::InvalidOperation);
+
+ // Only the pre-defined error code is accepted. Hardcoding '8' (max code
+ // + 1) is intentional; it'd be actually better if we notice it when we
+ // update the enum list (which shouldn't happen too often).
+ //
+ // Note: if you fix this testcase, you probably want to update the
+ // getErrorText() tests above too.
+ EXPECT_THROW(MasterToken(MasterToken::ErrorCode(8)),
+ isc::InvalidParameter);
+
+ // Check the coexistence of "from number" and "from error-code"
+ // constructors won't cause confusion.
+ EXPECT_EQ(MasterToken::NUMBER,
+ MasterToken(static_cast<uint32_t>(MasterToken::NOT_STARTED)).
+ getType());
+}
+}
diff --git a/src/lib/dns/tests/master_lexer_unittest.cc b/src/lib/dns/tests/master_lexer_unittest.cc
index 8b13789179..7bebb48bbe 100644
--- a/src/lib/dns/tests/master_lexer_unittest.cc
+++ b/src/lib/dns/tests/master_lexer_unittest.cc
@@ -1 +1,521 @@
+// Copyright (C) 2012-2020 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/master_lexer.h>
+#include <dns/master_lexer_state.h>
+
+#include <gtest/gtest.h>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <string>
+#include <sstream>
+
+using namespace isc::dns;
+using std::string;
+using std::stringstream;
+using boost::lexical_cast;
+using boost::scoped_ptr;
+using master_lexer_internal::State;
+
+namespace {
+
+class MasterLexerTest : public ::testing::Test {
+protected:
+ MasterLexerTest() :
+ expected_stream_name("stream-" + lexical_cast<string>(&ss))
+ {}
+
+ MasterLexer lexer;
+ stringstream ss;
+ const string expected_stream_name;
+};
+
+// Commonly used check case where the input sources stack is empty.
+void
+checkEmptySource(const MasterLexer& lexer) {
+ EXPECT_TRUE(lexer.getSourceName().empty());
+ EXPECT_EQ(0, lexer.getSourceLine());
+ EXPECT_EQ(0, lexer.getPosition());
+}
+
+TEST_F(MasterLexerTest, preOpen) {
+ // Initially sources stack is empty.
+ checkEmptySource(lexer);
+}
+
+TEST_F(MasterLexerTest, pushStream) {
+ EXPECT_EQ(0, lexer.getSourceCount());
+ ss << "test";
+ lexer.pushSource(ss);
+ EXPECT_EQ(expected_stream_name, lexer.getSourceName());
+ EXPECT_EQ(1, lexer.getSourceCount());
+ EXPECT_EQ(4, lexer.getTotalSourceSize()); // 4 = len("test")
+
+ // From the point of view of this test, we only have to check (though
+ // indirectly) getSourceLine calls InputSource::getCurrentLine. It should
+ // return 1 initially.
+ EXPECT_EQ(1, lexer.getSourceLine());
+
+ // By popping it the stack will be empty again.
+ lexer.popSource();
+ EXPECT_EQ(0, lexer.getSourceCount());
+ checkEmptySource(lexer);
+ EXPECT_EQ(4, lexer.getTotalSourceSize()); // this shouldn't change
+}
+
+TEST_F(MasterLexerTest, pushStreamFail) {
+ // Pretend a "bad" thing happened in the stream. This will make the
+ // initialization throw an exception.
+ ss << "test";
+ ss.setstate(std::ios_base::badbit);
+
+ EXPECT_THROW(lexer.pushSource(ss), isc::Unexpected);
+}
+
+TEST_F(MasterLexerTest, pushFile) {
+ // We use zone file (-like) data, but in this test that actually doesn't
+ // matter.
+ EXPECT_EQ(0, lexer.getSourceCount());
+ EXPECT_TRUE(lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt"));
+ EXPECT_EQ(1, lexer.getSourceCount());
+ EXPECT_EQ(TEST_DATA_SRCDIR "/masterload.txt", lexer.getSourceName());
+ EXPECT_EQ(1, lexer.getSourceLine());
+
+ // 143 = size of the test zone file. hardcode it assuming it won't change
+ // too often.
+ EXPECT_EQ(143, lexer.getTotalSourceSize());
+
+ lexer.popSource();
+ checkEmptySource(lexer);
+ EXPECT_EQ(0, lexer.getSourceCount());
+ EXPECT_EQ(143, lexer.getTotalSourceSize()); // this shouldn't change
+
+ // If we give a non NULL string pointer, its content will be intact
+ // if pushSource succeeds.
+ std::string error_txt = "dummy";
+ EXPECT_TRUE(lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt",
+ &error_txt));
+ EXPECT_EQ("dummy", error_txt);
+}
+
+TEST_F(MasterLexerTest, pushBadFileName) {
+ EXPECT_THROW(lexer.pushSource(NULL), isc::InvalidParameter);
+}
+
+TEST_F(MasterLexerTest, pushFileFail) {
+ // The file to be pushed doesn't exist. pushSource() fails and
+ // some non empty error string should be set.
+ std::string error_txt;
+ EXPECT_TRUE(error_txt.empty());
+ EXPECT_FALSE(lexer.pushSource("no-such-file", &error_txt));
+ EXPECT_FALSE(error_txt.empty());
+
+ // It's safe to pass NULL error_txt (either explicitly or implicitly as
+ // the default)
+ EXPECT_FALSE(lexer.pushSource("no-such-file", NULL));
+ EXPECT_FALSE(lexer.pushSource("no-such-file"));
+}
+
+TEST_F(MasterLexerTest, nestedPush) {
+ const string test_txt = "test";
+ ss << test_txt;
+ lexer.pushSource(ss);
+
+ EXPECT_EQ(test_txt.size(), lexer.getTotalSourceSize());
+ EXPECT_EQ(0, lexer.getPosition());
+
+ EXPECT_EQ(expected_stream_name, lexer.getSourceName());
+
+ // Read the string; getPosition() should reflect that.
+ EXPECT_EQ(MasterToken::STRING, lexer.getNextToken().getType());
+ EXPECT_EQ(test_txt.size(), lexer.getPosition());
+
+ // We can push another source without popping the previous one.
+ lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt");
+ EXPECT_EQ(TEST_DATA_SRCDIR "/masterload.txt", lexer.getSourceName());
+ EXPECT_EQ(143 + test_txt.size(),
+ lexer.getTotalSourceSize()); // see above for magic nums
+
+ // the next token should be the EOL (skipping a comment line), its
+ // position in the file is 35 (hardcoded).
+ EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
+ EXPECT_EQ(test_txt.size() + 35, lexer.getPosition());
+
+ // popSource() works on the "topmost" (last-pushed) source
+ lexer.popSource();
+ EXPECT_EQ(expected_stream_name, lexer.getSourceName());
+
+ // pop shouldn't change the total size and the current position
+ EXPECT_EQ(143 + test_txt.size(), lexer.getTotalSourceSize());
+ EXPECT_EQ(test_txt.size() + 35, lexer.getPosition());
+
+ lexer.popSource();
+ EXPECT_TRUE(lexer.getSourceName().empty());
+
+ // size and position still shouldn't change
+ EXPECT_EQ(143 + test_txt.size(), lexer.getTotalSourceSize());
+ EXPECT_EQ(test_txt.size() + 35, lexer.getPosition());
+}
+
+TEST_F(MasterLexerTest, unknownSourceSize) {
+ // Similar to the previous case, but the size of the second source
+ // will be considered "unknown" (by emulating an error).
+ ss << "test";
+ lexer.pushSource(ss);
+ EXPECT_EQ(4, lexer.getTotalSourceSize());
+
+ stringstream ss2;
+ ss2.setstate(std::ios_base::failbit); // this will make the size unknown
+ lexer.pushSource(ss2);
+ // Then the total size is also unknown.
+ EXPECT_EQ(MasterLexer::SOURCE_SIZE_UNKNOWN, lexer.getTotalSourceSize());
+
+ // Even if we pop that source, the size is still unknown.
+ lexer.popSource();
+ EXPECT_EQ(MasterLexer::SOURCE_SIZE_UNKNOWN, lexer.getTotalSourceSize());
+}
+
+TEST_F(MasterLexerTest, invalidPop) {
+ // popSource() cannot be called if the sources stack is empty.
+ EXPECT_THROW(lexer.popSource(), isc::InvalidOperation);
+}
+
+// Test it is not possible to get token when no source is available.
+TEST_F(MasterLexerTest, noSource) {
+ EXPECT_THROW(lexer.getNextToken(), isc::InvalidOperation);
+}
+
+// Test getting some tokens. It also check basic behavior of getPosition().
+TEST_F(MasterLexerTest, getNextToken) {
+ ss << "\n \n\"STRING\"\n";
+ lexer.pushSource(ss);
+
+ // First, the newline should get out.
+ EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
+ EXPECT_EQ(1, lexer.getPosition());
+ // Then the whitespace, if we specify the option.
+ EXPECT_EQ(MasterToken::INITIAL_WS,
+ lexer.getNextToken(MasterLexer::INITIAL_WS).getType());
+ EXPECT_EQ(2, lexer.getPosition());
+ // The newline
+ EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
+ EXPECT_EQ(5, lexer.getPosition()); // 1st \n + 3 spaces, then 2nd \n
+ // The (quoted) string
+ EXPECT_EQ(MasterToken::QSTRING,
+ lexer.getNextToken(MasterLexer::QSTRING).getType());
+ EXPECT_EQ(5 + 8, lexer.getPosition()); // 8 = len("STRING') + quotes
+
+ // And the end of line and file
+ EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
+ EXPECT_EQ(5 + 8 + 1, lexer.getPosition()); // previous + 3rd \n
+ EXPECT_EQ(MasterToken::END_OF_FILE, lexer.getNextToken().getType());
+ EXPECT_EQ(5 + 8 + 1, lexer.getPosition()); // position doesn't change
+}
+
+// Test we correctly find end of file.
+TEST_F(MasterLexerTest, eof) {
+ // Let the ss empty.
+ lexer.pushSource(ss);
+
+ // The first one is found to be EOF
+ EXPECT_EQ(MasterToken::END_OF_FILE, lexer.getNextToken().getType());
+ // And it stays on EOF for any following attempts
+ EXPECT_EQ(MasterToken::END_OF_FILE, lexer.getNextToken().getType());
+ // And we can step back one token, but that is the EOF too.
+ lexer.ungetToken();
+ EXPECT_EQ(MasterToken::END_OF_FILE, lexer.getNextToken().getType());
+}
+
+// Check we properly return error when there's an opened parentheses and no
+// closing one
+TEST_F(MasterLexerTest, getUnbalancedParen) {
+ ss << "(string";
+ lexer.pushSource(ss);
+
+ // The string gets out first
+ EXPECT_EQ(MasterToken::STRING, lexer.getNextToken().getType());
+ // Then an unbalanced parenthesis
+ EXPECT_EQ(MasterToken::UNBALANCED_PAREN,
+ lexer.getNextToken().getErrorCode());
+ // And then EOF
+ EXPECT_EQ(MasterToken::END_OF_FILE, lexer.getNextToken().getType());
+}
+
+// Check we properly return error when there's an opened quoted string and no
+// closing one
+TEST_F(MasterLexerTest, getUnbalancedString) {
+ ss << "\"string";
+ lexer.pushSource(ss);
+
+ // Then an unbalanced qstring (reported as an unexpected end)
+ EXPECT_EQ(MasterToken::UNEXPECTED_END,
+ lexer.getNextToken(MasterLexer::QSTRING).getErrorCode());
+ // And then EOF
+ EXPECT_EQ(MasterToken::END_OF_FILE, lexer.getNextToken().getType());
+}
+
+// Test ungetting tokens works. Also check getPosition() is adjusted
+TEST_F(MasterLexerTest, ungetToken) {
+ ss << "\n (\"string\"\n) more";
+ lexer.pushSource(ss);
+
+ // Try getting the newline
+ EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
+ EXPECT_EQ(1, lexer.getPosition());
+ // Return it and get again
+ lexer.ungetToken();
+ EXPECT_EQ(0, lexer.getPosition());
+ EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
+ EXPECT_EQ(1, lexer.getPosition());
+ // Get the string and return it back
+ EXPECT_EQ(MasterToken::QSTRING,
+ lexer.getNextToken(MasterLexer::QSTRING).getType());
+ EXPECT_EQ(string("\n (\"string\"").size(), lexer.getPosition());
+ lexer.ungetToken();
+ EXPECT_EQ(1, lexer.getPosition()); // back to just after 1st \n
+ // But if we change the options, it honors them
+ EXPECT_EQ(MasterToken::INITIAL_WS,
+ lexer.getNextToken(MasterLexer::QSTRING |
+ MasterLexer::INITIAL_WS).getType());
+ // Get to the "more" string
+ EXPECT_EQ(MasterToken::QSTRING,
+ lexer.getNextToken(MasterLexer::QSTRING).getType());
+ EXPECT_EQ(MasterToken::STRING,
+ lexer.getNextToken(MasterLexer::QSTRING).getType());
+ // Return it back. It should get inside the parentheses.
+ // Upon next attempt to get it again, the newline inside the parentheses
+ // should be still ignored.
+ lexer.ungetToken();
+ EXPECT_EQ(MasterToken::STRING,
+ lexer.getNextToken(MasterLexer::QSTRING).getType());
+}
+
+// Check ungetting token without overriding the start method. We also
+// check it works well with changing options between the calls.
+TEST_F(MasterLexerTest, ungetRealOptions) {
+ ss << " \n";
+ lexer.pushSource(ss);
+
+ // If we call it the usual way, it skips up to the newline and returns
+ // it
+ EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
+
+ // Now we return it. If we call it again, but with different options,
+ // we get the initial whitespace.
+ lexer.ungetToken();
+ EXPECT_EQ(MasterToken::INITIAL_WS,
+ lexer.getNextToken(MasterLexer::INITIAL_WS).getType());
+}
+
+// Check the initial whitespace is found even in the first line of included
+// file. It also confirms getPosition() works for multiple sources, each
+// of which is partially parsed.
+TEST_F(MasterLexerTest, includeAndInitialWS) {
+ ss << " \n";
+ lexer.pushSource(ss);
+
+ stringstream ss2;
+ ss2 << " \n";
+
+ EXPECT_EQ(MasterToken::INITIAL_WS,
+ lexer.getNextToken(MasterLexer::INITIAL_WS).getType());
+ EXPECT_EQ(1, lexer.getPosition());
+ lexer.pushSource(ss2);
+ EXPECT_EQ(MasterToken::INITIAL_WS,
+ lexer.getNextToken(MasterLexer::INITIAL_WS).getType());
+ EXPECT_EQ(2, lexer.getPosition()); // should be sum of pushed positions.
+}
+
+// Test only one token can be ungotten
+TEST_F(MasterLexerTest, ungetTwice) {
+ ss << "\n";
+ lexer.pushSource(ss);
+
+ EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
+ // Unget the token. It can be done once
+ lexer.ungetToken();
+ // But not twice
+ EXPECT_THROW(lexer.ungetToken(), isc::InvalidOperation);
+}
+
+// Test we can't unget a token before we get one
+TEST_F(MasterLexerTest, ungetBeforeGet) {
+ lexer.pushSource(ss); // Just to eliminate the missing source problem
+ EXPECT_THROW(lexer.ungetToken(), isc::InvalidOperation);
+}
+
+// Test we can't unget a token after a source switch, even when we got
+// something before.
+TEST_F(MasterLexerTest, ungetAfterSwitch) {
+ ss << "\n\n";
+ lexer.pushSource(ss);
+ EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
+ // Switch the source
+ std::stringstream ss2;
+ ss2 << "\n\n";
+ lexer.pushSource(ss2);
+ EXPECT_THROW(lexer.ungetToken(), isc::InvalidOperation);
+ // We can get from the new source
+ EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
+ // And when we drop the current source, we can't unget again
+ lexer.popSource();
+ EXPECT_THROW(lexer.ungetToken(), isc::InvalidOperation);
+}
+
+// Common checks for the case when getNextToken() should result in LexerError
+void
+lexerErrorCheck(MasterLexer& lexer, MasterToken::Type expect,
+ MasterToken::ErrorCode expected_error)
+{
+ bool thrown = false;
+ try {
+ lexer.getNextToken(expect);
+ } catch (const MasterLexer::LexerError& error) {
+ EXPECT_EQ(expected_error, error.token_.getErrorCode());
+ thrown = true;
+ }
+ EXPECT_TRUE(thrown);
+}
+
+// Common checks regarding expected/unexpected end-of-line
+//
+// The 'lexer' should be at a position before two consecutive '\n's.
+// The first one will be recognized, and the second one will be considered an
+// unexpected token. Then this helper consumes the second '\n', so the caller
+// can continue the test after these '\n's.
+void
+eolCheck(MasterLexer& lexer, MasterToken::Type expect) {
+ // If EOL is found and eol_ok is true, we get it.
+ EXPECT_EQ(MasterToken::END_OF_LINE,
+ lexer.getNextToken(expect, true).getType());
+ // We'll see the second '\n'; by default it will fail.
+ EXPECT_THROW(lexer.getNextToken(expect), MasterLexer::LexerError);
+ // Same if eol_ok is explicitly set to false. This also checks the
+ // offending '\n' was "ungotten".
+ EXPECT_THROW(lexer.getNextToken(expect, false), MasterLexer::LexerError);
+
+ // And also check the error token set in the exception object.
+ lexerErrorCheck(lexer, expect, MasterToken::UNEXPECTED_END);
+
+ // Then skip the 2nd '\n'
+ EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
+}
+
+// Common checks regarding expected/unexpected end-of-file
+//
+// The 'lexer' should be at a position just before an end-of-file.
+void
+eofCheck(MasterLexer& lexer, MasterToken::Type expect) {
+ EXPECT_EQ(MasterToken::END_OF_FILE,
+ lexer.getNextToken(expect, true).getType());
+ EXPECT_THROW(lexer.getNextToken(expect), MasterLexer::LexerError);
+ EXPECT_THROW(lexer.getNextToken(expect, false), MasterLexer::LexerError);
+}
+
+TEST_F(MasterLexerTest, getNextTokenString) {
+ ss << "normal-string\n";
+ ss << "\n";
+ ss << "another-string";
+ lexer.pushSource(ss);
+
+ // Normal successful case: Expecting a string and get one.
+ EXPECT_EQ("normal-string",
+ lexer.getNextToken(MasterToken::STRING).getString());
+ eolCheck(lexer, MasterToken::STRING);
+
+ // Same set of tests but for end-of-file
+ EXPECT_EQ("another-string",
+ lexer.getNextToken(MasterToken::STRING, true).getString());
+ eofCheck(lexer, MasterToken::STRING);
+}
+
+TEST_F(MasterLexerTest, getNextTokenQString) {
+ ss << "\"quoted-string\"\n";
+ ss << "\n";
+ ss << "normal-string";
+ lexer.pushSource(ss);
+
+ // Expecting a quoted string and get one.
+ EXPECT_EQ("quoted-string",
+ lexer.getNextToken(MasterToken::QSTRING).getString());
+ eolCheck(lexer, MasterToken::QSTRING);
+
+ // Expecting a quoted string but see a normal string. It's okay.
+ EXPECT_EQ("normal-string",
+ lexer.getNextToken(MasterToken::QSTRING).getString());
+ eofCheck(lexer, MasterToken::QSTRING);
+}
+
+TEST_F(MasterLexerTest, getNextTokenNumber) {
+ ss << "3600\n";
+ ss << "\n";
+ ss << "4294967296 "; // =2^32, out of range
+ ss << "not-a-number ";
+ ss << "123abc "; // starting with digits, but resulting in a string
+ ss << "86400";
+ lexer.pushSource(ss);
+
+ // Expecting a number string and get one.
+ EXPECT_EQ(3600,
+ lexer.getNextToken(MasterToken::NUMBER).getNumber());
+ eolCheck(lexer, MasterToken::NUMBER);
+
+ // Expecting a number, but it's too big for uint32.
+ lexerErrorCheck(lexer, MasterToken::NUMBER,
+ MasterToken::NUMBER_OUT_OF_RANGE);
+ // The token should have been "ungotten". Re-read and skip it.
+ EXPECT_EQ(MasterToken::STRING, lexer.getNextToken().getType());
+
+ // Expecting a number, but see a string.
+ lexerErrorCheck(lexer, MasterToken::NUMBER, MasterToken::BAD_NUMBER);
+ // The unexpected string should have been "ungotten". Re-read and skip it.
+ EXPECT_EQ(MasterToken::STRING, lexer.getNextToken().getType());
+
+ // Expecting a number, but see a string.
+ lexerErrorCheck(lexer, MasterToken::NUMBER, MasterToken::BAD_NUMBER);
+ // The unexpected string should have been "ungotten". Re-read and skip it.
+ EXPECT_EQ(MasterToken::STRING, lexer.getNextToken().getType());
+
+ // Unless we specify NUMBER, decimal number string should be recognized
+ // as a string.
+ EXPECT_EQ("86400",
+ lexer.getNextToken(MasterToken::STRING).getString());
+ eofCheck(lexer, MasterToken::NUMBER);
+}
+
+TEST_F(MasterLexerTest, getNextTokenErrors) {
+ // Check miscellaneous error cases
+
+ ss << ") "; // unbalanced parenthesis
+ ss << "string-after-error ";
+ lexer.pushSource(ss);
+
+ // Only string/qstring/number can be "expected".
+ EXPECT_THROW(lexer.getNextToken(MasterToken::END_OF_LINE),
+ isc::InvalidParameter);
+ EXPECT_THROW(lexer.getNextToken(MasterToken::END_OF_FILE),
+ isc::InvalidParameter);
+ EXPECT_THROW(lexer.getNextToken(MasterToken::INITIAL_WS),
+ isc::InvalidParameter);
+ EXPECT_THROW(lexer.getNextToken(MasterToken::ERROR),
+ isc::InvalidParameter);
+
+ // If it encounters a syntax error, it results in LexerError exception.
+ lexerErrorCheck(lexer, MasterToken::STRING, MasterToken::UNBALANCED_PAREN);
+
+ // Unlike the NUMBER_OUT_OF_RANGE case, the error part has been skipped
+ // within getNextToken(). We should be able to get the next token.
+ EXPECT_EQ("string-after-error",
+ lexer.getNextToken(MasterToken::STRING).getString());
+}
+
+}
diff --git a/src/lib/dns/tests/master_loader_callbacks_test.cc b/src/lib/dns/tests/master_loader_callbacks_test.cc
index 8b13789179..9d238023dd 100644
--- a/src/lib/dns/tests/master_loader_callbacks_test.cc
+++ b/src/lib/dns/tests/master_loader_callbacks_test.cc
@@ -1 +1,79 @@
+// Copyright (C) 2012-2020 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <dns/master_loader_callbacks.h>
+#include <dns/rrset.h>
+#include <dns/name.h>
+#include <dns/rrttl.h>
+#include <dns/rrclass.h>
+
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+#include <functional>
+
+namespace {
+
+using std::string;
+using namespace isc::dns;
+namespace ph = std::placeholders;
+
+class MasterLoaderCallbacksTest : public ::testing::Test {
+protected:
+ MasterLoaderCallbacksTest() :
+ last_was_error_(false), // Not needed, but then cppcheck complains
+ issue_called_(false),
+ rrset_(new RRset(Name("example.org"), RRClass::IN(), RRType::A(),
+ RRTTL(3600))),
+ error_(std::bind(&MasterLoaderCallbacksTest::checkCallback, this,
+ true, ph::_1, ph::_2, ph::_3)),
+ warning_(std::bind(&MasterLoaderCallbacksTest::checkCallback, this,
+ false, ph::_1, ph::_2, ph::_3)),
+ callbacks_(error_, warning_)
+ {}
+
+ void checkCallback(bool error, const string& source, size_t line,
+ const string& reason)
+ {
+ issue_called_ = true;
+ last_was_error_ = error;
+ EXPECT_EQ("source", source);
+ EXPECT_EQ(1, line);
+ EXPECT_EQ("reason", reason);
+ }
+ bool last_was_error_;
+ bool issue_called_;
+ const RRsetPtr rrset_;
+ const MasterLoaderCallbacks::IssueCallback error_, warning_;
+ MasterLoaderCallbacks callbacks_;
+};
+
+// Check the constructor rejects empty callbacks, but accepts non-empty ones
+TEST_F(MasterLoaderCallbacksTest, constructor) {
+ EXPECT_THROW(MasterLoaderCallbacks(MasterLoaderCallbacks::IssueCallback(),
+ warning_), isc::InvalidParameter);
+ EXPECT_THROW(MasterLoaderCallbacks(error_,
+ MasterLoaderCallbacks::IssueCallback()),
+ isc::InvalidParameter);
+ EXPECT_NO_THROW(MasterLoaderCallbacks(error_, warning_));
+}
+
+// Call the issue callbacks
+TEST_F(MasterLoaderCallbacksTest, issueCall) {
+ callbacks_.error("source", 1, "reason");
+ EXPECT_TRUE(last_was_error_);
+ EXPECT_TRUE(issue_called_);
+
+ issue_called_ = false;
+
+ callbacks_.warning("source", 1, "reason");
+ EXPECT_FALSE(last_was_error_);
+ EXPECT_TRUE(issue_called_);
+}
+
+}
diff --git a/src/lib/dns/tests/master_loader_unittest.cc b/src/lib/dns/tests/master_loader_unittest.cc
index 8b13789179..b9830072f6 100644
--- a/src/lib/dns/tests/master_loader_unittest.cc
+++ b/src/lib/dns/tests/master_loader_unittest.cc
@@ -1 +1,1426 @@
+// Copyright (C) 2012-2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <dns/master_loader_callbacks.h>
+#include <dns/master_loader.h>
+#include <dns/rrtype.h>
+#include <dns/rrset.h>
+#include <dns/rrclass.h>
+#include <dns/rrttl.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+
+#include <gtest/gtest.h>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <functional>
+#include <string>
+#include <vector>
+#include <list>
+#include <sstream>
+
+using namespace isc::dns;
+using std::vector;
+using std::string;
+using std::list;
+using std::stringstream;
+using std::endl;
+using boost::lexical_cast;
+namespace ph = std::placeholders;
+
+namespace {
+class MasterLoaderTest : public ::testing::Test {
+public:
+ MasterLoaderTest() :
+ callbacks_(std::bind(&MasterLoaderTest::callback, this,
+ &errors_, ph::_1, ph::_2, ph::_3),
+ std::bind(&MasterLoaderTest::callback, this,
+ &warnings_, ph::_1, ph::_2, ph::_3)) {
+ }
+
+ void TearDown() {
+ // Check there are no more RRs we didn't expect
+ EXPECT_TRUE(rrsets_.empty());
+ }
+
+ /// Concatenate file, line, and reason, and add it to either errors
+ /// or warnings
+ void callback(vector<string>* target, const std::string& file, size_t line,
+ const std::string& reason) {
+ std::stringstream ss;
+ ss << reason << " [" << file << ":" << line << "]";
+ target->push_back(ss.str());
+ }
+
+ void addRRset(const Name& name, const RRClass& rrclass,
+ const RRType& rrtype, const RRTTL& rrttl,
+ const rdata::RdataPtr& data) {
+ const RRsetPtr rrset(new BasicRRset(name, rrclass, rrtype, rrttl));
+ rrset->addRdata(data);
+ rrsets_.push_back(rrset);
+ }
+
+ void setLoader(const char* file, const Name& origin,
+ const RRClass& rrclass, const MasterLoader::Options options) {
+ loader_.reset(new MasterLoader(file, origin, rrclass, callbacks_,
+ std::bind(&MasterLoaderTest::addRRset,
+ this, ph::_1, ph::_2, ph::_3,
+ ph::_4, ph::_5),
+ options));
+ }
+
+ void setLoader(std::istream& stream, const Name& origin,
+ const RRClass& rrclass, const MasterLoader::Options options) {
+ loader_.reset(new MasterLoader(stream, origin, rrclass, callbacks_,
+ std::bind(&MasterLoaderTest::addRRset,
+ this, ph::_1, ph::_2, ph::_3,
+ ph::_4, ph::_5),
+ options));
+ }
+
+ static string prepareZone(const string& line, bool include_last) {
+ string result;
+ result += "example.org. 3600 IN SOA ns1.example.org. "
+ "admin.example.org. 1234 3600 1800 2419200 7200\n";
+ result += line;
+ if (include_last) {
+ result += "\n";
+ result += "correct 3600 IN A 192.0.2.2\n";
+ }
+ return (result);
+ }
+
+ void clear() {
+ warnings_.clear();
+ errors_.clear();
+ rrsets_.clear();
+ }
+
+ // Check the next RR in the ones produced by the loader
+ // Other than passed arguments are checked to be the default for the tests
+ void checkRR(const string& name, const RRType& type, const string& data,
+ const RRTTL& rrttl = RRTTL(3600)) {
+ ASSERT_FALSE(rrsets_.empty());
+ RRsetPtr current = rrsets_.front();
+ rrsets_.pop_front();
+
+ EXPECT_EQ(Name(name), current->getName());
+ EXPECT_EQ(type, current->getType());
+ EXPECT_EQ(RRClass::IN(), current->getClass());
+ EXPECT_EQ(rrttl, current->getTTL());
+ ASSERT_EQ(1, current->getRdataCount());
+ EXPECT_EQ(0, isc::dns::rdata::createRdata(type, RRClass::IN(), data)->
+ compare(current->getRdataIterator()->getCurrent()))
+ << data << " vs. "
+ << current->getRdataIterator()->getCurrent().toText();
+ }
+
+ void checkBasicRRs() {
+ checkRR("example.org", RRType::SOA(),
+ "ns1.example.org. admin.example.org. "
+ "1234 3600 1800 2419200 7200");
+ checkRR("example.org", RRType::NS(), "ns1.example.org.");
+ checkRR("www.example.org", RRType::A(), "192.0.2.1");
+ checkRR("www.example.org", RRType::AAAA(), "2001:db8::1");
+ }
+
+ void checkARR(const string& name) {
+ checkRR(name, RRType::A(), "192.0.2.1");
+ }
+
+ MasterLoaderCallbacks callbacks_;
+ boost::scoped_ptr<MasterLoader> loader_;
+ vector<string> errors_;
+ vector<string> warnings_;
+ list<RRsetPtr> rrsets_;
+};
+
+// Test simple loading. The zone file contains no tricky things, and nothing is
+// omitted. No RRset contains more than one RR Also no errors or warnings.
+TEST_F(MasterLoaderTest, basicLoad) {
+ setLoader(TEST_DATA_SRCDIR "/example.org", Name("example.org."),
+ RRClass::IN(), MasterLoader::MANY_ERRORS);
+
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+
+ // The following three should be set to 0 initially in case the loader
+ // is constructed from a file name.
+ EXPECT_EQ(0, loader_->getSize());
+ EXPECT_EQ(0, loader_->getPosition());
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+
+ EXPECT_TRUE(errors_.empty());
+ EXPECT_TRUE(warnings_.empty());
+
+ // Hardcode expected values taken from the test data file, assuming it
+ // won't change too often.
+ EXPECT_EQ(550, loader_->getSize());
+ EXPECT_EQ(550, loader_->getPosition());
+
+ checkBasicRRs();
+}
+
+// Test the $INCLUDE directive
+TEST_F(MasterLoaderTest, include) {
+ // Test various cases of include
+ const char* includes[] = {
+ "$include",
+ "$INCLUDE",
+ "$Include",
+ "$InCluDe",
+ "\"$INCLUDE\"",
+ NULL
+ };
+ for (const char** include = includes; *include != NULL; ++include) {
+ SCOPED_TRACE(*include);
+
+ clear();
+ // Prepare input source that has the include and some more data
+ // below (to see it returns back to the original source).
+ const string include_str = string(*include) + " " +
+ TEST_DATA_SRCDIR + "/example.org\nwww 3600 IN AAAA 2001:db8::1\n";
+ stringstream ss(include_str);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+ EXPECT_TRUE(warnings_.empty());
+
+ checkBasicRRs();
+ checkRR("www.example.org", RRType::AAAA(), "2001:db8::1");
+ }
+}
+
+TEST_F(MasterLoaderTest, includeAndIncremental) {
+ // Check getSize() and getPosition() are adjusted before and after
+ // $INCLUDE.
+ const string first_rr = "before.example.org. 0 A 192.0.2.1\n";
+ const string include_str = "$INCLUDE " TEST_DATA_SRCDIR "/example.org";
+ const string zone_data = first_rr + include_str + "\n" +
+ "www 3600 IN AAAA 2001:db8::1\n";
+ stringstream ss(zone_data);
+ setLoader(ss, Name("example.org."), RRClass::IN(), MasterLoader::DEFAULT);
+
+ // On construction, getSize() returns the size of the data (exclude the
+ // the file to be included); position is set to 0.
+ EXPECT_EQ(zone_data.size(), loader_->getSize());
+ EXPECT_EQ(0, loader_->getPosition());
+
+ // Read the first RR. getSize() doesn't change; position should be
+ // at the end of the first line.
+ loader_->loadIncremental(1);
+ EXPECT_EQ(zone_data.size(), loader_->getSize());
+ EXPECT_EQ(first_rr.size(), loader_->getPosition());
+
+ // Read next 4. It includes $INCLUDE processing. Magic number of 550
+ // is the size of the test zone file (see above); 507 is the position in
+ // the file at the end of 4th RR (due to extra comments it's smaller than
+ // the file size).
+ loader_->loadIncremental(4);
+ EXPECT_EQ(zone_data.size() + 550, loader_->getSize());
+ EXPECT_EQ(first_rr.size() + include_str.size() + 507,
+ loader_->getPosition());
+
+ // Read the last one. At this point getSize and getPosition return
+ // the same value, indicating progress of 100%.
+ loader_->loadIncremental(1);
+ EXPECT_EQ(zone_data.size() + 550, loader_->getSize());
+ EXPECT_EQ(zone_data.size() + 550, loader_->getPosition());
+
+ // we were not interested in checking RRs in this test. clear them to
+ // not confuse TearDown().
+ rrsets_.clear();
+}
+
+// A commonly used helper to check callback message.
+void
+checkCallbackMessage(const string& actual_msg, const string& expected_msg,
+ size_t expected_line) {
+ // The actual message should begin with the expected message.
+ EXPECT_EQ(0, actual_msg.find(expected_msg)) << "actual message: " <<
+ actual_msg << " expected: " <<
+ expected_msg;
+
+ // and it should end with "...:<line_num>]"
+ const string line_desc = ":" + lexical_cast<string>(expected_line) + "]";
+ EXPECT_EQ(actual_msg.size() - line_desc.size(),
+ actual_msg.find(line_desc)) << "Expected on line " <<
+ expected_line;
+}
+
+TEST_F(MasterLoaderTest, origin) {
+ // Various forms of the directive
+ const char* origins[] = {
+ "$origin",
+ "$ORIGIN",
+ "$Origin",
+ "$OrigiN",
+ "\"$ORIGIN\"",
+ NULL
+ };
+ for (const char** origin = origins; *origin != NULL; ++origin) {
+ SCOPED_TRACE(*origin);
+
+ clear();
+ const string directive = *origin;
+ const string input =
+ "@ 1H IN A 192.0.2.1\n" +
+ directive + " sub.example.org.\n"
+ "\"www\" 1H IN A 192.0.2.1\n" +
+ // Relative name in the origin
+ directive + " relative\n"
+ "@ 1H IN A 192.0.2.1\n"
+ // Origin is _not_ used here (absolute name)
+ "noorigin.example.org. 60M IN A 192.0.2.1\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+ // There's a relative origin in it, we warn about that.
+ EXPECT_EQ(1, warnings_.size());
+ checkCallbackMessage(warnings_.at(0),
+ "The new origin is relative, did you really mean "
+ "relative.sub.example.org.?", 4);
+
+ checkARR("example.org");
+ checkARR("www.sub.example.org");
+ checkARR("relative.sub.example.org");
+ checkARR("noorigin.example.org");
+ }
+}
+
+TEST_F(MasterLoaderTest, generate) {
+ // Various forms of the directive
+ const char* generates[] = {
+ "$generate",
+ "$GENERATE",
+ "$Generate",
+ "$GeneratE",
+ "\"$GENERATE\"",
+ NULL
+ };
+ for (const char** generate = generates; *generate != NULL; ++generate) {
+ SCOPED_TRACE(*generate);
+
+ clear();
+ const string directive = *generate;
+ const string input =
+ "$ORIGIN example.org.\n"
+ "before.example.org. 3600 IN A 192.0.2.0\n" +
+ directive + " 3-5 host$ A 192.0.2.$\n" +
+ "after.example.org. 3600 IN A 192.0.2.255\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+
+ // The "before" and "after" scaffolding below checks that no
+ // extra records are added by $GENERATE outside the requested
+ // range.
+ checkRR("before.example.org", RRType::A(), "192.0.2.0");
+ checkRR("host3.example.org", RRType::A(), "192.0.2.3");
+ checkRR("host4.example.org", RRType::A(), "192.0.2.4");
+ checkRR("host5.example.org", RRType::A(), "192.0.2.5");
+ checkRR("after.example.org", RRType::A(), "192.0.2.255");
+ }
+}
+
+TEST_F(MasterLoaderTest, generateRelativeLHS) {
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$GENERATE 1-2 @ 3600 NS ns$.example.org.\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+
+ checkRR("example.org", RRType::NS(), "ns1.example.org.");
+ checkRR("example.org", RRType::NS(), "ns2.example.org.");
+}
+
+TEST_F(MasterLoaderTest, generateInFront) {
+ // $ is in the front
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$GENERATE 9-10 $host 3600 TXT \"$ pomegranate\"\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+
+ checkRR("9host.example.org", RRType::TXT(), "9 pomegranate");
+ checkRR("10host.example.org", RRType::TXT(), "10 pomegranate");
+}
+
+TEST_F(MasterLoaderTest, generateInMiddle) {
+ // $ is in the middle
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$GENERATE 9-10 num$-host 3600 TXT \"This is $ pomegranate\"\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+
+ checkRR("num9-host.example.org", RRType::TXT(), "This is 9 pomegranate");
+ checkRR("num10-host.example.org", RRType::TXT(), "This is 10 pomegranate");
+}
+
+TEST_F(MasterLoaderTest, generateAtEnd) {
+ // $ is at the end
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$GENERATE 9-10 num$-host 3600 TXT Pomegranate$\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+
+ checkRR("num9-host.example.org", RRType::TXT(), "Pomegranate9");
+ checkRR("num10-host.example.org", RRType::TXT(), "Pomegranate10");
+}
+
+TEST_F(MasterLoaderTest, generateWithDoublePlaceholder) {
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$GENERATE 9-10 host$ 3600 TXT \"This is $$ pomegranate\"\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+
+ checkRR("host9.example.org", RRType::TXT(), "This is $ pomegranate");
+ checkRR("host10.example.org", RRType::TXT(), "This is $ pomegranate");
+}
+
+TEST_F(MasterLoaderTest, generateWithEscape) {
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$GENERATE 9-10 host$ 3600 TXT \"This is \\$\\pomegranate\"\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+
+ checkRR("host9.example.org", RRType::TXT(), "This is \\$\\pomegranate");
+ checkRR("host10.example.org", RRType::TXT(), "This is \\$\\pomegranate");
+}
+
+TEST_F(MasterLoaderTest, generateWithParams) {
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$TTL 3600\n"
+ "$GENERATE 2-3 host$ A 192.0.2.$\n"
+ "$GENERATE 5-6 host$ 3600 A 192.0.2.$\n"
+ "$GENERATE 8-9 host$ IN A 192.0.2.$\n"
+ "$GENERATE 11-12 host$ IN 3600 A 192.0.2.$\n"
+ "$GENERATE 14-15 host$ 3600 IN A 192.0.2.$\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+
+ checkRR("host2.example.org", RRType::A(), "192.0.2.2");
+ checkRR("host3.example.org", RRType::A(), "192.0.2.3");
+
+ checkRR("host5.example.org", RRType::A(), "192.0.2.5");
+ checkRR("host6.example.org", RRType::A(), "192.0.2.6");
+
+ checkRR("host8.example.org", RRType::A(), "192.0.2.8");
+ checkRR("host9.example.org", RRType::A(), "192.0.2.9");
+
+ checkRR("host11.example.org", RRType::A(), "192.0.2.11");
+ checkRR("host12.example.org", RRType::A(), "192.0.2.12");
+
+ checkRR("host14.example.org", RRType::A(), "192.0.2.14");
+ checkRR("host15.example.org", RRType::A(), "192.0.2.15");
+}
+
+TEST_F(MasterLoaderTest, generateWithStep) {
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$GENERATE 2-9/2 host$ 3600 A 192.0.2.$\n"
+ "$GENERATE 12-21/3 host$ 3600 A 192.0.2.$\n"
+ "$GENERATE 30-31/1 host$ 3600 A 192.0.2.$\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+
+ checkRR("host2.example.org", RRType::A(), "192.0.2.2");
+ checkRR("host4.example.org", RRType::A(), "192.0.2.4");
+ checkRR("host6.example.org", RRType::A(), "192.0.2.6");
+ checkRR("host8.example.org", RRType::A(), "192.0.2.8");
+
+ checkRR("host12.example.org", RRType::A(), "192.0.2.12");
+ checkRR("host15.example.org", RRType::A(), "192.0.2.15");
+ checkRR("host18.example.org", RRType::A(), "192.0.2.18");
+ checkRR("host21.example.org", RRType::A(), "192.0.2.21");
+
+ checkRR("host30.example.org", RRType::A(), "192.0.2.30");
+ checkRR("host31.example.org", RRType::A(), "192.0.2.31");
+}
+
+TEST_F(MasterLoaderTest, generateWithModifiers) {
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$TTL 3600\n"
+
+ // Use a positive delta of 1 in the LHS and a negative delta of
+ // -1 in the RHS
+ "$GENERATE 2-9/2 host${1} A 192.0.2.${-1}\n"
+
+ "$GENERATE 10-12 host${0,4} A 192.0.2.$\n"
+ "$GENERATE 14-15 host${0,4,d} A 192.0.2.$\n"
+
+ // Names are case-insensitive, so we use TXT's RDATA to check
+ // case with hex representation.
+ "$GENERATE 30-31 host$ TXT \"Value ${0,4,x}\"\n"
+ "$GENERATE 42-43 host$ TXT \"Value ${0,4,X}\"\n"
+
+ // Octal does not use any alphabets
+ "$GENERATE 45-46 host${0,4,o} A 192.0.2.$\n"
+
+ // Here, the LHS has a trailing dot (which would result in an
+ // out-of-zone name), but that should be handled as a relative
+ // name.
+ "$GENERATE 90-92 ${0,8,n} A 192.0.2.$\n"
+
+ // Here, the LHS has no trailing dot, and results in the same
+ // number of labels as width=8 above.
+ "$GENERATE 94-96 ${0,7,n} A 192.0.2.$\n"
+
+ // Names are case-insensitive, so we use TXT's RDATA to check
+ // case with nibble representation.
+ "$GENERATE 106-107 host$ TXT \"Value ${0,9,n}\"\n"
+ "$GENERATE 109-110 host$ TXT \"Value ${0,9,N}\"\n"
+
+ // Junk type will not parse and 'd' is assumed. No error is
+ // generated (this is to match BIND 9 behavior).
+ "$GENERATE 200-201 host${0,4,j} A 192.0.2.$\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+
+ checkRR("host3.example.org", RRType::A(), "192.0.2.1");
+ checkRR("host5.example.org", RRType::A(), "192.0.2.3");
+ checkRR("host7.example.org", RRType::A(), "192.0.2.5");
+ checkRR("host9.example.org", RRType::A(), "192.0.2.7");
+
+ checkRR("host0010.example.org", RRType::A(), "192.0.2.10");
+ checkRR("host0011.example.org", RRType::A(), "192.0.2.11");
+ checkRR("host0012.example.org", RRType::A(), "192.0.2.12");
+
+ checkRR("host0014.example.org", RRType::A(), "192.0.2.14");
+ checkRR("host0015.example.org", RRType::A(), "192.0.2.15");
+
+ checkRR("host30.example.org", RRType::TXT(), "Value 001e");
+ checkRR("host31.example.org", RRType::TXT(), "Value 001f");
+
+ checkRR("host42.example.org", RRType::TXT(), "Value 002A");
+ checkRR("host43.example.org", RRType::TXT(), "Value 002B");
+
+ checkRR("host0055.example.org", RRType::A(), "192.0.2.45");
+ checkRR("host0056.example.org", RRType::A(), "192.0.2.46");
+
+ checkRR("a.5.0.0.example.org", RRType::A(), "192.0.2.90");
+ checkRR("b.5.0.0.example.org", RRType::A(), "192.0.2.91");
+ checkRR("c.5.0.0.example.org", RRType::A(), "192.0.2.92");
+
+ checkRR("e.5.0.0.example.org", RRType::A(), "192.0.2.94");
+ checkRR("f.5.0.0.example.org", RRType::A(), "192.0.2.95");
+ checkRR("0.6.0.0.example.org", RRType::A(), "192.0.2.96");
+
+ checkRR("host106.example.org", RRType::TXT(), "Value a.6.0.0.0");
+ checkRR("host107.example.org", RRType::TXT(), "Value b.6.0.0.0");
+ checkRR("host109.example.org", RRType::TXT(), "Value D.6.0.0.0");
+ checkRR("host110.example.org", RRType::TXT(), "Value E.6.0.0.0");
+
+ checkRR("host0200.example.org", RRType::A(), "192.0.2.200");
+ checkRR("host0201.example.org", RRType::A(), "192.0.2.201");
+}
+
+TEST_F(MasterLoaderTest, generateWithNoModifiers) {
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$TTL 3600\n"
+ "$GENERATE 10-12 host${} A 192.0.2.$\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ ASSERT_EQ(2, errors_.size()); // For the broken GENERATE
+ EXPECT_TRUE(warnings_.empty());
+
+ checkCallbackMessage(errors_.at(0),
+ "Invalid $GENERATE format modifiers", 3);
+ checkCallbackMessage(errors_.at(1),
+ "$GENERATE error", 3);
+}
+
+TEST_F(MasterLoaderTest, generateWithBadModifiers) {
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$TTL 3600\n"
+ "$GENERATE 10-12 host${GARBAGE} A 192.0.2.$\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ ASSERT_EQ(2, errors_.size()); // For the broken GENERATE
+ EXPECT_TRUE(warnings_.empty());
+
+ checkCallbackMessage(errors_.at(0),
+ "Invalid $GENERATE format modifiers", 3);
+ checkCallbackMessage(errors_.at(1),
+ "$GENERATE error", 3);
+}
+
+TEST_F(MasterLoaderTest, generateMissingRange) {
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$GENERATE\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_EQ(1, errors_.size()); // For the broken GENERATE
+ EXPECT_TRUE(warnings_.empty());
+
+ checkCallbackMessage(errors_.at(0),
+ "unexpected end of input", 2);
+}
+
+TEST_F(MasterLoaderTest, generateMissingLHS) {
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$GENERATE 2-4\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_EQ(1, errors_.size()); // For the broken GENERATE
+ EXPECT_TRUE(warnings_.empty());
+
+ checkCallbackMessage(errors_.at(0),
+ "unexpected end of input", 2);
+}
+
+TEST_F(MasterLoaderTest, generateMissingType) {
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$GENERATE 2-4 host$\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_EQ(1, errors_.size()); // For the broken GENERATE
+ EXPECT_TRUE(warnings_.empty());
+
+ checkCallbackMessage(errors_.at(0),
+ "unexpected end of input", 2);
+}
+
+TEST_F(MasterLoaderTest, generateMissingRHS) {
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$GENERATE 2-4 host$ A\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_EQ(1, errors_.size()); // For the broken GENERATE
+ EXPECT_TRUE(warnings_.empty());
+
+ checkCallbackMessage(errors_.at(0),
+ "unexpected end of input", 2);
+}
+
+TEST_F(MasterLoaderTest, generateWithBadRangeSyntax) {
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$GENERATE ABCD host$ 3600 A 192.0.2.$\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_EQ(1, errors_.size()); // For the broken GENERATE
+ EXPECT_TRUE(warnings_.empty());
+
+ checkCallbackMessage(errors_.at(0),
+ "$GENERATE: invalid range: ABCD", 2);
+}
+
+TEST_F(MasterLoaderTest, generateWithInvalidRange) {
+ // start > stop
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$GENERATE 2-1 host$ 3600 A 192.0.2.$\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_EQ(1, errors_.size()); // For the broken GENERATE
+ EXPECT_TRUE(warnings_.empty());
+
+ checkCallbackMessage(errors_.at(0),
+ "$GENERATE: invalid range: 2-1", 2);
+}
+
+TEST_F(MasterLoaderTest, generateWithInvalidClass) {
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$GENERATE 1-2 host$ 3600 CH A 192.0.2.$\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_EQ(1, errors_.size()); // For the broken GENERATE
+ EXPECT_TRUE(warnings_.empty());
+
+ checkCallbackMessage(errors_.at(0),
+ "Class mismatch: CH vs. IN", 2);
+}
+
+TEST_F(MasterLoaderTest, generateWithNoAvailableTTL) {
+ const string input =
+ "$ORIGIN example.org.\n"
+ "$GENERATE 1-2 host$ A 192.0.2.$\n";
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_EQ(1, errors_.size()); // For the broken GENERATE
+ EXPECT_TRUE(warnings_.empty());
+
+ checkCallbackMessage(errors_.at(0),
+ "no TTL specified; load rejected", 2);
+}
+
+// Test the source is correctly popped even after error
+TEST_F(MasterLoaderTest, popAfterError) {
+ const string include_str = "$include " TEST_DATA_SRCDIR
+ "/broken.zone\nwww 3600 IN AAAA 2001:db8::1\n";
+ stringstream ss(include_str);
+ // We perform the test with MANY_ERRORS, we want to see what happens
+ // after the error.
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_EQ(1, errors_.size()); // For the broken RR
+ EXPECT_EQ(1, warnings_.size()); // For missing EOLN
+
+ // The included file doesn't contain anything usable, but the
+ // line after the include should be there.
+ checkRR("www.example.org", RRType::AAAA(), "2001:db8::1");
+}
+
+// Check it works the same when created based on a stream, not filename
+TEST_F(MasterLoaderTest, streamConstructor) {
+ const string zone_data(prepareZone("", true));
+ stringstream zone_stream(zone_data);
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+
+ // Unlike the basicLoad test, if we construct the loader from a stream
+ // getSize() returns the data size in the stream immediately after the
+ // construction.
+ EXPECT_EQ(zone_data.size(), loader_->getSize());
+ EXPECT_EQ(0, loader_->getPosition());
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+
+ EXPECT_TRUE(errors_.empty());
+ EXPECT_TRUE(warnings_.empty());
+ checkRR("example.org", RRType::SOA(), "ns1.example.org. "
+ "admin.example.org. 1234 3600 1800 2419200 7200");
+ checkRR("correct.example.org", RRType::A(), "192.0.2.2");
+
+ // On completion of the load, both getSize() and getPosition() return the
+ // size of the data.
+ EXPECT_EQ(zone_data.size(), loader_->getSize());
+ EXPECT_EQ(zone_data.size(), loader_->getPosition());
+}
+
+// Try loading data incrementally.
+TEST_F(MasterLoaderTest, incrementalLoad) {
+ setLoader(TEST_DATA_SRCDIR "/example.org", Name("example.org."),
+ RRClass::IN(), MasterLoader::MANY_ERRORS);
+
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_FALSE(loader_->loadIncremental(2));
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+
+ EXPECT_TRUE(errors_.empty());
+ EXPECT_TRUE(warnings_.empty());
+
+ checkRR("example.org", RRType::SOA(),
+ "ns1.example.org. admin.example.org. "
+ "1234 3600 1800 2419200 7200");
+ checkRR("example.org", RRType::NS(), "ns1.example.org.");
+
+ // The third one is not loaded yet
+ EXPECT_TRUE(rrsets_.empty());
+
+ // Load the rest.
+ EXPECT_TRUE(loader_->loadIncremental(20));
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+
+ EXPECT_TRUE(errors_.empty());
+ EXPECT_TRUE(warnings_.empty());
+
+ checkRR("www.example.org", RRType::A(), "192.0.2.1");
+ checkRR("www.example.org", RRType::AAAA(), "2001:db8::1");
+}
+
+// Try loading from file that doesn't exist. There should be single error
+// saying so.
+TEST_F(MasterLoaderTest, invalidFile) {
+ setLoader("This file doesn't exist at all",
+ Name("example.org."), RRClass::IN(), MasterLoader::MANY_ERRORS);
+
+ // Nothing yet. The loader is dormant until invoked.
+ // Is it really what we want?
+ EXPECT_TRUE(errors_.empty());
+
+ loader_->load();
+
+ EXPECT_TRUE(warnings_.empty());
+ EXPECT_TRUE(rrsets_.empty());
+ ASSERT_EQ(1, errors_.size());
+ EXPECT_EQ(0, errors_[0].find("Error opening the input source file: ")) <<
+ "Different error: " << errors_[0];
+}
+
+struct ErrorCase {
+ const char* const line; // The broken line in master file
+ const char* const reason; // If non NULL, the reason string
+ const char* const problem; // Description of the problem for SCOPED_TRACE
+} const error_cases[] = {
+ { "www... 3600 IN A 192.0.2.1", NULL, "Invalid name" },
+ { "www FORTNIGHT IN A 192.0.2.1", NULL, "Invalid TTL" },
+ { "www 3600 XX A 192.0.2.1", NULL, "Invalid class" },
+ { "www 3600 IN A bad_ip", NULL, "Invalid Rdata" },
+
+ // Parameter ordering errors
+ { "www IN A 3600 192.168.2.7",
+ "createRdata from text failed: Bad IN/A RDATA text: '3600'",
+ "Incorrect order of class, TTL and type" },
+ { "www A IN 3600 192.168.2.8",
+ "createRdata from text failed: Bad IN/A RDATA text: 'IN'",
+ "Incorrect order of class, TTL and type" },
+ { "www 3600 A IN 192.168.2.7",
+ "createRdata from text failed: Bad IN/A RDATA text: 'IN'",
+ "Incorrect order of class, TTL and type" },
+ { "www A 3600 IN 192.168.2.8",
+ "createRdata from text failed: Bad IN/A RDATA text: '3600'",
+ "Incorrect order of class, TTL and type" },
+
+ // Missing type and Rdata
+ { "www", "unexpected end of input", "Missing type and Rdata" },
+ { "www 3600", "unexpected end of input", "Missing type and Rdata" },
+ { "www IN", "unexpected end of input", "Missing type and Rdata" },
+ { "www 3600 IN", "unexpected end of input", "Missing type and Rdata" },
+ { "www IN 3600", "unexpected end of input", "Missing type and Rdata" },
+
+ // Missing Rdata
+ { "www A",
+ "createRdata from text failed: unexpected end of input",
+ "Missing Rdata" },
+ { "www 3600 A",
+ "createRdata from text failed: unexpected end of input",
+ "Missing Rdata" },
+ { "www IN A",
+ "createRdata from text failed: unexpected end of input",
+ "Missing Rdata" },
+ { "www 3600 IN A",
+ "createRdata from text failed: unexpected end of input",
+ "Missing Rdata" },
+ { "www IN 3600 A",
+ "createRdata from text failed: unexpected end of input",
+ "Missing Rdata" },
+
+ { "www 3600 IN", NULL, "Unexpected EOLN" },
+ { "www 3600 CH TXT nothing", "Class mismatch: CH vs. IN",
+ "Class mismatch" },
+ { "www \"3600\" IN A 192.0.2.1", NULL, "Quoted TTL" },
+ { "www 3600 \"IN\" A 192.0.2.1", NULL, "Quoted class" },
+ { "www 3600 IN \"A\" 192.0.2.1", NULL, "Quoted type" },
+ { "unbalanced)paren 3600 IN A 192.0.2.1", NULL, "Token error 1" },
+ { "www 3600 unbalanced)paren A 192.0.2.1", NULL,
+ "Token error 2" },
+ // Check the unknown directive. The rest looks like ordinary RR,
+ // so we see the $ is actually special.
+ { "$UNKNOWN 3600 IN A 192.0.2.1", NULL, "Unknown $ directive" },
+ { "$INCLUD " TEST_DATA_SRCDIR "/example.org", "Unknown directive 'INCLUD'",
+ "Include too short" },
+ { "$INCLUDES " TEST_DATA_SRCDIR "/example.org",
+ "Unknown directive 'INCLUDES'", "Include too long" },
+ { "$INCLUDE", "unexpected end of input", "Missing include path" },
+ // The following two error messages are system dependent, omitting
+ { "$INCLUDE /file/not/found", NULL, "Include file not found" },
+ { "$INCLUDE /file/not/found example.org. and here goes bunch of garbage",
+ NULL, "Include file not found and garbage at the end of line" },
+ { "$ORIGIN", "unexpected end of input", "Missing origin name" },
+ { "$ORIGIN invalid...name", "duplicate period in invalid...name",
+ "Invalid name for origin" },
+ { "$ORIGIN )brokentoken", "unbalanced parentheses",
+ "Broken token in origin" },
+ { "$ORIGIN example.org. garbage", "Extra tokens at the end of line",
+ "Garbage after origin" },
+ { "$ORIGI name.", "Unknown directive 'ORIGI'", "$ORIGIN too short" },
+ { "$ORIGINAL name.", "Unknown directive 'ORIGINAL'", "$ORIGIN too long" },
+ { "$TTL 100 extra-garbage", "Extra tokens at the end of line",
+ "$TTL with extra token" },
+ { "$TTL", "unexpected end of input", "missing TTL" },
+ { "$TTL No-ttl", "Unknown unit used: N in: No-ttl", "bad TTL" },
+ { "$TTL \"100\"", "unexpected quotes", "bad TTL, quoted" },
+ { "$TT 100", "Unknown directive 'TT'", "bad directive, too short" },
+ { "$TTLLIKE 100", "Unknown directive 'TTLLIKE'", "bad directive, extra" },
+ { NULL, NULL, NULL }
+};
+
+// Test a broken zone is handled properly. We test several problems,
+// both in strict and lenient mode.
+TEST_F(MasterLoaderTest, brokenZone) {
+ for (const ErrorCase* ec = error_cases; ec->line != NULL; ++ec) {
+ SCOPED_TRACE(ec->problem);
+ const string zone(prepareZone(ec->line, true));
+
+ {
+ SCOPED_TRACE("Strict mode");
+ clear();
+ stringstream zone_stream(zone);
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::DEFAULT);
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_THROW(loader_->load(), MasterLoaderError);
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_EQ(1, errors_.size());
+ if (ec->reason != NULL) {
+ checkCallbackMessage(errors_.at(0), ec->reason, 2);
+ }
+ EXPECT_TRUE(warnings_.empty());
+
+ checkRR("example.org", RRType::SOA(), "ns1.example.org. "
+ "admin.example.org. 1234 3600 1800 2419200 7200");
+ // In the strict mode, it is aborted. The last RR is not
+ // even attempted.
+ EXPECT_TRUE(rrsets_.empty());
+ }
+
+ {
+ SCOPED_TRACE("Lenient mode");
+ clear();
+ stringstream zone_stream(zone);
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_NO_THROW(loader_->load());
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_EQ(1, errors_.size());
+ EXPECT_TRUE(warnings_.empty());
+ checkRR("example.org", RRType::SOA(), "ns1.example.org. "
+ "admin.example.org. 1234 3600 1800 2419200 7200");
+ // This one is below the error one.
+ checkRR("correct.example.org", RRType::A(), "192.0.2.2");
+ EXPECT_TRUE(rrsets_.empty());
+ }
+
+ {
+ SCOPED_TRACE("Error at EOF");
+ // This case is interesting only in the lenient mode.
+ clear();
+ const string zoneEOF(prepareZone(ec->line, false));
+ stringstream zone_stream(zoneEOF);
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_NO_THROW(loader_->load());
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_EQ(1, errors_.size()) << errors_[0] << "\n" << errors_[1];
+ // The unexpected EOF warning
+ EXPECT_EQ(1, warnings_.size());
+ checkRR("example.org", RRType::SOA(), "ns1.example.org. "
+ "admin.example.org. 1234 3600 1800 2419200 7200");
+ EXPECT_TRUE(rrsets_.empty());
+ }
+ }
+}
+
+// Check that a garbage after the include generates an error, but not fatal
+// one (in lenient mode) and we can recover.
+TEST_F(MasterLoaderTest, includeWithGarbage) {
+ // Include an origin (example.org) because we expect it to be handled
+ // soon and we don't want it to break here.
+ const string include_str("$INCLUDE " TEST_DATA_SRCDIR
+ "/example.org example.org. bunch of other stuff\n"
+ "www 3600 IN AAAA 2001:db8::1\n");
+ stringstream zone_stream(include_str);
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ EXPECT_NO_THROW(loader_->load());
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ ASSERT_EQ(1, errors_.size());
+ checkCallbackMessage(errors_.at(0), "Extra tokens at the end of line", 1);
+ // It says something about extra tokens at the end
+ EXPECT_NE(string::npos, errors_[0].find("Extra"));
+ EXPECT_TRUE(warnings_.empty());
+ checkBasicRRs();
+ checkRR("www.example.org", RRType::AAAA(), "2001:db8::1");
+}
+
+// Check we error about garbage at the end of $ORIGIN line (but the line
+// works).
+TEST_F(MasterLoaderTest, originWithGarbage) {
+ const string origin_str = "$ORIGIN www.example.org. More garbage here\n"
+ "@ 1H IN A 192.0.2.1\n";
+ stringstream ss(origin_str);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+ EXPECT_NO_THROW(loader_->load());
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ ASSERT_EQ(1, errors_.size());
+ checkCallbackMessage(errors_.at(0), "Extra tokens at the end of line", 1);
+ EXPECT_TRUE(warnings_.empty());
+ checkARR("www.example.org");
+}
+
+// Test we can pass both file to include and the origin to switch
+TEST_F(MasterLoaderTest, includeAndOrigin) {
+ // First, switch origin to something else, so we can check it is
+ // switched back.
+ const string include_string = "$ORIGIN www.example.org.\n"
+ "@ 1H IN A 192.0.2.1\n"
+ // Then include the file with data and switch origin back
+ "$INCLUDE " TEST_DATA_SRCDIR "/example.org example.org.\n"
+ // Another RR to see we fall back to the previous origin.
+ "www 1H IN A 192.0.2.1\n";
+ stringstream ss(include_string);
+ setLoader(ss, Name("example.org"), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+ // Successfully load the data
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+ EXPECT_TRUE(warnings_.empty());
+ // And check it's the correct data
+ checkARR("www.example.org");
+ checkBasicRRs();
+ checkARR("www.www.example.org");
+}
+
+// Like above, but the origin after include is bogus. The whole line should
+// be rejected.
+TEST_F(MasterLoaderTest, includeAndBadOrigin) {
+ const string include_string =
+ "$INCLUDE " TEST_DATA_SRCDIR "/example.org example..org.\n"
+ // Another RR to see the switch survives after we exit include
+ "www 1H IN A 192.0.2.1\n";
+ stringstream ss(include_string);
+ setLoader(ss, Name("example.org"), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+ loader_->load();
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_EQ(1, errors_.size());
+ checkCallbackMessage(errors_.at(0), "duplicate period in example..org.",
+ 1);
+ EXPECT_TRUE(warnings_.empty());
+ // And check it's the correct data
+ checkARR("www.example.org");
+}
+
+// Check the origin doesn't get outside of the included file.
+TEST_F(MasterLoaderTest, includeOriginRestore) {
+ const string include_string =
+ "$INCLUDE " TEST_DATA_SRCDIR "/origincheck.txt\n"
+ "@ 1H IN A 192.0.2.1\n";
+ stringstream ss(include_string);
+ setLoader(ss, Name("example.org"), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+ // Successfully load the data
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+ EXPECT_TRUE(warnings_.empty());
+ // And check it's the correct data
+ checkARR("www.example.org");
+ checkARR("example.org");
+}
+
+// Check we restore the last name for initial whitespace when returning from
+// include. But we do produce a warning if there's one just ofter the include.
+TEST_F(MasterLoaderTest, includeAndInitialWS) {
+ const string include_string = "xyz 1H IN A 192.0.2.1\n"
+ "$INCLUDE " TEST_DATA_SRCDIR "/example.org\n"
+ " 1H IN A 192.0.2.1\n";
+ stringstream ss(include_string);
+ setLoader(ss, Name("example.org"), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+ // Successfully load the data
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+ EXPECT_EQ(1, warnings_.size());
+ checkCallbackMessage(warnings_.at(0),
+ "Owner name omitted around $INCLUDE, the result might "
+ "not be as expected", 3);
+ checkARR("xyz.example.org");
+ checkBasicRRs();
+ checkARR("xyz.example.org");
+}
+
+// Test for "$TTL"
+TEST_F(MasterLoaderTest, ttlDirective) {
+ stringstream zone_stream;
+
+ // Set the default TTL with $TTL followed by an RR omitting the TTL
+ zone_stream << "$TTL 1800\nexample.org. IN A 192.0.2.1\n";
+ // $TTL can be quoted. Also testing the case of $TTL being changed.
+ zone_stream << "\"$TTL\" 100\na.example.org. IN A 192.0.2.2\n";
+ // Extended TTL form is accepted.
+ zone_stream << "$TTL 1H\nb.example.org. IN A 192.0.2.3\n";
+ // Matching is case insensitive.
+ zone_stream << "$tTl 360\nc.example.org. IN A 192.0.2.4\n";
+ // Maximum allowable TTL
+ zone_stream << "$TTL 2147483647\nd.example.org. IN A 192.0.2.5\n";
+
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::DEFAULT);
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ checkRR("example.org", RRType::A(), "192.0.2.1", RRTTL(1800));
+ checkRR("a.example.org", RRType::A(), "192.0.2.2", RRTTL(100));
+ checkRR("b.example.org", RRType::A(), "192.0.2.3", RRTTL(3600));
+ checkRR("c.example.org", RRType::A(), "192.0.2.4", RRTTL(360));
+ checkRR("d.example.org", RRType::A(), "192.0.2.5", RRTTL(2147483647));
+}
+
+TEST_F(MasterLoaderTest, ttlFromSOA) {
+ // No $TTL, and the SOA doesn't have an explicit TTL field. Its minimum
+ // TTL field will be used as the RR's TTL, and it'll be used as the
+ // default TTL for others.
+ stringstream zone_stream("example.org. IN SOA . . 0 0 0 0 1800\n"
+ "a.example.org. IN A 192.0.2.1\n");
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::DEFAULT);
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ checkRR("example.org", RRType::SOA(), ". . 0 0 0 0 1800", RRTTL(1800));
+ checkRR("a.example.org", RRType::A(), "192.0.2.1", RRTTL(1800));
+
+ // The use of SOA minimum TTL should have caused a warning.
+ EXPECT_EQ(1, warnings_.size());
+ checkCallbackMessage(warnings_.at(0),
+ "no TTL specified; using SOA MINTTL instead", 1);
+}
+
+TEST_F(MasterLoaderTest, ttlFromPrevious) {
+ // No available default TTL. 2nd and 3rd RR will use the TTL of the
+ // 1st RR. This will result in a warning, but only for the first time.
+ stringstream zone_stream("a.example.org. 1800 IN A 192.0.2.1\n"
+ "b.example.org. IN A 192.0.2.2\n"
+ "c.example.org. IN A 192.0.2.3\n");
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::DEFAULT);
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ checkRR("a.example.org", RRType::A(), "192.0.2.1", RRTTL(1800));
+ checkRR("b.example.org", RRType::A(), "192.0.2.2", RRTTL(1800));
+ checkRR("c.example.org", RRType::A(), "192.0.2.3", RRTTL(1800));
+
+ EXPECT_EQ(1, warnings_.size());
+ checkCallbackMessage(warnings_.at(0), "using RFC1035 TTL semantics", 2);
+}
+
+TEST_F(MasterLoaderTest, RRParamsOrdering) {
+ // We test the order and existence of TTL, class and type. See
+ // MasterLoader::MasterLoaderImpl::parseRRParams() for ordering.
+
+ stringstream zone_stream;
+ // <TTL> <class> <type> <RDATA>
+ zone_stream << "a.example.org. 1800 IN A 192.0.2.1\n";
+ // <type> <RDATA>
+ zone_stream << "b.example.org. A 192.0.2.2\n";
+ // <class> <TTL> <type> <RDATA>
+ zone_stream << "c.example.org. IN 3600 A 192.0.2.3\n";
+ // <TTL> <type> <RDATA>
+ zone_stream << "d.example.org. 7200 A 192.0.2.4\n";
+ // <class> <type> <RDATA>
+ zone_stream << "e.example.org. IN A 192.0.2.5\n";
+
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::DEFAULT);
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ checkRR("a.example.org", RRType::A(), "192.0.2.1", RRTTL(1800));
+ checkRR("b.example.org", RRType::A(), "192.0.2.2", RRTTL(1800));
+ checkRR("c.example.org", RRType::A(), "192.0.2.3", RRTTL(3600));
+ checkRR("d.example.org", RRType::A(), "192.0.2.4", RRTTL(7200));
+ checkRR("e.example.org", RRType::A(), "192.0.2.5", RRTTL(7200));
+
+ EXPECT_EQ(1, warnings_.size());
+ checkCallbackMessage(warnings_.at(0), "using RFC1035 TTL semantics", 2);
+}
+
+TEST_F(MasterLoaderTest, ttlFromPreviousSOA) {
+ // Mixture of the previous two cases: SOA has explicit TTL, followed by
+ // an RR without an explicit TTL. In this case the minimum TTL won't be
+ // recognized as the "default TTL".
+ stringstream zone_stream("example.org. 100 IN SOA . . 0 0 0 0 1800\n"
+ "a.example.org. IN A 192.0.2.1\n");
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::DEFAULT);
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+
+ checkRR("example.org", RRType::SOA(), ". . 0 0 0 0 1800", RRTTL(100));
+ checkRR("a.example.org", RRType::A(), "192.0.2.1", RRTTL(100));
+
+ EXPECT_EQ(1, warnings_.size());
+ checkCallbackMessage(warnings_.at(0), "using RFC1035 TTL semantics", 2);
+}
+
+TEST_F(MasterLoaderTest, ttlUnknown) {
+ // No available TTL is known for the first RR.
+ stringstream zone_stream("a.example.org. IN A 192.0.2.1\n");
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::DEFAULT);
+ EXPECT_THROW(loader_->load(), MasterLoaderError);
+}
+
+TEST_F(MasterLoaderTest, ttlUnknownAndContinue) {
+ stringstream zone_stream("a.example.org. IN A 192.0.2.1\n"
+ "b.example.org. 1800 IN A 192.0.2.2\n");
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+ loader_->load();
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ checkRR("b.example.org", RRType::A(), "192.0.2.2", RRTTL(1800));
+
+ EXPECT_TRUE(warnings_.empty());
+ EXPECT_EQ(1, errors_.size());
+ checkCallbackMessage(errors_.at(0), "no TTL specified; load rejected", 1);
+}
+
+TEST_F(MasterLoaderTest, ttlUnknownAndEOF) {
+ // Similar to the previous case, but the input will be abruptly terminated
+ // after the offending RR. This will cause an additional warning.
+ stringstream zone_stream("a.example.org. IN A 192.0.2.1");
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+ loader_->load();
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(rrsets_.empty());
+
+ EXPECT_EQ(1, errors_.size());
+ checkCallbackMessage(errors_.at(0), "no TTL specified; load rejected", 1);
+
+ // RDATA implementation can complain about it, too. To be independent of
+ // its details, we focus on the very last warning.
+ EXPECT_FALSE(warnings_.empty());
+ checkCallbackMessage(*warnings_.rbegin(), "File does not end with newline",
+ 1);
+}
+
+TEST_F(MasterLoaderTest, ttlOverflow) {
+ stringstream zone_stream;
+ zone_stream << "example.org. IN SOA . . 0 0 0 0 2147483648\n";
+ zone_stream << "$TTL 3600\n"; // reset to an in-range value
+ zone_stream << "$TTL 2147483649\n";
+ zone_stream << "a.example.org. IN A 192.0.2.1\n";
+ zone_stream << "$TTL 3600\n"; // reset to an in-range value
+ zone_stream << "b.example.org. 2147483650 IN A 192.0.2.2\n";
+ setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+ MasterLoader::DEFAULT);
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_EQ(3, rrsets_.size());
+
+ checkRR("example.org", RRType::SOA(), ". . 0 0 0 0 2147483648", RRTTL(0));
+ checkRR("a.example.org", RRType::A(), "192.0.2.1", RRTTL(0));
+ checkRR("b.example.org", RRType::A(), "192.0.2.2", RRTTL(0));
+
+ EXPECT_EQ(4, warnings_.size());
+ checkCallbackMessage(warnings_.at(1),
+ "TTL 2147483648 > MAXTTL, setting to 0 per RFC2181",
+ 1);
+ checkCallbackMessage(warnings_.at(2),
+ "TTL 2147483649 > MAXTTL, setting to 0 per RFC2181",
+ 3);
+ checkCallbackMessage(warnings_.at(3),
+ "TTL 2147483650 > MAXTTL, setting to 0 per RFC2181",
+ 6);
+}
+
+// Test the constructor rejects empty add callback.
+TEST_F(MasterLoaderTest, emptyCallback) {
+ EXPECT_THROW(MasterLoader(TEST_DATA_SRCDIR "/example.org",
+ Name("example.org"), RRClass::IN(), callbacks_,
+ AddRRCallback()), isc::InvalidParameter);
+ // And the same with the second constructor
+ stringstream ss("");
+ EXPECT_THROW(MasterLoader(ss, Name("example.org"), RRClass::IN(),
+ callbacks_, AddRRCallback()),
+ isc::InvalidParameter);
+}
+
+// Check it throws when we try to load after loading was complete.
+TEST_F(MasterLoaderTest, loadTwice) {
+ setLoader(TEST_DATA_SRCDIR "/example.org", Name("example.org."),
+ RRClass::IN(), MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_THROW(loader_->load(), isc::InvalidOperation);
+ // Don't check them, they are not interesting, so suppress the error
+ // at TearDown
+ rrsets_.clear();
+}
+
+// Load 0 items should be rejected
+TEST_F(MasterLoaderTest, loadZero) {
+ setLoader(TEST_DATA_SRCDIR "/example.org", Name("example.org."),
+ RRClass::IN(), MasterLoader::MANY_ERRORS);
+ EXPECT_THROW(loader_->loadIncremental(0), isc::InvalidParameter);
+}
+
+// Test there's a warning when the file terminates without end of
+// line.
+TEST_F(MasterLoaderTest, noEOLN) {
+ // No \n at the end
+ const string input("example.org. 3600 IN SOA ns1.example.org. "
+ "admin.example.org. 1234 3600 1800 2419200 7200");
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+ // There should be one warning about the EOLN
+ EXPECT_EQ(1, warnings_.size());
+ checkRR("example.org", RRType::SOA(), "ns1.example.org. "
+ "admin.example.org. 1234 3600 1800 2419200 7200");
+}
+
+// Test it rejects when we don't have the previous name to use in place of
+// initial whitespace
+TEST_F(MasterLoaderTest, noPreviousName) {
+ const string input(" 1H IN A 192.0.2.1\n");
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+ loader_->load();
+ EXPECT_FALSE(loader_->loadedSuccessfully());
+ EXPECT_EQ(1, errors_.size());
+ checkCallbackMessage(errors_.at(0), "No previous name to use in place of "
+ "initial whitespace", 1);
+ EXPECT_TRUE(warnings_.empty());
+}
+
+// Check we warn if the first RR in an included file has omitted name
+TEST_F(MasterLoaderTest, previousInInclude) {
+ const string input("www 1H IN A 192.0.2.1\n"
+ "$INCLUDE " TEST_DATA_SRCDIR "/omitcheck.txt\n");
+ stringstream ss(input);
+ setLoader(ss, Name("example.org"), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+ // There should be one warning about the EOLN
+ EXPECT_EQ(1, warnings_.size());
+ checkCallbackMessage(warnings_.at(0), "Owner name omitted around "
+ "$INCLUDE, the result might not be as expected", 1);
+ checkARR("www.example.org");
+ checkARR("www.example.org");
+}
+
+TEST_F(MasterLoaderTest, numericOwnerName) {
+ const string input("$ORIGIN example.org.\n"
+ "1 3600 IN A 192.0.2.1\n");
+ stringstream ss(input);
+ setLoader(ss, Name("example.org."), RRClass::IN(),
+ MasterLoader::MANY_ERRORS);
+
+ loader_->load();
+ EXPECT_TRUE(loader_->loadedSuccessfully());
+ EXPECT_TRUE(errors_.empty());
+ EXPECT_TRUE(warnings_.empty());
+
+ checkRR("1.example.org", RRType::A(), "192.0.2.1");
+}
+
+}
diff --git a/src/lib/dns/tests/masterload_unittest.cc b/src/lib/dns/tests/masterload_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/masterload_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/message_unittest.cc b/src/lib/dns/tests/message_unittest.cc
index 8b13789179..850d018158 100644
--- a/src/lib/dns/tests/message_unittest.cc
+++ b/src/lib/dns/tests/message_unittest.cc
@@ -1 +1,1157 @@
+// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <fstream>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <util/time_utilities.h>
+
+#include <util/unittests/testdata.h>
+#include <util/unittests/textdata.h>
+
+#include <dns/edns.h>
+#include <dns/exceptions.h>
+#include <dns/message.h>
+#include <dns/messagerenderer.h>
+#include <dns/question.h>
+#include <dns/opcode.h>
+#include <dns/rcode.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrttl.h>
+#include <dns/rrtype.h>
+#include <dns/tsig.h>
+#include <dns/tsigkey.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+#include <util/unittests/wiredata.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+//
+// Note: we need more tests, including:
+// parsing malformed headers
+// more complete tests about parsing/rendering header flags, opcode, rcode, etc.
+// tests for adding RRsets
+// tests for RRset/Question iterators
+// But, we'll ship with the current set of tests for now, partly because many
+// of the above are covered as part of other tests, and partly due to time
+// limitation. We also expect to revisit the fundamental design of the Message
+// class, at which point we'll also revise the tests including more cases.
+//
+
+const uint16_t Message::DEFAULT_MAX_UDPSIZE;
+
+namespace isc {
+namespace util {
+namespace detail {
+extern int64_t (*gettimeFunction)();
+}
+}
+}
+
+// XXX: this is defined as class static constants, but some compilers
+// seemingly cannot find the symbol when used in the EXPECT_xxx macros.
+const uint16_t TSIGContext::DEFAULT_FUDGE;
+
+namespace {
+class MessageTest : public ::testing::Test {
+protected:
+ MessageTest() : test_name("test.example.com"), obuffer(0),
+ message_parse(Message::PARSE),
+ message_render(Message::RENDER),
+ bogus_section(static_cast<Message::Section>(
+ Message::SECTION_ADDITIONAL + 1)),
+ tsig_ctx(TSIGKey("www.example.com:"
+ "SFuWd/q99SzF8Yzd1QbB9g==")) {
+ rrset_a = RRsetPtr(new RRset(test_name, RRClass::IN(),
+ RRType::A(), RRTTL(3600)));
+ rrset_a->addRdata(in::A("192.0.2.1"));
+ rrset_a->addRdata(in::A("192.0.2.2"));
+
+ rrset_aaaa = RRsetPtr(new RRset(test_name, RRClass::IN(),
+ RRType::AAAA(), RRTTL(3600)));
+ rrset_aaaa->addRdata(in::AAAA("2001:db8::1234"));
+
+ rrset_rrsig = RRsetPtr(new RRset(test_name, RRClass::IN(),
+ RRType::RRSIG(), RRTTL(3600)));
+ rrset_rrsig->addRdata(generic::RRSIG("AAAA 5 3 7200 20100322084538 "
+ "20100220084538 1 example.com. "
+ "FAKEFAKEFAKEFAKE"));
+ rrset_aaaa->addRRsig(rrset_rrsig);
+ }
+
+ static Question factoryFromFile(const char* datafile);
+ const Name test_name;
+ OutputBuffer obuffer;
+ MessageRenderer renderer;
+ Message message_parse;
+ Message message_render;
+ const Message::Section bogus_section;
+ RRsetPtr rrset_a; // A RRset with two RDATAs
+ RRsetPtr rrset_aaaa; // AAAA RRset with one RDATA with RRSIG
+ RRsetPtr rrset_rrsig; // RRSIG for the AAAA RRset
+ TSIGContext tsig_ctx;
+ vector<unsigned char> received_data;
+ vector<unsigned char> expected_data;
+
+ void factoryFromFile(Message& message, const char* datafile,
+ Message::ParseOptions options =
+ Message::PARSE_DEFAULT);
+};
+
+void
+MessageTest::factoryFromFile(Message& message, const char* datafile,
+ Message::ParseOptions options)
+{
+ received_data.clear();
+ UnitTestUtil::readWireData(datafile, received_data);
+
+ InputBuffer buffer(&received_data[0], received_data.size());
+ message.fromWire(buffer, options);
+}
+
+TEST_F(MessageTest, headerFlag) {
+ // by default no flag is set
+ EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_QR));
+ EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_AA));
+ EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_TC));
+ EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_RD));
+ EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_RA));
+ EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_AD));
+ EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_CD));
+
+ // set operation: by default it will be on
+ message_render.setHeaderFlag(Message::HEADERFLAG_QR);
+ EXPECT_TRUE(message_render.getHeaderFlag(Message::HEADERFLAG_QR));
+
+ // it can be set to on explicitly, too
+ message_render.setHeaderFlag(Message::HEADERFLAG_AA, true);
+ EXPECT_TRUE(message_render.getHeaderFlag(Message::HEADERFLAG_AA));
+
+ // the bit can also be cleared
+ message_render.setHeaderFlag(Message::HEADERFLAG_AA, false);
+ EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_AA));
+
+ // Invalid flag values
+ EXPECT_THROW(message_render.setHeaderFlag(
+ static_cast<Message::HeaderFlag>(0)), InvalidParameter);
+ EXPECT_THROW(message_render.setHeaderFlag(
+ static_cast<Message::HeaderFlag>(0x7000)),
+ InvalidParameter);
+ EXPECT_THROW(message_render.setHeaderFlag(
+ static_cast<Message::HeaderFlag>(0x0800)),
+ InvalidParameter);
+ EXPECT_THROW(message_render.setHeaderFlag(
+ static_cast<Message::HeaderFlag>(0x0040)),
+ InvalidParameter);
+ EXPECT_THROW(message_render.setHeaderFlag(
+ static_cast<Message::HeaderFlag>(0x10000)),
+ InvalidParameter);
+ EXPECT_THROW(message_render.setHeaderFlag(
+ static_cast<Message::HeaderFlag>(0x80000000)),
+ InvalidParameter);
+
+ // set operation isn't allowed in the parse mode.
+ EXPECT_THROW(message_parse.setHeaderFlag(Message::HEADERFLAG_QR),
+ InvalidMessageOperation);
+}
+TEST_F(MessageTest, getEDNS) {
+ EXPECT_FALSE(message_parse.getEDNS()); // by default EDNS isn't set
+
+ factoryFromFile(message_parse, "message_fromWire10.wire");
+ EXPECT_TRUE(message_parse.getEDNS());
+ EXPECT_EQ(0, message_parse.getEDNS()->getVersion());
+ EXPECT_EQ(4096, message_parse.getEDNS()->getUDPSize());
+ EXPECT_TRUE(message_parse.getEDNS()->getDNSSECAwareness());
+}
+
+TEST_F(MessageTest, setEDNS) {
+ // setEDNS() isn't allowed in the parse mode
+ EXPECT_THROW(message_parse.setEDNS(EDNSPtr(new EDNS())),
+ InvalidMessageOperation);
+
+ EDNSPtr edns = EDNSPtr(new EDNS());
+ message_render.setEDNS(edns);
+ EXPECT_EQ(edns, message_render.getEDNS());
+}
+
+TEST_F(MessageTest, fromWireWithTSIG) {
+ // Initially there should be no TSIG
+ EXPECT_EQ(static_cast<void*>(NULL), message_parse.getTSIGRecord());
+
+ // getTSIGRecord() is only valid in the parse mode.
+ EXPECT_THROW(message_render.getTSIGRecord(), InvalidMessageOperation);
+
+ factoryFromFile(message_parse, "message_toWire2.wire");
+ const uint8_t expected_mac[] = {
+ 0x22, 0x70, 0x26, 0xad, 0x29, 0x7b, 0xee, 0xe7,
+ 0x21, 0xce, 0x6c, 0x6f, 0xff, 0x1e, 0x9e, 0xf3
+ };
+ const TSIGRecord* tsig_rr = message_parse.getTSIGRecord();
+ ASSERT_NE(static_cast<void*>(NULL), tsig_rr);
+ EXPECT_EQ(Name("www.example.com"), tsig_rr->getName());
+ EXPECT_EQ(85, tsig_rr->getLength()); // see TSIGRecordTest.getLength
+ EXPECT_EQ(TSIGKey::HMACMD5_NAME(), tsig_rr->getRdata().getAlgorithm());
+ EXPECT_EQ(0x4da8877a, tsig_rr->getRdata().getTimeSigned());
+ EXPECT_EQ(TSIGContext::DEFAULT_FUDGE, tsig_rr->getRdata().getFudge());
+ matchWireData(expected_mac, sizeof(expected_mac),
+ tsig_rr->getRdata().getMAC(),
+ tsig_rr->getRdata().getMACSize());
+ EXPECT_EQ(0, tsig_rr->getRdata().getError());
+ EXPECT_EQ(0, tsig_rr->getRdata().getOtherLen());
+ EXPECT_EQ(static_cast<void*>(NULL), tsig_rr->getRdata().getOtherData());
+
+ // If we clear the message for reuse, the recorded TSIG will be cleared.
+ message_parse.clear(Message::PARSE);
+ EXPECT_EQ(static_cast<void*>(NULL), message_parse.getTSIGRecord());
+}
+
+TEST_F(MessageTest, fromWireWithTSIGCompressed) {
+ // Mostly same as fromWireWithTSIG, but the TSIG owner name is compressed.
+ factoryFromFile(message_parse, "message_fromWire12.wire");
+ const TSIGRecord* tsig_rr = message_parse.getTSIGRecord();
+ ASSERT_NE(static_cast<void*>(NULL), tsig_rr);
+ EXPECT_EQ(Name("www.example.com"), tsig_rr->getName());
+ // len(www.example.com) = 17, but when fully compressed, the length is
+ // 2 bytes. So the length of the record should be 15 bytes shorter.
+ EXPECT_EQ(70, tsig_rr->getLength());
+}
+
+TEST_F(MessageTest, fromWireWithBadTSIG) {
+ // Multiple TSIG RRs
+ EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire13.wire"),
+ DNSMessageFORMERR);
+ message_parse.clear(Message::PARSE);
+
+ // TSIG in the answer section (must be in additional)
+ EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire14.wire"),
+ DNSMessageFORMERR);
+ message_parse.clear(Message::PARSE);
+
+ // TSIG is not the last record.
+ EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire15.wire"),
+ DNSMessageFORMERR);
+ message_parse.clear(Message::PARSE);
+
+ // Unexpected RR Class (this will fail in constructing TSIGRecord)
+ EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire16.wire"),
+ DNSMessageFORMERR);
+}
+
+TEST_F(MessageTest, getRRCount) {
+ // by default all counters should be 0
+ EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_QUESTION));
+ EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ANSWER));
+ EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_AUTHORITY));
+ EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ADDITIONAL));
+
+ message_render.addQuestion(Question(Name("test.example.com"),
+ RRClass::IN(), RRType::A()));
+ EXPECT_EQ(1, message_render.getRRCount(Message::SECTION_QUESTION));
+
+ // rrset_a contains two RRs
+ message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
+ EXPECT_EQ(2, message_render.getRRCount(Message::SECTION_ANSWER));
+
+ // parse a message containing a Question and EDNS OPT RR.
+ // OPT shouldn't be counted as normal RR, so result of getRRCount
+ // shouldn't change.
+ factoryFromFile(message_parse, "message_fromWire11.wire");
+ EXPECT_EQ(1, message_render.getRRCount(Message::SECTION_QUESTION));
+ EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ADDITIONAL));
+
+ // out-of-band section ID
+ EXPECT_THROW(message_parse.getRRCount(bogus_section), OutOfRange);
+}
+
+TEST_F(MessageTest, addRRset) {
+ // initially, we have 0
+ EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ANSWER));
+
+ // add two A RRs (unsigned)
+ message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
+ EXPECT_EQ(rrset_a,
+ *message_render.beginSection(Message::SECTION_ANSWER));
+ EXPECT_EQ(2, message_render.getRRCount(Message::SECTION_ANSWER));
+
+ message_render.clear(Message::RENDER);
+
+ // add one AAAA RR (signed)
+ message_render.addRRset(Message::SECTION_ANSWER, rrset_aaaa);
+ EXPECT_EQ(rrset_aaaa,
+ *message_render.beginSection(Message::SECTION_ANSWER));
+ EXPECT_EQ(2, message_render.getRRCount(Message::SECTION_ANSWER));
+}
+
+TEST_F(MessageTest, badAddRRset) {
+ // addRRset() isn't allowed in the parse mode.
+ EXPECT_THROW(message_parse.addRRset(Message::SECTION_ANSWER,
+ rrset_a), InvalidMessageOperation);
+ // out-of-band section ID
+ EXPECT_THROW(message_render.addRRset(bogus_section, rrset_a), OutOfRange);
+
+ // NULL RRset
+ EXPECT_THROW(message_render.addRRset(Message::SECTION_ANSWER, RRsetPtr()),
+ InvalidParameter);
+}
+
+TEST_F(MessageTest, hasRRset) {
+ message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
+ EXPECT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
+ RRClass::IN(), RRType::A()));
+ // section doesn't match
+ EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
+ RRClass::IN(), RRType::A()));
+ // name doesn't match
+ EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER,
+ Name("nomatch.example"),
+ RRClass::IN(), RRType::A()));
+ // RR class doesn't match
+ EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
+ RRClass::CH(), RRType::A()));
+ // RR type doesn't match
+ EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
+ RRClass::IN(), RRType::AAAA()));
+
+ // out-of-band section ID
+ EXPECT_THROW(message_render.hasRRset(bogus_section, test_name,
+ RRClass::IN(), RRType::A()),
+ OutOfRange);
+
+ // Repeat the checks having created an RRset of the appropriate type.
+
+ RRsetPtr rrs1(new RRset(test_name, RRClass::IN(), RRType::A(), RRTTL(60)));
+ EXPECT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, rrs1));
+ EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ADDITIONAL, rrs1));
+
+ RRsetPtr rrs2(new RRset(Name("nomatch.example"), RRClass::IN(), RRType::A(),
+ RRTTL(5)));
+ EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, rrs2));
+
+ RRsetPtr rrs3(new RRset(test_name, RRClass::CH(), RRType::A(), RRTTL(60)));
+ EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, rrs3));
+
+ RRsetPtr rrs4(new RRset(test_name, RRClass::IN(), RRType::AAAA(), RRTTL(5)));
+ EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, rrs4));
+
+ RRsetPtr rrs5(new RRset(test_name, RRClass::IN(), RRType::AAAA(), RRTTL(5)));
+ EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, rrs4));
+
+ EXPECT_THROW(message_render.hasRRset(bogus_section, rrs1), OutOfRange);
+}
+
+TEST_F(MessageTest, removeRRset) {
+ message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
+ message_render.addRRset(Message::SECTION_ANSWER, rrset_aaaa);
+ EXPECT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
+ RRClass::IN(), RRType::A()));
+ EXPECT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
+ RRClass::IN(), RRType::AAAA()));
+ EXPECT_EQ(4, message_render.getRRCount(Message::SECTION_ANSWER));
+
+ // Locate the AAAA RRset and remove it and any associated RRSIGs
+ RRsetIterator i = message_render.beginSection(Message::SECTION_ANSWER);
+ if ((*i)->getType() == RRType::A()) {
+ ++i;
+ }
+ EXPECT_EQ(RRType::AAAA(), (*i)->getType());
+ message_render.removeRRset(Message::SECTION_ANSWER, i);
+
+ EXPECT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
+ RRClass::IN(), RRType::A()));
+ EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
+ RRClass::IN(), RRType::AAAA()));
+ EXPECT_EQ(2, message_render.getRRCount(Message::SECTION_ANSWER));
+}
+
+TEST_F(MessageTest, clearQuestionSection) {
+ QuestionPtr q(new Question(Name("www.example.com"), RRClass::IN(),
+ RRType::A()));
+ message_render.addQuestion(q);
+ ASSERT_EQ(1, message_render.getRRCount(Message::SECTION_QUESTION));
+
+ message_render.clearSection(Message::SECTION_QUESTION);
+ EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_QUESTION));
+ EXPECT_TRUE(message_render.beginQuestion() ==
+ message_render.endQuestion());
+}
+
+
+TEST_F(MessageTest, clearAnswerSection) {
+ // Add two RRsets, check they are present, clear the section,
+ // check if they are gone.
+ message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
+ message_render.addRRset(Message::SECTION_ANSWER, rrset_aaaa);
+ ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
+ RRClass::IN(), RRType::A()));
+ ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
+ RRClass::IN(), RRType::AAAA()));
+ ASSERT_EQ(4, message_render.getRRCount(Message::SECTION_ANSWER));
+
+ message_render.clearSection(Message::SECTION_ANSWER);
+ EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
+ RRClass::IN(), RRType::A()));
+ EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
+ RRClass::IN(), RRType::AAAA()));
+ EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ANSWER));
+}
+
+TEST_F(MessageTest, clearAuthoritySection) {
+ // Add two RRsets, check they are present, clear the section,
+ // check if they are gone.
+ message_render.addRRset(Message::SECTION_AUTHORITY, rrset_a);
+ message_render.addRRset(Message::SECTION_AUTHORITY, rrset_aaaa);
+ ASSERT_TRUE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
+ RRClass::IN(), RRType::A()));
+ ASSERT_TRUE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
+ RRClass::IN(), RRType::AAAA()));
+ ASSERT_EQ(4, message_render.getRRCount(Message::SECTION_AUTHORITY));
+
+ message_render.clearSection(Message::SECTION_AUTHORITY);
+ EXPECT_FALSE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
+ RRClass::IN(), RRType::A()));
+ EXPECT_FALSE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
+ RRClass::IN(), RRType::AAAA()));
+ EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_AUTHORITY));
+}
+
+TEST_F(MessageTest, clearAdditionalSection) {
+ // Add two RRsets, check they are present, clear the section,
+ // check if they are gone.
+ message_render.addRRset(Message::SECTION_ADDITIONAL, rrset_a);
+ message_render.addRRset(Message::SECTION_ADDITIONAL, rrset_aaaa);
+ ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
+ RRClass::IN(), RRType::A()));
+ ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
+ RRClass::IN(), RRType::AAAA()));
+ ASSERT_EQ(4, message_render.getRRCount(Message::SECTION_ADDITIONAL));
+
+ message_render.clearSection(Message::SECTION_ADDITIONAL);
+ EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
+ RRClass::IN(), RRType::A()));
+ EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
+ RRClass::IN(), RRType::AAAA()));
+ EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ADDITIONAL));
+}
+
+TEST_F(MessageTest, badClearSection) {
+ // attempt of clearing a message in the parse mode.
+ EXPECT_THROW(message_parse.clearSection(Message::SECTION_QUESTION),
+ InvalidMessageOperation);
+ // attempt of clearing out-of-range section
+ EXPECT_THROW(message_render.clearSection(bogus_section), OutOfRange);
+}
+
+TEST_F(MessageTest, badBeginSection) {
+ // valid cases are tested via other tests
+ EXPECT_THROW(message_render.beginSection(Message::SECTION_QUESTION),
+ InvalidMessageSection);
+ EXPECT_THROW(message_render.beginSection(bogus_section), OutOfRange);
+}
+
+TEST_F(MessageTest, badEndSection) {
+ // valid cases are tested via other tests
+ EXPECT_THROW(message_render.endSection(Message::SECTION_QUESTION),
+ InvalidMessageSection);
+ EXPECT_THROW(message_render.endSection(bogus_section), OutOfRange);
+}
+
+TEST_F(MessageTest, appendSection) {
+ Message target(Message::RENDER);
+
+ // Section check
+ EXPECT_THROW(target.appendSection(bogus_section, message_render),
+ OutOfRange);
+
+ // Make sure nothing is copied if there is nothing to copy
+ target.appendSection(Message::SECTION_QUESTION, message_render);
+ EXPECT_EQ(0, target.getRRCount(Message::SECTION_QUESTION));
+ target.appendSection(Message::SECTION_ANSWER, message_render);
+ EXPECT_EQ(0, target.getRRCount(Message::SECTION_ANSWER));
+ target.appendSection(Message::SECTION_AUTHORITY, message_render);
+ EXPECT_EQ(0, target.getRRCount(Message::SECTION_AUTHORITY));
+ target.appendSection(Message::SECTION_ADDITIONAL, message_render);
+ EXPECT_EQ(0, target.getRRCount(Message::SECTION_ADDITIONAL));
+
+ // Now add some data, copy again, and see if it got added
+ message_render.addQuestion(Question(Name("test.example.com"),
+ RRClass::IN(), RRType::A()));
+ message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
+ message_render.addRRset(Message::SECTION_AUTHORITY, rrset_a);
+ message_render.addRRset(Message::SECTION_ADDITIONAL, rrset_a);
+ message_render.addRRset(Message::SECTION_ADDITIONAL, rrset_aaaa);
+
+ target.appendSection(Message::SECTION_QUESTION, message_render);
+ EXPECT_EQ(1, target.getRRCount(Message::SECTION_QUESTION));
+
+ target.appendSection(Message::SECTION_ANSWER, message_render);
+ EXPECT_EQ(2, target.getRRCount(Message::SECTION_ANSWER));
+ EXPECT_TRUE(target.hasRRset(Message::SECTION_ANSWER, test_name,
+ RRClass::IN(), RRType::A()));
+
+ target.appendSection(Message::SECTION_AUTHORITY, message_render);
+ EXPECT_EQ(2, target.getRRCount(Message::SECTION_AUTHORITY));
+ EXPECT_TRUE(target.hasRRset(Message::SECTION_AUTHORITY, test_name,
+ RRClass::IN(), RRType::A()));
+
+ target.appendSection(Message::SECTION_ADDITIONAL, message_render);
+ EXPECT_EQ(4, target.getRRCount(Message::SECTION_ADDITIONAL));
+ EXPECT_TRUE(target.hasRRset(Message::SECTION_ADDITIONAL, test_name,
+ RRClass::IN(), RRType::A()));
+ EXPECT_TRUE(target.hasRRset(Message::SECTION_ADDITIONAL, test_name,
+ RRClass::IN(), RRType::AAAA()));
+
+ // One more test, test to see if the section gets added, not replaced
+ Message source2(Message::RENDER);
+ source2.addRRset(Message::SECTION_ANSWER, rrset_aaaa);
+ target.appendSection(Message::SECTION_ANSWER, source2);
+ EXPECT_EQ(4, target.getRRCount(Message::SECTION_ANSWER));
+ EXPECT_TRUE(target.hasRRset(Message::SECTION_ANSWER, test_name,
+ RRClass::IN(), RRType::A()));
+ EXPECT_TRUE(target.hasRRset(Message::SECTION_ANSWER, test_name,
+ RRClass::IN(), RRType::AAAA()));
+}
+
+TEST_F(MessageTest, parseHeader) {
+ received_data.clear();
+ UnitTestUtil::readWireData("message_fromWire1", received_data);
+
+ // parseHeader() isn't allowed in the render mode.
+ InputBuffer buffer(&received_data[0], received_data.size());
+ EXPECT_THROW(message_render.parseHeader(buffer), InvalidMessageOperation);
+
+ message_parse.parseHeader(buffer);
+ EXPECT_EQ(0x1035, message_parse.getQid());
+ EXPECT_EQ(Opcode::QUERY(), message_parse.getOpcode());
+ EXPECT_EQ(Rcode::NOERROR(), message_parse.getRcode());
+ EXPECT_TRUE(message_parse.getHeaderFlag(Message::HEADERFLAG_QR));
+ EXPECT_TRUE(message_parse.getHeaderFlag(Message::HEADERFLAG_AA));
+ EXPECT_FALSE(message_parse.getHeaderFlag(Message::HEADERFLAG_TC));
+ EXPECT_TRUE(message_parse.getHeaderFlag(Message::HEADERFLAG_RD));
+ EXPECT_FALSE(message_parse.getHeaderFlag(Message::HEADERFLAG_RA));
+ EXPECT_FALSE(message_parse.getHeaderFlag(Message::HEADERFLAG_AD));
+ EXPECT_FALSE(message_parse.getHeaderFlag(Message::HEADERFLAG_CD));
+ EXPECT_EQ(1, message_parse.getRRCount(Message::SECTION_QUESTION));
+ EXPECT_EQ(2, message_parse.getRRCount(Message::SECTION_ANSWER));
+ EXPECT_EQ(0, message_parse.getRRCount(Message::SECTION_AUTHORITY));
+ EXPECT_EQ(0, message_parse.getRRCount(Message::SECTION_ADDITIONAL));
+
+ // Only the header part should have been examined.
+ EXPECT_EQ(12, buffer.getPosition()); // 12 = size of the header section
+ EXPECT_TRUE(message_parse.beginQuestion() == message_parse.endQuestion());
+ EXPECT_TRUE(message_parse.beginSection(Message::SECTION_ANSWER) ==
+ message_parse.endSection(Message::SECTION_ANSWER));
+ EXPECT_TRUE(message_parse.beginSection(Message::SECTION_AUTHORITY) ==
+ message_parse.endSection(Message::SECTION_AUTHORITY));
+ EXPECT_TRUE(message_parse.beginSection(Message::SECTION_ADDITIONAL) ==
+ message_parse.endSection(Message::SECTION_ADDITIONAL));
+}
+
+void
+checkMessageFromWire(const Message& message_parse,
+ const Name& test_name)
+{
+ EXPECT_EQ(0x1035, message_parse.getQid());
+ EXPECT_EQ(Opcode::QUERY(), message_parse.getOpcode());
+ EXPECT_EQ(Rcode::NOERROR(), message_parse.getRcode());
+ EXPECT_TRUE(message_parse.getHeaderFlag(Message::HEADERFLAG_QR));
+ EXPECT_TRUE(message_parse.getHeaderFlag(Message::HEADERFLAG_RD));
+ EXPECT_TRUE(message_parse.getHeaderFlag(Message::HEADERFLAG_AA));
+
+ QuestionPtr q = *message_parse.beginQuestion();
+ EXPECT_EQ(test_name, q->getName());
+ EXPECT_EQ(RRType::A(), q->getType());
+ EXPECT_EQ(RRClass::IN(), q->getClass());
+ EXPECT_EQ(1, message_parse.getRRCount(Message::SECTION_QUESTION));
+ EXPECT_EQ(2, message_parse.getRRCount(Message::SECTION_ANSWER));
+ EXPECT_EQ(0, message_parse.getRRCount(Message::SECTION_AUTHORITY));
+ EXPECT_EQ(0, message_parse.getRRCount(Message::SECTION_ADDITIONAL));
+
+ RRsetPtr rrset = *message_parse.beginSection(Message::SECTION_ANSWER);
+ EXPECT_EQ(test_name, rrset->getName());
+ EXPECT_EQ(RRType::A(), rrset->getType());
+ EXPECT_EQ(RRClass::IN(), rrset->getClass());
+ // TTL should be 3600, even though that of the 2nd RR is 7200
+ EXPECT_EQ(RRTTL(3600), rrset->getTTL());
+ RdataIteratorPtr it = rrset->getRdataIterator();
+ EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
+ it->next();
+ EXPECT_EQ("192.0.2.2", it->getCurrent().toText());
+ it->next();
+ EXPECT_TRUE(it->isLast());
+}
+
+
+TEST_F(MessageTest, fromWire) {
+ // fromWire() isn't allowed in the render mode.
+ EXPECT_THROW(factoryFromFile(message_render, "message_fromWire1"),
+ InvalidMessageOperation);
+
+ factoryFromFile(message_parse, "message_fromWire1");
+ checkMessageFromWire(message_parse, test_name);
+}
+
+TEST_F(MessageTest, fromWireMultiple) {
+ // Parse from wire multiple times.
+ factoryFromFile(message_parse, "message_fromWire1");
+ factoryFromFile(message_parse, "message_fromWire1");
+ factoryFromFile(message_parse, "message_fromWire1");
+ factoryFromFile(message_parse, "message_fromWire1");
+ checkMessageFromWire(message_parse, test_name);
+
+ // Calling parseHeader() directly before fromWire() should not cause
+ // any problems.
+ received_data.clear();
+ UnitTestUtil::readWireData("message_fromWire1", received_data);
+
+ InputBuffer buffer(&received_data[0], received_data.size());
+ message_parse.parseHeader(buffer);
+ message_parse.fromWire(buffer);
+ message_parse.parseHeader(buffer);
+ message_parse.fromWire(buffer);
+ checkMessageFromWire(message_parse, test_name);
+}
+
+TEST_F(MessageTest, fromWireShortBuffer) {
+ // We trim a valid message (ending with an SOA RR) for one byte.
+ // fromWire() should throw an exception while parsing the trimmed RR.
+ UnitTestUtil::readWireData("message_fromWire22.wire", received_data);
+ InputBuffer buffer(&received_data[0], received_data.size() - 1);
+ EXPECT_THROW(message_parse.fromWire(buffer), InvalidBufferPosition);
+}
+
+TEST_F(MessageTest, fromWireCombineRRs) {
+ // This message contains 3 RRs in the answer section in the order of
+ // A, AAAA, A types. fromWire() should combine the two A RRs into a
+ // single RRset by default.
+ factoryFromFile(message_parse, "message_fromWire19.wire");
+
+ RRsetIterator it = message_parse.beginSection(Message::SECTION_ANSWER);
+ RRsetIterator it_end = message_parse.endSection(Message::SECTION_ANSWER);
+ ASSERT_TRUE(it != it_end);
+ EXPECT_EQ(RRType::A(), (*it)->getType());
+ EXPECT_EQ(2, (*it)->getRdataCount());
+
+ ++it;
+ ASSERT_TRUE(it != it_end);
+ EXPECT_EQ(RRType::AAAA(), (*it)->getType());
+ EXPECT_EQ(1, (*it)->getRdataCount());
+}
+
+// A helper function for a test pattern commonly used in several tests below.
+void
+preserveRRCheck(const Message& message, Message::Section section) {
+ RRsetIterator it = message.beginSection(section);
+ RRsetIterator it_end = message.endSection(section);
+ ASSERT_TRUE(it != it_end);
+ EXPECT_EQ(RRType::A(), (*it)->getType());
+ EXPECT_EQ(1, (*it)->getRdataCount());
+ EXPECT_EQ("192.0.2.1", (*it)->getRdataIterator()->getCurrent().toText());
+
+ ++it;
+ ASSERT_TRUE(it != it_end);
+ EXPECT_EQ(RRType::AAAA(), (*it)->getType());
+ EXPECT_EQ(1, (*it)->getRdataCount());
+ EXPECT_EQ("2001:db8::1", (*it)->getRdataIterator()->getCurrent().toText());
+
+ ++it;
+ ASSERT_TRUE(it != it_end);
+ EXPECT_EQ(RRType::A(), (*it)->getType());
+ EXPECT_EQ(1, (*it)->getRdataCount());
+ EXPECT_EQ("192.0.2.2", (*it)->getRdataIterator()->getCurrent().toText());
+}
+
+TEST_F(MessageTest, fromWirePreserveAnswer) {
+ // Using the same data as the previous test, but specify the PRESERVE_ORDER
+ // option. The received order of RRs should be preserved, and each RR
+ // should be stored in a single RRset.
+ factoryFromFile(message_parse, "message_fromWire19.wire",
+ Message::PRESERVE_ORDER);
+ {
+ SCOPED_TRACE("preserve answer RRs");
+ preserveRRCheck(message_parse, Message::SECTION_ANSWER);
+ }
+}
+
+TEST_F(MessageTest, fromWirePreserveAuthority) {
+ // Same for the previous test, but for the authority section.
+ factoryFromFile(message_parse, "message_fromWire20.wire",
+ Message::PRESERVE_ORDER);
+ {
+ SCOPED_TRACE("preserve authority RRs");
+ preserveRRCheck(message_parse, Message::SECTION_AUTHORITY);
+ }
+}
+
+TEST_F(MessageTest, fromWirePreserveAdditional) {
+ // Same for the previous test, but for the additional section.
+ factoryFromFile(message_parse, "message_fromWire21.wire",
+ Message::PRESERVE_ORDER);
+ {
+ SCOPED_TRACE("preserve additional RRs");
+ preserveRRCheck(message_parse, Message::SECTION_ADDITIONAL);
+ }
+}
+
+TEST_F(MessageTest, EDNS0ExtRcode) {
+ // Extended Rcode = BADVERS
+ factoryFromFile(message_parse, "message_fromWire10.wire");
+ EXPECT_EQ(Rcode::BADVERS(), message_parse.getRcode());
+
+ // Maximum extended Rcode
+ message_parse.clear(Message::PARSE);
+ factoryFromFile(message_parse, "message_fromWire11.wire");
+ EXPECT_EQ(0xfff, message_parse.getRcode().getCode());
+}
+
+TEST_F(MessageTest, BadEDNS0) {
+ // OPT RR in the answer section
+ EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire4"),
+ DNSMessageFORMERR);
+ // multiple OPT RRs (in the additional section)
+ message_parse.clear(Message::PARSE);
+ EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire5"),
+ DNSMessageFORMERR);
+}
+
+TEST_F(MessageTest, toWire) {
+ message_render.setQid(0x1035);
+ message_render.setOpcode(Opcode::QUERY());
+ message_render.setRcode(Rcode::NOERROR());
+ message_render.setHeaderFlag(Message::HEADERFLAG_QR, true);
+ message_render.setHeaderFlag(Message::HEADERFLAG_RD, true);
+ message_render.setHeaderFlag(Message::HEADERFLAG_AA, true);
+ message_render.addQuestion(Question(Name("test.example.com"), RRClass::IN(),
+ RRType::A()));
+ message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
+
+ EXPECT_EQ(1, message_render.getRRCount(Message::SECTION_QUESTION));
+ EXPECT_EQ(2, message_render.getRRCount(Message::SECTION_ANSWER));
+ EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_AUTHORITY));
+ EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ADDITIONAL));
+
+ message_render.toWire(renderer);
+ vector<unsigned char> data;
+ UnitTestUtil::readWireData("message_toWire1", data);
+ matchWireData(&data[0], data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(MessageTest, toWireSigned) {
+ message_render.setQid(0x75c1);
+ message_render.setOpcode(Opcode::QUERY());
+ message_render.setRcode(Rcode::NOERROR());
+ message_render.setHeaderFlag(Message::HEADERFLAG_QR, true);
+ message_render.setHeaderFlag(Message::HEADERFLAG_RD, true);
+ message_render.setHeaderFlag(Message::HEADERFLAG_AA, true);
+ message_render.addQuestion(Question(Name("test.example.com"), RRClass::IN(),
+ RRType::A()));
+
+ rrset_rrsig = RRsetPtr(new RRset(test_name, RRClass::IN(),
+ RRType::RRSIG(), RRTTL(3600)));
+ // one signature algorithm (5 = RSA/SHA-1)
+ rrset_rrsig->addRdata(generic::RRSIG("A 5 3 3600 "
+ "20000101000000 20000201000000 "
+ "12345 example.com. FAKEFAKEFAKE"));
+ // another signature algorithm (3 = DSA/SHA-1)
+ rrset_rrsig->addRdata(generic::RRSIG("A 3 3 3600 "
+ "20000101000000 20000201000000 "
+ "12345 example.com. FAKEFAKEFAKE"));
+ rrset_a->addRRsig(rrset_rrsig);
+ EXPECT_EQ(2, rrset_a->getRRsigDataCount());
+
+ message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
+
+ EXPECT_EQ(1, message_render.getRRCount(Message::SECTION_QUESTION));
+ EXPECT_EQ(4, message_render.getRRCount(Message::SECTION_ANSWER));
+ EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_AUTHORITY));
+ EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ADDITIONAL));
+
+ message_render.toWire(renderer);
+ vector<unsigned char> data;
+ UnitTestUtil::readWireData("message_toWire6", data);
+ matchWireData(&data[0], data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(MessageTest, toWireSignedAndTruncated) {
+ message_render.setQid(0x75c1);
+ message_render.setOpcode(Opcode::QUERY());
+ message_render.setRcode(Rcode::NOERROR());
+ message_render.setHeaderFlag(Message::HEADERFLAG_QR, true);
+ message_render.setHeaderFlag(Message::HEADERFLAG_RD, true);
+ message_render.setHeaderFlag(Message::HEADERFLAG_AA, true);
+ message_render.addQuestion(Question(Name("test.example.com"), RRClass::IN(),
+ RRType::TXT()));
+
+ RRsetPtr rrset_txt = RRsetPtr(new RRset(test_name, RRClass::IN(),
+ RRType::TXT(), RRTTL(3600)));
+ rrset_txt->addRdata(generic::TXT(string(255, 'a')));
+ rrset_txt->addRdata(generic::TXT(string(255, 'b')));
+ rrset_txt->addRdata(generic::TXT(string(255, 'c')));
+ rrset_txt->addRdata(generic::TXT(string(255, 'd')));
+ rrset_txt->addRdata(generic::TXT(string(255, 'e')));
+ rrset_txt->addRdata(generic::TXT(string(255, 'f')));
+ rrset_txt->addRdata(generic::TXT(string(255, 'g')));
+ rrset_txt->addRdata(generic::TXT(string(255, 'h')));
+
+ rrset_rrsig = RRsetPtr(new RRset(test_name, RRClass::IN(),
+ RRType::RRSIG(), RRTTL(3600)));
+ // one signature algorithm (5 = RSA/SHA-1)
+ rrset_rrsig->addRdata(generic::RRSIG("TXT 5 3 3600 "
+ "20000101000000 20000201000000 "
+ "12345 example.com. FAKEFAKEFAKE"));
+ rrset_txt->addRRsig(rrset_rrsig);
+ EXPECT_EQ(1, rrset_txt->getRRsigDataCount());
+
+ message_render.addRRset(Message::SECTION_ANSWER, rrset_txt);
+
+ EXPECT_EQ(1, message_render.getRRCount(Message::SECTION_QUESTION));
+ EXPECT_EQ(9, message_render.getRRCount(Message::SECTION_ANSWER));
+ EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_AUTHORITY));
+ EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ADDITIONAL));
+
+ message_render.toWire(renderer);
+ vector<unsigned char> data;
+ UnitTestUtil::readWireData("message_toWire7", data);
+ matchWireData(&data[0], data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(MessageTest, toWireInParseMode) {
+ // toWire() isn't allowed in the parse mode.
+ EXPECT_THROW(message_parse.toWire(renderer), InvalidMessageOperation);
+}
+
+// See dnssectime_unittest.cc
+template <int64_t NOW>
+int64_t
+testGetTime() {
+ return (NOW);
+}
+
+// bit-wise constant flags to configure DNS header flags for test
+// messages.
+const unsigned int QR_FLAG = 0x1;
+const unsigned int AA_FLAG = 0x2;
+const unsigned int RD_FLAG = 0x4;
+
+void
+commonTSIGToWireCheck(Message& message, MessageRenderer& renderer,
+ TSIGContext& tsig_ctx, const char* const expected_file,
+ unsigned int message_flags = RD_FLAG,
+ RRType qtype = RRType::A(),
+ const vector<const char*>* answer_data = NULL) {
+ message.setOpcode(Opcode::QUERY());
+ message.setRcode(Rcode::NOERROR());
+ if ((message_flags & QR_FLAG) != 0) {
+ message.setHeaderFlag(Message::HEADERFLAG_QR);
+ }
+ if ((message_flags & AA_FLAG) != 0) {
+ message.setHeaderFlag(Message::HEADERFLAG_AA);
+ }
+ if ((message_flags & RD_FLAG) != 0) {
+ message.setHeaderFlag(Message::HEADERFLAG_RD);
+ }
+ message.addQuestion(Question(Name("www.example.com"), RRClass::IN(),
+ qtype));
+
+ if (answer_data != NULL) {
+ RRsetPtr ans_rrset(new RRset(Name("www.example.com"), RRClass::IN(),
+ qtype, RRTTL(86400)));
+ for (auto const& it : *answer_data) {
+ ans_rrset->addRdata(createRdata(qtype, RRClass::IN(), it));
+ }
+ message.addRRset(Message::SECTION_ANSWER, ans_rrset);
+ }
+
+ message.toWire(renderer, &tsig_ctx);
+ vector<unsigned char> expected_data;
+ UnitTestUtil::readWireData(expected_file, expected_data);
+ matchWireData(&expected_data[0], expected_data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(MessageTest, toWireWithTSIG) {
+ // Rendering a message with TSIG. Various special cases specific to
+ // TSIG are tested in the tsig tests. We only check the message contains
+ // a TSIG at the end and the ARCOUNT of the header is updated.
+
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ message_render.setQid(0x2d65);
+
+ {
+ SCOPED_TRACE("Message sign with TSIG");
+ commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
+ "message_toWire2.wire");
+ }
+}
+
+TEST_F(MessageTest, toWireWithEDNSAndTSIG) {
+ // Similar to the previous test, but with an EDNS before TSIG.
+ // The wire data check will confirm the ordering.
+ isc::util::detail::gettimeFunction = testGetTime<0x4db60d1f>;
+
+ message_render.setQid(0x6cd);
+
+ EDNSPtr edns(new EDNS());
+ edns->setUDPSize(4096);
+ message_render.setEDNS(edns);
+
+ {
+ SCOPED_TRACE("Message sign with TSIG and EDNS");
+ commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
+ "message_toWire3.wire");
+ }
+}
+
+// Some of the following tests involve truncation. We use the query name
+// "www.example.com" and some TXT question/answers. The length of the
+// header and question will be 33 bytes. If we also try to include a
+// TSIG of the same key name (not compressed) with HMAC-MD5, the TSIG RR
+// will be 85 bytes.
+
+// A long TXT RDATA. With a fully compressed owner name, the corresponding
+// RR will be 268 bytes.
+const char* const long_txt1 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde";
+
+// With a fully compressed owner name, the corresponding RR will be 212 bytes.
+// It should result in truncation even without TSIG (33 + 268 + 212 = 513)
+const char* const long_txt2 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456";
+
+// With a fully compressed owner name, the corresponding RR will be 127 bytes.
+// So, it can fit in the standard 512 bytes with txt1 and without TSIG, but
+// adding a TSIG would result in truncation (33 + 268 + 127 + 85 = 513)
+const char* const long_txt3 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01";
+
+// This is 1 byte shorter than txt3, which will result in a possible longest
+// message containing answer RRs and TSIG.
+const char* const long_txt4 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0";
+
+// Example output generated by
+// "dig -y www.example.com:SFuWd/q99SzF8Yzd1QbB9g== www.example.com txt
+// QID: 0x22c2
+// Time Signed: 0x00004e179212
+TEST_F(MessageTest, toWireTSIGTruncation) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4e179212>;
+
+ // Verify a validly signed query so that we can use the TSIG context
+
+ factoryFromFile(message_parse, "message_fromWire17.wire");
+ EXPECT_EQ(TSIGError::NOERROR(),
+ tsig_ctx.verify(message_parse.getTSIGRecord(),
+ &received_data[0], received_data.size()));
+
+ message_render.setQid(0x22c2);
+ vector<const char*> answer_data;
+ answer_data.push_back(long_txt1);
+ answer_data.push_back(long_txt2);
+ {
+ SCOPED_TRACE("Message sign with TSIG and TC bit on");
+ commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
+ "message_toWire4.wire",
+ QR_FLAG|AA_FLAG|RD_FLAG,
+ RRType::TXT(), &answer_data);
+ }
+}
+
+TEST_F(MessageTest, toWireTSIGTruncation2) {
+ // Similar to the previous test, but without TSIG it wouldn't cause
+ // truncation.
+ isc::util::detail::gettimeFunction = testGetTime<0x4e179212>;
+ factoryFromFile(message_parse, "message_fromWire17.wire");
+ EXPECT_EQ(TSIGError::NOERROR(),
+ tsig_ctx.verify(message_parse.getTSIGRecord(),
+ &received_data[0], received_data.size()));
+
+ message_render.setQid(0x22c2);
+ vector<const char*> answer_data;
+ answer_data.push_back(long_txt1);
+ answer_data.push_back(long_txt3);
+ {
+ SCOPED_TRACE("Message sign with TSIG and TC bit on (2)");
+ commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
+ "message_toWire4.wire",
+ QR_FLAG|AA_FLAG|RD_FLAG,
+ RRType::TXT(), &answer_data);
+ }
+}
+
+TEST_F(MessageTest, toWireTSIGTruncation3) {
+ // Similar to previous ones, but truncation occurs due to too many
+ // Questions (very unusual, but not necessarily illegal).
+
+ // We are going to create a message starting with a standard
+ // header (12 bytes) and multiple questions in the Question
+ // section of the same owner name (changing the RRType, just so
+ // that it would be the form that would be accepted by the BIND 9
+ // parser). The first Question is 21 bytes in length, and the subsequent
+ // ones are 6 bytes. We'll also use a TSIG whose size is 85 bytes.
+ // Up to 66 questions can fit in the standard 512-byte buffer
+ // (12 + 21 + 6 * 65 + 85 = 508). If we try to add one more it would
+ // result in truncation.
+ message_render.setOpcode(Opcode::QUERY());
+ message_render.setRcode(Rcode::NOERROR());
+ for (int i = 1; i <= 67; ++i) {
+ message_render.addQuestion(Question(Name("www.example.com"),
+ RRClass::IN(), RRType(i)));
+ }
+ message_render.toWire(renderer, &tsig_ctx);
+
+ // Check the rendered data by parsing it. We only check it has the
+ // TC bit on, has the correct number of questions, and has a TSIG RR.
+ // Checking the signature wouldn't be necessary for this rare case
+ // scenario.
+ InputBuffer buffer(renderer.getData(), renderer.getLength());
+ message_parse.fromWire(buffer);
+ EXPECT_TRUE(message_parse.getHeaderFlag(Message::HEADERFLAG_TC));
+ // Note that the number of questions are 66, not 67 as we tried to add.
+ EXPECT_EQ(66, message_parse.getRRCount(Message::SECTION_QUESTION));
+ EXPECT_TRUE(message_parse.getTSIGRecord() != NULL);
+}
+
+TEST_F(MessageTest, toWireTSIGNoTruncation) {
+ // A boundary case that shouldn't cause truncation: the resulting
+ // response message with a TSIG will be 512 bytes long.
+ isc::util::detail::gettimeFunction = testGetTime<0x4e17b38d>;
+ factoryFromFile(message_parse, "message_fromWire18.wire");
+ EXPECT_EQ(TSIGError::NOERROR(),
+ tsig_ctx.verify(message_parse.getTSIGRecord(),
+ &received_data[0], received_data.size()));
+
+ message_render.setQid(0xd6e2);
+ vector<const char*> answer_data;
+ answer_data.push_back(long_txt1);
+ answer_data.push_back(long_txt4);
+ {
+ SCOPED_TRACE("Message sign with TSIG, no truncation");
+ commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
+ "message_toWire5.wire",
+ QR_FLAG|AA_FLAG|RD_FLAG,
+ RRType::TXT(), &answer_data);
+ }
+}
+
+// This is a buggy renderer for testing. It behaves like the straightforward
+// MessageRenderer, but once it has some data, its setLengthLimit() ignores
+// the given parameter and resets the limit to the current length, making
+// subsequent insertion result in truncation, which would make TSIG RR
+// rendering fail unexpectedly in the test that follows.
+class BadRenderer : public MessageRenderer {
+public:
+ virtual void setLengthLimit(size_t len) {
+ if (getLength() > 0) {
+ MessageRenderer::setLengthLimit(getLength());
+ } else {
+ MessageRenderer::setLengthLimit(len);
+ }
+ }
+};
+
+TEST_F(MessageTest, toWireTSIGLengthErrors) {
+ // specify an unusual short limit that wouldn't be able to hold
+ // the TSIG.
+ renderer.setLengthLimit(tsig_ctx.getTSIGLength() - 1);
+ // Use commonTSIGToWireCheck() only to call toWire() with otherwise valid
+ // conditions. The checks inside it don't matter because we expect an
+ // exception before any of the checks.
+ EXPECT_THROW(commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
+ "message_toWire2.wire"),
+ InvalidParameter);
+
+ // This one is large enough for TSIG, but the remaining limit isn't
+ // even enough for the Header section.
+ renderer.clear();
+ message_render.clear(Message::RENDER);
+ renderer.setLengthLimit(tsig_ctx.getTSIGLength() + 1);
+ EXPECT_THROW(commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
+ "message_toWire2.wire"),
+ InvalidParameter);
+
+ // Trying to render a message with TSIG using a buggy renderer.
+ BadRenderer bad_renderer;
+ bad_renderer.setLengthLimit(512);
+ message_render.clear(Message::RENDER);
+ EXPECT_THROW(commonTSIGToWireCheck(message_render, bad_renderer, tsig_ctx,
+ "message_toWire2.wire"),
+ Unexpected);
+}
+
+TEST_F(MessageTest, toWireWithoutOpcode) {
+ message_render.setRcode(Rcode::NOERROR());
+ EXPECT_THROW(message_render.toWire(renderer), InvalidMessageOperation);
+}
+
+TEST_F(MessageTest, toWireWithoutRcode) {
+ message_render.setOpcode(Opcode::QUERY());
+ EXPECT_THROW(message_render.toWire(renderer), InvalidMessageOperation);
+}
+
+TEST_F(MessageTest, toText) {
+ // Check toText() output for a typical DNS response with records in
+ // all sections
+
+ factoryFromFile(message_parse, "message_toText1.wire");
+ {
+ SCOPED_TRACE("Message toText test (basic case)");
+ ifstream ifs;
+ unittests::openTestData("message_toText1.txt", ifs);
+ unittests::matchTextData(ifs, message_parse.toText());
+ }
+
+ // Another example with EDNS. The expected data was slightly modified
+ // from the dig output (other than replacing tabs with a space): adding
+ // a newline after the "OPT PSEUDOSECTION". This is an intentional change
+ // in our version for better readability.
+ message_parse.clear(Message::PARSE);
+ factoryFromFile(message_parse, "message_toText2.wire");
+ {
+ SCOPED_TRACE("Message toText test with EDNS");
+ ifstream ifs;
+ unittests::openTestData("message_toText2.txt", ifs);
+ unittests::matchTextData(ifs, message_parse.toText());
+ }
+
+ // Another example with TSIG. The expected data was slightly modified
+ // from the dig output (other than replacing tabs with a space): removing
+ // a redundant white space at the end of TSIG RDATA. We'd rather consider
+ // it a dig's defect than a feature.
+ message_parse.clear(Message::PARSE);
+ factoryFromFile(message_parse, "message_toText3.wire");
+ {
+ SCOPED_TRACE("Message toText test with TSIG");
+ ifstream ifs;
+ unittests::openTestData("message_toText3.txt", ifs);
+ unittests::matchTextData(ifs, message_parse.toText());
+ }
+}
+
+TEST_F(MessageTest, toTextWithoutOpcode) {
+ message_render.setRcode(Rcode::NOERROR());
+ EXPECT_THROW(message_render.toText(), InvalidMessageOperation);
+}
+
+TEST_F(MessageTest, toTextWithoutRcode) {
+ message_render.setOpcode(Opcode::QUERY());
+ EXPECT_THROW(message_render.toText(), InvalidMessageOperation);
+}
+}
diff --git a/src/lib/dns/tests/messagerenderer_unittest.cc b/src/lib/dns/tests/messagerenderer_unittest.cc
index 8b13789179..c3a53eb6ca 100644
--- a/src/lib/dns/tests/messagerenderer_unittest.cc
+++ b/src/lib/dns/tests/messagerenderer_unittest.cc
@@ -1 +1,292 @@
+// Copyright (C) 2009-2017 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <exceptions/exceptions.h>
+#include <util/buffer.h>
+#include <dns/name.h>
+#include <dns/labelsequence.h>
+#include <dns/messagerenderer.h>
+
+#include <dns/tests/unittest_util.h>
+#include <util/unittests/wiredata.h>
+
+#include <gtest/gtest.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include <string>
+#include <vector>
+
+using isc::UnitTestUtil;
+using isc::dns::Name;
+using isc::dns::LabelSequence;
+using isc::dns::MessageRenderer;
+using isc::util::OutputBuffer;
+using boost::lexical_cast;
+using isc::util::unittests::matchWireData;
+
+namespace {
+class MessageRendererTest : public ::testing::Test {
+protected:
+ MessageRendererTest() : expected_size(0) {
+ data16 = (2 << 8) | 3;
+ data32 = (4 << 24) | (5 << 16) | (6 << 8) | 7;
+ }
+ size_t expected_size;
+ uint16_t data16;
+ uint32_t data32;
+ MessageRenderer renderer;
+ std::vector<unsigned char> data;
+ static const uint8_t testdata[5];
+};
+
+const uint8_t MessageRendererTest::testdata[5] = {1, 2, 3, 4, 5};
+
+// The test cases are borrowed from those for the OutputBuffer class.
+TEST_F(MessageRendererTest, writeInteger) {
+ renderer.writeUint16(data16);
+ expected_size += sizeof(data16);
+
+ matchWireData(&testdata[1], sizeof(data16),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(MessageRendererTest, writeName) {
+ UnitTestUtil::readWireData("name_toWire1", data);
+ renderer.writeName(Name("a.example.com."));
+ renderer.writeName(Name("b.example.com."));
+ renderer.writeName(Name("a.example.org."));
+ matchWireData(&data[0], data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(MessageRendererTest, writeNameInLargeBuffer) {
+ size_t offset = 0x3fff;
+ renderer.skip(offset);
+
+ UnitTestUtil::readWireData("name_toWire2", data);
+ renderer.writeName(Name("a.example.com."));
+ renderer.writeName(Name("a.example.com."));
+ renderer.writeName(Name("b.example.com."));
+ matchWireData(&data[0], data.size(),
+ static_cast<const uint8_t*>(renderer.getData()) + offset,
+ renderer.getLength() - offset);
+}
+
+TEST_F(MessageRendererTest, writeNameWithUncompressed) {
+ UnitTestUtil::readWireData("name_toWire3", data);
+ renderer.writeName(Name("a.example.com."));
+ renderer.writeName(Name("b.example.com."), false);
+ renderer.writeName(Name("b.example.com."));
+ matchWireData(&data[0], data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(MessageRendererTest, writeNamePointerChain) {
+ UnitTestUtil::readWireData("name_toWire4", data);
+ renderer.writeName(Name("a.example.com."));
+ renderer.writeName(Name("b.example.com."));
+ renderer.writeName(Name("b.example.com."));
+ matchWireData(&data[0], data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(MessageRendererTest, compressMode) {
+ // By default the render performs case insensitive compression.
+ EXPECT_EQ(MessageRenderer::CASE_INSENSITIVE, renderer.getCompressMode());
+
+ // The mode can be explicitly changed.
+ renderer.setCompressMode(MessageRenderer::CASE_SENSITIVE);
+ EXPECT_EQ(MessageRenderer::CASE_SENSITIVE, renderer.getCompressMode());
+ renderer.setCompressMode(MessageRenderer::CASE_INSENSITIVE);
+ EXPECT_EQ(MessageRenderer::CASE_INSENSITIVE, renderer.getCompressMode());
+
+ // The clear() method resets the mode to the default.
+ renderer.setCompressMode(MessageRenderer::CASE_SENSITIVE);
+ renderer.clear();
+ EXPECT_EQ(MessageRenderer::CASE_INSENSITIVE, renderer.getCompressMode());
+}
+
+TEST_F(MessageRendererTest, writeNameCaseCompress) {
+ // By default MessageRenderer performs case insensitive compression.
+
+ UnitTestUtil::readWireData("name_toWire1", data);
+ renderer.writeName(Name("a.example.com."));
+ // this should match the first name in terms of compression:
+ renderer.writeName(Name("b.exAmple.CoM."));
+ renderer.writeName(Name("a.example.org."));
+ matchWireData(&data[0], data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(MessageRendererTest, writeNameCaseSensitiveCompress) {
+ // name compression in case sensitive manner. See the data file
+ // description for details.
+ renderer.setCompressMode(MessageRenderer::CASE_SENSITIVE);
+ UnitTestUtil::readWireData("name_toWire5.wire", data);
+ renderer.writeName(Name("a.example.com."));
+ renderer.writeName(Name("b.eXample.com."));
+ renderer.writeName(Name("c.eXample.com."));
+ matchWireData(&data[0], data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(MessageRendererTest, writeNameMixedCaseCompress) {
+ renderer.setCompressMode(MessageRenderer::CASE_SENSITIVE);
+ UnitTestUtil::readWireData("name_toWire6.wire", data);
+ renderer.writeName(Name("a.example.com."));
+ renderer.writeName(Name("b.eXample.com."));
+
+ // Change the compression mode in the middle of rendering. This is not
+ // allowed in this implementation.
+ EXPECT_THROW(renderer.setCompressMode(MessageRenderer::CASE_INSENSITIVE),
+ isc::InvalidParameter);
+
+ // Once the renderer is cleared, it's okay again.
+ renderer.clear();
+ EXPECT_NO_THROW(renderer.setCompressMode(
+ MessageRenderer::CASE_INSENSITIVE));
+}
+
+TEST_F(MessageRendererTest, writeRootName) {
+ // root name is special: it never causes compression or can (reasonably)
+ // be a compression pointer. So it makes sense to check this case
+ // explicitly.
+ Name example_name = Name("www.example.com");
+
+ OutputBuffer expected(0);
+ expected.writeUint8(0); // root name
+ example_name.toWire(expected);
+
+ renderer.writeName(Name("."));
+ renderer.writeName(example_name);
+ matchWireData(static_cast<const uint8_t*>(expected.getData()),
+ expected.getLength(),
+ static_cast<const uint8_t*>(renderer.getData()),
+ renderer.getLength());
+}
+
+TEST_F(MessageRendererTest, writeNameLabelSequence1) {
+ UnitTestUtil::readWireData("name_toWire7", data);
+
+ Name n1("a.example.com");
+ LabelSequence ls1(n1);
+
+ // a.example.com.
+ renderer.writeName(ls1);
+
+ ls1.stripLeft(1);
+
+ // example.com.
+ renderer.writeName(ls1);
+
+ matchWireData(&data[0], data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(MessageRendererTest, writeNameLabelSequence2) {
+ UnitTestUtil::readWireData("name_toWire8", data);
+
+ Name n1("a.example.com");
+ LabelSequence ls1(n1);
+
+ ls1.stripRight(1);
+
+ // a.example.com (without root .)
+ renderer.writeName(ls1);
+
+ matchWireData(&data[0], data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(MessageRendererTest, writeNameLabelSequence3) {
+ UnitTestUtil::readWireData("name_toWire9", data);
+
+ Name n1("a.example.com");
+ LabelSequence ls1(n1);
+
+ // a.example.com.
+ renderer.writeName(ls1);
+
+ ls1.stripRight(1);
+
+ // a.example.com (without root .)
+ renderer.writeName(ls1);
+
+ ls1.stripRight(1);
+
+ // a.example
+ renderer.writeName(ls1);
+
+ ls1.stripLeft(1);
+
+ // example
+ renderer.writeName(ls1);
+
+ matchWireData(&data[0], data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(MessageRendererTest, setBuffer) {
+ OutputBuffer new_buffer(0);
+ renderer.setBuffer(&new_buffer);
+ EXPECT_EQ(0, new_buffer.getLength()); // the buffer should be still empty
+ renderer.writeUint32(42);
+ EXPECT_EQ(sizeof(uint32_t), new_buffer.getLength());
+ EXPECT_EQ(sizeof(uint32_t), renderer.getLength());
+
+ // Change some other internal state for the reset test below.
+ EXPECT_EQ(512, renderer.getLengthLimit());
+ renderer.setLengthLimit(4096);
+ EXPECT_EQ(4096, renderer.getLengthLimit());
+
+ // Reset the buffer to the default again. Other internal states and
+ // resources should be cleared. The used buffer should be intact.
+ renderer.setBuffer(NULL);
+ EXPECT_EQ(sizeof(uint32_t), new_buffer.getLength());
+ EXPECT_EQ(0, renderer.getLength());
+ EXPECT_EQ(512, renderer.getLengthLimit());
+}
+
+TEST_F(MessageRendererTest, setBufferErrors) {
+ OutputBuffer new_buffer(0);
+
+ // Buffer cannot be reset when the renderer is in use.
+ renderer.writeUint32(10);
+ EXPECT_THROW(renderer.setBuffer(&new_buffer), isc::InvalidParameter);
+
+ renderer.clear();
+ renderer.setBuffer(&new_buffer);
+ renderer.writeUint32(10);
+ EXPECT_THROW(renderer.setBuffer(&new_buffer), isc::InvalidParameter);
+
+ // Resetting the buffer isn't allowed for the default buffer.
+ renderer.setBuffer(NULL);
+ EXPECT_THROW(renderer.setBuffer(NULL), isc::InvalidParameter);
+
+ // It's okay to reset a temporary buffer without using it.
+ renderer.setBuffer(&new_buffer);
+ EXPECT_NO_THROW(renderer.setBuffer(NULL));
+}
+
+TEST_F(MessageRendererTest, manyRRs) {
+ // Render a large number of names, and the confirm the resulting wire
+ // data store the expected names in the correct order (1000 is an
+ // arbitrary choice).
+ for (size_t i = 0; i < 1000; ++i) {
+ renderer.writeName(Name(lexical_cast<std::string>(i) + ".example"));
+ }
+ isc::util::InputBuffer b(renderer.getData(), renderer.getLength());
+ for (size_t i = 0; i < 1000; ++i) {
+ EXPECT_EQ(Name(lexical_cast<std::string>(i) + ".example"), Name(b));
+ }
+ // This will trigger trimming excessive hash items. It shouldn't cause
+ // any disruption.
+ EXPECT_NO_THROW(renderer.clear());
+}
+}
diff --git a/src/lib/dns/tests/name_unittest.cc b/src/lib/dns/tests/name_unittest.cc
index 8b13789179..636a403f38 100644
--- a/src/lib/dns/tests/name_unittest.cc
+++ b/src/lib/dns/tests/name_unittest.cc
@@ -1 +1,794 @@
+// Copyright (C) 2009-2024 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <vector>
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <limits>
+#include <stdexcept>
+
+#include <util/buffer.h>
+#include <dns/exceptions.h>
+#include <dns/name.h>
+#include <dns/messagerenderer.h>
+
+#include <dns/tests/unittest_util.h>
+#include <util/unittests/wiredata.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+using namespace isc::util;
+using isc::util::unittests::matchWireData;
+
+//
+// XXX: these are defined as class static constants, but some compilers
+// seemingly cannot find the symbols when used in the EXPECT_xxx macros.
+//
+const size_t Name::MAX_WIRE;
+const size_t Name::MAX_LABELS;
+
+// This is a name of maximum allowed number of labels
+const char* max_labels_str = "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 40
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 80
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 120
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 160
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 200
+ "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 240
+ "0.1.2.3.4.5.6";
+// This is a name of maximum allowed length
+const char* max_len_str = "123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789."
+ "123";
+
+namespace {
+class NameTest : public ::testing::Test {
+protected:
+ NameTest() : example_name("www.example.com"),
+ example_name_upper("WWW.EXAMPLE.COM"),
+ small_name("aaa.example.com"),
+ large_name("zzz.example.com"),
+ origin_name("example.com."),
+ origin_name_upper("EXAMPLE.COM"),
+ buffer_actual(0), buffer_expected(0)
+ {}
+
+ const Name example_name;
+ Name example_name_upper; // this will be modified and cannot be const
+ const Name small_name;
+ const Name large_name;
+ const Name origin_name;
+ const Name origin_name_upper;
+ OutputBuffer buffer_actual, buffer_expected;
+
+ //
+ // helper methods
+ //
+ static Name nameFactoryFromWire(const char* datafile, size_t position,
+ bool downcase = false);
+ // construct a name including all non-upper-case-alphabet characters.
+ static Name nameFactoryLowerCase();
+ void compareInWireFormat(const Name& name_actual,
+ const Name& name_expected);
+};
+
+const Name downcased_global("\\255.EXAMPLE.COM", true);
+
+Name
+NameTest::nameFactoryFromWire(const char* datafile, size_t position,
+ bool downcase)
+{
+ vector<unsigned char> data;
+ UnitTestUtil::readWireData(datafile, data);
+
+ InputBuffer buffer(&data[0], data.size());
+ buffer.setPosition(position);
+
+ return (Name(buffer, downcase));
+}
+
+Name
+NameTest::nameFactoryLowerCase() {
+ string lowercase_namestr;
+ lowercase_namestr.reserve(Name::MAX_WIRE);
+
+ unsigned int ch = 0;
+ unsigned int labelcount = 0;
+ do {
+ if (ch < 'A' || ch > 'Z') {
+ ostringstream ss;
+ ss.setf(ios_base::right, ios_base::adjustfield);
+ ss.width(3);
+ ss << setfill('0') << ch;
+ lowercase_namestr += '\\' + ss.str();
+
+ if (++labelcount == Name::MAX_LABELLEN) {
+ lowercase_namestr.push_back('.');
+ labelcount = 0;
+ }
+ }
+ } while (++ch <= Name::MAX_WIRE);
+
+ return (Name(lowercase_namestr));
+}
+
+void
+NameTest::compareInWireFormat(const Name& name_actual,
+ const Name& name_expected)
+{
+ buffer_actual.clear();
+ buffer_expected.clear();
+
+ name_actual.toWire(buffer_actual);
+ name_expected.toWire(buffer_expected);
+
+ matchWireData(buffer_expected.getData(), buffer_expected.getLength(),
+ buffer_actual.getData(), buffer_actual.getLength());
+}
+
+TEST_F(NameTest, nonlocalObject) {
+ // A previous version of code relied on a non local static object for
+ // name construction, so a non local static Name object defined outside
+ // the name module might not be initialized correctly. This test detects
+ // that kind of bug.
+ EXPECT_EQ("\\255.example.com.", downcased_global.toText());
+}
+
+template <typename ExceptionType>
+void
+checkBadTextName(const string& txt) {
+ // Check it results in the specified type of exception as well as
+ // NameParserException.
+ EXPECT_THROW(Name(txt, false), ExceptionType);
+ EXPECT_THROW(Name(txt, false), NameParserException);
+ // The same is thrown when constructing by the master-file constructor
+ EXPECT_THROW(Name(txt.c_str(), txt.length(), &Name::ROOT_NAME()),
+ ExceptionType);
+ EXPECT_THROW(Name(txt.c_str(), txt.length(), &Name::ROOT_NAME()),
+ NameParserException);
+}
+
+TEST_F(NameTest, checkExceptionsHierarchy) {
+ EXPECT_NO_THROW({
+ const isc::dns::EmptyLabel exception("", 0, "");
+ const isc::dns::NameParserException& exception_cast =
+ dynamic_cast<const isc::dns::NameParserException&>(exception);
+ // to avoid compiler warning
+ exception_cast.what();
+ });
+
+ EXPECT_NO_THROW({
+ const isc::dns::TooLongName exception("", 0, "");
+ const isc::dns::NameParserException& exception_cast =
+ dynamic_cast<const isc::dns::NameParserException&>(exception);
+ // to avoid compiler warning
+ exception_cast.what();
+ });
+
+ EXPECT_NO_THROW({
+ const isc::dns::TooLongLabel exception("", 0, "");
+ const isc::dns::NameParserException& exception_cast =
+ dynamic_cast<const isc::dns::NameParserException&>(exception);
+ // to avoid compiler warning
+ exception_cast.what();
+ });
+
+ EXPECT_NO_THROW({
+ const isc::dns::BadLabelType exception("", 0, "");
+ const isc::dns::NameParserException& exception_cast =
+ dynamic_cast<const isc::dns::NameParserException&>(exception);
+ // to avoid compiler warning
+ exception_cast.what();
+ });
+
+ EXPECT_NO_THROW({
+ const isc::dns::BadEscape exception("", 0, "");
+ const isc::dns::NameParserException& exception_cast =
+ dynamic_cast<const isc::dns::NameParserException&>(exception);
+ // to avoid compiler warning
+ exception_cast.what();
+ });
+
+ EXPECT_NO_THROW({
+ const isc::dns::IncompleteName exception("", 0, "");
+ const isc::dns::NameParserException& exception_cast =
+ dynamic_cast<const isc::dns::NameParserException&>(exception);
+ // to avoid compiler warning
+ exception_cast.what();
+ });
+
+ EXPECT_NO_THROW({
+ const isc::dns::MissingNameOrigin exception("", 0, "");
+ const isc::dns::NameParserException& exception_cast =
+ dynamic_cast<const isc::dns::NameParserException&>(exception);
+ // to avoid compiler warning
+ exception_cast.what();
+ });
+}
+
+TEST_F(NameTest, fromText) {
+ vector<string> strnames;
+ strnames.push_back("www.example.com");
+ strnames.push_back("www.example.com."); // with a trailing dot
+ strnames.push_back("wWw.exAmpLe.com"); // mixed cases
+ strnames.push_back("\\wWw.exAmpLe.com"); // escape with a backslash
+ // decimal representation for "WWW"
+ strnames.push_back("\\087\\087\\087.example.com");
+
+ for (auto const& it : strnames) {
+ EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name, Name(it));
+ }
+
+ // root names
+ EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, Name("@"), Name("."));
+
+ // downcase
+ EXPECT_EQ(Name("Www.eXample.coM", true).toText(), example_name.toText());
+
+ //
+ // Tests for bogus names. These should trigger exceptions.
+ //
+ // empty label cannot be followed by another label
+ checkBadTextName<EmptyLabel>(".a");
+ // duplicate period
+ checkBadTextName<EmptyLabel>("a..");
+ // label length must be < 64
+ checkBadTextName<TooLongLabel>("012345678901234567890123456789"
+ "012345678901234567890123456789"
+ "0123");
+ // now-unsupported bitstring labels
+ checkBadTextName<BadLabelType>("\\[b11010000011101]");
+ // label length must be < 64
+ checkBadTextName<TooLongLabel>("012345678901234567890123456789"
+ "012345678901234567890123456789"
+ "012\\x");
+ // but okay as long as resulting len < 64 even if the original string is
+ // "too long"
+ EXPECT_NO_THROW(Name("012345678901234567890123456789"
+ "012345678901234567890123456789"
+ "01\\x"));
+ // incomplete \DDD pattern (exactly 3 D's must appear)
+ checkBadTextName<BadEscape>("\\12abc");
+ // \DDD must not exceed 255
+ checkBadTextName<BadEscape>("\\256");
+ // Same tests for \111 as for \\x above
+ checkBadTextName<TooLongLabel>("012345678901234567890123456789"
+ "012345678901234567890123456789"
+ "012\\111");
+ EXPECT_NO_THROW(Name("012345678901234567890123456789"
+ "012345678901234567890123456789"
+ "01\\111"));
+ // A domain name must be 255 octets or less
+ checkBadTextName<TooLongName>("123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789."
+ "123456789.1234");
+ // This is a possible longest name and should be accepted
+ EXPECT_NO_THROW(Name(string(max_len_str)));
+ // \DDD must consist of 3 digits.
+ checkBadTextName<IncompleteName>("\\12");
+
+ // a name with the max number of labels. should be constructed without
+ // an error, and its length should be the max value.
+ Name maxlabels = Name(string(max_labels_str));
+ EXPECT_EQ(Name::MAX_LABELS, maxlabels.getLabelCount());
+}
+
+// The following test uses a name data that was produced by
+// fuzz testing and causes an unexpected condition in stringParser.
+// Formerly this condition was trapped by an assert, but for
+// robustness it has been replaced by a throw.
+TEST_F(NameTest, unexpectedParseError) {
+ std::vector<uint8_t> badname {
+ 0xff,0xff,0x7f,0x00,0x00,0x00,0x7f,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x04,0x63,0x82,0x53,0x63,0x35,0x01,0x01,0x3d,0x07,0x01,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x19,0x0c,0x4e,0x01,0x00,0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x35,0x01,0x05,0x3a,0x04,0x00,0x00,0x07,0x08,0x3b,0x04,0x00,
+ 0x00,0x2e,0x3b,0x04,0x00,0x19,0x2e,0x00,0x00,0x00,0x0a,0x00,0x12,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x0b,0x82,0x01,0xfc,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x35,0x01,0x05,0x3a,0x04,0x00,0x00,0x07,0x08,0x3b,0x04,
+ 0x00,0x00,0x2e,0x3b,0x04,0x00,0x19,0x2e,0x56,0x00,0x00,0x0a,0x00,0x12,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x0b,0x82,0x01,0xfc,0x42,0x00,0x00,0x00,0x00,0x19,0x0c,
+ 0x4e,0x01,0x05,0x3a,0x04,0xde,0x00,0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x35,0x01,0x05,0x3a,0x07,0x08,0x3b,0x04,0x00,0x00,0x2e,0x3b,0x04,
+ 0x00,0x19,0x2e,0x56,0x40,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x12,0x00,0x00,0x00,
+ 0x00,0x00,0x19,0x00,0x0b,0x82,0x01,0xfc,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x35,0x01,0x05,0xff,0xff,0x05,0x00,0x07,0x08,0x3b,0x04,
+ 0x00,0x00,0x2e,0x3b
+ };
+
+ std::string badnamestr(badname.begin(), badname.end());
+ EXPECT_THROW(Name(badnamestr, false), Unexpected);
+}
+
+// on the rest while we prepare it.
+// Check the @ syntax is accepted and it just copies the origin.
+TEST_F(NameTest, copyOrigin) {
+ EXPECT_EQ(origin_name, Name("@", 1, &origin_name));
+ // The downcase works on the origin too. But only when we provide it.
+ EXPECT_EQ(origin_name, Name("@", 1, &origin_name_upper, true));
+ EXPECT_EQ(origin_name_upper, Name("@", 1, &origin_name_upper, true));
+ // If we don't provide the origin, it throws
+ EXPECT_THROW(Name("@", 1, NULL), MissingNameOrigin);
+}
+
+// Test the master-file constructor does not append the origin when the
+// provided name is absolute
+TEST_F(NameTest, dontAppendOrigin) {
+ EXPECT_EQ(example_name, Name("www.example.com.", 16, &origin_name));
+ // The downcase works (only if provided, though)
+ EXPECT_EQ(example_name, Name("WWW.EXAMPLE.COM.", 16, &origin_name, true));
+ EXPECT_EQ(example_name_upper, Name("WWW.EXAMPLE.COM.", 16, &origin_name));
+ // And it does not require the origin to be provided
+ EXPECT_NO_THROW(Name("www.example.com.", 16, NULL));
+}
+
+// Test the master-file constructor properly appends the origin when
+// the provided name is relative.
+TEST_F(NameTest, appendOrigin) {
+ EXPECT_EQ(example_name, Name("www", 3, &origin_name));
+ // Check the downcase works (if provided)
+ EXPECT_EQ(example_name, Name("WWW", 3, &origin_name, true));
+ EXPECT_EQ(example_name, Name("WWW", 3, &origin_name_upper, true));
+ EXPECT_EQ(example_name_upper, Name("WWW", 3, &origin_name_upper));
+ // Check we can prepend more than one label
+ EXPECT_EQ(Name("a.b.c.d.example.com."), Name("a.b.c.d", 7, &origin_name));
+ // When the name is relative, we throw.
+ EXPECT_THROW(Name("www", 3, NULL), MissingNameOrigin);
+}
+
+// When we don't provide the data, it throws
+TEST_F(NameTest, noDataProvided) {
+ EXPECT_THROW(Name(NULL, 10, NULL), isc::InvalidParameter);
+ EXPECT_THROW(Name(NULL, 10, &origin_name), isc::InvalidParameter);
+ EXPECT_THROW(Name("www", 0, NULL), isc::InvalidParameter);
+ EXPECT_THROW(Name("www", 0, &origin_name), isc::InvalidParameter);
+}
+
+// When we combine the first part and the origin together, the resulting name
+// is too long. It should throw. Other test checks this is valid when alone
+// (without the origin appended).
+TEST_F(NameTest, combinedTooLong) {
+ EXPECT_THROW(Name(max_len_str, strlen(max_len_str), &origin_name),
+ TooLongName);
+ EXPECT_THROW(Name(max_labels_str, strlen(max_labels_str), &origin_name),
+ TooLongName);
+ // Appending the root should be OK
+ EXPECT_NO_THROW(Name(max_len_str, strlen(max_len_str),
+ &Name::ROOT_NAME()));
+ EXPECT_NO_THROW(Name(max_labels_str, strlen(max_labels_str),
+ &Name::ROOT_NAME()));
+}
+
+// Test the handling of @ in the name. If it is alone, it is the origin (when
+// it exists) or the root. If it is somewhere else, it has no special meaning.
+TEST_F(NameTest, atSign) {
+ // If it is alone, it is the origin
+ EXPECT_EQ(origin_name, Name("@", 1, &origin_name));
+ EXPECT_THROW(Name("@", 1, NULL), MissingNameOrigin);
+ EXPECT_EQ(Name::ROOT_NAME(), Name("@"));
+
+ // It is not alone. It is taken verbatim. We check the name converted
+ // back to the textual form, since checking it against other name object
+ // may be wrong -- if we create it wrong the same way as the tested
+ // object.
+ EXPECT_EQ("\\@.", Name("@.").toText());
+ EXPECT_EQ("\\@.", Name("@.", 2, NULL).toText());
+ EXPECT_EQ("\\@something.", Name("@something").toText());
+ EXPECT_EQ("something\\@.", Name("something@").toText());
+ EXPECT_EQ("\\@x.example.com.", Name("@x", 2, &origin_name).toText());
+ EXPECT_EQ("x\\@.example.com.", Name("x@", 2, &origin_name).toText());
+
+ // An escaped at-sign isn't active
+ EXPECT_EQ("\\@.", Name("\\@").toText());
+ EXPECT_EQ("\\@.example.com.", Name("\\@", 2, &origin_name).toText());
+}
+
+TEST_F(NameTest, fromWire) {
+ //
+ // test cases derived from BIND9 tests.
+ //
+ // normal case with a compression pointer
+ EXPECT_PRED_FORMAT2(UnitTestUtil::matchName,
+ nameFactoryFromWire("name_fromWire1", 25),
+ Name("vix.com"));
+ // bogus label character (looks like a local compression pointer)
+ EXPECT_THROW(nameFactoryFromWire("name_fromWire2", 25), DNSMessageFORMERR);
+ // a bad compression pointer (too big)
+ EXPECT_THROW(nameFactoryFromWire("name_fromWire3_1", 25),
+ DNSMessageFORMERR);
+ // forward reference
+ EXPECT_THROW(nameFactoryFromWire("name_fromWire3_2", 25),
+ DNSMessageFORMERR);
+ // invalid name length
+ EXPECT_THROW(nameFactoryFromWire("name_fromWire4", 550), DNSMessageFORMERR);
+
+ // skip test for from Wire5. It's for disabling decompression, but our
+ // implementation always allows it.
+
+ // bad pointer (too big)
+ EXPECT_THROW(nameFactoryFromWire("name_fromWire6", 25), DNSMessageFORMERR);
+ // input ends unexpectedly
+ EXPECT_THROW(nameFactoryFromWire("name_fromWire7", 25), DNSMessageFORMERR);
+ // many hops of compression but valid. should succeed.
+ EXPECT_PRED_FORMAT2(UnitTestUtil::matchName,
+ nameFactoryFromWire("name_fromWire8", 383),
+ Name("vix.com"));
+
+ //
+ // Additional test cases
+ //
+
+ // large names, a long but valid one, and invalid (too long) one.
+ EXPECT_EQ(Name::MAX_WIRE,
+ nameFactoryFromWire("name_fromWire9", 0).getLength());
+ EXPECT_THROW(nameFactoryFromWire("name_fromWire10", 0).getLength(),
+ DNSMessageFORMERR);
+
+ // A name with possible maximum number of labels; awkward but valid
+ EXPECT_EQ(nameFactoryFromWire("name_fromWire11", 0).getLabelCount(),
+ Name::MAX_LABELS);
+
+ // Wire format including an invalid label length
+ EXPECT_THROW(nameFactoryFromWire("name_fromWire12", 0), DNSMessageFORMERR);
+
+ // converting upper-case letters to down-case
+ EXPECT_EQ("vix.com.",
+ nameFactoryFromWire("name_fromWire1", 25, true).toText());
+ EXPECT_EQ(3, nameFactoryFromWire("name_fromWire1", 25).getLabelCount());
+}
+
+TEST_F(NameTest, copyConstruct) {
+ Name copy(example_name);
+ EXPECT_EQ(copy, example_name);
+
+ // Check the copied data is valid even after the original is deleted
+ Name* copy2 = new Name(example_name);
+ Name copy3(*copy2);
+ delete copy2;
+ EXPECT_EQ(copy3, example_name);
+}
+
+TEST_F(NameTest, assignment) {
+ Name copy(".");
+ copy = example_name;
+ EXPECT_EQ(copy, example_name);
+
+ // Check if the copied data is valid even after the original is deleted
+ Name* copy2 = new Name(example_name);
+ Name copy3(".");
+ copy3 = *copy2;
+ delete copy2;
+ EXPECT_EQ(copy3, example_name);
+
+ // Self assignment
+ copy = *&copy;
+ EXPECT_EQ(example_name, copy);
+}
+
+TEST_F(NameTest, toText) {
+ // tests derived from BIND9
+ EXPECT_EQ("a.b.c.d", Name("a.b.c.d").toText(true));
+ EXPECT_EQ("a.\\\\[[.c.d", Name("a.\\\\[\\[.c.d").toText(true));
+ EXPECT_EQ("a.b.C.d.", Name("a.b.C.d").toText(false));
+ EXPECT_EQ("a.b.", Name("a.b.").toText(false));
+
+ // test omit_final_dot. It's false by default.
+ EXPECT_EQ("a.b.c.d", Name("a.b.c.d.").toText(true));
+ EXPECT_EQ(Name("a.b.").toText(false), Name("a.b.").toText());
+
+ // the root name is a special case: omit_final_dot will be ignored.
+ EXPECT_EQ(".", Name(".").toText(true));
+
+ // test all printable characters to see whether special characters are
+ // escaped while the others are intact. note that the conversion is
+ // implementation specific; for example, it's not invalid to escape a
+ // "normal" character such as 'a' with regard to the standard.
+ string all_printable("!\\\"#\\$%&'\\(\\)*+,-\\./0123456789:\\;<=>?\\@"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "[\\\\]^_.`abcdefghijklmnopqrstuvwxyz{|}~.");
+ EXPECT_EQ(all_printable,
+ nameFactoryFromWire("name_fromWire13", 0).toText());
+
+ string all_nonprintable(
+ "\\000\\001\\002\\003\\004\\005\\006\\007\\008\\009"
+ "\\010\\011\\012\\013\\014\\015\\016\\017\\018\\019"
+ "\\020\\021\\022\\023\\024\\025\\026\\027\\028\\029"
+ "\\030\\031\\032\\127\\128\\129"
+ "\\130\\131\\132\\133\\134\\135\\136\\137\\138\\139"
+ "\\140\\141\\142\\143\\144\\145\\146\\147\\148\\149"
+ "\\150\\151\\152\\153\\154\\155\\156."
+ "\\157\\158\\159"
+ "\\160\\161\\162\\163\\164\\165\\166\\167\\168\\169"
+ "\\170\\171\\172\\173\\174\\175\\176\\177\\178\\179"
+ "\\180\\181\\182\\183\\184\\185\\186\\187\\188\\189"
+ "\\190\\191\\192\\193\\194\\195\\196\\197\\198\\199"
+ "\\200\\201\\202\\203\\204\\205\\206\\207\\208\\209"
+ "\\210\\211\\212\\213\\214\\215\\216\\217\\218\\219."
+ "\\220\\221\\222\\223\\224\\225\\226\\227\\228\\229"
+ "\\230\\231\\232\\233\\234\\235\\236\\237\\238\\239"
+ "\\240\\241\\242\\243\\244\\245\\246\\247\\248\\249"
+ "\\250\\251\\252\\253\\254\\255.");
+ EXPECT_EQ(all_nonprintable,
+ nameFactoryFromWire("name_fromWire14", 0).toText());
+}
+
+TEST_F(NameTest, toWireBuffer) {
+ vector<unsigned char> data;
+ OutputBuffer buffer(0);
+
+ UnitTestUtil::readWireData(string("01610376697803636f6d00"), data);
+ Name("a.vix.com.").toWire(buffer);
+ matchWireData(&data[0], data.size(),
+ buffer.getData(), buffer.getLength());
+}
+
+//
+// We test various corner cases in Renderer tests, but add this test case
+// to fill the code coverage gap.
+//
+TEST_F(NameTest, toWireRenderer) {
+ vector<unsigned char> data;
+ MessageRenderer renderer;
+
+ UnitTestUtil::readWireData(string("01610376697803636f6d00"), data);
+ Name("a.vix.com.").toWire(renderer);
+ matchWireData(&data[0], data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+//
+// Helper class to hold comparison test parameters.
+//
+struct CompareParameters {
+ CompareParameters(const Name& n1, const Name& n2,
+ NameComparisonResult::NameRelation r, int o,
+ unsigned int l) :
+ name1(n1), name2(n2), reln(r), order(o), labels(l) {}
+ static int normalizeOrder(int o)
+ {
+ if (o > 0) {
+ return (1);
+ } else if (o < 0) {
+ return (-1);
+ }
+ return (0);
+ }
+ Name name1;
+ Name name2;
+ NameComparisonResult::NameRelation reln;
+ int order;
+ unsigned int labels;
+};
+
+TEST_F(NameTest, compare) {
+ vector<CompareParameters> params;
+ params.push_back(CompareParameters(Name("c.d"), Name("a.b.c.d"),
+ NameComparisonResult::SUPERDOMAIN,
+ -1, 3));
+ params.push_back(CompareParameters(Name("a.b.c.d"), Name("c.d"),
+ NameComparisonResult::SUBDOMAIN, 1, 3));
+ params.push_back(CompareParameters(Name("a.b.c.d"), Name("c.d.e.f"),
+ NameComparisonResult::COMMONANCESTOR,
+ -1, 1));
+ params.push_back(CompareParameters(Name("a.b.c.d"), Name("f.g.c.d"),
+ NameComparisonResult::COMMONANCESTOR,
+ -1, 3));
+ params.push_back(CompareParameters(Name("a.b.c.d"), Name("A.b.C.d."),
+ NameComparisonResult::EQUAL,
+ 0, 5));
+
+ for (auto const& it : params) {
+ NameComparisonResult result = it.name1.compare(it.name2);
+ EXPECT_EQ(it.reln, result.getRelation());
+ EXPECT_EQ(it.order, CompareParameters::normalizeOrder(result.getOrder()));
+ EXPECT_EQ(it.labels, result.getCommonLabels());
+ }
+}
+
+TEST_F(NameTest, equal) {
+ EXPECT_TRUE(example_name == Name("WWW.EXAMPLE.COM."));
+ EXPECT_TRUE(example_name.equals(Name("WWW.EXAMPLE.COM.")));
+ EXPECT_TRUE(example_name != Name("www.example.org."));
+ EXPECT_TRUE(example_name.nequals(Name("www.example.org.")));
+ // lengths don't match
+ EXPECT_TRUE(example_name != Name("www2.example.com."));
+ EXPECT_TRUE(example_name.nequals(Name("www2.example.com.")));
+ // lengths are equal, but # of labels don't match (first test checks the
+ // prerequisite).
+ EXPECT_EQ(example_name.getLength(), Name("www\\.example.com.").getLength());
+ EXPECT_TRUE(example_name != Name("www\\.example.com."));
+ EXPECT_TRUE(example_name.nequals(Name("www\\.example.com.")));
+}
+
+TEST_F(NameTest, isWildcard) {
+ EXPECT_FALSE(example_name.isWildcard());
+ EXPECT_TRUE(Name("*.a.example.com").isWildcard());
+ EXPECT_FALSE(Name("a.*.example.com").isWildcard());
+}
+
+TEST_F(NameTest, concatenate) {
+ NameComparisonResult result =
+ Name("aaa.www.example.com.").compare(Name("aaa").concatenate(example_name));
+ EXPECT_EQ(NameComparisonResult::EQUAL, result.getRelation());
+
+ result = example_name.compare(Name(".").concatenate(example_name));
+ EXPECT_EQ(NameComparisonResult::EQUAL, result.getRelation());
+
+ result = example_name.compare(example_name.concatenate(Name(".")));
+ EXPECT_EQ(NameComparisonResult::EQUAL, result.getRelation());
+
+ // concatenating two valid names would result in too long a name.
+ Name n1("123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789.");
+ Name n2("123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789."
+ "1234.");
+ EXPECT_THROW(n1.concatenate(n2), TooLongName);
+}
+
+TEST_F(NameTest, reverse) {
+ EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name.reverse(),
+ Name("com.example.www."));
+ EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, Name(".").reverse(),
+ Name("."));
+ EXPECT_PRED_FORMAT2(UnitTestUtil::matchName,
+ Name("a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s").reverse(),
+ Name("s.r.q.p.o.n.m.l.k.j.i.h.g.f.e.d.c.b.a"));
+}
+
+TEST_F(NameTest, split) {
+ // normal cases with or without explicitly specifying the trailing dot.
+ EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name.split(1, 2),
+ Name("example.com."));
+ EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name.split(1, 3),
+ Name("example.com."));
+ // edge cases: only the first or last label.
+ EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name.split(0, 1),
+ Name("www."));
+ EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name.split(3, 1),
+ Name("."));
+ // invalid range: an exception should be thrown.
+ EXPECT_THROW(example_name.split(1, 0), OutOfRange);
+ EXPECT_THROW(example_name.split(2, 3), OutOfRange);
+
+ // invalid range: the following parameters would cause overflow,
+ // bypassing naive validation.
+ EXPECT_THROW(example_name.split(1, numeric_limits<unsigned int>::max()),
+ OutOfRange);
+}
+
+TEST_F(NameTest, split_for_suffix) {
+ EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name.split(1),
+ Name("example.com"));
+ EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name.split(0),
+ example_name);
+ EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name.split(3),
+ Name("."));
+
+ // Invalid case: the level must be less than the original label count.
+ EXPECT_THROW(example_name.split(4), OutOfRange);
+}
+
+TEST_F(NameTest, downcase) {
+ // usual case: all-upper case name to all-lower case
+ compareInWireFormat(example_name_upper.downcase(), example_name);
+ // confirm that non upper-case characters are intact
+ compareInWireFormat(nameFactoryLowerCase().downcase(),
+ nameFactoryLowerCase());
+ // confirm the calling object is actually modified
+ example_name_upper.downcase();
+ compareInWireFormat(example_name_upper, example_name);
+}
+
+TEST_F(NameTest, at) {
+ // Confirm at() produces the exact sequence of wire-format name data
+ vector<uint8_t> data;
+
+ for (size_t i = 0; i < example_name.getLength(); i++) {
+ data.push_back(example_name.at(i));
+ }
+
+ example_name.toWire(buffer_expected);
+ matchWireData(&data[0], data.size(),
+ buffer_expected.getData(), buffer_expected.getLength());
+
+ // Out-of-range access: should trigger an exception.
+ EXPECT_THROW(example_name.at(example_name.getLength()), OutOfRange);
+}
+
+//
+// The following set of tests confirm the result of <=, <, >=, >
+// The test logic is simple, and all tests are just straightforward variations
+// of the first one.
+//
+TEST_F(NameTest, leq) {
+ // small <= large is true
+ EXPECT_TRUE(small_name.leq(large_name));
+ EXPECT_TRUE(small_name <= large_name);
+
+ // small <= small is true
+ EXPECT_TRUE(small_name.leq(small_name));
+ EXPECT_LE(small_name, small_name);
+
+ // large <= small is false
+ EXPECT_FALSE(large_name.leq(small_name));
+ EXPECT_FALSE(large_name <= small_name);
+}
+
+TEST_F(NameTest, geq) {
+ EXPECT_TRUE(large_name.geq(small_name));
+ EXPECT_TRUE(large_name >= small_name);
+
+ EXPECT_TRUE(large_name.geq(large_name));
+ EXPECT_GE(large_name, large_name);
+
+ EXPECT_FALSE(small_name.geq(large_name));
+ EXPECT_FALSE(small_name >= large_name);
+}
+
+TEST_F(NameTest, lthan) {
+ EXPECT_TRUE(small_name.lthan(large_name));
+ EXPECT_TRUE(small_name < large_name);
+
+ EXPECT_FALSE(small_name.lthan(small_name));
+ // cppcheck-suppress duplicateExpression
+ EXPECT_FALSE(small_name < small_name);
+
+ EXPECT_FALSE(large_name.lthan(small_name));
+ EXPECT_FALSE(large_name < small_name);
+}
+
+TEST_F(NameTest, gthan) {
+ EXPECT_TRUE(large_name.gthan(small_name));
+ EXPECT_TRUE(large_name > small_name);
+
+ EXPECT_FALSE(large_name.gthan(large_name));
+ // cppcheck-suppress duplicateExpression
+ EXPECT_FALSE(large_name > large_name);
+
+ EXPECT_FALSE(small_name.gthan(large_name));
+ EXPECT_FALSE(small_name > large_name);
+}
+
+TEST_F(NameTest, constants) {
+ EXPECT_EQ(Name("."), Name::ROOT_NAME());
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST_F(NameTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << example_name;
+ EXPECT_EQ(example_name.toText(), oss.str());
+}
+
+// The following verifies that toRawText() returns a string
+// actual characters in place of escape sequences. We do not
+// bother with an exhaustive set of tests here as this is
+// not a primary use case.
+TEST_F(NameTest, toRawText) {
+ Name n("a bc.$exa(m)ple.@org");
+ EXPECT_EQ("a bc.$exa(m)ple.@org", n.toRawText(true));
+ EXPECT_EQ("a bc.$exa(m)ple.@org.", n.toRawText(false));
+ // Verify default value of omit parameter is false.
+ EXPECT_EQ("a bc.$exa(m)ple.@org.", n.toRawText());
+}
+
+}
diff --git a/src/lib/dns/tests/nsec3hash_unittest.cc b/src/lib/dns/tests/nsec3hash_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/nsec3hash_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/opcode_unittest.cc b/src/lib/dns/tests/opcode_unittest.cc
index 8b13789179..9bc60b5b7e 100644
--- a/src/lib/dns/tests/opcode_unittest.cc
+++ b/src/lib/dns/tests/opcode_unittest.cc
@@ -1 +1,100 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <vector>
+#include <sstream>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/opcode.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc::dns;
+
+namespace {
+TEST(OpcodeTest, construct) {
+ // This test also tests getCode()
+ EXPECT_EQ(0, Opcode(0).getCode());
+ EXPECT_EQ(15, Opcode(Opcode::RESERVED15_CODE).getCode());
+
+ EXPECT_THROW(Opcode(16), isc::OutOfRange);
+}
+
+TEST(OpcodeTest, constants) {
+ // We'll only test arbitrarily chosen subsets of the codes.
+ // This class is quite simple, so it should be suffice.
+
+ EXPECT_EQ(Opcode::QUERY_CODE, Opcode(0).getCode());
+ EXPECT_EQ(Opcode::IQUERY_CODE, Opcode(1).getCode());
+ EXPECT_EQ(Opcode::NOTIFY_CODE, Opcode(4).getCode());
+ EXPECT_EQ(Opcode::UPDATE_CODE, Opcode(5).getCode());
+ EXPECT_EQ(Opcode::RESERVED15_CODE, Opcode(15).getCode());
+
+ EXPECT_EQ(Opcode::QUERY_CODE, Opcode::QUERY().getCode());
+ EXPECT_EQ(Opcode::IQUERY_CODE, Opcode::IQUERY().getCode());
+ EXPECT_EQ(Opcode::NOTIFY_CODE, Opcode::NOTIFY().getCode());
+ EXPECT_EQ(Opcode::UPDATE_CODE, Opcode::UPDATE().getCode());
+ EXPECT_EQ(Opcode::RESERVED15_CODE, Opcode::RESERVED15().getCode());
+}
+
+TEST(OpcodeTest, equal) {
+ EXPECT_TRUE(Opcode::QUERY() == Opcode(Opcode::QUERY_CODE));
+ EXPECT_TRUE(Opcode::QUERY().equals(Opcode(Opcode::QUERY_CODE)));
+ EXPECT_TRUE(Opcode::IQUERY() == Opcode(Opcode::IQUERY_CODE));
+ EXPECT_TRUE(Opcode::IQUERY().equals(Opcode(Opcode::IQUERY_CODE)));
+ EXPECT_TRUE(Opcode::NOTIFY() == Opcode(Opcode::NOTIFY_CODE));
+ EXPECT_TRUE(Opcode::NOTIFY().equals(Opcode(Opcode::NOTIFY_CODE)));
+ EXPECT_TRUE(Opcode::UPDATE() == Opcode(Opcode::UPDATE_CODE));
+ EXPECT_TRUE(Opcode::UPDATE().equals(Opcode(Opcode::UPDATE_CODE)));
+ EXPECT_TRUE(Opcode::RESERVED15() == Opcode(Opcode::RESERVED15()));
+ EXPECT_TRUE(Opcode::RESERVED15().equals(Opcode(Opcode::RESERVED15())));
+}
+
+TEST(OpcodeTest, nequal) {
+ EXPECT_TRUE(Opcode::QUERY() != Opcode::IQUERY());
+ EXPECT_TRUE(Opcode::QUERY().nequals(Opcode::IQUERY()));
+ EXPECT_TRUE(Opcode::NOTIFY() != Opcode(1));
+ EXPECT_TRUE(Opcode::NOTIFY().nequals(Opcode(1)));
+ EXPECT_TRUE(Opcode(10) != Opcode(11));
+ EXPECT_TRUE(Opcode(10).nequals(Opcode(11)));
+}
+
+TEST(OpcodeTest, toText) {
+ vector<const char*> expects;
+ expects.resize(Opcode::RESERVED15_CODE + 1);
+ expects[Opcode::QUERY_CODE] = "QUERY";
+ expects[Opcode::IQUERY_CODE] = "IQUERY";
+ expects[Opcode::STATUS_CODE] = "STATUS";
+ expects[Opcode::RESERVED3_CODE] = "RESERVED3";
+ expects[Opcode::NOTIFY_CODE] = "NOTIFY";
+ expects[Opcode::UPDATE_CODE] = "UPDATE";
+ expects[Opcode::RESERVED6_CODE] = "RESERVED6";
+ expects[Opcode::RESERVED7_CODE] = "RESERVED7";
+ expects[Opcode::RESERVED8_CODE] = "RESERVED8";
+ expects[Opcode::RESERVED9_CODE] = "RESERVED9";
+ expects[Opcode::RESERVED10_CODE] = "RESERVED10";
+ expects[Opcode::RESERVED11_CODE] = "RESERVED11";
+ expects[Opcode::RESERVED12_CODE] = "RESERVED12";
+ expects[Opcode::RESERVED13_CODE] = "RESERVED13";
+ expects[Opcode::RESERVED14_CODE] = "RESERVED14";
+ expects[Opcode::RESERVED15_CODE] = "RESERVED15";
+
+ for (unsigned int i = 0; i <= Opcode::RESERVED15_CODE; ++i) {
+ EXPECT_EQ(expects.at(i), Opcode(i).toText());
+ }
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST(OpcodeTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << Opcode::NOTIFY();
+ EXPECT_EQ(Opcode::NOTIFY().toText(), oss.str());
+}
+}
diff --git a/src/lib/dns/tests/qid_gen_unittest.cc b/src/lib/dns/tests/qid_gen_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/qid_gen_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/question_unittest.cc b/src/lib/dns/tests/question_unittest.cc
index 8b13789179..d096c6b18d 100644
--- a/src/lib/dns/tests/question_unittest.cc
+++ b/src/lib/dns/tests/question_unittest.cc
@@ -1 +1,198 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <vector>
+#include <sstream>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <dns/exceptions.h>
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/question.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+#include <util/unittests/wiredata.h>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::util;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+namespace {
+class QuestionTest : public ::testing::Test {
+protected:
+ QuestionTest() : obuffer(0),
+ example_name1(Name("foo.example.com")),
+ example_name2(Name("bar.example.com")),
+ test_question1(example_name1, RRClass::IN(),
+ RRType::NS()),
+ test_question2(example_name2, RRClass::CH(),
+ RRType::A()) {
+ }
+ OutputBuffer obuffer;
+ MessageRenderer renderer;
+ Name example_name1;
+ Name example_name2;
+ Question test_question1;
+ Question test_question2;
+ vector<unsigned char> wiredata;
+};
+
+Question
+questionFromWire(const char* datafile, size_t position = 0) {
+ vector<unsigned char> data;
+ UnitTestUtil::readWireData(datafile, data);
+
+ InputBuffer buffer(&data[0], data.size());
+ buffer.setPosition(position);
+
+ return (Question(buffer));
+}
+
+TEST_F(QuestionTest, fromWire) {
+ Question q = questionFromWire("question_fromWire");
+
+ EXPECT_EQ(example_name1, q.getName());
+ EXPECT_EQ(RRClass::IN(), q.getClass());
+ EXPECT_EQ(RRType::NS(), q.getType());
+
+ // owner name of the second Question is compressed. It's uncommon
+ // (to have multiple questions), but isn't prohibited by the protocol.
+ q = questionFromWire("question_fromWire", 21);
+ EXPECT_EQ(example_name2, q.getName());
+ EXPECT_EQ(RRClass::CH(), q.getClass());
+ EXPECT_EQ(RRType::A(), q.getType());
+
+ // Pathological cases: Corresponding exceptions will be thrown from
+ // the underlying parser.
+ EXPECT_THROW(questionFromWire("question_fromWire", 31), DNSMessageFORMERR);
+ EXPECT_THROW(questionFromWire("question_fromWire", 36), IncompleteRRClass);
+}
+
+TEST_F(QuestionTest, toText) {
+ EXPECT_EQ("foo.example.com. IN NS", test_question1.toText());
+ EXPECT_EQ("bar.example.com. CH A", test_question2.toText());
+
+ EXPECT_EQ("foo.example.com. IN NS", test_question1.toText(false));
+ EXPECT_EQ("bar.example.com. CH A", test_question2.toText(false));
+
+ EXPECT_EQ("foo.example.com. IN NS\n", test_question1.toText(true));
+ EXPECT_EQ("bar.example.com. CH A\n", test_question2.toText(true));
+}
+
+TEST_F(QuestionTest, toWireBuffer) {
+ test_question1.toWire(obuffer);
+ test_question2.toWire(obuffer);
+ UnitTestUtil::readWireData("question_toWire1", wiredata);
+ matchWireData(&wiredata[0], wiredata.size(),
+ obuffer.getData(), obuffer.getLength());
+}
+
+TEST_F(QuestionTest, toWireRenderer) {
+ test_question1.toWire(renderer);
+ test_question2.toWire(renderer);
+ UnitTestUtil::readWireData("question_toWire2", wiredata);
+ matchWireData(&wiredata[0], wiredata.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(QuestionTest, toWireTruncated) {
+ // If the available length in the renderer is too small, it would require
+ // truncation. This won't happen in normal cases, but protocol wise it
+ // could still happen if and when we support some (possibly future) opcode
+ // that allows multiple questions.
+
+ // Set the length limit to the qname length so that the whole question
+ // would request truncated
+ renderer.setLengthLimit(example_name1.getLength());
+
+ EXPECT_FALSE(renderer.isTruncated()); // check pre-render condition
+ EXPECT_EQ(0, test_question1.toWire(renderer));
+ EXPECT_TRUE(renderer.isTruncated());
+ EXPECT_EQ(0, renderer.getLength()); // renderer shouldn't have any data
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST_F(QuestionTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << test_question1;
+ EXPECT_EQ(test_question1.toText(), oss.str());
+}
+
+TEST_F(QuestionTest, comparison) {
+ const Name a("a");
+ const Name b("b");
+ const RRClass in(RRClass::IN());
+ const RRClass ch(RRClass::CH());
+ const RRType ns(RRType::NS());
+ const RRType aaaa(RRType::AAAA());
+
+ EXPECT_TRUE(Question(a, in, ns) < Question(a, in, aaaa));
+ EXPECT_FALSE(Question(a, in, aaaa) < Question(a, in, ns));
+
+ EXPECT_TRUE(Question(a, in, ns) < Question(a, ch, ns));
+ EXPECT_FALSE(Question(a, ch, ns) < Question(a, in, ns));
+
+ EXPECT_TRUE(Question(a, in, ns) < Question(a, ch, aaaa));
+ EXPECT_FALSE(Question(a, ch, aaaa) < Question(a, in, ns));
+
+ EXPECT_TRUE(Question(a, in, ns) < Question(b, in, ns));
+ EXPECT_FALSE(Question(a, in, ns) < Question(a, in, ns));
+
+ EXPECT_TRUE(Question(a, in, ns) < Question(b, ch, ns));
+ EXPECT_FALSE(Question(b, ch, ns) < Question(a, in, ns));
+
+ EXPECT_TRUE(Question(a, in, ns) < Question(b, ch, aaaa));
+ EXPECT_FALSE(Question(b, ch, aaaa) < Question(a, in, ns));
+
+ EXPECT_FALSE(Question(a, in, ns) < Question(a, in, ns));
+ EXPECT_FALSE(Question(a, ch, ns) < Question(a, ch, ns));
+ EXPECT_FALSE(Question(b, in, ns) < Question(b, in, ns));
+ EXPECT_FALSE(Question(b, in, aaaa) < Question(b, in, aaaa));
+
+ // Identical questions are equal
+
+ EXPECT_TRUE(Question(a, in, ns) == Question(a, in, ns));
+ EXPECT_FALSE(Question(a, in, ns) != Question(a, in, ns));
+
+ // Components differing by one component are unequal...
+
+ EXPECT_FALSE(Question(b, in, ns) == Question(a, in, ns));
+ EXPECT_TRUE(Question(b, in, ns) != Question(a, in, ns));
+
+ EXPECT_FALSE(Question(a, ch, ns) == Question(a, in, ns));
+ EXPECT_TRUE(Question(a, ch, ns) != Question(a, in, ns));
+
+ EXPECT_FALSE(Question(a, in, aaaa) == Question(a, in, ns));
+ EXPECT_TRUE(Question(a, in, aaaa) != Question(a, in, ns));
+
+ // ... as are those differing by two components
+
+ EXPECT_FALSE(Question(b, ch, ns) == Question(a, in, ns));
+ EXPECT_TRUE(Question(b, ch, ns) != Question(a, in, ns));
+
+ EXPECT_FALSE(Question(b, in, aaaa) == Question(a, in, ns));
+ EXPECT_TRUE(Question(b, in, aaaa) != Question(a, in, ns));
+
+ EXPECT_FALSE(Question(a, ch, aaaa) == Question(a, in, ns));
+ EXPECT_TRUE(Question(a, ch, aaaa) != Question(a, in, ns));
+
+ // ... and question differing by all three
+
+ EXPECT_FALSE(Question(b, ch, aaaa) == Question(a, in, ns));
+ EXPECT_TRUE(Question(b, ch, aaaa) != Question(a, in, ns));
+}
+
+}
diff --git a/src/lib/dns/tests/rcode_unittest.cc b/src/lib/dns/tests/rcode_unittest.cc
index 8b13789179..220248f062 100644
--- a/src/lib/dns/tests/rcode_unittest.cc
+++ b/src/lib/dns/tests/rcode_unittest.cc
@@ -1 +1,126 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <vector>
+#include <sstream>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/rcode.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc::dns;
+
+namespace {
+TEST(RcodeTest, constructFromCode) {
+ // Normal cases. This test also tests getCode()
+ EXPECT_EQ(0, Rcode(0).getCode());
+ EXPECT_EQ(0xfff, Rcode(0xfff).getCode()); // possible max code
+
+ // should fail on attempt of construction with an out of range code
+ EXPECT_THROW(Rcode(0x1000), isc::OutOfRange);
+ EXPECT_THROW(Rcode(0xffff), isc::OutOfRange);
+}
+
+TEST(RcodeTest, constructFromCodePair) {
+ EXPECT_EQ(3, Rcode(Rcode::NXDOMAIN_CODE, 0).getCode());
+ EXPECT_EQ(Rcode::BADVERS_CODE, Rcode(0, 1).getCode());
+ EXPECT_EQ(0xfff, Rcode(0xf, 0xff).getCode());
+ EXPECT_THROW(Rcode(0x10, 0xff), isc::OutOfRange);
+}
+
+TEST(RcodeTest, getExtendedCode) {
+ EXPECT_EQ(0, Rcode::NOERROR().getExtendedCode());
+ EXPECT_EQ(0, Rcode::YXRRSET().getExtendedCode());
+ EXPECT_EQ(1, Rcode::BADVERS().getExtendedCode());
+ EXPECT_EQ(0xab, Rcode(0xabf).getExtendedCode());
+ EXPECT_EQ(0xff, Rcode(0xfff).getExtendedCode());
+}
+
+TEST(RcodeTest, constants) {
+ // We'll only test arbitrarily chosen subsets of the codes.
+ // This class is quite simple, so it should be suffice.
+
+ EXPECT_EQ(Rcode::NOERROR_CODE, Rcode(0).getCode());
+ EXPECT_EQ(Rcode::FORMERR_CODE, Rcode(1).getCode());
+ EXPECT_EQ(Rcode::NOTIMP_CODE, Rcode(4).getCode());
+ EXPECT_EQ(Rcode::REFUSED_CODE, Rcode(5).getCode());
+ EXPECT_EQ(Rcode::RESERVED15_CODE, Rcode(15).getCode());
+ EXPECT_EQ(Rcode::BADVERS_CODE, Rcode(16).getCode());
+
+ EXPECT_EQ(Rcode::NOERROR_CODE, Rcode::NOERROR().getCode());
+ EXPECT_EQ(Rcode::FORMERR_CODE, Rcode::FORMERR().getCode());
+ EXPECT_EQ(Rcode::NOTIMP_CODE, Rcode::NOTIMP().getCode());
+ EXPECT_EQ(Rcode::REFUSED_CODE, Rcode::REFUSED().getCode());
+ EXPECT_EQ(Rcode::RESERVED15_CODE, Rcode::RESERVED15().getCode());
+ EXPECT_EQ(Rcode::BADVERS_CODE, Rcode::BADVERS().getCode());
+}
+
+TEST(RcodeTest, equal) {
+ EXPECT_TRUE(Rcode::NOERROR() == Rcode(Rcode::NOERROR_CODE));
+ EXPECT_TRUE(Rcode::NOERROR().equals(Rcode(Rcode::NOERROR_CODE)));
+ EXPECT_TRUE(Rcode::FORMERR() == Rcode(Rcode::FORMERR_CODE));
+ EXPECT_TRUE(Rcode::FORMERR().equals(Rcode(Rcode::FORMERR_CODE)));
+ EXPECT_TRUE(Rcode::NOTIMP() == Rcode(Rcode::NOTIMP_CODE));
+ EXPECT_TRUE(Rcode::NOTIMP().equals(Rcode(Rcode::NOTIMP_CODE)));
+ EXPECT_TRUE(Rcode::REFUSED() == Rcode(Rcode::REFUSED_CODE));
+ EXPECT_TRUE(Rcode::REFUSED().equals(Rcode(Rcode::REFUSED_CODE)));
+ EXPECT_TRUE(Rcode::RESERVED15() == Rcode(Rcode::RESERVED15()));
+ EXPECT_TRUE(Rcode::RESERVED15().equals(Rcode(Rcode::RESERVED15())));
+ EXPECT_TRUE(Rcode::BADVERS() == Rcode(Rcode::BADVERS_CODE));
+ EXPECT_TRUE(Rcode::BADVERS().equals(Rcode(Rcode::BADVERS_CODE)));
+}
+
+TEST(RcodeTest, nequal) {
+ EXPECT_TRUE(Rcode::NOERROR() != Rcode::FORMERR());
+ EXPECT_TRUE(Rcode::NOERROR().nequals(Rcode::FORMERR()));
+ EXPECT_TRUE(Rcode::NOTIMP() != Rcode(1));
+ EXPECT_TRUE(Rcode::NOTIMP().nequals(Rcode(1)));
+ EXPECT_TRUE(Rcode(10) != Rcode(11));
+ EXPECT_TRUE(Rcode(10).nequals(Rcode(11)));
+}
+
+TEST(RcodeTest, toText) {
+ vector<const char*> expects;
+ expects.resize(Rcode::BADVERS_CODE + 1);
+ expects[Rcode::NOERROR_CODE] = "NOERROR";
+ expects[Rcode::FORMERR_CODE] = "FORMERR";
+ expects[Rcode::SERVFAIL_CODE] = "SERVFAIL";
+ expects[Rcode::NXDOMAIN_CODE] = "NXDOMAIN";
+ expects[Rcode::NOTIMP_CODE] = "NOTIMP";
+ expects[Rcode::REFUSED_CODE] = "REFUSED";
+ expects[Rcode::YXDOMAIN_CODE] = "YXDOMAIN";
+ expects[Rcode::YXRRSET_CODE] = "YXRRSET";
+ expects[Rcode::NXRRSET_CODE] = "NXRRSET";
+ expects[Rcode::NOTAUTH_CODE] = "NOTAUTH";
+ expects[Rcode::NOTZONE_CODE] = "NOTZONE";
+ expects[Rcode::RESERVED11_CODE] = "RESERVED11";
+ expects[Rcode::RESERVED12_CODE] = "RESERVED12";
+ expects[Rcode::RESERVED13_CODE] = "RESERVED13";
+ expects[Rcode::RESERVED14_CODE] = "RESERVED14";
+ expects[Rcode::RESERVED15_CODE] = "RESERVED15";
+ expects[Rcode::BADVERS_CODE] = "BADVERS";
+
+ for (unsigned int i = 0; i <= Rcode::BADVERS_CODE; ++i) {
+ EXPECT_EQ(expects.at(i), Rcode(i).toText());
+ }
+
+ // Non well-known Rcodes
+ EXPECT_EQ("17", Rcode(Rcode::BADVERS().getCode() + 1).toText());
+ EXPECT_EQ("4095", Rcode(Rcode(0xfff)).toText());
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST(RcodeTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << Rcode::SERVFAIL();
+ EXPECT_EQ(Rcode::SERVFAIL().toText(), oss.str());
+}
+}
diff --git a/src/lib/dns/tests/rdata_afsdb_unittest.cc b/src/lib/dns/tests/rdata_afsdb_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_afsdb_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_caa_unittest.cc b/src/lib/dns/tests/rdata_caa_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_caa_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_char_string_data_unittest.cc b/src/lib/dns/tests/rdata_char_string_data_unittest.cc
index 8b13789179..d4da8420a2 100644
--- a/src/lib/dns/tests/rdata_char_string_data_unittest.cc
+++ b/src/lib/dns/tests/rdata_char_string_data_unittest.cc
@@ -1 +1,181 @@
+// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <util/unittests/wiredata.h>
+
+#include <dns/exceptions.h>
+#include <dns/rdata.h>
+#include <dns/char_string.h>
+#include <util/buffer.h>
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <vector>
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using isc::dns::rdata::generic::detail::CharStringData;
+using isc::dns::rdata::generic::detail::stringToCharStringData;
+using isc::dns::rdata::generic::detail::charStringDataToString;
+using isc::dns::rdata::generic::detail::compareCharStringDatas;
+using isc::util::unittests::matchWireData;
+
+namespace {
+const uint8_t test_charstr[] = {
+ 'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'
+};
+
+class CharStringDataTest : public ::testing::Test {
+protected:
+ CharStringDataTest() :
+ // char-string representation for test data using two types of escape
+ // ('r' = 114)
+ test_str("Test\\ St\\114ing")
+ {
+ str_region.beg = &test_str[0];
+ str_region.len = test_str.size();
+ }
+ CharStringData chstr; // place holder
+ const std::string test_str;
+ MasterToken::StringRegion str_region;
+};
+
+MasterToken::StringRegion
+createStringRegion(const std::string& str) {
+ MasterToken::StringRegion region;
+ region.beg = &str[0]; // note std ensures this works even if str is empty
+ region.len = str.size();
+ return (region);
+}
+
+TEST_F(CharStringDataTest, normalConversion) {
+ uint8_t tmp[3]; // placeholder for expected sequence
+
+ stringToCharStringData(str_region, chstr);
+ matchWireData(test_charstr, sizeof(test_charstr), &chstr[0], chstr.size());
+
+ // Empty string
+ chstr.clear();
+ stringToCharStringData(createStringRegion(""), chstr);
+ EXPECT_TRUE(chstr.empty());
+
+ // Possible largest char string
+ chstr.clear();
+ std::string long_str(255, 'x');
+ stringToCharStringData(createStringRegion(long_str), chstr);
+ std::vector<uint8_t> expected;
+ expected.insert(expected.end(), long_str.begin(), long_str.end());
+ matchWireData(&expected[0], expected.size(), &chstr[0], chstr.size());
+
+ // Escaped '\'
+ chstr.clear();
+ tmp[0] = '\\';
+ stringToCharStringData(createStringRegion("\\\\"), chstr);
+ matchWireData(tmp, 1, &chstr[0], chstr.size());
+
+ // Boundary values for \DDD
+ chstr.clear();
+ tmp[0] = 0;
+ stringToCharStringData(createStringRegion("\\000"), chstr);
+ matchWireData(tmp, 1, &chstr[0], chstr.size());
+
+ chstr.clear();
+ stringToCharStringData(createStringRegion("\\255"), chstr);
+ tmp[0] = 255;
+ matchWireData(tmp, 1, &chstr[0], chstr.size());
+
+ // Another digit follows DDD; it shouldn't cause confusion
+ chstr.clear();
+ stringToCharStringData(createStringRegion("\\2550"), chstr);
+ tmp[1] = '0';
+ matchWireData(tmp, 2, &chstr[0], chstr.size());
+}
+
+TEST_F(CharStringDataTest, badConversion) {
+ // input string ending with (non escaped) '\'
+ chstr.clear();
+ EXPECT_THROW(stringToCharStringData(createStringRegion("foo\\"), chstr),
+ InvalidRdataText);
+}
+
+TEST_F(CharStringDataTest, badDDD) {
+ // Check various type of bad form of \DDD
+
+ // Not a number
+ EXPECT_THROW(stringToCharStringData(createStringRegion("\\1a2"), chstr),
+ InvalidRdataText);
+ EXPECT_THROW(stringToCharStringData(createStringRegion("\\12a"), chstr),
+ InvalidRdataText);
+
+ // Not in the range of uint8_t
+ EXPECT_THROW(stringToCharStringData(createStringRegion("\\256"), chstr),
+ InvalidRdataText);
+
+ // Short buffer
+ EXPECT_THROW(stringToCharStringData(createStringRegion("\\42"), chstr),
+ InvalidRdataText);
+}
+
+const struct TestData {
+ const char *data;
+ const char *expected;
+} conversion_data[] = {
+ {"Test\"Test", "Test\\\"Test"},
+ {"Test;Test", "Test\\;Test"},
+ {"Test\\Test", "Test\\\\Test"},
+ {"Test\x1fTest", "Test\\031Test"},
+ {"Test ~ Test", "Test ~ Test"},
+ {"Test\x7fTest", "Test\\127Test"},
+ {NULL, NULL}
+};
+
+TEST_F(CharStringDataTest, charStringDataToString) {
+ for (const TestData* cur = conversion_data; cur->data != NULL; ++cur) {
+ uint8_t idata[32];
+ size_t length = std::strlen(cur->data);
+ ASSERT_LT(length, sizeof(idata));
+ std::memcpy(idata, cur->data, length);
+ const CharStringData test_data(idata, idata + length);
+ EXPECT_EQ(cur->expected, charStringDataToString(test_data));
+ }
+}
+
+TEST_F(CharStringDataTest, compareCharStringData) {
+ CharStringData charstr;
+ CharStringData charstr2;
+ CharStringData charstr_small1;
+ CharStringData charstr_small2;
+ CharStringData charstr_large1;
+ CharStringData charstr_large2;
+ CharStringData charstr_empty;
+
+ stringToCharStringData(createStringRegion("test string"), charstr);
+ stringToCharStringData(createStringRegion("test string"), charstr2);
+ stringToCharStringData(createStringRegion("test strin"), charstr_small1);
+ stringToCharStringData(createStringRegion("test strina"), charstr_small2);
+ stringToCharStringData(createStringRegion("test stringa"), charstr_large1);
+ stringToCharStringData(createStringRegion("test strinz"), charstr_large2);
+
+ EXPECT_EQ(0, compareCharStringDatas(charstr, charstr2));
+ EXPECT_EQ(0, compareCharStringDatas(charstr2, charstr));
+ EXPECT_EQ(1, compareCharStringDatas(charstr, charstr_small1));
+ EXPECT_EQ(1, compareCharStringDatas(charstr, charstr_small2));
+ EXPECT_EQ(-1, compareCharStringDatas(charstr, charstr_large1));
+ EXPECT_EQ(-1, compareCharStringDatas(charstr, charstr_large2));
+ EXPECT_EQ(-1, compareCharStringDatas(charstr_small1, charstr));
+ EXPECT_EQ(-1, compareCharStringDatas(charstr_small2, charstr));
+ EXPECT_EQ(1, compareCharStringDatas(charstr_large1, charstr));
+ EXPECT_EQ(1, compareCharStringDatas(charstr_large2, charstr));
+
+ EXPECT_EQ(-1, compareCharStringDatas(charstr_empty, charstr));
+ EXPECT_EQ(1, compareCharStringDatas(charstr, charstr_empty));
+ EXPECT_EQ(0, compareCharStringDatas(charstr_empty, charstr_empty));
+}
+
+} // unnamed namespace
diff --git a/src/lib/dns/tests/rdata_char_string_unittest.cc b/src/lib/dns/tests/rdata_char_string_unittest.cc
index 8b13789179..607e6afe6b 100644
--- a/src/lib/dns/tests/rdata_char_string_unittest.cc
+++ b/src/lib/dns/tests/rdata_char_string_unittest.cc
@@ -1 +1,246 @@
+// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <util/unittests/wiredata.h>
+
+#include <dns/exceptions.h>
+#include <dns/rdata.h>
+#include <dns/char_string.h>
+#include <util/buffer.h>
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <vector>
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using isc::dns::rdata::generic::detail::CharString;
+using isc::dns::rdata::generic::detail::bufferToCharString;
+using isc::dns::rdata::generic::detail::stringToCharString;
+using isc::dns::rdata::generic::detail::charStringToString;
+using isc::dns::rdata::generic::detail::compareCharStrings;
+using isc::util::unittests::matchWireData;
+
+namespace {
+const uint8_t test_charstr[] = {
+ sizeof("Test String") - 1,
+ 'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'
+};
+
+class CharStringTest : public ::testing::Test {
+protected:
+ CharStringTest() :
+ // char-string representation for test data using two types of escape
+ // ('r' = 114)
+ test_str("Test\\ St\\114ing")
+ {
+ str_region.beg = &test_str[0];
+ str_region.len = test_str.size();
+ }
+ CharString chstr; // place holder
+ const std::string test_str;
+ MasterToken::StringRegion str_region;
+};
+
+MasterToken::StringRegion
+createStringRegion(const std::string& str) {
+ MasterToken::StringRegion region;
+ region.beg = &str[0]; // note std ensures this works even if str is empty
+ region.len = str.size();
+ return (region);
+}
+
+TEST_F(CharStringTest, normalConversion) {
+ uint8_t tmp[3]; // placeholder for expected sequence
+
+ stringToCharString(str_region, chstr);
+ matchWireData(test_charstr, sizeof(test_charstr), &chstr[0], chstr.size());
+
+ // Empty string
+ chstr.clear();
+ stringToCharString(createStringRegion(""), chstr);
+ tmp[0] = 0;
+ matchWireData(tmp, 1, &chstr[0], chstr.size());
+
+ // Possible largest char string
+ chstr.clear();
+ std::string long_str(255, 'x');
+ stringToCharString(createStringRegion(long_str), chstr);
+ std::vector<uint8_t> expected;
+ expected.push_back(255); // len of char string
+ expected.insert(expected.end(), long_str.begin(), long_str.end());
+ matchWireData(&expected[0], expected.size(), &chstr[0], chstr.size());
+
+ // Same data as the previous case, but the original string is longer than
+ // the max; this shouldn't be rejected
+ chstr.clear();
+ long_str.at(254) = '\\'; // replace the last 'x' with '\'
+ long_str.append("120"); // 'x' = 120
+ stringToCharString(createStringRegion(long_str), chstr);
+ matchWireData(&expected[0], expected.size(), &chstr[0], chstr.size());
+
+ // Escaped '\'
+ chstr.clear();
+ tmp[0] = 1;
+ tmp[1] = '\\';
+ stringToCharString(createStringRegion("\\\\"), chstr);
+ matchWireData(tmp, 2, &chstr[0], chstr.size());
+
+ // Boundary values for \DDD
+ chstr.clear();
+ tmp[0] = 1;
+ tmp[1] = 0;
+ stringToCharString(createStringRegion("\\000"), chstr);
+ matchWireData(tmp, 2, &chstr[0], chstr.size());
+
+ chstr.clear();
+ stringToCharString(createStringRegion("\\255"), chstr);
+ tmp[0] = 1;
+ tmp[1] = 255;
+ matchWireData(tmp, 2, &chstr[0], chstr.size());
+
+ // Another digit follows DDD; it shouldn't cause confusion
+ chstr.clear();
+ stringToCharString(createStringRegion("\\2550"), chstr);
+ tmp[0] = 2; // string len is now 2
+ tmp[2] = '0';
+ matchWireData(tmp, 3, &chstr[0], chstr.size());
+}
+
+TEST_F(CharStringTest, badConversion) {
+ // string cannot exceed 255 bytes
+ EXPECT_THROW(stringToCharString(createStringRegion(std::string(256, 'a')),
+ chstr),
+ CharStringTooLong);
+
+ // input string ending with (non escaped) '\'
+ chstr.clear();
+ EXPECT_THROW(stringToCharString(createStringRegion("foo\\"), chstr),
+ InvalidRdataText);
+}
+
+TEST_F(CharStringTest, badDDD) {
+ // Check various type of bad form of \DDD
+
+ // Not a number
+ EXPECT_THROW(stringToCharString(createStringRegion("\\1a2"), chstr),
+ InvalidRdataText);
+ EXPECT_THROW(stringToCharString(createStringRegion("\\12a"), chstr),
+ InvalidRdataText);
+
+ // Not in the range of uint8_t
+ EXPECT_THROW(stringToCharString(createStringRegion("\\256"), chstr),
+ InvalidRdataText);
+
+ // Short buffer
+ EXPECT_THROW(stringToCharString(createStringRegion("\\42"), chstr),
+ InvalidRdataText);
+}
+
+const struct TestData {
+ const char *data;
+ const char *expected;
+} conversion_data[] = {
+ {"Test\"Test", "Test\\\"Test"},
+ {"Test;Test", "Test\\;Test"},
+ {"Test\\Test", "Test\\\\Test"},
+ {"Test\x1fTest", "Test\\031Test"},
+ {"Test ~ Test", "Test ~ Test"},
+ {"Test\x7fTest", "Test\\127Test"},
+ {NULL, NULL}
+};
+
+TEST_F(CharStringTest, charStringToString) {
+ for (const TestData* cur = conversion_data; cur->data != NULL; ++cur) {
+ uint8_t idata[32];
+ size_t length = std::strlen(cur->data);
+ // length (1 byte) + string (length bytes)
+ assert(sizeof(idata) > length);
+ idata[0] = static_cast<uint8_t>(length);
+ std::memcpy(idata + 1, cur->data, length);
+ const CharString test_data(idata, idata + length + 1);
+ EXPECT_EQ(cur->expected, charStringToString(test_data));
+ }
+}
+
+TEST_F(CharStringTest, bufferToCharString) {
+ const size_t chstr_size = sizeof(test_charstr);
+ isc::util::InputBuffer buf(test_charstr, chstr_size);
+ size_t read = bufferToCharString(buf, chstr_size, chstr);
+
+ EXPECT_EQ(chstr_size, read);
+ EXPECT_EQ("Test String", charStringToString(chstr));
+}
+
+TEST_F(CharStringTest, bufferToCharString_bad) {
+ const size_t chstr_size = sizeof(test_charstr);
+ isc::util::InputBuffer buf(test_charstr, chstr_size);
+ // Set valid data in both so we can make sure the charstr is not
+ // modified
+ bufferToCharString(buf, chstr_size, chstr);
+ ASSERT_EQ("Test String", charStringToString(chstr));
+
+ // Should be at end of buffer now, so it should fail
+ EXPECT_THROW(bufferToCharString(buf, chstr_size - 1, chstr),
+ DNSMessageFORMERR);
+ EXPECT_EQ("Test String", charStringToString(chstr));
+
+ // reset and try to read with too low rdata_len
+ buf.setPosition(0);
+ EXPECT_THROW(bufferToCharString(buf, chstr_size - 1, chstr),
+ DNSMessageFORMERR);
+ EXPECT_EQ("Test String", charStringToString(chstr));
+
+ // set internal charstring len too high
+ const uint8_t test_charstr_err[] = {
+ sizeof("Test String") + 1,
+ 'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'
+ };
+ buf = isc::util::InputBuffer(test_charstr_err, sizeof(test_charstr_err));
+ EXPECT_THROW(bufferToCharString(buf, chstr_size, chstr),
+ DNSMessageFORMERR);
+ EXPECT_EQ("Test String", charStringToString(chstr));
+
+}
+
+
+
+TEST_F(CharStringTest, compareCharString) {
+ CharString charstr;
+ CharString charstr2;
+ CharString charstr_small1;
+ CharString charstr_small2;
+ CharString charstr_large1;
+ CharString charstr_large2;
+ CharString charstr_empty;
+
+ stringToCharString(createStringRegion("test string"), charstr);
+ stringToCharString(createStringRegion("test string"), charstr2);
+ stringToCharString(createStringRegion("test strin"), charstr_small1);
+ stringToCharString(createStringRegion("test strina"), charstr_small2);
+ stringToCharString(createStringRegion("test stringa"), charstr_large1);
+ stringToCharString(createStringRegion("test strinz"), charstr_large2);
+
+ EXPECT_EQ(0, compareCharStrings(charstr, charstr2));
+ EXPECT_EQ(0, compareCharStrings(charstr2, charstr));
+ EXPECT_EQ(1, compareCharStrings(charstr, charstr_small1));
+ EXPECT_EQ(1, compareCharStrings(charstr, charstr_small2));
+ EXPECT_EQ(-1, compareCharStrings(charstr, charstr_large1));
+ EXPECT_EQ(-1, compareCharStrings(charstr, charstr_large2));
+ EXPECT_EQ(-1, compareCharStrings(charstr_small1, charstr));
+ EXPECT_EQ(-1, compareCharStrings(charstr_small2, charstr));
+ EXPECT_EQ(1, compareCharStrings(charstr_large1, charstr));
+ EXPECT_EQ(1, compareCharStrings(charstr_large2, charstr));
+
+ EXPECT_EQ(-1, compareCharStrings(charstr_empty, charstr));
+ EXPECT_EQ(1, compareCharStrings(charstr, charstr_empty));
+ EXPECT_EQ(0, compareCharStrings(charstr_empty, charstr_empty));
+}
+
+} // unnamed namespace
diff --git a/src/lib/dns/tests/rdata_cname_unittest.cc b/src/lib/dns/tests/rdata_cname_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_cname_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_dhcid_unittest.cc b/src/lib/dns/tests/rdata_dhcid_unittest.cc
index 8b13789179..c2cedee57c 100644
--- a/src/lib/dns/tests/rdata_dhcid_unittest.cc
+++ b/src/lib/dns/tests/rdata_dhcid_unittest.cc
@@ -1 +1,165 @@
+// Copyright (C) 2011-2024 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <dns/rdataclass.h>
+#include <util/encode/encode.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+#include <dns/tests/rdata_unittest.h>
+#include <util/unittests/wiredata.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::util::encode;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+namespace {
+
+class Rdata_DHCID_Test : public RdataTest {
+protected:
+ Rdata_DHCID_Test() :
+ dhcid_txt("0LIg0LvQtdGB0YMg0YDQvtC00LjQu9Cw0YHRjCDRkdC70L7Rh9C60LA="),
+ rdata_dhcid(dhcid_txt)
+ {}
+
+ void checkFromText_None(const string& rdata_str) {
+ checkFromText<in::DHCID, isc::Exception, isc::Exception>(
+ rdata_str, rdata_dhcid, false, false);
+ }
+
+ void checkFromText_BadValue(const string& rdata_str) {
+ checkFromText<in::DHCID, BadValue, BadValue>(
+ rdata_str, rdata_dhcid, true, true);
+ }
+
+ void checkFromText_LexerError(const string& rdata_str) {
+ checkFromText
+ <in::DHCID, InvalidRdataText, MasterLexer::LexerError>(
+ rdata_str, rdata_dhcid, true, true);
+ }
+
+ void checkFromText_BadString(const string& rdata_str) {
+ checkFromText
+ <in::DHCID, InvalidRdataText, isc::Exception>(
+ rdata_str, rdata_dhcid, true, false);
+ }
+
+ const string dhcid_txt;
+ const in::DHCID rdata_dhcid;
+};
+
+TEST_F(Rdata_DHCID_Test, fromText) {
+ EXPECT_EQ(dhcid_txt, rdata_dhcid.toText());
+
+ // Space in digest data is OK
+ checkFromText_None(
+ "0LIg0LvQtdGB0YMg 0YDQvtC00LjQu9Cw 0YHRjCDRkdC70L7R h9C60LA=");
+
+ // Multi-line digest data is OK, if enclosed in parentheses
+ checkFromText_None(
+ "( 0LIg0LvQtdGB0YMg0YDQvtC00LjQu9Cw\n0YHRjCDRkdC70L7R h9C60LA= )");
+
+ // Trailing garbage. This should cause only the string constructor
+ // to fail, but the lexer constructor must be able to continue
+ // parsing from it.
+ checkFromText_BadString(
+ "0LIg0LvQtdGB0YMg0YDQvtC00LjQu9Cw0YHRjCDRkdC70L7Rh9C60LA="
+ " ; comment\n"
+ "AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=");
+}
+
+TEST_F(Rdata_DHCID_Test, badText) {
+ // missing digest data
+ checkFromText_LexerError("");
+
+ // invalid base64
+ checkFromText_BadValue("EEeeeeeeEEEeeeeeeGaaahAAAAAAAAHHHHHHHHHHH!=");
+
+ // unterminated multi-line base64
+ checkFromText_LexerError(
+ "( 0LIg0LvQtdGB0YMg0YDQvtC00LjQu9Cw\n0YHRjCDRkdC70L7R h9C60LA=");
+}
+
+TEST_F(Rdata_DHCID_Test, copy) {
+ const in::DHCID rdata_dhcid2(rdata_dhcid);
+ EXPECT_EQ(0, rdata_dhcid.compare(rdata_dhcid2));
+}
+
+TEST_F(Rdata_DHCID_Test, createFromWire) {
+ EXPECT_EQ(0, rdata_dhcid.compare(
+ *rdataFactoryFromFile(RRType("DHCID"), RRClass("IN"),
+ "rdata_dhcid_fromWire")));
+
+ InputBuffer buffer(NULL, 0);
+ EXPECT_THROW(in::DHCID(buffer, 0), InvalidRdataLength);
+
+ // TBD: more tests
+}
+
+TEST_F(Rdata_DHCID_Test, createFromLexer) {
+ EXPECT_EQ(0, rdata_dhcid.compare(
+ *test::createRdataUsingLexer(RRType::DHCID(), RRClass::IN(),
+ dhcid_txt)));
+}
+
+TEST_F(Rdata_DHCID_Test, toWireRenderer) {
+ rdata_dhcid.toWire(renderer);
+
+ vector<unsigned char> data;
+ UnitTestUtil::readWireData("rdata_dhcid_toWire", data);
+ matchWireData(&data[0], data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(Rdata_DHCID_Test, toWireBuffer) {
+ rdata_dhcid.toWire(obuffer);
+
+ vector<unsigned char> data;
+ UnitTestUtil::readWireData("rdata_dhcid_toWire", data);
+ matchWireData(&data[0], data.size(),
+ obuffer.getData(), obuffer.getLength());
+}
+
+TEST_F(Rdata_DHCID_Test, toText) {
+ EXPECT_EQ(dhcid_txt, rdata_dhcid.toText());
+}
+
+TEST_F(Rdata_DHCID_Test, getDHCIDDigest) {
+ const string dhcid_txt1(encodeBase64(rdata_dhcid.getDigest()));
+
+ EXPECT_EQ(dhcid_txt, dhcid_txt1);
+}
+
+TEST_F(Rdata_DHCID_Test, compare) {
+ // trivial case: self equivalence
+ // cppcheck-suppress uselessCallsCompare
+ EXPECT_EQ(0, rdata_dhcid.compare(rdata_dhcid));
+
+ in::DHCID rdata_dhcid1("0YLQvtC/0L7Qu9GPINC00LLQsCDRgNGD0LHQu9GP");
+ in::DHCID rdata_dhcid2("0YLQvtC/0L7Qu9GPINGC0YDQuCDRgNGD0LHQu9GP");
+ in::DHCID rdata_dhcid3("0YLQvtC/0L7Qu9GPINGH0LXRgtGL0YDQtSDRgNGD0LHQu9GP");
+
+ EXPECT_LT(rdata_dhcid1.compare(rdata_dhcid2), 0);
+ EXPECT_GT(rdata_dhcid2.compare(rdata_dhcid1), 0);
+
+ EXPECT_LT(rdata_dhcid2.compare(rdata_dhcid3), 0);
+ EXPECT_GT(rdata_dhcid3.compare(rdata_dhcid2), 0);
+
+ // comparison attempt between incompatible RR types should be rejected
+ EXPECT_THROW(rdata_dhcid.compare(*rdata_nomatch), bad_cast);
+}
+}
diff --git a/src/lib/dns/tests/rdata_dname_unittest.cc b/src/lib/dns/tests/rdata_dname_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_dname_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_dnskey_unittest.cc b/src/lib/dns/tests/rdata_dnskey_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_dnskey_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_ds_like_unittest.cc b/src/lib/dns/tests/rdata_ds_like_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_ds_like_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_hinfo_unittest.cc b/src/lib/dns/tests/rdata_hinfo_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_hinfo_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_in_a_unittest.cc b/src/lib/dns/tests/rdata_in_a_unittest.cc
index 8b13789179..809cfb5bd4 100644
--- a/src/lib/dns/tests/rdata_in_a_unittest.cc
+++ b/src/lib/dns/tests/rdata_in_a_unittest.cc
@@ -1 +1,159 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <dns/rdataclass.h>
+
+#include <util/buffer.h>
+#include <dns/exceptions.h>
+#include <dns/messagerenderer.h>
+#include <dns/master_lexer.h>
+#include <dns/master_loader.h>
+#include <dns/rdata.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+#include <dns/tests/rdata_unittest.h>
+#include <util/unittests/wiredata.h>
+
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+namespace {
+class Rdata_IN_A_Test : public RdataTest {
+protected:
+ Rdata_IN_A_Test() : rdata_in_a("192.0.2.1") {}
+
+ void checkFromTextIN_A(const std::string& rdata_txt,
+ bool throw_str_version = true,
+ bool throw_lexer_version = true) {
+ checkFromText<in::A, InvalidRdataText, InvalidRdataText>(
+ rdata_txt, rdata_in_a, throw_str_version, throw_lexer_version);
+ }
+
+ const in::A rdata_in_a;
+};
+
+const uint8_t wiredata_in_a[] = { 192, 0, 2, 1 };
+
+TEST_F(Rdata_IN_A_Test, createFromText) {
+ // Normal case: no exception for either case, so the exception type
+ // doesn't matter.
+ checkFromText<in::A, isc::Exception, isc::Exception>("192.0.2.1",
+ rdata_in_a, false,
+ false);
+
+ // should reject an abbreviated form of IPv4 address
+ checkFromTextIN_A("10.1");
+ // or an IPv6 address
+ checkFromTextIN_A("2001:db8::1234");
+ // or any meaningless text as an IP address
+ checkFromTextIN_A("xxx");
+
+ // NetBSD's inet_pton accepts trailing space after an IPv4 address, which
+ // would confuse some of the tests below. We check the case differently
+ // in these cases depending on the strictness of inet_pton (most
+ // implementations seem to be stricter).
+ uint8_t v4addr_buf[4];
+ const bool reject_extra_space =
+ inet_pton(AF_INET, "192.0.2.1 ", v4addr_buf) == 0;
+
+ // trailing white space: only string version throws
+ checkFromTextIN_A("192.0.2.1 ", reject_extra_space, false);
+ // same for beginning white space.
+ checkFromTextIN_A(" 192.0.2.1", true, false);
+ // same for trailing non-space garbage (note that lexer version still
+ // ignore it; it's expected to be detected at a higher layer).
+ checkFromTextIN_A("192.0.2.1 xxx", reject_extra_space, false);
+
+ // nul character after a valid textual representation.
+ string nul_after_addr = "192.0.2.1";
+ nul_after_addr.push_back(0);
+ checkFromTextIN_A(nul_after_addr, true, true);
+
+ // a valid address surrounded by parentheses; only okay with lexer
+ checkFromTextIN_A("(192.0.2.1)", true, false);
+
+ // input that would cause lexer-specific error; it's bad text as an
+ // address so should result in the string version, too.
+ checkFromText<in::A, InvalidRdataText, MasterLexer::LexerError>(
+ ")192.0.2.1", rdata_in_a);
+}
+
+TEST_F(Rdata_IN_A_Test, createFromWire) {
+ // Valid data
+ EXPECT_EQ(0, rdata_in_a.compare(
+ *rdataFactoryFromFile(RRType::A(), RRClass::IN(),
+ "rdata_in_a_fromWire")));
+ // RDLENGTH is too short
+ EXPECT_THROW(rdataFactoryFromFile(RRType::A(), RRClass::IN(),
+ "rdata_in_a_fromWire", 6),
+ DNSMessageFORMERR);
+ // RDLENGTH is too long
+ EXPECT_THROW(rdataFactoryFromFile(RRType::A(), RRClass::IN(),
+ "rdata_in_a_fromWire", 12),
+ DNSMessageFORMERR);
+ // buffer too short.
+ EXPECT_THROW(rdataFactoryFromFile(RRType::A(), RRClass::IN(),
+ "rdata_in_a_fromWire", 19),
+ DNSMessageFORMERR);
+}
+
+TEST_F(Rdata_IN_A_Test, toWireBuffer) {
+ rdata_in_a.toWire(obuffer);
+ matchWireData(wiredata_in_a, sizeof (wiredata_in_a),
+ obuffer.getData(), obuffer.getLength());
+}
+
+TEST_F(Rdata_IN_A_Test, toWireRenderer) {
+ rdata_in_a.toWire(renderer);
+ matchWireData(wiredata_in_a, sizeof (wiredata_in_a),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(Rdata_IN_A_Test, toText) {
+ EXPECT_EQ("192.0.2.1", rdata_in_a.toText());
+
+ // this shouldn't make the code crash
+ const string longaddr("255.255.255.255");
+ EXPECT_EQ(longaddr, in::A(longaddr).toText());
+}
+
+TEST_F(Rdata_IN_A_Test, compare) {
+ const in::A small1("1.1.1.1");
+ const in::A small2("1.2.3.4");
+ const in::A large1("255.255.255.255");
+ const in::A large2("4.3.2.1");
+
+ // trivial case: self equivalence
+ // cppcheck-suppress uselessCallsCompare
+ EXPECT_EQ(0, small1.compare(small1));
+
+ // confirm these are compared as unsigned values
+ EXPECT_GT(0, small1.compare(large1));
+ EXPECT_LT(0, large1.compare(small1));
+
+ // confirm these are compared in network byte order
+ EXPECT_GT(0, small2.compare(large2));
+ EXPECT_LT(0, large2.compare(small2));
+
+ // comparison attempt between incompatible RR types should be rejected
+ EXPECT_THROW(rdata_in_a.compare(*RdataTest::rdata_nomatch), bad_cast);
+}
+}
diff --git a/src/lib/dns/tests/rdata_in_aaaa_unittest.cc b/src/lib/dns/tests/rdata_in_aaaa_unittest.cc
index 8b13789179..cc7b07d8c6 100644
--- a/src/lib/dns/tests/rdata_in_aaaa_unittest.cc
+++ b/src/lib/dns/tests/rdata_in_aaaa_unittest.cc
@@ -1 +1,151 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <util/buffer.h>
+#include <dns/exceptions.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+#include <dns/tests/rdata_unittest.h>
+#include <util/unittests/wiredata.h>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+namespace {
+class Rdata_IN_AAAA_Test : public RdataTest {
+protected:
+ Rdata_IN_AAAA_Test() : rdata_in_aaaa("2001:db8::1234") {}
+
+ // Common check to see the result of in::A Rdata construction either from
+ // std::string or with MasterLexer object. If it's expected to succeed
+ // the result should be identical to the commonly used test data
+ // (rdata_in_a); otherwise it should result in the exception specified as
+ // the template parameter.
+ void checkFromTextIN_AAAA(const string& in_aaaa_txt,
+ bool throw_str_version = true,
+ bool throw_lexer_version = true)
+ {
+ checkFromText<in::AAAA, InvalidRdataText, InvalidRdataText>(
+ in_aaaa_txt, rdata_in_aaaa, throw_str_version,
+ throw_lexer_version);
+ }
+
+ const in::AAAA rdata_in_aaaa;
+};
+
+const uint8_t wiredata_in_aaaa[] = {
+ 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x12, 0x34 };
+
+TEST_F(Rdata_IN_AAAA_Test, createFromText) {
+ // Normal case: no exception for either case, so the exception type
+ // doesn't matter.
+ checkFromText<in::AAAA, isc::Exception, isc::Exception>(
+ "2001:db8::1234", rdata_in_aaaa, false, false);
+
+ // should reject an IP4 address.
+ checkFromTextIN_AAAA("192.0.2.1");
+ // or any meaningless text as an IPv6 address
+ checkFromTextIN_AAAA("xxx");
+
+ // trailing white space: only string version throws
+ checkFromTextIN_AAAA("2001:db8::1234 ", true, false);
+ // same for beginning white space.
+ checkFromTextIN_AAAA(" 2001:db8::1234", true, false);
+ // same for trailing non-space garbage (note that lexer version still
+ // ignore it; it's expected to be detected at a higher layer).
+ checkFromTextIN_AAAA("2001:db8::1234 xxx", true, false);
+
+ // nul character after a valid textual representation.
+ string nul_after_addr = "2001:db8::1234";
+ nul_after_addr.push_back(0);
+ checkFromTextIN_AAAA(nul_after_addr, true, true);
+
+ // a valid address surrounded by parentheses; only okay with lexer
+ checkFromTextIN_AAAA("(2001:db8::1234)", true, false);
+
+ // input that would cause lexer-specific error; it's bad text as an
+ // address so should result in the string version, too.
+ checkFromText<in::AAAA, InvalidRdataText, MasterLexer::LexerError>(
+ ")2001:db8::1234", rdata_in_aaaa);
+}
+
+TEST_F(Rdata_IN_AAAA_Test, createFromWire) {
+ // Valid data
+ EXPECT_EQ(0, rdata_in_aaaa.compare(
+ *rdataFactoryFromFile(RRType::AAAA(), RRClass::IN(),
+ "rdata_in_aaaa_fromWire")));
+ // RDLENGTH is too short
+ EXPECT_THROW(rdataFactoryFromFile(RRType::AAAA(), RRClass::IN(),
+ "rdata_in_aaaa_fromWire", 18),
+ DNSMessageFORMERR);
+ // RDLENGTH is too long
+ EXPECT_THROW(rdataFactoryFromFile(RRType::AAAA(), RRClass::IN(),
+ "rdata_in_aaaa_fromWire", 36),
+ DNSMessageFORMERR);
+ // buffer too short.
+ EXPECT_THROW(rdataFactoryFromFile(RRType::AAAA(), RRClass::IN(),
+ "rdata_in_aaaa_fromWire", 55),
+ DNSMessageFORMERR);
+}
+
+TEST_F(Rdata_IN_AAAA_Test, createFromLexer) {
+ EXPECT_EQ(0, rdata_in_aaaa.compare(
+ *test::createRdataUsingLexer(RRType::AAAA(), RRClass::IN(),
+ "2001:db8::1234")));
+}
+
+TEST_F(Rdata_IN_AAAA_Test, toWireBuffer) {
+ rdata_in_aaaa.toWire(obuffer);
+ matchWireData(wiredata_in_aaaa, sizeof (wiredata_in_aaaa),
+ obuffer.getData(), obuffer.getLength());
+}
+
+TEST_F(Rdata_IN_AAAA_Test, toWireRenderer) {
+ rdata_in_aaaa.toWire(renderer);
+ matchWireData(wiredata_in_aaaa, sizeof (wiredata_in_aaaa),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(Rdata_IN_AAAA_Test, toText) {
+ EXPECT_EQ("2001:db8::1234", rdata_in_aaaa.toText());
+}
+
+TEST_F(Rdata_IN_AAAA_Test, compare) {
+ in::AAAA small1("::1");
+ in::AAAA small2("1:2:3:4:5:6:7:8");
+ in::AAAA large1("ffff::");
+ in::AAAA large2("8:7:6:5:4:3:2:1");
+
+ // trivial case: self equivalence
+ // cppcheck-suppress uselessCallsCompare
+ EXPECT_EQ(0, small1.compare(small1));
+
+ // confirm these are compared as unsigned values
+ EXPECT_GT(0, small1.compare(large1));
+ EXPECT_LT(0, large1.compare(small1));
+
+ // confirm these are compared in network byte order
+ EXPECT_GT(0, small2.compare(large2));
+ EXPECT_LT(0, large2.compare(small2));
+
+ // comparison attempt between incompatible RR types should be rejected
+ EXPECT_THROW(rdata_in_aaaa.compare(*RdataTest::rdata_nomatch), bad_cast);
+}
+}
diff --git a/src/lib/dns/tests/rdata_minfo_unittest.cc b/src/lib/dns/tests/rdata_minfo_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_minfo_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_mx_unittest.cc b/src/lib/dns/tests/rdata_mx_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_mx_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_naptr_unittest.cc b/src/lib/dns/tests/rdata_naptr_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_naptr_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_ns_unittest.cc b/src/lib/dns/tests/rdata_ns_unittest.cc
index 8b13789179..80123ae937 100644
--- a/src/lib/dns/tests/rdata_ns_unittest.cc
+++ b/src/lib/dns/tests/rdata_ns_unittest.cc
@@ -1 +1,145 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <dns/exceptions.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/tests/unittest_util.h>
+#include <dns/tests/rdata_unittest.h>
+#include <util/unittests/wiredata.h>
+#include <util/buffer.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::util;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+using namespace std;
+
+namespace {
+class Rdata_NS_Test : public RdataTest {
+public:
+ Rdata_NS_Test() :
+ rdata_ns("ns.example.com."),
+ rdata_ns2("ns2.example.com.") {
+ }
+
+ const generic::NS rdata_ns;
+ const generic::NS rdata_ns2;
+};
+
+const uint8_t wiredata_ns[] = {
+ 0x02, 0x6e, 0x73, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03,
+ 0x63, 0x6f, 0x6d, 0x00 };
+const uint8_t wiredata_ns2[] = {
+ // first name: ns.example.com.
+ 0x02, 0x6e, 0x73, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03,
+ 0x63, 0x6f, 0x6d, 0x00,
+ // second name: ns2.example.com. all labels except the first should be
+ // compressed.
+ 0x03, 0x6e, 0x73, 0x32, 0xc0, 0x03 };
+
+TEST_F(Rdata_NS_Test, createFromText) {
+ EXPECT_EQ(0, rdata_ns.compare(generic::NS("ns.example.com.")));
+ // explicitly add a trailing dot. should be the same RDATA.
+ EXPECT_EQ(0, rdata_ns.compare(generic::NS("ns.example.com.")));
+ // should be case sensitive.
+ EXPECT_EQ(0, rdata_ns.compare(generic::NS("NS.EXAMPLE.COM.")));
+ // RDATA of a class-independent type should be recognized for any
+ // "unknown" class.
+ EXPECT_EQ(0, rdata_ns.compare(*createRdata(RRType("NS"), RRClass(65000),
+ "ns.example.com.")));
+}
+
+TEST_F(Rdata_NS_Test, badText) {
+ // Extra input at end of line
+ EXPECT_THROW(generic::NS("ns.example.com. extra."), InvalidRdataText);
+}
+
+TEST_F(Rdata_NS_Test, createFromWire) {
+ EXPECT_EQ(0, rdata_ns.compare(
+ *rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
+ "rdata_ns_fromWire")));
+ // RDLENGTH is too short
+ EXPECT_THROW(rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
+ "rdata_ns_fromWire", 18),
+ InvalidRdataLength);
+ // RDLENGTH is too long
+ EXPECT_THROW(rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
+ "rdata_ns_fromWire", 36),
+ InvalidRdataLength);
+ // incomplete name. the error should be detected in the name constructor
+ EXPECT_THROW(rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
+ "rdata_ns_fromWire", 71),
+ DNSMessageFORMERR);
+
+ EXPECT_EQ(0, generic::NS("ns2.example.com.").compare(
+ *rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
+ "rdata_ns_fromWire", 55)));
+ EXPECT_THROW(*rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
+ "rdata_ns_fromWire", 63),
+ InvalidRdataLength);
+}
+
+TEST_F(Rdata_NS_Test, createFromLexer) {
+ EXPECT_EQ(0, rdata_ns.compare(
+ *test::createRdataUsingLexer(RRType::NS(), RRClass::IN(),
+ "ns.example.com.")));
+
+ // test::createRdataUsingLexer() constructs relative to
+ // "example.org." origin.
+ EXPECT_EQ(0, generic::NS("ns8.example.org.").compare(
+ *test::createRdataUsingLexer(RRType::NS(), RRClass::IN(),
+ "ns8")));
+
+ // Exceptions cause NULL to be returned.
+ EXPECT_FALSE(test::createRdataUsingLexer(RRType::NS(), RRClass::IN(),
+ ""));
+
+ // Extra input at end of line
+ EXPECT_FALSE(test::createRdataUsingLexer(RRType::NS(), RRClass::IN(),
+ "ns.example.com. extra."));
+}
+
+TEST_F(Rdata_NS_Test, toWireBuffer) {
+ rdata_ns.toWire(obuffer);
+ matchWireData(wiredata_ns, sizeof(wiredata_ns),
+ obuffer.getData(), obuffer.getLength());
+}
+
+TEST_F(Rdata_NS_Test, toWireRenderer) {
+ rdata_ns.toWire(renderer);
+ matchWireData(wiredata_ns, sizeof(wiredata_ns),
+ renderer.getData(), renderer.getLength());
+
+ rdata_ns2.toWire(renderer);
+ matchWireData(wiredata_ns2, sizeof(wiredata_ns2),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(Rdata_NS_Test, toText) {
+ EXPECT_EQ("ns.example.com.", rdata_ns.toText());
+}
+
+TEST_F(Rdata_NS_Test, compare) {
+ generic::NS small("a.example.");
+ generic::NS large("example.");
+ EXPECT_TRUE(Name("a.example") > Name("example"));
+ EXPECT_GT(0, small.compare(large));
+}
+
+TEST_F(Rdata_NS_Test, getNSName) {
+ EXPECT_EQ(Name("ns.example.com."), rdata_ns.getNSName());
+}
+}
diff --git a/src/lib/dns/tests/rdata_nsec3_unittest.cc b/src/lib/dns/tests/rdata_nsec3_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_nsec3_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_nsec3param_like_unittest.cc b/src/lib/dns/tests/rdata_nsec3param_like_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_nsec3param_like_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_nsec3param_unittest.cc b/src/lib/dns/tests/rdata_nsec3param_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_nsec3param_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_nsec_unittest.cc b/src/lib/dns/tests/rdata_nsec_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_nsec_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_nsecbitmap_unittest.cc b/src/lib/dns/tests/rdata_nsecbitmap_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_nsecbitmap_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_opt_unittest.cc b/src/lib/dns/tests/rdata_opt_unittest.cc
index 8b13789179..6be2d08a39 100644
--- a/src/lib/dns/tests/rdata_opt_unittest.cc
+++ b/src/lib/dns/tests/rdata_opt_unittest.cc
@@ -1 +1,198 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <util/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+#include <dns/tests/rdata_unittest.h>
+#include <util/unittests/wiredata.h>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+namespace {
+class Rdata_OPT_Test : public RdataTest {
+ // there's nothing to specialize
+};
+
+const uint8_t rdata_opt_wiredata[] = {
+ // Option code
+ 0x00, 0x2a,
+ // Option length
+ 0x00, 0x03,
+ // Option data
+ 0x00, 0x01, 0x02
+};
+
+TEST_F(Rdata_OPT_Test, createFromText) {
+ // OPT RR cannot be created from text.
+ EXPECT_THROW(generic::OPT("this does not matter"), InvalidRdataText);
+}
+
+TEST_F(Rdata_OPT_Test, createFromWire) {
+ // Valid cases: in the simple implementation with no supported options,
+ // we can only check these don't throw.
+ EXPECT_NO_THROW(rdataFactoryFromFile(RRType::OPT(), RRClass("CLASS4096"),
+ "rdata_opt_fromWire1"));
+ EXPECT_NO_THROW(rdataFactoryFromFile(RRType::OPT(), RRClass::ANY(),
+ "rdata_opt_fromWire1", 2));
+
+ // Short RDLEN. This throws InvalidRdataLength even if subsequent
+ // pseudo RRs cause RDLEN size to be exhausted.
+ EXPECT_THROW(rdataFactoryFromFile(RRType::OPT(), RRClass::IN(),
+ "rdata_opt_fromWire2"),
+ InvalidRdataLength);
+ EXPECT_THROW(rdataFactoryFromFile(RRType::OPT(), RRClass::IN(),
+ "rdata_opt_fromWire3"),
+ InvalidRdataLength);
+ // Option lengths can add up and overflow RDLEN. Unlikely when
+ // parsed from wire data, but we'll check for it anyway.
+ EXPECT_THROW(rdataFactoryFromFile(RRType::OPT(), RRClass::IN(),
+ "rdata_opt_fromWire4"),
+ InvalidRdataText);
+
+ // short buffer case.
+ EXPECT_THROW(rdataFactoryFromFile(RRType::OPT(), RRClass::IN(),
+ "rdata_opt_fromWire1", 11),
+ InvalidBufferPosition);
+}
+
+TEST_F(Rdata_OPT_Test, createFromLexer) {
+ // OPT RR cannot be created from text. Exceptions cause NULL to be
+ // returned.
+ EXPECT_FALSE(test::createRdataUsingLexer(RRType::OPT(), RRClass::IN(),
+ "this does not matter"));
+}
+
+TEST_F(Rdata_OPT_Test, toWireBuffer) {
+ const generic::OPT rdata_opt =
+ dynamic_cast<const generic::OPT&>
+ (*rdataFactoryFromFile(RRType("OPT"), RRClass("IN"),
+ "rdata_opt_fromWire1", 2));
+
+ obuffer.clear();
+ rdata_opt.toWire(obuffer);
+
+ matchWireData(rdata_opt_wiredata, sizeof(rdata_opt_wiredata),
+ obuffer.getData(), obuffer.getLength());
+}
+
+TEST_F(Rdata_OPT_Test, toWireRenderer) {
+ const generic::OPT rdata_opt =
+ dynamic_cast<const generic::OPT&>
+ (*rdataFactoryFromFile(RRType("OPT"), RRClass("IN"),
+ "rdata_opt_fromWire1", 2));
+
+ renderer.clear();
+ rdata_opt.toWire(renderer);
+
+ matchWireData(rdata_opt_wiredata, sizeof(rdata_opt_wiredata),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(Rdata_OPT_Test, toText) {
+ // empty OPT
+ const generic::OPT rdata_opt;
+
+ EXPECT_THROW(rdata_opt.toText(),
+ isc::InvalidOperation);
+}
+
+TEST_F(Rdata_OPT_Test, compare) {
+ // empty OPT
+ const generic::OPT rdata_opt;
+
+ EXPECT_THROW(rdata_opt.compare(
+ *rdataFactoryFromFile(RRType::OPT(), RRClass::ANY(),
+ "rdata_opt_fromWire1", 2)),
+ isc::InvalidOperation);
+
+ // comparison attempt between incompatible RR types also results in
+ // isc::InvalidOperation.
+ EXPECT_THROW(rdata_opt.compare(*RdataTest::rdata_nomatch),
+ isc::InvalidOperation);
+}
+
+TEST_F(Rdata_OPT_Test, appendPseudoRR) {
+ generic::OPT rdata_opt;
+
+ // Append empty option data
+ rdata_opt.appendPseudoRR(0x0042, NULL, 0);
+
+ // Append simple option data
+ const uint8_t option_data[] = {'H', 'e', 'l', 'l', 'o'};
+ rdata_opt.appendPseudoRR(0x0043, option_data, sizeof(option_data));
+
+ // Duplicate option codes are okay.
+ rdata_opt.appendPseudoRR(0x0042, option_data, sizeof(option_data));
+
+ // When option length may overflow RDLEN, append should throw.
+ const std::vector<uint8_t> buffer((1 << 16) - 1);
+ EXPECT_THROW(rdata_opt.appendPseudoRR(0x0044, &buffer[0], buffer.size()),
+ isc::InvalidParameter);
+
+ const uint8_t rdata_opt_wiredata2[] = {
+ // OPTION #1
+ // ` Option code
+ 0x00, 0x42,
+ // ` Option length
+ 0x00, 0x00,
+
+ // OPTION #2
+ // ` Option code
+ 0x00, 0x43,
+ // ` Option length
+ 0x00, 0x05,
+ // ` Option data
+ 'H', 'e', 'l', 'l', 'o',
+
+ // OPTION #3
+ // ` Option code
+ 0x00, 0x42,
+ // ` Option length
+ 0x00, 0x05,
+ // ` Option data
+ 'H', 'e', 'l', 'l', 'o'
+ };
+
+ obuffer.clear();
+ rdata_opt.toWire(obuffer);
+
+ matchWireData(rdata_opt_wiredata2, sizeof(rdata_opt_wiredata2),
+ obuffer.getData(), obuffer.getLength());
+}
+
+TEST_F(Rdata_OPT_Test, getPseudoRRs) {
+ const generic::OPT rdf =
+ dynamic_cast<const generic::OPT&>
+ (*rdataFactoryFromFile(RRType("OPT"), RRClass("IN"),
+ "rdata_opt_fromWire1", 2));
+
+ const std::vector<generic::OPT::PseudoRR>& rrs = rdf.getPseudoRRs();
+ ASSERT_FALSE(rrs.empty());
+ EXPECT_EQ(1, rrs.size());
+ EXPECT_EQ(0x2a, rrs.at(0).getCode());
+ EXPECT_EQ(3, rrs.at(0).getLength());
+
+ const uint8_t expected_data[] = {0x00, 0x01, 0x02};
+ const uint8_t* actual_data = rrs.at(0).getData();
+ EXPECT_EQ(0, std::memcmp(expected_data, actual_data,
+ sizeof(expected_data)));
+}
+}
diff --git a/src/lib/dns/tests/rdata_pimpl_holder_unittest.cc b/src/lib/dns/tests/rdata_pimpl_holder_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_pimpl_holder_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_ptr_unittest.cc b/src/lib/dns/tests/rdata_ptr_unittest.cc
index 8b13789179..8275ea5fb4 100644
--- a/src/lib/dns/tests/rdata_ptr_unittest.cc
+++ b/src/lib/dns/tests/rdata_ptr_unittest.cc
@@ -1 +1,145 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <util/buffer.h>
+#include <dns/exceptions.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+#include <dns/tests/rdata_unittest.h>
+#include <util/unittests/wiredata.h>
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::util;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+using namespace std;
+//
+// This test currently simply copies the NS RDATA tests.
+//
+
+namespace {
+class Rdata_PTR_Test : public RdataTest {
+public:
+ Rdata_PTR_Test() :
+ rdata_ptr("ns.example.com."),
+ rdata_ptr2("ns2.example.com.") {
+ }
+
+ const generic::PTR rdata_ptr;
+ const generic::PTR rdata_ptr2;
+};
+
+const uint8_t wiredata_ptr[] = {
+ 0x02, 0x6e, 0x73, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03,
+ 0x63, 0x6f, 0x6d, 0x00 };
+const uint8_t wiredata_ptr2[] = {
+ // first name: ns.example.com.
+ 0x02, 0x6e, 0x73, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03,
+ 0x63, 0x6f, 0x6d, 0x00,
+ // second name: ns2.example.com. all labels except the first should be
+ // compressed.
+ 0x03, 0x6e, 0x73, 0x32, 0xc0, 0x03 };
+
+TEST_F(Rdata_PTR_Test, createFromText) {
+ EXPECT_EQ(0, rdata_ptr.compare(generic::PTR("ns.example.com.")));
+ // explicitly add a trailing dot. should be the same RDATA.
+ EXPECT_EQ(0, rdata_ptr.compare(generic::PTR("ns.example.com.")));
+ // should be case sensitive.
+ EXPECT_EQ(0, rdata_ptr.compare(generic::PTR("NS.EXAMPLE.COM.")));
+ // RDATA of a class-independent type should be recognized for any
+ // "unknown" class.
+ EXPECT_EQ(0, rdata_ptr.compare(*createRdata(RRType("PTR"), RRClass(65000),
+ "ns.example.com.")));
+}
+
+TEST_F(Rdata_PTR_Test, badText) {
+ // Extra text at end of line
+ EXPECT_THROW(generic::PTR("foo.example.com. extra."), InvalidRdataText);
+}
+
+TEST_F(Rdata_PTR_Test, createFromWire) {
+ EXPECT_EQ(0, rdata_ptr.compare(
+ *rdataFactoryFromFile(RRType("PTR"), RRClass("IN"),
+ "rdata_ns_fromWire")));
+ // RDLENGTH is too short
+ EXPECT_THROW(rdataFactoryFromFile(RRType("PTR"), RRClass("IN"),
+ "rdata_ns_fromWire", 18),
+ InvalidRdataLength);
+ // RDLENGTH is too long
+ EXPECT_THROW(rdataFactoryFromFile(RRType("PTR"), RRClass("IN"),
+ "rdata_ns_fromWire", 36),
+ InvalidRdataLength);
+ // incomplete name. the error should be detected in the name constructor
+ EXPECT_THROW(rdataFactoryFromFile(RRType("PTR"), RRClass("IN"),
+ "rdata_ns_fromWire", 71),
+ DNSMessageFORMERR);
+
+ EXPECT_EQ(0, generic::PTR("ns2.example.com.").compare(
+ *rdataFactoryFromFile(RRType("PTR"), RRClass("IN"),
+ "rdata_ns_fromWire", 55)));
+ EXPECT_THROW(*rdataFactoryFromFile(RRType("PTR"), RRClass("IN"),
+ "rdata_ns_fromWire", 63),
+ InvalidRdataLength);
+}
+
+TEST_F(Rdata_PTR_Test, createFromLexer) {
+ EXPECT_EQ(0, rdata_ptr.compare(
+ *test::createRdataUsingLexer(RRType::PTR(), RRClass::IN(),
+ "ns.example.com.")));
+
+ // test::createRdataUsingLexer() constructs relative to
+ // "example.org." origin.
+ EXPECT_EQ(0, generic::PTR("foo0.example.org.").compare(
+ *test::createRdataUsingLexer(RRType::PTR(), RRClass::IN(),
+ "foo0")));
+
+ // Extra text at end of line
+ EXPECT_FALSE(test::createRdataUsingLexer(RRType::PTR(), RRClass::IN(),
+ "foo.example.com. extra."));
+}
+
+TEST_F(Rdata_PTR_Test, toWireBuffer) {
+ rdata_ptr.toWire(obuffer);
+ matchWireData(wiredata_ptr, sizeof(wiredata_ptr),
+ obuffer.getData(), obuffer.getLength());
+}
+
+TEST_F(Rdata_PTR_Test, toWireRenderer) {
+ rdata_ptr.toWire(renderer);
+ matchWireData(wiredata_ptr, sizeof(wiredata_ptr),
+ renderer.getData(), renderer.getLength());
+
+ rdata_ptr2.toWire(renderer);
+ matchWireData(wiredata_ptr2, sizeof(wiredata_ptr2),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(Rdata_PTR_Test, toText) {
+ EXPECT_EQ("ns.example.com.", rdata_ptr.toText());
+}
+
+TEST_F(Rdata_PTR_Test, compare) {
+ generic::PTR small("a.example.");
+ generic::PTR large("example.");
+ EXPECT_TRUE(Name("a.example") > Name("example"));
+ EXPECT_GT(0, small.compare(large));
+}
+
+TEST_F(Rdata_PTR_Test, getPTRName) {
+ EXPECT_EQ(Name("ns.example.com"), rdata_ptr.getPTRName());
+}
+}
diff --git a/src/lib/dns/tests/rdata_rp_unittest.cc b/src/lib/dns/tests/rdata_rp_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_rp_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_rrsig_unittest.cc b/src/lib/dns/tests/rdata_rrsig_unittest.cc
index 8b13789179..b198d15c62 100644
--- a/src/lib/dns/tests/rdata_rrsig_unittest.cc
+++ b/src/lib/dns/tests/rdata_rrsig_unittest.cc
@@ -1 +1,369 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <util/time_utilities.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+#include <util/unittests/wiredata.h>
+#include <dns/tests/rdata_unittest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+namespace {
+
+const uint8_t wiredata_rrsig[] = {
+ // type covered = A
+ 0x00, 0x01,
+ // algorithm = 5
+ 0x05,
+ // labels = 4
+ 0x04,
+ // original TTL = 43200 (0x0000a8c0)
+ 0x00, 0x00, 0xa8, 0xc0,
+ // signature expiration = 1266961577 (0x4b844ca9)
+ 0x4b, 0x84, 0x4c, 0xa9,
+ // signature inception = 1266875177 (0x4b82fb29)
+ 0x4b, 0x82, 0xfb, 0x29,
+ // key tag = 8496 (0x2130)
+ 0x21, 0x30,
+ // signer's name (isc.org.)
+ // 3 i s c 3 o r g 0
+ 0x03, 0x69, 0x73, 0x63, 0x03, 0x6f, 0x72, 0x67, 0x00,
+ // signature data follows
+ 0x7a, 0xfc, 0x61, 0x94, 0x6c,
+ 0x75, 0xde, 0x6a, 0x4a, 0x2d, 0x59, 0x0a, 0xb2,
+ 0x3a, 0x46, 0xcf, 0x27, 0x12, 0xe6, 0xdc, 0x2d,
+ 0x22, 0x8c, 0x4e, 0x9a, 0x53, 0x75, 0xe3, 0x0f,
+ 0x6d, 0xe4, 0x08, 0x33, 0x18, 0x19, 0xb3, 0x76,
+ 0x21, 0x9d, 0x2c, 0x8a, 0xc5, 0x69, 0xba, 0xab,
+ 0xef, 0x66, 0x9f, 0xda, 0xb5, 0x2a, 0xf9, 0x40,
+ 0xc1, 0x28, 0xc5, 0x97, 0xba, 0x3c, 0x19, 0x4d,
+ 0x95, 0x13, 0xc2, 0xcd, 0xf6, 0xb1, 0x59, 0x5d,
+ 0x0c, 0xf9, 0x3f, 0x35, 0xbb, 0x9a, 0x70, 0x93,
+ 0x36, 0xe5, 0xf4, 0x17, 0x7e, 0xfe, 0x66, 0x3b,
+ 0x70, 0x1f, 0xed, 0x33, 0xa8, 0xa3, 0x0d, 0xc0,
+ 0x8c, 0xc6, 0x95, 0x1b, 0xd8, 0x9c, 0x8c, 0x25,
+ 0xb4, 0x57, 0x9e, 0x56, 0x71, 0x64, 0x14, 0x7f,
+ 0x8f, 0x6d, 0xfa, 0xc5, 0xca, 0x3f, 0x36, 0xe2,
+ 0xa4, 0xdf, 0x60, 0xfa, 0xcd, 0x59, 0x3e, 0x22,
+ 0x32, 0xa1, 0xf7
+};
+
+class Rdata_RRSIG_Test : public RdataTest {
+protected:
+ Rdata_RRSIG_Test() :
+ rrsig_txt("A 5 4 43200 20100223214617 20100222214617 8496 isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc="),
+ rdata_rrsig(rrsig_txt)
+ {}
+
+ void checkFromText_None(const string& rdata_str) {
+ checkFromText<generic::RRSIG, isc::Exception, isc::Exception>(
+ rdata_str, rdata_rrsig, false, false);
+ }
+
+ void checkFromText_InvalidText(const string& rdata_str) {
+ checkFromText<generic::RRSIG, InvalidRdataText, InvalidRdataText>(
+ rdata_str, rdata_rrsig, true, true);
+ }
+
+ void checkFromText_InvalidType(const string& rdata_str) {
+ checkFromText<generic::RRSIG, InvalidRRType, InvalidRRType>(
+ rdata_str, rdata_rrsig, true, true);
+ }
+
+ void checkFromText_InvalidTime(const string& rdata_str) {
+ checkFromText<generic::RRSIG, InvalidTime, InvalidTime>(
+ rdata_str, rdata_rrsig, true, true);
+ }
+
+ void checkFromText_BadValue(const string& rdata_str) {
+ checkFromText<generic::RRSIG, BadValue, BadValue>(
+ rdata_str, rdata_rrsig, true, true);
+ }
+
+ void checkFromText_LexerError(const string& rdata_str) {
+ checkFromText
+ <generic::RRSIG, InvalidRdataText, MasterLexer::LexerError>(
+ rdata_str, rdata_rrsig, true, true);
+ }
+
+ void checkFromText_MissingOrigin(const string& rdata_str) {
+ checkFromText
+ <generic::RRSIG, MissingNameOrigin, MissingNameOrigin>(
+ rdata_str, rdata_rrsig, true, true);
+ }
+
+ void checkFromText_BadString(const string& rdata_str) {
+ checkFromText
+ <generic::RRSIG, InvalidRdataText, isc::Exception>(
+ rdata_str, rdata_rrsig, true, false);
+ }
+
+ const string rrsig_txt;
+ const generic::RRSIG rdata_rrsig;
+};
+
+TEST_F(Rdata_RRSIG_Test, fromText) {
+ EXPECT_EQ(rrsig_txt, rdata_rrsig.toText());
+ EXPECT_EQ(isc::dns::RRType::A(), rdata_rrsig.typeCovered());
+
+ // Missing signature is OK
+ EXPECT_NO_THROW(const generic::RRSIG sig(
+ "A 5 4 43200 20100223214617 20100222214617 8496 isc.org."));
+
+ // Space in signature data is OK
+ checkFromText_None(
+ "A 5 4 43200 20100223214617 20100222214617 8496 isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz "
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/ "
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU "
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+
+ // Multi-line signature data is OK, if enclosed in parentheses
+ checkFromText_None(
+ "A 5 4 43200 20100223214617 20100222214617 8496 isc.org. "
+ "( evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz\n"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/\n"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU\n"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc= )");
+
+ // Trailing garbage. This should cause only the string constructor
+ // to fail, but the lexer constructor must be able to continue
+ // parsing from it.
+ checkFromText_BadString(
+ "A 5 4 43200 20100223214617 20100222214617 8496 isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc= ; comment\n"
+ "A 5 4 43200 20100223214617 20100222214617 8496 isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_missingFields) {
+ checkFromText_LexerError("A");
+ checkFromText_LexerError("A 5");
+ checkFromText_LexerError("A 5 4");
+ checkFromText_LexerError("A 5 4 43200");
+ checkFromText_LexerError("A 5 4 43200 20100223214617");
+ checkFromText_LexerError("A 5 4 43200 20100223214617 20100222214617");
+ checkFromText_LexerError("A 5 4 43200 20100223214617 20100222214617 "
+ "8496");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_coveredType) {
+ checkFromText_InvalidType("SPORK");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_algorithm) {
+ checkFromText_InvalidText(
+ "A 555 4 43200 "
+ "20100223214617 20100222214617 8496 isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+ checkFromText_LexerError(
+ "A FIVE 4 43200 "
+ "20100223214617 20100222214617 8496 isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_labels) {
+ checkFromText_InvalidText(
+ "A 5 4444 43200 "
+ "20100223214617 20100222214617 8496 isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+ checkFromText_LexerError(
+ "A 5 FOUR 43200 "
+ "20100223214617 20100222214617 8496 isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_ttl) {
+ checkFromText_LexerError(
+ "A 5 4 999999999999 "
+ "20100223214617 20100222214617 8496 isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+ checkFromText_LexerError(
+ "A 5 4 TTL "
+ "20100223214617 20100222214617 8496 isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+
+ // alternate form of TTL is not okay
+ checkFromText_LexerError(
+ "A 5 4 12H 20100223214617 20100222214617 8496 isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz "
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/ "
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU "
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_expiration) {
+ checkFromText_InvalidTime(
+ "A 5 4 43200 "
+ "201002232 20100222214617 8496 isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+ checkFromText_InvalidTime(
+ "A 5 4 43200 "
+ "EXPIRATION 20100222214617 8496 isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_inception) {
+ checkFromText_InvalidTime(
+ "A 5 4 43200 "
+ "20100223214617 20100227 8496 isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+ checkFromText_InvalidTime(
+ "A 5 4 43200 "
+ "20100223214617 INCEPTION 8496 isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_keytag) {
+ checkFromText_InvalidText(
+ "A 5 4 43200 "
+ "20100223214617 20100222214617 999999 isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+ checkFromText_LexerError(
+ "A 5 4 43200 "
+ "20100223214617 20100222214617 TAG isc.org. "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_signer) {
+ checkFromText_MissingOrigin(
+ "A 5 4 43200 "
+ "20100223214617 20100222214617 8496 isc.org "
+ "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_signature) {
+ checkFromText_BadValue(
+ "A 5 4 43200 "
+ "20100223214617 20100222214617 8496 isc.org. "
+ "EEeeeeeeEEEeeeeeeGaaahAAAAAAAAHHHHHHHHHHH!=");
+
+ // no space between the tag and signer
+ checkFromText_LexerError(
+ "A 5 4 43200 20100223214617 20100222214617 "
+ "8496isc.org. ofc=");
+
+ // unterminated multi-line base64
+ checkFromText_LexerError(
+ "A 5 4 43200 20100223214617 20100222214617 8496 isc.org. "
+ "( evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz\n"
+ "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/\n"
+ "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU\n"
+ "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+}
+
+TEST_F(Rdata_RRSIG_Test, createFromLexer) {
+ EXPECT_EQ(0, rdata_rrsig.compare(
+ *test::createRdataUsingLexer(RRType::RRSIG(), RRClass::IN(),
+ rrsig_txt)));
+
+ // Exceptions cause NULL to be returned.
+ EXPECT_FALSE(test::createRdataUsingLexer(RRType::RRSIG(), RRClass::IN(),
+ "INVALIDINPUT"));
+}
+
+TEST_F(Rdata_RRSIG_Test, toWireRenderer) {
+ rdata_rrsig.toWire(renderer);
+
+ matchWireData(wiredata_rrsig, sizeof(wiredata_rrsig),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(Rdata_RRSIG_Test, toWireBuffer) {
+ rdata_rrsig.toWire(obuffer);
+
+ matchWireData(wiredata_rrsig, sizeof(wiredata_rrsig),
+ obuffer.getData(), obuffer.getLength());
+}
+
+TEST_F(Rdata_RRSIG_Test, createFromWire) {
+ const string rrsig_txt2(
+ "A 5 2 43200 20100327070149 20100225070149 2658 isc.org. "
+ "HkJk/xZTvzePU8NENl/ley8bbUumhk1hXciyqhLnz1VQFzkDooej6neX"
+ "ZgWZzQKeTKPOYWrnYtdZW4PnPQFeUl3orgLev7F8J6FZlDn0y/J/ThR5"
+ "m36Mo2/Gdxjj8lJ/IjPVkdpKyBpcnYND8KEIma5MyNCNeyO1UkfPQZGHNSQ=");
+ EXPECT_EQ(rrsig_txt2,
+ rdataFactoryFromFile(RRType("RRSIG"), RRClass("IN"),
+ "rdata_rrsig_fromWire1")->toText());
+ const generic::RRSIG rdata_rrsig2(rrsig_txt2);
+ EXPECT_EQ(0, rdata_rrsig2.compare(
+ *rdataFactoryFromFile(RRType("RRSIG"), RRClass("IN"),
+ "rdata_rrsig_fromWire1")));
+
+ // RDLEN is too short
+ EXPECT_THROW(rdataFactoryFromFile(RRType::RRSIG(), RRClass::IN(),
+ "rdata_rrsig_fromWire2.wire"),
+ InvalidRdataLength);
+}
+}
diff --git a/src/lib/dns/tests/rdata_soa_unittest.cc b/src/lib/dns/tests/rdata_soa_unittest.cc
index 8b13789179..21f4dc4854 100644
--- a/src/lib/dns/tests/rdata_soa_unittest.cc
+++ b/src/lib/dns/tests/rdata_soa_unittest.cc
@@ -1 +1,249 @@
+// Copyright (C) 2010-2017 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <util/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+#include <dns/tests/rdata_unittest.h>
+#include <util/unittests/wiredata.h>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+namespace {
+class Rdata_SOA_Test : public RdataTest {
+protected:
+ Rdata_SOA_Test() :
+ rdata_soa(Name("ns.example.com"),
+ Name("root.example.com"),
+ 2010012601, 3600, 300, 3600000, 1200)
+ {}
+
+ template <typename ExForString, typename ExForLexer>
+ void checkFromTextSOA(const string& soa_txt, const Name* origin = NULL,
+ bool throw_str_version = true,
+ bool throw_lexer_version = true)
+ {
+ checkFromText<generic::SOA, ExForString, ExForLexer>(
+ soa_txt, rdata_soa, throw_str_version, throw_lexer_version,
+ origin);
+ }
+
+ const generic::SOA rdata_soa;
+};
+
+TEST_F(Rdata_SOA_Test, createFromText) {
+ // Below we specify isc::Exception as a dummy value for the exception type
+ // in case it's not expected to throw an exception; the type isn't used
+ // in the check code.
+
+ // A simple case.
+ checkFromTextSOA<isc::Exception, isc::Exception>(
+ "ns.example.com. root.example.com. 2010012601 3600 300 3600000 1200",
+ NULL, false, false);
+
+ // Beginning and trailing space are ignored.
+ checkFromTextSOA<isc::Exception, isc::Exception>(
+ " ns.example.com. root.example.com. "
+ "2010012601 3600 300 3600000 1200 ", NULL, false, false);
+
+ // using extended TTL-like form for some parameters.
+ checkFromTextSOA<isc::Exception, isc::Exception>(
+ "ns.example.com. root.example.com. 2010012601 1H 5M 1000H 20M",
+ NULL, false, false);
+
+ // multi-line.
+ checkFromTextSOA<isc::Exception, isc::Exception>(
+ "ns.example.com. (root.example.com.\n"
+ "2010012601 1H 5M 1000H) 20M", NULL, false, false);
+
+ // relative names for MNAME and RNAME with a separate origin (lexer
+ // version only)
+ const Name origin("example.com");
+ checkFromTextSOA<MissingNameOrigin, isc::Exception>(
+ "ns root 2010012601 1H 5M 1000H 20M", &origin, true, false);
+
+ // with the '@' notation with a separate origin (lexer version only;
+ // string version would throw)
+ const Name full_mname("ns.example.com");
+ checkFromTextSOA<MissingNameOrigin, isc::Exception>(
+ "@ root.example.com. 2010012601 1H 5M 1000H 20M", &full_mname, true,
+ false);
+
+ // bad MNAME/RNAMEs
+ checkFromTextSOA<EmptyLabel, EmptyLabel>(
+ "bad..example. . 2010012601 1H 5M 1000H 20M");
+ checkFromTextSOA<EmptyLabel, EmptyLabel>(
+ ". bad..example. 2010012601 1H 5M 1000H 20M");
+
+ // Names shouldn't be quoted.
+ checkFromTextSOA<InvalidRdataText, MasterLexer::LexerError>(
+ "\".\" . 0 0 0 0 0");
+ checkFromTextSOA<InvalidRdataText, MasterLexer::LexerError>(
+ ". \".\" 0 0 0 0 0");
+
+ // Missing MAME or RNAME: for the string version, the serial would be
+ // tried as RNAME and result in "not absolute". For the lexer version,
+ // it reaches the end-of-line, missing min TTL.
+ checkFromTextSOA<MissingNameOrigin, MasterLexer::LexerError>(
+ ". 2010012601 0 0 0 0", &Name::ROOT_NAME());
+
+ // bad serial. the string version converts lexer error to
+ // InvalidRdataText.
+ checkFromTextSOA<InvalidRdataText, MasterLexer::LexerError>(
+ ". . bad 0 0 0 0");
+
+ // bad serial; exceeding the uint32_t range (4294967296 = 2^32)
+ checkFromTextSOA<InvalidRdataText, MasterLexer::LexerError>(
+ ". . 4294967296 0 0 0 0");
+
+ // Bad format for other numeric parameters. These will be tried as a TTL,
+ // and result in an exception there.
+ checkFromTextSOA<InvalidRRTTL, InvalidRRTTL>(
+ ". . 2010012601 bad 0 0 0");
+ checkFromTextSOA<InvalidRRTTL, InvalidRRTTL>(
+ ". . 2010012601 4294967296 0 0 0");
+ checkFromTextSOA<InvalidRRTTL, InvalidRRTTL>(
+ ". . 2010012601 0 bad 0 0");
+ checkFromTextSOA<InvalidRRTTL, InvalidRRTTL>(
+ ". . 2010012601 0 4294967296 0 0");
+ checkFromTextSOA<InvalidRRTTL, InvalidRRTTL>(
+ ". . 2010012601 0 0 bad 0");
+ checkFromTextSOA<InvalidRRTTL, InvalidRRTTL>(
+ ". . 2010012601 0 0 4294967296 0");
+ checkFromTextSOA<InvalidRRTTL, InvalidRRTTL>(
+ ". . 2010012601 0 0 0 bad");
+ checkFromTextSOA<InvalidRRTTL, InvalidRRTTL>(
+ ". . 2010012601 0 0 0 4294967296");
+
+ // No space between RNAME and serial. This case is the same as missing
+ // M/RNAME.
+ checkFromTextSOA<MissingNameOrigin, MasterLexer::LexerError>(
+ ". example.0 0 0 0 0", &Name::ROOT_NAME());
+
+ // Extra parameter. string version immediately detects the error.
+ // lexer version defers the check to the upper layer (we pass origin
+ // to skip the check with the string version).
+ checkFromTextSOA<InvalidRdataText, isc::Exception>(
+ "ns.example.com. root.example.com. 2010012601 1H 5M 1000H 20M "
+ "extra", &origin, true, false);
+
+ // Likewise. Redundant newline is also considered an error. The lexer
+ // version accepts trailing newline, but not the beginning one (where
+ // the lexer expects a string excluding newline and EOF).
+ checkFromTextSOA<InvalidRdataText, isc::Exception>(
+ "ns.example.com. root.example.com. 2010012601 1H 5M 1000H 20M\n",
+ NULL, true, false);
+ checkFromTextSOA<InvalidRdataText, MasterLexer::LexerError>(
+ "\nns.example.com. root.example.com. 2010012601 1H 5M 1000H 20M",
+ NULL, true, true);
+}
+
+TEST_F(Rdata_SOA_Test, createFromWire) {
+ EXPECT_EQ(0, rdata_soa.compare(
+ *rdataFactoryFromFile(RRType("SOA"), RRClass("IN"),
+ "rdata_soa_fromWire")));
+ // TBD: more tests
+}
+
+TEST_F(Rdata_SOA_Test, createFromLexer) {
+ EXPECT_EQ(0, rdata_soa.compare(
+ *test::createRdataUsingLexer(RRType::SOA(), RRClass::IN(),
+ "ns.example.com. root.example.com. "
+ "2010012601 3600 300 3600000 1200")));
+}
+
+TEST_F(Rdata_SOA_Test, toWireRenderer) {
+ renderer.skip(2);
+ rdata_soa.toWire(renderer);
+
+ vector<unsigned char> data;
+ UnitTestUtil::readWireData("rdata_soa_fromWire", data);
+ matchWireData(&data[2], data.size() - 2,
+ static_cast<const uint8_t *>(renderer.getData()) + 2,
+ renderer.getLength() - 2);
+}
+
+TEST_F(Rdata_SOA_Test, toWireBuffer) {
+ obuffer.skip(2);
+ rdata_soa.toWire(obuffer);
+ vector<unsigned char> data;
+ UnitTestUtil::readWireData("rdata_soa_toWireUncompressed.wire", data);
+ matchWireData(&data[2], data.size() - 2,
+ static_cast<const uint8_t *>(obuffer.getData()) + 2,
+ obuffer.getLength() - 2);
+}
+
+TEST_F(Rdata_SOA_Test, toText) {
+ EXPECT_EQ("ns.example.com. root.example.com. "
+ "2010012601 3600 300 3600000 1200", rdata_soa.toText());
+}
+
+TEST_F(Rdata_SOA_Test, getSerial) {
+ EXPECT_EQ(2010012601, rdata_soa.getSerial().getValue());
+}
+
+TEST_F(Rdata_SOA_Test, getMinimum) {
+ EXPECT_EQ(1200, rdata_soa.getMinimum());
+
+ // Also check with a very large number (with the MSB being 1).
+ EXPECT_EQ(2154848336u, generic::SOA(Name("ns.example.com"),
+ Name("root.example.com"),
+ 0, 0, 0, 0, 0x80706050).getMinimum());
+}
+
+void
+compareCheck(const generic::SOA& small, const generic::SOA& large) {
+ EXPECT_GT(0, small.compare(large));
+ EXPECT_LT(0, large.compare(small));
+}
+
+TEST_F(Rdata_SOA_Test, compare) {
+ // Check simple equivalence
+ EXPECT_EQ(0, rdata_soa.compare(generic::SOA(
+ "ns.example.com. root.example.com. "
+ "2010012601 3600 300 3600000 1200")));
+ // Check name comparison is case insensitive
+ EXPECT_EQ(0, rdata_soa.compare(generic::SOA(
+ "NS.example.com. root.EXAMPLE.com. "
+ "2010012601 3600 300 3600000 1200")));
+
+ // Check names are compared in the RDATA comparison semantics (different
+ // from DNSSEC ordering for owner names)
+ compareCheck(generic::SOA("a.example. . 0 0 0 0 0"),
+ generic::SOA("example. . 0 0 0 0 0"));
+ compareCheck(generic::SOA(". a.example. 0 0 0 0 0"),
+ generic::SOA(". example. 0 0 0 0 0"));
+
+ // Compare other numeric fields: 1076895760 = 0x40302010,
+ // 270544960 = 0x10203040. These are chosen to make sure that machine
+ // endianness doesn't confuse the comparison results.
+ compareCheck(generic::SOA(". . 270544960 0 0 0 0"),
+ generic::SOA(". . 1076895760 0 0 0 0"));
+ compareCheck(generic::SOA(". . 0 270544960 0 0 0"),
+ generic::SOA(". . 0 1076895760 0 0 0"));
+ compareCheck(generic::SOA(". . 0 0 270544960 0 0"),
+ generic::SOA(". . 0 0 1076895760 0 0"));
+ compareCheck(generic::SOA(". . 0 0 0 270544960 0"),
+ generic::SOA(". . 0 0 0 1076895760 0"));
+ compareCheck(generic::SOA(". . 0 0 0 0 270544960"),
+ generic::SOA(". . 0 0 0 0 1076895760"));
+}
+
+}
diff --git a/src/lib/dns/tests/rdata_srv_unittest.cc b/src/lib/dns/tests/rdata_srv_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_srv_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_sshfp_unittest.cc b/src/lib/dns/tests/rdata_sshfp_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_sshfp_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_tkey_unittest.cc b/src/lib/dns/tests/rdata_tkey_unittest.cc
index 8b13789179..8592a27a01 100644
--- a/src/lib/dns/tests/rdata_tkey_unittest.cc
+++ b/src/lib/dns/tests/rdata_tkey_unittest.cc
@@ -1 +1,450 @@
+// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <string>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <util/time_utilities.h>
+#include <dns/exceptions.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/tsigerror.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+#include <dns/tests/rdata_unittest.h>
+#include <util/unittests/wiredata.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+namespace {
+
+class Rdata_TKEY_Test : public RdataTest {
+protected:
+ Rdata_TKEY_Test() :
+ // no Key or Other Data
+ valid_text1("gss-tsig. 20210501120000 20210501130000 GSS-API NOERROR 0 0"),
+ // Key but no Other Data
+ valid_text2("GSS-TSIG. 20210501120000 20210501130000 GSS-API BADSIG "
+ "12 FAKEFAKEFAKEFAKE 0"),
+ // Key and Other Data
+ valid_text3("gss.tsig. 20210501120000 20210501130000 GSS-API BADSIG "
+ "12 FAKEFAKEFAKEFAKE 6 FAKEFAKE"),
+ // Key and Other Data (with Error that doesn't expect Other Data)
+ valid_text4("gss.tsig. 20210501120000 20210501130000 3 BADSIG 12 "
+ "FAKEFAKEFAKEFAKE 6 FAKEFAKE"),
+ // numeric error code
+ valid_text5("GSS-TSIG. 20210501120000 20210501130000 GSS-API 2845 12 "
+ "FAKEFAKEFAKEFAKE 0"),
+ // GSS-API mode
+ valid_text6("gss-tsig. 20210501120000 20210501130000 GSS-API 0 12 "
+ "FAKEFAKEFAKEFAKE 0"),
+ rdata_tkey(valid_text1)
+ {}
+
+ void checkFromText_None(const string& rdata_str) {
+ checkFromText<generic::TKEY, isc::Exception, isc::Exception>(
+ rdata_str, rdata_tkey, false, false);
+ }
+
+ void checkFromText_InvalidTime(const string& rdata_str) {
+ checkFromText<generic::TKEY, InvalidTime, InvalidTime>(
+ rdata_str, rdata_tkey, true, true);
+ }
+
+ void checkFromText_InvalidText(const string& rdata_str) {
+ checkFromText<generic::TKEY, InvalidRdataText, InvalidRdataText>(
+ rdata_str, rdata_tkey, true, true);
+ }
+
+ void checkFromText_BadValue(const string& rdata_str) {
+ checkFromText<generic::TKEY, BadValue, BadValue>(
+ rdata_str, rdata_tkey, true, true);
+ }
+
+ void checkFromText_LexerError(const string& rdata_str) {
+ checkFromText
+ <generic::TKEY, InvalidRdataText, MasterLexer::LexerError>(
+ rdata_str, rdata_tkey, true, true);
+ }
+
+ void checkFromText_TooLongLabel(const string& rdata_str) {
+ checkFromText<generic::TKEY, TooLongLabel, TooLongLabel>(
+ rdata_str, rdata_tkey, true, true);
+ }
+
+ void checkFromText_EmptyLabel(const string& rdata_str) {
+ checkFromText<generic::TKEY, EmptyLabel, EmptyLabel>(
+ rdata_str, rdata_tkey, true, true);
+ }
+
+ void checkFromText_BadString(const string& rdata_str) {
+ checkFromText
+ <generic::TKEY, InvalidRdataText, isc::Exception>(
+ rdata_str, rdata_tkey, true, false);
+ }
+
+ template <typename Output>
+ void toWireCommonChecks(Output& output) const;
+
+ const string valid_text1;
+ const string valid_text2;
+ const string valid_text3;
+ const string valid_text4;
+ const string valid_text5;
+ const string valid_text6;
+ vector<uint8_t> expect_data;
+ const generic::TKEY rdata_tkey; // commonly used test RDATA
+};
+
+TEST_F(Rdata_TKEY_Test, fromText) {
+ // normal case. it also tests getter methods.
+ EXPECT_EQ(Name("gss-tsig"), rdata_tkey.getAlgorithm());
+ EXPECT_EQ(1619870400, rdata_tkey.getInception());
+ EXPECT_EQ("20210501120000", rdata_tkey.getInceptionDate());
+ EXPECT_EQ(1619874000, rdata_tkey.getExpire());
+ EXPECT_EQ("20210501130000", rdata_tkey.getExpireDate());
+ EXPECT_EQ(3, rdata_tkey.getMode());
+ EXPECT_EQ(0, rdata_tkey.getError());
+ EXPECT_EQ(0, rdata_tkey.getKeyLen());
+ EXPECT_EQ(static_cast<void*>(0), rdata_tkey.getKey());
+ EXPECT_EQ(0, rdata_tkey.getOtherLen());
+ EXPECT_EQ(static_cast<void*>(0), rdata_tkey.getOtherData());
+
+ generic::TKEY tkey2(valid_text2);
+ EXPECT_EQ(12, tkey2.getKeyLen());
+ EXPECT_EQ(TSIGError::BAD_SIG_CODE, tkey2.getError());
+
+ generic::TKEY tkey3(valid_text3);
+ EXPECT_EQ(6, tkey3.getOtherLen());
+
+ // The other data is unusual, but we don't reject it.
+ EXPECT_NO_THROW(generic::TKEY tkey4(valid_text4));
+
+ // numeric representation of TKEY error
+ generic::TKEY tkey5(valid_text5);
+ EXPECT_EQ(2845, tkey5.getError());
+
+ // symbolic representation of TKEY mode
+ generic::TKEY tkey6(valid_text6);
+ EXPECT_EQ(generic::TKEY::GSS_API_MODE, tkey6.getMode());
+
+ // not fully qualified algorithm name
+ generic::TKEY tkey1("gss-tsig 20210501120000 20210501130000 3 0 0 0");
+ EXPECT_EQ(0, tkey1.compare(rdata_tkey));
+
+ // multi-line rdata
+ checkFromText_None("gss-tsig. ( 20210501120000 20210501130000 GSS-API \n"
+ "NOERROR 0 0 )");
+};
+
+TEST_F(Rdata_TKEY_Test, badText) {
+ // too many fields
+ checkFromText_BadString(valid_text1 + " 0 0");
+ // not enough fields
+ checkFromText_LexerError("foo 20210501120000 20210501130000 0 BADKEY");
+ // bad domain name
+ checkFromText_TooLongLabel(
+ "0123456789012345678901234567890123456789012345678901234567890123"
+ " 20210501120000 20210501130000 0 0 0 0");
+ checkFromText_EmptyLabel("foo..bar 20210501120000 20210501130000 0 0 0 0");
+ // invalid inception (no digit)
+ checkFromText_InvalidTime("foo TIME 20210501130000 0 0 0 0");
+ // invalid inception (bad format)
+ checkFromText_InvalidTime("foo 0 20210501130000 0 0 0 0");
+ // invalid expire (no digit)
+ checkFromText_InvalidTime("foo 20210501120000 TIME 0 0 0 0");
+ // invalid expire (bad format)
+ checkFromText_InvalidTime("foo 20210501120000 0 0 0 0 0");
+ // Unknown mode
+ checkFromText_InvalidText("foo 20210501120000 20210501130000 TEST 0 0 0");
+ // Numeric mode is is too large
+ checkFromText_InvalidText("foo 20210501120000 20210501130000 65536 0 0 0");
+ // Numeric mode is negative
+ checkFromText_InvalidText("foo 20210501120000 20210501130000 -1 0 0 0 0");
+ // Unknown error code
+ checkFromText_InvalidText("foo 20210501120000 20210501130000 0 TEST 0 0");
+ // Numeric error code is too large
+ checkFromText_InvalidText("foo 20210501120000 20210501130000 0 65536 0 0");
+ // Numeric error code is negative
+ checkFromText_InvalidText("foo 20210501120000 20210501130000 0 -1 0 0");
+ // Key len is too large
+ checkFromText_InvalidText("foo 20210501120000 20210501130000 0 0 65536 0");
+ // invalid Key len (negative)
+ checkFromText_LexerError("foo 20210501120000 20210501130000 0 0 -1 0");
+ // invalid Key len (not a number)
+ checkFromText_LexerError("foo 20210501120000 20210501130000 0 0 MACSIZE 0");
+ // Key len and Key mismatch
+ checkFromText_InvalidText("foo 20210501120000 20210501130000 0 0 9 FAKE 0");
+ // Key is bad base64
+ checkFromText_BadValue("foo 20210501120000 20210501130000 0 0 3 FAK= 0");
+ // Other len is too large
+ checkFromText_InvalidText("foo 20210501120000 20210501130000 0 0 0 65536 FAKE");
+ // Other len is negative
+ checkFromText_LexerError("foo 20210501120000 20210501130000 0 0 0 -1 FAKE");
+ // invalid Other len
+ checkFromText_LexerError("foo 20210501120000 20210501130000 0 0 0 LEN FAKE");
+ // Other len and data mismatch
+ checkFromText_InvalidText("foo 20210501120000 20210501130000 0 0 0 9 FAKE");
+}
+
+void
+fromWireCommonChecks(const generic::TKEY& tkey) {
+ EXPECT_EQ(Name("gss-tsig"), tkey.getAlgorithm());
+ EXPECT_EQ(1619870400, tkey.getInception());
+ EXPECT_EQ("20210501120000", tkey.getInceptionDate());
+ EXPECT_EQ(1619874000, tkey.getExpire());
+ EXPECT_EQ("20210501130000", tkey.getExpireDate());
+ EXPECT_EQ(3, tkey.getMode());
+ EXPECT_EQ(0, tkey.getError());
+
+ vector<uint8_t> expect_key(32, 'x');
+ matchWireData(&expect_key[0], expect_key.size(),
+ tkey.getKey(), tkey.getKeyLen());
+
+ EXPECT_EQ(0, tkey.getOtherLen());
+ EXPECT_EQ(static_cast<const void*>(0), tkey.getOtherData());
+}
+
+TEST_F(Rdata_TKEY_Test, createFromWire) {
+ RdataPtr rdata(rdataFactoryFromFile(RRType::TKEY(), RRClass::ANY(),
+ "rdata_tkey_fromWire1.wire"));
+ fromWireCommonChecks(dynamic_cast<generic::TKEY&>(*rdata));
+}
+
+TEST_F(Rdata_TKEY_Test, createFromWireWithOtherData) {
+ RdataPtr rdata(rdataFactoryFromFile(RRType::TKEY(), RRClass::ANY(),
+ "rdata_tkey_fromWire2.wire"));
+ const generic::TKEY& tkey(dynamic_cast<generic::TKEY&>(*rdata));
+
+ vector<uint8_t> expect_key(32, 'x');
+ matchWireData(&expect_key[0], expect_key.size(),
+ tkey.getKey(), tkey.getKeyLen());
+
+ vector<uint8_t> expect_data = { 'a', 'b', 'c', 'd', '0', '1', '2', '3' };
+ matchWireData(&expect_data[0], expect_data.size(),
+ tkey.getOtherData(), tkey.getOtherLen());
+}
+
+TEST_F(Rdata_TKEY_Test, createFromWireWithoutKey) {
+ RdataPtr rdata(rdataFactoryFromFile(RRType::TKEY(), RRClass::ANY(),
+ "rdata_tkey_fromWire3.wire"));
+ const generic::TKEY& tkey(dynamic_cast<generic::TKEY&>(*rdata));
+ EXPECT_EQ(0, tkey.getKeyLen());
+ EXPECT_EQ(static_cast<const void*>(0), tkey.getKey());
+
+ vector<uint8_t> expect_data = { 'a', 'b', 'c', 'd', '0', '1', '2', '3' };
+ matchWireData(&expect_data[0], expect_data.size(),
+ tkey.getOtherData(), tkey.getOtherLen());
+}
+
+TEST_F(Rdata_TKEY_Test, createFromWireWithCompression) {
+ RdataPtr rdata(rdataFactoryFromFile(RRType::TKEY(), RRClass::ANY(),
+ "rdata_tkey_fromWire4.wire",
+ // we need to skip the dummy name:
+ Name("gss-tsig").getLength()));
+ fromWireCommonChecks(dynamic_cast<generic::TKEY&>(*rdata));
+}
+
+TEST_F(Rdata_TKEY_Test, badFromWire) {
+ // RDLENGTH is too short:
+ EXPECT_THROW(rdataFactoryFromFile(RRType::TKEY(), RRClass::ANY(),
+ "rdata_tkey_fromWire5.wire"),
+ InvalidRdataLength);
+ // RDLENGTH is too long:
+ EXPECT_THROW(rdataFactoryFromFile(RRType::TKEY(), RRClass::ANY(),
+ "rdata_tkey_fromWire6.wire"),
+ InvalidRdataLength);
+ // Algorithm name is broken:
+ EXPECT_THROW(rdataFactoryFromFile(RRType::TKEY(), RRClass::ANY(),
+ "rdata_tkey_fromWire7.wire"),
+ DNSMessageFORMERR);
+ // Key length is bogus:
+ EXPECT_THROW(rdataFactoryFromFile(RRType::TKEY(), RRClass::ANY(),
+ "rdata_tkey_fromWire8.wire"),
+ InvalidBufferPosition);
+ // Other-data length is bogus:
+ EXPECT_THROW(rdataFactoryFromFile(RRType::TKEY(), RRClass::ANY(),
+ "rdata_tkey_fromWire9.wire"),
+ InvalidBufferPosition);
+}
+
+TEST_F(Rdata_TKEY_Test, copyConstruct) {
+ const generic::TKEY copy(rdata_tkey);
+ EXPECT_EQ(0, copy.compare(rdata_tkey));
+
+ // Check the copied data is valid even after the original is deleted
+ generic::TKEY* copy2 = new generic::TKEY(rdata_tkey);
+ generic::TKEY copy3(*copy2);
+ delete copy2;
+ EXPECT_EQ(0, copy3.compare(rdata_tkey));
+}
+
+TEST_F(Rdata_TKEY_Test, createFromParams) {
+ EXPECT_EQ(0, rdata_tkey.compare(generic::TKEY(Name("gss-tsig"),
+ 1619870400,
+ 1619874000,
+ 3, 0, 0, 0, 0, 0)));
+
+ const uint8_t fake_data[] = { 0x14, 0x02, 0x84, 0x14, 0x02, 0x84,
+ 0x14, 0x02, 0x84, 0x14, 0x02, 0x84 };
+ EXPECT_EQ(0, generic::TKEY(valid_text2).compare(
+ generic::TKEY(Name("GSS-TSIG"), 1619870400, 1619874000,
+ 3, 16, 12, fake_data, 0, 0)));
+
+ const uint8_t fake_data2[] = { 0x14, 0x02, 0x84, 0x14, 0x02, 0x84 };
+ EXPECT_EQ(0, generic::TKEY(valid_text3).compare(
+ generic::TKEY(Name("gss.tsig"), 1619870400, 1619874000,
+ 3, 16, 12, fake_data, 6, fake_data2)));
+
+ EXPECT_THROW(generic::TKEY(Name("gss-tsig"), 0, 0, 0, 0, 0, fake_data, 0, 0),
+ isc::InvalidParameter);
+ EXPECT_THROW(generic::TKEY(Name("gss-tsig"), 0, 0, 0, 0, 12, 0, 0, 0),
+ isc::InvalidParameter);
+ EXPECT_THROW(generic::TKEY(Name("gss-tsig"), 0, 0, 0, 0, 0, 0, 0, fake_data),
+ isc::InvalidParameter);
+ EXPECT_THROW(generic::TKEY(Name("fake_data"), 0, 0, 0, 0, 0, 0, 6, 0),
+ isc::InvalidParameter);
+}
+
+TEST_F(Rdata_TKEY_Test, assignment) {
+ generic::TKEY copy(valid_text2);
+ copy = rdata_tkey;
+ EXPECT_EQ(0, copy.compare(rdata_tkey));
+
+ // Check if the copied data is valid even after the original is deleted
+ generic::TKEY* copy2 = new generic::TKEY(rdata_tkey);
+ generic::TKEY copy3(valid_text2);
+ copy3 = *copy2;
+ delete copy2;
+ EXPECT_EQ(0, copy3.compare(rdata_tkey));
+
+ // Self assignment
+ copy = *&copy;
+ EXPECT_EQ(0, copy.compare(rdata_tkey));
+}
+
+template <typename Output>
+void
+Rdata_TKEY_Test::toWireCommonChecks(Output& output) const {
+ vector<uint8_t> expect_data;
+
+ output.clear();
+ expect_data.clear();
+ rdata_tkey.toWire(output);
+ // read the expected wire format data and trim the RDLEN part.
+ UnitTestUtil::readWireData("rdata_tkey_toWire1.wire", expect_data);
+ expect_data.erase(expect_data.begin(), expect_data.begin() + 2);
+ matchWireData(&expect_data[0], expect_data.size(),
+ output.getData(), output.getLength());
+
+ expect_data.clear();
+ output.clear();
+ generic::TKEY(valid_text2).toWire(output);
+ UnitTestUtil::readWireData("rdata_tkey_toWire2.wire", expect_data);
+ expect_data.erase(expect_data.begin(), expect_data.begin() + 2);
+ matchWireData(&expect_data[0], expect_data.size(),
+ output.getData(), output.getLength());
+
+ expect_data.clear();
+ output.clear();
+ generic::TKEY(valid_text3).toWire(output);
+ UnitTestUtil::readWireData("rdata_tkey_toWire3.wire", expect_data);
+ expect_data.erase(expect_data.begin(), expect_data.begin() + 2);
+ matchWireData(&expect_data[0], expect_data.size(),
+ output.getData(), output.getLength());
+}
+
+TEST_F(Rdata_TKEY_Test, toWireBuffer) {
+ toWireCommonChecks<OutputBuffer>(obuffer);
+}
+
+TEST_F(Rdata_TKEY_Test, toWireRenderer) {
+ toWireCommonChecks<MessageRenderer>(renderer);
+
+ // check algorithm name won't compressed when it would otherwise.
+ expect_data.clear();
+ renderer.clear();
+ renderer.writeName(Name("gss-tsig"));
+ renderer.writeUint16(26); // RDLEN
+ rdata_tkey.toWire(renderer);
+ UnitTestUtil::readWireData("rdata_tkey_toWire4.wire", expect_data);
+ matchWireData(&expect_data[0], expect_data.size(),
+ renderer.getData(), renderer.getLength());
+
+ // check algorithm can be used as a compression target.
+ expect_data.clear();
+ renderer.clear();
+ renderer.writeUint16(26);
+ rdata_tkey.toWire(renderer);
+ renderer.writeName(Name("gss-tsig"));
+ UnitTestUtil::readWireData("rdata_tkey_toWire5.wire", expect_data);
+ matchWireData(&expect_data[0], expect_data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(Rdata_TKEY_Test, toText) {
+ EXPECT_EQ(valid_text1, rdata_tkey.toText());
+ EXPECT_EQ(valid_text2, generic::TKEY(valid_text2).toText());
+ EXPECT_EQ(valid_text3, generic::TKEY(valid_text3).toText());
+ EXPECT_EQ(valid_text5, generic::TKEY(valid_text5).toText());
+}
+
+TEST_F(Rdata_TKEY_Test, compare) {
+ // test RDATAs, sorted in the ascending order.
+ // "AAAA" encoded in BASE64 corresponds to 0x000000, so it should be the
+ // smallest data of the same length.
+ vector<generic::TKEY> compare_set;
+ compare_set.push_back(generic::TKEY("a.example 20210501120000 "
+ "20210501130000 3 0 0 0"));
+ compare_set.push_back(generic::TKEY("example 20210501120000 "
+ "20210501130000 3 0 0 0"));
+ compare_set.push_back(generic::TKEY("example 20210501120001 "
+ "20210501130000 3 0 0 0"));
+ compare_set.push_back(generic::TKEY("example 20210501120001 "
+ "20210501130001 3 0 0 0"));
+ compare_set.push_back(generic::TKEY("example 20210501120001 "
+ "20210501130001 4 0 0 0"));
+ compare_set.push_back(generic::TKEY("example 20210501120001 "
+ "20210501130001 4 1 0 0"));
+ compare_set.push_back(generic::TKEY("example 20210501120001 "
+ "20210501130001 4 1 3 AAAA 0"));
+ compare_set.push_back(generic::TKEY("example 20210501120001 "
+ "20210501130001 4 1 3 FAKE 0"));
+ compare_set.push_back(generic::TKEY("example 20210501120001 "
+ "20210501130001 4 1 3 FAKE 3 AAAA"));
+ compare_set.push_back(generic::TKEY("example 20210501120001 "
+ "20210501130001 4 1 3 FAKE 3 FAKE"));
+
+ EXPECT_EQ(0,
+ compare_set[0].compare(generic::TKEY("A.EXAMPLE 20210501120000 "
+ "20210501130000 3 0 0 0")));
+
+ vector<generic::TKEY>::const_iterator it;
+ vector<generic::TKEY>::const_iterator it_end = compare_set.end();
+ for (it = compare_set.begin(); it != it_end - 1; ++it) {
+ EXPECT_GT(0, (*it).compare(*(it + 1)));
+ EXPECT_LT(0, (*(it + 1)).compare(*it));
+ }
+
+ // comparison attempt between incompatible RR types should be rejected
+ EXPECT_THROW(rdata_tkey.compare(*RdataTest::rdata_nomatch), bad_cast);
+}
+}
diff --git a/src/lib/dns/tests/rdata_tlsa_unittest.cc b/src/lib/dns/tests/rdata_tlsa_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdata_tlsa_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rdata_tsig_unittest.cc b/src/lib/dns/tests/rdata_tsig_unittest.cc
index 8b13789179..9d3bd89662 100644
--- a/src/lib/dns/tests/rdata_tsig_unittest.cc
+++ b/src/lib/dns/tests/rdata_tsig_unittest.cc
@@ -1 +1,423 @@
+// Copyright (C) 2010-2023 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <string>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <dns/exceptions.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/tsigerror.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+#include <dns/tests/rdata_unittest.h>
+#include <util/unittests/wiredata.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::dns::rdata;
+using namespace isc::dns::rdata::any;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+namespace {
+
+class Rdata_TSIG_Test : public RdataTest {
+protected:
+ Rdata_TSIG_Test() :
+ // no MAC or Other Data
+ valid_text1("hmac-md5.sig-alg.reg.int. 1286779327 300 "
+ "0 16020 BADKEY 0"),
+ // MAC but no Other Data
+ valid_text2("hmac-sha256. 1286779327 300 12 "
+ "FAKEFAKEFAKEFAKE 16020 BADSIG 0"),
+ // MAC and Other Data
+ valid_text3("hmac-sha1. 1286779327 300 12 "
+ "FAKEFAKEFAKEFAKE 16020 BADTIME 6 FAKEFAKE"),
+ // MAC and Other Data (with Error that doesn't expect Other Data)
+ valid_text4("hmac-sha1. 1286779327 300 12 "
+ "FAKEFAKEFAKEFAKE 16020 BADSIG 6 FAKEFAKE"),
+ // numeric error code
+ valid_text5("hmac-sha256. 1286779327 300 12 "
+ "FAKEFAKEFAKEFAKE 16020 2845 0"),
+ rdata_tsig(valid_text1)
+ {}
+
+ void checkFromText_None(const string& rdata_str) {
+ checkFromText<TSIG, isc::Exception, isc::Exception>(
+ rdata_str, rdata_tsig, false, false);
+ }
+
+ void checkFromText_InvalidText(const string& rdata_str) {
+ checkFromText<TSIG, InvalidRdataText, InvalidRdataText>(
+ rdata_str, rdata_tsig, true, true);
+ }
+
+ void checkFromText_BadValue(const string& rdata_str) {
+ checkFromText<TSIG, BadValue, BadValue>(
+ rdata_str, rdata_tsig, true, true);
+ }
+
+ void checkFromText_LexerError(const string& rdata_str) {
+ checkFromText
+ <TSIG, InvalidRdataText, MasterLexer::LexerError>(
+ rdata_str, rdata_tsig, true, true);
+ }
+
+ void checkFromText_TooLongLabel(const string& rdata_str) {
+ checkFromText<TSIG, TooLongLabel, TooLongLabel>(
+ rdata_str, rdata_tsig, true, true);
+ }
+
+ void checkFromText_EmptyLabel(const string& rdata_str) {
+ checkFromText<TSIG, EmptyLabel, EmptyLabel>(
+ rdata_str, rdata_tsig, true, true);
+ }
+
+ void checkFromText_BadString(const string& rdata_str) {
+ checkFromText
+ <TSIG, InvalidRdataText, isc::Exception>(
+ rdata_str, rdata_tsig, true, false);
+ }
+
+ template <typename Output>
+ void toWireCommonChecks(Output& output) const;
+
+ const string valid_text1;
+ const string valid_text2;
+ const string valid_text3;
+ const string valid_text4;
+ const string valid_text5;
+ vector<uint8_t> expect_data;
+ const TSIG rdata_tsig; // commonly used test RDATA
+};
+
+TEST_F(Rdata_TSIG_Test, fromText) {
+ // normal case. it also tests getter methods.
+ EXPECT_EQ(Name("hmac-md5.sig-alg.reg.int"), rdata_tsig.getAlgorithm());
+ EXPECT_EQ(1286779327, rdata_tsig.getTimeSigned());
+ EXPECT_EQ(300, rdata_tsig.getFudge());
+ EXPECT_EQ(0, rdata_tsig.getMACSize());
+ EXPECT_EQ(static_cast<void*>(NULL), rdata_tsig.getMAC());
+ EXPECT_EQ(16020, rdata_tsig.getOriginalID());
+ EXPECT_EQ(TSIGError::BAD_KEY_CODE, rdata_tsig.getError());
+ EXPECT_EQ(0, rdata_tsig.getOtherLen());
+ EXPECT_EQ(static_cast<void*>(NULL), rdata_tsig.getOtherData());
+
+ TSIG tsig2(valid_text2);
+ EXPECT_EQ(12, tsig2.getMACSize());
+ EXPECT_EQ(TSIGError::BAD_SIG_CODE, tsig2.getError());
+
+ TSIG tsig3(valid_text3);
+ EXPECT_EQ(6, tsig3.getOtherLen());
+
+ // The other data is unusual, but we don't reject it.
+ EXPECT_NO_THROW(TSIG tsig4(valid_text4));
+
+ // numeric representation of TSIG error
+ TSIG tsig5(valid_text5);
+ EXPECT_EQ(2845, tsig5.getError());
+
+ // not fully qualified algorithm name
+ TSIG tsig1("hmac-md5.sig-alg.reg.int 1286779327 300 0 16020 BADKEY 0");
+ EXPECT_EQ(0, tsig1.compare(rdata_tsig));
+
+ // multi-line rdata
+ checkFromText_None("hmac-md5.sig-alg.reg.int. ( 1286779327 300 \n"
+ "0 16020 BADKEY 0 )");
+
+ // short-form HMAC-MD5 name
+ const TSIG tsig6("hmac-md5. 1286779327 300 0 16020 BADKEY 0");
+ EXPECT_EQ(0, tsig6.compare(rdata_tsig));
+};
+
+TEST_F(Rdata_TSIG_Test, badText) {
+ // too many fields
+ checkFromText_BadString(valid_text1 + " 0 0");
+ // not enough fields
+ checkFromText_LexerError("foo 0 0 0 0 BADKEY");
+ // bad domain name
+ checkFromText_TooLongLabel(
+ "0123456789012345678901234567890123456789012345678901234567890123"
+ " 0 0 0 0 BADKEY 0");
+ checkFromText_EmptyLabel("foo..bar 0 0 0 0 BADKEY");
+ // time is too large (2814...6 is 2^48)
+ checkFromText_InvalidText("foo 281474976710656 0 0 0 BADKEY 0");
+ // invalid time (negative)
+ checkFromText_InvalidText("foo -1 0 0 0 BADKEY 0");
+ // invalid time (not a number)
+ checkFromText_InvalidText("foo TIME 0 0 0 BADKEY 0");
+ // fudge is too large
+ checkFromText_InvalidText("foo 0 65536 0 0 BADKEY 0");
+ // invalid fudge (negative)
+ checkFromText_LexerError("foo 0 -1 0 0 BADKEY 0");
+ // invalid fudge (not a number)
+ checkFromText_LexerError("foo 0 FUDGE 0 0 BADKEY 0");
+ // MAC size is too large
+ checkFromText_InvalidText("foo 0 0 65536 0 BADKEY 0");
+ // invalid MAC size (negative)
+ checkFromText_LexerError("foo 0 0 -1 0 BADKEY 0");
+ // invalid MAC size (not a number)
+ checkFromText_LexerError("foo 0 0 MACSIZE 0 BADKEY 0");
+ // MAC size and MAC mismatch
+ checkFromText_InvalidText("foo 0 0 9 FAKE 0 BADKEY 0");
+ // MAC is bad base64
+ checkFromText_BadValue("foo 0 0 3 FAK= 0 BADKEY 0");
+ // Unknown error code
+ checkFromText_InvalidText("foo 0 0 0 0 TEST 0");
+ // Numeric error code is too large
+ checkFromText_InvalidText("foo 0 0 0 0 65536 0");
+ // Numeric error code is negative
+ checkFromText_InvalidText("foo 0 0 0 0 -1 0");
+ // Other len is too large
+ checkFromText_InvalidText("foo 0 0 0 0 NOERROR 65536 FAKE");
+ // Other len is negative
+ checkFromText_LexerError("foo 0 0 0 0 NOERROR -1 FAKE");
+ // invalid Other len
+ checkFromText_LexerError("foo 0 0 0 0 NOERROR LEN FAKE");
+ // Other len and data mismatch
+ checkFromText_InvalidText("foo 0 0 0 0 NOERROR 9 FAKE");
+}
+
+void
+fromWireCommonChecks(const TSIG& tsig) {
+ EXPECT_EQ(Name("hmac-sha256"), tsig.getAlgorithm());
+ EXPECT_EQ(1286978795, tsig.getTimeSigned());
+ EXPECT_EQ(300, tsig.getFudge());
+
+ vector<uint8_t> expect_mac(32, 'x');
+ matchWireData(&expect_mac[0], expect_mac.size(),
+ tsig.getMAC(), tsig.getMACSize());
+
+ EXPECT_EQ(2845, tsig.getOriginalID());
+
+ EXPECT_EQ(0, tsig.getOtherLen());
+ EXPECT_EQ(static_cast<const void*>(NULL), tsig.getOtherData());
+}
+
+TEST_F(Rdata_TSIG_Test, createFromWire) {
+ RdataPtr rdata(rdataFactoryFromFile(RRType::TSIG(), RRClass::ANY(),
+ "rdata_tsig_fromWire1.wire"));
+ fromWireCommonChecks(dynamic_cast<TSIG&>(*rdata));
+}
+
+TEST_F(Rdata_TSIG_Test, createFromWireWithOtherData) {
+ RdataPtr rdata(rdataFactoryFromFile(RRType::TSIG(), RRClass::ANY(),
+ "rdata_tsig_fromWire2.wire"));
+ const TSIG& tsig(dynamic_cast<TSIG&>(*rdata));
+
+ EXPECT_EQ(18, tsig.getError());
+ const uint64_t otherdata = 1286978795 + 300 + 1; // time-signed + fudge + 1
+ expect_data.resize(6);
+ expect_data[0] = (otherdata >> 40);
+ expect_data[1] = ((otherdata >> 32) & 0xff);
+ expect_data[2] = ((otherdata >> 24) & 0xff);
+ expect_data[3] = ((otherdata >> 16) & 0xff);
+ expect_data[4] = ((otherdata >> 8) & 0xff);
+ expect_data[5] = (otherdata & 0xff);
+ matchWireData(&expect_data[0], expect_data.size(),
+ tsig.getOtherData(), tsig.getOtherLen());
+}
+
+TEST_F(Rdata_TSIG_Test, createFromWireWithoutMAC) {
+ RdataPtr rdata(rdataFactoryFromFile(RRType::TSIG(), RRClass::ANY(),
+ "rdata_tsig_fromWire3.wire"));
+ const TSIG& tsig(dynamic_cast<TSIG&>(*rdata));
+ EXPECT_EQ(16, tsig.getError());
+ EXPECT_EQ(0, tsig.getMACSize());
+ EXPECT_EQ(static_cast<const void*>(NULL), tsig.getMAC());
+}
+
+TEST_F(Rdata_TSIG_Test, createFromWireWithCompression) {
+ RdataPtr rdata(rdataFactoryFromFile(RRType::TSIG(), RRClass::ANY(),
+ "rdata_tsig_fromWire4.wire",
+ // we need to skip the dummy name:
+ Name("hmac-sha256").getLength()));
+ fromWireCommonChecks(dynamic_cast<TSIG&>(*rdata));
+}
+
+TEST_F(Rdata_TSIG_Test, badFromWire) {
+ // RDLENGTH is too short:
+ EXPECT_THROW(rdataFactoryFromFile(RRType::TSIG(), RRClass::ANY(),
+ "rdata_tsig_fromWire5.wire"),
+ InvalidRdataLength);
+ // RDLENGTH is too long:
+ EXPECT_THROW(rdataFactoryFromFile(RRType::TSIG(), RRClass::ANY(),
+ "rdata_tsig_fromWire6.wire"),
+ InvalidRdataLength);
+ // Algorithm name is broken:
+ EXPECT_THROW(rdataFactoryFromFile(RRType::TSIG(), RRClass::ANY(),
+ "rdata_tsig_fromWire7.wire"),
+ DNSMessageFORMERR);
+ // MAC size is bogus:
+ EXPECT_THROW(rdataFactoryFromFile(RRType::TSIG(), RRClass::ANY(),
+ "rdata_tsig_fromWire8.wire"),
+ InvalidBufferPosition);
+ // Other-data length is bogus:
+ EXPECT_THROW(rdataFactoryFromFile(RRType::TSIG(), RRClass::ANY(),
+ "rdata_tsig_fromWire9.wire"),
+ InvalidBufferPosition);
+}
+
+TEST_F(Rdata_TSIG_Test, copyConstruct) {
+ const TSIG copy(rdata_tsig);
+ EXPECT_EQ(0, copy.compare(rdata_tsig));
+
+ // Check the copied data is valid even after the original is deleted
+ TSIG* copy2 = new TSIG(rdata_tsig);
+ TSIG copy3(*copy2);
+ delete copy2;
+ EXPECT_EQ(0, copy3.compare(rdata_tsig));
+}
+
+TEST_F(Rdata_TSIG_Test, createFromParams) {
+ EXPECT_EQ(0, rdata_tsig.compare(TSIG(Name("hmac-md5.sig-alg.reg.int"),
+ 1286779327, 300, 0, NULL, 16020, 17, 0, NULL)));
+
+ const uint8_t fake_data[] = { 0x14, 0x02, 0x84, 0x14, 0x02, 0x84,
+ 0x14, 0x02, 0x84, 0x14, 0x02, 0x84 };
+ EXPECT_EQ(0, TSIG(valid_text2).compare(TSIG(Name("hmac-sha256"), 1286779327, 300, 12,
+ fake_data, 16020, 16, 0, NULL)));
+
+ const uint8_t fake_data2[] = { 0x14, 0x02, 0x84, 0x14, 0x02, 0x84 };
+ EXPECT_EQ(0, TSIG(valid_text3).compare(TSIG(Name("hmac-sha1"), 1286779327, 300, 12,
+ fake_data, 16020, 18, 6, fake_data2)));
+
+ EXPECT_THROW(TSIG(Name("hmac-sha256"), 1ULL << 48, 300, 12, fake_data, 16020, 18, 6, fake_data2),
+ isc::OutOfRange);
+ EXPECT_THROW(TSIG(Name("hmac-sha256"), 0, 300, 0, fake_data, 16020, 18, 0, NULL),
+ isc::InvalidParameter);
+ EXPECT_THROW(TSIG(Name("hmac-sha256"), 0, 300, 12, NULL, 16020, 18, 0, NULL),
+ isc::InvalidParameter);
+ EXPECT_THROW(TSIG(Name("hmac-sha256"), 0, 300, 0, NULL, 16020, 18, 0, fake_data),
+ isc::InvalidParameter);
+ EXPECT_THROW(TSIG(Name("hmac-sha256"), 0, 300, 0, NULL, 16020, 18, 6, NULL),
+ isc::InvalidParameter);
+}
+
+TEST_F(Rdata_TSIG_Test, assignment) {
+ TSIG copy(valid_text2);
+ copy = rdata_tsig;
+ EXPECT_EQ(0, copy.compare(rdata_tsig));
+
+ // Check if the copied data is valid even after the original is deleted
+ TSIG* copy2 = new TSIG(rdata_tsig);
+ TSIG copy3(valid_text2);
+ copy3 = *copy2;
+ delete copy2;
+ EXPECT_EQ(0, copy3.compare(rdata_tsig));
+
+ // Self assignment
+ copy = *&copy;
+ EXPECT_EQ(0, copy.compare(rdata_tsig));
+}
+
+template <typename Output>
+void
+Rdata_TSIG_Test::toWireCommonChecks(Output& output) const {
+ vector<uint8_t> expect_data;
+
+ output.clear();
+ expect_data.clear();
+ rdata_tsig.toWire(output);
+ // read the expected wire format data and trim the RDLEN part.
+ UnitTestUtil::readWireData("rdata_tsig_toWire1.wire", expect_data);
+ expect_data.erase(expect_data.begin(), expect_data.begin() + 2);
+ matchWireData(&expect_data[0], expect_data.size(),
+ output.getData(), output.getLength());
+
+ expect_data.clear();
+ output.clear();
+ TSIG(valid_text2).toWire(output);
+ UnitTestUtil::readWireData("rdata_tsig_toWire2.wire", expect_data);
+ expect_data.erase(expect_data.begin(), expect_data.begin() + 2);
+ matchWireData(&expect_data[0], expect_data.size(),
+ output.getData(), output.getLength());
+
+ expect_data.clear();
+ output.clear();
+ TSIG(valid_text3).toWire(output);
+ UnitTestUtil::readWireData("rdata_tsig_toWire3.wire", expect_data);
+ expect_data.erase(expect_data.begin(), expect_data.begin() + 2);
+ matchWireData(&expect_data[0], expect_data.size(),
+ output.getData(), output.getLength());
+}
+
+TEST_F(Rdata_TSIG_Test, toWireBuffer) {
+ toWireCommonChecks<OutputBuffer>(obuffer);
+}
+
+TEST_F(Rdata_TSIG_Test, toWireRenderer) {
+ toWireCommonChecks<MessageRenderer>(renderer);
+
+ // check algorithm name won't compressed when it would otherwise.
+ expect_data.clear();
+ renderer.clear();
+ renderer.writeName(Name("hmac-md5.sig-alg.reg.int"));
+ renderer.writeUint16(42); // RDLEN
+ rdata_tsig.toWire(renderer);
+ UnitTestUtil::readWireData("rdata_tsig_toWire4.wire", expect_data);
+ matchWireData(&expect_data[0], expect_data.size(),
+ renderer.getData(), renderer.getLength());
+
+ // check algorithm can be used as a compression target.
+ expect_data.clear();
+ renderer.clear();
+ renderer.writeUint16(42);
+ rdata_tsig.toWire(renderer);
+ renderer.writeName(Name("hmac-md5.sig-alg.reg.int"));
+ UnitTestUtil::readWireData("rdata_tsig_toWire5.wire", expect_data);
+ matchWireData(&expect_data[0], expect_data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(Rdata_TSIG_Test, toText) {
+ EXPECT_EQ(valid_text1, rdata_tsig.toText());
+ EXPECT_EQ(valid_text2, TSIG(valid_text2).toText());
+ EXPECT_EQ(valid_text3, TSIG(valid_text3).toText());
+ EXPECT_EQ(valid_text5, TSIG(valid_text5).toText());
+}
+
+TEST_F(Rdata_TSIG_Test, compare) {
+ // test RDATAs, sorted in the ascending order.
+ // "AAAA" encoded in BASE64 corresponds to 0x000000, so it should be the
+ // smallest data of the same length.
+ vector<TSIG> compare_set;
+ compare_set.push_back(TSIG("a.example 0 300 0 16020 0 0"));
+ compare_set.push_back(TSIG("example 0 300 0 16020 0 0"));
+ compare_set.push_back(TSIG("example 1 300 0 16020 0 0"));
+ compare_set.push_back(TSIG("example 1 600 0 16020 0 0"));
+ compare_set.push_back(TSIG("example 1 600 3 AAAA 16020 0 0"));
+ compare_set.push_back(TSIG("example 1 600 3 FAKE 16020 0 0"));
+ compare_set.push_back(TSIG("example 1 600 3 FAKE 16021 0 0"));
+ compare_set.push_back(TSIG("example 1 600 3 FAKE 16021 1 0"));
+ compare_set.push_back(TSIG("example 1 600 3 FAKE 16021 1 3 AAAA"));
+ compare_set.push_back(TSIG("example 1 600 3 FAKE 16021 1 3 FAKE"));
+
+ EXPECT_EQ(0, compare_set[0].compare(TSIG("A.EXAMPLE 0 300 0 16020 0 0")));
+
+ vector<TSIG>::const_iterator it;
+ vector<TSIG>::const_iterator it_end = compare_set.end();
+ for (it = compare_set.begin(); it != it_end - 1; ++it) {
+ EXPECT_GT(0, (*it).compare(*(it + 1)));
+ EXPECT_LT(0, (*(it + 1)).compare(*it));
+ }
+
+ // comparison attempt between incompatible RR types should be rejected
+ EXPECT_THROW(rdata_tsig.compare(*RdataTest::rdata_nomatch), bad_cast);
+}
+}
diff --git a/src/lib/dns/tests/rdata_txt_like_unittest.cc b/src/lib/dns/tests/rdata_txt_like_unittest.cc
index 8b13789179..dcb5ac168b 100644
--- a/src/lib/dns/tests/rdata_txt_like_unittest.cc
+++ b/src/lib/dns/tests/rdata_txt_like_unittest.cc
@@ -1 +1,394 @@
+// Copyright (C) 2011-2024 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+// This is the common code for TXT tests.
+
+#include <config.h>
+
+#include <util/buffer.h>
+#include <dns/exceptions.h>
+#include <dns/rdataclass.h>
+
+#include <dns/tests/unittest_util.h>
+#include <dns/tests/rdata_unittest.h>
+
+#include <util/unittests/wiredata.h>
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <sstream>
+#include <vector>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+namespace {
+
+template<class T>
+class RRTYPE : public RRType {
+public:
+ RRTYPE();
+};
+
+template<> RRTYPE<generic::TXT>::RRTYPE() : RRType(RRType::TXT()) {}
+
+const uint8_t wiredata_txt_like[] = {
+ sizeof("Test-String") - 1,
+ 'T', 'e', 's', 't', '-', 'S', 't', 'r', 'i', 'n', 'g'
+};
+
+const uint8_t wiredata_nulltxt[] = { 0 };
+
+template<class TXT_LIKE>
+class Rdata_TXT_LIKE_Test : public RdataTest {
+protected:
+ Rdata_TXT_LIKE_Test() :
+ wiredata_longesttxt(256, 'a'),
+ rdata_txt_like("Test-String"),
+ rdata_txt_like_empty("\"\""),
+ rdata_txt_like_quoted("\"Test-String\"")
+ {
+ wiredata_longesttxt[0] = 255; // adjust length
+ }
+
+protected:
+ vector<uint8_t> wiredata_longesttxt;
+ const TXT_LIKE rdata_txt_like;
+ const TXT_LIKE rdata_txt_like_empty;
+ const TXT_LIKE rdata_txt_like_quoted;
+};
+
+// The list of types we want to test.
+typedef testing::Types<generic::TXT> Implementations;
+
+#ifdef TYPED_TEST_SUITE
+TYPED_TEST_SUITE(Rdata_TXT_LIKE_Test, Implementations);
+#else
+TYPED_TEST_CASE(Rdata_TXT_LIKE_Test, Implementations);
+#endif
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, createFromText) {
+ // Below we check the behavior for the "from text" constructors, both
+ // from std::string and with MasterLexer. The underlying implementation
+ // is the same, so both should work exactly same, but we confirm both
+ // cases.
+
+ const std::string multi_line = "(\n \"Test-String\" )";
+ const std::string escaped_txt = "Test\\045Strin\\g";
+
+ // test input for the lexer version
+ std::stringstream ss;
+ ss << "Test-String\n";
+ ss << "\"Test-String\"\n"; // explicitly surrounded by '"'s
+ ss << multi_line << "\n"; // multi-line text with ()
+ ss << escaped_txt << "\n"; // using the two types of escape with '\'
+ ss << "\"\"\n"; // empty string (note: still valid char-str)
+ ss << string(255, 'a') << "\n"; // Longest possible character-string.
+ ss << string(256, 'a') << "\n"; // char-string too long
+ ss << "\"Test-String\\\"\n"; // unbalanced quote
+ ss << "\"Test-String\\\"\"\n";
+ this->lexer.pushSource(ss);
+
+ // commonly used Rdata to compare below, created from wire
+ ConstRdataPtr const rdata =
+ this->rdataFactoryFromFile(RRTYPE<TypeParam>(),
+ RRClass("IN"), "rdata_txt_fromWire1");
+
+ // normal case is covered in toWireBuffer. First check the std::string
+ // case, then with MasterLexer. For the latter, we need to read and skip
+ // '\n'. These apply to most of the other cases below.
+ EXPECT_EQ(0, this->rdata_txt_like.compare(*rdata));
+ EXPECT_EQ(0, TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS,
+ this->loader_cb).compare(*rdata));
+ EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType());
+
+ // surrounding double-quotes shouldn't change the result.
+ EXPECT_EQ(0, this->rdata_txt_like_quoted.compare(*rdata));
+ EXPECT_EQ(0, TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS,
+ this->loader_cb).compare(*rdata));
+ EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType());
+
+ // multi-line input with ()
+ EXPECT_EQ(0, TypeParam(multi_line).compare(*rdata));
+ EXPECT_EQ(0, TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS,
+ this->loader_cb).compare(*rdata));
+ EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType());
+
+ // for the same data using escape
+ EXPECT_EQ(0, TypeParam(escaped_txt).compare(*rdata));
+ EXPECT_EQ(0, TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS,
+ this->loader_cb).compare(*rdata));
+ EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType());
+
+ // Null character-string.
+ this->obuffer.clear();
+ TypeParam(string("\"\"")).toWire(this->obuffer);
+ matchWireData(wiredata_nulltxt, sizeof(wiredata_nulltxt),
+ this->obuffer.getData(), this->obuffer.getLength());
+
+ this->obuffer.clear();
+ TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS, this->loader_cb).
+ toWire(this->obuffer);
+ matchWireData(wiredata_nulltxt, sizeof(wiredata_nulltxt),
+ this->obuffer.getData(), this->obuffer.getLength());
+
+ EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType());
+
+ // Longest possible character-string.
+ this->obuffer.clear();
+ TypeParam(string(255, 'a')).toWire(this->obuffer);
+ matchWireData(&this->wiredata_longesttxt[0],
+ this->wiredata_longesttxt.size(),
+ this->obuffer.getData(), this->obuffer.getLength());
+
+ this->obuffer.clear();
+ TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS, this->loader_cb).
+ toWire(this->obuffer);
+ matchWireData(&this->wiredata_longesttxt[0],
+ this->wiredata_longesttxt.size(),
+ this->obuffer.getData(), this->obuffer.getLength());
+
+ EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType());
+
+ // Too long text for a valid character-string.
+ EXPECT_THROW(TypeParam(string(256, 'a')), CharStringTooLong);
+ EXPECT_THROW(TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS,
+ this->loader_cb), CharStringTooLong);
+ EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType());
+
+ // The escape character makes the double quote a part of character-string,
+ // so this is invalid input and should be rejected.
+ EXPECT_THROW(TypeParam("\"Test-String\\\""), InvalidRdataText);
+ EXPECT_THROW(TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS,
+ this->loader_cb), MasterLexer::LexerError);
+ EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType());
+}
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, createMultiStringsFromText) {
+ // Tests for "from text" variants construction with various forms of
+ // multi character-strings.
+
+ std::vector<std::string > texts;
+ texts.push_back("\"Test-String\" \"Test-String\""); // most common form
+ texts.push_back("\"Test-String\"\"Test-String\""); // no space between'em
+ texts.push_back("\"Test-String\" Test-String"); // no '"' for one
+ texts.push_back("\"Test-String\"Test-String"); // and no space either
+ texts.push_back("Test-String \"Test-String\""); // no '"' for the other
+ texts.push_back("Test-String\"Test-String\""); // and no space either
+
+ std::stringstream ss;
+ for (auto const& it : texts) {
+ ss << it << "\n";
+ }
+ this->lexer.pushSource(ss);
+
+ // The corresponding Rdata built from wire to compare in the checks below.
+ ConstRdataPtr const rdata =
+ this->rdataFactoryFromFile(RRTYPE<TypeParam>(),
+ RRClass("IN"), "rdata_txt_fromWire3.wire");
+
+ // Confirm we can construct the Rdata from the test text, both from
+ // std::string and with lexer, and that matches the from-wire data.
+ for (auto const& it : texts) {
+ SCOPED_TRACE(it);
+ EXPECT_EQ(0, TypeParam(it).compare(*rdata));
+
+ EXPECT_EQ(0, TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS,
+ this->loader_cb).compare(*rdata));
+ EXPECT_EQ(MasterToken::END_OF_LINE,
+ this->lexer.getNextToken().getType());
+ }
+}
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, createFromTextExtra) {
+ // This is for the std::string version only: the input must end with EOF;
+ // an extra new-line will result in an exception.
+ EXPECT_THROW(TypeParam("\"Test-String\"\n"), InvalidRdataText);
+ // Same if there's a space before '\n'
+ EXPECT_THROW(TypeParam("\"Test-String\" \n"), InvalidRdataText);
+}
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, fromTextEmpty) {
+ // If the input text doesn't contain any character-string, it should be
+ // rejected
+ EXPECT_THROW(TypeParam(""), InvalidRdataText);
+ EXPECT_THROW(TypeParam(" "), InvalidRdataText); // even with a space
+ EXPECT_THROW(TypeParam("(\n)"), InvalidRdataText); // or multi-line with ()
+}
+
+void
+makeLargest(vector<uint8_t>& data) {
+ uint8_t ch = 0;
+
+ // create 255 sets of character-strings, each of which has the longest
+ // length (255bytes string + 1-byte length field)
+ for (int i = 0; i < 255; ++i, ++ch) {
+ data.push_back(255);
+ data.insert(data.end(), 255, ch);
+ }
+ // the last character-string should be 255 bytes (including the one-byte
+ // length field) in length so that the total length should be in the range
+ // of 16-bit integers.
+ data.push_back(254);
+ data.insert(data.end(), 254, ch);
+
+ assert(data.size() == 65535);
+}
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, createFromWire) {
+ EXPECT_EQ(0, this->rdata_txt_like.compare(
+ *this->rdataFactoryFromFile(RRTYPE<TypeParam>(),
+ RRClass("IN"),
+ "rdata_txt_fromWire1")));
+
+ // Empty character string
+ EXPECT_EQ(0, this->rdata_txt_like_empty.compare(
+ *this->rdataFactoryFromFile(RRTYPE<TypeParam>(),
+ RRClass("IN"),
+ "rdata_txt_fromWire2.wire")));
+
+ // Multiple character strings
+ this->obuffer.clear();
+ this->rdataFactoryFromFile(RRTYPE<TypeParam>(), RRClass("IN"),
+ "rdata_txt_fromWire3.wire")->toWire(this->obuffer);
+ // the result should be 'wiredata_txt' repeated twice
+ vector<uint8_t> expected_data(wiredata_txt_like, wiredata_txt_like +
+ sizeof(wiredata_txt_like));
+ expected_data.insert(expected_data.end(), wiredata_txt_like,
+ wiredata_txt_like + sizeof(wiredata_txt_like));
+ matchWireData(&expected_data[0], expected_data.size(),
+ this->obuffer.getData(), this->obuffer.getLength());
+
+ // Largest length of data. There's nothing special, but should be
+ // constructed safely, and the content should be identical to the original
+ // data.
+ vector<uint8_t> largest_txt_like_data;
+ makeLargest(largest_txt_like_data);
+ InputBuffer ibuffer(&largest_txt_like_data[0],
+ largest_txt_like_data.size());
+ TypeParam largest_txt_like(ibuffer, largest_txt_like_data.size());
+ this->obuffer.clear();
+ largest_txt_like.toWire(this->obuffer);
+ matchWireData(&largest_txt_like_data[0], largest_txt_like_data.size(),
+ this->obuffer.getData(), this->obuffer.getLength());
+
+ // rdlen parameter is out of range. This is a rare event because we'd
+ // normally call the constructor via a polymorphic wrapper, where the
+ // length is validated. But this should be checked explicitly.
+ InputBuffer ibuffer2(&largest_txt_like_data[0],
+ largest_txt_like_data.size());
+ EXPECT_THROW(TypeParam(ibuffer2, 65536), InvalidRdataLength);
+
+ // RDATA is empty, which is invalid for TXT_LIKE.
+ EXPECT_THROW(this->rdataFactoryFromFile(RRTYPE<TypeParam>(), RRClass("IN"),
+ "rdata_txt_fromWire4.wire"),
+ DNSMessageFORMERR);
+
+ // character-string length is too large, which could cause overrun.
+ EXPECT_THROW(this->rdataFactoryFromFile(RRTYPE<TypeParam>(), RRClass("IN"),
+ "rdata_txt_fromWire5.wire"),
+ DNSMessageFORMERR);
+}
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, createFromLexer) {
+ EXPECT_EQ(0, this->rdata_txt_like.compare(
+ *test::createRdataUsingLexer(RRTYPE<TypeParam>(), RRClass::IN(),
+ "Test-String")));
+}
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, toWireBuffer) {
+ this->rdata_txt_like.toWire(this->obuffer);
+ matchWireData(wiredata_txt_like, sizeof(wiredata_txt_like),
+ this->obuffer.getData(), this->obuffer.getLength());
+}
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, toWireRenderer) {
+ this->rdata_txt_like.toWire(this->renderer);
+ matchWireData(wiredata_txt_like, sizeof(wiredata_txt_like),
+ this->renderer.getData(), this->renderer.getLength());
+}
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, toText) {
+ EXPECT_EQ("\"Test-String\"", this->rdata_txt_like.toText());
+ EXPECT_EQ("\"\"", this->rdata_txt_like_empty.toText());
+ EXPECT_EQ("\"Test-String\"", this->rdata_txt_like_quoted.toText());
+
+ // Check escape behavior
+ const TypeParam double_quotes("Test-String\"Test-String\"");
+ EXPECT_EQ("\"Test-String\" \"Test-String\"", double_quotes.toText());
+ const TypeParam semicolon("Test-String\\;Test-String");
+ EXPECT_EQ("\"Test-String\\;Test-String\"", semicolon.toText());
+ const TypeParam backslash("Test-String\\\\Test-String");
+ EXPECT_EQ("\"Test-String\\\\Test-String\"", backslash.toText());
+ const TypeParam before_x20("Test-String\\031Test-String");
+ EXPECT_EQ("\"Test-String\\031Test-String\"", before_x20.toText());
+ const TypeParam from_x20_to_x7e("\"Test-String ~ Test-String\"");
+ EXPECT_EQ("\"Test-String ~ Test-String\"", from_x20_to_x7e.toText());
+ const TypeParam from_x20_to_x7e_2("Test-String\\032\\126\\032Test-String");
+ EXPECT_EQ("\"Test-String ~ Test-String\"", from_x20_to_x7e_2.toText());
+ const TypeParam after_x7e("Test-String\\127Test-String");
+ EXPECT_EQ("\"Test-String\\127Test-String\"", after_x7e.toText());
+}
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, assignment) {
+ TypeParam rdata1("assignment1");
+ TypeParam rdata2("assignment2");
+ rdata1 = rdata2;
+ EXPECT_EQ(0, rdata2.compare(rdata1));
+
+ // Check if the copied data is valid even after the original is deleted
+ TypeParam* rdata3 = new TypeParam(rdata1);
+ TypeParam rdata4("assignment3");
+ rdata4 = *rdata3;
+ delete rdata3;
+ EXPECT_EQ(0, rdata4.compare(rdata1));
+
+ // Self assignment
+ rdata2 = *&rdata2;
+ EXPECT_EQ(0, rdata2.compare(rdata1));
+}
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, compare) {
+ string const txt1("aaaaaaaa");
+ string const txt2("aaaaaaaaaa");
+ string const txt3("bbbbbbbb");
+ string const txt4(129, 'a');
+ string const txt5(128, 'b');
+
+ EXPECT_EQ(TypeParam(txt1).compare(TypeParam(txt1)), 0);
+
+ EXPECT_LT(TypeParam("\"\"").compare(TypeParam(txt1)), 0);
+ EXPECT_GT(TypeParam(txt1).compare(TypeParam("\"\"")), 0);
+
+ EXPECT_LT(TypeParam(txt1).compare(TypeParam(txt2)), 0);
+ EXPECT_GT(TypeParam(txt2).compare(TypeParam(txt1)), 0);
+
+ EXPECT_LT(TypeParam(txt1).compare(TypeParam(txt3)), 0);
+ EXPECT_GT(TypeParam(txt3).compare(TypeParam(txt1)), 0);
+
+ // we're comparing the data raw, starting at the length octet, so a shorter
+ // string sorts before a longer one no matter the lexicopraphical order
+ EXPECT_LT(TypeParam(txt3).compare(TypeParam(txt2)), 0);
+ EXPECT_GT(TypeParam(txt2).compare(TypeParam(txt3)), 0);
+
+ // to make sure the length octet compares unsigned
+ EXPECT_LT(TypeParam(txt1).compare(TypeParam(txt4)), 0);
+ EXPECT_GT(TypeParam(txt4).compare(TypeParam(txt1)), 0);
+
+ EXPECT_LT(TypeParam(txt5).compare(TypeParam(txt4)), 0);
+ EXPECT_GT(TypeParam(txt4).compare(TypeParam(txt5)), 0);
+
+ // comparison attempt between incompatible RR types should be rejected
+ EXPECT_THROW(TypeParam(txt1).compare(*this->rdata_nomatch),
+ bad_cast);
+}
+
+}
diff --git a/src/lib/dns/tests/rdata_unittest.cc b/src/lib/dns/tests/rdata_unittest.cc
index 8b13789179..4bfa38c81b 100644
--- a/src/lib/dns/tests/rdata_unittest.cc
+++ b/src/lib/dns/tests/rdata_unittest.cc
@@ -1 +1,471 @@
+// Copyright (C) 2010-2023 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <functional>
+#include <iomanip>
+#include <vector>
+#include <string>
+#include <sstream>
+
+#include <util/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+#include <dns/tests/rdata_unittest.h>
+
+#include <util/unittests/wiredata.h>
+
+#include <boost/lexical_cast.hpp>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+namespace ph = std::placeholders;
+
+namespace isc {
+namespace dns {
+namespace rdata {
+
+namespace {
+void
+nullCallback(const std::string&, size_t, const std::string&) {
+}
+}
+
+RdataTest::RdataTest() :
+ obuffer(0), rdata_nomatch(createRdata(RRType(0), RRClass(1), "\\# 0")),
+ loader_cb(MasterLoaderCallbacks(nullCallback, nullCallback)) {
+}
+
+RdataPtr
+RdataTest::rdataFactoryFromFile(const RRType& rrtype, const RRClass& rrclass,
+ const char* datafile, size_t position) {
+ std::vector<unsigned char> data;
+ UnitTestUtil::readWireData(datafile, data);
+
+ InputBuffer buffer(&data[0], data.size());
+ buffer.setPosition(position);
+
+ uint16_t rdlen = buffer.readUint16();
+ return (createRdata(rrtype, rrclass, buffer, rdlen));
+}
+
+namespace test {
+
+RdataPtr
+createRdataUsingLexer(const RRType& rrtype, const RRClass& rrclass,
+ const std::string& str) {
+ std::stringstream ss(str);
+ MasterLexer lexer;
+ lexer.pushSource(ss);
+
+ MasterLoaderCallbacks callbacks(nullCallback, nullCallback);
+ const Name origin("example.org.");
+
+ return (createRdata(rrtype, rrclass, lexer, &origin,
+ MasterLoader::MANY_ERRORS, callbacks));
+}
+
+} // end of namespace isc::dns::rdata::test
+
+// A mock class to check parameters passed via loader callbacks. Its callback
+// records the passed parameters, allowing the test to check them later via
+// the check() method.
+class CreateRdataCallback {
+public:
+ enum CallbackType { NONE, ERROR, WARN };
+ CreateRdataCallback() : type_(NONE), line_(0) {}
+ void callback(CallbackType type, const string& source, size_t line,
+ const string& reason_txt) {
+ type_ = type;
+ source_ = source;
+ line_ = line;
+ reason_txt_ = reason_txt;
+ }
+
+ void clear() {
+ type_ = NONE;
+ source_.clear();
+ line_ = 0;
+ reason_txt_.clear();
+ }
+
+ // Return if callback is called since the previous call to clear().
+ bool isCalled() const { return (type_ != NONE); }
+
+ void check(const string& expected_srcname, size_t expected_line,
+ CallbackType expected_type, const string& expected_reason)
+ const
+ {
+ EXPECT_EQ(expected_srcname, source_);
+ EXPECT_EQ(expected_line, line_);
+ EXPECT_EQ(expected_type, type_);
+ EXPECT_EQ(expected_reason, reason_txt_);
+ }
+
+private:
+ CallbackType type_;
+ string source_;
+ size_t line_;
+ string reason_txt_;
+};
+
+// Test class/type-independent behavior of createRdata().
+TEST_F(RdataTest, createRdataWithLexer) {
+ const in::AAAA aaaa_rdata("2001:db8::1");
+
+ stringstream ss;
+ const string src_name = "stream-" + boost::lexical_cast<string>(&ss);
+ ss << aaaa_rdata.toText() << "\n"; // valid case
+ ss << aaaa_rdata.toText() << "; comment, should be ignored\n";
+ ss << aaaa_rdata.toText() << " extra-token\n"; // extra token
+ ss << aaaa_rdata.toText() << " extra token\n"; // 2 extra tokens
+ ss << ")\n"; // causing lexer error in parsing the RDATA text
+ ss << "192.0.2.1\n"; // semantics error: IPv4 address is given for AAAA
+ ss << aaaa_rdata.toText(); // valid, but end with EOF, not EOL
+ lexer.pushSource(ss);
+
+ CreateRdataCallback callback;
+ MasterLoaderCallbacks callbacks(
+ std::bind(&CreateRdataCallback::callback, &callback,
+ CreateRdataCallback::ERROR, ph::_1, ph::_2, ph::_3),
+ std::bind(&CreateRdataCallback::callback, &callback,
+ CreateRdataCallback::WARN, ph::_1, ph::_2, ph::_3));
+
+ size_t line = 0;
+
+ // Valid case.
+ ++line;
+ ConstRdataPtr rdata = createRdata(RRType::AAAA(), RRClass::IN(), lexer,
+ NULL, MasterLoader::MANY_ERRORS,
+ callbacks);
+ EXPECT_EQ(0, aaaa_rdata.compare(*rdata));
+ EXPECT_FALSE(callback.isCalled());
+
+ // Similar to the previous case, but RDATA is followed by a comment.
+ // It should cause any confusion.
+ ++line;
+ callback.clear();
+ rdata = createRdata(RRType::AAAA(), RRClass::IN(), lexer, NULL,
+ MasterLoader::MANY_ERRORS, callbacks);
+ EXPECT_EQ(0, aaaa_rdata.compare(*rdata));
+ EXPECT_FALSE(callback.isCalled());
+
+ // Broken RDATA text: extra token. createRdata() returns NULL, error
+ // callback is called.
+ ++line;
+ callback.clear();
+ EXPECT_FALSE(createRdata(RRType::AAAA(), RRClass::IN(), lexer, NULL,
+ MasterLoader::MANY_ERRORS, callbacks));
+ callback.check(src_name, line, CreateRdataCallback::ERROR,
+ "createRdata from text failed near 'extra-token': "
+ "extra input text");
+
+ // Similar to the previous case, but only the first extra token triggers
+ // callback.
+ ++line;
+ callback.clear();
+ EXPECT_FALSE(createRdata(RRType::AAAA(), RRClass::IN(), lexer, NULL,
+ MasterLoader::MANY_ERRORS, callbacks));
+ callback.check(src_name, line, CreateRdataCallback::ERROR,
+ "createRdata from text failed near 'extra': "
+ "extra input text");
+
+ // Lexer error will happen, corresponding error callback will be triggered.
+ ++line;
+ callback.clear();
+ EXPECT_FALSE(createRdata(RRType::AAAA(), RRClass::IN(), lexer, NULL,
+ MasterLoader::MANY_ERRORS, callbacks));
+ callback.check(src_name, line, CreateRdataCallback::ERROR,
+ "createRdata from text failed: unbalanced parentheses");
+
+ // Semantics level error will happen, corresponding error callback will be
+ // triggered.
+ ++line;
+ callback.clear();
+ EXPECT_FALSE(createRdata(RRType::AAAA(), RRClass::IN(), lexer, NULL,
+ MasterLoader::MANY_ERRORS, callbacks));
+ callback.check(src_name, line, CreateRdataCallback::ERROR,
+ "createRdata from text failed: Bad IN/AAAA RDATA text: "
+ "'192.0.2.1'");
+
+ // Input is valid and parse will succeed, but with a warning that the
+ // file is not ended with a newline.
+ ++line;
+ callback.clear();
+ rdata = createRdata(RRType::AAAA(), RRClass::IN(), lexer, NULL,
+ MasterLoader::MANY_ERRORS, callbacks);
+ EXPECT_EQ(0, aaaa_rdata.compare(*rdata));
+ callback.check(src_name, line, CreateRdataCallback::WARN,
+ "file does not end with newline");
+}
+
+TEST_F(RdataTest, getLength) {
+ const in::AAAA aaaa_rdata("2001:db8::1");
+ EXPECT_EQ(16, aaaa_rdata.getLength());
+
+ const generic::TXT txt_rdata("Hello World");
+ EXPECT_EQ(12, txt_rdata.getLength());
+}
+
+}
+}
+}
+
+namespace {
+
+// Wire-format data correspond to rdata_unknown. Note that it doesn't
+// include RDLENGTH.
+const uint8_t wiredata_unknown[] = { 0xa1, 0xb2, 0xc3, 0x0d };
+
+class Rdata_Unknown_Test : public RdataTest {
+public:
+ Rdata_Unknown_Test() :
+ // "Unknown" RR Type used for the test cases below. If/when we
+ // use this type number as a "well-known" (probably
+ // experimental) type, we'll need to renumber it.
+ unknown_rrtype(RRType(65000)),
+ rdata_unknowntxt("\\# 4 a1b2c30d"),
+ rdata_unknown(rdata_unknowntxt)
+ {}
+protected:
+ static string getLongestRdataTxt();
+ static void getLongestRdataWire(vector<uint8_t>& v);
+
+ const RRType unknown_rrtype;
+ const std::string rdata_unknowntxt;
+ const generic::Generic rdata_unknown;
+};
+
+string
+Rdata_Unknown_Test::getLongestRdataTxt() {
+ ostringstream oss;
+
+ oss << "\\# " << MAX_RDLENGTH << " ";
+ oss.fill('0');
+ oss << right << hex;
+ for (int i = 0; i < MAX_RDLENGTH; i++) {
+ oss << setw(2) << (i & 0xff);
+ }
+
+ return (oss.str());
+}
+
+void
+Rdata_Unknown_Test::getLongestRdataWire(vector<uint8_t>& v) {
+ unsigned char ch = 0;
+ for (int i = 0; i < MAX_RDLENGTH; ++i, ++ch) {
+ v.push_back(ch);
+ }
+}
+
+TEST_F(Rdata_Unknown_Test, createFromText) {
+ // valid construction. This also tests a normal case of "FromWire".
+ EXPECT_EQ(0, generic::Generic("\\# 4 a1b2c30d").compare(
+ *rdataFactoryFromFile(unknown_rrtype, RRClass::IN(),
+ "rdata_unknown_fromWire")));
+ // upper case hexadecimal digits should also be okay.
+ EXPECT_EQ(0, generic::Generic("\\# 4 A1B2C30D").compare(
+ *rdataFactoryFromFile(unknown_rrtype, RRClass::IN(),
+ "rdata_unknown_fromWire")));
+ // 0-length RDATA should be accepted
+ EXPECT_EQ(0, generic::Generic("\\# 0").compare(
+ *rdataFactoryFromFile(unknown_rrtype, RRClass::IN(),
+ "rdata_unknown_fromWire", 6)));
+ // hex encoding can be space-separated
+ EXPECT_EQ(0, generic::Generic("\\# 4 a1 b2c30d").compare(rdata_unknown));
+ EXPECT_EQ(0, generic::Generic("\\# 4 a1b2 c30d").compare(rdata_unknown));
+ EXPECT_EQ(0, generic::Generic("\\# 4 a1 b2 c3 0d").compare(rdata_unknown));
+ EXPECT_EQ(0, generic::Generic("\\# 4 a1\tb2c3 0d").compare(rdata_unknown));
+
+ // Max-length RDATA
+ vector<uint8_t> v;
+ getLongestRdataWire(v);
+ InputBuffer ibuffer(&v[0], v.size());
+ EXPECT_EQ(0, generic::Generic(getLongestRdataTxt()).compare(
+ generic::Generic(ibuffer, v.size())));
+
+ // the length field must match the encoding data length.
+ EXPECT_THROW(generic::Generic("\\# 4 1080c0ff00"), InvalidRdataLength);
+ EXPECT_THROW(generic::Generic("\\# 5 1080c0ff"), InvalidRdataLength);
+ // RDATA encoding part must consist of an even number of hex digits.
+ EXPECT_THROW(generic::Generic("\\# 1 1"), InvalidRdataText);
+ EXPECT_THROW(generic::Generic("\\# 1 ax"), InvalidRdataText);
+ // the length should be 16-bit unsigned integer
+ EXPECT_THROW(generic::Generic("\\# 65536 a1b2c30d"), InvalidRdataLength);
+ EXPECT_THROW(generic::Generic("\\# -1 a1b2c30d"), InvalidRdataLength);
+ EXPECT_THROW(generic::Generic("\\# 1.1 a1"), InvalidRdataLength);
+ EXPECT_THROW(generic::Generic("\\# 0a 00010203040506070809"),
+ InvalidRdataLength);
+ // should reject if the special token is missing.
+ EXPECT_THROW(generic::Generic("4 a1b2c30d"), InvalidRdataText);
+ // the special token, the RDLENGTH and the data must be space separated.
+ EXPECT_THROW(generic::Generic("\\#0"), InvalidRdataText);
+ EXPECT_THROW(generic::Generic("\\# 1ff"), InvalidRdataLength);
+}
+
+TEST_F(Rdata_Unknown_Test, createFromWire) {
+ // normal case (including 0-length data) is covered in createFromText.
+
+ // buffer too short. the error should be detected in buffer read
+ EXPECT_THROW(rdataFactoryFromFile(unknown_rrtype, RRClass::IN(),
+ "rdata_unknown_fromWire", 8),
+ InvalidBufferPosition);
+
+ // too large data
+ vector<uint8_t> v;
+ getLongestRdataWire(v);
+ v.push_back(0); // making it too long
+ InputBuffer ibuffer(&v[0], v.size());
+ EXPECT_THROW(generic::Generic(ibuffer, v.size()), InvalidRdataLength);
+}
+
+// The following 3 sets of tests check the behavior of createRdata() variants
+// with the "unknown" RRtype. The result should be RRclass independent.
+TEST_F(Rdata_Unknown_Test, createRdataFromString) {
+ EXPECT_EQ(0, rdata_unknown.compare(
+ *createRdata(unknown_rrtype, RRClass::IN(),
+ rdata_unknowntxt)));
+ EXPECT_EQ(0, rdata_unknown.compare(
+ *createRdata(unknown_rrtype, RRClass::CH(),
+ rdata_unknowntxt)));
+ EXPECT_EQ(0, rdata_unknown.compare(
+ *createRdata(unknown_rrtype, RRClass("CLASS65000"),
+ rdata_unknowntxt)));
+}
+
+TEST_F(Rdata_Unknown_Test, createRdataFromWire) {
+ InputBuffer ibuffer(wiredata_unknown, sizeof(wiredata_unknown));
+ EXPECT_EQ(0, rdata_unknown.compare(
+ *createRdata(unknown_rrtype, RRClass::IN(),
+ ibuffer, sizeof(wiredata_unknown))));
+
+ InputBuffer ibuffer2(wiredata_unknown, sizeof(wiredata_unknown));
+ EXPECT_EQ(0, rdata_unknown.compare(
+ *createRdata(unknown_rrtype, RRClass::CH(),
+ ibuffer2, sizeof(wiredata_unknown))));
+
+ InputBuffer ibuffer3(wiredata_unknown, sizeof(wiredata_unknown));
+ EXPECT_EQ(0, rdata_unknown.compare(
+ *createRdata(unknown_rrtype, RRClass(65000),
+ ibuffer3, sizeof(wiredata_unknown))));
+}
+
+TEST_F(Rdata_Unknown_Test, createRdataByCopy) {
+ EXPECT_EQ(0, rdata_unknown.compare(
+ *createRdata(unknown_rrtype, RRClass::IN(), rdata_unknown)));
+ EXPECT_EQ(0, rdata_unknown.compare(
+ *createRdata(unknown_rrtype, RRClass::CH(), rdata_unknown)));
+ EXPECT_EQ(0, rdata_unknown.compare(
+ *createRdata(unknown_rrtype, RRClass(65000),
+ rdata_unknown)));
+}
+
+TEST_F(Rdata_Unknown_Test, copyConstruct) {
+ generic::Generic copy(rdata_unknown);
+ EXPECT_EQ(0, copy.compare(rdata_unknown));
+
+ // Check the copied data is valid even after the original is deleted
+ generic::Generic* copy2 = new generic::Generic(rdata_unknown);
+ generic::Generic copy3(*copy2);
+ delete copy2;
+ EXPECT_EQ(0, copy3.compare(rdata_unknown));
+}
+
+TEST_F(Rdata_Unknown_Test, assignment) {
+ generic::Generic copy("\\# 1 10");
+ copy = rdata_unknown;
+ EXPECT_EQ(0, copy.compare(rdata_unknown));
+
+ // Check if the copied data is valid even after the original is deleted
+ generic::Generic* copy2 = new generic::Generic(rdata_unknown);
+ generic::Generic copy3("\\# 1 10");
+ copy3 = *copy2;
+ delete copy2;
+ EXPECT_EQ(0, copy3.compare(rdata_unknown));
+
+ // Self assignment
+ copy = *&copy;
+ EXPECT_EQ(0, copy.compare(rdata_unknown));
+}
+
+TEST_F(Rdata_Unknown_Test, toText) {
+ EXPECT_EQ(rdata_unknowntxt, rdata_unknown.toText());
+ EXPECT_EQ(getLongestRdataTxt(),
+ generic::Generic(getLongestRdataTxt()).toText());
+}
+
+TEST_F(Rdata_Unknown_Test, toWireBuffer) {
+ rdata_unknown.toWire(obuffer);
+ matchWireData(wiredata_unknown, sizeof(wiredata_unknown),
+ obuffer.getData(), obuffer.getLength());
+}
+
+TEST_F(Rdata_Unknown_Test, toWireRenderer) {
+ rdata_unknown.toWire(renderer);
+ matchWireData(wiredata_unknown, sizeof(wiredata_unknown),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(Rdata_Unknown_Test, compare) {
+ // comparison as left-justified unsigned octet sequences:
+ // cppcheck-suppress uselessCallsCompare
+ EXPECT_EQ(0, rdata_unknown.compare(rdata_unknown));
+
+ generic::Generic rdata_unknown_small("\\# 4 00b2c3ff");
+ EXPECT_GT(0, rdata_unknown_small.compare(rdata_unknown));
+ EXPECT_LT(0, rdata_unknown.compare(rdata_unknown_small));
+
+ generic::Generic rdata_unknown_large("\\# 4 ffb2c300");
+ EXPECT_LT(0, rdata_unknown_large.compare(rdata_unknown));
+ EXPECT_GT(0, rdata_unknown.compare(rdata_unknown_large));
+
+ // the absence of an octet sorts before a zero octet.
+ generic::Generic rdata_unknown_short("\\# 3 a1b2c3");
+ EXPECT_GT(0, rdata_unknown_short.compare(rdata_unknown));
+ EXPECT_LT(0, rdata_unknown.compare(rdata_unknown_short));
+}
+
+TEST_F(Rdata_Unknown_Test, LeftShiftOperator) {
+ ostringstream oss;
+ oss << rdata_unknown;
+ EXPECT_EQ(rdata_unknown.toText(), oss.str());
+}
+
+//
+// Tests for global utility functions
+//
+TEST_F(RdataTest, compareNames) {
+ Name small("a.example");
+ Name large("example");
+
+ // Check the case where the order is different from the owner name
+ // comparison:
+ EXPECT_TRUE(small > large);
+ EXPECT_EQ(-1, compareNames(small, large));
+ EXPECT_EQ(1, compareNames(large, small));
+
+ // Check case insensitive comparison:
+ Name small_upper("A.EXAMPLE");
+ EXPECT_EQ(0, compareNames(small, small_upper));
+
+ // the absence of an octet sorts before a zero octet.
+ Name large2("a.example2");
+ EXPECT_EQ(-1, compareNames(small, large2));
+ EXPECT_EQ(1, compareNames(large2, small));
+}
+}
diff --git a/src/lib/dns/tests/rdata_unittest.h b/src/lib/dns/tests/rdata_unittest.h
index 8b13789179..c412bbbc06 100644
--- a/src/lib/dns/tests/rdata_unittest.h
+++ b/src/lib/dns/tests/rdata_unittest.h
@@ -1 +1,87 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef RDATA_UNITTEST_H
+#define RDATA_UNITTEST_H
+
+#include <util/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/rdata.h>
+#include <dns/master_lexer.h>
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <sstream>
+
+namespace isc {
+namespace dns {
+namespace rdata {
+class RdataTest : public ::testing::Test {
+protected:
+ RdataTest();
+ static RdataPtr rdataFactoryFromFile(const RRType& rrtype,
+ const RRClass& rrclass,
+ const char* datafile,
+ size_t position = 0);
+
+ // Common check to see the result of Rdata construction of given type
+ // (template parameter RdataType) either from std::string or with
+ // MasterLexer object. If it's expected to succeed the result should be
+ // identical to the commonly used test data (rdata_expected); otherwise it
+ // should result in the exception specified as the template parameter:
+ // ExForString for the string version, and ExForLexer for the lexer
+ // version. throw_str_version and throw_lexer_version are set to true
+ // iff the string/lexer version is expected to throw, respectively.
+ // Parameter origin can be set to non NULL for the origin parameter of
+ // the lexer version of Rdata constructor.
+ template <typename RdataType, typename ExForString, typename ExForLexer>
+ void checkFromText(const std::string& rdata_txt,
+ const RdataType& rdata_expected,
+ bool throw_str_version = true,
+ bool throw_lexer_version = true,
+ const Name* origin = NULL) {
+ SCOPED_TRACE(rdata_txt);
+
+ if (throw_str_version) {
+ EXPECT_THROW(RdataType rdata(rdata_txt), ExForString);
+ } else {
+ EXPECT_EQ(0, RdataType(rdata_txt).compare(rdata_expected));
+ }
+
+ std::stringstream ss(rdata_txt);
+ MasterLexer lexer;
+ lexer.pushSource(ss);
+ if (throw_lexer_version) {
+ EXPECT_THROW(RdataType rdata(lexer, origin, MasterLoader::DEFAULT,
+ loader_cb), ExForLexer);
+ } else {
+ EXPECT_EQ(0, RdataType(lexer, origin, MasterLoader::DEFAULT,
+ loader_cb).compare(rdata_expected));
+ }
+ }
+
+ isc::util::OutputBuffer obuffer;
+ MessageRenderer renderer;
+ /// This is an RDATA object of some "unknown" RR type so that it can be
+ /// used to test the compare() method against a well-known RR type.
+ RdataPtr rdata_nomatch;
+ MasterLexer lexer;
+ MasterLoaderCallbacks loader_cb;
+};
+
+namespace test {
+RdataPtr
+createRdataUsingLexer(const RRType& rrtype, const RRClass& rrclass,
+ const std::string& str);
+}
+
+}
+}
+}
+#endif // RDATA_UNITTEST_H
diff --git a/src/lib/dns/tests/rdatafields_unittest.cc b/src/lib/dns/tests/rdatafields_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rdatafields_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rrclass_unittest.cc b/src/lib/dns/tests/rrclass_unittest.cc
index 8b13789179..54e616cd77 100644
--- a/src/lib/dns/tests/rrclass_unittest.cc
+++ b/src/lib/dns/tests/rrclass_unittest.cc
@@ -1 +1,174 @@
+// Copyright (C) 2010-2017 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <gtest/gtest.h>
+
+#include <util/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rrclass.h>
+
+#include <dns/tests/unittest_util.h>
+#include <util/unittests/wiredata.h>
+
+#include <boost/scoped_ptr.hpp>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+using namespace isc::util;
+using boost::scoped_ptr;
+using isc::util::unittests::matchWireData;
+
+namespace {
+class RRClassTest : public ::testing::Test {
+protected:
+ RRClassTest() : obuffer(0) {}
+
+ OutputBuffer obuffer;
+ MessageRenderer renderer;
+
+ static RRClass rrclassFactoryFromWire(const char* datafile);
+ static const RRClass rrclass_1, rrclass_0x80, rrclass_0x800,
+ rrclass_0x8000, rrclass_max;
+ static const uint8_t wiredata[];
+};
+
+const RRClass RRClassTest::rrclass_1(1);
+const RRClass RRClassTest::rrclass_0x80(0x80);
+const RRClass RRClassTest::rrclass_0x800(0x800);
+const RRClass RRClassTest::rrclass_0x8000(0x8000);
+const RRClass RRClassTest::rrclass_max(0xffff);
+// This is wire-format data for the above sample RRClass rendered in the
+// appearing order.
+const uint8_t RRClassTest::wiredata[] = { 0x00, 0x01, 0x00, 0x80, 0x08,
+ 0x00, 0x80, 0x00, 0xff, 0xff };
+
+RRClass
+RRClassTest::rrclassFactoryFromWire(const char* datafile) {
+ std::vector<unsigned char> data;
+ UnitTestUtil::readWireData(datafile, data);
+
+ InputBuffer buffer(&data[0], data.size());
+
+ return (RRClass(buffer));
+}
+
+TEST_F(RRClassTest, fromTextConstructor) {
+ EXPECT_EQ("IN", RRClass("IN").toText());
+ EXPECT_EQ("CH", RRClass("CH").toText());
+
+ EXPECT_EQ("CLASS65535", RRClass("CLASS65535").toText());
+
+ // some uncommon cases: see the corresponding RRType tests.
+ EXPECT_EQ(53, RRClass("CLASS00053").getCode());
+ EXPECT_THROW(RRClass("CLASS000053"), InvalidRRClass);
+
+ // bogus CLASSnnn representations: should trigger an exception
+ EXPECT_THROW(RRClass("CLASS"), InvalidRRClass);
+ EXPECT_THROW(RRClass("CLASS-1"), InvalidRRClass);
+ EXPECT_THROW(RRClass("CLASSxxx"), InvalidRRClass);
+ EXPECT_THROW(RRClass("CLASS65536"), InvalidRRClass);
+ EXPECT_THROW(RRClass("CLASS6500x"), InvalidRRClass);
+ EXPECT_THROW(RRClass("CLASS65000 "), InvalidRRClass);
+}
+
+TEST_F(RRClassTest, fromWire) {
+ EXPECT_EQ(0x1234,
+ rrclassFactoryFromWire("rrcode16_fromWire1").getCode());
+ EXPECT_THROW(rrclassFactoryFromWire("rrcode16_fromWire2"),
+ IncompleteRRClass);
+}
+
+TEST_F(RRClassTest, caseConstruct) {
+ EXPECT_EQ("IN", RRClass("in").toText());
+ EXPECT_EQ("CH", RRClass("ch").toText());
+ EXPECT_EQ("CLASS65535", RRClass("class65535").toText());
+}
+
+TEST_F(RRClassTest, toText) {
+ EXPECT_EQ("IN", RRClass(1).toText());
+ EXPECT_EQ("CLASS65000", RRClass(65000).toText());
+}
+
+TEST_F(RRClassTest, createFromText) {
+ scoped_ptr<RRClass> chclass(RRClass::createFromText("CH"));
+ EXPECT_TRUE(chclass);
+ EXPECT_EQ("CH", chclass->toText());
+
+ scoped_ptr<RRClass> zzclass(RRClass::createFromText("ZZ"));
+ EXPECT_FALSE(zzclass);
+}
+
+TEST_F(RRClassTest, toWireBuffer) {
+ rrclass_1.toWire(obuffer);
+ rrclass_0x80.toWire(obuffer);
+ rrclass_0x800.toWire(obuffer);
+ rrclass_0x8000.toWire(obuffer);
+ rrclass_max.toWire(obuffer);
+
+ matchWireData(wiredata, sizeof (wiredata),
+ obuffer.getData(), obuffer.getLength());
+}
+
+TEST_F(RRClassTest, toWireRenderer) {
+ rrclass_1.toWire(renderer);
+ rrclass_0x80.toWire(renderer);
+ rrclass_0x800.toWire(renderer);
+ rrclass_0x8000.toWire(renderer);
+ rrclass_max.toWire(renderer);
+
+ matchWireData(wiredata, sizeof (wiredata),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(RRClassTest, wellKnownClass) {
+ EXPECT_EQ(1, RRClass::IN().getCode());
+ EXPECT_EQ("IN", RRClass::IN().toText());
+}
+
+TEST_F(RRClassTest, compare) {
+ EXPECT_TRUE(RRClass(1) == RRClass("IN"));
+ EXPECT_TRUE(RRClass(1).equals(RRClass("IN")));
+ EXPECT_TRUE(RRClass(0).nequals(RRClass("IN")));
+
+ EXPECT_TRUE(RRClass("IN") < RRClass("CH"));
+ EXPECT_TRUE(RRClass(100) < RRClass(65535));
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST_F(RRClassTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << RRClass::IN();
+ EXPECT_EQ(RRClass::IN().toText(), oss.str());
+}
+
+// Below, we'll check definitions for all well-known RR classes; whether they
+// are defined and have the correct parameter values. Test data are generated
+// from the list available at:
+// http://www.iana.org/assignments/dns-parameters/dns-parameters.xml
+struct ClassParam {
+ const char* const txt; // "IN", "CH", etc
+ const uint16_t code; // 1, 3,
+ const RRClass& (*obj)(); // RRClass::IN(), etc
+} known_classes[] = {
+ {"IN", 1, RRClass::IN}, {"CH", 3, RRClass::CH},
+ {"NONE", 254, RRClass::NONE}, {"ANY", 255, RRClass::ANY},
+ {NULL, 0, NULL}
+};
+
+TEST(RRClassConstTest, wellKnowns) {
+ for (int i = 0; known_classes[i].txt; ++i) {
+ SCOPED_TRACE("Checking well known RRClass: " +
+ string(known_classes[i].txt));
+ EXPECT_EQ(known_classes[i].code,
+ RRClass(known_classes[i].txt).getCode());
+ EXPECT_EQ(known_classes[i].code,
+ (*known_classes[i].obj)().getCode());
+ }
+}
+}
diff --git a/src/lib/dns/tests/rrcollator_unittest.cc b/src/lib/dns/tests/rrcollator_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rrcollator_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rrparamregistry_unittest.cc b/src/lib/dns/tests/rrparamregistry_unittest.cc
index b928cc603f..a5e26656a2 100644
--- a/src/lib/dns/tests/rrparamregistry_unittest.cc
+++ b/src/lib/dns/tests/rrparamregistry_unittest.cc
@@ -1,3 +1,9 @@
+// Copyright (C) 2010-2020 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
#include <config.h>
#include <string>
@@ -18,10 +24,14 @@
using namespace std;
using namespace isc::dns;
-using namespace isc::util;
using namespace isc::dns::rdata;
+using namespace isc::util;
namespace {
+void
+nullCallback(const std::string&, size_t, const std::string&) {
+}
+
class RRParamRegistryTest : public ::testing::Test {
protected:
RRParamRegistryTest()
@@ -155,7 +165,7 @@ createRdataHelper(const std::string& str) {
MasterLexer lexer;
lexer.pushSource(ss);
- MasterLoaderCallbacks callbacks(MasterLoaderCallbacks::getNullCallbacks());
+ MasterLoaderCallbacks callbacks(nullCallback, nullCallback);
const Name origin("example.org.");
return (rdf->create(lexer, &origin,
diff --git a/src/lib/dns/tests/rrset_collection_unittest.cc b/src/lib/dns/tests/rrset_collection_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/rrset_collection_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tests/rrset_unittest.cc b/src/lib/dns/tests/rrset_unittest.cc
index 8b13789179..447fed5085 100644
--- a/src/lib/dns/tests/rrset_unittest.cc
+++ b/src/lib/dns/tests/rrset_unittest.cc
@@ -1 +1,441 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <util/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/rrttl.h>
+#include <dns/rrset.h>
+
+#include <dns/tests/unittest_util.h>
+#include <util/unittests/wiredata.h>
+
+#include <gtest/gtest.h>
+
+#include <stdexcept>
+#include <sstream>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+namespace {
+class RRsetTest : public ::testing::Test {
+protected:
+ RRsetTest() : buffer(0),
+ test_name("test.example.com"),
+ test_domain("example.com"),
+ test_nsname("ns.example.com"),
+ rrset_a(test_name, RRClass::IN(), RRType::A(), RRTTL(3600)),
+ rrset_a_empty(test_name, RRClass::IN(), RRType::A(),
+ RRTTL(3600)),
+ rrset_any_a_empty(test_name, RRClass::ANY(), RRType::A(),
+ RRTTL(3600)),
+ rrset_none_a_empty(test_name, RRClass::NONE(), RRType::A(),
+ RRTTL(3600)),
+ rrset_ns(test_domain, RRClass::IN(), RRType::NS(),
+ RRTTL(86400)),
+ rrset_ch_txt(test_domain, RRClass::CH(), RRType::TXT(),
+ RRTTL(0)) {
+ rrset_a.addRdata(in::A("192.0.2.1"));
+ rrset_a.addRdata(in::A("192.0.2.2"));
+ }
+
+ OutputBuffer buffer;
+ MessageRenderer renderer;
+ Name test_name;
+ Name test_domain;
+ Name test_nsname;
+ RRset rrset_a;
+ RRset rrset_a_empty;
+ RRset rrset_any_a_empty;
+ RRset rrset_none_a_empty;
+ RRset rrset_ns;
+ RRset rrset_ch_txt;
+ std::vector<unsigned char> wiredata;
+
+ // max number of Rdata objects added to a test RRset object.
+ // this is an arbitrary chosen limit, but should be sufficiently large
+ // in practice and reasonable even as an extreme test case.
+ static const int MAX_RDATA_COUNT = 100;
+};
+
+TEST_F(RRsetTest, getRdataCount) {
+ for (int i = 0; i < MAX_RDATA_COUNT; ++i) {
+ EXPECT_EQ(i, rrset_a_empty.getRdataCount());
+ rrset_a_empty.addRdata(in::A("192.0.2.1"));
+ }
+}
+
+TEST_F(RRsetTest, getName) {
+ EXPECT_EQ(test_name, rrset_a.getName());
+ EXPECT_EQ(test_domain, rrset_ns.getName());
+}
+
+TEST_F(RRsetTest, getClass) {
+ EXPECT_EQ(RRClass("IN"), rrset_a.getClass());
+ EXPECT_EQ(RRClass("CH"), rrset_ch_txt.getClass());
+}
+
+TEST_F(RRsetTest, getType) {
+ EXPECT_EQ(RRType("A"), rrset_a.getType());
+ EXPECT_EQ(RRType("NS"), rrset_ns.getType());
+ EXPECT_EQ(RRType("TXT"), rrset_ch_txt.getType());
+}
+
+TEST_F(RRsetTest, getTTL) {
+ EXPECT_EQ(RRTTL(3600), rrset_a.getTTL());
+ EXPECT_EQ(RRTTL(86400), rrset_ns.getTTL());
+ EXPECT_EQ(RRTTL(0), rrset_ch_txt.getTTL());
+}
+
+TEST_F(RRsetTest, setTTL) {
+ rrset_a.setTTL(RRTTL(86400));
+ EXPECT_EQ(RRTTL(86400), rrset_a.getTTL());
+ rrset_a.setTTL(RRTTL(0));
+ EXPECT_EQ(RRTTL(0), rrset_a.getTTL());
+}
+
+TEST_F(RRsetTest, isSameKind) {
+ RRset rrset_w(test_name, RRClass::IN(), RRType::A(), RRTTL(3600));
+ RRset rrset_x(test_name, RRClass::IN(), RRType::A(), RRTTL(3600));
+ RRset rrset_y(test_name, RRClass::IN(), RRType::NS(), RRTTL(3600));
+ RRset rrset_z(test_name, RRClass::CH(), RRType::A(), RRTTL(3600));
+ RRset rrset_p(test_nsname, RRClass::IN(), RRType::A(), RRTTL(3600));
+
+ EXPECT_TRUE(rrset_w.isSameKind(rrset_w));
+ EXPECT_TRUE(rrset_w.isSameKind(rrset_x));
+ EXPECT_FALSE(rrset_w.isSameKind(rrset_y));
+ EXPECT_FALSE(rrset_w.isSameKind(rrset_z));
+ EXPECT_FALSE(rrset_w.isSameKind(rrset_p));
+}
+
+void
+addRdataTestCommon(const RRset& rrset) {
+ ASSERT_EQ(2, rrset.getRdataCount());
+
+ RdataIteratorPtr it = rrset.getRdataIterator(); // cursor is set to the 1st
+ EXPECT_FALSE(it->isLast());
+ EXPECT_EQ(0, it->getCurrent().compare(in::A("192.0.2.1")));
+ it->next();
+ EXPECT_FALSE(it->isLast());
+ EXPECT_EQ(0, it->getCurrent().compare(in::A("192.0.2.2")));
+ it->next();
+ EXPECT_TRUE(it->isLast());
+}
+
+TEST_F(RRsetTest, addRdata) {
+ addRdataTestCommon(rrset_a);
+
+ // Reference version of addRdata() doesn't allow to add a different
+ // type of Rdata.
+ EXPECT_THROW(rrset_a.addRdata(generic::NS(test_nsname)), std::bad_cast);
+}
+
+TEST_F(RRsetTest, addRdataPtr) {
+ rrset_a_empty.addRdata(createRdata(rrset_a_empty.getType(),
+ rrset_a_empty.getClass(),
+ "192.0.2.1"));
+ rrset_a_empty.addRdata(createRdata(rrset_a_empty.getType(),
+ rrset_a_empty.getClass(),
+ "192.0.2.2"));
+ addRdataTestCommon(rrset_a_empty);
+}
+
+TEST_F(RRsetTest, addRdataPtrMismatched) {
+ // Pointer version of addRdata() doesn't type check and does allow to
+ //add a different type of Rdata as a result.
+
+ // Type mismatch
+ rrset_a_empty.addRdata(createRdata(RRType::NS(), RRClass::IN(),
+ "ns.example.com."));
+ EXPECT_EQ(1, rrset_a_empty.getRdataCount());
+
+ // Class mismatch
+ rrset_ch_txt.addRdata(createRdata(RRType::TXT(), RRClass::IN(),
+ "Test String"));
+ EXPECT_EQ(1, rrset_ch_txt.getRdataCount());
+}
+
+TEST_F(RRsetTest, addRdataString) {
+ rrset_a_empty.addRdata("192.0.2.1");
+ rrset_a_empty.addRdata("192.0.2.2");
+
+ addRdataTestCommon(rrset_a_empty);
+
+ // String version of addRdata() will throw for bad RDATA for
+ // RRType::A().
+ EXPECT_THROW(rrset_a_empty.addRdata("ns.example.com."), InvalidRdataText);
+ addRdataTestCommon(rrset_a_empty);
+}
+
+TEST_F(RRsetTest, iterator) {
+ // Iterator for an empty RRset.
+ RdataIteratorPtr it = rrset_a_empty.getRdataIterator();
+ EXPECT_TRUE(it->isLast());
+
+ // Normal case (already tested, but do it again just in case)
+ rrset_a_empty.addRdata(in::A("192.0.2.1"));
+ rrset_a_empty.addRdata(in::A("192.0.2.2"));
+ addRdataTestCommon(rrset_a_empty);
+
+ // Rewind test: should be repeat the iteration by calling first().
+ for (int i = 0; i < 2; ++i) {
+ it = rrset_a_empty.getRdataIterator();
+ it->first();
+ EXPECT_FALSE(it->isLast());
+ it->next();
+ EXPECT_FALSE(it->isLast());
+ it->next();
+ EXPECT_TRUE(it->isLast());
+ }
+}
+
+TEST_F(RRsetTest, toText) {
+ EXPECT_EQ("test.example.com. 3600 IN A 192.0.2.1\n"
+ "test.example.com. 3600 IN A 192.0.2.2\n",
+ rrset_a.toText());
+
+ // toText() cannot be performed for an empty RRset
+ EXPECT_THROW(rrset_a_empty.toText(), EmptyRRset);
+
+ // Unless it is type ANY or NONE
+ EXPECT_EQ("test.example.com. 3600 ANY A\n",
+ rrset_any_a_empty.toText());
+ EXPECT_EQ("test.example.com. 3600 NONE A\n",
+ rrset_none_a_empty.toText());
+}
+
+TEST_F(RRsetTest, getLength) {
+ // Empty RRset should throw
+ EXPECT_THROW(rrset_a_empty.getLength(), EmptyRRset);
+
+ // Unless it is type ANY or NONE:
+ // test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets
+ // TYPE field = 2 octets
+ // CLASS field = 2 octets
+ // TTL field = 4 octets
+ // RDLENGTH field = 2 octets
+ // Total = 18 + 2 + 2 + 4 + 2 = 28 octets
+ EXPECT_EQ(28, rrset_any_a_empty.getLength());
+ EXPECT_EQ(28, rrset_none_a_empty.getLength());
+
+ // RRset with single RDATA
+ // 28 (above) + 4 octets (A RDATA) = 32 octets
+ rrset_a_empty.addRdata(in::A("192.0.2.1"));
+ EXPECT_EQ(32, rrset_a_empty.getLength());
+
+ // 2 A RRs
+ rrset_a_empty.addRdata(in::A("192.0.2.2"));
+ EXPECT_EQ(32 + 32, rrset_a_empty.getLength());
+}
+
+TEST_F(RRsetTest, toWireBuffer) {
+ rrset_a.toWire(buffer);
+
+ UnitTestUtil::readWireData("rrset_toWire1", wiredata);
+ matchWireData(&wiredata[0], wiredata.size(),
+ buffer.getData(), buffer.getLength());
+
+ // toWire() cannot be performed for an empty RRset except when
+ // class=ANY or class=NONE.
+ buffer.clear();
+ EXPECT_THROW(rrset_a_empty.toWire(buffer), EmptyRRset);
+
+ // When class=ANY or class=NONE, toWire() can also be performed for
+ // an empty RRset.
+ buffer.clear();
+ rrset_any_a_empty.toWire(buffer);
+ wiredata.clear();
+ UnitTestUtil::readWireData("rrset_toWire3", wiredata);
+ matchWireData(&wiredata[0], wiredata.size(),
+ buffer.getData(), buffer.getLength());
+
+ buffer.clear();
+ rrset_none_a_empty.toWire(buffer);
+ wiredata.clear();
+ UnitTestUtil::readWireData("rrset_toWire4", wiredata);
+ matchWireData(&wiredata[0], wiredata.size(),
+ buffer.getData(), buffer.getLength());
+}
+
+TEST_F(RRsetTest, toWireRenderer) {
+ rrset_ns.addRdata(generic::NS(test_nsname));
+
+ rrset_a.toWire(renderer);
+ rrset_ns.toWire(renderer);
+
+ UnitTestUtil::readWireData("rrset_toWire2", wiredata);
+ matchWireData(&wiredata[0], wiredata.size(),
+ renderer.getData(), renderer.getLength());
+
+ // toWire() cannot be performed for an empty RRset except when
+ // class=ANY or class=NONE.
+ renderer.clear();
+ EXPECT_THROW(rrset_a_empty.toWire(renderer), EmptyRRset);
+
+ // When class=ANY or class=NONE, toWire() can also be performed for
+ // an empty RRset.
+ renderer.clear();
+ rrset_any_a_empty.toWire(renderer);
+ wiredata.clear();
+ UnitTestUtil::readWireData("rrset_toWire3", wiredata);
+ matchWireData(&wiredata[0], wiredata.size(),
+ renderer.getData(), renderer.getLength());
+
+ renderer.clear();
+ rrset_none_a_empty.toWire(renderer);
+ wiredata.clear();
+ UnitTestUtil::readWireData("rrset_toWire4", wiredata);
+ matchWireData(&wiredata[0], wiredata.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST_F(RRsetTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << rrset_a;
+ EXPECT_EQ(rrset_a.toText(), oss.str());
+}
+
+class RRsetRRSIGTest : public ::testing::Test {
+protected:
+ RRsetRRSIGTest() : test_name("test.example.com")
+ {
+ rrset_a = RRsetPtr(new RRset(test_name, RRClass::IN(),
+ RRType::A(), RRTTL(3600)));
+ rrset_a->addRdata(in::A("192.0.2.1"));
+ rrset_a->addRdata(in::A("192.0.2.2"));
+
+ rrset_aaaa = RRsetPtr(new RRset(test_name, RRClass::IN(),
+ RRType::AAAA(), RRTTL(3600)));
+ rrset_aaaa->addRdata(in::AAAA("2001:db8::1234"));
+
+ rrset_rrsig = RRsetPtr(new RRset(test_name, RRClass::IN(),
+ RRType::RRSIG(), RRTTL(3600)));
+ rrset_rrsig->addRdata(generic::RRSIG("AAAA 5 3 7200 20100322084538 "
+ "20100220084538 1 example.com. "
+ "FAKEFAKEFAKEFAKE"));
+ rrset_aaaa->addRRsig(rrset_rrsig);
+ }
+
+ const Name test_name;
+ RRsetPtr rrset_a; // A RRset with two RDATAs
+ RRsetPtr rrset_aaaa; // AAAA RRset with one RDATA with RRSIG
+ RRsetPtr rrset_rrsig; // RRSIG for the AAAA RRset
+};
+
+TEST_F(RRsetRRSIGTest, getRRsig) {
+ RRsetPtr sp = rrset_a->getRRsig();
+ EXPECT_EQ(static_cast<void*>(NULL), sp.get());
+
+ sp = rrset_aaaa->getRRsig();
+ EXPECT_NE(static_cast<void*>(NULL), sp.get());
+}
+
+TEST_F(RRsetRRSIGTest, addRRsig) {
+ RRsetPtr sp = rrset_a->getRRsig();
+ EXPECT_EQ(static_cast<void*>(NULL), sp.get());
+
+ rrset_rrsig = RRsetPtr(new RRset(test_name, RRClass::IN(),
+ RRType::RRSIG(), RRTTL(3600)));
+ // one signature algorithm (5 = RSA/SHA-1)
+ rrset_rrsig->addRdata(generic::RRSIG("A 5 3 3600 "
+ "20000101000000 20000201000000 "
+ "12345 example.com. FAKEFAKEFAKE"));
+ // another signature algorithm (3 = DSA/SHA-1)
+ rrset_rrsig->addRdata(generic::RRSIG("A 3 3 3600 "
+ "20000101000000 20000201000000 "
+ "12345 example.com. FAKEFAKEFAKE"));
+ rrset_a->addRRsig(rrset_rrsig);
+
+ sp = rrset_a->getRRsig();
+ EXPECT_NE(static_cast<void*>(NULL), sp.get());
+ EXPECT_EQ(2, sp->getRdataCount());
+
+ // add to existing RRSIG
+ rrset_rrsig = RRsetPtr(new RRset(test_name, RRClass::IN(),
+ RRType::RRSIG(), RRTTL(3600)));
+ // another signature algorithm (4 = ECC)
+ rrset_rrsig->addRdata(generic::RRSIG("A 4 3 3600 "
+ "20000101000000 20000201000000 "
+ "12345 example.com. FAKEFAKEFAKE"));
+ rrset_a->addRRsig(rrset_rrsig);
+ EXPECT_EQ(3, sp->getRdataCount());
+}
+
+TEST_F(RRsetRRSIGTest, getRRsigDataCount) {
+ EXPECT_EQ(1, rrset_aaaa->getRRsigDataCount());
+ EXPECT_EQ(0, rrset_a->getRRsigDataCount());
+
+ rrset_rrsig = RRsetPtr(new RRset(test_name, RRClass::IN(),
+ RRType::RRSIG(), RRTTL(3600)));
+ // one signature algorithm (5 = RSA/SHA-1)
+ rrset_rrsig->addRdata(generic::RRSIG("A 5 3 3600 "
+ "20000101000000 20000201000000 "
+ "12345 example.com. FAKEFAKEFAKE"));
+ // another signature algorithm (3 = DSA/SHA-1)
+ rrset_rrsig->addRdata(generic::RRSIG("A 3 3 3600 "
+ "20000101000000 20000201000000 "
+ "12345 example.com. FAKEFAKEFAKE"));
+ rrset_a->addRRsig(rrset_rrsig);
+ EXPECT_EQ(2, rrset_a->getRRsigDataCount());
+
+ rrset_a->removeRRsig();
+ EXPECT_EQ(0, rrset_a->getRRsigDataCount());
+}
+
+TEST_F(RRsetRRSIGTest, toText) {
+ // toText() should also return the associated RRSIG.
+ EXPECT_EQ("test.example.com. 3600 IN AAAA 2001:db8::1234\n"
+ "test.example.com. 3600 IN RRSIG AAAA 5 3 7200 "
+ "20100322084538 20100220084538 1 example.com. FAKEFAKEFAKEFAKE\n",
+ rrset_aaaa->toText());
+}
+
+TEST_F(RRsetRRSIGTest, getLength) {
+ // A RR
+ // test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets
+ // TYPE field = 2 octets
+ // CLASS field = 2 octets
+ // TTL field = 4 octets
+ // RDLENGTH field = 2 octets
+ // A RDATA = 4 octets
+ // Total = 18 + 2 + 2 + 4 + 2 + 4 = 32 octets
+
+ // 2 A RRs
+ EXPECT_EQ(32 + 32, rrset_a->getLength());
+
+ // RRSIG
+ // test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets
+ // TYPE field = 2 octets
+ // CLASS field = 2 octets
+ // TTL field = 4 octets
+ // RDLENGTH field = 2 octets
+ // RRSIG RDATA = 40 octets
+ // Total = 18 + 2 + 2 + 4 + 2 + 40 = 68 octets
+ RRsetPtr my_rrsig(new RRset(test_name, RRClass::IN(),
+ RRType::RRSIG(), RRTTL(3600)));
+ my_rrsig->addRdata(generic::RRSIG("A 4 3 3600 "
+ "20000101000000 20000201000000 "
+ "12345 example.com. FAKEFAKEFAKE"));
+ EXPECT_EQ(68, my_rrsig->getLength());
+
+ // RRset with attached RRSIG
+ rrset_a->addRRsig(my_rrsig);
+
+ EXPECT_EQ(32 + 32 + 68, rrset_a->getLength());
+}
+}
diff --git a/src/lib/dns/tests/rrttl_unittest.cc b/src/lib/dns/tests/rrttl_unittest.cc
index 8b13789179..3cada14cbc 100644
--- a/src/lib/dns/tests/rrttl_unittest.cc
+++ b/src/lib/dns/tests/rrttl_unittest.cc
@@ -1 +1,279 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <gtest/gtest.h>
+
+#include <util/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rrttl.h>
+
+#include <dns/tests/unittest_util.h>
+#include <util/unittests/wiredata.h>
+
+#include <boost/scoped_ptr.hpp>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+using namespace isc::util;
+using boost::scoped_ptr;
+using isc::util::unittests::matchWireData;
+
+namespace {
+class RRTTLTest : public ::testing::Test {
+protected:
+ RRTTLTest() : obuffer(0) {}
+
+ OutputBuffer obuffer;
+ MessageRenderer renderer;
+
+ static RRTTL rrttlFactoryFromWire(const char* datafile);
+ static const RRTTL ttl_0, ttl_1h, ttl_1d, ttl_32bit, ttl_max;
+ static const RRTTL ttl_small, ttl_large;
+ static const uint8_t wiredata[20];
+};
+
+const RRTTL RRTTLTest::ttl_0(0);
+const RRTTL RRTTLTest::ttl_1h(3600);
+const RRTTL RRTTLTest::ttl_1d(86400);
+const RRTTL RRTTLTest::ttl_32bit(0x12345678);
+const RRTTL RRTTLTest::ttl_max(0xffffffff);
+
+const RRTTL RRTTLTest::ttl_small(1);
+const RRTTL RRTTLTest::ttl_large(0x80000001);
+// This is wire-format data for the above sample RRTTLs rendered in the
+// appearing order.
+const uint8_t RRTTLTest::wiredata[20] = { 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x10,
+ 0x00, 0x01, 0x51, 0x80,
+ 0x12, 0x34, 0x56, 0x78,
+ 0xff, 0xff, 0xff, 0xff };
+
+RRTTL
+RRTTLTest::rrttlFactoryFromWire(const char* datafile) {
+ std::vector<unsigned char> data;
+ UnitTestUtil::readWireData(datafile, data);
+
+ InputBuffer buffer(&data[0], data.size());
+
+ return (RRTTL(buffer));
+}
+
+TEST_F(RRTTLTest, getValue) {
+ EXPECT_EQ(0, ttl_0.getValue());
+ EXPECT_EQ(3600, ttl_1h.getValue());
+ EXPECT_EQ(86400, ttl_1d.getValue());
+ EXPECT_EQ(0x12345678, ttl_32bit.getValue());
+ EXPECT_EQ(0xffffffff, ttl_max.getValue());
+}
+
+TEST_F(RRTTLTest, copyConstruct) {
+ const RRTTL ttl1(3600);
+ const RRTTL ttl2(ttl1);
+ EXPECT_EQ(ttl1.getValue(), ttl2.getValue());
+}
+
+TEST_F(RRTTLTest, fromText) {
+ // Border cases
+ EXPECT_EQ(0, RRTTL("0").getValue());
+ EXPECT_EQ(4294967295U, RRTTL("4294967295").getValue());
+
+ // Invalid cases
+ EXPECT_THROW(RRTTL("0xdeadbeef"), InvalidRRTTL); // must be decimal
+ EXPECT_THROW(RRTTL("-1"), InvalidRRTTL); // must be positive
+ EXPECT_THROW(RRTTL("1.1"), InvalidRRTTL); // must be integer
+ EXPECT_THROW(RRTTL("4294967296"), InvalidRRTTL); // must be 32-bit
+}
+
+TEST_F(RRTTLTest, createFromText) {
+ // It returns an actual RRTTL iff the given text is recognized as a
+ // valid RR TTL.
+ scoped_ptr<RRTTL> good_ttl(RRTTL::createFromText("3600"));
+ EXPECT_TRUE(good_ttl);
+ EXPECT_EQ(RRTTL(3600), *good_ttl);
+
+ scoped_ptr<RRTTL> bad_ttl(RRTTL::createFromText("bad"));
+ EXPECT_FALSE(bad_ttl);
+}
+
+void
+checkUnit(unsigned multiply, char suffix) {
+ SCOPED_TRACE(string("Unit check with suffix ") + suffix);
+ const uint32_t value = 10 * multiply;
+ const string num = "10";
+ // Check both lower and upper version of the suffix
+ EXPECT_EQ(value,
+ RRTTL(num + static_cast<char>(tolower(suffix))).getValue());
+ EXPECT_EQ(value,
+ RRTTL(num + static_cast<char>(toupper(suffix))).getValue());
+}
+
+// Check parsing the unit form (1D, etc)
+TEST_F(RRTTLTest, fromTextUnit) {
+ // Check each of the units separately
+ checkUnit(1, 'S');
+ checkUnit(60, 'M');
+ checkUnit(60 * 60, 'H');
+ checkUnit(24 * 60 * 60, 'D');
+ checkUnit(7 * 24 * 60 * 60, 'W');
+
+ // Some border cases (with units)
+ EXPECT_EQ(4294967295U, RRTTL("4294967295S").getValue());
+ EXPECT_EQ(0, RRTTL("0W0D0H0M0S").getValue());
+ EXPECT_EQ(4294967295U, RRTTL("1193046H1695S").getValue());
+ // Leading zeroes are accepted
+ EXPECT_EQ(4294967295U, RRTTL("0000000000000004294967295S").getValue());
+
+ // Now some compound ones. We allow any order (it would be much work to
+ // check the order anyway).
+ EXPECT_EQ(60 * 60 + 3, RRTTL("1H3S").getValue());
+
+ // Awkward, but allowed case - the same unit used twice.
+ EXPECT_EQ(20 * 3600, RRTTL("12H8H").getValue());
+
+ // Negative number in part of the expression, but the total is positive.
+ // Rejected.
+ EXPECT_THROW(RRTTL("-1S1H"), InvalidRRTTL);
+
+ // Some things out of range in the ttl, but it wraps to number in range
+ // in int64_t. Should still not get fooled and reject it.
+
+ // First part out of range
+ EXPECT_THROW(RRTTL("9223372036854775807S9223372036854775807S2S"),
+ InvalidRRTTL);
+ // Second part out of range, but it immediately wraps (2S+2^64-2S)
+ EXPECT_THROW(RRTTL("2S18446744073709551614S"), InvalidRRTTL);
+ // The whole thing wraps right away (2^64S)
+ EXPECT_THROW(RRTTL("18446744073709551616S"), InvalidRRTTL);
+ // Second part out of range, and will become negative with the unit,
+ EXPECT_THROW(RRTTL("256S307445734561825856M"), InvalidRRTTL);
+
+ // Missing before unit.
+ EXPECT_THROW(RRTTL("W5H"), InvalidRRTTL);
+ EXPECT_THROW(RRTTL("5hW"), InvalidRRTTL);
+
+ // Empty string is not allowed
+ EXPECT_THROW(RRTTL(""), InvalidRRTTL);
+ // Missing the last unit is not allowed
+ EXPECT_THROW(RRTTL("3D5"), InvalidRRTTL);
+
+ // There are some wrong units
+ EXPECT_THROW(RRTTL("13X"), InvalidRRTTL);
+ EXPECT_THROW(RRTTL("3D5F"), InvalidRRTTL);
+}
+
+TEST_F(RRTTLTest, fromWire) {
+ EXPECT_EQ(0x12345678,
+ rrttlFactoryFromWire("rrcode32_fromWire1").getValue());
+ EXPECT_THROW(rrttlFactoryFromWire("rrcode32_fromWire2"),
+ IncompleteRRTTL);
+}
+
+TEST_F(RRTTLTest, toText) {
+ EXPECT_EQ("0", ttl_0.toText());
+ EXPECT_EQ("3600", ttl_1h.toText());
+ EXPECT_EQ("86400", ttl_1d.toText());
+ EXPECT_EQ("305419896", ttl_32bit.toText());
+ EXPECT_EQ("4294967295", ttl_max.toText());
+}
+
+TEST_F(RRTTLTest, toWireBuffer) {
+ ttl_0.toWire(obuffer);
+ ttl_1h.toWire(obuffer);
+ ttl_1d.toWire(obuffer);
+ ttl_32bit.toWire(obuffer);
+ ttl_max.toWire(obuffer);
+
+ matchWireData(wiredata, sizeof(wiredata),
+ obuffer.getData(), obuffer.getLength());
+}
+
+TEST_F(RRTTLTest, toWireRenderer) {
+ ttl_0.toWire(renderer);
+ ttl_1h.toWire(renderer);
+ ttl_1d.toWire(renderer);
+ ttl_32bit.toWire(renderer);
+ ttl_max.toWire(renderer);
+
+ matchWireData(wiredata, sizeof(wiredata),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(RRTTLTest, equal) {
+ EXPECT_TRUE(RRTTL("3600") == ttl_1h);
+ EXPECT_TRUE(RRTTL("86400").equals(ttl_1d));
+
+ EXPECT_TRUE(ttl_1d != ttl_1h);
+ EXPECT_TRUE(ttl_1d.nequals(ttl_max));
+}
+
+//
+// The following set of tests confirm the result of <=, <, >=, >
+// The test logic is simple, and all tests are just straightforward variations
+// of the first one.
+//
+TEST_F(RRTTLTest, leq) {
+ // small <= large is true
+ EXPECT_TRUE(ttl_small.leq(ttl_large));
+ EXPECT_TRUE(ttl_small <= ttl_large);
+
+ // small <= small is true
+ EXPECT_TRUE(ttl_small.leq(ttl_small));
+ EXPECT_LE(ttl_small, ttl_small);
+
+ // large <= small is false
+ EXPECT_FALSE(ttl_large.leq(ttl_small));
+ EXPECT_FALSE(ttl_large <= ttl_small);
+}
+
+TEST_F(RRTTLTest, geq) {
+ EXPECT_TRUE(ttl_large.geq(ttl_small));
+ EXPECT_TRUE(ttl_large >= ttl_small);
+
+ EXPECT_TRUE(ttl_large.geq(ttl_large));
+ EXPECT_GE(ttl_large, ttl_large);
+
+ EXPECT_FALSE(ttl_small.geq(ttl_large));
+ EXPECT_FALSE(ttl_small >= ttl_large);
+}
+
+TEST_F(RRTTLTest, lthan) {
+ EXPECT_TRUE(ttl_small.lthan(ttl_large));
+ EXPECT_TRUE(ttl_small < ttl_large);
+
+ EXPECT_FALSE(ttl_small.lthan(ttl_small));
+ // cppcheck-suppress duplicateExpression
+ EXPECT_FALSE(ttl_small < ttl_small);
+
+ EXPECT_FALSE(ttl_large.lthan(ttl_small));
+ EXPECT_FALSE(ttl_large < ttl_small);
+}
+
+TEST_F(RRTTLTest, gthan) {
+ EXPECT_TRUE(ttl_large.gthan(ttl_small));
+ EXPECT_TRUE(ttl_large > ttl_small);
+
+ EXPECT_FALSE(ttl_large.gthan(ttl_large));
+ // cppcheck-suppress duplicateExpression
+ EXPECT_FALSE(ttl_large > ttl_large);
+
+ EXPECT_FALSE(ttl_small.gthan(ttl_large));
+ EXPECT_FALSE(ttl_small > ttl_large);
+}
+
+TEST_F(RRTTLTest, maxTTL) {
+ EXPECT_EQ((1u << 31) - 1, RRTTL::MAX_TTL().getValue());
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST_F(RRTTLTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << ttl_1h;
+ EXPECT_EQ(ttl_1h.toText(), oss.str());
+}
+}
diff --git a/src/lib/dns/tests/rrtype_unittest.cc b/src/lib/dns/tests/rrtype_unittest.cc
index 8b13789179..97975409b8 100644
--- a/src/lib/dns/tests/rrtype_unittest.cc
+++ b/src/lib/dns/tests/rrtype_unittest.cc
@@ -1 +1,170 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <gtest/gtest.h>
+
+#include <util/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rrtype.h>
+
+#include <dns/tests/unittest_util.h>
+#include <util/unittests/wiredata.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+using namespace isc::util;
+using isc::util::unittests::matchWireData;
+
+namespace {
+class RRTypeTest : public ::testing::Test {
+protected:
+ RRTypeTest() : obuffer(0) {}
+
+ OutputBuffer obuffer;
+ MessageRenderer renderer;
+
+ static RRType rrtypeFactoryFromWire(const char* datafile);
+ static const RRType rrtype_1, rrtype_0x80, rrtype_0x800, rrtype_0x8000,
+ rrtype_max;
+ static const uint8_t wiredata[];
+};
+
+const RRType RRTypeTest::rrtype_1(1);
+const RRType RRTypeTest::rrtype_0x80(0x80);
+const RRType RRTypeTest::rrtype_0x800(0x800);
+const RRType RRTypeTest::rrtype_0x8000(0x8000);
+const RRType RRTypeTest::rrtype_max(0xffff);
+// This is wire-format data for the above sample RRTypes rendered in the
+// appearing order.
+const uint8_t RRTypeTest::wiredata[] = { 0x00, 0x01, 0x00, 0x80, 0x08,
+ 0x00, 0x80, 0x00, 0xff, 0xff };
+
+RRType
+RRTypeTest::rrtypeFactoryFromWire(const char* datafile) {
+ std::vector<unsigned char> data;
+ UnitTestUtil::readWireData(datafile, data);
+
+ InputBuffer buffer(&data[0], data.size());
+
+ return (RRType(buffer));
+}
+
+TEST_F(RRTypeTest, fromText) {
+ EXPECT_EQ("A", RRType("A").toText());
+ EXPECT_EQ("NS", RRType("NS").toText());
+
+ EXPECT_EQ("TYPE65535", RRType("TYPE65535").toText());
+
+ // something unusual, but existing implementations accept this form,
+ // so do we.
+ EXPECT_EQ(53, RRType("TYPE00053").getCode());
+ // again, unusual, and the majority of other implementations reject it.
+ // In any case, there should be no reasonable reason to accept such a
+ // ridiculously long input.
+ EXPECT_THROW(RRType("TYPE000053"), InvalidRRType);
+
+ // bogus TYPEnnn representations: should trigger an exception
+ EXPECT_THROW(RRType("TYPE"), InvalidRRType);
+ EXPECT_THROW(RRType("TYPE-1"), InvalidRRType);
+ EXPECT_THROW(RRType("TYPExxx"), InvalidRRType);
+ EXPECT_THROW(RRType("TYPE65536"), InvalidRRType);
+ EXPECT_THROW(RRType("TYPE6500x"), InvalidRRType);
+ EXPECT_THROW(RRType("TYPE65000 "), InvalidRRType);
+}
+
+TEST_F(RRTypeTest, fromWire) {
+ EXPECT_EQ(0x1234,
+ rrtypeFactoryFromWire("rrcode16_fromWire1").getCode());
+ EXPECT_THROW(rrtypeFactoryFromWire("rrcode16_fromWire2"), IncompleteRRType);
+}
+
+// from string, lower case
+TEST_F(RRTypeTest, caseConstruct) {
+ EXPECT_EQ("A", RRType("a").toText());
+ EXPECT_EQ("NS", RRType("ns").toText());
+ EXPECT_EQ("TYPE65535", RRType("type65535").toText());
+}
+
+TEST_F(RRTypeTest, toText) {
+ EXPECT_EQ("A", RRType(1).toText());
+ EXPECT_EQ("TYPE65000", RRType(65000).toText());
+}
+
+TEST_F(RRTypeTest, toWireBuffer) {
+ rrtype_1.toWire(obuffer);
+ rrtype_0x80.toWire(obuffer);
+ rrtype_0x800.toWire(obuffer);
+ rrtype_0x8000.toWire(obuffer);
+ rrtype_max.toWire(obuffer);
+
+ matchWireData(wiredata, sizeof(wiredata),
+ obuffer.getData(), obuffer.getLength());
+}
+
+TEST_F(RRTypeTest, toWireRenderer) {
+ rrtype_1.toWire(renderer);
+ rrtype_0x80.toWire(renderer);
+ rrtype_0x800.toWire(renderer);
+ rrtype_0x8000.toWire(renderer);
+ rrtype_max.toWire(renderer);
+
+ matchWireData(wiredata, sizeof(wiredata),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(RRTypeTest, wellKnownTypes) {
+ EXPECT_EQ(1, RRType::A().getCode());
+ EXPECT_EQ("A", RRType::A().toText());
+}
+
+TEST_F(RRTypeTest, compare) {
+ EXPECT_TRUE(RRType(1) == RRType("A"));
+ EXPECT_TRUE(RRType(1).equals(RRType("A")));
+ EXPECT_TRUE(RRType(0) != RRType("A"));
+ EXPECT_TRUE(RRType(0).nequals(RRType("A")));
+
+ EXPECT_TRUE(RRType("A") < RRType("NS"));
+ EXPECT_TRUE(RRType(100) < RRType(65535));
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST_F(RRTypeTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << RRType::A();
+ EXPECT_EQ(RRType::A().toText(), oss.str());
+}
+
+// Below, we'll check definitions for all well-known RR types; whether they
+// are defined and have the correct parameter values. Test data are generated
+// from the list available at:
+// http://www.iana.org/assignments/dns-parameters/dns-parameters.xml
+struct TypeParam {
+ const char* const txt; // "A", "AAAA", "NS", etc
+ const uint16_t code; // 1, 28, 2, etc
+ const RRType& (*obj)(); // RRType::A(), etc
+} known_types[] = {
+ {"A", 1, RRType::A}, {"NS", 2, RRType::NS},
+ {"SOA", 6, RRType::SOA}, {"PTR", 12, RRType::PTR},
+ {"TXT", 16, RRType::TXT}, {"AAAA", 28, RRType::AAAA},
+ {"OPT", 41, RRType::OPT}, {"RRSIG", 46, RRType::RRSIG},
+ {"DHCID", 49, RRType::DHCID}, {"TKEY", 249, RRType::TKEY},
+ {"TSIG", 250, RRType::TSIG}, {"ANY", 255, RRType::ANY},
+ {NULL, 0, NULL}
+};
+
+TEST(RRTypeConstTest, wellKnowns) {
+ for (int i = 0; known_types[i].txt; ++i) {
+ SCOPED_TRACE("Checking well known RRType: " +
+ string(known_types[i].txt));
+ EXPECT_EQ(known_types[i].code, RRType(known_types[i].txt).getCode());
+ EXPECT_EQ(known_types[i].code,
+ (*known_types[i].obj)().getCode());
+ }
+}
+}
diff --git a/src/lib/dns/tests/serial_unittest.cc b/src/lib/dns/tests/serial_unittest.cc
index 8b13789179..305b0b0d79 100644
--- a/src/lib/dns/tests/serial_unittest.cc
+++ b/src/lib/dns/tests/serial_unittest.cc
@@ -1 +1,173 @@
+// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/serial.h>
+
+using namespace isc::dns;
+
+class SerialTest : public ::testing::Test {
+public:
+ SerialTest() : one(1), one_2(1), two(2),
+ date_zero(1980120100), date_one(1980120101),
+ min(0), max(4294967295u),
+ number_low(12345),
+ number_medium(2000000000),
+ number_high(4000000000u)
+ {}
+ Serial one, one_2, two, date_zero, date_one, min, max, number_low, number_medium, number_high;
+};
+
+//
+// Basic tests
+//
+
+TEST_F(SerialTest, get_value) {
+ EXPECT_EQ(1, one.getValue());
+ EXPECT_NE(2, one.getValue());
+ EXPECT_EQ(2, two.getValue());
+ EXPECT_EQ(1980120100, date_zero.getValue());
+ EXPECT_EQ(1980120101, date_one.getValue());
+ EXPECT_EQ(0, min.getValue());
+ EXPECT_EQ(4294967295u, max.getValue());
+ EXPECT_EQ(12345, number_low.getValue());
+ EXPECT_EQ(2000000000, number_medium.getValue());
+ EXPECT_EQ(4000000000u, number_high.getValue());
+}
+
+TEST_F(SerialTest, equals) {
+ EXPECT_EQ(one, one);
+ EXPECT_EQ(one, one_2);
+ EXPECT_NE(one, two);
+ EXPECT_NE(two, one);
+ EXPECT_EQ(Serial(12345), number_low);
+ EXPECT_NE(Serial(12346), number_low);
+}
+
+TEST_F(SerialTest, comparison) {
+ // These should be true/false even without serial arithmetic
+ EXPECT_LE(one, one);
+ EXPECT_LE(one, one_2);
+ EXPECT_LT(one, two);
+ EXPECT_LE(one, two);
+ EXPECT_GE(two, two);
+ EXPECT_GT(two, one);
+ EXPECT_GE(two, one);
+ EXPECT_LT(one, number_low);
+ EXPECT_LT(number_low, number_medium);
+ EXPECT_LT(number_medium, number_high);
+
+ // now let's try some that 'wrap', as it were
+ EXPECT_GT(min, max);
+ EXPECT_LT(max, min);
+ EXPECT_LT(number_high, number_low);
+}
+
+//
+// RFC 1982 Section 3.1
+//
+TEST_F(SerialTest, addition) {
+ EXPECT_EQ(two, one + one);
+ EXPECT_EQ(two, one + one_2);
+ EXPECT_EQ(max, max + min);
+ EXPECT_EQ(min, max + one);
+ EXPECT_EQ(one, max + two);
+ EXPECT_EQ(one, max + one + one);
+
+ EXPECT_EQ(one + 100, max + 102);
+ EXPECT_EQ(min + 2147483645, max + 2147483646);
+ EXPECT_EQ(min + 2147483646, max + MAX_SERIAL_INCREMENT);
+}
+
+//
+// RFC 1982 Section 3.2 has been checked by the basic tests above
+//
+
+//
+// RFC 1982 Section 4.1
+//
+
+// Helper function for addition_always_larger test, add some numbers
+// and check that the result is always larger than the original
+void do_addition_larger_test(const Serial& number) {
+ EXPECT_GE(number + 0, number);
+ EXPECT_EQ(number + 0, number);
+ EXPECT_GT(number + 1, number);
+ EXPECT_GT(number + 2, number);
+ EXPECT_GT(number + 100, number);
+ EXPECT_GT(number + 1111111, number);
+ EXPECT_GT(number + 2147483646, number);
+ EXPECT_GT(number + MAX_SERIAL_INCREMENT, number);
+ // Try MAX_SERIAL_INCREMENT as a hardcoded number as well
+ EXPECT_GT(number + 2147483647, number);
+}
+
+TEST_F(SerialTest, addition_always_larger) {
+ do_addition_larger_test(one);
+ do_addition_larger_test(two);
+ do_addition_larger_test(date_zero);
+ do_addition_larger_test(date_one);
+ do_addition_larger_test(min);
+ do_addition_larger_test(max);
+ do_addition_larger_test(number_low);
+ do_addition_larger_test(number_medium);
+ do_addition_larger_test(number_high);
+}
+
+//
+// RFC 1982 Section 4.2
+//
+
+// Helper function to do the second addition
+void
+do_two_additions_test_second(const Serial &original,
+ const Serial &number)
+{
+ EXPECT_NE(original, number);
+ EXPECT_NE(original, number + 0);
+ EXPECT_NE(original, number + 1);
+ EXPECT_NE(original, number + 2);
+ EXPECT_NE(original, number + 100);
+ EXPECT_NE(original, number + 1111111);
+ EXPECT_NE(original, number + 2147483646);
+ EXPECT_NE(original, number + MAX_SERIAL_INCREMENT);
+ EXPECT_NE(original, number + 2147483647);
+}
+
+void do_two_additions_test_first(const Serial &number) {
+ do_two_additions_test_second(number, number + 1);
+ do_two_additions_test_second(number, number + 2);
+ do_two_additions_test_second(number, number + 100);
+ do_two_additions_test_second(number, number + 1111111);
+ do_two_additions_test_second(number, number + 2147483646);
+ do_two_additions_test_second(number, number + MAX_SERIAL_INCREMENT);
+ do_two_additions_test_second(number, number + 2147483647);
+}
+
+TEST_F(SerialTest, two_additions_never_equal) {
+ do_two_additions_test_first(one);
+ do_two_additions_test_first(two);
+ do_two_additions_test_first(date_zero);
+ do_two_additions_test_first(date_one);
+ do_two_additions_test_first(min);
+ do_two_additions_test_first(max);
+ do_two_additions_test_first(number_low);
+ do_two_additions_test_first(number_medium);
+ do_two_additions_test_first(number_high);
+}
+
+//
+// RFC 1982 Section 4.3 and 4.4 have nothing to test
+//
+
+//
+// Tests from RFC 1982 examples
+//
+TEST(SerialTextRFCExamples, rfc_example_tests) {
+}
diff --git a/src/lib/dns/tests/testdata/Makefile.am b/src/lib/dns/tests/testdata/Makefile.am
index e5c8081c07..66dc8b5900 100644
--- a/src/lib/dns/tests/testdata/Makefile.am
+++ b/src/lib/dns/tests/testdata/Makefile.am
@@ -30,60 +30,14 @@ EXTRA_DIST += name_toWire1 name_toWire2 name_toWire3 name_toWire4
EXTRA_DIST += name_toWire5.spec name_toWire6.spec
EXTRA_DIST += name_toWire7 name_toWire8 name_toWire9
EXTRA_DIST += question_fromWire question_toWire1 question_toWire2
-EXTRA_DIST += rdatafields1.spec rdatafields2.spec rdatafields3.spec
-EXTRA_DIST += rdatafields4.spec rdatafields5.spec rdatafields6.spec
-EXTRA_DIST += rdata_cname_fromWire rdata_dname_fromWire
-EXTRA_DIST += rdata_dnskey_fromWire.spec rdata_dnskey_empty_keydata_fromWire.spec
EXTRA_DIST += rdata_dhcid_fromWire rdata_dhcid_toWire
-EXTRA_DIST += rdata_ds_fromWire rdata_in_a_fromWire rdata_in_aaaa_fromWire
-EXTRA_DIST += rdata_mx_fromWire rdata_mx_toWire1 rdata_mx_toWire2
-EXTRA_DIST += rdata_ns_fromWire
-EXTRA_DIST += rdata_nsec_fromWire1 rdata_nsec_fromWire2 rdata_nsec_fromWire3
-EXTRA_DIST += rdata_nsec_fromWire4.spec rdata_nsec_fromWire5.spec
-EXTRA_DIST += rdata_nsec_fromWire6.spec rdata_nsec_fromWire7.spec
-EXTRA_DIST += rdata_nsec_fromWire8.spec rdata_nsec_fromWire9.spec
-EXTRA_DIST += rdata_nsec_fromWire10.spec
-EXTRA_DIST += rdata_nsec_fromWire16.spec
-EXTRA_DIST += rdata_nsec3param_fromWire1
-EXTRA_DIST += rdata_nsec3param_fromWire2.spec
-EXTRA_DIST += rdata_nsec3param_fromWire11.spec
-EXTRA_DIST += rdata_nsec3param_fromWire13.spec
-EXTRA_DIST += rdata_nsec3_fromWire1 rdata_nsec3_fromWire1.spec
-EXTRA_DIST += rdata_nsec3_fromWire2.spec rdata_nsec3_fromWire3
-EXTRA_DIST += rdata_nsec3_fromWire4.spec rdata_nsec3_fromWire5.spec
-EXTRA_DIST += rdata_nsec3_fromWire6.spec rdata_nsec3_fromWire7.spec
-EXTRA_DIST += rdata_nsec3_fromWire8.spec rdata_nsec3_fromWire9.spec
-EXTRA_DIST += rdata_nsec3_fromWire10.spec rdata_nsec3_fromWire11.spec
-EXTRA_DIST += rdata_nsec3_fromWire12.spec rdata_nsec3_fromWire13.spec
-EXTRA_DIST += rdata_nsec3_fromWire14.spec rdata_nsec3_fromWire15.spec
-EXTRA_DIST += rdata_nsec3_fromWire16.spec rdata_nsec3_fromWire17.spec
+EXTRA_DIST += rdata_ptr_fromWire
+EXTRA_DIST += rdata_in_a_fromWire rdata_in_aaaa_fromWire
EXTRA_DIST += rdata_opt_fromWire1 rdata_opt_fromWire2
EXTRA_DIST += rdata_opt_fromWire3 rdata_opt_fromWire4
EXTRA_DIST += rdata_rrsig_fromWire1
EXTRA_DIST += rdata_rrsig_fromWire2.spec
-EXTRA_DIST += rdata_rp_fromWire1.spec rdata_rp_fromWire2.spec
-EXTRA_DIST += rdata_rp_fromWire3.spec rdata_rp_fromWire4.spec
-EXTRA_DIST += rdata_rp_fromWire5.spec rdata_rp_fromWire6.spec
-EXTRA_DIST += rdata_rp_toWire1.spec rdata_rp_toWire2.spec
-EXTRA_DIST += rdata_sshfp_fromWire rdata_sshfp_fromWire2
-EXTRA_DIST += rdata_sshfp_fromWire1.spec rdata_sshfp_fromWire2.spec
-EXTRA_DIST += rdata_sshfp_fromWire3.spec rdata_sshfp_fromWire4.spec
-EXTRA_DIST += rdata_sshfp_fromWire5.spec rdata_sshfp_fromWire6.spec
-EXTRA_DIST += rdata_sshfp_fromWire7.spec rdata_sshfp_fromWire8.spec
-EXTRA_DIST += rdata_sshfp_fromWire9 rdata_sshfp_fromWire10
-EXTRA_DIST += rdata_sshfp_fromWire11 rdata_sshfp_fromWire12
-EXTRA_DIST += rdata_afsdb_fromWire1.spec rdata_afsdb_fromWire2.spec
-EXTRA_DIST += rdata_afsdb_fromWire3.spec rdata_afsdb_fromWire4.spec
-EXTRA_DIST += rdata_afsdb_fromWire5.spec
-EXTRA_DIST += rdata_afsdb_toWire1.spec rdata_afsdb_toWire2.spec
EXTRA_DIST += rdata_soa_fromWire rdata_soa_toWireUncompressed.spec
-EXTRA_DIST += rdata_srv_fromWire
-EXTRA_DIST += rdata_minfo_fromWire1.spec rdata_minfo_fromWire2.spec
-EXTRA_DIST += rdata_minfo_fromWire3.spec rdata_minfo_fromWire4.spec
-EXTRA_DIST += rdata_minfo_fromWire5.spec rdata_minfo_fromWire6.spec
-EXTRA_DIST += rdata_minfo_toWire1.spec rdata_minfo_toWire2.spec
-EXTRA_DIST += rdata_minfo_toWireUncompressed1.spec
-EXTRA_DIST += rdata_minfo_toWireUncompressed2.spec
EXTRA_DIST += rdata_txt_fromWire1 rdata_txt_fromWire2.spec
EXTRA_DIST += rdata_txt_fromWire3.spec rdata_txt_fromWire4.spec
EXTRA_DIST += rdata_txt_fromWire5.spec rdata_unknown_fromWire
@@ -99,12 +53,6 @@ EXTRA_DIST += rdata_tkey_fromWire9.spec
EXTRA_DIST += rdata_tkey_toWire1.spec rdata_tkey_toWire2.spec
EXTRA_DIST += rdata_tkey_toWire3.spec rdata_tkey_toWire4.spec
EXTRA_DIST += rdata_tkey_toWire5.spec
-EXTRA_DIST += rdata_tlsa_fromWire rdata_tlsa_fromWire2
-EXTRA_DIST += rdata_tlsa_fromWire3.spec rdata_tlsa_fromWire4.spec
-EXTRA_DIST += rdata_tlsa_fromWire5.spec rdata_tlsa_fromWire6.spec
-EXTRA_DIST += rdata_tlsa_fromWire7.spec rdata_tlsa_fromWire8.spec
-EXTRA_DIST += rdata_tlsa_fromWire9 rdata_tlsa_fromWire10
-EXTRA_DIST += rdata_tlsa_fromWire11 rdata_tlsa_fromWire12
EXTRA_DIST += rdata_tsig_fromWire1.spec rdata_tsig_fromWire2.spec
EXTRA_DIST += rdata_tsig_fromWire3.spec rdata_tsig_fromWire4.spec
EXTRA_DIST += rdata_tsig_fromWire5.spec rdata_tsig_fromWire6.spec
@@ -113,9 +61,6 @@ EXTRA_DIST += rdata_tsig_fromWire9.spec
EXTRA_DIST += rdata_tsig_toWire1.spec rdata_tsig_toWire2.spec
EXTRA_DIST += rdata_tsig_toWire3.spec rdata_tsig_toWire4.spec
EXTRA_DIST += rdata_tsig_toWire5.spec
-EXTRA_DIST += rdata_caa_fromWire1.spec rdata_caa_fromWire2.spec
-EXTRA_DIST += rdata_caa_fromWire3.spec rdata_caa_fromWire4.spec
-EXTRA_DIST += rdata_caa_fromWire5 rdata_caa_fromWire6
EXTRA_DIST += tsigrecord_toWire1.spec tsigrecord_toWire2.spec
EXTRA_DIST += tsig_verify1.spec tsig_verify2.spec tsig_verify3.spec
EXTRA_DIST += tsig_verify4.spec tsig_verify5.spec tsig_verify6.spec
@@ -142,51 +87,11 @@ EXTRA_DIST += message_toText1.txt message_toText1.wire
EXTRA_DIST += message_toText2.txt message_toText2.wire
EXTRA_DIST += message_toText3.txt message_toText3.wire
EXTRA_DIST += name_toWire5.wire name_toWire6.wire
-EXTRA_DIST += rdatafields1.wire rdatafields2.wire rdatafields3.wire
-EXTRA_DIST += rdatafields4.wire rdatafields5.wire rdatafields6.wire
-EXTRA_DIST += rdata_dnskey_fromWire.wire rdata_dnskey_empty_keydata_fromWire.wire
-EXTRA_DIST += rdata_nsec_fromWire4.wire rdata_nsec_fromWire5.wire
-EXTRA_DIST += rdata_nsec_fromWire6.wire rdata_nsec_fromWire7.wire
-EXTRA_DIST += rdata_nsec_fromWire8.wire rdata_nsec_fromWire9.wire
-EXTRA_DIST += rdata_nsec_fromWire10.wire
-EXTRA_DIST += rdata_nsec_fromWire16.wire
-EXTRA_DIST += rdata_nsec3param_fromWire2.wire
-EXTRA_DIST += rdata_nsec3param_fromWire11.wire
-EXTRA_DIST += rdata_nsec3param_fromWire13.wire
-EXTRA_DIST += rdata_nsec3_fromWire2.wire rdata_nsec3_fromWire3
-EXTRA_DIST += rdata_nsec3_fromWire4.wire rdata_nsec3_fromWire5.wire
-EXTRA_DIST += rdata_nsec3_fromWire6.wire rdata_nsec3_fromWire7.wire
-EXTRA_DIST += rdata_nsec3_fromWire8.wire rdata_nsec3_fromWire9.wire
-EXTRA_DIST += rdata_nsec3_fromWire10.wire rdata_nsec3_fromWire11.wire
-EXTRA_DIST += rdata_nsec3_fromWire12.wire rdata_nsec3_fromWire13.wire
-EXTRA_DIST += rdata_nsec3_fromWire14.wire rdata_nsec3_fromWire15.wire
-EXTRA_DIST += rdata_nsec3_fromWire16.wire rdata_nsec3_fromWire17.wire
EXTRA_DIST += rdata_rrsig_fromWire2.wire
-EXTRA_DIST += rdata_rp_fromWire1.wire rdata_rp_fromWire2.wire
-EXTRA_DIST += rdata_rp_fromWire3.wire rdata_rp_fromWire4.wire
-EXTRA_DIST += rdata_rp_fromWire5.wire rdata_rp_fromWire6.wire
-EXTRA_DIST += rdata_rp_toWire1.wire rdata_rp_toWire2.wire
-EXTRA_DIST += rdata_sshfp_fromWire1.wire rdata_sshfp_fromWire2.wire
-EXTRA_DIST += rdata_sshfp_fromWire3.wire rdata_sshfp_fromWire4.wire
-EXTRA_DIST += rdata_sshfp_fromWire5.wire rdata_sshfp_fromWire6.wire
-EXTRA_DIST += rdata_sshfp_fromWire7.wire rdata_sshfp_fromWire8.wire
-EXTRA_DIST += rdata_afsdb_fromWire1.wire rdata_afsdb_fromWire2.wire
-EXTRA_DIST += rdata_afsdb_fromWire3.wire rdata_afsdb_fromWire4.wire
-EXTRA_DIST += rdata_afsdb_fromWire5.wire
-EXTRA_DIST += rdata_afsdb_toWire1.wire rdata_afsdb_toWire2.wire
EXTRA_DIST += rdata_soa_fromWire rdata_soa_toWireUncompressed.wire
-EXTRA_DIST += rdata_minfo_fromWire1.wire rdata_minfo_fromWire2.wire
-EXTRA_DIST += rdata_minfo_fromWire3.wire rdata_minfo_fromWire4.wire
-EXTRA_DIST += rdata_minfo_fromWire5.wire rdata_minfo_fromWire6.wire
-EXTRA_DIST += rdata_minfo_toWire1.wire rdata_minfo_toWire2.wire
-EXTRA_DIST += rdata_minfo_toWireUncompressed1.wire
-EXTRA_DIST += rdata_minfo_toWireUncompressed2.wire
EXTRA_DIST += rdata_txt_fromWire1 rdata_txt_fromWire2.wire
EXTRA_DIST += rdata_txt_fromWire3.wire rdata_txt_fromWire4.wire
EXTRA_DIST += rdata_txt_fromWire5.wire rdata_unknown_fromWire
-EXTRA_DIST += rdata_tlsa_fromWire3.wire rdata_tlsa_fromWire4.wire
-EXTRA_DIST += rdata_tlsa_fromWire5.wire rdata_tlsa_fromWire6.wire
-EXTRA_DIST += rdata_tlsa_fromWire7.wire rdata_tlsa_fromWire8.wire
EXTRA_DIST += rdata_tsig_fromWire1.wire rdata_tsig_fromWire2.wire
EXTRA_DIST += rdata_tsig_fromWire3.wire rdata_tsig_fromWire4.wire
EXTRA_DIST += rdata_tsig_fromWire5.wire rdata_tsig_fromWire6.wire
@@ -195,8 +100,6 @@ EXTRA_DIST += rdata_tsig_fromWire9.wire
EXTRA_DIST += rdata_tsig_toWire1.wire rdata_tsig_toWire2.wire
EXTRA_DIST += rdata_tsig_toWire3.wire rdata_tsig_toWire4.wire
EXTRA_DIST += rdata_tsig_toWire5.wire
-EXTRA_DIST += rdata_caa_fromWire1.wire rdata_caa_fromWire2.wire
-EXTRA_DIST += rdata_caa_fromWire3.wire rdata_caa_fromWire4.wire
EXTRA_DIST += rdata_tkey_fromWire1.wire rdata_tkey_fromWire2.wire
EXTRA_DIST += rdata_tkey_fromWire3.wire rdata_tkey_fromWire4.wire
EXTRA_DIST += rdata_tkey_fromWire5.wire rdata_tkey_fromWire6.wire
diff --git a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire1.spec b/src/lib/dns/tests/testdata/rdata_afsdb_fromWire1.spec
deleted file mode 100644
index f831313827..0000000000
--- a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire1.spec
+++ /dev/null
@@ -1,3 +0,0 @@
-[custom]
-sections: afsdb
-[afsdb]
diff --git a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire1.wire b/src/lib/dns/tests/testdata/rdata_afsdb_fromWire1.wire
deleted file mode 100644
index b32776b37b..0000000000
--- a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire1.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_afsdb_fromWire1.spec
-###
-
-# AFSDB RDATA, RDLEN=21
-0015
-# SUBTYPE=1 SERVER=afsdb.example.com
-0001 056166736462076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire2.spec b/src/lib/dns/tests/testdata/rdata_afsdb_fromWire2.spec
deleted file mode 100644
index f33e768589..0000000000
--- a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire2.spec
+++ /dev/null
@@ -1,6 +0,0 @@
-[custom]
-sections: name:afsdb
-[name]
-name: example.com
-[afsdb]
-server: afsdb.ptr=0
diff --git a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire2.wire b/src/lib/dns/tests/testdata/rdata_afsdb_fromWire2.wire
deleted file mode 100644
index fdc53c526f..0000000000
--- a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire2.wire
+++ /dev/null
@@ -1,11 +0,0 @@
-###
-### This data file was auto-generated from rdata_afsdb_fromWire2.spec
-###
-
-# DNS Name: example.com
-076578616d706c6503636f6d00
-
-# AFSDB RDATA, RDLEN=10
-000a
-# SUBTYPE=1 SERVER=afsdb.ptr=0
-0001 056166736462c000
diff --git a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire3.spec b/src/lib/dns/tests/testdata/rdata_afsdb_fromWire3.spec
deleted file mode 100644
index 993032f605..0000000000
--- a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire3.spec
+++ /dev/null
@@ -1,4 +0,0 @@
-[custom]
-sections: afsdb
-[afsdb]
-rdlen: 3
diff --git a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire3.wire b/src/lib/dns/tests/testdata/rdata_afsdb_fromWire3.wire
deleted file mode 100644
index 7ea43429a0..0000000000
--- a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire3.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_afsdb_fromWire3.spec
-###
-
-# AFSDB RDATA, RDLEN=3
-0003
-# SUBTYPE=1 SERVER=afsdb.example.com
-0001 056166736462076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire4.spec b/src/lib/dns/tests/testdata/rdata_afsdb_fromWire4.spec
deleted file mode 100644
index 37abf134c5..0000000000
--- a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire4.spec
+++ /dev/null
@@ -1,4 +0,0 @@
-[custom]
-sections: afsdb
-[afsdb]
-rdlen: 80
diff --git a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire4.wire b/src/lib/dns/tests/testdata/rdata_afsdb_fromWire4.wire
deleted file mode 100644
index 79ff6c222f..0000000000
--- a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire4.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_afsdb_fromWire4.spec
-###
-
-# AFSDB RDATA, RDLEN=80
-0050
-# SUBTYPE=1 SERVER=afsdb.example.com
-0001 056166736462076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire5.spec b/src/lib/dns/tests/testdata/rdata_afsdb_fromWire5.spec
deleted file mode 100644
index 0ea79dd173..0000000000
--- a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire5.spec
+++ /dev/null
@@ -1,4 +0,0 @@
-[custom]
-sections: afsdb
-[afsdb]
-server: "01234567890123456789012345678901234567890123456789012345678901234"
diff --git a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire5.wire b/src/lib/dns/tests/testdata/rdata_afsdb_fromWire5.wire
deleted file mode 100644
index 13eb016d8d..0000000000
--- a/src/lib/dns/tests/testdata/rdata_afsdb_fromWire5.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_afsdb_fromWire5.spec
-###
-
-# AFSDB RDATA, RDLEN=71
-0047
-# SUBTYPE=1 SERVER="01234567890123456789012345678901234567890123456789012345678901234"
-0001 432230313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233342200
diff --git a/src/lib/dns/tests/testdata/rdata_afsdb_toWire1.spec b/src/lib/dns/tests/testdata/rdata_afsdb_toWire1.spec
deleted file mode 100644
index 19464589e1..0000000000
--- a/src/lib/dns/tests/testdata/rdata_afsdb_toWire1.spec
+++ /dev/null
@@ -1,4 +0,0 @@
-[custom]
-sections: afsdb
-[afsdb]
-rdlen: -1
diff --git a/src/lib/dns/tests/testdata/rdata_afsdb_toWire1.wire b/src/lib/dns/tests/testdata/rdata_afsdb_toWire1.wire
deleted file mode 100644
index 7746fa6e1d..0000000000
--- a/src/lib/dns/tests/testdata/rdata_afsdb_toWire1.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_afsdb_toWire1.spec
-###
-
-# AFSDB RDATA
-
-# SUBTYPE=1 SERVER=afsdb.example.com
-0001 056166736462076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdata_afsdb_toWire2.spec b/src/lib/dns/tests/testdata/rdata_afsdb_toWire2.spec
deleted file mode 100644
index c80011a488..0000000000
--- a/src/lib/dns/tests/testdata/rdata_afsdb_toWire2.spec
+++ /dev/null
@@ -1,8 +0,0 @@
-[custom]
-sections: name:afsdb
-[name]
-name: example.com.
-[afsdb]
-subtype: 0
-server: root.example.com
-rdlen: -1
diff --git a/src/lib/dns/tests/testdata/rdata_afsdb_toWire2.wire b/src/lib/dns/tests/testdata/rdata_afsdb_toWire2.wire
deleted file mode 100644
index 7f01512a60..0000000000
--- a/src/lib/dns/tests/testdata/rdata_afsdb_toWire2.wire
+++ /dev/null
@@ -1,11 +0,0 @@
-###
-### This data file was auto-generated from rdata_afsdb_toWire2.spec
-###
-
-# DNS Name: example.com.
-076578616d706c6503636f6d00
-
-# AFSDB RDATA
-
-# SUBTYPE=0 SERVER=root.example.com
-0000 04726f6f74076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdata_caa_fromWire1.spec b/src/lib/dns/tests/testdata/rdata_caa_fromWire1.spec
deleted file mode 100644
index d21987c7eb..0000000000
--- a/src/lib/dns/tests/testdata/rdata_caa_fromWire1.spec
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# The simplest form of CAA: all default parameters
-#
-[custom]
-sections: caa
-[caa]
diff --git a/src/lib/dns/tests/testdata/rdata_caa_fromWire1.wire b/src/lib/dns/tests/testdata/rdata_caa_fromWire1.wire
deleted file mode 100644
index 780bd8dc25..0000000000
--- a/src/lib/dns/tests/testdata/rdata_caa_fromWire1.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_caa_fromWire1.spec
-###
-
-# CAA RDATA, RDLEN=21
-0015
-# FLAGS=0 TAG=issue VALUE=ca.example.net
-00 05 697373756563612e6578616d706c652e6e6574
diff --git a/src/lib/dns/tests/testdata/rdata_caa_fromWire2.spec b/src/lib/dns/tests/testdata/rdata_caa_fromWire2.spec
deleted file mode 100644
index 867e43d048..0000000000
--- a/src/lib/dns/tests/testdata/rdata_caa_fromWire2.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Mixed case CAA tag field.
-#
-[custom]
-sections: caa
-[caa]
-tag: 'ISSue'
diff --git a/src/lib/dns/tests/testdata/rdata_caa_fromWire2.wire b/src/lib/dns/tests/testdata/rdata_caa_fromWire2.wire
deleted file mode 100644
index 09ca24d972..0000000000
--- a/src/lib/dns/tests/testdata/rdata_caa_fromWire2.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_caa_fromWire2.spec
-###
-
-# CAA RDATA, RDLEN=21
-0015
-# FLAGS=0 TAG=ISSue VALUE=ca.example.net
-00 05 495353756563612e6578616d706c652e6e6574
diff --git a/src/lib/dns/tests/testdata/rdata_caa_fromWire3.spec b/src/lib/dns/tests/testdata/rdata_caa_fromWire3.spec
deleted file mode 100644
index 9297151df0..0000000000
--- a/src/lib/dns/tests/testdata/rdata_caa_fromWire3.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Missing CAA value field.
-#
-[custom]
-sections: caa
-[caa]
-value: ''
diff --git a/src/lib/dns/tests/testdata/rdata_caa_fromWire3.wire b/src/lib/dns/tests/testdata/rdata_caa_fromWire3.wire
deleted file mode 100644
index 16b5c43432..0000000000
--- a/src/lib/dns/tests/testdata/rdata_caa_fromWire3.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_caa_fromWire3.spec
-###
-
-# CAA RDATA, RDLEN=7
-0007
-# FLAGS=0 TAG=issue VALUE=
-00 05 6973737565
diff --git a/src/lib/dns/tests/testdata/rdata_caa_fromWire4.spec b/src/lib/dns/tests/testdata/rdata_caa_fromWire4.spec
deleted file mode 100644
index 53e16b12a3..0000000000
--- a/src/lib/dns/tests/testdata/rdata_caa_fromWire4.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Missing CAA value field.
-#
-[custom]
-sections: caa
-[caa]
-tag: ''
diff --git a/src/lib/dns/tests/testdata/rdata_caa_fromWire4.wire b/src/lib/dns/tests/testdata/rdata_caa_fromWire4.wire
deleted file mode 100644
index 3225e60b09..0000000000
--- a/src/lib/dns/tests/testdata/rdata_caa_fromWire4.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_caa_fromWire4.spec
-###
-
-# CAA RDATA, RDLEN=16
-0010
-# FLAGS=0 TAG= VALUE=ca.example.net
-00 00 63612e6578616d706c652e6e6574
diff --git a/src/lib/dns/tests/testdata/rdata_caa_fromWire5 b/src/lib/dns/tests/testdata/rdata_caa_fromWire5
deleted file mode 100644
index 123011fdb3..0000000000
--- a/src/lib/dns/tests/testdata/rdata_caa_fromWire5
+++ /dev/null
@@ -1,6 +0,0 @@
-# Test where CAA value field is shorter than the RDATA length
-
-# CAA RDATA, RDLEN=32
-0020
-# FLAGS=0 TAG=c VALUE=ca.example.net
-00 01 63 63612e6578616d706c652e6e6574
diff --git a/src/lib/dns/tests/testdata/rdata_caa_fromWire6 b/src/lib/dns/tests/testdata/rdata_caa_fromWire6
deleted file mode 100644
index 1a35a1aef7..0000000000
--- a/src/lib/dns/tests/testdata/rdata_caa_fromWire6
+++ /dev/null
@@ -1,4 +0,0 @@
-# Test where RDATA is completely missing
-
-# CAA RDATA, RDLEN=32
-0020
diff --git a/src/lib/dns/tests/testdata/rdata_cname_fromWire b/src/lib/dns/tests/testdata/rdata_cname_fromWire
deleted file mode 100644
index 57eae13b62..0000000000
--- a/src/lib/dns/tests/testdata/rdata_cname_fromWire
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# various kinds of CNAME RDATA stored in an input buffer
-#
-# Valid non-compressed RDATA for cn.example.com.
-# RDLENGTH=16 bytes
-# 0 1
- 00 10
-# 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7(bytes)
-#(2) c n (7) e x a m p l e (3) c o m .
- 02 63 6e 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
-#
-# short length
-# 8 9
- 00 0f
-#20 1 2 3 4 5 6 7 8 9 30 1 2 3 4 5
- 02 63 6e 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
-#
-# length too long
-# 6 7
- 00 11
-#
-# 8 9 40 1 2 3 4 5 6 7 8 9 50 1 2 3 4
- 02 63 6e 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00
-#
-# Valid compressed CNAME name: 'cn2' + pointer
-# 5 6
- 00 06
-# 7 8 9 60 1 2
-#(3) c n 2 ptr=5
- 03 63 6e 32 c0 05
-#
-# Valid compressed CNAME name but RDLENGTH is incorrect: it must be the length
-# of the sequence from the head to the pointer, not the decompressed name
-# length.
-# 3 4
- 00 11
-# 5 6 7 8 9 70
- 03 63 6e 32 c0 05
-# incomplete name (no trailing dot). this can be tested only at the end of
-# the buffer.
-# 1 2
- 00 0f
-# 3 4 5 6 7 8 9 80 1 2 3 4 5 6 7
- 02 63 6e 07 65 78 61 6d 70 6c 65 03 63 6f 6d
diff --git a/src/lib/dns/tests/testdata/rdata_dname_fromWire b/src/lib/dns/tests/testdata/rdata_dname_fromWire
deleted file mode 100644
index 1c899bf19d..0000000000
--- a/src/lib/dns/tests/testdata/rdata_dname_fromWire
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# various kinds of DNAME RDATA stored in an input buffer
-#
-# Valid non-compressed RDATA for dn.example.com.
-# RDLENGTH=16 bytes
-# 0 1
- 00 10
-# 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7(bytes)
-#(2) d n (7) e x a m p l e (3) c o m .
- 02 64 6e 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
-#
-# short length
-# 8 9
- 00 0f
-#20 1 2 3 4 5 6 7 8 9 30 1 2 3 4 5
- 02 64 6e 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
-#
-# length too long
-# 6 7
- 00 11
-#
-# 8 9 40 1 2 3 4 5 6 7 8 9 50 1 2 3 4
- 02 64 6e 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00
-#
-# Valid compressed DNAME name: 'dn2' + pointer
-# 5 6
- 00 06
-# 7 8 9 60 1 2
-#(3) d n 2 ptr=5
- 03 64 6e 32 c0 05
-#
-# Valid compressed DNAME name but RDLENGTH is incorrect: it must be the length
-# of the sequence from the head to the pointer, not the decompressed name
-# length.
-# 3 4
- 00 11
-# 5 6 7 8 9 70
- 03 64 6e 32 c0 05
-# incomplete name (no trailing dot). this can be tested only at the end of
-# the buffer.
-# 1 2
- 00 0f
-# 3 4 5 6 7 8 9 80 1 2 3 4 5 6 7
- 02 64 6e 07 65 78 61 6d 70 6c 65 03 63 6f 6d
diff --git a/src/lib/dns/tests/testdata/rdata_dnskey_empty_keydata_fromWire.spec b/src/lib/dns/tests/testdata/rdata_dnskey_empty_keydata_fromWire.spec
deleted file mode 100644
index b65271d48b..0000000000
--- a/src/lib/dns/tests/testdata/rdata_dnskey_empty_keydata_fromWire.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-# DNSKEY test data with empty digest
-
-[custom]
-sections: dnskey
-
-[dnskey]
-digest:
diff --git a/src/lib/dns/tests/testdata/rdata_dnskey_empty_keydata_fromWire.wire b/src/lib/dns/tests/testdata/rdata_dnskey_empty_keydata_fromWire.wire
deleted file mode 100644
index 35388b193a..0000000000
--- a/src/lib/dns/tests/testdata/rdata_dnskey_empty_keydata_fromWire.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_dnskey_empty_keydata_fromWire.spec
-###
-
-# DNSKEY RDATA, RDLEN=4
-0004
-# FLAGS=257
-0101
-# PROTOCOL=3
-03
-# ALGORITHM=5
-05
-# DIGEST=
-
diff --git a/src/lib/dns/tests/testdata/rdata_dnskey_fromWire.spec b/src/lib/dns/tests/testdata/rdata_dnskey_fromWire.spec
deleted file mode 100644
index 87e66db087..0000000000
--- a/src/lib/dns/tests/testdata/rdata_dnskey_fromWire.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-# DNSKEY test data
-
-[custom]
-sections: dnskey
-
-[dnskey]
-digest: BEAAAAOhHQDBrhQbtphgq2wQUpEQ5t4DtUHxoMVFu2hWLDMvoOMRXjGrhhCeFvAZih7yJHf8ZGfW6hd38hXG/xylYCO6Krpbdojwx8YMXLA5/kA+u50WIL8ZR1R6KTbsYVMf/Qx5RiNbPClw+vT+U8eXEJmO20jIS1ULgqy347cBB1zMnnz/4LJpA0da9CbKj3A254T515sNIMcwsB8/2+2E63/zZrQzBkj0BrN/9Bexjpiks3jRhZatEsXn3dTy47R09Uix5WcJt+xzqZ7+ysyLKOOedS39Z7SDmsn2eA0FKtQpwA6LXeG2w+jxmw3oA8lVUgEf/rzeC/bByBNsO70aEFTd
diff --git a/src/lib/dns/tests/testdata/rdata_dnskey_fromWire.wire b/src/lib/dns/tests/testdata/rdata_dnskey_fromWire.wire
deleted file mode 100644
index 0a2e41fadc..0000000000
--- a/src/lib/dns/tests/testdata/rdata_dnskey_fromWire.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_dnskey_fromWire.spec
-###
-
-# DNSKEY RDATA, RDLEN=265
-0109
-# FLAGS=257
-0101
-# PROTOCOL=3
-03
-# ALGORITHM=5
-05
-# DIGEST=BEAAAAOhHQDBrhQbtphgq2wQUpEQ5t4DtUHxoMVFu2hWLDMvoOMRXjGrhhCeFvAZih7yJHf8ZGfW6hd38hXG/xylYCO6Krpbdojwx8YMXLA5/kA+u50WIL8ZR1R6KTbsYVMf/Qx5RiNbPClw+vT+U8eXEJmO20jIS1ULgqy347cBB1zMnnz/4LJpA0da9CbKj3A254T515sNIMcwsB8/2+2E63/zZrQzBkj0BrN/9Bexjpiks3jRhZatEsXn3dTy47R09Uix5WcJt+xzqZ7+ysyLKOOedS39Z7SDmsn2eA0FKtQpwA6LXeG2w+jxmw3oA8lVUgEf/rzeC/bByBNsO70aEFTd
-0440000003a11d00c1ae141bb69860ab6c10529110e6de03b541f1a0c545bb68562c332fa0e3115e31ab86109e16f0198a1ef22477fc6467d6ea1777f215c6ff1ca56023ba2aba5b7688f0c7c60c5cb039fe403ebb9d1620bf1947547a2936ec61531ffd0c7946235b3c2970faf4fe53c79710998edb48c84b550b82acb7e3b701075ccc9e7cffe0b26903475af426ca8f7036e784f9d79b0d20c730b01f3fdbed84eb7ff366b4330648f406b37ff417b18e98a4b378d18596ad12c5e7ddd4f2e3b474f548b1e56709b7ec73a99efecacc8b28e39e752dfd67b4839ac9f6780d052ad429c00e8b5de1b6c3e8f19b0de803c95552011ffebcde0bf6c1c8136c3bbd1a1054dd
diff --git a/src/lib/dns/tests/testdata/rdata_ds_fromWire b/src/lib/dns/tests/testdata/rdata_ds_fromWire
deleted file mode 100644
index 81c412ca4e..0000000000
--- a/src/lib/dns/tests/testdata/rdata_ds_fromWire
+++ /dev/null
@@ -1,6 +0,0 @@
-# RDLENGTH 36 bytes
-00 24
-# DS record, keyid 12892
-32 5c 05 02 f1 e1 84 c0 e1 d6 15 d2 0e b3 c2 23
-ac ed 3b 03 c7 73 dd 95 2d 5f 0e b5 c7 77 58 6d
-e1 8d a6 b5
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_fromWire1.spec b/src/lib/dns/tests/testdata/rdata_minfo_fromWire1.spec
deleted file mode 100644
index 2c43db0727..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_fromWire1.spec
+++ /dev/null
@@ -1,3 +0,0 @@
-[custom]
-sections: minfo
-[minfo]
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_fromWire1.wire b/src/lib/dns/tests/testdata/rdata_minfo_fromWire1.wire
deleted file mode 100644
index 3483e9b1ea..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_fromWire1.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_minfo_fromWire1.spec
-###
-
-# MINFO RDATA, RDLEN=44
-002c
-# RMAILBOX=rmailbox.example.com EMAILBOX=emailbox.example.com
-08726d61696c626f78076578616d706c6503636f6d00 08656d61696c626f78076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_fromWire2.spec b/src/lib/dns/tests/testdata/rdata_minfo_fromWire2.spec
deleted file mode 100644
index d781cac71d..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_fromWire2.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-[custom]
-sections: name:minfo
-[name]
-name: a.example.com.
-[minfo]
-rmailbox: rmailbox.ptr=02
-emailbox: emailbox.ptr=02
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_fromWire2.wire b/src/lib/dns/tests/testdata/rdata_minfo_fromWire2.wire
deleted file mode 100644
index d79e936335..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_fromWire2.wire
+++ /dev/null
@@ -1,11 +0,0 @@
-###
-### This data file was auto-generated from rdata_minfo_fromWire2.spec
-###
-
-# DNS Name: a.example.com.
-0161076578616d706c6503636f6d00
-
-# MINFO RDATA, RDLEN=22
-0016
-# RMAILBOX=rmailbox.ptr=02 EMAILBOX=emailbox.ptr=02
-08726d61696c626f78c002 08656d61696c626f78c002
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_fromWire3.spec b/src/lib/dns/tests/testdata/rdata_minfo_fromWire3.spec
deleted file mode 100644
index a1d4b769d9..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_fromWire3.spec
+++ /dev/null
@@ -1,6 +0,0 @@
-[custom]
-sections: minfo
-# rdlength too short
-[minfo]
-emailbox: emailbox.ptr=11
-rdlen: 3
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_fromWire3.wire b/src/lib/dns/tests/testdata/rdata_minfo_fromWire3.wire
deleted file mode 100644
index 55df1a2de4..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_fromWire3.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_minfo_fromWire3.spec
-###
-
-# MINFO RDATA, RDLEN=3
-0003
-# RMAILBOX=rmailbox.example.com EMAILBOX=emailbox.ptr=11
-08726d61696c626f78076578616d706c6503636f6d00 08656d61696c626f78c00b
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_fromWire4.spec b/src/lib/dns/tests/testdata/rdata_minfo_fromWire4.spec
deleted file mode 100644
index 269a6ce7e2..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_fromWire4.spec
+++ /dev/null
@@ -1,6 +0,0 @@
-[custom]
-sections: minfo
-# rdlength too long
-[minfo]
-emailbox: emailbox.ptr=11
-rdlen: 80
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_fromWire4.wire b/src/lib/dns/tests/testdata/rdata_minfo_fromWire4.wire
deleted file mode 100644
index 746f55abe2..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_fromWire4.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_minfo_fromWire4.spec
-###
-
-# MINFO RDATA, RDLEN=80
-0050
-# RMAILBOX=rmailbox.example.com EMAILBOX=emailbox.ptr=11
-08726d61696c626f78076578616d706c6503636f6d00 08656d61696c626f78c00b
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_fromWire5.spec b/src/lib/dns/tests/testdata/rdata_minfo_fromWire5.spec
deleted file mode 100644
index 3a888e3c20..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_fromWire5.spec
+++ /dev/null
@@ -1,5 +0,0 @@
-[custom]
-sections: minfo
-# bogus rmailbox name
-[minfo]
-rmailbox: "01234567890123456789012345678901234567890123456789012345678901234"
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_fromWire5.wire b/src/lib/dns/tests/testdata/rdata_minfo_fromWire5.wire
deleted file mode 100644
index dacd9a026a..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_fromWire5.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_minfo_fromWire5.spec
-###
-
-# MINFO RDATA, RDLEN=91
-005b
-# RMAILBOX="01234567890123456789012345678901234567890123456789012345678901234" EMAILBOX=emailbox.example.com
-432230313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233342200 08656d61696c626f78076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_fromWire6.spec b/src/lib/dns/tests/testdata/rdata_minfo_fromWire6.spec
deleted file mode 100644
index c75ed8e214..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_fromWire6.spec
+++ /dev/null
@@ -1,5 +0,0 @@
-[custom]
-sections: minfo
-# bogus emailbox name
-[minfo]
-emailbox: "01234567890123456789012345678901234567890123456789012345678901234"
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_fromWire6.wire b/src/lib/dns/tests/testdata/rdata_minfo_fromWire6.wire
deleted file mode 100644
index 4199fee44e..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_fromWire6.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_minfo_fromWire6.spec
-###
-
-# MINFO RDATA, RDLEN=91
-005b
-# RMAILBOX=rmailbox.example.com EMAILBOX="01234567890123456789012345678901234567890123456789012345678901234"
-08726d61696c626f78076578616d706c6503636f6d00 432230313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233342200
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_toWire1.spec b/src/lib/dns/tests/testdata/rdata_minfo_toWire1.spec
deleted file mode 100644
index 7b340a3904..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_toWire1.spec
+++ /dev/null
@@ -1,5 +0,0 @@
-[custom]
-sections: minfo
-[minfo]
-emailbox: emailbox.ptr=09
-rdlen: -1
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_toWire1.wire b/src/lib/dns/tests/testdata/rdata_minfo_toWire1.wire
deleted file mode 100644
index 8ac4afe295..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_toWire1.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_minfo_toWire1.spec
-###
-
-# MINFO RDATA
-
-# RMAILBOX=rmailbox.example.com EMAILBOX=emailbox.ptr=09
-08726d61696c626f78076578616d706c6503636f6d00 08656d61696c626f78c009
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_toWire2.spec b/src/lib/dns/tests/testdata/rdata_minfo_toWire2.spec
deleted file mode 100644
index 132f11839f..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_toWire2.spec
+++ /dev/null
@@ -1,6 +0,0 @@
-[custom]
-sections: minfo
-[minfo]
-rmailbox: root.example.com.
-emailbox: emailbox.ptr=05
-rdlen: -1
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_toWire2.wire b/src/lib/dns/tests/testdata/rdata_minfo_toWire2.wire
deleted file mode 100644
index 7fb847cc91..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_toWire2.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_minfo_toWire2.spec
-###
-
-# MINFO RDATA
-
-# RMAILBOX=root.example.com. EMAILBOX=emailbox.ptr=05
-04726f6f74076578616d706c6503636f6d00 08656d61696c626f78c005
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_toWireUncompressed1.spec b/src/lib/dns/tests/testdata/rdata_minfo_toWireUncompressed1.spec
deleted file mode 100644
index d99a3813ca..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_toWireUncompressed1.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# A simplest form of MINFO: all default parameters
-#
-[custom]
-sections: minfo
-[minfo]
-rdlen: -1
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_toWireUncompressed1.wire b/src/lib/dns/tests/testdata/rdata_minfo_toWireUncompressed1.wire
deleted file mode 100644
index 6de233e633..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_toWireUncompressed1.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_minfo_toWireUncompressed1.spec
-###
-
-# MINFO RDATA
-
-# RMAILBOX=rmailbox.example.com EMAILBOX=emailbox.example.com
-08726d61696c626f78076578616d706c6503636f6d00 08656d61696c626f78076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_toWireUncompressed2.spec b/src/lib/dns/tests/testdata/rdata_minfo_toWireUncompressed2.spec
deleted file mode 100644
index 0f78fcc63b..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_toWireUncompressed2.spec
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# A simplest form of MINFO: custom rmailbox and default emailbox
-#
-[custom]
-sections: minfo
-[minfo]
-rmailbox: root.example.com.
-rdlen: -1
diff --git a/src/lib/dns/tests/testdata/rdata_minfo_toWireUncompressed2.wire b/src/lib/dns/tests/testdata/rdata_minfo_toWireUncompressed2.wire
deleted file mode 100644
index 51e9e354c3..0000000000
--- a/src/lib/dns/tests/testdata/rdata_minfo_toWireUncompressed2.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_minfo_toWireUncompressed2.spec
-###
-
-# MINFO RDATA
-
-# RMAILBOX=root.example.com. EMAILBOX=emailbox.example.com
-04726f6f74076578616d706c6503636f6d00 08656d61696c626f78076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdata_mx_fromWire b/src/lib/dns/tests/testdata/rdata_mx_fromWire
deleted file mode 100644
index 8e09154e53..0000000000
--- a/src/lib/dns/tests/testdata/rdata_mx_fromWire
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# various kinds of MX RDATA stored in an input buffer
-#
-# Valid RDATA for "10 mail.example.com"
-#
-# RDLENGTH=18 bytes
-# 0 1
- 00 12
-# 2 3
-# PREFERENCE: 10
- 00 0a
-# EXCHANGE: non compressed
-# 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 (bytes)
-#(2) m x (7) e x a m p l e (3) c o m .
- 02 6d 78 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
diff --git a/src/lib/dns/tests/testdata/rdata_mx_toWire1 b/src/lib/dns/tests/testdata/rdata_mx_toWire1
deleted file mode 100644
index 3049373246..0000000000
--- a/src/lib/dns/tests/testdata/rdata_mx_toWire1
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# compressed MX RDATA stored in an output buffer
-#
-# sentinel name: example.com.
-# 0 1 2 3 4 5 6 7 8 9 10 1 2 (bytes)
-#(7) e x a m p l e (3) c o m .
- 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
-# PREFERENCE: 10
- 00 0a
-# EXCHANGE: compressed
-#(4) m x ptr=0
- 02 6d 78 c0 00
diff --git a/src/lib/dns/tests/testdata/rdata_mx_toWire2 b/src/lib/dns/tests/testdata/rdata_mx_toWire2
deleted file mode 100644
index ebd2f27cfc..0000000000
--- a/src/lib/dns/tests/testdata/rdata_mx_toWire2
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# compressed MX RDATA stored in an output buffer
-#
-# sentinel name: example.com.
-# 0 1 2 3 4 5 6 7 8 9 10 1 2 (bytes)
-#(7) e x a m p l e (3) c o m .
- 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
-# PREFERENCE: 10
- 00 0a
-# EXCHANGE: not compressed
-#(4) m x ptr=0
- 02 6d 78 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire1 b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire1
deleted file mode 100644
index 1dd5f52929..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire1
+++ /dev/null
@@ -1,7 +0,0 @@
-# RDLENGTH, 39 bytes
-00 27
-# NSEC3 record:
-# 1 1 1 D399EAAB H9RSFB7FPF2L8HG35CMPC765TDK23RP6 NS SOA RRSIG DNSKEY NSEC3PARAM
-01 01 00 01 04 d3 99 ea ab 14 8a 77 c7 ac ef cb
-c5 54 46 03 2b 2d 96 1c c5 eb 68 21 ef 26 00 07
-22 00 00 00 00 02 90
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire1.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire1.spec
deleted file mode 100644
index 39a78d75f1..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire1.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# A malformed NSEC3 RDATA: bit map length is too large, causing overflow
-#
-
-[custom]
-sections: nsec3
-[nsec3]
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire10.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire10.spec
deleted file mode 100644
index 30417f5e15..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire10.spec
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# An invalid NSEC3 RDATA: a bitmap block containing empty bytes
-#
-
-[custom]
-sections: nsec3
-[nsec3]
-bitmap: '01000000'
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire10.wire b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire10.wire
deleted file mode 100644
index 99c5afd5ae..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire10.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3_fromWire10.spec
-###
-
-# NSEC3 RDATA, RDLEN=37
-0025
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=5, Salt='sssss'
-05 7373737373
-# Hash Len=20, Hash='hhhhhhhhhhhhhhhhhhhh'
-14 6868686868686868686868686868686868686868
-# Bitmap: Block=0, Length=4
-00 04 01000000
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire11.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire11.spec
deleted file mode 100644
index 80ec59f0c4..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire11.spec
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# An invalid NSEC3 RDATA: Saltlen is too large
-#
-
-[custom]
-sections: nsec3
-[nsec3]
-rdlen: 7
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire11.wire b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire11.wire
deleted file mode 100644
index 48dc589f35..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire11.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3_fromWire11.spec
-###
-
-# NSEC3 RDATA, RDLEN=7
-0007
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=5, Salt='sssss'
-05 7373737373
-# Hash Len=20, Hash='hhhhhhhhhhhhhhhhhhhh'
-14 6868686868686868686868686868686868686868
-# Bitmap: Block=0, Length=6
-00 06 040000000003
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire12.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire12.spec
deleted file mode 100644
index 1e01655d31..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire12.spec
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# An invalid NSEC3 RDATA: Hash length is too large
-#
-
-[custom]
-sections: nsec3
-[nsec3]
-# only contains the first byte of hash
-rdlen: 12
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire12.wire b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire12.wire
deleted file mode 100644
index e880d553b7..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire12.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3_fromWire12.spec
-###
-
-# NSEC3 RDATA, RDLEN=12
-000c
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=5, Salt='sssss'
-05 7373737373
-# Hash Len=20, Hash='hhhhhhhhhhhhhhhhhhhh'
-14 6868686868686868686868686868686868686868
-# Bitmap: Block=0, Length=6
-00 06 040000000003
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire13.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire13.spec
deleted file mode 100644
index fcc9d535dd..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire13.spec
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# A valid (but unusual) NSEC3 RDATA: salt is empty.
-#
-
-[custom]
-sections: nsec3
-[nsec3]
-saltlen: 0
-salt: ''
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire13.wire b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire13.wire
deleted file mode 100644
index 86a06c5d98..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire13.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3_fromWire13.spec
-###
-
-# NSEC3 RDATA, RDLEN=34
-0022
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=0, Salt=''
-00
-# Hash Len=20, Hash='hhhhhhhhhhhhhhhhhhhh'
-14 6868686868686868686868686868686868686868
-# Bitmap: Block=0, Length=6
-00 06 040000000003
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire14.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire14.spec
deleted file mode 100644
index a0550d5e6f..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire14.spec
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# An invalid NSEC3 RDATA: empty hash
-#
-
-[custom]
-sections: nsec3
-[nsec3]
-hashlen: 0
-hash: ''
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire14.wire b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire14.wire
deleted file mode 100644
index 9d76b5ab15..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire14.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3_fromWire14.spec
-###
-
-# NSEC3 RDATA, RDLEN=19
-0013
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=5, Salt='sssss'
-05 7373737373
-# Hash Len=0, Hash=''
-00
-# Bitmap: Block=0, Length=6
-00 06 040000000003
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire15.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire15.spec
deleted file mode 100644
index 4993e03f67..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire15.spec
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# NSEC3 RDATA with empty type bitmap. It's okay.
-# The test data includes bytes for a bitmap field, but RDLEN indicates
-# it's not part of the RDATA and so it will be ignored.
-#
-
-[custom]
-sections: nsec3
-[nsec3]
-rdlen: 31
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire15.wire b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire15.wire
deleted file mode 100644
index bd636a7e93..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire15.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3_fromWire15.spec
-###
-
-# NSEC3 RDATA, RDLEN=31
-001f
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=5, Salt='sssss'
-05 7373737373
-# Hash Len=20, Hash='hhhhhhhhhhhhhhhhhhhh'
-14 6868686868686868686868686868686868686868
-# Bitmap: Block=0, Length=6
-00 06 040000000003
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire16.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire16.spec
deleted file mode 100644
index dac14eaa21..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire16.spec
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# NSEC3 RDATA with an empty bitmap
-#
-
-[custom]
-sections: nsec3
-[nsec3]
-nbitmap: 0
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire16.wire b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire16.wire
deleted file mode 100644
index bab957ead6..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire16.wire
+++ /dev/null
@@ -1,12 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3_fromWire16.spec
-###
-
-# NSEC3 RDATA, RDLEN=31
-001f
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=5, Salt='sssss'
-05 7373737373
-# Hash Len=20, Hash='hhhhhhhhhhhhhhhhhhhh'
-14 6868686868686868686868686868686868686868
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire17.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire17.spec
deleted file mode 100644
index 42533491bf..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire17.spec
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# An invalid NSEC3 RDATA: RDLEN is too short to include the hash len field.
-#
-
-[custom]
-sections: nsec3
-[nsec3]
-rdlen: 10
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire17.wire b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire17.wire
deleted file mode 100644
index f7972a0ace..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire17.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3_fromWire17.spec
-###
-
-# NSEC3 RDATA, RDLEN=10
-000a
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=5, Salt='sssss'
-05 7373737373
-# Hash Len=20, Hash='hhhhhhhhhhhhhhhhhhhh'
-14 6868686868686868686868686868686868686868
-# Bitmap: Block=0, Length=6
-00 06 040000000003
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire2.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire2.spec
deleted file mode 100644
index f35de8399f..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire2.spec
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# A malformed NSEC3 RDATA: RDLEN indicates it doesn't even contain the fixed
-# 5 octets
-#
-
-[custom]
-sections: nsec3
-[nsec3]
-rdlen: 4
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire2.wire b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire2.wire
deleted file mode 100644
index ec14a5840e..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire2.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3_fromWire2.spec
-###
-
-# NSEC3 RDATA, RDLEN=4
-0004
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=5, Salt='sssss'
-05 7373737373
-# Hash Len=20, Hash='hhhhhhhhhhhhhhhhhhhh'
-14 6868686868686868686868686868686868686868
-# Bitmap: Block=0, Length=6
-00 06 040000000003
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire3 b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire3
deleted file mode 100644
index a0c8f599c0..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire3
+++ /dev/null
@@ -1,6 +0,0 @@
-# RDLENGTH, 39 bytes
-00 27
-# NSEC3 record with a broken type bitmap
-01 01 00 01 04 d3 99 ea ab 14 8a 77 c7 ac ef cb
-c5 54 46 03 2b 2d 96 1c c5 eb 68 21 ef 26 00 ff
-22 00 00 00 00 02 90
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire4.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire4.spec
deleted file mode 100644
index 06d6eb4d2b..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire4.spec
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# A malformed NSEC3 RDATA: bit map length is too large, causing overflow
-#
-
-[custom]
-sections: nsec3
-[nsec3]
-maplen: 31
-bitmap: '01'
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire4.wire b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire4.wire
deleted file mode 100644
index 527860c35b..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire4.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3_fromWire4.spec
-###
-
-# NSEC3 RDATA, RDLEN=34
-0022
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=5, Salt='sssss'
-05 7373737373
-# Hash Len=20, Hash='hhhhhhhhhhhhhhhhhhhh'
-14 6868686868686868686868686868686868686868
-# Bitmap: Block=0, Length=31
-00 1f 01
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire5.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire5.spec
deleted file mode 100644
index 2d5713cee9..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire5.spec
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# A malformed NSEC3 RDATA: incomplete bit map field
-#
-
-[custom]
-sections: nsec3
-[nsec3]
-# only containing the block field of the bitmap
-rdlen: 32
-#dummy data
-maplen: 31
-#dummy data
-bitmap: '00'
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire5.wire b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire5.wire
deleted file mode 100644
index 97b798beca..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire5.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3_fromWire5.spec
-###
-
-# NSEC3 RDATA, RDLEN=32
-0020
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=5, Salt='sssss'
-05 7373737373
-# Hash Len=20, Hash='hhhhhhhhhhhhhhhhhhhh'
-14 6868686868686868686868686868686868686868
-# Bitmap: Block=0, Length=31
-00 1f 00
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire6.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire6.spec
deleted file mode 100644
index 36e9e59b4c..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire6.spec
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# A malformed NSEC3 RDATA: bit map length being 0
-#
-
-[custom]
-sections: nsec3
-[nsec3]
-rdlen: 33
-maplen: 0
-# dummy data:
-bitmap: '01'
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire6.wire b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire6.wire
deleted file mode 100644
index 4cf1189ea2..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire6.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3_fromWire6.spec
-###
-
-# NSEC3 RDATA, RDLEN=33
-0021
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=5, Salt='sssss'
-05 7373737373
-# Hash Len=20, Hash='hhhhhhhhhhhhhhhhhhhh'
-14 6868686868686868686868686868686868686868
-# Bitmap: Block=0, Length=0
-00 00 01
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire7.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire7.spec
deleted file mode 100644
index 338c0c98de..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire7.spec
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# NSEC3 RDATA with a longest bitmap field (32 bitmap bytes)
-#
-
-[custom]
-sections: nsec3
-[nsec3]
-maplen: 32
-bitmap: '0101010101010101010101010101010101010101010101010101010101010101'
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire7.wire b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire7.wire
deleted file mode 100644
index 1fddd5866d..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire7.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3_fromWire7.spec
-###
-
-# NSEC3 RDATA, RDLEN=65
-0041
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=5, Salt='sssss'
-05 7373737373
-# Hash Len=20, Hash='hhhhhhhhhhhhhhhhhhhh'
-14 6868686868686868686868686868686868686868
-# Bitmap: Block=0, Length=32
-00 20 0101010101010101010101010101010101010101010101010101010101010101
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire8.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire8.spec
deleted file mode 100644
index 041714ecb8..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire8.spec
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# An invalid NSEC3 RDATA with an oversized bitmap field (33 bitmap bytes)
-#
-
-[custom]
-sections: nsec3
-[nsec3]
-maplen: 33
-bitmap: '010101010101010101010101010101010101010101010101010101010101010101'
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire8.wire b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire8.wire
deleted file mode 100644
index 956909470b..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire8.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3_fromWire8.spec
-###
-
-# NSEC3 RDATA, RDLEN=66
-0042
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=5, Salt='sssss'
-05 7373737373
-# Hash Len=20, Hash='hhhhhhhhhhhhhhhhhhhh'
-14 6868686868686868686868686868686868686868
-# Bitmap: Block=0, Length=33
-00 21 010101010101010101010101010101010101010101010101010101010101010101
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire9.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire9.spec
deleted file mode 100644
index b04c84f7fc..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire9.spec
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# An invalid NSEC3 RDATA: disordered bitmap blocks
-#
-
-[custom]
-sections: nsec3
-[nsec3]
-nbitmap: 2
-block0: 2
-block1: 1
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire9.wire b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire9.wire
deleted file mode 100644
index 9c0de10c7e..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire9.wire
+++ /dev/null
@@ -1,16 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3_fromWire9.spec
-###
-
-# NSEC3 RDATA, RDLEN=47
-002f
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=5, Salt='sssss'
-05 7373737373
-# Hash Len=20, Hash='hhhhhhhhhhhhhhhhhhhh'
-14 6868686868686868686868686868686868686868
-# Bitmap: Block=2, Length=6
-02 06 040000000003
-# Bitmap: Block=1, Length=6
-01 06 040000000003
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire1 b/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire1
deleted file mode 100644
index 1b8697ff83..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire1
+++ /dev/null
@@ -1,5 +0,0 @@
-# RDLENGTH, 9 bytes
-00 09
-# NSEC3PARAM record
-# 1 1 1 D399EAAB
-01 01 00 01 04 d3 99 ea ab
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire11.spec b/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire11.spec
deleted file mode 100644
index 41e17847f1..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire11.spec
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# An invalid NSEC3PARAM RDATA: Saltlen is too large
-#
-
-[custom]
-sections: nsec3param
-[nsec3param]
-rdlen: 7
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire11.wire b/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire11.wire
deleted file mode 100644
index e9ffb4620e..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire11.wire
+++ /dev/null
@@ -1,10 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3param_fromWire11.spec
-###
-
-# NSEC3PARAM RDATA, RDLEN=7
-0007
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=5, Salt='sssss'
-05 7373737373
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire13.spec b/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire13.spec
deleted file mode 100644
index 311b2dd898..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire13.spec
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# A valid (but unusual) NSEC3PARAM RDATA: salt is empty.
-#
-
-[custom]
-sections: nsec3param
-[nsec3param]
-saltlen: 0
-salt: ''
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire13.wire b/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire13.wire
deleted file mode 100644
index 511da87f5c..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire13.wire
+++ /dev/null
@@ -1,10 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3param_fromWire13.spec
-###
-
-# NSEC3PARAM RDATA, RDLEN=5
-0005
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=0, Salt=''
-00
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire2.spec b/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire2.spec
deleted file mode 100644
index e04b818e98..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire2.spec
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# A malformed NSEC3PARAM RDATA: RDLEN indicates it doesn't even contain the
-# fixed 5 octets
-#
-
-[custom]
-sections: nsec3param
-[nsec3param]
-rdlen: 4
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire2.wire b/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire2.wire
deleted file mode 100644
index adc5ea9f64..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec3param_fromWire2.wire
+++ /dev/null
@@ -1,10 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec3param_fromWire2.spec
-###
-
-# NSEC3PARAM RDATA, RDLEN=4
-0004
-# Hash Alg=SHA1(1), Opt-Out=0, Other Flags=0, Iterations=1
-01 00 0001
-# Salt Len=5, Salt='sssss'
-05 7373737373
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire1 b/src/lib/dns/tests/testdata/rdata_nsec_fromWire1
deleted file mode 100644
index 9c343941ff..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire1
+++ /dev/null
@@ -1,6 +0,0 @@
-# RDLENGTH, 22 bytes
-00 16
-# NSEC record
-# www2.isc.org. CNAME RRSIG NSEC
-04 77 77 77 32 03 69 73 63 03 6f 72 67 00 00 06
-04 00 00 00 00 03
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire10.spec b/src/lib/dns/tests/testdata/rdata_nsec_fromWire10.spec
deleted file mode 100644
index 39d19ae15c..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire10.spec
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# An invalid NSEC RDATA: a bitmap block containing empty bytes
-#
-
-[custom]
-sections: nsec
-[nsec]
-bitmap: '01000000'
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire10.wire b/src/lib/dns/tests/testdata/rdata_nsec_fromWire10.wire
deleted file mode 100644
index 1145dbd586..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire10.wire
+++ /dev/null
@@ -1,10 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec_fromWire10.spec
-###
-
-# NSEC RDATA, RDLEN=24
-0018
-# Next Name=next.example.com (18 bytes)
-046e657874076578616d706c6503636f6d00
-# Bitmap: Block=0, Length=4
-00 04 01000000
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire16.spec b/src/lib/dns/tests/testdata/rdata_nsec_fromWire16.spec
deleted file mode 100644
index d7faeedd8a..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire16.spec
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# An invalid NSEC RDATA: with an empty bitmap
-#
-
-[custom]
-sections: nsec
-[nsec]
-nbitmap: 0
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire16.wire b/src/lib/dns/tests/testdata/rdata_nsec_fromWire16.wire
deleted file mode 100644
index 943601aacb..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire16.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec_fromWire16.spec
-###
-
-# NSEC RDATA, RDLEN=18
-0012
-# Next Name=next.example.com (18 bytes)
-046e657874076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire2 b/src/lib/dns/tests/testdata/rdata_nsec_fromWire2
deleted file mode 100644
index e9b41e284a..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire2
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# NSEC RDATA with a bogus RDLEN (too short)
-#
-
-# RDLENGTH, 13 bytes (should be 22)
-00 0d
-# NSEC record
-# www2.isc.org. CNAME RRSIG NSEC
-04 77 77 77 32 03 69 73 63 03 6f 72 67 00 00 06
-04 00 00 00 00 03
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire3 b/src/lib/dns/tests/testdata/rdata_nsec_fromWire3
deleted file mode 100644
index 67e6b3f112..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire3
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# NSEC RDATA with an invalid type bitmap
-#
-
-# RDLENGTH, 22 bytes
-00 16
-# NSEC record
-# www2.isc.org. followed by a broken bitmap
-04 77 77 77 32 03 69 73 63 03 6f 72 67 00 00 ff
-00 00 00 00 00 00
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire4.spec b/src/lib/dns/tests/testdata/rdata_nsec_fromWire4.spec
deleted file mode 100644
index a5744c194f..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire4.spec
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# A malformed NSEC RDATA: bit map length is too large, causing overflow
-#
-
-[custom]
-sections: nsec
-[nsec]
-maplen: 31
-bitmap: '01'
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire4.wire b/src/lib/dns/tests/testdata/rdata_nsec_fromWire4.wire
deleted file mode 100644
index 1c4d4a427f..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire4.wire
+++ /dev/null
@@ -1,10 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec_fromWire4.spec
-###
-
-# NSEC RDATA, RDLEN=21
-0015
-# Next Name=next.example.com (18 bytes)
-046e657874076578616d706c6503636f6d00
-# Bitmap: Block=0, Length=31
-00 1f 01
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire5.spec b/src/lib/dns/tests/testdata/rdata_nsec_fromWire5.spec
deleted file mode 100644
index 795d1e061b..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire5.spec
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# A malformed NSEC RDATA: incomplete bit map field
-#
-
-[custom]
-sections: nsec
-[nsec]
-# only containing the block field of the bitmap
-rdlen: 19
-#dummy data
-maplen: 31
-#dummy data
-bitmap: '00'
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire5.wire b/src/lib/dns/tests/testdata/rdata_nsec_fromWire5.wire
deleted file mode 100644
index 104a2b9b98..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire5.wire
+++ /dev/null
@@ -1,10 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec_fromWire5.spec
-###
-
-# NSEC RDATA, RDLEN=19
-0013
-# Next Name=next.example.com (18 bytes)
-046e657874076578616d706c6503636f6d00
-# Bitmap: Block=0, Length=31
-00 1f 00
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire6.spec b/src/lib/dns/tests/testdata/rdata_nsec_fromWire6.spec
deleted file mode 100644
index cb864abcf1..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire6.spec
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# A malformed NSEC RDATA: bit map length being 0
-#
-
-[custom]
-sections: nsec
-[nsec]
-rdlen: 20
-maplen: 0
-# dummy data:
-bitmap: '01'
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire6.wire b/src/lib/dns/tests/testdata/rdata_nsec_fromWire6.wire
deleted file mode 100644
index 3108ed7f01..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire6.wire
+++ /dev/null
@@ -1,10 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec_fromWire6.spec
-###
-
-# NSEC RDATA, RDLEN=20
-0014
-# Next Name=next.example.com (18 bytes)
-046e657874076578616d706c6503636f6d00
-# Bitmap: Block=0, Length=0
-00 00 01
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire7.spec b/src/lib/dns/tests/testdata/rdata_nsec_fromWire7.spec
deleted file mode 100644
index 46b521b525..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire7.spec
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# NSEC RDATA with a longest bitmap field (32 bitmap bytes)
-#
-
-[custom]
-sections: nsec
-[nsec]
-maplen: 32
-bitmap: '0101010101010101010101010101010101010101010101010101010101010101'
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire7.wire b/src/lib/dns/tests/testdata/rdata_nsec_fromWire7.wire
deleted file mode 100644
index e265a3b7e3..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire7.wire
+++ /dev/null
@@ -1,10 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec_fromWire7.spec
-###
-
-# NSEC RDATA, RDLEN=52
-0034
-# Next Name=next.example.com (18 bytes)
-046e657874076578616d706c6503636f6d00
-# Bitmap: Block=0, Length=32
-00 20 0101010101010101010101010101010101010101010101010101010101010101
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire8.spec b/src/lib/dns/tests/testdata/rdata_nsec_fromWire8.spec
deleted file mode 100644
index 3f957a3ce1..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire8.spec
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# An invalid NSEC RDATA with an oversized bitmap field (33 bitmap bytes)
-#
-
-[custom]
-sections: nsec
-[nsec]
-maplen: 33
-bitmap: '010101010101010101010101010101010101010101010101010101010101010101'
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire8.wire b/src/lib/dns/tests/testdata/rdata_nsec_fromWire8.wire
deleted file mode 100644
index 066cd70c26..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire8.wire
+++ /dev/null
@@ -1,10 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec_fromWire8.spec
-###
-
-# NSEC RDATA, RDLEN=53
-0035
-# Next Name=next.example.com (18 bytes)
-046e657874076578616d706c6503636f6d00
-# Bitmap: Block=0, Length=33
-00 21 010101010101010101010101010101010101010101010101010101010101010101
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire9.spec b/src/lib/dns/tests/testdata/rdata_nsec_fromWire9.spec
deleted file mode 100644
index a3bd0c90ec..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire9.spec
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# An invalid NSEC RDATA: disordered bitmap blocks
-#
-
-[custom]
-sections: nsec
-[nsec]
-nbitmap: 2
-block0: 2
-block1: 1
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire9.wire b/src/lib/dns/tests/testdata/rdata_nsec_fromWire9.wire
deleted file mode 100644
index 53ad6cc3f4..0000000000
--- a/src/lib/dns/tests/testdata/rdata_nsec_fromWire9.wire
+++ /dev/null
@@ -1,12 +0,0 @@
-###
-### This data file was auto-generated from rdata_nsec_fromWire9.spec
-###
-
-# NSEC RDATA, RDLEN=34
-0022
-# Next Name=next.example.com (18 bytes)
-046e657874076578616d706c6503636f6d00
-# Bitmap: Block=2, Length=6
-02 06 040000000003
-# Bitmap: Block=1, Length=6
-01 06 040000000003
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire1.spec b/src/lib/dns/tests/testdata/rdata_rp_fromWire1.spec
deleted file mode 100644
index edb9f345be..0000000000
--- a/src/lib/dns/tests/testdata/rdata_rp_fromWire1.spec
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# A simplest form of RP: all default parameters
-#
-[custom]
-sections: rp
-[rp]
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire1.wire b/src/lib/dns/tests/testdata/rdata_rp_fromWire1.wire
deleted file mode 100644
index aa939861af..0000000000
--- a/src/lib/dns/tests/testdata/rdata_rp_fromWire1.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_rp_fromWire1.spec
-###
-
-# RP RDATA, RDLEN=39
-0027
-# MAILBOX=root.example.com TEXT=rp-text.example.com
-04726f6f74076578616d706c6503636f6d00 0772702d74657874076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire2.spec b/src/lib/dns/tests/testdata/rdata_rp_fromWire2.spec
deleted file mode 100644
index 57adb5a0a0..0000000000
--- a/src/lib/dns/tests/testdata/rdata_rp_fromWire2.spec
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# A simplest form of RP: names are compressed.
-#
-[custom]
-sections: name/1:name/2:rp
-[name/1]
-name: a.example.com
-[name/2]
-name: b.example.net
-[rp]
-mailbox: root.ptr=2
-text: rp-text.ptr=17
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire2.wire b/src/lib/dns/tests/testdata/rdata_rp_fromWire2.wire
deleted file mode 100644
index 507bb1a9b5..0000000000
--- a/src/lib/dns/tests/testdata/rdata_rp_fromWire2.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_rp_fromWire2.spec
-###
-
-# DNS Name: a.example.com
-0161076578616d706c6503636f6d00
-
-# DNS Name: b.example.net
-0162076578616d706c65036e657400
-
-# RP RDATA, RDLEN=17
-0011
-# MAILBOX=root.ptr=2 TEXT=rp-text.ptr=17
-04726f6f74c002 0772702d74657874c011
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire3.spec b/src/lib/dns/tests/testdata/rdata_rp_fromWire3.spec
deleted file mode 100644
index a238b7e2c5..0000000000
--- a/src/lib/dns/tests/testdata/rdata_rp_fromWire3.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# RP-like RDATA but RDLEN is too short.
-#
-[custom]
-sections: rp
-[rp]
-rdlen: 38
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire3.wire b/src/lib/dns/tests/testdata/rdata_rp_fromWire3.wire
deleted file mode 100644
index c2a7086093..0000000000
--- a/src/lib/dns/tests/testdata/rdata_rp_fromWire3.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_rp_fromWire3.spec
-###
-
-# RP RDATA, RDLEN=38
-0026
-# MAILBOX=root.example.com TEXT=rp-text.example.com
-04726f6f74076578616d706c6503636f6d00 0772702d74657874076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire4.spec b/src/lib/dns/tests/testdata/rdata_rp_fromWire4.spec
deleted file mode 100644
index 6f3abd1a3a..0000000000
--- a/src/lib/dns/tests/testdata/rdata_rp_fromWire4.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# RP-like RDATA but RDLEN is too long.
-#
-[custom]
-sections: rp
-[rp]
-rdlen: 40
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire4.wire b/src/lib/dns/tests/testdata/rdata_rp_fromWire4.wire
deleted file mode 100644
index 56c643e531..0000000000
--- a/src/lib/dns/tests/testdata/rdata_rp_fromWire4.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_rp_fromWire4.spec
-###
-
-# RP RDATA, RDLEN=40
-0028
-# MAILBOX=root.example.com TEXT=rp-text.example.com
-04726f6f74076578616d706c6503636f6d00 0772702d74657874076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire5.spec b/src/lib/dns/tests/testdata/rdata_rp_fromWire5.spec
deleted file mode 100644
index b8d5e29cc0..0000000000
--- a/src/lib/dns/tests/testdata/rdata_rp_fromWire5.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# RP-like RDATA but mailbox name is broken.
-#
-[custom]
-sections: rp
-[rp]
-mailbox: "01234567890123456789012345678901234567890123456789012345678901234"
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire5.wire b/src/lib/dns/tests/testdata/rdata_rp_fromWire5.wire
deleted file mode 100644
index 1127047130..0000000000
--- a/src/lib/dns/tests/testdata/rdata_rp_fromWire5.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_rp_fromWire5.spec
-###
-
-# RP RDATA, RDLEN=90
-005a
-# MAILBOX="01234567890123456789012345678901234567890123456789012345678901234" TEXT=rp-text.example.com
-432230313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233342200 0772702d74657874076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire6.spec b/src/lib/dns/tests/testdata/rdata_rp_fromWire6.spec
deleted file mode 100644
index e9e79f30f7..0000000000
--- a/src/lib/dns/tests/testdata/rdata_rp_fromWire6.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# RP-like RDATA but text name is broken.
-#
-[custom]
-sections: rp
-[rp]
-text: "01234567890123456789012345678901234567890123456789012345678901234"
diff --git a/src/lib/dns/tests/testdata/rdata_rp_fromWire6.wire b/src/lib/dns/tests/testdata/rdata_rp_fromWire6.wire
deleted file mode 100644
index 49aedc6593..0000000000
--- a/src/lib/dns/tests/testdata/rdata_rp_fromWire6.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_rp_fromWire6.spec
-###
-
-# RP RDATA, RDLEN=87
-0057
-# MAILBOX=root.example.com TEXT="01234567890123456789012345678901234567890123456789012345678901234"
-04726f6f74076578616d706c6503636f6d00 432230313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233342200
diff --git a/src/lib/dns/tests/testdata/rdata_rp_toWire1.spec b/src/lib/dns/tests/testdata/rdata_rp_toWire1.spec
deleted file mode 100644
index 948bd1ad5c..0000000000
--- a/src/lib/dns/tests/testdata/rdata_rp_toWire1.spec
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# A simplest form of RP for toWire test: all default parameters except rdlen,
-# which is to be omitted.
-#
-[custom]
-sections: rp
-[rp]
-rdlen: -1
diff --git a/src/lib/dns/tests/testdata/rdata_rp_toWire1.wire b/src/lib/dns/tests/testdata/rdata_rp_toWire1.wire
deleted file mode 100644
index dcadb154b9..0000000000
--- a/src/lib/dns/tests/testdata/rdata_rp_toWire1.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_rp_toWire1.spec
-###
-
-# RP RDATA
-
-# MAILBOX=root.example.com TEXT=rp-text.example.com
-04726f6f74076578616d706c6503636f6d00 0772702d74657874076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdata_rp_toWire2.spec b/src/lib/dns/tests/testdata/rdata_rp_toWire2.spec
deleted file mode 100644
index 09a7ddc255..0000000000
--- a/src/lib/dns/tests/testdata/rdata_rp_toWire2.spec
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# A simple form of RP: names could be compressed (but MUST NOT).
-# rdlen is omitted for the "to wire" test.
-#
-[custom]
-sections: name/1:name/2:rp
-[name/1]
-name: a.example.com
-[name/2]
-name: b.example.net
-[rp]
-rdlen: -1
-mailbox: root.example.com
-text: rp-text.example.net
diff --git a/src/lib/dns/tests/testdata/rdata_rp_toWire2.wire b/src/lib/dns/tests/testdata/rdata_rp_toWire2.wire
deleted file mode 100644
index 38057eff68..0000000000
--- a/src/lib/dns/tests/testdata/rdata_rp_toWire2.wire
+++ /dev/null
@@ -1,14 +0,0 @@
-###
-### This data file was auto-generated from rdata_rp_toWire2.spec
-###
-
-# DNS Name: a.example.com
-0161076578616d706c6503636f6d00
-
-# DNS Name: b.example.net
-0162076578616d706c65036e657400
-
-# RP RDATA
-
-# MAILBOX=root.example.com TEXT=rp-text.example.net
-04726f6f74076578616d706c6503636f6d00 0772702d74657874076578616d706c65036e657400
diff --git a/src/lib/dns/tests/testdata/rdata_srv_fromWire b/src/lib/dns/tests/testdata/rdata_srv_fromWire
deleted file mode 100644
index 0f1e4ec75a..0000000000
--- a/src/lib/dns/tests/testdata/rdata_srv_fromWire
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# various kinds of SRV RDATA stored in an input buffer
-#
-# RDLENGTH=21 bytes
-# 0 1
- 00 15
-# 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 20 1 2(bytes)
- 00 01 00 05 05 dc 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
-#
-# short length
-# 3 4
- 00 12
-# 5 6 7 8 9 30 1 2 3 4 5 6 7 8 9 40 1 2 3 4 5
- 00 01 00 05 05 dc 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
-#
-# length too long
-# 6 7
- 00 19
-#
-# 8 9 50 1 2 3 4 5 6 7 8 9 60 1 2 3 4 5 6 7 8
- 00 01 00 05 05 dc 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
-#
-#
-# incomplete target name
-# 9 70
- 00 12
-# 1 2 3 4 5 6 7 8 9 80 1 2 3 4 5 6 7 8
- 00 01 00 05 05 dc 01 61 07 65 78 61 6d 70 6c 65 03 63
-#
-#
-# Valid compressed target name: 'a' + pointer
-# 9 90
- 00 0a
-#
-# 1 2 3 4 5 6 7 8 9 100
- 00 01 00 05 05 dc 01 61 c0 0a
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire
deleted file mode 100644
index added405ca..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire
+++ /dev/null
@@ -1,4 +0,0 @@
-# SSHFP RDATA, RDLEN=22
-0016
-# ALGORITHM=2 FINGERPRINT_TYPE=1 FINGERPRINT=123456789abcdef67890123456789abcdef67890
-02 01 123456789abcdef67890123456789abcdef67890
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire1.spec b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire1.spec
deleted file mode 100644
index e28a62fb0f..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire1.spec
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# A simplest form of SSHFP: all default parameters
-#
-[custom]
-sections: sshfp
-[sshfp]
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire1.wire b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire1.wire
deleted file mode 100644
index c7059e1452..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire1.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_sshfp_fromWire1.spec
-###
-
-# SSHFP RDATA, RDLEN=22
-0016
-# ALGORITHM=2 FINGERPRINT_TYPE=1 FINGERPRINT=123456789abcdef67890123456789abcdef67890
-02 01 123456789abcdef67890123456789abcdef67890
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire10 b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire10
deleted file mode 100644
index 220e570563..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire10
+++ /dev/null
@@ -1,6 +0,0 @@
-# Test where fingerprint is missing
-
-# SSHFP RDATA, RDLEN=32
-0020
-# ALGORITHM=2 FINGERPRINT_TYPE=1 FINGERPRINT=(none)
-02 01
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire11 b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire11
deleted file mode 100644
index a2f86368e1..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire11
+++ /dev/null
@@ -1,4 +0,0 @@
-# Test where RDATA is completely missing
-
-# SSHFP RDATA, RDLEN=32
-0020
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire12 b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire12
deleted file mode 100644
index eabd06b97f..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire12
+++ /dev/null
@@ -1,4 +0,0 @@
-# SSHFP RDATA, RDLEN=02
-0002
-# ALGORITHM=4 FINGERPRINT_TYPE=9
-04 09
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire2 b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire2
deleted file mode 100644
index a695548fbb..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire2
+++ /dev/null
@@ -1,4 +0,0 @@
-# SSHFP RDATA, RDLEN=22
-0016
-# ALGORITHM=2 FINGERPRINT_TYPE=1 FINGERPRINT=123456789ABCDEF67890123456789abcdef67890
-02 01 123456789ABCDEF67890123456789abcdef67890
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire2.spec b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire2.spec
deleted file mode 100644
index 59a336e592..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire2.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# SSHFP RDATA
-#
-[custom]
-sections: sshfp
-[sshfp]
-fingerprint: 123456789abcdef67890123456789abcdef67890
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire2.wire b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire2.wire
deleted file mode 100644
index e492316027..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire2.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_sshfp_fromWire2.spec
-###
-
-# SSHFP RDATA, RDLEN=22
-0016
-# ALGORITHM=2 FINGERPRINT_TYPE=1 FINGERPRINT=123456789abcdef67890123456789abcdef67890
-02 01 123456789abcdef67890123456789abcdef67890
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire3.spec b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire3.spec
deleted file mode 100644
index d111afde9a..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire3.spec
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# SSHFP RDATA
-#
-[custom]
-sections: sshfp
-[sshfp]
-algorithm: 1
-fingerprint_type: 1
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire3.wire b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire3.wire
deleted file mode 100644
index daa102f483..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire3.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_sshfp_fromWire3.spec
-###
-
-# SSHFP RDATA, RDLEN=22
-0016
-# ALGORITHM=1 FINGERPRINT_TYPE=1 FINGERPRINT=123456789abcdef67890123456789abcdef67890
-01 01 123456789abcdef67890123456789abcdef67890
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire4.spec b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire4.spec
deleted file mode 100644
index b9b2658b1a..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire4.spec
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# SSHFP RDATA
-#
-[custom]
-sections: sshfp
-[sshfp]
-algorithm: 255
-fingerprint_type: 1
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire4.wire b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire4.wire
deleted file mode 100644
index f05faad9d4..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire4.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_sshfp_fromWire4.spec
-###
-
-# SSHFP RDATA, RDLEN=22
-0016
-# ALGORITHM=255 FINGERPRINT_TYPE=1 FINGERPRINT=123456789abcdef67890123456789abcdef67890
-ff 01 123456789abcdef67890123456789abcdef67890
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire5.spec b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire5.spec
deleted file mode 100644
index b3a19facf7..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire5.spec
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# SSHFP RDATA
-#
-[custom]
-sections: sshfp
-[sshfp]
-algorithm: 0
-fingerprint_type: 1
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire5.wire b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire5.wire
deleted file mode 100644
index ddc8edb57e..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire5.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_sshfp_fromWire5.spec
-###
-
-# SSHFP RDATA, RDLEN=22
-0016
-# ALGORITHM=0 FINGERPRINT_TYPE=1 FINGERPRINT=123456789abcdef67890123456789abcdef67890
-00 01 123456789abcdef67890123456789abcdef67890
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire6.spec b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire6.spec
deleted file mode 100644
index 437e282c6c..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire6.spec
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# SSHFP RDATA
-#
-[custom]
-sections: sshfp
-[sshfp]
-algorithm: 5
-fingerprint_type: 0
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire6.wire b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire6.wire
deleted file mode 100644
index d4e591e4b7..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire6.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_sshfp_fromWire6.spec
-###
-
-# SSHFP RDATA, RDLEN=22
-0016
-# ALGORITHM=5 FINGERPRINT_TYPE=0 FINGERPRINT=123456789abcdef67890123456789abcdef67890
-05 00 123456789abcdef67890123456789abcdef67890
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire7.spec b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire7.spec
deleted file mode 100644
index 8e21d11026..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire7.spec
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# SSHFP RDATA
-#
-[custom]
-sections: sshfp
-[sshfp]
-algorithm: 255
-fingerprint_type: 255
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire7.wire b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire7.wire
deleted file mode 100644
index c8b9d8b2e6..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire7.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_sshfp_fromWire7.spec
-###
-
-# SSHFP RDATA, RDLEN=22
-0016
-# ALGORITHM=255 FINGERPRINT_TYPE=255 FINGERPRINT=123456789abcdef67890123456789abcdef67890
-ff ff 123456789abcdef67890123456789abcdef67890
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire8.spec b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire8.spec
deleted file mode 100644
index 98aa00f97b..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire8.spec
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# SSHFP RDATA
-#
-[custom]
-sections: sshfp
-[sshfp]
-fingerprint: 082359342fd9
-algorithm: 255
-fingerprint_type: 255
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire8.wire b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire8.wire
deleted file mode 100644
index 32cede87e5..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire8.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_sshfp_fromWire8.spec
-###
-
-# SSHFP RDATA, RDLEN=8
-0008
-# ALGORITHM=255 FINGERPRINT_TYPE=255 FINGERPRINT=082359342fd9
-ff ff 082359342fd9
diff --git a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire9 b/src/lib/dns/tests/testdata/rdata_sshfp_fromWire9
deleted file mode 100644
index 05fc80684b..0000000000
--- a/src/lib/dns/tests/testdata/rdata_sshfp_fromWire9
+++ /dev/null
@@ -1,6 +0,0 @@
-# Test where fingerprint length is smaller than what RDATA len indicates
-
-# SSHFP RDATA, RDLEN=32
-0020
-# ALGORITHM=2 FINGERPRINT_TYPE=1 FINGERPRINT=123456789abcdef67890123456789abcdef67890
-02 01 123456789abcdef67890123456789abcdef67890
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire
deleted file mode 100644
index 38e279ceca..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire
+++ /dev/null
@@ -1,4 +0,0 @@
-# TLSA RDATA, RDLEN=35
-0023
-# CERTIFICATE_USAGE=0 SELECTOR=0 MATCHING_TYPE=1 CERTIFICATE_ASSOCIATION_DATA=...
-00 00 01 d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire10 b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire10
deleted file mode 100644
index 67cecb15de..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire10
+++ /dev/null
@@ -1,6 +0,0 @@
-# Test where certificate association data is missing.
-
-# TLSA RDATA, RDLEN=35
-0023
-# CERTIFICATE_USAGE=0 SELECTOR=0 MATCHING_TYPE=1 CERTIFICATE_ASSOCIATION_DATA=(missing)
-00 00 01
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire11 b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire11
deleted file mode 100644
index 4b8ec930e2..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire11
+++ /dev/null
@@ -1,4 +0,0 @@
-# Test where RDATA is completely missing
-
-# TLSA RDATA, RDLEN=35
-0023
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire12 b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire12
deleted file mode 100644
index 71c7b9ceb5..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire12
+++ /dev/null
@@ -1,4 +0,0 @@
-# TLSA RDATA, RDLEN=3
-0003
-# CERTIFICATE_USAGE=0 SELECTOR=0 MATCHING_TYPE=1 CERTIFICATE_ASSOCIATION_DATA=(none)
-03 01 02
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire2 b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire2
deleted file mode 100644
index 36ce27806f..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire2
+++ /dev/null
@@ -1,4 +0,0 @@
-# TLSA RDATA, RDLEN=35
-0023
-# CERTIFICATE_USAGE=0 SELECTOR=0 MATCHING_TYPE=1 CERTIFICATE_ASSOCIATION_DATA=...
-00 00 01 d2abde240d7cd3ee6b4b28c54df034b97983A1D16E8A410E4561CB106618E971
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire3.spec b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire3.spec
deleted file mode 100644
index 39c8057d6a..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire3.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# TLSA RDATA
-#
-[custom]
-sections: tlsa
-[tlsa]
-certificate_usage: 0
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire3.wire b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire3.wire
deleted file mode 100644
index 6a8b552af2..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire3.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_tlsa_fromWire3.spec
-###
-
-# TLSA RDATA, RDLEN=34
-0022
-# CERTIFICATE_USAGE=0 SELECTOR=0 MATCHING_TYPE=1 CERTIFICATE_ASSOCIATION_DATA=d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971
-00 00 01 d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire4.spec b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire4.spec
deleted file mode 100644
index d97ae6a9e8..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire4.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# TLSA RDATA
-#
-[custom]
-sections: tlsa
-[tlsa]
-certificate_usage: 255
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire4.wire b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire4.wire
deleted file mode 100644
index b5a39c85be..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire4.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_tlsa_fromWire4.spec
-###
-
-# TLSA RDATA, RDLEN=34
-0022
-# CERTIFICATE_USAGE=255 SELECTOR=0 MATCHING_TYPE=1 CERTIFICATE_ASSOCIATION_DATA=d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971
-ff 00 01 d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire5.spec b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire5.spec
deleted file mode 100644
index cc3e296b84..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire5.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# TLSA RDATA
-#
-[custom]
-sections: tlsa
-[tlsa]
-selector: 255
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire5.wire b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire5.wire
deleted file mode 100644
index b79f97d93c..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire5.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_tlsa_fromWire5.spec
-###
-
-# TLSA RDATA, RDLEN=34
-0022
-# CERTIFICATE_USAGE=0 SELECTOR=255 MATCHING_TYPE=1 CERTIFICATE_ASSOCIATION_DATA=d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971
-00 ff 01 d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire6.spec b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire6.spec
deleted file mode 100644
index eed0ab90a6..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire6.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# TLSA RDATA
-#
-[custom]
-sections: tlsa
-[tlsa]
-matching_type: 255
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire6.wire b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire6.wire
deleted file mode 100644
index 02afe27fd1..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire6.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_tlsa_fromWire6.spec
-###
-
-# TLSA RDATA, RDLEN=34
-0022
-# CERTIFICATE_USAGE=0 SELECTOR=0 MATCHING_TYPE=255 CERTIFICATE_ASSOCIATION_DATA=d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971
-00 00 ff d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire7.spec b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire7.spec
deleted file mode 100644
index 576df1ef36..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire7.spec
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# TLSA RDATA
-#
-[custom]
-sections: tlsa
-[tlsa]
-certificate_usage: 3
-selector: 1
-matching_type: 2
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire7.wire b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire7.wire
deleted file mode 100644
index e5c23a4e1f..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire7.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_tlsa_fromWire7.spec
-###
-
-# TLSA RDATA, RDLEN=34
-0022
-# CERTIFICATE_USAGE=3 SELECTOR=1 MATCHING_TYPE=2 CERTIFICATE_ASSOCIATION_DATA=d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971
-03 01 02 d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire8.spec b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire8.spec
deleted file mode 100644
index ef5c108dff..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire8.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# TLSA RDATA
-#
-[custom]
-sections: tlsa
-[tlsa]
-certificate_association_data: '0123'
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire8.wire b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire8.wire
deleted file mode 100644
index dc29a0bee5..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire8.wire
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### This data file was auto-generated from rdata_tlsa_fromWire8.spec
-###
-
-# TLSA RDATA, RDLEN=4
-0004
-# CERTIFICATE_USAGE=0 SELECTOR=0 MATCHING_TYPE=1 CERTIFICATE_ASSOCIATION_DATA=0123
-00 00 01 0123
diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire9 b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire9
deleted file mode 100644
index fc4560af51..0000000000
--- a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire9
+++ /dev/null
@@ -1,7 +0,0 @@
-# Test where certificate association data length is smaller than what
-# RDATA length indicates.
-
-# TLSA RDATA, RDLEN=64
-0040
-# CERTIFICATE_USAGE=0 SELECTOR=0 MATCHING_TYPE=1 CERTIFICATE_ASSOCIATION_DATA=(32 bytes)
-00 00 01 d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971
diff --git a/src/lib/dns/tests/testdata/rdatafields1.spec b/src/lib/dns/tests/testdata/rdatafields1.spec
deleted file mode 100644
index 6e105fbe6c..0000000000
--- a/src/lib/dns/tests/testdata/rdatafields1.spec
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# A sequence of names that could be compressed (but not compressed)
-#
-
-[custom]
-sections: name/1:name/2
-[name/1]
-name: www.example.com
-[name/2]
-name: example.com
diff --git a/src/lib/dns/tests/testdata/rdatafields1.wire b/src/lib/dns/tests/testdata/rdatafields1.wire
deleted file mode 100644
index 42028c167d..0000000000
--- a/src/lib/dns/tests/testdata/rdatafields1.wire
+++ /dev/null
@@ -1,9 +0,0 @@
-###
-### This data file was auto-generated from rdatafields1.spec
-###
-
-# DNS Name: www.example.com
-03777777076578616d706c6503636f6d00
-
-# DNS Name: example.com
-076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdatafields2.spec b/src/lib/dns/tests/testdata/rdatafields2.spec
deleted file mode 100644
index 920dc956e6..0000000000
--- a/src/lib/dns/tests/testdata/rdatafields2.spec
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# A sequence of names that can be compressed.
-#
-
-[custom]
-sections: name/1:name/2
-[name/1]
-name: www.example.com
-[name/2]
-name: ''
-pointer: 4
diff --git a/src/lib/dns/tests/testdata/rdatafields2.wire b/src/lib/dns/tests/testdata/rdatafields2.wire
deleted file mode 100644
index cbb0ce0685..0000000000
--- a/src/lib/dns/tests/testdata/rdatafields2.wire
+++ /dev/null
@@ -1,9 +0,0 @@
-###
-### This data file was auto-generated from rdatafields2.spec
-###
-
-# DNS Name: www.example.com
-03777777076578616d706c6503636f6d00
-
-# DNS Name: + compression pointer: 4
-c004
diff --git a/src/lib/dns/tests/testdata/rdatafields3.spec b/src/lib/dns/tests/testdata/rdatafields3.spec
deleted file mode 100644
index b37fca3483..0000000000
--- a/src/lib/dns/tests/testdata/rdatafields3.spec
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# TXT RDATA with multiple character-strings.
-#
-
-[custom]
-sections: txt
-[txt]
-nstring: 3
-string0: 'first string'
-string1: 'second string'
-string2: 'last string'
diff --git a/src/lib/dns/tests/testdata/rdatafields3.wire b/src/lib/dns/tests/testdata/rdatafields3.wire
deleted file mode 100644
index 3ff32f1692..0000000000
--- a/src/lib/dns/tests/testdata/rdatafields3.wire
+++ /dev/null
@@ -1,12 +0,0 @@
-###
-### This data file was auto-generated from rdatafields3.spec
-###
-
-# TXT RDATA, RDLEN=39
-0027
-# String Len=12, String="first string"
-0c 666972737420737472696e67
-# String Len=13, String="second string"
-0d 7365636f6e6420737472696e67
-# String Len=11, String="last string"
-0b 6c61737420737472696e67
diff --git a/src/lib/dns/tests/testdata/rdatafields4.spec b/src/lib/dns/tests/testdata/rdatafields4.spec
deleted file mode 100644
index 24b59aaeb3..0000000000
--- a/src/lib/dns/tests/testdata/rdatafields4.spec
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Simple form of RRSIG (all fields use the default of generator script)
-#
-
-[custom]
-sections: rrsig
-[rrsig]
diff --git a/src/lib/dns/tests/testdata/rdatafields4.wire b/src/lib/dns/tests/testdata/rdatafields4.wire
deleted file mode 100644
index e5744266c9..0000000000
--- a/src/lib/dns/tests/testdata/rdatafields4.wire
+++ /dev/null
@@ -1,12 +0,0 @@
-###
-### This data file was auto-generated from rdatafields4.spec
-###
-
-# RRSIG RDATA, RDLEN=46
-002e
-# Covered=A(1) Algorithm=RSASHA1(5) Labels=2 OrigTTL=3600
-0001 05 02 00000e10
-# Expiration=1264935600, Inception=1262343600
-4b6562b0 4b3dd5b0
-# Tag=4149 Signer=example.com and Signature
-1035 076578616d706c6503636f6d00 123456789abcdef123456789abcdef
diff --git a/src/lib/dns/tests/testdata/rdatafields5.spec b/src/lib/dns/tests/testdata/rdatafields5.spec
deleted file mode 100644
index 2c7828250e..0000000000
--- a/src/lib/dns/tests/testdata/rdatafields5.spec
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Names and RDATA (RRSIG) with an incompressible name. All names are
-# rendered without compression.
-#
-
-[custom]
-sections: name/1:rrsig:name/2
-[name/1]
-name: com
-[rrsig]
-[name/2]
-name: www.example.com
diff --git a/src/lib/dns/tests/testdata/rdatafields5.wire b/src/lib/dns/tests/testdata/rdatafields5.wire
deleted file mode 100644
index d0cebc97d5..0000000000
--- a/src/lib/dns/tests/testdata/rdatafields5.wire
+++ /dev/null
@@ -1,18 +0,0 @@
-###
-### This data file was auto-generated from rdatafields5.spec
-###
-
-# DNS Name: com
-03636f6d00
-
-# RRSIG RDATA, RDLEN=46
-002e
-# Covered=A(1) Algorithm=RSASHA1(5) Labels=2 OrigTTL=3600
-0001 05 02 00000e10
-# Expiration=1264935600, Inception=1262343600
-4b6562b0 4b3dd5b0
-# Tag=4149 Signer=example.com and Signature
-1035 076578616d706c6503636f6d00 123456789abcdef123456789abcdef
-
-# DNS Name: www.example.com
-03777777076578616d706c6503636f6d00
diff --git a/src/lib/dns/tests/testdata/rdatafields6.spec b/src/lib/dns/tests/testdata/rdatafields6.spec
deleted file mode 100644
index f9f0da18f7..0000000000
--- a/src/lib/dns/tests/testdata/rdatafields6.spec
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# Names and RDATA (RRSIG) with an incompressible name. The name in RRSIG
-# isn't compressed, but it's used as the compression target.
-#
-
-[custom]
-sections: name/1:rrsig:name/2
-[name/1]
-name: com
-[rrsig]
-[name/2]
-name: www
-pointer: 25
diff --git a/src/lib/dns/tests/testdata/rdatafields6.wire b/src/lib/dns/tests/testdata/rdatafields6.wire
deleted file mode 100644
index 0e8b3d9001..0000000000
--- a/src/lib/dns/tests/testdata/rdatafields6.wire
+++ /dev/null
@@ -1,18 +0,0 @@
-###
-### This data file was auto-generated from rdatafields6.spec
-###
-
-# DNS Name: com
-03636f6d00
-
-# RRSIG RDATA, RDLEN=46
-002e
-# Covered=A(1) Algorithm=RSASHA1(5) Labels=2 OrigTTL=3600
-0001 05 02 00000e10
-# Expiration=1264935600, Inception=1262343600
-4b6562b0 4b3dd5b0
-# Tag=4149 Signer=example.com and Signature
-1035 076578616d706c6503636f6d00 123456789abcdef123456789abcdef
-
-# DNS Name: www + compression pointer: 25
-03777777c019
diff --git a/src/lib/dns/tests/tsig_unittest.cc b/src/lib/dns/tests/tsig_unittest.cc
index 8b13789179..ca2a28c68e 100644
--- a/src/lib/dns/tests/tsig_unittest.cc
+++ b/src/lib/dns/tests/tsig_unittest.cc
@@ -1 +1,1181 @@
+// Copyright (C) 2011-2024 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <time.h>
+#include <string>
+#include <stdexcept>
+#include <vector>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <gtest/gtest.h>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <util/encode/encode.h>
+#include <util/unittests/newhook.h>
+#include <util/time_utilities.h>
+
+#include <dns/message.h>
+#include <dns/messagerenderer.h>
+#include <dns/question.h>
+#include <dns/opcode.h>
+#include <dns/rcode.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/tsig.h>
+#include <dns/tsigkey.h>
+#include <dns/tsigrecord.h>
+
+#include <dns/tests/unittest_util.h>
+#include <util/unittests/wiredata.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::util::encode;
+using namespace isc::dns::rdata;
+using namespace isc::dns::rdata::any;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+// @note: blocks and SCOPED_TRACE can make buggy cppchecks raise
+// a spurious syntax error...
+
+// See dnssectime.cc
+namespace isc {
+namespace util {
+namespace detail {
+extern int64_t (*gettimeFunction)();
+}
+}
+}
+
+namespace {
+// See dnssectime_unittest.cc
+template <int64_t NOW>
+int64_t
+testGetTime() {
+ return (NOW);
+}
+
+// Thin wrapper around TSIGContext to allow access to the
+// update method.
+class TestTSIGContext : public TSIGContext {
+public:
+ TestTSIGContext(const TSIGKey& key) :
+ TSIGContext(key) {
+ }
+ TestTSIGContext(const Name& key_name, const Name& algorithm_name,
+ const TSIGKeyRing& keyring) :
+ TSIGContext(key_name, algorithm_name, keyring) {
+ }
+ void update(const void* const data, size_t len) {
+ TSIGContext::update(data, len);
+ }
+};
+
+class TSIGTest : public ::testing::Test {
+protected:
+ TSIGTest() :
+ tsig_ctx(NULL), qid(0x2d65), test_name("www.example.com"),
+ badkey_name("badkey.example.com"), test_class(RRClass::IN()),
+ test_ttl(86400), message(Message::RENDER),
+ dummy_data(1024, 0xdd), // should be sufficiently large for all tests
+ dummy_record(badkey_name, TSIG(TSIGKey::HMACMD5_NAME(), 0x4da8877a,
+ TSIGContext::DEFAULT_FUDGE, 0, NULL, qid, 0, 0, NULL)) {
+ // Make sure we use the system time by default so that we won't be
+ // confused due to other tests that tweak the time.
+ isc::util::detail::gettimeFunction = NULL;
+
+ decodeBase64("SFuWd/q99SzF8Yzd1QbB9g==", secret);
+ tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACMD5_NAME(),
+ &secret[0],
+ secret.size())));
+ tsig_verify_ctx.reset(new TSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACMD5_NAME(),
+ &secret[0],
+ secret.size())));
+ }
+ ~TSIGTest() {
+ isc::util::detail::gettimeFunction = NULL;
+ }
+
+ // Many of the tests below create some DNS message and sign it under
+ // some specific TSIG context. This helper method unifies the common
+ // logic with slightly different parameters.
+ ConstTSIGRecordPtr createMessageAndSign(uint16_t qid, const Name& qname,
+ TSIGContext* ctx,
+ unsigned int message_flags =
+ RD_FLAG,
+ RRType qtype = RRType::A(),
+ const char* answer_data = NULL,
+ const RRType* answer_type = NULL,
+ bool add_question = true,
+ Rcode rcode = Rcode::NOERROR());
+
+ void createMessageFromFile(const char* datafile);
+
+ // bit-wise constant flags to configure DNS header flags for test
+ // messages.
+ static const unsigned int QR_FLAG = 0x1;
+ static const unsigned int AA_FLAG = 0x2;
+ static const unsigned int RD_FLAG = 0x4;
+
+ boost::scoped_ptr<TestTSIGContext> tsig_ctx;
+ boost::scoped_ptr<TSIGContext> tsig_verify_ctx;
+ TSIGKeyRing keyring;
+ const uint16_t qid;
+ const Name test_name;
+ const Name badkey_name;
+ const RRClass test_class;
+ const RRTTL test_ttl;
+ Message message;
+ MessageRenderer renderer;
+ vector<uint8_t> secret;
+ vector<uint8_t> dummy_data;
+ const TSIGRecord dummy_record;
+ vector<uint8_t> received_data;
+};
+
+ConstTSIGRecordPtr
+TSIGTest::createMessageAndSign(uint16_t id, const Name& qname,
+ TSIGContext* ctx, unsigned int message_flags,
+ RRType qtype, const char* answer_data,
+ const RRType* answer_type, bool add_question,
+ Rcode rcode) {
+ message.clear(Message::RENDER);
+ message.setQid(id);
+ message.setOpcode(Opcode::QUERY());
+ message.setRcode(rcode);
+ if ((message_flags & QR_FLAG) != 0) {
+ message.setHeaderFlag(Message::HEADERFLAG_QR);
+ }
+ if ((message_flags & AA_FLAG) != 0) {
+ message.setHeaderFlag(Message::HEADERFLAG_AA);
+ }
+ if ((message_flags & RD_FLAG) != 0) {
+ message.setHeaderFlag(Message::HEADERFLAG_RD);
+ }
+ if (add_question) {
+ message.addQuestion(Question(qname, test_class, qtype));
+ }
+ if (answer_data != NULL) {
+ if (answer_type == NULL) {
+ answer_type = &qtype;
+ }
+ RRsetPtr answer_rrset(new RRset(qname, test_class, *answer_type,
+ test_ttl));
+ answer_rrset->addRdata(createRdata(*answer_type, test_class,
+ answer_data));
+ message.addRRset(Message::SECTION_ANSWER, answer_rrset);
+ }
+ renderer.clear();
+
+ TSIGContext::State expected_new_state =
+ (ctx->getState() == TSIGContext::INIT) ?
+ TSIGContext::SENT_REQUEST : TSIGContext::SENT_RESPONSE;
+
+ message.toWire(renderer, ctx);
+
+ message.clear(Message::PARSE);
+ InputBuffer buffer(renderer.getData(), renderer.getLength());
+ message.fromWire(buffer);
+
+ EXPECT_EQ(expected_new_state, ctx->getState());
+
+ return (ConstTSIGRecordPtr(new TSIGRecord(*message.getTSIGRecord())));
+}
+
+void
+TSIGTest::createMessageFromFile(const char* datafile) {
+ message.clear(Message::PARSE);
+ received_data.clear();
+ UnitTestUtil::readWireData(datafile, received_data);
+ InputBuffer buffer(&received_data[0], received_data.size());
+ message.fromWire(buffer);
+}
+
+void
+commonSignChecks(ConstTSIGRecordPtr tsig, uint16_t expected_qid,
+ uint64_t expected_timesigned,
+ const uint8_t* expected_mac, size_t expected_maclen,
+ uint16_t expected_error = 0,
+ uint16_t expected_otherlen = 0,
+ const uint8_t* expected_otherdata = NULL,
+ const Name& expected_algorithm = TSIGKey::HMACMD5_NAME()) {
+ ASSERT_TRUE(tsig != NULL);
+ const TSIG& tsig_rdata = tsig->getRdata();
+
+ EXPECT_EQ(expected_algorithm, tsig_rdata.getAlgorithm());
+ EXPECT_EQ(expected_timesigned, tsig_rdata.getTimeSigned());
+ EXPECT_EQ(300, tsig_rdata.getFudge());
+ EXPECT_EQ(expected_maclen, tsig_rdata.getMACSize());
+ matchWireData(expected_mac, expected_maclen,
+ tsig_rdata.getMAC(), tsig_rdata.getMACSize());
+
+ EXPECT_EQ(expected_qid, tsig_rdata.getOriginalID());
+ EXPECT_EQ(expected_error, tsig_rdata.getError());
+ EXPECT_EQ(expected_otherlen, tsig_rdata.getOtherLen());
+ matchWireData(expected_otherdata, expected_otherlen,
+ tsig_rdata.getOtherData(), tsig_rdata.getOtherLen());
+}
+
+void
+commonVerifyChecks(TSIGContext& ctx, const TSIGRecord* record,
+ const void* data, size_t data_len, TSIGError expected_error,
+ TSIGContext::State expected_new_state =
+ TSIGContext::VERIFIED_RESPONSE,
+ bool last_should_throw = false) {
+ EXPECT_EQ(expected_error, ctx.verify(record, data, data_len));
+ EXPECT_EQ(expected_error, ctx.getError());
+ EXPECT_EQ(expected_new_state, ctx.getState());
+ if (last_should_throw) {
+ EXPECT_THROW(ctx.lastHadSignature(), TSIGContextError);
+ } else {
+ EXPECT_EQ(record != NULL, ctx.lastHadSignature());
+ }
+}
+
+TEST_F(TSIGTest, initialState) {
+ // Until signing or verifying, the state should be INIT
+ EXPECT_EQ(TSIGContext::INIT, tsig_ctx->getState());
+
+ // And there should be no error code.
+ EXPECT_EQ(TSIGError(Rcode::NOERROR()), tsig_ctx->getError());
+
+ // Nothing verified yet
+ EXPECT_THROW(tsig_ctx->lastHadSignature(), TSIGContextError);
+}
+
+TEST_F(TSIGTest, constructFromKeyRing) {
+ // Construct a TSIG context with an empty key ring. Key shouldn't be
+ // found, and the BAD_KEY error should be recorded.
+ TSIGContext ctx1(test_name, TSIGKey::HMACMD5_NAME(), keyring);
+ EXPECT_EQ(TSIGContext::INIT, ctx1.getState());
+ EXPECT_EQ(TSIGError::BAD_KEY(), ctx1.getError());
+
+ // Add a matching key (we don't use the secret so leave it empty), and
+ // construct it again. This time it should be constructed with a valid
+ // key.
+ keyring.add(TSIGKey(test_name, TSIGKey::HMACMD5_NAME(), NULL, 0));
+ TSIGContext ctx2(test_name, TSIGKey::HMACMD5_NAME(), keyring);
+ EXPECT_EQ(TSIGContext::INIT, ctx2.getState());
+ EXPECT_EQ(TSIGError::NOERROR(), ctx2.getError());
+
+ // Similar to the first case except that the key ring isn't empty but
+ // it doesn't contain a matching key.
+ TSIGContext ctx3(test_name, TSIGKey::HMACSHA1_NAME(), keyring);
+ EXPECT_EQ(TSIGContext::INIT, ctx3.getState());
+ EXPECT_EQ(TSIGError::BAD_KEY(), ctx3.getError());
+
+ TSIGContext ctx4(Name("different-key.example"), TSIGKey::HMACMD5_NAME(),
+ keyring);
+ EXPECT_EQ(TSIGContext::INIT, ctx4.getState());
+ EXPECT_EQ(TSIGError::BAD_KEY(), ctx4.getError());
+
+ // "Unknown" algorithm name will result in BADKEY, too.
+ TSIGContext ctx5(test_name, Name("unknown.algorithm"), keyring);
+ EXPECT_EQ(TSIGContext::INIT, ctx5.getState());
+ EXPECT_EQ(TSIGError::BAD_KEY(), ctx5.getError());
+}
+
+// Example output generated by
+// "dig -y www.example.com:SFuWd/q99SzF8Yzd1QbB9g== www.example.com
+// QID: 0x2d65
+// Time Signed: 0x00004da8877a
+// MAC: 227026ad297beee721ce6c6fff1e9ef3
+const uint8_t common_expected_mac[] = {
+ 0x22, 0x70, 0x26, 0xad, 0x29, 0x7b, 0xee, 0xe7,
+ 0x21, 0xce, 0x6c, 0x6f, 0xff, 0x1e, 0x9e, 0xf3
+};
+TEST_F(TSIGTest, sign) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ {
+ SCOPED_TRACE("Sign test for query");
+ commonSignChecks(createMessageAndSign(qid, test_name, tsig_ctx.get()),
+ qid, 0x4da8877a, common_expected_mac,
+ sizeof(common_expected_mac));
+ }
+}
+
+// Same test as sign, but specifying the key name with upper-case (i.e.
+// non canonical) characters. The digest must be the same. It should actually
+// be ensured at the level of TSIGKey, but we confirm that at this level, too.
+TEST_F(TSIGTest, signUsingUpperCasedKeyName) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ TSIGContext cap_ctx(TSIGKey(Name("WWW.EXAMPLE.COM"),
+ TSIGKey::HMACMD5_NAME(),
+ &secret[0], secret.size()));
+
+ {
+ SCOPED_TRACE("Sign test for query using non canonical key name");
+ commonSignChecks(createMessageAndSign(qid, test_name, &cap_ctx), qid,
+ 0x4da8877a, common_expected_mac,
+ sizeof(common_expected_mac));
+ }
+}
+
+// Same as the previous test, but for the algorithm name.
+TEST_F(TSIGTest, signUsingUpperCasedAlgorithmName) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ TSIGContext cap_ctx(TSIGKey(test_name,
+ Name("HMAC-md5.SIG-alg.REG.int"),
+ &secret[0], secret.size()));
+
+ {
+ SCOPED_TRACE("Sign test for query using non canonical algorithm name");
+ commonSignChecks(createMessageAndSign(qid, test_name, &cap_ctx), qid,
+ 0x4da8877a, common_expected_mac,
+ sizeof(common_expected_mac));
+ }
+}
+
+TEST_F(TSIGTest, signAtActualTime) {
+ // Sign the message using the actual time, and check the accuracy of it.
+ // We cannot reasonably predict the expected MAC, so don't bother to
+ // check it.
+ const uint64_t now = static_cast<uint64_t>(time(NULL));
+
+ {
+ SCOPED_TRACE("Sign test for query at actual time");
+ ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+ tsig_ctx.get());
+ const TSIG& tsig_rdata = tsig->getRdata();
+
+ // Check the resulted time signed is in the range of [now, now + 5]
+ // (5 is an arbitrary choice). Note that due to the order of the call
+ // to time() and sign(), time signed must not be smaller than the
+ // current time.
+ EXPECT_LE(now, tsig_rdata.getTimeSigned());
+ EXPECT_GE(now + 5, tsig_rdata.getTimeSigned());
+ }
+}
+
+TEST_F(TSIGTest, signBadData) {
+ // some specific bad data should be rejected proactively.
+ const unsigned char dummy_data = 0;
+ EXPECT_THROW(tsig_ctx->sign(0, NULL, 10), InvalidParameter);
+ EXPECT_THROW(tsig_ctx->sign(0, &dummy_data, 0), InvalidParameter);
+}
+
+TEST_F(TSIGTest, verifyBadData) {
+ // the data must at least hold the DNS message header and the specified
+ // TSIG.
+ EXPECT_THROW(tsig_ctx->verify(&dummy_record, &dummy_data[0],
+ 12 + dummy_record.getLength() - 1),
+ InvalidParameter);
+
+ // Still nothing verified
+ EXPECT_THROW(tsig_ctx->lastHadSignature(), TSIGContextError);
+
+ // And the data must not be NULL.
+ EXPECT_THROW(tsig_ctx->verify(&dummy_record, NULL,
+ 12 + dummy_record.getLength()),
+ InvalidParameter);
+
+ // Still nothing verified
+ EXPECT_THROW(tsig_ctx->lastHadSignature(), TSIGContextError);
+
+}
+
+#ifdef ENABLE_CUSTOM_OPERATOR_NEW
+// We enable this test only when we enable custom new/delete at build time
+// We could enable/disable the test runtime using the gtest filter, but
+// we'd basically like to minimize the number of disabled tests (they
+// should generally be considered tests that temporarily fail and should
+// be fixed).
+TEST_F(TSIGTest, signExceptionSafety) {
+ // Check sign() provides the strong exception guarantee for the simpler
+ // case (with a key error and empty MAC). The general case is more
+ // complicated and involves more memory allocation, so the test result
+ // won't be reliable.
+
+ commonVerifyChecks(*tsig_verify_ctx, &dummy_record, &dummy_data[0],
+ dummy_data.size(), TSIGError::BAD_KEY(),
+ TSIGContext::RECEIVED_REQUEST);
+
+ try {
+ int dummydata;
+ isc::util::unittests::force_throw_on_new = true;
+ isc::util::unittests::throw_size_on_new = sizeof(TSIGRecord);
+ tsig_verify_ctx->sign(0, &dummydata, sizeof(dummydata));
+ isc::util::unittests::force_throw_on_new = false;
+ ASSERT_FALSE(true) << "Expected throw on new, but it didn't happen";
+ } catch (const std::bad_alloc&) {
+ isc::util::unittests::force_throw_on_new = false;
+
+ // sign() threw, so the state should still be RECEIVED_REQUEST
+ EXPECT_EQ(TSIGContext::RECEIVED_REQUEST, tsig_verify_ctx->getState());
+ }
+ isc::util::unittests::force_throw_on_new = false;
+}
+#endif // ENABLE_CUSTOM_OPERATOR_NEW
+
+// Same test as "sign" but use a different algorithm just to confirm we don't
+// naively hardcode constants specific to a particular algorithm.
+// Test data generated by
+// "dig -y hmac-sha1:www.example.com:MA+QDhXbyqUak+qnMFyTyEirzng= www.example.com"
+// QID: 0x0967, RDflag
+// Current Time: 00004da8be86
+// Time Signed: 00004dae7d5f
+// HMAC Size: 20
+// HMAC: 415340c7daf824ed684ee586f7b5a67a2febc0d3
+TEST_F(TSIGTest, signUsingHMACSHA1) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4dae7d5f>;
+
+ secret.clear();
+ decodeBase64("MA+QDhXbyqUak+qnMFyTyEirzng=", secret);
+ TSIGContext sha1_ctx(TSIGKey(test_name, TSIGKey::HMACSHA1_NAME(),
+ &secret[0], secret.size()));
+
+ const uint16_t sha1_qid = 0x0967;
+ const uint8_t expected_mac[] = {
+ 0x41, 0x53, 0x40, 0xc7, 0xda, 0xf8, 0x24, 0xed, 0x68, 0x4e,
+ 0xe5, 0x86, 0xf7, 0xb5, 0xa6, 0x7a, 0x2f, 0xeb, 0xc0, 0xd3
+ };
+ {
+ SCOPED_TRACE("Sign test using HMAC-SHA1");
+ commonSignChecks(createMessageAndSign(sha1_qid, test_name, &sha1_ctx),
+ sha1_qid, 0x4dae7d5f, expected_mac,
+ sizeof(expected_mac), 0, 0, NULL,
+ TSIGKey::HMACSHA1_NAME());
+ }
+}
+
+TEST_F(TSIGTest, signUsingHMACSHA224) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4dae7d5f>;
+
+ secret.clear();
+ decodeBase64("MA+QDhXbyqUak+qnMFyTyEirzng=", secret);
+ TSIGContext sha1_ctx(TSIGKey(test_name, TSIGKey::HMACSHA224_NAME(),
+ &secret[0], secret.size()));
+
+ const uint16_t sha1_qid = 0x0967;
+ const uint8_t expected_mac[] = {
+ 0x3b, 0x93, 0xd3, 0xc5, 0xf9, 0x64, 0xb9, 0xc5, 0x00, 0x35,
+ 0x02, 0x69, 0x9f, 0xfc, 0x44, 0xd6, 0xe2, 0x66, 0xf4, 0x08,
+ 0xef, 0x33, 0xa2, 0xda, 0xa1, 0x48, 0x71, 0xd3
+ };
+ {
+ SCOPED_TRACE("Sign test using HMAC-SHA224");
+ commonSignChecks(createMessageAndSign(sha1_qid, test_name, &sha1_ctx),
+ sha1_qid, 0x4dae7d5f, expected_mac,
+ sizeof(expected_mac), 0, 0, NULL,
+ TSIGKey::HMACSHA224_NAME());
+ }
+}
+
+// The first part of this test checks verifying the signed query used for
+// the "sign" test.
+// The second part of this test generates a signed response to the signed
+// query as follows:
+// Answer: www.example.com. 86400 IN A 192.0.2.1
+// MAC: 8fcda66a7cd1a3b9948eb1869d384a9f
+TEST_F(TSIGTest, verifyThenSignResponse) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ // This test data for the message test has the same wire format data
+ // as the message used in the "sign" test.
+ createMessageFromFile("message_toWire2.wire");
+ {
+ SCOPED_TRACE("Verify test for request");
+ commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::NOERROR(), TSIGContext::RECEIVED_REQUEST);
+ }
+
+ // Transform the original message to a response, then sign the response
+ // with the context of "verified state".
+ ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+ tsig_verify_ctx.get(),
+ QR_FLAG|AA_FLAG|RD_FLAG,
+ RRType::A(), "192.0.2.1");
+ const uint8_t expected_mac[] = {
+ 0x8f, 0xcd, 0xa6, 0x6a, 0x7c, 0xd1, 0xa3, 0xb9,
+ 0x94, 0x8e, 0xb1, 0x86, 0x9d, 0x38, 0x4a, 0x9f
+ };
+ {
+ SCOPED_TRACE("Sign test for response");
+ commonSignChecks(tsig, qid, 0x4da8877a, expected_mac,
+ sizeof(expected_mac));
+ }
+}
+
+TEST_F(TSIGTest, verifyUpperCaseNames) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ // This test data for the message test has the same wire format data
+ // as the message used in the "sign" test.
+ createMessageFromFile("tsig_verify9.wire");
+ {
+ SCOPED_TRACE("Verify test for request");
+ commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::NOERROR(), TSIGContext::RECEIVED_REQUEST);
+ }
+}
+
+TEST_F(TSIGTest, verifyForwardedMessage) {
+ // Similar to the first part of the previous test, but this test emulates
+ // the "forward" case, where the ID of the Header and the original ID in
+ // TSIG is different.
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ createMessageFromFile("tsig_verify6.wire");
+ {
+ SCOPED_TRACE("Verify test for forwarded request");
+ commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::NOERROR(), TSIGContext::RECEIVED_REQUEST);
+ }
+}
+
+// Example of signing multiple messages in a single TCP stream,
+// taken from data using BIND 9's "one-answer" transfer-format.
+// Request:
+// QID: 0x3410, flags (none)
+// Question: example.com/IN/AXFR
+// Time Signed: 0x4da8e951
+// MAC: 35b2fd08268781634400c7c8a5533b13
+// First message:
+// QID: 0x3410, flags QR, AA
+// Question: example.com/IN/AXFR
+// Answer: example.com. 86400 IN SOA ns.example.com. root.example.com. (
+// 2011041503 7200 3600 2592000 1200)
+// MAC: bdd612cd2c7f9e0648bd6dc23713e83c
+// Second message:
+// Answer: example.com. 86400 IN NS ns.example.com.
+// MAC: 102458f7f62ddd7d638d746034130968
+TEST_F(TSIGTest, signContinuation) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8e951>;
+
+ const uint16_t axfr_qid = 0x3410;
+ const Name zone_name("example.com");
+
+ // Create and sign the AXFR request
+ ConstTSIGRecordPtr tsig = createMessageAndSign(axfr_qid, zone_name,
+ tsig_ctx.get(), 0,
+ RRType(252));
+ // Then verify it (the wire format test data should contain the same
+ // message data, and verification should succeed).
+ received_data.clear();
+ UnitTestUtil::readWireData("tsig_verify1.wire", received_data);
+ {
+ SCOPED_TRACE("Verify AXFR query");
+ commonVerifyChecks(*tsig_verify_ctx, tsig.get(), &received_data[0],
+ received_data.size(), TSIGError::NOERROR(),
+ TSIGContext::RECEIVED_REQUEST);
+ }
+
+ // Create and sign the first response message
+ tsig = createMessageAndSign(axfr_qid, zone_name, tsig_verify_ctx.get(),
+ AA_FLAG|QR_FLAG, RRType(252),
+ "ns.example.com. root.example.com. "
+ "2011041503 7200 3600 2592000 1200",
+ &RRType::SOA());
+
+ // Then verify it at the requester side.
+ received_data.clear();
+ UnitTestUtil::readWireData("tsig_verify2.wire", received_data);
+ {
+ SCOPED_TRACE("Verify first AXFR response");
+ commonVerifyChecks(*tsig_ctx, tsig.get(), &received_data[0],
+ received_data.size(), TSIGError::NOERROR());
+ }
+
+ // Create and sign the second response message
+ const uint8_t expected_mac[] = {
+ 0x10, 0x24, 0x58, 0xf7, 0xf6, 0x2d, 0xdd, 0x7d,
+ 0x63, 0x8d, 0x74, 0x60, 0x34, 0x13, 0x09, 0x68
+ };
+ {
+ SCOPED_TRACE("Sign test for continued response in TCP stream");
+ tsig = createMessageAndSign(axfr_qid, zone_name, tsig_verify_ctx.get(),
+ AA_FLAG|QR_FLAG, RRType(252),
+ "ns.example.com.", &RRType::NS(), false);
+ commonSignChecks(tsig, axfr_qid, 0x4da8e951, expected_mac,
+ sizeof(expected_mac));
+ }
+
+ // Then verify it at the requester side.
+ received_data.clear();
+ UnitTestUtil::readWireData("tsig_verify3.wire", received_data);
+ {
+ SCOPED_TRACE("Verify second AXFR response");
+ commonVerifyChecks(*tsig_ctx, tsig.get(), &received_data[0],
+ received_data.size(), TSIGError::NOERROR());
+ }
+}
+
+// BADTIME example, taken from data using specially hacked BIND 9's nsupdate
+// Query:
+// QID: 0x1830, RD flag
+// Current Time: 00004da8be86
+// Time Signed: 00004da8b9d6
+// Question: www.example.com/IN/SOA
+//(mac) 8406 7d50 b8e7 d054 3d50 5bd9 de2a bb68
+// Response:
+// QRbit, RCODE=9(NOTAUTH)
+// Time Signed: 00004da8b9d6 (the one in the query)
+// MAC: d4b043f6f44495ec8a01260e39159d76
+// Error: 0x12 (BADTIME), Other Len: 6
+// Other data: 00004da8be86
+TEST_F(TSIGTest, badtimeResponse) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6>;
+
+ const uint16_t test_qid = 0x7fc4;
+ ConstTSIGRecordPtr tsig = createMessageAndSign(test_qid, test_name,
+ tsig_ctx.get(), 0,
+ RRType::SOA());
+
+ // "advance the clock" and try validating, which should fail due to BADTIME
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8be86>;
+ {
+ SCOPED_TRACE("Verify resulting in BADTIME due to expired SIG");
+ commonVerifyChecks(*tsig_verify_ctx, tsig.get(), &dummy_data[0],
+ dummy_data.size(), TSIGError::BAD_TIME(),
+ TSIGContext::RECEIVED_REQUEST);
+ }
+
+ // make and sign a response in the context of TSIG error.
+ tsig = createMessageAndSign(test_qid, test_name, tsig_verify_ctx.get(),
+ QR_FLAG, RRType::SOA(), NULL, NULL,
+ true, Rcode::NOTAUTH());
+ const uint8_t expected_otherdata[] = { 0, 0, 0x4d, 0xa8, 0xbe, 0x86 };
+ const uint8_t expected_mac[] = {
+ 0xd4, 0xb0, 0x43, 0xf6, 0xf4, 0x44, 0x95, 0xec,
+ 0x8a, 0x01, 0x26, 0x0e, 0x39, 0x15, 0x9d, 0x76
+ };
+ {
+ SCOPED_TRACE("Sign test for response with BADTIME");
+ commonSignChecks(tsig, message.getQid(), 0x4da8b9d6,
+ expected_mac, sizeof(expected_mac),
+ 18, // error: BADTIME
+ sizeof(expected_otherdata),
+ expected_otherdata);
+ }
+}
+
+TEST_F(TSIGTest, badtimeResponse2) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6>;
+
+ ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+ tsig_ctx.get(), 0,
+ RRType::SOA());
+
+ // "rewind the clock" and try validating, which should fail due to BADTIME
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6 - 600>;
+ {
+ SCOPED_TRACE("Verify resulting in BADTIME due to too future SIG");
+ commonVerifyChecks(*tsig_verify_ctx, tsig.get(), &dummy_data[0],
+ dummy_data.size(), TSIGError::BAD_TIME(),
+ TSIGContext::RECEIVED_REQUEST);
+ }
+}
+
+TEST_F(TSIGTest, badtimeBoundaries) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6>;
+
+ // Test various boundary conditions. We intentionally use the magic
+ // number of 300 instead of the constant variable for testing.
+ // In the okay cases, signature is not correct, but it's sufficient to
+ // check the error code isn't BADTIME for the purpose of this test.
+ ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+ tsig_ctx.get(), 0,
+ RRType::SOA());
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6 + 301>;
+ EXPECT_EQ(TSIGError::BAD_TIME(),
+ tsig_verify_ctx->verify(tsig.get(), &dummy_data[0],
+ dummy_data.size()));
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6 + 300>;
+ EXPECT_NE(TSIGError::BAD_TIME(),
+ tsig_verify_ctx->verify(tsig.get(), &dummy_data[0],
+ dummy_data.size()));
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6 - 301>;
+ EXPECT_EQ(TSIGError::BAD_TIME(),
+ tsig_verify_ctx->verify(tsig.get(), &dummy_data[0],
+ dummy_data.size()));
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6 - 300>;
+ EXPECT_NE(TSIGError::BAD_TIME(),
+ tsig_verify_ctx->verify(tsig.get(), &dummy_data[0],
+ dummy_data.size()));
+}
+
+TEST_F(TSIGTest, badtimeOverflow) {
+ isc::util::detail::gettimeFunction = testGetTime<200>;
+ ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+ tsig_ctx.get(), 0,
+ RRType::SOA());
+
+ // This should be in the okay range, but since "200 - fudge" overflows
+ // and we compare them as 64-bit unsigned integers, it results in a false
+ // positive (we intentionally accept that).
+ isc::util::detail::gettimeFunction = testGetTime<100>;
+ EXPECT_EQ(TSIGError::BAD_TIME(),
+ tsig_verify_ctx->verify(tsig.get(), &dummy_data[0],
+ dummy_data.size()));
+}
+
+TEST_F(TSIGTest, badsigResponse) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ // Try to sign a simple message with bogus secret. It should fail
+ // with BADSIG.
+ createMessageFromFile("message_toWire2.wire");
+ TSIGContext bad_ctx(TSIGKey(test_name, TSIGKey::HMACMD5_NAME(),
+ &dummy_data[0], dummy_data.size()));
+ {
+ SCOPED_TRACE("Verify resulting in BADSIG");
+ commonVerifyChecks(bad_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::BAD_SIG(), TSIGContext::RECEIVED_REQUEST);
+ }
+
+ // Sign the same message (which doesn't matter for this test) with the
+ // context of "checked state".
+ {
+ SCOPED_TRACE("Sign test for response with BADSIG error");
+ commonSignChecks(createMessageAndSign(qid, test_name, &bad_ctx),
+ message.getQid(), 0x4da8877a, NULL, 0,
+ 16); // 16: BADSIG
+ }
+}
+
+TEST_F(TSIGTest, badkeyResponse) {
+ // A similar test as badsigResponse but for BADKEY
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ tsig_ctx.reset(new TestTSIGContext(badkey_name, TSIGKey::HMACMD5_NAME(),
+ keyring));
+ {
+ SCOPED_TRACE("Verify resulting in BADKEY");
+ commonVerifyChecks(*tsig_ctx, &dummy_record, &dummy_data[0],
+ dummy_data.size(), TSIGError::BAD_KEY(),
+ TSIGContext::RECEIVED_REQUEST);
+ }
+
+ {
+ SCOPED_TRACE("Sign test for response with BADKEY error");
+ ConstTSIGRecordPtr sig = createMessageAndSign(qid, test_name,
+ tsig_ctx.get());
+ EXPECT_EQ(badkey_name, sig->getName());
+ commonSignChecks(sig, qid, 0x4da8877a, NULL, 0, 17); // 17: BADKEY
+ }
+}
+
+TEST_F(TSIGTest, badkeyForResponse) {
+ // "BADKEY" case for a response to a signed message
+ createMessageAndSign(qid, test_name, tsig_ctx.get());
+ {
+ SCOPED_TRACE("Verify a response resulting in BADKEY");
+ commonVerifyChecks(*tsig_ctx, &dummy_record, &dummy_data[0],
+ dummy_data.size(), TSIGError::BAD_KEY(),
+ TSIGContext::SENT_REQUEST);
+ }
+
+ // A similar case with a different algorithm
+ const TSIGRecord dummy_record2(test_name, TSIG(TSIGKey::HMACSHA1_NAME(),
+ 0x4da8877a,
+ TSIGContext::DEFAULT_FUDGE,
+ 0, NULL, qid, 0, 0, NULL));
+ {
+ SCOPED_TRACE("Verify a response resulting in BADKEY due to bad alg");
+ commonVerifyChecks(*tsig_ctx, &dummy_record2, &dummy_data[0],
+ dummy_data.size(), TSIGError::BAD_KEY(),
+ TSIGContext::SENT_REQUEST);
+ }
+}
+
+TEST_F(TSIGTest, badsigThenValidate) {
+ // According to RFC2845 4.6, if TSIG verification fails the client
+ // should discard that message and wait for another signed response.
+ // This test emulates that situation.
+
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ createMessageAndSign(qid, test_name, tsig_ctx.get());
+
+ createMessageFromFile("tsig_verify4.wire");
+ {
+ SCOPED_TRACE("Verify a response that should fail due to BADSIG");
+ commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::BAD_SIG(), TSIGContext::SENT_REQUEST);
+ }
+
+ createMessageFromFile("tsig_verify5.wire");
+ {
+ SCOPED_TRACE("Verify a response after a BADSIG failure");
+ commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::NOERROR(),
+ TSIGContext::VERIFIED_RESPONSE);
+ }
+}
+
+TEST_F(TSIGTest, nosigThenValidate) {
+ // Similar to the previous test, but the first response doesn't contain
+ // TSIG.
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ createMessageAndSign(qid, test_name, tsig_ctx.get());
+
+ {
+ SCOPED_TRACE("Verify a response without TSIG that should exist");
+ commonVerifyChecks(*tsig_ctx, NULL, &dummy_data[0],
+ dummy_data.size(), TSIGError::FORMERR(),
+ TSIGContext::SENT_REQUEST, true);
+ }
+
+ createMessageFromFile("tsig_verify5.wire");
+ {
+ SCOPED_TRACE("Verify a response after a FORMERR failure");
+ commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::NOERROR(),
+ TSIGContext::VERIFIED_RESPONSE);
+ }
+}
+
+TEST_F(TSIGTest, badtimeThenValidate) {
+ // Similar to the previous test, but the first response results in BADTIME.
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+ tsig_ctx.get());
+
+ // "advance the clock" and try validating, which should fail due to BADTIME
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a + 600>;
+ {
+ SCOPED_TRACE("Verify resulting in BADTIME due to expired SIG");
+ commonVerifyChecks(*tsig_ctx, tsig.get(), &dummy_data[0],
+ dummy_data.size(), TSIGError::BAD_TIME(),
+ TSIGContext::SENT_REQUEST);
+ }
+
+ // revert the clock again.
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ createMessageFromFile("tsig_verify5.wire");
+ {
+ SCOPED_TRACE("Verify a response after a BADTIME failure");
+ commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::NOERROR(),
+ TSIGContext::VERIFIED_RESPONSE);
+ }
+}
+
+TEST_F(TSIGTest, emptyMAC) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ // We don't allow empty MAC unless the TSIG error is BADSIG or BADKEY.
+ createMessageFromFile("tsig_verify7.wire");
+ {
+ SCOPED_TRACE("Verify test for request");
+ commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::BAD_SIG(), TSIGContext::RECEIVED_REQUEST);
+ }
+
+ // If the empty MAC comes with a BADKEY error, the error is passed
+ // transparently.
+ createMessageFromFile("tsig_verify8.wire");
+ {
+ SCOPED_TRACE("Verify test for request");
+ commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::BAD_KEY(), TSIGContext::RECEIVED_REQUEST);
+ }
+}
+
+TEST_F(TSIGTest, verifyAfterSendResponse) {
+ // Once the context is used for sending a signed response, it shouldn't
+ // be used for further verification.
+
+ // The following are essentially the same as what verifyThenSignResponse
+ // does with simplification.
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ createMessageFromFile("message_toWire2.wire");
+ tsig_verify_ctx->verify(message.getTSIGRecord(), &received_data[0],
+ received_data.size());
+ EXPECT_EQ(TSIGContext::RECEIVED_REQUEST, tsig_verify_ctx->getState());
+ createMessageAndSign(qid, test_name, tsig_verify_ctx.get(),
+ QR_FLAG|AA_FLAG|RD_FLAG, RRType::A(), "192.0.2.1");
+ EXPECT_EQ(TSIGContext::SENT_RESPONSE, tsig_verify_ctx->getState());
+
+ // Now trying further verification.
+ createMessageFromFile("message_toWire2.wire");
+ EXPECT_THROW(tsig_verify_ctx->verify(message.getTSIGRecord(),
+ &received_data[0],
+ received_data.size()),
+ TSIGContextError);
+}
+
+TEST_F(TSIGTest, signAfterVerified) {
+ // Likewise, once the context verifies a response, it shouldn't for
+ // signing any more.
+
+ // The following are borrowed from badsigThenValidate (without the
+ // intermediate failure)
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ createMessageAndSign(qid, test_name, tsig_ctx.get());
+ createMessageFromFile("tsig_verify5.wire");
+ tsig_ctx->verify(message.getTSIGRecord(), &received_data[0],
+ received_data.size());
+ EXPECT_EQ(TSIGContext::VERIFIED_RESPONSE, tsig_ctx->getState());
+
+ // Now trying further signing.
+ EXPECT_THROW(createMessageAndSign(qid, test_name, tsig_ctx.get()),
+ TSIGContextError);
+}
+
+TEST_F(TSIGTest, tooShortMAC) {
+ // Too short MAC should be rejected.
+
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ createMessageFromFile("tsig_verify10.wire");
+ {
+ SCOPED_TRACE("Verify test for request");
+ commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::FORMERR(), TSIGContext::RECEIVED_REQUEST);
+ }
+}
+
+TEST_F(TSIGTest, truncatedMAC) {
+ // Check truncated MAC support with HMAC-SHA512-256
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ secret.clear();
+ decodeBase64("jI/Pa4qRu96t76Pns5Z/Ndxbn3QCkwcxLOgt9vgvnJw5wqTRvNyk3FtD6yIMd1dWVlqZ+Y4fe6Uasc0ckctEmg==", secret);
+ TSIGContext sha_ctx(TSIGKey(test_name, TSIGKey::HMACSHA512_NAME(),
+ &secret[0], secret.size(), 256));
+
+ createMessageFromFile("tsig_verify11.wire");
+ {
+ SCOPED_TRACE("Verify test for request");
+ commonVerifyChecks(sha_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::NOERROR(), TSIGContext::RECEIVED_REQUEST);
+ }
+
+ // Try with HMAC-SHA512-264 (should fail)
+ TSIGContext bad_sha_ctx(TSIGKey(test_name, TSIGKey::HMACSHA512_NAME(),
+ &secret[0], secret.size(), 264));
+ {
+ SCOPED_TRACE("Verify test for request");
+ commonVerifyChecks(bad_sha_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::BAD_TRUNC(), TSIGContext::RECEIVED_REQUEST);
+ }
+}
+
+TEST_F(TSIGTest, getTSIGLength) {
+ // Check for the most common case with various algorithms
+ // See the comment in TSIGContext::getTSIGLength() for calculation and
+ // parameter notation.
+ // The key name (www.example.com) is the same for most cases, where n1=17
+
+ // hmac-md5.sig-alg.reg.int.: n2=26, x=16
+ EXPECT_EQ(85, tsig_ctx->getTSIGLength());
+
+ // hmac-md5-80: n2=26, x=10
+ tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACMD5_NAME(),
+ &dummy_data[0], 10, 80)));
+ EXPECT_EQ(79, tsig_ctx->getTSIGLength());
+
+ // hmac-sha1: n2=11, x=20
+ tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACSHA1_NAME(),
+ &dummy_data[0], 20)));
+ EXPECT_EQ(74, tsig_ctx->getTSIGLength());
+
+ // hmac-sha256: n2=13, x=32
+ tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACSHA256_NAME(),
+ &dummy_data[0], 32)));
+ EXPECT_EQ(88, tsig_ctx->getTSIGLength());
+
+ // hmac-sha224: n2=13, x=28
+ tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACSHA224_NAME(),
+ &dummy_data[0], 28)));
+ EXPECT_EQ(84, tsig_ctx->getTSIGLength());
+
+ // hmac-sha384: n2=13, x=48
+ tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACSHA384_NAME(),
+ &dummy_data[0], 48)));
+ EXPECT_EQ(104, tsig_ctx->getTSIGLength());
+
+ // hmac-sha512: n2=13, x=64
+ tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACSHA512_NAME(),
+ &dummy_data[0], 64)));
+ EXPECT_EQ(120, tsig_ctx->getTSIGLength());
+
+ // hmac-sha512-256: n2=13, x=32
+ tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACSHA512_NAME(),
+ &dummy_data[0], 32, 256)));
+ EXPECT_EQ(88, tsig_ctx->getTSIGLength());
+
+ // bad key case: n1=len(badkey.example.com)=20, n2=26, x=0
+ tsig_ctx.reset(new TestTSIGContext(badkey_name, TSIGKey::HMACMD5_NAME(),
+ keyring));
+ EXPECT_EQ(72, tsig_ctx->getTSIGLength());
+
+ // bad sig case: n1=17, n2=26, x=0
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ createMessageFromFile("message_toWire2.wire");
+ tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACMD5_NAME(),
+ &dummy_data[0],
+ dummy_data.size())));
+ {
+ SCOPED_TRACE("Verify resulting in BADSIG");
+ commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::BAD_SIG(), TSIGContext::RECEIVED_REQUEST);
+ }
+ EXPECT_EQ(69, tsig_ctx->getTSIGLength());
+
+ // bad time case: n1=17, n2=26, x=16, y=6
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a - 1000>;
+ tsig_ctx.reset(new TestTSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACMD5_NAME(),
+ &dummy_data[0],
+ dummy_data.size())));
+ {
+ SCOPED_TRACE("Verify resulting in BADTIME");
+ commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::BAD_TIME(),
+ TSIGContext::RECEIVED_REQUEST);
+ }
+ EXPECT_EQ(91, tsig_ctx->getTSIGLength());
+}
+
+// Verify a stream of multiple messages. Some of them have a signature omitted.
+//
+// We have two contexts, one that signs, another that verifies.
+TEST_F(TSIGTest, verifyMulti) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ // First, send query from the verify one to the normal one, so
+ // we initialize something like AXFR
+ {
+ SCOPED_TRACE("Query");
+ ConstTSIGRecordPtr tsig = createMessageAndSign(1234, test_name,
+ tsig_verify_ctx.get());
+ commonVerifyChecks(*tsig_ctx, tsig.get(),
+ renderer.getData(), renderer.getLength(),
+ TSIGError(Rcode::NOERROR()),
+ TSIGContext::RECEIVED_REQUEST);
+ }
+
+ {
+ SCOPED_TRACE("First message");
+ ConstTSIGRecordPtr tsig = createMessageAndSign(1234, test_name,
+ tsig_ctx.get());
+ commonVerifyChecks(*tsig_verify_ctx, tsig.get(),
+ renderer.getData(), renderer.getLength(),
+ TSIGError(Rcode::NOERROR()),
+ TSIGContext::VERIFIED_RESPONSE);
+ EXPECT_TRUE(tsig_verify_ctx->lastHadSignature());
+ }
+
+ {
+ SCOPED_TRACE("Second message");
+ ConstTSIGRecordPtr tsig = createMessageAndSign(1234, test_name,
+ tsig_ctx.get());
+ commonVerifyChecks(*tsig_verify_ctx, tsig.get(),
+ renderer.getData(), renderer.getLength(),
+ TSIGError(Rcode::NOERROR()),
+ TSIGContext::VERIFIED_RESPONSE);
+ EXPECT_TRUE(tsig_verify_ctx->lastHadSignature());
+ }
+
+ {
+ SCOPED_TRACE("Third message. Unsigned.");
+ // Another message does not carry the TSIG on it. But it should
+ // be OK, it's in the middle of stream.
+ message.clear(Message::RENDER);
+ message.setQid(1234);
+ message.setOpcode(Opcode::QUERY());
+ message.setRcode(Rcode::NOERROR());
+ RRsetPtr answer_rrset(new RRset(test_name, test_class, RRType::A(),
+ test_ttl));
+ answer_rrset->addRdata(createRdata(RRType::A(), test_class,
+ "192.0.2.1"));
+ message.addRRset(Message::SECTION_ANSWER, answer_rrset);
+ message.toWire(renderer);
+ // Update the internal state. We abuse the knowledge of
+ // internals here a little bit to generate correct test data
+ tsig_ctx->update(renderer.getData(), renderer.getLength());
+
+ commonVerifyChecks(*tsig_verify_ctx, NULL,
+ renderer.getData(), renderer.getLength(),
+ TSIGError(Rcode::NOERROR()),
+ TSIGContext::VERIFIED_RESPONSE);
+
+ EXPECT_FALSE(tsig_verify_ctx->lastHadSignature());
+ }
+
+ {
+ SCOPED_TRACE("Fourth message. Signed again.");
+ ConstTSIGRecordPtr tsig = createMessageAndSign(1234, test_name,
+ tsig_ctx.get());
+ commonVerifyChecks(*tsig_verify_ctx, tsig.get(),
+ renderer.getData(), renderer.getLength(),
+ TSIGError(Rcode::NOERROR()),
+ TSIGContext::VERIFIED_RESPONSE);
+ EXPECT_TRUE(tsig_verify_ctx->lastHadSignature());
+ }
+
+ {
+ SCOPED_TRACE("Filling in bunch of unsigned messages");
+ for (size_t i = 0; i < 100; ++i) {
+ SCOPED_TRACE(i);
+ // Another message does not carry the TSIG on it. But it should
+ // be OK, it's in the middle of stream.
+ message.clear(Message::RENDER);
+ message.setQid(1234);
+ message.setOpcode(Opcode::QUERY());
+ message.setRcode(Rcode::NOERROR());
+ RRsetPtr answer_rrset(new RRset(test_name, test_class, RRType::A(),
+ test_ttl));
+ answer_rrset->addRdata(createRdata(RRType::A(), test_class,
+ "192.0.2.1"));
+ message.addRRset(Message::SECTION_ANSWER, answer_rrset);
+ message.toWire(renderer);
+ // Update the internal state. We abuse the knowledge of
+ // internals here a little bit to generate correct test data
+ tsig_ctx->update(renderer.getData(), renderer.getLength());
+
+ // 99 unsigned messages is OK. But the 100th must be signed, according
+ // to the RFC2845, section 4.4
+ commonVerifyChecks(*tsig_verify_ctx, NULL,
+ renderer.getData(), renderer.getLength(),
+ i == 99 ? TSIGError::FORMERR() :
+ TSIGError(Rcode::NOERROR()),
+ TSIGContext::VERIFIED_RESPONSE);
+
+ EXPECT_FALSE(tsig_verify_ctx->lastHadSignature());
+ }
+ }
+}
+
+} // end namespace
diff --git a/src/lib/dns/tests/tsigerror_unittest.cc b/src/lib/dns/tests/tsigerror_unittest.cc
index 8b13789179..e50f0763d3 100644
--- a/src/lib/dns/tests/tsigerror_unittest.cc
+++ b/src/lib/dns/tests/tsigerror_unittest.cc
@@ -1 +1,126 @@
+// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <string>
+#include <ostream>
+
+#include <gtest/gtest.h>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/rcode.h>
+#include <dns/tsigerror.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+
+namespace {
+TEST(TSIGErrorTest, constructFromErrorCode) {
+ // These are pretty trivial, and also test getCode();
+ EXPECT_EQ(0, TSIGError(0).getCode());
+ EXPECT_EQ(18, TSIGError(18).getCode());
+ EXPECT_EQ(65535, TSIGError(65535).getCode());
+}
+
+TEST(TSIGErrorTest, constructFromRcode) {
+ // We use RCODE for code values from 0-15.
+ EXPECT_EQ(0, TSIGError(Rcode::NOERROR()).getCode());
+ EXPECT_EQ(15, TSIGError(Rcode(15)).getCode());
+
+ // From error code 16 TSIG errors define a separate space, so passing
+ // corresponding RCODE for such code values should be prohibited.
+ EXPECT_THROW(TSIGError(Rcode(16)).getCode(), OutOfRange);
+}
+
+TEST(TSIGErrorTest, constants) {
+ // We'll only test arbitrarily chosen subsets of the codes.
+ // This class is quite simple, so it should be suffice.
+
+ EXPECT_EQ(TSIGError::BAD_SIG_CODE, TSIGError(16).getCode());
+ EXPECT_EQ(TSIGError::BAD_KEY_CODE, TSIGError(17).getCode());
+ EXPECT_EQ(TSIGError::BAD_TIME_CODE, TSIGError(18).getCode());
+ EXPECT_EQ(TSIGError::BAD_MODE_CODE, TSIGError(19).getCode());
+ EXPECT_EQ(TSIGError::BAD_NAME_CODE, TSIGError(20).getCode());
+ EXPECT_EQ(TSIGError::BAD_ALG_CODE, TSIGError(21).getCode());
+ EXPECT_EQ(TSIGError::BAD_TRUNC_CODE, TSIGError(22).getCode());
+
+ EXPECT_EQ(0, TSIGError::NOERROR().getCode());
+ EXPECT_EQ(9, TSIGError::NOTAUTH().getCode());
+ EXPECT_EQ(14, TSIGError::RESERVED14().getCode());
+ EXPECT_EQ(TSIGError::BAD_SIG_CODE, TSIGError::BAD_SIG().getCode());
+ EXPECT_EQ(TSIGError::BAD_KEY_CODE, TSIGError::BAD_KEY().getCode());
+ EXPECT_EQ(TSIGError::BAD_TIME_CODE, TSIGError::BAD_TIME().getCode());
+ EXPECT_EQ(TSIGError::BAD_MODE_CODE, TSIGError::BAD_MODE().getCode());
+ EXPECT_EQ(TSIGError::BAD_NAME_CODE, TSIGError::BAD_NAME().getCode());
+ EXPECT_EQ(TSIGError::BAD_ALG_CODE, TSIGError::BAD_ALG().getCode());
+ EXPECT_EQ(TSIGError::BAD_TRUNC_CODE, TSIGError::BAD_TRUNC().getCode());
+}
+
+TEST(TSIGErrorTest, equal) {
+ EXPECT_TRUE(TSIGError::NOERROR() == TSIGError(Rcode::NOERROR()));
+ EXPECT_TRUE(TSIGError(Rcode::NOERROR()) == TSIGError::NOERROR());
+ EXPECT_TRUE(TSIGError::NOERROR().equals(TSIGError(Rcode::NOERROR())));
+ EXPECT_TRUE(TSIGError::NOERROR().equals(TSIGError(Rcode::NOERROR())));
+
+ EXPECT_TRUE(TSIGError::BAD_SIG() == TSIGError(16));
+ EXPECT_TRUE(TSIGError(16) == TSIGError::BAD_SIG());
+ EXPECT_TRUE(TSIGError::BAD_SIG().equals(TSIGError(16)));
+ EXPECT_TRUE(TSIGError(16).equals(TSIGError::BAD_SIG()));
+}
+
+TEST(TSIGErrorTest, nequal) {
+ EXPECT_TRUE(TSIGError::BAD_KEY() != TSIGError(Rcode::NOERROR()));
+ EXPECT_TRUE(TSIGError(Rcode::NOERROR()) != TSIGError::BAD_KEY());
+ EXPECT_TRUE(TSIGError::BAD_KEY().nequals(TSIGError(Rcode::NOERROR())));
+ EXPECT_TRUE(TSIGError(Rcode::NOERROR()).nequals(TSIGError::BAD_KEY()));
+}
+
+TEST(TSIGErrorTest, toText) {
+ // TSIGError derived from the standard Rcode
+ EXPECT_EQ("NOERROR", TSIGError(Rcode::NOERROR()).toText());
+
+ // Well known TSIG errors
+ EXPECT_EQ("BADSIG", TSIGError::BAD_SIG().toText());
+ EXPECT_EQ("BADKEY", TSIGError::BAD_KEY().toText());
+ EXPECT_EQ("BADTIME", TSIGError::BAD_TIME().toText());
+ EXPECT_EQ("BADMODE", TSIGError::BAD_MODE().toText());
+ EXPECT_EQ("BADNAME", TSIGError::BAD_NAME().toText());
+ EXPECT_EQ("BADALG", TSIGError::BAD_ALG().toText());
+ EXPECT_EQ("BADTRUNC", TSIGError::BAD_TRUNC().toText());
+
+ // Unknown (or not yet supported) codes. Simply converted as numeric.
+ EXPECT_EQ("23", TSIGError(23).toText());
+ EXPECT_EQ("65535", TSIGError(65535).toText());
+}
+
+TEST(TSIGErrorTest, toRcode) {
+ // TSIGError derived from the standard Rcode
+ EXPECT_EQ(Rcode::NOERROR(), TSIGError(Rcode::NOERROR()).toRcode());
+
+ // Well known TSIG errors
+ EXPECT_EQ(Rcode::NOTAUTH(), TSIGError::BAD_SIG().toRcode());
+ EXPECT_EQ(Rcode::NOTAUTH(), TSIGError::BAD_KEY().toRcode());
+ EXPECT_EQ(Rcode::NOTAUTH(), TSIGError::BAD_TIME().toRcode());
+ EXPECT_EQ(Rcode::NOTAUTH(), TSIGError::BAD_MODE().toRcode());
+ EXPECT_EQ(Rcode::NOTAUTH(), TSIGError::BAD_NAME().toRcode());
+ EXPECT_EQ(Rcode::NOTAUTH(), TSIGError::BAD_ALG().toRcode());
+ EXPECT_EQ(Rcode::NOTAUTH(), TSIGError::BAD_TRUNC().toRcode());
+
+ // Unknown (or not yet supported) codes are treated as SERVFAIL.
+ EXPECT_EQ(Rcode::SERVFAIL(), TSIGError(23).toRcode());
+ EXPECT_EQ(Rcode::SERVFAIL(), TSIGError(65535).toRcode());
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST(TSIGErrorTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << TSIGError::BAD_KEY();
+ EXPECT_EQ(TSIGError::BAD_KEY().toText(), oss.str());
+}
+} // end namespace
diff --git a/src/lib/dns/tests/tsigkey_unittest.cc b/src/lib/dns/tests/tsigkey_unittest.cc
index 8b13789179..90c59ac112 100644
--- a/src/lib/dns/tests/tsigkey_unittest.cc
+++ b/src/lib/dns/tests/tsigkey_unittest.cc
@@ -1 +1,350 @@
+// Copyright (C) 2021-2019 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <exceptions/exceptions.h>
+
+#include <cryptolink/cryptolink.h>
+
+#include <dns/tsigkey.h>
+
+#include <dns/tests/unittest_util.h>
+#include <util/unittests/wiredata.h>
+
+using namespace std;
+using namespace isc::dns;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+namespace {
+class TSIGKeyTest : public ::testing::Test {
+protected:
+ TSIGKeyTest() : secret("someRandomData"), key_name("example.com") {}
+ string secret;
+ const Name key_name;
+};
+
+TEST_F(TSIGKeyTest, algorithmNames) {
+ EXPECT_EQ(Name("hmac-md5.sig-alg.reg.int"), TSIGKey::HMACMD5_NAME());
+ EXPECT_EQ(Name("hmac-md5"), TSIGKey::HMACMD5_SHORT_NAME());
+ EXPECT_EQ(Name("hmac-sha1"), TSIGKey::HMACSHA1_NAME());
+ EXPECT_EQ(Name("hmac-sha256"), TSIGKey::HMACSHA256_NAME());
+ EXPECT_EQ(Name("hmac-sha224"), TSIGKey::HMACSHA224_NAME());
+ EXPECT_EQ(Name("hmac-sha384"), TSIGKey::HMACSHA384_NAME());
+ EXPECT_EQ(Name("hmac-sha512"), TSIGKey::HMACSHA512_NAME());
+ EXPECT_EQ(Name("gss-tsig"), TSIGKey::GSSTSIG_NAME());
+
+ // Also check conversion to cryptolink definitions
+ EXPECT_EQ(isc::cryptolink::MD5, TSIGKey(key_name, TSIGKey::HMACMD5_NAME(),
+ NULL, 0).getAlgorithm());
+ EXPECT_EQ(isc::cryptolink::MD5,
+ TSIGKey(key_name, TSIGKey::HMACMD5_SHORT_NAME(),
+ NULL, 0).getAlgorithm());
+ EXPECT_EQ(isc::cryptolink::SHA1, TSIGKey(key_name, TSIGKey::HMACSHA1_NAME(),
+ NULL, 0).getAlgorithm());
+ EXPECT_EQ(isc::cryptolink::SHA256, TSIGKey(key_name,
+ TSIGKey::HMACSHA256_NAME(),
+ NULL, 0).getAlgorithm());
+ EXPECT_EQ(isc::cryptolink::SHA224, TSIGKey(key_name,
+ TSIGKey::HMACSHA224_NAME(),
+ NULL, 0).getAlgorithm());
+ EXPECT_EQ(isc::cryptolink::SHA384, TSIGKey(key_name,
+ TSIGKey::HMACSHA384_NAME(),
+ NULL, 0).getAlgorithm());
+ EXPECT_EQ(isc::cryptolink::SHA512, TSIGKey(key_name,
+ TSIGKey::HMACSHA512_NAME(),
+ NULL, 0).getAlgorithm());
+}
+
+TEST_F(TSIGKeyTest, construct) {
+ TSIGKey key(key_name, TSIGKey::HMACMD5_NAME(),
+ secret.c_str(), secret.size());
+ EXPECT_EQ(key_name, key.getKeyName());
+ EXPECT_EQ(Name("hmac-md5.sig-alg.reg.int"), key.getAlgorithmName());
+ matchWireData(secret.c_str(), secret.size(),
+ key.getSecret(), key.getSecretLength());
+
+ TSIGKey key_short_md5(key_name, TSIGKey::HMACMD5_SHORT_NAME(),
+ secret.c_str(), secret.size());
+ EXPECT_EQ(key_name, key_short_md5.getKeyName());
+ EXPECT_EQ(Name("hmac-md5.sig-alg.reg.int"),
+ key_short_md5.getAlgorithmName());
+ matchWireData(secret.c_str(), secret.size(),
+ key_short_md5.getSecret(), key_short_md5.getSecretLength());
+
+ // "unknown" algorithm is only accepted with empty secret.
+ EXPECT_THROW(TSIGKey(key_name, Name("unknown-alg"),
+ secret.c_str(), secret.size()),
+ isc::InvalidParameter);
+ TSIGKey key2(key_name, Name("unknown-alg"), NULL, 0);
+ EXPECT_EQ(key_name, key2.getKeyName());
+ EXPECT_EQ(Name("unknown-alg"), key2.getAlgorithmName());
+
+ // The algorithm name should be converted to the canonical form.
+ EXPECT_EQ("hmac-sha1.",
+ TSIGKey(key_name, Name("HMAC-sha1"),
+ secret.c_str(),
+ secret.size()).getAlgorithmName().toText());
+
+ // Same for key name
+ EXPECT_EQ("example.com.",
+ TSIGKey(Name("EXAMPLE.CoM."), TSIGKey::HMACSHA256_NAME(),
+ secret.c_str(),
+ secret.size()).getKeyName().toText());
+
+ // Check digestbits
+ EXPECT_EQ(key.getDigestbits(), 0);
+ TSIGKey key_trunc(key_name, TSIGKey::HMACMD5_NAME(),
+ secret.c_str(), secret.size(), 120);
+ EXPECT_EQ(key_trunc.getDigestbits(), 120);
+
+ // Invalid combinations of secret and secret_len:
+ EXPECT_THROW(TSIGKey(key_name, TSIGKey::HMACSHA1_NAME(), secret.c_str(), 0),
+ isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey(key_name, TSIGKey::HMACSHA256_NAME(), NULL, 16),
+ isc::InvalidParameter);
+
+ // Empty secret
+ TSIGKey keye = TSIGKey(key_name, TSIGKey::HMACSHA256_NAME(), NULL, 0);
+ EXPECT_EQ(keye.getSecretLength(), 0);
+ EXPECT_EQ(keye.getSecret(), (const void*)0);
+}
+
+void
+compareTSIGKeys(const TSIGKey& expect, const TSIGKey& actual) {
+ EXPECT_EQ(expect.getKeyName(), actual.getKeyName());
+ EXPECT_EQ(expect.getAlgorithmName(), actual.getAlgorithmName());
+ EXPECT_EQ(expect.getDigestbits(), actual.getDigestbits());
+ matchWireData(expect.getSecret(), expect.getSecretLength(),
+ actual.getSecret(), actual.getSecretLength());
+}
+
+TEST_F(TSIGKeyTest, copyConstruct) {
+ const TSIGKey original(key_name, TSIGKey::HMACSHA256_NAME(),
+ secret.c_str(), secret.size(), 128);
+ const TSIGKey copy(original);
+ compareTSIGKeys(original, copy);
+
+ // Check the copied data is valid even after the original is deleted
+ TSIGKey* copy2 = new TSIGKey(original);
+ TSIGKey copy3(*copy2);
+ delete copy2;
+ compareTSIGKeys(original, copy3);
+}
+
+TEST_F(TSIGKeyTest, assignment) {
+ const TSIGKey original(key_name, TSIGKey::HMACSHA256_NAME(),
+ secret.c_str(), secret.size(), 200);
+ TSIGKey copy = original;
+ compareTSIGKeys(original, copy);
+
+ // Check if the copied data is valid even after the original is deleted
+ TSIGKey* copy2 = new TSIGKey(original);
+ TSIGKey copy3(original);
+ copy3 = *copy2;
+ delete copy2;
+ compareTSIGKeys(original, copy3);
+
+ // Self assignment
+ copy = *&copy;
+ compareTSIGKeys(original, copy);
+}
+
+class TSIGKeyRingTest : public ::testing::Test {
+protected:
+ TSIGKeyRingTest() :
+ key_name("example.com"),
+ md5_name("hmac-md5.sig-alg.reg.int"),
+ sha1_name("hmac-sha1"),
+ sha256_name("hmac-sha256"),
+ secretstring("anotherRandomData"),
+ secret(secretstring.c_str()),
+ secret_len(secretstring.size())
+ {}
+ TSIGKeyRing keyring;
+ const Name key_name;
+ const Name md5_name;
+ const Name sha1_name;
+ const Name sha256_name;
+private:
+ const string secretstring;
+protected:
+ const char* secret;
+ size_t secret_len;
+};
+
+TEST_F(TSIGKeyRingTest, init) {
+ EXPECT_EQ(0, keyring.size());
+}
+
+TEST_F(TSIGKeyRingTest, add) {
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(
+ TSIGKey(key_name, TSIGKey::HMACSHA256_NAME(),
+ secret, secret_len)));
+ EXPECT_EQ(1, keyring.size());
+ EXPECT_EQ(TSIGKeyRing::EXIST, keyring.add(
+ TSIGKey(key_name, TSIGKey::HMACSHA256_NAME(),
+ secret, secret_len)));
+ // keys are identified by their names, the same name of key with a
+ // different algorithm would be considered a duplicate.
+ EXPECT_EQ(TSIGKeyRing::EXIST, keyring.add(
+ TSIGKey(Name("example.com"), TSIGKey::HMACSHA1_NAME(),
+ secret, secret_len)));
+ // names are compared in a case insensitive manner.
+ EXPECT_EQ(TSIGKeyRing::EXIST, keyring.add(
+ TSIGKey(Name("EXAMPLE.COM"), TSIGKey::HMACSHA1_NAME(),
+ secret, secret_len)));
+ EXPECT_EQ(1, keyring.size());
+}
+
+TEST_F(TSIGKeyRingTest, addMore) {
+ // essentially the same test, but try adding more than 1
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(
+ TSIGKey(key_name, TSIGKey::HMACSHA256_NAME(),
+ secret, secret_len)));
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(
+ TSIGKey(Name("another.example"), TSIGKey::HMACMD5_NAME(),
+ secret, secret_len)));
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(
+ TSIGKey(Name("more.example"), TSIGKey::HMACSHA1_NAME(),
+ secret, secret_len)));
+ EXPECT_EQ(3, keyring.size());
+}
+
+TEST_F(TSIGKeyRingTest, remove) {
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(
+ TSIGKey(key_name, TSIGKey::HMACSHA256_NAME(),
+ secret, secret_len)));
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.remove(key_name));
+ EXPECT_EQ(TSIGKeyRing::NOTFOUND, keyring.remove(key_name));
+}
+
+TEST_F(TSIGKeyRingTest, removeFromSome) {
+ // essentially the same test, but try removing from a larger set
+
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(
+ TSIGKey(key_name, TSIGKey::HMACSHA256_NAME(),
+ secret, secret_len)));
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(
+ TSIGKey(Name("another.example"), TSIGKey::HMACMD5_NAME(),
+ secret, secret_len)));
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(
+ TSIGKey(Name("more.example"), TSIGKey::HMACSHA1_NAME(),
+ secret, secret_len)));
+
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.remove(Name("another.example")));
+ EXPECT_EQ(TSIGKeyRing::NOTFOUND, keyring.remove(Name("noexist.example")));
+ EXPECT_EQ(2, keyring.size());
+}
+
+TEST_F(TSIGKeyRingTest, find) {
+ // If the keyring is empty the search should fail.
+ EXPECT_EQ(TSIGKeyRing::NOTFOUND, keyring.find(key_name, md5_name).code);
+ EXPECT_EQ(static_cast<const TSIGKey*>(NULL),
+ keyring.find(key_name, md5_name).key);
+
+ // Add a key and try to find it. Should succeed.
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(TSIGKey(key_name, sha256_name,
+ secret, secret_len)));
+ const TSIGKeyRing::FindResult result1(keyring.find(key_name, sha256_name));
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, result1.code);
+ EXPECT_EQ(key_name, result1.key->getKeyName());
+ EXPECT_EQ(TSIGKey::HMACSHA256_NAME(), result1.key->getAlgorithmName());
+ matchWireData(secret, secret_len,
+ result1.key->getSecret(), result1.key->getSecretLength());
+
+ // If either key name or algorithm doesn't match, search should fail.
+ const TSIGKeyRing::FindResult result2 =
+ keyring.find(Name("different-key.example"), sha256_name);
+ EXPECT_EQ(TSIGKeyRing::NOTFOUND, result2.code);
+ EXPECT_EQ(static_cast<const TSIGKey*>(NULL), result2.key);
+
+ const TSIGKeyRing::FindResult result3 = keyring.find(key_name, md5_name);
+ EXPECT_EQ(TSIGKeyRing::NOTFOUND, result3.code);
+ EXPECT_EQ(static_cast<const TSIGKey*>(NULL), result3.key);
+
+ // But with just the name it should work
+ const TSIGKeyRing::FindResult result4(keyring.find(key_name));
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, result4.code);
+ EXPECT_EQ(key_name, result4.key->getKeyName());
+ EXPECT_EQ(TSIGKey::HMACSHA256_NAME(), result4.key->getAlgorithmName());
+ matchWireData(secret, secret_len,
+ result4.key->getSecret(), result4.key->getSecretLength());
+}
+
+TEST_F(TSIGKeyRingTest, findFromSome) {
+ // essentially the same test, but search a larger set
+
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(TSIGKey(key_name, sha256_name,
+ secret, secret_len)));
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(TSIGKey(Name("another.example"),
+ md5_name,
+ secret, secret_len)));
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(TSIGKey(Name("more.example"),
+ sha1_name,
+ secret, secret_len)));
+
+ const TSIGKeyRing::FindResult result(
+ keyring.find(Name("another.example"), md5_name));
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, result.code);
+ EXPECT_EQ(Name("another.example"), result.key->getKeyName());
+ EXPECT_EQ(TSIGKey::HMACMD5_NAME(), result.key->getAlgorithmName());
+
+ EXPECT_EQ(TSIGKeyRing::NOTFOUND,
+ keyring.find(Name("noexist.example"), sha1_name).code);
+ EXPECT_EQ(static_cast<const TSIGKey*>(NULL),
+ keyring.find(Name("noexist.example"), sha256_name).key);
+
+ EXPECT_EQ(TSIGKeyRing::NOTFOUND,
+ keyring.find(Name("another.example"), sha1_name).code);
+ EXPECT_EQ(static_cast<const TSIGKey*>(NULL),
+ keyring.find(Name("another.example"), sha256_name).key);
+}
+
+TEST(TSIGStringTest, TSIGKeyFromToString) {
+ TSIGKey k1 = TSIGKey("test.example:MSG6Ng==:hmac-md5.sig-alg.reg.int");
+ TSIGKey k2 = TSIGKey("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.");
+ TSIGKey k3 = TSIGKey("test.example:MSG6Ng==");
+ TSIGKey k4 = TSIGKey("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.:120");
+ TSIGKey k5 = TSIGKey(Name("test.example."), Name("hmac-sha1."), NULL, 0);
+ // "Unknown" key with empty secret is okay
+ TSIGKey k6 = TSIGKey("test.example.::unknown");
+
+ EXPECT_EQ("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.",
+ k1.toText());
+ EXPECT_EQ("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.",
+ k2.toText());
+ EXPECT_EQ("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.",
+ k3.toText());
+ EXPECT_EQ("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.:120",
+ k4.toText());
+ EXPECT_EQ(120, k4.getDigestbits());
+ EXPECT_EQ("test.example.::hmac-sha1.", k5.toText());
+ EXPECT_EQ(Name("test.example."), k6.getKeyName());
+ EXPECT_EQ(Name("unknown"), k6.getAlgorithmName());
+
+ EXPECT_THROW(TSIGKey(""), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey(":"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("::"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("..:aa:"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example:xxxx:"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example.::"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example.:"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example.:MSG6Ng==:"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example.:MSG6Ng==:unknown"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.:"),
+ isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.:xxx"),
+ isc::InvalidParameter);
+}
+
+
+} // end namespace
diff --git a/src/lib/dns/tests/tsigrecord_unittest.cc b/src/lib/dns/tests/tsigrecord_unittest.cc
index 8b13789179..624f03b85e 100644
--- a/src/lib/dns/tests/tsigrecord_unittest.cc
+++ b/src/lib/dns/tests/tsigrecord_unittest.cc
@@ -1 +1,158 @@
+// Copyright (C) 2011-2023 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+
+#include <vector>
+#include <sstream>
+
+#include <gtest/gtest.h>
+
+#include <util/buffer.h>
+
+#include <dns/exceptions.h>
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/tsig.h>
+#include <dns/tsigkey.h>
+#include <dns/tsigrecord.h>
+
+#include <dns/tests/unittest_util.h>
+#include <util/unittests/wiredata.h>
+
+using namespace std;
+using namespace isc::util;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::dns::rdata::any;
+using isc::UnitTestUtil;
+using isc::util::unittests::matchWireData;
+
+namespace {
+class TSIGRecordTest : public ::testing::Test {
+protected:
+ TSIGRecordTest() :
+ test_name("www.example.com"), test_mac(16, 0xda),
+ test_rdata(TSIG(TSIGKey::HMACMD5_NAME(), 0x4da8877a, TSIGContext::DEFAULT_FUDGE,
+ test_mac.size(), &test_mac[0], 0x2d65, 0, 0, NULL)),
+ test_record(test_name, test_rdata),
+ buffer(0) {
+ }
+
+ const Name test_name;
+
+ vector<unsigned char> test_mac;
+
+ const TSIG test_rdata;
+
+ const TSIGRecord test_record;
+
+ OutputBuffer buffer;
+
+ MessageRenderer renderer;
+
+ vector<unsigned char> data;
+};
+
+TEST_F(TSIGRecordTest, getName) {
+ EXPECT_EQ(test_name, test_record.getName());
+}
+
+TEST_F(TSIGRecordTest, getLength) {
+ // 85 = 17 + 26 + 16 + 26
+ // len(www.example.com) = 17
+ // len(hmac-md5.sig-alg.reg.int) = 26
+ // len(MAC) = 16
+ // the rest are fixed length fields (26 in total)
+ EXPECT_EQ(85, test_record.getLength());
+}
+
+TEST_F(TSIGRecordTest, fromParams) {
+ // Construct the same TSIG RR as test_record from parameters.
+ // See the getLength test for the magic number of 85 (although it
+ // actually doesn't matter)
+ const TSIGRecord record(test_name, TSIGRecord::getClass(),
+ TSIGRecord::getTTL(), test_rdata, 85);
+ // Perform straight sanity checks
+ EXPECT_EQ(test_name, record.getName());
+ EXPECT_EQ(85, record.getLength());
+ EXPECT_EQ(0, test_rdata.compare(record.getRdata()));
+
+ // The constructor doesn't check the length...
+ EXPECT_NO_THROW(TSIGRecord(test_name, TSIGRecord::getClass(),
+ TSIGRecord::getTTL(), test_rdata, 82));
+ // ...even for impossibly small values...
+ EXPECT_NO_THROW(TSIGRecord(test_name, TSIGRecord::getClass(),
+ TSIGRecord::getTTL(), test_rdata, 1));
+ // ...or too large values.
+ EXPECT_NO_THROW(TSIGRecord(test_name, TSIGRecord::getClass(),
+ TSIGRecord::getTTL(), test_rdata, 65536));
+
+ // RDATA must indeed be TSIG
+ EXPECT_THROW(TSIGRecord(test_name, TSIGRecord::getClass(),
+ TSIGRecord::getTTL(), in::A("192.0.2.1"), 85),
+ DNSMessageFORMERR);
+
+ // Unexpected class
+ EXPECT_THROW(TSIGRecord(test_name, RRClass::IN(), TSIGRecord::getTTL(),
+ test_rdata, 85), DNSMessageFORMERR);
+
+ // Unexpected TTL
+ EXPECT_THROW(TSIGRecord(test_name, TSIGRecord::getClass(),
+ RRTTL(3600), test_rdata, 85), DNSMessageFORMERR);
+}
+
+TEST_F(TSIGRecordTest, recordToWire) {
+ UnitTestUtil::readWireData("tsigrecord_toWire1.wire", data);
+ EXPECT_EQ(1, test_record.toWire(renderer));
+ matchWireData(&data[0], data.size(),
+ renderer.getData(), renderer.getLength());
+
+ // Same test for a dumb buffer
+ buffer.clear();
+ EXPECT_EQ(1, test_record.toWire(buffer));
+ matchWireData(&data[0], data.size(),
+ buffer.getData(), buffer.getLength());
+}
+
+TEST_F(TSIGRecordTest, recordToOLongToWire) {
+ // By setting the limit to "record length - 1", it will fail, and the
+ // renderer will be marked as "truncated".
+ renderer.setLengthLimit(test_record.getLength() - 1);
+ EXPECT_FALSE(renderer.isTruncated()); // not marked before render attempt
+ EXPECT_EQ(0, test_record.toWire(renderer));
+ EXPECT_TRUE(renderer.isTruncated());
+}
+
+TEST_F(TSIGRecordTest, recordToWireAfterNames) {
+ // A similar test but the TSIG RR follows some domain names that could
+ // cause name compression inside TSIG. Our implementation shouldn't
+ // compress either owner (key) name or the algorithm name. This test
+ // confirms that.
+
+ UnitTestUtil::readWireData("tsigrecord_toWire2.wire", data);
+ renderer.writeName(TSIGKey::HMACMD5_NAME());
+ renderer.writeName(Name("foo.example.com"));
+ EXPECT_EQ(1, test_record.toWire(renderer));
+ matchWireData(&data[0], data.size(),
+ renderer.getData(), renderer.getLength());
+}
+
+TEST_F(TSIGRecordTest, toText) {
+ EXPECT_EQ("www.example.com. 0 ANY TSIG hmac-md5.sig-alg.reg.int. "
+ "1302890362 300 16 2tra2tra2tra2tra2tra2g== 11621 NOERROR 0\n",
+ test_record.toText());
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST_F(TSIGRecordTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << test_record;
+ EXPECT_EQ(test_record.toText(), oss.str());
+}
+} // end namespace
diff --git a/src/lib/dns/tests/unittest_util.cc b/src/lib/dns/tests/unittest_util.cc
index a86203d3dc..5e0c620527 100644
--- a/src/lib/dns/tests/unittest_util.cc
+++ b/src/lib/dns/tests/unittest_util.cc
@@ -21,7 +21,7 @@
#include <dns/tests/unittest_util.h>
using namespace std;
-//using namespace isc::dns;
+using namespace isc::dns;
using isc::UnitTestUtil;
@@ -121,3 +121,20 @@ UnitTestUtil::readWireData(const string& datastr,
}
} while (!iss.eof());
}
+
+::testing::AssertionResult
+UnitTestUtil::matchName(const char*, const char*,
+ const isc::dns::Name& name1,
+ const isc::dns::Name& name2) {
+ ::testing::Message msg;
+
+ NameComparisonResult cmpresult = name1.compare(name2);
+ if (cmpresult.getOrder() != 0 ||
+ cmpresult.getRelation() != NameComparisonResult::EQUAL) {
+ msg << "Two names are expected to be equal but not:\n"
+ << " One: " << name1 << "\n"
+ << "Other: " << name2 << "\n";
+ return (::testing::AssertionFailure(msg));
+ }
+ return (::testing::AssertionSuccess());
+}
diff --git a/src/lib/dns/tests/unittest_util.h b/src/lib/dns/tests/unittest_util.h
index f1af813de0..9026119727 100644
--- a/src/lib/dns/tests/unittest_util.h
+++ b/src/lib/dns/tests/unittest_util.h
@@ -37,6 +37,18 @@ public:
static void readWireData(const std::string& datastr,
std::vector<unsigned char>& data);
+ ///
+ /// Compare two names.
+ ///
+ /// This check method uses \c Name::compare() for comparison, which performs
+ /// deeper checks including the equality of offsets, and should be better
+ /// than EXPECT_EQ, which uses operator==. Like the \c matchWireData()
+ /// method, the usage is a bit awkward; the caller should use
+ /// \c EXPECT_PRED_FORMAT2.
+ ///
+ static ::testing::AssertionResult
+ matchName(const char* nameexp1, const char* nameexp2,
+ const isc::dns::Name& name1, const isc::dns::Name& name2);
};
}
#endif // UNITTEST_UTIL_H
diff --git a/src/lib/dns/tests/zone_checker_unittest.cc b/src/lib/dns/tests/zone_checker_unittest.cc
deleted file mode 100644
index 8b13789179..0000000000
--- a/src/lib/dns/tests/zone_checker_unittest.cc
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/lib/dns/tsig.cc b/src/lib/dns/tsig.cc
index ee5ba98e3c..7281d9ab04 100644
--- a/src/lib/dns/tsig.cc
+++ b/src/lib/dns/tsig.cc
@@ -6,34 +6,30 @@
#include <config.h>
-#include <sys/time.h>
-
-#include <stdint.h>
-
-#include <cassert>
-#include <vector>
-
-#include <boost/shared_ptr.hpp>
-
#include <exceptions/exceptions.h>
-
-#include <util/buffer.h>
-#include <util/time_utilities.h>
-
+#include <cryptolink/cryptolink.h>
+#include <cryptolink/crypto_hmac.h>
#include <dns/rdataclass.h>
#include <dns/rrclass.h>
#include <dns/tsig.h>
#include <dns/tsigerror.h>
#include <dns/tsigkey.h>
+#include <util/buffer.h>
+#include <util/time_utilities.h>
-#include <cryptolink/cryptolink.h>
-#include <cryptolink/crypto_hmac.h>
+#include <cassert>
+#include <sys/time.h>
+#include <stdint.h>
+#include <vector>
+#include <boost/shared_ptr.hpp>
-using namespace std;
using namespace isc::util;
using namespace isc::cryptolink;
using namespace isc::dns::rdata;
+using namespace std;
+
+
namespace isc {
namespace dns {
namespace {
@@ -187,10 +183,11 @@ TSIGContext::TSIGContextImpl::digestPreviousMAC(HMACPtr hmac) {
}
void
-TSIGContext::TSIGContextImpl::digestTSIGVariables(
- HMACPtr hmac, uint16_t rrclass, uint32_t rrttl, uint64_t time_signed,
- uint16_t fudge, uint16_t error, uint16_t otherlen, const void* otherdata,
- bool time_variables_only) const {
+TSIGContext::TSIGContextImpl::digestTSIGVariables(HMACPtr hmac, uint16_t rrclass,
+ uint32_t rrttl, uint64_t time_signed,
+ uint16_t fudge, uint16_t error,
+ uint16_t otherlen, const void* otherdata,
+ bool time_variables_only) const {
// It's bit complicated, but we can still predict the necessary size of
// the data to be digested. So we precompute it to avoid possible
// reallocation inside OutputBuffer (not absolutely necessary, but this
diff --git a/src/lib/dns/tsigrecord.cc b/src/lib/dns/tsigrecord.cc
index 13b7e9acdd..1d36373b0c 100644
--- a/src/lib/dns/tsigrecord.cc
+++ b/src/lib/dns/tsigrecord.cc
@@ -6,16 +6,15 @@
#include <config.h>
-#include <ostream>
-#include <string>
-
-#include <util/buffer.h>
-
#include <dns/exceptions.h>
#include <dns/messagerenderer.h>
#include <dns/rrclass.h>
#include <dns/rrttl.h>
#include <dns/tsigrecord.h>
+#include <util/buffer.h>
+
+#include <ostream>
+#include <string>
using namespace isc::util;
using namespace isc::dns::rdata;
@@ -105,7 +104,7 @@ toWireCommon(OUTPUT& output, const rdata::any::TSIG& rdata) {
}
}
-int
+uint32_t
TSIGRecord::toWire(AbstractMessageRenderer& renderer) const {
// If adding the TSIG would exceed the size limit, don't do it.
if (renderer.getLength() + length_ > renderer.getLengthLimit()) {
@@ -119,7 +118,7 @@ TSIGRecord::toWire(AbstractMessageRenderer& renderer) const {
return (1);
}
-int
+uint32_t
TSIGRecord::toWire(OutputBuffer& buffer) const {
key_name_.toWire(buffer);
toWireCommon(buffer, rdata_);
diff --git a/src/lib/dns/tsigrecord.h b/src/lib/dns/tsigrecord.h
index f754b2f69e..1ae8f3dfc1 100644
--- a/src/lib/dns/tsigrecord.h
+++ b/src/lib/dns/tsigrecord.h
@@ -244,7 +244,7 @@ public:
/// \param renderer DNS message rendering context that encapsulates the
/// output buffer and name compression information.
/// \return 1 if the TSIG RR fits in the message size limit; otherwise 0.
- int toWire(AbstractMessageRenderer& renderer) const;
+ uint32_t toWire(AbstractMessageRenderer& renderer) const;
/// \brief Render the \c TSIG RR in the wire format.
///
@@ -252,7 +252,7 @@ public:
/// except it renders the RR in an \c OutputBuffer and therefore
/// does not care about message size limit.
/// As a consequence it always returns 1.
- int toWire(isc::util::OutputBuffer& buffer) const;
+ uint32_t toWire(isc::util::OutputBuffer& buffer) const;
/// Convert the TSIG record to a string.
///
diff --git a/src/lib/dns/txt_like.h b/src/lib/dns/txt_like.h
new file mode 100644
index 0000000000..d0610e333b
--- /dev/null
+++ b/src/lib/dns/txt_like.h
@@ -0,0 +1,237 @@
+// Copyright (C) 2011-2015,2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef TXT_LIKE_H
+#define TXT_LIKE_H 1
+
+#include <dns/master_lexer.h>
+#include <dns/char_string.h>
+
+#include <stdint.h>
+#include <algorithm>
+#include <string>
+#include <sstream>
+#include <vector>
+
+namespace isc {
+namespace dns {
+namespace rdata {
+namespace generic {
+namespace detail {
+
+/// \brief \c rdata::TXTLikeImpl class represents the TXT-like RDATA for TXT
+/// and SPF types.
+///
+/// This class implements the basic interfaces inherited by the TXT and SPF
+/// classes from the abstract \c rdata::Rdata class, and provides trivial
+/// accessors to TXT-like RDATA.
+template<class Type, uint16_t typeCode>class TXTLikeImpl {
+public:
+ /// \brief Constructor from wire-format data.
+ ///
+ /// \param buffer A buffer storing the wire format data.
+ /// \param rdata_len The length of the RDATA in bytes, normally expected
+ /// to be the value of the RDLENGTH field of the corresponding RR.
+ ///
+ /// <b>Exceptions</b>
+ ///
+ /// \c InvalidRdataLength is thrown if rdata_len exceeds the maximum.
+ /// \c DNSMessageFORMERR is thrown if the RR is malformed.
+ TXTLikeImpl(util::InputBuffer& buffer, size_t rdata_len) {
+ if (rdata_len > MAX_RDLENGTH) {
+ isc_throw(InvalidRdataLength, "RDLENGTH too large: " << rdata_len);
+ }
+
+ if (rdata_len == 0) { // note that this couldn't happen in the loop.
+ isc_throw(DNSMessageFORMERR, "Error in parsing " <<
+ RRType(typeCode) << " RDATA: 0-length character string");
+ }
+
+ do {
+ const uint8_t len = buffer.readUint8();
+ if (rdata_len < len + 1) {
+ isc_throw(DNSMessageFORMERR, "Error in parsing " <<
+ RRType(typeCode) <<
+ " RDATA: character string length is too large: " <<
+ static_cast<int>(len));
+ }
+ std::vector<uint8_t> data(len + 1);
+ data[0] = len;
+ buffer.readData(&data[0] + 1, len);
+ string_list_.push_back(data);
+
+ rdata_len -= (len + 1);
+ } while (rdata_len > 0);
+ }
+
+ /// \brief Constructor from string.
+ ///
+ /// \throw CharStringTooLong the parameter string length exceeds maximum.
+ /// \throw InvalidRdataText the method cannot process the parameter data
+ explicit TXTLikeImpl(const std::string& txtstr) {
+ std::istringstream ss(txtstr);
+ MasterLexer lexer;
+ lexer.pushSource(ss);
+
+ try {
+ buildFromTextHelper(lexer);
+ if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+ isc_throw(InvalidRdataText, "Failed to construct " <<
+ RRType(typeCode) << " RDATA from '" << txtstr <<
+ "': extra new line");
+ }
+ } catch (const MasterLexer::LexerError& ex) {
+ isc_throw(InvalidRdataText, "Failed to construct " <<
+ RRType(typeCode) << " RDATA from '" << txtstr << "': "
+ << ex.what());
+ }
+ }
+
+ /// \brief Constructor using the master lexer.
+ ///
+ /// \throw CharStringTooLong the parameter string length exceeds maximum.
+ /// \throw InvalidRdataText the method cannot process the parameter data
+ ///
+ /// \param lexer A \c MasterLexer object parsing a master file for this
+ /// RDATA.
+ TXTLikeImpl(MasterLexer& lexer) {
+ buildFromTextHelper(lexer);
+ }
+
+private:
+ void buildFromTextHelper(MasterLexer& lexer) {
+ while (true) {
+ const MasterToken& token = lexer.getNextToken(
+ MasterToken::QSTRING, true);
+ if (token.getType() != MasterToken::STRING &&
+ token.getType() != MasterToken::QSTRING) {
+ break;
+ }
+ string_list_.push_back(std::vector<uint8_t>());
+ stringToCharString(token.getStringRegion(), string_list_.back());
+ }
+
+ // Let upper layer handle eol/eof.
+ lexer.ungetToken();
+
+ if (string_list_.empty()) {
+ isc_throw(InvalidRdataText, "Failed to construct " <<
+ RRType(typeCode) << " RDATA: empty input");
+ }
+ }
+
+public:
+ /// \brief The copy constructor.
+ ///
+ /// Trivial for now, we could've used the default one.
+ TXTLikeImpl(const TXTLikeImpl& other) :
+ string_list_(other.string_list_)
+ {}
+
+ /// \brief Render the TXT-like data in the wire format to an OutputBuffer
+ /// object.
+ ///
+ /// \param buffer An output buffer to store the wire data.
+ void
+ toWire(util::OutputBuffer& buffer) const {
+ for (std::vector<std::vector<uint8_t> >::const_iterator it =
+ string_list_.begin();
+ it != string_list_.end();
+ ++it)
+ {
+ buffer.writeData(&(*it)[0], (*it).size());
+ }
+ }
+
+ /// \brief Render the TXT-like data in the wire format to an
+ /// AbstractMessageRenderer object.
+ ///
+ /// \param buffer An output AbstractMessageRenderer to send the wire data
+ /// to.
+ void
+ toWire(AbstractMessageRenderer& renderer) const {
+ for (std::vector<std::vector<uint8_t> >::const_iterator it =
+ string_list_.begin();
+ it != string_list_.end();
+ ++it)
+ {
+ renderer.writeData(&(*it)[0], (*it).size());
+ }
+ }
+
+ /// \brief Convert the TXT-like data to a string.
+ ///
+ /// \return A \c string object that represents the TXT-like data.
+ std::string
+ toText() const {
+ std::string s;
+
+ for (std::vector<std::vector<uint8_t> >::const_iterator it =
+ string_list_.begin(); it != string_list_.end(); ++it)
+ {
+ if (!s.empty()) {
+ s.push_back(' ');
+ }
+ s.push_back('"');
+ s.append(charStringToString(*it));
+ s.push_back('"');
+ }
+
+ return (s);
+ }
+
+ /// \brief Compare two instances of TXT-like RDATA.
+ ///
+ /// It is up to the caller to make sure that \c other is an object of the
+ /// same \c TXTLikeImpl class.
+ ///
+ /// \param other the right-hand operand to compare against.
+ /// \return < 0 if \c this would be sorted before \c other.
+ /// \return 0 if \c this is identical to \c other in terms of sorting
+ /// order.
+ /// \return > 0 if \c this would be sorted after \c other.
+ int
+ compare(const TXTLikeImpl& other) const {
+ // This implementation is not efficient. Revisit this (TBD).
+ util::OutputBuffer this_buffer(0);
+ toWire(this_buffer);
+ uint8_t const* const this_data = (uint8_t const*)this_buffer.getData();
+ const size_t this_len = this_buffer.getLength();
+
+ util::OutputBuffer other_buffer(0);
+ other.toWire(other_buffer);
+ uint8_t const* const other_data
+ = (uint8_t const*)other_buffer.getData();
+ const size_t other_len = other_buffer.getLength();
+
+ const size_t cmplen = std::min(this_len, other_len);
+ const int cmp = memcmp(this_data, other_data, cmplen);
+
+ if (cmp != 0) {
+ return (cmp);
+ } else {
+ return ((this_len == other_len) ? 0 :
+ (this_len < other_len) ? -1 : 1);
+ }
+ }
+
+private:
+ /// Note: this is a prototype version; we may reconsider
+ /// this representation later.
+ std::vector<std::vector<uint8_t> > string_list_;
+};
+
+} // namespace detail
+} // namespace generic
+} // namespace rdata
+} // namespace dns
+} // namespace isc
+
+#endif // TXT_LIKE_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/unittests/wiredata.cc b/src/lib/util/unittests/wiredata.cc
index c14c8f164d..ebec617a82 100644
--- a/src/lib/util/unittests/wiredata.cc
+++ b/src/lib/util/unittests/wiredata.cc
@@ -21,10 +21,8 @@ namespace unittests {
void
matchWireData(const void* expected_data, size_t expected_len,
- const void* actual_data, size_t actual_len)
-{
+ const void* actual_data, size_t actual_len) {
const size_t cmplen = std::min(expected_len, actual_len);
-
for (size_t i = 0; i < cmplen; ++i) {
const int ebyte = static_cast<const uint8_t*>(expected_data)[i];
const int abyte = static_cast<const uint8_t*>(actual_data)[i];